Change tracking cue: InsetText and InsetCollapsible

* Underline or strike through the label as if it was text (it is).

* Strike through deleted InsetText, but let RowPainter handle the case of
  non-MultiPar text insets.

* Change the colour of the frame as a cue, unless its colour is customised (not
  Color_foreground). (Essentially do the border of CharStyles like Tabular does
  it already.)

* The change info needs to be reset when entering InsetText. Otherwise labels
  are painted with the change of their n+1-th parent.
This commit is contained in:
Guillaume Munch 2016-05-23 10:01:29 +01:00
parent 16ec606ab4
commit f151b932c2
3 changed files with 94 additions and 52 deletions

View File

@ -33,6 +33,7 @@
#include "support/gettext.h" #include "support/gettext.h"
#include "support/lassert.h" #include "support/lassert.h"
#include "support/lstrings.h" #include "support/lstrings.h"
#include "support/RefChanger.h"
using namespace std; using namespace std;
@ -228,9 +229,7 @@ void InsetCollapsable::draw(PainterInfo & pi, int x, int y) const
view_[&bv].auto_open_ = bv.cursor().isInside(this); view_[&bv].auto_open_ = bv.cursor().isInside(this);
FontInfo tmpfont = pi.base.font; Changer dummy = pi.base.font.change(getFont(), true);
pi.base.font = getFont();
pi.base.font.realize(tmpfont);
// Draw button first -- top, left or only // Draw button first -- top, left or only
Dimension dimc = dimensionCollapsed(bv); Dimension dimc = dimensionCollapsed(bv);
@ -246,7 +245,11 @@ void InsetCollapsable::draw(PainterInfo & pi, int x, int y) const
FontInfo labelfont = getLabelfont(); FontInfo labelfont = getLabelfont();
labelfont.setColor(labelColor()); labelfont.setColor(labelColor());
pi.pain.buttonText(x, y, buttonLabel(bv), labelfont, pi.pain.buttonText(x, y, buttonLabel(bv), labelfont,
view_[&bv].mouse_hover_); view_[&bv].mouse_hover_);
// Draw the change tracking cue on the label, unless RowPainter already
// takes care of it.
if (canPaintChange(bv))
pi.change_.paintCue(pi, x, y, x + dimc.width(), labelfont);
} else { } else {
view_[&bv].button_dim_.x1 = 0; view_[&bv].button_dim_.x1 = 0;
view_[&bv].button_dim_.y1 = 0; view_[&bv].button_dim_.y1 = 0;
@ -257,17 +260,24 @@ void InsetCollapsable::draw(PainterInfo & pi, int x, int y) const
Dimension const textdim = InsetText::dimension(bv); Dimension const textdim = InsetText::dimension(bv);
int const baseline = y; int const baseline = y;
int textx, texty; int textx, texty;
switch (geometry(bv)) { Geometry g = geometry(bv);
switch (g) {
case LeftButton: case LeftButton:
textx = x + dimc.width(); case TopButton: {
texty = baseline; if (g == LeftButton) {
InsetText::draw(pi, textx, texty); textx = x + dimc.width();
break; texty = baseline;
case TopButton: } else {
textx = x; textx = x;
texty = baseline + dimc.des + textdim.asc; texty = baseline + dimc.des + textdim.asc;
}
// Do not draw the cue for INSERTED -- it is already in the button and
// that's enough.
Changer dummy = make_change(pi.change_, Change(),
pi.change_.type == Change::INSERTED);
InsetText::draw(pi, textx, texty); InsetText::draw(pi, textx, texty);
break; break;
}
case ButtonOnly: case ButtonOnly:
break; break;
case NoButton: case NoButton:
@ -279,38 +289,43 @@ void InsetCollapsable::draw(PainterInfo & pi, int x, int y) const
case Corners: case Corners:
textx = x; textx = x;
texty = baseline; texty = baseline;
const_cast<InsetCollapsable *>(this)->setDrawFrame(false); { // We will take care of the frame and the change tracking cue
InsetText::draw(pi, textx, texty); // ourselves, below.
const_cast<InsetCollapsable *>(this)->setDrawFrame(true); Changer dummy = make_change(pi.change_, Change());
const_cast<InsetCollapsable *>(this)->setDrawFrame(false);
InsetText::draw(pi, textx, texty);
const_cast<InsetCollapsable *>(this)->setDrawFrame(true);
}
int desc = textdim.descent(); int desc = textdim.descent();
if (geometry(bv) == Corners) if (g == Corners)
desc -= 3; desc -= 3;
// Colour the frame according to the change type. (Like for tables.)
Color colour = pi.change_.changed() ? pi.change_.color()
: Color_foreground;
const int xx1 = x + TEXT_TO_INSET_OFFSET - 1; const int xx1 = x + TEXT_TO_INSET_OFFSET - 1;
const int xx2 = x + textdim.wid - TEXT_TO_INSET_OFFSET + 1; const int xx2 = x + textdim.wid - TEXT_TO_INSET_OFFSET + 1;
pi.pain.line(xx1, y + desc - 4, pi.pain.line(xx1, y + desc - 4,
xx1, y + desc, xx1, y + desc, colour);
Color_foreground);
if (status_ == Open) if (status_ == Open)
pi.pain.line(xx1, y + desc, pi.pain.line(xx1, y + desc,
xx2, y + desc, xx2, y + desc, colour);
Color_foreground);
else { else {
// Make status_ value visible: // Make status_ value visible:
pi.pain.line(xx1, y + desc, pi.pain.line(xx1, y + desc,
xx1 + 4, y + desc, xx1 + 4, y + desc, colour);
Color_foreground);
pi.pain.line(xx2 - 4, y + desc, pi.pain.line(xx2 - 4, y + desc,
xx2, y + desc, xx2, y + desc, colour);
Color_foreground);
} }
pi.pain.line(x + textdim.wid - 3, y + desc, x + textdim.wid - 3, pi.pain.line(x + textdim.wid - 3, y + desc, x + textdim.wid - 3,
y + desc - 4, Color_foreground); y + desc - 4, colour);
// the label below the text. Can be toggled. // the label below the text. Can be toggled.
if (geometry(bv) == SubLabel) { if (g == SubLabel) {
FontInfo font(getLabelfont()); FontInfo font(getLabelfont());
if (pi.change_.changed())
font.setPaintColor(colour);
font.realize(sane_font); font.realize(sane_font);
font.decSize(); font.decSize();
font.decSize(); font.decSize();
@ -323,20 +338,21 @@ void InsetCollapsable::draw(PainterInfo & pi, int x, int y) const
buttonLabel(bv), font, Color_none, Color_none); buttonLabel(bv), font, Color_none, Color_none);
} }
int const y1 = y - textdim.asc + 3;
// a visual cue when the cursor is inside the inset // a visual cue when the cursor is inside the inset
Cursor const & cur = bv.cursor(); Cursor const & cur = bv.cursor();
if (cur.isInside(this)) { if (cur.isInside(this)) {
y -= textdim.asc; pi.pain.line(xx1, y1 + 4, xx1, y1, colour);
y += 3; pi.pain.line(xx1 + 4, y1, xx1, y1, colour);
pi.pain.line(xx1, y + 4, xx1, y, Color_foreground); pi.pain.line(xx2, y1 + 4, xx2, y1, colour);
pi.pain.line(xx1 + 4, y, xx1, y, Color_foreground); pi.pain.line(xx2 - 4, y1, xx2, y1, colour);
pi.pain.line(xx2, y + 4, xx2, y, Color_foreground);
pi.pain.line(xx2 - 4, y, xx2, y, Color_foreground);
} }
// Strike through the inset if deleted and not already handled by
// RowPainter.
if (pi.change_.deleted() && canPaintChange(bv))
pi.change_.paintCue(pi, xx1, y1, xx2, y + desc);
break; break;
} }
pi.base.font = tmpfont;
} }
@ -618,16 +634,18 @@ string InsetCollapsable::contextMenuName() const
bool InsetCollapsable::canPaintChange(BufferView const & bv) const bool InsetCollapsable::canPaintChange(BufferView const & bv) const
{ {
// return false to let RowPainter draw the change tracking cue consistently
// with the surrounding text, when the inset is inline: for buttons, for
// non-allowMultiPar insets.
switch (geometry(bv)) { switch (geometry(bv)) {
case Corners: case Corners:
case SubLabel: case SubLabel:
return allowMultiPar();
case ButtonOnly: case ButtonOnly:
// these cases are handled by RowPainter since the inset is inline.
return false; return false;
default: default:
break; break;
} }
// TODO: implement the drawing in the remaining cases
return true; return true;
} }

