Several improvements in the CSS Animations.

UITabWidget now acts as a draw invalidator, skipping the draw invalidation if the element invalidating is not visible in the current tab.
premake5 file now supports different architectures.
Updated README.md and docs.
Minor fixes in UIColorPicker.
Updated SOIL2 and efsw.
Added LICENSE file.
This commit is contained in:
Martín Lucas Golini
2020-02-25 01:15:27 -03:00
parent f8c21880d1
commit 04c407077f
28 changed files with 512 additions and 230 deletions

19
LICENSE Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2020 Martín Lucas Golini
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -233,7 +233,8 @@ UITextView::New()->setText( "Text on test 1" )
Element styling can be done with a custom implementation of Cascading Style
Sheets, most common CSS2 rules are available, plus several CSS3 rules (some
examples: [transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions),
examples: [animations](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/),
[transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions),
[custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties),
[media queries](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries),
[@font-face at rule](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face),
@@ -522,8 +523,6 @@ Keep improving the UI system, adding new widgets and layouts and improving the C
Simplify and improve the UI widgets skinning/theming support.
Add [CSS animations](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations) support.
Improve/create documentation for the UI module.
Add more examples and some tools.
@@ -532,7 +531,7 @@ Add Scripting support ( first I would like to stabilize the library, but I'm get
Add 2D skeletal animations support ( probably Spine2D, shouldn't be much work to implement ).
Probably deprecate the Maps module, since i will focus my efforts on the UI system.
Probably deprecate the Maps module, since I will focus my efforts on the UI system.
## Acknowledgements

View File

@@ -184,7 +184,7 @@ CheckBox:checked {
background-color: #221122;
}
to {
background-color: #332233;
background-color: #110011;
}
}
@@ -456,6 +456,16 @@ TabWidget {
animation: 0.5s infinite alternate pulse;
}
#rttv {
animation: 0.5s infinite alternate paused ease-in pulse;
}
#rttv:hover {
/** This rule should be ignored. */
foreground-color: red;
animation-play-state: running;
}
@media screen and (max-width: 1024px) {
#lvbox {

View File

@@ -1,30 +1,27 @@
UI Introduction
===============
# UI Introduction
## Introduction
Introduction
------------
eepp UI is designed to be flexible and efficient. Inspired in
[Android Layouts structure](https://developer.android.com/guide/topics/ui/declaring-layout)
and [CSS standards](https://developer.mozilla.org/en-US/docs/Web/CSS).
It's still a work in progress so several features are still not stable, but
already provides a very solid foundation to create rich and interactive UIs.
## Layout
Layout
------
A layout defines the structure for a user interface in your app.
For constructing layouts in eepp we have two options: instantiate layout
elements at runtime or declare UI elements in XML.
* **Declare UI elements in XML.** eepp provides a straightforward XML
vocabulary that corresponds to the UI Widget classes and subclasses.
There are two kinds of widgets: normal widgets and layouts. The difference
between this two is that layouts are the ones in charge of arranging their
child in a particular way.
* **Declare UI elements in XML.** eepp provides a straightforward XML
vocabulary that corresponds to the UI Widget classes and subclasses.
There are two kinds of widgets: normal widgets and layouts. The difference
between this two is that layouts are the ones in charge of arranging their
child in a particular way.
* **Instantiate layout elements at runtime.** Your app can create Widget and
Layout objects (and manipulate their properties) programmatically.
* **Instantiate layout elements at runtime.** Your app can create Widget and
Layout objects (and manipulate their properties) programmatically.
Declaring your UI in XML allows you to separate the presentation of your app
from the code that controls its behavior. Using XML files in conjunction with
@@ -35,9 +32,8 @@ The framework gives you the flexibility to use either or both of these methods
to build your app's UI. For example, you can declare your app's default
layouts in XML, and then modify the layout at runtime.
## Write the XML
Write the XML
-------------
Using eepp XML vocabulary, you can quickly design UI layouts and the screen
elements they contain, in the same way you create web pages in HTML — with a
series of nested elements.
@@ -67,9 +63,8 @@ and a EE::UI::UIPushButton:
After you've declared your layout in XML, save the file with the `.xml`
extension into a project accessible path and you're done.
## Initializing the UI
Initializing the UI
-------------------
The library does not assume that the user is going to use the UI at all, so you
must initialize it manually. This usually comes right after the main
EE::Window::Window initialization.
@@ -79,6 +74,7 @@ EE::UI::UISceneNode. Setting the font as the default scene node. And finally,
adding this scene node to the EE::Scene::SceneManager.
For example:
```cpp
// ... after window creation
// Load a font to use as the default font in our UI.
@@ -98,13 +94,13 @@ SceneManager::instance()->add( uiSceneNode );
And that's all we need for a basic initialization.
## Updating the UI
Updating the UI
---------------
Updating the UI consist in two simple steps: updating and drawing the UI scene
node contained by the EE::Scene::SceneManager.
So we just need to do in our main loop:
```cpp
// Update the UI scene
SceneManager::instance()->update();
@@ -130,9 +126,8 @@ the scene on every update or only when is needed. There are several options
regarding this topic, since each scene node can be drawn into a separated
frame buffer, in order to be able to control when to redraw a scene.
## Load the XML Layout Resource
Load the XML Layout Resource
----------------------------
XML layout resources can be loaded from any file system path,
EE::UI::Pack accessible path or a hard-coded string.
@@ -142,6 +137,7 @@ root scene node will be used.
Following the [Write the XML](#write-the-xml) layout and the
[Initializing the UI](#initializing-the-ui) code:
```cpp
uiSceneNode->loadLayoutFromString( R"xml(
<LinearLayout layout_width="match_parent"
@@ -162,37 +158,37 @@ uiSceneNode->loadLayoutFromString( R"xml(
This will load and create the widgets into the root element of the UI scene
node.
## Cascading Style Sheets
Cascading Style Sheets
----------------------
[CSS (Cascading Style Sheets)](https://developer.mozilla.org/en-US/docs/Web/CSS)
is the code you use to style the UI. It's very heavily based on the
[CSS 2.1](https://www.w3.org/TR/CSS21/) standards with a good amount of CSS 3
features. Some of the main current differences are: eepp CSS properties don't
support inheritance (except for
[Custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties),
support inheritance (except for the case
[custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties),
and `*` is supported), eepp also adds new properties oriented to decoration
related and layout control stuffs, and CSS layout properties differ from the
standard since we use a different layout model. But you can learn how style the
standard since we use a different layout model. But you can learn how to style the
UI following the CSS standards and then reading about the specific eepp UI
features.
Important CSS3 features that are currently supported:
* [Transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions)
* [Animations](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/)
* [Custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties)
* [Transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions)
* [Media queries](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries)
* [Custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties)
* [@font-face at rule](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face)
* [Media queries](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries)
* [:root element](https://developer.mozilla.org/en-US/docs/Web/CSS/:root)
* [@font-face at rule](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face)
* [Most of the background properties](https://developer.mozilla.org/en-US/docs/Web/CSS/background)
* [:root element](https://developer.mozilla.org/en-US/docs/Web/CSS/:root)
* [Most of the background properties](https://developer.mozilla.org/en-US/docs/Web/CSS/background)
## Write the CSS
Write the CSS
-------------
Following [Load the XML Layout Resource](#load-the-xml-layout-resource) we are
going to write a very simple style to our UI. In order to that we can create a
new CSS file (with `.css` extension) in our file system and save it in an
@@ -200,6 +196,7 @@ accesible path to our project, or we can simply write the CSS in a string in our
code.
This is how our CSS could look like:
```css
* {
font-size: 22dp;
@@ -223,8 +220,8 @@ pixel](https://en.wikipedia.org/wiki/Device-independent_pixel), that allow us to
keep our layout consistent between different screen densities. This concept was
taken from the [Android pixel density implementation](https://developer.android.com/guide/practices/screens_support.html#density).
Loading the CSS Resource
------------------------
## Loading the CSS Resource
Following [Load the XML Layout Resource](#load-the-xml-layout-resource) and
[Write the CSS](#write-the-css) we are going to load our CSS from a string:
@@ -252,13 +249,14 @@ To load a CSS from a file we need to first parse it with the
EE::UI::CSS::StyleSheetParser.
It will look like:
```cpp
CSS::StyleSheetParser parser;
parser.loadFromFile( "path/to/our/stylesheet.css" );
uiSceneNode->setStyleSheet( parser.getStyleSheet() );
```
Example
-------
## Example
For a complete example of this introduction you can look into:
[src/examples/ui_hello_world/ui_hello_world.cpp](https://github.com/SpartanJ/eepp/blob/develop/src/examples/ui_hello_world/ui_hello_world.cpp).

View File

@@ -49,7 +49,6 @@ class EE_API ActionManager {
protected:
std::list<Action*> mActions;
std::list<Action*> mActionsRemoveList;
Mutex mMutex;
bool mUpdating;
};

View File

@@ -329,7 +329,7 @@ class EE_API Node : public Transformable {
bool invalidated() const;
void invalidate();
virtual void invalidate( Node* invalidator );
Uint32 getChildCount() const;

View File

@@ -4,7 +4,7 @@
#include <eepp/math/ease.hpp>
#include <eepp/system/time.hpp>
#include <eepp/ui/css/stylesheetproperty.hpp>
#include <map>
#include <unordered_map>
#include <vector>
using namespace EE::Math;
@@ -14,7 +14,7 @@ namespace EE { namespace UI { namespace CSS {
class EE_API AnimationDefinition {
public:
static std::map<std::string, AnimationDefinition>
static std::unordered_map<std::string, AnimationDefinition>
parseAnimationProperties( const std::vector<StyleSheetProperty>& stylesheetProperties );
/* https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction */
@@ -57,17 +57,50 @@ class EE_API AnimationDefinition {
const Ease::Interpolation& getTimingFunction() const;
std::string name;
Time delay = Time::Zero;
Time duration = Time::Zero;
Int32 iterations = 1; /* -1 == "infinite" */
Ease::Interpolation timingFunction = Ease::Interpolation::Linear;
AnimationDirection direction = Normal;
AnimationFillMode fillMode = None;
bool paused = false;
const AnimationFillMode& getFillMode() const;
void setName( const std::string& value );
void setDelay( const Time& value );
void setDuration( const Time& value );
void setIterations( const Int32& value );
void setTimingFunction( const Ease::Interpolation& value );
void setDirection( const AnimationDirection& value );
void setFillMode( const AnimationFillMode& value );
void setPaused( bool value );
const Uint32& getId() const;
protected:
Uint32 mId;
std::string mName;
Time mDelay = Time::Zero;
Time mDuration = Time::Zero;
Int32 mIterations = 1; /* -1 == "infinite" */
Ease::Interpolation mTimingFunction = Ease::Interpolation::Linear;
AnimationDirection mDirection = Normal;
AnimationFillMode mFillMode = None;
bool mPaused = false;
};
typedef std::map<std::string, AnimationDefinition> AnimationsMap;
inline bool operator==( const AnimationDefinition& a, const AnimationDefinition& b ) {
return a.getDuration() == b.getDuration() && a.getTimingFunction() == b.getTimingFunction() &&
a.getDelay() == b.getDelay() && a.getDirection() == b.getDirection() &&
a.isPaused() == b.isPaused() && a.getIterations() == b.getIterations() &&
a.getName() == b.getName();
}
inline bool operator!=( const AnimationDefinition& a, const AnimationDefinition& b ) {
return !( a == b );
}
typedef std::unordered_map<std::string, AnimationDefinition> AnimationsMap;
}}} // namespace EE::UI::CSS

View File

@@ -74,8 +74,14 @@ class EE_API StyleSheetPropertyAnimation : public Action {
const AnimationOrigin& getAnimationOrigin() const;
void setRunning( const bool& running );
void setPaused( const bool& paused );
void notifyClose();
const AnimationDefinition& getAnimation() const;
protected:
AnimationDefinition mAnimation;
const PropertyDefinition* mPropertyDef;
@@ -87,6 +93,7 @@ class EE_API StyleSheetPropertyAnimation : public Action {
Uint32 mPropertyIndex;
std::string mFillModeValue;
AnimationOrigin mAnimationOrigin;
bool mPaused;
StyleSheetPropertyAnimation( const AnimationDefinition& animation,
const PropertyDefinition* propertyDef,

View File

@@ -15,6 +15,10 @@ namespace EE { namespace Graphics {
class Font;
}} // namespace EE::Graphics
namespace EE { namespace UI { namespace CSS {
class StyleSheetPropertyAnimation;
}}} // namespace EE::UI::CSS
namespace EE { namespace UI {
class UIWidget;
@@ -41,6 +45,10 @@ class EE_API UIStyle : public UIState {
bool hasTransition( const std::string& propertyName );
CSS::StyleSheetPropertyAnimation* getAnimation( const CSS::PropertyDefinition* propertyDef );
bool hasAnimation( const CSS::PropertyDefinition* propertyDef );
CSS::TransitionDefinition getTransition( const std::string& propertyName );
const bool& isChangingState() const;
@@ -54,8 +62,8 @@ class EE_API UIStyle : public UIState {
CSS::StyleSheetStyle mElementStyle;
CSS::StyleSheetProperties mProperties;
CSS::StyleSheetVariables mVariables;
std::vector<CSS::StyleSheetProperty> mTransitionAttributes;
std::vector<CSS::StyleSheetProperty> mAnimationAttributes;
std::vector<CSS::StyleSheetProperty> mTransitionProperties;
std::vector<CSS::StyleSheetProperty> mAnimationProperties;
CSS::TransitionsMap mTransitions;
CSS::AnimationsMap mAnimations;
std::set<UIWidget*> mRelatedWidgets;
@@ -87,7 +95,11 @@ class EE_API UIStyle : public UIState {
void applyStyleSheetProperty( const CSS::StyleSheetProperty& property,
CSS::StyleSheetProperties& prevProperties );
void startAnimations();
void updateAnimationsPlayState();
void updateAnimations();
void startAnimations( const CSS::AnimationsMap& animations );
void removeAllAnimations();

View File

@@ -116,6 +116,10 @@ class EE_API UITabWidget : public UIWidget {
virtual std::string getPropertyString( const PropertyDefinition* propertyDef,
const Uint32& propertyIndex = 0 );
virtual bool isDrawInvalidator() const;
void invalidate( Node* invalidator );
protected:
friend class UITab;

View File

@@ -146,7 +146,7 @@ class EE_API UIWindow : public UIWidget {
virtual void internalDraw();
void invalidate();
void invalidate( Node* invalidator );
bool invalidated();

View File

@@ -802,14 +802,7 @@ solution "eepp"
project "SOIL2-static"
kind "StaticLib"
if is_vs() then
language "C++"
buildoptions { "/TP" }
else
language "C"
end
language "C"
set_targetdir("libs/" .. os.get_real() .. "/thirdparty/")
files { "src/thirdparty/SOIL2/src/SOIL2/*.c" }
includedirs { "src/thirdparty/SOIL2" }

View File

@@ -216,9 +216,12 @@ function build_link_configuration( package_name, use_ee_icon )
links { "SDL2", "SDL2main" }
end
filter { "options:windows-vc-build", "system:windows" }
filter { "options:windows-vc-build", "system:windows", "platforms:x86" }
syslibdirs { "src/thirdparty/" .. remote_sdl2_version .."/lib/x86" }
filter { "options:windows-vc-build", "system:windows", "platforms:x86_64" }
syslibdirs { "src/thirdparty/" .. remote_sdl2_version .."/lib/x64" }
filter "system:emscripten"
linkoptions{ "-O2 -s TOTAL_MEMORY=67108864 -s ASM_JS=1 -s VERBOSE=1 -s DISABLE_EXCEPTION_CATCHING=0 -s USE_SDL=2 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s ERROR_ON_MISSING_LIBRARIES=0 -s FULL_ES3=1 -s \"BINARYEN_TRAP_MODE='clamp'\"" }
buildoptions { "-fno-strict-aliasing -O2 -s USE_SDL=2 -s PRECISE_F32=1 -s ENVIRONMENT=web" }
@@ -534,6 +537,7 @@ end
workspace "eepp"
targetdir("./bin/")
configurations { "debug", "release" }
platforms { "x86_64", "x86" }
rtti "On"
download_and_extract_dependencies()
select_backend()
@@ -542,6 +546,12 @@ workspace "eepp"
location("./make/" .. os.target() .. "/")
objdir("obj/" .. os.target() .. "/")
filter "platforms:x86"
architecture "x86"
filter "platforms:x86_64"
architecture "x86_64"
filter "system:macosx"
defines { "GL_SILENCE_DEPRECATION" }
@@ -558,15 +568,11 @@ workspace "eepp"
project "SOIL2-static"
kind "StaticLib"
language "C"
targetdir("libs/" .. os.target() .. "/thirdparty/")
files { "src/thirdparty/SOIL2/src/SOIL2/*.c" }
incdirs { "src/thirdparty/SOIL2" }
build_base_configuration( "SOIL2" )
filter "action:vs*"
language "C++"
buildoptions { "/TP" }
filter "action:not vs*"
language "C"
project "glew-static"
kind "StaticLib"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.11.1, 2020-02-19T00:05:12. -->
<!-- Written by QtCreator 4.11.1, 2020-02-25T01:13:48. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
@@ -79,7 +79,7 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{6d057187-158a-4883-8d5b-d470a6b6b025}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">10</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">15</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">../../make/linux</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
@@ -130,7 +130,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets"/>
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release eepp-test</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release_x86_64 eepp-test</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@@ -144,7 +144,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release_x86_64 clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Command">/usr/bin/make</value>
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">clean</value>
@@ -217,8 +217,8 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets"/>
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand">make</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release_x86_64</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
@@ -231,7 +231,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release_x86_64 clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Command">make</value>
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.ProcessStep</value>
@@ -253,7 +253,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets"/>
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments"></value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=debug_x86</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand">make.sh</value>
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@@ -289,7 +289,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets"/>
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release_x86</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand">make.sh</value>
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@@ -303,7 +303,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release_x86 clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Command">make.sh</value>
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.ProcessStep</value>
@@ -657,7 +657,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets"/>
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release eepp-static</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release_x86_64 eepp-static</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@@ -671,7 +671,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release_x86_64 clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Command">make</value>
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">clean</value>
@@ -731,7 +731,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets"/>
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release eepp-shared</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release_x86_64 eepp-shared</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@@ -745,7 +745,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release_x86_64 clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Command">make</value>
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">clean</value>
@@ -813,7 +813,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets"/>
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release eepp-ew</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release_x86_64 eepp-ew</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@@ -828,7 +828,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release_x86_64 clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Command">/usr/bin/make</value>
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clone of clean</value>
@@ -889,7 +889,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets"/>
<value type="bool" key="GenericProjectManager.GenericMakeStep.Clean">false</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release eepp-es</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeArguments">-e config=release_x86_64 eepp-es</value>
<value type="QString" key="GenericProjectManager.GenericMakeStep.MakeCommand"></value>
<value type="bool" key="GenericProjectManager.GenericMakeStep.OverrideMakeflags">false</value>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@@ -904,7 +904,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Arguments">-e config=release_x86_64 clean</value>
<value type="QString" key="ProjectExplorer.ProcessStep.Command">/usr/bin/make</value>
<value type="QString" key="ProjectExplorer.ProcessStep.WorkingDirectory">%{buildDir}</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clone of clean</value>

View File

@@ -104,7 +104,7 @@ void UIMap::scheduledUpdate( const Time& time ) {
UIWindow::scheduledUpdate( time );
if ( NULL != mMap ) {
invalidate();
invalidate( this );
invalidateDraw();
mMap->update();

View File

@@ -17,8 +17,6 @@ ActionManager::~ActionManager() {
}
void ActionManager::addAction( Action* action ) {
Lock lock( mMutex );
bool found = ( std::find( mActions.begin(), mActions.end(), action ) != mActions.end() );
if ( !found ) {
@@ -27,8 +25,6 @@ void ActionManager::addAction( Action* action ) {
}
Action* ActionManager::getActionByTag( const Uint32& tag ) {
Lock lock( mMutex );
for ( auto it = mActions.begin(); it != mActions.end(); ++it ) {
Action* action = ( *it );
@@ -40,7 +36,6 @@ Action* ActionManager::getActionByTag( const Uint32& tag ) {
}
std::vector<Action*> ActionManager::getActionsFromTarget( Node* target ) {
Lock lock( mMutex );
std::vector<Action*> actions;
for ( auto it = mActions.begin(); it != mActions.end(); ++it ) {
@@ -54,7 +49,6 @@ std::vector<Action*> ActionManager::getActionsFromTarget( Node* target ) {
}
std::vector<Action*> ActionManager::getActionsByTagFromTarget( Node* target, const Uint32& tag ) {
Lock lock( mMutex );
std::vector<Action*> actions;
for ( auto it = mActions.begin(); it != mActions.end(); ++it ) {
@@ -74,15 +68,11 @@ void ActionManager::removeActionByTag( const Uint32& tag ) {
void ActionManager::removeActionsByTagFromTarget( Node* target, const Uint32& tag ) {
std::vector<Action*> removeList;
{
Lock lock( mMutex );
for ( auto it = mActions.begin(); it != mActions.end(); ++it ) {
Action* action = ( *it );
for ( auto it = mActions.begin(); it != mActions.end(); ++it ) {
Action* action = ( *it );
if ( action->getTarget() == target && action->getTag() == tag ) {
removeList.push_back( *it );
}
if ( action->getTarget() == target && action->getTag() == tag ) {
removeList.push_back( *it );
}
}
@@ -96,25 +86,22 @@ void ActionManager::update( const Time& time ) {
std::vector<Action*> removeList;
{
Lock lock( mMutex );
mUpdating = true;
mUpdating = true;
for ( auto it = mActions.begin(); it != mActions.end(); ++it ) {
Action* action = ( *it );
for ( auto it = mActions.begin(); it != mActions.end(); ++it ) {
Action* action = ( *it );
action->update( time );
action->update( time );
if ( action->isDone() ) {
action->sendEvent( Action::ActionType::OnDone );
if ( action->isDone() ) {
action->sendEvent( Action::ActionType::OnDone );
removeList.push_back( action );
}
removeList.push_back( action );
}
mUpdating = false;
}
mUpdating = false;
for ( auto it = mActionsRemoveList.begin(); it != mActionsRemoveList.end(); ++it )
removeAction( ( *it ) );
@@ -125,20 +112,14 @@ void ActionManager::update( const Time& time ) {
}
std::size_t ActionManager::count() const {
Lock lock( const_cast<Mutex&>( mMutex ) );
return mActions.size();
}
bool ActionManager::isEmpty() const {
Lock lock( const_cast<Mutex&>( mMutex ) );
return mActions.empty();
}
void ActionManager::clear() {
Lock lock( mMutex );
for ( auto it = mActions.begin(); it != mActions.end(); ++it ) {
Action* action = ( *it );
@@ -149,8 +130,6 @@ void ActionManager::clear() {
}
void ActionManager::removeAction( Action* action ) {
Lock lock( mMutex );
if ( NULL != action ) {
if ( !mUpdating ) {
bool found = std::find( mActions.begin(), mActions.end(), action ) != mActions.end();
@@ -175,15 +154,11 @@ void ActionManager::removeActions( const std::vector<Action*>& actions ) {
void ActionManager::removeAllActionsFromTarget( Node* target ) {
std::vector<Action*> removeList;
{
Lock lock( mMutex );
for ( auto it = mActions.begin(); it != mActions.end(); ++it ) {
Action* action = ( *it );
for ( auto it = mActions.begin(); it != mActions.end(); ++it ) {
Action* action = ( *it );
if ( action->getTarget() == target ) {
removeList.push_back( *it );
}
if ( action->getTarget() == target ) {
removeList.push_back( *it );
}
}

View File

@@ -52,7 +52,7 @@ void EventDispatcher::inputCallback( InputEvent* Event ) {
case InputEvent::VideoResize:
case InputEvent::VideoExpose: {
if ( NULL != mSceneNode )
mSceneNode->invalidate();
mSceneNode->invalidate( NULL );
}
}
}

View File

@@ -1101,7 +1101,7 @@ void Node::setReverseDraw( bool reverseDraw ) {
void Node::invalidateDraw() {
if ( NULL != mNodeDrawInvalidator ) {
mNodeDrawInvalidator->invalidate();
mNodeDrawInvalidator->invalidate( this );
}
}
@@ -1572,7 +1572,7 @@ bool Node::isDrawInvalidator() const {
return false;
}
void Node::invalidate() {
void Node::invalidate( Node* invalidator ) {
if ( mVisible && mAlpha != 0.f ) {
writeNodeFlag( NODE_FLAG_VIEW_DIRTY, 1 );
}

View File

@@ -7,7 +7,7 @@ bool isTimingFunction( const std::string& str ) {
return Ease::Interpolation::None != Ease::fromName( str, Ease::Interpolation::None );
}
std::map<std::string, AnimationDefinition> AnimationDefinition::parseAnimationProperties(
std::unordered_map<std::string, AnimationDefinition> AnimationDefinition::parseAnimationProperties(
const std::vector<StyleSheetProperty>& stylesheetProperties ) {
AnimationsMap animations;
std::vector<std::string> names;
@@ -41,40 +41,39 @@ std::map<std::string, AnimationDefinition> AnimationDefinition::parseAnimationPr
std::string val( String::trim( String::toLower( part ) ) );
if ( isDirectionString( val ) ) {
animationDef.direction = directionFromString( val );
animationDef.setDirection( directionFromString( val ) );
} else if ( isAnimationFillModeString( val ) ) {
animationDef.fillMode = fillModeFromString( val );
animationDef.setFillMode( fillModeFromString( val ) );
} else if ( "infinite" == val ) {
animationDef.iterations = -1;
animationDef.setIterations( -1 );
} else if ( "paused" == val ) {
animationDef.paused = true;
animationDef.setPaused( true );
} else if ( "running" == val ) {
animationDef.paused = false;
animationDef.setPaused( false );
} else if ( isTimingFunction( val ) ) {
animationDef.timingFunction = Ease::fromName( val );
animationDef.setTimingFunction( Ease::fromName( val ) );
} else if ( Time::isValid( val ) ) {
if ( durationSet ) {
animationDef.delay =
StyleSheetProperty( "animation-delay", val ).asTime();
animationDef.setDelay( Time::fromString( val ) );
} else {
animationDef.duration =
StyleSheetProperty( "animation-duration", val ).asTime();
animationDef.setDuration( Time::fromString( val ) );
durationSet = true;
}
} else if ( String::isNumber( val, true ) ) {
int iterations = 1;
if ( String::fromString( iterations, val ) ) {
animationDef.iterations = iterations;
animationDef.setIterations( iterations );
}
} else {
animationDef.name = part;
animationDef.setName( part );
}
}
animations[animationDef.name] = std::move( animationDef );
animations[animationDef.getName()] = std::move( animationDef );
}
}
return animations;
break;
}
case PropertyId::AnimationName:
@@ -133,27 +132,27 @@ std::map<std::string, AnimationDefinition> AnimationDefinition::parseAnimationPr
for ( size_t i = 0; i < names.size(); i++ ) {
AnimationDefinition animationDef;
animationDef.name = names[i];
animationDef.setName( names[i] );
if ( !delays.empty() )
animationDef.delay = delays[i % delays.size()];
animationDef.setDelay( delays[i % delays.size()] );
if ( !durations.empty() )
animationDef.duration = delays[i % durations.size()];
animationDef.setDuration( delays[i % durations.size()] );
if ( !fillModes.empty() )
animationDef.fillMode = fillModes[i % fillModes.size()];
animationDef.setFillMode( fillModes[i % fillModes.size()] );
if ( !pausedStates.empty() )
animationDef.paused = pausedStates[i % pausedStates.size()];
animationDef.setPaused( pausedStates[i % pausedStates.size()] );
if ( !iterations.empty() )
animationDef.iterations = iterations[i % iterations.size()];
animationDef.setIterations( iterations[i % iterations.size()] );
if ( !timingFunctions.empty() )
animationDef.timingFunction = timingFunctions[i % timingFunctions.size()];
animationDef.setTimingFunction( timingFunctions[i % timingFunctions.size()] );
animations[animationDef.name] = std::move( animationDef );
animations[animationDef.getName()] = std::move( animationDef );
}
return animations;
@@ -205,31 +204,72 @@ AnimationDefinition::AnimationFillMode AnimationDefinition::fillModeFromString(
AnimationDefinition::AnimationDefinition() {}
const AnimationDefinition::AnimationDirection& AnimationDefinition::getDirection() const {
return direction;
return mDirection;
}
const bool& AnimationDefinition::isPaused() const {
return paused;
return mPaused;
}
const Int32& AnimationDefinition::getIterations() const {
return iterations;
return mIterations;
}
const std::string& AnimationDefinition::getName() const {
return name;
return mName;
}
const Time& AnimationDefinition::getDelay() const {
return delay;
return mDelay;
}
const Time& AnimationDefinition::getDuration() const {
return duration;
return mDuration;
}
const Ease::Interpolation& AnimationDefinition::getTimingFunction() const {
return timingFunction;
return mTimingFunction;
}
void AnimationDefinition::setName( const std::string& value ) {
mName = value;
mId = String::hash( mName );
}
void AnimationDefinition::setFillMode( const AnimationFillMode& value ) {
mFillMode = value;
}
void AnimationDefinition::setPaused( bool value ) {
mPaused = value;
}
const Uint32& AnimationDefinition::getId() const {
return mId;
}
const AnimationDefinition::AnimationFillMode& AnimationDefinition::getFillMode() const {
return mFillMode;
}
void AnimationDefinition::setDirection( const AnimationDirection& value ) {
mDirection = value;
}
void AnimationDefinition::setTimingFunction( const Ease::Interpolation& value ) {
mTimingFunction = value;
}
void AnimationDefinition::setIterations( const Int32& value ) {
mIterations = value;
}
void AnimationDefinition::setDuration( const Time& value ) {
mDuration = value;
}
void AnimationDefinition::setDelay( const Time& value ) {
mDelay = value;
}
}}} // namespace EE::UI::CSS

View File

@@ -106,12 +106,14 @@ const KeyframesDefinition& StyleSheet::getKeyframesDefinition( const std::string
}
void StyleSheet::addKeyframes( const KeyframesDefinition& keyframes ) {
mKeyframesMap[keyframes.getName()] = keyframes;
// "none" is a reserved keyword
if ( keyframes.getName() != "none" )
mKeyframesMap[keyframes.getName()] = keyframes;
}
void StyleSheet::addKeyframes( const KeyframesDefinitionMap& keyframesMap ) {
for ( auto& keyframe : keyframesMap ) {
mKeyframesMap[keyframe.first] = keyframe.second;
for ( auto& keyframes : keyframesMap ) {
addKeyframes( keyframes.second );
}
}

View File

@@ -172,9 +172,9 @@ StyleSheetPropertyAnimation* StyleSheetPropertyAnimation::New(
const Uint32& propertyIndex, const Time& duration, const Time& delay,
const Ease::Interpolation& timingFunction, const AnimationOrigin& animationOrigin ) {
AnimationDefinition animation;
animation.delay = delay;
animation.duration = duration;
animation.timingFunction = timingFunction;
animation.setDelay( delay );
animation.setDuration( duration );
animation.setTimingFunction( timingFunction );
return New( animation, property, {startValue, endValue}, {0, 1}, propertyIndex,
animationOrigin );
}
@@ -189,9 +189,10 @@ StyleSheetPropertyAnimation::StyleSheetPropertyAnimation( const AnimationDefinit
mPropertyDef( propertyDef ),
mStates( states ),
mAnimationStepsTime( animationStepsTime ),
mPendingIterations( animation.iterations ),
mPendingIterations( animation.getIterations() ),
mPropertyIndex( propertyIndex ),
mAnimationOrigin( animationOrigin ) {
mAnimationOrigin( animationOrigin ),
mPaused( mAnimation.isPaused() ) {
mId = ID;
}
@@ -208,38 +209,41 @@ void StyleSheetPropertyAnimation::stop() {
}
void StyleSheetPropertyAnimation::update( const Time& time ) {
if ( mPaused )
return;
mRealElapsed += time;
bool wasDone = false;
if ( mRealElapsed >= mAnimation.delay ) {
if ( mRealElapsed >= mAnimation.getDelay() ) {
mElapsed += time;
if ( mPendingIterations > 0 ) {
while ( mElapsed > mAnimation.duration ) {
while ( mElapsed > mAnimation.getDuration() ) {
if ( mPendingIterations > 0 ) {
mPendingIterations--;
if ( mPendingIterations > 0 ) {
wasDone = true;
mElapsed -= mAnimation.duration;
mElapsed -= mAnimation.getDuration();
} else {
mElapsed = mAnimation.duration;
mElapsed = mAnimation.getDuration();
}
} else {
break;
}
}
} else if ( mPendingIterations == -1 ) {
while ( mElapsed > mAnimation.duration ) {
mElapsed -= mAnimation.duration;
while ( mElapsed > mAnimation.getDuration() ) {
mElapsed -= mAnimation.getDuration();
wasDone = true;
}
}
if ( wasDone && ( mPendingIterations > 0 || mPendingIterations == -1 ) ) {
if ( mAnimation.direction == AnimationDefinition::AnimationDirection::Alternate ||
mAnimation.direction ==
if ( mAnimation.getDirection() == AnimationDefinition::AnimationDirection::Alternate ||
mAnimation.getDirection() ==
AnimationDefinition::AnimationDirection::AlternateReverse ) {
reverseAnimation();
}
@@ -254,16 +258,16 @@ void StyleSheetPropertyAnimation::update( const Time& time ) {
}
bool StyleSheetPropertyAnimation::isDone() {
return mElapsed.asMicroseconds() >= mAnimation.duration.asMicroseconds() &&
return mElapsed.asMicroseconds() >= mAnimation.getDuration().asMicroseconds() &&
( mPendingIterations == 0 || mPendingIterations != -1 );
}
Float StyleSheetPropertyAnimation::getCurrentProgress() {
return eemin( mElapsed.asMilliseconds() / mAnimation.duration.asMilliseconds(), 1. );
return eemin( mElapsed.asMilliseconds() / mAnimation.getDuration().asMilliseconds(), 1. );
}
Time StyleSheetPropertyAnimation::getTotalTime() {
return mAnimation.duration;
return mAnimation.getDuration();
}
Action* StyleSheetPropertyAnimation::clone() const {
@@ -291,7 +295,7 @@ const std::string& StyleSheetPropertyAnimation::getEndValue() const {
}
void StyleSheetPropertyAnimation::onStart() {
if ( mRealElapsed >= mAnimation.delay ) {
if ( mRealElapsed >= mAnimation.getDelay() ) {
onUpdate( Time::Zero );
}
}
@@ -313,15 +317,58 @@ void StyleSheetPropertyAnimation::onUpdate( const Time& time ) {
if ( curPos - 1 >= 0 && curPos < static_cast<Int32>( mStates.size() ) ) {
tweenProperty( widget, normalizedProgress, mPropertyDef, mStates[curPos - 1],
mStates[curPos], mAnimation.timingFunction, mPropertyIndex, isDone() );
mStates[curPos], mAnimation.getTimingFunction(), mPropertyIndex,
isDone() );
}
}
}
void StyleSheetPropertyAnimation::onTargetChange() {
if ( NULL != mNode && mNode->isWidget() && mAnimationOrigin == AnimationOrigin::Animation ) {
UIWidget* widget = mNode->asType<UIWidget>();
mFillModeValue = widget->getPropertyString( mPropertyDef, mPropertyIndex );
if ( mAnimation.getFillMode() == AnimationDefinition::AnimationFillMode::None ) {
UIWidget* widget = mNode->asType<UIWidget>();
mFillModeValue = widget->getPropertyString( mPropertyDef, mPropertyIndex );
} else if ( mAnimation.getFillMode() == AnimationDefinition::AnimationFillMode::Forwards ) {
if ( mStates.empty() )
return;
switch ( mAnimation.getDirection() ) {
case AnimationDefinition::AnimationDirection::Normal: {
mFillModeValue = mStates[mStates.size() - 1];
break;
}
case AnimationDefinition::AnimationDirection::Reverse: {
mFillModeValue = mStates[0];
break;
}
case AnimationDefinition::AnimationDirection::Alternate: {
if ( mAnimation.getIterations() % 2 == 0 ) {
mFillModeValue = mStates[0];
} else {
mFillModeValue = mStates[mStates.size() - 1];
}
break;
}
case AnimationDefinition::AnimationDirection::AlternateReverse: {
if ( mAnimation.getIterations() % 2 == 0 ) {
mFillModeValue = mStates[mStates.size() - 1];
} else {
mFillModeValue = mStates[0];
}
break;
}
}
} else if ( mAnimation.getFillMode() ==
AnimationDefinition::AnimationFillMode::Backwards ) {
if ( mStates.empty() )
return;
if ( mAnimation.getDirection() == AnimationDefinition::AnimationDirection::Normal ||
mAnimation.getDirection() == AnimationDefinition::AnimationDirection::Alternate ) {
mFillModeValue = mStates[0];
} else {
mFillModeValue = mStates[mStates.size() - 1];
}
}
}
}
@@ -329,10 +376,10 @@ void StyleSheetPropertyAnimation::setElapsed( const Time& elapsed ) {
mElapsed = elapsed;
if ( mPendingIterations > 0 ) {
while ( mElapsed > mAnimation.duration ) {
while ( mElapsed > mAnimation.getDuration() ) {
if ( mPendingIterations > 0 ) {
mPendingIterations--;
mElapsed = mAnimation.duration - mElapsed;
mElapsed = mAnimation.getDuration() - mElapsed;
} else {
break;
}
@@ -344,9 +391,17 @@ const AnimationOrigin& StyleSheetPropertyAnimation::getAnimationOrigin() const {
return mAnimationOrigin;
}
void StyleSheetPropertyAnimation::setRunning( const bool& running ) {
mPaused = !running;
}
void StyleSheetPropertyAnimation::setPaused( const bool& paused ) {
mPaused = paused;
}
void StyleSheetPropertyAnimation::notifyClose() {
if ( mAnimationOrigin == AnimationOrigin::Animation && NULL != mNode && mNode->isWidget() ) {
if ( mAnimation.fillMode == AnimationDefinition::AnimationFillMode::None ) {
if ( mAnimation.getFillMode() != AnimationDefinition::AnimationFillMode::Both ) {
UIWidget* widget = mNode->asType<UIWidget>();
widget->applyProperty(
StyleSheetProperty( mPropertyDef, mFillModeValue, mPropertyIndex ) );
@@ -354,13 +409,17 @@ void StyleSheetPropertyAnimation::notifyClose() {
}
}
const AnimationDefinition& StyleSheetPropertyAnimation::getAnimation() const {
return mAnimation;
}
const Time& StyleSheetPropertyAnimation::getElapsed() const {
return mElapsed;
}
void StyleSheetPropertyAnimation::prepareDirection() {
if ( mAnimation.direction == AnimationDefinition::AnimationDirection::Reverse ||
mAnimation.direction == AnimationDefinition::AnimationDirection::AlternateReverse ) {
if ( mAnimation.getDirection() == AnimationDefinition::AnimationDirection::Reverse ||
mAnimation.getDirection() == AnimationDefinition::AnimationDirection::AlternateReverse ) {
reverseAnimation();
}
}

View File

@@ -6,11 +6,14 @@ namespace EE { namespace UI { namespace CSS {
SINGLETON_DECLARE_IMPLEMENTATION( StyleSheetSpecification )
StyleSheetSpecification::StyleSheetSpecification() {
// TODO: Add support to animations (@keyframes).
// TODO: Add correct "background" and "foreground" shorthand.
// TODO: Support border-color top right bottom left.
// TODO: Support border-radius top right bottom left.
// TODO: Support box-sizing or something similar.
// TODO: Add correct "background" and "foreground" shorthand.
// TODO: Create a rule to set the border position against its box.
// Something like: "border-box", with the following options:
// inside: The border is drawn inside the box.
// outside: The border is drawn outside the box.
// over: The border is drawn in the middle point of inside and outside.
registerDefaultProperties();
registerDefaultNodeSelectors();
}

View File

@@ -182,27 +182,27 @@ UIColorPicker::UIColorPicker( UIWindow* attachTo, const UIColorPicker::ColorPick
</RelativeLayout>
</LinearLayout>
<Widget class="separator" layout_width="match_parent" layout_height="1dp" />
<LinearLayout id="red_container" class="slider_container" orientation="horizontal" ayout_width="match_parent" layout_height="wrap_content">
<LinearLayout id="red_container" class="slider_container" orientation="horizontal" layout_width="match_parent" layout_height="wrap_content">
<TextView layout_width="16dp" layout_height="wrap_content" text="R" layout_gravity="center" />
<Slider layout_width="0dp" layout_weight="1" layout_height="wrap_content" orientation="horizontal" layout_gravity="center" minValue="0" maxValue="255" />
<SpinBox layout_width="48dp" layout_height="wrap_content" minValue="0" maxValue="255" />
</LinearLayout>
<LinearLayout id="green_container" class="slider_container" orientation="horizontal" ayout_width="match_parent" layout_height="wrap_content">
<LinearLayout id="green_container" class="slider_container" orientation="horizontal" layout_width="match_parent" layout_height="wrap_content">
<TextView layout_width="16dp" layout_height="wrap_content" text="G" layout_gravity="center" />
<Slider layout_width="0dp" layout_weight="1" layout_height="wrap_content" orientation="horizontal" layout_gravity="center" minValue="0" maxValue="255" />
<SpinBox layout_width="48dp" layout_height="wrap_content" minValue="0" maxValue="255" />
</LinearLayout>
<LinearLayout id="blue_container" class="slider_container" orientation="horizontal" ayout_width="match_parent" layout_height="wrap_content">
<LinearLayout id="blue_container" class="slider_container" orientation="horizontal" layout_width="match_parent" layout_height="wrap_content">
<TextView layout_width="16dp" layout_height="wrap_content" text="B" layout_gravity="center" />
<Slider layout_width="0dp" layout_weight="1" layout_height="wrap_content" orientation="horizontal" layout_gravity="center" minValue="0" maxValue="255" />
<SpinBox layout_width="48dp" layout_height="wrap_content" minValue="0" maxValue="255" />
</LinearLayout>
<LinearLayout id="alpha_container" class="slider_container" orientation="horizontal" ayout_width="match_parent" layout_height="wrap_content">
<LinearLayout id="alpha_container" class="slider_container" orientation="horizontal" layout_width="match_parent" layout_height="wrap_content">
<TextView layout_width="16dp" layout_height="wrap_content" text="A" layout_gravity="center" />
<Slider layout_width="0dp" layout_weight="1" layout_height="wrap_content" orientation="horizontal" layout_gravity="center" minValue="0" maxValue="255" />
<SpinBox layout_width="48dp" layout_height="wrap_content" minValue="0" maxValue="255" />
</LinearLayout>
<LinearLayout id="footer" class="footer" orientation="horizontal" ayout_width="match_parent" layout_height="wrap_content">
<LinearLayout id="footer" class="footer" orientation="horizontal" layout_width="match_parent" layout_height="wrap_content">
<Widget layout_width="0dp" layout_weight="1" layout_height="match_parent" />
<TextView layout_width="wrap_content" layout_height="wrap_content" text="#" layout_gravity="center" />
<TextInput layout_width="120dp" layout_height="wrap_content" />

View File

@@ -97,6 +97,26 @@ bool UIStyle::hasTransition( const std::string& propertyName ) {
mTransitions.find( "all" ) != mTransitions.end();
}
StyleSheetPropertyAnimation* UIStyle::getAnimation( const PropertyDefinition* propertyDef ) {
std::vector<Action*> actions = mWidget->getActionsByTag( propertyDef->getId() );
if ( !actions.empty() ) {
for ( auto& action : actions ) {
if ( action->getId() == StyleSheetPropertyAnimation::ID ) {
StyleSheetPropertyAnimation* animation =
static_cast<StyleSheetPropertyAnimation*>( action );
if ( animation->getAnimationOrigin() == AnimationOrigin::Animation ) {
return animation;
}
}
}
}
return NULL;
}
bool UIStyle::hasAnimation( const PropertyDefinition* propertyDef ) {
return NULL != getAnimation( propertyDef );
}
TransitionDefinition UIStyle::getTransition( const std::string& propertyName ) {
auto propertyTransitionIt = mTransitions.find( propertyName );
@@ -152,9 +172,9 @@ void UIStyle::tryApplyStyle( const StyleSheetStyle& style ) {
mProperties[property.getId()] = property;
if ( String::startsWith( property.getName(), "transition" ) )
mTransitionAttributes.push_back( property );
mTransitionProperties.push_back( property );
else if ( String::startsWith( property.getName(), "animation" ) )
mAnimationAttributes.push_back( property );
mAnimationProperties.push_back( property );
}
}
}
@@ -223,12 +243,10 @@ void UIStyle::onStateChange() {
if ( NULL != mWidget ) {
mChangingState = true;
bool wasAnAnimation = !mAnimations.empty();
CSS::StyleSheetProperties prevProperties( mProperties );
mProperties.clear();
mTransitionAttributes.clear();
mAnimationAttributes.clear();
mAnimations.clear();
mTransitionProperties.clear();
mAnimationProperties.clear();
tryApplyStyle( mElementStyle );
@@ -241,21 +259,14 @@ void UIStyle::onStateChange() {
}
if ( !mapEquals( mProperties, prevProperties ) ) {
if ( wasAnAnimation )
removeAllAnimations();
if ( !mAnimationAttributes.empty() ) {
mAnimations = AnimationDefinition::parseAnimationProperties( mAnimationAttributes );
}
if ( !mTransitionAttributes.empty() ) {
mTransitions =
TransitionDefinition::parseTransitionProperties( mTransitionAttributes );
}
mWidget->beginAttributesTransaction();
startAnimations();
updateAnimations();
if ( !mTransitionProperties.empty() ) {
mTransitions =
TransitionDefinition::parseTransitionProperties( mTransitionProperties );
}
for ( auto& prop : mProperties ) {
StyleSheetProperty& property = prop.second;
@@ -382,7 +393,8 @@ void UIStyle::applyStyleSheetProperty( const StyleSheetProperty& property,
if ( !mWidget->isSceneNodeLoading() && NULL != propertyDefinition &&
StyleSheetPropertyAnimation::animationSupported( propertyDefinition->getType() ) &&
hasTransition( property.getName() ) ) {
hasTransition( property.getName() ) &&
!hasAnimation( property.getPropertyDefinition() ) ) {
std::string currentValue =
mWidget->getPropertyString( propertyDefinition, property.getIndex() );
std::string startValue( currentValue );
@@ -467,14 +479,95 @@ void UIStyle::applyStyleSheetProperty( const StyleSheetProperty& property,
}
}
void UIStyle::startAnimations() {
void UIStyle::updateAnimations() {
bool isDifferent = false;
CSS::AnimationsMap animations;
if ( !mAnimationProperties.empty() ) {
animations = AnimationDefinition::parseAnimationProperties( mAnimationProperties );
if ( animations.size() == mAnimations.size() ) {
for ( auto& animation : animations ) {
auto animIt = mAnimations.find( animation.second.getName() );
if ( animIt == mAnimations.end() || animIt->second != animation.second ) {
isDifferent = true;
break;
}
}
} else {
isDifferent = true;
}
} else if ( !mAnimations.empty() && mAnimationProperties.empty() ) {
isDifferent = true;
}
if ( isDifferent ) {
mAnimations.clear();
removeAllAnimations();
startAnimations( animations );
} else if ( !mAnimationProperties.empty() ) {
updateAnimationsPlayState();
}
}
void UIStyle::updateAnimationsPlayState() {
if ( mAnimations.empty() )
return;
std::vector<Action*> actions = mWidget->getActions();
for ( auto& action : actions ) {
if ( action->getId() == StyleSheetPropertyAnimation::ID ) {
StyleSheetPropertyAnimation* animation =
static_cast<StyleSheetPropertyAnimation*>( action );
if ( animation->getAnimationOrigin() == AnimationOrigin::Animation ) {
// Check all the active animations.
size_t animPos = 0;
for ( auto anim = mAnimations.begin(); anim != mAnimations.end(); anim++ ) {
// Find the animation index by iterating over them...
if ( anim->first == animation->getAnimation().getName() ) {
// Once found the iteration index of the corresponding keyframe animation
// First check if in the current animation properties is there any
// "animation-play-state" definition.
bool isSet = false;
for ( auto& animProp : mAnimationProperties ) {
if ( NULL != animProp.getPropertyDefinition() &&
animProp.getPropertyDefinition()->getPropertyId() ==
PropertyId::AnimationPlayState ) {
// If found, get the pause/running state of the property, using the
// index of the current animation, and set the animation.play-state.
size_t animPropCount = animProp.getPropertyIndexCount();
bool paused = animProp.getPropertyIndex( animPos % animPropCount )
.getValue() == "paused"
? true
: false;
animation->setPaused( paused );
isSet = true;
break;
}
}
// If animation-play-state if set, continue with the next action.
if ( isSet )
break;
// Otherwise set the animation-play-state defined on the animation.
animation->setPaused( animation->getAnimation().isPaused() );
}
animPos++;
}
}
}
}
}
void UIStyle::startAnimations( const CSS::AnimationsMap& animations ) {
UISceneNode* uiSceneNode = mWidget->getUISceneNode();
if ( NULL == uiSceneNode )
return;
mAnimations = animations;
CSS::StyleSheet& styleSheet = uiSceneNode->getStyleSheet();
for ( auto& anim : mAnimations ) {
for ( auto& anim : animations ) {
if ( styleSheet.isKeyframesDefined( anim.first ) ) {
const AnimationDefinition& animation = anim.second;
const KeyframesDefinition& keyframes = styleSheet.getKeyframesDefinition( anim.first );
@@ -493,6 +586,7 @@ void UIStyle::startAnimations() {
StyleSheetPropertyAnimation* newAnimation =
StyleSheetPropertyAnimation::fromAnimationKeyframes(
animation, keyframes, propDef, mWidget, i );
newAnimation->setFlags( animation.getId() );
newAnimation->setTag( propDef->getId() );
mWidget->runAction( newAnimation );
}
@@ -501,6 +595,7 @@ void UIStyle::startAnimations() {
StyleSheetPropertyAnimation* newAnimation =
StyleSheetPropertyAnimation::fromAnimationKeyframes(
animation, keyframes, propDef, mWidget, 0 );
newAnimation->setFlags( animation.getId() );
newAnimation->setTag( propDef->getId() );
mWidget->runAction( newAnimation );
}
@@ -509,6 +604,7 @@ void UIStyle::startAnimations() {
StyleSheetPropertyAnimation* newAnimation =
StyleSheetPropertyAnimation::fromAnimationKeyframes(
animation, keyframes, propDef, mWidget, 0 );
newAnimation->setFlags( animation.getId() );
newAnimation->setTag( propDef->getId() );
mWidget->runAction( newAnimation );
}

View File

@@ -160,6 +160,33 @@ std::string UITabWidget::getPropertyString( const PropertyDefinition* propertyDe
}
}
bool UITabWidget::isDrawInvalidator() const {
return true;
}
void UITabWidget::invalidate( Node* invalidator ) {
// Only invalidate if the invalidator is actually visible in the current active tab.
if ( NULL != invalidator ) {
if ( invalidator == mCtrlContainer ) {
mSceneNode->invalidate( mCtrlContainer );
} else if ( invalidator->getParent() == mCtrlContainer ) {
if ( invalidator->isVisible() ) {
mSceneNode->invalidate( mCtrlContainer );
}
} else {
Node* container = invalidator->getParent();
while ( container->getParent() != NULL && container->getParent() != mCtrlContainer ) {
container = container->getParent();
}
if ( container->getParent() == mCtrlContainer && container->isVisible() ) {
mSceneNode->invalidate( mCtrlContainer );
}
}
} else if ( NULL != mSceneNode ) {
mSceneNode->invalidate( this );
}
}
bool UITabWidget::applyProperty( const StyleSheetProperty& attribute ) {
if ( !checkPropertyDefinition( attribute ) )
return false;

View File

@@ -1112,7 +1112,7 @@ void UIWindow::onPositionChange() {
// Invalidate the buffer since a position change can get childs into a drawable position
// (on screen), when the drawable could have been outside the viewport and not drawn in the
// previous position.
invalidate();
invalidate( this );
UIWidget::onPositionChange();
}
@@ -1241,12 +1241,12 @@ void UIWindow::internalDraw() {
}
}
void UIWindow::invalidate() {
void UIWindow::invalidate( Node* invalidator ) {
if ( mVisible && mAlpha != 0.f ) {
writeNodeFlag( NODE_FLAG_VIEW_DIRTY, 1 );
if ( NULL != mSceneNode )
mSceneNode->invalidate();
mSceneNode->invalidate( invalidator );
}
}