dillo  3.0.5
About: dillo is a small, fast, extensible Web browser particularly suitable for older or smaller computers and embedded systems (but only limited or no support for frames, CSS, JavaScript, Java).
  Fossies Dox: dillo-3.0.5.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

layout.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 "core.hh"
23 
24 #include "../lout/msg.h"
25 #include "../lout/debug.hh"
26 #include "../lout/misc.hh"
27 
28 using namespace lout;
29 using namespace lout::container;
30 using namespace lout::object;
31 
32 namespace dw {
33 namespace core {
34 
35 bool Layout::LayoutImgRenderer::readyToDraw ()
36 {
37  return true;
38 }
39 
40 void Layout::LayoutImgRenderer::getBgArea (int *x, int *y, int *width,
41  int *height)
42 {
43  // TODO Actually not padding area, but visible area?
44  getRefArea (x, y, width, height);
45 }
46 
47 void Layout::LayoutImgRenderer::getRefArea (int *xRef, int *yRef, int *widthRef,
48  int *heightRef)
49 {
50  *xRef = 0;
51  *yRef = 0;
52  *widthRef = misc::max (layout->viewportWidth
53  - (layout->canvasHeightGreater ?
54  layout->vScrollbarThickness : 0),
55  layout->canvasWidth);
56  *heightRef = misc::max (layout->viewportHeight
57  - layout->hScrollbarThickness,
58  layout->canvasAscent + layout->canvasDescent);
59 }
60 
61 style::StyleImage *Layout::LayoutImgRenderer::getBackgroundImage ()
62 {
63  return layout->bgImage;
64 }
65 
66 style::BackgroundRepeat Layout::LayoutImgRenderer::getBackgroundRepeat ()
67 {
68  return layout->bgRepeat;
69 }
70 
72  Layout::LayoutImgRenderer::getBackgroundAttachment ()
73 {
74  return layout->bgAttachment;
75 }
76 
77 style::Length Layout::LayoutImgRenderer::getBackgroundPositionX ()
78 {
79  return layout->bgPositionX;
80 }
81 
82 style::Length Layout::LayoutImgRenderer::getBackgroundPositionY ()
83 {
84  return layout->bgPositionY;
85 }
86 
87 void Layout::LayoutImgRenderer::draw (int x, int y, int width, int height)
88 {
89  layout->queueDraw (x, y, width, height);
90 }
91 
92 // ----------------------------------------------------------------------
93 
94 void Layout::Receiver::canvasSizeChanged (int width, int ascent, int descent)
95 {
96 }
97 
98 // ----------------------------------------------------------------------
99 
100 bool Layout::Emitter::emitToReceiver (lout::signal::Receiver *receiver,
101  int signalNo, int argc,
102  lout::object::Object **argv)
103 {
104  Receiver *layoutReceiver = (Receiver*)receiver;
105 
106  switch (signalNo) {
107  case CANVAS_SIZE_CHANGED:
108  layoutReceiver->canvasSizeChanged (((Integer*)argv[0])->getValue (),
109  ((Integer*)argv[1])->getValue (),
110  ((Integer*)argv[2])->getValue ());
111  break;
112 
113  default:
115  }
116 
117  return false;
118 }
119 
120 void Layout::Emitter::emitCanvasSizeChanged (int width,
121  int ascent, int descent)
122 {
123  Integer w (width), a (ascent), d (descent);
124  Object *argv[3] = { &w, &a, &d };
125  emitVoid (CANVAS_SIZE_CHANGED, 3, argv);
126 }
127 
128 // ----------------------------------------------------------------------
129 
130 bool Layout::LinkReceiver::enter (Widget *widget, int link, int img,
131  int x, int y)
132 {
133  return false;
134 }
135 
136 bool Layout::LinkReceiver::press (Widget *widget, int link, int img,
137  int x, int y, EventButton *event)
138 {
139  return false;
140 }
141 
142 bool Layout::LinkReceiver::release (Widget *widget, int link, int img,
143  int x, int y, EventButton *event)
144 {
145  return false;
146 }
147 
148 bool Layout::LinkReceiver::click (Widget *widget, int link, int img,
149  int x, int y, EventButton *event)
150 {
151  return false;
152 }
153 
154 // ----------------------------------------------------------------------
155 
156 bool Layout::LinkEmitter::emitToReceiver (lout::signal::Receiver *receiver,
157  int signalNo, int argc,
158  lout::object::Object **argv)
159 {
160  LinkReceiver *linkReceiver = (LinkReceiver*)receiver;
161 
162  switch (signalNo) {
163  case ENTER:
164  return linkReceiver->enter ((Widget*)argv[0],
165  ((Integer*)argv[1])->getValue (),
166  ((Integer*)argv[2])->getValue (),
167  ((Integer*)argv[3])->getValue (),
168  ((Integer*)argv[4])->getValue ());
169 
170  case PRESS:
171  return linkReceiver->press ((Widget*)argv[0],
172  ((Integer*)argv[1])->getValue (),
173  ((Integer*)argv[2])->getValue (),
174  ((Integer*)argv[3])->getValue (),
175  ((Integer*)argv[4])->getValue (),
176  (EventButton*)argv[5]);
177 
178  case RELEASE:
179  return linkReceiver->release ((Widget*)argv[0],
180  ((Integer*)argv[1])->getValue (),
181  ((Integer*)argv[2])->getValue (),
182  ((Integer*)argv[3])->getValue (),
183  ((Integer*)argv[4])->getValue (),
184  (EventButton*)argv[5]);
185 
186  case CLICK:
187  return linkReceiver->click ((Widget*)argv[0],
188  ((Integer*)argv[1])->getValue (),
189  ((Integer*)argv[2])->getValue (),
190  ((Integer*)argv[3])->getValue (),
191  ((Integer*)argv[4])->getValue (),
192  (EventButton*)argv[5]);
193 
194  default:
196  }
197  return false;
198 }
199 
200 bool Layout::LinkEmitter::emitEnter (Widget *widget, int link, int img,
201  int x, int y)
202 {
203  Integer ilink (link), iimg (img), ix (x), iy (y);
204  Object *argv[5] = { widget, &ilink, &iimg, &ix, &iy };
205  return emitBool (ENTER, 5, argv);
206 }
207 
208 bool Layout::LinkEmitter::emitPress (Widget *widget, int link, int img,
209  int x, int y, EventButton *event)
210 {
211  Integer ilink (link), iimg (img), ix (x), iy (y);
212  Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
213  return emitBool (PRESS, 6, argv);
214 }
215 
216 bool Layout::LinkEmitter::emitRelease (Widget *widget, int link, int img,
217  int x, int y, EventButton *event)
218 {
219  Integer ilink (link), iimg (img), ix (x), iy (y);
220  Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
221  return emitBool (RELEASE, 6, argv);
222 }
223 
224 bool Layout::LinkEmitter::emitClick (Widget *widget, int link, int img,
225  int x, int y, EventButton *event)
226 {
227  Integer ilink (link), iimg (img), ix (x), iy (y);
228  Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
229  return emitBool (CLICK, 6, argv);
230 }
231 
232 // ---------------------------------------------------------------------
233 
234 Layout::Anchor::~Anchor ()
235 {
236  free(name);
237 }
238 
239 // ---------------------------------------------------------------------
240 
241 Layout::Layout (Platform *platform)
242 {
243  this->platform = platform;
244  view = NULL;
245  topLevel = NULL;
246  widgetAtPoint = NULL;
247 
248  DBG_OBJ_CREATE ("dw::core::Layout");
249 
250  bgColor = NULL;
251  bgImage = NULL;
252  cursor = style::CURSOR_DEFAULT;
253 
254  canvasWidth = canvasAscent = canvasDescent = 0;
255 
256  usesViewport = false;
257  drawAfterScrollReq = false;
258  scrollX = scrollY = 0;
259  viewportWidth = viewportHeight = 0;
260  hScrollbarThickness = vScrollbarThickness = 0;
261 
262  requestedAnchor = NULL;
263  scrollIdleId = -1;
264  scrollIdleNotInterrupted = false;
265 
266  anchorsTable =
268 
269  resizeIdleId = -1;
270 
271  textZone = new misc::ZoneAllocator (16 * 1024);
272 
273  DBG_OBJ_ASSOC_CHILD (&findtextState);
274  DBG_OBJ_ASSOC_CHILD (&selectionState);
275 
276  platform->setLayout (this);
277 
278  selectionState.setLayout(this);
279 
280  layoutImgRenderer = NULL;
281 }
282 
283 Layout::~Layout ()
284 {
285  widgetAtPoint = NULL;
286 
287  if (layoutImgRenderer) {
288  if (bgImage)
289  bgImage->removeExternalImgRenderer (layoutImgRenderer);
290  delete layoutImgRenderer;
291  }
292 
293  if (scrollIdleId != -1)
294  platform->removeIdle (scrollIdleId);
295  if (resizeIdleId != -1)
296  platform->removeIdle (resizeIdleId);
297  if (bgColor)
298  bgColor->unref ();
299  if (bgImage)
300  bgImage->unref ();
301  if (topLevel) {
302  Widget *w = topLevel;
303  topLevel = NULL;
304  delete w;
305  }
306  delete platform;
307  delete view;
308  delete anchorsTable;
309  delete textZone;
310 
311  DBG_OBJ_DELETE ();
312 }
313 
314 void Layout::addWidget (Widget *widget)
315 {
316  if (topLevel) {
317  MSG_WARN("widget already set\n");
318  return;
319  }
320 
321  topLevel = widget;
322  widget->layout = this;
323 
324  findtextState.setWidget (widget);
325 
326  canvasHeightGreater = false;
327  setSizeHints ();
328  queueResize ();
329 }
330 
331 void Layout::removeWidget ()
332 {
336  topLevel = NULL;
337  widgetAtPoint = NULL;
338  canvasWidth = canvasAscent = canvasDescent = 0;
339  scrollX = scrollY = 0;
340 
341  view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent);
342  if (view->usesViewport ())
343  view->setViewportSize (viewportWidth, viewportHeight, 0, 0);
344  view->queueDrawTotal ();
345 
346  setAnchor (NULL);
347  updateAnchor ();
348 
349  emitter.emitCanvasSizeChanged (canvasWidth, canvasAscent, canvasDescent);
350 
351  findtextState.setWidget (NULL);
352  selectionState.reset ();
353 
354  updateCursor ();
355 }
356 
357 void Layout::setWidget (Widget *widget)
358 {
359  DBG_OBJ_ASSOC_CHILD (widget);
360 
361  widgetAtPoint = NULL;
362  if (topLevel) {
363  Widget *w = topLevel;
364  topLevel = NULL;
365  delete w;
366  }
367  textZone->zoneFree ();
368  addWidget (widget);
369 
370  updateCursor ();
371 }
372 
379 void Layout::attachView (View *view)
380 {
381  if (this->view)
382  MSG_ERR("attachView: Multiple views for layout!\n");
383 
384  DBG_OBJ_ASSOC_CHILD (view);
385 
386  this->view = view;
387  platform->attachView (view);
388 
389  /*
390  * The layout of the view is set later, first, we "project" the current
391  * state of the layout into the new view. A view must handle this without
392  * a layout. See also at the end of this function.
393  */
394  if (bgColor)
395  view->setBgColor (bgColor);
396  view->setCursor (cursor);
397  view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent);
398 
399  if (view->usesViewport ()) {
400  if (usesViewport) {
401  view->scrollTo (scrollX, scrollY);
402  view->setViewportSize (viewportWidth, viewportHeight,
403  hScrollbarThickness, vScrollbarThickness);
404  hScrollbarThickness = misc::max (hScrollbarThickness,
405  view->getHScrollbarThickness ());
406  vScrollbarThickness = misc::max (vScrollbarThickness,
407  view->getVScrollbarThickness ());
408  }
409  else {
410  usesViewport = true;
411  scrollX = scrollY = 0;
412  viewportWidth = viewportHeight = 100; // random values
413  hScrollbarThickness = view->getHScrollbarThickness ();
414  vScrollbarThickness = view->getVScrollbarThickness ();
415  }
416  }
417 
418  /*
419  * This is the last call within this function, so that it is safe for
420  * the implementation of dw::core::View::setLayout, to call methods
421  * of dw::core::Layout.
422  */
423  view->setLayout (this);
424 }
425 
426 void Layout::detachView (View *view)
427 {
428  if (this->view != view)
429  MSG_ERR("detachView: this->view: %p view %p\n", this->view, view);
430 
431  view->setLayout (NULL);
432  platform->detachView (view);
433  this->view = NULL;
440 }
441 
442 void Layout::scroll(ScrollCommand cmd)
443 {
444  if (view->usesViewport ())
445  view->scroll(cmd);
446 }
447 
452 void Layout::scrollTo (HPosition hpos, VPosition vpos,
453  int x, int y, int width, int height)
454 {
455  scrollTo0 (hpos, vpos, x, y, width, height, true);
456 }
457 
458 void Layout::scrollTo0 (HPosition hpos, VPosition vpos,
459  int x, int y, int width, int height,
460  bool scrollingInterrupted)
461 {
462  if (usesViewport) {
463  _MSG("scrollTo (%d, %d, %s)\n",
464  x, y, scrollingInterrupted ? "true" : "false");
465 
466  scrollTargetHpos = hpos;
467  scrollTargetVpos = vpos;
468  scrollTargetX = x;
469  scrollTargetY = y;
470  scrollTargetWidth = width;
471  scrollTargetHeight = height;
472 
473  if (scrollIdleId == -1) {
474  scrollIdleId = platform->addIdle (&Layout::scrollIdle);
475  scrollIdleNotInterrupted = true;
476  }
477 
478  scrollIdleNotInterrupted =
479  scrollIdleNotInterrupted || !scrollingInterrupted;
480  }
481 }
482 
483 void Layout::scrollIdle ()
484 {
485  bool xChanged = true;
486  switch (scrollTargetHpos) {
487  case HPOS_LEFT:
488  scrollX = scrollTargetX;
489  break;
490  case HPOS_CENTER:
491  scrollX =
492  scrollTargetX
493  - (viewportWidth - currVScrollbarThickness() - scrollTargetWidth) / 2;
494  break;
495  case HPOS_RIGHT:
496  scrollX =
497  scrollTargetX
498  - (viewportWidth - currVScrollbarThickness() - scrollTargetWidth);
499  break;
500  case HPOS_INTO_VIEW:
501  xChanged = calcScrollInto (scrollTargetX, scrollTargetWidth, &scrollX,
502  viewportWidth - currVScrollbarThickness());
503  break;
504  case HPOS_NO_CHANGE:
505  xChanged = false;
506  break;
507  }
508 
509  bool yChanged = true;
510  switch (scrollTargetVpos) {
511  case VPOS_TOP:
512  scrollY = scrollTargetY;
513  break;
514  case VPOS_CENTER:
515  scrollY =
516  scrollTargetY
517  - (viewportHeight - currHScrollbarThickness() - scrollTargetHeight)/2;
518  break;
519  case VPOS_BOTTOM:
520  scrollY =
521  scrollTargetY
522  - (viewportHeight - currHScrollbarThickness() - scrollTargetHeight);
523  break;
524  case VPOS_INTO_VIEW:
525  yChanged = calcScrollInto (scrollTargetY, scrollTargetHeight, &scrollY,
526  viewportHeight - currHScrollbarThickness());
527  break;
528  case VPOS_NO_CHANGE:
529  yChanged = false;
530  break;
531  }
532 
533  if (xChanged || yChanged) {
534  adjustScrollPos ();
535  view->scrollTo (scrollX, scrollY);
536  if (drawAfterScrollReq) {
537  drawAfterScrollReq = false;
538  view->queueDrawTotal ();
539  }
540  }
541 
542  scrollIdleId = -1;
543 }
544 
545 void Layout::adjustScrollPos ()
546 {
547  scrollX = misc::min (scrollX,
548  canvasWidth - (viewportWidth - vScrollbarThickness));
549  scrollX = misc::max (scrollX, 0);
550 
551  scrollY = misc::min (scrollY,
552  canvasAscent + canvasDescent - (viewportHeight - hScrollbarThickness));
553  scrollY = misc::max (scrollY, 0);
554 
555  _MSG("adjustScrollPos: scrollX=%d scrollY=%d\n", scrollX, scrollY);
556 }
557 
558 bool Layout::calcScrollInto (int requestedValue, int requestedSize,
559  int *value, int viewportSize)
560 {
561  if (requestedSize > viewportSize) {
562  // The viewport size is smaller than the size of the region which will
563  // be shown. If the region is already visible, do not change the
564  // position. Otherwise, show the left/upper border, this is most likely
565  // what is needed.
566  if (*value >= requestedValue &&
567  *value + viewportSize < requestedValue + requestedSize)
568  return false;
569  else
570  requestedSize = viewportSize;
571  }
572 
573  if (requestedValue < *value) {
574  *value = requestedValue;
575  return true;
576  } else if (requestedValue + requestedSize > *value + viewportSize) {
577  *value = requestedValue - viewportSize + requestedSize;
578  return true;
579  } else
580  return false;
581 }
582 
583 void Layout::draw (View *view, Rectangle *area)
584 {
585  Rectangle widgetArea, intersection, widgetDrawArea;
586 
587  // First of all, draw background image. (Unlike background *color*,
588  // this is not a feature of the views.)
589  if (bgImage != NULL && bgImage->getImgbufSrc() != NULL)
590  style::drawBackgroundImage (view, bgImage, bgRepeat, bgAttachment,
591  bgPositionX, bgPositionY,
592  area->x, area->y, area->width,
593  area->height, 0, 0,
594  // Reference area: maximum of canvas size and
595  // viewport size.
596  misc::max (viewportWidth
597  - (canvasHeightGreater ?
598  vScrollbarThickness : 0),
599  canvasWidth),
600  misc::max (viewportHeight
601  - hScrollbarThickness,
602  canvasAscent + canvasDescent));
603 
604  if (scrollIdleId != -1) {
605  /* scroll is pending, defer draw until after scrollIdle() */
606  drawAfterScrollReq = true;
607 
608  } else if (topLevel) {
609  /* Draw the top level widget. */
610  widgetArea.x = topLevel->allocation.x;
611  widgetArea.y = topLevel->allocation.y;
612  widgetArea.width = topLevel->allocation.width;
613  widgetArea.height = topLevel->getHeight ();
614 
615  if (area->intersectsWith (&widgetArea, &intersection)) {
616  view->startDrawing (&intersection);
617 
618  /* Intersection in widget coordinates. */
619  widgetDrawArea.x = intersection.x - topLevel->allocation.x;
620  widgetDrawArea.y = intersection.y - topLevel->allocation.y;
621  widgetDrawArea.width = intersection.width;
622  widgetDrawArea.height = intersection.height;
623 
624  topLevel->draw (view, &widgetDrawArea);
625 
626  view->finishDrawing (&intersection);
627  }
628  }
629 }
630 
631 int Layout::currHScrollbarThickness()
632 {
633  return (canvasWidth > viewportWidth) ? hScrollbarThickness : 0;
634 }
635 
636 int Layout::currVScrollbarThickness()
637 {
638  return (canvasAscent + canvasDescent > viewportHeight) ?
639  vScrollbarThickness : 0;
640 }
641 
645 void Layout::setAnchor (const char *anchor)
646 {
647  _MSG("setAnchor (%s)\n", anchor);
648 
649  if (requestedAnchor)
650  free(requestedAnchor);
651  requestedAnchor = anchor ? strdup (anchor) : NULL;
652  updateAnchor ();
653 }
654 
658 char *Layout::addAnchor (Widget *widget, const char* name)
659 {
660  return addAnchor (widget, name, -1);
661 }
662 
663 char *Layout::addAnchor (Widget *widget, const char* name, int y)
664 {
665  String key (name);
666  if (anchorsTable->contains (&key))
667  return NULL;
668  else {
669  Anchor *anchor = new Anchor ();
670  anchor->name = strdup (name);
671  anchor->widget = widget;
672  anchor->y = y;
673 
674  anchorsTable->put (new String (name), anchor);
675  updateAnchor ();
676 
677  return anchor->name;
678  }
679 }
680 
681 void Layout::changeAnchor (Widget *widget, char* name, int y)
682 {
683  String key (name);
684  Anchor *anchor = anchorsTable->get (&key);
685  assert (anchor);
686  assert (anchor->widget == widget);
687  anchor->y = y;
688  updateAnchor ();
689 }
690 
691 void Layout::removeAnchor (Widget *widget, char* name)
692 {
693  String key (name);
694  anchorsTable->remove (&key);
695 }
696 
697 void Layout::updateAnchor ()
698 {
699  Anchor *anchor;
700  if (requestedAnchor) {
701  String key (requestedAnchor);
702  anchor = anchorsTable->get (&key);
703  } else
704  anchor = NULL;
705 
706  if (anchor == NULL) {
708  if (scrollIdleId != -1 && !scrollIdleNotInterrupted) {
709  platform->removeIdle (scrollIdleId);
710  scrollIdleId = -1;
711  }
712  } else
713  if (anchor->y != -1)
714  scrollTo0 (HPOS_NO_CHANGE, VPOS_TOP, 0, anchor->y, 0, 0, false);
715 }
716 
717 void Layout::setCursor (style::Cursor cursor)
718 {
719  if (cursor != this->cursor) {
720  this->cursor = cursor;
721  view->setCursor (cursor);
722  }
723 }
724 
725 void Layout::updateCursor ()
726 {
727  if (widgetAtPoint && widgetAtPoint->style)
728  setCursor (widgetAtPoint->style->cursor);
729  else
730  setCursor (style::CURSOR_DEFAULT);
731 }
732 
733 void Layout::setBgColor (style::Color *color)
734 {
735  color->ref ();
736 
737  if (bgColor)
738  bgColor->unref ();
739 
740  bgColor = color;
741 
742  if (view)
743  view->setBgColor (bgColor);
744 }
745 
746 void Layout::setBgImage (style::StyleImage *bgImage,
747  style::BackgroundRepeat bgRepeat,
748  style::BackgroundAttachment bgAttachment,
749  style::Length bgPositionX, style::Length bgPositionY)
750 {
751  if (layoutImgRenderer && this->bgImage)
752  this->bgImage->removeExternalImgRenderer (layoutImgRenderer);
753 
754  if (bgImage)
755  bgImage->ref ();
756 
757  if (this->bgImage)
758  this->bgImage->unref ();
759 
760  this->bgImage = bgImage;
761  this->bgRepeat = bgRepeat;
762  this->bgAttachment = bgAttachment;
763  this->bgPositionX = bgPositionX;
764  this->bgPositionY = bgPositionY;
765 
766  if (bgImage) {
767  // Create instance of LayoutImgRenderer when needed. Until this
768  // layout is deleted, "layoutImgRenderer" will be kept, since it
769  // is not specific to the style, but only to this layout.
770  if (layoutImgRenderer == NULL)
771  layoutImgRenderer = new LayoutImgRenderer (this);
772  bgImage->putExternalImgRenderer (layoutImgRenderer);
773  }
774 }
775 
776 
777 void Layout::resizeIdle ()
778 {
779  //static int calls = 0;
780  //MSG(" Layout::resizeIdle calls = %d\n", ++calls);
781 
782  assert (resizeIdleId != -1);
783 
784  // Reset already here, since in this function, queueResize() may be
785  // called again.
786  resizeIdleId = -1;
787 
788  if (topLevel) {
789  Requisition requisition;
790  Allocation allocation;
791 
792  topLevel->sizeRequest (&requisition);
793 
794  allocation.x = allocation.y = 0;
795  allocation.width = requisition.width;
796  allocation.ascent = requisition.ascent;
797  allocation.descent = requisition.descent;
798  topLevel->sizeAllocate (&allocation);
799 
800  canvasWidth = requisition.width;
801  canvasAscent = requisition.ascent;
802  canvasDescent = requisition.descent;
803 
804  emitter.emitCanvasSizeChanged (canvasWidth, canvasAscent, canvasDescent);
805 
806  // Tell the view about the new world size.
807  view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent);
808  // view->queueDrawTotal (false);
809 
810  if (usesViewport) {
811  int currHThickness = currHScrollbarThickness();
812  int currVThickness = currVScrollbarThickness();
813 
814  if (!canvasHeightGreater &&
815  canvasAscent + canvasDescent
816  > viewportHeight - currHThickness) {
817  canvasHeightGreater = true;
818  setSizeHints ();
819  /* May queue a new resize. */
820  }
821 
822  // Set viewport sizes.
823  view->setViewportSize (viewportWidth, viewportHeight,
824  currHThickness, currVThickness);
825  }
826 
827  // views are redrawn via Widget::resizeDrawImpl ()
828 
829  }
830 
831  updateAnchor ();
832 }
833 
834 void Layout::setSizeHints ()
835 {
836  if (topLevel) {
837  topLevel->setWidth (viewportWidth
838  - (canvasHeightGreater ? vScrollbarThickness : 0));
839  topLevel->setAscent (viewportHeight - hScrollbarThickness);
840  topLevel->setDescent (0);
841  }
842 }
843 
844 void Layout::queueDraw (int x, int y, int width, int height)
845 {
846  Rectangle area;
847  area.x = x;
848  area.y = y;
849  area.width = width;
850  area.height = height;
851 
852  if (area.isEmpty ()) return;
853 
854  view->queueDraw (&area);
855 }
856 
857 void Layout::queueDrawExcept (int x, int y, int width, int height,
858  int ex, int ey, int ewidth, int eheight) {
859 
860  if (x == ex && y == ey && width == ewidth && height == eheight)
861  return;
862 
863  // queueDraw() the four rectangles within rectangle (x, y, width, height)
864  // around rectangle (ex, ey, ewidth, eheight).
865  // Some or all of these may be empty.
866 
867  // upper left corner of the intersection rectangle
868  int ix1 = misc::max (x, ex);
869  int iy1 = misc::max (y, ey);
870  // lower right corner of the intersection rectangle
871  int ix2 = misc::min (x + width, ex + ewidth);
872  int iy2 = misc::min (y + height, ey + eheight);
873 
874  queueDraw (x, y, width, iy1 - y);
875  queueDraw (x, iy2, width, y + height - iy2);
876  queueDraw (x, iy1, ix1 - x, iy2 - iy1);
877  queueDraw (ix2, iy1, x + width - ix2, iy2 - iy1);
878 }
879 
880 void Layout::queueResize ()
881 {
882  if (resizeIdleId == -1) {
883  view->cancelQueueDraw ();
884 
885  resizeIdleId = platform->addIdle (&Layout::resizeIdle);
886  }
887 }
888 
889 
890 // Views
891 
892 bool Layout::buttonEvent (ButtonEventType type, View *view, int numPressed,
893  int x, int y, ButtonState state, int button)
894 
895 {
896  EventButton event;
897 
898  moveToWidgetAtPoint (x, y, state);
899 
900  event.xCanvas = x;
901  event.yCanvas = y;
902  event.state = state;
903  event.button = button;
904  event.numPressed = numPressed;
905 
906  return processMouseEvent (&event, type);
907 }
908 
915 bool Layout::motionNotify (View *view, int x, int y, ButtonState state)
916 {
917  EventButton event;
918 
919  moveToWidgetAtPoint (x, y, state);
920 
921  event.xCanvas = x;
922  event.yCanvas = y;
923  event.state = state;
924 
925  return processMouseEvent (&event, MOTION_NOTIFY);
926 }
927 
933 void Layout::enterNotify (View *view, int x, int y, ButtonState state)
934 {
935  Widget *lastWidget;
936  EventCrossing event;
937 
938  lastWidget = widgetAtPoint;
939  moveToWidgetAtPoint (x, y, state);
940 
941  if (widgetAtPoint) {
942  event.state = state;
943  event.lastWidget = lastWidget;
944  event.currentWidget = widgetAtPoint;
945  widgetAtPoint->enterNotify (&event);
946  }
947 }
948 
954 void Layout::leaveNotify (View *view, ButtonState state)
955 {
956 #if 0
957  Widget *lastWidget;
958  EventCrossing event;
959 
960  lastWidget = widgetAtPoint;
961  moveOutOfView (state);
962 
963  if (lastWidget) {
964  event.state = state;
965  event.lastWidget = lastWidget;
966  event.currentWidget = widgetAtPoint;
967  lastWidget->leaveNotify (&event);
968  }
969 #else
970  moveOutOfView (state);
971 #endif
972 }
973 
974 /*
975  * Return the widget at position (x, y). Return NULL, if there is no widget.
976  */
977 Widget *Layout::getWidgetAtPoint (int x, int y)
978 {
979  _MSG ("------------------------------------------------------------\n");
980  _MSG ("widget at (%d, %d)\n", x, y);
981  if (topLevel)
982  return topLevel->getWidgetAtPoint (x, y, 0);
983  else
984  return NULL;
985 }
986 
987 
988 /*
989  * Emit the necessary crossing events, when the mouse pointer has moved to
990  * the given widget (by mouse or scrolling).
991  */
992 void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state)
993 {
994  Widget *ancestor, *w;
995  Widget **track;
996  int trackLen, i, i_a;
997  EventCrossing crossingEvent;
998 
999  _MSG("moveToWidget: wap=%p nwap=%p\n",widgetAtPoint,newWidgetAtPoint);
1000  if (newWidgetAtPoint != widgetAtPoint) {
1001  // The mouse pointer has been moved into another widget.
1002  if (newWidgetAtPoint && widgetAtPoint)
1003  ancestor =
1004  newWidgetAtPoint->getNearestCommonAncestor (widgetAtPoint);
1005  else if (newWidgetAtPoint)
1006  ancestor = newWidgetAtPoint->getTopLevel ();
1007  else
1008  ancestor = widgetAtPoint->getTopLevel ();
1009 
1010  // Construct the track.
1011  trackLen = 0;
1012  if (widgetAtPoint)
1013  // first part
1014  for (w = widgetAtPoint; w != ancestor; w = w->getParent ())
1015  trackLen++;
1016  trackLen++; // for the ancestor
1017  if (newWidgetAtPoint)
1018  // second part
1019  for (w = newWidgetAtPoint; w != ancestor; w = w->getParent ())
1020  trackLen++;
1021 
1022  track = new Widget* [trackLen];
1023  i = 0;
1024  if (widgetAtPoint)
1025  /* first part */
1026  for (w = widgetAtPoint; w != ancestor; w = w->getParent ())
1027  track[i++] = w;
1028  i_a = i;
1029  track[i++] = ancestor;
1030  if (newWidgetAtPoint) {
1031  /* second part */
1032  i = trackLen - 1;
1033  for (w = newWidgetAtPoint; w != ancestor; w = w->getParent ())
1034  track[i--] = w;
1035  }
1036 #if 0
1037  MSG("Track: %s[ ", widgetAtPoint ? "" : "nil ");
1038  for (i = 0; i < trackLen; i++)
1039  MSG("%s%p ", i == i_a ? ">" : "", track[i]);
1040  MSG("] %s\n", newWidgetAtPoint ? "" : "nil");
1041 #endif
1042 
1043  /* Send events to the widgets on the track */
1044  for (i = 0; i < trackLen; i++) {
1045  crossingEvent.state = state;
1046  crossingEvent.currentWidget = widgetAtPoint; // ???
1047  crossingEvent.lastWidget = widgetAtPoint; // ???
1048  if (i < i_a) {
1049  track[i]->leaveNotify (&crossingEvent);
1050  } else if (i == i_a) { /* ancestor */
1051  /* Don't touch ancestor unless:
1052  * - moving into/from NULL,
1053  * - ancestor becomes the newWidgetAtPoint */
1054  if (i_a == trackLen-1 && !newWidgetAtPoint)
1055  track[i]->leaveNotify (&crossingEvent);
1056  else if ((i_a == 0 && !widgetAtPoint) ||
1057  (i_a == trackLen-1 && newWidgetAtPoint))
1058  track[i]->enterNotify (&crossingEvent);
1059  } else {
1060  track[i]->enterNotify (&crossingEvent);
1061  }
1062  }
1063 
1064  delete[] track;
1065 
1066  widgetAtPoint = newWidgetAtPoint;
1067  updateCursor ();
1068  }
1069 }
1070 
1077 bool Layout::processMouseEvent (MousePositionEvent *event,
1078  ButtonEventType type)
1079 {
1080  Widget *widget;
1081 
1082  /*
1083  * If the event is outside of the visible region of the canvas, treat it
1084  * as occurring at the region's edge. Notably, this helps when selecting
1085  * text.
1086  */
1087  if (event->xCanvas < scrollX)
1088  event->xCanvas = scrollX;
1089  else {
1090  int maxX = scrollX + viewportWidth - currVScrollbarThickness() - 1;
1091 
1092  if (event->xCanvas > maxX)
1093  event->xCanvas = maxX;
1094  }
1095  if (event->yCanvas < scrollY)
1096  event->yCanvas = scrollY;
1097  else {
1098  int maxY = misc::min(scrollY + viewportHeight -currHScrollbarThickness(),
1099  canvasAscent + canvasDescent) - 1;
1100 
1101  if (event->yCanvas > maxY)
1102  event->yCanvas = maxY;
1103  }
1104 
1105  widget = getWidgetAtPoint(event->xCanvas, event->yCanvas);
1106 
1107  for (; widget; widget = widget->getParent ()) {
1108  if (widget->isButtonSensitive ()) {
1109  event->xWidget = event->xCanvas - widget->getAllocation()->x;
1110  event->yWidget = event->yCanvas - widget->getAllocation()->y;
1111 
1112  switch (type) {
1113  case BUTTON_PRESS:
1114  return widget->buttonPress ((EventButton*)event);
1115 
1116  case BUTTON_RELEASE:
1117  return widget->buttonRelease ((EventButton*)event);
1118 
1119  case MOTION_NOTIFY:
1120  return widget->motionNotify ((EventMotion*)event);
1121 
1122  default:
1124  }
1125  }
1126  }
1127  if (type == BUTTON_PRESS)
1128  return emitLinkPress (NULL, -1, -1, -1, -1, (EventButton*)event);
1129  else if (type == BUTTON_RELEASE)
1130  return emitLinkRelease(NULL, -1, -1, -1, -1, (EventButton*)event);
1131 
1132  return false;
1133 }
1134 
1135 /*
1136  * This function must be called by a view, when the user has manually changed
1137  * the viewport position. It is *not* called, when the layout has requested the
1138  * position change.
1139  */
1140 void Layout::scrollPosChanged (View *view, int x, int y)
1141 {
1142  if (x != scrollX || y != scrollY) {
1143  scrollX = x;
1144  scrollY = y;
1145 
1146  setAnchor (NULL);
1147  updateAnchor ();
1148  }
1149 }
1150 
1151 /*
1152  * This function must be called by a viewport view, when its viewport size has
1153  * changed. It is *not* called, when the layout has requested the size change.
1154  */
1155 void Layout::viewportSizeChanged (View *view, int width, int height)
1156 {
1157  _MSG("Layout::viewportSizeChanged w=%d h=%d new_w=%d new_h=%d\n",
1158  viewportWidth, viewportHeight, width, height);
1159 
1160  /* If the width has become higher, we test again, whether the vertical
1161  * scrollbar (so to speak) can be hidden again. */
1162  if (usesViewport && width > viewportWidth)
1163  canvasHeightGreater = false;
1164 
1165  /* if size changes, redraw this view.
1166  * TODO: this is a resize call (redraw/resize code needs a review). */
1167  if (viewportWidth != width || viewportHeight != height)
1168  queueResize();
1169 
1170  viewportWidth = width;
1171  viewportHeight = height;
1172 
1173  setSizeHints ();
1174 }
1175 
1176 } // namespace core
1177 } // namespace dw
DBG_OBJ_DELETE
#define DBG_OBJ_DELETE()
Definition: debug.hh:176
dw::core::Widget::buttonPress
bool buttonPress(EventButton *event)
Definition: widget.cc:293
dw::core::style::StyleImage::putExternalImgRenderer
void putExternalImgRenderer(ImgRenderer *ir)
Add an additional ImgRenderer, especially used for drawing.
Definition: style.hh:848
dw::core::style::Cursor
Cursor
Definition: style.hh:198
dw::core::Layout::Anchor::widget
Widget * widget
Definition: layout.hh:147
dw::core::HPosition
HPosition
Definition: types.hh:15
dw::core::Layout::LinkReceiver::click
virtual bool click(Widget *widget, int link, int img, int x, int y, EventButton *event)
Called, when the user has clicked on a link.
Definition: layout.cc:148
dw::core::Allocation::y
int y
Definition: types.hh:166
dw::core::HPOS_RIGHT
Definition: types.hh:19
dw::core::EventCrossing::lastWidget
Widget * lastWidget
Definition: events.hh:77
dw::core::Allocation::x
int x
Definition: types.hh:165
lout::object::Integer
An object::Object wrapper for int's.
Definition: object.hh:92
DBG_OBJ_CREATE
#define DBG_OBJ_CREATE(klass)
Definition: debug.hh:175
dw::core::Layout::LinkReceiver::release
virtual bool release(Widget *widget, int link, int img, int x, int y, EventButton *event)
Called, when the user has released the mouse button on a link.
Definition: layout.cc:142
MSG
#define MSG(...)
Definition: bookmarks.c:45
dw::core::Requisition
Definition: types.hh:172
lout::object
Here, some common classes (or interfaces) are defined, to standardize the access to other classes.
Definition: object.cc:29
dw::core::MousePositionEvent
Base class for all mouse events related to a specific position.
Definition: events.hh:48
dw::core::EventCrossing
Represents a enter or leave notify event.
Definition: events.hh:74
lout::misc::ZoneAllocator
A simple allocator optimized to handle many small chunks of memory. The chunks can not be free'd indi...
Definition: misc.hh:549
dw::core::EventButton
Represents a button press or release event.
Definition: events.hh:57
dw::core::VPOS_CENTER
Definition: types.hh:28
dw::core::Requisition::descent
int descent
Definition: types.hh:176
dw::core::Widget::layout
Layout * layout
Definition: widget.hh:159
dw::core::Widget::enterNotify
void enterNotify(EventCrossing *event)
Definition: widget.cc:308
dw::core::style::Color
Definition: style.hh:709
dw::core::View::setViewportSize
virtual void setViewportSize(int width, int height, int hScrollbarThickness, int vScrollbarThickness)=0
Set the viewport size.
dw::core::View::startDrawing
virtual void startDrawing(Rectangle *area)=0
Called before drawing.
dw::core::Layout::Anchor
Definition: layout.hh:143
lout::misc::assertNotReached
void assertNotReached()
Definition: misc.hh:35
dw::core::Rectangle::intersectsWith
bool intersectsWith(Rectangle *otherRect, Rectangle *dest)
Definition: types.cc:53
dw::core::Widget::isButtonSensitive
bool isButtonSensitive()
Definition: widget.hh:300
dw::core::HPOS_INTO_VIEW
Definition: types.hh:20
dw::core::style::StyleImage::unref
void unref()
Definition: style.hh:832
dw::core::Rectangle::x
int x
Definition: types.hh:72
key
Definition: colors.c:28
dw::core::style::Color::ref
void ref()
Definition: style.hh:734
dw::core::Allocation
Represents the allocation, i.e. actual position and size of a dw::core::Widget.
Definition: types.hh:163
dw::core::Widget::getParent
Widget * getParent()
Definition: widget.hh:302
dw::core::HPOS_NO_CHANGE
Definition: types.hh:22
dw::core::VPOS_TOP
Definition: types.hh:27
dw::core::Layout::LinkReceiver::press
virtual bool press(Widget *widget, int link, int img, int x, int y, EventButton *event)
Called, when the user has pressed the mouse button on a link (but not yet released).
Definition: layout.cc:136
lout::object::String
An object::Object wrapper for strings (char*).
Definition: object.hh:134
lout::misc::max
T max(T a, T b)
Definition: misc.hh:20
DBG_OBJ_ASSOC_CHILD
#define DBG_OBJ_ASSOC_CHILD(child)
Definition: debug.hh:179
dw::core::style::BackgroundAttachment
BackgroundAttachment
Definition: style.hh:241
lout::misc::min
T min(T a, T b)
Definition: misc.hh:19
dw::core::View::usesViewport
virtual bool usesViewport()=0
Return, whether this view uses a viewport.
dw::core::Widget::getNearestCommonAncestor
Widget * getNearestCommonAncestor(Widget *otherWidget)
Get the widget with the highest level, which is a direct ancestor of widget1 and widget2.
Definition: widget.cc:516
dw::core::Allocation::descent
int descent
Definition: types.hh:169
lout::container::typed::HashTable
Typed version of container::untyped::HashTable.
Definition: container.hh:475
lout::object::Object
This is the base class for many other classes, which defines very common virtual methods.
Definition: object.hh:24
dw::core::Layout::Anchor::y
int y
Definition: layout.hh:148
dw::core::Layout::Anchor::name
char * name
Definition: layout.hh:146
dw::core::Rectangle::height
int height
Definition: types.hh:75
dw::core::EventMotion
Represents a mouse motion event.
Definition: events.hh:67
dw::core::Layout::LinkReceiver
Definition: layout.hh:53
dw::core::Requisition::ascent
int ascent
Definition: types.hh:175
lout
Definition: container.cc:26
dw::core::Rectangle::isEmpty
bool isEmpty()
Definition: types.hh:84
dw::core::ScrollCommand
ScrollCommand
Definition: types.hh:35
dw::core::Requisition::width
int width
Definition: types.hh:174
dw::core::MousePositionEvent::yCanvas
int yCanvas
Definition: events.hh:51
MSG_ERR
#define MSG_ERR(...)
Definition: dpid_common.h:22
dw::core::Widget::getTopLevel
Widget * getTopLevel()
Get the widget at the root of the tree, this widget is part from.
Definition: widget.cc:484
dw::core::Rectangle
dw::core::Shape implemtation for simple rectangles.
Definition: types.hh:69
dw::core::Widget::getAllocation
Allocation * getAllocation()
Definition: widget.hh:270
dw::core::Layout::LinkReceiver::enter
virtual bool enter(Widget *widget, int link, int img, int x, int y)
Called, when a link is entered, left, or the position has changed.
Definition: layout.cc:130
dw::core::View::setLayout
virtual void setLayout(Layout *layout)=0
This methods notifies the view, that it has been attached to a layout.
dw::core::Layout::Receiver
Receiver interface different signals.
Definition: layout.hh:47
dw::core::Layout::LayoutImgRenderer
Definition: layout.hh:21
dw::core::View
An interface to encapsulate platform dependent drawing.
Definition: view.hh:16
dw::core::Layout::Receiver::canvasSizeChanged
virtual void canvasSizeChanged(int width, int ascent, int descent)
Definition: layout.cc:94
dw::core::View::getVScrollbarThickness
virtual int getVScrollbarThickness()=0
Get the thickness of the vertical scrollbar, when it is visible.
dw::core::MousePositionEvent::xCanvas
int xCanvas
Definition: events.hh:51
lout::container
This namespace contains a framework for container classes, which members are instances of object::Obj...
Definition: container.cc:30
dw::core::View::setBgColor
virtual void setBgColor(style::Color *color)=0
Set the background of the view.
dw::core::View::scroll
virtual void scroll(ScrollCommand)
Scroll the viewport as commanded.
Definition: view.hh:85
dw::core::View::finishDrawing
virtual void finishDrawing(Rectangle *area)=0
Called after drawing.
dw::core::HPOS_LEFT
Definition: types.hh:17
dw::core::Widget::buttonRelease
bool buttonRelease(EventButton *event)
Definition: widget.cc:298
dw::core::View::scrollTo
virtual void scrollTo(int x, int y)=0
Scroll the vieport to the given position.
dw::core::style::drawBackgroundImage
void drawBackgroundImage(View *view, StyleImage *backgroundImage, BackgroundRepeat backgroundRepeat, BackgroundAttachment backgroundAttachment, Length backgroundPositionX, Length backgroundPositionY, int x, int y, int width, int height, int xRef, int yRef, int widthRef, int heightRef)
Definition: style.cc:1214
dw::core::Layout::ButtonEventType
ButtonEventType
Definition: layout.hh:187
dw::core::VPOS_BOTTOM
Definition: types.hh:29
dw::core::style::StyleImage::ref
void ref()
Definition: style.hh:831
dw::core::Allocation::ascent
int ascent
Definition: types.hh:168
dw::core::style::Length
int Length
Type for representing all lengths within dw::core::style.
Definition: style.hh:389
dw::core::Widget::motionNotify
bool motionNotify(EventMotion *event)
Definition: widget.cc:303
_MSG
#define _MSG(...)
Definition: bookmarks.c:44
core.hh
dw::core::VPosition
VPosition
Definition: types.hh:25
lout::signal::Receiver
The base class for signal receiver base classes.
Definition: signal.hh:253
dw::core::View::setCursor
virtual void setCursor(style::Cursor cursor)=0
Set the cursor appearance.
dw::core::ButtonState
ButtonState
Platform independent representation.
Definition: events.hh:14
dw::core::Widget::leaveNotify
void leaveNotify(EventCrossing *event)
Definition: widget.cc:313
dw::core::Widget
The base class of all dillo widgets.
Definition: widget.hh:23
dw::core::Layout::setWidget
void setWidget(Widget *widget)
Definition: layout.cc:357
MSG_WARN
#define MSG_WARN(...)
Definition: msg.h:27
dw::core::VPOS_NO_CHANGE
Definition: types.hh:32
dw
Dw is in this namespace, or sub namespaces of this one.
Definition: alignedtextblock.cc:26
dw::core::style::CURSOR_DEFAULT
Definition: style.hh:200
dw::core::style::StyleImage::removeExternalImgRenderer
void removeExternalImgRenderer(ImgRenderer *ir)
Remove a previously added additional ImgRenderer.
Definition: style.hh:854
dw::core::MouseEvent::state
ButtonState state
Definition: events.hh:42
dw::core::HPOS_CENTER
Definition: types.hh:18
dw::core::Platform
An interface to encapsulate some platform dependencies.
Definition: platform.hh:16
dw::core::style::BackgroundRepeat
BackgroundRepeat
Definition: style.hh:234
dw::core::EventCrossing::currentWidget
Widget * currentWidget
Definition: events.hh:77
dw::core::VPOS_INTO_VIEW
Definition: types.hh:30
dw::core::Rectangle::width
int width
Definition: types.hh:74
dw::core::Rectangle::y
int y
Definition: types.hh:73
dw::core::Platform::setLayout
virtual void setLayout(Layout *layout)=0
This methods notifies the platform, that it has been attached to a layout.
dw::core::View::getHScrollbarThickness
virtual int getHScrollbarThickness()=0
Get the thickness of the horizontal scrollbar, when it is visible.
dw::core::Allocation::width
int width
Definition: types.hh:167
dw::core::style::StyleImage
Definition: style.hh:740
dw::core::View::setCanvasSize
virtual void setCanvasSize(int width, int ascent, int descent)=0
Set the canvas size.