diff options
Diffstat (limited to 'dw/fltkviewport.cc')
-rw-r--r-- | dw/fltkviewport.cc | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/dw/fltkviewport.cc b/dw/fltkviewport.cc new file mode 100644 index 00000000..c999745a --- /dev/null +++ b/dw/fltkviewport.cc @@ -0,0 +1,496 @@ +/* + * 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 "fltkviewport.hh" + +#include <fltk/draw.h> +#include <fltk/damage.h> +#include <fltk/events.h> + +#include <stdio.h> + +using namespace fltk; +using namespace lout::object; +using namespace lout::container::typed; + +namespace dw { +namespace fltk { + +FltkViewport::FltkViewport (int x, int y, int w, int h, const char *label): + FltkWidgetView (x, y, w, h, label) +{ + hscrollbar = new Scrollbar (0, 0, 1, 1); + hscrollbar->set_horizontal(); + hscrollbar->callback (hscrollbarCallback, this); + add (hscrollbar); + + vscrollbar = new Scrollbar (0, 0, 1, 1); + vscrollbar->set_vertical(); + vscrollbar->callback (vscrollbarCallback, this); + add (vscrollbar); + + scrollX = scrollY = scrollDX = scrollDY = 0; + dragScrolling = 0; + + gadgetOrientation[0] = GADGET_HORIZONTAL; + gadgetOrientation[1] = GADGET_HORIZONTAL; + gadgetOrientation[2] = GADGET_VERTICAL; + gadgetOrientation[3] = GADGET_HORIZONTAL; + + gadgets = + new container::typed::List <object::TypedPointer < ::fltk::Widget> > + (true); +} + +FltkViewport::~FltkViewport () +{ + delete gadgets; +} + +void FltkViewport::adjustScrollbarsAndGadgetsAllocation () +{ + int hdiff = 0, vdiff = 0; + int visibility = 0; + + if (hscrollbar->visible ()) + visibility |= 1; + if (vscrollbar->visible ()) + visibility |= 2; + + if (gadgets->size () > 0) { + switch (gadgetOrientation [visibility]) { + case GADGET_VERTICAL: + hdiff = SCROLLBAR_THICKNESS; + vdiff = SCROLLBAR_THICKNESS * gadgets->size (); + break; + + case GADGET_HORIZONTAL: + hdiff = SCROLLBAR_THICKNESS * gadgets->size (); + vdiff = SCROLLBAR_THICKNESS; + break; + } + } else { + hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + } + + hscrollbar->x (0); + hscrollbar->y (0 + h () - SCROLLBAR_THICKNESS); + hscrollbar->w (w () - hdiff); + hscrollbar->h (SCROLLBAR_THICKNESS); + + vscrollbar->x (0 + w () - SCROLLBAR_THICKNESS); + vscrollbar->y (0); + vscrollbar->h (h () - vdiff); + vscrollbar->w (SCROLLBAR_THICKNESS); + + int x = w () - SCROLLBAR_THICKNESS, y = h () - SCROLLBAR_THICKNESS; + for(Iterator <TypedPointer < ::fltk::Widget> > it = gadgets->iterator (); + it.hasNext (); ) { + ::fltk::Widget *widget = it.getNext()->getTypedValue (); + widget->x (0); + widget->y (0); + widget->w (SCROLLBAR_THICKNESS); + widget->h (SCROLLBAR_THICKNESS); + + switch (gadgetOrientation [visibility]) { + case GADGET_VERTICAL: + y -= SCROLLBAR_THICKNESS; + break; + + case GADGET_HORIZONTAL: + x -= SCROLLBAR_THICKNESS; + break; + } + } +} + +void FltkViewport::adjustScrollbarValues () +{ + hscrollbar->value (scrollX, hscrollbar->w (), 0, canvasWidth); + vscrollbar->value (scrollY, vscrollbar->h (), 0, canvasHeight); +} + +void FltkViewport::hscrollbarChanged () +{ + scroll (hscrollbar->value () - scrollX, 0); +} + +void FltkViewport::vscrollbarChanged () +{ + scroll (0, vscrollbar->value () - scrollY); +} + +void FltkViewport::vscrollbarCallback (Widget *vscrollbar, void *viewportPtr) +{ + ((FltkViewport*)viewportPtr)->vscrollbarChanged (); +} + +void FltkViewport::hscrollbarCallback (Widget *hscrollbar, void *viewportPtr) +{ + ((FltkViewport*)viewportPtr)->hscrollbarChanged (); +} + +// ---------------------------------------------------------------------- + +void FltkViewport::layout () +{ + theLayout->viewportSizeChanged (this, w(), h()); + adjustScrollbarsAndGadgetsAllocation (); + + FltkWidgetView::layout (); +} + +void FltkViewport::draw_area (void *data, const Rectangle& cr ) +{ + FltkViewport *vp = (FltkViewport*) data; + push_clip(cr); + + vp->FltkWidgetView::draw (); + + for(Iterator <TypedPointer < ::fltk::Widget> > it = vp->gadgets->iterator (); + it.hasNext (); ) { + ::fltk::Widget *widget = it.getNext()->getTypedValue (); + vp->draw_child (*widget); + } + + pop_clip(); + +} + +void FltkViewport::draw () +{ + int hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + int vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + Rectangle cr (0, 0, w () - hdiff, h () - vdiff); + int d = damage(); + + if (d & DAMAGE_SCROLL) { + set_damage (DAMAGE_SCROLL); + scrollrect(cr, -scrollDX, -scrollDY, draw_area, this); + d &= ~DAMAGE_SCROLL; + set_damage (d); + } + + if (d) { + draw_area(this, cr); + + if (d == DAMAGE_CHILD) { + if (hscrollbar->damage ()) + draw_child (*hscrollbar); + if (vscrollbar->damage ()) + draw_child (*vscrollbar); + } else { + draw_child (*hscrollbar); + draw_child (*vscrollbar); + } + } + + scrollDX = 0; + scrollDY = 0; +} + +int FltkViewport::handle (int event) +{ + //printf("FltkViewport::handle %d\n", event); + + if (hscrollbar->Rectangle::contains (event_x (), event_y ()) && + !(event_state() & (SHIFT | CTRL | ALT)) && + hscrollbar->send (event)) { + return 1; + } + + if (vscrollbar->Rectangle::contains (event_x (), event_y ()) && + vscrollbar->send (event)) { + return 1; + } + + switch(event) { + case ::fltk::FOCUS: + /** \bug Draw focus box. */ + return 1; + + case ::fltk::UNFOCUS: + /** \bug Undraw focus box. */ + return 1; + + case ::fltk::PUSH: + take_focus(); + if (::fltk::event_button() == ::fltk::MiddleButton) { + /* pass event so that middle click can open link in new window */ + if (FltkWidgetView::handle (event) == 0) { + dragScrolling = 1; + dragX = ::fltk::event_x(); + dragY = ::fltk::event_y(); + setCursor (core::style::CURSOR_MOVE); + } + return 1; + } + break; + + case ::fltk::DRAG: + if (::fltk::event_button() == ::fltk::MiddleButton) { + if (dragScrolling) { + scroll(dragX - ::fltk::event_x(), dragY - ::fltk::event_y()); + dragX = ::fltk::event_x(); + dragY = ::fltk::event_y(); + return 1; + } + } + break; + + case ::fltk:: MOUSEWHEEL: + return (event_dx() ? hscrollbar : vscrollbar)->handle(event); + break; + + case ::fltk::RELEASE: + if (::fltk::event_button() == ::fltk::MiddleButton) { + dragScrolling = 0; + setCursor (core::style::CURSOR_DEFAULT); + } + break; + + case ::fltk::ENTER: + /* could be the result of, e.g., closing another window. */ + mouse_x = ::fltk::event_x(); + mouse_y = ::fltk::event_y(); + positionChanged(); + break; + + case ::fltk::LEAVE: + mouse_x = mouse_y = -1; + break; + + case ::fltk::KEY: + /* tell fltk we want to receive these KEY events as SHORTCUT */ + switch (::fltk::event_key()) { + case PageUpKey: + case PageDownKey: + case SpaceKey: + case DownKey: + case UpKey: + case RightKey: + case LeftKey: + case HomeKey: + case EndKey: + return 0; + } + break; + + case ::fltk::SHORTCUT: + switch (::fltk::event_key()) { + case PageUpKey: + case 'b': + case 'B': + scroll (0, -vscrollbar->pagesize ()); + return 1; + + case PageDownKey: + case SpaceKey: + scroll (0, vscrollbar->pagesize ()); + return 1; + + case DownKey: + scroll (0, (int) vscrollbar->linesize ()); + return 1; + + case UpKey: + scroll (0, (int) -vscrollbar->linesize ()); + return 1; + + case RightKey: + scroll ((int) hscrollbar->linesize (), 0); + return 1; + + case LeftKey: + scroll ((int) -hscrollbar->linesize (), 0); + return 1; + + case HomeKey: + scrollTo (scrollX, 0); + return 1; + + case EndKey: + scrollTo (scrollX, canvasHeight); /* gets adjusted in scrollTo () */ + return 1; + } + } + + return FltkWidgetView::handle (event); +} + +// ---------------------------------------------------------------------- + +void FltkViewport::setCanvasSize (int width, int ascent, int descent) +{ + FltkWidgetView::setCanvasSize (width, ascent, descent); + adjustScrollbarValues (); +} + +/* + * This is used to simulate mouse motion (e.g., when scrolling). + */ +void FltkViewport::positionChanged () +{ + if (mouse_x != -1) + (void)theLayout->motionNotify (this, + translateViewXToCanvasX (mouse_x), + translateViewYToCanvasY (mouse_y), + (core::ButtonState)0); +} + +/* + * For scrollbars, this currently sets the same step to both vertical and + * horizontal. It may me differentiated if necessary. + */ +void FltkViewport::setScrollStep(int step) +{ + vscrollbar->linesize(step); + hscrollbar->linesize(step); +} + +bool FltkViewport::usesViewport () +{ + return true; +} + +int FltkViewport::getHScrollbarThickness () +{ + return SCROLLBAR_THICKNESS; +} + +int FltkViewport::getVScrollbarThickness () +{ + return SCROLLBAR_THICKNESS; +} + +void FltkViewport::scrollTo (int x, int y) +{ + int hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + int vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0; + + x = misc::min (x, canvasWidth - w() + hdiff); + x = misc::max (x, 0); + + y = misc::min (y, canvasHeight - h() + vdiff); + y = misc::max (y, 0); + + if (x == scrollX && y == scrollY) { + return; + } + + /* multiple calls to scroll can happen before a redraw occurs. + * scrollDX / scrollDY can therefore be non-zero here. + */ + updateCanvasWidgets (x - scrollX, y - scrollY); + scrollDX += x - scrollX; + scrollDY += y - scrollY; + + scrollX = x; + scrollY = y; + + adjustScrollbarValues (); + redraw (DAMAGE_SCROLL); + theLayout->scrollPosChanged (this, scrollX, scrollY); + positionChanged(); +} + +void FltkViewport::scroll (int dx, int dy) +{ + scrollTo (scrollX + dx, scrollY + dy); +} + +void FltkViewport::setViewportSize (int width, int height, + int hScrollbarThickness, + int vScrollbarThickness) +{ + if (hScrollbarThickness > 0) + hscrollbar->show (); + else + hscrollbar->hide (); + if (vScrollbarThickness > 0) + vscrollbar->show (); + else + vscrollbar->hide (); + + /* If no scrollbar, go to the beginning */ + scroll(hScrollbarThickness ? 0 : -scrollX, + vScrollbarThickness ? 0 : -scrollY); +} + +void FltkViewport::updateCanvasWidgets (int dx, int dy) +{ + // scroll all child widgets except scroll bars + for (int i = children () - 1; i > 0; i--) { + ::fltk::Widget *widget = child (i); + + if (widget == hscrollbar || widget == vscrollbar) + continue; + + widget->x (widget->x () - dx); + widget->y (widget->y () - dy); + } +} + +int FltkViewport::translateViewXToCanvasX (int x) +{ + return x + scrollX; +} + +int FltkViewport::translateViewYToCanvasY (int y) +{ + return y + scrollY; +} + +int FltkViewport::translateCanvasXToViewX (int x) +{ + return x - scrollX; +} + +int FltkViewport::translateCanvasYToViewY (int y) +{ + return y - scrollY; +} + +// ---------------------------------------------------------------------- + +void FltkViewport::setGadgetOrientation (bool hscrollbarVisible, + bool vscrollbarVisible, + FltkViewport::GadgetOrientation + gadgetOrientation) +{ + this->gadgetOrientation[(hscrollbarVisible ? 0 : 1) | + (vscrollbarVisible ? 0 : 2)] = gadgetOrientation; + adjustScrollbarsAndGadgetsAllocation (); +} + +void FltkViewport::addGadget (::fltk::Widget *gadget) +{ + /** \bug Reparent? */ + + gadgets->append (new TypedPointer < ::fltk::Widget> (gadget)); + adjustScrollbarsAndGadgetsAllocation (); +} + + +} // namespace fltk +} // namespace dw |