View File

@ -56,13 +56,13 @@
#include "frontends/alert.h" #include "frontends/alert.h"
#include "frontends/Painter.h" #include "frontends/Painter.h"
#include "support/bind.h"
#include "support/convert.h" #include "support/convert.h"
#include "support/debug.h" #include "support/debug.h"
#include "support/gettext.h" #include "support/gettext.h"
#include "support/lstrings.h"
#include "support/bind.h"
#include "support/lassert.h" #include "support/lassert.h"
#include "support/lstrings.h"
#include "support/RefChanger.h"
#include <algorithm> #include <algorithm>
@ -215,24 +215,48 @@ void InsetText::draw(PainterInfo & pi, int x, int y) const
{ {
TextMetrics & tm = pi.base.bv->textMetrics(&text_); TextMetrics & tm = pi.base.bv->textMetrics(&text_);
int const w = tm.width() + TEXT_TO_INSET_OFFSET;
int const yframe = y - TEXT_TO_INSET_OFFSET - tm.ascent();
int const h = tm.height() + 2 * TEXT_TO_INSET_OFFSET;
int const xframe = x + TEXT_TO_INSET_OFFSET / 2;
bool change_drawn = false;
if (drawFrame_ || pi.full_repaint) { if (drawFrame_ || pi.full_repaint) {
int const w = tm.width() + TEXT_TO_INSET_OFFSET;
int const yframe = y - TEXT_TO_INSET_OFFSET - tm.ascent();
int const h = tm.height() + 2 * TEXT_TO_INSET_OFFSET;
int const xframe = x + TEXT_TO_INSET_OFFSET / 2;
if (pi.full_repaint) if (pi.full_repaint)
pi.pain.fillRectangle(xframe, yframe, w, h, pi.pain.fillRectangle(xframe, yframe, w, h,
pi.backgroundColor(this)); pi.backgroundColor(this));
// Change color of the frame in tracked changes, like for tabulars.
// Only do so if the color is not custom. But do so even if RowPainter
// handles the strike-through already.
Color c;
if (pi.change_.changed()
// Originally, these are the colors with role Text, from role() in
// ColorCache.cpp. The code is duplicated to avoid depending on Qt
// types, and also maybe it need not match in the future.
&& (frameColor() == Color_foreground
|| frameColor() == Color_cursor
|| frameColor() == Color_preview
|| frameColor() == Color_tabularline
|| frameColor() == Color_previewframe)) {
c = pi.change_.color();
change_drawn = true;
} else
c = frameColor();
if (drawFrame_) if (drawFrame_)
pi.pain.rectangle(xframe, yframe, w, h, frameColor()); pi.pain.rectangle(xframe, yframe, w, h, c);
} }
ColorCode const old_color = pi.background_color; {
pi.background_color = pi.backgroundColor(this, false); Changer dummy = make_change(pi.background_color,
pi.backgroundColor(this, false));
tm.draw(pi, x + TEXT_TO_INSET_OFFSET, y); // The change tracking cue must not be inherited
Changer dummy2 = make_change(pi.change_, Change());
pi.background_color = old_color; tm.draw(pi, x + TEXT_TO_INSET_OFFSET, y);
}
if (canPaintChange(*pi.base.bv) && (!change_drawn || pi.change_.deleted()))
// Do not draw the change tracking cue if already done by RowPainter and
// do not draw the cue for INSERTED if the information is already in the
// color of the frame
pi.change_.paintCue(pi, xframe, yframe, xframe + w, yframe + h);
} }

View File

@ -63,8 +63,8 @@ public:
bool editable() const { return true; } bool editable() const { return true; }
/// ///
bool canTrackChanges() const { return true; } bool canTrackChanges() const { return true; }
/// /// Rely on RowPainter to draw the cue of inline insets.
bool canPaintChange(BufferView const &) const { return false; } bool canPaintChange(BufferView const &) const { return allowMultiPar(); }
/// ///
InsetText * asInsetText() { return this; } InsetText * asInsetText() { return this; }
/// ///