Merge branch 'timeline' into dev

This commit is contained in:
David Capello 2013-12-11 01:41:48 -03:00
commit b5ea9fd7e7
44 changed files with 2746 additions and 728 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -63,6 +63,17 @@
<color id="filelist_selected_row_face" value="#2c4c91" />
<color id="filelist_disabled_row_text" value="#ffc8c8" />
<color id="workspace" value="#7d929e" />
<color id="timeline_normal" value="#c6c6c6" />
<color id="timeline_normal_text" value="#000000" />
<color id="timeline_hover" value="#d9d9d9" />
<color id="timeline_hover_text" value="#000000" />
<color id="timeline_active" value="#7d929e" />
<color id="timeline_active_text" value="#ffffff" />
<color id="timeline_active_hover" value="#99b3c2" />
<color id="timeline_active_hover_text" value="#ffffff" />
<color id="timeline_clicked" value="#536069" />
<color id="timeline_clicked_text" value="#ffffff" />
<color id="timeline_padding" value="#7d929e" />
</colors>
<cursors>
@ -80,14 +91,14 @@
<cursor id="size_bl" x="80" y="176" w="16" h="16" focusx="8" focusy="8" />
<cursor id="size_b" x="80" y="192" w="16" h="16" focusx="8" focusy="8" />
<cursor id="size_br" x="80" y="208" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_tl" x="240" y="96" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_t" x="240" y="112" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_tr" x="240" y="128" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_l" x="240" y="144" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_r" x="240" y="160" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_bl" x="240" y="176" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_b" x="240" y="192" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_br" x="240" y="208" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_tl" x="240" y="160" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_tr" x="256" y="160" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_l" x="240" y="176" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_r" x="256" y="176" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_t" x="240" y="192" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_b" x="256" y="192" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_bl" x="240" y="208" w="16" h="16" focusx="8" focusy="8" />
<cursor id="rotate_br" x="256" y="208" w="16" h="16" focusx="8" focusy="8" />
<cursor id="eyedropper" x="80" y="224" w="16" h="16" focusx="0" focusy="15" />
</cursors>
@ -259,6 +270,133 @@
<part id="drop_down_button_right_selected" x="71" y="48" w1="2" w2="2" w3="3" h1="4" h2="6" h3="6" />
<part id="transformation_handle" x="208" y="144" w="5" h="5" />
<part id="pivot_handle" x="224" y="144" w="9" h="9" />
<part id="timeline_normal" x="240" y="0" w1="2" w2="8" w3="2" h1="2" h2="8" h3="2" />
<part id="timeline_active" x="252" y="0" w1="2" w2="8" w3="2" h1="2" h2="8" h3="2" />
<part id="timeline_hover" x="264" y="0" w1="2" w2="8" w3="2" h1="2" h2="8" h3="2" />
<part id="timeline_active_hover" x="276" y="0" w1="2" w2="8" w3="2" h1="2" h2="8" h3="2" />
<part id="timeline_clicked" x="288" y="0" w1="2" w2="8" w3="2" h1="2" h2="8" h3="2" />
<part id="timeline_open_eye_normal" x="240" y="12" w="12" h="12" />
<part id="timeline_open_eye_active" x="252" y="12" w="12" h="12" />
<part id="timeline_closed_eye_normal" x="240" y="24" w="12" h="12" />
<part id="timeline_closed_eye_active" x="252" y="24" w="12" h="12" />
<part id="timeline_open_padlock_normal" x="240" y="36" w="12" h="12" />
<part id="timeline_open_padlock_active" x="252" y="36" w="12" h="12" />
<part id="timeline_closed_padlock_normal" x="240" y="48" w="12" h="12" />
<part id="timeline_closed_padlock_active" x="252" y="48" w="12" h="12" />
<part id="timeline_empty_frame_normal" x="240" y="60" w="12" h="12" />
<part id="timeline_empty_frame_active" x="252" y="60" w="12" h="12" />
<part id="timeline_keyframe_normal" x="240" y="72" w="12" h="12" />
<part id="timeline_keyframe_active" x="252" y="72" w="12" h="12" />
<part id="timeline_fromleft_normal" x="240" y="84" w="12" h="12" />
<part id="timeline_fromleft_active" x="252" y="84" w="12" h="12" />
<part id="timeline_fromright_normal" x="240" y="96" w="12" h="12" />
<part id="timeline_fromright_active" x="252" y="96" w="12" h="12" />
<part id="timeline_fromboth_normal" x="240" y="108" w="12" h="12" />
<part id="timeline_fromboth_active" x="252" y="108" w="12" h="12" />
<part id="timeline_gear" x="264" y="12" w="12" h="12" />
<part id="timeline_padding" x="276" y="12" w1="2" w2="8" w3="2" h1="2" h2="8" h3="2" />
<part id="timeline_padding_tr" x="288" y="12" w1="2" w2="8" w3="2" h1="2" h2="8" h3="2" />
<part id="timeline_padding_bl" x="276" y="24" w1="2" w2="8" w3="2" h1="2" h2="8" h3="2" />
<part id="timeline_padding_br" x="288" y="24" w1="2" w2="8" w3="2" h1="2" h2="8" h3="2" />
</parts>
<stylesheet>
<!-- timeline -->
<style id="timeline">
<background color="timeline_normal" part="timeline_normal" />
</style>
<!-- timeline_box -->
<style id="timeline_box">
<background color="timeline_normal" part="timeline_normal" />
<text color="timeline_normal_text" align="center" valign="middle" />
</style>
<style id="timeline_box:hover">
<background color="timeline_hover" part="timeline_hover" />
<text color="timeline_hover_text" />
</style>
<style id="timeline_box:active">
<background color="timeline_active" part="timeline_active" />
<text color="timeline_active_text" />
</style>
<style id="timeline_box:active:hover">
<background color="timeline_active_hover" part="timeline_active_hover" />
<text color="timeline_active_hover_text" />
</style>
<style id="timeline_box:clicked">
<background color="timeline_clicked" part="timeline_clicked" />
<text color="timeline_clicked_text" />
</style>
<!-- timeline_eye -->
<style id="timeline_open_eye" base="timeline_box">
<icon part="timeline_open_eye_normal" />
</style>
<style id="timeline_open_eye:active">
<icon part="timeline_open_eye_active" />
</style>
<style id="timeline_closed_eye" base="timeline_box">
<icon part="timeline_closed_eye_normal" />
</style>
<style id="timeline_closed_eye:active">
<icon part="timeline_closed_eye_active" />
</style>
<!-- timeline_padlock -->
<style id="timeline_open_padlock" base="timeline_box">
<icon part="timeline_open_padlock_normal" />
</style>
<style id="timeline_open_padlock:active">
<icon part="timeline_open_padlock_active" />
</style>
<style id="timeline_closed_padlock" base="timeline_box">
<icon part="timeline_closed_padlock_normal" />
</style>
<style id="timeline_closed_padlock:active">
<icon part="timeline_closed_padlock_active" />
</style>
<!-- timeline_layer -->
<style id="timeline_layer" base="timeline_box">
<text align="left" valign="middle" padding-left="4" />
</style>
<!-- timeline_empty_frame -->
<style id="timeline_empty_frame" base="timeline_box">
<icon part="timeline_empty_frame_normal" />
</style>
<style id="timeline_empty_frame:active">
<icon part="timeline_empty_frame_active" />
</style>
<!--timeline_keyframe-->
<style id="timeline_keyframe" base="timeline_box">
<icon part="timeline_keyframe_normal" />
</style>
<style id="timeline_keyframe:active">
<icon part="timeline_keyframe_active" />
</style>
<!-- timeline_cel -->
<style id="timeline_gear" base="timeline_box">
<icon part="timeline_gear" />
</style>
<!-- paddings -->
<style id="timeline_padding">
<background color="timeline_normal" part="timeline_padding" />
</style>
<style id="timeline_padding_tr">
<background color="timeline_normal" part="timeline_padding_tr" />
</style>
<style id="timeline_padding_bl">
<background color="timeline_normal" part="timeline_padding_bl" />
</style>
<style id="timeline_padding_br">
<background color="timeline_normal" part="timeline_padding_br" />
</style>
</stylesheet>
</skin>

View File

@ -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})

View File

@ -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.

View File

