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