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