]> git.lyx.org Git - lyx.git/blob - src/cursor.C
3aa3273cf92e8047340283ebbb04eadc9eacc7d5
[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, CursorItem const & item)
36 {
37         os << " inset: " << item.inset_
38            << " text: " << item.text()
39 //         << " par: " << item.par_
40 //         << " pos: " << item.pos_
41            << " x: " << item.inset_->x()
42            << " y: " << item.inset_->y()
43 ;
44         return os;
45 }
46
47
48 LyXText * CursorItem::text() const
49 {
50         return inset_->getText(0);
51 }
52
53
54 std::ostream & operator<<(std::ostream & os, LCursor const & cursor)
55 {
56         os << "\n";
57         for (size_t i = 0, n = cursor.data_.size(); i != n; ++i)
58                 os << "   " << cursor.data_[i] << "\n";
59         return os;
60 }
61
62
63 LCursor::LCursor(BufferView * bv)
64         : bv_(bv)
65 {}
66
67
68 DispatchResult LCursor::dispatch(FuncRequest const & cmd0)
69 {
70         lyxerr << "\nLCursor::dispatch: " << *this << endl;
71         FuncRequest cmd = cmd0;
72
73         for (int i = data_.size() - 1; i >= 0; --i) {
74                 CursorItem const & citem = data_[i];
75                 lyxerr << "trying to dispatch to inset " << citem.inset_ << endl;
76                 DispatchResult res = citem.inset_->dispatch(cmd);
77                 if (res.update())
78                         bv_->update();
79                 if (res.dispatched()) {
80                         lyxerr << " successfully dispatched to inset " << citem.inset_ << endl;
81                         return DispatchResult(true, true);
82                 }
83                 // remove one level of cursor
84                 switch (res.val()) {
85                         case FINISHED:
86                                 pop(i);
87                                 cmd = FuncRequest(bv_, LFUN_FINISHED_LEFT);
88                                 break;
89                         case FINISHED_RIGHT:
90                                 pop(i);
91                                 cmd = FuncRequest(bv_, LFUN_FINISHED_RIGHT);
92                                 break;
93                         case FINISHED_UP: 
94                                 pop(i);
95                                 cmd = FuncRequest(bv_, LFUN_FINISHED_UP);
96                                 break;
97                         case FINISHED_DOWN:
98                                 pop(i);
99                                 cmd = FuncRequest(bv_, LFUN_FINISHED_DOWN);
100                                 break;
101                         default:
102                                 lyxerr << "not handled on level " << i << " val: " << res.val() << endl;
103                                 break;
104                 }
105         }
106         lyxerr << "trying to dispatch to main text " << bv_->text << endl;
107         DispatchResult res = bv_->text->dispatch(cmd);
108         lyxerr << "   result: " << res.val() << endl;
109         return res;
110 }
111
112
113 void LCursor::push(UpdatableInset * inset)
114 {
115         lyxerr << "LCursor::push()  inset: " << inset << endl;
116         data_.push_back(CursorItem(inset));
117         cached_y_ = bv_->top_y() + innerInset()->y();
118 }
119
120
121 void LCursor::pop(int depth)
122 {
123         lyxerr << "LCursor::pop() to " << depth << endl;
124         while (depth < data_.size()) {
125                 lyxerr <<   "LCursor::pop a level " << endl;
126                 data_.pop_back();
127         }
128 }
129
130
131 void LCursor::pop()
132 {
133         lyxerr << "LCursor::pop() " << endl;
134         //BOOST_ASSERT(!data_.empty());
135         if (data_.empty())
136                 lyxerr << "### TRYING TO POP FROM EMPTY CURSOR" << endl;
137         else
138                 data_.pop_back();
139 }
140
141
142 UpdatableInset * LCursor::innerInset() const
143 {
144         return data_.empty() ? 0 : data_.back().inset_;
145 }
146
147
148 LyXText * LCursor::innerText() const
149 {
150         if (!data_.empty()) {
151                 // go up until first non-0 text is hit
152                 // (innermost text is 0 e.g. for mathed and the outer tabular level)
153                 for (int i = data_.size() - 1; i >= 0; --i)
154                         if (data_[i].text())
155                                 return data_[i].text();
156         }
157         return bv_->text;
158 }
159
160
161 void LCursor::updatePos()
162 {
163         if (!data_.empty())
164                 cached_y_ = bv_->top_y() + innerInset()->y();
165 }
166
167
168 void LCursor::getDim(int & asc, int & desc) const
169 {
170         LyXText * txt = innerText();
171         
172         if (txt) {
173                 Row const & row = *txt->cursorRow();
174                 asc = row.baseline();
175                 desc = row.height() - asc;
176         } else
177                 innerInset()->getCursorDim(bv_, asc, desc);
178 }
179
180
181 void LCursor::getPos(int & x, int & y) const
182 {
183         if (data_.empty()) {
184                 x = bv_->text->cursor.x();
185                 y = bv_->text->cursor.y();
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                 //inset->getCursorPos(bv_, x, y);
198                 //y = inset->insetInInsetY() + bv_->text->cursor.y();
199                 inset->getCursorPos(bv_, x, y);
200                 x += inset->x();
201                 y += cached_y_;
202         }
203 }
204
205
206 UpdatableInset * LCursor::innerInsetOfType(int code) const
207 {
208         for (int i = data_.size() - 1; i >= 0; --i)
209                 if (data_[i].inset_->lyxCode() == code)
210                         return data_[i].inset_;
211         return 0;
212 }
213
214         
215 InsetTabular * LCursor::innerInsetTabular() const
216 {
217         return static_cast<InsetTabular *>
218                 (innerInsetOfType(InsetOld::TABULAR_CODE));
219 }