MythTV  master
mythuiimage.cpp
Go to the documentation of this file.
1 
2 #include "mythuiimage.h"
3 
4 // C++
5 #include <cmath>
6 #include <cstdint>
7 #include <cstdlib>
8 #include <ctime>
9 #include <random>
10 #include <algorithm>
11 
12 // QT
13 #include <QCoreApplication>
14 #include <QDir>
15 #include <QDomDocument>
16 #include <QEvent>
17 #include <QFile>
18 #include <QImageReader>
19 #include <QReadWriteLock>
20 #include <QRunnable>
21 
22 // libmythbase
26 #ifdef _MSC_VER
27 # include "libmythbase/compat.h" // random
28 #endif
29 
30 // Mythui
31 #include "mythpainter.h"
32 #include "mythmainwindow.h"
33 #include "mythuihelper.h"
34 #include "mythscreentype.h"
35 
36 class ImageLoadThread;
37 
38 #define LOC QString("MythUIImage(0x%1): ").arg((uint64_t)this,0,16)
39 
41 
43 {
44  Copy(other);
45 }
46 
48 {
49  if (this == &other)
50  return *this;
51 
52  Copy(other);
53 
54  return *this;
55 }
56 
58 {
59  if (m_maskImage)
61 }
62 
63 // The m_maskImage field is assigned in the call to SetMaskImage().
64 //
65 // cppcheck-suppress operatorEqVarError
67 {
68  m_filename = other.m_filename;
69 
70  m_cropRect = other.m_cropRect;
71  m_forceSize = other.m_forceSize;
72 
76  m_isOriented = other.m_isOriented;
77 
84 
86 
88  m_isMasked = other.m_isMasked;
90 }
91 
93 {
94  if (image)
95  image->IncrRef();
96  if (m_maskImage)
98 
99  m_maskImage = image;
101 }
102 
107 {
108  public:
109  ImageLoader() = default;
110  ~ImageLoader() = default;
111 
112  static QHash<QString, const MythUIImage *> m_loadingImages;
113  static QMutex m_loadingImagesLock;
114  static QWaitCondition m_loadingImagesCond;
115 
116  static bool PreLoad(const QString &cacheKey, const MythUIImage *uitype)
117  {
118  m_loadingImagesLock.lock();
119 
120  // Check to see if the image is being loaded by us in another thread
121  if ((m_loadingImages.contains(cacheKey)) &&
122  (m_loadingImages[cacheKey] == uitype))
123  {
124  LOG(VB_GUI | VB_FILE, LOG_DEBUG,
125  QString("ImageLoader::PreLoad(%1), this "
126  "file is already being loaded by this same MythUIImage "
127  "in another thread.").arg(cacheKey));
128  m_loadingImagesLock.unlock();
129  return false;
130  }
131 
132  // Check to see if the exact same image is being loaded anywhere else
133  while (m_loadingImages.contains(cacheKey))
135 
136  m_loadingImages[cacheKey] = uitype;
137  m_loadingImagesLock.unlock();
138 
139  return true;
140  }
141 
142  static void PostLoad(const QString &cacheKey)
143  {
144  m_loadingImagesLock.lock();
145  m_loadingImages.remove(cacheKey);
146  m_loadingImagesCond.wakeAll();
147  m_loadingImagesLock.unlock();
148  }
149 
150  static bool SupportsAnimation(const QString &filename)
151  {
152  QString extension = filename.section('.', -1);
153  return !filename.startsWith("myth://") &&
154  (extension == "gif" ||
155  extension == "apng" ||
156  extension == "mng");
157  }
158 
163  static QString GenImageLabel(const ImageProperties &imProps)
164  {
165  QString imagelabel;
166  QString s_Attrib;
167 
168  if (imProps.m_isMasked)
169  s_Attrib = "masked";
170 
171  if (imProps.m_isReflected)
172  s_Attrib += "reflected";
173 
174  if (imProps.m_isGreyscale)
175  s_Attrib += "greyscale";
176 
177  if (imProps.m_isOriented)
178  {
179  s_Attrib += "orientation";
180  s_Attrib += QString("%1").arg(imProps.m_orientation);
181  }
182 
183  int w = -1;
184  int h = -1;
185  if (!imProps.m_forceSize.isNull())
186  {
187  if (imProps.m_forceSize.width() != -1)
188  w = imProps.m_forceSize.width();
189 
190  if (imProps.m_forceSize.height() != -1)
191  h = imProps.m_forceSize.height();
192  }
193 
194 
195  imagelabel = QString("%1-%2-%3x%4.png")
196  .arg(imProps.m_filename,
197  s_Attrib)
198  .arg(w)
199  .arg(h);
200  imagelabel.replace('/', '-');
201 #ifdef Q_OS_ANDROID
202  imagelabel.replace(':', '-');
203 #endif
204 
205  return imagelabel;
206  }
207 
208  static MythImage *LoadImage(MythPainter *painter,
209  // Must be a copy for thread safety
210  ImageProperties imProps,
211  ImageCacheMode cacheMode,
212  // Included only to check address, could be
213  // replaced by generating a unique value for
214  // each MythUIImage object?
215  const MythUIImage *parent,
216  bool &aborted,
217  MythImageReader *imageReader = nullptr)
218  {
219  QString cacheKey = GenImageLabel(imProps);
220  if (!PreLoad(cacheKey, parent))
221  {
222  aborted = true;
223  return nullptr;
224  }
225 
226  QString filename = imProps.m_filename;
227  MythImage *image = nullptr;
228 
229  bool bResize = false;
230  bool bFoundInCache = false;
231 
232  int w = -1;
233  int h = -1;
234 
235  if (!imProps.m_forceSize.isNull())
236  {
237  if (imProps.m_forceSize.width() != -1)
238  w = imProps.m_forceSize.width();
239 
240  if (imProps.m_forceSize.height() != -1)
241  h = imProps.m_forceSize.height();
242 
243  bResize = true;
244  }
245 
246  if (!imageReader)
247  {
248  image = GetMythUI()->LoadCacheImage(filename, cacheKey,
249  painter, cacheMode);
250  }
251 
252  if (image)
253  {
254  if (VERBOSE_LEVEL_CHECK(VB_GUI | VB_FILE, LOG_INFO))
255  {
256  image->IncrRef();
257  int cnt = image->DecrRef();
258  LOG(VB_GUI | VB_FILE, LOG_INFO,
259  QString("ImageLoader::LoadImage(%1) Found in cache, "
260  "RefCount = %2")
261  .arg(cacheKey).arg(cnt));
262  }
263 
264  if (imProps.m_isReflected)
265  image->setIsReflected(true);
266 
267  if (imProps.m_isOriented)
268  image->setIsOriented(true);
269 
270  bFoundInCache = true;
271  }
272  else
273  {
274  LOG(VB_GUI | VB_FILE, LOG_INFO,
275  QString("ImageLoader::LoadImage(%1) NOT Found in cache. "
276  "Loading Directly").arg(cacheKey));
277 
278  image = painter->GetFormatImage();
279  bool ok = false;
280 
281  if (imageReader)
282  ok = image->Load(imageReader);
283  else
284  ok = image->Load(filename);
285 
286  if (!ok)
287  {
288  image->DecrRef();
289  image = nullptr;
290  }
291  }
292 
293  if (image && image->isNull())
294  {
295  LOG(VB_GUI | VB_FILE, LOG_INFO,
296  QString("ImageLoader::LoadImage(%1) Image is NULL")
297  .arg(filename));
298 
299  image->DecrRef();
300  image = nullptr;
301  }
302 
303  if (image && !bFoundInCache)
304  {
305  if (imProps.m_isReflected)
306  {
307  image->Reflect(imProps.m_reflectAxis, imProps.m_reflectShear,
308  imProps.m_reflectScale, imProps.m_reflectLength,
309  imProps.m_reflectSpacing);
310  }
311 
312  if (imProps.m_isGreyscale)
313  image->ToGreyscale();
314 
315  if (imProps.m_isOriented)
316  image->Orientation(imProps.m_orientation);
317 
318  // Even if an explicit size wasn't defined this image may still need
319  // to be scaled because of a difference between the theme resolution
320  // and the screen resolution. We want to avoid scaling twice.
321  if (!bResize && imProps.m_isThemeImage)
322  {
323  float wmult = NAN; // Width multipler
324  float hmult = NAN; // Height multipler
325  GetMythMainWindow()->GetScalingFactors(wmult, hmult);
326  if (wmult != 1.0F || hmult != 1.0F)
327  {
328  w = image->size().width() * wmult;
329  h = image->size().height() * hmult;
330  bResize = true;
331  }
332  }
333 
334  if (bResize)
335  image->Resize(QSize(w, h), imProps.m_preserveAspect);
336 
337  if (imProps.m_isMasked)
338  {
339  MythImage *newMaskImage = painter->GetFormatImage();
340  if (newMaskImage->Load(imProps.GetMaskImageFilename()))
341  {
342  float wmult = NAN; // Width multipler
343  float hmult = NAN; // Height multipler
344  GetMythMainWindow()->GetScalingFactors(wmult, hmult);
345  if (wmult != 1.0F || hmult != 1.0F)
346  {
347  int width = newMaskImage->size().width() * wmult;
348  int height = newMaskImage->size().height() * hmult;
349  newMaskImage->Resize(QSize(width, height));
350  }
351 
352  imProps.SetMaskImage(newMaskImage);
353  }
354  else
355  imProps.SetMaskImage(nullptr);
356  newMaskImage->DecrRef();
357 
358  QRect imageArea = image->rect();
359  QRect maskArea = imProps.GetMaskImageRect();
360 
361  // Crop the mask to the image
362  int x = 0;
363  int y = 0;
364 
365  if (maskArea.width() > imageArea.width())
366  x = (maskArea.width() - imageArea.width()) / 2;
367 
368  if (maskArea.height() > imageArea.height())
369  y = (maskArea.height() - imageArea.height()) / 2;
370 
371  if (x > 0 || y > 0)
372  imageArea.translate(x, y);
373 
374  QImage mask = imProps.GetMaskImageSubset(imageArea);
375  image->setAlphaChannel(mask.convertToFormat(QImage::Format_Alpha8));
376  }
377 
378  if (!imageReader)
379  GetMythUI()->CacheImage(cacheKey, image);
380  }
381 
382  if (image)
383  image->SetChanged();
384 
385  PostLoad(cacheKey);
386 
387  return image;
388  }
389 
391  // Must be a copy for thread safety
392  const ImageProperties& imProps,
393  ImageCacheMode cacheMode,
394  // Included only to check address, could be
395  // replaced by generating a unique value for
396  // each MythUIImage object?
397  const MythUIImage *parent,
398  bool &aborted)
399  {
400  QString filename = QString("frame-%1-") + imProps.m_filename;
401  QString frameFilename;
402  int imageCount = 1;
403 
404  auto *imageReader = new MythImageReader(imProps.m_filename);
405  auto *images = new AnimationFrames();
406 
407  while (imageReader->canRead() && !aborted)
408  {
409  frameFilename = filename.arg(imageCount);
410 
411  ImageProperties frameProps = imProps;
412  frameProps.m_filename = frameFilename;
413 
414  MythImage *im = LoadImage(painter, frameProps, cacheMode, parent,
415  aborted, imageReader);
416 
417  if (!im)
418  aborted = true;
419 
420  images->append(AnimationFrame(im, std::chrono::milliseconds(imageReader->nextImageDelay())));
421  imageCount++;
422  }
423 
424  delete imageReader;
425 
426  return images;
427  }
428 
429 };
430 
431 QHash<QString, const MythUIImage *> ImageLoader::m_loadingImages;
433 QWaitCondition ImageLoader::m_loadingImagesCond;
434 
438 class ImageLoadEvent : public QEvent
439 {
440  public:
441  ImageLoadEvent(const MythUIImage *parent, MythImage *image,
442  QString basefile, QString filename,
443  int number, bool aborted)
444  : QEvent(kEventType),
445  m_parent(parent), m_image(image), m_basefile(std::move(basefile)),
446  m_filename(std::move(filename)), m_number(number),
447  m_aborted(aborted) { }
448 
450  QString basefile,
451  QString filename, bool aborted)
452  : QEvent(kEventType),
453  m_parent(parent), m_basefile(std::move(basefile)),
454  m_filename(std::move(filename)),
455  m_images(frames), m_aborted(aborted) { }
456 
457  const MythUIImage *GetParent() const { return m_parent; }
458  MythImage *GetImage() const { return m_image; }
459  QString GetBasefile() const { return m_basefile; }
460  QString GetFilename() const { return m_filename; }
461  int GetNumber() const { return m_number; }
463  bool GetAbortState() const { return m_aborted; }
464 
465  static Type kEventType;
466 
467  private:
468  const MythUIImage *m_parent {nullptr};
469  MythImage *m_image {nullptr};
470  QString m_basefile;
471  QString m_filename;
472  int m_number {0};
473 
474  // Animated Images
476 
477  // Image Load
478  bool m_aborted;
479 };
480 
481 QEvent::Type ImageLoadEvent::kEventType =
482  (QEvent::Type) QEvent::registerEventType();
483 
487 class ImageLoadThread : public QRunnable
488 {
489  public:
491  const ImageProperties &imProps, QString basefile,
492  int number, ImageCacheMode mode) :
493  m_parent(parent), m_painter(painter), m_imageProperties(imProps),
494  m_basefile(std::move(basefile)), m_number(number), m_cacheMode(mode)
495  {
496  }
497 
498  void run() override // QRunnable
499  {
500  bool aborted = false;
502 
503  // NOTE Do NOT use MythImageReader::supportsAnimation here, it defeats
504  // the point of caching remote images
506  {
507  AnimationFrames *frames =
511  aborted);
512 
513  if (frames && frames->count() > 1)
514  {
515  auto *le = new ImageLoadEvent(m_parent, frames, m_basefile,
517  aborted);
518  QCoreApplication::postEvent(m_parent, le);
519 
520  return;
521  }
522  delete frames;
523  }
524 
528  aborted);
529 
530  auto *le = new ImageLoadEvent(m_parent, image, m_basefile,
532  m_number, aborted);
533  QCoreApplication::postEvent(m_parent, le);
534  }
535 
536 private:
537  MythUIImage *m_parent {nullptr};
538  MythPainter *m_painter {nullptr};
540  QString m_basefile;
541  int m_number;
543 };
544 
547 {
548 public:
550  : m_parent(p) { }
551  ~MythUIImagePrivate() = default;
552 
553  MythUIImage *m_parent {nullptr};
554 
555  QReadWriteLock m_updateLock {QReadWriteLock::Recursive};
556 };
557 
559 
560 MythUIImage::MythUIImage(const QString &filepattern,
561  int low, int high, std::chrono::milliseconds delay,
562  MythUIType *parent, const QString &name)
563  : MythUIType(parent, name),
564  m_delay(delay),
565  m_lowNum(low),
566  m_highNum(high)
567 {
568  m_imageProperties.m_filename = filepattern;
569 
570  m_enableInitiator = true;
571 
572  d = new MythUIImagePrivate(this);
573  emit DependChanged(false);
574 }
575 
577  const QString &name)
578  : MythUIType(parent, name),
579  m_origFilename(filename),
580  m_delay(-1ms)
581 {
583 
584  m_enableInitiator = true;
585 
586  d = new MythUIImagePrivate(this);
587  emit DependChanged(false);
588 }
589 
590 MythUIImage::MythUIImage(MythUIType *parent, const QString &name)
591  : MythUIType(parent, name),
592  m_delay(-1ms)
593 {
594  m_enableInitiator = true;
595 
596  d = new MythUIImagePrivate(this);
597 }
598 
600 {
601  // Wait until all image loading threads are complete or bad things
602  // may happen if this MythUIImage disappears when a queued thread
603  // needs it.
604  if (m_runningThreads > 0)
605  {
607  }
608 
609  Clear();
610 
611  delete d;
612 }
613 
618 {
619  QWriteLocker updateLocker(&d->m_updateLock);
620  QMutexLocker locker(&m_imagesLock);
621 
622  while (!m_images.isEmpty())
623  {
624  QHash<int, MythImage *>::iterator it = m_images.begin();
625 
626  if (*it)
627  (*it)->DecrRef();
628 
629  m_images.remove(it.key());
630  }
631 
632  m_delays.clear();
633 
634  if (m_animatedImage)
635  {
636  m_lowNum = 0;
637  m_highNum = 0;
638  m_animatedImage = false;
639  }
640 }
641 
646 {
647  d->m_updateLock.lockForWrite();
648 
649  SetMinArea(MythRect());
650 
652  {
655 
656  if (m_animatedImage)
657  {
658  m_lowNum = 0;
659  m_highNum = 0;
660  m_animatedImage = false;
661  }
662  emit DependChanged(true);
663 
664  d->m_updateLock.unlock();
665  Load();
666  }
667  else
668  d->m_updateLock.unlock();
669 
671 }
672 
676 void MythUIImage::SetFilename(const QString &filename)
677 {
678  QWriteLocker updateLocker(&d->m_updateLock);
681  if (filename == m_origFilename)
682  emit DependChanged(true);
683  else
684  emit DependChanged(false);
685 }
686 
691 void MythUIImage::SetFilepattern(const QString &filepattern, int low,
692  int high)
693 {
694  QWriteLocker updateLocker(&d->m_updateLock);
696  m_imageProperties.m_filename = filepattern;
697  m_lowNum = low;
698  m_highNum = high;
699  if (filepattern == m_origFilename)
700  emit DependChanged(true);
701  else
702  emit DependChanged(false);
703 }
704 
708 void MythUIImage::SetImageCount(int low, int high)
709 {
710  QWriteLocker updateLocker(&d->m_updateLock);
711  m_lowNum = low;
712  m_highNum = high;
713 }
714 
718 void MythUIImage::SetDelay(std::chrono::milliseconds delay)
719 {
720  QWriteLocker updateLocker(&d->m_updateLock);
721  m_delay = delay;
722  m_lastDisplay = QTime::currentTime();
723  m_curPos = 0;
724 }
725 
729 void MythUIImage::SetDelays(const QVector<std::chrono::milliseconds>& delays)
730 {
731  QWriteLocker updateLocker(&d->m_updateLock);
732  QMutexLocker imageLocker(&m_imagesLock);
733 
734  for (std::chrono::milliseconds delay : qAsConst(delays))
735  m_delays[m_delays.size()] = delay;
736 
737  if (m_delay == -1ms)
738  m_delay = m_delays[0];
739 
740  m_lastDisplay = QTime::currentTime();
741  m_curPos = 0;
742 }
743 
749 {
750  d->m_updateLock.lockForWrite();
751 
752  if (!img)
753  {
754  d->m_updateLock.unlock();
755  Reset();
756  return;
757  }
758 
761 
762  img->IncrRef();
763 
764  QSize forceSize = m_imageProperties.m_forceSize;
765  if (!forceSize.isNull())
766  {
767  int w = (forceSize.width() <= 0) ? img->width() : forceSize.width();
768  int h = (forceSize.height() <= 0) ? img->height() : forceSize.height();
769  img->Resize(QSize(w, h), m_imageProperties.m_preserveAspect);
770  }
771 
773  {
779  }
780 
781  if (m_imageProperties.m_isGreyscale && !img->isGrayscale())
782  img->ToGreyscale();
783 
784  Clear();
785  m_delay = -1ms;
786 
789 
790  if (m_imageProperties.m_forceSize.isNull())
791  SetSize(img->size());
792 
793  m_imagesLock.lock();
794  m_images[0] = img;
795  m_delays.clear();
796  m_imagesLock.unlock();
797 
798  m_curPos = 0;
800  SetRedraw();
801 
802  d->m_updateLock.unlock();
803 }
804 
810 void MythUIImage::SetImages(QVector<MythImage *> *images)
811 {
812  Clear();
813 
814  QWriteLocker updateLocker(&d->m_updateLock);
815  QSize aSize = GetFullArea().size();
816 
818 
819  for (auto *im : qAsConst(*images))
820  {
821  if (!im)
822  {
823  QMutexLocker locker(&m_imagesLock);
824  m_images[m_images.size()] = im;
825  continue;
826  }
827 
828  im->IncrRef();
829 
830 
831  QSize forceSize = m_imageProperties.m_forceSize;
832  if (!forceSize.isNull())
833  {
834  int w = (forceSize.width() <= 0) ? im->width() : forceSize.width();
835  int h = (forceSize.height() <= 0) ? im->height() : forceSize.height();
836  im->Resize(QSize(w, h), m_imageProperties.m_preserveAspect);
837  }
838 
839  if (m_imageProperties.m_isReflected && !im->IsReflected())
840  {
841  im->Reflect(m_imageProperties.m_reflectAxis,
846  }
847 
848  if (m_imageProperties.m_isGreyscale && !im->isGrayscale())
849  im->ToGreyscale();
850 
851  if (m_imageProperties.m_isOriented && !im->IsOriented())
852  im->Orientation(m_imageProperties.m_orientation);
853 
854  m_imagesLock.lock();
855  m_images[m_images.size()] = im;
856  m_imagesLock.unlock();
857 
858  aSize = aSize.expandedTo(im->size());
859  }
860 
861  SetImageCount(1, m_images.size());
862 
863  if (m_imageProperties.m_forceSize.isNull())
864  SetSize(aSize);
865 
866  MythRect rect(GetFullArea());
867  rect.setSize(aSize);
868  SetMinArea(rect);
869 
870  m_curPos = 0;
871  m_animatedImage = true;
873  SetRedraw();
874 }
875 
877 {
878  QVector<std::chrono::milliseconds> delays;
879  QVector<MythImage *> images;
880 
881  for (const auto & frame : qAsConst(frames))
882  {
883  images.append(frame.first);
884  delays.append(frame.second);
885  }
886 
887  if (!images.empty())
888  {
889  SetImages(&images);
890 
891  if (m_delay < 0ms && !delays.empty())
892  SetDelays(delays);
893  }
894  else
895  Reset();
896 }
897 
901 void MythUIImage::ForceSize(const QSize size)
902 {
903  if (m_imageProperties.m_forceSize == size)
904  return;
905 
906  d->m_updateLock.lockForWrite();
908  d->m_updateLock.unlock();
909 
910  if (size.isEmpty())
911  return;
912 
914 
915  Load();
916 }
917 
921 void MythUIImage::SetOrientation(int orientation)
922 {
924  m_imageProperties.m_orientation = orientation;
925 }
926 
930 void MythUIImage::SetSize(int width, int height)
931 {
932  SetSize(QSize(width, height));
933 }
934 
938 void MythUIImage::SetSize(const QSize size)
939 {
940  QWriteLocker updateLocker(&d->m_updateLock);
941  MythUIType::SetSize(size);
942  m_needLoad = true;
943 }
944 
949 void MythUIImage::SetCropRect(int x, int y, int width, int height)
950 {
951  SetCropRect(MythRect(x, y, width, height));
952 }
953 
959 {
960  QWriteLocker updateLocker(&d->m_updateLock);
962  SetRedraw();
963 }
964 
968 bool MythUIImage::Load(bool allowLoadInBackground, bool forceStat)
969 {
970  d->m_updateLock.lockForRead();
971 
973 
974  QString bFilename = m_imageProperties.m_filename;
975 
976  d->m_updateLock.unlock();
977 
978  QString filename = bFilename;
979 
980  if (bFilename.isEmpty())
981  {
982  Clear();
983  SetMinArea(MythRect());
984  SetRedraw();
985 
986  return false;
987  }
988 
989  if (qEnvironmentVariableIsSet("DISABLETHREADEDMYTHUIIMAGE"))
990  allowLoadInBackground = false;
991 
992  // Don't clear the widget before we need to, otherwise it causes
993  // unsightly flashing. We exclude animations for now since that requires a
994  // deeper fix
995  bool isAnimation = (m_highNum != m_lowNum) || m_animatedImage;
996 
997  if (isAnimation)
998  Clear();
999 
1000  bool complete = true;
1001 
1002  QString imagelabel;
1003 
1004  int j = 0;
1005 
1006  for (int i = m_lowNum; i <= m_highNum && !m_animatedImage; i++)
1007  {
1008  if (!m_animatedImage && m_highNum != m_lowNum &&
1009  bFilename.contains("%1"))
1010  filename = bFilename.arg(i);
1011 
1013  imProps.m_filename = filename;
1014  imagelabel = ImageLoader::GenImageLabel(imProps);
1015 
1016  // Only load in the background if allowed and the image is
1017  // not already in our mem cache
1018  int cacheMode = kCacheIgnoreDisk;
1019 
1020  if (forceStat)
1021  cacheMode |= (int)kCacheForceStat;
1022 
1023  int cacheMode2 = kCacheNormal;
1024 
1025  if (forceStat)
1026  cacheMode2 |= (int)kCacheForceStat;
1027 
1028  bool do_background_load = false;
1029  if (allowLoadInBackground)
1030  {
1032  filename, imagelabel, GetPainter(),
1033  static_cast<ImageCacheMode>(cacheMode));
1034  if (img)
1035  img->DecrRef();
1036  else
1037  do_background_load = true;
1038  }
1039 
1040  if (do_background_load)
1041  {
1042  SetMinArea(MythRect());
1043  LOG(VB_GUI | VB_FILE, LOG_DEBUG, LOC +
1044  QString("Load(), spawning thread to load '%1'").arg(filename));
1045 
1046  m_runningThreads++;
1047  auto *bImgThread = new ImageLoadThread(this, GetPainter(),
1048  imProps, bFilename, i,
1049  static_cast<ImageCacheMode>(cacheMode2));
1050  GetMythUI()->GetImageThreadPool()->start(bImgThread, "ImageLoad");
1051  }
1052  else
1053  {
1054  if (!isAnimation && !GetMythUI()->IsImageInCache(imagelabel))
1055  Clear();
1056 
1057  // Perform a blocking load
1058  LOG(VB_GUI | VB_FILE, LOG_DEBUG, LOC +
1059  QString("Load(), loading '%1' in foreground").arg(filename));
1060  bool aborted = false;
1061 
1063  {
1064  AnimationFrames *myFrames =
1066  static_cast<ImageCacheMode>(cacheMode2),
1067  this, aborted);
1068 
1069  // TODO We might want to handle an abort here more gracefully
1070  if (aborted)
1071  {
1072  LOG(VB_GUI, LOG_DEBUG, QString("Aborted loading animated"
1073  "image %1 in foreground")
1074  .arg(filename));
1075  }
1076 
1077  SetAnimationFrames(*myFrames);
1078 
1079  delete myFrames;
1080  }
1081  else
1082  {
1083  MythImage *image = nullptr;
1084 
1086  imProps,
1087  static_cast<ImageCacheMode>(cacheMode2),
1088  this, aborted);
1089 
1090  // TODO We might want to handle an abort here more gracefully
1091  if (aborted)
1092  {
1093  LOG(VB_GUI, LOG_DEBUG, QString("Aborted loading animated"
1094  "image %1 in foreground")
1095  .arg(filename));
1096  }
1097 
1098  if (image)
1099  {
1100  if (m_imageProperties.m_forceSize.isNull())
1101  SetSize(image->size());
1102 
1103  MythRect rect(GetFullArea());
1104  rect.setSize(image->size());
1105  SetMinArea(rect);
1106 
1107  m_imagesLock.lock();
1108  m_images[j] = image;
1109  m_imagesLock.unlock();
1110 
1111  SetRedraw();
1112  d->m_updateLock.lockForWrite();
1113  m_lastDisplay = QTime::currentTime();
1114  d->m_updateLock.unlock();
1115  }
1116  else
1117  {
1118  Reset();
1119 
1120  m_imagesLock.lock();
1121  m_images[j] = nullptr;
1122  m_imagesLock.unlock();
1123  }
1124  }
1125  }
1126 
1127  ++j;
1128 
1129  // Load is complete if no image is loading in background
1130  complete &= !do_background_load;
1131  }
1132 
1133  if (complete)
1134  emit LoadComplete();
1135 
1136  return true;
1137 }
1138 
1143 {
1144  d->m_updateLock.lockForWrite();
1145 
1146  auto delay = -1ms;
1147 
1148  if (m_delays.contains(m_curPos))
1149  delay = m_delays[m_curPos];
1150  else if (m_delay > 0ms)
1151  delay = m_delay;
1152 
1153  if (delay > 0ms &&
1154  abs(m_lastDisplay.msecsTo(QTime::currentTime())) > delay.count())
1155  {
1157  {
1158  FindRandomImage();
1159  d->m_updateLock.unlock();
1160  Load();
1161  d->m_updateLock.lockForWrite();
1162  }
1163  else
1164  {
1165  m_imagesLock.lock();
1166 
1168  {
1169  ++m_curPos;
1170 
1171  if (m_curPos >= (uint)m_images.size())
1172  m_curPos = 0;
1173  }
1174  else if (m_animationCycle == kCycleReverse)
1175  {
1176  if ((m_curPos + 1) >= (uint)m_images.size())
1177  {
1178  m_animationReverse = true;
1179  }
1180  else if (m_curPos == 0)
1181  {
1182  m_animationReverse = false;
1183  }
1184 
1185  if (m_animationReverse)
1186  --m_curPos;
1187  else
1188  ++m_curPos;
1189  }
1190 
1191  m_imagesLock.unlock();
1192 
1193  SetRedraw();
1194  }
1195 
1196  m_lastDisplay = QTime::currentTime();
1197  }
1198 
1200 
1201  d->m_updateLock.unlock();
1202 }
1203 
1207 void MythUIImage::DrawSelf(MythPainter *p, int xoffset, int yoffset,
1208  int alphaMod, QRect clipRect)
1209 {
1210  m_imagesLock.lock();
1211 
1212  if (!m_images.empty())
1213  {
1214  d->m_updateLock.lockForWrite();
1215 
1216  if (m_curPos >= (uint)m_images.size())
1217  m_curPos = 0;
1218 
1219  if (!m_images[m_curPos])
1220  {
1221  unsigned int origPos = m_curPos;
1222  m_curPos++;
1223 
1224  while (!m_images[m_curPos] && m_curPos != origPos)
1225  {
1226  m_curPos++;
1227 
1228  if (m_curPos >= (uint)m_images.size())
1229  m_curPos = 0;
1230  }
1231  }
1232 
1233  QRect area = GetArea().toQRect();
1234  area.translate(xoffset, yoffset);
1235 
1236  int alpha = CalcAlpha(alphaMod);
1237 
1238  MythImage *currentImage = m_images[m_curPos];
1239 
1240  if (currentImage)
1241  currentImage->IncrRef();
1242 
1243  m_imagesLock.unlock();
1244  d->m_updateLock.unlock();
1245 
1246  if (!currentImage)
1247  return;
1248 
1249  d->m_updateLock.lockForRead();
1250 
1251  QRect currentImageArea = currentImage->rect();
1252 
1253  if (!m_imageProperties.m_forceSize.isNull())
1254  area.setSize(area.size().expandedTo(currentImage->size()));
1255 
1256  // Centre image in available space, accounting for zoom
1257  int x = 0;
1258  int y = 0;
1259  QRect visibleImage = m_effects.GetExtent(currentImageArea.size());
1260 
1261  if (area.width() > visibleImage.width())
1262  x = area.width() / 2 + visibleImage.topLeft().x();
1263 
1264  if (area.height() > visibleImage.height())
1265  y = area.height() / 2 + visibleImage.topLeft().y();
1266 
1267  if ((x > 0 || y > 0))
1268  area.translate(x, y);
1269 
1270  QRect srcRect;
1272 
1273  if (!m_imageProperties.m_cropRect.isEmpty())
1274  srcRect = m_imageProperties.m_cropRect.toQRect();
1275  else
1276  srcRect = currentImageArea;
1277 
1278  p->SetClipRect(clipRect);
1279  p->DrawImage(area, currentImage, srcRect, alpha);
1280  currentImage->DecrRef();
1281  d->m_updateLock.unlock();
1282  }
1283  else
1284  m_imagesLock.unlock();
1285 }
1286 
1291  const QString &filename, QDomElement &element, bool showWarnings)
1292 {
1293  QWriteLocker updateLocker(&d->m_updateLock);
1294 
1295  if (element.tagName() == "filename")
1296  {
1297  m_imageProperties.m_isThemeImage = true; // This is an image distributed with the theme
1299 
1300  if (m_imageProperties.m_filename.endsWith('/'))
1301  {
1302  m_showingRandomImage = true;
1304 
1305  FindRandomImage();
1306  }
1307  }
1308  else if (element.tagName() == "filepattern")
1309  {
1310  m_imageProperties.m_isThemeImage = true; // This is an image distributed with the theme
1312  QString tmp = element.attribute("low");
1313 
1314  if (!tmp.isEmpty())
1315  m_lowNum = tmp.toInt();
1316 
1317  tmp = element.attribute("high");
1318 
1319  if (!tmp.isEmpty())
1320  m_highNum = tmp.toInt();
1321 
1322  tmp = element.attribute("cycle", "start");
1323 
1324  if (tmp == "reverse")
1326  }
1327  else if (element.tagName() == "area")
1328  {
1329  SetArea(parseRect(element));
1331  }
1332  else if (element.tagName() == "preserveaspect")
1334  else if (element.tagName() == "crop")
1336  else if (element.tagName() == "delay")
1337  {
1338  QString value = getFirstText(element);
1339 
1340  if (value.contains(","))
1341  {
1342  QVector<std::chrono::milliseconds> delays;
1343  QStringList tokens = value.split(",");
1344  for (const auto & token : qAsConst(tokens))
1345  {
1346  if (token.isEmpty())
1347  {
1348  if (!delays.empty())
1349  delays.append(delays[delays.size()-1]);
1350  else
1351  delays.append(0ms); // Default delay before first image
1352  }
1353  else
1354  {
1355  delays.append(std::chrono::milliseconds(token.toInt()));
1356  }
1357  }
1358 
1359  if (!delays.empty())
1360  {
1361  m_delay = delays[0];
1362  SetDelays(delays);
1363  }
1364  }
1365  else
1366  {
1367  m_delay = std::chrono::milliseconds(value.toInt());
1368  }
1369  }
1370  else if (element.tagName() == "reflection")
1371  {
1373  QString tmp = element.attribute("axis");
1374 
1375  if (!tmp.isEmpty())
1376  {
1377  if (tmp.toLower() == "horizontal")
1379  else
1381  }
1382 
1383  tmp = element.attribute("shear");
1384 
1385  if (!tmp.isEmpty())
1387 
1388  tmp = element.attribute("scale");
1389 
1390  if (!tmp.isEmpty())
1392 
1393  tmp = element.attribute("length");
1394 
1395  if (!tmp.isEmpty())
1397 
1398  tmp = element.attribute("spacing");
1399 
1400  if (!tmp.isEmpty())
1402  }
1403  else if (element.tagName() == "mask")
1404  {
1407  }
1408  else if (element.tagName() == "grayscale" ||
1409  element.tagName() == "greyscale")
1410  {
1412  }
1413  else
1414  {
1415  return MythUIType::ParseElement(filename, element, showWarnings);
1416  }
1417 
1418  m_needLoad = true;
1419 
1420  if (m_parent && m_parent->IsDeferredLoading(true))
1421  m_needLoad = false;
1422 
1423  return true;
1424 }
1425 
1430 {
1431  d->m_updateLock.lockForWrite();
1432  auto *im = dynamic_cast<MythUIImage *>(base);
1433  if (!im)
1434  {
1435  LOG(VB_GENERAL, LOG_ERR,
1436  QString("'%1' (%2) ERROR, bad parsing '%3' (%4)")
1437  .arg(objectName(), GetXMLLocation(),
1438  base->objectName(), base->GetXMLLocation()));
1439  d->m_updateLock.unlock();
1440  return;
1441  }
1442 
1443  m_origFilename = im->m_origFilename;
1444 
1445  m_delay = im->m_delay;
1446  m_lowNum = im->m_lowNum;
1447  m_highNum = im->m_highNum;
1448 
1449  m_lastDisplay = QTime::currentTime();
1450  m_curPos = 0;
1451 
1452  m_imageProperties = im->m_imageProperties;
1453 
1454  m_animationCycle = im->m_animationCycle;
1455  m_animatedImage = im->m_animatedImage;
1456 
1457  m_showingRandomImage = im->m_showingRandomImage;
1458  m_imageDirectory = im->m_imageDirectory;
1459 
1460  MythUIType::CopyFrom(base);
1461 
1462  // We need to update forceSize in case the parent area has changed
1463  // however we only want to set forceSize if it was previously in use
1464  if (!m_imageProperties.m_forceSize.isNull())
1466 
1467  m_needLoad = im->m_needLoad;
1468 
1469  d->m_updateLock.unlock();
1470 
1471  d->m_updateLock.lockForRead();
1472 
1473  if (m_needLoad)
1474  {
1475  d->m_updateLock.unlock();
1476  Load();
1477  }
1478  else
1479  d->m_updateLock.unlock();
1480 }
1481 
1486 {
1487  QReadLocker updateLocker(&d->m_updateLock);
1488  auto *im = new MythUIImage(parent, objectName());
1489  im->CopyFrom(this);
1490 }
1491 
1496 {
1497  d->m_updateLock.lockForRead();
1498 
1499  if (m_needLoad)
1500  {
1501  d->m_updateLock.unlock();
1502  Load();
1503  }
1504  else
1505  d->m_updateLock.unlock();
1506 
1508 }
1509 
1514 {
1515  d->m_updateLock.lockForWrite();
1516 
1517  if (m_needLoad)
1518  {
1519  d->m_updateLock.unlock();
1520  return;
1521  }
1522 
1523  m_needLoad = true;
1524  d->m_updateLock.unlock();
1525 
1526  Load(false);
1527 
1529 }
1530 
1534 void MythUIImage::customEvent(QEvent *event)
1535 {
1536  if (event->type() == ImageLoadEvent::kEventType)
1537  {
1538  auto * le = dynamic_cast<ImageLoadEvent *>(event);
1539  if (!le || le->GetParent() != this)
1540  return;
1541 
1542  MythImage *image = le->GetImage();
1543  int number = le->GetNumber();
1544  QString filename = le->GetFilename();
1545  AnimationFrames *animationFrames = le->GetAnimationFrames();
1546  bool aborted = le->GetAbortState();
1547 
1548  m_runningThreads--;
1549 
1550  d->m_updateLock.lockForRead();
1551  QString propFilename = m_imageProperties.m_filename;
1552  d->m_updateLock.unlock();
1553 
1554  // 1) We aborted loading the image for some reason (e.g. two requests
1555  // for same image)
1556  // 2) Filename changed since we started this image, so abort to avoid
1557  // rendering two different images in quick succession which causes
1558  // unsightly flickering
1559  if (aborted || (le->GetBasefile() != propFilename))
1560  {
1561  if (aborted)
1562  LOG(VB_GUI, LOG_DEBUG, QString("Aborted loading image %1")
1563  .arg(filename));
1564 
1565  if (image)
1566  image->DecrRef();
1567 
1568  if (animationFrames)
1569  {
1570  for (const auto & frame : qAsConst(*animationFrames))
1571  {
1572  MythImage *im = frame.first;
1573  if (im)
1574  im->DecrRef();
1575  }
1576 
1577  delete animationFrames;
1578  }
1579  }
1580  else if (animationFrames)
1581  {
1582  SetAnimationFrames(*animationFrames);
1583 
1584  delete animationFrames;
1585  }
1586  else if (image)
1587  {
1588  // We don't clear until we have the new image ready to display to
1589  // avoid unsightly flashing. This isn't currently supported for
1590  // animations.
1591  if ((m_highNum == m_lowNum) && !m_animatedImage)
1592  Clear();
1593 
1594  d->m_updateLock.lockForWrite();
1595 
1596  if (m_imageProperties.m_forceSize.isNull())
1597  SetSize(image->size());
1598 
1599  MythRect rect(GetFullArea());
1600  rect.setSize(image->size());
1601  SetMinArea(rect);
1602 
1603  d->m_updateLock.unlock();
1604 
1605  m_imagesLock.lock();
1606 
1607  if (m_images[number])
1608  {
1609  // If we got to this point, it means this same MythUIImage
1610  // was told to reload the same image, so we use the newest
1611  // copy of the image.
1612  m_images[number]->DecrRef(); // delete the original
1613  }
1614 
1615  m_images[number] = image;
1616  m_imagesLock.unlock();
1617 
1618  SetRedraw();
1619 
1620  d->m_updateLock.lockForWrite();
1621  m_lastDisplay = QTime::currentTime();
1622  d->m_updateLock.unlock();
1623  }
1624  else
1625  {
1626  // No Images were loaded, so trigger Reset to default
1627  Reset();
1628  }
1629 
1630  // NOLINTNEXTLINE(readability-misleading-indentation)
1631  emit LoadComplete();
1632  }
1633 }
1634 
1636 {
1637  QString randFile;
1638 
1639  // find and save the list of available images
1640  if (m_imageList.isEmpty())
1641  {
1642  QDir imageDir(m_imageDirectory);
1643 
1644  if (!imageDir.exists())
1645  {
1646  QString themeDir = GetMythUI()->GetThemeDir() + '/';
1647  imageDir.setPath(themeDir + m_imageDirectory);
1648  }
1649 
1650  QStringList imageTypes;
1651 
1652  QList< QByteArray > exts = QImageReader::supportedImageFormats();
1653  for (const auto & ext : qAsConst(exts))
1654  {
1655  imageTypes.append(QString("*.").append(ext));
1656  }
1657 
1658  imageDir.setNameFilters(imageTypes);
1659 
1660  m_imageList = imageDir.entryList();
1661 
1662  if (m_imageList.empty())
1663  {
1665  return;
1666  }
1667 
1668  // randomly shuffle the images
1669  std::random_device rd;
1670  std::mt19937 g(rd());
1671  std::shuffle(m_imageList.begin(), m_imageList.end(), g);
1672  m_imageListIndex = 0;
1673  randFile = QString("%1%2").arg(m_imageDirectory, m_imageList.at(m_imageListIndex));
1674  }
1675  else
1676  {
1677  if (!m_imageList.empty())
1678  {
1679  m_imageListIndex++;
1680 
1681  // if we are at the last image in the list re-shuffle the list and start from the beginning
1682  if (m_imageListIndex == m_imageList.size())
1683  {
1684  std::random_device rd;
1685  std::mt19937 g(rd());
1686  std::shuffle(m_imageList.begin(), m_imageList.end(), g);
1687  m_imageListIndex = 0;
1688  }
1689 
1690  // make sure we don't show the same image again in the unlikely event the re-shuffle shows the same image again
1691  if (m_imageList.at(m_imageListIndex) == m_origFilename && m_imageList.size() > 1)
1692  m_imageListIndex++;
1693 
1694  randFile = QString("%1%2").arg(m_imageDirectory, m_imageList.at(m_imageListIndex));
1695  }
1696  }
1697 
1699 }
MythUIType::m_area
MythRect m_area
Definition: mythuitype.h:274
MythUIImage::MythUIImagePrivate
friend class MythUIImagePrivate
Definition: mythuiimage.h:199
MythUIImage::SetDelays
void SetDelays(const QVector< std::chrono::milliseconds > &delays)
Sets the delays between each image in an animation.
Definition: mythuiimage.cpp:729
MythUIImage::m_origFilename
QString m_origFilename
Definition: mythuiimage.h:168
ImageLoadThread::m_cacheMode
ImageCacheMode m_cacheMode
Definition: mythuiimage.cpp:542
ImageLoadThread::m_basefile
QString m_basefile
Definition: mythuiimage.cpp:540
MythUIImage::m_imagesLock
QMutex m_imagesLock
Definition: mythuiimage.h:172
ImageProperties::SetMaskImage
void SetMaskImage(MythImage *image)
Definition: mythuiimage.cpp:92
ImageLoadEvent::GetAbortState
bool GetAbortState() const
Definition: mythuiimage.cpp:463
MythUIImage
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
ImageLoadThread::ImageLoadThread
ImageLoadThread(MythUIImage *parent, MythPainter *painter, const ImageProperties &imProps, QString basefile, int number, ImageCacheMode mode)
Definition: mythuiimage.cpp:490
MythImage::Load
bool Load(MythImageReader *reader)
Definition: mythimage.cpp:276
ImageProperties::m_cropRect
MythRect m_cropRect
Definition: mythuiimage.h:60
MythUIImage::m_images
QHash< int, MythImage * > m_images
Definition: mythuiimage.h:170
MythUIImagePrivate::m_updateLock
QReadWriteLock m_updateLock
Definition: mythuiimage.cpp:555
ImageLoadEvent::GetImage
MythImage * GetImage() const
Definition: mythuiimage.cpp:458
MythUIType::GetFullArea
virtual MythRect GetFullArea(void) const
Definition: mythuitype.cpp:892
MythUIType::CalcAlpha
int CalcAlpha(int alphamod) const
Definition: mythuitype.cpp:473
MythRect::toQRect
QRect toQRect(void) const
Definition: mythrect.cpp:405
ImageProperties::m_reflectSpacing
int m_reflectSpacing
Definition: mythuiimage.h:73
MythUIImage::m_imageListIndex
int m_imageListIndex
Definition: mythuiimage.h:190
ImageProperties::m_isThemeImage
bool m_isThemeImage
Definition: mythuiimage.h:77
MythUIImagePrivate::m_parent
MythUIImage * m_parent
Definition: mythuiimage.cpp:553
MythImage::Reflect
void Reflect(ReflectAxis axis, int shear, int scale, int length, int spacing=0)
Definition: mythimage.cpp:165
ImageLoadEvent
Definition: mythuiimage.cpp:438
MythUIImage::MythUIImage
MythUIImage(const QString &filepattern, int low, int high, std::chrono::milliseconds delay, MythUIType *parent, const QString &name)
Definition: mythuiimage.cpp:560
MythUIImage::Load
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
Definition: mythuiimage.cpp:968
MythPainter::GetFormatImage
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
Definition: mythpainter.cpp:540
ImageLoader::m_loadingImages
static QHash< QString, const MythUIImage * > m_loadingImages
Definition: mythuiimage.cpp:112
ImageLoader::PostLoad
static void PostLoad(const QString &cacheKey)
Definition: mythuiimage.cpp:142
MythUIImage::m_delays
QHash< int, std::chrono::milliseconds > m_delays
Definition: mythuiimage.h:171
ImageLoader::m_loadingImagesLock
static QMutex m_loadingImagesLock
Definition: mythuiimage.cpp:113
VERBOSE_LEVEL_CHECK
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
MythUIType::GetPainter
virtual MythPainter * GetPainter(void)
Definition: mythuitype.cpp:1421
ImageProperties::m_reflectAxis
ReflectAxis m_reflectAxis
Definition: mythuiimage.h:69
ImageLoader::GenImageLabel
static QString GenImageLabel(const ImageProperties &imProps)
Generates a unique identifying string for this image which is used as a key in the image cache.
Definition: mythuiimage.cpp:163
ImageLoadEvent::ImageLoadEvent
ImageLoadEvent(const MythUIImage *parent, AnimationFrames *frames, QString basefile, QString filename, bool aborted)
Definition: mythuiimage.cpp:449
MythUIImage::customEvent
void customEvent(QEvent *event) override
Definition: mythuiimage.cpp:1534
ImageLoadThread::m_parent
MythUIImage * m_parent
Definition: mythuiimage.cpp:537
MythUIImage::SetOrientation
void SetOrientation(int orientation)
Saves the exif orientation value of the first image in the widget.
Definition: mythuiimage.cpp:921
ImageProperties::m_reflectScale
int m_reflectScale
Definition: mythuiimage.h:70
MythUIType::SetArea
virtual void SetArea(const MythRect &rect)
Definition: mythuitype.cpp:609
ImageLoadEvent::GetBasefile
QString GetBasefile() const
Definition: mythuiimage.cpp:459
ImageProperties::GetMaskImageSubset
QImage GetMaskImageSubset(QRect imageArea)
Definition: mythuiimage.h:48
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
ImageLoadEvent::GetAnimationFrames
AnimationFrames * GetAnimationFrames() const
Definition: mythuiimage.cpp:462
ImageLoadThread::m_number
int m_number
Definition: mythuiimage.cpp:541
MythUIImage::LoadNow
void LoadNow(void) override
Cause images in this and child widgets to be loaded.
Definition: mythuiimage.cpp:1513
MythUIImage::SetFilepattern
void SetFilepattern(const QString &filepattern, int low, int high)
Must be followed by a call to Load() to load the image.
Definition: mythuiimage.cpp:691
MythUIImage::Clear
void Clear(void)
Remove all images from the widget.
Definition: mythuiimage.cpp:617
ImageProperties::m_orientation
int m_orientation
Definition: mythuiimage.h:75
MythUIImage::Reset
void Reset(void) override
Reset the image back to the default defined in the theme.
Definition: mythuiimage.cpp:645
MythRect
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:17
MythUIType::Pulse
virtual void Pulse(void)
Pulse is called 70 times a second to trigger a single frame of an animation.
Definition: mythuitype.cpp:455
ImageProperties
Definition: mythuiimage.h:23
mythuiimage.h
AnimationFrames
QVector< AnimationFrame > AnimationFrames
Definition: mythuiimage.h:88
ImageProperties::m_forceSize
QSize m_forceSize
Definition: mythuiimage.h:61
ImageProperties::m_preserveAspect
bool m_preserveAspect
Definition: mythuiimage.h:63
ImageLoader::m_loadingImagesCond
static QWaitCondition m_loadingImagesCond
Definition: mythuiimage.cpp:114
ImageProperties::m_filename
QString m_filename
Definition: mythuiimage.h:58
MythUIImage::m_showingRandomImage
bool m_showingRandomImage
Definition: mythuiimage.h:187
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
MythUIType::GetArea
virtual MythRect GetArea(void) const
If the object has a minimum area defined, return it, other wise return the default area.
Definition: mythuitype.cpp:884
MythImage::setIsOriented
void setIsOriented(bool oriented)
Definition: mythimage.h:94
MythUIImage::m_lowNum
int m_lowNum
Definition: mythuiimage.h:175
MythUIType::m_effects
UIEffects m_effects
Definition: mythuitype.h:281
MythUIImage::m_delay
std::chrono::milliseconds m_delay
Definition: mythuiimage.h:174
MythUIImage::SetCropRect
void SetCropRect(int x, int y, int width, int height)
Crop the image using the given rectangle, useful for removing unsightly edges from imported images or...
Definition: mythuiimage.cpp:949
MythImage::IsReflected
bool IsReflected() const
Definition: mythimage.h:54
ImageProperties::m_maskImage
MythImage * m_maskImage
Definition: mythuiimage.h:83
ImageProperties::m_maskImageFilename
QString m_maskImageFilename
Definition: mythuiimage.h:84
ReflectAxis::Horizontal
@ Horizontal
ImageLoader::PreLoad
static bool PreLoad(const QString &cacheKey, const MythUIImage *uitype)
Definition: mythuiimage.cpp:116
mythlogging.h
MythUIImage::m_imageList
QStringList m_imageList
Definition: mythuiimage.h:189
MythUIImage::LoadComplete
void LoadComplete()
ImageProperties::operator=
ImageProperties & operator=(const ImageProperties &other)
Definition: mythuiimage.cpp:47
MythUIImage::m_curPos
unsigned int m_curPos
Definition: mythuiimage.h:178
MythUIImage::SetSize
void SetSize(int width, int height)
Set the size of the widget.
Definition: mythuiimage.cpp:930
MythUIType::GetXMLLocation
QString GetXMLLocation(void) const
Definition: mythuitype.h:180
ImageCacheMode
ImageCacheMode
Definition: mythuithemecache.h:16
MThreadPool::waitForDone
void waitForDone(void)
Definition: mthreadpool.cpp:574
MythUIType::SetMinArea
virtual void SetMinArea(const MythRect &rect)
Set the minimum area based on the given size.
Definition: mythuitype.cpp:819
MythUIType::DependChanged
void DependChanged(bool isDefault)
hardwareprofile.config.p
p
Definition: config.py:33
MythUIImagePrivate::~MythUIImagePrivate
~MythUIImagePrivate()=default
MythUIImage::m_runningThreads
int m_runningThreads
Definition: mythuiimage.h:185
MythUIImage::SetAnimationFrames
void SetAnimationFrames(const AnimationFrames &frames)
Definition: mythuiimage.cpp:876
kCacheNormal
@ kCacheNormal
Definition: mythuithemecache.h:18
kCacheForceStat
@ kCacheForceStat
Definition: mythuithemecache.h:21
MythUIThemeHelper::GetThemeDir
QString GetThemeDir()
Definition: mythuithemehelper.cpp:141
compat.h
ImageLoadEvent::m_images
AnimationFrames * m_images
Definition: mythuiimage.cpp:475
MythUIImage::d
MythUIImagePrivate * d
Definition: mythuiimage.h:192
XMLParseBase::getFirstText
static QString getFirstText(QDomElement &element)
Definition: xmlparsebase.cpp:52
MythImage::DecrRef
int DecrRef(void) override
Decrements reference count and deletes on 0.
Definition: mythimage.cpp:52
MythUIType::m_parent
MythUIType * m_parent
Definition: mythuitype.h:294
MythRect::CalculateArea
void CalculateArea(QRect parentArea)
Definition: mythrect.cpp:64
MythUIImage::ImageLoadThread
friend class ImageLoadThread
Definition: mythuiimage.h:205
MythUIImage::m_animationReverse
bool m_animationReverse
Definition: mythuiimage.h:196
MythUIImage::m_highNum
int m_highNum
Definition: mythuiimage.h:176
MythImage::setIsReflected
void setIsReflected(bool reflected)
Definition: mythimage.h:93
MythUIType::CopyFrom
virtual void CopyFrom(MythUIType *base)
Copy this widgets state from another.
Definition: mythuitype.cpp:1174
ImageProperties::m_isOriented
bool m_isOriented
Definition: mythuiimage.h:67
ImageProperties::Copy
void Copy(const ImageProperties &other)
Definition: mythuiimage.cpp:66
MythUIImage::m_imageDirectory
QString m_imageDirectory
Definition: mythuiimage.h:188
mythpainter.h
MythUIImage::SetDelay
void SetDelay(std::chrono::milliseconds delayms)
Set the delay between each image in an animation.
Definition: mythuiimage.cpp:718
MythUIThemeCache::LoadCacheImage
MythImage * LoadCacheImage(QString File, const QString &Label, MythPainter *Painter, ImageCacheMode cacheMode=kCacheNormal)
Definition: mythuithemecache.cpp:257
MythUIImage::kCycleStart
@ kCycleStart
Definition: mythuiimage.h:194
XMLParseBase::parseRect
static MythRect parseRect(const QString &text, bool normalize=true)
Definition: xmlparsebase.cpp:136
MythImage::SetChanged
virtual void SetChanged(bool change=true)
Definition: mythimage.h:50
MythUIImage::CreateCopy
void CreateCopy(MythUIType *parent) override
Copy the state of this widget to the one given, it must be of the same type.
Definition: mythuiimage.cpp:1485
ImageProperties::SetMaskImageFilename
void SetMaskImageFilename(const QString &filename)
Definition: mythuiimage.h:33
uint
unsigned int uint
Definition: compat.h:81
ImageLoader::SupportsAnimation
static bool SupportsAnimation(const QString &filename)
Definition: mythuiimage.cpp:150
kCacheIgnoreDisk
@ kCacheIgnoreDisk
Definition: mythuithemecache.h:19
MythUIImage::ParseElement
bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings) override
Parse the xml definition of this widget setting the state of the object accordingly.
Definition: mythuiimage.cpp:1290
ImageProperties::m_isMasked
bool m_isMasked
Definition: mythuiimage.h:66
ImageLoadEvent::m_filename
QString m_filename
Definition: mythuiimage.cpp:471
MythUIImage::CopyFrom
void CopyFrom(MythUIType *base) override
Copy this widgets state from another.
Definition: mythuiimage.cpp:1429
MythUIImage::m_lastDisplay
QTime m_lastDisplay
Definition: mythuiimage.h:179
ImageLoadEvent::m_parent
const MythUIImage * m_parent
Definition: mythuiimage.cpp:468
MythUIType::Reset
virtual void Reset(void)
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitype.cpp:72
ImageLoader::LoadAnimatedImage
static AnimationFrames * LoadAnimatedImage(MythPainter *painter, const ImageProperties &imProps, ImageCacheMode cacheMode, const MythUIImage *parent, bool &aborted)
Definition: mythuiimage.cpp:390
MythUIType
The base class on which all widgets and screens are based.
Definition: mythuitype.h:85
MythImage::Orientation
void Orientation(int orientation)
Changes the orientation angle of the image according to the exif rotation values.
Definition: mythimage.cpp:134
MythUIType::IsDeferredLoading
bool IsDeferredLoading(bool recurse=false) const
Definition: mythuitype.cpp:1387
MythUIImage::SetImageCount
void SetImageCount(int low, int high)
Set the integer range for an animated image pattern.
Definition: mythuiimage.cpp:708
ImageLoadThread::m_imageProperties
ImageProperties m_imageProperties
Definition: mythuiimage.cpp:539
mthreadpool.h
ImageProperties::m_reflectShear
int m_reflectShear
Definition: mythuiimage.h:72
ImageLoadEvent::GetFilename
QString GetFilename() const
Definition: mythuiimage.cpp:460
mythuihelper.h
ImageLoadThread::run
void run() override
Definition: mythuiimage.cpp:498
MythImage::IncrRef
int IncrRef(void) override
Increments reference count.
Definition: mythimage.cpp:44
MythImage::IsOriented
bool IsOriented() const
Definition: mythimage.h:55
ImageLoadEvent::m_number
int m_number
Definition: mythuiimage.cpp:472
MythUIImage::SetImages
void SetImages(QVector< MythImage * > *images)
Should not be used unless absolutely necessary since it bypasses the image caching and threaded loade...
Definition: mythuiimage.cpp:810
MythUIType::m_initiator
bool m_initiator
Definition: mythuitype.h:266
ImageProperties::m_isReflected
bool m_isReflected
Definition: mythuiimage.h:65
mythmiscutil.h
MythUIImage::m_animatedImage
bool m_animatedImage
Definition: mythuiimage.h:197
MythUIImagePrivate
Definition: mythuiimage.cpp:546
ImageProperties::GetMaskImageRect
QRect GetMaskImageRect(void)
Definition: mythuiimage.h:41
ImageProperties::m_isGreyscale
bool m_isGreyscale
Definition: mythuiimage.h:64
MythUIType::LoadNow
virtual void LoadNow(void)
Cause images in this and child widgets to be loaded.
Definition: mythuitype.cpp:1403
ImageProperties::ImageProperties
ImageProperties()=default
MythPainter
Definition: mythpainter.h:34
MythImage
Definition: mythimage.h:36
ImageLoadEvent::kEventType
static Type kEventType
Definition: mythuiimage.cpp:465
MythUIType::SetSize
virtual void SetSize(QSize size)
Definition: mythuitype.cpp:568
ImageLoadThread::m_painter
MythPainter * m_painter
Definition: mythuiimage.cpp:538
ImageProperties::m_reflectLength
int m_reflectLength
Definition: mythuiimage.h:71
std
Definition: mythchrono.h:23
LOC
#define LOC
Definition: mythuiimage.cpp:38
ImageProperties::~ImageProperties
~ImageProperties()
Definition: mythuiimage.cpp:57
MythUIImage::ForceSize
void ForceSize(QSize size)
Force the dimensions of the widget and image to the given size.
Definition: mythuiimage.cpp:901
MythUIImagePrivate::MythUIImagePrivate
MythUIImagePrivate(MythUIImage *p)
Definition: mythuiimage.cpp:549
MythUIImage::m_needLoad
bool m_needLoad
Definition: mythuiimage.h:181
MythUIImage::kCycleReverse
@ kCycleReverse
Definition: mythuiimage.h:194
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:102
MythUIImage::FindRandomImage
void FindRandomImage(void)
Definition: mythuiimage.cpp:1635
ImageProperties::GetMaskImageFilename
QString GetMaskImageFilename()
Definition: mythuiimage.h:37
MythUIImage::Pulse
void Pulse(void) override
Pulse is called 70 times a second to trigger a single frame of an animation.
Definition: mythuiimage.cpp:1142
MythImage::ToGreyscale
void ToGreyscale()
Definition: mythimage.cpp:260
ImageLoadEvent::m_image
MythImage * m_image
Definition: mythuiimage.cpp:469
ImageLoadEvent::ImageLoadEvent
ImageLoadEvent(const MythUIImage *parent, MythImage *image, QString basefile, QString filename, int number, bool aborted)
Definition: mythuiimage.cpp:441
MythImage::Resize
void Resize(QSize newSize, bool preserveAspect=false)
Definition: mythimage.cpp:143
MythUIImage::SetImage
void SetImage(MythImage *img)
Should not be used unless absolutely necessary since it bypasses the image caching and threaded loade...
Definition: mythuiimage.cpp:748
MythImageReader
Definition: mythimage.h:25
ImageLoadEvent::m_basefile
QString m_basefile
Definition: mythuiimage.cpp:470
ImageLoader::ImageLoader
ImageLoader()=default
ImageLoadEvent::m_aborted
bool m_aborted
Definition: mythuiimage.cpp:478
MythUIImage::Finalize
void Finalize(void) override
Perform any post-xml parsing initialisation tasks.
Definition: mythuiimage.cpp:1495
MythUIImage::m_imageProperties
ImageProperties m_imageProperties
Definition: mythuiimage.h:183
MythUIImage::SetFilename
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
Definition: mythuiimage.cpp:676
ImageLoadEvent::GetNumber
int GetNumber() const
Definition: mythuiimage.cpp:461
ReflectAxis::Vertical
@ Vertical
MythUIImage::~MythUIImage
~MythUIImage() override
Definition: mythuiimage.cpp:599
MythUIType::ParseElement
virtual bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings)
Parse the xml definition of this widget setting the state of the object accordingly.
Definition: mythuitype.cpp:1240
GetMythUI
MythUIHelper * GetMythUI()
Definition: mythuihelper.cpp:66
build_compdb.filename
filename
Definition: build_compdb.py:21
MythUIScreenBounds::GetScalingFactors
void GetScalingFactors(float &Horizontal, float &Vertical) const
Definition: mythuiscreenbounds.cpp:237
mythmainwindow.h
MythUIImage::m_animationCycle
AnimationCycle m_animationCycle
Definition: mythuiimage.h:195
MythUIType::SetRedraw
void SetRedraw(void)
Definition: mythuitype.cpp:308
XMLParseBase::parseBool
static bool parseBool(const QString &text)
Definition: xmlparsebase.cpp:64
UIEffects::GetExtent
QRect GetExtent(QSize size) const
Definition: mythuianimation.cpp:8
ImageLoader::LoadImage
static MythImage * LoadImage(MythPainter *painter, ImageProperties imProps, ImageCacheMode cacheMode, const MythUIImage *parent, bool &aborted, MythImageReader *imageReader=nullptr)
Definition: mythuiimage.cpp:208
MythUIType::m_enableInitiator
bool m_enableInitiator
Definition: mythuitype.h:265
ImageLoadThread
Definition: mythuiimage.cpp:487
MThreadPool::start
void start(QRunnable *runnable, const QString &debugName, int priority=0)
Definition: mthreadpool.cpp:352
MythUIType::Finalize
virtual void Finalize(void)
Perform any post-xml parsing initialisation tasks.
Definition: mythuitype.cpp:1316
MythUIThemeCache::GetImageThreadPool
MThreadPool * GetImageThreadPool()
Definition: mythuithemecache.cpp:570
ImageLoader::~ImageLoader
~ImageLoader()=default
mythscreentype.h
ImageLoadEvent::GetParent
const MythUIImage * GetParent() const
Definition: mythuiimage.cpp:457
MythUIThemeCache::CacheImage
MythImage * CacheImage(const QString &URL, MythImage *Image, bool NoDisk=false)
Definition: mythuithemecache.cpp:413
MythImage::GetFileName
QString GetFileName(void) const
Definition: mythimage.h:91
AnimationFrame
QPair< MythImage *, std::chrono::milliseconds > AnimationFrame
Definition: mythuiimage.h:87
MythUIImage::DrawSelf
void DrawSelf(MythPainter *p, int xoffset, int yoffset, int alphaMod, QRect clipRect) override
Definition: mythuiimage.cpp:1207
ImageLoader
Definition: mythuiimage.cpp:106