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 
10 // QT
11 #include <QCoreApplication>
12 #include <QDir>
13 #include <QDomDocument>
14 #include <QEvent>
15 #include <QFile>
16 #include <QImageReader>
17 #include <QReadWriteLock>
18 #include <QRunnable>
19 
20 // libmythbase
21 #include "mythlogging.h"
22 #include "mythmiscutil.h"
23 #include "mthreadpool.h"
24 
25 // Mythui
26 #include "mythpainter.h"
27 #include "mythmainwindow.h"
28 #include "mythuihelper.h"
29 #include "mythscreentype.h"
30 
31 #ifdef _MSC_VER
32 # include "compat.h" // random
33 #endif
34 
35 class ImageLoadThread;
36 
37 #define LOC QString("MythUIImage(0x%1): ").arg((uint64_t)this,0,16)
38 
40 
42 {
43  Copy(other);
44 }
45 
47 {
48  if (this == &other)
49  return *this;
50 
51  Copy(other);
52 
53  return *this;
54 }
55 
57 {
58  if (m_maskImage)
60 }
61 
63 {
64  m_filename = other.m_filename;
65 
66  m_cropRect = other.m_cropRect;
67  m_forceSize = other.m_forceSize;
68 
72  m_isOriented = other.m_isOriented;
73 
80 
82 
84  m_isMasked = other.m_isMasked;
86 }
87 
89 {
90  if (image)
91  image->IncrRef();
92  if (m_maskImage)
94 
95  m_maskImage = image;
97 }
98 
103 {
104  public:
105  ImageLoader() = default;
106  ~ImageLoader() = default;
107 
108  static QHash<QString, const MythUIImage *> m_loadingImages;
109  static QMutex m_loadingImagesLock;
110  static QWaitCondition m_loadingImagesCond;
111 
112  static bool PreLoad(const QString &cacheKey, const MythUIImage *uitype)
113  {
114  m_loadingImagesLock.lock();
115 
116  // Check to see if the image is being loaded by us in another thread
117  if ((m_loadingImages.contains(cacheKey)) &&
118  (m_loadingImages[cacheKey] == uitype))
119  {
120  LOG(VB_GUI | VB_FILE, LOG_DEBUG,
121  QString("ImageLoader::PreLoad(%1), this "
122  "file is already being loaded by this same MythUIImage "
123  "in another thread.").arg(cacheKey));
124  m_loadingImagesLock.unlock();
125  return false;
126  }
127 
128  // Check to see if the exact same image is being loaded anywhere else
129  while (m_loadingImages.contains(cacheKey))
131 
132  m_loadingImages[cacheKey] = uitype;
133  m_loadingImagesLock.unlock();
134 
135  return true;
136  }
137 
138  static void PostLoad(const QString &cacheKey)
139  {
140  m_loadingImagesLock.lock();
141  m_loadingImages.remove(cacheKey);
142  m_loadingImagesCond.wakeAll();
143  m_loadingImagesLock.unlock();
144  }
145 
146  static bool SupportsAnimation(const QString &filename)
147  {
148  QString extension = filename.section('.', -1);
149  return !filename.startsWith("myth://") &&
150  (extension == "gif" ||
151  extension == "apng" ||
152  extension == "mng");
153  }
154 
159  static QString GenImageLabel(const ImageProperties &imProps)
160  {
161  QString imagelabel;
162  QString s_Attrib;
163 
164  if (imProps.m_isMasked)
165  s_Attrib = "masked";
166 
167  if (imProps.m_isReflected)
168  s_Attrib += "reflected";
169 
170  if (imProps.m_isGreyscale)
171  s_Attrib += "greyscale";
172 
173  if (imProps.m_isOriented)
174  {
175  s_Attrib += "orientation";
176  s_Attrib += QString("%1").arg(imProps.m_orientation);
177  }
178 
179  int w = -1;
180  int h = -1;
181  if (!imProps.m_forceSize.isNull())
182  {
183  if (imProps.m_forceSize.width() != -1)
184  w = imProps.m_forceSize.width();
185 
186  if (imProps.m_forceSize.height() != -1)
187  h = imProps.m_forceSize.height();
188  }
189 
190 
191  imagelabel = QString("%1-%2-%3x%4.png")
192  .arg(imProps.m_filename)
193  .arg(s_Attrib)
194  .arg(w)
195  .arg(h);
196  imagelabel.replace('/', '-');
197 #ifdef Q_OS_ANDROID
198  imagelabel.replace(':', '-');
199 #endif
200 
201  return imagelabel;
202  }
203 
204  static MythImage *LoadImage(MythPainter *painter,
205  // Must be a copy for thread safety
206  ImageProperties imProps,
207  ImageCacheMode cacheMode,
208  // Included only to check address, could be
209  // replaced by generating a unique value for
210  // each MythUIImage object?
211  const MythUIImage *parent,
212  bool &aborted,
213  MythImageReader *imageReader = nullptr)
214  {
215  QString cacheKey = GenImageLabel(imProps);
216  if (!PreLoad(cacheKey, parent))
217  {
218  aborted = true;
219  return nullptr;
220  }
221 
222  QString filename = imProps.m_filename;
223  MythImage *image = nullptr;
224 
225  bool bResize = false;
226  bool bFoundInCache = false;
227 
228  int w = -1;
229  int h = -1;
230 
231  if (!imProps.m_forceSize.isNull())
232  {
233  if (imProps.m_forceSize.width() != -1)
234  w = imProps.m_forceSize.width();
235 
236  if (imProps.m_forceSize.height() != -1)
237  h = imProps.m_forceSize.height();
238 
239  bResize = true;
240  }
241 
242  if (!imageReader)
243  {
244  image = GetMythUI()->LoadCacheImage(filename, cacheKey,
245  painter, cacheMode);
246  }
247 
248  if (image)
249  {
250  if (VERBOSE_LEVEL_CHECK(VB_GUI | VB_FILE, LOG_INFO))
251  {
252  image->IncrRef();
253  int cnt = image->DecrRef();
254  LOG(VB_GUI | VB_FILE, LOG_INFO,
255  QString("ImageLoader::LoadImage(%1) Found in cache, "
256  "RefCount = %2")
257  .arg(cacheKey).arg(cnt));
258  }
259 
260  if (imProps.m_isReflected)
261  image->setIsReflected(true);
262 
263  if (imProps.m_isOriented)
264  image->setIsOriented(true);
265 
266  bFoundInCache = true;
267  }
268  else
269  {
270  LOG(VB_GUI | VB_FILE, LOG_INFO,
271  QString("ImageLoader::LoadImage(%1) NOT Found in cache. "
272  "Loading Directly").arg(cacheKey));
273 
274  image = painter->GetFormatImage();
275  bool ok = false;
276 
277  if (imageReader)
278  ok = image->Load(imageReader);
279  else
280  ok = image->Load(filename);
281 
282  if (!ok)
283  {
284  image->DecrRef();
285  image = nullptr;
286  }
287  }
288 
289  if (image && image->isNull())
290  {
291  LOG(VB_GUI | VB_FILE, LOG_INFO,
292  QString("ImageLoader::LoadImage(%1) Image is NULL")
293  .arg(filename));
294 
295  image->DecrRef();
296  image = nullptr;
297  }
298 
299  if (image && !bFoundInCache)
300  {
301  if (imProps.m_isReflected)
302  {
303  image->Reflect(imProps.m_reflectAxis, imProps.m_reflectShear,
304  imProps.m_reflectScale, imProps.m_reflectLength,
305  imProps.m_reflectSpacing);
306  }
307 
308  if (imProps.m_isGreyscale)
309  image->ToGreyscale();
310 
311  if (imProps.m_isOriented)
312  image->Orientation(imProps.m_orientation);
313 
314  // Even if an explicit size wasn't defined this image may still need
315  // to be scaled because of a difference between the theme resolution
316  // and the screen resolution. We want to avoid scaling twice.
317  if (!bResize && imProps.m_isThemeImage)
318  {
319  float wmult = NAN; // Width multipler
320  float hmult = NAN; // Height multipler
321  GetMythMainWindow()->GetScalingFactors(wmult, hmult);
322  if (wmult != 1.0F || hmult != 1.0F)
323  {
324  w = image->size().width() * wmult;
325  h = image->size().height() * hmult;
326  bResize = true;
327  }
328  }
329 
330  if (bResize)
331  image->Resize(QSize(w, h), imProps.m_preserveAspect);
332 
333  if (imProps.m_isMasked)
334  {
335  MythImage *newMaskImage = painter->GetFormatImage();
336  if (newMaskImage->Load(imProps.GetMaskImageFilename()))
337  {
338  float wmult = NAN; // Width multipler
339  float hmult = NAN; // Height multipler
340  GetMythMainWindow()->GetScalingFactors(wmult, hmult);
341  if (wmult != 1.0F || hmult != 1.0F)
342  {
343  int width = newMaskImage->size().width() * wmult;
344  int height = newMaskImage->size().height() * hmult;
345  newMaskImage->Resize(QSize(width, height));
346  }
347 
348  imProps.SetMaskImage(newMaskImage);
349  }
350  else
351  imProps.SetMaskImage(nullptr);
352  newMaskImage->DecrRef();
353 
354  QRect imageArea = image->rect();
355  QRect maskArea = imProps.GetMaskImageRect();
356 
357  // Crop the mask to the image
358  int x = 0;
359  int y = 0;
360 
361  if (maskArea.width() > imageArea.width())
362  x = (maskArea.width() - imageArea.width()) / 2;
363 
364  if (maskArea.height() > imageArea.height())
365  y = (maskArea.height() - imageArea.height()) / 2;
366 
367  if (x > 0 || y > 0)
368  imageArea.translate(x, y);
369 
370  QImage mask = imProps.GetMaskImageSubset(imageArea);
371  image->setAlphaChannel(mask.convertToFormat(QImage::Format_Alpha8));
372  }
373 
374  if (!imageReader)
375  GetMythUI()->CacheImage(cacheKey, image);
376  }
377 
378  if (image)
379  image->SetChanged();
380 
381  PostLoad(cacheKey);
382 
383  return image;
384  }
385 
387  // Must be a copy for thread safety
388  const ImageProperties& imProps,
389  ImageCacheMode cacheMode,
390  // Included only to check address, could be
391  // replaced by generating a unique value for
392  // each MythUIImage object?
393  const MythUIImage *parent,
394  bool &aborted)
395  {
396  QString filename = QString("frame-%1-") + imProps.m_filename;
397  QString frameFilename;
398  int imageCount = 1;
399 
400  auto *imageReader = new MythImageReader(imProps.m_filename);
401  auto *images = new AnimationFrames();
402 
403  while (imageReader->canRead() && !aborted)
404  {
405  frameFilename = filename.arg(imageCount);
406 
407  ImageProperties frameProps = imProps;
408  frameProps.m_filename = frameFilename;
409 
410  MythImage *im = LoadImage(painter, frameProps, cacheMode, parent,
411  aborted, imageReader);
412 
413  if (!im)
414  aborted = true;
415 
416  images->append(AnimationFrame(im, imageReader->nextImageDelay()));
417  imageCount++;
418  }
419 
420  delete imageReader;
421 
422  return images;
423  }
424 
425 };
426 
427 QHash<QString, const MythUIImage *> ImageLoader::m_loadingImages;
429 QWaitCondition ImageLoader::m_loadingImagesCond;
430 
434 class ImageLoadEvent : public QEvent
435 {
436  public:
437  ImageLoadEvent(const MythUIImage *parent, MythImage *image,
438  QString basefile, QString filename,
439  int number, bool aborted)
440  : QEvent(kEventType),
441  m_parent(parent), m_image(image), m_basefile(std::move(basefile)),
442  m_filename(std::move(filename)), m_number(number),
443  m_aborted(aborted) { }
444 
446  QString basefile,
447  QString filename, bool aborted)
448  : QEvent(kEventType),
449  m_parent(parent), m_basefile(std::move(basefile)),
450  m_filename(std::move(filename)),
451  m_images(frames), m_aborted(aborted) { }
452 
453  const MythUIImage *GetParent() const { return m_parent; }
454  MythImage *GetImage() const { return m_image; }
455  QString GetBasefile() const { return m_basefile; }
456  QString GetFilename() const { return m_filename; }
457  int GetNumber() const { return m_number; }
459  bool GetAbortState() const { return m_aborted; }
460 
461  static Type kEventType;
462 
463  private:
464  const MythUIImage *m_parent {nullptr};
465  MythImage *m_image {nullptr};
466  QString m_basefile;
467  QString m_filename;
468  int m_number {0};
469 
470  // Animated Images
472 
473  // Image Load
474  bool m_aborted;
475 };
476 
477 QEvent::Type ImageLoadEvent::kEventType =
478  (QEvent::Type) QEvent::registerEventType();
479 
483 class ImageLoadThread : public QRunnable
484 {
485  public:
487  const ImageProperties &imProps, QString basefile,
488  int number, ImageCacheMode mode) :
489  m_parent(parent), m_painter(painter), m_imageProperties(imProps),
490  m_basefile(std::move(basefile)), m_number(number), m_cacheMode(mode)
491  {
492  }
493 
494  void run() override // QRunnable
495  {
496  bool aborted = false;
498 
499  // NOTE Do NOT use MythImageReader::supportsAnimation here, it defeats
500  // the point of caching remote images
502  {
503  AnimationFrames *frames =
507  aborted);
508 
509  if (frames && frames->count() > 1)
510  {
511  auto *le = new ImageLoadEvent(m_parent, frames, m_basefile,
513  aborted);
514  QCoreApplication::postEvent(m_parent, le);
515 
516  return;
517  }
518  delete frames;
519  }
520 
524  aborted);
525 
526  auto *le = new ImageLoadEvent(m_parent, image, m_basefile,
528  m_number, aborted);
529  QCoreApplication::postEvent(m_parent, le);
530  }
531 
532 private:
533  MythUIImage *m_parent {nullptr};
534  MythPainter *m_painter {nullptr};
536  QString m_basefile;
537  int m_number;
539 };
540 
543 {
544 public:
546  : m_parent(p) { }
547  ~MythUIImagePrivate() = default;
548 
549  MythUIImage *m_parent {nullptr};
550 
551  QReadWriteLock m_updateLock {QReadWriteLock::Recursive};
552 };
553 
555 
556 MythUIImage::MythUIImage(const QString &filepattern,
557  int low, int high, int delayms,
558  MythUIType *parent, const QString &name)
559  : MythUIType(parent, name)
560 {
561  m_imageProperties.m_filename = filepattern;
562  m_lowNum = low;
563  m_highNum = high;
564 
565  m_delay = delayms;
566  m_enableInitiator = true;
567 
568  d = new MythUIImagePrivate(this);
569  emit DependChanged(false);
570 }
571 
573  const QString &name)
574  : MythUIType(parent, name)
575 {
578 
579  m_lowNum = 0;
580  m_highNum = 0;
581  m_delay = -1;
582  m_enableInitiator = true;
583 
584  d = new MythUIImagePrivate(this);
585  emit DependChanged(false);
586 }
587 
588 MythUIImage::MythUIImage(MythUIType *parent, const QString &name)
589  : MythUIType(parent, name)
590 {
591  m_lowNum = 0;
592  m_highNum = 0;
593  m_delay = -1;
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(int delayms)
719 {
720  QWriteLocker updateLocker(&d->m_updateLock);
721  m_delay = delayms;
722  m_lastDisplay = QTime::currentTime();
723  m_curPos = 0;
724 }
725 
729 void MythUIImage::SetDelays(const QVector<int>& delays)
730 {
731  QWriteLocker updateLocker(&d->m_updateLock);
732  QMutexLocker imageLocker(&m_imagesLock);
733 
734  for (int delay : qAsConst(delays))
735  m_delays[m_delays.size()] = delay;
736 
737  if (m_delay == -1)
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 = -1;
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<int> 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 < 0 && !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 (getenv("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  int delay = -1;
1147 
1148  if (m_delays.contains(m_curPos))
1149  delay = m_delays[m_curPos];
1150  else if (m_delay > 0)
1151  delay = m_delay;
1152 
1153  if (delay > 0 &&
1154  abs(m_lastDisplay.msecsTo(QTime::currentTime())) > delay)
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<int> 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(0); // Default 0ms delay before first image
1352  }
1353  else
1354  {
1355  delays.append(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 = 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()).arg(GetXMLLocation())
1438  .arg(base->objectName()).arg(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->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  QDir imageDir(m_imageDirectory);
1638 
1639  if (!imageDir.exists())
1640  {
1641  QString themeDir = GetMythUI()->GetThemeDir() + '/';
1642  imageDir.setPath(themeDir + m_imageDirectory);
1643  }
1644 
1645  QStringList imageTypes;
1646 
1647  QList< QByteArray > exts = QImageReader::supportedImageFormats();
1648  for (const auto & ext : qAsConst(exts))
1649  {
1650  imageTypes.append(QString("*.").append(ext));
1651  }
1652 
1653  imageDir.setNameFilters(imageTypes);
1654 
1655  QStringList imageList = imageDir.entryList();
1656  QString randFile;
1657 
1658  if (!imageList.empty())
1659  {
1660  // try to find a different image
1661  do
1662  {
1663  uint32_t rand = MythRandom() % static_cast<uint32_t>(imageList.size());
1664  randFile = QString("%1%2").arg(m_imageDirectory).arg(imageList.takeAt(static_cast<int>(rand)));
1665 
1666  } while (imageList.size() > 1 && randFile == m_origFilename);
1667  }
1668 
1670 }
MythUIType::m_area
MythRect m_area
Definition: mythuitype.h:251
MythUIImage::MythUIImagePrivate
friend class MythUIImagePrivate
Definition: mythuiimage.h:197
MythUIImage::m_origFilename
QString m_origFilename
Definition: mythuiimage.h:168
ImageLoadThread::m_cacheMode
ImageCacheMode m_cacheMode
Definition: mythuiimage.cpp:538
ImageLoadThread::m_basefile
QString m_basefile
Definition: mythuiimage.cpp:536
MythUIImage::m_imagesLock
QMutex m_imagesLock
Definition: mythuiimage.h:172
ImageProperties::SetMaskImage
void SetMaskImage(MythImage *image)
Definition: mythuiimage.cpp:88
ImageLoadEvent::GetAbortState
bool GetAbortState() const
Definition: mythuiimage.cpp:459
MythRect::CalculateArea
void CalculateArea(const QRect &parentArea)
Definition: mythrect.cpp:64
MythUIImage
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:98
ImageLoadThread::ImageLoadThread
ImageLoadThread(MythUIImage *parent, MythPainter *painter, const ImageProperties &imProps, QString basefile, int number, ImageCacheMode mode)
Definition: mythuiimage.cpp:486
MythImage::Load
bool Load(MythImageReader *reader)
Definition: mythimage.cpp:278
ImageProperties::m_cropRect
MythRect m_cropRect
Definition: mythuiimage.h:60
MythUIImage::m_images
QHash< int, MythImage * > m_images
Definition: mythuiimage.h:170
MythUIImage::MythUIImage
MythUIImage(const QString &filepattern, int low, int high, int delayms, MythUIType *parent, const QString &name)
Definition: mythuiimage.cpp:556
MythUIImagePrivate::m_updateLock
QReadWriteLock m_updateLock
Definition: mythuiimage.cpp:551
MythUIImage::m_delays
QHash< int, int > m_delays
Definition: mythuiimage.h:171
ImageLoadEvent::GetImage
MythImage * GetImage() const
Definition: mythuiimage.cpp:454
MythUIType::GetFullArea
virtual MythRect GetFullArea(void) const
Definition: mythuitype.cpp:878
MythUIType::CalcAlpha
int CalcAlpha(int alphamod) const
Definition: mythuitype.cpp:459
MythRect::toQRect
QRect toQRect(void) const
Definition: mythrect.cpp:405
ImageProperties::m_reflectSpacing
int m_reflectSpacing
Definition: mythuiimage.h:73
ImageProperties::m_isThemeImage
bool m_isThemeImage
Definition: mythuiimage.h:77
MythUIImagePrivate::m_parent
MythUIImage * m_parent
Definition: mythuiimage.cpp:549
MythImage::Reflect
void Reflect(ReflectAxis axis, int shear, int scale, int length, int spacing=0)
Definition: mythimage.cpp:167
ImageLoadEvent
Definition: mythuiimage.cpp:435
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:108
ImageLoader::PostLoad
static void PostLoad(const QString &cacheKey)
Definition: mythuiimage.cpp:138
UIEffects::GetExtent
QRect GetExtent(const QSize &size) const
Definition: mythuianimation.cpp:7
ImageLoader::m_loadingImagesLock
static QMutex m_loadingImagesLock
Definition: mythuiimage.cpp:109
arg
arg(title).arg(filename).arg(doDelete))
MythUIType::GetPainter
virtual MythPainter * GetPainter(void)
Definition: mythuitype.cpp:1398
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:159
ImageLoadEvent::ImageLoadEvent
ImageLoadEvent(const MythUIImage *parent, AnimationFrames *frames, QString basefile, QString filename, bool aborted)
Definition: mythuiimage.cpp:445
MythUIImage::customEvent
void customEvent(QEvent *event) override
Definition: mythuiimage.cpp:1534
ImageLoadThread::m_parent
MythUIImage * m_parent
Definition: mythuiimage.cpp:533
MythUIImage::SetOrientation
void SetOrientation(int orientation)
Saves the exif orientation value of the first image in the widget.
Definition: mythuiimage.cpp:921
MythUIType::SetSize
virtual void SetSize(const QSize &size)
Definition: mythuitype.cpp:554
MythImage::Resize
void Resize(const QSize &newSize, bool preserveAspect=false)
Definition: mythimage.cpp:145
ImageProperties::m_reflectScale
int m_reflectScale
Definition: mythuiimage.h:70
MythUIType::SetArea
virtual void SetArea(const MythRect &rect)
Definition: mythuitype.cpp:595
ImageLoadEvent::GetBasefile
QString GetBasefile() const
Definition: mythuiimage.cpp:455
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
AnimationFrame
QPair< MythImage *, int > AnimationFrame
Definition: mythuiimage.h:87
ImageLoadEvent::GetAnimationFrames
AnimationFrames * GetAnimationFrames() const
Definition: mythuiimage.cpp:458
ImageLoadThread::m_number
int m_number
Definition: mythuiimage.cpp:537
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:18
MythUIType::Pulse
virtual void Pulse(void)
Pulse is called 70 times a second to trigger a single frame of an animation.
Definition: mythuitype.cpp:441
ImageProperties
Definition: mythuiimage.h:24
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:110
ImageProperties::m_filename
QString m_filename
Definition: mythuiimage.h:58
ImageProperties::GetMaskImageSubset
QImage GetMaskImageSubset(const QRect &imageArea)
Definition: mythuiimage.h:48
MythUIImage::m_showingRandomImage
bool m_showingRandomImage
Definition: mythuiimage.h:187
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
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:870
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:258
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:112
mythlogging.h
MythUIImage::LoadComplete
void LoadComplete()
ImageProperties::operator=
ImageProperties & operator=(const ImageProperties &other)
Definition: mythuiimage.cpp:46
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:158
ImageCacheMode
ImageCacheMode
Definition: mythuithemecache.h:12
MThreadPool::waitForDone
void waitForDone(void)
Definition: mthreadpool.cpp:562
MythUIType::SetMinArea
virtual void SetMinArea(const MythRect &rect)
Set the minimum area based on the given size.
Definition: mythuitype.cpp:805
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:13
kCacheForceStat
@ kCacheForceStat
Definition: mythuithemecache.h:16
MythUIThemeHelper::GetThemeDir
QString GetThemeDir()
Definition: mythuithemehelper.cpp:140
compat.h
MythUIImage::SetDelay
void SetDelay(int delayms)
Set the delay between each image in an animation.
Definition: mythuiimage.cpp:718
ImageLoadEvent::m_images
AnimationFrames * m_images
Definition: mythuiimage.cpp:471
MythUIImage::d
MythUIImagePrivate * d
Definition: mythuiimage.h:190
XMLParseBase::getFirstText
static QString getFirstText(QDomElement &element)
Definition: xmlparsebase.cpp:53
MythImage::DecrRef
int DecrRef(void) override
Decrements reference count and deletes on 0.
Definition: mythimage.cpp:54
MythUIType::m_parent
MythUIType * m_parent
Definition: mythuitype.h:271
MythUIImage::ImageLoadThread
friend class ImageLoadThread
Definition: mythuiimage.h:203
filename
QString filename
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:637
MythUIImage::m_animationReverse
bool m_animationReverse
Definition: mythuiimage.h:194
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:1151
ImageProperties::m_isOriented
bool m_isOriented
Definition: mythuiimage.h:67
ImageProperties::Copy
void Copy(const ImageProperties &other)
Definition: mythuiimage.cpp:62
MythUIImage::m_imageDirectory
QString m_imageDirectory
Definition: mythuiimage.h:188
mythpainter.h
MythUIThemeCache::LoadCacheImage
MythImage * LoadCacheImage(QString File, const QString &Label, MythPainter *Painter, ImageCacheMode cacheMode=kCacheNormal)
Definition: mythuithemecache.cpp:257
MythUIImage::kCycleStart
@ kCycleStart
Definition: mythuiimage.h:192
XMLParseBase::parseRect
static MythRect parseRect(const QString &text, bool normalize=true)
Definition: xmlparsebase.cpp:137
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:140
ImageLoader::SupportsAnimation
static bool SupportsAnimation(const QString &filename)
Definition: mythuiimage.cpp:146
kCacheIgnoreDisk
@ kCacheIgnoreDisk
Definition: mythuithemecache.h:14
token
return token
Definition: musicutils.cpp:74
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:467
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:464
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:70
MythUIImage::ForceSize
void ForceSize(const QSize &size)
Force the dimensions of the widget and image to the given size.
Definition: mythuiimage.cpp:901
ImageLoader::LoadAnimatedImage
static AnimationFrames * LoadAnimatedImage(MythPainter *painter, const ImageProperties &imProps, ImageCacheMode cacheMode, const MythUIImage *parent, bool &aborted)
Definition: mythuiimage.cpp:386
MythUIType
The base class on which all widgets and screens are based.
Definition: mythuitype.h:66
MythImage::Orientation
void Orientation(int orientation)
Changes the orientation angle of the image according to the exif rotation values.
Definition: mythimage.cpp:136
MythUIType::IsDeferredLoading
bool IsDeferredLoading(bool recurse=false) const
Definition: mythuitype.cpp:1364
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:535
mthreadpool.h
ImageProperties::m_reflectShear
int m_reflectShear
Definition: mythuiimage.h:72
ImageLoadEvent::GetFilename
QString GetFilename() const
Definition: mythuiimage.cpp:456
mythuihelper.h
MythUIImage::m_delay
int m_delay
Definition: mythuiimage.h:174
MythRandom
MBASE_PUBLIC uint32_t MythRandom()
Definition: mythmiscutil.h:24
ImageLoadThread::run
void run() override
Definition: mythuiimage.cpp:494
MythImage::IncrRef
int IncrRef(void) override
Increments reference count.
Definition: mythimage.cpp:46
MythImage::IsOriented
bool IsOriented() const
Definition: mythimage.h:55
ImageLoadEvent::m_number
int m_number
Definition: mythuiimage.cpp:468
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:243
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:195
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:1380
ImageProperties::ImageProperties
ImageProperties()=default
MythPainter
Definition: mythpainter.h:33
MythImage
Definition: mythimage.h:37
ImageLoadEvent::kEventType
static Type kEventType
Definition: mythuiimage.cpp:461
ImageLoadThread::m_painter
MythPainter * m_painter
Definition: mythuiimage.cpp:534
ImageProperties::m_reflectLength
int m_reflectLength
Definition: mythuiimage.h:71
LOC
#define LOC
Definition: mythuiimage.cpp:37
ImageProperties::~ImageProperties
~ImageProperties()
Definition: mythuiimage.cpp:56
MythUIImagePrivate::MythUIImagePrivate
MythUIImagePrivate(MythUIImage *p)
Definition: mythuiimage.cpp:545
MythUIImage::m_needLoad
bool m_needLoad
Definition: mythuiimage.h:181
MythUIImage::kCycleReverse
@ kCycleReverse
Definition: mythuiimage.h:192
MythUIImage::SetDelays
void SetDelays(const QVector< int > &delays)
Sets the delays between each image in an animation.
Definition: mythuiimage.cpp:729
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:105
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:262
ImageLoadEvent::m_image
MythImage * m_image
Definition: mythuiimage.cpp:465
ImageLoadEvent::ImageLoadEvent
ImageLoadEvent(const MythUIImage *parent, MythImage *image, QString basefile, QString filename, int number, bool aborted)
Definition: mythuiimage.cpp:437
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:26
ImageLoadEvent::m_basefile
QString m_basefile
Definition: mythuiimage.cpp:466
ImageLoader::ImageLoader
ImageLoader()=default
ImageLoadEvent::m_aborted
bool m_aborted
Definition: mythuiimage.cpp:474
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:457
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:1217
GetMythUI
MythUIHelper * GetMythUI()
Definition: mythuihelper.cpp:66
MythUIScreenBounds::GetScalingFactors
void GetScalingFactors(float &Horizontal, float &Vertical) const
Definition: mythuiscreenbounds.cpp:231
mythmainwindow.h
MythUIImage::m_animationCycle
AnimationCycle m_animationCycle
Definition: mythuiimage.h:193
MythUIType::SetRedraw
void SetRedraw(void)
Definition: mythuitype.cpp:294
XMLParseBase::parseBool
static bool parseBool(const QString &text)
Definition: xmlparsebase.cpp:65
ImageLoader::LoadImage
static MythImage * LoadImage(MythPainter *painter, ImageProperties imProps, ImageCacheMode cacheMode, const MythUIImage *parent, bool &aborted, MythImageReader *imageReader=nullptr)
Definition: mythuiimage.cpp:204
MythUIType::m_enableInitiator
bool m_enableInitiator
Definition: mythuitype.h:242
ImageLoadThread
Definition: mythuiimage.cpp:484
MThreadPool::start
void start(QRunnable *runnable, const QString &debugName, int priority=0)
Definition: mthreadpool.cpp:341
MythUIType::Finalize
virtual void Finalize(void)
Perform any post-xml parsing initialisation tasks.
Definition: mythuitype.cpp:1293
MythUIThemeCache::GetImageThreadPool
MThreadPool * GetImageThreadPool()
Definition: mythuithemecache.cpp:599
ImageLoader::~ImageLoader
~ImageLoader()=default
mythscreentype.h
ImageLoadEvent::GetParent
const MythUIImage * GetParent() const
Definition: mythuiimage.cpp:453
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
MythUIImage::DrawSelf
void DrawSelf(MythPainter *p, int xoffset, int yoffset, int alphaMod, QRect clipRect) override
Definition: mythuiimage.cpp:1207
ImageLoader
Definition: mythuiimage.cpp:103