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"
18 #include "insettext.h"
20 #include "BufferView.h"
26 #include "WordLangTuple.h"
27 #include "funcrequest.h"
29 #include "frontends/font_metrics.h"
30 #include "frontends/Painter.h"
32 #include "support/LOstream.h"
33 #include "support/lstrings.h"
44 InsetCollapsable::InsetCollapsable(BufferParams const & bp, bool collapsed)
45 : UpdatableInset(), collapsed_(collapsed), inset(bp),
46 button_length(0), button_top_y(0), button_bottom_y(0),
47 need_update(NONE), label("Label"),
51 oldWidth(0), in_update(false), first_after_edit(false)
54 inset.setAutoBreakRows(true);
55 inset.setDrawFrame(0, InsetText::ALWAYS);
56 inset.setFrameColor(0, LColor::collapsableframe);
57 setInsetName("Collapsable");
61 InsetCollapsable::InsetCollapsable(InsetCollapsable const & in, bool same_id)
62 : UpdatableInset(in, same_id), collapsed_(in.collapsed_),
63 framecolor(in.framecolor), labelfont(in.labelfont), inset(in.inset),
64 button_length(0), button_top_y(0), button_bottom_y(0),
65 need_update(NONE), label(in.label),
67 autocollapse(in.autocollapse),
69 oldWidth(0), in_update(false), first_after_edit(false)
71 inset.init(&(in.inset), same_id);
76 bool InsetCollapsable::insertInset(BufferView * bv, Inset * in)
78 if (!insetAllowed(in->lyxCode())) {
79 lyxerr << "InsetCollapsable::InsertInset: "
80 "Unable to insert inset." << endl;
83 return inset.insertInset(bv, in);
87 void InsetCollapsable::write(Buffer const * buf, ostream & os) const
89 os << "collapsed " << tostr(collapsed_) << "\n";
90 inset.writeParagraphData(buf, os);
95 void InsetCollapsable::read(Buffer const * buf, LyXLex & lex)
99 string const token = lex.getString();
100 if (token == "collapsed") {
102 collapsed_ = lex.getBool();
104 lyxerr << "InsetCollapsable::Read: Missing collapsed!"
106 // Take countermeasures
107 lex.pushToken(token);
110 inset.read(buf, lex);
114 int InsetCollapsable::ascent_collapsed() const
119 font_metrics::buttonText(label, labelfont, width, ascent, descent);
124 int InsetCollapsable::descent_collapsed() const
129 font_metrics::buttonText(label, labelfont, width, ascent, descent);
134 //int InsetCollapsable::width_collapsed(Painter & pain) const
135 int InsetCollapsable::width_collapsed() const
140 font_metrics::buttonText(label, labelfont, width, ascent, descent);
141 return width + 2 * TEXT_TO_INSET_OFFSET;
145 int InsetCollapsable::ascent(BufferView * /*bv*/, LyXFont const &) const
147 return ascent_collapsed();
151 int InsetCollapsable::descent(BufferView * bv, LyXFont const & font) const
154 return descent_collapsed();
156 return descent_collapsed()
157 + inset.descent(bv, font)
158 + inset.ascent(bv, font)
159 + TEXT_TO_BOTTOM_OFFSET;
163 int InsetCollapsable::width(BufferView * bv, LyXFont const & font) const
166 return width_collapsed();
168 int widthCollapsed = width_collapsed();
170 return (inset.width(bv, font) > widthCollapsed) ?
171 inset.width(bv, font) : widthCollapsed;
175 void InsetCollapsable::draw_collapsed(Painter & pain,
176 int baseline, float & x) const
178 pain.buttonText(int(x) + TEXT_TO_INSET_OFFSET,
179 baseline, label, labelfont);
180 x += width_collapsed();
184 void InsetCollapsable::draw(BufferView * bv, LyXFont const & f,
185 int baseline, float & x, bool cleared) const
187 if (need_update != NONE) {
188 const_cast<InsetText *>(&inset)->update(bv, f, true);
189 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
196 Painter & pain = bv->painter();
198 button_length = width_collapsed();
199 button_top_y = -ascent(bv, f);
200 button_bottom_y = -ascent(bv, f) + ascent_collapsed() +
204 draw_collapsed(pain, baseline, x);
211 x += static_cast<float>(scroll());
213 if (!cleared && (inset.need_update == InsetText::FULL ||
214 inset.need_update == InsetText::INIT ||
216 top_baseline != baseline))
218 // we don't need anymore to clear here we just have to tell
219 // the underlying LyXText that it should do the RowClear!
220 inset.setUpdateStatus(bv, InsetText::FULL);
221 bv->text->status(bv, LyXText::CHANGED_IN_DRAW);
227 top_baseline = baseline;
229 int const bl = baseline - ascent(bv, f) + ascent_collapsed();
231 draw_collapsed(pain, bl, old_x);
233 bl + descent_collapsed() + inset.ascent(bv, f),
235 if (x < (top_x + button_length + TEXT_TO_INSET_OFFSET))
236 x = top_x + button_length + TEXT_TO_INSET_OFFSET;
240 void InsetCollapsable::edit(BufferView * bv, int xp, int yp,
241 mouse_button::state button)
244 #warning Fix this properly in BufferView_pimpl::workAreaButtonRelease
246 if (button == mouse_button::button3)
249 UpdatableInset::edit(bv, xp, yp, button);
253 // set this only here as it should be recollapsed only if
254 // it was already collapsed!
255 first_after_edit = true;
256 if (!bv->lockInset(this))
258 bv->updateInset(this, false);
261 if (!bv->lockInset(this))
263 if (yp <= button_bottom_y) {
264 inset.edit(bv, xp, 0, button);
266 LyXFont font(LyXFont::ALL_SANE);
267 int yy = ascent(bv, font) + yp -
268 (ascent_collapsed() +
269 descent_collapsed() +
270 inset.ascent(bv, font));
271 inset.edit(bv, xp, yy, button);
277 void InsetCollapsable::edit(BufferView * bv, bool front)
279 UpdatableInset::edit(bv, front);
283 if (!bv->lockInset(this))
285 inset.setUpdateStatus(bv, InsetText::FULL);
286 bv->updateInset(this, false);
287 inset.edit(bv, front);
288 first_after_edit = true;
290 if (!bv->lockInset(this))
292 inset.edit(bv, front);
297 Inset::EDITABLE InsetCollapsable::editable() const
301 return HIGHLY_EDITABLE;
305 void InsetCollapsable::insetUnlock(BufferView * bv)
309 if (change_label_with_text) {
310 draw_label = get_new_label();
317 inset.insetUnlock(bv);
320 bv->updateInset(this, false);
324 void InsetCollapsable::lfunMousePress(FuncRequest const & cmd)
326 if (!collapsed_ && (cmd.y > button_bottom_y)) {
327 LyXFont font(LyXFont::ALL_SANE);
328 FuncRequest cmd1 = cmd;
329 cmd1.y = ascent(cmd.view(), font) + cmd.y -
330 (ascent_collapsed() +
331 descent_collapsed() +
332 inset.ascent(cmd.view(), font));
333 inset.localDispatch(cmd1);
338 bool InsetCollapsable::lfunMouseRelease(FuncRequest const & cmd)
341 BufferView * bv = cmd.view();
342 if ((cmd.button() != mouse_button::button3) && (cmd.x < button_length) &&
343 (cmd.y >= button_top_y) && (cmd.y <= button_bottom_y))
347 // should not be called on inset open!
348 // inset.insetButtonRelease(bv, 0, 0, button);
349 inset.setUpdateStatus(bv, InsetText::FULL);
350 bv->updateInset(this, false);
353 bv->unlockInset(this);
354 bv->updateInset(this, false);
356 } else if (!collapsed_ && (cmd.y > button_bottom_y)) {
357 LyXFont font(LyXFont::ALL_SANE);
358 FuncRequest cmd1 = cmd;
359 cmd1.y = ascent(cmd.view(), font) + cmd.y -
360 (ascent_collapsed() +
361 descent_collapsed() +
362 inset.ascent(cmd.view(), font));
363 ret = (inset.localDispatch(cmd1) == DISPATCHED);
365 if (cmd.button() == mouse_button::button3 && !ret)
366 return showInsetDialog(bv);
371 void InsetCollapsable::lfunMouseMotion(FuncRequest const & cmd)
373 if (cmd.y > button_bottom_y) {
374 LyXFont font(LyXFont::ALL_SANE);
375 FuncRequest cmd1 = cmd;
376 cmd1.y = ascent(cmd.view(), font) + cmd.y -
377 (ascent_collapsed() +
378 descent_collapsed() +
379 inset.ascent(cmd.view(), font));
380 inset.localDispatch(cmd1);
385 int InsetCollapsable::latex(Buffer const * buf, ostream & os,
386 bool fragile, bool free_spc) const
388 return inset.latex(buf, os, fragile, free_spc);
392 int InsetCollapsable::ascii(Buffer const * buf, ostream & os, int ll) const
394 return inset.ascii(buf, os, ll);
398 int InsetCollapsable::linuxdoc(Buffer const * buf, ostream & os) const
400 return inset.linuxdoc(buf, os);
404 int InsetCollapsable::docbook(Buffer const * buf, ostream & os, bool mixcont) const
406 return inset.docbook(buf, os, mixcont);
410 int InsetCollapsable::getMaxWidth(BufferView * bv,
411 UpdatableInset const * in) const
414 int const w = UpdatableInset::getMaxWidth(bv, in);
417 // What does a negative max width signify? (Lgb)
418 // Use the max width of the draw-area (Jug)
421 // should be at least 30 pixels !!!
422 return max(30, w - width_collapsed());
424 return UpdatableInset::getMaxWidth(bv, in);
430 void InsetCollapsable::update(BufferView * bv, LyXFont const & font,
434 if (reinit && owner()) {
435 owner()->update(bv, font, true);
440 inset.update(bv, font, reinit);
441 if (reinit && owner()) {
442 owner()->update(bv, font, true);
448 Inset::RESULT InsetCollapsable::localDispatch(FuncRequest const & cmd)
450 switch (cmd.action) {
452 case LFUN_MOUSE_PRESS:
456 case LFUN_MOUSE_MOTION:
457 lfunMouseMotion(cmd);
460 case LFUN_MOUSE_RELEASE:
461 lfunMouseRelease(cmd);
465 UpdatableInset::RESULT result = inset.localDispatch(cmd);
466 if (result >= FINISHED)
467 cmd.view()->unlockInset(this);
468 first_after_edit = false;
475 bool InsetCollapsable::lockInsetInInset(BufferView * bv, UpdatableInset * in)
479 return inset.lockInsetInInset(bv, in);
483 bool InsetCollapsable::unlockInsetInInset(BufferView * bv, UpdatableInset * in,
487 bv->unlockInset(this);
490 return inset.unlockInsetInInset(bv, in, lr);
494 bool InsetCollapsable::updateInsetInInset(BufferView * bv, Inset *in)
498 return inset.updateInsetInInset(bv, in);
502 int InsetCollapsable::insetInInsetY() const
504 return inset.insetInInsetY() - (top_baseline - inset.y());
508 void InsetCollapsable::validate(LaTeXFeatures & features) const
510 inset.validate(features);
514 void InsetCollapsable::getCursorPos(BufferView * bv, int & x, int & y) const
516 inset.getCursorPos(bv, x , y);
520 void InsetCollapsable::toggleInsetCursor(BufferView * bv)
522 inset.toggleInsetCursor(bv);
526 void InsetCollapsable::showInsetCursor(BufferView * bv, bool show)
528 inset.showInsetCursor(bv, show);
532 void InsetCollapsable::hideInsetCursor(BufferView * bv)
534 inset.hideInsetCursor(bv);
538 UpdatableInset * InsetCollapsable::getLockingInset() const
540 UpdatableInset * in = inset.getLockingInset();
541 if (const_cast<InsetText *>(&inset) == in)
542 return const_cast<InsetCollapsable *>(this);
547 UpdatableInset * InsetCollapsable::getFirstLockingInsetOfType(Inset::Code c)
551 return inset.getFirstLockingInsetOfType(c);
555 void InsetCollapsable::setFont(BufferView * bv, LyXFont const & font,
556 bool toggleall, bool selectall)
558 inset.setFont(bv, font, toggleall, selectall);
562 bool InsetCollapsable::doClearArea() const
564 return inset.doClearArea();
568 LyXText * InsetCollapsable::getLyXText(BufferView const * bv,
569 bool const recursive) const
571 return inset.getLyXText(bv, recursive);
575 void InsetCollapsable::deleteLyXText(BufferView * bv, bool recursive) const
577 inset.deleteLyXText(bv, recursive);
581 void InsetCollapsable::resizeLyXText(BufferView * bv, bool force) const
583 inset.resizeLyXText(bv, force);
584 LyXFont font(LyXFont::ALL_SANE);
585 oldWidth = width(bv, font);
589 vector<string> const InsetCollapsable::getLabelList() const
591 return inset.getLabelList();
595 bool InsetCollapsable::nodraw() const
597 return inset.nodraw();
601 int InsetCollapsable::scroll(bool recursive) const
603 int sx = UpdatableInset::scroll(false);
606 sx += inset.scroll(recursive);
612 Paragraph * InsetCollapsable::getParFromID(int id) const
614 lyxerr[Debug::INFO] << "Looking for paragraph " << id << endl;
615 return inset.getParFromID(id);
619 Paragraph * InsetCollapsable::firstParagraph() const
621 return inset.firstParagraph();
625 Paragraph * InsetCollapsable::getFirstParagraph(int i) const
627 return inset.getFirstParagraph(i);
631 LyXCursor const & InsetCollapsable::cursor(BufferView * bv) const
633 return inset.cursor(bv);
637 Inset * InsetCollapsable::getInsetFromID(int id_arg) const
640 return const_cast<InsetCollapsable *>(this);
641 return inset.getInsetFromID(id_arg);
645 void InsetCollapsable::open(BufferView * bv)
647 if (!collapsed_) return;
650 bv->updateInset(this, false);
654 void InsetCollapsable::close(BufferView * bv) const
660 bv->updateInset(const_cast<InsetCollapsable *>(this), false);
664 void InsetCollapsable::setLabel(string const & l) const
670 bool InsetCollapsable::searchForward(BufferView * bv, string const & str,
673 bool found = inset.searchForward(bv, str, cs, mw);
674 if (first_after_edit && !found)
677 first_after_edit = false;
682 bool InsetCollapsable::searchBackward(BufferView * bv, string const & str,
685 bool found = inset.searchBackward(bv, str, cs, mw);
686 if (first_after_edit && !found)
689 first_after_edit = false;
695 InsetCollapsable::selectNextWordToSpellcheck(BufferView * bv, float & value) const
697 WordLangTuple word = inset.selectNextWordToSpellcheck(bv, value);
698 if (first_after_edit && word.word().empty())
700 first_after_edit = false;
705 void InsetCollapsable::addPreview(grfx::PreviewLoader & loader) const
707 inset.addPreview(loader);