MythTV  master
cc708window.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 // Copyright (c) 2003-2005, Daniel Kristjansson
3 
4 #include <cassert>
5 #include <algorithm>
6 using namespace std;
7 
8 #include "cc708window.h"
9 #include "mythlogging.h"
10 
11 /************************************************************************
12 
13  FCC Addons to EIA-708.
14 
15  * Decoders must support the standard, large, and small caption sizes
16  and must allow the caption provider to choose a size and allow the
17  viewer to choose an alternative size.
18 
19  * Decoders must support the eight fonts listed in EIA-708. Caption
20  providers may specify 1 of these 8 font styles to be used to write
21  caption text. Decoders must include the ability for consumers to
22  choose among the eight fonts. The decoder must display the font
23  chosen by the caption provider unless the viewer chooses a different
24  font.
25 
26  * Decoders must implement the same 8 character background colors
27  as those that Section 9 requires be implemented for character
28  foreground (white, black, red, green, blue, yellow, magenta and cyan).
29 
30  * Decoders must implement options for altering the appearance of
31  caption character edges.
32 
33  * Decoders must display the color chosen by the caption provider,
34  and must allow viewers to override the foreground and/or background
35  color chosen by the caption provider and select alternate colors.
36 
37  * Decoders must be capable of decoding and processing data for the
38  six standard services, but information from only one service need
39  be displayed at a given time.
40 
41  * Decoders must include an option that permits a viewer to choose a
42  setting that will display captions as intended by the caption
43  provider (a default). Decoders must also include an option that
44  allows a viewer's chosen settings to remain until the viewer
45  chooses to alter these settings, including during periods when
46  the television is turned off.
47 
48  * Cable providers and other multichannel video programming
49  distributors must transmit captions in a format that will be
50  understandable to this decoder circuitry in digital cable
51  television sets when transmitting programming to digital
52  television devices.
53 
54 ******************************************************************************/
55 
60 
61 const uint k708EffectSnap = 0;
62 const uint k708EffectFade = 1;
63 const uint k708EffectWipe = 2;
64 
65 const uint k708BorderNone = 0;
71 
76 
80 
84 
93 
100 
103 
108 
109 void CC708Window::DefineWindow(int _priority, bool _visible,
110  int _anchor_point, int _relative_pos,
111  int _anchor_vertical, int _anchor_horizontal,
112  int _row_count, int _column_count,
113  int _row_lock, int _column_lock,
114  int _pen_style, int _window_style)
115 {
116  // The DefineWindow command may be sent frequently to allow a
117  // caption decoder just tuning in to get in synch quickly.
118  // Usually the row_count and column_count are unchanged, but it is
119  // possible to add or remove rows or columns. Due to the
120  // one-dimensional row-major representation of characters, if the
121  // number of columns is changed, a new array must be created and
122  // the old characters copied in. If only the number of rows
123  // decreases, the array can be left unchanged. If only the number
124  // of rows increases, the old characters can be copied into the
125  // new character array directly without any index translation.
126  QMutexLocker locker(&m_lock);
127 
128  _row_count++;
129  _column_count++;
130 
131  m_priority = _priority;
132  SetVisible(_visible);
133  m_anchor_point = _anchor_point;
134  m_relative_pos = _relative_pos;
135  m_anchor_vertical = _anchor_vertical;
136  m_anchor_horizontal = _anchor_horizontal;
137  m_row_lock = _row_lock;
138  m_column_lock = _column_lock;
139 
140  if ((!_pen_style && !GetExists()) || _pen_style)
141  m_pen.SetPenStyle(_pen_style ? _pen_style : 1);
142 
143  if ((!_window_style && !GetExists()) || _window_style)
144  SetWindowStyle(_window_style ? _window_style : 1);
145 
146  Resize(_row_count, _column_count);
147  m_row_count = _row_count;
148  m_column_count = _column_count;
149  LimitPenLocation();
150 
151  SetExists(true);
152 }
153 
154 // Expand the internal array of characters if necessary to accommodate
155 // the current values of row_count and column_count. Any new (space)
156 // characters exposed are given the current pen attributes. At the
157 // end, row_count and column_count are NOT updated.
158 void CC708Window::Resize(uint new_rows, uint new_columns)
159 {
160 
161  if (!GetExists() || m_text == nullptr)
162  {
163  m_true_row_count = 0;
164  m_true_column_count = 0;
165  }
166 
167  //We need to shrink Rows, at times Scroll (row >= (int)m_true_row_count)) fails and we
168  // Don't scroll caption line resulting in overwriting the same.
169  // Ex: [CAPTIONING FUNDED BY CBS SPORTS
170  // DIVISION]NG FUNDED BY CBS SPORTS
171 
172  if(new_rows < m_true_row_count || new_columns < m_true_column_count)
173  {
174  delete [] m_text;
175  m_text = new CC708Character [new_rows * new_columns];
176  m_true_row_count = new_rows;
177  m_true_column_count = new_columns;
178  m_pen.m_row = 0;
179  m_pen.m_column = 0;
180  Clear();
181  SetChanged();
182  SetExists(true);
183  LOG(VB_VBI,
184  LOG_DEBUG,
185  QString("Shrinked nr %1 nc %2 rc %3 cc %4 tr %5 tc %6").arg(new_rows)
186  .arg(new_columns) .arg(m_row_count) .arg(m_column_count)
187  .arg(m_true_row_count) .arg(m_true_column_count));
188  return;
189  }
190 
191  if (new_rows > m_true_row_count || new_columns > m_true_column_count)
192  {
193  new_rows = max(new_rows, m_true_row_count);
194  new_columns = max(new_columns, m_true_column_count);
195 
196  // Expand the array if the new size exceeds the current capacity
197  // in either dimension.
198  CC708Character *new_text =
199  new CC708Character[new_rows * new_columns];
200  m_pen.m_column = 0;
201  m_pen.m_row = 0;
202  uint i, j;
203  for (i = 0; m_text && i < m_row_count; ++i)
204  {
205  for (j = 0; j < m_column_count; ++j)
206  new_text[i * new_columns + j] = m_text[i * m_true_column_count + j];
207  for (; j < new_columns; ++j)
208  new_text[i * new_columns + j].m_attr = m_pen.attr;
209  }
210  for (; i < new_rows; ++i)
211  for (j = 0; j < new_columns; ++j)
212  new_text[i * new_columns + j].m_attr = m_pen.attr;
213 
214  delete [] m_text;
215  m_text = new_text;
216  m_true_row_count = new_rows;
217  m_true_column_count = new_columns;
218  SetChanged();
219  }
220  else if (new_rows > m_row_count || new_columns > m_column_count)
221  {
222  // At least one dimension expanded into existing space, so
223  // those newly exposed characters must be cleared.
224  for (uint i = 0; i < m_row_count; ++i)
225  for (uint j = m_column_count; j < new_columns; ++j)
226  {
227  m_text[i * m_true_column_count + j].m_character = ' ';
228  m_text[i * m_true_column_count + j].m_attr = m_pen.attr;
229  }
230  for (uint i = m_row_count; i < new_rows; ++i)
231  for (uint j = 0; j < new_columns; ++j)
232  {
233  m_text[i * m_true_column_count + j].m_character = ' ';
234  m_text[i * m_true_column_count + j].m_attr = m_pen.attr;
235  }
236  SetChanged();
237  }
238  SetExists(true);
239 }
240 
241 
243 {
244  QMutexLocker locker(&m_lock);
245 
246  SetExists(false);
247  m_true_row_count = 0;
248  m_true_column_count = 0;
249 
250  if (m_text)
251  {
252  delete [] m_text;
253  m_text = nullptr;
254  }
255 }
256 
258 {
259  QMutexLocker locker(&m_lock);
260 
261  if (!GetExists() || !m_text)
262  return;
263 
264  for (uint i = 0; i < m_true_row_count * m_true_column_count; i++)
265  {
266  m_text[i].m_character = QChar(' ');
267  m_text[i].m_attr = m_pen.attr;
268  }
269  SetChanged();
270 }
271 
273 {
274  assert(GetExists());
275  assert(m_text);
276  assert(m_pen.m_row < m_true_row_count);
277  assert(m_pen.m_column < m_true_column_count);
278  return m_text[m_pen.m_row * m_true_column_count + m_pen.m_column];
279 }
280 
281 vector<CC708String*> CC708Window::GetStrings(void) const
282 {
283  // Note on implementation. In many cases, one line will be
284  // computed as the concatenation of 3 strings: a prefix of spaces
285  // with a default foreground color, followed by the actual text in
286  // a specific foreground color, followed by a suffix of spaces
287  // with a default foreground color. This leads to 3
288  // FormattedTextChunk objects when 1 would suffice. The prefix
289  // and suffix ultimately get optimized away, but not before a
290  // certain amount of unnecessary work.
291  //
292  // This can be solved with two steps. First, suppress a format
293  // change when only non-underlined spaces have been seen so far.
294  // (Background changes can be ignored because the subtitle code
295  // suppresses leading spaces.) Second, for trailing
296  // non-underlined spaces, either suppress a format change, or
297  // avoid creating such a string when it appears at the end of the
298  // row. (We can't do the latter for an initial string of spaces,
299  // because the spaces are needed for coordinate calculations.)
300  QMutexLocker locker(&m_lock);
301 
302  vector<CC708String*> list;
303 
304  CC708String *cur = nullptr;
305 
306  if (!m_text)
307  return list;
308 
309  bool createdNonblankStrings = false;
310  QChar chars[k708MaxColumns];
311  for (uint j = 0; j < m_row_count; j++)
312  {
313  bool inLeadingSpaces = true;
314  bool inTrailingSpaces = true;
315  bool createdString = false;
316  uint strStart = 0;
317  for (uint i = 0; i < m_column_count; i++)
318  {
319  CC708Character &chr = m_text[j * m_true_column_count + i];
320  chars[i] = chr.m_character;
321  if (!cur)
322  {
323  cur = new CC708String;
324  cur->x = i;
325  cur->y = j;
326  cur->attr = chr.m_attr;
327  strStart = i;
328  }
329  bool isDisplayable = (chr.m_character != ' ' || chr.m_attr.m_underline);
330  if (inLeadingSpaces && isDisplayable)
331  {
332  cur->attr = chr.m_attr;
333  inLeadingSpaces = false;
334  }
335  if (isDisplayable)
336  {
337  inTrailingSpaces = false;
338  }
339  if (cur->attr != chr.m_attr)
340  {
341  cur->str = QString(&chars[strStart], i - strStart);
342  list.push_back(cur);
343  createdString = true;
344  createdNonblankStrings = true;
345  inTrailingSpaces = true;
346  cur = nullptr;
347  i--;
348  }
349  }
350  if (cur)
351  {
352  // If the entire string is spaces, we still may need to
353  // create a chunk to preserve spacing between lines.
354  if (!inTrailingSpaces || !createdString)
355  {
356  bool allSpaces = (inLeadingSpaces || inTrailingSpaces);
357  int length = allSpaces ? 0 : m_column_count - strStart;
358  if (length)
359  createdNonblankStrings = true;
360  cur->str = QString(&chars[strStart], length);
361  list.push_back(cur);
362  }
363  else
364  delete cur;
365  cur = nullptr;
366  }
367  }
368  if (!createdNonblankStrings)
369  list.clear();
370  return list;
371 }
372 
373 void CC708Window::DisposeStrings(vector<CC708String*> &strings) const
374 {
375  while (!strings.empty())
376  {
377  delete strings.back();
378  strings.pop_back();
379  }
380 }
381 
383 {
384  const uint style2justify[] =
385  {
388  };
389 
390  if ((style < 1) || (style > 7))
391  return;
392 
393  m_fill_color = k708AttrColorBlack;
394  m_fill_opacity = ((2 == style) || (5 == style)) ?
396  m_border_color = k708AttrColorBlack;
397  m_border_type = k708BorderNone;
398  m_scroll_dir = (style < 7) ? k708DirBottomToTop : k708DirRightToLeft;
399  m_print_dir = (style < 7) ? k708DirLeftToRight : k708DirTopToBottom;
400  m_effect_dir = m_scroll_dir;
401  m_display_effect = k708EffectSnap;
402  m_effect_speed = 0;
403  m_justify = style2justify[style];
404  m_word_wrap = (style > 3) && (style < 7) ? 1 : 0;
405 
407  // It appears that ths is missused by broadcasters (FOX -- Dollhouse)
408  m_fill_opacity = k708AttrOpacityTransparent;
410 }
411 
412 void CC708Window::AddChar(QChar ch)
413 {
414  if (!GetExists())
415  return;
416 
417  QString dbg_char = ch;
418  if (ch.toLatin1() < 32)
419  dbg_char = QString("0x%1").arg( (int)ch.toLatin1(), 0,16);
420 
421  if (!IsPenValid())
422  {
423  LOG(VB_VBI, LOG_DEBUG,
424  QString("AddChar(%1) at (c %2, r %3) INVALID win(%4,%5)")
425  .arg(dbg_char).arg(m_pen.m_column).arg(m_pen.m_row)
426  .arg(m_true_column_count).arg(m_true_row_count));
427  return;
428  }
429 
430  if (ch.toLatin1() == 0x0D)
431  {
432  Scroll(m_pen.m_row + 1, 0);
433  SetChanged();
434  return;
435  }
436  QMutexLocker locker(&m_lock);
437 
438  if (ch.toLatin1() == 0x08)
439  {
440  DecrPenLocation();
441  CC708Character& chr = GetCCChar();
442  chr.m_attr = m_pen.attr;
443  chr.m_character = QChar(' ');
444  SetChanged();
445  return;
446  }
447 
448  CC708Character& chr = GetCCChar();
449  chr.m_attr = m_pen.attr;
450  chr.m_character = ch;
451  int c = m_pen.m_column;
452  int r = m_pen.m_row;
453  IncrPenLocation();
454  SetChanged();
455 
456  LOG(VB_VBI, LOG_DEBUG, QString("AddChar(%1) at (c %2, r %3) -> (%4,%5)")
457  .arg(dbg_char).arg(c).arg(r).arg(m_pen.m_column).arg(m_pen.m_row));
458 }
459 
460 void CC708Window::Scroll(int row, int col)
461 {
462  QMutexLocker locker(&m_lock);
463 
464  if (!m_true_row_count || !m_true_column_count)
465  return;
466 
467  if (m_text && (k708DirBottomToTop == m_scroll_dir) &&
468  (row >= (int)m_true_row_count))
469  {
470  for (uint j = 0; j < m_true_row_count - 1; j++)
471  for (uint i = 0; i < m_true_column_count; i++)
472  m_text[(m_true_column_count * j) + i] =
473  m_text[(m_true_column_count * (j+1)) + i];
474  //uint colsz = m_true_column_count * sizeof(CC708Character);
475  //memmove(m_text, m_text + colsz, colsz * (m_true_row_count - 1));
476 
477  CC708Character tmp(*this);
478  for (uint i = 0; i < m_true_column_count; i++)
479  m_text[(m_true_column_count * (m_true_row_count - 1)) + i] = tmp;
480 
481  m_pen.m_row = m_true_row_count - 1;
482  SetChanged();
483  }
484  else
485  {
486  m_pen.m_row = row;
487  }
488  // TODO implement other 3 scroll directions...
489 
490  m_pen.m_column = col;
491 }
492 
494 {
495  // TODO: Scroll direction and up/down printing,
496  // and word wrap not handled yet...
497  int new_column = m_pen.m_column, new_row = m_pen.m_row;
498 
499  new_column += (m_print_dir == k708DirLeftToRight) ? +1 : 0;
500  new_column += (m_print_dir == k708DirRightToLeft) ? -1 : 0;
501  new_row += (m_print_dir == k708DirTopToBottom) ? +1 : 0;
502  new_row += (m_print_dir == k708DirBottomToTop) ? -1 : 0;
503 
504 #if 0
505  LOG(VB_VBI, LOG_DEBUG, QString("IncrPen dir%1: (c %2, r %3) -> (%4,%5)")
506  .arg(m_print_dir).arg(m_pen.m_column).arg(m_pen.m_row)
507  .arg(new_column).arg(new_row));
508 #endif
509 
510  if (k708DirLeftToRight == m_print_dir || k708DirRightToLeft == m_print_dir)
511  {
512  // basic wrapping for l->r, r->l languages
513  if (!m_row_lock && m_column_lock && (new_column >= (int)m_true_column_count))
514  {
515  new_column = 0;
516  new_row += 1;
517  }
518  else if (!m_row_lock && m_column_lock && (new_column < 0))
519  {
520  new_column = (int)m_true_column_count - 1;
521  new_row -= 1;
522  }
523  Scroll(new_row, new_column);
524  }
525  else
526  {
527  m_pen.m_column = max(new_column, 0);
528  m_pen.m_row = max(new_row, 0);
529  }
530  // TODO implement other 2 scroll directions...
531 
532  LimitPenLocation();
533 }
534 
536 {
537  // TODO: Scroll direction and up/down printing,
538  // and word wrap not handled yet...
539  int new_column = m_pen.m_column, new_row = m_pen.m_row;
540 
541  new_column -= (m_print_dir == k708DirLeftToRight) ? +1 : 0;
542  new_column -= (m_print_dir == k708DirRightToLeft) ? -1 : 0;
543  new_row -= (m_print_dir == k708DirTopToBottom) ? +1 : 0;
544  new_row -= (m_print_dir == k708DirBottomToTop) ? -1 : 0;
545 
546 #if 0
547  LOG(VB_VBI, LOG_DEBUG, QString("DecrPen dir%1: (c %2, r %3) -> (%4,%5)")
548  .arg(m_print_dir).arg(m_pen.m_column).arg(m_pen.m_row)
549  .arg(new_column).arg(new_row));
550 #endif
551 
552  if (k708DirLeftToRight == m_print_dir || k708DirRightToLeft == m_print_dir)
553  {
554  // basic wrapping for l->r, r->l languages
555  if (!m_row_lock && m_column_lock && (new_column >= (int)m_true_column_count))
556  {
557  new_column = 0;
558  new_row += 1;
559  }
560  else if (!m_row_lock && m_column_lock && (new_column < 0))
561  {
562  new_column = (int)m_true_column_count - 1;
563  new_row -= 1;
564  }
565  Scroll(new_row, new_column);
566  }
567  else
568  {
569  m_pen.m_column = max(new_column, 0);
570  m_pen.m_row = max(new_row, 0);
571  }
572  // TODO implement other 2 scroll directions...
573 
574  LimitPenLocation();
575 }
576 
578 {
579  //Clear current row in case we are reseting Pen Location.
580  LOG(VB_VBI,
581  LOG_DEBUG,
582  QString("SetPenLocation nr %1 nc %2 rc %3 cc %4 tr %5 tc %6").arg(row)
583  .arg(column).arg(m_row_count).arg(m_column_count).arg(m_true_row_count)
584  .arg(m_true_column_count));
585  if(0 == row)
586  {
587  Scroll(m_true_row_count, column);
588  m_pen.m_row = row;
589  }
590  else
591  {
592  Scroll(row, column);
593  }
594  LimitPenLocation();
595 }
596 
598 {
599  // basic limiting
600  uint max_col = max((int)m_true_column_count - 1, 0);
601  uint max_row = max((int)m_true_row_count - 1, 0);
602  m_pen.m_column = min(m_pen.m_column, max_col);
603  m_pen.m_row = min(m_pen.m_row, max_row);
604 }
605 
606 /***************************************************************************/
607 
609 {
610  static const uint style2font[] = { 0, 0, 1, 2, 3, 4, 3, 4 };
611 
612  if ((style < 1) || (style > 7))
613  return;
614 
615  attr.m_pen_size = k708AttrSizeStandard;
616  attr.m_offset = k708AttrOffsetNormal;
617  attr.m_font_tag = style2font[style];
618  attr.m_italics = false;
619  attr.m_underline = false;
620  attr.m_boldface = false;
621  attr.m_edge_type = 0;
622  attr.m_fg_color = k708AttrColorWhite;
623  attr.m_fg_opacity = k708AttrOpacitySolid;
624  attr.m_bg_color = k708AttrColorBlack;
625  attr.m_bg_opacity = (style<6) ?
627  attr.m_edge_color = k708AttrColorBlack;
628  attr.m_actual_fg_color = QColor();
629 }
630 
632  : m_attr(win.m_pen.attr)
633 {
634 }
635 
637  const CC708CharacterAttribute &other) const
638 {
639  return ((m_pen_size == other.m_pen_size) &&
640  (m_offset == other.m_offset) &&
641  (m_text_tag == other.m_text_tag) &&
642  (m_font_tag == other.m_font_tag) &&
643  (m_edge_type == other.m_edge_type) &&
644  (m_underline == other.m_underline) &&
645  (m_italics == other.m_italics) &&
646  (m_fg_color == other.m_fg_color) &&
647  (m_fg_opacity == other.m_fg_opacity) &&
648  (m_bg_color == other.m_bg_color) &&
649  (m_bg_opacity == other.m_bg_opacity) &&
650  (m_edge_color == other.m_edge_color));
651 }
652 
654 {
655  // Color is expressed in 6 bits, 2 each for red, green, and blue.
656  // U.S. ATSC programs seem to use just the higher-order bit,
657  // i.e. values 0 and 2, so the last two elements of X[] are both
658  // set to the maximum 255, otherwise font colors are dim.
659  static int X[] = {0, 96, 255, 255};
660  return {X[(eia708color>>4)&3], X[(eia708color>>2)&3], X[eia708color&3]};
661 }
const uint k708AttrOpacityTranslucent
const uint k708JustifyLeft
Definition: cc708window.cpp:56
const uint k708AttrEdgeDepressed
Definition: cc708window.cpp:96
void SetWindowStyle(uint)
CC708CharacterAttribute m_attr
Definition: cc708window.h:170
CC708Character()=default
const uint k708AttrColorBlack
const uint k708BorderShadowLeft
Definition: cc708window.cpp:69
bool operator==(const CC708CharacterAttribute &other) const
void Clear(void)
const uint k708AttrEdgeUniform
Definition: cc708window.cpp:97
void DisposeStrings(vector< CC708String * > &strings) const
unsigned int uint
Definition: compat.h:140
void AddChar(QChar)
const uint k708AttrFontCursive
Definition: cc708window.cpp:91
const uint k708DirBottomToTop
Definition: cc708window.cpp:75
static guint32 * tmp
Definition: goom_core.c:35
const uint k708BorderNone
Definition: cc708window.cpp:65
const uint k708DirTopToBottom
Definition: cc708window.cpp:74
unsigned char r
Definition: ParseText.cpp:329
const uint k708BorderRaised
Definition: cc708window.cpp:66
const uint k708AttrOffsetSubscript
Definition: cc708window.cpp:81
const uint k708AttrFontMonospacedSansSerif
Definition: cc708window.cpp:88
const uint k708DirLeftToRight
Definition: cc708window.cpp:72
const uint k708AttrFontDefault
Definition: cc708window.cpp:85
void IncrPenLocation(void)
void Resize(uint new_rows, uint new_columns)
const uint k708AttrOpacityFlash
const uint k708AttrEdgeLeftDropShadow
Definition: cc708window.cpp:98
const uint k708AttrEdgeNone
Definition: cc708window.cpp:94
const uint k708EffectWipe
Definition: cc708window.cpp:63
void Scroll(int row, int col)
const uint k708AttrOpacityTransparent
void DecrPenLocation(void)
CC708Character & GetCCChar(void) const
QString str
Definition: cc708window.h:179
const uint k708JustifyCenter
Definition: cc708window.cpp:58
const uint k708EffectSnap
Definition: cc708window.cpp:61
void SetPenStyle(uint style)
const uint k708AttrSizeLarge
Definition: cc708window.cpp:79
static QColor ConvertToQColor(uint eia708color)
const uint k708BorderShadowRight
Definition: cc708window.cpp:70
const uint k708AttrSizeStandard
Definition: cc708window.cpp:78
CC708CharacterAttribute attr
Definition: cc708window.h:180
const uint k708AttrEdgeRightDropShadow
Definition: cc708window.cpp:99
const uint k708AttrEdgeRaised
Definition: cc708window.cpp:95
const uint k708AttrOffsetNormal
Definition: cc708window.cpp:82
const uint k708AttrFontProportionalSerif
Definition: cc708window.cpp:87
const uint k708BorderDepressed
Definition: cc708window.cpp:67
const int k708MaxColumns
Definition: cc708window.h:71
const uint k708AttrSizeSmall
Definition: cc708window.cpp:77
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void DefineWindow(int priority, bool visible, int anchor_point, int relative_pos, int anchor_vertical, int anchor_horizontal, int row_count, int column_count, int row_lock, int column_lock, int pen_style, int window_style)
void SetPenLocation(uint, uint)
#define assert(x)
const uint k708AttrFontProportionalSansSerif
Definition: cc708window.cpp:89
vector< CC708String * > GetStrings(void) const
void LimitPenLocation(void)
const uint k708AttrColorWhite
const uint k708AttrFontCasual
Definition: cc708window.cpp:90
const uint k708AttrFontSmallCaps
Definition: cc708window.cpp:92
const uint k708EffectFade
Definition: cc708window.cpp:62
const uint k708AttrFontMonospacedSerif
Definition: cc708window.cpp:86
const uint k708BorderUniform
Definition: cc708window.cpp:68
#define Clear(a)
const uint k708DirRightToLeft
Definition: cc708window.cpp:73
const uint k708AttrOffsetSuperscript
Definition: cc708window.cpp:83
const uint k708JustifyFull
Definition: cc708window.cpp:59
const uint k708JustifyRight
Definition: cc708window.cpp:57
const uint k708AttrOpacitySolid