add otk::MessageDialog
Dana Jansens danakj@orodu.net
8 files changed,
244 insertions(+),
2 deletions(-)
M
otk/.cvsignore
→
otk/.cvsignore
@@ -37,6 +37,7 @@ surface.lo
rendertexture.lo rendertest renderstyle.lo +messagedialog.lo rendercontrol.lo rendercolor.lo otk.py
M
otk/Makefile.am
→
otk/Makefile.am
@@ -11,7 +11,7 @@ renderstyle.cc rendercolor.cc pseudorendercontrol.cc \
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 \ - otk.cc + otk.cc messagedialog.cc #focuswidget.cc focuslabel.cc@@ -21,7 +21,7 @@ label.hh otk.hh point.hh property.hh pseudorendercontrol.hh\
rect.hh rendercolor.hh rendercontrol.hh renderstyle.hh \ rendertexture.hh screeninfo.hh size.hh strut.hh surface.hh \ timer.hh truerendercontrol.hh ustring.hh util.hh widget.hh \ - ../config.h + messagedialog.hh ../config.h EXTRA_DIST = otk.pc.in
A
otk/messagedialog.cc
@@ -0,0 +1,168 @@
+// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- + +#include "config.h" + +#include "messagedialog.hh" +#include "assassin.hh" +#include "button.hh" +#include "label.hh" +#include "display.hh" +#include "property.hh" +#include "eventdispatcher.hh" +#include "timer.hh" + +#include <algorithm> + +namespace otk { + +DialogButton MessageDialog::_default_result("", false); + +class DialogButtonWidget : public Button { + MessageDialog *_dia; + const DialogButton &_res; +public: + DialogButtonWidget(Widget *parent, MessageDialog *dia, + const DialogButton &b) + : Button(parent), + _dia(dia), + _res(b) + { + assert(dia); + setBevel(1); + setMaxSize(Size(0,0)); + setText(b.label()); + setHighlighted(b.isDefault()); + show(); + } + + virtual void buttonPressHandler(const XButtonEvent &e) { + // limit to the left button + if (e.button == Button1) + Button::buttonPressHandler(e); + } + virtual void clickHandler(unsigned int) { + _dia->setResult(_res); + _dia->hide(); + } +}; + +MessageDialog::MessageDialog(int screen, EventDispatcher *ed, ustring title, + ustring caption) + : Widget(screen, ed, Widget::Vertical) +{ + init(title, caption); +} + +MessageDialog::MessageDialog(EventDispatcher *ed, ustring title, + ustring caption) + : Widget(DefaultScreen(**display), ed, Widget::Vertical) +{ + init(title, caption); +} + +MessageDialog::MessageDialog(Widget *parent, ustring title, ustring caption) + : Widget(parent, Widget::Vertical) +{ + init(title, caption); +} + +void MessageDialog::init(const ustring &title, const ustring &caption) +{ + _label = new Label(this); + _label->show(); + _label->setHighlighted(true); + _button_holder = new Widget(this, Widget::Horizontal); + _button_holder->show(); + _return = XKeysymToKeycode(**display, XStringToKeysym("Return")); + _escape = XKeysymToKeycode(**display, XStringToKeysym("Escape")); + _result = &_default_result; + + setEventMask(eventMask() | KeyPressMask); + _label->setText(caption); + if (title.utf8()) + otk::Property::set(window(), otk::Property::atoms.net_wm_name, + otk::Property::utf8, title); + otk::Property::set(window(), otk::Property::atoms.wm_name, + otk::Property::ascii, otk::ustring(title.c_str(), false)); + + // set WM Protocols on the window + Atom protocols[2]; + protocols[0] = Property::atoms.wm_protocols; + protocols[1] = Property::atoms.wm_delete_window; + XSetWMProtocols(**display, window(), protocols, 2); +} + +MessageDialog::~MessageDialog() +{ + if (visible()) hide(); + delete _button_holder; + delete _label; +} + +const DialogButton& MessageDialog::run() +{ + show(); + + while (visible()) { + dispatcher()->dispatchEvents(); + if (visible()) + Timer::dispatchTimers(); // fire pending events + } + return *_result; +} + +void MessageDialog::show() +{ + std::vector<DialogButton>::const_iterator it, end = _buttons.end(); + for (it = _buttons.begin(); it != end; ++it) + _button_widgets.push_back(new DialogButtonWidget(_button_holder, + this, *it)); + + XSizeHints size; + size.flags = PMinSize; + size.min_width = minSize().width(); + size.min_height = minSize().height(); + XSetWMNormalHints(**display, window(), &size); + + Size dest = area().size(); + if (dest.width() < 200 || dest.height() < 100) { + if (dest.width() < 200 && dest.height() < 100) dest = Size(200, 100); + else if (dest.width() < 200) dest = Size(200, dest.height()); + else dest = Size(dest.width(), 100); + resize(dest); + } + + Widget::show(); +} + +void MessageDialog::hide() +{ + Widget::hide(); + std::for_each(_button_widgets.begin(), _button_widgets.end(), + PointerAssassin()); +} + +void MessageDialog::keyPressHandler(const XKeyEvent &e) +{ + if (e.keycode == _return) { + std::vector<DialogButton>::const_iterator it, end = _buttons.end(); + for (it = _buttons.begin(); it != end; ++it) + if (it->isDefault()) { + _result = &(*it); + break; + } + hide(); + } else if (e.keycode == _escape) { + hide(); + } +} + +void MessageDialog::clientMessageHandler(const XClientMessageEvent &e) +{ + EventHandler::clientMessageHandler(e); + if (e.message_type == Property::atoms.wm_protocols && + static_cast<Atom>(e.data.l[0]) == Property::atoms.wm_delete_window) + hide(); +} + +}
A
otk/messagedialog.hh
@@ -0,0 +1,66 @@
+// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- +#ifndef __messagedialog_hh +#define __messagedialog_hh + +#include "widget.hh" +#include "ustring.hh" + +#include <vector> + +namespace otk { + +class Button; +class Label; + +class DialogButton { + ustring _label; + bool _default; +public: + DialogButton(char *label) : _label(label), _default(false) + {} + DialogButton(ustring label) : _label(label), _default(false) + {} + DialogButton(ustring label, bool def) : _label(label), _default(def) + {} + inline const ustring& label() const { return _label; } + inline const bool& isDefault() const { return _default; } +}; + +class MessageDialog : public Widget { +public: + MessageDialog(int screen, EventDispatcher *ed, ustring title, + ustring caption); + MessageDialog(EventDispatcher *ed, ustring title, ustring caption); + MessageDialog(Widget *parent, ustring title, ustring caption); + virtual ~MessageDialog(); + + virtual void addButton(const DialogButton &b) { _buttons.push_back(b); } + + virtual const DialogButton& run(); + + virtual void show(); + virtual void hide(); + + virtual const DialogButton& result() const { return *_result; } + virtual void setResult(const DialogButton &result) { _result = &result; } + + virtual void keyPressHandler(const XKeyEvent &e); + virtual void clientMessageHandler(const XClientMessageEvent &e); + +private: + static DialogButton _default_result; + + void init(const ustring &title, const ustring &caption); + + std::vector<DialogButton> _buttons; + std::vector<Button *> _button_widgets; + Label *_label; + Widget *_button_holder; + KeyCode _return; + KeyCode _escape; + const DialogButton *_result; +}; + +} + +#endif // __messagedialog_hh
M
otk/otk.hh
→
otk/otk.hh
@@ -15,6 +15,7 @@ #include "button.hh"
#include "rendercolor.hh" #include "display.hh" #include "font.hh" +#include "messagedialog.hh" #include "rendercontrol.hh" #include "size.hh" #include "point.hh"
M
otk/widget.hh
→
otk/widget.hh
@@ -100,6 +100,8 @@
void createWindow(bool overrideredir); RenderTexture *_texture; + + EventDispatcher *dispatcher() const { return _dispatcher; } private: void internal_moveresize(int x, int y, int w, int h);