]> git.lyx.org Git - lyx.git/blob - src/cursor.C
shift small stuff from math cursor to cursor
[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 "mathed/math_data.h"
30
31 #include <boost/assert.hpp>
32
33 using std::vector;
34 using std::endl;
35
36
37 std::ostream & operator<<(std::ostream & os, LCursor const & cur)
38 {
39         os << "\n";
40         for (size_t i = 0, n = cur.cursor_.size(); i != n; ++i)
41                 os << "   (" << cur.cursor_[i] << " | " << cur.anchor_[i] << "\n";
42         return os;
43 }
44
45
46 LCursor::LCursor()
47         : cursor_(1), anchor_(1), bv_(0)
48 {}
49
50
51 LCursor::LCursor(BufferView & bv)
52         : cursor_(1), anchor_(1), bv_(&bv)
53 {}
54
55
56 DispatchResult LCursor::dispatch(FuncRequest const & cmd0)
57 {
58         lyxerr << "\nLCursor::dispatch: " << *this << endl;
59         FuncRequest cmd = cmd0;
60
61         for (int i = cursor_.size() - 1; i >= 1; --i) {
62                 CursorSlice const & citem = cursor_[i];
63                 lyxerr << "trying to dispatch to inset " << citem.inset_ << endl;
64                 DispatchResult res = citem.inset_->dispatch(*bv_, cmd);
65                 if (res.dispatched()) {
66                         lyxerr << " successfully dispatched to inset " << citem.inset_ << endl;
67                         return DispatchResult(true, true);
68                 }
69                 // remove one level of cursor
70                 switch (res.val()) {
71                         case FINISHED:
72                                 pop(i);
73                                 cmd = FuncRequest(LFUN_FINISHED_LEFT);
74                                 break;
75                         case FINISHED_RIGHT:
76                                 pop(i);
77                                 cmd = FuncRequest(LFUN_FINISHED_RIGHT);
78                                 break;
79                         case FINISHED_UP:
80                                 pop(i);
81                                 cmd = FuncRequest(LFUN_FINISHED_UP);
82                                 break;
83                         case FINISHED_DOWN:
84                                 pop(i);
85                                 cmd = FuncRequest(LFUN_FINISHED_DOWN);
86                                 break;
87                         default:
88                                 lyxerr << "not handled on level " << i << " val: " << res.val() << endl;
89                                 break;
90                 }
91         }
92         lyxerr << "trying to dispatch to main text " << bv_->text() << endl;
93         DispatchResult res = bv_->text()->dispatch(*bv_, cmd);
94         lyxerr << "   result: " << res.val() << endl;
95
96         if (!res.dispatched()) {
97                 lyxerr << "trying to dispatch to bv " << bv_ << endl;
98                 bool sucess = bv_->dispatch(cmd);
99                 lyxerr << "   result: " << sucess << endl;
100                 res.dispatched(sucess);
101         }
102
103         return res;
104 }
105
106
107 void LCursor::push(InsetBase * inset)
108 {
109         lyxerr << "LCursor::push()  inset: " << inset << endl;
110         cursor_.push_back(CursorSlice(inset));
111         anchor_.push_back(CursorSlice(inset));
112         updatePos();
113 }
114
115
116
117 void LCursor::pop(int depth)
118 {
119         lyxerr << "LCursor::pop() to " << depth << endl;
120         while (cursor_.size() > 1 && depth < cursor_.size()) {
121                 lyxerr <<   "LCursor::pop a level " << endl;
122                 cursor_.pop_back();
123                 anchor_.pop_back();
124         }
125 }
126
127
128 void LCursor::pop()
129 {
130         lyxerr << "LCursor::pop() " << endl;
131         //BOOST_ASSERT(!cursor_.empty());
132         if (cursor_.size() <= 1)
133                 lyxerr << "### TRYING TO POP FROM EMPTY CURSOR" << endl;
134         else {
135                 cursor_.pop_back();
136                 anchor_.pop_back();
137         }
138 }
139
140
141 UpdatableInset * LCursor::innerInset() const
142 {
143         return cursor_.size() <= 1 ? 0 : cursor_.back().asUpdatableInset();
144 }
145
146
147 LyXText * LCursor::innerText() const
148 {
149         if (cursor_.size() > 1) {
150                 // go up until first non-0 text is hit
151                 // (innermost text is 0 e.g. for mathed and the outer tabular level)
152                 for (int i = cursor_.size() - 1; i >= 1; --i)
153                         if (cursor_[i].text())
154                                 return cursor_[i].text();
155         }
156         return bv_->text();
157 }
158
159
160 void LCursor::updatePos()
161 {
162         if (cursor_.size() > 1)
163                 cached_y_ = bv_->top_y() + cursor_.back().inset()->y();
164 }
165
166
167 void LCursor::getDim(int & asc, int & desc) const
168 {
169         LyXText * txt = innerText();
170
171         if (txt) {
172                 Row const & row = *txt->cursorRow();
173                 asc = row.baseline();
174                 desc = row.height() - asc;
175         } else {
176                 innerInset()->getCursorDim(asc, desc);
177         }
178 }
179
180
181 void LCursor::getPos(int & x, int & y) const
182 {
183         if (cursor_.size() <= 1) {
184                 x = bv_->text()->cursorX();
185                 y = bv_->text()->cursorY();
186 //              y -= bv_->top_y();
187         } else {
188                 // Would be nice to clean this up to make some understandable sense...
189                 UpdatableInset * inset = innerInset();
190                 // Non-obvious. The reason we have to have these
191                 // extra checks is that the ->getCursor() calls rely
192                 // on the inset's own knowledge of its screen position.
193                 // If we scroll up or down in a big enough increment, the
194                 // inset->draw() is not called: this doesn't update
195                 // inset.top_baseline, so getCursor() returns an old value.
196                 // Ugly as you like.
197                 if (inset) {
198                         inset->getCursorPos(cursor_.back().idx_, x, y);
199                         x += inset->x();
200                         y += cached_y_;
201                 }
202         }
203 }
204
205
206 UpdatableInset * LCursor::innerInsetOfType(int code) const
207 {
208         for (int i = cursor_.size() - 1; i >= 1; --i)
209                 if (cursor_[i].asUpdatableInset()->lyxCode() == code)
210                         return cursor_[i].asUpdatableInset();
211         return 0;
212 }
213
214
215 InsetTabular * LCursor::innerInsetTabular() const
216 {
217         return static_cast<InsetTabular *>
218                 (innerInsetOfType(InsetOld::TABULAR_CODE));
219 }
220
221
222 void LCursor::resetAnchor()
223 {
224         anchor_ = cursor_;
225 }
226
227
228 BufferView & LCursor::bv() const
229 {
230         return *bv_;
231 }
232
233
234 MathAtom const & LCursor::prevAtom() const
235 {
236         BOOST_ASSERT(pos() > 0);
237         return cell()[pos() - 1];
238 }
239
240
241 MathAtom & LCursor::prevAtom()
242 {
243         BOOST_ASSERT(pos() > 0);
244         return cell()[pos() - 1];
245 }
246
247
248 MathAtom const & LCursor::nextAtom() const
249 {
250         BOOST_ASSERT(pos() < lastpos());
251         return cell()[pos()];
252 }
253
254
255 MathAtom & LCursor::nextAtom()
256 {
257         BOOST_ASSERT(pos() < lastpos());
258         return cell()[pos()];
259 }
260
261
262 bool LCursor::posLeft()
263 {
264         if (pos() == 0)
265                 return false;
266         --pos();
267         return true;
268 }
269
270
271 bool LCursor::posRight()
272 {
273         if (pos() == lastpos())
274                 return false;
275         ++pos();
276         return true;
277 }