MythTV  master
Text.cpp
Go to the documentation of this file.
1 /* Text.cpp
2 
3  Copyright (C) David C. J. Matthews 2004, 2008 dm at prolingua.co.uk
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU General Public License
7  as published by the Free Software Foundation; either version 2
8  of the License, or (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18  Or, point your browser to http://www.gnu.org/copyleft/gpl.html
19 
20 */
21 #include "compat.h"
22 
23 #include "Text.h"
24 #include "Visible.h"
25 #include "Presentable.h"
26 #include "Ingredients.h"
27 #include "Root.h"
28 #include "BaseClasses.h"
29 #include "ParseNode.h"
30 #include "ASN1Codes.h"
31 #include "Engine.h"
32 #include "Logging.h"
33 #include "freemheg.h"
34 
35 MHText::MHText(const MHText &ref): MHVisible(ref) // Copy constructor for cloning.
36 {
41  m_nCharSet = ref.m_nCharSet;
42  m_HorizJ = ref.m_HorizJ;
43  m_VertJ = ref.m_VertJ;
47  m_pDisplay = nullptr;
49 }
50 
52 {
53  delete(m_pDisplay);
54 }
55 
56 
58 {
59  MHVisible::Initialise(p, engine);
60  // Font and attributes.
61  MHParseNode *pFontBody = p->GetNamedArg(C_ORIGINAL_FONT);
62 
63  if (pFontBody)
64  {
65  m_OrigFont.Initialise(pFontBody->GetArgN(0), engine);
66  }
67 
68  MHParseNode *pFontAttrs = p->GetNamedArg(C_FONT_ATTRIBUTES);
69 
70  if (pFontAttrs)
71  {
73  }
74 
75  // Colours
76  MHParseNode *pTextColour = p->GetNamedArg(C_TEXT_COLOUR);
77 
78  if (pTextColour)
79  {
80  m_OriginalTextColour.Initialise(pTextColour->GetArgN(0), engine);
81  }
82 
83  MHParseNode *pBGColour = p->GetNamedArg(C_BACKGROUND_COLOUR);
84 
85  if (pBGColour)
86  {
87  m_OriginalBgColour.Initialise(pBGColour->GetArgN(0), engine);
88  }
89 
90  // Character set
91  MHParseNode *pChset = p->GetNamedArg(C_CHARACTER_SET);
92 
93  if (pChset)
94  {
95  m_nCharSet = pChset->GetArgN(0)->GetIntValue();
96  }
97 
98  // Justification
99  MHParseNode *pHJust = p->GetNamedArg(C_HORIZONTAL_JUSTIFICATION);
100 
101  if (pHJust)
102  {
103  m_HorizJ = (enum Justification)pHJust->GetArgN(0)->GetEnumValue();
104  }
105 
106  MHParseNode *pVJust = p->GetNamedArg(C_VERTICAL_JUSTIFICATION);
107 
108  if (pVJust)
109  {
110  m_VertJ = (enum Justification)pVJust->GetArgN(0)->GetEnumValue();
111  }
112 
113  // Line orientation
114  MHParseNode *pLineO = p->GetNamedArg(C_LINE_ORIENTATION);
115 
116  if (pLineO)
117  {
119  }
120 
121  // Start corner
122  MHParseNode *pStartC = p->GetNamedArg(C_START_CORNER);
123 
124  if (pStartC)
125  {
126  m_StartCorner = (enum StartCorner)pStartC->GetArgN(0)->GetEnumValue();
127  }
128 
129  // Text wrapping
130  MHParseNode *pTextWrap = p->GetNamedArg(C_TEXT_WRAPPING);
131 
132  if (pTextWrap)
133  {
134  m_fTextWrap = pTextWrap->GetArgN(0)->GetBoolValue();
135  }
136 
137  m_pDisplay = engine->GetContext()->CreateText();
138  m_fNeedsRedraw = true;
139 }
140 
141 static const char * const rchJustification[] =
142 {
143  "start", // 1
144  "end",
145  "centre",
146  "justified" // 4
147 };
148 
149 // Look up the Justification. Returns zero if it doesn't match. Used in the text parser only.
150 int MHText::GetJustification(const char *str)
151 {
152  for (int i = 0; i < (int)(sizeof(rchJustification) / sizeof(rchJustification[0])); i++)
153  {
154  if (strcasecmp(str, rchJustification[i]) == 0)
155  {
156  return (i + 1); // Numbered from 1
157  }
158  }
159 
160  return 0;
161 }
162 
163 static const char * const rchlineOrientation[] =
164 {
165  "vertical", // 1
166  "horizontal"
167 };
168 
169 int MHText::GetLineOrientation(const char *str)
170 {
171  for (int i = 0; i < (int)(sizeof(rchlineOrientation) / sizeof(rchlineOrientation[0])); i++)
172  {
173  if (strcasecmp(str, rchlineOrientation[i]) == 0)
174  {
175  return (i + 1);
176  }
177  }
178 
179  return 0;
180 }
181 
182 static const char * const rchStartCorner[] =
183 {
184  "upper-left", // 1
185  "upper-right",
186  "lower-left",
187  "lower-right" // 4
188 };
189 
190 int MHText::GetStartCorner(const char *str)
191 {
192  for (int i = 0; i < (int)(sizeof(rchStartCorner) / sizeof(rchStartCorner[0])); i++)
193  {
194  if (strcasecmp(str, rchStartCorner[i]) == 0)
195  {
196  return (i + 1);
197  }
198  }
199 
200  return 0;
201 }
202 
203 void MHText::PrintMe(FILE *fd, int nTabs) const
204 {
205  PrintTabs(fd, nTabs);
206  fprintf(fd, "{:Text ");
207  MHVisible::PrintMe(fd, nTabs + 1);
208 
209  if (m_OrigFont.IsSet())
210  {
211  PrintTabs(fd, nTabs + 1);
212  fprintf(fd, ":OrigFont ");
213  m_OrigFont.PrintMe(fd, nTabs + 1);
214  fprintf(fd, "\n");
215  }
216 
217  if (m_OriginalFontAttrs.Size() > 0)
218  {
219  PrintTabs(fd, nTabs + 1);
220  fprintf(fd, ":FontAttributes ");
221  m_OriginalFontAttrs.PrintMe(fd, nTabs + 1);
222  fprintf(fd, "\n");
223  }
224 
226  {
227  PrintTabs(fd, nTabs + 1);
228  fprintf(fd, ":TextColour ");
229  m_OriginalTextColour.PrintMe(fd, nTabs + 1);
230  fprintf(fd, "\n");
231  }
232 
234  {
235  PrintTabs(fd, nTabs + 1);
236  fprintf(fd, ":BackgroundColour ");
237  m_OriginalBgColour.PrintMe(fd, nTabs + 1);
238  fprintf(fd, "\n");
239  }
240 
241  if (m_nCharSet >= 0)
242  {
243  PrintTabs(fd, nTabs + 1);
244  fprintf(fd, ":CharacterSet %d\n", m_nCharSet);
245  }
246 
247  if (m_HorizJ != Start)
248  {
249  PrintTabs(fd, nTabs + 1);
250  fprintf(fd, ":HJustification %s\n", rchJustification[m_HorizJ-1]);
251  }
252 
253  if (m_VertJ != Start)
254  {
255  PrintTabs(fd, nTabs + 1);
256  fprintf(fd, ":VJustification %s\n", rchJustification[m_VertJ-1]);
257  }
258 
260  {
261  PrintTabs(fd, nTabs + 1);
262  fprintf(fd, ":LineOrientation %s\n", rchlineOrientation[m_LineOrientation-1]);
263  }
264 
265  if (m_StartCorner != UpperLeft)
266  {
267  PrintTabs(fd, nTabs + 1);
268  fprintf(fd, ":StartCorner %s\n", rchStartCorner[m_StartCorner-1]);
269  }
270 
271  if (m_fTextWrap)
272  {
273  PrintTabs(fd, nTabs + 1);
274  fprintf(fd, ":TextWrapping true\n");
275  }
276 
277  PrintTabs(fd, nTabs);
278  fprintf(fd, "}\n");
279 }
280 
282 {
283  if (m_fAvailable)
284  {
285  return;
286  }
287 
288  // Set the colours and font up from the originals if specified otherwise use the application defaults.
289  // if (m_OrigFont.IsSet()) m_Font.Copy(m_OrigFont);
290  // else m_Font.Copy(engine->m_DefaultFont);
292  {
294  }
295  else
296  {
298  }
299 
301  {
303  }
304  else
305  {
307  }
308 
309  if (m_OriginalFontAttrs.Size() > 0)
310  {
312  }
313  else
314  {
316  }
317 
318  MHVisible::Preparation(engine);
319 
320  if (m_pDisplay == nullptr)
321  {
322  m_pDisplay = engine->GetContext()->CreateText();
323  }
324 
326  m_fNeedsRedraw = true;
327 }
328 
329 // Content preparation. If it's included we can set up the content.
331 {
333 
334  if (m_ContentType == IN_NoContent)
335  {
336  MHERROR("Text object must have content");
337  }
338 
339  if (m_ContentType == IN_IncludedContent)
340  {
342  }
343 }
344 
345 // Called when external content is available.
346 void MHText::ContentArrived(const unsigned char *data, int length, MHEngine *engine)
347 {
348  CreateContent(data, length, engine);
349  MHLOG(MHLogDetail, QString("Content arrived %1 := '%2'")
351  // Now signal that the content is available.
352  engine->EventTriggered(this, EventContentAvailable);
353  m_fNeedsRedraw = true;
354 }
355 
356 //
357 void MHText::CreateContent(const unsigned char *p, int s, MHEngine *engine)
358 {
359  m_Content.Copy(MHOctetString((const char *)p, s));
360  engine->Redraw(GetVisibleArea()); // Have to redraw if the content has changed.
361  m_fNeedsRedraw = true;
362  // fprintf(fd, "Text content is now "); m_Content.PrintMe(0); fprintf(fd, "\n");
363 }
364 
365 void MHText::SetTextColour(const MHColour &colour, MHEngine *engine)
366 {
367  m_textColour.Copy(colour);
368  m_fNeedsRedraw = true;
369  engine->Redraw(GetVisibleArea());
370 }
371 
372 void MHText::SetBackgroundColour(const MHColour &colour, MHEngine *engine)
373 {
374  m_bgColour.Copy(colour);
375  // Setting the background colour doesn't affect the text image but we have to
376  // redraw it onto the display.
377  engine->Redraw(GetVisibleArea());
378 }
379 
380 void MHText::SetFontAttributes(const MHOctetString &fontAttrs, MHEngine *engine)
381 {
382  m_fontAttrs.Copy(fontAttrs);
383  m_fNeedsRedraw = true;
384  engine->Redraw(GetVisibleArea());
385 }
386 
387 // UK MHEG. Interpret the font attributes.
388 static void InterpretAttributes(const MHOctetString &attrs, int &style, int &size, int &lineSpace, int &letterSpace)
389 {
390  // Set the defaults.
391  style = 0;
392  size = 0x18;
393  lineSpace = 0x18;
394  letterSpace = 0;
395 
396  if (attrs.Size() == 5) // Short form.
397  {
398  style = attrs.GetAt(0); // Only the bottom nibble is significant.
399  size = attrs.GetAt(1);
400  lineSpace = attrs.GetAt(2);
401  // Is this big-endian or little-endian? Assume big.
402  letterSpace = attrs.GetAt(3) * 256 + attrs.GetAt(4);
403 
404  if (letterSpace > 32767)
405  {
406  letterSpace -= 65536; // Signed.
407  }
408  }
409  else // Textual form.
410  {
411  const unsigned char *str = attrs.Bytes();
412  char *p = (char *)str;
413  char *q = strchr(p, '.'); // Find the terminating dot
414 
415  if (q != nullptr) // plain, italic etc.
416  {
417  if (q - p == 6 && strncmp(p, "italic", 6) == 0)
418  {
419  style = 1;
420  }
421  else if (q - p == 4 && strncmp(p, "bold", 4) == 0)
422  {
423  style = 2;
424  }
425  else if (q - p == 11 && strncmp(p, "bold-italic", 11) == 0)
426  {
427  style = 3;
428  }
429 
430  // else it's plain.
431  p = q + 1;
432  q = strchr(p, '.'); // Find the next dot.
433  }
434 
435  if (q != nullptr) // Size
436  {
437  size = atoi(p);
438 
439  if (size == 0)
440  {
441  size = 0x18;
442  }
443 
444  p = q + 1;
445  q = strchr(p, '.'); // Find the next dot.
446  }
447 
448  if (q != nullptr) // lineSpacing
449  {
450  lineSpace = atoi(p);
451 
452  if (lineSpace == 0)
453  {
454  lineSpace = 0x18;
455  }
456 
457  p = q + 1;
458  q = strchr(p, '.'); // Find the next dot.
459  }
460 
461  if (q != nullptr) // letter spacing. May be zero or negative
462  {
463  letterSpace = atoi(p);
464  }
465  }
466 }
467 
468 // We break the text up into pieces of line segment.
470 {
471  public:
472  MHTextItem();
473  MHOctetString m_text; // UTF-8 text
474  QString m_unicode; // Unicode text
475  int m_nUnicode; // Number of characters in it
476  int m_width; // Size of this block
477  MHRgba m_colour; // Colour of the text
478  int m_nTabCount; // Number of tabs immediately before this (usually zero)
479 
480  // Generate new items inheriting properties from the previous
481  MHTextItem *NewItem() const;
482 };
483 
485 {
486  m_nUnicode = 0;
487  m_width = 0; // Size of this block
488  m_colour = MHRgba(0, 0, 0, 255);
489  m_nTabCount = 0;
490 }
491 
493 {
494  auto *pItem = new MHTextItem;
495  pItem->m_colour = m_colour;
496  return pItem;
497 }
498 
499 // A line consists of one or more sequences of text items.
501 {
502  public:
503  MHTextLine() = default;
504  ~MHTextLine();
506  int m_nLineWidth {0};
507  int m_nLineHeight {0};
508  int m_nDescent {0};
509 };
510 
512 {
513  for (int i = 0; i < m_items.Size(); i++)
514  {
515  delete(m_items.GetAt(i));
516  }
517 }
518 
519 // Tabs are set every 56 pixels
520 // = (FONT_WIDTHRES * 56)/ 72 points - see libmythtv/mhi.cpp
521 // = (54 * 56)/72 = 42
522 #define TABSTOP 42 // pts
523 static inline int Tabs(int nXpos, int nTabCount)
524 {
525  int nNextTab = nXpos;
526  if (nTabCount-- > 0)
527  {
528  nNextTab += TABSTOP - nXpos % TABSTOP;
529  nNextTab += nTabCount * TABSTOP;
530  }
531  return nNextTab;
532 }
533 
534 // I attempted to use QSimpleRichText but that does not give sufficient fine control over
535 // the layout. UK MHEG specifies the use of the Tiresias font and broadcasters appear to
536 // assume that all MHEG applications will lay the text out in the same way.
537 
538 // Recreate the image.
540 {
541  if (! m_fRunning || !m_pDisplay)
542  {
543  return;
544  }
545 
546  if (m_nBoxWidth == 0 || m_nBoxHeight == 0)
547  {
548  return; // Can't draw zero sized boxes.
549  }
550 
552  m_pDisplay->Clear();
553 
554  MHRgba textColour = GetColour(m_textColour);
555  // Process any escapes in the text and construct the text arrays.
557  // Set up the first item on the first line.
558  auto *pCurrItem = new MHTextItem;
559  auto *pCurrLine = new MHTextLine;
560  pCurrLine->m_items.Append(pCurrItem);
561  theText.Append(pCurrLine);
562  MHStack <MHRgba> colourStack; // Stack to handle nested colour codes.
563  colourStack.Push(textColour);
564  pCurrItem->m_colour = textColour;
565 
566 // FILE *fd=stdout; fprintf(fd, "Redraw Text "); m_Content.PrintMe(fd, 0); fprintf(fd, "\n");
567  int i = 0;
568 
569  while (i < m_Content.Size())
570  {
571  unsigned char ch = m_Content.GetAt(i++);
572 
573  if (ch == 0x09) // Tab - start a new item if we have any text in the existing one.
574  {
575  if (pCurrItem->m_text.Size() != 0)
576  {
577  pCurrItem = pCurrItem->NewItem();
578  pCurrLine->m_items.Append(pCurrItem);
579  }
580  if (m_HorizJ == Start)
581  pCurrItem->m_nTabCount++;
582  }
583 
584  else if (ch == 0x0d) // CR - line break.
585  {
586  // TODO: Two CRs next to one another are treated as </P> rather than <BR><BR>
587  // This should also include the sequence CRLFCRLF.
588  pCurrLine = new MHTextLine;
589  theText.Append(pCurrLine);
590  pCurrItem = pCurrItem->NewItem();
591  pCurrLine->m_items.Append(pCurrItem);
592  }
593 
594  else if (ch == 0x1b) // Escape - special codes.
595  {
596  if (i == m_Content.Size())
597  {
598  break;
599  }
600 
601  unsigned char code = m_Content.GetAt(i);
602  // The only codes we are interested in are the start and end of colour.
603  // TODO: We may also need "bold" and some hypertext colours.
604 
605  if (code >= 0x40 && code <= 0x5e) // Start code
606  {
607  // Start codes are followed by a parameter count and a number of parameter bytes.
608  if (++i == m_Content.Size())
609  {
610  break;
611  }
612 
613  unsigned char paramCount = m_Content.GetAt(i);
614  i++;
615 
616  if (code == 0x43 && paramCount == 4 && i + paramCount <= m_Content.Size())
617  {
618  // Start of colour.
619  if (pCurrItem->m_text.Size() != 0)
620  {
621  pCurrItem = pCurrItem->NewItem();
622  pCurrLine->m_items.Append(pCurrItem);
623  }
624 
625  pCurrItem->m_colour = MHRgba(m_Content.GetAt(i), m_Content.GetAt(i + 1),
626  m_Content.GetAt(i + 2), 255 - m_Content.GetAt(i + 3));
627  // Push this colour onto the colour stack.
628  colourStack.Push(pCurrItem->m_colour);
629  }
630  else
631  {
632  MHLOG(MHLogWarning, QString("Unknown text escape code 0x%1").arg(code, 2, 16));
633  }
634 
635  i += paramCount; // Skip the parameters
636  }
637  else if (code >= 0x60 && code <= 0x7e) // End code.
638  {
639  i++;
640 
641  if (code == 0x63)
642  {
643  if (colourStack.Size() > 1)
644  {
645  colourStack.Pop();
646 
647  // Start a new item since we're using a new colour.
648  if (pCurrItem->m_text.Size() != 0)
649  {
650  pCurrItem = pCurrItem->NewItem();
651  pCurrLine->m_items.Append(pCurrItem);
652  }
653 
654  // Set the subsequent text in the colour we're using now.
655  pCurrItem->m_colour = colourStack.Top();
656  }
657  }
658  else MHLOG(MHLogWarning, QString("Unknown text escape code 0x%1").arg(code,2,16));
659  }
660  else MHLOG(MHLogWarning, QString("Unknown text escape code 0x%1").arg(code,2,16));
661  }
662 
663  else if (ch <= 0x1f)
664  {
665  // Certain characters including LF and the marker codes between 0x1c and 0x1f are
666  // explicitly intended to be ignored. Include all the other codes.
667  }
668 
669  else // Add to the current text.
670  {
671  int nStart = i - 1;
672 
673  while (i < m_Content.Size() && m_Content.GetAt(i) >= 0x20)
674  {
675  i++;
676  }
677 
678  pCurrItem->m_text.Append(MHOctetString(m_Content, nStart, i - nStart));
679  }
680  }
681 
682  // Set up the initial attributes.
683  int style = 0;
684  int size = 0;
685  int lineSpace = 0;
686  int letterSpace = 0;
687  InterpretAttributes(m_fontAttrs, style, size, lineSpace, letterSpace);
688  // Create a font with this information.
689  m_pDisplay->SetFont(size, (style & 2) != 0, (style & 1) != 0);
690 
691  // Calculate the layout of each section.
692  for (i = 0; i < theText.Size(); i++)
693  {
694  MHTextLine *pLine = theText.GetAt(i);
695  pLine->m_nLineWidth = 0;
696 
697  for (int j = 0; j < pLine->m_items.Size(); j++)
698  {
699  MHTextItem *pItem = pLine->m_items.GetAt(j);
700 
701  // Set any tabs.
702  pLine->m_nLineWidth = Tabs(pLine->m_nLineWidth, pItem->m_nTabCount);
703 
704  if (pItem->m_unicode.isEmpty()) // Convert UTF-8 to Unicode.
705  {
706  int s = pItem->m_text.Size();
707  pItem->m_unicode = QString::fromUtf8((const char *)pItem->m_text.Bytes(), s);
708  pItem->m_nUnicode = pItem->m_unicode.length();
709  }
710 
711  // Fit the text onto the line.
712  int nFullText = pItem->m_nUnicode;
713  // Get the box size and update pItem->m_nUnicode to the number that will fit.
714  QRect rect = m_pDisplay->GetBounds(pItem->m_unicode, pItem->m_nUnicode, m_nBoxWidth - pLine->m_nLineWidth);
715 
716  if (nFullText != pItem->m_nUnicode && m_fTextWrap) // Doesn't fit, we have to word-wrap.
717  {
718  int nTruncated = pItem->m_nUnicode; // Just in case.
719  // Now remove characters until we find a word-break character.
720  while (pItem->m_nUnicode > 0 && pItem->m_unicode[pItem->m_nUnicode] != ' ')
721  {
722  pItem->m_nUnicode--;
723  }
724 
725  // If there are now word-break characters we truncate the text.
726  if (pItem->m_nUnicode == 0)
727  {
728  pItem->m_nUnicode = nTruncated;
729  }
730 
731  // Special case to avoid infinite loop if the box is very narrow.
732  if (pItem->m_nUnicode == 0)
733  {
734  pItem->m_nUnicode = 1;
735  }
736 
737  // We need to move the text we've cut off this line into a new line.
738  int nNewWidth = nFullText - pItem->m_nUnicode;
739  int nNewStart = pItem->m_nUnicode;
740 
741  // Remove any spaces at the start of the new section.
742  while (nNewWidth != 0 && pItem->m_unicode[nNewStart] == ' ')
743  {
744  nNewStart++;
745  nNewWidth--;
746  }
747 
748  if (nNewWidth != 0)
749  {
750  // Create a new line from the extra text.
751  auto *pNewLine = new MHTextLine;
752  theText.InsertAt(pNewLine, i + 1);
753  // The first item on the new line is the rest of the text.
754  MHTextItem *pNewItem = pItem->NewItem();
755  pNewLine->m_items.Append(pNewItem);
756  pNewItem->m_unicode = pItem->m_unicode.mid(nNewStart, nNewWidth);
757  pNewItem->m_nUnicode = nNewWidth;
758 
759  // Move any remaining items, e.g. in a different colour, from this line onto the new line.
760  while (pLine->m_items.Size() > j + 1)
761  {
762  pNewLine->m_items.Append(pLine->m_items.GetAt(j + 1));
763  pLine->m_items.RemoveAt(j + 1);
764  }
765  }
766 
767  // Remove any spaces at the end of the old section. If we don't do that and
768  // we are centering or right aligning the text we'll get it wrong.
769  while (pItem->m_nUnicode > 1 && pItem->m_unicode[pItem->m_nUnicode-1] == ' ')
770  {
771  pItem->m_nUnicode--;
772  }
773 
774  rect = m_pDisplay->GetBounds(pItem->m_unicode, pItem->m_nUnicode);
775  }
776 
777  pItem->m_width = rect.width();
778  pLine->m_nLineWidth += rect.width();
779 
780  if (rect.height() > pLine->m_nLineHeight)
781  {
782  pLine->m_nLineHeight = rect.height();
783  }
784 
785  if (rect.bottom() > pLine->m_nDescent)
786  {
787  pLine->m_nDescent = rect.bottom();
788  }
789  }
790  }
791 
792  // Now output the text.
793  int yOffset = 0;
794  // If there isn't space for all the lines we should drop extra lines.
795  int nNumLines = theText.Size();
796 
797  do
798  {
799  if (m_VertJ == End)
800  {
801  yOffset = m_nBoxHeight - nNumLines * lineSpace;
802  }
803  else if (m_VertJ == Centre)
804  {
805  yOffset = (m_nBoxHeight - nNumLines * lineSpace) / 2;
806  }
807 
808  if (yOffset < 0)
809  {
810  nNumLines--;
811  }
812  }
813  while (yOffset < 0);
814 
815  for (i = 0; i < nNumLines; i++)
816  {
817  MHTextLine *pLine = theText.GetAt(i);
818  int xOffset = 0;
819 
820  if (m_HorizJ == End)
821  {
822  xOffset = m_nBoxWidth - pLine->m_nLineWidth;
823  }
824  else if (m_HorizJ == Centre)
825  {
826  xOffset = (m_nBoxWidth - pLine->m_nLineWidth) / 2;
827  }
828 
829  for (int j = 0; j < pLine->m_items.Size(); j++)
830  {
831  MHTextItem *pItem = pLine->m_items.GetAt(j);
832 
833  // Tab across if necessary.
834  xOffset = Tabs(xOffset, pItem->m_nTabCount);
835 
836  if (! pItem->m_unicode.isEmpty()) // We may have blank lines.
837  {
838  m_pDisplay->AddText(xOffset, yOffset + (pLine->m_nLineHeight + lineSpace) / 2 - pLine->m_nDescent,
839  pItem->m_unicode.left(pItem->m_nUnicode), pItem->m_colour);
840  }
841 
842  xOffset += pItem->m_width;
843  }
844 
845  yOffset += lineSpace;
846 
847  if (yOffset + lineSpace > m_nBoxHeight)
848  {
849  break;
850  }
851  }
852 
853  // Clean up.
854  for (int k = 0; k < theText.Size(); k++)
855  {
856  delete(theText.GetAt(k));
857  }
858 }
859 
861 {
862  if (! m_fRunning || ! m_pDisplay || m_nBoxWidth == 0 || m_nBoxHeight == 0)
863  {
864  return; // Can't draw zero sized boxes.
865  }
866 
867  // We only need to recreate the display if something has changed.
868  if (m_fNeedsRedraw)
869  {
870  Redraw();
871  m_fNeedsRedraw = false;
872  }
873 
874  // Draw the background first, then the text.
877 }
878 
879 // Return the area actually obscured. This is empty unless the background is opaque.
881 {
882  if (! m_fRunning || (GetColour(m_bgColour)).alpha() != 255)
883  {
884  return QRegion();
885  }
886  return QRegion(QRect(m_nPosX, m_nPosY, m_nBoxWidth, m_nBoxHeight));
887 }
888 
889 
891 {
892  MHText::Initialise(p, engine);
893  MHInteractible::Initialise(p, engine);
894  //
895 }
896 
897 void MHHyperText::PrintMe(FILE *fd, int nTabs) const
898 {
899  PrintTabs(fd, nTabs);
900  fprintf(fd, "{:HyperText ");
901  MHText::PrintMe(fd, nTabs + 1);
902  MHInteractible::PrintMe(fd, nTabs + 1);
903  fprintf(fd, "****TODO\n");
904  PrintTabs(fd, nTabs);
905  fprintf(fd, "}\n");
906 }
907 
908 
910 {
911  MHElemAction::Initialise(p, engine); // Target
912  m_FontAttrs.Initialise(p->GetArgN(1), engine); // New font attrs
913 }
914 
916 {
917  // Get the new font attributes.
918  MHOctetString newAttrs;
919  m_FontAttrs.GetValue(newAttrs, engine);
920  Target(engine)->SetFontAttributes(newAttrs, engine);
921 }
MHTextDisplay::AddText
virtual void AddText(int x, int y, const QString &, MHRgba colour)=0
MHContext::CreateText
virtual MHTextDisplay * CreateText(void)=0
MHTextDisplay::Clear
virtual void Clear(void)=0
C_ORIGINAL_FONT
#define C_ORIGINAL_FONT
Definition: ASN1Codes.h:119
MHHyperText::PrintMe
void PrintMe(FILE *fd, int nTabs) const override
Definition: Text.cpp:897
Presentable.h
MHEngine::GetDefaultBGColour
void GetDefaultBGColour(MHColour &colour)
Definition: Engine.cpp:1359
C_CHARACTER_SET
#define C_CHARACTER_SET
Definition: ASN1Codes.h:71
MHStack::Push
void Push(BASE b)
Definition: BaseClasses.h:93
EventContentAvailable
@ EventContentAvailable
Definition: Root.h:33
MHTextItem::m_colour
MHRgba m_colour
Definition: Text.cpp:477
MHTextLine::MHTextLine
MHTextLine()=default
MHRoot::m_fAvailable
bool m_fAvailable
Definition: Root.h:251
MHEngine::GetContext
MHContext * GetContext()
Definition: Engine.h:154
ASN1Codes.h
MHText::End
@ End
Definition: Text.h:79
MHEngine
Definition: Engine.h:72
MHLogDetail
@ MHLogDetail
Definition: freemheg.h:71
MHParseNode::GetIntValue
int GetIntValue()
Definition: ParseNode.cpp:170
MHText::GetJustification
static int GetJustification(const char *str)
Definition: Text.cpp:150
MHIngredient::IN_NoContent
enum MHIngredient::@10 IN_NoContent
MHVisible::GetColour
static MHRgba GetColour(const MHColour &colour)
Definition: Visible.cpp:156
MHText
Definition: Text.h:37
MHTextItem::NewItem
MHTextItem * NewItem() const
Definition: Text.cpp:492
MHText::ContentPreparation
void ContentPreparation(MHEngine *engine) override
Definition: Text.cpp:330
MHText::LineOrientation
LineOrientation
Definition: Text.h:80
rchStartCorner
static const char *const rchStartCorner[]
Definition: Text.cpp:182
MHOctetString::GetAt
unsigned char GetAt(int i) const
Definition: BaseClasses.h:123
MHOctetString::Bytes
const unsigned char * Bytes() const
Definition: BaseClasses.h:124
MHSetFontAttributes::Initialise
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Text.cpp:909
arg
arg(title).arg(filename).arg(doDelete))
MHVisible::PrintMe
void PrintMe(FILE *fd, int nTabs) const override
Definition: Visible.cpp:84
MHTextDisplay::SetSize
virtual void SetSize(int width, int height)=0
C_HORIZONTAL_JUSTIFICATION
#define C_HORIZONTAL_JUSTIFICATION
Definition: ASN1Codes.h:120
MHText::UpperLeft
@ UpperLeft
Definition: Text.h:81
rchJustification
static const char *const rchJustification[]
Definition: Text.cpp:141
MHText::m_pDisplay
MHTextDisplay * m_pDisplay
Definition: Text.h:94
Visible.h
MHStack::Size
int Size() const
Definition: BaseClasses.h:99
MHElemAction::Initialise
virtual void Initialise(MHParseNode *p, MHEngine *engine)
Definition: BaseActions.cpp:31
MHStack::Top
BASE Top()
Definition: BaseClasses.h:95
MHStack
Definition: BaseClasses.h:83
MHIngredient::ContentPreparation
void ContentPreparation(MHEngine *engine) override
Definition: Ingredients.cpp:181
MHSequence< MHTextItem * >
MHText::StartCorner
StartCorner
Definition: Text.h:81
MHOctetString
Definition: BaseClasses.h:106
MHVisible::Preparation
void Preparation(MHEngine *engine) override
Definition: Visible.cpp:105
MHText::CreateContent
void CreateContent(const unsigned char *p, int s, MHEngine *engine)
Definition: Text.cpp:357
MHTextLine::m_nLineWidth
int m_nLineWidth
Definition: Text.cpp:506
MHFontBody::IsSet
bool IsSet() const
Definition: BaseClasses.h:314
MHFontBody::PrintMe
void PrintMe(FILE *fd, int nTabs) const
Definition: BaseClasses.cpp:815
mythburn.FILE
int FILE
Definition: mythburn.py:139
MHOctetString::PrintMe
void PrintMe(FILE *fd, int nTabs) const
Definition: BaseClasses.cpp:154
MHVisible::m_nPosY
int m_nPosY
Definition: Visible.h:82
MHText::Start
@ Start
Definition: Text.h:79
MHText::m_textColour
MHColour m_textColour
Definition: Text.h:90
InterpretAttributes
static void InterpretAttributes(const MHOctetString &attrs, int &style, int &size, int &lineSpace, int &letterSpace)
Definition: Text.cpp:388
MHRoot::m_fRunning
bool m_fRunning
Definition: Root.h:252
MHRoot::m_ObjectReference
MHObjectRef m_ObjectReference
Definition: Root.h:247
MHEngine::Redraw
void Redraw(const QRegion &region)
Definition: Engine.cpp:899
MHTextLine
Definition: Text.cpp:500
MHText::m_OrigFont
MHFontBody m_OrigFont
Definition: Text.h:74
MHEngine::EventTriggered
void EventTriggered(MHRoot *pSource, enum EventType ev)
Definition: Engine.h:94
MHText::~MHText
~MHText() override
Definition: Text.cpp:51
MHTextItem::m_unicode
QString m_unicode
Definition: Text.cpp:474
MHColour::Initialise
void Initialise(MHParseNode *p, MHEngine *engine)
Definition: BaseClasses.cpp:236
hardwareprofile.config.p
p
Definition: config.py:33
MHText::SetFontAttributes
void SetFontAttributes(const MHOctetString &fontAttrs, MHEngine *engine) override
Definition: Text.cpp:380
MHInteractible::Initialise
void Initialise(MHParseNode *p, MHEngine *engine)
Definition: Visible.cpp:499
ParseNode.h
compat.h
MHText::GetOpaqueArea
QRegion GetOpaqueArea() override
Definition: Text.cpp:880
MHText::MHText
MHText()=default
MHFontBody::Initialise
void Initialise(MHParseNode *p, MHEngine *engine)
Definition: BaseClasses.cpp:803
MHText::m_fontAttrs
MHOctetString m_fontAttrs
Definition: Text.h:91
MHText::m_StartCorner
StartCorner m_StartCorner
Definition: Text.h:85
rchlineOrientation
static const char *const rchlineOrientation[]
Definition: Text.cpp:163
PrintTabs
void PrintTabs(FILE *fd, int n)
Definition: ParseNode.cpp:34
MHGenericOctetString::GetValue
void GetValue(MHOctetString &str, MHEngine *engine) const
Definition: BaseClasses.cpp:505
MHParseNode::GetArgN
MHParseNode * GetArgN(int n)
Definition: ParseNode.cpp:78
MHVisible::m_nBoxHeight
int m_nBoxHeight
Definition: Visible.h:80
MHIngredient::m_IncludedContent
MHOctetString m_IncludedContent
Definition: Ingredients.h:77
MHTextItem::MHTextItem
MHTextItem()
Definition: Text.cpp:484
Tabs
static int Tabs(int nXpos, int nTabCount)
Definition: Text.cpp:523
MHText::m_OriginalTextColour
MHColour m_OriginalTextColour
Definition: Text.h:76
MHColour
Definition: BaseClasses.h:138
MHText::m_OriginalFontAttrs
MHOctetString m_OriginalFontAttrs
Definition: Text.h:75
MHTextDisplay::GetBounds
virtual QRect GetBounds(const QString &str, int &strLen, int maxSize=-1)=0
MHTextItem::m_width
int m_width
Definition: Text.cpp:476
TABSTOP
#define TABSTOP
Definition: Text.cpp:522
MHLOG
#define MHLOG(__level, __text)
Definition: Logging.h:36
MHVisible::GetVisibleArea
virtual QRegion GetVisibleArea()
Definition: Visible.cpp:197
MHVisible::m_nPosX
int m_nPosX
Definition: Visible.h:81
MHHyperText::Initialise
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Text.cpp:890
C_START_CORNER
#define C_START_CORNER
Definition: ASN1Codes.h:123
MHText::GetLineOrientation
static int GetLineOrientation(const char *str)
Definition: Text.cpp:169
MHSequence::RemoveAt
void RemoveAt(int i)
Definition: BaseClasses.h:65
Engine.h
MHText::m_nCharSet
int m_nCharSet
Definition: Text.h:77
MHLogWarning
@ MHLogWarning
Definition: freemheg.h:66
Ingredients.h
MHText::Justification
Justification
Definition: Text.h:79
MHEngine::GetDefaultTextColour
void GetDefaultTextColour(MHColour &colour)
Definition: Engine.cpp:1373
Text.h
MHText::Display
void Display(MHEngine *engine) override
Definition: Text.cpp:860
MHGenericOctetString::Initialise
void Initialise(MHParseNode *p, MHEngine *engine)
Definition: BaseClasses.cpp:476
MHElemAction::Target
MHRoot * Target(MHEngine *engine)
Definition: BaseActions.cpp:46
MHOctetString::Printable
QString Printable() const
Definition: BaseClasses.h:127
MHSequence::InsertAt
void InsertAt(BASE b, int n)
Definition: BaseClasses.h:52
C_TEXT_COLOUR
#define C_TEXT_COLOUR
Definition: ASN1Codes.h:74
MHEngine::GetDefaultFontAttrs
void GetDefaultFontAttrs(MHOctetString &str)
Definition: Engine.cpp:1462
MHFontBody::Copy
void Copy(const MHFontBody &fb)
Definition: BaseClasses.cpp:827
MHParseNode::GetBoolValue
bool GetBoolValue()
Definition: ParseNode.cpp:192
Root.h
MHTextItem
Definition: Text.cpp:469
MHOctetString::Size
int Size() const
Definition: BaseClasses.h:119
C_LINE_ORIENTATION
#define C_LINE_ORIENTATION
Definition: ASN1Codes.h:122
MHText::m_fNeedsRedraw
bool m_fNeedsRedraw
Definition: Text.h:95
MHText::m_OriginalBgColour
MHColour m_OriginalBgColour
Definition: Text.h:76
MHText::m_fTextWrap
bool m_fTextWrap
Definition: Text.h:86
MHVisible
Definition: Visible.h:35
MHText::m_VertJ
Justification m_VertJ
Definition: Text.h:83
MHColour::IsSet
bool IsSet() const
Definition: BaseClasses.h:143
MHText::Centre
@ Centre
Definition: Text.h:79
MHText::GetStartCorner
static int GetStartCorner(const char *str)
Definition: Text.cpp:190
MHTextLine::m_items
MHSequence< MHTextItem * > m_items
Definition: Text.cpp:505
MHColour::Copy
void Copy(const MHColour &col)
Definition: BaseClasses.cpp:266
BaseClasses.h
MHVisible::Initialise
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Visible.cpp:50
MHTextDisplay::SetFont
virtual void SetFont(int size, bool isBold, bool isItalic)=0
MHTextItem::m_text
MHOctetString m_text
Definition: Text.cpp:473
C_FONT_ATTRIBUTES
#define C_FONT_ATTRIBUTES
Definition: ASN1Codes.h:76
MHSequence::Size
int Size() const
Definition: BaseClasses.h:46
C_VERTICAL_JUSTIFICATION
#define C_VERTICAL_JUSTIFICATION
Definition: ASN1Codes.h:121
MHParseNode
Definition: ParseNode.h:38
MHSetFontAttributes::m_FontAttrs
MHGenericOctetString m_FontAttrs
Definition: Text.h:159
MHInteractible::PrintMe
void PrintMe(FILE *fd, int nTabs) const
Definition: Visible.cpp:525
MHStack::Pop
BASE Pop()
Definition: BaseClasses.h:88
MHSequence::GetAt
BASE GetAt(int i) const
Definition: BaseClasses.h:48
MHParseNode::GetEnumValue
int GetEnumValue()
Definition: ParseNode.cpp:181
MHText::PrintMe
void PrintMe(FILE *fd, int nTabs) const override
Definition: Text.cpp:203
MHText::Redraw
void Redraw()
Definition: Text.cpp:539
MHParseNode::GetStringValue
void GetStringValue(MHOctetString &str)
Definition: ParseNode.cpp:203
MHText::m_bgColour
MHColour m_bgColour
Definition: Text.h:90
MHSequence::Append
void Append(BASE b)
Definition: BaseClasses.h:63
MHTextLine::~MHTextLine
~MHTextLine()
Definition: Text.cpp:511
freemheg.h
MHERROR
#define MHERROR(__text)
Definition: Logging.h:42
Logging.h
MHText::SetTextColour
void SetTextColour(const MHColour &colour, MHEngine *engine) override
Definition: Text.cpp:365
MHText::m_LineOrientation
LineOrientation m_LineOrientation
Definition: Text.h:84
MHVisible::m_nBoxWidth
int m_nBoxWidth
Definition: Visible.h:79
MHTextLine::m_nLineHeight
int m_nLineHeight
Definition: Text.cpp:507
MHText::m_HorizJ
Justification m_HorizJ
Definition: Text.h:82
MHText::Initialise
void Initialise(MHParseNode *p, MHEngine *engine) override
Definition: Text.cpp:57
MHContext::DrawRect
virtual void DrawRect(int xPos, int yPos, int width, int height, MHRgba colour)=0
MHText::m_Content
MHOctetString m_Content
Definition: Text.h:92
MHColour::PrintMe
void PrintMe(FILE *fd, int nTabs) const
Definition: BaseClasses.cpp:248
MHRoot::SetFontAttributes
virtual void SetFontAttributes(const MHOctetString &, MHEngine *)
Definition: Root.h:118
MHTextItem::m_nUnicode
int m_nUnicode
Definition: Text.cpp:475
C_TEXT_WRAPPING
#define C_TEXT_WRAPPING
Definition: ASN1Codes.h:124
MHText::Horizontal
@ Horizontal
Definition: Text.h:80
MHText::Preparation
void Preparation(MHEngine *engine) override
Definition: Text.cpp:281
C_BACKGROUND_COLOUR
#define C_BACKGROUND_COLOUR
Definition: ASN1Codes.h:72
MHText::SetBackgroundColour
void SetBackgroundColour(const MHColour &colour, MHEngine *engine) override
Definition: Text.cpp:372
MHTextItem::m_nTabCount
int m_nTabCount
Definition: Text.cpp:478
MHTextDisplay::Draw
virtual void Draw(int x, int y)=0
MHOctetString::Copy
void Copy(const MHOctetString &str)
Definition: BaseClasses.cpp:131
MHTextLine::m_nDescent
int m_nDescent
Definition: Text.cpp:508
MHRgba
Definition: freemheg.h:76
MHIngredient::IN_IncludedContent
@ IN_IncludedContent
Definition: Ingredients.h:71
MHObjectRef::Printable
QString Printable() const
Definition: BaseClasses.cpp:313
MHText::ContentArrived
void ContentArrived(const unsigned char *data, int length, MHEngine *engine) override
Definition: Text.cpp:346
MHSetFontAttributes::Perform
void Perform(MHEngine *engine) override
Definition: Text.cpp:915