summaryrefslogtreecommitdiff
path: root/dw/fltkui.hh
diff options
context:
space:
mode:
Diffstat (limited to 'dw/fltkui.hh')
-rw-r--r--dw/fltkui.hh505
1 files changed, 505 insertions, 0 deletions
diff --git a/dw/fltkui.hh b/dw/fltkui.hh
new file mode 100644
index 0000000..fa47992
--- /dev/null
+++ b/dw/fltkui.hh
@@ -0,0 +1,505 @@
+#ifndef __DW_FLTK_UI_HH__
+#define __DW_FLTK_UI_HH__
+
+#ifndef __INCLUDED_FROM_DW_FLTK_CORE_HH__
+# error Do not include this file directly, use "fltkcore.hh" instead.
+#endif
+
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Menu.H>
+#include <FL/Fl_Text_Buffer.H>
+
+namespace dw {
+namespace fltk {
+
+/**
+ * \brief FLTK implementation of dw::core::ui.
+ *
+ * <div style="border: 2px solid #ff0000; margin-top: 0.5em;
+ * margin-bottom: 0.5em; padding: 0.5em 1em;
+ * background-color: #ffefe0"><b>Update:</b> The complicated design
+ * results from my insufficient knowledge of C++ some years ago; since
+ * then, I've learned how to deal with "diamond inheritance", as the
+ * (ideal, not actually implemented) design in the first diagram
+ * shows. It should be possible to implement this ideal design in a
+ * straightforward way, and so get rid of templates. --SG</div>
+ *
+ * The design should be like this:
+ *
+ * \dot
+ * digraph G {
+ * node [shape=record, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="none", arrowtail="empty", dir="both",
+ * labelfontname=Helvetica, labelfontsize=10, color="#404040",
+ * labelfontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ *
+ * subgraph cluster_core {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::core::ui";
+ *
+ * Resource [color="#a0a0a0", URL="\ref dw::core::ui::Resource"];
+ * LabelButtonResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::LabelButtonResource"];
+ * EntryResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::EntryResource"];
+ * }
+ *
+ * subgraph cluster_fltk {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::fltk::ui";
+ *
+ * FltkResource [color="#a0a0a0", URL="\ref dw::fltk::ui::FltkResource"];
+ * FltkLabelButtonResource
+ * [URL="\ref dw::fltk::ui::FltkLabelButtonResource"];
+ * FltkEntryResource [URL="\ref dw::fltk::ui::FltkEntryResource"];
+ * }
+ *
+ * Resource -> LabelButtonResource;
+ * Resource -> EntryResource;
+ * FltkResource -> FltkLabelButtonResource;
+ * FltkResource -> FltkEntryResource;
+ * Resource -> FltkResource;
+ * LabelButtonResource -> FltkLabelButtonResource;
+ * EntryResource -> FltkEntryResource;
+ * }
+ * \enddot
+ *
+ * <center>[\ref uml-legend "legend"]</center>
+ *
+ * where dw::fltk::ui::FltkResource provides some base funtionality for all
+ * conctrete FLTK implementations of sub-interfaces of dw::core::ui::Resource.
+ * However, this is not directly possible in C++, since the base class
+ * dw::core::ui::Resource is ambiguous for
+ * dw::fltk::ui::FltkLabelButtonResource.
+ *
+ * To solve this, we have to remove the dependency between
+ * dw::fltk::ui::FltkResource and dw::core::ui::Resource, instead, the part
+ * of dw::core::ui::Resource, which is implemented in
+ * dw::fltk::ui::FltkResource, must be explicitly delegated from
+ * dw::fltk::ui::FltkLabelButtonResourceto dw::fltk::ui::FltkResource:
+ *
+ * \dot
+ * digraph G {
+ * node [shape=record, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="none", arrowtail="empty", dir="both",
+ * labelfontname=Helvetica, labelfontsize=10, color="#404040",
+ * labelfontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ *
+ * subgraph cluster_core {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::core::ui";
+ *
+ * Resource [color="#a0a0a0", URL="\ref dw::core::ui::Resource"];
+ * LabelButtonResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::LabelButtonResource"];
+ * EntryResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::EntryResource"];
+ * }
+ *
+ * subgraph cluster_fltk {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::fltk::ui";
+ *
+ * FltkResource [color="#a0a0a0", URL="\ref dw::fltk::ui::FltkResource"];
+ * FltkLabelButtonResource
+ * [URL="\ref dw::fltk::ui::FltkLabelButtonResource"];
+ * FltkEntryResource [URL="\ref dw::fltk::ui::FltkEntryResource"];
+ * }
+ *
+ * Resource -> LabelButtonResource;
+ * Resource -> EntryResource;
+ * FltkResource -> FltkLabelButtonResource;
+ * FltkResource -> FltkEntryResource;
+ * LabelButtonResource -> FltkLabelButtonResource;
+ * EntryResource -> FltkEntryResource;
+ * }
+ * \enddot
+ *
+ * <center>[\ref uml-legend "legend"]</center>
+ *
+ * To make this a bit simpler, we use templates:
+ *
+ * \dot
+ * digraph G {
+ * node [shape=record, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="none", arrowtail="empty", dir="both",
+ * labelfontname=Helvetica, labelfontsize=10, color="#404040",
+ * labelfontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ *
+ * subgraph cluster_core {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::core::ui";
+ *
+ * Resource [color="#a0a0a0", URL="\ref dw::core::ui::Resource"];
+ * LabelButtonResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::LabelButtonResource"];
+ * EntryResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::EntryResource"];
+ * }
+ *
+ * subgraph cluster_fltk {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::fltk::ui";
+ *
+ * FltkResource [color="#a0a0a0", URL="\ref dw::fltk::ui::FltkResource"];
+ * FltkSpecificResource [color="#a0a0a0",
+ * fillcolor="#ffffc0", style="filled"
+ * URL="\ref dw::fltk::ui::FltkSpecificResource"];
+ * FltkSpecificResource_button [color="#a0a0a0",
+ * label="FltkSpecificResource \<LabelButtonResource\>"];
+ * FltkSpecificResource_entry [color="#a0a0a0",
+ * label="FltkSpecificResource \<EntryResource\>"];
+ * FltkEntryResource [URL="\ref dw::fltk::ui::FltkEntryResource"];
+ * FltkLabelButtonResource
+ * [URL="\ref dw::fltk::ui::FltkLabelButtonResource"];
+ * }
+ *
+ * Resource -> LabelButtonResource;
+ * Resource -> EntryResource;
+ * FltkResource -> FltkSpecificResource;
+ * FltkSpecificResource -> FltkSpecificResource_button [arrowhead="open",
+ * arrowtail="none",
+ * dir="both",
+ * style="dashed",
+ * color="#808000"];
+ * FltkSpecificResource -> FltkSpecificResource_entry [arrowhead="open",
+ * arrowtail="none",
+ * dir="both",
+ * style="dashed",
+ * color="#808000"];
+ * LabelButtonResource -> FltkSpecificResource_button;
+ * EntryResource -> FltkSpecificResource_entry;
+ * FltkSpecificResource_button -> FltkLabelButtonResource;
+ * FltkSpecificResource_entry -> FltkEntryResource;
+ * }
+ * \enddot
+ *
+ * <center>[\ref uml-legend "legend"]</center>
+ */
+namespace ui {
+
+/**
+ * ...
+ */
+class FltkResource: public lout::object::Object
+{
+private:
+ bool enabled;
+
+protected:
+ FltkView *view;
+ Fl_Widget *widget;
+ core::Allocation allocation;
+ FltkPlatform *platform;
+
+ core::style::Style *style;
+
+ FltkResource (FltkPlatform *platform);
+ void init (FltkPlatform *platform);
+ virtual Fl_Widget *createNewWidget (core::Allocation *allocation) = 0;
+
+ virtual void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+ void setDisplayed (bool displayed);
+ bool displayed();
+public:
+ ~FltkResource ();
+
+ virtual void attachView (FltkView *view);
+ virtual void detachView (FltkView *view);
+
+ void sizeAllocate (core::Allocation *allocation);
+ void draw (core::View *view, core::Rectangle *area);
+
+ void setStyle (core::style::Style *style);
+
+ bool isEnabled ();
+ void setEnabled (bool enabled);
+};
+
+
+template <class I> class FltkSpecificResource: public I, public FltkResource
+{
+public:
+ FltkSpecificResource (FltkPlatform *platform);
+ ~FltkSpecificResource ();
+
+ void sizeAllocate (core::Allocation *allocation);
+ void draw (core::View *view, core::Rectangle *area);
+ void setStyle (core::style::Style *style);
+
+ bool isEnabled ();
+ void setEnabled (bool enabled);
+};
+
+
+class FltkLabelButtonResource:
+ public FltkSpecificResource <dw::core::ui::LabelButtonResource>
+{
+private:
+ const char *label;
+
+ static void widgetCallback (Fl_Widget *widget, void *data);
+
+protected:
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+
+public:
+ FltkLabelButtonResource (FltkPlatform *platform, const char *label);
+ ~FltkLabelButtonResource ();
+
+ void sizeRequest (core::Requisition *requisition);
+
+ const char *getLabel ();
+ void setLabel (const char *label);
+};
+
+/**
+ * \bug Maximal length not supported yet.
+ * \todo Text values are not synchronized (not needed in dillo).
+ */
+class FltkEntryResource:
+ public FltkSpecificResource <dw::core::ui::EntryResource>
+{
+private:
+ int size;
+ bool password;
+ const char *initText;
+ char *label;
+ int label_w;
+ bool editable;
+
+ static void widgetCallback (Fl_Widget *widget, void *data);
+ void setDisplayed (bool displayed);
+
+protected:
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+ void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+
+public:
+ FltkEntryResource (FltkPlatform *platform, int size, bool password,
+ const char *label);
+ ~FltkEntryResource ();
+
+ void sizeRequest (core::Requisition *requisition);
+ void sizeAllocate (core::Allocation *allocation);
+
+ const char *getText ();
+ void setText (const char *text);
+ bool isEditable ();
+ void setEditable (bool editable);
+ void setMaxLength (int maxlen);
+};
+
+
+class FltkMultiLineTextResource:
+ public FltkSpecificResource <dw::core::ui::MultiLineTextResource>
+{
+private:
+ Fl_Text_Buffer *buffer;
+ char *text_copy;
+ bool editable;
+ int numCols, numRows;
+
+protected:
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+ void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+
+public:
+ FltkMultiLineTextResource (FltkPlatform *platform, int cols, int rows);
+ ~FltkMultiLineTextResource ();
+
+ void sizeRequest (core::Requisition *requisition);
+
+ const char *getText ();
+ void setText (const char *text);
+ bool isEditable ();
+ void setEditable (bool editable);
+};
+
+
+template <class I> class FltkToggleButtonResource:
+ public FltkSpecificResource <I>
+{
+private:
+ bool initActivated;
+
+protected:
+ virtual Fl_Button *createNewButton (core::Allocation *allocation) = 0;
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+ void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+
+public:
+ FltkToggleButtonResource (FltkPlatform *platform,
+ bool activated);
+ ~FltkToggleButtonResource ();
+
+ void sizeRequest (core::Requisition *requisition);
+
+ bool isActivated ();
+ void setActivated (bool activated);
+};
+
+
+class FltkCheckButtonResource:
+ public FltkToggleButtonResource <dw::core::ui::CheckButtonResource>
+{
+protected:
+ Fl_Button *createNewButton (core::Allocation *allocation);
+
+public:
+ FltkCheckButtonResource (FltkPlatform *platform,
+ bool activated);
+ ~FltkCheckButtonResource ();
+};
+
+
+class FltkRadioButtonResource:
+ public FltkToggleButtonResource <dw::core::ui::RadioButtonResource>
+{
+private:
+ class Group
+ {
+ private:
+ class FltkGroupIterator:
+ public dw::core::ui::RadioButtonResource::GroupIterator
+ {
+ private:
+ lout::container::typed::Iterator <FltkRadioButtonResource> it;
+
+ public:
+ inline FltkGroupIterator (lout::container::typed::List
+ <FltkRadioButtonResource>
+ *list)
+ { it = list->iterator (); }
+
+ bool hasNext ();
+ dw::core::ui::RadioButtonResource *getNext ();
+ void unref ();
+ };
+
+ lout::container::typed::List <FltkRadioButtonResource> *list;
+
+ protected:
+ ~Group ();
+
+ public:
+ Group (FltkRadioButtonResource *radioButtonResource);
+
+ inline lout::container::typed::Iterator <FltkRadioButtonResource>
+ iterator ()
+ {
+ return list->iterator ();
+ }
+
+ inline dw::core::ui::RadioButtonResource::GroupIterator
+ *groupIterator ()
+ {
+ return new FltkGroupIterator (list);
+ }
+
+ void connect (FltkRadioButtonResource *radioButtonResource);
+ void unconnect (FltkRadioButtonResource *radioButtonResource);
+ };
+
+ Group *group;
+
+ static void widgetCallback (Fl_Widget *widget, void *data);
+ void buttonClicked ();
+
+protected:
+ Fl_Button *createNewButton (core::Allocation *allocation);
+
+public:
+ FltkRadioButtonResource (FltkPlatform *platform,
+ FltkRadioButtonResource *groupedWith,
+ bool activated);
+ ~FltkRadioButtonResource ();
+
+ GroupIterator *groupIterator ();
+};
+
+
+template <class I> class FltkSelectionResource:
+ public FltkSpecificResource <I>
+{
+protected:
+ virtual bool setSelectedItems() { return false; }
+ virtual void addItem (const char *str, bool enabled, bool selected) = 0;
+ virtual void setItem (int index, bool selected) = 0;
+ virtual void pushGroup (const char *name, bool enabled) = 0;
+ virtual void popGroup () = 0;
+public:
+ FltkSelectionResource (FltkPlatform *platform) :
+ FltkSpecificResource<I> (platform) {};
+ dw::core::Iterator *iterator (dw::core::Content::Type mask, bool atEnd);
+};
+
+
+class FltkOptionMenuResource:
+ public FltkSelectionResource <dw::core::ui::OptionMenuResource>
+{
+protected:
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+ virtual bool setSelectedItems() { return true; }
+ void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+ int getNumberOfItems();
+ int getMaxItemWidth ();
+private:
+ static void widgetCallback (Fl_Widget *widget, void *data);
+ void enlargeMenu();
+ Fl_Menu_Item *newItem();
+ Fl_Menu_Item *menu;
+ int itemsAllocated, itemsUsed;
+public:
+ FltkOptionMenuResource (FltkPlatform *platform);
+ ~FltkOptionMenuResource ();
+
+ void addItem (const char *str, bool enabled, bool selected);
+ void setItem (int index, bool selected);
+ void pushGroup (const char *name, bool enabled);
+ void popGroup ();
+
+ void sizeRequest (core::Requisition *requisition);
+ bool isSelected (int index);
+};
+
+class FltkListResource:
+ public FltkSelectionResource <dw::core::ui::ListResource>
+{
+protected:
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+ void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+ int getNumberOfItems();
+ int getMaxItemWidth ();
+private:
+ static void widgetCallback (Fl_Widget *widget, void *data);
+ void *newItem (const char *str, bool enabled, bool selected);
+ int currDepth;
+ int colWidths[4];
+ int showRows;
+ ListResource::SelectionMode mode;
+public:
+ FltkListResource (FltkPlatform *platform,
+ core::ui::ListResource::SelectionMode selectionMode,
+ int rows);
+ ~FltkListResource ();
+
+ void addItem (const char *str, bool enabled, bool selected);
+ void setItem (int index, bool selected);
+ void pushGroup (const char *name, bool enabled);
+ void popGroup ();
+
+ void sizeRequest (core::Requisition *requisition);
+ bool isSelected (int index);
+};
+
+
+} // namespace ui
+} // namespace fltk
+} // namespace dw
+
+
+#endif // __DW_FLTK_UI_HH__