1 /*****************************************************************************
2 * osd.c - The OSD Menu core code.
3 *****************************************************************************
4 * Copyright (C) 2005-2007 M2X
7 * Authors: Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_image.h>
37 static const char *ppsz_button_states[] = { "unselect", "select", "pressed" };
39 /*****************************************************************************
41 *****************************************************************************/
43 static void osd_UpdateState( osd_menu_state_t *, int, int, int, int, picture_t * );
44 static inline osd_state_t *osd_VolumeStateChange( osd_state_t *, int );
45 static int osd_VolumeStep( vlc_object_t *, int, int );
46 static vlc_bool_t osd_isVisible( osd_menu_t *p_osd );
47 static osd_menu_t *osd_ParserLoad( vlc_object_t *, const char * );
48 static void osd_ParserUnload( vlc_object_t *, osd_menu_t * );
50 static vlc_bool_t osd_isVisible( osd_menu_t *p_osd )
54 var_Get( p_osd, "osd-menu-visible", &val );
58 /*****************************************************************************
59 * Wrappers for loading and unloading osd parser modules.
60 *****************************************************************************/
61 static osd_menu_t *osd_ParserLoad( vlc_object_t *p_this, const char *psz_file )
65 p_menu = vlc_object_create( p_this, VLC_OBJECT_OSDMENU );
68 msg_Err( p_this, "out of memory" );
71 vlc_object_yield( p_menu );
72 vlc_object_attach( p_menu, p_this->p_libvlc );
74 /* Stuff needed for Parser */
75 p_menu->psz_file = strdup( psz_file );
76 p_menu->p_image = image_HandlerCreate( p_this );
77 if( !p_menu->p_image || !p_menu->psz_file )
79 msg_Err( p_this, "unable to load images, aborting .." );
80 osd_ParserUnload( p_this, p_menu );
86 char *psz_ext = strrchr( p_menu->psz_file, '.' );
88 if( psz_ext && !strcmp( psz_ext, ".cfg") )
89 psz_type = "import-osd";
91 psz_type = "import-osd-xml";
93 p_menu->p_parser = module_Need( p_menu, "osd parser",
95 if( !p_menu->p_parser )
97 osd_ParserUnload( p_this, p_menu );
104 static void osd_ParserUnload( vlc_object_t *p_this, osd_menu_t *p_menu )
106 if( p_menu->p_image )
107 image_HandlerDelete( p_menu->p_image );
108 if( p_menu->psz_file )
109 free( p_menu->psz_file );
111 if( p_menu->p_parser )
112 module_Unneed( p_menu, p_menu->p_parser );
114 vlc_object_detach( p_menu );
115 vlc_object_destroy( p_menu );
119 * Change state on an osd_button_t.
121 * This function selects the specified state and returns a pointer to it. The
122 * following states are currently supported:
123 * \see OSD_BUTTON_UNSELECT
124 * \see OSD_BUTTON_SELECT
125 * \see OSD_BUTTON_PRESSED
127 static osd_state_t *osd_StateChange( osd_button_t *p_button, const int i_state )
129 osd_state_t *p_current = p_button->p_states;
130 osd_state_t *p_temp = NULL;
133 for( i=0; p_current != NULL; i++ )
135 if( p_current->i_state == i_state )
137 p_button->i_x = p_current->i_x;
138 p_button->i_y = p_current->i_y;
139 p_button->i_width = p_current->i_width;
140 p_button->i_height = p_current->i_height;
143 p_temp = p_current->p_next;
146 return p_button->p_states;
149 /*****************************************************************************
151 *****************************************************************************/
152 osd_menu_t *__osd_MenuCreate( vlc_object_t *p_this, const char *psz_file )
154 osd_menu_t *p_osd = NULL;
159 /* to be sure to avoid multiple creation */
160 var_Create( p_this->p_libvlc, "osd_mutex", VLC_VAR_MUTEX );
161 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
162 vlc_mutex_lock( lockval.p_address );
164 p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
169 /* Parse configuration file */
170 p_osd = osd_ParserLoad( p_this, psz_file );
174 /* Setup default button (first button) */
175 p_osd->p_state->p_visible = p_osd->p_button;
176 p_osd->p_state->p_visible->p_current_state =
177 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
178 p_osd->i_width = p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_pitch;
179 p_osd->i_height = p_osd->p_state->p_visible->p_current_state->p_pic->p[Y_PLANE].i_visible_lines;
181 if( p_osd->p_state->p_volume )
183 /* Update the volume state images to match the current volume */
184 i_volume = config_GetInt( p_this, "volume" );
185 i_steps = osd_VolumeStep( p_this, i_volume, p_osd->p_state->p_volume->i_ranges );
186 p_osd->p_state->p_volume->p_current_state = osd_VolumeStateChange(
187 p_osd->p_state->p_volume->p_states, i_steps );
189 /* Initialize OSD state */
190 osd_UpdateState( p_osd->p_state, p_osd->i_x, p_osd->i_y,
191 p_osd->i_width, p_osd->i_height, NULL );
193 /* Signal when an update of OSD menu is needed */
194 var_Create( p_osd, "osd-menu-update", VLC_VAR_BOOL );
195 var_Create( p_osd, "osd-menu-visible", VLC_VAR_BOOL );
197 val.b_bool = VLC_FALSE;
198 var_Set( p_osd, "osd-menu-update", val );
199 var_Set( p_osd, "osd-menu-visible", val );
201 vlc_mutex_unlock( lockval.p_address );
205 msg_Err( p_this, "creating OSD menu object failed" );
208 image_HandlerDelete( p_osd->p_image );
209 if( p_osd->psz_file )
210 free( p_osd->psz_file );
212 vlc_object_detach( p_osd );
213 vlc_object_destroy( p_osd );
214 vlc_mutex_unlock( lockval.p_address );
218 void __osd_MenuDelete( vlc_object_t *p_this, osd_menu_t *p_osd )
222 if( !p_osd || !p_this ) return;
224 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
225 vlc_mutex_lock( lockval.p_address );
227 vlc_object_release( p_osd );
228 if( p_osd->p_internals->i_refcount > 0 )
230 vlc_mutex_unlock( lockval.p_address );
234 var_Destroy( p_osd, "osd-menu-visible" );
235 var_Destroy( p_osd, "osd-menu-update" );
237 osd_ParserUnload( p_this, p_osd );
239 vlc_mutex_unlock( lockval.p_address );
242 /* The volume can be modified in another interface while the OSD Menu
243 * has not been instantiated yet. This routines updates the "volume OSD menu item"
244 * to reflect the current state of the GUI.
246 static inline osd_state_t *osd_VolumeStateChange( osd_state_t *p_current, int i_steps )
248 osd_state_t *p_temp = NULL;
251 if( i_steps < 0 ) i_steps = 0;
253 for( i=0; (i < i_steps) && (p_current != NULL); i++ )
255 p_temp = p_current->p_next;
256 if( !p_temp ) return p_current;
259 return (!p_temp) ? p_current : p_temp;
262 /* Update the state of the OSD Menu */
263 static void osd_UpdateState( osd_menu_state_t *p_state, int i_x, int i_y,
264 int i_width, int i_height, picture_t *p_pic )
268 p_state->i_width = i_width;
269 p_state->i_height = i_height;
270 p_state->p_pic = p_pic;
273 void __osd_MenuShow( vlc_object_t *p_this )
275 osd_menu_t *p_osd = NULL;
276 osd_button_t *p_button = NULL;
279 p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
282 msg_Err( p_this, "osd_MenuNext failed" );
286 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
287 vlc_mutex_lock( lockval.p_address );
289 #if defined(OSD_MENU_DEBUG)
290 msg_Dbg( p_osd, "menu on" );
292 p_button = p_osd->p_state->p_visible;
295 if( !p_button->b_range )
296 p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_UNSELECT );
297 p_osd->p_state->p_visible = p_osd->p_button;
299 if( !p_osd->p_state->p_visible->b_range )
300 p_osd->p_state->p_visible->p_current_state =
301 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
303 osd_UpdateState( p_osd->p_state,
304 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
305 p_osd->p_state->p_visible->p_current_state->i_width,
306 p_osd->p_state->p_visible->p_current_state->i_height,
307 p_osd->p_state->p_visible->p_current_state->p_pic );
308 osd_SetMenuUpdate( p_osd, VLC_TRUE );
310 osd_SetMenuVisible( p_osd, VLC_TRUE );
312 vlc_object_release( (vlc_object_t*) p_osd );
313 vlc_mutex_unlock( lockval.p_address );
316 void __osd_MenuHide( vlc_object_t *p_this )
318 osd_menu_t *p_osd = NULL;
321 p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
324 msg_Err( p_this, "osd_MenuNext failed" );
328 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
329 vlc_mutex_lock( lockval.p_address );
331 #if defined(OSD_MENU_DEBUG)
332 msg_Dbg( p_osd, "menu off" );
334 osd_UpdateState( p_osd->p_state,
335 p_osd->p_state->i_x, p_osd->p_state->i_y,
337 osd_SetMenuUpdate( p_osd, VLC_TRUE );
339 vlc_object_release( (vlc_object_t*) p_osd );
340 vlc_mutex_unlock( lockval.p_address );
343 void __osd_MenuActivate( vlc_object_t *p_this )
345 osd_menu_t *p_osd = NULL;
346 osd_button_t *p_button = NULL;
349 p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
352 msg_Err( p_this, "osd_MenuNext failed" );
356 if( osd_isVisible( p_osd ) == VLC_FALSE )
358 vlc_object_release( (vlc_object_t*) p_osd );
362 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
363 vlc_mutex_lock( lockval.p_address );
365 #if defined(OSD_MENU_DEBUG)
366 msg_Dbg( p_osd, "select" );
368 p_button = p_osd->p_state->p_visible;
370 * Is there a menu item above or below? If so, then select it.
372 if( p_button && p_button->p_up )
374 vlc_object_release( (vlc_object_t*) p_osd );
375 vlc_mutex_unlock( lockval.p_address );
376 __osd_MenuUp( p_this ); /* "menu select" means go to menu item above. */
379 if( p_button && p_button->p_down )
381 vlc_object_release( (vlc_object_t*) p_osd );
382 vlc_mutex_unlock( lockval.p_address );
383 __osd_MenuDown( p_this ); /* "menu select" means go to menu item below. */
387 if( p_button && !p_button->b_range )
389 p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_PRESSED );
390 osd_UpdateState( p_osd->p_state,
391 p_button->i_x, p_button->i_y,
392 p_osd->p_state->p_visible->p_current_state->i_width,
393 p_osd->p_state->p_visible->p_current_state->i_height,
394 p_button->p_current_state->p_pic );
395 osd_SetMenuUpdate( p_osd, VLC_TRUE );
396 osd_SetMenuVisible( p_osd, VLC_TRUE );
397 osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc), config_GetInt( p_osd, p_button->psz_action ) );
398 #if defined(OSD_MENU_DEBUG)
399 msg_Dbg( p_osd, "select (%d, %s)", config_GetInt( p_osd, p_button->psz_action ), p_button->psz_action );
402 vlc_object_release( (vlc_object_t*) p_osd );
403 vlc_mutex_unlock( lockval.p_address );
406 void __osd_MenuNext( vlc_object_t *p_this )
408 osd_menu_t *p_osd = NULL;
409 osd_button_t *p_button = NULL;
412 p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
415 msg_Err( p_this, "osd_MenuNext failed" );
419 if( osd_isVisible( p_osd ) == VLC_FALSE )
421 vlc_object_release( (vlc_object_t*) p_osd );
425 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
426 vlc_mutex_lock( lockval.p_address );
428 p_button = p_osd->p_state->p_visible;
431 if( !p_button->b_range )
432 p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_UNSELECT );
433 if( p_button->p_next )
434 p_osd->p_state->p_visible = p_button->p_next;
436 p_osd->p_state->p_visible = p_osd->p_button;
438 if( !p_osd->p_state->p_visible->b_range )
439 p_osd->p_state->p_visible->p_current_state =
440 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
442 osd_UpdateState( p_osd->p_state,
443 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
444 p_osd->p_state->p_visible->p_current_state->i_width,
445 p_osd->p_state->p_visible->p_current_state->i_height,
446 p_osd->p_state->p_visible->p_current_state->p_pic );
447 osd_SetMenuUpdate( p_osd, VLC_TRUE );
449 #if defined(OSD_MENU_DEBUG)
450 msg_Dbg( p_osd, "direction right [button %s]", p_osd->p_state->p_visible->psz_action );
453 vlc_object_release( (vlc_object_t*) p_osd );
454 vlc_mutex_unlock( lockval.p_address );
457 void __osd_MenuPrev( vlc_object_t *p_this )
459 osd_menu_t *p_osd = NULL;
460 osd_button_t *p_button = NULL;
463 p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
466 msg_Err( p_this, "osd_MenuPrev failed" );
470 if( osd_isVisible( p_osd ) == VLC_FALSE )
472 vlc_object_release( (vlc_object_t*) p_osd );
476 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
477 vlc_mutex_lock( lockval.p_address );
479 p_button = p_osd->p_state->p_visible;
482 if( !p_button->b_range )
483 p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_UNSELECT );
484 if( p_button->p_prev )
485 p_osd->p_state->p_visible = p_button->p_prev;
487 p_osd->p_state->p_visible = p_osd->p_last_button;
489 if( !p_osd->p_state->p_visible->b_range )
490 p_osd->p_state->p_visible->p_current_state =
491 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
493 osd_UpdateState( p_osd->p_state,
494 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
495 p_osd->p_state->p_visible->p_current_state->i_width,
496 p_osd->p_state->p_visible->p_current_state->i_height,
497 p_osd->p_state->p_visible->p_current_state->p_pic );
498 osd_SetMenuUpdate( p_osd, VLC_TRUE );
500 #if defined(OSD_MENU_DEBUG)
501 msg_Dbg( p_osd, "direction left [button %s]", p_osd->p_state->p_visible->psz_action );
504 vlc_object_release( (vlc_object_t*) p_osd );
505 vlc_mutex_unlock( lockval.p_address );
508 void __osd_MenuUp( vlc_object_t *p_this )
510 osd_menu_t *p_osd = NULL;
511 osd_button_t *p_button = NULL;
513 #if defined(OSD_MENU_DEBUG)
516 p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
519 msg_Err( p_this, "osd_MenuDown failed" );
523 if( osd_isVisible( p_osd ) == VLC_FALSE )
525 vlc_object_release( (vlc_object_t*) p_osd );
529 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
530 vlc_mutex_lock( lockval.p_address );
532 p_button = p_osd->p_state->p_visible;
535 if( !p_button->b_range )
537 p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_SELECT );
539 p_osd->p_state->p_visible = p_button->p_up;
542 if( p_button->b_range && p_osd->p_state->p_visible->b_range )
544 osd_state_t *p_temp = p_osd->p_state->p_visible->p_current_state;
545 if( p_temp && p_temp->p_next )
546 p_osd->p_state->p_visible->p_current_state = p_temp->p_next;
548 else if( !p_osd->p_state->p_visible->b_range )
550 p_osd->p_state->p_visible->p_current_state =
551 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
554 osd_UpdateState( p_osd->p_state,
555 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
556 p_osd->p_state->p_visible->p_current_state->i_width,
557 p_osd->p_state->p_visible->p_current_state->i_height,
558 p_osd->p_state->p_visible->p_current_state->p_pic );
559 osd_SetMenuUpdate( p_osd, VLC_TRUE );
560 /* If this is a range style action with associated images of only one state,
561 * then perform "menu select" on every menu navigation
563 if( p_button->b_range )
565 osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc), config_GetInt(p_osd, p_button->psz_action) );
566 #if defined(OSD_MENU_DEBUG)
567 msg_Dbg( p_osd, "select (%d, %s)", val.i_int, p_button->psz_action );
571 #if defined(OSD_MENU_DEBUG)
572 msg_Dbg( p_osd, "direction up [button %s]", p_osd->p_state->p_visible->psz_action );
575 vlc_object_release( (vlc_object_t*) p_osd );
576 vlc_mutex_unlock( lockval.p_address );
579 void __osd_MenuDown( vlc_object_t *p_this )
581 osd_menu_t *p_osd = NULL;
582 osd_button_t *p_button = NULL;
584 #if defined(OSD_MENU_DEBUG)
588 p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
591 msg_Err( p_this, "osd_MenuDown failed" );
595 if( osd_isVisible( p_osd ) == VLC_FALSE )
597 vlc_object_release( (vlc_object_t*) p_osd );
601 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
602 vlc_mutex_lock( lockval.p_address );
604 p_button = p_osd->p_state->p_visible;
607 if( !p_button->b_range )
609 p_button->p_current_state = osd_StateChange( p_button, OSD_BUTTON_SELECT );
610 if( p_button->p_down )
611 p_osd->p_state->p_visible = p_button->p_down;
614 if( p_button->b_range && p_osd->p_state->p_visible->b_range )
616 osd_state_t *p_temp = p_osd->p_state->p_visible->p_current_state;
617 if( p_temp && p_temp->p_prev )
618 p_osd->p_state->p_visible->p_current_state = p_temp->p_prev;
620 else if( !p_osd->p_state->p_visible->b_range )
622 p_osd->p_state->p_visible->p_current_state =
623 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
626 osd_UpdateState( p_osd->p_state,
627 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
628 p_osd->p_state->p_visible->p_current_state->i_width,
629 p_osd->p_state->p_visible->p_current_state->i_height,
630 p_osd->p_state->p_visible->p_current_state->p_pic );
631 osd_SetMenuUpdate( p_osd, VLC_TRUE );
632 /* If this is a range style action with associated images of only one state,
633 * then perform "menu select" on every menu navigation
635 if( p_button->b_range )
637 osd_SetKeyPressed( VLC_OBJECT(p_osd->p_libvlc), config_GetInt(p_osd, p_button->psz_action_down) );
638 #if defined(OSD_MENU_DEBUG)
639 msg_Dbg( p_osd, "select (%d, %s)", val.i_int, p_button->psz_action_down );
643 #if defined(OSD_MENU_DEBUG)
644 msg_Dbg( p_osd, "direction down [button %s]", p_osd->p_state->p_visible->psz_action );
647 vlc_object_release( (vlc_object_t*) p_osd );
648 vlc_mutex_unlock( lockval.p_address );
651 static int osd_VolumeStep( vlc_object_t *p_this, int i_volume, int i_steps )
653 int i_volume_step = 0;
656 i_volume_step = config_GetInt( p_this->p_libvlc, "volume-step" );
657 return (i_volume/i_volume_step);
661 * Display current audio volume bitmap
663 * The OSD Menu audio volume bar is updated to reflect the new audio volume. Call this function
664 * when the audio volume is updated outside the OSD menu command "menu up", "menu down" or "menu select".
666 void __osd_Volume( vlc_object_t *p_this )
668 osd_menu_t *p_osd = NULL;
669 osd_button_t *p_button = NULL;
674 p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
677 msg_Err( p_this, "OSD menu volume update failed" );
681 if( p_osd->p_state && p_osd->p_state->p_volume )
683 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
684 vlc_mutex_lock( lockval.p_address );
686 p_button = p_osd->p_state->p_volume;
687 if( p_osd->p_state->p_volume )
688 p_osd->p_state->p_visible = p_osd->p_state->p_volume;
689 if( p_button && p_button->b_range )
691 /* Update the volume state images to match the current volume */
692 i_volume = config_GetInt( p_this, "volume" );
693 i_steps = osd_VolumeStep( p_this, i_volume, p_button->i_ranges );
694 p_button->p_current_state = osd_VolumeStateChange( p_button->p_states, i_steps );
696 osd_UpdateState( p_osd->p_state,
697 p_button->i_x, p_button->i_y,
698 p_button->p_current_state->i_width,
699 p_button->p_current_state->i_height,
700 p_button->p_current_state->p_pic );
701 osd_SetMenuUpdate( p_osd, VLC_TRUE );
702 osd_SetMenuVisible( p_osd, VLC_TRUE );
704 vlc_object_release( (vlc_object_t*) p_osd );
705 vlc_mutex_unlock( lockval.p_address );
709 osd_button_t *__osd_ButtonFind( vlc_object_t *p_this, int i_x, int i_y,
710 int i_window_height, int i_window_width,
711 int i_scale_width, int i_scale_height )
714 osd_button_t *p_button, *p_start, *p_end;
717 p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
720 msg_Err( p_this, "OSD menu button find failed" );
724 if( osd_isVisible( p_osd ) == VLC_FALSE )
726 vlc_object_release( (vlc_object_t*) p_osd );
730 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
731 vlc_mutex_lock( lockval.p_address );
733 p_button = p_osd->p_button;
734 for( ; p_button != NULL; p_button = p_button->p_next )
736 int i_source_video_width = ( i_window_width * 1000 ) / i_scale_width;
737 int i_source_video_height = ( i_window_height * 1000 ) / i_scale_height;
738 int i_y_offset = p_button->i_y;
739 int i_x_offset = p_button->i_x;
740 int i_width = p_button->i_width;
741 int i_height = p_button->i_height;
743 if( p_osd->i_position > 0 )
745 int i_inv_scale_y = i_source_video_height;
746 int i_inv_scale_x = i_source_video_width;
749 if( p_osd->i_position & SUBPICTURE_ALIGN_BOTTOM )
751 i_y_offset = i_window_height - p_button->i_height -
752 (p_osd->i_y + p_button->i_y) * i_inv_scale_y / 1000;
754 else if ( !(p_osd->i_position & SUBPICTURE_ALIGN_TOP) )
756 i_y_offset = i_window_height / 2 - p_button->i_height / 2;
759 if( p_osd->i_position & SUBPICTURE_ALIGN_RIGHT )
761 i_x_offset = i_window_width - p_button->i_width -
762 (pi_x + p_button->i_x)
763 * i_inv_scale_x / 1000;
765 else if ( !(p_osd->i_position & SUBPICTURE_ALIGN_LEFT) )
767 i_x_offset = i_window_width / 2 - p_button->i_width / 2;
770 i_width = i_window_width - p_button->i_width - i_inv_scale_x / 1000;
771 i_height = i_window_height - p_button->i_height - i_inv_scale_y / 1000;
774 // TODO: write for Up / Down case too.
775 // TODO: handle absolute positioning case
776 if( ( i_x >= i_x_offset ) && ( i_x <= i_x_offset + i_width ) &&
777 ( i_y >= i_y_offset ) && ( i_y <= i_y_offset + i_height ) )
779 vlc_object_release( (vlc_object_t*) p_osd );
780 vlc_mutex_unlock( lockval.p_address );
785 vlc_object_release( (vlc_object_t*) p_osd );
786 vlc_mutex_unlock( lockval.p_address );
791 * Select the button provided as the new active button
793 void __osd_ButtonSelect( vlc_object_t *p_this, osd_button_t *p_button )
799 p_osd = vlc_object_find( p_this, VLC_OBJECT_OSDMENU, FIND_ANYWHERE );
802 msg_Err( p_this, "OSD menu button select failed" );
806 if( osd_isVisible( p_osd ) == VLC_FALSE )
808 vlc_object_release( (vlc_object_t*) p_osd );
812 var_Get( p_this->p_libvlc, "osd_mutex", &lockval );
813 vlc_mutex_lock( lockval.p_address );
815 p_old = p_osd->p_state->p_visible;
818 if( !p_old->b_range )
819 p_old->p_current_state = osd_StateChange( p_old, OSD_BUTTON_UNSELECT );
820 p_osd->p_state->p_visible = p_button;
822 if( !p_osd->p_state->p_visible->b_range )
823 p_osd->p_state->p_visible->p_current_state =
824 osd_StateChange( p_osd->p_state->p_visible, OSD_BUTTON_SELECT );
826 osd_UpdateState( p_osd->p_state,
827 p_osd->p_state->p_visible->i_x, p_osd->p_state->p_visible->i_y,
828 p_osd->p_state->p_visible->p_current_state->i_width,
829 p_osd->p_state->p_visible->p_current_state->i_height,
830 p_osd->p_state->p_visible->p_current_state->p_pic );
831 osd_SetMenuUpdate( p_osd, VLC_TRUE );
833 #if defined(OSD_MENU_DEBUG)
834 msg_Dbg( p_osd, "button selected is [button %s]", p_osd->p_state->p_visible->psz_action );
837 vlc_object_release( (vlc_object_t*) p_osd );
838 vlc_mutex_unlock( lockval.p_address );