mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-21 16:20:53 +00:00
New Style class in "ui" layer to paint widgets (only button at this moment)
This new ui::Style should finally replace the old app::skin::SkinStyle class. At this moment both implementations are working to avoid an huge refactor in just one commit. - Added new ui::Style property in ui::Widget. - Removed old code to set the button "bevel" (removed app::setup_bevels() functions). - Removed setup_look() function and Left/RightButtonLooks. - Removed check_button_new() function. - Removed ui::Theme::paintButton/ComboBoxButton() functions.
This commit is contained in:
parent
75020d9405
commit
bb4faca1d1
@ -898,4 +898,91 @@
|
||||
|
||||
</stylesheet>
|
||||
|
||||
<styles>
|
||||
|
||||
<style id="button">
|
||||
<background part="button_normal" />
|
||||
<background part="button_hot" state="mouse" />
|
||||
<background part="button_focused" state="focus" />
|
||||
<background part="button_selected" state="selected" />
|
||||
<text color="button_normal_text" />
|
||||
<text color="button_hot_text" state="mouse" />
|
||||
<text color="button_selected_text" state="selected" />
|
||||
</style>
|
||||
|
||||
<style id="mini_button">
|
||||
<background part="toolbutton_last" />
|
||||
<background part="toolbutton_hot" state="mouse" />
|
||||
<background part="toolbutton_hot" state="focus" />
|
||||
<background part="toolbutton_pushed" state="selected" />
|
||||
<text color="button_normal_text" />
|
||||
<text color="button_hot_text" state="mouse" />
|
||||
<text color="button_selected_text" state="selected" />
|
||||
</style>
|
||||
|
||||
<style id="combobox_button" extends="mini_button">
|
||||
<icon part="combobox_arrow_down" />
|
||||
<icon part="combobox_arrow_down_selected" state="selected" />
|
||||
<icon part="combobox_arrow_down_disabled" state="disabled" />
|
||||
</style>
|
||||
|
||||
<style id="drop_down_button" extends="button">
|
||||
<background part="drop_down_button_left_normal" />
|
||||
<background part="drop_down_button_left_selected" state="selected" />
|
||||
<background part="drop_down_button_left_hot" state="mouse" />
|
||||
<background part="drop_down_button_left_focused" state="focus" />
|
||||
</style>
|
||||
|
||||
<style id="drop_down_expand_button" extends="button">
|
||||
<background part="drop_down_button_right_normal" />
|
||||
<background part="drop_down_button_right_selected" state="selected" />
|
||||
<background part="drop_down_button_right_hot" state="mouse" />
|
||||
<background part="drop_down_button_right_focused" state="focus" />
|
||||
<icon part="combobox_arrow_down" />
|
||||
<icon part="combobox_arrow_down_selected" state="selected" />
|
||||
<icon part="combobox_arrow_down_disabled" state="disabled" />
|
||||
</style>
|
||||
|
||||
<style id="go_back_button" extends="mini_button">
|
||||
<icon part="combobox_arrow_left" />
|
||||
<icon part="combobox_arrow_left_selected" state="selected" />
|
||||
<icon part="combobox_arrow_left_disabled" state="disabled" />
|
||||
</style>
|
||||
|
||||
<style id="go_forward_button" extends="mini_button">
|
||||
<icon part="combobox_arrow_right" />
|
||||
<icon part="combobox_arrow_right_selected" state="selected" />
|
||||
<icon part="combobox_arrow_right_disabled" state="disabled" />
|
||||
</style>
|
||||
|
||||
<style id="go_up_button" extends="mini_button">
|
||||
<icon part="combobox_arrow_up" />
|
||||
<icon part="combobox_arrow_up_selected" state="selected" />
|
||||
<icon part="combobox_arrow_up_disabled" state="disabled" />
|
||||
</style>
|
||||
|
||||
<style id="new_folder_button" extends="mini_button">
|
||||
<icon part="newfolder" />
|
||||
<icon part="newfolder_selected" state="selected" />
|
||||
</style>
|
||||
|
||||
<style id="color_wheel_options" border="1">
|
||||
<background color="editor_face" />
|
||||
<background color="check_hot_face" state="mouse" />
|
||||
<background color="check_hot_face" state="selected" />
|
||||
<icon part="pal_options" />
|
||||
</style>
|
||||
|
||||
<style id="recover_sprites_button" extends="button"
|
||||
border="0" padding="8">
|
||||
</style>
|
||||
|
||||
<style id="new_frame_button" extends="mini_button">
|
||||
</style>
|
||||
|
||||
<style id="color_button" extends="mini_button" border="5">
|
||||
</style>
|
||||
|
||||
</styles>
|
||||
|
||||
</theme>
|
||||
|
@ -1,23 +1,23 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2001-2016 by David Capello -->
|
||||
<!-- Copyright (C) 2001-2017 by David Capello -->
|
||||
<gui>
|
||||
<window id="file_selector" text="">
|
||||
<vbox id="main">
|
||||
<box horizontal="true">
|
||||
<box horizontal="true" noborders="true">
|
||||
<button text="" id="go_back_button" bevel="2 0 2 0" tooltip="@file_selector.go_back_button_tooltip" />
|
||||
<button text="" id="go_forward_button" bevel="0 2 0 2" tooltip="@file_selector.go_forward_button_tooltip" />
|
||||
<button text="" id="go_back_button" style="go_back_button" tooltip="@.go_back_button_tooltip" />
|
||||
<button text="" id="go_forward_button" style="go_forward_button" tooltip="@.go_forward_button_tooltip" />
|
||||
</box>
|
||||
<button text="" id="go_up_button" tooltip="@file_selector.go_up_button_tooltip" />
|
||||
<button text="" id="new_folder_button" tooltip="@file_selector.new_folder_button_tooltip" />
|
||||
<button text="" id="go_up_button" style="go_up_button" tooltip="@.go_up_button_tooltip" />
|
||||
<button text="" id="new_folder_button" style="new_folder_button" tooltip="@.new_folder_button_tooltip" />
|
||||
<combobox id="location" expansive="true" />
|
||||
</box>
|
||||
<vbox id="file_view_placeholder" expansive="true" />
|
||||
<grid columns="2">
|
||||
<label text="@file_selector.file_name" />
|
||||
<label text="@.file_name" />
|
||||
<box id="file_name_placeholder" cell_align="horizontal" />
|
||||
|
||||
<label text="@file_selector.file_type" />
|
||||
<label text="@.file_type" />
|
||||
<hbox cell_align="horizontal">
|
||||
<combobox id="file_type" minwidth="70" />
|
||||
<vbox>
|
||||
|
@ -1,10 +1,10 @@
|
||||
<!-- Aseprite -->
|
||||
<!-- Copyright (C) 2001-2016 by David Capello -->
|
||||
<!-- Copyright (C) 2001-2017 by David Capello -->
|
||||
<gui>
|
||||
<vbox noborders="true" id="home_view" border="4" childspacing="2" expansive="true">
|
||||
<hbox noborders="true" id="recover_sprites_placeholder">
|
||||
<boxfiller />
|
||||
<button id="recover_sprites" text="@.recover" border="8" />
|
||||
<button id="recover_sprites" text="@.recover" style="recover_sprites_button" />
|
||||
<boxfiller />
|
||||
</hbox>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -286,41 +286,16 @@ Widget* setup_mini_font(Widget* widget)
|
||||
}
|
||||
|
||||
Widget* setup_mini_look(Widget* widget)
|
||||
{
|
||||
return setup_look(widget, MiniLook);
|
||||
}
|
||||
|
||||
Widget* setup_look(Widget* widget, LookType lookType)
|
||||
{
|
||||
SkinPropertyPtr skinProp = get_skin_property(widget);
|
||||
skinProp->setLook(lookType);
|
||||
skinProp->setLook(MiniLook);
|
||||
return widget;
|
||||
}
|
||||
|
||||
void setup_bevels(Widget* widget, int b1, int b2, int b3, int b4)
|
||||
{
|
||||
SkinPropertyPtr skinProp = get_skin_property(widget);
|
||||
skinProp->setUpperLeft(b1);
|
||||
skinProp->setUpperRight(b2);
|
||||
skinProp->setLowerLeft(b3);
|
||||
skinProp->setLowerRight(b4);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Button style (convert radio or check buttons and draw it like
|
||||
// normal buttons)
|
||||
|
||||
CheckBox* check_button_new(const char *text, int b1, int b2, int b3, int b4)
|
||||
{
|
||||
CheckBox* widget = new CheckBox(text, kButtonWidget);
|
||||
|
||||
widget->setAlign(CENTER | MIDDLE);
|
||||
|
||||
setup_mini_look(widget);
|
||||
setup_bevels(widget, b1, b2, b3, b4);
|
||||
return widget;
|
||||
}
|
||||
|
||||
void defer_invalid_rect(const gfx::Rect& rc)
|
||||
{
|
||||
if (!defered_invalid_timer)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -41,10 +41,6 @@ namespace app {
|
||||
|
||||
ui::Widget* setup_mini_font(ui::Widget* widget);
|
||||
ui::Widget* setup_mini_look(ui::Widget* widget);
|
||||
ui::Widget* setup_look(ui::Widget* widget, skin::LookType lookType);
|
||||
void setup_bevels(ui::Widget* widget, int b1, int b2, int b3, int b4);
|
||||
|
||||
ui::CheckBox* check_button_new(const char* text, int b1, int b2, int b3, int b4);
|
||||
|
||||
// This function can be used to reinvalidate a specific rectangle if
|
||||
// we weren't able to validate it on a onPaint() event. E.g. Because
|
||||
|
@ -55,6 +55,7 @@ ColorButton::ColorButton(const app::Color& color,
|
||||
this->setFocusStop(true);
|
||||
|
||||
setup_mini_font(this);
|
||||
setStyle(SkinTheme::instance()->newStyles.colorButton());
|
||||
|
||||
UIContext::instance()->add_observer(this);
|
||||
}
|
||||
@ -160,12 +161,15 @@ bool ColorButton::onProcessMessage(Message* msg)
|
||||
|
||||
void ColorButton::onSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
ButtonBase::onSizeHint(ev);
|
||||
|
||||
gfx::Rect box;
|
||||
getTextIconInfo(&box);
|
||||
box.w = 64*guiscale();
|
||||
|
||||
ev.setSizeHint(box.w + border().width(),
|
||||
box.h + border().height());
|
||||
gfx::Size sz = ev.sizeHint();
|
||||
sz.w = std::max(sz.w, box.w);
|
||||
ev.setSizeHint(sz);
|
||||
}
|
||||
|
||||
void ColorButton::onPaint(PaintEvent& ev)
|
||||
|
@ -53,20 +53,14 @@ ColorWheel::ColorWheel()
|
||||
: m_discrete(Preferences::instance().colorBar.discreteWheel())
|
||||
, m_colorModel((ColorModel)Preferences::instance().colorBar.wheelModel())
|
||||
, m_harmony((Harmony)Preferences::instance().colorBar.harmony())
|
||||
, m_options("", kButtonWidget, kButtonWidget, kCheckWidget)
|
||||
, m_options("")
|
||||
, m_harmonyPicked(false)
|
||||
{
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
|
||||
setBorder(gfx::Border(3*ui::guiscale()));
|
||||
|
||||
m_options.Click.connect(base::Bind<void>(&ColorWheel::onOptions, this));
|
||||
m_options.setBgColor(theme->colors.editorFace());
|
||||
m_options.setIconInterface(
|
||||
new ButtonIconImpl(theme->parts.palOptions(),
|
||||
theme->parts.palOptions(),
|
||||
theme->parts.palOptions(),
|
||||
CENTER | MIDDLE));
|
||||
m_options.setStyle(theme->newStyles.colorWheelOptions());
|
||||
|
||||
addChild(&m_options);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -63,7 +63,7 @@ namespace app {
|
||||
bool m_discrete;
|
||||
ColorModel m_colorModel;
|
||||
Harmony m_harmony;
|
||||
ui::ButtonBase m_options;
|
||||
ui::Button m_options;
|
||||
|
||||
// Internal flag used to know if after pickColor() we selected an
|
||||
// harmony.
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -28,11 +28,10 @@ DropDownButton::DropDownButton(const char* text)
|
||||
{
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
|
||||
setup_look(m_button, LeftButtonLook);
|
||||
setup_look(m_dropDown, RightButtonLook);
|
||||
m_button->setStyle(theme->newStyles.dropDownButton());
|
||||
m_dropDown->setStyle(theme->newStyles.dropDownExpandButton());
|
||||
|
||||
m_button->setExpansive(true);
|
||||
m_button->setAlign(LEFT | MIDDLE);
|
||||
m_button->Click.connect(&DropDownButton::onButtonClick, this);
|
||||
m_dropDown->Click.connect(&DropDownButton::onDropDownButtonClick, this);
|
||||
|
||||
@ -40,12 +39,6 @@ DropDownButton::DropDownButton(const char* text)
|
||||
addChild(m_dropDown);
|
||||
|
||||
setChildSpacing(0);
|
||||
|
||||
m_dropDown->setIconInterface
|
||||
(new ButtonIconImpl(theme->parts.comboboxArrowDown(),
|
||||
theme->parts.comboboxArrowDownSelected(),
|
||||
theme->parts.comboboxArrowDownDisabled(),
|
||||
CENTER | MIDDLE));
|
||||
}
|
||||
|
||||
void DropDownButton::onButtonClick(Event& ev)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -313,7 +313,6 @@ FileSelector::FileSelector(FileSelectorType type, FileSelectorDelegate* delegate
|
||||
, m_extras(nullptr)
|
||||
, m_navigationLocked(false)
|
||||
{
|
||||
SkinTheme* theme = SkinTheme::instance();
|
||||
bool withResizeOptions = (delegate && delegate->hasResizeCombobox());
|
||||
|
||||
addChild(new ArrowNavigator(this));
|
||||
@ -327,32 +326,6 @@ FileSelector::FileSelector(FileSelectorType type, FileSelectorDelegate* delegate
|
||||
goUpButton()->setFocusStop(false);
|
||||
newFolderButton()->setFocusStop(false);
|
||||
|
||||
goBackButton()->setIconInterface(
|
||||
new ButtonIconImpl(theme->parts.comboboxArrowLeft(),
|
||||
theme->parts.comboboxArrowLeftSelected(),
|
||||
theme->parts.comboboxArrowLeftDisabled(),
|
||||
CENTER | MIDDLE));
|
||||
goForwardButton()->setIconInterface(
|
||||
new ButtonIconImpl(theme->parts.comboboxArrowRight(),
|
||||
theme->parts.comboboxArrowRightSelected(),
|
||||
theme->parts.comboboxArrowRightDisabled(),
|
||||
CENTER | MIDDLE));
|
||||
goUpButton()->setIconInterface(
|
||||
new ButtonIconImpl(theme->parts.comboboxArrowUp(),
|
||||
theme->parts.comboboxArrowUpSelected(),
|
||||
theme->parts.comboboxArrowUpDisabled(),
|
||||
CENTER | MIDDLE));
|
||||
newFolderButton()->setIconInterface(
|
||||
new ButtonIconImpl(theme->parts.newfolder(),
|
||||
theme->parts.newfolderSelected(),
|
||||
theme->parts.newfolder(),
|
||||
CENTER | MIDDLE));
|
||||
|
||||
setup_mini_look(goBackButton());
|
||||
setup_mini_look(goForwardButton());
|
||||
setup_mini_look(goUpButton());
|
||||
setup_mini_look(newFolderButton());
|
||||
|
||||
m_fileList = new FileList();
|
||||
m_fileList->setId("fileview");
|
||||
m_fileName->setAssociatedFileList(m_fileList);
|
||||
|
@ -50,7 +50,6 @@ public:
|
||||
SkinTheme::instance()->parts.windowButtonSelected(),
|
||||
SkinTheme::instance()->parts.windowCenterIcon())
|
||||
{
|
||||
setup_bevels(this, 0, 0, 0, 0);
|
||||
setDecorative(true);
|
||||
setSelected(true);
|
||||
}
|
||||
@ -97,7 +96,6 @@ public:
|
||||
, m_isPlaying(false) {
|
||||
enableFlags(CTRL_RIGHT_CLICK);
|
||||
setupIcons();
|
||||
setup_bevels(this, 0, 0, 0, 0);
|
||||
setDecorative(true);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -22,10 +22,6 @@ SkinProperty::SkinProperty()
|
||||
{
|
||||
m_look = NormalLook;
|
||||
m_miniFont = false;
|
||||
m_upperLeft = 0;
|
||||
m_upperRight = 0;
|
||||
m_lowerLeft = 0;
|
||||
m_lowerRight = 0;
|
||||
}
|
||||
|
||||
SkinProperty::~SkinProperty()
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
// Copyright (C) 2001-2015, 2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -22,8 +22,6 @@ namespace app {
|
||||
NormalLook,
|
||||
MiniLook,
|
||||
WithoutBordersLook,
|
||||
LeftButtonLook,
|
||||
RightButtonLook,
|
||||
};
|
||||
|
||||
// Property to show widgets with a special look (e.g.: buttons or sliders with mini-borders)
|
||||
@ -40,23 +38,9 @@ namespace app {
|
||||
bool hasMiniFont() const { return m_miniFont; }
|
||||
void setMiniFont() { m_miniFont = true; }
|
||||
|
||||
int getUpperLeft() const { return m_upperLeft; }
|
||||
int getUpperRight() const { return m_upperRight; }
|
||||
int getLowerLeft() const { return m_lowerLeft; }
|
||||
int getLowerRight() const { return m_lowerRight; }
|
||||
|
||||
void setUpperLeft(int value) { m_upperLeft = value; }
|
||||
void setUpperRight(int value) { m_upperRight = value; }
|
||||
void setLowerLeft(int value) { m_lowerLeft = value; }
|
||||
void setLowerRight(int value) { m_lowerRight = value; }
|
||||
|
||||
private:
|
||||
LookType m_look;
|
||||
bool m_miniFont;
|
||||
int m_upperLeft;
|
||||
int m_upperRight;
|
||||
int m_lowerLeft;
|
||||
int m_lowerRight;
|
||||
};
|
||||
|
||||
typedef base::SharedPtr<SkinProperty> SkinPropertyPtr;
|
||||
|
@ -56,7 +56,6 @@ const char* SkinTheme::kThemeCloseButtonId = "theme_close_button";
|
||||
class WindowCloseButton : public Button {
|
||||
public:
|
||||
WindowCloseButton() : Button("") {
|
||||
setup_bevels(this, 0, 0, 0, 0);
|
||||
setDecorative(true);
|
||||
setId(SkinTheme::kThemeCloseButtonId);
|
||||
}
|
||||
@ -422,7 +421,7 @@ void SkinTheme::loadXml(const std::string& skinId)
|
||||
}
|
||||
}
|
||||
|
||||
// Load styles
|
||||
// Load old stylesheet
|
||||
{
|
||||
TiXmlElement* xmlStyle = handle
|
||||
.FirstChild("theme")
|
||||
@ -508,6 +507,140 @@ void SkinTheme::loadXml(const std::string& skinId)
|
||||
}
|
||||
}
|
||||
|
||||
// Load new styles
|
||||
{
|
||||
TiXmlElement* xmlStyle = handle
|
||||
.FirstChild("theme")
|
||||
.FirstChild("styles")
|
||||
.FirstChild("style").ToElement();
|
||||
while (xmlStyle) {
|
||||
const char* style_id = xmlStyle->Attribute("id");
|
||||
if (!style_id) {
|
||||
throw base::Exception("<style> without 'id' attribute in '%s'\n",
|
||||
xml_filename.c_str());
|
||||
}
|
||||
|
||||
const char* extends_id = xmlStyle->Attribute("extends");
|
||||
const ui::Style* base = nullptr;
|
||||
if (extends_id)
|
||||
base = m_styles[extends_id];
|
||||
|
||||
ui::Style* style = m_styles[style_id];
|
||||
if (!style) {
|
||||
m_styles[style_id] = style = new ui::Style(base);
|
||||
style->setId(style_id);
|
||||
}
|
||||
else {
|
||||
*style = ui::Style(base);
|
||||
}
|
||||
|
||||
// Border
|
||||
{
|
||||
const char* m = xmlStyle->Attribute("border");
|
||||
const char* l = xmlStyle->Attribute("border-left");
|
||||
const char* t = xmlStyle->Attribute("border-top");
|
||||
const char* r = xmlStyle->Attribute("border-right");
|
||||
const char* b = xmlStyle->Attribute("border-bottom");
|
||||
gfx::Border border(-1, -1, -1, -1);
|
||||
if (m || l) border.left(std::strtol(l ? l: m, nullptr, 10));
|
||||
if (m || t) border.top(std::strtol(t ? t: m, nullptr, 10));
|
||||
if (m || r) border.right(std::strtol(r ? r: m, nullptr, 10));
|
||||
if (m || b) border.bottom(std::strtol(b ? b: m, nullptr, 10));
|
||||
style->setBorder(border*guiscale());
|
||||
}
|
||||
|
||||
// Padding
|
||||
{
|
||||
const char* m = xmlStyle->Attribute("padding");
|
||||
const char* l = xmlStyle->Attribute("padding-left");
|
||||
const char* t = xmlStyle->Attribute("padding-top");
|
||||
const char* r = xmlStyle->Attribute("padding-right");
|
||||
const char* b = xmlStyle->Attribute("padding-bottom");
|
||||
gfx::Border padding(-1, -1, -1, -1);
|
||||
if (m || l) padding.left(std::strtol(l ? l: m, nullptr, 10));
|
||||
if (m || t) padding.top(std::strtol(t ? t: m, nullptr, 10));
|
||||
if (m || r) padding.right(std::strtol(r ? r: m, nullptr, 10));
|
||||
if (m || b) padding.bottom(std::strtol(b ? b: m, nullptr, 10));
|
||||
style->setPadding(padding*guiscale());
|
||||
}
|
||||
|
||||
TiXmlElement* xmlLayer = xmlStyle->FirstChildElement();
|
||||
while (xmlLayer) {
|
||||
const std::string layerName = xmlLayer->Value();
|
||||
|
||||
LOG(VERBOSE) << "SKIN: Layer " << layerName
|
||||
<< " for " << style_id << "\n";
|
||||
|
||||
ui::Style::Layer layer;
|
||||
|
||||
// Layer type
|
||||
if (layerName == "background") {
|
||||
layer.setType(ui::Style::Layer::Type::kBackground);
|
||||
}
|
||||
else if (layerName == "border") {
|
||||
layer.setType(ui::Style::Layer::Type::kBorder);
|
||||
}
|
||||
else if (layerName == "icon") {
|
||||
layer.setType(ui::Style::Layer::Type::kIcon);
|
||||
}
|
||||
else if (layerName == "text") {
|
||||
layer.setType(ui::Style::Layer::Type::kText);
|
||||
}
|
||||
else if (layerName == "newlayer") {
|
||||
layer.setType(ui::Style::Layer::Type::kNewLayer);
|
||||
}
|
||||
|
||||
// Parse state condition
|
||||
const char* stateValue = xmlLayer->Attribute("state");
|
||||
if (stateValue) {
|
||||
std::string state(stateValue);
|
||||
int flags = 0;
|
||||
if (state.find("disabled") != std::string::npos) flags |= ui::Style::Layer::kDisabled;
|
||||
if (state.find("selected") != std::string::npos) flags |= ui::Style::Layer::kSelected;
|
||||
if (state.find("focus") != std::string::npos) flags |= ui::Style::Layer::kFocus;
|
||||
if (state.find("mouse") != std::string::npos) flags |= ui::Style::Layer::kMouse;
|
||||
layer.setFlags(flags);
|
||||
}
|
||||
|
||||
// Color
|
||||
const char* colorId = xmlLayer->Attribute("color");
|
||||
if (colorId) {
|
||||
layer.setColor(getColorById(colorId));
|
||||
}
|
||||
|
||||
// Sprite sheet
|
||||
const char* partId = xmlLayer->Attribute("part");
|
||||
if (partId) {
|
||||
auto it = m_parts_by_id.find(partId);
|
||||
if (it != m_parts_by_id.end()) {
|
||||
SkinPartPtr part = it->second;
|
||||
if (part) {
|
||||
if (layer.type() == ui::Style::Layer::Type::kIcon)
|
||||
layer.setIcon(part->bitmap(0));
|
||||
else {
|
||||
layer.setSpriteSheet(m_sheet);
|
||||
layer.setSpriteBounds(part->spriteBounds());
|
||||
layer.setSlicesBounds(part->slicesBounds());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw base::Exception("Part <%s part='%s' ...> was not found in '%s'\n",
|
||||
layerName.c_str(), partId,
|
||||
xml_filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (layer.type() != ui::Style::Layer::Type::kNone)
|
||||
style->addLayer(layer);
|
||||
|
||||
xmlLayer = xmlLayer->NextSiblingElement();
|
||||
}
|
||||
|
||||
xmlStyle = xmlStyle->NextSiblingElement();
|
||||
}
|
||||
}
|
||||
|
||||
ThemeFile<SkinTheme>::updateInternals();
|
||||
}
|
||||
|
||||
@ -570,12 +703,7 @@ void SkinTheme::initWidget(Widget* widget)
|
||||
break;
|
||||
|
||||
case kButtonWidget:
|
||||
BORDER4(
|
||||
parts.buttonNormal()->bitmapW()->width(),
|
||||
parts.buttonNormal()->bitmapN()->height(),
|
||||
parts.buttonNormal()->bitmapE()->width(),
|
||||
parts.buttonNormal()->bitmapS()->height());
|
||||
widget->setChildSpacing(0);
|
||||
widget->setStyle(newStyles.button());
|
||||
break;
|
||||
|
||||
case kCheckWidget:
|
||||
@ -616,25 +744,12 @@ void SkinTheme::initWidget(Widget* widget)
|
||||
BORDER(1 * scale);
|
||||
break;
|
||||
|
||||
case kComboBoxWidget:
|
||||
{
|
||||
ComboBox* combobox = dynamic_cast<ComboBox*>(widget);
|
||||
ASSERT(combobox != NULL);
|
||||
|
||||
Button* button = combobox->getButtonWidget();
|
||||
|
||||
button->setBorder(gfx::Border(0));
|
||||
button->setChildSpacing(0);
|
||||
button->setMinSize(gfx::Size(15 * guiscale(),
|
||||
16 * guiscale()));
|
||||
|
||||
static_cast<ButtonBase*>(button)->setIconInterface
|
||||
(new ButtonIconImpl(parts.comboboxArrowDown(),
|
||||
parts.comboboxArrowDownSelected(),
|
||||
parts.comboboxArrowDownDisabled(),
|
||||
CENTER | MIDDLE));
|
||||
}
|
||||
case kComboBoxWidget: {
|
||||
ComboBox* combobox = static_cast<ComboBox*>(widget);
|
||||
Button* button = combobox->getButtonWidget();
|
||||
button->setStyle(newStyles.comboboxButton());
|
||||
break;
|
||||
}
|
||||
|
||||
case kMenuWidget:
|
||||
case kMenuBarWidget:
|
||||
@ -800,79 +915,6 @@ void SkinTheme::paintBox(PaintEvent& ev)
|
||||
}
|
||||
}
|
||||
|
||||
void SkinTheme::paintButton(PaintEvent& ev)
|
||||
{
|
||||
Graphics* g = ev.graphics();
|
||||
ButtonBase* widget = static_cast<ButtonBase*>(ev.getSource());
|
||||
IButtonIcon* iconInterface = widget->iconInterface();
|
||||
gfx::Rect box, text, icon;
|
||||
gfx::Color fg;
|
||||
SkinPartPtr part_nw;
|
||||
|
||||
widget->getTextIconInfo(&box, &text, &icon,
|
||||
iconInterface ? iconInterface->iconAlign(): 0,
|
||||
iconInterface ? iconInterface->size().w: 0,
|
||||
iconInterface ? iconInterface->size().h: 0);
|
||||
|
||||
// Tool buttons are smaller
|
||||
LookType look = NormalLook;
|
||||
SkinPropertyPtr skinPropery = widget->getProperty(SkinProperty::Name);
|
||||
if (skinPropery)
|
||||
look = skinPropery->getLook();
|
||||
|
||||
// Selected
|
||||
if (widget->isSelected()) {
|
||||
fg = colors.buttonSelectedText();
|
||||
part_nw = (look == MiniLook ? parts.toolbuttonNormal():
|
||||
look == LeftButtonLook ? parts.dropDownButtonLeftSelected():
|
||||
look == RightButtonLook ? parts.dropDownButtonRightSelected():
|
||||
parts.buttonSelected());
|
||||
}
|
||||
// With mouse
|
||||
else if (widget->isEnabled() && widget->hasMouseOver()) {
|
||||
fg = colors.buttonHotText();
|
||||
part_nw = (look == MiniLook ? parts.toolbuttonHot():
|
||||
look == LeftButtonLook ? parts.dropDownButtonLeftHot():
|
||||
look == RightButtonLook ? parts.dropDownButtonRightHot():
|
||||
parts.buttonHot());
|
||||
}
|
||||
// Without mouse
|
||||
else {
|
||||
fg = colors.buttonNormalText();
|
||||
|
||||
if (widget->hasFocus())
|
||||
part_nw = (look == MiniLook ? parts.toolbuttonHot():
|
||||
look == LeftButtonLook ? parts.dropDownButtonLeftFocused():
|
||||
look == RightButtonLook ? parts.dropDownButtonRightFocused():
|
||||
parts.buttonFocused());
|
||||
else
|
||||
part_nw = (look == MiniLook ? parts.toolbuttonNormal():
|
||||
look == LeftButtonLook ? parts.dropDownButtonLeftNormal():
|
||||
look == RightButtonLook ? parts.dropDownButtonRightNormal():
|
||||
parts.buttonNormal());
|
||||
}
|
||||
|
||||
// external background
|
||||
g->fillRect(BGCOLOR, g->getClipBounds());
|
||||
|
||||
// draw borders
|
||||
if (part_nw)
|
||||
drawRect(g, widget->clientBounds(), part_nw.get());
|
||||
|
||||
// text
|
||||
drawText(g, NULL, fg, ColorNone, widget,
|
||||
widget->clientChildrenBounds(), get_button_selected_offset());
|
||||
|
||||
// Paint the icon
|
||||
if (iconInterface) {
|
||||
if (widget->isSelected())
|
||||
icon.offset(get_button_selected_offset(),
|
||||
get_button_selected_offset());
|
||||
|
||||
paintIcon(widget, ev.graphics(), iconInterface, icon.x, icon.y);
|
||||
}
|
||||
}
|
||||
|
||||
void SkinTheme::paintCheckBox(PaintEvent& ev)
|
||||
{
|
||||
Graphics* g = ev.graphics();
|
||||
@ -1516,43 +1558,6 @@ void SkinTheme::paintComboBoxEntry(ui::PaintEvent& ev)
|
||||
drawEntryText(g, widget);
|
||||
}
|
||||
|
||||
void SkinTheme::paintComboBoxButton(PaintEvent& ev)
|
||||
{
|
||||
Button* widget = static_cast<Button*>(ev.getSource());
|
||||
Graphics* g = ev.graphics();
|
||||
IButtonIcon* iconInterface = widget->iconInterface();
|
||||
SkinPartPtr part_nw;
|
||||
|
||||
if (widget->isSelected()) {
|
||||
part_nw = parts.toolbuttonPushed();
|
||||
}
|
||||
// With mouse
|
||||
else if (widget->isEnabled() && widget->hasMouseOver()) {
|
||||
part_nw = parts.toolbuttonHot();
|
||||
}
|
||||
// Without mouse
|
||||
else {
|
||||
part_nw = parts.toolbuttonLast();
|
||||
}
|
||||
|
||||
Rect rc = widget->clientBounds();
|
||||
|
||||
// external background
|
||||
g->fillRect(BGCOLOR, rc);
|
||||
|
||||
// draw borders
|
||||
drawRect(g, rc, part_nw.get());
|
||||
|
||||
// Paint the icon
|
||||
if (iconInterface) {
|
||||
// Icon
|
||||
int x = rc.x + rc.w/2 - iconInterface->size().w/2;
|
||||
int y = rc.y + rc.h/2 - iconInterface->size().h/2;
|
||||
|
||||
paintIcon(widget, ev.graphics(), iconInterface, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void SkinTheme::paintTextBox(ui::PaintEvent& ev)
|
||||
{
|
||||
Graphics* g = ev.graphics();
|
||||
|
@ -59,7 +59,6 @@ namespace app {
|
||||
|
||||
void paintDesktop(ui::PaintEvent& ev) override;
|
||||
void paintBox(ui::PaintEvent& ev) override;
|
||||
void paintButton(ui::PaintEvent& ev) override;
|
||||
void paintCheckBox(ui::PaintEvent& ev) override;
|
||||
void paintEntry(ui::PaintEvent& ev) override;
|
||||
void paintGrid(ui::PaintEvent& ev) override;
|
||||
@ -74,7 +73,6 @@ namespace app {
|
||||
void paintSeparator(ui::PaintEvent& ev) override;
|
||||
void paintSlider(ui::PaintEvent& ev) override;
|
||||
void paintComboBoxEntry(ui::PaintEvent& ev) override;
|
||||
void paintComboBoxButton(ui::PaintEvent& ev) override;
|
||||
void paintTextBox(ui::PaintEvent& ev) override;
|
||||
void paintView(ui::PaintEvent& ev) override;
|
||||
void paintViewScrollbar(ui::PaintEvent& ev) override;
|
||||
@ -103,6 +101,10 @@ namespace app {
|
||||
return m_stylesheet.getStyle(id);
|
||||
}
|
||||
|
||||
ui::Style* getNewStyle(const std::string& id) {
|
||||
return m_styles[id];
|
||||
}
|
||||
|
||||
SkinPartPtr getPartById(const std::string& id) {
|
||||
return m_parts_by_id[id];
|
||||
}
|
||||
@ -149,6 +151,7 @@ namespace app {
|
||||
std::map<std::string, int> m_dimensions_by_id;
|
||||
std::vector<ui::Cursor*> m_cursors;
|
||||
StyleSheet m_stylesheet;
|
||||
std::map<std::string, ui::Style*> m_styles;
|
||||
she::Font* m_defaultFont;
|
||||
she::Font* m_miniFont;
|
||||
};
|
||||
|
@ -548,11 +548,11 @@ StatusBar::StatusBar()
|
||||
m_currentFrame = new GotoFrameEntry();
|
||||
m_newFrame = new Button("+");
|
||||
m_newFrame->Click.connect(base::Bind<void>(&StatusBar::newFrame, this));
|
||||
m_newFrame->setStyle(theme->newStyles.newFrameButton());
|
||||
m_zoomEntry = new ZoomEntry;
|
||||
m_zoomEntry->ZoomChange.connect(&StatusBar::onChangeZoom, this);
|
||||
|
||||
setup_mini_look(m_currentFrame);
|
||||
setup_mini_look(m_newFrame);
|
||||
|
||||
box1->setBorder(gfx::Border(2, 1, 2, 2)*guiscale());
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -174,30 +174,10 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
bool top = bool_attr_is_true(elem, "top");
|
||||
bool bottom = bool_attr_is_true(elem, "bottom");
|
||||
bool closewindow = bool_attr_is_true(elem, "closewindow");
|
||||
const char *_bevel = elem->Attribute("bevel");
|
||||
|
||||
widget->setAlign((left ? LEFT: (right ? RIGHT: CENTER)) |
|
||||
(top ? TOP: (bottom ? BOTTOM: MIDDLE)));
|
||||
|
||||
if (_bevel != NULL) {
|
||||
char* bevel = base_strdup(_bevel);
|
||||
int c, b[4];
|
||||
char *tok;
|
||||
|
||||
for (c=0; c<4; ++c)
|
||||
b[c] = 0;
|
||||
|
||||
for (tok=strtok(bevel, " "), c=0;
|
||||
tok;
|
||||
tok=strtok(NULL, " "), ++c) {
|
||||
if (c < 4)
|
||||
b[c] = strtol(tok, NULL, 10);
|
||||
}
|
||||
base_free(bevel);
|
||||
|
||||
setup_bevels(widget, b[0], b[1], b[2], b[3]);
|
||||
}
|
||||
|
||||
if (closewindow) {
|
||||
static_cast<Button*>(widget)
|
||||
->Click.connect(base::Bind<void>(&Widget::closeWindow, widget));
|
||||
@ -594,10 +574,18 @@ void WidgetLoader::fillWidgetWithXmlElementAttributes(const TiXmlElement* elem,
|
||||
|
||||
if (styleid) {
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(root->theme());
|
||||
skin::Style* style = theme->getStyle(styleid);
|
||||
ASSERT(style);
|
||||
SkinStylePropertyPtr prop(new SkinStyleProperty(style));
|
||||
widget->setProperty(prop);
|
||||
|
||||
// New styles
|
||||
ui::Style* style = theme->getNewStyle(styleid);
|
||||
if (style)
|
||||
widget->setStyle(style);
|
||||
else {
|
||||
skin::Style* style = theme->getStyle(styleid);
|
||||
if (style) {
|
||||
SkinStylePropertyPtr prop(new SkinStyleProperty(style));
|
||||
widget->setProperty(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ void gen_theme_class(TiXmlDocument* doc, const std::string& inputFn)
|
||||
std::vector<std::string> colors;
|
||||
std::vector<std::string> parts;
|
||||
std::vector<std::string> styles;
|
||||
std::vector<std::string> newStyles;
|
||||
|
||||
TiXmlHandle handle(doc);
|
||||
TiXmlElement* elem = handle
|
||||
@ -62,6 +63,16 @@ void gen_theme_class(TiXmlDocument* doc, const std::string& inputFn)
|
||||
elem = elem->NextSiblingElement();
|
||||
}
|
||||
|
||||
elem = handle
|
||||
.FirstChild("theme")
|
||||
.FirstChild("styles")
|
||||
.FirstChild("style").ToElement();
|
||||
while (elem) {
|
||||
const char* id = elem->Attribute("id");
|
||||
newStyles.push_back(id);
|
||||
elem = elem->NextSiblingElement();
|
||||
}
|
||||
|
||||
std::cout
|
||||
<< "// Don't modify, generated file from " << inputFn << "\n"
|
||||
<< "\n"
|
||||
@ -158,12 +169,34 @@ void gen_theme_class(TiXmlDocument* doc, const std::string& inputFn)
|
||||
std::cout
|
||||
<< " };\n";
|
||||
|
||||
// New styles sub class
|
||||
std::cout
|
||||
<< "\n"
|
||||
<< " class NewStyles {\n"
|
||||
<< " template<typename> friend class ThemeFile;\n"
|
||||
<< " public:\n";
|
||||
for (auto style : newStyles) {
|
||||
std::string id = convert_xmlid_to_cppid(style, false);
|
||||
std::cout
|
||||
<< " ui::Style* " << id << "() const { return m_" << id << "; }\n";
|
||||
}
|
||||
std::cout
|
||||
<< " private:\n";
|
||||
for (auto style : newStyles) {
|
||||
std::string id = convert_xmlid_to_cppid(style, false);
|
||||
std::cout
|
||||
<< " ui::Style* m_" << id << ";\n";
|
||||
}
|
||||
std::cout
|
||||
<< " };\n";
|
||||
|
||||
std::cout
|
||||
<< "\n"
|
||||
<< " Dimensions dimensions;\n"
|
||||
<< " Colors colors;\n"
|
||||
<< " Parts parts;\n"
|
||||
<< " Styles styles;\n"
|
||||
<< " NewStyles newStyles;\n"
|
||||
<< "\n"
|
||||
<< " protected:\n"
|
||||
<< " void updateInternals() {\n";
|
||||
@ -187,6 +220,11 @@ void gen_theme_class(TiXmlDocument* doc, const std::string& inputFn)
|
||||
std::cout << " byId(styles.m_" << id
|
||||
<< ", \"" << style << "\");\n";
|
||||
}
|
||||
for (auto newStyle : newStyles) {
|
||||
std::string id = convert_xmlid_to_cppid(newStyle, false);
|
||||
std::cout << " byId(newStyles.m_" << id
|
||||
<< ", \"" << newStyle << "\");\n";
|
||||
}
|
||||
std::cout
|
||||
<< " }\n"
|
||||
<< "\n"
|
||||
@ -202,6 +240,9 @@ void gen_theme_class(TiXmlDocument* doc, const std::string& inputFn)
|
||||
<< " }\n"
|
||||
<< " void byId(skin::Style*& style, const std::string& id) {\n"
|
||||
<< " style = static_cast<T*>(this)->getStyle(id);\n"
|
||||
<< " }\n"
|
||||
<< " void byId(ui::Style*& style, const std::string& id) {\n"
|
||||
<< " style = static_cast<T*>(this)->getNewStyle(id);\n"
|
||||
<< " }\n";
|
||||
|
||||
std::cout
|
||||
|
@ -45,6 +45,7 @@ add_library(ui-lib
|
||||
size_hint_event.cpp
|
||||
slider.cpp
|
||||
splitter.cpp
|
||||
style.cpp
|
||||
system.cpp
|
||||
textbox.cpp
|
||||
theme.cpp
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -272,6 +272,13 @@ bool ButtonBase::onProcessMessage(Message* msg)
|
||||
|
||||
void ButtonBase::onSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
// If there is a style specified in this widget, use the new generic
|
||||
// widget to calculate the size hint.
|
||||
if (style()) {
|
||||
Widget::onSizeHint(ev);
|
||||
return;
|
||||
}
|
||||
|
||||
gfx::Rect box;
|
||||
gfx::Size iconSize = (m_iconInterface ? m_iconInterface->size(): gfx::Size(0, 0));
|
||||
getTextIconInfo(&box, NULL, NULL,
|
||||
@ -285,8 +292,13 @@ void ButtonBase::onSizeHint(SizeHintEvent& ev)
|
||||
|
||||
void ButtonBase::onPaint(PaintEvent& ev)
|
||||
{
|
||||
// If there is a style specified in this widget, use the new generic
|
||||
// widget painting code.
|
||||
if (style())
|
||||
return Widget::onPaint(ev);
|
||||
|
||||
switch (m_drawType) {
|
||||
case kButtonWidget: theme()->paintButton(ev); break;
|
||||
case kButtonWidget: ASSERT(false); break;
|
||||
case kCheckWidget: theme()->paintCheckBox(ev); break;
|
||||
case kRadioWidget: theme()->paintRadioButton(ev); break;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -21,10 +21,6 @@ public:
|
||||
ComboBoxButton() : Button("") {
|
||||
setFocusStop(false);
|
||||
}
|
||||
|
||||
void onPaint(PaintEvent& ev) override {
|
||||
theme()->paintComboBoxButton(ev);
|
||||
}
|
||||
};
|
||||
|
||||
class ComboBoxEntry : public Entry {
|
||||
|
51
src/ui/style.cpp
Normal file
51
src/ui/style.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "ui/style.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
Style::Style(const Style* base)
|
||||
: m_insertionPoint(0)
|
||||
, m_border(base ? base->border(): gfx::Border(-1, -1, -1, -1))
|
||||
, m_padding(base ? base->padding(): gfx::Border(-1, -1, -1, -1))
|
||||
{
|
||||
if (base)
|
||||
m_layers = base->layers();
|
||||
}
|
||||
|
||||
void Style::addLayer(const Layer& layer)
|
||||
{
|
||||
int i, j = int(m_layers.size());
|
||||
|
||||
for (i=m_insertionPoint; i<int(m_layers.size()); ++i) {
|
||||
if (layer.type() == m_layers[i].type()) {
|
||||
for (j=i+1; j<int(m_layers.size()); ++j) {
|
||||
if (layer.type() != m_layers[j].type())
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < int(m_layers.size())) {
|
||||
if (layer.type() == Style::Layer::Type::kNewLayer)
|
||||
m_insertionPoint = i+1;
|
||||
else
|
||||
m_layers.insert(m_layers.begin()+j, layer);
|
||||
}
|
||||
else {
|
||||
m_layers.push_back(layer);
|
||||
if (layer.type() == Style::Layer::Type::kNewLayer)
|
||||
m_insertionPoint = int(m_layers.size());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ui
|
105
src/ui/style.h
Normal file
105
src/ui/style.h
Normal file
@ -0,0 +1,105 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef UI_STYLE_H_INCLUDED
|
||||
#define UI_STYLE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "gfx/border.h"
|
||||
#include "gfx/color.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "gfx/size.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace she {
|
||||
class Surface;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
|
||||
class Style {
|
||||
public:
|
||||
class Layer {
|
||||
public:
|
||||
enum class Type {
|
||||
kNone,
|
||||
kBackground,
|
||||
kBorder,
|
||||
kIcon,
|
||||
kText,
|
||||
kNewLayer,
|
||||
};
|
||||
|
||||
// Flags (in which state the widget must be to show this layer)
|
||||
enum {
|
||||
kMouse = 1,
|
||||
kFocus = 2,
|
||||
kSelected = 4,
|
||||
kDisabled = 8,
|
||||
};
|
||||
|
||||
Layer()
|
||||
: m_type(Type::kNone)
|
||||
, m_flags(0)
|
||||
, m_color(gfx::ColorNone)
|
||||
, m_icon(nullptr)
|
||||
, m_spriteSheet(nullptr) {
|
||||
}
|
||||
|
||||
Type type() const { return m_type; }
|
||||
int flags() const { return m_flags; }
|
||||
|
||||
gfx::Color color() const { return m_color; }
|
||||
she::Surface* icon() const { return m_icon; }
|
||||
she::Surface* spriteSheet() const { return m_spriteSheet; }
|
||||
const gfx::Rect& spriteBounds() const { return m_spriteBounds; }
|
||||
const gfx::Rect& slicesBounds() const { return m_slicesBounds; }
|
||||
|
||||
void setType(const Type type) { m_type = type; }
|
||||
void setFlags(const int flags) { m_flags = flags; }
|
||||
void setColor(gfx::Color color) { m_color = color; }
|
||||
void setIcon(she::Surface* icon) { m_icon = icon; }
|
||||
void setSpriteSheet(she::Surface* spriteSheet) { m_spriteSheet = spriteSheet; }
|
||||
void setSpriteBounds(const gfx::Rect& bounds) { m_spriteBounds = bounds; }
|
||||
void setSlicesBounds(const gfx::Rect& bounds) { m_slicesBounds = bounds; }
|
||||
|
||||
private:
|
||||
Type m_type;
|
||||
int m_flags;
|
||||
gfx::Color m_color;
|
||||
she::Surface* m_icon;
|
||||
she::Surface* m_spriteSheet;
|
||||
gfx::Rect m_spriteBounds;
|
||||
gfx::Rect m_slicesBounds;
|
||||
};
|
||||
|
||||
typedef std::vector<Layer> Layers;
|
||||
|
||||
Style(const Style* base);
|
||||
|
||||
const std::string& id() const { return m_id; }
|
||||
const gfx::Border& border() const { return m_border; }
|
||||
const gfx::Border& padding() const { return m_padding; }
|
||||
const Layers& layers() const { return m_layers; }
|
||||
|
||||
void setId(const std::string& id) { m_id = id; }
|
||||
void setBorder(const gfx::Border& value) { m_border = value; }
|
||||
void setPadding(const gfx::Border& value) { m_padding = value; }
|
||||
void addLayer(const Layer& layer);
|
||||
|
||||
private:
|
||||
std::string m_id; // Just for debugging purposes
|
||||
Layers m_layers;
|
||||
int m_insertionPoint;
|
||||
gfx::Border m_border;
|
||||
gfx::Border m_padding;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif
|
226
src/ui/theme.cpp
226
src/ui/theme.cpp
@ -8,6 +8,8 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "ui/theme.h"
|
||||
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/size.h"
|
||||
#include "she/font.h"
|
||||
@ -15,11 +17,14 @@
|
||||
#include "she/system.h"
|
||||
#include "ui/intern.h"
|
||||
#include "ui/manager.h"
|
||||
#include "ui/paint_event.h"
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/style.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/theme.h"
|
||||
#include "ui/view.h"
|
||||
#include "ui/widget.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace ui {
|
||||
@ -55,6 +60,225 @@ void Theme::regenerate()
|
||||
set_mouse_cursor(type);
|
||||
}
|
||||
|
||||
void Theme::paintWidget(PaintEvent& ev)
|
||||
{
|
||||
Widget* widget = static_cast<Widget*>(ev.getSource());
|
||||
const Style* style = widget->style();
|
||||
if (!style) {
|
||||
// Without a ui::Style we don't know how to draw the widget
|
||||
return;
|
||||
}
|
||||
|
||||
Graphics* g = ev.graphics();
|
||||
gfx::Rect rc = widget->clientBounds();
|
||||
int flags =
|
||||
(widget->isEnabled() ? 0: Style::Layer::kDisabled) |
|
||||
(widget->isSelected() ? Style::Layer::kSelected: 0) |
|
||||
(widget->hasMouse() ? Style::Layer::kMouse: 0) |
|
||||
(widget->hasFocus() ? Style::Layer::kFocus: 0);
|
||||
|
||||
// External background
|
||||
g->fillRect(widget->bgColor(), rc);
|
||||
|
||||
const Style::Layer* bestLayer = nullptr;
|
||||
|
||||
for (const auto& layer : style->layers()) {
|
||||
if (bestLayer &&
|
||||
bestLayer->type() != layer.type()) {
|
||||
paintLayer(g, widget, *bestLayer, rc);
|
||||
bestLayer = nullptr;
|
||||
}
|
||||
|
||||
if ((!layer.flags()
|
||||
|| (layer.flags() & flags) == layer.flags())
|
||||
&& (!bestLayer
|
||||
|| (bestLayer && compareLayerFlags(bestLayer->flags(), layer.flags()) <= 0))) {
|
||||
bestLayer = &layer;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestLayer)
|
||||
paintLayer(g, widget, *bestLayer, rc);
|
||||
}
|
||||
|
||||
void Theme::paintLayer(Graphics* g, Widget* widget,
|
||||
const Style::Layer& layer,
|
||||
gfx::Rect& rc)
|
||||
{
|
||||
switch (layer.type()) {
|
||||
|
||||
case Style::Layer::Type::kBackground:
|
||||
if (layer.color() != gfx::ColorNone) {
|
||||
g->fillRect(layer.color(), rc);
|
||||
}
|
||||
|
||||
if (layer.spriteSheet() &&
|
||||
!layer.spriteBounds().isEmpty() &&
|
||||
!layer.slicesBounds().isEmpty()) {
|
||||
Theme::drawSlices(g, layer.spriteSheet(), rc,
|
||||
layer.spriteBounds(),
|
||||
layer.slicesBounds(), true);
|
||||
|
||||
rc.x += layer.slicesBounds().x;
|
||||
rc.y += layer.slicesBounds().y;
|
||||
rc.w -= layer.spriteBounds().w - layer.slicesBounds().w;
|
||||
rc.h -= layer.spriteBounds().h - layer.slicesBounds().h;
|
||||
}
|
||||
break;
|
||||
|
||||
case Style::Layer::Type::kBorder:
|
||||
if (layer.color() != gfx::ColorNone) {
|
||||
g->drawRect(layer.color(), rc);
|
||||
}
|
||||
|
||||
if (layer.spriteSheet() &&
|
||||
!layer.spriteBounds().isEmpty() &&
|
||||
!layer.slicesBounds().isEmpty()) {
|
||||
Theme::drawSlices(g, layer.spriteSheet(), rc,
|
||||
layer.spriteBounds(),
|
||||
layer.slicesBounds(), false);
|
||||
|
||||
rc.x += layer.slicesBounds().x;
|
||||
rc.y += layer.slicesBounds().y;
|
||||
rc.w -= layer.spriteBounds().w - layer.slicesBounds().w;
|
||||
rc.h -= layer.spriteBounds().h - layer.slicesBounds().h;
|
||||
}
|
||||
break;
|
||||
|
||||
case Style::Layer::Type::kText:
|
||||
if (layer.color() != gfx::ColorNone) {
|
||||
gfx::Size textSize = g->measureUIText(widget->text());
|
||||
g->drawUIText(widget->text(),
|
||||
layer.color(),
|
||||
gfx::ColorNone,
|
||||
gfx::Point(rc.x+rc.w/2-textSize.w/2,
|
||||
rc.y+rc.h/2-textSize.h/2), true);
|
||||
}
|
||||
break;
|
||||
|
||||
case Style::Layer::Type::kIcon: {
|
||||
she::Surface* icon = layer.icon();
|
||||
if (icon) {
|
||||
if (layer.color() != gfx::ColorNone) {
|
||||
g->drawColoredRgbaSurface(icon,
|
||||
layer.color(),
|
||||
rc.x+rc.w/2-icon->width()/2,
|
||||
rc.y+rc.h/2-icon->height()/2);
|
||||
}
|
||||
else {
|
||||
g->drawRgbaSurface(icon,
|
||||
rc.x+rc.w/2-icon->width()/2,
|
||||
rc.y+rc.h/2-icon->height()/2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Theme::calcSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
Widget* widget = static_cast<Widget*>(ev.getSource());
|
||||
const Style* style = widget->style();
|
||||
if (!style)
|
||||
return;
|
||||
|
||||
gfx::Border hintBorder(0, 0, 0, 0);
|
||||
gfx::Border hintPadding(0, 0, 0, 0);
|
||||
gfx::Size hintText(0, 0);
|
||||
gfx::Size hintIcon(0, 0);
|
||||
|
||||
int flags =
|
||||
(widget->isEnabled() ? 0: Style::Layer::kDisabled) |
|
||||
(widget->isSelected() ? Style::Layer::kSelected: 0) |
|
||||
(widget->hasMouse() ? Style::Layer::kMouse: 0) |
|
||||
(widget->hasFocus() ? Style::Layer::kFocus: 0);
|
||||
|
||||
const Style::Layer* bestLayer = nullptr;
|
||||
|
||||
for (const auto& layer : style->layers()) {
|
||||
if (bestLayer &&
|
||||
bestLayer->type() != layer.type()) {
|
||||
measureLayer(widget, *bestLayer,
|
||||
hintBorder, hintText, hintIcon);
|
||||
bestLayer = nullptr;
|
||||
}
|
||||
|
||||
if ((!layer.flags()
|
||||
|| (layer.flags() & flags) == layer.flags())
|
||||
&& (!bestLayer
|
||||
|| (bestLayer && compareLayerFlags(bestLayer->flags(), layer.flags()) < 0))) {
|
||||
bestLayer = &layer;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestLayer)
|
||||
measureLayer(widget, *bestLayer,
|
||||
hintBorder, hintText, hintIcon);
|
||||
|
||||
if (style->border().left() >= 0) hintBorder.left(style->border().left());
|
||||
if (style->border().top() >= 0) hintBorder.top(style->border().top());
|
||||
if (style->border().right() >= 0) hintBorder.right(style->border().right());
|
||||
if (style->border().bottom() >= 0) hintBorder.bottom(style->border().bottom());
|
||||
|
||||
if (style->padding().left() >= 0) hintPadding.left(style->padding().left());
|
||||
if (style->padding().top() >= 0) hintPadding.top(style->padding().top());
|
||||
if (style->padding().right() >= 0) hintPadding.right(style->padding().right());
|
||||
if (style->padding().bottom() >= 0) hintPadding.bottom(style->padding().bottom());
|
||||
|
||||
gfx::Size sz(hintBorder.width() + hintPadding.width() + hintIcon.w + hintText.w,
|
||||
hintBorder.height() + hintPadding.height() + std::max(hintIcon.h, hintText.h));
|
||||
ev.setSizeHint(sz);
|
||||
}
|
||||
|
||||
void Theme::measureLayer(Widget* widget,
|
||||
const Style::Layer& layer,
|
||||
gfx::Border& hintBorder,
|
||||
gfx::Size& hintText,
|
||||
gfx::Size& hintIcon)
|
||||
{
|
||||
switch (layer.type()) {
|
||||
|
||||
case Style::Layer::Type::kBackground:
|
||||
case Style::Layer::Type::kBorder:
|
||||
if (layer.spriteSheet() &&
|
||||
!layer.spriteBounds().isEmpty() &&
|
||||
!layer.slicesBounds().isEmpty()) {
|
||||
hintBorder.left(std::max(hintBorder.left(), layer.slicesBounds().x));
|
||||
hintBorder.top(std::max(hintBorder.top(), layer.slicesBounds().y));
|
||||
hintBorder.right(std::max(hintBorder.right(), layer.spriteBounds().w - layer.slicesBounds().x2()));
|
||||
hintBorder.bottom(std::max(hintBorder.bottom(), layer.spriteBounds().h - layer.slicesBounds().y2()));
|
||||
}
|
||||
break;
|
||||
|
||||
case Style::Layer::Type::kText:
|
||||
if (layer.color() != gfx::ColorNone) {
|
||||
gfx::Size textSize(Graphics::measureUITextLength(widget->text(),
|
||||
widget->font()),
|
||||
widget->font()->height());
|
||||
hintText.w = std::max(hintText.w, textSize.w);
|
||||
hintText.h = std::max(hintText.h, textSize.h);
|
||||
}
|
||||
break;
|
||||
|
||||
case Style::Layer::Type::kIcon: {
|
||||
she::Surface* icon = layer.icon();
|
||||
if (icon) {
|
||||
hintIcon.w = std::max(hintIcon.w, icon->width());
|
||||
hintIcon.h = std::max(hintIcon.h, icon->height());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int Theme::compareLayerFlags(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void set_theme(Theme* theme)
|
||||
|
@ -8,10 +8,13 @@
|
||||
#define UI_THEME_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "gfx/border.h"
|
||||
#include "gfx/color.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "gfx/size.h"
|
||||
#include "ui/base.h"
|
||||
#include "ui/cursor_type.h"
|
||||
#include "ui/style.h"
|
||||
|
||||
namespace gfx {
|
||||
class Region;
|
||||
@ -27,6 +30,7 @@ namespace ui {
|
||||
class Cursor;
|
||||
class Graphics;
|
||||
class PaintEvent;
|
||||
class SizeHintEvent;
|
||||
class Widget;
|
||||
|
||||
class Theme {
|
||||
@ -51,7 +55,6 @@ namespace ui {
|
||||
|
||||
virtual void paintDesktop(PaintEvent& ev) = 0;
|
||||
virtual void paintBox(PaintEvent& ev) = 0;
|
||||
virtual void paintButton(PaintEvent& ev) = 0;
|
||||
virtual void paintCheckBox(PaintEvent& ev) = 0;
|
||||
virtual void paintEntry(PaintEvent& ev) = 0;
|
||||
virtual void paintGrid(PaintEvent& ev) = 0;
|
||||
@ -66,7 +69,6 @@ namespace ui {
|
||||
virtual void paintSeparator(PaintEvent& ev) = 0;
|
||||
virtual void paintSlider(PaintEvent& ev) = 0;
|
||||
virtual void paintComboBoxEntry(PaintEvent& ev) = 0;
|
||||
virtual void paintComboBoxButton(PaintEvent& ev) = 0;
|
||||
virtual void paintTextBox(PaintEvent& ev) = 0;
|
||||
virtual void paintView(PaintEvent& ev) = 0;
|
||||
virtual void paintViewScrollbar(PaintEvent& ev) = 0;
|
||||
@ -75,6 +77,10 @@ namespace ui {
|
||||
virtual void paintPopupWindow(PaintEvent& ev) = 0;
|
||||
virtual void paintTooltip(PaintEvent& ev) = 0;
|
||||
|
||||
// Default implementation to draw widgets with new ui::Styles
|
||||
virtual void paintWidget(PaintEvent& ev);
|
||||
virtual void calcSizeHint(SizeHintEvent& ev);
|
||||
|
||||
static void drawSlices(Graphics* g,
|
||||
she::Surface* sheet,
|
||||
const gfx::Rect& rc,
|
||||
@ -89,6 +95,16 @@ namespace ui {
|
||||
virtual void onRegenerate() = 0;
|
||||
|
||||
private:
|
||||
void paintLayer(Graphics* g, Widget* widget,
|
||||
const Style::Layer& layer,
|
||||
gfx::Rect& rc);
|
||||
void measureLayer(Widget* widget,
|
||||
const Style::Layer& layer,
|
||||
gfx::Border& hintBorder,
|
||||
gfx::Size& hintText,
|
||||
gfx::Size& hintIcon);
|
||||
int compareLayerFlags(int a, int b);
|
||||
|
||||
int m_guiscale;
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -54,6 +54,7 @@
|
||||
#include "ui/size_hint_event.h"
|
||||
#include "ui/slider.h"
|
||||
#include "ui/splitter.h"
|
||||
#include "ui/style.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/textbox.h"
|
||||
#include "ui/theme.h"
|
||||
|
@ -64,6 +64,7 @@ Widget::Widget(WidgetType type)
|
||||
: m_type(type)
|
||||
, m_flags(0)
|
||||
, m_theme(get_theme())
|
||||
, m_style(nullptr)
|
||||
, m_font(nullptr)
|
||||
, m_bgColor(gfx::ColorNone)
|
||||
, m_bounds(0, 0, 0, 0)
|
||||
@ -182,6 +183,11 @@ void Widget::setTheme(Theme* theme)
|
||||
m_font = nullptr;
|
||||
}
|
||||
|
||||
void Widget::setStyle(Style* style)
|
||||
{
|
||||
m_style = style;
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// COMMON PROPERTIES
|
||||
// ===============================================================
|
||||
@ -1397,7 +1403,12 @@ void Widget::onInvalidateRegion(const Region& region)
|
||||
|
||||
void Widget::onSizeHint(SizeHintEvent& ev)
|
||||
{
|
||||
ev.setSizeHint(m_minSize);
|
||||
if (m_style) {
|
||||
m_theme->calcSizeHint(ev);
|
||||
}
|
||||
else {
|
||||
ev.setSizeHint(m_minSize);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::onLoadLayout(LoadLayoutEvent& ev)
|
||||
@ -1422,7 +1433,8 @@ void Widget::onResize(ResizeEvent& ev)
|
||||
|
||||
void Widget::onPaint(PaintEvent& ev)
|
||||
{
|
||||
// Do nothing
|
||||
if (m_style)
|
||||
m_theme->paintWidget(ev);
|
||||
}
|
||||
|
||||
void Widget::onBroadcastMouseMessage(WidgetsList& targets)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -40,6 +40,7 @@ namespace ui {
|
||||
class ResizeEvent;
|
||||
class SaveLayoutEvent;
|
||||
class SizeHintEvent;
|
||||
class Style;
|
||||
class Theme;
|
||||
class Window;
|
||||
|
||||
@ -151,7 +152,9 @@ namespace ui {
|
||||
void setBgColor(gfx::Color color);
|
||||
|
||||
Theme* theme() const { return m_theme; }
|
||||
Style* style() const { return m_style; }
|
||||
void setTheme(Theme* theme);
|
||||
void setStyle(Style* style);
|
||||
void initTheme();
|
||||
|
||||
// ===============================================================
|
||||
@ -387,6 +390,7 @@ namespace ui {
|
||||
std::string m_id; // Widget's id
|
||||
int m_flags; // Special boolean properties (see flags in ui/base.h)
|
||||
Theme* m_theme; // Widget's theme
|
||||
Style* m_style;
|
||||
std::string m_text; // Widget text
|
||||
mutable she::Font* m_font; // Cached font returned by the theme
|
||||
gfx::Color m_bgColor; // Background color
|
||||
|
Loading…
x
Reference in New Issue
Block a user