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:
parent
d2df40965b
commit
99cd843fc6
28 changed files with 908 additions and 1578 deletions
|
@ -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 \
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
154
otk/label.cc
154
otk/label.cc
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
39
otk/label.hh
39
otk/label.hh
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
32
otk/point.hh
32
otk/point.hh
|
@ -2,40 +2,22 @@
|
|||
#ifndef __point_hh
|
||||
#define __point_hh
|
||||
|
||||
/*! @file point.hh
|
||||
@brief The Point class contains an x/y pair
|
||||
*/
|
||||
|
||||
namespace otk {
|
||||
|
||||
//! The Point class is an x/y coordinate or size pair
|
||||
class Point {
|
||||
private:
|
||||
//! The x value
|
||||
int _x;
|
||||
//! The y value
|
||||
int _y;
|
||||
|
||||
int _x, _y;
|
||||
public:
|
||||
//! Constructs a new Point with 0,0 values
|
||||
Point() : _x(0), _y(0) {}
|
||||
//! Constructs a new Point with given values
|
||||
Point(int x, int y) : _x(x), _y(y) {}
|
||||
Point(const Point &p) : _x(p._x), _y(p._y) {}
|
||||
|
||||
//! Changes the x value to the new value specified
|
||||
void setX(int x) { _x = x; }
|
||||
//! Returns the x value
|
||||
int x() const { return _x; }
|
||||
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
|
||||
|
|
151
otk/rect.cc
151
otk/rect.cc
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
261
otk/rect.hh
261
otk/rect.hh
|
@ -1,256 +1,39 @@
|
|||
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
|
||||
#ifndef __rect_hh
|
||||
#define __rect_hh
|
||||
|
||||
extern "C" {
|
||||
#include <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
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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)));
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
877
otk/widget.cc
877
otk/widget.cc
|
@ -1,522 +1,485 @@
|
|||
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "../config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include "config.h"
|
||||
#include "widget.hh"
|
||||
#include "display.hh"
|
||||
#include "assassin.hh"
|
||||
#include "surface.hh"
|
||||
#include "rendertexture.hh"
|
||||
#include "rendercolor.hh"
|
||||
#include "eventdispatcher.hh"
|
||||
#include "screeninfo.hh"
|
||||
#include "focuslabel.hh"
|
||||
|
||||
#include <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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
243
otk/widget.hh
243
otk/widget.hh
|
@ -2,179 +2,136 @@
|
|||
#ifndef __widget_hh
|
||||
#define __widget_hh
|
||||
|
||||
#include "eventhandler.hh"
|
||||
#include "rect.hh"
|
||||
#include "point.hh"
|
||||
#include "rendertexture.hh"
|
||||
#include "renderstyle.hh"
|
||||
#include "eventdispatcher.hh"
|
||||
#include "display.hh"
|
||||
#include "surface.hh"
|
||||
|
||||
extern "C" {
|
||||
#include <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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue