MythTV  master
mythuitext.cpp
Go to the documentation of this file.
1 
2 #include "mythuitext.h"
3 
4 #include <cmath>
5 
6 #include <QCoreApplication>
7 #include <QtGlobal>
8 #include <QDomDocument>
9 #include <QFontMetrics>
10 #include <QString>
11 #include <QHash>
12 
13 #include "mythlogging.h"
14 
15 #include "mythuihelper.h"
16 #include "mythpainter.h"
17 #include "mythmainwindow.h"
18 #include "mythfontproperties.h"
19 #include "mythcorecontext.h"
20 
21 #include "compat.h"
22 
23 MythUIText::MythUIText(MythUIType *parent, const QString &name)
24  : MythUIType(parent, name),
25  m_Justification(Qt::AlignLeft | Qt::AlignTop), m_OrigDisplayRect(),
26  m_AltDisplayRect(), m_Canvas(),
27  m_drawRect(), m_cursorPos(-1, -1),
28  m_Message(""), m_CutMessage(""),
29  m_DefaultMessage(""), m_TemplateText(""),
30  m_ShrinkNarrow(true), m_Cutdown(Qt::ElideRight),
31  m_MultiLine(false), m_Ascent(0),
32  m_Descent(0), m_leftBearing(0),
33  m_rightBearing(0), m_Leading(1),
34  m_extraLeading(0), m_lineHeight(0),
35  m_textCursor(-1),
36  m_Font(new MythFontProperties()), m_colorCycling(false),
37  m_startColor(), m_endColor(),
38  m_numSteps(0), m_curStep(0),
39  curR(0.0), curG(0.0), curB(0.0),
40  incR(0.0), incG(0.0), incB(0.0),
41  m_scrollStartDelay(ScrollBounceDelay),
42  m_scrollReturnDelay(ScrollBounceDelay), m_scrollPause(0),
43  m_scrollForwardRate(70.0 / MythMainWindow::drawRefresh),
44  m_scrollReturnRate(70.0 / MythMainWindow::drawRefresh),
45  m_scrollBounce(false), m_scrollOffset(0),
46  m_scrollPos(0), m_scrollPosWhole(0),
47  m_scrollDirection(ScrollNone), m_scrolling(false),
48  m_textCase(CaseNormal)
49 {
50 #if 0 // Not currently used
51  m_usingAltArea = false;
52 #endif
53  m_EnableInitiator = true;
54 
55  m_FontStates.insert("default", MythFontProperties());
56  *m_Font = m_FontStates["default"];
57 }
58 
59 MythUIText::MythUIText(const QString &text, const MythFontProperties &font,
60  QRect displayRect, QRect altDisplayRect,
61  MythUIType *parent, const QString &name)
62  : MythUIType(parent, name),
63  m_Justification(Qt::AlignLeft | Qt::AlignTop),
64  m_OrigDisplayRect(displayRect), m_AltDisplayRect(altDisplayRect),
65  m_Canvas(0, 0, displayRect.width(), displayRect.height()),
66  m_drawRect(displayRect), m_cursorPos(-1, -1),
67  m_Message(text.trimmed()),
68  m_CutMessage(""), m_DefaultMessage(text),
69  m_Cutdown(Qt::ElideRight), m_Font(new MythFontProperties()),
70  m_colorCycling(false), m_startColor(),
71  m_endColor(), m_numSteps(0),
72  m_curStep(0),
73  curR(0.0), curG(0.0), curB(0.0),
74  incR(0.0), incG(0.0), incB(0.0)
75 {
76 #if 0 // Not currently used
77  m_usingAltArea = false;
78 #endif
79  m_ShrinkNarrow = true;
80  m_MultiLine = false;
81 
83  m_scrollPause = 0;
86  m_scrollBounce = false;
87  m_scrollOffset = 0;
88  m_scrollPos = 0;
89  m_scrollPosWhole = 0;
91  m_scrolling = false;
92 
95  m_Leading = 1;
96  m_extraLeading = 0;
97  m_lineHeight = 0;
98  m_textCursor = -1;
99  m_EnableInitiator = true;
100 
101  SetArea(displayRect);
102  m_FontStates.insert("default", font);
103  *m_Font = m_FontStates["default"];
104 }
105 
107 {
108  delete m_Font;
109  m_Font = nullptr;
110 
111  QVector<QTextLayout *>::iterator Ilayout;
112  for (Ilayout = m_Layouts.begin(); Ilayout != m_Layouts.end(); ++Ilayout)
113  delete *Ilayout;
114 }
115 
117 {
119  {
121  SetRedraw();
122  emit DependChanged(true);
123  }
124 
125  SetFontState("default");
126 
128 }
129 
131 {
132  QString newText = GetTemplateText();
133 
134  if (newText.isEmpty())
135  newText = GetDefaultText();
136 
137  QRegExp regexp("%(([^\\|%]+)?\\||\\|(.))?([\\w#]+)(\\|(.+))?%");
138  regexp.setMinimal(true);
139 
140  bool replaced = map.contains(objectName());
141 
142  if (!replaced && !newText.isEmpty() && newText.contains(regexp))
143  {
144  int pos = 0;
145 
146  QString translatedTemplate = qApp->translate("ThemeUI",
147  newText.toUtf8());
148 
149  while ((pos = regexp.indexIn(translatedTemplate, pos)) != -1)
150  {
151  QString key = regexp.cap(4).toLower().trimmed();
152 
153  if (map.contains(key))
154  {
155  replaced = true;
156  break;
157  }
158  pos += regexp.matchedLength();
159  }
160  }
161 
162  if (replaced)
163  {
164  Reset();
165  }
166 }
167 
168 void MythUIText::SetText(const QString &text)
169 {
170  QString newtext = text;
171 
172  if (!m_Layouts.isEmpty() && newtext == m_Message)
173  return;
174 
175  if (newtext.isEmpty())
176  {
178  emit DependChanged(true);
179  }
180  else
181  {
182  m_Message = newtext;
183  emit DependChanged(false);
184  }
185  m_CutMessage.clear();
186  FillCutMessage();
187 
188  SetRedraw();
189 }
190 
192 {
193  QString newText = GetTemplateText();
194 
195  if (newText.isEmpty())
196  newText = GetDefaultText();
197 
198  QRegExp regexp("%(([^\\|%]+)?\\||\\|(.))?([\\w#]+)(\\|(.+))?%");
199  regexp.setMinimal(true);
200 
201  if (!newText.isEmpty() && newText.contains(regexp))
202  {
203  int pos = 0;
204 
205  QString translatedTemplate = qApp->translate("ThemeUI",
206  newText.toUtf8());
207 
208  QString tempString = translatedTemplate;
209  bool replaced = map.contains(objectName());
210 
211  while ((pos = regexp.indexIn(translatedTemplate, pos)) != -1)
212  {
213  QString key = regexp.cap(4).toLower().trimmed();
214  QString replacement;
215 
216  if (map.contains(key))
217  {
218  replaced = true;
219  }
220  if (!map.value(key).isEmpty())
221  {
222  replacement = QString("%1%2%3%4")
223  .arg(regexp.cap(2))
224  .arg(regexp.cap(3))
225  .arg(map.value(key))
226  .arg(regexp.cap(6));
227  }
228 
229  tempString.replace(regexp.cap(0), replacement);
230  pos += regexp.matchedLength();
231  }
232  if (replaced)
233  {
234  SetText(tempString);
235  }
236  }
237  else if (map.contains(objectName()))
238  {
239  SetText(map.value(objectName()));
240  }
241 }
242 
244 {
245  m_FontStates.insert("default", fontProps);
246  if (m_Font->GetHash() != m_FontStates["default"].GetHash())
247  {
248  *m_Font = m_FontStates["default"];
249  if (!m_Message.isEmpty())
250  {
251  FillCutMessage();
252  SetRedraw();
253  }
254  }
255 }
256 
257 void MythUIText::SetFontState(const QString &state)
258 {
259  if (m_FontStates.contains(state))
260  {
261  if (m_Font->GetHash() == m_FontStates[state].GetHash())
262  return;
263  *m_Font = m_FontStates[state];
264  }
265  else
266  {
267  if (m_Font->GetHash() == m_FontStates["default"].GetHash())
268  return;
269  *m_Font = m_FontStates["default"];
270  }
271  if (!m_Message.isEmpty())
272  {
273  FillCutMessage();
274  SetRedraw();
275  }
276 }
277 
278 #if 0 // Not currently used
279 void MythUIText::UseAlternateArea(bool useAlt)
280 {
281  if (useAlt && m_AltDisplayRect.width() > 1)
282  {
284  m_usingAltArea = true;
285  }
286  else
287  {
289  m_usingAltArea = false;
290  }
291 
292  FillCutMessage();
293 }
294 #endif
295 
297 {
298  int h = just & Qt::AlignHorizontal_Mask;
299  int v = just & Qt::AlignVertical_Mask;
300 
301  if ((h && (m_Justification & Qt::AlignHorizontal_Mask) ^ h) ||
302  (v && (m_Justification & Qt::AlignVertical_Mask) ^ v))
303  {
304  // preserve the wordbreak attribute, drop everything else
305  m_Justification = m_Justification & Qt::TextWordWrap;
306  m_Justification |= just;
307  if (!m_Message.isEmpty())
308  {
309  FillCutMessage();
310  SetRedraw();
311  }
312  }
313 }
314 
316 {
317  return m_Justification;
318 }
319 
320 void MythUIText::SetCutDown(Qt::TextElideMode mode)
321 {
322  if (mode != m_Cutdown)
323  {
324  m_Cutdown = mode;
325  if (m_scrolling && m_Cutdown != Qt::ElideNone)
326  {
327  LOG(VB_GENERAL, LOG_ERR, QString("'%1' (%2): <scroll> and "
328  "<cutdown> are not combinable.")
329  .arg(objectName()).arg(GetXMLLocation()));
330  m_Cutdown = Qt::ElideNone;
331  }
332  if (!m_Message.isEmpty())
333  {
334  FillCutMessage();
335  SetRedraw();
336  }
337  }
338 }
339 
340 void MythUIText::SetMultiLine(bool multiline)
341 {
342  if (multiline != m_MultiLine)
343  {
344  m_MultiLine = multiline;
345 
346  if (m_MultiLine)
347  m_Justification |= Qt::TextWordWrap;
348  else
349  m_Justification &= ~Qt::TextWordWrap;
350 
351  if (!m_Message.isEmpty())
352  {
353  FillCutMessage();
354  SetRedraw();
355  }
356  }
357 }
358 
359 void MythUIText::SetArea(const MythRect &rect)
360 {
361  MythUIType::SetArea(rect);
362  m_CutMessage.clear();
363 
364  m_drawRect = m_Area;
365  FillCutMessage();
366 }
367 
369 {
372 }
373 
375 {
376  QPoint newpoint(x, y);
377 
378  if (newpoint == m_Canvas.topLeft())
379  return;
380 
381  m_Canvas.moveTopLeft(newpoint);
382  SetRedraw();
383 }
384 
385 void MythUIText::ShiftCanvas(int x, int y)
386 {
387  if (x == 0 && y == 0)
388  return;
389 
390  m_Canvas.moveTop(m_Canvas.y() + y);
391  m_Canvas.moveLeft(m_Canvas.x() + x);
392  SetRedraw();
393 }
394 
395 void MythUIText::DrawSelf(MythPainter *p, int xoffset, int yoffset,
396  int alphaMod, QRect clipRect)
397 {
398  if (m_Canvas.isEmpty())
399  return;
400 
402  QRect drawrect = m_drawRect.toQRect();
403  drawrect.translate(xoffset, yoffset);
404  QRect canvas = m_Canvas.toQRect();
405 
406  int alpha = CalcAlpha(alphaMod);
407 
408  if (m_Ascent)
409  {
410  drawrect.setY(drawrect.y() - m_Ascent);
411  canvas.moveTop(canvas.y() + m_Ascent);
412  canvas.setHeight(canvas.height() + m_Ascent);
413  }
414  if (m_Descent)
415  {
416  drawrect.setHeight(drawrect.height() + m_Descent);
417  canvas.setHeight(canvas.height() + m_Descent);
418  }
419 
420  if (m_leftBearing)
421  {
422  drawrect.setX(drawrect.x() + m_leftBearing);
423  canvas.moveLeft(canvas.x() - m_leftBearing);
424  canvas.setWidth(canvas.width() - m_leftBearing);
425  }
426  if (m_rightBearing)
427  {
428  drawrect.setWidth(drawrect.width() - m_rightBearing);
429  canvas.setWidth(canvas.width() - m_rightBearing);
430  }
431 
432  if (GetFontProperties()->hasOutline())
433  {
434  QTextLayout::FormatRange range;
435 
436  QColor outlineColor;
437  int outlineSize, outlineAlpha;
438 
439  GetFontProperties()->GetOutline(outlineColor, outlineSize,
440  outlineAlpha);
441  outlineColor.setAlpha(outlineAlpha);
442 
443  MythPoint outline(outlineSize, outlineSize);
444  outline.NormPoint(); // scale it to screen resolution
445 
446  QPen pen;
447  pen.setBrush(outlineColor);
448  pen.setWidth(outline.x());
449 
450  range.start = 0;
451  range.length = m_CutMessage.size();
452  range.format.setTextOutline(pen);
453  formats.push_back(range);
454 
455  drawrect.setX(drawrect.x() - outline.x());
456  drawrect.setWidth(drawrect.width() + outline.x());
457  drawrect.setY(drawrect.y() - outline.y());
458  drawrect.setHeight(drawrect.height() + outline.y());
459 
460  /* Canvas pos is where the view port (drawrect) pulls from, so
461  * it needs moved to the right for the left edge to be picked up*/
462  canvas.moveLeft(canvas.x() + outline.x());
463  canvas.setWidth(canvas.width() + outline.x());
464  canvas.moveTop(canvas.y() + outline.y());
465  canvas.setHeight(canvas.height() + outline.y());
466  }
467 
468  if (GetFontProperties()->hasShadow())
469  {
470  QPoint shadowOffset;
471  QColor shadowColor;
472  int shadowAlpha;
473 
474  GetFontProperties()->GetShadow(shadowOffset, shadowColor, shadowAlpha);
475 
476  MythPoint shadow(shadowOffset);
477  shadow.NormPoint(); // scale it to screen resolution
478 
479  drawrect.setWidth(drawrect.width() + shadow.x());
480  drawrect.setHeight(drawrect.height() + shadow.y());
481 
482  canvas.setWidth(canvas.width() + shadow.x());
483  canvas.setHeight(canvas.height() + shadow.y());
484  }
485 
486  p->SetClipRect(clipRect);
487  p->DrawTextLayout(canvas, m_Layouts, formats,
488  *GetFontProperties(), alpha, drawrect);
489 }
490 
491 bool MythUIText::Layout(QString & paragraph, QTextLayout *layout, bool final,
492  bool & overflow, qreal width, qreal & height,
493  bool force, qreal & last_line_width,
494  QRectF & min_rect, int & num_lines)
495 {
496  int last_line = 0;
497 
498  layout->setText(paragraph);
499  layout->beginLayout();
500  num_lines = 0;
501  for (;;)
502  {
503  QTextLine line = layout->createLine();
504  if (!line.isValid())
505  break;
506 
507  // Try "visible" width first, so alignment works
508  line.setLineWidth(width);
509 
510  if (!m_MultiLine && line.textLength() < paragraph.size())
511  {
512  if (!force && m_Cutdown != Qt::ElideNone)
513  {
514  QFontMetrics fm(GetFontProperties()->face());
515  paragraph = fm.elidedText(paragraph, m_Cutdown,
516  width - fm.averageCharWidth());
517  return false;
518  }
519  // If text does not fit, then expand so canvas size is correct
520  line.setLineWidth(INT_MAX);
521  }
522 
523  height += m_Leading;
524  line.setPosition(QPointF(0, height));
525  height += m_lineHeight;
526  if (!overflow)
527  {
528  if (height > m_Area.height())
529  {
530  LOG(VB_GUI, num_lines ? LOG_DEBUG : LOG_NOTICE,
531  QString("'%1' (%2): height overflow. line height %3 "
532  "paragraph height %4, area height %5")
533  .arg(objectName())
534  .arg(GetXMLLocation())
535  .arg(line.height())
536  .arg(height)
537  .arg(m_Area.height()));
538 
539  if (!m_MultiLine)
540  m_drawRect.setHeight(height);
541  if (m_Cutdown != Qt::ElideNone)
542  {
543  QFontMetrics fm(GetFontProperties()->face());
544  QString cut_line = fm.elidedText
545  (paragraph.mid(last_line),
546  Qt::ElideRight,
547  width - fm.averageCharWidth());
548  paragraph = paragraph.left(last_line) + cut_line;
549  if (last_line == 0)
550  min_rect |= line.naturalTextRect();
551  return false;
552  }
553  overflow = true;
554  }
555  else
556  m_drawRect.setHeight(height);
557  if (!m_MultiLine)
558  overflow = true;
559  }
560 
561  last_line = line.textStart();
562  last_line_width = line.naturalTextWidth();
563  min_rect |= line.naturalTextRect();
564  ++num_lines;
565 
566  if (final && line.textLength())
567  {
576  QFontMetrics fm(GetFontProperties()->face());
577  int bearing;
578 
579  bearing = fm.leftBearing(m_CutMessage[last_line]);
580  if (m_leftBearing > bearing)
581  m_leftBearing = bearing;
582  bearing = fm.rightBearing
583  (m_CutMessage[last_line + line.textLength() - 1]);
584  if (m_rightBearing > bearing)
585  m_rightBearing = bearing;
586  }
587  }
588 
589  layout->endLayout();
590  return true;
591 }
592 
593 bool MythUIText::LayoutParagraphs(const QStringList & paragraphs,
594  const QTextOption & textoption,
595  qreal width, qreal & height,
596  QRectF & min_rect, qreal & last_line_width,
597  int & num_lines, bool final)
598 {
599  QStringList::const_iterator Ipara;
600  QVector<QTextLayout *>::iterator Ilayout;
601  QTextLayout *layout;
602  QString para;
603  bool overflow = false;
604  qreal saved_height;
605  QRectF saved_rect;
606  int idx;
607 
608  for (Ilayout = m_Layouts.begin(); Ilayout != m_Layouts.end(); ++Ilayout)
609  (*Ilayout)->clearLayout();
610 
611  for (Ipara = paragraphs.begin(), idx = 0;
612  Ipara != paragraphs.end(); ++Ipara, ++idx)
613  {
614  layout = m_Layouts[idx];
615  layout->setTextOption(textoption);
616  layout->setFont(m_Font->face());
617 
618  para = *Ipara;
619  saved_height = height;
620  saved_rect = min_rect;
621  if (!Layout(para, layout, final, overflow, width, height, false,
622  last_line_width, min_rect, num_lines))
623  {
624  // Again, with cut down
625  min_rect = saved_rect;
626  height = saved_height;
627  Layout(para, layout, final, overflow, width, height, true,
628  last_line_width, min_rect, num_lines);
629  break;
630  }
631  }
632  m_drawRect.setWidth(width);
633 
634  return (!overflow);
635 }
636 
637 bool MythUIText::GetNarrowWidth(const QStringList & paragraphs,
638  const QTextOption & textoption, qreal & width)
639 {
640  qreal height, last_line_width, lines;
641  int best_width, too_narrow, last_width = -1;
642  int num_lines = 0;
643  int line_height = 0;
644  int attempt = 0;
645  Qt::TextElideMode cutdown = m_Cutdown;
646  m_Cutdown = Qt::ElideNone;
647 
648  line_height = m_Leading + m_lineHeight;
649  width = m_Area.width() / 2.0;
650  best_width = m_Area.width();
651  too_narrow = 0;
652 
653  for (attempt = 0; attempt < 10; ++attempt)
654  {
655  QRectF min_rect;
656 
657  m_drawRect.setWidth(0);
658  height = 0;
659 
660  LayoutParagraphs(paragraphs, textoption, width, height,
661  min_rect, last_line_width, num_lines, false);
662 
663  if (num_lines <= 0)
664  return false;
665 
666  if (height > m_drawRect.height())
667  {
668  if (too_narrow < width)
669  too_narrow = width;
670 
671  // Too narrow? How many lines didn't fit?
672  lines = static_cast<int>
673  ((height - m_drawRect.height()) / line_height);
674  lines -= (1.0 - last_line_width / width);
675  width += (lines * width) /
676  (m_drawRect.height() / line_height);
677 
678  if (width > best_width || static_cast<int>(width) == last_width)
679  {
680  width = best_width;
681  m_Cutdown = cutdown;
682  return true;
683  }
684  }
685  else
686  {
687  if (best_width > width)
688  best_width = width;
689 
690  lines = static_cast<int>
691  (m_Area.height() - height) / line_height;
692  if (lines >= 1)
693  {
694  // Too wide?
695  width -= width * (lines / num_lines - 1 + lines);
696  if (static_cast<int>(width) == last_width)
697  {
698  m_Cutdown = cutdown;
699  return true;
700  }
701  }
702  else if (last_line_width < m_Area.width())
703  {
704  // Is the last line fully used?
705  width -= (1.0 - last_line_width / width) / num_lines;
706  if (width > last_line_width)
707  width = last_line_width;
708  if (static_cast<int>(width) == last_width)
709  {
710  m_Cutdown = cutdown;
711  return true;
712  }
713  }
714  if (width < too_narrow)
715  width = too_narrow;
716  }
717  last_width = width;
718  }
719 
720  LOG(VB_GENERAL, LOG_ERR, QString("'%1' (%2) GetNarrowWidth: Gave up "
721  "while trying to find optimal width "
722  "for '%3'.")
723  .arg(objectName()).arg(GetXMLLocation()).arg(m_CutMessage));
724 
725  width = best_width;
726  m_Cutdown = cutdown;
727  return false;
728 }
729 
731 {
732  if (m_Area.isNull())
733  return;
734 
735  qreal width, height;
736  QRectF min_rect;
737  QFontMetrics fm(GetFontProperties()->face());
738 
739  m_lineHeight = fm.height();
740  m_Leading = m_MultiLine ? fm.leading() + m_extraLeading : m_extraLeading;
741  m_CutMessage.clear();
742  m_textCursor = -1;
743 
745  {
746  bool isNumber;
747  int value = m_Message.toInt(&isNumber);
748 
749  if (isNumber && m_TemplateText.contains("%n"))
750  {
751  m_CutMessage = qApp->translate("ThemeUI",
752  m_TemplateText.toUtf8(), nullptr,
753  qAbs(value));
754  }
755  else if (m_TemplateText.contains("%1"))
756  {
757  QString tmp = qApp->translate("ThemeUI", m_TemplateText.toUtf8());
758  m_CutMessage = tmp.arg(m_Message);
759  }
760  }
761 
762  if (m_CutMessage.isEmpty())
764 
765  if (m_CutMessage.isEmpty())
766  {
767  if (m_Layouts.empty())
768  m_Layouts.push_back(new QTextLayout);
769 
770  QTextLine line;
771  QTextOption textoption(static_cast<Qt::Alignment>(m_Justification));
772  QVector<QTextLayout *>::iterator Ilayout = m_Layouts.begin();
773 
774  (*Ilayout)->setTextOption(textoption);
775  (*Ilayout)->setText("");
776  (*Ilayout)->beginLayout();
777  line = (*Ilayout)->createLine();
778  line.setLineWidth(m_Area.width());
779  line.setPosition(QPointF(0, 0));
780  (*Ilayout)->endLayout();
781  m_drawRect.setWidth(m_Area.width());
783 
784  for (++Ilayout ; Ilayout != m_Layouts.end(); ++Ilayout)
785  (*Ilayout)->clearLayout();
786 
788  }
789  else
790  {
791  QStringList templist;
792  QStringList::iterator it;
793 
794  switch (m_textCase)
795  {
796  case CaseUpper :
797  m_CutMessage = m_CutMessage.toUpper();
798  break;
799  case CaseLower :
800  m_CutMessage = m_CutMessage.toLower();
801  break;
802  case CaseCapitaliseFirst :
803  //m_CutMessage = m_CutMessage.toLower();
804  templist = m_CutMessage.split(". ");
805 
806  for (it = templist.begin(); it != templist.end(); ++it)
807  (*it).replace(0, 1, (*it).left(1).toUpper());
808 
809  m_CutMessage = templist.join(". ");
810  break;
811  case CaseCapitaliseAll :
812  //m_CutMessage = m_CutMessage.toLower();
813  templist = m_CutMessage.split(" ");
814 
815  for (it = templist.begin(); it != templist.end(); ++it)
816  (*it).replace(0, 1, (*it).left(1).toUpper());
817 
818  m_CutMessage = templist.join(" ");
819  break;
820  case CaseNormal:
821  break;
822  }
823 
824  QTextOption textoption(static_cast<Qt::Alignment>(m_Justification));
825  textoption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
826 
827  int idx, num_lines;
828  qreal last_line_width;
829  QStringList paragraphs = m_CutMessage.split('\n',
830  QString::KeepEmptyParts);
831 
832  for (idx = m_Layouts.size(); idx < paragraphs.size(); ++idx)
833  m_Layouts.push_back(new QTextLayout);
834 
835  if (m_MultiLine && m_ShrinkNarrow &&
836  m_MinSize.isValid() && !m_CutMessage.isEmpty())
837  GetNarrowWidth(paragraphs, textoption, width);
838  else
839  width = m_Area.width();
840 
841  height = 0;
843  LayoutParagraphs(paragraphs, textoption, width, height,
844  min_rect, last_line_width, num_lines, true);
845 
846  m_Canvas.setRect(0, 0, min_rect.x() + min_rect.width(), height);
848  m_scrollBounce = false;
849 
856  QRect actual = fm.boundingRect(m_CutMessage);
857  m_Ascent = -(actual.y() + fm.ascent());
858  m_Descent = actual.height() - fm.height();
859  }
860 
861  if (m_scrolling)
862  {
863  if (m_scrollDirection == ScrollLeft ||
866  {
867  if (m_Canvas.width() > m_drawRect.width())
868  {
869  m_drawRect.setX(m_Area.x());
870  m_drawRect.setWidth(m_Area.width());
871  m_scrollOffset = m_drawRect.x() - m_Canvas.x();
872  }
873  }
874  else
875  {
876  if (m_Canvas.height() > m_drawRect.height())
877  {
878  m_drawRect.setY(m_Area.y());
879  m_drawRect.setHeight(m_Area.height());
880  m_scrollOffset = m_drawRect.y() - m_Canvas.y();
881  }
882  }
883  }
884 
885  // If any of hcenter|vcenter|Justify, center it all, then adjust
886  if (m_Justification & (Qt::AlignCenter|Qt::AlignJustify))
887  {
888  m_drawRect.moveCenter(m_Area.center());
889  min_rect.moveCenter(m_Area.center());
890  }
891 
892  // Adjust horizontal
893  if (m_Justification & Qt::AlignLeft)
894  {
895  // If text size is less than allowed min size, center it
896  if (m_ShrinkNarrow && m_MinSize.isValid() && min_rect.isValid() &&
897  min_rect.width() < m_MinSize.x())
898  {
900  (((m_MinSize.x() - min_rect.width() +
901  fm.averageCharWidth()) / 2)));
902  min_rect.setWidth(m_MinSize.x());
903  }
904  else
906 
907  min_rect.moveLeft(m_Area.x());
908  }
909  else if (m_Justification & Qt::AlignRight)
910  {
911  // If text size is less than allowed min size, center it
912  if (m_ShrinkNarrow && m_MinSize.isValid() && min_rect.isValid() &&
913  min_rect.width() < m_MinSize.x())
914  {
915  m_drawRect.moveRight(m_Area.x() + m_Area.width() -
916  (((m_MinSize.x() - min_rect.width() +
917  fm.averageCharWidth()) / 2)));
918  min_rect.setWidth(m_MinSize.x());
919  }
920  else
921  m_drawRect.moveRight(m_Area.x() + m_Area.width());
922 
923  min_rect.moveRight(m_Area.x() + m_Area.width());
924  }
925 
926  // Adjust vertical
927  if (m_Justification & Qt::AlignTop)
928  {
929  // If text size is less than allowed min size, center it
930  if (!m_ShrinkNarrow && m_MinSize.isValid() && min_rect.isValid() &&
931  min_rect.height() < m_MinSize.y())
932  {
934  ((m_MinSize.y() - min_rect.height()) / 2));
935  min_rect.setHeight(m_MinSize.y());
936  }
937  else
939 
940  min_rect.moveTop(m_Area.y());
941  }
942  else if (m_Justification & Qt::AlignBottom)
943  {
944  // If text size is less than allowed min size, center it
945  if (!m_ShrinkNarrow && m_MinSize.isValid() && min_rect.isValid() &&
946  min_rect.height() < m_MinSize.y())
947  {
948  m_drawRect.moveBottom(m_Area.y() + m_Area.height() -
949  ((m_MinSize.y() - min_rect.height()) / 2));
950  min_rect.setHeight(m_MinSize.y());
951  }
952  else
953  m_drawRect.moveBottom(m_Area.y() + m_Area.height());
954 
955  min_rect.moveBottom(m_Area.y() + m_Area.height());
956  }
957 
959  if (m_MinSize.isValid())
960  {
961  // Record the minimal area needed for the message.
962  SetMinArea(min_rect.toRect());
963  }
964 }
965 
967 {
968  int lineNo = -1;
969  int lineCount = 0;
970  int currPos = 0;
971  int layoutStartPos = 0;
972  int xPos;
973 
974  for (int x = 0; x < m_Layouts.count(); x++)
975  {
976  QTextLayout *layout = m_Layouts.at(x);
977 
978  for (int y = 0; y < layout->lineCount(); y++)
979  {
980  lineCount++;
981  if (lineNo != -1)
982  continue;
983 
984  QTextLine line = layout->lineAt(y);
985 
986  if (m_textCursor >= currPos && m_textCursor < currPos + line.textLength()
987  + (line.lineNumber() == layout->lineCount() - 1 ? 1 : 0))
988  {
989  lineNo = lineCount - 1;
990  xPos = line.cursorToX(m_textCursor - layoutStartPos);
991  continue;
992  }
993 
994  currPos += line.textLength();
995  }
996 
997  currPos += 1; // skip the newline
998  layoutStartPos = currPos;
999  }
1000 
1001  // are we are at the top and need to scroll up
1002  if (lineNo == 0 && lines < 0)
1003  return -1;
1004 
1005  // are we at the bottom and need to scroll down
1006  if (lineNo == lineCount - 1 && lines > 0)
1007  return -1;
1008 
1009  if (lineNo == -1)
1010  {
1011  LOG(VB_GENERAL, LOG_ERR,
1012  QString("'%1' (%2) MoveCursor offset %3 not found in ANY paragraph!")
1013  .arg(objectName()).arg(GetXMLLocation()).arg(m_textCursor));
1014  return m_textCursor;
1015  }
1016 
1017  int newLine = lineNo + lines;
1018 
1019  if (newLine < 0)
1020  newLine = 0;
1021 
1022  if (newLine >= lineCount)
1023  newLine = lineCount - 1;
1024 
1025  lineNo = -1;
1026  currPos = 0;
1027  layoutStartPos = 0;
1028 
1029  for (int x = 0; x < m_Layouts.count(); x++)
1030  {
1031  QTextLayout *layout = m_Layouts.at(x);
1032 
1033  for (int y = 0; y < layout->lineCount(); y++)
1034  {
1035  lineNo++;
1036  QTextLine line = layout->lineAt(y);
1037 
1038  if (lineNo == newLine)
1039  return layoutStartPos + line.xToCursor(xPos);
1040  }
1041 
1042  layoutStartPos += layout->text().length() + 1;
1043  }
1044 
1045  // should never reach here
1046  return m_textCursor;
1047 }
1048 
1049 QPoint MythUIText::CursorPosition(int text_offset)
1050 {
1051  if (m_Layouts.empty())
1052  return m_Area.topLeft().toQPoint();
1053 
1054  if (text_offset == m_textCursor)
1055  return m_cursorPos;
1056  m_textCursor = text_offset;
1057 
1058  QVector<QTextLayout *>::const_iterator Ipara;
1059  QPoint pos;
1060  int x, y, mid, line_height;
1061  int offset = text_offset;
1062 
1063  for (Ipara = m_Layouts.constBegin(); Ipara != m_Layouts.constEnd(); ++Ipara)
1064  {
1065  QTextLine line = (*Ipara)->lineForTextPosition(offset);
1066 
1067  if (line.isValid())
1068  {
1069  pos.setX(line.cursorToX(&offset));
1070  pos.setY(line.y());
1071  break;
1072  }
1073  offset -= ((*Ipara)->text().size() + 1); // Account for \n
1074  }
1075  if (Ipara == m_Layouts.constEnd())
1076  {
1077  LOG(VB_GENERAL, LOG_ERR,
1078  QString("'%1' (%2) CursorPosition offset %3 not found in "
1079  "ANY paragraph!")
1080  .arg(objectName()).arg(GetXMLLocation()).arg(text_offset));
1081  return m_Area.topLeft().toQPoint();
1082  }
1083 
1084  mid = m_drawRect.width() / 2;
1085  if (m_Canvas.width() <= m_drawRect.width() || pos.x() <= mid)
1086  x = 0; // start
1087  else if (pos.x() >= m_Canvas.width() - mid) // end
1088  {
1089  x = m_Canvas.width() - m_drawRect.width();
1090  pos.setX(pos.x() - x);
1091  }
1092  else // middle
1093  {
1094  x = pos.x() - mid;
1095  pos.setX(pos.x() - x);
1096  }
1097 
1098  line_height = m_lineHeight + m_Leading;
1099  mid = m_Area.height() / 2;
1100  mid -= (mid % line_height);
1101  y = pos.y() - mid;
1102 
1103  if (y <= 0 || m_Canvas.height() <= m_Area.height()) // Top of buffer
1104  y = 0;
1105  else if (y + m_Area.height() > m_Canvas.height()) // Bottom of buffer
1106  {
1107  int visible_lines = ((m_Area.height() / line_height) * line_height);
1108  y = m_Canvas.height() - visible_lines;
1109  pos.setY(visible_lines - (m_Canvas.height() - pos.y()));
1110  }
1111  else // somewhere in the middle
1112  {
1113  y -= m_Leading;
1114  pos.setY(mid + m_Leading);
1115  }
1116 
1117  m_Canvas.moveTopLeft(QPoint(-x, -y));
1118 
1119  // Compensate for vertical alignment
1120  pos.setY(pos.y() + m_drawRect.y() - m_Area.y());
1121 
1122  pos += m_Area.topLeft().toQPoint();
1123  m_cursorPos = pos;
1124 
1125  return pos;
1126 }
1127 
1129 {
1130  //
1131  // Call out base class pulse which will handle any alpha cycling and
1132  // movement
1133  //
1134 
1136 
1137  if (m_colorCycling)
1138  {
1139  curR += incR;
1140  curG += incG;
1141  curB += incB;
1142 
1143  m_curStep++;
1144 
1145  if (m_curStep >= m_numSteps)
1146  {
1147  m_curStep = 0;
1148  incR *= -1;
1149  incG *= -1;
1150  incB *= -1;
1151  }
1152 
1153  QColor newColor = QColor((int)curR, (int)curG, (int)curB);
1154 
1155  if (newColor != m_Font->color())
1156  {
1157  m_Font->SetColor(newColor);
1158  SetRedraw();
1159  }
1160  }
1161 
1162  if (m_scrolling)
1163  {
1164  int whole;
1165 
1166  if (m_scrollPause > 0)
1167  --m_scrollPause;
1168  else
1169  {
1170  if (m_scrollBounce)
1172  else
1174  }
1175 
1176  whole = static_cast<int>(m_scrollPos);
1177  if (m_scrollPosWhole != whole)
1178  {
1179  int shift = whole - m_scrollPosWhole;
1180  m_scrollPosWhole = whole;
1181 
1182  switch (m_scrollDirection)
1183  {
1184  case ScrollLeft :
1185  if (m_Canvas.width() > m_drawRect.width())
1186  {
1187  ShiftCanvas(-shift, 0);
1188  if (m_Canvas.x() + m_Canvas.width() < 0)
1189  {
1190  SetCanvasPosition(m_drawRect.width(), 0);
1192  }
1193  }
1194  break;
1195  case ScrollRight :
1196  if (m_Canvas.width() > m_drawRect.width())
1197  {
1198  ShiftCanvas(shift, 0);
1199  if (m_Canvas.x() > m_drawRect.width())
1200  {
1201  SetCanvasPosition(-m_Canvas.width(), 0);
1203  }
1204  }
1205  break;
1206  case ScrollHorizontal:
1207  if (m_Canvas.width() <= m_drawRect.width())
1208  break;
1209  if (m_scrollBounce) // scroll right
1210  {
1211  if (m_Canvas.x() + m_scrollOffset > m_drawRect.x())
1212  {
1213  m_scrollBounce = false;
1216  }
1217  else
1218  ShiftCanvas(shift, 0);
1219  }
1220  else // scroll left
1221  {
1222  if (m_Canvas.x() + m_Canvas.width() + m_scrollOffset <
1223  m_drawRect.x() + m_drawRect.width())
1224  {
1225  m_scrollBounce = true;
1228  }
1229  else
1230  ShiftCanvas(-shift, 0);
1231  }
1232  break;
1233  case ScrollUp :
1234  if (m_Canvas.height() > m_drawRect.height())
1235  {
1236  ShiftCanvas(0, -shift);
1237  if (m_Canvas.y() + m_Canvas.height() < 0)
1238  {
1239  SetCanvasPosition(0, m_drawRect.height());
1241  }
1242  }
1243  break;
1244  case ScrollDown :
1245  if (m_Canvas.height() > m_drawRect.height())
1246  {
1247  ShiftCanvas(0, shift);
1248  if (m_Canvas.y() > m_drawRect.height())
1249  {
1250  SetCanvasPosition(0, -m_Canvas.height());
1252  }
1253  }
1254  break;
1255  case ScrollVertical:
1256  if (m_Canvas.height() <= m_drawRect.height())
1257  break;
1258  if (m_scrollBounce) // scroll down
1259  {
1260  if (m_Canvas.y() + m_scrollOffset > m_drawRect.y())
1261  {
1262  m_scrollBounce = false;
1265  }
1266  else
1267  ShiftCanvas(0, shift);
1268  }
1269  else // scroll up
1270  {
1271  if (m_Canvas.y() + m_Canvas.height() + m_scrollOffset <
1272  m_drawRect.y() + m_drawRect.height())
1273  {
1274  m_scrollBounce = true;
1277  }
1278  else
1279  ShiftCanvas(0, -shift);
1280  }
1281  break;
1282  case ScrollNone:
1283  break;
1284  }
1285  }
1286  }
1287 }
1288 
1289 void MythUIText::CycleColor(QColor startColor, QColor endColor, int numSteps)
1290 {
1291  if (!GetPainter()->SupportsAnimation())
1292  return;
1293 
1294  m_startColor = startColor;
1295  m_endColor = endColor;
1296  m_numSteps = numSteps;
1297  m_curStep = 0;
1298 
1299  curR = startColor.red();
1300  curG = startColor.green();
1301  curB = startColor.blue();
1302 
1303  incR = (endColor.red() * 1.0f - curR) / m_numSteps;
1304  incG = (endColor.green() * 1.0f - curG) / m_numSteps;
1305  incB = (endColor.blue() * 1.0f - curB) / m_numSteps;
1306 
1307  m_colorCycling = true;
1308 }
1309 
1311 {
1312  if (!m_colorCycling)
1313  return;
1314 
1316  m_colorCycling = false;
1317  SetRedraw();
1318 }
1319 
1321  const QString &filename, QDomElement &element, bool showWarnings)
1322 {
1323  if (element.tagName() == "area")
1324  {
1325  SetArea(parseRect(element));
1327  }
1328  // else if (element.tagName() == "altarea") // Unused, but maybe in future?
1329  // m_AltDisplayRect = parseRect(element);
1330  else if (element.tagName() == "font")
1331  {
1332  QString fontname = getFirstText(element);
1333  MythFontProperties *fp = GetFont(fontname);
1334 
1335  if (!fp)
1336  fp = GetGlobalFontMap()->GetFont(fontname);
1337 
1338  if (fp)
1339  {
1340  MythFontProperties font = *fp;
1341  int screenHeight = GetMythMainWindow()->GetUIScreenRect().height();
1342  font.Rescale(screenHeight);
1343  int fontStretch = GetMythUI()->GetFontStretch();
1344  font.AdjustStretch(fontStretch);
1345  QString state = element.attribute("state", "");
1346 
1347  if (!state.isEmpty())
1348  {
1349  m_FontStates.insert(state, font);
1350  }
1351  else
1352  {
1353  m_FontStates.insert("default", font);
1354  *m_Font = m_FontStates["default"];
1355  }
1356  }
1357  }
1358  else if (element.tagName() == "extraleading")
1359  {
1360  m_extraLeading = getFirstText(element).toInt();
1361  }
1362  else if (element.tagName() == "value")
1363  {
1364  if (element.attribute("lang", "").isEmpty())
1365  {
1366  m_Message = qApp->translate("ThemeUI",
1367  parseText(element).toUtf8());
1368  }
1369  else if (element.attribute("lang", "").toLower() ==
1371  {
1372  m_Message = parseText(element);
1373  }
1374  else if (element.attribute("lang", "").toLower() ==
1376  {
1377  m_Message = parseText(element);
1378  }
1379 
1381  SetText(m_Message);
1382  }
1383  else if (element.tagName() == "template")
1384  {
1385  m_TemplateText = parseText(element);
1386  }
1387  else if (element.tagName() == "cutdown")
1388  {
1389  QString mode = getFirstText(element).toLower();
1390 
1391  if (mode == "left")
1392  SetCutDown(Qt::ElideLeft);
1393  else if (mode == "middle")
1394  SetCutDown(Qt::ElideMiddle);
1395  else if (mode == "right" || parseBool(element))
1396  SetCutDown(Qt::ElideRight);
1397  else
1398  SetCutDown(Qt::ElideNone);
1399  }
1400  else if (element.tagName() == "multiline")
1401  {
1402  SetMultiLine(parseBool(element));
1403  }
1404  else if (element.tagName() == "align")
1405  {
1406  QString align = getFirstText(element).toLower();
1408  }
1409  else if (element.tagName() == "colorcycle")
1410  {
1411  if (GetPainter()->SupportsAnimation())
1412  {
1413  QString tmp = element.attribute("start");
1414 
1415  if (!tmp.isEmpty())
1416  m_startColor = QColor(tmp);
1417 
1418  tmp = element.attribute("end");
1419 
1420  if (!tmp.isEmpty())
1421  m_endColor = QColor(tmp);
1422 
1423  tmp = element.attribute("steps");
1424 
1425  if (!tmp.isEmpty())
1426  m_numSteps = tmp.toInt();
1427 
1428  // initialize the rest of the stuff
1430  }
1431  else
1432  m_colorCycling = false;
1433 
1434  m_colorCycling = parseBool(element.attribute("disable"));
1435  }
1436  else if (element.tagName() == "scroll")
1437  {
1438  if (GetPainter()->SupportsAnimation())
1439  {
1440  QString tmp = element.attribute("direction");
1441 
1442  if (!tmp.isEmpty())
1443  {
1444  tmp = tmp.toLower();
1445 
1446  if (tmp == "left")
1448  else if (tmp == "right")
1450  else if (tmp == "up")
1452  else if (tmp == "down")
1454  else if (tmp == "horizontal")
1456  else if (tmp == "vertical")
1458  else
1459  {
1461  LOG(VB_GENERAL, LOG_ERR,
1462  QString("'%1' (%2) Invalid scroll attribute")
1463  .arg(objectName()).arg(GetXMLLocation()));
1464  }
1465  }
1466 
1467  tmp = element.attribute("startdelay");
1468  if (!tmp.isEmpty())
1469  {
1470  float seconds = tmp.toFloat();
1471  m_scrollStartDelay = lroundf(seconds *
1472  static_cast<float>(MythMainWindow::drawRefresh));
1473  }
1474  tmp = element.attribute("returndelay");
1475  if (!tmp.isEmpty())
1476  {
1477  float seconds = tmp.toFloat();
1478  m_scrollReturnDelay = lroundf(seconds *
1479  static_cast<float>(MythMainWindow::drawRefresh));
1480  }
1481  tmp = element.attribute("rate");
1482  if (!tmp.isEmpty())
1483  {
1484 #if 0 // scroll rate as a percentage of 70Hz
1485  float percent = tmp.toFloat() / 100.0;
1486  m_scrollForwardRate = percent *
1487  static_cast<float>(MythMainWindow::drawRefresh) / 70.0;
1488 #else // scroll rate as pixels per second
1489  int pixels = tmp.toInt();
1491  pixels / static_cast<float>(MythMainWindow::drawRefresh);
1492 #endif
1493  }
1494  tmp = element.attribute("returnrate");
1495  if (!tmp.isEmpty())
1496  {
1497 #if 0 // scroll rate as a percentage of 70Hz
1498  float percent = tmp.toFloat() / 100.0;
1499  m_scrollReturnRate = percent *
1500  static_cast<float>(MythMainWindow::drawRefresh) / 70.0;
1501 #else // scroll rate as pixels per second
1502  int pixels = tmp.toInt();
1504  pixels / static_cast<float>(MythMainWindow::drawRefresh);
1505 #endif
1506  }
1507 
1508  m_scrolling = true;
1509  }
1510  else
1511  m_scrolling = false;
1512  }
1513  else if (element.tagName() == "case")
1514  {
1515  QString stringCase = getFirstText(element).toLower();
1516 
1517  if (stringCase == "lower")
1519  else if (stringCase == "upper")
1521  else if (stringCase == "capitalisefirst")
1523  else if (stringCase == "capitaliseall")
1525  else
1527  }
1528  else
1529  {
1530  if (element.tagName() == "minsize" && element.hasAttribute("shrink"))
1531  {
1532  m_ShrinkNarrow = (element.attribute("shrink")
1533  .toLower() != "short");
1534  }
1535 
1536  return MythUIType::ParseElement(filename, element, showWarnings);
1537  }
1538 
1539  return true;
1540 }
1541 
1543 {
1544  MythUIText *text = dynamic_cast<MythUIText *>(base);
1545 
1546  if (!text)
1547  {
1548  LOG(VB_GENERAL, LOG_ERR,
1549  QString("'%1' (%2) ERROR, bad parsing '%3' (%4)")
1550  .arg(objectName()).arg(GetXMLLocation())
1551  .arg(base->objectName()).arg(base->GetXMLLocation()));
1552  return;
1553  }
1554 
1558  m_Canvas = text->m_Canvas;
1559  m_drawRect = text->m_drawRect;
1560 
1562  SetText(text->m_Message);
1563  m_CutMessage = text->m_CutMessage;
1565 
1567  m_Cutdown = text->m_Cutdown;
1568  m_MultiLine = text->m_MultiLine;
1569  m_Leading = text->m_Leading;
1571  m_lineHeight = text->m_lineHeight;
1572  m_textCursor = text->m_textCursor;
1573 
1574  QMutableMapIterator<QString, MythFontProperties> it(text->m_FontStates);
1575 
1576  while (it.hasNext())
1577  {
1578  it.next();
1579  m_FontStates.insert(it.key(), it.value());
1580  }
1581 
1582  *m_Font = m_FontStates["default"];
1583 
1585  m_startColor = text->m_startColor;
1586  m_endColor = text->m_endColor;
1587  m_numSteps = text->m_numSteps;
1588  m_curStep = text->m_curStep;
1589  curR = text->curR;
1590  curG = text->curG;
1591  curB = text->curB;
1592  incR = text->incR;
1593  incG = text->incG;
1594  incB = text->incB;
1595 
1601  m_scrolling = text->m_scrolling;
1602 
1603  m_textCase = text->m_textCase;
1604 
1605  MythUIType::CopyFrom(base);
1606  FillCutMessage();
1607 }
1608 
1610 {
1611  MythUIText *text = new MythUIText(parent, objectName());
1612  text->CopyFrom(this);
1613 }
1614 
1615 
1617 {
1618  if (m_scrolling && m_Cutdown != Qt::ElideNone)
1619  {
1620  LOG(VB_GENERAL, LOG_ERR,
1621  QString("'%1' (%2): <scroll> and <cutdown> are not combinable.")
1622  .arg(objectName()).arg(GetXMLLocation()));
1623  m_Cutdown = Qt::ElideNone;
1624  }
1625  FillCutMessage();
1626 }
QString GetLanguageAndVariant(void)
Returns the user-set language and variant.
QPoint toQPoint(void) const
Definition: mythrect.cpp:569
void SetCanvasPosition(int x, int y)
Definition: mythuitext.cpp:374
QString GetDefaultText(void) const
Definition: mythuitext.h:42
QColor color(void) const
void setHeight(const QString &sHeight)
Definition: mythrect.cpp:260
float m_scrollPos
Definition: mythuitext.h:156
QColor m_endColor
Definition: mythuitext.h:139
void SetFontProperties(const MythFontProperties &fontProps)
Definition: mythuitext.cpp:243
bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings) override
Parse the xml definition of this widget setting the state of the object accordingly.
virtual MythPainter * GetPainter(void)
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
void StopCycling()
static int parseAlignment(const QString &text)
int m_scrollReturnDelay
Definition: mythuitext.h:150
All purpose text widget, displays a text string.
Definition: mythuitext.h:28
MythRect m_drawRect
Definition: mythuitext.h:110
void SetRedraw(void)
Definition: mythuitype.cpp:318
bool m_colorCycling
Definition: mythuitext.h:138
float incG
Definition: mythuitext.h:142
void CycleColor(QColor startColor, QColor endColor, int numSteps)
QString m_TemplateText
Definition: mythuitext.h:116
int m_scrollOffset
Definition: mythuitext.h:155
float m_scrollReturnRate
Definition: mythuitext.h:153
void CreateCopy(MythUIType *parent) override
Copy the state of this widget to the one given, it must be of the same type.
void SetPosition(const MythPoint &pos) override
Definition: mythuitext.cpp:368
void SetTextFromMap(const InfoMap &map)
Definition: mythuitext.cpp:191
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:168
float incR
Definition: mythuitext.h:142
void GetShadow(QPoint &offset, QColor &color, int &alpha) const
MythRect m_Canvas
Definition: mythuitext.h:109
int CalcAlpha(int alphamod)
Definition: mythuitype.cpp:483
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void SetColor(const QColor &color)
QString GetHash(void) const
Qt::TextElideMode m_Cutdown
Definition: mythuitext.h:122
void SetArea(const MythRect &rect) override
Definition: mythuitext.cpp:359
QString m_Message
Definition: mythuitext.h:113
QColor m_startColor
Definition: mythuitext.h:139
int m_rightBearing
Definition: mythuitext.h:127
ScrollDir m_scrollDirection
Definition: mythuitext.h:158
int m_extraLeading
Definition: mythuitext.h:129
const char * formats[8]
Definition: vbilut.cpp:190
static guint32 * tmp
Definition: goom_core.c:35
int m_Leading
Definition: mythuitext.h:128
The base class on which all widgets and screens are based.
Definition: mythuitype.h:63
QString GetXMLLocation(void) const
Definition: mythuitype.h:155
void SetPosition(int x, int y)
Convenience method, calls SetPosition(const MythPoint&) Override that instead to change functionality...
Definition: mythuitype.cpp:541
QVector< QTextLayout * > m_Layouts
Definition: mythuitext.h:133
virtual bool SupportsAnimation(void)=0
void Pulse(void) override
Pulse is called 70 times a second to trigger a single frame of an animation.
void SetJustification(int just)
Definition: mythuitext.cpp:296
FontMap * GetGlobalFontMap(void)
void SetMultiLine(bool multiline)
Definition: mythuitext.cpp:340
float curR
Definition: mythuitext.h:141
int m_numSteps
Definition: mythuitext.h:140
QFont face(void) const
QRect toQRect(void) const
Definition: mythrect.cpp:381
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
QString m_DefaultMessage
Definition: mythuitext.h:115
void setRect(const QString &sX, const QString &sY, const QString &sWidth, const QString &sHeight, const QString &baseRes=QString())
Definition: mythrect.cpp:122
void setX(const QString &sX)
Definition: mythrect.cpp:229
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
QMap< QString, MythFontProperties > m_FontStates
Definition: mythuitext.h:136
virtual void SetMinArea(const MythRect &rect)
Set the minimum area based on the given size.
Definition: mythuitype.cpp:820
void DependChanged(bool isDefault)
static QString getFirstText(QDomElement &element)
float incB
Definition: mythuitext.h:142
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:116
virtual void Pulse(void)
Pulse is called 70 times a second to trigger a single frame of an animation.
Definition: mythuitype.cpp:465
bool m_Initiator
Definition: mythuitype.h:241
void setY(const QString &sY)
Definition: mythrect.cpp:239
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:17
int m_Descent
Definition: mythuitext.h:125
void moveLeft(const QString &sX)
Definition: mythrect.cpp:285
MythFontProperties * m_Font
Definition: mythuitext.h:135
void ResetMap(const InfoMap &map)
Definition: mythuitext.cpp:130
void FillCutMessage(void)
Definition: mythuitext.cpp:730
void AdjustStretch(int stretch)
MythRect m_Area
Definition: mythuitype.h:249
int GetFontStretch(void) const
void setWidth(const QString &sWidth)
Definition: mythrect.cpp:249
const char * name
Definition: ParseText.cpp:339
bool Layout(QString &paragraph, QTextLayout *layout, bool final, bool &overflow, qreal width, qreal &height, bool force, qreal &last_line_width, QRectF &min_rect, int &num_lines)
Definition: mythuitext.cpp:491
MythUIHelper * GetMythUI()
void SetCutDown(Qt::TextElideMode mode)
Definition: mythuitext.cpp:320
void GetOutline(QColor &color, int &size, int &alpha) const
static QString parseText(QDomElement &element)
int m_curStep
Definition: mythuitext.h:140
MythMainWindow * GetMythMainWindow(void)
QString m_CutMessage
Definition: mythuitext.h:114
int m_leftBearing
Definition: mythuitext.h:126
MythFontProperties * GetFont(const QString &text) const
virtual void SetArea(const MythRect &rect)
Definition: mythuitype.cpp:613
bool m_ShrinkNarrow
Definition: mythuitext.h:121
float m_scrollForwardRate
Definition: mythuitext.h:152
int m_Justification
Definition: mythuitext.h:106
int m_textCursor
Definition: mythuitext.h:131
void CopyFrom(MythUIType *base) override
Copy this widgets state from another.
bool hasOutline(void) const
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
virtual void Reset(void)
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitype.cpp:92
MythUIText(MythUIType *parent, const QString &name)
Definition: mythuitext.cpp:23
bool isValid(void) const
Definition: mythrect.h:94
QVector< QTextLayout::FormatRange > FormatVector
Definition: mythpainter.h:30
bool LayoutParagraphs(const QStringList &paragraphs, const QTextOption &textoption, qreal width, qreal &height, QRectF &min_rect, qreal &last_line_width, int &num_lines, bool final)
Definition: mythuitext.cpp:593
MythFontProperties * GetFont(const QString &text)
MythPoint m_MinSize
Definition: mythuitype.h:251
void DrawSelf(MythPainter *p, int xoffset, int yoffset, int alphaMod, QRect clipRect) override
Definition: mythuitext.cpp:395
virtual void DrawTextLayout(const QRect &canvasRect, const LayoutVector &layouts, const FormatVector &formats, const MythFontProperties &font, int alpha, const QRect &destRect)
bool GetNarrowWidth(const QStringList &paragraphs, const QTextOption &textoption, qreal &width)
Definition: mythuitext.cpp:637
MythPoint topLeft(void) const
Definition: mythrect.cpp:271
bool m_scrollBounce
Definition: mythuitext.h:154
bool m_scrolling
Definition: mythuitext.h:159
void moveTopLeft(const MythPoint &point)
Definition: mythrect.cpp:279
virtual void CopyFrom(MythUIType *base)
Copy this widgets state from another.
QString GetTemplateText(void) const
Definition: mythuitext.h:47
TextCase m_textCase
Definition: mythuitext.h:164
int m_scrollStartDelay
Definition: mythuitext.h:149
int m_scrollPause
Definition: mythuitext.h:151
int m_lineHeight
Definition: mythuitext.h:130
static MythRect parseRect(const QString &text, bool normalize=true)
Wrapper around QPoint allowing us to handle percentage and other relative values for positioning in m...
Definition: mythrect.h:84
bool m_MultiLine
Definition: mythuitext.h:123
MythRect m_OrigDisplayRect
Definition: mythuitext.h:107
int MoveCursor(int lines)
Definition: mythuitext.cpp:966
bool m_EnableInitiator
Definition: mythuitype.h:240
const MythFontProperties * GetFontProperties()
Definition: mythuitext.h:77
QPoint m_cursorPos
Definition: mythuitext.h:111
bool hasShadow(void) const
int m_scrollPosWhole
Definition: mythuitext.h:157
void SetFontState(const QString &)
Definition: mythuitext.cpp:257
void moveTop(const QString &sX)
Definition: mythrect.cpp:295
MythRect m_AltDisplayRect
Definition: mythuitext.h:108
QString GetLanguage(void)
Returns two character ISO-639 language descriptor for UI language.
float curB
Definition: mythuitext.h:141
void NormPoint(void)
Definition: mythrect.cpp:446
static bool parseBool(const QString &text)
QPoint CursorPosition(int text_offset)
int GetJustification(void)
Definition: mythuitext.cpp:315
float curG
Definition: mythuitext.h:141
virtual void SetClipRect(const QRect &clipRect)
Definition: mythpainter.cpp:50
void ShiftCanvas(int x, int y)
Definition: mythuitext.cpp:385
void Finalize(void) override
Perform any post-xml parsing initialisation tasks.
virtual bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings)
Parse the xml definition of this widget setting the state of the object accordingly.
int m_Ascent
Definition: mythuitext.h:124