Commit 095628c6 authored by John Rassa's avatar John Rassa Committed by Subs

added origin and rotation support to guicomponent, exposed as theme options for several components

parent 46cd1553
......@@ -532,6 +532,10 @@ Can be created as an extra.
- The image will be resized as large as possible so that it fits within this size and maintains its aspect ratio. Use this instead of `size` when you don't know what kind of image you're using so it doesn't get grossly oversized on one axis (e.g. with a game's image metadata).
* `origin` - type: NORMALIZED_PAIR.
- Where on the image `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the image exactly in the middle of the screen. If the "POSITION" and "SIZE" attributes are themable, "ORIGIN" is implied.
* `rotation` - type: FLOAT.
- angle in degrees that the image should be rotated. Positive values will rotate clockwise, negative values will rotate counterclockwise.
* `rotationOrigin` - type: NORMALIZED_PAIR.
- Point around which the image will be rotated. Defaults to `0.5 0.5`.
* `path` - type: PATH.
- Path to the image file. Most common extensions are supported (including .jpg, .png, and unanimated .gif).
* `tile` - type: BOOLEAN.
......@@ -551,6 +555,12 @@ Can be created as an extra.
- `0 0` - automatically size so text fits on one line (expanding horizontally).
- `w 0` - automatically wrap text so it doesn't go beyond `w` (expanding vertically).
- `w h` - works like a "text box." If `h` is non-zero and `h` <= `fontSize` (implying it should be a single line of text), text that goes beyond `w` will be truncated with an elipses (...).
* `origin` - type: NORMALIZED_PAIR.
- Where on the component `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the component exactly in the middle of the screen. If the "POSITION" and "SIZE" attributes are themable, "ORIGIN" is implied.
* `rotation` - type: FLOAT.
- angle in degrees that the text should be rotated. Positive values will rotate clockwise, negative values will rotate counterclockwise.
* `rotationOrigin` - type: NORMALIZED_PAIR.
- Point around which the text will be rotated. Defaults to `0.5 0.5`.
* `text` - type: STRING.
* `color` - type: COLOR.
* `fontPath` - type: PATH.
......@@ -568,6 +578,8 @@ Can be created as an extra.
* `pos` - type: NORMALIZED_PAIR.
* `size` - type: NORMALIZED_PAIR.
* `origin` - type: NORMALIZED_PAIR.
- Where on the component `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the component exactly in the middle of the screen. If the "POSITION" and "SIZE" attributes are themable, "ORIGIN" is implied.
* `selectorColor` - type: COLOR.
- Color of the "selector bar."
* `selectorImagePath` - type: PATH.
......@@ -612,6 +624,12 @@ EmulationStation borrows the concept of "nine patches" from Android (or "9-Slice
* `pos` - type: NORMALIZED_PAIR.
* `size` - type: NORMALIZED_PAIR.
- Only one value is actually used. The other value should be zero. (e.g. specify width OR height, but not both. This is done to maintain the aspect ratio.)
* `origin` - type: NORMALIZED_PAIR.
- Where on the component `pos` refers to. For example, an origin of `0.5 0.5` and a `pos` of `0.5 0.5` would place the component exactly in the middle of the screen. If the "POSITION" and "SIZE" attributes are themable, "ORIGIN" is implied.
* `rotation` - type: FLOAT.
- angle in degrees that the rating should be rotated. Positive values will rotate clockwise, negative values will rotate counterclockwise.
* `rotationOrigin` - type: NORMALIZED_PAIR.
- Point around which the rating will be rotated. Defaults to `0.5 0.5`.
* `filledPath` - type: PATH.
- Path to the "filled star" image. Image must be square (width equals height).
* `unfilledPath` - type: PATH.
......
......@@ -87,7 +87,7 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
BasicGameListView::onThemeChanged(theme);
using namespace ThemeFlags;
mImage.applyTheme(theme, getName(), "md_image", POSITION | ThemeFlags::SIZE | Z_INDEX);
mImage.applyTheme(theme, getName(), "md_image", POSITION | ThemeFlags::SIZE | Z_INDEX | ROTATION);
initMDLabels();
std::vector<TextComponent*> labels = getMDLabels();
......@@ -151,7 +151,7 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
mDescContainer.applyTheme(theme, getName(), "md_description", POSITION | ThemeFlags::SIZE | Z_INDEX);
mDescription.setSize(mDescContainer.getSize().x(), 0);
mDescription.applyTheme(theme, getName(), "md_description", ALL ^ (POSITION | ThemeFlags::SIZE | TEXT));
mDescription.applyTheme(theme, getName(), "md_description", ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT));
sortChildren();
}
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
#include "Settings.h"
GuiComponent::GuiComponent(Window* window) : mWindow(window), mParent(NULL), mOpacity(255),
mPosition(Eigen::Vector3f::Zero()), mSize(Eigen::Vector2f::Zero()), mTransform(Eigen::Affine3f::Identity()), mIsProcessing(false)
mPosition(Eigen::Vector3f::Zero()), mOrigin(Eigen::Vector2f::Zero()), mRotationOrigin(0.5, 0.5), mSize(Eigen::Vector2f::Zero()), mTransform(Eigen::Affine3f::Identity()), mIsProcessing(false)
{
for(unsigned char i = 0; i < MAX_ANIMATIONS; i++)
mAnimationMap[i] = NULL;
......@@ -76,27 +76,36 @@ Eigen::Vector3f GuiComponent::getPosition() const
return mPosition;
}
void GuiComponent::setPosition(const Eigen::Vector3f& offset)
void GuiComponent::setPosition(float x, float y, float z)
{
mPosition = offset;
mPosition << x, y, z;
onPositionChanged();
}
void GuiComponent::setPosition(float x, float y, float z)
Eigen::Vector2f GuiComponent::getOrigin() const
{
mPosition << x, y, z;
onPositionChanged();
return mOrigin;
}
Eigen::Vector2f GuiComponent::getSize() const
void GuiComponent::setOrigin(float x, float y)
{
return mSize;
mOrigin << x, y;
onOriginChanged();
}
void GuiComponent::setSize(const Eigen::Vector2f& size)
Eigen::Vector2f GuiComponent::getRotationOrigin() const
{
mSize = size;
onSizeChanged();
return mRotationOrigin;
}
void GuiComponent::setRotationOrigin(float x, float y)
{
mRotationOrigin << x, y;;
}
Eigen::Vector2f GuiComponent::getSize() const
{
return mSize;
}
void GuiComponent::setSize(float w, float h)
......@@ -105,6 +114,27 @@ void GuiComponent::setSize(float w, float h)
onSizeChanged();
}
float GuiComponent::getRotation() const
{
return mRotation;
}
void GuiComponent::setRotation(float rotation)
{
mRotation = rotation;
}
float GuiComponent::getScale() const
{
return mScale;
}
void GuiComponent::setScale(float scale)
{
mScale = scale;
onSizeChanged();
}
float GuiComponent::getZIndex() const
{
return mZIndex;
......@@ -125,6 +155,12 @@ float GuiComponent::getZIndex() const
mDefaultZIndex = z;
}
Eigen::Vector2f GuiComponent::getCenter() const
{
return Eigen::Vector2f(mPosition.x() - (getSize().x() * mOrigin.x()) + getSize().x() / 2,
mPosition.y() - (getSize().y() * mOrigin.y()) + getSize().y() / 2);
}
//Children stuff.
void GuiComponent::addChild(GuiComponent* cmp)
{
......@@ -208,6 +244,28 @@ const Eigen::Affine3f& GuiComponent::getTransform()
{
mTransform.setIdentity();
mTransform.translate(mPosition);
if (mScale != 1.0)
{
mTransform *= Eigen::Scaling(mScale);
}
if (mRotation != 0.0)
{
// Calculate offset as difference between origin and rotation origin
float xOff = (mOrigin.x() - mRotationOrigin.x()) * mSize.x();
float yOff = (mOrigin.y() - mRotationOrigin.y()) * mSize.y();
// transform to offset point
if (xOff != 0.0 || yOff != 0.0)
mTransform.translate(Eigen::Vector3f(xOff * -1, yOff * -1, 0.0f));
// apply rotation transorm
mTransform *= Eigen::AngleAxisf(mRotation, Eigen::Vector3f::UnitZ());
// Tranform back to original point
if (xOff != 0.0 || yOff != 0.0)
mTransform.translate(Eigen::Vector3f(xOff, yOff, 0.0f));
}
mTransform.translate(Eigen::Vector3f(mOrigin.x() * mSize.x() * -1, mOrigin.y() * mSize.y() * -1, 0.0f));
return mTransform;
}
......@@ -351,6 +409,17 @@ void GuiComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std
if(properties & ThemeFlags::SIZE && elem->has("size"))
setSize(elem->get<Eigen::Vector2f>("size").cwiseProduct(scale));
// position + size also implies origin
if((properties & ORIGIN || (properties & POSITION && properties & ThemeFlags::SIZE)) && elem->has("origin"))
setOrigin(elem->get<Eigen::Vector2f>("origin"));
if(properties & ThemeFlags::ROTATION) {
if(elem->has("rotation"))
setRotationDegrees(elem->get<float>("rotation"));
if(elem->has("rotationOrigin"))
setRotationOrigin(elem->get<Eigen::Vector2f>("rotationOrigin"));
}
if(properties & ThemeFlags::Z_INDEX && elem->has("zIndex"))
setZIndex(elem->get<float>("zIndex"));
......
......@@ -37,20 +37,41 @@ public:
virtual void render(const Eigen::Affine3f& parentTrans);
Eigen::Vector3f getPosition() const;
void setPosition(const Eigen::Vector3f& offset);
inline void setPosition(const Eigen::Vector3f& offset) { setPosition(offset.x(), offset.y(), offset.z()); }
void setPosition(float x, float y, float z = 0.0f);
virtual void onPositionChanged() {};
//Sets the origin as a percentage of this image (e.g. (0, 0) is top left, (0.5, 0.5) is the center)
Eigen::Vector2f getOrigin() const;
void setOrigin(float originX, float originY);
inline void setOrigin(Eigen::Vector2f origin) { setOrigin(origin.x(), origin.y()); }
virtual void onOriginChanged() {};
//Sets the rotation origin as a percentage of this image (e.g. (0, 0) is top left, (0.5, 0.5) is the center)
Eigen::Vector2f getRotationOrigin() const;
void setRotationOrigin(float originX, float originY);
inline void setRotationOrigin(Eigen::Vector2f origin) { setRotationOrigin(origin.x(), origin.y()); }
Eigen::Vector2f getSize() const;
void setSize(const Eigen::Vector2f& size);
inline void setSize(const Eigen::Vector2f& size) { setSize(size.x(), size.y()); }
void setSize(float w, float h);
virtual void onSizeChanged() {};
float getRotation() const;
void setRotation(float rotation);
inline void setRotationDegrees(float rotation) { setRotation(rotation * M_PI / 180); }
float getScale() const;
void setScale(float scale);
float getZIndex() const;
void setZIndex(float zIndex);
float getDefaultZIndex() const;
void setDefaultZIndex(float zIndex);
// Returns the center point of the image (takes origin into account).
Eigen::Vector2f getCenter() const;
void setParent(GuiComponent* parent);
GuiComponent* getParent() const;
......@@ -115,7 +136,12 @@ protected:
std::vector<GuiComponent*> mChildren;
Eigen::Vector3f mPosition;
Eigen::Vector2f mOrigin;
Eigen::Vector2f mRotationOrigin;
Eigen::Vector2f mSize;
float mRotation = 0.0;
float mScale = 1.0;
float mDefaultZIndex = 0;
float mZIndex = 0;
......
......@@ -33,6 +33,8 @@ std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign::
("size", NORMALIZED_PAIR)
("maxSize", NORMALIZED_PAIR)
("origin", NORMALIZED_PAIR)
("rotation", FLOAT)
("rotationOrigin", NORMALIZED_PAIR)
("path", PATH)
("tile", BOOLEAN)
("color", COLOR)
......@@ -40,6 +42,9 @@ std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign::
("text", makeMap(boost::assign::map_list_of
("pos", NORMALIZED_PAIR)
("size", NORMALIZED_PAIR)
("origin", NORMALIZED_PAIR)
("rotation", FLOAT)
("rotationOrigin", NORMALIZED_PAIR)
("text", STRING)
("backgroundColor", COLOR)
("fontPath", PATH)
......@@ -53,6 +58,7 @@ std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign::
("textlist", makeMap(boost::assign::map_list_of
("pos", NORMALIZED_PAIR)
("size", NORMALIZED_PAIR)
("origin", NORMALIZED_PAIR)
("selectorHeight", FLOAT)
("selectorOffsetY", FLOAT)
("selectorColor", COLOR)
......@@ -72,6 +78,7 @@ std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign::
("container", makeMap(boost::assign::map_list_of
("pos", NORMALIZED_PAIR)
("size", NORMALIZED_PAIR)
("origin", NORMALIZED_PAIR)
("zIndex", FLOAT)))
("ninepatch", makeMap(boost::assign::map_list_of
("pos", NORMALIZED_PAIR)
......@@ -89,6 +96,9 @@ std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign::
("rating", makeMap(boost::assign::map_list_of
("pos", NORMALIZED_PAIR)
("size", NORMALIZED_PAIR)
("origin", NORMALIZED_PAIR)
("rotation", FLOAT)
("rotationOrigin", NORMALIZED_PAIR)
("filledPath", PATH)
("unfilledPath", PATH)
("zIndex", FLOAT)))
......
......@@ -38,6 +38,7 @@ namespace ThemeFlags
FORCE_UPPERCASE = 1024,
LINE_SPACING = 2048,
Z_INDEX = 8192,
ROTATION = 16384,
ALL = 0xFFFFFFFF
};
......
......@@ -13,17 +13,11 @@ Eigen::Vector2i ImageComponent::getTextureSize() const
if(mTexture)
return mTexture->getSize();
else
return Eigen::Vector2i(0, 0);
}
Eigen::Vector2f ImageComponent::getCenter() const
{
return Eigen::Vector2f(mPosition.x() - (getSize().x() * mOrigin.x()) + getSize().x() / 2,
mPosition.y() - (getSize().y() * mOrigin.y()) + getSize().y() / 2);
return Eigen::Vector2i::Zero();
}
ImageComponent::ImageComponent(Window* window, bool forceLoad, bool dynamic) : GuiComponent(window),
mTargetIsMax(false), mFlipX(false), mFlipY(false), mOrigin(0.0, 0.0), mTargetSize(0, 0), mColorShift(0xFFFFFFFF),
mTargetIsMax(false), mFlipX(false), mFlipY(false), mTargetSize(0, 0), mColorShift(0xFFFFFFFF),
mForceLoad(forceLoad), mDynamic(dynamic), mFadeOpacity(0.0f), mFading(false)
{
updateColors();
......@@ -127,12 +121,6 @@ void ImageComponent::setImage(const std::shared_ptr<TextureResource>& texture)
resize();
}
void ImageComponent::setOrigin(float originX, float originY)
{
mOrigin << originX, originY;
updateVertices();
}
void ImageComponent::setResize(float width, float height)
{
mTargetSize << width, height;
......@@ -186,16 +174,8 @@ void ImageComponent::updateVertices()
// we go through this mess to make sure everything is properly rounded
// if we just round vertices at the end, edge cases occur near sizes of 0.5
Eigen::Vector2f topLeft(-mSize.x() * mOrigin.x(), -mSize.y() * mOrigin.y());
Eigen::Vector2f bottomRight(mSize.x() * (1 -mOrigin.x()), mSize.y() * (1 - mOrigin.y()));
const float width = round(bottomRight.x() - topLeft.x());
const float height = round(bottomRight.y() - topLeft.y());
topLeft[0] = floor(topLeft[0]);
topLeft[1] = floor(topLeft[1]);
bottomRight[0] = topLeft[0] + width;
bottomRight[1] = topLeft[1] + height;
Eigen::Vector2f topLeft(0.0, 0.0);
Eigen::Vector2f bottomRight(round(mSize.x()), round(mSize.y()));
mVertices[0].pos << topLeft.x(), topLeft.y();
mVertices[1].pos << topLeft.x(), bottomRight.y();
......@@ -242,7 +222,7 @@ void ImageComponent::updateColors()
void ImageComponent::render(const Eigen::Affine3f& parentTrans)
{
Eigen::Affine3f trans = roundMatrix(parentTrans * getTransform());
Eigen::Affine3f trans = parentTrans * getTransform();
Renderer::setMatrix(trans);
if(mTexture && mOpacity > 0)
......@@ -368,6 +348,13 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const s
if(properties & COLOR && elem->has("color"))
setColorShift(elem->get<unsigned int>("color"));
if(properties & ThemeFlags::ROTATION) {
if(elem->has("rotation"))
setRotationDegrees(elem->get<float>("rotation"));
if(elem->has("rotationOrigin"))
setRotationOrigin(elem->get<Eigen::Vector2f>("rotationOrigin"));
}
if(properties & ThemeFlags::Z_INDEX && elem->has("zIndex"))
setZIndex(elem->get<float>("zIndex"));
......
......@@ -25,10 +25,6 @@ public:
void onSizeChanged() override;
void setOpacity(unsigned char opacity) override;
//Sets the origin as a percentage of this image (e.g. (0, 0) is top left, (0.5, 0.5) is the center)
void setOrigin(float originX, float originY);
inline void setOrigin(Eigen::Vector2f origin) { setOrigin(origin.x(), origin.y()); }
// Resize the image to fit this size. If one axis is zero, scale that axis to maintain aspect ratio.
// If both are non-zero, potentially break the aspect ratio. If both are zero, no resizing.
// Can be set before or after an image is loaded.
......@@ -52,9 +48,6 @@ public:
// Returns the size of the current texture, or (0, 0) if none is loaded. May be different than drawn size (use getSize() for that).
Eigen::Vector2i getTextureSize() const;
// Returns the center point of the image (takes origin into account).
Eigen::Vector2f getCenter() const;
bool hasImage();
void render(const Eigen::Affine3f& parentTrans) override;
......@@ -64,7 +57,6 @@ public:
virtual std::vector<HelpPrompt> getHelpPrompts() override;
private:
Eigen::Vector2f mTargetSize;
Eigen::Vector2f mOrigin;
bool mFlipX, mFlipY, mTargetIsMax;
......
#include "components/VideoComponent.h"
#include "Renderer.h"
#include "ThemeData.h"
#include "Util.h"
#include "Window.h"
#ifdef WIN32
#include <codecvt>
#endif
#define FADE_TIME_MS 200
std::string getTitlePath() {
std::string titleFolder = getTitleFolder();
return titleFolder + "last_title.srt";
}
std::string getTitleFolder() {
std::string home = getHomePath();
return home + "/.emulationstation/tmp/";
}
void writeSubtitle(const char* gameName, const char* systemName, bool always)
{
FILE* file = fopen(getTitlePath().c_str(), "w");
if (always) {
fprintf(file, "1\n00:00:01,000 --> 00:00:30,000\n");
}
else
{
fprintf(file, "1\n00:00:01,000 --> 00:00:08,000\n");
}
fprintf(file, "%s\n", gameName);
fprintf(file, "<i>%s</i>\n\n", systemName);
if (!always) {
fprintf(file, "2\n00:00:26,000 --> 00:00:30,000\n");
fprintf(file, "%s\n", gameName);
fprintf(file, "<i>%s</i>\n", systemName);
}
fflush(file);
fclose(file);
file = NULL;
}
void VideoComponent::setScreensaverMode(bool isScreensaver)
{
mScreensaverMode = isScreensaver;
}
VideoComponent::VideoComponent(Window* window) :
GuiComponent(window),
mStaticImage(window),
mVideoHeight(0),
mVideoWidth(0),
mStartDelayed(false),
mIsPlaying(false),
mShowing(false),
mScreensaverActive(false),
mDisable(false),
mScreensaverMode(false),
mTargetIsMax(false),
mTargetSize(0, 0)
{
// Setup the default configuration
mConfig.showSnapshotDelay = false;
mConfig.showSnapshotNoVideo = false;
mConfig.startDelay = 0;
if (mWindow->getGuiStackSize() > 1) {
topWindow(false);
}
std::string path = getTitleFolder();
if(!boost::filesystem::exists(path))
boost::filesystem::create_directory(path);
}
VideoComponent::~VideoComponent()
{
// Stop any currently running video
stopVideo();
// Delete subtitle file, if existing
remove(getTitlePath().c_str());
}
void VideoComponent::onOriginChanged()
{
// Update the embeded static image
mStaticImage.setOrigin(mOrigin);
}
void VideoComponent::onSizeChanged()
{
// Update the embeded static image
mStaticImage.onSizeChanged();
}
bool VideoComponent::setVideo(std::string path)
{
// Convert the path into a generic format
boost::filesystem::path fullPath = getCanonicalPath(path);
fullPath.make_preferred().native();
// Check that it's changed
if (fullPath == mVideoPath)
return !path.empty();
// Store the path
mVideoPath = fullPath;
// If the file exists then set the new video
if (!fullPath.empty() && ResourceManager::getInstance()->fileExists(fullPath.generic_string()))
{
// Return true to show that we are going to attempt to play a video
return true;
}
// Return false to show that no video will be displayed
return false;
}
void VideoComponent::setImage(std::string path)
{
// Check that the image has changed
if (path == mStaticImagePath)
return;
mStaticImage.setImage(path);
mFadeIn = 0.0f;
mStaticImagePath = path;
}
void VideoComponent::setDefaultVideo()
{
setVideo(mConfig.defaultVideoPath);
}
void VideoComponent::setOpacity(unsigned char opacity)
{
mOpacity = opacity;
// Update the embeded static image
mStaticImage.setOpacity(opacity);
}
void VideoComponent::render(const Eigen::Affine3f& parentTrans)
{
float x, y;
Eigen::Affine3f trans = parentTrans * getTransform();
GuiComponent::renderChildren(trans);
Renderer::setMatrix(trans);
// Handle the case where the video is delayed
handleStartDelay();
// Handle looping of the video
handleLooping();
}
void VideoComponent::renderSnapshot(const Eigen::Affine3f& parentTrans)
{
// This is the case where the video is not currently being displayed. Work out
// if we need to display a static image
if ((mConfig.showSnapshotNoVideo && mVideoPath.empty()) || (mStartDelayed && mConfig.showSnapshotDelay))
{
// Display the static image instead
mStaticImage.setOpacity((unsigned char)(mFadeIn * 255.0f));
mStaticImage.render(parentTrans);
}
}
void VideoComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
{
using namespace ThemeFlags;
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "video");
if(!elem)
{
return;
}
Eigen::Vector2f scale = getParent() ? getParent()->getSize() : Eigen::Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
if ((properties & POSITION) && elem->has("pos"))
{
Eigen::Vector2f denormalized = elem->get<Eigen::Vector2f>("pos").cwiseProduct(scale);
setPosition(Eigen::Vector3f(denormalized.x(), denormalized.y(), 0));
mStaticImage.setPosition(Eigen::Vector3f(denormalized.x(), denormalized.y(), 0));
}
if(properties & ThemeFlags::SIZE)
{
if(elem->has("size"))
setResize(elem->get<Eigen::Vector2f>("size").cwiseProduct(scale));
else if(elem->has("maxSize"))
setMaxSize(elem->get<Eigen::Vector2f>("maxSize").cwiseProduct(scale));
}
// position + size also implies origin
if (((properties & ORIGIN) || ((properties & POSITION) && (properties & ThemeFlags::SIZE))) && elem->has("origin"))
setOrigin(elem->get<Eigen::Vector2f>("origin"));
if(elem->has("default"))
mConfig.defaultVideoPath = elem->get<std::string>("default");
if((properties & ThemeFlags::DELAY) && elem->has("delay"))
mConfig.startDelay = (unsigned)(elem->get<float>("delay") * 1000.0f);
if (elem->has("showSnapshotNoVideo"))
mConfig.showSnapshotNoVideo = elem->get<bool>("showSnapshotNoVideo");
if (elem->has("showSnapshotDelay"))
mConfig.showSnapshotDelay = elem->get<bool>("showSnapshotDelay");
if(properties & ThemeFlags::ROTATION) {
if(elem->has("rotation"))
setRotationDegrees(elem->get<float>("rotation"));
if(elem->has("rotationOrigin"))
setRotationOrigin(elem->get<Eigen::Vector2f>("rotationOrigin"));
}
if(properties & ThemeFlags::Z_INDEX && elem->has("zIndex"))
setZIndex(elem->get<float>("zIndex"));
else
setZIndex(getDefaultZIndex());
}
std::vector<HelpPrompt> VideoComponent::getHelpPrompts()
{
std::vector<HelpPrompt> ret;
ret.push_back(HelpPrompt("a", "select"));
return ret;
}
void VideoComponent::handleStartDelay()
{
// Only play if any delay has timed out
if (mStartDelayed)
{
if (mStartTime > SDL_GetTicks())
{
// Timeout not yet completed
return;
}
// Completed
mStartDelayed = false;
// Clear the playing flag so startVideo works
mIsPlaying = false;
startVideo();
}
}
void VideoComponent::handleLooping()
{
}
void VideoComponent::startVideoWithDelay()
{
// If not playing then either start the video or initiate the delay
if (!mIsPlaying)
{
// Set the video that we are going to be playing so we don't attempt to restart it
mPlayingVideoPath = mVideoPath;
if (mConfig.startDelay == 0)
{
// No delay. Just start the video
mStartDelayed = false;
startVideo();
}
else
{
// Configure the start delay
mStartDelayed = true;
mFadeIn = 0.0f;
mStartTime = SDL_GetTicks() + mConfig.startDelay;
}
mIsPlaying = true;
}
}
void VideoComponent::update(int deltaTime)
{
manageState();
// If the video start is delayed and there is less than the fade time then set the image fade
// accordingly
if (mStartDelayed)
{
Uint32 ticks = SDL_GetTicks();