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