@ -177,9 +177,12 @@ add_library(app-library
ui/palette_view.cpp
ui/popup_window_pin.cpp
ui/skin/button_icon_impl.cpp
ui/skin/skin_part.cpp
ui/skin/skin_property.cpp
ui/skin/skin_slider_property.cpp
ui/skin/skin_theme.cpp
ui/skin/style.cpp
ui/skin/style_sheet.cpp
ui/status_bar.cpp
ui/tabs.cpp
ui/timeline.cpp

View File

@ -404,30 +404,17 @@ void setup_mini_look(Widget* widget)
void setup_look(Widget* widget, LookType lookType)
{
SharedPtr<SkinProperty> skinProp;
skinProp = widget->getProperty(SkinProperty::SkinPropertyName);
if (skinProp == NULL)
skinProp.reset(new SkinProperty);
SkinPropertyPtr skinProp = get_skin_property(widget);
skinProp->setLook(lookType);
widget->setProperty(skinProp);
}
void setup_bevels(Widget* widget, int b1, int b2, int b3, int b4)
{
SharedPtr<SkinProperty> skinProp;
skinProp = widget->getProperty(SkinProperty::SkinPropertyName);
if (skinProp == NULL)
skinProp.reset(new SkinProperty);
SkinPropertyPtr skinProp = get_skin_property(widget);
skinProp->setUpperLeft(b1);
skinProp->setUpperRight(b2);
skinProp->setLowerLeft(b3);
skinProp->setLowerRight(b4);
widget->setProperty(skinProp);
}
// Sets the IconInterface pointer interface of the button to show the

View File

@ -128,7 +128,7 @@ void ColorSliders::addSlider(Channel channel, const char* labelText, int min, in
m_entry.push_back(entry);
m_channel.push_back(channel);
slider->setProperty(PropertyPtr(new SkinSliderProperty(new ColorSliderBgPainter(channel))));
slider->setProperty(SkinSliderPropertyPtr(new SkinSliderProperty(new ColorSliderBgPainter(channel))));
slider->setDoubleBuffered(true);
slider->Change.connect(Bind<void>(&ColorSliders::onSliderChange, this, m_slider.size()-1));
@ -201,7 +201,7 @@ void ColorSliders::updateSlidersBgColor(const app::Color& color)
void ColorSliders::updateSliderBgColor(Slider* slider, const app::Color& color)
{
SharedPtr<SkinSliderProperty> sliderProperty(slider->getProperty("SkinProperty"));
SkinSliderPropertyPtr sliderProperty(slider->getProperty(SkinSliderProperty::Name));
static_cast<ColorSliderBgPainter*>(sliderProperty->getBgPainter())->setColor(color);

View File

@ -31,9 +31,9 @@ namespace app {
template<typename Base = ui::Button>
class SkinButton : public Base {
public:
SkinButton(SkinPart partNormal,
SkinPart partHot,
SkinPart partSelected)
SkinButton(SkinParts partNormal,
SkinParts partHot,
SkinParts partSelected)
: Base("")
, m_partNormal(partNormal)
, m_partHot(partHot)
@ -41,9 +41,9 @@ namespace app {
{
}
void setParts(SkinPart partNormal,
SkinPart partHot,
SkinPart partSelected) {
void setParts(SkinParts partNormal,
SkinParts partHot,
SkinParts partSelected) {
m_partNormal = partNormal;
m_partHot = partHot;
m_partSelected = partSelected;
@ -55,7 +55,7 @@ namespace app {
gfx::Rect bounds(Base::getClientBounds());
ui::Graphics* g = ev.getGraphics();
SkinTheme* theme = static_cast<SkinTheme*>(Base::getTheme());
SkinPart part;
SkinParts part;
if (Base::isSelected())
part = m_partSelected;
@ -68,9 +68,9 @@ namespace app {
}
private:
SkinPart m_partNormal;
SkinPart m_partHot;
SkinPart m_partSelected;
SkinParts m_partNormal;
SkinParts m_partHot;
SkinParts m_partSelected;
};
} // namespace skin

View File

@ -0,0 +1,63 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/skin/skin_part.h"
#include <allegro.h>
namespace app {
namespace skin {
SkinPart::SkinPart()
{
}
SkinPart::~SkinPart()
{
clear();
}
void SkinPart::clear()
{
for (Bitmaps::iterator it = m_bitmaps.begin(), end = m_bitmaps.end();
it != end; ++it) {
destroy_bitmap(*it);
*it = NULL;
}
}
void SkinPart::setBitmap(size_t index, BITMAP* bitmap)
{
if (index >= m_bitmaps.size())
m_bitmaps.resize(index+1, NULL);
if (m_bitmaps[index] == bitmap)
return;
if (m_bitmaps[index])
destroy_bitmap(m_bitmaps[index]);
m_bitmaps[index] = bitmap;
}
} // namespace skin
} // namespace app

View File

@ -0,0 +1,54 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef APP_UI_SKIN_SKIN_PART_H_INCLUDED
#define APP_UI_SKIN_SKIN_PART_H_INCLUDED
#include <vector>
#include "base/shared_ptr.h"
struct BITMAP;
namespace app {
namespace skin {
class SkinPart {
public:
typedef std::vector<BITMAP*> Bitmaps;
SkinPart();
~SkinPart();
size_t size() const { return m_bitmaps.size(); }
void clear();
void setBitmap(size_t index, BITMAP* bitmap);
BITMAP* getBitmap(size_t index) const {
return (index < m_bitmaps.size() ? m_bitmaps[index]: NULL);
}
private:
Bitmaps m_bitmaps;
};
typedef SharedPtr<SkinPart> SkinPartPtr;
} // namespace skin
} // namespace app
#endif

View File

@ -33,7 +33,9 @@ namespace app {
name##_W
// Available parts in the skin sheet
enum SkinPart {
enum SkinParts {
PART_NONE,
PART_RADIO_NORMAL,
PART_RADIO_SELECTED,

View File

@ -22,13 +22,15 @@
#include "app/ui/skin/skin_property.h"
#include "ui/widget.h"
namespace app {
namespace skin {
const char* SkinProperty::SkinPropertyName = "SkinProperty";
const char* SkinProperty::Name = "SkinProperty";
SkinProperty::SkinProperty()
: Property(SkinPropertyName)
: Property(Name)
{
m_look = NormalLook;
m_upperLeft = 0;
@ -41,5 +43,18 @@ SkinProperty::~SkinProperty()
{
}
SkinPropertyPtr get_skin_property(ui::Widget* widget)
{
SkinPropertyPtr skinProp;
skinProp = widget->getProperty(SkinProperty::Name);
if (skinProp == NULL) {
skinProp.reset(new SkinProperty);
widget->setProperty(skinProp);
}
return skinProp;
}
} // namespace skin
} // namespace app

View File

@ -19,8 +19,13 @@
#ifndef APP_UI_SKIN_SKIN_PROPERTY_H_INCLUDED
#define APP_UI_SKIN_SKIN_PROPERTY_H_INCLUDED
#include "base/shared_ptr.h"
#include "ui/property.h"
namespace ui {
class Widget;
}
namespace app {
namespace skin {
@ -35,7 +40,7 @@ namespace app {
// Property to show widgets with a special look (e.g.: buttons or sliders with mini-borders)
class SkinProperty : public ui::Property {
public:
static const char* SkinPropertyName;
static const char* Name;
SkinProperty();
~SkinProperty();
@ -61,6 +66,10 @@ namespace app {
int m_lowerRight;
};
typedef SharedPtr<SkinProperty> SkinPropertyPtr;
SkinPropertyPtr get_skin_property(ui::Widget* widget);
} // namespace skin
} // namespace app

View File

@ -25,8 +25,11 @@
namespace app {
namespace skin {
const char* SkinSliderProperty::Name = "SkinSliderProperty";
SkinSliderProperty::SkinSliderProperty(ISliderBgPainter* painter)
: m_painter(painter)
: Property(Name)
, m_painter(painter)
{
}

View File

@ -19,8 +19,9 @@
#ifndef APP_UI_SKIN_SKIN_SLIDER_PROPERTY_H_INCLUDED
#define APP_UI_SKIN_SKIN_SLIDER_PROPERTY_H_INCLUDED
#include "gfx/rect.h"
#include "app/ui/skin/skin_property.h"
#include "base/shared_ptr.h"
#include "gfx/rect.h"
namespace ui {
class Slider;
@ -35,8 +36,10 @@ namespace app {
virtual void paint(ui::Slider* slider, ui::Graphics* graphics, const gfx::Rect& rc) = 0;
};
class SkinSliderProperty : public SkinProperty {
class SkinSliderProperty : public ui::Property {
public:
static const char* Name;
// The given painter is deleted automatically when this
// property the destroyed.
SkinSliderProperty(ISliderBgPainter* painter);
@ -48,6 +51,8 @@ namespace app {
ISliderBgPainter* m_painter;
};
typedef SharedPtr<SkinSliderProperty> SkinSliderPropertyPtr;
} // namespace skin
} // namespace app

View File

@ -29,11 +29,14 @@
#include "app/ui/skin/skin_property.h"
#include "app/ui/skin/skin_slider_property.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/skin/style.h"
#include "app/ui/skin/style_sheet.h"
#include "app/xml_document.h"
#include "app/xml_exception.h"
#include "base/bind.h"
#include "base/fs.h"
#include "base/shared_ptr.h"
#include "css/sheet.h"
#include "gfx/border.h"
#include "gfx/point.h"
#include "gfx/rect.h"
@ -145,8 +148,7 @@ SkinTheme::SkinTheme()
// Initialize all graphics in NULL (these bitmaps are loaded from the skin)
m_sheet_bmp = NULL;
for (int c=0; c<PARTS; ++c)
m_part[c] = NULL;
m_part.resize(PARTS, NULL);
sheet_mapping["radio_normal"] = PART_RADIO_NORMAL;
sheet_mapping["radio_selected"] = PART_RADIO_SELECTED;
@ -348,8 +350,8 @@ SkinTheme::~SkinTheme()
for (size_t c=0; c<m_cursors.size(); ++c)
delete m_cursors[c];
for (int c=0; c<PARTS; ++c)
destroy_bitmap(m_part[c]);
m_part.clear();
m_parts_by_id.clear();
for (std::map<std::string, BITMAP*>::iterator
it = m_toolicon.begin(); it != m_toolicon.end(); ++it) {
@ -364,7 +366,7 @@ SkinTheme::~SkinTheme()
destroy_font(m_minifont);
}
// Call ji_regen_theme after this
// Call Theme::regenerate() after this.
void SkinTheme::reload_skin()
{
if (m_sheet_bmp) {
@ -417,150 +419,241 @@ void SkinTheme::onRegenerate()
{
scrollbar_size = 12 * jguiscale();
m_part.clear();
m_part.resize(PARTS, NULL);
// Load the skin XML
std::string xml_filename = "skins/" + m_selected_skin + "/skin.xml";
ResourceFinder rf;
rf.findInDataDir(xml_filename.c_str());
while (const char* path = rf.next()) {
if (!base::file_exists(path))
continue;
const char* path;
while ((path = rf.next()) &&
!base::file_exists(path)) {
}
if (!path) // not found
return;
XmlDocumentRef doc = open_xml(path);
TiXmlHandle handle(doc);
XmlDocumentRef doc = open_xml(path);
TiXmlHandle handle(doc);
// Load colors
{
TiXmlElement* xmlColor = handle
.FirstChild("skin")
.FirstChild("colors")
.FirstChild("color").ToElement();
while (xmlColor) {
std::string id = xmlColor->Attribute("id");
uint32_t value = strtol(xmlColor->Attribute("value")+1, NULL, 16);
// Load colors
{
TiXmlElement* xmlColor = handle
.FirstChild("skin")
.FirstChild("colors")
.FirstChild("color").ToElement();
while (xmlColor) {
std::string id = xmlColor->Attribute("id");
uint32_t value = strtol(xmlColor->Attribute("value")+1, NULL, 16);
ui::Color color = ui::rgba((value & 0xff0000) >> 16,
(value & 0xff00) >> 8,
(value & 0xff));
std::map<std::string, ThemeColor::Type>::iterator it =
color_mapping.find(id);
if (it != color_mapping.end()) {
m_colors[it->second] = ui::rgba((value & 0xff0000) >> 16,
(value & 0xff00) >> 8,
(value & 0xff));
}
PRINTF("Loading color '%s'...\n", id.c_str());
xmlColor = xmlColor->NextSiblingElement();
m_colors_by_id[id] = color;
std::map<std::string, ThemeColor::Type>::iterator it = color_mapping.find(id);
if (it != color_mapping.end()) {
m_colors[it->second] = color;
}
xmlColor = xmlColor->NextSiblingElement();
}
}
// Load cursors
{
TiXmlElement* xmlCursor = handle
.FirstChild("skin")
.FirstChild("cursors")
.FirstChild("cursor").ToElement();
while (xmlCursor) {
std::string id = xmlCursor->Attribute("id");
int x = strtol(xmlCursor->Attribute("x"), NULL, 10);
int y = strtol(xmlCursor->Attribute("y"), NULL, 10);
int w = strtol(xmlCursor->Attribute("w"), NULL, 10);
int h = strtol(xmlCursor->Attribute("h"), NULL, 10);
int focusx = strtol(xmlCursor->Attribute("focusx"), NULL, 10);
int focusy = strtol(xmlCursor->Attribute("focusy"), NULL, 10);
int c;
// Load cursors
{
TiXmlElement* xmlCursor = handle
.FirstChild("skin")
.FirstChild("cursors")
.FirstChild("cursor").ToElement();
while (xmlCursor) {
std::string id = xmlCursor->Attribute("id");
int x = strtol(xmlCursor->Attribute("x"), NULL, 10);
int y = strtol(xmlCursor->Attribute("y"), NULL, 10);
int w = strtol(xmlCursor->Attribute("w"), NULL, 10);
int h = strtol(xmlCursor->Attribute("h"), NULL, 10);
int focusx = strtol(xmlCursor->Attribute("focusx"), NULL, 10);
int focusy = strtol(xmlCursor->Attribute("focusy"), NULL, 10);
int c;
for (c=0; c<kCursorTypes; ++c) {
if (id != cursor_names[c])
continue;
PRINTF("Loading cursor '%s'...\n", id.c_str());
delete m_cursors[c];
m_cursors[c] = NULL;
for (c=0; c<kCursorTypes; ++c) {
if (id != cursor_names[c])
continue;
BITMAP* bmp = cropPartFromSheet(NULL, x, y, w, h);
she::Surface* surface =
she::Instance()->createSurfaceFromNativeHandle(reinterpret_cast<void*>(bmp));
delete m_cursors[c];
m_cursors[c] = NULL;
m_cursors[c] = new Cursor(surface, gfx::Point(focusx*jguiscale(),
focusy*jguiscale()));
break;
}
BITMAP* bmp = cropPartFromSheet(NULL, x, y, w, h);
she::Surface* surface =
she::Instance()->createSurfaceFromNativeHandle(reinterpret_cast<void*>(bmp));
if (c == kCursorTypes) {
throw base::Exception("Unknown cursor specified in '%s':\n"
"<cursor id='%s' ... />\n", xml_filename.c_str(), id.c_str());
}
xmlCursor = xmlCursor->NextSiblingElement();
m_cursors[c] = new Cursor(surface, gfx::Point(focusx*jguiscale(),
focusy*jguiscale()));
break;
}
}
// Load tool icons
{
TiXmlElement* xmlIcon = handle
.FirstChild("skin")
.FirstChild("tools")
.FirstChild("tool").ToElement();
while (xmlIcon) {
// Get the tool-icon rectangle
const char* tool_id = xmlIcon->Attribute("id");
int x = strtol(xmlIcon->Attribute("x"), NULL, 10);
int y = strtol(xmlIcon->Attribute("y"), NULL, 10);
int w = strtol(xmlIcon->Attribute("w"), NULL, 10);
int h = strtol(xmlIcon->Attribute("h"), NULL, 10);
// Crop the tool-icon from the sheet
m_toolicon[tool_id] = cropPartFromSheet(m_toolicon[tool_id], x, y, w, h);
xmlIcon = xmlIcon->NextSiblingElement();
if (c == kCursorTypes) {
throw base::Exception("Unknown cursor specified in '%s':\n"
"<cursor id='%s' ... />\n", xml_filename.c_str(), id.c_str());
}
xmlCursor = xmlCursor->NextSiblingElement();
}
}
// Load parts
{
TiXmlElement* xmlPart = handle
.FirstChild("skin")
.FirstChild("parts")
.FirstChild("part").ToElement();
while (xmlPart) {
// Get the tool-icon rectangle
const char* part_id = xmlPart->Attribute("id");
int x = strtol(xmlPart->Attribute("x"), NULL, 10);
int y = strtol(xmlPart->Attribute("y"), NULL, 10);
int w = xmlPart->Attribute("w") ? strtol(xmlPart->Attribute("w"), NULL, 10): 0;
int h = xmlPart->Attribute("h") ? strtol(xmlPart->Attribute("h"), NULL, 10): 0;
std::map<std::string, int>::iterator it = sheet_mapping.find(part_id);
if (it == sheet_mapping.end()) {
throw base::Exception("Unknown part specified in '%s':\n"
"<part id='%s' ... />\n", xml_filename.c_str(), part_id);
}
// Load tool icons
{
TiXmlElement* xmlIcon = handle
.FirstChild("skin")
.FirstChild("tools")
.FirstChild("tool").ToElement();
while (xmlIcon) {
// Get the tool-icon rectangle
const char* tool_id = xmlIcon->Attribute("id");
int x = strtol(xmlIcon->Attribute("x"), NULL, 10);
int y = strtol(xmlIcon->Attribute("y"), NULL, 10);
int w = strtol(xmlIcon->Attribute("w"), NULL, 10);
int h = strtol(xmlIcon->Attribute("h"), NULL, 10);
PRINTF("Loading tool icon '%s'...\n", tool_id);
// Crop the tool-icon from the sheet
m_toolicon[tool_id] = cropPartFromSheet(m_toolicon[tool_id], x, y, w, h);
xmlIcon = xmlIcon->NextSiblingElement();
}
}
// Load parts
{
TiXmlElement* xmlPart = handle
.FirstChild("skin")
.FirstChild("parts")
.FirstChild("part").ToElement();
while (xmlPart) {
// Get the tool-icon rectangle
const char* part_id = xmlPart->Attribute("id");
int x = strtol(xmlPart->Attribute("x"), NULL, 10);
int y = strtol(xmlPart->Attribute("y"), NULL, 10);
int w = xmlPart->Attribute("w") ? strtol(xmlPart->Attribute("w"), NULL, 10): 0;
int h = xmlPart->Attribute("h") ? strtol(xmlPart->Attribute("h"), NULL, 10): 0;
PRINTF("Loading part '%s'...\n", part_id);
SkinPartPtr part = m_parts_by_id[part_id];
if (part == NULL)
part = m_parts_by_id[part_id] = SkinPartPtr(new SkinPart);
if (w > 0 && h > 0) {
part->setBitmap(0, cropPartFromSheet(part->getBitmap(0), x, y, w, h));
}
else if (xmlPart->Attribute("w1")) { // 3x3-1 part (NW, N, NE, E, SE, S, SW, W)
int w1 = strtol(xmlPart->Attribute("w1"), NULL, 10);
int w2 = strtol(xmlPart->Attribute("w2"), NULL, 10);
int w3 = strtol(xmlPart->Attribute("w3"), NULL, 10);
int h1 = strtol(xmlPart->Attribute("h1"), NULL, 10);
int h2 = strtol(xmlPart->Attribute("h2"), NULL, 10);
int h3 = strtol(xmlPart->Attribute("h3"), NULL, 10);
part->setBitmap(0, cropPartFromSheet(part->getBitmap(0), x, y, w1, h1)); // NW
part->setBitmap(1, cropPartFromSheet(part->getBitmap(1), x+w1, y, w2, h1)); // N
part->setBitmap(2, cropPartFromSheet(part->getBitmap(2), x+w1+w2, y, w3, h1)); // NE
part->setBitmap(3, cropPartFromSheet(part->getBitmap(3), x+w1+w2, y+h1, w3, h2)); // E
part->setBitmap(4, cropPartFromSheet(part->getBitmap(4), x+w1+w2, y+h1+h2, w3, h3)); // SE
part->setBitmap(5, cropPartFromSheet(part->getBitmap(5), x+w1, y+h1+h2, w2, h3)); // S
part->setBitmap(6, cropPartFromSheet(part->getBitmap(6), x, y+h1+h2, w1, h3)); // SW
part->setBitmap(7, cropPartFromSheet(part->getBitmap(7), x, y+h1, w1, h2)); // W
}
// Prepare the m_part vector (which is used for backward
// compatibility for widgets that doesn't use SkinStyle).
std::map<std::string, int>::iterator it = sheet_mapping.find(part_id);
if (it != sheet_mapping.end()) {
int c = it->second;
if (w > 0 && h > 0) {
// Crop the part from the sheet
m_part[c] = cropPartFromSheet(m_part[c], x, y, w, h);
}
else if (xmlPart->Attribute("w1")) { // 3x3-1 part (NW, N, NE, E, SE, S, SW, W)
int w1 = strtol(xmlPart->Attribute("w1"), NULL, 10);
int w2 = strtol(xmlPart->Attribute("w2"), NULL, 10);
int w3 = strtol(xmlPart->Attribute("w3"), NULL, 10);
int h1 = strtol(xmlPart->Attribute("h1"), NULL, 10);
int h2 = strtol(xmlPart->Attribute("h2"), NULL, 10);
int h3 = strtol(xmlPart->Attribute("h3"), NULL, 10);
m_part[c ] = cropPartFromSheet(m_part[c ], x, y, w1, h1); // NW
m_part[c+1] = cropPartFromSheet(m_part[c+1], x+w1, y, w2, h1); // N
m_part[c+2] = cropPartFromSheet(m_part[c+2], x+w1+w2, y, w3, h1); // NE
m_part[c+3] = cropPartFromSheet(m_part[c+3], x+w1+w2, y+h1, w3, h2); // E
m_part[c+4] = cropPartFromSheet(m_part[c+4], x+w1+w2, y+h1+h2, w3, h3); // SE
m_part[c+5] = cropPartFromSheet(m_part[c+5], x+w1, y+h1+h2, w2, h3); // S
m_part[c+6] = cropPartFromSheet(m_part[c+6], x, y+h1+h2, w1, h3); // SW
m_part[c+7] = cropPartFromSheet(m_part[c+7], x, y+h1, w1, h2); // W
}
xmlPart = xmlPart->NextSiblingElement();
for (size_t i=0; i<part->size(); ++i)
m_part[c+i] = part->getBitmap(i);
}
}
break;
xmlPart = xmlPart->NextSiblingElement();
}
}
// Load styles
{
TiXmlElement* xmlStyle = handle
.FirstChild("skin")
.FirstChild("stylesheet")
.FirstChild("style").ToElement();
while (xmlStyle) {
const char* style_id = xmlStyle->Attribute("id");
const char* base_id = xmlStyle->Attribute("base");
const css::Style* base = NULL;
if (base_id)
base = m_stylesheet.sheet().getStyle(base_id);
css::Style* style = new css::Style(style_id, base);
m_stylesheet.sheet().addStyle(style);
TiXmlElement* xmlRule = xmlStyle->FirstChildElement();
while (xmlRule) {
const std::string ruleName = xmlRule->Value();
PRINTF("- Rule '%s' for '%s'\n", ruleName.c_str(), style_id);
// TODO This code design to read styles could be improved.
const char* part_id = xmlRule->Attribute("part");
const char* color_id = xmlRule->Attribute("color");
// Style align
int align = 0;
const char* halign = xmlRule->Attribute("align");
const char* valign = xmlRule->Attribute("valign");
if (halign) {
if (strcmp(halign, "left") == 0) align |= JI_LEFT;
else if (strcmp(halign, "right") == 0) align |= JI_RIGHT;
else if (strcmp(halign, "center") == 0) align |= JI_CENTER;
}
if (valign) {
if (strcmp(valign, "top") == 0) align |= JI_TOP;
else if (strcmp(valign, "bottom") == 0) align |= JI_BOTTOM;
else if (strcmp(valign, "middle") == 0) align |= JI_MIDDLE;
}
if (ruleName == "background") {
if (color_id) (*style)[StyleSheet::backgroundColorRule()] = css::Value(color_id);
if (part_id) (*style)[StyleSheet::backgroundPartRule()] = css::Value(part_id);
}
else if (ruleName == "icon") {
if (align) (*style)[StyleSheet::iconAlignRule()] = css::Value(align);
if (part_id) (*style)[StyleSheet::iconPartRule()] = css::Value(part_id);
}
else if (ruleName == "text") {
if (color_id) (*style)[StyleSheet::textColorRule()] = css::Value(color_id);
if (align) (*style)[StyleSheet::textAlignRule()] = css::Value(align);
const char* padding_left = xmlRule->Attribute("padding-left");
const char* padding_top = xmlRule->Attribute("padding-top");
const char* padding_right = xmlRule->Attribute("padding-right");
const char* padding_bottom = xmlRule->Attribute("padding-bottom");
if (padding_left) (*style)[StyleSheet::paddingLeftRule()] = css::Value(strtol(padding_left, NULL, 10));
if (padding_top) (*style)[StyleSheet::paddingTopRule()] = css::Value(strtol(padding_top, NULL, 10));
if (padding_right) (*style)[StyleSheet::paddingRightRule()] = css::Value(strtol(padding_right, NULL, 10));
if (padding_bottom) (*style)[StyleSheet::paddingBottomRule()] = css::Value(strtol(padding_bottom, NULL, 10));
}
xmlRule = xmlRule->NextSiblingElement();
}
xmlStyle = xmlStyle->NextSiblingElement();
}
}
}
@ -851,7 +944,7 @@ void SkinTheme::paintButton(PaintEvent& ev)
// Tool buttons are smaller
LookType look = NormalLook;
SharedPtr<SkinProperty> skinPropery = widget->getProperty(SkinProperty::SkinPropertyName);
SkinPropertyPtr skinPropery = widget->getProperty(SkinProperty::Name);
if (skinPropery != NULL)
look = skinPropery->getLook();
@ -926,7 +1019,7 @@ void SkinTheme::paintCheckBox(PaintEvent& ev)
// Check box look
LookType look = NormalLook;
SharedPtr<SkinProperty> skinPropery = widget->getProperty(SkinProperty::SkinPropertyName);
SkinPropertyPtr skinPropery = widget->getProperty(SkinProperty::Name);
if (skinPropery != NULL)
look = skinPropery->getLook();
@ -990,7 +1083,7 @@ void SkinTheme::paintEntry(PaintEvent& ev)
y2 = widget->getBounds().y2()-1;
bool isMiniLook = false;
SharedPtr<SkinProperty> skinPropery = widget->getProperty(SkinProperty::SkinPropertyName);
SkinPropertyPtr skinPropery = widget->getProperty(SkinProperty::Name);
if (skinPropery != NULL)
isMiniLook = (skinPropery->getLook() == MiniLook);
@ -1404,12 +1497,13 @@ void SkinTheme::paintSlider(PaintEvent& ev)
// customized background (e.g. RGB sliders)
ISliderBgPainter* bgPainter = NULL;
SharedPtr<SkinProperty> skinPropery = widget->getProperty(SkinProperty::SkinPropertyName);
SkinPropertyPtr skinPropery = widget->getProperty(SkinProperty::Name);
if (skinPropery != NULL)
isMiniLook = (skinPropery->getLook() == MiniLook);
if (SkinSliderProperty* sliderProperty = dynamic_cast<SkinSliderProperty*>(skinPropery.get()))
bgPainter = sliderProperty->getBgPainter();
SkinSliderPropertyPtr skinSliderPropery = widget->getProperty(SkinSliderProperty::Name);
if (skinSliderPropery != NULL)
bgPainter = skinSliderPropery->getBgPainter();
// Draw customized background
if (bgPainter) {
@ -2022,53 +2116,82 @@ void SkinTheme::draw_bounds_template(BITMAP* bmp, int x1, int y1, int x2, int y2
void SkinTheme::draw_bounds_template(Graphics* g, const Rect& rc,
int nw, int n, int ne, int e, int se, int s, int sw, int w)
{
draw_bounds_template(g, rc,
m_part[nw],
m_part[n],
m_part[ne],
m_part[e],
m_part[se],
m_part[s],
m_part[sw],
m_part[w]);
}
void SkinTheme::draw_bounds_template(ui::Graphics* g, const gfx::Rect& rc, const SkinPartPtr& skinPart)
{
draw_bounds_template(g, rc,
skinPart->getBitmap(0),
skinPart->getBitmap(1),
skinPart->getBitmap(2),
skinPart->getBitmap(3),
skinPart->getBitmap(4),
skinPart->getBitmap(5),
skinPart->getBitmap(6),
skinPart->getBitmap(7));
}
void SkinTheme::draw_bounds_template(Graphics* g, const Rect& rc,
BITMAP* nw, BITMAP* n, BITMAP* ne,
BITMAP* e, BITMAP* se, BITMAP* s,
BITMAP* sw, BITMAP* w)
{
int x, y;
// Top
g->drawAlphaBitmap(m_part[nw], rc.x, rc.y);
g->drawAlphaBitmap(nw, rc.x, rc.y);
if (IntersectClip clip = IntersectClip(g, Rect(rc.x+m_part[nw]->w, rc.y,
rc.w-m_part[nw]->w-m_part[ne]->w, rc.h))) {
for (x = rc.x+m_part[nw]->w;
x < rc.x+rc.w-m_part[ne]->w;
x += m_part[n]->w) {
g->drawAlphaBitmap(m_part[n], x, rc.y);
if (IntersectClip clip = IntersectClip(g, Rect(rc.x+nw->w, rc.y,
rc.w-nw->w-ne->w, rc.h))) {
for (x = rc.x+nw->w;
x < rc.x+rc.w-ne->w;
x += n->w) {
g->drawAlphaBitmap(n, x, rc.y);
}
}
g->drawAlphaBitmap(m_part[ne], rc.x+rc.w-m_part[ne]->w, rc.y);
g->drawAlphaBitmap(ne, rc.x+rc.w-ne->w, rc.y);
// Bottom
g->drawAlphaBitmap(m_part[sw], rc.x, rc.y+rc.h-m_part[sw]->h);
g->drawAlphaBitmap(sw, rc.x, rc.y+rc.h-sw->h);
if (IntersectClip clip = IntersectClip(g, Rect(rc.x+m_part[sw]->w, rc.y,
rc.w-m_part[sw]->w-m_part[se]->w, rc.h))) {
for (x = rc.x+m_part[sw]->w;
x < rc.x+rc.w-m_part[se]->w;
x += m_part[s]->w) {
g->drawAlphaBitmap(m_part[s], x, rc.y+rc.h-m_part[s]->h);
if (IntersectClip clip = IntersectClip(g, Rect(rc.x+sw->w, rc.y,
rc.w-sw->w-se->w, rc.h))) {
for (x = rc.x+sw->w;
x < rc.x+rc.w-se->w;
x += s->w) {
g->drawAlphaBitmap(s, x, rc.y+rc.h-s->h);
}
}
g->drawAlphaBitmap(m_part[se], rc.x+rc.w-m_part[se]->w, rc.y+rc.h-m_part[se]->h);
g->drawAlphaBitmap(se, rc.x+rc.w-se->w, rc.y+rc.h-se->h);
if (IntersectClip clip = IntersectClip(g, Rect(rc.x, rc.y+m_part[nw]->h,
rc.w, rc.h-m_part[nw]->h-m_part[sw]->h))) {
if (IntersectClip clip = IntersectClip(g, Rect(rc.x, rc.y+nw->h,
rc.w, rc.h-nw->h-sw->h))) {
// Left
for (y = rc.y+m_part[nw]->h;
y < rc.y+rc.h-m_part[sw]->h;
y += m_part[w]->h) {
g->drawAlphaBitmap(m_part[w], rc.x, y);
for (y = rc.y+nw->h;
y < rc.y+rc.h-sw->h;
y += w->h) {
g->drawAlphaBitmap(w, rc.x, y);
}
// Right
for (y = rc.y+m_part[ne]->h;
y < rc.y+rc.h-m_part[se]->h;
y += m_part[e]->h) {
g->drawAlphaBitmap(m_part[e], rc.x+rc.w-m_part[e]->w, y);
for (y = rc.y+ne->h;
y < rc.y+rc.h-se->h;
y += e->h) {
g->drawAlphaBitmap(e, rc.x+rc.w-e->w, y);
}
}
}
@ -2123,6 +2246,19 @@ void SkinTheme::draw_bounds_nw(Graphics* g, const Rect& rc, int nw, ui::Color bg
}
}
void SkinTheme::draw_bounds_nw(ui::Graphics* g, const gfx::Rect& rc, const SkinPartPtr skinPart, ui::Color bg)
{
draw_bounds_template(g, rc, skinPart);
// Center
if (!is_transparent(bg)) {
g->fillRect(bg, Rect(rc).shrink(Border(skinPart->getBitmap(7)->w,
skinPart->getBitmap(1)->h,
skinPart->getBitmap(3)->w,
skinPart->getBitmap(5)->h)));
}
}
void SkinTheme::draw_bounds_nw2(Graphics* g, const Rect& rc, int x_mid, int nw1, int nw2, ui::Color bg1, ui::Color bg2)
{
Rect rc2(rc.x, rc.y, x_mid-rc.x+1, rc.h);

View File

@ -19,9 +19,13 @@
#ifndef APP_UI_SKIN_SKIN_THEME_H_INCLUDED
#define APP_UI_SKIN_SKIN_THEME_H_INCLUDED
#include "gfx/fwd.h"
#include "app/ui/skin/skin_part.h"
#include "app/ui/skin/skin_parts.h"
#include "app/ui/skin/style_sheet.h"
#include "base/compiler_specific.h"
#include "gfx/fwd.h"
#include "ui/color.h"
#include "ui/manager.h"
#include "ui/system.h"
#include "ui/theme.h"
@ -164,6 +168,7 @@ namespace app {
void draw_bounds_array(BITMAP* bmp, int x1, int y1, int x2, int y2, int parts[8]);
void draw_bounds_nw(BITMAP* bmp, int x1, int y1, int x2, int y2, int nw, ui::Color bg = ui::ColorNone);
void draw_bounds_nw(ui::Graphics* g, const gfx::Rect& rc, int nw, ui::Color bg = ui::ColorNone);
void draw_bounds_nw(ui::Graphics* g, const gfx::Rect& rc, const SkinPartPtr skinPart, ui::Color bg = ui::ColorNone);
void draw_bounds_nw2(ui::Graphics* g, const gfx::Rect& rc, int x_mid, int nw1, int nw2, ui::Color bg1, ui::Color bg2);
void draw_part_as_hline(BITMAP* bmp, int x1, int y1, int x2, int y2, int part);
void draw_part_as_vline(BITMAP* bmp, int x1, int y1, int x2, int y2, int part);
@ -177,14 +182,31 @@ namespace app {
void drawProgressBar(BITMAP* bmp, int x1, int y1, int x2, int y2, float progress);
Style* getStyle(const std::string& id) {
return m_stylesheet.getStyle(id);
}
SkinPartPtr getPartById(const std::string& id) {
return m_parts_by_id[id];
}
ui::Color getColorById(const std::string& id) {
return m_colors_by_id[id];
}
protected:
void onRegenerate();
void onRegenerate() OVERRIDE;
private:
void draw_bounds_template(BITMAP* bmp, int x1, int y1, int x2, int y2,
int nw, int n, int ne, int e, int se, int s, int sw, int w);
void draw_bounds_template(ui::Graphics* g, const gfx::Rect& rc,
int nw, int n, int ne, int e, int se, int s, int sw, int w);
void draw_bounds_template(ui::Graphics* g, const gfx::Rect& rc, const SkinPartPtr& skinPart);
void draw_bounds_template(ui::Graphics* g, const gfx::Rect& rc,
BITMAP* nw, BITMAP* n, BITMAP* ne,
BITMAP* e, BITMAP* se, BITMAP* s,
BITMAP* sw, BITMAP* w);
BITMAP* cropPartFromSheet(BITMAP* bmp, int x, int y, int w, int h);
ui::Color getWidgetBgColor(ui::Widget* widget);
@ -202,13 +224,28 @@ namespace app {
std::string m_selected_skin;
BITMAP* m_sheet_bmp;
BITMAP* m_part[PARTS];
std::vector<BITMAP*> m_part;
std::map<std::string, SkinPartPtr> m_parts_by_id;
std::map<std::string, BITMAP*> m_toolicon;
std::map<std::string, ui::Color> m_colors_by_id;
std::vector<ui::Cursor*> m_cursors;
std::vector<ui::Color> m_colors;
StyleSheet m_stylesheet;
FONT* m_minifont;
};
inline Style* get_style(const std::string& id) {
return static_cast<SkinTheme*>(ui::Manager::getDefault()->getTheme())->getStyle(id);
}
inline SkinPartPtr get_part_by_id(const std::string& id) {
return static_cast<SkinTheme*>(ui::Manager::getDefault()->getTheme())->getPartById(id);
}
inline ui::Color get_color_by_id(const std::string& id) {
return static_cast<SkinTheme*>(ui::Manager::getDefault()->getTheme())->getColorById(id);
}
} // namespace skin
} // namespace app

202
src/app/ui/skin/style.cpp Normal file
View File

@ -0,0 +1,202 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/skin/style.h"
#include "app/ui/skin/skin_theme.h"
#include "css/sheet.h"
#include "ui/graphics.h"
#include "ui/theme.h"
#include <allegro.h>
namespace app {
namespace skin {
css::State Style::m_hoverState("hover");
css::State Style::m_activeState("active");
css::State Style::m_clickedState("clicked");
Rule::~Rule()
{
}
void Rule::paint(ui::Graphics* g,
const gfx::Rect& bounds,
const char* text)
{
onPaint(g, bounds, text);
}
void BackgroundRule::onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* text)
{
SkinTheme* theme = static_cast<SkinTheme*>(ui::CurrentTheme::get());
if (m_part != NULL && m_part->size() > 0) {
if (m_part->size() == 1) {
if (!ui::is_transparent(m_color))
g->fillRect(m_color, bounds);
g->drawAlphaBitmap(m_part->getBitmap(0), bounds.x, bounds.y);
}
else if (m_part->size() == 8) {
theme->draw_bounds_nw(g, bounds, m_part, m_color);
}
}
else if (!ui::is_transparent(m_color)) {
g->fillRect(m_color, bounds);
}
}
void TextRule::onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* text)
{
SkinTheme* theme = static_cast<SkinTheme*>(ui::CurrentTheme::get());
if (text) {
g->drawString(text,
(ui::is_transparent(m_color) ?
theme->getColor(ThemeColor::Text):
m_color),
ui::ColorNone,
gfx::Rect(bounds).shrink(m_padding), m_align);
}
}
void IconRule::onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* text)
{
BITMAP* bmp = m_part->getBitmap(0);
int x, y;
if (m_align & JI_RIGHT)
x = bounds.x2() - bmp->w;
else if (m_align & JI_CENTER)
x = bounds.x + bounds.w/2 - bmp->w/2;
else
x = bounds.x;
if (m_align & JI_BOTTOM)
y = bounds.y2() - bmp->h;
else if (m_align & JI_MIDDLE)
y = bounds.y + bounds.h/2 - bmp->h/2;
else
y = bounds.y;
g->drawAlphaBitmap(bmp, x, y);
}
Rules::Rules(const css::Query& query) :
m_background(NULL),
m_text(NULL),
m_icon(NULL)
{
css::Value backgroundColor = query[StyleSheet::backgroundColorRule()];
css::Value backgroundPart = query[StyleSheet::backgroundPartRule()];
css::Value iconAlign = query[StyleSheet::iconAlignRule()];
css::Value iconPart = query[StyleSheet::iconPartRule()];
css::Value textAlign = query[StyleSheet::textAlignRule()];
css::Value textColor = query[StyleSheet::textColorRule()];
css::Value paddingLeft = query[StyleSheet::paddingLeftRule()];
css::Value paddingTop = query[StyleSheet::paddingTopRule()];
css::Value paddingRight = query[StyleSheet::paddingRightRule()];
css::Value paddingBottom = query[StyleSheet::paddingBottomRule()];
css::Value none;
if (backgroundColor != none
|| backgroundPart != none) {
m_background = new BackgroundRule();
m_background->setColor(StyleSheet::convertColor(backgroundColor));
m_background->setPart(StyleSheet::convertPart(backgroundPart));
}
if (iconAlign != none
|| iconPart != none) {
m_icon = new IconRule();
m_icon->setAlign((int)iconAlign.number());
m_icon->setPart(StyleSheet::convertPart(iconPart));
}
if (textAlign != none
|| textColor != none
|| paddingLeft != none
|| paddingTop != none
|| paddingRight != none
|| paddingBottom != none) {
m_text = new TextRule();
m_text->setAlign((int)textAlign.number());
m_text->setColor(StyleSheet::convertColor(textColor));
m_text->setPadding(gfx::Border(
paddingLeft.number(), paddingTop.number(),
paddingRight.number(), paddingBottom.number())*ui::jguiscale());
}
}
Rules::~Rules()
{
delete m_background;
delete m_text;
delete m_icon;
}
void Rules::paint(ui::Graphics* g,
const gfx::Rect& bounds,
const char* text)
{
if (m_background) m_background->paint(g, bounds, text);
if (m_icon) m_icon->paint(g, bounds, text);
if (m_text) m_text->paint(g, bounds, text);
}
Style::Style(css::Sheet& sheet, const std::string& id)
: m_id(id)
, m_compoundStyle(sheet.compoundStyle(id))
{
}
Style::~Style()
{
for (RulesMap::iterator it = m_rules.begin(), end = m_rules.end();
it != end; ++it) {
delete it->second;
}
}
void Style::paint(ui::Graphics* g,
const gfx::Rect& bounds,
const char* text,
const State& state)
{
Rules* rules = NULL;
RulesMap::iterator it = m_rules.find(state);
if (it != m_rules.end()) {
rules = it->second;
}
else {
rules = new Rules(m_compoundStyle[state]);
m_rules[state] = rules;
}
rules->paint(g, bounds, text);
}
} // namespace skin
} // namespace app

154
src/app/ui/skin/style.h Normal file
View File

@ -0,0 +1,154 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef APP_UI_SKIN_STYLE_H_INCLUDED
#define APP_UI_SKIN_STYLE_H_INCLUDED
#include "app/ui/skin/skin_part.h"
#include "base/compiler_specific.h"
#include "base/disable_copying.h"
#include "css/compound_style.h"
#include "css/state.h"
#include "css/stateful_style.h"
#include "gfx/border.h"
#include "gfx/fwd.h"
#include "ui/color.h"
#include <map>
#include <string>
#include <vector>
namespace ui {
class Graphics;
}
namespace app {
namespace skin {
class Rule {
public:
Rule() { }
virtual ~Rule();
void paint(ui::Graphics* g,
const gfx::Rect& bounds,
const char* text);
protected:
virtual void onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* text) = 0;
};
class BackgroundRule : public Rule {
public:
BackgroundRule() : m_color(ui::ColorNone) { }
void setColor(ui::Color color) { m_color = color; }
void setPart(const SkinPartPtr& part) { m_part = part; }
protected:
void onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* text) OVERRIDE;
private:
ui::Color m_color;
SkinPartPtr m_part;
};
class TextRule : public Rule {
public:
explicit TextRule() : m_align(0),
m_color(ui::ColorNone) { }
void setAlign(int align) { m_align = align; }
void setColor(ui::Color color) { m_color = color; }
void setPadding(const gfx::Border& padding) { m_padding = padding; }
protected:
void onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* text) OVERRIDE;
private:
int m_align;
ui::Color m_color;
gfx::Border m_padding;
};
class IconRule : public Rule {
public:
explicit IconRule() : m_align(0) { }
void setAlign(int align) { m_align = align; }
void setPart(const SkinPartPtr& part) { m_part = part; }
protected:
void onPaint(ui::Graphics* g, const gfx::Rect& bounds, const char* text) OVERRIDE;
private:
int m_align;
SkinPartPtr m_part;
};
class Rules {
public:
Rules(const css::Query& query);
~Rules();
void paint(ui::Graphics* g,
const gfx::Rect& bounds,
const char* text);
private:
BackgroundRule* m_background;
TextRule* m_text;
IconRule* m_icon;
DISABLE_COPYING(Rules);
};
class Style {
public:
typedef css::States State;
static const css::State& hover() { return m_hoverState; }
static const css::State& active() { return m_activeState; }
static const css::State& clicked() { return m_clickedState; }
Style(css::Sheet& sheet, const std::string& id);
~Style();
void paint(ui::Graphics* g,
const gfx::Rect& bounds,
const char* text,
const State& state);
const std::string& id() const { return m_id; }
private:
typedef std::map<State, Rules*> RulesMap;
std::string m_id;
css::CompoundStyle m_compoundStyle;
RulesMap m_rules;
static css::State m_hoverState;
static css::State m_activeState;
static css::State m_clickedState;
};
} // namespace skin
} // namespace app
#endif

View File

@ -0,0 +1,116 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/ui/skin/style_sheet.h"
#include "app/ui/skin/skin_theme.h"
#include "app/ui/skin/style.h"
#include "base/exception.h"
#include "css/sheet.h"
#include "tinyxml.h"
namespace app {
namespace skin {
css::Rule StyleSheet::m_backgroundColorRule("background-color");
css::Rule StyleSheet::m_backgroundPartRule("background-part");
css::Rule StyleSheet::m_iconAlignRule("icon-align");
css::Rule StyleSheet::m_iconPartRule("icon-part");
css::Rule StyleSheet::m_textAlignRule("text-align");
css::Rule StyleSheet::m_textColorRule("text-color");
css::Rule StyleSheet::m_paddingLeftRule("padding-left");
css::Rule StyleSheet::m_paddingTopRule("padding-top");
css::Rule StyleSheet::m_paddingRightRule("padding-right");
css::Rule StyleSheet::m_paddingBottomRule("padding-bottom");
StyleSheet::StyleSheet()
{
m_sheet = new css::Sheet;
m_sheet->addRule(&m_backgroundColorRule);
m_sheet->addRule(&m_backgroundPartRule);
m_sheet->addRule(&m_iconAlignRule);
m_sheet->addRule(&m_iconPartRule);
m_sheet->addRule(&m_textAlignRule);
m_sheet->addRule(&m_textColorRule);
m_sheet->addRule(&m_paddingLeftRule);
m_sheet->addRule(&m_paddingTopRule);
m_sheet->addRule(&m_paddingRightRule);
m_sheet->addRule(&m_paddingBottomRule);
}
StyleSheet::~StyleSheet()
{
destroyAllStyles();
delete m_sheet;
}
void StyleSheet::destroyAllStyles()
{
for (StyleMap::iterator it = m_styles.begin(), end = m_styles.end();
it != end; ++it)
delete it->second;
}
Style* StyleSheet::getStyle(const std::string& id)
{
Style* style = NULL;
StyleMap::iterator it = m_styles.find(id);
if (it != m_styles.end())
style = it->second;
else {
style = new Style(*m_sheet, id);
m_styles[id] = style;
}
return style;
}
// static
SkinPartPtr StyleSheet::convertPart(const css::Value& value)
{
SkinPartPtr part;
if (value.type() == css::Value::String) {
const std::string& part_id = value.string();
part = get_part_by_id(part_id);
if (part == NULL)
throw base::Exception("Unknown part '%s'\n", part_id.c_str());
}
return part;
}
// static
ui::Color StyleSheet::convertColor(const css::Value& value)
{
ui::Color color;
if (value.type() == css::Value::String) {
const std::string& color_id = value.string();
color = get_color_by_id(color_id);
if (color == ui::ColorNone)
throw base::Exception("Unknown color '%s'\n", color_id.c_str());
}
return color;
}
} // namespace skin
} // namespace app

View File

@ -0,0 +1,88 @@
/* Aseprite
* Copyright (C) 2001-2013 David Capello
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef APP_UI_SKIN_STYLE_SHEET_H_INCLUDED
#define APP_UI_SKIN_STYLE_SHEET_H_INCLUDED
#include "app/ui/skin/skin_part.h"
#include "css/rule.h"
#include "css/state.h"
#include "ui/color.h"
#include <map>
#include <string>
class TiXmlElement;
namespace css {
class Sheet;
class Value;
}
namespace app {
namespace skin {
class Style;
class StyleSheet {
public:
StyleSheet();
~StyleSheet();
static css::Rule& backgroundColorRule() { return m_backgroundColorRule; }
static css::Rule& backgroundPartRule() { return m_backgroundPartRule; }
static css::Rule& iconAlignRule() { return m_iconAlignRule; }
static css::Rule& iconPartRule() { return m_iconPartRule; }
static css::Rule& textAlignRule() { return m_textAlignRule; }
static css::Rule& textColorRule() { return m_textColorRule; }
static css::Rule& paddingLeftRule() { return m_paddingLeftRule; }
static css::Rule& paddingTopRule() { return m_paddingTopRule; }
static css::Rule& paddingRightRule() { return m_paddingRightRule; }
static css::Rule& paddingBottomRule() { return m_paddingBottomRule; }
css::Sheet& sheet() { return *m_sheet; }
Style* getStyle(const std::string& id);
static SkinPartPtr convertPart(const css::Value& value);
static ui::Color convertColor(const css::Value& value);
private:
typedef std::map<std::string, Style*> StyleMap;
void destroyAllStyles();
static css::Rule m_backgroundColorRule;
static css::Rule m_backgroundPartRule;
static css::Rule m_iconAlignRule;
static css::Rule m_iconPartRule;
static css::Rule m_textAlignRule;
static css::Rule m_textColorRule;
static css::Rule m_paddingLeftRule;
static css::Rule m_paddingTopRule;
static css::Rule m_paddingRightRule;
static css::Rule m_paddingBottomRule;
css::Sheet* m_sheet;
StyleMap m_styles;
};
} // namespace skin
} // namespace app
#endif

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,7 @@
#include "app/context_observer.h"
#include "app/document_observer.h"
#include "app/ui/editor/editor_observer.h"
#include "app/ui/skin/style.h"
#include "base/compiler_specific.h"
#include "raster/frame_number.h"
#include "ui/widget.h"
@ -34,6 +35,10 @@ namespace raster {
class Sprite;
}
namespace ui {
class Graphics;
}
namespace app {
using namespace raster;
@ -49,6 +54,7 @@ namespace app {
enum State {
STATE_STANDBY,
STATE_SCROLLING,
STATE_SELECTING_FRAME,
STATE_MOVING_SEPARATOR,
STATE_MOVING_LAYER,
STATE_MOVING_CEL,
@ -74,6 +80,7 @@ namespace app {
protected:
bool onProcessMessage(ui::Message* msg) OVERRIDE;
void onPreferredSize(ui::PreferredSizeEvent& ev) OVERRIDE;
void onPaint(ui::PaintEvent& ev) OVERRIDE;
// DocumentObserver impl.
void onAddLayer(DocumentEvent& ev) OVERRIDE;
@ -95,18 +102,19 @@ namespace app {
private:
void detachDocument();
void setCursor(int x, int y);
void getDrawableLayers(const gfx::Rect& clip, int* first_layer, int* last_layer);
void getDrawableFrames(const gfx::Rect& clip, FrameNumber* first_frame, FrameNumber* last_frame);
void drawHeader(const gfx::Rect& clip);
void drawHeaderFrame(const gfx::Rect& clip, FrameNumber frame);
void drawHeaderPart(const gfx::Rect& clip, int x1, int y1, int x2, int y2,
bool is_hot, bool is_clk,
const char* text, int text_align);
void drawSeparator(const gfx::Rect& clip);
void drawLayer(const gfx::Rect& clip, int layer_index);
void drawLayerPadding();
void drawCel(const gfx::Rect& clip, int layer_index, FrameNumber frame, Cel* cel);
bool drawPart(int part, int layer, FrameNumber frame);
void getDrawableLayers(ui::Graphics* g, int* first_layer, int* last_layer);
void getDrawableFrames(ui::Graphics* g, FrameNumber* first_frame, FrameNumber* last_frame);
void drawPart(ui::Graphics* g, const gfx::Rect& bounds,
const char* text, skin::Style* style,
bool is_active = false, bool is_hover = false, bool is_clicked = false);
void drawHeader(ui::Graphics* g);
void drawHeaderFrame(ui::Graphics* g, FrameNumber frame);
void drawLayer(ui::Graphics* g, int layer_index);
void drawCel(ui::Graphics* g, int layer_index, FrameNumber frame, Cel* cel);
void drawPaddings(ui::Graphics* g);
bool drawPart(ui::Graphics* g, int part, int layer, FrameNumber frame);
gfx::Rect getPartBounds(int part, int layer = 0, FrameNumber frame = FrameNumber(0)) const;
void invalidatePart(int part, int layer, FrameNumber frame);
void regenerateLayers();
void hotThis(int hot_part, int hot_layer, FrameNumber hotFrame);
void centerCel(int layer, FrameNumber frame);
@ -114,14 +122,32 @@ namespace app {
void showCurrentCel();
void cleanClk();
void setScroll(int x, int y, bool use_refresh_region);
int getLayerIndex(const Layer* layer);
int getLayerIndex(const Layer* layer) const;
bool isLayerActive(const Layer* layer) const;
bool isFrameActive(FrameNumber frame) const;
skin::Style* m_timelineStyle;
skin::Style* m_timelineBoxStyle;
skin::Style* m_timelineOpenEyeStyle;
skin::Style* m_timelineClosedEyeStyle;
skin::Style* m_timelineOpenPadlockStyle;
skin::Style* m_timelineClosedPadlockStyle;
skin::Style* m_timelineLayerStyle;
skin::Style* m_timelineEmptyFrameStyle;
skin::Style* m_timelineKeyframeStyle;
skin::Style* m_timelineGearStyle;
skin::Style* m_timelinePaddingStyle;
skin::Style* m_timelinePaddingTrStyle;
skin::Style* m_timelinePaddingBlStyle;
skin::Style* m_timelinePaddingBrStyle;
Context* m_context;
Editor* m_editor;
Document* m_document;
Sprite* m_sprite;
Layer* m_layer;
FrameNumber m_frame;
FrameNumber m_frameBegin;
FrameNumber m_frameEnd;
State m_state;
std::vector<Layer*> m_layers;
int m_scroll_x;

10
src/css/CMakeLists.txt Normal file
View File

@ -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)

20
src/css/LICENSE.txt Normal file
View File

@ -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.

4
src/css/README.md Normal file
View File

@ -0,0 +1,4 @@
# Aseprite CSS Library
*Copyright (C) 2013 David Capello*
> Distributed under [MIT license](LICENSE.txt)

View File

@ -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();
const 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 {
const 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

42
src/css/compound_style.h Normal file
View File

@ -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<States, Query*> QueriesMap;
void deleteQueries();
Sheet* m_sheet;
std::string m_name;
Query m_normal;
mutable QueriesMap m_queries;
};
} // namespace css
#endif

19
src/css/css.h Normal file
View File

@ -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

250
src/css/css_unittest.cpp Normal file
View File

@ -0,0 +1,250 @@
// Aseprite CSS Library
// Copyright (C) 2013 David Capello
//
// This source file is distributed under MIT license,
// please read LICENSE.txt for more information.
#include <gtest/gtest.h>
#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);
Style sub2("sub2", &sub);
Style sub3("sub3", &sub2);
Style sub3FocusHover("sub3:focus:hover", &sub2);
base[bg] = Value(1);
base[fg] = Value(2);
baseHover[fg] = Value(3);
baseFocus[bg] = Value(4);
sub[bg] = Value(5);
subFocus[fg] = Value(6);
sub3[bg] = Value(7);
sub3FocusHover[fg] = Value(8);
Sheet sheet;
sheet.addRule(&bg);
sheet.addRule(&fg);
sheet.addStyle(&base);
sheet.addStyle(&baseHover);
sheet.addStyle(&baseFocus);
sheet.addStyle(&sub);
sheet.addStyle(&subFocus);
sheet.addStyle(&sub2);
sheet.addStyle(&sub3);
sheet.addStyle(&sub3FocusHover);
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]);
CompoundStyle compoundSub2 = sheet.compoundStyle("sub2");
EXPECT_EQ(Value(5), compoundSub2[bg]);
EXPECT_EQ(Value(2), compoundSub2[fg]);
EXPECT_EQ(Value(5), compoundSub2[hover][bg]);
EXPECT_EQ(Value(3), compoundSub2[hover][fg]);
EXPECT_EQ(Value(4), compoundSub2[focus][bg]);
EXPECT_EQ(Value(6), compoundSub2[focus][fg]);
EXPECT_EQ(Value(4), compoundSub2[hover+focus][bg]);
EXPECT_EQ(Value(6), compoundSub2[hover+focus][fg]);
CompoundStyle compoundSub3 = sheet.compoundStyle("sub3");
EXPECT_EQ(Value(7), compoundSub3[bg]);
EXPECT_EQ(Value(2), compoundSub3[fg]);
EXPECT_EQ(Value(7), compoundSub3[hover][bg]);
EXPECT_EQ(Value(3), compoundSub3[hover][fg]);
EXPECT_EQ(Value(4), compoundSub3[focus][bg]);
EXPECT_EQ(Value(6), compoundSub3[focus][fg]);
EXPECT_EQ(Value(4), compoundSub3[hover+focus][bg]);
EXPECT_EQ(Value(6), compoundSub3[hover+focus][fg]);
EXPECT_EQ(Value(8), compoundSub3[focus+hover][fg]);
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

61
src/css/map.h Normal file
View File

@ -0,0 +1,61 @@
// 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 <map>
#include <string>
namespace css {
template<typename T>
class Map {
public:
typedef std::map<std::string, T> 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;
}
bool exists(const std::string& name) const {
return (m_map.find(name) != m_map.end());
}
private:
map m_map;
T m_default;
};
} // namespace css
#endif

29
src/css/query.cpp Normal file
View File

@ -0,0 +1,29 @@
// 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::addFromStyle(const Style* style)
{
for (Style::const_iterator it = style->begin(), end = style->end();
it != end; ++it) {
addRuleValue(it->first, style);
}
}
void Query::addRuleValue(const std::string& ruleName, const Style* style)
{
if (!m_ruleValue.exists(ruleName))
m_ruleValue.add(ruleName, style);
}
} // namespace css

43
src/css/query.h Normal file
View File

@ -0,0 +1,43 @@
// 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 <map>
namespace css {
class Query {
public:
Query() { }
// Adds more rules from the given style only if the query doesn't
// contain those rules already.
void addFromStyle(const Style* style);
const Value& operator[](const Rule& rule) const {
const Style* style = m_ruleValue[rule.name()];
if (style)
return (*style)[rule.name()];
else
return m_none;
}
private:
void addRuleValue(const std::string& ruleName, const Style* style);
Styles m_ruleValue;
Value m_none;
};
} // namespace css
#endif

20
src/css/rule.cpp Normal file
View File

@ -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

32
src/css/rule.h Normal file
View File

@ -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 <map>
#include <string>
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<Rule*> Rules;
} // namespace css
#endif

110
src/css/sheet.cpp Normal file
View File

@ -0,0 +1,110 @@
// 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"
#include <stdio.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);
}
const Style* Sheet::getStyle(const std::string& name)
{
return m_styles[name];
}
Query Sheet::query(const StatefulStyle& compound)
{
const Style* firstStyle = &compound.style();
const Style* style;
Query query;
std::string name;
// We create a string with all states. This is the style with
// highest priority.
std::string states;
for (States::const_iterator
state_it = compound.states().begin(),
state_end = compound.states().end(); state_it != state_end; ++state_it) {
states += StatefulStyle::kSeparator;
states += (*state_it)->name();
}
// Query by priority for the following styles:
// style:state1:state2:...
// ...
// base1:state1:state2:...
// base0:state1:state2:...
for (style=firstStyle; style != NULL; style=style->base()) {
name = style->name();
name += states;
const Style* style2 = m_styles[name];
if (style2)
query.addFromStyle(style2);
}
// Query for:
// style:state2
// style:state1
// ...
// base1:state2
// base1:state1
// base0:state2
// base0:state1
for (States::const_reverse_iterator
state_it = compound.states().rbegin(),
state_end = compound.states().rend(); state_it != state_end; ++state_it) {
for (style=firstStyle; style != NULL; style=style->base()) {
name = style->name();
name += StatefulStyle::kSeparator;
name += (*state_it)->name();
const Style* style2 = m_styles[name];
if (style2)
query.addFromStyle(style2);
}
}
// Query for:
// style
// ...
// base1
// base0
for (style=firstStyle; style != NULL; style=style->base()) {
query.addFromStyle(style);
}
return query;
}
CompoundStyle Sheet::compoundStyle(const std::string& name)
{
return CompoundStyle(this, name);
}
} // namespace css

42
src/css/sheet.h Normal file
View File

@ -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 <map>
#include <string>
namespace css {
class CompoundStyle;
class Query;
class StatefulStyle;
class Sheet {
public:
Sheet();
void addRule(Rule* rule);
void addStyle(Style* style);
const 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

76
src/css/state.h Normal file
View File

@ -0,0 +1,76 @@
// 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 <string>
#include <vector>
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<const State*> List;
typedef List::iterator iterator;
typedef List::const_iterator const_iterator;
typedef List::reverse_iterator reverse_iterator;
typedef List::const_reverse_iterator const_reverse_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(); }
reverse_iterator rbegin() { return m_list.rbegin(); }
reverse_iterator rend() { return m_list.rend(); }
const_reverse_iterator rbegin() const { return m_list.rbegin(); }
const_reverse_iterator rend() const { return m_list.rend(); }
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

73
src/css/stateful_style.h Normal file
View File

@ -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

20
src/css/style.cpp Normal file
View File

@ -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, const Style* base) :
m_name(name),
m_base(base) {
}
} // namespace css

53
src/css/style.h Normal file
View File

@ -0,0 +1,53 @@
// 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 <map>
#include <string>
#include "css/map.h"
#include "css/rule.h"
#include "css/value.h"
namespace css {
class Style {
public:
typedef Values::iterator iterator;
typedef Values::const_iterator const_iterator;
Style() { }
Style(const std::string& name, const Style* base = NULL);
const std::string& name() const { return m_name; }
const 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(); }
const_iterator begin() const { return m_values.begin(); }
const_iterator end() const { return m_values.end(); }
private:
std::string m_name;
const Style* m_base;
Values m_values;
};
typedef Map<const Style*> Styles;
} // namespace css
#endif

98
src/css/value.cpp Normal file
View File

@ -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

53
src/css/value.h Normal file
View File

@ -0,0 +1,53 @@
// 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 <string>
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;
bool operator!=(const Value& other) const {
return !operator==(other);
}
private:
Type m_type;
double m_number;
std::string m_string;
};
typedef Map<Value> Values;
} // namespace css
#endif

View File

@ -145,13 +145,21 @@ gfx::Size Graphics::fitString(const std::string& str, int maxWidth, int align)
gfx::Size Graphics::drawStringAlgorithm(const std::string& str, Color fg, Color bg, const gfx::Rect& rc, int align, bool draw)
{
gfx::Point pt(0, rc.y);
if ((align & (JI_MIDDLE | JI_BOTTOM)) != 0) {
gfx::Size preSize = drawStringAlgorithm(str, ColorNone, ColorNone, rc, 0, false);
if (align & JI_MIDDLE)
pt.y = rc.y + rc.h/2 - preSize.h/2;
else if (align & JI_BOTTOM)
pt.y = rc.y + rc.h - preSize.h;
}
gfx::Size calculatedSize(0, 0);
size_t beg, end, new_word_beg, old_end;
std::string line;
gfx::Point pt;
// Draw line-by-line
pt.y = rc.y;
for (beg=end=0; end != std::string::npos; ) {
pt.x = rc.x;
@ -209,19 +217,19 @@ gfx::Size Graphics::drawStringAlgorithm(const std::string& str, Color fg, Color
ji_font_set_aa_mode(m_currentFont, to_system(bg));
textout_ex(m_bmp, m_currentFont, line.c_str(), m_dx+xout, m_dy+pt.y, to_system(fg), to_system(bg));
jrectexclude(m_bmp,
m_dx+rc.x, m_dy+pt.y, m_dx+rc.x+rc.w-1, m_dy+pt.y+lineSize.h-1,
m_dx+xout, m_dy+pt.y, m_dx+xout+lineSize.w-1, m_dy+pt.y+lineSize.h-1, bg);
if (!is_transparent(bg))
jrectexclude(m_bmp,
m_dx+rc.x, m_dy+pt.y, m_dx+rc.x+rc.w-1, m_dy+pt.y+lineSize.h-1,
m_dx+xout, m_dy+pt.y, m_dx+xout+lineSize.w-1, m_dy+pt.y+lineSize.h-1, bg);
}
pt.y += lineSize.h;
calculatedSize.h += lineSize.h;
beg = end+1;
}
calculatedSize.h += pt.y;
// Fill bottom area
if (draw) {
if (draw && !is_transparent(bg)) {
if (pt.y < rc.y+rc.h)
fillRect(bg, gfx::Rect(rc.x, pt.y, rc.w, rc.y+rc.h-pt.y));
}