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