aboutsummaryrefslogtreecommitdiff
path: root/dw
diff options
context:
space:
mode:
Diffstat (limited to 'dw')
-rw-r--r--dw/alignedtextblock.cc17
-rw-r--r--dw/alignedtextblock.hh4
-rw-r--r--dw/bullet.cc7
-rw-r--r--dw/bullet.hh4
-rw-r--r--dw/events.hh6
-rw-r--r--dw/findtext.cc133
-rw-r--r--dw/findtext.hh22
-rw-r--r--dw/fltkcomplexbutton.cc43
-rw-r--r--dw/fltkcomplexbutton.hh38
-rw-r--r--dw/fltkflatview.cc5
-rw-r--r--dw/fltkflatview.hh2
-rw-r--r--dw/fltkimgbuf.cc123
-rw-r--r--dw/fltkmisc.cc3
-rw-r--r--dw/fltkplatform.cc184
-rw-r--r--dw/fltkplatform.hh45
-rw-r--r--dw/fltkpreview.cc16
-rw-r--r--dw/fltkpreview.hh1
-rw-r--r--dw/fltkui.cc439
-rw-r--r--dw/fltkui.hh84
-rw-r--r--dw/fltkviewbase.cc144
-rw-r--r--dw/fltkviewbase.hh26
-rw-r--r--dw/fltkviewport.cc131
-rw-r--r--dw/fltkviewport.hh6
-rw-r--r--dw/image.cc201
-rw-r--r--dw/image.hh34
-rw-r--r--dw/imgbuf.hh30
-rw-r--r--dw/iterator.cc47
-rw-r--r--dw/iterator.hh54
-rw-r--r--dw/layout.cc298
-rw-r--r--dw/layout.hh141
-rw-r--r--dw/listitem.cc17
-rw-r--r--dw/listitem.hh2
-rw-r--r--dw/platform.hh39
-rw-r--r--dw/ruler.cc5
-rw-r--r--dw/ruler.hh4
-rw-r--r--dw/selection.cc20
-rw-r--r--dw/selection.hh60
-rw-r--r--dw/style.cc272
-rw-r--r--dw/style.hh191
-rw-r--r--dw/table.cc296
-rw-r--r--dw/table.hh232
-rw-r--r--dw/tablecell.cc8
-rw-r--r--dw/textblock.cc1276
-rw-r--r--dw/textblock.hh155
-rw-r--r--dw/types.cc63
-rw-r--r--dw/types.hh29
-rw-r--r--dw/ui.cc65
-rw-r--r--dw/ui.hh169
-rw-r--r--dw/view.hh15
-rw-r--r--dw/widget.cc248
-rw-r--r--dw/widget.hh173
51 files changed, 2916 insertions, 2711 deletions
diff --git a/dw/alignedtextblock.cc b/dw/alignedtextblock.cc
index bb24a3bc..dde408b2 100644
--- a/dw/alignedtextblock.cc
+++ b/dw/alignedtextblock.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -27,8 +26,8 @@ namespace dw {
AlignedTextblock::List::List ()
{
- textblocks = new misc::SimpleVector <AlignedTextblock*> (4);
- values = new misc::SimpleVector <int> (4);
+ textblocks = new lout::misc::SimpleVector <AlignedTextblock*> (4);
+ values = new lout::misc::SimpleVector <int> (4);
maxValue = 0;
refCount = 0;
}
@@ -54,7 +53,7 @@ void AlignedTextblock::List::unref(int pos)
textblocks->set (pos, NULL);
refCount--;
- if(refCount == 0)
+ if (refCount == 0)
delete this;
}
@@ -63,12 +62,12 @@ int AlignedTextblock::CLASS_ID = -1;
AlignedTextblock::AlignedTextblock (bool limitTextWidth):
Textblock (limitTextWidth)
{
- registerName ("dw::AlignedTextblock", &CLASS_ID);
+ registerName ("dw::AlignedTextblock", &CLASS_ID);
}
void AlignedTextblock::setRefTextblock (AlignedTextblock *ref)
{
- if(ref == NULL)
+ if (ref == NULL)
list = new List();
else
list = ref->list;
@@ -76,7 +75,7 @@ void AlignedTextblock::setRefTextblock (AlignedTextblock *ref)
listPos = list->add (this);
updateValue ();
}
-
+
AlignedTextblock::~AlignedTextblock()
{
list->unref (listPos);
@@ -86,7 +85,7 @@ void AlignedTextblock::updateValue ()
{
if (list) {
list->setValue (listPos, getValue ());
-
+
if (list->getValue (listPos) > list->getMaxValue ()) {
// New value greater than current maximum -> apply it to others.
list->setMaxValue (list->getValue (listPos));
diff --git a/dw/alignedtextblock.hh b/dw/alignedtextblock.hh
index e855f1cc..7bac15bb 100644
--- a/dw/alignedtextblock.hh
+++ b/dw/alignedtextblock.hh
@@ -16,8 +16,8 @@ private:
class List
{
private:
- misc::SimpleVector <AlignedTextblock*> *textblocks;
- misc::SimpleVector <int> *values;
+ lout::misc::SimpleVector <AlignedTextblock*> *textblocks;
+ lout::misc::SimpleVector <int> *values;
int maxValue, refCount;
~List ();
diff --git a/dw/bullet.cc b/dw/bullet.cc
index cc13867c..af7f5451 100644
--- a/dw/bullet.cc
+++ b/dw/bullet.cc
@@ -14,14 +14,13 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bullet.hh"
-
+
#include <stdio.h>
namespace dw {
@@ -58,7 +57,7 @@ void Bullet::draw (core::View *view, core::Rectangle *area)
case core::style::LIST_STYLE_TYPE_DISC:
default:
view->drawArc (getStyle()->color, core::style::Color::SHADING_NORMAL,
- filled, x, y, l, l, 0, 360);
+ filled, x + l/2, y + l/2, l, l, 0, 360);
}
}
diff --git a/dw/bullet.hh b/dw/bullet.hh
index 00912bd8..98854abb 100644
--- a/dw/bullet.hh
+++ b/dw/bullet.hh
@@ -15,8 +15,8 @@ class Bullet: public core::Widget
{
protected:
void sizeRequestImpl (core::Requisition *requisition);
- void draw (core::View *view, core::Rectangle *area);
- core::Iterator *iterator (core::Content::Type mask, bool atEnd);
+ void draw (core::View *view, core::Rectangle *area);
+ core::Iterator *iterator (core::Content::Type mask, bool atEnd);
public:
Bullet ();
diff --git a/dw/events.hh b/dw/events.hh
index 860472ab..c29cb7f4 100644
--- a/dw/events.hh
+++ b/dw/events.hh
@@ -9,7 +9,7 @@ namespace dw {
namespace core {
/**
- * \brief Platform independant representation.
+ * \brief Platform independent representation.
*/
enum ButtonState
{
@@ -25,10 +25,10 @@ enum ButtonState
/**
* \brief Base class for all events.
*
- * The dw::core::Event hierarchy describes events in a platform independant
+ * The dw::core::Event hierarchy describes events in a platform independent
* way.
*/
-class Event: public object::Object
+class Event: public lout::object::Object
{
public:
};
diff --git a/dw/findtext.cc b/dw/findtext.cc
index 15de9f16..f3e0ba20 100644
--- a/dw/findtext.cc
+++ b/dw/findtext.cc
@@ -14,13 +14,13 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core.hh"
+#include "../lout/msg.h"
namespace dw {
namespace core {
@@ -66,14 +66,15 @@ void FindtextState::setWidget (Widget *widget)
hlIterator = NULL;
}
-FindtextState::Result FindtextState::search (const char *key, bool caseSens)
+FindtextState::Result FindtextState::search (const char *key, bool caseSens,
+ bool backwards)
{
if (!widget || *key == 0) // empty keys are not found
return NOT_FOUND;
bool wasHighlighted = unhighlight ();
bool newKey;
-
+
// If the key (or the widget) changes (including case sensitivity),
// the search is started from the beginning.
if (this->key == NULL || this->caseSens != caseSens ||
@@ -86,18 +87,25 @@ FindtextState::Result FindtextState::search (const char *key, bool caseSens)
if (nexttab)
delete[] nexttab;
- nexttab = createNexttab (key, caseSens);
-
+ nexttab = createNexttab (key, caseSens, backwards);
+
if (iterator)
delete iterator;
iterator = new CharIterator (widget);
- iterator->next ();
+
+ if (backwards) {
+ /* Go to end */
+ while (iterator->next () ) ;
+ iterator->prev (); //We don't want to be at CharIterator::END.
+ } else {
+ iterator->next ();
+ }
} else
newKey = false;
bool firstTrial = !wasHighlighted || newKey;
- if (search0 ()) {
+ if (search0 (backwards, firstTrial)) {
// Highlighlighting is done with a clone.
hlIterator = iterator->cloneCharIterator ();
for (int i = 0; key[i]; i++)
@@ -110,16 +118,21 @@ FindtextState::Result FindtextState::search (const char *key, bool caseSens)
iterator->next ();
return SUCCESS;
} else {
- if (firstTrial)
+ if (firstTrial) {
return NOT_FOUND;
- else {
+ } else {
// Nothing found anymore, reset the state for the next trial.
delete iterator;
iterator = new CharIterator (widget);
- iterator->next ();
-
+ if (backwards) {
+ /* Go to end */
+ while (iterator->next ()) ;
+ iterator->prev (); //We don't want to be at CharIterator::END.
+ } else {
+ iterator->next ();
+ }
// We expect a success.
- Result result2 = search (key, caseSens);
+ Result result2 = search (key, caseSens, backwards);
assert (result2 == SUCCESS);
return RESTART;
}
@@ -135,11 +148,32 @@ void FindtextState::resetSearch ()
if (key)
delete key;
- key = NULL;
+ key = NULL;
+}
+
+/*
+ * Return a new string: with the reverse of the original.
+ */
+const char* FindtextState::rev(const char *str)
+{
+ if (!str)
+ return NULL;
+
+ int len = strlen(str);
+ char *nstr = new char[len+1];
+ for (int i = 0; i < len; ++i)
+ nstr[i] = str[len-1 -i];
+ nstr[len] = 0;
+
+ return nstr;
}
-int *FindtextState::createNexttab (const char *key, bool caseSens)
+int *FindtextState::createNexttab (const char *needle, bool caseSens,
+ bool backwards)
{
+ const char* key;
+
+ key = (backwards) ? rev(needle) : needle;
int i = 0;
int j = -1;
int l = strlen (key);
@@ -156,6 +190,9 @@ int *FindtextState::createNexttab (const char *key, bool caseSens)
j = nexttab[j];
} while (i < l - 1);
+ if (backwards)
+ delete [] key;
+
return nexttab;
}
@@ -179,30 +216,76 @@ bool FindtextState::unhighlight ()
return false;
}
-bool FindtextState::search0 ()
+bool FindtextState::search0 (bool backwards, bool firstTrial)
{
if (iterator->getChar () == CharIterator::END)
return false;
+ bool ret = false;
+ const char* searchKey = (backwards) ? rev(key) : key;
int j = 0;
bool nextit = true;
int l = strlen (key);
+ if (backwards && !firstTrial) {
+ _MSG("Having to do.");
+ /* Position correctly */
+ /* In order to achieve good results (i.e: find a word that ends within
+ * the previously searched word's limit) we have to position the
+ * iterator in the semilast character of the previously searched word.
+ *
+ * Since we know that if a word was found before it was exactly the
+ * same word as the one we are searching for now, we can apply the
+ * following expression:
+ *
+ * Where l=length of the key and n=num of positions to move:
+ *
+ * n = l - 3
+ *
+ * If n is negative, we have to move backwards, but if it is
+ * positive, we have to move forward. So, when l>=4, we start moving
+ * the iterator forward. */
+
+ if (l==1) {
+ iterator->prev();
+ iterator->prev();
+ } else if (l==2) {
+ iterator->prev();
+ } else if (l>=4) {
+ for (int i=0; i<l-3; i++) {
+ iterator->next();
+ }
+ }
+
+ } else if (backwards && l==1) {
+ /* Particular case where we can't find the last character */
+ iterator->next();
+ }
+
do {
- if (j == -1 || charsEqual (iterator->getChar (), key[j], caseSens)) {
+ if (j == -1 || charsEqual (iterator->getChar(),searchKey[j],caseSens)) {
j++;
- nextit = iterator->next ();
+ nextit = backwards ? iterator->prev () : iterator->next ();
} else
j = nexttab[j];
} while (nextit && j < l);
-
+
if (j >= l) {
- // Go back to where the word was found.
- for (int i = 0; i < l; i++)
- iterator->prev ();
- return true;
- } else
- return false;
+ if (backwards) {
+ //This is the location of the key
+ iterator->next();
+ } else {
+ // Go back to where the key was found.
+ for (int i = 0; i < l; i++)
+ iterator->prev ();
+ }
+ ret = true;
+ }
+
+ if (backwards)
+ delete [] searchKey;
+
+ return ret;
}
} // namespace dw
diff --git a/dw/findtext.hh b/dw/findtext.hh
index d0c20206..14789878 100644
--- a/dw/findtext.hh
+++ b/dw/findtext.hh
@@ -14,12 +14,12 @@ class FindtextState
{
public:
typedef enum {
- /** \brief The next occurance of the pattern has been found. */
+ /** \brief The next occurrence of the pattern has been found. */
SUCCESS,
/**
- * \brief There is no further occurance of the pattern, instead, the
- * first occurance has been selected.
+ * \brief There is no further occurrence of the pattern, instead, the
+ * first occurrence has been selected.
*/
RESTART,
@@ -48,31 +48,33 @@ private:
* dw::core::Findtext::widget
*/
Widget *widget;
-
+
/** \brief The position from where the next search will start. */
CharIterator *iterator;
/**
* \brief The position from where the characters are highlighted.
- *
+ *
* NULL, when no text is highlighted.
*/
- CharIterator *hlIterator;
+ CharIterator *hlIterator;
+
+ static const char* rev(const char* _str); /* reverse a C string */
- static int *createNexttab (const char *key, bool caseSens);
+ static int *createNexttab (const char *needle,bool caseSens,bool backwards);
bool unhighlight ();
- bool search0 ();
+ bool search0 (bool backwards, bool firstTrial);
inline static bool charsEqual (char c1, char c2, bool caseSens)
{ return caseSens ? c1 == c2 : tolower (c1) == tolower (c2) ||
- isspace (c1) && isspace (c2); }
+ (isspace (c1) && isspace (c2)); }
public:
FindtextState ();
~FindtextState ();
void setWidget (Widget *widget);
- Result search (const char *key, bool caseSens);
+ Result search (const char *key, bool caseSens, bool backwards);
void resetSearch ();
};
diff --git a/dw/fltkcomplexbutton.cc b/dw/fltkcomplexbutton.cc
index 6c15cee3..f80d0eb0 100644
--- a/dw/fltkcomplexbutton.cc
+++ b/dw/fltkcomplexbutton.cc
@@ -1,21 +1,22 @@
-//
-//
-// Copyright 1998-2006 by Bill Spitzak and others.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 3 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
+
+// fltkcomplexbutton.cc contains code from FLTK2's src/Button.cxx
+// that is Copyright 1998-2006 by Bill Spitzak and others.
+// (see http://svn.easysw.com/public/fltk/fltk/trunk/src/Button.cxx)
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
#include <fltk/events.h>
#include <fltk/damage.h>
@@ -87,7 +88,7 @@ int ComplexButton::handle(int event, const Rectangle& rectangle) {
if (pushed()) return 1; // ignore extra pushes on currently-pushed button
initial_state = state();
clear_flag(PUSHED);
- do_callback();
+ /* do_callback(); */
case DRAG: {
bool inside = event_inside(rectangle);
if (inside) {
@@ -112,7 +113,7 @@ int ComplexButton::handle(int event, const Rectangle& rectangle) {
redraw(DAMAGE_VALUE);
if (type() == RADIO)
setonly();
- else if (type()) // TOGGLE
+ else if (type() == TOGGLE)
state(!initial_state);
else {
state(initial_state);
@@ -139,7 +140,7 @@ int ComplexButton::handle(int event, const Rectangle& rectangle) {
setonly();
if (when() & WHEN_CHANGED) do_callback(); else set_changed();
}
- } else if (type()) { // TOGGLE
+ } else if (type() == TOGGLE) {
state(!state());
if (when() & WHEN_CHANGED) do_callback(); else set_changed();
}
diff --git a/dw/fltkcomplexbutton.hh b/dw/fltkcomplexbutton.hh
index 72799d42..83160c06 100644
--- a/dw/fltkcomplexbutton.hh
+++ b/dw/fltkcomplexbutton.hh
@@ -1,22 +1,22 @@
-//
-//
-// Copyright 2002 by Bill Spitzak and others.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Library General Public
-// License as published by the Free Software Foundation; either
-// version 2 of the License, or (at your option) any later version.
-//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Library General Public License for more details.
-//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-// USA.
-//
+
+// fltkcomplexbutton.hh contains code from FLTK2's fltk/Button.h
+// that is Copyright 2002 by Bill Spitzak and others.
+// (see http://svn.easysw.com/public/fltk/fltk/trunk/fltk/Button.h)
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
#ifndef __FLTK_COMPLEX_BUTTON_HH__
#define __FLTK_COMPLEX_BUTTON_HH__
diff --git a/dw/fltkflatview.cc b/dw/fltkflatview.cc
index 7f5f88a6..85385394 100644
--- a/dw/fltkflatview.cc
+++ b/dw/fltkflatview.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -52,7 +51,7 @@ void FltkFlatView::setCanvasSize (int width, int ascent, int descent)
#if 0
FltkWidgetView::setCanvasSize (width, ascent, descent);
-
+
w (width);
h (ascent + descent);
#endif
diff --git a/dw/fltkflatview.hh b/dw/fltkflatview.hh
index dee5498f..5106cbdf 100644
--- a/dw/fltkflatview.hh
+++ b/dw/fltkflatview.hh
@@ -22,7 +22,7 @@ protected:
public:
FltkFlatView (int x, int y, int w, int h, const char *label = 0);
~FltkFlatView ();
-
+
void setCanvasSize (int width, int ascent, int descent);
bool usesViewport ();
diff --git a/dw/fltkimgbuf.cc b/dw/fltkimgbuf.cc
index b8beb1cb..6ba7ff1d 100644
--- a/dw/fltkimgbuf.cc
+++ b/dw/fltkimgbuf.cc
@@ -14,34 +14,36 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "fltkcore.hh"
+#include "../lout/msg.h"
#include "../lout/misc.hh"
#include <fltk/draw.h>
#include <fltk/Color.h>
+#define IMAGE_MAX_AREA (6000 * 6000)
+
using namespace fltk;
namespace dw {
namespace fltk {
-using namespace container::typed;
+using namespace lout::container::typed;
FltkImgbuf::FltkImgbuf (Type type, int width, int height)
{
- //printf("FltkImgbuf: new root %p\n", this);
+ _MSG("FltkImgbuf: new root %p\n", this);
init (type, width, height, NULL);
}
FltkImgbuf::FltkImgbuf (Type type, int width, int height, FltkImgbuf *root)
{
- //printf("FltkImgbuf: new scaled %p, root is %p\n", this, root);
+ _MSG("FltkImgbuf: new scaled %p, root is %p\n", this, root);
init (type, width, height, root);
}
@@ -58,19 +60,18 @@ void FltkImgbuf::init (Type type, int width, int height, FltkImgbuf *root)
case RGB: bpp = 3; break;
default: bpp = 1; break;
}
- //fprintf(stderr,"FltkImgbuf::init width=%d height=%d bpp=%d\n",
- // width, height, bpp);
+ _MSG("FltkImgbuf::init width=%d height=%d bpp=%d\n", width, height, bpp);
rawdata = new uchar[bpp * width * height];
// Set light-gray as interim background color.
memset(rawdata, 222, width*height*bpp);
refCount = 1;
deleteOnUnref = true;
- copiedRows = new misc::BitSet (height);
+ copiedRows = new lout::misc::BitSet (height);
// The list is only used for root buffers.
if (isRoot())
- scaledBuffers = new container::typed::List <FltkImgbuf> (true);
+ scaledBuffers = new lout::container::typed::List <FltkImgbuf> (true);
else
scaledBuffers = NULL;
@@ -85,12 +86,7 @@ void FltkImgbuf::init (Type type, int width, int height, FltkImgbuf *root)
FltkImgbuf::~FltkImgbuf ()
{
- //printf ("FltkImgbuf::~FltkImgbuf (%s)\n", isRoot() ? "root" : "scaled");
-
- //if (root)
- // printf("FltkImgbuf[scaled %p, root is %p]: deleted\n", this, root);
- //else
- // printf("FltkImgbuf[root %p]: deleted\n", this);
+ _MSG("~FltkImgbuf[%s %p] deleted\n", isRoot() ? "root":"scaled", this);
if (!isRoot())
root->detachScaledBuf (this);
@@ -110,8 +106,8 @@ void FltkImgbuf::detachScaledBuf (FltkImgbuf *scaledBuf)
{
scaledBuffers->detachRef (scaledBuf);
- //printf("FltkImgbuf[root %p]: scaled buffer %p is detached, %d left\n",
- // this, scaledBuf, scaledBuffers->size ());
+ _MSG("FltkImgbuf[root %p]: scaled buffer %p is detached, %d left\n",
+ this, scaledBuf, scaledBuffers->size ());
if (refCount == 0 && scaledBuffers->isEmpty () && deleteOnUnref)
// If the root buffer is not used anymore, but this is the last scaled
@@ -128,17 +124,17 @@ inline void FltkImgbuf::scaleRow (int row, const core::byte *data)
{
int sr1 = scaledY (row);
int sr2 = scaledY (row + 1);
-
- for(int sr = sr1; sr < sr2; sr++) {
+
+ for (int sr = sr1; sr < sr2; sr++) {
// Avoid multiple passes.
if (copiedRows->get(sr)) continue;
copiedRows->set (sr, true);
if (sr == sr1) {
- for(int px = 0; px < root->width; px++) {
+ for (int px = 0; px < root->width; px++) {
int px1 = px * width / root->width;
int px2 = (px+1) * width / root->width;
- for(int sp = px1; sp < px2; sp++) {
+ for (int sp = px1; sp < px2; sp++) {
memcpy(rawdata + (sr*width + sp)*bpp, data + px*bpp, bpp);
}
}
@@ -168,16 +164,16 @@ void FltkImgbuf::newScan ()
if (isRoot()) {
for (Iterator<FltkImgbuf> it = scaledBuffers->iterator(); it.hasNext();){
FltkImgbuf *sb = it.getNext ();
- sb->copiedRows->clear();
+ sb->copiedRows->clear();
}
}
}
core::Imgbuf* FltkImgbuf::getScaledBuf (int width, int height)
{
- if (root)
+ if (!isRoot())
return root->getScaledBuf (width, height);
-
+
if (width == this->width && height == this->height) {
ref ();
return this;
@@ -191,6 +187,18 @@ core::Imgbuf* FltkImgbuf::getScaledBuf (int width, int height)
}
}
+ /* Check for excessive image sizes which would cause crashes due to
+ * too big allocations for the image buffer.
+ * In this case we return a pointer to the unscaled image buffer.
+ */
+ if (width <= 0 || height <= 0 ||
+ width > IMAGE_MAX_AREA / height) {
+ MSG("FltkImgbuf::getScaledBuf: suspicious image size request %dx%d\n",
+ width, height);
+ ref ();
+ return this;
+ }
+
/* This size is not yet used, so a new buffer has to be created. */
FltkImgbuf *sb = new FltkImgbuf (type, width, height, this);
scaledBuffers->append (sb);
@@ -207,8 +215,8 @@ void FltkImgbuf::getRowArea (int row, dw::core::Rectangle *area)
area->y = row;
area->width = width;
area->height = 1;
- //fprintf(stderr,"::getRowArea: area x=%d y=%d width=%d height=%d\n",
- // area->x, area->y, area->width, area->height);
+ _MSG("::getRowArea: area x=%d y=%d width=%d height=%d\n",
+ area->x, area->y, area->width, area->height);
} else {
// scaled buffer
int sr1 = scaledY (row);
@@ -218,8 +226,8 @@ void FltkImgbuf::getRowArea (int row, dw::core::Rectangle *area)
area->y = sr1;
area->width = width;
area->height = sr2 - sr1;
- //fprintf(stderr,"::getRowArea: area x=%d y=%d width=%d height=%d\n",
- // area->x, area->y, area->width, area->height);
+ _MSG("::getRowArea: area x=%d y=%d width=%d height=%d\n",
+ area->x, area->y, area->width, area->height);
}
}
@@ -238,28 +246,30 @@ void FltkImgbuf::ref ()
refCount++;
//if (root)
- // printf("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n",
- // this, root, refCount);
+ // MSG("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n",
+ // this, root, refCount);
//else
- // printf("FltkImgbuf[root %p]: ref() => %d\n", this, refCount);
+ // MSG("FltkImgbuf[root %p]: ref() => %d\n", this, refCount);
}
void FltkImgbuf::unref ()
{
//if (root)
- // printf("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n",
- // this, root, refCount - 1);
+ // MSG("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n",
+ // this, root, refCount - 1);
//else
- // printf("FltkImgbuf[root %p]: ref() => %d\n", this, refCount - 1);
+ // MSG("FltkImgbuf[root %p]: ref() => %d\n", this, refCount - 1);
if (--refCount == 0) {
if (isRoot ()) {
// Root buffer, it must be ensured that no scaled buffers are left.
// See also FltkImgbuf::detachScaledBuf().
- if (scaledBuffers->isEmpty () && deleteOnUnref)
+ if (scaledBuffers->isEmpty () && deleteOnUnref) {
delete this;
- else
- printf("FltkImgbuf[root %p]: not deleted\n", this);
+ } else {
+ _MSG("FltkImgbuf[root %p]: not deleted. numScaled=%d\n",
+ this, scaledBuffers->size ());
+ }
} else
// Scaled buffer buffer, simply delete it.
delete this;
@@ -268,7 +278,7 @@ void FltkImgbuf::unref ()
bool FltkImgbuf::lastReference ()
{
- return refCount == 1 &&
+ return refCount == 1 &&
(scaledBuffers == NULL || scaledBuffers->isEmpty ());
}
@@ -293,29 +303,15 @@ int FltkImgbuf::scaledY(int ySrc)
}
void FltkImgbuf::draw (::fltk::Widget *target, int xRoot, int yRoot,
- int x, int y, int width, int height)
+ int x, int y, int width, int height)
{
- // TODO (i): Implementation.
- // TODO (ii): Clarify the question, whether "target" is the current widget
- // (and so has not to be passed at all).
+ // TODO: Clarify the question, whether "target" is the current widget
+ // (and so has not to be passed at all).
-/*
- setcolor (0);
+ _MSG("::draw: xRoot=%d x=%d yRoot=%d y=%d width=%d height=%d\n"
+ " this->width=%d this->height=%d\n",
+ xRoot, x, yRoot, y, width, height, this->width, this->height);
- for (int row = y; row < y + height; row++) {
- if (copiedRows->get (row)) {
- ::fltk::Rectangle rect (x + xRoot, row + yRoot, width, 1);
- fillrect (rect);
- }
- }
-*/
-
- //fprintf(stderr,"::draw: xRoot=%d x=%d yRoot=%d y=%d width=%d height=%d\n"
- // " this->width=%d this->height=%d\n",
- // xRoot, x, yRoot, y, width, height, this->width, this->height);
-
-//{
-#if 1
if (x > this->width || y > this->height) {
return;
}
@@ -328,19 +324,10 @@ void FltkImgbuf::draw (::fltk::Widget *target, int xRoot, int yRoot,
height = this->height - y;
}
- // almost OK for rows. For some unknown reason it trims the bottom and
- // rightmost parts when scrolling.
+ // Draw
::fltk::Rectangle rect (xRoot + x, yRoot + y, width, height);
PixelType ptype = (type == RGBA) ? ::fltk::RGBA : ::fltk::RGB;
drawimage(rawdata+bpp*(y*this->width + x),ptype,rect,bpp*this->width);
-
-#else
- // OK for full image.
- ::fltk::Rectangle rect (xRoot, yRoot, this->width, this->height);
- PixelType ptype = (type == RGBA) ? ::fltk::RGBA : ::fltk::RGB;
- drawimage(rawdata,ptype,rect);
-#endif
-//}
}
} // namespace dw
diff --git a/dw/fltkmisc.cc b/dw/fltkmisc.cc
index 08d75854..5d20a87a 100644
--- a/dw/fltkmisc.cc
+++ b/dw/fltkmisc.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
diff --git a/dw/fltkplatform.cc b/dw/fltkplatform.cc
index 337f4dba..97e10710 100644
--- a/dw/fltkplatform.cc
+++ b/dw/fltkplatform.cc
@@ -14,17 +14,19 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+#include "../lout/msg.h"
#include "fltkcore.hh"
#include <fltk/draw.h>
#include <fltk/run.h>
#include <fltk/events.h>
+#include <fltk/Monitor.h>
+#include <fltk/InvisibleBox.h>
+#include <fltk/Tooltip.h>
#include <fltk/utf.h>
#include <stdio.h>
@@ -32,6 +34,7 @@ namespace dw {
namespace fltk {
using namespace ::fltk;
+using namespace lout;
/**
* \todo Distinction between italics and oblique would be nice.
@@ -47,23 +50,22 @@ FltkFont::FltkFont (core::style::FontAttrs *attrs)
copyAttrs (attrs);
int fa = 0;
- if(weight >= 500)
+ if (weight >= 500)
fa |= BOLD;
- if(style != core::style::FONT_STYLE_NORMAL)
+ if (style != core::style::FONT_STYLE_NORMAL)
fa |= ITALIC;
font = ::fltk::font(name, fa);
- if(font == NULL) {
- fprintf(stderr, "No font '%s', using default sans-serif font.\n", name);
+ if (font == NULL) {
/*
* If using xft, fltk::HELVETICA just means sans, fltk::COURIER
* means mono, and fltk::TIMES means serif.
*/
- font = HELVETICA;
- }
+ font = HELVETICA->plus (fa);
+ }
setfont(font, size);
- spaceWidth = (int)getwidth(" ");
+ spaceWidth = misc::max(0, (int)getwidth(" ") + letterSpacing);
int xw, xh;
measure("x", xw, xh);
xHeight = xh;
@@ -81,6 +83,12 @@ FltkFont::~FltkFont ()
fontsTable->remove (this);
}
+bool
+FltkPlatform::fontExists (const char *name)
+{
+ return ::fltk::font(name) != NULL;
+}
+
FltkFont*
FltkFont::create (core::style::FontAttrs *attrs)
{
@@ -100,11 +108,9 @@ container::typed::HashTable <dw::core::style::ColorAttrs,
new container::typed::HashTable <dw::core::style::ColorAttrs,
FltkColor> (false, false);
-FltkColor::FltkColor (int color, core::style::Color::Type type):
- Color (color, type)
+FltkColor::FltkColor (int color): Color (color)
{
this->color = color;
- this->type = type;
/*
* fltk/setcolor.cxx:
@@ -122,13 +128,10 @@ FltkColor::FltkColor (int color, core::style::Color::Type type):
colors[SHADING_NORMAL] = ::fltk::BLACK;
if (!(colors[SHADING_INVERSE] = shadeColor (color, SHADING_INVERSE) << 8))
colors[SHADING_INVERSE] = ::fltk::BLACK;
-
- if(type == core::style::Color::TYPE_SHADED) {
- if (!(colors[SHADING_DARK] = shadeColor (color, SHADING_DARK) << 8))
- colors[SHADING_DARK] = ::fltk::BLACK;
- if (!(colors[SHADING_LIGHT] = shadeColor (color, SHADING_LIGHT) << 8))
- colors[SHADING_LIGHT] = ::fltk::BLACK;
- }
+ if (!(colors[SHADING_DARK] = shadeColor (color, SHADING_DARK) << 8))
+ colors[SHADING_DARK] = ::fltk::BLACK;
+ if (!(colors[SHADING_LIGHT] = shadeColor (color, SHADING_LIGHT) << 8))
+ colors[SHADING_LIGHT] = ::fltk::BLACK;
}
FltkColor::~FltkColor ()
@@ -136,17 +139,74 @@ FltkColor::~FltkColor ()
colorsTable->remove (this);
}
-FltkColor * FltkColor::create (int col, core::style::Color::Type type)
+FltkColor * FltkColor::create (int col)
{
- ColorAttrs attrs(col, type);
+ ColorAttrs attrs(col);
FltkColor *color = colorsTable->get (&attrs);
if (color == NULL) {
- color = new FltkColor (col, type);
+ color = new FltkColor (col);
colorsTable->put (color, color);
}
- return color;
+ return color;
+}
+
+FltkTooltip::FltkTooltip (const char *text) : Tooltip(text)
+{
+ shown = false;
+
+ if (!text || !strpbrk(text, "&@")) {
+ escaped_str = NULL;
+ } else {
+ /*
+ * WORKAROUND: ::fltk::Tooltip::tooltip_timeout() makes instance_
+ * if necessary, and immediately uses it. This means that we can't
+ * get our hands on it to set RAW_LABEL until after it has been shown
+ * once. So let's escape the special characters ourselves.
+ */
+ const char *src = text;
+ char *dest = escaped_str = (char *) malloc(strlen(text) * 2 + 1);
+
+ while (*src) {
+ if (*src == '&' || *src == '@')
+ *dest++ = *src;
+ *dest++ = *src++;
+ }
+ *dest = '\0';
+ }
+}
+
+FltkTooltip::~FltkTooltip ()
+{
+ if (shown)
+ ::fltk::Tooltip::exit();
+ if (escaped_str)
+ free(escaped_str);
+}
+
+FltkTooltip *FltkTooltip::create (const char *text)
+{
+ return new FltkTooltip(text);
+}
+
+void FltkTooltip::onEnter()
+{
+ fltk::Widget *widget = fltk::belowmouse();
+
+ ::fltk::Tooltip::enter(widget, *((fltk::Rectangle *)widget),
+ escaped_str ? escaped_str : str);
+ shown = true;
+}
+
+void FltkTooltip::onLeave()
+{
+ ::fltk::Tooltip::exit();
+ shown = false;
+}
+
+void FltkTooltip::onMotion()
+{
}
void FltkView::addFltkWidget (::fltk::Widget *widget,
@@ -187,9 +247,9 @@ core::ui::ListResource *
FltkPlatform::FltkResourceFactory::createListResource (core::ui
::ListResource
::SelectionMode
- selectionMode)
+ selectionMode, int rows)
{
- return new ui::FltkListResource (platform, selectionMode);
+ return new ui::FltkListResource (platform, selectionMode, rows);
}
core::ui::OptionMenuResource *
@@ -200,9 +260,10 @@ FltkPlatform::FltkResourceFactory::createOptionMenuResource ()
core::ui::EntryResource *
FltkPlatform::FltkResourceFactory::createEntryResource (int maxLength,
- bool password)
+ bool password,
+ const char *label)
{
- return new ui::FltkEntryResource (platform, maxLength, password);
+ return new ui::FltkEntryResource (platform, maxLength, password, label);
}
core::ui::MultiLineTextResource *
@@ -238,7 +299,7 @@ FltkPlatform::FltkPlatform ()
idleFuncRunning = false;
idleFuncId = 0;
- views = new container::typed::List <FltkView> (false);
+ view = NULL;
resources = new container::typed::List <ui::FltkResource> (false);
resourceFactory.setPlatform (this);
@@ -246,10 +307,9 @@ FltkPlatform::FltkPlatform ()
FltkPlatform::~FltkPlatform ()
{
- if(idleFuncRunning)
+ if (idleFuncRunning)
remove_idle (generalStaticIdle, (void*)this);
delete idleQueue;
- delete views;
delete resources;
}
@@ -261,34 +321,51 @@ void FltkPlatform::setLayout (core::Layout *layout)
void FltkPlatform::attachView (core::View *view)
{
- views->append ((FltkView*)view);
+ if (this->view)
+ MSG_ERR("FltkPlatform::attachView: multiple views!\n");
+ this->view = (FltkView*)view;
for (container::typed::Iterator <ui::FltkResource> it =
resources->iterator (); it.hasNext (); ) {
ui::FltkResource *resource = it.getNext ();
- resource->attachView ((FltkView*)view);
+ resource->attachView (this->view);
}
}
void FltkPlatform::detachView (core::View *view)
{
- views->removeRef ((FltkView*)view);
+ if (this->view != view)
+ MSG_ERR("FltkPlatform::detachView: this->view: %p view: %p\n",
+ this->view, view);
for (container::typed::Iterator <ui::FltkResource> it =
resources->iterator (); it.hasNext (); ) {
ui::FltkResource *resource = it.getNext ();
resource->detachView ((FltkView*)view);
}
+ this->view = NULL;
}
int FltkPlatform::textWidth (core::style::Font *font, const char *text,
int len)
{
+ int width;
FltkFont *ff = (FltkFont*) font;
setfont (ff->font, ff->size);
- return (int) getwidth (text, len);
+ width = (int) getwidth (text, len);
+
+ if (font->letterSpacing) {
+ int curr = 0, next = 0;
+
+ while (next < len) {
+ next = nextGlyph(text, curr);
+ width += font->letterSpacing;
+ curr = next;
+ }
+ }
+ return width;
}
int FltkPlatform::nextGlyph (const char *text, int idx)
@@ -301,6 +378,16 @@ int FltkPlatform::prevGlyph (const char *text, int idx)
return utf8back (&text[idx - 1], text, &text[strlen (text)]) - text;
}
+float FltkPlatform::dpiX ()
+{
+ return ::fltk::Monitor::all ().dpi_x ();
+}
+
+float FltkPlatform::dpiY ()
+{
+ return ::fltk::Monitor::all ().dpi_y ();
+}
+
void FltkPlatform::generalStaticIdle (void *data)
{
((FltkPlatform*)data)->generalIdle();
@@ -314,12 +401,12 @@ void FltkPlatform::generalIdle ()
/* Execute the first function in the list. */
idleFunc = idleQueue->getFirst ();
(layout->*(idleFunc->func)) ();
-
+
/* Remove this function. */
idleQueue->removeRef(idleFunc);
}
- if(idleQueue->isEmpty()) {
+ if (idleQueue->isEmpty()) {
idleFuncRunning = false;
remove_idle (generalStaticIdle, (void*)this);
}
@@ -334,7 +421,7 @@ int FltkPlatform::addIdle (void (core::Layout::*func) ())
* Since ... (todo) we have to wrap around fltk_add_idle. There is only one
* idle function, the passed idle function is put into a queue.
*/
- if(!idleFuncRunning) {
+ if (!idleFuncRunning) {
add_idle (generalStaticIdle, (void*)this);
idleFuncRunning = true;
}
@@ -355,15 +442,15 @@ void FltkPlatform::removeIdle (int idleId)
container::typed::Iterator <IdleFunc> it;
IdleFunc *idleFunc;
- for(found = false, it = idleQueue->iterator(); !found && it.hasNext(); ) {
+ for (found = false, it = idleQueue->iterator(); !found && it.hasNext(); ) {
idleFunc = it.getNext();
- if(idleFunc->id == idleId) {
+ if (idleFunc->id == idleId) {
idleQueue->removeRef (idleFunc);
found = true;
}
}
- if(idleFuncRunning && idleQueue->isEmpty())
+ if (idleFuncRunning && idleQueue->isEmpty())
remove_idle (generalStaticIdle, (void*)this);
}
@@ -374,14 +461,14 @@ core::style::Font *FltkPlatform::createFont (core::style::FontAttrs
return FltkFont::create (attrs);
}
-core::style::Color *FltkPlatform::createSimpleColor (int color)
+core::style::Color *FltkPlatform::createColor (int color)
{
- return FltkColor::create (color, core::style::Color::TYPE_SIMPLE);
+ return FltkColor::create (color);
}
-core::style::Color *FltkPlatform::createShadedColor (int color)
+core::style::Tooltip *FltkPlatform::createTooltip (const char *text)
{
- return FltkColor::create (color, core::style::Color::TYPE_SHADED);
+ return FltkTooltip::create (text);
}
void FltkPlatform::copySelection(const char *text)
@@ -404,12 +491,7 @@ core::ui::ResourceFactory *FltkPlatform::getResourceFactory ()
void FltkPlatform::attachResource (ui::FltkResource *resource)
{
resources->append (resource);
-
- for (container::typed::Iterator <FltkView> it = views->iterator ();
- it.hasNext (); ) {
- FltkView *view = it.getNext ();
- resource->attachView (view);
- }
+ resource->attachView (view);
}
void FltkPlatform::detachResource (ui::FltkResource *resource)
diff --git a/dw/fltkplatform.hh b/dw/fltkplatform.hh
index 7b3d3e73..7a708938 100644
--- a/dw/fltkplatform.hh
+++ b/dw/fltkplatform.hh
@@ -24,7 +24,7 @@ class FltkFont: public core::style::Font
public:
::fltk::Font *font;
-
+
static FltkFont *create (core::style::FontAttrs *attrs);
};
@@ -34,13 +34,27 @@ class FltkColor: public core::style::Color
static lout::container::typed::HashTable <dw::core::style::ColorAttrs,
FltkColor> *colorsTable;
- FltkColor (int color, core::style::Color::Type type);
+ FltkColor (int color);
~FltkColor ();
public:
int colors[SHADING_NUM];
- static FltkColor *create(int color, core::style::Color::Type type);
+ static FltkColor *create(int color);
+};
+
+class FltkTooltip: public core::style::Tooltip
+{
+private:
+ FltkTooltip (const char *text);
+ ~FltkTooltip ();
+ bool shown;
+ char *escaped_str; /* fltk WORKAROUND */
+public:
+ static FltkTooltip *create(const char *text);
+ void onEnter();
+ void onLeave();
+ void onMotion();
};
@@ -78,10 +92,12 @@ private:
core::ui::ComplexButtonResource *
createComplexButtonResource (core::Widget *widget, bool relief);
core::ui::ListResource *
- createListResource (core::ui::ListResource::SelectionMode selectionMode);
+ createListResource (core::ui::ListResource::SelectionMode selectionMode,
+ int rows);
core::ui::OptionMenuResource *createOptionMenuResource ();
core::ui::EntryResource *createEntryResource (int maxLength,
- bool password);
+ bool password,
+ const char *label);
core::ui::MultiLineTextResource *createMultiLineTextResource (int cols,
int rows);
core::ui::CheckButtonResource *createCheckButtonResource (bool
@@ -109,7 +125,7 @@ private:
static void generalStaticIdle(void *data);
void generalIdle();
- lout::container::typed::List <FltkView> *views;
+ FltkView *view;
lout::container::typed::List <ui::FltkResource> *resources;
public:
@@ -117,23 +133,26 @@ public:
~FltkPlatform ();
void setLayout (core::Layout *layout);
-
+
void attachView (core::View *view);
void detachView (core::View *view);
-
+
int textWidth (core::style::Font *font, const char *text, int len);
int nextGlyph (const char *text, int idx);
int prevGlyph (const char *text, int idx);
-
+ float dpiX ();
+ float dpiY ();
+
int addIdle (void (core::Layout::*func) ());
void removeIdle (int idleId);
-
+
core::style::Font *createFont (core::style::FontAttrs *attrs,
bool tryEverything);
- core::style::Color *createSimpleColor (int color);
- core::style::Color *createShadedColor (int color);
-
+ bool fontExists (const char *name);
+ core::style::Color *createColor (int color);
+ core::style::Tooltip *createTooltip (const char *text);
+
core::Imgbuf *createImgbuf (core::Imgbuf::Type type, int width, int height);
void copySelection(const char *text);
diff --git a/dw/fltkpreview.cc b/dw/fltkpreview.cc
index 6bed7adf..7096420f 100644
--- a/dw/fltkpreview.cc
+++ b/dw/fltkpreview.cc
@@ -14,11 +14,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+#include "../lout/msg.h"
#include "fltkpreview.hh"
#include "fltkmisc.hh"
@@ -104,6 +103,11 @@ void FltkPreview::scrollTo (int x, int y)
scrollY = y;
}
+void FltkPreview::scroll (dw::core::ScrollCommand cmd)
+{
+ MSG_ERR("FltkPreview::scroll not implemented\n");
+}
+
void FltkPreview::setViewportSize (int width, int height,
int hScrollbarThickness,
int vScrollbarThickness)
@@ -155,7 +159,7 @@ bool FltkPreview::usesFltkWidgets ()
return false;
}
-void FltkPreview::drawFltkWidget (Widget *widget,
+void FltkPreview::drawFltkWidget (::fltk::Widget *widget,
core::Rectangle *area)
{
}
@@ -191,7 +195,7 @@ void FltkPreviewWindow::reallocate ()
int mx, my, width, height;
bool warp = false;
- if(preview->canvasHeight * maxWidth > maxHeight * preview->canvasWidth) {
+ if (preview->canvasHeight * maxWidth > maxHeight * preview->canvasWidth) {
// Expand to maximal height (most likely case).
width = preview->canvasWidth * maxHeight / preview->canvasHeight;
height = maxHeight;
@@ -288,7 +292,7 @@ int FltkPreviewButton::handle (int event)
case RELEASE:
window->hideWindow ();
return Button::handle (event);
-
+
default:
return Button::handle (event);
}
diff --git a/dw/fltkpreview.hh b/dw/fltkpreview.hh
index 2464db89..13db2811 100644
--- a/dw/fltkpreview.hh
+++ b/dw/fltkpreview.hh
@@ -34,6 +34,7 @@ public:
int getHScrollbarThickness ();
int getVScrollbarThickness ();
void scrollTo (int x, int y);
+ void scroll (dw::core::ScrollCommand cmd);
void setViewportSize (int width, int height,
int hScrollbarThickness, int vScrollbarThickness);
diff --git a/dw/fltkui.cc b/dw/fltkui.cc
index 9255d7d2..c1bfd873 100644
--- a/dw/fltkui.cc
+++ b/dw/fltkui.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -23,19 +22,18 @@
#include "fltkcore.hh"
#include "fltkflatview.hh"
#include "fltkcomplexbutton.hh"
+#include "../lout/msg.h"
#include "../lout/misc.hh"
#include <stdio.h>
#include <fltk/Widget.h>
#include <fltk/Group.h>
#include <fltk/Input.h>
-#include <fltk/SecretInput.h>
#include <fltk/TextEditor.h>
#include <fltk/RadioButton.h>
#include <fltk/CheckButton.h>
#include <fltk/Choice.h>
#include <fltk/Browser.h>
-#include <fltk/MultiBrowser.h>
#include <fltk/Font.h>
#include <fltk/draw.h>
#include <fltk/Symbol.h>
@@ -49,8 +47,8 @@ namespace ui {
enum { RELIEF_X_THICKNESS = 3, RELIEF_Y_THICKNESS = 3 };
-using namespace object;
-using namespace container::typed;
+using namespace lout::object;
+using namespace lout::container::typed;
FltkResource::FltkResource (FltkPlatform *platform)
{
@@ -63,6 +61,8 @@ FltkResource::FltkResource (FltkPlatform *platform)
allocation.descent = 0;
style = NULL;
+
+ enabled = true;
}
/**
@@ -71,98 +71,72 @@ FltkResource::FltkResource (FltkPlatform *platform)
*/
void FltkResource::init (FltkPlatform *platform)
{
- viewsAndWidgets = new container::typed::List <ViewAndWidget> (true);
+ view = NULL;
+ widget = NULL;
platform->attachResource (this);
}
FltkResource::~FltkResource ()
{
platform->detachResource (this);
- for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
- it.hasNext(); ) {
- ViewAndWidget *viewAndWidget = it.getNext ();
-
- if (viewAndWidget->widget) {
- if (viewAndWidget->view) {
- viewAndWidget->view->removeFltkWidget(viewAndWidget->widget);
- }
- delete viewAndWidget->widget;
+ if (widget) {
+ if (view) {
+ view->removeFltkWidget(widget);
}
-
+ delete widget;
}
- delete viewsAndWidgets;
- if(style)
+ if (style)
style->unref ();
}
void FltkResource::attachView (FltkView *view)
{
+ if (this->view)
+ MSG_ERR("FltkResource::attachView: multiple views!\n");
+
if (view->usesFltkWidgets ()) {
- ViewAndWidget *viewAndWidget = new ViewAndWidget();
- viewAndWidget->view = view;
-
- viewAndWidget->widget = createNewWidget (&allocation);
- viewAndWidget->view->addFltkWidget (viewAndWidget->widget, &allocation);
- viewsAndWidgets->append (viewAndWidget);
+ this->view = view;
+
+ widget = createNewWidget (&allocation);
+ view->addFltkWidget (widget, &allocation);
if (style)
- setWidgetStyle (viewAndWidget->widget, style);
+ setWidgetStyle (widget, style);
+ if (! enabled)
+ widget->deactivate ();
}
}
void FltkResource::detachView (FltkView *view)
{
- for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
- it.hasNext(); ) {
- ViewAndWidget *viewAndWidget = it.getNext ();
- if (viewAndWidget->view == view) {
- viewsAndWidgets->removeRef (viewAndWidget);
- return;
- }
- }
-
- fprintf (stderr, "FltkResource::detachView: View not found.");
+ if (this->view != view)
+ MSG_ERR("FltkResource::detachView: this->view: %p view: %p\n",
+ this->view, view);
+ this->view = NULL;
}
void FltkResource::sizeAllocate (core::Allocation *allocation)
{
this->allocation = *allocation;
-
- for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
- it.hasNext(); ) {
- ViewAndWidget *viewAndWidget = it.getNext ();
- viewAndWidget->view->allocateFltkWidget (viewAndWidget->widget,
- allocation);
- }
+ view->allocateFltkWidget (widget, allocation);
}
void FltkResource::draw (core::View *view, core::Rectangle *area)
{
FltkView *fltkView = (FltkView*)view;
- if (fltkView->usesFltkWidgets ()) {
- for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
- it.hasNext(); ) {
- ViewAndWidget *viewAndWidget = it.getNext ();
- if (viewAndWidget->view == fltkView) {
- fltkView->drawFltkWidget (viewAndWidget->widget, area);
- break;
- }
- }
+ if (fltkView->usesFltkWidgets () && this->view == fltkView) {
+ fltkView->drawFltkWidget (widget, area);
}
}
void FltkResource::setStyle (core::style::Style *style)
{
- if(this->style)
+ if (this->style)
this->style->unref ();
this->style = style;
style->ref ();
- for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
- it.hasNext(); ) {
- ViewAndWidget *viewAndWidget = it.getNext ();
- setWidgetStyle (viewAndWidget->widget, style);
- }
+ setWidgetStyle (widget, style);
}
void FltkResource::setWidgetStyle (::fltk::Widget *widget,
@@ -176,39 +150,62 @@ void FltkResource::setWidgetStyle (::fltk::Widget *widget,
FltkColor *bg = (FltkColor*)style->backgroundColor;
if (bg) {
+ int normal_bg = bg->colors[FltkColor::SHADING_NORMAL];
+
if (style->color) {
- /*
- * TODO: if/when CSS is implemented, test whether style->color
- * will consistently provide readable widgets.
- */
- int32_t c = bg->colors[FltkColor::SHADING_NORMAL];
- int r = (c >> 24) & 0xff, g = (c >> 16) & 0xff, b = (c >> 8) & 0xff;
- bool light = (r + g >= 0x150) || (r + g + b >= 0x180);
-
- widget->labelcolor(light? ::fltk::BLACK : ::fltk::WHITE);
- widget->textcolor(light? ::fltk::BLACK : ::fltk::WHITE);
- widget->selection_color(light? ::fltk::BLACK : ::fltk::WHITE);
+ int style_fg = ((FltkColor*)style->color)->colors
+ [FltkColor::SHADING_NORMAL];
+ ::fltk::Color fg = ::fltk::contrast(style_fg, normal_bg);
+
+ widget->labelcolor(fg);
+ widget->textcolor(fg);
+ widget->selection_color(fg);
}
- widget->color(bg->colors[FltkColor::SHADING_NORMAL]);
- widget->buttoncolor(bg->colors[FltkColor::SHADING_NORMAL]);
- widget->selection_textcolor(bg->colors[FltkColor::SHADING_NORMAL]);
- if (!(widget->type() & (::fltk::Widget::RADIO|::fltk::Widget::TOGGLE))) {
+ widget->color(normal_bg);
+ widget->buttoncolor(normal_bg);
+ widget->selection_textcolor(normal_bg);
+ if (widget->type() != ::fltk::Widget::RADIO &&
+ widget->type() != ::fltk::Widget::TOGGLE) {
/* it looks awful to highlight the buttons */
widget->highlight_color(bg->colors[FltkColor::SHADING_LIGHT]);
}
}
}
-
+
+void FltkResource::setDisplayed(bool displayed)
+{
+ if (displayed)
+ widget->show();
+ else
+ widget->hide();
+}
+
+bool FltkResource::displayed()
+{
+ bool ret = false;
+
+ if (widget) {
+ // visible() is not the same thing as being show()n exactly, but
+ // show()/hide() set it appropriately for our purposes.
+ ret = widget->visible();
+ }
+ return ret;
+}
+
bool FltkResource::isEnabled ()
{
- /** \bug Not implemented. */
- return true;
+ return enabled;
}
void FltkResource::setEnabled (bool enabled)
{
- /** \bug Not implemented. */
+ this->enabled = enabled;
+
+ if (enabled)
+ widget->activate ();
+ else
+ widget->deactivate ();
}
// ----------------------------------------------------------------------
@@ -286,11 +283,47 @@ void FltkLabelButtonResource::sizeRequest (core::Requisition *requisition)
}
}
+/*
+ * Get FLTK state and translate to dw
+ *
+ * TODO: find a good home for this and the fltkviewbase.cc original.
+ */
+static core::ButtonState getDwButtonState ()
+{
+ int s1 = ::fltk::event_state ();
+ int s2 = (core::ButtonState)0;
+
+ if (s1 & ::fltk::SHIFT) s2 |= core::SHIFT_MASK;
+ if (s1 & ::fltk::CTRL) s2 |= core::CONTROL_MASK;
+ if (s1 & ::fltk::ALT) s2 |= core::META_MASK;
+ if (s1 & ::fltk::BUTTON1) s2 |= core::BUTTON1_MASK;
+ if (s1 & ::fltk::BUTTON2) s2 |= core::BUTTON2_MASK;
+ if (s1 & ::fltk::BUTTON3) s2 |= core::BUTTON3_MASK;
+
+ return (core::ButtonState)s2;
+}
+
+static void setButtonEvent(dw::core::EventButton *event)
+{
+ event->xCanvas = ::fltk::event_x();
+ event->yCanvas = ::fltk::event_y();
+ event->state = getDwButtonState();
+ event->button = ::fltk::event_button();
+ event->numPressed = ::fltk::event_clicks() + 1;
+}
+
void FltkLabelButtonResource::widgetCallback (::fltk::Widget *widget,
void *data)
{
- if (widget->when () & ::fltk::WHEN_RELEASE)
- ((FltkLabelButtonResource*)data)->emitActivate ();
+ if ((widget->when () & ::fltk::WHEN_RELEASE) &&
+ ((::fltk::event_key() == ::fltk::ReturnKey) ||
+ (::fltk::event_button() == ::fltk::LeftButton ||
+ ::fltk::event_button() == ::fltk::MiddleButton))) {
+ FltkLabelButtonResource *lbr = (FltkLabelButtonResource*) data;
+ dw::core::EventButton event;
+ setButtonEvent(&event);
+ lbr->emitClicked(&event);
+ }
}
const char *FltkLabelButtonResource::getLabel ()
@@ -304,12 +337,7 @@ void FltkLabelButtonResource::setLabel (const char *label)
delete this->label;
this->label = strdup (label);
- for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
- it.hasNext(); ) {
- ViewAndWidget *viewAndWidget = it.getNext ();
- viewAndWidget->widget->label (this->label);
- }
-
+ widget->label (this->label);
queueResize (true);
}
@@ -320,7 +348,7 @@ FltkComplexButtonResource::FltkComplexButtonResource (FltkPlatform *platform,
*widget, bool relief):
FltkSpecificResource <dw::core::ui::ComplexButtonResource> (platform)
{
- viewsAndViews = new container::typed::List <ViewAndView> (true);
+ flatView = topView = NULL;
this->relief = relief;
FltkResource::init (platform);
ComplexButtonResource::init (widget);
@@ -328,7 +356,6 @@ FltkComplexButtonResource::FltkComplexButtonResource (FltkPlatform *platform,
FltkComplexButtonResource::~FltkComplexButtonResource ()
{
- delete viewsAndViews;
}
void FltkComplexButtonResource::widgetCallback (::fltk::Widget *widget,
@@ -336,14 +363,17 @@ void FltkComplexButtonResource::widgetCallback (::fltk::Widget *widget,
{
FltkComplexButtonResource *res = (FltkComplexButtonResource*)data;
- /* would be best not to send click pos. if the image could not be loaded */
- if (::fltk::event() == ::fltk::RELEASE &&
- ::fltk::event_button() == ::fltk::LeftButton) {
+ if (widget->when() == ::fltk::WHEN_RELEASE &&
+ ((::fltk::event_key() == ::fltk::ReturnKey) ||
+ (::fltk::event_button() == ::fltk::LeftButton ||
+ ::fltk::event_button() == ::fltk::MiddleButton))) {
res->click_x = ::fltk::event_x();
res->click_y = ::fltk::event_y();
- res->emitActivate ();
+ dw::core::EventButton event;
+ setButtonEvent(&event);
+ res->emitClicked(&event);
} else {
- ((FltkViewBase*)res->lastFlatView)->handle(::fltk::event());
+ ((FltkViewBase*)res->flatView)->handle(::fltk::event());
}
}
@@ -356,56 +386,30 @@ void FltkComplexButtonResource::attachView (FltkView *view)
{
FltkResource::attachView (view);
- if (view->usesFltkWidgets ()) {
- ViewAndView *viewAndView = new ViewAndView();
- viewAndView->topView = view;
- viewAndView->flatView = lastFlatView;
- viewsAndViews->append (viewAndView);
- }
+ if (view->usesFltkWidgets ())
+ topView = view;
}
void FltkComplexButtonResource::detachView (FltkView *view)
{
FltkResource::detachView (view);
-
- for (Iterator <ViewAndView> it = viewsAndViews->iterator ();
- it.hasNext(); ) {
- ViewAndView *viewAndView = it.getNext ();
- if (viewAndView->topView == view) {
- viewsAndViews->removeRef (viewAndView);
- return;
- }
- }
-
- fprintf (stderr,
- "FltkComplexButtonResourceResource::detachView: View not "
- "found.\n");
}
void FltkComplexButtonResource::sizeAllocate (core::Allocation *allocation)
{
FltkResource::sizeAllocate (allocation);
- for (Iterator <ViewAndView> it = viewsAndViews->iterator ();
- it.hasNext(); ) {
- ViewAndView *viewAndView = it.getNext ();
- ((FltkFlatView*)viewAndView->flatView)->resize (
- reliefXThickness (),
- reliefYThickness (),
- allocation->width - 2 * reliefXThickness (),
- allocation->ascent + allocation->descent - 2 * reliefYThickness ());
-
- ((FltkFlatView*)viewAndView->flatView)->parent ()->init_sizes ();
- }
+ ((FltkFlatView*)flatView)->resize (
+ reliefXThickness (), reliefYThickness (),
+ allocation->width - 2 * reliefXThickness (),
+ allocation->ascent + allocation->descent - 2 * reliefYThickness ());
+
+ ((FltkFlatView*)flatView)->parent ()->init_sizes ();
}
void FltkComplexButtonResource::setLayout (dw::core::Layout *layout)
{
- for (Iterator <ViewAndView> it = viewsAndViews->iterator ();
- it.hasNext(); ) {
- ViewAndView *viewAndView = it.getNext ();
- layout->attachView (viewAndView->flatView);
- }
+ layout->attachView (flatView);
}
int FltkComplexButtonResource::reliefXThickness ()
@@ -430,30 +434,28 @@ int FltkComplexButtonResource::reliefYThickness ()
if (!relief)
button->box(::fltk::FLAT_BOX);
- FltkFlatView *flatView =
- new FltkFlatView (allocation->x + reliefXThickness (),
- allocation->y + reliefYThickness (),
- allocation->width - 2 * reliefXThickness (),
- allocation->ascent + allocation->descent
- - 2 * reliefYThickness ());
- button->add (flatView);
-
- lastFlatView = flatView;
+ flatView = new FltkFlatView (allocation->x + reliefXThickness (),
+ allocation->y + reliefYThickness (),
+ allocation->width - 2 * reliefXThickness (),
+ allocation->ascent + allocation->descent
+ - 2 * reliefYThickness ());
+ button->add ((FltkFlatView *)flatView);
if (layout)
- layout->attachView (lastFlatView);
+ layout->attachView (flatView);
return button;
}
// ----------------------------------------------------------------------
FltkEntryResource::FltkEntryResource (FltkPlatform *platform, int maxLength,
- bool password):
+ bool password, const char *label):
FltkSpecificResource <dw::core::ui::EntryResource> (platform)
{
this->maxLength = maxLength;
this->password = password;
-
+ this->label = label ? strdup(label) : NULL;
+
initText = NULL;
editable = false;
@@ -464,46 +466,51 @@ FltkEntryResource::~FltkEntryResource ()
{
if (initText)
delete initText;
+ if (label)
+ delete label;
}
::fltk::Widget *FltkEntryResource::createNewWidget (core::Allocation
*allocation)
{
::fltk::Input *input =
- password ?
- new ::fltk::SecretInput (allocation->x, allocation->y,
- allocation->width,
- allocation->ascent + allocation->descent) :
new ::fltk::Input (allocation->x, allocation->y, allocation->width,
allocation->ascent + allocation->descent);
+ if (password)
+ input->type(::fltk::Input::SECRET);
input->callback (widgetCallback, this);
input->when (::fltk::WHEN_ENTER_KEY_ALWAYS);
- if (viewsAndWidgets->isEmpty ()) {
- // First widget created, attach the set text.
- if (initText)
- input->value (initText);
- } else
- input->value
- (((::fltk::Input*)viewsAndWidgets->getFirst()->widget)->value ());
+ if (label) {
+ input->label(label);
+ input->set_flag(::fltk::ALIGN_INSIDE_LEFT);
+ }
+ if (initText)
+ input->value (initText);
return input;
}
+void FltkEntryResource::setDisplayed(bool displayed)
+{
+ FltkResource::setDisplayed(displayed);
+ queueResize(true);
+}
+
void FltkEntryResource::sizeRequest (core::Requisition *requisition)
{
- if (style) {
+ if (displayed() && style) {
FltkFont *font = (FltkFont*)style->font;
::fltk::setfont(font->font,font->size);
requisition->width =
- (int)::fltk::getwidth ("M", 1)
+ (int)::fltk::getwidth ("n", 1)
* (maxLength == UNLIMITED_MAX_LENGTH ? 10 : maxLength)
+ 2 * RELIEF_X_THICKNESS;
requisition->ascent = font->ascent + RELIEF_Y_THICKNESS;
requisition->descent = font->descent + RELIEF_Y_THICKNESS;
} else {
- requisition->width = 1;
- requisition->ascent = 1;
+ requisition->width = 0;
+ requisition->ascent = 0;
requisition->descent = 0;
}
}
@@ -517,7 +524,7 @@ void FltkEntryResource::widgetCallback (::fltk::Widget *widget,
* The Back or Forward, buttons, or the first click on a rendered
* page. BUG: this must be investigated and reported to FLTK2 team
*/
- printf ("when = %d\n", widget->when ());
+ MSG("when = %d\n", widget->when ());
if ((widget->when () & ::fltk::WHEN_ENTER_KEY_ALWAYS) &&
(::fltk::event_key() == ::fltk::ReturnKey))
((FltkEntryResource*)data)->emitActivate ();
@@ -525,10 +532,7 @@ void FltkEntryResource::widgetCallback (::fltk::Widget *widget,
const char *FltkEntryResource::getText ()
{
- if (viewsAndWidgets->isEmpty ())
- return initText;
- else
- return ((::fltk::Input*)viewsAndWidgets->getFirst()->widget)->value ();
+ return ((::fltk::Input*)widget)->value ();
}
void FltkEntryResource::setText (const char *text)
@@ -537,11 +541,7 @@ void FltkEntryResource::setText (const char *text)
delete initText;
initText = strdup (text);
- for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
- it.hasNext(); ) {
- ViewAndWidget *viewAndWidget = it.getNext ();
- ((::fltk::Input*)viewAndWidget->widget)->value (initText);
- }
+ ((::fltk::Input*)widget)->value (initText);
}
bool FltkEntryResource::isEditable ()
@@ -557,7 +557,7 @@ void FltkEntryResource::setEditable (bool editable)
// ----------------------------------------------------------------------
FltkMultiLineTextResource::FltkMultiLineTextResource (FltkPlatform *platform,
- int cols, int rows):
+ int cols, int rows):
FltkSpecificResource <dw::core::ui::MultiLineTextResource> (platform)
{
buffer = new ::fltk::TextBuffer;
@@ -568,11 +568,11 @@ FltkMultiLineTextResource::FltkMultiLineTextResource (FltkPlatform *platform,
// Check values. Upper bound check is left to the caller.
if (numCols < 1) {
- fprintf (stderr, "WARNING: numCols = %d is set to 1.\n", numCols);
+ MSG_WARN("numCols = %d is set to 1.\n", numCols);
numCols = 1;
}
if (numRows < 1) {
- fprintf (stderr, "WARNING: numRows = %d is set to 1.\n", numRows);
+ MSG_WARN("numRows = %d is set to 1.\n", numRows);
numRows = 1;
}
@@ -582,11 +582,7 @@ FltkMultiLineTextResource::FltkMultiLineTextResource (FltkPlatform *platform,
FltkMultiLineTextResource::~FltkMultiLineTextResource ()
{
/* Free memory avoiding a double-free of text buffers */
- for (Iterator <ViewAndWidget> it = viewsAndWidgets->iterator ();
- it.hasNext(); ) {
- ViewAndWidget *viewAndWidget = it.getNext ();
- ((::fltk::TextEditor *) viewAndWidget->widget)->buffer (0);
- }
+ ((::fltk::TextEditor *) widget)->buffer (0);
delete buffer;
}
@@ -607,13 +603,13 @@ void FltkMultiLineTextResource::sizeRequest (core::Requisition *requisition)
FltkFont *font = (FltkFont*)style->font;
::fltk::setfont(font->font,font->size);
requisition->width =
- (int)::fltk::getwidth ("X", 1) * numCols +
+ (int)::fltk::getwidth ("n", 1) * numCols +
2 * RELIEF_X_THICKNESS;
requisition->ascent =
- font->ascent + RELIEF_Y_THICKNESS;
+ RELIEF_Y_THICKNESS + font->ascent +
+ (font->ascent + font->descent) * (numRows - 1);
requisition->descent =
font->descent +
- (font->ascent + font->descent) * (numRows - 1) +
RELIEF_Y_THICKNESS;
} else {
requisition->width = 1;
@@ -647,7 +643,7 @@ void FltkMultiLineTextResource::setEditable (bool editable)
template <class I>
FltkToggleButtonResource<I>::FltkToggleButtonResource (FltkPlatform *platform,
bool activated):
- FltkSpecificResource <I> (platform)
+ FltkSpecificResource <I> (platform)
{
initActivated = activated;
}
@@ -664,13 +660,7 @@ template <class I>
*allocation)
{
::fltk::Button *button = createNewButton (allocation);
-
- if (this->viewsAndWidgets->isEmpty ())
- button->value (initActivated);
- else
- button->value (((::fltk::Button*)this->viewsAndWidgets
- ->getFirst()->widget)->value ());
-
+ button->value (initActivated);
return button;
}
@@ -697,12 +687,7 @@ void FltkToggleButtonResource<I>::sizeRequest (core::Requisition *requisition)
template <class I>
bool FltkToggleButtonResource<I>::FltkToggleButtonResource::isActivated ()
{
- if (this->viewsAndWidgets->isEmpty ())
- return initActivated;
- else
- return
- ((::fltk::Button*)this->viewsAndWidgets->getFirst()->widget)
- ->value ();
+ return ((::fltk::Button*)this->widget)->value ();
}
@@ -710,13 +695,7 @@ template <class I>
void FltkToggleButtonResource<I>::setActivated (bool activated)
{
initActivated = activated;
-
- for (Iterator <FltkResource::ViewAndWidget> it =
- this->viewsAndWidgets->iterator ();
- it.hasNext(); ) {
- FltkResource::ViewAndWidget *viewAndWidget = it.getNext ();
- ((::fltk::Button*)viewAndWidget->widget)->value (initActivated);
- }
+ ((::fltk::Button*)this->widget)->value (initActivated);
}
// ----------------------------------------------------------------------
@@ -736,7 +715,7 @@ FltkCheckButtonResource::~FltkCheckButtonResource ()
::fltk::Button *FltkCheckButtonResource::createNewButton (core::Allocation
- *allocation)
+ *allocation)
{
::fltk::CheckButton *cb =
new ::fltk::CheckButton (allocation->x, allocation->y, allocation->width,
@@ -767,7 +746,7 @@ void FltkRadioButtonResource::Group::FltkGroupIterator::unref ()
FltkRadioButtonResource::Group::Group (FltkRadioButtonResource
*radioButtonResource)
{
- list = new container::typed::List <FltkRadioButtonResource> (false);
+ list = new lout::container::typed::List <FltkRadioButtonResource> (false);
connect (radioButtonResource);
}
@@ -775,7 +754,7 @@ FltkRadioButtonResource::Group::~Group ()
{
delete list;
}
-
+
void FltkRadioButtonResource::Group::connect (FltkRadioButtonResource
*radioButtonResource)
{
@@ -836,7 +815,7 @@ void FltkRadioButtonResource::buttonClicked ()
}
::fltk::Button *FltkRadioButtonResource::createNewButton (core::Allocation
- *allocation)
+ *allocation)
{
/*
* Groups of fltk::RadioButton must be added to one fltk::Group, which is
@@ -1025,7 +1004,7 @@ template <class I> void FltkSelectionResource<I>::addItem (const char *str,
}
}
}
-
+
template <class I> void FltkSelectionResource<I>::pushGroup (const char *name,
bool enabled)
{
@@ -1038,7 +1017,7 @@ template <class I> void FltkSelectionResource<I>::pushGroup (const char *name,
::fltk::ItemGroup *group = item->createNewGroupWidget ();
widgetStack->stack->getTop()->getTypedValue()->add (group);
widgetStack->stack->push (new TypedPointer < ::fltk::Menu> (group));
- if(!enabled)
+ if (!enabled)
group->deactivate ();
}
}
@@ -1123,7 +1102,7 @@ void FltkOptionMenuResource::sizeRequest (core::Requisition *requisition)
requisition->width = 1;
requisition->ascent = 1;
requisition->descent = 0;
- }
+ }
}
void FltkOptionMenuResource::addItem (const char *str,
@@ -1146,10 +1125,12 @@ bool FltkOptionMenuResource::isSelected (int index)
FltkListResource::FltkListResource (FltkPlatform *platform,
core::ui::ListResource::SelectionMode
- selectionMode):
+ selectionMode, int rowCount):
FltkSelectionResource <dw::core::ui::ListResource> (platform),
itemsSelected(8)
{
+ mode = selectionMode;
+ showRows = rowCount;
init (platform);
}
@@ -1161,9 +1142,10 @@ FltkListResource::~FltkListResource ()
::fltk::Menu *FltkListResource::createNewMenu (core::Allocation *allocation)
{
::fltk::Menu *menu =
- new ::fltk::MultiBrowser (allocation->x, allocation->y,
- allocation->width,
- allocation->ascent + allocation->descent);
+ new ::fltk::Browser (allocation->x, allocation->y, allocation->width,
+ allocation->ascent + allocation->descent);
+ if (mode == SELECTION_MULTIPLE)
+ menu->type(::fltk::Browser::MULTI);
menu->set_flag (::fltk::RAW_LABEL);
menu->callback(widgetCallback,this);
menu->when(::fltk::WHEN_CHANGED);
@@ -1173,10 +1155,25 @@ FltkListResource::~FltkListResource ()
void FltkListResource::widgetCallback (::fltk::Widget *widget, void *data)
{
::fltk::Widget *fltkItem = ((::fltk::Menu *) widget)->item ();
- int index = (long) (fltkItem->user_data ());
+ int index = -1;
+ if (fltkItem)
+ index = (long) (fltkItem->user_data ());
if (index > -1) {
- bool selected = fltkItem->selected ();
- ((FltkListResource *) data)->itemsSelected.set (index, selected);
+ /* A MultiBrowser will trigger a callback for each item that is
+ * selected and each item that is deselected, but a "plain"
+ * Browser will only trigger the callback for the newly selected item
+ * (for which selected() is false, incidentally).
+ */
+ FltkListResource *res = (FltkListResource *) data;
+ if (res->mode == SELECTION_MULTIPLE) {
+ bool selected = fltkItem->selected ();
+ res->itemsSelected.set (index, selected);
+ } else {
+ int size = res->itemsSelected.size();
+ for (int i = 0; i < size; i++)
+ res->itemsSelected.set (i, false);
+ res->itemsSelected.set (index, true);
+ }
}
}
@@ -1195,18 +1192,24 @@ void FltkListResource::sizeRequest (core::Requisition *requisition)
if (style) {
FltkFont *font = (FltkFont*)style->font;
::fltk::setfont(font->font,font->size);
- int maxStringWidth = getMaxStringWidth ();
- requisition->ascent = font->ascent + RELIEF_Y_THICKNESS;
- requisition->descent =
- (getNumberOfItems () - 1) * (font->ascent) + font->descent;
- requisition->width = maxStringWidth
- + (font->ascent + font->descent) * 4 / 5
- + 2 * RELIEF_X_THICKNESS;
+ int rows = getNumberOfItems();
+ if (showRows < rows) {
+ rows = showRows;
+ }
+ /*
+ * The widget sometimes shows scrollbars when they are not required.
+ * The following values try to keep any scrollbars from obscuring
+ * options, at the cost of showing too much whitespace at times.
+ */
+ requisition->width = getMaxStringWidth() + 24;
+ requisition->ascent = font->ascent + 2 +
+ (rows - 1) * (font->ascent + font->descent + 1);
+ requisition->descent = font->descent + 3;
} else {
requisition->width = 1;
requisition->ascent = 1;
requisition->descent = 0;
- }
+ }
}
bool FltkListResource::isSelected (int index)
diff --git a/dw/fltkui.hh b/dw/fltkui.hh
index 4de99d27..245d5aad 100644
--- a/dw/fltkui.hh
+++ b/dw/fltkui.hh
@@ -14,8 +14,6 @@
namespace dw {
namespace fltk {
-using namespace lout;
-
/**
* \brief FLTK implementation of dw::core::ui.
*
@@ -27,7 +25,7 @@ using namespace lout;
* edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica,
* labelfontsize=10, color="#404040", labelfontcolor="#000080"];
* fontname=Helvetica; fontsize=10;
- *
+ *
* subgraph cluster_core {
* style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
* label="dw::core::ui";
@@ -67,10 +65,10 @@ using namespace lout;
* dw::core::ui::Resource is ambiguous for
* dw::fltk::ui::FltkLabelButtonResource.
*
- * To solve this, we have to remove the depencency between
+ * To solve this, we have to remove the dependency between
* dw::fltk::ui::FltkResource and dw::core::ui::Resource, instead, the part
* of dw::core::ui::Resource, which is implemented in
- * dw::fltk::ui::FltkResource, must be explicitely delegated from
+ * dw::fltk::ui::FltkResource, must be explicitly delegated from
* dw::fltk::ui::FltkLabelButtonResourceto dw::fltk::ui::FltkResource:
*
* \dot
@@ -79,7 +77,7 @@ using namespace lout;
* edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica,
* labelfontsize=10, color="#404040", labelfontcolor="#000080"];
* fontname=Helvetica; fontsize=10;
- *
+ *
* subgraph cluster_core {
* style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
* label="dw::core::ui";
@@ -120,7 +118,7 @@ using namespace lout;
* edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica,
* labelfontsize=10, color="#404040", labelfontcolor="#000080"];
* fontname=Helvetica; fontsize=10;
- *
+ *
* subgraph cluster_core {
* style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
* label="dw::core::ui";
@@ -174,17 +172,14 @@ namespace ui {
/**
* ...
*/
-class FltkResource: public object::Object
+class FltkResource: public lout::object::Object
{
-protected:
- class ViewAndWidget: public object::Object
- {
- public:
- FltkView *view;
- ::fltk::Widget *widget;
- };
+private:
+ bool enabled;
- container::typed::List <ViewAndWidget> *viewsAndWidgets;
+protected:
+ FltkView *view;
+ ::fltk::Widget *widget;
core::Allocation allocation;
FltkPlatform *platform;
@@ -195,12 +190,14 @@ protected:
virtual ::fltk::Widget *createNewWidget (core::Allocation *allocation) = 0;
void setWidgetStyle (::fltk::Widget *widget, core::style::Style *style);
+ void setDisplayed (bool displayed);
+ bool displayed();
public:
~FltkResource ();
virtual void attachView (FltkView *view);
virtual void detachView (FltkView *view);
-
+
void sizeAllocate (core::Allocation *allocation);
void draw (core::View *view, core::Rectangle *area);
@@ -257,15 +254,7 @@ private:
static void widgetCallback (::fltk::Widget *widget, void *data);
protected:
- class ViewAndView: public object::Object
- {
- public:
- FltkView *topView, *flatView;
- };
-
- FltkView *lastFlatView;
-
- container::typed::List <ViewAndView> *viewsAndViews;
+ FltkView *topView, *flatView;
void attachView (FltkView *view);
void detachView (FltkView *view);
@@ -274,7 +263,7 @@ protected:
dw::core::Platform *createPlatform ();
void setLayout (dw::core::Layout *layout);
-
+
int reliefXThickness ();
int reliefYThickness ();
@@ -298,15 +287,18 @@ private:
int maxLength;
bool password;
const char *initText;
+ char *label;
bool editable;
static void widgetCallback (::fltk::Widget *widget, void *data);
+ void setDisplayed (bool displayed);
protected:
::fltk::Widget *createNewWidget (core::Allocation *allocation);
public:
- FltkEntryResource (FltkPlatform *platform, int maxLength, bool password);
+ FltkEntryResource (FltkPlatform *platform, int maxLength, bool password,
+ const char *label);
~FltkEntryResource ();
void sizeRequest (core::Requisition *requisition);
@@ -351,7 +343,7 @@ private:
protected:
virtual ::fltk::Button *createNewButton (core::Allocation *allocation) = 0;
::fltk::Widget *createNewWidget (core::Allocation *allocation);
-
+
public:
FltkToggleButtonResource (FltkPlatform *platform,
bool activated);
@@ -388,10 +380,10 @@ private:
public dw::core::ui::RadioButtonResource::GroupIterator
{
private:
- container::typed::Iterator <FltkRadioButtonResource> it;
+ lout::container::typed::Iterator <FltkRadioButtonResource> it;
public:
- inline FltkGroupIterator (container::typed::List
+ inline FltkGroupIterator (lout::container::typed::List
<FltkRadioButtonResource>
*list)
{ it = list->iterator (); }
@@ -401,15 +393,15 @@ private:
void unref ();
};
- container::typed::List <FltkRadioButtonResource> *list;
+ lout::container::typed::List <FltkRadioButtonResource> *list;
protected:
~Group ();
public:
Group (FltkRadioButtonResource *radioButtonResource);
-
- inline container::typed::Iterator <FltkRadioButtonResource> iterator ()
+
+ inline lout::container::typed::Iterator <FltkRadioButtonResource> iterator ()
{
return list->iterator ();
}
@@ -446,7 +438,7 @@ template <class I> class FltkSelectionResource:
public FltkSpecificResource <I>
{
protected:
- class Item: public object::Object
+ class Item: public lout::object::Object
{
public:
enum Type { ITEM, START, END } type;
@@ -462,19 +454,19 @@ protected:
::fltk::ItemGroup *createNewGroupWidget ();
};
- class WidgetStack: public object::Object
+ class WidgetStack: public lout::object::Object
{
public:
::fltk::Menu *widget;
- container::typed::Stack <object::TypedPointer < ::fltk::Menu> > *stack;
+ lout::container::typed::Stack <lout::object::TypedPointer < ::fltk::Menu> > *stack;
WidgetStack (::fltk::Menu *widget);
~WidgetStack ();
};
- container::typed::List <WidgetStack> *widgetStacks;
- container::typed::List <Item> *allItems;
- container::typed::Vector <Item> *items;
+ lout::container::typed::List <WidgetStack> *widgetStacks;
+ lout::container::typed::List <Item> *allItems;
+ lout::container::typed::Vector <Item> *items;
Item *createNewItem (typename Item::Type type,
const char *name = NULL,
@@ -491,10 +483,10 @@ public:
FltkSelectionResource (FltkPlatform *platform);
~FltkSelectionResource ();
- dw::core::Iterator *iterator (dw::core::Content::Type mask, bool atEnd);
+ dw::core::Iterator *iterator (dw::core::Content::Type mask, bool atEnd);
void addItem (const char *str, bool enabled, bool selected);
-
+
void pushGroup (const char *name, bool enabled);
void popGroup ();
@@ -532,11 +524,13 @@ protected:
private:
static void widgetCallback (::fltk::Widget *widget, void *data);
- misc::SimpleVector <bool> itemsSelected;
-
+ lout::misc::SimpleVector <bool> itemsSelected;
+ int showRows;
+ ListResource::SelectionMode mode;
public:
FltkListResource (FltkPlatform *platform,
- core::ui::ListResource::SelectionMode selectionMode);
+ core::ui::ListResource::SelectionMode selectionMode,
+ int rows);
~FltkListResource ();
void addItem (const char *str, bool enabled, bool selected);
diff --git a/dw/fltkviewbase.cc b/dw/fltkviewbase.cc
index b35b07df..7d519f05 100644
--- a/dw/fltkviewbase.cc
+++ b/dw/fltkviewbase.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -30,6 +29,7 @@
#include <fltk/run.h>
#include <stdio.h>
+#include "../lout/msg.h"
using namespace fltk;
using namespace lout::object;
@@ -47,9 +47,8 @@ FltkViewBase::FltkViewBase (int x, int y, int w, int h, const char *label):
canvasWidth = 1;
canvasHeight = 1;
bgColor = WHITE;
- lastDraw = time(0);
- drawDelay = 2; /* in seconds */
mouse_x = mouse_y = 0;
+ exposeArea = NULL;
if (backBuffer == NULL) {
backBuffer = new Image ();
}
@@ -74,10 +73,10 @@ void FltkViewBase::draw ()
int d = damage ();
if ((d & DAMAGE_VALUE) && !(d & DAMAGE_EXPOSE)) {
- container::typed::Iterator <core::Rectangle> it;
+ lout::container::typed::Iterator <core::Rectangle> it;
for (it = drawRegion.rectangles (); it.hasNext (); ) {
- drawRectangle (it.getNext (), true);
+ draw (it.getNext (), DRAW_BUFFERED);
}
drawRegion.clear ();
@@ -96,16 +95,18 @@ void FltkViewBase::draw ()
w (),
h ());
- drawRectangle (&rect, false);
-
- if (! (d & DAMAGE_SCROLL)) {
+ if (d == DAMAGE_SCROLL) {
+ // a clipping rectangle has already been set by fltk::scrollrect ()
+ draw (&rect, DRAW_PLAIN);
+ } else {
+ draw (&rect, DRAW_CLIPPED);
drawRegion.clear ();
}
}
}
-void FltkViewBase::drawRectangle (const core::Rectangle *rect,
- bool doubleBuffer)
+void FltkViewBase::draw (const core::Rectangle *rect,
+ DrawType type)
{
int offsetX = 0, offsetY = 0;
@@ -116,7 +117,7 @@ void FltkViewBase::drawRectangle (const core::Rectangle *rect,
translateCanvasXToViewX (rect->x) + offsetX,
translateCanvasYToViewY (rect->y) + offsetY,
rect->width, rect->height);
-
+
::fltk::intersect_with_clip (viewRect);
viewRect.x (viewRect.x () - offsetX);
@@ -129,14 +130,16 @@ void FltkViewBase::drawRectangle (const core::Rectangle *rect,
viewRect.w (),
viewRect.h ());
- if (doubleBuffer && backBuffer && !backBufferInUse) {
+ exposeArea = &viewRect;
+
+ if (type == DRAW_BUFFERED && backBuffer && !backBufferInUse) {
backBufferInUse = true;
{
GSave gsave;
backBuffer->setsize (viewRect.w (), viewRect.h ());
backBuffer->make_current ();
- translate (-viewRect.x (), -viewRect.y ());
+ translate (-viewRect.x (), -viewRect.y ());
setcolor (bgColor);
fillrect (viewRect);
@@ -147,19 +150,21 @@ void FltkViewBase::drawRectangle (const core::Rectangle *rect,
viewRect);
backBufferInUse = false;
- } else if (doubleBuffer) {
+ } else if (type == DRAW_BUFFERED || type == DRAW_CLIPPED) {
+ // if type == DRAW_BUFFERED but we do not have backBuffer available
+ // we fall back to clipped drawing
push_clip (viewRect);
setcolor (bgColor);
fillrect (viewRect);
theLayout->expose (this, &r);
pop_clip ();
} else {
- // if doubleBuffer is false we assume that a clipping
- // rectangle has been set already
setcolor (bgColor);
fillrect (viewRect);
theLayout->expose (this, &r);
}
+
+ exposeArea = NULL;
}
}
@@ -178,13 +183,13 @@ core::ButtonState getDwButtonState ()
{
int s1 = event_state ();
int s2 = (core::ButtonState)0;
-
- if(s1 & SHIFT) s2 |= core::SHIFT_MASK;
- if(s1 & CTRL) s2 |= core::CONTROL_MASK;
- if(s1 & ALT) s2 |= core::META_MASK;
- if(s1 & BUTTON1) s2 |= core::BUTTON1_MASK;
- if(s1 & BUTTON2) s2 |= core::BUTTON2_MASK;
- if(s1 & BUTTON3) s2 |= core::BUTTON3_MASK;
+
+ if (s1 & SHIFT) s2 |= core::SHIFT_MASK;
+ if (s1 & CTRL) s2 |= core::CONTROL_MASK;
+ if (s1 & ALT) s2 |= core::META_MASK;
+ if (s1 & BUTTON1) s2 |= core::BUTTON1_MASK;
+ if (s1 & BUTTON2) s2 |= core::BUTTON2_MASK;
+ if (s1 & BUTTON3) s2 |= core::BUTTON3_MASK;
return (core::ButtonState)s2;
}
@@ -194,7 +199,7 @@ int FltkViewBase::handle (int event)
bool processed;
/**
- * \todo Consider, whether this from the FLTK documentation has any
+ * \todo Consider, whether this from the FLTK documentation has any
* impacts: "To receive fltk::RELEASE events you must return non-zero
* when passed a fltk::PUSH event. "
*/
@@ -205,7 +210,11 @@ int FltkViewBase::handle (int event)
translateViewXToCanvasX (event_x ()),
translateViewYToCanvasY (event_y ()),
getDwButtonState (), event_button ());
- //printf ("PUSH => %s\n", processed ? "true" : "false");
+ _MSG("PUSH => %s\n", processed ? "true" : "false");
+ if (processed) {
+ /* pressed dw content; give focus to the view */
+ ::fltk::focus(this);
+ }
return processed ? true : Group::handle (event);
case RELEASE:
@@ -214,7 +223,7 @@ int FltkViewBase::handle (int event)
translateViewXToCanvasX (event_x ()),
translateViewYToCanvasY (event_y ()),
getDwButtonState (), event_button ());
- //printf ("RELEASE => %s\n", processed ? "true" : "false");
+ _MSG("RELEASE => %s\n", processed ? "true" : "false");
return processed ? true : Group::handle (event);
case MOVE:
@@ -225,7 +234,7 @@ int FltkViewBase::handle (int event)
translateViewXToCanvasX (mouse_x),
translateViewYToCanvasY (mouse_y),
getDwButtonState ());
- //printf ("MOVE => %s\n", processed ? "true" : "false");
+ _MSG("MOVE => %s\n", processed ? "true" : "false");
return processed ? true : Group::handle (event);
case DRAG:
@@ -234,7 +243,7 @@ int FltkViewBase::handle (int event)
translateViewXToCanvasX (event_x ()),
translateViewYToCanvasY (event_y ()),
getDwButtonState ());
- //printf ("DRAG => %s\n", processed ? "true" : "false");
+ _MSG("DRAG => %s\n", processed ? "true" : "false");
return processed ? true : Group::handle (event);
case ENTER:
@@ -246,7 +255,7 @@ int FltkViewBase::handle (int event)
case LEAVE:
theLayout->leaveNotify (this, getDwButtonState ());
return Group::handle (event);
-
+
default:
return Group::handle (event);
}
@@ -269,7 +278,7 @@ void FltkViewBase::setCursor (core::style::Cursor cursor)
{
static Cursor *mapDwToFltk[] = {
CURSOR_CROSS,
- CURSOR_ARROW,
+ CURSOR_DEFAULT,
CURSOR_HAND,
CURSOR_MOVE,
CURSOR_WE,
@@ -288,7 +297,7 @@ void FltkViewBase::setCursor (core::style::Cursor cursor)
/*
static char *cursorName[] = {
"CURSOR_CROSS",
- "CURSOR_ARROW",
+ "CURSOR_DEFAULT",
"CURSOR_HAND",
"CURSOR_MOVE",
"CURSOR_WE",
@@ -304,7 +313,7 @@ void FltkViewBase::setCursor (core::style::Cursor cursor)
"CURSOR_HELP"
};
- printf ("Cursor changes to '%s'.\n", cursorName[cursor]);
+ MSG("Cursor changes to '%s'.\n", cursorName[cursor]);
*/
/** \bug Does not work */
@@ -333,33 +342,13 @@ void FltkViewBase::queueDraw (core::Rectangle *area)
redraw (DAMAGE_VALUE);
}
-static void drawTotalTimeout (void *data)
-{
- FltkViewBase *view = (FltkViewBase*) data;
- if (time(0) >= view->lastDraw + view->drawDelay) {
- view->drawTotal ();
- } else {
- ::fltk::add_timeout (0.2f, drawTotalTimeout, data);
- }
-}
-
-void FltkViewBase::drawTotal ()
-{
- //static int calls = 0;
- //printf(" FltkViewBase::drawTotal calls = %d\n", ++calls);
- redraw (DAMAGE_EXPOSE);
- lastDraw = time (0);
- cancelQueueDraw ();
-}
-
void FltkViewBase::queueDrawTotal ()
{
- drawTotal ();
+ redraw (DAMAGE_EXPOSE);
}
void FltkViewBase::cancelQueueDraw ()
{
- ::fltk::remove_timeout (drawTotalTimeout, this);
}
void FltkViewBase::drawPoint (core::style::Color *color,
@@ -383,10 +372,26 @@ void FltkViewBase::drawRectangle (core::style::Color *color,
int x, int y, int width, int height)
{
setcolor(((FltkColor*)color)->colors[shading]);
+ if (width < 0) {
+ x += width;
+ width = -width;
+ }
+ if (height < 0) {
+ y += height;
+ height = -height;
+ }
+
int x1 = translateCanvasXToViewX (x);
int y1 = translateCanvasYToViewY (y);
int x2 = translateCanvasXToViewX (x + width);
int y2 = translateCanvasYToViewY (y + height);
+
+ // We only support rectangles with line width 1px, so we clip with
+ // a rectangle 1px wider and higher than what we actually expose.
+ // This is only really necessary for non-filled rectangles.
+ clipPoint (&x1, &y1, 1);
+ clipPoint (&x2, &y2, 1);
+
::fltk::Rectangle rect (x1, y1, x2 - x1, y2 - y1);
if (filled)
fillrect (rect);
@@ -396,13 +401,13 @@ void FltkViewBase::drawRectangle (core::style::Color *color,
void FltkViewBase::drawArc (core::style::Color *color,
core::style::Color::Shading shading, bool filled,
- int x, int y, int width, int height,
+ int centerX, int centerY, int width, int height,
int angle1, int angle2)
{
setcolor(((FltkColor*)color)->colors[shading]);
- int x1 = translateCanvasXToViewX (x);
- int y1 = translateCanvasYToViewY (y);
- ::fltk::Rectangle rect (x1, y1, width, height);
+ int x = translateCanvasXToViewX (centerX) - width / 2;
+ int y = translateCanvasYToViewY (centerY) - height / 2;
+ ::fltk::Rectangle rect (x, y, width, height);
addchord(rect, angle1, angle2);
closepath();
if (filled)
@@ -427,7 +432,7 @@ void FltkViewBase::drawPolygon (core::style::Color *color,
fillpath();
else
strokepath();
- }
+ }
}
core::View *FltkViewBase::getClippingView (int x, int y, int width, int height)
@@ -456,7 +461,7 @@ FltkWidgetView::~FltkWidgetView ()
void FltkWidgetView::layout () {
/**
- * pass layout to child widgets. This is needed for complex fltk
+ * pass layout to child widgets. This is needed for complex fltk
* widgets as TextEditor.
* We can't use Group::layout() as that would rearrange the widgets.
*/
@@ -477,8 +482,23 @@ void FltkWidgetView::drawText (core::style::Font *font,
FltkFont *ff = (FltkFont*)font;
setfont(ff->font, ff->size);
setcolor(((FltkColor*)color)->colors[shading]);
- drawtext(text, len,
- translateCanvasXToViewX (x), translateCanvasYToViewY (y));
+
+ if (!font->letterSpacing) {
+ drawtext(text, len,
+ translateCanvasXToViewX (x), translateCanvasYToViewY (y));
+ } else {
+ /* Nonzero letter spacing adjustment, draw each glyph individually */
+ int viewX = translateCanvasXToViewX (x),
+ viewY = translateCanvasYToViewY (y);
+ int curr = 0, next = 0;
+
+ while (next < len) {
+ next = theLayout->nextGlyph(text, curr);
+ drawtext(text + curr, next - curr, viewX, viewY);
+ viewX += font->letterSpacing + (int)getwidth(text + curr,next - curr);
+ curr = next;
+ }
+ }
}
void FltkWidgetView::drawImage (core::Imgbuf *imgbuf, int xRoot, int yRoot,
diff --git a/dw/fltkviewbase.hh b/dw/fltkviewbase.hh
index fcc2b43d..5e1981f8 100644
--- a/dw/fltkviewbase.hh
+++ b/dw/fltkviewbase.hh
@@ -16,17 +16,28 @@ namespace fltk {
class FltkViewBase: public FltkView, public ::fltk::Group
{
private:
+ typedef enum { DRAW_PLAIN, DRAW_CLIPPED, DRAW_BUFFERED } DrawType;
+
int bgColor;
core::Region drawRegion;
+ ::fltk::Rectangle *exposeArea;
static ::fltk::Image *backBuffer;
static bool backBufferInUse;
- void drawRectangle (const core::Rectangle *rect, bool doubleBuffer);
+ void draw (const core::Rectangle *rect, DrawType type);
void drawChildWidgets ();
-
-public:
- time_t lastDraw;
- time_t drawDelay;
+ inline void clipPoint (int *x, int *y, int border) {
+ if (exposeArea) {
+ if (*x < exposeArea->x () - border)
+ *x = exposeArea->x () - border;
+ if (*x > exposeArea->r () + border)
+ *x = exposeArea->r () + border;
+ if (*y < exposeArea->y () - border)
+ *y = exposeArea->y () - border;
+ if (*y > exposeArea->b () + border)
+ *y = exposeArea->b () + border;
+ }
+ }
protected:
core::Layout *theLayout;
@@ -54,7 +65,6 @@ public:
void finishDrawing (core::Rectangle *area);
void queueDraw (core::Rectangle *area);
void queueDrawTotal ();
- void drawTotal ();
void cancelQueueDraw ();
void drawPoint (core::style::Color *color,
core::style::Color::Shading shading,
@@ -67,7 +77,7 @@ public:
int x, int y, int width, int height);
void drawArc (core::style::Color *color,
core::style::Color::Shading shading, bool filled,
- int x, int y, int width, int height,
+ int centerX, int centerY, int width, int height,
int angle1, int angle2);
void drawPolygon (core::style::Color *color,
core::style::Color::Shading shading,
@@ -84,7 +94,7 @@ class FltkWidgetView: public FltkViewBase
public:
FltkWidgetView (int x, int y, int w, int h, const char *label = 0);
~FltkWidgetView ();
-
+
void layout();
void drawText (core::style::Font *font,
diff --git a/dw/fltkviewport.cc b/dw/fltkviewport.cc
index c999745a..a8555c60 100644
--- a/dw/fltkviewport.cc
+++ b/dw/fltkviewport.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -27,8 +26,10 @@
#include <fltk/events.h>
#include <stdio.h>
+#include "../lout/msg.h"
using namespace fltk;
+using namespace lout;
using namespace lout::object;
using namespace lout::container::typed;
@@ -104,8 +105,8 @@ void FltkViewport::adjustScrollbarsAndGadgetsAllocation ()
vscrollbar->w (SCROLLBAR_THICKNESS);
int x = w () - SCROLLBAR_THICKNESS, y = h () - SCROLLBAR_THICKNESS;
- for(Iterator <TypedPointer < ::fltk::Widget> > it = gadgets->iterator ();
- it.hasNext (); ) {
+ for (Iterator <TypedPointer < ::fltk::Widget> > it = gadgets->iterator ();
+ it.hasNext (); ) {
::fltk::Widget *widget = it.getNext()->getTypedValue ();
widget->x (0);
widget->y (0);
@@ -156,7 +157,7 @@ void FltkViewport::layout ()
{
theLayout->viewportSizeChanged (this, w(), h());
adjustScrollbarsAndGadgetsAllocation ();
-
+
FltkWidgetView::layout ();
}
@@ -167,10 +168,10 @@ void FltkViewport::draw_area (void *data, const Rectangle& cr )
vp->FltkWidgetView::draw ();
- for(Iterator <TypedPointer < ::fltk::Widget> > it = vp->gadgets->iterator ();
- it.hasNext (); ) {
- ::fltk::Widget *widget = it.getNext()->getTypedValue ();
- vp->draw_child (*widget);
+ for (Iterator <TypedPointer < ::fltk::Widget> > it = vp->gadgets->iterator();
+ it.hasNext (); ) {
+ ::fltk::Widget *widget = it.getNext()->getTypedValue ();
+ vp->draw_child (*widget);
}
pop_clip();
@@ -205,13 +206,13 @@ void FltkViewport::draw ()
}
}
- scrollDX = 0;
- scrollDY = 0;
+ scrollDX = 0;
+ scrollDY = 0;
}
int FltkViewport::handle (int event)
{
- //printf("FltkViewport::handle %d\n", event);
+ _MSG("FltkViewport::handle %d\n", event);
if (hscrollbar->Rectangle::contains (event_x (), event_y ()) &&
!(event_state() & (SHIFT | CTRL | ALT)) &&
@@ -225,13 +226,30 @@ int FltkViewport::handle (int event)
}
switch(event) {
+ case ::fltk::KEY:
+ /* Tell fltk we want to receive KEY events as SHORTCUT.
+ * As we don't know the exact keybindings set by the user, we ask
+ * for all of them (except TabKey to keep form navigation). */
+ if (::fltk::event_key() != TabKey)
+ return 0;
+ break;
+
case ::fltk::FOCUS:
/** \bug Draw focus box. */
- return 1;
+
+ /* If the user clicks with the left button we take focus
+ * and thereby unfocus any form widgets.
+ * Otherwise we let fltk do the focus handling.
+ */
+ if (::fltk::event_button() == ::fltk::LeftButton || focus_index() < 0) {
+ focus_index(-1);
+ return 1;
+ }
+ break;
case ::fltk::UNFOCUS:
/** \bug Undraw focus box. */
- return 1;
+ break;
case ::fltk::PUSH:
take_focus();
@@ -261,12 +279,12 @@ int FltkViewport::handle (int event)
case ::fltk:: MOUSEWHEEL:
return (event_dx() ? hscrollbar : vscrollbar)->handle(event);
break;
-
+
case ::fltk::RELEASE:
if (::fltk::event_button() == ::fltk::MiddleButton) {
dragScrolling = 0;
setCursor (core::style::CURSOR_DEFAULT);
- }
+ }
break;
case ::fltk::ENTER:
@@ -279,60 +297,6 @@ int FltkViewport::handle (int event)
case ::fltk::LEAVE:
mouse_x = mouse_y = -1;
break;
-
- case ::fltk::KEY:
- /* tell fltk we want to receive these KEY events as SHORTCUT */
- switch (::fltk::event_key()) {
- case PageUpKey:
- case PageDownKey:
- case SpaceKey:
- case DownKey:
- case UpKey:
- case RightKey:
- case LeftKey:
- case HomeKey:
- case EndKey:
- return 0;
- }
- break;
-
- case ::fltk::SHORTCUT:
- switch (::fltk::event_key()) {
- case PageUpKey:
- case 'b':
- case 'B':
- scroll (0, -vscrollbar->pagesize ());
- return 1;
-
- case PageDownKey:
- case SpaceKey:
- scroll (0, vscrollbar->pagesize ());
- return 1;
-
- case DownKey:
- scroll (0, (int) vscrollbar->linesize ());
- return 1;
-
- case UpKey:
- scroll (0, (int) -vscrollbar->linesize ());
- return 1;
-
- case RightKey:
- scroll ((int) hscrollbar->linesize (), 0);
- return 1;
-
- case LeftKey:
- scroll ((int) -hscrollbar->linesize (), 0);
- return 1;
-
- case HomeKey:
- scrollTo (scrollX, 0);
- return 1;
-
- case EndKey:
- scrollTo (scrollX, canvasHeight); /* gets adjusted in scrollTo () */
- return 1;
- }
}
return FltkWidgetView::handle (event);
@@ -361,7 +325,7 @@ void FltkViewport::positionChanged ()
/*
* For scrollbars, this currently sets the same step to both vertical and
* horizontal. It may me differentiated if necessary.
- */
+ */
void FltkViewport::setScrollStep(int step)
{
vscrollbar->linesize(step);
@@ -419,6 +383,27 @@ void FltkViewport::scroll (int dx, int dy)
scrollTo (scrollX + dx, scrollY + dy);
}
+void FltkViewport::scroll (core::ScrollCommand cmd)
+{
+ if (cmd == core::SCREEN_UP_CMD) {
+ scroll (0, -vscrollbar->pagesize ());
+ } else if (cmd == core::SCREEN_DOWN_CMD) {
+ scroll (0, vscrollbar->pagesize ());
+ } else if (cmd == core::LINE_UP_CMD) {
+ scroll (0, (int) -vscrollbar->linesize ());
+ } else if (cmd == core::LINE_DOWN_CMD) {
+ scroll (0, (int) vscrollbar->linesize ());
+ } else if (cmd == core::LEFT_CMD) {
+ scroll ((int) -hscrollbar->linesize (), 0);
+ } else if (cmd == core::RIGHT_CMD) {
+ scroll ((int) hscrollbar->linesize (), 0);
+ } else if (cmd == core::TOP_CMD) {
+ scrollTo (scrollX, 0);
+ } else if (cmd == core::BOTTOM_CMD) {
+ scrollTo (scrollX, canvasHeight); /* gets adjusted in scrollTo () */
+ }
+}
+
void FltkViewport::setViewportSize (int width, int height,
int hScrollbarThickness,
int vScrollbarThickness)
@@ -442,8 +427,8 @@ void FltkViewport::updateCanvasWidgets (int dx, int dy)
// scroll all child widgets except scroll bars
for (int i = children () - 1; i > 0; i--) {
::fltk::Widget *widget = child (i);
-
- if (widget == hscrollbar || widget == vscrollbar)
+
+ if (widget == hscrollbar || widget == vscrollbar)
continue;
widget->x (widget->x () - dx);
diff --git a/dw/fltkviewport.hh b/dw/fltkviewport.hh
index 6af377d4..1e7f54f6 100644
--- a/dw/fltkviewport.hh
+++ b/dw/fltkviewport.hh
@@ -26,7 +26,8 @@ private:
::fltk::Scrollbar *vscrollbar, *hscrollbar;
GadgetOrientation gadgetOrientation[4];
- container::typed::List <object::TypedPointer < ::fltk::Widget> > *gadgets;
+ lout::container::typed::List <lout::object::TypedPointer < ::fltk::Widget> >
+ *gadgets;
void adjustScrollbarsAndGadgetsAllocation ();
void adjustScrollbarValues ();
@@ -49,7 +50,7 @@ protected:
public:
FltkViewport (int x, int y, int w, int h, const char *label = 0);
~FltkViewport ();
-
+
void layout();
void draw ();
int handle (int event);
@@ -60,6 +61,7 @@ public:
int getHScrollbarThickness ();
int getVScrollbarThickness ();
void scroll(int dx, int dy);
+ void scroll(dw::core::ScrollCommand cmd);
void scrollTo (int x, int y);
void setViewportSize (int width, int height,
int hScrollbarThickness, int vScrollbarThickness);
diff --git a/dw/image.cc b/dw/image.cc
index ce54f561..cab40ed5 100644
--- a/dw/image.cc
+++ b/dw/image.cc
@@ -14,13 +14,13 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "image.hh"
+#include "../lout/msg.h"
#include "../lout/misc.hh"
namespace dw {
@@ -38,6 +38,18 @@ ImageMapsList::ImageMap::~ImageMap ()
delete shapesAndLinks;
}
+void ImageMapsList::ImageMap::draw (core::View *view,core::style::Style *style,
+ int x, int y)
+{
+ container::typed::Iterator <ShapeAndLink> it;
+
+ for (it = shapesAndLinks->iterator (); it.hasNext (); ) {
+ ShapeAndLink *shapeAndLink = it.getNext ();
+
+ shapeAndLink->shape->draw(view, style, x, y);
+ }
+}
+
void ImageMapsList::ImageMap::add (core::Shape *shape, int link) {
ShapeAndLink *shapeAndLink = new ShapeAndLink ();
shapeAndLink->shape = shape;
@@ -105,6 +117,15 @@ void ImageMapsList::setCurrentMapDefaultLink (int link)
currentMap->setDefaultLink (link);
}
+void ImageMapsList::drawMap (lout::object::Object *key, core::View *view,
+ core::style::Style *style, int x, int y)
+{
+ ImageMap *map = imageMaps->get (key);
+
+ if (map)
+ map->draw(view, style, x, y);
+}
+
int ImageMapsList::link (object::Object *key, int x, int y)
{
int link = -1;
@@ -139,16 +160,34 @@ Image::~Image()
delete altText;
if (buffer)
buffer->unref ();
+ if (mapKey)
+ delete mapKey;
}
void Image::sizeRequestImpl (core::Requisition *requisition)
{
if (buffer) {
- requisition->width = buffer->getRootWidth ();
- requisition->ascent = buffer->getRootHeight ();
+ if (getStyle ()->height == core::style::LENGTH_AUTO &&
+ core::style::isAbsLength (getStyle ()->width) &&
+ buffer->getRootWidth () > 0) {
+ // preserve aspect ratio when only width is given
+ requisition->width = core::style::absLengthVal (getStyle ()->width);
+ requisition->ascent = buffer->getRootHeight () *
+ requisition->width / buffer->getRootWidth ();
+ } else if (getStyle ()->width == core::style::LENGTH_AUTO &&
+ core::style::isAbsLength (getStyle ()->height) &&
+ buffer->getRootHeight () > 0) {
+ // preserve aspect ratio when only height is given
+ requisition->ascent = core::style::absLengthVal (getStyle ()->height);
+ requisition->width = buffer->getRootWidth () *
+ requisition->ascent / buffer->getRootHeight ();
+ } else {
+ requisition->width = buffer->getRootWidth ();
+ requisition->ascent = buffer->getRootHeight ();
+ }
requisition->descent = 0;
} else {
- if(altText && altText[0]) {
+ if (altText && altText[0]) {
if (altTextWidth == -1)
altTextWidth =
layout->textWidth (getStyle()->font, altText, strlen (altText));
@@ -181,20 +220,21 @@ void Image::sizeAllocateImpl (core::Allocation *allocation)
dx = getStyle()->boxDiffWidth ();
dy = getStyle()->boxDiffHeight ();
#if 0
- printf("boxDiffHeight = %d + %d, buffer=%p\n",
- getStyle()->boxOffsetY(), getStyle()->boxRestHeight(), buffer);
- printf("getContentWidth() = allocation.width - style->boxDiffWidth ()"
- " = %d - %d = %d\n",
- this->allocation.width, getStyle()->boxDiffWidth(),
- this->allocation.width - getStyle()->boxDiffWidth());
- printf("getContentHeight() = getHeight() - style->boxDiffHeight ()"
- " = %d - %d = %d\n", this->getHeight(), getStyle()->boxDiffHeight(),
- this->getHeight() - getStyle()->boxDiffHeight());
+ MSG("boxDiffHeight = %d + %d, buffer=%p\n",
+ getStyle()->boxOffsetY(), getStyle()->boxRestHeight(), buffer);
+ MSG("getContentWidth() = allocation.width - style->boxDiffWidth ()"
+ " = %d - %d = %d\n",
+ this->allocation.width, getStyle()->boxDiffWidth(),
+ this->allocation.width - getStyle()->boxDiffWidth());
+ MSG("getContentHeight() = getHeight() - style->boxDiffHeight ()"
+ " = %d - %d = %d\n", this->getHeight(), getStyle()->boxDiffHeight(),
+ this->getHeight() - getStyle()->boxDiffHeight());
#endif
- if (buffer != NULL &&
- /* It may be, that the image is allocated at zero content size. In this
- * case, we simply wait. */
- getContentWidth () > 0 && getContentHeight () > 0) {
+ if (buffer &&
+ (allocation->width - dx > 0 ||
+ allocation->ascent + allocation->descent - dy > 0)) {
+ // Zero content size : simply wait...
+ // Only one dimension: naturally scale
oldBuffer = buffer;
buffer = oldBuffer->getScaledBuf (allocation->width - dx,
allocation->ascent
@@ -209,35 +249,64 @@ void Image::enterNotifyImpl (core::EventCrossing *event)
currLink = getStyle()->x_link;
if (currLink != -1) {
- (void) emitLinkEnter (currLink, -1, -1, -1);
+ (void) layout->emitLinkEnter (this, currLink, -1, -1, -1);
}
+ Widget::enterNotifyImpl(event);
}
void Image::leaveNotifyImpl (core::EventCrossing *event)
-{
+{
clicking = false;
if (currLink != -1) {
currLink = -1;
- (void) emitLinkEnter (-1, -1, -1, -1);
+ (void) layout->emitLinkEnter (this, -1, -1, -1, -1);
}
+ Widget::leaveNotifyImpl(event);
+}
+
+/*
+ * Return the coordinate relative to the contents.
+ * If the event occurred in the surrounding box, return the value at the
+ * edge of the contents instead.
+ */
+int Image::contentX (core::MousePositionEvent *event)
+{
+ int ret = event->xWidget - getStyle()->boxOffsetX();
+
+ ret = misc::min(getContentWidth(), misc::max(ret, 0));
+ return ret;
+}
+
+int Image::contentY (core::MousePositionEvent *event)
+{
+ int ret = event->yWidget - getStyle()->boxOffsetY();
+
+ ret = misc::min(getContentHeight(), misc::max(ret, 0));
+ return ret;
}
bool Image::motionNotifyImpl (core::EventMotion *event)
{
- if (mapList) {
- /* client-side image map */
- int newLink = mapList->link (mapKey, event->xWidget, event->yWidget);
- if (newLink != currLink) {
- currLink = newLink;
- clicking = false;
- setCursor(newLink == -1 ? core::style::CURSOR_DEFAULT :
- core::style::CURSOR_POINTER);
- (void) emitLinkEnter (newLink, -1, -1, -1);
+ if (mapList || isMap) {
+ int x = contentX(event);
+ int y = contentY(event);
+
+ if (mapList) {
+ /* client-side image map */
+ int newLink = mapList->link (mapKey, x, y);
+ if (newLink != currLink) {
+ currLink = newLink;
+ clicking = false;
+ /* \todo Using MAP/AREA styles would probably be best */
+ setCursor(newLink == -1 ? getStyle()->cursor :
+ core::style::CURSOR_POINTER);
+ (void) layout->emitLinkEnter (this, newLink, -1, -1, -1);
+ }
+ } else if (isMap && currLink != -1) {
+ /* server-side image map */
+ (void) layout->emitLinkEnter (this, currLink, -1, x, y);
}
- } else if (isMap && currLink != -1) {
- /* server-side image map */
- (void) emitLinkEnter (currLink, -1, event->xWidget, event->yWidget);
}
return true;
}
@@ -245,27 +314,29 @@ bool Image::motionNotifyImpl (core::EventMotion *event)
bool Image::buttonPressImpl (core::EventButton *event)
{
bool ret = false;
- currLink = mapList ? mapList->link (mapKey, event->xWidget, event->yWidget):
- getStyle()->x_link;
+
+ currLink = mapList? mapList->link (mapKey, contentX(event),contentY(event)):
+ getStyle()->x_link;
if (event->button == 3){
- (void)emitLinkPress(currLink, getStyle()->x_img, -1,-1,event);
+ (void)layout->emitLinkPress(this, currLink, getStyle()->x_img, -1, -1,
+ event);
ret = true;
} else if (event->button == 1 || currLink != -1){
clicking = true;
ret = true;
}
return ret;
-}
+}
bool Image::buttonReleaseImpl (core::EventButton *event)
{
- currLink = mapList ? mapList->link (mapKey, event->xWidget, event->yWidget):
+ currLink = mapList ? mapList->link (mapKey, contentX(event),contentY(event)):
getStyle()->x_link;
if (clicking) {
- int x = isMap ? event->xWidget : -1;
- int y = isMap ? event->yWidget : -1;
+ int x = isMap ? contentX(event) : -1;
+ int y = isMap ? contentY(event) : -1;
clicking = false;
- emitLinkClick (currLink, getStyle()->x_img, x, y, event);
+ layout->emitLinkClick (this, currLink, getStyle()->x_img, x, y, event);
return true;
}
return false;
@@ -292,22 +363,25 @@ void Image::draw (core::View *view, core::Rectangle *area)
intersection.x - dx, intersection.y - dy,
intersection.width, intersection.height);
} else {
- if(altText && altText[0]) {
+ core::View *clippingView;
+
+ if (altText && altText[0]) {
+ core::View *usedView = view;
+
+ clippingView = NULL;
+
if (altTextWidth == -1)
altTextWidth =
layout->textWidth (getStyle()->font, altText, strlen (altText));
-
- core::View *clippingView = NULL, *usedView = view;
- if (allocation.width < altTextWidth ||
- allocation.ascent < getStyle()->font->ascent ||
- allocation.descent < getStyle()->font->descent) {
+
+ if ((getContentWidth() < altTextWidth) ||
+ (getContentHeight() <
+ getStyle()->font->ascent + getStyle()->font->descent)) {
clippingView = usedView =
view->getClippingView (allocation.x + getStyle()->boxOffsetX (),
allocation.y + getStyle()->boxOffsetY (),
- allocation.width
- - getStyle()->boxDiffWidth (),
- allocation.ascent + allocation.descent
- - getStyle()->boxDiffHeight ());
+ getContentWidth(),
+ getContentHeight());
}
usedView->drawText (getStyle()->font, getStyle()->color,
@@ -317,9 +391,21 @@ void Image::draw (core::View *view, core::Rectangle *area)
+ getStyle()->font->ascent,
altText, strlen(altText));
- if(clippingView)
+ if (clippingView)
view->mergeClippingView (clippingView);
}
+ if (mapKey) {
+ clippingView = view->getClippingView (allocation.x +
+ getStyle()->boxOffsetX (),
+ allocation.y +
+ getStyle()->boxOffsetY (),
+ getContentWidth(),
+ getContentHeight());
+ mapList->drawMap(mapKey, clippingView, getStyle(),
+ allocation.x + getStyle()->boxOffsetX (),
+ allocation.y + getStyle()->boxOffsetY ());
+ view->mergeClippingView (clippingView);
+ }
}
/** TODO: draw selection */
@@ -339,11 +425,10 @@ void Image::setBuffer (core::Imgbuf *buffer, bool resize)
if (resize)
queueResize (0, true);
- // If the image has not yet been allocated, or is allocated at zero
- // content size, the first part is useless.
if (wasAllocated () && getContentWidth () > 0 && getContentHeight () > 0) {
- this->buffer =
- buffer->getScaledBuf (getContentWidth (), getContentHeight ());
+ // Only scale when both dimensions are known.
+ this->buffer =
+ buffer->getScaledBuf (getContentWidth (), getContentHeight ());
} else {
this->buffer = buffer;
buffer->ref ();
@@ -358,7 +443,7 @@ void Image::drawRow (int row)
core::Rectangle area;
assert (buffer != NULL);
-
+
buffer->getRowArea (row, &area);
if (area.width && area.height)
queueDrawArea (area.x + getStyle()->boxOffsetX (),
@@ -386,6 +471,8 @@ void Image::setIsMap ()
void Image::setUseMap (ImageMapsList *list, object::Object *key)
{
mapList = list;
+ if (mapKey && mapKey != key)
+ delete mapKey;
mapKey = key;
}
diff --git a/dw/image.hh b/dw/image.hh
index 37c27e0d..a8314d4f 100644
--- a/dw/image.hh
+++ b/dw/image.hh
@@ -38,7 +38,8 @@ private:
public:
ImageMap ();
~ImageMap ();
-
+
+ void draw (core::View *view, core::style::Style *style, int x, int y);
void add (core::Shape *shape, int link);
void setDefaultLink (int link) { defaultLink = link; };
int link (int x, int y);
@@ -47,7 +48,7 @@ private:
lout::container::typed::HashTable <lout::object::Object, ImageMap>
*imageMaps;
ImageMap *currentMap;
-
+
public:
ImageMapsList ();
~ImageMapsList ();
@@ -55,6 +56,8 @@ public:
void startNewMap (lout::object::Object *key);
void addShapeToCurrentMap (core::Shape *shape, int link);
void setCurrentMapDefaultLink (int link);
+ void drawMap(lout::object::Object *key, core::View *view,
+ core::style::Style *style, int x, int y);
int link (lout::object::Object *key, int x, int y);
};
@@ -68,7 +71,7 @@ public:
* <h3>Signals</h3>
*
* For image maps, dw::Image uses the signals defined in
- * dw::core::Widget::LinkReceiver. For client side image maps, -1 is
+ * dw::core::Layout::LinkReceiver. For client side image maps, -1 is
* passed for the coordinates, for server side image maps, the respective
* coordinates are used. See section "Image Maps" below.
*
@@ -89,8 +92,8 @@ public:
*
* dw::ImageMapsList::addShapeToCurrentMap adds a shape to the current
* map. The \em link argument is a number, which is later passed to
- * the dw::core::Widget::LinkReceiver.
- *
+ * the dw::core::Layout::LinkReceiver.
+ *
* This map list is then, together with the key for the image, passed to
* dw::Image::setUseMap. For HTML, a URL with the value of the "ismap"
* attribute of \<IMG\> should be used.
@@ -103,13 +106,13 @@ public:
* Currently, only maps defined in the same document as the image may be
* used, since the dw::ImageMapsList is stored in the HTML link block, and
* contains only the image maps defined in the document.
- *
+ *
* <h4>Server Side %Image Maps</h4>
- *
+ *
* To use images for server side image maps, you must call
* dw::Image::setIsMap, and the dw::Image::style must contain a valid link
* (dw::core::style::Style::x_link). After this, motions and clicks are
- * delegated to dw::core::Widget::LinkReceiver.
+ * delegated to dw::core::Layout::LinkReceiver.
*
* \sa\ref dw-images-and-backgrounds
*/
@@ -129,15 +132,17 @@ protected:
void sizeRequestImpl (core::Requisition *requisition);
void sizeAllocateImpl (core::Allocation *allocation);
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area);
bool buttonPressImpl (core::EventButton *event);
bool buttonReleaseImpl (core::EventButton *event);
void enterNotifyImpl (core::EventCrossing *event);
void leaveNotifyImpl (core::EventCrossing *event);
bool motionNotifyImpl (core::EventMotion *event);
+ int contentX (core::MousePositionEvent *event);
+ int contentY (core::MousePositionEvent *event);
- //core::Iterator *iterator (Content::Type mask, bool atEnd);
+ //core::Iterator *iterator (Content::Type mask, bool atEnd);
public:
static int CLASS_ID;
@@ -145,7 +150,7 @@ public:
Image(const char *altText);
~Image();
- core::Iterator *iterator (core::Content::Type mask, bool atEnd);
+ core::Iterator *iterator (core::Content::Type mask, bool atEnd);
inline core::Imgbuf *getBuffer () { return buffer; }
void setBuffer (core::Imgbuf *buffer, bool resize = false);
@@ -154,6 +159,13 @@ public:
void setIsMap ();
void setUseMap (ImageMapsList *list, Object *key);
+
+ /* This is a hack for the perhaps frivolous feature of drawing image map
+ * shapes when there is no image to display. If the map is defined after
+ * an image using an image map, and the actual image data has not been
+ * loaded, tell the image to redraw.
+ */
+ void forceMapRedraw () { if (mapKey && ! buffer) queueDraw (); };
};
} // namespace dw
diff --git a/dw/imgbuf.hh b/dw/imgbuf.hh
index 8948bbef..150bf165 100644
--- a/dw/imgbuf.hh
+++ b/dw/imgbuf.hh
@@ -8,13 +8,11 @@
namespace dw {
namespace core {
-using namespace lout;
-
/**
- * \brief The platform independant interface for image buffers.
+ * \brief The platform independent interface for image buffers.
*
* %Image buffers depend on the platform (see \ref dw-images-and-backgrounds),
- * but have this general, platform independant interface. The purpose of
+ * but have this general, platform independent interface. The purpose of
* an image buffer is
*
* <ol>
@@ -53,16 +51,16 @@ using namespace lout;
*
*
* <h3>Scaling</h3>
- *
+ *
* The buffer with the original size, which was created by
* dw::core::Platform::createImgbuf, is called root buffer. Imgbuf provides
* the ability to scale buffers. Generally, both root buffers, as well as
* scaled buffers, may be shared, memory management is done by reference
* counters.
- *
+ *
* Via dw::core::Imgbuf::getScaledBuf, you can retrieve a scaled buffer.
* Generally, something like this must work always, in an efficient way:
- *
+ *
* \code
* dw::core::Imgbuf *curBuf, *oldBuf;
* int width, heigt,
@@ -71,15 +69,15 @@ using namespace lout;
* curBuf = oldBuf->getScaledBuf(oldBuf, width, height);
* oldBuf->unref();
* \endcode
- *
+ *
* \em oldBuf may both be a root buffer, or a scaled buffer.
- *
+ *
* The root buffer keeps a list of all children, and all methods
* operating on the image data (dw::core::Imgbuf::copyRow and
* dw::core::Imgbuf::setCMap) are delegated to the scaled buffers, when
* processed, and inherited, when a new scaled buffer is created. This
* means, that they must only be performed for the root buffer.
- *
+ *
* A possible implementation could be (dw::fltk::FltkImgbuf does it this way):
*
* <ul>
@@ -92,7 +90,7 @@ using namespace lout;
* <li> Otherwise, if this buffer has already been scaled to the given
* size, return this scaled buffer, with an increased reference
* counter.
- *
+ *
* <li> Otherwise, return a new scaled buffer with reference counter 1.
* </ul>
*
@@ -120,7 +118,7 @@ using namespace lout;
* \code
* dw::fltk::FltkPlatform *platform = new dw::fltk::FltkPlatform ();
* dw::core::Layout *layout = new dw::core::Layout (platform);
- *
+ *
* dw::core::Imgbuf *rootbuf =
* layout->createImgbuf (dw::core::Imgbuf::RGB, 100, 100);
* dw::core::Imgbuf *scaledbuf = rootbuf->getScaledBuf (50, 50);
@@ -133,12 +131,12 @@ using namespace lout;
* the scaled buffer, it is deleted, and after it, the root buffer.
*
* <h3>Drawing</h3>
- *
+ *
* dw::core::Imgbuf provides no methods for drawing, instead, this is
* done by the views (implementation of dw::core::View).
*
* There are two situations, when drawing is necessary:
- *
+ *
* <ol>
* <li> To react on expose events, the function dw::core::View::drawImage
* should be used, with the following parameters:
@@ -149,7 +147,7 @@ using namespace lout;
* <li> the region within the image, which should be displayed (\em x,
* \em y, \em width, \em height).
* </ul>
- *
+ *
* <li> When a row has been copied, it has to be drawn. To determine the
* area, which has to be drawn, the dw::core::Imgbuf::getRowArea
* should be used. The result can then passed
@@ -158,7 +156,7 @@ using namespace lout;
*
* \sa \ref dw-images-and-backgrounds
*/
-class Imgbuf: public object::Object, public lout::signal::ObservedObject
+class Imgbuf: public lout::object::Object, public lout::signal::ObservedObject
{
public:
enum Type { RGB, RGBA, GRAY, INDEXED, INDEXED_ALPHA };
diff --git a/dw/iterator.cc b/dw/iterator.cc
index 39e09d41..e9431e9b 100644
--- a/dw/iterator.cc
+++ b/dw/iterator.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -23,6 +22,8 @@
#include "core.hh"
#include <limits.h>
+using namespace lout;
+
namespace dw {
namespace core {
@@ -57,7 +58,7 @@ bool Iterator::equals (Object *other)
/**
* \brief Delete the iterator.
*
- * The desctructor is hidden, implementations may use optimizations for
+ * The destructor is hidden, implementations may use optimizations for
* the allocation. (Will soon be the case for dw::core::EmptyIteratorFactory.)
*/
void Iterator::unref ()
@@ -146,7 +147,7 @@ void Iterator::scrollTo (Iterator *it1, Iterator *it2, int start, int end,
// |----------------------------|
// width
//
- // Therefor, we the region smaller, so that the region will be
+ // Therefore, we make the region smaller, so that the region will be
// displayed like this:
//
// ,-- alloc1
@@ -159,7 +160,7 @@ void Iterator::scrollTo (Iterator *it1, Iterator *it2, int start, int end,
// |----------|
// width
//
-
+
/** \todo Changes in the viewport size, until the idle function is
* called, are not regarded. */
@@ -210,7 +211,7 @@ int EmptyIterator::compareTo (misc::Comparable *other)
if (content.type == otherIt->content.type)
return 0;
- else if(content.type == Content::START)
+ else if (content.type == Content::START)
return -1;
else
return +1;
@@ -468,7 +469,7 @@ DeepIterator::DeepIterator (Iterator *it)
// since an DeepIterator should never return widgets.
if (it->getContent()->type == Content::WIDGET) {
Iterator *it2;
-
+
// The second argument of searchDownward is actually a matter of
// taste :-)
if ((it2 = searchDownward (it, mask, false)) ||
@@ -484,10 +485,10 @@ DeepIterator::DeepIterator (Iterator *it)
hasContents = false;
}
}
-
+
//DEBUG_MSG (1, " => %s\n", a_Dw_iterator_text (it));
- if(hasContents) {
+ if (hasContents) {
// If this widget has parents, we must construct appropriate iterators.
//
// \todo There may be a faster way instead of iterating through the
@@ -509,7 +510,7 @@ DeepIterator::DeepIterator (Iterator *it)
break;
}
}
-
+
stack.put (it, thisLevel);
content = *(it->getContent());
}
@@ -552,10 +553,10 @@ int DeepIterator::compareTo (misc::Comparable *other)
while (stack.get(level)->getWidget ()
!= otherDeepIterator->stack.get(level)->getWidget ())
level--;
-
+
return stack.get(level)->compareTo (otherDeepIterator->stack.get(level));
}
-
+
DeepIterator *DeepIterator::createVariant(Iterator *it)
{
/** \todo Not yet implemented, and actually not yet needed very much. */
@@ -574,7 +575,7 @@ bool DeepIterator::isEmpty () {
bool DeepIterator::next ()
{
Iterator *it = stack.getTop ();
-
+
if (it->next ()) {
if (it->getContent()->type == Content::WIDGET) {
// Widget: new iterator on stack, to search in this widget.
@@ -596,7 +597,7 @@ bool DeepIterator::next ()
content.type = Content::END;
return false;
}
- }
+ }
}
/**
@@ -607,7 +608,7 @@ bool DeepIterator::next ()
bool DeepIterator::prev ()
{
Iterator *it = stack.getTop ();
-
+
if (it->prev ()) {
if (it->getContent()->type == Content::WIDGET) {
// Widget: new iterator on stack, to search in this widget.
@@ -629,7 +630,7 @@ bool DeepIterator::prev ()
content.type = Content::START;
return false;
}
- }
+ }
}
// -----------------
@@ -679,7 +680,7 @@ bool CharIterator::next ()
if (ch == START || it->getContent()->type == Content::BREAK ||
(it->getContent()->type == Content::TEXT &&
it->getContent()->text[pos] == 0)) {
- if(it->next()) {
+ if (it->next()) {
if (it->getContent()->type == Content::BREAK)
ch = '\n';
else { // if (it->getContent()->type == Content::TEXT)
@@ -695,7 +696,7 @@ bool CharIterator::next ()
ch = END;
return false;
}
- } else if(ch == END)
+ } else if (ch == END)
return false;
else {
// at this point, it->getContent()->type == Content::TEXT
@@ -708,16 +709,16 @@ bool CharIterator::next ()
return next ();
}
}
-
+
return true;
- }
+ }
}
bool CharIterator::prev ()
{
if (ch == END || it->getContent()->type == Content::BREAK ||
(it->getContent()->type == Content::TEXT && pos == 0)) {
- if(it->prev()) {
+ if (it->prev()) {
if (it->getContent()->type == Content::BREAK)
ch = '\n';
else { // if (it->getContent()->type == Content::TEXT)
@@ -739,14 +740,14 @@ bool CharIterator::prev ()
ch = START;
return false;
}
- } else if(ch == START)
+ } else if (ch == START)
return false;
else {
// at this point, it->getContent()->type == Content::TEXT
pos--;
ch = it->getContent()->text[pos];
return true;
- }
+ }
}
void CharIterator::highlight (CharIterator *it1, CharIterator *it2,
diff --git a/dw/iterator.hh b/dw/iterator.hh
index 605217ec..838d66a1 100644
--- a/dw/iterator.hh
+++ b/dw/iterator.hh
@@ -16,7 +16,7 @@ namespace core {
*
* \sa dw::core::Widget::iterator
*/
-class Iterator: public object::Object, public misc::Comparable
+class Iterator: public lout::object::Object, public lout::misc::Comparable
{
protected:
Iterator(Widget *widget, Content::Type mask, bool atEnd);
@@ -65,10 +65,10 @@ public:
/**
* \brief Shrink highlighted region to no longer contain the
* current content.
- *
- * The direction parameter indicates whether the highlighted region should be
- * reduced from the start (direction > 0) or from the end (direction < 0).
- * If direction is 0 all content is unhighlighted.
+ *
+ * The direction parameter indicates whether the highlighted region should
+ * be reduced from the start (direction > 0) or from the end
+ * (direction < 0). If direction is 0 all content is unhighlighted.
*/
virtual void unhighlight (int direction, HighlightLayer layer) = 0;
@@ -80,7 +80,7 @@ public:
* DwIterator::highlight().
*/
virtual void getAllocation (int start, int end, Allocation *allocation) = 0;
-
+
inline Iterator *cloneIterator () { return (Iterator*)clone(); }
static void scrollTo (Iterator *it1, Iterator *it2, int start, int end,
@@ -96,12 +96,12 @@ class EmptyIterator: public Iterator
{
private:
EmptyIterator (EmptyIterator &it);
-
+
public:
EmptyIterator (Widget *widget, Content::Type mask, bool atEnd);
-
- object::Object *clone();
- int compareTo(misc::Comparable *other);
+
+ lout::object::Object *clone();
+ int compareTo(lout::misc::Comparable *other);
bool next ();
bool prev ();
void highlight (int start, int end, HighlightLayer layer);
@@ -119,14 +119,14 @@ class TextIterator: public Iterator
private:
/** May be NULL, in this case, the next is skipped. */
const char *text;
-
+
TextIterator (TextIterator &it);
-
+
public:
TextIterator (Widget *widget, Content::Type mask, bool atEnd,
const char *text);
-
- int compareTo(misc::Comparable *other);
+
+ int compareTo(lout::misc::Comparable *other);
bool next ();
bool prev ();
@@ -142,13 +142,13 @@ public:
* iterators do not have the limitation, that iteration is only done within
* a widget, instead, child widgets are iterated through recursively.
*/
-class DeepIterator: public object::Object, public misc::Comparable
+class DeepIterator: public lout::object::Object, public lout::misc::Comparable
{
private:
- class Stack: public container::typed::Vector<Iterator>
+ class Stack: public lout::container::typed::Vector<Iterator>
{
public:
- inline Stack (): container::typed::Vector<Iterator> (4, false) { }
+ inline Stack (): lout::container::typed::Vector<Iterator> (4, false) { }
~Stack ();
inline Iterator *getTop () { return get (size () - 1); }
inline void push (Iterator *it) { put(it, -1); }
@@ -168,14 +168,14 @@ private:
inline DeepIterator () { }
-public:
+public:
DeepIterator(Iterator *it);
~DeepIterator();
- object::Object *clone ();
+ lout::object::Object *clone ();
DeepIterator *createVariant(Iterator *it);
- inline Iterator *getTopIterator () { return stack.getTop(); }
+ inline Iterator *getTopIterator () { return stack.getTop(); }
inline Content *getContent () { return &content; }
bool isEmpty ();
@@ -183,12 +183,12 @@ public:
bool next ();
bool prev ();
inline DeepIterator *cloneDeepIterator() { return (DeepIterator*)clone(); }
- int compareTo(misc::Comparable *other);
+ int compareTo(lout::misc::Comparable *other);
/**
* \brief Highlight a part of the current content.
*
- * Unhighlight the current content by passing -1 as start (see also
+ * Unhighlight the current content by passing -1 as start (see also
* (dw::core::Iterator::unhighlight). For text, start and end define the
* characters, otherwise, the shape is defined as [0, 1], i.e. for
* highlighting a whole dw::core::Content, pass 0 and >= 1.
@@ -216,10 +216,12 @@ public:
start, end, hpos, vpos); }
};
-class CharIterator: public object::Object, public misc::Comparable
+class CharIterator: public lout::object::Object, public lout::misc::Comparable
{
public:
- enum { START = -1, END = -2 };
+ // START and END must not clash with any char value
+ // neither for signed nor unsigned char.
+ enum { START = 257, END = 258 };
private:
DeepIterator *it;
@@ -231,8 +233,8 @@ public:
CharIterator (Widget *widget);
~CharIterator ();
- object::Object *clone();
- int compareTo(misc::Comparable *other);
+ lout::object::Object *clone();
+ int compareTo(lout::misc::Comparable *other);
bool next ();
bool prev ();
diff --git a/dw/layout.cc b/dw/layout.cc
index 060c182f..d8b96d55 100644
--- a/dw/layout.cc
+++ b/dw/layout.cc
@@ -14,17 +14,18 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core.hh"
+#include "../lout/msg.h"
#include "../lout/debug.hh"
#include "../lout/misc.hh"
+using namespace lout;
using namespace lout::container;
using namespace lout::object;
@@ -38,8 +39,8 @@ void Layout::Receiver::canvasSizeChanged (int width, int ascent, int descent)
// ----------------------------------------------------------------------
bool Layout::Emitter::emitToReceiver (lout::signal::Receiver *receiver,
- int signalNo,
- int argc, Object **argv)
+ int signalNo, int argc,
+ lout::object::Object **argv)
{
Receiver *layoutReceiver = (Receiver*)receiver;
@@ -54,7 +55,7 @@ bool Layout::Emitter::emitToReceiver (lout::signal::Receiver *receiver,
misc::assertNotReached ();
}
- return false;
+ return false;
}
void Layout::Emitter::emitCanvasSizeChanged (int width,
@@ -65,6 +66,110 @@ void Layout::Emitter::emitCanvasSizeChanged (int width,
emitVoid (CANVAS_SIZE_CHANGED, 3, argv);
}
+// ----------------------------------------------------------------------
+
+bool Layout::LinkReceiver::enter (Widget *widget, int link, int img,
+ int x, int y)
+{
+ return false;
+}
+
+bool Layout::LinkReceiver::press (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ return false;
+}
+
+bool Layout::LinkReceiver::release (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ return false;
+}
+
+bool Layout::LinkReceiver::click (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ return false;
+}
+
+// ----------------------------------------------------------------------
+
+bool Layout::LinkEmitter::emitToReceiver (lout::signal::Receiver *receiver,
+ int signalNo, int argc,
+ lout::object::Object **argv)
+{
+ LinkReceiver *linkReceiver = (LinkReceiver*)receiver;
+
+ switch (signalNo) {
+ case ENTER:
+ return linkReceiver->enter ((Widget*)argv[0],
+ ((Integer*)argv[1])->getValue (),
+ ((Integer*)argv[2])->getValue (),
+ ((Integer*)argv[3])->getValue (),
+ ((Integer*)argv[4])->getValue ());
+
+ case PRESS:
+ return linkReceiver->press ((Widget*)argv[0],
+ ((Integer*)argv[1])->getValue (),
+ ((Integer*)argv[2])->getValue (),
+ ((Integer*)argv[3])->getValue (),
+ ((Integer*)argv[4])->getValue (),
+ (EventButton*)argv[5]);
+
+ case RELEASE:
+ return linkReceiver->release ((Widget*)argv[0],
+ ((Integer*)argv[1])->getValue (),
+ ((Integer*)argv[2])->getValue (),
+ ((Integer*)argv[3])->getValue (),
+ ((Integer*)argv[4])->getValue (),
+ (EventButton*)argv[5]);
+
+ case CLICK:
+ return linkReceiver->click ((Widget*)argv[0],
+ ((Integer*)argv[1])->getValue (),
+ ((Integer*)argv[2])->getValue (),
+ ((Integer*)argv[3])->getValue (),
+ ((Integer*)argv[4])->getValue (),
+ (EventButton*)argv[5]);
+
+ default:
+ misc::assertNotReached ();
+ }
+ return false;
+}
+
+bool Layout::LinkEmitter::emitEnter (Widget *widget, int link, int img,
+ int x, int y)
+{
+ Integer ilink (link), iimg (img), ix (x), iy (y);
+ Object *argv[5] = { widget, &ilink, &iimg, &ix, &iy };
+ return emitBool (ENTER, 5, argv);
+}
+
+bool Layout::LinkEmitter::emitPress (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ Integer ilink (link), iimg (img), ix (x), iy (y);
+ Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
+ return emitBool (PRESS, 6, argv);
+}
+
+bool Layout::LinkEmitter::emitRelease (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ Integer ilink (link), iimg (img), ix (x), iy (y);
+ Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
+ return emitBool (RELEASE, 6, argv);
+}
+
+bool Layout::LinkEmitter::emitClick (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ Integer ilink (link), iimg (img), ix (x), iy (y);
+ Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
+ return emitBool (CLICK, 6, argv);
+}
+
// ---------------------------------------------------------------------
Layout::Anchor::~Anchor ()
@@ -77,7 +182,7 @@ Layout::Anchor::~Anchor ()
Layout::Layout (Platform *platform)
{
this->platform = platform;
- views = new container::typed::List <View> (true);
+ view = NULL;
topLevel = NULL;
widgetAtPoint = NULL;
@@ -87,9 +192,11 @@ Layout::Layout (Platform *platform)
cursor = style::CURSOR_DEFAULT;
canvasWidth = canvasAscent = canvasDescent = 0;
-
+
usesViewport = false;
scrollX = scrollY = 0;
+ viewportWidth = viewportHeight = 0;
+ hScrollbarThickness = vScrollbarThickness = 0;
requestedAnchor = NULL;
scrollIdleId = -1;
@@ -120,7 +227,7 @@ Layout::~Layout ()
if (topLevel)
delete topLevel;
delete platform;
- delete views;
+ delete view;
delete anchorsTable;
delete textZone;
}
@@ -128,7 +235,7 @@ Layout::~Layout ()
void Layout::addWidget (Widget *widget)
{
if (topLevel) {
- fprintf (stderr, "widget already set\n");
+ MSG_WARN("widget already set\n");
return;
}
@@ -154,13 +261,10 @@ void Layout::removeWidget ()
canvasWidth = canvasAscent = canvasDescent = 0;
scrollX = scrollY = 0;
- for (typed::Iterator <View> it = views->iterator (); it.hasNext (); ) {
- View *view = it.getNext ();
- view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent);
- if (view->usesViewport ())
- view->setViewportSize (viewportWidth, viewportHeight, 0, 0);
- view->queueDrawTotal ();
- }
+ view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent);
+ if (view->usesViewport ())
+ view->setViewportSize (viewportWidth, viewportHeight, 0, 0);
+ view->queueDrawTotal ();
setAnchor (NULL);
updateAnchor ();
@@ -192,7 +296,10 @@ void Layout::setWidget (Widget *widget)
*/
void Layout::attachView (View *view)
{
- views->append (view);
+ if (this->view)
+ MSG_ERR("attachView: Multiple views for layout!\n");
+
+ this->view = view;
platform->attachView (view);
/*
@@ -234,11 +341,12 @@ void Layout::attachView (View *view)
void Layout::detachView (View *view)
{
+ if (this->view != view)
+ MSG_ERR("detachView: this->view: %p view %p\n", this->view, view);
+
view->setLayout (NULL);
platform->detachView (view);
-
- views->detachRef (view);
-
+ this->view = NULL;
/**
* \todo Actually, viewportMarkerWidthDiff and
* viewportMarkerHeightDiff have to be recalculated here, since the
@@ -247,8 +355,14 @@ void Layout::detachView (View *view)
*/
}
+void Layout::scroll(ScrollCommand cmd)
+{
+ if (view->usesViewport ())
+ view->scroll(cmd);
+}
+
/**
- * \brief Scrolls all viewports, so that the region [x, y, width, height]
+ * \brief Scrolls all viewports, so that the region [x, y, width, height]
* is seen, according to hpos and vpos.
*/
void Layout::scrollTo (HPosition hpos, VPosition vpos,
@@ -262,8 +376,8 @@ void Layout::scrollTo0 (HPosition hpos, VPosition vpos,
bool scrollingInterrupted)
{
if (usesViewport) {
- //printf ("scrollTo (%d, %d, %s)\n",
- // x, y, scrollingInterrupted ? "true" : "false");
+ _MSG("scrollTo (%d, %d, %s)\n",
+ x, y, scrollingInterrupted ? "true" : "false");
scrollTargetHpos = hpos;
scrollTargetVpos = vpos;
@@ -271,12 +385,12 @@ void Layout::scrollTo0 (HPosition hpos, VPosition vpos,
scrollTargetY = y;
scrollTargetWidth = width;
scrollTargetHeight = height;
-
+
if (scrollIdleId == -1) {
scrollIdleId = platform->addIdle (&Layout::scrollIdle);
scrollIdleNotInterrupted = true;
}
-
+
scrollIdleNotInterrupted =
scrollIdleNotInterrupted || !scrollingInterrupted;
}
@@ -334,11 +448,7 @@ void Layout::scrollIdle ()
if (xChanged || yChanged) {
adjustScrollPos ();
- for (container::typed::Iterator <View> it = views->iterator ();
- it.hasNext (); ) {
- View *thisView = it.getNext();
- thisView->scrollTo (scrollX, scrollY);
- }
+ view->scrollTo (scrollX, scrollY);
}
scrollIdleId = -1;
@@ -354,7 +464,7 @@ void Layout::adjustScrollPos ()
canvasAscent + canvasDescent - (viewportHeight - hScrollbarThickness));
scrollY = misc::max (scrollY, 0);
- //printf("adjustScrollPos: scrollX=%d scrollY=%d\n", scrollX, scrollY);
+ _MSG("adjustScrollPos: scrollX=%d scrollY=%d\n", scrollX, scrollY);
}
bool Layout::calcScrollInto (int requestedValue, int requestedSize,
@@ -414,7 +524,7 @@ void Layout::draw (View *view, Rectangle *area)
*/
void Layout::setAnchor (const char *anchor)
{
- //printf ("setAnchor (%s)\n", anchor);
+ _MSG("setAnchor (%s)\n", anchor);
if (requestedAnchor)
delete requestedAnchor;
@@ -450,7 +560,7 @@ char *Layout::addAnchor (Widget *widget, const char* name, int y)
void Layout::changeAnchor (Widget *widget, char* name, int y)
{
- String key (name);
+ String key (name);
Anchor *anchor = anchorsTable->get (&key);
assert (anchor);
assert (anchor->widget == widget);
@@ -488,11 +598,7 @@ void Layout::setCursor (style::Cursor cursor)
{
if (cursor != this->cursor) {
this->cursor = cursor;
-
- for (typed::Iterator <View> it = views->iterator (); it.hasNext (); ) {
- View *view = it.getNext ();
- view->setCursor (cursor);
- }
+ view->setCursor (cursor);
}
}
@@ -514,17 +620,13 @@ void Layout::updateBgColor ()
bgColor = topLevel->getStyle()->backgroundColor;
else
bgColor = NULL;
-
- for (typed::Iterator <View> it = views->iterator (); it.hasNext (); ) {
- View *view = it.getNext ();
- view->setBgColor (bgColor);
- }
+ view->setBgColor (bgColor);
}
void Layout::resizeIdle ()
{
//static int calls = 0;
- //printf(" Layout::resizeIdle calls = %d\n", ++calls);
+ //MSG(" Layout::resizeIdle calls = %d\n", ++calls);
while (resizeIdleId != -1) {
// Reset already here, since in this function, queueResize() may be
@@ -550,12 +652,9 @@ void Layout::resizeIdle ()
emitter.emitCanvasSizeChanged (
canvasWidth, canvasAscent, canvasDescent);
- // Tell the views about the new world size.
- for (typed::Iterator <View> it = views->iterator (); it.hasNext ();) {
- View *view = it.getNext ();
- view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent);
- // view->queueDrawTotal (false);
- }
+ // Tell the view about the new world size.
+ view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent);
+ // view->queueDrawTotal (false);
if (usesViewport) {
int actualHScrollbarThickness =
@@ -564,7 +663,7 @@ void Layout::resizeIdle ()
(canvasAscent + canvasDescent > viewportHeight) ?
vScrollbarThickness : 0;
- if (!canvasHeightGreater &&
+ if (!canvasHeightGreater &&
canvasAscent + canvasDescent
> viewportHeight - actualHScrollbarThickness) {
canvasHeightGreater = true;
@@ -573,14 +672,10 @@ void Layout::resizeIdle ()
}
// Set viewport sizes.
- for (typed::Iterator <View> it = views->iterator ();
- it.hasNext (); ) {
- View *view = it.getNext ();
- if (view->usesViewport ())
- view->setViewportSize (viewportWidth, viewportHeight,
- actualHScrollbarThickness,
- actualVScrollbarThickness);
- }
+ if (view->usesViewport ())
+ view->setViewportSize (viewportWidth, viewportHeight,
+ actualHScrollbarThickness,
+ actualVScrollbarThickness);
}
}
@@ -592,7 +687,7 @@ void Layout::resizeIdle ()
}
void Layout::setSizeHints ()
-{
+{
if (topLevel) {
topLevel->setWidth (viewportWidth
- (canvasHeightGreater ? vScrollbarThickness : 0));
@@ -611,11 +706,7 @@ void Layout::queueDraw (int x, int y, int width, int height)
if (area.isEmpty ()) return;
- for (container::typed::Iterator <View> it = views->iterator ();
- it.hasNext (); ) {
- View *view = it.getNext ();
- view->queueDraw (&area);
- }
+ view->queueDraw (&area);
}
void Layout::queueDrawExcept (int x, int y, int width, int height,
@@ -623,15 +714,15 @@ void Layout::queueDrawExcept (int x, int y, int width, int height,
if (x == ex && y == ey && width == ewidth && height == eheight)
return;
-
+
// queueDraw() the four rectangles within rectangle (x, y, width, height)
// around rectangle (ex, ey, ewidth, eheight).
// Some or all of these may be empty.
- // upper left corner of the intersection rectangle
+ // upper left corner of the intersection rectangle
int ix1 = misc::max (x, ex);
int iy1 = misc::max (y, ey);
- // lower right corner of the intersection rectangle
+ // lower right corner of the intersection rectangle
int ix2 = misc::min (x + width, ex + ewidth);
int iy2 = misc::min (y + height, ey + eheight);
@@ -644,11 +735,7 @@ void Layout::queueDrawExcept (int x, int y, int width, int height,
void Layout::queueResize ()
{
if (resizeIdleId == -1) {
- for (container::typed::Iterator <View> it = views->iterator ();
- it.hasNext (); ) {
- View *view = it.getNext ();
- view->cancelQueueDraw ();
- }
+ view->cancelQueueDraw ();
resizeIdleId = platform->addIdle (&Layout::resizeIdle);
}
@@ -659,10 +746,10 @@ void Layout::queueResize ()
bool Layout::buttonEvent (ButtonEventType type, View *view, int numPressed,
int x, int y, ButtonState state, int button)
-
+
{
EventButton event;
-
+
moveToWidgetAtPoint (x, y, state);
event.xCanvas = x;
@@ -670,7 +757,7 @@ bool Layout::buttonEvent (ButtonEventType type, View *view, int numPressed,
event.state = state;
event.button = button;
event.numPressed = numPressed;
-
+
return processMouseEvent (&event, type, true);
}
@@ -683,13 +770,13 @@ bool Layout::buttonEvent (ButtonEventType type, View *view, int numPressed,
bool Layout::motionNotify (View *view, int x, int y, ButtonState state)
{
EventButton event;
-
+
moveToWidgetAtPoint (x, y, state);
event.xCanvas = x;
event.yCanvas = y;
event.state = state;
-
+
return processMouseEvent (&event, MOTION_NOTIFY, true);
}
@@ -706,7 +793,7 @@ void Layout::enterNotify (View *view, int x, int y, ButtonState state)
lastWidget = widgetAtPoint;
moveToWidgetAtPoint (x, y, state);
- if(widgetAtPoint) {
+ if (widgetAtPoint) {
event.state = state;
event.lastWidget = lastWidget;
event.currentWidget = widgetAtPoint;
@@ -727,7 +814,7 @@ void Layout::leaveNotify (View *view, ButtonState state)
lastWidget = widgetAtPoint;
moveOutOfView (state);
- if(lastWidget) {
+ if (lastWidget) {
event.state = state;
event.lastWidget = lastWidget;
event.currentWidget = widgetAtPoint;
@@ -740,8 +827,8 @@ void Layout::leaveNotify (View *view, ButtonState state)
*/
Widget *Layout::getWidgetAtPoint (int x, int y)
{
- //_MSG ("------------------------------------------------------------\n");
- //_MSG ("widget at (%d, %d)\n", x, y);
+ _MSG ("------------------------------------------------------------\n");
+ _MSG ("widget at (%d, %d)\n", x, y);
if (topLevel)
return topLevel->getWidgetAtPoint (x, y, 0);
else
@@ -761,11 +848,11 @@ void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state)
EventCrossing crossingEvent;
if (newWidgetAtPoint != widgetAtPoint) {
- // The mouse pointer has been moved into another widget.
+ // The mouse pointer has been moved into another widget.
if (newWidgetAtPoint && widgetAtPoint)
ancestor =
newWidgetAtPoint->getNearestCommonAncestor (widgetAtPoint);
- else if(newWidgetAtPoint)
+ else if (newWidgetAtPoint)
ancestor = newWidgetAtPoint->getTopLevel ();
else
ancestor = widgetAtPoint->getTopLevel ();
@@ -777,7 +864,7 @@ void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state)
for (w = widgetAtPoint; w != ancestor; w = w->getParent ())
trackLen++;
trackLen++; // for the ancestor
- if(newWidgetAtPoint)
+ if (newWidgetAtPoint)
// second part
for (w = newWidgetAtPoint; w != ancestor; w = w->getParent ())
trackLen++;
@@ -789,7 +876,7 @@ void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state)
for (w = widgetAtPoint; w != ancestor; w = w->getParent ())
track[i++] = w;
track[i++] = ancestor;
- if(newWidgetAtPoint) {
+ if (newWidgetAtPoint) {
/* second part */
i = trackLen - 1;
for (w = newWidgetAtPoint; w != ancestor; w = w->getParent ())
@@ -801,13 +888,13 @@ void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state)
crossingEvent.state = state;
crossingEvent.currentWidget = widgetAtPoint; // ???
crossingEvent.lastWidget = widgetAtPoint; // ???
-
+
if (i != 0)
track[i]->enterNotify (&crossingEvent);
if (i != trackLen - 1)
track[i]->leaveNotify (&crossingEvent);
}
-
+
delete[] track;
widgetAtPoint = newWidgetAtPoint;
@@ -827,7 +914,7 @@ bool Layout::processMouseEvent (MousePositionEvent *event,
Widget *widget;
for (widget = widgetAtPoint; widget; widget = widget->getParent ()) {
- if(!mayBeSuppressed || widget->isButtonSensitive ()) {
+ if (!mayBeSuppressed || widget->isButtonSensitive ()) {
event->xWidget = event->xCanvas - widget->getAllocation()->x;
event->yWidget = event->yCanvas - widget->getAllocation()->y;
@@ -846,6 +933,10 @@ bool Layout::processMouseEvent (MousePositionEvent *event,
}
}
}
+ if (type == BUTTON_PRESS)
+ return emitLinkPress (NULL, -1, -1, -1, -1, (EventButton*)event);
+ else if (type == BUTTON_RELEASE)
+ return emitLinkRelease(NULL, -1, -1, -1, -1, (EventButton*)event);
return false;
}
@@ -860,14 +951,6 @@ void Layout::scrollPosChanged (View *view, int x, int y)
if (x != scrollX || y != scrollY) {
scrollX = x;
scrollY = y;
-
- // Tell all views about the scrolling position, except the caller.
- for (container::typed::Iterator <View> it = views->iterator ();
- it.hasNext (); ) {
- View *thisView = it.getNext();
- if(view != thisView && thisView->usesViewport ())
- thisView->scrollTo (scrollX, scrollY);
- }
setAnchor (NULL);
updateAnchor ();
@@ -880,12 +963,12 @@ void Layout::scrollPosChanged (View *view, int x, int y)
*/
void Layout::viewportSizeChanged (View *view, int width, int height)
{
- //printf("Layout::viewportSizeChanged w=%d h=%d new_w=%d new_h=%d\n",
- // viewportWidth, viewportHeight, width, height);
+ _MSG("Layout::viewportSizeChanged w=%d h=%d new_w=%d new_h=%d\n",
+ viewportWidth, viewportHeight, width, height);
/* If the width has become higher, we test again, whether the vertical
* scrollbar (so to speak) can be hidden again. */
- if(usesViewport && width > viewportWidth)
+ if (usesViewport && width > viewportWidth)
canvasHeightGreater = false;
/* if size changes, redraw this view.
@@ -897,21 +980,6 @@ void Layout::viewportSizeChanged (View *view, int width, int height)
viewportHeight = height;
setSizeHints ();
-
- int actualHScrollbarThickness =
- (canvasWidth > viewportWidth) ? hScrollbarThickness : 0;
- int actualVScrollbarThickness =
- (canvasAscent + canvasDescent > viewportWidth) ? vScrollbarThickness : 0;
-
- /* Tell all views about the size, except the caller. */
- for (container::typed::Iterator <View> it = views->iterator ();
- it.hasNext (); ) {
- View *thisView = it.getNext();
- if(view != thisView && thisView->usesViewport ())
- thisView->setViewportSize (viewportWidth, viewportHeight,
- actualHScrollbarThickness,
- actualVScrollbarThickness);
- }
}
} // namespace dw
diff --git a/dw/layout.hh b/dw/layout.hh
index 13b8f312..304cf166 100644
--- a/dw/layout.hh
+++ b/dw/layout.hh
@@ -13,7 +13,7 @@ namespace core {
*
* \sa\ref dw-overview, \ref dw-layout-widgets, \ref dw-layout-views
*/
-class Layout: public object::Object
+class Layout: public lout::object::Object
{
friend class Widget;
@@ -29,6 +29,78 @@ public:
virtual void canvasSizeChanged (int width, int ascent, int descent);
};
+ class LinkReceiver: public lout::signal::Receiver
+ {
+ public:
+ /**
+ * \brief Called, when a link is entered, left, or the position has
+ * changed.
+ *
+ * When a link is entered, this method is called with the respective
+ * arguments. When a link is left, this method is called with all
+ * three arguments (\em link, \em x, \em y) set to -1.
+ *
+ * When coordinates are supported, a change of the coordinates also
+ * causes emitting this signal.
+ */
+ virtual bool enter (Widget *widget, int link, int img, int x, int y);
+
+ /**
+ * \brief Called, when the user has pressed the mouse button on a
+ * link (but not yet released).
+ *
+ * The causing event is passed as \em event.
+ */
+ virtual bool press (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+
+ /**
+ * \brief Called, when the user has released the mouse button on a
+ * link.
+ *
+ * The causing event is passed as \em event.
+ */
+ virtual bool release (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+
+ /**
+ * \brief Called, when the user has clicked on a link.
+ *
+ * For mouse interaction, this is equivalent to "press" and "release"
+ * on the same link. In this case, \em event contains the "release"
+ * event.
+ *
+ *
+ * When activating links via keyboard is supported, only a "clicked"
+ * signal will be emitted, and \em event will be NULL.
+ */
+ virtual bool click (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+ };
+
+ class LinkEmitter: public lout::signal::Emitter
+ {
+ private:
+ enum { ENTER, PRESS, RELEASE, CLICK };
+
+ protected:
+ bool emitToReceiver (lout::signal::Receiver *receiver, int signalNo,
+ int argc, lout::object::Object **argv);
+
+ public:
+ inline void connectLink (LinkReceiver *receiver) { connect (receiver); }
+
+ bool emitEnter (Widget *widget, int link, int img, int x, int y);
+ bool emitPress (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+ bool emitRelease (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+ bool emitClick (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+ };
+
+ LinkEmitter linkEmitter;
+
private:
class Emitter: public lout::signal::Emitter
{
@@ -37,7 +109,7 @@ private:
protected:
bool emitToReceiver (lout::signal::Receiver *receiver, int signalNo,
- int argc, Object **argv);
+ int argc, lout::object::Object **argv);
public:
inline void connectLayout (Receiver *receiver) { connect (receiver); }
@@ -47,7 +119,7 @@ private:
Emitter emitter;
- class Anchor: public object::Object
+ class Anchor: public lout::object::Object
{
public:
char *name;
@@ -58,10 +130,10 @@ private:
};
Platform *platform;
- container::typed::List <View> *views;
+ View *view;
Widget *topLevel, *widgetAtPoint;
- /* The state, which must be projected into the views. */
+ /* The state, which must be projected into the view. */
style::Color *bgColor;
style::Cursor cursor;
int canvasWidth, canvasAscent, canvasDescent;
@@ -70,7 +142,7 @@ private:
int scrollX, scrollY, viewportWidth, viewportHeight;
bool canvasHeightGreater;
int hScrollbarThickness, vScrollbarThickness;
-
+
HPosition scrollTargetHpos;
VPosition scrollTargetVpos;
int scrollTargetX, scrollTargetY, scrollTargetWidth, scrollTargetHeight;
@@ -80,7 +152,7 @@ private:
bool scrollIdleNotInterrupted;
/* Anchors of the widget tree */
- container::typed::HashTable <object::String, Anchor> *anchorsTable;
+ lout::container::typed::HashTable <lout::object::String, Anchor> *anchorsTable;
SelectionState selectionState;
FindtextState findtextState;
@@ -136,13 +208,31 @@ private:
int ex, int ey, int ewidth, int eheight);
void queueResize ();
void removeWidget ();
-
+
public:
Layout (Platform *platform);
~Layout ();
- misc::ZoneAllocator *textZone;
-
+ inline void connectLink (LinkReceiver *receiver)
+ { linkEmitter.connectLink (receiver); }
+
+ inline bool emitLinkEnter (Widget *w, int link, int img, int x, int y)
+ { return linkEmitter.emitEnter (w, link, img, x, y); }
+
+ inline bool emitLinkPress (Widget *w, int link, int img,
+ int x, int y, EventButton *event)
+ { return linkEmitter.emitPress (w, link, img, x, y, event); }
+
+ inline bool emitLinkRelease (Widget *w, int link, int img,
+ int x, int y, EventButton *event)
+ { return linkEmitter.emitRelease (w, link, img, x, y, event); }
+
+ inline bool emitLinkClick (Widget *w, int link, int img,
+ int x, int y, EventButton *event)
+ { return linkEmitter.emitClick (w, link, img, x, y, event); }
+
+ lout::misc::ZoneAllocator *textZone;
+
void addWidget (Widget *widget);
void setWidget (Widget *widget);
@@ -159,6 +249,7 @@ public:
void scrollTo (HPosition hpos, VPosition vpos,
int x, int y, int width, int height);
+ void scroll (ScrollCommand);
void setAnchor (const char *anchor);
/* View */
@@ -168,7 +259,7 @@ public:
/**
* \brief This function is called by a view, to delegate a button press
* event.
- *
+ *
* \em numPressed is 1 for simple presses, 2 for double presses etc. (more
* that 2 is never needed), \em x and \em y the world coordinates, and
* \em button the number of the button pressed.
@@ -216,19 +307,34 @@ public:
return platform->prevGlyph (text, idx);
}
+ inline float dpiX ()
+ {
+ return platform->dpiX ();
+ }
+
+ inline float dpiY ()
+ {
+ return platform->dpiY ();
+ }
+
inline style::Font *createFont (style::FontAttrs *attrs, bool tryEverything)
{
return platform->createFont (attrs, tryEverything);
}
- inline style::Color *createSimpleColor (int color)
+ inline bool fontExists (const char *name)
+ {
+ return platform->fontExists (name);
+ }
+
+ inline style::Color *createColor (int color)
{
- return platform->createSimpleColor (color);
+ return platform->createColor (color);
}
- inline style::Color *createShadedColor (int color)
+ inline style::Tooltip *createTooltip (const char *text)
{
- return platform->createShadedColor (color);
+ return platform->createTooltip (text);
}
inline Imgbuf *createImgbuf (Imgbuf::Type type, int width, int height)
@@ -250,8 +356,9 @@ public:
emitter.connectLayout (receiver); }
/** \brief See dw::core::FindtextState::search. */
- inline FindtextState::Result search (const char *str, bool caseSens)
- { return findtextState.search (str, caseSens); }
+ inline FindtextState::Result search (const char *str, bool caseSens,
+ int backwards)
+ { return findtextState.search (str, caseSens, backwards); }
/** \brief See dw::core::FindtextState::resetSearch. */
inline void resetSearch () { findtextState.resetSearch (); }
diff --git a/dw/listitem.cc b/dw/listitem.cc
index ba960b46..ed7a2c75 100644
--- a/dw/listitem.cc
+++ b/dw/listitem.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -41,16 +40,20 @@ ListItem::~ListItem()
void ListItem::initWithWidget (core::Widget *widget,
core::style::Style *style)
{
+ hasListitemValue = true;
addWidget (widget, style);
addSpace (style);
- updateValue ();
+ if (style->listStylePosition == core::style::LIST_STYLE_POSITION_OUTSIDE)
+ updateValue ();
}
-void ListItem::initWithText (char *text, core::style::Style *style)
+void ListItem::initWithText (const char *text, core::style::Style *style)
{
+ hasListitemValue = true;
addText (text, style);
- addSpace (style);
- updateValue ();
+ addSpace (style);
+ if (style->listStylePosition == core::style::LIST_STYLE_POSITION_OUTSIDE)
+ updateValue ();
}
int ListItem::getValue ()
@@ -58,7 +61,7 @@ int ListItem::getValue ()
if (words->size () == 0)
return 0;
else
- return words->get(0).size.width + words->get(0).origSpace;
+ return words->getRef(0)->size.width + words->getRef(0)->origSpace;
}
void ListItem::setMaxValue (int maxValue, int value)
diff --git a/dw/listitem.hh b/dw/listitem.hh
index ea24af3e..2e303d5d 100644
--- a/dw/listitem.hh
+++ b/dw/listitem.hh
@@ -19,7 +19,7 @@ public:
~ListItem();
void initWithWidget (core::Widget *widget, core::style::Style *style);
- void initWithText (char *texty, core::style::Style *style);
+ void initWithText (const char *text, core::style::Style *style);
};
} // namespace dw
diff --git a/dw/platform.hh b/dw/platform.hh
index 0ae5d508..69d1feab 100644
--- a/dw/platform.hh
+++ b/dw/platform.hh
@@ -13,7 +13,7 @@ namespace core {
*
* \sa\ref dw-overview
*/
-class Platform: public object::Object
+class Platform: public lout::object::Object
{
public:
/*
@@ -27,7 +27,7 @@ public:
* a layout.
*/
virtual void setLayout (Layout *layout) = 0;
-
+
/*
* -------------------------
* Operations on views
@@ -45,10 +45,10 @@ public:
* from the related layout.
*/
virtual void detachView (View *view) = 0;
-
+
/*
* -----------------------------------
- * Platform dependant properties
+ * Platform dependent properties
* -----------------------------------
*/
@@ -66,7 +66,17 @@ public:
* \brief Return the index of the previous glyph in string text.
*/
virtual int prevGlyph (const char *text, int idx) = 0;
-
+
+ /**
+ * \brief Return screen resolution in x-direction.
+ */
+ virtual float dpiX () = 0;
+
+ /**
+ * \brief Return screen resolution in y-direction.
+ */
+ virtual float dpiY () = 0;
+
/*
* ---------------------------------------------------------
* These are to encapsulate some platform dependencies
@@ -75,7 +85,7 @@ public:
/**
* \brief Add an idle function.
- *
+ *
* An idle function is called once, when no other
* tasks are to be done (e.g. there are no events to process), and then
* removed from the queue. The return value is a number, which can be
@@ -95,10 +105,10 @@ public:
*/
/**
- * \brief Create a (platform dependant) font.
+ * \brief Create a (platform dependent) font.
*
* Typically, within a platform, a sub class of dw::core::style::Font
- * is defined, which holds more platform dependant data.
+ * is defined, which holds more platform dependent data.
*
* Also, this method must fill the attributes "font" (when needed),
* "ascent", "descent", "spaceSidth" and "xHeight". If "tryEverything"
@@ -108,17 +118,18 @@ public:
*/
virtual style::Font *createFont (style::FontAttrs *attrs,
bool tryEverything) = 0;
-
+
+ virtual bool fontExists (const char *name) = 0;
+
/**
- * \brief Create a simple color resource for a given 0xrrggbb value.
+ * \brief Create a color resource for a given 0xrrggbb value.
*/
- virtual style::Color *createSimpleColor (int color) = 0;
+ virtual style::Color *createColor (int color) = 0;
/**
- * \brief Create a shaded color resource for a given 0xrrggbb value.
+ * \brief Create a tooltip
*/
- virtual style::Color *createShadedColor (int color) = 0;
-
+ virtual style::Tooltip *createTooltip (const char *text) = 0;
/*
* --------------------
diff --git a/dw/ruler.cc b/dw/ruler.cc
index abefa1bf..6dce07d0 100644
--- a/dw/ruler.cc
+++ b/dw/ruler.cc
@@ -14,15 +14,14 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ruler.hh"
#include "../lout/misc.hh"
-
+
#include <stdio.h>
namespace dw {
diff --git a/dw/ruler.hh b/dw/ruler.hh
index a1ae67ea..32e859a1 100644
--- a/dw/ruler.hh
+++ b/dw/ruler.hh
@@ -17,12 +17,12 @@ class Ruler: public core::Widget
{
protected:
void sizeRequestImpl (core::Requisition *requisition);
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area);
public:
Ruler ();
- core::Iterator *iterator (core::Content::Type mask, bool atEnd);
+ core::Iterator *iterator (core::Content::Type mask, bool atEnd);
};
} // namespace dw
diff --git a/dw/selection.cc b/dw/selection.cc
index 3153576f..275eddaa 100644
--- a/dw/selection.cc
+++ b/dw/selection.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -24,6 +23,8 @@
#include <string.h>
+using namespace lout;
+
/*
* strndup() is a GNU extension.
*/
@@ -95,13 +96,13 @@ void SelectionState::resetLink ()
link = NULL;
linkState = LINK_NONE;
}
-
+
bool SelectionState::buttonPress (Iterator *it, int charPos, int linkNo,
EventButton *event, bool withinContent)
{
Widget *itWidget = it->getWidget ();
bool ret = false;
-
+
if (event && event->button == 1 &&
!withinContent && event->numPressed == 2) {
// When the user double-clicks on empty parts, emit the double click
@@ -117,8 +118,7 @@ bool SelectionState::buttonPress (Iterator *it, int charPos, int linkNo,
if (linkNo != -1) {
// link handling
if (event) {
- // return value is ignored
- itWidget->emitLinkPress (linkNo, -1, -1, -1, event);
+ (void) layout->emitLinkPress (itWidget, linkNo, -1, -1, -1, event);
resetLink ();
linkState = LINK_PRESSED;
linkButton = event->button;
@@ -161,7 +161,7 @@ bool SelectionState::buttonPress (Iterator *it, int charPos, int linkNo,
} else {
if (event && event->button == 3) {
// menu popup
- itWidget->emitLinkPress (-1, -1, -1, -1, event);
+ layout->emitLinkPress (itWidget, -1, -1, -1, -1, event);
ret = true;
}
}
@@ -181,14 +181,12 @@ bool SelectionState::buttonRelease (Iterator *it, int charPos, int linkNo,
// link handling
ret = true;
if (linkNo != -1)
- // return value is ignored
- itWidget->emitLinkRelease (linkNo, -1, -1, -1, event);
+ (void) layout->emitLinkRelease (itWidget, linkNo, -1, -1, -1, event);
// The link where the user clicked the mouse button?
if (linkNo == linkNumber) {
resetLink ();
- // return value is ignored
- itWidget->emitLinkClick (linkNo, -1, -1, -1, event);
+ (void) layout->emitLinkClick (itWidget, linkNo, -1, -1, -1, event);
} else {
if (event->button == 1)
// Reset links and switch to selection mode. The selection
diff --git a/dw/selection.hh b/dw/selection.hh
index 9cc8d25f..ba03fd18 100644
--- a/dw/selection.hh
+++ b/dw/selection.hh
@@ -8,30 +8,28 @@
namespace dw {
namespace core {
-using namespace lout;
-
/**
* \brief This class handles selections, as well as activation of links,
* which is closely related.
*
* <h3>General Overview</h3>
- *
+ *
* dw::core::SelectionState is associated with dw::core::Layout. The selection
* state is controlled by "abstract events", which are sent by single
* widgets by calling one of the following methods:
- *
+ *
* <ul>
* <li> dw::core::SelectionState::buttonPress for button press events,
* <li> dw::core::SelectionState::buttonRelease for button release events, and
* <li> dw::core::SelectionState::buttonMotion for motion events (with pressed
* mouse button).
* </ul>
- *
+ *
* The widget must construct simple iterators (dw::core::Iterator), which will
* be transferred to deep iterators (dw::core::DeepIterator), see below for
* more details. All event handling methods have the same signature, the
* arguments in detail are:
- *
+ *
* <table>
* <tr><td>dw::core::Iterator *it <td>the iterator pointing on the item
* under the mouse pointer; this
@@ -42,7 +40,7 @@ using namespace lout;
* within the iterator,
* <tr><td>int linkNo <td>if this item is associated with a
* link, its number (see
- * dw::core::Widget::LinkReceiver),
+ * dw::core::Layout::LinkReceiver),
* otherwise -1
* <tr><td>dw::core::EventButton *event <td>the event itself; only the button
* is used
@@ -64,26 +62,26 @@ using namespace lout;
* simple iterator is discarded and instead the stack has an iterator
* pointing to text at the top. As a result, only the first letter of the
* ALT text would be copied.
- *
+ *
* To avoid this problem, widgets should in this case pass
* dw::core::SelectionState::END_OF_WORD as \em charPos, which is then
* automatically reduced to the actual length of the deep(!) iterator.
- *
+ *
* The return value is the same as in DwWidget event handling methods.
* I.e., in most cases, they should simply return it. The events
- * dw::core::Widget::LinkReceiver::press,
- * dw::core::Widget::LinkReceiver::release and
- * dw::core::Widget::LinkReceiver::click (but not
- * dw::core::Widget::LinkReceiver::enter) are emitted by these methods, so
+ * dw::core::Layout::LinkReceiver::press,
+ * dw::core::Layout::LinkReceiver::release and
+ * dw::core::Layout::LinkReceiver::click (but not
+ * dw::core::Layout::LinkReceiver::enter) are emitted by these methods, so
* that widgets which let dw::core::SelectionState handle links, should only
- * emit dw::core::Widget::LinkReceiver::enter for themselves.
- *
+ * emit dw::core::Layout::LinkReceiver::enter for themselves.
+ *
* <h3>Selection State</h3>
- *
+ *
* Selection interferes with handling the activation of links, so the
* latter is also handled by the dw::core::SelectionState. Details are based on
* following guidelines:
- *
+ *
* <ol>
* <li> It should be simple to select links and to start selection in
* links. The rule to distinguish between link activation and
@@ -91,18 +89,18 @@ using namespace lout;
* the link. (This is, IMO, a useful feature. Even after drag and
* drop has been implemented in dillo, this should be somehow
* preserved.)
- *
+ *
* <li> The selection should stay as long as possible, i.e., the old
* selection is only cleared when a new selection is started.
* </ol>
- *
+ *
* The latter leads to a model with two states: the selection state and
* the link handling state.
- *
+ *
* The general selection works, for events not pointing on links, like
* this (numbers in parantheses after the event denote the button, "n"
* means arbitrary button):
- *
+ *
* \dot
* digraph G {
* node [shape=ellipse, fontname=Helvetica, fontsize=10];
@@ -122,15 +120,15 @@ using namespace lout;
* q -> SELECTED [label="yes"];
* q -> NONE [label="no"];
* SELECTED -> SELECTING [label="press(1)"];
- *
+ *
* }
* \enddot
*
* The selected region is represented by two instances of
* dw::core::DeepIterator.
- *
+ *
* Links are handled by a different state machine:
- *
+ *
* \dot
* digraph G {
* node [shape=ellipse, fontname=Helvetica, fontsize=10];
@@ -170,16 +168,16 @@ using namespace lout;
* eventually be SELECTED/SELECTING, with the original and the current
* position making up the selection region. This happens for button 1,
* events with buttons other than 1 do not affect selection at all.
- *
- *
+ *
+ *
* \todo dw::core::SelectionState::buttonMotion currently always assumes
* that button 1 has been pressed (since otherwise it would not do
* anything). This should be made a bit cleaner.
- *
+ *
* \todo The selection should be cleared, when the user selects something
* somewhere else (perhaps switched into "non-active" mode, as e.g. Gtk+
* does).
- *
+ *
*/
class SelectionState
{
@@ -248,15 +246,15 @@ private:
public:
enum EventType { BUTTON_PRESS, BUTTON_RELEASE, BUTTON_MOTION };
-
+
SelectionState ();
~SelectionState ();
-
+
inline void setLayout (Layout *layout) { this->layout = layout; }
void reset ();
inline void connectDoubleClick (DoubleClickReceiver *receiver)
{ doubleClickEmitter.connectDoubleClick (receiver); }
-
+
bool buttonPress (Iterator *it, int charPos, int linkNo,
EventButton *event, bool withinContent);
bool buttonRelease (Iterator *it, int charPos, int linkNo,
diff --git a/dw/style.cc b/dw/style.cc
index 207c47a3..b361e068 100644
--- a/dw/style.cc
+++ b/dw/style.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
@@ -24,6 +23,9 @@
#include <ctype.h>
#include "core.hh"
+#include "../lout/msg.h"
+
+using namespace lout;
namespace dw {
namespace core {
@@ -37,14 +39,13 @@ void StyleAttrs::initValues ()
textDecoration = TEXT_DECORATION_NONE;
textAlign = TEXT_ALIGN_LEFT;
textAlignChar = '.';
+ listStylePosition = LIST_STYLE_POSITION_OUTSIDE;
listStyleType = LIST_STYLE_TYPE_DISC;
- valign = VALIGN_MIDDLE;
+ valign = VALIGN_BASELINE;
backgroundColor = NULL;
- width = LENGTH_AUTO;
- height = LENGTH_AUTO;
+ width = height = lineHeight = LENGTH_AUTO;
vloat = FLOAT_NONE;
clear = CLEAR_NONE;
-
margin.setVal (0);
borderWidth.setVal (0);
padding.setVal (0);
@@ -52,6 +53,7 @@ void StyleAttrs::initValues ()
setBorderStyle (BORDER_NONE);
hBorderSpacing = 0;
vBorderSpacing = 0;
+ wordSpacing = 0;
display = DISPLAY_INLINE;
whiteSpace = WHITE_SPACE_NORMAL;
@@ -64,12 +66,9 @@ void StyleAttrs::initValues ()
*/
void StyleAttrs::resetValues ()
{
- x_link = -1;
x_img = -1;
- x_tooltip = NULL;
- textAlign = TEXT_ALIGN_LEFT; /* ??? */
- valign = VALIGN_MIDDLE;
+ valign = VALIGN_BASELINE;
textAlignChar = '.';
vloat = FLOAT_NONE; /** \todo Correct? Check specification. */
clear = CLEAR_NONE; /** \todo Correct? Check specification. */
@@ -86,8 +85,6 @@ void StyleAttrs::resetValues ()
vBorderSpacing = 0;
display = DISPLAY_INLINE;
- whiteSpace = WHITE_SPACE_NORMAL;
- cursor = CURSOR_DEFAULT; /** \todo Check CSS specification again. */
}
/**
@@ -121,8 +118,10 @@ bool StyleAttrs::equals (object::Object *other) {
textAlignChar == otherAttrs->textAlignChar &&
hBorderSpacing == otherAttrs->hBorderSpacing &&
vBorderSpacing == otherAttrs->vBorderSpacing &&
+ wordSpacing == otherAttrs->wordSpacing &&
width == otherAttrs->width &&
height == otherAttrs->height &&
+ lineHeight == otherAttrs->lineHeight &&
margin.equals (&otherAttrs->margin) &&
borderWidth.equals (&otherAttrs->borderWidth) &&
padding.equals (&otherAttrs->padding) &&
@@ -136,7 +135,9 @@ bool StyleAttrs::equals (object::Object *other) {
borderStyle.left == otherAttrs->borderStyle.left &&
display == otherAttrs->display &&
whiteSpace == otherAttrs->whiteSpace &&
+ listStylePosition == otherAttrs->listStylePosition &&
listStyleType == otherAttrs->listStyleType &&
+ cursor == otherAttrs->cursor &&
x_link == otherAttrs->x_link &&
x_img == otherAttrs->x_img &&
x_tooltip == otherAttrs->x_tooltip);
@@ -152,10 +153,12 @@ int StyleAttrs::hashValue () {
textAlignChar +
hBorderSpacing +
vBorderSpacing +
+ wordSpacing +
width +
height +
+ lineHeight +
margin.hashValue () +
- borderWidth.hashValue () +
+ borderWidth.hashValue () +
padding.hashValue () +
(intptr_t) borderColor.top +
(intptr_t) borderColor.right +
@@ -167,7 +170,9 @@ int StyleAttrs::hashValue () {
borderStyle.left +
display +
whiteSpace +
+ listStylePosition +
listStyleType +
+ cursor +
x_link +
x_img +
(intptr_t) x_tooltip;
@@ -222,7 +227,7 @@ Style::~Style ()
x_tooltip->unref();
styleTable->remove (this);
- totalRef--;
+ totalRef--;
}
void Style::copyAttrs (StyleAttrs *attrs)
@@ -238,8 +243,10 @@ void Style::copyAttrs (StyleAttrs *attrs)
clear = attrs->clear;
hBorderSpacing = attrs->hBorderSpacing;
vBorderSpacing = attrs->vBorderSpacing;
+ wordSpacing = attrs->wordSpacing;
width = attrs->width;
height = attrs->height;
+ lineHeight = attrs->lineHeight;
margin = attrs->margin;
borderWidth = attrs->borderWidth;
padding = attrs->padding;
@@ -247,6 +254,7 @@ void Style::copyAttrs (StyleAttrs *attrs)
borderStyle = attrs->borderStyle;
display = attrs->display;
whiteSpace = attrs->whiteSpace;
+ listStylePosition = attrs->listStylePosition;
listStyleType = attrs->listStyleType;
cursor = attrs->cursor;
x_link = attrs->x_link;
@@ -261,8 +269,11 @@ bool FontAttrs::equals(object::Object *other)
FontAttrs *otherAttrs = (FontAttrs*)other;
return
this == otherAttrs ||
- (size == otherAttrs->size && weight == otherAttrs->weight &&
- style == otherAttrs->style && strcmp (name, otherAttrs->name) == 0);
+ (size == otherAttrs->size &&
+ weight == otherAttrs->weight &&
+ style == otherAttrs->style &&
+ letterSpacing == otherAttrs->letterSpacing &&
+ strcmp (name, otherAttrs->name) == 0);
}
int FontAttrs::hashValue()
@@ -271,12 +282,13 @@ int FontAttrs::hashValue()
h = (h << 5) - h + size;
h = (h << 5) - h + weight;
h = (h << 5) - h + style;
+ h = (h << 5) - h + letterSpacing;
return h;
}
Font::~Font ()
{
- delete name;
+ free ((char*)name);
}
void Font::copyAttrs (FontAttrs *attrs)
@@ -285,6 +297,7 @@ void Font::copyAttrs (FontAttrs *attrs)
size = attrs->size;
weight = attrs->weight;
style = attrs->style;
+ letterSpacing = attrs->letterSpacing;
}
Font *Font::create0 (Layout *layout, FontAttrs *attrs,
@@ -298,43 +311,9 @@ Font *Font::create (Layout *layout, FontAttrs *attrs)
return create0 (layout, attrs, false);
}
-Font *Font::createFromList (Layout *layout, FontAttrs *attrs,
- char *defaultFamily)
+bool Font::exists (Layout *layout, const char *name)
{
- Font *font = NULL;
- FontAttrs attrs2;
- char *comma, *list, *current;
-
- attrs2 = *attrs;
- current = list = strdup (attrs->name);
-
- while (current && (font == NULL)) {
- comma = strchr (current, ',');
- if (comma) *comma = 0;
-
- attrs2.name = current;
- font = create0 (layout, &attrs2, false);
- if (font)
- break;
-
- if (comma) {
- current = comma + 1;
- while (isspace (*current)) current++;
- } else
- current = NULL;
- }
-
- delete list;
-
- if (font == NULL) {
- attrs2.name = defaultFamily;
- font = create0 (layout, &attrs2, true);
- }
-
- if (font == NULL)
- fprintf (stderr, "Could not find any font.\n");
-
- return font;
+ return layout->fontExists (name);
}
// ----------------------------------------------------------------------
@@ -342,12 +321,12 @@ Font *Font::createFromList (Layout *layout, FontAttrs *attrs,
bool ColorAttrs::equals(object::Object *other)
{
ColorAttrs *oc = (ColorAttrs*)other;
- return this == oc || (color == oc->color && type == oc->type);
+ return this == oc || (color == oc->color);
}
int ColorAttrs::hashValue()
{
- return color ^ type;
+ return color;
}
Color::~Color ()
@@ -410,72 +389,33 @@ int Color::shadeColor (int color, Shading shading)
}
}
-
-Color *Color::create (Layout *layout, int col, Type type)
+
+Color *Color::create (Layout *layout, int col)
{
- ColorAttrs attrs(col, type);
- Color *color = NULL;
-
- switch (type) {
- case TYPE_SIMPLE:
- color = layout->createSimpleColor (col);
- break;
- case TYPE_SHADED:
- color = layout->createShadedColor (col);
- break;
- }
+ ColorAttrs attrs(col);
- return color;
+ return layout->createColor (col);
+}
+
+Tooltip *Tooltip::create (Layout *layout, const char *text)
+{
+ return layout->createTooltip (text);
}
// ----------------------------------------------------------------------
-/**
- * \brief Draw a part of a border.
- */
-static void drawPolygon (View *view, Color *color, Color::Shading shading,
- int x1, int y1, int x2, int y2,
- int width, int w1, int w2)
-{
- int points[4][2];
-
- if (width != 0) {
- if (width == 1) {
- if (x1 == x2)
- view->drawLine (color, shading, x1, y1, x2, y2 - 1);
- else
- view->drawLine (color, shading, x1, y1, x2 - 1, y2);
- } else if (width == -1) {
- if (x1 == x2)
- view->drawLine (color, shading, x1 - 1, y1, x2 - 1, y2 - 1);
- else
- view->drawLine (color, shading, x1, y1 - 1, x2 - 1, y2 - 1);
- } else {
- points[0][0] = x1;
- points[0][1] = y1;
- points[1][0] = x2;
- points[1][1] = y2;
-
- if (x1 == x2) {
- points[2][0] = x1 + width;
- points[2][1] = y2 + w2;
- points[3][0] = x1 + width;
- points[3][1] = y1 + w1;
- } else {
- points[2][0] = x2 + w2;
- points[2][1] = y1 + width;
- points[3][0] = x1 + w1;
- points[3][1] = y1 + width;
- }
-
- /*
- printf ("drawPolygon: (%d, %d) .. (%d, %d) .. (%d, %d) .. (%d, %d)\n",
- points[0][0], points[0][1], points[1][0], points[1][1],
- points[2][0], points[2][1], points[3][0], points[3][1]);
- */
- view->drawPolygon (color, shading, true, points, 4);
- }
- }
+static void drawTriangle (View *view, Color *color, Color::Shading shading,
+ int x1, int y1, int x2, int y2, int x3, int y3) {
+ int points[3][2];
+
+ points[0][0] = x1;
+ points[0][1] = y1;
+ points[1][0] = x2;
+ points[1][1] = y2;
+ points[2][0] = x3;
+ points[2][1] = y3;
+
+ view->drawPolygon (color, shading, true, points, 3);
}
/**
@@ -492,18 +432,17 @@ void drawBorder (View *view, Rectangle *area,
Color::Shading top, right, bottom, left;
int xb1, yb1, xb2, yb2, xp1, yp1, xp2, yp2;
- if (style->borderStyle.top == BORDER_NONE)
- return;
-
+ // top left and bottom right point of outer border boundary
xb1 = x + style->margin.left;
yb1 = y + style->margin.top;
- xb2 = xb1 + width - style->margin.left - style->margin.right;
- yb2 = yb1 + height - style->margin.top - style->margin.bottom;
+ xb2 = x + width - style->margin.right;
+ yb2 = y + height - style->margin.bottom;
- xp1 = xb1 + style->borderWidth.top;
- yp1 = yb1 + style->borderWidth.left;
- xp2 = xb2 + style->borderWidth.bottom;
- yp2 = yb2 + style->borderWidth.right;
+ // top left and bottom right point of inner border boundary
+ xp1 = xb1 + style->borderWidth.left;
+ yp1 = yb1 + style->borderWidth.top;
+ xp2 = xb2 - style->borderWidth.right;
+ yp2 = yb2 - style->borderWidth.bottom;
light = inverse ? Color::SHADING_DARK : Color::SHADING_LIGHT;
dark = inverse ? Color::SHADING_LIGHT : Color::SHADING_DARK;
@@ -525,18 +464,47 @@ void drawBorder (View *view, Rectangle *area,
break;
}
- drawPolygon (view, style->borderColor.top, top, xb1, yb1, xb2, yb1,
- style->borderWidth.top, style->borderWidth.left,
- - style->borderWidth.right);
- drawPolygon (view, style->borderColor.right, right, xb2, yb1, xb2, yb2,
- - style->borderWidth.right, style->borderWidth.top,
- - style->borderWidth.bottom);
- drawPolygon (view, style->borderColor.bottom, bottom, xb1, yb2, xb2, yb2,
- - style->borderWidth.bottom, style->borderWidth.left,
- - style->borderWidth.right);
- drawPolygon (view, style->borderColor.left, left, xb1, yb1, xb1, yb2,
- style->borderWidth.left, style->borderWidth.top,
- - style->borderWidth.bottom);
+ if (style->borderStyle.top != BORDER_NONE && style->borderColor.top)
+ view->drawRectangle(style->borderColor.top, top, true,
+ xb1, yb1, xb2 - xb1, style->borderWidth.top);
+
+ if (style->borderStyle.bottom != BORDER_NONE && style->borderColor.bottom)
+ view->drawRectangle(style->borderColor.bottom, bottom, true,
+ xb1, yb2, xb2 - xb1, - style->borderWidth.bottom);
+
+ if (style->borderStyle.left != BORDER_NONE && style->borderColor.left)
+ view->drawRectangle(style->borderColor.left, left, true,
+ xb1, yp1, style->borderWidth.left, yp2 - yp1);
+
+ if (style->borderWidth.left > 1) {
+ if (style->borderWidth.top > 1 &&
+ (style->borderColor.left != style->borderColor.top ||
+ left != top))
+ drawTriangle (view, style->borderColor.left, left,
+ xb1, yp1, xp1, yp1, xb1, yb1);
+ if (style->borderWidth.bottom > 1 &&
+ (style->borderColor.left != style->borderColor.bottom ||
+ left != bottom))
+ drawTriangle (view, style->borderColor.left, left,
+ xb1, yp2, xp1, yp2, xb1, yb2);
+ }
+
+ if (style->borderStyle.right != BORDER_NONE && style->borderColor.right)
+ view->drawRectangle(style->borderColor.right, right, true,
+ xb2, yp1, - style->borderWidth.right, yp2 - yp1);
+
+ if (style->borderWidth.right > 1) {
+ if (style->borderWidth.top > 1 &&
+ (style->borderColor.right != style->borderColor.top ||
+ right != top))
+ drawTriangle (view, style->borderColor.right, right,
+ xb2, yp1, xp2, yp1, xb2, yb1);
+ if (style->borderWidth.bottom > 1 &&
+ (style->borderColor.right != style->borderColor.bottom ||
+ right != bottom))
+ drawTriangle (view, style->borderColor.right, right,
+ xb2, yp2, xp2, yp2, xb2, yb2);
+ }
}
@@ -574,12 +542,12 @@ void drawBackground (View *view, Rectangle *area,
// ----------------------------------------------------------------------
static const char
- *roman_I0[] = { "","I","II","III","IV","V","VI","VII","VIII","IX" },
- *roman_I1[] = { "","X","XX","XXX","XL","L","LX","LXX","LXXX","XC" },
- *roman_I2[] = { "","C","CC","CCC","CD","D","DC","DCC","DCCC","CM" },
- *roman_I3[] = { "","M","MM","MMM","MMMM" };
+ *const roman_I0[] = { "","I","II","III","IV","V","VI","VII","VIII","IX" },
+ *const roman_I1[] = { "","X","XX","XXX","XL","L","LX","LXX","LXXX","XC" },
+ *const roman_I2[] = { "","C","CC","CCC","CD","D","DC","DCC","DCCC","CM" },
+ *const roman_I3[] = { "","M","MM","MMM","MMMM" };
-void strtolower (char *s)
+static void strtolower (char *s)
{
for ( ; *s; s++)
*s = tolower (*s);
@@ -596,16 +564,21 @@ void numtostr (int num, char *buf, int buflen, ListStyleType listStyleType)
bool low = false;
int start_ch = 'A';
+ if (buflen <= 0)
+ return;
+
switch(listStyleType){
case LIST_STYLE_TYPE_LOWER_ALPHA:
+ case LIST_STYLE_TYPE_LOWER_LATIN:
start_ch = 'a';
case LIST_STYLE_TYPE_UPPER_ALPHA:
+ case LIST_STYLE_TYPE_UPPER_LATIN:
i0 = num - 1;
i1 = i0/26 - 1; i2 = i1/26 - 1;
if (i2 > 25) /* more than 26+26^2+26^3=18278 elements ? */
- sprintf(buf, "****.");
+ snprintf(buf, buflen, "****.");
else
- sprintf(buf, "%c%c%c.",
+ snprintf(buf, buflen, "%c%c%c.",
i2<0 ? ' ' : start_ch + i2%26,
i1<0 ? ' ' : start_ch + i1%26,
i0<0 ? ' ' : start_ch + i0%26);
@@ -617,18 +590,23 @@ void numtostr (int num, char *buf, int buflen, ListStyleType listStyleType)
i1 = i0/10; i2 = i1/10; i3 = i2/10;
i0 %= 10; i1 %= 10; i2 %= 10;
if (num < 0 || i3 > 4) /* more than 4999 elements ? */
- sprintf(buf, "****.");
+ snprintf(buf, buflen, "****.");
else
snprintf(buf, buflen, "%s%s%s%s.", roman_I3[i3], roman_I2[i2],
roman_I1[i1], roman_I0[i0]);
- if (low)
- strtolower(buf);
break;
case LIST_STYLE_TYPE_DECIMAL:
default:
- sprintf(buf, "%d.", num);
+ snprintf(buf, buflen, "%d.", num);
break;
}
+
+ // ensure termination
+ buf[buflen - 1] = '\0';
+
+ if (low)
+ strtolower(buf);
+
}
} // namespace style
diff --git a/dw/style.hh b/dw/style.hh
index a96a3471..81d47930 100644
--- a/dw/style.hh
+++ b/dw/style.hh
@@ -14,100 +14,100 @@ namespace core {
* \brief Anything related to Dillo %Widget styles is defined here.
*
* <h3>Overview</h3>
- *
+ *
* dw::core::style::Style provides some resources and attributes for
* drawing widgets, as well as for parts of a widget (e.g., dw::Textblock
* uses styles for its words). Creating a style is done by filling a
* dw::core::style::StyleAttrs with the attributes and calling
* dw::core::style::Style::create:
- *
+ *
* \code
* dw::core::style::Style styleAttrs;
* dw::core::style::Style *style;
* dw::core::Layout *layout;
- *
+ *
* // ...
- *
+ *
* styleAttrs.foo = bar;
* // etc.
* style = dw::core::style::Style::create (&styleAttrs, layout);
* // do something with style
* \endcode
- *
+ *
* After this, the attributes of a dw::core::style::Style should not be
* changed anymore, since styles are often shared between different
* widgets etc. (see below). Most times, you simply copy the attributes
* of another style (possible, since dw::core::style::Style is a sub
* class of dw::core::style::StyleAttrs), modify them and create a new
* style:
- *
+ *
* \code
* styleAttrs = *anotherStyle;
* styleAttrs.foo = baz;
* style = dw::core::style::Style::create (&styleAttrs, layout);
* \endcode
- *
+ *
* The dw::core::style::Font structure can be created by
* dw::core::style::Font::create, in a similar, with
* dw::core::style::FontAttrs, and colors by
* dw::core::style::Color::create, passing 0xrrggbb as an
* argument. Furthermore, there is dw::core::style::Tooltip, created by
* dw::core::style::Tooltip::create.
- *
+ *
* Notice that fonts, colors and tooltips are only intended to be used in
* conjunction with dw::core::style::Style.
- *
- *
+ *
+ *
* <h3>Naming</h3>
- *
+ *
* dw::core::style::Style will become important for CSS, each CSS
* attribute, which is supported by dillo, will refer to an attribute in
* dw::core::style::Style. For this reason, the attributes in
* dw::core::style::Style get the names from the CSS attributes, with
* "camelCase" instead of hythens (e.g. "background-color" becomes
* "backgroundColor").
- *
+ *
* However, dw::core::style::Style will be extended by some more
* attributes, which are not defined by CSS. To distinguish them, they
* get the prefix "x_", e.g. dw::core::style::Style::x_link.
- *
- *
+ *
+ *
* <h3>Lengths and Percentages</h3>
- *
+ *
* dw::core::style::Length is a simple data type for lengths and
* percentages:
- *
+ *
* <ul>
* <li> A length refers to an absolute measurement. It is used to
* represent the HTML type %Pixels; and the CSS type \<length\>.
- *
- * For CSS lenghts, there are two units: (i) pixels and absolute
+ *
+ * For CSS lengths, there are two units: (i) pixels and absolute
* units, which have to be converted to pixels (a pixel is, unlike
* in the CSS specification, treated as absolute unit), and (ii) the
* relative units "em" and "ex" (see below).
- *
+ *
* <li> A percentage refers to a value relative to another value. It is
* used for the HTML type %Length; (except %Pixels;), and the CSS
* type \<percentage\>.
- *
+ *
* <li> A relative length can be used in lists of HTML MultiLengths.
* </ul>
- *
+ *
* Since many values in CSS may be either lengths or percentages, a
* single type is very useful.
- *
+ *
* <h4>Useful Functions</h4>
- *
+ *
* Creating lengths:
- *
+ *
* <ul>
* <li> dw::core::style::createAbsLength
* <li> dw::core::style::createPerLength
* <li> dw::core::style::createRelLength
* </ul>
- *
+ *
* Examine lengths:
- *
+ *
* <ul>
* <li> dw::core::style::isAbsLength
* <li> dw::core::style::isPerLength
@@ -116,61 +116,61 @@ namespace core {
* <li> dw::core::style::perLengthVal
* <li> dw::core::style::relLengthVal
* </ul>
- *
- *
+ *
+ *
* <h3>Boxes</h3>
- *
+ *
* <h4>The CSS %Box Model</h4>
- *
+ *
* For borders, margins etc., the box model defined by CSS2 is
* used. dw::core::style::Style contains some members defining these
* attributes. A dw::core::Widget must use these values for any
* calculation of sizes. There are some helper functions (see
* dw/style.hh). A dw::core::style::Style box looks quite similar to a
* CSS box:
- *
+ *
* \image html dw-style-box-model.png
- *
+ *
* <h4>Background colors</h4>
- *
+ *
* The background color is stored in
* dw::core::style::Style::backgroundColor, which may be NULL (the
* background color of the parent widget is shining through).
- *
+ *
* For toplevel widgets, this color is set as the background color of the
* views (dw::core::View::setBgColor), for other widgets, a filled
* rectangle is drawn, covering the content and padding. (This is
* compliant with CSS2, the background color of the toplevel element
* covers the whole canvas.)
- *
+ *
* <h4>Drawing</h4>
- *
+ *
* The following methods may be useful:
- *
+ *
* <ul>
* <li> dw::core::Widget::drawWidgetBox for drawing the box of a widget
* (typically at the beginning of the implementation of
* dw::core::Widget::draw), and
- *
+ *
* <li> dw::core::Widget::drawBox, for drawing parts of a widget (e.g.
* dw::Textblock::Word, which has its own dw::Textblock::Word::style).
* </ul>
- *
- *
+ *
+ *
* <h3>Notes on Memory Management</h3>
- *
+ *
* Memory management is done by reference counting,
* dw::core::style::Style::create returns a pointer to
* dw::core::style::Style with an increased reference counter, so you
* should care about calling dw::core::style::Style::unref if it is not
* used anymore. You do \em not need to care about the reference counters
* of fonts and styles.
- *
+ *
* In detail:
- *
+ *
* <ul>
* <li> dw::core::style::Style::ref is called in
- *
+ *
* <ul>
* <li> dw::core::Widget::setStyle to assign a style to a widget,
* <li> dw::Textblock::addText, dw::Textblock::addWidget,
@@ -179,9 +179,9 @@ namespace core {
* to assign a style to a dw::Textblock::Word, and
* <li> by the HTML parser, when pushing an element on the stack.
* </ul>
- *
+ *
* <li> dw::core::style::Style::unref is called in
- *
+ *
* <ul>
* <li> dw::core::Widget::~Widget, dw::Textblock::~Textblock, by the
* HTML parser, when popping an element fom the stack, and
@@ -237,7 +237,9 @@ enum VAlignType {
VALIGN_MIDDLE,
VALIGN_BASELINE,
VALIGN_SUB,
- VALIGN_SUPER
+ VALIGN_SUPER,
+ VALIGN_TEXT_TOP,
+ VALIGN_TEXT_BOTTOM,
};
/**
@@ -247,15 +249,19 @@ enum DisplayType {
DISPLAY_BLOCK,
DISPLAY_INLINE,
DISPLAY_LIST_ITEM,
+ DISPLAY_NONE,
DISPLAY_TABLE,
DISPLAY_TABLE_ROW_GROUP,
DISPLAY_TABLE_HEADER_GROUP,
DISPLAY_TABLE_FOOTER_GROUP,
DISPLAY_TABLE_ROW,
- DISPLAY_TABLE_CELL,
- DISPLAY_LAST
+ DISPLAY_TABLE_CELL
};
+enum ListStylePosition {
+ LIST_STYLE_POSITION_INSIDE,
+ LIST_STYLE_POSITION_OUTSIDE
+};
enum ListStyleType {
LIST_STYLE_TYPE_DISC,
LIST_STYLE_TYPE_CIRCLE,
@@ -297,7 +303,9 @@ enum TextDecoration {
enum WhiteSpace {
WHITE_SPACE_NORMAL,
WHITE_SPACE_PRE,
- WHITE_SPACE_NOWRAP
+ WHITE_SPACE_NOWRAP,
+ WHITE_SPACE_PRE_WRAP,
+ WHITE_SPACE_PRE_LINE,
};
enum FloatType {
@@ -331,15 +339,15 @@ enum ClearType {
* This is an implementation detail, use one of the following functions:
*
* Creating lengths:
- *
+ *
* <ul>
* <li> dw::core::style::createAbsLength
* <li> dw::core::style::createPerLength
* <li> dw::core::style::createRelLength
* </ul>
- *
+ *
* Examine lengths:
- *
+ *
* <ul>
* <li> dw::core::style::isAbsLength
* <li> dw::core::style::isPerLength
@@ -349,7 +357,7 @@ enum ClearType {
* <li> dw::core::style::relLengthVal
* </ul>
*
- * "auto" lenghths are represented as dw::core::style::LENGTH_AUTO.
+ * "auto" lengths are represented as dw::core::style::LENGTH_AUTO.
*/
typedef int Length;
@@ -358,11 +366,11 @@ inline Length createAbsLength(int n) { return (n << 2) | 1; }
/** \brief Returns a percentage, \em v is relative to 1, not to 100. */
inline Length createPerLength(double v) {
- return (int)(v * (1 << 18)) & ~3 | 2; }
+ return ((int)(v * (1 << 18)) & ~3) | 2; }
/** \brief Returns a relative length. */
inline Length createRelLength(double v) {
- return (int)(v * (1 << 18)) & ~3 | 3; }
+ return ((int)(v * (1 << 18)) & ~3) | 3; }
/** \brief Returns true if \em l is an absolute length. */
inline bool isAbsLength(Length l) { return (l & 3) == 1; }
@@ -418,7 +426,7 @@ class Tooltip;
/**
* \sa dw::core::style
*/
-class StyleAttrs : public object::Object
+class StyleAttrs : public lout::object::Object
{
public:
Font *font;
@@ -433,8 +441,8 @@ public:
FloatType vloat; /* "float" is a keyword. */
ClearType clear;
- int hBorderSpacing, vBorderSpacing;
- Length width, height;
+ int hBorderSpacing, vBorderSpacing, wordSpacing;
+ Length width, height, lineHeight;
Box margin, borderWidth, padding;
struct { Color *top, *right, *bottom, *left; } borderColor;
@@ -442,13 +450,14 @@ public:
DisplayType display;
WhiteSpace whiteSpace;
+ ListStylePosition listStylePosition;
ListStyleType listStyleType;
Cursor cursor;
int x_link;
int x_img;
Tooltip *x_tooltip;
-
+
void initValues ();
void resetValues ();
@@ -482,7 +491,7 @@ public:
inline bool hasBackground () { return backgroundColor != NULL; }
- bool equals (object::Object *other);
+ bool equals (lout::object::Object *other);
int hashValue ();
};
@@ -495,7 +504,7 @@ class Style: public StyleAttrs
private:
static int totalRef;
int refCount;
- static container::typed::HashTable <StyleAttrs, Style> *styleTable;
+ static lout::container::typed::HashTable <StyleAttrs, Style> *styleTable;
Style (StyleAttrs *attrs);
@@ -518,17 +527,17 @@ public:
}
inline void ref () { refCount++; }
- inline void unref () { if(--refCount == 0) delete this; }
+ inline void unref () { if (--refCount == 0) delete this; }
};
/**
* \sa dw::core::style
*/
-class TooltipAttrs: public object::String
+class TooltipAttrs: public lout::object::String
{
public:
- TooltipAttrs(const char *text): object::String(text) { }
+ TooltipAttrs(const char *text): lout::object::String(text) { }
};
/**
@@ -539,34 +548,34 @@ class Tooltip: public TooltipAttrs
private:
int refCount;
+protected:
Tooltip (const char *text): TooltipAttrs(text) { refCount = 0; }
public:
- inline Tooltip *create (Layout *layout, const char *text)
- { return new Tooltip (text); }
-
+ static Tooltip *create (dw::core::Layout *layout, const char *text);
inline void ref () { refCount++; }
inline void unref ()
- { if(--refCount == 0) delete this; }
+ { if (--refCount == 0) delete this; }
- inline void onEnter () { }
- inline void onLeave () { }
- inline void onMotion () { }
+ inline virtual void onEnter () { }
+ inline virtual void onLeave () { }
+ inline virtual void onMotion () { }
};
/**
* \sa dw::core::style
*/
-class FontAttrs: public object::Object
+class FontAttrs: public lout::object::Object
{
public:
const char *name;
int size;
int weight;
+ int letterSpacing;
FontStyle style;
- bool equals(object::Object *other);
+ bool equals(lout::object::Object *other);
int hashValue();
};
@@ -593,37 +602,30 @@ public:
int xHeight;
static Font *create (Layout *layout, FontAttrs *attrs);
- static Font *createFromList (Layout *layout, FontAttrs *attrs,
- char *defaultFamily);
+ static bool exists (Layout *layout, const char *name);
inline void ref () { refCount++; }
- inline void unref () { if(--refCount == 0) delete this; }
+ inline void unref () { if (--refCount == 0) delete this; }
};
/**
* \sa dw::core::style
*/
-class ColorAttrs: public object::Object
+class ColorAttrs: public lout::object::Object
{
-public:
- enum Type { TYPE_SIMPLE, TYPE_SHADED };
-
protected:
int color;
- Type type;
public:
- inline ColorAttrs(int color, Type type)
+ inline ColorAttrs(int color)
{
this->color = color;
- this->type = type;
}
inline int getColor () { return color; }
- inline Type getType () { return type; }
- bool equals(object::Object *other);
+ bool equals(lout::object::Object *other);
int hashValue();
};
@@ -636,12 +638,11 @@ class Color: public ColorAttrs
private:
int refCount;
- static Color *create (Layout *layout, int color, Type type);
void remove(dw::core::Layout *layout);
- int shadeColor (int color, int d);
+ int shadeColor (int color, int d);
protected:
- inline Color (int color, Type type): ColorAttrs (color, type) {
+ inline Color (int color): ColorAttrs (color) {
refCount = 0; }
virtual ~Color ();
@@ -653,19 +654,11 @@ protected:
int shadeColor (int color, Shading shading);
public:
- inline static Color *createSimple (Layout *layout, int color)
- {
- return create (layout, color, TYPE_SIMPLE);
- }
-
- inline static Color *createShaded (Layout *layout, int color)
- {
- return create (layout, color, TYPE_SHADED);
- }
+ static Color *create (Layout *layout, int color);
inline void ref () { refCount++; }
inline void unref ()
- { if(--refCount == 0) delete this; }
+ { if (--refCount == 0) delete this; }
};
void drawBorder (View *view, Rectangle *area,
diff --git a/dw/table.cc b/dw/table.cc
index 4135799b..51718587 100644
--- a/dw/table.cc
+++ b/dw/table.cc
@@ -14,17 +14,18 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//#define DBG
#include "table.hh"
+#include "../lout/msg.h"
#include "../lout/misc.hh"
#define MAX misc::max
+using namespace lout;
namespace dw {
@@ -34,6 +35,7 @@ Table::Table(bool limitTextWidth)
{
registerName ("dw::Table", &CLASS_ID);
setFlags (USES_HINTS);
+ setButtonSensitive(false);
this->limitTextWidth = limitTextWidth;
@@ -113,7 +115,7 @@ void Table::sizeRequestImpl (core::Requisition *requisition)
getStyle()->boxDiffHeight () + cumHeight->get (numRows)
+ getStyle()->vBorderSpacing;
requisition->descent = 0;
-
+
}
void Table::getExtremesImpl (core::Extremes *extremes)
@@ -141,10 +143,8 @@ void Table::getExtremesImpl (core::Extremes *extremes)
core::style::absLengthVal(getStyle()->width));
}
-#ifdef DBG
- printf(" Table::getExtremesImpl, {%d, %d} numCols=%d\n",
- extremes->minWidth, extremes->maxWidth, numCols);
-#endif
+ _MSG(" Table::getExtremesImpl, {%d, %d} numCols=%d\n",
+ extremes->minWidth, extremes->maxWidth, numCols);
}
void Table::sizeAllocateImpl (core::Allocation *allocation)
@@ -172,14 +172,14 @@ void Table::sizeAllocateImpl (core::Allocation *allocation)
core::Allocation childAllocation;
core::Requisition childRequisition;
-
+
children->get(n)->cell.widget->sizeRequest (&childRequisition);
childAllocation.x = x;
childAllocation.y = cumHeight->get (row) + offy;
childAllocation.width = width;
childAllocation.ascent = childRequisition.ascent;
- childAllocation.descent =
+ childAllocation.descent =
cumHeight->get (row + children->get(n)->cell.rowspan)
- cumHeight->get (row) - getStyle()->vBorderSpacing
- childRequisition.ascent;
@@ -188,7 +188,7 @@ void Table::sizeAllocateImpl (core::Allocation *allocation)
}
x += colWidths->get (col) + getStyle()->hBorderSpacing;
- }
+ }
}
void Table::resizeDrawImpl ()
@@ -200,12 +200,10 @@ void Table::resizeDrawImpl ()
}
void Table::setWidth (int width)
-{
+{
// If limitTextWidth is set, a queueResize may also be necessary.
if (availWidth != width || limitTextWidth) {
-#ifdef DBG
- printf(" Table::setWidth %d\n", width);
-#endif
+ _MSG(" Table::setWidth %d\n", width);
availWidth = width;
queueResize (0, false);
}
@@ -258,7 +256,7 @@ void Table::draw (core::View *view, core::Rectangle *area)
}
}
}
-
+
void Table::removeChild (Widget *child)
{
/** \bug Not implemented. */
@@ -277,22 +275,22 @@ void Table::addCell (Widget *widget, int colspan, int rowspan)
// We limit the values for colspan and rowspan to 50, to avoid
// attacks by malicious web pages.
if (colspan > 50 || colspan < 0) {
- fprintf (stderr, "WARNING: colspan = %d is set to 50.\n", colspan);
+ MSG_WARN("colspan = %d is set to 50.\n", colspan);
colspan = 50;
}
if (rowspan > 50 || rowspan <= 0) {
- fprintf (stderr, "WARNING: rowspan = %d is set to 50.\n", rowspan);
+ MSG_WARN("rowspan = %d is set to 50.\n", rowspan);
rowspan = 50;
}
if (numRows == 0) {
// to prevent a crash
- fprintf (stderr, "WARNING: Cell without row.\n");
+ MSG("addCell: cell without row.\n");
addRow (NULL);
}
if (rowClosed) {
- fprintf (stderr, "WARNING: Last cell had colspan=0.\n");
+ MSG_WARN("Last cell had colspan=0.\n");
addRow (NULL);
}
@@ -308,10 +306,9 @@ void Table::addCell (Widget *widget, int colspan, int rowspan)
child->type == Child::SPAN_SPACE)
curCol++;
-#ifdef DBG
- printf("Table::addCell numCols=%d,curCol=%d,colspan=%d,colspanEff=%d\n",
- numCols, curCol, colspan, colspanEff);
-#endif
+ _MSG("Table::addCell numCols=%d,curCol=%d,colspan=%d,colspanEff=%d\n",
+ numCols, curCol, colspan, colspanEff);
+
// Increase children array, when necessary.
if (curRow + rowspan > numRows)
reallocChildren (numCols, curRow + rowspan);
@@ -337,7 +334,7 @@ void Table::addCell (Widget *widget, int colspan, int rowspan)
child->cell.colspanEff = colspanEff;
child->cell.rowspan = rowspan;
children->set (curRow * numCols + curCol, child);
-
+
curCol += colspanEff;
widget->setParent (this);
@@ -351,18 +348,18 @@ void Table::addCell (Widget *widget, int colspan, int rowspan)
for (int col = 0; col < numCols; col++) {
int n = row * numCols + col;
if (!(child = children->get (n))) {
- printf("[null ] ");
+ MSG("[null ] ");
} else if (children->get(n)->type == Child::CELL) {
- printf("[CELL rs=%d] ", child->cell.rowspan);
+ MSG("[CELL rs=%d] ", child->cell.rowspan);
} else if (children->get(n)->type == Child::SPAN_SPACE) {
- printf("[SPAN rs=%d] ", child->cell.rowspan);
+ MSG("[SPAN rs=%d] ", child->cell.rowspan);
} else {
- printf("[Unk. ] ");
+ MSG("[Unk. ] ");
}
}
- printf("\n");
+ MSG("\n");
}
- printf("\n");
+ MSG("\n");
#endif
}
@@ -458,7 +455,7 @@ void Table::reallocChildren (int newNumCols, int newNumRows)
for (int row = numRows; row < newNumRows; row++)
for (int col = 0; col < newNumCols; col++)
children->set (row * newNumCols + col, NULL);
-
+
// Simple arrays.
rowStyle->setSize (newNumRows);
for (int row = numRows; row < newNumRows; row++)
@@ -485,7 +482,7 @@ void Table::forceCalcCellSizes ()
// Will also call calcColumnExtremes(), when needed.
getExtremes (&extremes);
-
+
if (core::style::isAbsLength (getStyle()->width)) {
totalWidth = core::style::absLengthVal (getStyle()->width);
} else if (core::style::isPerLength (getStyle()->width)) {
@@ -503,28 +500,28 @@ void Table::forceCalcCellSizes ()
totalWidth = availWidth;
forceTotalWidth = 0;
}
-#ifdef DBG
- printf(" availWidth = %d\n", availWidth);
- printf(" totalWidth1 = %d\n", totalWidth);
-#endif
+
+ _MSG(" availWidth = %d\n", availWidth);
+ _MSG(" totalWidth1 = %d\n", totalWidth);
+
if (totalWidth < extremes.minWidth)
totalWidth = extremes.minWidth;
totalWidth = totalWidth
- (numCols + 1) * getStyle()->hBorderSpacing
- getStyle()->boxDiffWidth ();
-#ifdef DBG
- printf(" totalWidth2 = %d curCol=%d\n", totalWidth,curCol);
-#endif
+
+ _MSG(" totalWidth2 = %d curCol=%d\n", totalWidth,curCol);
+
colWidths->setSize (numCols, 0);
cumHeight->setSize (numRows + 1, 0);
rowSpanCells->setSize (0);
baseline->setSize (numRows);
-#ifdef DBG
- printf(" extremes = %d,%d\n", extremes.minWidth, extremes.maxWidth);
- printf(" getStyle()->boxDiffWidth() = %d\n", getStyle()->boxDiffWidth());
- printf(" getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
-#endif
+
+ _MSG(" extremes = %d,%d\n", extremes.minWidth, extremes.maxWidth);
+ _MSG(" getStyle()->boxDiffWidth() = %d\n", getStyle()->boxDiffWidth());
+ _MSG(" getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
+
apportion_percentages2 (totalWidth, forceTotalWidth);
if (!hasColPercent)
@@ -583,10 +580,9 @@ void Table::apportionRowSpan ()
continue;
// Cell size is too small.
-#ifdef DBG
- printf("Short cell %d, sumRows=%d spanHeight=%d\n",
- n,sumRows,spanHeight);
-#endif
+ _MSG("Short cell %d, sumRows=%d spanHeight=%d\n",
+ n,sumRows,spanHeight);
+
// Fill height array
if (!rowHeight) {
rowHeight = new int[numRows];
@@ -594,10 +590,10 @@ void Table::apportionRowSpan ()
rowHeight[i] = cumHeight->get(i+1) - cumHeight->get(i);
}
#ifdef DBG
- printf (" rowHeight { ");
+ MSG(" rowHeight { ");
for (int i = 0; i < numRows; i++)
- printf ("%d ", rowHeight[i]);
- printf ("}\n");
+ MSG("%d ", rowHeight[i]);
+ MSG("}\n");
#endif
// Calc new row sizes for this span.
@@ -607,12 +603,12 @@ void Table::apportionRowSpan ()
sumRows == 0 ? (int)((float)(spanHeight-cumHnew_i)/(row+rs-i)) :
(sumRows-cumh_i) <= 0 ? 0 :
(int)((float)(spanHeight-cumHnew_i)*rowHeight[i]/(sumRows-cumh_i));
-#ifdef DBG
- printf (" i=%-3d h=%d hnew_i=%d =%d*%d/%d cumh_i=%d cumHnew_i=%d\n",
- i,rowHeight[i],hnew_i,
- spanHeight-cumHnew_i,rowHeight[i],sumRows-cumh_i,
- cumh_i, cumHnew_i);
-#endif
+
+ _MSG(" i=%-3d h=%d hnew_i=%d =%d*%d/%d cumh_i=%d cumHnew_i=%d\n",
+ i,rowHeight[i],hnew_i,
+ spanHeight-cumHnew_i,rowHeight[i],sumRows-cumh_i,
+ cumh_i, cumHnew_i);
+
cumHnew_i += hnew_i;
cumh_i += rowHeight[i];
rowHeight[i] = hnew_i;
@@ -642,9 +638,8 @@ void Table::calcColumnExtremes ()
*/
void Table::forceCalcColumnExtremes ()
{
-#ifdef DBG
- printf(" Table::forceCalcColumnExtremes numCols=%d\n", numCols);
-#endif
+ _MSG(" Table::forceCalcColumnExtremes numCols=%d\n", numCols);
+
if (numCols == 0)
return;
@@ -678,13 +673,13 @@ void Table::forceCalcColumnExtremes ()
cellMinW = cellExtremes.minWidth;
cellMaxW = cellExtremes.maxWidth;
}
-#ifdef DBG
- printf("FCCE, col%d colMin,colMax,cellMin,cellMax = %d,%d,%d,%d\n",
- col,
- colExtremes->getRef(col)->minWidth,
- colExtremes->getRef(col)->maxWidth,
- cellMinW, cellMaxW);
-#endif
+
+ _MSG("FCCE, col%d colMin,colMax,cellMin,cellMax = %d,%d,%d,%d\n",
+ col,
+ colExtremes->getRef(col)->minWidth,
+ colExtremes->getRef(col)->maxWidth,
+ cellMinW, cellMaxW);
+
colExtremes->getRef(col)->minWidth =
MAX (colExtremes->getRef(col)->minWidth, cellMinW);
colExtremes->getRef(col)->maxWidth =
@@ -737,10 +732,10 @@ void Table::forceCalcColumnExtremes ()
minSumCols += colExtremes->getRef(col+i)->minWidth;
maxSumCols += colExtremes->getRef(col+i)->maxWidth;
}
-#ifdef DBG
- printf("cs=%d spanWidth=%d,%d sumCols=%d,%d\n",
- cs,cellMinW,cellMaxW,minSumCols,maxSumCols);
-#endif
+
+ _MSG("cs=%d spanWidth=%d,%d sumCols=%d,%d\n",
+ cs,cellMinW,cellMaxW,minSumCols,maxSumCols);
+
if (minSumCols >= cellMinW && maxSumCols >= cellMaxW)
continue;
@@ -785,7 +780,7 @@ void Table::forceCalcColumnExtremes ()
int d_a = colExtremes->getRef(i)->maxWidth;
int d_w = curAppW > 0 ? (int)((float)curExtraW * d_a/curAppW) : 0;
if (d_a < 0||d_w < 0) {
- printf("d_a=%d d_w=%d\n",d_a,d_w);
+ MSG("d_a=%d d_w=%d\n",d_a,d_w);
exit(1);
}
wMin = colExtremes->getRef(i)->minWidth + d_w;
@@ -809,19 +804,19 @@ void Table::forceCalcColumnExtremes ()
cumMaxWnew += wMax;
cumMaxWold += colExtremes->getRef(i)->maxWidth;
colExtremes->getRef(i)->maxWidth = wMax;
-#ifdef DBG
- printf ("i=%d, wMin=%d wMax=%d cumMaxWold=%d\n",
- i,wMin,wMax,cumMaxWold);
-#endif
+
+ _MSG("i=%d, wMin=%d wMax=%d cumMaxWold=%d\n",
+ i,wMin,wMax,cumMaxWold);
+
}
#ifdef DBG
- printf ("col min,max: [");
+ MSG("col min,max: [");
for (int i = 0; i < numCols; i++)
- printf ("%d,%d ",
- colExtremes->getRef(i)->minWidth,
- colExtremes->getRef(i)->maxWidth);
- printf ("]\n");
- printf ("getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
+ MSG("%d,%d ",
+ colExtremes->getRef(i)->minWidth,
+ colExtremes->getRef(i)->maxWidth);
+ MSG("]\n");
+ MSG("getStyle()->hBorderSpacing = %d\n", getStyle()->hBorderSpacing);
#endif
}
}
@@ -835,13 +830,13 @@ void Table::apportion2 (int totalWidth, int forceTotalWidth)
if (colExtremes->size() == 0)
return;
#ifdef DBG
- printf("app2, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
- availWidth, totalWidth, forceTotalWidth);
- printf("app2, extremes: ( ");
+ MSG("app2, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
+ availWidth, totalWidth, forceTotalWidth);
+ MSG("app2, extremes: ( ");
for (int i = 0; i < colExtremes->size (); i++)
- printf("%d,%d ",
- colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
- printf(")\n");
+ MSG("%d,%d ",
+ colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
+ MSG(")\n");
#endif
int minAutoWidth = 0, maxAutoWidth = 0, availAutoWidth = totalWidth;
for (int col = 0; col < numCols; col++) {
@@ -871,10 +866,9 @@ void Table::apportion2 (int totalWidth, int forceTotalWidth)
int curMaxWidth = maxAutoWidth;
int curNewWidth = minAutoWidth;
for (int col = 0; col < numCols; col++) {
-#ifdef DBG
- printf("app2, col %d, minWidth=%d maxWidth=%d\n",
- col,extremes->get(col).minWidth, colExtremes->get(col).maxWidth);
-#endif
+ _MSG("app2, col %d, minWidth=%d maxWidth=%d\n",
+ col,extremes->get(col).minWidth, colExtremes->get(col).maxWidth);
+
if (colPercents->get(col) != LEN_AUTO)
continue;
@@ -882,19 +876,19 @@ void Table::apportion2 (int totalWidth, int forceTotalWidth)
int colMaxWidth = colExtremes->getRef(col)->maxWidth;
int w = (curMaxWidth <= 0) ? 0 :
(int)((float)curTargetWidth * colMaxWidth/curMaxWidth);
-#ifdef DBG
- printf("app2, curTargetWidth=%d colMaxWidth=%d curMaxWidth=%d "
- "curNewWidth=%d ",
- curTargetWidth, colMaxWidth,curMaxWidth,curNewWidth);
- printf("w = %d, ", w);
-#endif
+
+ _MSG("app2, curTargetWidth=%d colMaxWidth=%d curMaxWidth=%d "
+ "curNewWidth=%d ",
+ curTargetWidth, colMaxWidth,curMaxWidth,curNewWidth);
+ _MSG("w = %d, ", w);
+
if (w <= colMinWidth)
w = colMinWidth;
else if (curNewWidth - colMinWidth + w > curTargetWidth)
w = colMinWidth + curExtraWidth;
-#ifdef DBG
- printf("w = %d\n", w);
-#endif
+
+ _MSG("w = %d\n", w);
+
curNewWidth -= colMinWidth;
curMaxWidth -= colMaxWidth;
curExtraWidth -= (w - colMinWidth);
@@ -902,10 +896,10 @@ void Table::apportion2 (int totalWidth, int forceTotalWidth)
setColWidth (col, w);
}
#ifdef DBG
- printf("app2, result: ( ");
+ MSG("app2, result: ( ");
for (int i = 0; i < colWidths->size (); i++)
- printf("%d ", colWidths->get (i));
- printf(")\n");
+ MSG("%d ", colWidths->get (i));
+ MSG(")\n");
#endif
}
@@ -917,19 +911,17 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
return;
// If there's a table-wide percentage, totalWidth comes already scaled.
-#ifdef DBG
- printf("APP_P, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
- availWidth, totalWidth, forceTotalWidth);
-#endif
+ _MSG("APP_P, availWidth=%d, totalWidth=%d, forceTotalWidth=%d\n",
+ availWidth, totalWidth, forceTotalWidth);
if (!hasColPercent) {
#ifdef DBG
- printf("APP_P, only a table-wide percentage\n");
- printf("APP_P, extremes = { ");
+ MSG("APP_P, only a table-wide percentage\n");
+ MSG("APP_P, extremes = { ");
for (int col = 0; col < numCols; col++)
- printf("%d,%d ", colExtremes->getRef(col)->minWidth,
- colExtremes->getRef(col)->maxWidth);
- printf("}\n");
+ MSG("%d,%d ", colExtremes->getRef(col)->minWidth,
+ colExtremes->getRef(col)->maxWidth);
+ MSG("}\n");
#endif
// It has only a table-wide percentage. Apportion non-absolute widths.
int sumMaxWidth = 0, perAvailWidth = totalWidth;
@@ -939,10 +931,10 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
else
sumMaxWidth += colExtremes->getRef(col)->maxWidth;
}
-#ifdef DBG
- printf("APP_P, perAvailWidth=%d, sumMaxWidth=%d\n",
- perAvailWidth, sumMaxWidth);
-#endif
+
+ _MSG("APP_P, perAvailWidth=%d, sumMaxWidth=%d\n",
+ perAvailWidth, sumMaxWidth);
+
for (int col = 0; col < numCols; col++) {
int max_wi = colExtremes->getRef(col)->maxWidth, new_wi;
if (colPercents->get(col) != LEN_ABS) {
@@ -954,17 +946,16 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
}
}
#ifdef DBG
- printf("APP_P, result = { ");
+ MSG("APP_P, result = { ");
for (int col = 0; col < numCols; col++)
- printf("%d ", result->get(col));
- printf("}\n");
+ MSG("%d ", colWidths->get(col));
+ MSG("}\n");
#endif
} else {
// we'll have to apportion...
-#ifdef DBG
- printf("APP_P, we'll have to apportion...\n");
-#endif
+ _MSG("APP_P, we'll have to apportion...\n");
+
// Calculate cumPercent and available space
float cumPercent = 0.0f;
int hasAutoCol = 0;
@@ -979,11 +970,10 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
}
sumMinWidth += colExtremes->getRef(col)->minWidth;
sumMaxWidth += colExtremes->getRef(col)->maxWidth;
-#ifdef DBG
- printf("APP_P, col %d minWidth=%d maxWidth=%d\n", col,
- colExtremes->getRef(col)->minWidth,
- colExtremes->getRef(col)->maxWidth);
-#endif
+
+ _MSG("APP_P, col %d minWidth=%d maxWidth=%d\n", col,
+ colExtremes->getRef(col)->minWidth,
+ colExtremes->getRef(col)->maxWidth);
}
int oldTotalWidth = totalWidth;
if (!forceTotalWidth) {
@@ -1011,11 +1001,11 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
workingWidth = totalWidth;
curPerWidth = sumMinWidth;
}
-#ifdef DBG
- printf("APP_P, oldTotalWidth=%d totalWidth=%d"
- " workingWidth=%d extraWidth=%d sumMinNonPer=%d\n",
- oldTotalWidth,totalWidth,workingWidth,extraWidth,sumMinNonPer);
-#endif
+
+ _MSG("APP_P, oldTotalWidth=%d totalWidth=%d"
+ " workingWidth=%d extraWidth=%d sumMinNonPer=%d\n",
+ oldTotalWidth,totalWidth,workingWidth,extraWidth,sumMinNonPer);
+
for (int col = 0; col < numCols; col++) {
int colMinWidth = colExtremes->getRef(col)->minWidth;
if (colPercents->get(col) >= 0.0f) {
@@ -1035,20 +1025,20 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
if (cumPercent < 0.99f) {
// Will have to apportion the other columns
#ifdef DBG
- printf("APP_P, extremes: ( ");
+ MSG("APP_P, extremes: ( ");
for (int i = 0; i < colExtremes->size (); i++)
- printf("%d,%d ",
- colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
- printf(")\n");
+ MSG("%d,%d ",
+ colExtremes->get(i).minWidth, colExtremes->get(i).maxWidth);
+ MSG(")\n");
#endif
curPerWidth -= sumMinNonPer;
int perWidth = (int)(curPerWidth/cumPercent);
totalWidth = MAX (totalWidth, perWidth);
totalWidth = misc::min (totalWidth, oldTotalWidth);
-#ifdef DBG
- printf("APP_P, curPerWidth=%d perWidth=%d, totalWidth=%d\n",
- curPerWidth, perWidth, totalWidth);
-#endif
+
+ _MSG("APP_P, curPerWidth=%d perWidth=%d, totalWidth=%d\n",
+ curPerWidth, perWidth, totalWidth);
+
if (hasAutoCol == 0) {
// Special case, cumPercent < 100% and no other columns to expand.
// We'll honor totalWidth by expanding the percentage cols.
@@ -1062,22 +1052,22 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
}
}
#ifdef DBG
- printf("APP_P, result ={ ");
+ MSG("APP_P, result ={ ");
for (int col = 0; col < numCols; col++)
- printf("%d ", colWidths->get(col));
- printf("}\n");
+ MSG("%d ", colWidths->get(col));
+ MSG("}\n");
#endif
apportion2 (totalWidth, 2);
#ifdef DBG
- printf("APP_P, percent={");
+ MSG("APP_P, percent={");
for (int col = 0; col < numCols; col++)
- printf("%f ", colPercents->get(col));
- printf("}\n");
- printf("APP_P, result ={ ");
+ MSG("%f ", colPercents->get(col));
+ MSG("}\n");
+ MSG("APP_P, result ={ ");
for (int col = 0; col < numCols; col++)
- printf("%d ", colWidths->get(col));
- printf("}\n");
+ MSG("%d ", colWidths->get(col));
+ MSG("}\n");
#endif
}
}
@@ -1117,7 +1107,7 @@ int Table::TableIterator::compareTo(misc::Comparable *other)
{
return index - ((TableIterator*)other)->index;
}
-
+
bool Table::TableIterator::next ()
{
Table *table = (Table*)getWidget();
@@ -1130,7 +1120,7 @@ bool Table::TableIterator::next ()
content.type = core::Content::END;
return false;
}
-
+
do {
index++;
if (index >= table->children->size ()) {
@@ -1157,7 +1147,7 @@ bool Table::TableIterator::prev ()
content.type = core::Content::START;
return false;
}
-
+
do {
index--;
if (index < 0) {
diff --git a/dw/table.hh b/dw/table.hh
index ec2bacc8..87bbaa76 100644
--- a/dw/table.hh
+++ b/dw/table.hh
@@ -11,22 +11,22 @@ namespace dw {
* \brief A Widget for rendering tables.
*
* <h3>Introduction</h3>
- *
+ *
* The dw::Table widget is used to render HTML tables.
- *
- * Each cell is itself an own widget. Any widget may be used, however, in
+ *
+ * Each cell is itself a separate widget. Any widget may be used, however, in
* dillo, only instances of dw::Textblock and dw::TableCell are used as
* children of dw::Table.
- *
- *
+ *
+ *
* <h3>Sizes</h3>
- *
+ *
* <h4>General</h4>
- *
+ *
* The following diagram shows the dependencies between the different
* functions, which are related to size calculation. Click on the boxes
- * for more informations.
- *
+ * for more information.
+ *
* \dot
* digraph G {
* node [shape=record, fontname=Helvetica, fontsize=10, color="#c0c0c0"];
@@ -34,125 +34,125 @@ namespace dw {
* labelfontsize=10, color="#404040", labelfontcolor="#000080",
* fontname=Helvetica, fontsize=10];
* fontname=Helvetica; fontsize=10;
- *
+ *
* sizeRequestImpl [color="#0000ff", URL="\ref dw::Table::sizeRequestImpl"];
* sizeAllocateImpl [color="#0000ff",
* URL="\ref dw::Table::sizeAllocateImpl"];
* getExtremesImpl [color="#0000ff", URL="\ref dw::Table::getExtremesImpl"];
- *
+ *
* subgraph cluster_sizes {
* style="dashed"; color="#8080c0";
* calcCellSizes [URL="\ref dw::Table::calcCellSizes"];
* forceCalcCellSizes [URL="\ref dw::Table::forceCalcCellSizes"];
* }
- *
+ *
* subgraph cluster_extremes {
* style="dashed"; color="#8080c0";
* calcColumnExtremes [URL="\ref dw::Table::calcColumnExtremes"];
* forceCalcColumnExtremes[URL="\ref dw::Table::forceCalcColumnExtremes"];
* }
- *
+ *
* sizeRequestImpl -> forceCalcCellSizes [label="[B]"];
* sizeAllocateImpl -> calcCellSizes [label="[A]"];
* getExtremesImpl -> forceCalcColumnExtremes [label="[B]"];
- *
+ *
* forceCalcCellSizes -> calcColumnExtremes;
- *
+ *
* calcCellSizes -> forceCalcCellSizes [style="dashed", label="[C]"];
* calcColumnExtremes -> forceCalcColumnExtremes [style="dashed",
* label="[C]"];
* }
* \enddot
- *
+ *
* [A] In this case, the new calculation is \em not forced, but only
* done, when necessary.
- *
+ *
* [B] In this case, the new calculation is allways necessary, since [C]
* is the case.
- *
+ *
* [C] Whether this function is called, depends on NEEDS_RESIZE /
* EXTREMES_CHANGED.
- *
- *
+ *
+ *
* <h4>Apportionment</h4>
- *
+ *
* \sa\ref rounding-errors
- *
+ *
* Given two array \f$e_{i,\min}\f$ and \f$e_{i,\max}\f$, which
* represent the column minima and maxima, and a total width \f$W\f$, \em
* apportionment means to calculate column widths \f$w_{i}\f$, with
- *
+ *
* \f[e_{i,\min} \le w_{i} \le e_{i,\max}\f]
- *
+ *
* and
- *
+ *
* \f[\sum w_{i} = W\f]
- *
+ *
* There are different algorithms for apportionment, a simple one is
* recommended in the HTML 4.0.1 specification
* (http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.5.2.2):
- *
+ *
* \f[w_{i} = e_{i,\min} +
* {e_{i,\max} - e_{i,\min}\over\sum e_{i,\max} - \sum e_{i,\min}}
* (W - \sum e_{i,\min})\f]
- *
+ *
* This one is used currently, but another one will be used soon, which is
- * described below. The rest of this chapter is independant of the exact
+ * described below. The rest of this chapter is independent of the exact
* apportionment algorithm.
- *
+ *
* When referring to the apportionment function, we will call it
* \f$a_i (W, (e_{i,\min}), (e_{i,\min}))\f$ and write
* something like this:
- *
+ *
* \f[w_{i} = a_i (W, (e_{i,\min}), (e_{i,\max})) \f]
- *
+ *
* It is implemented by dw::Table::apportion.
- *
+ *
* <h4>Column Extremes</h4>
- *
+ *
* \sa\ref rounding-errors
- *
+ *
* The sizes, which all other sizes depend on, are column extremes, which
* define, how wide a column may be at min and at max. They are
* calculated in the following way:
- *
+ *
* <ol>
* <li> First, only cells with colspan = 1 are regarded:
- *
+ *
* \f[ e_{\hbox{base},i,\min} = \max \{ e_{\hbox{cell},i,j,\min} \} \f]
* \f[ e_{\hbox{base},i,\max} = \max \{ e_{\hbox{cell},i,j,\max} \} \f]
- *
+ *
* only for cells \f$(i, j)\f$ with colspan = 1.
- *
+ *
* <li> Then,
* \f$e_{\hbox{span},i,\min}\f$ (but not \f$e_{\hbox{span},i,\max}\f$)
* are calculated from cells with colspan > 1. (In the following formulas,
* the cell at \f$(i_1, j)\f$ always span from \f$i_1\f$ to \f$i_2\f$.)
- * If the minimal width of the column exeeds the sum of the column minima
+ * If the minimal width of the column exceeds the sum of the column minima
* calculated in the last step:
- *
+ *
* \f[e_{\hbox{cell},i_1,j,\min} >
* \sum_{i=i_1}^{i=i_2} e_{\hbox{base},i,\min}\f]
- *
+ *
* then the minimal width of this cell is apportioned to the columns:
- *
+ *
* <ul>
- * <li> If the minimal width of this cell also exeeds the sum of the
+ * <li> If the minimal width of this cell also exceeds the sum of the
* column maxima:
- *
+ *
* \f[e_{\hbox{cell},i_1,j,\min} >
* \sum_{i=i_1}^{i=i_2} e_{\hbox{base},i,\max}\f]
- *
+ *
* then \f$e_{\hbox{cell},i_1,j,\min}\f$ is apportioned in a simple
* way:
- *
+ *
* \f[e_{\hbox{span},i,j,\min} =
* e_{\hbox{base},i,\max}
* {e_{\hbox{span},i,j,\min} \over
* \sum_{i=i_1}^{i=i_2} e_{\hbox{base},i,\max}}\f]
- *
+ *
* <li> Otherwise, the apportionment function is used:
- *
+ *
* \f[e_{\hbox{span},i,j,\min} =
* a_i (e_{\hbox{cell},i_1,j,\min},
* (e_{\hbox{cell},i_1,j,\min} \ldots
@@ -160,133 +160,133 @@ namespace dw {
* (e_{\hbox{cell},i_1,j,\max} \ldots
* e_{\hbox{cell},i_2,j,\max}))\f]
* </ul>
- *
+ *
* After this, \f$e_{\hbox{span},i,\min}\f$ is then the maximum of all
* \f$e_{\hbox{span},i,j,\min}\f$.
- *
+ *
* <li> Finally, the maximum of both is used.
* \f[ e_{i,\min} =
* \max \{ e_{\hbox{base},i,\min}, e_{\hbox{span},i,\min} \} \f]
* \f[ e_{i,\max} =
* \max \{ e_{\hbox{base},i,\max}, e_{i,\min} \} \f]
* For the maxima, there is no \f$e_{\hbox{span},i,\max}\f$, but it has to
- * be assured, that the maximum is always greater or equal than/to the
+ * be assured, that the maximum is always greater than or equal to the
* minimum.
* </ol>
- *
- * Generally, if absolute widths are speficied, they are, instead of the
+ *
+ * Generally, if absolute widths are specified, they are, instead of the
* results of dw::core::Widget::getExtremes, taken for the minimal and
* maximal width of a cell (minus the box difference, i.e. the difference
* between content size and widget size). If the content width
* specification is smaller than the minimal content width of the widget
* (determined by dw::core::Widget::getExtremes), the latter is used
* instead.
- *
+ *
* If percentage widths are specified, they are also collected, as column
* maxima. A similar method as for the extremes is used, for cells with
* colspan > 1:
- *
+ *
* \f[w_{\hbox{span},i,j,\%} =
* a_i (w_{\hbox{cell},i_1,j,\%},
* (e_{\hbox{cell},i_1,j,\min} \ldots e_{\hbox{cell},i_2,j,\min}),
* (e_{\hbox{cell},i_1,j,\max} \ldots e_{\hbox{cell},i_2,j,\max}))\f]
- *
+ *
* <h4>Cell Sizes</h4>
- *
+ *
* <h5>Determining the Width of the Table</h5>
- *
+ *
* The total width is
- *
+ *
* <ul>
* <li> the specified absolute width of the table, when given, or
- * <li> the available width (set by dw::Table::setWidth) times the specifies
- * percentage width pf t(at max 100%), if the latter is given, or
+ * <li> the available width (set by dw::Table::setWidth) times the specified
+ * percentage width of t(at max 100%), if the latter is given, or
* <li> otherwise the available width.
* </ul>
- *
+ *
* In any case, it is corrected, if it is less than the minimal width
* (but not if it is greater than the maximal width).
- *
- * \bug The parantheses is not fully clear, look at the old code.
- *
+ *
+ * \bug The parentheses is not fully clear, look at the old code.
+ *
* Details on differences because of styles are omitted. Below, this
* total width is called \f$W\f$.
- *
+ *
* <h5>Evaluating percentages</h5>
- *
+ *
* The following algorithms are used to solve collisions between
* different size specifications (absolute and percentage). Generally,
* inherent sizes and specified absolute sizes are preferred.
- *
+ *
* <ol>
* <li> First, calculate the sum of the minimal widths, for columns, where
* no percentage width has been specified. The difference to the total
* width is at max available to the columns with percentage width
* specifications:
- *
+ *
* \f[W_{\hbox{columns}_\%,\hbox{available}} = W - \sum e_{i,\min}\f]
- *
+ *
* with only those columns \f$i\f$ with no percentage width specification.
- *
+ *
* <li> Then, calculate the sum of the widths, which the columns with
* percentage width specification would allocate, when fully adhering to
- * then:
- *
+ * them:
+ *
* \f[W_{\hbox{columns}_\%,\hbox{best}} = W \sum w_{i,\%}\f]
- *
+ *
* with only those columns \f$i\f$ with a percentage width specification.
- *
+ *
* <li> Two cases are distinguished:
- *
+ *
* <ul>
* <li> \f$W_{\hbox{columns}_\%,\hbox{available}} \ge
* W_{\hbox{columns}_\%,\hbox{best}}\f$: In this case, the
* percentage widths can be used without any modification, by
* setting the extremes:
- *
+ *
* \f[e_{i,\min} = e_{i,\max} = W w_{i,\%}\f]
- *
+ *
* for only those columns \f$i\f$ with a percentage width
* specification.
- *
+ *
* <li> \f$W_{\hbox{columns}_\%,\hbox{available}} <
* W_{\hbox{columns}_\%,\hbox{best}}\f$: In this case, the widths
* for these columns must be cut down:
- *
+ *
* \f[e_{i,\min} = e_{i,\max} =
* w_{i,\%}
* {W_{\hbox{columns}_\%,\hbox{available}} \over
* w_{\hbox{total},\%}}\f]
- *
+ *
* with
- *
+ *
* \f[w_{\hbox{total},\%} = \sum w_{i,\%}\f]
- *
+ *
* in both cases for only those columns \f$i\f$ with a percentage
- * width specification.
+ * width specification.
* </ul>
* </ol>
- *
+ *
* (\f$e_{i,\min}\f$ and \f$e_{i,\max}\f$ are set \em temporarily here,
* the notation should be a bit clearer.)
- *
- *
+ *
+ *
* <h5>Column Widths</h5>
- *
+ *
* The column widths are now simply calculated by applying the
- * apportenment function.
- *
- *
+ * apportionment function.
+ *
+ *
* <h5>Row Heights</h5>
- *
+ *
* ...
- *
+ *
* <h3>Alternative Apportionment Algorithm</h3>
*
* The algorithm described here tends to result in more homogeneous column
* widths.
*
- * The following rule lead to well-defined \f$w_{i}\f$: All columns
+ * The following rule leads to well-defined \f$w_{i}\f$: All columns
* \f$i\f$ have have the same width \f$w\f$, except:
* <ul>
* <li> \f$w < e_{i,\min}\f$, or
@@ -306,13 +306,13 @@ namespace dw {
* Based on an initial value \f$w = {W\over n}\f$, \f$w\f$ can iteratively
* adjusted, based on these rules.
*
- *
+ *
* <h3>Borders, Paddings, Spacing</h3>
- *
+ *
* Currently, DwTable supports only the separated borders model (see CSS
* specification). Borders, paddings, spacing is done by creating
* dw::core::style::Style structures with values equivalent to following CSS:
- *
+ *
* <pre>
* TABLE {
* border: outset \em table-border;
@@ -320,14 +320,14 @@ namespace dw {
* border-spacing: \em table-cellspacing;
* background-color: \em table-bgcolor;
* }
- *
+ *
* TD TH {
* border: inset \em table-border;
* padding: \em table-cellspacing;
* background-color: \em td/th-bgcolor;
* }
* </pre>
- *
+ *
* Here, \em foo-bar refers to the attribute \em bar of the tag \em foo foo.
* Look at the HTML parser for more details.
*/
@@ -361,8 +361,8 @@ private:
TableIterator (Table *table, core::Content::Type mask, bool atEnd);
TableIterator (Table *table, core::Content::Type mask, int index);
- object::Object *clone();
- int compareTo(misc::Comparable *other);
+ lout::object::Object *clone();
+ int compareTo(lout::misc::Comparable *other);
bool next ();
bool prev ();
@@ -377,37 +377,37 @@ private:
int availWidth, availAscent, availDescent; // set by set...
int numRows, numCols, curRow, curCol;
- misc::SimpleVector<Child*> *children;
+ lout::misc::SimpleVector<Child*> *children;
int redrawX, redrawY;
-
+
/**
* \brief The extremes of all columns.
*/
- misc::SimpleVector<core::Extremes> *colExtremes;
+ lout::misc::SimpleVector<core::Extremes> *colExtremes;
/**
* \brief The widths of all columns.
*/
- misc::SimpleVector<int> *colWidths;
+ lout::misc::SimpleVector<int> *colWidths;
/**
* Row cumulative height array: cumHeight->size() is numRows + 1,
* cumHeight->get(0) is 0, cumHeight->get(numRows) is the total table
* height.
*/
- misc::SimpleVector<int> *cumHeight;
+ lout::misc::SimpleVector<int> *cumHeight;
/**
* If a Cell has rowspan > 1, it goes into this array
*/
- misc::SimpleVector<int> *rowSpanCells;
+ lout::misc::SimpleVector<int> *rowSpanCells;
/**
* If a Cell has colspan > 1, it goes into this array
*/
- misc::SimpleVector<int> *colSpanCells;
- misc::SimpleVector<int> *baseline;
+ lout::misc::SimpleVector<int> *colSpanCells;
+ lout::misc::SimpleVector<int> *baseline;
- misc::SimpleVector<core::style::Style*> *rowStyle;
+ lout::misc::SimpleVector<core::style::Style*> *rowStyle;
/**
* hasColPercent becomes true when any cell specifies a percentage width.
@@ -415,7 +415,7 @@ private:
*/
enum { LEN_AUTO = -1, LEN_ABS = -2};
int hasColPercent;
- misc::SimpleVector<float> *colPercents;
+ lout::misc::SimpleVector<float> *colPercents;
inline bool childDefined(int n)
{
@@ -438,7 +438,7 @@ private:
void setCumHeight (int row, int value)
{
if (value != cumHeight->get (row)) {
- redrawY = misc::min ( redrawY, value );
+ redrawY = lout::misc::min ( redrawY, value );
cumHeight->set (row, value);
}
}
@@ -446,7 +446,7 @@ private:
inline void setColWidth (int col, int value)
{
if (value != colWidths->get (col)) {
- redrawX = misc::min (redrawX, value);
+ redrawX = lout::misc::min (redrawX, value);
colWidths->set (col, value);
}
}
@@ -460,7 +460,7 @@ protected:
void setWidth (int width);
void setAscent (int ascent);
void setDescent (int descent);
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area);
//bool buttonPressImpl (core::EventButton *event);
//bool buttonReleaseImpl (core::EventButton *event);
@@ -474,7 +474,7 @@ public:
Table(bool limitTextWidth);
~Table();
- core::Iterator *iterator (core::Content::Type mask, bool atEnd);
+ core::Iterator *iterator (core::Content::Type mask, bool atEnd);
void addCell (Widget *widget, int colspan, int rowspan);
void addRow (core::style::Style *style);
diff --git a/dw/tablecell.cc b/dw/tablecell.cc
index b4d404f7..5b93fe86 100644
--- a/dw/tablecell.cc
+++ b/dw/tablecell.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -29,13 +28,14 @@ int TableCell::CLASS_ID = -1;
TableCell::TableCell (TableCell *ref, bool limitTextWidth):
AlignedTextblock (limitTextWidth)
-{
+{
registerName ("dw::TableCell", &CLASS_ID);
/** \bug ignoreLine1OffsetSometimes does not work? */
//ignoreLine1OffsetSometimes = true;
charWordIndex = -1;
setRefTextblock (ref);
+ setButtonSensitive(true);
}
TableCell::~TableCell()
@@ -45,7 +45,7 @@ TableCell::~TableCell()
void TableCell::wordWrap(int wordIndex)
{
Textblock::Word *word;
- char *p;
+ const char *p;
Textblock::wordWrap (wordIndex);
diff --git a/dw/textblock.cc b/dw/textblock.cc
index 6bfd4d90..33d3a1b0 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -14,18 +14,20 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "textblock.hh"
#include "table.hh" // Yes, this is ugly. -- SG
+#include "../lout/msg.h"
#include "../lout/misc.hh"
#include <stdio.h>
#include <math.h> // remove again
#include <limits.h>
+using namespace lout;
+
namespace dw {
int Textblock::CLASS_ID = -1;
@@ -34,15 +36,16 @@ Textblock::Textblock (bool limitTextWidth)
{
registerName ("dw::Textblock", &CLASS_ID);
setFlags (USES_HINTS);
+ setButtonSensitive(true);
- listItem = false;
+ hasListitemValue = false;
innerPadding = 0;
line1Offset = 0;
line1OffsetEff = 0;
ignoreLine1OffsetSometimes = false;
mustQueueResize = false;
redrawY = 0;
- lastWordDrawn = 0;
+ lastWordDrawn = -1;
/*
* The initial sizes of lines and words should not be
@@ -56,6 +59,7 @@ Textblock::Textblock (bool limitTextWidth)
lines = new misc::SimpleVector <Line> (1);
words = new misc::SimpleVector <Word> (1);
leftFloatSide = rightFloatSide = NULL;
+ anchors = new misc::SimpleVector <Anchor> (1);
//DBG_OBJ_SET_NUM(page, "num_lines", num_lines);
@@ -97,17 +101,20 @@ Textblock::~Textblock ()
Word *word = words->getRef (i);
if (word->content.type == core::Content::WIDGET)
delete word->content.widget;
- else if (word->content.type == core::Content::ANCHOR)
- /* This also frees the names (see removeAnchor() and related). */
- removeAnchor(word->content.anchor);
-
word->style->unref ();
word->spaceStyle->unref ();
}
+ for (int i = 0; i < anchors->size(); i++) {
+ Anchor *anchor = anchors->getRef (i);
+ /* This also frees the names (see removeAnchor() and related). */
+ removeAnchor(anchor->name);
+ }
+
delete lines;
delete words;
-
+ delete anchors;
+
if(leftFloatSide)
delete leftFloatSide;
if(rightFloatSide)
@@ -133,11 +140,12 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
Line *lastLine = lines->getRef (lines->size () - 1);
requisition->width =
misc::max (lastLine->maxLineWidth, lastLineWidth);
- /* Note: the break_space of the last line is ignored, so breaks
+ /* Note: the breakSpace of the last line is ignored, so breaks
at the end of a textblock are not visible. */
- requisition->ascent = lines->getRef(0)->ascent;
+ requisition->ascent = lines->getRef(0)->boxAscent;
requisition->descent = lastLine->top
- + lastLine->ascent + lastLine->descent - lines->getRef(0)->ascent;
+ + lastLine->boxAscent + lastLine->boxDescent -
+ lines->getRef(0)->boxAscent;
} else {
requisition->width = lastLineWidth;
requisition->ascent = 0;
@@ -237,21 +245,23 @@ void Textblock::getExtremesImpl (core::Extremes *extremes)
for (lineIndex = wrapRef; lineIndex < lines->size (); lineIndex++) {
//DBG_MSGF (widget, "extremes", 0, "line %d", lineIndex);
//DBG_MSG_START (widget);
+ core::style::WhiteSpace ws;
line = lines->getRef (lineIndex);
- nowrap =
- words->getRef(line->firstWord)->style->whiteSpace
- != core::style::WHITE_SPACE_NORMAL;
+ ws = words->getRef(line->firstWord)->style->whiteSpace;
+ nowrap = ws == core::style::WHITE_SPACE_PRE ||
+ ws == core::style::WHITE_SPACE_NOWRAP;
//DEBUG_MSG (DEBUG_SIZE_LEVEL, " line %d (of %d), nowrap = %d\n",
// lineIndex, page->num_lines, nowrap);
- for (wordIndex = line->firstWord; wordIndex < line->lastWord;
+ for (wordIndex = line->firstWord; wordIndex <= line->lastWord;
wordIndex++) {
word = words->getRef (wordIndex);
getWordExtremes (word, &wordExtremes);
/* For the first word, we simply add the line1_offset. */
+ /* This test looks questionable */
if (ignoreLine1OffsetSometimes && wordIndex == 0) {
wordExtremes.minWidth += line1Offset;
//DEBUG_MSG (DEBUG_SIZE_LEVEL + 1,
@@ -266,8 +276,8 @@ void Textblock::getExtremesImpl (core::Extremes *extremes)
extremes->minWidth = wordExtremes.minWidth;
}
- //printf("parMax = %d, wordMaxWidth=%d, prevWordSpace=%d\n",
- // parMax, wordExtremes.maxWidth, prevWordSpace);
+ _MSG("parMax = %d, wordMaxWidth=%d, prevWordSpace=%d\n",
+ parMax, wordExtremes.maxWidth, prevWordSpace);
if (word->content.type != core::Content::BREAK)
parMax += prevWordSpace;
parMax += wordExtremes.maxWidth;
@@ -279,11 +289,9 @@ void Textblock::getExtremesImpl (core::Extremes *extremes)
// word_extremes.maxWidth);
}
- if ((line->lastWord > line->firstWord &&
- words->getRef(line->lastWord - 1)->content.type
+ if ((words->getRef(line->lastWord)->content.type
== core::Content::BREAK ) ||
lineIndex == lines->size () - 1 ) {
- word = words->getRef (line->lastWord - 1);
//DEBUG_MSG (DEBUG_SIZE_LEVEL + 2,
// " parMax = %d, after word %d (%s)\n",
@@ -335,7 +343,6 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
int xCursor;
core::Allocation childAllocation;
core::Allocation *oldChildAllocation;
- int wordInLine;
if (allocation->width != this->allocation.width) {
redrawY = 0;
@@ -345,17 +352,15 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
line = lines->getRef (lineIndex);
xCursor = lineXOffsetWidget (line);
- wordInLine = 0;
- for (wordIndex = line->firstWord; wordIndex < line->lastWord;
+ for (wordIndex = line->firstWord; wordIndex <= line->lastWord;
wordIndex++) {
word = words->getRef (wordIndex);
- if (wordIndex == lastWordDrawn) {
+ if (wordIndex == lastWordDrawn + 1) {
redrawY = misc::min (redrawY, lineYOffsetWidget (line));
}
- switch (word->content.type) {
- case core::Content::WIDGET:
+ if (word->content.type == core::Content::WIDGET) {
/** \todo Justification within the line is done here. */
childAllocation.x = xCursor + allocation->x;
/* align=top:
@@ -367,7 +372,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
* http://www.dillo.org/test/img/ */
childAllocation.y =
lineYOffsetCanvasAllocation (line, allocation)
- + (line->ascent - word->size.ascent);
+ + (line->boxAscent - word->size.ascent);
// - word->content.widget->getStyle()->margin.top;
childAllocation.width = word->size.width;
childAllocation.ascent = word->size.ascent;
@@ -376,9 +381,9 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
// + word->content.widget->getStyle()->margin.bottom;
oldChildAllocation = word->content.widget->getAllocation();
-
- if (childAllocation.x != oldChildAllocation->x ||
- childAllocation.y != oldChildAllocation->y ||
+
+ if (childAllocation.x != oldChildAllocation->x ||
+ childAllocation.y != oldChildAllocation->y ||
childAllocation.width != oldChildAllocation->width) {
/* The child widget has changed its position or its width
* so we need to redraw from this line onwards.
@@ -397,38 +402,53 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
* child might be a table covering the whole page so we would
* end up redrawing the whole screen over and over.
* The drawing of the child content is left to the child itself.
+ * However this optimization is only possible if the widget is
+ * the only word in the line apart from an optional BREAK.
+ * Otherwise the height change of the widget could change the
+ * position of other words in the line, requiring a
+ * redraw of the complete line.
*/
- int childChangedY =
- misc::min(childAllocation.y - allocation->y +
- childAllocation.ascent + childAllocation.descent,
- oldChildAllocation->y - this->allocation.y +
- oldChildAllocation->ascent + oldChildAllocation->descent);
-
- redrawY = misc::min (redrawY, childChangedY);
+ if (line->lastWord == line->firstWord ||
+ (line->lastWord == line->firstWord + 1 &&
+ words->getRef (line->lastWord)->content.type ==
+ core::Content::BREAK)) {
+
+ int childChangedY =
+ misc::min(childAllocation.y - allocation->y +
+ childAllocation.ascent + childAllocation.descent,
+ oldChildAllocation->y - this->allocation.y +
+ oldChildAllocation->ascent +
+ oldChildAllocation->descent);
+
+ redrawY = misc::min (redrawY, childChangedY);
+ } else {
+ redrawY = misc::min (redrawY, lineYOffsetWidget (line));
+ }
}
-
word->content.widget->sizeAllocate (&childAllocation);
- break;
-
- case core::Content::ANCHOR:
- changeAnchor (word->content.anchor,
- lineYOffsetCanvasAllocation (line, allocation));
- break;
-
- default:
- wordInLine++;
- // make compiler happy
- break;
}
xCursor += (word->size.width + word->effSpace);
}
}
-
+
if(leftFloatSide)
leftFloatSide->sizeAllocate(allocation);
if(rightFloatSide)
rightFloatSide->sizeAllocate(allocation);
+
+ for (int i = 0; i < anchors->size(); i++) {
+ Anchor *anchor = anchors->getRef(i);
+ int y;
+
+ if (anchor->wordIndex >= words->size()) {
+ y = allocation->y + allocation->ascent + allocation->descent;
+ } else {
+ Line *line = lines->getRef(findLineOfWord (anchor->wordIndex));
+ y = lineYOffsetCanvasAllocation (line, allocation);
+ }
+ changeAnchor (anchor->name, y);
+ }
}
void Textblock::resizeDrawImpl ()
@@ -594,28 +614,22 @@ bool Textblock::motionNotifyImpl (core::EventMotion *event)
if (event->state & core::BUTTON1_MASK)
return sendSelectionEvent (core::SelectionState::BUTTON_MOTION, event);
else {
- int linkOld, wordIndex;
- core::style::Tooltip *tooltipOld;
-
- wordIndex = findWord (event->xWidget, event->yWidget);
+ bool inSpace;
+ int linkOld = hoverLink;
+ core::style::Tooltip *tooltipOld = hoverTooltip;
+ const Word *word = findWord (event->xWidget, event->yWidget, &inSpace);
// cursor from word or widget style
- if (wordIndex == -1)
+ if (word == NULL) {
setCursor (getStyle()->cursor);
- else
- setCursor (words->getRef(wordIndex)->style->cursor);
-
- linkOld = hoverLink;
- tooltipOld = hoverTooltip;
-
- if (wordIndex == -1) {
hoverLink = -1;
hoverTooltip = NULL;
} else {
- hoverLink = words->getRef(wordIndex)->style->x_link;
- hoverTooltip = words->getRef(wordIndex)->style->x_tooltip;
+ core::style::Style *style = inSpace ? word->spaceStyle : word->style;
+ setCursor (style->cursor);
+ hoverLink = style->x_link;
+ hoverTooltip = style->x_tooltip;
}
-
// Show/hide tooltip
if (tooltipOld != hoverTooltip) {
if (tooltipOld)
@@ -626,7 +640,7 @@ bool Textblock::motionNotifyImpl (core::EventMotion *event)
hoverTooltip->onMotion ();
if (hoverLink != linkOld)
- return emitLinkEnter (hoverLink, -1, -1, -1);
+ return layout->emitLinkEnter (this, hoverLink, -1, -1, -1);
else
return hoverLink != -1;
}
@@ -639,7 +653,11 @@ void Textblock::enterNotifyImpl (core::EventCrossing *event)
void Textblock::leaveNotifyImpl (core::EventCrossing *event)
{
hoverLink = -1;
- (void) emitLinkEnter (hoverLink, -1, -1, -1);
+ (void) layout->emitLinkEnter (this, hoverLink, -1, -1, -1);
+ if (hoverTooltip) {
+ hoverTooltip->onLeave();
+ hoverTooltip = NULL;
+ }
}
/**
@@ -651,114 +669,110 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType,
core::Iterator *it;
Line *line, *lastLine;
int nextWordStartX, wordStartX, wordX, nextWordX, yFirst, yLast;
- int charPos = 0, prevPos, wordIndex, lineIndex, link;
+ int charPos = 0, link = -1, prevPos, wordIndex, lineIndex;
Word *word;
- bool found, withinContent, r;
-
- if (words->size () == 0)
- // no contens at all
- return false;
+ bool found, r, withinContent = true;
- // In most cases true, so set here:
- link = -1;
- withinContent = true;
-
- lastLine = lines->getRef (lines->size () - 1);
- yFirst = lineYOffsetCanvasI (0);
- yLast =
- lineYOffsetCanvas (lastLine) + lastLine->ascent + lastLine->descent;
- if (event->yCanvas < yFirst) {
- // Above the first line: take the first word.
- withinContent = false;
- wordIndex = 0;
- charPos = 0;
- } else if (event->yCanvas >= yLast) {
- // Below the last line: take the last word.
+ if (words->size () == 0) {
withinContent = false;
- wordIndex = words->size () - 1;
- word = words->getRef (wordIndex);
- charPos = word->content.type == core::Content::TEXT ?
- strlen (word->content.text) : 0;
+ wordIndex = -1;
} else {
- lineIndex = findLineIndex (event->yWidget);
- line = lines->getRef (lineIndex);
-
- // Pointer within the break space?
- if (event->yWidget >
- (lineYOffsetWidget (line) + line->ascent + line->descent)) {
- // Choose this break.
+ lastLine = lines->getRef (lines->size () - 1);
+ yFirst = lineYOffsetCanvasI (0);
+ yLast = lineYOffsetCanvas (lastLine) + lastLine->boxAscent +
+ lastLine->boxDescent;
+ if (event->yCanvas < yFirst) {
+ // Above the first line: take the first word.
withinContent = false;
- wordIndex = line->lastWord - 1;
+ wordIndex = 0;
charPos = 0;
- } else if (event->xWidget < lineXOffsetWidget (line)) {
- // Left of the first word in the line.
- wordIndex = line->firstWord;
+ } else if (event->yCanvas >= yLast) {
+ // Below the last line: take the last word.
withinContent = false;
- charPos = 0;
+ wordIndex = words->size () - 1;
+ word = words->getRef (wordIndex);
+ charPos = word->content.type == core::Content::TEXT ?
+ strlen (word->content.text) : 0;
} else {
- nextWordStartX = lineXOffsetWidget (line);
- found = false;
- for (wordIndex = line->firstWord;
- !found && wordIndex < line->lastWord;
- wordIndex++) {
- word = words->getRef (wordIndex);
- wordStartX = nextWordStartX;
- nextWordStartX += word->size.width + word->effSpace;
-
- if (event->xWidget >= wordStartX &&
- event->xWidget < nextWordStartX) {
- // We have found the word.
- if (word->content.type == core::Content::TEXT) {
- // Search the character the mouse pointer is in.
- // nextWordX is the right side of this character.
- charPos = 0;
- while ((nextWordX = wordStartX +
- layout->textWidth (word->style->font,
- word->content.text, charPos))
- <= event->xWidget)
- charPos = layout->nextGlyph (word->content.text, charPos);
-
- // The left side of this character.
- prevPos = layout->prevGlyph (word->content.text, charPos);
- wordX = wordStartX + layout->textWidth (word->style->font,
- word->content.text,
- prevPos);
-
- // If the mouse pointer is left from the middle, use the left
- // position, otherwise, use the right one.
- if (event->xWidget <= (wordX + nextWordX) / 2)
- charPos = prevPos;
- } else {
- // Depends on whether the pointer is within the left or
- // right half of the (non-text) word.
- if (event->xWidget >=
- (wordStartX + nextWordStartX) / 2)
- charPos = core::SelectionState::END_OF_WORD;
- else
+ lineIndex = findLineIndex (event->yWidget);
+ line = lines->getRef (lineIndex);
+
+ // Pointer within the break space?
+ if (event->yWidget >
+ (lineYOffsetWidget (line) + line->boxAscent + line->boxDescent)) {
+ // Choose this break.
+ withinContent = false;
+ wordIndex = line->lastWord;
+ charPos = 0;
+ } else if (event->xWidget < lineXOffsetWidget (line)) {
+ // Left of the first word in the line.
+ wordIndex = line->firstWord;
+ withinContent = false;
+ charPos = 0;
+ } else {
+ nextWordStartX = lineXOffsetWidget (line);
+ found = false;
+ for (wordIndex = line->firstWord;
+ !found && wordIndex <= line->lastWord;
+ wordIndex++) {
+ word = words->getRef (wordIndex);
+ wordStartX = nextWordStartX;
+ nextWordStartX += word->size.width + word->effSpace;
+
+ if (event->xWidget >= wordStartX &&
+ event->xWidget < nextWordStartX) {
+ // We have found the word.
+ if (word->content.type == core::Content::TEXT) {
+ // Search the character the mouse pointer is in.
+ // nextWordX is the right side of this character.
charPos = 0;
+ while ((nextWordX = wordStartX +
+ layout->textWidth (word->style->font,
+ word->content.text, charPos))
+ <= event->xWidget)
+ charPos = layout->nextGlyph (word->content.text,
+ charPos);
+ // The left side of this character.
+ prevPos = layout->prevGlyph (word->content.text, charPos);
+ wordX = wordStartX + layout->textWidth (word->style->font,
+ word->content.text,
+ prevPos);
+
+ // If the mouse pointer is left from the middle, use the
+ // left position, otherwise, use the right one.
+ if (event->xWidget <= (wordX + nextWordX) / 2)
+ charPos = prevPos;
+ } else {
+ // Depends on whether the pointer is within the left or
+ // right half of the (non-text) word.
+ if (event->xWidget >=
+ (wordStartX + nextWordStartX) / 2)
+ charPos = core::SelectionState::END_OF_WORD;
+ else
+ charPos = 0;
+ }
+
+ found = true;
+ link = word->style ? word->style->x_link : -1;
+ break;
}
-
- found = true;
- link = word->style ? word->style->x_link : -1;
- break;
}
- }
- if (!found) {
- // No word found in this line (i.e. we are on the right side),
- // take the last of this line.
- withinContent = false;
- wordIndex = line->lastWord - 1;
- if (wordIndex >= words->size ())
- wordIndex--;
- word = words->getRef (wordIndex);
- charPos = word->content.type == core::Content::TEXT ?
- strlen (word->content.text) :
- (int)core::SelectionState::END_OF_WORD;
+ if (!found) {
+ // No word found in this line (i.e. we are on the right side),
+ // take the last of this line.
+ withinContent = false;
+ wordIndex = line->lastWord;
+ if (wordIndex >= words->size ())
+ wordIndex--;
+ word = words->getRef (wordIndex);
+ charPos = word->content.type == core::Content::TEXT ?
+ strlen (word->content.text) :
+ (int)core::SelectionState::END_OF_WORD;
+ }
}
}
}
-
it = new TextblockIterator (this, core::Content::SELECTION_CONTENT,
wordIndex);
r = selectionHandleEvent (eventType, it, charPos, link, event,
@@ -794,12 +808,12 @@ void Textblock::justifyLine (Line *line, int availWidth)
diff = availWidth - lastLineWidth;
if (diff > 0) {
origSpaceSum = 0;
- for (i = line->firstWord; i < line->lastWord - 1; i++)
+ for (i = line->firstWord; i < line->lastWord; i++)
origSpaceSum += words->getRef(i)->origSpace;
origSpaceCum = 0;
lastEffSpaceDiffCum = 0;
- for (i = line->firstWord; i < line->lastWord - 1; i++) {
+ for (i = line->firstWord; i < line->lastWord; i++) {
origSpaceCum += words->getRef(i)->origSpace;
if (origSpaceCum == 0)
@@ -818,9 +832,9 @@ void Textblock::justifyLine (Line *line, int availWidth)
}
-void Textblock::addLine (int wordInd, bool newPar)
+Textblock::Line *Textblock::addLine (int wordIndex, bool newPar)
{
- Line *lastLine, *plastLine;
+ Line *lastLine;
//DBG_MSG (page, "wrap", 0, "Dw_page_add_line");
//DBG_MSG_START (page);
@@ -833,29 +847,19 @@ void Textblock::addLine (int wordInd, bool newPar)
lastLine = lines->getRef (lines->size () - 1);
- if (lines->size () == 1)
- plastLine = NULL;
- else
- plastLine = lines->getRef (lines->size () - 2);
-
- if (plastLine) {
- /* second or more lines: copy values of last line */
- lastLine->top =
- plastLine->top + plastLine->ascent +
- plastLine->descent + plastLine->breakSpace;
- lastLine->maxLineWidth = plastLine->maxLineWidth;
- lastLine->maxWordMin = plastLine->maxWordMin;
- lastLine->maxParMax = plastLine->maxParMax;
- lastLine->parMin = plastLine->parMin;
- lastLine->parMax = plastLine->parMax;
- } else {
- /* first line: initialize values */
+ if (lines->size () == 1) {
lastLine->top = 0;
lastLine->maxLineWidth = line1OffsetEff;
lastLine->maxWordMin = 0;
lastLine->maxParMax = 0;
- lastLine->parMin = line1OffsetEff;
- lastLine->parMax = line1OffsetEff;
+ } else {
+ Line *prevLine = lines->getRef (lines->size () - 2);
+
+ lastLine->top = prevLine->top + prevLine->boxAscent +
+ prevLine->boxDescent + prevLine->breakSpace;
+ lastLine->maxLineWidth = prevLine->maxLineWidth;
+ lastLine->maxWordMin = prevLine->maxWordMin;
+ lastLine->maxParMax = prevLine->maxParMax;
}
//DBG_OBJ_ARRSET_NUM (page, "lines.%d.top", page->num_lines - 1,
@@ -871,9 +875,9 @@ void Textblock::addLine (int wordInd, bool newPar)
//DBG_OBJ_ARRSET_NUM (page, "lines.%d.parMax", page->num_lines - 1,
// lastLine->parMax);
- lastLine->firstWord = wordInd;
- lastLine->ascent = 0;
- lastLine->descent = 0;
+ lastLine->firstWord = wordIndex;
+ lastLine->boxAscent = lastLine->contentAscent = 0;
+ lastLine->boxDescent = lastLine->contentDescent = 0;
lastLine->marginDescent = 0;
lastLine->breakSpace = 0;
lastLine->leftOffset = 0;
@@ -881,9 +885,9 @@ void Textblock::addLine (int wordInd, bool newPar)
lastLine->boxRight = 0;
//DBG_OBJ_ARRSET_NUM (page, "lines.%d.ascent", page->num_lines - 1,
- // lastLine->ascent);
+ // lastLine->boxAscent);
//DBG_OBJ_ARRSET_NUM (page, "lines.%d.descent", page->num_lines - 1,
- // lastLine->descent);
+ // lastLine->boxDescent);
/* update values in line */
lastLine->maxLineWidth = misc::max (lastLine->maxLineWidth, lastLineWidth);
@@ -898,6 +902,10 @@ void Textblock::addLine (int wordInd, bool newPar)
//DBG_OBJ_ARRSET_NUM (page, "lines.%d.maxParMax", page->num_lines - 1,
// lastLine->maxParMax);
+ /* The following code looks questionable (especially since the values
+ * will be overwritten). In any case, line1OffsetEff is probably
+ * supposed to go into lastLinePar*, not lastLine->par*.
+ */
if (lines->size () > 1) {
lastLine->parMin = 0;
lastLine->parMax = 0;
@@ -921,18 +929,19 @@ void Textblock::addLine (int wordInd, bool newPar)
// lastLine->parMax);
//DBG_MSG_END (page);
+ return lastLine;
}
/*
- * This method is called in two cases: (i) when a word is added (by
- * Dw_page_add_word), and (ii) when a page has to be (partially)
- * rewrapped. It does word wrap, and adds new lines, if necesary.
+ * This method is called in two cases: (i) when a word is added
+ * (ii) when a page has to be (partially) rewrapped. It does word wrap,
+ * and adds new lines if necessary.
*/
void Textblock::wordWrap(int wordIndex)
{
Line *lastLine;
- Word *word, *prevWord;
- int availWidth, lastSpace, leftOffset;
+ Word *word;
+ int availWidth, lastSpace, leftOffset, len;
bool newLine = false, newPar = false;
core::Extremes wordExtremes;
@@ -948,6 +957,17 @@ void Textblock::wordWrap(int wordIndex)
availWidth = layout->getWidthViewport () - 10;
word = words->getRef (wordIndex);
+ word->effSpace = word->origSpace;
+
+ /* Test whether line1Offset can be used. */
+ if (wordIndex == 0) {
+ if (ignoreLine1OffsetSometimes &&
+ line1Offset + word->size.width > availWidth) {
+ line1OffsetEff = 0;
+ } else {
+ line1OffsetEff = line1Offset;
+ }
+ }
if(word->content.type == dw::core::Content::FLOAT_REF)
{
@@ -955,10 +975,12 @@ void Textblock::wordWrap(int wordIndex)
int y =
allocation.y - containingBox->allocation.y + getStyle()->boxOffsetY() +
(line ? line->top : 0);
- int lineHeight = line ? line->ascent + line->descent : 0;
+ int lineHeight = line ? line->boxAscent + line->boxDescent : 0;
containingBox->handleFloatInContainer(word->content.widget, misc::max(lines->size() - 1, 0), y, lastLineWidth, lineHeight);
}
+
+
if (lines->size () == 0) {
//DBG_MSG (page, "wrap", 0, "first line");
@@ -966,72 +988,61 @@ void Textblock::wordWrap(int wordIndex)
newPar = true;
lastLine = NULL;
} else {
+ Word *prevWord = words->getRef (wordIndex - 1);
+
lastLine = lines->getRef (lines->size () - 1);
- if (lines->size () > 0) {
- prevWord = words->getRef (wordIndex - 1);
- if (prevWord->content.type == core::Content::BREAK) {
- //DBG_MSG (page, "wrap", 0, "after a break");
- /* previous word is a break */
- newLine = true;
- newPar = true;
- } else if (word->style->whiteSpace
- != core::style::WHITE_SPACE_NORMAL) {
- //DBG_MSGF (page, "wrap", 0, "no wrap (white_space = %d)",
- // word->style->white_space);
- newLine = false;
- newPar = false;
- } else {
- if (lastLine->firstWord != wordIndex) {
- /* Does new word fit into the last line? */
- //DBG_MSGF (page, "wrap", 0,
- // "word %d (%s) fits? (%d + %d + %d &lt;= %d)...",
- // word_ind, a_Dw_content_html (&word->content),
- // page->lastLine_width, prevWord->orig_space,
- // word->size.width, availWidth);
- newLine = (lastLineWidth + prevWord->origSpace +
- word->size.width
- > availWidth -
- (lastLine->boxLeft + lastLine->boxRight));
- //DBG_MSGF (page, "wrap", 0, "... %s.",
- // newLine ? "No" : "Yes");
- }
- }
+ if (prevWord->content.type == core::Content::BREAK) {
+ //DBG_MSG (page, "wrap", 0, "after a break");
+ /* previous word is a break */
+ newLine = true;
+ newPar = true;
+ } else if (word->style->whiteSpace == core::style::WHITE_SPACE_NOWRAP ||
+ word->style->whiteSpace == core::style::WHITE_SPACE_PRE) {
+ //DBG_MSGF (page, "wrap", 0, "no wrap (white_space = %d)",
+ // word->style->white_space);
+ newLine = false;
+ newPar = false;
+ } else if (lastLine->firstWord != wordIndex) {
+ /* Does new word fit into the last line? */
+ //DBG_MSGF (page, "wrap", 0,
+ // "word %d (%s) fits? (%d + %d + %d &lt;= %d)...",
+ // word_ind, a_Dw_content_html (&word->content),
+ // page->lastLine_width, prevWord->orig_space,
+ // word->size.width, availWidth);
+ newLine = lastLineWidth + prevWord->origSpace + word->size.width >
+ availWidth - (lastLine->boxLeft + lastLine->boxRight);
+ //DBG_MSGF (page, "wrap", 0, "... %s.",
+ // newLine ? "No" : "Yes");
}
}
- /* Has sometimes the wrong value. */
- word->effSpace = word->origSpace;
- //DBG_OBJ_ARRSET_NUM (page,"words.%d.eff_space", word_ind, word->eff_space);
-
- /* Test, whether line1_offset can be used. */
- if (wordIndex == 0) {
- if (ignoreLine1OffsetSometimes) {
- if (line1Offset + word->size.width > availWidth)
- line1OffsetEff = 0;
- else
- line1OffsetEff = line1Offset;
- } else
- line1OffsetEff = line1Offset;
+ if (newLine) {
+ if (word->style->textAlign == core::style::TEXT_ALIGN_JUSTIFY &&
+ lastLine != NULL && !newPar) {
+ justifyLine (lastLine, availWidth);
+ }
+ lastLine = addLine (wordIndex, newPar);
}
- if (lastLine != NULL && newLine && !newPar &&
- word->style->textAlign == core::style::TEXT_ALIGN_JUSTIFY)
- justifyLine (lastLine, availWidth);
+ lastLine->lastWord = wordIndex;
+ lastLine->boxAscent = misc::max (lastLine->boxAscent, word->size.ascent);
+ lastLine->boxDescent = misc::max (lastLine->boxDescent, word->size.descent);
- if (newLine) {
- addLine (wordIndex, newPar);
- lastLine = lines->getRef (lines->size () - 1);
- }
+ len = word->style->font->ascent;
+ if (word->style->valign == core::style::VALIGN_SUPER)
+ len += len / 2;
+ lastLine->contentAscent = misc::max (lastLine->contentAscent, len);
- lastLine->lastWord = wordIndex + 1;
- lastLine->ascent = misc::max (lastLine->ascent, (int) word->size.ascent);
- lastLine->descent = misc::max (lastLine->descent, (int) word->size.descent);
+ len = word->style->font->descent;
+ if (word->style->valign == core::style::VALIGN_SUB)
+ len += word->style->font->ascent / 3;
+ lastLine->contentDescent = misc::max (lastLine->contentDescent, len);
//DBG_OBJ_ARRSET_NUM (page, "lines.%d.ascent", page->num_lines - 1,
- // lastLine->ascent);
+ // lastLine->boxAscent);
//DBG_OBJ_ARRSET_NUM (page, "lines.%d.descent", page->num_lines - 1,
- // lastLine->descent);
+ // lastLine->boxDescent);
if (word->content.type == core::Content::WIDGET) {
lastLine->marginDescent =
@@ -1049,49 +1060,52 @@ void Textblock::wordWrap(int wordIndex)
/* Here, we know already what the break and the bottom margin
* contributed to the space before this line.
*/
- lastLine->ascent =
- misc::max (lastLine->ascent,
+ lastLine->boxAscent =
+ misc::max (lastLine->boxAscent,
word->size.ascent
+ word->content.widget->getStyle()->margin.top);
//DBG_OBJ_ARRSET_NUM (page, "lines.%d.ascent", page->num_lines - 1,
- // lastLine->ascent);
+ // lastLine->boxAscent);
}
- } else
+ } else {
lastLine->marginDescent =
- misc::max (lastLine->marginDescent, lastLine->descent);
+ misc::max (lastLine->marginDescent, lastLine->boxDescent);
- getWordExtremes (word, &wordExtremes);
- lastSpace = (wordIndex > 0) ? words->getRef(wordIndex - 1)->origSpace : 0;
+ if (word->content.type == core::Content::BREAK)
+ lastLine->breakSpace =
+ misc::max (word->content.breakSpace,
+ lastLine->marginDescent - lastLine->boxDescent,
+ lastLine->breakSpace);
+ }
- if (word->content.type == core::Content::BREAK)
- lastLine->breakSpace =
- misc::max (word->content.breakSpace,
- lastLine->marginDescent - lastLine->descent,
- lastLine->breakSpace);
+ lastSpace = (wordIndex > 0) ? words->getRef(wordIndex - 1)->origSpace : 0;
- lastLineWidth += word->size.width;
if (!newLine)
lastLineWidth += lastSpace;
-
- lastLineParMin += wordExtremes.maxWidth;
- lastLineParMax += wordExtremes.maxWidth;
if (!newPar) {
lastLineParMin += lastSpace;
lastLineParMax += lastSpace;
}
- if (word->style->whiteSpace != core::style::WHITE_SPACE_NORMAL) {
+ lastLineWidth += word->size.width;
+
+ getWordExtremes (word, &wordExtremes);
+ lastLineParMin += wordExtremes.maxWidth; /* Why maxWidth? */
+ lastLineParMax += wordExtremes.maxWidth;
+
+ if (word->style->whiteSpace == core::style::WHITE_SPACE_NOWRAP ||
+ word->style->whiteSpace == core::style::WHITE_SPACE_PRE) {
lastLine->parMin += wordExtremes.minWidth + lastSpace;
/* This may also increase the accumulated minimum word width. */
lastLine->maxWordMin =
misc::max (lastLine->maxWordMin, lastLine->parMin);
/* NOTE: Most code relies on that all values of nowrap are equal for all
* words within one line. */
- } else
- /* Simple case. */
+ } else {
lastLine->maxWordMin =
misc::max (lastLine->maxWordMin, wordExtremes.minWidth);
+ }
//DBG_OBJ_SET_NUM(page, "lastLine_par_min", page->lastLine_par_min);
//DBG_OBJ_SET_NUM(page, "lastLine_par_max", page->lastLine_par_max);
@@ -1102,8 +1116,9 @@ void Textblock::wordWrap(int wordIndex)
//DBG_OBJ_ARRSET_NUM (page, "lines.%d.max_word_min", page->num_lines - 1,
// lastLine->max_word_min);
- /* Finally, justify the line. Breaks are ignored, since the HTML
- * parser sometimes assignes the wrong style to them. (TODO: ) */
+ /* Align the line.
+ * \todo Use block's style instead once paragraphs become proper blocks.
+ */
if (word->content.type != core::Content::BREAK) {
switch (word->style->textAlign) {
case core::style::TEXT_ALIGN_LEFT:
@@ -1112,15 +1127,12 @@ void Textblock::wordWrap(int wordIndex)
* future) */
leftOffset = 0;
break;
-
case core::style::TEXT_ALIGN_RIGHT:
leftOffset = availWidth - lastLineWidth;
break;
-
case core::style::TEXT_ALIGN_CENTER:
leftOffset = (availWidth - lastLineWidth) / 2;
break;
-
default:
/* compiler happiness */
leftOffset = 0;
@@ -1130,22 +1142,22 @@ void Textblock::wordWrap(int wordIndex)
if (leftOffset < 0)
leftOffset = 0;
- if (listItem && lastLine == lines->getRef (0)) {
+ if (hasListitemValue && lastLine == lines->getRef (0)) {
/* List item markers are always on the left. */
lastLine->leftOffset = 0;
words->getRef(0)->effSpace = words->getRef(0)->origSpace + leftOffset;
//DBG_OBJ_ARRSET_NUM (page, "words.%d.eff_space", 0,
// page->words[0].eff_space);
- } else
+ } else {
lastLine->leftOffset = leftOffset;
-
+ }
+
int y =
allocation.y - containingBox->allocation.y +
getStyle()->boxOffsetX () + lastLine->top;
lastLine->boxLeft = calcLeftFloatBorder(y, this);
lastLine->boxRight = calcRightFloatBorder(y, this);
}
-
mustQueueResize = true;
//DBG_MSG_END (page);
@@ -1160,6 +1172,7 @@ void Textblock::calcWidgetSize (core::Widget *widget, core::Requisition *size)
{
core::Requisition requisition;
int availWidth, availAscent, availDescent;
+ core::style::Style *wstyle = widget->getStyle();
/* We ignore line1_offset[_eff]. */
availWidth = this->availWidth - getStyle()->boxDiffWidth () - innerPadding;
@@ -1171,39 +1184,37 @@ void Textblock::calcWidgetSize (core::Widget *widget, core::Requisition *size)
widget->setAscent (availAscent);
widget->setDescent (availDescent);
widget->sizeRequest (size);
- size->ascent -= widget->getStyle()->margin.top;
- size->descent -= widget->getStyle()->margin.bottom;
+// size->ascent -= wstyle->margin.top;
+// size->descent -= wstyle->margin.bottom;
} else {
/* TODO: Use margin.{top|bottom} here, like above.
* (No harm for the next future.) */
- if (widget->getStyle()->width == core::style::LENGTH_AUTO ||
- widget->getStyle()->height == core::style::LENGTH_AUTO)
+ if (wstyle->width == core::style::LENGTH_AUTO ||
+ wstyle->height == core::style::LENGTH_AUTO)
widget->sizeRequest (&requisition);
- if (widget->getStyle()->width == core::style::LENGTH_AUTO)
+ if (wstyle->width == core::style::LENGTH_AUTO)
size->width = requisition.width;
- else if (core::style::isAbsLength (widget->getStyle()->width))
+ else if (core::style::isAbsLength (wstyle->width))
/* Fixed lengths are only applied to the content, so we have to
* add padding, border and margin. */
- size->width = core::style::absLengthVal (widget->getStyle()->width)
- + widget->getStyle()->boxDiffWidth ();
+ size->width = core::style::absLengthVal (wstyle->width)
+ + wstyle->boxDiffWidth ();
else
- size->width =
- (int) (core::style::perLengthVal (widget->getStyle()->width)
- * availWidth);
+ size->width = (int) (core::style::perLengthVal (wstyle->width)
+ * availWidth);
- if (widget->getStyle()->height == core::style::LENGTH_AUTO) {
+ if (wstyle->height == core::style::LENGTH_AUTO) {
size->ascent = requisition.ascent;
size->descent = requisition.descent;
- } else if (core::style::isAbsLength (widget->getStyle()->height)) {
+ } else if (core::style::isAbsLength (wstyle->height)) {
/* Fixed lengths are only applied to the content, so we have to
* add padding, border and margin. */
- size->ascent =
- core::style::absLengthVal (widget->getStyle()->height)
- + widget->getStyle()->boxDiffHeight ();
+ size->ascent = core::style::absLengthVal (wstyle->height)
+ + wstyle->boxDiffHeight ();
size->descent = 0;
} else {
- double len = core::style::perLengthVal (widget->getStyle()->height);
+ double len = core::style::perLengthVal (wstyle->height);
size->ascent = (int) (len * availAscent);
size->descent = (int) (len * availDescent);
}
@@ -1238,8 +1249,7 @@ void Textblock::rewrap ()
//DBG_OBJ_SET_NUM(page, "num_lines", page->num_lines);
//DBG_OBJ_SET_NUM(page, "lastLine_width", page->lastLine_width);
- /* In the word list, we start at the last word, plus one (see definition
- * of last_word), in the line before. */
+ /* In the word list, start at the last word plus one in the line before. */
if (wrapRef > 0) {
/* Note: In this case, Dw_page_real_word_wrap will immediately find
* the need to rewrap the line, since we start with the last one (plus
@@ -1250,11 +1260,11 @@ void Textblock::rewrap ()
lastLineParMin = lastLine->parMin;
lastLineParMax = lastLine->parMax;
- wordIndex = lastLine->lastWord;
- for (i = lastLine->firstWord; i < lastLine->lastWord - 1; i++)
+ wordIndex = lastLine->lastWord + 1;
+ for (i = lastLine->firstWord; i < lastLine->lastWord; i++)
lastLineWidth += (words->getRef(i)->size.width +
words->getRef(i)->origSpace);
- lastLineWidth += words->getRef(lastLine->lastWord - 1)->size.width;
+ lastLineWidth += words->getRef(lastLine->lastWord)->size.width;
} else {
lastLineParMin = 0;
lastLineParMax = 0;
@@ -1298,6 +1308,156 @@ void Textblock::rewrap ()
}
/*
+ * Draw the decorations on a word.
+ */
+void Textblock::decorateText(core::View *view, core::style::Style *style,
+ core::style::Color::Shading shading,
+ int x, int yBase, int width)
+{
+ int y;
+
+ if (style->textDecoration & core::style::TEXT_DECORATION_UNDERLINE) {
+ y = yBase + 1;
+ view->drawLine (style->color, shading, x, y, x + width - 1, y);
+ }
+ if (style->textDecoration & core::style::TEXT_DECORATION_OVERLINE) {
+ y = yBase - style->font->ascent + 1;
+ view->drawLine (style->color, shading, x, y, x + width - 1, y);
+ }
+ if (style->textDecoration & core::style::TEXT_DECORATION_LINE_THROUGH) {
+ int height = 1 + style->font->xHeight / 10;
+
+ y = yBase + (style->font->descent - style->font->ascent) / 2;
+ view->drawRectangle (style->color, shading, true, x, y, width, height);
+ }
+}
+
+/*
+ * Draw a word of text.
+ */
+void Textblock::drawText(int wordIndex, core::View *view,core::Rectangle *area,
+ int xWidget, int yWidgetBase)
+{
+ Word *word = words->getRef(wordIndex);
+ int xWorld = allocation.x + xWidget;
+ core::style::Style *style = word->style;
+ int yWorldBase;
+
+ /* Adjust the text baseline if the word is <SUP>-ed or <SUB>-ed. */
+ if (style->valign == core::style::VALIGN_SUB)
+ yWidgetBase += style->font->ascent / 3;
+ else if (style->valign == core::style::VALIGN_SUPER) {
+ yWidgetBase -= style->font->ascent / 2;
+ }
+ yWorldBase = yWidgetBase + allocation.y;
+
+ view->drawText (style->font, style->color,
+ core::style::Color::SHADING_NORMAL, xWorld, yWorldBase,
+ word->content.text, strlen (word->content.text));
+
+ if (style->textDecoration)
+ decorateText(view, style, core::style::Color::SHADING_NORMAL, xWorld,
+ yWorldBase, word->size.width);
+
+ for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
+ if (hlStart[layer].index <= wordIndex &&
+ hlEnd[layer].index >= wordIndex) {
+ const int wordLen = strlen (word->content.text);
+ int xStart, width;
+ int firstCharIdx = 0;
+ int lastCharIdx = wordLen;
+
+ if (wordIndex == hlStart[layer].index)
+ firstCharIdx = misc::min (hlStart[layer].nChar, wordLen);
+
+ if (wordIndex == hlEnd[layer].index)
+ lastCharIdx = misc::min (hlEnd[layer].nChar, wordLen);
+
+ xStart = xWorld;
+ if (firstCharIdx)
+ xStart += layout->textWidth (style->font, word->content.text,
+ firstCharIdx);
+ if (firstCharIdx == 0 && lastCharIdx == wordLen)
+ width = word->size.width;
+ else
+ width = layout->textWidth (style->font,
+ word->content.text + firstCharIdx,
+ lastCharIdx - firstCharIdx);
+ if (width > 0) {
+ /* Highlight text */
+ core::style::Color *wordBgColor;
+
+ if (!(wordBgColor = style->backgroundColor))
+ wordBgColor = getBgColor();
+
+ /* Draw background for highlighted text. */
+ view->drawRectangle (
+ wordBgColor, core::style::Color::SHADING_INVERSE, true, xStart,
+ yWorldBase - style->font->ascent, width,
+ style->font->ascent + style->font->descent);
+
+ /* Highlight the text. */
+ view->drawText (style->font, style->color,
+ core::style::Color::SHADING_INVERSE, xStart,
+ yWorldBase, word->content.text + firstCharIdx,
+ lastCharIdx - firstCharIdx);
+
+ if (style->textDecoration)
+ decorateText(view, style, core::style::Color::SHADING_INVERSE,
+ xStart, yWorldBase, width);
+ }
+ }
+ }
+}
+
+/*
+ * Draw a space.
+ */
+void Textblock::drawSpace(int wordIndex, core::View *view,
+ core::Rectangle *area, int xWidget, int yWidgetBase)
+{
+ Word *word = words->getRef(wordIndex);
+ int xWorld = allocation.x + xWidget;
+ int yWorldBase;
+ core::style::Style *style = word->spaceStyle;
+ bool highlight = false;
+
+ /* Adjust the space baseline if it is <SUP>-ed or <SUB>-ed */
+ if (style->valign == core::style::VALIGN_SUB)
+ yWidgetBase += style->font->ascent / 3;
+ else if (style->valign == core::style::VALIGN_SUPER) {
+ yWidgetBase -= style->font->ascent / 2;
+ }
+ yWorldBase = allocation.y + yWidgetBase;
+
+ for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
+ if (hlStart[layer].index <= wordIndex &&
+ hlEnd[layer].index > wordIndex) {
+ highlight = true;
+ break;
+ }
+ }
+ if (highlight) {
+ core::style::Color *spaceBgColor;
+
+ if (!(spaceBgColor = style->backgroundColor))
+ spaceBgColor = getBgColor();
+
+ view->drawRectangle (
+ spaceBgColor, core::style::Color::SHADING_INVERSE, true, xWorld,
+ yWorldBase - style->font->ascent, word->effSpace,
+ style->font->ascent + style->font->descent);
+ }
+ if (style->textDecoration) {
+ core::style::Color::Shading shading = highlight ?
+ core::style::Color::SHADING_INVERSE :
+ core::style::Color::SHADING_NORMAL;
+
+ decorateText(view, style, shading, xWorld, yWorldBase, word->effSpace);
+ }
+}
+
+/*
* Paint a line
* - x and y are toplevel dw coordinates (Question: what Dw? Changed. Test!)
* - area is used always (ev. set it to event->area)
@@ -1305,219 +1465,56 @@ void Textblock::rewrap ()
*/
void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
{
- Word *word;
- int wordIndex;
- int xWidget, yWidget, xWorld, yWorld, yWorldBase;
- int startHL, widthHL;
- int wordLen;
- int diff, effHLStart, effHLEnd, layer;
- core::Widget *child;
- core::Rectangle childArea;
- core::style::Color *color, *thisBgColor, *wordBgColor;
+ int xWidget = lineXOffsetWidget(line);
+ int yWidgetBase = lineYOffsetWidget (line) + line->boxAscent;
/* Here's an idea on how to optimize this routine to minimize the number
- * of calls to gdk_draw_string:
+ * of drawing calls:
*
* Copy the text from the words into a buffer, adding a new word
* only if: the attributes match, and the spacing is either zero or
* equal to the width of ' '. In the latter case, copy a " " into
* the buffer. Then draw the buffer. */
- thisBgColor = getBgColor ();
+ for (int wordIndex = line->firstWord;
+ wordIndex <= line->lastWord && xWidget < area->x + area->width;
+ wordIndex++) {
+ Word *word = words->getRef(wordIndex);
- xWidget = lineXOffsetWidget(line);
- xWorld = allocation.x + xWidget;
- yWidget = lineYOffsetWidget (line);
- yWorld = allocation.y + yWidget;
- yWorldBase = yWorld + line->ascent;
+ if (xWidget + word->size.width + word->effSpace >= area->x) {
+ if (word->content.type == core::Content::TEXT ||
+ word->content.type == core::Content::WIDGET) {
- for (wordIndex = line->firstWord; wordIndex < line->lastWord;
- wordIndex++) {
- word = words->getRef(wordIndex);
- diff = 0;
- color = word->style->color;
-
- //DBG_OBJ_ARRSET_NUM (page, "words.%d.<i>drawn at</i>.x", wordIndex,
- // xWidget);
- //DBG_OBJ_ARRSET_NUM (page, "words.%d.<i>drawn at</i>.y", wordIndex,
- // yWidget);
-
- switch (word->content.type) {
- case core::Content::TEXT:
- if (word->style->backgroundColor)
- wordBgColor = word->style->backgroundColor;
- else
- wordBgColor = thisBgColor;
-
- /* Adjust the text baseline if the word is <SUP>-ed or <SUB>-ed. */
- if (word->style->valign == core::style::VALIGN_SUB)
- diff = word->size.ascent / 2;
- else if (word->style->valign == core::style::VALIGN_SUPER)
- diff -= word->size.ascent / 3;
-
- /* Draw background (color, image), when given. */
- if (word->style->hasBackground () && word->size.width > 0)
- drawBox (view, word->style, area,
- xWidget, yWidget + line->ascent - word->size.ascent,
- word->size.width, word->size.ascent + word->size.descent,
- false);
-
- /* Draw space background (color, image), when given. */
- if (word->spaceStyle->hasBackground () && word->effSpace > 0)
- drawBox (view, word->spaceStyle, area,
- xWidget + word->size.width,
- yWidget + line->ascent - word->size.ascent,
- word->effSpace, word->size.ascent + word->size.descent,
- false);
- view->drawText (word->style->font, color,
- core::style::Color::SHADING_NORMAL,
- xWorld, yWorldBase + diff,
- word->content.text, strlen (word->content.text));
-
- /* underline */
- if (word->style->textDecoration &
- core::style::TEXT_DECORATION_UNDERLINE)
- view->drawLine (color, core::style::Color::SHADING_NORMAL,
- xWorld, yWorldBase + 1 + diff,
- xWorld + word->size.width - 1,
- yWorldBase + 1 + diff);
- if (wordIndex + 1 < line->lastWord &&
- (word->spaceStyle->textDecoration
- & core::style::TEXT_DECORATION_UNDERLINE))
- view->drawLine (word->spaceStyle->color,
- core::style::Color::SHADING_NORMAL,
- xWorld + word->size.width,
- yWorldBase + 1 + diff,
- xWorld + word->size.width + word->effSpace - 1,
- yWorldBase + 1 + diff);
-
- /* strike-through */
- if (word->style->textDecoration
- & core::style::TEXT_DECORATION_LINE_THROUGH)
- view->drawLine (color, core::style::Color::SHADING_NORMAL,
- xWorld,
- yWorldBase - word->size.ascent / 2 + diff,
- xWorld + word->size.width - 1,
- yWorldBase - word->size.ascent / 2 + diff);
- if (wordIndex + 1 < line->lastWord &&
- (word->spaceStyle->textDecoration
- & core::style::TEXT_DECORATION_LINE_THROUGH))
- view->drawLine (word->spaceStyle->color,
- core::style::Color::SHADING_NORMAL,
- xWorld + word->size.width,
- yWorldBase - word->size.ascent / 2 + diff,
- xWorld + word->size.width + word->effSpace - 1,
- yWorldBase - word->size.ascent / 2 + diff);
-
- for (layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
- if (hlStart[layer].index <= wordIndex &&
- hlEnd[layer].index >= wordIndex) {
-
- wordLen = strlen (word->content.text);
- effHLEnd = misc::min (wordLen, hlEnd[layer].nChar);
- effHLStart = 0;
- if (wordIndex == hlStart[layer].index)
- effHLStart = misc::min (hlStart[layer].nChar, wordLen);
-
- effHLEnd = wordLen;
- if (wordIndex == hlEnd[layer].index)
- effHLEnd = misc::min (hlEnd[layer].nChar, wordLen);
-
- startHL = xWorld + layout->textWidth (word->style->font,
- word->content.text,
- effHLStart);
- widthHL =
- layout->textWidth (word->style->font,
- word->content.text + effHLStart,
- effHLEnd - effHLStart);
-
- // If the space after this word highlighted, and this word
- // is not the last one in this line, highlight also the
- // space.
- /** \todo This should also be done with spaces after non-text
- * words, but this is not yet defined very well. */
- if (wordIndex < hlEnd[layer].index &&
- wordIndex < words->size () &&
- wordIndex != line->lastWord - 1)
- widthHL += word->effSpace;
-
-
- if (widthHL != 0) {
- /* Draw background for highlighted text. */
- view->drawRectangle (wordBgColor,
- core::style::Color::SHADING_INVERSE,
- true, startHL,
- yWorldBase - word->size.ascent,
- widthHL,
- word->size.ascent + word->size.descent);
-
- /* Highlight the text. */
- view->drawText (word->style->font,
- color, core::style::Color::SHADING_INVERSE,
- startHL, yWorldBase + diff,
- word->content.text + effHLStart,
- effHLEnd - effHLStart);
-
- /* underline and strike-through */
- if (word->style->textDecoration
- & core::style::TEXT_DECORATION_UNDERLINE)
- view->drawLine (color,
- core::style::Color::SHADING_INVERSE,
- startHL, yWorldBase + 1 + diff,
- startHL + widthHL - 1,
- yWorldBase + 1 + diff);
- if (word->style->textDecoration
- & core::style::TEXT_DECORATION_LINE_THROUGH)
- view->drawLine (color,
- core::style::Color::SHADING_INVERSE,
- startHL,
- yWorldBase - word->size.ascent / 2 + diff,
- startHL + widthHL - 1,
- yWorldBase - word->size.ascent / 2
- + diff);
+ if (word->size.width > 0) {
+ if (word->style->hasBackground ()) {
+ drawBox (view, word->style, area, xWidget,
+ yWidgetBase - line->boxAscent, word->size.width,
+ line->boxAscent + line->boxDescent, false);
}
- }
- }
- break;
-
- case core::Content::WIDGET:
- child = word->content.widget;
- if (child->intersects (area, &childArea))
- child->draw (view, &childArea);
- break;
+ if (word->content.type == core::Content::WIDGET) {
+ core::Widget *child = word->content.widget;
+ core::Rectangle childArea;
- case core::Content::ANCHOR: case core::Content::BREAK:
- /* nothing - an anchor/break isn't seen */
- /*
- * Historical note:
- * > BUG: sometimes anchors have x_space;
- * > we subtract that just in case --EG
- * This is inconsistent with other parts of the code, so it should
- * be tried to prevent this earlier.--SG
- */
- /*
- * x_viewport -= word->size.width + word->eff_space;
- * xWidget -= word->size.width + word->eff_space;
- */
-#if 0
- /* Useful for testing: draw breaks. */
- if (word->content.type == DW_CONTENT_BREAK)
- gdk_draw_rectangle (window, color, TRUE,
- p_Dw_widget_xWorld_to_viewport (widget,
- widget->allocation.x +
- Dw_page_line_total_x_offset(page, line)),
- y_viewport_base + line->descent,
- DW_WIDGET_CONTENT_WIDTH(widget),
- word->content.break_space);
-#endif
- break;
+ if (child->intersects (area, &childArea))
+ child->draw (view, &childArea);
+ } else {
+ drawText(wordIndex, view, area, xWidget, yWidgetBase);
+ }
+ }
+ if (word->effSpace > 0 && wordIndex < line->lastWord &&
+ words->getRef(wordIndex + 1)->content.type !=
+ core::Content::BREAK) {
+ if (word->spaceStyle->hasBackground ())
+ drawBox (view, word->spaceStyle, area,
+ xWidget + word->size.width,
+ yWidgetBase - line->boxAscent, word->effSpace,
+ line->boxAscent + line->boxDescent, false);
+ drawSpace(wordIndex, view, area, xWidget + word->size.width,
+ yWidgetBase);
+ }
- default:
- fprintf (stderr, "BUG!!! at (%d, %d).\n", xWorld, yWorldBase + diff);
- break;
+ }
}
-
- xWorld += word->size.width + word->effSpace;
xWidget += word->size.width + word->effSpace;
}
}
@@ -1534,19 +1531,19 @@ int Textblock::findLineIndex (int y)
while ( step > 1 ) {
index = low + step;
if (index <= maxIndex &&
- lineYOffsetWidgetI (index) < y)
+ lineYOffsetWidgetI (index) <= y)
low = index;
step = (step + 1) >> 1;
}
- if (low < maxIndex && lineYOffsetWidgetI (low + 1) < y)
+ if (low < maxIndex && lineYOffsetWidgetI (low + 1) <= y)
low++;
/*
* This new routine returns the line number between (top) and
- * (top + size.ascent + size.descent + break_space): the space
+ * (top + size.ascent + size.descent + breakSpace): the space
* _below_ the line is considered part of the line. Old routine
- * returned line number between (top - previous_line->break_space)
+ * returned line number between (top - previous_line->breakSpace)
* and (top + size.ascent + size.descent): the space _above_ the
* line was considered part of the line. This is important for
* Dw_page_find_link() --EG
@@ -1562,13 +1559,13 @@ int Textblock::findLineOfWord (int wordIndex)
{
int high = lines->size () - 1, index, low = 0;
- //g_return_val_if_fail (word_index >= 0, -1);
- //g_return_val_if_fail (word_index < page->num_words, -1);
+ if (wordIndex < 0 || wordIndex >= words->size ())
+ return -1;
while (true) {
index = (low + high) / 2;
if (wordIndex >= lines->getRef(index)->firstWord) {
- if (wordIndex < lines->getRef(index)->lastWord)
+ if (wordIndex <= lines->getRef(index)->lastWord)
return index;
else
low = index + 1;
@@ -1580,29 +1577,36 @@ int Textblock::findLineOfWord (int wordIndex)
/**
* \brief Find the index of the word, or -1.
*/
-int Textblock::findWord (int x, int y)
+Textblock::Word *Textblock::findWord (int x, int y, bool *inSpace)
{
int lineIndex, wordIndex;
- int xCursor, lastXCursor;
+ int xCursor, lastXCursor, yWidgetBase;
Line *line;
Word *word;
+ *inSpace = false;
+
if ((lineIndex = findLineIndex (y)) >= lines->size ())
- return -1;
+ return NULL;
line = lines->getRef (lineIndex);
- if (lineYOffsetWidget (line) + line->ascent + line->descent <= y)
- return -1;
+ yWidgetBase = lineYOffsetWidget (line) + line->boxAscent;
+ if (yWidgetBase + line->boxDescent <= y)
+ return NULL;
xCursor = lineXOffsetWidget (line);
- for (wordIndex = line->firstWord; wordIndex < line->lastWord; wordIndex++) {
+ for (wordIndex = line->firstWord; wordIndex <= line->lastWord;wordIndex++) {
word = words->getRef (wordIndex);
lastXCursor = xCursor;
xCursor += word->size.width + word->effSpace;
- if (lastXCursor <= x && xCursor > x)
- return wordIndex;
+ if (lastXCursor <= x && xCursor > x &&
+ y > yWidgetBase - word->size.ascent &&
+ y <= yWidgetBase + word->size.descent) {
+ *inSpace = x >= xCursor - word->effSpace;
+ return word;
+ }
}
- return -1;
+ return NULL;
}
void Textblock::draw (core::View *view, core::Rectangle *area)
@@ -1670,37 +1674,67 @@ Textblock::Word *Textblock::addWord (int width, int ascent, int descent,
/**
* Calculate the size of a text word.
*/
-void Textblock::calcTextSize (const char *text, core::style::Style *style,
+void Textblock::calcTextSize (const char *text, size_t len,
+ core::style::Style *style,
core::Requisition *size)
{
- size->width =
- layout->textWidth (style->font, text, strlen (text));
+ size->width = layout->textWidth (style->font, text, len);
size->ascent = style->font->ascent;
size->descent = style->font->descent;
+ /*
+ * For 'normal' line height, just use ascent and descent from font.
+ * For absolute/percentage, line height is relative to font size, which
+ * is (irritatingly) smaller than ascent+descent.
+ */
+ if (style->lineHeight != core::style::LENGTH_AUTO) {
+ int height, leading;
+ float factor = style->font->size;
+
+ factor /= (style->font->ascent + style->font->descent);
+
+ size->ascent = size->ascent * factor + 0.5;
+ size->descent = size->descent * factor + 0.5;
+
+ /* TODO: The containing block's line-height property gives a minimum
+ * height for the line boxes. (Even when it's set to 'normal', i.e.,
+ * AUTO? Apparently.) Once all block elements make Textblocks or
+ * something, this can be handled.
+ */
+ if (core::style::isAbsLength (style->lineHeight))
+ height = core::style::absLengthVal(style->lineHeight);
+ else
+ height = core::style::perLengthVal(style->lineHeight) *
+ style->font->size;
+ leading = height - style->font->size;
+
+ size->ascent += leading / 2;
+ size->descent += leading - (leading / 2);
+ }
+
/* In case of a sub or super script we increase the word's height and
* potentially the line's height.
*/
if (style->valign == core::style::VALIGN_SUB)
- size->descent += (size->ascent / 2);
+ size->descent += (style->font->ascent / 3);
else if (style->valign == core::style::VALIGN_SUPER)
- size->ascent += (size->ascent / 3);
+ size->ascent += (style->font->ascent / 2);
}
/**
- * Add a word to the page structure. Stashes the argument pointer in
- * the page data structure so that it will be deallocated on destroy.
+ * Add a word to the page structure.
*/
-void Textblock::addText (const char *text, core::style::Style *style)
+void Textblock::addText (const char *text, size_t len,
+ core::style::Style *style)
{
Word *word;
core::Requisition size;
- calcTextSize (text, style, &size);
+ calcTextSize (text, len, style, &size);
word = addWord (size.width, size.ascent, size.descent, style);
word->content.type = core::Content::TEXT;
- word->content.text = layout->textZone->strdup(text);
+ word->content.text = layout->textZone->strndup(text, len);
//DBG_OBJ_ARRSET_STR (page, "words.%d.content.text", page->num_words - 1,
// word->content.text);
@@ -1717,7 +1751,7 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style)
core::Requisition size;
/* We first assign -1 as parent_ref, since the call of widget->size_request
- * will otherwise let this DwPage be rewrapped from the beginning.
+ * will otherwise let this Textblock be rewrapped from the beginning.
* (parent_ref is actually undefined, but likely has the value 0.) At the,
* end of this function, the correct value is assigned. */
widget->parentRef = -1;
@@ -1749,7 +1783,7 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style)
/**
- * Add an anchor to the page. "name" is copied, so no strdup is neccessary for
+ * Add an anchor to the page. "name" is copied, so no strdup is necessary for
* the caller.
*
* Return true on success, and false, when this anchor had already been
@@ -1757,11 +1791,10 @@ void Textblock::addWidget (core::Widget *widget, core::style::Style *style)
*/
bool Textblock::addAnchor (const char *name, core::style::Style *style)
{
- Word *word;
char *copy;
int y;
- // Since an anchor does not take any space, it is safe to call
+ // Since an anchor does not take any space, it is safe to call
// addAnchor already here.
if (wasAllocated ()) {
if (lines->size () == 0)
@@ -1774,15 +1807,17 @@ bool Textblock::addAnchor (const char *name, core::style::Style *style)
if (copy == NULL)
/**
- * \todo It may be neccessary for future uses to save the anchor in
+ * \todo It may be necessary for future uses to save the anchor in
* some way, e.g. when parts of the widget tree change.
*/
return false;
else {
- word = addWord (0, 0, 0, style);
- word->content.type = core::Content::ANCHOR;
- word->content.anchor = copy;
- wordWrap (words->size () - 1);
+ Anchor *anchor;
+
+ anchors->increase();
+ anchor = anchors->getRef(anchors->size() - 1);
+ anchor->name = copy;
+ anchor->wordIndex = words->size();
return true;
}
}
@@ -1793,22 +1828,15 @@ bool Textblock::addAnchor (const char *name, core::style::Style *style)
*/
void Textblock::addSpace (core::style::Style *style)
{
- int nl, nw;
- int space;
+ int wordIndex = words->size () - 1;
- nl = lines->size () - 1;
- if (nl >= 0) {
- nw = words->size () - 1;
- if (nw >= 0) {
- /* TODO: remove this test case */
- //if (page->words[nw].orig_space != 0) {
- // _MSG(" a_Dw_page_add_space:: already existing space!!!\n");
- //}
+ if (wordIndex >= 0) {
+ Word *word = words->getRef(wordIndex);
- space = style->font->spaceWidth;
- words->getRef(nw)->origSpace = space;
- words->getRef(nw)->effSpace = space;
- words->getRef(nw)->content.space = true;
+ if (!word->content.space) {
+ word->content.space = true;
+ word->effSpace = word->origSpace = style->font->spaceWidth +
+ style->wordSpacing;
//DBG_OBJ_ARRSET_NUM (page, "words.%d.orig_space", nw,
// page->words[nw].orig_space);
@@ -1816,9 +1844,8 @@ void Textblock::addSpace (core::style::Style *style)
// page->words[nw].eff_space);
//DBG_OBJ_ARRSET_NUM (page, "words.%d.content.space", nw,
// page->words[nw].content.space);
-
- words->getRef(nw)->spaceStyle->unref ();
- words->getRef(nw)->spaceStyle = style;
+ word->spaceStyle->unref ();
+ word->spaceStyle = style;
style->ref ();
}
}
@@ -1830,45 +1857,41 @@ void Textblock::addSpace (core::style::Style *style)
*/
void Textblock::addParbreak (int space, core::style::Style *style)
{
- Word *word, *word2 = NULL; // Latter for compiler happiness, search!
- bool isfirst;
- Widget *widget;
- int lineno;
+ Word *word;
/* A break may not be the first word of a page, or directly after
the bullet/number (which is the first word) in a list item. (See
also comment in Dw_page_size_request.) */
if (words->size () == 0 ||
- (listItem && words->size () == 1)) {
+ (hasListitemValue && words->size () == 1)) {
/* This is a bit hackish: If a break is added as the
first/second word of a page, and the parent widget is also a
- DwPage, and there is a break before -- this is the case when
+ Textblock, and there is a break before -- this is the case when
a widget is used as a text box (lists, blockquotes, list
items etc) -- then we simply adjust the break before, in a
way that the space is in any case visible. */
+ Widget *widget;
- /* Find the widget where to adjust the break_space. */
+ /* Find the widget where to adjust the breakSpace. */
for (widget = this;
widget->getParent() &&
widget->getParent()->instanceOf (Textblock::CLASS_ID);
widget = widget->getParent ()) {
Textblock *textblock2 = (Textblock*)widget->getParent ();
- if (textblock2->listItem)
- isfirst = (textblock2->words->get(1).content.type
- == core::Content::WIDGET
- && textblock2->words->get(1).content.widget == widget);
- else
- isfirst = (textblock2->words->get(0).content.type
- == core::Content::WIDGET
- && textblock2->words->get(0).content.widget == widget);
+ int index = textblock2->hasListitemValue ? 1 : 0;
+ bool isfirst = (textblock2->words->getRef(index)->content.type
+ == core::Content::WIDGET
+ && textblock2->words->getRef(index)->content.widget
+ == widget);
if (!isfirst) {
/* The page we searched for has been found. */
+ Word *word2;
// ABC
- lineno = widget->parentRef >> 3;
+ int lineno = widget->parentRef >> 3;
if (lineno > 0 &&
(word2 =
textblock2->words->getRef(textblock2->lines
- ->get(lineno - 1).firstWord)) &&
+ ->getRef(lineno - 1)->firstWord)) &&
word2->content.type == core::Content::BREAK) {
if (word2->content.breakSpace < space) {
word2->content.breakSpace = space;
@@ -1897,7 +1920,7 @@ void Textblock::addParbreak (int space, core::style::Style *style)
misc::max (word->content.breakSpace, space);
lastLine->breakSpace =
misc::max (word->content.breakSpace,
- lastLine->marginDescent - lastLine->descent,
+ lastLine->marginDescent - lastLine->boxDescent,
lastLine->breakSpace);
return;
}
@@ -1916,7 +1939,7 @@ void Textblock::addLinebreak (core::style::Style *style)
Word *word;
if (words->size () == 0 ||
- words->get(words->size () - 1).content.type == core::Content::BREAK)
+ words->getRef(words->size () - 1)->content.type == core::Content::BREAK)
// An <BR> in an empty line gets the height of the current font
// (why would someone else place it here?), ...
word = addWord (0, style->font->ascent, style->font->descent, style);
@@ -1926,7 +1949,6 @@ void Textblock::addLinebreak (core::style::Style *style)
word->content.type = core::Content::BREAK;
word->content.breakSpace = 0;
- word->style = style;
wordWrap (words->size () - 1);
}
@@ -1949,9 +1971,9 @@ void Textblock::addFloatIntoGenerator (core::Widget *widget, core::style::Style
/**
* \brief Search recursively through widget.
- *
+ *
* This is an optimized version of the general
- * dw::core::Widget::getWidgetAtPoint method.
+ * dw::core::Widget::getWidgetAtPoint method.
*/
core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level)
{
@@ -1973,7 +1995,7 @@ core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level)
line = lines->getRef (lineIndex);
- for (wordIndex = line->firstWord; wordIndex < line->lastWord; wordIndex++) {
+ for (wordIndex = line->firstWord; wordIndex <= line->lastWord;wordIndex++) {
Word *word = words->getRef (wordIndex);
if (word->content.type == core::Content::WIDGET) {
@@ -1996,19 +2018,16 @@ core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level)
*/
void Textblock::handOverBreak (core::style::Style *style)
{
- #if 0
- MISSING
- DwPageLine *last_line;
- DwWidget *parent;
-
- if (page->num_lines == 0)
- return;
+ if (lines->size() > 0) {
+ Widget *parent;
+ Line *lastLine = lines->getRef (lines->size () - 1);
- last_line = &page->lines[page->num_lines - 1];
- if (last_line->break_space != 0 &&
- (parent = DW_WIDGET(page)->parent) && DW_IS_PAGE (parent))
- a_Dw_page_add_parbreak (DW_PAGE (parent), last_line->break_space, style);
-#endif
+ if (lastLine->breakSpace != 0 && (parent = getParent()) &&
+ parent->instanceOf (Textblock::CLASS_ID)) {
+ Textblock *textblock2 = (Textblock*) parent;
+ textblock2->addParbreak(lastLine->breakSpace, style);
+ }
+ }
}
/*
@@ -2039,10 +2058,10 @@ void Textblock::changeLinkColor (int link, int newColor)
for (int lineIndex = 0; lineIndex < lines->size(); lineIndex++) {
bool changed = false;
Line *line = lines->getRef (lineIndex);
- int wordIndex;
+ int wordIdx;
- for (wordIndex = line->firstWord;wordIndex < line->lastWord;wordIndex++){
- Word *word = words->getRef(wordIndex);
+ for (wordIdx = line->firstWord; wordIdx <= line->lastWord; wordIdx++){
+ Word *word = words->getRef(wordIdx);
if (word->style->x_link == link) {
core::style::StyleAttrs styleAttrs;
@@ -2051,14 +2070,14 @@ void Textblock::changeLinkColor (int link, int newColor)
case core::Content::TEXT:
{ core::style::Style *old_style = word->style;
styleAttrs = *old_style;
- styleAttrs.color = core::style::Color::createSimple (layout,
- newColor);
+ styleAttrs.color = core::style::Color::create (layout,
+ newColor);
word->style = core::style::Style::create (layout, &styleAttrs);
old_style->unref();
old_style = word->spaceStyle;
styleAttrs = *old_style;
- styleAttrs.color = core::style::Color::createSimple (layout,
- newColor);
+ styleAttrs.color = core::style::Color::create (layout,
+ newColor);
word->spaceStyle =
core::style::Style::create(layout, &styleAttrs);
old_style->unref();
@@ -2067,10 +2086,10 @@ void Textblock::changeLinkColor (int link, int newColor)
case core::Content::WIDGET:
{ core::Widget *widget = word->content.widget;
styleAttrs = *widget->getStyle();
- styleAttrs.color = core::style::Color::createSimple (layout,
- newColor);
+ styleAttrs.color = core::style::Color::create (layout,
+ newColor);
styleAttrs.setBorderColor(
- core::style::Color::createShaded(layout, newColor));
+ core::style::Color::create (layout, newColor));
widget->setStyle(
core::style::Style::create (layout, &styleAttrs));
break;
@@ -2083,7 +2102,7 @@ void Textblock::changeLinkColor (int link, int newColor)
}
if (changed)
queueDrawArea (0, lineYOffsetWidget(line), allocation.width,
- line->ascent + line->descent);
+ line->boxAscent + line->boxDescent);
}
}
@@ -2325,7 +2344,7 @@ Textblock::TextblockIterator::TextblockIterator (Textblock *textblock,
else if (index >= textblock->words->size ())
content.type = core::Content::END;
else
- content = textblock->words->get(index).content;
+ content = textblock->words->getRef(index)->content;
}
object::Object *Textblock::TextblockIterator::clone()
@@ -2337,23 +2356,23 @@ int Textblock::TextblockIterator::compareTo(misc::Comparable *other)
{
return index - ((TextblockIterator*)other)->index;
}
-
+
bool Textblock::TextblockIterator::next ()
{
Textblock *textblock = (Textblock*)getWidget();
if (content.type == core::Content::END)
return false;
-
+
do {
index++;
if (index >= textblock->words->size ()) {
content.type = core::Content::END;
return false;
}
- } while ((textblock->words->get(index).content.type & getMask()) == 0);
+ } while ((textblock->words->getRef(index)->content.type & getMask()) == 0);
- content = textblock->words->get(index).content;
+ content = textblock->words->getRef(index)->content;
return true;
}
@@ -2363,16 +2382,16 @@ bool Textblock::TextblockIterator::prev ()
if (content.type == core::Content::START)
return false;
-
+
do {
index--;
if (index < 0) {
content.type = core::Content::START;
return false;
}
- } while ((textblock->words->get(index).content.type & getMask()) == 0);
+ } while ((textblock->words->getRef(index)->content.type & getMask()) == 0);
- content = textblock->words->get(index).content;
+ content = textblock->words->getRef(index)->content;
return true;
}
@@ -2440,16 +2459,19 @@ void Textblock::queueDrawRange (int index1, int index2)
to = misc::min (to, words->size () - 1);
to = misc::max (to, 0);
- int line1 = findLineOfWord (from);
- int line2 = findLineOfWord (to);
+ int line1idx = findLineOfWord (from);
+ int line2idx = findLineOfWord (to);
+
+ if (line1idx >= 0 && line2idx >= 0) {
+ Line *line1 = lines->getRef (line1idx),
+ *line2 = lines->getRef (line2idx);
+ int y = lineYOffsetWidget (line1) + line1->boxAscent -
+ line1->contentAscent;
+ int h = lineYOffsetWidget (line2) + line2->boxAscent +
+ line2->contentDescent - y;
- queueDrawArea (0,
- lineYOffsetWidgetI (line1),
- allocation.width,
- lineYOffsetWidgetI (line2)
- - lineYOffsetWidgetI (line1)
- + lines->getRef (line2)->ascent
- + lines->getRef (line2)->descent);
+ queueDrawArea (0, y, allocation.width, h);
+ }
}
void Textblock::TextblockIterator::getAllocation (int start, int end,
@@ -2462,13 +2484,31 @@ void Textblock::TextblockIterator::getAllocation (int start, int end,
allocation->x =
textblock->allocation.x + textblock->lineXOffsetWidget (line);
- for (int i = line->firstWord; i < index; i++)
- allocation->x += textblock->words->getRef(i)->size.width;
- allocation->y =
- textblock->allocation.y
- + textblock->lineYOffsetWidget (line) + line->ascent - word->size.ascent;
+ for (int i = line->firstWord; i < index; i++) {
+ Word *w = textblock->words->getRef(i);
+ allocation->x += w->size.width + w->effSpace;
+ }
+ if (start > 0 && word->content.type == core::Content::TEXT) {
+ allocation->x += textblock->layout->textWidth (word->style->font,
+ word->content.text,
+ start);
+ }
+ allocation->y = textblock->lineYOffsetCanvas (line) + line->boxAscent -
+ word->size.ascent;
+
allocation->width = word->size.width;
+ if (word->content.type == core::Content::TEXT) {
+ int wordEnd = strlen(word->content.text);
+
+ if (start > 0 || end < wordEnd) {
+ end = misc::min(end, wordEnd); /* end could be INT_MAX */
+ allocation->width =
+ textblock->layout->textWidth (word->style->font,
+ word->content.text + start,
+ end - start);
+ }
+ }
allocation->ascent = word->size.ascent;
allocation->descent = word->size.descent;
}
diff --git a/dw/textblock.hh b/dw/textblock.hh
index 80e16393..15f81eb1 100644
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -6,8 +6,6 @@
namespace dw {
-using namespace lout;
-
/**
* \brief A Widget for rendering text blocks, i.e. paragraphs or sequences
* of paragraphs.
@@ -16,118 +14,118 @@ using namespace lout;
* floats have been implementet. Will be updated and extended soon.
*
* <h3>Signals</h3>
- *
+ *
* dw::Textblock uses the signals defined in
- * dw::core::Widget::LinkReceiver, related to links. The coordinates are
+ * dw::core::Layout::LinkReceiver, related to links. The coordinates are
* always -1.
- *
- *
+ *
+ *
* <h3>Collapsing Spaces</h3>
- *
+ *
* The idea behind this is that every paragraph has a specific vertical
* space around and that they are combined to one space, according to
* rules stated below. A paragraph consists either of the lines between
* two paragraph breaks within a dw::Textblock, or of a dw::Textblock
* within a dw::Textblock, in a single line; the latter is used for
* indented boxes and list items.
- *
+ *
* The rules:
- *
+ *
* <ol>
* <li> If a paragraph is following by another, the space between them is the
* maximum of both box spaces:
- *
+ *
* \image html dw-textblock-collapsing-spaces-1-1.png
- *
+ *
* are combined like this:
- *
+ *
* \image html dw-textblock-collapsing-spaces-1-2.png
- *
+ *
* <li> a) If one paragraph is the first paragraph within another, the upper
* space of these paragraphs collapse. b) The analogue is the case for the
* last box:
- *
+ *
* \image html dw-textblock-collapsing-spaces-2-1.png
- *
+ *
* If B and C are put into A, the result is:
- *
+ *
* \image html dw-textblock-collapsing-spaces-2-2.png
* </ol>
- *
+ *
* For achieving this, there are some features of dw::Textblock:
- *
+ *
* <ul>
* <li> Consequent breaks are automatically combined, according to
* rule 1. See the code of dw::Textblock::addParBreak for details.
- *
+ *
* <li> If a break is added as the first word of the dw::Textblock within
* another dw::Textblock, collapsing according to rule 2a is done
* automatically. See the code of dw::Textblock::addParBreak.
- *
+ *
* <li> To collapse spaces according to rule 2b,
* dw::Textblock::addParBreak::handOverBreak must be called for
* the \em inner widget. The HTML parser does this in
* Html_eventually_pop_dw.
* </ul>
- *
- *
+ *
+ *
* <h3>Collapsing Margins</h3>
- *
+ *
* Collapsing margins, as defined in the CSS2 specification, are,
* supported in addition to collapsing spaces. Also, spaces and margins
* collapse themselves. I.e., the space between two paragraphs is the
* maximum of the space calculated as described in "Collapsing Spaces"
* and the space calculated according to the rules for collapsing margins.
- *
+ *
* (This is an intermediate hybrid state, collapsing spaces are used in
* the current version of dillo, while I implemented collapsing margins
* for the CSS prototype and integrated it already into the main trunk. For
* a pure CSS-based dillo, collapsing spaces will not be needed anymore, and
* may be removed for simplicity.)
- *
- *
+ *
+ *
* <h3>Some Internals</h3>
- *
- * There are two lists, dw::Textblock::words and
- * dw::Textblock::lines. The word list is quite static; only new words
- * may be added. A word is either text, a widget, a break or an
- * anchor. Anchors are stored in the text, because it may be necessary to
- * correct the scroller positions at rewrapping.
- *
- * Lines refer to the word list (first and last), they are completely
+ *
+ * There are 3 lists, dw::Textblock::words, dw::Textblock::lines, and
+ * dw::Textblock::anchors. The word list is quite static; only new words
+ * may be added. A word is either text, a widget, or a break.
+ *
+ * Lines refer to the word list (first and last). They are completely
* redundant, i.e., they can be rebuilt from the words. Lines can be
* rewrapped either completely or partially (see "Incremental Resizing"
* below). For the latter purpose, several values are accumulated in the
* lines. See dw::Textblock::Line for details.
- *
- *
+ *
+ * Anchors associate the anchor name with the index of the next word at
+ * the point of the anchor.
+ *
* <h4>Incremental Resizing</h4>
- *
+ *
* dw::Textblock makes use of incremental resizing as described in \ref
* dw-widget-sizes. The parentRef is, for children of a dw::Textblock, simply
* the number of the line.
- *
+ *
* Generally, there are three cases which may change the size of the
* widget:
- *
+ *
* <ul>
* <li> The available size of the widget has changed, e.g., because the
* user has changed the size of the browser window. In this case,
* it is necessary to rewrap all the lines.
- *
+ *
* <li> A child widget has changed its size. In this case, only a rewrap
* down from the line where this widget is located is necessary.
- *
+ *
* (This case is very important for tables. Tables are quite at the
* bottom, so that a partial rewrap is relevant. Otherwise, tables
* change their size quite often, so that this is necessary for a
* fast, non-blocking rendering)
- *
+ *
* <li> A word (or widget, break etc.) is added to the text block. This
* makes it possible to reuse the old size by simply adjusting the
* current width and height, so no rewrapping is necessary.
* </ul>
- *
+ *
* The state of the size calculation is stored in wrapRef within
* dw::Textblock, which has the value -1 if no rewrapping of lines
* necessary, or otherwise the line from which a rewrap is necessary.
@@ -141,7 +139,7 @@ private:
class FloatSide
{
protected:
- class Float: public object::Object
+ class Float: public lout::object::Object
{
public:
Textblock *floatGenerator;
@@ -150,8 +148,8 @@ private:
};
Textblock *floatContainer;
- container::typed::Vector<Float> *floats;
- container::typed::HashTable<object::TypedPointer<dw::core::Widget>, Float> *floatsByWidget;
+ lout::container::typed::Vector<Float> *floats;
+ lout::container::typed::HashTable<lout::object::TypedPointer<dw::core::Widget>, Float> *floatsByWidget;
Float *findFloat(int y);
@@ -198,13 +196,13 @@ private:
protected:
struct Line
{
- int firstWord; /* first-word's position in DwPageWord [0 based] */
- int lastWord; /* last-word's position in DwPageWord [1 based] */
+ int firstWord; /* first word's index in word vector */
+ int lastWord; /* last word's index in word vector */
/* "top" is always relative to the top of the first line, i.e.
* page->lines[0].top is always 0. */
- int top, ascent, descent, breakSpace;
- int leftOffset; /* nonzero for centered and rightly-aligned text */
+ int top, boxAscent, boxDescent, contentAscent, contentDescent,
+ breakSpace, leftOffset;
int boxLeft, boxRight;
/* This is similar to descent, but includes the bottom margins of the
@@ -229,9 +227,9 @@ protected:
/* TODO: perhaps add a xLeft? */
core::Requisition size;
/* Space after the word, only if it's not a break: */
- unsigned short origSpace; /* from font, set by addSpace */
- unsigned short effSpace; /* effective space, set by wordWrap,
- * used for drawing etc. */
+ short origSpace; /* from font, set by addSpace */
+ short effSpace; /* effective space, set by wordWrap,
+ * used for drawing etc. */
core::Content content;
core::style::Style *style;
@@ -239,6 +237,12 @@ protected:
later set by a_Dw_page_add_space */
};
+ struct Anchor
+ {
+ char *name;
+ int wordIndex;
+ };
+
class TextblockIterator: public core::Iterator
{
private:
@@ -250,8 +254,8 @@ protected:
TextblockIterator (Textblock *textblock, core::Content::Type mask,
int index);
- object::Object *clone();
- int compareTo(misc::Comparable *other);
+ lout::object::Object *clone();
+ int compareTo(lout::misc::Comparable *other);
bool next ();
bool prev ();
@@ -263,7 +267,7 @@ protected:
friend class TextblockIterator;
/* These fields provide some ad-hoc-functionality, used by sub-classes. */
- bool listItem; /* If true, the first word of the page is treated
+ bool hasListitemValue; /* If true, the first word of the page is treated
specially (search in source). */
int innerPadding; /* This is an additional padding on the left side
(used by ListItem). */
@@ -304,17 +308,13 @@ protected:
int lastLineParMax;
int wrapRef; /* [0 based] */
- misc::SimpleVector <Line> *lines;
- misc::SimpleVector <Word> *words;
+ lout::misc::SimpleVector <Line> *lines;
+ lout::misc::SimpleVector <Word> *words;
+ lout::misc::SimpleVector <Anchor> *anchors;
struct {int index, nChar;}
hlStart[core::HIGHLIGHT_NUM_LAYERS], hlEnd[core::HIGHLIGHT_NUM_LAYERS];
- /* The word index of the link under a button press, and the char
- * position */
- int linkPressedIndex;
- int link_pressedCharPos;
-
int hoverLink; /* The link under the button. */
core::style::Tooltip *hoverTooltip; /* The tooltip under the button. No ref
* hold. */
@@ -324,17 +324,24 @@ protected:
void getWordExtremes (Word *word, core::Extremes *extremes);
void markChange (int ref);
void justifyLine (Line *line, int availWidth);
- void addLine (int wordInd, bool newPar);
+ Line *addLine (int wordInd, bool newPar);
void calcWidgetSize (core::Widget *widget, core::Requisition *size);
void rewrap ();
+ void decorateText(core::View *view, core::style::Style *style,
+ core::style::Color::Shading shading,
+ int x, int yBase, int width);
+ void drawText(int wordIndex, core::View *view, core::Rectangle *area,
+ int xWidget, int yWidgetBase);
+ void drawSpace(int wordIndex, core::View *view, core::Rectangle *area,
+ int xWidget, int yWidgetBase);
void drawLine (Line *line, core::View *view, core::Rectangle *area);
int findLineIndex (int y);
int findLineOfWord (int wordIndex);
- int findWord (int x, int y);
+ Word *findWord (int x, int y, bool *inSpace);
Word *addWord (int width, int ascent, int descent,
core::style::Style *style);
- void calcTextSize (const char *text, core::style::Style *style,
+ void calcTextSize (const char *text, size_t len, core::style::Style *style,
core::Requisition *size);
void addFloatIntoContainer(core::Widget *widget, Textblock *floatGenerator);
@@ -355,7 +362,7 @@ protected:
*/
inline int lineXOffsetContents (Line *line)
{
- return innerPadding + line->leftOffset + line->boxLeft +
+ return innerPadding + line->leftOffset + line->boxLeft +
(line == lines->getRef (0) ? line1OffsetEff : 0);
}
@@ -371,7 +378,7 @@ protected:
inline int lineYOffsetWidgetAllocation (Line *line,
core::Allocation *allocation)
{
- return line->top + (allocation->ascent - lines->getRef(0)->ascent);
+ return line->top + (allocation->ascent - lines->getRef(0)->boxAscent);
}
inline int lineYOffsetWidget (Line *line)
@@ -400,7 +407,7 @@ protected:
{
return lineYOffsetWidget (lines->getRef (lineIndex));
}
-
+
inline int lineYOffsetCanvasI (int lineIndex)
{
return lineYOffsetCanvas (lines->getRef (lineIndex));
@@ -423,7 +430,7 @@ protected:
void setWidth (int width);
void setAscent (int ascent);
void setDescent (int descent);
- void draw (core::View *view, core::Rectangle *area);
+ void draw (core::View *view, core::Rectangle *area);
bool buttonPressImpl (core::EventButton *event);
bool buttonReleaseImpl (core::EventButton *event);
@@ -439,11 +446,15 @@ public:
Textblock(bool limitTextWidth);
~Textblock();
- core::Iterator *iterator (core::Content::Type mask, bool atEnd);
+ core::Iterator *iterator (core::Content::Type mask, bool atEnd);
void flush ();
- void addText (const char *text, core::style::Style *style);
+ void addText (const char *text, size_t len, core::style::Style *style);
+ inline void addText (const char *text, core::style::Style *style)
+ {
+ addText (text, strlen(text), style);
+ }
void addWidget (core::Widget *widget, core::style::Style *style);
bool addAnchor (const char *name, core::style::Style *style);
void addSpace(core::style::Style *style);
diff --git a/dw/types.cc b/dw/types.cc
index 94f95b42..672ec7f6 100644
--- a/dw/types.cc
+++ b/dw/types.cc
@@ -1,3 +1,7 @@
+// Rectangle::intersectsWith() has code that was derived from gdkrectangle.c.
+// gdkrectangle.c bears the notice that GDK, the GIMP Drawing Kit, is
+// "Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald".
+
/*
* Dillo Widget
*
@@ -14,13 +18,15 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core.hh"
+#include "../lout/msg.h"
+
+using namespace lout;
namespace dw {
namespace core {
@@ -33,12 +39,20 @@ Rectangle::Rectangle (int x, int y, int width, int height)
this->height = height;
}
+/*
+ * Draw rectangle in view relative to point (x,y).
+ */
+void Rectangle::draw (core::View *view, core::style::Style *style, int x,int y)
+{
+ const bool filled = false;
+
+ view->drawRectangle(style->color, core::style::Color::SHADING_NORMAL,filled,
+ x + this->x, y + this->y, this->width, this->height);
+}
+
/**
* Return whether this rectangle and otherRect intersect. If yes,
* return the intersection rectangle in dest.
- *
- * \todo The function has been copied from gdktrectangle.c. Is this relevant
- * for copyright?
*/
bool Rectangle::intersectsWith (Rectangle *otherRect, Rectangle *dest)
{
@@ -121,6 +135,18 @@ Circle::Circle (int x, int y, int radius)
this->radius = radius;
}
+/*
+ * Draw circle in view relative to point (x,y).
+ */
+void Circle::draw (core::View *view, core::style::Style *style, int x, int y)
+{
+ const bool filled = false;
+
+ view->drawArc(style->color, core::style::Color::SHADING_NORMAL, filled,
+ x + this->x, y + this->y, 2 * this->radius, 2 * this->radius,
+ 0, 360);
+}
+
bool Circle::isPointWithin (int x, int y)
{
return
@@ -142,6 +168,27 @@ Polygon::~Polygon ()
delete points;
}
+/*
+ * Draw polygon in view relative to point (x,y).
+ */
+void Polygon::draw (core::View *view, core::style::Style *style, int x, int y)
+{
+ if (points->size()) {
+ int i;
+ const bool filled = false;
+ int (*pointArray)[2] =
+ (int (*)[2]) malloc(points->size() * sizeof(*pointArray));
+
+ for (i = 0; i < points->size(); i++) {
+ pointArray[i][0] = x + points->getRef(i)->x;
+ pointArray[i][1] = y + points->getRef(i)->y;
+ }
+ view->drawPolygon(style->color, core::style::Color::SHADING_NORMAL,
+ filled, pointArray, i);
+ free(pointArray);
+ }
+}
+
void Polygon::addPoint (int x, int y)
{
points->increase ();
@@ -180,8 +227,8 @@ bool Polygon::linesCross(int ax1, int ay1, int ax2, int ay2,
bool cross =
linesCross0 (ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) &&
linesCross0 (bx1, by1, bx2, by2, ax1, ay1, ax2, ay2);
- //printf ("(%d, %d) - (%d, %d) and (%d, %d) - (%d, %d) cross? %s.\n",
- // ax1, ay1, ax2, ay2, bx1, by1, bx2, by2, cross ? "Yes" : "No");
+ _MSG("(%d, %d) - (%d, %d) and (%d, %d) - (%d, %d) cross? %s.\n",
+ ax1, ay1, ax2, ay2, bx1, by1, bx2, by2, cross ? "Yes" : "No");
return cross;
}
@@ -248,7 +295,7 @@ void Region::addRectangle (Rectangle *rPointer)
r->y = misc::min(r->y, ownRect->y);
r->width = combinedWidth;
r->height = combinedHeight;
-
+
rectangleList->removeRef (ownRect);
}
}
diff --git a/dw/types.hh b/dw/types.hh
index cd35e1f6..420a500f 100644
--- a/dw/types.hh
+++ b/dw/types.hh
@@ -8,7 +8,9 @@
namespace dw {
namespace core {
-using namespace lout;
+namespace style {
+ class Style;
+}
enum HPosition
{
@@ -30,6 +32,8 @@ enum VPosition
VPOS_NO_CHANGE
};
+enum ScrollCommand {SCREEN_UP_CMD, SCREEN_DOWN_CMD, LINE_UP_CMD, LINE_DOWN_CMD,
+ LEFT_CMD, RIGHT_CMD, TOP_CMD, BOTTOM_CMD};
/*
* Different "layers" may be highlighted in a widget.
@@ -50,10 +54,12 @@ struct Point
/**
* \brief Abstract interface for different shapes.
*/
-class Shape: public object::Object
+class Shape: public lout::object::Object
{
public:
virtual bool isPointWithin (int x, int y) = 0;
+ virtual void draw (core::View *view, core::style::Style *style, int x,
+ int y) = 0;
};
/**
@@ -70,6 +76,7 @@ public:
inline Rectangle () { }
Rectangle (int x, int y, int width, int height);
+ void draw (core::View *view, core::style::Style *style, int x, int y);
bool intersectsWith (Rectangle *otherRect, Rectangle *dest);
bool isSubsetOf (Rectangle *otherRect);
bool isPointWithin (int x, int y);
@@ -86,6 +93,7 @@ public:
Circle (int x, int y, int radius);
+ void draw (core::View *view, core::style::Style *style, int x, int y);
bool isPointWithin (int x, int y);
};
@@ -95,12 +103,12 @@ public:
class Polygon: public Shape
{
private:
- misc::SimpleVector<Point> *points;
+ lout::misc::SimpleVector<Point> *points;
int minx, miny, maxx, maxy;
/**
* \brief Return the z-coordinate of the vector product of two
- * vectors, whose z-coordinate is 0 (so that x and y of
+ * vectors, whose z-coordinate is 0 (so that x and y of
* the vector product is 0, too).
*/
inline int zOfVectorProduct(int x1, int y1, int x2, int y2) {
@@ -116,6 +124,7 @@ public:
Polygon ();
~Polygon ();
+ void draw (core::View *view, core::style::Style *style, int x, int y);
void addPoint (int x, int y);
bool isPointWithin (int x, int y);
};
@@ -130,8 +139,8 @@ public:
class Region
{
private:
- container::typed::List <Rectangle> *rectangleList;
-
+ lout::container::typed::List <Rectangle> *rectangleList;
+
public:
Region ();
~Region ();
@@ -140,7 +149,7 @@ public:
void addRectangle (Rectangle *r);
- container::typed::Iterator <Rectangle> rectangles ()
+ lout::container::typed::Iterator <Rectangle> rectangles ()
{
return rectangleList->iterator ();
};
@@ -179,22 +188,20 @@ struct Content
END = 1 << 1,
TEXT = 1 << 2,
WIDGET = 1 << 3,
- ANCHOR = 1 << 4,
- BREAK = 1 << 5,
+ BREAK = 1 << 4,
FLOAT_REF = 1 << 6, /** \todo A bit ugly. */
ALL = 0xff,
REAL_CONTENT = 0xff ^ (START | END | FLOAT_REF),
SELECTION_CONTENT = TEXT | WIDGET | BREAK
};
/* Content is embedded in struct Word therefore we
- * try to be space efficient.
+ * try to be space efficient.
*/
short type;
bool space;
union {
const char *text;
Widget *widget;
- char *anchor;
int breakSpace;
};
};
diff --git a/dw/ui.cc b/dw/ui.cc
index f857e387..058dfde8 100644
--- a/dw/ui.cc
+++ b/dw/ui.cc
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -28,7 +27,8 @@ namespace dw {
namespace core {
namespace ui {
-using namespace object;
+using namespace lout;
+using namespace lout::object;
int Embed::CLASS_ID = -1;
@@ -62,11 +62,26 @@ void Embed::sizeAllocateImpl (Allocation *allocation)
void Embed::enterNotifyImpl (core::EventCrossing *event)
{
resource->emitEnter();
+ Widget::enterNotifyImpl(event);
}
void Embed::leaveNotifyImpl (core::EventCrossing *event)
{
resource->emitLeave();
+ Widget::leaveNotifyImpl(event);
+}
+
+bool Embed::buttonPressImpl (core::EventButton *event)
+{
+ bool handled;
+
+ if (event->button == 3) {
+ resource->emitClicked(event);
+ handled = true;
+ } else {
+ handled = false;
+ }
+ return handled;
}
void Embed::setWidth (int width)
@@ -84,6 +99,16 @@ void Embed::setDescent (int descent)
resource->setDescent (descent);
}
+void Embed::setDisplayed (bool displayed)
+{
+ resource->setDisplayed (displayed);
+}
+
+void Embed::setEnabled (bool enabled)
+{
+ resource->setEnabled (enabled);
+}
+
void Embed::draw (View *view, Rectangle *area)
{
drawWidgetBox (view, area, false);
@@ -183,6 +208,10 @@ void Resource::setDescent (int descent)
{
}
+void Resource::setDisplayed (bool displayed)
+{
+}
+
void Resource::draw (View *view, Rectangle *area)
{
}
@@ -201,31 +230,23 @@ void Resource::emitLeave ()
activateEmitter.emitLeave(this);
}
-// ----------------------------------------------------------------------
-
-bool ButtonResource::ClickedEmitter::emitToReceiver (lout::signal::Receiver
- *receiver,
- int signalNo,
- int argc,
- Object **argv)
+bool Resource::ClickedEmitter::emitToReceiver(lout::signal::Receiver *receiver,
+ int signalNo, int argc,
+ Object **argv)
{
((ClickedReceiver*)receiver)
- ->clicked ((ButtonResource*)((Pointer*)argv[0])->getValue (),
- ((Integer*)argv[1])->getValue (),
- ((Integer*)argv[2])->getValue (),
- ((Integer*)argv[3])->getValue ());
+ ->clicked ((Resource*)((Pointer*)argv[0])->getValue (),
+ (EventButton*)((Pointer*)argv[1])->getValue());
return false;
}
-void ButtonResource::ClickedEmitter::emitClicked (ButtonResource *resource,
- int buttonNo, int x, int y)
+void Resource::ClickedEmitter::emitClicked (Resource *resource,
+ EventButton *event)
{
- Integer i1 (buttonNo);
- Integer i2 (x);
- Integer i3 (y);
- Pointer p (resource);
- Object *argv[4] = { &p, &i1, &i2, &i3 };
- emitVoid (0, 4, argv);
+ Pointer p1 (resource);
+ Pointer p2 (event);
+ Object *argv[2] = { &p1, &p2 };
+ emitVoid (0, 2, argv);
}
// ----------------------------------------------------------------------
diff --git a/dw/ui.hh b/dw/ui.hh
index de3e1b2b..02aab093 100644
--- a/dw/ui.hh
+++ b/dw/ui.hh
@@ -14,24 +14,24 @@ namespace core {
* UI resources are another abstraction for Dw widgets, which are not
* fully implemented in a platform-independent way. Typically, they
* involve creating widgets, which the underlying UI toolkit provides.
- *
+ *
* As you see in this diagram:
- *
+ *
* \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_core {
* style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
* label="dw::core";
- *
+ *
* subgraph cluster_ui {
* style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
* label="dw::core::ui";
- *
+ *
* Embed [URL="\ref dw::core::ui::Embed"];
* Resource [color="#a0a0a0", URL="\ref dw::core::ui::Resource"];
* LabelButtonResource [color="#a0a0a0",
@@ -40,19 +40,19 @@ namespace core {
* URL="\ref dw::core::ui::EntryResource"];
* etc [color="#a0a0a0", label="..."];
* }
- *
+ *
* Widget [URL="\ref dw::core::Widget", color="#a0a0a0"];
* }
- *
+ *
* subgraph cluster_fltk {
* style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
* label="dw::fltk::ui";
- *
+ *
* FltkLabelButtonResource
* [URL="\ref dw::fltk::ui::FltkLabelButtonResource"];
* FltkEntryResource [URL="\ref dw::fltk::ui::FltkEntryResource"];
* }
- *
+ *
* Widget -> Embed;
* Embed -> Resource [arrowhead="open", arrowtail="none",
* headlabel="1", taillabel="1"];
@@ -63,16 +63,16 @@ namespace core {
* EntryResource -> FltkEntryResource;
* }
* \enddot
- *
+ *
* <center>[\ref uml-legend "legend"]</center>
- *
+ *
* there are several levels:
- *
+ *
* <ol>
* <li> The Dw widget is dw::core::ui::Embed. It delegates most to
* dw::core::ui::Resource, which has similar methods like
* dw::core::Widget.
- *
+ *
* <li> There are several sub interfaces of dw::core::ui::Resource, which
* may provide methods, as e.g. dw::core::ui::ListResource::addItem. In a
* platform independent context, you can cast the result of
@@ -80,54 +80,54 @@ namespace core {
* know, which one is used. E.g., if you know, that a given instance
* dw::core::ui::Embed refers to a dw::core::ui::ListResource, you can
* write something like:
- *
+ *
* \code
* dw::core::ui::Embed *embed;
* //...
* ((dw::core::ui::ListResource*)embed->getResource ())->addItem ("Hello!");
* \endcode
- *
+ *
* <li> These sub classes are then fully implemented in a platform specific
* way. For an example, look at dw::fltk::ui.
* </ol>
- *
+ *
* There is a factory interface, dw::core::ui::ResourceFactory, which
* provides methods for creating common resources. By calling
* dw::core::Layout::getResourceFactory, which calls
* dw::core::Platform::getResourceFactory, you get the factory for the used
* platform.
- *
+ *
* It is possible to define additional sub classes of
* dw::core::ui::Resource, but since they are not provided by
* dw::core::ui::ResourceFactory, you have to define some other
* abstractions, if you want to remain platform independent.
- *
- *
+ *
+ *
* <h3>...</h3>
- *
- *
+ *
+ *
* <h3>Resouces needed for HTML</h3>
- *
+ *
* This chapter describes, how the form controls defined by HTML are
* implemented in Dw. Some of them do not refer to UI resources, but to
* other widgets, links to the respective documentations are provided
* here.
- *
+ *
* <h4>Resouces created with \<INPUT\></h4>
- *
+ *
* The HTML \<INPUT\> is always implemented by using UI
* resources. \<INPUT\> element has the following attributes:
- *
+ *
* <table>
* <tr><th>Attribute <th>Implementation
- * <tr><td>type <td>This defines the resource you have to instanciate.
+ * <tr><td>type <td>This defines the resource you have to instantiate.
* <tr><td>name <td>Not needed within Dw.
* <tr><td>value <td>The initial value is treated differently by different
* resources.
* <tr><td>checked <td>Parameter to
* dw::core::ui::ResourceFactory::createCheckButtonResource
* and dw::core::ui::ResourceFactory::createRadioButtonResource.
- * <tr><td>disabled <td>This is provided for all resources by
+ * <tr><td>disabled <td>This is provided for all resources by
* dw::core::ui::Resource::setEnabled.
* <tr><td>readonly <td>This is provided by
* dw::core::ui::TextResource::setEditable.
@@ -146,10 +146,10 @@ namespace core {
* <tr><td>onchange <td>Not supported currently.
* <tr><td>accept <td>Not supported currently.
* </table>
- *
+ *
* For the different values of \em type, the following resources can be
* used:
- *
+ *
* <table>
* <tr><th>Type <th>Resource
* <th>Factory Method
@@ -175,35 +175,35 @@ namespace core {
* <tr><td>file <td>Not supported currently.
* <td>-
* </table>
- *
+ *
* <h4>\<SELECT\>, \<OPTGROUP\>, and \<OPTION\></h4>
- *
+ *
* \<SELECT\> is implemented either by dw::core::ui::OptionMenuResource
* (better suitable for \em size = 1 and single selection) or
* dw::core::ui::ListResource, which have a common base,
* dw::core::ui::SelectionResource. In the latter case, \em size must be
* specified via dw::core::style::Style.
- *
+ *
* Factory methods are dw::core::ui::ResourceFactory::createListResource and
* dw::core::ui::ResourceFactory::createOptionMenuResource.
- *
+ *
* \<OPTION\>'s are added via dw::core::ui::SelectionResource::addItem.
- *
+ *
* \<OPTGROUP\> are created by using dw::core::ui::SelectionResource::pushGroup
* and dw::core::ui::SelectionResource::popGroup.
- *
+ *
* For lists, the selection mode must be set in
* dw::core::ui::ResourceFactory::createListResource.
- *
+ *
* <h4>\<TEXTAREA\></h4>
- *
+ *
* \<TEXTAREA\> is implemented by dw::core::ui::MultiLineTextResource,
* the factory method is
* dw::core::ui::ResourceFactory::createMultiLineTextResource.
* dw::core::ui::TextResource::setEditable can be used, as for entries.
- *
+ *
* <h4>\<BUTTON\></h4>
- *
+ *
* For handling \<BUTTON\>, dw::core::ui::ComplexButtonResource should be used,
* with a dw::Textblock inside, and relief = true. The contents of \<BUTTON\>
* is then added to the dw::Textblock.
@@ -232,6 +232,7 @@ protected:
void sizeAllocateImpl (Allocation *allocation);
void enterNotifyImpl (core::EventCrossing *event);
void leaveNotifyImpl (core::EventCrossing *event);
+ bool buttonPressImpl (core::EventButton *event);
public:
static int CLASS_ID;
@@ -242,6 +243,8 @@ public:
void setWidth (int width);
void setAscent (int ascent);
void setDescent (int descent);
+ void setDisplayed (bool displayed);
+ void setEnabled (bool enabled);
void draw (View *view, Rectangle *area);
Iterator *iterator (Content::Type mask, bool atEnd);
void setStyle (style::Style *style);
@@ -271,6 +274,14 @@ public:
virtual void enter (Resource *resource) = 0;
virtual void leave (Resource *resource) = 0;
};
+ /**
+ * \brief Receiver interface for the "clicked" signal.
+ */
+ class ClickedReceiver: public lout::signal::Receiver
+ {
+ public:
+ virtual void clicked (Resource *resource, EventButton *event) = 0;
+ };
private:
class ActivateEmitter: public lout::signal::Emitter
@@ -286,8 +297,20 @@ private:
void emitLeave (Resource *resource);
};
+ class ClickedEmitter: public lout::signal::Emitter
+ {
+ protected:
+ bool emitToReceiver (lout::signal::Receiver *receiver, int signalNo,
+ int argc, Object **argv);
+ public:
+ inline void connectClicked (ClickedReceiver *receiver) {
+ connect (receiver); }
+ void emitClicked (Resource *resource, EventButton *event);
+ };
+
Embed *embed;
ActivateEmitter activateEmitter;
+ ClickedEmitter clickedEmitter;
void emitEnter ();
void emitLeave ();
@@ -301,10 +324,12 @@ protected:
inline void emitActivate () {
return activateEmitter.emitActivate (this); }
+ inline void emitClicked (EventButton *event) {
+ clickedEmitter.emitClicked (this, event); }
public:
inline Resource () { embed = NULL; }
-
+
virtual ~Resource ();
virtual void sizeRequest (Requisition *requisition) = 0;
@@ -313,8 +338,9 @@ public:
virtual void setWidth (int width);
virtual void setAscent (int ascent);
virtual void setDescent (int descent);
+ virtual void setDisplayed (bool displayed);
virtual void draw (View *view, Rectangle *area);
- virtual Iterator *iterator (Content::Type mask, bool atEnd) = 0;
+ virtual Iterator *iterator (Content::Type mask, bool atEnd) = 0;
virtual void setStyle (style::Style *style);
virtual bool isEnabled () = 0;
@@ -322,44 +348,13 @@ public:
inline void connectActivate (ActivateReceiver *receiver) {
activateEmitter.connectActivate (receiver); }
+ inline void connectClicked (ClickedReceiver *receiver) {
+ clickedEmitter.connectClicked (receiver); }
};
class ButtonResource: public Resource
-{
-public:
- /**
- * \brief Receiver interface for the "clicked" signal.
- */
- class ClickedReceiver: public lout::signal::Receiver
- {
- public:
- virtual void clicked (ButtonResource *resource, int buttonNo, int x,
- int y) = 0;
- };
-
-private:
- class ClickedEmitter: public lout::signal::Emitter
- {
- protected:
- bool emitToReceiver (lout::signal::Receiver *receiver, int signalNo,
- int argc, Object **argv);
- public:
- inline void connectClicked (ClickedReceiver *receiver) {
- connect (receiver); }
- void emitClicked (ButtonResource *resource, int buttonNo, int x, int y);
- };
-
- ClickedEmitter clickedEmitter;
-
-protected:
- inline void emitClicked (int buttonNo, int x, int y) {
- return clickedEmitter.emitClicked (this, buttonNo, x, y); }
-
-public:
- inline void connectClicked (ClickedReceiver *receiver) {
- clickedEmitter.connectClicked (receiver); }
-};
+{};
/**
* \brief Interface for labelled buttons resources.
@@ -367,7 +362,7 @@ public:
class LabelButtonResource: public ButtonResource
{
public:
- Iterator *iterator (Content::Type mask, bool atEnd);
+ Iterator *iterator (Content::Type mask, bool atEnd);
virtual const char *getLabel () = 0;
virtual void setLabel (const char *label) = 0;
@@ -397,7 +392,7 @@ protected:
virtual Platform *createPlatform () = 0;
virtual void setLayout (Layout *layout) = 0;
-
+
virtual int reliefXThickness () = 0;
virtual int reliefYThickness () = 0;
@@ -419,14 +414,14 @@ public:
};
/**
- * \brief Base interface for dw::core::ui::ListResource and
+ * \brief Base interface for dw::core::ui::ListResource and
* dw::core::ui::OptionMenuResource.
*/
class SelectionResource: public Resource
{
public:
virtual void addItem (const char *str, bool enabled, bool selected) = 0;
-
+
virtual void pushGroup (const char *name, bool enabled) = 0;
virtual void popGroup () = 0;
@@ -448,7 +443,7 @@ public:
/**
* \brief Exactly one item is selected, except possibly at the beginning.
- *
+ *
* If no item is selected initially, no one is selected automatically.
* The user may not unselect the only selected item.
*/
@@ -476,7 +471,7 @@ class OptionMenuResource: public SelectionResource
class TextResource: public Resource
{
public:
- Iterator *iterator (Content::Type mask, bool atEnd);
+ Iterator *iterator (Content::Type mask, bool atEnd);
virtual const char *getText () = 0;
virtual void setText (const char *text) = 0;
@@ -505,7 +500,7 @@ public:
class CheckButtonResource: public ToggleButtonResource
{
public:
- Iterator *iterator (Content::Type mask, bool atEnd);
+ Iterator *iterator (Content::Type mask, bool atEnd);
};
class RadioButtonResource: public ToggleButtonResource
@@ -529,14 +524,14 @@ public:
*/
virtual GroupIterator *groupIterator () = 0;
- Iterator *iterator (Content::Type mask, bool atEnd);
+ Iterator *iterator (Content::Type mask, bool atEnd);
};
/**
* \brief A factory for the common resource.
*/
-class ResourceFactory: public object::Object
+class ResourceFactory: public lout::object::Object
{
public:
virtual LabelButtonResource *createLabelButtonResource (const char *label)
@@ -545,10 +540,10 @@ public:
bool relief)
= 0;
virtual ListResource *createListResource (ListResource::SelectionMode
- selectionMode) = 0;
+ selectionMode, int rows) = 0;
virtual OptionMenuResource *createOptionMenuResource () = 0;
- virtual EntryResource *createEntryResource (int maxLength,
- bool password) = 0;
+ virtual EntryResource *createEntryResource (int maxLength, bool password,
+ const char *label) = 0;
virtual MultiLineTextResource *createMultiLineTextResource (int cols,
int rows) = 0;
virtual CheckButtonResource *createCheckButtonResource (bool activated) = 0;
diff --git a/dw/view.hh b/dw/view.hh
index ef604549..d0f6c6b9 100644
--- a/dw/view.hh
+++ b/dw/view.hh
@@ -13,7 +13,7 @@ namespace core {
*
* \sa\ref dw-overview, \ref dw-layout-views
*/
-class View: public object::Object
+class View: public lout::object::Object
{
public:
/*
@@ -34,7 +34,7 @@ public:
virtual void setCanvasSize (int width, int ascent, int descent) = 0;
/**
- * \brief Set the cursor appearance.
+ * \brief Set the cursor appearance.
*/
virtual void setCursor (style::Cursor cursor) = 0;
@@ -42,7 +42,7 @@ public:
* \brief Set the background of the view.
*/
virtual void setBgColor (style::Color *color) = 0;
-
+
/*
* ---------------------------------------------------------
* Scrolling and Related. Only usesViewport must be
@@ -80,6 +80,11 @@ public:
virtual void scrollTo (int x, int y) = 0;
/**
+ * \brief Scroll the viewport as commanded.
+ */
+ virtual void scroll (ScrollCommand) { };
+
+ /**
* \brief Set the viewport size.
*
* Does not have to be implemented, when usesViewport returns false.
@@ -107,7 +112,7 @@ public:
/**
* \brief Called before drawing.
*
- * All actual drawing operations will be enclosed into calls of
+ * All actual drawing operations will be enclosed into calls of
* dw::core:View::startDrawing and dw::core:View::finishDrawing. They
* may be implemented, e.g. when a backing
* pixmap is used, to prevent flickering. StartDrawing() will then
@@ -166,7 +171,7 @@ public:
int x, int y, int width, int height) = 0;
virtual void drawArc (style::Color *color,
style::Color::Shading shading, bool filled,
- int x, int y, int width, int height,
+ int centerX, int centerY, int width, int height,
int angle1, int angle2) = 0;
virtual void drawPolygon (style::Color *color,
style::Color::Shading shading,
diff --git a/dw/widget.cc b/dw/widget.cc
index b664b433..751cdcdf 100644
--- a/dw/widget.cc
+++ b/dw/widget.cc
@@ -14,222 +14,22 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core.hh"
+#include "../lout/msg.h"
#include "../lout/debug.hh"
+using namespace lout;
using namespace lout::object;
namespace dw {
namespace core {
-bool Widget::EventReceiver::buttonPress (Widget *widget, EventButton *event)
-{
- return false;
-}
-
-bool Widget::EventReceiver::buttonRelease (Widget *widget, EventButton *event)
-{
- return false;
-}
-
-bool Widget::EventReceiver::motionNotify (Widget *widget, EventMotion *event)
-{
- return false;
-}
-
-void Widget::EventReceiver::enterNotify (Widget *widget, EventCrossing *event)
-{
-}
-
-void Widget::EventReceiver::leaveNotify (Widget *widget, EventCrossing *event)
-{
-}
-
-
-bool Widget::EventEmitter::emitToReceiver (lout::signal::Receiver *receiver,
- int signalNo,
- int argc, Object **argv)
-{
- EventReceiver *eventReceiver = (EventReceiver*)receiver;
-
- switch (signalNo) {
- case BUTTON_PRESS:
- return eventReceiver->buttonPress ((Widget*)argv[0],
- (EventButton*)argv[1]);
-
- case BUTTON_RELEASE:
- return eventReceiver->buttonRelease ((Widget*)argv[0],
- (EventButton*)argv[1]);
-
- case MOTION_NOTIFY:
- return eventReceiver->motionNotify ((Widget*)argv[0],
- (EventMotion*)argv[1]);
-
- case ENTER_NOTIFY:
- eventReceiver->enterNotify ((Widget*)argv[0],
- (EventCrossing*)argv[1]);
- break;
-
- case LEAVE_NOTIFY:
- eventReceiver->leaveNotify ((Widget*)argv[1],
- (EventCrossing*)argv[0]);
- break;
-
- default:
- misc::assertNotReached ();
- }
-
- /* Compiler happiness. */
- return false;
-}
-
-bool Widget::EventEmitter::emitButtonPress (Widget *widget, EventButton *event)
-{
- Object *argv[2] = { widget, event };
- return emitBool (BUTTON_PRESS, 2, argv);
-}
-
-bool Widget::EventEmitter::emitButtonRelease (Widget *widget,
- EventButton *event)
-{
- Object *argv[2] = { widget, event };
- return emitBool (BUTTON_RELEASE, 2, argv);
-}
-
-bool Widget::EventEmitter::emitMotionNotify (Widget *widget,
- EventMotion *event)
-{
- Object *argv[2] = { widget, event };
- return emitBool (MOTION_NOTIFY, 2, argv);
-}
-
-void Widget::EventEmitter::emitEnterNotify (Widget *widget,
- EventCrossing *event)
-{
- Object *argv[2] = { widget, event };
- emitVoid (ENTER_NOTIFY, 2, argv);
-}
-
-void Widget::EventEmitter::emitLeaveNotify (Widget *widget,
- EventCrossing *event)
-{
- Object *argv[2] = { widget, event };
- emitVoid (LEAVE_NOTIFY, 2, argv);
-}
-
-// ----------------------------------------------------------------------
-
-bool Widget::LinkReceiver::enter (Widget *widget, int link, int img,
- int x, int y)
-{
- return false;
-}
-
-bool Widget::LinkReceiver::press (Widget *widget, int link, int img,
- int x, int y, EventButton *event)
-{
- return false;
-}
-
-bool Widget::LinkReceiver::release (Widget *widget, int link, int img,
- int x, int y, EventButton *event)
-{
- return false;
-}
-
-bool Widget::LinkReceiver::click (Widget *widget, int link, int img,
- int x, int y, EventButton *event)
-{
- return false;
-}
-
-
-bool Widget::LinkEmitter::emitToReceiver (lout::signal::Receiver *receiver,
- int signalNo,
- int argc, Object **argv)
-{
- LinkReceiver *linkReceiver = (LinkReceiver*)receiver;
-
- switch (signalNo) {
- case ENTER:
- return linkReceiver->enter ((Widget*)argv[0],
- ((Integer*)argv[1])->getValue (),
- ((Integer*)argv[2])->getValue (),
- ((Integer*)argv[3])->getValue (),
- ((Integer*)argv[4])->getValue ());
-
- case PRESS:
- return linkReceiver->press ((Widget*)argv[0],
- ((Integer*)argv[1])->getValue (),
- ((Integer*)argv[2])->getValue (),
- ((Integer*)argv[3])->getValue (),
- ((Integer*)argv[4])->getValue (),
- (EventButton*)argv[5]);
-
- case RELEASE:
- return linkReceiver->release ((Widget*)argv[0],
- ((Integer*)argv[1])->getValue (),
- ((Integer*)argv[2])->getValue (),
- ((Integer*)argv[3])->getValue (),
- ((Integer*)argv[4])->getValue (),
- (EventButton*)argv[5]);
-
- case CLICK:
- return linkReceiver->click ((Widget*)argv[0],
- ((Integer*)argv[1])->getValue (),
- ((Integer*)argv[2])->getValue (),
- ((Integer*)argv[3])->getValue (),
- ((Integer*)argv[4])->getValue (),
- (EventButton*)argv[5]);
-
- default:
- misc::assertNotReached ();
- }
-
- /* Compiler happiness. */
- return false;
-}
-
-bool Widget::LinkEmitter::emitEnter (Widget *widget, int link, int img,
- int x, int y)
-{
- Integer ilink (link), iimg (img), ix (x), iy (y);
- Object *argv[5] = { widget, &ilink, &iimg, &ix, &iy };
- return emitBool (ENTER, 5, argv);
-}
-
-bool Widget::LinkEmitter::emitPress (Widget *widget, int link, int img,
- int x, int y, EventButton *event)
-{
- Integer ilink (link), iimg (img), ix (x), iy (y);
- Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
- return emitBool (PRESS, 6, argv);
-}
-
-bool Widget::LinkEmitter::emitRelease (Widget *widget, int link, int img,
- int x, int y, EventButton *event)
-{
- Integer ilink (link), iimg (img), ix (x), iy (y);
- Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
- return emitBool (RELEASE, 6, argv);
-}
-
-bool Widget::LinkEmitter::emitClick (Widget *widget, int link, int img,
- int x, int y, EventButton *event)
-{
- Integer ilink (link), iimg (img), ix (x), iy (y);
- Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
- return emitBool (CLICK, 6, argv);
-}
-
-
// ----------------------------------------------------------------------
int Widget::CLASS_ID = -1;
@@ -237,7 +37,7 @@ int Widget::CLASS_ID = -1;
Widget::Widget ()
{
registerName ("dw::core::Widget", &CLASS_ID);
-
+
flags = (Flags)(NEEDS_RESIZE | EXTREMES_CHANGED | HAS_CONTENTS);
parent = NULL;
layout = NULL;
@@ -317,7 +117,7 @@ void Widget::queueDrawArea (int x, int y, int width, int height)
{
/** \todo Maybe only the intersection? */
layout->queueDraw (x + allocation.x, y + allocation.y, width, height);
- //printf("Widget::queueDrawArea x=%d y=%d w=%d h=%d\n", x, y, width, height);
+ _MSG("Widget::queueDrawArea x=%d y=%d w=%d h=%d\n", x, y, width, height);
}
/**
@@ -460,35 +260,27 @@ void Widget::sizeAllocate (Allocation *allocation)
bool Widget::buttonPress (EventButton *event)
{
- bool b1 = buttonPressImpl (event);
- bool b2 = eventEmitter.emitButtonPress (this, event);
- return b1 || b2;
+ return buttonPressImpl (event);
}
bool Widget::buttonRelease (EventButton *event)
{
- bool b1 = buttonReleaseImpl (event);
- bool b2 = eventEmitter.emitButtonRelease (this, event);
- return b1 || b2;
+ return buttonReleaseImpl (event);
}
bool Widget::motionNotify (EventMotion *event)
{
- bool b1 = motionNotifyImpl (event);
- bool b2 = eventEmitter.emitMotionNotify (this, event);
- return b1 || b2;
+ return motionNotifyImpl (event);
}
void Widget::enterNotify (EventCrossing *event)
{
enterNotifyImpl (event);
- eventEmitter.emitEnterNotify (this, event);
}
void Widget::leaveNotify (EventCrossing *event)
{
leaveNotifyImpl (event);
- eventEmitter.emitLeaveNotify (this, event);
}
/**
@@ -497,7 +289,7 @@ void Widget::leaveNotify (EventCrossing *event)
* The old style is automatically unreferred, the new is referred. If this
* call causes the widget to change its size, dw::core::Widget::queueResize
* is called.
- */
+ */
void Widget::setStyle (style::Style *style)
{
bool sizeChanged;
@@ -549,7 +341,7 @@ style::Color *Widget::getBgColor ()
widget = widget->parent;
}
- fprintf (stderr, "No background color found!\n");
+ MSG_WARN("No background color found!\n");
return NULL;
}
@@ -694,10 +486,10 @@ Widget *Widget::getNearestCommonAncestor (Widget *otherWidget)
/* Search upwards. */
while (widget1 != widget2) {
if (widget1->parent == NULL) {
- fprintf (stderr, "widgets in different trees\n");
+ MSG_WARN("widgets in different trees\n");
return NULL;
}
-
+
widget1 = widget1->parent;
widget2 = widget2->parent;
}
@@ -708,7 +500,7 @@ Widget *Widget::getNearestCommonAncestor (Widget *otherWidget)
/**
* \brief Search recursively through widget.
- *
+ *
* Used by dw::core::Layout:getWidgetAtPoint.
*/
Widget *Widget::getWidgetAtPoint (int x, int y, int level)
@@ -740,7 +532,7 @@ Widget *Widget::getWidgetAtPoint (int x, int y, int level)
level + 1);
it->unref ();
-
+
if (childAtPoint)
return childAtPoint;
else
@@ -823,12 +615,20 @@ bool Widget::motionNotifyImpl (EventMotion *event)
return false;
}
-void Widget::enterNotifyImpl (EventCrossing *event)
+void Widget::enterNotifyImpl (EventCrossing *)
{
+ core::style::Tooltip *tooltip = getStyle()->x_tooltip;
+
+ if (tooltip)
+ tooltip->onEnter();
}
-void Widget::leaveNotifyImpl (EventCrossing *event)
+void Widget::leaveNotifyImpl (EventCrossing *)
{
+ core::style::Tooltip *tooltip = getStyle()->x_tooltip;
+
+ if (tooltip)
+ tooltip->onLeave();
}
void Widget::removeChild (Widget *child)
diff --git a/dw/widget.hh b/dw/widget.hh
index fde48ecc..013be27b 100644
--- a/dw/widget.hh
+++ b/dw/widget.hh
@@ -20,149 +20,16 @@ namespace core {
*
* \sa\ref dw-overview, \ref dw-layout-widgets
*/
-class Widget: public identity::IdentifiableObject
+class Widget: public lout::identity::IdentifiableObject
{
friend class Layout;
-public:
- class EventReceiver: public lout::signal::Receiver
- {
- public:
- virtual bool buttonPress (Widget *widget, EventButton *event);
- virtual bool buttonRelease (Widget *widget, EventButton *event);
- virtual bool motionNotify (Widget *widget, EventMotion *event);
- virtual void enterNotify (Widget *widget, EventCrossing *event);
- virtual void leaveNotify (Widget *widget, EventCrossing *event);
- };
-
- /**
- * \brief This receiver is for signals related to HTML pages.
- *
- * The \em link argument to all signals defines a number, which has
- * been passed before, e.g. by setting dw::core::style::Style::x_link.
- * When defining this number (e.g in dw::core::style::Style::x_link),
- * and when receiving the signal, the caller must interpret these numbers
- * in a consistent way. In the HTML link block, this number is an index
- * to an array of URLs.
- *
- * \em link = -1 represents an undefined link.
- *
- * The \em img argument to all signals defines a number which has
- * been passed before, e.g. by setting dw::core::style::Style::x_img.
- * When defining this number (e.g in dw::core::style::Style::x_img),
- * and when receiving the signal, the caller must interpret these numbers
- * in a consistent way. In the HTML link block, this number is an index
- * to an array of structures containing image information.
- *
- * \em img = -1 represents an undefined image.
- *
- * \em x and \em y define the coordinates within the link area. They are
- * only used for server-side image maps, see dw::Image.
- *
- * \sa dw::Image, dw::Textblock
- */
- class LinkReceiver: public lout::signal::Receiver
- {
- public:
- /**
- * \brief Called, when a link is entered, left, or the position has
- * changed.
- *
- * When a link is entered, this method is called with the respective
- * arguments. When a link is left, this method is called with all
- * three arguments (\em link, \em x, \em y) set to -1.
- *
- * When coordinates are supported, a change of the coordinates also
- * causes emitting this signal.
- */
- virtual bool enter (Widget *widget, int link, int img, int x, int y);
-
- /**
- * \brief Called, when the user has pressed the mouse button on a
- * link (but not yet released).
- *
- * The causing event is passed as \em event.
- */
- virtual bool press (Widget *widget, int link, int img, int x, int y,
- EventButton *event);
-
- /**
- * \brief Called, when the user has released the mouse button on a
- * link.
- *
- * The causing event is passed as \em event.
- */
- virtual bool release (Widget *widget, int link, int img, int x, int y,
- EventButton *event);
-
- /**
- * \brief Called, when the user has clicked on a link.
- *
- * For mouse interaction, this is equivalent to "press" and "release"
- * on the same link. In this case, \em event contains the "release"
- * event.
- *
- * When activating links via keyboard is supported, only a "clicked"
- * signal will be emitted, and \em event will be NULL.
- */
- virtual bool click (Widget *widget, int link, int img, int x, int y,
- EventButton *event);
- };
-
-private:
- class EventEmitter: public lout::signal::Emitter
- {
- private:
- enum { BUTTON_PRESS, BUTTON_RELEASE, MOTION_NOTIFY, ENTER_NOTIFY,
- LEAVE_NOTIFY };
-
- protected:
- bool emitToReceiver (lout::signal::Receiver *receiver, int signalNo,
- int argc, Object **argv);
-
- public:
- inline void connectEvent (EventReceiver *receiver)
- { connect (receiver); }
-
- bool emitButtonPress (Widget *widget, EventButton *event);
- bool emitButtonRelease (Widget *widget, EventButton *event);
- bool emitMotionNotify (Widget *widget, EventMotion *event);
- void emitEnterNotify (Widget *widget, EventCrossing *event);
- void emitLeaveNotify (Widget *widget, EventCrossing *event);
- };
-
- class LinkEmitter: public lout::signal::Emitter
- {
- private:
- enum { ENTER, PRESS, RELEASE, CLICK };
-
- protected:
- bool emitToReceiver (lout::signal::Receiver *receiver, int signalNo,
- int argc, Object **argv);
-
- public:
- inline void connectLink (LinkReceiver *receiver) { connect (receiver); }
-
- bool emitEnter (Widget *widget, int link, int img, int x, int y);
- bool emitPress (Widget *widget, int link, int img, int x, int y,
- EventButton *event);
- bool emitRelease (Widget *widget, int link, int img, int x, int y,
- EventButton *event);
- bool emitClick (Widget *widget, int link, int img, int x, int y,
- EventButton *event);
- };
-
- EventEmitter eventEmitter;
-
- style::Style *style;
-
-
protected:
enum Flags {
/**
* \brief Set, when dw::core::Widget::requisition is not up to date
* anymore.
- */
+ */
NEEDS_RESIZE = 1 << 0,
/**
@@ -175,7 +42,7 @@ protected:
/**
* \brief Set, when dw::core::Widget::extremes is not up to date
* anymore.
- */
+ */
EXTREMES_CHANGED = 1 << 2,
/**
@@ -183,7 +50,7 @@ protected:
* methods are implemented.
*
* Will hopefully be removed, after redesigning the size model.
- */
+ */
USES_HINTS = 1 << 3,
/**
@@ -191,7 +58,7 @@ protected:
* some contents, e.g. an image, as opposed to a horizontal ruler.
*
* Will hopefully be removed, after redesigning the size model.
- */
+ */
HAS_CONTENTS = 1 << 4,
/**
@@ -207,6 +74,7 @@ private:
* \brief The parent widget, NULL for top-level widgets.
*/
Widget *parent;
+ style::Style *style;
Flags flags;
@@ -248,7 +116,6 @@ public:
int parentRef;
protected:
- LinkEmitter linkEmitter;
/**
* \brief The current allocation: size and position, always relative to the
@@ -266,7 +133,7 @@ protected:
inline void setFlags (Flags f) { flags = (Flags)(flags | f); }
inline void unsetFlags (Flags f) { flags = (Flags)(flags & ~f); }
-
+
inline void queueDraw ()
{
@@ -346,7 +213,7 @@ protected:
EventMotion *event, bool withinContent)
{ return layout->selectionState.buttonMotion (it, charPos, linkNo, event,
withinContent); }
-
+
inline bool selectionHandleEvent (SelectionState::EventType eventType,
Iterator *it, int charPos, int linkNo,
MousePositionEvent *event,
@@ -372,28 +239,6 @@ public:
inline bool needsAllocate () { return flags & NEEDS_ALLOCATE; }
inline bool extremesChanged () { return flags & EXTREMES_CHANGED; }
inline bool wasAllocated () { return flags & WAS_ALLOCATED; }
-
- inline void connectEvent (EventReceiver *receiver)
- { eventEmitter.connectEvent (receiver); }
-
- inline void connectLink (LinkReceiver *receiver)
- { linkEmitter.connectLink (receiver); }
-
- inline bool emitLinkEnter (int link, int img, int x, int y)
- { return linkEmitter.emitEnter (this, link, img, x, y); }
-
- inline bool emitLinkPress (int link, int img,
- int x, int y, EventButton *event)
- { return linkEmitter.emitPress (this, link, img, x, y, event); }
-
- inline bool emitLinkRelease (int link, int img,
- int x, int y, EventButton *event)
- { return linkEmitter.emitRelease (this, link, img, x, y, event); }
-
- inline bool emitLinkClick (int link, int img,
- int x, int y, EventButton *event)
- { return linkEmitter.emitClick (this, link, img, x, y, event); }
-
inline bool usesHints () { return flags & USES_HINTS; }
inline bool hasContents () { return flags & HAS_CONTENTS; }
@@ -420,7 +265,7 @@ public:
bool motionNotify (EventMotion *event);
void enterNotify (EventCrossing *event);
void leaveNotify (EventCrossing *event);
-
+
virtual void setStyle (style::Style *style);
void setBgColor (style::Color *bgColor);
style::Color *getBgColor ();