673 lines
19 KiB
C++
673 lines
19 KiB
C++
/*
|
|
* Dillo Widget
|
|
*
|
|
* Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
|
|
* Copyright 2024 Rodrigo Arias Mallo <rodarima@gmail.com>
|
|
*
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
|
|
#include "fltkviewport.hh"
|
|
|
|
#include <FL/Fl.H>
|
|
#include <FL/fl_draw.H>
|
|
#include <FL/names.h>
|
|
|
|
#include <stdio.h>
|
|
#include "../lout/msg.h"
|
|
#include "../lout/debug.hh"
|
|
|
|
using namespace lout;
|
|
using namespace lout::object;
|
|
using namespace lout::container::typed;
|
|
|
|
namespace dw {
|
|
namespace fltk {
|
|
|
|
/*
|
|
* Lets SHIFT+{Left,Right} go to the parent
|
|
*/
|
|
class CustScrollbar : public Fl_Scrollbar
|
|
{
|
|
public:
|
|
CustScrollbar(int x, int y, int w, int h) : Fl_Scrollbar(x,y,w,h) {};
|
|
int handle(int e) {
|
|
if (e == FL_SHORTCUT && Fl::event_state() == FL_SHIFT &&
|
|
(Fl::event_key() == FL_Left || Fl::event_key() == FL_Right))
|
|
return 0;
|
|
return Fl_Scrollbar::handle(e);
|
|
}
|
|
};
|
|
|
|
FltkViewport::FltkViewport (int X, int Y, int W, int H, const char *label):
|
|
FltkWidgetView (X, Y, W, H, label)
|
|
{
|
|
DBG_OBJ_CREATE ("dw::fltk::FltkViewport");
|
|
|
|
hscrollbar = new CustScrollbar (x (), y (), 1, 1);
|
|
hscrollbar->type(FL_HORIZONTAL);
|
|
hscrollbar->callback (hscrollbarCallback, this);
|
|
hscrollbar->hide();
|
|
add (hscrollbar);
|
|
|
|
vscrollbar = new Fl_Scrollbar (x (), y(), 1, 1);
|
|
vscrollbar->type(FL_VERTICAL);
|
|
vscrollbar->callback (vscrollbarCallback, this);
|
|
vscrollbar->hide();
|
|
add (vscrollbar);
|
|
|
|
hasDragScroll = 1;
|
|
scrollX = scrollY = scrollDX = scrollDY = 0;
|
|
horScrolling = verScrolling = dragScrolling = 0;
|
|
scrollbarPageMode = false;
|
|
pageOverlap = 50;
|
|
pageScrolling = core::NONE_CMD;
|
|
|
|
pageScrollDelay = 0.300;
|
|
pageScrollInterval = 0.100;
|
|
|
|
gadgetOrientation[0] = GADGET_HORIZONTAL;
|
|
gadgetOrientation[1] = GADGET_HORIZONTAL;
|
|
gadgetOrientation[2] = GADGET_VERTICAL;
|
|
gadgetOrientation[3] = GADGET_HORIZONTAL;
|
|
}
|
|
|
|
FltkViewport::~FltkViewport ()
|
|
{
|
|
DBG_OBJ_DELETE ();
|
|
}
|
|
|
|
void FltkViewport::adjustScrollbarsAndGadgetsAllocation ()
|
|
{
|
|
int hdiff = 0, vdiff = 0;
|
|
int visibility = 0;
|
|
|
|
_MSG(" >>FltkViewport::adjustScrollbarsAndGadgetsAllocation\n");
|
|
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;
|
|
}
|
|
|
|
if (scrollbarOnLeft) {
|
|
hscrollbar->resize(x () + hdiff, y () + h () - SCROLLBAR_THICKNESS,
|
|
w () - hdiff, SCROLLBAR_THICKNESS);
|
|
vscrollbar->resize(x (), y (),
|
|
SCROLLBAR_THICKNESS, h () - vdiff);
|
|
} else {
|
|
hscrollbar->resize(x (), y () + h () - SCROLLBAR_THICKNESS,
|
|
w () - hdiff, SCROLLBAR_THICKNESS);
|
|
vscrollbar->resize(x () + w () - SCROLLBAR_THICKNESS, y (),
|
|
SCROLLBAR_THICKNESS, h () - vdiff);
|
|
}
|
|
|
|
//int X = x () + w () - SCROLLBAR_THICKNESS;
|
|
//int Y = y () + h () - SCROLLBAR_THICKNESS;
|
|
for( auto &widget : gadgets )
|
|
{
|
|
widget->resize(x (), y (), SCROLLBAR_THICKNESS, SCROLLBAR_THICKNESS);
|
|
|
|
/* FIXME: This has no effect */
|
|
#if 0
|
|
switch (gadgetOrientation [visibility]) {
|
|
case GADGET_VERTICAL:
|
|
Y -= SCROLLBAR_THICKNESS;
|
|
break;
|
|
|
|
case GADGET_HORIZONTAL:
|
|
X -= SCROLLBAR_THICKNESS;
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
adjustScrollbarValues();
|
|
}
|
|
|
|
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 (Fl_Widget *vscrollbar,void *viewportPtr)
|
|
{
|
|
((FltkViewport*)viewportPtr)->vscrollbarChanged ();
|
|
}
|
|
|
|
void FltkViewport::hscrollbarCallback (Fl_Widget *hscrollbar,void *viewportPtr)
|
|
{
|
|
((FltkViewport*)viewportPtr)->hscrollbarChanged ();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
void FltkViewport::resize(int X, int Y, int W, int H)
|
|
{
|
|
bool dimension_changed = W != w() || H != h();
|
|
|
|
Fl_Group::resize(X, Y, W, H);
|
|
if (dimension_changed) {
|
|
theLayout->viewportSizeChanged (this, W, H);
|
|
adjustScrollbarsAndGadgetsAllocation ();
|
|
}
|
|
}
|
|
|
|
void FltkViewport::draw_area (void *data, int x, int y, int w, int h)
|
|
{
|
|
FltkViewport *vp = (FltkViewport*) data;
|
|
fl_push_clip(x, y, w, h);
|
|
|
|
vp->FltkWidgetView::draw ();
|
|
|
|
for( auto &widget: vp->gadgets )
|
|
{
|
|
vp->draw_child (*widget);
|
|
}
|
|
|
|
fl_pop_clip();
|
|
}
|
|
|
|
/*
|
|
* Draw the viewport.
|
|
*
|
|
* + Damage flags come in different ways, draw() should cope with them all.
|
|
* + Damage flags are alive for visible and hidden widgets.
|
|
* + FL_DAMAGE_CHILD can flag scroll bars or embedded FLTK widgets.
|
|
*/
|
|
void FltkViewport::draw ()
|
|
{
|
|
const int d = damage(),
|
|
vis_vs = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0,
|
|
vis_hs = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0,
|
|
draw = d & (FL_DAMAGE_ALL | FL_DAMAGE_EXPOSE),
|
|
draw_vs = vis_vs && vscrollbar->damage (),
|
|
draw_hs = vis_hs && hscrollbar->damage ();
|
|
|
|
_MSG("FltkViewport::draw d=%d => ", d);
|
|
// scrollbars
|
|
if (draw || draw_vs)
|
|
draw_child (*vscrollbar);
|
|
if (draw || draw_hs)
|
|
draw_child (*hscrollbar);
|
|
if (draw && vis_vs && vis_hs) {
|
|
fl_color(FL_BACKGROUND_COLOR);
|
|
if (scrollbarOnLeft) {
|
|
fl_rectf(x(), y()+h()-vis_hs, vis_vs, vis_hs);
|
|
} else {
|
|
fl_rectf(x()+w()-vis_vs, y()+h()-vis_hs, vis_vs, vis_hs);
|
|
}
|
|
}
|
|
// main area
|
|
if (d == FL_DAMAGE_CHILD && (draw_vs || draw_hs)) {
|
|
_MSG("none\n");
|
|
} else if (d == (FL_DAMAGE_SCROLL | FL_DAMAGE_CHILD)) {
|
|
int x = this->x();
|
|
|
|
if (scrollbarOnLeft)
|
|
x += vis_vs;
|
|
fl_scroll(x, y(), w() - vis_vs, h() - vis_hs,
|
|
-scrollDX, -scrollDY, draw_area, this);
|
|
_MSG("fl_scroll()\n");
|
|
} else {
|
|
int x = this->x();
|
|
|
|
if (scrollbarOnLeft)
|
|
x += vis_vs;
|
|
draw_area(this, x, y(), w() - vis_vs, h() - vis_hs);
|
|
_MSG("draw_area()\n");
|
|
}
|
|
|
|
scrollDX = 0;
|
|
scrollDY = 0;
|
|
}
|
|
|
|
int FltkViewport::handle (int event)
|
|
{
|
|
int ret = 0;
|
|
_MSG("FltkViewport::handle %s\n", fl_eventnames[event]);
|
|
|
|
switch(event) {
|
|
case FL_KEYBOARD:
|
|
/* When the viewport has focus (and not one of its children), FLTK
|
|
* sends the event here. Returning zero tells FLTK to resend the
|
|
* event as SHORTCUT, which we finally route to the parent. */
|
|
|
|
/* As we don't know the exact keybindings set by the user, we ask for
|
|
* all of them (except for the minimum needed to keep form navigation).*/
|
|
if (Fl::event_key() != FL_Tab || Fl::event_ctrl())
|
|
return 0;
|
|
break;
|
|
|
|
case FL_SHORTCUT:
|
|
/* send it to the parent (UI) */
|
|
return 0;
|
|
|
|
case FL_FOCUS:
|
|
/** \bug Draw focus box. */
|
|
break;
|
|
|
|
case FL_UNFOCUS:
|
|
/** \bug Undraw focus box. */
|
|
break;
|
|
|
|
case FL_PUSH:
|
|
if (vscrollbar->visible() && Fl::event_inside(vscrollbar)) {
|
|
if (scrollbarPageMode ^ (bool) Fl::event_shift()) {
|
|
/* Check top and bottom actions first */
|
|
int yclick = Fl::event_y();
|
|
int ytop = y() + SCROLLBAR_THICKNESS;
|
|
int ybottom = y() + h() - SCROLLBAR_THICKNESS;
|
|
if (hscrollbar->visible())
|
|
ybottom -= SCROLLBAR_THICKNESS;
|
|
|
|
if (yclick <= ytop) {
|
|
scroll(core::TOP_CMD);
|
|
return 1;
|
|
} else if (yclick >= ybottom) {
|
|
scroll(core::BOTTOM_CMD);
|
|
return 1;
|
|
}
|
|
|
|
if (Fl::event_button() == FL_LEFT_MOUSE)
|
|
pageScrolling = core::SCREEN_DOWN_CMD;
|
|
else if (Fl::event_button() == FL_RIGHT_MOUSE)
|
|
pageScrolling = core::SCREEN_UP_CMD;
|
|
else
|
|
pageScrolling = core::NONE_CMD;
|
|
|
|
if (pageScrolling != core::NONE_CMD) {
|
|
scroll(pageScrolling);
|
|
/* Repeat until released */
|
|
if (!Fl::has_timeout(repeatPageScroll, this))
|
|
Fl::add_timeout(pageScrollDelay, repeatPageScroll, this);
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
if (vscrollbar->handle(event)) {
|
|
verScrolling = 1;
|
|
}
|
|
} else if (hscrollbar->visible() && Fl::event_inside(hscrollbar)) {
|
|
if (hscrollbar->handle(event))
|
|
horScrolling = 1;
|
|
} else if (FltkWidgetView::handle(event) == 0 &&
|
|
Fl::event_button() == FL_MIDDLE_MOUSE) {
|
|
if (!hasDragScroll) {
|
|
/* let the parent widget handle it... */
|
|
return 0;
|
|
} else {
|
|
/* receive FL_DRAG and FL_RELEASE */
|
|
dragScrolling = 1;
|
|
dragX = Fl::event_x();
|
|
dragY = Fl::event_y();
|
|
setCursor (core::style::CURSOR_MOVE);
|
|
}
|
|
}
|
|
return 1;
|
|
break;
|
|
|
|
case FL_DRAG:
|
|
if (Fl::event_inside(this))
|
|
Fl::remove_timeout(selectionScroll);
|
|
if (dragScrolling) {
|
|
scroll(dragX - Fl::event_x(), dragY - Fl::event_y());
|
|
dragX = Fl::event_x();
|
|
dragY = Fl::event_y();
|
|
return 1;
|
|
} else if (verScrolling) {
|
|
vscrollbar->handle(event);
|
|
return 1;
|
|
} else if (horScrolling) {
|
|
hscrollbar->handle(event);
|
|
return 1;
|
|
} else if (!Fl::event_inside(this)) {
|
|
mouse_x = Fl::event_x();
|
|
mouse_y = Fl::event_y();
|
|
if (!Fl::has_timeout(selectionScroll, this))
|
|
Fl::add_timeout(0.025, selectionScroll, this);
|
|
}
|
|
break;
|
|
|
|
case FL_MOUSEWHEEL:
|
|
if ((vscrollbar->visible() && Fl::event_inside(vscrollbar)) ||
|
|
Fl::event_shift()) {
|
|
if (Fl::event_dy() > 0) {
|
|
scroll(core::SCREEN_DOWN_CMD);
|
|
return 1;
|
|
} else if (Fl::event_dy() < 0) {
|
|
scroll(core::SCREEN_UP_CMD);
|
|
return 1;
|
|
}
|
|
}
|
|
return (Fl::event_dx() ? hscrollbar : vscrollbar)->handle(event);
|
|
break;
|
|
|
|
case FL_RELEASE:
|
|
Fl::remove_timeout(repeatPageScroll);
|
|
Fl::remove_timeout(selectionScroll);
|
|
if (Fl::event_button() == FL_MIDDLE_MOUSE) {
|
|
setCursor (core::style::CURSOR_DEFAULT);
|
|
} else if (verScrolling) {
|
|
ret = vscrollbar->handle(event);
|
|
} else if (horScrolling) {
|
|
ret = hscrollbar->handle(event);
|
|
}
|
|
horScrolling = verScrolling = dragScrolling = 0;
|
|
break;
|
|
|
|
case FL_ENTER:
|
|
if (vscrollbar->visible() && Fl::event_inside(vscrollbar))
|
|
return vscrollbar->handle(event);
|
|
if (hscrollbar->visible() && Fl::event_inside(hscrollbar))
|
|
return hscrollbar->handle(event);
|
|
/* could be the result of, e.g., closing another window. */
|
|
mouse_x = Fl::event_x();
|
|
mouse_y = Fl::event_y();
|
|
positionChanged();
|
|
break;
|
|
|
|
case FL_MOVE:
|
|
/* Use LEAVE in order not to be over a link, etc., anymore. */
|
|
if (vscrollbar->visible() && Fl::event_inside(vscrollbar)) {
|
|
(void)FltkWidgetView::handle(FL_LEAVE);
|
|
return vscrollbar->handle(event);
|
|
}
|
|
if (hscrollbar->visible() && Fl::event_inside(hscrollbar)) {
|
|
(void)FltkWidgetView::handle(FL_LEAVE);
|
|
return hscrollbar->handle(event);
|
|
}
|
|
break;
|
|
case FL_LEAVE:
|
|
mouse_x = mouse_y = -1;
|
|
break;
|
|
}
|
|
|
|
return ret ? ret : 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 (!dragScrolling && mouse_x >= x() && mouse_x < x()+w() && mouse_y >= y()
|
|
&& mouse_y < y()+h())
|
|
(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 be differentiated if necessary.
|
|
*/
|
|
void FltkViewport::setScrollStep(int step)
|
|
{
|
|
vscrollbar->linesize(step);
|
|
hscrollbar->linesize(step);
|
|
}
|
|
|
|
void FltkViewport::setPageOverlap(int overlap)
|
|
{
|
|
pageOverlap = overlap;
|
|
}
|
|
|
|
void FltkViewport::setScrollbarPageMode(bool enable)
|
|
{
|
|
scrollbarPageMode = enable;
|
|
}
|
|
|
|
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 = std::min (x, canvasWidth - w() + hdiff);
|
|
x = std::max (x, 0);
|
|
|
|
y = std::min (y, canvasHeight - h() + vdiff);
|
|
y = std::max (y, 0);
|
|
|
|
if (x == scrollX && y == scrollY) {
|
|
return;
|
|
}
|
|
|
|
/* multiple calls to scroll can happen before a redraw occurs.
|
|
* scrollDX and scrollDY can therefore be non-zero here.
|
|
*/
|
|
updateCanvasWidgets (x - scrollX, y - scrollY);
|
|
scrollDX += x - scrollX;
|
|
scrollDY += y - scrollY;
|
|
|
|
scrollX = x;
|
|
scrollY = y;
|
|
|
|
adjustScrollbarValues ();
|
|
damage(FL_DAMAGE_SCROLL);
|
|
theLayout->scrollPosChanged (this, scrollX, scrollY);
|
|
positionChanged();
|
|
}
|
|
|
|
void FltkViewport::scroll (int dx, int dy)
|
|
{
|
|
scrollTo (scrollX + dx, scrollY + dy);
|
|
}
|
|
|
|
void FltkViewport::scroll (core::ScrollCommand cmd)
|
|
{
|
|
int hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
|
|
int vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
|
|
if (cmd == core::SCREEN_UP_CMD) {
|
|
scroll (0, -h () + pageOverlap + vdiff);
|
|
} else if (cmd == core::SCREEN_DOWN_CMD) {
|
|
scroll (0, h () - pageOverlap - vdiff);
|
|
} else if (cmd == core::SCREEN_LEFT_CMD) {
|
|
scroll (-w() + pageOverlap + hdiff, 0);
|
|
} else if (cmd == core::SCREEN_RIGHT_CMD) {
|
|
scroll (w() - pageOverlap - hdiff, 0);
|
|
} else if (cmd == core::LINE_UP_CMD) {
|
|
scroll (0, -vscrollbar->linesize ());
|
|
} else if (cmd == core::LINE_DOWN_CMD) {
|
|
scroll (0, vscrollbar->linesize ());
|
|
} else if (cmd == core::LEFT_CMD) {
|
|
scroll (-hscrollbar->linesize (), 0);
|
|
} else if (cmd == core::RIGHT_CMD) {
|
|
scroll (hscrollbar->linesize (), 0);
|
|
} else if (cmd == core::TOP_CMD) {
|
|
scrollTo (scrollX, 0);
|
|
} else if (cmd == core::BOTTOM_CMD) {
|
|
scrollTo (scrollX, canvasHeight); /* gets adjusted in scrollTo () */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Scrolling in response to selection where the cursor is outside the view.
|
|
*/
|
|
void FltkViewport::selectionScroll ()
|
|
{
|
|
int distance;
|
|
int dx = 0, dy = 0;
|
|
|
|
if ((distance = x() - mouse_x) > 0)
|
|
dx = -distance * hscrollbar->linesize () / 48 - 1;
|
|
else if ((distance = mouse_x - (x() + w())) > 0)
|
|
dx = distance * hscrollbar->linesize () / 48 + 1;
|
|
if ((distance = y() - mouse_y) > 0)
|
|
dy = -distance * vscrollbar->linesize () / 48 - 1;
|
|
else if ((distance = mouse_y - (y() + h())) > 0)
|
|
dy = distance * vscrollbar->linesize () / 48 + 1;
|
|
|
|
scroll (dx, dy);
|
|
}
|
|
|
|
void FltkViewport::selectionScroll (void *data)
|
|
{
|
|
((FltkViewport *)data)->selectionScroll ();
|
|
Fl::repeat_timeout(0.025, selectionScroll, data);
|
|
}
|
|
|
|
void FltkViewport::repeatPageScroll ()
|
|
{
|
|
scroll(pageScrolling);
|
|
Fl::repeat_timeout(pageScrollInterval, repeatPageScroll, this);
|
|
}
|
|
|
|
void FltkViewport::repeatPageScroll (void *data)
|
|
{
|
|
((FltkViewport *)data)->repeatPageScroll ();
|
|
}
|
|
|
|
void FltkViewport::setScrollbarOnLeft (bool enable)
|
|
{
|
|
scrollbarOnLeft = enable ? 1 : 0;
|
|
adjustScrollbarsAndGadgetsAllocation();
|
|
damage(FL_DAMAGE_ALL);
|
|
}
|
|
|
|
void FltkViewport::setViewportSize (int width, int height,
|
|
int hScrollbarThickness,
|
|
int vScrollbarThickness)
|
|
{
|
|
int adjustReq =
|
|
(hscrollbar->visible() ? !hScrollbarThickness : hScrollbarThickness) ||
|
|
(vscrollbar->visible() ? !vScrollbarThickness : vScrollbarThickness);
|
|
|
|
_MSG("FltkViewport::setViewportSize old_w,old_h=%dx%d -> w,h=%dx%d\n"
|
|
"\t hThick=%d hVis=%d, vThick=%d vVis=%d, adjustReq=%d\n",
|
|
w(),h(),width,height,
|
|
hScrollbarThickness,hscrollbar->visible(),
|
|
vScrollbarThickness,vscrollbar->visible(), adjustReq);
|
|
|
|
(hScrollbarThickness > 0) ? hscrollbar->show () : hscrollbar->hide ();
|
|
(vScrollbarThickness > 0) ? vscrollbar->show () : vscrollbar->hide ();
|
|
|
|
/* If no scrollbar, go to the beginning */
|
|
scroll(hScrollbarThickness ? 0 : -scrollX,
|
|
vScrollbarThickness ? 0 : -scrollY);
|
|
|
|
/* Adjust when scrollbar visibility changes */
|
|
if (adjustReq)
|
|
adjustScrollbarsAndGadgetsAllocation ();
|
|
}
|
|
|
|
void FltkViewport::updateCanvasWidgets (int dx, int dy)
|
|
{
|
|
// scroll all child widgets except scroll bars
|
|
for (int i = children () - 1; i > 0; i--) {
|
|
Fl_Widget *widget = child (i);
|
|
|
|
if (widget == hscrollbar || widget == vscrollbar)
|
|
continue;
|
|
|
|
widget->position(widget->x () - dx, widget->y () - dy);
|
|
}
|
|
}
|
|
|
|
int FltkViewport::translateViewXToCanvasX (int X)
|
|
{
|
|
return X - x () + scrollX;
|
|
}
|
|
|
|
int FltkViewport::translateViewYToCanvasY (int Y)
|
|
{
|
|
return Y - y () + scrollY;
|
|
}
|
|
|
|
int FltkViewport::translateCanvasXToViewX (int X)
|
|
{
|
|
return X + x () - scrollX;
|
|
}
|
|
|
|
int FltkViewport::translateCanvasYToViewY (int Y)
|
|
{
|
|
return Y + 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 (std::unique_ptr< Fl_Widget > gadget)
|
|
{
|
|
/** \bug Reparent? */
|
|
|
|
gadgets.push_back( std::move( gadget ) );
|
|
adjustScrollbarsAndGadgetsAllocation ();
|
|
}
|
|
|
|
|
|
} // namespace fltk
|
|
} // namespace dw
|