From: Dana Jansens Date: Sat, 8 Feb 2003 07:33:48 +0000 (+0000) Subject: Brand spankin new widgets for otk (Label and Button). X-Git-Url: https://git.brokenzipper.com/gitweb?a=commitdiff_plain;h=99cd843fc6dc7a7f55b6c90fd1162f233853aad2;p=chaz%2Fopenbox Brand spankin new widgets for otk (Label and Button). Add a new Size class. Rect, Point, and Size are immutable classes. Size uses *UNSIGNED* ints. This is causing me headaches * a bajillion right now, so we'll see about that. --- diff --git a/otk/Makefile.am b/otk/Makefile.am index 504319a7..0c463b5c 100644 --- a/otk/Makefile.am +++ b/otk/Makefile.am @@ -4,18 +4,17 @@ pkgconfigdir = $(libdir)/pkgconfig CPPFLAGS=$(XFT_CFLAGS) @CPPFLAGS@ -DBUTTONSDIR=\"$(buttonsdir)\" -#noinst_LIBRARIES=libotk.a lib_LTLIBRARIES=libotk.la -libotk_la_SOURCES=rendercontrol.cc truerendercontrol.cc surface.cc \ +libotk_la_SOURCES=rendercontrol.cc truerendercontrol.cc surface.cc util.cc \ renderstyle.cc rendercolor.cc pseudorendercontrol.cc \ - display.cc font.cc \ - property.cc rect.cc screeninfo.cc \ - timer.cc \ - util.cc widget.cc focuswidget.cc \ - button.cc eventhandler.cc eventdispatcher.cc ustring.cc \ - label.cc focuslabel.cc application.cc appwidget.cc -includeotk_HEADERS=application.hh appwidget.hh assassin.hh button.hh \ + display.cc font.cc screeninfo.cc property.cc timer.cc \ + eventdispatcher.cc eventhandler.cc ustring.cc \ + widget.cc application.cc label.cc appwidget.cc button.cc + +#focuswidget.cc focuslabel.cc + +includeotk_HEADERS=application.hh appwidget.hh assassin.hh button.hh size.hh \ display.hh eventdispatcher.hh eventhandler.hh \ focuslabel.hh focuswidget.hh font.hh label.hh otk.hh \ point.hh property.hh pseudorendercontrol.hh rect.hh \ diff --git a/otk/application.cc b/otk/application.cc index efe86d15..ffa33ab8 100644 --- a/otk/application.cc +++ b/otk/application.cc @@ -6,10 +6,10 @@ #include "application.hh" #include "eventhandler.hh" -#include "widget.hh" #include "timer.hh" #include "property.hh" #include "rendercolor.hh" +#include "renderstyle.hh" extern "C" { #ifdef HAVE_STDLIB_H @@ -30,17 +30,19 @@ Application::Application(int argc, char **argv) (void)argc; (void)argv; + _screen = DefaultScreen(*_display); + Timer::initialize(); RenderColor::initialize(); + RenderStyle::initialize(); Property::initialize(); - _style = new RenderStyle(DefaultScreen(*_display), ""); // XXX: get a path! loadStyle(); } Application::~Application() { - delete _style; + RenderStyle::destroy(); RenderColor::destroy(); Timer::destroy(); } diff --git a/otk/application.hh b/otk/application.hh index 6f1cebc6..848b7985 100644 --- a/otk/application.hh +++ b/otk/application.hh @@ -4,7 +4,6 @@ #include "eventdispatcher.hh" #include "display.hh" -#include "renderstyle.hh" namespace otk { @@ -17,20 +16,19 @@ public: Application(int argc, char **argv); virtual ~Application(); + inline int screen() const { return _screen; } + virtual void run(void); // more bummy cool functionality void setDockable(bool dockable) { _dockable = dockable; } inline bool isDockable(void) const { return _dockable; } - inline RenderStyle *getStyle(void) const { return _style; } - // more accessors - private: void loadStyle(void); Display _display; - RenderStyle *_style; + int _screen; bool _dockable; int _appwidget_count; diff --git a/otk/appwidget.cc b/otk/appwidget.cc index afb86c0b..5c963f7b 100644 --- a/otk/appwidget.cc +++ b/otk/appwidget.cc @@ -7,6 +7,7 @@ #include "appwidget.hh" #include "application.hh" #include "property.hh" +#include "renderstyle.hh" extern "C" { #include @@ -14,9 +15,8 @@ extern "C" { namespace otk { -AppWidget::AppWidget(Application *app, Direction direction, - Cursor cursor, int bevel_width) - : Widget(app, app->getStyle(), direction, cursor, bevel_width), +AppWidget::AppWidget(Application *app, Direction direction, int bevel) + : Widget(app->screen(), app, direction, bevel), _application(app) { assert(app); @@ -26,29 +26,28 @@ AppWidget::AppWidget(Application *app, Direction direction, protocols[0] = Property::atoms.wm_protocols; protocols[1] = Property::atoms.wm_delete_window; XSetWMProtocols(**display, window(), protocols, 2); - - setStyle(_style); } AppWidget::~AppWidget() { } -void AppWidget::setStyle(RenderStyle *style) +void AppWidget::render() { - Widget::setStyle(style); - - setTexture(style->titlebarUnfocusBackground()); + XSetWindowBackground(**display, window(), + RenderStyle::style(screen())-> + titlebarUnfocusBackground()->color().pixel()); + Widget::render(); } -void AppWidget::show(void) +void AppWidget::show() { Widget::show(true); _application->_appwidget_count++; } -void AppWidget::hide(void) +void AppWidget::hide() { Widget::hide(); diff --git a/otk/appwidget.hh b/otk/appwidget.hh index b305dbae..b2ea44aa 100644 --- a/otk/appwidget.hh +++ b/otk/appwidget.hh @@ -11,14 +11,13 @@ class Application; class AppWidget : public Widget { public: - AppWidget(Application *app, Direction direction = Horizontal, - Cursor cursor = 0, int bevel_width = 1); + AppWidget(Application *app, Direction direction = Horizontal, int bevel = 0); virtual ~AppWidget(); - virtual void setStyle(RenderStyle *style); - - virtual void show(void); - virtual void hide(void); + virtual void render(); + + virtual void show(); + virtual void hide(); virtual void clientMessageHandler(const XClientMessageEvent &e); diff --git a/otk/button.cc b/otk/button.cc index c70511fc..8d63ed0c 100644 --- a/otk/button.cc +++ b/otk/button.cc @@ -9,73 +9,73 @@ namespace otk { Button::Button(Widget *parent) - : FocusLabel(parent), _pressed(false), _pressed_focus_tx(0), - _pressed_unfocus_tx(0), _unpr_focus_tx(0), _unpr_unfocus_tx(0) + : Label(parent), _default(false), _pressed(false) { - setStyle(_style); + setHorizontalJustify(RenderStyle::CenterJustify); + setVerticalJustify(RenderStyle::CenterJustify); + styleChanged(*RenderStyle::style(screen())); } Button::~Button() { } - -void Button::setStyle(RenderStyle *style) -{ - FocusLabel::setStyle(style); - - setTexture(style->buttonUnpressFocusBackground()); - setUnfocusTexture(style->buttonUnpressUnfocusBackground()); - _pressed_focus_tx = style->buttonPressFocusBackground(); - _pressed_unfocus_tx = style->buttonPressUnfocusBackground(); -} - - void Button::press(unsigned int mouse_button) { if (_pressed) return; - if (_pressed_unfocus_tx) - FocusWidget::setUnfocusTexture(_pressed_unfocus_tx); - if (_pressed_focus_tx) - FocusWidget::setTexture(_pressed_focus_tx); _pressed = true; _mouse_button = mouse_button; + + styleChanged(*RenderStyle::style(screen())); + refresh(); } void Button::release(unsigned int mouse_button) { - if (_mouse_button != mouse_button) return; // wrong button + if (!_pressed || _mouse_button != mouse_button) return; // wrong button - FocusWidget::setUnfocusTexture(_unpr_unfocus_tx); - FocusWidget::setTexture(_unpr_focus_tx); _pressed = false; + + styleChanged(*RenderStyle::style(screen())); + refresh(); } -void Button::setTexture(RenderTexture *texture) +void Button::buttonPressHandler(const XButtonEvent &e) { - FocusWidget::setTexture(texture); - _unpr_focus_tx = texture; + Widget::buttonPressHandler(e); + press(e.button); } -void Button::setUnfocusTexture(RenderTexture *texture) +void Button::buttonReleaseHandler(const XButtonEvent &e) { - FocusWidget::setUnfocusTexture(texture); - _unpr_unfocus_tx = texture; + Widget::buttonReleaseHandler(e); + release(e.button); } -void Button::buttonPressHandler(const XButtonEvent &e) +void Button::setDefault(bool d) { - press(e.button); - update(); - FocusWidget::buttonPressHandler(e); + _default = d; + styleChanged(*RenderStyle::style(screen())); + refresh(); } -void Button::buttonReleaseHandler(const XButtonEvent &e) +void Button::styleChanged(const RenderStyle &style) { - release(e.button); - update(); - FocusWidget::buttonReleaseHandler(e); + if (_default) { + if (_pressed) + _texture = style.buttonPressFocusBackground(); + else + _texture = style.buttonUnpressFocusBackground(); + _forecolor = style.buttonFocusColor(); + } else { + if (_pressed) + _texture = style.buttonPressUnfocusBackground(); + else + _texture = style.buttonUnpressUnfocusBackground(); + _forecolor = style.buttonUnfocusColor(); + } + Widget::styleChanged(style); } } diff --git a/otk/button.hh b/otk/button.hh index 1483677e..53d08a86 100644 --- a/otk/button.hh +++ b/otk/button.hh @@ -2,49 +2,33 @@ #ifndef __button_hh #define __button_hh -#include "focuslabel.hh" +#include "label.hh" namespace otk { -class Button : public FocusLabel { +class Button : public Label { public: - Button(Widget *parent); - ~Button(); - - inline const RenderTexture *getPressedFocusTexture(void) const - { return _pressed_focus_tx; } - void setPressedFocusTexture(RenderTexture *texture) - { _pressed_focus_tx = texture; } + virtual ~Button(); - inline const RenderTexture *getPressedUnfocusTexture(void) const - { return _pressed_unfocus_tx; } - void setPressedUnfocusTexture(RenderTexture *texture) - { _pressed_unfocus_tx = texture; } - - void setTexture(RenderTexture *texture); - void setUnfocusTexture(RenderTexture *texture); + virtual inline bool isDefault() const { return _default; } + virtual void setDefault(bool d); + + virtual inline bool isPressed() const { return _pressed; } - inline bool isPressed(void) const { return _pressed; } - void press(unsigned int mouse_button); - void release(unsigned int mouse_button); + virtual void press(unsigned int mouse_button); + virtual void release(unsigned int mouse_button); - void buttonPressHandler(const XButtonEvent &e); - void buttonReleaseHandler(const XButtonEvent &e); + virtual void buttonPressHandler(const XButtonEvent &e); + virtual void buttonReleaseHandler(const XButtonEvent &e); - virtual void setStyle(RenderStyle *style); - + virtual void styleChanged(const RenderStyle &style); + private: - + bool _default; bool _pressed; unsigned int _mouse_button; - - RenderTexture *_pressed_focus_tx; - RenderTexture *_pressed_unfocus_tx; - - RenderTexture *_unpr_focus_tx; - RenderTexture *_unpr_unfocus_tx; }; } diff --git a/otk/focuslabel.cc b/otk/focuslabel.cc deleted file mode 100644 index 846d035e..00000000 --- a/otk/focuslabel.cc +++ /dev/null @@ -1,110 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif - -#include "focuslabel.hh" -#include "display.hh" -#include "screeninfo.hh" - -namespace otk { - -FocusLabel::FocusLabel(Widget *parent) - : FocusWidget(parent), _text("") -{ - setStyle(_style); -} - -FocusLabel::~FocusLabel() -{ -} - - -void FocusLabel::setStyle(RenderStyle *style) -{ - FocusWidget::setStyle(style); - - setTexture(style->labelFocusBackground()); - setUnfocusTexture(style->labelUnfocusBackground()); -} - -void FocusLabel::fitString(const std::string &str) -{ - const Font *ft = style()->labelFont(); - fitSize(ft->measureString(str), ft->height()); -} - -void FocusLabel::fitSize(int w, int h) -{ - unsigned int sidemargin = _bevel_width * 2; - resize(w + sidemargin * 2, h + _bevel_width * 2); -} - -void FocusLabel::update() -{ - if (_dirty) { - int w = _rect.width(), h = _rect.height(); - const Font *ft = style()->labelFont(); - unsigned int sidemargin = _bevel_width * 2; - if (!_fixed_width) - w = ft->measureString(_text) + sidemargin * 2; - if (!_fixed_height) - h = ft->height(); - - // enforce a minimum size - if (w > _rect.width()) { - if (h > _rect.height()) - internalResize(w, h); - else - internalResize(w, _rect.height()); - } else if (h > _rect.height()) - internalResize(_rect.width(), h); - } - FocusWidget::update(); -} - - -void FocusLabel::renderForeground() -{ - FocusWidget::renderForeground(); - - const Font *ft = style()->labelFont(); - RenderColor *text_color = (isFocused() ? style()->textFocusColor() - : style()->textUnfocusColor()); - unsigned int sidemargin = _bevel_width * 2; - - ustring t = _text; // the actual text to draw - int x = sidemargin; // x coord for the text - - // find a string that will fit inside the area for text - int max_length = width() - sidemargin * 2; - if (max_length <= 0) { - t = ""; // can't fit anything - } else { - size_t text_len = t.size(); - int length; - - do { - t.resize(text_len); - length = ft->measureString(t); - } while (length > max_length && text_len-- > 0); - - // justify the text - switch (style()->labelTextJustify()) { - case RenderStyle::RightJustify: - x += max_length - length; - break; - case RenderStyle::CenterJustify: - x += (max_length - length) / 2; - break; - case RenderStyle::LeftJustify: - break; - } - } - - display->renderControl(_screen)-> - drawString(*_surface, *ft, x, _bevel_width, *text_color, t); -} - -} diff --git a/otk/focuslabel.hh b/otk/focuslabel.hh deleted file mode 100644 index c25ab29c..00000000 --- a/otk/focuslabel.hh +++ /dev/null @@ -1,35 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -#ifndef __focuslabel_hh -#define __focuslabel_hh - -#include "focuswidget.hh" - -namespace otk { - -class FocusLabel : public FocusWidget { - -public: - - FocusLabel(Widget *parent); - ~FocusLabel(); - - inline const ustring &getText(void) const { return _text; } - void setText(const ustring &text) { _text = text; _dirty = true; } - - virtual void renderForeground(); - - virtual void update(); - - void fitString(const std::string &str); - void fitSize(int w, int h); - - virtual void setStyle(RenderStyle *style); - -private: - //! Text displayed in the label - ustring _text; -}; - -} - -#endif // __focuslabel_hh diff --git a/otk/focuswidget.cc b/otk/focuswidget.cc deleted file mode 100644 index b8e18d78..00000000 --- a/otk/focuswidget.cc +++ /dev/null @@ -1,66 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif - -#include "focuswidget.hh" - -namespace otk { - -FocusWidget::FocusWidget(Widget *parent, Direction direction) - : Widget(parent, direction), _unfocus_texture(0), _unfocus_bcolor(0) -{ - _focused = true; - _focus_texture = parent->texture(); - _focus_bcolor = parent->borderColor(); -} - -FocusWidget::~FocusWidget() -{ -} - - -void FocusWidget::focus(void) -{ - if (_focused) - return; - - Widget::focus(); - - if (_focus_bcolor) - Widget::setBorderColor(_focus_bcolor); - - Widget::setTexture(_focus_texture); - update(); -} - -void FocusWidget::unfocus(void) -{ - if (!_focused) - return; - - Widget::unfocus(); - - if (_unfocus_bcolor) - Widget::setBorderColor(_unfocus_bcolor); - - Widget::setTexture(_unfocus_texture); - update(); -} - -void FocusWidget::setTexture(RenderTexture *texture) -{ - Widget::setTexture(texture); - _focus_texture = texture; - if (!_focused) - Widget::setTexture(_unfocus_texture); -} - -void FocusWidget::setBorderColor(const RenderColor *color) -{ - Widget::setBorderColor(color); - _focus_bcolor = color; -} - -} diff --git a/otk/focuswidget.hh b/otk/focuswidget.hh deleted file mode 100644 index 886a2e31..00000000 --- a/otk/focuswidget.hh +++ /dev/null @@ -1,47 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -#ifndef __focuswidget_hh -#define __focuswidget_hh - -#include "widget.hh" -#include "application.hh" - -namespace otk { - -class FocusWidget : public Widget { - -public: - - FocusWidget(Widget *parent, Direction = Horizontal); - virtual ~FocusWidget(); - - virtual void focus(void); - virtual void unfocus(void); - - virtual void setTexture(RenderTexture *texture); - virtual void setBorderColor(const RenderColor *color); - - inline void setUnfocusTexture(RenderTexture *texture) - { _unfocus_texture = texture; } - inline RenderTexture *getUnfocusTexture(void) const - { return _unfocus_texture; } - - inline void setUnfocusBorderColor(const RenderColor *color) - { _unfocus_bcolor = color; } - inline const RenderColor *getUnfocusBorderColor(void) const - { return _unfocus_bcolor; } - - inline bool isFocused(void) const { return _focused; } - inline bool isUnfocused(void) const { return !_focused; } - -private: - - RenderTexture *_unfocus_texture; - RenderTexture *_focus_texture; - - const RenderColor *_unfocus_bcolor; - const RenderColor *_focus_bcolor; -}; - -} - -#endif // __focuswidget_hh diff --git a/otk/label.cc b/otk/label.cc index 16bfd5f4..0c18b5d0 100644 --- a/otk/label.cc +++ b/otk/label.cc @@ -5,100 +5,138 @@ #endif #include "label.hh" +#include "display.hh" +#include "rendercontrol.hh" + +#include namespace otk { Label::Label(Widget *parent) - : Widget(parent), _text("") + : Widget(parent), + _text(""), + _justify_horz(RenderStyle::LeftTopJustify), + _justify_vert(RenderStyle::LeftTopJustify) { - setStyle(_style); + styleChanged(*RenderStyle::style(screen())); } Label::~Label() { } -void Label::setStyle(RenderStyle *style) +void Label::setHorizontalJustify(RenderStyle::Justify j) { - Widget::setStyle(style); + _justify_horz = j; + refresh(); +} - setTexture(style->labelUnfocusBackground()); +void Label::setVerticalJustify(RenderStyle::Justify j) +{ + _justify_vert = j; + refresh(); } -void Label::fitString(const std::string &str) +void Label::setText(const ustring &text) { - const Font *ft = style()->labelFont(); - fitSize(ft->measureString(str), ft->height()); + bool utf = text.utf8(); + std::string s = text.c_str(); // use a normal string, for its functionality + + _parsedtext.clear(); + + // parse it into multiple lines + std::string::size_type p = 0; + while (p != std::string::npos) { + std::string::size_type p2 = s.find('\n', p); + _parsedtext.push_back(s.substr(p, (p2==std::string::npos?p2:p2-p))); + _parsedtext.back().setUtf8(utf); + p = (p2==std::string::npos?p2:p2+1); + } + calcDefaultSizes(); } -void Label::fitSize(int w, int h) +void Label::setFont(const Font *f) { - unsigned int sidemargin = _bevel_width * 2; - resize(w + sidemargin * 2, h + _bevel_width * 2); + _font = f; + calcDefaultSizes(); } -void Label::update() +void Label::calcDefaultSizes() { - if (_dirty) { - int w = _rect.width(), h = _rect.height(); - const Font *ft = style()->labelFont(); - unsigned int sidemargin = _bevel_width * 2; - if (!_fixed_width) - w = ft->measureString(_text) + sidemargin * 2; - if (!_fixed_height) - h = ft->height(); - - // enforce a minimum size - if (w > _rect.width()) { - if (h > _rect.height()) - internalResize(w, h); - else - internalResize(w, _rect.height()); - } else if (h > _rect.height()) - internalResize(_rect.width(), h); + unsigned int longest = 0; + // find the longest line + std::vector::iterator it, end = _parsedtext.end(); + for (it = _parsedtext.begin(); it != end; ++it) { + unsigned int length = _font->measureString(*it); + if (length > longest) longest = length; } - Widget::update(); + setMinSize(Size(longest + borderWidth() * 2 + bevel() * 4, + _parsedtext.size() * _font->height() + borderWidth() * 2 + + bevel() * 2)); } - - -void Label::renderForeground(void) + +void Label::styleChanged(const RenderStyle &style) { - Widget::renderForeground(); - - const Font *ft = style()->labelFont(); - unsigned int sidemargin = _bevel_width * 2; - - ustring t = _text; // the actual text to draw - int x = sidemargin; // x coord for the text + _texture = style.labelFocusBackground(); + _forecolor = style.textFocusColor(); + _font = style.labelFont(); + Widget::styleChanged(style); + calcDefaultSizes(); +} - // find a string that will fit inside the area for text - int max_length = width() - sidemargin * 2; - if (max_length <= 0) { - t = ""; // can't fit anything - } else { - size_t text_len = t.size(); - int length; +void Label::renderForeground(Surface &surface) +{ + const RenderControl *control = display->renderControl(screen()); + unsigned int sidemargin = bevel() * 2; + int y = bevel(); + unsigned int w = area().width() - borderWidth() * 2 - sidemargin * 2; + unsigned int h = area().height() - borderWidth() * 2 - bevel() * 2; + + switch (_justify_vert) { + case RenderStyle::RightBottomJustify: + y += h - (_parsedtext.size() * _font->height()); + if (y < bevel()) y = bevel(); + break; + case RenderStyle::CenterJustify: + y += (h - (_parsedtext.size() * _font->height())) / 2; + if (y < bevel()) y = bevel(); + break; + case RenderStyle::LeftTopJustify: + break; + } + + if (w <= 0) return; // can't fit anything + + std::vector::iterator it, end = _parsedtext.end(); + for (it = _parsedtext.begin(); it != end; ++it, y += _font->height()) { + ustring t = *it; // the actual text to draw + int x = sidemargin; // x coord for the text + + // find a string that will fit inside the area for text + ustring::size_type text_len = t.size(); + unsigned int length; do { t.resize(text_len); - length = ft->measureString(t); - } while (length > max_length && text_len-- > 0); + length = _font->measureString(t); + } while (length > w && text_len-- > 0); + + if (text_len <= 0) continue; // won't fit anything // justify the text - switch (style()->labelTextJustify()) { - case RenderStyle::RightJustify: - x += max_length - length; + switch (_justify_horz) { + case RenderStyle::RightBottomJustify: + x += w - length; break; case RenderStyle::CenterJustify: - x += (max_length - length) / 2; + x += (w - length) / 2; break; - case RenderStyle::LeftJustify: + case RenderStyle::LeftTopJustify: break; } - } - - display->renderControl(_screen)-> - drawString(*_surface, *ft, x, _bevel_width, *style()->textUnfocusColor(), t); + + control->drawString(surface, *_font, x, y, *_forecolor, t); + } } } diff --git a/otk/label.hh b/otk/label.hh index 9c32e544..1b31ae79 100644 --- a/otk/label.hh +++ b/otk/label.hh @@ -3,33 +3,54 @@ #define __label_hh #include "widget.hh" +#include "ustring.hh" +#include "renderstyle.hh" +#include "font.hh" + +#include namespace otk { class Label : public Widget { public: - Label(Widget *parent); - ~Label(); + virtual ~Label(); - inline const ustring &getText(void) const { return _text; } - void setText(const ustring &text) { _text = text; _dirty = true; } + inline const ustring& getText(void) const { return _text; } + void setText(const ustring &text); - virtual void renderForeground(void); + RenderStyle::Justify horizontalJustify() const { return _justify_horz; } + virtual void setHorizontalJustify(RenderStyle::Justify j); + RenderStyle::Justify verticalJustify() const { return _justify_vert; } + virtual void setVerticalJustify(RenderStyle::Justify j); - virtual void update(); + const Font *font() const { return _font; } + virtual void setFont(const Font *f); - void fitString(const std::string &str); - void fitSize(int w, int h); + virtual void calcDefaultSizes(); - virtual void setStyle(RenderStyle *style); + virtual void styleChanged(const RenderStyle &style); + + virtual void renderForeground(Surface &surface); +protected: + //! The color the label will use for rendering its text + RenderColor *_forecolor; + private: //! Text to be displayed in the label ustring _text; + //! Text to be displayed, parsed into its separate lines + std::vector _parsedtext; //! The actual text being shown, may be a subset of _text ustring _drawtext; + //! The font the text will be rendered with + const Font *_font; + //! The horizontal justification used for drawing text + RenderStyle::Justify _justify_horz; + //! The vertical justification used for drawing text + RenderStyle::Justify _justify_vert; //! The drawing offset for the text int _drawx; }; diff --git a/otk/otk.hh b/otk/otk.hh index 9be1ec36..62788cba 100644 --- a/otk/otk.hh +++ b/otk/otk.hh @@ -7,8 +7,6 @@ #include "eventdispatcher.hh" #include "eventhandler.hh" #include "widget.hh" -#include "focuswidget.hh" -#include "focuslabel.hh" #include "appwidget.hh" #include "application.hh" #include "assassin.hh" @@ -17,8 +15,8 @@ #include "rendercolor.hh" #include "display.hh" #include "font.hh" -//#include "gccache.hh" #include "rendercontrol.hh" +#include "size.hh" #include "point.hh" #include "property.hh" #include "rect.hh" diff --git a/otk/otk_test.cc b/otk/otk_test.cc index fb4db835..c36abfd1 100644 --- a/otk/otk_test.cc +++ b/otk/otk_test.cc @@ -5,75 +5,30 @@ #endif #include "application.hh" -#include "focuswidget.hh" #include "appwidget.hh" +#include "label.hh" #include "button.hh" int main(int argc, char **argv) { otk::Application app(argc, argv); - otk::AppWidget foo(&app); - - foo.resize(600, 500); - foo.setTexture(app.getStyle()->titlebarFocusBackground()); -// foo.setUnfocusTexture(app.getStyle()->titlebarUnfocusBackground()); - - foo.setBevelWidth(2); - foo.setDirection(otk::Widget::Horizontal); - - otk::FocusWidget left(&foo); - otk::FocusWidget right(&foo); - - left.setDirection(otk::Widget::Horizontal); - left.setStretchableVert(true); - left.setStretchableHorz(true); - left.setTexture(app.getStyle()->titlebarFocusBackground()); - left.setUnfocusTexture(app.getStyle()->titlebarUnfocusBackground()); - - right.setDirection(otk::Widget::Vertical); - right.setBevelWidth(10); - right.setStretchableVert(true); - right.setWidth(300); - right.setTexture(app.getStyle()->titlebarFocusBackground()); - right.setUnfocusTexture(app.getStyle()->titlebarUnfocusBackground()); - otk::Button iconb(&left); - iconb.resize(40,20); - -/* otk::FocusWidget label(&left); - otk::Button maxb(&left); - otk::Button closeb(&left); + otk::AppWidget foo(&app, otk::Widget::Vertical, 3); + otk::Label lab(&foo); + otk::Label lab2(&foo); + otk::Button but(&foo); + otk::Button but2(&foo); - // fixed size - iconb.setText("foo"); - iconb.press(Button1); - - // fix width to 60 and let the height be calculated by its parent - //label.setHeight(20); - label.setStretchableVert(true); - label.setStretchableHorz(true); - label.setTexture(app.getStyle()->labelFocusBackground()); - label.setUnfocusTexture(app.getStyle()->labelUnfocusBackground()); - - // fixed size - maxb.setText("bar"); - - // fixed size - closeb.setText("fuubar"); -*/ - otk::FocusWidget rblef(&right); - otk::Button rbutt1(&right); - otk::Button rbutt2(&right); - - rblef.setStretchableHorz(true); - rblef.setHeight(50); - rblef.setTexture(app.getStyle()->handleFocusBackground()); - rblef.setUnfocusTexture(app.getStyle()->handleUnfocusBackground()); + foo.resize(otk::Size(100, 150)); + + lab.setText("Hi, I'm a sexy\nlabel!!!"); + lab.setMaxSize(otk::Size(0,0)); + lab2.setText("Me too!!"); + lab2.setBorderWidth(10); + lab2.setBorderColor(otk::RenderStyle::style(app.screen())->buttonFocusColor()); + but.setText("Im not the default button..."); + but2.setText("But I AM!!"); + but2.setDefault(true); - rbutt1.setText("this is fucking tight"); - rbutt2.setText("heh, WOOP"); - - // will recursively unfocus its children - //foo.unfocus(); foo.show(); diff --git a/otk/point.hh b/otk/point.hh index 66c3b14d..f438b347 100644 --- a/otk/point.hh +++ b/otk/point.hh @@ -2,40 +2,22 @@ #ifndef __point_hh #define __point_hh -/*! @file point.hh - @brief The Point class contains an x/y pair -*/ - namespace otk { -//! The Point class is an x/y coordinate or size pair class Point { -private: - //! The x value - int _x; - //! The y value - int _y; - + int _x, _y; public: - //! Constructs a new Point with 0,0 values Point() : _x(0), _y(0) {} - //! Constructs a new Point with given values Point(int x, int y) : _x(x), _y(y) {} + Point(const Point &p) : _x(p._x), _y(p._y) {} - //! Changes the x value to the new value specified - void setX(int x) { _x = x; } - //! Returns the x value - int x() const { return _x; } - - //! Changes the y value to the new value specified - void setY(int y) { _y = y; } - //! Returns the y value - int y() const { return _y; } + inline int x() const { return _x; } + inline int y() const { return _y; } - //! Changes the x and y values - void setPoint(int x, int y) { _x = x; _y = y; } + bool operator==(const Point &o) const { return _x == o._x && _y == o._y; } + bool operator!=(const Point &o) const { return _x != o._x || _y != o._y; } }; } -#endif /* __point_hh */ +#endif // __point_hh diff --git a/otk/rect.cc b/otk/rect.cc deleted file mode 100644 index 7ec5c2c4..00000000 --- a/otk/rect.cc +++ /dev/null @@ -1,151 +0,0 @@ -// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- - -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif - -#include "rect.hh" - -namespace otk { - -void Rect::setX(int x) -{ - _x2 += x - _x1; - _x1 = x; -} - - -void Rect::setY(int y) -{ - _y2 += y - _y1; - _y1 = y; -} - - -void Rect::setPos(const Point &location) -{ - _x2 += location.x() - _x1; - _x1 = location.x(); - _y2 += location.y() - _y1; - _y1 = location.y(); -} - - -void Rect::setPos(int x, int y) -{ - _x2 += x - _x1; - _x1 = x; - _y2 += y - _y1; - _y1 = y; -} - - -void Rect::setWidth(int w) -{ - _x2 = w + _x1 - 1; -} - - -void Rect::setHeight(int h) -{ - _y2 = h + _y1 - 1; -} - - -void Rect::setSize(int w, int h) -{ - _x2 = w + _x1 - 1; - _y2 = h + _y1 - 1; -} - - -void Rect::setSize(const Point &size) -{ - _x2 = size.x() + _x1 - 1; - _y2 = size.y() + _y1 - 1; -} - - -void Rect::setRect(int x, int y, int w, int h) -{ - *this = Rect(x, y, w, h); -} - - -void Rect::setRect(const Point &location, const Point &size) -{ - *this = Rect(location, size); -} - - -void Rect::setCoords(int l, int t, int r, int b) -{ - _x1 = l; - _y1 = t; - _x2 = r; - _y2 = b; -} - - -void Rect::setCoords(const Point &tl, const Point &br) -{ - _x1 = tl.x(); - _y1 = tl.y(); - _x2 = br.x(); - _y2 = br.y(); -} - - -Rect Rect::operator|(const Rect &a) const -{ - Rect b; - - b._x1 = std::min(_x1, a._x1); - b._y1 = std::min(_y1, a._y1); - b._x2 = std::max(_x2, a._x2); - b._y2 = std::max(_y2, a._y2); - - return b; -} - - -Rect Rect::operator&(const Rect &a) const -{ - Rect b; - - b._x1 = std::max(_x1, a._x1); - b._y1 = std::max(_y1, a._y1); - b._x2 = std::min(_x2, a._x2); - b._y2 = std::min(_y2, a._y2); - - return b; -} - - -bool Rect::intersects(const Rect &a) const -{ - return std::max(_x1, a._x1) <= std::min(_x2, a._x2) && - std::max(_y1, a._y1) <= std::min(_y2, a._y2); -} - - -bool Rect::contains(int x, int y) const -{ - return x >= _x1 && x <= _x2 && - y >= _y1 && y <= _y2; -} - - -bool Rect::contains(const Point &p) const -{ - return contains(p.x(), p.y()); -} - - -bool Rect::contains(const Rect& a) const -{ - return a._x1 >= _x1 && a._x2 <= _x2 && - a._y1 >= _y1 && a._y2 <= _y2; -} - -} diff --git a/otk/rect.hh b/otk/rect.hh index de4f5e03..fe98dcb5 100644 --- a/otk/rect.hh +++ b/otk/rect.hh @@ -1,256 +1,39 @@ // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -#ifndef __rect_hh -#define __rect_hh - -extern "C" { -#include -} +#ifndef __rect_hh +#define __rect_hh #include "point.hh" -#include +#include "size.hh" namespace otk { -//! The Rect class defines a rectangle in the plane. class Rect { + Point _p; + Size _s; public: - //! Constructs an invalid Rect - inline Rect(void) : _x1(0), _y1(0), _x2(0), _y2(0) { } - //! Constructs a Rect - /*! - @param x The x component of the point defining the top left corner of the - rectangle - @param y The y component of the point defining the top left corner of the - rectangle - @param w The width of the rectangle - @param h The height of the rectangle - */ - inline Rect(int x, int y, int w, int h) - : _x1(x), _y1(y), _x2(w + x - 1), _y2(h + y - 1) { } - //! Constructs a Rect from 2 Point objects - /*! - @param location The point defining the top left corner of the rectangle - @param size The width and height of the rectangle - */ - inline Rect(const Point &location, const Point &size) - : _x1(location.x()), _y1(location.y()), - _x2(size.x() + location.x() - 1), _y2(size.y() + location.y() - 1) { } - //! Constructs a Rect from another Rect - /*! - @param rect The rectangle from which to construct this new one - */ - inline Rect(const Rect &rect) - : _x1(rect._x1), _y1(rect._y1), _x2(rect._x2), _y2(rect._y2) { } - //! Constructs a Rect from an XRectangle - inline explicit Rect(const XRectangle& xrect) - : _x1(xrect.x), _y1(xrect.y), _x2(xrect.width + xrect.x - 1), - _y2(xrect.height + xrect.y - 1) { } - - //! Returns the left coordinate of the Rect. Identical to Rect::x. - inline int left(void) const { return _x1; } - //! Returns the top coordinate of the Rect. Identical to Rect::y. - inline int top(void) const { return _y1; } - //! Returns the right coordinate of the Rect - inline int right(void) const { return _x2; } - //! Returns the bottom coordinate of the Rect - inline int bottom(void) const { return _y2; } - - //! The x component of the point defining the top left corner of the Rect - inline int x(void) const { return _x1; } - //! The y component of the point defining the top left corner of the Rect - inline int y(void) const { return _y1; } - //! Returns the Point that defines the top left corner of the rectangle - inline Point location() const { return Point(_x1, _y1); } - - //! Sets the x coordinate of the Rect. - /*! - @param x The new x component of the point defining the top left corner of - the rectangle - */ - void setX(int x); - //! Sets the y coordinate of the Rect. - /*! - @param y The new y component of the point defining the top left corner of - the rectangle - */ - void setY(int y); - //! Sets the x and y coordinates of the Rect. - /*! - @param x The new x component of the point defining the top left corner of - the rectangle - @param y The new y component of the point defining the top left corner of - the rectangle - */ - void setPos(int x, int y); - //! Sets the x and y coordinates of the Rect. - /*! - @param location The point defining the top left corner of the rectangle. - */ - void setPos(const Point &location); - - //! The width of the Rect - inline int width(void) const { return _x2 - _x1 + 1; } - //! The height of the Rect - inline int height(void) const { return _y2 - _y1 + 1; } - //! Returns the size of the Rect - inline Point size() const { return Point(_x2 - _x1 + 1, _y2 - _y1 + 1); } - - //! Sets the width of the Rect - /*! - @param w The new width of the rectangle - */ - void setWidth(int w); - //! Sets the height of the Rect - /*! - @param h The new height of the rectangle - */ - void setHeight(int h); - //! Sets the size of the Rect. - /*! - @param w The new width of the rectangle - @param h The new height of the rectangle - */ - void setSize(int w, int h); - //! Sets the size of the Rect. - /*! - @param size The new size of the rectangle - */ - void setSize(const Point &size); - - //! Sets the position and size of the Rect - /*! - @param x The new x component of the point defining the top left corner of - the rectangle - @param y The new y component of the point defining the top left corner of - the rectangle - @param w The new width of the rectangle - @param h The new height of the rectangle - */ - void setRect(int x, int y, int w, int h); - //! Sets the position and size of the Rect - /*! - @param location The new point defining the top left corner of the rectangle - @param size The new size of the rectangle - */ - void setRect(const Point &location, const Point &size); - - //! Sets the position of all 4 sides of the Rect - /*! - @param l The new left coordinate of the rectangle - @param t The new top coordinate of the rectangle - @param r The new right coordinate of the rectangle - @param b The new bottom coordinate of the rectangle - */ - void setCoords(int l, int t, int r, int b); - //! Sets the position of all 4 sides of the Rect - /*! - @param tl The new point at the top left of the rectangle - @param br The new point at the bottom right of the rectangle - */ - void setCoords(const Point &tl, const Point &br); - - //! Determines if two Rect objects are equal - /*! - The rectangles are considered equal if they are in the same position and - are the same size. - */ - inline bool operator==(const Rect &a) - { return _x1 == a._x1 && _y1 == a._y1 && _x2 == a._x2 && _y2 == a._y2; } - //! Determines if two Rect objects are inequal - /*! - @see operator== - */ - inline bool operator!=(const Rect &a) { return ! operator==(a); } - - //! Returns the union of two Rect objects - /*! - The union of the rectangles will consist of the maximimum area that the two - rectangles can make up. - @param a A second Rect object to form a union with. - */ - Rect operator|(const Rect &a) const; - //! Returns the intersection of two Rect objects - /*! - The intersection of the rectangles will consist of just the area where the - two rectangles overlap. - @param a A second Rect object to form an intersection with. - @return The intersection between this Rect and the one passed to the - function - */ - Rect operator&(const Rect &a) const; - //! Sets the Rect to the union of itself with another Rect object - /*! - The union of the rectangles will consist of the maximimum area that the two - rectangles can make up. - @param a A second Rect object to form a union with. - @return The union between this Rect and the one passed to the function - */ - inline Rect &operator|=(const Rect &a) { *this = *this | a; return *this; } - //! Sets the Rect to the intersection of itself with another Rect object - /*! - The intersection of the rectangles will consist of just the area where the - two rectangles overlap. - @param a A second Rect object to form an intersection with. - */ - inline Rect &operator&=(const Rect &a) { *this = *this & a; return *this; } - - //! Returns if the Rect is valid - /*! - A rectangle is valid only if its right and bottom coordinates are larger - than its left and top coordinates (i.e. it does not have a negative width - or height). - @return true if the Rect is valid; otherwise, false - */ - inline bool valid(void) const { return _x2 > _x1 && _y2 > _y1; } - - //! Determines if this Rect intersects another Rect - /*! - The rectangles intersect if any part of them overlaps. - @param a Another Rect object to compare this Rect with - @return true if the Rect objects overlap; otherwise, false - */ - bool intersects(const Rect &a) const; - //! Determines if this Rect contains a point - /*! - The rectangle contains the point if it falls within the rectangle's - boundaries. - @param x The x coordinate of the point to operate on - @param y The y coordinate of the point to operate on - @return true if the point is contained within this Rect; otherwise, false - */ - bool contains(int x, int y) const; - //! Determines if this Rect contains a point - /*! - The rectangle contains the point if it falls within the rectangle's - boundaries. - @param p The point to operate on - @return true if the point is contained within this Rect; otherwise, false - */ - bool contains(const Point &p) const; - //! Determines if this Rect contains another Rect entirely - /*! - This rectangle contains the second rectangle if it is entirely within this - rectangle's boundaries. - @param a The Rect to test for containment inside of this Rect - @return true if the second Rect is contained within this Rect; otherwise, - false - */ - bool contains(const Rect &a) const; - -private: - //! The left coordinate of the Rect - int _x1; - //! The top coordinate of the Rect - int _y1; - //! The right coordinate of the Rect - int _x2; - //! The bottom coordinate of the Rect - int _y2; + Rect() : _p(), _s() {} + Rect(const Point &p, const Size &s) : _p(p), _s(s) {} + Rect(const Rect &r) : _p(r._p), _s(r._s) {} + Rect(int x, int y, unsigned int w, unsigned int h) + : _p(x, y), _s(w, h) {} + + inline int x() const { return _p.x(); } + inline int y() const { return _p.y(); } + inline unsigned int width() const { return _s.width(); } + inline unsigned int height() const { return _s.height(); } + + inline int left() const { return _p.x(); } + inline int top() const { return _p.y(); } + inline int right() const { return _p.x() + _s.width() - 1; } + inline int bottom() const { return _p.y() + _s.height() - 1; } + + inline const Point& position() const { return _p; } + inline const Size& size() const { return _s; } + + bool operator==(const Rect &o) const { return _p == o._p && _s == o._s; } + bool operator!=(const Rect &o) const { return _p != o._p || _s != o._s; } }; -//! A list for Rect objects -typedef std::vector RectList; - } #endif // __rect_hh diff --git a/otk/rendercontrol.cc b/otk/rendercontrol.cc index aae6c76b..bf69a4e5 100644 --- a/otk/rendercontrol.cc +++ b/otk/rendercontrol.cc @@ -9,6 +9,7 @@ #include "pseudorendercontrol.hh" #include "rendertexture.hh" #include "rendercolor.hh" +#include "renderstyle.hh" #include "display.hh" #include "screeninfo.hh" #include "surface.hh" @@ -50,15 +51,11 @@ RenderControl::RenderControl(int screen) : _screen(screen) { printf("Initializing RenderControl\n"); - - } RenderControl::~RenderControl() { printf("Destroying RenderControl\n"); - - } void RenderControl::drawRoot(const RenderColor &color) const @@ -120,7 +117,7 @@ void RenderControl::drawSolidBackground(Surface& sf, sf.setPixmap(texture.color()); - int width = sf.width(), height = sf.height(); + int width = sf.size().width(), height = sf.size().height(); int left = 0, top = 0, right = width - 1, bottom = height - 1; if (texture.interlaced()) diff --git a/otk/renderstyle.cc b/otk/renderstyle.cc index 5e19aa47..13d9e577 100644 --- a/otk/renderstyle.cc +++ b/otk/renderstyle.cc @@ -8,8 +8,49 @@ #include "display.hh" #include "screeninfo.hh" +#include + namespace otk { +RenderStyle **RenderStyle::_styles = 0; +std::list *RenderStyle::_notifies = 0; + +void RenderStyle::initialize() +{ + int screens = ScreenCount(**display); + _styles = new RenderStyle*[screens]; + for (int i = 0; i < screens; ++i) + _styles[i] = new RenderStyle(i, ""); // XXX get a path + _notifies = new std::list[screens]; +} + +void RenderStyle::destroy() +{ + int screens = ScreenCount(**display); + for (int i = 0; i < screens; ++i) + delete _styles[i]; + delete [] _styles; + delete [] _notifies; +} + +void RenderStyle::registerNotify(int screen, StyleNotify *n) +{ + assert(screen >= 0 && screen < ScreenCount(**display)); + _notifies[screen].push_back(n); +} + +void RenderStyle::unregisterNotify(int screen, StyleNotify *n) +{ + assert(screen >= 0 && screen < ScreenCount(**display)); + _notifies[screen].remove(n); +} + +RenderStyle *RenderStyle::style(int screen) +{ + assert(screen >= 0 && screen < ScreenCount(**display)); + return _styles[screen]; +} + RenderStyle::RenderStyle(int screen, const std::string &stylefile) : _screen(screen), _file(stylefile) @@ -175,7 +216,7 @@ RenderStyle::RenderStyle(int screen, const std::string &stylefile) 0x0); _label_font = new Font(_screen, "Arial,Sans-9:bold", true, 1, 0x40); - _label_justify = RightJustify; + _label_justify = RightBottomJustify; _max_mask = new PixmapMask(); _max_mask->w = _max_mask->h = 8; diff --git a/otk/renderstyle.hh b/otk/renderstyle.hh index 2d2c3250..69745533 100644 --- a/otk/renderstyle.hh +++ b/otk/renderstyle.hh @@ -7,6 +7,7 @@ #include "font.hh" #include +#include namespace otk { @@ -16,11 +17,27 @@ struct PixmapMask { PixmapMask() { mask = None; w = h = 0; } }; +class RenderStyle; + +class StyleNotify { +public: + //! Called when the style is changed on the same screen as the handler. + virtual void styleChanged(const RenderStyle &) {} +}; + class RenderStyle { + static RenderStyle **_styles; + static std::list *_notifies; public: - enum TextJustify { - LeftJustify, - RightJustify, + static void initialize(); + static void destroy(); + static void registerNotify(int screen, StyleNotify *n); + static void unregisterNotify(int screen, StyleNotify *n); + static RenderStyle *style(int screen); + + enum Justify { + LeftTopJustify, + RightBottomJustify, CenterJustify }; @@ -61,7 +78,7 @@ private: RenderTexture *_grip_unfocus; Font *_label_font; - TextJustify _label_justify; + Justify _label_justify; PixmapMask *_max_mask; PixmapMask *_icon_mask; @@ -120,7 +137,7 @@ public: inline RenderTexture *gripUnfocusBackground() const { return _grip_unfocus; } inline Font *labelFont() const { return _label_font; } - inline TextJustify labelTextJustify() const { return _label_justify; } + inline Justify labelTextJustify() const { return _label_justify; } inline PixmapMask *maximizeMask() const { return _max_mask; } inline PixmapMask *iconifyMask() const { return _icon_mask; } diff --git a/otk/screeninfo.cc b/otk/screeninfo.cc index 087f4efd..560a5636 100644 --- a/otk/screeninfo.cc +++ b/otk/screeninfo.cc @@ -22,8 +22,8 @@ ScreenInfo::ScreenInfo(unsigned int num) { _root_window = RootWindow(**display, _screen); - _rect.setSize(WidthOfScreen(ScreenOfDisplay(**display, - _screen)), + _size = Size(WidthOfScreen(ScreenOfDisplay(**display, + _screen)), HeightOfScreen(ScreenOfDisplay(**display, _screen))); /* diff --git a/otk/screeninfo.hh b/otk/screeninfo.hh index f523d23b..440573aa 100644 --- a/otk/screeninfo.hh +++ b/otk/screeninfo.hh @@ -2,6 +2,7 @@ #ifndef __screeninfo_hh #define __screeninfo_hh +#include "size.hh" #include "rect.hh" extern "C" { @@ -9,6 +10,7 @@ extern "C" { } #include +#include namespace otk { @@ -21,9 +23,9 @@ private: int _depth; unsigned int _screen; std::string _display_string; - Rect _rect; + Size _size; #ifdef XINERAMA - RectList _xinerama_areas; + std::vector _xinerama_areas; bool _xinerama_active; #endif @@ -35,12 +37,11 @@ public: inline Colormap colormap() const { return _colormap; } inline int depth() const { return _depth; } inline unsigned int screen() const { return _screen; } - inline const Rect& rect() const { return _rect; } - inline unsigned int width() const { return _rect.width(); } - inline unsigned int height() const { return _rect.height(); } + inline const Size& size() const { return _size; } inline const std::string& displayString() const { return _display_string; } #ifdef XINERAMA - inline const RectList &xineramaAreas() const { return _xinerama_areas; } + inline const std::vector &xineramaAreas() const + { return _xinerama_areas; } inline bool isXineramaActive() const { return _xinerama_active; } #endif }; diff --git a/otk/surface.cc b/otk/surface.cc index 9dfb8889..aabbf85a 100644 --- a/otk/surface.cc +++ b/otk/surface.cc @@ -15,7 +15,7 @@ extern "C" { namespace otk { -Surface::Surface(int screen, const Point &size) +Surface::Surface(int screen, const Size &size) : _screen(screen), _size(size), _pixmap(None), @@ -34,19 +34,19 @@ void Surface::setPixmap(const RenderColor &color) createObjects(); XFillRectangle(**display, _pixmap, color.gc(), 0, 0, - _size.x(), _size.y()); + _size.width(), _size.height()); } void Surface::setPixmap(XImage *image) { - assert(image->width == _size.x()); - assert(image->height == _size.y()); + assert((unsigned)image->width == _size.width()); + assert((unsigned)image->height == _size.height()); if (_pixmap == None) createObjects(); XPutImage(**display, _pixmap, DefaultGC(**display, _screen), - image, 0, 0, 0, 0, _size.x(), _size.y()); + image, 0, 0, 0, 0, _size.width(), _size.height()); } void Surface::createObjects() @@ -56,7 +56,7 @@ void Surface::createObjects() const ScreenInfo *info = display->screenInfo(_screen); _pixmap = XCreatePixmap(**display, info->rootWindow(), - _size.x(), _size.y(), info->depth()); + _size.width(), _size.height(), info->depth()); assert(_pixmap != None); _xftdraw = XftDrawCreate(**display, _pixmap, diff --git a/otk/surface.hh b/otk/surface.hh index 112bb392..7a202491 100644 --- a/otk/surface.hh +++ b/otk/surface.hh @@ -2,7 +2,7 @@ #ifndef __surface_hh #define __surface_hh -#include "point.hh" +#include "size.hh" #include "truerendercontrol.hh" #include "pseudorendercontrol.hh" @@ -19,7 +19,7 @@ class RenderColor; class Surface { int _screen; - Point _size; + Size _size; Pixmap _pixmap; XftDraw *_xftdraw; @@ -31,14 +31,12 @@ protected: void setPixmap(const RenderColor &color); public: - Surface(int screen, const Point &size); + Surface(int screen, const Size &size); virtual ~Surface(); inline int screen(void) const { return _screen; } - virtual const Point& size() const { return _size; } - virtual int width() const { return _size.x(); } - virtual int height() const { return _size.y(); } + virtual const Size& size() const { return _size; } virtual Pixmap pixmap() const { return _pixmap; } diff --git a/otk/truerendercontrol.cc b/otk/truerendercontrol.cc index 5e9f3188..2c7c42a4 100644 --- a/otk/truerendercontrol.cc +++ b/otk/truerendercontrol.cc @@ -59,13 +59,14 @@ void TrueRenderControl::drawGradientBackground( Surface &sf, const RenderTexture &texture) const { unsigned int r,g,b; - int w = sf.width(), h = sf.height(), off, x; + unsigned int w = sf.size().width(), h = sf.size().height(); + unsigned int off, x; const ScreenInfo *info = display->screenInfo(_screen); XImage *im = XCreateImage(**display, info->visual(), info->depth(), ZPixmap, 0, NULL, w, h, 32, 0); im->byte_order = endian; - pixel32 *data = new pixel32[sf.height()*sf.width()]; + pixel32 *data = new pixel32[h*w]; pixel32 current; switch (texture.gradient()) { @@ -101,25 +102,29 @@ void TrueRenderControl::drawGradientBackground( if (texture.relief() != RenderTexture::Flat) { if (texture.bevel() == RenderTexture::Bevel1) { - for (off = 1, x = 1; x < w - 1; ++x, off++) - highlight(data + off, - data + off + (h-1) * w, - texture.relief()==RenderTexture::Raised); - for (off = 0, x = 0; x < h; ++x, off++) - highlight(data + off * w, - data + off * w + w - 1, - texture.relief()==RenderTexture::Raised); + if (w >= 1 && h >= 1) { + for (off = 1, x = 1; x < w - 1; ++x, off++) + highlight(data + off, + data + off + (h-1) * w, + texture.relief()==RenderTexture::Raised); + for (off = 0, x = 0; x < h; ++x, off++) + highlight(data + off * w, + data + off * w + w - 1, + texture.relief()==RenderTexture::Raised); + } } if (texture.bevel() == RenderTexture::Bevel2) { - for (off = 2, x = 2; x < w - 2; ++x, off++) - highlight(data + off + w, - data + off + (h-2) * w, - texture.relief()==RenderTexture::Raised); - for (off = 1, x = 1; x < h-1; ++x, off++) - highlight(data + off * w + 1, - data + off * w + w - 2, - texture.relief()==RenderTexture::Raised); + if (w >= 2 && h >= 2) { + for (off = 2, x = 2; x < w - 2; ++x, off++) + highlight(data + off + w, + data + off + (h-2) * w, + texture.relief()==RenderTexture::Raised); + for (off = 1, x = 1; x < h-1; ++x, off++) + highlight(data + off * w + 1, + data + off * w + w - 2, + texture.relief()==RenderTexture::Raised); + } } } @@ -141,24 +146,25 @@ void TrueRenderControl::verticalGradient(Surface &sf, pixel32 current; float dr, dg, db; unsigned int r,g,b; + unsigned int w = sf.size().width(), h = sf.size().height(); dr = (float)(texture.secondary_color().red() - texture.color().red()); - dr/= (float)sf.height(); + dr/= (float)h; dg = (float)(texture.secondary_color().green() - texture.color().green()); - dg/= (float)sf.height(); + dg/= (float)h; db = (float)(texture.secondary_color().blue() - texture.color().blue()); - db/= (float)sf.height(); + db/= (float)h; - for (int y = 0; y < sf.height(); ++y) { + for (unsigned int y = 0; y < h; ++y) { r = texture.color().red() + (int)(dr * y); g = texture.color().green() + (int)(dg * y); b = texture.color().blue() + (int)(db * y); current = (r << default_red_shift) + (g << default_green_shift) + (b << default_blue_shift); - for (int x = 0; x < sf.width(); ++x, ++data) + for (unsigned int x = 0; x < w; ++x, ++data) *data = current; } } @@ -170,21 +176,21 @@ void TrueRenderControl::diagonalGradient(Surface &sf, pixel32 current; float drx, dgx, dbx, dry, dgy, dby; unsigned int r,g,b; + unsigned int w = sf.size().width(), h = sf.size().height(); - - for (int y = 0; y < sf.height(); ++y) { + for (unsigned int y = 0; y < h; ++y) { drx = (float)(texture.secondary_color().red() - texture.color().red()); - dry = drx/(float)sf.height(); - drx/= (float)sf.width(); + dry = drx/(float)h; + drx/= (float)w; dgx = (float)(texture.secondary_color().green() - texture.color().green()); - dgy = dgx/(float)sf.height(); - dgx/= (float)sf.width(); + dgy = dgx/(float)h; + dgx/= (float)w; dbx = (float)(texture.secondary_color().blue() - texture.color().blue()); - dby = dbx/(float)sf.height(); - dbx/= (float)sf.width(); - for (int x = 0; x < sf.width(); ++x, ++data) { + dby = dbx/(float)h; + dbx/= (float)w; + for (unsigned int x = 0; x < w; ++x, ++data) { r = texture.color().red() + ((int)(drx * x) + (int)(dry * y))/2; g = texture.color().green() + ((int)(dgx * x) + (int)(dgy * y))/2; b = texture.color().blue() + ((int)(dbx * x) + (int)(dby * y))/2; @@ -203,20 +209,21 @@ void TrueRenderControl::crossDiagonalGradient(Surface &sf, pixel32 current; float drx, dgx, dbx, dry, dgy, dby; unsigned int r,g,b; + unsigned int w = sf.size().width(), h = sf.size().height(); - for (int y = 0; y < sf.height(); ++y) { + for (unsigned int y = 0; y < h; ++y) { drx = (float)(texture.secondary_color().red() - texture.color().red()); - dry = drx/(float)sf.height(); - drx/= (float)sf.width(); + dry = drx/(float)h; + drx/= (float)w; dgx = (float)(texture.secondary_color().green() - texture.color().green()); - dgy = dgx/(float)sf.height(); - dgx/= (float)sf.width(); + dgy = dgx/(float)h; + dgx/= (float)w; dbx = (float)(texture.secondary_color().blue() - texture.color().blue()); - dby = dbx/(float)sf.height(); - dbx/= (float)sf.width(); - for (int x = sf.width(); x > 0; --x, ++data) { + dby = dbx/(float)h; + dbx/= (float)w; + for (int x = w; x > 0; --x, ++data) { r = texture.color().red() + ((int)(drx * (x-1)) + (int)(dry * y))/2; g = texture.color().green() + ((int)(dgx * (x-1)) + (int)(dgy * y))/2; b = texture.color().blue() + ((int)(dbx * (x-1)) + (int)(dby * y))/2; diff --git a/otk/widget.cc b/otk/widget.cc index 67535024..612a252d 100644 --- a/otk/widget.cc +++ b/otk/widget.cc @@ -1,522 +1,485 @@ // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - +#include "config.h" #include "widget.hh" #include "display.hh" -#include "assassin.hh" +#include "surface.hh" +#include "rendertexture.hh" +#include "rendercolor.hh" +#include "eventdispatcher.hh" #include "screeninfo.hh" -#include "focuslabel.hh" + +#include +#include #include -#include namespace otk { -Widget::Widget(Widget *parent, Direction direction) - : EventHandler(), - _dirty(false), _focused(false), - _parent(parent), _style(parent->style()), _direction(direction), - _cursor(parent->cursor()), _bevel_width(parent->bevelWidth()), - _ignore_config(0), - _visible(false), _grabbed_mouse(false), - _grabbed_keyboard(false), _stretchable_vert(false), - _stretchable_horz(false), _texture(0), _bg_pixmap(0), _bg_pixel(0), - _bcolor(0), _bwidth(0), _rect(0, 0, 1, 1), _screen(parent->screen()), - _fixed_width(false), _fixed_height(false), +Widget::Widget(int screen, EventDispatcher *ed, Direction direction, int bevel, + bool overrideredir) + : _texture(0), + _screen(screen), + _parent(0), + _window(0), + _surface(0), _event_mask(ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask | StructureNotifyMask), + _alignment(RenderStyle::CenterJustify), + _direction(direction), + _max_size(UINT_MAX, UINT_MAX), + _visible(false), + _bordercolor(0), + _borderwidth(0), + _bevel(bevel), + _dirty(true), + _dispatcher(ed), + _ignore_config(0) +{ + createWindow(overrideredir); + _dispatcher->registerHandler(_window, this); +} + +Widget::Widget(Widget *parent, Direction direction, int bevel) + : _texture(0), + _screen(parent->_screen), + _parent(parent), + _window(0), _surface(0), - _event_dispatcher(parent->eventDispatcher()) -{ - assert(parent); - parent->addChild(this); - create(); - _event_dispatcher->registerHandler(_window, this); -} - -Widget::Widget(EventDispatcher *event_dispatcher, RenderStyle *style, - Direction direction, Cursor cursor, int bevel_width, - bool override_redirect) - : EventHandler(), - _dirty(false),_focused(false), - _parent(0), _style(style), _direction(direction), _cursor(cursor), - _bevel_width(bevel_width), _ignore_config(0), _visible(false), - _grabbed_mouse(false), _grabbed_keyboard(false), - _stretchable_vert(false), _stretchable_horz(false), _texture(0), - _bg_pixmap(0), _bg_pixel(0), _bcolor(0), _bwidth(0), _rect(0, 0, 1, 1), - _screen(style->screen()), _fixed_width(false), _fixed_height(false), _event_mask(ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask | StructureNotifyMask), - _surface(0), - _event_dispatcher(event_dispatcher) + _alignment(RenderStyle::CenterJustify), + _direction(direction), + _max_size(UINT_MAX, UINT_MAX), + _visible(false), + _bordercolor(0), + _borderwidth(0), + _bevel(bevel), + _dirty(true), + _dispatcher(parent->_dispatcher), + _ignore_config(0) { - assert(event_dispatcher); - assert(style); - create(override_redirect); - _event_dispatcher->registerHandler(_window, this); + assert(parent); + createWindow(false); + parent->addChild(this); + parent->layout(); + _dispatcher->registerHandler(_window, this); } Widget::~Widget() { - if (_visible) - hide(); - - if (_surface) - delete _surface; + assert(_children.empty()); // this would be bad. theyd have a hanging _parent - _event_dispatcher->clearHandler(_window); - - std::for_each(_children.begin(), _children.end(), PointerAssassin()); - - if (_parent) - _parent->removeChild(this); + if (_surface) delete _surface; + if (_parent) _parent->removeChild(this); + _dispatcher->clearHandler(_window); XDestroyWindow(**display, _window); } -void Widget::create(bool override_redirect) +void Widget::show(bool children) { - const ScreenInfo *scr_info = display->screenInfo(_screen); - Window p_window = _parent ? _parent->window() : scr_info->rootWindow(); - - _rect.setRect(0, 0, 1, 1); // just some initial values - - XSetWindowAttributes attrib_create; - unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask; - - attrib_create.background_pixmap = None; - attrib_create.colormap = scr_info->colormap(); - attrib_create.event_mask = _event_mask; - - if (override_redirect) { - create_mask |= CWOverrideRedirect; - attrib_create.override_redirect = true; + if (children) { + std::list::iterator it , end = _children.end(); + for (it = _children.begin(); it != end; ++it) + (*it)->show(true); } - - if (_cursor) { - create_mask |= CWCursor; - attrib_create.cursor = _cursor; + if (!_visible) { + _visible = true; + XMapWindow(**display, _window); + update(); } - - _window = XCreateWindow(**display, p_window, _rect.x(), - _rect.y(), _rect.width(), _rect.height(), 0, - scr_info->depth(), InputOutput, - scr_info->visual(), create_mask, &attrib_create); - _ignore_config++; } +void Widget::hide() +{ + if (_visible) { + _visible = false; + XUnmapWindow(**display, _window); + if (_parent) _parent->layout(); + } +} + void Widget::setEventMask(long e) { XSelectInput(**display, _window, e); _event_mask = e; } -void Widget::setWidth(int w) -{ - assert(w > 0); - _fixed_width = true; - setGeometry(_rect.x(), _rect.y(), w, _rect.height()); -} - -void Widget::setHeight(int h) -{ - assert(h > 0); - _fixed_height = true; - setGeometry(_rect.x(), _rect.y(), _rect.width(), h); -} - -void Widget::move(const Point &to) -{ - move(to.x(), to.y()); -} - -void Widget::move(int x, int y) +void Widget::update() { - _rect.setPos(x, y); - XMoveWindow(**display, _window, x, y); - _ignore_config++; + _dirty = true; + if (parent()) + parent()->layout(); // relay-out us and our siblings + else { + render(); + layout(); + } } -void Widget::resize(const Point &to) +void Widget::moveresize(const Rect &r) { - resize(to.x(), to.y()); -} + unsigned int w, h; + w = std::min(std::max(r.width(), minSize().width()), maxSize().width()); + h = std::min(std::max(r.height(), minSize().height()), maxSize().height()); -void Widget::resize(int w, int h) -{ - assert(w > 0 && h > 0); - _fixed_width = _fixed_height = true; - setGeometry(_rect.x(), _rect.y(), w, h); -} + if (r.x() == area().x() && r.y() == area().y() && + w == area().width() && h == area().height()) { + return; // no change, don't cause a big layout chain to occur! + } + + internal_moveresize(r.x(), r.y(), w, h); -void Widget::setGeometry(const Rect &new_geom) -{ - setGeometry(new_geom.x(), new_geom.y(), new_geom.width(), new_geom.height()); -} - -void Widget::setGeometry(const Point &topleft, int width, int height) -{ - setGeometry(topleft.x(), topleft.y(), width, height); + update(); } -void Widget::setGeometry(int x, int y, int width, int height) +void Widget::internal_moveresize(int x, int y, unsigned w, unsigned int h) { - _rect = Rect(x, y, width, height); + assert(w > 0); + assert(h > 0); + assert(_borderwidth >= 0); _dirty = true; + XMoveResizeWindow(**display, _window, x, y, + w - _borderwidth * 2, + h - _borderwidth * 2); + _ignore_config++; - // make all parents dirty too - Widget *p = _parent; - while (p) { - p->_dirty = true; - p = p->_parent; - } - - // don't use an XMoveResizeWindow here, because it doesn't seem to move - // windows with StaticGravity? This works, that didn't. - XResizeWindow(**display, _window, width, height); - XMoveWindow(**display, _window, x, y); - _ignore_config+=2; + _area = Rect(x, y, w, h); } -void Widget::show(bool recursive) +void Widget::setAlignment(RenderStyle::Justify a) { - if (_visible) - return; - - // make sure the internal state isn't mangled - if (_dirty) - update(); - - if (recursive) { - WidgetList::iterator it = _children.begin(), end = _children.end(); - for (; it != end; ++it) - (*it)->show(recursive); - } - - XMapWindow(**display, _window); - _visible = true; + _alignment = a; + layout(); } - -void Widget::hide(bool recursive) + +void Widget::createWindow(bool overrideredir) { - if (! _visible) - return; + const ScreenInfo *info = display->screenInfo(_screen); + XSetWindowAttributes attrib; + unsigned long mask = CWEventMask | CWBorderPixel; - if (recursive) { - WidgetList::iterator it = _children.begin(), end = _children.end(); - for (; it != end; ++it) - (*it)->hide(); - } - - XUnmapWindow(**display, _window); - _visible = false; -} + attrib.event_mask = _event_mask; + attrib.border_pixel = (_bordercolor ? + _bordercolor->pixel(): + BlackPixel(**display, _screen)); -void Widget::focus(void) -{ - _focused = true; + if (overrideredir) { + mask |= CWOverrideRedirect; + attrib.override_redirect = true; + } - Widget::WidgetList::iterator it = _children.begin(), - end = _children.end(); - for (; it != end; ++it) - (*it)->focus(); -} - -void Widget::unfocus(void) -{ - _focused = false; + _window = XCreateWindow(**display, (_parent ? + _parent->_window : + RootWindow(**display, _screen)), + _area.x(), _area.y(), + _area.width(), _area.height(), + _borderwidth, + info->depth(), + InputOutput, + info->visual(), + mask, + &attrib); + assert(_window != None); + ++_ignore_config; +} + +void Widget::setBorderWidth(int w) +{ + assert(w >= 0); + if (!parent()) return; // top-level windows cannot have borders + if (w == borderWidth()) return; // no change - Widget::WidgetList::iterator it = _children.begin(), - end = _children.end(); - for (; it != end; ++it) - (*it)->unfocus(); -} + _borderwidth = w; + XSetWindowBorderWidth(**display, _window, _borderwidth); -bool Widget::grabMouse(void) -{ - Status ret = XGrabPointer(**display, _window, True, - (ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | EnterWindowMask | - LeaveWindowMask | PointerMotionMask), - GrabModeSync, GrabModeAsync, None, None, - CurrentTime); - _grabbed_mouse = (ret == GrabSuccess); - return _grabbed_mouse; + calcDefaultSizes(); + update(); } -void Widget::ungrabMouse(void) +void Widget::setMinSize(const Size &s) { - if (! _grabbed_mouse) - return; - - XUngrabPointer(**display, CurrentTime); - _grabbed_mouse = false; + _min_size = s; + update(); } -bool Widget::grabKeyboard(void) +void Widget::setMaxSize(const Size &s) { - Status ret = XGrabKeyboard(**display, _window, True, - GrabModeSync, GrabModeAsync, CurrentTime); - _grabbed_keyboard = (ret == GrabSuccess); - return _grabbed_keyboard; - + _max_size = s; + update(); } -void Widget::ungrabKeyboard(void) +void Widget::setBorderColor(const RenderColor *c) { - if (! _grabbed_keyboard) - return; - - XUngrabKeyboard(**display, CurrentTime); - _grabbed_keyboard = false; + _bordercolor = c; + XSetWindowBorder(**otk::display, _window, + c ? c->pixel() : BlackPixel(**otk::display, _screen)); } -void Widget::render(void) +void Widget::setBevel(int b) { - if (!_texture) { - XSetWindowBackgroundPixmap(**display, _window, ParentRelative); - return; - } - - Surface *s = _surface; // save the current surface - - _surface = new Surface(_screen, _rect.size()); - display->renderControl(_screen)->drawBackground(*_surface, *_texture); - - renderForeground(); // for inherited types to render onto the _surface - - XSetWindowBackgroundPixmap(**display, _window, _surface->pixmap()); - - if (s) - delete s; // delete the old surface *after* its pixmap isn't in use anymore + _bevel = b; + calcDefaultSizes(); + layout(); } -void Widget::adjust(void) +void Widget::layout() { if (_direction == Horizontal) - adjustHorz(); + layoutHorz(); else - adjustVert(); + layoutVert(); } -void Widget::adjustHorz(void) +void Widget::layoutHorz() { - if (_children.size() == 0) - return; - - Widget *tmp; - WidgetList::iterator it, end = _children.end(); - - int tallest = 0; - int width = _bevel_width; - WidgetList stretchable; - - for (it = _children.begin(); it != end; ++it) { - tmp = *it; - if (tmp->isStretchableVert()) - tmp->setHeight(_rect.height() > _bevel_width * 2 ? - _rect.height() - _bevel_width * 2 : _bevel_width); - if (tmp->isStretchableHorz()) - stretchable.push_back(tmp); - else - width += tmp->_rect.width() + _bevel_width; - - if (tmp->_rect.height() > tallest) - tallest = tmp->_rect.height(); - } - - if (stretchable.size() > 0) { - WidgetList::iterator str_it = stretchable.begin(), - str_end = stretchable.end(); + std::list::iterator it, end; - int str_width = _rect.width() - width / stretchable.size(); - - for (; str_it != str_end; ++str_it) - (*str_it)->setWidth(str_width > _bevel_width ? str_width - _bevel_width - : _bevel_width); + // work with just the visible children + std::list visible = _children; + for (it = visible.begin(), end = visible.end(); it != end;) { + std::list::iterator next = it; ++next; + if (!(*it)->visible()) + visible.erase(it); + it = next; } - Widget *prev_widget = 0; - - for (it = _children.begin(); it != end; ++it) { - tmp = *it; - int x, y; + if (visible.empty()) return; - if (prev_widget) - x = prev_widget->_rect.x() + prev_widget->_rect.width() + _bevel_width; - else - x = _bevel_width; - y = (tallest - tmp->_rect.height()) / 2 + _bevel_width; - - tmp->move(x, y); + if ((unsigned)(_borderwidth * 2 + _bevel * 2) > _area.width() || + (unsigned)(_borderwidth * 2 + _bevel * 2) > _area.height()) + return; // not worth laying anything out! + + int x, y; unsigned int w, h; // working area + x = y = _bevel; + w = _area.width() - _borderwidth * 2 - _bevel * 2; + h = _area.height() - _borderwidth * 2 - _bevel * 2; + + int free = w - (visible.size() - 1) * _bevel; + if (free < 0) free = 0; + unsigned int each; + + std::list adjustable = visible; + + // find the 'free' space, and how many children will be using it + for (it = adjustable.begin(), end = adjustable.end(); it != end;) { + std::list::iterator next = it; ++next; + free -= (*it)->minSize().width(); + if (free < 0) free = 0; + if ((*it)->maxSize().width() - (*it)->minSize().width() <= 0) + adjustable.erase(it); + it = next; + } + // some widgets may have max widths that restrict them, find the 'true' + // amount of free space after these widgets are not included + if (!adjustable.empty()) { + do { + each = free / adjustable.size(); + for (it = adjustable.begin(), end = adjustable.end(); it != end;) { + std::list::iterator next = it; ++next; + unsigned int m = (*it)->maxSize().width() - (*it)->minSize().width(); + if (m > 0 && m < each) { + free -= m; + if (free < 0) free = 0; + adjustable.erase(it); + break; // if one is found to be fixed, then the free space needs to + // change, and the rest need to be reexamined + } + it = next; + } + } while (it != end && !adjustable.empty()); + } - prev_widget = tmp; + // place/size the widgets + if (!adjustable.empty()) + each = free / adjustable.size(); + else + each = 0; + for (it = visible.begin(), end = visible.end(); it != end; ++it) { + unsigned int w; + // is the widget adjustable? + std::list::const_iterator + found = std::find(adjustable.begin(), adjustable.end(), *it); + if (found != adjustable.end()) { + // adjustable + w = (*it)->minSize().width() + each; + } else { + // fixed + w = (*it)->minSize().width(); + } + // align it vertically + int yy = y; + unsigned int hh = std::max(std::min(h, (*it)->_max_size.height()), + (*it)->_min_size.height()); + if (hh < h) { + switch(_alignment) { + case RenderStyle::RightBottomJustify: + yy += h - hh; + break; + case RenderStyle::CenterJustify: + yy += (h - hh) / 2; + break; + case RenderStyle::LeftTopJustify: + break; + } + } + (*it)->internal_moveresize(x, yy, w, hh); + (*it)->render(); + (*it)->layout(); + x += w + _bevel; } - internalResize(width, tallest + _bevel_width * 2); } -void Widget::adjustVert(void) +void Widget::layoutVert() { - if (_children.size() == 0) - return; - - Widget *tmp; - WidgetList::iterator it, end = _children.end(); - - int widest = 0; - int height = _bevel_width; - WidgetList stretchable; - - for (it = _children.begin(); it != end; ++it) { - tmp = *it; - if (tmp->isStretchableHorz()) - tmp->setWidth(_rect.width() > _bevel_width * 2 ? - _rect.width() - _bevel_width * 2 : _bevel_width); - if (tmp->isStretchableVert()) - stretchable.push_back(tmp); - else - height += tmp->_rect.height() + _bevel_width; - - if (tmp->_rect.width() > widest) - widest = tmp->_rect.width(); - } - - if (stretchable.size() > 0) { - WidgetList::iterator str_it = stretchable.begin(), - str_end = stretchable.end(); + std::list::iterator it, end; - int str_height = _rect.height() - height / stretchable.size(); - - for (; str_it != str_end; ++str_it) - (*str_it)->setHeight(str_height > _bevel_width ? - str_height - _bevel_width : _bevel_width); + // work with just the visible children + std::list visible = _children; + for (it = visible.begin(), end = visible.end(); it != end;) { + std::list::iterator next = it; ++next; + if (!(*it)->visible()) + visible.erase(it); + it = next; } - if (stretchable.size() > 0) - height = _rect.height(); - - Widget *prev_widget = 0; - - for (it = _children.begin(); it != end; ++it) { - tmp = *it; - int x, y; - - if (prev_widget) - y = prev_widget->_rect.y() + prev_widget->_rect.height() + _bevel_width; - else - y = _bevel_width; - x = (widest - tmp->_rect.width()) / 2 + _bevel_width; - tmp->move(x, y); + if (visible.empty()) return; - prev_widget = tmp; + if ((unsigned)(_borderwidth * 2 + _bevel * 2) > _area.width() || + (unsigned)(_borderwidth * 2 + _bevel * 2) > _area.height()) + return; // not worth laying anything out! + + int x, y; unsigned int w, h; // working area + x = y = _bevel; + w = _area.width() - _borderwidth * 2 - _bevel * 2; + h = _area.height() - _borderwidth * 2 - _bevel * 2; + + int free = h - (visible.size() - 1) * _bevel; + if (free < 0) free = 0; + unsigned int each; + + std::list adjustable = visible; + + // find the 'free' space, and how many children will be using it + for (it = adjustable.begin(), end = adjustable.end(); it != end;) { + std::list::iterator next = it; ++next; + free -= (*it)->minSize().height(); + if (free < 0) free = 0; + if ((*it)->maxSize().height() - (*it)->minSize().height() <= 0) + adjustable.erase(it); + it = next; } - - internalResize(widest + _bevel_width * 2, height); -} - -void Widget::update() -{ - WidgetList::iterator it = _children.begin(), end = _children.end(); - for (; it != end; ++it) - (*it)->update(); - - if (_dirty) { - adjust(); - render(); - XClearWindow(**display, _window); + // some widgets may have max heights that restrict them, find the 'true' + // amount of free space after these widgets are not included + if (!adjustable.empty()) { + do { + each = free / adjustable.size(); + for (it = adjustable.begin(), end = adjustable.end(); it != end;) { + std::list::iterator next = it; ++next; + unsigned int m = (*it)->maxSize().height() - (*it)->minSize().height(); + if (m > 0 && m < each) { + free -= m; + if (free < 0) free = 0; + adjustable.erase(it); + break; // if one is found to be fixed, then the free space needs to + // change, and the rest need to be reexamined + } + it = next; + } + } while (it != end && !adjustable.empty()); } - _dirty = false; + // place/size the widgets + if (!adjustable.empty()) + each = free / adjustable.size(); + else + each = 0; + for (it = visible.begin(), end = visible.end(); it != end; ++it) { + unsigned int h; + // is the widget adjustable? + std::list::const_iterator + found = std::find(adjustable.begin(), adjustable.end(), *it); + if (found != adjustable.end()) { + // adjustable + h = (*it)->minSize().height() + each; + } else { + // fixed + h = (*it)->minSize().height(); + } + // align it horizontally + int xx = x; + unsigned int ww = std::max(std::min(w, (*it)->_max_size.width()), + (*it)->_min_size.width()); + if (ww < w) { + switch(_alignment) { + case RenderStyle::RightBottomJustify: + xx += w - ww; + break; + case RenderStyle::CenterJustify: + xx += (w - ww) / 2; + break; + case RenderStyle::LeftTopJustify: + break; + } + } + (*it)->internal_moveresize(xx, y, ww, h); + (*it)->render(); + (*it)->layout(); + y += h + _bevel; + } } -void Widget::internalResize(int w, int h) +void Widget::render() { - assert(w > 0 && h > 0); - - bool fw = _fixed_width, fh = _fixed_height; + if (!_texture || !_dirty) return; + if ((unsigned)_borderwidth * 2 > _area.width() || + (unsigned)_borderwidth * 2 > _area.height()) + return; // no surface to draw on - if (! fw && ! fh) - resize(w, h); - else if (! fw) - resize(w, _rect.height()); - else if (! fh) - resize(_rect.width(), h); - - _fixed_width = fw; - _fixed_height = fh; -} + Surface *s = new Surface(_screen, Size(_area.width() - _borderwidth * 2, + _area.height() - _borderwidth * 2)); + display->renderControl(_screen)->drawBackground(*s, *_texture); -void Widget::addChild(Widget *child, bool front) -{ - assert(child); - if (front) - _children.push_front(child); - else - _children.push_back(child); -} + renderForeground(*s); // for inherited types to render onto the _surface -void Widget::removeChild(Widget *child) -{ - assert(child); - WidgetList::iterator it, end = _children.end(); - for (it = _children.begin(); it != end; ++it) { - if ((*it) == child) - break; - } + XSetWindowBackgroundPixmap(**display, _window, s->pixmap()); + XClearWindow(**display, _window); - if (it != _children.end()) - _children.erase(it); -} + // delete the old surface *after* its pixmap isn't in use anymore + if (_surface) delete _surface; -void Widget::setStyle(RenderStyle *style) -{ - assert(style); - _style = style; - _dirty = true; + _surface = s; - WidgetList::iterator it, end = _children.end(); - for (it = _children.begin(); it != end; ++it) - (*it)->setStyle(style); + _dirty = false; } - -void Widget::setEventDispatcher(EventDispatcher *disp) +void Widget::renderChildren() { - if (_event_dispatcher) - _event_dispatcher->clearHandler(_window); - _event_dispatcher = disp; - _event_dispatcher->registerHandler(_window, this); + std::list::iterator it, end = _children.end(); + for (it = _children.begin(); it != end; ++it) + (*it)->render(); } void Widget::exposeHandler(const XExposeEvent &e) { EventHandler::exposeHandler(e); -// XClearArea(**display, _window, e.x, e.y, e.width, e.height, false); + XClearArea(**display, _window, e.x, e.y, e.width, e.height, false); } void Widget::configureHandler(const XConfigureEvent &e) { - EventHandler::configureHandler(e); - if (_ignore_config) { _ignore_config--; } else { - int width = e.width; - int height = e.height; - XEvent ev; - while (XCheckTypedWindowEvent(**display, _window, ConfigureNotify, &ev)) { - width = ev.xconfigure.width; - height = ev.xconfigure.height; - } - - if (!(width == _rect.width() && height == _rect.height())) { - _dirty = true; - _rect.setSize(width, height); + ev.xconfigure.width = e.width; + ev.xconfigure.height = e.height; + while (XCheckTypedWindowEvent(**display, window(), ConfigureNotify, &ev)); + + if (!((unsigned)ev.xconfigure.width == area().width() && + (unsigned)ev.xconfigure.height == area().height())) { + _area = Rect(_area.position(), Size(e.width, e.height)); + update(); } - update(); } } diff --git a/otk/widget.hh b/otk/widget.hh index 3427e681..2e4de47e 100644 --- a/otk/widget.hh +++ b/otk/widget.hh @@ -2,179 +2,136 @@ #ifndef __widget_hh #define __widget_hh +#include "eventhandler.hh" #include "rect.hh" -#include "point.hh" -#include "rendertexture.hh" #include "renderstyle.hh" -#include "eventdispatcher.hh" -#include "display.hh" -#include "surface.hh" -extern "C" { -#include -} - -#include #include +#include +#include namespace otk { -class Widget : public EventHandler { +class Surface; +class RenderTexture; +class RenderColor; +class EventDispatcher; +class Widget : public EventHandler, public StyleNotify { public: - enum Direction { Horizontal, Vertical }; - typedef std::list WidgetList; - - Widget(Widget *parent, Direction = Horizontal); - Widget(EventDispatcher *event_dispatcher, RenderStyle *style, - Direction direction = Horizontal, Cursor cursor = 0, - int bevel_width = 1, bool override_redirect = false); - + Widget(int screen, EventDispatcher *ed, Direction direction = Horizontal, + int bevel = 3, bool overrideredir = false); + Widget(Widget *parent, Direction direction = Horizontal, int bevel = 3); virtual ~Widget(); - virtual void update(); - - void exposeHandler(const XExposeEvent &e); - void configureHandler(const XConfigureEvent &e); - - inline Window window(void) const { return _window; } - inline const Widget *parent(void) const { return _parent; } - inline const WidgetList &children(void) const { return _children; } - inline unsigned int screen(void) const { return _screen; } - inline const Rect &rect(void) const { return _rect; } - - void move(const Point &to); - void move(int x, int y); - - virtual void setWidth(int); - virtual void setHeight(int); - - virtual int width() const { return _rect.width(); } - virtual int height() const { return _rect.height(); } + inline int screen() const { return _screen; } + inline Window window() const { return _window; } + inline Widget *parent() const { return _parent; } + inline Direction direction() const { return _direction; } - virtual void resize(const Point &to); - virtual void resize(int x, int y); + inline RenderStyle::Justify alignment() const { return _alignment; } + void setAlignment(RenderStyle::Justify a); - virtual void setGeometry(const Rect &new_geom); - virtual void setGeometry(const Point &topleft, int width, int height); - virtual void setGeometry(int x, int y, int width, int height); - - inline bool isVisible(void) const { return _visible; }; - virtual void show(bool recursive = false); - virtual void hide(bool recursive = false); - - inline bool isFocused(void) const { return _focused; }; - virtual void focus(void); - virtual void unfocus(void); - - inline bool hasGrabbedMouse(void) const { return _grabbed_mouse; } - bool grabMouse(void); - void ungrabMouse(void); - - inline bool hasGrabbedKeyboard(void) const { return _grabbed_keyboard; } - bool grabKeyboard(void); - void ungrabKeyboard(void); - - inline RenderTexture *texture(void) const { return _texture; } - virtual void setTexture(RenderTexture *texture) - { _texture = texture; _dirty = true; } + inline long eventMask() const { return _event_mask; } + virtual void setEventMask(long e); + + inline const Rect& area() const { return _area; } + inline Rect usableArea() const { return Rect(_area.position(), + Size(_area.width() - + _borderwidth * 2, + _area.height() - + _borderwidth * 2));} + inline const Size& minSize() const { return _min_size; } + inline const Size& maxSize() const { return _max_size; } + virtual void setMaxSize(const Size &s); + + virtual void show(bool children = false); + virtual void hide(); + inline bool visible() const { return _visible; } - inline const RenderColor *borderColor(void) const { return _bcolor; } - virtual void setBorderColor(const RenderColor *color) { - assert(color); _bcolor = color; - XSetWindowBorder(**display, _window, color->pixel()); - } + virtual void update(); + virtual void refresh() { _dirty = true; render(); } + + virtual void setBevel(int b); + inline int bevel() const { return _bevel; } - inline int borderWidth(void) const { return _bwidth; } - void setBorderWidth(int width) { - _bwidth = width; - XSetWindowBorderWidth(**display, _window, width); - } + void move(const Point &p) + { moveresize(Rect(p, _area.size())); } + void resize(const Size &s) + { moveresize(Rect(_area.position(), s)); } + /*! + When a widget has a parent, this won't change the widget directly, but will + just cause the parent to re-layout all its children. + */ + virtual void moveresize(const Rect &r); - virtual void addChild(Widget *child, bool front = false); - virtual void removeChild(Widget *child); + inline const RenderColor *borderColor() const { return _bordercolor; } + virtual void setBorderColor(const RenderColor *c); - inline bool isStretchableHorz(void) const { return _stretchable_horz; } - void setStretchableHorz(bool s_horz = true) { _stretchable_horz = s_horz; } + inline int borderWidth() const { return _borderwidth; } + virtual void setBorderWidth(int w); - inline bool isStretchableVert(void) const { return _stretchable_vert; } - void setStretchableVert(bool s_vert = true) { _stretchable_vert = s_vert; } + const std::list& children() const { return _children; } - inline Cursor cursor(void) const { return _cursor; } - void setCursor(Cursor cursor) { - _cursor = cursor; - XDefineCursor(**display, _window, _cursor); - } + virtual void exposeHandler(const XExposeEvent &e); + virtual void configureHandler(const XConfigureEvent &e); + virtual void styleChanged(const RenderStyle &) {calcDefaultSizes();update();} - inline int bevelWidth(void) const { return _bevel_width; } - void setBevelWidth(int bevel_width) - { assert(bevel_width > 0); _bevel_width = bevel_width; } +protected: + virtual void addChild(Widget *w) { assert(w); _children.push_back(w); } + virtual void removeChild(Widget *w) { assert(w); _children.remove(w); } - inline Direction direction(void) const { return _direction; } - void setDirection(Direction dir) { _direction = dir; } + //! Find the default min/max sizes for the widget. Useful after the in-use + //! style has changed. + virtual void calcDefaultSizes() {}; - inline RenderStyle *style(void) const { return _style; } - virtual void setStyle(RenderStyle *style); + virtual void setMinSize(const Size &s); - inline long eventMask(void) const { return _event_mask; } - void setEventMask(long e); + //! Arrange the widget's children + virtual void layout(); + virtual void layoutHorz(); + virtual void layoutVert(); + virtual void render(); + virtual void renderForeground(Surface&) {}; + virtual void renderChildren(); - inline EventDispatcher *eventDispatcher(void) - { return _event_dispatcher; } - void setEventDispatcher(EventDispatcher *disp); + void createWindow(bool overrideredir); -protected: + RenderTexture *_texture; - bool _dirty; - bool _focused; - - virtual void adjust(void); - virtual void create(bool override_redirect = false); - virtual void adjustHorz(void); - virtual void adjustVert(void); - virtual void internalResize(int width, int height); - virtual void render(void); - virtual void renderForeground() {} // for overriding - - Window _window; +private: + void internal_moveresize(int x, int y, unsigned w, unsigned int h); + int _screen; Widget *_parent; - WidgetList _children; - - RenderStyle *_style; + Window _window; + Surface *_surface; + long _event_mask; + + RenderStyle::Justify _alignment; Direction _direction; - Cursor _cursor; - int _bevel_width; - int _ignore_config; + Rect _area; + //! This size is the size *inside* the border, so they won't match the + //! actual size of the widget + Size _min_size; + //! This size is the size *inside* the border, so they won't match the + //! actual size of the widget + Size _max_size; bool _visible; + + const RenderColor *_bordercolor; + int _borderwidth; + int _bevel; + bool _dirty; - bool _grabbed_mouse; - bool _grabbed_keyboard; - - bool _stretchable_vert; - bool _stretchable_horz; - - RenderTexture *_texture; - Pixmap _bg_pixmap; - unsigned int _bg_pixel; - - const RenderColor *_bcolor; - unsigned int _bwidth; - - Rect _rect; - unsigned int _screen; - - bool _fixed_width; - bool _fixed_height; - - long _event_mask; + std::list _children; - Surface *_surface; + EventDispatcher *_dispatcher; - EventDispatcher *_event_dispatcher; + int _ignore_config; }; }