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