summaryrefslogtreecommitdiff
path: root/dw/fltkui.cc
diff options
context:
space:
mode:
authorjcid <devnull@localhost>2008-09-24 18:44:40 +0200
committerjcid <devnull@localhost>2008-09-24 18:44:40 +0200
commitc377e06400f138325a9a9d43d91a9272691867a1 (patch)
tree49f3ca1c46af11a058a68714899d4137ec717618 /dw/fltkui.cc
parent642f9b3e747859a7256ea12fab9f9ed50aa9253a (diff)
- Moved the dw2 tree into dillo2's tree.
Diffstat (limited to 'dw/fltkui.cc')
-rw-r--r--dw/fltkui.cc1202
1 files changed, 1202 insertions, 0 deletions
diff --git a/dw/fltkui.cc b/dw/fltkui.cc
new file mode 100644
index 00000000..70ba1ef3
--- /dev/null
+++ b/dw/fltkui.cc
@@ -0,0 +1,1202 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+
+#include "fltkcore.hh"
+#include "fltkflatview.hh"
+#include "fltkcomplexbutton.hh"
+#include "../lout/misc.hh"
+
+#include <stdio.h>
+#include <fltk/Widget.h>
+#include <fltk/Group.h>
+#include <fltk/Input.h>
+#include <fltk/SecretInput.h>
+#include <fltk/TextEditor.h>
+#include <fltk/RadioButton.h>
+#include <fltk/CheckButton.h>
+#include <fltk/Choice.h>
+#include <fltk/Browser.h>
+#include <fltk/MultiBrowser.h>
+#include <fltk/Font.h>
+#include <fltk/draw.h>
+#include <fltk/Symbol.h>
+#include <fltk/Item.h>
+#include <fltk/ItemGroup.h>
+#include <fltk/events.h>
+
+namespace dw {
+namespace fltk {
+namespace ui {
+
+enum { RELIEF_X_THICKNESS = 5, RELIEF_Y_THICKNESS = 3 };
+
+using namespace object;
+using namespace container::typed;
+
+FltkResource::FltkResource (FltkPlatform *platform)
+{
+ this->platform = platform;
+
+ allocation.x = 0;
+ allocation.y = 0;
+ allocation.width = 1;
+ allocation.ascent = 1;
+ allocation.descent = 0;
+
+ style = NULL;
+}
+
+/**
+ * This is not a constructor, since it calls some virtual methods, which
+ * should not be done in a C++ base constructor.
+ */
+void FltkResource::init (FltkPlatform *platform)
+{
+ viewsAndWidgets = new container::typed::List <ViewAndWidget> (true);
+ platform->attachResource (this);
+}
+
+FltkResource::~FltkResource ()
+{
+ platform->detachResource (this);
+ for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
+ it.hasNext(); ) {
+ ViewAndWidget *viewAndWidget = it.getNext ();
+
+ if (viewAndWidget->widget) {
+ if (viewAndWidget->view) {
+ viewAndWidget->view->removeFltkWidget(viewAndWidget->widget);
+ }
+ delete viewAndWidget->widget;
+ }
+
+ }
+ delete viewsAndWidgets;
+ if(style)
+ style->unref ();
+}
+
+void FltkResource::attachView (FltkView *view)
+{
+ if (view->usesFltkWidgets ()) {
+ ViewAndWidget *viewAndWidget = new ViewAndWidget();
+ viewAndWidget->view = view;
+
+ viewAndWidget->widget = createNewWidget (&allocation);
+ viewAndWidget->view->addFltkWidget (viewAndWidget->widget, &allocation);
+ viewsAndWidgets->append (viewAndWidget);
+ if (style)
+ setWidgetStyle (viewAndWidget->widget, style);
+ }
+}
+
+void FltkResource::detachView (FltkView *view)
+{
+ for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
+ it.hasNext(); ) {
+ ViewAndWidget *viewAndWidget = it.getNext ();
+ if (viewAndWidget->view == view) {
+ viewsAndWidgets->removeRef (viewAndWidget);
+ return;
+ }
+ }
+
+ fprintf (stderr, "FltkResource::detachView: View not found.");
+}
+
+void FltkResource::sizeAllocate (core::Allocation *allocation)
+{
+ this->allocation = *allocation;
+
+ for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
+ it.hasNext(); ) {
+ ViewAndWidget *viewAndWidget = it.getNext ();
+ viewAndWidget->view->allocateFltkWidget (viewAndWidget->widget,
+ allocation);
+ }
+}
+
+void FltkResource::draw (core::View *view, core::Rectangle *area)
+{
+ FltkView *fltkView = (FltkView*)view;
+ if (fltkView->usesFltkWidgets ()) {
+ for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
+ it.hasNext(); ) {
+ ViewAndWidget *viewAndWidget = it.getNext ();
+ if (viewAndWidget->view == fltkView) {
+ fltkView->drawFltkWidget (viewAndWidget->widget, area);
+ break;
+ }
+ }
+ }
+}
+
+void FltkResource::setStyle (core::style::Style *style)
+{
+ if(this->style)
+ this->style->unref ();
+
+ this->style = style;
+ style->ref ();
+
+ for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
+ it.hasNext(); ) {
+ ViewAndWidget *viewAndWidget = it.getNext ();
+ setWidgetStyle (viewAndWidget->widget, style);
+ }
+}
+
+void FltkResource::setWidgetStyle (::fltk::Widget *widget,
+ core::style::Style *style)
+{
+ /** \bug label or text? */
+
+ FltkFont *font = (FltkFont*)style->font;
+ widget->labelsize (font->size);
+ widget->labelfont (font->font);
+ widget->textsize (font->size);
+ widget->textfont (font->font);
+
+ FltkColor *bg = (FltkColor*)style->backgroundColor;
+ if (bg) {
+ if (style->color) {
+ /*
+ * todo: if/when CSS is implemented, test whether style->color
+ * will consistently provide readable widgets.
+ */
+ int32_t c = bg->colors[FltkColor::SHADING_NORMAL];
+ int r = (c >> 24) & 0xff, g = (c >> 16) & 0xff, b = (c >> 8) & 0xff;
+ bool light = (r + g >= 0x150) || (r + g + b >= 0x180);
+
+ widget->labelcolor(light? ::fltk::BLACK : ::fltk::WHITE);
+ widget->textcolor(light? ::fltk::BLACK : ::fltk::WHITE);
+ widget->selection_color(light? ::fltk::BLACK : ::fltk::WHITE);
+ }
+
+ widget->color(bg->colors[FltkColor::SHADING_NORMAL]);
+ widget->buttoncolor(bg->colors[FltkColor::SHADING_NORMAL]);
+ widget->highlight_color(bg->colors[FltkColor::SHADING_LIGHT]);
+ widget->selection_textcolor(bg->colors[FltkColor::SHADING_NORMAL]);
+ }
+}
+
+bool FltkResource::isEnabled ()
+{
+ /** \bug Not implemented. */
+ return true;
+}
+
+void FltkResource::setEnabled (bool enabled)
+{
+ /** \bug Not implemented. */
+}
+
+// ----------------------------------------------------------------------
+
+template <class I> void FltkSpecificResource<I>::sizeAllocate (core::Allocation
+ *allocation)
+{
+ FltkResource::sizeAllocate (allocation);
+}
+
+template <class I> void FltkSpecificResource<I>::draw (core::View *view,
+ core::Rectangle *area)
+{
+ FltkResource::draw (view, area);
+}
+
+template <class I> void FltkSpecificResource<I>::setStyle (core::style::Style
+ *style)
+{
+ FltkResource::setStyle (style);
+}
+
+template <class I> bool FltkSpecificResource<I>::isEnabled ()
+{
+ return FltkResource::isEnabled ();
+}
+
+template <class I> void FltkSpecificResource<I>::setEnabled (bool enabled)
+{
+ FltkResource::setEnabled (enabled);
+}
+
+// ----------------------------------------------------------------------
+
+FltkLabelButtonResource::FltkLabelButtonResource (FltkPlatform *platform,
+ const char *label):
+ FltkSpecificResource <dw::core::ui::LabelButtonResource> (platform)
+{
+ this->label = strdup (label);
+ init (platform);
+}
+
+FltkLabelButtonResource::~FltkLabelButtonResource ()
+{
+ delete label;
+}
+
+::fltk::Widget *FltkLabelButtonResource::createNewWidget (core::Allocation
+ *allocation)
+{
+ ::fltk::Button *button =
+ new ::fltk::Button (allocation->x, allocation->y, allocation->width,
+ allocation->ascent + allocation->descent,
+ label);
+ button->callback (widgetCallback, this);
+ button->when (::fltk::WHEN_RELEASE);
+ return button;
+}
+
+void FltkLabelButtonResource::sizeRequest (core::Requisition *requisition)
+{
+ if (style) {
+ FltkFont *font = (FltkFont*)style->font;
+ ::fltk::setfont(font->font,font->size);
+ requisition->width =
+ (int)::fltk::getwidth (label, strlen (label))
+ + 2 * RELIEF_X_THICKNESS;
+ requisition->ascent = font->ascent + RELIEF_Y_THICKNESS;
+ requisition->descent = font->descent + RELIEF_Y_THICKNESS;
+ } else {
+ requisition->width = 1;
+ requisition->ascent = 1;
+ requisition->descent = 0;
+ }
+}
+
+void FltkLabelButtonResource::widgetCallback (::fltk::Widget *widget,
+ void *data)
+{
+ if (widget->when () & ::fltk::WHEN_RELEASE)
+ ((FltkLabelButtonResource*)data)->emitActivate ();
+}
+
+const char *FltkLabelButtonResource::getLabel ()
+{
+ return label;
+}
+
+
+void FltkLabelButtonResource::setLabel (const char *label)
+{
+ delete this->label;
+ this->label = strdup (label);
+
+ for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
+ it.hasNext(); ) {
+ ViewAndWidget *viewAndWidget = it.getNext ();
+ viewAndWidget->widget->label (this->label);
+ }
+
+ queueResize (true);
+}
+
+// ----------------------------------------------------------------------
+
+FltkComplexButtonResource::FltkComplexButtonResource (FltkPlatform *platform,
+ dw::core::Widget
+ *widget, bool relief):
+ FltkSpecificResource <dw::core::ui::ComplexButtonResource> (platform)
+{
+ viewsAndViews = new container::typed::List <ViewAndView> (true);
+ this->relief = relief;
+ FltkResource::init (platform);
+ ComplexButtonResource::init (widget);
+}
+
+FltkComplexButtonResource::~FltkComplexButtonResource ()
+{
+ delete viewsAndViews;
+}
+
+void FltkComplexButtonResource::widgetCallback (::fltk::Widget *widget,
+ void *data)
+{
+ FltkComplexButtonResource *res = (FltkComplexButtonResource*)data;
+
+ /* would be best not to send click pos. if the image could not be loaded */
+ if (::fltk::event() == ::fltk::RELEASE &&
+ ::fltk::event_button() == ::fltk::LeftButton) {
+ res->click_x = ::fltk::event_x();
+ res->click_y = ::fltk::event_y();
+ res->emitActivate ();
+ } else {
+ ((FltkViewBase*)res->lastFlatView)->handle(::fltk::event());
+ }
+}
+
+dw::core::Platform *FltkComplexButtonResource::createPlatform ()
+{
+ return new FltkPlatform ();
+}
+
+void FltkComplexButtonResource::attachView (FltkView *view)
+{
+ FltkResource::attachView (view);
+
+ if (view->usesFltkWidgets ()) {
+ ViewAndView *viewAndView = new ViewAndView();
+ viewAndView->topView = view;
+ viewAndView->flatView = lastFlatView;
+ viewsAndViews->append (viewAndView);
+ }
+}
+
+void FltkComplexButtonResource::detachView (FltkView *view)
+{
+ FltkResource::detachView (view);
+
+ for (Iterator <ViewAndView> it = viewsAndViews->iterator ();
+ it.hasNext(); ) {
+ ViewAndView *viewAndView = it.getNext ();
+ if (viewAndView->topView == view) {
+ viewsAndViews->removeRef (viewAndView);
+ return;
+ }
+ }
+
+ fprintf (stderr,
+ "FltkComplexButtonResourceResource::detachView: View not "
+ "found.\n");
+}
+
+void FltkComplexButtonResource::sizeAllocate (core::Allocation *allocation)
+{
+ FltkResource::sizeAllocate (allocation);
+
+ for (Iterator <ViewAndView> it = viewsAndViews->iterator ();
+ it.hasNext(); ) {
+ ViewAndView *viewAndView = it.getNext ();
+ ((FltkFlatView*)viewAndView->flatView)->resize (
+ reliefXThickness (),
+ reliefYThickness (),
+ allocation->width - 2 * reliefXThickness (),
+ allocation->ascent + allocation->descent - 2 * reliefYThickness ());
+
+ ((FltkFlatView*)viewAndView->flatView)->parent ()->init_sizes ();
+ }
+}
+
+void FltkComplexButtonResource::setLayout (dw::core::Layout *layout)
+{
+ for (Iterator <ViewAndView> it = viewsAndViews->iterator ();
+ it.hasNext(); ) {
+ ViewAndView *viewAndView = it.getNext ();
+ layout->attachView (viewAndView->flatView);
+ }
+}
+
+int FltkComplexButtonResource::reliefXThickness ()
+{
+ return relief ? RELIEF_X_THICKNESS : 0;
+}
+
+int FltkComplexButtonResource::reliefYThickness ()
+{
+ return relief ? RELIEF_Y_THICKNESS : 0;
+}
+
+
+::fltk::Widget *FltkComplexButtonResource::createNewWidget (core::Allocation
+ *allocation)
+{
+ ComplexButton *button =
+ new ComplexButton (allocation->x, allocation->y, allocation->width,
+ allocation->ascent + allocation->descent);
+ button->callback (widgetCallback, this);
+ button->when (::fltk::WHEN_RELEASE);
+ if (!relief)
+ button->box(::fltk::FLAT_BOX);
+
+ FltkFlatView *flatView =
+ new FltkFlatView (allocation->x + reliefXThickness (),
+ allocation->y + reliefYThickness (),
+ allocation->width - 2 * reliefXThickness (),
+ allocation->ascent + allocation->descent
+ - 2 * reliefYThickness ());
+ button->add (flatView);
+
+ lastFlatView = flatView;
+
+ if (layout)
+ layout->attachView (lastFlatView);
+ return button;
+}
+
+// ----------------------------------------------------------------------
+
+FltkEntryResource::FltkEntryResource (FltkPlatform *platform, int maxLength,
+ bool password):
+ FltkSpecificResource <dw::core::ui::EntryResource> (platform)
+{
+ this->maxLength = maxLength;
+ this->password = password;
+
+ initText = NULL;
+ editable = false;
+
+ init (platform);
+}
+
+FltkEntryResource::~FltkEntryResource ()
+{
+ if (initText)
+ delete initText;
+}
+
+::fltk::Widget *FltkEntryResource::createNewWidget (core::Allocation
+ *allocation)
+{
+ ::fltk::Input *input =
+ password ?
+ new ::fltk::SecretInput (allocation->x, allocation->y,
+ allocation->width,
+ allocation->ascent + allocation->descent) :
+ new ::fltk::Input (allocation->x, allocation->y, allocation->width,
+ allocation->ascent + allocation->descent);
+ input->callback (widgetCallback, this);
+ input->when (::fltk::WHEN_ENTER_KEY_ALWAYS);
+
+ if (viewsAndWidgets->isEmpty ()) {
+ // First widget created, attach the set text.
+ if (initText)
+ input->value (initText);
+ } else
+ input->value
+ (((::fltk::Input*)viewsAndWidgets->getFirst()->widget)->value ());
+
+ return input;
+}
+
+void FltkEntryResource::sizeRequest (core::Requisition *requisition)
+{
+ if (style) {
+ FltkFont *font = (FltkFont*)style->font;
+ ::fltk::setfont(font->font,font->size);
+ requisition->width =
+ (int)::fltk::getwidth ("M", 1)
+ * (maxLength == UNLIMITED_MAX_LENGTH ? 10 : maxLength)
+ + 2 * RELIEF_X_THICKNESS;
+ requisition->ascent = font->ascent + RELIEF_Y_THICKNESS;
+ requisition->descent = font->descent + RELIEF_Y_THICKNESS;
+ } else {
+ requisition->width = 1;
+ requisition->ascent = 1;
+ requisition->descent = 0;
+ }
+}
+
+void FltkEntryResource::widgetCallback (::fltk::Widget *widget,
+ void *data)
+{
+ /* The (::fltk::event_key() == ::fltk::ReturnKey) test
+ * is necessary because WHEN_ENTER_KEY also includes
+ * other events we're not interested in. For instance pressing
+ * The Back or Forward, buttons, or the first click on a rendered
+ * page. BUG: this must be investigated and reported to FLTK2 team
+ */
+ printf ("when = %d\n", widget->when ());
+ if ((widget->when () & ::fltk::WHEN_ENTER_KEY_ALWAYS) &&
+ (::fltk::event_key() == ::fltk::ReturnKey))
+ ((FltkEntryResource*)data)->emitActivate ();
+}
+
+const char *FltkEntryResource::getText ()
+{
+ if (viewsAndWidgets->isEmpty ())
+ return initText;
+ else
+ return ((::fltk::Input*)viewsAndWidgets->getFirst()->widget)->value ();
+}
+
+void FltkEntryResource::setText (const char *text)
+{
+ if (initText)
+ delete initText;
+ initText = strdup (text);
+
+ for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
+ it.hasNext(); ) {
+ ViewAndWidget *viewAndWidget = it.getNext ();
+ ((::fltk::Input*)viewAndWidget->widget)->value (initText);
+ }
+}
+
+bool FltkEntryResource::isEditable ()
+{
+ return editable;
+}
+
+void FltkEntryResource::setEditable (bool editable)
+{
+ this->editable = editable;
+}
+
+// ----------------------------------------------------------------------
+
+FltkMultiLineTextResource::FltkMultiLineTextResource (FltkPlatform *platform,
+ int cols, int rows):
+ FltkSpecificResource <dw::core::ui::MultiLineTextResource> (platform)
+{
+ buffer = new ::fltk::TextBuffer;
+ editable = false;
+
+ numCols = cols;
+ numRows = rows;
+
+ // Check values. Upper bound check is left to the caller.
+ if (numCols < 1) {
+ fprintf (stderr, "WARNING: numCols = %d is set to 1.\n", numCols);
+ numCols = 1;
+ }
+ if (numRows < 1) {
+ fprintf (stderr, "WARNING: numRows = %d is set to 1.\n", numRows);
+ numRows = 1;
+ }
+
+ init (platform);
+}
+
+FltkMultiLineTextResource::~FltkMultiLineTextResource ()
+{
+ /* Free memory avoiding a double-free of text buffers */
+ for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
+ it.hasNext(); ) {
+ ViewAndWidget *viewAndWidget = it.getNext ();
+ ((::fltk::TextEditor *) viewAndWidget->widget)->buffer (0);
+ }
+ delete buffer;
+}
+
+::fltk::Widget *FltkMultiLineTextResource::createNewWidget (core::Allocation
+ *allocation)
+{
+ ::fltk::TextEditor *text =
+ new ::fltk::TextEditor (allocation->x, allocation->y,
+ allocation->width,
+ allocation->ascent + allocation->descent);
+ text->buffer (buffer);
+ return text;
+}
+
+void FltkMultiLineTextResource::sizeRequest (core::Requisition *requisition)
+{
+ if (style) {
+ FltkFont *font = (FltkFont*)style->font;
+ ::fltk::setfont(font->font,font->size);
+ requisition->width =
+ (int)::fltk::getwidth ("X", 1) * numCols +
+ 2 * RELIEF_X_THICKNESS;
+ requisition->ascent =
+ font->ascent + RELIEF_Y_THICKNESS;
+ requisition->descent =
+ font->descent +
+ (font->ascent + font->descent) * (numRows - 1) +
+ RELIEF_Y_THICKNESS;
+ } else {
+ requisition->width = 1;
+ requisition->ascent = 1;
+ requisition->descent = 0;
+ }
+}
+
+const char *FltkMultiLineTextResource::getText ()
+{
+ return buffer->text ();
+}
+
+void FltkMultiLineTextResource::setText (const char *text)
+{
+ buffer->text (text);
+}
+
+bool FltkMultiLineTextResource::isEditable ()
+{
+ return editable;
+}
+
+void FltkMultiLineTextResource::setEditable (bool editable)
+{
+ this->editable = editable;
+}
+
+// ----------------------------------------------------------------------
+
+template <class I>
+FltkToggleButtonResource<I>::FltkToggleButtonResource (FltkPlatform *platform,
+ bool activated):
+ FltkSpecificResource <I> (platform)
+{
+ initActivated = activated;
+}
+
+
+template <class I>
+FltkToggleButtonResource<I>::~FltkToggleButtonResource ()
+{
+}
+
+
+template <class I>
+::fltk::Widget *FltkToggleButtonResource<I>::createNewWidget (core::Allocation
+ *allocation)
+{
+ ::fltk::Button *button = createNewButton (allocation);
+
+ if (this->viewsAndWidgets->isEmpty ())
+ button->value (initActivated);
+ else
+ button->value (((::fltk::Button*)this->viewsAndWidgets
+ ->getFirst()->widget)->value ());
+
+ return button;
+}
+
+
+template <class I>
+void FltkToggleButtonResource<I>::sizeRequest (core::Requisition *requisition)
+{
+ /** \bug Random values. */
+ requisition->width = 20;
+ requisition->ascent = 18;
+ requisition->descent = 5;
+}
+
+
+template <class I>
+bool FltkToggleButtonResource<I>::FltkToggleButtonResource::isActivated ()
+{
+ if (this->viewsAndWidgets->isEmpty ())
+ return initActivated;
+ else
+ return
+ ((::fltk::Button*)this->viewsAndWidgets->getFirst()->widget)
+ ->value ();
+}
+
+
+template <class I>
+void FltkToggleButtonResource<I>::setActivated (bool activated)
+{
+ initActivated = activated;
+
+ for (Iterator <FltkResource::ViewAndWidget> it =
+ this->viewsAndWidgets->iterator ();
+ it.hasNext(); ) {
+ FltkResource::ViewAndWidget *viewAndWidget = it.getNext ();
+ ((::fltk::Button*)viewAndWidget->widget)->value (initActivated);
+ }
+}
+
+// ----------------------------------------------------------------------
+
+FltkCheckButtonResource::FltkCheckButtonResource (FltkPlatform *platform,
+ bool activated):
+ FltkToggleButtonResource<dw::core::ui::CheckButtonResource> (platform,
+ activated)
+{
+ init (platform);
+}
+
+
+FltkCheckButtonResource::~FltkCheckButtonResource ()
+{
+}
+
+
+::fltk::Button *FltkCheckButtonResource::createNewButton (core::Allocation
+ *allocation)
+{
+ return
+ new ::fltk::CheckButton (allocation->x, allocation->y, allocation->width,
+ allocation->ascent + allocation->descent);
+}
+
+// ----------------------------------------------------------------------
+
+bool FltkRadioButtonResource::Group::FltkGroupIterator::hasNext ()
+{
+ return it.hasNext ();
+}
+
+dw::core::ui::RadioButtonResource
+*FltkRadioButtonResource::Group::FltkGroupIterator::getNext ()
+{
+ return (dw::core::ui::RadioButtonResource*)it.getNext ();
+}
+
+void FltkRadioButtonResource::Group::FltkGroupIterator::unref ()
+{
+ delete this;
+}
+
+
+FltkRadioButtonResource::Group::Group (FltkRadioButtonResource
+ *radioButtonResource)
+{
+ list = new container::typed::List <FltkRadioButtonResource> (false);
+ connect (radioButtonResource);
+}
+
+FltkRadioButtonResource::Group::~Group ()
+{
+ delete list;
+}
+
+void FltkRadioButtonResource::Group::connect (FltkRadioButtonResource
+ *radioButtonResource)
+{
+ list->append (radioButtonResource);
+}
+
+void FltkRadioButtonResource::Group::unconnect (FltkRadioButtonResource
+ *radioButtonResource)
+{
+ list->removeRef (radioButtonResource);
+ if (list->isEmpty ())
+ delete this;
+}
+
+
+FltkRadioButtonResource::FltkRadioButtonResource (FltkPlatform *platform,
+ FltkRadioButtonResource
+ *groupedWith,
+ bool activated):
+ FltkToggleButtonResource<dw::core::ui::RadioButtonResource> (platform,
+ activated)
+{
+ init (platform);
+
+ if (groupedWith) {
+ group = groupedWith->group;
+ group->connect (this);
+ } else
+ group = new Group (this);
+}
+
+
+FltkRadioButtonResource::~FltkRadioButtonResource ()
+{
+ group->unconnect (this);
+}
+
+dw::core::ui::RadioButtonResource::GroupIterator
+*FltkRadioButtonResource::groupIterator ()
+{
+ return group->groupIterator ();
+}
+
+void FltkRadioButtonResource::widgetCallback (::fltk::Widget *widget,
+ void *data)
+{
+ if (widget->when () & ::fltk::WHEN_CHANGED)
+ ((FltkRadioButtonResource*)data)->buttonClicked ();
+}
+
+void FltkRadioButtonResource::buttonClicked ()
+{
+ for (Iterator <FltkRadioButtonResource> it = group->iterator ();
+ it.hasNext (); ) {
+ FltkRadioButtonResource *other = it.getNext ();
+ other->setActivated (other == this);
+ }
+}
+
+::fltk::Button *FltkRadioButtonResource::createNewButton (core::Allocation
+ *allocation)
+{
+ /*
+ * Groups of fltk::RadioButton must be added to one fltk::Group, which is
+ * not possible in this context. For this, we do the grouping ourself,
+ * based on FltkRadioButtonResource::Group.
+ *
+ * What we actually need for this, is a widget, which behaves like a
+ * check button, but looks like a radio button. The first depends on the
+ * type, the second on the style. Since the type is simpler to change
+ * than the style, we create a radio button, and then change the type
+ * (instead of creating a check button, and changing the style).
+ */
+
+ ::fltk::Button *button =
+ new ::fltk::RadioButton (allocation->x, allocation->y,
+ allocation->width,
+ allocation->ascent + allocation->descent);
+ button->when (::fltk::WHEN_CHANGED);
+ button->callback (widgetCallback, this);
+ button->type (::fltk::Button::TOGGLE);
+
+ return button;
+}
+
+// ----------------------------------------------------------------------
+
+template <class I> FltkSelectionResource<I>::Item::Item (Type type,
+ const char *name,
+ bool enabled,
+ bool selected)
+{
+ this->type = type;
+ this->name = name ? strdup (name) : NULL;
+ this->enabled = enabled;
+ initSelected = selected;
+}
+
+template <class I> FltkSelectionResource<I>::Item::~Item ()
+{
+ if (name)
+ delete name;
+}
+
+template <class I>
+::fltk::Item *FltkSelectionResource<I>::Item::createNewWidget (int index)
+{
+ ::fltk::Item *item = new ::fltk::Item (name);
+ item->user_data ((void *) index);
+ return item;
+}
+
+template <class I>
+::fltk::ItemGroup *
+FltkSelectionResource<I>::Item::createNewGroupWidget ()
+{
+ ::fltk::ItemGroup *itemGroup = new ::fltk::ItemGroup (name);
+ itemGroup->user_data ((void *) -1L);
+ return itemGroup;
+}
+
+
+template <class I>
+FltkSelectionResource<I>::WidgetStack::WidgetStack (::fltk::Menu *widget)
+{
+ this->widget = widget;
+ this->stack = new Stack <TypedPointer < ::fltk::Menu> > (true);
+}
+
+template <class I> FltkSelectionResource<I>::WidgetStack::~WidgetStack ()
+{
+ delete stack;
+}
+
+
+template <class I>
+FltkSelectionResource<I>::FltkSelectionResource (FltkPlatform *platform):
+ FltkSpecificResource<I> (platform)
+{
+ widgetStacks = new List <WidgetStack> (true);
+ allItems = new List <Item> (true);
+ items = new Vector <Item> (16, false);
+}
+
+template <class I> FltkSelectionResource<I>::~FltkSelectionResource ()
+{
+ delete widgetStacks;
+ delete allItems;
+ delete items;
+}
+
+template <class I> dw::core::Iterator *
+FltkSelectionResource<I>::iterator (dw::core::Content::Type mask, bool atEnd)
+{
+ /** \bug Implementation. */
+ return new core::EmptyIterator (this->getEmbed (), mask, atEnd);
+}
+
+template <class I> ::fltk::Widget *
+FltkSelectionResource<I>::createNewWidget (core::Allocation *allocation)
+{
+ /** \todo Attributes (enabled, selected). */
+
+ ::fltk::Menu *menu = createNewMenu (allocation);
+ WidgetStack *widgetStack = new WidgetStack (menu);
+ widgetStack->stack->push (new TypedPointer < ::fltk::Menu> (menu));
+ widgetStacks->append (widgetStack);
+
+
+ ::fltk::Menu *itemGroup;
+ ::fltk::Item *itemWidget;
+
+ ::fltk::Group *currGroup = widgetStack->stack->getTop()->getTypedValue();
+
+ int index = 0;
+ for (Iterator <Item> it = allItems->iterator (); it.hasNext (); ) {
+ Item *item = it.getNext ();
+ switch (item->type) {
+ case Item::ITEM:
+ itemWidget = item->createNewWidget (index++);
+ currGroup->add (itemWidget);
+ break;
+
+ case Item::START:
+ itemGroup = item->createNewGroupWidget ();
+ currGroup->add (itemGroup);
+ widgetStack->stack->push (new TypedPointer < ::fltk::Menu> (menu));
+ currGroup = itemGroup;
+ break;
+
+ case Item::END:
+ widgetStack->stack->pop ();
+ currGroup = widgetStack->stack->getTop()->getTypedValue();
+ break;
+ }
+ }
+
+ return menu;
+}
+
+template <class I>
+typename FltkSelectionResource<I>::Item *
+FltkSelectionResource<I>::createNewItem (typename Item::Type type,
+ const char *name,
+ bool enabled,
+ bool selected) {
+ return new Item(type,name,enabled,selected);
+}
+
+template <class I> void FltkSelectionResource<I>::addItem (const char *str,
+ bool enabled,
+ bool selected)
+{
+ int index = items->size ();
+ Item *item = createNewItem (Item::ITEM, str, enabled, selected);
+ items->put (item);
+ allItems->append (item);
+
+ for (Iterator <WidgetStack> it = widgetStacks->iterator ();
+ it.hasNext(); ) {
+ WidgetStack *widgetStack = it.getNext ();
+ ::fltk::Item *itemWidget = item->createNewWidget (index);
+ widgetStack->stack->getTop()->getTypedValue()->add (itemWidget);
+
+ if (!enabled)
+ itemWidget->deactivate ();
+
+ if (selected) {
+ itemWidget->set_selected();
+ if (setSelectedItems ()) {
+ // Handle multiple item selection.
+ int pos[widgetStack->stack->size ()];
+ int i;
+ Iterator <TypedPointer < ::fltk::Menu> > it;
+ for (it = widgetStack->stack->iterator (),
+ i = widgetStack->stack->size () - 1;
+ it.hasNext ();
+ i--) {
+ TypedPointer < ::fltk::Menu> * p = it.getNext ();
+ pos[i] = p->getTypedValue()->children () - 1;
+ }
+ widgetStack->widget->set_item (pos, widgetStack->stack->size ());
+ }
+ }
+ }
+}
+
+template <class I> void FltkSelectionResource<I>::pushGroup (const char *name,
+ bool enabled)
+{
+ Item *item = createNewItem (Item::START, name, enabled);
+ allItems->append (item);
+
+ for (Iterator <WidgetStack> it = widgetStacks->iterator ();
+ it.hasNext(); ) {
+ WidgetStack *widgetStack = it.getNext ();
+ ::fltk::ItemGroup *group = item->createNewGroupWidget ();
+ widgetStack->stack->getTop()->getTypedValue()->add (group);
+ widgetStack->stack->push (new TypedPointer < ::fltk::Menu> (group));
+ if(!enabled)
+ group->deactivate ();
+ }
+}
+
+template <class I> void FltkSelectionResource<I>::popGroup ()
+{
+ Item *item = createNewItem (Item::END);
+ allItems->append (item);
+
+ for (Iterator <WidgetStack> it = widgetStacks->iterator ();
+ it.hasNext(); ) {
+ WidgetStack *widgetStack = it.getNext ();
+ widgetStack->stack->pop ();
+ }
+}
+
+template <class I> int FltkSelectionResource<I>::getNumberOfItems ()
+{
+ return items->size ();
+}
+
+template <class I> const char *FltkSelectionResource<I>::getItem (int index)
+{
+ return items->get(index)->name;
+}
+
+template <class I> int FltkSelectionResource<I>::getMaxStringWidth ()
+{
+ int width = 0, numberOfItems = getNumberOfItems ();
+ for (int i = 0; i < numberOfItems; i++) {
+ int len = (int)::fltk::getwidth (getItem(i));
+ if (len > width) width = len;
+ }
+ return width;
+}
+
+// ----------------------------------------------------------------------
+
+FltkOptionMenuResource::FltkOptionMenuResource (FltkPlatform *platform):
+ FltkSelectionResource <dw::core::ui::OptionMenuResource> (platform),
+ selection(-1)
+{
+ init (platform);
+}
+
+FltkOptionMenuResource::~FltkOptionMenuResource ()
+{
+}
+
+
+::fltk::Menu *FltkOptionMenuResource::createNewMenu (core::Allocation
+ *allocation)
+{
+ ::fltk::Menu *menu =
+ new ::fltk::Choice (allocation->x, allocation->y,
+ allocation->width,
+ allocation->ascent + allocation->descent);
+ menu->callback(widgetCallback,this);
+ return menu;
+}
+
+void FltkOptionMenuResource::widgetCallback (::fltk::Widget *widget,
+ void *data)
+{
+ ((FltkOptionMenuResource *) data)->selection =
+ (long) (((::fltk::Menu *) widget)->item()->user_data());
+}
+
+void FltkOptionMenuResource::sizeRequest (core::Requisition *requisition)
+{
+ if (style) {
+ FltkFont *font = (FltkFont*)style->font;
+ ::fltk::setfont(font->font,font->size);
+ int maxStringWidth = getMaxStringWidth ();
+ requisition->ascent = font->ascent + RELIEF_Y_THICKNESS;
+ requisition->descent = font->descent + RELIEF_Y_THICKNESS;
+ requisition->width = maxStringWidth
+ + (requisition->ascent + requisition->descent) * 4 / 5
+ + 2 * RELIEF_X_THICKNESS;
+ } else {
+ requisition->width = 1;
+ requisition->ascent = 1;
+ requisition->descent = 0;
+ }
+}
+
+void FltkOptionMenuResource::addItem (const char *str,
+ bool enabled, bool selected)
+{
+ FltkSelectionResource<dw::core::ui::OptionMenuResource>::addItem
+ (str,enabled,selected);
+ if (selected)
+ selection = (items->size ()) - 1;
+
+ queueResize (true);
+}
+
+bool FltkOptionMenuResource::isSelected (int index)
+{
+ return index == selection;
+}
+
+// ----------------------------------------------------------------------
+
+FltkListResource::FltkListResource (FltkPlatform *platform,
+ core::ui::ListResource::SelectionMode
+ selectionMode):
+ FltkSelectionResource <dw::core::ui::ListResource> (platform),
+ itemsSelected(8)
+{
+ init (platform);
+}
+
+FltkListResource::~FltkListResource ()
+{
+}
+
+
+::fltk::Menu *FltkListResource::createNewMenu (core::Allocation *allocation)
+{
+ ::fltk::Menu *menu =
+ new ::fltk::MultiBrowser (allocation->x, allocation->y,
+ allocation->width,
+ allocation->ascent + allocation->descent);
+ menu->callback(widgetCallback,this);
+ menu->when(::fltk::WHEN_CHANGED);
+ return menu;
+}
+
+void FltkListResource::widgetCallback (::fltk::Widget *widget, void *data)
+{
+ ::fltk::Widget *fltkItem = ((::fltk::Menu *) widget)->item ();
+ int index = (long) (fltkItem->user_data ());
+ if (index > -1) {
+ bool selected = fltkItem->selected ();
+ ((FltkListResource *) data)->itemsSelected.set (index, selected);
+ }
+}
+
+void FltkListResource::addItem (const char *str, bool enabled, bool selected)
+{
+ FltkSelectionResource<dw::core::ui::ListResource>::addItem
+ (str,enabled,selected);
+ int index = itemsSelected.size ();
+ itemsSelected.increase ();
+ itemsSelected.set (index,selected);
+ queueResize (true);
+}
+
+void FltkListResource::sizeRequest (core::Requisition *requisition)
+{
+ if (style) {
+ FltkFont *font = (FltkFont*)style->font;
+ ::fltk::setfont(font->font,font->size);
+ int maxStringWidth = getMaxStringWidth ();
+ requisition->ascent = font->ascent + RELIEF_Y_THICKNESS;
+ requisition->descent =
+ (getNumberOfItems () - 1) * (font->ascent) + font->descent;
+ requisition->width = maxStringWidth
+ + (font->ascent + font->descent) * 4 / 5
+ + 2 * RELIEF_X_THICKNESS;
+ } else {
+ requisition->width = 1;
+ requisition->ascent = 1;
+ requisition->descent = 0;
+ }
+}
+
+bool FltkListResource::isSelected (int index)
+{
+ return itemsSelected.get (index);
+}
+
+} // namespace ui
+} // namespace fltk
+} // namespace dw
+