diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/Makefile.am | 61 | ||||
-rw-r--r-- | doc/dw-changes.doc | 109 | ||||
-rw-r--r-- | doc/dw-images-and-backgrounds.doc | 146 | ||||
-rw-r--r-- | doc/dw-layout-views.doc | 270 | ||||
-rw-r--r-- | doc/dw-layout-widgets.doc | 270 | ||||
-rw-r--r-- | doc/dw-map.doc | 59 | ||||
-rw-r--r-- | doc/dw-overview.doc | 157 | ||||
-rw-r--r-- | doc/dw-usage.doc | 373 | ||||
-rw-r--r-- | doc/dw-widget-sizes.doc | 186 | ||||
-rw-r--r-- | doc/fltk-problems.doc | 219 | ||||
-rw-r--r-- | doc/index.doc | 48 | ||||
-rw-r--r-- | doc/lout.doc | 94 | ||||
-rw-r--r-- | doc/rounding-errors.doc | 24 | ||||
-rw-r--r-- | doc/uml-legend.doc | 192 |
14 files changed, 2190 insertions, 18 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am index 9142fa3a..faea2b6c 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,19 +1,44 @@ EXTRA_DIST = \ - Cache.txt \ - Cookies.txt \ - Dillo.txt \ - Dw.txt \ - DwImage.txt \ - DwPage.txt \ - DwRender.txt \ - DwStyle.txt \ - DwTable.txt \ - DwWidget.txt \ - HtmlParser.txt \ - IO.txt \ - Images.txt \ - Imgbuf.txt \ - NC_design.txt \ - Selection.txt \ - Dpid.txt \ - README + index.doc \ + lout.doc \ + dw-map.doc \ + dw-overview.doc \ + dw-usage.doc \ + dw-layout-views.doc \ + dw-layout-widgets.doc \ + dw-widget-sizes.doc \ + dw-changes.doc \ + dw-images-and-backgrounds.doc \ + fltk-problems.doc \ + rounding-errors.doc \ + uml-legend.doc \ + dw-example-screenshot.png \ + dw-viewport-without-scrollbar.png \ + dw-viewport-with-scrollbar.png \ + dw-size-of-widget.png \ + dw-style-box-model.png \ + dw-style-length-absolute.png \ + dw-style-length-percentage.png \ + dw-style-length-relative.png \ + dw-textblock-collapsing-spaces-1-1.png \ + dw-textblock-collapsing-spaces-1-2.png \ + dw-textblock-collapsing-spaces-2-1.png \ + dw-textblock-collapsing-spaces-2-2.png \ + Cache.txt \ + Cookies.txt \ + Dillo.txt \ + Dw.txt \ + DwImage.txt \ + DwPage.txt \ + DwRender.txt \ + DwStyle.txt \ + DwTable.txt \ + DwWidget.txt \ + HtmlParser.txt \ + IO.txt \ + Images.txt \ + Imgbuf.txt \ + NC_design.txt \ + Selection.txt \ + Dpid.txt \ + README diff --git a/doc/dw-changes.doc b/doc/dw-changes.doc new file mode 100644 index 00000000..b76e9433 --- /dev/null +++ b/doc/dw-changes.doc @@ -0,0 +1,109 @@ +/** \page dw-changes Changes to the GTK+-based Release Version + +<h2>Changes in Dw</h2> + +Related to the FLTK port, there have been many changes, this is a +(hopefully complete) list: + +<ul> +<li> Rendering abstraction, read \ref dw-overview and \ref dw-layout-views + for details. Some important changes: + + <ul> + <li> The underlying platform (e.g. the UI toolkit) is fully abstract, + there are several platform independent structures replacing + GTK+ structures, e.g. dw::core::Event. + + <li> The central class managing the widget tree is not anymore + GtkDwViewport, but dw::core::Layout. + + <li> There are multiple views (implementations of dw::core::View). + Typically, you keep a reference on dw::core::Layout and a "main" + view (a viewport). + + <li> Drawing is done via dw::core::View, a pointer is passed to + dw::core::Widget::draw. + + <li> The distinction between viewport coordinates and canvas + coordinates (formerly world coordinates) has been mostly + removed. (Only for views, it sometimes plays a role, see + \ref dw-layout-views). +</ul> + +<li> Cursors have been moved to dw::core::style, see + dw::core::style::Style::cursor. dw::core::Widget::setCursor is now + protected (and so only called by widget implementations). + +<li> World coordinates are now called canvas coordinates. + +<li> There is now a distinction between dw::core::style::StyleAttrs and + dw::core::style::Style. + +<li> There is no base class for container widgets anymore. The former + DwContainer::for_all has been removed, instead this functionality + is now done via iterators (dw::core::Widget::iterator, + dw::core::Iterator). + +<li> DwPage is now called dw::Textblock, and DwAlignedPage + dw::AlignedTextblock. + +<li> dw::Textblock, all sub classes of it, and dw::Table do not read + "limit_text_width" from the preferences, but get it as an argument. + (May change again.) + +<li> dw::Table has been rewritten. + +<li> Instead of border_spacing in the old DwStyle, there are two attributes, + dw::core::style::Style::hBorderSpacing and + dw::core::style::Style::vBorderSpacing, since CSS allowes to specify + two values. Without CSS, both attributes should have the same value. + +<li> Images are handled differently, see \ref dw-images-and-backgrounds. + +<li> Embedded UI widgets (formerly GtkWidget's) are handled differently, + see dw::core::ui. + +<li> DwButton has been removed, instead, embedded UI widgets are used. See + dw::core::ui and dw::core::ui::ComplexButtonResource. +</ul> + +Dw is now written C++, the transition should be obvious. All "Dw" +prefixes have been removed, instead, namespaces are used now: + +<ul> +<li>dw::core contains the core, +<li>dw::core::style styles, +<li>dw::core::ui embedded UI resources, +<li>dw::fltk classes related to FLTK, and +<li>::dw the widgets. +</ul> + +<h2>Documentation</h2> + +The old documentation has been moved to: + +<table> +<tr><th colspan="2">Old <th>New +<tr><td rowspan="2">Dw.txt + <td>general part <td>\ref dw-overview, \ref dw-usage, + \ref dw-layout-widgets, + \ref dw-widget-sizes +<tr><td>remarks on specific widgets <td>respective source files: dw::Bullet, + dw::core::ui::Embed +<tr><td rowspan="2">DwImage.txt + <td>signals <td>dw::core::Widget::LinkReceiver +<tr><td>rest <td>dw::Image, + \ref dw-images-and-backgrounds +<tr><td colspan="2">Imgbuf.txt <td>dw::core::Imgbuf, + \ref dw-images-and-backgrounds +<tr><td colspan="2">DwPage.txt <td>dw::Textblock +<tr><td colspan="2">DwRender.txt <td>\ref dw-overview, \ref dw-layout-views, + dw::core::ui +<tr><td colspan="2">DwStyle.txt <td>dw::core::style +<tr><td colspan="2">DwTable.txt <td>dw::Table +<tr><td colspan="2">DwWidget.txt <td>dw::core::Widget, \ref dw-layout-widgets, + \ref dw-widget-sizes +<tr><td colspan="2">Selection.txt <td>dw::core::SelectionState +</table> + +*/
\ No newline at end of file diff --git a/doc/dw-images-and-backgrounds.doc b/doc/dw-images-and-backgrounds.doc new file mode 100644 index 00000000..c4991807 --- /dev/null +++ b/doc/dw-images-and-backgrounds.doc @@ -0,0 +1,146 @@ +/** \page dw-images-and-backgrounds Images and Backgrounds in Dw + +<h2>General</h2> + +Representation of the image data is delegated to dw::core::Imgbuf, see +there for details. Drawing is delegated to dw::core::View +(dw::core::View::drawImgbuf). + +Since dw::core::Imgbuf provides memory management based on reference +counting, there may be an 1-to-n relation from image renderers (image +widgets or backgrounds, see below) and dw::core::Imgbuf. Since +dw::core::Imgbuf does not know about renderers, but just provides +rendering functionality, the caller must (typically after calling +dw::core::Imgbuf::copyRow) notify all renderers connected to the +buffer. + + +<h2>Images</h2> + +This is the simplest renderer, displaying an image. For each row to be +drawn, + +<ol> +<li> first dw::core::Imgbuf::copyRow, and then +<li> for each dw::Image, dw::Image::drawRow must be called, with the same + argument (no scaling is necessary). +</ol> + +dw::Image automatically scales the dw::core::Imgbuf, the root buffer +should be passed to dw::Image::setBuffer. + +\see dw::Image for more details. + +<h2>Future Extensions</h2> + +(This is not implemented yet.) Rendering itself (image widgets and +background) will be abstracted, by a new interface +dw::core::ImageRenderer. In the current code for image decoding, this +interface will replace references to dw::Image, which implements +dw::core::ImageRenderer, in most cases. + +<h2>Backgrounds</h2> + +(This is based on future extensions described above.) Since background +are style resources, they are associated with +dw::core::style::Style. For backgrounds, another level is needed, +because of the 1-to-n relation from dw::core::style::Style to +dw::core::Widget: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", arrowtail="none", labelfontname=Helvetica, + labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + "background renderer (as a part of style)" -> "image buffer" [headlabel="*", + taillabel="1"]; + "widget (or a part of it)" -> "background renderer (as a part of style)" + [headlabel="*", taillabel="1"]; +} +\enddot + +Unlike dw::Image, dw::core::style::BgRenderer is not associated with a +certain rectangle on the canvas. Instead, widgets, or parts of widgets +take this role. This is generally represented by an implementation of +the interface dw::core::style::BgAllocation, which is implemented by +dw::core::Widget, but also by all parts of widget implementation, +which may have an own background image. + +The following diagram gives a total overview: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", arrowtail="none", labelfontname=Helvetica, + labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + "DICache Entry"; + + subgraph cluster_dw_images { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="Dw Images"; + + ImageRenderer [URL="\ref dw::core::ImageRenderer", color="#ff8080"]; + Imgbuf [URL="\ref dw::core::Imgbuf", color="#ff8080"]; + } + + subgraph cluster_widgets { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="Widgets"; + + Widget [URL="\ref dw::core::Widget", color="#a0a0a0"]; + Textblock [URL="\ref dw::Textblock"]; + "Textblock::Word" [URL="\ref dw::Textblock::Word"]; + Table [URL="\ref dw::Table"]; + "Table::Row" [URL="\ref dw::Table::Row"]; + Image [URL="\ref dw::Image"]; + } + + subgraph cluster_style { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="dw::core::style"; + + Style [URL="\ref dw::core::style::Style"]; + BgRenderer [URL="\ref dw::core::style::BgRenderer"]; + BgAllocation [URL="\ref dw::core::style::BgAllocation", color="#ff8080"]; + } + + "DICache Entry" -> ImageRenderer [headlabel="*", taillabel="1"]; + "DICache Entry" -> Imgbuf [headlabel="1", taillabel="1"]; + + BgRenderer -> Imgbuf [headlabel="1", taillabel="*"]; + BgRenderer -> BgAllocation [headlabel="*", taillabel="1"]; + ImageRenderer -> BgRenderer [arrowhead="none", arrowtail="empty", + style="dashed"]; + ImageRenderer -> Image [arrowhead="none", arrowtail="empty", + style="dashed"]; + + Style -> BgRenderer [headlabel="0..1", taillabel="1"]; + + Widget -> Textblock [arrowhead="none", arrowtail="empty"]; + Textblock -> "Textblock::Word" [headlabel="*", taillabel="1"]; + Widget -> Table [arrowhead="none", arrowtail="empty"]; + Table -> "Table::Row" [headlabel="*", taillabel="1"]; + Widget -> Image [arrowhead="none", arrowtail="empty"]; + + BgAllocation -> Widget [arrowhead="none", arrowtail="empty", + style="dashed"]; + BgAllocation -> "Textblock::Word" [arrowhead="none", arrowtail="empty", + style="dashed"]; + BgAllocation -> "Table::Row" [arrowhead="none", arrowtail="empty", + style="dashed"]; +} +\enddot + +<center>[\ref uml-legend "legend"]</center> + + +<h2>Integration into dillo</h2> + +\todo Add some references. + + +*/ 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 diff --git a/doc/dw-layout-widgets.doc b/doc/dw-layout-widgets.doc new file mode 100644 index 00000000..f5b0ed06 --- /dev/null +++ b/doc/dw-layout-widgets.doc @@ -0,0 +1,270 @@ +/** \page dw-layout-widgets Layout and Widgets + +Both, the layouting and the drawing is delegated to a tree of +widgets. A widget represents a given part of the document, e.g. a text +block, a table, or an image. Widgets may be nested, so layouting and +drawing may be delegated by one widget to its child widgets. + +Where do define the borders of a widget, wheather to combine different +widgets to one, or to split one widget into multiple ones, should be +considered based on different concerns: + +<ul> +<li> First, there are some restrictions of Dw: + + <ul> + <li> The allocation (this is the space a widget allocates at + a time) of a dillo widget is always rectangular, and + <li> the allocation of a child widget must be a within the allocation + of the parent widget. + </ul> + +<li> Since some widgets are already rather complex, an important goal + is to keep the implementation of the widget simple. + +<li> Furthermore, the granularity should not be to fine, because of the + overhead each single widget adds. +</ul> + +For CSS, there will be a document tree on top of Dw, this will be +flexible enough when mapping the document structure on the widget +structure, so you should not have the document structure in mind. + +<h2>Sizes</h2> + +\ref dw-widget-sizes + + +<h2>Styles</h2> + +Each widget is assigned a style, see dw::core::style for more +informations. + + +<h2>Iterators</h2> + +Widgets must implement dw::core::Widget::iterator. There are several +common iterators: + +<ul> +<li>dw::core::EmptyIterator, and +<li>dw::core::TextIterator. +</ul> + +Both hide the constructor, use the \em create method. + +These simple iterators only iterate through one widget, it does not +have to iterate recursively through child widgets. Instead, the type +dw::core::Content::WIDGET is returned, and the next call of +dw::core::Iterator::next will return the piece of contents \em after +(not within) this child widget. + +This makes implementation much simpler, for recursive iteration, there +is dw::core::DeepIterator. + + +<h2>Anchors and Scrolling</h2> + +\todo This section is not implemented yet, after the implementation, + the documentation should be reviewed. + +Here is a description, what is to be done for a widget +implementation. How to jump to anchors, set scrolling positions +etc. is described in \ref dw-usage. + +<h3>Anchors</h3> + +Anchors are position markers, which are identified by a name, which is +unique in the widget tree. The widget must care about anchors in three +different situations: + +<ol> +<li> Adding an anchor is inititiated by a specific widget method, e.g. + dw::Textblock::addAnchor. Here, dw::core::Widget::addAnchor must be + called, + +<li> Whenever the position of an anchor is changed, + dw::core::Widget::changeAnchor is called (typically, this is done + in the implementation of dw::core::Widget::sizeAllocateImpl). + +<li> When a widget is destroyed, the anchor must be removed, by calling + dw::core::Widget::removeAnchor. +</ol> + +All these methods are delegated to dw::core::Layout, which manages +anchors centrally. If the anchor in question has been set to jump to, +the viewport position is automatically adjusted, see \ref +dw-usage. + + +<h2>Drawing</h2> + +In two cases, a widget has to be drawn: + +<ol> +<li> as a reaction on an expose event, +<li> if the widget content has changed and it needs to be redrawn. +</ol> + +In both cases, drawing is done by the implementation of +dw::core::Widget::draw. Generally, a widget draws into different views +(see \ref dw-layout-views), the view to draw into is passed as the +first argument. In the first case, only the view, which causes the +expose event, is passed, in the second case, dw::core::Widget::draw is +called multiple times, once for each view connected to the layout. + +Each view provides some primitive methods for drawing, most should be +obvious. Notice that the views do not know anything about dillo +widgets, and so coordinates have to be passed as canvas coordinates. + +A widget may only draw in its own allocation. If this cannot be +achieved, a <i>clipping view</i> can be used, this is described in +\ref dw-layout-views. Generally, drawing should then look like: + +\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 + +Clipping views are expensive, so they should be avoided, when possible. + +The second argument to dw::core::Widget::draw is the region, which has +to be drawn. This may (but needs not) be used for optimization. + +If a widget contains child widgets, it must explicitly draw these +children (see also code example above). For this, there is the useful +method dw::core::Widget::intersects, which returns, which area of the +child must be drawn. + +<h3>Explicit Redrawing</h3> + +If a widget changes its contents, so that it must be redrawn, it must +call dw::core::Widget::queueDrawArea or +dw::core::Widget::queueDraw. The first variant expects a region within +the widget, the second will cause the whole widget to be redrawn. This +will cause an asynchronous call of dw::core::Widget::draw. + +If only the size changes, a call to dw::core::Widget::queueResize is +sufficient, this will also queue a complete redraw (see \ref +dw-widget-sizes.) + + +<h2>Mouse Events</h2> + +A widget may process mouse events. The views (\ref dw-layout-views) +pass mouse events to the layout, which then passes them to the +widgtes. There are two kinds of mouse events: + +<ul> +<li>events returning bool, and +<li>events returning nothing (void). +</ul> + +The first group consists of: + +<ul> +<li>dw::core::Widget::buttonPressImpl, +<li>dw::core::Widget::buttonReleaseImpl, and +<li>dw::core::Widget::motionNotifyImpl. +</ul> + +For these events, a widget returns a boolean value, which denotes, +whether the widget has processed this event (true) or not (false). In +the latter case, the event is delegated according to the following +rules: + +<ol> +<li> First, this event is passed to the bottom-most widget, in which + allocation the mouse position is in. +<li> If the widget does not process this event (returning false), it is + passed to the parent, and so on. +<li> The final result (whether \em any widget has processed this event) is + returned to the view. +</ol> + +The view may return this to the UI toolkit, which then interprets this +in a similar way (whether the viewport, a UI widget, has processed +this event). + +These events return nothing: + +<ul> +<li>dw::core::Widget::enterNotifyImpl and +<li>dw::core::Widget::leaveNotifyImpl. +</ul> + +since they are bound to a widget. + +When processing mouse events, the layout always deals with two +widgets: the widget, the mouse pointer was in, when the previous mouse +event was processed, (below called the "old widget") and the widget, +in which the mouse pointer is now ("new widget"). + +The following paths are calculated: + +<ol> +<li> the path from the old widget to the nearest common anchestor of the old + and the new widget, and +<li> the path from this anchestor to the new widget. +</ol> + +For the widgets along these paths, dw::core::Widget::enterNotifyImpl +and dw::core::Widget::leaveNotifyImpl are called. + +<h3>Signals</h3> + +If a caller outside of the widget is interested in these events, he +can connect a dw::core::Widget::EventReceiver. For those events with a +boolean return value, the results of the signal emission is regarded, +i.e. the delegation of an event to the parent of the widget can be +stopped by a signal receiver returning true, even if the widget method +returns false. + +First, the widget method is called, then (in any case) the signal is +emitted. + +<h3>Selection</h3> + +If your widget has selectable contents, it should delegate the events +to dw::core::SelectionState (dw::core::Layout::selectionState). + + +<h2>Miscellaneous</h2> + +<h3>Cursors</h3> + +Each widget has a cursor, which is set by +dw::core::Widget::setCursor. If a cursor is assigned to a part of a +widget, this widget must process mouse events, and call +dw::core::Widget::setCursor explicitly. + +(This will change, cursors should become part of +dw::core::style::Style.) + +<h3>Background</h3> + +Backgrounds are part of styles +(dw::core::style::Style::backgroundColor). If a widget assigns +background colors to parts of a widget (as dw::Table does for rows), +it must call dw::core::Widget::setBgColor for the children inside this +part. + +*/
\ No newline at end of file diff --git a/doc/dw-map.doc b/doc/dw-map.doc new file mode 100644 index 00000000..aebeb7da --- /dev/null +++ b/doc/dw-map.doc @@ -0,0 +1,59 @@ +/** \page dw-map Dillo Widget Documentation Map + +This maps includes special documentations as well as longer comments +in the sources. Arrows denote references between the documents. + +\dot +digraph G { + rankdir=LR; + node [shape=record, fontname=Helvetica, fontsize=8]; + fontname=Helvetica; fontsize=8; + + dw_overview [label="Dillo Widget Overview", URL="\ref dw-overview"]; + dw_usage [label="Dillo Widget Usage", URL="\ref dw-usage"]; + dw_layout_views [label="Layout and Views", URL="\ref dw-layout-views"]; + dw_layout_widgets [label="Layout and Widgets", + URL="\ref dw-layout-widgets"]; + dw_widget_sizes [label="Sizes of Dillo Widgets", + URL="\ref dw-widget-sizes"]; + dw_changes [label="Changes to the GTK+-based Release Version", + URL="\ref dw-changes"]; + dw_images_and_backgrounds [label="Images and Backgrounds in Dw", + URL="\ref dw-images-and-backgrounds"]; + dw_Image [label="dw::Image", URL="\ref dw::Image"]; + dw_core_Imgbuf [label="dw::core::Imgbuf", URL="\ref dw::core::Imgbuf"]; + dw_core_SelectionState [label="dw::core::SelectionState", + URL="\ref dw::core::SelectionState"]; + dw_core_style [label="dw::core::style", URL="\ref dw::core::style"]; + dw_Table [label="dw::Table", URL="\ref dw::Table"]; + dw_Textblock [label="dw::Textblock", URL="\ref dw::Textblock"]; + dw_core_ui [label="dw::core::ui", URL="\ref dw::core::ui"]; + + dw_overview -> dw_changes; + dw_overview -> dw_usage; + dw_overview -> dw_core_style; + dw_overview -> dw_core_ui; + dw_overview -> dw_images_and_backgrounds; + dw_overview -> dw_layout_widgets; + dw_overview -> dw_widget_sizes; + dw_overview -> dw_layout_views; + + dw_usage -> dw_Table; + dw_usage -> dw_Textblock; + dw_usage -> dw_core_style; + dw_usage -> dw_core_ui; + dw_usage -> dw_images_and_backgrounds; + + dw_layout_widgets -> dw_widget_sizes; + dw_layout_widgets -> dw_core_SelectionState; + + dw_widget_sizes -> dw_Table; + dw_widget_sizes -> dw_Textblock; + + dw_images_and_backgrounds -> dw_core_Imgbuf; + dw_images_and_backgrounds -> dw_Image; + + dw_core_style -> dw_Textblock; +} +\enddot +*/
\ No newline at end of file diff --git a/doc/dw-overview.doc b/doc/dw-overview.doc new file mode 100644 index 00000000..2414a5da --- /dev/null +++ b/doc/dw-overview.doc @@ -0,0 +1,157 @@ +/** \page dw-overview Dillo Widget Overview + +Note: If you are already familiar with the Gtk+-based version of Dw, +read \ref dw-changes. + + +The module Dw (Dillo Widget) is responsible for the low-level rendering of +all resources, e.g. images, plain text, and HTML pages (this is the +most complex type). Dw is \em not responsible for parsing HTML, or +decoding image data. Furthermore, the document tree, which is planned +for CSS, is neither a part of Dw, instead, it is a new module on top +of Dw. + +The rendering, as done by Dw, is split into two phases: + +<ul> +<li> the \em layouting, this means calculating the exact positions of + words, lines, etc. (in pixel position), and +<li> the \em drawing, i.e. making the result of the layouting visible + on the screen. +</ul> + +The result of the layouting allocates an area, which is called +\em canvas. + +<h2>Structure</h2> + +The whole Dw module can be split into the following parts: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", fontname=Helvetica, fontsize=10, + labelfontname=Helvetica, labelfontsize=10, + color="#404040", labelfontcolor="#000080"]; + + subgraph cluster_core { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="Platform independent core"; + + Layout [URL="\ref dw::core::Layout"]; + Platform [URL="\ref dw::core::Platform", color="#ff8080"]; + View [URL="\ref dw::core::View", color="#ff8080"]; + Widget [URL="\ref dw::core::Widget", color="#a0a0a0"]; + } + + subgraph cluster_fltk { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="FLTK specific part (as an\nexample for the platform specific\n\ +implementations)"; + + subgraph cluster_fltkcore { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="FLTK core"; + + FltkPlatform [URL="\ref dw::fltk::FltkPlatform"]; + FltkView [URL="\ref dw::fltk::FltkView", color="#ff8080"]; + } + + FltkViewport [URL="\ref dw::fltk::FltkViewport"]; + FltkPreview [URL="\ref dw::fltk::FltkPreview"]; + } + + subgraph cluster_widgets { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="Platform independent widgets"; + + Textblock [URL="\ref dw::Textblock"]; + AlignedTextblock [URL="\ref dw::AlignedTextblock", color="#a0a0a0"]; + Table [URL="\ref dw::Table"]; + Image [URL="\ref dw::Image"]; + etc1 [label="..."]; + etc2 [label="..."]; + } + + Layout -> Platform [headlabel="1", taillabel="1"]; + Layout -> View [headlabel="*", taillabel="1"]; + + Layout -> Widget [headlabel="1", taillabel="1", label="topLevel"]; + Widget -> Widget [headlabel="*", taillabel="1", label="children"]; + + Widget -> Textblock [arrowhead="none", arrowtail="empty"]; + Widget -> Table [arrowhead="none", arrowtail="empty"]; + Widget -> Image [arrowhead="none", arrowtail="empty"]; + Widget -> etc1 [arrowhead="none", arrowtail="empty"]; + Textblock -> AlignedTextblock [arrowhead="none", arrowtail="empty"]; + AlignedTextblock -> etc2 [arrowhead="none", arrowtail="empty"]; + + Platform -> FltkPlatform [arrowhead="none", arrowtail="empty", + style="dashed"]; + FltkPlatform -> FltkView [headlabel="*", taillabel="1"]; + + View -> FltkView [arrowhead="none", arrowtail="empty"]; + FltkView -> FltkViewport [arrowhead="none", arrowtail="empty", + style="dashed"]; + FltkView -> FltkPreview [arrowhead="none", arrowtail="empty", + style="dashed"]; +} +\enddot + +<center>[\ref uml-legend "legend"]</center> + +\em Platform means in most cases the underlying UI toolkit +(e.g. FLTK). A layout is bound to a specific platform, but multiple +platforms may be handled in one program. + +A short overview: + +<ul> +<li> dw::core::Layout is the central class, it manages the widgets and the + views, and provides delegation methods for the platform. + +<li> The layouting is done by a tree of widgets (details are described in + \ref dw-layout-widgets), also the drawing, which is finally delegated + to the views. + +<li> The views (implementations of dw::core::View) provide primitive methods + for drawing, but also have an influence on + the canvas size (via size hints). See \ref dw-layout-views for details. + +<li> Some platform dependencies are handled by implementations + of dw::core::Platform. +</ul> + + +<h3>Header Files</h3> + +The structures mentioned above can be found in the following header +files: + +<ul> +<li> Anything from the Dw core in core.hh. Do not include the single files. + +<li> The single widgets can be found in the respective header files, e.g. + image.hh for dw::Image. + +<li> The core of the FLTK implementation is defined in fltkcore.hh. This + includes dw::fltk::FltkPlatform, dw::fltk::FltkView, but not the concrete + view implementations. + +<li> The views can be found in single header files, e.g fltkviewport.hh for + dw::fltk::FltkViewport. +</ul> + + +<h2>Further Documentations</h2> + +A complete map can be found at \ref dw-map. + +<ul> +<li> For learning, how to use Dw, read \ref dw-usage and related documents, + dw::core::style, dw::core::ui and \ref dw-images-and-backgrounds. +<li> Advanced topics are described in \ref dw-layout-widgets, + \ref dw-widget-sizes and \ref dw-layout-views. +</ul> + +*/
\ No newline at end of file diff --git a/doc/dw-usage.doc b/doc/dw-usage.doc new file mode 100644 index 00000000..d0aa8d36 --- /dev/null +++ b/doc/dw-usage.doc @@ -0,0 +1,373 @@ +/** \page dw-usage Dillo Widget Usage + +This document describes the usage of Dw, without going too much into +detail. + + +<h2>Getting Started</h2> + +In this section, a small runnable example is described, based on the +FLTK implementation. + +As described in \ref dw-overview, the following objects are needed: + +<ul> +<li> dw::core::Layout, +<li> an implementation of dw::core::Platform (we will use + dw::fltk::FltkPlatform), +<li> at least one implementation of dw::core::View (dw::fltk::FltkViewport), + and +<li> some widgets (for this example, only a simple dw::Textblock). +</ul> + +First of all, the necessary #include's: + +\code +#include <fltk/Window.h> +#include <fltk/run.h> + +#include "dw/core.hh" +#include "dw/fltkcore.hh" +#include "dw/fltkviewport.hh" +#include "dw/textblock.hh" +\endcode + +Everything is put into one function: + +\code +int main(int argc, char **argv) +{ +\endcode + +As the first object, the platform is instanciated: + +\code + dw::fltk::FltkPlatform *platform = new dw::fltk::FltkPlatform (); +\endcode + +Then, the layout is created, with the platform attached: + +\code + dw::core::Layout *layout = new dw::core::Layout (platform); +\endcode + +For the view, we first need a FLTK window: + +\code + fltk::Window *window = new fltk::Window(200, 300, "Dw Example"); + window->begin(); +\endcode + +After this, we can create a viewport, and attach it to the layout: + +\code + dw::fltk::FltkViewport *viewport = + new dw::fltk::FltkViewport (0, 0, 200, 300); + layout->attachView (viewport); +\endcode + +Each widget needs a style (dw::core::style::Style, see dw::core::style), +so we construct it here. For this, we need to fill a +dw::core::style::StyleAttrs structure with values, and call +dw::core::style::Style::create (latter is done further below): + +\code + dw::core::style::StyleAttrs styleAttrs; + styleAttrs.initValues (); + styleAttrs.margin.setVal (5); +\endcode + +dw::core::style::StyleAttrs::initValues sets several default +values. The last line sets a margin of 5 pixels. Next, we need a +font. Fonts are created in a similar way, first, the attributes are +defined: + +\code + dw::core::style::FontAttrs fontAttrs; + fontAttrs.name = "Bitstream Charter"; + fontAttrs.size = 14; + fontAttrs.weight = 400; + fontAttrs.style = dw::core::style::FONT_STYLE_NORMAL; +\endcode + +Now, the font can be created: + +\code + styleAttrs.font = dw::core::style::Font::create (layout, &fontAttrs); +\endcode + +As the last attributes, the background and forground colors are +defined, here dw::core::style::Color::createSimple must be called: + +\code + styleAttrs.color = + dw::core::style::Color::createSimple (layout, 0x000000); + styleAttrs.backgroundColor = + dw::core::style::Color::createSimple (layout, 0xffffff); +\endcode + +Finally, the style for the widget is created: + +\code + dw::core::style::Style *widgetStyle = + dw::core::style::Style::create (layout, &styleAttrs); +\endcode + +Now, we create a widget, assign a style to it, and set it as the +toplevel widget of the layout: + +\code + dw::Textblock *textblock = new dw::Textblock (false); + textblock->setStyle (widgetStyle); + layout->setWidget (textblock); +\endcode + +The style is not needed anymore (a reference is added in +dw::core::Widget::setStyle), so it should be unreferred: + +\code + widgetStyle->unref(); +\endcode + +Now, some text should be added to the textblock. For this, we first +need another style. \em styleAttrs can still be used for this. We set +the margin to 0, and the background color to "transparent": + +\code + styleAttrs.margin.setVal (0); + styleAttrs.backgroundColor = NULL; + + dw::core::style::Style *wordStyle = + dw::core::style::Style::create (layout, &styleAttrs); +\endcode + +This loop adds some paragraphs: + +\code + for(int i = 1; i <= 10; i++) { + char buf[4]; + sprintf(buf, "%d.", i); + + char *words[] = { "This", "is", "the", buf, "paragraph.", + "Here", "comes", "some", "more", "text", + "to", "demonstrate", "word", "wrapping.", + NULL }; + + for(int j = 0; words[j]; j++) { + textblock->addText(strdup(words[j]), wordStyle); +\endcode + +Notice the \em strdup, dw::Textblock::addText will feel responsible +for the string, and free the text at the end. (This has been done to +avoid some overhead in the HTML parser.) + +The rest is simple, it also includes spaces (which also have styles): + +\code + textblock->addSpace(wordStyle); + } +\endcode + +Finally, a paragraph break is added, which is 10 pixels high: + +\code + textblock->addParbreak(10, wordStyle); + } +\endcode + +Again, this style should be unreferred: + +\code + wordStyle->unref(); +\endcode + +After adding text, this method should always be called (for faster +adding large text blocks): + +\code + textblock->flush (); +\endcode + +Some FLTK stuff to finally show the window: + +\code + window->resizable(viewport); + window->show(); + int errorCode = fltk::run(); +\endcode + +For cleaning up, it is sufficient to destroy the layout: + +\code + delete layout; +\endcode + +And the rest + +\code + return errorCode; +} +\endcode + +If you compile and start the program, you should see the following: + +\image html dw-example-screenshot.png + +Try to scroll, or to resize the window, you will see, that everything +is done automatically. + +Of course, creating new widgets, adding text to widgets etc. can also +be done while the program is running, i.e. after fltk::run has been +called, within timeouts, idles, I/O functions etc. Notice that Dw is +not thread safe, so that everything should be done within one thread. + +With the exception, that you have to call dw::Textblock::flush, +everything gets imediately visible, within reasonable times; Dw has +been optimized for frequent updates. + + +<h2>List of all Widgets</h2> + +These widgets are used within dillo: + +<ul> +<li>dw::core::ui::Embed +<li>dw::AlignedTextblock +<li>dw::Bullet +<li>dw::Ruler +<li>dw::Image +<li>dw::ListItem +<li>dw::Table +<li>dw::TableCell +<li>dw::Textblock +</ul> + +If you want to create a new widget, refer to \ref dw-layout-widgets. + + +<h2>List of Views</h2> + +There are three dw::core::View implementations for FLTK: + +<ul> +<li> dw::fltk::FltkViewport implements a viewport, which is used in the + example above. + +<li> dw::fltk::FltkPreview implements a preview window, together with + dw::fltk::FltkPreviewButton, it is possible to have a scaled down + overview of the whole canvas. + +<li> dw::fltk::FltkFlatView is a "flat" view, i.e. it does not support + scrolling. It is used for HTML buttons, see + dw::fltk::ui::FltkComplexButtonResource and especially + dw::fltk::ui::FltkComplexButtonResource::createNewWidget for details. +</ul> + +More informations about views in general can be found in \ref +dw-layout-views. + + +<h2>Iterators</h2> + +For examining generally the contents of widgets, there are iterators +(dw::core::Iterator), created by the method +dw::core::Widget::iterator (see there for more details). + +These simple iterators only iterate through one widget, and return +child widgets as dw::core::Content::WIDGET. The next call of +dw::core::Iterator::next will return the piece of contents \em after +(not within) this child widget. + +If you want to iterate through the whole widget trees, there are two +possibilities: + +<ol> +<li> Use a recursive function. Of course, with this approach, you are + limited by the program flow. + +<li> Maintain a stack of iterators, so you can freely pass this stack + around. This is already implemented, as dw::core::DeepIterator. +</ol> + +As an example, dw::core::SelectionState represents the selected region +as two instances of dw::core::DeepIterator. + + +<h2>Finding Text</h2> + +See dw::core::Layout::findtextState and dw::core::FindtextState +(details in the latter). There are delegation methods: + +<ul> +<li> dw::core::Layout::search and +<li> dw::core::Layout::resetSearch. +</ul> + + +<h2>Anchors and Scrolling</h2> + +In some cases, it is necessary to scroll to a given position, or to +an anchor, programmatically. + +<h3>Anchors</h3> + +Anchors are defined by widgets, e.g. dw::Textblock defines them, when +dw::Textblock::addAnchor is called. To jump to a specific anchor +within the current widget tree, use dw::core::Layout::setAnchor. + +This can be done immediately after assignig a toplevel widget, even +when the anchor has not yet been defined. The layout will remember the +anchor, and jump to the respective position, as soon as possible. Even +if the anchor position changes (e.g., when an anchor is moved +downwards, since some space is needed for an image in the text above), +the position is corrected. + +As soon as the user scrolls the viewport, this correction is not done +anymore. If in dillo, the user request a page with an anchor, which is +quite at the bottom of the page, he may be get interested in the text +at the beginning of the page, and so scrolling down. If then, after +the anchor has been read and added to the dw::Textblock, this anchor +would be jumped at, the user would become confused. + +The anchor is dismissed, too, when the toplevel widget is removed +again. + +\todo Currently, anchors only define vertical positions. + +<h3>Scrolling</h3> + +To scroll to a given position, use the method +dw::core::Layout::scrollTo. It expects several parameters: + +<ul> +<li>a horizontal adjustment parameter, defined by dw::core::HPosition, +<li>a vertical adjustment parameter, defined by dw::core::VPosition, and +<li>a rectangle (\em x, \em y, \em width and \em heigh) of the region + to be adjusted. +</ul> + +If you just want to move the canvas coordinate (\em x, \em y) into the +upper left corner of the viewport, you can call: + +\code +dw::core::Layout *layout; +// ... +layout->scrollTo(dw::core::HPOS_LEFT, dw::core::VPOS_TOP, 0, 0, 0, 0); +\endcode + +By using dw::core::HPOS_NO_CHANGE or dw::core::VPOS_NO_CHANGE, you can +change only one dimension. dw::core::HPOS_INTO_VIEW and +dw::core::VPOS_INTO_VIEW will cause the viewport to move as much as +necessary, that the region is visible in the viewport (this is +e.g. used for finding text). + + +<h2>Further Documentations</h2> + +<ul> +<li> dw::core::style +<li> dw::core::ui +<li> \ref dw-images-and-backgrounds +</ul> + +*/ diff --git a/doc/dw-widget-sizes.doc b/doc/dw-widget-sizes.doc new file mode 100644 index 00000000..989eb83c --- /dev/null +++ b/doc/dw-widget-sizes.doc @@ -0,0 +1,186 @@ +/** \page dw-widget-sizes Sizes of Dillo Widgets + +<h2>Allocation</h2> + +Each widget has an \em allocation at a given time, this includes + +<ul> +<li> the position (\em x, \em y) relative to the upper left corner of the + canvas, and +<li> the size (\em width, \em ascent, \em descent). +</ul> + +The \em canvas is the whole area available for the widgets, in most +cases, only a part is seen in a viewport. The allocation of the toplevel widget is exactly the allocation of the canvas, i.e. + +<ul> +<li> the position of the toplevel widget is always (0, 0), and +<li> the canvas size is defined by the size of the toplevel widget. +</ul> + +The size of a widget is not simply defined by the width and the +height, instead, widgets may have a base line, and so are vertically +divided into an ascender (which height is called \em ascent), and a +descender (which height is called \em descent). The total height is so +the sum of \em ascent and \em descent. + +Sizes of zero are allowed. The upper limit for the size of a widget is +defined by the limits of the C++ type \em int. + +\image html dw-size-of-widget.png Allocation of a Widget + +In the example in the image, the widget has the following allocation: + +<ul> +<li>\em x = 50 +<li>\em y = 50 +<li>\em width = 150 +<li>\em ascent = 150 +<li>\em descent = 100 +</ul> + +The current allocation of a widget is hold in +dw::core::Widget::allocation. It can be set from outside by +callcalling dw::core::Widget::sizeAllocate. This is a concrete method, +which will call dw::core::Widget::sizeAllocateImpl (see code of +dw::core::Widget::sizeAllocate for details). + +For trivial widgets (like dw::Bullet), +dw::core::Widget::sizeAllocateImpl does not need to be +implemented. For more complex widgets, the implementation should call +dw::core::Widget::sizeAllocate (not +dw::core::Widget::sizeAllocateImpl) on all child widgets, with +appropriate child allocations. dw::core::Widget::allocation should not +be changed here, this is already done in +dw::core::Widget::sizeAllocate. + +<h2>Requisitions</h2> + +A widget may prefer a given size for the allocation. This size, the +\em requisition, should be returned by the method +dw::core::Widget::sizeRequestImpl. In the simplest case, this is +independent of the context, e.g. for an +image. dw::Image::sizeRequestImpl returns the following size: + +<ul> +<li> If no buffer has yet been assigned (see dw::Image for more details), + the size necessary for the alternative text is returned. If no + alternative text has been set, zero is returned. + +<li> If a buffer has been assigned (by dw::Image::setBuffer), the root + size is returned (i.e. the original size of the image to display). +</ul> + +This is a bit simplified, dw::Image::sizeRequestImpl should also deal +with margins, borders and paddings, see dw::core::style. + +From the outside, dw::Image::sizeRequest should be called, which does +a bit of optimization. Notice that in dw::Image::sizeRequestImpl, no +optimization like lazy evaluation is necessary, this is already done +in dw::Image::sizeRequest. + +A widget, which has children, will likely call dw::Image::sizeRequest +on its children, to calculate the total requisition. + +The caller (this is either the dw::core::Layout, or the parent +widget), may, but also may not consider the requisition. Instead, a +widget must deal with any allocation. (For example, dw::Image scales +the image buffer when allocated at another size.) + +<h2>Size Hints</h2> + +Some widgets do not have an inherent size, but depend on the context, +e.g. the viewport size. These widgets should adhere to <i>size hints</i>, +i.e. implement the methods dw::core::Widget::setWidth, +dw::core::Widget::setAscent and dw::core::Widget::setDescent. The values +passed to the calles are + +<ul> +<li> the viewport size (ascent is the heigt here, while descent is 0) for + the toplevel widget, and +<li> determined by the parent for its child widgets. +</ul> + +Generally, the values should define the available space for the +widget. + +A widget, which depends on size hints, should call +dw::core::Widget::queueResize, when apropriate. + +\todo There should be a definition of "available space". + +<h2>Width Extremes</h2> + +dw::Table uses width extremes for fast calculation of column +widths. The structure dw::core::Extremes represents the minimal and +maximal width of a widget, as defined by: + +<ul> +<li> the minimal width is the smallest width, at which a widget can still + display contents, and +<li> the maximal width is the largest width, above which increasing the width + does not make any sense. +</ul> + +Especially the latter is vaguely defined, here are some examples: + +<ul> +<li> For those widgets, which do not depend on size hints, the minimal and + the maximal width is the inherent width (the one returned by + dw::core::Widget::sizeRequest). + +<li> For a textblock, the minimal width is the width of the widest + (unbreakable) word, the maximal width is the width of the total + paragraph (stretching a paragraph further would only waste space). + Actually, the implementation of dw::Textblock::getExtremesImpl is + a bit more complex. + +<li> dw::Table is an example, where the width extremes are calculated + from the width extremes of the children. +</ul> + +Handling width extremes is similar to handling requisitions, a widget +must implement dw::core::Widget::getExtremesImpl, but a caller will +use dw::core::Widget::getExtremes. + + +<h2>Resizing</h2> + +When the widget changes its size (requisition), it should call +dw::core::Widget::queueResize. The next call of +dw::core::Widget::sizeRequestImpl should then return the new +size. See dw::Image::setBuffer as an example. + +Interna are described in the code of dw::core::Widget::queueResize. + +<h3>Incremental Resizing</h3> + +A widget may calculate its size based on size calculations already +done before. In this case, a widget must exactly know the reasons, why +a call of dw::core::Widget::sizeRequestImpl is necessary. To make use +of this, a widget must implement the following: + +<ol> +<li> There is a member dw::core::Widget::parentRef, which is + totally under control of the parent widget (and so sometimes not + used at all). It is necessary to define how parentRef is used + by a specific parent widget, and it has to be set to the correct + value whenever necessary. + +<li> The widget must implement dw::core::Widget::markSizeChange and + dw::core::Widget::markExtremesChange, these methods are called in + two cases: + + <ol> + <li> directly after dw::core::Widget::queueResize, with the argument + ref was passed to dw::core::Widget::queueResize, and + <li> if a child widget has called dw::core::Widget::queueResize, + with the value of the parent_ref member of this child. + </ol> +</ol> + +This way, a widget can exactly keep track on size changes, and so +implement resizing in a faster way. A good example on how to use this +is dw::Textblock. + +*/
\ No newline at end of file diff --git a/doc/fltk-problems.doc b/doc/fltk-problems.doc new file mode 100644 index 00000000..3e8c401f --- /dev/null +++ b/doc/fltk-problems.doc @@ -0,0 +1,219 @@ +/** \page fltk-problems Problems with FLTK + +<h2>dw::fltk::FltkViewport</h2> + +Current problems: + +<ul> +<li> dw::fltk::FltkViewport::draw should only draw the region, for which e.g. + an expose event was received. + +<li> dw::fltk::FltkViewport::queueDraw will collect data, which has to be + redrawn. Currently, it calls redraw (DAMAGE_EXPOSE), can this be changed, + so that dw::fltk::FltkViewport::draw will distinguish between the two + cases? + +<li> For Scrolling, something similar applies, only parts of the viewport + have to be redrawn. + +<li> Also for Scrolling, it is necessary to copy parts of the window. + +<li> How should dw::fltk::FltkViewport::cancelQueueDraw be implemented? + +<li> If the value of a scrollbar is changed by the program, not the user, + the callback seems not to be called. Can this be assured? + +<li> The same for dw::fltk::FltkViewport::layout? + +<li> Also, the problems with the widgets seems to work. Also sure? + +<li> When drawing, clipping of 32 bit values seems to work. + +<li> Who is responsable for clearing before drawing? + +<li> The embedded buttons are not redrawn, when pressing the mouse button + on them. + +<li> The item group within a selection widget (menu) should not be selectable. +</ul> + + +<h2>dw::fltk::FltkPlatform</h2> + +<ul> +<li> There is the problem, that fltk::font always returns a font, the + required one, or a replacements. The latter is not wanted in all + cases, e.g. when several fonts are tested. Perhaps, this could be + solved by searching in the font list. + +<li> In dw::fltk::FltkFont::FltkFont, fltk::measure does not seem to work + for the calculation of dw::core::style::Font::xHeight. + +<li> Distinction between italics and oblique would be nice + (dw::fltk::FltkFont::FltkFont). +</ul> + + +<h2>dw::fltk::ui::FltkCheckButtonResource</h2> + +Groups of fltk::RadioButton must be added to one fltk::Group, which is +not possible in this context. There are two alternatives: + +<ol> +<li>there is a more flexible way to group radio buttons, or +<li>radio buttons are not grouped, instead, grouping (especially + unchecking other buttons) is done by the application. +</ol> + +(This is mostly solved.) + +<h2>dw::fltk::FltkImgbuf</h2> + +Alpha transparency should be best abstracted by FLTK itself. If not, +perhaps different implementations for different window systems could +be used. Then, it is for X necessary to use GCs with clipping masks. + + +<h2>Lower Priority</h2> + +There needs to be an XEmbed implementation. + + +<h2>dw::fltk::ui::ComplexButton</h2> + +Unfortunately, FLTK does not provide a button with Group as parent, so +that children may be added to the button. dw::fltk::ui::ComplexButton does +exactly this, and is, in an ugly way, a modified copy of the FLTK +button. + +It would be nice, if this is merged with the standard FLTK +button. Furthermore, setting the type is strange. + +If the files do not compile, it may be useful to create a new one from +the FLTK source: + +<ol> +<li> Copy fltk/Button.h from FLTK to dw/fltkcomplexbutton.hh and + src/Button.cxx to dw/fltkcomplexbutton.cc. + +<li> In both files, rename "Button" to "ComplexButton". Automatic replacing + should work. + +<li> Apply the changes below. +</ol> + +The following changes should be applied manually. + +<h3>Changes in fltkcomplexbutton.hh</h3> + +First of all, the #define's for avoiding multiple includes: + +\code +-#ifndef fltk_ComplexButton_h // fltk_Button_h formerly +-#define fltk_ComplexButton_h ++#ifndef __FLTK_COMPLEX_BUTTON_HH__ ++#define __FLTK_COMPLEX_BUTTON_HH__ +\endcode + +at the beginning and + +\code +-#endif ++#endif // __FLTK_COMPLEX_BUTTON_HH__ +\endcode + +at the end. Then, the namespace is changed: + +\code +-namespace fltk { ++namespace dw { ++namespace fltk { ++namespace ui { +\endcode + +at the beginning and + +\code +-} ++} // namespace ui ++} // namespace fltk ++} // namespace dw +\endcode + +at the end. Most important, the base class is changed: + +\code +-#ifndef fltk_Widget_h +-#include "Widget.h" +-#endif ++#include <fltk/Group.h> +\endcode + +and + +\code +-class FL_API ComplexButton : public Widget { ++class ComplexButton: public ::fltk::Group ++{ +\endcode + +Finally, for dw::fltk::ui::ComplexButton::default_style, there is a +namespace conflict: + +\code +- static NamedStyle* default_style; ++ static ::fltk::NamedStyle* default_style; +\endcode + +<h3>Changes in fltkcomplexbutton.cc</h3> + +First, #include's: + +\code + + #include <fltk/events.h> + #include <fltk/damage.h> +-#include <fltk/ComplexButton.h> // <fltk/Button.h> formerly + #include <fltk/Group.h> + #include <fltk/Box.h> + #include <stdlib.h> ++ ++#include "fltkcomplexbutton.hh" +\endcode + +Second, namespaces: + +\code ++using namespace dw::fltk::ui; + using namespace fltk; +\endcode + +Since the base class is now Group, the constructor must be changed: + +\code +-ComplexButton::ComplexButton(int x,int y,int w,int h, const char *l) : Widget(x,y,w,h,l) { ++ComplexButton::ComplexButton(int x,int y,int w,int h, const char *l) : ++ Group(x,y,w,h,l) ++{ +\endcode + +At the end of the constructor, + +\code ++ type (NORMAL); + } +\endcode + +must be added (I've forgotten, what this is for). + +Finally, the button must draw its children (end of +dw::fltk::ui::ComplexButton::draw()): + +\code ++ ++ for (int i = 0; i < children (); i++) ++ draw_child (*child (i)); + } +\endcode + +*/
\ No newline at end of file diff --git a/doc/index.doc b/doc/index.doc new file mode 100644 index 00000000..9892f177 --- /dev/null +++ b/doc/index.doc @@ -0,0 +1,48 @@ +/** \mainpage + +<h2>Overview</h2> + +This is a list of documents to start with: + +<ul> +<li> \ref lout +<li> \ref dw-overview (map at \ref dw-map) +</ul> + +Currently, a document \ref fltk-problems is maintained, ideally, it +will be removed soon. + +<h2>Historical</h2> + +<h3>Replacements for GTK+ and GLib</h3> + +There are several classes etc., which are used for tasks formerly (in the GTK+ +version of dillo) achieved by GtkObject (in 1.2.x, this is part of Gtk+) and +GLib. For an overview on all this, take a look at \ref lout. + +GtkObject is replaced by the following: + +<ul> +<li> object::Object is a common base class for many classes used dillo. In + the namespace ::object, there are also some more common classes and + interfaces. + +<li> A sub class of object::Object is identity::IdentifiableObject, which + allows to determine the class at run-time (equivalent to GTK_CHECK_CAST + in GtkObject). + +<li> For signals, there is the namespace ::signal. +</ul> + +Hash tables, linked lists etc. can be found in the ::container namespace, +several useful macros from GLib have been implemented as inline functions +in the ::misc namespace. + +As an alternative to the macros defined in list.h, there is also a template +class, misc::SimpleVector, which does the same. + +<h3>Changes in Dw</h3> + +If you have been familiar with Dw before, take a look at \ref dw-changes. + +*/ diff --git a/doc/lout.doc b/doc/lout.doc new file mode 100644 index 00000000..0d5be679 --- /dev/null +++ b/doc/lout.doc @@ -0,0 +1,94 @@ +/** \page lout Lots of Useful Tools + +In the "lout" directory, there are some common base functionality for +C++. Most is described as doxygen comments, this text gives an +overview. + +<h2>Common Base Class</h2> + +Many classes are derived from object::Object, which defines some +general methods. See there for more information. + +For the case, that you need primitive C++ types, there are some +wrappers: + +<table> +<tr><th>C++ Type <th>Wrapper Class +<tr><td>void* <td>object::Pointer +<tr><td>specific pointer <td>object::TypedPointer (template class) +<tr><td>int <td>object::Integer +<tr><td>const char* <td>object::ConstString +<tr><td>char* <td>object::String +</table> + + +<h2>Containers</h2> + +In the namespace ::container, several container classes are defined, +which all deal with instances of object::Object. + +<h3>Untyped Containers</h3> + +In container::untyped, there are the following containers: + +<ul> +<li>container::untyped::Vector, a dynamically increases array, +<li>container::untyped::List, a linked list, +<li>container::untyped::HashTable, a hash table, and +<li>container::untyped::Stack, a stack. +</ul> + +All provide specific methods, but since they have a common base class, +container::untyped::Collection, they all provide iterators, by the +method container::untyped::Collection::iterator. + +<h3>Typed Containers</h3> + +container::typed provides wrappers for the container classes defined +in container::untyped, which are more type safe, by using C++ +templates. + + +<h2>Signals</h2> + +For how to connect objects at run-time (to reduce dependencies), take a +look at the ::signal namespace. + +There is also a base class signal::ObservedObject, which implements +signals for deletion. + + +<h2>Debugging</h2> + +In debug.hh, there are some some useful macros for debugging messages, +see the file for mor informations. + + +<h2>Identifying Classes at Runtime</h2> + +If the class of an object must be identified at runtime, +identity::IdentifiableObject should be used as the base class, see +there for more details. + + +<h2>Miscellaneous</h2> + +The ::misc namespace provides several miscellaneous stuff: + +<ul> +<li> In some contexts, it is necessary to compare objects + (less/greater), for this, also misc::Comparable must be + implemented. For example., container::untyped::Vector::sort and + container::typed::Vector::sort cast the elements to + misc::Comparable. This can be mixed with object::Object. +<li> misc::SimpleVector, a simple, template based vector class (not + depending on object::Object), +<li> misc::StringBuffer, class for fast concatenation of a large number + of strings, +<li> misc::BitSet implements a bitset. +<li> useful (template) functions (misc::min, misc::max), and +<li> some functions useful for runtime checks (misc::assert, + misc::assertNotReached). +</ul> + +*/ diff --git a/doc/rounding-errors.doc b/doc/rounding-errors.doc new file mode 100644 index 00000000..433d6ed9 --- /dev/null +++ b/doc/rounding-errors.doc @@ -0,0 +1,24 @@ +/** \page rounding-errors How to Avoid Rounding Errors + +(Probably, this is a standard algorithm, so if someone knows the name, +drop me a note.) + +If something like + +\f[y_i = {x_i a \over b}\f] + +is to be calculated, and all numbers are integers, a naive +implementation would result in something, for which + +\f[\sum y_i \ne {(\sum x_i) a \over b}\f] + +because of rounding errors, due to the integer division. This can be +avoided by transforming the formula into + +\f[y_i = {(\sum_{j=0}^{j=i} x_j) a \over b} - \sum_{j=0}^{j=i} y_j\f] + +Of corse, when all \f$y_i\f$ are calculated in a sequence, +\f$\sum_{j=0}^{j=i} x_j\f$ and \f$\sum_{j=0}^{j=i} y_j\f$ can be +accumulated in the same loop. + +*/
\ No newline at end of file diff --git a/doc/uml-legend.doc b/doc/uml-legend.doc new file mode 100644 index 00000000..14a64e7d --- /dev/null +++ b/doc/uml-legend.doc @@ -0,0 +1,192 @@ +/** \page uml-legend UML Legend + +This page describes the notation for several diagrams used in the +documentation, which is a slight variation of UML. + + +<h2>Classes</h2> + +Classes are represented by boxes, containing there names: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + fontname=Helvetica; fontsize=8; + "Concrete Class"; + "Abstract Class" [color="#a0a0a0"]; + Interface [color="#ff8080"]; +} +\enddot + +(In most cases, the attributes and operations are left away, for +better readibility. Just click on it, to get to the detailed +description.) + +Of course, in C++, there are no interfaces, but here, we call a class, +which has only virtual abstract methods, and so does not provide any +functionality, an interface. + +Templates get a yellow background color: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10, + fillcolor="#ffffc0", style="filled"]; + fontname=Helvetica; fontsize=8; + "Concrete Class Template"; + "Abstract Class Template" [color="#a0a0a0"]; + "Interface Template" [color="#ff8080"]; +} +\enddot + + +<h2>Objects</h2> + +In some cases, an examle for a concrete constellation of objects is +shown. An object is represented by a box containing a name and the +class, separated by a colon. + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", labelfontname=Helvetica, labelfontsize=10, + color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + "x: A" -> "y1: B"; + "x: A" -> "y2: B"; +} +\enddot + +The names (\em x, \em y, and \em z) are only meant within the context +of the diagram, there needs not to be a relation to the actual names +in the program. They should be unique within the diagram. + +Classes and objects may be mixed in one diagram. + + +<h2>Associations</h2> + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="open", labelfontname=Helvetica, labelfontsize=10, + color="#404040", labelfontcolor="#000080", + fontname=Helvetica, fontsize=10, fontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + A -> B [headlabel="*", taillabel="1", label="x"]; +} +\enddot + +In this example, one instance of A refers to an arbitrary number of B +instances (denoted by the "*"), and each instance of B is referred by +exactly one ("1") A. The label \em x is the name of the association, +in most cases the name of the field, e.g. A::x. + +Possible other values for the \em multiplicity: + +<ul> +<li> a concrete number, in most cases "1", +<li> a range, e.g. "0..1", +<li> "*", denoting an arbitrary number. +</ul> + + +<h2>Implementations and Inheritance</h2> + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica, + labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + A[color="#ff8080"]; + B[color="#ff8080"]; + C; + D; + A -> B; + A -> C [style="dashed"]; + C -> D; +} +\enddot + +In this example, + +<ul> +<li> the interface B extends the interface A, +<li> the class C implements the interface A, and +<li> the class D extends the class C. +</ul> + + +<h2>Template Instanciations</h2> + +Template instanciations are shown as own classes/interfaces, the +instanciation by the template is shown by a yellow dashed arrow: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica, + labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + A[color="#ff8080"]; + B[color="#ff8080"]; + C[color="#ff8080", fillcolor="#ffffc0", style="filled"]; + C_A[color="#ff8080", label="C \<A\>"]; + C_B[color="#ff8080", label="C \<A\>"]; + D; + + C -> C_A [arrowhead="open", arrowtail="none", style="dashed", + color="#808000"]; + C -> C_B [arrowhead="open", arrowtail="none", style="dashed", + color="#808000"]; + A -> C_A; + B -> C_B; + C_A -> D [style="dashed"]; +} +\enddot + +In this example, the interface template C uses the template argument +as super interface. + + +<h2>Packages</h2> + +Packages are presented by dashed rectangles: + +\dot +digraph G { + node [shape=record, fontname=Helvetica, fontsize=10]; + edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica, + labelfontsize=10, color="#404040", labelfontcolor="#000080"]; + fontname=Helvetica; fontsize=10; + + subgraph cluster_1 { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="package 1"; + + A; + B [color="#a0a0a0"]; + } + + subgraph cluster_2 { + style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10; + label="package 2"; + + C; + D [color="#a0a0a0"]; + E + } + + A -> C; + B -> D; + D -> E; + E -> A [arrowhead="open", arrowtail="none"]; +} +\enddot + +Packages may be nested. + +*/
\ No newline at end of file |