2 * \file insetcollapsable.C
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alejandro Aguilar Sierra
8 * \author Lars Gullik Bjønnes
10 * Full author contact details are available in file CREDITS
16 #include "insetcollapsable.h"
17 #include "insettext.h"
19 #include "BufferView.h"
25 #include "WordLangTuple.h"
26 #include "funcrequest.h"
28 #include "frontends/font_metrics.h"
29 #include "frontends/Painter.h"
30 #include "frontends/LyXView.h"
32 #include "support/LAssert.h"
33 #include "support/LOstream.h"
34 #include "support/lstrings.h"
45 InsetCollapsable::InsetCollapsable(BufferParams const & bp, bool collapsed)
46 : UpdatableInset(), collapsed_(collapsed), inset(bp),
47 button_length(0), button_top_y(0), button_bottom_y(0),
48 need_update(NONE), label("Label"),
52 oldWidth(0), in_update(false), first_after_edit(false)
55 inset.setAutoBreakRows(true);
56 inset.setDrawFrame(0, InsetText::ALWAYS);
57 inset.setFrameColor(0, LColor::collapsableframe);
58 setInsetName("Collapsable");
62 InsetCollapsable::InsetCollapsable(InsetCollapsable const & in, bool same_id)
63 : UpdatableInset(in, same_id), collapsed_(in.collapsed_),
64 framecolor(in.framecolor), labelfont(in.labelfont), inset(in.inset),
65 button_length(0), button_top_y(0), button_bottom_y(0),
66 need_update(NONE), label(in.label),
68 autocollapse(in.autocollapse),
70 oldWidth(0), in_update(false), first_after_edit(false)
72 inset.init(&(in.inset), same_id);
77 bool InsetCollapsable::insertInset(BufferView * bv, Inset * in)
79 if (!insetAllowed(in->lyxCode())) {
80 lyxerr << "InsetCollapsable::InsertInset: "
81 "Unable to insert inset." << endl;
84 return inset.insertInset(bv, in);
88 void InsetCollapsable::write(Buffer const * buf, ostream & os) const
90 os << "collapsed " << tostr(collapsed_) << "\n";
91 inset.writeParagraphData(buf, os);
96 void InsetCollapsable::read(Buffer const * buf, LyXLex & lex)
100 string const token = lex.getString();
101 if (token == "collapsed") {
103 collapsed_ = lex.getBool();
105 lyxerr << "InsetCollapsable::Read: Missing collapsed!"
107 // Take countermeasures
108 lex.pushToken(token);
111 inset.read(buf, lex);
115 int InsetCollapsable::ascent_collapsed() const
120 font_metrics::buttonText(label, labelfont, width, ascent, descent);
125 int InsetCollapsable::descent_collapsed() const
130 font_metrics::buttonText(label, labelfont, width, ascent, descent);
135 //int InsetCollapsable::width_collapsed(Painter & pain) const
136 int InsetCollapsable::width_collapsed() const
141 font_metrics::buttonText(label, labelfont, width, ascent, descent);
142 return width + 2 * TEXT_TO_INSET_OFFSET;
146 int InsetCollapsable::ascent(BufferView * /*bv*/, LyXFont const &) const
148 return ascent_collapsed();
152 int InsetCollapsable::descent(BufferView * bv, LyXFont const & font) const
155 return descent_collapsed();
157 return descent_collapsed()
158 + inset.descent(bv, font)
159 + inset.ascent(bv, font)
160 + TEXT_TO_BOTTOM_OFFSET;
164 int InsetCollapsable::width(BufferView * bv, LyXFont const & font) const
167 return width_collapsed();
169 int widthCollapsed = width_collapsed();
171 return (inset.width(bv, font) > widthCollapsed) ?
172 inset.width(bv, font) : widthCollapsed;
176 void InsetCollapsable::draw_collapsed(Painter & pain,
177 int baseline, float & x) const
179 pain.buttonText(int(x) + TEXT_TO_INSET_OFFSET,
180 baseline, label, labelfont);
181 x += width_collapsed();
185 void InsetCollapsable::draw(BufferView * bv, LyXFont const & f,
186 int baseline, float & x, bool cleared) const
191 if (need_update != NONE) {
192 const_cast<InsetText *>(&inset)->update(bv, f, true);
193 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
200 Painter & pain = bv->painter();
202 button_length = width_collapsed();
203 button_top_y = -ascent(bv, f);
204 button_bottom_y = -ascent(bv, f) + ascent_collapsed() +
208 draw_collapsed(pain, baseline, x);
215 x += static_cast<float>(scroll());
217 if (!cleared && (inset.need_update == InsetText::FULL ||
218 inset.need_update == InsetText::INIT ||
220 top_baseline != baseline))
222 // we don't need anymore to clear here we just have to tell
223 // the underlying LyXText that it should do the RowClear!
224 inset.setUpdateStatus(bv, InsetText::FULL);
225 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
231 top_baseline = baseline;
233 int const bl = baseline - ascent(bv, f) + ascent_collapsed();
235 draw_collapsed(pain, bl, old_x);
237 bl + descent_collapsed() + inset.ascent(bv, f),
239 if (x < (top_x + button_length + TEXT_TO_INSET_OFFSET))
240 x = top_x + button_length + TEXT_TO_INSET_OFFSET;
244 void InsetCollapsable::edit(BufferView * bv, int xp, int yp,
245 mouse_button::state button)
248 #warning Fix this properly in BufferView_pimpl::workAreaButtonRelease
250 if (button == mouse_button::button3)
253 UpdatableInset::edit(bv, xp, yp, button);
257 // set this only here as it should be recollapsed only if
258 // it was already collapsed!
259 first_after_edit = true;
260 if (!bv->lockInset(this))
262 bv->updateInset(this, false);
265 if (!bv->lockInset(this))
267 if (yp <= button_bottom_y) {
268 inset.edit(bv, xp, 0, button);
270 LyXFont font(LyXFont::ALL_SANE);
271 int yy = ascent(bv, font) + yp -
272 (ascent_collapsed() +
273 descent_collapsed() +
274 inset.ascent(bv, font));
275 inset.edit(bv, xp, yy, button);
281 void InsetCollapsable::edit(BufferView * bv, bool front)
283 UpdatableInset::edit(bv, front);
287 if (!bv->lockInset(this))
289 inset.setUpdateStatus(bv, InsetText::FULL);
290 bv->updateInset(this, false);
291 inset.edit(bv, front);
292 first_after_edit = true;
294 if (!bv->lockInset(this))
296 inset.edit(bv, front);
301 Inset::EDITABLE InsetCollapsable::editable() const
305 return HIGHLY_EDITABLE;
309 void InsetCollapsable::insetUnlock(BufferView * bv)
313 if (change_label_with_text) {
314 draw_label = get_new_label();
321 inset.insetUnlock(bv);
324 bv->updateInset(this, false);
328 void InsetCollapsable::lfunMousePress(FuncRequest const & cmd)
330 if (!collapsed_ && (cmd.y > button_bottom_y)) {
331 LyXFont font(LyXFont::ALL_SANE);
332 FuncRequest cmd1 = cmd;
333 cmd1.y = ascent(cmd.view(), font) + cmd.y -
334 (ascent_collapsed() +
335 descent_collapsed() +
336 inset.ascent(cmd.view(), font));
337 inset.localDispatch(cmd1);
342 bool InsetCollapsable::lfunMouseRelease(FuncRequest const & cmd)
345 BufferView * bv = cmd.view();
346 if ((cmd.button() != mouse_button::button3) && (cmd.x < button_length) &&
347 (cmd.y >= button_top_y) && (cmd.y <= button_bottom_y))
351 // should not be called on inset open!
352 // inset.insetButtonRelease(bv, 0, 0, button);
353 inset.setUpdateStatus(bv, InsetText::FULL);
354 bv->updateInset(this, false);
357 bv->unlockInset(this);
358 bv->updateInset(this, false);
360 } else if (!collapsed_ && (cmd.y > button_bottom_y)) {
361 LyXFont font(LyXFont::ALL_SANE);
362 FuncRequest cmd1 = cmd;
363 cmd1.y = ascent(cmd.view(), font) + cmd.y -
364 (ascent_collapsed() +
365 descent_collapsed() +
366 inset.ascent(cmd.view(), font));
367 ret = (inset.localDispatch(cmd1) == DISPATCHED);
369 if (cmd.button() == mouse_button::button3 && !ret)
370 return showInsetDialog(bv);
375 void InsetCollapsable::lfunMouseMotion(FuncRequest const & cmd)
377 if (cmd.y > button_bottom_y) {
378 LyXFont font(LyXFont::ALL_SANE);
379 FuncRequest cmd1 = cmd;
380 cmd1.y = ascent(cmd.view(), font) + cmd.y -
381 (ascent_collapsed() +
382 descent_collapsed() +
383 inset.ascent(cmd.view(), font));
384 inset.localDispatch(cmd1);
389 int InsetCollapsable::latex(Buffer const * buf, ostream & os,
390 bool fragile, bool free_spc) const
392 return inset.latex(buf, os, fragile, free_spc);
396 int InsetCollapsable::ascii(Buffer const * buf, ostream & os, int ll) const
398 return inset.ascii(buf, os, ll);
402 int InsetCollapsable::linuxdoc(Buffer const * buf, ostream & os) const
404 return inset.linuxdoc(buf, os);
408 int InsetCollapsable::docbook(Buffer const * buf, ostream & os, bool mixcont) const
410 return inset.docbook(buf, os, mixcont);
414 int InsetCollapsable::getMaxWidth(BufferView * bv,
415 UpdatableInset const * in) const
418 int const w = UpdatableInset::getMaxWidth(bv, in);
421 // What does a negative max width signify? (Lgb)
422 // Use the max width of the draw-area (Jug)
425 // should be at least 30 pixels !!!
426 return max(30, w - width_collapsed());
428 return UpdatableInset::getMaxWidth(bv, in);
434 void InsetCollapsable::update(BufferView * bv, LyXFont const & font,
438 if (reinit && owner()) {
439 owner()->update(bv, font, true);
444 inset.update(bv, font, reinit);
445 if (reinit && owner()) {
446 owner()->update(bv, font, true);
452 Inset::RESULT InsetCollapsable::localDispatch(FuncRequest const & cmd)
454 switch (cmd.action) {
456 case LFUN_MOUSE_PRESS:
460 case LFUN_MOUSE_MOTION:
461 lfunMouseMotion(cmd);
464 case LFUN_MOUSE_RELEASE:
465 lfunMouseRelease(cmd);
469 UpdatableInset::RESULT result = inset.localDispatch(cmd);
470 if (result >= FINISHED)
471 cmd.view()->unlockInset(this);
472 first_after_edit = false;
479 bool InsetCollapsable::lockInsetInInset(BufferView * bv, UpdatableInset * in)
483 return inset.lockInsetInInset(bv, in);
487 bool InsetCollapsable::unlockInsetInInset(BufferView * bv, UpdatableInset * in,
491 bv->unlockInset(this);
494 return inset.unlockInsetInInset(bv, in, lr);
498 bool InsetCollapsable::updateInsetInInset(BufferView * bv, Inset *in)
502 return inset.updateInsetInInset(bv, in);
506 int InsetCollapsable::insetInInsetY() const
508 return inset.insetInInsetY() - (top_baseline - inset.y());
512 void InsetCollapsable::validate(LaTeXFeatures & features) const
514 inset.validate(features);
518 void InsetCollapsable::getCursorPos(BufferView * bv, int & x, int & y) const
520 inset.getCursorPos(bv, x , y);
524 void InsetCollapsable::toggleInsetCursor(BufferView * bv)
526 inset.toggleInsetCursor(bv);
530 void InsetCollapsable::showInsetCursor(BufferView * bv, bool show)
532 inset.showInsetCursor(bv, show);
536 void InsetCollapsable::hideInsetCursor(BufferView * bv)
538 inset.hideInsetCursor(bv);
542 UpdatableInset * InsetCollapsable::getLockingInset() const
544 UpdatableInset * in = inset.getLockingInset();
545 if (const_cast<InsetText *>(&inset) == in)
546 return const_cast<InsetCollapsable *>(this);
551 UpdatableInset * InsetCollapsable::getFirstLockingInsetOfType(Inset::Code c)
555 return inset.getFirstLockingInsetOfType(c);
559 void InsetCollapsable::setFont(BufferView * bv, LyXFont const & font,
560 bool toggleall, bool selectall)
562 inset.setFont(bv, font, toggleall, selectall);
566 bool InsetCollapsable::doClearArea() const
568 return inset.doClearArea();
572 LyXText * InsetCollapsable::getLyXText(BufferView const * bv,
573 bool const recursive) const
575 return inset.getLyXText(bv, recursive);
579 void InsetCollapsable::deleteLyXText(BufferView * bv, bool recursive) const
581 inset.deleteLyXText(bv, recursive);
585 void InsetCollapsable::resizeLyXText(BufferView * bv, bool force) const
587 inset.resizeLyXText(bv, force);
588 LyXFont font(LyXFont::ALL_SANE);
589 oldWidth = width(bv, font);
593 vector<string> const InsetCollapsable::getLabelList() const
595 return inset.getLabelList();
599 bool InsetCollapsable::nodraw() const
601 return inset.nodraw();
605 int InsetCollapsable::scroll(bool recursive) const
607 int sx = UpdatableInset::scroll(false);
610 sx += inset.scroll(recursive);
616 Paragraph * InsetCollapsable::firstParagraph() const
618 return inset.firstParagraph();
622 Paragraph * InsetCollapsable::getFirstParagraph(int i) const
624 return inset.getFirstParagraph(i);
628 LyXCursor const & InsetCollapsable::cursor(BufferView * bv) const
630 return inset.cursor(bv);
634 Inset * InsetCollapsable::getInsetFromID(int id_arg) const
637 return const_cast<InsetCollapsable *>(this);
638 return inset.getInsetFromID(id_arg);
642 void InsetCollapsable::open(BufferView * bv)
644 if (!collapsed_) return;
647 bv->updateInset(this, false);
651 void InsetCollapsable::close(BufferView * bv) const
657 bv->updateInset(const_cast<InsetCollapsable *>(this), false);
661 void InsetCollapsable::setLabel(string const & l) const
667 void InsetCollapsable::markErased()
673 bool InsetCollapsable::nextChange(BufferView * bv, lyx::pos_type & length)
675 bool found = inset.nextChange(bv, length);
677 if (first_after_edit && !found)
680 first_after_edit = false;
685 bool InsetCollapsable::searchForward(BufferView * bv, string const & str,
688 bool found = inset.searchForward(bv, str, cs, mw);
689 if (first_after_edit && !found)
692 first_after_edit = false;
697 bool InsetCollapsable::searchBackward(BufferView * bv, string const & str,
700 bool found = inset.searchBackward(bv, str, cs, mw);
701 if (first_after_edit && !found)
704 first_after_edit = false;
710 InsetCollapsable::selectNextWordToSpellcheck(BufferView * bv, float & value) const
712 WordLangTuple word = inset.selectNextWordToSpellcheck(bv, value);
713 if (first_after_edit && word.word().empty())
715 first_after_edit = false;
720 void InsetCollapsable::addPreview(grfx::PreviewLoader & loader) const
722 inset.addPreview(loader);
726 void InsetCollapsable::cache(BufferView * bv) const
728 view_ = bv->owner()->view();
732 BufferView * InsetCollapsable::view() const
734 return view_.lock().get();