]> git.lyx.org Git - lyx.git/blob - src/insets/insetcollapsable.C
get rid of same_id from function signatures
[lyx.git] / src / insets / insetcollapsable.C
1 /**
2  * \file insetcollapsable.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author Jürgen Vigna
8  * \author Lars Gullik Bjønnes
9  *
10  * Full author contact details are available in file CREDITS
11  */
12
13 #include <config.h>
14
15 #include "insetcollapsable.h"
16 #include "insettext.h"
17
18 #include "BufferView.h"
19 #include "debug.h"
20 #include "dimension.h"
21 #include "gettext.h"
22 #include "lyxfont.h"
23 #include "lyxlex.h"
24 #include "lyxtext.h"
25 #include "WordLangTuple.h"
26 #include "funcrequest.h"
27 #include "buffer.h"
28
29 #include "frontends/font_metrics.h"
30 #include "frontends/Painter.h"
31 #include "frontends/LyXView.h"
32
33 #include "support/LAssert.h"
34 #include "support/LOstream.h"
35
36 using std::vector;
37 using std::ostream;
38 using std::endl;
39 using std::max;
40
41
42 InsetCollapsable::InsetCollapsable(BufferParams const & bp, bool collapsed)
43         : UpdatableInset(), collapsed_(collapsed), inset(bp),
44           button_length(0), button_top_y(0), button_bottom_y(0),
45           label("Label"),
46 #if 0
47         autocollapse(false),
48 #endif
49           oldWidth(0), in_update(false), first_after_edit(false)
50 {
51         inset.setOwner(this);
52         inset.setAutoBreakRows(true);
53         inset.setDrawFrame(0, InsetText::ALWAYS);
54         inset.setFrameColor(0, LColor::collapsableframe);
55         setInsetName("Collapsable");
56 }
57
58
59 InsetCollapsable::InsetCollapsable(InsetCollapsable const & in)
60         : UpdatableInset(in), collapsed_(in.collapsed_),
61           framecolor(in.framecolor), labelfont(in.labelfont), inset(in.inset),
62           button_length(0), button_top_y(0), button_bottom_y(0),
63           label(in.label),
64 #if 0
65           autocollapse(in.autocollapse),
66 #endif
67           oldWidth(0), in_update(false), first_after_edit(false)
68 {
69         inset.init(&(in.inset));
70         inset.setOwner(this);
71 }
72
73
74 // InsetCollapsable::InsetCollapsable(InsetCollapsable const & in, bool same_id)
75 //      : UpdatableInset(in, same_id), collapsed_(in.collapsed_),
76 //        framecolor(in.framecolor), labelfont(in.labelfont), inset(in.inset),
77 //        button_length(0), button_top_y(0), button_bottom_y(0),
78 //        label(in.label),
79 // #if 0
80 //        autocollapse(in.autocollapse),
81 // #endif
82 //        oldWidth(0), in_update(false), first_after_edit(false)
83 // {
84 //      inset.init(&(in.inset), same_id);
85 //      inset.setOwner(this);
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 " << (collapsed_ ? "true" : "false") << "\n";
103         inset.writeParagraphData(buf, os);
104 }
105
106
107 void InsetCollapsable::read(Buffer const * buf, LyXLex & lex)
108 {
109         if (lex.isOK()) {
110                 lex.next();
111                 string const token = lex.getString();
112                 if (token == "collapsed") {
113                         lex.next();
114                         collapsed_ = lex.getBool();
115                 } else {
116                         lyxerr << "InsetCollapsable::Read: Missing collapsed!"
117                                << endl;
118                         // Take countermeasures
119                         lex.pushToken(token);
120                 }
121         }
122         inset.read(buf, lex);
123 }
124
125
126 void InsetCollapsable::dimension_collapsed(Dimension & dim) const
127 {
128         font_metrics::buttonText(label, labelfont, dim.w, dim.a, dim.d);
129         dim.w += 2 * TEXT_TO_INSET_OFFSET;
130 }
131
132
133 int InsetCollapsable::height_collapsed() const
134 {
135         Dimension dim;
136         font_metrics::buttonText(label, labelfont, dim.w, dim.a, dim.d);
137         return dim.a + dim.d;
138 }
139
140
141 void InsetCollapsable::dimension(BufferView * bv, LyXFont const & font,
142         Dimension & dim) const
143 {
144         dimension_collapsed(dim);
145         if (collapsed_)
146                 return;
147         Dimension insetdim;
148         inset.dimension(bv, font, insetdim);
149         dim.d += insetdim.height() + TEXT_TO_BOTTOM_OFFSET;
150         dim.w = max(dim.w, insetdim.width());
151 }
152
153
154 void InsetCollapsable::draw_collapsed(Painter & pain,
155                                       int baseline, float & x) const
156 {
157         pain.buttonText(int(x) + TEXT_TO_INSET_OFFSET,
158                         baseline, label, labelfont);
159         Dimension dim;
160         dimension_collapsed(dim);
161         x += dim.w;
162 }
163
164
165 void InsetCollapsable::draw(BufferView * bv, LyXFont const & f,
166                             int baseline, float & x, bool inlined) const
167 {
168         lyx::Assert(bv);
169         cache(bv);
170
171         if (nodraw())
172                 return;
173
174         Dimension dim_collapsed;
175         dimension_collapsed(dim_collapsed);
176
177         Painter & pain = bv->painter();
178
179         button_length   = dim_collapsed.width();
180         button_top_y    = -ascent(bv, f);
181         button_bottom_y = -ascent(bv, f) + dim_collapsed.height();
182
183         if (!isOpen()) {
184                 draw_collapsed(pain, baseline, x);
185                 return;
186         }
187
188         float old_x = x;
189
190         if (!owner())
191                 x += scroll();
192
193         top_x = int(x);
194         top_baseline = baseline;
195
196         int const bl = baseline - ascent(bv, f) + dim_collapsed.ascent();
197
198         if (inlined) {
199                 inset.draw(bv, f, baseline, x);
200         } else {
201                 draw_collapsed(pain, bl, old_x);
202                 int const yy = bl + dim_collapsed.descent() + inset.ascent(bv, f);
203                 inset.draw(bv, f, yy, x);
204                 // contained inset may be shorter than the button
205                 if (x < top_x + button_length + TEXT_TO_INSET_OFFSET)
206                         x = top_x + button_length + TEXT_TO_INSET_OFFSET;
207         }
208 }
209
210
211 void InsetCollapsable::draw(BufferView * bv, LyXFont const & f,
212                             int baseline, float & x) const
213 {
214         // by default, we are not inlined-drawing
215         draw(bv, f, baseline, x, false);
216 }
217
218
219 Inset::EDITABLE InsetCollapsable::editable() const
220 {
221         return collapsed_ ? IS_EDITABLE : HIGHLY_EDITABLE;
222 }
223
224
225 void InsetCollapsable::insetUnlock(BufferView * bv)
226 {
227 #if 0
228         if (autocollapse) {
229                 if (change_label_with_text) {
230                         draw_label = get_new_label();
231                 } else {
232                         draw_label = label;
233                 }
234                 collapsed_ = true;
235         }
236 #endif
237         inset.insetUnlock(bv);
238         if (scroll())
239                 scroll(bv, 0.0F);
240         bv->updateInset(this);
241 }
242
243
244 FuncRequest InsetCollapsable::adjustCommand(FuncRequest const & cmd)
245 {
246         LyXFont font(LyXFont::ALL_SANE);
247         FuncRequest cmd1 = cmd;
248         cmd1.y = ascent(cmd.view(), font) + cmd.y -
249             (height_collapsed() + inset.ascent(cmd.view(), font));
250         return cmd1;
251 }
252
253
254 void InsetCollapsable::lfunMouseRelease(FuncRequest const & cmd)
255 {
256         bool ret = false;
257         BufferView * bv = cmd.view();
258
259         if (collapsed_ && cmd.button() != mouse_button::button3) {
260                 collapsed_ = false;
261                 inset.setUpdateStatus(bv, InsetText::FULL);
262                 bv->updateInset(this);
263                 bv->buffer()->markDirty();
264                 return;
265         }
266
267         if ((cmd.button() != mouse_button::button3) && (cmd.x < button_length) &&
268             (cmd.y >= button_top_y) && (cmd.y <= button_bottom_y))
269         {
270                 if (collapsed_) {
271                         collapsed_ = false;
272                         inset.setUpdateStatus(bv, InsetText::FULL);
273                         bv->updateInset(this);
274                         bv->buffer()->markDirty();
275                 } else {
276                         collapsed_ = true;
277                         bv->unlockInset(this);
278                         bv->updateInset(this);
279                         bv->buffer()->markDirty();
280                 }
281         } else if (!collapsed_ && (cmd.y > button_bottom_y)) {
282                 ret = (inset.localDispatch(adjustCommand(cmd)) == DISPATCHED);
283         }
284         if (cmd.button() == mouse_button::button3 && !ret)
285                 showInsetDialog(bv);
286 }
287
288
289 int InsetCollapsable::latex(Buffer const * buf, ostream & os,
290                             LatexRunParams const & runparams) const
291 {
292         return inset.latex(buf, os, runparams);
293 }
294
295
296 int InsetCollapsable::ascii(Buffer const * buf, ostream & os, int ll) const
297 {
298         return inset.ascii(buf, os, ll);
299 }
300
301
302 int InsetCollapsable::linuxdoc(Buffer const * buf, ostream & os) const
303 {
304         return inset.linuxdoc(buf, os);
305 }
306
307
308 int InsetCollapsable::docbook(Buffer const * buf, ostream & os, bool mixcont) const
309 {
310         return inset.docbook(buf, os, mixcont);
311 }
312
313
314 void InsetCollapsable::update(BufferView * bv, bool reinit)
315 {
316         if (in_update) {
317                 if (reinit && owner()) {
318                         owner()->update(bv, true);
319                 }
320                 return;
321         }
322         in_update = true;
323         inset.update(bv, reinit);
324         if (reinit && owner()) {
325                 owner()->update(bv, true);
326         }
327         in_update = false;
328 }
329
330
331 Inset::RESULT InsetCollapsable::localDispatch(FuncRequest const & cmd)
332 {
333         //lyxerr << "InsetCollapsable::localDispatch: " << cmd.action << "\n";
334         BufferView * bv = cmd.view();
335         switch (cmd.action) {
336                 case LFUN_INSET_EDIT: {
337                         if (!cmd.argument.empty()) {
338                                 UpdatableInset::localDispatch(cmd);
339                                 if (collapsed_) {
340                                         collapsed_ = false;
341                                         if (bv->lockInset(this)) {
342                                                 inset.setUpdateStatus(bv, InsetText::FULL);
343                                                 bv->updateInset(this);
344                                                 bv->buffer()->markDirty();
345                                                 inset.localDispatch(cmd);
346                                                 first_after_edit = true;
347                                         }
348                                 } else {
349                                         if (bv->lockInset(this))
350                                                 inset.localDispatch(cmd);
351                                 }
352                                 return DISPATCHED;
353                         }
354
355 #ifdef WITH_WARNINGS
356 #warning Fix this properly in BufferView_pimpl::workAreaButtonRelease
357 #endif
358                         if (cmd.button() == mouse_button::button3)
359                                 return DISPATCHED;
360
361                         UpdatableInset::localDispatch(cmd);
362
363                         if (collapsed_) {
364                                 collapsed_ = false;
365                                 // set this only here as it should be recollapsed only if
366                                 // it was already collapsed!
367                                 first_after_edit = true;
368                                 if (!bv->lockInset(this))
369                                         return DISPATCHED;
370                                 bv->updateInset(this);
371                                 bv->buffer()->markDirty();
372                                 inset.localDispatch(cmd);
373                         } else {
374                                 FuncRequest cmd1 = cmd;
375                                 if (!bv->lockInset(this))
376                                         return DISPATCHED;
377                                 if (cmd.y <= button_bottom_y) {
378                                         cmd1.y = 0;
379                                 } else {
380                                         LyXFont font(LyXFont::ALL_SANE);
381                                         cmd1.y = ascent(bv, font) + cmd.y -
382                                                 (height_collapsed() + inset.ascent(bv, font));
383                                 }
384                                 inset.localDispatch(cmd);
385                         }
386                         return DISPATCHED;
387                 }
388
389                 case LFUN_MOUSE_PRESS:
390                         if (!collapsed_ && cmd.y > button_bottom_y)
391                                 inset.localDispatch(adjustCommand(cmd));
392                         return DISPATCHED;
393
394                 case LFUN_MOUSE_MOTION:
395                         if (!collapsed_ && cmd.y > button_bottom_y)
396                                 inset.localDispatch(adjustCommand(cmd));
397                         return DISPATCHED;
398
399                 case LFUN_MOUSE_RELEASE:
400                         lfunMouseRelease(cmd);
401                         return DISPATCHED;
402
403                 default:
404                         UpdatableInset::RESULT result = inset.localDispatch(cmd);
405                         if (result >= FINISHED)
406                                 bv->unlockInset(this);
407                         first_after_edit = false;
408                         return result;
409         }
410 }
411
412
413 bool InsetCollapsable::lockInsetInInset(BufferView * bv, UpdatableInset * in)
414 {
415         if (&inset == in)
416                 return true;
417         return inset.lockInsetInInset(bv, in);
418 }
419
420
421 bool InsetCollapsable::unlockInsetInInset(BufferView * bv, UpdatableInset * in,
422                                           bool lr)
423 {
424         if (&inset == in) {
425                 bv->unlockInset(this);
426                 return true;
427         }
428         return inset.unlockInsetInInset(bv, in, lr);
429 }
430
431
432 bool InsetCollapsable::updateInsetInInset(BufferView * bv, Inset *in)
433 {
434         if (in == this)
435                 return true;
436         return inset.updateInsetInInset(bv, in);
437 }
438
439
440 int InsetCollapsable::insetInInsetY() const
441 {
442         return inset.insetInInsetY() - (top_baseline - inset.y());
443 }
444
445
446 void InsetCollapsable::validate(LaTeXFeatures & features) const
447 {
448         inset.validate(features);
449 }
450
451
452 void InsetCollapsable::getCursor(BufferView & bv, int & x, int & y) const
453 {
454         inset.getCursor(bv, x, y);
455 }
456
457
458 void InsetCollapsable::getCursorPos(BufferView * bv, int & x, int & y) const
459 {
460         inset.getCursorPos(bv, x , y);
461 }
462
463
464 UpdatableInset * InsetCollapsable::getLockingInset() const
465 {
466         UpdatableInset * in = inset.getLockingInset();
467         if (const_cast<InsetText *>(&inset) == in)
468                 return const_cast<InsetCollapsable *>(this);
469         return in;
470 }
471
472
473 UpdatableInset * InsetCollapsable::getFirstLockingInsetOfType(Inset::Code c)
474 {
475         if (c == lyxCode())
476                 return this;
477         return inset.getFirstLockingInsetOfType(c);
478 }
479
480
481 void InsetCollapsable::setFont(BufferView * bv, LyXFont const & font,
482                                bool toggleall, bool selectall)
483 {
484         inset.setFont(bv, font, toggleall, selectall);
485 }
486
487
488 LyXText * InsetCollapsable::getLyXText(BufferView const * bv,
489                                        bool const recursive) const
490 {
491         return inset.getLyXText(bv, recursive);
492 }
493
494
495 void InsetCollapsable::deleteLyXText(BufferView * bv, bool recursive) const
496 {
497         inset.deleteLyXText(bv, recursive);
498 }
499
500
501 void InsetCollapsable::resizeLyXText(BufferView * bv, bool force) const
502 {
503         inset.resizeLyXText(bv, force);
504         LyXFont font(LyXFont::ALL_SANE);
505         oldWidth = width(bv, font);
506 }
507
508
509 vector<string> const InsetCollapsable::getLabelList() const
510 {
511         return inset.getLabelList();
512 }
513
514
515 bool InsetCollapsable::nodraw() const
516 {
517         return inset.nodraw();
518 }
519
520
521 int InsetCollapsable::scroll(bool recursive) const
522 {
523         int sx = UpdatableInset::scroll(false);
524
525         if (recursive)
526                 sx += inset.scroll(recursive);
527
528         return sx;
529 }
530
531
532 ParagraphList * InsetCollapsable::getParagraphs(int i) const
533 {
534         return inset.getParagraphs(i);
535 }
536
537
538 LyXCursor const & InsetCollapsable::cursor(BufferView * bv) const
539 {
540         return inset.cursor(bv);
541 }
542
543
544 Inset * InsetCollapsable::getInsetFromID(int id_arg) const
545 {
546         if (id_arg == id())
547                 return const_cast<InsetCollapsable *>(this);
548         return inset.getInsetFromID(id_arg);
549 }
550
551
552 void InsetCollapsable::open(BufferView * bv)
553 {
554         if (!collapsed_) return;
555
556         collapsed_ = false;
557         bv->updateInset(this);
558 }
559
560
561 void InsetCollapsable::close(BufferView * bv) const
562 {
563         if (collapsed_)
564                 return;
565
566         collapsed_ = true;
567         bv->updateInset(const_cast<InsetCollapsable *>(this));
568 }
569
570
571 void InsetCollapsable::setLabel(string const & l) const
572 {
573         label = l;
574 }
575
576
577 void InsetCollapsable::markErased()
578 {
579         inset.markErased();
580 }
581
582
583 bool InsetCollapsable::nextChange(BufferView * bv, lyx::pos_type & length)
584 {
585         bool found = inset.nextChange(bv, length);
586
587         if (first_after_edit && !found)
588                 close(bv);
589         else if (!found)
590                 first_after_edit = false;
591         return found;
592 }
593
594
595 bool InsetCollapsable::searchForward(BufferView * bv, string const & str,
596                                      bool cs, bool mw)
597 {
598         bool found = inset.searchForward(bv, str, cs, mw);
599         if (first_after_edit && !found)
600                 close(bv);
601         else if (!found)
602                 first_after_edit = false;
603         return found;
604 }
605
606
607 bool InsetCollapsable::searchBackward(BufferView * bv, string const & str,
608                                       bool cs, bool mw)
609 {
610         bool found = inset.searchBackward(bv, str, cs, mw);
611         if (first_after_edit && !found)
612                 close(bv);
613         else if (!found)
614                 first_after_edit = false;
615         return found;
616 }
617
618
619 WordLangTuple const
620 InsetCollapsable::selectNextWordToSpellcheck(BufferView * bv, float & value) const
621 {
622         WordLangTuple word = inset.selectNextWordToSpellcheck(bv, value);
623         if (first_after_edit && word.word().empty())
624                 close(bv);
625         first_after_edit = false;
626         return word;
627 }
628
629
630 void InsetCollapsable::addPreview(grfx::PreviewLoader & loader) const
631 {
632         inset.addPreview(loader);
633 }
634
635
636 void InsetCollapsable::cache(BufferView * bv) const
637 {
638         view_ = bv->owner()->view();
639 }
640
641
642 BufferView * InsetCollapsable::view() const
643 {
644         return view_.lock().get();
645 }