Dillo v3.1.1-46-g8a360e32
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 /* FIXME: This has no effect */
132#if 0
133 switch (gadgetOrientation [visibility]) {
134 case GADGET_VERTICAL:
136 break;
137
140 break;
141 }
142#endif
143 }
144}
145
151
153{
154 scroll (hscrollbar->value () - scrollX, 0);
155}
156
158{
159 scroll (0, vscrollbar->value () - scrollY);
160}
161
162void FltkViewport::vscrollbarCallback (Fl_Widget *vscrollbar,void *viewportPtr)
163{
164 ((FltkViewport*)viewportPtr)->vscrollbarChanged ();
165}
166
167void FltkViewport::hscrollbarCallback (Fl_Widget *hscrollbar,void *viewportPtr)
168{
169 ((FltkViewport*)viewportPtr)->hscrollbarChanged ();
170}
171
172// ----------------------------------------------------------------------
173
174void FltkViewport::resize(int X, int Y, int W, int H)
175{
176 bool dimension_changed = W != w() || H != h();
177
178 Fl_Group::resize(X, Y, W, H);
179 if (dimension_changed) {
180 theLayout->viewportSizeChanged (this, W, H);
182 }
183}
184
185void FltkViewport::draw_area (void *data, int x, int y, int w, int h)
186{
187 FltkViewport *vp = (FltkViewport*) data;
188 fl_push_clip(x, y, w, h);
189
190 vp->FltkWidgetView::draw ();
191
192 for (Iterator <TypedPointer < Fl_Widget> > it = vp->gadgets->iterator();
193 it.hasNext (); ) {
194 Fl_Widget *widget = it.getNext()->getTypedValue ();
195 vp->draw_child (*widget);
196 }
197
198 fl_pop_clip();
199}
200
201/*
202 * Draw the viewport.
203 *
204 * + Damage flags come in different ways, draw() should cope with them all.
205 * + Damage flags are alive for visible and hidden widgets.
206 * + FL_DAMAGE_CHILD can flag scroll bars or embedded FLTK widgets.
207 */
209{
210 const int d = damage(),
211 vis_vs = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0,
212 vis_hs = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0,
213 draw = d & (FL_DAMAGE_ALL | FL_DAMAGE_EXPOSE),
214 draw_vs = vis_vs && vscrollbar->damage (),
215 draw_hs = vis_hs && hscrollbar->damage ();
216
217 _MSG("FltkViewport::draw d=%d => ", d);
218 // scrollbars
219 if (draw || draw_vs)
220 draw_child (*vscrollbar);
221 if (draw || draw_hs)
222 draw_child (*hscrollbar);
223 if (draw && vis_vs && vis_hs) {
224 fl_color(FL_BACKGROUND_COLOR);
225 fl_rectf(x()+w()-vis_vs, y()+h()-vis_hs, vis_vs, vis_hs);
226 }
227 // main area
228 if (d == FL_DAMAGE_CHILD && (draw_vs || draw_hs)) {
229 _MSG("none\n");
230 } else if (d == (FL_DAMAGE_SCROLL | FL_DAMAGE_CHILD)) {
231 fl_scroll(x(), y(), w() - vis_vs, h() - vis_hs,
232 -scrollDX, -scrollDY, draw_area, this);
233 _MSG("fl_scroll()\n");
234 } else {
235 draw_area(this, x(), y(), w() - vis_vs, h() - vis_hs);
236 _MSG("draw_area()\n");
237 }
238
239 scrollDX = 0;
240 scrollDY = 0;
241}
242
243int FltkViewport::handle (int event)
244{
245 int ret = 0;
246 _MSG("FltkViewport::handle %s\n", fl_eventnames[event]);
247
248 switch(event) {
249 case FL_KEYBOARD:
250 /* When the viewport has focus (and not one of its children), FLTK
251 * sends the event here. Returning zero tells FLTK to resend the
252 * event as SHORTCUT, which we finally route to the parent. */
253
254 /* As we don't know the exact keybindings set by the user, we ask for
255 * all of them (except for the minimum needed to keep form navigation).*/
256 if (Fl::event_key() != FL_Tab || Fl::event_ctrl())
257 return 0;
258 break;
259
260 case FL_SHORTCUT:
261 /* send it to the parent (UI) */
262 return 0;
263
264 case FL_FOCUS:
266 break;
267
268 case FL_UNFOCUS:
270 break;
271
272 case FL_PUSH:
273 if (vscrollbar->visible() && Fl::event_inside(vscrollbar)) {
274 if (vscrollbar->handle(event))
275 verScrolling = 1;
276 } else if (hscrollbar->visible() && Fl::event_inside(hscrollbar)) {
277 if (hscrollbar->handle(event))
278 horScrolling = 1;
279 } else if (FltkWidgetView::handle(event) == 0 &&
280 Fl::event_button() == FL_MIDDLE_MOUSE) {
281 if (!hasDragScroll) {
282 /* let the parent widget handle it... */
283 return 0;
284 } else {
285 /* receive FL_DRAG and FL_RELEASE */
286 dragScrolling = 1;
287 dragX = Fl::event_x();
288 dragY = Fl::event_y();
290 }
291 }
292 return 1;
293 break;
294
295 case FL_DRAG:
296 if (Fl::event_inside(this))
297 Fl::remove_timeout(selectionScroll);
298 if (dragScrolling) {
299 scroll(dragX - Fl::event_x(), dragY - Fl::event_y());
300 dragX = Fl::event_x();
301 dragY = Fl::event_y();
302 return 1;
303 } else if (verScrolling) {
304 vscrollbar->handle(event);
305 return 1;
306 } else if (horScrolling) {
307 hscrollbar->handle(event);
308 return 1;
309 } else if (!Fl::event_inside(this)) {
310 mouse_x = Fl::event_x();
311 mouse_y = Fl::event_y();
312 if (!Fl::has_timeout(selectionScroll, this))
313 Fl::add_timeout(0.025, selectionScroll, this);
314 }
315 break;
316
317 case FL_MOUSEWHEEL:
318 return (Fl::event_dx() ? hscrollbar : vscrollbar)->handle(event);
319 break;
320
321 case FL_RELEASE:
322 Fl::remove_timeout(selectionScroll);
323 if (Fl::event_button() == FL_MIDDLE_MOUSE) {
325 } else if (verScrolling) {
326 ret = vscrollbar->handle(event);
327 } else if (horScrolling) {
328 ret = hscrollbar->handle(event);
329 }
331 break;
332
333 case FL_ENTER:
334 /* could be the result of, e.g., closing another window. */
335 mouse_x = Fl::event_x();
336 mouse_y = Fl::event_y();
338 break;
339
340 case FL_LEAVE:
341 mouse_x = mouse_y = -1;
342 break;
343 }
344
345 return ret ? ret : FltkWidgetView::handle (event);
346}
347
348// ----------------------------------------------------------------------
349
350void FltkViewport::setCanvasSize (int width, int ascent, int descent)
351{
352 FltkWidgetView::setCanvasSize (width, ascent, descent);
354}
355
356/*
357 * This is used to simulate mouse motion (e.g., when scrolling).
358 */
360{
361 if (!dragScrolling && mouse_x >= x() && mouse_x < x()+w() && mouse_y >= y()
362 && mouse_y < y()+h())
363 (void)theLayout->motionNotify (this,
367}
368
369/*
370 * For scrollbars, this currently sets the same step to both vertical and
371 * horizontal. It may be differentiated if necessary.
372 */
374{
375 vscrollbar->linesize(step);
376 hscrollbar->linesize(step);
377}
378
380{
381 return true;
382}
383
388
393
394void FltkViewport::scrollTo (int x, int y)
395{
396 int hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
397 int vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
398
399 x = misc::min (x, canvasWidth - w() + hdiff);
400 x = misc::max (x, 0);
401
402 y = misc::min (y, canvasHeight - h() + vdiff);
403 y = misc::max (y, 0);
404
405 if (x == scrollX && y == scrollY) {
406 return;
407 }
408
409 /* multiple calls to scroll can happen before a redraw occurs.
410 * scrollDX and scrollDY can therefore be non-zero here.
411 */
413 scrollDX += x - scrollX;
414 scrollDY += y - scrollY;
415
416 scrollX = x;
417 scrollY = y;
418
420 damage(FL_DAMAGE_SCROLL);
423}
424
425void FltkViewport::scroll (int dx, int dy)
426{
427 scrollTo (scrollX + dx, scrollY + dy);
428}
429
431{
432 if (cmd == core::SCREEN_UP_CMD) {
433 scroll (0, -h () + vscrollbar->linesize ());
434 } else if (cmd == core::SCREEN_DOWN_CMD) {
435 scroll (0, h () - vscrollbar->linesize ());
436 } else if (cmd == core::SCREEN_LEFT_CMD) {
437 scroll (-w() + hscrollbar->linesize (), 0);
438 } else if (cmd == core::SCREEN_RIGHT_CMD) {
439 scroll (w() - hscrollbar->linesize (), 0);
440 } else if (cmd == core::LINE_UP_CMD) {
441 scroll (0, (int) -vscrollbar->linesize ());
442 } else if (cmd == core::LINE_DOWN_CMD) {
443 scroll (0, (int) vscrollbar->linesize ());
444 } else if (cmd == core::LEFT_CMD) {
445 scroll ((int) -hscrollbar->linesize (), 0);
446 } else if (cmd == core::RIGHT_CMD) {
447 scroll ((int) hscrollbar->linesize (), 0);
448 } else if (cmd == core::TOP_CMD) {
449 scrollTo (scrollX, 0);
450 } else if (cmd == core::BOTTOM_CMD) {
451 scrollTo (scrollX, canvasHeight); /* gets adjusted in scrollTo () */
452 }
453}
454
455/*
456 * Scrolling in response to selection where the cursor is outside the view.
457 */
459{
460 int distance;
461 int dx = 0, dy = 0;
462
463 if ((distance = x() - mouse_x) > 0)
464 dx = -distance * hscrollbar->linesize () / 48 - 1;
465 else if ((distance = mouse_x - (x() + w())) > 0)
466 dx = distance * hscrollbar->linesize () / 48 + 1;
467 if ((distance = y() - mouse_y) > 0)
468 dy = -distance * vscrollbar->linesize () / 48 - 1;
469 else if ((distance = mouse_y - (y() + h())) > 0)
470 dy = distance * vscrollbar->linesize () / 48 + 1;
471
472 scroll (dx, dy);
473}
474
476{
477 ((FltkViewport *)data)->selectionScroll ();
478 Fl::repeat_timeout(0.025, selectionScroll, data);
479}
480
481void FltkViewport::setViewportSize (int width, int height,
482 int hScrollbarThickness,
483 int vScrollbarThickness)
484{
485 int adjustReq =
486 (hscrollbar->visible() ? !hScrollbarThickness : hScrollbarThickness) ||
487 (vscrollbar->visible() ? !vScrollbarThickness : vScrollbarThickness);
488
489 _MSG("FltkViewport::setViewportSize old_w,old_h=%dx%d -> w,h=%dx%d\n"
490 "\t hThick=%d hVis=%d, vThick=%d vVis=%d, adjustReq=%d\n",
491 w(),h(),width,height,
492 hScrollbarThickness,hscrollbar->visible(),
493 vScrollbarThickness,vscrollbar->visible(), adjustReq);
494
495 (hScrollbarThickness > 0) ? hscrollbar->show () : hscrollbar->hide ();
496 (vScrollbarThickness > 0) ? vscrollbar->show () : vscrollbar->hide ();
497
498 /* If no scrollbar, go to the beginning */
499 scroll(hScrollbarThickness ? 0 : -scrollX,
500 vScrollbarThickness ? 0 : -scrollY);
501
502 /* Adjust when scrollbar visibility changes */
503 if (adjustReq)
505}
506
508{
509 // scroll all child widgets except scroll bars
510 for (int i = children () - 1; i > 0; i--) {
511 Fl_Widget *widget = child (i);
512
513 if (widget == hscrollbar || widget == vscrollbar)
514 continue;
515
516 widget->position(widget->x () - dx, widget->y () - dy);
517 }
518}
519
521{
522 return X - x () + scrollX;
523}
524
526{
527 return Y - y () + scrollY;
528}
529
531{
532 return X + x () - scrollX;
533}
534
536{
537 return Y + y () - scrollY;
538}
539
540// ----------------------------------------------------------------------
541
542void FltkViewport::setGadgetOrientation (bool hscrollbarVisible,
543 bool vscrollbarVisible,
545 gadgetOrientation)
546{
547 this->gadgetOrientation[(hscrollbarVisible ? 0 : 1) |
548 (vscrollbarVisible ? 0 : 2)] = gadgetOrientation;
550}
551
552void FltkViewport::addGadget (Fl_Widget *gadget)
553{
556 gadgets->append (new TypedPointer < Fl_Widget> (gadget));
558}
559
560
561} // namespace fltk
562} // 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:1067
void viewportSizeChanged(View *view, int width, int height)
Definition layout.cc:1319
void scrollPosChanged(View *view, int x, int y)
Definition layout.cc:1304
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:20
T max(T a, T b)
Definition misc.hh:21
Here, some common classes (or interfaces) are defined, to standardize the access to other classes.
Definition object.cc:30