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