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