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
) : screen(scrn
), openbox(*scrn
.getOpenbox()) {
53 image_ctrl
= screen
.getImageControl();
54 display
= openbox
.getXDisplay();
55 parent
= (Basemenu
*) 0;
56 alignment
= AlignDontCare
;
82 menu
.sel_pixmap
= None
;
84 menu
.bevel_w
= screen
.getBevelWidth();
86 if (i18n
->multibyte())
87 menu
.width
= menu
.title_h
= menu
.item_w
= menu
.frame_h
=
88 screen
.getMenuStyle()->t_fontset_extents
->max_ink_extent
.height
+
91 menu
.width
= menu
.title_h
= menu
.item_w
= menu
.frame_h
=
92 screen
.getMenuStyle()->t_font
->ascent
+
93 screen
.getMenuStyle()->t_font
->descent
+ (menu
.bevel_w
* 2);
101 MenuStyle
*style
= screen
.getMenuStyle();
102 if (i18n
->multibyte()) {
103 menu
.item_h
= style
->f_fontset_extents
->max_ink_extent
.height
+
106 menu
.item_h
= style
->f_font
->ascent
+ style
->f_font
->descent
+
110 menu
.height
= menu
.title_h
+ screen
.getBorderWidth() + menu
.frame_h
;
112 unsigned long attrib_mask
= CWBackPixmap
| CWBackPixel
| CWBorderPixel
|
113 CWColormap
| CWOverrideRedirect
| CWEventMask
;
114 XSetWindowAttributes attrib
;
115 attrib
.background_pixmap
= None
;
116 attrib
.background_pixel
= attrib
.border_pixel
=
117 screen
.getBorderColor()->getPixel();
118 attrib
.colormap
= screen
.getColormap();
119 attrib
.override_redirect
= True
;
120 attrib
.event_mask
= ButtonPressMask
| ButtonReleaseMask
|
121 ButtonMotionMask
| ExposureMask
;
124 XCreateWindow(display
, screen
.getRootWindow(), menu
.x
, menu
.y
, menu
.width
,
125 menu
.height
, screen
.getBorderWidth(), screen
.getDepth(),
126 InputOutput
, screen
.getVisual(), attrib_mask
, &attrib
);
127 openbox
.saveMenuSearch(menu
.window
, this);
129 attrib_mask
= CWBackPixmap
| CWBackPixel
| CWBorderPixel
| CWEventMask
;
130 attrib
.background_pixel
= screen
.getBorderColor()->getPixel();
131 attrib
.event_mask
|= EnterWindowMask
| LeaveWindowMask
;
134 XCreateWindow(display
, menu
.window
, 0, 0, menu
.width
, menu
.height
, 0,
135 screen
.getDepth(), InputOutput
, screen
.getVisual(),
136 attrib_mask
, &attrib
);
137 openbox
.saveMenuSearch(menu
.title
, this);
139 attrib
.event_mask
|= PointerMotionMask
;
140 menu
.frame
= XCreateWindow(display
, menu
.window
, 0,
141 menu
.title_h
+ screen
.getBorderWidth(),
142 menu
.width
, menu
.frame_h
, 0,
143 screen
.getDepth(), InputOutput
,
144 screen
.getVisual(), attrib_mask
, &attrib
);
145 openbox
.saveMenuSearch(menu
.frame
, this);
147 menuitems
= new LinkedList
<BasemenuItem
>;
149 // even though this is the end of the constructor the menu is still not
150 // completely created. items must be inserted and it must be update()'d
154 Basemenu::~Basemenu(void) {
155 XUnmapWindow(display
, menu
.window
);
157 if (shown
&& shown
->getWindowID() == getWindowID())
158 shown
= (Basemenu
*) 0;
160 int n
= menuitems
->count();
161 for (int i
= 0; i
< n
; ++i
)
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
);
199 menuitems
->insert(item
, pos
);
201 return menuitems
->count();
205 int Basemenu::insert(const char *l
, Basemenu
*submenu
, int pos
) {
208 if (l
) label
= bstrdup(l
);
210 BasemenuItem
*item
= new BasemenuItem(label
, submenu
);
211 menuitems
->insert(item
, pos
);
213 submenu
->parent
= this;
215 return menuitems
->count();
219 int Basemenu::insert(const char **ulabel
, int pos
, int function
) {
220 BasemenuItem
*item
= new BasemenuItem(ulabel
, function
);
221 menuitems
->insert(item
, pos
);
223 return menuitems
->count();
227 int Basemenu::remove(int index
) {
228 if (index
< 0 || index
> menuitems
->count()) return -1;
230 BasemenuItem
*item
= menuitems
->remove(index
);
233 if ((! internal_menu
) && (item
->submenu())) {
234 Basemenu
*tmp
= (Basemenu
*) item
->submenu();
236 if (! tmp
->internal_menu
) {
239 tmp
->internal_hide();
244 delete [] item
->label();
247 delete [] item
->exec();
252 if (which_sub
== index
)
254 else if (which_sub
> index
)
257 return menuitems
->count();
261 void Basemenu::update(void) {
262 MenuStyle
*style
= screen
.getMenuStyle();
263 if (i18n
->multibyte()) {
264 menu
.item_h
= style
->f_fontset_extents
->max_ink_extent
.height
+
266 menu
.title_h
= style
->t_fontset_extents
->max_ink_extent
.height
+
269 menu
.item_h
= style
->f_font
->ascent
+ style
->f_font
->descent
+
271 menu
.title_h
= style
->t_font
->ascent
+ style
->t_font
->descent
+
276 const char *s
= (menu
.label
) ? menu
.label
:
277 i18n
->getMessage(BasemenuSet
, BasemenuOpenboxMenu
,
282 if (i18n
->multibyte()) {
283 XRectangle ink
, logical
;
284 XmbTextExtents(screen
.getMenuStyle()->t_fontset
, s
, l
, &ink
, &logical
);
285 menu
.item_w
= logical
.width
;
287 menu
.item_w
= XTextWidth(screen
.getMenuStyle()->t_font
, s
, l
);
290 menu
.item_w
+= (menu
.bevel_w
* 2);
296 LinkedListIterator
<BasemenuItem
> it(menuitems
);
297 for (BasemenuItem
*tmp
= it
.current(); tmp
; it
++, tmp
= it
.current()) {
298 const char *s
= ((tmp
->u
&& *tmp
->u
) ? *tmp
->u
:
299 ((tmp
->l
) ? tmp
->l
: (const char *) 0));
302 if (i18n
->multibyte()) {
303 XRectangle ink
, logical
;
304 XmbTextExtents(screen
.getMenuStyle()->f_fontset
, s
, l
, &ink
, &logical
);
307 ii
= XTextWidth(screen
.getMenuStyle()->f_font
, s
, l
);
309 ii
+= (menu
.bevel_w
* 2) + (menu
.item_h
* 2);
311 menu
.item_w
= ((menu
.item_w
< (unsigned int) ii
) ? ii
: menu
.item_w
);
314 if (menuitems
->count()) {
317 while (((menu
.item_h
* (menuitems
->count() + 1) / menu
.sublevels
)
318 + menu
.title_h
+ screen
.getBorderWidth()) >
322 if (menu
.sublevels
< menu
.minsub
) menu
.sublevels
= menu
.minsub
;
324 menu
.persub
= menuitems
->count() / menu
.sublevels
;
325 if (menuitems
->count() % menu
.sublevels
) menu
.persub
++;
331 menu
.width
= (menu
.sublevels
* (menu
.item_w
));
332 if (! menu
.width
) menu
.width
= menu
.item_w
;
334 menu
.frame_h
= (menu
.item_h
* menu
.persub
);
335 menu
.height
= ((title_vis
) ? menu
.title_h
+ screen
.getBorderWidth() : 0) +
337 if (! menu
.frame_h
) menu
.frame_h
= 1;
338 if (menu
.height
< 1) menu
.height
= 1;
343 tmp
= menu
.title_pixmap
;
344 texture
= &(screen
.getMenuStyle()->title
);
345 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
346 menu
.title_pixmap
= None
;
347 XSetWindowBackground(display
, menu
.title
,
348 texture
->getColor()->getPixel());
351 image_ctrl
->renderImage(menu
.width
, menu
.title_h
, texture
);
352 XSetWindowBackgroundPixmap(display
, menu
.title
, menu
.title_pixmap
);
354 if (tmp
) image_ctrl
->removeImage(tmp
);
355 XClearWindow(display
, menu
.title
);
358 tmp
= menu
.frame_pixmap
;
359 texture
= &(screen
.getMenuStyle()->frame
);
360 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
361 menu
.frame_pixmap
= None
;
362 XSetWindowBackground(display
, menu
.frame
,
363 texture
->getColor()->getPixel());
366 image_ctrl
->renderImage(menu
.width
, menu
.frame_h
, texture
);
367 XSetWindowBackgroundPixmap(display
, menu
.frame
, menu
.frame_pixmap
);
369 if (tmp
) image_ctrl
->removeImage(tmp
);
371 tmp
= menu
.hilite_pixmap
;
372 texture
= &(screen
.getMenuStyle()->hilite
);
373 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
374 menu
.hilite_pixmap
= None
;
377 image_ctrl
->renderImage(menu
.item_w
, menu
.item_h
, texture
);
379 if (tmp
) image_ctrl
->removeImage(tmp
);
381 tmp
= menu
.sel_pixmap
;
382 if (texture
->getTexture() == (BImage_Flat
| BImage_Solid
)) {
383 menu
.sel_pixmap
= None
;
385 int hw
= menu
.item_h
/ 2;
387 image_ctrl
->renderImage(hw
, hw
, texture
);
389 if (tmp
) image_ctrl
->removeImage(tmp
);
391 XResizeWindow(display
, menu
.window
, menu
.width
, menu
.height
);
394 XResizeWindow(display
, menu
.title
, menu
.width
, menu
.title_h
);
396 XMoveResizeWindow(display
, menu
.frame
, 0,
397 ((title_vis
) ? menu
.title_h
+
398 screen
.getBorderWidth() : 0), menu
.width
,
401 XClearWindow(display
, menu
.window
);
402 XClearWindow(display
, menu
.title
);
403 XClearWindow(display
, menu
.frame
);
405 if (title_vis
&& visible
) redrawTitle();
407 for (int i
= 0; visible
&& i
< menuitems
->count(); i
++) {
408 if (i
== which_sub
) {
409 drawItem(i
, True
, 0);
412 drawItem(i
, False
, 0);
416 if (parent
&& visible
)
417 parent
->drawSubmenu(parent
->which_sub
);
419 XMapSubwindows(display
, menu
.window
);
423 void Basemenu::show(void) {
424 XMapSubwindows(display
, menu
.window
);
425 XMapWindow(display
, menu
.window
);
429 if (shown
&& (! shown
->torn
))
437 void Basemenu::hide(void) {
438 if ((! torn
) && hide_tree
&& parent
&& parent
->isVisible()) {
439 Basemenu
*p
= parent
;
441 while (p
->isVisible() && (! p
->torn
) && p
->parent
) p
= p
->parent
;
449 void Basemenu::internal_hide(void) {
450 if (which_sub
!= -1) {
451 BasemenuItem
*tmp
= menuitems
->find(which_sub
);
452 tmp
->submenu()->internal_hide();
455 if (parent
&& (! torn
)) {
456 parent
->drawItem(parent
->which_sub
, False
, True
);
458 parent
->which_sub
= -1;
459 } else if (shown
&& shown
->menu
.window
== menu
.window
) {
460 shown
= (Basemenu
*) 0;
463 torn
= visible
= False
;
464 which_sub
= which_press
= which_sub
= -1;
466 XUnmapWindow(display
, menu
.window
);
470 void Basemenu::move(int x
, int y
) {
473 XMoveWindow(display
, menu
.window
, x
, y
);
475 drawSubmenu(which_sub
);
479 void Basemenu::redrawTitle(void) {
480 char *text
= (char *) ((menu
.label
) ? menu
.label
:
481 i18n
->getMessage(BasemenuSet
, BasemenuOpenboxMenu
,
483 int dx
= menu
.bevel_w
, len
= strlen(text
);
486 if (i18n
->multibyte()) {
487 XRectangle ink
, logical
;
488 XmbTextExtents(screen
.getMenuStyle()->t_fontset
, text
, len
, &ink
, &logical
);
491 l
= XTextWidth(screen
.getMenuStyle()->t_font
, text
, len
);
494 l
+= (menu
.bevel_w
* 2);
496 switch (screen
.getMenuStyle()->t_justify
) {
497 case BScreen::RightJustify
:
498 dx
+= menu
.width
- l
;
501 case BScreen::CenterJustify
:
502 dx
+= (menu
.width
- l
) / 2;
506 MenuStyle
*style
= screen
.getMenuStyle();
507 if (i18n
->multibyte())
508 XmbDrawString(display
, menu
.title
, style
->t_fontset
, style
->t_text_gc
, dx
,
509 (menu
.bevel_w
- style
->t_fontset_extents
->max_ink_extent
.y
),
512 XDrawString(display
, menu
.title
, style
->t_text_gc
, dx
,
513 (style
->t_font
->ascent
+ menu
.bevel_w
), text
, len
);
517 void Basemenu::drawSubmenu(int index
) {
518 if (which_sub
!= -1 && which_sub
!= index
) {
519 BasemenuItem
*itmp
= menuitems
->find(which_sub
);
521 if (! itmp
->submenu()->isTorn())
522 itmp
->submenu()->internal_hide();
525 if (index
>= 0 && index
< menuitems
->count()) {
526 BasemenuItem
*item
= menuitems
->find(index
);
527 if (item
->submenu() && visible
&& (! item
->submenu()->isTorn()) &&
529 if (item
->submenu()->parent
!= this) item
->submenu()->parent
= this;
530 int sbl
= index
/ menu
.persub
, i
= index
- (sbl
* menu
.persub
),
532 ((menu
.item_w
* (sbl
+ 1)) + screen
.getBorderWidth()), y
;
534 if (alignment
== AlignTop
)
535 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
536 ((title_vis
) ? menu
.title_h
+ screen
.getBorderWidth() : 0) -
537 ((item
->submenu()->title_vis
) ?
538 item
->submenu()->menu
.title_h
+ screen
.getBorderWidth() : 0));
540 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
542 ((title_vis
) ? menu
.title_h
+ screen
.getBorderWidth() : 0) -
543 ((item
->submenu()->title_vis
) ?
544 item
->submenu()->menu
.title_h
+ screen
.getBorderWidth() : 0));
546 if (alignment
== AlignBottom
&&
547 (y
+ item
->submenu()->menu
.height
) > ((shifted
) ? menu
.y_shift
:
548 menu
.y
) + menu
.height
)
549 y
= (((shifted
) ? menu
.y_shift
: menu
.y
) +
550 menu
.height
- item
->submenu()->menu
.height
);
552 if ((x
+ item
->submenu()->getWidth()) > screen
.getWidth()) {
553 x
= ((shifted
) ? menu
.x_shift
: menu
.x
) -
554 item
->submenu()->getWidth() - screen
.getBorderWidth();
559 if ((y
+ item
->submenu()->getHeight()) > screen
.getHeight())
560 y
= screen
.getHeight() - item
->submenu()->getHeight() -
561 (screen
.getBorderWidth() * 2);
564 item
->submenu()->move(x
, y
);
565 if (! moving
) drawItem(index
, True
);
567 if (! item
->submenu()->isVisible())
568 item
->submenu()->show();
569 item
->submenu()->moving
= moving
;
578 Bool
Basemenu::hasSubmenu(int index
) {
579 if ((index
>= 0) && (index
< menuitems
->count()))
580 if (menuitems
->find(index
)->submenu())
587 void Basemenu::drawItem(int index
, Bool highlight
, Bool clear
,
588 int x
, int y
, unsigned int w
, unsigned int h
)
590 if (index
< 0 || index
> menuitems
->count()) return;
592 BasemenuItem
*item
= menuitems
->find(index
);
595 Bool dotext
= True
, dohilite
= True
, dosel
= True
;
596 const char *text
= (item
->ulabel()) ? *item
->ulabel() : item
->label();
597 int sbl
= index
/ menu
.persub
, i
= index
- (sbl
* menu
.persub
);
598 int item_x
= (sbl
* menu
.item_w
), item_y
= (i
* menu
.item_h
);
599 int hilite_x
= item_x
, hilite_y
= item_y
, hoff_x
= 0, hoff_y
= 0;
600 int text_x
= 0, text_y
= 0, len
= strlen(text
), sel_x
= 0, sel_y
= 0;
601 unsigned int hilite_w
= menu
.item_w
, hilite_h
= menu
.item_h
, text_w
= 0,
603 unsigned int half_w
= menu
.item_h
/ 2, quarter_w
= menu
.item_h
/ 4;
606 if (i18n
->multibyte()) {
607 XRectangle ink
, logical
;
608 XmbTextExtents(screen
.getMenuStyle()->f_fontset
,
609 text
, len
, &ink
, &logical
);
610 text_w
= logical
.width
;
611 text_y
= item_y
+ (menu
.bevel_w
/ 2) -
612 screen
.getMenuStyle()->f_fontset_extents
->max_ink_extent
.y
;
614 text_w
= XTextWidth(screen
.getMenuStyle()->f_font
, text
, len
);
616 screen
.getMenuStyle()->f_font
->ascent
+
620 switch(screen
.getMenuStyle()->f_justify
) {
621 case BScreen::LeftJustify
:
622 text_x
= item_x
+ menu
.bevel_w
+ menu
.item_h
+ 1;
625 case BScreen::RightJustify
:
626 text_x
= item_x
+ menu
.item_w
- (menu
.item_h
+ menu
.bevel_w
+ text_w
);
629 case BScreen::CenterJustify
:
630 text_x
= item_x
+ ((menu
.item_w
+ 1 - text_w
) / 2);
634 text_h
= menu
.item_h
- menu
.bevel_w
;
638 ((highlight
|| item
->isSelected()) ? screen
.getMenuStyle()->h_text_gc
:
639 screen
.getMenuStyle()->f_text_gc
),
641 ((highlight
) ? screen
.getMenuStyle()->h_text_gc
:
642 ((item
->isEnabled()) ? screen
.getMenuStyle()->f_text_gc
:
643 screen
.getMenuStyle()->d_text_gc
));
646 if (screen
.getMenuStyle()->bullet_pos
== Right
)
647 sel_x
+= (menu
.item_w
- menu
.item_h
- menu
.bevel_w
);
649 sel_y
= item_y
+ quarter_w
;
652 XClearArea(display
, menu
.frame
, item_x
, item_y
, menu
.item_w
, menu
.item_h
,
654 } else if (! (x
== y
&& y
== -1 && w
== h
&& h
== 0)) {
655 // calculate the which part of the hilite to redraw
656 if (! (max(item_x
, x
) <= (signed) min(item_x
+ menu
.item_w
, x
+ w
) &&
657 max(item_y
, y
) <= (signed) min(item_y
+ menu
.item_h
, y
+ h
))) {
660 hilite_x
= max(item_x
, x
);
661 hilite_y
= max(item_y
, y
);
662 hilite_w
= min(item_x
+ menu
.item_w
, x
+ w
) - hilite_x
;
663 hilite_h
= min(item_y
+ menu
.item_h
, y
+ h
) - hilite_y
;
664 hoff_x
= hilite_x
% menu
.item_w
;
665 hoff_y
= hilite_y
% menu
.item_h
;
668 // check if we need to redraw the text
669 int text_ry
= item_y
+ (menu
.bevel_w
/ 2);
670 if (! (max(text_x
, x
) <= (signed) min(text_x
+ text_w
, x
+ w
) &&
671 max(text_ry
, y
) <= (signed) min(text_ry
+ text_h
, y
+ h
)))
674 // check if we need to redraw the select pixmap/menu bullet
675 if (! (max(sel_x
, x
) <= (signed) min(sel_x
+ half_w
, x
+ w
) &&
676 max(sel_y
, y
) <= (signed) min(sel_y
+ half_w
, y
+ h
)))
680 if (dohilite
&& highlight
&& (menu
.hilite_pixmap
!= ParentRelative
)) {
681 if (menu
.hilite_pixmap
)
682 XCopyArea(display
, menu
.hilite_pixmap
, menu
.frame
,
683 screen
.getMenuStyle()->hilite_gc
, hoff_x
, hoff_y
,
684 hilite_w
, hilite_h
, hilite_x
, hilite_y
);
686 XFillRectangle(display
, menu
.frame
,
687 screen
.getMenuStyle()->hilite_gc
,
688 hilite_x
, hilite_y
, hilite_w
, hilite_h
);
689 } else if (dosel
&& item
->isSelected() &&
690 (menu
.sel_pixmap
!= ParentRelative
)) {
692 XCopyArea(display
, menu
.sel_pixmap
, menu
.frame
,
693 screen
.getMenuStyle()->hilite_gc
, 0, 0,
694 half_w
, half_w
, sel_x
, sel_y
);
696 XFillRectangle(display
, menu
.frame
,
697 screen
.getMenuStyle()->hilite_gc
,
698 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 tgc
, text_x
, text_y
, text
, len
);
706 XDrawString(display
, menu
.frame
, tgc
, text_x
, text_y
, text
, len
);
709 if (dosel
&& item
->submenu()) {
710 switch (screen
.getMenuStyle()->bullet
) {
712 XDrawRectangle(display
, menu
.frame
, 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
, 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
, gc
, dia
, 4, Convex
,
758 void Basemenu::setLabel(const char *l
) {
760 delete [] menu
.label
;
762 if (l
) menu
.label
= bstrdup(l
);
767 void Basemenu::setItemSelected(int index
, Bool sel
) {
768 if (index
< 0 || index
>= menuitems
->count()) return;
770 BasemenuItem
*item
= find(index
);
773 item
->setSelected(sel
);
774 if (visible
) drawItem(index
, (index
== which_sub
), True
);
778 Bool
Basemenu::isItemSelected(int index
) {
779 if (index
< 0 || index
>= menuitems
->count()) return False
;
781 BasemenuItem
*item
= find(index
);
782 if (! item
) return False
;
784 return item
->isSelected();
788 void Basemenu::setItemEnabled(int index
, Bool enable
) {
789 if (index
< 0 || index
>= menuitems
->count()) return;
791 BasemenuItem
*item
= find(index
);
794 item
->setEnabled(enable
);
795 if (visible
) drawItem(index
, (index
== which_sub
), True
);
799 Bool
Basemenu::isItemEnabled(int index
) {
800 if (index
< 0 || index
>= menuitems
->count()) return False
;
802 BasemenuItem
*item
= find(index
);
803 if (! item
) return False
;
805 return item
->isEnabled();
809 void Basemenu::buttonPressEvent(XButtonEvent
*be
) {
810 if (be
->window
== menu
.frame
) {
811 int sbl
= (be
->x
/ menu
.item_w
), i
= (be
->y
/ menu
.item_h
);
812 int w
= (sbl
* menu
.persub
) + i
;
814 if (w
< menuitems
->count() && w
>= 0) {
818 BasemenuItem
*item
= menuitems
->find(w
);
823 drawItem(w
, (item
->isEnabled()), True
);
826 menu
.x_move
= be
->x_root
- menu
.x
;
827 menu
.y_move
= be
->y_root
- menu
.y
;
832 void Basemenu::buttonReleaseEvent(XButtonEvent
*re
) {
833 if (re
->window
== menu
.title
) {
838 drawSubmenu(which_sub
);
841 if (re
->x
>= 0 && re
->x
<= (signed) menu
.width
&&
842 re
->y
>= 0 && re
->y
<= (signed) menu
.title_h
)
845 } else if (re
->window
== menu
.frame
&&
846 re
->x
>= 0 && re
->x
< (signed) menu
.width
&&
847 re
->y
>= 0 && re
->y
< (signed) menu
.frame_h
) {
848 if (re
->button
== 3) {
851 int sbl
= (re
->x
/ menu
.item_w
), i
= (re
->y
/ menu
.item_h
),
852 ix
= sbl
* menu
.item_w
, iy
= i
* menu
.item_h
,
853 w
= (sbl
* menu
.persub
) + i
,
854 p
= (which_sbl
* menu
.persub
) + which_press
;
856 if (w
< menuitems
->count() && w
>= 0) {
857 drawItem(p
, (p
== which_sub
), True
);
859 if (p
== w
&& isItemEnabled(w
)) {
860 if (re
->x
> ix
&& re
->x
< (signed) (ix
+ menu
.item_w
) &&
861 re
->y
> iy
&& re
->y
< (signed) (iy
+ menu
.item_h
)) {
862 itemSelected(re
->button
, w
);
866 drawItem(p
, False
, True
);
872 void Basemenu::motionNotifyEvent(XMotionEvent
*me
) {
873 if (me
->window
== menu
.title
&& (me
->state
& Button1Mask
)) {
876 if (parent
&& (! torn
)) {
877 parent
->drawItem(parent
->which_sub
, False
, True
);
878 parent
->which_sub
= -1;
881 moving
= torn
= True
;
884 drawSubmenu(which_sub
);
886 menu
.x
= me
->x_root
- menu
.x_move
,
887 menu
.y
= me
->y_root
- menu
.y_move
;
889 XMoveWindow(display
, menu
.window
, menu
.x
, menu
.y
);
892 drawSubmenu(which_sub
);
895 } else if ((! (me
->state
& Button1Mask
)) && me
->window
== menu
.frame
&&
896 me
->x
>= 0 && me
->x
< (signed) menu
.width
&&
897 me
->y
>= 0 && me
->y
< (signed) menu
.frame_h
) {
898 int sbl
= (me
->x
/ menu
.item_w
), i
= (me
->y
/ menu
.item_h
),
899 w
= (sbl
* menu
.persub
) + i
;
901 if ((i
!= which_press
|| sbl
!= which_sbl
) &&
902 (w
< menuitems
->count() && w
>= 0)) {
903 if (which_press
!= -1 && which_sbl
!= -1) {
904 int p
= (which_sbl
* menu
.persub
) + which_press
;
905 BasemenuItem
*item
= menuitems
->find(p
);
907 drawItem(p
, False
, True
);
909 if (item
->submenu()->isVisible() &&
910 (! item
->submenu()->isTorn())) {
911 item
->submenu()->internal_hide();
919 BasemenuItem
*itmp
= menuitems
->find(w
);
924 drawItem(w
, (itmp
->isEnabled()), True
);
930 void Basemenu::exposeEvent(XExposeEvent
*ee
) {
931 if (ee
->window
== menu
.title
) {
933 } else if (ee
->window
== menu
.frame
) {
934 // this is a compilicated algorithm... lets do it step by step...
935 // first... we see in which sub level the expose starts... and how many
936 // items down in that sublevel
938 int sbl
= (ee
->x
/ menu
.item_w
), id
= (ee
->y
/ menu
.item_h
),
939 // next... figure out how many sublevels over the redraw spans
940 sbl_d
= ((ee
->x
+ ee
->width
) / menu
.item_w
),
941 // then we see how many items down to redraw
942 id_d
= ((ee
->y
+ ee
->height
) / menu
.item_h
);
944 if (id_d
> menu
.persub
) id_d
= menu
.persub
;
946 // draw the sublevels and the number of items the exposure spans
947 LinkedListIterator
<BasemenuItem
> it(menuitems
);
949 for (i
= sbl
; i
<= sbl_d
; i
++) {
950 // set the iterator to the first item in the sublevel needing redrawing
951 it
.set(id
+ (i
* menu
.persub
));
952 for (ii
= id
; ii
<= id_d
&& it
.current(); it
++, ii
++) {
953 int index
= ii
+ (i
* menu
.persub
);
955 drawItem(index
, (which_sub
== index
), False
,
956 ee
->x
, ee
->y
, ee
->width
, ee
->height
);
963 void Basemenu::enterNotifyEvent(XCrossingEvent
*ce
) {
964 if (ce
->window
== menu
.frame
) {
965 menu
.x_shift
= menu
.x
, menu
.y_shift
= menu
.y
;
966 if (menu
.x
+ menu
.width
> screen
.getWidth()) {
967 menu
.x_shift
= screen
.getWidth() - menu
.width
-
968 screen
.getBorderWidth();
970 } else if (menu
.x
< 0) {
971 menu
.x_shift
= -screen
.getBorderWidth();
975 if (menu
.y
+ menu
.height
> screen
.getHeight()) {
976 menu
.y_shift
= screen
.getHeight() - menu
.height
-
977 screen
.getBorderWidth();
979 } else if (menu
.y
+ (signed) menu
.title_h
< 0) {
980 menu
.y_shift
= -screen
.getBorderWidth();
985 XMoveWindow(display
, menu
.window
, menu
.x_shift
, menu
.y_shift
);
987 if (which_sub
!= -1) {
988 BasemenuItem
*tmp
= menuitems
->find(which_sub
);
989 if (tmp
->submenu()->isVisible()) {
990 int sbl
= (ce
->x
/ menu
.item_w
), i
= (ce
->y
/ menu
.item_h
),
991 w
= (sbl
* menu
.persub
) + i
;
993 if (w
!= which_sub
&& (! tmp
->submenu()->isTorn())) {
994 tmp
->submenu()->internal_hide();
996 drawItem(which_sub
, False
, True
);
1005 void Basemenu::leaveNotifyEvent(XCrossingEvent
*ce
) {
1006 if (ce
->window
== menu
.frame
) {
1007 if (which_press
!= -1 && which_sbl
!= -1 && menuitems
->count() > 0) {
1008 int p
= (which_sbl
* menu
.persub
) + which_press
;
1010 drawItem(p
, (p
== which_sub
), True
);
1012 which_sbl
= which_press
= -1;
1016 XMoveWindow(display
, menu
.window
, menu
.x
, menu
.y
);
1019 if (which_sub
!= -1) drawSubmenu(which_sub
);
1025 void Basemenu::reconfigure(void) {
1026 XSetWindowBackground(display
, menu
.window
,
1027 screen
.getBorderColor()->getPixel());
1028 XSetWindowBorder(display
, menu
.window
,
1029 screen
.getBorderColor()->getPixel());
1030 XSetWindowBorderWidth(display
, menu
.window
, screen
.getBorderWidth());
1032 menu
.bevel_w
= screen
.getBevelWidth();