1 // Basemenu.cc for Openbox
2 // Copyright (c) 2001 Sean 'Shaleh' Perry <shaleh@debian.org>
3 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
5 // Permission is hereby granted, free of charge, to any person obtaining a
6 // copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the
10 // Software is furnished to do so, subject to the following conditions:
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 // DEALINGS IN THE SOFTWARE.
23 // stupid macros needed to access some functions in version 2 of the GNU C
30 # include "../config.h"
31 #endif // HAVE_CONFIG_H
35 #endif // HAVE_STDIO_H
39 #endif // HAVE_STDLIB_H
43 #endif // HAVE_STRING_H
53 static Basemenu
*shown
= (Basemenu
*) 0;
55 Basemenu::Basemenu(BScreen
&scrn
) : openbox(scrn
.getOpenbox()), screen(scrn
) {
56 image_ctrl
= screen
.getImageControl();
57 display
= openbox
.getXDisplay();
58 parent
= (Basemenu
*) 0;
59 alignment
= AlignDontCare
;
85 menu
.sel_pixmap
= None
;
87 menu
.bevel_w
= screen
.getBevelWidth();
89 if (i18n
->multibyte())
90 menu
.width
= menu
.title_h
= menu
.item_w
= menu
.frame_h
=
91 screen
.getMenuStyle()->t_fontset_extents
->max_ink_extent
.height
+
94 menu
.width
= menu
.title_h
= menu
.item_w
= menu
.frame_h
=
95 screen
.getMenuStyle()->t_font
->ascent
+
96 screen
.getMenuStyle()->t_font
->descent
+ (menu
.bevel_w
* 2);
104 MenuStyle
*style
= screen
.getMenuStyle();
105 if (i18n
->multibyte()) {
106 menu
.item_h
= style
->f_fontset_extents
->max_ink_extent
.height
+
109 menu
.item_h
= style
->f_font
->ascent
+ style
->f_font
->descent
+
113 menu
.height
= menu
.title_h
+ screen
.getBorderWidth() + menu
.frame_h
;
115 unsigned long attrib_mask
= CWBackPixmap
| CWBackPixel
| CWBorderPixel
|
116 CWColormap
| CWOverrideRedirect
| CWEventMask
;
117 XSetWindowAttributes attrib
;
118 attrib
.background_pixmap
= None
;
119 attrib
.background_pixel
= attrib
.border_pixel
=
120 screen
.getBorderColor()->getPixel();
121 attrib
.colormap
= screen
.getColormap();
122 attrib
.override_redirect
= True
;
123 attrib
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
124 ButtonMotionMask
| ExposureMask
;
127 XCreateWindow(display
, screen
.getRootWindow(), menu
.x
, menu
.y
, menu
.width
,
128 menu
.height
, screen
.getBorderWidth(), screen
.getDepth(),
129 InputOutput
, screen
.getVisual(), attrib_mask
, &attrib
);
130 openbox
.saveMenuSearch(menu
.window
, this);
132 attrib_mask
= CWBackPixmap
| CWBackPixel
| CWBorderPixel
| CWEventMask
;
133 attrib
.background_pixel
= screen
.getBorderColor()->getPixel();
134 attrib
.event_mask
|= EnterWindowMask
| LeaveWindowMask
;
137 XCreateWindow(display
, menu
.window
, 0, 0, menu
.width
, menu
.height
, 0,
138 screen
.getDepth(), InputOutput
, screen
.getVisual(),
139 attrib_mask
, &attrib
);
140 openbox
.saveMenuSearch(menu
.title
, this);
142 attrib
.event_mask
|= PointerMotionMask
;
143 menu
.frame
= XCreateWindow(display
, menu
.window
, 0,
144 menu
.title_h
+ screen
.getBorderWidth(),
145 menu
.width
, menu
.frame_h
, 0,
146 screen
.getDepth(), InputOutput
,
147 screen
.getVisual(), attrib_mask
, &attrib
);
148 openbox
.saveMenuSearch(menu
.frame
, this);
150 // even though this is the end of the constructor the menu is still not
151 // completely created. items must be inserted and it must be update()'d
155 Basemenu::~Basemenu(void) {
156 XUnmapWindow(display
, menu
.window
);
158 if (shown
&& shown
->getWindowID() == getWindowID())
159 shown
= (Basemenu
*) 0;
161 while (!menuitems
.empty()) {
163 menuitems
.erase(menuitems
.begin());
167 delete [] menu
.label
;
169 if (menu
.title_pixmap
)
170 image_ctrl
->removeImage(menu
.title_pixmap
);
172 if (menu
.frame_pixmap
)
173 image_ctrl
->removeImage(menu
.frame_pixmap
);
175 if (menu
.hilite_pixmap
)
176 image_ctrl
->removeImage(menu
.hilite_pixmap
);
179 image_ctrl
->removeImage(menu
.sel_pixmap
);
181 openbox
.removeMenuSearch(menu
.title
);
182 XDestroyWindow(display
, menu
.title
);
184 openbox
.removeMenuSearch(menu
.frame
);
185 XDestroyWindow(display
, menu
.frame
);
187 openbox
.removeMenuSearch(menu
.window
);
188 XDestroyWindow(display
, menu
.window
);
192 int Basemenu::insert(const char *l
, int function
, const char *e
, int pos
) {
193 char *label
= 0, *exec
= 0;
195 if (l
) label
= bstrdup(l
);
196 if (e
) exec
= bstrdup(e
);
198 BasemenuItem
*item
= new BasemenuItem(label
, function
, exec
);
200 menuitems
.push_back(item
);
202 menuitems
.insert(menuitems
.begin() + pos
, item
);
204 return menuitems
.size();
208 int Basemenu::insert(const char *l
, Basemenu
*submenu
, int pos
) {
211 if (l
) label
= bstrdup(l
);
213 BasemenuItem
*item
= new BasemenuItem(label
, submenu
);
215 menuitems
.push_back(item
);
217 menuitems
.insert(menuitems
.begin() + pos
, item
);
219 submenu
->parent
= this;
221 return menuitems
.size();
225 int Basemenu::insert(const char **ulabel
, int pos
, int function
) {
226 BasemenuItem
*item
= new BasemenuItem(ulabel
, function
);
228 menuitems
.push_back(item
);
230 menuitems
.insert(menuitems
.begin() + pos
, item
);
232 return menuitems
.size();
236 int Basemenu::remove(int index
) {
237 if (index
< 0 || index
> menuitems
.size()) return -1;
239 BasemenuItem
*item
= menuitems
[index
];
240 menuitems
.erase(menuitems
.begin() + index
);
243 if ((!internal_menu
) && (item
->submenu())) {
244 Basemenu
*tmp
= (Basemenu
*) item
->submenu();
246 if (! tmp
->internal_menu
) {
249 tmp
->internal_hide();
254 delete [] item
->label();
257 delete [] item
->exec();
262 if (which_sub
== index
)
264 else if (which_sub
> index
)
267 return menuitems
.size();
271 void Basemenu::update(void) {
272 MenuStyle
*style
= screen
.getMenuStyle();
273 if (i18n
->multibyte()) {
274 menu
.item_h
= style
->f_fontset_extents
->max_ink_extent
.height
+
276 menu
.title_h
= style
->t_fontset_extents
->max_ink_extent
.height
+
279 menu
.item_h
= style
->f_font
->ascent
+ style
->f_font
->descent
+
281 menu
.title_h
= style
->t_font
->ascent
+ style
->t_font
->descent
+
286 const char *s
= (menu
.label
) ? menu
.label
:
287 i18n
->getMessage(BasemenuSet
, BasemenuOpenboxMenu
,
292 if (i18n
->multibyte()) {
293 XRectangle ink
, logical
;
294 XmbTextExtents(screen
.getMenuStyle()->t_fontset
, s
, l
, &ink
, &logical
);
295 menu
.item_w
= logical
.width
;
297 menu
.item_w
= XTextWidth(screen
.getMenuStyle()->t_font
, s
, l
);
300 menu
.item_w
+= (menu
.bevel_w
* 2);
306 menuitemList::const_iterator it
= menuitems
.begin();
307 for (; it
!= menuitems
.end(); it
++) {
308 const char *s
= (((*it
)->u
&& *(*it
)->u
) ? *(*it
)->u
:
309 (((*it
)->l
) ? (*it
)->l
: (const char *) 0));
312 if (i18n
->multibyte()) {
313 XRectangle ink
, logical
;
314 XmbTextExtents(screen
.getMenuStyle()->f_fontset
, s
, l
, &ink
, &logical
);
317 ii
= XTextWidth(screen
.getMenuStyle()->f_font
, s
, l
);
319 ii
+= (menu
.bevel_w
* 2) + (menu
.item_h
* 2);
321 menu
.item_w
= ((menu
.item_w
< (unsigned int) ii
) ? ii
: menu
.item_w
);
324 if (menuitems
.size()) {
327 while (((menu
.item_h
* (menuitems
.size() + 1) / menu
.sublevels
)
328 + menu
.title_h
+ screen
.getBorderWidth()) >
332 if (menu
.sublevels
< menu
.minsub
) menu
.sublevels
= menu
.minsub
;
334 menu
.persub
= menuitems
.size() / menu
.sublevels
;
335 if (menuitems
.size() % menu
.sublevels
) menu
.persub
++;
341 menu
.width
= (menu
.sublevels
* (menu
.item_w
));
342 if (! menu
.width
) menu
.width
= menu
.item_w
;
344 menu
.frame_h
= (menu
.item_h
* menu
.persub
);
345 menu
.height
= ((title_vis
) ? menu
.title_h
+ screen
.getBorderWidth() : 0) +
347 if (! menu
.frame_h
) menu
.frame_h
= 1;
348 if (menu
.height
< 1) menu
.height
= 1;
353 tmp
= menu
.title_pixmap
;
354 texture
= &(screen
.getMenuStyle()->title
);
355 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
356 menu
.title_pixmap
= None
;
357 XSetWindowBackground(display
, menu
.title
,
358 texture
->getColor()->getPixel());
361 image_ctrl
->renderImage(menu
.width
, menu
.title_h
, texture
);
362 XSetWindowBackgroundPixmap(display
, menu
.title
, menu
.title_pixmap
);
364 if (tmp
) image_ctrl
->removeImage(tmp
);
365 XClearWindow(display
, menu
.title
);
368 tmp
= menu
.frame_pixmap
;
369 texture
= &(screen
.getMenuStyle()->frame
);
370 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
371 menu
.frame_pixmap
= None
;
372 XSetWindowBackground(display
, menu
.frame
,
373 texture
->getColor()->getPixel());
376 image_ctrl
->renderImage(menu
.width
, menu
.frame_h
, texture
);
377 XSetWindowBackgroundPixmap(display
, menu
.frame
, menu
.frame_pixmap
);
379 if (tmp
) image_ctrl
->removeImage(tmp
);
381 tmp
= menu
.hilite_pixmap
;
382 texture
= &(screen
.getMenuStyle()->hilite
);
383 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
384 menu
.hilite_pixmap
= None
;
387 image_ctrl
->renderImage(menu
.item_w
, menu
.item_h
, texture
);
389 if (tmp
) image_ctrl
->removeImage(tmp
);
391 tmp
= menu
.sel_pixmap
;
392 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
393 menu
.sel_pixmap
= None
;
395 int hw
= menu
.item_h
/ 2;
397 image_ctrl
->renderImage(hw
, hw
, texture
);
399 if (tmp
) image_ctrl
->removeImage(tmp
);
401 XResizeWindow(display
, menu
.window
, menu
.width
, menu
.height
);
404 XResizeWindow(display
, menu
.title
, menu
.width
, menu
.title_h
);
406 XMoveResizeWindow(display
, menu
.frame
, 0,
407 ((title_vis
) ? menu
.title_h
+
408 screen
.getBorderWidth() : 0), menu
.width
,
411 XClearWindow(display
, menu
.window
);
412 XClearWindow(display
, menu
.title
);
413 XClearWindow(display
, menu
.frame
);
415 if (title_vis
&& visible
) redrawTitle();
417 for (int i
= 0; visible
&& i
< menuitems
.size(); i
++) {
418 if (i
== which_sub
) {
419 drawItem(i
, True
, 0);
422 drawItem(i
, False
, 0);
426 if (parent
&& visible
)
427 parent
->drawSubmenu(parent
->which_sub
);
429 XMapSubwindows(display
, menu
.window
);
433 void Basemenu::show(void) {
434 XMapSubwindows(display
, menu
.window
);
435 XMapWindow(display
, menu
.window
);
439 if (shown
&& (! shown
->torn
))
447 void Basemenu::hide(void) {
448 if ((! torn
) && hide_tree
&& parent
&& parent
->isVisible()) {
449 Basemenu
*p
= parent
;
451 while (p
->isVisible() && (! p
->torn
) && p
->parent
) p
= p
->parent
;
459 void Basemenu::internal_hide(void) {
460 if (which_sub
!= -1) {
461 BasemenuItem
*tmp
= menuitems
[which_sub
];
462 tmp
->submenu()->internal_hide();
465 if (parent
&& (! torn
)) {
466 parent
->drawItem(parent
->which_sub
, False
, True
);
468 parent
->which_sub
= -1;
469 } else if (shown
&& shown
->menu
.window
== menu
.window
) {
470 shown
= (Basemenu
*) 0;
473 torn
= visible
= False
;
474 which_sub
= which_press
= which_sub
= -1;
476 XUnmapWindow(display
, menu
.window
);
480 void Basemenu::move(int x
, int y
) {
483 XMoveWindow(display
, menu
.window
, x
, y
);
485 drawSubmenu(which_sub
);
489 void Basemenu::redrawTitle(void) {
490 char *text
= (char *) ((menu
.label
) ? menu
.label
:
491 i18n
->getMessage(BasemenuSet
, BasemenuOpenboxMenu
,
493 int dx
= menu
.bevel_w
, len
= strlen(text
);
496 if (i18n
->multibyte()) {
497 XRectangle ink
, logical
;
498 XmbTextExtents(screen
.getMenuStyle()->t_fontset
, text
, len
, &ink
, &logical
);
501 l
= XTextWidth(screen
.getMenuStyle()->t_font
, text
, len
);
504 l
+= (menu
.bevel_w
* 2);
506 switch (screen
.getMenuStyle()->t_justify
) {
507 case BScreen::RightJustify
:
508 dx
+= menu
.width
- l
;
511 case BScreen::CenterJustify
:
512 dx
+= (menu
.width
- l
) / 2;
516 MenuStyle
*style
= screen
.getMenuStyle();
517 if (i18n
->multibyte())
518 XmbDrawString(display
, menu
.title
, style
->t_fontset
, style
->t_text_gc
, dx
,
519 (menu
.bevel_w
- style
->t_fontset_extents
->max_ink_extent
.y
),
522 XDrawString(display
, menu
.title
, style
->t_text_gc
, dx
,
523 (style
->t_font
->ascent
+ menu
.bevel_w
), text
, len
);
527 void Basemenu::drawSubmenu(int index
) {
528 if (which_sub
!= -1 && which_sub
!= index
) {
529 BasemenuItem
*itmp
= menuitems
[which_sub
];
531 if (! itmp
->submenu()->isTorn())
532 itmp
->submenu()->internal_hide();
535 if (index
>= 0 && index
< menuitems
.size()) {
536 BasemenuItem
*item
= menuitems
[index
];
537 if (item
->submenu() && visible
&& (! item
->submenu()->isTorn()) &&
539 if (item
->submenu()->parent
!= this) item
->submenu()->parent
= this;
540 int sbl
= index
/ menu
.persub
, i
= index
- (sbl
* menu
.persub
),
542 ((menu
.item_w
* (sbl
+ 1)) + screen
.getBorderWidth()), y
;
544 if (alignment
== AlignTop
)
545 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
546 ((title_vis
) ? menu
.title_h
+ screen
.getBorderWidth() : 0) -
547 ((item
->submenu()->title_vis
) ?
548 item
->submenu()->menu
.title_h
+ screen
.getBorderWidth() : 0));
550 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
552 ((title_vis
) ? menu
.title_h
+ screen
.getBorderWidth() : 0) -
553 ((item
->submenu()->title_vis
) ?
554 item
->submenu()->menu
.title_h
+ screen
.getBorderWidth() : 0));
556 if (alignment
== AlignBottom
&&
557 (y
+ item
->submenu()->menu
.height
) > ((shifted
) ? menu
.y_shift
:
558 menu
.y
) + menu
.height
)
559 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
560 menu
.height
- item
->submenu()->menu
.height
);
562 if ((x
+ item
->submenu()->getWidth()) > screen
.size().w()) {
563 x
= ((shifted
) ? menu
.x_shift
: menu
.x
) -
564 item
->submenu()->getWidth() - screen
.getBorderWidth();
569 if ((y
+ item
->submenu()->getHeight()) > screen
.size().h())
570 y
= screen
.size().h() - item
->submenu()->getHeight() -
571 (screen
.getBorderWidth() * 2);
574 item
->submenu()->move(x
, y
);
575 if (! moving
) drawItem(index
, True
);
577 if (! item
->submenu()->isVisible())
578 item
->submenu()->show();
579 item
->submenu()->moving
= moving
;
588 Bool
Basemenu::hasSubmenu(int index
) {
589 if ((index
>= 0) && (index
< menuitems
.size()))
590 if (menuitems
[index
]->submenu())
597 void Basemenu::drawItem(int index
, Bool highlight
, Bool clear
,
598 int x
, int y
, unsigned int w
, unsigned int h
)
600 if (index
< 0 || index
> menuitems
.size()) return;
602 BasemenuItem
*item
= menuitems
[index
];
605 Bool dotext
= True
, dohilite
= True
, dosel
= True
;
606 const char *text
= (item
->ulabel()) ? *item
->ulabel() : item
->label();
607 int sbl
= index
/ menu
.persub
, i
= index
- (sbl
* menu
.persub
);
608 int item_x
= (sbl
* menu
.item_w
), item_y
= (i
* menu
.item_h
);
609 int hilite_x
= item_x
, hilite_y
= item_y
, hoff_x
= 0, hoff_y
= 0;
610 int text_x
= 0, text_y
= 0, len
= strlen(text
), sel_x
= 0, sel_y
= 0;
611 unsigned int hilite_w
= menu
.item_w
, hilite_h
= menu
.item_h
, text_w
= 0,
613 unsigned int half_w
= menu
.item_h
/ 2, quarter_w
= menu
.item_h
/ 4;
616 if (i18n
->multibyte()) {
617 XRectangle ink
, logical
;
618 XmbTextExtents(screen
.getMenuStyle()->f_fontset
,
619 text
, len
, &ink
, &logical
);
620 text_w
= logical
.width
;
621 text_y
= item_y
+ (menu
.bevel_w
/ 2) -
622 screen
.getMenuStyle()->f_fontset_extents
->max_ink_extent
.y
;
624 text_w
= XTextWidth(screen
.getMenuStyle()->f_font
, text
, len
);
626 screen
.getMenuStyle()->f_font
->ascent
+
630 switch(screen
.getMenuStyle()->f_justify
) {
631 case BScreen::LeftJustify
:
632 text_x
= item_x
+ menu
.bevel_w
+ menu
.item_h
+ 1;
635 case BScreen::RightJustify
:
636 text_x
= item_x
+ menu
.item_w
- (menu
.item_h
+ menu
.bevel_w
+ text_w
);
639 case BScreen::CenterJustify
:
640 text_x
= item_x
+ ((menu
.item_w
+ 1 - text_w
) / 2);
644 text_h
= menu
.item_h
- menu
.bevel_w
;
648 ((highlight
|| item
->isSelected()) ? screen
.getMenuStyle()->h_text_gc
:
649 screen
.getMenuStyle()->f_text_gc
),
651 ((highlight
) ? screen
.getMenuStyle()->h_text_gc
:
652 ((item
->isEnabled()) ? screen
.getMenuStyle()->f_text_gc
:
653 screen
.getMenuStyle()->d_text_gc
));
656 if (screen
.getMenuStyle()->bullet_pos
== Right
)
657 sel_x
+= (menu
.item_w
- menu
.item_h
- menu
.bevel_w
);
659 sel_y
= item_y
+ quarter_w
;
662 XClearArea(display
, menu
.frame
, item_x
, item_y
, menu
.item_w
, menu
.item_h
,
664 } else if (! (x
== y
&& y
== -1 && w
== h
&& h
== 0)) {
665 // calculate the which part of the hilite to redraw
666 if (! (max(item_x
, x
) <= (signed) min(item_x
+ menu
.item_w
, x
+ w
) &&
667 max(item_y
, y
) <= (signed) min(item_y
+ menu
.item_h
, y
+ h
))) {
670 hilite_x
= max(item_x
, x
);
671 hilite_y
= max(item_y
, y
);
672 hilite_w
= min(item_x
+ menu
.item_w
, x
+ w
) - hilite_x
;
673 hilite_h
= min(item_y
+ menu
.item_h
, y
+ h
) - hilite_y
;
674 hoff_x
= hilite_x
% menu
.item_w
;
675 hoff_y
= hilite_y
% menu
.item_h
;
678 // check if we need to redraw the text
679 int text_ry
= item_y
+ (menu
.bevel_w
/ 2);
680 if (! (max(text_x
, x
) <= (signed) min(text_x
+ text_w
, x
+ w
) &&
681 max(text_ry
, y
) <= (signed) min(text_ry
+ text_h
, y
+ h
)))
684 // check if we need to redraw the select pixmap/menu bullet
685 if (! (max(sel_x
, x
) <= (signed) min(sel_x
+ half_w
, x
+ w
) &&
686 max(sel_y
, y
) <= (signed) min(sel_y
+ half_w
, y
+ h
)))
690 if (dohilite
&& highlight
&& (menu
.hilite_pixmap
!= ParentRelative
)) {
691 if (menu
.hilite_pixmap
)
692 XCopyArea(display
, menu
.hilite_pixmap
, menu
.frame
,
693 screen
.getMenuStyle()->hilite_gc
, hoff_x
, hoff_y
,
694 hilite_w
, hilite_h
, hilite_x
, hilite_y
);
696 XFillRectangle(display
, menu
.frame
,
697 screen
.getMenuStyle()->hilite_gc
,
698 hilite_x
, hilite_y
, hilite_w
, hilite_h
);
699 } else if (dosel
&& item
->isSelected() &&
700 (menu
.sel_pixmap
!= ParentRelative
)) {
702 XCopyArea(display
, menu
.sel_pixmap
, menu
.frame
,
703 screen
.getMenuStyle()->hilite_gc
, 0, 0,
704 half_w
, half_w
, sel_x
, sel_y
);
706 XFillRectangle(display
, menu
.frame
,
707 screen
.getMenuStyle()->hilite_gc
,
708 sel_x
, sel_y
, half_w
, half_w
);
711 if (dotext
&& text
) {
712 if (i18n
->multibyte())
713 XmbDrawString(display
, menu
.frame
, screen
.getMenuStyle()->f_fontset
,
714 tgc
, text_x
, text_y
, text
, len
);
716 XDrawString(display
, menu
.frame
, tgc
, text_x
, text_y
, text
, len
);
719 if (dosel
&& item
->submenu()) {
720 switch (screen
.getMenuStyle()->bullet
) {
722 XDrawRectangle(display
, menu
.frame
, gc
, sel_x
, sel_y
, half_w
, half_w
);
728 if (screen
.getMenuStyle()->bullet_pos
== Right
) {
729 tri
[0].x
= sel_x
+ quarter_w
- 2;
730 tri
[0].y
= sel_y
+ quarter_w
- 2;
736 tri
[0].x
= sel_x
+ quarter_w
- 2;
737 tri
[0].y
= item_y
+ half_w
;
744 XFillPolygon(display
, menu
.frame
, gc
, tri
, 3, Convex
,
751 dia
[0].x
= sel_x
+ quarter_w
- 3;
752 dia
[0].y
= item_y
+ half_w
;
760 XFillPolygon(display
, menu
.frame
, gc
, dia
, 4, Convex
,
768 void Basemenu::setLabel(const char *l
) {
770 delete [] menu
.label
;
772 if (l
) menu
.label
= bstrdup(l
);
777 void Basemenu::setItemSelected(int index
, Bool sel
) {
778 if (index
< 0 || index
>= menuitems
.size()) return;
780 BasemenuItem
*item
= find(index
);
783 item
->setSelected(sel
);
784 if (visible
) drawItem(index
, (index
== which_sub
), True
);
788 Bool
Basemenu::isItemSelected(int index
) {
789 if (index
< 0 || index
>= menuitems
.size()) return False
;
791 BasemenuItem
*item
= find(index
);
792 if (! item
) return False
;
794 return item
->isSelected();
798 void Basemenu::setItemEnabled(int index
, Bool enable
) {
799 if (index
< 0 || index
>= menuitems
.size()) return;
801 BasemenuItem
*item
= find(index
);
804 item
->setEnabled(enable
);
805 if (visible
) drawItem(index
, (index
== which_sub
), True
);
809 Bool
Basemenu::isItemEnabled(int index
) {
810 if (index
< 0 || index
>= menuitems
.size()) return False
;
812 BasemenuItem
*item
= find(index
);
813 if (! item
) return False
;
815 return item
->isEnabled();
819 void Basemenu::buttonPressEvent(XButtonEvent
*be
) {
820 if (be
->window
== menu
.frame
) {
821 int sbl
= (be
->x
/ menu
.item_w
), i
= (be
->y
/ menu
.item_h
);
822 int w
= (sbl
* menu
.persub
) + i
;
824 if (w
< menuitems
.size() && w
>= 0) {
828 BasemenuItem
*item
= menuitems
[w
];
833 drawItem(w
, (item
->isEnabled()), True
);
836 menu
.x_move
= be
->x_root
- menu
.x
;
837 menu
.y_move
= be
->y_root
- menu
.y
;
842 void Basemenu::buttonReleaseEvent(XButtonEvent
*re
) {
843 if (re
->window
== menu
.title
) {
848 drawSubmenu(which_sub
);
851 if (re
->x
>= 0 && re
->x
<= (signed) menu
.width
&&
852 re
->y
>= 0 && re
->y
<= (signed) menu
.title_h
)
855 } else if (re
->window
== menu
.frame
&&
856 re
->x
>= 0 && re
->x
< (signed) menu
.width
&&
857 re
->y
>= 0 && re
->y
< (signed) menu
.frame_h
) {
858 if (re
->button
== 3) {
861 int sbl
= (re
->x
/ menu
.item_w
), i
= (re
->y
/ menu
.item_h
),
862 ix
= sbl
* menu
.item_w
, iy
= i
* menu
.item_h
,
863 w
= (sbl
* menu
.persub
) + i
,
864 p
= (which_sbl
* menu
.persub
) + which_press
;
866 if (w
< menuitems
.size() && w
>= 0) {
867 drawItem(p
, (p
== which_sub
), True
);
869 if (p
== w
&& isItemEnabled(w
)) {
870 if (re
->x
> ix
&& re
->x
< (signed) (ix
+ menu
.item_w
) &&
871 re
->y
> iy
&& re
->y
< (signed) (iy
+ menu
.item_h
)) {
872 itemSelected(re
->button
, w
);
876 drawItem(p
, False
, True
);
882 void Basemenu::motionNotifyEvent(XMotionEvent
*me
) {
883 if (me
->window
== menu
.title
&& (me
->state
& Button1Mask
)) {
886 if (parent
&& (! torn
)) {
887 parent
->drawItem(parent
->which_sub
, False
, True
);
888 parent
->which_sub
= -1;
891 moving
= torn
= True
;
894 drawSubmenu(which_sub
);
896 menu
.x
= me
->x_root
- menu
.x_move
,
897 menu
.y
= me
->y_root
- menu
.y_move
;
899 XMoveWindow(display
, menu
.window
, menu
.x
, menu
.y
);
902 drawSubmenu(which_sub
);
905 } else if ((! (me
->state
& Button1Mask
)) && me
->window
== menu
.frame
&&
906 me
->x
>= 0 && me
->x
< (signed) menu
.width
&&
907 me
->y
>= 0 && me
->y
< (signed) menu
.frame_h
) {
908 int sbl
= (me
->x
/ menu
.item_w
), i
= (me
->y
/ menu
.item_h
),
909 w
= (sbl
* menu
.persub
) + i
;
911 if ((i
!= which_press
|| sbl
!= which_sbl
) &&
912 (w
< menuitems
.size() && w
>= 0)) {
913 if (which_press
!= -1 && which_sbl
!= -1) {
914 int p
= (which_sbl
* menu
.persub
) + which_press
;
915 BasemenuItem
*item
= menuitems
[p
];
917 drawItem(p
, False
, True
);
919 if (item
->submenu()->isVisible() &&
920 (! item
->submenu()->isTorn())) {
921 item
->submenu()->internal_hide();
929 BasemenuItem
*itmp
= menuitems
[w
];
934 drawItem(w
, (itmp
->isEnabled()), True
);
940 void Basemenu::exposeEvent(XExposeEvent
*ee
) {
941 if (ee
->window
== menu
.title
) {
943 } else if (ee
->window
== menu
.frame
) {
944 // this is a compilicated algorithm... lets do it step by step...
945 // first... we see in which sub level the expose starts... and how many
946 // items down in that sublevel
948 int sbl
= (ee
->x
/ menu
.item_w
), id
= (ee
->y
/ menu
.item_h
),
949 // next... figure out how many sublevels over the redraw spans
950 sbl_d
= ((ee
->x
+ ee
->width
) / menu
.item_w
),
951 // then we see how many items down to redraw
952 id_d
= ((ee
->y
+ ee
->height
) / menu
.item_h
);
954 if (id_d
> menu
.persub
) id_d
= menu
.persub
;
956 // draw the sublevels and the number of items the exposure spans
957 menuitemList::const_iterator it
= menuitems
.begin();
959 for (i
= sbl
; i
<= sbl_d
; i
++) {
960 // set the iterator to the first item in the sublevel needing redrawing
961 it
= menuitems
.begin() + (id
+ (i
* menu
.persub
));
962 for (ii
= id
; ii
<= id_d
&& it
!= menuitems
.end(); it
++, ii
++) {
963 int index
= ii
+ (i
* menu
.persub
);
965 drawItem(index
, (which_sub
== index
), False
,
966 ee
->x
, ee
->y
, ee
->width
, ee
->height
);
973 void Basemenu::enterNotifyEvent(XCrossingEvent
*ce
) {
974 if (ce
->window
== menu
.frame
) {
975 menu
.x_shift
= menu
.x
, menu
.y_shift
= menu
.y
;
976 if (menu
.x
+ menu
.width
> screen
.size().w()) {
977 menu
.x_shift
= screen
.size().w() - menu
.width
-
978 screen
.getBorderWidth();
980 } else if (menu
.x
< 0) {
981 menu
.x_shift
= -screen
.getBorderWidth();
985 if (menu
.y
+ menu
.height
> screen
.size().h()) {
986 menu
.y_shift
= screen
.size().h() - menu
.height
-
987 screen
.getBorderWidth();
989 } else if (menu
.y
+ (signed) menu
.title_h
< 0) {
990 menu
.y_shift
= -screen
.getBorderWidth();
995 XMoveWindow(display
, menu
.window
, menu
.x_shift
, menu
.y_shift
);
997 if (which_sub
!= -1) {
998 BasemenuItem
*tmp
= menuitems
[which_sub
];
999 if (tmp
->submenu()->isVisible()) {
1000 int sbl
= (ce
->x
/ menu
.item_w
), i
= (ce
->y
/ menu
.item_h
),
1001 w
= (sbl
* menu
.persub
) + i
;
1003 if (w
!= which_sub
&& (! tmp
->submenu()->isTorn())) {
1004 tmp
->submenu()->internal_hide();
1006 drawItem(which_sub
, False
, True
);
1015 void Basemenu::leaveNotifyEvent(XCrossingEvent
*ce
) {
1016 if (ce
->window
== menu
.frame
) {
1017 if (which_press
!= -1 && which_sbl
!= -1 && menuitems
.size() > 0) {
1018 int p
= (which_sbl
* menu
.persub
) + which_press
;
1020 drawItem(p
, (p
== which_sub
), True
);
1022 which_sbl
= which_press
= -1;
1026 XMoveWindow(display
, menu
.window
, menu
.x
, menu
.y
);
1029 if (which_sub
!= -1) drawSubmenu(which_sub
);
1035 void Basemenu::reconfigure(void) {
1036 XSetWindowBackground(display
, menu
.window
,
1037 screen
.getBorderColor()->getPixel());
1038 XSetWindowBorder(display
, menu
.window
,
1039 screen
.getBorderColor()->getPixel());
1040 XSetWindowBorderWidth(display
, menu
.window
, screen
.getBorderWidth());
1042 menu
.bevel_w
= screen
.getBevelWidth();