MythTV  master
galleryslide.cpp
Go to the documentation of this file.
1 #include "galleryslide.h"
2 
3 #include <cmath> // for roundf
4 #include "mythmainwindow.h"
5 #include "mythlogging.h"
6 
7 #include "imagemetadata.h"
8 
9 
10 #define LOC QString("Slide: ")
11 #define SBLOC QString("SlideBuffer: ")
12 
13 
14 // Number of slides to use for buffering image requests.
15 // When browsing quickly the buffer will load consecutive slides until it fills.
16 // If too large, rapid browsing will be stodgy (sequential access) for images that
17 // aren't cached (Cached images are always fast).
18 // If too small, rapid browsing will result in skipping slides rather than flicking
19 // quickly through them.
20 // Minimum is 4: 3 for displaying a transition, 1 to handle load requests
21 #define SLIDE_BUFFER_SIZE 9
22 
23 
29 void AbstractAnimation::Start(bool forwards, float speed)
30 {
31  m_forwards = forwards;
32  m_speed = speed;
33  m_running = true;
34 }
35 
36 
45 void Animation::Set(const QVariant& from, const QVariant& to, int duration,
46  const QEasingCurve& curve, UIEffects::Centre centre)
47 {
48  setStartValue(from);
49  setEndValue(to);
50  m_centre = centre;
51  setDuration(duration);
52  setEasingCurve(curve);
53 }
54 
55 
61 void Animation::Start(bool forwards, float speed)
62 {
63  if (duration() == 0)
64  return;
65 
66  m_elapsed = forwards ? 0 : duration();
67  setCurrentTime(m_elapsed);
68 
69  AbstractAnimation::Start(forwards, speed);
70 }
71 
72 
77 void Animation::Pulse(int interval)
78 {
79  if (!m_running)
80  return;
81 
82  m_elapsed += (m_forwards ? interval : -interval) * m_speed;
83 
84  setCurrentTime(m_elapsed);
85 
86  // Detect completion
87  if ((m_forwards && m_elapsed >= duration())
88  || (!m_forwards && m_elapsed <= 0))
89  Finished();
90 }
91 
92 
97 void Animation::updateCurrentValue(const QVariant &value)
98 {
99  if (m_parent && m_running)
100  {
102 
103  switch (m_type)
104  {
105  case None: break;
106  case Position: m_parent->SetPosition(value.toPoint()); break;
107  case Alpha: m_parent->SetAlpha(value.toInt()); break;
108  case Zoom: m_parent->SetZoom(value.toFloat()); break;
109  case HorizontalZoom: m_parent->SetHorizontalZoom(value.toFloat()); break;
110  case VerticalZoom: m_parent->SetVerticalZoom(value.toFloat()); break;
111  case Angle: m_parent->SetAngle(value.toFloat()); break;
112  }
113  }
114 }
115 
116 
122 {
123  // Signal group when child completes
124  m_group.append(child);
125  connect(child, SIGNAL(finished()), this, SLOT(Finished()));
126 }
127 
128 
133 {
134  qDeleteAll(m_group);
135  m_group.clear();
136 }
137 
138 
143 void SequentialAnimation::Pulse(int interval)
144 {
145  if (!m_running || m_current < 0 || m_current >= m_group.size())
146  return;
147 
148  // Pulse current running child
149  m_group.at(m_current)->Pulse(interval);
150 }
151 
152 
158 void SequentialAnimation::Start(bool forwards, float speed)
159 {
160  if (m_group.empty())
161  return;
162 
163  m_current = forwards ? 0 : m_group.size() - 1;
164 
165  // Start group, then first child
166  // Parent function explicitly set to zero. Have to call
167  // grandparent directly to get work done.
168  AbstractAnimation::Start(forwards, speed);
169  m_group.at(m_current)->Start(m_forwards, m_speed);
170 }
171 
172 
178 {
179  // Set group speed for subsequent children
180  // Parent function explicitly set to zero. Have to call
181  // grandparent directly to get work done.
183 
184  // Set active child
185  if (!m_running || m_current < 0 || m_current >= m_group.size())
186  return;
187 
188  m_group.at(m_current)->SetSpeed(speed);
189 }
190 
191 
196 {
197  // Finish group when last child finishes
198  if ((m_forwards && ++m_current == m_group.size())
199  || (!m_forwards && --m_current < 0))
201  else
202  // Start next child
203  m_group.at(m_current)->Start(m_forwards, m_speed);
204 }
205 
206 
211 void ParallelAnimation::Pulse(int interval)
212 {
213  if (m_running)
214  // Pulse all children
215  foreach(AbstractAnimation *animation, m_group)
216  animation->Pulse(interval);
217 }
218 
219 
225 void ParallelAnimation::Start(bool forwards, float speed)
226 {
227  if (m_group.empty())
228  return;
229 
230  m_finished = m_group.size();
231 
232  // Start group, then all children
233  // Parent function explicitly set to zero. Have to call
234  // grandparent directly to get work done.
235  AbstractAnimation::Start(forwards, speed);
236  foreach(AbstractAnimation *animation, m_group)
237  animation->Start(m_forwards, m_speed);
238 }
239 
240 
246 {
247  // Set group speed, then all children
248  // Parent function explicitly set to zero. Have to call
249  // grandparent directly to get work done.
251  foreach(AbstractAnimation *animation, m_group)
252  animation->SetSpeed(m_speed);
253 }
254 
255 
260 {
261  // Finish group when last child finishes
262  if (--m_finished == 0)
264 }
265 
266 
271 void PanAnimation::updateCurrentValue(const QVariant &value)
272 {
273  if (m_parent && m_running)
274  {
275  Slide *image = m_parent;
276  image->SetPan(value.toPoint());
277  }
278 }
279 
280 
287 Slide::Slide(MythUIType *parent, const QString& name, MythUIImage *image)
288  : MythUIImage(parent, name)
289 {
290  // Clone from image
291  CopyFrom(image);
292 
293  // Null parent indicates we should become a child of the image (after
294  // copy to avoid recursion)
295  if (!parent)
296  {
297  // Slides sit on top of parent image area
298  SetArea(MythRect(image->GetArea().toQRect()));
299  m_Area.moveTo(0, 0);
300  setParent(image);
301  m_Parent = image;
302  image->AddChild(this);
303  }
304 
305  // Provide animations for pan & zoom
306  if (GetPainter()->SupportsAnimation())
307  {
309  m_panAnimation = new PanAnimation(this);
310  }
311 
312  connect(this, SIGNAL(LoadComplete()), this, SLOT(SlideLoaded()));
313 }
314 
315 
320 {
321  delete m_zoomAnimation;
322  delete m_panAnimation;
323  LOG(VB_GUI, LOG_DEBUG, "Deleted Slide " + objectName());
324 }
325 
326 
331 {
332  m_state = kEmpty;
333  m_data.clear();
334  m_waitingFor.clear();
335  SetCropRect(0, 0, 0, 0);
336  SetVisible(false);
337 }
338 
339 
344 QChar Slide::GetDebugState() const
345 {
346  switch (m_state)
347  {
348  case kEmpty: return 'e';
349  case kFailed: return 'f';
350  case kLoaded: return m_waitingFor ? 'r' : 'a';
351  case kLoading: return m_waitingFor ? 'l' : 'p';
352  }
353  return '?';
354 }
355 
356 
369 bool Slide::LoadSlide(const ImagePtrK& im, int direction, bool notifyCompletion)
370 {
371  m_direction = direction;
372  m_waitingFor = notifyCompletion ? im : ImagePtrK();
373 
374  if (im == m_data)
375  {
376  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Already loading/loaded %1 in %2")
377  .arg(im->m_filePath, objectName()));
378 
379  if (m_state >= kLoaded && notifyCompletion)
380  // Image has been pre-loaded
381  emit ImageLoaded(this);
382 
383  return (m_state >= kLoaded);
384  }
385 
386  // Is a different image loading ?
387  if (m_state == kLoading)
388  {
389  // Can't abort image loads, so must wait for it to finish
390  // before starting new load
391  m_waitingFor = im;
392 
393  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Postponing load of %1 in %2")
394  .arg(im->m_filePath, objectName()));
395 
396  return false;
397  }
398 
399  // Start load
400  m_data = im;
401  m_state = kLoading;
402 
403  if (im->m_type == kVideoFile)
404  {
405  // Use thumbnail, which has already been orientated
406  SetFilename(im->m_thumbNails.at(0).second);
407  SetOrientation(1);
408  }
409  else
410  {
411  // Load image, compensating for any Qt auto-orientation
412  SetFilename(im->m_url);
413  SetOrientation(Orientation(m_data->m_orientation).GetCurrent(true));
414  }
415 
416  // Load in background
417  Load(true);
418  return false;
419 }
420 
421 
429 {
430  m_state = m_Images[0] ? kLoaded : kFailed;
431  if (m_state == kFailed)
432  LOG(VB_GENERAL, LOG_ERR, LOC +
433  QString("Failed to load %1").arg(m_data->m_filePath));
434 
435  // Ignore superseded requests and preloads
436  if (m_data == m_waitingFor)
437  {
438  // Loaded image is the latest requested
439  emit ImageLoaded(this);
440  }
441  else if (m_waitingFor)
442  {
443  LOG(VB_FILE, LOG_DEBUG, LOC + QString("Starting delayed load %1")
444  .arg(m_waitingFor->m_filePath));
445 
446  // Start latest postponed load
448  }
449 }
450 
451 
457 void Slide::Zoom(int percentage)
458 {
459  // Sentinel indicates reset to default zoom
460  float newZoom = (percentage == 0)
461  ? 1.0F
462  : qMax(MIN_ZOOM,
463  qMin(MAX_ZOOM, m_zoom * (1.0F + percentage / 100.0F)));
464  if (newZoom != m_zoom)
465  {
466  if (m_zoomAnimation)
467  {
468  m_zoomAnimation->Set(m_zoom, newZoom, 250, QEasingCurve::OutQuad);
470  }
471  else
472  SetZoom(newZoom);
473  }
474 }
475 
476 
483 void Slide::SetZoom(float zoom)
484 {
485  m_zoom = zoom;
487 
488  // TODO
489  // MythUIImage displaces widget or doesn't centre for some combinations of
490  // zoom centre/cropping so frig centre for now.
492 
493  SetPan(m_pan);
494 }
495 
496 
501 void Slide::Pan(QPoint offset)
502 {
503  // Panning only possible when zoomed in
504  if (m_zoom > 1.0F)
505  {
506  QPoint start = m_pan;
507 
508  // Sentinel indicates reset to centre
509  // Panning is applied to original (unzoomed) image co-ords.
510  // Adjust offset for zoom so that pan moves a constant screen distance rather
511  // than constant image distance
512  QPoint dest = offset.isNull() ? QPoint(0, 0) : start + offset / m_zoom;
513 
514  if (m_panAnimation)
515  {
516  m_panAnimation->Set(start, dest, 250, QEasingCurve::Linear);
518  }
519  else
520  SetPan(dest);
521  }
522 }
523 
524 
531 void Slide::SetPan(QPoint pos)
532 {
533  if (m_state == kFailed)
534  {
535  m_pan = pos;
536  return;
537  }
538 
539  // Determine zoom of largest dimension
540  QRect imageArea = m_Images[m_CurPos]->rect();
541  float hRatio = float(imageArea.height()) / m_Area.height();
542  float wRatio = float(imageArea.width()) / m_Area.width();
543  float ratio = qMax(hRatio, wRatio);
544 
545  if (m_zoom != 0.0F)
546  ratio /= m_zoom;
547 
548  // Determine crop area
549  int h = qMin(int(roundf(m_Area.height() * ratio)), imageArea.height());
550  int w = qMin(int(roundf(m_Area.width() * ratio)), imageArea.width());
551  int x = imageArea.center().x() - w / 2;
552  int y = imageArea.center().y() - h / 2;
553 
554  // Constrain pan to boundaries
555  int limitX = (imageArea.width() - w) / 2;
556  int limitY = (imageArea.height() - h) / 2;
557  m_pan.setX(qMax(qMin(pos.x(), limitX), -limitX));
558  m_pan.setY(qMax(qMin(pos.y(), limitY), -limitY));
559 
560  SetCropRect(x + m_pan.x(), y + m_pan.y(), w, h);
561  SetRedraw();
562 }
563 
564 
569 {
570  // Update zoom/pan animations
571  if (m_zoomAnimation)
572  m_zoomAnimation->Pulse(GetMythMainWindow()->GetDrawInterval());
573 
574  if (m_panAnimation)
575  m_panAnimation->Pulse(GetMythMainWindow()->GetDrawInterval());
576 }
577 
578 
580 {
581  LOG(VB_GUI, LOG_DEBUG, "Deleted Slidebuffer");
582 }
583 
584 
586 {
587  QMutexLocker lock(&m_mutexQ);
588  foreach (Slide *s, m_queue)
589  s->Clear();
590  LOG(VB_GUI, LOG_DEBUG, "Aborted Slidebuffer");
591 }
592 
593 
600 {
601  // Require at least 4 slides: 2 for transitions, 1 to handle further requests
602  // and 1 to prevent solitary slide from being used whilst it is loading
603  int size = qMax(SLIDE_BUFFER_SIZE, 4);
604 
605  // Fill buffer with slides cloned from the XML image widget
606 
607  // Create first as a child of the XML image.
608  Slide *slide = new Slide(nullptr, "slide0", &image);
609 
610  // Buffer is notified when it has loaded image
611  connect(slide, SIGNAL(ImageLoaded(Slide *)),
612  this, SLOT(Flush(Slide *)));
613 
614  m_queue.enqueue(slide);
615 
616  // Rest are simple clones of first
617  for (int i = 1; i < size; ++i)
618  {
619  slide = new Slide(&image, QString("slide%1").arg(i), slide);
620 
621  // All slides (except first) start off hidden
622  slide->SetVisible(false);
623 
624  // Buffer is notified when it has loaded image
625  connect(slide, SIGNAL(ImageLoaded(Slide *)),
626  this, SLOT(Flush(Slide *)));
627 
628  m_queue.enqueue(slide);
629  }
630 
631  m_nextLoad = 1;
632 }
633 
634 
640 {
641  QMutexLocker lock(&m_mutexQ);
642 
643  QString state;
644  for (int i = 0; i < m_queue.size(); ++i)
645  {
646  QChar code(m_queue.at(i)->GetDebugState());
647  state += (i == m_nextLoad ? code.toUpper() : code);
648  }
649  return QString("[%1] (%2)").arg(state, m_queue.head()->objectName());
650 }
651 
652 
660 bool SlideBuffer::Load(const ImagePtrK& im, int direction)
661 {
662  if (!im)
663  return false;
664 
665  QMutexLocker lock(&m_mutexQ);
666 
667  // Start loading image in next available slide
668  Slide *slide = m_queue.at(m_nextLoad);
669 
670  // Further load requests will go to same slide if no free ones are available
671  if (m_nextLoad < m_queue.size() - 1)
672  ++m_nextLoad;
673 
674  LOG(VB_FILE, LOG_DEBUG, SBLOC + QString("Loading %1 in %2, %3")
675  .arg(im->m_filePath, slide->objectName()).arg(BufferState()));
676 
677  return slide->LoadSlide(im, direction, true);
678 }
679 
680 
686 {
687  if (!im)
688  return;
689 
690  QMutexLocker lock(&m_mutexQ);
691 
692  // Start loading image in next available slide
693  Slide *slide = m_queue.at(m_nextLoad);
694 
695  LOG(VB_FILE, LOG_DEBUG, SBLOC + QString("Preloading %1 in %2, %3")
696  .arg(im->m_filePath, slide->objectName()).arg(BufferState()));
697 
698  // Load silently
699  slide->LoadSlide(im);
700 }
701 
702 
708 {
709  QMutexLocker lock(&m_mutexQ);
710 
711  // Reset slide & return to buffer for re-use
712  Slide *slide = m_queue.dequeue();
713  slide->Clear();
714  m_queue.enqueue(slide);
715 
716  QString name = slide->objectName();
717 
718  // Free constrained load ptr now a spare slide is available
719  if (!m_queue.at(--m_nextLoad)->IsEmpty())
720  ++m_nextLoad;
721 
722  LOG(VB_FILE, LOG_DEBUG, SBLOC + QString("Released %1").arg(name));
723 
724  // Flush any pending slides that originate from multiple requests (skipping)
725  Flush(m_queue.head(), "Pending");
726 }
727 
728 
735 void SlideBuffer::Flush(Slide *slide, const QString& reason)
736 {
737  QMutexLocker lock(&m_mutexQ);
738 
739  // Determine number of consecutive slides that are now available after head
740  // Include last slide to ensure transition speed is consistent: it will never
741  // be displayed because queue size is always > 2
742  int available = 1;
743  while (available < m_queue.size() && m_queue.at(available)->IsLoaded())
744  ++available;
745 
746  if (available == 1)
747  return;
748 
749  // Notify that more slides are available
750  ImagePtrK im = slide->GetImageData();
751  QString path = im ? im->m_filePath : "Unknown";
752 
753  LOG(VB_FILE, LOG_DEBUG, SBLOC + QString("%1 %2 in %3, %4")
754  .arg(reason, path, slide->objectName()).arg(BufferState()));
755 
756  emit SlideReady(--available);
757 }
void SetSpeed(float speed) override
Change speed of group and all child animations.
A video.
Definition: imagetypes.h:39
QPoint m_pan
Pan position (0,0) = no pan.
Definition: galleryslide.h:198
PanAnimation * m_panAnimation
Dedicated animation for panning, if supported.
Definition: galleryslide.h:197
int m_elapsed
Current millisec position within animation, 0..duration.
Definition: galleryslide.h:86
void Flush(Slide *, const QString &reason="Loaded")
Signal if any slides are waiting to be displayed.
Encapsulates Exif orientation processing.
Definition: imagemetadata.h:58
virtual MythPainter * GetPainter(void)
void finished()
Signals animation has finished.
void SetVerticalZoom(float zoom)
Definition: mythuitype.cpp:955
void Pulse() override
Update pan & zoom animations.
void SlideLoaded()
An image has completed loading.
virtual void Finished()
To be called when animation completes.
Definition: galleryslide.h:40
virtual void Add(AbstractAnimation *child)
Add child animation to group.
Slide(MythUIType *parent, const QString &name, MythUIImage *image)
Clone slide from a theme MythUIImage.
Specialised animation for panning slideshow images (MythUI doesn't support panning)
Definition: galleryslide.h:146
void SetAlpha(int newalpha)
Definition: mythuitype.cpp:924
void SetRedraw(void)
Definition: mythuitype.cpp:295
bool m_forwards
Play direction.
Definition: galleryslide.h:47
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
void Start(bool forwards, float speed=1.0) override
Start sequential animation.
void Finished() override
A child animation has completed.
virtual void Pulse(int interval)=0
Base animation class that is driven by a Myth pulse and implements variable speed.
Definition: galleryslide.h:27
#define MAX_ZOOM
Definition: galleryslide.h:21
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...
void SetHorizontalZoom(float zoom)
Definition: mythuitype.cpp:949
int m_nextLoad
Index of first spare slide, (or last slide if none spare)
Definition: galleryslide.h:251
bool Load(const ImagePtrK &im, int direction)
Assign an image to next available slide, start loading and signal when done.
ImagePtrK m_data
The image currently loading/loaded.
Definition: galleryslide.h:190
void updateCurrentValue(const QVariant &value) override
Update pan value.
UIEffects m_Effects
Definition: mythuitype.h:257
The base class on which all widgets and screens are based.
Definition: mythuitype.h:63
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
void ReleaseCurrent()
Move head slide to back of queue and flush waiting slides.
void SetPosition(int x, int y)
Convenience method, calls SetPosition(const MythPoint&) Override that instead to change functionality...
Definition: mythuitype.cpp:519
Handles Exif/FFMpeg metadata tags for images.
virtual void Start(bool forwards, float speed=1.0)
Initialise & start base animation.
void CopyFrom(MythUIType *base) override
Copy this widgets state from another.
Centre m_centre
void SetOrientation(int orientation)
Saves the exif orientation value of the first image in the widget.
void SetZoom(float)
Sets slide zoom.
float m_zoom
Current zoom, 1.0 = fullsize.
Definition: galleryslide.h:193
ImagePtrK GetImageData() const
Definition: galleryslide.h:164
virtual void SetVisible(bool visible)
void Pulse(int interval) override
Progress sequential animation.
QRect toQRect(void) const
Definition: mythrect.cpp:354
bool m_running
True whilst animation is active.
Definition: galleryslide.h:48
void Finished() override
A child animation has completed.
void Initialise(MythUIImage &image)
Construct buffer.
void updateCurrentValue(const QVariant &value) override
Update animated value.
void Preload(const ImagePtrK &im)
Load an image in next available slide.
int GetCurrent(bool compensate)
Determines orientation required for an image.
virtual MythRect GetArea(void) const
If the object has a minimum area defined, return it, other wise return the default area.
Definition: mythuitype.cpp:863
QMutex m_mutexQ
Queue protection.
Definition: galleryslide.h:249
void Pan(QPoint offset)
Initiate pan.
Defines specialised images used by the Gallery slideshow and the animation framework used by transfor...
virtual void SetSpeed(float speed)
Definition: galleryslide.h:34
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:17
SlideState m_state
Slide validity.
Definition: galleryslide.h:189
bool LoadSlide(const ImagePtrK &im, int direction=0, bool notifyCompletion=false)
Load slide with an image.
float m_speed
Real-time = 1.0, Double-speed = 2.0.
Definition: galleryslide.h:49
MythRect m_Area
Definition: mythuitype.h:249
QList< AbstractAnimation * > m_group
Definition: galleryslide.h:103
QChar GetDebugState() const
Return debug status.
void SetSpeed(float speed) override
Change speed of current child animation and all subsequent ones.
const char * name
Definition: ParseText.cpp:328
void Clear()
Reset slide to unused state.
void SetPan(QPoint pos)
Sets slide pan.
void ImageLoaded(Slide *)
Generated when the last requested image has loaded.
#define SBLOC
#define MIN_ZOOM
Definition: galleryslide.h:20
~Slide()
Destructor.
QSharedPointer< ImageItemK > ImagePtrK
Definition: imagetypes.h:179
MythMainWindow * GetMythMainWindow(void)
void Set(const QVariant &from, const QVariant &to, int duration=500, const QEasingCurve &curve=QEasingCurve::InOutCubic, UIEffects::Centre=UIEffects::Middle)
Initialises an animation.
Slide * m_parent
Image to be animated.
Definition: galleryslide.h:81
void LoadComplete()
virtual void SetArea(const MythRect &rect)
Definition: mythuitype.cpp:591
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void Zoom(int percentage)
Initiate slide zoom.
A specialised image for slideshows.
Definition: galleryslide.h:155
int m_direction
Navigation that created this image, -1 = Prev, 0 = Update, 1 = Next.
Definition: galleryslide.h:195
#define LOC
QQueue< Slide * > m_queue
Queue of slides.
Definition: galleryslide.h:250
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
ImagePtrK m_waitingFor
The most recently requested image. Null for preloads. Differs from m_data when skipping.
Definition: galleryslide.h:192
QHash< int, MythImage * > m_Images
Definition: mythuiimage.h:170
A single animation controlling alpha, zoom, rotation and position.
Definition: galleryslide.h:55
#define SLIDE_BUFFER_SIZE
MythUIType * m_Parent
Definition: mythuitype.h:270
unsigned int m_CurPos
Definition: mythuiimage.h:178
Animation * m_zoomAnimation
Dedicated animation for zoom, if supported.
Definition: galleryslide.h:196
void Start(bool forwards, float speed=1.0) override
Start parallel group. All children play simultaneously.
int m_current
Index of child currently playing.
Definition: galleryslide.h:122
void Pulse(int interval) override
Progress parallel animations.
void Pulse(int interval) override
Progress single animation.
QString BufferState()
Determines buffer state for debug logging.
void SetAngle(float angle)
Definition: mythuitype.cpp:961
void Clear() override
Delete all child animations.
int m_finished
Count of child animations that have finished.
Definition: galleryslide.h:140
UIEffects::Centre m_centre
Definition: galleryslide.h:83
void SetCentre(UIEffects::Centre centre)
Definition: mythuitype.cpp:938
void Start(bool forwards=true, float speed=1.0) override
Start a single animation.
void AddChild(MythUIType *child)
Add a child UIType.
Definition: mythuitype.cpp:85
void SlideReady(int count)
Signals that buffer has (count) loaded slides awaiting display.
Type m_type
Definition: galleryslide.h:82