--- /dev/null
+// -*- 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();
+}
+
+}
--- /dev/null
+// -*- 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