00001 #include <qimage.h>
00002 #include <qmap.h>
00003 #include <qregexp.h>
00004 #include <qdeepcopy.h>
00005
00006 #include <iostream>
00007 #include <algorithm>
00008 using namespace std;
00009
00010 #include "yuv2rgb.h"
00011 #include "osdtypes.h"
00012 #include "ttfont.h"
00013 #include "osdsurface.h"
00014 #include "osdlistbtntype.h"
00015 #include "osdtypeteletext.h"
00016
00017 #include "mythcontext.h"
00018 #include "mythdialogs.h"
00019
00020 #ifdef USING_FRIBIDI
00021 #include "fribidi/fribidi.h"
00022 #include <qtextcodec.h>
00023 #endif // USING_FRIBIDI
00024
00026 OSDImageCache OSDTypeImage::c_cache;
00027
00028
00029 OSDSet::OSDSet(const QString &name, bool cache, int screenwidth,
00030 int screenheight, float wmult, float hmult,
00031 int frint, int xoff, int yoff)
00032 : QObject()
00033 {
00034 m_wantsupdates = false;
00035 m_lastupdate = 0;
00036 m_needsupdate = false;
00037
00038 m_name = name;
00039 m_cache = cache;
00040
00041 m_frameint = frint;
00042
00043 m_hasdisplayed = false;
00044 m_displaying = false;
00045 m_timeleft = 0;
00046 m_allowfade = true;
00047
00048 m_draweveryframe = false;
00049
00050 m_screenwidth = screenwidth;
00051 m_screenheight = screenheight;
00052 m_wmult = wmult;
00053 m_hmult = hmult;
00054 m_xoffsetbase = xoff;
00055 m_yoffsetbase = yoff;
00056
00057 m_notimeout = false;
00058 m_fadetime = -1;
00059 m_maxfade = -1;
00060
00061 m_xmove = 0;
00062 m_ymove = 0;
00063
00064 m_xoff = 0;
00065 m_yoff = 0;
00066
00067 m_priority = 5;
00068 currentOSDFunctionalType = 0;
00069
00070 m_showwith = QRegExp(".*");
00071
00072 allTypes = new vector<OSDType *>;
00073 }
00074
00075 OSDSet::OSDSet(const OSDSet &other)
00076 : QObject()
00077 {
00078 m_screenwidth = other.m_screenwidth;
00079 m_screenheight = other.m_screenheight;
00080 m_frameint = other.m_frameint;
00081 m_wmult = other.m_wmult;
00082 m_hmult = other.m_hmult;
00083 m_xoffsetbase = other.m_xoffsetbase;
00084 m_yoffsetbase = other.m_yoffsetbase;
00085 m_cache = other.m_cache;
00086 m_name = other.m_name;
00087 m_notimeout = other.m_notimeout;
00088 m_hasdisplayed = other.m_hasdisplayed;
00089 m_timeleft = other.m_timeleft;
00090 m_displaying = other.m_displaying;
00091 m_fadetime = other.m_fadetime;
00092 m_maxfade = other.m_maxfade;
00093 m_priority = other.m_priority;
00094 m_xmove = other.m_xmove;
00095 m_ymove = other.m_ymove;
00096 m_xoff = other.m_xoff;
00097 m_yoff = other.m_yoff;
00098 m_allowfade = other.m_allowfade;
00099 m_wantsupdates = other.m_wantsupdates;
00100 m_lastupdate = other.m_lastupdate;
00101 m_needsupdate = other.m_needsupdate;
00102 m_draweveryframe = other.m_draweveryframe;
00103
00104 currentOSDFunctionalType = 0;
00105
00106 allTypes = new vector<OSDType *>;
00107
00108 vector<OSDType *>::iterator iter = other.allTypes->begin();
00109 for (;iter != other.allTypes->end(); iter++)
00110 {
00111 OSDType *type = (*iter);
00112
00113 if (OSDTypeText *item = dynamic_cast<OSDTypeText*>(type))
00114 {
00115 OSDTypeText *newtext = new OSDTypeText(*item);
00116 AddType(newtext);
00117 }
00118 else if (OSDTypeTeletext *item = dynamic_cast<OSDTypeTeletext*>(type))
00119 {
00120 OSDTypeTeletext *newtt = new OSDTypeTeletext(*item);
00121 AddType(newtt);
00122 }
00123 else if (OSDTypePositionImage *item =
00124 dynamic_cast<OSDTypePositionImage*>(type))
00125 {
00126 OSDTypePositionImage *newrect = new OSDTypePositionImage(*item);
00127 AddType(newrect);
00128 }
00129 else if (OSDTypeImage *item = dynamic_cast<OSDTypeImage*>(type))
00130 {
00131 OSDTypeImage *newimage = new OSDTypeImage(*item);
00132 AddType(newimage);
00133 }
00134 else if (OSDTypeBox *item = dynamic_cast<OSDTypeBox*>(type))
00135 {
00136 OSDTypeBox *newbox = new OSDTypeBox(*item);
00137 AddType(newbox);
00138 }
00139 else if (OSDTypePositionRectangle *item =
00140 dynamic_cast<OSDTypePositionRectangle*>(type))
00141 {
00142 OSDTypePositionRectangle *newrect =
00143 new OSDTypePositionRectangle(*item);
00144 AddType(newrect);
00145 }
00146 else
00147 {
00148 VERBOSE(VB_IMPORTANT, "Unknown conversion in OSDSet copy");
00149 }
00150 }
00151 }
00152
00153 OSDSet::~OSDSet()
00154 {
00155 Clear();
00156 delete allTypes;
00157 }
00158
00159 void OSDSet::Clear()
00160 {
00161 vector<OSDType *>::iterator i = allTypes->begin();
00162 for (; i != allTypes->end(); i++)
00163 {
00164 OSDType *type = (*i);
00165 if (type)
00166 type->deleteLater();
00167 }
00168 allTypes->clear();
00169 }
00170
00171 void OSDSet::AddType(OSDType *type)
00172 {
00173 typeList[type->Name()] = type;
00174 allTypes->push_back(type);
00175 type->SetParent(this);
00176 }
00177
00178 void OSDSet::Reinit(int screenwidth, int screenheight, int xoff, int yoff,
00179 int displaywidth, int displayheight,
00180 float wmult, float hmult, int frint)
00181 {
00182 m_frameint = frint;
00183
00184 m_screenwidth = screenwidth;
00185 m_screenheight = screenheight;
00186 m_wmult = wmult;
00187 m_hmult = hmult;
00188 m_xoffsetbase = xoff;
00189 m_yoffsetbase = yoff;
00190
00191 vector<OSDType *>::iterator iter = allTypes->begin();
00192 for (;iter != allTypes->end(); iter++)
00193 {
00194 if (OSDTypeCC *cc608 = dynamic_cast<OSDTypeCC*>(*iter))
00195 cc608->Reinit(xoff, yoff, displaywidth, displayheight,
00196 wmult, hmult);
00197 else if (OSDType708CC *cc708 = dynamic_cast<OSDType708CC*>(*iter))
00198 cc708->Reinit(xoff, yoff, displaywidth, displayheight);
00199 else
00200 (*iter)->Reinit(wmult, hmult);
00201 }
00202 }
00203
00204 const OSDType *OSDSet::GetType(const QString &name) const
00205 {
00206 QMap<QString,OSDType*>::const_iterator it = typeList.find(name);
00207 if (it != typeList.end())
00208 return *it;
00209 return NULL;
00210 }
00211
00212 OSDType *OSDSet::GetType(const QString &name)
00213 {
00214 QMap<QString,OSDType*>::iterator it = typeList.find(name);
00215 if (it != typeList.end())
00216 return *it;
00217 return NULL;
00218 }
00219
00220 const OSDTypeText *OSDSet::GetSelected(void) const
00221 {
00222 vector<OSDType*>::const_iterator it = allTypes->begin();
00223 for (; it != allTypes->end(); it++)
00224 {
00225 const OSDTypeText *item = dynamic_cast<const OSDTypeText*>(*it);
00226 if (item && item->IsEntry() && item->IsSelected())
00227 return item;
00228 }
00229
00230 return NULL;
00231 }
00232
00233 OSDTypeText *OSDSet::GetSelected(void)
00234 {
00235 vector<OSDType*>::iterator it = allTypes->begin();
00236 for (; it != allTypes->end(); it++)
00237 {
00238 OSDTypeText *item = dynamic_cast<OSDTypeText*>(*it);
00239 if (item && item->IsEntry() && item->IsSelected())
00240 return item;
00241 }
00242
00243 return NULL;
00244 }
00245
00246 void OSDSet::ClearAllText(void)
00247 {
00248 vector<OSDType *>::iterator iter = allTypes->begin();
00249 for (; iter != allTypes->end(); iter++)
00250 {
00251 OSDType *type = (*iter);
00252 if (OSDTypeText *item = dynamic_cast<OSDTypeText *>(type))
00253 {
00254 QString defText = item->GetDefaultText();
00255 if ((defText == "") ||
00256 (defText.contains(QRegExp("%"))))
00257 item->SetText(QString(""));
00258 }
00259 }
00260 }
00261
00262 void OSDSet::SetText(const QMap<QString, QString> &infoMap)
00263 {
00264 vector<OSDType *>::iterator it = allTypes->begin();
00265 for (; it != allTypes->end(); it++)
00266 {
00267 OSDTypeText *item = dynamic_cast<OSDTypeText*>(*it);
00268 if (!item)
00269 continue;
00270
00271 QMap<QString, QString>::const_iterator riter = infoMap.begin();
00272 QString new_text = item->GetDefaultText();
00273
00274 if ((new_text == "") && (infoMap.contains(item->Name())))
00275 {
00276 new_text = infoMap[item->Name()];
00277 }
00278 else if (new_text.contains(QRegExp("%.*%")))
00279 {
00280 for (; riter != infoMap.end(); riter++)
00281 {
00282 QString key = riter.key().upper();
00283 QString data = riter.data();
00284
00285 if (new_text.contains(key))
00286 {
00287 QRegExp full_regex(
00288 QString("%") + key +
00289 QString("(\\|([^%|]*))?") +
00290 QString("(\\|([^%|]*))?") +
00291 QString("(\\|([^%]*))?%"));
00292
00293 if (riter.data() != "")
00294 {
00295 new_text.replace(full_regex,
00296 QString("\\2") + data + "\\4");
00297 }
00298 else
00299 {
00300 new_text.replace(full_regex, "\\6");
00301 }
00302 }
00303 }
00304 }
00305
00306 if (new_text != "")
00307 item->SetText(new_text);
00308 }
00309 m_needsupdate = true;
00310 }
00311
00312 void OSDSet::GetText(QMap<QString, QString> &infoMap) const
00313 {
00314 vector<OSDType*>::const_iterator it = allTypes->begin();
00315 for (; it != allTypes->end(); it++)
00316 {
00317 OSDTypeText *item = dynamic_cast<OSDTypeText *>(*it);
00318 if (item && item->IsEntry())
00319 infoMap[item->Name()] = item->GetText();
00320 }
00321 }
00322
00323 bool OSDSet::SetSelected(int index)
00324 {
00325 bool success = false;
00326
00327 if (index < 0)
00328 {
00329 OSDTypeText *max_item = NULL;
00330 int max_item_num = -1;
00331
00332 vector<OSDType*>::iterator it = allTypes->begin();
00333 for (; it != allTypes->end(); it++)
00334 {
00335 OSDTypeText *item = dynamic_cast<OSDTypeText *>(*it);
00336 if (item && item->IsEntry() && item->IsSelected())
00337 item->SetSelected(false);
00338 if (item && item->GetEntryNum() > max_item_num)
00339 {
00340 max_item = item;
00341 max_item_num = item->GetEntryNum();
00342 }
00343 }
00344 if (max_item)
00345 max_item->SetSelected(success = true);
00346
00347 m_needsupdate = true;
00348 return success;
00349 }
00350
00351 vector<OSDType*>::iterator it = allTypes->begin();
00352 for (; it != allTypes->end(); it++)
00353 {
00354 OSDTypeText *item = dynamic_cast<OSDTypeText *>(*it);
00355 if (item && item->IsEntry() && item->IsSelected())
00356 item->SetSelected(false);
00357 if (item && (item->GetEntryNum() == index))
00358 item->SetSelected(success = true);
00359 }
00360
00361 m_needsupdate = true;
00362 return success;
00363 }
00364
00365 bool OSDSet::HandleKey(const QKeyEvent *e, bool *focus_change,
00366 QString *button_pressed)
00367 {
00368 QStringList actions;
00369 int move = 0;
00370 int del = 0;
00371 int field_move = 0;
00372
00373 if (focus_change)
00374 *focus_change = false;
00375 if (button_pressed)
00376 *button_pressed = "";
00377
00378 int key = e->key();
00379 QString txt = e->text();
00380 if (key == Qt::Key_Escape)
00381 {
00382 SetSelected(0);
00383 Hide();
00384 return true;
00385 }
00386 else if (Qt::Key_Down == key || Qt::Key_Tab == key)
00387 field_move = +1;
00388 else if (Qt::Key_Up == key || Qt::Key_BackTab == key)
00389 field_move = -1;
00390 else if (Qt::Key_Right == key)
00391 move = +1;
00392 else if (Qt::Key_Left == key)
00393 move = -1;
00394 else if (Qt::Key_Delete == key)
00395 del = +1;
00396 else if (Qt::Key_BackSpace == key)
00397 del = -1;
00398 else if (e->state() == Qt::ControlButton)
00399 {
00400 if (Qt::Key_A == key)
00401 move = -1000;
00402 else if (Qt::Key_E == key)
00403 move = +1000;
00404 else if (Qt::Key_F == key)
00405 move = +1;
00406 else if (Qt::Key_B == key)
00407 move = -1;
00408 else if (Qt::Key_U == key)
00409 del = -1000;
00410 else if (Qt::Key_K == key)
00411 del = +1000;
00412 else if (Qt::Key_D == key)
00413 del = +1;
00414 else if (Qt::Key_H == key)
00415 del = -1;
00416 else
00417 {
00418 const QString btn = HandleHotKey(e);
00419 if (!btn.isEmpty())
00420 {
00421 if ((btn == "ok") || (btn == "cancel"))
00422 Hide();
00423
00424 if (button_pressed)
00425 *button_pressed = btn;
00426
00427 return true;
00428 }
00429 }
00430 }
00431
00432 OSDTypeText *item = GetSelected();
00433 if (!item)
00434 return false;
00435
00436 if (item->IsButton() && !field_move)
00437 {
00438 if (txt != "\n" && txt != "\r" && txt != " ")
00439 return false;
00440
00441 const QString btn = item->Name().lower();
00442 if ((btn == "ok") || (btn == "cancel"))
00443 Hide();
00444
00445 if (button_pressed)
00446 *button_pressed = btn;
00447
00448 return true;
00449 }
00450
00451 if (!item->IsButton() && (Qt::Key_Return == key || Qt::Key_Enter == key))
00452 field_move = +1;
00453
00454 if (field_move != 0)
00455 {
00456 if (focus_change)
00457 *focus_change = true;
00458
00459 int next = (int)item->GetEntryNum() + field_move;
00460 if (next >= 0 && SetSelected(next))
00461 return true;
00462
00463 return SetSelected((field_move > 0) ? 0 : -1);
00464 }
00465
00466 if (move != 0)
00467 item->MoveCursor(move);
00468 else if (del != 0)
00469 item->Delete(del);
00470 else if ((1 == txt.length()) && txt.at(0).isPrint() &&
00471 (txt != "[") && (txt != "]"))
00472 {
00473 item->InsertCharacter(txt.at(0));
00474 }
00475 else
00476 {
00477 VERBOSE(VB_IMPORTANT, "Unhandled event");
00478 return false;
00479 }
00480
00481 m_needsupdate = true;
00482 return true;
00483 }
00484
00485 static int extract_hot_key(const QString &text)
00486 {
00487 int i = text.find("[");
00488 if ((i < 0) || ((i + 1) >= (int)text.length()))
00489 return 0;
00490 int ch = text.at(i + 1).upper() - 'A' + Qt::Key_A;
00491 if (ch >= Qt::Key_A && ch <= Qt::Key_Z)
00492 return ch;
00493 return 0;
00494 }
00495
00496 QString OSDSet::HandleHotKey(const QKeyEvent *e)
00497 {
00498 vector<OSDType*>::iterator it = allTypes->begin();
00499 for (; it != allTypes->end(); it++)
00500 {
00501 OSDTypeText *item = dynamic_cast<OSDTypeText *>(*it);
00502 if (item && item->IsButton() &&
00503 extract_hot_key(item->GetText()) == e->key())
00504 {
00505 return item->Name().lower();
00506 }
00507 }
00508 return QString::null;
00509 }
00510
00511 void OSDSet::Display(bool onoff, int osdFunctionalType)
00512 {
00513
00514 if (onoff)
00515 {
00516 m_notimeout = true;
00517 m_displaying = true;
00518 m_timeleft = 1;
00519 m_fadetime = -1;
00520 m_xoff = 0;
00521 m_yoff = 0;
00522 }
00523 else
00524 {
00525 m_displaying = false;
00526 }
00527
00528 if (currentOSDFunctionalType != osdFunctionalType &&
00529 currentOSDFunctionalType != 0)
00530 {
00531 emit OSDClosed(currentOSDFunctionalType);
00532 }
00533
00534 currentOSDFunctionalType = osdFunctionalType;
00535 }
00536
00537 void OSDSet::DisplayFor(int time, int osdFunctionalType)
00538 {
00539 m_timeleft = time;
00540 m_displaying = true;
00541 m_fadetime = -1;
00542 m_notimeout = false;
00543 m_xoff = 0;
00544 m_yoff = 0;
00545
00546 if (currentOSDFunctionalType != osdFunctionalType &&
00547 currentOSDFunctionalType != 0)
00548 {
00549 emit OSDClosed(currentOSDFunctionalType);
00550 }
00551
00552 currentOSDFunctionalType = osdFunctionalType;
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569 void OSDSet::Hide(void)
00570 {
00571 m_timeleft = -1;
00572 m_fadetime = 0;
00573 m_notimeout = false;
00574 m_displaying = false;
00575
00576 if (currentOSDFunctionalType)
00577 {
00578 emit OSDClosed(currentOSDFunctionalType);
00579 currentOSDFunctionalType = 0;
00580 }
00581 }
00582
00583 static int round_uts(int time) { return (time + 999999) / 1000000; }
00584
00585 void OSDSet::Draw(OSDSurface *surface, bool actuallydraw)
00586 {
00587
00588
00589
00590
00591 m_fadetime = (1 == m_fadetime) ? 0 : m_fadetime;
00592
00593 if (actuallydraw && m_displaying)
00594 {
00595 vector<OSDType *>::iterator i = allTypes->begin();
00596 for (; i != allTypes->end(); i++)
00597 {
00598 OSDType *type = (*i);
00599 type->Draw(surface, m_fadetime, m_maxfade, m_xoff + m_xoffsetbase,
00600 m_yoff + m_yoffsetbase);
00601
00602 if (m_wantsupdates)
00603 m_lastupdate = round_uts(m_timeleft);
00604 }
00605 }
00606
00607 m_hasdisplayed |= m_displaying;
00608
00609
00610 m_needsupdate &= !actuallydraw;
00611
00612
00613 m_needsupdate |= m_draweveryframe ||
00614 (m_wantsupdates && (round_uts(m_timeleft) != m_lastupdate));
00615
00616
00617
00618 if (!m_notimeout && m_displaying)
00619 {
00620
00621 m_timeleft = max(m_timeleft - m_frameint, 0);
00622
00623
00624 if (IsFading())
00625 m_fadetime = max(m_fadetime - m_frameint, 1);
00626
00627 if (IsFading() && (m_xmove || m_ymove))
00628 {
00629 m_xoff += (m_xmove * m_frameint * 30) / 1000000;
00630 m_yoff += (m_ymove * m_frameint * 30) / 1000000;
00631 m_fadetime = max(m_fadetime - (4 * m_frameint), 1);
00632 }
00633
00634
00635 m_displaying = m_timeleft > 0 || m_fadetime > 0;
00636
00637
00638 m_needsupdate |= !m_displaying;
00639
00640
00641 if (!m_displaying && currentOSDFunctionalType)
00642 {
00643 emit OSDClosed(currentOSDFunctionalType);
00644 currentOSDFunctionalType = 0;
00645 }
00646 }
00647 }
00648
00649
00650 bool OSDSet::CanShowWith(const QString &name) const
00651 {
00652 return m_showwith.exactMatch(name);
00653 }
00654
00655
00656
00657 OSDType::OSDType(const QString &name) :
00658 m_lock(true),
00659 m_hidden(false),
00660 m_name(QDeepCopy<QString>(name)),
00661 m_parent(NULL)
00662 {
00663 }
00664
00665 QString OSDType::Name(void)
00666 {
00667 QMutexLocker locker(&m_lock);
00668 return QDeepCopy<QString>(m_name);
00669 }
00670
00671 OSDType::~OSDType()
00672 {
00673 }
00674
00675
00676
00677 OSDTypeText::OSDTypeText(const QString &name, TTFFont *font,
00678 const QString &text, QRect displayrect,
00679 float wmult, float hmult) :
00680 OSDType(name),
00681 m_displaysize(displayrect),
00682 m_screensize(displayrect),
00683 m_unbiasedsize(unbias(m_screensize, wmult, hmult)),
00684 m_message(QDeepCopy<QString>(text)),
00685 m_default_msg(QDeepCopy<QString>(text)),
00686
00687 m_font(font),
00688 m_altfont(NULL),
00689
00690 m_centered(false),
00691 m_right(false),
00692
00693 m_multiline(false),
00694 m_usingalt(false),
00695
00696 m_selected(false),
00697 m_button(false),
00698 m_entrynum(-1),
00699 m_cursorpos(0),
00700
00701 m_scroller(false),
00702 m_scrollx(0),
00703 m_scrolly(0),
00704
00705 m_scrollinit(false),
00706
00707 m_linespacing(1.5f),
00708
00709 m_draw_info_str(""),
00710 m_draw_info_len(0),
00711
00712 codeci(NULL)
00713 {
00714 }
00715
00716 OSDTypeText::OSDTypeText(const OSDTypeText &other) :
00717 OSDType(other.m_name),
00718
00719 m_displaysize(QRect(0,0,0,0)),
00720 m_screensize(QRect(0,0,0,0)),
00721 m_unbiasedsize(QRect(0,0,0,0)),
00722 m_message(QString::null),
00723 m_default_msg(QString::null),
00724
00725 m_font(NULL),
00726 m_altfont(NULL),
00727
00728 m_centered(false),
00729 m_right(false),
00730
00731 m_multiline(false),
00732 m_usingalt(false),
00733
00734 m_selected(false),
00735 m_button(false),
00736 m_entrynum(-1),
00737 m_cursorpos(0),
00738
00739 m_scroller(false),
00740 m_scrollx(0),
00741 m_scrolly(0),
00742
00743 m_scrollinit(false),
00744
00745 m_linespacing(1.5f),
00746
00747 m_draw_info_str(""),
00748 m_draw_info_len(0),
00749
00750 codeci(NULL)
00751 {
00752 QMutexLocker locker(&other.m_lock);
00753
00754 m_displaysize = other.m_displaysize;
00755 m_screensize = other.m_screensize;
00756 m_unbiasedsize = other.m_unbiasedsize;
00757
00758 m_message = QDeepCopy<QString>(other.m_message);
00759 m_default_msg = QDeepCopy<QString>(other.m_default_msg);
00760
00761 m_font = other.m_font;
00762 m_altfont = other.m_altfont;
00763
00764 m_centered = other.m_centered;
00765 m_right = other.m_right;
00766
00767 m_multiline = other.m_multiline;
00768 m_usingalt = other.m_usingalt;
00769
00770 m_selected = other.m_selected;
00771 m_button = other.m_button;
00772 m_entrynum = other.m_entrynum;
00773 m_cursorpos = other.m_cursorpos;
00774
00775 m_scroller = other.m_scroller;
00776 m_scrollx = other.m_scrollx;
00777 m_scrolly = other.m_scrolly;
00778
00779 m_scrollinit = other.m_scrollinit;
00780
00781 m_linespacing = other.m_linespacing;
00782 }
00783
00784 OSDTypeText::~OSDTypeText()
00785 {
00786 }
00787
00788 void OSDTypeText::SetAltFont(TTFFont *font)
00789 {
00790 QMutexLocker locker(&m_lock);
00791 m_altfont = font;
00792 }
00793
00794 QString OSDTypeText::BasicConvertFromRtoL(const QString &text)
00795 {
00796 QStringList rtl_string_composer;
00797 bool handle_rtl = false;
00798 QChar prev_char;
00799
00800
00801
00802 for (int i = (int)text.length() - 1; i >= 0; i--)
00803 {
00804 QChar::Direction text_dir = text[i].direction();
00805 if (text_dir != QChar::DirR &&
00806 text_dir != QChar::DirRLE &&
00807 text_dir != QChar::DirRLO)
00808 {
00809 if (handle_rtl || rtl_string_composer.empty())
00810 rtl_string_composer.append(QString());
00811
00812 if (text[i].isSpace() && !prev_char.isNull()
00813 && prev_char.isDigit() && handle_rtl)
00814 rtl_string_composer.back().append(text[i]);
00815 else
00816 rtl_string_composer.back().prepend(text[i]);
00817
00818 prev_char = text[i];
00819
00820 handle_rtl = false;
00821 }
00822 else
00823 {
00824 if (!handle_rtl)
00825 {
00826 rtl_string_composer.append(QString());
00827 handle_rtl = true;
00828 prev_char = QChar();
00829 }
00830 rtl_string_composer.back().append(text[i]);
00831 }
00832 }
00833
00834 QString output = rtl_string_composer.join("");
00835
00836 return QDeepCopy<QString>(output);
00837 }
00838
00839 QString OSDTypeText::ConvertFromRtoL(const QString &text) const
00840 {
00841 QString output = BasicConvertFromRtoL(text);
00842
00843 #ifdef USING_FRIBIDI
00844 QMutexLocker locker(&fribidi_lock);
00845 if (!codeci)
00846 codeci = QTextCodec::codecForName("utf8");
00847
00848 if (!codeci)
00849 return output;
00850
00851 QCString temp = codeci->fromUnicode(output);
00852
00853 FriBidiCharType base;
00854 size_t len;
00855
00856 bool fribidi_flip_commas = true;
00857 base = (fribidi_flip_commas) ? FRIBIDI_TYPE_ON : FRIBIDI_TYPE_L;
00858
00859 const char *ip = temp;
00860 FriBidiChar logical[strlen(ip) + 1], visual[strlen(ip) + 1];
00861
00862 int char_set_num = fribidi_parse_charset("UTF-8");
00863
00864 len = fribidi_charset_to_unicode(
00865 (FriBidiCharSet) char_set_num, ip, strlen(ip), logical);
00866
00867 bool log2vis = fribidi_log2vis(
00868 logical, len, &base, visual, NULL, NULL, NULL);
00869
00870 if (log2vis)
00871 len = fribidi_remove_bidi_marks(visual, len, NULL, NULL, NULL);
00872
00873 output = "";
00874 for (size_t i = 0; i < len ; i++)
00875 output += QChar(visual[i]);
00876 #endif // USING_FRIBIDI
00877
00878 return output;
00879 }
00880
00881 void OSDTypeText::SetText(const QString &text)
00882 {
00883 QMutexLocker locker(&m_lock);
00884 m_message = ConvertFromRtoL(text);
00885 m_cursorpos = m_message.length();
00886 m_scrollinit = false;
00887 }
00888
00889 QString OSDTypeText::GetText(void) const
00890 {
00891 QMutexLocker locker(&m_lock);
00892 return QDeepCopy<QString>(m_message);
00893 }
00894
00895 void OSDTypeText::SetDefaultText(const QString &text)
00896 {
00897 QMutexLocker locker(&m_lock);
00898 m_message = ConvertFromRtoL(text);
00899 m_default_msg = QDeepCopy<QString>(m_message);
00900 m_scrollinit = false;
00901 }
00902
00903 QString OSDTypeText::GetDefaultText(void) const
00904 {
00905 QMutexLocker locker(&m_lock);
00906 return QDeepCopy<QString>(m_default_msg);
00907 }
00908
00909 void OSDTypeText::SetMultiLine(bool multi)
00910 {
00911 QMutexLocker locker(&m_lock);
00912 m_multiline = multi;
00913 }
00914
00915 void OSDTypeText::SetCentered(bool docenter)
00916 {
00917 QMutexLocker locker(&m_lock);
00918 m_centered = docenter;
00919 }
00920
00921 void OSDTypeText::SetRightJustified(bool right)
00922 {
00923 QMutexLocker locker(&m_lock);
00924 m_right = right;
00925 }
00926
00927 void OSDTypeText::SetScrolling(int x, int y)
00928 {
00929 QMutexLocker locker(&m_lock);
00930 m_scroller = true;
00931 m_scrollx = x;
00932 m_scrolly = y;
00933 }
00934
00935 void OSDTypeText::SetLineSpacing(float linespacing)
00936 {
00937 QMutexLocker locker(&m_lock);
00938 m_linespacing = linespacing;
00939 }
00940
00941 void OSDTypeText::Reinit(float wmult, float hmult)
00942 {
00943 QMutexLocker locker(&m_lock);
00944 m_displaysize = m_screensize = bias(m_unbiasedsize, wmult, hmult);
00945 }
00946
00947 void OSDTypeText::Draw(OSDSurface *surface, int fade, int maxfade, int xoff,
00948 int yoff)
00949 {
00950 QMutexLocker locker(&m_lock);
00951
00952
00953 static QMutex regexp_lock;
00954 static QRegExp br("%BR%");
00955 static QRegExp nl("\n");
00956
00957 int textlength = 0;
00958
00959 if (m_message == QString::null)
00960 return;
00961
00962 if (m_message.contains("%d"))
00963 m_parent->SetWantsUpdates(true);
00964
00965 if (m_scroller)
00966 m_parent->SetDrawEveryFrame(true);
00967
00968 m_font->CalcWidth(m_message, &textlength);
00969
00970 int maxlength = m_displaysize.width();
00971
00972 if (m_multiline)
00973 {
00974 QString tmp_msg = QDeepCopy<QString>(m_message);
00975 regexp_lock.lock();
00976 tmp_msg.replace(br, "\n");
00977 tmp_msg.replace(nl," \n ");
00978 regexp_lock.unlock();
00979
00980 QStringList wordlist = QStringList::split(" ", tmp_msg);
00981 int length = 0;
00982 int lines = 0;
00983
00984 QString line = "";
00985
00986 QStringList::iterator it = wordlist.begin();
00987 for (; it != wordlist.end(); ++it)
00988 {
00989 QString word = *it;
00990 if (word == "%d")
00991 {
00992 m_parent->SetWantsUpdates(true);
00993 int timeleft = (m_parent->GetTimeLeft() + 999999) / 1000000;
00994 if (timeleft > 99)
00995 timeleft = 99;
00996 if (timeleft < 0)
00997 timeleft = 0;
00998
00999 word = QString::number(timeleft);
01000 }
01001
01002 if (!length && word == "\n")
01003 continue;
01004
01005 m_font->CalcWidth(word, &textlength);
01006 if ((textlength + m_font->SpaceWidth() + length > maxlength) ||
01007 (word == "\n"))
01008 {
01009 QRect drawrect = m_displaysize;
01010 drawrect.setTop((int)(m_displaysize.top() + m_font->Size() *
01011 (lines) * m_linespacing));
01012 DrawString(surface, drawrect, line, fade, maxfade, xoff, yoff);
01013 length = 0;
01014
01015 line = "";
01016 lines++;
01017
01018 if (word == "\n")
01019 {
01020 word = "";
01021 textlength = 0;
01022 }
01023 }
01024
01025 if (length == 0)
01026 {
01027 length = textlength;
01028 line = word;
01029 }
01030 else
01031 {
01032 line += " " + word;
01033 length += textlength + m_font->SpaceWidth();
01034 }
01035 }
01036
01037 QRect drawrect = m_displaysize;
01038 drawrect.setTop((int)(m_displaysize.top() + m_font->Size() * (lines) *
01039 m_linespacing));
01040 DrawString(surface, drawrect, line, fade, maxfade, xoff, yoff);
01041 }
01042 else if (m_scroller)
01043 {
01044 if (!m_scrollinit)
01045 {
01046 m_displaysize = m_screensize;
01047 if (m_scrollx < 0)
01048 {
01049 int numspaces = m_displaysize.width() / m_font->SpaceWidth();
01050 for (int i = 0; i < numspaces; i++)
01051 m_message.prepend(" ");
01052
01053 int messagewidth = 0;
01054 m_font->CalcWidth(m_message, &messagewidth);
01055 m_scrollstartx = 0;
01056 m_scrollendx = 0 - (messagewidth);
01057 m_scrollposx = m_scrollstartx;
01058 m_displaysize.setWidth(messagewidth);
01059 }
01060 else if (m_scrollx > 0)
01061 {
01062 int messagewidth = 0;
01063 m_font->CalcWidth(m_message, &messagewidth);
01064 m_scrollstartx = 0 - (messagewidth);
01065 m_scrollendx = m_displaysize.width();
01066 m_scrollposx = m_scrollstartx;
01067 m_displaysize.setWidth(messagewidth);
01068 }
01069
01070 m_scrollstarty = 0;
01071 m_scrollendy = 0;
01072 m_scrollposy = 0;
01073
01074 m_scrollinit = true;
01075 }
01076 else
01077 {
01078 m_scrollposx += m_scrollx;
01079 m_scrollposy += m_scrolly;
01080
01081 if ((m_scrollx < 0 && m_scrollposx < m_scrollendx) ||
01082 (m_scrollx > 0 && m_scrollposx > m_scrollendx))
01083 m_parent->Hide();
01084 }
01085
01086 DrawString(surface, m_displaysize, m_message, fade, maxfade,
01087 xoff + m_scrollposx, yoff + m_scrollposy);
01088 }
01089 else if (!m_message.contains("["))
01090 {
01091 DrawString(surface, m_displaysize, m_message,
01092 fade, maxfade, xoff, yoff);
01093 }
01094 else
01095 {
01096 DrawHiLiteString(surface, m_displaysize, m_message,
01097 fade, maxfade, xoff, yoff);
01098 }
01099 }
01100
01101 void OSDTypeText::DrawHiLiteString(OSDSurface *surface, QRect rect,
01102 const QString &text, int fade, int maxfade,
01103 int xoff, int yoff, bool double_size)
01104 {
01105 QMutexLocker locker(&m_lock);
01106
01107 if (m_draw_info_str != text)
01108 {
01109 m_draw_info_str = QDeepCopy<QString>(text);
01110 m_draw_info.clear();
01111 m_draw_info_len = 0;
01112
01113 bool in_hilite = false;
01114 QString str = text;
01115
01116 while (!str.isEmpty())
01117 {
01118 QString tmp = str;
01119 int loc = str.find((in_hilite) ? "]" : "[");
01120
01121 if (loc < 0)
01122 {
01123 str = QString::null;
01124 }
01125 else
01126 {
01127 tmp = str.left(loc);
01128 str = str.mid(loc + 1);
01129 }
01130
01131 if (!tmp.isEmpty())
01132 {
01133 int msgwidth = 0;
01134 TTFFont *font = (in_hilite || m_selected) ? m_altfont : m_font;
01135 if (font)
01136 font->CalcWidth(tmp, &msgwidth);
01137 m_draw_info_len += msgwidth;
01138 m_draw_info.push_back(DrawInfo(tmp, msgwidth, in_hilite));
01139 }
01140
01141 in_hilite = !in_hilite;
01142 }
01143 }
01144
01145 if (m_centered || m_right)
01146 {
01147 int xoffset = rect.width() - m_draw_info_len;
01148 if (m_centered)
01149 xoffset /= 2;
01150
01151 if (xoffset > 0)
01152 rect.moveBy(xoffset, 0);
01153 }
01154
01155 rect.moveBy(xoff, yoff);
01156 rect.setRight( min(rect.right(), surface->width));
01157 rect.setBottom(min(rect.bottom(), surface->height));
01158
01159 QRect off_rect = rect;
01160 for (uint i = 0; i < m_draw_info.size(); i++)
01161 {
01162 int alphamod = 255;
01163 if (maxfade > 0 && fade >= 0)
01164 alphamod = (int)((((float)(fade) / maxfade) * 256.0) + 0.5);
01165
01166 bool use_alt = m_draw_info[i].hilite || m_selected;
01167 TTFFont *font = (use_alt) ? m_altfont : m_font;
01168 if (font && (off_rect.width() > 0) && (off_rect.height() > 0))
01169 {
01170 font->DrawString(surface, off_rect.left(), off_rect.top(),
01171 m_draw_info[i].msg,
01172 off_rect.right(), off_rect.bottom(),
01173 alphamod, double_size);
01174
01175 off_rect.moveBy(m_draw_info[i].width, 0);
01176 rect.setRight( min(rect.right(), surface->width));
01177 rect.setBottom(min(rect.bottom(), surface->height));
01178 }
01179 }
01180
01181
01182 if (IsSelected() && !IsButton())
01183 {
01184 xoff = 0;
01185 if (m_cursorpos > 0)
01186 {
01187 int i = 0, w = 0, len = 0, pos = m_cursorpos;
01188 for (; i < (int) m_draw_info.size(); i++)
01189 {
01190 len += m_draw_info[i].msg.length();
01191 if (len > m_cursorpos)
01192 break;
01193 xoff += m_draw_info[i].width;
01194 pos -= m_draw_info[i].msg.length();
01195 }
01196 QString tmp = m_draw_info[i].msg.left(max(pos,0));
01197 if (!tmp.isEmpty())
01198 {
01199 bool use_alt = m_draw_info[i].hilite || m_selected;
01200 TTFFont *font = (use_alt) ? m_altfont : m_font;
01201 font->CalcWidth(tmp, &w);
01202 xoff += w;
01203 }
01204 }
01205
01206 QRect crect(rect.top(), rect.left(), 2, (m_font->Size() * 3) / 2);
01207 if (crect.right() < surface->width && crect.right() < rect.right())
01208 {
01209 OSDTypeBox box("cursor", crect, 1.0f, 1.0f);
01210 box.SetColor(Qt::white);
01211 box.Draw(surface, fade, maxfade, xoff, 0, 200);
01212 }
01213 }
01214 }
01215
01216 void OSDTypeText::DrawString(OSDSurface *surface, QRect rect,
01217 const QString &text, int fade, int maxfade,
01218 int xoff, int yoff, bool doubl)
01219 {
01220 QMutexLocker locker(&m_lock);
01221
01222 if (m_centered || m_right)
01223 {
01224 int textlength = 0;
01225 m_font->CalcWidth(text, &textlength);
01226
01227 int xoffset = rect.width() - textlength;
01228 if (m_centered)
01229 xoffset /= 2;
01230
01231 if (xoffset > 0)
01232 rect.moveBy(xoffset, 0);
01233 }
01234
01235 rect.moveBy(xoff, yoff);
01236 rect.setRight( min(rect.right(), surface->width));
01237 rect.setBottom(min(rect.bottom(), surface->height));
01238
01239 int alphamod = 255;
01240 if (maxfade > 0 && fade >= 0)
01241 alphamod = (int)((((float)(fade) / maxfade) * 256.0) + 0.5);
01242
01243 TTFFont *font = m_font;
01244 if ((m_usingalt || m_selected) && m_altfont)
01245 font = m_altfont;
01246
01247 font->DrawString(surface, rect.left(), rect.top(), text,
01248 rect.right(), rect.bottom(), alphamod, doubl);
01249
01250
01251 if (IsSelected() && !IsButton())
01252 {
01253 xoff = 0;
01254 if (m_cursorpos > 0)
01255 m_font->CalcWidth(text.left(m_cursorpos), &xoff);
01256
01257 QRect crect(rect.left(), rect.top(), 2, (m_font->Size() * 3) / 2);
01258 if (crect.right() < surface->width && crect.right() < rect.right())
01259 {
01260 OSDTypeBox box("cursor", crect, 1.0f, 1.0f);
01261 box.SetColor(Qt::white);
01262 box.Draw(surface, fade, maxfade, xoff, 0, 200);
01263 }
01264 }
01265 }
01266
01267 int clamp(int val, int minimum, int maximum)
01268 {
01269 return min(max(val, minimum), maximum);
01270 }
01271
01272 bool OSDTypeText::MoveCursor(int dir)
01273 {
01274 QMutexLocker locker(&m_lock);
01275
01276 if (!IsEntry() || IsButton())
01277 return false;
01278
01279 int new_pos = m_cursorpos + dir;
01280 m_cursorpos = clamp(new_pos, 0, (int)m_message.length());
01281 return new_pos == m_cursorpos;
01282 }
01283
01284 bool OSDTypeText::Delete(int dir)
01285 {
01286 QMutexLocker locker(&m_lock);
01287
01288 if (!IsEntry() || IsButton())
01289 return false;
01290
01291 if (dir > 0)
01292 {
01293 m_message.remove(m_cursorpos, dir);
01294 return true;
01295 }
01296
01297 if (dir < 0)
01298 {
01299 int cpos = max(m_cursorpos + dir, 0);
01300 m_message.remove(cpos, abs(cpos - m_cursorpos));
01301 m_cursorpos = cpos;
01302 return true;
01303 }
01304
01305 return false;
01306 }
01307
01308 void OSDTypeText::InsertCharacter(QChar ch)
01309 {
01310 QMutexLocker locker(&m_lock);
01311
01312 if (!IsEntry() || IsButton())
01313 return;
01314
01315 m_message.insert(m_cursorpos, ch);
01316 MoveCursor(+1);
01317 }
01318
01319
01320
01321 OSDTypeImage::OSDTypeImage(const QString &name, const QString &filename,
01322 QPoint displaypos, float wmult, float hmult,
01323 int scalew, int scaleh)
01324 : OSDType(name)
01325 {
01326 m_drawwidth = -1;
01327 m_onlyusefirst = false;
01328
01329 m_filename = filename;
01330 SetPosition(displaypos, wmult, hmult);
01331
01332 m_yuv = m_alpha = NULL;
01333 m_isvalid = false;
01334 m_imagesize = QRect(0, 0, 0, 0);
01335
01336 m_scalew = scalew;
01337 m_scaleh = scaleh;
01338 m_dontround = false;
01339 m_cacheitem = NULL;
01340
01341 Load(filename, wmult, hmult, scalew, scaleh);
01342 }
01343
01344 OSDTypeImage::OSDTypeImage(const OSDTypeImage &other)
01345 : OSDType(other.m_name)
01346 {
01347 m_drawwidth = other.m_drawwidth;
01348 m_onlyusefirst = other.m_onlyusefirst;
01349
01350 m_filename = other.m_filename;
01351 m_displaypos = other.m_displaypos;
01352 m_imagesize = other.m_imagesize;
01353 m_isvalid = other.m_isvalid;
01354 m_name = other.m_name;
01355 m_scalew = other.m_scalew;
01356 m_scaleh = other.m_scaleh;
01357 m_cacheitem = NULL;
01358 m_dontround = other.m_dontround;
01359
01360 m_alpha = m_yuv = NULL;
01361 if (m_isvalid)
01362 {
01363 int size = m_imagesize.width() * m_imagesize.height() * 3 / 2;
01364 m_yuv = new unsigned char[size];
01365 memcpy(m_yuv, other.m_yuv, size);
01366
01367
01368 size = m_imagesize.width() * m_imagesize.height();
01369 m_alpha = new unsigned char[size];
01370 memcpy(m_alpha, other.m_alpha, size);
01371
01372 m_ybuffer = m_yuv;
01373 m_ubuffer = m_yuv + (m_imagesize.width() * m_imagesize.height());
01374 m_vbuffer = m_yuv + (m_imagesize.width() * m_imagesize.height() *
01375 5 / 4);
01376 }
01377 }
01378
01379 OSDTypeImage::OSDTypeImage(const QString &name)
01380 : OSDType(name)
01381 {
01382 m_drawwidth = -1;
01383 m_onlyusefirst = false;
01384
01385 m_displaypos = QPoint(0, 0);
01386 m_unbiasedpos = QPoint(0, 0);
01387
01388 m_yuv = NULL;
01389 m_alpha = NULL;
01390 m_ybuffer = NULL;
01391 m_ubuffer = NULL;
01392 m_vbuffer = NULL;
01393 m_isvalid = false;
01394 m_filename = "";
01395 m_cacheitem = NULL;
01396 m_dontround = false;
01397 }
01398
01399 OSDTypeImage::OSDTypeImage(void)
01400 : OSDType("")
01401 {
01402 m_name = "";
01403 m_drawwidth = -1;
01404 m_onlyusefirst = false;
01405
01406 m_displaypos = QPoint(0, 0);
01407 m_unbiasedpos = QPoint(0, 0);
01408
01409 m_yuv = NULL;
01410 m_alpha = NULL;
01411 m_ybuffer = NULL;
01412 m_ubuffer = NULL;
01413 m_vbuffer = NULL;
01414 m_isvalid = false;
01415 m_filename = "";
01416 m_cacheitem = NULL;
01417 m_dontround = false;
01418 }
01419
01420 OSDTypeImage::~OSDTypeImage()
01421 {
01422
01423
01424
01425 if (m_cacheitem)
01426 {
01427 delete m_cacheitem;
01428 m_cacheitem = NULL;
01429 }
01430 else
01431 {
01432
01433 if (m_yuv)
01434 delete [] m_yuv;
01435 if (m_alpha)
01436 delete [] m_alpha;
01437 }
01438 }
01439
01440 void OSDTypeImage::SetName(const QString &name)
01441 {
01442 m_name = name;
01443 }
01444
01445 void OSDTypeImage::SetPosition(QPoint pos, float wmult, float hmult)
01446 {
01447 m_displaypos = pos;
01448 m_unbiasedpos =
01449 QPoint((int)round(pos.x() / wmult),
01450 (int)round(pos.y() / hmult));
01451 }
01452
01453 void OSDTypeImage::Reinit(float wmult, float hmult)
01454 {
01455 m_displaypos =
01456 QPoint((int)round(m_unbiasedpos.x() * wmult),
01457 (int)round(m_unbiasedpos.y() * hmult));
01458
01459 Load(m_filename, wmult, hmult, m_scalew, m_scaleh);
01460 }
01461
01462 void OSDTypeImage::Load(const QString &filename, float wmult, float hmult,
01463 int scalew, int scaleh, bool usecache)
01464 {
01465 QString ckey;
01466
01467 m_isvalid = false;
01468
01469
01470 if (m_cacheitem && !usecache)
01471 {
01472 c_cache.Insert(m_cacheitem);
01473 m_cacheitem = NULL;
01474 }
01475 else if (!m_cacheitem || !usecache)
01476 {
01477 if (m_yuv)
01478 delete [] m_yuv;
01479 m_yuv = NULL;
01480 if (m_alpha)
01481 delete [] m_alpha;
01482 m_alpha = NULL;
01483 }
01484
01485 if (scalew > 0 && m_scalew > 0)
01486 scalew = m_scalew;
01487 if (scaleh > 0 && m_scaleh > 0)
01488 scaleh = m_scaleh;
01489
01490 if (usecache)
01491 {
01492 if (!filename.isEmpty() && filename.length() >= 2)
01493 ckey = OSDImageCache::CreateKey(filename, wmult, hmult,
01494 scalew, scaleh);
01495 else
01496 return;
01497
01498
01499 OSDImageCacheValue *value = c_cache.Get(ckey, true);
01500
01501 if (value != NULL)
01502 {
01503 m_yuv = value->m_yuv;
01504 m_ybuffer = value->m_ybuffer;
01505 m_ubuffer = value->m_ubuffer;
01506 m_vbuffer = value->m_vbuffer;
01507 m_alpha = value->m_alpha;
01508 m_imagesize = value->m_imagesize;
01509 m_isvalid = true;
01510 m_filename = filename;
01511
01512
01513
01514
01515 if (m_cacheitem)
01516 c_cache.Insert(m_cacheitem);
01517 m_cacheitem = value;
01518
01519 return;
01520 }
01521 }
01522
01523
01524 QImage tmpimage(filename);
01525
01526 if (tmpimage.width() == 0)
01527 return;
01528
01529 int imwidth = 0, imheight = 0;
01530
01531 if (scalew > 0)
01532 imwidth = ((int)(scalew * wmult) / 2) * 2;
01533 else
01534 imwidth = ((int)(tmpimage.width() * wmult) / 2) * 2;
01535
01536 if (scaleh > 0)
01537 imheight = ((int)(scaleh * hmult) / 2) * 2;
01538 else
01539 imheight = ((int)(tmpimage.height() * hmult) / 2) * 2;
01540
01541 QImage tmp2 = tmpimage.smoothScale(imwidth, imheight);
01542
01543 m_isvalid = true;
01544 m_filename = filename;
01545
01546 m_yuv = new unsigned char[imwidth * imheight * 3 / 2];
01547 m_ybuffer = m_yuv;
01548 m_ubuffer = m_yuv + (imwidth * imheight);
01549 m_vbuffer = m_yuv + (imwidth * imheight * 5 / 4);
01550
01551 m_alpha = new unsigned char[imwidth * imheight];
01552
01553 rgb32_to_yuv420p(m_ybuffer, m_ubuffer, m_vbuffer, m_alpha, tmp2.bits(),
01554 imwidth, imheight, tmp2.width());
01555
01556 m_imagesize = QRect(0, 0, imwidth, imheight);
01557
01558 if (usecache)
01559 {
01560
01561
01562
01563 if (m_cacheitem)
01564 c_cache.Insert(m_cacheitem);
01565
01566 m_cacheitem = new OSDImageCacheValue(
01567 ckey,
01568 m_yuv, m_ybuffer, m_ubuffer,
01569 m_vbuffer, m_alpha, m_imagesize);
01570
01571
01572 if (!filename.isEmpty())
01573 c_cache.SaveToDisk(m_cacheitem);
01574 }
01575 }
01576
01577 void OSDTypeImage::Load(const QImage &img)
01578 {
01579
01580
01581 if (!m_cacheitem)
01582 {
01583 if (m_yuv)
01584 delete [] m_yuv;
01585 m_yuv = NULL;
01586 if (m_alpha)
01587 delete [] m_alpha;
01588 m_alpha = NULL;
01589 m_isvalid = false;
01590 }
01591 else
01592 {
01593 delete m_cacheitem;
01594 m_cacheitem = NULL;
01595 m_isvalid = false;
01596 m_yuv = NULL;
01597 m_alpha = NULL;
01598 }
01599
01600 m_isvalid = true;
01601
01602 int imwidth = (img.width() + 1) & ~1;
01603 int imheight = (img.height() + 1) & ~1;
01604
01605 m_yuv = new unsigned char[imwidth * imheight * 3 / 2];
01606 m_ybuffer = m_yuv;
01607 m_ubuffer = m_yuv + (imwidth * imheight);
01608 m_vbuffer = m_yuv + (imwidth * imheight * 5 / 4);
01609
01610 m_alpha = new unsigned char[imwidth * imheight];
01611
01612 rgb32_to_yuv420p(m_ybuffer, m_ubuffer, m_vbuffer, m_alpha, img.bits(),
01613 img.width(), img.height(), img.bytesPerLine() / 4);
01614
01615 m_imagesize = QRect(0, 0, imwidth, imheight);
01616 }
01617
01618 void OSDTypeImage::Draw(OSDSurface *surface, int fade, int maxfade,
01619 int xoff, int yoff)
01620 {
01621 if (m_hidden)
01622 return;
01623
01624 if (!m_isvalid)
01625 return;
01626
01627 int xstart = 0, ystart = 0, startcol = 0, startline = 0;
01628
01629 if (m_dontround)
01630 {
01631 xstart = m_displaypos.x() + xoff;
01632 ystart = m_displaypos.y() + yoff;
01633 }
01634 else
01635 {
01636 xstart = ((m_displaypos.x() + xoff + 1) / 2) * 2;
01637 ystart = ((m_displaypos.y() + yoff) / 2) * 2;
01638 }
01639
01640 if (ystart < 0)
01641 {
01642 startline = 0 - ystart;
01643 ystart = 0;
01644 }
01645
01646 if (xstart < 0)
01647 {
01648 startcol = 0 - xstart;
01649 xstart = 0;
01650 }
01651
01652 int iwidth = m_imagesize.width();
01653 int drawwidth = (m_drawwidth >= 0) ? m_drawwidth : m_imagesize.width();
01654 int drawheight = m_imagesize.height();
01655
01656 drawwidth = (drawwidth + xstart > surface->width) ?
01657 surface->width - xstart - 1 : drawwidth;
01658
01659 drawheight = (drawheight + ystart > surface->height) ?
01660 surface->height - ystart - 1 : drawheight;
01661
01662 if ((drawwidth <= 0) || (drawheight <= 0))
01663 return;
01664
01665 QRect destRect = QRect(xstart, ystart, drawwidth, drawheight);
01666 bool needblend = m_onlyusefirst || surface->IntersectsDrawn(destRect);
01667
01668 surface->AddRect(destRect);
01669
01670 int alphamod = 255;
01671
01672 if (maxfade > 0 && fade >= 0)
01673 alphamod = (int)((((float)(fade) / maxfade) * 256.0) + 0.5);
01674
01675 if (!needblend)
01676 {
01677 for (int y = startline; y < drawheight; y++)
01678 {
01679 int ysrcwidth = y * iwidth;
01680 int ydestwidth = (y + ystart - startline) * surface->width;
01681
01682 memcpy(surface->y + xstart + ydestwidth,
01683 m_ybuffer + startcol + ysrcwidth, drawwidth);
01684
01685 unsigned char *destalpha = surface->alpha + xstart + ydestwidth;
01686
01687 for (int x = startcol; x < drawwidth; x++)
01688 {
01689 int alpha = *(m_alpha + x + ysrcwidth);
01690
01691 if (alpha == 0)
01692 *destalpha = 0;
01693 else
01694 *destalpha = ((alpha * alphamod) + 0x80) >> 8;
01695
01696 destalpha++;
01697 }
01698 }
01699
01700 iwidth /= 2;
01701 drawwidth /= 2;
01702 drawheight /= 2;
01703 ystart /= 2;
01704 xstart /= 2;
01705 startline /= 2;
01706 startcol /= 2;
01707
01708 for (int y = startline; y < drawheight; y++)
01709 {
01710 int uvsrcwidth = y * iwidth;
01711 int uvdestwidth = (y + ystart - startline) * (surface->width / 2);
01712
01713 memcpy(surface->u + xstart + uvdestwidth,
01714 m_ubuffer + startcol + uvsrcwidth, drawwidth);
01715 memcpy(surface->v + xstart + uvdestwidth,
01716 m_vbuffer + startcol + uvsrcwidth, drawwidth);
01717 }
01718
01719 return;
01720 }
01721
01722 int ysrcwidth = startline * iwidth;
01723 int uvsrcwidth = ysrcwidth / 4;
01724 int startingx = (m_onlyusefirst) ? 0 : startcol;
01725
01726 unsigned char *src = m_ybuffer + ysrcwidth + startingx;
01727 unsigned char *usrc = m_ubuffer + uvsrcwidth + startingx / 2;
01728 unsigned char *vsrc = m_vbuffer + uvsrcwidth + startingx / 2;
01729 unsigned char *srcalpha = m_alpha + ysrcwidth + startingx;
01730
01731 int ydestwidth = ystart * surface->width;
01732 int uvdestwidth = ydestwidth / 4;
01733
01734 unsigned char *dest = surface->y + xstart + ydestwidth;
01735 unsigned char *udest = surface->u + xstart / 2 + uvdestwidth;
01736 unsigned char *vdest = surface->v + xstart / 2 + uvdestwidth;
01737 unsigned char *destalpha = surface->alpha + xstart + ydestwidth;
01738
01739 if (m_onlyusefirst)
01740 (surface->blendcolumnfunc) (src, usrc, vsrc, srcalpha, iwidth, dest,
01741 udest, vdest, destalpha, surface->width,
01742 drawwidth - startcol,
01743 drawheight - startline,
01744 alphamod, 1, surface->rec_lut,
01745 surface->pow_lut);
01746 else
01747 (surface->blendregionfunc) (src, usrc, vsrc, srcalpha, iwidth, dest,
01748 udest, vdest, destalpha, surface->width,
01749 drawwidth - startcol,
01750 drawheight - startline,
01751 alphamod, 1, surface->rec_lut,
01752 surface->pow_lut);
01753 }
01754
01755
01756
01757 OSDTypePosSlider::OSDTypePosSlider(const QString &name,
01758 const QString &filename,
01759 QRect displayrect, float wmult,
01760 float hmult, int scalew, int scaleh)
01761 : OSDTypeImage(name, filename, displayrect.topLeft(), wmult,
01762 hmult, scalew, scaleh)
01763 {
01764 m_maxval = 1000;
01765 m_curval = 0;
01766 m_displayrect = displayrect;
01767 m_unbiasedrect = unbias(m_displayrect, wmult, hmult);
01768 }
01769
01770 OSDTypePosSlider::~OSDTypePosSlider()
01771 {
01772 }
01773
01774 void OSDTypePosSlider::Reinit(float wmult, float hmult)
01775 {
01776 m_displayrect = bias(m_unbiasedrect, wmult, hmult);
01777 OSDTypeImage::Reinit(wmult, hmult);
01778 }
01779
01780 void OSDTypePosSlider::SetPosition(int pos)
01781 {
01782 m_curval = pos;
01783 if (m_curval > 1000)
01784 m_curval = 1000;
01785 if (m_curval < 0)
01786 m_curval = 0;
01787
01788 int xpos = (int)((m_displayrect.width() / 1000.0) * m_curval);
01789 int width = m_imagesize.width() / 2;
01790
01791 xpos = m_displayrect.left() + xpos - width;
01792
01793 m_displaypos.setX(xpos);
01794 }
01795
01796
01797
01798 OSDTypeFillSlider::OSDTypeFillSlider(const QString &name,
01799 const QString &filename,
01800 QRect displayrect, float wmult,
01801 float hmult, int scalew, int scaleh)
01802 : OSDTypeImage(name, filename, displayrect.topLeft(), wmult,
01803 hmult, scalew, scaleh)
01804 {
01805 m_maxval = 1000;
01806 m_curval = 0;
01807 m_drawwidth = 0;
01808 m_onlyusefirst = true;
01809 m_displayrect = displayrect;
01810 m_unbiasedrect = unbias(m_displayrect, wmult, hmult);
01811 }
01812
01813 OSDTypeFillSlider::~OSDTypeFillSlider()
01814 {
01815 }
01816
01817 void OSDTypeFillSlider::Reinit(float wmult, float hmult)
01818 {
01819 m_displayrect = bias(m_unbiasedrect, wmult, hmult);
01820 OSDTypeImage::Reinit(wmult, hmult);
01821 }
01822
01823 void OSDTypeFillSlider::SetPosition(int pos)
01824 {
01825 m_curval = pos;
01826 if (m_curval > 1000)
01827 m_curval = 1000;
01828 if (m_curval < 0)
01829 m_curval = 0;
01830
01831 m_drawwidth = (int)((m_displayrect.width() / 1000.0) * m_curval);
01832 }
01833
01834 void OSDTypeFillSlider::Draw(OSDSurface *surface, int fade, int maxfade,
01835 int xoff, int yoff)
01836 {
01837 if (!m_isvalid)
01838 return;
01839
01840 OSDTypeImage::Draw(surface, fade, maxfade, xoff, yoff);
01841 }
01842
01843
01844
01845 OSDTypeEditSlider::OSDTypeEditSlider(const QString &name,
01846 const QString &bluefilename,
01847 const QString &redfilename,
01848 QRect displayrect, float wmult,
01849 float hmult, int scalew, int scaleh)
01850 : OSDTypeImage(name)
01851 {
01852 m_maxval = 1000;
01853 m_curval = 0;
01854 m_displayrect = displayrect;
01855 m_unbiasedrect = unbias(m_displayrect, wmult, hmult);
01856 m_drawwidth = displayrect.width();
01857
01858 m_drawMap = new unsigned char[m_drawwidth + 1];
01859 for (int i = 0; i < m_drawwidth; i++)
01860 m_drawMap[i] = 0;
01861
01862 m_displaypos = displayrect.topLeft();
01863
01864 m_yuv = m_alpha = NULL;
01865 m_isvalid = false;
01866
01867 m_ryuv = m_ralpha = NULL;
01868 m_risvalid = false;
01869
01870 m_redname = redfilename;
01871 m_bluename = bluefilename;
01872
01873 m_scalew = scalew;
01874 m_scaleh = scaleh;
01875 m_cacheitem = NULL;
01876
01877 Load(m_redname, wmult, hmult, scalew, scaleh, false);
01878 if (m_isvalid)
01879 {
01880 m_risvalid = m_isvalid;
01881 m_ralpha = m_alpha;
01882 m_ryuv = m_yuv;
01883 m_rimagesize = m_imagesize;
01884 m_rybuffer = m_ybuffer;
01885 m_rubuffer = m_ubuffer;
01886 m_rvbuffer = m_vbuffer;
01887
01888 m_isvalid = false;
01889 m_alpha = m_yuv = NULL;
01890 }
01891
01892 Load(m_bluename, wmult, hmult, scalew, scaleh, false);
01893 }
01894
01895 OSDTypeEditSlider::~OSDTypeEditSlider()
01896 {
01897 delete [] m_drawMap;
01898 }
01899
01900 void OSDTypeEditSlider::Reinit(float wmult, float hmult)
01901 {
01902 m_displayrect = bias(m_unbiasedrect, wmult, hmult);
01903 m_drawwidth = m_displayrect.width();
01904
01905 delete [] m_drawMap;
01906
01907 m_drawMap = new unsigned char[m_drawwidth + 1];
01908 for (int i = 0; i < m_drawwidth; i++)
01909 m_drawMap[i] = 0;
01910
01911 m_displaypos = m_displayrect.topLeft();
01912
01913 Load(m_redname, wmult, hmult, m_scalew, m_scaleh, false);
01914 if (m_isvalid)
01915 {
01916 m_risvalid = m_isvalid;
01917 m_ralpha = m_alpha;
01918 m_ryuv = m_yuv;
01919 m_rimagesize = m_imagesize;
01920 m_rybuffer = m_ybuffer;
01921 m_rubuffer = m_ubuffer;
01922 m_rvbuffer = m_vbuffer;
01923
01924 m_isvalid = false;
01925 m_alpha = m_yuv = NULL;
01926 }
01927
01928 Load(m_bluename, wmult, hmult, m_scalew, m_scaleh, false);
01929 }
01930
01931 void OSDTypeEditSlider::ClearAll(void)
01932 {
01933 for (int i = 0; i < m_drawwidth; i++)
01934 m_drawMap[i] = 0;
01935 }
01936
01937 void OSDTypeEditSlider::SetRange(int start, int end)
01938 {
01939 start = (int)((m_drawwidth / 1000.0) * start);
01940 end = (int)((m_drawwidth / 1000.0) * end);
01941
01942 if (start < 0)
01943 start = 0;
01944 if (start >= m_drawwidth)
01945 start = m_drawwidth - 1;
01946 if (end < 0)
01947 end = 0;
01948 if (end >= m_drawwidth)
01949 end = m_drawwidth - 1;
01950
01951 if (end < start)
01952 {
01953 int tmp = start;
01954 start = end;
01955 end = tmp;
01956 }
01957
01958 for (int i = start; i < end; i++)
01959 m_drawMap[i] = 1;
01960 }
01961
01962 void OSDTypeEditSlider::Draw(OSDSurface *surface, int fade, int maxfade,
01963 int xoff, int yoff)
01964 {
01965 if (!m_isvalid || !m_risvalid)
01966 return;
01967
01968 unsigned char *dest, *destalpha, *src, *rsrc, *srcalpha, *rsrcalpha;
01969 unsigned char *udest, *vdest, *usrc, *rusrc, *vsrc, *rvsrc;
01970
01971 int iwidth, riwidth, width;
01972 iwidth = m_imagesize.width();
01973 riwidth = m_rimagesize.width();
01974 width = m_drawwidth;
01975 int height = m_imagesize.height();
01976
01977 int ystart = m_displaypos.y();
01978 int xstart = m_displaypos.x();
01979
01980 xstart += xoff;
01981 ystart += yoff;
01982
01983 ystart = (ystart / 2) * 2;
01984 xstart = (xstart / 2) * 2;
01985
01986 int startline = 0;
01987 int startcol = 0;
01988
01989 if (ystart < 0)
01990 {
01991 startline = 0 - ystart;
01992 ystart = 0;
01993 }
01994
01995 if (xstart < 0)
01996 {
01997 startcol = 0 - xstart;
01998 xstart = 0;
01999 }
02000
02001 if (height + ystart > surface->height)
02002 height = surface->height - ystart - 1;
02003 if (width + xstart > surface->width)
02004 width = surface->width - xstart - 1;
02005
02006 if (width == 0 || height == 0)
02007 return;
02008
02009 QRect destRect = QRect(xstart, ystart, width, height);
02010 surface->AddRect(destRect);
02011
02012 int ysrcwidth;
02013 int rysrcwidth;
02014 int ydestwidth;
02015
02016 int uvsrcwidth;
02017 int ruvsrcwidth;
02018 int uvdestwidth;
02019
02020 int alphamod = 255;
02021
02022 if (maxfade > 0 && fade >= 0)
02023 alphamod = (int)((((float)(fade) / maxfade) * 256.0) + 0.5);
02024
02025 ysrcwidth = startline * iwidth;
02026 rysrcwidth = startline * riwidth;
02027 ydestwidth = ystart * surface->width;
02028
02029 dest = surface->y + xstart + ydestwidth;
02030 destalpha = surface->alpha + xstart + ydestwidth;
02031 src = m_ybuffer + ysrcwidth;
02032 rsrc = m_rybuffer + rysrcwidth;
02033
02034 srcalpha = m_alpha + ysrcwidth;
02035 rsrcalpha = m_ralpha + rysrcwidth;
02036
02037 uvdestwidth = ydestwidth / 4;
02038 uvsrcwidth = ysrcwidth / 4;
02039 ruvsrcwidth = rysrcwidth / 4;
02040
02041 udest = surface->u + xstart / 2 + uvdestwidth;
02042 usrc = m_ubuffer + uvsrcwidth;
02043 rusrc = m_rubuffer + ruvsrcwidth;
02044
02045 vdest = surface->v + xstart / 2 + uvdestwidth;
02046 vsrc = m_vbuffer + uvsrcwidth;
02047 rvsrc = m_rvbuffer + ruvsrcwidth;
02048 (surface->blendcolumn2func) (rsrc, rusrc, rvsrc, rsrcalpha, riwidth, src,
02049 usrc, vsrc, srcalpha, iwidth,
02050 m_drawMap + startcol, dest, udest, vdest,
02051 destalpha, surface->width, width - startcol,
02052 height - startline, alphamod, 1,
02053 surface->rec_lut, surface->pow_lut);
02054 }
02055
02056
02057
02058 OSDTypeBox::OSDTypeBox(const QString &name, QRect displayrect,
02059 float wmult, float hmult)
02060 : OSDType(name), size(displayrect), m_color(Qt::black)
02061 {
02062 m_unbiasedsize = unbias(size, wmult, hmult);
02063 }
02064
02065 void OSDTypeBox::SetRect(QRect newrect, float wmult, float hmult)
02066 {
02067 size = newrect;
02068 m_unbiasedsize = unbias(size, wmult, hmult);
02069 }
02070
02071 OSDTypeBox::OSDTypeBox(const OSDTypeBox &other)
02072 : OSDType(other.m_name)
02073 {
02074 size = other.size;
02075 m_unbiasedsize = other.m_unbiasedsize;
02076 m_color = other.m_color;
02077 }
02078
02079 OSDTypeBox::~OSDTypeBox()
02080 {
02081 }
02082
02083 void OSDTypeBox::Reinit(float wmult, float hmult)
02084 {
02085 size = bias(m_unbiasedsize, wmult, hmult);
02086 }
02087
02088 void OSDTypeBox::Draw(OSDSurface *surface, int fade, int maxfade,
02089 int xoff, int yoff, unsigned int xalpha)
02090 {
02091 unsigned char *dest, *destalpha;
02092 unsigned char alpha = xalpha & 0xff;
02093
02094 QRect disprect = size;
02095 disprect.moveBy(xoff, yoff);
02096
02097 int xstart = clamp(disprect.left(), 0, surface->width);
02098 int xend = clamp(disprect.right(), 0, surface->width);
02099 int ystart = clamp(disprect.top(), 0, surface->height);
02100 int yend = clamp(disprect.bottom(), 0, surface->height);
02101 int height = yend - ystart;
02102 int width = xend - xstart;
02103
02104 if ((height <= 0) || (width <= 0))
02105 return;
02106
02107 QRect destRect(xstart, ystart, width, height);
02108 surface->AddRect(destRect);
02109
02110 int alphamod = 255;
02111 if (maxfade > 0 && fade >= 0)
02112 alphamod = (int)((((float)(fade) / maxfade) * 256.0) + 0.5);
02113
02114 int h,s,v;
02115 m_color.getHsv(&h, &s, &v);
02116
02117 alpha = ((alpha * alphamod) + 0x80) >> 8;
02118
02119 if (surface->IntersectsDrawn(destRect))
02120 {
02121
02122 dest = surface->y + ystart * surface->width + xstart;
02123 destalpha = surface->alpha + ystart * surface->width + xstart;
02124 (surface->blendconstfunc) (v, 0, 0, alpha, dest, NULL, NULL, destalpha,
02125 surface->width, width, height, 0,
02126 surface->rec_lut, surface->pow_lut);
02127 }
02128 else
02129 {
02130 for (int y = ystart; y < yend; y++)
02131 {
02132 int ydestwidth = y * surface->width;
02133
02134 memset(surface->y + xstart + ydestwidth, 0, width);
02135 memset(surface->alpha + xstart + ydestwidth, alpha, width);
02136 }
02137 }
02138 }
02139
02140
02141
02142 OSDTypePositionIndicator::OSDTypePositionIndicator(void)
02143 {
02144 m_numpositions = 0;
02145 m_curposition = -1;
02146 m_offset = 0;
02147 }
02148
02149 OSDTypePositionIndicator::OSDTypePositionIndicator(
02150 const OSDTypePositionIndicator &other)
02151 {
02152 m_numpositions = other.m_numpositions;
02153 m_curposition = other.m_curposition;
02154 m_offset = other.m_offset;
02155 }
02156
02157 OSDTypePositionIndicator::~OSDTypePositionIndicator()
02158 {
02159 }
02160
02161 void OSDTypePositionIndicator::SetPosition(int pos)
02162 {
02163 m_curposition = pos + m_offset;
02164 if (m_curposition >= m_numpositions)
02165 m_curposition = m_numpositions - 1;
02166 }
02167
02168 void OSDTypePositionIndicator::PositionUp(void)
02169 {
02170 if (m_curposition > m_offset)
02171 m_curposition--;
02172 else if (m_curposition == m_offset)
02173 m_curposition = m_numpositions - 1;
02174 }
02175
02176 void OSDTypePositionIndicator::PositionDown(void)
02177 {
02178 if (m_curposition < m_numpositions - 1)
02179 m_curposition++;
02180 else if (m_curposition == m_numpositions - 1)
02181 m_curposition = m_offset;
02182 }
02183
02184
02185
02186
02187 OSDTypePositionRectangle::OSDTypePositionRectangle(const QString &name)
02188 : OSDType(name), OSDTypePositionIndicator()
02189 {
02190 }
02191
02192 OSDTypePositionRectangle::OSDTypePositionRectangle(
02193 const OSDTypePositionRectangle &other)
02194 : OSDType(other.m_name), OSDTypePositionIndicator(other)
02195 {
02196 for (int i = 0; i < m_numpositions; i++)
02197 {
02198 QRect tmp = other.positions[i];
02199 positions.push_back(tmp);
02200 }
02201 for (int i = 0; i < m_numpositions; i++)
02202 {
02203 QRect tmp = other.unbiasedpos[i];
02204 unbiasedpos.push_back(tmp);
02205 }
02206 }
02207
02208 OSDTypePositionRectangle::~OSDTypePositionRectangle()
02209 {
02210 }
02211
02212 void OSDTypePositionRectangle::Reinit(float wmult, float hmult)
02213 {
02214 for (int i = 0; i < m_numpositions; i++)
02215 positions[i] = bias(unbiasedpos[i], wmult, hmult);
02216 }
02217
02218 void OSDTypePositionRectangle::AddPosition(
02219 QRect rect, float wmult, float hmult)
02220 {
02221 positions.push_back(rect);
02222 unbiasedpos.push_back(unbias(rect, wmult, hmult));
02223 m_numpositions++;
02224 }
02225
02226 void OSDTypePositionRectangle::Draw(
02227 OSDSurface *surface, int fade, int maxfade, int xoff, int yoff)
02228 {
02229 fade = fade;
02230 maxfade = maxfade;
02231 xoff = xoff;
02232 yoff = yoff;
02233
02234 if (m_curposition < 0 || m_curposition >= m_numpositions)
02235 return;
02236
02237 QRect rect = positions[m_curposition];
02238
02239 unsigned char *src;
02240 int ystart = rect.top() + yoff;
02241 int yend = rect.bottom() + yoff;
02242 int xstart = rect.left() + xoff;
02243 int xend = rect.right() + xoff;
02244
02245 if (xstart < 0)
02246 xstart = 0;
02247 if (xend > surface->width)
02248 xend = surface->width;
02249 if (ystart < 0)
02250 ystart = 0;
02251 if (yend > surface->height)
02252 yend = surface->height;
02253
02254 int height = yend - ystart + 1, width = xend - xstart + 1;
02255
02256 QRect destRect = QRect(xstart, ystart, width, height);
02257 surface->AddRect(destRect);
02258
02259 for (int y = ystart; y < yend; y++)
02260 {
02261 if (y < 0 || y >= surface->height)
02262 continue;
02263
02264 for (int x = xstart; x < xstart + 2; x++)
02265 {
02266 if (x < 0 || x >= surface->width)
02267 continue;
02268
02269 src = surface->y + x + y * surface->width;
02270 *src = 255;
02271 }
02272
02273 for (int x = xend - 2; x < xend; x++)
02274 {
02275 if (x < 0 || x >= surface->width)
02276 continue;
02277
02278 src = surface->y + x + y * surface->width;
02279 *src = 255;
02280 }
02281 }
02282
02283 for (int x = xstart; x < xend; x++)
02284 {
02285 if (x < 0 || x >= surface->width)
02286 continue;
02287
02288 for (int y = ystart; y < ystart + 2; y++)
02289 {
02290 if (y < 0 || y >= surface->height)
02291 continue;
02292
02293 src = surface->y + x + y * surface->width;
02294 *src = 255;
02295 }
02296 for (int y = yend - 2; y < yend; y++)
02297 {
02298 if (y < 0 || y >= surface->height)
02299 continue;
02300
02301 src = surface->y + x + y * surface->width;
02302 *src = 255;
02303 }
02304 }
02305 }
02306
02307
02308
02309 OSDTypePositionImage::OSDTypePositionImage(const QString &name)
02310 : OSDTypeImage(name), OSDTypePositionIndicator(),
02311 m_wmult(0.0f), m_hmult(0.0f)
02312 {
02313 }
02314
02315 OSDTypePositionImage::OSDTypePositionImage(const OSDTypePositionImage &other)
02316 : OSDTypeImage(other), OSDTypePositionIndicator(other)
02317 {
02318 m_wmult = other.m_wmult;
02319 m_hmult = other.m_hmult;
02320
02321 for (int i = 0; i < m_numpositions; i++)
02322 {
02323 positions.push_back(other.positions[i]);
02324 unbiasedpos.push_back(other.unbiasedpos[i]);
02325 }
02326 }
02327
02328 OSDTypePositionImage::~OSDTypePositionImage()
02329 {
02330 }
02331
02332 void OSDTypePositionImage::Reinit(float wmult, float hmult)
02333 {
02334 m_wmult = wmult;
02335 m_hmult = hmult;
02336
02337 OSDTypeImage::Reinit(wmult, hmult);
02338
02339 for (int i = 0; i < m_numpositions; i++)
02340 {
02341 positions[i] =
02342 QPoint((int)round(unbiasedpos[i].x() * wmult),
02343 (int)round(unbiasedpos[i].y() * hmult));
02344 }
02345 }
02346
02347 void OSDTypePositionImage::AddPosition(QPoint pos, float wmult, float hmult)
02348 {
02349 if (m_wmult == 0.0f || m_hmult == 0.0f)
02350 {
02351 m_wmult = wmult;
02352 m_hmult = hmult;
02353 }
02354 positions.push_back(pos);
02355 unbiasedpos.push_back(
02356 QPoint((int)round(pos.x() / wmult),
02357 (int)round(pos.y() / hmult)));
02358
02359 VERBOSE(VB_OSD,
02360 "OSDTypePositionImage::AddPosition["<<m_numpositions<<"]("
02361 <<pos.x()<<"x"<<pos.y()
02362 <<" "<<wmult<<", "<<hmult<<")");
02363
02364 m_numpositions++;
02365 }
02366
02367 void OSDTypePositionImage::Draw(OSDSurface *surface, int fade, int maxfade,
02368 int xoff, int yoff)
02369 {
02370 VERBOSE(VB_OSD,
02371 "OSDTypePositionImage::Draw["<<m_curposition<<"]("
02372 <<m_wmult<<", "<<m_hmult<<")");
02373
02374 if (m_curposition < 0 || m_curposition >= m_numpositions)
02375 return;
02376
02377 QPoint pos = positions[m_curposition];
02378
02379 OSDTypeImage::SetPosition(pos, m_wmult, m_hmult);
02380 OSDTypeImage::Draw(surface, fade, maxfade, xoff, yoff);
02381 }
02382
02383
02384
02385 OSDTypeCC::OSDTypeCC(const QString &name, TTFFont *font, int xoff, int yoff,
02386 int dispw, int disph, float wmult, float hmult)
02387 : OSDType(name)
02388 {
02389 m_font = font;
02390 m_textlist = NULL;
02391 xoffset = xoff;
02392 yoffset = yoff;
02393 displaywidth = dispw;
02394 displayheight = disph;
02395 m_wmult = wmult;
02396 m_hmult = hmult;
02397
02398 QRect rect = QRect(0, 0, 0, 0);
02399 m_box = new OSDTypeBox("cc_background", rect, wmult, hmult);
02400 m_ccbackground = gContext->GetNumSetting("CCBackground", 0);
02401 }
02402
02403 OSDTypeCC::~OSDTypeCC()
02404 {
02405 ClearAllCCText();
02406 delete m_box;
02407 }
02408
02409 void OSDTypeCC::Reinit(float wmult, float hmult)
02410 {
02411 (void) wmult;
02412 (void) hmult;
02413 VERBOSE(VB_IMPORTANT, "Programmer error: "
02414 "Call to OSDTypeCC::Reinit(float,float)");
02415 }
02416
02417 void OSDTypeCC::Reinit(int x, int y, int dispw, int disph,
02418 float wmult, float hmult)
02419 {
02420 xoffset = x;
02421 yoffset = y;
02422 displaywidth = dispw;
02423 displayheight = disph;
02424 m_wmult = wmult;
02425 m_hmult = hmult;
02426 }
02427
02428 void OSDTypeCC::AddCCText(const QString &text, int x, int y, int color,
02429 bool teletextmode)
02430 {
02431 ccText *cc = new ccText();
02432 cc->text = text;
02433 cc->x = x;
02434 cc->y = y;
02435 cc->color = color;
02436 cc->teletextmode = teletextmode;
02437
02438 if (!m_textlist)
02439 m_textlist = new vector<ccText *>;
02440
02441 m_textlist->push_back(cc);
02442 }
02443
02444 void OSDTypeCC::ClearAllCCText()
02445 {
02446 if (m_textlist)
02447 {
02448 vector<ccText*>::iterator i = m_textlist->begin();
02449 for (; i != m_textlist->end(); i++)
02450 {
02451 ccText *cc = (*i);
02452 if (cc)
02453 delete cc;
02454 }
02455 delete m_textlist;
02456 m_textlist = NULL;
02457 }
02458 }
02459
02460 int OSDTypeCC::UpdateCCText(vector<ccText*> *ccbuf,
02461 int replace, int scroll, bool scroll_prsv,
02462 int scroll_yoff, int scroll_ymax)
02463
02464
02465
02466
02467
02468
02469 {
02470 vector<ccText*>::iterator i;
02471 int visible = 0;
02472
02473 if (m_textlist && (scroll || replace))
02474 {
02475 ccText *cc;
02476
02477
02478 int ylast = 0;
02479 i = m_textlist->end() - 1;
02480 cc = *i;
02481 if (cc)
02482 ylast = cc->y;
02483
02484
02485 int ydel = scroll_yoff + scroll;
02486 int ykeep = scroll_ymax;
02487 int ymove = 0;
02488 if (scroll_prsv && ylast)
02489 {
02490 ymove = ylast - scroll_ymax;
02491 ydel += ymove;
02492 ykeep += ymove;
02493 }
02494
02495 i = m_textlist->begin();
02496 while (i < m_textlist->end())
02497 {
02498 cc = (*i);
02499 if (!cc)
02500 {
02501 i = m_textlist->erase(i);
02502 continue;
02503 }
02504
02505 if (cc->y > (ylast - replace))
02506 {
02507
02508 delete cc;
02509 i = m_textlist->erase(i);
02510 }
02511 else if (scroll)
02512 {
02513 if (cc->y > ydel && cc->y <= ykeep)
02514 {
02515
02516 cc->y -= (scroll + ymove);
02517 i++;
02518 }
02519 else
02520 {
02521
02522 i = m_textlist->erase(i);
02523 delete cc;
02524 }
02525 }
02526 else
02527 i++;
02528 }
02529 }
02530
02531 if (m_textlist)
02532 visible += m_textlist->size();
02533
02534 if (ccbuf)
02535 {
02536
02537 i = ccbuf->begin();
02538 while (i < ccbuf->end())
02539 {
02540 if (*i)
02541 {
02542 visible++;
02543 if (!m_textlist)
02544 m_textlist = new vector<ccText *>;
02545 m_textlist->push_back(*i);
02546 }
02547 i++;
02548 }
02549 }
02550
02551 return visible;
02552 }
02553
02554 void OSDTypeCC::Draw(OSDSurface *surface, int fade, int maxfade, int xoff,
02555 int yoff)
02556 {
02557
02558 fade = fade;
02559 maxfade = maxfade;
02560 xoff = xoff;
02561 yoff = yoff;
02562
02563 static const QColor clr[8] =
02564 {
02565 Qt::white, Qt::red, Qt::green, Qt::yellow,
02566 Qt::blue, Qt::magenta, Qt::cyan, Qt::white,
02567 };
02568
02569 vector<ccText*>::iterator i = m_textlist->begin();
02570 for (; i != m_textlist->end(); i++)
02571 {
02572 ccText *cc = (*i);
02573
02574 if (cc && (cc->text != QString::null))
02575 {
02576 int textlength = 0;
02577 m_font->CalcWidth(cc->text, &textlength);
02578
02579 int x, y;
02580 if (cc->teletextmode)
02581 {
02582
02583
02584 x = cc->y * displaywidth / 40 + xoffset;
02585 y = cc->x * displayheight / 25 + yoffset;
02586 }
02587 else
02588 {
02589 x = (cc->x + 3) * displaywidth / 36 + xoffset;
02590 y = cc->y * displayheight / 17 + yoffset;
02591 }
02592
02593 int maxx = x + textlength;
02594 int maxy = y + m_font->Size() * 3 / 2;
02595
02596 if (maxx > surface->width)
02597 maxx = surface->width;
02598
02599 if (maxy > surface->height)
02600 maxy = surface->height;
02601
02602 if (m_ccbackground && !cc->teletextmode)
02603 {
02604 QRect rect = QRect(0, 0, textlength + 4,
02605 (m_font->Size() * 3 / 2) + 3);
02606 m_box->SetRect(rect, m_wmult, m_hmult);
02607 m_box->Draw(surface, 0, 0, x - 2, y - 2);
02608 }
02609
02610 m_font->setOutline(!m_ccbackground);
02611 m_font->setColor(Qt::black, kTTF_Outline);
02612 m_font->setColor(clr[max(min(0, cc->color), 7)], kTTF_Normal);
02613
02614 m_font->DrawString(surface, x, y + 2, cc->text, maxx, maxy, 255);
02615 }
02616 }
02617 }
02618
02619
02620
02621 void OSDType708CC::Reinit(int x, int y, int dispw, int disph)
02622 {
02623 xoffset = x;
02624 yoffset = y;
02625 displaywidth = dispw;
02626 displayheight = disph;
02627 }
02628
02629 OSDType708CC::OSDType708CC(const QString &name, TTFFont *fonts[48],
02630 int xoff, int yoff, int dispw, int disph) :
02631 OSDType(name)
02632 {
02633 xoffset = xoff;
02634 yoffset = yoff;
02635 displaywidth = dispw;
02636 displayheight = disph;
02637
02638 for (uint i = 0; i < 48; i++)
02639 m_fonts[i] = fonts[i];
02640 }
02641
02642 QRect OSDType708CC::CalcBounds(const OSDSurface *surface,
02643 const CC708Window &win,
02644 const vector<CC708String*> &list,
02645 uint &min_xoffset)
02646 {
02647 uint max_width = 0, total_height = 0, i = 0;
02648 min_xoffset = 0xffffffff;
02649 for (uint row = 0; (row < win.true_row_count) && (i < list.size()); row++)
02650 {
02651 uint tot_width = 0, max_height = 0;
02652 for (; (i < list.size()) && list[i] && (list[i]->y <= row); i++)
02653 {
02654 int space_length, text_length;
02655 if (list[i]->y < row)
02656 continue;
02657
02658 TTFFont *font = m_fonts[list[i]->attr.FontIndex()];
02659
02660 if (list[i]->str.stripWhiteSpace().isEmpty())
02661 {
02662 max_height = max(max_height, (uint)font->Size() * 3 / 2);
02663 continue;
02664 }
02665
02666 font->CalcWidth(list[i]->str, &text_length);
02667 font->CalcWidth(" ", &space_length);
02668
02669 min_xoffset = min(min_xoffset, space_length * list[i]->x);
02670 tot_width += max(text_length, 0);
02671 max_height = max(max_height, (uint)font->Size() * 3 / 2);
02672
02673 VERBOSE(VB_VBI, "Row#"<<row<<" str#"<<i<<" "
02674 <<"w/x("<<list[i]->x<<"): "
02675 <<"W,H ("<<text_length<<","<<max_height<<") "
02676 <<"'"<<list[i]->str<<"'"
02677 <<" xoff: "<<space_length * list[i]->x);
02678 }
02679 max_width = max(max_width, tot_width);
02680 total_height += max_height;
02681 }
02682 min_xoffset = (min_xoffset == 0xffffffff) ? 0 : min_xoffset;
02683
02684 if (!max_width || !total_height)
02685 return QRect(0,0,0,0);
02686
02687
02688 max_width += 4;
02689 total_height += 4;
02690
02691
02692
02693 float xrange = 210.0f;
02694 float yrange = 75.0f;
02695
02696
02697
02698
02699
02700 xrange = (win.relative_pos) ? 100.0f : xrange;
02701 yrange = (win.relative_pos) ? 100.0f : yrange;
02702
02703 float xmult = (surface->width - 4) / xrange;
02704 float ymult = (surface->height - 4) / yrange;
02705
02706 uint anchor_x = (uint) xmult * win.anchor_horizontal + 2;
02707 uint anchor_y = (uint) ymult * win.anchor_vertical + 2;
02708
02709
02710
02711
02712 bool center = (win.anchor_point % 3 == 1);
02713 bool right = (win.anchor_point % 3 == 2);
02714 bool middle = (win.anchor_point / 3 == 1);
02715 bool bottom = (win.anchor_point / 3 == 2);
02716 if (center)
02717 anchor_x = max(0, ((int)anchor_x) - (((int)max_width) / 2));
02718 if (right)
02719 anchor_x = max(0, ((int)anchor_x) - ((int)max_width));
02720 if (middle)
02721 anchor_y = max(0, ((int)anchor_y) - (((int)total_height) / 2));
02722 if (bottom)
02723 anchor_y = max(0, ((int)anchor_y) - ((int)total_height));
02724
02725
02726
02727
02728
02729 int x_adj = (int)(anchor_x + max_width) - (surface->width - 4);
02730 if (x_adj > 0)
02731 anchor_x = max(0, (int)anchor_x - x_adj);
02732
02733 int y_adj = (int)(anchor_y + total_height) - (surface->height - 4);
02734 if (y_adj > 0)
02735 anchor_y = max(0, (int)anchor_y - y_adj);
02736
02737
02738
02739
02740 if (anchor_x + max_width > (uint)surface->width)
02741 max_width = surface->width - anchor_x;
02742
02743 if (anchor_y + total_height > (uint)surface->height)
02744 total_height = surface->height - anchor_y;
02745
02746 return QRect(anchor_x, anchor_y, max_width, total_height);
02747 }
02748
02749 void OSDType708CC::Draw(OSDSurface *surface,
02750 const QPoint &ul,
02751 const CC708Window &win,
02752 const vector<CC708String*> &list)
02753 {
02754 int maxx = surface->width;
02755 int maxy = surface->height;
02756 uint max_width = 0, total_height = 0, i = 0;
02757 for (uint row = 0; (row < win.true_row_count) && (i < list.size()); row++)
02758 {
02759 uint tot_width = 0, max_height = 0;
02760 for (; (i < list.size() && list[i] && (list[i]->y == row)); i++)
02761 {
02762 int text_length;
02763
02764 if (list[i]->str.isEmpty())
02765 continue;
02766
02767 TTFFont *font = m_fonts[list[i]->attr.FontIndex()];
02768
02769 font->CalcWidth(list[i]->str, &text_length);
02770
02771 font->setColor(list[i]->attr.GetFGColor(), kTTF_Normal);
02772
02773 font->setOutline(false);
02774 font->setShadow(0,0);
02775 if (list[i]->attr.edge_type == 3)
02776 {
02777 font->setColor(list[i]->attr.GetEdgeColor(), kTTF_Outline);
02778 font->setOutline(true);
02779 }
02780 else if (list[i]->attr.edge_type == 4)
02781 {
02782 font->setColor(list[i]->attr.GetEdgeColor(), kTTF_Shadow);
02783 font->setShadow(-2, +2);
02784 }
02785 else if (list[i]->attr.edge_type == 5)
02786 {
02787 font->setColor(list[i]->attr.GetEdgeColor(), kTTF_Shadow);
02788 font->setShadow(+2, +2);
02789 }
02790
02791 font->DrawString(surface,
02792 ul.x() + tot_width, ul.y() + total_height + 2,
02793 list[i]->str, maxx, maxy,
02794 list[i]->attr.GetFGAlpha());
02795
02796 tot_width += max(text_length, 0);
02797 max_height = max(max_height, (uint)font->Size() * 3 / 2);
02798 }
02799 max_width = max(max_width, tot_width);
02800 total_height += max_height;
02801 }
02802 }
02803
02804 void OSDType708CC::Draw(OSDSurface *surface, int , int ,
02805 int , int )
02806 {
02807 float wmult = 1.0f;
02808 float hmult = 1.0f;
02809
02810 if (!cc708data || surface->width < 4 || surface->height < 4)
02811 return;
02812
02813 for (uint i = 0; i < 8; i++)
02814 {
02815 const CC708Window &win = cc708data->windows[i];
02816 if (!win.exists)
02817 continue;
02818
02819 QMutexLocker locker(&win.lock);
02820
02821
02822 vector<CC708String*> list = win.GetStrings();
02823 uint box_xoffset = 0;
02824 QRect bounds = CalcBounds(surface, win, list, box_xoffset);
02825 QPoint ul(0,0);
02826 if (bounds.width())
02827 {
02828 if (list.size() && win.GetFillAlpha())
02829 {
02830 QRect rect(0,0, bounds.width(), bounds.height());
02831 OSDTypeBox box(QString("cc708_background%1").arg(i),
02832 rect, wmult, hmult);
02833 box.SetRect(rect, wmult, hmult);
02834 box.Draw(surface, 0, 0,
02835 bounds.left() + box_xoffset,
02836 bounds.top(), win.GetFillAlpha());
02837 }
02838 Draw(surface, bounds.topLeft(), win, list);
02839 }
02840
02841
02842 for (uint i = 0; i < list.size(); i++)
02843 delete list[i];
02844 }
02845 }