4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcdisplayinfo.h"
23 #include "bcmenubar.h"
24 #include "bcmenuitem.h"
25 #include "bcmenupopup.h"
28 #include "bcresources.h"
29 #include "bcwindowbase.h"
36 // ==================================== Menu Popup =============================
38 // Types of menu popups
39 #define MENUPOPUP_MENUBAR 0
40 #define MENUPOPUP_SUBMENU 1
41 #define MENUPOPUP_POPUP 2
43 BC_MenuPopup::BC_MenuPopup()
52 BC_MenuPopup::~BC_MenuPopup()
54 while(menu_items.size())
56 // Each menuitem recursively removes itself from the arraylist
57 delete menu_items.get(0);
67 int BC_MenuPopup::initialize(BC_WindowBase *top_level,
70 BC_MenuItem *menu_item,
71 BC_PopupMenu *popup_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;
81 if(menu_item) this->type = MENUPOPUP_SUBMENU;
83 if(menu) this->type = MENUPOPUP_MENUBAR;
85 if(popup_menu) this->type = MENUPOPUP_POPUP;
87 BC_Resources *resources = top_level->get_resources();
88 if(resources->menu_popup_bg)
90 window_bg = new BC_Pixmap(top_level, resources->menu_popup_bg);
93 if(resources->menu_item_bg)
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);
102 check = new BC_Pixmap(top_level, resources->check, PIXMAP_ALPHA);
108 int BC_MenuPopup::add_item(BC_MenuItem *item)
110 menu_items.append(item);
111 item->initialize(top_level, menu_bar, this);
115 int BC_MenuPopup::remove_item(BC_MenuItem *item)
117 menu_items.remove(item);
121 int BC_MenuPopup::del_item(BC_MenuItem *item)
123 if(!item && menu_items.size() > 0)
125 item = menu_items.get(menu_items.size() - 1);
131 item->menu_popup = 0;
137 BC_MenuItem *BC_MenuPopup::get_item(int i)
139 return menu_items[i];
142 int BC_MenuPopup::total_items()
144 return menu_items.size();
148 int BC_MenuPopup::dispatch_button_press()
153 for(int i = 0; i < menu_items.total && !result && popup; i++) {
154 BC_MenuItem *item = menu_items[i];
155 if( !item->enabled ) continue;
156 result = item->dispatch_button_press();
158 if(result) draw_items();
163 int BC_MenuPopup::dispatch_button_release()
165 int result = 0, redraw = 0;
168 for(int i = 0; i < menu_items.total && !result && popup; i++) {
169 BC_MenuItem *item = menu_items[i];
170 if( !item->enabled ) continue;
171 result = item->dispatch_button_release(redraw);
173 if(redraw) draw_items();
178 int BC_MenuPopup::dispatch_key_press()
181 for(int i = 0; i < menu_items.total && !result; i++) {
182 BC_MenuItem *item = menu_items[i];
183 if( !item->enabled ) continue;
184 result = item->dispatch_key_press();
189 int BC_MenuPopup::dispatch_motion_event()
191 int i, result = 0, redraw = 0;
195 // Try submenus and items
196 for(i = 0; i < menu_items.total; i++) {
197 BC_MenuItem *item = menu_items[i];
198 if( !item->enabled ) continue;
199 result |= item->dispatch_motion_event(redraw);
202 if(redraw) draw_items();
208 int BC_MenuPopup::dispatch_translation_event()
213 (top_level->last_translate_x - top_level->prev_x -
214 BC_DisplayInfo::get_left_border());
216 (top_level->last_translate_y - top_level->prev_y -
217 BC_DisplayInfo::get_top_border());
219 // printf("BC_MenuPopup::dispatch_translation_event %d %d %d %d\n",
220 // top_level->prev_x,
221 // top_level->last_translate_x,
222 // top_level->prev_y,
223 // top_level->last_translate_y);
224 popup->reposition_window(new_x, new_y, popup->get_w(), popup->get_h());
229 for(int i = 0; i < menu_items.total; i++) {
230 BC_MenuItem *item = menu_items[i];
231 if( !item->enabled ) continue;
232 item->dispatch_translation_event();
239 int BC_MenuPopup::dispatch_cursor_leave()
245 for(int i = 0; i < menu_items.total; i++) {
246 BC_MenuItem *item = menu_items[i];
247 if( !item->enabled ) continue;
248 result |= item->dispatch_cursor_leave();
250 if(result) draw_items();
255 int BC_MenuPopup::activate_menu(int x,
259 int top_window_coords,
260 int vertical_justify)
264 int top_x0 = top_level->get_screen_x(0, -1);
265 int top_y0 = top_level->get_screen_y(0, -1);
266 int top_x1 = top_x0 + top_level->get_screen_w(0, -1);
267 int top_y1 = top_y0 + top_level->get_screen_h(0, -1);
271 // Coords are relative to the main window
272 if(top_window_coords)
273 XTranslateCoordinates(top_level->display,
282 // Coords are absolute
288 // All coords are now relative to root window.
293 if( this->x < top_x0 ) this->x = top_x0;
294 if( this->y < top_y0 ) this->y = top_y0;
295 if(this->x + this->w > top_x1) this->x -= this->x + this->w - top_x1; // Right justify
296 if(this->y + this->h > top_y1) this->y -= this->h + h; // Bottom justify
297 // Avoid top of menu going out of screen
305 if( this->x < top_x0 ) this->x = top_x0;
306 if( this->y < top_y0 ) this->y = top_y0;
307 if(this->x + this->w > top_x1) this->x = new_x - this->w;
308 if(this->y + this->h > top_y1) this->y = new_y + h - this->h;
310 top_x0 += xS(2); top_y0 += yS(2);
311 if( this->x < top_x0 ) this->x = top_x0;
312 if( this->y < top_y0 ) this->y = top_y0;
317 popup = new BC_Popup(menu_bar, this->x, this->y, this->w, this->h,
318 top_level->get_resources()->menu_up, 1, menu_bar->bg_pixmap);
322 popup = new BC_Popup(top_level, this->x, this->y, this->w, this->h,
323 top_level->get_resources()->menu_up, 1, 0);
324 // popup->set_background(top_level->get_resources()->menu_bg);
327 popup->show_window();
331 int BC_MenuPopup::deactivate_submenus(BC_MenuPopup *exclude)
333 for(int i = 0; i < menu_items.total; i++) {
334 BC_MenuItem *item = menu_items[i];
335 if( !item->enabled ) continue;
336 item->deactivate_submenus(exclude);
341 int BC_MenuPopup::deactivate_menu()
343 deactivate_submenus(0);
345 if(popup) delete popup;
352 int BC_MenuPopup::draw_items()
355 popup->draw_top_tiles(menu_bar, 0, 0, w, h);
357 popup->draw_top_tiles(popup, 0, 0, w, h);
361 popup->draw_9segment(0, 0, w, h, window_bg);
365 popup->draw_3d_border(0, 0, w, h,
366 top_level->get_resources()->menu_light,
367 top_level->get_resources()->menu_up,
368 top_level->get_resources()->menu_shadow,
372 for(int i = 0; i < menu_items.total; i++) {
373 BC_MenuItem *item = menu_items[i];
374 if( !item->enabled ) continue;
383 int BC_MenuPopup::get_dimensions()
385 int xs10 = xS(10), xs20 = xS(20);
386 int ys4 = yS(4), ys5 = yS(10);
387 int widest_text = xs10, widest_key = xs10;
393 // Set up parameters in each item and get total h.
394 for(i = 0; i < menu_items.total; i++) {
395 BC_MenuItem *item = menu_items[i];
396 if( !item->enabled ) continue;
397 text_w = xs10 + top_level->get_text_width(MEDIUMFONT, item->text);
398 if(item->checked) text_w += check->get_w() + xS(1);
400 key_w = xs10 + top_level->get_text_width(MEDIUMFONT, item->hotkey_text);
401 if(text_w > widest_text) widest_text = text_w;
402 if(key_w > widest_key) widest_key = key_w;
404 if(!strcmp(item->text, "-"))
407 item->h = item_bg[0] ? item_bg[0]->get_h() :
408 top_level->get_text_height(MEDIUMFONT) + ys4;
412 item->highlighted = 0;
416 w = widest_text + widest_key + xs20;
418 w = MAX(w, top_level->get_resources()->min_menu_w);
420 key_x = widest_text + xS(16);
426 int BC_MenuPopup::get_key_x()
431 BC_Popup* BC_MenuPopup::get_popup()
436 int BC_MenuPopup::cursor_inside()
438 if( !popup ) return 0;
439 if( popup->cursor_above() ) return 1;
440 for( int i=0; i<menu_items.size(); ++i ) {
441 BC_MenuItem *item = menu_items[i];
442 if( !item->enabled || !item->submenu ) continue;
443 if( item->submenu->cursor_inside() ) return 1;
448 int BC_MenuPopup::get_w()
457 // ================================= Sub Menu ==================================
459 BC_SubMenu::BC_SubMenu() : BC_MenuPopup()
463 BC_SubMenu::~BC_SubMenu()
467 int BC_SubMenu::add_submenuitem(BC_MenuItem *item)