rework keyframe hide popup, keyframe auto render, textbox set_selection wide text
[goodguy/history.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 }
119
120 int BC_MenuPopup::del_item(BC_MenuItem *item)
121 {
122         if(!item && menu_items.size() > 0)
123         {
124                 item = menu_items.get(menu_items.size() - 1);
125         }
126
127         if(item)
128         {
129                 remove_item(item);
130                 item->menu_popup = 0;
131                 delete item;
132         }
133         return 0;
134 }
135
136 int BC_MenuPopup::total_menuitems()
137 {
138         return menu_items.total;
139 }
140
141 int BC_MenuPopup::dispatch_button_press()
142 {
143         int result = 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_press();
149                 }
150                 if(result) draw_items();
151         }
152         return 0;
153 }
154
155 int BC_MenuPopup::dispatch_button_release()
156 {
157         int result = 0, redraw = 0;
158         if(popup)
159         {
160                 for(int i = 0; i < menu_items.total && !result; i++)
161                 {
162                         result = menu_items.values[i]->dispatch_button_release(redraw);
163                 }
164                 if(redraw) draw_items();
165         }
166         return result;
167 }
168
169 int BC_MenuPopup::dispatch_key_press()
170 {
171         int result = 0;
172         for(int i = 0; i < menu_items.total && !result; i++)
173         {
174                 result = menu_items.values[i]->dispatch_key_press();
175         }
176         return result;
177 }
178
179 int BC_MenuPopup::dispatch_motion_event()
180 {
181         int i, result = 0, redraw = 0;
182
183         if(popup)
184         {
185 // Try submenus and items
186                 for(i = 0; i < menu_items.total; i++)
187                 {
188                         result |= menu_items.values[i]->dispatch_motion_event(redraw);
189                 }
190
191                 if(redraw) draw_items();
192         }
193
194         return result;
195 }
196
197 int BC_MenuPopup::dispatch_translation_event()
198 {
199         if(popup)
200         {
201                 int new_x = x +
202                         (top_level->last_translate_x - top_level->prev_x -
203                         BC_DisplayInfo::get_left_border());
204                 int new_y = y +
205                         (top_level->last_translate_y - top_level->prev_y -
206                         BC_DisplayInfo::get_top_border());
207
208 // printf("BC_MenuPopup::dispatch_translation_event %d %d %d %d\n",
209 // top_level->prev_x,
210 // top_level->last_translate_x,
211 // top_level->prev_y,
212 // top_level->last_translate_y);
213                 popup->reposition_window(new_x, new_y, popup->get_w(), popup->get_h());
214                 top_level->flush();
215                 this->x = new_x;
216                 this->y = new_y;
217
218                 for(int i = 0; i < menu_items.total; i++)
219                 {
220                         menu_items.values[i]->dispatch_translation_event();
221                 }
222         }
223         return 0;
224 }
225
226
227 int BC_MenuPopup::dispatch_cursor_leave()
228 {
229         int result = 0;
230
231         if(popup)
232         {
233                 for(int i = 0; i < menu_items.total; i++)
234                 {
235                         result |= menu_items.values[i]->dispatch_cursor_leave();
236                 }
237                 if(result) draw_items();
238         }
239         return 0;
240 }
241
242 int BC_MenuPopup::activate_menu(int x,
243         int y,
244         int w,
245         int h,
246         int top_window_coords,
247         int vertical_justify)
248 {
249         Window tempwin;
250         int new_x, new_y;
251         int top_x0 = top_level->get_screen_x(0, -1);
252         int top_y0 = top_level->get_screen_y(0, -1);
253         int top_x1 = top_x0 + top_level->get_screen_w(0, -1);
254         int top_y1 = top_y0 + top_level->get_screen_h(0, -1);
255
256         get_dimensions();
257
258 // Coords are relative to the main window
259         if(top_window_coords)
260                 XTranslateCoordinates(top_level->display,
261                         top_level->win,
262                         top_level->rootwin,
263                         x,
264                         y,
265                         &new_x,
266                         &new_y,
267                         &tempwin);
268         else
269 // Coords are absolute
270         {
271                 new_x = x;
272                 new_y = y;
273         }
274
275 // All coords are now relative to root window.
276         if(vertical_justify)
277         {
278                 this->x = new_x;
279                 this->y = new_y + h;
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 -= this->x + this->w - top_x1; // Right justify
283                 if(this->y + this->h > top_y1) this->y -= this->h + h; // Bottom justify
284 // Avoid top of menu going out of screen
285                 if(this->y < 0)
286                         this->y = 2;
287         }
288         else
289         {
290                 this->x = new_x + w;
291                 this->y = new_y;
292                 if( this->x < top_x0 ) this->x = top_x0;
293                 if( this->y < top_y0 ) this->y = top_y0;
294                 if(this->x + this->w > top_x1) this->x = new_x - this->w;
295                 if(this->y + this->h > top_y1) this->y = new_y + h - this->h;
296         }
297         top_x0 += 2;  top_y0 += 2;
298         if( this->x < top_x0 ) this->x = top_x0;
299         if( this->y < top_y0 ) this->y = top_y0;
300
301         active = 1;
302         if(menu_bar)
303         {
304                 popup = new BC_Popup(menu_bar, this->x, this->y, this->w, this->h,
305                                         top_level->get_resources()->menu_up,
306                                         1,
307                                         menu_bar->bg_pixmap);
308         }
309         else
310         {
311                 popup = new BC_Popup(top_level, this->x, this->y, this->w, this->h,
312                                         top_level->get_resources()->menu_up,
313                                         1,
314                                         0);
315 //              popup->set_background(top_level->get_resources()->menu_bg);
316         }
317         draw_items();
318         popup->show_window();
319         return 0;
320 }
321
322 int BC_MenuPopup::deactivate_submenus(BC_MenuPopup *exclude)
323 {
324         for(int i = 0; i < menu_items.total; i++)
325         {
326                 menu_items.values[i]->deactivate_submenus(exclude);
327         }
328         return 0;
329 }
330
331 int BC_MenuPopup::deactivate_menu()
332 {
333         deactivate_submenus(0);
334
335         if(popup) delete popup;
336         popup = 0;
337         active = 0;
338
339         return 0;
340 }
341
342 int BC_MenuPopup::draw_items()
343 {
344         if(menu_bar)
345                 popup->draw_top_tiles(menu_bar, 0, 0, w, h);
346         else
347                 popup->draw_top_tiles(popup, 0, 0, w, h);
348
349         if(window_bg)
350         {
351                 popup->draw_9segment(0, 0, w, h, window_bg);
352         }
353         else
354         {
355                 popup->draw_3d_border(0, 0, w, h,
356                         top_level->get_resources()->menu_light,
357                         top_level->get_resources()->menu_up,
358                         top_level->get_resources()->menu_shadow,
359                         BLACK);
360         }
361
362         for(int i = 0; i < menu_items.total; i++)
363         {
364                 menu_items.values[i]->draw();
365         }
366         popup->flash();
367
368
369         return 0;
370 }
371
372 int BC_MenuPopup::get_dimensions()
373 {
374         int widest_text = 10, widest_key = 10;
375         int text_w, key_w;
376         int i = 0;
377
378 // pad for border
379         h = 2;
380 // Set up parameters in each item and get total h.
381         for(i = 0; i < menu_items.total; i++)
382         {
383                 text_w = 10 + top_level->get_text_width(MEDIUMFONT, menu_items.values[i]->text);
384                 if(menu_items.values[i]->checked) text_w += check->get_w() + 1;
385
386                 key_w = 10 + top_level->get_text_width(MEDIUMFONT, menu_items.values[i]->hotkey_text);
387                 if(text_w > widest_text) widest_text = text_w;
388                 if(key_w > widest_key) widest_key = key_w;
389
390                 if(!strcmp(menu_items.values[i]->text, "-"))
391                         menu_items.values[i]->h = 5;
392                 else
393                 {
394                         menu_items.values[i]->h = item_bg[0] ? item_bg[0]->get_h() :
395                                 top_level->get_text_height(MEDIUMFONT) + 4;
396                 }
397
398                 menu_items.values[i]->y = h;
399                 menu_items.values[i]->highlighted = 0;
400                 menu_items.values[i]->down = 0;
401                 h += menu_items.values[i]->h;
402         }
403         w = widest_text + widest_key + 10;
404
405         w = MAX(w, top_level->get_resources()->min_menu_w);
406 // pad for division
407         key_x = widest_text + 5;
408 // pad for border
409         h += 2;
410         return 0;
411 }
412
413 int BC_MenuPopup::get_key_x()
414 {
415         return key_x;
416 }
417
418 BC_Popup* BC_MenuPopup::get_popup()
419 {
420         return popup;
421 }
422
423 int BC_MenuPopup::cursor_inside()
424 {
425         if( !popup ) return 0;
426         int x = popup->get_relative_cursor_x();
427         if( x < 0 || x > popup->get_w() ) return 0;
428         int y = popup->get_relative_cursor_y();
429         if( y < 0 || y > popup->get_h() ) return 0;
430         return 1;
431 }
432
433 int BC_MenuPopup::get_w()
434 {
435         return w;
436 }
437
438
439
440
441
442 // ================================= Sub Menu ==================================
443
444 BC_SubMenu::BC_SubMenu() : BC_MenuPopup()
445 {
446 }
447
448 BC_SubMenu::~BC_SubMenu()
449 {
450 }
451
452 int BC_SubMenu::add_submenuitem(BC_MenuItem *item)
453 {
454         add_item(item);
455         return 0;
456 }
457