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.
This commit is contained in:
Dana Jansens 2003-02-08 07:33:48 +00:00
parent d2df40965b
commit 99cd843fc6
28 changed files with 908 additions and 1578 deletions

View file

@ -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 \

View file

@ -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();
}

View file

@ -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;

View file

@ -7,6 +7,7 @@
#include "appwidget.hh"
#include "application.hh"
#include "property.hh"
#include "renderstyle.hh"
extern "C" {
#include <X11/Xlib.h>
@ -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();

View file

@ -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);

View file

@ -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;
}
void Button::setTexture(RenderTexture *texture)
{
FocusWidget::setTexture(texture);
_unpr_focus_tx = texture;
}
void Button::setUnfocusTexture(RenderTexture *texture)
{
FocusWidget::setUnfocusTexture(texture);
_unpr_unfocus_tx = texture;
styleChanged(*RenderStyle::style(screen()));
refresh();
}
void Button::buttonPressHandler(const XButtonEvent &e)
{
Widget::buttonPressHandler(e);
press(e.button);
update();
FocusWidget::buttonPressHandler(e);
}
void Button::buttonReleaseHandler(const XButtonEvent &e)
{
Widget::buttonReleaseHandler(e);
release(e.button);
update();
FocusWidget::buttonReleaseHandler(e);
}
void Button::setDefault(bool d)
{
_default = d;
styleChanged(*RenderStyle::style(screen()));
refresh();
}
void Button::styleChanged(const RenderStyle &style)
{
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);
}
}

View file

@ -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();
virtual ~Button();
inline const RenderTexture *getPressedFocusTexture(void) const
{ return _pressed_focus_tx; }
void setPressedFocusTexture(RenderTexture *texture)
{ _pressed_focus_tx = texture; }
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);
inline bool isPressed(void) const { return _pressed; }
void press(unsigned int mouse_button);
void release(unsigned int mouse_button);
void buttonPressHandler(const XButtonEvent &e);
void buttonReleaseHandler(const XButtonEvent &e);
virtual void setStyle(RenderStyle *style);
virtual inline bool isDefault() const { return _default; }
virtual void setDefault(bool d);
private:
virtual inline bool isPressed() const { return _pressed; }
virtual void press(unsigned int mouse_button);
virtual void release(unsigned int mouse_button);
virtual void buttonPressHandler(const XButtonEvent &e);
virtual void buttonReleaseHandler(const XButtonEvent &e);
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;
};
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -5,100 +5,138 @@
#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);
setTexture(style->labelUnfocusBackground());
_justify_horz = j;
refresh();
}
void Label::fitString(const std::string &str)
void Label::setVerticalJustify(RenderStyle::Justify j)
{
const Font *ft = style()->labelFont();
fitSize(ft->measureString(str), ft->height());
_justify_vert = j;
refresh();
}
void Label::fitSize(int w, int h)
void Label::setText(const ustring &text)
{
unsigned int sidemargin = _bevel_width * 2;
resize(w + sidemargin * 2, h + _bevel_width * 2);
}
bool utf = text.utf8();
std::string s = text.c_str(); // use a normal string, for its functionality
void Label::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);
_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);
}
Widget::update();
calcDefaultSizes();
}
void Label::renderForeground(void)
void Label::setFont(const Font *f)
{
Widget::renderForeground();
_font = f;
calcDefaultSizes();
}
const Font *ft = style()->labelFont();
unsigned int sidemargin = _bevel_width * 2;
void Label::calcDefaultSizes()
{
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;
}
setMinSize(Size(longest + borderWidth() * 2 + bevel() * 4,
_parsedtext.size() * _font->height() + borderWidth() * 2 +
bevel() * 2));
}
void Label::styleChanged(const RenderStyle &style)
{
_texture = style.labelFocusBackground();
_forecolor = style.textFocusColor();
_font = style.labelFont();
Widget::styleChanged(style);
calcDefaultSizes();
}
ustring t = _text; // the actual text to draw
int x = sidemargin; // x coord for the text
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;
// 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;
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);
}
}
}

View file

@ -3,33 +3,54 @@
#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;
};

View file

@ -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"

View file

@ -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);
foo.resize(otk::Size(100, 150));
// 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());
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();

View file

@ -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; }
inline int x() const { return _x; }
inline int y() const { return _y; }
//! Changes the y value to the new value specified
void setY(int y) { _y = y; }
//! Returns the y value
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

