System Carousel feature, now with only a single commit!

This commit is contained in:
D. Polders 2017-03-13 22:11:07 +01:00
parent 6cb81ab1af
commit ac5e3ad95f
9 changed files with 325 additions and 133 deletions

3
.gitignore vendored
View file

@ -34,6 +34,3 @@ Makefile
.cproject .cproject
.project .project
.settings/ .settings/
# WinMerge
.bak

View file

@ -86,7 +86,7 @@ if(CMAKE_COMPILER_IS_GNUCXX)
#set up compiler flags for GCC #set up compiler flags for GCC
if (CMAKE_BUILD_TYPE MATCHES Debug) if (CMAKE_BUILD_TYPE MATCHES Debug)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-attributes -O0") #support C++11 for std::, optimize set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-attributes -O0") #support C++11 for std::, optimize
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O0") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O0")
else() else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-attributes -O3") #support C++11 for std::, optimize set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-attributes -O3") #support C++11 for std::, optimize

View file

@ -400,8 +400,12 @@ Reference
#### system #### system
* `helpsystem name="help"` - ALL * `helpsystem name="help"` - ALL
- The help system style for this view. - The help system style for this view.
* `carousel name="systemcarousel"` -ALL
- The system logo carousel
* `image name="logo"` - PATH * `image name="logo"` - PATH
- A logo image, to be displayed in the system logo carousel. - A logo image, to be displayed in the system logo carousel.
* `text name="systemInfo"` - ALL
- Displays details of the system currently selected in the carousel.
* You can use extra elements (elements with `extra="true"`) to add your own backgrounds, etc. They will be displayed behind the carousel, and scroll relative to the carousel. * You can use extra elements (elements with `extra="true"`) to add your own backgrounds, etc. They will be displayed behind the carousel, and scroll relative to the carousel.
@ -468,6 +472,7 @@ Can be created as an extra.
- `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 (...). - `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 (...).
* `text` - type: STRING. * `text` - type: STRING.
* `color` - type: COLOR. * `color` - type: COLOR.
* `backgroundColor` - type: COLOR;
* `fontPath` - type: PATH. * `fontPath` - type: PATH.
- Path to a truetype font (.ttf). - Path to a truetype font (.ttf).
* `fontSize` - type: FLOAT. * `fontSize` - type: FLOAT.
@ -541,6 +546,24 @@ EmulationStation borrows the concept of "nine patches" from Android (or "9-Slice
* `fontPath` - type: PATH. * `fontPath` - type: PATH.
* `fontSize` - type: FLOAT. * `fontSize` - type: FLOAT.
#### carousel
* `type` - type: STRING.
* Accepted values are "HORIZONTAL" or "VERTICAL". Sets the scoll direction of the carousel.
* Default is "HORIZONTAL".
* `size` - type: NORMALIZED_PAIR. Default is "1 0.2325"
* `pos` - type: NORMALIZED_PAIR. Default is "0 0.38375".
* `color` - type: COLOR.
* Controls the color of the carousel background.
* Default is FFFFFFD8
* `logoSize` - type: NORMALIZED_PAIR. Default is "0.25 0.155"
* `logoScale` - type: FLOAT.
* Selected logo is increased in size by this scale
* Default is 1.5
* `maxLogoCount` - type: FLOAT.
* Sets the number of logos to display in the carousel.
* Default is 3
The help system is a special element that displays a context-sensitive list of actions the user can take at any time. You should try and keep the position constant throughout every screen. Keep in mind the "default" settings (including position) are used whenever the user opens a menu. The help system is a special element that displays a context-sensitive list of actions the user can take at any time. You should try and keep the position constant throughout every screen. Keep in mind the "default" settings (including position) are used whenever the user opens a menu.
[*Check out the "official" themes for some more examples!*](http://aloshi.com/emulationstation#themes) [*Check out the "official" themes for some more examples!*](http://aloshi.com/emulationstation#themes)

View file

@ -9,22 +9,15 @@
#include "Settings.h" #include "Settings.h"
#include "Util.h" #include "Util.h"
#define SELECTED_SCALE 1.5f
#define LOGO_PADDING ((logoSize().x() * (SELECTED_SCALE - 1)/2) + (mSize.x() * 0.06f))
#define BAND_HEIGHT (logoSize().y() * SELECTED_SCALE)
SystemView::SystemView(Window* window) : IList<SystemViewData, SystemData*>(window, LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP), SystemView::SystemView(Window* window) : IList<SystemViewData, SystemData*>(window, LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP),
mSystemInfo(window, "SYSTEM INFO", Font::get(FONT_SIZE_SMALL), 0x33333300, ALIGN_CENTER) mViewNeedsReload(true),
mSystemInfo(window, "SYSTEM INFO", Font::get(FONT_SIZE_SMALL), 0x33333300, ALIGN_CENTER)
{ {
mCamOffset = 0; mCamOffset = 0;
mExtrasCamOffset = 0; mExtrasCamOffset = 0;
mExtrasFadeOpacity = 0.0f; mExtrasFadeOpacity = 0.0f;
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
mSystemInfo.setSize(mSize.x(), mSystemInfo.getSize().y() * 1.333f);
mSystemInfo.setPosition(0, (mSize.y() + BAND_HEIGHT) / 2);
populate(); populate();
} }
@ -36,6 +29,9 @@ void SystemView::populate()
{ {
const std::shared_ptr<ThemeData>& theme = (*it)->getTheme(); const std::shared_ptr<ThemeData>& theme = (*it)->getTheme();
if(mViewNeedsReload)
getViewElements(theme);
Entry e; Entry e;
e.name = (*it)->getName(); e.name = (*it)->getName();
e.object = *it; e.object = *it;
@ -43,18 +39,20 @@ void SystemView::populate()
// make logo // make logo
if(theme->getElement("system", "logo", "image")) if(theme->getElement("system", "logo", "image"))
{ {
ImageComponent* logo = new ImageComponent(mWindow, false, false); ImageComponent* logo = new ImageComponent(mWindow);
logo->setMaxSize(Eigen::Vector2f(logoSize().x(), logoSize().y())); logo->setMaxSize(Eigen::Vector2f(mCarousel.logoSize.x(), mCarousel.logoSize.y()));
logo->applyTheme((*it)->getTheme(), "system", "logo", ThemeFlags::PATH); logo->applyTheme((*it)->getTheme(), "system", "logo", ThemeFlags::PATH);
logo->setPosition((logoSize().x() - logo->getSize().x()) / 2, (logoSize().y() - logo->getSize().y()) / 2); // center logo->setPosition((mCarousel.logoSize.x() - logo->getSize().x()) / 2,
(mCarousel.logoSize.y() - logo->getSize().y()) / 2); // center
e.data.logo = std::shared_ptr<GuiComponent>(logo); e.data.logo = std::shared_ptr<GuiComponent>(logo);
ImageComponent* logoSelected = new ImageComponent(mWindow, false, false); ImageComponent* logoSelected = new ImageComponent(mWindow);
logoSelected->setMaxSize(Eigen::Vector2f(logoSize().x() * SELECTED_SCALE, logoSize().y() * SELECTED_SCALE * 0.70f)); logoSelected->setMaxSize(Eigen::Vector2f(mCarousel.logoSize.x() * mCarousel.logoScale, mCarousel.logoSize.y() * mCarousel.logoScale));
logoSelected->applyTheme((*it)->getTheme(), "system", "logo", ThemeFlags::PATH); logoSelected->applyTheme((*it)->getTheme(), "system", "logo", ThemeFlags::PATH | ThemeFlags::COLOR);
logoSelected->setPosition((logoSize().x() - logoSelected->getSize().x()) / 2, logoSelected->setPosition((mCarousel.logoSize.x() - logoSelected->getSize().x()) / 2,
(logoSize().y() - logoSelected->getSize().y()) / 2); // center (mCarousel.logoSize.y() - logoSelected->getSize().y()) / 2); // center
e.data.logoSelected = std::shared_ptr<GuiComponent>(logoSelected); e.data.logoSelected = std::shared_ptr<GuiComponent>(logoSelected);
}else{ }else{
// no logo in theme; use text // no logo in theme; use text
TextComponent* text = new TextComponent(mWindow, TextComponent* text = new TextComponent(mWindow,
@ -62,15 +60,15 @@ void SystemView::populate()
Font::get(FONT_SIZE_LARGE), Font::get(FONT_SIZE_LARGE),
0x000000FF, 0x000000FF,
ALIGN_CENTER); ALIGN_CENTER);
text->setSize(logoSize()); text->setSize(mCarousel.logoSize);
e.data.logo = std::shared_ptr<GuiComponent>(text); e.data.logo = std::shared_ptr<GuiComponent>(text);
TextComponent* textSelected = new TextComponent(mWindow, TextComponent* textSelected = new TextComponent(mWindow,
(*it)->getName(), (*it)->getName(),
Font::get((int)(FONT_SIZE_LARGE * SELECTED_SCALE)), Font::get((int)(FONT_SIZE_LARGE * 1.5)),
0x000000FF, 0x000000FF,
ALIGN_CENTER); ALIGN_CENTER);
textSelected->setSize(logoSize()); textSelected->setSize(mCarousel.logoSize);
e.data.logoSelected = std::shared_ptr<GuiComponent>(textSelected); e.data.logoSelected = std::shared_ptr<GuiComponent>(textSelected);
} }
@ -96,26 +94,40 @@ bool SystemView::input(InputConfig* config, Input input)
{ {
if(config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_r && SDL_GetModState() & KMOD_LCTRL && Settings::getInstance()->getBool("Debug")) if(config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_r && SDL_GetModState() & KMOD_LCTRL && Settings::getInstance()->getBool("Debug"))
{ {
LOG(LogInfo) << " Reloading SystemList view"; LOG(LogInfo) << " Reloading all";
ViewController::get()->reloadAll();
return true;
}
// reload themes switch (mCarousel.type)
for(auto it = mEntries.begin(); it != mEntries.end(); it++) {
it->object->loadTheme(); case VERTICAL:
if (config->isMappedTo("up", input))
{
listInput(-1);
return true;
}
if (config->isMappedTo("down", input))
{
listInput(1);
return true;
}
break;
case HORIZONTAL:
default:
if (config->isMappedTo("left", input))
{
listInput(-1);
return true;
}
if (config->isMappedTo("right", input))
{
listInput(1);
return true;
}
break;
}
populate();
updateHelpPrompts();
return true;
}
if(config->isMappedTo("left", input))
{
listInput(-1);
return true;
}
if(config->isMappedTo("right", input))
{
listInput(1);
return true;
}
if(config->isMappedTo("a", input)) if(config->isMappedTo("a", input))
{ {
stopScrolling(); stopScrolling();
@ -123,7 +135,10 @@ bool SystemView::input(InputConfig* config, Input input)
return true; return true;
} }
}else{ }else{
if(config->isMappedTo("left", input) || config->isMappedTo("right", input)) if(config->isMappedTo("left", input) ||
config->isMappedTo("right", input) ||
config->isMappedTo("up", input) ||
config->isMappedTo("down", input))
listInput(0); listInput(0);
} }
@ -254,28 +269,136 @@ void SystemView::onCursorChanged(const CursorState& state)
void SystemView::render(const Eigen::Affine3f& parentTrans) void SystemView::render(const Eigen::Affine3f& parentTrans)
{ {
if(size() == 0) if(size() == 0)
return; return; // nothing to render
Eigen::Affine3f trans = getTransform() * parentTrans;
// draw the list elements (titles, backgrounds, logos) Eigen::Affine3f trans = getTransform() * parentTrans;
const float logoSizeX = logoSize().x() + LOGO_PADDING;
int logoCount = (int)(mSize.x() / logoSizeX) + 2; // how many logos we need to draw renderExtras(trans);
renderCarousel(trans);
renderInfoBar(trans);
}
std::vector<HelpPrompt> SystemView::getHelpPrompts()
{
std::vector<HelpPrompt> prompts;
if (mCarousel.type == VERTICAL)
prompts.push_back(HelpPrompt("up/down", "choose"));
else
prompts.push_back(HelpPrompt("left/right", "choose"));
prompts.push_back(HelpPrompt("a", "select"));
return prompts;
}
HelpStyle SystemView::getHelpStyle()
{
HelpStyle style;
style.applyTheme(mEntries.at(mCursor).object->getTheme(), "system");
return style;
}
void SystemView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
{
LOG(LogDebug) << "SystemView::onThemeChanged()";
mViewNeedsReload = true;
populate();
}
// Get the ThemeElements that make up the SystemView.
void SystemView::getViewElements(const std::shared_ptr<ThemeData>& theme)
{
LOG(LogDebug) << "SystemView::getViewElements()";
getDefaultElements();
const ThemeData::ThemeElement* carouselElem = theme->getElement("system", "systemcarousel", "carousel");
if (carouselElem)
getCarouselFromTheme(carouselElem);
const ThemeData::ThemeElement* sysInfoElem = theme->getElement("system", "systemInfo", "text");
if (sysInfoElem)
mSystemInfo.applyTheme(theme, "system", "systemInfo", ThemeFlags::ALL);
mViewNeedsReload = false;
}
// Render system carousel
void SystemView::renderCarousel(const Eigen::Affine3f& trans)
{
Eigen::Vector2i clipPos((int)mCarousel.pos.x(), (int)mCarousel.pos.y());
Eigen::Vector2i clipSize((int)mCarousel.size.x(), (int)mCarousel.size.y());
Renderer::pushClipRect(clipPos, clipSize);
// background box behind logos
Renderer::setMatrix(trans);
Renderer::drawRect(mCarousel.pos.x(), mCarousel.pos.y(), mCarousel.size.x(), mCarousel.size.y(), mCarousel.color);
// draw logos
Eigen::Vector2f logoSpacing(0.0, 0.0); // NB: logoSpacing will include the size of the logo itself as well!
float xOff = 0.0;
float yOff = 0.0;
switch (mCarousel.type)
{
case VERTICAL:
logoSpacing[1] = ((mCarousel.size.y() - (mCarousel.logoSize.y() * mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.y();
xOff = mCarousel.pos.x() + (mCarousel.size.x() / 2) - (mCarousel.logoSize.x() / 2);
yOff = mCarousel.pos.y() + (mCarousel.size.y() - mCarousel.logoSize.y()) / 2 - (mCamOffset * logoSpacing[1]);
break;
case HORIZONTAL:
default:
logoSpacing[0] = ((mCarousel.size.x() - (mCarousel.logoSize.x() * mCarousel.maxLogoCount)) / (mCarousel.maxLogoCount)) + mCarousel.logoSize.x();
xOff = mCarousel.pos.x() + (mCarousel.size.x() - mCarousel.logoSize.x()) / 2 - (mCamOffset * logoSpacing[0]);
yOff = mCarousel.pos.y() + (mCarousel.size.y() / 2) - (mCarousel.logoSize.y() / 2);
break;
}
Eigen::Affine3f logoTrans = trans;
int center = (int)(mCamOffset); int center = (int)(mCamOffset);
int logoCount = std::min(mCarousel.maxLogoCount, (int)mEntries.size()) + 2;
if(mEntries.size() == 1) for (int i = center - logoCount / 2; i < center + logoCount / 2 + 1; i++)
logoCount = 1;
// draw background extras
Eigen::Affine3f extrasTrans = trans;
int extrasCenter = (int)mExtrasCamOffset;
for(int i = extrasCenter - 1; i < extrasCenter + 2; i++)
{ {
int index = i; int index = i;
while(index < 0) while (index < 0)
index += mEntries.size(); index += mEntries.size();
while(index >= (int)mEntries.size()) while (index >= (int)mEntries.size())
index -= mEntries.size();
logoTrans.translation() = trans.translation() + Eigen::Vector3f(i * logoSpacing[0] + xOff, i * logoSpacing [1] + yOff, 0);
if (index == mCursor) //Selected System
{
const std::shared_ptr<GuiComponent>& comp = mEntries.at(index).data.logoSelected;
comp->setOpacity(0xFF);
comp->render(logoTrans);
}
else { // not selected systems
const std::shared_ptr<GuiComponent>& comp = mEntries.at(index).data.logo;
comp->setOpacity(0x80);
comp->render(logoTrans);
}
}
Renderer::popClipRect();
}
void SystemView::renderInfoBar(const Eigen::Affine3f& trans)
{
Renderer::setMatrix(trans);
mSystemInfo.render(trans);
}
// Draw background extras
void SystemView::renderExtras(const Eigen::Affine3f& trans)
{
Eigen::Affine3f extrasTrans = trans;
int extrasCenter = (int)mExtrasCamOffset;
for (int i = extrasCenter - 1; i < extrasCenter + 2; i++)
{
int index = i;
while (index < 0)
index += mEntries.size();
while (index >= (int)mEntries.size())
index -= mEntries.size(); index -= mEntries.size();
extrasTrans.translation() = trans.translation() + Eigen::Vector3f((i - mExtrasCamOffset) * mSize.x(), 0, 0); extrasTrans.translation() = trans.translation() + Eigen::Vector3f((i - mExtrasCamOffset) * mSize.x(), 0, 0);
@ -287,61 +410,50 @@ void SystemView::render(const Eigen::Affine3f& parentTrans)
} }
// fade extras if necessary // fade extras if necessary
if(mExtrasFadeOpacity) if (mExtrasFadeOpacity)
{ {
Renderer::setMatrix(trans); Renderer::setMatrix(trans);
Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), 0x00000000 | (unsigned char)(mExtrasFadeOpacity * 255)); Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), 0x00000000 | (unsigned char)(mExtrasFadeOpacity * 255));
} }
// draw logos
float xOff = (mSize.x() - logoSize().x())/2 - (mCamOffset * logoSizeX);
float yOff = (mSize.y() - logoSize().y())/2;
// background behind the logos
Renderer::setMatrix(trans);
Renderer::drawRect(0.f, (mSize.y() - BAND_HEIGHT) / 2, mSize.x(), BAND_HEIGHT, 0xFFFFFFD8);
Eigen::Affine3f logoTrans = trans;
for(int i = center - logoCount/2; i < center + logoCount/2 + 1; i++)
{
int index = i;
while(index < 0)
index += mEntries.size();
while(index >= (int)mEntries.size())
index -= mEntries.size();
logoTrans.translation() = trans.translation() + Eigen::Vector3f(i * logoSizeX + xOff, yOff, 0);
if(index == mCursor) //scale our selection up
{
// selected
const std::shared_ptr<GuiComponent>& comp = mEntries.at(index).data.logoSelected;
comp->setOpacity(0xFF);
comp->render(logoTrans);
}else{
// not selected
const std::shared_ptr<GuiComponent>& comp = mEntries.at(index).data.logo;
comp->setOpacity(0x80);
comp->render(logoTrans);
}
}
Renderer::setMatrix(trans);
Renderer::drawRect(mSystemInfo.getPosition().x(), mSystemInfo.getPosition().y() - 1, mSize.x(), mSystemInfo.getSize().y(), 0xDDDDDD00 | (unsigned char)(mSystemInfo.getOpacity() / 255.f * 0xD8));
mSystemInfo.render(trans);
} }
std::vector<HelpPrompt> SystemView::getHelpPrompts() // Populate the system carousel with the legacy values
void SystemView::getDefaultElements(void)
{ {
std::vector<HelpPrompt> prompts; // Carousel
prompts.push_back(HelpPrompt("left/right", "choose")); mCarousel.type = HORIZONTAL;
prompts.push_back(HelpPrompt("a", "select")); mCarousel.size.x() = mSize.x();
return prompts; mCarousel.size.y() = 0.2325f * mSize.y();
mCarousel.pos.x() = 0.0f;
mCarousel.pos.y() = 0.5f * (mSize.y() - mCarousel.size.y());
mCarousel.color = 0xFFFFFFD8;
mCarousel.logoScale = 1.5f;
mCarousel.logoSize.x() = 0.25f * mSize.x();
mCarousel.logoSize.y() = 0.155f * mSize.y();
mCarousel.maxLogoCount = 3;
// System Info Bar
mSystemInfo.setSize(mSize.x(), mSystemInfo.getFont()->getLetterHeight()*2.2f);
mSystemInfo.setPosition(0, (mCarousel.pos.y() + mCarousel.size.y()));
mSystemInfo.setBackgroundColor(0xDDDDDDD8);
mSystemInfo.setFont(Font::get((int)(0.035f * mSize.y()), Font::getDefaultPath()));
mSystemInfo.setColor(0x000000FF);
} }
HelpStyle SystemView::getHelpStyle() void SystemView::getCarouselFromTheme(const ThemeData::ThemeElement* elem)
{ {
HelpStyle style; if (elem->has("type"))
style.applyTheme(mEntries.at(mCursor).object->getTheme(), "system"); mCarousel.type = !(elem->get<std::string>("type").compare("vertical")) ? VERTICAL : HORIZONTAL;
return style; if (elem->has("size"))
mCarousel.size = elem->get<Eigen::Vector2f>("size").cwiseProduct(mSize);
if (elem->has("pos"))
mCarousel.pos = elem->get<Eigen::Vector2f>("pos").cwiseProduct(mSize);
if (elem->has("color"))
mCarousel.color = elem->get<unsigned int>("color");
if (elem->has("logoScale"))
mCarousel.logoScale = elem->get<float>("logoScale");
if (elem->has("logoSize"))
mCarousel.logoSize = elem->get<Eigen::Vector2f>("logoSize").cwiseProduct(mSize);
if (elem->has("maxLogoCount"))
mCarousel.maxLogoCount = std::round(elem->get<float>("maxLogoCount"));
} }

View file

@ -10,6 +10,12 @@
class SystemData; class SystemData;
class AnimatedImageComponent; class AnimatedImageComponent;
enum CarouselType : unsigned int
{
HORIZONTAL = 0,
VERTICAL = 1
};
struct SystemViewData struct SystemViewData
{ {
std::shared_ptr<GuiComponent> logo; std::shared_ptr<GuiComponent> logo;
@ -17,6 +23,18 @@ struct SystemViewData
std::shared_ptr<ThemeExtras> backgroundExtras; std::shared_ptr<ThemeExtras> backgroundExtras;
}; };
struct SystemViewCarousel
{
CarouselType type;
Eigen::Vector2f pos;
Eigen::Vector2f size;
float logoScale;
Eigen::Vector2f logoSpacing;
unsigned int color;
int maxLogoCount; // number of logos shown on the carousel
Eigen::Vector2f logoSize;
};
class SystemView : public IList<SystemViewData, SystemData*> class SystemView : public IList<SystemViewData, SystemData*>
{ {
public: public:
@ -28,6 +46,8 @@ public:
void update(int deltaTime) override; void update(int deltaTime) override;
void render(const Eigen::Affine3f& parentTrans) override; void render(const Eigen::Affine3f& parentTrans) override;
void onThemeChanged(const std::shared_ptr<ThemeData>& theme);
std::vector<HelpPrompt> getHelpPrompts() override; std::vector<HelpPrompt> getHelpPrompts() override;
virtual HelpStyle getHelpStyle() override; virtual HelpStyle getHelpStyle() override;
@ -35,14 +55,22 @@ protected:
void onCursorChanged(const CursorState& state) override; void onCursorChanged(const CursorState& state) override;
private: private:
inline Eigen::Vector2f logoSize() const { return Eigen::Vector2f(mSize.x() * 0.25f, mSize.y() * 0.155f); }
void populate(); void populate();
void getViewElements(const std::shared_ptr<ThemeData>& theme);
void getDefaultElements(void);
void getCarouselFromTheme(const ThemeData::ThemeElement* elem);
void renderCarousel(const Eigen::Affine3f& parentTrans);
void renderExtras(const Eigen::Affine3f& parentTrans);
void renderInfoBar(const Eigen::Affine3f& trans);
SystemViewCarousel mCarousel;
TextComponent mSystemInfo; TextComponent mSystemInfo;
// unit is list index // unit is list index
float mCamOffset; float mCamOffset;
float mExtrasCamOffset; float mExtrasCamOffset;
float mExtrasFadeOpacity; float mExtrasFadeOpacity;
bool mViewNeedsReload;
}; };

View file

@ -12,7 +12,7 @@
#include "animations/LaunchAnimation.h" #include "animations/LaunchAnimation.h"
#include "animations/MoveCameraAnimation.h" #include "animations/MoveCameraAnimation.h"
#include "animations/LambdaAnimation.h" #include "animations/LambdaAnimation.h"
#include <SDL2/SDL.h> #include <SDL.h>
ViewController* ViewController::sInstance = NULL; ViewController* ViewController::sInstance = NULL;

View file

@ -24,7 +24,7 @@ ElementMapType makeMap(const T& mapInit)
} }
std::vector<std::string> ThemeData::sSupportedViews = boost::assign::list_of("system")("basic")("detailed")("video"); std::vector<std::string> ThemeData::sSupportedViews = boost::assign::list_of("system")("basic")("detailed")("video");
std::vector<std::string> ThemeData::sSupportedFeatures = boost::assign::list_of("video"); std::vector<std::string> ThemeData::sSupportedFeatures = boost::assign::list_of("video")("carousel");
std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign::map_list_of std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign::map_list_of
("image", makeMap(boost::assign::map_list_of ("image", makeMap(boost::assign::map_list_of
@ -39,12 +39,14 @@ std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign::
("pos", NORMALIZED_PAIR) ("pos", NORMALIZED_PAIR)
("size", NORMALIZED_PAIR) ("size", NORMALIZED_PAIR)
("text", STRING) ("text", STRING)
("color", COLOR) ("backgroundColor", COLOR)
("fontPath", PATH) ("fontPath", PATH)
("fontSize", FLOAT) ("fontSize", FLOAT)
("color", COLOR)
("alignment", STRING) ("alignment", STRING)
("forceUppercase", BOOLEAN) ("forceUppercase", BOOLEAN)
("lineSpacing", FLOAT))) ("lineSpacing", FLOAT)
("value", STRING)))
("textlist", makeMap(boost::assign::map_list_of ("textlist", makeMap(boost::assign::map_list_of
("pos", NORMALIZED_PAIR) ("pos", NORMALIZED_PAIR)
("size", NORMALIZED_PAIR) ("size", NORMALIZED_PAIR)
@ -94,12 +96,20 @@ std::map< std::string, ElementMapType > ThemeData::sElementMap = boost::assign::
("default", PATH) ("default", PATH)
("delay", FLOAT) ("delay", FLOAT)
("showSnapshotNoVideo", BOOLEAN) ("showSnapshotNoVideo", BOOLEAN)
("showSnapshotDelay", BOOLEAN))); ("showSnapshotDelay", BOOLEAN)))
("carousel", makeMap(boost::assign::map_list_of
("type", STRING)
("size", NORMALIZED_PAIR)
("pos", NORMALIZED_PAIR)
("color", COLOR)
("logoScale", FLOAT)
("logoSize", NORMALIZED_PAIR)
("maxLogoCount", FLOAT)));
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
#define MINIMUM_THEME_FORMAT_VERSION 3 #define MINIMUM_THEME_FORMAT_VERSION 3
#define CURRENT_THEME_FORMAT_VERSION 3 #define CURRENT_THEME_FORMAT_VERSION 4
// helper // helper
unsigned int getHexColor(const char* str) unsigned int getHexColor(const char* str)

View file

@ -1,4 +1,5 @@
#include "components/TextComponent.h" #include "components/TextComponent.h"
#include "Renderer.h" #include "Renderer.h"
#include "Log.h" #include "Log.h"
#include "Window.h" #include "Window.h"
@ -7,16 +8,17 @@
#include "Settings.h" #include "Settings.h"
TextComponent::TextComponent(Window* window) : GuiComponent(window), TextComponent::TextComponent(Window* window) : GuiComponent(window),
mFont(Font::get(FONT_SIZE_MEDIUM)), mUppercase(false), mColor(0x000000FF), mAutoCalcExtent(true, true), mAlignment(ALIGN_LEFT), mLineSpacing(1.5f) mFont(Font::get(FONT_SIZE_MEDIUM)), mUppercase(false), mColor(0x000000FF), mAutoCalcExtent(true, true), mAlignment(ALIGN_LEFT), mLineSpacing(1.5f), mBgColor(NULL)
{ {
} }
TextComponent::TextComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color, Alignment align, TextComponent::TextComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color, Alignment align,
Eigen::Vector3f pos, Eigen::Vector2f size) : GuiComponent(window), Eigen::Vector3f pos, Eigen::Vector2f size, unsigned int bgcolor) : GuiComponent(window),
mFont(NULL), mUppercase(false), mColor(0x000000FF), mAutoCalcExtent(true, true), mAlignment(align), mLineSpacing(1.5f) mFont(NULL), mUppercase(false), mColor(0x000000FF), mAutoCalcExtent(true, true), mAlignment(align), mLineSpacing(1.5f), mBgColor(NULL)
{ {
setFont(font); setFont(font);
setColor(color); setColor(color);
setBackgroundColor(bgcolor);
setText(text); setText(text);
setPosition(pos); setPosition(pos);
setSize(size); setSize(size);
@ -34,19 +36,34 @@ void TextComponent::setFont(const std::shared_ptr<Font>& font)
onTextChanged(); onTextChanged();
} }
// Set the color of the font/text
void TextComponent::setColor(unsigned int color) void TextComponent::setColor(unsigned int color)
{ {
mColor = color; mColor = color;
mColorOpacity = mColor & 0x000000FF;
unsigned char opacity = mColor & 0x000000FF;
GuiComponent::setOpacity(opacity);
onColorChanged(); onColorChanged();
} }
// Set the color of the background box
void TextComponent::setBackgroundColor(unsigned int color)
{
mBgColor = color;
mBgColorOpacity = mBgColor & 0x000000FF;
}
// Scale the opacity
void TextComponent::setOpacity(unsigned char opacity) void TextComponent::setOpacity(unsigned char opacity)
{ {
mColor = (mColor & 0xFFFFFF00) | opacity; // This method is mostly called to do fading in-out of the Text component element.
// Therefore, we assume here that opacity is a fractional value (expressed as an int 0-255),
// of the opacity originally set with setColor() or setBackgroundColor().
unsigned char o = (unsigned char)((float)opacity / 255.f * (float) mColorOpacity);
mColor = (mColor & 0xFFFFFF00) | (unsigned char) o;
unsigned char bgo = (unsigned char)((float)opacity / 255.f * (float)mBgColorOpacity);
mBgColor = (mBgColor & 0xFFFFFF00) | (unsigned char)bgo;
onColorChanged(); onColorChanged();
GuiComponent::setOpacity(opacity); GuiComponent::setOpacity(opacity);
@ -73,11 +90,11 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans)
{ {
Eigen::Affine3f trans = parentTrans * getTransform(); Eigen::Affine3f trans = parentTrans * getTransform();
/*Eigen::Vector3f dim(mSize.x(), mSize.y(), 0); if (mBgColor)
dim = trans * dim - trans.translation(); {
Renderer::pushClipRect(Eigen::Vector2i((int)trans.translation().x(), (int)trans.translation().y()), Renderer::drawRect(getPosition().x(), getPosition().y() - 1,
Eigen::Vector2i((int)(dim.x() + 0.5f), (int)(dim.y() + 0.5f))); getSize().x(), getSize().y(), mBgColor);
*/ }
if(mTextCache) if(mTextCache)
{ {
@ -90,7 +107,7 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans)
Renderer::setMatrix(trans); Renderer::setMatrix(trans);
Renderer::drawRect(0.f, 0.f, mSize.x(), mSize.y(), 0xFF000033); Renderer::drawRect(0.f, 0.f, mSize.x(), mSize.y(), 0xFF000033);
} }
trans.translate(off); trans.translate(off);
trans = roundMatrix(trans); trans = roundMatrix(trans);
Renderer::setMatrix(trans); Renderer::setMatrix(trans);
@ -111,11 +128,8 @@ void TextComponent::render(const Eigen::Affine3f& parentTrans)
break; break;
} }
} }
mFont->renderTextCache(mTextCache.get()); mFont->renderTextCache(mTextCache.get());
} }
//Renderer::popClipRect();
} }
void TextComponent::calculateExtent() void TextComponent::calculateExtent()
@ -216,8 +230,11 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const st
if(!elem) if(!elem)
return; return;
if(properties & COLOR && elem->has("color")) if (properties & COLOR && elem->has("color"))
setColor(elem->get<unsigned int>("color")); setColor(elem->get<unsigned int>("color"));
if (properties & COLOR && elem->has("backgroundColor"))
setBackgroundColor(elem->get<unsigned int>("backgroundColor"));
if(properties & ALIGNMENT && elem->has("alignment")) if(properties & ALIGNMENT && elem->has("alignment"))
{ {

View file

@ -16,7 +16,7 @@ class TextComponent : public GuiComponent
public: public:
TextComponent(Window* window); TextComponent(Window* window);
TextComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color = 0x000000FF, Alignment align = ALIGN_LEFT, TextComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color = 0x000000FF, Alignment align = ALIGN_LEFT,
Eigen::Vector3f pos = Eigen::Vector3f::Zero(), Eigen::Vector2f size = Eigen::Vector2f::Zero()); Eigen::Vector3f pos = Eigen::Vector3f::Zero(), Eigen::Vector2f size = Eigen::Vector2f::Zero(), unsigned int bgcolor = 0x00000000);
void setFont(const std::shared_ptr<Font>& font); void setFont(const std::shared_ptr<Font>& font);
void setUppercase(bool uppercase); void setUppercase(bool uppercase);
@ -25,6 +25,7 @@ public:
void setColor(unsigned int color); void setColor(unsigned int color);
void setAlignment(Alignment align); void setAlignment(Alignment align);
void setLineSpacing(float spacing); void setLineSpacing(float spacing);
void setBackgroundColor(unsigned int color);
void render(const Eigen::Affine3f& parentTrans) override; void render(const Eigen::Affine3f& parentTrans) override;
@ -45,6 +46,10 @@ private:
void onColorChanged(); void onColorChanged();
unsigned int mColor; unsigned int mColor;
unsigned int mBgColor;
unsigned char mColorOpacity;
unsigned char mBgColorOpacity;
std::shared_ptr<Font> mFont; std::shared_ptr<Font> mFont;
bool mUppercase; bool mUppercase;
Eigen::Matrix<bool, 1, 2> mAutoCalcExtent; Eigen::Matrix<bool, 1, 2> mAutoCalcExtent;