rework keyframe hide popup, keyframe auto render, textbox set_selection wide text
[goodguy/history.git] / cinelerra-5.1 / guicast / bcpopupmenu.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 "bcpopupmenu.h"
27 #include "bcresources.h"
28 #include "bcsignals.h"
29 #include "colors.h"
30 #include "fonts.h"
31 #include <string.h>
32 #include "vframe.h"
33
34 #define BUTTON_UP 0
35 #define BUTTON_HI 1
36 #define BUTTON_DN 2
37 #define TOTAL_IMAGES 3
38
39
40 #define TRIANGLE_W 10
41 #define TRIANGLE_H 10
42
43
44 BC_PopupMenu::BC_PopupMenu(int x,
45                 int y,
46                 int w,
47                 const char *text,
48                 int use_title,
49                 VFrame **data,
50                 int margin)
51  : BC_SubWindow(x, y, 0, 0, -1)
52 {
53         highlighted = popup_down = 0;
54         menu_popup = 0;
55         icon = 0;
56         if(margin >= 0)
57                 this->margin = margin;
58         else
59                 this->margin = BC_WindowBase::get_resources()->popupmenu_margin;
60
61         this->use_title = use_title;
62         strcpy(this->text, text);
63         for(int i = 0; i < TOTAL_IMAGES; i++)
64         {
65                 images[i] = 0;
66         }
67         this->data = data;
68         this->w_argument = w;
69         status = BUTTON_UP;
70 }
71
72 BC_PopupMenu::BC_PopupMenu(int x,
73                 int y,
74                 const char *text,
75                 int use_title,
76                 VFrame **data)
77  : BC_SubWindow(x, y, 0, -1, -1)
78 {
79         highlighted = popup_down = 0;
80         menu_popup = 0;
81         icon = 0;
82         this->use_title = use_title;
83         strcpy(this->text, text);
84         for(int i = 0; i < TOTAL_IMAGES; i++)
85         {
86                 images[i] = 0;
87         }
88         this->data = data;
89         this->w_argument = -1;
90         status = BUTTON_UP;
91 }
92
93 BC_PopupMenu::~BC_PopupMenu()
94 {
95         if(menu_popup) delete menu_popup;
96         for(int i = 0; i < TOTAL_IMAGES; i++)
97         {
98                 if(images[i]) delete images[i];
99         }
100 }
101
102 char* BC_PopupMenu::get_text()
103 {
104         return text;
105 }
106
107 void BC_PopupMenu::set_text(const char *text)
108 {
109         if(use_title)
110         {
111                 strcpy(this->text, text);
112                 draw_title(1);
113         }
114 }
115
116 void BC_PopupMenu::set_icon(BC_Pixmap *icon)
117 {
118         if(use_title)
119         {
120                 this->icon = icon;
121                 if(menu_popup) draw_title(1);
122         }
123 }
124
125 int BC_PopupMenu::initialize()
126 {
127         if(use_title)
128         {
129                 if(data)
130                         set_images(data);
131                 else
132                 if(BC_WindowBase::get_resources()->popupmenu_images)
133                         set_images(BC_WindowBase::get_resources()->popupmenu_images);
134                 else
135                         set_images(BC_WindowBase::get_resources()->generic_button_images);
136         }
137         else
138 // Move outside window if no title
139         {
140                 x = -10;
141                 y = -10;
142                 w = 10;
143                 h = 10;
144         }
145
146         BC_SubWindow::initialize();
147
148         menu_popup = new BC_MenuPopup;
149         menu_popup->initialize(top_level,
150                 0,
151                 0,
152                 0,
153                 this);
154
155         if(use_title) draw_title(0);
156
157         return 0;
158 }
159
160 int BC_PopupMenu::set_images(VFrame **data)
161 {
162         BC_Resources *resources = get_resources();
163         for(int i = 0; i < 3; i++)
164         {
165                 if(images[i]) delete images[i];
166                 images[i] = new BC_Pixmap(parent_window, data[i], PIXMAP_ALPHA);
167         }
168
169         if(w_argument >= 0)
170                 w = w_argument +
171                         margin +
172                         resources->popupmenu_triangle_margin;
173         else
174                 w = get_text_width(MEDIUMFONT, text) +
175                         margin +
176                         resources->popupmenu_triangle_margin;
177
178         h = images[BUTTON_UP]->get_h();
179         return 0;
180 }
181
182 int BC_PopupMenu::calculate_w(int w_argument)
183 {
184         return w_argument +
185                 BC_WindowBase::get_resources()->popupmenu_margin +
186                 BC_WindowBase::get_resources()->popupmenu_triangle_margin;
187 }
188
189 int BC_PopupMenu::calculate_h(VFrame **data)
190 {
191         if(data)
192                 ;
193         else
194         if(BC_WindowBase::get_resources()->popupmenu_images)
195                 data = BC_WindowBase::get_resources()->popupmenu_images;
196         else
197                 data = BC_WindowBase::get_resources()->generic_button_images;
198
199
200         return data[BUTTON_UP]->get_h();
201 }
202
203 int BC_PopupMenu::add_item(BC_MenuItem *item)
204 {
205         menu_popup->add_item(item);
206         return 0;
207 }
208
209 int BC_PopupMenu::remove_item(BC_MenuItem *item)
210 {
211         menu_popup->remove_item(item);
212         return 0;
213 }
214
215 int BC_PopupMenu::del_item(BC_MenuItem *item)
216 {
217         menu_popup->del_item(item);
218         return 0;
219 }
220
221 int BC_PopupMenu::total_items()
222 {
223         return menu_popup->total_menuitems();
224         return 0;
225 }
226
227 BC_MenuItem* BC_PopupMenu::get_item(int i)
228 {
229         return menu_popup->menu_items.values[i];
230 }
231
232 int BC_PopupMenu::draw_title(int flush)
233 {
234         if(!use_title) return 0;
235         BC_Resources *resources = get_resources();
236
237 // Background
238         draw_top_background(parent_window, 0, 0, w, h);
239         draw_3segmenth(0, 0, w, images[status]);
240
241 // Overlay text
242         set_color(get_resources()->popup_title_text);
243         int offset = 0;
244         if(status == BUTTON_DN)
245                 offset = 1;
246         if(!icon)
247         {
248                 set_font(MEDIUMFONT);
249                 char truncated[BCTEXTLEN];
250                 int available_w = get_w() - margin * 2 - resources->popupmenu_triangle_margin;
251                 truncate_text(truncated, text, available_w);
252
253                 BC_WindowBase::draw_center_text(
254                         available_w / 2 + margin + offset,
255                         (int)((float)get_h() / 2 + get_text_ascent(MEDIUMFONT) / 2 - 2) + offset,
256                         truncated);
257         }
258
259         if(icon)
260         {
261                 draw_pixmap(icon,
262                         (get_w() - margin * 2 - resources->popupmenu_triangle_margin) / 2 + margin + offset - icon->get_w() / 2 ,
263                         get_h() / 2 - icon->get_h() / 2 + offset);
264         }
265
266         if( use_title >= 0 )
267                 draw_triangle_down_flat(get_w() - margin - resources->popupmenu_triangle_margin,
268                         get_h() / 2 - TRIANGLE_H / 2, TRIANGLE_W, TRIANGLE_H);
269
270         flash(flush);
271         return 0;
272 }
273
274 int BC_PopupMenu::deactivate()
275 {
276         if(popup_down)
277         {
278                 top_level->active_popup_menu = 0;
279                 popup_down = 0;
280                 menu_popup->deactivate_menu();
281
282                 if(use_title) draw_title(1);    // draw the title
283         }
284         return 0;
285 }
286
287 int BC_PopupMenu::activate_menu()
288 {
289         if(!popup_down)
290         {
291                 int x = this->x;
292                 int y = this->y;
293
294                 top_level->deactivate();
295                 top_level->active_popup_menu = this;
296                 if(!use_title)
297                 {
298                         x = top_level->get_abs_cursor_x(0) - get_w();
299                         y = top_level->get_abs_cursor_y(0) - get_h();
300                         button_press_x = top_level->cursor_x;
301                         button_press_y = top_level->cursor_y;
302                 }
303
304                 button_releases = 0;
305                 if(use_title)
306                 {
307                         Window tempwin;
308                         int new_x, new_y;
309                         XTranslateCoordinates(top_level->display,
310                                 win, top_level->rootwin,
311                                 0, 0, &new_x, &new_y, &tempwin);
312                         menu_popup->activate_menu(new_x, new_y,
313                                 w, h, 0, 1);
314                 }
315                 else
316 // back off x,y just a bit so the menu doesnt deactivate without motion
317                         menu_popup->activate_menu(x-10, y-10, w, h, 0, 1);
318                 popup_down = 1;
319                 if(use_title) draw_title(1);
320         }
321         return 0;
322 }
323
324 int BC_PopupMenu::deactivate_menu()
325 {
326         deactivate();
327         return 0;
328 }
329
330
331 int BC_PopupMenu::reposition_window(int x, int y)
332 {
333         BC_WindowBase::reposition_window(x, y);
334         draw_title(0);
335         return 0;
336 }
337
338 int BC_PopupMenu::focus_out_event()
339 {
340         if( popup_down && !get_button_down() &&
341             !cursor_inside() && !menu_popup->cursor_inside() )
342                 deactivate();
343         return 0;
344 }
345
346
347 int BC_PopupMenu::repeat_event(int64_t duration)
348 {
349         if( status == BUTTON_HI && !tooltip_done &&
350                 tooltip_text && tooltip_text[0] != 0 &&
351                 duration == top_level->get_resources()->tooltip_delay )
352         {
353                 show_tooltip();
354                 tooltip_done = 1;
355                 return 1;
356         }
357         return 0;
358 }
359
360 int BC_PopupMenu::button_press_event()
361 {
362         if(get_buttonpress() == 1 &&
363                 is_event_win() &&
364                 use_title)
365         {
366                 top_level->hide_tooltip();
367                 if(status == BUTTON_HI || status == BUTTON_UP) status = BUTTON_DN;
368                 activate_menu();
369                 draw_title(1);
370                 return 1;
371         }
372
373         // Scrolling section
374         if (is_event_win()
375                 && (get_buttonpress() == 4 || get_buttonpress() == 5)
376                 && menu_popup->total_menuitems() > 1 )
377         {
378                 int theval = -1;
379                 for (int i = 0; i < menu_popup->total_menuitems(); i++) {
380                         if (!strcmp(menu_popup->menu_items.values[i]->get_text(),get_text())) {
381                                 theval=i;
382                                 break;
383                         }
384                 }
385
386                 if (theval == -1)                  theval=0;
387                 else if (get_buttonpress() == 4)   theval--;
388                 else if (get_buttonpress() == 5)   theval++;
389
390                 if (theval < 0)
391                         theval=0;
392                 if (theval >= menu_popup->total_menuitems())
393                         theval = menu_popup->total_menuitems() - 1;
394
395                 BC_MenuItem *tmp = menu_popup->menu_items.values[theval];
396                 set_text(tmp->get_text());
397                 if (!tmp->handle_event())
398                         this->handle_event();
399         }
400         if(popup_down)
401         {
402 // Menu is down so dispatch to popup.
403                 menu_popup->dispatch_button_press();
404                 return 1;
405         }
406
407         return 0;
408 }
409
410 int BC_PopupMenu::button_release_event()
411 {
412 // try the title
413         int result = 0;
414
415         button_releases++;
416
417         if(is_event_win() && use_title)
418         {
419                 hide_tooltip();
420                 if(status == BUTTON_DN)
421                 {
422                         status = BUTTON_HI;
423                         draw_title(1);
424                 }
425         }
426
427         if( !use_title && status == BUTTON_DN ) {
428                 result = 1;
429         }
430         else if(popup_down)
431         {
432 // Menu is down so dispatch to popup.
433                 result = menu_popup->dispatch_button_release();
434         }
435
436         if(popup_down && button_releases >= 2)
437         {
438                 deactivate();
439         }
440
441         if(!result && use_title && cursor_inside() && is_event_win())
442         {
443                 hide_tooltip();
444                 result = 1;
445         }
446         else
447         if(!result && !use_title && popup_down && button_releases < 2)
448         {
449                 result = 1;
450         }
451
452
453         if(!result && popup_down)
454         {
455 // Button was released outside any menu.
456                 deactivate();
457                 result = 1;
458         }
459
460         return result;
461
462
463
464
465
466
467
468
469
470
471         if(popup_down)
472         {
473 // Menu is down so dispatch to popup.
474                 result = menu_popup->dispatch_button_release();
475         }
476
477         if(!result && use_title && cursor_inside() && top_level->event_win == win)
478         {
479 // Inside title
480                 if(button_releases >= 2)
481                 {
482                         highlighted = 1;
483                         deactivate();
484                 }
485                 result = 1;
486         }
487         else
488         if(!result && !use_title && button_releases < 2)
489         {
490 // First release outside a floating menu
491 // Released outside a fictitious title area
492 //              if(top_level->cursor_x < button_press_x - 5 ||
493 //                      top_level->cursor_y < button_press_y - 5 ||
494 //                      top_level->cursor_x > button_press_x + 5 ||
495 //                      top_level->cursor_y > button_press_y + 5)
496                         deactivate();
497                 result = 1;
498         }
499
500         return result;
501 }
502
503 int BC_PopupMenu::translation_event()
504 {
505 //printf("BC_PopupMenu::translation_event 1\n");
506         if(popup_down) menu_popup->dispatch_translation_event();
507         return 0;
508 }
509
510 int BC_PopupMenu::cursor_leave_event()
511 {
512
513         if(status == BUTTON_HI && use_title)
514         {
515                 status = BUTTON_UP;
516                 draw_title(1);
517                 hide_tooltip();
518         }
519
520 // dispatch to popup
521         if( popup_down ) {
522                 if( !get_button_down() && !menu_popup->cursor_inside() )
523                         deactivate_menu();
524                 menu_popup->dispatch_cursor_leave();
525         }
526
527         return 0;
528 }
529
530
531 int BC_PopupMenu::cursor_enter_event()
532 {
533         if(is_event_win() && use_title)
534         {
535                 tooltip_done = 0;
536                 if(top_level->button_down)
537                 {
538                         status = BUTTON_DN;
539                 }
540                 else
541                 if(status == BUTTON_UP)
542                         status = BUTTON_HI;
543                 draw_title(1);
544         }
545
546         return 0;
547 }
548
549 int BC_PopupMenu::cursor_motion_event()
550 {
551         int result = 0;
552
553 // This menu is down.
554         if(popup_down)
555         {
556                 result = menu_popup->dispatch_motion_event();
557         }
558
559         if(!result && use_title && top_level->event_win == win)
560         {
561                 if(highlighted)
562                 {
563                         if(cursor_inside())
564                         {
565                                 highlighted = 0;
566                                 draw_title(1);
567                         }
568                 }
569                 else
570                 {
571                         if(cursor_inside())
572                         {
573                                 highlighted = 1;
574                                 draw_title(1);
575                                 result = 1;
576                         }
577                 }
578         }
579
580         return result;
581 }
582
583 int BC_PopupMenu::drag_start_event()
584 {
585 //printf("BC_PopupMenu::drag_start_event %d\n", popup_down);
586         if(popup_down) return 1;
587         return 0;
588 }
589
590 int BC_PopupMenu::drag_stop_event()
591 {
592         if(popup_down) return 1;
593         return 0;
594 }
595
596 int BC_PopupMenu::drag_motion_event()
597 {
598         if(popup_down) return 1;
599         return 0;
600 }
601
602
603
604
605
606
607