]> git.lyx.org Git - lyx.git/blob - src/insets/insetcollapsable.C
03f214c2c1eb9696288d0d8f6a3db4012c7276d2
[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 #include "font.h"
28 #include "lyxlex.h"
29
30 class LyXText;
31
32 using std::ostream;
33 using std::endl;
34 using std::max;
35
36
37 InsetCollapsable::InsetCollapsable(bool collapsed)
38         : UpdatableInset(), collapsed_(collapsed), 
39           button_length(0), button_top_y(0), button_bottom_y(0),
40           need_update(FULL), label("Label"),
41 #if 0
42         autocollapse(false),
43 #endif
44           oldWidth(0)
45 {
46         inset.setOwner(this);
47         inset.setAutoBreakRows(true);
48         inset.setDrawFrame(0, InsetText::ALWAYS);
49         inset.setFrameColor(0, LColor::collapsableframe);
50         setInsetName("Collapsable");
51 }
52
53
54 InsetCollapsable::InsetCollapsable(InsetCollapsable const & in, bool same_id)
55         : UpdatableInset(in, same_id), collapsed_(in.collapsed_), 
56           framecolor(in.framecolor), labelfont(in.labelfont),
57           button_length(0), button_top_y(0), button_bottom_y(0),
58           need_update(FULL), label(in.label),
59 #if 0
60           autocollapse(in.autocollapse),
61 #endif
62           oldWidth(0)
63 {
64         inset.init(&(in.inset), same_id);
65         inset.setOwner(this);
66 }
67
68
69 bool InsetCollapsable::insertInset(BufferView * bv, Inset * in)
70 {
71         if (!insetAllowed(in->lyxCode())) {
72                 lyxerr << "InsetCollapsable::InsertInset: "
73                         "Unable to insert inset." << endl;
74                 return false;
75         }
76         return inset.insertInset(bv, in);
77 }
78
79
80 void InsetCollapsable::write(Buffer const * buf, ostream & os) const
81 {
82         os << "collapsed " << tostr(collapsed_) << "\n";
83         inset.writeParagraphData(buf, os);
84 }
85
86
87
88 void InsetCollapsable::read(Buffer const * buf, LyXLex & lex)
89 {
90         if (lex.IsOK()) {
91                 lex.next();
92                 string const token = lex.GetString();
93                 if (token == "collapsed") {
94                         lex.next();
95                         collapsed_ = lex.GetBool();
96                 } else {
97                         lyxerr << "InsetCollapsable::Read: Missing collapsed!"
98                                << endl;
99                         // Take countermeasures
100                         lex.pushToken(token);
101                 }
102         }
103         inset.read(buf, lex);
104 }
105
106
107 int InsetCollapsable::ascent_collapsed() const
108 {
109         int width = 0;
110         int ascent = 0;
111         int descent = 0;
112         lyxfont::buttonText(label, labelfont, width, ascent, descent);
113         return ascent;
114 }
115
116
117 int InsetCollapsable::descent_collapsed() const
118 {
119         int width = 0;
120         int ascent = 0;
121         int descent = 0;
122         lyxfont::buttonText(label, labelfont, width, ascent, descent);
123         return descent;
124 }
125
126
127 //int InsetCollapsable::width_collapsed(Painter & pain) const
128 int InsetCollapsable::width_collapsed() const
129 {
130         int width;
131         int ascent;
132         int descent;
133         lyxfont::buttonText(label, labelfont, width, ascent, descent);
134         return width + (2*TEXT_TO_INSET_OFFSET);
135 }
136
137
138 int InsetCollapsable::ascent(BufferView * /*bv*/, LyXFont const &) const
139 {
140         return ascent_collapsed();
141 }
142
143
144 int InsetCollapsable::descent(BufferView * bv, LyXFont const & font) const
145 {
146         if (collapsed_) 
147                 return descent_collapsed();
148
149         return descent_collapsed()
150                 + inset.descent(bv, font)
151                 + inset.ascent(bv, font)
152                 + TEXT_TO_BOTTOM_OFFSET;
153 }
154
155
156 int InsetCollapsable::width(BufferView * bv, LyXFont const & font) const
157 {
158         if (collapsed_) 
159                 return width_collapsed();
160
161         int widthCollapsed = width_collapsed();
162
163         return (inset.width(bv, font) > widthCollapsed) ?
164                 inset.width(bv, font) : widthCollapsed;
165 }
166
167
168 void InsetCollapsable::draw_collapsed(Painter & pain,
169                                       int baseline, float & x) const
170 {
171         pain.buttonText(int(x) + TEXT_TO_INSET_OFFSET,
172                         baseline, label, labelfont);
173         x += width_collapsed();
174 }
175
176
177 void InsetCollapsable::draw(BufferView * bv, LyXFont const & f, 
178                             int baseline, float & x, bool cleared) const
179 {
180         if (nodraw())
181                 return;
182
183         Painter & pain = bv->painter();
184
185         button_length = width_collapsed();
186         button_top_y = -ascent(bv, f);
187         button_bottom_y = -ascent(bv, f) + ascent_collapsed() +
188                 descent_collapsed();
189
190         if (!isOpen()) {
191                 draw_collapsed(pain, baseline, x);
192                 x += TEXT_TO_INSET_OFFSET;
193                 return;
194         }
195
196         float old_x = x;
197
198         if (!owner())
199                 x += static_cast<float>(scroll());
200
201         if (!cleared && (inset.need_update == InsetText::FULL ||
202                          inset.need_update == InsetText::INIT ||
203                          top_x != int(x) ||
204                          top_baseline != baseline))
205         {
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(bv, LyXText::CHANGED_IN_DRAW);
210                 return;
211         }
212
213         top_x = int(x);
214         top_baseline = baseline;
215
216         int const bl = baseline - ascent(bv, f) + ascent_collapsed();
217         
218         draw_collapsed(pain, bl, old_x);
219         inset.draw(bv, f, 
220                            bl + descent_collapsed() + inset.ascent(bv, f),
221                            x, cleared);
222         need_update = NONE;
223 }
224
225
226 void InsetCollapsable::edit(BufferView * bv, int xp, int yp,
227                             unsigned int button)
228 {
229         UpdatableInset::edit(bv, xp, yp, button);
230
231         if (collapsed_) {
232                 collapsed_ = false;
233                 if (!bv->lockInset(this))
234                         return;
235                 bv->updateInset(this, true);
236                 inset.edit(bv);
237         } else {
238                 if (!bv->lockInset(this))
239                         return;
240                 if (yp <= button_bottom_y) {
241                         inset.edit(bv);
242                 } else {
243                         LyXFont font(LyXFont::ALL_SANE);
244                         int yy = ascent(bv, font) + yp -
245                                 (ascent_collapsed() +
246                                  descent_collapsed() +
247                                  inset.ascent(bv, font));
248                         inset.edit(bv, xp, yy, button);
249                 }
250         }
251 }
252
253
254 void InsetCollapsable::edit(BufferView * bv, bool front)
255 {
256         UpdatableInset::edit(bv, front);
257
258         if (collapsed_) {
259                 collapsed_ = false;
260                 if (!bv->lockInset(this))
261                         return;
262                 inset.setUpdateStatus(bv, InsetText::FULL);
263                 bv->updateInset(this, true);
264                 inset.edit(bv, front);
265         } else {
266                 if (!bv->lockInset(this))
267                         return;
268                 inset.edit(bv, front);
269         }
270 }
271
272
273 Inset::EDITABLE InsetCollapsable::editable() const
274 {
275         if (collapsed_)
276                 return IS_EDITABLE;
277         return HIGHLY_EDITABLE;
278 }
279
280
281 void InsetCollapsable::insetUnlock(BufferView * bv)
282 {
283 #if 0
284         if (autocollapse) {
285                 if (change_label_with_text) {
286                         draw_label = get_new_label();
287                 } else {
288                         draw_label = label;
289                 }
290                 collapsed_ = true;
291         }
292 #endif
293         inset.insetUnlock(bv);
294         if (scroll())
295                 scroll(bv, 0.0F);
296         bv->updateInset(this, false);
297 }
298
299
300 void InsetCollapsable::insetButtonPress(BufferView * bv,
301                                         int x, int y, int button)
302 {
303         if (!collapsed_ && (y > button_bottom_y)) {
304                 LyXFont font(LyXFont::ALL_SANE);
305                 int yy = ascent(bv, font) + y -
306                     (ascent_collapsed() +
307                      descent_collapsed() +
308                      inset.ascent(bv, font));
309                 inset.insetButtonPress(bv, x, yy, button);
310         }
311 }
312
313
314 void InsetCollapsable::insetButtonRelease(BufferView * bv,
315                                           int x, int y, int button)
316 {
317         if ((x >= 0)  && (x < button_length) &&
318             (y >= button_top_y) &&  (y <= button_bottom_y))
319         {
320                 if (collapsed_) {
321                         collapsed_ = false;
322 // should not be called on inset open!
323 //                      inset.insetButtonRelease(bv, 0, 0, button);
324                         inset.setUpdateStatus(bv, InsetText::FULL);
325                         bv->updateInset(this, true);
326                 } else {
327                         collapsed_ = true;
328                         bv->unlockInset(this);
329                         bv->updateInset(this, true);
330                 }
331         } else if (!collapsed_ && (y > button_bottom_y)) {
332                 LyXFont font(LyXFont::ALL_SANE);
333                 int yy = ascent(bv, font) + y -
334                     (ascent_collapsed() +
335                      descent_collapsed() +
336                      inset.ascent(bv, font));
337                 inset.insetButtonRelease(bv, x, yy, button);
338         }
339 }
340
341
342 void InsetCollapsable::insetMotionNotify(BufferView * bv,
343                                          int x, int y, int state)
344 {
345         if (y > button_bottom_y) {
346                 LyXFont font(LyXFont::ALL_SANE);
347                 int yy = ascent(bv, font) + y -
348                     (ascent_collapsed() +
349                      descent_collapsed() +
350                      inset.ascent(bv, font));
351                 inset.insetMotionNotify(bv, x, yy, state);
352         }
353 }
354
355
356 void InsetCollapsable::insetKeyPress(XKeyEvent * xke)
357 {
358         inset.insetKeyPress(xke);
359 }
360
361
362 int InsetCollapsable::latex(Buffer const * buf, ostream & os,
363                             bool fragile, bool free_spc) const
364 {
365         return inset.latex(buf, os, fragile, free_spc);
366 }
367
368
369 int InsetCollapsable::getMaxWidth(BufferView * bv,
370                                   UpdatableInset const * inset) const
371 {
372         int const w = UpdatableInset::getMaxWidth(bv, inset);
373
374         if (w < 0) {
375                 // What does a negative max width signify? (Lgb)
376                 // Use the max width of the draw-area (Jug)
377                 return w;
378         }
379         // should be at least 30 pixels !!!
380         return max(30, w - width_collapsed());
381 }
382
383
384 void InsetCollapsable::update(BufferView * bv, LyXFont const & font,
385                               bool reinit)
386 {
387         inset.update(bv, font, reinit);
388 }
389
390
391 UpdatableInset::RESULT
392 InsetCollapsable::localDispatch(BufferView * bv, kb_action action,
393                                 string const & arg)
394 {
395         UpdatableInset::RESULT result = inset.localDispatch(bv, action, arg);
396         if (result == FINISHED)
397                 bv->unlockInset(this);
398         return result;
399 }
400
401
402 bool InsetCollapsable::lockInsetInInset(BufferView * bv, UpdatableInset * in)
403 {
404         if (&inset == in)
405                 return true;
406         return inset.lockInsetInInset(bv, in);
407 }
408
409
410 bool InsetCollapsable::unlockInsetInInset(BufferView * bv, UpdatableInset * in,
411                                           bool lr)
412 {
413         if (&inset == in) {
414                 bv->unlockInset(this);
415                 return true;
416         }
417         return inset.unlockInsetInInset(bv, in, lr);
418 }
419
420
421 bool InsetCollapsable::updateInsetInInset(BufferView * bv, Inset *in)
422 {
423         if (&inset == in)
424                 return true;
425         return inset.updateInsetInInset(bv, in);
426 }
427
428
429 unsigned int InsetCollapsable::insetInInsetY()
430 {
431         return inset.insetInInsetY() - (top_baseline - inset.y());
432 }
433
434
435 void InsetCollapsable::validate(LaTeXFeatures & features) const
436 {
437         inset.validate(features);
438 }
439
440
441 void InsetCollapsable::getCursorPos(BufferView * bv, int & x, int & y) const
442 {
443         inset.getCursorPos(bv, x , y);
444 }
445
446
447 void InsetCollapsable::toggleInsetCursor(BufferView * bv)
448 {
449         inset.toggleInsetCursor(bv);
450 }
451
452
453 void InsetCollapsable::showInsetCursor(BufferView * bv, bool show)
454 {
455         inset.showInsetCursor(bv, show);
456 }
457
458
459 void InsetCollapsable::hideInsetCursor(BufferView * bv)
460 {
461         inset.hideInsetCursor(bv);
462 }
463
464
465 UpdatableInset * InsetCollapsable::getLockingInset() const
466 {
467         UpdatableInset * in = inset.getLockingInset();
468         if (const_cast<InsetText *>(&inset) == in)
469                 return const_cast<InsetCollapsable *>(this);
470         return in;
471 }
472
473
474 UpdatableInset * InsetCollapsable::getFirstLockingInsetOfType(Inset::Code c)
475 {
476         if (c == lyxCode())
477                 return this;
478         return inset.getFirstLockingInsetOfType(c);
479 }
480
481
482 void InsetCollapsable::setFont(BufferView * bv, LyXFont const & font,
483                                bool toggleall, bool selectall)
484 {
485         inset.setFont(bv, font, toggleall, selectall);
486 }
487
488
489 bool InsetCollapsable::doClearArea() const
490 {
491         return inset.doClearArea();
492 }
493
494
495 LyXText * InsetCollapsable::getLyXText(BufferView const * bv,
496                                        bool const recursive) const
497 {
498         return inset.getLyXText(bv, recursive);
499 }
500
501
502 void InsetCollapsable::deleteLyXText(BufferView * bv, bool recursive) const
503 {
504         inset.deleteLyXText(bv, recursive);
505 }
506
507
508 void InsetCollapsable::resizeLyXText(BufferView * bv, bool force) const
509 {
510         inset.resizeLyXText(bv, force);
511         LyXFont font(LyXFont::ALL_SANE);
512         oldWidth = width(bv, font);
513 }
514
515
516 std::vector<string> const InsetCollapsable::getLabelList() const
517 {
518         return inset.getLabelList();
519 }
520
521
522 bool InsetCollapsable::nodraw() const
523 {
524         return inset.nodraw();
525 }
526
527  
528 int InsetCollapsable::scroll(bool recursive) const
529 {
530         int sx = UpdatableInset::scroll(false);
531
532         if (recursive)
533                 sx += inset.scroll(recursive);
534
535         return sx;
536 }
537
538
539 Paragraph * InsetCollapsable::getParFromID(int id) const
540 {
541         return inset.getParFromID(id);
542 }
543
544
545 Paragraph * InsetCollapsable::firstParagraph() const
546 {
547         return inset.firstParagraph();
548 }
549
550
551 LyXCursor const & InsetCollapsable::cursor(BufferView * bv) const
552 {
553         return inset.cursor(bv);
554 }
555
556
557 Inset * InsetCollapsable::getInsetFromID(int id_arg) const
558 {
559         if (id_arg == id())
560                 return const_cast<InsetCollapsable *>(this);
561         return inset.getInsetFromID(id_arg);
562 }
563
564
565 void InsetCollapsable::open(BufferView * bv)
566 {
567         if (!collapsed_) return;
568         
569         collapsed_ = false;
570         bv->updateInset(this, true);
571 }
572
573
574 void InsetCollapsable::close(BufferView * bv)
575 {
576         if (collapsed_)
577                 return;
578         
579         collapsed_ = true;
580         bv->updateInset(this, true);
581 }
582
583
584 void InsetCollapsable::setLabel(string const & l)
585 {
586         label = l;
587 }