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 #pragma implementation
19 #include "insetcollapsable.h"
20 #include "insettext.h"
22 #include "BufferView.h"
28 #include "WordLangTuple.h"
29 #include "funcrequest.h"
31 #include "frontends/font_metrics.h"
32 #include "frontends/Painter.h"
34 #include "support/LOstream.h"
35 #include "support/lstrings.h"
46 InsetCollapsable::InsetCollapsable(BufferParams const & bp, bool collapsed)
47 : UpdatableInset(), collapsed_(collapsed), inset(bp),
48 button_length(0), button_top_y(0), button_bottom_y(0),
49 need_update(NONE), label("Label"),
53 oldWidth(0), in_update(false), first_after_edit(false)
56 inset.setAutoBreakRows(true);
57 inset.setDrawFrame(0, InsetText::ALWAYS);
58 inset.setFrameColor(0, LColor::collapsableframe);
59 setInsetName("Collapsable");
63 InsetCollapsable::InsetCollapsable(InsetCollapsable const & in, bool same_id)
64 : UpdatableInset(in, same_id), collapsed_(in.collapsed_),
65 framecolor(in.framecolor), labelfont(in.labelfont), inset(in.inset),
66 button_length(0), button_top_y(0), button_bottom_y(0),
67 need_update(NONE), label(in.label),
69 autocollapse(in.autocollapse),
71 oldWidth(0), in_update(false), first_after_edit(false)
73 inset.init(&(in.inset), same_id);
78 bool InsetCollapsable::insertInset(BufferView * bv, Inset * in)
80 if (!insetAllowed(in->lyxCode())) {
81 lyxerr << "InsetCollapsable::InsertInset: "
82 "Unable to insert inset." << endl;
85 return inset.insertInset(bv, in);
89 void InsetCollapsable::write(Buffer const * buf, ostream & os) const
91 os << "collapsed " << tostr(collapsed_) << "\n";
92 inset.writeParagraphData(buf, os);
97 void InsetCollapsable::read(Buffer const * buf, LyXLex & lex)
101 string const token = lex.getString();
102 if (token == "collapsed") {
104 collapsed_ = lex.getBool();
106 lyxerr << "InsetCollapsable::Read: Missing collapsed!"
108 // Take countermeasures
109 lex.pushToken(token);
112 inset.read(buf, lex);
116 int InsetCollapsable::ascent_collapsed() const
121 font_metrics::buttonText(label, labelfont, width, ascent, descent);
126 int InsetCollapsable::descent_collapsed() const
131 font_metrics::buttonText(label, labelfont, width, ascent, descent);
136 //int InsetCollapsable::width_collapsed(Painter & pain) const
137 int InsetCollapsable::width_collapsed() const
142 font_metrics::buttonText(label, labelfont, width, ascent, descent);
143 return width + 2 * TEXT_TO_INSET_OFFSET;
147 int InsetCollapsable::ascent(BufferView * /*bv*/, LyXFont const &) const
149 return ascent_collapsed();
153 int InsetCollapsable::descent(BufferView * bv, LyXFont const & font) const
156 return descent_collapsed();
158 return descent_collapsed()
159 + inset.descent(bv, font)
160 + inset.ascent(bv, font)
161 + TEXT_TO_BOTTOM_OFFSET;
165 int InsetCollapsable::width(BufferView * bv, LyXFont const & font) const
168 return width_collapsed();
170 int widthCollapsed = width_collapsed();
172 return (inset.width(bv, font) > widthCollapsed) ?
173 inset.width(bv, font) : widthCollapsed;
177 void InsetCollapsable::draw_collapsed(Painter & pain,
178 int baseline, float & x) const
180 pain.buttonText(int(x) + TEXT_TO_INSET_OFFSET,
181 baseline, label, labelfont);
182 x += width_collapsed();
186 void InsetCollapsable::draw(BufferView * bv, LyXFont const & f,
187 int baseline, float & x, bool cleared) const
189 if (need_update != NONE) {
190 const_cast<InsetText *>(&inset)->update(bv, f, true);
191 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
198 Painter & pain = bv->painter();
200 button_length = width_collapsed();
201 button_top_y = -ascent(bv, f);
202 button_bottom_y = -ascent(bv, f) + ascent_collapsed() +
206 draw_collapsed(pain, baseline, x);
213 x += static_cast<float>(scroll());
215 if (!cleared && (inset.need_update == InsetText::FULL ||
216 inset.need_update == InsetText::INIT ||
218 top_baseline != baseline))
220 // we don't need anymore to clear here we just have to tell
221 // the underlying LyXText that it should do the RowClear!
222 inset.setUpdateStatus(bv, InsetText::FULL);
223 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
229 top_baseline = baseline;
231 int const bl = baseline - ascent(bv, f) + ascent_collapsed();
233 draw_collapsed(pain, bl, old_x);
235 bl + descent_collapsed() + inset.ascent(bv, f),
237 if (x < (top_x + button_length + TEXT_TO_INSET_OFFSET))
238 x = top_x + button_length + TEXT_TO_INSET_OFFSET;
242 void InsetCollapsable::edit(BufferView * bv, int xp, int yp,
243 mouse_button::state button)
246 #warning Fix this properly in BufferView_pimpl::workAreaButtonRelease
248 if (button == mouse_button::button3)
251 UpdatableInset::edit(bv, xp, yp, button);
255 // set this only here as it should be recollapsed only if
256 // it was already collapsed!
257 first_after_edit = true;
258 if (!bv->lockInset(this))
260 bv->updateInset(this, false);
263 if (!bv->lockInset(this))
265 if (yp <= button_bottom_y) {
266 inset.edit(bv, xp, 0, button);
268 LyXFont font(LyXFont::ALL_SANE);
269 int yy = ascent(bv, font) + yp -
270 (ascent_collapsed() +
271 descent_collapsed() +
272 inset.ascent(bv, font));
273 inset.edit(bv, xp, yy, button);
279 void InsetCollapsable::edit(BufferView * bv, bool front)
281 UpdatableInset::edit(bv, front);
285 if (!bv->lockInset(this))
287 inset.setUpdateStatus(bv, InsetText::FULL);
288 bv->updateInset(this, false);
289 inset.edit(bv, front);
290 first_after_edit = true;
292 if (!bv->lockInset(this))
294 inset.edit(bv, front);
299 Inset::EDITABLE InsetCollapsable::editable() const
303 return HIGHLY_EDITABLE;
307 void InsetCollapsable::insetUnlock(BufferView * bv)
311 if (change_label_with_text) {
312 draw_label = get_new_label();
319 inset.insetUnlock(bv);
322 bv->updateInset(this, false);
326 void InsetCollapsable::lfunMousePress(FuncRequest const & cmd)
328 if (!collapsed_ && (cmd.y > button_bottom_y)) {
329 LyXFont font(LyXFont::ALL_SANE);
330 FuncRequest cmd1 = cmd;
331 cmd1.y = ascent(cmd.view(), font) + cmd.y -
332 (ascent_collapsed() +
333 descent_collapsed() +
334 inset.ascent(cmd.view(), font));
335 inset.localDispatch(cmd1);
340 bool InsetCollapsable::lfunMouseRelease(FuncRequest const & cmd)
343 BufferView * bv = cmd.view();
344 if ((cmd.button() != mouse_button::button3) && (cmd.x < button_length) &&
345 (cmd.y >= button_top_y) && (cmd.y <= button_bottom_y))
349 // should not be called on inset open!
350 // inset.insetButtonRelease(bv, 0, 0, button);
351 inset.setUpdateStatus(bv, InsetText::FULL);
352 bv->updateInset(this, false);
355 bv->unlockInset(this);
356 bv->updateInset(this, false);
358 } else if (!collapsed_ && (cmd.y > button_bottom_y)) {
359 LyXFont font(LyXFont::ALL_SANE);
360 FuncRequest cmd1 = cmd;
361 cmd1.y = ascent(cmd.view(), font) + cmd.y -
362 (ascent_collapsed() +
363 descent_collapsed() +
364 inset.ascent(cmd.view(), font));
365 ret = (inset.localDispatch(cmd1) == DISPATCHED);
367 if (cmd.button() == mouse_button::button3 && !ret)
368 return showInsetDialog(bv);
373 void InsetCollapsable::lfunMouseMotion(FuncRequest const & cmd)
375 if (cmd.y > button_bottom_y) {
376 LyXFont font(LyXFont::ALL_SANE);
377 FuncRequest cmd1 = cmd;
378 cmd1.y = ascent(cmd.view(), font) + cmd.y -
379 (ascent_collapsed() +
380 descent_collapsed() +
381 inset.ascent(cmd.view(), font));
382 inset.localDispatch(cmd1);
387 int InsetCollapsable::latex(Buffer const * buf, ostream & os,
388 bool fragile, bool free_spc) const
390 return inset.latex(buf, os, fragile, free_spc);
394 int InsetCollapsable::ascii(Buffer const * buf, ostream & os, int ll) const
396 return inset.ascii(buf, os, ll);
400 int InsetCollapsable::linuxdoc(Buffer const * buf, ostream & os) const
402 return inset.linuxdoc(buf, os);
406 int InsetCollapsable::docbook(Buffer const * buf, ostream & os, bool mixcont) const
408 return inset.docbook(buf, os, mixcont);
412 int InsetCollapsable::getMaxWidth(BufferView * bv,
413 UpdatableInset const * in) const
416 int const w = UpdatableInset::getMaxWidth(bv, in);
419 // What does a negative max width signify? (Lgb)
420 // Use the max width of the draw-area (Jug)
423 // should be at least 30 pixels !!!
424 return max(30, w - width_collapsed());
426 return UpdatableInset::getMaxWidth(bv, in);
432 void InsetCollapsable::update(BufferView * bv, LyXFont const & font,
436 if (reinit && owner()) {
437 owner()->update(bv, font, true);
442 inset.update(bv, font, reinit);
443 if (reinit && owner()) {
444 owner()->update(bv, font, true);
450 Inset::RESULT InsetCollapsable::localDispatch(FuncRequest const & cmd)
452 switch (cmd.action) {
454 case LFUN_MOUSE_PRESS:
458 case LFUN_MOUSE_MOTION:
459 lfunMouseMotion(cmd);
462 case LFUN_MOUSE_RELEASE:
463 lfunMouseRelease(cmd);
467 UpdatableInset::RESULT result = inset.localDispatch(cmd);
468 if (result >= FINISHED)
469 cmd.view()->unlockInset(this);
470 first_after_edit = false;
477 bool InsetCollapsable::lockInsetInInset(BufferView * bv, UpdatableInset * in)
481 return inset.lockInsetInInset(bv, in);
485 bool InsetCollapsable::unlockInsetInInset(BufferView * bv, UpdatableInset * in,
489 bv->unlockInset(this);
492 return inset.unlockInsetInInset(bv, in, lr);
496 bool InsetCollapsable::updateInsetInInset(BufferView * bv, Inset *in)
500 return inset.updateInsetInInset(bv, in);
504 int InsetCollapsable::insetInInsetY() const
506 return inset.insetInInsetY() - (top_baseline - inset.y());
510 void InsetCollapsable::validate(LaTeXFeatures & features) const
512 inset.validate(features);
516 void InsetCollapsable::getCursorPos(BufferView * bv, int & x, int & y) const
518 inset.getCursorPos(bv, x , y);
522 void InsetCollapsable::toggleInsetCursor(BufferView * bv)
524 inset.toggleInsetCursor(bv);
528 void InsetCollapsable::showInsetCursor(BufferView * bv, bool show)
530 inset.showInsetCursor(bv, show);
534 void InsetCollapsable::hideInsetCursor(BufferView * bv)
536 inset.hideInsetCursor(bv);
540 UpdatableInset * InsetCollapsable::getLockingInset() const
542 UpdatableInset * in = inset.getLockingInset();
543 if (const_cast<InsetText *>(&inset) == in)
544 return const_cast<InsetCollapsable *>(this);
549 UpdatableInset * InsetCollapsable::getFirstLockingInsetOfType(Inset::Code c)
553 return inset.getFirstLockingInsetOfType(c);
557 void InsetCollapsable::setFont(BufferView * bv, LyXFont const & font,
558 bool toggleall, bool selectall)
560 inset.setFont(bv, font, toggleall, selectall);
564 bool InsetCollapsable::doClearArea() const
566 return inset.doClearArea();
570 LyXText * InsetCollapsable::getLyXText(BufferView const * bv,
571 bool const recursive) const
573 return inset.getLyXText(bv, recursive);
577 void InsetCollapsable::deleteLyXText(BufferView * bv, bool recursive) const
579 inset.deleteLyXText(bv, recursive);
583 void InsetCollapsable::resizeLyXText(BufferView * bv, bool force) const
585 inset.resizeLyXText(bv, force);
586 LyXFont font(LyXFont::ALL_SANE);
587 oldWidth = width(bv, font);
591 vector<string> const InsetCollapsable::getLabelList() const
593 return inset.getLabelList();
597 bool InsetCollapsable::nodraw() const
599 return inset.nodraw();
603 int InsetCollapsable::scroll(bool recursive) const
605 int sx = UpdatableInset::scroll(false);
608 sx += inset.scroll(recursive);
614 Paragraph * InsetCollapsable::getParFromID(int id) const
616 lyxerr[Debug::INFO] << "Looking for paragraph " << id << endl;
617 return inset.getParFromID(id);
621 Paragraph * InsetCollapsable::firstParagraph() const
623 return inset.firstParagraph();
627 Paragraph * InsetCollapsable::getFirstParagraph(int i) const
629 return inset.getFirstParagraph(i);
633 LyXCursor const & InsetCollapsable::cursor(BufferView * bv) const
635 return inset.cursor(bv);
639 Inset * InsetCollapsable::getInsetFromID(int id_arg) const
642 return const_cast<InsetCollapsable *>(this);
643 return inset.getInsetFromID(id_arg);
647 void InsetCollapsable::open(BufferView * bv)
649 if (!collapsed_) return;
652 bv->updateInset(this, false);
656 void InsetCollapsable::close(BufferView * bv) const
662 bv->updateInset(const_cast<InsetCollapsable *>(this), false);
666 void InsetCollapsable::setLabel(string const & l) const
672 bool InsetCollapsable::searchForward(BufferView * bv, string const & str,
675 bool found = inset.searchForward(bv, str, cs, mw);
676 if (first_after_edit && !found)
679 first_after_edit = false;
684 bool InsetCollapsable::searchBackward(BufferView * bv, string const & str,
687 bool found = inset.searchBackward(bv, str, cs, mw);
688 if (first_after_edit && !found)
691 first_after_edit = false;
697 InsetCollapsable::selectNextWordToSpellcheck(BufferView * bv, float & value) const
699 WordLangTuple word = inset.selectNextWordToSpellcheck(bv, value);
700 if (first_after_edit && word.word().empty())
702 first_after_edit = false;
707 void InsetCollapsable::addPreview(grfx::PreviewLoader & loader) const
709 inset.addPreview(loader);