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