diff options
Diffstat (limited to 'dw/fltkui.cc')
-rw-r--r-- | dw/fltkui.cc | 1202 |
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 + |