diff options
Diffstat (limited to 'dw/layout.cc')
-rw-r--r-- | dw/layout.cc | 918 |
1 files changed, 918 insertions, 0 deletions
diff --git a/dw/layout.cc b/dw/layout.cc new file mode 100644 index 00000000..e2f437a3 --- /dev/null +++ b/dw/layout.cc @@ -0,0 +1,918 @@ +/* + * Dillo Widget + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + + +#include "core.hh" + +#include "../lout/debug.hh" +#include "../lout/misc.hh" + +using namespace lout::container; +using namespace lout::object; + +namespace dw { +namespace core { + +void Layout::Receiver::canvasSizeChanged (int width, int ascent, int descent) +{ +} + +// ---------------------------------------------------------------------- + +bool Layout::Emitter::emitToReceiver (lout::signal::Receiver *receiver, + int signalNo, + int argc, Object **argv) +{ + Receiver *layoutReceiver = (Receiver*)receiver; + + switch (signalNo) { + case CANVAS_SIZE_CHANGED: + layoutReceiver->canvasSizeChanged (((Integer*)argv[0])->getValue (), + ((Integer*)argv[1])->getValue (), + ((Integer*)argv[2])->getValue ()); + break; + + default: + misc::assertNotReached (); + } + + return false; +} + +void Layout::Emitter::emitCanvasSizeChanged (int width, + int ascent, int descent) +{ + Integer w (width), a (ascent), d (descent); + Object *argv[3] = { &w, &a, &d }; + emitVoid (CANVAS_SIZE_CHANGED, 3, argv); +} + +// --------------------------------------------------------------------- + +Layout::Anchor::~Anchor () +{ + delete name; +} + +// --------------------------------------------------------------------- + +Layout::Layout (Platform *platform) +{ + this->platform = platform; + views = new container::typed::List <View> (true); + topLevel = NULL; + widgetAtPoint = NULL; + + DBG_OBJ_CREATE (this, "DwRenderLayout"); + + bgColor = NULL; + cursor = style::CURSOR_DEFAULT; + + canvasWidth = canvasAscent = canvasDescent = 0; + + usesViewport = false; + scrollX = scrollY = 0; + + requestedAnchor = NULL; + scrollIdleId = -1; + scrollIdleNotInterrupted = false; + + anchorsTable = + new container::typed::HashTable <object::String, Anchor> (true, true); + + resizeIdleId = -1; + + textZone = new misc::ZoneAllocator (16 * 1024); + + DBG_OBJ_ASSOC (&findtextState, this); + DBG_OBJ_ASSOC (&selectionState, this); + + platform->setLayout (this); + + selectionState.setLayout(this); +} + +Layout::~Layout () +{ + if (scrollIdleId != -1) + platform->removeIdle (scrollIdleId); + if (resizeIdleId != -1) + platform->removeIdle (resizeIdleId); + + if (topLevel) + delete topLevel; + delete platform; + delete views; + delete anchorsTable; + delete textZone; +} + +void Layout::addWidget (Widget *widget) +{ + if (topLevel) { + fprintf (stderr, "widget already set\n"); + return; + } + + topLevel = widget; + widget->layout = this; + + findtextState.setWidget (widget); + + canvasHeightGreater = false; + setSizeHints (); + updateBgColor (); + queueResize (); +} + +void Layout::removeWidget () +{ + /** + * \bug Some more attributes must be reset here. + */ + topLevel = NULL; + widgetAtPoint = NULL; + canvasWidth = canvasAscent = canvasDescent = 0; + scrollX = scrollY = 0; + + for (typed::Iterator <View> it = views->iterator (); it.hasNext (); ) { + View *view = it.getNext (); + view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent); + if (view->usesViewport ()) + view->setViewportSize (viewportWidth, viewportHeight, 0, 0); + view->queueDrawTotal (); + } + + setAnchor (NULL); + updateAnchor (); + + emitter.emitCanvasSizeChanged (canvasWidth, canvasAscent, canvasDescent); + + findtextState.setWidget (NULL); + selectionState.reset (); + + updateCursor (); +} + +void Layout::setWidget (Widget *widget) +{ + if (topLevel) + delete topLevel; + widgetAtPoint = NULL; + textZone->zoneFree (); + addWidget (widget); + + updateCursor (); +} + +/** + * \brief Attach a view to the layout. + * + * It will become a child of the layout, + * and so it will be destroyed, when the layout will be destroyed. + */ +void Layout::attachView (View *view) +{ + views->append (view); + platform->attachView (view); + + /* + * The layout of the view is set later, first, we "project" the current + * state of the layout into the new view. A view must handle this without + * a layout. See also at the end of this function. + */ + if (bgColor) + view->setBgColor (bgColor); + view->setCursor (cursor); + view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent); + + if (view->usesViewport ()) { + if (usesViewport) { + view->scrollTo (scrollX, scrollY); + view->setViewportSize (viewportWidth, viewportHeight, + hScrollbarThickness, vScrollbarThickness); + hScrollbarThickness = misc::max (hScrollbarThickness, + view->getHScrollbarThickness ()); + vScrollbarThickness = misc::max (vScrollbarThickness, + view->getVScrollbarThickness ()); + } + else { + usesViewport = true; + scrollX = scrollY = 0; + viewportWidth = viewportHeight = 100; // random values + hScrollbarThickness = view->getHScrollbarThickness (); + vScrollbarThickness = view->getVScrollbarThickness (); + } + } + + /* + * This is the last call within this function, so that it is safe for + * the implementation of dw::core::View::setLayout, to call methods + * of dw::core::Layout. + */ + view->setLayout (this); +} + +void Layout::detachView (View *view) +{ + view->setLayout (NULL); + platform->detachView (view); + + views->detachRef (view); + + /** + * \todo Actually, viewportMarkerWidthDiff and + * viewportMarkerHeightDiff have to be recalculated here, since the + * effective (i.e. maximal) values may change, after the view has been + * detached. Same applies to the usage of viewports. + */ +} + +/** + * \brief Scrolls all viewports, so that the region [x, y, width, height] + * is seen, according to hpos and vpos. + */ +void Layout::scrollTo (HPosition hpos, VPosition vpos, + int x, int y, int width, int height) +{ + scrollTo0 (hpos, vpos, x, y, width, height, true); +} + +void Layout::scrollTo0 (HPosition hpos, VPosition vpos, + int x, int y, int width, int height, + bool scrollingInterrupted) +{ + if (usesViewport) { + //printf ("scrollTo (%d, %d, %s)\n", + // x, y, scrollingInterrupted ? "true" : "false"); + + scrollTargetHpos = hpos; + scrollTargetVpos = vpos; + scrollTargetX = x; + scrollTargetY = y; + scrollTargetWidth = width; + scrollTargetHeight = height; + + if (scrollIdleId == -1) { + scrollIdleId = platform->addIdle (&Layout::scrollIdle); + scrollIdleNotInterrupted = true; + } + + scrollIdleNotInterrupted = + scrollIdleNotInterrupted || !scrollingInterrupted; + } +} + +void Layout::scrollIdle () +{ + bool xChanged = true; + switch (scrollTargetHpos) { + case HPOS_LEFT: + scrollX = scrollTargetX; + break; + case HPOS_CENTER: + scrollX = + scrollTargetX + - (viewportWidth - vScrollbarThickness - scrollTargetWidth) / 2; + break; + case HPOS_RIGHT: + scrollX = + scrollTargetX + - (viewportWidth - vScrollbarThickness - scrollTargetWidth); + break; + case HPOS_INTO_VIEW: + xChanged = calcScrollInto (scrollTargetX, scrollTargetWidth, &scrollX, + viewportWidth - vScrollbarThickness); + break; + case HPOS_NO_CHANGE: + xChanged = false; + break; + } + + bool yChanged = true; + switch (scrollTargetVpos) { + case VPOS_TOP: + scrollY = scrollTargetY; + break; + case VPOS_CENTER: + scrollY = + scrollTargetY + - (viewportHeight - hScrollbarThickness - scrollTargetHeight) / 2; + break; + case VPOS_BOTTOM: + scrollY = + scrollTargetY + - (viewportHeight - hScrollbarThickness - scrollTargetHeight); + break; + case VPOS_INTO_VIEW: + yChanged = calcScrollInto (scrollTargetY, scrollTargetHeight, &scrollY, + viewportHeight - hScrollbarThickness); + break; + case VPOS_NO_CHANGE: + yChanged = false; + break; + } + + if (xChanged || yChanged) { + adjustScrollPos (); + for (container::typed::Iterator <View> it = views->iterator (); + it.hasNext (); ) { + View *thisView = it.getNext(); + thisView->scrollTo (scrollX, scrollY); + } + } + + scrollIdleId = -1; +} + +void Layout::adjustScrollPos () +{ + scrollX = misc::min (scrollX, + canvasWidth - (viewportWidth - vScrollbarThickness)); + scrollX = misc::max (scrollX, 0); + + scrollY = misc::min (scrollY, + canvasAscent + canvasDescent - (viewportHeight - hScrollbarThickness)); + scrollY = misc::max (scrollY, 0); + + //printf("adjustScrollPos: scrollX=%d scrollY=%d\n", scrollX, scrollY); +} + +bool Layout::calcScrollInto (int requestedValue, int requestedSize, + int *value, int viewportSize) +{ + if (requestedSize > viewportSize) { + // The viewport size is smaller than the size of the region which will + // be shown. If the region is already visible, do not change the + // position. Otherwise, show the left/upper border, this is most likely + // what is needed. + if (*value >= requestedValue && + *value + viewportSize < requestedValue + requestedSize) + return false; + else + requestedSize = viewportSize; + } + + if (requestedValue < *value) { + *value = requestedValue; + return true; + } else if (requestedValue + requestedSize > *value + viewportSize) { + *value = requestedValue - viewportSize + requestedSize; + return true; + } else + return false; +} + +void Layout::draw (View *view, Rectangle *area) +{ + Rectangle widgetArea, intersection, widgetDrawArea; + + if (topLevel) { + /* Draw the top level widget. */ + widgetArea.x = topLevel->allocation.x; + widgetArea.y = topLevel->allocation.y; + widgetArea.width = topLevel->allocation.width; + widgetArea.height = topLevel->getHeight (); + + if (area->intersectsWith (&widgetArea, &intersection)) { + view->startDrawing (&intersection); + + /* Intersection in widget coordinates. */ + widgetDrawArea.x = intersection.x - topLevel->allocation.x; + widgetDrawArea.y = intersection.y - topLevel->allocation.y; + widgetDrawArea.width = intersection.width; + widgetDrawArea.height = intersection.height; + + topLevel->draw (view, &widgetDrawArea); + + view->finishDrawing (&intersection); + } + } +} + +/** + * Sets the anchor to scroll to. + */ +void Layout::setAnchor (const char *anchor) +{ + //printf ("setAnchor (%s)\n", anchor); + + if (requestedAnchor) + delete requestedAnchor; + requestedAnchor = anchor ? strdup (anchor) : NULL; + updateAnchor (); +} + +/** + * Used, when the widget is not allocated yet. + */ +char *Layout::addAnchor (Widget *widget, const char* name) +{ + return addAnchor (widget, name, -1); +} + +char *Layout::addAnchor (Widget *widget, const char* name, int y) +{ + String key (name); + if (anchorsTable->contains (&key)) + return NULL; + else { + Anchor *anchor = new Anchor (); + anchor->name = strdup (name); + anchor->widget = widget; + anchor->y = y; + + anchorsTable->put (new String (name), anchor); + updateAnchor (); + + return anchor->name; + } +} + +void Layout::changeAnchor (Widget *widget, char* name, int y) +{ + String key (name); + Anchor *anchor = anchorsTable->get (&key); + assert (anchor); + assert (anchor->widget == widget); + anchor->y = y; + updateAnchor (); +} + +void Layout::removeAnchor (Widget *widget, char* name) +{ + String key (name); + anchorsTable->remove (&key); +} + +void Layout::updateAnchor () +{ + Anchor *anchor; + if (requestedAnchor) { + String key (requestedAnchor); + anchor = anchorsTable->get (&key); + } else + anchor = NULL; + + if (anchor == NULL) { + /** \todo Copy comment from old docs. */ + if (scrollIdleId != -1 && !scrollIdleNotInterrupted) { + platform->removeIdle (scrollIdleId); + scrollIdleId = -1; + } + } else + if (anchor->y != -1) + scrollTo0 (HPOS_NO_CHANGE, VPOS_TOP, 0, anchor->y, 0, 0, false); +} + +void Layout::setCursor (style::Cursor cursor) +{ + if (cursor != this->cursor) { + this->cursor = cursor; + + for (typed::Iterator <View> it = views->iterator (); it.hasNext (); ) { + View *view = it.getNext (); + view->setCursor (cursor); + } + } +} + +void Layout::updateCursor () +{ + if (widgetAtPoint && widgetAtPoint->style) + setCursor (widgetAtPoint->style->cursor); + else + setCursor (style::CURSOR_DEFAULT); +} + +void Layout::updateBgColor () +{ + /* The toplevel widget should always have a defined background color, + * except at the beginning. Searching a defined background is not + * necessary. */ + if (topLevel && topLevel->getStyle() && + topLevel->getStyle()->backgroundColor) + bgColor = topLevel->getStyle()->backgroundColor; + else + bgColor = NULL; + + for (typed::Iterator <View> it = views->iterator (); it.hasNext (); ) { + View *view = it.getNext (); + view->setBgColor (bgColor); + } +} + +void Layout::resizeIdle () +{ + //static int calls = 0; + //printf(" Layout::resizeIdle calls = %d\n", ++calls); + + while (resizeIdleId != -1) { + // Reset already here, since in this function, queueResize() may be + // called again. + resizeIdleId = -1; + + if (topLevel) { + Requisition requisition; + Allocation allocation; + + topLevel->sizeRequest (&requisition); + + allocation.x = allocation.y = 0; + allocation.width = requisition.width; + allocation.ascent = requisition.ascent; + allocation.descent = requisition.descent; + topLevel->sizeAllocate (&allocation); + + canvasWidth = requisition.width; + canvasAscent = requisition.ascent; + canvasDescent = requisition.descent; + + emitter.emitCanvasSizeChanged ( + canvasWidth, canvasAscent, canvasDescent); + + // Tell the views about the new world size. + for (typed::Iterator <View> it = views->iterator (); it.hasNext ();) { + View *view = it.getNext (); + view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent); + // view->queueDrawTotal (false); + } + + if (usesViewport) { + int actualHScrollbarThickness = + (canvasWidth > viewportWidth) ? hScrollbarThickness : 0; + int actualVScrollbarThickness = + (canvasAscent + canvasDescent > viewportHeight) ? + vScrollbarThickness : 0; + + if (!canvasHeightGreater && + canvasAscent + canvasDescent + > viewportHeight - actualHScrollbarThickness) { + canvasHeightGreater = true; + setSizeHints (); + /* May queue a new resize. */ + } + + // Set viewport sizes. + for (typed::Iterator <View> it = views->iterator (); + it.hasNext (); ) { + View *view = it.getNext (); + if (view->usesViewport ()) + view->setViewportSize (viewportWidth, viewportHeight, + actualHScrollbarThickness, + actualVScrollbarThickness); + } + } + } + + // views are redrawn via Widget::resizeDrawImpl () + + } + + updateAnchor (); +} + +void Layout::setSizeHints () +{ + if (topLevel) { + topLevel->setWidth (viewportWidth + - (canvasHeightGreater ? vScrollbarThickness : 0)); + topLevel->setAscent (viewportHeight - vScrollbarThickness); + topLevel->setDescent (0); + } +} + +void Layout::queueDraw (int x, int y, int width, int height) +{ + Rectangle area; + area.x = x; + area.y = y; + area.width = width; + area.height = height; + + if (area.isEmpty ()) return; + + for (container::typed::Iterator <View> it = views->iterator (); + it.hasNext (); ) { + View *view = it.getNext (); + view->queueDraw (&area); + } +} + +void Layout::queueDrawExcept (int x, int y, int width, int height, + int ex, int ey, int ewidth, int eheight) { + + if (x == ex && y == ey && width == ewidth && height == eheight) + return; + + // queueDraw() the four rectangles within rectangle (x, y, width, height) + // around rectangle (ex, ey, ewidth, eheight). + // Some or all of these may be empty. + + // upper left corner of the intersection rectangle + int ix1 = misc::max (x, ex); + int iy1 = misc::max (y, ey); + // lower right corner of the intersection rectangle + int ix2 = misc::min (x + width, ex + ewidth); + int iy2 = misc::min (y + height, ey + eheight); + + queueDraw (x, y, width, iy1 - y); + queueDraw (x, iy2, width, y + height - iy2); + queueDraw (x, iy1, ix1 - x, iy2 - iy1); + queueDraw (ix2, iy1, x + width - ix2, iy2 - iy1); +} + +void Layout::queueResize () +{ + if (resizeIdleId == -1) { + for (container::typed::Iterator <View> it = views->iterator (); + it.hasNext (); ) { + View *view = it.getNext (); + view->cancelQueueDraw (); + } + + resizeIdleId = platform->addIdle (&Layout::resizeIdle); + } +} + + +// Views + +bool Layout::buttonEvent (ButtonEventType type, View *view, int numPressed, + int x, int y, ButtonState state, int button) + +{ + EventButton event; + + moveToWidgetAtPoint (x, y, state); + + event.xCanvas = x; + event.yCanvas = y; + event.state = state; + event.button = button; + event.numPressed = numPressed; + + return processMouseEvent (&event, type, true); +} + +/** + * \brief This function is called by a view, to delegate a motion notify + * event. + * + * Arguments are similar to dw::core::Layout::buttonPress. + */ +bool Layout::motionNotify (View *view, int x, int y, ButtonState state) +{ + EventButton event; + + moveToWidgetAtPoint (x, y, state); + + event.xCanvas = x; + event.yCanvas = y; + event.state = state; + + return processMouseEvent (&event, MOTION_NOTIFY, true); +} + +/** + * \brief This function is called by a view, to delegate a enter notify event. + * + * Arguments are similar to dw::core::Layout::buttonPress. + */ +void Layout::enterNotify (View *view, int x, int y, ButtonState state) +{ + Widget *lastWidget; + EventCrossing event; + + lastWidget = widgetAtPoint; + moveToWidgetAtPoint (x, y, state); + + if(widgetAtPoint) { + event.state = state; + event.lastWidget = lastWidget; + event.currentWidget = widgetAtPoint; + widgetAtPoint->enterNotify (&event); + } +} + +/** + * \brief This function is called by a view, to delegate a leave notify event. + * + * Arguments are similar to dw::core::Layout::buttonPress. + */ +void Layout::leaveNotify (View *view, ButtonState state) +{ + Widget *lastWidget; + EventCrossing event; + + lastWidget = widgetAtPoint; + moveOutOfView (state); + + if(lastWidget) { + event.state = state; + event.lastWidget = lastWidget; + event.currentWidget = widgetAtPoint; + lastWidget->leaveNotify (&event); + } +} + +/* + * Return the widget at position (x, y). Return NULL, if there is no widget. + */ +Widget *Layout::getWidgetAtPoint (int x, int y) +{ + //_MSG ("------------------------------------------------------------\n"); + //_MSG ("widget at (%d, %d)\n", x, y); + if (topLevel) + return topLevel->getWidgetAtPoint (x, y, 0); + else + return NULL; +} + + +/* + * Emit the necessary crossing events, when the mouse pointer has moved to + * the given widget. + */ +void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state) +{ + Widget *ancestor, *w; + Widget **track; + int trackLen, i; + EventCrossing crossingEvent; + + if (newWidgetAtPoint != widgetAtPoint) { + // The mouse pointer has been moved into another widget. + if (newWidgetAtPoint && widgetAtPoint) + ancestor = + newWidgetAtPoint->getNearestCommonAncestor (widgetAtPoint); + else if(newWidgetAtPoint) + ancestor = newWidgetAtPoint->getTopLevel (); + else + ancestor = widgetAtPoint->getTopLevel (); + + // Construct the track. + trackLen = 0; + if (widgetAtPoint) + // first part + for (w = widgetAtPoint; w != ancestor; w = w->getParent ()) + trackLen++; + trackLen++; // for the ancestor + if(newWidgetAtPoint) + // second part + for (w = newWidgetAtPoint; w != ancestor; w = w->getParent ()) + trackLen++; + + track = new Widget* [trackLen]; + i = 0; + if (widgetAtPoint) + /* first part */ + for (w = widgetAtPoint; w != ancestor; w = w->getParent ()) + track[i++] = w; + track[i++] = ancestor; + if(newWidgetAtPoint) { + /* second part */ + i = trackLen - 1; + for (w = newWidgetAtPoint; w != ancestor; w = w->getParent ()) + track[i--] = w; + } + + /* Send events to all events on the track */ + for (i = 0; i < trackLen; i++) { + crossingEvent.state = state; + crossingEvent.currentWidget = widgetAtPoint; // ??? + crossingEvent.lastWidget = widgetAtPoint; // ??? + + if (i != 0) + track[i]->enterNotify (&crossingEvent); + if (i != trackLen - 1) + track[i]->leaveNotify (&crossingEvent); + } + + delete[] track; + + widgetAtPoint = newWidgetAtPoint; + updateCursor (); + } +} + +/** + * \brief Common processing of press, release and motion events. + * + * This function depends on that move_to_widget_at_point() + * has been called before. + */ +bool Layout::processMouseEvent (MousePositionEvent *event, + ButtonEventType type, bool mayBeSuppressed) +{ + Widget *widget; + + for (widget = widgetAtPoint; widget; widget = widget->getParent ()) { + if(!mayBeSuppressed || widget->isButtonSensitive ()) { + event->xWidget = event->xCanvas - widget->getAllocation()->x; + event->yWidget = event->yCanvas - widget->getAllocation()->y; + + switch (type) { + case BUTTON_PRESS: + return widget->buttonPress ((EventButton*)event); + + case BUTTON_RELEASE: + return widget->buttonRelease ((EventButton*)event); + + case MOTION_NOTIFY: + return widget->motionNotify ((EventMotion*)event); + + default: + misc::assertNotReached (); + } + } + } + + return false; +} + +/* + * This function must be called by a view, when the user has manually changed + * the viewport position. It is *not* called, when the layout has requested the + * position change. + */ +void Layout::scrollPosChanged (View *view, int x, int y) +{ + if (x != scrollX || y != scrollY) { + scrollX = x; + scrollY = y; + + // Tell all views about the scrolling position, except the caller. + for (container::typed::Iterator <View> it = views->iterator (); + it.hasNext (); ) { + View *thisView = it.getNext(); + if(view != thisView && thisView->usesViewport ()) + thisView->scrollTo (scrollX, scrollY); + } + + setAnchor (NULL); + updateAnchor (); + } +} + +/* + * This function must be called by a viewport view, when its viewport size has + * changed. It is *not* called, when the layout has requested the size change. + */ +void Layout::viewportSizeChanged (View *view, int width, int height) +{ + //printf("Layout::viewportSizeChanged w=%d h=%d new_w=%d new_h=%d\n", + // viewportWidth, viewportHeight, width, height); + + /* If the width has become higher, we test again, whether the vertical + * scrollbar (so to speak) can be hidden again. */ + if(usesViewport && width > viewportWidth) + canvasHeightGreater = false; + + /* if size changes, redraw this view. + * todo: this is a resize call (redraw/resize code needs a review). */ + if (viewportWidth != width || viewportHeight != height) + queueResize(); + + viewportWidth = width; + viewportHeight = height; + + setSizeHints (); + + int actualHScrollbarThickness = + (canvasWidth > viewportWidth) ? hScrollbarThickness : 0; + int actualVScrollbarThickness = + (canvasAscent + canvasDescent > viewportWidth) ? vScrollbarThickness : 0; + + /* Tell all views about the size, except the caller. */ + for (container::typed::Iterator <View> it = views->iterator (); + it.hasNext (); ) { + View *thisView = it.getNext(); + if(view != thisView && thisView->usesViewport ()) + thisView->setViewportSize (viewportWidth, viewportHeight, + actualHScrollbarThickness, + actualVScrollbarThickness); + } +} + +} // namespace dw +} // namespace core + |