00001
00002
00003
00004 #include <cassert>
00005 #include <algorithm>
00006 using namespace std;
00007
00008 #include "cc708window.h"
00009 #include "mythlogging.h"
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 const uint k708JustifyLeft = 0;
00057 const uint k708JustifyRight = 1;
00058 const uint k708JustifyCenter = 2;
00059 const uint k708JustifyFull = 3;
00060
00061 const uint k708EffectSnap = 0;
00062 const uint k708EffectFade = 1;
00063 const uint k708EffectWipe = 2;
00064
00065 const uint k708BorderNone = 0;
00066 const uint k708BorderRaised = 1;
00067 const uint k708BorderDepressed = 2;
00068 const uint k708BorderUniform = 3;
00069 const uint k708BorderShadowLeft = 4;
00070 const uint k708BorderShadowRight = 5;
00071
00072 const uint k708DirLeftToRight = 0;
00073 const uint k708DirRightToLeft = 1;
00074 const uint k708DirTopToBottom = 2;
00075 const uint k708DirBottomToTop = 3;
00076
00077 const uint k708AttrSizeSmall = 0;
00078 const uint k708AttrSizeStandard = 1;
00079 const uint k708AttrSizeLarge = 2;
00080
00081 const uint k708AttrOffsetSubscript = 0;
00082 const uint k708AttrOffsetNormal = 1;
00083 const uint k708AttrOffsetSuperscript = 2;
00084
00085 const uint k708AttrFontDefault = 1;
00086 const uint k708AttrFontMonospacedSerif = 1;
00087 const uint k708AttrFontProportionalSerif = 2;
00088 const uint k708AttrFontMonospacedSansSerif = 3;
00089 const uint k708AttrFontProportionalSansSerif = 4;
00090 const uint k708AttrFontCasual = 5;
00091 const uint k708AttrFontCursive = 6;
00092 const uint k708AttrFontSmallCaps = 7;
00093
00094 extern const uint k708AttrEdgeNone = 0;
00095 extern const uint k708AttrEdgeRaised = 1;
00096 extern const uint k708AttrEdgeDepressed = 2;
00097 extern const uint k708AttrEdgeUniform = 3;
00098 extern const uint k708AttrEdgeLeftDropShadow = 4;
00099 extern const uint k708AttrEdgeRightDropShadow = 5;
00100
00101 const uint k708AttrColorBlack = 0;
00102 const uint k708AttrColorWhite = 63;
00103
00104 const uint k708AttrOpacitySolid = 0;
00105 const uint k708AttrOpacityFlash = 1;
00106 const uint k708AttrOpacityTranslucent = 2;
00107 const uint k708AttrOpacityTransparent = 3;
00108
00109 CC708Window::CC708Window()
00110 : priority(0), visible(0),
00111 anchor_point(0), relative_pos(0),
00112 anchor_vertical(0), anchor_horizontal(0),
00113 row_count(0), column_count(0),
00114 row_lock(0), column_lock(0),
00115 pen_style(0), window_style(0),
00116
00117 fill_color(0), fill_opacity(0),
00118 border_color(0), border_type(0),
00119 scroll_dir(0), print_dir(0),
00120 effect_dir(0), display_effect(0),
00121 effect_speed(0),
00122 justify(0), word_wrap(0),
00123
00124 true_row_count(0), true_column_count(0),
00125 text(NULL), exists(false),
00126 changed(true), lock(QMutex::Recursive)
00127 {
00128 }
00129
00130 void CC708Window::DefineWindow(int _priority, int _visible,
00131 int _anchor_point, int _relative_pos,
00132 int _anchor_vertical, int _anchor_horizontal,
00133 int _row_count, int _column_count,
00134 int _row_lock, int _column_lock,
00135 int _pen_style, int _window_style)
00136 {
00137 QMutexLocker locker(&lock);
00138
00139 _row_count++;
00140 _column_count++;
00141
00142 priority = _priority;
00143 visible = _visible;
00144 anchor_point = _anchor_point;
00145 relative_pos = _relative_pos;
00146 anchor_vertical = _anchor_vertical;
00147 anchor_horizontal = _anchor_horizontal;
00148 row_count = _row_count;
00149 column_count = _column_count;
00150 row_lock = _row_lock;
00151 column_lock = _column_lock;
00152
00153 if ((!_pen_style && !exists) || _pen_style)
00154 pen.SetPenStyle(_pen_style ? _pen_style : 1);
00155
00156 if ((!_window_style && !exists) || _window_style)
00157 SetWindowStyle(_window_style ? _window_style : 1);
00158
00159 uint old_row = true_row_count;
00160 uint old_col = true_column_count;
00161
00162 true_row_count = row_count;
00163 true_column_count = column_count;
00164
00165 if (text && exists && (old_col == true_column_count) &&
00166 (old_row < true_row_count))
00167 {
00168
00169 uint num = true_row_count * true_column_count;
00170 CC708Character *new_text = new CC708Character[num];
00171 pen.column = 0;
00172 pen.row = 0;
00173 for (uint i = 0; i < old_row * old_col; i++)
00174 new_text[i] = text[i];
00175 for (uint i = old_row * old_col; i < num; i++)
00176 new_text[i].attr = pen.attr;
00177 delete [] text;
00178 text = new_text;
00179 }
00180 else if (text && (!exists || (old_row != true_row_count) ||
00181 (old_col != true_column_count)))
00182 {
00183 delete [] text;
00184 text = NULL;
00185 }
00186
00187 if (!text)
00188 {
00189 uint num = true_row_count * true_column_count;
00190 text = new CC708Character[num];
00191 pen.column = 0;
00192 pen.row = 0;
00193 for (uint i = 0; i < num; i++)
00194 text[i].attr = pen.attr;
00195 }
00196
00197 exists = true;
00198 changed = true;
00199 }
00200
00201
00202 CC708Window::~CC708Window()
00203 {
00204 QMutexLocker locker(&lock);
00205
00206 exists = false;
00207 true_row_count = 0;
00208 true_column_count = 0;
00209
00210 if (text)
00211 {
00212 delete [] text;
00213 text = NULL;
00214 }
00215 }
00216
00217 void CC708Window::Clear(void)
00218 {
00219 QMutexLocker locker(&lock);
00220
00221 if (!exists || !text)
00222 return;
00223
00224 for (uint i = 0; i < true_row_count * true_column_count; i++)
00225 {
00226 text[i].character = QChar(' ');
00227 text[i].attr = pen.attr;
00228 }
00229 changed = true;
00230 }
00231
00232 CC708Character &CC708Window::GetCCChar(void) const
00233 {
00234 QMutexLocker locker(&lock);
00235 assert(exists);
00236 assert(text);
00237 assert(pen.row < true_row_count);
00238 assert(pen.column < true_column_count);
00239 return text[pen.row * true_column_count + pen.column];
00240 }
00241
00242 vector<CC708String*> CC708Window::GetStrings(void) const
00243 {
00244 QMutexLocker locker(&lock);
00245
00246 vector<CC708String*> list;
00247
00248 CC708String *cur = NULL;
00249
00250 if (!text)
00251 return list;
00252
00253 for (uint j = 0; j < true_row_count; j++)
00254 {
00255 for (uint i = 0; i < true_column_count; i++)
00256 {
00257 CC708Character &chr = text[j * true_column_count + i];
00258 if (!cur)
00259 {
00260 cur = new CC708String;
00261 cur->x = i;
00262 cur->y = j;
00263 cur->str = QString("%1").arg(chr.character);
00264 cur->attr = chr.attr;
00265 }
00266 else if (cur->attr == chr.attr)
00267 {
00268 cur->str = QString("%1%2").arg(cur->str).arg(chr.character);
00269 }
00270 else
00271 {
00272 list.push_back(cur);
00273 cur = NULL;
00274 i--;
00275 }
00276 }
00277 if (cur)
00278 {
00279 list.push_back(cur);
00280 cur = NULL;
00281 }
00282 }
00283 return list;
00284 }
00285
00286 void CC708Window::SetWindowStyle(uint style)
00287 {
00288 const uint style2justify[] =
00289 {
00290 k708JustifyLeft, k708JustifyLeft, k708JustifyLeft, k708JustifyCenter,
00291 k708JustifyLeft, k708JustifyLeft, k708JustifyCenter, k708JustifyLeft,
00292 };
00293
00294 if ((style < 1) || (style > 7))
00295 return;
00296
00297 fill_color = k708AttrColorBlack;
00298 fill_opacity = ((2 == style) || (5 == style)) ?
00299 k708AttrOpacityTransparent : k708AttrOpacitySolid;
00300 border_color = k708AttrColorBlack;
00301 border_type = k708BorderNone;
00302 scroll_dir = (style < 7) ? k708DirBottomToTop : k708DirRightToLeft;
00303 print_dir = (style < 7) ? k708DirLeftToRight : k708DirTopToBottom;
00304 effect_dir = scroll_dir;
00305 display_effect = k708EffectSnap;
00306 effect_speed = 0;
00307 justify = style2justify[style];
00308 word_wrap = (style > 3) && (style < 7) ? 1 : 0;
00309
00311
00312 fill_opacity = k708AttrOpacityTransparent;
00314 changed = true;
00315 }
00316
00317 void CC708Window::AddChar(QChar ch)
00318 {
00319 if (!exists)
00320 return;
00321
00322 QString dbg_char = ch;
00323 if (ch.toAscii() < 32)
00324 dbg_char = QString("0x%1").arg( (int)ch.toAscii(), 0,16);
00325
00326 if (!IsPenValid())
00327 {
00328 LOG(VB_VBI, LOG_INFO,
00329 QString("AddChar(%1) at (c %2, r %3) INVALID win(%4,%5)")
00330 .arg(dbg_char).arg(pen.column).arg(pen.row)
00331 .arg(true_column_count).arg(true_row_count));
00332 return;
00333 }
00334
00335 if (ch.toAscii() == 0x0D)
00336 {
00337 Scroll(pen.row + 1, 0);
00338 changed = true;
00339 return;
00340 }
00341
00342 if (ch.toAscii() == 0x08)
00343 {
00344 DecrPenLocation();
00345 GetCCChar().attr = pen.attr;
00346 GetCCChar().character = QChar(' ');
00347 changed = true;
00348 return;
00349 }
00350
00351 GetCCChar().attr = pen.attr;
00352 GetCCChar().character = ch;
00353 int c = pen.column;
00354 int r = pen.row;
00355 IncrPenLocation();
00356 changed = true;
00357
00358 LOG(VB_VBI, LOG_INFO, QString("AddChar(%1) at (c %2, r %3) -> (%4,%5)")
00359 .arg(dbg_char).arg(c).arg(r).arg(pen.column).arg(pen.row));
00360 }
00361
00362 void CC708Window::Scroll(int row, int col)
00363 {
00364 QMutexLocker locker(&lock);
00365
00366 if (!true_row_count || !true_column_count)
00367 return;
00368
00369 if (text && (k708DirBottomToTop == scroll_dir) &&
00370 (row >= (int)true_row_count))
00371 {
00372 for (uint j = 0; j < true_row_count - 1; j++)
00373 for (uint i = 0; i < true_column_count; i++)
00374 text[(true_column_count * j) + i] =
00375 text[(true_column_count * (j+1)) + i];
00376
00377
00378
00379 CC708Character tmp(*this);
00380 for (uint i = 0; i < true_column_count; i++)
00381 text[(true_column_count * (true_row_count - 1)) + i] = tmp;
00382
00383 pen.row = true_row_count - 1;
00384 changed = true;
00385 }
00386 else
00387 {
00388 pen.row = row;
00389 }
00390
00391
00392 pen.column = col;
00393 }
00394
00395 void CC708Window::IncrPenLocation(void)
00396 {
00397
00398
00399 int new_column = pen.column, new_row = pen.row;
00400
00401 new_column += (print_dir == k708DirLeftToRight) ? +1 : 0;
00402 new_column += (print_dir == k708DirRightToLeft) ? -1 : 0;
00403 new_row += (print_dir == k708DirTopToBottom) ? +1 : 0;
00404 new_row += (print_dir == k708DirBottomToTop) ? -1 : 0;
00405
00406 #if 0
00407 LOG(VB_VBI, LOG_INFO, QString("IncrPen dir%1: (c %2, r %3) -> (%4,%5)")
00408 .arg(print_dir).arg(pen.column).arg(pen.row)
00409 .arg(new_column).arg(new_row));
00410 #endif
00411
00412 if (k708DirLeftToRight == print_dir || k708DirRightToLeft == print_dir)
00413 {
00414
00415 if (!row_lock && column_lock && (new_column >= (int)true_column_count))
00416 {
00417 new_column = 0;
00418 new_row += 1;
00419 }
00420 else if (!row_lock && column_lock && (new_column < 0))
00421 {
00422 new_column = (int)true_column_count - 1;
00423 new_row -= 1;
00424 }
00425 Scroll(new_row, new_column);
00426 }
00427 else
00428 {
00429 pen.column = max(new_column, 0);
00430 pen.row = max(new_row, 0);
00431 }
00432
00433
00434 LimitPenLocation();
00435 }
00436
00437 void CC708Window::DecrPenLocation(void)
00438 {
00439
00440
00441 int new_column = pen.column, new_row = pen.row;
00442
00443 new_column -= (print_dir == k708DirLeftToRight) ? +1 : 0;
00444 new_column -= (print_dir == k708DirRightToLeft) ? -1 : 0;
00445 new_row -= (print_dir == k708DirTopToBottom) ? +1 : 0;
00446 new_row -= (print_dir == k708DirBottomToTop) ? -1 : 0;
00447
00448 #if 0
00449 LOG(VB_VBI, LOG_INFO, QString("DecrPen dir%1: (c %2, r %3) -> (%4,%5)")
00450 .arg(print_dir).arg(pen.column).arg(pen.row)
00451 .arg(new_column).arg(new_row));
00452 #endif
00453
00454 if (k708DirLeftToRight == print_dir || k708DirRightToLeft == print_dir)
00455 {
00456
00457 if (!row_lock && column_lock && (new_column >= (int)true_column_count))
00458 {
00459 new_column = 0;
00460 new_row += 1;
00461 }
00462 else if (!row_lock && column_lock && (new_column < 0))
00463 {
00464 new_column = (int)true_column_count - 1;
00465 new_row -= 1;
00466 }
00467 Scroll(new_row, new_column);
00468 }
00469 else
00470 {
00471 pen.column = max(new_column, 0);
00472 pen.row = max(new_row, 0);
00473 }
00474
00475
00476 LimitPenLocation();
00477 }
00478
00479 void CC708Window::SetPenLocation(uint row, uint column)
00480 {
00481 Scroll(row, column);
00482 LimitPenLocation();
00483 }
00484
00485 void CC708Window::LimitPenLocation(void)
00486 {
00487
00488 uint max_col = max((int)true_column_count - 1, 0);
00489 uint max_row = max((int)true_row_count - 1, 0);
00490 pen.column = min(pen.column, max_col);
00491 pen.row = min(pen.row, max_row);
00492 }
00493
00494
00495
00496 void CC708Pen::SetPenStyle(uint style)
00497 {
00498 static const uint style2font[] = { 0, 0, 1, 2, 3, 4, 3, 4 };
00499
00500 if ((style < 1) || (style > 7))
00501 return;
00502
00503 attr.pen_size = k708AttrSizeStandard;
00504 attr.offset = k708AttrOffsetNormal;
00505 attr.font_tag = style2font[style];
00506 attr.italics = 0;
00507 attr.underline = 0;
00508 attr.boldface = 0;
00509 attr.edge_type = 0;
00510 attr.fg_color = k708AttrColorWhite;
00511 attr.fg_opacity = k708AttrOpacitySolid;
00512 attr.bg_color = k708AttrColorBlack;
00513 attr.bg_opacity = (style<6) ?
00514 k708AttrOpacitySolid : k708AttrOpacityTransparent;
00515 attr.edge_color = k708AttrColorBlack;
00516 attr.override_fg_color = false;
00517 }
00518
00519 CC708Character::CC708Character(const CC708Window &win)
00520 {
00521 attr = win.pen.attr;
00522 character = ' ';
00523 }
00524
00525 bool CC708CharacterAttribute::operator==(
00526 const CC708CharacterAttribute &other) const
00527 {
00528 return ((pen_size == other.pen_size) &&
00529 (offset == other.offset) &&
00530 (text_tag == other.text_tag) &&
00531 (font_tag == other.font_tag) &&
00532 (edge_type == other.edge_type) &&
00533 (underline == other.underline) &&
00534 (italics == other.italics) &&
00535 (fg_color == other.fg_color) &&
00536 (fg_opacity == other.fg_opacity) &&
00537 (bg_color == other.bg_color) &&
00538 (bg_opacity == other.bg_opacity) &&
00539 (edge_color == other.edge_color));
00540 }
00541
00542 QColor CC708CharacterAttribute::ConvertToQColor(uint c)
00543 {
00544
00545
00546
00547
00548 static int X[] = {0, 96, 255, 255};
00549 return QColor(X[(c>>4)&3], X[(c>>2)&3], X[c&3]);
00550 }