]> git.lyx.org Git - lyx.git/blob - src/cursor.C
some integer type changes for inset unification
[lyx.git] / src / cursor.C
1 /**
2  * \file cursor.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author André Pönitz
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "buffer.h"
14 #include "BufferView.h"
15 #include "cursor.h"
16 #include "debug.h"
17 #include "dispatchresult.h"
18 #include "funcrequest.h"
19 #include "iterators.h"
20 #include "lfuns.h"
21 #include "lyxtext.h"
22 #include "paragraph.h"
23 #include "lyxrow.h"
24
25 #include "insets/updatableinset.h"
26 #include "insets/insettabular.h"
27 #include "insets/insettext.h"
28
29 #include <boost/assert.hpp>
30
31 using std::vector;
32 using std::endl;
33
34
35 std::ostream & operator<<(std::ostream & os, LCursor const & cursor)
36 {
37         os << "\n";
38         for (size_t i = 0, n = cursor.data_.size(); i != n; ++i)
39                 os << "   " << cursor.data_[i] << "\n";
40         return os;
41 }
42
43
44 LCursor::LCursor(BufferView * bv)
45         : data_(1), bv_(bv)
46 {}
47
48
49 DispatchResult LCursor::dispatch(FuncRequest const & cmd0)
50 {
51         lyxerr << "\nLCursor::dispatch: " << *this << endl;
52         FuncRequest cmd = cmd0;
53
54         for (int i = data_.size() - 1; i >= 1; --i) {
55                 CursorSlice const & citem = data_[i];
56                 lyxerr << "trying to dispatch to inset " << citem.inset_ << endl;
57                 DispatchResult res = citem.inset_->dispatch(cmd);
58                 if (res.dispatched()) {
59                         lyxerr << " successfully dispatched to inset " << citem.inset_ << endl;
60                         return DispatchResult(true, true);
61                 }
62                 // remove one level of cursor
63                 switch (res.val()) {
64                         case FINISHED:
65                                 pop(i);
66                                 cmd = FuncRequest(bv_, LFUN_FINISHED_LEFT);
67                                 break;
68                         case FINISHED_RIGHT:
69                                 pop(i);
70                                 cmd = FuncRequest(bv_, LFUN_FINISHED_RIGHT);
71                                 break;
72                         case FINISHED_UP:
73                                 pop(i);
74                                 cmd = FuncRequest(bv_, LFUN_FINISHED_UP);
75                                 break;
76                         case FINISHED_DOWN:
77                                 pop(i);
78                                 cmd = FuncRequest(bv_, LFUN_FINISHED_DOWN);
79                                 break;
80                         default:
81                                 lyxerr << "not handled on level " << i << " val: " << res.val() << endl;
82                                 break;
83                 }
84         }
85         lyxerr << "trying to dispatch to main text " << bv_->text() << endl;
86         DispatchResult res = bv_->text()->dispatch(cmd);
87         lyxerr << "   result: " << res.val() << endl;
88
89         if (!res.dispatched()) {
90                 lyxerr << "trying to dispatch to bv " << bv_ << endl;
91                 bool sucess = bv_->dispatch(cmd);
92                 lyxerr << "   result: " << sucess << endl;
93                 res.dispatched(sucess);
94         }
95
96         return res;
97 }
98
99
100 void LCursor::push(UpdatableInset * inset)
101 {
102         lyxerr << "LCursor::push()  inset: " << inset << endl;
103         data_.push_back(CursorSlice(inset));
104         updatePos();
105 }
106
107
108
109 void LCursor::pop(int depth)
110 {
111         lyxerr << "LCursor::pop() to " << depth << endl;
112         while (data_.size() > 1 && depth < data_.size()) {
113                 lyxerr <<   "LCursor::pop a level " << endl;
114                 data_.pop_back();
115         }
116 }
117
118
119 void LCursor::pop()
120 {
121         lyxerr << "LCursor::pop() " << endl;
122         //BOOST_ASSERT(!data_.empty());
123         if (data_.size() <= 1)
124                 lyxerr << "### TRYING TO POP FROM EMPTY CURSOR" << endl;
125         else
126                 data_.pop_back();
127 }
128
129
130 UpdatableInset * LCursor::innerInset() const
131 {
132         return data_.size() <= 1 ? 0 : data_.back().asUpdatableInset();
133 }
134
135
136 LyXText * LCursor::innerText() const
137 {
138         if (data_.size() > 1) {
139                 // go up until first non-0 text is hit
140                 // (innermost text is 0 e.g. for mathed and the outer tabular level)
141                 for (int i = data_.size() - 1; i >= 1; --i)
142                         if (data_[i].text())
143                                 return data_[i].text();
144         }
145         return bv_->text();
146 }
147
148
149 void LCursor::updatePos()
150 {
151         if (data_.size() > 1)
152                 cached_y_ = bv_->top_y() + innerInset()->y();
153 }
154
155
156 void LCursor::getDim(int & asc, int & desc) const
157 {
158         LyXText * txt = innerText();
159
160         if (txt) {
161                 Row const & row = *txt->cursorRow();
162                 asc = row.baseline();
163                 desc = row.height() - asc;
164         } else
165                 innerInset()->getCursorDim(asc, desc);
166 }
167
168
169 void LCursor::getPos(int & x, int & y) const
170 {
171         if (data_.size() <= 1) {
172                 x = bv_->text()->cursorX();
173                 y = bv_->text()->cursorY();
174 //              y -= bv_->top_y();
175         } else {
176                 // Would be nice to clean this up to make some understandable sense...
177                 UpdatableInset * inset = innerInset();
178                 // Non-obvious. The reason we have to have these
179                 // extra checks is that the ->getCursor() calls rely
180                 // on the inset's own knowledge of its screen position.
181                 // If we scroll up or down in a big enough increment, the
182                 // inset->draw() is not called: this doesn't update
183                 // inset.top_baseline, so getCursor() returns an old value.
184                 // Ugly as you like.
185                 inset->getCursorPos(data_.back().idx_, x, y);
186                 x += inset->x();
187                 y += cached_y_;
188         }
189 }
190
191
192 UpdatableInset * LCursor::innerInsetOfType(int code) const
193 {
194         for (int i = data_.size() - 1; i >= 1; --i)
195                 if (data_[i].asUpdatableInset()->lyxCode() == code)
196                         return data_[i].asUpdatableInset();
197         return 0;
198 }
199
200
201 InsetTabular * LCursor::innerInsetTabular() const
202 {
203         return static_cast<InsetTabular *>
204                 (innerInsetOfType(InsetOld::TABULAR_CODE));
205 }
206
207
208 void LCursor::cell(int idx)
209 {
210         BOOST_ASSERT(!data_.empty());
211         data_.back().idx_ = idx;
212 }
213
214
215 int LCursor::cell() const
216 {
217         BOOST_ASSERT(!data_.empty());
218         return data_.back().idx_;
219 }