Dillo v3.1.1-11-g8f0909b7
Loading...
Searching...
No Matches
fltkviewport.cc
Go to the documentation of this file.
1/*
2 * Dillo Widget
3 *
4 * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21
22#include "fltkviewport.hh"
23
24#include <FL/Fl.H>
25#include <FL/fl_draw.H>
26#include <FL/names.h>
27
28#include <stdio.h>
29#include "../lout/msg.h"
30#include "../lout/debug.hh"
31
32using namespace lout;
33using namespace lout::object;
34using namespace lout::container::typed;
35
36namespace dw {
37namespace fltk {
38
39/*
40 * Lets SHIFT+{Left,Right} go to the parent
41 */
42class CustScrollbar : public Fl_Scrollbar
43{
44public:
45 CustScrollbar(int x, int y, int w, int h) : Fl_Scrollbar(x,y,w,h) {};
46 int handle(int e) {
47 if (e == FL_SHORTCUT && Fl::event_state() == FL_SHIFT &&
48 (Fl::event_key() == FL_Left || Fl::event_key() == FL_Right))
49 return 0;
50 return Fl_Scrollbar::handle(e);
51 }
52};
53
54FltkViewport::FltkViewport (int X, int Y, int W, int H, const char *label):
55 FltkWidgetView (X, Y, W, H, label)
56{
57 DBG_OBJ_CREATE ("dw::fltk::FltkViewport");
58
59 hscrollbar = new CustScrollbar (x (), y (), 1, 1);
60 hscrollbar->type(FL_HORIZONTAL);
61 hscrollbar->callback (hscrollbarCallback, this);
62 hscrollbar->hide();
63 add (hscrollbar);
64
65 vscrollbar = new Fl_Scrollbar (x (), y(), 1, 1);
66 vscrollbar->type(FL_VERTICAL);
67 vscrollbar->callback (vscrollbarCallback, this);
68 vscrollbar->hide();
69 add (vscrollbar);
70
71 hasDragScroll = 1;
74
79
80 gadgets =
81 new container::typed::List <object::TypedPointer < Fl_Widget> >
82 (true);
83}
84
90
92{
93 int hdiff = 0, vdiff = 0;
94 int visibility = 0;
95
96 _MSG(" >>FltkViewport::adjustScrollbarsAndGadgetsAllocation\n");
97 if (hscrollbar->visible ())
98 visibility |= 1;
99 if (vscrollbar->visible ())
100 visibility |= 2;
101
102 if (gadgets->size () > 0) {
103 switch (gadgetOrientation [visibility]) {
104 case GADGET_VERTICAL:
105 hdiff = SCROLLBAR_THICKNESS;
106 vdiff = SCROLLBAR_THICKNESS * gadgets->size ();
107 break;
108
110 hdiff = SCROLLBAR_THICKNESS * gadgets->size ();
111 vdiff = SCROLLBAR_THICKNESS;
112 break;
113 }
114 } else {
115 hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
116 vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
117 }
118
119 hscrollbar->resize(x (), y () + h () - SCROLLBAR_THICKNESS,
120 w () - hdiff, SCROLLBAR_THICKNESS);
121 vscrollbar->resize(x () + w () - SCROLLBAR_THICKNESS, y (),
122 SCROLLBAR_THICKNESS, h () - vdiff);
123
124 int X = x () + w () - SCROLLBAR_THICKNESS;
125 int Y = y () + h () - SCROLLBAR_THICKNESS;
126 for (Iterator <TypedPointer < Fl_Widget> > it = gadgets->iterator ();
127 it.hasNext (); ) {
128 Fl_Widget *widget = it.getNext()->getTypedValue ();
129 widget->resize(x (), y (), SCROLLBAR_THICKNESS, SCROLLBAR_THICKNESS);
130
131 switch (gadgetOrientation [visibility]) {
132 case GADGET_VERTICAL:
134 break;
135
138 break;
139 }
140 }
141}
142
148
150{
151 scroll (hscrollbar->value () - scrollX, 0);
152}
153
155{
156 scroll (0, vscrollbar->value () - scrollY);
157}
158
159void FltkViewport::vscrollbarCallback (Fl_Widget *vscrollbar,void *viewportPtr)
160{
161 ((FltkViewport*)viewportPtr)->vscrollbarChanged ();
162}
163
164void FltkViewport::hscrollbarCallback (Fl_Widget *hscrollbar,void *viewportPtr)
165{
166 ((FltkViewport*)viewportPtr)->hscrollbarChanged ();
167}
168
169// ----------------------------------------------------------------------
170
171void FltkViewport::resize(int X, int Y, int W, int H)
172{
173 bool dimension_changed = W != w() || H != h();
174
175 Fl_Group::resize(X, Y, W, H);
176 if (dimension_changed) {
177 theLayout->viewportSizeChanged (this, W, H);
179 }
180}
181
182void FltkViewport::draw_area (void *data, int x, int y, int w, int h)
183{
184 FltkViewport *vp = (FltkViewport*) data;
185 fl_push_clip(x, y, w, h);
186
187 vp->FltkWidgetView::draw ();
188
189 for (Iterator <TypedPointer < Fl_Widget> > it = vp->gadgets->iterator();
190 it.hasNext (); ) {
191 Fl_Widget *widget = it.getNext()->getTypedValue ();
192 vp->draw_child (*widget);
193 }
194
195 fl_pop_clip();
196}
197
198/*
199 * Draw the viewport.
200 *
201 * + Damage flags come in different ways, draw() should cope with them all.
202 * + Damage flags are alive for visible and hidden widgets.
203 * + FL_DAMAGE_CHILD can flag scroll bars or embedded FLTK widgets.
204 */
206{
207 const int d = damage(),
208 vis_vs = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0,
209 vis_hs = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0,
210 draw = d & (FL_DAMAGE_ALL | FL_DAMAGE_EXPOSE),
211 draw_vs = vis_vs && vscrollbar->damage (),
212 draw_hs = vis_hs && hscrollbar->damage ();
213
214 _MSG("FltkViewport::draw d=%d => ", d);
215 // scrollbars
216 if (draw || draw_vs)
217 draw_child (*vscrollbar);
218 if (draw || draw_hs)
219 draw_child (*hscrollbar);
220 if (draw && vis_vs && vis_hs) {
221 fl_color(FL_BACKGROUND_COLOR);
222 fl_rectf(x()+w()-vis_vs, y()+h()-vis_hs, vis_vs, vis_hs);
223 }
224 // main area
225 if (d == FL_DAMAGE_CHILD && (draw_vs || draw_hs)) {
226 _MSG("none\n");
227 } else if (d == (FL_DAMAGE_SCROLL | FL_DAMAGE_CHILD)) {
228 fl_scroll(x(), y(), w() - vis_vs, h() - vis_hs,
229 -scrollDX, -scrollDY, draw_area, this);
230 _MSG("fl_scroll()\n");
231 } else {
232 draw_area(this, x(), y(), w() - vis_vs, h() - vis_hs);
233 _MSG("draw_area()\n");
234 }
235
236 scrollDX = 0;
237 scrollDY = 0;
238}
239
240int FltkViewport::handle (int event)
241{
242 int ret = 0;
243 _MSG("FltkViewport::handle %s\n", fl_eventnames[event]);
244
245 switch(event) {
246 case FL_KEYBOARD:
247 /* When the viewport has focus (and not one of its children), FLTK
248 * sends the event here. Returning zero tells FLTK to resend the
249 * event as SHORTCUT, which we finally route to the parent. */
250
251 /* As we don't know the exact keybindings set by the user, we ask for
252 * all of them (except for the minimum needed to keep form navigation).*/
253 if (Fl::event_key() != FL_Tab || Fl::event_ctrl())
254 return 0;
255 break;
256
257 case FL_SHORTCUT:
258 /* send it to the parent (UI) */
259 return 0;
260
261 case FL_FOCUS:
263 break;
264
265 case FL_UNFOCUS:
267 break;
268
269 case FL_PUSH:
270 if (vscrollbar->visible() && Fl::event_inside(vscrollbar)) {
271 if (vscrollbar->handle(event))
272 verScrolling = 1;
273 } else if (hscrollbar->visible() && Fl::event_inside(hscrollbar)) {
274 if (hscrollbar->handle(event))
275 horScrolling = 1;
276 } else if (FltkWidgetView::handle(event) == 0 &&
277 Fl::event_button() == FL_MIDDLE_MOUSE) {
278 if (!hasDragScroll) {
279 /* let the parent widget handle it... */
280 return 0;
281 } else {
282 /* receive FL_DRAG and FL_RELEASE */
283 dragScrolling = 1;
284 dragX = Fl::event_x();
285 dragY = Fl::event_y();
287 }
288 }
289 return 1;
290 break;
291
292 case FL_DRAG:
293 if (Fl::event_inside(this))
294 Fl::remove_timeout(selectionScroll);
295 if (dragScrolling) {
296 scroll(dragX - Fl::event_x(), dragY - Fl::event_y());
297 dragX = Fl::event_x();
298 dragY = Fl::event_y();
299 return 1;
300 } else if (verScrolling) {
301 vscrollbar->handle(event);
302 return 1;
303 } else if (horScrolling) {
304 hscrollbar->handle(event);
305 return 1;
306 } else if (!Fl::event_inside(this)) {
307 mouse_x = Fl::event_x();
308 mouse_y = Fl::event_y();
309 if (!Fl::has_timeout(selectionScroll, this))
310 Fl::add_timeout(0.025, selectionScroll, this);
311 }
312 break;
313
314 case FL_MOUSEWHEEL:
315 return (Fl::event_dx() ? hscrollbar : vscrollbar)->handle(event);
316 break;
317
318 case FL_RELEASE:
319 Fl::remove_timeout(selectionScroll);
320 if (Fl::event_button() == FL_MIDDLE_MOUSE) {
322 } else if (verScrolling) {
323 ret = vscrollbar->handle(event);
324 } else if (horScrolling) {
325 ret = hscrollbar->handle(event);
326 }
328 break;
329
330 case FL_ENTER:
331 /* could be the result of, e.g., closing another window. */
332 mouse_x = Fl::event_x();
333 mouse_y = Fl::event_y();
335 break;
336
337 case FL_LEAVE:
338 mouse_x = mouse_y = -1;
339 break;
340 }
341
342 return ret ? ret : FltkWidgetView::handle (event);
343}
344
345// ----------------------------------------------------------------------
346
347void FltkViewport::setCanvasSize (int width, int ascent, int descent)
348{
349 FltkWidgetView::setCanvasSize (width, ascent, descent);
351}
352
353/*
354 * This is used to simulate mouse motion (e.g., when scrolling).
355 */
357{
358 if (!dragScrolling && mouse_x >= x() && mouse_x < x()+w() && mouse_y >= y()
359 && mouse_y < y()+h())
360 (void)theLayout->motionNotify (this,
364}
365
366/*
367 * For scrollbars, this currently sets the same step to both vertical and
368 * horizontal. It may be differentiated if necessary.
369 */
371{
372 vscrollbar->linesize(step);
373 hscrollbar->linesize(step);
374}
375
377{
378 return true;
379}
380
385
390
391void FltkViewport::scrollTo (int x, int y)
392{
393 int hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
394 int vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
395
396 x = misc::min (x, canvasWidth - w() + hdiff);
397 x = misc::max (x, 0);
398
399 y = misc::min (y, canvasHeight - h() + vdiff);
400 y = misc::max (y, 0);
401
402 if (x == scrollX && y == scrollY) {
403 return;
404 }
405
406 /* multiple calls to scroll can happen before a redraw occurs.
407 * scrollDX and scrollDY can therefore be non-zero here.
408 */
410 scrollDX += x - scrollX;
411 scrollDY += y - scrollY;
412
413 scrollX = x;
414 scrollY = y;
415
417 damage(FL_DAMAGE_SCROLL);
420}
421
422void FltkViewport::scroll (int dx, int dy)
423{
424 scrollTo (scrollX + dx, scrollY + dy);
425}
426
428{
429 if (cmd == core::SCREEN_UP_CMD) {
430 scroll (0, -h () + vscrollbar->linesize ());
431 } else if (cmd == core::SCREEN_DOWN_CMD) {
432 scroll (0, h () - vscrollbar->linesize ());
433 } else if (cmd == core::SCREEN_LEFT_CMD) {
434 scroll (-w() + hscrollbar->linesize (), 0);
435 } else if (cmd == core::SCREEN_RIGHT_CMD) {
436 scroll (w() - hscrollbar->linesize (), 0);
437 } else if (cmd == core::LINE_UP_CMD) {
438 scroll (0, (int) -vscrollbar->linesize ());
439 } else if (cmd == core::LINE_DOWN_CMD) {
440 scroll (0, (int) vscrollbar->linesize ());
441 } else if (cmd == core::LEFT_CMD) {
442 scroll ((int) -hscrollbar->linesize (), 0);
443 } else if (cmd == core::RIGHT_CMD) {
444 scroll ((int) hscrollbar->linesize (), 0);
445 } else if (cmd == core::TOP_CMD) {
446 scrollTo (scrollX, 0);
447 } else if (cmd == core::BOTTOM_CMD) {
448 scrollTo (scrollX, canvasHeight); /* gets adjusted in scrollTo () */
449 }
450}
451
452/*
453 * Scrolling in response to selection where the cursor is outside the view.
454 */
456{
457 int distance;
458 int dx = 0, dy = 0;
459
460 if ((distance = x() - mouse_x) > 0)
461 dx = -distance * hscrollbar->linesize () / 48 - 1;
462 else if ((distance = mouse_x - (x() + w())) > 0)
463 dx = distance * hscrollbar->linesize () / 48 + 1;
464 if ((distance = y() - mouse_y) > 0)
465 dy = -distance * vscrollbar->linesize () / 48 - 1;
466 else if ((distance = mouse_y - (y() + h())) > 0)
467 dy = distance * vscrollbar->linesize () / 48 + 1;
468
469 scroll (dx, dy);
470}
471
473{
474 ((FltkViewport *)data)->selectionScroll ();
475 Fl::repeat_timeout(0.025, selectionScroll, data);
476}
477
478void FltkViewport::setViewportSize (int width, int height,
479 int hScrollbarThickness,
480 int vScrollbarThickness)
481{
482 int adjustReq =
483 (hscrollbar->visible() ? !hScrollbarThickness : hScrollbarThickness) ||
484 (vscrollbar->visible() ? !vScrollbarThickness : vScrollbarThickness);
485
486 _MSG("FltkViewport::setViewportSize old_w,old_h=%dx%d -> w,h=%dx%d\n"
487 "\t hThick=%d hVis=%d, vThick=%d vVis=%d, adjustReq=%d\n",
488 w(),h(),width,height,
489 hScrollbarThickness,hscrollbar->visible(),
490 vScrollbarThickness,vscrollbar->visible(), adjustReq);
491
492 (hScrollbarThickness > 0) ? hscrollbar->show () : hscrollbar->hide ();
493 (vScrollbarThickness > 0) ? vscrollbar->show () : vscrollbar->hide ();
494
495 /* If no scrollbar, go to the beginning */
496 scroll(hScrollbarThickness ? 0 : -scrollX,
497 vScrollbarThickness ? 0 : -scrollY);
498
499 /* Adjust when scrollbar visibility changes */
500 if (adjustReq)
502}
503
505{
506 // scroll all child widgets except scroll bars
507 for (int i = children () - 1; i > 0; i--) {
508 Fl_Widget *widget = child (i);
509
510 if (widget == hscrollbar || widget == vscrollbar)
511 continue;
512
513 widget->position(widget->x () - dx, widget->y () - dy);
514 }
515}
516
518{
519 return X - x () + scrollX;
520}
521
523{
524 return Y - y () + scrollY;
525}
526
528{
529 return X + x () - scrollX;
530}
531
533{
534 return Y + y () - scrollY;
535}
536
537// ----------------------------------------------------------------------
538
539void FltkViewport::setGadgetOrientation (bool hscrollbarVisible,
540 bool vscrollbarVisible,
542 gadgetOrientation)
543{
544 this->gadgetOrientation[(hscrollbarVisible ? 0 : 1) |
545 (vscrollbarVisible ? 0 : 2)] = gadgetOrientation;
547}
548
549void FltkViewport::addGadget (Fl_Widget *gadget)
550{
553 gadgets->append (new TypedPointer < Fl_Widget> (gadget));
555}
556
557
558} // namespace fltk
559} // namespace dw
#define _MSG(...)
Definition bookmarks.c:45
bool motionNotify(View *view, int x, int y, ButtonState state)
This function is called by a view, to delegate a motion notify event.
Definition layout.cc:1046
void viewportSizeChanged(View *view, int width, int height)
Definition layout.cc:1298
void scrollPosChanged(View *view, int x, int y)
Definition layout.cc:1283
void setCanvasSize(int width, int ascent, int descent)
Set the canvas size.
void setCursor(core::style::Cursor cursor)
Set the cursor appearance.
core::Layout * theLayout
void scrollTo(int x, int y)
Scroll the vieport to the given position.
static void vscrollbarCallback(Fl_Widget *vscrollbar, void *viewportPtr)
static void draw_area(void *data, int x, int y, int w, int h)
int translateCanvasXToViewX(int x)
void addGadget(Fl_Widget *gadget)
int translateViewXToCanvasX(int x)
int translateViewYToCanvasY(int y)
Fl_Scrollbar * hscrollbar
Fl_Scrollbar * vscrollbar
void scroll(int dx, int dy)
int getVScrollbarThickness()
Get the thickness of the vertical scrollbar, when it is visible.
void setCanvasSize(int width, int ascent, int descent)
Set the canvas size.
void updateCanvasWidgets(int oldScrollX, int oldScrollY)
static void hscrollbarCallback(Fl_Widget *hscrollbar, void *viewportPtr)
void adjustScrollbarsAndGadgetsAllocation()
FltkViewport(int x, int y, int w, int h, const char *label=0)
bool usesViewport()
Return, whether this view uses a viewport.
int translateCanvasYToViewY(int y)
GadgetOrientation gadgetOrientation[4]
void setScrollStep(int step)
void setViewportSize(int width, int height, int hScrollbarThickness, int vScrollbarThickness)
Set the viewport size.
void setGadgetOrientation(bool hscrollbarVisible, bool vscrollbarVisible, GadgetOrientation gadgetOrientation)
void resize(int x, int y, int w, int h)
lout::container::typed::List< lout::object::TypedPointer< Fl_Widget > > * gadgets
int getHScrollbarThickness()
Get the thickness of the horizontal scrollbar, when it is visible.
Typed version of container::untyped::Iterator.
Definition container.hh:395
#define DBG_OBJ_DELETE()
#define DBG_OBJ_CREATE(klass)
#define H(x, y, z)
ButtonState
Platform independent representation.
Definition events.hh:15
ScrollCommand
Definition types.hh:35
@ LINE_UP_CMD
Definition types.hh:36
@ BOTTOM_CMD
Definition types.hh:37
@ RIGHT_CMD
Definition types.hh:37
@ SCREEN_LEFT_CMD
Definition types.hh:35
@ LEFT_CMD
Definition types.hh:37
@ SCREEN_DOWN_CMD
Definition types.hh:35
@ LINE_DOWN_CMD
Definition types.hh:36
@ SCREEN_UP_CMD
Definition types.hh:35
@ SCREEN_RIGHT_CMD
Definition types.hh:36
@ TOP_CMD
Definition types.hh:37
Dw is in this namespace, or sub namespaces of this one.
This namespace provides thin wrappers, implemented as C++ templates, to gain type-safety.
Definition container.hh:387
T min(T a, T b)
Definition misc.hh:19
T max(T a, T b)
Definition misc.hh:20
Here, some common classes (or interfaces) are defined, to standardize the access to other classes.
Definition object.cc:29