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