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.
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 \
#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
(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();
}
#include "eventdispatcher.hh"
#include "display.hh"
-#include "renderstyle.hh"
namespace otk {
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;
#include "appwidget.hh"
#include "application.hh"
#include "property.hh"
+#include "renderstyle.hh"
extern "C" {
#include <X11/Xlib.h>
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);
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();
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);
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);
}
}
#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;
};
}
+++ /dev/null
-// -*- 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);
-}
-
-}
+++ /dev/null
-// -*- 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
+++ /dev/null
-// -*- 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;
-}
-
-}
+++ /dev/null
-// -*- 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
#endif
#include "label.hh"
+#include "display.hh"
+#include "rendercontrol.hh"
+
+#include <string>
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<ustring>::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<ustring>::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);
+ }
}
}
#define __label_hh
#include "widget.hh"
+#include "ustring.hh"
+#include "renderstyle.hh"
+#include "font.hh"
+
+#include <vector>
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<ustring> _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;
};
#include "eventdispatcher.hh"
#include "eventhandler.hh"
#include "widget.hh"
-#include "focuswidget.hh"
-#include "focuslabel.hh"
#include "appwidget.hh"
#include "application.hh"
#include "assassin.hh"
#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"
#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();
#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
+++ /dev/null
-// -*- 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;
-}
-
-}
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
-#ifndef __rect_hh
-#define __rect_hh
-
-extern "C" {
-#include <X11/Xlib.h>
-}
+#ifndef __rect_hh
+#define __rect_hh
#include "point.hh"
-#include <vector>
+#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<Rect> RectList;
-
}
#endif // __rect_hh
#include "pseudorendercontrol.hh"
#include "rendertexture.hh"
#include "rendercolor.hh"
+#include "renderstyle.hh"
#include "display.hh"
#include "screeninfo.hh"
#include "surface.hh"
: _screen(screen)
{
printf("Initializing RenderControl\n");
-
-
}
RenderControl::~RenderControl()
{
printf("Destroying RenderControl\n");
-
-
}
void RenderControl::drawRoot(const RenderColor &color) const
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())
#include "display.hh"
#include "screeninfo.hh"
+#include <cassert>
+
namespace otk {
+RenderStyle **RenderStyle::_styles = 0;
+std::list<StyleNotify*> *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<StyleNotify*>[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)
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;
#include "font.hh"
#include <string>
+#include <list>
namespace otk {
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<StyleNotify*> *_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
};
RenderTexture *_grip_unfocus;
Font *_label_font;
- TextJustify _label_justify;
+ Justify _label_justify;
PixmapMask *_max_mask;
PixmapMask *_icon_mask;
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; }
_root_window = RootWindow(**display, _screen);
- _rect.setSize(WidthOfScreen(ScreenOfDisplay(**display,
- _screen)),
+ _size = Size(WidthOfScreen(ScreenOfDisplay(**display,
+ _screen)),
HeightOfScreen(ScreenOfDisplay(**display,
_screen)));
/*
#ifndef __screeninfo_hh
#define __screeninfo_hh
+#include "size.hh"
#include "rect.hh"
extern "C" {
}
#include <string>
+#include <vector>
namespace otk {
int _depth;
unsigned int _screen;
std::string _display_string;
- Rect _rect;
+ Size _size;
#ifdef XINERAMA
- RectList _xinerama_areas;
+ std::vector<Rect> _xinerama_areas;
bool _xinerama_active;
#endif
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<Rect> &xineramaAreas() const
+ { return _xinerama_areas; }
inline bool isXineramaActive() const { return _xinerama_active; }
#endif
};
namespace otk {
-Surface::Surface(int screen, const Point &size)
+Surface::Surface(int screen, const Size &size)
: _screen(screen),
_size(size),
_pixmap(None),
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()
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,
#ifndef __surface_hh
#define __surface_hh
-#include "point.hh"
+#include "size.hh"
#include "truerendercontrol.hh"
#include "pseudorendercontrol.hh"
class Surface {
int _screen;
- Point _size;
+ Size _size;
Pixmap _pixmap;
XftDraw *_xftdraw;
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; }
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()) {
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);
+ }
}
}
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;
}
}
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;
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;
// -*- 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 <climits>
+#include <cassert>
#include <algorithm>
-#include <iostream>
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<Widget*>::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<Widget*>::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<Widget*> visible = _children;
+ for (it = visible.begin(), end = visible.end(); it != end;) {
+ std::list<Widget*>::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<Widget*> 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<Widget*>::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<Widget*>::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<Widget*>::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<Widget*>::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<Widget*> visible = _children;
+ for (it = visible.begin(), end = visible.end(); it != end;) {
+ std::list<Widget*>::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<Widget*> 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<Widget*>::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<Widget*>::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<Widget*>::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<Widget*>::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();
}
}
#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 <assert.h>
-}
-
-#include <string>
#include <list>
+#include <algorithm>
+#include <cassert>
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<Widget *> 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<Widget*>& 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<Widget*> _children;
- Surface *_surface;
+ EventDispatcher *_dispatcher;
- EventDispatcher *_event_dispatcher;
+ int _ignore_config;
};
}