2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "libmpcodecs/img_format.h"
27 #include "libmpcodecs/mp_image.h"
32 #include "libvo/font_load.h"
33 #include "osdep/keycodes.h"
36 #include "menu_list.h"
38 extern double menu_mouse_x
;
39 extern double menu_mouse_y
;
40 extern int menu_mouse_pos_updated
;
43 static int selection_x
;
44 static int selection_y
;
45 static int selection_w
;
46 static int selection_h
;
48 #define mpriv (menu->priv)
50 void menu_list_draw(menu_t
* menu
,mp_image_t
* mpi
) {
58 int need_h
= 0,need_w
= 0,ptr_l
,sidx
= 0;
67 if(h
<= 0) h
= mpi
->height
;
68 if(w
<= 0) w
= mpi
->width
;
69 dh
= h
- 2*mpriv
->minb
;
70 dw
= w
- 2*mpriv
->minb
;
71 ptr_l
= mpriv
->ptr
? menu_text_length(mpriv
->ptr
) : 0;
73 if(h
- vo_font
->height
<= 0 || w
- ptr_l
<= 0 || dw
<= 0 || dh
<= 0)
76 line_h
= mpriv
->vspace
+ vo_font
->height
;
77 th
= menu_text_num_lines(mpriv
->title
,dw
) * line_h
+ mpriv
->vspace
;
79 // the selected item is hidden, find a visible one
80 if(mpriv
->current
->hide
) {
82 for(m
= mpriv
->current
->next
; m
; m
= m
->next
)
84 if(!m
) // or the previous
85 for(m
= mpriv
->current
->prev
; m
; m
= m
->prev
)
87 if(m
) mpriv
->current
= m
;
91 for(i
= 0, m
= mpriv
->menu
; m
; m
= m
->next
, i
++) {
94 ll
= menu_text_length(m
->txt
);
95 if(ptr_l
+ ll
> need_w
) need_w
= ptr_l
+ ll
;
96 if(m
== mpriv
->current
) sidx
= i
;
99 if(need_w
> dw
) need_w
= dw
;
107 need_h
= count
* line_h
- mpriv
->vspace
;
108 if( need_h
+ th
> dh
) {
110 mpriv
->disp_lines
= (dh
+ mpriv
->vspace
- th
) / line_h
;
111 if(mpriv
->disp_lines
< 4) {
113 mpriv
->disp_lines
= (dh
+ mpriv
->vspace
) / line_h
;
116 if(mpriv
->disp_lines
< 1) return;
117 need_h
= mpriv
->disp_lines
* line_h
- mpriv
->vspace
;
119 start
= sidx
- (mpriv
->disp_lines
/2);
120 if(start
< 0) start
= 0;
121 end
= start
+ mpriv
->disp_lines
;
124 if(end
- start
< mpriv
->disp_lines
)
125 start
= end
- mpriv
->disp_lines
< 0 ? 0 : end
- mpriv
->disp_lines
;
128 for(i
= 0 ; m
->next
&& i
< start
; ) {
134 mpriv
->disp_lines
= count
;
137 bg_w
= need_w
+2*mpriv
->minb
;
140 menu_text_size(mpriv
->title
,dw
,mpriv
->vspace
,1,&tw
,&th2
);
141 if(mpriv
->title_bg
>= 0) {
142 if(tw
+2*mpriv
->minb
> bg_w
) bg_w
= tw
+2*mpriv
->minb
;
143 menu_draw_box(mpi
,mpriv
->title_bg
,mpriv
->title_bg_alpha
,
144 x
< 0 ? (mpi
->w
-bg_w
)/2 : x
-mpriv
->minb
,dy
+y
-mpriv
->vspace
/2,bg_w
,th
);
146 menu_draw_text_full(mpi
,mpriv
->title
,
147 x
< 0 ? mpi
->w
/ 2 : x
,
148 dy
+y
, x
< 0 ? dw
: (tw
> need_w
? tw
: need_w
), 0,
150 MENU_TEXT_TOP
|MENU_TEXT_HCENTER
,
151 MENU_TEXT_TOP
|(x
< 0 ? MENU_TEXT_HCENTER
:MENU_TEXT_LEFT
));
155 dx
= x
< 0 ? (mpi
->w
- need_w
) / 2 : x
;
156 bx
= x
< 0 ? (mpi
->w
- bg_w
) / 2 : x
- mpriv
->minb
;
158 // If mouse moved, try to update selected menu item by the mouse position.
159 if (menu_mouse_pos_updated
) {
160 mouse_x
= menu_mouse_x
* mpi
->width
;
161 mouse_y
= menu_mouse_y
* mpi
->height
;
162 if (mouse_x
>= bx
&& mouse_x
< bx
+ bg_w
) {
163 int by
= dy
+ y
- mpriv
->vspace
/ 2;
164 int max_by
= dh
+ y
+ mpriv
->vspace
/ 2;
165 if (mouse_y
>= by
&& mouse_y
< max_by
) {
166 int cur_no
= (mouse_y
- by
) / line_h
;
168 for (i
= 0; e
!= NULL
; e
= e
->next
) {
169 if (e
->hide
) continue;
178 menu_mouse_pos_updated
= 0;
181 for( ; m
!= NULL
&& dy
+ vo_font
->height
< dh
; m
= m
->next
) {
182 if(m
->hide
) continue;
183 if(m
== mpriv
->current
) {
184 // Record rectangle of current selection box.
186 selection_y
= dy
+ y
- mpriv
->vspace
/ 2;
188 selection_h
= line_h
;
190 if(mpriv
->ptr_bg
>= 0)
191 menu_draw_box(mpi
,mpriv
->ptr_bg
,mpriv
->ptr_bg_alpha
,
192 bx
, dy
+ y
- mpriv
->vspace
/ 2,
195 menu_draw_text_full(mpi
,mpriv
->ptr
,
199 MENU_TEXT_TOP
|MENU_TEXT_LEFT
,
200 MENU_TEXT_TOP
|MENU_TEXT_LEFT
);
201 } else if(mpriv
->item_bg
>= 0)
202 menu_draw_box(mpi
,mpriv
->item_bg
,mpriv
->item_bg_alpha
,
203 bx
, dy
+ y
- mpriv
->vspace
/ 2,
205 menu_draw_text_full(mpi
,m
->txt
,
207 dy
+y
,dw
-ptr_l
,dh
- dy
,
209 MENU_TEXT_TOP
|MENU_TEXT_LEFT
,
210 MENU_TEXT_TOP
|MENU_TEXT_LEFT
);
216 void menu_list_read_cmd(menu_t
* menu
,int cmd
) {
221 while(mpriv
->current
->prev
) {
222 mpriv
->current
= mpriv
->current
->prev
;
223 if(!mpriv
->current
->hide
) return;
225 for( ; mpriv
->current
->next
!= NULL
; mpriv
->current
= mpriv
->current
->next
)
227 if(!mpriv
->current
->hide
) return;
228 while(mpriv
->current
->prev
) {
229 mpriv
->current
= mpriv
->current
->prev
;
230 if(!mpriv
->current
->hide
) return;
234 while(mpriv
->current
->next
) {
235 mpriv
->current
= mpriv
->current
->next
;
236 if(!mpriv
->current
->hide
) return;
238 mpriv
->current
= mpriv
->menu
;
239 if(!mpriv
->current
->hide
) return;
240 while(mpriv
->current
->next
) {
241 mpriv
->current
= mpriv
->current
->next
;
242 if(!mpriv
->current
->hide
) return;
246 mpriv
->current
= mpriv
->menu
;
249 for(m
= mpriv
->current
; m
&& m
->next
; m
= m
->next
)
254 case MENU_CMD_PAGE_UP
:
255 for(i
= 0, m
= mpriv
->current
; m
&& m
->prev
&& i
< mpriv
->disp_lines
; m
= m
->prev
, i
++)
260 case MENU_CMD_PAGE_DOWN
:
261 for(i
= 0, m
= mpriv
->current
; m
&& m
->next
&& i
< mpriv
->disp_lines
; m
= m
->next
, i
++)
267 case MENU_CMD_CANCEL
:
272 if (mouse_x
>= selection_x
&& mouse_x
< selection_x
+ selection_w
&&
273 mouse_y
>= selection_y
&& mouse_y
< selection_y
+ selection_h
)
274 menu_read_cmd(menu
, MENU_CMD_OK
);
279 int menu_list_jump_to_key(menu_t
* menu
,int c
) {
280 if(c
< 256 && isalnum(c
)) {
281 list_entry_t
* e
= mpriv
->current
;
282 if(e
->txt
[0] == c
) e
= e
->next
;
283 for( ; e
; e
= e
->next
) {
289 for(e
= mpriv
->menu
; e
; e
= e
->next
) {
300 void menu_list_add_entry(menu_t
* menu
,list_entry_t
* entry
) {
304 if(mpriv
->menu
== NULL
) {
305 mpriv
->menu
= mpriv
->current
= entry
;
309 for(l
= mpriv
->menu
; l
->next
!= NULL
; l
= l
->next
)
315 void menu_list_init(menu_t
* menu
) {
317 mpriv
= calloc(1,sizeof(struct menu_priv_s
));
321 void menu_list_uninit(menu_t
* menu
,free_entry_t free_func
) {
324 if(!free_func
) free_func
= (free_entry_t
)free
;
326 for(i
= mpriv
->menu
; i
!= NULL
; ) {
332 mpriv
->menu
= mpriv
->current
= NULL
;