wintv remote control + kernel patch, add codec fileref, amp up OpenEDL, add loadmode...
[goodguy/cinelerra.git] / cinelerra-5.1 / guicast / bcmenupopup.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "bcmenubar.h"
24 #include "bcmenuitem.h"
25 #include "bcmenupopup.h"
26 #include "bcpixmap.h"
27 #include "bcpopup.h"
28 #include "bcresources.h"
29 #include "bcwindowbase.h"
30 #include "clip.h"
31
32 #include <string.h>
33
34
35
36 // ==================================== Menu Popup =============================
37
38 // Types of menu popups
39 #define MENUPOPUP_MENUBAR 0
40 #define MENUPOPUP_SUBMENU 1
41 #define MENUPOPUP_POPUP   2
42
43 BC_MenuPopup::BC_MenuPopup()
44 {
45         window_bg = 0;
46         item_bg[0] = 0;
47         item_bg[1] = 0;
48         item_bg[2] = 0;
49         check = 0;
50 }
51
52 BC_MenuPopup::~BC_MenuPopup()
53 {
54         while(menu_items.size())
55         {
56 // Each menuitem recursively removes itself from the arraylist
57                 delete menu_items.get(0);
58         }
59
60         delete window_bg;
61         delete item_bg[0];
62         delete item_bg[1];
63         delete item_bg[2];
64         delete check;
65 }
66
67 int BC_MenuPopup::initialize(BC_WindowBase *top_level,
68                 BC_MenuBar *menu_bar,
69                 BC_Menu *menu,
70                 BC_MenuItem *menu_item,
71                 BC_PopupMenu *popup_menu)
72 {
73         popup = 0;
74         active = 0;
75         this->menu = menu;
76         this->menu_bar = menu_bar;
77         this->menu_item = menu_item;
78         this->popup_menu = popup_menu;
79         this->top_level = top_level;
80
81         if(menu_item) this->type = MENUPOPUP_SUBMENU;
82         else
83         if(menu) this->type = MENUPOPUP_MENUBAR;
84         else
85         if(popup_menu) this->type = MENUPOPUP_POPUP;
86
87         BC_Resources *resources = top_level->get_resources();
88         if(resources->menu_popup_bg)
89         {
90                 window_bg = new BC_Pixmap(top_level, resources->menu_popup_bg);
91         }
92
93         if(resources->menu_item_bg)
94         {
95                 item_bg[0] = new BC_Pixmap(top_level, resources->menu_item_bg[0], PIXMAP_ALPHA);
96                 item_bg[1] = new BC_Pixmap(top_level, resources->menu_item_bg[1], PIXMAP_ALPHA);
97                 item_bg[2] = new BC_Pixmap(top_level, resources->menu_item_bg[2], PIXMAP_ALPHA);
98         }
99
100         if(resources->check)
101         {
102                 check = new BC_Pixmap(top_level, resources->check, PIXMAP_ALPHA);
103         }
104
105         return 0;
106 }
107
108 int BC_MenuPopup::add_item(BC_MenuItem *item)
109 {
110         menu_items.append(item);
111         item->initialize(top_level, menu_bar, this);
112         return 0;
113 }
114
115 int BC_MenuPopup::remove_item(BC_MenuItem *item)
116 {
117         menu_items.remove(item);
118         return 0;
119 }
120
121 int BC_MenuPopup::del_item(BC_MenuItem *item)
122 {
123         if(!item && menu_items.size() > 0)
124         {
125                 item = menu_items.get(menu_items.size() - 1);
126         }
127
128         if(item)
129         {
130                 remove_item(item);
131                 item->menu_popup = 0;
132                 delete item;
133         }
134         return 0;
135 }
136
137 BC_MenuItem *BC_MenuPopup::get_item(int i)
138 {
139         return menu_items[i];
140 }
141
142 int BC_MenuPopup::total_items()
143 {
144         return menu_items.size();
145 }
146
147
148 int BC_MenuPopup::dispatch_button_press()
149 {
150         int result = 0;
151         if(popup)
152         {
153                 for(int i = 0; i < menu_items.total && !result && popup; i++) {
154                         BC_MenuItem *item = menu_items[i];
155                         if( !item->enabled ) continue;
156                         result = item->dispatch_button_press();
157                 }
158                 if(result) draw_items();
159         }
160         return 0;
161 }
162
163 int BC_MenuPopup::dispatch_button_release()
164 {
165         int result = 0, redraw = 0;
166         if(popup)
167         {
168                 for(int i = 0; i < menu_items.total && !result && popup; i++) {
169                         BC_MenuItem *item = menu_items[i];
170                         if( !item->enabled ) continue;
171                         result = item->dispatch_button_release(redraw);
172                 }
173                 if(redraw) draw_items();
174         }
175         return result;
176 }
177
178 int BC_MenuPopup::dispatch_key_press()
179 {
180         int result = 0;
181         for(int i = 0; i < menu_items.total && !result; i++) {
182                 BC_MenuItem *item = menu_items[i];
183                 if( !item->enabled ) continue;
184                 result = item->dispatch_key_press();
185         }
186         return result;
187 }
188
189 int BC_MenuPopup::dispatch_motion_event()
190 {
191         int i, result = 0, redraw = 0;
192
193         if(popup)
194         {
195 // Try submenus and items
196                 for(i = 0; i < menu_items.total; i++) {
197                         BC_MenuItem *item = menu_items[i];
198                         if( !item->enabled ) continue;
199                         result |= item->dispatch_motion_event(redraw);
200                 }
201
202                 if(redraw) draw_items();
203         }
204
205         return result;
206 }
207
208 int BC_MenuPopup::dispatch_translation_event()
209 {
210         if(popup)
211         {
212                 int new_x = x +
213                         (top_level->last_translate_x - top_level->prev_x -
214                         BC_DisplayInfo::get_left_border());
215                 int new_y = y +
216                         (top_level->last_translate_y - top_level->prev_y -
217                         BC_DisplayInfo::get_top_border());
218
219 // printf("BC_MenuPopup::dispatch_translation_event %d %d %d %d\n",
220 // top_level->prev_x,
221 // top_level->last_translate_x,
222 // top_level->prev_y,
223 // top_level->last_translate_y);
224                 popup->reposition_window(new_x, new_y, popup->get_w(), popup->get_h());
225                 top_level->flush();
226                 this->x = new_x;
227                 this->y = new_y;
228
229                 for(int i = 0; i < menu_items.total; i++) {
230                         BC_MenuItem *item = menu_items[i];
231                         if( !item->enabled ) continue;
232                         item->dispatch_translation_event();
233                 }
234         }
235         return 0;
236 }
237
238
239 int BC_MenuPopup::dispatch_cursor_leave()
240 {
241         int result = 0;
242
243         if(popup)
244         {
245                 for(int i = 0; i < menu_items.total; i++) {
246                         BC_MenuItem *item = menu_items[i];
247                         if( !item->enabled ) continue;
248                         result |= item->dispatch_cursor_leave();
249                 }
250                 if(result) draw_items();
251         }
252         return 0;
253 }
254
255 int BC_MenuPopup::activate_menu(int x,
256         int y,
257         int w,
258         int h,
259         int top_window_coords,
260         int vertical_justify)
261 {
262         Window tempwin;
263         int new_x, new_y;
264         int top_x0 = top_level->get_screen_x(0, -1);
265         int top_y0 = top_level->get_screen_y(0, -1);
266         int top_x1 = top_x0 + top_level->get_screen_w(0, -1);
267         int top_y1 = top_y0 + top_level->get_screen_h(0, -1);
268
269         get_dimensions();
270
271 // Coords are relative to the main window
272         if(top_window_coords)
273                 XTranslateCoordinates(top_level->display,
274                         top_level->win,
275                         top_level->rootwin,
276                         x,
277                         y,
278                         &new_x,
279                         &new_y,
280                         &tempwin);
281         else
282 // Coords are absolute
283         {
284                 new_x = x;
285                 new_y = y;
286         }
287
288 // All coords are now relative to root window.
289         if(vertical_justify)
290         {
291                 this->x = new_x;
292                 this->y = new_y + h;
293                 if( this->x < top_x0 ) this->x = top_x0;
294                 if( this->y < top_y0 ) this->y = top_y0;
295                 if(this->x + this->w > top_x1) this->x -= this->x + this->w - top_x1; // Right justify
296                 if(this->y + this->h > top_y1) this->y -= this->h + h; // Bottom justify
297 // Avoid top of menu going out of screen
298                 if(this->y < 0)
299                         this->y = yS(2);
300         }
301         else
302         {
303                 this->x = new_x + w;
304                 this->y = new_y;
305                 if( this->x < top_x0 ) this->x = top_x0;
306                 if( this->y < top_y0 ) this->y = top_y0;
307                 if(this->x + this->w > top_x1) this->x = new_x - this->w;
308                 if(this->y + this->h > top_y1) this->y = new_y + h - this->h;
309         }
310         top_x0 += xS(2);  top_y0 += yS(2);
311         if( this->x < top_x0 ) this->x = top_x0;
312         if( this->y < top_y0 ) this->y = top_y0;
313
314         active = 1;
315         if(menu_bar)
316         {
317                 popup = new BC_Popup(menu_bar, this->x, this->y, this->w, this->h,
318                                 top_level->get_resources()->menu_up, 1, menu_bar->bg_pixmap);
319         }
320         else
321         {
322                 popup = new BC_Popup(top_level, this->x, this->y, this->w, this->h,
323                                 top_level->get_resources()->menu_up, 1, 0);
324 //              popup->set_background(top_level->get_resources()->menu_bg);
325         }
326         draw_items();
327         popup->show_window();
328         return 0;
329 }
330
331 int BC_MenuPopup::deactivate_submenus(BC_MenuPopup *exclude)
332 {
333         for(int i = 0; i < menu_items.total; i++) {
334                 BC_MenuItem *item = menu_items[i];
335                 if( !item->enabled ) continue;
336                 item->deactivate_submenus(exclude);
337         }
338         return 0;
339 }
340
341 int BC_MenuPopup::deactivate_menu()
342 {
343         deactivate_submenus(0);
344
345         if(popup) delete popup;
346         popup = 0;
347         active = 0;
348
349         return 0;
350 }
351
352 int BC_MenuPopup::draw_items()
353 {
354         if(menu_bar)
355                 popup->draw_top_tiles(menu_bar, 0, 0, w, h);
356         else
357                 popup->draw_top_tiles(popup, 0, 0, w, h);
358
359         if(window_bg)
360         {
361                 popup->draw_9segment(0, 0, w, h, window_bg);
362         }
363         else
364         {
365                 popup->draw_3d_border(0, 0, w, h,
366                         top_level->get_resources()->menu_light,
367                         top_level->get_resources()->menu_up,
368                         top_level->get_resources()->menu_shadow,
369                         BLACK);
370         }
371
372         for(int i = 0; i < menu_items.total; i++) {
373                 BC_MenuItem *item = menu_items[i];
374                 if( !item->enabled ) continue;
375                 item->draw();
376         }
377         popup->flash();
378
379
380         return 0;
381 }
382
383 int BC_MenuPopup::get_dimensions()
384 {
385         int xs10 = xS(10), xs20 = xS(20);
386         int ys4 = yS(4), ys5 = yS(10);
387         int widest_text = xs10, widest_key = xs10;
388         int text_w, key_w;
389         int i = 0;
390
391 // pad for border
392         h = yS(2);
393 // Set up parameters in each item and get total h.
394         for(i = 0; i < menu_items.total; i++) {
395                 BC_MenuItem *item = menu_items[i];
396                 if( !item->enabled ) continue;
397                 text_w = xs10 + top_level->get_text_width(MEDIUMFONT, item->text);
398                 if(item->checked) text_w += check->get_w() + xS(1);
399
400                 key_w = xs10 + top_level->get_text_width(MEDIUMFONT, item->hotkey_text);
401                 if(text_w > widest_text) widest_text = text_w;
402                 if(key_w > widest_key) widest_key = key_w;
403
404                 if(!strcmp(item->text, "-"))
405                         item->h = ys5;
406                 else {
407                         item->h = item_bg[0] ? item_bg[0]->get_h() :
408                                 top_level->get_text_height(MEDIUMFONT) + ys4;
409                 }
410
411                 item->y = h;
412                 item->highlighted = 0;
413                 item->down = 0;
414                 h += item->h;
415         }
416         w = widest_text + widest_key + xs20;
417
418         w = MAX(w, top_level->get_resources()->min_menu_w);
419 // pad for division
420         key_x = widest_text + xS(16);
421 // pad for border
422         h += yS(2);
423         return 0;
424 }
425
426 int BC_MenuPopup::get_key_x()
427 {
428         return key_x;
429 }
430
431 BC_Popup* BC_MenuPopup::get_popup()
432 {
433         return popup;
434 }
435
436 int BC_MenuPopup::cursor_inside()
437 {
438         if( !popup ) return 0;
439         if( popup->cursor_above() ) return 1;
440         for( int i=0; i<menu_items.size(); ++i ) {
441                 BC_MenuItem *item = menu_items[i];
442                 if( !item->enabled || !item->submenu ) continue;
443                 if( item->submenu->cursor_inside() ) return 1;
444         }
445         return 0;
446 }
447
448 int BC_MenuPopup::get_w()
449 {
450         return w;
451 }
452
453
454
455
456
457 // ================================= Sub Menu ==================================
458
459 BC_SubMenu::BC_SubMenu() : BC_MenuPopup()
460 {
461 }
462
463 BC_SubMenu::~BC_SubMenu()
464 {
465 }
466
467 int BC_SubMenu::add_submenuitem(BC_MenuItem *item)
468 {
469         add_item(item);
470         return 0;
471 }
472