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
46 #include "blackbox.hh"
47 #include "Basemenu.hh"
54 static Basemenu
*shown
= (Basemenu
*) 0;
56 Basemenu::Basemenu(BScreen
*scrn
) {
58 blackbox
= screen
->getBlackbox();
59 image_ctrl
= screen
->getImageControl();
60 display
= blackbox
->getXDisplay();
61 parent
= (Basemenu
*) 0;
62 alignment
= AlignDontCare
;
88 menu
.sel_pixmap
= None
;
90 menu
.bevel_w
= screen
->getBevelWidth();
93 menu
.width
= menu
.title_h
= menu
.item_w
= menu
.frame_h
=
94 screen
->getMenuStyle()->t_fontset_extents
->max_ink_extent
.height
+
97 menu
.width
= menu
.title_h
= menu
.item_w
= menu
.frame_h
=
98 screen
->getMenuStyle()->t_font
->ascent
+
99 screen
->getMenuStyle()->t_font
->descent
+ (menu
.bevel_w
* 2);
105 MenuStyle
*style
= screen
->getMenuStyle();
106 if (i18n
.multibyte()) {
107 menu
.item_h
= style
->f_fontset_extents
->max_ink_extent
.height
+
110 menu
.item_h
= style
->f_font
->ascent
+ style
->f_font
->descent
+
114 menu
.height
= menu
.title_h
+ screen
->getBorderWidth() + menu
.frame_h
;
116 unsigned long attrib_mask
= CWBackPixmap
| CWBackPixel
| CWBorderPixel
|
117 CWColormap
| CWOverrideRedirect
| CWEventMask
;
118 XSetWindowAttributes attrib
;
119 attrib
.background_pixmap
= None
;
120 attrib
.background_pixel
= attrib
.border_pixel
=
121 screen
->getBorderColor()->pixel();
122 attrib
.colormap
= screen
->getColormap();
123 attrib
.override_redirect
= True
;
124 attrib
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
125 ButtonMotionMask
| ExposureMask
;
128 XCreateWindow(display
, screen
->getRootWindow(),
129 menu
.x
, menu
.y
, menu
.width
, menu
.height
,
130 screen
->getBorderWidth(), screen
->getDepth(),
131 InputOutput
, screen
->getVisual(), attrib_mask
, &attrib
);
132 blackbox
->saveMenuSearch(menu
.window
, this);
134 attrib_mask
= CWBackPixmap
| CWBackPixel
| CWBorderPixel
| CWEventMask
;
135 attrib
.background_pixel
= screen
->getBorderColor()->pixel();
136 attrib
.event_mask
|= EnterWindowMask
| LeaveWindowMask
;
139 XCreateWindow(display
, menu
.window
, 0, 0, menu
.width
, menu
.height
, 0,
140 screen
->getDepth(), InputOutput
, screen
->getVisual(),
141 attrib_mask
, &attrib
);
142 blackbox
->saveMenuSearch(menu
.title
, this);
144 attrib
.event_mask
|= PointerMotionMask
;
145 menu
.frame
= XCreateWindow(display
, menu
.window
, 0,
146 menu
.title_h
+ screen
->getBorderWidth(),
147 menu
.width
, menu
.frame_h
, 0,
148 screen
->getDepth(), InputOutput
,
149 screen
->getVisual(), attrib_mask
, &attrib
);
150 blackbox
->saveMenuSearch(menu
.frame
, this);
152 // even though this is the end of the constructor the menu is still not
153 // completely created. items must be inserted and it must be update()'d
156 Basemenu::~Basemenu(void) {
157 XUnmapWindow(display
, menu
.window
);
159 if (shown
&& shown
->getWindowID() == getWindowID())
160 shown
= (Basemenu
*) 0;
162 MenuItems::const_iterator it
= menuitems
.begin();
163 while (it
!= menuitems
.end()) {
164 BasemenuItem
*item
= *it
;
165 if ((! internal_menu
)) {
166 Basemenu
*tmp
= (Basemenu
*) item
->submenu();
168 if (! tmp
->internal_menu
) {
171 tmp
->internal_hide();
178 std::for_each(menuitems
.begin(), menuitems
.end(), PointerAssassin());
180 if (menu
.title_pixmap
)
181 image_ctrl
->removeImage(menu
.title_pixmap
);
183 if (menu
.frame_pixmap
)
184 image_ctrl
->removeImage(menu
.frame_pixmap
);
186 if (menu
.hilite_pixmap
)
187 image_ctrl
->removeImage(menu
.hilite_pixmap
);
190 image_ctrl
->removeImage(menu
.sel_pixmap
);
192 blackbox
->removeMenuSearch(menu
.title
);
193 XDestroyWindow(display
, menu
.title
);
195 blackbox
->removeMenuSearch(menu
.frame
);
196 XDestroyWindow(display
, menu
.frame
);
198 blackbox
->removeMenuSearch(menu
.window
);
199 XDestroyWindow(display
, menu
.window
);
203 BasemenuItem::~BasemenuItem(void) {}
206 BasemenuItem
*Basemenu::find(int index
) {
207 if (index
< 0 || index
> static_cast<signed>(menuitems
.size()))
208 return (BasemenuItem
*) 0;
210 return *(menuitems
.begin() + index
);
214 int Basemenu::insert(BasemenuItem
*item
, int pos
) {
216 menuitems
.push_back(item
);
218 assert(pos
< static_cast<signed>(menuitems
.size()));
219 menuitems
.insert((menuitems
.begin() + pos
), item
);
221 return menuitems
.size();
225 int Basemenu::insert(const string
& label
, int function
,
226 const string
& exec
, int pos
) {
227 BasemenuItem
*item
= new BasemenuItem(label
, function
, exec
);
228 return insert(item
, pos
);
232 int Basemenu::insert(const string
& label
, Basemenu
*submenu
, int pos
) {
233 BasemenuItem
*item
= new BasemenuItem(label
, submenu
);
234 submenu
->parent
= this;
236 return insert(item
, pos
);
240 int Basemenu::remove(int index
) {
241 BasemenuItem
*item
= find(index
);
242 if (! item
) return -1;
244 if ((! internal_menu
)) {
245 Basemenu
*tmp
= (Basemenu
*) item
->submenu();
247 if (! tmp
->internal_menu
) {
250 tmp
->internal_hide();
257 if (which_sub
== index
)
259 else if (which_sub
> index
)
262 menuitems
.erase(menuitems
.begin() + index
);
264 return menuitems
.size();
268 void Basemenu::update(void) {
269 MenuStyle
*style
= screen
->getMenuStyle();
270 if (i18n
.multibyte()) {
271 menu
.item_h
= style
->f_fontset_extents
->max_ink_extent
.height
+
273 menu
.title_h
= style
->t_fontset_extents
->max_ink_extent
.height
+
276 menu
.item_h
= style
->f_font
->ascent
+ style
->f_font
->descent
+
278 menu
.title_h
= style
->t_font
->ascent
+ style
->t_font
->descent
+
283 const char *s
= getLabel();
286 if (i18n
.multibyte()) {
287 XRectangle ink
, logical
;
288 XmbTextExtents(screen
->getMenuStyle()->t_fontset
, s
, l
, &ink
, &logical
);
289 menu
.item_w
= logical
.width
;
291 menu
.item_w
= XTextWidth(screen
->getMenuStyle()->t_font
, s
, l
);
294 menu
.item_w
+= (menu
.bevel_w
* 2);
300 MenuItems::iterator it
= menuitems
.begin(), end
= menuitems
.end();
301 for (; it
!= end
; ++it
) {
302 BasemenuItem
*tmp
= *it
;
303 const char *s
= tmp
->l
.c_str();
306 if (i18n
.multibyte()) {
307 XRectangle ink
, logical
;
308 XmbTextExtents(screen
->getMenuStyle()->f_fontset
, s
, l
, &ink
, &logical
);
311 ii
= XTextWidth(screen
->getMenuStyle()->f_font
, s
, l
);
313 ii
+= (menu
.bevel_w
* 2) + (menu
.item_h
* 2);
315 menu
.item_w
= ((menu
.item_w
< ii
) ? ii
: menu
.item_w
);
318 if (! menuitems
.empty()) {
321 unsigned int menu_size
= menuitems
.size();
322 while (((menu
.item_h
* (menu_size
+ 1) / menu
.sublevels
)
323 + menu
.title_h
+ screen
->getBorderWidth()) >
327 if (menu
.sublevels
< menu
.minsub
) menu
.sublevels
= menu
.minsub
;
329 menu
.persub
= menu_size
/ menu
.sublevels
;
330 if (menu_size
% menu
.sublevels
) menu
.persub
++;
336 menu
.width
= (menu
.sublevels
* (menu
.item_w
));
337 if (! menu
.width
) menu
.width
= menu
.item_w
;
339 menu
.frame_h
= (menu
.item_h
* menu
.persub
);
340 menu
.height
= ((title_vis
) ? menu
.title_h
+ screen
->getBorderWidth() : 0) +
342 if (! menu
.frame_h
) menu
.frame_h
= 1;
343 if (menu
.height
< 1) menu
.height
= 1;
348 tmp
= menu
.title_pixmap
;
349 texture
= &(screen
->getMenuStyle()->title
);
350 if (texture
->texture() == (BTexture::Flat
| BTexture::Solid
)) {
351 menu
.title_pixmap
= None
;
352 XSetWindowBackground(display
, menu
.title
,
353 texture
->color().pixel());
356 image_ctrl
->renderImage(menu
.width
, menu
.title_h
, *texture
);
357 XSetWindowBackgroundPixmap(display
, menu
.title
, menu
.title_pixmap
);
359 if (tmp
) image_ctrl
->removeImage(tmp
);
360 XClearWindow(display
, menu
.title
);
363 tmp
= menu
.frame_pixmap
;
364 texture
= &(screen
->getMenuStyle()->frame
);
365 if (texture
->texture() == (BTexture::Flat
| BTexture::Solid
)) {
366 menu
.frame_pixmap
= None
;
367 XSetWindowBackground(display
, menu
.frame
,
368 texture
->color().pixel());
371 image_ctrl
->renderImage(menu
.width
, menu
.frame_h
, *texture
);
372 XSetWindowBackgroundPixmap(display
, menu
.frame
, menu
.frame_pixmap
);
374 if (tmp
) image_ctrl
->removeImage(tmp
);
376 tmp
= menu
.hilite_pixmap
;
377 texture
= &(screen
->getMenuStyle()->hilite
);
378 if (texture
->texture() == (BTexture::Flat
| BTexture::Solid
)) {
379 menu
.hilite_pixmap
= None
;
382 image_ctrl
->renderImage(menu
.item_w
, menu
.item_h
, *texture
);
384 if (tmp
) image_ctrl
->removeImage(tmp
);
386 tmp
= menu
.sel_pixmap
;
387 if (texture
->texture() == (BTexture::Flat
| BTexture::Solid
)) {
388 menu
.sel_pixmap
= None
;
390 int hw
= menu
.item_h
/ 2;
392 image_ctrl
->renderImage(hw
, hw
, *texture
);
394 if (tmp
) image_ctrl
->removeImage(tmp
);
396 XResizeWindow(display
, menu
.window
, menu
.width
, menu
.height
);
399 XResizeWindow(display
, menu
.title
, menu
.width
, menu
.title_h
);
401 XMoveResizeWindow(display
, menu
.frame
, 0,
402 ((title_vis
) ? menu
.title_h
+
403 screen
->getBorderWidth() : 0), menu
.width
,
406 XClearWindow(display
, menu
.window
);
407 XClearWindow(display
, menu
.title
);
408 XClearWindow(display
, menu
.frame
);
410 if (title_vis
&& visible
) redrawTitle();
412 const int menu_size
= menuitems
.size();
413 for (int i
= 0; visible
&& i
< menu_size
; i
++) {
414 if (i
== which_sub
) {
415 drawItem(i
, True
, 0);
418 drawItem(i
, False
, 0);
422 if (parent
&& visible
)
423 parent
->drawSubmenu(parent
->which_sub
);
425 XMapSubwindows(display
, menu
.window
);
429 void Basemenu::show(void) {
430 XMapSubwindows(display
, menu
.window
);
431 XMapWindow(display
, menu
.window
);
435 if (shown
&& (! shown
->torn
))
443 void Basemenu::hide(void) {
444 if ((! torn
) && hide_tree
&& parent
&& parent
->isVisible()) {
445 Basemenu
*p
= parent
;
447 while (p
->isVisible() && (! p
->torn
) && p
->parent
) p
= p
->parent
;
455 void Basemenu::internal_hide(void) {
456 BasemenuItem
*tmp
= find(which_sub
);
458 tmp
->submenu()->internal_hide();
460 if (parent
&& (! torn
)) {
461 parent
->drawItem(parent
->which_sub
, False
, True
);
463 parent
->which_sub
= -1;
464 } else if (shown
&& shown
->menu
.window
== menu
.window
) {
465 shown
= (Basemenu
*) 0;
468 torn
= visible
= False
;
469 which_sub
= which_press
= which_sub
= -1;
471 XUnmapWindow(display
, menu
.window
);
475 void Basemenu::move(int x
, int y
) {
478 XMoveWindow(display
, menu
.window
, x
, y
);
480 drawSubmenu(which_sub
);
484 void Basemenu::redrawTitle(void) {
485 const char *text
= (! menu
.label
.empty()) ? getLabel() :
486 i18n(BasemenuSet
, BasemenuBlackboxMenu
, "Blackbox Menu");
487 int dx
= menu
.bevel_w
, len
= strlen(text
);
490 if (i18n
.multibyte()) {
491 XRectangle ink
, logical
;
492 XmbTextExtents(screen
->getMenuStyle()->t_fontset
, text
, len
,
496 l
= XTextWidth(screen
->getMenuStyle()->t_font
, text
, len
);
499 l
+= (menu
.bevel_w
* 2);
501 switch (screen
->getMenuStyle()->t_justify
) {
503 dx
+= menu
.width
- l
;
507 dx
+= (menu
.width
- l
) / 2;
515 MenuStyle
*style
= screen
->getMenuStyle();
516 BPen
pen(style
->t_text
, style
->t_font
);
517 if (i18n
.multibyte())
518 XmbDrawString(display
, menu
.title
, style
->t_fontset
, pen
.gc(), dx
,
519 (menu
.bevel_w
- style
->t_fontset_extents
->max_ink_extent
.y
),
522 XDrawString(display
, menu
.title
, pen
.gc(), dx
,
523 (style
->t_font
->ascent
+ menu
.bevel_w
), text
, len
);
527 void Basemenu::drawSubmenu(int index
) {
528 BasemenuItem
*item
= find(which_sub
);
529 if (item
&& item
->submenu() && ! item
->submenu()->isTorn() &&
531 item
->submenu()->internal_hide();
536 Basemenu
*submenu
= item
->submenu();
538 if (submenu
&& visible
&& ! submenu
->isTorn() && item
->isEnabled()) {
539 if (submenu
->parent
!= this) submenu
->parent
= this;
540 int sbl
= index
/ menu
.persub
, i
= index
- (sbl
* menu
.persub
),
541 x
= menu
.x
+ ((menu
.item_w
* (sbl
+ 1)) + screen
->getBorderWidth()), y
;
543 if (alignment
== AlignTop
) {
544 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
545 ((title_vis
) ? menu
.title_h
+ screen
->getBorderWidth() : 0) -
546 ((submenu
->title_vis
) ?
547 submenu
->menu
.title_h
+ screen
->getBorderWidth() : 0));
549 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
551 ((title_vis
) ? menu
.title_h
+ screen
->getBorderWidth() : 0) -
552 ((submenu
->title_vis
) ?
553 submenu
->menu
.title_h
+ screen
->getBorderWidth() : 0));
556 if (alignment
== AlignBottom
&&
557 (y
+ submenu
->menu
.height
) > ((shifted
) ? menu
.y_shift
:
558 menu
.y
) + menu
.height
)
559 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
560 menu
.height
- submenu
->menu
.height
);
562 if ((x
+ submenu
->getWidth()) > screen
->getWidth())
563 x
= ((shifted
) ? menu
.x_shift
: menu
.x
) -
564 submenu
->getWidth() - screen
->getBorderWidth();
568 if ((y
+ submenu
->getHeight()) > screen
->getHeight())
569 y
= screen
->getHeight() - submenu
->getHeight() -
570 (screen
->getBorderWidth() * 2);
574 if (! moving
) drawItem(index
, True
);
576 if (! submenu
->isVisible())
578 submenu
->moving
= moving
;
586 bool Basemenu::hasSubmenu(int index
) {
587 BasemenuItem
*item
= find(index
);
588 if (item
&& item
->submenu())
594 void Basemenu::drawItem(int index
, bool highlight
, bool clear
,
595 int x
, int y
, unsigned int w
, unsigned int h
)
597 BasemenuItem
*item
= find(index
);
600 bool dotext
= True
, dohilite
= True
, dosel
= True
;
601 const char *text
= item
->label();
602 int sbl
= index
/ menu
.persub
, i
= index
- (sbl
* menu
.persub
);
603 int item_x
= (sbl
* menu
.item_w
), item_y
= (i
* menu
.item_h
);
604 int hilite_x
= item_x
, hilite_y
= item_y
, hoff_x
= 0, hoff_y
= 0;
605 int text_x
= 0, text_y
= 0, len
= strlen(text
), sel_x
= 0, sel_y
= 0;
606 unsigned int hilite_w
= menu
.item_w
, hilite_h
= menu
.item_h
, text_w
= 0,
608 unsigned int half_w
= menu
.item_h
/ 2, quarter_w
= menu
.item_h
/ 4;
611 if (i18n
.multibyte()) {
612 XRectangle ink
, logical
;
613 XmbTextExtents(screen
->getMenuStyle()->f_fontset
,
614 text
, len
, &ink
, &logical
);
615 text_w
= logical
.width
;
616 text_y
= item_y
+ (menu
.bevel_w
/ 2) -
617 screen
->getMenuStyle()->f_fontset_extents
->max_ink_extent
.y
;
619 text_w
= XTextWidth(screen
->getMenuStyle()->f_font
, text
, len
);
621 screen
->getMenuStyle()->f_font
->ascent
+
625 switch(screen
->getMenuStyle()->f_justify
) {
627 text_x
= item_x
+ menu
.bevel_w
+ menu
.item_h
+ 1;
631 text_x
= item_x
+ menu
.item_w
- (menu
.item_h
+ menu
.bevel_w
+ text_w
);
635 text_x
= item_x
+ ((menu
.item_w
+ 1 - text_w
) / 2);
639 text_h
= menu
.item_h
- menu
.bevel_w
;
642 MenuStyle
*style
= screen
->getMenuStyle();
643 BPen
pen((highlight
|| item
->isSelected()) ? style
->h_text
: style
->f_text
),
644 textpen((highlight
) ? style
->h_text
:
645 item
->isEnabled() ? style
->f_text
: style
->d_text
, style
->f_font
),
646 hipen(style
->hilite
.color());
650 if (screen
->getMenuStyle()->bullet_pos
== Right
)
651 sel_x
+= (menu
.item_w
- menu
.item_h
- menu
.bevel_w
);
653 sel_y
= item_y
+ quarter_w
;
656 XClearArea(display
, menu
.frame
, item_x
, item_y
, menu
.item_w
, menu
.item_h
,
658 } else if (! (x
== y
&& y
== -1 && w
== h
&& h
== 0)) {
659 // calculate the which part of the hilite to redraw
660 if (! (max(item_x
, x
) <= min
<signed>(item_x
+ menu
.item_w
, x
+ w
) &&
661 max(item_y
, y
) <= min
<signed>(item_y
+ menu
.item_h
, y
+ h
))) {
664 hilite_x
= max(item_x
, x
);
665 hilite_y
= max(item_y
, y
);
666 hilite_w
= min(item_x
+ menu
.item_w
, x
+ w
) - hilite_x
;
667 hilite_h
= min(item_y
+ menu
.item_h
, y
+ h
) - hilite_y
;
668 hoff_x
= hilite_x
% menu
.item_w
;
669 hoff_y
= hilite_y
% menu
.item_h
;
672 // check if we need to redraw the text
673 int text_ry
= item_y
+ (menu
.bevel_w
/ 2);
674 if (! (max(text_x
, x
) <= min
<signed>(text_x
+ text_w
, x
+ w
) &&
675 max(text_ry
, y
) <= min
<signed>(text_ry
+ text_h
, y
+ h
)))
678 // check if we need to redraw the select pixmap/menu bullet
679 if (! (max(sel_x
, x
) <= min
<signed>(sel_x
+ half_w
, x
+ w
) &&
680 max(sel_y
, y
) <= min
<signed>(sel_y
+ half_w
, y
+ h
)))
684 if (dohilite
&& highlight
&& (menu
.hilite_pixmap
!= ParentRelative
)) {
685 if (menu
.hilite_pixmap
)
686 XCopyArea(display
, menu
.hilite_pixmap
, menu
.frame
,
687 hipen
.gc(), hoff_x
, hoff_y
,
688 hilite_w
, hilite_h
, hilite_x
, hilite_y
);
690 XFillRectangle(display
, menu
.frame
, hipen
.gc(),
691 hilite_x
, hilite_y
, hilite_w
, hilite_h
);
692 } else if (dosel
&& item
->isSelected() &&
693 (menu
.sel_pixmap
!= ParentRelative
)) {
695 XCopyArea(display
, menu
.sel_pixmap
, menu
.frame
, hipen
.gc(), 0, 0,
696 half_w
, half_w
, sel_x
, sel_y
);
698 XFillRectangle(display
, menu
.frame
, hipen
.gc(), sel_x
, sel_y
, half_w
, half_w
);
701 if (dotext
&& text
) {
702 if (i18n
.multibyte())
703 XmbDrawString(display
, menu
.frame
, screen
->getMenuStyle()->f_fontset
,
704 textpen
.gc(), text_x
, text_y
, text
, len
);
706 XDrawString(display
, menu
.frame
, textpen
.gc(), text_x
, text_y
, text
, len
);
709 if (dosel
&& item
->submenu()) {
710 switch (screen
->getMenuStyle()->bullet
) {
712 XDrawRectangle(display
, menu
.frame
, pen
.gc(), sel_x
, sel_y
, half_w
, half_w
);
718 if (screen
->getMenuStyle()->bullet_pos
== Right
) {
719 tri
[0].x
= sel_x
+ quarter_w
- 2;
720 tri
[0].y
= sel_y
+ quarter_w
- 2;
726 tri
[0].x
= sel_x
+ quarter_w
- 2;
727 tri
[0].y
= item_y
+ half_w
;
734 XFillPolygon(display
, menu
.frame
, pen
.gc(), tri
, 3, Convex
,
741 dia
[0].x
= sel_x
+ quarter_w
- 3;
742 dia
[0].y
= item_y
+ half_w
;
750 XFillPolygon(display
, menu
.frame
, pen
.gc(), dia
, 4, Convex
,
758 void Basemenu::setLabel(const string
& label
) {
763 void Basemenu::setItemSelected(int index
, bool sel
) {
765 BasemenuItem
*item
= find(index
);
768 item
->setSelected(sel
);
769 if (visible
) drawItem(index
, (index
== which_sub
), True
);
773 bool Basemenu::isItemSelected(int index
) {
775 BasemenuItem
*item
= find(index
);
776 if (! item
) return False
;
778 return item
->isSelected();
782 void Basemenu::setItemEnabled(int index
, bool enable
) {
784 BasemenuItem
*item
= find(index
);
787 item
->setEnabled(enable
);
788 if (visible
) drawItem(index
, (index
== which_sub
), True
);
792 bool Basemenu::isItemEnabled(int index
) {
794 BasemenuItem
*item
= find(index
);
795 if (! item
) return False
;
797 return item
->isEnabled();
801 void Basemenu::buttonPressEvent(XButtonEvent
*be
) {
802 if (be
->window
== menu
.frame
) {
803 int sbl
= (be
->x
/ menu
.item_w
), i
= (be
->y
/ menu
.item_h
);
804 int w
= (sbl
* menu
.persub
) + i
;
806 BasemenuItem
*item
= find(w
);
815 drawItem(w
, (item
->isEnabled()), True
);
818 menu
.x_move
= be
->x_root
- menu
.x
;
819 menu
.y_move
= be
->y_root
- menu
.y
;
824 void Basemenu::buttonReleaseEvent(XButtonEvent
*re
) {
825 if (re
->window
== menu
.title
) {
830 drawSubmenu(which_sub
);
833 if (re
->x
>= 0 && re
->x
<= static_cast<signed>(menu
.width
) &&
834 re
->y
>= 0 && re
->y
<= static_cast<signed>(menu
.title_h
))
837 } else if (re
->window
== menu
.frame
&&
838 re
->x
>= 0 && re
->x
< static_cast<signed>(menu
.width
) &&
839 re
->y
>= 0 && re
->y
< static_cast<signed>(menu
.frame_h
)) {
840 if (re
->button
== 3) {
843 int sbl
= (re
->x
/ menu
.item_w
), i
= (re
->y
/ menu
.item_h
),
844 ix
= sbl
* menu
.item_w
, iy
= i
* menu
.item_h
,
845 w
= (sbl
* menu
.persub
) + i
,
846 p
= (which_sbl
* menu
.persub
) + which_press
;
848 if (w
>= 0 && w
< static_cast<signed>(menuitems
.size())) {
849 drawItem(p
, (p
== which_sub
), True
);
851 if (p
== w
&& isItemEnabled(w
)) {
852 if (re
->x
> ix
&& re
->x
< static_cast<signed>(ix
+ menu
.item_w
) &&
853 re
->y
> iy
&& re
->y
< static_cast<signed>(iy
+ menu
.item_h
)) {
854 itemSelected(re
->button
, w
);
858 drawItem(p
, False
, True
);
865 void Basemenu::motionNotifyEvent(XMotionEvent
*me
) {
866 if (me
->window
== menu
.title
&& (me
->state
& Button1Mask
)) {
869 if (parent
&& (! torn
)) {
870 parent
->drawItem(parent
->which_sub
, False
, True
);
871 parent
->which_sub
= -1;
874 moving
= torn
= True
;
877 drawSubmenu(which_sub
);
879 menu
.x
= me
->x_root
- menu
.x_move
,
880 menu
.y
= me
->y_root
- menu
.y_move
;
882 XMoveWindow(display
, menu
.window
, menu
.x
, menu
.y
);
885 drawSubmenu(which_sub
);
888 } else if ((! (me
->state
& Button1Mask
)) && me
->window
== menu
.frame
&&
889 me
->x
>= 0 && me
->x
< static_cast<signed>(menu
.width
) &&
890 me
->y
>= 0 && me
->y
< static_cast<signed>(menu
.frame_h
)) {
891 int sbl
= (me
->x
/ menu
.item_w
), i
= (me
->y
/ menu
.item_h
),
892 w
= (sbl
* menu
.persub
) + i
;
894 if ((i
!= which_press
|| sbl
!= which_sbl
) &&
895 (w
>= 0 && w
< static_cast<signed>(menuitems
.size()))) {
896 if (which_press
!= -1 && which_sbl
!= -1) {
897 int p
= (which_sbl
* menu
.persub
) + which_press
;
898 BasemenuItem
*item
= find(p
);
900 drawItem(p
, False
, True
);
902 if (item
->submenu()->isVisible() &&
903 (! item
->submenu()->isTorn())) {
904 item
->submenu()->internal_hide();
912 BasemenuItem
*itmp
= find(w
);
917 drawItem(w
, (itmp
->isEnabled()), True
);
923 void Basemenu::exposeEvent(XExposeEvent
*ee
) {
924 if (ee
->window
== menu
.title
) {
926 } else if (ee
->window
== menu
.frame
) {
927 // this is a compilicated algorithm... lets do it step by step...
928 // first... we see in which sub level the expose starts... and how many
929 // items down in that sublevel
931 int sbl
= (ee
->x
/ menu
.item_w
), id
= (ee
->y
/ menu
.item_h
),
932 // next... figure out how many sublevels over the redraw spans
933 sbl_d
= ((ee
->x
+ ee
->width
) / menu
.item_w
),
934 // then we see how many items down to redraw
935 id_d
= ((ee
->y
+ ee
->height
) / menu
.item_h
);
937 if (id_d
> menu
.persub
) id_d
= menu
.persub
;
939 // draw the sublevels and the number of items the exposure spans
940 MenuItems::iterator it
,
941 end
= menuitems
.end();
943 for (i
= sbl
; i
<= sbl_d
; i
++) {
944 // set the iterator to the first item in the sublevel needing redrawing
945 it
= menuitems
.begin() + (id
+ (i
* menu
.persub
));
946 for (ii
= id
; ii
<= id_d
&& it
!= end
; ++it
, ii
++) {
947 int index
= ii
+ (i
* menu
.persub
);
949 drawItem(index
, (which_sub
== index
), False
,
950 ee
->x
, ee
->y
, ee
->width
, ee
->height
);
957 void Basemenu::enterNotifyEvent(XCrossingEvent
*ce
) {
958 if (ce
->window
== menu
.frame
) {
959 menu
.x_shift
= menu
.x
, menu
.y_shift
= menu
.y
;
960 if (menu
.x
+ menu
.width
> screen
->getWidth()) {
961 menu
.x_shift
= screen
->getWidth() - menu
.width
-
962 screen
->getBorderWidth();
964 } else if (menu
.x
< 0) {
965 menu
.x_shift
= -screen
->getBorderWidth();
969 if (menu
.y
+ menu
.height
> screen
->getHeight()) {
970 menu
.y_shift
= screen
->getHeight() - menu
.height
-
971 screen
->getBorderWidth();
973 } else if (menu
.y
+ static_cast<signed>(menu
.title_h
) < 0) {
974 menu
.y_shift
= -screen
->getBorderWidth();
979 XMoveWindow(display
, menu
.window
, menu
.x_shift
, menu
.y_shift
);
981 if (which_sub
!= -1) {
982 BasemenuItem
*tmp
= find(which_sub
);
983 if (tmp
->submenu()->isVisible()) {
984 int sbl
= (ce
->x
/ menu
.item_w
), i
= (ce
->y
/ menu
.item_h
),
985 w
= (sbl
* menu
.persub
) + i
;
987 if (w
!= which_sub
&& (! tmp
->submenu()->isTorn())) {
988 tmp
->submenu()->internal_hide();
990 drawItem(which_sub
, False
, True
);
999 void Basemenu::leaveNotifyEvent(XCrossingEvent
*ce
) {
1000 if (ce
->window
== menu
.frame
) {
1001 if (which_press
!= -1 && which_sbl
!= -1 && menuitems
.size() > 0) {
1002 int p
= (which_sbl
* menu
.persub
) + which_press
;
1004 drawItem(p
, (p
== which_sub
), True
);
1006 which_sbl
= which_press
= -1;
1010 XMoveWindow(display
, menu
.window
, menu
.x
, menu
.y
);
1013 if (which_sub
!= -1) drawSubmenu(which_sub
);
1019 void Basemenu::reconfigure(void) {
1020 XSetWindowBackground(display
, menu
.window
,
1021 screen
->getBorderColor()->pixel());
1022 XSetWindowBorder(display
, menu
.window
,
1023 screen
->getBorderColor()->pixel());
1024 XSetWindowBorderWidth(display
, menu
.window
, screen
->getBorderWidth());
1026 menu
.bevel_w
= screen
->getBevelWidth();
1031 void Basemenu::changeItemLabel(unsigned int index
, const string
& label
) {
1032 BasemenuItem
*item
= find(index
);
1034 item
->newLabel(label
);