]> git.lyx.org Git - lyx.git/blob - src/cursor.C
c3d7c950806215a5211c2498277ef4c8ed710094
[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
24 #include "insets/updatableinset.h"
25 #include "insets/insettabular.h"
26 #include "insets/insettext.h"
27
28 #include <boost/assert.hpp>
29
30 using std::vector;
31 using std::endl;
32
33
34 std::ostream & operator<<(std::ostream & os, CursorItem const & item)
35 {
36         os << " inset: " << item.inset_
37            << " text: " << item.text()
38 //         << " par: " << item.par_
39 //         << " pos: " << item.pos_
40            << " x: " << item.inset_->x()
41            << " y: " << item.inset_->y()
42 ;
43         return os;
44 }
45
46
47 LyXText * CursorItem::text() const
48 {
49         return inset_->getText(0);
50 }
51
52
53 std::ostream & operator<<(std::ostream & os, LCursor const & cursor)
54 {
55         os << "\n";
56         for (size_t i = 0, n = cursor.data_.size(); i != n; ++i)
57                 os << "   " << cursor.data_[i] << "\n";
58         return os;
59 }
60
61
62 LCursor::LCursor(BufferView * bv)
63         : bv_(bv)
64 {}
65
66
67 DispatchResult LCursor::dispatch(FuncRequest const & cmd0)
68 {
69         lyxerr << "\nLCursor::dispatch: " << *this << endl;
70         FuncRequest cmd = cmd0;
71
72         for (int i = data_.size() - 1; i >= 0; --i) {
73                 CursorItem const & citem = data_[i];
74                 lyxerr << "trying to dispatch to inset " << citem.inset_ << endl;
75                 DispatchResult res = citem.inset_->dispatch(cmd);
76                 if (res.update())
77                         bv_->update();
78                 if (res.dispatched()) {
79                         lyxerr << " successfully dispatched to inset " << citem.inset_ << endl;
80                         return DispatchResult(true, true);
81                 }
82                 // remove one level of cursor
83                 switch (res.val()) {
84                         case FINISHED:
85                                 pop(i);
86                                 cmd = FuncRequest(bv_, LFUN_FINISHED_LEFT);
87                                 break;
88                         case FINISHED_RIGHT:
89                                 pop(i);
90                                 cmd = FuncRequest(bv_, LFUN_FINISHED_RIGHT);
91                                 break;
92                         case FINISHED_UP: 
93                                 pop(i);
94                                 cmd = FuncRequest(bv_, LFUN_FINISHED_UP);
95                                 break;
96                         case FINISHED_DOWN:
97                                 pop(i);
98                                 cmd = FuncRequest(bv_, LFUN_FINISHED_DOWN);
99                                 break;
100                         default:
101                                 lyxerr << "not handled on level " << i << " val: " << res.val() << endl;
102                                 break;
103                 }
104         }
105         lyxerr << "trying to dispatch to main text " << bv_->text << endl;
106         DispatchResult res = bv_->text->dispatch(cmd);
107         lyxerr << "   result: " << res.val() << endl;
108         return res;
109 }
110
111
112 void LCursor::push(UpdatableInset * inset)
113 {
114         lyxerr << "LCursor::push()  inset: " << inset << endl;
115         data_.push_back(CursorItem(inset));
116         cached_y_ = bv_->top_y() + inset->y();
117 }
118
119
120 void LCursor::pop(int depth)
121 {
122         lyxerr << "LCursor::pop() to " << depth << endl;
123         while (depth < data_.size()) {
124                 lyxerr <<   "LCursor::pop a level " << endl;
125                 data_.pop_back();
126         }
127 }
128
129
130 void LCursor::pop()
131 {
132         lyxerr << "LCursor::pop() " << endl;
133         //BOOST_ASSERT(!data_.empty());
134         if (data_.empty())
135                 lyxerr << "### TRYING TO POP FROM EMPTY CURSOR" << endl;
136         else
137                 data_.pop_back();
138 }
139
140
141 UpdatableInset * LCursor::innerInset() const
142 {
143         return data_.empty() ? 0 : data_.back().inset_;
144 }
145
146
147 LyXText * LCursor::innerText() const
148 {
149         if (!data_.empty()) {
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 = data_.size() - 1; i >= 0; --i)
153                         if (data_[i].text())
154                                 return data_[i].text();
155         }
156         return bv_->text;
157 }
158
159
160 void LCursor::getPos(int & x, int & y) const
161 {
162         if (data_.empty()) {
163                 x = bv_->text->cursor.x();
164                 y = bv_->text->cursor.y();
165 //              y -= bv_->top_y();
166         } else {
167                 // Would be nice to clean this up to make some understandable sense...
168                 UpdatableInset * inset = innerInset();
169                 // Non-obvious. The reason we have to have these
170                 // extra checks is that the ->getCursor() calls rely
171                 // on the inset's own knowledge of its screen position.
172                 // If we scroll up or down in a big enough increment, the
173                 // inset->draw() is not called: this doesn't update
174                 // inset.top_baseline, so getCursor() returns an old value.
175                 // Ugly as you like.
176                 //inset->getCursorPos(bv_, x, y);
177                 //y = inset->insetInInsetY() + bv_->text->cursor.y();
178                 inset->getCursorPos(bv_, x, y);
179                 x += inset->x();
180                 y += cached_y_;
181         }
182 }
183
184
185 UpdatableInset * LCursor::innerInsetOfType(int code) const
186 {
187         for (int i = data_.size() - 1; i >= 0; --i)
188                 if (data_[i].inset_->lyxCode() == code)
189                         return data_[i].inset_;
190         return 0;
191 }
192
193         
194 InsetTabular * LCursor::innerInsetTabular() const
195 {
196         return static_cast<InsetTabular *>
197                 (innerInsetOfType(InsetOld::TABULAR_CODE));
198 }