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