]> git.lyx.org Git - lyx.git/blob - src/insets/insetcollapsable.C
a999b83d47ae137ffb0e4c4fe6c10a03e327f97a
[lyx.git] / src / insets / insetcollapsable.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *       
6  *          Copyright 1998-2001 The LyX Team.
7  *
8  * ======================================================
9  */
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include "insetcollapsable.h"
18 #include "gettext.h"
19 #include "lyxfont.h"
20 #include "BufferView.h"
21 #include "Painter.h"
22 #include "insets/insettext.h"
23 #include "support/LOstream.h"
24 #include "support/lstrings.h"
25 #include "debug.h"
26 #include "lyxtext.h"
27
28 class LyXText;
29
30 using std::ostream;
31 using std::endl;
32 using std::max;
33
34 InsetCollapsable::InsetCollapsable()
35         : UpdatableInset()
36 {
37         inset.setOwner(this);
38         collapsed = false;
39         label = "Label";
40         autocollapse = true;
41         inset.SetAutoBreakRows(true);
42         inset.SetDrawFrame(0, InsetText::ALWAYS);
43         inset.SetFrameColor(0, LColor::footnoteframe);
44         button_length = button_top_y = button_bottom_y = 0;
45         setInsetName("Collapsable");
46         widthCollapsed = oldWidth = 0;
47         need_update = FULL;
48 }
49
50
51 Inset * InsetCollapsable::Clone(Buffer const &) const
52 {
53         InsetCollapsable * result = new InsetCollapsable();
54         result->inset.init(&inset);
55         result->inset.setOwner(result);
56
57         result->collapsed = collapsed;
58         return result;
59 }
60
61
62 bool InsetCollapsable::InsertInset(BufferView * bv, Inset * in)
63 {
64         if (!InsertInsetAllowed(in)) {
65                 lyxerr << "InsetCollapsable::InsertInset: "
66                         "Unable to insert inset." << endl;
67                 return false;
68         }
69         return inset.InsertInset(bv, in);
70 }
71
72
73 void InsetCollapsable::Write(Buffer const * buf, ostream & os) const
74 {
75         os << "collapsed " << tostr(collapsed) << "\n";
76         inset.WriteParagraphData(buf, os);
77 }
78
79
80
81 void InsetCollapsable::Read(Buffer const * buf, LyXLex & lex)
82 {
83         if (lex.IsOK()) {
84                 lex.next();
85                 string const token = lex.GetString();
86                 if (token == "collapsed") {
87                         lex.next();
88                         collapsed = lex.GetBool();
89                 } else {
90                         lyxerr << "InsetCollapsable::Read: Missing collapsed!"
91                                    << endl;
92                 }
93         }
94         inset.Read(buf, lex);
95 }
96
97
98 int InsetCollapsable::ascent_collapsed(Painter & pain, LyXFont const &) const
99 {
100         int width = 0;
101         int ascent = 0;
102         int descent = 0;
103         pain.buttonText(0, 0, label, labelfont, false, 
104                                         width, ascent, descent);
105         return ascent;
106 }
107
108
109 int InsetCollapsable::descent_collapsed(Painter & pain, LyXFont const &) const
110 {
111         int width = 0;
112         int ascent = 0;
113         int descent = 0;
114         pain.buttonText(0, 0, label, labelfont, false, 
115                                         width, ascent, descent);
116         return descent;
117 }
118
119
120 int InsetCollapsable::width_collapsed(Painter & pain, LyXFont const &) const
121 {
122         int width;
123         int ascent;
124         int descent;
125         pain.buttonText(TEXT_TO_INSET_OFFSET, 0, label, labelfont, false,
126                                         width, ascent, descent);
127         return width + (2*TEXT_TO_INSET_OFFSET);
128 }
129
130
131 int InsetCollapsable::ascent(BufferView * bv, LyXFont const & font) const
132 {
133         return ascent_collapsed(bv->painter(), font);
134 }
135
136
137 int InsetCollapsable::descent(BufferView * bv, LyXFont const & font) const
138 {
139         if (collapsed) 
140                 return descent_collapsed(bv->painter(), font);
141
142         return descent_collapsed(bv->painter(), font) + inset.descent(bv, font) +
143                 inset.ascent(bv, font) + TEXT_TO_BOTTOM_OFFSET;
144 }
145
146
147 int InsetCollapsable::width(BufferView * bv, LyXFont const & font) const
148 {
149         if (collapsed) 
150                 return widthCollapsed;
151
152         return (inset.width(bv, font) > widthCollapsed) ?
153                 inset.width(bv, font) : widthCollapsed;
154 }
155
156
157 void InsetCollapsable::draw_collapsed(Painter & pain, LyXFont const &,
158                                                                           int baseline, float & x) const
159 {
160         int width = 0;
161         pain.buttonText(int(x) + TEXT_TO_INSET_OFFSET,
162                                         baseline, label, labelfont, true, width);
163         x += width + TEXT_TO_INSET_OFFSET;
164 }
165
166
167 void InsetCollapsable::draw(BufferView * bv, LyXFont const & f, 
168                                                         int baseline, float & x, bool cleared) const
169 {
170         Painter & pain = bv->painter();
171
172         button_length = widthCollapsed;
173         button_top_y = -ascent(bv, f);
174         button_bottom_y = -ascent(bv, f) + ascent_collapsed(pain,f) +
175         descent_collapsed(pain, f);
176         if (collapsed) {
177                 draw_collapsed(pain, f, baseline, x);
178                 x += TEXT_TO_INSET_OFFSET;
179                 return;
180         }
181
182         if (!cleared && ((inset.need_update == InsetText::FULL) ||
183                                          (inset.need_update == InsetText::INIT) ||
184                                          (top_x != int(x)) || (top_baseline != baseline))) {
185                 int w =  owner() ? width(bv, f) : pain.paperWidth();
186                 int h = ascent(bv, f) + descent(bv, f);
187                 int tx = (needFullRow() && !owner()) ? 0 : int(x);
188                 int ty = max(0, baseline - ascent(bv, f));
189                 
190                 if ((ty + h) > pain.paperHeight())
191                         h = pain.paperHeight();
192                 if ((top_x + w) > pain.paperWidth())
193                         w = pain.paperWidth();
194                 if (baseline < 0)
195                         h += (baseline - ascent(bv, f));
196                 pain.fillRectangle(tx, ty - 1, w, h + 2);
197                 cleared = true;
198         }
199
200         top_x = int(x);
201         top_baseline = baseline;
202
203         float dummy = x;
204         int bl = baseline - ascent(bv, f) + ascent_collapsed(pain, f);
205
206         draw_collapsed(pain, f, bl, dummy);
207         inset.draw(bv, f, 
208                            bl + descent_collapsed(pain, f) + inset.ascent(bv, f),
209                            x, cleared);
210         need_update = NONE;
211 }
212
213
214 void InsetCollapsable::Edit(BufferView * bv, int xp, int yp, unsigned int button)
215 {
216         UpdatableInset::Edit(bv, xp, yp, button);
217
218         if (collapsed && autocollapse) {
219                 collapsed = false;
220                 if (!bv->lockInset(this))
221                         return;
222                 bv->updateInset(this, false);
223                 inset.Edit(bv, 0, 0, button);
224         } else if (!collapsed) {
225                 if (!bv->lockInset(this))
226                         return;
227                 inset.Edit(bv, xp, yp+(top_baseline - inset.y()), button);
228         }
229 }
230
231
232 Inset::EDITABLE InsetCollapsable::Editable() const
233 {
234         if (collapsed)
235                 return IS_EDITABLE;
236         return HIGHLY_EDITABLE;
237 }
238
239
240 void InsetCollapsable::InsetUnlock(BufferView * bv)
241 {
242         if (autocollapse) {
243                 collapsed = true;
244         }
245         inset.InsetUnlock(bv);
246         bv->updateInset(this, false);
247 }
248
249
250 void InsetCollapsable::InsetButtonPress(BufferView * bv,int x,int y,int button)
251 {
252         if (!collapsed && (y > button_bottom_y)) {
253                 inset.InsetButtonPress(bv, x, y+(top_baseline - inset.y()), button);
254         }
255 }
256
257
258 void InsetCollapsable::InsetButtonRelease(BufferView * bv,
259                                           int x, int y, int button)
260 {
261         if ((x >= 0)  && (x < button_length) &&
262                 (y >= button_top_y) &&  (y <= button_bottom_y)) {
263                 if (collapsed) {
264                         collapsed = false;
265                         inset.InsetButtonRelease(bv, 0, 0, button);
266                         bv->updateInset(this, false);
267                 } else {
268                         collapsed = true;
269                         bv->unlockInset(this);
270                         bv->updateInset(this, false);
271                 }
272         } else if (!collapsed && (y > button_top_y)) {
273                 inset.InsetButtonRelease(bv, x, y+(top_baseline-inset.y()), button);
274         }
275 }
276
277
278 void InsetCollapsable::InsetMotionNotify(BufferView * bv,
279                                          int x, int y, int state)
280 {
281         if (x > button_bottom_y) {
282                 inset.InsetMotionNotify(bv, x, y+(top_baseline - inset.y()), state);
283         }
284 }
285
286
287 void InsetCollapsable::InsetKeyPress(XKeyEvent * xke)
288 {
289         inset.InsetKeyPress(xke);
290 }
291
292
293 int InsetCollapsable::Latex(Buffer const * buf, ostream & os,
294                                 bool fragile, bool free_spc) const
295 {
296         return inset.Latex(buf, os, fragile, free_spc);
297 }
298
299
300 int InsetCollapsable::getMaxWidth(BufferView * bv,
301                                   UpdatableInset const * inset) const
302 {
303         int const w = UpdatableInset::getMaxWidth(bv, inset);
304
305         if (w < 0) {
306                 // What does a negative max width signify? (Lgb)
307                 // Use the max width of the draw-area (Jug)
308                 return w;
309         }
310         // should be at least 30 pixels !!!
311         return max(30, w - widthCollapsed);
312 }
313
314
315 void InsetCollapsable::update(BufferView * bv, LyXFont const & font,
316                                   bool reinit)
317 {
318         if (reinit) {
319                 need_update = FULL;
320                 if (owner())
321                         owner()->update(bv, font, true);
322                 return;
323         }
324         if (!widthCollapsed) {
325                 widthCollapsed = width_collapsed(bv->painter(), font);
326                 inset.resizeLyXText(bv);
327                 need_update = FULL;
328                 if (owner()) {
329                         owner()->update(bv, font);
330                         return;
331                 }
332         }
333         if (oldWidth != width(bv, font)) {
334                 oldWidth = width(bv, font);
335                 inset.resizeLyXText(bv);
336                 need_update = FULL;
337                 if (owner()) {
338                         owner()->update(bv, font);
339                         return;
340                 }
341         }
342         inset.update(bv, font);
343 }
344
345
346 UpdatableInset::RESULT
347 InsetCollapsable::LocalDispatch(BufferView * bv, kb_action action,
348                                 string const & arg)
349 {
350         UpdatableInset::RESULT result = inset.LocalDispatch(bv, action, arg);
351         if (result == FINISHED)
352                 bv->unlockInset(this);
353         return result;
354 }
355
356
357 bool InsetCollapsable::LockInsetInInset(BufferView * bv, UpdatableInset * in)
358 {
359         if (&inset == in)
360                 return true;
361         return inset.LockInsetInInset(bv, in);
362 }
363
364
365 bool InsetCollapsable::UnlockInsetInInset(BufferView * bv, UpdatableInset * in,
366                                           bool lr)
367 {
368         if (&inset == in) {
369                 bv->unlockInset(this);
370                 return true;
371         }
372         return inset.UnlockInsetInInset(bv, in, lr);
373 }
374
375
376 bool InsetCollapsable::UpdateInsetInInset(BufferView * bv, Inset *in)
377 {
378         if (&inset == in)
379                 return true;
380         return inset.UpdateInsetInInset(bv, in);
381 }
382
383
384 unsigned int InsetCollapsable::InsetInInsetY()
385 {
386         return inset.InsetInInsetY() - (top_baseline - inset.y());
387 }
388
389
390 void InsetCollapsable::Validate(LaTeXFeatures & features) const
391 {
392         inset.Validate(features);
393 }
394
395
396 void InsetCollapsable::GetCursorPos(BufferView * bv, int & x, int & y) const
397 {
398         inset.GetCursorPos(bv, x , y);
399 }
400
401
402 void InsetCollapsable::ToggleInsetCursor(BufferView * bv)
403 {
404         inset.ToggleInsetCursor(bv);
405 }
406
407
408 UpdatableInset * InsetCollapsable::GetLockingInset()
409 {
410         UpdatableInset * in = inset.GetLockingInset();
411         if (&inset == in)
412                 return this;
413         return in;
414 }
415
416
417 UpdatableInset * InsetCollapsable::GetFirstLockingInsetOfType(Inset::Code c)
418 {
419         if (c == LyxCode())
420                 return this;
421         return inset.GetFirstLockingInsetOfType(c);
422 }
423
424
425 void InsetCollapsable::SetFont(BufferView * bv,
426                                                            LyXFont const & font, bool toggleall)
427 {
428         inset.SetFont(bv, font, toggleall);
429 }
430
431
432 bool InsetCollapsable::doClearArea() const
433 {
434         return inset.doClearArea();
435 }
436
437
438 LyXText * InsetCollapsable::getLyXText(BufferView const * bv,
439                                            bool const recursive) const
440 {
441         return inset.getLyXText(bv, recursive);
442 }
443
444
445 void InsetCollapsable::deleteLyXText(BufferView * bv, bool recursive) const
446 {
447         inset.deleteLyXText(bv, recursive);
448 }
449
450
451 void InsetCollapsable::resizeLyXText(BufferView * bv) const
452 {
453         inset.resizeLyXText(bv);
454         LyXFont font(LyXFont::ALL_SANE);
455         oldWidth = width(bv, font);
456 }