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
40 #endif // STDC_HEADERS
50 static Basemenu
*shown
= (Basemenu
*) 0;
52 Basemenu::Basemenu(BScreen
*scrn
) {
54 openbox
= screen
->getOpenbox();
55 image_ctrl
= screen
->getImageControl();
56 display
= openbox
->getXDisplay();
57 parent
= (Basemenu
*) 0;
58 alignment
= AlignDontCare
;
84 menu
.sel_pixmap
= None
;
86 menu
.bevel_w
= screen
->getBevelWidth();
88 if (i18n
->multibyte())
89 menu
.width
= menu
.title_h
= menu
.item_w
= menu
.frame_h
=
90 screen
->getMenuStyle()->t_fontset_extents
->max_ink_extent
.height
+
93 menu
.width
= menu
.title_h
= menu
.item_w
= menu
.frame_h
=
94 screen
->getMenuStyle()->t_font
->ascent
+
95 screen
->getMenuStyle()->t_font
->descent
+ (menu
.bevel_w
* 2);
103 MenuStyle
*style
= screen
->getMenuStyle();
104 if (i18n
->multibyte()) {
105 menu
.item_h
= style
->f_fontset_extents
->max_ink_extent
.height
+
108 menu
.item_h
= style
->f_font
->ascent
+ style
->f_font
->descent
+
112 menu
.height
= menu
.title_h
+ screen
->getBorderWidth() + menu
.frame_h
;
114 unsigned long attrib_mask
= CWBackPixmap
| CWBackPixel
| CWBorderPixel
|
115 CWColormap
| CWOverrideRedirect
| CWEventMask
;
116 XSetWindowAttributes attrib
;
117 attrib
.background_pixmap
= None
;
118 attrib
.background_pixel
= attrib
.border_pixel
=
119 screen
->getBorderColor()->getPixel();
120 attrib
.colormap
= screen
->getColormap();
121 attrib
.override_redirect
= True
;
122 attrib
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
123 ButtonMotionMask
| ExposureMask
;
126 XCreateWindow(display
, screen
->getRootWindow(), menu
.x
, menu
.y
, menu
.width
,
127 menu
.height
, screen
->getBorderWidth(), screen
->getDepth(),
128 InputOutput
, screen
->getVisual(), attrib_mask
, &attrib
);
129 openbox
->saveMenuSearch(menu
.window
, this);
131 attrib_mask
= CWBackPixmap
| CWBackPixel
| CWBorderPixel
| CWEventMask
;
132 attrib
.background_pixel
= screen
->getBorderColor()->getPixel();
133 attrib
.event_mask
|= EnterWindowMask
| LeaveWindowMask
;
136 XCreateWindow(display
, menu
.window
, 0, 0, menu
.width
, menu
.height
, 0,
137 screen
->getDepth(), InputOutput
, screen
->getVisual(),
138 attrib_mask
, &attrib
);
139 openbox
->saveMenuSearch(menu
.title
, this);
141 attrib
.event_mask
|= PointerMotionMask
;
142 menu
.frame
= XCreateWindow(display
, menu
.window
, 0,
143 menu
.title_h
+ screen
->getBorderWidth(),
144 menu
.width
, menu
.frame_h
, 0,
145 screen
->getDepth(), InputOutput
,
146 screen
->getVisual(), attrib_mask
, &attrib
);
147 openbox
->saveMenuSearch(menu
.frame
, this);
149 menuitems
= new LinkedList
<BasemenuItem
>;
151 // even though this is the end of the constructor the menu is still not
152 // 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 int n
= menuitems
->count();
163 for (int i
= 0; i
< n
; ++i
)
169 delete [] menu
.label
;
171 if (menu
.title_pixmap
)
172 image_ctrl
->removeImage(menu
.title_pixmap
);
174 if (menu
.frame_pixmap
)
175 image_ctrl
->removeImage(menu
.frame_pixmap
);
177 if (menu
.hilite_pixmap
)
178 image_ctrl
->removeImage(menu
.hilite_pixmap
);
181 image_ctrl
->removeImage(menu
.sel_pixmap
);
183 openbox
->removeMenuSearch(menu
.title
);
184 XDestroyWindow(display
, menu
.title
);
186 openbox
->removeMenuSearch(menu
.frame
);
187 XDestroyWindow(display
, menu
.frame
);
189 openbox
->removeMenuSearch(menu
.window
);
190 XDestroyWindow(display
, menu
.window
);
194 int Basemenu::insert(const char *l
, int function
, const char *e
, int pos
) {
195 char *label
= 0, *exec
= 0;
197 if (l
) label
= bstrdup(l
);
198 if (e
) exec
= bstrdup(e
);
200 BasemenuItem
*item
= new BasemenuItem(label
, function
, exec
);
201 menuitems
->insert(item
, pos
);
203 return menuitems
->count();
207 int Basemenu::insert(const char *l
, Basemenu
*submenu
, int pos
) {
210 if (l
) label
= bstrdup(l
);
212 BasemenuItem
*item
= new BasemenuItem(label
, submenu
);
213 menuitems
->insert(item
, pos
);
215 submenu
->parent
= this;
217 return menuitems
->count();
221 int Basemenu::insert(const char **ulabel
, int pos
, int function
) {
222 BasemenuItem
*item
= new BasemenuItem(ulabel
, function
);
223 menuitems
->insert(item
, pos
);
225 return menuitems
->count();
229 int Basemenu::remove(int index
) {
230 if (index
< 0 || index
> menuitems
->count()) return -1;
232 BasemenuItem
*item
= menuitems
->remove(index
);
235 if ((! internal_menu
) && (item
->submenu())) {
236 Basemenu
*tmp
= (Basemenu
*) item
->submenu();
238 if (! tmp
->internal_menu
) {
241 tmp
->internal_hide();
246 delete [] item
->label();
249 delete [] item
->exec();
254 if (which_sub
== index
)
256 else if (which_sub
> index
)
259 return menuitems
->count();
263 void Basemenu::update(void) {
264 MenuStyle
*style
= screen
->getMenuStyle();
265 if (i18n
->multibyte()) {
266 menu
.item_h
= style
->f_fontset_extents
->max_ink_extent
.height
+
268 menu
.title_h
= style
->t_fontset_extents
->max_ink_extent
.height
+
271 menu
.item_h
= style
->f_font
->ascent
+ style
->f_font
->descent
+
273 menu
.title_h
= style
->t_font
->ascent
+ style
->t_font
->descent
+
278 const char *s
= (menu
.label
) ? menu
.label
:
279 i18n
->getMessage(BasemenuSet
, BasemenuOpenboxMenu
,
284 if (i18n
->multibyte()) {
285 XRectangle ink
, logical
;
286 XmbTextExtents(screen
->getMenuStyle()->t_fontset
, s
, l
, &ink
, &logical
);
287 menu
.item_w
= logical
.width
;
289 menu
.item_w
= XTextWidth(screen
->getMenuStyle()->t_font
, s
, l
);
292 menu
.item_w
+= (menu
.bevel_w
* 2);
298 LinkedListIterator
<BasemenuItem
> it(menuitems
);
299 for (BasemenuItem
*tmp
= it
.current(); tmp
; it
++, tmp
= it
.current()) {
300 const char *s
= ((tmp
->u
&& *tmp
->u
) ? *tmp
->u
:
301 ((tmp
->l
) ? tmp
->l
: (const char *) 0));
304 if (i18n
->multibyte()) {
305 XRectangle ink
, logical
;
306 XmbTextExtents(screen
->getMenuStyle()->f_fontset
, s
, l
, &ink
, &logical
);
309 ii
= XTextWidth(screen
->getMenuStyle()->f_font
, s
, l
);
311 ii
+= (menu
.bevel_w
* 2) + (menu
.item_h
* 2);
313 menu
.item_w
= ((menu
.item_w
< (unsigned int) ii
) ? ii
: menu
.item_w
);
316 if (menuitems
->count()) {
319 while (((menu
.item_h
* (menuitems
->count() + 1) / menu
.sublevels
)
320 + menu
.title_h
+ screen
->getBorderWidth()) >
324 if (menu
.sublevels
< menu
.minsub
) menu
.sublevels
= menu
.minsub
;
326 menu
.persub
= menuitems
->count() / menu
.sublevels
;
327 if (menuitems
->count() % menu
.sublevels
) menu
.persub
++;
333 menu
.width
= (menu
.sublevels
* (menu
.item_w
));
334 if (! menu
.width
) menu
.width
= menu
.item_w
;
336 menu
.frame_h
= (menu
.item_h
* menu
.persub
);
337 menu
.height
= ((title_vis
) ? menu
.title_h
+ screen
->getBorderWidth() : 0) +
339 if (! menu
.frame_h
) menu
.frame_h
= 1;
340 if (menu
.height
< 1) menu
.height
= 1;
345 tmp
= menu
.title_pixmap
;
346 texture
= &(screen
->getMenuStyle()->title
);
347 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
348 menu
.title_pixmap
= None
;
349 XSetWindowBackground(display
, menu
.title
,
350 texture
->getColor()->getPixel());
353 image_ctrl
->renderImage(menu
.width
, menu
.title_h
, texture
);
354 XSetWindowBackgroundPixmap(display
, menu
.title
, menu
.title_pixmap
);
356 if (tmp
) image_ctrl
->removeImage(tmp
);
357 XClearWindow(display
, menu
.title
);
360 tmp
= menu
.frame_pixmap
;
361 texture
= &(screen
->getMenuStyle()->frame
);
362 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
363 menu
.frame_pixmap
= None
;
364 XSetWindowBackground(display
, menu
.frame
,
365 texture
->getColor()->getPixel());
368 image_ctrl
->renderImage(menu
.width
, menu
.frame_h
, texture
);
369 XSetWindowBackgroundPixmap(display
, menu
.frame
, menu
.frame_pixmap
);
371 if (tmp
) image_ctrl
->removeImage(tmp
);
373 tmp
= menu
.hilite_pixmap
;
374 texture
= &(screen
->getMenuStyle()->hilite
);
375 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
376 menu
.hilite_pixmap
= None
;
379 image_ctrl
->renderImage(menu
.item_w
, menu
.item_h
, texture
);
381 if (tmp
) image_ctrl
->removeImage(tmp
);
383 tmp
= menu
.sel_pixmap
;
384 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
385 menu
.sel_pixmap
= None
;
387 int hw
= menu
.item_h
/ 2;
389 image_ctrl
->renderImage(hw
, hw
, texture
);
391 if (tmp
) image_ctrl
->removeImage(tmp
);
393 XResizeWindow(display
, menu
.window
, menu
.width
, menu
.height
);
396 XResizeWindow(display
, menu
.title
, menu
.width
, menu
.title_h
);
398 XMoveResizeWindow(display
, menu
.frame
, 0,
399 ((title_vis
) ? menu
.title_h
+
400 screen
->getBorderWidth() : 0), menu
.width
,
403 XClearWindow(display
, menu
.window
);
404 XClearWindow(display
, menu
.title
);
405 XClearWindow(display
, menu
.frame
);
407 if (title_vis
&& visible
) redrawTitle();
409 for (int i
= 0; visible
&& i
< menuitems
->count(); i
++) {
410 if (i
== which_sub
) {
411 drawItem(i
, True
, 0);
414 drawItem(i
, False
, 0);
418 if (parent
&& visible
)
419 parent
->drawSubmenu(parent
->which_sub
);
421 XMapSubwindows(display
, menu
.window
);
425 void Basemenu::show(void) {
426 XMapSubwindows(display
, menu
.window
);
427 XMapWindow(display
, menu
.window
);
431 if (shown
&& (! shown
->torn
))
439 void Basemenu::hide(void) {
440 if ((! torn
) && hide_tree
&& parent
&& parent
->isVisible()) {
441 Basemenu
*p
= parent
;
443 while (p
->isVisible() && (! p
->torn
) && p
->parent
) p
= p
->parent
;
451 void Basemenu::internal_hide(void) {
452 if (which_sub
!= -1) {
453 BasemenuItem
*tmp
= menuitems
->find(which_sub
);
454 tmp
->submenu()->internal_hide();
457 if (parent
&& (! torn
)) {
458 parent
->drawItem(parent
->which_sub
, False
, True
);
460 parent
->which_sub
= -1;
461 } else if (shown
&& shown
->menu
.window
== menu
.window
) {
462 shown
= (Basemenu
*) 0;
465 torn
= visible
= False
;
466 which_sub
= which_press
= which_sub
= -1;
468 XUnmapWindow(display
, menu
.window
);
472 void Basemenu::move(int x
, int y
) {
475 XMoveWindow(display
, menu
.window
, x
, y
);
477 drawSubmenu(which_sub
);
481 void Basemenu::redrawTitle(void) {
482 char *text
= (char *) ((menu
.label
) ? menu
.label
:
483 i18n
->getMessage(BasemenuSet
, BasemenuOpenboxMenu
,
485 int dx
= menu
.bevel_w
, len
= strlen(text
);
488 if (i18n
->multibyte()) {
489 XRectangle ink
, logical
;
490 XmbTextExtents(screen
->getMenuStyle()->t_fontset
, text
, len
, &ink
, &logical
);
493 l
= XTextWidth(screen
->getMenuStyle()->t_font
, text
, len
);
496 l
+= (menu
.bevel_w
* 2);
498 switch (screen
->getMenuStyle()->t_justify
) {
499 case BScreen::RightJustify
:
500 dx
+= menu
.width
- l
;
503 case BScreen::CenterJustify
:
504 dx
+= (menu
.width
- l
) / 2;
508 MenuStyle
*style
= screen
->getMenuStyle();
509 if (i18n
->multibyte())
510 XmbDrawString(display
, menu
.title
, style
->t_fontset
, style
->t_text_gc
, dx
,
511 (menu
.bevel_w
- style
->t_fontset_extents
->max_ink_extent
.y
),
514 XDrawString(display
, menu
.title
, style
->t_text_gc
, dx
,
515 (style
->t_font
->ascent
+ menu
.bevel_w
), text
, len
);
519 void Basemenu::drawSubmenu(int index
) {
520 if (which_sub
!= -1 && which_sub
!= index
) {
521 BasemenuItem
*itmp
= menuitems
->find(which_sub
);
523 if (! itmp
->submenu()->isTorn())
524 itmp
->submenu()->internal_hide();
527 if (index
>= 0 && index
< menuitems
->count()) {
528 BasemenuItem
*item
= menuitems
->find(index
);
529 if (item
->submenu() && visible
&& (! item
->submenu()->isTorn()) &&
531 if (item
->submenu()->parent
!= this) item
->submenu()->parent
= this;
532 int sbl
= index
/ menu
.persub
, i
= index
- (sbl
* menu
.persub
),
534 ((menu
.item_w
* (sbl
+ 1)) + screen
->getBorderWidth()), y
;
536 if (alignment
== AlignTop
)
537 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
538 ((title_vis
) ? menu
.title_h
+ screen
->getBorderWidth() : 0) -
539 ((item
->submenu()->title_vis
) ?
540 item
->submenu()->menu
.title_h
+ screen
->getBorderWidth() : 0));
542 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
544 ((title_vis
) ? menu
.title_h
+ screen
->getBorderWidth() : 0) -
545 ((item
->submenu()->title_vis
) ?
546 item
->submenu()->menu
.title_h
+ screen
->getBorderWidth() : 0));
548 if (alignment
== AlignBottom
&&
549 (y
+ item
->submenu()->menu
.height
) > ((shifted
) ? menu
.y_shift
:
550 menu
.y
) + menu
.height
)
551 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
552 menu
.height
- item
->submenu()->menu
.height
);
554 if ((x
+ item
->submenu()->getWidth()) > screen
->getWidth()) {
555 x
= ((shifted
) ? menu
.x_shift
: menu
.x
) -
556 item
->submenu()->getWidth() - screen
->getBorderWidth();
561 if ((y
+ item
->submenu()->getHeight()) > screen
->getHeight())
562 y
= screen
->getHeight() - item
->submenu()->getHeight() -
563 (screen
->getBorderWidth() * 2);
566 item
->submenu()->move(x
, y
);
567 if (! moving
) drawItem(index
, True
);
569 if (! item
->submenu()->isVisible())
570 item
->submenu()->show();
571 item
->submenu()->moving
= moving
;
580 Bool
Basemenu::hasSubmenu(int index
) {
581 if ((index
>= 0) && (index
< menuitems
->count()))
582 if (menuitems
->find(index
)->submenu())
589 void Basemenu::drawItem(int index
, Bool highlight
, Bool clear
,
590 int x
, int y
, unsigned int w
, unsigned int h
)
592 if (index
< 0 || index
> menuitems
->count()) return;
594 BasemenuItem
*item
= menuitems
->find(index
);
597 Bool dotext
= True
, dohilite
= True
, dosel
= True
;
598 const char *text
= (item
->ulabel()) ? *item
->ulabel() : item
->label();
599 int sbl
= index
/ menu
.persub
, i
= index
- (sbl
* menu
.persub
);
600 int item_x
= (sbl
* menu
.item_w
), item_y
= (i
* menu
.item_h
);
601 int hilite_x
= item_x
, hilite_y
= item_y
, hoff_x
= 0, hoff_y
= 0;
602 int text_x
= 0, text_y
= 0, len
= strlen(text
), sel_x
= 0, sel_y
= 0;
603 unsigned int hilite_w
= menu
.item_w
, hilite_h
= menu
.item_h
, text_w
= 0,
605 unsigned int half_w
= menu
.item_h
/ 2, quarter_w
= menu
.item_h
/ 4;
608 if (i18n
->multibyte()) {
609 XRectangle ink
, logical
;
610 XmbTextExtents(screen
->getMenuStyle()->f_fontset
,
611 text
, len
, &ink
, &logical
);
612 text_w
= logical
.width
;
613 text_y
= item_y
+ (menu
.bevel_w
/ 2) -
614 screen
->getMenuStyle()->f_fontset_extents
->max_ink_extent
.y
;
616 text_w
= XTextWidth(screen
->getMenuStyle()->f_font
, text
, len
);
618 screen
->getMenuStyle()->f_font
->ascent
+
622 switch(screen
->getMenuStyle()->f_justify
) {
623 case BScreen::LeftJustify
:
624 text_x
= item_x
+ menu
.bevel_w
+ menu
.item_h
+ 1;
627 case BScreen::RightJustify
:
628 text_x
= item_x
+ menu
.item_w
- (menu
.item_h
+ menu
.bevel_w
+ text_w
);
631 case BScreen::CenterJustify
:
632 text_x
= item_x
+ ((menu
.item_w
+ 1 - text_w
) / 2);
636 text_h
= menu
.item_h
- menu
.bevel_w
;
640 ((highlight
|| item
->isSelected()) ? screen
->getMenuStyle()->h_text_gc
:
641 screen
->getMenuStyle()->f_text_gc
),
643 ((highlight
) ? screen
->getMenuStyle()->h_text_gc
:
644 ((item
->isEnabled()) ? screen
->getMenuStyle()->f_text_gc
:
645 screen
->getMenuStyle()->d_text_gc
));
648 if (screen
->getMenuStyle()->bullet_pos
== Right
)
649 sel_x
+= (menu
.item_w
- menu
.item_h
- menu
.bevel_w
);
651 sel_y
= item_y
+ quarter_w
;
654 XClearArea(display
, menu
.frame
, item_x
, item_y
, menu
.item_w
, menu
.item_h
,
656 } else if (! (x
== y
&& y
== -1 && w
== h
&& h
== 0)) {
657 // calculate the which part of the hilite to redraw
658 if (! (max(item_x
, x
) <= (signed) min(item_x
+ menu
.item_w
, x
+ w
) &&
659 max(item_y
, y
) <= (signed) min(item_y
+ menu
.item_h
, y
+ h
))) {
662 hilite_x
= max(item_x
, x
);
663 hilite_y
= max(item_y
, y
);
664 hilite_w
= min(item_x
+ menu
.item_w
, x
+ w
) - hilite_x
;
665 hilite_h
= min(item_y
+ menu
.item_h
, y
+ h
) - hilite_y
;
666 hoff_x
= hilite_x
% menu
.item_w
;
667 hoff_y
= hilite_y
% menu
.item_h
;
670 // check if we need to redraw the text
671 int text_ry
= item_y
+ (menu
.bevel_w
/ 2);
672 if (! (max(text_x
, x
) <= (signed) min(text_x
+ text_w
, x
+ w
) &&
673 max(text_ry
, y
) <= (signed) min(text_ry
+ text_h
, y
+ h
)))
676 // check if we need to redraw the select pixmap/menu bullet
677 if (! (max(sel_x
, x
) <= (signed) min(sel_x
+ half_w
, x
+ w
) &&
678 max(sel_y
, y
) <= (signed) min(sel_y
+ half_w
, y
+ h
)))
682 if (dohilite
&& highlight
&& (menu
.hilite_pixmap
!= ParentRelative
)) {
683 if (menu
.hilite_pixmap
)
684 XCopyArea(display
, menu
.hilite_pixmap
, menu
.frame
,
685 screen
->getMenuStyle()->hilite_gc
, hoff_x
, hoff_y
,
686 hilite_w
, hilite_h
, hilite_x
, hilite_y
);
688 XFillRectangle(display
, menu
.frame
,
689 screen
->getMenuStyle()->hilite_gc
,
690 hilite_x
, hilite_y
, hilite_w
, hilite_h
);
691 } else if (dosel
&& item
->isSelected() &&
692 (menu
.sel_pixmap
!= ParentRelative
)) {
694 XCopyArea(display
, menu
.sel_pixmap
, menu
.frame
,
695 screen
->getMenuStyle()->hilite_gc
, 0, 0,
696 half_w
, half_w
, sel_x
, sel_y
);
698 XFillRectangle(display
, menu
.frame
,
699 screen
->getMenuStyle()->hilite_gc
,
700 sel_x
, sel_y
, half_w
, half_w
);
703 if (dotext
&& text
) {
704 if (i18n
->multibyte())
705 XmbDrawString(display
, menu
.frame
, screen
->getMenuStyle()->f_fontset
,
706 tgc
, text_x
, text_y
, text
, len
);
708 XDrawString(display
, menu
.frame
, tgc
, text_x
, text_y
, text
, len
);
711 if (dosel
&& item
->submenu()) {
712 switch (screen
->getMenuStyle()->bullet
) {
714 XDrawRectangle(display
, menu
.frame
, gc
, sel_x
, sel_y
, half_w
, half_w
);
720 if (screen
->getMenuStyle()->bullet_pos
== Right
) {
721 tri
[0].x
= sel_x
+ quarter_w
- 2;
722 tri
[0].y
= sel_y
+ quarter_w
- 2;
728 tri
[0].x
= sel_x
+ quarter_w
- 2;
729 tri
[0].y
= item_y
+ half_w
;
736 XFillPolygon(display
, menu
.frame
, gc
, tri
, 3, Convex
,
743 dia
[0].x
= sel_x
+ quarter_w
- 3;
744 dia
[0].y
= item_y
+ half_w
;
752 XFillPolygon(display
, menu
.frame
, gc
, dia
, 4, Convex
,
760 void Basemenu::setLabel(const char *l
) {
762 delete [] menu
.label
;
764 if (l
) menu
.label
= bstrdup(l
);
769 void Basemenu::setItemSelected(int index
, Bool sel
) {
770 if (index
< 0 || index
>= menuitems
->count()) return;
772 BasemenuItem
*item
= find(index
);
775 item
->setSelected(sel
);
776 if (visible
) drawItem(index
, (index
== which_sub
), True
);
780 Bool
Basemenu::isItemSelected(int index
) {
781 if (index
< 0 || index
>= menuitems
->count()) return False
;
783 BasemenuItem
*item
= find(index
);
784 if (! item
) return False
;
786 return item
->isSelected();
790 void Basemenu::setItemEnabled(int index
, Bool enable
) {
791 if (index
< 0 || index
>= menuitems
->count()) return;
793 BasemenuItem
*item
= find(index
);
796 item
->setEnabled(enable
);
797 if (visible
) drawItem(index
, (index
== which_sub
), True
);
801 Bool
Basemenu::isItemEnabled(int index
) {
802 if (index
< 0 || index
>= menuitems
->count()) return False
;
804 BasemenuItem
*item
= find(index
);
805 if (! item
) return False
;
807 return item
->isEnabled();
811 void Basemenu::buttonPressEvent(XButtonEvent
*be
) {
812 if (be
->window
== menu
.frame
) {
813 int sbl
= (be
->x
/ menu
.item_w
), i
= (be
->y
/ menu
.item_h
);
814 int w
= (sbl
* menu
.persub
) + i
;
816 if (w
< menuitems
->count() && w
>= 0) {
820 BasemenuItem
*item
= menuitems
->find(w
);
825 drawItem(w
, (item
->isEnabled()), True
);
828 menu
.x_move
= be
->x_root
- menu
.x
;
829 menu
.y_move
= be
->y_root
- menu
.y
;
834 void Basemenu::buttonReleaseEvent(XButtonEvent
*re
) {
835 if (re
->window
== menu
.title
) {
840 drawSubmenu(which_sub
);
843 if (re
->x
>= 0 && re
->x
<= (signed) menu
.width
&&
844 re
->y
>= 0 && re
->y
<= (signed) menu
.title_h
)
847 } else if (re
->window
== menu
.frame
&&
848 re
->x
>= 0 && re
->x
< (signed) menu
.width
&&
849 re
->y
>= 0 && re
->y
< (signed) menu
.frame_h
) {
850 if (re
->button
== 3) {
853 int sbl
= (re
->x
/ menu
.item_w
), i
= (re
->y
/ menu
.item_h
),
854 ix
= sbl
* menu
.item_w
, iy
= i
* menu
.item_h
,
855 w
= (sbl
* menu
.persub
) + i
,
856 p
= (which_sbl
* menu
.persub
) + which_press
;
858 if (w
< menuitems
->count() && w
>= 0) {
859 drawItem(p
, (p
== which_sub
), True
);
861 if (p
== w
&& isItemEnabled(w
)) {
862 if (re
->x
> ix
&& re
->x
< (signed) (ix
+ menu
.item_w
) &&
863 re
->y
> iy
&& re
->y
< (signed) (iy
+ menu
.item_h
)) {
864 itemSelected(re
->button
, w
);
868 drawItem(p
, False
, True
);
874 void Basemenu::motionNotifyEvent(XMotionEvent
*me
) {
875 if (me
->window
== menu
.title
&& (me
->state
& Button1Mask
)) {
878 if (parent
&& (! torn
)) {
879 parent
->drawItem(parent
->which_sub
, False
, True
);
880 parent
->which_sub
= -1;
883 moving
= torn
= True
;
886 drawSubmenu(which_sub
);
888 menu
.x
= me
->x_root
- menu
.x_move
,
889 menu
.y
= me
->y_root
- menu
.y_move
;
891 XMoveWindow(display
, menu
.window
, menu
.x
, menu
.y
);
894 drawSubmenu(which_sub
);
897 } else if ((! (me
->state
& Button1Mask
)) && me
->window
== menu
.frame
&&
898 me
->x
>= 0 && me
->x
< (signed) menu
.width
&&
899 me
->y
>= 0 && me
->y
< (signed) menu
.frame_h
) {
900 int sbl
= (me
->x
/ menu
.item_w
), i
= (me
->y
/ menu
.item_h
),
901 w
= (sbl
* menu
.persub
) + i
;
903 if ((i
!= which_press
|| sbl
!= which_sbl
) &&
904 (w
< menuitems
->count() && w
>= 0)) {
905 if (which_press
!= -1 && which_sbl
!= -1) {
906 int p
= (which_sbl
* menu
.persub
) + which_press
;
907 BasemenuItem
*item
= menuitems
->find(p
);
909 drawItem(p
, False
, True
);
911 if (item
->submenu()->isVisible() &&
912 (! item
->submenu()->isTorn())) {
913 item
->submenu()->internal_hide();
921 BasemenuItem
*itmp
= menuitems
->find(w
);
926 drawItem(w
, (itmp
->isEnabled()), True
);
932 void Basemenu::exposeEvent(XExposeEvent
*ee
) {
933 if (ee
->window
== menu
.title
) {
935 } else if (ee
->window
== menu
.frame
) {
936 // this is a compilicated algorithm... lets do it step by step...
937 // first... we see in which sub level the expose starts... and how many
938 // items down in that sublevel
940 int sbl
= (ee
->x
/ menu
.item_w
), id
= (ee
->y
/ menu
.item_h
),
941 // next... figure out how many sublevels over the redraw spans
942 sbl_d
= ((ee
->x
+ ee
->width
) / menu
.item_w
),
943 // then we see how many items down to redraw
944 id_d
= ((ee
->y
+ ee
->height
) / menu
.item_h
);
946 if (id_d
> menu
.persub
) id_d
= menu
.persub
;
948 // draw the sublevels and the number of items the exposure spans
949 LinkedListIterator
<BasemenuItem
> it(menuitems
);
951 for (i
= sbl
; i
<= sbl_d
; i
++) {
952 // set the iterator to the first item in the sublevel needing redrawing
953 it
.set(id
+ (i
* menu
.persub
));
954 for (ii
= id
; ii
<= id_d
&& it
.current(); it
++, ii
++) {
955 int index
= ii
+ (i
* menu
.persub
);
957 drawItem(index
, (which_sub
== index
), False
,
958 ee
->x
, ee
->y
, ee
->width
, ee
->height
);
965 void Basemenu::enterNotifyEvent(XCrossingEvent
*ce
) {
966 if (ce
->window
== menu
.frame
) {
967 menu
.x_shift
= menu
.x
, menu
.y_shift
= menu
.y
;
968 if (menu
.x
+ menu
.width
> screen
->getWidth()) {
969 menu
.x_shift
= screen
->getWidth() - menu
.width
-
970 screen
->getBorderWidth();
972 } else if (menu
.x
< 0) {
973 menu
.x_shift
= -screen
->getBorderWidth();
977 if (menu
.y
+ menu
.height
> screen
->getHeight()) {
978 menu
.y_shift
= screen
->getHeight() - menu
.height
-
979 screen
->getBorderWidth();
981 } else if (menu
.y
+ (signed) menu
.title_h
< 0) {
982 menu
.y_shift
= -screen
->getBorderWidth();
987 XMoveWindow(display
, menu
.window
, menu
.x_shift
, menu
.y_shift
);
989 if (which_sub
!= -1) {
990 BasemenuItem
*tmp
= menuitems
->find(which_sub
);
991 if (tmp
->submenu()->isVisible()) {
992 int sbl
= (ce
->x
/ menu
.item_w
), i
= (ce
->y
/ menu
.item_h
),
993 w
= (sbl
* menu
.persub
) + i
;
995 if (w
!= which_sub
&& (! tmp
->submenu()->isTorn())) {
996 tmp
->submenu()->internal_hide();
998 drawItem(which_sub
, False
, True
);
1007 void Basemenu::leaveNotifyEvent(XCrossingEvent
*ce
) {
1008 if (ce
->window
== menu
.frame
) {
1009 if (which_press
!= -1 && which_sbl
!= -1 && menuitems
->count() > 0) {
1010 int p
= (which_sbl
* menu
.persub
) + which_press
;
1012 drawItem(p
, (p
== which_sub
), True
);
1014 which_sbl
= which_press
= -1;
1018 XMoveWindow(display
, menu
.window
, menu
.x
, menu
.y
);
1021 if (which_sub
!= -1) drawSubmenu(which_sub
);
1027 void Basemenu::reconfigure(void) {
1028 XSetWindowBackground(display
, menu
.window
,
1029 screen
->getBorderColor()->getPixel());
1030 XSetWindowBorder(display
, menu
.window
,
1031 screen
->getBorderColor()->getPixel());
1032 XSetWindowBorderWidth(display
, menu
.window
, screen
->getBorderWidth());
1034 menu
.bevel_w
= screen
->getBevelWidth();