aboutsummaryrefslogtreecommitdiff
path: root/dw
diff options
context:
space:
mode:
Diffstat (limited to 'dw')
-rw-r--r--dw/Makefile.am2
-rw-r--r--dw/alignedtextblock.cc2
-rw-r--r--dw/core.hh1
-rw-r--r--dw/findtext.cc3
-rw-r--r--dw/fltkflatview.cc2
-rw-r--r--dw/fltkimgbuf.cc67
-rw-r--r--dw/fltkimgbuf.hh3
-rw-r--r--dw/fltkplatform.cc4
-rw-r--r--dw/fltkviewport.cc3
-rw-r--r--dw/image.cc12
-rw-r--r--dw/image.hh5
-rw-r--r--dw/imgbuf.hh13
-rw-r--r--dw/imgrenderer.cc48
-rw-r--r--dw/imgrenderer.hh87
-rw-r--r--dw/layout.cc128
-rw-r--r--dw/layout.hh31
-rw-r--r--dw/listitem.cc2
-rw-r--r--dw/selection.cc3
-rw-r--r--dw/style.cc465
-rw-r--r--dw/style.hh158
-rw-r--r--dw/table.cc2
-rw-r--r--dw/tablecell.cc2
-rw-r--r--dw/textblock.cc199
-rw-r--r--dw/textblock.hh52
-rw-r--r--dw/textblock_linebreaking.cc17
-rw-r--r--dw/ui.cc2
-rw-r--r--dw/widget.cc163
-rw-r--r--dw/widget.hh24
28 files changed, 1390 insertions, 110 deletions
diff --git a/dw/Makefile.am b/dw/Makefile.am
index aa5c88c3..47ec5275 100644
--- a/dw/Makefile.am
+++ b/dw/Makefile.am
@@ -14,6 +14,8 @@ libDw_core_a_SOURCES = \
findtext.cc \
findtext.hh \
imgbuf.hh \
+ imgrenderer.hh \
+ imgrenderer.cc \
iterator.cc \
iterator.hh \
layout.cc \
diff --git a/dw/alignedtextblock.cc b/dw/alignedtextblock.cc
index dde408b2..0d910c93 100644
--- a/dw/alignedtextblock.cc
+++ b/dw/alignedtextblock.cc
@@ -20,6 +20,7 @@
#include "alignedtextblock.hh"
+#include "../lout/debug.hh"
#include <stdio.h>
namespace dw {
@@ -62,6 +63,7 @@ int AlignedTextblock::CLASS_ID = -1;
AlignedTextblock::AlignedTextblock (bool limitTextWidth):
Textblock (limitTextWidth)
{
+ DBG_OBJ_CREATE ("dw::AlignedTextblock");
registerName ("dw::AlignedTextblock", &CLASS_ID);
}
diff --git a/dw/core.hh b/dw/core.hh
index f39c38cc..022574b1 100644
--- a/dw/core.hh
+++ b/dw/core.hh
@@ -44,6 +44,7 @@ class ResourceFactory;
#include "types.hh"
#include "events.hh"
#include "imgbuf.hh"
+#include "imgrenderer.hh"
#include "style.hh"
#include "view.hh"
#include "platform.hh"
diff --git a/dw/findtext.cc b/dw/findtext.cc
index 19485078..e86116f1 100644
--- a/dw/findtext.cc
+++ b/dw/findtext.cc
@@ -20,6 +20,7 @@
#include "core.hh"
+#include "../lout/debug.hh"
#include "../lout/msg.h"
namespace dw {
@@ -27,6 +28,8 @@ namespace core {
FindtextState::FindtextState ()
{
+ DBG_OBJ_CREATE ("dw::core::FindtextState");
+
key = NULL;
nexttab = NULL;
widget = NULL;
diff --git a/dw/fltkflatview.cc b/dw/fltkflatview.cc
index b9e85d99..d40c59e5 100644
--- a/dw/fltkflatview.cc
+++ b/dw/fltkflatview.cc
@@ -20,6 +20,7 @@
#include "fltkflatview.hh"
+#include "../lout/debug.hh"
#include <stdio.h>
@@ -31,6 +32,7 @@ namespace fltk {
FltkFlatView::FltkFlatView (int x, int y, int w, int h, const char *label):
FltkWidgetView (x, y, w, h, label)
{
+ DBG_OBJ_CREATE ("dw::fltk::FltkFlatView");
}
FltkFlatView::~FltkFlatView ()
diff --git a/dw/fltkimgbuf.cc b/dw/fltkimgbuf.cc
index 81d2dc2d..d9d653ec 100644
--- a/dw/fltkimgbuf.cc
+++ b/dw/fltkimgbuf.cc
@@ -143,7 +143,7 @@ void FltkImgbuf::init (Type type, int width, int height, double gamma,
scaledBuffers = new lout::container::typed::List <FltkImgbuf> (true);
else
scaledBuffers = NULL;
-
+
if (!isRoot()) {
// Scaling
for (int row = 0; row < root->height; row++) {
@@ -228,31 +228,33 @@ inline void FltkImgbuf::scaleRowBeautiful (int row, const core::byte *data)
{
int sr1 = scaledY (row);
int sr2 = scaledY (row + 1);
+ bool allRootRows = false;
- for (int sr = sr1; sr < sr2; sr++)
- copiedRows->set (sr, true);
+ // Don't rescale rows!
+ if (copiedRows->get(sr1)) return;
- if (height > root->height)
+ if (height > root->height) {
scaleBuffer (data, root->width, 1,
rawdata + sr1 * width * bpp, width, sr2 - sr1,
bpp, gamma);
- else {
- assert (sr1 ==sr2 || sr1 + 1 == sr2);
+ // Mark scaled rows done
+ for (int sr = sr1; sr < sr2 || sr == sr1; sr++)
+ copiedRows->set (sr, true);
+ } else {
+ assert (sr1 == sr2 || sr1 + 1 == sr2);
int row1 = backscaledY(sr1), row2 = backscaledY(sr1 + 1);
- // Draw only when all original lines are retrieved (speed).
- bool allRootRows = true;
- for (int r = row1; allRootRows && r < row2; r++)
- allRootRows = allRootRows && root->copiedRows->get(r);
-
- if (allRootRows)
- // We have to access root->rawdata (which has to be up to
- // date), since a larger area than the single row is accessed
- // here.
+ // Check all the necessary root lines already arrived,
+ // a larger area than a single row may be accessed here.
+ for (int r=row1; (allRootRows=root->copiedRows->get(r)) && ++r < row2; );
+ if (allRootRows) {
scaleBuffer (root->rawdata + row1 * root->width * bpp,
root->width, row2 - row1,
rawdata + sr1 * width * bpp, width, 1,
bpp, gamma);
+ // Mark scaled row done
+ copiedRows->set (sr1, true);
+ }
}
}
@@ -295,7 +297,7 @@ inline void FltkImgbuf::scaleBuffer (const core::byte *src, int srcWidth,
int yo1 = y * srcHeight / destHeight;
int yo2 = lout::misc::max ((y + 1) * srcHeight / destHeight, yo1 + 1);
int n = (xo2 - xo1) * (yo2 - yo1);
-
+
int v[bpp];
for(int i = 0; i < bpp; i++)
v[i] = 0;
@@ -328,7 +330,7 @@ void FltkImgbuf::copyRow (int row, const core::byte *data)
for (Iterator <FltkImgbuf> it = scaledBuffers->iterator();
it.hasNext(); ) {
FltkImgbuf *sb = it.getNext ();
- sb->scaleRow(row, data);
+ sb->scaleRow (row, data);
}
}
}
@@ -427,6 +429,37 @@ int FltkImgbuf::getRootHeight ()
return root ? root->height : height;
}
+core::Imgbuf *FltkImgbuf::createSimilarBuf (int width, int height)
+{
+ return new FltkImgbuf (type, width, height, gamma);
+}
+
+void FltkImgbuf::copyTo (Imgbuf *dest, int xDestRoot, int yDestRoot,
+ int xSrc, int ySrc, int widthSrc, int heightSrc)
+{
+ FltkImgbuf *fDest = (FltkImgbuf*)dest;
+ assert (bpp == fDest->bpp);
+
+ int xSrc2 = lout::misc::min (xSrc + widthSrc, fDest->width - xDestRoot);
+ int ySrc2 = lout::misc::min (ySrc + heightSrc, fDest->height - yDestRoot);
+
+ //printf ("copying from (%d, %d), %d x %d to (%d, %d) (root) => "
+ // "xSrc2 = %d, ySrc2 = %d\n",
+ // xSrc, ySrc, widthSrc, heightSrc, xDestRoot, yDestRoot,
+ // xSrc2, ySrc2);
+
+ for (int x = xSrc; x < xSrc2; x++)
+ for (int y = ySrc; y < ySrc2; y++) {
+ int iSrc = x + width * y;
+ int iDest = xDestRoot + x + fDest->width * (yDestRoot + y);
+
+ //printf (" (%d, %d): %d -> %d\n", x, y, iSrc, iDest);
+
+ for (int b = 0; b < bpp; b++)
+ fDest->rawdata[bpp * iDest + b] = rawdata[bpp * iSrc + b];
+ }
+}
+
void FltkImgbuf::ref ()
{
refCount++;
diff --git a/dw/fltkimgbuf.hh b/dw/fltkimgbuf.hh
index ee5ae922..0b8b5549 100644
--- a/dw/fltkimgbuf.hh
+++ b/dw/fltkimgbuf.hh
@@ -73,6 +73,9 @@ public:
void getRowArea (int row, dw::core::Rectangle *area);
int getRootWidth ();
int getRootHeight ();
+ core::Imgbuf *createSimilarBuf (int width, int height);
+ void copyTo (Imgbuf *dest, int xDestRoot, int yDestRoot,
+ int xSrc, int ySrc, int widthSrc, int heightSrc);
void ref ();
void unref ();
diff --git a/dw/fltkplatform.cc b/dw/fltkplatform.cc
index 1d77e289..2a160d63 100644
--- a/dw/fltkplatform.cc
+++ b/dw/fltkplatform.cc
@@ -20,6 +20,7 @@
#include <stdio.h>
#include "../lout/msg.h"
+#include "../lout/debug.hh"
#include "fltkcore.hh"
#include <FL/fl_draw.H>
@@ -454,6 +455,8 @@ core::ui::RadioButtonResource
FltkPlatform::FltkPlatform ()
{
+ DBG_OBJ_CREATE ("dw::fltk::FltkPlatform");
+
layout = NULL;
idleQueue = new container::typed::List <IdleFunc> (true);
idleFuncRunning = false;
@@ -476,6 +479,7 @@ FltkPlatform::~FltkPlatform ()
void FltkPlatform::setLayout (core::Layout *layout)
{
this->layout = layout;
+ DBG_OBJ_ASSOC_CHILD (layout);
}
diff --git a/dw/fltkviewport.cc b/dw/fltkviewport.cc
index de4c8f94..7e91a83a 100644
--- a/dw/fltkviewport.cc
+++ b/dw/fltkviewport.cc
@@ -27,6 +27,7 @@
#include <stdio.h>
#include "../lout/msg.h"
+#include "../lout/debug.hh"
using namespace lout;
using namespace lout::object;
@@ -53,6 +54,8 @@ public:
FltkViewport::FltkViewport (int X, int Y, int W, int H, const char *label):
FltkWidgetView (X, Y, W, H, label)
{
+ DBG_OBJ_CREATE ("dw::fltk::FltkViewport");
+
hscrollbar = new CustScrollbar (x (), y (), 1, 1);
hscrollbar->type(FL_HORIZONTAL);
hscrollbar->callback (hscrollbarCallback, this);
diff --git a/dw/image.cc b/dw/image.cc
index 1cb9ce39..3aef42ac 100644
--- a/dw/image.cc
+++ b/dw/image.cc
@@ -22,6 +22,7 @@
#include "image.hh"
#include "../lout/msg.h"
#include "../lout/misc.hh"
+#include "../lout/debug.hh"
namespace dw {
@@ -143,6 +144,7 @@ int Image::CLASS_ID = -1;
Image::Image(const char *altText)
{
+ DBG_OBJ_CREATE ("dw::Image");
registerName ("dw::Image", &CLASS_ID);
this->altText = altText ? strdup (altText) : NULL;
altTextWidth = -1; // not yet calculated
@@ -450,6 +452,16 @@ void Image::drawRow (int row)
area.width, area.height);
}
+void Image::finish ()
+{
+ // Nothing to do; images are always drawn line by line.
+}
+
+void Image::fatal ()
+{
+ // Could display an error.
+}
+
/**
* \brief Sets image as server side image map.
diff --git a/dw/image.hh b/dw/image.hh
index a8314d4f..a712936e 100644
--- a/dw/image.hh
+++ b/dw/image.hh
@@ -116,7 +116,7 @@ public:
*
* \sa\ref dw-images-and-backgrounds
*/
-class Image: public core::Widget
+class Image: public core::Widget, public core::ImgRenderer
{
private:
char *altText;
@@ -157,6 +157,9 @@ public:
void drawRow (int row);
+ void finish ();
+ void fatal ();
+
void setIsMap ();
void setUseMap (ImageMapsList *list, Object *key);
diff --git a/dw/imgbuf.hh b/dw/imgbuf.hh
index 02ba9087..3ccbe3c5 100644
--- a/dw/imgbuf.hh
+++ b/dw/imgbuf.hh
@@ -178,6 +178,19 @@ public:
virtual int getRootWidth () = 0;
virtual int getRootHeight () = 0;
+
+ /**
+ * Creates an image buffer with same parameters (type, gamma etc.)
+ * except size.
+ */
+ virtual Imgbuf *createSimilarBuf (int width, int height) = 0;
+
+ /**
+ * Copies another image buffer into this image buffer.
+ */
+ virtual void copyTo (Imgbuf *dest, int xDestRoot, int yDestRoot,
+ int xSrc, int ySrc, int widthSrc, int heightSrc) = 0;
+
/*
* Reference counting.
*/
diff --git a/dw/imgrenderer.cc b/dw/imgrenderer.cc
new file mode 100644
index 00000000..285a8dcd
--- /dev/null
+++ b/dw/imgrenderer.cc
@@ -0,0 +1,48 @@
+#include "core.hh"
+
+namespace dw {
+namespace core {
+
+using namespace lout::container;
+using namespace lout::object;
+
+void ImgRendererDist::setBuffer (core::Imgbuf *buffer, bool resize)
+{
+ for (typed::Iterator <TypedPointer <ImgRenderer> > it =
+ children->iterator (); it.hasNext (); ) {
+ TypedPointer <ImgRenderer> *tp = it.getNext ();
+ tp->getTypedValue()->setBuffer (buffer, resize);
+ }
+}
+
+void ImgRendererDist::drawRow (int row)
+{
+ for (typed::Iterator <TypedPointer <ImgRenderer> > it =
+ children->iterator (); it.hasNext (); ) {
+ TypedPointer <ImgRenderer> *tp = it.getNext ();
+ tp->getTypedValue()->drawRow (row);
+ }
+}
+
+
+void ImgRendererDist::finish ()
+{
+ for (typed::Iterator <TypedPointer <ImgRenderer> > it =
+ children->iterator (); it.hasNext (); ) {
+ TypedPointer <ImgRenderer> *tp = it.getNext ();
+ tp->getTypedValue()->finish ();
+ }
+}
+
+void ImgRendererDist::fatal ()
+{
+ for (typed::Iterator <TypedPointer <ImgRenderer> > it =
+ children->iterator (); it.hasNext (); ) {
+ TypedPointer <ImgRenderer> *tp = it.getNext ();
+ tp->getTypedValue()->fatal ();
+ }
+}
+
+
+} // namespace core
+} // namespace dw
diff --git a/dw/imgrenderer.hh b/dw/imgrenderer.hh
new file mode 100644
index 00000000..325a1998
--- /dev/null
+++ b/dw/imgrenderer.hh
@@ -0,0 +1,87 @@
+#ifndef __DW_IMGRENDERER_HH__
+#define __DW_IMGRENDERER_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief ...
+ *
+ * \sa \ref dw-images-and-backgrounds
+ */
+class ImgRenderer
+{
+public:
+ virtual ~ImgRenderer () { }
+
+ /**
+ * \brief Called, when an image buffer is attached.
+ *
+ * This is typically the case when all meta data (size, depth) has been read.
+ */
+ virtual void setBuffer (core::Imgbuf *buffer, bool resize = false) = 0;
+
+ /**
+ * \brief Called, when data from a row is available and has been copied into
+ * the image buffer.
+ *
+ * The implementation will typically queue the respective area for drawing.
+ */
+ virtual void drawRow (int row) = 0;
+
+ /**
+ * \brief Called, when all image data has been retrieved.
+ *
+ * The implementation may use this instead of "drawRow" for drawing, to
+ * limit the number of draws.
+ */
+ virtual void finish () = 0;
+
+ /**
+ * \brief Called, when there are problems with the retrieval of image data.
+ *
+ * The implementation may use this to indicate an error.
+ */
+ virtual void fatal () = 0;
+};
+
+/**
+ * \brief Implementation of ImgRenderer, which distributes all calls
+ * to a set of other implementations of ImgRenderer.
+ *
+ * The order of the call children is not defined, especially not
+ * identical to the order in which they have been added.
+ */
+class ImgRendererDist: public ImgRenderer
+{
+ lout::container::typed::HashSet <lout::object::TypedPointer <ImgRenderer> >
+ *children;
+
+public:
+ inline ImgRendererDist ()
+ { children = new lout::container::typed::HashSet
+ <lout::object::TypedPointer <ImgRenderer> > (true); }
+ ~ImgRendererDist () { delete children; }
+
+ void setBuffer (core::Imgbuf *buffer, bool resize);
+ void drawRow (int row);
+ void finish ();
+ void fatal ();
+
+ void put (ImgRenderer *child)
+ { children->put (new lout::object::TypedPointer <ImgRenderer> (child)); }
+ void remove (ImgRenderer *child)
+ { lout::object::TypedPointer <ImgRenderer> tp (child);
+ children->remove (&tp); }
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_IMGRENDERER_HH__
+
+
diff --git a/dw/layout.cc b/dw/layout.cc
index 4879bb1e..ff121250 100644
--- a/dw/layout.cc
+++ b/dw/layout.cc
@@ -32,6 +32,65 @@ using namespace lout::object;
namespace dw {
namespace core {
+bool Layout::LayoutImgRenderer::readyToDraw ()
+{
+ return true;
+}
+
+void Layout::LayoutImgRenderer::getBgArea (int *x, int *y, int *width,
+ int *height)
+{
+ // TODO Actually not padding area, but visible area?
+ getRefArea (x, y, width, height);
+}
+
+void Layout::LayoutImgRenderer::getRefArea (int *xRef, int *yRef, int *widthRef,
+ int *heightRef)
+{
+ *xRef = 0;
+ *yRef = 0;
+ *widthRef = misc::max (layout->viewportWidth
+ - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0),
+ layout->canvasWidth);
+ *heightRef = misc::max (layout->viewportHeight
+ - layout->hScrollbarThickness,
+ layout->canvasAscent + layout->canvasDescent);
+}
+
+style::StyleImage *Layout::LayoutImgRenderer::getBackgroundImage ()
+{
+ return layout->bgImage;
+}
+
+style::BackgroundRepeat Layout::LayoutImgRenderer::getBackgroundRepeat ()
+{
+ return layout->bgRepeat;
+}
+
+style::BackgroundAttachment
+ Layout::LayoutImgRenderer::getBackgroundAttachment ()
+{
+ return layout->bgAttachment;
+}
+
+style::Length Layout::LayoutImgRenderer::getBackgroundPositionX ()
+{
+ return layout->bgPositionX;
+}
+
+style::Length Layout::LayoutImgRenderer::getBackgroundPositionY ()
+{
+ return layout->bgPositionY;
+}
+
+void Layout::LayoutImgRenderer::draw (int x, int y, int width, int height)
+{
+ layout->queueDraw (x, y, width, height);
+}
+
+// ----------------------------------------------------------------------
+
void Layout::Receiver::canvasSizeChanged (int width, int ascent, int descent)
{
}
@@ -188,9 +247,10 @@ Layout::Layout (Platform *platform)
queueResizeList = new typed::Vector<Widget> (4, false);
- DBG_OBJ_CREATE (this, "DwRenderLayout");
+ DBG_OBJ_CREATE ("dw::core::Layout");
bgColor = NULL;
+ bgImage = NULL;
cursor = style::CURSOR_DEFAULT;
canvasWidth = canvasAscent = canvasDescent = 0;
@@ -212,8 +272,8 @@ Layout::Layout (Platform *platform)
textZone = new misc::ZoneAllocator (16 * 1024);
- DBG_OBJ_ASSOC (&findtextState, this);
- DBG_OBJ_ASSOC (&selectionState, this);
+ DBG_OBJ_ASSOC_CHILD (&findtextState);
+ DBG_OBJ_ASSOC_CHILD (&selectionState);
platform->setLayout (this);
@@ -221,18 +281,28 @@ Layout::Layout (Platform *platform)
queueResizeCounter = sizeAllocateCounter = sizeRequestCounter =
getExtremesCounter = 0;
+
+ layoutImgRenderer = NULL;
}
Layout::~Layout ()
{
widgetAtPoint = NULL;
+ if (layoutImgRenderer) {
+ if (bgImage)
+ bgImage->removeExternalImgRenderer (layoutImgRenderer);
+ delete layoutImgRenderer;
+ }
+
if (scrollIdleId != -1)
platform->removeIdle (scrollIdleId);
if (resizeIdleId != -1)
platform->removeIdle (resizeIdleId);
if (bgColor)
bgColor->unref ();
+ if (bgImage)
+ bgImage->unref ();
if (topLevel) {
Widget *w = topLevel;
topLevel = NULL;
@@ -297,6 +367,8 @@ void Layout::removeWidget ()
void Layout::setWidget (Widget *widget)
{
+ DBG_OBJ_ASSOC_CHILD (widget);
+
widgetAtPoint = NULL;
if (topLevel) {
Widget *w = topLevel;
@@ -320,6 +392,8 @@ void Layout::attachView (View *view)
if (this->view)
MSG_ERR("attachView: Multiple views for layout!\n");
+ DBG_OBJ_ASSOC_CHILD (view);
+
this->view = view;
platform->attachView (view);
@@ -521,6 +595,23 @@ void Layout::draw (View *view, Rectangle *area)
{
Rectangle widgetArea, intersection, widgetDrawArea;
+ // First of all, draw background image. (Unlike background *color*,
+ // this is not a feature of the views.)
+ if (bgImage != NULL && bgImage->getImgbufSrc() != NULL)
+ style::drawBackgroundImage (view, bgImage, bgRepeat, bgAttachment,
+ bgPositionX, bgPositionY,
+ area->x, area->y, area->width,
+ area->height, 0, 0,
+ // Reference area: maximum of canvas size and
+ // viewport size.
+ misc::max (viewportWidth
+ - (canvasHeightGreater ?
+ vScrollbarThickness : 0),
+ canvasWidth),
+ misc::max (viewportHeight
+ - hScrollbarThickness,
+ canvasAscent + canvasDescent));
+
if (scrollIdleId != -1) {
/* scroll is pending, defer draw until after scrollIdle() */
drawAfterScrollReq = true;
@@ -663,6 +754,37 @@ void Layout::setBgColor (style::Color *color)
view->setBgColor (bgColor);
}
+void Layout::setBgImage (style::StyleImage *bgImage,
+ style::BackgroundRepeat bgRepeat,
+ style::BackgroundAttachment bgAttachment,
+ style::Length bgPositionX, style::Length bgPositionY)
+{
+ if (layoutImgRenderer && this->bgImage)
+ this->bgImage->removeExternalImgRenderer (layoutImgRenderer);
+
+ if (bgImage)
+ bgImage->ref ();
+
+ if (this->bgImage)
+ this->bgImage->unref ();
+
+ this->bgImage = bgImage;
+ this->bgRepeat = bgRepeat;
+ this->bgAttachment = bgAttachment;
+ this->bgPositionX = bgPositionX;
+ this->bgPositionY = bgPositionY;
+
+ if (bgImage) {
+ // Create instance of LayoutImgRenderer when needed. Until this
+ // layout is deleted, "layoutImgRenderer" will be kept, since it
+ // is not specific to the style, but only to this layout.
+ if (layoutImgRenderer == NULL)
+ layoutImgRenderer = new LayoutImgRenderer (this);
+ bgImage->putExternalImgRenderer (layoutImgRenderer);
+ }
+}
+
+
void Layout::resizeIdle ()
{
enterQueueResize ();
diff --git a/dw/layout.hh b/dw/layout.hh
index 2055b751..64274714 100644
--- a/dw/layout.hh
+++ b/dw/layout.hh
@@ -17,6 +17,27 @@ class Layout: public lout::object::Object
{
friend class Widget;
+private:
+ class LayoutImgRenderer: public style::StyleImage::ExternalImgRenderer
+ {
+ Layout *layout;
+
+ public:
+ LayoutImgRenderer (Layout *layout) { this->layout = layout; }
+
+ bool readyToDraw ();
+ void getBgArea (int *x, int *y, int *width, int *height);
+ void getRefArea (int *xRef, int *yRef, int *widthRef, int *heightRef);
+ style::StyleImage *getBackgroundImage ();
+ style::BackgroundRepeat getBackgroundRepeat ();
+ style::BackgroundAttachment getBackgroundAttachment ();
+ style::Length getBackgroundPositionX ();
+ style::Length getBackgroundPositionY ();
+ void draw (int x, int y, int width, int height);
+ };
+
+ LayoutImgRenderer *layoutImgRenderer;
+
public:
/**
* \brief Receiver interface different signals.
@@ -136,6 +157,11 @@ private:
/* The state, which must be projected into the view. */
style::Color *bgColor;
+ style::StyleImage *bgImage;
+ style::BackgroundRepeat bgRepeat;
+ style::BackgroundAttachment bgAttachment;
+ style::Length bgPositionX, bgPositionY;
+
style::Cursor cursor;
int canvasWidth, canvasAscent, canvasDescent;
@@ -397,8 +423,13 @@ public:
inline void resetSearch () { findtextState.resetSearch (); }
void setBgColor (style::Color *color);
+ void setBgImage (style::StyleImage *bgImage,
+ style::BackgroundRepeat bgRepeat,
+ style::BackgroundAttachment bgAttachment,
+ style::Length bgPositionX, style::Length bgPositionY);
inline style::Color* getBgColor () { return bgColor; }
+ inline style::StyleImage* getBgImage () { return bgImage; }
};
} // namespace core
diff --git a/dw/listitem.cc b/dw/listitem.cc
index ed7a2c75..11086a9e 100644
--- a/dw/listitem.cc
+++ b/dw/listitem.cc
@@ -20,6 +20,7 @@
#include "listitem.hh"
+#include "../lout/debug.hh"
#include <stdio.h>
namespace dw {
@@ -29,6 +30,7 @@ int ListItem::CLASS_ID = -1;
ListItem::ListItem (ListItem *ref, bool limitTextWidth):
AlignedTextblock (limitTextWidth)
{
+ DBG_OBJ_CREATE ("dw::ListItem");
registerName ("dw::ListItem", &CLASS_ID);
setRefTextblock (ref);
}
diff --git a/dw/selection.cc b/dw/selection.cc
index 8b4cf318..2201af44 100644
--- a/dw/selection.cc
+++ b/dw/selection.cc
@@ -20,6 +20,7 @@
#include "core.hh"
+#include "../lout/debug.hh"
#include <string.h>
@@ -45,6 +46,8 @@ namespace core {
SelectionState::SelectionState ()
{
+ DBG_OBJ_CREATE ("dw::core::SelectionState");
+
layout = NULL;
selectionState = NONE;
diff --git a/dw/style.cc b/dw/style.cc
index 51dda098..3f39a39e 100644
--- a/dw/style.cc
+++ b/dw/style.cc
@@ -32,6 +32,27 @@ namespace dw {
namespace core {
namespace style {
+const bool drawBackgroundLineByLine = false;
+
+const int MIN_BG_IMG_W = 10;
+const int MIN_BG_IMG_H = 10;
+const int OPT_BG_IMG_W = 50;
+const int OPT_BG_IMG_H = 50;
+
+static void calcBackgroundRelatedValues (StyleImage *backgroundImage,
+ BackgroundRepeat backgroundRepeat,
+ BackgroundAttachment
+ backgroundAttachment,
+ Length backgroundPositionX,
+ Length backgroundPositionY,
+ int xDraw, int yDraw, int widthDraw,
+ int heightDraw, int xRef, int yRef,
+ int widthRef, int heightRef,
+ bool *repeatX, bool *repeatY,
+ int *origX, int *origY,
+ int *tileX1, int *tileX2, int *tileY1,
+ int *tileY2, bool *doDraw);
+
void StyleAttrs::initValues ()
{
x_link = -1;
@@ -46,6 +67,11 @@ void StyleAttrs::initValues ()
listStyleType = LIST_STYLE_TYPE_DISC;
valign = VALIGN_BASELINE;
backgroundColor = NULL;
+ backgroundImage = NULL;
+ backgroundRepeat = BACKGROUND_REPEAT;
+ backgroundAttachment = BACKGROUND_ATTACHMENT_SCROLL;
+ backgroundPositionX = createPerLength (0);
+ backgroundPositionY = createPerLength (0);
width = height = lineHeight = LENGTH_AUTO;
vloat = FLOAT_NONE;
clear = CLEAR_NONE;
@@ -83,6 +109,11 @@ void StyleAttrs::resetValues ()
top = bottom = left = right = LENGTH_AUTO; /** \todo Correct? Check
specification. */
backgroundColor = NULL;
+ backgroundImage = NULL;
+ backgroundRepeat = BACKGROUND_REPEAT;
+ backgroundAttachment = BACKGROUND_ATTACHMENT_SCROLL;
+ backgroundPositionX = createPerLength (0);
+ backgroundPositionY = createPerLength (0);
width = LENGTH_AUTO;
height = LENGTH_AUTO;
@@ -123,6 +154,11 @@ bool StyleAttrs::equals (object::Object *other) {
textDecoration == otherAttrs->textDecoration &&
color == otherAttrs->color &&
backgroundColor == otherAttrs->backgroundColor &&
+ backgroundImage == otherAttrs->backgroundImage &&
+ backgroundRepeat == otherAttrs->backgroundRepeat &&
+ backgroundAttachment == otherAttrs->backgroundAttachment &&
+ backgroundPositionX == otherAttrs->backgroundPositionX &&
+ backgroundPositionY == otherAttrs->backgroundPositionY &&
textAlign == otherAttrs->textAlign &&
valign == otherAttrs->valign &&
textAlignChar == otherAttrs->textAlignChar &&
@@ -170,6 +206,11 @@ int StyleAttrs::hashValue () {
textDecoration +
(intptr_t) color +
(intptr_t) backgroundColor +
+ (intptr_t) backgroundImage +
+ backgroundRepeat +
+ backgroundAttachment +
+ backgroundPositionX +
+ backgroundPositionY +
textAlign +
valign +
textAlignChar +
@@ -226,6 +267,8 @@ Style::Style (StyleAttrs *attrs)
color->ref ();
if (backgroundColor)
backgroundColor->ref ();
+ if (backgroundImage)
+ backgroundImage->ref ();
if (borderColor.top)
borderColor.top->ref();
if (borderColor.bottom)
@@ -248,6 +291,8 @@ Style::~Style ()
color->unref ();
if (backgroundColor)
backgroundColor->unref ();
+ if (backgroundImage)
+ backgroundImage->unref ();
if (borderColor.top)
borderColor.top->unref();
if (borderColor.bottom)
@@ -269,6 +314,11 @@ void Style::copyAttrs (StyleAttrs *attrs)
textDecoration = attrs->textDecoration;
color = attrs->color;
backgroundColor = attrs->backgroundColor;
+ backgroundImage = attrs->backgroundImage;
+ backgroundRepeat = attrs->backgroundRepeat;
+ backgroundAttachment = attrs->backgroundAttachment;
+ backgroundPositionX = attrs->backgroundPositionX;
+ backgroundPositionY = attrs->backgroundPositionY;
textAlign = attrs->textAlign;
valign = attrs->valign;
textAlignChar = attrs->textAlignChar;
@@ -450,6 +500,210 @@ Tooltip *Tooltip::create (Layout *layout, const char *text)
// ----------------------------------------------------------------------
+void StyleImage::StyleImgRenderer::setBuffer (core::Imgbuf *buffer, bool resize)
+{
+ if (image->imgbufSrc)
+ image->imgbufSrc->unref ();
+ if (image->imgbufTiled)
+ image->imgbufTiled->unref ();
+
+ image->imgbufTiled = NULL;
+
+ image->imgbufSrc = buffer;
+ if (image->imgbufSrc) {
+ image->imgbufSrc->ref ();
+
+ // If the image is too small, drawing a background will cause
+ // many calls of View::drawImgbuf. For this reason, we create
+ // another image buffer, the "tiled" image buffer, which is
+ // larger (the "optimal" size is defined as OPT_BG_IMG_W *
+ // OPT_BG_IMG_H) and contains the "source" buffer several times.
+ //
+ // This "tiled" buffer is not used when 'background-repeat' has
+ // another value than 'repeat', for obvious reasons. Image
+ // buffers only "tiled" in one dimension (to optimize 'repeat-x'
+ // and 'repeat-y') are not supported.
+
+ if (image->imgbufSrc->getRootWidth() * image->imgbufSrc->getRootHeight()
+ < MIN_BG_IMG_W * MIN_BG_IMG_H) {
+ image->tilesX =
+ misc::max (OPT_BG_IMG_W / image->imgbufSrc->getRootWidth(), 1);
+ image->tilesY =
+ misc::max (OPT_BG_IMG_H / image->imgbufSrc->getRootHeight(), 1);
+ image->imgbufTiled =
+ image->imgbufSrc->createSimilarBuf
+ (image->tilesX * image->imgbufSrc->getRootWidth(),
+ image->tilesY * image->imgbufSrc->getRootHeight());
+ }
+ }
+}
+
+void StyleImage::StyleImgRenderer::drawRow (int row)
+{
+ if (image->imgbufTiled) {
+ // A row of data has been copied to the source buffer, here it
+ // is copied into the tiled buffer.
+
+ // Unfortunately, this code may be called *after* some other
+ // implementations of ImgRenderer::drawRow, which actually
+ // *draw* the tiled buffer, which is so not up to date
+ // (ImgRendererDist does not define an order). OTOH, these
+ // drawing implementations calle Widget::queueResize, so the
+ // actual drawing (and so access to the tiled buffer) is done
+ // later.
+
+ int w = image->imgbufSrc->getRootWidth ();
+ int h = image->imgbufSrc->getRootHeight ();
+
+ for (int x = 0; x < image->tilesX; x++)
+ for (int y = 0; y < image->tilesX; y++)
+ image->imgbufSrc->copyTo (image->imgbufTiled, x * w, y * h,
+ 0, row, w, 1);
+ }
+}
+
+void StyleImage::StyleImgRenderer::finish ()
+{
+ // Nothing to do.
+}
+
+void StyleImage::StyleImgRenderer::fatal ()
+{
+ // Nothing to do.
+}
+
+StyleImage::StyleImage ()
+{
+ //printf ("new StyleImage %p\n", this);
+
+ refCount = 0;
+ imgbufSrc = NULL;
+ imgbufTiled = NULL;
+
+ imgRendererDist = new ImgRendererDist ();
+ styleImgRenderer = new StyleImgRenderer (this);
+ imgRendererDist->put (styleImgRenderer);
+}
+
+StyleImage::~StyleImage ()
+{
+ //printf ("delete StyleImage %p\n", this);
+
+ if (imgbufSrc)
+ imgbufSrc->unref ();
+ if (imgbufTiled)
+ imgbufTiled->unref ();
+
+ delete imgRendererDist;
+ delete styleImgRenderer;
+}
+
+void StyleImage::ExternalImgRenderer::setBuffer (core::Imgbuf *buffer,
+ bool resize)
+{
+ // Nothing to do?
+}
+
+void StyleImage::ExternalImgRenderer::drawRow (int row)
+{
+ if (drawBackgroundLineByLine) {
+ StyleImage *backgroundImage;
+ if (readyToDraw () && (backgroundImage = getBackgroundImage ())) {
+ // All single rows are drawn.
+
+ Imgbuf *imgbuf = backgroundImage->getImgbufSrc();
+ int imgWidth = imgbuf->getRootWidth ();
+ int imgHeight = imgbuf->getRootHeight ();
+
+ int x, y, width, height;
+ getBgArea (&x, &y, &width, &height);
+
+ int xRef, yRef, widthRef, heightRef;
+ getRefArea (&xRef, &yRef, &widthRef, &heightRef);
+
+ bool repeatX, repeatY, doDraw;
+ int origX, origY, tileX1, tileX2, tileY1, tileY2;
+
+ calcBackgroundRelatedValues (backgroundImage,
+ getBackgroundRepeat (),
+ getBackgroundAttachment (),
+ getBackgroundPositionX (),
+ getBackgroundPositionY (),
+ x, y, width, height, xRef, yRef, widthRef,
+ heightRef, &repeatX, &repeatY, &origX,
+ &origY, &tileX1, &tileX2, &tileY1,
+ &tileY2, &doDraw);
+
+ //printf ("tileX1 = %d, tileX2 = %d, tileY1 = %d, tileY2 = %d\n",
+ // tileX1, tileX2, tileY1, tileY2);
+
+ if (doDraw)
+ // Only iterate over y, because the rows can be combined
+ // horizontally.
+ for (int tileY = tileY1; tileY <= tileY2; tileY++) {
+ int x1 = misc::max (origX + tileX1 * imgWidth, x);
+ int x2 = misc::min (origX + (tileX2 + 1) * imgWidth, x + width);
+
+ int yt = origY + tileY * imgHeight + row;
+ if (yt >= y && yt < y + height)
+ draw (x1, yt, x2 - x1, 1);
+ }
+ }
+ }
+}
+
+void StyleImage::ExternalImgRenderer::finish ()
+{
+ if (!drawBackgroundLineByLine) {
+ if (readyToDraw ()) {
+ // Draw total area, as a whole.
+ int x, y, width, height;
+ getBgArea (&x, &y, &width, &height);
+ draw (x, y, width, height);
+ }
+ }
+}
+
+void StyleImage::ExternalImgRenderer::fatal ()
+{
+ // Nothing to do.
+}
+
+// ----------------------------------------------------------------------
+
+StyleImage *StyleImage::ExternalWidgetImgRenderer::getBackgroundImage ()
+{
+ Style *style = getStyle ();
+ return style ? style->backgroundImage : NULL;
+}
+
+BackgroundRepeat StyleImage::ExternalWidgetImgRenderer::getBackgroundRepeat ()
+{
+ Style *style = getStyle ();
+ return style ? style->backgroundRepeat : BACKGROUND_REPEAT;
+}
+
+BackgroundAttachment
+ StyleImage::ExternalWidgetImgRenderer::getBackgroundAttachment ()
+{
+ Style *style = getStyle ();
+ return style ? style->backgroundAttachment : BACKGROUND_ATTACHMENT_SCROLL;
+}
+
+Length StyleImage::ExternalWidgetImgRenderer::getBackgroundPositionX ()
+{
+ Style *style = getStyle ();
+ return style ? style->backgroundPositionX : createPerLength (0);
+}
+
+Length StyleImage::ExternalWidgetImgRenderer::getBackgroundPositionY ()
+{
+ Style *style = getStyle ();
+ return style ? style->backgroundPositionY : createPerLength (0);
+}
+
+// ----------------------------------------------------------------------
+
/*
* The drawBorder{Top,Bottom,Left,Right} functions are similar. They
* use a trapezium as draw polygon, or drawTypedLine() for dots and dashes.
@@ -851,8 +1105,11 @@ static void drawBorderRight(View *view, Style *style,
* \brief Draw the border of a region in window, according to style.
*
* Used by dw::core::Widget::drawBox and dw::core::Widget::drawWidgetBox.
+ *
+ * "area" is the area to be drawn, "x", "y", "width" and "height"
+ * define the box itself. All are given in canvas coordinates.
*/
-void drawBorder (View *view, Rectangle *area,
+void drawBorder (View *view, Layout *layout, Rectangle *area,
int x, int y, int width, int height,
Style *style, bool inverse)
{
@@ -889,29 +1146,193 @@ void drawBorder (View *view, Rectangle *area,
* according to style.
*
* Used by dw::core::Widget::drawBox and dw::core::Widget::drawWidgetBox.
+ *
+ * "area" is the area to be drawn, "x", "y", "width" and "height"
+ * define the box itself (padding box). "xRef", "yRef", "widthRef" and
+ * "heightRef" define the reference area, which is important for the
+ * tiling of background images (for position 0%/0%, a tile is set at
+ * xRef/yRef; for position 100%/100%, a tile is set at xRef +
+ * widthRef/yRef + widthRef). See calls for more informations; in most
+ * cases, these boxes are identical (padding box). All these
+ * coordinates are given in canvas coordinates.
+ *
+ * "atTop" should be true, only if the area is drawn directly on the
+ * canvas, not on top of other areas; this is only true for the
+ * toplevel widget itself (not parts of its contents). Toplevel widget
+ * background colors are already set as viewport background color, so
+ * that drawing again is is not neccessary, but some time can be
+ * saved.
+ *
+ * Otherwise, the caller should not try to increase the performance by
+ * doing some tests before; this is all done in this method.
*/
-void drawBackground (View *view, Rectangle *area,
+void drawBackground (View *view, Layout *layout, Rectangle *area,
int x, int y, int width, int height,
- Style *style, bool inverse)
-{
- Rectangle bgArea, intersection;
-
- if (style->backgroundColor) {
- bgArea.x = x + style->margin.left + style->borderWidth.left;
- bgArea.y = y + style->margin.top + style->borderWidth.top;
- bgArea.width =
- width - style->margin.left - style->borderWidth.left -
- style->margin.right - style->borderWidth.right;
- bgArea.height =
- height - style->margin.top - style->borderWidth.top -
- style->margin.bottom - style->borderWidth.bottom;
-
- if (area->intersectsWith (&bgArea, &intersection))
- view->drawRectangle (style->backgroundColor,
- inverse ?
- Color::SHADING_INVERSE : Color::SHADING_NORMAL,
- true, intersection.x, intersection.y,
- intersection.width, intersection.height);
+ int xRef, int yRef, int widthRef, int heightRef,
+ Style *style, bool inverse, bool atTop)
+{
+ bool bgColor = style->backgroundColor != NULL &&
+ // The test for background colors is rather simple, since only the color
+ // has to be compared, ...
+ (!atTop || layout->getBgColor () != style->backgroundColor);
+ bool bgImage = (style->backgroundImage != NULL &&
+ style->backgroundImage->getImgbufSrc() != NULL) &&
+ // ... but for backgrounds, it would be rather complicated. To handle the
+ // two cases (normal HTML in a viewport, where the layout background
+ // image is set, and contents of <button> within a flat view, where the
+ // background image of the toplevel widget is set), only the background
+ // images are compared. A full test, which also deals with all other
+ // attributes related to background images (repeat, position etc.) would
+ // be complicated and useless, so not worth the work.
+ (!atTop || layout->getBgImage () != style->backgroundImage);
+
+ // Since widgets are always drawn from top to bottom, it is *not*
+ // necessary to draw the background if background color and image
+ // are not set (NULL), i. e. shining through.
+
+ if (bgColor || bgImage) {
+ Rectangle bgArea, intersection;
+ bgArea.x = x;
+ bgArea.y = y;
+ bgArea.width = width;
+ bgArea.height = height;
+
+ if (area->intersectsWith (&bgArea, &intersection)) {
+ if (bgColor)
+ view->drawRectangle (style->backgroundColor,
+ inverse ?
+ Color::SHADING_INVERSE : Color::SHADING_NORMAL,
+ true, intersection.x, intersection.y,
+ intersection.width, intersection.height);
+
+ if (bgImage)
+ drawBackgroundImage (view, style->backgroundImage,
+ style->backgroundRepeat,
+ style->backgroundAttachment,
+ style->backgroundPositionX,
+ style->backgroundPositionY,
+ intersection.x, intersection.y,
+ intersection.width, intersection.height,
+ xRef, yRef, widthRef, heightRef);
+
+ }
+ }
+}
+
+void drawBackgroundImage (View *view, StyleImage *backgroundImage,
+ BackgroundRepeat backgroundRepeat,
+ BackgroundAttachment backgroundAttachment,
+ Length backgroundPositionX,
+ Length backgroundPositionY,
+ int x, int y, int width, int height,
+ int xRef, int yRef, int widthRef, int heightRef)
+{
+ //printf ("drawBackgroundImage (..., [img: %d, %d], ..., (%d, %d), %d x %d, "
+ // "(%d, %d), %d x %d)\n", imgWidth, imgHeight, x, y, width, height,
+ // xRef, yRef, widthRef, heightRef);
+
+ bool repeatX, repeatY, doDraw;
+ int origX, origY, tileX1, tileX2, tileY1, tileY2;
+
+ calcBackgroundRelatedValues (backgroundImage, backgroundRepeat,
+ backgroundAttachment, backgroundPositionX,
+ backgroundPositionY, x, y, width, height,
+ xRef, yRef, widthRef, heightRef,
+ &repeatX, &repeatY, &origX, &origY,
+ &tileX1, &tileX2, &tileY1, &tileY2, &doDraw);
+
+ //printf ("tileX1 = %d, tileX2 = %d, tileY1 = %d, tileY2 = %d\n",
+ // tileX1, tileX2, tileY1, tileY2);
+
+ if (doDraw) {
+ // Drawing is done with the "tiled" buffer, but all calculations
+ // before have been done with the "source" buffer.
+
+ Imgbuf *imgbufS = backgroundImage->getImgbufSrc();
+ int imgWidthS = imgbufS->getRootWidth ();
+ int imgHeightS = imgbufS->getRootHeight ();
+
+ Imgbuf *imgbufT = backgroundImage->getImgbufTiled(repeatX, repeatY);
+ int imgWidthT = imgbufT->getRootWidth ();
+ int imgHeightT = imgbufT->getRootHeight ();
+ int tilesX = backgroundImage->getTilesX (repeatX, repeatY);
+ int tilesY = backgroundImage->getTilesY (repeatX, repeatY);
+
+ for (int tileX = tileX1; tileX <= tileX2; tileX += tilesX)
+ for (int tileY = tileY1; tileY <= tileY2; tileY += tilesY) {
+ int xt = origX + tileX * imgWidthS;
+ int x1 = misc::max (xt, x);
+ int x2 = misc::min (xt + imgWidthT, x + width);
+ int yt = origY + tileY * imgHeightS;
+ int y1 = misc::max (yt, y);
+ int y2 = misc::min (yt + imgHeightT, y + height);
+
+ view->drawImage (imgbufT, xt, yt, x1 - xt, y1 - yt,
+ x2 - x1, y2 - y1);
+ }
+ }
+}
+
+void calcBackgroundRelatedValues (StyleImage *backgroundImage,
+ BackgroundRepeat backgroundRepeat,
+ BackgroundAttachment backgroundAttachment,
+ Length backgroundPositionX,
+ Length backgroundPositionY,
+ int xDraw, int yDraw, int widthDraw,
+ int heightDraw, int xRef, int yRef,
+ int widthRef, int heightRef, bool *repeatX,
+ bool *repeatY, int *origX, int *origY,
+ int *tileX1, int *tileX2, int *tileY1,
+ int *tileY2, bool *doDraw)
+{
+ Imgbuf *imgbuf = backgroundImage->getImgbufSrc();
+ int imgWidth = imgbuf->getRootWidth ();
+ int imgHeight = imgbuf->getRootHeight ();
+
+ *repeatX = backgroundRepeat == BACKGROUND_REPEAT ||
+ backgroundRepeat == BACKGROUND_REPEAT_X;
+ *repeatY = backgroundRepeat == BACKGROUND_REPEAT ||
+ backgroundRepeat == BACKGROUND_REPEAT_Y;
+
+ *origX = xRef +
+ (isPerLength (backgroundPositionX) ?
+ multiplyWithPerLength (widthRef - imgWidth, backgroundPositionX) :
+ absLengthVal (backgroundPositionX));
+ *origY = yRef +
+ (isPerLength (backgroundPositionY) ?
+ multiplyWithPerLength (heightRef - imgHeight, backgroundPositionY) :
+ absLengthVal (backgroundPositionY));
+
+ *tileX1 = xDraw < *origX ?
+ - (*origX - xDraw + imgWidth - 1) / imgWidth :
+ (xDraw - *origX) / imgWidth;
+ *tileX2 = *origX < xDraw + widthDraw ?
+ (xDraw + widthDraw - *origX - 1) / imgWidth :
+ - (*origX - (xDraw + widthDraw) + imgWidth - 1) / imgWidth;
+ *tileY1 = yDraw < *origY ?
+ - (*origY - yDraw + imgHeight - 1) / imgHeight :
+ (yDraw - *origY) / imgHeight;
+ *tileY2 = *origY < yDraw + heightDraw ?
+ (yDraw + heightDraw - *origY - 1) / imgHeight :
+ - (*origY - (yDraw + heightDraw) + imgHeight - 1) / imgHeight;
+
+ *doDraw = true;
+ if (!*repeatX) {
+ // Only center tile (tileX = 0) is drawn, ...
+ if (*tileX1 <= 0 && *tileX2 >= 0)
+ // ... and is visible.
+ *tileX1 = *tileX2 = 0;
+ else
+ // ... but is not visible.
+ *doDraw = false;
+ }
+
+ if (!*repeatY) {
+ // Analogue.
+ if (*tileY1 <= 0 && *tileY2 >= 0)
+ *tileY1 = *tileY2 = 0;
+ else
+ *doDraw = false;
}
}
diff --git a/dw/style.hh b/dw/style.hh
index 96343df9..3fe3b7c9 100644
--- a/dw/style.hh
+++ b/dw/style.hh
@@ -7,6 +7,8 @@
# error Do not include this file directly, use "core.hh" instead.
#endif
+#include "../lout/signal.hh"
+
namespace dw {
namespace core {
@@ -228,6 +230,18 @@ enum BorderStyle {
BORDER_OUTSET
};
+enum BackgroundRepeat {
+ BACKGROUND_REPEAT,
+ BACKGROUND_REPEAT_X,
+ BACKGROUND_REPEAT_Y,
+ BACKGROUND_NO_REPEAT
+};
+
+enum BackgroundAttachment {
+ BACKGROUND_ATTACHMENT_SCROLL,
+ BACKGROUND_ATTACHMENT_FIXED
+};
+
enum TextAlignType {
TEXT_ALIGN_LEFT,
TEXT_ALIGN_RIGHT,
@@ -482,9 +496,10 @@ public:
}
};
+class Tooltip;
class Font;
class Color;
-class Tooltip;
+class StyleImage;
/**
* \sa dw::core::style
@@ -496,6 +511,11 @@ public:
int textDecoration; /* No TextDecoration because of problems converting
* TextDecoration <-> int */
Color *color, *backgroundColor;
+ StyleImage *backgroundImage;
+ BackgroundRepeat backgroundRepeat;
+ BackgroundAttachment backgroundAttachment;
+ Length backgroundPositionX; // "left" defined by "0%" etc. (see CSS spec)
+ Length backgroundPositionY; // "top" defined by "0%" etc. (see CSS spec)
TextAlignType textAlign;
VAlignType valign;
@@ -561,7 +581,8 @@ public:
}
inline int boxDiffHeight () { return boxOffsetY () + boxRestHeight (); }
- inline bool hasBackground () { return backgroundColor != NULL; }
+ inline bool hasBackground ()
+ { return backgroundColor != NULL || backgroundImage != NULL; }
bool equals (lout::object::Object *other);
int hashValue ();
@@ -734,12 +755,139 @@ public:
{ if (--refCount == 0) delete this; }
};
-void drawBorder (View *view, Rectangle *area,
+
+class StyleImage: public lout::signal::ObservedObject
+{
+private:
+ class StyleImgRenderer: public ImgRenderer
+ {
+ private:
+ StyleImage *image;
+
+ public:
+ inline StyleImgRenderer (StyleImage *image) { this->image = image; }
+
+ void setBuffer (core::Imgbuf *buffer, bool resize);
+ void drawRow (int row);
+ void finish ();
+ void fatal ();
+ };
+
+ int refCount, tilesX, tilesY;
+ Imgbuf *imgbufSrc, *imgbufTiled;
+ ImgRendererDist *imgRendererDist;
+ StyleImgRenderer *styleImgRenderer;
+
+ StyleImage ();
+ ~StyleImage ();
+
+public:
+ /**
+ * \brief Useful (but not mandatory) base class for updates of
+ * areas with background images.
+ */
+ class ExternalImgRenderer: public ImgRenderer
+ {
+ public:
+ void setBuffer (core::Imgbuf *buffer, bool resize);
+ void drawRow (int row);
+ void finish ();
+ void fatal ();
+
+ /**
+ * \brief If this method returns false, nothing is done at all.
+ */
+ virtual bool readyToDraw () = 0;
+
+ /**
+ * \brief Return the area covered by the background image.
+ */
+ virtual void getBgArea (int *x, int *y, int *width, int *height) = 0;
+
+ /**
+ * \brief Return the "reference area".
+ *
+ * See comment of "drawBackground".
+ */
+ virtual void getRefArea (int *xRef, int *yRef, int *widthRef,
+ int *heightRef) = 0;
+
+ virtual StyleImage *getBackgroundImage () = 0;
+ virtual BackgroundRepeat getBackgroundRepeat () = 0;
+ virtual BackgroundAttachment getBackgroundAttachment () = 0;
+ virtual Length getBackgroundPositionX () = 0;
+ virtual Length getBackgroundPositionY () = 0;
+
+ /**
+ * \brief Draw (or queue for drawing) an area, which is given in
+ * canvas coordinates.
+ */
+ virtual void draw (int x, int y, int width, int height) = 0;
+ };
+
+ /**
+ * \brief Suitable for widgets and parts of widgets.
+ */
+ class ExternalWidgetImgRenderer: public ExternalImgRenderer
+ {
+ public:
+ void getPaddingArea (int *x, int *y, int *width, int *height);
+
+ StyleImage *getBackgroundImage ();
+ BackgroundRepeat getBackgroundRepeat ();
+ BackgroundAttachment getBackgroundAttachment ();
+ Length getBackgroundPositionX ();
+ Length getBackgroundPositionY ();
+
+ /**
+ * \brief Return the style this background image is part of.
+ */
+ virtual Style *getStyle () = 0;
+ };
+
+ static StyleImage *create () { return new StyleImage (); }
+
+ inline void ref () { refCount++; }
+ inline void unref ()
+ { if (--refCount == 0) delete this; }
+
+ inline Imgbuf *getImgbufSrc () { return imgbufSrc; }
+ inline Imgbuf *getImgbufTiled (bool repeatX, bool repeatY)
+ { return (imgbufTiled && repeatX && repeatY) ? imgbufTiled : imgbufSrc; }
+ inline int getTilesX (bool repeatX, bool repeatY)
+ { return (imgbufTiled && repeatX && repeatY) ? tilesX : 1; }
+ inline int getTilesY (bool repeatX, bool repeatY)
+ { return (imgbufTiled && repeatX && repeatY) ? tilesY : 1; }
+ inline ImgRenderer *getMainImgRenderer () { return imgRendererDist; }
+
+ /**
+ * \brief Add an additional ImgRenderer, especially used for
+ * drawing.
+ */
+ inline void putExternalImgRenderer (ImgRenderer *ir)
+ { imgRendererDist->put (ir); }
+
+ /**
+ * \brief Remove a previously added additional ImgRenderer.
+ */
+ inline void removeExternalImgRenderer (ImgRenderer *ir)
+ { imgRendererDist->remove (ir); }
+};
+
+void drawBorder (View *view, Layout *layout, Rectangle *area,
int x, int y, int width, int height,
Style *style, bool inverse);
-void drawBackground (View *view, Rectangle *area,
+void drawBackground (View *view, Layout *layout, Rectangle *area,
int x, int y, int width, int height,
- Style *style, bool inverse);
+ int xRef, int yRef, int widthRef, int heightRef,
+ Style *style, bool inverse, bool atTop);
+void drawBackgroundImage (View *view, StyleImage *backgroundImage,
+ BackgroundRepeat backgroundRepeat,
+ BackgroundAttachment backgroundAttachment,
+ Length backgroundPositionX,
+ Length backgroundPositionY,
+ int x, int y, int width, int height,
+ int xRef, int yRef, int widthRef, int heightRef);
void numtostr (int num, char *buf, int buflen, ListStyleType listStyleType);
} // namespace style
diff --git a/dw/table.cc b/dw/table.cc
index f1a9c5c1..eef1b6ce 100644
--- a/dw/table.cc
+++ b/dw/table.cc
@@ -22,6 +22,7 @@
#include "table.hh"
#include "../lout/msg.h"
#include "../lout/misc.hh"
+#include "../lout/debug.hh"
using namespace lout;
@@ -31,6 +32,7 @@ int Table::CLASS_ID = -1;
Table::Table(bool limitTextWidth)
{
+ DBG_OBJ_CREATE ("dw::Table");
registerName ("dw::Table", &CLASS_ID);
setFlags (BLOCK_LEVEL);
setFlags (USES_HINTS);
diff --git a/dw/tablecell.cc b/dw/tablecell.cc
index 66f86576..edad1524 100644
--- a/dw/tablecell.cc
+++ b/dw/tablecell.cc
@@ -20,6 +20,7 @@
#include "tablecell.hh"
+#include "../lout/debug.hh"
#include <stdio.h>
namespace dw {
@@ -29,6 +30,7 @@ int TableCell::CLASS_ID = -1;
TableCell::TableCell (TableCell *ref, bool limitTextWidth):
AlignedTextblock (limitTextWidth)
{
+ DBG_OBJ_CREATE ("dw::TableCell");
registerName ("dw::TableCell", &CLASS_ID);
/** \bug ignoreLine1OffsetSometimes does not work? */
diff --git a/dw/textblock.cc b/dw/textblock.cc
index b4f5c3d4..c0a902f4 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -22,6 +22,7 @@
#include "../lout/msg.h"
#include "../lout/misc.hh"
#include "../lout/unicode.hh"
+#include "../lout/debug.hh"
#include <stdio.h>
#include <math.h> // remove again?
@@ -42,6 +43,103 @@ namespace dw {
int Textblock::CLASS_ID = -1;
+Textblock::WordImgRenderer::WordImgRenderer (Textblock *textblock,
+ int wordNo)
+{
+ //printf ("new WordImgRenderer %p\n", this);
+
+ this->textblock = textblock;
+ this->wordNo = wordNo;
+ dataSet = false;
+}
+
+Textblock::WordImgRenderer::~WordImgRenderer ()
+{
+ //printf ("delete WordImgRenderer %p\n", this);
+}
+
+void Textblock::WordImgRenderer::setData (int xWordWidget, int lineNo)
+{
+ dataSet = true;
+ this->xWordWidget = xWordWidget;
+ this->lineNo = lineNo;
+}
+
+bool Textblock::WordImgRenderer::readyToDraw ()
+{
+ //print ();
+ //printf ("\n");
+
+ return dataSet && textblock->wasAllocated ()
+ && wordNo < textblock->words->size()
+ && lineNo < textblock->lines->size();
+}
+
+void Textblock::WordImgRenderer::getBgArea (int *x, int *y, int *width,
+ int *height)
+{
+ // TODO Subtract margin and border (padding box)?
+ Line *line = textblock->lines->getRef (lineNo);
+ *x = textblock->allocation.x + this->xWordWidget;
+ *y = textblock->lineYOffsetCanvas (line);
+ *width = textblock->words->getRef(wordNo)->size.width;
+ *height = line->boxAscent + line->boxDescent;
+}
+
+void Textblock::WordImgRenderer::getRefArea (int *xRef, int *yRef,
+ int *widthRef, int *heightRef)
+{
+ // See comment in Widget::drawBox about the reference area.
+ textblock->getPaddingArea (xRef, yRef, widthRef, heightRef);
+}
+
+core::style::Style *Textblock::WordImgRenderer::getStyle ()
+{
+ return textblock->words->getRef(wordNo)->style;
+}
+
+void Textblock::WordImgRenderer::draw (int x, int y, int width, int height)
+{
+ textblock->queueDrawArea (x - textblock->allocation.x,
+ y - textblock->allocation.y, width, height);
+
+}
+
+void Textblock::WordImgRenderer::print ()
+{
+ printf ("%p: word #%d, ", this, wordNo);
+ if (wordNo < textblock->words->size())
+ textblock->printWordShort (textblock->words->getRef(wordNo));
+ else
+ printf ("<word %d does not exist>", wordNo);
+ printf (", data set: %s", dataSet ? "yes" : "no");
+}
+
+void Textblock::SpaceImgRenderer::getBgArea (int *x, int *y, int *width,
+ int *height)
+{
+ WordImgRenderer::getBgArea (x, y, width, height);
+ *x += *width;
+ *width = textblock->words->getRef(wordNo)->effSpace;
+}
+
+core::style::Style *Textblock::SpaceImgRenderer::getStyle ()
+{
+ return textblock->words->getRef(wordNo)->spaceStyle;
+}
+
+void Textblock::SpaceImgRenderer::print ()
+{
+ printf ("%p: word FOR SPACE #%d, ", this, wordNo);
+ if (wordNo < textblock->words->size())
+ textblock->printWordShort (textblock->words->getRef(wordNo));
+ else
+ printf ("<word %d does not exist>", wordNo);
+ printf (", data set: %s", dataSet ? "yes" : "no");
+}
+
+// ----------------------------------------------------------------------
+
Textblock::DivChar Textblock::divChars[NUM_DIV_CHARS] = {
// soft hyphen (U+00AD)
{ "\xc2\xad", true, false, true, PENALTY_HYPHEN, -1 },
@@ -125,6 +223,7 @@ void Textblock::setStretchabilityFactor (int stretchabilityFactor)
Textblock::Textblock (bool limitTextWidth)
{
+ DBG_OBJ_CREATE ("dw::Textblock");
registerName ("dw::Textblock", &CLASS_ID);
setFlags (BLOCK_LEVEL);
setFlags (USES_HINTS);
@@ -195,9 +294,14 @@ Textblock::~Textblock ()
for (int i = 0; i < words->size(); i++) {
Word *word = words->getRef (i);
+
if (word->content.type == core::Content::WIDGET_IN_FLOW)
delete word->content.widget;
/** \todo Widget references? What about texts? */
+
+ removeWordImgRenderer (i);
+ removeSpaceImgRenderer (i);
+
word->style->unref ();
word->spaceStyle->unref ();
}
@@ -1528,14 +1632,77 @@ Textblock::Word *Textblock::addWord (int width, int ascent, int descent,
short flags, core::style::Style *style)
{
words->increase ();
- Word *word = words->getLastRef ();
- fillWord (word, width, ascent, descent, flags, style);
- return word;
+ int wordNo = words->size () - 1;
+ initWord (wordNo);
+ fillWord (wordNo, width, ascent, descent, flags, style);
+ return words->getRef (wordNo);;
+}
+
+/**
+ * Basic initialization, which is neccessary before fillWord.
+ */
+void Textblock::initWord (int wordNo)
+{
+ Word *word = words->getRef (wordNo);
+
+ word->style = word->spaceStyle = NULL;
+ word->wordImgRenderer = NULL;
+ word->spaceImgRenderer = NULL;
+}
+
+void Textblock::removeWordImgRenderer (int wordNo)
+{
+ Word *word = words->getRef (wordNo);
+
+ if (word->style && word->wordImgRenderer) {
+ word->style->backgroundImage->removeExternalImgRenderer
+ (word->wordImgRenderer);
+ delete word->wordImgRenderer;
+ word->wordImgRenderer = NULL;
+ }
+}
+
+void Textblock::setWordImgRenderer (int wordNo)
+{
+ Word *word = words->getRef (wordNo);
+
+ if (word->style->backgroundImage) {
+ word->wordImgRenderer = new WordImgRenderer (this, wordNo);
+ word->style->backgroundImage->putExternalImgRenderer
+ (word->wordImgRenderer);
+ } else
+ word->wordImgRenderer = NULL;
+}
+
+void Textblock::removeSpaceImgRenderer (int wordNo)
+{
+ Word *word = words->getRef (wordNo);
+
+ if (word->spaceStyle && word->spaceImgRenderer) {
+ word->spaceStyle->backgroundImage->removeExternalImgRenderer
+ (word->spaceImgRenderer);
+ delete word->spaceImgRenderer;
+ word->spaceImgRenderer = NULL;
+ }
+}
+
+void Textblock::setSpaceImgRenderer (int wordNo)
+{
+ Word *word = words->getRef (wordNo);
+
+ if (word->spaceStyle->backgroundImage) {
+ word->spaceImgRenderer = new SpaceImgRenderer (this, wordNo);
+ word->spaceStyle->backgroundImage->putExternalImgRenderer
+ (word->spaceImgRenderer);
+ } else
+ word->spaceImgRenderer = NULL;
}
-void Textblock::fillWord (Word *word, int width, int ascent, int descent,
+void Textblock::fillWord (int wordNo, int width, int ascent, int descent,
short flags, core::style::Style *style)
{
+ Word *word = words->getRef (wordNo);
+
word->size.width = width;
word->size.ascent = ascent;
word->size.descent = descent;
@@ -1545,8 +1712,15 @@ void Textblock::fillWord (Word *word, int width, int ascent, int descent,
word->content.space = false;
word->flags = flags;
+ removeWordImgRenderer (wordNo);
+ removeSpaceImgRenderer (wordNo);
+
word->style = style;
word->spaceStyle = style;
+
+ setWordImgRenderer (wordNo);
+ setSpaceImgRenderer (wordNo);
+
style->ref ();
style->ref ();
}
@@ -1622,8 +1796,6 @@ void Textblock::calcTextSize (const char *text, size_t len,
core::style::Style *style,
core::Requisition *size, bool isStart, bool isEnd)
{
- int requiredAscent, requiredDescent;
-
size->width = textWidth (text, 0, len, style, isStart, isEnd);
size->ascent = style->font->ascent;
size->descent = style->font->descent;
@@ -1663,10 +1835,10 @@ void Textblock::calcTextSize (const char *text, size_t len,
* potentially the line's height.
*/
if (style->valign == core::style::VALIGN_SUB) {
- requiredDescent = style->font->descent + style->font->ascent / 3;
+ int requiredDescent = style->font->descent + style->font->ascent / 3;
size->descent = misc::max (size->descent, requiredDescent);
} else if (style->valign == core::style::VALIGN_SUPER) {
- requiredAscent = style->font->ascent + style->font->ascent / 2;
+ int requiredAscent = style->font->ascent + style->font->ascent / 2;
size->ascent = misc::max (size->ascent, requiredAscent);
}
}
@@ -2052,7 +2224,7 @@ void Textblock::addSpace (core::style::Style *style)
{
int wordIndex = words->size () - 1;
if (wordIndex >= 0) {
- fillSpace (words->getRef(wordIndex), style);
+ fillSpace (wordIndex, style);
accumulateWordData (wordIndex);
correctLastWordExtremes ();
}
@@ -2074,7 +2246,7 @@ void Textblock::addBreakOption (core::style::Style *style, bool forceBreak)
}
}
-void Textblock::fillSpace (Word *word, core::style::Style *style)
+void Textblock::fillSpace (int wordNo, core::style::Style *style)
{
// Old comment:
//
@@ -2090,6 +2262,8 @@ void Textblock::fillSpace (Word *word, core::style::Style *style)
//
// TODO: Re-evaluate again.
+ Word *word = words->getRef (wordNo);
+
// TODO: This line does not work: addBreakOption (word, style);
if (// Do not override a previously set break penalty:
@@ -2109,9 +2283,14 @@ void Textblock::fillSpace (Word *word, core::style::Style *style)
//DBG_OBJ_ARRSET_NUM (this, "words.%d.content.space", wordIndex,
// word->content.space);
+
+ removeSpaceImgRenderer (wordNo);
+
word->spaceStyle->unref ();
word->spaceStyle = style;
style->ref ();
+
+ setSpaceImgRenderer (wordNo);
}
}
diff --git a/dw/textblock.hh b/dw/textblock.hh
index 3af933ce..b9255bb9 100644
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -244,6 +244,44 @@ private:
OutOfFlowMgr *outOfFlowMgr;
protected:
+ /**
+ * \brief Implementation used for words.
+ */
+ class WordImgRenderer:
+ public core::style::StyleImage::ExternalWidgetImgRenderer
+ {
+ protected:
+ Textblock *textblock;
+ int wordNo, xWordWidget, lineNo;
+ bool dataSet;
+
+ public:
+ WordImgRenderer (Textblock *textblock, int wordNo);
+ ~WordImgRenderer ();
+
+ void setData (int xWordWidget, int lineNo);
+
+ bool readyToDraw ();
+ void getBgArea (int *x, int *y, int *width, int *height);
+ void getRefArea (int *xRef, int *yRef, int *widthRef, int *heightRef);
+ core::style::Style *getStyle ();
+ void draw (int x, int y, int width, int height);
+
+ virtual void print ();
+ };
+
+ class SpaceImgRenderer: public WordImgRenderer
+ {
+ public:
+ inline SpaceImgRenderer (Textblock *textblock, int wordNo) :
+ WordImgRenderer (textblock, wordNo) { }
+
+ void getBgArea (int *x, int *y, int *width, int *height);
+ core::style::Style *getStyle ();
+
+ void print ();
+ };
+
struct Paragraph
{
int firstWord; /* first word's index in word vector */
@@ -373,6 +411,11 @@ protected:
core::style::Style *style;
core::style::Style *spaceStyle; /* initially the same as of the word,
later set by a_Dw_page_add_space */
+
+ // These two are used rarely, so there is perhaps a way to store
+ // them which is consuming less memory.
+ WordImgRenderer *wordImgRenderer;
+ SpaceImgRenderer *spaceImgRenderer;
};
void printWordShort (Word *word);
@@ -536,9 +579,14 @@ protected:
Word *addWord (int width, int ascent, int descent, short flags,
core::style::Style *style);
- void fillWord (Word *word, int width, int ascent, int descent,
+ void initWord (int wordNo);
+ void removeWordImgRenderer (int wordNo);
+ void setWordImgRenderer (int wordNo);
+ void removeSpaceImgRenderer (int wordNo);
+ void setSpaceImgRenderer (int wordNo);
+ void fillWord (int wordNo, int width, int ascent, int descent,
short flags, core::style::Style *style);
- void fillSpace (Word *word, core::style::Style *style);
+ void fillSpace (int wordNo, core::style::Style *style);
void setBreakOption (Word *word, core::style::Style *style,
int breakPenalty1, int breakPenalty2, bool forceBreak);
bool isBreakAllowed (Word *word);
diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc
index 6d3e3f39..1c1a3c1f 100644
--- a/dw/textblock_linebreaking.cc
+++ b/dw/textblock_linebreaking.cc
@@ -432,6 +432,16 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
//printf (": ");
//words->getRef(line->lastWord)->badnessAndPenalty.print ();
//printf ("\n");
+
+ int xWidget = line->offsetCompleteWidget;
+ for (int i = firstWord; i <= lastWord; i++) {
+ Word *word = words->getRef (i);
+ if (word->wordImgRenderer)
+ word->wordImgRenderer->setData (xWidget, lines->size () - 1);
+ if (word->spaceImgRenderer)
+ word->spaceImgRenderer->setData (xWidget, lines->size () - 1);
+ xWidget += word->size.width + word->effSpace;
+ }
line->finished = true;
@@ -1026,6 +1036,8 @@ int Textblock::hyphenateWord (int wordIndex)
PRINTF ("[%p] %d words ...\n", this, words->size ());
words->insert (wordIndex, numBreaks);
+ for (int i = 0; i < numBreaks; i++)
+ initWord (wordIndex + i);
PRINTF ("[%p] ... => %d words\n", this, words->size ());
if (containingBlock->outOfFlowMgr)
@@ -1041,8 +1053,7 @@ int Textblock::hyphenateWord (int wordIndex)
for (int i = 0; i < numBreaks + 1; i++) {
Word *w = words->getRef (wordIndex + i);
-
- fillWord (w, wordSize[i].width, wordSize[i].ascent,
+ fillWord (wordIndex + i, wordSize[i].width, wordSize[i].ascent,
wordSize[i].descent, false, origWord.style);
// TODO There should be a method fillText0.
@@ -1081,7 +1092,7 @@ int Textblock::hyphenateWord (int wordIndex)
PRINTF (" [%d] + hyphen\n", wordIndex + i);
} else {
if (origWord.content.space) {
- fillSpace (w, origWord.spaceStyle);
+ fillSpace (wordIndex + i, origWord.spaceStyle);
PRINTF (" [%d] + space\n", wordIndex + i);
} else {
PRINTF (" [%d] + nothing\n", wordIndex + i);
diff --git a/dw/ui.cc b/dw/ui.cc
index 374f360b..17cf2288 100644
--- a/dw/ui.cc
+++ b/dw/ui.cc
@@ -20,6 +20,7 @@
#include "core.hh"
+#include "../lout/debug.hh"
#include <stdio.h>
@@ -34,6 +35,7 @@ int Embed::CLASS_ID = -1;
Embed::Embed(Resource *resource)
{
+ DBG_OBJ_CREATE ("dw::core::ui::Embed");
registerName ("dw::core::ui::Embed", &CLASS_ID);
this->resource = resource;
resource->setEmbed (this);
diff --git a/dw/widget.cc b/dw/widget.cc
index f1f47f9e..83b9956a 100644
--- a/dw/widget.cc
+++ b/dw/widget.cc
@@ -32,10 +32,41 @@ namespace core {
// ----------------------------------------------------------------------
+bool Widget::WidgetImgRenderer::readyToDraw ()
+{
+ return widget->wasAllocated ();
+}
+
+void Widget::WidgetImgRenderer::getBgArea (int *x, int *y, int *width,
+ int *height)
+{
+ widget->getPaddingArea (x, y, width, height);
+}
+
+void Widget::WidgetImgRenderer::getRefArea (int *xRef, int *yRef, int *widthRef,
+ int *heightRef)
+{
+ widget->getPaddingArea (xRef, yRef, widthRef, heightRef);
+}
+
+style::Style *Widget::WidgetImgRenderer::getStyle ()
+{
+ return widget->getStyle ();
+}
+
+void Widget::WidgetImgRenderer::draw (int x, int y, int width, int height)
+{
+ widget->queueDrawArea (x - widget->allocation.x, y - widget->allocation.y,
+ width, height);
+}
+
+// ----------------------------------------------------------------------
+
int Widget::CLASS_ID = -1;
Widget::Widget ()
{
+ DBG_OBJ_CREATE ("dw::core::Widget");
registerName ("dw::core::Widget", &CLASS_ID);
flags = (Flags)(NEEDS_RESIZE | EXTREMES_CHANGED | HAS_CONTENTS);
@@ -55,6 +86,8 @@ Widget::Widget ()
deleteCallbackData = NULL;
deleteCallbackFunc = NULL;
+
+ widgetImgRenderer = NULL;
}
Widget::~Widget ()
@@ -62,6 +95,12 @@ Widget::~Widget ()
if (deleteCallbackFunc)
deleteCallbackFunc (deleteCallbackData);
+ if (widgetImgRenderer) {
+ if (style && style->backgroundImage)
+ style->backgroundImage->removeExternalImgRenderer (widgetImgRenderer);
+ delete widgetImgRenderer;
+ }
+
if (style)
style->unref ();
@@ -108,11 +147,11 @@ void Widget::setParent (Widget *parent)
if (!buttonSensitiveSet)
buttonSensitive = parent->buttonSensitive;
- notifySetParent();
-
- //DBG_OBJ_ASSOC (widget, parent);
+ DBG_OBJ_ASSOC_PARENT (parent);
//printf ("The %s %p becomes a child of the %s %p\n",
// getClassName(), this, parent->getClassName(), parent);
+
+ notifySetParent();
}
void Widget::queueDrawArea (int x, int y, int width, int height)
@@ -220,9 +259,9 @@ void Widget::sizeRequest (Requisition *requisition)
this->requisition = *requisition;
unsetFlags (NEEDS_RESIZE);
- DBG_OBJ_SET_NUM (this, "requisition->width", requisition->width);
- DBG_OBJ_SET_NUM (this, "requisition->ascent", requisition->ascent);
- DBG_OBJ_SET_NUM (this, "requisition->descent", requisition->descent);
+ DBG_OBJ_SET_NUM ("requisition.width", requisition->width);
+ DBG_OBJ_SET_NUM ("requisition.ascent", requisition->ascent);
+ DBG_OBJ_SET_NUM ("requisition.descent", requisition->descent);
} else
*requisition = this->requisition;
@@ -255,8 +294,8 @@ void Widget::getExtremes (Extremes *extremes)
this->extremes = *extremes;
unsetFlags (EXTREMES_CHANGED);
- DBG_OBJ_SET_NUM (this, "extremes->minWidth", extremes->minWidth);
- DBG_OBJ_SET_NUM (this, "extremes->maxWidth", extremes->maxWidth);
+ DBG_OBJ_SET_NUM ("extremes.minWidth", extremes->minWidth);
+ DBG_OBJ_SET_NUM ("extremes.maxWidth", extremes->maxWidth);
} else
*extremes = this->extremes;
@@ -318,11 +357,11 @@ void Widget::sizeAllocate (Allocation *allocation)
resizeDrawImpl ();
- DBG_OBJ_SET_NUM (this, "allocation.x", this->allocation.x);
- DBG_OBJ_SET_NUM (this, "allocation.y", this->allocation.y);
- DBG_OBJ_SET_NUM (this, "allocation.width", this->allocation.width);
- DBG_OBJ_SET_NUM (this, "allocation.ascent", this->allocation.ascent);
- DBG_OBJ_SET_NUM (this, "allocation.descent", this->allocation.descent);
+ DBG_OBJ_SET_NUM ("allocation.x", this->allocation.x);
+ DBG_OBJ_SET_NUM ("allocation.y", this->allocation.y);
+ DBG_OBJ_SET_NUM ("allocation.width", this->allocation.width);
+ DBG_OBJ_SET_NUM ("allocation.ascent", this->allocation.ascent);
+ DBG_OBJ_SET_NUM ("allocation.descent", this->allocation.descent);
}
/*unsetFlags (NEEDS_RESIZE);*/
@@ -366,6 +405,10 @@ void Widget::setStyle (style::Style *style)
{
bool sizeChanged;
+ if (widgetImgRenderer && this->style && this->style->backgroundImage)
+ this->style->backgroundImage->removeExternalImgRenderer
+ (widgetImgRenderer);
+
style->ref ();
if (this->style) {
@@ -376,6 +419,15 @@ void Widget::setStyle (style::Style *style)
this->style = style;
+ if (style && style->backgroundImage) {
+ // Create instance of WidgetImgRenderer when needed. Until this
+ // widget is deleted, "widgetImgRenderer" will be kept, since it
+ // is not specific to the style, but only to this widget.
+ if (widgetImgRenderer == NULL)
+ widgetImgRenderer = new WidgetImgRenderer (this);
+ style->backgroundImage->putExternalImgRenderer (widgetImgRenderer);
+ }
+
if (layout != NULL) {
layout->updateCursor ();
}
@@ -425,20 +477,31 @@ style::Color *Widget::getBgColor ()
void Widget::drawBox (View *view, style::Style *style, Rectangle *area,
int x, int y, int width, int height, bool inverse)
{
- Rectangle viewArea;
- viewArea.x = area->x + allocation.x;
- viewArea.y = area->y + allocation.y;
- viewArea.width = area->width;
- viewArea.height = area->height;
+ Rectangle canvasArea;
+ canvasArea.x = area->x + allocation.x;
+ canvasArea.y = area->y + allocation.y;
+ canvasArea.width = area->width;
+ canvasArea.height = area->height;
- style::drawBorder (view, &viewArea, allocation.x + x, allocation.y + y,
+ style::drawBorder (view, layout, &canvasArea,
+ allocation.x + x, allocation.y + y,
width, height, style, inverse);
- /** \todo Background images? */
- if (style->backgroundColor)
- style::drawBackground (view, &viewArea,
- allocation.x + x, allocation.y + y, width, height,
- style, inverse);
+ // This method is used for inline elements, where the CSS 2 specification
+ // does not define what here is called "reference area". To make it look
+ // smoothly, the widget padding box is used.
+
+ int xPad, yPad, widthPad, heightPad;
+ getPaddingArea (&xPad, &yPad, &widthPad, &heightPad);
+ style::drawBackground
+ (view, layout, &canvasArea,
+ allocation.x + x + style->margin.left + style->borderWidth.left,
+ allocation.y + y + style->margin.top + style->borderWidth.top,
+ width - style->margin.left - style->borderWidth.left
+ - style->margin.right - style->borderWidth.right,
+ height - style->margin.top - style->borderWidth.top
+ - style->margin.bottom - style->borderWidth.bottom,
+ xPad, yPad, widthPad, heightPad, style, inverse, false);
}
/**
@@ -449,32 +512,21 @@ void Widget::drawBox (View *view, style::Style *style, Rectangle *area,
*/
void Widget::drawWidgetBox (View *view, Rectangle *area, bool inverse)
{
- Rectangle viewArea;
- viewArea.x = area->x + allocation.x;
- viewArea.y = area->y + allocation.y;
- viewArea.width = area->width;
- viewArea.height = area->height;
+ Rectangle canvasArea;
+ canvasArea.x = area->x + allocation.x;
+ canvasArea.y = area->y + allocation.y;
+ canvasArea.width = area->width;
+ canvasArea.height = area->height;
- style::drawBorder (view, &viewArea, allocation.x, allocation.y,
+ style::drawBorder (view, layout, &canvasArea, allocation.x, allocation.y,
allocation.width, getHeight (), style, inverse);
- /** \todo Adjust following comment from the old dw sources. */
- /*
- * - Toplevel widget background colors are set as viewport
- * background color. This is not crucial for the rendering, but
- * looks a bit nicer when scrolling. Furthermore, the viewport
- * does anything else in this case.
- *
- * - Since widgets are always drawn from top to bottom, it is
- * *not* necessary to draw the background if
- * widget->style->background_color is NULL (shining through).
- */
- /** \todo Background images? */
-
- if (style->backgroundColor &&
- (parent || layout->getBgColor () != style->backgroundColor))
- style::drawBackground (view, &viewArea, allocation.x, allocation.y,
- allocation.width, getHeight (), style, inverse);
+ int xPad, yPad, widthPad, heightPad;
+ getPaddingArea (&xPad, &yPad, &widthPad, &heightPad);
+ style::drawBackground (view, layout, &canvasArea,
+ xPad, yPad, widthPad, heightPad,
+ xPad, yPad, widthPad, heightPad,
+ style, inverse, parent == NULL);
}
/*
@@ -639,6 +691,23 @@ void Widget::scrollTo (HPosition hpos, VPosition vpos,
x + allocation.x, y + allocation.y, width, height);
}
+/**
+ * \brief Return the padding area (content plus padding).
+ *
+ * Used as "reference area" (ee comment of "style::drawBackground")
+ * for backgrounds.
+ */
+void Widget::getPaddingArea (int *xPad, int *yPad, int *widthPad,
+ int *heightPad)
+{
+ *xPad = allocation.x + style->margin.left + style->borderWidth.left;
+ *yPad = allocation.y + style->margin.top + style->borderWidth.top;
+ *widthPad = allocation.width - style->margin.left - style->borderWidth.left
+ - style->margin.right - style->borderWidth.right;
+ *heightPad = getHeight () - style->margin.top - style->borderWidth.top
+ - style->margin.bottom - style->borderWidth.bottom;
+}
+
void Widget::getExtremesImpl (Extremes *extremes)
{
/* Simply return the requisition width */
diff --git a/dw/widget.hh b/dw/widget.hh
index 7dd12267..c9aeb427 100644
--- a/dw/widget.hh
+++ b/dw/widget.hh
@@ -97,6 +97,28 @@ protected:
BLOCK_LEVEL = 1 << 9,
};
+ /**
+ * \brief Implementation which represents the whole widget.
+ *
+ * The only instance is set created needed.
+ */
+ class WidgetImgRenderer: public style::StyleImage::ExternalWidgetImgRenderer
+ {
+ private:
+ Widget *widget;
+
+ public:
+ inline WidgetImgRenderer (Widget *widget) { this->widget = widget; }
+
+ bool readyToDraw ();
+ void getBgArea (int *x, int *y, int *width, int *height);
+ void getRefArea (int *xRef, int *yRef, int *widthRef, int *heightRef);
+ style::Style *getStyle ();
+ void draw (int x, int y, int width, int height);
+ };
+
+ WidgetImgRenderer *widgetImgRenderer;
+
private:
/**
* \brief The parent widget, NULL for top-level widgets.
@@ -351,6 +373,8 @@ public:
void scrollTo (HPosition hpos, VPosition vpos,
int x, int y, int width, int height);
+ void getPaddingArea (int *xPad, int *yPad, int *widthPad, int *heightPad);
+
/**
* \brief Return an iterator for this widget.
*