// // Copyright (C) 1996 Ben Ross // // You may distribute under the terms of the GNU General Public // License as specified in the COPYING file. // // $Id: XeMenuBar.C,v 1.4 1999/10/21 09:10:05 ben Exp $ #include #include #include #include #include #include #include #include #include XeMenuBar::XeMenuBar(XeObject* parent, char* name, const char* className) : XeWidget(parent, name, className) { _borderWidth = 2; _menuGap = 5; _head = _tail = NULL; _selected = NULL; _inMenu = FALSE; char *fontname = "-adobe-helvetica-bold-r-normal-*-12-*-*-*-*-*-*-*"; setFont(fontname); XSetWindowAttributes attr; XGCValues values; ulong valmask; valmask = CWBitGravity; attr.bit_gravity = NorthWestGravity; XChangeWindowAttributes(gDisplay, _window, valmask, &attr); valmask = GCForeground; values.foreground = lookupColour(this, "grey40"); _shadowGC = getGC(this, &values, valmask); values.foreground = lookupColour(this, "grey90"); _rshadowGC = getGC(this, &values, valmask); values.foreground = _background; _backGC = getGC(this, &values, valmask); XSelectInput(gDisplay, _window, (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask)); resize(_width, _font->ascent + _font->descent + _borderWidth*2 + 4); } XeMenuBar::~XeMenuBar(void) { XeMenuStruct* temp = _head, *next; while (temp) { next = temp->_next; if (temp->_label) free (temp->_label); if (!temp->_static) delete temp->_menu; delete temp; temp = next; } } int XeMenuBar::doEvent(XEvent* theEvent) { switch(theEvent->type) { case Expose: redraw(); break; case ButtonPress: case ButtonRelease: doButton((XButtonEvent *)theEvent); break; case MotionNotify: doMotion((XMotionEvent *)theEvent); break; } return 0; } void XeMenuBar::resizeEvent(uint width, uint height) { // XXX - fix so resizing vertically works also: if(width > _width) { XClearArea(gDisplay, _window, _width - _borderWidth, _borderWidth, _borderWidth, _height - _borderWidth * 2, False); } else { XRectangle r = { 0, 0, width, height}; drawBorder(r, _borderWidth, _rshadowGC, _shadowGC); } } void XeMenuBar::insertMenu(XeMenu* menu, char* label, bool global) { XeMenuStruct* newMenu = new XeMenuStruct; newMenu->_next = NULL; newMenu->_prev = NULL; newMenu->_static = global; if (!global) menu->addCallback(KrPMF(&XeMenuBar::menuCB, this), XE_CB_ACTIVATE); newMenu->_menu = menu; newMenu->_label = strdup(label); if(_tail) { _tail->_next = newMenu; newMenu->_prev = _tail; } _tail = newMenu; if(!_head) _head = _tail; // $$$ bit of a kludge setRects(); } void XeMenuBar::redraw(void) { XRectangle r; r.x = 0; r.y = 0; r.width = _width, r.height = _height; drawBorder(r, _borderWidth, _rshadowGC, _shadowGC); XeMenuStruct* temp = _head; int x, y = _font->ascent+_borderWidth+2; while(temp) { x = temp->_rect.x + _menuGap; XDrawString(gDisplay, _window, _textGC , x, y, temp->_label, strlen(temp->_label)); temp = temp->_next; } } void XeMenuBar::doButton(XButtonEvent* event) { if(event->type == ButtonPress) { menuSelect(event->x); } else if(event->type == ButtonRelease) { if(_selected) { hilite(_selected, FALSE); _selected->_menu->hide(); XFlush(gDisplay); _selected->_menu->doSelect(); } _inMenu = FALSE; _selected = NULL; } } void XeMenuBar::doMotion(XMotionEvent* event) { int y = event->y; XeMenu* theMenu = NULL; if(_selected) theMenu = _selected->_menu; if(_selected && (event->x_root >= theMenu->x() && event->y_root >= theMenu->y() && event->x_root < int(theMenu->x() + theMenu->width()) && event->y_root < int(theMenu->y() + theMenu->height()))) { int mx = event->x_root - theMenu->x(); int my = event->y_root - theMenu->y(); _inMenu = TRUE; theMenu->doMotion(mx, my); } else if(y >=0 && y < int(_height)) { menuSelect(event->x); if(_inMenu) { theMenu->doLeaveNotify(); _inMenu = FALSE; } } else { if(_inMenu) { theMenu->doLeaveNotify(); _inMenu = FALSE; } } } void XeMenuBar::menuSelect(int x) { XeMenuStruct *temp = _head; XeMenu* theMenu; while(temp) { if(x >= temp->_rect.x && x < temp->_rect.width + temp->_rect.x) { if(_selected == temp) break; if(_selected) hilite(_selected, FALSE); hilite(temp, TRUE); theMenu = temp->_menu; XRaiseWindow(gDisplay, theMenu->getWindow()); int xroot, yroot; getRootCoords(xroot, yroot); theMenu->move(xroot + temp->_rect.x, yroot + _height); theMenu->show(); if(_selected) { _selected->_menu->hide(); } _selected = temp; break; } temp = temp->_next; } } void XeMenuBar::hilite(XeMenuStruct* header, bool state) { if(state) drawBorder(header->_rect, 1, _rshadowGC, _shadowGC); else drawBorder(header->_rect, 1, _backGC, _backGC); } void XeMenuBar::setRects(void) { XeMenuStruct* temp = _head; int x = _borderWidth; while(temp) { temp->_rect.x = x; temp->_rect.y = _borderWidth; temp->_rect.height = _font->ascent + _font->descent + 4; x += _menuGap * 2; x += XTextWidth(_font, temp->_label, strlen(temp->_label)); temp->_rect.width = x - temp->_rect.x; temp = temp->_next; } } void XeMenuBar::menuCB(const void* data) { XeObject::CBData* cbdata = (XeObject::CBData*)data; menuSelect(cbdata->ob, cbdata->event, cbdata->callData); } void XeMenuBar::menuSelect(XeObject*, ulong, void* callData) { callCallbacks(XE_CB_ACTIVATE, callData); }