Slightly improve placement of the text in the topic widget
[quassel.git] / src / uisupport / styledlabel.cpp
index 13690df..38250ea 100644 (file)
@@ -30,14 +30,23 @@ StyledLabel::StyledLabel(QWidget *parent)
 : QFrame(parent),
   _wrapMode(QTextOption::NoWrap),
   _alignment(Qt::AlignVCenter|Qt::AlignLeft),
-  _toolTipEnabled(true)
+  _toolTipEnabled(true),
+  _resizeMode(NoResize)
 {
+  setMouseTracking(true);
+
   QTextOption opt = _layout.textOption();
   opt.setWrapMode(_wrapMode);
   opt.setAlignment(_alignment);
   _layout.setTextOption(opt);
 }
 
+void StyledLabel::setCustomFont(const QFont &font) {
+  setFont(font);
+  _layout.setFont(font);
+  setText(_layout.text());
+}
+
 void StyledLabel::setWrapMode(QTextOption::WrapMode mode) {
   if(_wrapMode == mode)
     return;
@@ -62,6 +71,17 @@ void StyledLabel::setAlignment(Qt::Alignment alignment) {
   layout();
 }
 
+void StyledLabel::setResizeMode(ResizeMode mode) {
+  if(_resizeMode == mode)
+    return;
+
+  _resizeMode = mode;
+  if(mode == DynamicResize)
+    setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+  else
+    setWrapMode(QTextOption::NoWrap);
+}
+
 void StyledLabel::resizeEvent(QResizeEvent *event) {
   QFrame::resizeEvent(event);
 
@@ -89,10 +109,31 @@ void StyledLabel::setText(const QString &text) {
   UiStyle::StyledString sstr = style->styleString(style->mircToInternal(text), UiStyle::PlainMsg);
   QList<QTextLayout::FormatRange> layoutList = style->toTextLayoutList(sstr.formatList, sstr.plainText.length(), 0);
 
+  // Use default font rather than the style's
+  QTextLayout::FormatRange fmtRange;
+  fmtRange.format.setFont(font());
+  fmtRange.start = 0;
+  fmtRange.length = sstr.plainText.length();
+  layoutList << fmtRange;
+
+  // Mark URLs
+  _clickables = ClickableList::fromString(sstr.plainText);
+  foreach(Clickable click, _clickables) {
+    if(click.type() == Clickable::Url) {
+      QTextLayout::FormatRange range;
+      range.start = click.start();
+      range.length = click.length();
+      range.format.setForeground(palette().link());
+      layoutList << range;
+    }
+  }
+
   _layout.setText(sstr.plainText);
   _layout.setAdditionalFormats(layoutList);
 
   layout();
+
+  endHoverMode();
 }
 
 void StyledLabel::updateToolTip() {
@@ -104,7 +145,7 @@ void StyledLabel::updateToolTip() {
 
 void StyledLabel::layout() {
   qreal h = 0;
-  qreal w = frameRect().width() - 2*frameWidth();
+  qreal w = contentsRect().width();
 
   _layout.beginLayout();
   forever {
@@ -122,9 +163,74 @@ void StyledLabel::layout() {
   update();
 }
 
-void StyledLabel::paintEvent(QPaintEvent *) {
+void StyledLabel::paintEvent(QPaintEvent *e) {
+  QFrame::paintEvent(e);
   QPainter painter(this);
 
-  qreal y = (frameRect().height() - _layout.boundingRect().height()) / 2;
-  _layout.draw(&painter, QPointF(0, y), QVector<QTextLayout::FormatRange>());
+  qreal y = contentsRect().y() + (contentsRect().height() - _layout.boundingRect().height()) / 2;
+  _layout.draw(&painter, QPointF(contentsRect().x(), y), _extraLayoutList);
+}
+
+int StyledLabel::posToCursor(const QPointF &pos) {
+  if(pos.y() < 0 || pos.y() > height())
+    return -1;
+
+  for(int l = _layout.lineCount() - 1; l >= 0; l--) {
+    QTextLine line = _layout.lineAt(l);
+    if(pos.y() >= line.y()) {
+      return line.xToCursor(pos.x(), QTextLine::CursorOnCharacter);
+    }
+  }
+  return -1;
+}
+
+void StyledLabel::mouseMoveEvent(QMouseEvent *event) {
+  if(event->buttons() == Qt::NoButton) {
+    Clickable click = _clickables.atCursorPos(posToCursor(event->posF()));
+    if(click.isValid())
+      setHoverMode(click.start(), click.length());
+    else
+      endHoverMode();
+  }
 }
+
+void StyledLabel::enterEvent(QEvent *) {
+  if(resizeMode() == ResizeOnHover)
+    setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+}
+
+void StyledLabel::leaveEvent(QEvent *) {
+  endHoverMode();
+  if(resizeMode() == ResizeOnHover)
+    setWrapMode(QTextOption::NoWrap);
+}
+
+void StyledLabel::mousePressEvent(QMouseEvent *event) {
+  if(event->button() == Qt::LeftButton) {
+    Clickable click = _clickables.atCursorPos(posToCursor(event->posF()));
+    if(click.isValid())
+      emit clickableActivated(click);
+  }
+}
+
+void StyledLabel::setHoverMode(int start, int length) {
+  if(_extraLayoutList.count() >= 1 && _extraLayoutList.first().start == start && _extraLayoutList.first().length == length)
+    return;
+
+  QTextLayout::FormatRange range;
+  range.start = start;
+  range.length = length;
+  range.format.setFontUnderline(true);
+  _extraLayoutList.clear();
+  _extraLayoutList << range;
+
+  setCursor(Qt::PointingHandCursor);
+  update();
+}
+
+void StyledLabel::endHoverMode() {
+  _extraLayoutList.clear();
+  setCursor(Qt::ArrowCursor);
+  update();
+}
+