summaryrefslogtreecommitdiff
path: root/dw/iterator.hh
diff options
context:
space:
mode:
Diffstat (limited to 'dw/iterator.hh')
-rw-r--r--dw/iterator.hh271
1 files changed, 271 insertions, 0 deletions
diff --git a/dw/iterator.hh b/dw/iterator.hh
new file mode 100644
index 0000000..abf31d0
--- /dev/null
+++ b/dw/iterator.hh
@@ -0,0 +1,271 @@
+#ifndef __ITERATOR_HH__
+#define __ITERATOR_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief Iterators are used to iterate through the contents of a widget.
+ *
+ * When using iterators, you should care about the results of
+ * dw::core::Widget::hasContents.
+ *
+ * \sa dw::core::Widget::iterator
+ */
+class Iterator: public lout::object::Comparable
+{
+protected:
+ Iterator(Widget *widget, Content::Type mask, bool atEnd);
+ Iterator(Iterator &it);
+ ~Iterator();
+
+ Content content;
+
+private:
+ Widget *widget;
+ Content::Type mask;
+
+public:
+ bool equals (Object *other);
+ void intoStringBuffer(lout::misc::StringBuffer *sb);
+
+ inline Widget *getWidget () { return widget; }
+ inline Content *getContent () { return &content; }
+ inline Content::Type getMask () { return mask; }
+
+ virtual void unref ();
+
+ /**
+ * \brief Move iterator forward and store content it.
+ *
+ * Returns true on success.
+ */
+ virtual bool next () = 0;
+
+ /**
+ * \brief Move iterator backward and store content it.
+ *
+ * Returns true on success.
+ */
+ virtual bool prev () = 0;
+
+ /**
+ * \brief Extend highlighted region to contain part of the current content.
+ *
+ * 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.
+ * To unhighlight see also dw::core::Iterator::unhighlight.
+ */
+ virtual void highlight (int start, int end, HighlightLayer layer) = 0;
+
+ /**
+ * \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.
+ */
+ virtual void unhighlight (int direction, HighlightLayer layer) = 0;
+
+ /**
+ * \brief Return the shape, which a part of the item, the iterator points
+ * on, allocates.
+ *
+ * The parameters start and end have the same meaning as in
+ * 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,
+ HPosition hpos, VPosition vpos);
+
+ virtual void print ();
+};
+
+
+/**
+ * \brief This implementation of dw::core::Iterator can be used by widgets
+ * with no contents.
+ */
+class EmptyIterator: public Iterator
+{
+private:
+ EmptyIterator (EmptyIterator &it);
+
+public:
+ EmptyIterator (Widget *widget, Content::Type mask, bool atEnd);
+
+ lout::object::Object *clone();
+ int compareTo(lout::object::Comparable *other);
+ bool next ();
+ bool prev ();
+ void highlight (int start, int end, HighlightLayer layer);
+ void unhighlight (int direction, HighlightLayer layer);
+ void getAllocation (int start, int end, Allocation *allocation);
+};
+
+
+/**
+ * \brief This implementation of dw::core::Iterator can be used by widgets
+ * having one text word as contents
+ */
+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(lout::object::Comparable *other);
+
+ bool next ();
+ bool prev ();
+ void getAllocation (int start, int end, Allocation *allocation);
+};
+
+
+/**
+ * \brief A stack of iterators, to iterate recursively through a widget tree.
+ *
+ * This class is similar to dw::core::Iterator, but not
+ * created by a widget, but explicitly from another iterator. Deep
+ * iterators do not have the limitation, that iteration is only done within
+ * a widget, instead, child widgets are iterated through recursively.
+ */
+class DeepIterator: public lout::object::Comparable
+{
+private:
+ class Stack: public lout::container::typed::Vector<Iterator>
+ {
+ public:
+ 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); }
+ inline void pop() { getTop()->unref (); remove (size () - 1); }
+ };
+
+ Stack stack;
+
+ static Iterator *searchDownward (Iterator *it, Content::Type mask,
+ bool fromEnd);
+ static Iterator *searchSideward (Iterator *it, Content::Type mask,
+ bool fromEnd);
+
+ Content::Type mask;
+ Content content;
+ bool hasContents;
+
+ inline DeepIterator () { }
+
+ static Widget *getRespectiveParent (Widget *widget, Content::Type mask);
+ inline Widget *getRespectiveParent (Widget *widget) {
+ return getRespectiveParent (widget, mask);
+ }
+
+ static int getRespectiveLevel (Widget *widget, Content::Type mask);
+ inline int getRespectiveLevel (Widget *widget) {
+ return getRespectiveLevel (widget, mask);
+ }
+
+public:
+ DeepIterator(Iterator *it);
+ ~DeepIterator();
+
+ lout::object::Object *clone ();
+
+ DeepIterator *createVariant(Iterator *it);
+ inline Iterator *getTopIterator () { return stack.getTop(); }
+ inline Content *getContent () { return &content; }
+
+ bool isEmpty ();
+
+ bool next ();
+ bool prev ();
+ inline DeepIterator *cloneDeepIterator() { return (DeepIterator*)clone(); }
+ int compareTo(lout::object::Comparable *other);
+
+ /**
+ * \brief Highlight a part of the current content.
+ *
+ * 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.
+ */
+ inline void highlight (int start, int end, HighlightLayer layer)
+ { stack.getTop()->highlight (start, end, layer); }
+
+ /**
+ * \brief Return the shape, which a part of the item, the iterator points
+ * on, allocates.
+ *
+ * The parameters start and end have the same meaning as in
+ * DwIterator::highlight().
+ */
+ inline void getAllocation (int start, int end, Allocation *allocation)
+ { stack.getTop()->getAllocation (start, end, allocation); }
+
+ inline void unhighlight (int direction, HighlightLayer layer)
+ { stack.getTop()->unhighlight (direction, layer); }
+
+ inline static void scrollTo (DeepIterator *it1, DeepIterator *it2,
+ int start, int end,
+ HPosition hpos, VPosition vpos)
+ { Iterator::scrollTo(it1->stack.getTop(), it2->stack.getTop(),
+ start, end, hpos, vpos); }
+};
+
+class CharIterator: public lout::object::Comparable
+{
+public:
+ // START and END must not clash with any char value
+ // neither for signed nor unsigned char.
+ enum { START = 257, END = 258 };
+
+private:
+ DeepIterator *it;
+ int pos, ch;
+
+ CharIterator ();
+
+public:
+ CharIterator (Widget *widget, bool followReferences);
+ ~CharIterator ();
+
+ lout::object::Object *clone();
+ int compareTo(lout::object::Comparable *other);
+
+ bool next ();
+ bool prev ();
+ inline int getChar() { return ch; }
+ inline CharIterator *cloneCharIterator() { return (CharIterator*)clone(); }
+
+ static void highlight (CharIterator *it1, CharIterator *it2,
+ HighlightLayer layer);
+ static void unhighlight (CharIterator *it1, CharIterator *it2,
+ HighlightLayer layer);
+
+ inline static void scrollTo (CharIterator *it1, CharIterator *it2,
+ HPosition hpos, VPosition vpos)
+ { DeepIterator::scrollTo(it1->it, it2->it, it1->pos, it2->pos,
+ hpos, vpos); }
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __ITERATOR_HH__