1 /*****************************************************************************
2 * osd.c - The OSD Menu core code.
3 *****************************************************************************
4 * Copyright (C) 2005-2008 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 *****************************************************************************/
32 #include <vlc_common.h>
35 #include <vlc_image.h>
36 #include <vlc_modules.h>
42 /*****************************************************************************
44 *****************************************************************************/
46 static void osd_UpdateState( osd_menu_state_t
*, int, int, int, int, picture_t
* );
47 static inline osd_state_t
*osd_VolumeStateChange( osd_state_t
*, int );
48 static int osd_VolumeStep( vlc_object_t
*, int, int );
49 static bool osd_ParserLoad( osd_menu_t
*, const char * );
50 static void osd_ParserUnload( osd_menu_t
* );
52 static inline bool osd_isVisible( osd_menu_t
*p_osd
)
54 return var_GetBool( p_osd
, "osd-menu-visible" );
57 static vlc_mutex_t
*osd_GetMutex( vlc_object_t
*p_this
)
61 var_Create( p_this
->p_libvlc
, "osd_mutex", VLC_VAR_MUTEX
);
62 var_Get( p_this
->p_libvlc
, "osd_mutex", &lockval
);
63 return lockval
.p_address
;
66 /*****************************************************************************
67 * Wrappers for loading and unloading osd parser modules.
68 *****************************************************************************/
69 static bool osd_ParserLoad( osd_menu_t
*p_menu
, const char *psz_file
)
71 /* Stuff needed for Parser */
72 p_menu
->psz_file
= strdup( psz_file
);
73 p_menu
->p_image
= image_HandlerCreate( p_menu
);
74 if( !p_menu
->p_image
|| !p_menu
->psz_file
)
76 msg_Err( p_menu
, "unable to load images, aborting .." );
82 const char *psz_ext
= strrchr( p_menu
->psz_file
, '.' );
84 if( psz_ext
&& !strcmp( psz_ext
, ".cfg") )
85 psz_type
= "import-osd";
87 psz_type
= "import-osd-xml";
89 p_menu
->p_parser
= module_need( p_menu
, "osd parser",
91 if( !p_menu
->p_parser
)
99 static void osd_ParserUnload( osd_menu_t
*p_menu
)
101 if( p_menu
->p_image
)
102 image_HandlerDelete( p_menu
->p_image
);
104 if( p_menu
->p_parser
)
105 module_unneed( p_menu
, p_menu
->p_parser
);
107 free( p_menu
->psz_file
);
111 * Change state on an osd_button_t.
113 * This function selects the specified state and returns a pointer
114 * vlc_custom_create to it. The following states are currently supported:
115 * \see OSD_BUTTON_UNSELECT
116 * \see OSD_BUTTON_SELECT
117 * \see OSD_BUTTON_PRESSED
119 static osd_state_t
*osd_StateChange( osd_button_t
*p_button
, const int i_state
)
121 osd_state_t
*p_current
= p_button
->p_states
;
122 osd_state_t
*p_temp
= NULL
;
125 for( i
= 0; p_current
!= NULL
; i
++ )
127 if( p_current
->i_state
== i_state
)
129 p_button
->i_x
= p_current
->i_x
;
130 p_button
->i_y
= p_current
->i_y
;
131 p_button
->i_width
= p_current
->i_width
;
132 p_button
->i_height
= p_current
->i_height
;
135 p_temp
= p_current
->p_next
;
138 return p_button
->p_states
;
141 #undef osd_MenuCreate
142 /*****************************************************************************
144 *****************************************************************************/
145 osd_menu_t
*osd_MenuCreate( vlc_object_t
*p_this
, const char *psz_file
)
147 osd_menu_t
*p_osd
= NULL
;
153 /* to be sure to avoid multiple creation */
154 p_lock
= osd_GetMutex( p_this
);
155 vlc_mutex_lock( p_lock
);
157 var_Create( p_this
->p_libvlc
, "osd-object", VLC_VAR_ADDRESS
);
158 var_Get( p_this
->p_libvlc
, "osd-object", &val
);
159 if( val
.p_address
== NULL
)
161 static const char osdmenu_name
[] = "osd menu";
163 p_osd
= vlc_custom_create( p_this
, sizeof( *p_osd
),
164 VLC_OBJECT_GENERIC
, osdmenu_name
);
168 p_osd
->p_parser
= NULL
;
169 vlc_object_attach( p_osd
, p_this
->p_libvlc
);
171 /* Parse configuration file */
172 if ( !osd_ParserLoad( p_osd
, psz_file
) )
174 if( !p_osd
->p_state
)
177 /* Setup default button (first button) */
178 p_osd
->p_state
->p_visible
= p_osd
->p_button
;
179 p_osd
->p_state
->p_visible
->p_current_state
=
180 osd_StateChange( p_osd
->p_state
->p_visible
, OSD_BUTTON_SELECT
);
181 p_osd
->i_width
= p_osd
->p_state
->p_visible
->p_current_state
->p_pic
->p
[Y_PLANE
].i_visible_pitch
;
182 p_osd
->i_height
= p_osd
->p_state
->p_visible
->p_current_state
->p_pic
->p
[Y_PLANE
].i_visible_lines
;
184 if( p_osd
->p_state
->p_volume
)
186 /* Update the volume state images to match the current volume */
187 i_volume
= config_GetInt( p_this
, "volume" );
188 i_steps
= osd_VolumeStep( p_this
, i_volume
, p_osd
->p_state
->p_volume
->i_ranges
);
189 p_osd
->p_state
->p_volume
->p_current_state
= osd_VolumeStateChange(
190 p_osd
->p_state
->p_volume
->p_states
, i_steps
);
192 /* Initialize OSD state */
193 osd_UpdateState( p_osd
->p_state
, p_osd
->i_x
, p_osd
->i_y
,
194 p_osd
->i_width
, p_osd
->i_height
, NULL
);
196 /* Signal when an update of OSD menu is needed */
197 var_Create( p_osd
, "osd-menu-update", VLC_VAR_BOOL
);
198 var_Create( p_osd
, "osd-menu-visible", VLC_VAR_BOOL
);
200 var_SetBool( p_osd
, "osd-menu-update", false );
201 var_SetBool( p_osd
, "osd-menu-visible", false );
203 var_SetAddress( p_this
->p_libvlc
, "osd-object", p_osd
);
206 p_osd
= val
.p_address
;
207 vlc_object_hold( p_osd
);
208 vlc_mutex_unlock( p_lock
);
212 vlc_mutex_unlock( p_lock
);
213 osd_MenuDelete( p_this
, p_osd
);
217 #undef osd_MenuDelete
218 void osd_MenuDelete( vlc_object_t
*p_this
, osd_menu_t
*p_osd
)
222 if( !p_osd
|| !p_this
) return;
224 p_lock
= osd_GetMutex( p_this
);
225 vlc_mutex_lock( p_lock
);
227 if( vlc_internals( VLC_OBJECT(p_osd
) )->i_refcount
== 1 )
229 var_Destroy( p_osd
, "osd-menu-visible" );
230 var_Destroy( p_osd
, "osd-menu-update" );
231 osd_ParserUnload( p_osd
);
232 var_SetAddress( p_this
->p_libvlc
, "osd-object", NULL
);
235 vlc_object_release( p_osd
);
236 vlc_mutex_unlock( p_lock
);
239 static osd_menu_t
*osd_Find( vlc_object_t
*p_this
)
243 if( var_Get( p_this
->p_libvlc
, "osd-object", &val
) )
245 return val
.p_address
;
248 /* The volume can be modified in another interface while the OSD Menu
249 * has not been instantiated yet. This routines updates the "volume OSD menu item"
250 * to reflect the current state of the GUI.
252 static inline osd_state_t
*osd_VolumeStateChange( osd_state_t
*p_current
, int i_steps
)
254 osd_state_t
*p_temp
= NULL
;
257 if( i_steps
< 0 ) i_steps
= 0;
259 for( i
=0; (i
< i_steps
) && (p_current
!= NULL
); i
++ )
261 p_temp
= p_current
->p_next
;
262 if( !p_temp
) return p_current
;
265 return (!p_temp
) ? p_current
: p_temp
;
268 /* Update the state of the OSD Menu */
269 static void osd_UpdateState( osd_menu_state_t
*p_state
, int i_x
, int i_y
,
270 int i_width
, int i_height
, picture_t
*p_pic
)
274 p_state
->i_width
= i_width
;
275 p_state
->i_height
= i_height
;
276 p_state
->p_pic
= p_pic
;
280 void osd_MenuShow( vlc_object_t
*p_this
)
283 osd_button_t
*p_button
= NULL
;
284 vlc_mutex_t
*p_lock
= osd_GetMutex( p_this
);
286 vlc_mutex_lock( p_lock
);
287 p_osd
= osd_Find( p_this
);
290 vlc_mutex_unlock( p_lock
);
291 msg_Err( p_this
, "osd_MenuShow failed" );
295 #if defined(OSD_MENU_DEBUG)
296 msg_Dbg( p_osd
, "menu on" );
298 p_button
= p_osd
->p_state
->p_visible
;
301 if( !p_button
->b_range
)
302 p_button
->p_current_state
= osd_StateChange( p_button
, OSD_BUTTON_UNSELECT
);
303 p_osd
->p_state
->p_visible
= p_osd
->p_button
;
305 if( !p_osd
->p_state
->p_visible
->b_range
)
306 p_osd
->p_state
->p_visible
->p_current_state
=
307 osd_StateChange( p_osd
->p_state
->p_visible
, OSD_BUTTON_SELECT
);
309 osd_UpdateState( p_osd
->p_state
,
310 p_osd
->p_state
->p_visible
->i_x
, p_osd
->p_state
->p_visible
->i_y
,
311 p_osd
->p_state
->p_visible
->p_current_state
->i_width
,
312 p_osd
->p_state
->p_visible
->p_current_state
->i_height
,
313 p_osd
->p_state
->p_visible
->p_current_state
->p_pic
);
314 osd_SetMenuUpdate( p_osd
, true );
316 osd_SetMenuVisible( p_osd
, true );
318 vlc_mutex_unlock( p_lock
);
322 void osd_MenuHide( vlc_object_t
*p_this
)
325 vlc_mutex_t
*p_lock
= osd_GetMutex( p_this
);
327 vlc_mutex_lock( p_lock
);
329 p_osd
= osd_Find( p_this
);
332 vlc_mutex_unlock( p_lock
);
333 msg_Err( p_this
, "osd_MenuHide failed" );
337 #if defined(OSD_MENU_DEBUG)
338 msg_Dbg( p_osd
, "menu off" );
340 osd_UpdateState( p_osd
->p_state
,
341 p_osd
->p_state
->i_x
, p_osd
->p_state
->i_y
,
343 osd_SetMenuUpdate( p_osd
, true );
345 vlc_mutex_unlock( p_lock
);
348 #undef osd_MenuActivate
349 void osd_MenuActivate( vlc_object_t
*p_this
)
352 osd_button_t
*p_button
= NULL
;
353 vlc_mutex_t
*p_lock
= osd_GetMutex( p_this
);
355 vlc_mutex_lock( p_lock
);
357 p_osd
= osd_Find( p_this
);
358 if( p_osd
== NULL
|| !osd_isVisible( p_osd
) )
360 vlc_mutex_unlock( p_lock
);
361 msg_Err( p_this
, "osd_MenuActivate failed" );
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_mutex_unlock( p_lock
);
375 osd_MenuUp( p_this
); /* "menu select" means go to menu item above. */
378 if( p_button
&& p_button
->p_down
)
380 vlc_mutex_unlock( p_lock
);
381 osd_MenuDown( p_this
); /* "menu select" means go to menu item below. */
385 if( p_button
&& !p_button
->b_range
)
387 p_button
->p_current_state
= osd_StateChange( p_button
, OSD_BUTTON_PRESSED
);
388 osd_UpdateState( p_osd
->p_state
,
389 p_button
->i_x
, p_button
->i_y
,
390 p_osd
->p_state
->p_visible
->p_current_state
->i_width
,
391 p_osd
->p_state
->p_visible
->p_current_state
->i_height
,
392 p_button
->p_current_state
->p_pic
);
393 osd_SetMenuUpdate( p_osd
, true );
394 osd_SetMenuVisible( p_osd
, true );
395 osd_SetKeyPressed( VLC_OBJECT(p_osd
->p_libvlc
),
396 var_InheritInteger( p_osd
, p_button
->psz_action
) );
397 #if defined(OSD_MENU_DEBUG)
398 msg_Dbg( p_osd
, "select (%d, %s)",
399 (int)var_InheritInteger( p_osd
, p_button
->psz_action
),
400 p_button
->psz_action
);
403 vlc_mutex_unlock( p_lock
);
407 void osd_MenuNext( vlc_object_t
*p_this
)
410 osd_button_t
*p_button
= NULL
;
411 vlc_mutex_t
*p_lock
= osd_GetMutex( p_this
);
413 vlc_mutex_lock( p_lock
);
415 p_osd
= osd_Find( p_this
);
416 if( p_osd
== NULL
|| !osd_isVisible( p_osd
) )
418 vlc_mutex_unlock( p_lock
);
419 msg_Err( p_this
, "osd_MenuNext failed" );
423 p_button
= p_osd
->p_state
->p_visible
;
426 if( !p_button
->b_range
)
427 p_button
->p_current_state
= osd_StateChange( p_button
, OSD_BUTTON_UNSELECT
);
428 if( p_button
->p_next
)
429 p_osd
->p_state
->p_visible
= p_button
->p_next
;
431 p_osd
->p_state
->p_visible
= p_osd
->p_button
;
433 if( !p_osd
->p_state
->p_visible
->b_range
)
434 p_osd
->p_state
->p_visible
->p_current_state
=
435 osd_StateChange( p_osd
->p_state
->p_visible
, OSD_BUTTON_SELECT
);
437 osd_UpdateState( p_osd
->p_state
,
438 p_osd
->p_state
->p_visible
->i_x
, p_osd
->p_state
->p_visible
->i_y
,
439 p_osd
->p_state
->p_visible
->p_current_state
->i_width
,
440 p_osd
->p_state
->p_visible
->p_current_state
->i_height
,
441 p_osd
->p_state
->p_visible
->p_current_state
->p_pic
);
442 osd_SetMenuUpdate( p_osd
, true );
444 #if defined(OSD_MENU_DEBUG)
445 msg_Dbg( p_osd
, "direction right [button %s]", p_osd
->p_state
->p_visible
->psz_action
);
448 vlc_mutex_unlock( p_lock
);
452 void osd_MenuPrev( vlc_object_t
*p_this
)
455 osd_button_t
*p_button
= NULL
;
456 vlc_mutex_t
*p_lock
= osd_GetMutex( p_this
);
458 vlc_mutex_lock( p_lock
);
459 p_osd
= osd_Find( p_this
);
460 if( p_osd
== NULL
|| !osd_isVisible( p_osd
) )
462 vlc_mutex_unlock( p_lock
);
463 msg_Err( p_this
, "osd_MenuPrev failed" );
467 p_button
= p_osd
->p_state
->p_visible
;
470 if( !p_button
->b_range
)
471 p_button
->p_current_state
= osd_StateChange( p_button
, OSD_BUTTON_UNSELECT
);
472 if( p_button
->p_prev
)
473 p_osd
->p_state
->p_visible
= p_button
->p_prev
;
475 p_osd
->p_state
->p_visible
= p_osd
->p_last_button
;
477 if( !p_osd
->p_state
->p_visible
->b_range
)
478 p_osd
->p_state
->p_visible
->p_current_state
=
479 osd_StateChange( p_osd
->p_state
->p_visible
, OSD_BUTTON_SELECT
);
481 osd_UpdateState( p_osd
->p_state
,
482 p_osd
->p_state
->p_visible
->i_x
, p_osd
->p_state
->p_visible
->i_y
,
483 p_osd
->p_state
->p_visible
->p_current_state
->i_width
,
484 p_osd
->p_state
->p_visible
->p_current_state
->i_height
,
485 p_osd
->p_state
->p_visible
->p_current_state
->p_pic
);
486 osd_SetMenuUpdate( p_osd
, true );
488 #if defined(OSD_MENU_DEBUG)
489 msg_Dbg( p_osd
, "direction left [button %s]", p_osd
->p_state
->p_visible
->psz_action
);
492 vlc_mutex_unlock( p_lock
);
496 void osd_MenuUp( vlc_object_t
*p_this
)
499 osd_button_t
*p_button
= NULL
;
500 #if defined(OSD_MENU_DEBUG)
503 vlc_mutex_t
*p_lock
= osd_GetMutex( p_this
);
505 vlc_mutex_lock( p_lock
);
506 p_osd
= osd_Find( p_this
);
507 if( p_osd
== NULL
|| !osd_isVisible( p_osd
) )
509 vlc_mutex_unlock( p_lock
);
510 msg_Err( p_this
, "osd_MenuActivate failed" );
514 p_button
= p_osd
->p_state
->p_visible
;
517 if( !p_button
->b_range
)
519 p_button
->p_current_state
= osd_StateChange( p_button
, OSD_BUTTON_SELECT
);
521 p_osd
->p_state
->p_visible
= p_button
->p_up
;
524 if( p_button
->b_range
&& p_osd
->p_state
->p_visible
->b_range
)
526 osd_state_t
*p_temp
= p_osd
->p_state
->p_visible
->p_current_state
;
527 if( p_temp
&& p_temp
->p_next
)
528 p_osd
->p_state
->p_visible
->p_current_state
= p_temp
->p_next
;
530 else if( !p_osd
->p_state
->p_visible
->b_range
)
532 p_osd
->p_state
->p_visible
->p_current_state
=
533 osd_StateChange( p_osd
->p_state
->p_visible
, OSD_BUTTON_SELECT
);
536 osd_UpdateState( p_osd
->p_state
,
537 p_osd
->p_state
->p_visible
->i_x
, p_osd
->p_state
->p_visible
->i_y
,
538 p_osd
->p_state
->p_visible
->p_current_state
->i_width
,
539 p_osd
->p_state
->p_visible
->p_current_state
->i_height
,
540 p_osd
->p_state
->p_visible
->p_current_state
->p_pic
);
541 osd_SetMenuUpdate( p_osd
, true );
542 /* If this is a range style action with associated images of only one state,
543 * then perform "menu select" on every menu navigation
545 if( p_button
->b_range
)
547 osd_SetKeyPressed( VLC_OBJECT(p_osd
->p_libvlc
),
548 var_InheritInteger(p_osd
, p_button
->psz_action
) );
549 #if defined(OSD_MENU_DEBUG)
550 msg_Dbg( p_osd
, "select (%"PRId64
", %s)", val
.i_int
, p_button
->psz_action
);
554 #if defined(OSD_MENU_DEBUG)
555 msg_Dbg( p_osd
, "direction up [button %s]", p_osd
->p_state
->p_visible
->psz_action
);
558 vlc_mutex_unlock( p_lock
);
562 void osd_MenuDown( vlc_object_t
*p_this
)
565 osd_button_t
*p_button
= NULL
;
566 #if defined(OSD_MENU_DEBUG)
569 vlc_mutex_t
*p_lock
= osd_GetMutex( p_this
);
571 vlc_mutex_lock( p_lock
);
573 p_osd
= osd_Find( p_this
);
574 if( p_osd
== NULL
|| !osd_isVisible( p_osd
) )
576 vlc_mutex_unlock( p_lock
);
577 msg_Err( p_this
, "osd_MenuActivate failed" );
581 p_button
= p_osd
->p_state
->p_visible
;
584 if( !p_button
->b_range
)
586 p_button
->p_current_state
= osd_StateChange( p_button
, OSD_BUTTON_SELECT
);
587 if( p_button
->p_down
)
588 p_osd
->p_state
->p_visible
= p_button
->p_down
;
591 if( p_button
->b_range
&& p_osd
->p_state
->p_visible
->b_range
)
593 osd_state_t
*p_temp
= p_osd
->p_state
->p_visible
->p_current_state
;
594 if( p_temp
&& p_temp
->p_prev
)
595 p_osd
->p_state
->p_visible
->p_current_state
= p_temp
->p_prev
;
597 else if( !p_osd
->p_state
->p_visible
->b_range
)
599 p_osd
->p_state
->p_visible
->p_current_state
=
600 osd_StateChange( p_osd
->p_state
->p_visible
, OSD_BUTTON_SELECT
);
603 osd_UpdateState( p_osd
->p_state
,
604 p_osd
->p_state
->p_visible
->i_x
, p_osd
->p_state
->p_visible
->i_y
,
605 p_osd
->p_state
->p_visible
->p_current_state
->i_width
,
606 p_osd
->p_state
->p_visible
->p_current_state
->i_height
,
607 p_osd
->p_state
->p_visible
->p_current_state
->p_pic
);
608 osd_SetMenuUpdate( p_osd
, true );
609 /* If this is a range style action with associated images of only one state,
610 * then perform "menu select" on every menu navigation
612 if( p_button
->b_range
)
614 osd_SetKeyPressed( VLC_OBJECT(p_osd
->p_libvlc
),
615 var_InheritInteger(p_osd
, p_button
->psz_action_down
) );
616 #if defined(OSD_MENU_DEBUG)
617 msg_Dbg( p_osd
, "select (%"PRId64
", %s)", val
.i_int
, p_button
->psz_action_down
);
621 #if defined(OSD_MENU_DEBUG)
622 msg_Dbg( p_osd
, "direction down [button %s]", p_osd
->p_state
->p_visible
->psz_action
);
625 vlc_mutex_unlock( p_lock
);
628 static int osd_VolumeStep( vlc_object_t
*p_this
, int i_volume
, int i_steps
)
630 int i_volume_step
= 0;
633 i_volume_step
= config_GetInt( p_this
->p_libvlc
, "volume-step" );
634 return (i_volume
/i_volume_step
);
639 * Display current audio volume bitmap
641 * The OSD Menu audio volume bar is updated to reflect the new audio volume. Call this function
642 * when the audio volume is updated outside the OSD menu command "menu up", "menu down" or "menu select".
644 void osd_Volume( vlc_object_t
*p_this
)
647 osd_button_t
*p_button
= NULL
;
648 vlc_mutex_t
*p_lock
= osd_GetMutex( p_this
);
652 vlc_mutex_lock( p_lock
);
654 p_osd
= osd_Find( p_this
);
657 vlc_mutex_unlock( p_lock
);
658 msg_Err( p_this
, "OSD menu volume update failed" );
662 if( p_osd
->p_state
&& p_osd
->p_state
->p_volume
)
665 p_button
= p_osd
->p_state
->p_volume
;
666 if( p_osd
->p_state
->p_volume
)
667 p_osd
->p_state
->p_visible
= p_osd
->p_state
->p_volume
;
668 if( p_button
&& p_button
->b_range
)
670 /* Update the volume state images to match the current volume */
671 i_volume
= config_GetInt( p_this
, "volume" );
672 i_steps
= osd_VolumeStep( p_this
, i_volume
, p_button
->i_ranges
);
673 p_button
->p_current_state
= osd_VolumeStateChange( p_button
->p_states
, i_steps
);
675 osd_UpdateState( p_osd
->p_state
,
676 p_button
->i_x
, p_button
->i_y
,
677 p_button
->p_current_state
->i_width
,
678 p_button
->p_current_state
->i_height
,
679 p_button
->p_current_state
->p_pic
);
680 osd_SetMenuUpdate( p_osd
, true );
681 osd_SetMenuVisible( p_osd
, true );
684 vlc_mutex_unlock( p_lock
);
687 #undef osd_ButtonFind
688 osd_button_t
*osd_ButtonFind( vlc_object_t
*p_this
, int i_x
, int i_y
,
689 int i_window_height
, int i_window_width
,
690 int i_scale_width
, int i_scale_height
)
693 osd_button_t
*p_button
;
694 vlc_mutex_t
*p_lock
= osd_GetMutex( p_this
);
696 vlc_mutex_lock( p_lock
);
698 p_osd
= osd_Find( p_this
);
699 if( p_osd
== NULL
|| !osd_isVisible( p_osd
) )
701 vlc_mutex_unlock( p_lock
);
702 msg_Err( p_this
, "osd_ButtonFind failed" );
706 p_button
= p_osd
->p_button
;
707 for( ; p_button
!= NULL
; p_button
= p_button
->p_next
)
709 int i_source_video_width
= ( i_window_width
* 1000 ) / i_scale_width
;
710 int i_source_video_height
= ( i_window_height
* 1000 ) / i_scale_height
;
711 int i_y_offset
= p_button
->i_y
;
712 int i_x_offset
= p_button
->i_x
;
713 int i_width
= p_button
->i_width
;
714 int i_height
= p_button
->i_height
;
716 if( p_osd
->i_position
> 0 )
718 int i_inv_scale_y
= i_source_video_height
;
719 int i_inv_scale_x
= i_source_video_width
;
722 if( p_osd
->i_position
& SUBPICTURE_ALIGN_BOTTOM
)
724 i_y_offset
= i_window_height
- p_button
->i_height
-
725 (p_osd
->i_y
+ p_button
->i_y
) * i_inv_scale_y
/ 1000;
727 else if ( !(p_osd
->i_position
& SUBPICTURE_ALIGN_TOP
) )
729 i_y_offset
= i_window_height
/ 2 - p_button
->i_height
/ 2;
732 if( p_osd
->i_position
& SUBPICTURE_ALIGN_RIGHT
)
734 i_x_offset
= i_window_width
- p_button
->i_width
-
735 (pi_x
+ p_button
->i_x
)
736 * i_inv_scale_x
/ 1000;
738 else if ( !(p_osd
->i_position
& SUBPICTURE_ALIGN_LEFT
) )
740 i_x_offset
= i_window_width
/ 2 - p_button
->i_width
/ 2;
743 i_width
= i_window_width
- p_button
->i_width
- i_inv_scale_x
/ 1000;
744 i_height
= i_window_height
- p_button
->i_height
- i_inv_scale_y
/ 1000;
747 // TODO: write for Up / Down case too.
748 // TODO: handle absolute positioning case
749 if( ( i_x
>= i_x_offset
) && ( i_x
<= i_x_offset
+ i_width
) &&
750 ( i_y
>= i_y_offset
) && ( i_y
<= i_y_offset
+ i_height
) )
752 vlc_mutex_unlock( p_lock
);
757 vlc_mutex_unlock( p_lock
);
761 #undef osd_ButtonSelect
763 * Select the button provided as the new active button
765 void osd_ButtonSelect( vlc_object_t
*p_this
, osd_button_t
*p_button
)
769 vlc_mutex_t
*p_lock
= osd_GetMutex( p_this
);
771 vlc_mutex_lock( p_lock
);
773 p_osd
= osd_Find( p_this
);
774 if( p_osd
== NULL
|| !osd_isVisible( p_osd
) )
776 vlc_mutex_unlock( p_lock
);
777 msg_Err( p_this
, "osd_ButtonSelect failed" );
781 p_old
= p_osd
->p_state
->p_visible
;
784 if( !p_old
->b_range
)
785 p_old
->p_current_state
= osd_StateChange( p_old
, OSD_BUTTON_UNSELECT
);
786 p_osd
->p_state
->p_visible
= p_button
;
788 if( !p_osd
->p_state
->p_visible
->b_range
)
789 p_osd
->p_state
->p_visible
->p_current_state
=
790 osd_StateChange( p_osd
->p_state
->p_visible
, OSD_BUTTON_SELECT
);
792 osd_UpdateState( p_osd
->p_state
,
793 p_osd
->p_state
->p_visible
->i_x
, p_osd
->p_state
->p_visible
->i_y
,
794 p_osd
->p_state
->p_visible
->p_current_state
->i_width
,
795 p_osd
->p_state
->p_visible
->p_current_state
->i_height
,
796 p_osd
->p_state
->p_visible
->p_current_state
->p_pic
);
797 osd_SetMenuUpdate( p_osd
, true );
799 #if defined(OSD_MENU_DEBUG)
800 msg_Dbg( p_osd
, "button selected is [button %s]", p_osd
->p_state
->p_visible
->psz_action
);
803 vlc_mutex_unlock( p_lock
);