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