From 1c2f92a3d2288b1cae9500110a72173506a18072 Mon Sep 17 00:00:00 2001 From: simonb Date: Tue, 26 Apr 2005 01:41:55 +0000 Subject: extension of previous big patch. Move a bunch of menu things onto background pixmap. Same for textbuttons. --- ChangeLog | 14 +++ src/ClockTool.cc | 1 + src/FbTk/FbWindow.cc | 52 ++++---- src/FbTk/FbWindow.hh | 14 ++- src/FbTk/GContext.hh | 1 + src/FbTk/Menu.cc | 319 ++++++++++++++++++++++--------------------------- src/FbTk/Menu.hh | 22 ++-- src/FbTk/MenuIcon.cc | 54 +++++---- src/FbTk/MenuIcon.hh | 1 + src/FbTk/MenuItem.cc | 247 +++++++++++++++++++++++--------------- src/FbTk/MenuItem.hh | 2 + src/FbTk/MenuTheme.cc | 19 ++- src/FbTk/MenuTheme.hh | 9 ++ src/FbTk/TextButton.cc | 30 +++-- src/FbTk/TextButton.hh | 8 +- src/FbWinFrame.cc | 22 +--- src/FbWinFrame.hh | 1 - src/IconButton.cc | 6 +- src/IconButton.hh | 2 +- src/ToggleMenu.hh | 11 +- src/Window.cc | 9 +- src/fluxbox.cc | 4 +- 22 files changed, 462 insertions(+), 386 deletions(-) diff --git a/ChangeLog b/ChangeLog index d967eb7..e938d6f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ (Format: Year/Month/Day) Changes for 0.9.13 +*05/04/26: + * Extension of previous patch, pushing various bits of menu items and + text buttons onto the background, and fixing various issues (Simon) + + Incidentally, adds some new theme items (due to backwards + compatibility fix): + - menu.hilite.submenu.pixmap: + - menu.hilite.selected.pixmap: + - menu.hilite.unselected.pixmap: + These are equivalent to the no-.hilite ones, except are shown + when the item is highlighted... + FbTk/... + Menu.hh/cc MenuItem.hh/cc MenuTheme.hh/cc TextButton.hh/cc + FbWindow.hh/cc MenuIcon.hh/cc + FbWinFrame.hh/cc IconButton.hh/cc ToggleMenu.hh Window.cc *05/04/25: * Fixed #1188690, fbrun segfault (Mathias) FbTk/App.cc diff --git a/src/ClockTool.cc b/src/ClockTool.cc index 7c688cc..6b23ee7 100644 --- a/src/ClockTool.cc +++ b/src/ClockTool.cc @@ -249,6 +249,7 @@ void ClockTool::updateTime() { if (!strftime(time_string, 255, m_timeformat->c_str(), time_type) || m_button.text() == time_string) return; m_button.setText(time_string); + m_button.parentMoved(); #else // dont have strftime so we have to set it to hour:minut // sprintf(time_string, "%d:%d", ); #endif // HAVE_STRFTIME diff --git a/src/FbTk/FbWindow.cc b/src/FbTk/FbWindow.cc index 1b4f77f..acdc7c1 100644 --- a/src/FbTk/FbWindow.cc +++ b/src/FbTk/FbWindow.cc @@ -46,7 +46,7 @@ namespace FbTk { FbWindow::FbWindow():FbDrawable(), m_parent(0), m_screen_num(0), m_window(0), m_x(0), m_y(0), m_width(0), m_height(0), m_border_width(0), m_depth(0), m_destroy(true), - m_lastbg_pm(0){ + m_lastbg_pm(0), m_renderer(0) { } @@ -57,7 +57,7 @@ FbWindow::FbWindow(const FbWindow& the_copy):FbDrawable(), m_width(the_copy.width()), m_height(the_copy.height()), m_border_width(the_copy.borderWidth()), m_depth(the_copy.depth()), m_destroy(true), - m_lastbg_pm(0) { + m_lastbg_pm(0), m_renderer(the_copy.m_renderer) { the_copy.m_window = 0; } @@ -75,7 +75,7 @@ FbWindow::FbWindow(int screen_num, m_destroy(true), m_lastbg_color_set(false), m_lastbg_color(0), - m_lastbg_pm(0) { + m_lastbg_pm(0), m_renderer(0) { create(RootWindow(display(), screen_num), x, y, width, height, eventmask, @@ -93,7 +93,7 @@ FbWindow::FbWindow(const FbWindow &parent, m_destroy(true), m_lastbg_color_set(false), m_lastbg_color(0x42), - m_lastbg_pm(0) { + m_lastbg_pm(0), m_renderer(0) { create(parent.window(), x, y, width, height, eventmask, override_redirect, save_unders, depth, class_type); @@ -109,7 +109,7 @@ FbWindow::FbWindow(Window client):FbDrawable(), m_parent(0), m_border_width(0), m_depth(0), m_destroy(false), // don't destroy this window - m_lastbg_pm(0) { + m_lastbg_pm(0), m_renderer(0) { setNew(client); } @@ -166,22 +166,19 @@ void FbWindow::updateBackground(bool only_if_alpha) { if (m_transparent->source() != root) m_transparent->setSource(root, screenNumber()); - newbg = XCreatePixmap(display(), window(), width(), height(), depth()); - free_newbg = true; + FbPixmap newpm = FbPixmap(*this, width(), height(), depth()); + free_newbg = true; // newpm gets released to newbg at end of block GC gc = XCreateGC(display(), window(), 0, 0); if (m_lastbg_pm == None && m_lastbg_color_set) { XSetForeground(display(), gc, m_lastbg_color); - XFillRectangle(display(), newbg, gc, 0, 0, width(), height()); + newpm.fillRectangle(gc, 0, 0, width(), height()); } else { // copy from window if no color and no bg... - XCopyArea(display(), (m_lastbg_pm == None)?drawable():m_lastbg_pm, newbg, gc, - 0, 0, - width(), height(), - 0, 0); + newpm.copyArea((m_lastbg_pm == None)?drawable():m_lastbg_pm, gc, 0, 0, 0, 0, width(), height()); } XFreeGC(display(), gc); - m_transparent->setDest(newbg, screenNumber()); + m_transparent->setDest(newpm.drawable(), screenNumber()); // get root position @@ -202,7 +199,13 @@ void FbWindow::updateBackground(bool only_if_alpha) { m_transparent->render(root_x, root_y, 0, 0, width(), height()); + + // render any foreground items + if (m_renderer) + m_renderer->renderForeground(*this, newpm); + m_transparent->freeDest(); // it's only temporary, don't leave it hanging around + newbg = newpm.release(); } if (newbg != None) @@ -238,10 +241,14 @@ void FbWindow::clear() { void FbWindow::clearArea(int x, int y, unsigned int width, unsigned int height, bool exposures) { + // TODO: probably could call renderForeground here (with x,y,w,h) XClearArea(display(), window(), x, y, width, height, exposures); } -void FbWindow::updateTransparent(int the_x, int the_y, unsigned int the_width, unsigned int the_height) { +// If override_is_offset, then dest_override is a pixmap located at the_x, the_y +// with size the_width x the_height in the target window. + +void FbWindow::updateTransparent(int the_x, int the_y, unsigned int the_width, unsigned int the_height, Pixmap dest_override, bool override_is_offset) { #ifdef HAVE_XRENDER if (!m_transparent.get()) return; @@ -249,13 +256,16 @@ void FbWindow::updateTransparent(int the_x, int the_y, unsigned int the_width, u if (width() == 0 || height() == 0) return; - if ((the_width == 0 && the_height == 0 || the_width == width() && the_height == height()) && + if (!dest_override && (the_width == 0 && the_height == 0 || the_width == width() && the_height == height()) && the_x <= 0 && the_y <= 0) { // do the whole thing updateBackground(true); return; } + if (!dest_override) + dest_override = window(); + if (the_width == 0 || the_height == 0) { the_width = width(); the_height = height(); @@ -271,8 +281,8 @@ void FbWindow::updateTransparent(int the_x, int the_y, unsigned int the_width, u if (m_transparent->source() != root) m_transparent->setSource(root, screenNumber()); - if (m_transparent->dest() != window()) - m_transparent->setDest(window(), screenNumber()); + if (m_transparent->dest() != dest_override) + m_transparent->setDest(dest_override, screenNumber()); // get root position @@ -292,7 +302,7 @@ void FbWindow::updateTransparent(int the_x, int the_y, unsigned int the_width, u // render background image from root pos to our window m_transparent->render(root_x + the_x, root_y + the_y, - the_x, the_y, + override_is_offset?0:the_x, override_is_offset?0:the_y, the_width, the_height); #endif // HAVE_XRENDER } @@ -497,12 +507,6 @@ void FbWindow::setOpaque(unsigned char alpha) { #endif // HAVE_XRENDER } -/* -void FbWindow::setBufferPixmap(Pixmap pm) { - m_lastbg_pm = pm; -} -*/ - void FbWindow::updateGeometry() { if (m_window == 0) return; diff --git a/src/FbTk/FbWindow.hh b/src/FbTk/FbWindow.hh index 0c481c9..ff1b42e 100644 --- a/src/FbTk/FbWindow.hh +++ b/src/FbTk/FbWindow.hh @@ -34,6 +34,8 @@ namespace FbTk { class Color; class Transparent; +class FbPixmap; +class FbWindowRenderer; /// Wrapper for X window /** @@ -82,7 +84,7 @@ public: virtual void clearArea(int x, int y, unsigned int width, unsigned int height, bool exposures = false); - void updateTransparent(int x = -1, int y = -1, unsigned int width = 0, unsigned int height = 0); + void updateTransparent(int x = -1, int y = -1, unsigned int width = 0, unsigned int height = 0, Pixmap dest_override = None, bool override_is_offset = false); void setAlpha(unsigned char alpha); @@ -182,6 +184,8 @@ public: // used for composite void setOpaque(unsigned char alpha); + void setRenderer(FbWindowRenderer &renderer) { m_renderer = &renderer; } + protected: /// creates a window with x window client (m_window = client) explicit FbWindow(Window client); @@ -213,6 +217,8 @@ private: bool m_lastbg_color_set; unsigned long m_lastbg_color; Pixmap m_lastbg_pm; + + FbWindowRenderer *m_renderer; }; bool operator == (Window win, const FbWindow &fbwin); @@ -235,9 +241,15 @@ private: unsigned char *m_state; int m_num; int m_mode; +}; +/// Interface class to render FbWindow foregrounds. +class FbWindowRenderer { +public: + virtual void renderForeground(FbWindow &win, FbDrawable &drawable) = 0; }; + } // end namespace FbTk #endif // FBTK_FBWINDOW_HH diff --git a/src/FbTk/GContext.hh b/src/FbTk/GContext.hh index 15b0ff2..6b93b7a 100644 --- a/src/FbTk/GContext.hh +++ b/src/FbTk/GContext.hh @@ -131,6 +131,7 @@ public: void copy(GC gc); void copy(const GContext &gc); + inline GContext &operator = (const GContext ©_gc) { copy(copy_gc); return *this; } inline GContext &operator = (GC copy_gc) { copy(copy_gc); return *this; } inline GC gc() const { return m_gc; } diff --git a/src/FbTk/Menu.cc b/src/FbTk/Menu.cc index a4aed46..4d6a6c0 100644 --- a/src/FbTk/Menu.cc +++ b/src/FbTk/Menu.cc @@ -121,9 +121,7 @@ Menu::Menu(MenuTheme &tm, ImageControl &imgctrl): menu.frame_pixmap = menu.title_pixmap = - menu.hilite_pixmap = - menu.sel_pixmap = None; - + menu.hilite_pixmap = None; menu.item_w = menu.frame_h = theme().titleFont().height() + theme().bevelWidth() * 2; @@ -157,6 +155,7 @@ Menu::Menu(MenuTheme &tm, ImageControl &imgctrl): true); // save under evm.add(*this, menu.title); + menu.title.setRenderer(*this); event_mask |= PointerMotionMask; menu.frame = FbTk::FbWindow(menu.window, // parent @@ -166,6 +165,7 @@ Menu::Menu(MenuTheme &tm, ImageControl &imgctrl): false, // override redirect true); // save under evm.add(*this, menu.frame); + menu.frame.setRenderer(*this); menu.title.raise(); @@ -190,9 +190,6 @@ Menu::~Menu() { if (menu.hilite_pixmap) m_image_ctrl.removeImage(menu.hilite_pixmap); - if (menu.sel_pixmap) - m_image_ctrl.removeImage(menu.sel_pixmap); - if (s_focused == this) s_focused = 0; } @@ -285,7 +282,7 @@ void Menu::nextItem() { // since it might hide the parent if we use Menu::hide menuitems[old_which_press]->submenu()->internal_hide(); } - drawItem(old_which_press, true); // clear + clearItem(old_which_press); } // restore old in case we changed m_which_press @@ -306,7 +303,7 @@ void Menu::nextItem() { m_active_index = m_which_press; - drawItem(m_which_press, true); // clear + clearItem(m_which_press); } @@ -320,7 +317,7 @@ void Menu::prevItem() { // since it might hide the parent if we use Menu::hide menuitems[old_which_press]->submenu()->internal_hide(); } - drawItem(old_which_press, true); // clear + clearItem(old_which_press); } // restore old in case we changed m_which_press m_which_press = old_which_press - 1; @@ -340,7 +337,7 @@ void Menu::prevItem() { m_active_index = m_which_press; - drawItem(m_which_press, true); // clear + clearItem(m_which_press); } @@ -370,7 +367,7 @@ void Menu::enterParent() { submenu->internal_hide(); m_active_index = -1; - drawItem(m_which_press, true); // clear + //clearItem(m_which_press); m_which_press = -1; // dont select any in this // hide self m_visible = false; @@ -451,7 +448,36 @@ void Menu::updateMenu(int active_index) { if (menu.frame.alpha() != alpha()) menu.frame.setAlpha(alpha()); - Pixmap tmp = 0; + Pixmap tmp = menu.hilite_pixmap; + const FbTk::Texture &hilite_tex = theme().hiliteTexture(); + if (!hilite_tex.usePixmap()) { + menu.hilite_pixmap = None; + } else + menu.hilite_pixmap = + m_image_ctrl.renderImage(menu.item_w, theme().itemHeight(), hilite_tex); + if (tmp) + m_image_ctrl.removeImage(tmp); + + + if (!theme().selectedPixmap().pixmap().drawable()) { + int hw = theme().itemHeight() / 2; + m_theme.setSelectedPixmap(m_image_ctrl.renderImage(hw, hw, theme().hiliteTexture())); + + if (!theme().highlightSelectedPixmap().pixmap().drawable()) { + int hw = theme().itemHeight() / 2; + m_theme.setHighlightSelectedPixmap(m_image_ctrl.renderImage(hw, hw, theme().frameTexture())); + } + } + + if (m_title_vis) { + menu.title.moveResize(-menu.title.borderWidth(), -menu.title.borderWidth(), + width() + menu.title.borderWidth(), theme().titleHeight()); + } + + menu.frame.moveResize(0, ((m_title_vis) ? menu.title.y() + menu.title.height() + + menu.title.borderWidth()*2 : 1), + width(), menu.frame_h); + if (m_title_vis && m_need_update) { tmp = menu.title_pixmap; const FbTk::Texture &tex = theme().titleTexture(); @@ -485,46 +511,8 @@ void Menu::updateMenu(int active_index) { m_image_ctrl.removeImage(tmp); } - tmp = menu.hilite_pixmap; - const FbTk::Texture &hilite_tex = theme().hiliteTexture(); - if (!hilite_tex.usePixmap()) { - menu.hilite_pixmap = None; - } else - menu.hilite_pixmap = - m_image_ctrl.renderImage(menu.item_w, theme().itemHeight(), hilite_tex); - if (tmp) - m_image_ctrl.removeImage(tmp); - - tmp = menu.sel_pixmap; - if (!hilite_tex.usePixmap()) { - menu.sel_pixmap = None; - } else { - int hw = theme().itemHeight() / 2; - menu.sel_pixmap = - m_image_ctrl.renderImage(hw, hw, hilite_tex); - } - if (tmp) - m_image_ctrl.removeImage(tmp); - - - - if (m_title_vis) { - menu.title.moveResize(-menu.title.borderWidth(), -menu.title.borderWidth(), - width() + menu.title.borderWidth(), theme().titleHeight()); - } - - menu.frame.moveResize(0, ((m_title_vis) ? menu.title.y() + menu.title.height() + - menu.title.borderWidth()*2 : 1), - width(), menu.frame_h); - - // if menu m_visible and title m_visible - if (m_title_vis && m_visible) - redrawTitle(); - - if (m_visible && (active_index >= 0 || m_need_update)) { - redrawFrame(); - } + clearWindow(); m_need_update = false; } @@ -583,14 +571,18 @@ void Menu::grabInputFocus() { void Menu::clearWindow() { - redrawTitle(); - redrawFrame(); + menu.title.clear(); + menu.frame.clear(); + + // clear foreground bits of frame items + for (unsigned int i = 0; i < menuitems.size(); i++) { + clearItem(i, false); // no clear + } } -void Menu::redrawFrame() { - menu.frame.clear(); +void Menu::redrawFrame(FbDrawable &drawable) { for (unsigned int i = 0; i < menuitems.size(); i++) { - drawItem(i, false); // no clear + drawItem(drawable, i); } } @@ -606,7 +598,7 @@ void Menu::internal_hide() { // as non active int old = m_active_index; m_active_index = -1; - drawItem(old, true); // clear old area from highlight + clearItem(old); // clear old area from highlight if (shown && shown->menu.window == menu.window) shown = (Menu *) 0; @@ -638,7 +630,7 @@ void Menu::move(int x, int y) { } -void Menu::redrawTitle() { +void Menu::redrawTitle(FbDrawable &drawable) { const char *text = menu.label.c_str(); const FbTk::Font &font = theme().titleFont(); @@ -657,16 +649,9 @@ void Menu::redrawTitle() { break; } - if (menu.title.alpha() != alpha()) - menu.title.setAlpha(alpha()); - - FbTk::GContext def_gc(menu.title); - - menu.title.clear(); - // difference between height based on font, and style-set height int height_offset = theme().titleHeight() - (font.height() + 2*theme().bevelWidth()); - font.drawText(menu.title, // drawable + font.drawText(drawable, // drawable screenNumber(), theme().titleTextGC().gc(), // graphic context text, len, // text string with length @@ -741,7 +726,7 @@ void Menu::drawSubmenu(unsigned int index) { item->submenu()->move(new_x, new_y); if (! m_moving) - drawItem(index); + clearItem(index); if (! item->submenu()->isVisible()) { item->submenu()->show(); @@ -766,99 +751,24 @@ bool Menu::hasSubmenu(unsigned int index) const { } -int Menu::drawItem(unsigned int index, bool clear, - int x, int y, unsigned int w, unsigned int h) { +int Menu::drawItem(FbDrawable &drawable, unsigned int index, + bool highlight, bool exclusive_drawable) { + if (index >= menuitems.size() || menuitems.size() == 0 || menu.persub == 0) return 0; - // don't bother if we're not showing - if (!isVisible()) - return 0; - MenuItem *item = menuitems[index]; if (! item) return 0; int sbl = index / menu.persub, i = index - (sbl * menu.persub); int item_x = (sbl * menu.item_w), item_y = (i * theme().itemHeight()); - unsigned int item_w = menu.item_w, item_h = theme().itemHeight(); - int hilite_x = item_x, hilite_y = item_y, hoff_x = 0, hoff_y = 0; - int sel_x = 0, sel_y = 0; - unsigned int hilite_w = menu.item_w, hilite_h = theme().itemHeight(); - unsigned int half_w = theme().itemHeight() / 2, quarter_w = theme().itemHeight() / 4; - bool highlight = (index == m_active_index); - GC gc = - ((highlight || item->isSelected()) ? theme().hiliteTextGC().gc() : - theme().frameTextGC().gc()); - - sel_x = item_x; - - if (theme().bulletPos() == FbTk::RIGHT) - sel_x += (menu.item_w - theme().itemHeight() - theme().bevelWidth()); - - sel_x += quarter_w; - sel_y = item_y + quarter_w; - - if (clear) { - frameWindow().clearArea(item_x, item_y, - menu.item_w, theme().itemHeight(), False); - } - - if (highlight && (menu.hilite_pixmap != ParentRelative)) { - if (menu.hilite_pixmap) { - menu.frame.copyArea(menu.hilite_pixmap, - theme().hiliteGC().gc(), hoff_x, hoff_y, - item_x, item_y, - item_w, item_h); - } else { - menu.frame.fillRectangle(theme().hiliteGC().gc(), - item_x, item_y, item_w, item_h); - } - menu.frame.updateTransparent(item_x, item_y, item_w, item_h); - } - //!! - //!! TODO: Move this out to MenuItem - //!! current problem: menu.sel_pixmap needs a image control instance - //!! to be generated :( - //!! - if (item->isToggleItem() && item->isSelected()) { - Display *disp = FbTk::App::instance()->display(); - if (theme().selectedPixmap().pixmap().drawable()) { - - // enable clip mask - XSetClipMask(disp, - gc, - theme().selectedPixmap().mask().drawable()); - XSetClipOrigin(disp, - gc, sel_x, item_y); - // copy bullet pixmap to frame - menu.frame.copyArea(theme().selectedPixmap().pixmap().drawable(), - gc, - 0, 0, - sel_x, item_y, - theme().selectedPixmap().width(), - theme().selectedPixmap().height()); - // disable clip mask - XSetClipMask(disp, - gc, - None); - } else { - if (highlight && menu.sel_pixmap) { - menu.frame.copyArea(menu.sel_pixmap, - theme().hiliteGC().gc(), - 0, 0, - sel_x, sel_y, - half_w, half_w); - } else { - menu.frame.fillRectangle(theme().hiliteGC().gc(), - sel_x, sel_y, half_w, half_w); - } - } - - } + if (exclusive_drawable) + item_x = item_y = 0; - item->draw(menu.frame, theme(), highlight, + item->draw(drawable, theme(), highlight, + exclusive_drawable, true, // draw fg, draw bg item_x, item_y, menu.item_w, theme().itemHeight()); @@ -955,8 +865,6 @@ void Menu::buttonPressEvent(XButtonEvent &be) { if (item->submenu()) { if (!item->submenu()->isVisible()) drawSubmenu(w); - } else { - drawItem(w, true); // clear } } } else { @@ -978,8 +886,7 @@ void Menu::buttonReleaseEvent(XButtonEvent &re) { // update these since we've (probably) moved menu.title.parentMoved(); menu.frame.parentMoved(); - redrawTitle(); - redrawFrame(); + clearWindow(); } } @@ -1002,7 +909,7 @@ void Menu::buttonReleaseEvent(XButtonEvent &re) { } } - drawItem(p, true); // clear + clearItem(p); } } } @@ -1016,8 +923,8 @@ void Menu::motionNotifyEvent(XMotionEvent &me) { if (! m_moving) { // if not m_moving: start m_moving operation if (m_parent && (! m_torn)) { - m_parent->drawItem(m_parent->m_which_sub, true); // clear m_parent->m_which_sub = -1; + m_parent->clearItem(m_parent->m_which_sub); // clear } m_moving = m_torn = true; @@ -1047,10 +954,9 @@ void Menu::motionNotifyEvent(XMotionEvent &me) { if (item != 0) { - drawItem(old, true); // clear + clearItem(old); if (item->submenu()) { - if (item->submenu()->isVisible() && !item->submenu()->isTorn()) { // setup hide timer for submenu @@ -1085,8 +991,8 @@ void Menu::motionNotifyEvent(XMotionEvent &me) { // draw item highlighted and // start submenu open delay - drawItem(w, true); // clear - + clearItem(w); + if (theme().menuMode() == MenuTheme::DELAY_OPEN) { // setup show menu timer timeval timeout; @@ -1102,7 +1008,7 @@ void Menu::motionNotifyEvent(XMotionEvent &me) { // draw highlighted m_submenu_timer.stop(); if (itmp->isEnabled()) { - drawItem(w, true); // clear + clearItem(w); } } @@ -1112,10 +1018,8 @@ void Menu::motionNotifyEvent(XMotionEvent &me) { void Menu::exposeEvent(XExposeEvent &ee) { if (ee.window == menu.title) { - redrawTitle(); + menu.title.clearArea(ee.x, ee.y, ee.width, ee.height); } else if (ee.window == menu.frame) { - menu.frame.clearArea(ee.x, ee.y, ee.width, ee.height); - // find where to clear // this is a compilicated algorithm... lets do it step by step... // first... we see in which sub level the expose starts... and how many @@ -1140,7 +1044,7 @@ void Menu::exposeEvent(XExposeEvent &ee) { for (ii = id; ii <= id_d && it != it_end; ++it, ii++) { int index = ii + (i * menu.persub); // redraw the item - drawItem(index, false); // no clear + clearItem(index); } } } @@ -1187,7 +1091,7 @@ void Menu::enterNotifyEvent(XCrossingEvent &ce) { if (w != m_which_sub && (! tmp->submenu()->isTorn())) { tmp->submenu()->internal_hide(); - drawItem(m_which_sub, true); // clear + clearItem(m_which_sub); // not highlighted anymore m_which_sub = -1; } } @@ -1198,18 +1102,6 @@ void Menu::leaveNotifyEvent(XCrossingEvent &ce) { if (menu.frame != ce.window) return; - if (m_which_press != -1 && m_which_sbl != -1 && menuitems.size() > 0) { - int p = (m_which_sbl * menu.persub) + m_which_press; - - drawItem(p, true); // clear - - m_which_sbl = m_which_press = -1; - } - - if (m_shifted) { - // menu.window.move(menu.x, menu.y); - m_shifted = false; - } } void Menu::keyPressEvent(XKeyEvent &event) { @@ -1282,7 +1174,7 @@ void Menu::openSubmenu() { if (!validIndex(item)) return; - drawItem(item, true); // clear + clearItem(item); if (menuitems[item]->submenu() != 0 && !menuitems[item]->submenu()->isVisible()) drawSubmenu(item); @@ -1311,8 +1203,9 @@ void Menu::update(FbTk::Subject *subj) { Menuitems::iterator it = menuitems.begin(); Menuitems::iterator it_end = menuitems.end(); - for (; it != it_end; ++it) + for (; it != it_end; ++it) { (*it)->updateTheme(theme()); + } reconfigure(); } @@ -1324,4 +1217,72 @@ void Menu::setScreen(int x, int y, int w, int h) { m_screen_height = h; } +// Render the foreground objects of given window onto given pixmap +void Menu::renderForeground(FbWindow &win, FbDrawable &drawable) { + if (&win == &menu.frame) { + redrawFrame(drawable); + } else if (&win == &menu.title) { + redrawTitle(drawable); + } +} + +// clear item clears the item and draws the dynamic bits +// thus sometimes it won't perform the actual clear operation +// nothing in here should be rendered transparently +// (unless you use a caching pixmap, which I think we should avoid) +void Menu::clearItem(int index, bool clear) { + if (!validIndex(index)) + return; + + int sbl = index / menu.persub, i = index - (sbl * menu.persub); + unsigned int item_w = menu.item_w, item_h = theme().itemHeight(); + int item_x = (sbl * item_w), item_y = (i * item_h); + bool highlight = (index == m_active_index); + + if (highlight) { + highlightItem(index); + return; + } else if (clear) + menu.frame.clearArea(item_x, item_y, item_w, item_h); + + MenuItem *item = menuitems[index]; + if (! item) return; + + item->draw(menu.frame, theme(), highlight, + true, false, item_x, item_y, + item_w, item_h); +} + +// Area must have been cleared before calling highlight +void Menu::highlightItem(int index) { + int sbl = index / menu.persub, i = index - (sbl * menu.persub); + unsigned int item_w = menu.item_w, item_h = theme().itemHeight(); + int item_x = (sbl * menu.item_w), item_y = (i * item_h); + + FbPixmap buffer = FbPixmap(menu.frame, item_w, item_h, menu.frame.depth()); + + int hilite_x = item_x, hilite_y = item_y; + if (menu.hilite_pixmap != ParentRelative) { + if (menu.hilite_pixmap) { + buffer.copyArea(menu.hilite_pixmap, + theme().hiliteGC().gc(), 0, 0, + 0, 0, + item_w, item_h); + } else { + buffer.fillRectangle(theme().hiliteGC().gc(), + 0, 0, item_w, item_h); + } + menu.frame.updateTransparent(item_x, item_y, item_w, item_h, buffer.drawable(), true); + } + + + drawItem(buffer, index, true, true); + + menu.frame.copyArea(buffer.drawable(), theme().hiliteGC().gc(), + 0, 0, + item_x, item_y, + item_w, item_h); + +} + }; // end namespace FbTk diff --git a/src/FbTk/Menu.hh b/src/FbTk/Menu.hh index d079ba8..bec76ac 100644 --- a/src/FbTk/Menu.hh +++ b/src/FbTk/Menu.hh @@ -47,7 +47,7 @@ class MenuItem; class ImageControl; /// Base class for menus -class Menu: public FbTk::EventHandler, protected FbTk::Observer { +class Menu: public FbTk::EventHandler, FbTk::FbWindowRenderer, protected FbTk::Observer { public: enum Alignment{ ALIGNDONTCARE = 1, ALIGNTOP, ALIGNBOTTOM }; enum { RIGHT = 1, LEFT }; @@ -166,6 +166,8 @@ public: inline Menu *parent() { return m_parent; } inline const Menu *parent() const { return m_parent; } + void renderForeground(FbWindow &win, FbDrawable &drawable); + protected: inline void setTitleVisibility(bool b) { @@ -177,12 +179,14 @@ protected: } virtual void itemSelected(int button, unsigned int index) { } - virtual int drawItem(unsigned int index, - bool clear = false, - int x= -1, int y= -1, - unsigned int width= 0, unsigned int height= 0); - virtual void redrawTitle(); - virtual void redrawFrame(); + // renders item onto pm + int drawItem(FbDrawable &pm, unsigned int index, + bool highlight = false, + bool exclusive_drawable = false); + void clearItem(int index, bool clear = true); + void highlightItem(int index); + virtual void redrawTitle(FbDrawable &pm); + virtual void redrawFrame(FbDrawable &pm); virtual void internal_hide(); @@ -197,7 +201,7 @@ private: typedef std::vector Menuitems; - const MenuTheme &m_theme; + MenuTheme &m_theme; Menu *m_parent; ImageControl &m_image_ctrl; Menuitems menuitems; @@ -215,7 +219,7 @@ private: Alignment m_alignment; struct _menu { - Pixmap frame_pixmap, title_pixmap, hilite_pixmap, sel_pixmap; + Pixmap frame_pixmap, title_pixmap, hilite_pixmap; FbTk::FbWindow window, frame, title; std::string label; diff --git a/src/FbTk/MenuIcon.cc b/src/FbTk/MenuIcon.cc index acdc333..f1ae389 100644 --- a/src/FbTk/MenuIcon.cc +++ b/src/FbTk/MenuIcon.cc @@ -53,35 +53,39 @@ void MenuIcon::updateTheme(const MenuTheme &theme) { void MenuIcon::draw(FbDrawable &drawable, const MenuTheme &theme, - bool highlight, + bool highlight, bool draw_foreground, bool draw_background, int x, int y, unsigned int width, unsigned int height) const { - Display *disp = FbTk::App::instance()->display(); - if (height - 2*theme.bevelWidth() != m_pixmap.height() && - !m_filename.empty()) { - unsigned int scale_size = height - 2*theme.bevelWidth(); - m_pixmap.scale(scale_size, scale_size); - m_mask.scale(scale_size, scale_size); + // all background + if (draw_background) { + Display *disp = FbTk::App::instance()->display(); + if (height - 2*theme.bevelWidth() != m_pixmap.height() && + !m_filename.empty()) { + unsigned int scale_size = height - 2*theme.bevelWidth(); + m_pixmap.scale(scale_size, scale_size); + m_mask.scale(scale_size, scale_size); + } + + if (m_pixmap.drawable() != 0) { + GC gc = theme.frameTextGC().gc(); + + // enable clip mask + XSetClipMask(disp, gc, m_mask.drawable()); + XSetClipOrigin(disp, gc, x + theme.bevelWidth(), y + theme.bevelWidth()); + + drawable.copyArea(m_pixmap.drawable(), + gc, + 0, 0, + x + theme.bevelWidth(), y + theme.bevelWidth(), + m_pixmap.width(), m_pixmap.height()); + + // restore clip mask + XSetClipMask(disp, gc, None); + } } - - if (m_pixmap.drawable() != 0) { - GC gc = theme.frameTextGC().gc(); - - // enable clip mask - XSetClipMask(disp, gc, m_mask.drawable()); - XSetClipOrigin(disp, gc, x + theme.bevelWidth(), y + theme.bevelWidth()); - - drawable.copyArea(m_pixmap.drawable(), - gc, - 0, 0, - x + theme.bevelWidth(), y + theme.bevelWidth(), - m_pixmap.width(), m_pixmap.height()); - - // restore clip mask - XSetClipMask(disp, gc, None); - } - FbTk::MenuItem::draw(drawable, theme, highlight, x, y, width, height); + FbTk::MenuItem::draw(drawable, theme, highlight, + draw_background, draw_foreground, x, y, width, height); } unsigned int MenuIcon::width(const MenuTheme &theme) const { diff --git a/src/FbTk/MenuIcon.hh b/src/FbTk/MenuIcon.hh index dd68b18..7fbd12a 100644 --- a/src/FbTk/MenuIcon.hh +++ b/src/FbTk/MenuIcon.hh @@ -38,6 +38,7 @@ public: void draw(FbDrawable &drawable, const MenuTheme &theme, bool highlight, + bool draw_foreground, bool draw_background, int x, int y, unsigned int width, unsigned int height) const; unsigned int width(const MenuTheme &item) const; diff --git a/src/FbTk/MenuItem.cc b/src/FbTk/MenuItem.cc index 1f3125c..1ed3ebd 100644 --- a/src/FbTk/MenuItem.cc +++ b/src/FbTk/MenuItem.cc @@ -39,142 +39,194 @@ void MenuItem::click(int button, int time) { void MenuItem::draw(FbDrawable &draw, const MenuTheme &theme, - bool highlight, + bool highlight, bool draw_foreground, bool draw_background, int x, int y, unsigned int width, unsigned int height) const { + // text and submenu icon are background + // selected pixmaps are foreground + Display *disp = App::instance()->display(); // // Icon // - if (m_icon.get() != 0 && m_icon->pixmap.get() != 0) { - // scale pixmap to right size - if (height - 2*theme.bevelWidth() != m_icon->pixmap->height() && - !m_icon->filename.empty()) { - unsigned int scale_size = height - 2*theme.bevelWidth(); - m_icon->pixmap->scale(scale_size, scale_size); - } - - if (m_icon->pixmap->pixmap().drawable() != 0) { - GC gc = theme.frameTextGC().gc(); - int icon_x = x + theme.bevelWidth(); - int icon_y = y + theme.bevelWidth(); - // enable clip mask - XSetClipMask(disp, gc, m_icon->pixmap->mask().drawable()); - XSetClipOrigin(disp, gc, icon_x, icon_y); - - draw.copyArea(m_icon->pixmap->pixmap().drawable(), - gc, - 0, 0, - icon_x, icon_y, - m_icon->pixmap->width(), m_icon->pixmap->height()); + if (draw_background) { + if (m_icon.get() != 0 && m_icon->pixmap.get() != 0) { + // scale pixmap to right size + if (height - 2*theme.bevelWidth() != m_icon->pixmap->height() && + !m_icon->filename.empty()) { + unsigned int scale_size = height - 2*theme.bevelWidth(); + m_icon->pixmap->scale(scale_size, scale_size); + } - // restore clip mask - XSetClipMask(disp, gc, None); + if (m_icon->pixmap->pixmap().drawable() != 0) { + GC gc = theme.frameTextGC().gc(); + int icon_x = x + theme.bevelWidth(); + int icon_y = y + theme.bevelWidth(); + // enable clip mask + XSetClipMask(disp, gc, m_icon->pixmap->mask().drawable()); + XSetClipOrigin(disp, gc, icon_x, icon_y); + + draw.copyArea(m_icon->pixmap->pixmap().drawable(), + gc, + 0, 0, + icon_x, icon_y, + m_icon->pixmap->width(), m_icon->pixmap->height()); + + // restore clip mask + XSetClipMask(disp, gc, None); + } } - } if (label().empty()) return; - const GContext &tgc = - (highlight ? theme.hiliteTextGC() : - (isEnabled() ? theme.frameTextGC() : theme.disableTextGC() ) ); - // - // Text - // - int text_y = y, text_x = x; - - int text_w = theme.frameFont().textWidth(label().c_str(), label().size()); - - int height_offset = theme.itemHeight() - (theme.frameFont().height() + 2*theme.bevelWidth()); - text_y = y + theme.bevelWidth() + theme.frameFont().ascent() + height_offset/2; ///2 + height/2; - - switch(theme.frameFontJustify()) { - case FbTk::LEFT: - text_x = x + theme.bevelWidth() + height + 1; - break; + // text is background + if (draw_background) { + const GContext &tgc = + (highlight ? theme.hiliteTextGC() : + (isEnabled() ? theme.frameTextGC() : theme.disableTextGC() ) ); + // + // Text + // + int text_y = y, text_x = x; + + int text_w = theme.frameFont().textWidth(label().c_str(), label().size()); + + int height_offset = theme.itemHeight() - (theme.frameFont().height() + 2*theme.bevelWidth()); + text_y = y + theme.bevelWidth() + theme.frameFont().ascent() + height_offset/2; + + switch(theme.frameFontJustify()) { + case FbTk::LEFT: + text_x = x + theme.bevelWidth() + height + 1; + break; + + case FbTk::RIGHT: + text_x = x + width - (height + theme.bevelWidth() + text_w); + break; + default: //center + text_x = x + ((width + 1 - text_w) / 2); + break; + } - case FbTk::RIGHT: - text_x = x + width - (height + theme.bevelWidth() + text_w); - break; - default: //center - text_x = x + ((width + 1 - text_w) / 2); - break; + theme.frameFont().drawText(draw, // drawable + theme.screenNum(), + tgc.gc(), + m_label.c_str(), m_label.size(), // text string and lenght + text_x, text_y); // position } - theme.frameFont().drawText(draw, // drawable - theme.screenNum(), - tgc.gc(), - m_label.c_str(), m_label.size(), // text string and lenght - text_x, text_y); // position - - GC gc = - ((highlight || isSelected()) ? theme.hiliteTextGC().gc() : - theme.frameTextGC().gc()); + GC gc = (highlight) ? theme.hiliteTextGC().gc() : + theme.frameTextGC().gc(); + int sel_x = x; + int sel_y = y; + unsigned int item_pm_height = theme.itemHeight(); - int sel_x = x + height/4; + if (theme.bulletPos() == FbTk::RIGHT) + sel_x += width - height - theme.bevelWidth(); + // selected pixmap is foreground + if (draw_foreground && isToggleItem()) { - if (theme.bulletPos() == FbTk::RIGHT) - sel_x += width - height - 2*theme.bevelWidth(); + // + // ToggleItem + // + const PixmapWithMask *pm = 0; - // - // ToggleItem - // - if (isToggleItem() && theme.unselectedPixmap().pixmap().drawable() != 0) { - XSetClipMask(disp, gc, theme.unselectedPixmap().mask().drawable()); - XSetClipOrigin(disp, gc, sel_x, y); - // copy bullet pixmap to drawable - draw.copyArea(theme.unselectedPixmap().pixmap().drawable(), - gc, - 0, 0, - sel_x, y, - theme.unselectedPixmap().width(), - theme.unselectedPixmap().height()); - // disable clip mask - XSetClipMask(disp, gc, None); + if (isSelected()) { + if (highlight && theme.highlightSelectedPixmap().pixmap().drawable() != 0) + pm = &theme.highlightSelectedPixmap(); + else + pm = &theme.selectedPixmap(); + } else { + if (highlight && theme.highlightUnselectedPixmap().pixmap().drawable() != 0) + pm = &theme.highlightUnselectedPixmap(); + else + pm = &theme.unselectedPixmap(); + } + if (pm != 0 && pm->pixmap().drawable() != 0) { + unsigned int selw = pm->width(); + unsigned int selh = pm->height(); + int offset_x = 0; + int offset_y = 0; + if (selw < item_pm_height) + offset_x += (item_pm_height - selw) / 2; + if (selh < item_pm_height) + offset_y += (item_pm_height - selh) / 2; + + XSetClipMask(disp, gc, pm->mask().drawable()); + XSetClipOrigin(disp, gc, sel_x+offset_x, sel_y+offset_y); + // copy bullet pixmap to drawable + draw.copyArea(pm->pixmap().drawable(), + gc, + 0, 0, + sel_x+offset_x, sel_y+offset_y, + selw, + selh); + // disable clip mask + XSetClipMask(disp, gc, None); + } else if (isSelected()) { + draw.fillRectangle(theme.hiliteGC().gc(), + sel_x+item_pm_height/4, sel_y+item_pm_height/4, item_pm_height/2, item_pm_height/2); + } } // - // Submenu + // Submenu (background) // - if (submenu()) { - if (theme.bulletPixmap().pixmap().drawable() != 0) { - // enable clip mask - XSetClipMask(disp, gc, theme.bulletPixmap().mask().drawable()); - XSetClipOrigin(disp, gc, sel_x, y); - // copy bullet pixmap to frame - draw.copyArea(theme.bulletPixmap().pixmap().drawable(), + if (draw_background && submenu()) { + + const PixmapWithMask *pm = 0; + + if (highlight && theme.highlightBulletPixmap().pixmap().drawable() != 0) + pm = &theme.highlightBulletPixmap(); + else + pm = &theme.bulletPixmap(); + + if (pm && pm->pixmap().drawable() != 0) { + unsigned int selw = pm->width(); + unsigned int selh = pm->height(); + + int offset_x = 0; + int offset_y = 0; + if (selw < item_pm_height) + offset_x += (item_pm_height - selw) / 2; + if (selh < item_pm_height) + offset_y += (item_pm_height - selh) / 2; + + XSetClipMask(disp, gc, pm->mask().drawable()); + XSetClipOrigin(disp, gc, sel_x+offset_x, sel_y+offset_y); + // copy bullet pixmap to drawable + draw.copyArea(pm->pixmap().drawable(), gc, 0, 0, - sel_x, y, - theme.bulletPixmap().width(), - theme.bulletPixmap().height()); + sel_x+offset_x, sel_y+offset_y, + selw, + selh); // disable clip mask XSetClipMask(disp, gc, None); + } else { - unsigned int half_w = height / 2, quarter_w = height / 4; - int sel_y = y + height/4; + unsigned int half_w = item_pm_height / 2, quarter_w = item_pm_height / 4; switch (theme.bullet()) { case MenuTheme::SQUARE: - draw.drawRectangle(gc, sel_x, sel_y, half_w, half_w); + draw.drawRectangle(gc, sel_x+quarter_w, y+quarter_w, half_w, half_w); break; case MenuTheme::TRIANGLE: XPoint tri[3]; if (theme.bulletPos() == FbTk::RIGHT) { - tri[0].x = sel_x + quarter_w - 2; - tri[0].y = sel_y + quarter_w - 2; + tri[0].x = sel_x + half_w - 2; + tri[0].y = sel_y + half_w - 2; tri[1].x = 4; tri[1].y = 2; tri[2].x = -4; tri[2].y = 2; - } else { - tri[0].x = sel_x + quarter_w - 2; - tri[0].y = y + half_w; + } else { // point the other way + tri[0].x = sel_x + half_w - 2; + tri[0].y = sel_y + half_w; tri[1].x = 4; tri[1].y = 2; tri[2].x = 0; @@ -188,8 +240,8 @@ void MenuItem::draw(FbDrawable &draw, case MenuTheme::DIAMOND: XPoint dia[4]; - dia[0].x = sel_x + quarter_w - 3; - dia[0].y = y + half_w; + dia[0].x = sel_x + half_w - 3; + dia[0].y = sel_y + half_w; dia[1].x = 3; dia[1].y = -3; dia[2].x = 3; @@ -225,7 +277,7 @@ void MenuItem::setIcon(const std::string &filename, int screen_num) { } unsigned int MenuItem::height(const MenuTheme &theme) const { - return std::max(theme.frameFont().height() + theme.bevelWidth(), theme.itemHeight()); + return std::max(theme.frameFont().height() + 2*theme.bevelWidth(), theme.itemHeight()); } unsigned int MenuItem::width(const MenuTheme &theme) const { @@ -233,7 +285,6 @@ unsigned int MenuItem::width(const MenuTheme &theme) const { const unsigned int icon_width = height(theme); const unsigned int normal = theme.frameFont().textWidth(label().c_str(), label().size()) + 2 * (theme.bevelWidth() + icon_width); - return m_icon.get() == 0 ? normal : normal + icon_width; } diff --git a/src/FbTk/MenuItem.hh b/src/FbTk/MenuItem.hh index fe2800c..20da8f7 100644 --- a/src/FbTk/MenuItem.hh +++ b/src/FbTk/MenuItem.hh @@ -96,6 +96,8 @@ public: virtual void draw(FbDrawable &drawable, const MenuTheme &theme, bool highlight, + // "foreground" is the transient bits - more likely to change + bool draw_foreground, bool draw_background, int x, int y, unsigned int width, unsigned int height) const; virtual void updateTheme(const MenuTheme &theme); diff --git a/src/FbTk/MenuTheme.cc b/src/FbTk/MenuTheme.cc index bf4cfc6..1e02f63 100644 --- a/src/FbTk/MenuTheme.cc +++ b/src/FbTk/MenuTheme.cc @@ -61,6 +61,9 @@ MenuTheme::MenuTheme(int screen_num): m_bullet_pixmap(*this, "menu.submenu.pixmap", "Menu.Submenu.Pixmap"), m_selected_pixmap(*this, "menu.selected.pixmap", "Menu.Selected.Pixmap"), m_unselected_pixmap(*this, "menu.unselected.pixmap", "Menu.Unselected.Pixmap"), + m_hl_bullet_pixmap(*this, "menu.hilite.submenu.pixmap", "Menu.Hilite.Submenu.Pixmap"), + m_hl_selected_pixmap(*this, "menu.hilite.selected.pixmap", "Menu.Hilite.Selected.Pixmap"), + m_hl_unselected_pixmap(*this, "menu.hilite.unselected.pixmap", "Menu.Hilite.Unselected.Pixmap"), m_display(FbTk::App::instance()->display()), t_text_gc(RootWindow(m_display, screen_num)), f_text_gc(RootWindow(m_display, screen_num)), @@ -109,12 +112,18 @@ void MenuTheme::reconfigTheme() { m_real_title_height = std::max(*m_title_height, titleFont().height() + 2*bevelWidth()); - m_real_item_height = m_real_item_height == 0 ? 1 : m_real_item_height; - m_real_title_height = m_real_title_height == 0 ? 1 : m_real_title_height; + unsigned int minsize = 2*bevelWidth()+1; + m_real_item_height = m_real_item_height < minsize ? minsize: m_real_item_height; + m_real_title_height = m_real_title_height == minsize ? minsize : m_real_title_height; + unsigned int item_pm_height = itemHeight(); + + m_bullet_pixmap->scale(item_pm_height, item_pm_height); + m_selected_pixmap->scale(item_pm_height, item_pm_height); + m_unselected_pixmap->scale(item_pm_height, item_pm_height); - m_bullet_pixmap->scale(itemHeight(), itemHeight()); - m_selected_pixmap->scale(itemHeight(), itemHeight()); - m_unselected_pixmap->scale(itemHeight(), itemHeight()); + m_hl_bullet_pixmap->scale(item_pm_height, item_pm_height); + m_hl_selected_pixmap->scale(item_pm_height, item_pm_height); + m_hl_unselected_pixmap->scale(item_pm_height, item_pm_height); t_text_gc.setForeground(*t_text); f_text_gc.setForeground(*f_text); diff --git a/src/FbTk/MenuTheme.hh b/src/FbTk/MenuTheme.hh index ddc8d8f..8fc4d1c 100644 --- a/src/FbTk/MenuTheme.hh +++ b/src/FbTk/MenuTheme.hh @@ -71,6 +71,10 @@ public: inline const FbTk::PixmapWithMask &bulletPixmap() const { return *m_bullet_pixmap; } inline const FbTk::PixmapWithMask &selectedPixmap() const { return *m_selected_pixmap; } inline const FbTk::PixmapWithMask &unselectedPixmap() const { return *m_unselected_pixmap; } + + inline const FbTk::PixmapWithMask &highlightBulletPixmap() const { return *m_hl_bullet_pixmap; } + inline const FbTk::PixmapWithMask &highlightSelectedPixmap() const { return *m_hl_selected_pixmap; } + inline const FbTk::PixmapWithMask &highlightUnselectedPixmap() const { return *m_hl_unselected_pixmap; } /** @name fonts */ @@ -121,6 +125,10 @@ public: inline const FbTk::Color &borderColor() const { return *m_border_color; } + // special override + inline void setSelectedPixmap(Pixmap pm) { m_selected_pixmap->pixmap() = pm; } + inline void setHighlightSelectedPixmap(Pixmap pm) { m_hl_selected_pixmap->pixmap() = pm; } + private: FbTk::ThemeItem t_text, f_text, h_text, d_text; FbTk::ThemeItem title, frame, hilite; @@ -133,6 +141,7 @@ private: FbTk::ThemeItem m_bevel_width; FbTk::ThemeItem m_border_color; FbTk::ThemeItem m_bullet_pixmap, m_selected_pixmap, m_unselected_pixmap; + FbTk::ThemeItem m_hl_bullet_pixmap, m_hl_selected_pixmap, m_hl_unselected_pixmap; Display *m_display; FbTk::GContext t_text_gc, f_text_gc, h_text_gc, d_text_gc, hilite_gc; diff --git a/src/FbTk/TextButton.cc b/src/FbTk/TextButton.cc index fdbdc78..9a16c2c 100644 --- a/src/FbTk/TextButton.cc +++ b/src/FbTk/TextButton.cc @@ -24,8 +24,6 @@ #include "TextButton.hh" #include "Font.hh" #include "GContext.hh" -#include -using namespace std; namespace FbTk { @@ -38,6 +36,7 @@ TextButton::TextButton(const FbTk::FbWindow &parent, m_justify(FbTk::LEFT), m_bevel(1), m_left_padding(0), m_right_padding(0) { + setRenderer(*this); } @@ -62,7 +61,11 @@ void TextButton::setJustify(FbTk::Justify just) { } void TextButton::setText(const std::string &text) { - m_text = text; + if (m_text != text) { + m_text = text; + parentMoved(); + clear(); + } } void TextButton::setFont(const FbTk::Font &font) { @@ -102,30 +105,37 @@ void TextButton::clearArea(int x, int y, unsigned int width, unsigned int height, bool exposure) { Button::clearArea(x, y, width, height, exposure); - // TODO: do we need to check if the text overlaps the clearing area - // and if so, then clear a rectangle that encompases all the text plus the - // requested area? - drawText(); + if (backgroundPixmap() == ParentRelative) + drawText(0, 0, this); } unsigned int TextButton::textWidth() const { return font().textWidth(text().c_str(), text().size()); } -void TextButton::drawText(int x_offset, int y_offset) { +void TextButton::renderForeground(FbWindow &win, FbDrawable &drawable) { + // (win should always be *this, no need to check) + drawText(0, 0, &drawable); +} + +void TextButton::drawText(int x_offset, int y_offset, FbDrawable *drawable) { unsigned int textlen = text().size(); // do text alignment + int align_x = FbTk::doAlignment(width() - x_offset - m_left_padding - m_right_padding, bevel(), justify(), font(), text().c_str(), text().size(), - textlen); // return new text len + textlen); // return new text lne // center text by default int center_pos = height()/2 + font().ascent()/2 - 1; - font().drawText(*this, + if (drawable == 0) + drawable = this; + + font().drawText(*drawable, screenNumber(), gc(), // graphic context text().c_str(), textlen, // string and string size diff --git a/src/FbTk/TextButton.hh b/src/FbTk/TextButton.hh index 3a9407f..f5738b5 100644 --- a/src/FbTk/TextButton.hh +++ b/src/FbTk/TextButton.hh @@ -35,7 +35,7 @@ namespace FbTk { class Font; /// Displays a text on a button -class TextButton: public FbTk::Button { +class TextButton: public FbTk::Button, FbTk::FbWindowRenderer { public: TextButton(const FbTk::FbWindow &parent, const FbTk::Font &font, const std::string &text); @@ -61,6 +61,8 @@ public: void exposeEvent(XExposeEvent &event); + void renderForeground(FbDrawable &drawable); + inline FbTk::Justify justify() const { return m_justify; } inline const std::string &text() const { return m_text; } inline const FbTk::Font &font() const { return *m_font; } @@ -69,8 +71,10 @@ public: unsigned int leftPadding() const { return m_left_padding; } unsigned int rightPadding() const { return m_right_padding; } + void renderForeground(FbWindow &win, FbDrawable &drawable); + protected: - virtual void drawText(int x_offset = 0, int y_offset = 0); + virtual void drawText(int x_offset, int y_offset, FbDrawable *drawable_override); private: const FbTk::Font *m_font; diff --git a/src/FbWinFrame.cc b/src/FbWinFrame.cc index ba98740..a1745ef 100644 --- a/src/FbWinFrame.cc +++ b/src/FbWinFrame.cc @@ -377,7 +377,7 @@ void FbWinFrame::moveLabelButtonLeft(const FbTk::TextButton &btn) { // insert on the new place m_labelbuttons.insert(new_pos, item); // update titlebar - redrawTitle(); + redrawTitlebar(); } void FbWinFrame::moveLabelButtonRight(const FbTk::TextButton &btn) { @@ -395,7 +395,7 @@ void FbWinFrame::moveLabelButtonRight(const FbTk::TextButton &btn) { // insert on the new place m_labelbuttons.insert(new_pos, item); // update titlebar - redrawTitle(); + redrawTitlebar(); } void FbWinFrame::moveLabelButtonTo(FbTk::TextButton &btn, int x, int y) { @@ -464,7 +464,7 @@ void FbWinFrame::moveLabelButtonLeftOf(const FbTk::TextButton &btn, const FbTk:: //insert on the new place m_labelbuttons.insert(new_pos, item); //update titlebar - redrawTitle(); + redrawTitlebar(); } void FbWinFrame::moveLabelButtonRightOf(const FbTk::TextButton &btn, const FbTk::TextButton &dest) { @@ -494,7 +494,7 @@ void FbWinFrame::moveLabelButtonRightOf(const FbTk::TextButton &btn, const FbTk: else m_labelbuttons.insert(new_pos, item); //update titlebar - redrawTitle(); + redrawTitlebar(); } void FbWinFrame::setLabelButtonFocus(FbTk::TextButton &btn) { @@ -893,8 +893,8 @@ unsigned int FbWinFrame::buttonHeight() const { /** aligns and redraws title */ -void FbWinFrame::redrawTitle() { - if (m_labelbuttons.empty()) +void FbWinFrame::redrawTitlebar() { + if (!m_use_titlebar || m_labelbuttons.empty()) return; int focus_button_min_percent = Fluxbox::instance()->getFocusedTabMinWidth(); @@ -965,14 +965,6 @@ void FbWinFrame::redrawTitle() { } } -void FbWinFrame::redrawTitlebar() { - if (!m_use_titlebar) - return; - - redrawTitle(); - - } - /** Align buttons with title text window */ @@ -998,7 +990,6 @@ void FbWinFrame::reconfigureTitlebar() { unsigned int button_size = buttonHeight(); m_button_size = button_size; for (size_t i=0; i < m_buttons_left.size(); i++, next_x += button_size + m_bevel) { - //cerr<<"m_buttons_left["<moveResize(next_x="<moveResize(next_x, m_bevel, button_size, button_size); } @@ -1024,7 +1015,6 @@ void FbWinFrame::reconfigureTitlebar() { button_size, button_size); } -// renderTitlebar(); // gets done outside m_titlebar.raise(); // always on top } diff --git a/src/FbWinFrame.hh b/src/FbWinFrame.hh index 7582f2c..9bff974 100644 --- a/src/FbWinFrame.hh +++ b/src/FbWinFrame.hh @@ -193,7 +193,6 @@ public: private: void redrawTitlebar(); - void redrawTitle(); /// reposition titlebar items void reconfigureTitlebar(); diff --git a/src/IconButton.cc b/src/IconButton.cc index 052035e..4258f13 100644 --- a/src/IconButton.cc +++ b/src/IconButton.cc @@ -288,12 +288,12 @@ void IconButton::setupWindow() { FbTk::TextButton::clear(); } -void IconButton::drawText(int x, int y) { +void IconButton::drawText(int x, int y, FbTk::FbDrawable *drawable) { // offset text if (m_icon_pixmap.drawable() != 0) - FbTk::TextButton::drawText(m_icon_window.x() + m_icon_window.width() + 1, y); + FbTk::TextButton::drawText(m_icon_window.x() + m_icon_window.width() + 1, y, drawable); else - FbTk::TextButton::drawText(1, y); + FbTk::TextButton::drawText(1, y, drawable); } diff --git a/src/IconButton.hh b/src/IconButton.hh index e5ff171..a4ccd8e 100644 --- a/src/IconButton.hh +++ b/src/IconButton.hh @@ -54,7 +54,7 @@ public: const FluxboxWindow &win() const { return m_win; } protected: - void drawText(int x = 0, int y = 0); + void drawText(int x, int y, FbTk::FbDrawable *drawable_override); private: void setupWindow(); diff --git a/src/ToggleMenu.hh b/src/ToggleMenu.hh index b2d9e54..f506df8 100644 --- a/src/ToggleMenu.hh +++ b/src/ToggleMenu.hh @@ -48,12 +48,11 @@ public: // so that the last toggled item gets redrawn as // not toggled. if (ev.window == frameWindow()) { - frameWindow().clear(); - for (size_t i = 0; i < numberOfItems(); ++i) { - drawItem(i, // index - false); // clear - - } + // force full foreground update (by setting bg to same thing) + frameWindow().parentMoved(); +// for (size_t i = 0; i < numberOfItems(); ++i) { +// clearItem(i); +// } } } diff --git a/src/Window.cc b/src/Window.cc index c2b3a62..e92c989 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -1207,11 +1207,8 @@ void FluxboxWindow::updateTitleFromClient(WinClient &client) { client.updateTitle(); // compare old title with new and see if we need to update // graphics - if (m_labelbuttons[&client]->text() != client.title()) { + if (m_labelbuttons[&client]->text() != client.title()) m_labelbuttons[&client]->setText(client.title()); - m_labelbuttons[&client]->clear(); // redraw text - //m_labelbuttons[&client]->updateTransparent(); - } } /// update icon title from client @@ -2346,7 +2343,9 @@ void FluxboxWindow::handleEvent(XEvent &event) { //break; case PropertyNotify: { #ifdef DEBUG - cerr<<"PropertyNotify("<