1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Basemenu.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
31 #endif // HAVE_STDIO_H
35 #endif // HAVE_STDLIB_H
39 #endif // HAVE_STRING_H
47 #include "blackbox.hh"
48 #include "Basemenu.hh"
56 static Basemenu
*shown
= (Basemenu
*) 0;
58 Basemenu::Basemenu(BScreen
*scrn
) {
60 blackbox
= screen
->getBlackbox();
61 image_ctrl
= screen
->getImageControl();
62 display
= blackbox
->getXDisplay();
63 parent
= (Basemenu
*) 0;
64 alignment
= AlignDontCare
;
93 menu
.hilite_pixmap
= None
;
95 menu
.bevel_w
= screen
->getBevelWidth();
97 const MenuStyle
* const style
= screen
->getMenuStyle();
98 menu
.width
= menu
.title_h
= menu
.item_w
= menu
.frame_h
=
99 style
->t_font
->height() + (menu
.bevel_w
* 2);
101 menu
.item_h
= style
->f_font
->height() + menu
.bevel_w
;
103 menu
.height
= menu
.title_h
+ screen
->getBorderWidth() + menu
.frame_h
;
105 unsigned long attrib_mask
= CWBackPixmap
| CWBackPixel
| CWBorderPixel
|
106 CWColormap
| CWOverrideRedirect
| CWEventMask
;
107 XSetWindowAttributes attrib
;
108 attrib
.background_pixmap
= None
;
109 attrib
.background_pixel
= attrib
.border_pixel
=
110 screen
->getBorderColor()->pixel();
111 attrib
.colormap
= screen
->getColormap();
112 attrib
.override_redirect
= True
;
113 attrib
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
114 ButtonMotionMask
| ExposureMask
;
117 XCreateWindow(display
, screen
->getRootWindow(),
118 menu
.x
, menu
.y
, menu
.width
, menu
.height
,
119 screen
->getBorderWidth(), screen
->getDepth(),
120 InputOutput
, screen
->getVisual(), attrib_mask
, &attrib
);
121 blackbox
->saveMenuSearch(menu
.window
, this);
123 attrib_mask
= CWBackPixmap
| CWBackPixel
| CWBorderPixel
| CWEventMask
;
124 attrib
.background_pixel
= screen
->getBorderColor()->pixel();
125 attrib
.event_mask
|= EnterWindowMask
| LeaveWindowMask
;
128 XCreateWindow(display
, menu
.window
, 0, 0, menu
.width
, menu
.height
, 0,
129 screen
->getDepth(), InputOutput
, screen
->getVisual(),
130 attrib_mask
, &attrib
);
131 blackbox
->saveMenuSearch(menu
.title
, this);
133 attrib
.event_mask
|= PointerMotionMask
;
134 menu
.frame
= XCreateWindow(display
, menu
.window
, 0,
135 menu
.title_h
+ screen
->getBorderWidth(),
136 menu
.width
, menu
.frame_h
, 0,
137 screen
->getDepth(), InputOutput
,
138 screen
->getVisual(), attrib_mask
, &attrib
);
139 blackbox
->saveMenuSearch(menu
.frame
, this);
141 // even though this is the end of the constructor the menu is still not
142 // completely created. items must be inserted and it must be update()'d
146 Basemenu::~Basemenu(void) {
147 XUnmapWindow(display
, menu
.window
);
149 if (shown
&& shown
->getWindowID() == getWindowID())
150 shown
= (Basemenu
*) 0;
152 MenuItems::const_iterator it
= menuitems
.begin(),
153 end
= menuitems
.end();
154 for (; it
!= end
; ++it
) {
155 if (! internal_menu
) {
156 Basemenu
*tmp
= (*it
)->submenu();
158 if (! tmp
->internal_menu
)
161 tmp
->internal_hide();
166 std::for_each(menuitems
.begin(), menuitems
.end(), PointerAssassin());
168 if (menu
.title_pixmap
)
169 image_ctrl
->removeImage(menu
.title_pixmap
);
171 if (menu
.frame_pixmap
)
172 image_ctrl
->removeImage(menu
.frame_pixmap
);
174 if (menu
.hilite_pixmap
)
175 image_ctrl
->removeImage(menu
.hilite_pixmap
);
177 blackbox
->removeMenuSearch(menu
.title
);
178 XDestroyWindow(display
, menu
.title
);
180 blackbox
->removeMenuSearch(menu
.frame
);
181 XDestroyWindow(display
, menu
.frame
);
183 blackbox
->removeMenuSearch(menu
.window
);
184 XDestroyWindow(display
, menu
.window
);
188 BasemenuItem
*Basemenu::find(int index
) {
189 if (index
< 0 || index
>= static_cast<signed>(menuitems
.size()))
190 return (BasemenuItem
*) 0;
192 return menuitems
[index
];
196 int Basemenu::insert(BasemenuItem
*item
, int pos
) {
198 menuitems
.push_back(item
);
200 assert(pos
<= static_cast<signed>(menuitems
.size()));
201 menuitems
.insert((menuitems
.begin() + pos
), item
);
203 return menuitems
.size();
207 int Basemenu::insert(const string
& label
, int function
,
208 const string
& exec
, int pos
) {
209 BasemenuItem
*item
= new BasemenuItem(label
, function
, exec
);
210 return insert(item
, pos
);
214 int Basemenu::insert(const string
& label
, Basemenu
*submenu
, int pos
) {
215 BasemenuItem
*item
= new BasemenuItem(label
, submenu
);
216 submenu
->parent
= this;
218 return insert(item
, pos
);
222 int Basemenu::remove(int index
) {
223 BasemenuItem
*item
= find(index
);
224 if (! item
) return -1;
226 if (! internal_menu
) {
227 Basemenu
*tmp
= item
->submenu();
229 if (! tmp
->internal_menu
)
232 tmp
->internal_hide();
238 if (which_sub
== index
)
240 else if (which_sub
> index
)
243 menuitems
.erase(menuitems
.begin() + index
);
245 return menuitems
.size();
249 void Basemenu::update(void) {
250 const MenuStyle
* const style
= screen
->getMenuStyle();
251 menu
.item_h
= (style
->f_font
->height() < 9 ? 9 : style
->f_font
->height()) +
252 menu
.bevel_w
; // 9 for the menu pixmaps (checkmarks)
253 menu
.title_h
= style
->t_font
->height() + menu
.bevel_w
* 2;
256 menu
.item_w
= screen
->getMenuStyle()->t_font
->measureString(menu
.label
) +
263 MenuItems::iterator it
= menuitems
.begin(), end
= menuitems
.end();
264 for (; it
!= end
; ++it
) {
265 ii
= screen
->getMenuStyle()->f_font
->measureString((*it
)->l
) +
266 (menu
.bevel_w
* 2) + (menu
.item_h
* 2);
268 menu
.item_w
= ((menu
.item_w
< ii
) ? ii
: menu
.item_w
);
271 if (! menuitems
.empty()) {
274 const unsigned int menu_size
= menuitems
.size();
275 while (((menu
.item_h
* (menu_size
+ 1) / menu
.sublevels
)
276 + menu
.title_h
+ screen
->getBorderWidth()) >
280 if (menu
.sublevels
< menu
.minsub
) menu
.sublevels
= menu
.minsub
;
282 menu
.persub
= menu_size
/ menu
.sublevels
;
283 if (menu_size
% menu
.sublevels
) menu
.persub
++;
289 menu
.width
= (menu
.sublevels
* (menu
.item_w
));
290 if (! menu
.width
) menu
.width
= menu
.item_w
;
292 menu
.frame_h
= (menu
.item_h
* menu
.persub
);
293 menu
.height
= ((title_vis
) ? menu
.title_h
+ screen
->getBorderWidth() : 0) +
295 if (! menu
.frame_h
) menu
.frame_h
= 1;
296 if (menu
.height
< 1) menu
.height
= 1;
301 tmp
= menu
.title_pixmap
;
302 texture
= &(screen
->getMenuStyle()->title
);
303 if (texture
->texture() == (BTexture::Flat
| BTexture::Solid
)) {
304 menu
.title_pixmap
= None
;
305 XSetWindowBackground(display
, menu
.title
,
306 texture
->color().pixel());
309 image_ctrl
->renderImage(menu
.width
, menu
.title_h
, *texture
);
310 XSetWindowBackgroundPixmap(display
, menu
.title
, menu
.title_pixmap
);
312 if (tmp
) image_ctrl
->removeImage(tmp
);
313 XClearWindow(display
, menu
.title
);
316 tmp
= menu
.frame_pixmap
;
317 texture
= &(screen
->getMenuStyle()->frame
);
318 if (texture
->texture() == (BTexture::Flat
| BTexture::Solid
)) {
319 menu
.frame_pixmap
= None
;
320 XSetWindowBackground(display
, menu
.frame
,
321 texture
->color().pixel());
324 image_ctrl
->renderImage(menu
.width
, menu
.frame_h
, *texture
);
325 XSetWindowBackgroundPixmap(display
, menu
.frame
, menu
.frame_pixmap
);
327 if (tmp
) image_ctrl
->removeImage(tmp
);
329 tmp
= menu
.hilite_pixmap
;
330 texture
= &(screen
->getMenuStyle()->hilite
);
331 if (texture
->texture() == (BTexture::Flat
| BTexture::Solid
)) {
332 menu
.hilite_pixmap
= None
;
335 image_ctrl
->renderImage(menu
.item_w
, menu
.item_h
, *texture
);
337 if (tmp
) image_ctrl
->removeImage(tmp
);
339 XResizeWindow(display
, menu
.window
, menu
.width
, menu
.height
);
342 XResizeWindow(display
, menu
.title
, menu
.width
, menu
.title_h
);
344 XMoveResizeWindow(display
, menu
.frame
, 0,
345 ((title_vis
) ? menu
.title_h
+
346 screen
->getBorderWidth() : 0), menu
.width
,
349 XClearWindow(display
, menu
.window
);
350 XClearWindow(display
, menu
.title
);
351 XClearWindow(display
, menu
.frame
);
353 if (title_vis
&& visible
) redrawTitle();
355 const int menu_size
= menuitems
.size();
356 for (int i
= 0; visible
&& i
< menu_size
; i
++) {
357 if (i
== which_sub
) {
358 drawItem(i
, True
, 0);
361 drawItem(i
, False
, 0);
365 if (parent
&& visible
)
366 parent
->drawSubmenu(parent
->which_sub
);
368 XMapSubwindows(display
, menu
.window
);
372 void Basemenu::show(void) {
373 XMapSubwindows(display
, menu
.window
);
374 XMapWindow(display
, menu
.window
);
378 if (shown
&& (! shown
->torn
))
386 void Basemenu::hide(void) {
387 if (! torn
&& hide_tree
&& parent
&& parent
->isVisible()) {
388 Basemenu
*p
= parent
;
390 while (p
->isVisible() && ! p
->torn
&& p
->parent
) p
= p
->parent
;
398 void Basemenu::internal_hide(void) {
399 BasemenuItem
*tmp
= find(which_sub
);
401 tmp
->submenu()->internal_hide();
403 if (parent
&& ! torn
) {
404 parent
->drawItem(parent
->which_sub
, False
, True
);
406 parent
->which_sub
= -1;
407 } else if (shown
&& shown
->menu
.window
== menu
.window
) {
408 shown
= (Basemenu
*) 0;
411 torn
= visible
= False
;
412 which_sub
= which_press
= which_sub
= -1;
414 XUnmapWindow(display
, menu
.window
);
418 void Basemenu::move(int x
, int y
) {
421 XMoveWindow(display
, menu
.window
, x
, y
);
423 drawSubmenu(which_sub
);
427 void Basemenu::redrawTitle(void) {
428 const char *text
= (! menu
.label
.empty()) ? getLabel() :
429 i18n(BasemenuSet
, BasemenuBlackboxMenu
, "Blackbox Menu");
430 int dx
= menu
.bevel_w
;
432 const MenuStyle
* const style
= screen
->getMenuStyle();
434 l
= style
->t_font
->measureString(text
) + menu
.bevel_w
* 2;
436 switch (screen
->getMenuStyle()->t_justify
) {
438 dx
+= menu
.width
- l
;
442 dx
+= (menu
.width
- l
) / 2;
450 style
->t_font
->drawString(menu
.title
, dx
, menu
.bevel_w
,
451 style
->t_text
, text
);
455 void Basemenu::drawSubmenu(int index
) {
456 BasemenuItem
*item
= find(which_sub
);
457 if (item
&& item
->submenu() && ! item
->submenu()->isTorn() &&
459 item
->submenu()->internal_hide();
465 Basemenu
*submenu
= item
->submenu();
467 if (submenu
&& visible
&& ! submenu
->isTorn() && item
->isEnabled()) {
468 if (submenu
->parent
!= this) submenu
->parent
= this;
469 const int sbl
= index
/ menu
.persub
, i
= index
- (sbl
* menu
.persub
);
470 int x
= menu
.x
+ ((menu
.item_w
* (sbl
+ 1)) + screen
->getBorderWidth()), y
;
472 if (alignment
== AlignTop
) {
473 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
474 ((title_vis
) ? menu
.title_h
+ screen
->getBorderWidth() : 0) -
475 ((submenu
->title_vis
) ?
476 submenu
->menu
.title_h
+ screen
->getBorderWidth() : 0));
478 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
480 ((title_vis
) ? menu
.title_h
+ screen
->getBorderWidth() : 0) -
481 ((submenu
->title_vis
) ?
482 submenu
->menu
.title_h
+ screen
->getBorderWidth() : 0));
485 if (alignment
== AlignBottom
&&
486 (y
+ submenu
->menu
.height
) > ((shifted
) ? menu
.y_shift
:
487 menu
.y
) + menu
.height
)
488 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
489 menu
.height
- submenu
->menu
.height
);
491 if ((x
+ submenu
->getWidth()) > screen
->getWidth())
492 x
= ((shifted
) ? menu
.x_shift
: menu
.x
) -
493 submenu
->getWidth() - screen
->getBorderWidth();
497 if ((y
+ submenu
->getHeight()) > screen
->getHeight())
498 y
= screen
->getHeight() - submenu
->getHeight() -
499 (screen
->getBorderWidth() * 2);
503 if (! moving
) drawItem(index
, True
);
505 if (! submenu
->isVisible())
507 submenu
->moving
= moving
;
515 bool Basemenu::hasSubmenu(int index
) {
516 BasemenuItem
*item
= find(index
);
517 if (item
&& item
->submenu())
523 void Basemenu::drawItem(int index
, bool highlight
, bool clear
,
524 int x
, int y
, unsigned int w
, unsigned int h
) {
525 BasemenuItem
*item
= find(index
);
528 bool dotext
= True
, dohilite
= True
, dosel
= True
, dooppsel
= True
;
529 const char *text
= item
->label();
530 const int sbl
= index
/ menu
.persub
, i
= index
- (sbl
* menu
.persub
);
531 const unsigned int half_w
= menu
.item_h
/ 2, quarter_w
= menu
.item_h
/ 4;
532 int item_x
= (sbl
* menu
.item_w
), item_y
= (i
* menu
.item_h
);
533 int hilite_x
= item_x
, hilite_y
= item_y
, hoff_x
= 0, hoff_y
= 0;
534 int text_x
= 0, text_y
= 0, sel_x
= 0, oppsel_x
= 0, sel_y
= 0;
535 unsigned int hilite_w
= menu
.item_w
, hilite_h
= menu
.item_h
, text_w
= 0,
539 text_w
= screen
->getMenuStyle()->f_font
->measureString(text
);
540 text_y
= item_y
+ menu
.bevel_w
/ 2;
542 switch(screen
->getMenuStyle()->f_justify
) {
544 text_x
= item_x
+ menu
.bevel_w
+ menu
.item_h
+ 1;
548 text_x
= item_x
+ menu
.item_w
- (menu
.item_h
+ menu
.bevel_w
+ text_w
);
552 text_x
= item_x
+ ((menu
.item_w
+ 1 - text_w
) / 2);
556 text_h
= menu
.item_h
- menu
.bevel_w
;
559 const MenuStyle
* const style
= screen
->getMenuStyle();
560 const BPen
hipen(style
->hilite
.color());
561 // match the text color
562 const BPen
pen((highlight
? style
->h_text
:
563 (item
->isEnabled() ? style
->f_text
:
568 if (screen
->getMenuStyle()->bullet_pos
== Right
)
569 sel_x
+= (menu
.item_w
- menu
.item_h
- menu
.bevel_w
);
572 if (screen
->getMenuStyle()->bullet_pos
== Right
)
573 oppsel_x
-= (menu
.item_w
- menu
.item_h
- menu
.bevel_w
);
575 oppsel_x
+= (menu
.item_w
- menu
.item_h
- menu
.bevel_w
);
576 sel_y
= item_y
+ quarter_w
;
579 XClearArea(display
, menu
.frame
, item_x
, item_y
, menu
.item_w
, menu
.item_h
,
581 } else if (! (x
== y
&& y
== -1 && w
== h
&& h
== 0)) {
582 // calculate the which part of the hilite to redraw
583 if (! (max(item_x
, x
) <= min
<signed>(item_x
+ menu
.item_w
, x
+ w
) &&
584 max(item_y
, y
) <= min
<signed>(item_y
+ menu
.item_h
, y
+ h
))) {
587 hilite_x
= max(item_x
, x
);
588 hilite_y
= max(item_y
, y
);
589 hilite_w
= min(item_x
+ menu
.item_w
, x
+ w
) - hilite_x
;
590 hilite_h
= min(item_y
+ menu
.item_h
, y
+ h
) - hilite_y
;
591 hoff_x
= hilite_x
% menu
.item_w
;
592 hoff_y
= hilite_y
% menu
.item_h
;
595 // check if we need to redraw the text
596 const int text_ry
= item_y
+ (menu
.bevel_w
/ 2);
597 if (! (max(text_x
, x
) <= min
<signed>(text_x
+ text_w
, x
+ w
) &&
598 max(text_ry
, y
) <= min
<signed>(text_ry
+ text_h
, y
+ h
)))
601 // check if we need to redraw the select pixmap/menu bullet
602 if (! (max(sel_x
, x
) <= min
<signed>(sel_x
+ half_w
, x
+ w
) &&
603 max(sel_y
, y
) <= min
<signed>(sel_y
+ half_w
, y
+ h
)))
606 // check if we need to redraw the select pixmap/menu bullet
607 // on the opposite side of the menu
608 if (! (max(oppsel_x
, x
) <= min
<signed>(oppsel_x
+ half_w
, x
+ w
) &&
609 max(sel_y
, y
) <= min
<signed>(sel_y
+ half_w
, y
+ h
)))
613 if (dohilite
&& highlight
&& (menu
.hilite_pixmap
!= ParentRelative
)) {
614 if (menu
.hilite_pixmap
)
615 XCopyArea(display
, menu
.hilite_pixmap
, menu
.frame
,
616 hipen
.gc(), hoff_x
, hoff_y
,
617 hilite_w
, hilite_h
, hilite_x
, hilite_y
);
619 XFillRectangle(display
, menu
.frame
, hipen
.gc(),
620 hilite_x
, hilite_y
, hilite_w
, hilite_h
);
623 if (dooppsel
&& item
->isSelected()) {
625 if ( style
->tick_image
.mask
!= None
) {
626 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
627 oppsel_x
, item_y
+ menu
.item_h
/2 - style
->tick_image
.h
/2);
628 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(),
629 style
->tick_image
.mask
);
631 XFillRectangle(blackbox
->getXDisplay(), menu
.frame
, pen
.gc(),
632 oppsel_x
, item_y
+ menu
.item_h
/2 - style
->tick_image
.h
/2,
634 style
->tick_image
.h
);
636 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), None
);
638 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
641 #endif // BITMAPBUTTONS
644 pts
[0].x
= oppsel_x
+ 0;
645 pts
[0].y
= sel_y
+ 2;
663 XFillPolygon(display
, menu
.frame
, pen
.gc(), pts
, 6, Nonconvex
,
667 #endif // BITMAPBUTTONS
670 if (dotext
&& text
) {
671 style
->f_font
->drawString(menu
.frame
, text_x
, text_y
,
672 (highlight
? style
->h_text
:
673 (item
->isEnabled() ? style
->f_text
:
678 if (dosel
&& item
->submenu()) {
680 if ( style
->bullet_image
.mask
!= None
) {
681 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
682 sel_x
, item_y
+ menu
.item_h
/2 - style
->bullet_image
.h
/2);
683 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(),
684 style
->bullet_image
.mask
);
686 XFillRectangle(blackbox
->getXDisplay(), menu
.frame
, pen
.gc(),
687 sel_x
, item_y
+ menu
.item_h
/2 - style
->bullet_image
.h
/2,
688 style
->bullet_image
.w
, style
->bullet_image
.h
);
690 XSetClipMask(blackbox
->getXDisplay(), pen
.gc(), None
);
692 XSetClipOrigin(blackbox
->getXDisplay(), pen
.gc(),
695 #endif // BITMAPBUTTONS
696 const int bullet_size
= 3;
698 switch (screen
->getMenuStyle()->bullet
) {
700 XDrawRectangle(display
, menu
.frame
, pen
.gc(), sel_x
, sel_y
,
701 bullet_size
* 2, bullet_size
* 2);
707 if (screen
->getMenuStyle()->bullet_pos
== Right
) {
708 tri
[0].x
= sel_x
+ quarter_w
- bullet_size
;
709 tri
[0].y
= sel_y
+ quarter_w
- bullet_size
;
710 tri
[1].x
= 2 * bullet_size
;
711 tri
[1].y
= bullet_size
;
712 tri
[2].x
= -(2 * bullet_size
);
713 tri
[2].y
= bullet_size
;
715 tri
[0].x
= sel_x
+ quarter_w
- bullet_size
;
716 tri
[0].y
= item_y
+ half_w
;
717 tri
[1].x
= 2 * bullet_size
;
718 tri
[1].y
= bullet_size
;
720 tri
[2].y
= -(2 * bullet_size
);
723 XFillPolygon(display
, menu
.frame
, pen
.gc(), tri
, 3, Convex
,
730 dia
[0].x
= sel_x
+ quarter_w
- bullet_size
;
731 dia
[0].y
= item_y
+ half_w
;
732 dia
[1].x
= bullet_size
;
733 dia
[1].y
= -bullet_size
;
734 dia
[2].x
= bullet_size
;
735 dia
[2].y
= bullet_size
;
736 dia
[3].x
= -bullet_size
;
737 dia
[3].y
= bullet_size
;
739 XFillPolygon(display
, menu
.frame
, pen
.gc(), dia
, 4, Convex
,
745 #endif // BITMAPBUTTONS
750 void Basemenu::setLabel(const string
& label
) {
755 void Basemenu::setItemSelected(int index
, bool sel
) {
757 BasemenuItem
*item
= find(index
);
760 item
->setSelected(sel
);
761 if (visible
) drawItem(index
, (index
== which_sub
), True
);
765 bool Basemenu::isItemSelected(int index
) {
767 BasemenuItem
*item
= find(index
);
768 if (! item
) return False
;
770 return item
->isSelected();
774 void Basemenu::setItemEnabled(int index
, bool enable
) {
776 BasemenuItem
*item
= find(index
);
779 item
->setEnabled(enable
);
780 if (visible
) drawItem(index
, (index
== which_sub
), True
);
784 bool Basemenu::isItemEnabled(int index
) {
786 BasemenuItem
*item
= find(index
);
787 if (! item
) return False
;
789 return item
->isEnabled();
793 void Basemenu::buttonPressEvent(XButtonEvent
*be
) {
794 if (be
->window
== menu
.frame
) {
795 const int sbl
= (be
->x
/ menu
.item_w
), i
= (be
->y
/ menu
.item_h
),
796 w
= (sbl
* menu
.persub
) + i
;
798 BasemenuItem
*item
= find(w
);
807 drawItem(w
, (item
->isEnabled()), True
);
810 menu
.x_move
= be
->x_root
- menu
.x
;
811 menu
.y_move
= be
->y_root
- menu
.y
;
816 void Basemenu::buttonReleaseEvent(XButtonEvent
*re
) {
817 if (re
->window
== menu
.title
) {
822 drawSubmenu(which_sub
);
825 if (re
->x
>= 0 && re
->x
<= static_cast<signed>(menu
.width
) &&
826 re
->y
>= 0 && re
->y
<= static_cast<signed>(menu
.title_h
))
829 } else if (re
->window
== menu
.frame
&&
830 re
->x
>= 0 && re
->x
< static_cast<signed>(menu
.width
) &&
831 re
->y
>= 0 && re
->y
< static_cast<signed>(menu
.frame_h
)) {
832 if (re
->button
== 3) {
835 const int sbl
= (re
->x
/ menu
.item_w
), i
= (re
->y
/ menu
.item_h
),
836 ix
= sbl
* menu
.item_w
, iy
= i
* menu
.item_h
,
837 w
= (sbl
* menu
.persub
) + i
,
838 p
= (which_sbl
* menu
.persub
) + which_press
;
840 if (w
>= 0 && w
< static_cast<signed>(menuitems
.size())) {
841 drawItem(p
, (p
== which_sub
), True
);
843 if (p
== w
&& isItemEnabled(w
)) {
844 if (re
->x
> ix
&& re
->x
< static_cast<signed>(ix
+ menu
.item_w
) &&
845 re
->y
> iy
&& re
->y
< static_cast<signed>(iy
+ menu
.item_h
)) {
846 itemSelected(re
->button
, w
);
850 drawItem(p
, False
, True
);
857 void Basemenu::motionNotifyEvent(XMotionEvent
*me
) {
858 if (me
->window
== menu
.title
&& (me
->state
& Button1Mask
)) {
861 if (parent
&& ! torn
) {
862 parent
->drawItem(parent
->which_sub
, False
, True
);
863 parent
->which_sub
= -1;
866 moving
= torn
= True
;
869 drawSubmenu(which_sub
);
871 menu
.x
= me
->x_root
- menu
.x_move
,
872 menu
.y
= me
->y_root
- menu
.y_move
;
874 XMoveWindow(display
, menu
.window
, menu
.x
, menu
.y
);
877 drawSubmenu(which_sub
);
880 } else if (me
->window
== menu
.frame
&&
881 me
->x
>= 0 && me
->x
< static_cast<signed>(menu
.width
) &&
882 me
->y
>= 0 && me
->y
< static_cast<signed>(menu
.frame_h
)) {
883 const int sbl
= (me
->x
/ menu
.item_w
), i
= (me
->y
/ menu
.item_h
),
884 w
= (sbl
* menu
.persub
) + i
;
886 if ((i
!= which_press
|| sbl
!= which_sbl
) &&
887 (w
>= 0 && w
< static_cast<signed>(menuitems
.size()))) {
888 if (which_press
!= -1 && which_sbl
!= -1) {
889 const int p
= (which_sbl
* menu
.persub
) + which_press
;
890 BasemenuItem
*item
= find(p
);
893 drawItem(p
, False
, True
);
894 if (item
->submenu() &&
895 item
->submenu()->isVisible() &&
896 ! item
->submenu()->isTorn()) {
897 item
->submenu()->internal_hide();
905 BasemenuItem
*itmp
= find(w
);
911 drawItem(w
, (itmp
->isEnabled()), True
);
917 void Basemenu::exposeEvent(XExposeEvent
*ee
) {
918 if (ee
->window
== menu
.title
) {
920 } else if (ee
->window
== menu
.frame
) {
921 // this is a complicated algorithm... lets do it step by step...
922 // first... we see in which sub level the expose starts... and how many
923 // items down in that sublevel
925 const int sbl
= (ee
->x
/ menu
.item_w
), id
= (ee
->y
/ menu
.item_h
),
926 // next... figure out how many sublevels over the redraw spans
927 sbl_d
= ((ee
->x
+ ee
->width
) / menu
.item_w
);
928 // then we see how many items down to redraw
929 int id_d
= ((ee
->y
+ ee
->height
) / menu
.item_h
);
931 if (id_d
> menu
.persub
) id_d
= menu
.persub
;
933 // draw the sublevels and the number of items the exposure spans
934 MenuItems::iterator it
,
935 end
= menuitems
.end();
936 for (int i
= sbl
; i
<= sbl_d
; i
++) {
937 // set the iterator to the first item in the sublevel needing redrawing
938 it
= menuitems
.begin() + (id
+ (i
* menu
.persub
));
939 for (int ii
= id
; ii
<= id_d
&& it
!= end
; ++it
, ii
++) {
940 const int index
= ii
+ (i
* menu
.persub
);
942 drawItem(index
, (which_sub
== index
), False
,
943 ee
->x
, ee
->y
, ee
->width
, ee
->height
);
950 void Basemenu::enterNotifyEvent(XCrossingEvent
*ce
) {
951 if (ce
->window
== menu
.frame
) {
952 menu
.x_shift
= menu
.x
, menu
.y_shift
= menu
.y
;
953 if (menu
.x
+ menu
.width
> screen
->getWidth()) {
954 menu
.x_shift
= screen
->getWidth() - menu
.width
-
955 screen
->getBorderWidth();
957 } else if (menu
.x
< 0) {
958 menu
.x_shift
= -screen
->getBorderWidth();
962 if (menu
.y
+ menu
.height
> screen
->getHeight()) {
963 menu
.y_shift
= screen
->getHeight() - menu
.height
-
964 screen
->getBorderWidth();
966 } else if (menu
.y
+ static_cast<signed>(menu
.title_h
) < 0) {
967 menu
.y_shift
= -screen
->getBorderWidth();
972 XMoveWindow(display
, menu
.window
, menu
.x_shift
, menu
.y_shift
);
974 if (which_sub
!= -1) {
975 BasemenuItem
*tmp
= find(which_sub
);
976 if (tmp
->submenu()->isVisible()) {
977 const int sbl
= (ce
->x
/ menu
.item_w
), i
= (ce
->y
/ menu
.item_h
),
978 w
= (sbl
* menu
.persub
) + i
;
980 if (w
!= which_sub
&& ! tmp
->submenu()->isTorn()) {
981 tmp
->submenu()->internal_hide();
983 drawItem(which_sub
, False
, True
);
992 void Basemenu::leaveNotifyEvent(XCrossingEvent
*ce
) {
993 if (ce
->window
== menu
.frame
) {
994 if (which_press
!= -1 && which_sbl
!= -1 && menuitems
.size() > 0) {
995 const int p
= (which_sbl
* menu
.persub
) + which_press
;
997 drawItem(p
, (p
== which_sub
), True
);
999 which_sbl
= which_press
= -1;
1003 XMoveWindow(display
, menu
.window
, menu
.x
, menu
.y
);
1006 if (which_sub
!= -1) drawSubmenu(which_sub
);
1012 void Basemenu::reconfigure(void) {
1013 XSetWindowBackground(display
, menu
.window
,
1014 screen
->getBorderColor()->pixel());
1015 XSetWindowBorder(display
, menu
.window
,
1016 screen
->getBorderColor()->pixel());
1017 XSetWindowBorderWidth(display
, menu
.window
, screen
->getBorderWidth());
1019 menu
.bevel_w
= screen
->getBevelWidth();
1024 void Basemenu::changeItemLabel(unsigned int index
, const string
& label
) {
1025 BasemenuItem
*item
= find(index
);
1027 item
->newLabel(label
);