diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6bdbc2269..753104c77 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# ASEPRITE +# Aseprite # Copyright (C) 2001-2013 David Capello add_definitions(-DHAVE_CONFIG_H) @@ -11,9 +11,8 @@ if(MSVC) endif(MSVC) # Libraries in this directory -set(aseprite_libraries app-library raster-lib - scripting-lib undo-lib filters-lib ui-lib - she gfx-lib base-lib) +set(aseprite_libraries app-library css-lib raster-lib scripting-lib + undo-lib filters-lib ui-lib she gfx-lib base-lib) # Directories where .h files can be found include_directories(. .. ../third_party) @@ -150,6 +149,7 @@ endif() add_subdirectory(base) add_subdirectory(filters) add_subdirectory(gfx) +add_subdirectory(css) add_subdirectory(raster) add_subdirectory(scripting) add_subdirectory(she) @@ -244,6 +244,7 @@ endfunction() find_unittests(base base-lib ${sys_libs}) find_unittests(gfx gfx-lib base-lib ${sys_libs}) find_unittests(raster raster-lib gfx-lib base-lib ${libs3rdparty} ${sys_libs}) +find_unittests(css css-lib gfx-lib base-lib ${libs3rdparty} ${sys_libs}) find_unittests(ui ui-lib she gfx-lib base-lib ${libs3rdparty} ${sys_libs}) find_unittests(file ${all_libs}) find_unittests(app ${all_libs}) diff --git a/src/README.md b/src/README.md index 41d60361d..41a070a01 100644 --- a/src/README.md +++ b/src/README.md @@ -15,6 +15,7 @@ because they don't depend on any other component. * [allegro](allegro/): Modified version of [Allegro](http://alleg.sourceforge.net/) library, used for keyboard/mouse input, and drawing 2D graphics on screen. * [base](base/): Core/basic stuff, multithreading, utf8, sha1, file system, memory, etc. + * [css](css/): Style sheet library. * [gfx](gfx/): Abstract graphics structures like point, size, rectangle, region, color, etc. * [scripting](scripting/): JavaScript engine ([V8](https://code.google.com/p/v8/)). * [undo](undo/): Generic library to manage undo history of undoable actions. diff --git a/src/css/CMakeLists.txt b/src/css/CMakeLists.txt new file mode 100644 index 000000000..c7c32b6e2 --- /dev/null +++ b/src/css/CMakeLists.txt @@ -0,0 +1,10 @@ +# Aseprite CSS Library +# Copyright (C) 2013 David Capello + +add_library(css-lib + compound_style.cpp + query.cpp + rule.cpp + sheet.cpp + style.cpp + value.cpp) diff --git a/src/css/LICENSE.txt b/src/css/LICENSE.txt new file mode 100644 index 000000000..d7ebf2162 --- /dev/null +++ b/src/css/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2001-2013 David Capello + +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. diff --git a/src/css/README.md b/src/css/README.md new file mode 100644 index 000000000..b7e8b15c1 --- /dev/null +++ b/src/css/README.md @@ -0,0 +1,4 @@ +# Aseprite CSS Library +*Copyright (C) 2013 David Capello* + +> Distributed under [MIT license](LICENSE.txt) diff --git a/src/css/compound_style.cpp b/src/css/compound_style.cpp new file mode 100644 index 000000000..f10986ff1 --- /dev/null +++ b/src/css/compound_style.cpp @@ -0,0 +1,69 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "css/compound_style.h" + +#include "css/sheet.h" + +namespace css { + +CompoundStyle::CompoundStyle(Sheet* sheet, const std::string& name) : + m_sheet(sheet), + m_name(name) +{ + update(); +} + +void CompoundStyle::update() +{ + deleteQueries(); + + Style* style = m_sheet->getStyle(m_name); + if (style) + m_normal = m_sheet->query(*style); +} + +CompoundStyle::~CompoundStyle() +{ + deleteQueries(); +} + +void CompoundStyle::deleteQueries() +{ + for (QueriesMap::iterator it = m_queries.begin(), end = m_queries.end(); + it != end; ++it) { + delete it->second; + } + m_queries.clear(); +} + +const Value& CompoundStyle::operator[](const Rule& rule) const +{ + return m_normal[rule]; +} + +const Query& CompoundStyle::operator[](const States& states) const +{ + QueriesMap::const_iterator it = m_queries.find(states); + + if (it != m_queries.end()) + return *it->second; + else { + Style* style = m_sheet->getStyle(m_name); + if (style == NULL) + return m_normal; + + Query* newQuery = new Query(m_sheet->query(StatefulStyle(*style, states))); + m_queries[states] = newQuery; + return *newQuery; + } +} + +} // namespace css diff --git a/src/css/compound_style.h b/src/css/compound_style.h new file mode 100644 index 000000000..d9e106b72 --- /dev/null +++ b/src/css/compound_style.h @@ -0,0 +1,42 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifndef CSS_COMPOUND_STYLE_H_INCLUDED +#define CSS_COMPOUND_STYLE_H_INCLUDED + +#include "css/query.h" +#include "css/rule.h" +#include "css/state.h" +#include "css/stateful_style.h" + +namespace css { + + class Sheet; + + class CompoundStyle { + public: + CompoundStyle(Sheet* sheet, const std::string& name); + ~CompoundStyle(); + + void update(); + + const Value& operator[](const Rule& rule) const; + const Query& operator[](const States& states) const; + + private: + typedef std::map QueriesMap; + + void deleteQueries(); + + Sheet* m_sheet; + std::string m_name; + Query m_normal; + mutable QueriesMap m_queries; + }; + +} // namespace css + +#endif diff --git a/src/css/css.h b/src/css/css.h new file mode 100644 index 000000000..9e9f4ea85 --- /dev/null +++ b/src/css/css.h @@ -0,0 +1,19 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifndef CSS_CSS_H_INCLUDED +#define CSS_CSS_H_INCLUDED + +#include "css/compound_style.h" +#include "css/query.h" +#include "css/rule.h" +#include "css/sheet.h" +#include "css/state.h" +#include "css/stateful_style.h" +#include "css/style.h" +#include "css/value.h" + +#endif diff --git a/src/css/css_unittest.cpp b/src/css/css_unittest.cpp new file mode 100644 index 000000000..c6a8d8336 --- /dev/null +++ b/src/css/css_unittest.cpp @@ -0,0 +1,220 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#include + +#include "css/css.h" + +using namespace css; +using namespace std; + +ostream& operator<<(ostream& os, const Value& value) +{ + os << "(" << value.type(); + + if (value.type() == Value::Number) + os << ", " << value.number() << " [" << value.unit() << "]"; + else if (value.type() == Value::String) + os << ", " << value.string(); + + os << ")"; + return os; +} + +TEST(Css, Style) +{ + Rule background("background"); + Rule text("text"); + Rule border("border"); + Style style("style"); + + style[background] = Value("image.png"); + style[text] = Value("hi"); + style[border] = Value(12.0, "px"); + EXPECT_EQ(Value("image.png"), style[background]); + EXPECT_EQ(Value("hi"), style[text]); + EXPECT_EQ(Value(12.0, "px"), style[border]); + + style[border].setNumber(13.0); + EXPECT_EQ(Value(13.0, "px"), style[border]); + + Style style2("style2", &style); + EXPECT_EQ(&style, style2.base()); + EXPECT_EQ(Value(), style2[background]); + EXPECT_EQ(Value(), style2[text]); + EXPECT_EQ(Value(), style2[border]); +} + +TEST(Css, QueryIsInSyncWithStyleSheet) +{ + Rule background("background"); + Sheet sheet; + sheet.addRule(&background); + + Style style("style"); + style[background] = Value("a.png"); + sheet.addStyle(&style); + + Query query = sheet.query(style); + EXPECT_EQ(Value("a.png"), query[background]); + + style[background] = Value("b.png"); + EXPECT_EQ(Value("b.png"), query[background]); +} + +TEST(Css, StatefulStyles) +{ + Rule background("background"); + Rule text("text"); + Rule border("border"); + State hover("hover"); + State focus("focus"); + State active("active"); + Style base("base"); + Style baseHover("base:hover"); + Style baseFocus("base:focus"); + Style baseActive("base:active"); + base[background] = Value("image.png"); + base[text] = Value("textnormal"); + baseHover[text] = Value("texthover"); + baseFocus[border] = Value(12.0); + baseActive[border] = Value(24.0); + + Sheet sheet; + sheet.addRule(&background); + sheet.addRule(&text); + sheet.addRule(&border); + sheet.addStyle(&base); + sheet.addStyle(&baseHover); + sheet.addStyle(&baseFocus); + sheet.addStyle(&baseActive); + + Query query = sheet.query(base); + EXPECT_EQ(Value("image.png"), query[background]); + EXPECT_EQ(Value("textnormal"), query[text]); + + query = sheet.query(base + hover); + EXPECT_EQ(Value("image.png"), query[background]); + EXPECT_EQ(Value("texthover"), query[text]); + + query = sheet.query(base + focus); + EXPECT_EQ(Value("image.png"), query[background]); + EXPECT_EQ(Value("textnormal"), query[text]); + EXPECT_EQ(Value(12.0), query[border]); + + query = sheet.query(base + focus + hover); + EXPECT_EQ(Value("image.png"), query[background]); + EXPECT_EQ(Value("texthover"), query[text]); + EXPECT_EQ(Value(12.0), query[border]); + + query = sheet.query(base + focus + hover + active); + EXPECT_EQ(Value("image.png"), query[background]); + EXPECT_EQ(Value("texthover"), query[text]); + EXPECT_EQ(Value(24.0), query[border]); + + query = sheet.query(base + active + focus + hover); // Different order + EXPECT_EQ(Value("image.png"), query[background]); + EXPECT_EQ(Value("texthover"), query[text]); + EXPECT_EQ(Value(12.0), query[border]); +} + +TEST(Css, StyleHierarchy) +{ + Rule bg("bg"); + Rule fg("fg"); + State hover("hover"); + State focus("focus"); + Style base("base"); + Style stylea("stylea", &base); + Style styleb("styleb", &stylea); + Style stylec("stylec", &styleb); + base[bg] = Value(1); + base[fg] = Value(2); + stylea[bg] = Value(3); + styleb[bg] = Value(4); + styleb[fg] = Value(5); + stylec[bg] = Value(6); + + Sheet sheet; + sheet.addRule(&bg); + sheet.addRule(&fg); + sheet.addStyle(&base); + sheet.addStyle(&stylea); + sheet.addStyle(&styleb); + sheet.addStyle(&stylec); + + Query query = sheet.query(base); + EXPECT_EQ(Value(1), query[bg]); + EXPECT_EQ(Value(2), query[fg]); + + query = sheet.query(stylea); + EXPECT_EQ(Value(3), query[bg]); + EXPECT_EQ(Value(2), query[fg]); + + query = sheet.query(styleb); + EXPECT_EQ(Value(4), query[bg]); + EXPECT_EQ(Value(5), query[fg]); + + query = sheet.query(stylec); + EXPECT_EQ(Value(6), query[bg]); + EXPECT_EQ(Value(5), query[fg]); +} + +TEST(Css, CompoundStyles) +{ + Rule bg("bg"); + Rule fg("fg"); + State hover("hover"); + State focus("focus"); + Style base("base"); + Style baseHover("base:hover"); + Style baseFocus("base:focus"); + Style sub("sub", &base); + Style subFocus("sub:focus", &base); + + base[bg] = Value(1); + base[fg] = Value(2); + baseHover[fg] = Value(3); + baseFocus[bg] = Value(4); + + sub[bg] = Value(5); + subFocus[fg] = Value(6); + + Sheet sheet; + sheet.addRule(&bg); + sheet.addRule(&fg); + sheet.addStyle(&base); + sheet.addStyle(&baseHover); + sheet.addStyle(&baseFocus); + sheet.addStyle(&sub); + sheet.addStyle(&subFocus); + + CompoundStyle compoundBase = sheet.compoundStyle("base"); + EXPECT_EQ(Value(1), compoundBase[bg]); + EXPECT_EQ(Value(2), compoundBase[fg]); + EXPECT_EQ(Value(1), compoundBase[hover][bg]); + EXPECT_EQ(Value(3), compoundBase[hover][fg]); + EXPECT_EQ(Value(4), compoundBase[focus][bg]); + EXPECT_EQ(Value(2), compoundBase[focus][fg]); + EXPECT_EQ(Value(4), compoundBase[hover+focus][bg]); + EXPECT_EQ(Value(3), compoundBase[hover+focus][fg]); + + CompoundStyle compoundSub = sheet.compoundStyle("sub"); + EXPECT_EQ(Value(5), compoundSub[bg]); + EXPECT_EQ(Value(2), compoundSub[fg]); + EXPECT_EQ(Value(5), compoundSub[hover][bg]); + EXPECT_EQ(Value(3), compoundSub[hover][fg]); + EXPECT_EQ(Value(4), compoundSub[focus][bg]); + EXPECT_EQ(Value(6), compoundSub[focus][fg]); + EXPECT_EQ(Value(4), compoundSub[hover+focus][bg]); + EXPECT_EQ(Value(6), compoundSub[hover+focus][fg]); +} + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/css/map.h b/src/css/map.h new file mode 100644 index 000000000..41cd5064b --- /dev/null +++ b/src/css/map.h @@ -0,0 +1,57 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifndef CSS_MAP_H_INCLUDED +#define CSS_MAP_H_INCLUDED + +#include +#include + +namespace css { + + template + class Map { + public: + typedef std::map map; + typedef typename map::iterator iterator; + typedef typename map::const_iterator const_iterator; + + Map() : m_default() { } + + iterator begin() { return m_map.begin(); } + iterator end() { return m_map.end(); } + + const_iterator begin() const { return m_map.begin(); } + const_iterator end() const { return m_map.end(); } + + const T& operator[](const std::string& name) const { + const_iterator it = m_map.find(name); + if (it != m_map.end()) + return it->second; + else + return m_default; + } + + T& operator[](const std::string& name) { + iterator it = m_map.find(name); + if (it != m_map.end()) + return it->second; + else + return m_map[name] = T(); + } + + void add(const std::string& name, T value) { + m_map[name] = value; + } + + private: + map m_map; + T m_default; + }; + +} // namespace css + +#endif diff --git a/src/css/query.cpp b/src/css/query.cpp new file mode 100644 index 000000000..5dde769ac --- /dev/null +++ b/src/css/query.cpp @@ -0,0 +1,28 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "css/query.h" + +namespace css { + +void Query::addRuleValue(const std::string& ruleName, Style* style) +{ + m_ruleValue.add(ruleName, style); +} + +void Query::addFromStyle(Style* style) +{ + for (Style::iterator it = style->begin(), end = style->end(); + it != end; ++it) { + addRuleValue(it->first, style); + } +} + +} // namespace css diff --git a/src/css/query.h b/src/css/query.h new file mode 100644 index 000000000..187b30c63 --- /dev/null +++ b/src/css/query.h @@ -0,0 +1,40 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifndef CSS_QUERY_H_INCLUDED +#define CSS_QUERY_H_INCLUDED + +#include "css/rule.h" +#include "css/style.h" +#include "css/value.h" + +#include + +namespace css { + + class Query { + public: + Query() { } + + void addRuleValue(const std::string& ruleName, Style* style); + void addFromStyle(Style* style); + + const Value& operator[](const Rule& rule) const { + Style* style = m_ruleValue[rule.name()]; + if (style) + return (*style)[rule.name()]; + else + return m_none; + } + + private: + Styles m_ruleValue; + Value m_none; + }; + +} // namespace css + +#endif diff --git a/src/css/rule.cpp b/src/css/rule.cpp new file mode 100644 index 000000000..376273745 --- /dev/null +++ b/src/css/rule.cpp @@ -0,0 +1,20 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "css/rule.h" + +namespace css { + +Rule::Rule(const std::string& name) : + m_name(name) +{ +} + +} // namespace css diff --git a/src/css/rule.h b/src/css/rule.h new file mode 100644 index 000000000..2e13852e5 --- /dev/null +++ b/src/css/rule.h @@ -0,0 +1,32 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifndef CSS_RULE_H_INCLUDED +#define CSS_RULE_H_INCLUDED + +#include "css/map.h" + +#include +#include + +namespace css { + + class Rule { + public: + Rule() { } + Rule(const std::string& name); + + const std::string& name() const { return m_name; } + + private: + std::string m_name; + }; + + typedef Map Rules; + +} // namespace css + +#endif diff --git a/src/css/sheet.cpp b/src/css/sheet.cpp new file mode 100644 index 000000000..859f1d5e7 --- /dev/null +++ b/src/css/sheet.cpp @@ -0,0 +1,80 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "css/sheet.h" + +#include "css/compound_style.h" +#include "css/query.h" +#include "css/stateful_style.h" + +namespace css { + +Sheet::Sheet() +{ +} + +void Sheet::addRule(Rule* rule) +{ + m_rules.add(rule->name(), rule); +} + +void Sheet::addStyle(Style* style) +{ + m_styles.add(style->name(), style); +} + +Style* Sheet::getStyle(const std::string& name) +{ + return m_styles[name]; +} + +Query Sheet::query(const StatefulStyle& compound) +{ + Query query; + + std::string name = compound.style().name(); + Style* style = m_styles[name]; + Style* base = NULL; + if (style) { + base = style->base(); + if (base) + query.addFromStyle(base); + + query.addFromStyle(style); + } + + for (States::const_iterator it = compound.states().begin(), + end = compound.states().end(); it != end; ++it) { + if (base) { + name = base->name(); + name += StatefulStyle::kSeparator; + name += (*it)->name(); + style = m_styles[name]; + if (style) + query.addFromStyle(style); + } + + name = compound.style().name(); + name += StatefulStyle::kSeparator; + name += (*it)->name(); + style = m_styles[name]; + if (style) + query.addFromStyle(style); + } + + return query; +} + +CompoundStyle Sheet::compoundStyle(const std::string& name) +{ + return CompoundStyle(this, name); +} + +} // namespace css diff --git a/src/css/sheet.h b/src/css/sheet.h new file mode 100644 index 000000000..62feed4c4 --- /dev/null +++ b/src/css/sheet.h @@ -0,0 +1,42 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifndef CSS_SHEET_H_INCLUDED +#define CSS_SHEET_H_INCLUDED + +#include "css/rule.h" +#include "css/style.h" +#include "css/value.h" + +#include +#include + +namespace css { + + class CompoundStyle; + class Query; + class StatefulStyle; + + class Sheet { + public: + Sheet(); + + void addRule(Rule* rule); + void addStyle(Style* style); + + Style* getStyle(const std::string& name); + + Query query(const StatefulStyle& stateful); + CompoundStyle compoundStyle(const std::string& name); + + private: + Rules m_rules; + Styles m_styles; + }; + +} // namespace css + +#endif diff --git a/src/css/state.h b/src/css/state.h new file mode 100644 index 000000000..1c0378390 --- /dev/null +++ b/src/css/state.h @@ -0,0 +1,71 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifndef CSS_STATE_H_INCLUDED +#define CSS_STATE_H_INCLUDED + +#include +#include + +namespace css { + + class State { + public: + State() { } + State(const std::string& name) : m_name(name) { } + + const std::string& name() const { return m_name; } + + private: + std::string m_name; + }; + + class States { + public: + typedef std::vector List; + typedef List::iterator iterator; + typedef List::const_iterator const_iterator; + + States() { } + States(const State& state) { + operator+=(state); + } + + iterator begin() { return m_list.begin(); } + iterator end() { return m_list.end(); } + + const_iterator begin() const { return m_list.begin(); } + const_iterator end() const { return m_list.end(); } + + States& operator+=(const State& other) { + m_list.push_back(&other); + return *this; + } + + States& operator+=(const States& others) { + for (const_iterator it=others.begin(), end=others.end(); it != end; ++it) + operator+=(*(*it)); + return *this; + } + + bool operator<(const States& other) const { + return m_list < other.m_list; + } + + private: + List m_list; + }; + + inline States operator+(const State& a, const State& b) { + States states; + states += a; + states += b; + return states; + } + +} // namespace css + +#endif diff --git a/src/css/stateful_style.h b/src/css/stateful_style.h new file mode 100644 index 000000000..3a5a1893d --- /dev/null +++ b/src/css/stateful_style.h @@ -0,0 +1,73 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifndef CSS_STATEFUL_STYLE_H_INCLUDED +#define CSS_STATEFUL_STYLE_H_INCLUDED + +#include "css/rule.h" +#include "css/state.h" +#include "css/style.h" +#include "css/value.h" + +namespace css { + + class StatefulStyle { + public: + static const char kSeparator = ':'; + + StatefulStyle() : m_style(NULL) { } + StatefulStyle(const Style& style) : m_style(&style) { } + StatefulStyle(const State& state) { + operator+=(state); + } + StatefulStyle(const Style& style, const States& states) : + m_style(&style) { + operator+=(states); + } + + const Style& style() const { return *m_style; } + const States& states() const { return m_states; } + + StatefulStyle& setStyle(const Style& style) { + m_style = &style; + return *this; + } + StatefulStyle& operator+=(const State& state) { + m_states += state; + return *this; + } + StatefulStyle& operator+=(const States& states) { + m_states += states; + return *this; + } + + private: + const Style* m_style; + States m_states; + }; + + inline StatefulStyle operator+(const Style& style, const State& state) { + StatefulStyle styleState; + styleState.setStyle(style); + styleState += state; + return styleState; + } + + inline StatefulStyle operator+(StatefulStyle& styleState, const State& state) { + StatefulStyle styleState2 = styleState; + styleState2 += state; + return styleState2; + } + + inline StatefulStyle operator+(StatefulStyle& styleState, const States& states) { + StatefulStyle styleState2 = styleState; + styleState2 += states; + return styleState2; + } + +} // namespace css + +#endif diff --git a/src/css/style.cpp b/src/css/style.cpp new file mode 100644 index 000000000..98eaa34c8 --- /dev/null +++ b/src/css/style.cpp @@ -0,0 +1,20 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "css/style.h" + +namespace css { + +Style::Style(const std::string& name, Style* base) : + m_name(name), + m_base(base) { +} + +} // namespace css diff --git a/src/css/style.h b/src/css/style.h new file mode 100644 index 000000000..b915a194c --- /dev/null +++ b/src/css/style.h @@ -0,0 +1,50 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifndef CSS_STYLE_H_INCLUDED +#define CSS_STYLE_H_INCLUDED + +#include +#include + +#include "css/map.h" +#include "css/rule.h" +#include "css/value.h" + +namespace css { + + class Style { + public: + typedef Values::iterator iterator; + + Style() { } + Style(const std::string& name, Style* base = NULL); + + const std::string& name() const { return m_name; } + Style* base() const { return m_base; } + + const Value& operator[](const Rule& rule) const { + return m_values[rule.name()]; + } + + Value& operator[](const Rule& rule) { + return m_values[rule.name()]; + } + + iterator begin() { return m_values.begin(); } + iterator end() { return m_values.end(); } + + private: + std::string m_name; + Style* m_base; + Values m_values; + }; + + typedef Map Styles; + +} // namespace css + +#endif diff --git a/src/css/value.cpp b/src/css/value.cpp new file mode 100644 index 000000000..2b5833781 --- /dev/null +++ b/src/css/value.cpp @@ -0,0 +1,98 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "css/value.h" + +namespace css { + +Value::Value() : + m_type(None) +{ +} + +Value::Value(double value, const std::string& unit) : + m_type(Number), + m_number(value), + m_string(unit) +{ +} + +Value::Value(const std::string& value) : + m_type(String), + m_string(value) +{ +} + +double Value::number() const +{ + if (m_type == Number) + return m_number; + else + return 0.0; +} + +std::string Value::string() const +{ + if (m_type == String) + return m_string; + else + return std::string(); +} + +std::string Value::unit() const +{ + if (m_type == Number) + return m_string; + else + return std::string(); +} + +void Value::setNumber(double value) +{ + if (m_type != Number) { + m_type = Number; + m_string = ""; + } + m_number = value; +} + +void Value::setString(const std::string& value) +{ + m_type = String; + m_string = value; +} + +void Value::setUnit(const std::string& unit) +{ + if (m_type != Number) { + m_type = Number; + m_number = 0.0; + } + m_string = unit; +} + +bool Value::operator==(const Value& other) const +{ + if (m_type != other.m_type) + return false; + + switch (m_type) { + case None: + return true; + case Number: + return m_number == other.m_number && m_string == other.m_string; + case String: + return m_string == other.m_string; + default: + return false; + } +} + +} // namespace css diff --git a/src/css/value.h b/src/css/value.h new file mode 100644 index 000000000..c84342330 --- /dev/null +++ b/src/css/value.h @@ -0,0 +1,50 @@ +// Aseprite CSS Library +// Copyright (C) 2013 David Capello +// +// This source file is distributed under MIT license, +// please read LICENSE.txt for more information. + +#ifndef CSS_VALUE_H_INCLUDED +#define CSS_VALUE_H_INCLUDED + +#include "css/map.h" + +#include + +namespace css { + + class Value { + public: + enum Type { + None, + Number, + String + }; + + Value(); + explicit Value(double value, const std::string& unit = ""); + explicit Value(const std::string& value); + + Type type() const { return m_type; } + + double number() const; + std::string string() const; + std::string unit() const; + + void setNumber(double value); + void setString(const std::string& value); + void setUnit(const std::string& unit = ""); + + bool operator==(const Value& other) const; + + private: + Type m_type; + double m_number; + std::string m_string; + }; + + typedef Map Values; + +} // namespace css + +#endif