View file

@ -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;
}
}

View file

@ -1,256 +1,39 @@
// -*- 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) { }
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) {}
//! 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; }
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(); }
//! 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); }
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; }
//! 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);
inline const Point& position() const { return _p; }
inline const Size& size() const { return _s; }
//! 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;
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

View file

@ -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())

View file

@ -8,8 +8,49 @@
#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)
@ -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;

View file

@ -7,6 +7,7 @@
#include "font.hh"
#include <string>
#include <list>
namespace otk {
@ -16,11 +17,27 @@ struct PixmapMask {
PixmapMask() { mask = None; w = h = 0; }
};
class RenderStyle {
class RenderStyle;
class StyleNotify {
public:
enum TextJustify {
LeftJustify,
RightJustify,
//! 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:
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; }

View file

@ -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)));
/*

View file

@ -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 <string>
#include <vector>
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<Rect> _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<Rect> &xineramaAreas() const
{ return _xinerama_areas; }
inline bool isXineramaActive() const { return _xinerama_active; }
#endif
};

View file

@ -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,

View file

@ -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; }

View file

@ -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;

View file

@ -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 <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),
_surface(0),
_event_dispatcher(parent->eventDispatcher())
_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)
{
assert(parent);
parent->addChild(this);
create();
_event_dispatcher->registerHandler(_window, this);
createWindow(overrideredir);
_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),
Widget::Widget(Widget *parent, Direction direction, int bevel)
: _texture(0),
_screen(parent->_screen),
_parent(parent),
_window(0),
_surface(0),
_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)
{
_rect.setPos(x, y);
XMoveWindow(**display, _window, x, y);
_ignore_config++;
}
void Widget::resize(const Point &to)
{
resize(to.x(), to.y());
}
void Widget::resize(int w, int h)
{
assert(w > 0 && h > 0);
_fixed_width = _fixed_height = true;
setGeometry(_rect.x(), _rect.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);
}
void Widget::setGeometry(int x, int y, int width, int height)
{
_rect = Rect(x, y, width, height);
_dirty = true;
// 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;
}
void Widget::show(bool recursive)
{
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;
}
void Widget::hide(bool recursive)
{
if (! _visible)
return;
if (recursive) {
WidgetList::iterator it = _children.begin(), end = _children.end();
for (; it != end; ++it)
(*it)->hide();
}
XUnmapWindow(**display, _window);
_visible = false;
}
void Widget::focus(void)
{
_focused = true;
Widget::WidgetList::iterator it = _children.begin(),
end = _children.end();
for (; it != end; ++it)
(*it)->focus();
}
void Widget::unfocus(void)
{
_focused = false;
Widget::WidgetList::iterator it = _children.begin(),
end = _children.end();
for (; it != end; ++it)
(*it)->unfocus();
}
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;
}
void Widget::ungrabMouse(void)
{
if (! _grabbed_mouse)
return;
XUngrabPointer(**display, CurrentTime);
_grabbed_mouse = false;
}
bool Widget::grabKeyboard(void)
{
Status ret = XGrabKeyboard(**display, _window, True,
GrabModeSync, GrabModeAsync, CurrentTime);
_grabbed_keyboard = (ret == GrabSuccess);
return _grabbed_keyboard;
}
void Widget::ungrabKeyboard(void)
{
if (! _grabbed_keyboard)
return;
XUngrabKeyboard(**display, CurrentTime);
_grabbed_keyboard = false;
}
void Widget::render(void)
{
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
}
void Widget::adjust(void)
{
if (_direction == Horizontal)
adjustHorz();
else
adjustVert();
}
void Widget::adjustHorz(void)
{
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();
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);
}
Widget *prev_widget = 0;
for (it = _children.begin(); it != end; ++it) {
tmp = *it;
int x, y;
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);
prev_widget = tmp;
}
internalResize(width, tallest + _bevel_width * 2);
}
void Widget::adjustVert(void)
{
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();
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);
}
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);
prev_widget = tmp;
}
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();
_dirty = true;
if (parent())
parent()->layout(); // relay-out us and our siblings
else {
render();
XClearWindow(**display, _window);
layout();
}
}
void Widget::moveresize(const Rect &r)
{
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());
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);
update();
}
void Widget::internal_moveresize(int x, int y, unsigned w, unsigned int h)
{
assert(w > 0);
assert(h > 0);
assert(_borderwidth >= 0);
_dirty = true;
XMoveResizeWindow(**display, _window, x, y,
w - _borderwidth * 2,
h - _borderwidth * 2);
_ignore_config++;
_area = Rect(x, y, w, h);
}
void Widget::setAlignment(RenderStyle::Justify a)
{
_alignment = a;
layout();
}
void Widget::createWindow(bool overrideredir)
{
const ScreenInfo *info = display->screenInfo(_screen);
XSetWindowAttributes attrib;
unsigned long mask = CWEventMask | CWBorderPixel;
attrib.event_mask = _event_mask;
attrib.border_pixel = (_bordercolor ?
_bordercolor->pixel():
BlackPixel(**display, _screen));
if (overrideredir) {
mask |= CWOverrideRedirect;
attrib.override_redirect = true;
}
_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
_borderwidth = w;
XSetWindowBorderWidth(**display, _window, _borderwidth);
calcDefaultSizes();
update();
}
void Widget::setMinSize(const Size &s)
{
_min_size = s;
update();
}
void Widget::setMaxSize(const Size &s)
{
_max_size = s;
update();
}
void Widget::setBorderColor(const RenderColor *c)
{
_bordercolor = c;
XSetWindowBorder(**otk::display, _window,
c ? c->pixel() : BlackPixel(**otk::display, _screen));
}
void Widget::setBevel(int b)
{
_bevel = b;
calcDefaultSizes();
layout();
}
void Widget::layout()
{
if (_direction == Horizontal)
layoutHorz();
else
layoutVert();
}
void Widget::layoutHorz()
{
std::list<Widget*>::iterator it, end;
// 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 (visible.empty()) return;
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());
}
// 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;
}
}
void Widget::layoutVert()
{
std::list<Widget*>::iterator it, end;
// 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 (visible.empty()) return;
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;
}
// 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());
}
// 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::render()
{
if (!_texture || !_dirty) return;
if ((unsigned)_borderwidth * 2 > _area.width() ||
(unsigned)_borderwidth * 2 > _area.height())
return; // no surface to draw on
Surface *s = new Surface(_screen, Size(_area.width() - _borderwidth * 2,
_area.height() - _borderwidth * 2));
display->renderControl(_screen)->drawBackground(*s, *_texture);
renderForeground(*s); // for inherited types to render onto the _surface
XSetWindowBackgroundPixmap(**display, _window, s->pixmap());
XClearWindow(**display, _window);
// delete the old surface *after* its pixmap isn't in use anymore
if (_surface) delete _surface;
_surface = s;
_dirty = false;
}
void Widget::internalResize(int w, int h)
void Widget::renderChildren()
{
assert(w > 0 && h > 0);
bool fw = _fixed_width, fh = _fixed_height;
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;
}
void Widget::addChild(Widget *child, bool front)
{
assert(child);
if (front)
_children.push_front(child);
else
_children.push_back(child);
}
void Widget::removeChild(Widget *child)
{
assert(child);
WidgetList::iterator it, end = _children.end();
for (it = _children.begin(); it != end; ++it) {
if ((*it) == child)
break;
}
if (it != _children.end())
_children.erase(it);
}
void Widget::setStyle(RenderStyle *style)
{
assert(style);
_style = style;
_dirty = true;
WidgetList::iterator it, end = _children.end();
std::list<Widget*>::iterator it, end = _children.end();
for (it = _children.begin(); it != end; ++it)
(*it)->setStyle(style);
}
void Widget::setEventDispatcher(EventDispatcher *disp)
{
if (_event_dispatcher)
_event_dispatcher->clearHandler(_window);
_event_dispatcher = disp;
_event_dispatcher->registerHandler(_window, this);
(*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;
}
ev.xconfigure.width = e.width;
ev.xconfigure.height = e.height;
while (XCheckTypedWindowEvent(**display, window(), ConfigureNotify, &ev));
if (!(width == _rect.width() && height == _rect.height())) {
_dirty = true;
_rect.setSize(width, height);
if (!((unsigned)ev.xconfigure.width == area().width() &&
(unsigned)ev.xconfigure.height == area().height())) {
_area = Rect(_area.position(), Size(e.width, e.height));
update();
}
update();
}
}

View file

@ -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 <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();
inline int screen() const { return _screen; }
inline Window window() const { return _window; }
inline Widget *parent() const { return _parent; }
inline Direction direction() const { return _direction; }
inline RenderStyle::Justify alignment() const { return _alignment; }
void setAlignment(RenderStyle::Justify a);
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; }
virtual void update();
virtual void refresh() { _dirty = true; render(); }
virtual void setBevel(int b);
inline int bevel() const { return _bevel; }
void exposeHandler(const XExposeEvent &e);
void configureHandler(const XConfigureEvent &e);
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);
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; }
inline const RenderColor *borderColor() const { return _bordercolor; }
virtual void setBorderColor(const RenderColor *c);
void move(const Point &to);
void move(int x, int y);
inline int borderWidth() const { return _borderwidth; }
virtual void setBorderWidth(int w);
virtual void setWidth(int);
virtual void setHeight(int);
const std::list<Widget*>& children() const { return _children; }
virtual int width() const { return _rect.width(); }
virtual int height() const { return _rect.height(); }
virtual void resize(const Point &to);
virtual void resize(int x, int y);
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 const RenderColor *borderColor(void) const { return _bcolor; }
virtual void setBorderColor(const RenderColor *color) {
assert(color); _bcolor = color;
XSetWindowBorder(**display, _window, color->pixel());
}
inline int borderWidth(void) const { return _bwidth; }
void setBorderWidth(int width) {
_bwidth = width;
XSetWindowBorderWidth(**display, _window, width);
}
virtual void addChild(Widget *child, bool front = false);
virtual void removeChild(Widget *child);
inline bool isStretchableHorz(void) const { return _stretchable_horz; }
void setStretchableHorz(bool s_horz = true) { _stretchable_horz = s_horz; }
inline bool isStretchableVert(void) const { return _stretchable_vert; }
void setStretchableVert(bool s_vert = true) { _stretchable_vert = s_vert; }
inline Cursor cursor(void) const { return _cursor; }
void setCursor(Cursor cursor) {
_cursor = cursor;
XDefineCursor(**display, _window, _cursor);
}
inline int bevelWidth(void) const { return _bevel_width; }
void setBevelWidth(int bevel_width)
{ assert(bevel_width > 0); _bevel_width = bevel_width; }
inline Direction direction(void) const { return _direction; }
void setDirection(Direction dir) { _direction = dir; }
inline RenderStyle *style(void) const { return _style; }
virtual void setStyle(RenderStyle *style);
inline long eventMask(void) const { return _event_mask; }
void setEventMask(long e);
inline EventDispatcher *eventDispatcher(void)
{ return _event_dispatcher; }
void setEventDispatcher(EventDispatcher *disp);
virtual void exposeHandler(const XExposeEvent &e);
virtual void configureHandler(const XConfigureEvent &e);
virtual void styleChanged(const RenderStyle &) {calcDefaultSizes();update();}
protected:
bool _dirty;
bool _focused;
virtual void addChild(Widget *w) { assert(w); _children.push_back(w); }
virtual void removeChild(Widget *w) { assert(w); _children.remove(w); }
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
//! Find the default min/max sizes for the widget. Useful after the in-use
//! style has changed.
virtual void calcDefaultSizes() {};
Window _window;
virtual void setMinSize(const Size &s);
Widget *_parent;
WidgetList _children;
//! Arrange the widget's children
virtual void layout();
virtual void layoutHorz();
virtual void layoutVert();
virtual void render();
virtual void renderForeground(Surface&) {};
virtual void renderChildren();
RenderStyle *_style;
Direction _direction;
Cursor _cursor;
int _bevel_width;
int _ignore_config;
bool _visible;
bool _grabbed_mouse;
bool _grabbed_keyboard;
bool _stretchable_vert;
bool _stretchable_horz;
void createWindow(bool overrideredir);
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;
private:
void internal_moveresize(int x, int y, unsigned w, unsigned int h);
int _screen;
Widget *_parent;
Window _window;
Surface *_surface;
long _event_mask;
RenderStyle::Justify _alignment;
Direction _direction;
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;
EventDispatcher *_event_dispatcher;
bool _visible;
const RenderColor *_bordercolor;
int _borderwidth;
int _bevel;
bool _dirty;
std::list<Widget*> _children;
EventDispatcher *_dispatcher;
int _ignore_config;
};
}