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"
31 #include "support/LOstream.h"
32 #include "support/lstrings.h"
43 InsetCollapsable::InsetCollapsable(BufferParams const & bp, bool collapsed)
44 : UpdatableInset(), collapsed_(collapsed), inset(bp),
45 button_length(0), button_top_y(0), button_bottom_y(0),
46 need_update(NONE), label("Label"),
50 oldWidth(0), in_update(false), first_after_edit(false)
53 inset.setAutoBreakRows(true);
54 inset.setDrawFrame(0, InsetText::ALWAYS);
55 inset.setFrameColor(0, LColor::collapsableframe);
56 setInsetName("Collapsable");
60 InsetCollapsable::InsetCollapsable(InsetCollapsable const & in, bool same_id)
61 : UpdatableInset(in, same_id), collapsed_(in.collapsed_),
62 framecolor(in.framecolor), labelfont(in.labelfont), inset(in.inset),
63 button_length(0), button_top_y(0), button_bottom_y(0),
64 need_update(NONE), label(in.label),
66 autocollapse(in.autocollapse),
68 oldWidth(0), in_update(false), first_after_edit(false)
70 inset.init(&(in.inset), same_id);
75 bool InsetCollapsable::insertInset(BufferView * bv, Inset * in)
77 if (!insetAllowed(in->lyxCode())) {
78 lyxerr << "InsetCollapsable::InsertInset: "
79 "Unable to insert inset." << endl;
82 return inset.insertInset(bv, in);
86 void InsetCollapsable::write(Buffer const * buf, ostream & os) const
88 os << "collapsed " << tostr(collapsed_) << "\n";
89 inset.writeParagraphData(buf, os);
94 void InsetCollapsable::read(Buffer const * buf, LyXLex & lex)
98 string const token = lex.getString();
99 if (token == "collapsed") {
101 collapsed_ = lex.getBool();
103 lyxerr << "InsetCollapsable::Read: Missing collapsed!"
105 // Take countermeasures
106 lex.pushToken(token);
109 inset.read(buf, lex);
113 int InsetCollapsable::ascent_collapsed() const
118 font_metrics::buttonText(label, labelfont, width, ascent, descent);
123 int InsetCollapsable::descent_collapsed() const
128 font_metrics::buttonText(label, labelfont, width, ascent, descent);
133 //int InsetCollapsable::width_collapsed(Painter & pain) const
134 int InsetCollapsable::width_collapsed() const
139 font_metrics::buttonText(label, labelfont, width, ascent, descent);
140 return width + 2 * TEXT_TO_INSET_OFFSET;
144 int InsetCollapsable::ascent(BufferView * /*bv*/, LyXFont const &) const
146 return ascent_collapsed();
150 int InsetCollapsable::descent(BufferView * bv, LyXFont const & font) const
153 return descent_collapsed();
155 return descent_collapsed()
156 + inset.descent(bv, font)
157 + inset.ascent(bv, font)
158 + TEXT_TO_BOTTOM_OFFSET;
162 int InsetCollapsable::width(BufferView * bv, LyXFont const & font) const
165 return width_collapsed();
167 int widthCollapsed = width_collapsed();
169 return (inset.width(bv, font) > widthCollapsed) ?
170 inset.width(bv, font) : widthCollapsed;
174 void InsetCollapsable::draw_collapsed(Painter & pain,
175 int baseline, float & x) const
177 pain.buttonText(int(x) + TEXT_TO_INSET_OFFSET,
178 baseline, label, labelfont);
179 x += width_collapsed();
183 void InsetCollapsable::draw(BufferView * bv, LyXFont const & f,
184 int baseline, float & x, bool cleared) const
186 if (need_update != NONE) {
187 const_cast<InsetText *>(&inset)->update(bv, f, true);
188 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
195 Painter & pain = bv->painter();
197 button_length = width_collapsed();
198 button_top_y = -ascent(bv, f);
199 button_bottom_y = -ascent(bv, f) + ascent_collapsed() +
203 draw_collapsed(pain, baseline, x);
210 x += static_cast<float>(scroll());
212 if (!cleared && (inset.need_update == InsetText::FULL ||
213 inset.need_update == InsetText::INIT ||
215 top_baseline != baseline))
217 // we don't need anymore to clear here we just have to tell
218 // the underlying LyXText that it should do the RowClear!
219 inset.setUpdateStatus(bv, InsetText::FULL);
220 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
226 top_baseline = baseline;
228 int const bl = baseline - ascent(bv, f) + ascent_collapsed();
230 draw_collapsed(pain, bl, old_x);
232 bl + descent_collapsed() + inset.ascent(bv, f),
234 if (x < (top_x + button_length + TEXT_TO_INSET_OFFSET))
235 x = top_x + button_length + TEXT_TO_INSET_OFFSET;
239 void InsetCollapsable::edit(BufferView * bv, int xp, int yp,
240 mouse_button::state button)
243 #warning Fix this properly in BufferView_pimpl::workAreaButtonRelease
245 if (button == mouse_button::button3)
248 UpdatableInset::edit(bv, xp, yp, button);
252 // set this only here as it should be recollapsed only if
253 // it was already collapsed!
254 first_after_edit = true;
255 if (!bv->lockInset(this))
257 bv->updateInset(this, false);
260 if (!bv->lockInset(this))
262 if (yp <= button_bottom_y) {
263 inset.edit(bv, xp, 0, button);
265 LyXFont font(LyXFont::ALL_SANE);
266 int yy = ascent(bv, font) + yp -
267 (ascent_collapsed() +
268 descent_collapsed() +
269 inset.ascent(bv, font));
270 inset.edit(bv, xp, yy, button);
276 void InsetCollapsable::edit(BufferView * bv, bool front)
278 UpdatableInset::edit(bv, front);
282 if (!bv->lockInset(this))
284 inset.setUpdateStatus(bv, InsetText::FULL);
285 bv->updateInset(this, false);
286 inset.edit(bv, front);
287 first_after_edit = true;
289 if (!bv->lockInset(this))
291 inset.edit(bv, front);
296 Inset::EDITABLE InsetCollapsable::editable() const
300 return HIGHLY_EDITABLE;
304 void InsetCollapsable::insetUnlock(BufferView * bv)
308 if (change_label_with_text) {
309 draw_label = get_new_label();
316 inset.insetUnlock(bv);
319 bv->updateInset(this, false);
323 void InsetCollapsable::lfunMousePress(FuncRequest const & cmd)
325 if (!collapsed_ && (cmd.y > button_bottom_y)) {
326 LyXFont font(LyXFont::ALL_SANE);
327 FuncRequest cmd1 = cmd;
328 cmd1.y = ascent(cmd.view(), font) + cmd.y -
329 (ascent_collapsed() +
330 descent_collapsed() +
331 inset.ascent(cmd.view(), font));
332 inset.localDispatch(cmd1);
337 bool InsetCollapsable::lfunMouseRelease(FuncRequest const & cmd)
340 BufferView * bv = cmd.view();
341 if ((cmd.button() != mouse_button::button3) && (cmd.x < button_length) &&
342 (cmd.y >= button_top_y) && (cmd.y <= button_bottom_y))
346 // should not be called on inset open!
347 // inset.insetButtonRelease(bv, 0, 0, button);
348 inset.setUpdateStatus(bv, InsetText::FULL);
349 bv->updateInset(this, false);
352 bv->unlockInset(this);
353 bv->updateInset(this, false);
355 } else if (!collapsed_ && (cmd.y > button_bottom_y)) {
356 LyXFont font(LyXFont::ALL_SANE);
357 FuncRequest cmd1 = cmd;
358 cmd1.y = ascent(cmd.view(), font) + cmd.y -
359 (ascent_collapsed() +
360 descent_collapsed() +
361 inset.ascent(cmd.view(), font));
362 ret = (inset.localDispatch(cmd1) == DISPATCHED);
364 if (cmd.button() == mouse_button::button3 && !ret)
365 return showInsetDialog(bv);
370 void InsetCollapsable::lfunMouseMotion(FuncRequest const & cmd)
372 if (cmd.y > button_bottom_y) {
373 LyXFont font(LyXFont::ALL_SANE);
374 FuncRequest cmd1 = cmd;
375 cmd1.y = ascent(cmd.view(), font) + cmd.y -
376 (ascent_collapsed() +
377 descent_collapsed() +
378 inset.ascent(cmd.view(), font));
379 inset.localDispatch(cmd1);
384 int InsetCollapsable::latex(Buffer const * buf, ostream & os,
385 bool fragile, bool free_spc) const
387 return inset.latex(buf, os, fragile, free_spc);
391 int InsetCollapsable::ascii(Buffer const * buf, ostream & os, int ll) const
393 return inset.ascii(buf, os, ll);
397 int InsetCollapsable::linuxdoc(Buffer const * buf, ostream & os) const
399 return inset.linuxdoc(buf, os);
403 int InsetCollapsable::docbook(Buffer const * buf, ostream & os, bool mixcont) const
405 return inset.docbook(buf, os, mixcont);
409 int InsetCollapsable::getMaxWidth(BufferView * bv,
410 UpdatableInset const * in) const
413 int const w = UpdatableInset::getMaxWidth(bv, in);
416 // What does a negative max width signify? (Lgb)
417 // Use the max width of the draw-area (Jug)
420 // should be at least 30 pixels !!!
421 return max(30, w - width_collapsed());
423 return UpdatableInset::getMaxWidth(bv, in);
429 void InsetCollapsable::update(BufferView * bv, LyXFont const & font,
433 if (reinit && owner()) {
434 owner()->update(bv, font, true);
439 inset.update(bv, font, reinit);
440 if (reinit && owner()) {
441 owner()->update(bv, font, true);
447 Inset::RESULT InsetCollapsable::localDispatch(FuncRequest const & cmd)
449 switch (cmd.action) {
451 case LFUN_MOUSE_PRESS:
455 case LFUN_MOUSE_MOTION:
456 lfunMouseMotion(cmd);
459 case LFUN_MOUSE_RELEASE:
460 lfunMouseRelease(cmd);
464 UpdatableInset::RESULT result = inset.localDispatch(cmd);
465 if (result >= FINISHED)
466 cmd.view()->unlockInset(this);
467 first_after_edit = false;
474 bool InsetCollapsable::lockInsetInInset(BufferView * bv, UpdatableInset * in)
478 return inset.lockInsetInInset(bv, in);
482 bool InsetCollapsable::unlockInsetInInset(BufferView * bv, UpdatableInset * in,
486 bv->unlockInset(this);
489 return inset.unlockInsetInInset(bv, in, lr);
493 bool InsetCollapsable::updateInsetInInset(BufferView * bv, Inset *in)
497 return inset.updateInsetInInset(bv, in);
501 int InsetCollapsable::insetInInsetY() const
503 return inset.insetInInsetY() - (top_baseline - inset.y());
507 void InsetCollapsable::validate(LaTeXFeatures & features) const
509 inset.validate(features);
513 void InsetCollapsable::getCursorPos(BufferView * bv, int & x, int & y) const
515 inset.getCursorPos(bv, x , y);
519 void InsetCollapsable::toggleInsetCursor(BufferView * bv)
521 inset.toggleInsetCursor(bv);
525 void InsetCollapsable::showInsetCursor(BufferView * bv, bool show)
527 inset.showInsetCursor(bv, show);
531 void InsetCollapsable::hideInsetCursor(BufferView * bv)
533 inset.hideInsetCursor(bv);
537 UpdatableInset * InsetCollapsable::getLockingInset() const
539 UpdatableInset * in = inset.getLockingInset();
540 if (const_cast<InsetText *>(&inset) == in)
541 return const_cast<InsetCollapsable *>(this);
546 UpdatableInset * InsetCollapsable::getFirstLockingInsetOfType(Inset::Code c)
550 return inset.getFirstLockingInsetOfType(c);
554 void InsetCollapsable::setFont(BufferView * bv, LyXFont const & font,
555 bool toggleall, bool selectall)
557 inset.setFont(bv, font, toggleall, selectall);
561 bool InsetCollapsable::doClearArea() const
563 return inset.doClearArea();
567 LyXText * InsetCollapsable::getLyXText(BufferView const * bv,
568 bool const recursive) const
570 return inset.getLyXText(bv, recursive);
574 void InsetCollapsable::deleteLyXText(BufferView * bv, bool recursive) const
576 inset.deleteLyXText(bv, recursive);
580 void InsetCollapsable::resizeLyXText(BufferView * bv, bool force) const
582 inset.resizeLyXText(bv, force);
583 LyXFont font(LyXFont::ALL_SANE);
584 oldWidth = width(bv, font);
588 vector<string> const InsetCollapsable::getLabelList() const
590 return inset.getLabelList();
594 bool InsetCollapsable::nodraw() const
596 return inset.nodraw();
600 int InsetCollapsable::scroll(bool recursive) const
602 int sx = UpdatableInset::scroll(false);
605 sx += inset.scroll(recursive);
611 Paragraph * InsetCollapsable::firstParagraph() const
613 return inset.firstParagraph();
617 Paragraph * InsetCollapsable::getFirstParagraph(int i) const
619 return inset.getFirstParagraph(i);
623 LyXCursor const & InsetCollapsable::cursor(BufferView * bv) const
625 return inset.cursor(bv);
629 Inset * InsetCollapsable::getInsetFromID(int id_arg) const
632 return const_cast<InsetCollapsable *>(this);
633 return inset.getInsetFromID(id_arg);
637 void InsetCollapsable::open(BufferView * bv)
639 if (!collapsed_) return;
642 bv->updateInset(this, false);
646 void InsetCollapsable::close(BufferView * bv) const
652 bv->updateInset(const_cast<InsetCollapsable *>(this), false);
656 void InsetCollapsable::setLabel(string const & l) const
662 void InsetCollapsable::markErased()
668 bool InsetCollapsable::nextChange(BufferView * bv, lyx::pos_type & length)
670 bool found = inset.nextChange(bv, length);
672 if (first_after_edit && !found)
675 first_after_edit = false;
680 bool InsetCollapsable::searchForward(BufferView * bv, string const & str,
683 bool found = inset.searchForward(bv, str, cs, mw);
684 if (first_after_edit && !found)
687 first_after_edit = false;
692 bool InsetCollapsable::searchBackward(BufferView * bv, string const & str,
695 bool found = inset.searchBackward(bv, str, cs, mw);
696 if (first_after_edit && !found)
699 first_after_edit = false;
705 InsetCollapsable::selectNextWordToSpellcheck(BufferView * bv, float & value) const
707 WordLangTuple word = inset.selectNextWordToSpellcheck(bv, value);
708 if (first_after_edit && word.word().empty())
710 first_after_edit = false;
715 void InsetCollapsable::addPreview(grfx::PreviewLoader & loader) const
717 inset.addPreview(loader);