aboutsummaryrefslogtreecommitdiff
path: root/dw/iterator.hh
blob: 773cf3033255c629f6195c7656a205c5622d767a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
#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);
};


/**
 * \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); }
};

/**
 * \brief Some completely different kind of iterator: ...
 */
class StackingIteratorStack
{
private:
   lout::container::untyped::Vector *vector;
   int topPos;
   
public:
   StackingIteratorStack ();
   ~StackingIteratorStack ();

   void intoStringBuffer(lout::misc::StringBuffer *sb);

   inline bool atRealTop () { return topPos == vector->size () - 1; }
   inline lout::object::Object *getTop () { return vector->get (topPos); }

   void push (lout::object::Object *object);
   void pop ();
   void forward ();
   void backward ();
};

} // namespace core
} // namespace dw

#endif // __ITERATOR_HH__