aboutsummaryrefslogtreecommitdiff
path: root/doc/dw-layout-views.doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc/dw-layout-views.doc')
-rw-r--r--doc/dw-layout-views.doc270
1 files changed, 270 insertions, 0 deletions
diff --git a/doc/dw-layout-views.doc b/doc/dw-layout-views.doc
new file mode 100644
index 00000000..f064c671
--- /dev/null
+++ b/doc/dw-layout-views.doc
@@ -0,0 +1,270 @@
+/** \page dw-layout-views Layout and Views
+
+Rendering of Dw is done in a way resembling the model-view pattern, at
+least formally. Actually, the counterpart of the model, the layout
+(dw::core::Layout), does a bit more than a typical model, namely the
+layouting (delegated to the widget tree, see \ref dw-layout-widgets),
+and the views do a bit less than a typical view, i.e. only the actual
+drawing.
+
+Additionally, there is a structure representing common properties of
+the platform, views generally work only together with one specific
+platform. A platform is typically related to the underlying UI
+toolkit, but other uses may be thought of.
+
+This design helps to archieve three important goals:
+
+<ul>
+<li> It makes different views of the same document simple, e.g. the
+ normal viewport and the preview window.
+
+<li> Abstraction of the actual drawing, by different implementations
+ of dw::core::View. Most important, there must be a viewport, but
+ some other views are possible, e.g. a preview window.
+
+<li> It makes portability simple.
+</ul>
+
+
+<h2>Viewports</h2>
+
+Although the design implies that the usage of viewports should be
+fully transparent to the layout module, this cannot be fully archived,
+for the following reasons:
+
+<ul>
+<li> Some features, which are used on the level of dw::core::Widget,
+ e.g. anchors, refer to scrolling positions.
+
+<li> Size hints (see \ref dw-layout-widgets) depend on the viewport
+ sizes, e.g. when the user changes the window size, and so also
+ the size of a viewport, the text within should be rewrapped.
+</ul>
+
+Therefor, dw::core::Layout keeps track of the viewport size, the
+viewport position, and even the thickness of the scrollbars, they are
+relevant, see below for more details. These sizes are always equal in
+all views. However, a given view may not use viewports at all, and
+there may be the case, that no view related to a layout uses
+viewports, in this case, the viewport size is not defined at all.
+
+(The case, that there is no viewport at all, is currently not well
+defined, but this case does not occur currently within dillo.)
+
+Whether a given dw::core::View implementation is a viewport or not, is
+defined by the return value of dw::core::View::usesViewport. If this
+method returns false, the following methods need not to be implemented
+at all:
+
+<ul>
+<li> dw::core::View::getHScrollbarThickness,
+<li> dw::core::View::getVScrollbarThickness,
+<li> dw::core::View::scrollTo, and
+<li> dw::core::View::setViewportSize.
+</ul>
+
+<h3>Scrolling Positions</h3>
+
+The scrolling position is the canvas position at the upper left corner
+of the viewport. Views using viewports must
+
+<ol>
+<li> change this value on request (dw::core::View::scrollTo), and
+<li> tell other changes to the layout, e.g. caused by user events
+ (dw::core::Layout::scrollPosChanged).
+</ol>
+
+Applications of scrolling positions (anchors, test search etc.) are
+handled by the layout, in a way fully transparent to the views.
+
+<h3>Scrollbars</h3>
+
+A feature of the viewport size model are scrollbars. There may be a
+vertical scrollbar and a horizontal scrollbar, displaying the
+relationship between canvas and viewport height or width,
+respectively. If they are not needed, they are hidden, to save screen
+space.
+
+Since scrollbars decrease the usable space of a view, dw::core::Layout
+must know how much space they take. Each view returns, via
+dw::core::View::getHScrollbarThickness and
+dw::core::View::getVScrollbarThickness, how thick they will be, when
+visible. The total space difference is then the maximum of all values,
+which the views return.
+
+Viewport sizes, which denote the size of the viewport widgets, include
+scrollbar thicknesses. When referring to the viewport \em excluding
+the scrollbars space, we will call it "usable viewport size", this is
+the area, which is used to display the canvas.
+
+<h2>Drawing</h2>
+
+A view must implement several drawing methods, which work on the whole
+canvas. If it is neccesary to convert them (e.g. into
+dw::fltk::FltkViewport), this is done in a way fully transparent to
+dw::core::Widget and dw::core::Layout, instead, this is done by the
+view implementation.
+
+There exist following situations:
+
+<ul>
+<li> A view gets an expose event: It will delegate this to the
+ layout (dw::core::Layout::draw), which will then pass it to the
+ widgets (dw::core::Widget::draw), with the view as a parameter.
+ Eventually, the widgets will call drawing methods of the view.
+
+<li> A widget requests a redraw: In this case, the widget will
+ delegate this to the layout (dw::core::Layout::queueDraw), which
+ delegates it to all views (dw::core::View::queueDraw).
+ Typically, the views will queue these requests, for efficiency.
+
+<li> A widget requests a resize: This case is described below, in short,
+ dw::core::View::queueDrawTotal is called for the view.
+</ul>
+
+If the draw method of a widget is implemented in a way that it may
+draw outside of the widget's allocation, it should draw into a
+<i>clipping view.</i> A clipping view is a view related to the actual
+view, which guarantees that the parts drawn outside are discarded. At
+the end, the clipping view is merged into the actual view. Sample
+code:
+
+\code
+void Foo::draw (dw::core::View *view, dw::core::Rectangle *area)
+{
+ // 1. Create a clipping view.
+ dw::core::View clipView =
+ view->getClippingView (allocation.x, allocation.y,
+ allocation.width, getHeight ());
+
+ // 2. Draw into clip_view
+ clipView->doSomeDrawing (...);
+
+ // 3. Draw the children, they receive the clipping view as argument.
+ dw::core::Rectangle *childArea
+ for (<all relevant children>) {
+ if (child->intersects (area, &childArea))
+ child->draw (clipView, childArea);
+ }
+
+ // 4. Merge
+ view->mergeClippingView (clipView);
+}
+\endcode
+
+A drawing process is always embedded into calls of
+dw::core::View::startDrawing and dw::core::View::finishDrawing. An
+implementation of this may e.g. use backing pixmaps, to prevent
+flickering.
+
+
+<h2>Sizes</h2>
+
+Generally, all views show the same layout, which has a given size
+(canvas size). In the simplest case, views do not have an influence on
+the canvas size, so that they are just told about changes of the
+canvas size, by a call to dw::core::View::setCanvasSize. This happens
+in the following situations:
+
+<ul>
+<li> dw::core::Layout::addWidget,
+<li> dw::core::Layout::removeWidget (called by dw::core::Widget::~Widget),
+ and
+<li> dw::core::Layout::queueResize (called by
+ dw::core::Widget::queueResize, when a widget itself requests a size
+ change).
+</ul>
+
+<h3>Viewports</h3>
+
+Furthermore, viewport sizes and scrollbar thicknesses are always the
+same. There are two cases, in which the viewport size changes:
+
+<ul>
+<li> As an reaction on a user event, e.g. when the user changes the
+ window size. In this case, the affected view delegates this
+ change to the layout, by calling
+ dw::core::Layout::viewportSizeChanged. All other views are
+ told about this, by calling dw::core::Layout::setViewportSize.
+
+<li> The viewport size may also depend on the visibility of UI
+ widgets, which depend on the world size, e.g scrollbars,
+ generally called "viewport markers". This is described in an own
+ section.
+</ul>
+
+After the creation of the layout, the viewport size is undefined. When
+a view is attached to a layout, and this view is already to be able to
+define its viewport size, it may already call
+dw::core::Layout::viewportSizeChanged within the implementation of
+dw::core::Layout::setLayout. If not, it may do this, as soon as the
+viewport size gets known.
+
+Generally, the scrollbars have to be considered. If e.g. an HTML page
+is rather small, it looks like this:
+
+\image html dw-viewport-without-scrollbar.png
+
+If some more data is retrieved, so that the height exceeds the
+viewport size, the text has to be rewrapped, since the available width
+gets smaller, due to the vertical scrollbar:
+
+\image html dw-viewport-with-scrollbar.png
+
+Notice the different line breaks.
+
+This means circular dependencies between these different sizes:
+
+<ol>
+<li> Whether the scrollbars are visible or not, determines the
+ usable space of the viewport.
+
+<li> From the usable space of the viewport, the size hints for the
+ toplevel are calculated.
+
+<li> The size hints for the toplevel widgets may have an effect on its
+ size, which is actually the canvas size.
+
+<li> The canvas size determines the visibility of the scrollbarss.
+</ol>
+
+To make an implementation simpler, we simplify the model:
+
+<ol>
+<li> For the calls to dw::core::Widget::setAscent and
+ dw::core::Widget::setDescent, we will always exclude the
+ horizontal scrollbar thickness (i.e. assume the horizontal
+ scrollbar is used, although the visibility is determined correctly).
+
+<li> For the calls to dw::core::Widget::setWidth, we will calculate
+ the usable viewport width, but with the general assumption, that
+ the widget generally gets higher.
+</ol>
+
+This results in the following rules:
+
+<ol>
+<li> Send always (when it changes) dw::core::Layout::viewportHeight
+ minus the maximal value of dw::core::View::getHScrollbarThickness as
+ argument to dw::core::Widget::setAscent, and 0 as argument to
+ dw::core::Widget::setDescent.
+
+<li> There is a flag, dw::core::Layout::canvasHeightGreater, which is set
+ to false in the following cases:
+
+ <ul>
+ <li> dw::core::Layout::addWidget,
+ <li> dw::core::Layout::removeWidget (called by dw::core::Widget::~Widget),
+ and
+ <li> dw::core::Layout::viewportSizeChanged.
+ </ul>
+
+ Whenever the canvas size is calculated (dw::core::Layout::resizeIdle),
+ and dw::core::Layout::canvasHeightGreater is false, a test is made,
+ whether the widget has in the meantime grown that high, that the second
+ argument should be set to true (i.e. the vertical scrollbar gets visible).
+ As soon as and dw::core::Layout::canvasHeightGreater is true, no such test
+ is done anymore.
+</ol>
+
+*/ \ No newline at end of file