1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1998-2001 The LyX Team.
8 * ======================================================
14 #pragma implementation
17 #include "insetcollapsable.h"
20 #include "BufferView.h"
21 #include "frontends/Painter.h"
24 #include "frontends/font_metrics.h"
27 #include "insets/insettext.h"
29 #include "support/LOstream.h"
30 #include "support/lstrings.h"
41 InsetCollapsable::InsetCollapsable(BufferParams const & bp, bool collapsed)
42 : UpdatableInset(), collapsed_(collapsed), inset(bp),
43 button_length(0), button_top_y(0), button_bottom_y(0),
44 need_update(NONE), label("Label"),
48 oldWidth(0), in_update(false), first_after_edit(false)
51 inset.setAutoBreakRows(true);
52 inset.setDrawFrame(0, InsetText::ALWAYS);
53 inset.setFrameColor(0, LColor::collapsableframe);
54 setInsetName("Collapsable");
58 InsetCollapsable::InsetCollapsable(InsetCollapsable const & in, bool same_id)
59 : UpdatableInset(in, same_id), collapsed_(in.collapsed_),
60 framecolor(in.framecolor), labelfont(in.labelfont), inset(in.inset),
61 button_length(0), button_top_y(0), button_bottom_y(0),
62 need_update(NONE), label(in.label),
64 autocollapse(in.autocollapse),
66 oldWidth(0), in_update(false), first_after_edit(false)
68 inset.init(&(in.inset), same_id);
73 bool InsetCollapsable::insertInset(BufferView * bv, Inset * in)
75 if (!insetAllowed(in->lyxCode())) {
76 lyxerr << "InsetCollapsable::InsertInset: "
77 "Unable to insert inset." << endl;
80 return inset.insertInset(bv, in);
84 void InsetCollapsable::write(Buffer const * buf, ostream & os) const
86 os << "collapsed " << tostr(collapsed_) << "\n";
87 inset.writeParagraphData(buf, os);
92 void InsetCollapsable::read(Buffer const * buf, LyXLex & lex)
96 string const token = lex.getString();
97 if (token == "collapsed") {
99 collapsed_ = lex.getBool();
101 lyxerr << "InsetCollapsable::Read: Missing collapsed!"
103 // Take countermeasures
104 lex.pushToken(token);
107 inset.read(buf, lex);
111 int InsetCollapsable::ascent_collapsed() const
116 font_metrics::buttonText(label, labelfont, width, ascent, descent);
121 int InsetCollapsable::descent_collapsed() const
126 font_metrics::buttonText(label, labelfont, width, ascent, descent);
131 //int InsetCollapsable::width_collapsed(Painter & pain) const
132 int InsetCollapsable::width_collapsed() const
137 font_metrics::buttonText(label, labelfont, width, ascent, descent);
138 return width + (2*TEXT_TO_INSET_OFFSET);
142 int InsetCollapsable::ascent(BufferView * /*bv*/, LyXFont const &) const
144 return ascent_collapsed();
148 int InsetCollapsable::descent(BufferView * bv, LyXFont const & font) const
151 return descent_collapsed();
153 return descent_collapsed()
154 + inset.descent(bv, font)
155 + inset.ascent(bv, font)
156 + TEXT_TO_BOTTOM_OFFSET;
160 int InsetCollapsable::width(BufferView * bv, LyXFont const & font) const
163 return width_collapsed();
165 int widthCollapsed = width_collapsed();
167 return (inset.width(bv, font) > widthCollapsed) ?
168 inset.width(bv, font) : widthCollapsed;
172 void InsetCollapsable::draw_collapsed(Painter & pain,
173 int baseline, float & x) const
175 pain.buttonText(int(x) + TEXT_TO_INSET_OFFSET,
176 baseline, label, labelfont);
177 x += width_collapsed();
181 void InsetCollapsable::draw(BufferView * bv, LyXFont const & f,
182 int baseline, float & x, bool cleared) const
184 if (need_update != NONE) {
185 const_cast<InsetText *>(&inset)->update(bv, f, true);
186 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
193 Painter & pain = bv->painter();
195 button_length = width_collapsed();
196 button_top_y = -ascent(bv, f);
197 button_bottom_y = -ascent(bv, f) + ascent_collapsed() +
201 draw_collapsed(pain, baseline, x);
208 x += static_cast<float>(scroll());
210 if (!cleared && (inset.need_update == InsetText::FULL ||
211 inset.need_update == InsetText::INIT ||
213 top_baseline != baseline))
215 // we don't need anymore to clear here we just have to tell
216 // the underlying LyXText that it should do the RowClear!
217 inset.setUpdateStatus(bv, InsetText::FULL);
218 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
224 top_baseline = baseline;
226 int const bl = baseline - ascent(bv, f) + ascent_collapsed();
228 draw_collapsed(pain, bl, old_x);
230 bl + descent_collapsed() + inset.ascent(bv, f),
232 if (x < (top_x + button_length + TEXT_TO_INSET_OFFSET))
233 x = top_x + button_length + TEXT_TO_INSET_OFFSET;
237 void InsetCollapsable::edit(BufferView * bv, int xp, int yp,
238 mouse_button::state button)
240 UpdatableInset::edit(bv, xp, yp, button);
244 // set this only here as it should be recollapsed only if
245 // it was already collapsed!
246 first_after_edit = true;
247 if (!bv->lockInset(this))
249 bv->updateInset(this, false);
252 if (!bv->lockInset(this))
254 if (yp <= button_bottom_y) {
255 inset.edit(bv, xp, 0, button);
257 LyXFont font(LyXFont::ALL_SANE);
258 int yy = ascent(bv, font) + yp -
259 (ascent_collapsed() +
260 descent_collapsed() +
261 inset.ascent(bv, font));
262 inset.edit(bv, xp, yy, button);
268 void InsetCollapsable::edit(BufferView * bv, bool front)
270 UpdatableInset::edit(bv, front);
274 if (!bv->lockInset(this))
276 inset.setUpdateStatus(bv, InsetText::FULL);
277 bv->updateInset(this, false);
278 inset.edit(bv, front);
279 first_after_edit = true;
281 if (!bv->lockInset(this))
283 inset.edit(bv, front);
288 Inset::EDITABLE InsetCollapsable::editable() const
292 return HIGHLY_EDITABLE;
296 void InsetCollapsable::insetUnlock(BufferView * bv)
300 if (change_label_with_text) {
301 draw_label = get_new_label();
308 inset.insetUnlock(bv);
311 bv->updateInset(this, false);
315 void InsetCollapsable::insetButtonPress(BufferView * bv,
316 int x, int y, mouse_button::state button)
318 if (!collapsed_ && (y > button_bottom_y)) {
319 LyXFont font(LyXFont::ALL_SANE);
320 int yy = ascent(bv, font) + y -
321 (ascent_collapsed() +
322 descent_collapsed() +
323 inset.ascent(bv, font));
324 inset.insetButtonPress(bv, x, yy, button);
329 bool InsetCollapsable::insetButtonRelease(BufferView * bv,
330 int x, int y, mouse_button::state button)
333 if ((button != mouse_button::button3) && (x < button_length) &&
334 (y >= button_top_y) && (y <= button_bottom_y))
338 // should not be called on inset open!
339 // inset.insetButtonRelease(bv, 0, 0, button);
340 inset.setUpdateStatus(bv, InsetText::FULL);
341 bv->updateInset(this, false);
344 bv->unlockInset(this);
345 bv->updateInset(this, false);
347 } else if (!collapsed_ && (y > button_bottom_y)) {
348 LyXFont font(LyXFont::ALL_SANE);
349 int yy = ascent(bv, font) + y -
350 (ascent_collapsed() +
351 descent_collapsed() +
352 inset.ascent(bv, font));
353 ret = inset.insetButtonRelease(bv, x, yy, button);
355 if ((button == mouse_button::button3) && !ret) {
356 return showInsetDialog(bv);
362 void InsetCollapsable::insetMotionNotify(BufferView * bv,
363 int x, int y, mouse_button::state state)
365 if (y > button_bottom_y) {
366 LyXFont font(LyXFont::ALL_SANE);
367 int yy = ascent(bv, font) + y -
368 (ascent_collapsed() +
369 descent_collapsed() +
370 inset.ascent(bv, font));
371 inset.insetMotionNotify(bv, x, yy, state);
376 int InsetCollapsable::latex(Buffer const * buf, ostream & os,
377 bool fragile, bool free_spc) const
379 return inset.latex(buf, os, fragile, free_spc);
383 int InsetCollapsable::ascii(Buffer const * buf, ostream & os, int ll) const
385 return inset.ascii(buf, os, ll);
389 int InsetCollapsable::linuxdoc(Buffer const * buf, ostream & os) const
391 return inset.linuxdoc(buf, os);
395 int InsetCollapsable::docbook(Buffer const * buf, ostream & os, bool mixcont) const
397 return inset.docbook(buf, os, mixcont);
401 int InsetCollapsable::getMaxWidth(BufferView * bv,
402 UpdatableInset const * in) const
405 int const w = UpdatableInset::getMaxWidth(bv, in);
408 // What does a negative max width signify? (Lgb)
409 // Use the max width of the draw-area (Jug)
412 // should be at least 30 pixels !!!
413 return max(30, w - width_collapsed());
415 return UpdatableInset::getMaxWidth(bv, in);
421 void InsetCollapsable::update(BufferView * bv, LyXFont const & font,
425 if (reinit && owner()) {
426 owner()->update(bv, font, true);
431 inset.update(bv, font, reinit);
432 if (reinit && owner()) {
433 owner()->update(bv, font, true);
439 UpdatableInset::RESULT
440 InsetCollapsable::localDispatch(BufferView * bv, kb_action action,
443 UpdatableInset::RESULT result = inset.localDispatch(bv, action, arg);
444 if (result >= FINISHED)
445 bv->unlockInset(this);
446 first_after_edit = false;
451 bool InsetCollapsable::lockInsetInInset(BufferView * bv, UpdatableInset * in)
455 return inset.lockInsetInInset(bv, in);
459 bool InsetCollapsable::unlockInsetInInset(BufferView * bv, UpdatableInset * in,
463 bv->unlockInset(this);
466 return inset.unlockInsetInInset(bv, in, lr);
470 bool InsetCollapsable::updateInsetInInset(BufferView * bv, Inset *in)
474 return inset.updateInsetInInset(bv, in);
478 int InsetCollapsable::insetInInsetY() const
480 return inset.insetInInsetY() - (top_baseline - inset.y());
484 void InsetCollapsable::validate(LaTeXFeatures & features) const
486 inset.validate(features);
490 void InsetCollapsable::getCursorPos(BufferView * bv, int & x, int & y) const
492 inset.getCursorPos(bv, x , y);
496 void InsetCollapsable::toggleInsetCursor(BufferView * bv)
498 inset.toggleInsetCursor(bv);
502 void InsetCollapsable::showInsetCursor(BufferView * bv, bool show)
504 inset.showInsetCursor(bv, show);
508 void InsetCollapsable::hideInsetCursor(BufferView * bv)
510 inset.hideInsetCursor(bv);
514 UpdatableInset * InsetCollapsable::getLockingInset() const
516 UpdatableInset * in = inset.getLockingInset();
517 if (const_cast<InsetText *>(&inset) == in)
518 return const_cast<InsetCollapsable *>(this);
523 UpdatableInset * InsetCollapsable::getFirstLockingInsetOfType(Inset::Code c)
527 return inset.getFirstLockingInsetOfType(c);
531 void InsetCollapsable::setFont(BufferView * bv, LyXFont const & font,
532 bool toggleall, bool selectall)
534 inset.setFont(bv, font, toggleall, selectall);
538 bool InsetCollapsable::doClearArea() const
540 return inset.doClearArea();
544 LyXText * InsetCollapsable::getLyXText(BufferView const * bv,
545 bool const recursive) const
547 return inset.getLyXText(bv, recursive);
551 void InsetCollapsable::deleteLyXText(BufferView * bv, bool recursive) const
553 inset.deleteLyXText(bv, recursive);
557 void InsetCollapsable::resizeLyXText(BufferView * bv, bool force) const
559 inset.resizeLyXText(bv, force);
560 LyXFont font(LyXFont::ALL_SANE);
561 oldWidth = width(bv, font);
565 vector<string> const InsetCollapsable::getLabelList() const
567 return inset.getLabelList();
571 bool InsetCollapsable::nodraw() const
573 return inset.nodraw();
577 int InsetCollapsable::scroll(bool recursive) const
579 int sx = UpdatableInset::scroll(false);
582 sx += inset.scroll(recursive);
588 Paragraph * InsetCollapsable::getParFromID(int id) const
590 lyxerr[Debug::INFO] << "Looking for paragraph " << id << endl;
591 return inset.getParFromID(id);
595 Paragraph * InsetCollapsable::firstParagraph() const
597 return inset.firstParagraph();
601 Paragraph * InsetCollapsable::getFirstParagraph(int i) const
603 return inset.getFirstParagraph(i);
607 LyXCursor const & InsetCollapsable::cursor(BufferView * bv) const
609 return inset.cursor(bv);
613 Inset * InsetCollapsable::getInsetFromID(int id_arg) const
616 return const_cast<InsetCollapsable *>(this);
617 return inset.getInsetFromID(id_arg);
621 void InsetCollapsable::open(BufferView * bv)
623 if (!collapsed_) return;
626 bv->updateInset(this, false);
630 void InsetCollapsable::close(BufferView * bv) const
636 bv->updateInset(const_cast<InsetCollapsable *>(this), false);
640 void InsetCollapsable::setLabel(string const & l) const
646 bool InsetCollapsable::searchForward(BufferView * bv, string const & str,
649 bool found = inset.searchForward(bv, str, cs, mw);
650 if (first_after_edit && !found)
653 first_after_edit = false;
658 bool InsetCollapsable::searchBackward(BufferView * bv, string const & str,
661 bool found = inset.searchBackward(bv, str, cs, mw);
662 if (first_after_edit && !found)
665 first_after_edit = false;
670 string const InsetCollapsable::selectNextWordToSpellcheck(BufferView * bv,
673 string const str = inset.selectNextWordToSpellcheck(bv, value);
674 if (first_after_edit && str.empty())
676 first_after_edit = false;
681 void InsetCollapsable::addPreview(grfx::PreviewLoader & loader) const
683 inset.addPreview(loader);