qsptextbox.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. #include "qsptextbox.h"
  2. #include <QFileInfo>
  3. #include <QPalette>
  4. #include <QAbstractScrollArea>
  5. #include <QScrollBar>
  6. #include <QPainter>
  7. #include <QTextBlock>
  8. #include "comtools.h"
  9. QspTextBox::QspTextBox(QWidget *parent) : QTextBrowser(parent)
  10. {
  11. //SetBorders(5);
  12. setFocusPolicy(Qt::NoFocus);
  13. setFrameStyle(QFrame::NoFrame);
  14. setFrameShadow(QFrame::Plain);
  15. setContentsMargins(0,0,0,0);
  16. m_isUseHtml = false;
  17. showPlainText = false;
  18. disableVideo = false;
  19. //m_linkColor = palette().color(QPalette::Link);
  20. //m_fontColor = palette().color(QPalette::Text);
  21. //m_backColor = QColor(224, 224, 224);
  22. m_font = font();
  23. setOpenLinks(false);
  24. #ifndef _WEBBOX_COMMON
  25. connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(resizeAnimations()) );
  26. connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(resizeAnimations()) );
  27. #endif
  28. // m_font = *wxNORMAL_FONT;
  29. // m_outFormat = wxString::Format(
  30. // wxT("<HTML><META HTTP-EQUIV = \"Content-Type\" CONTENT = \"text/html; charset=%s\">")
  31. // wxT("<BODY><FONT COLOR = #%%s>%%s</FONT></BODY></HTML>"),
  32. // wxFontMapper::GetEncodingName(wxLocale::GetSystemEncoding()).wx_str()
  33. // );
  34. }
  35. QspTextBox::~QspTextBox()
  36. {
  37. #ifndef _WEBBOX_COMMON
  38. clearManualResources();
  39. #endif
  40. }
  41. void QspTextBox::SetIsHtml(bool isHtml)
  42. {
  43. if (m_isUseHtml != isHtml)
  44. {
  45. m_isUseHtml = isHtml;
  46. RefreshUI();
  47. }
  48. }
  49. void QspTextBox::RefreshUI(bool isScroll)
  50. {
  51. QString color(QSPTools::GetHexColor(GetForegroundColor()));
  52. //QString str(QByteArray::fromPercentEncoding(m_text.replace("%", "%25").toUtf8()));
  53. //QString text(QSPTools::HtmlizeWhitespaces(m_isUseHtml ? str : QSPTools::ProceedAsPlain(str)));
  54. QString str = m_text;
  55. QString text;
  56. if(m_isUseHtml)
  57. {
  58. if(str.endsWith("\r"))
  59. str.chop(1);
  60. if(str.endsWith("\n"))
  61. str.chop(1);
  62. str = str.replace("\r", "").replace("\n", "<br>").replace("<video ", "<img ", Qt::CaseInsensitive);
  63. text = str.replace("</center><br>", "</center>", Qt::CaseInsensitive).replace("</table><br>", "</table>", Qt::CaseInsensitive);
  64. }
  65. else
  66. {
  67. text = Qt::convertFromPlainText(str);
  68. }
  69. //TODO: set colour and font
  70. if(showPlainText)
  71. setPlainText(text);
  72. else
  73. setHtml(text);
  74. if (isScroll) verticalScrollBar()->setValue(verticalScrollBar()->maximum());
  75. }
  76. void QspTextBox::SetText(const QString& text, bool isScroll)
  77. {
  78. if (m_text != text)
  79. {
  80. #ifndef _WEBBOX_COMMON
  81. clearManualResources();
  82. #endif
  83. if (isScroll)
  84. {
  85. if (m_text.isEmpty() || !text.startsWith(m_text))
  86. isScroll = false;
  87. }
  88. m_text = text;
  89. RefreshUI(isScroll);
  90. #ifndef _WEBBOX_COMMON
  91. resizeAnimations();
  92. #endif
  93. }
  94. }
  95. void QspTextBox::SetTextFont(const QFont& new_font)
  96. {
  97. if (m_font != new_font)
  98. {
  99. m_font = new_font;
  100. setFont(new_font); //TODO: check which one of this to use
  101. setCurrentFont(new_font);
  102. }
  103. }
  104. bool QspTextBox::SetLinkColor(const QColor &color)
  105. {
  106. //QPalette p = palette();
  107. //p.setBrush( QPalette::Link, clr);
  108. //setPalette( p );
  109. //NOTE: From Qt documentation:
  110. //Note that we do not use the Link and LinkVisited roles when rendering rich text in Qt, and that we recommend that you use CSS and the QTextDocument::setDefaultStyleSheet() function to alter the appearance of links.
  111. if(m_linkColor != color)
  112. {
  113. QString sheet = QString::fromLatin1("a { text-decoration: underline; color: %1 }").arg(color.name());
  114. document()->setDefaultStyleSheet(sheet);
  115. m_linkColor = color;
  116. RefreshUI();
  117. return true;
  118. }
  119. return false;
  120. }
  121. void QspTextBox::SetGamePath(const QString &path)
  122. {
  123. m_path = path;
  124. setSearchPaths(QStringList(path));
  125. }
  126. //Returns the background color of the window.
  127. QColor QspTextBox::GetBackgroundColor()
  128. {
  129. return m_backColor;
  130. }
  131. //The meaning of foreground colour varies according to the window class; it may be the text colour or other colour, or it may not be used at all. Additionally, not all native controls support changing their foreground colour so this method may change their colour only partially or even not at all.
  132. QColor QspTextBox::GetForegroundColor()
  133. {
  134. return m_fontColor;
  135. }
  136. //Returns true if the color was really changed, false if it was already set to this color and nothing was done.
  137. bool QspTextBox::SetBackgroundColor(const QColor &color)
  138. {
  139. if(m_backColor != color)
  140. {
  141. QPalette p = palette();
  142. p.setColor(QPalette::Base, color);
  143. setPalette(p);
  144. m_backColor = color;
  145. setTextBackgroundColor(color);
  146. RefreshUI();
  147. return true;
  148. }
  149. return false;
  150. }
  151. bool QspTextBox::SetForegroundColor(const QColor &color)
  152. {
  153. //TODO: find alternative
  154. //NOTE: From Qt documentation
  155. //Warning: Do not use this function (void setPalette(const QPalette &)) in conjunction with Qt Style Sheets.
  156. if(m_fontColor != color)
  157. {
  158. m_fontColor = color;
  159. setTextColor(color);
  160. QPalette p = palette();
  161. p.setColor(QPalette::Text, color);
  162. p.setColor(QPalette::WindowText, color);
  163. setPalette(p);
  164. RefreshUI();
  165. return true;
  166. }
  167. return false;
  168. }
  169. void QspTextBox::SetShowPlainText(bool isPlain)
  170. {
  171. showPlainText = isPlain;
  172. RefreshUI();
  173. }
  174. void QspTextBox::wheelEvent(QWheelEvent *e)
  175. {
  176. if( e->modifiers() == Qt::ControlModifier )
  177. return;
  178. QTextBrowser::wheelEvent(e);
  179. }
  180. void QspTextBox::keyPressEvent(QKeyEvent *event)
  181. {
  182. QTextBrowser::keyPressEvent(event);
  183. }
  184. #ifndef _WEBBOX_COMMON
  185. void QspTextBox::SetBackgroundImage(const QImage& bmpBg)
  186. {
  187. m_bmpBg = bmpBg;
  188. CalcImageSize();
  189. }
  190. void QspTextBox::LoadBackImage(const QString& fileName)
  191. {
  192. QFileInfo file(m_path + fileName);
  193. QString path(file.absoluteFilePath());
  194. if (m_imagePath != path)
  195. {
  196. m_imagePath = path;
  197. if (file.exists() && file.isFile())
  198. {
  199. QImage image;
  200. if (image.load(path))
  201. {
  202. SetBackgroundImage(image);
  203. //Refresh();
  204. return;
  205. }
  206. }
  207. SetBackgroundImage(QImage());
  208. //Refresh();
  209. }
  210. }
  211. void QspTextBox::CalcImageSize()
  212. {
  213. if (!m_bmpBg.isNull())
  214. {
  215. int w, h;
  216. w = this->childrenRect().width();
  217. h = this->childrenRect().height();
  218. if (w < 1) w = 1;
  219. if (h < 1) h = 1;
  220. int srcW = m_bmpBg.width(), srcH = m_bmpBg.height();
  221. int destW = srcW * h / srcH, destH = srcH * w / srcW;
  222. if (destW > w)
  223. destW = w;
  224. else
  225. destH = h;
  226. m_posX = (w - destW) / 2;
  227. m_posY = (h - destH) / 2;
  228. if (destW > 0 && destH > 0)
  229. m_bmpRealBg = m_bmpBg.scaled(destW, destH);
  230. }
  231. }
  232. void QspTextBox::paintEvent(QPaintEvent *e)
  233. {
  234. QPainter painter(viewport());
  235. if (!m_bmpBg.isNull())
  236. {
  237. painter.drawImage(m_posX, m_posY, m_bmpRealBg);
  238. }
  239. QTextBrowser::paintEvent(e);
  240. }
  241. void QspTextBox::resizeEvent(QResizeEvent *e)
  242. {
  243. if (!m_bmpBg.isNull())
  244. {
  245. CalcImageSize();
  246. }
  247. resizeAnimations();
  248. QTextBrowser::resizeEvent(e);
  249. }
  250. void QspTextBox::clearManualResources()
  251. {
  252. for(auto animationsItem : animations_gif)
  253. {
  254. if(animationsItem.movie != 0)
  255. delete animationsItem.movie;
  256. if(animationsItem.movieLabel != 0)
  257. delete animationsItem.movieLabel;
  258. }
  259. animations_gif.clear();
  260. for(auto animationsItem : animations_video)
  261. {
  262. if(animationsItem.videoLabel != 0)
  263. delete animationsItem.videoLabel;
  264. }
  265. animations_video.clear();
  266. }
  267. QVariant QspTextBox::loadResource(int type, const QUrl &name)
  268. {
  269. QString new_name = QSPTools::GetCaseInsensitiveFilePath(m_path, QString(QByteArray::fromPercentEncoding(name.toString().toUtf8())));
  270. if(new_name.endsWith(".gif", Qt::CaseInsensitive) || new_name.endsWith(".mng", Qt::CaseInsensitive))
  271. {
  272. QMovie *movie = new QMovie(m_path + new_name);
  273. QLabel *videoL = new QLabel(this);
  274. if(movie->isValid())
  275. {
  276. videoL->setScaledContents(true);
  277. videoL->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
  278. videoL->setAttribute(Qt::WA_TransparentForMouseEvents);
  279. videoL->setMovie(movie);
  280. connect(movie, SIGNAL(started()), this, SLOT(resizeAnimations()));
  281. connect(movie, SIGNAL(finished()), this, SLOT(resizeAnimations()));
  282. movie->start();
  283. videoL->raise();
  284. videoL->show();
  285. videoL->setGeometry(0,0, movie->frameRect().size().width(), movie->frameRect().size().height());
  286. animations_gif.insert(QString(QByteArray::fromPercentEncoding(name.toString().toUtf8())), {movie, videoL});
  287. QImage image(movie->frameRect().size(), QImage::Format_ARGB32);
  288. image.fill(qRgba(0,0,0,0));
  289. return QVariant(image);
  290. }
  291. else
  292. {
  293. if(movie != 0)
  294. delete movie;
  295. if(videoL != 0)
  296. delete videoL;
  297. QImage image(1, 1, QImage::Format_ARGB32);
  298. image.fill(qRgba(0,0,0,0));
  299. return QVariant(image);
  300. }
  301. }
  302. if(new_name.endsWith(".mp4", Qt::CaseInsensitive) || new_name.endsWith(".avi", Qt::CaseInsensitive) || new_name.endsWith(".wmv", Qt::CaseInsensitive) || new_name.endsWith(".mkv", Qt::CaseInsensitive) || new_name.endsWith(".webm", Qt::CaseInsensitive) || new_name.endsWith(".m4v", Qt::CaseInsensitive) || new_name.endsWith(".ogv", Qt::CaseInsensitive))
  303. {
  304. if(!disableVideo)
  305. {
  306. VideoLabel *videoL = new VideoLabel(m_path, new_name, this);
  307. connect(videoL, SIGNAL(medialLoaded()), this, SLOT(resizeAnimations()));
  308. animations_video.insert(QString(QByteArray::fromPercentEncoding(name.toString().toUtf8())), { videoL });
  309. videoL->setGeometry(0,0, 0, 0);
  310. videoL->raise();
  311. videoL->show();
  312. QImage image(1,1, QImage::Format_ARGB32);
  313. image.fill(qRgba(0,0,0,0));
  314. return QVariant(image);
  315. }
  316. QImage image(1,1, QImage::Format_ARGB32);
  317. image.fill(qRgba(0,0,0,0));
  318. return QVariant(image);
  319. }
  320. if(type == QTextDocument::ImageResource)
  321. return QVariant(QImage(m_path + new_name));
  322. else
  323. return QTextBrowser::loadResource(type, QUrl(new_name));
  324. }
  325. void QspTextBox::resizeAnimations()
  326. {
  327. if(mutex.tryLock())
  328. {
  329. if(animations_gif.count() > 0 || animations_video.count() > 0)
  330. {
  331. QTextBlock bl = document()->begin();
  332. QTextCursor cursor(document());
  333. while(bl.isValid())
  334. {
  335. QTextBlock::iterator it;
  336. for(it = bl.begin(); !(it.atEnd()); ++it)
  337. {
  338. if(it.fragment().isValid())
  339. {
  340. if(it.fragment().charFormat().isImageFormat())
  341. {
  342. cursor.setPosition(it.fragment().position());
  343. if (animations_gif.contains(it.fragment().charFormat().toImageFormat().name()))
  344. {
  345. QRect curRect = cursorRect(cursor);
  346. if(it.fragment().charFormat().toImageFormat().width() > 0 && it.fragment().charFormat().toImageFormat().height() > 0)
  347. animations_gif[it.fragment().charFormat().toImageFormat().name()].movieLabel->setGeometry(curRect.x(),curRect.y(),it.fragment().charFormat().toImageFormat().width(),it.fragment().charFormat().toImageFormat().height());
  348. else
  349. animations_gif[it.fragment().charFormat().toImageFormat().name()].movieLabel->move(curRect.x(),curRect.y());
  350. }
  351. else
  352. if (animations_video.contains(it.fragment().charFormat().toImageFormat().name()))
  353. {
  354. if(animations_video[it.fragment().charFormat().toImageFormat().name()].videoLabel != 0)
  355. {
  356. if(animations_video[it.fragment().charFormat().toImageFormat().name()].videoLabel->hasFrame())
  357. {
  358. QRect curRect = cursorRect(cursor);
  359. if(it.fragment().charFormat().toImageFormat().width() > 0 && it.fragment().charFormat().toImageFormat().height() > 0)
  360. animations_video[it.fragment().charFormat().toImageFormat().name()].videoLabel->setGeometry(curRect.x(),curRect.y(),it.fragment().charFormat().toImageFormat().width(),it.fragment().charFormat().toImageFormat().height());
  361. else
  362. {
  363. animations_video[it.fragment().charFormat().toImageFormat().name()].videoLabel->move(curRect.x(),curRect.y());
  364. if(!animations_video[it.fragment().charFormat().toImageFormat().name()].videoLabel->resolution_set)
  365. {
  366. QTextImageFormat newImageFormat = it.fragment().charFormat().toImageFormat();
  367. newImageFormat.setWidth(animations_video[it.fragment().charFormat().toImageFormat().name()].videoLabel->getResolution().width());
  368. newImageFormat.setHeight(animations_video[it.fragment().charFormat().toImageFormat().name()].videoLabel->getResolution().height());
  369. if (newImageFormat.isValid())
  370. {
  371. QTextCursor cur(document());
  372. cur.setPosition(it.fragment().position());
  373. cur.setPosition(it.fragment().position() + it.fragment().length(), QTextCursor::KeepAnchor);
  374. cur.setCharFormat(newImageFormat);
  375. cur.setPosition(it.fragment().position());
  376. curRect = cursorRect(cur);
  377. }
  378. animations_video[it.fragment().charFormat().toImageFormat().name()].videoLabel->setGeometry(curRect.x(),curRect.y(), animations_video[it.fragment().charFormat().toImageFormat().name()].videoLabel->getResolution().width(), animations_video[it.fragment().charFormat().toImageFormat().name()].videoLabel->getResolution().height());
  379. animations_video[it.fragment().charFormat().toImageFormat().name()].videoLabel->resolution_set = true;
  380. }
  381. }
  382. }
  383. }
  384. }
  385. //QVariant image_data=document()->resource(QTextDocument::ImageResource, QUrl(image_name));
  386. //QImage picture=image_data.value<QImage>();
  387. }
  388. }
  389. }
  390. bl = bl.next();
  391. }
  392. }
  393. mutex.unlock();
  394. }
  395. }
  396. void QspTextBox::repaintAnimation()
  397. {
  398. viewport()->update();
  399. }
  400. #endif