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:
David Capello 2017-02-13 18:34:23 -03:00
parent 75020d9405
commit bb4faca1d1
28 changed files with 752 additions and 293 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -45,6 +45,7 @@ add_library(ui-lib
size_hint_event.cpp
slider.cpp
splitter.cpp
style.cpp
system.cpp
textbox.cpp
theme.cpp

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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