533 lines
16 KiB
C++
533 lines
16 KiB
C++
#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 functionality 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,
|
|
core::DrawingContext *context);
|
|
|
|
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,
|
|
core::DrawingContext *context);
|
|
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);
|
|
};
|
|
|
|
|
|
class FltkComplexButtonResource:
|
|
public FltkSpecificResource <dw::core::ui::ComplexButtonResource>
|
|
{
|
|
private:
|
|
bool relief;
|
|
|
|
static void widgetCallback (Fl_Widget *widget, void *data);
|
|
|
|
protected:
|
|
FltkView *topView, *flatView;
|
|
|
|
void attachView (FltkView *view);
|
|
void detachView (FltkView *view);
|
|
|
|
void sizeAllocate (core::Allocation *allocation);
|
|
|
|
std::unique_ptr< dw::core::Platform > createPlatform ();
|
|
void setLayout (dw::core::Layout *layout);
|
|
|
|
int reliefXThickness ();
|
|
int reliefYThickness ();
|
|
|
|
Fl_Widget *createNewWidget (core::Allocation *allocation);
|
|
|
|
public:
|
|
FltkComplexButtonResource (FltkPlatform *platform, std::unique_ptr< dw::core::Widget > widget,
|
|
bool relief);
|
|
~FltkComplexButtonResource ();
|
|
};
|
|
|
|
|
|
/**
|
|
* \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;
|
|
char *placeholder;
|
|
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, const char *placeholder);
|
|
~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:
|
|
bool editable;
|
|
int numCols, numRows;
|
|
char *placeholder;
|
|
protected:
|
|
Fl_Widget *createNewWidget (core::Allocation *allocation);
|
|
void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
|
|
|
|
public:
|
|
FltkMultiLineTextResource (FltkPlatform *platform, int cols, int rows,
|
|
const char *placeholder);
|
|
~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:
|
|
std::list< FltkRadioButtonResource * >::iterator pos;
|
|
std::list< FltkRadioButtonResource * >::iterator last;
|
|
|
|
public:
|
|
inline FltkGroupIterator (std::list< FltkRadioButtonResource * > &list )
|
|
{ pos = list.begin (); last = list.end(); }
|
|
|
|
bool hasNext ();
|
|
dw::core::ui::RadioButtonResource *getNext ();
|
|
void unref ();
|
|
};
|
|
|
|
std::list< FltkRadioButtonResource * > list;
|
|
|
|
public:
|
|
Group (FltkRadioButtonResource *radioButtonResource);
|
|
|
|
auto begin () { return list.begin(); }
|
|
auto end () { return list.end(); }
|
|
|
|
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 std::string &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 std::string &name, bool enabled ) override;
|
|
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 std::string &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 std::string &name, bool enabled ) override;
|
|
void popGroup ();
|
|
|
|
void sizeRequest (core::Requisition *requisition);
|
|
bool isSelected (int index);
|
|
};
|
|
|
|
|
|
} // namespace ui
|
|
} // namespace fltk
|
|
} // namespace dw
|
|
|
|
|
|
#endif // __DW_FLTK_UI_HH__
|