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