summaryrefslogtreecommitdiff
path: root/dw/fltkviewbase.cc
diff options
context:
space:
mode:
authorRodrigo Arias Mallo <rodarima@gmail.com>2024-12-10 22:30:12 +0100
committerRodrigo Arias Mallo <rodarima@gmail.com>2024-12-10 22:30:12 +0100
commit429d5f88b94ff28416cbfc6420b6389fa284df97 (patch)
treefb6fdaf7731de1ef396f98b748c56f3149801c84 /dw/fltkviewbase.cc
Import RTFL 0.1.1v0.1.1
Diffstat (limited to 'dw/fltkviewbase.cc')
-rw-r--r--dw/fltkviewbase.cc744
1 files changed, 744 insertions, 0 deletions
diff --git a/dw/fltkviewbase.cc b/dw/fltkviewbase.cc
new file mode 100644
index 0000000..3b1c0cc
--- /dev/null
+++ b/dw/fltkviewbase.cc
@@ -0,0 +1,744 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+
+#include "fltkviewport.hh"
+
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+
+#include <stdio.h>
+#include "../lout/msg.h"
+
+extern Fl_Widget* fl_oldfocus;
+
+using namespace lout::object;
+using namespace lout::container::typed;
+
+namespace dw {
+namespace fltk {
+
+FltkViewBase::BackBuffer::BackBuffer ()
+{
+ w = 0;
+ h = 0;
+ created = false;
+}
+
+FltkViewBase::BackBuffer::~BackBuffer ()
+{
+ if (created)
+ fl_delete_offscreen (offscreen);
+}
+
+void FltkViewBase::BackBuffer::setSize (int w, int h)
+{
+ if (!created || w > this->w || h > this->h) {
+ this->w = w;
+ this->h = h;
+ if (created)
+ fl_delete_offscreen (offscreen);
+ offscreen = fl_create_offscreen (w, h);
+ created = true;
+ }
+}
+
+FltkViewBase::BackBuffer *FltkViewBase::backBuffer;
+bool FltkViewBase::backBufferInUse;
+
+FltkViewBase::FltkViewBase (int x, int y, int w, int h, const char *label):
+ Fl_Group (x, y, w, h, label)
+{
+ Fl_Group::current(0);
+ canvasWidth = 1;
+ canvasHeight = 1;
+ bgColor = FL_WHITE;
+ mouse_x = mouse_y = 0;
+ focused_child = NULL;
+ exposeArea = NULL;
+ if (backBuffer == NULL) {
+ backBuffer = new BackBuffer ();
+ }
+ box(FL_NO_BOX);
+ resizable(NULL);
+}
+
+FltkViewBase::~FltkViewBase ()
+{
+ cancelQueueDraw ();
+}
+
+void FltkViewBase::setBufferedDrawing (bool b) {
+ if (b && backBuffer == NULL) {
+ backBuffer = new BackBuffer ();
+ } else if (!b && backBuffer != NULL) {
+ delete backBuffer;
+ backBuffer = NULL;
+ }
+}
+
+void FltkViewBase::draw ()
+{
+ int d = damage ();
+
+ if ((d & FL_DAMAGE_USER1) && !(d & FL_DAMAGE_EXPOSE)) {
+ lout::container::typed::Iterator <core::Rectangle> it;
+
+ for (it = drawRegion.rectangles (); it.hasNext (); ) {
+ draw (it.getNext (), DRAW_BUFFERED);
+ }
+
+ drawRegion.clear ();
+ d &= ~FL_DAMAGE_USER1;
+ }
+
+ if (d & FL_DAMAGE_CHILD) {
+ drawChildWidgets ();
+ d &= ~FL_DAMAGE_CHILD;
+ }
+
+ if (d) {
+ dw::core::Rectangle rect (
+ translateViewXToCanvasX (x ()),
+ translateViewYToCanvasY (y ()),
+ w (),
+ h ());
+
+ if (d == FL_DAMAGE_SCROLL) {
+ // a clipping rectangle has already been set by fltk::scrollrect ()
+ draw (&rect, DRAW_PLAIN);
+ } else {
+ draw (&rect, DRAW_CLIPPED);
+ drawRegion.clear ();
+ }
+ }
+}
+
+void FltkViewBase::draw (const core::Rectangle *rect,
+ DrawType type)
+{
+ int X = translateCanvasXToViewX (rect->x);
+ int Y = translateCanvasYToViewY (rect->y);
+ int W, H;
+
+ // fl_clip_box() can't handle values greater than SHRT_MAX!
+ if (X > x () + w () || Y > y () + h ())
+ return;
+
+ W = X + rect->width > x () + w () ? x () + w () - X : rect->width;
+ H = Y + rect->height > y () + h () ? y () + h () - Y : rect->height;
+
+ fl_clip_box(X, Y, W, H, X, Y, W, H);
+
+ core::Rectangle r (translateViewXToCanvasX (X),
+ translateViewYToCanvasY (Y), W, H);
+
+ if (r.isEmpty ())
+ return;
+
+ exposeArea = &r;
+
+ if (type == DRAW_BUFFERED && backBuffer && !backBufferInUse) {
+ backBufferInUse = true;
+ backBuffer->setSize (X + W, Y + H); // would be nicer to use (W, H)...
+ fl_begin_offscreen (backBuffer->offscreen);
+ fl_push_matrix ();
+ fl_color (bgColor);
+ fl_rectf (X, Y, W, H);
+ theLayout->expose (this, &r);
+ fl_pop_matrix ();
+ fl_end_offscreen ();
+ fl_copy_offscreen (X, Y, W, H, backBuffer->offscreen, X, Y);
+ backBufferInUse = false;
+ } else if (type == DRAW_BUFFERED || type == DRAW_CLIPPED) {
+ // if type == DRAW_BUFFERED but we do not have backBuffer available
+ // we fall back to clipped drawing
+ fl_push_clip (X, Y, W, H);
+ fl_color (bgColor);
+ fl_rectf (X, Y, W, H);
+ theLayout->expose (this, &r);
+ fl_pop_clip ();
+ } else {
+ fl_color (bgColor);
+ fl_rectf (X, Y, W, H);
+ theLayout->expose (this, &r);
+ }
+ // DEBUG:
+ //fl_color(FL_RED);
+ //fl_rect(X, Y, W, H);
+
+ exposeArea = NULL;
+}
+
+void FltkViewBase::drawChildWidgets () {
+ for (int i = children () - 1; i >= 0; i--) {
+ Fl_Widget& w = *child(i);
+#if 0
+PORT1.3
+ if (w.damage() & DAMAGE_CHILD_LABEL) {
+ draw_outside_label(w);
+ w.set_damage(w.damage() & ~DAMAGE_CHILD_LABEL);
+ }
+#endif
+ update_child(w);
+ }
+}
+
+core::ButtonState getDwButtonState ()
+{
+ int s1 = Fl::event_state ();
+ int s2 = (core::ButtonState)0;
+
+ if (s1 & FL_SHIFT) s2 |= core::SHIFT_MASK;
+ if (s1 & FL_CTRL) s2 |= core::CONTROL_MASK;
+ if (s1 & FL_ALT) s2 |= core::META_MASK;
+ if (s1 & FL_BUTTON1) s2 |= core::BUTTON1_MASK;
+ if (s1 & FL_BUTTON2) s2 |= core::BUTTON2_MASK;
+ if (s1 & FL_BUTTON3) s2 |= core::BUTTON3_MASK;
+
+ return (core::ButtonState)s2;
+}
+
+/*
+ * We handle Tab to determine which FLTK widget should get focus.
+ *
+ * Presumably a proper solution that allows focusing links, etc., would live
+ * in Textblock and use iterators.
+ */
+int FltkViewBase::manageTabToFocus()
+{
+ int i, ret = 0;
+ Fl_Widget *old_child = NULL;
+
+ if (this == Fl::focus()) {
+ // if we have focus, give it to a child. Go forward typically,
+ // or backward with Shift pressed.
+ if (!(Fl::event_state() & FL_SHIFT)) {
+ for (i = 0; i < children(); i++) {
+ if (child(i)->take_focus()) {
+ ret = 1;
+ break;
+ }
+ }
+ } else {
+ for (i = children() - 1; i >= 0; i--) {
+ if (child(i)->take_focus()) {
+ ret = 1;
+ break;
+ }
+ }
+ }
+ } else {
+ // tabbing between children
+ old_child = Fl::focus();
+
+ if (!(ret = Fl_Group::handle (FL_KEYBOARD))) {
+ // group didn't have any more children to focus.
+ Fl::focus(this);
+ return 1;
+ } else {
+ // which one did it focus? (Note i == children() if not found)
+ i = find(Fl::focus());
+ }
+ }
+ if (ret) {
+ if (i >= 0 && i < children()) {
+ Fl_Widget *c = child(i);
+ int canvasX = translateViewXToCanvasX(c->x()),
+ canvasY = translateViewYToCanvasY(c->y());
+
+ theLayout->scrollTo(core::HPOS_INTO_VIEW, core::VPOS_INTO_VIEW,
+ canvasX, canvasY, c->w(), c->h());
+
+ // Draw the children who gained and lost focus. Otherwise a
+ // widget that had been only partly visible still shows its old
+ // appearance in the previously-visible portion.
+ core::Rectangle r(canvasX, canvasY, c->w(), c->h());
+
+ queueDraw(&r);
+
+ if (old_child) {
+ r.x = translateViewXToCanvasX(old_child->x());
+ r.y = translateViewYToCanvasY(old_child->y());
+ r.width = old_child->w();
+ r.height = old_child->h();
+ queueDraw(&r);
+ }
+ }
+ }
+ return ret;
+}
+
+int FltkViewBase::handle (int event)
+{
+ bool processed;
+
+ /**
+ * \todo Consider, whether this from the FLTK documentation has any
+ * impacts: "To receive fltk::RELEASE events you must return non-zero
+ * when passed a fltk::PUSH event. "
+ */
+ switch(event) {
+ case FL_PUSH:
+ /* Hide the tooltip */
+ theLayout->cancelTooltip();
+
+ processed =
+ theLayout->buttonPress (this, Fl::event_clicks () + 1,
+ translateViewXToCanvasX (Fl::event_x ()),
+ translateViewYToCanvasY (Fl::event_y ()),
+ getDwButtonState (), Fl::event_button ());
+ _MSG("PUSH => %s\n", processed ? "true" : "false");
+ if (processed) {
+ /* pressed dw content; give focus to the view */
+ if (Fl::event_button() != FL_RIGHT_MOUSE)
+ Fl::focus(this);
+ return true;
+ }
+ break;
+ case FL_RELEASE:
+ processed =
+ theLayout->buttonRelease (this, Fl::event_clicks () + 1,
+ translateViewXToCanvasX (Fl::event_x ()),
+ translateViewYToCanvasY (Fl::event_y ()),
+ getDwButtonState (), Fl::event_button ());
+ _MSG("RELEASE => %s\n", processed ? "true" : "false");
+ if (processed)
+ return true;
+ break;
+ case FL_MOVE:
+ mouse_x = Fl::event_x();
+ mouse_y = Fl::event_y();
+ processed =
+ theLayout->motionNotify (this,
+ translateViewXToCanvasX (mouse_x),
+ translateViewYToCanvasY (mouse_y),
+ getDwButtonState ());
+ _MSG("MOVE => %s\n", processed ? "true" : "false");
+ if (processed)
+ return true;
+ break;
+ case FL_DRAG:
+ processed =
+ theLayout->motionNotify (this,
+ translateViewXToCanvasX (Fl::event_x ()),
+ translateViewYToCanvasY (Fl::event_y ()),
+ getDwButtonState ());
+ _MSG("DRAG => %s\n", processed ? "true" : "false");
+ if (processed)
+ return true;
+ break;
+ case FL_ENTER:
+ theLayout->enterNotify (this,
+ translateViewXToCanvasX (Fl::event_x ()),
+ translateViewYToCanvasY (Fl::event_y ()),
+ getDwButtonState ());
+ break;
+ case FL_HIDE:
+ /* WORKAROUND: strangely, the tooltip window is not automatically hidden
+ * with its parent. Here we fake a LEAVE to achieve it. */
+ case FL_LEAVE:
+ theLayout->leaveNotify (this, getDwButtonState ());
+ break;
+ case FL_FOCUS:
+ if (focused_child && find(focused_child) < children()) {
+ /* strangely, find() == children() if the child is not found */
+ focused_child->take_focus();
+ }
+ return 1;
+ case FL_UNFOCUS:
+ focused_child = fl_oldfocus;
+ return 0;
+ case FL_KEYBOARD:
+ if (Fl::event_key() == FL_Tab)
+ return manageTabToFocus();
+ break;
+ default:
+ break;
+ }
+ return Fl_Group::handle (event);
+}
+
+// ----------------------------------------------------------------------
+
+void FltkViewBase::setLayout (core::Layout *layout)
+{
+ theLayout = layout;
+ if (usesViewport())
+ theLayout->viewportSizeChanged(this, w(), h());
+}
+
+void FltkViewBase::setCanvasSize (int width, int ascent, int descent)
+{
+ canvasWidth = width;
+ canvasHeight = ascent + descent;
+}
+
+void FltkViewBase::setCursor (core::style::Cursor cursor)
+{
+ static Fl_Cursor mapDwToFltk[] = {
+ FL_CURSOR_CROSS,
+ FL_CURSOR_DEFAULT,
+ FL_CURSOR_HAND,
+ FL_CURSOR_MOVE,
+ FL_CURSOR_WE,
+ FL_CURSOR_NESW,
+ FL_CURSOR_NWSE,
+ FL_CURSOR_NS,
+ FL_CURSOR_NWSE,
+ FL_CURSOR_NESW,
+ FL_CURSOR_NS,
+ FL_CURSOR_WE,
+ FL_CURSOR_INSERT,
+ FL_CURSOR_WAIT,
+ FL_CURSOR_HELP
+ };
+
+ fl_cursor (mapDwToFltk[cursor]);
+}
+
+void FltkViewBase::setBgColor (core::style::Color *color)
+{
+ bgColor = color ?
+ ((FltkColor*)color)->colors[dw::core::style::Color::SHADING_NORMAL] :
+ FL_WHITE;
+}
+
+void FltkViewBase::startDrawing (core::Rectangle *area)
+{
+}
+
+void FltkViewBase::finishDrawing (core::Rectangle *area)
+{
+}
+
+void FltkViewBase::queueDraw (core::Rectangle *area)
+{
+ drawRegion.addRectangle (area);
+ damage (FL_DAMAGE_USER1);
+}
+
+void FltkViewBase::queueDrawTotal ()
+{
+ damage (FL_DAMAGE_EXPOSE);
+}
+
+void FltkViewBase::cancelQueueDraw ()
+{
+}
+
+void FltkViewBase::drawPoint (core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x, int y)
+{
+}
+
+void FltkViewBase::drawLine (core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x1, int y1, int x2, int y2)
+{
+ fl_color(((FltkColor*)color)->colors[shading]);
+ // we clip with a large border (5000px), as clipping causes artefacts
+ // with non-solid line styles.
+ // However it's still better than no clipping at all.
+ clipPoint (&x1, &y1, 5000);
+ clipPoint (&x2, &y2, 5000);
+ fl_line (translateCanvasXToViewX (x1),
+ translateCanvasYToViewY (y1),
+ translateCanvasXToViewX (x2),
+ translateCanvasYToViewY (y2));
+}
+
+void FltkViewBase::drawTypedLine (core::style::Color *color,
+ core::style::Color::Shading shading,
+ core::style::LineType type, int width,
+ int x1, int y1, int x2, int y2)
+{
+ char dashes[3], w, ng, d, gap, len;
+ const int f = 2;
+
+ w = (width == 1) ? 0 : width;
+ if (type == core::style::LINE_DOTTED) {
+ /* customized drawing for dotted lines */
+ len = (x2 == x1) ? y2 - y1 + 1 : (y2 == y1) ? x2 - x1 + 1 : 0;
+ ng = len / f*width;
+ d = len % f*width;
+ gap = ng ? d/ng + (w > 3 ? 2 : 0) : 0;
+ dashes[0] = 1; dashes[1] = f*width-gap; dashes[2] = 0;
+ fl_line_style(FL_DASH + FL_CAP_ROUND, w, dashes);
+
+ /* These formulas also work, but ain't pretty ;)
+ * fl_line_style(FL_DOT + FL_CAP_ROUND, w);
+ * dashes[0] = 1; dashes[1] = 3*width-2; dashes[2] = 0;
+ */
+ } else if (type == core::style::LINE_DASHED) {
+ fl_line_style(FL_DASH + FL_CAP_ROUND, w);
+ }
+
+ fl_color(((FltkColor*)color)->colors[shading]);
+ drawLine (color, shading, x1, y1, x2, y2);
+
+ if (type != core::style::LINE_NORMAL)
+ fl_line_style(FL_SOLID);
+}
+
+void FltkViewBase::drawRectangle (core::style::Color *color,
+ core::style::Color::Shading shading,
+ bool filled,
+ int X, int Y, int width, int height)
+{
+ fl_color(((FltkColor*)color)->colors[shading]);
+ if (width < 0) {
+ X += width;
+ width = -width;
+ }
+ if (height < 0) {
+ Y += height;
+ height = -height;
+ }
+
+ int x1 = X;
+ int y1 = Y;
+ int x2 = X + width;
+ int y2 = Y + height;
+
+ // We only support rectangles with line width 1px, so we clip with
+ // a rectangle 1px wider and higher than what we actually expose.
+ // This is only really necessary for non-filled rectangles.
+ clipPoint (&x1, &y1, 1);
+ clipPoint (&x2, &y2, 1);
+
+ x1 = translateCanvasXToViewX (x1);
+ y1 = translateCanvasYToViewY (y1);
+ x2 = translateCanvasXToViewX (x2);
+ y2 = translateCanvasYToViewY (y2);
+
+ if (filled)
+ fl_rectf (x1, y1, x2 - x1, y2 - y1);
+ else
+ fl_rect (x1, y1, x2 - x1, y2 - y1);
+}
+
+void FltkViewBase::drawArc (core::style::Color *color,
+ core::style::Color::Shading shading, bool filled,
+ int centerX, int centerY, int width, int height,
+ int angle1, int angle2)
+{
+ fl_color(((FltkColor*)color)->colors[shading]);
+ int x = translateCanvasXToViewX (centerX) - width / 2;
+ int y = translateCanvasYToViewY (centerY) - height / 2;
+
+ fl_arc(x, y, width, height, angle1, angle2);
+ if (filled) {
+ // WORKAROUND: We call both fl_arc and fl_pie due to a FLTK bug
+ // (STR #2703) that was present in 1.3.0.
+ fl_pie(x, y, width, height, angle1, angle2);
+ }
+}
+
+void FltkViewBase::drawPolygon (core::style::Color *color,
+ core::style::Color::Shading shading,
+ bool filled, bool convex, core::Point *points,
+ int npoints)
+{
+ if (npoints > 0) {
+ fl_color(((FltkColor*)color)->colors[shading]);
+
+ if (filled) {
+ if (convex)
+ fl_begin_polygon();
+ else
+ fl_begin_complex_polygon();
+ } else
+ fl_begin_loop();
+
+ for (int i = 0; i < npoints; i++) {
+ fl_vertex(translateCanvasXToViewX(points[i].x),
+ translateCanvasYToViewY(points[i].y));
+ }
+ if (filled) {
+ if (convex)
+ fl_end_polygon();
+ else
+ fl_end_complex_polygon();
+ } else
+ fl_end_loop();
+ }
+}
+
+core::View *FltkViewBase::getClippingView (int x, int y, int width, int height)
+{
+ fl_push_clip (translateCanvasXToViewX (x), translateCanvasYToViewY (y),
+ width, height);
+ return this;
+}
+
+void FltkViewBase::mergeClippingView (core::View *clippingView)
+{
+ fl_pop_clip ();
+}
+
+// ----------------------------------------------------------------------
+
+FltkWidgetView::FltkWidgetView (int x, int y, int w, int h,
+ const char *label):
+ FltkViewBase (x, y, w, h, label)
+{
+}
+
+FltkWidgetView::~FltkWidgetView ()
+{
+}
+
+void FltkWidgetView::drawText (core::style::Font *font,
+ core::style::Color *color,
+ core::style::Color::Shading shading,
+ int X, int Y, const char *text, int len)
+{
+ //printf ("drawText (..., %d, %d, '", X, Y);
+ //for (int i = 0; i < len; i++)
+ // putchar (text[i]);
+ //printf ("'\n");
+
+ FltkFont *ff = (FltkFont*)font;
+ fl_font(ff->font, ff->size);
+ fl_color(((FltkColor*)color)->colors[shading]);
+
+ if (!font->letterSpacing && !font->fontVariant) {
+ fl_draw(text, len,
+ translateCanvasXToViewX (X), translateCanvasYToViewY (Y));
+ } else {
+ /* Nonzero letter spacing adjustment, draw each glyph individually */
+ int viewX = translateCanvasXToViewX (X),
+ viewY = translateCanvasYToViewY (Y);
+ int curr = 0, next = 0, nb;
+ char chbuf[4];
+ int c, cu, width;
+
+ if (font->fontVariant == core::style::FONT_VARIANT_SMALL_CAPS) {
+ int sc_fontsize = lout::misc::roundInt(ff->size * 0.78);
+ for (curr = 0; next < len; curr = next) {
+ next = theLayout->nextGlyph(text, curr);
+ c = fl_utf8decode(text + curr, text + next, &nb);
+ if ((cu = fl_toupper(c)) == c) {
+ /* already uppercase, just draw the character */
+ fl_font(ff->font, ff->size);
+ width = (int)fl_width(text + curr, next - curr);
+ if (curr && width)
+ viewX += font->letterSpacing;
+ fl_draw(text + curr, next - curr, viewX, viewY);
+ viewX += width;
+ } else {
+ /* make utf8 string for converted char */
+ nb = fl_utf8encode(cu, chbuf);
+ fl_font(ff->font, sc_fontsize);
+ width = (int)fl_width(chbuf, nb);
+ if (curr && width)
+ viewX += font->letterSpacing;
+ fl_draw(chbuf, nb, viewX, viewY);
+ viewX += width;
+ }
+ }
+ } else {
+ while (next < len) {
+ next = theLayout->nextGlyph(text, curr);
+ width = (int)fl_width(text + curr, next - curr);
+ if (curr && width)
+ viewX += font->letterSpacing;
+ fl_draw(text + curr, next - curr, viewX, viewY);
+ viewX += width;
+ curr = next;
+ }
+ }
+ }
+}
+
+/*
+ * "simple" in that it ignores letter-spacing, etc. This was added for image
+ * alt text where none of that matters.
+ */
+void FltkWidgetView::drawSimpleWrappedText (core::style::Font *font,
+ core::style::Color *color,
+ core::style::Color::Shading shading,
+ int X, int Y, int W, int H,
+ const char *text)
+{
+ FltkFont *ff = (FltkFont*)font;
+ fl_font(ff->font, ff->size);
+ fl_color(((FltkColor*)color)->colors[shading]);
+ fl_draw(text,
+ translateCanvasXToViewX (X), translateCanvasYToViewY (Y),
+ W, H, FL_ALIGN_TOP|FL_ALIGN_LEFT|FL_ALIGN_WRAP, NULL, 0);
+}
+
+void FltkWidgetView::drawImage (core::Imgbuf *imgbuf, int xRoot, int yRoot,
+ int X, int Y, int width, int height)
+{
+ ((FltkImgbuf*)imgbuf)->draw (this,
+ translateCanvasXToViewX (xRoot),
+ translateCanvasYToViewY (yRoot),
+ X, Y, width, height);
+}
+
+bool FltkWidgetView::usesFltkWidgets ()
+{
+ return true;
+}
+
+void FltkWidgetView::addFltkWidget (Fl_Widget *widget,
+ core::Allocation *allocation)
+{
+ allocateFltkWidget (widget, allocation);
+ add (widget);
+}
+
+void FltkWidgetView::removeFltkWidget (Fl_Widget *widget)
+{
+ remove (widget);
+}
+
+void FltkWidgetView::allocateFltkWidget (Fl_Widget *widget,
+ core::Allocation *allocation)
+{
+ widget->resize (translateCanvasXToViewX (allocation->x),
+ translateCanvasYToViewY (allocation->y),
+ allocation->width,
+ allocation->ascent + allocation->descent);
+}
+
+void FltkWidgetView::drawFltkWidget (Fl_Widget *widget,
+ core::Rectangle *area)
+{
+ draw_child (*widget);
+ draw_outside_label(*widget);
+}
+
+} // namespace fltk
+} // namespace dw