Implement clickable osdmenu. The clickable positioning and scaling guessing is not...
[vlc.git] / modules / misc / osd / osd_menu.c
1 /*****************************************************************************
2  * parser.c : OSD import module
3  *****************************************************************************
4  * Copyright (C) 2007 M2X
5  * $Id: $
6  *
7  * Authors: Jean-Paul Saman
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #include <vlc/vlc.h>
29 #include <vlc_vout.h>
30 #include <vlc_config.h>
31
32 #include <vlc_keys.h>
33 #include <vlc_image.h>
34 #include <vlc_osd.h>
35 #include <vlc_charset.h>
36
37 #include "osd_menu.h"
38
39 #undef OSD_MENU_DEBUG
40
41 /*****************************************************************************
42  * Local prototypes
43  *****************************************************************************/
44
45 /*****************************************************************************
46  * Create a new Menu structure
47  *****************************************************************************/
48 osd_menu_t *osd_MenuNew( osd_menu_t *p_menu, const char *psz_path,
49                          int i_x, int i_y )
50 {
51     if( !p_menu ) return NULL;
52
53     p_menu->p_state = (osd_menu_state_t *) malloc( sizeof( osd_menu_state_t ) );
54     if( !p_menu->p_state )
55     {
56         msg_Err( p_menu, "Memory allocation for OSD Menu state failed" );
57         return NULL;
58     }
59
60     memset(p_menu->p_state, 0, sizeof(osd_menu_state_t));
61     if( psz_path != NULL )
62         p_menu->psz_path = strdup( psz_path );
63     else
64         p_menu->psz_path = NULL;
65
66     p_menu->i_x = i_x;
67     p_menu->i_y = i_y;
68     p_menu->i_style = OSD_MENU_STYLE_SIMPLE;
69
70     return p_menu;
71 }
72
73 /*****************************************************************************
74  * Free the menu
75  *****************************************************************************/
76 void osd_MenuFree( osd_menu_t *p_menu )
77 {
78     msg_Dbg( p_menu, "freeing menu" );
79     osd_ButtonFree( p_menu, p_menu->p_button );
80
81     if( p_menu->psz_path ) free( p_menu->psz_path );
82     if( p_menu->p_state ) free( p_menu->p_state );
83
84     p_menu->p_button = NULL;
85     p_menu->p_last_button = NULL;
86     p_menu->psz_path = NULL;
87     p_menu->p_state = NULL;
88 }
89
90 /*****************************************************************************
91  * Create a new button
92  *****************************************************************************/
93 osd_button_t *osd_ButtonNew( const char *psz_action, int i_x, int i_y )
94 {
95     osd_button_t *p_button = NULL;
96     p_button = (osd_button_t*) malloc( sizeof(osd_button_t) );
97     if( !p_button )
98         return NULL;
99
100     memset( p_button, 0, sizeof(osd_button_t) );
101     p_button->psz_action = strdup(psz_action);
102     p_button->psz_action_down = NULL;
103     p_button->p_feedback = NULL;
104     p_button->i_x = i_x;
105     p_button->i_y = i_y;
106
107     return p_button;
108 }
109
110 /*****************************************************************************
111  * Free a button
112  *****************************************************************************/
113 void osd_ButtonFree( osd_menu_t *p_menu, osd_button_t *p_button )
114 {
115     osd_button_t *p_current = p_button;
116     osd_button_t *p_next = NULL;
117     osd_button_t *p_prev = NULL;
118
119     /* First walk to the end. */
120     while( p_current->p_next )
121     {
122         p_next = p_current->p_next;
123         p_current = p_next;
124     }
125     /* Then free end first and walk to the start. */
126     while( p_current->p_prev )
127     {
128         msg_Dbg( p_menu, "+ freeing button %s [%p]",
129                  p_current->psz_action, p_current );
130         p_prev = p_current->p_prev;
131         p_current = p_prev;
132         if( p_current->p_next )
133         {
134             if( p_current->p_next->psz_name )
135                 free( p_current->p_next->psz_name );
136             if( p_current->p_next->psz_action )
137                 free( p_current->p_next->psz_action );
138             if( p_current->p_next->psz_action_down )
139                 free( p_current->p_next->psz_action_down );
140             if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
141                 free( p_current->p_feedback->p_data_orig );
142             if( p_current->p_feedback )
143                 free( p_current->p_feedback );
144
145             p_current->p_feedback = NULL;
146
147             /* Free all states first */
148             if( p_current->p_next->p_states )
149                 osd_StatesFree( p_menu, p_current->p_next->p_states );
150
151             free( p_current->p_next );
152             p_current->p_next = NULL;
153         }
154
155         if( p_current->p_up )
156         {
157             if( p_current->p_up->psz_name )
158                 free( p_current->p_up->psz_name );
159             if( p_current->p_up->psz_action )
160                 free( p_current->p_up->psz_action );
161             if( p_current->p_up->psz_action_down )
162                 free( p_current->p_up->psz_action_down );
163             if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
164                 free( p_current->p_feedback->p_data_orig );
165             if( p_current->p_feedback )
166                 free( p_current->p_feedback );
167
168             p_current->p_feedback = NULL;
169
170             /* Free all states first */
171             if( p_current->p_up->p_states )
172                 osd_StatesFree( p_menu, p_current->p_up->p_states );
173             free( p_current->p_up );
174             p_current->p_up = NULL;
175         }
176     }
177     /* Free the last one. */
178     if( p_button )
179     {
180         msg_Dbg( p_menu, "+ freeing button %s [%p]",
181                  p_button->psz_action, p_button );
182         if( p_button->psz_name ) free( p_button->psz_name );
183         if( p_button->psz_action ) free( p_button->psz_action );
184         if( p_button->psz_action_down ) free( p_button->psz_action_down );
185         if( p_current->p_feedback && p_current->p_feedback->p_data_orig )
186             free( p_current->p_feedback->p_data_orig );
187         if( p_current->p_feedback )
188             free( p_current->p_feedback );
189         p_current->p_feedback = NULL;
190
191         if( p_button->p_states )
192             osd_StatesFree( p_menu, p_button->p_states );
193
194         free( p_button );
195         p_button = NULL;
196     }
197 }
198
199 /*****************************************************************************
200  * Create a new state image
201  *****************************************************************************/
202 osd_state_t *osd_StateNew( osd_menu_t *p_menu, const char *psz_file,
203                            const char *psz_state )
204 {
205     osd_state_t *p_state = NULL;
206     video_format_t fmt_in, fmt_out;
207
208     p_state = (osd_state_t*) malloc( sizeof(osd_state_t) );
209     if( !p_state )
210         return NULL;
211
212     memset( p_state, 0, sizeof(osd_state_t) );
213     memset( &fmt_in, 0, sizeof(video_format_t) );
214     memset( &fmt_out, 0, sizeof(video_format_t) );
215
216     fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
217     if( p_menu->p_image )
218     {
219         p_state->p_pic = image_ReadUrl( p_menu->p_image, psz_file,
220                                         &fmt_in, &fmt_out );
221
222         p_state->i_width  = p_state->p_pic->p[Y_PLANE].i_visible_pitch;
223         p_state->i_height = p_state->p_pic->p[Y_PLANE].i_visible_lines;
224     }
225
226     if( psz_state )
227     {
228         p_state->psz_state = strdup( psz_state );
229         if( strncmp( ppsz_button_states[0], psz_state,
230                      strlen(ppsz_button_states[0]) ) == 0 )
231             p_state->i_state = OSD_BUTTON_UNSELECT;
232         else if( strncmp( ppsz_button_states[1], psz_state,
233                           strlen(ppsz_button_states[1]) ) == 0 )
234             p_state->i_state = OSD_BUTTON_SELECT;
235         else if( strncmp( ppsz_button_states[2], psz_state,
236                           strlen(ppsz_button_states[2]) ) == 0 )
237             p_state->i_state = OSD_BUTTON_PRESSED;
238     }
239     return p_state;
240 }
241
242 /*****************************************************************************
243  * Free state images
244  *****************************************************************************/
245 void osd_StatesFree( osd_menu_t *p_menu, osd_state_t *p_states )
246 {
247     osd_state_t *p_state = p_states;
248     osd_state_t *p_next = NULL;
249     osd_state_t *p_prev = NULL;
250
251     while( p_state->p_next )
252     {
253         p_next = p_state->p_next;
254         p_state = p_next;
255     }
256     /* Then free end first and walk to the start. */
257     while( p_state->p_prev )
258     {
259         msg_Dbg( p_menu, " |- freeing state %s [%p]",
260                  p_state->psz_state, p_state );
261         p_prev = p_state->p_prev;
262         p_state = p_prev;
263         if( p_state->p_next )
264         {
265             if( p_state->p_next->p_pic )
266             {
267                 if( p_state->p_next->p_pic->p_data_orig )
268                     free( p_state->p_next->p_pic->p_data_orig );
269                 free( p_state->p_next->p_pic );
270             }
271             if( p_state->p_next->psz_state )
272                 free( p_state->p_next->psz_state );
273             free( p_state->p_next );
274             p_state->p_next = NULL;
275         }
276     }
277     /* Free the last one. */
278     if( p_states )
279     {
280         msg_Dbg( p_menu, " |- freeing state %s [%p]",
281                  p_state->psz_state, p_states );
282         if( p_states->p_pic )
283         {
284             if( p_states->p_pic->p_data_orig )
285                 free( p_states->p_pic->p_data_orig );
286             free( p_states->p_pic );
287         }
288         if( p_state->psz_state ) free( p_state->psz_state );
289         free( p_states );
290         p_states = NULL;
291     }
292 }