summaryrefslogtreecommitdiff
path: root/dwr/label.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dwr/label.cc')
-rw-r--r--dwr/label.cc378
1 files changed, 378 insertions, 0 deletions
diff --git a/dwr/label.cc b/dwr/label.cc
new file mode 100644
index 0000000..dfef145
--- /dev/null
+++ b/dwr/label.cc
@@ -0,0 +1,378 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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 "label.hh"
+
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace dw {
+
+int Label::CLASS_ID = -1;
+
+// ----------------------------------------------------------------------
+
+Label::LabelIterator::LabelIterator (Label *label, Content::Type mask,
+ bool atEnd) : Iterator (label, mask, atEnd)
+{
+ index = atEnd ? label->words->size() : -1;
+ content.type = atEnd ? Content::END : Content::START;
+}
+
+Label::LabelIterator::LabelIterator (Label *label, Content::Type mask,
+ int index) : Iterator (label, mask, false)
+{
+ this->index = index;
+
+ if (index < 0)
+ content.type = Content::START;
+ else if (index >= label->words->size ())
+ content.type = Content::END;
+ else {
+ content.type = Content::TEXT;
+ content.text = label->words->getRef(index)->text;
+ }
+}
+
+lout::object::Object *Label::LabelIterator::clone()
+{
+ return new LabelIterator ((Label*)getWidget(), getMask(), index);
+}
+
+int Label::LabelIterator::compareTo(lout::object::Comparable *other)
+{
+ return index - ((LabelIterator*)other)->index;
+}
+
+bool Label::LabelIterator::next ()
+{
+ Label *label = (Label*)getWidget();
+
+ if (content.type == Content::END)
+ return false;
+
+ // labels only contain widgets:
+ if ((getMask() & Content::TEXT) == 0) {
+ content.type = Content::END;
+ return false;
+ }
+
+ index++;
+ if (index >= label->words->size ()) {
+ content.type = Content::END;
+ return false;
+ } else {
+ content.type = Content::TEXT;
+ content.text = label->words->getRef(index)->text;
+ return true;
+ }
+}
+
+bool Label::LabelIterator::prev ()
+{
+ Label *label = (Label*)getWidget();
+
+ if (content.type == Content::START)
+ return false;
+
+ // labels only contain widgets:
+ if ((getMask() & Content::TEXT) == 0) {
+ content.type = Content::START;
+ return false;
+ }
+
+ index--;
+ if (index < 0) {
+ content.type = Content::START;
+ return false;
+ } else {
+ content.type = Content::TEXT;
+ content.text = label->words->getRef(index)->text;
+ return true;
+ }
+}
+
+void Label::LabelIterator::highlight (int start, int end, HighlightLayer layer)
+{
+ /** \bug Not implemented. */
+}
+
+void Label::LabelIterator::unhighlight (int direction, HighlightLayer layer)
+{
+ /** \bug Not implemented. */
+}
+
+void Label::LabelIterator::getAllocation (int start, int end,
+ Allocation *allocation)
+{
+ /** \bug Not implemented. */
+}
+
+// ----------------------------------------------------------------------
+
+Label::Label (const char *text, int link)
+{
+ DBG_OBJ_CREATE ("rtfl::dw::Label");
+ registerName ("rtfl::dw::Label", &CLASS_ID);
+
+ words = new SimpleVector<Word> (1);
+
+ for (int i = 0; i < 4; i++)
+ styles[i] = NULL;
+
+ selected = buttonDown = false;
+ this->link = link;
+
+ setText (text);
+}
+
+Label::~Label ()
+{
+ clearWords ();
+ delete words;
+
+ clearStyles ();
+
+ DBG_OBJ_DELETE ();
+}
+
+void Label::setText (const char *text)
+{
+ clearWords ();
+
+ DBG_OBJ_SET_STR ("text", text);
+
+ // Parse text for tags <i>, </i>, <b>, </b>. Very simple, no stack.
+ const char *start = text;
+ int styleIndex = 0;
+ while (*start) {
+ const char *end = start;
+
+ while (!(*end == 0 ||
+ strncmp (end, "<i>", 3) == 0 || strncmp (end, "<b>", 3) == 0 ||
+ strncmp (end, "</i>", 4) == 0 || strncmp (end, "</b>", 4) == 0))
+ end++;
+
+ //printf ("start: '%s', end: '%s'\n", start, end);
+
+ if (end > start) {
+ words->increase ();
+ Word *word = words->getLastRef ();
+ word->text = strndup (start, end - start);
+ word->styleIndex = styleIndex;
+
+ //printf (" new word '%s' with attributes %c%c\n", word->text,
+ // (word->styleIndex & ITALIC) ? 'i' : '-',
+ // (word->styleIndex & BOLD) ? 'b' : '-');
+ }
+
+ if (*end == 0)
+ start = end;
+ else if (strncmp (end, "<i>", 3) == 0) {
+ start = end + 3;
+ styleIndex |= ITALIC;
+ } else if (strncmp (end, "<b>", 3) == 0) {
+ start = end + 3;
+ styleIndex |= BOLD;
+ } else if (strncmp (end, "</i>", 4) == 0) {
+ start = end + 4;
+ styleIndex &= ~ITALIC;
+ } else if (strncmp (end, "</b>", 4) == 0) {
+ start = end + 4;
+ styleIndex &= ~BOLD;
+ } else
+ assertNotReached ();
+ }
+
+ queueResize (0, true);
+}
+
+void Label::clearWords ()
+{
+ for (int i = 0; i < words->size (); i++)
+ free (words->getRef(i)->text);
+ words->setSize (0);
+}
+
+void Label::clearStyles ()
+{
+ for (int i = 0; i < 4; i++)
+ if (styles[i]) {
+ styles[i]->unref ();
+ styles[i] = NULL;
+ }
+}
+
+void Label::ensureStyles ()
+{
+ if (getStyle () && styles[0] == NULL) {
+ styles[0] = getStyle ();
+ styles[0]->ref ();
+
+ for (int i = 1; i < 4; i++) {
+ StyleAttrs styleAttrs = *getStyle ();
+ FontAttrs fontAttrs = *(styleAttrs.font);
+ fontAttrs.weight = (i & BOLD) ? 700 : 400;
+ fontAttrs.style = (i & ITALIC) ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL;
+ styleAttrs.font = Font::create (layout, &fontAttrs);
+ styles[i] = Style::create (&styleAttrs);
+ }
+ }
+}
+
+void Label::sizeRequestImplImpl (Requisition *requisition)
+{
+ totalSize.width = totalSize.ascent = totalSize.descent = 0;
+
+ if (getStyle ()) {
+ ensureStyles ();
+
+ for (int i = 0; i < words->size (); i++) {
+ Word *word = words->getRef(i);
+ Font *font = styles[(int)word->styleIndex]->font;
+
+ word->size.width =
+ layout->textWidth (font, word->text, strlen (word->text));
+ word->size.ascent = font->ascent;
+ word->size.descent = font->descent;
+
+ totalSize.width += word->size.width;
+ totalSize.ascent = max (totalSize.ascent, word->size.ascent);
+ totalSize.descent = max (totalSize.descent, word->size.descent);
+ }
+ } else
+ totalSize.width = totalSize.ascent = totalSize.descent = 0;
+
+ requisition->width = totalSize.width + getStyle()->boxDiffWidth ();
+ requisition->ascent = totalSize.ascent + getStyle()->boxOffsetY ();
+ requisition->descent = totalSize.descent + getStyle()->boxRestHeight ();
+}
+
+void Label::getExtremesImplImpl (Extremes *extremes)
+{
+ // Not used within RTFL.
+ assertNotReached ();
+}
+
+void Label::drawImpl (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("drawImpl", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ drawWidgetBox (view, area, selected);
+
+ if (getStyle ()) {
+ ensureStyles ();
+
+ // Could adhere to style::textAlign. This can be used for
+ // centered text:
+ //
+ // int x = getAllocation()->x
+ // + (getAllocation()->width - totalSize.width) / 2;
+ //
+ // Now, only left-aligned text is supported.
+
+ int x = getAllocation()->x + getStyle()->boxOffsetX ();
+
+ // Same for style::valign:
+ //
+ // int baseY = getAllocation()->y
+ // + (getHeight () - (totalSize.ascent + totalSize.descent)) / 2
+ // + totalSize.ascent;
+
+ int baseY =
+ getAllocation()->y + totalSize.ascent + getStyle()->boxOffsetY ();
+
+ for (int i = 0; i < words->size (); i++) {
+ Word *word = words->getRef(i);
+ view-> drawText (styles[(int)word->styleIndex]->font,
+ styles[(int)word->styleIndex]->color,
+ selected ? Color::SHADING_INVERSE
+ : Color::SHADING_NORMAL,
+ x, baseY, word->text, strlen (word->text));
+ x += word->size.width;
+ }
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void Label::leaveNotifyImpl (EventCrossing *event)
+{
+ buttonDown = false;
+}
+
+bool Label::buttonPressImpl (EventButton *event)
+{
+ if (link != -1 && event->button == 1) {
+ buttonDown = true;
+ return true;
+ } else
+ return false;
+}
+
+bool Label::buttonReleaseImpl (EventButton *event)
+{
+ if (link != -1 && event->button == 1) {
+ if (buttonDown)
+ linkEmitter.emitClick (this, link, -1, -1, -1, event);
+ return true;
+ } else
+ return false;
+}
+
+Iterator *Label::iterator (Content::Type mask, bool atEnd)
+{
+ return new LabelIterator (this, mask, atEnd);
+}
+
+void Label::setStyle (Style *style)
+{
+ Widget::setStyle (style);
+ clearStyles ();
+}
+
+void Label::select ()
+{
+ selected = true;
+ queueDraw ();
+}
+
+void Label::unselect ()
+{
+ selected = false;
+ queueDraw ();
+}
+
+} // namespace rtfl
+
+} // namespace dw