1
0
mirror of https://github.com/aseprite/aseprite.git synced 2025-02-21 12:40:34 +00:00

Add a slider style in theme

We've added some code to handle backward compatibility with themes. In
this way we can still load old themes in the latest version but should
look as in previous versions (this will not be done with previous
properties or parts migrated to styles, so we start from now on).
This commit is contained in:
David Capello 2020-05-01 23:31:10 -03:00
parent 3555bbe29f
commit cc7bdbcec4
7 changed files with 138 additions and 67 deletions
data/extensions/aseprite-theme
src

@ -958,5 +958,11 @@
<icon part="aseprite_face_mouse" state="mouse" /> <icon part="aseprite_face_mouse" state="mouse" />
<icon part="aseprite_face_pushed" state="mouse selected" /> <icon part="aseprite_face_pushed" state="mouse selected" />
</style> </style>
<style id="slider" border-top="4" border-bottom="5">
<background part="slider_empty" />
<background part="slider_empty_focused" state="focus" />
<text color="slider_empty_text" align="center middle" />
<text color="slider_empty_text" align="center middle" state="focus" y="1" />
</style>
</styles> </styles>
</theme> </theme>

@ -57,6 +57,39 @@ using namespace ui;
// TODO For backward compatibility, in future versions we should remove this (extensions are preferred) // TODO For backward compatibility, in future versions we should remove this (extensions are preferred)
const char* SkinTheme::kThemesFolderName = "themes"; const char* SkinTheme::kThemesFolderName = "themes";
// This class offer backward compatibility with old themes, completing
// or changing styles from the default theme to match the default
// theme of previous versions, so third-party themes can look like
// they are running in the old Aseprite without any modification.
struct app::skin::SkinTheme::BackwardCompatibility {
bool hasSliderStyle = false;
void notifyStyleExistence(const char* styleId) {
if (std::strcmp(styleId, "slider") == 0)
hasSliderStyle = true;
}
void createMissingStyles(SkinTheme* theme) {
if (!hasSliderStyle &&
theme->styles.slider()) {
// Old slider style
ui::Style style(nullptr);
os::Font* font = theme->getDefaultFont();
const int h = font->height();
style.setId(theme->styles.slider()->id());
style.setFont(font);
auto part = theme->parts.sliderEmpty();
style.setBorder(
gfx::Border(part->bitmapW()->width()-1*guiscale(),
part->bitmapN()->height()+h/2,
part->bitmapE()->width()-1*guiscale(),
part->bitmapS()->height()-1*guiscale()+h/2));
*theme->styles.slider() = style;
}
}
};
static const char* g_cursor_names[kCursorTypes] = { static const char* g_cursor_names[kCursorTypes] = {
"null", // kNoCursor "null", // kNoCursor
"normal", // kArrowCursor "normal", // kArrowCursor
@ -224,7 +257,8 @@ void SkinTheme::onRegenerateTheme()
// Then we load the selected theme to redefine default theme parts. // Then we load the selected theme to redefine default theme parts.
if (pref.theme.selected.defaultValue() != pref.theme.selected()) { if (pref.theme.selected.defaultValue() != pref.theme.selected()) {
try { try {
loadAll(pref.theme.selected()); BackwardCompatibility backward;
loadAll(pref.theme.selected(), &backward);
} }
catch (const std::exception& e) { catch (const std::exception& e) {
LOG("THEME: Error loading user-theme: %s\n", e.what()); LOG("THEME: Error loading user-theme: %s\n", e.what());
@ -265,7 +299,8 @@ void SkinTheme::loadFontData()
} }
} }
void SkinTheme::loadAll(const std::string& themeId) void SkinTheme::loadAll(const std::string& themeId,
BackwardCompatibility* backward)
{ {
LOG("THEME: Loading theme %s\n", themeId.c_str()); LOG("THEME: Loading theme %s\n", themeId.c_str());
@ -277,7 +312,7 @@ void SkinTheme::loadAll(const std::string& themeId)
throw base::Exception("Theme %s not found", themeId.c_str()); throw base::Exception("Theme %s not found", themeId.c_str());
loadSheet(); loadSheet();
loadXml(); loadXml(backward);
} }
void SkinTheme::loadSheet() void SkinTheme::loadSheet()
@ -315,7 +350,7 @@ void SkinTheme::loadSheet()
} }
} }
void SkinTheme::loadXml() void SkinTheme::loadXml(BackwardCompatibility* backward)
{ {
const int scale = guiscale(); const int scale = guiscale();
@ -515,6 +550,9 @@ void SkinTheme::loadXml()
if (extends_id) if (extends_id)
base = m_styles[extends_id]; base = m_styles[extends_id];
if (backward)
backward->notifyStyleExistence(style_id);
ui::Style* style = m_styles[style_id]; ui::Style* style = m_styles[style_id];
if (!style) { if (!style) {
m_styles[style_id] = style = new ui::Style(base); m_styles[style_id] = style = new ui::Style(base);
@ -699,6 +737,9 @@ void SkinTheme::loadXml()
} }
} }
if (backward)
backward->createMissingStyles(this);
ThemeFile<SkinTheme>::updateInternals(); ThemeFile<SkinTheme>::updateInternals();
} }
@ -851,13 +892,7 @@ void SkinTheme::initWidget(Widget* widget)
break; break;
case kSliderWidget: case kSliderWidget:
BORDER4( widget->setStyle(styles.slider());
parts.sliderEmpty()->bitmapW()->width()-1*scale,
parts.sliderEmpty()->bitmapN()->height(),
parts.sliderEmpty()->bitmapE()->width()-1*scale,
parts.sliderEmpty()->bitmapS()->height()-1*scale);
widget->setChildSpacing(widget->textHeight());
widget->setAlign(CENTER | MIDDLE);
break; break;
case kTextBoxWidget: case kTextBoxWidget:
@ -1100,7 +1135,7 @@ void SkinTheme::drawEntryText(ui::Graphics* g, ui::Entry* widget)
drawText( drawText(
g, widget->getSuffix().c_str(), g, widget->getSuffix().c_str(),
colors.entrySuffix(), ColorNone, colors.entrySuffix(), ColorNone,
widget, sufBounds, 0, 0); widget, sufBounds, widget->align(), 0);
} }
} }
@ -1187,8 +1222,8 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
Rect pos = bounds; Rect pos = bounds;
if (!bar) if (!bar)
pos.offset(widget->childSpacing()/2, 0); pos.offset(widget->childSpacing()/2, 0);
drawText(g, nullptr, fg, ColorNone, widget, pos, 0, drawText(g, nullptr, fg, ColorNone, widget, pos,
widget->mnemonic()); widget->align(), widget->mnemonic());
// For menu-box // For menu-box
if (!bar) { if (!bar) {
@ -1225,7 +1260,7 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
std::string buf = appMenuItem->key()->accels().front().toString(); std::string buf = appMenuItem->key()->accels().front().toString();
widget->setAlign(RIGHT | MIDDLE); widget->setAlign(RIGHT | MIDDLE);
drawText(g, buf.c_str(), fg, ColorNone, widget, pos, 0, 0); drawText(g, buf.c_str(), fg, ColorNone, widget, pos, widget->align(), 0);
widget->setAlign(old_align); widget->setAlign(old_align);
} }
} }
@ -1236,7 +1271,7 @@ void SkinTheme::paintSlider(PaintEvent& ev)
{ {
Graphics* g = ev.graphics(); Graphics* g = ev.graphics();
Slider* widget = static_cast<Slider*>(ev.getSource()); Slider* widget = static_cast<Slider*>(ev.getSource());
Rect bounds = widget->clientBounds(); const Rect bounds = widget->clientBounds();
int min, max, value; int min, max, value;
// Outside borders // Outside borders
@ -1246,14 +1281,15 @@ void SkinTheme::paintSlider(PaintEvent& ev)
widget->getSliderThemeInfo(&min, &max, &value); widget->getSliderThemeInfo(&min, &max, &value);
Rect rc(Rect(bounds).shrink(widget->border())); Rect rc = bounds;
rc.shrink(widget->border());
int x; int x;
if (min != max) if (min != max)
x = rc.x + rc.w * (value-min) / (max-min); x = rc.x + rc.w * (value-min) / (max-min);
else else
x = rc.x; x = rc.x;
rc = widget->clientBounds(); rc = bounds;
// The mini-look is used for sliders with tiny borders. // The mini-look is used for sliders with tiny borders.
bool isMiniLook = false; bool isMiniLook = false;
@ -1328,12 +1364,16 @@ void SkinTheme::paintSlider(PaintEvent& ev)
std::string old_text = widget->text(); std::string old_text = widget->text();
widget->setTextQuiet(widget->convertValueToText(value)); widget->setTextQuiet(widget->convertValueToText(value));
gfx::Rect textrc;
int textAlign;
calcTextInfo(widget, widget->style(), bounds, textrc, textAlign);
{ {
IntersectClip clip(g, Rect(rc.x, rc.y, x-rc.x, rc.h)); IntersectClip clip(g, Rect(rc.x, rc.y, x-rc.x+1, rc.h));
if (clip) { if (clip) {
drawText(g, nullptr, drawText(g, nullptr,
colors.sliderFullText(), ColorNone, colors.sliderFullText(), ColorNone,
widget, rc, 0, widget->mnemonic()); widget, textrc, textAlign, widget->mnemonic());
} }
} }
@ -1342,7 +1382,7 @@ void SkinTheme::paintSlider(PaintEvent& ev)
if (clip) { if (clip) {
drawText(g, nullptr, drawText(g, nullptr,
colors.sliderEmptyText(), colors.sliderEmptyText(),
ColorNone, widget, rc, 0, widget->mnemonic()); ColorNone, widget, textrc, textAlign, widget->mnemonic());
} }
} }
@ -1400,9 +1440,13 @@ gfx::Color SkinTheme::getWidgetBgColor(Widget* widget)
return colors.face(); return colors.face();
} }
void SkinTheme::drawText(Graphics* g, const char *t, gfx::Color fg_color, gfx::Color bg_color, void SkinTheme::drawText(Graphics* g, const char* t,
Widget* widget, const Rect& rc, const gfx::Color fgColor,
int selected_offset, int mnemonic) const gfx::Color bgColor,
const Widget* widget,
const Rect& rc,
const int textAlign,
const int mnemonic)
{ {
if (t || widget->hasText()) { if (t || widget->hasText()) {
Rect textrc; Rect textrc;
@ -1416,33 +1460,28 @@ void SkinTheme::drawText(Graphics* g, const char *t, gfx::Color fg_color, gfx::C
// Horizontally text alignment // Horizontally text alignment
if (widget->align() & RIGHT) if (textAlign & RIGHT)
textrc.x = rc.x + rc.w - textrc.w - 1; textrc.x = rc.x + rc.w - textrc.w - 1;
else if (widget->align() & CENTER) else if (textAlign & CENTER)
textrc.x = rc.center().x - textrc.w/2; textrc.x = rc.center().x - textrc.w/2;
else else
textrc.x = rc.x; textrc.x = rc.x;
// Vertically text alignment // Vertically text alignment
if (widget->align() & BOTTOM) if (textAlign & BOTTOM)
textrc.y = rc.y + rc.h - textrc.h - 1; textrc.y = rc.y + rc.h - textrc.h - 1;
else if (widget->align() & MIDDLE) else if (textAlign & MIDDLE)
textrc.y = rc.center().y - textrc.h/2; textrc.y = rc.center().y - textrc.h/2;
else else
textrc.y = rc.y; textrc.y = rc.y;
if (widget->isSelected()) {
textrc.x += selected_offset;
textrc.y += selected_offset;
}
// Background // Background
if (!is_transparent(bg_color)) { if (!is_transparent(bgColor)) {
if (!widget->isEnabled()) if (!widget->isEnabled())
g->fillRect(bg_color, Rect(textrc).inflate(guiscale(), guiscale())); g->fillRect(bgColor, Rect(textrc).inflate(guiscale(), guiscale()));
else else
g->fillRect(bg_color, textrc); g->fillRect(bgColor, textrc);
} }
// Text // Text
@ -1467,9 +1506,9 @@ void SkinTheme::drawText(Graphics* g, const char *t, gfx::Color fg_color, gfx::C
t, t,
(!widget->isEnabled() ? (!widget->isEnabled() ?
colors.disabled(): colors.disabled():
(gfx::geta(fg_color) > 0 ? fg_color : (gfx::geta(fgColor) > 0 ? fgColor :
colors.text())), colors.text())),
bg_color, textrc.origin(), bgColor, textrc.origin(),
mnemonic); mnemonic);
} }
} }

@ -130,16 +130,24 @@ namespace app {
void onRegenerateTheme() override; void onRegenerateTheme() override;
private: private:
struct BackwardCompatibility;
void loadFontData(); void loadFontData();
void loadAll(const std::string& themeId); void loadAll(const std::string& themeId,
BackwardCompatibility* backward = nullptr);
void loadSheet(); void loadSheet();
void loadXml(); void loadXml(BackwardCompatibility* backward);
os::Surface* sliceSheet(os::Surface* sur, const gfx::Rect& bounds); os::Surface* sliceSheet(os::Surface* sur, const gfx::Rect& bounds);
gfx::Color getWidgetBgColor(ui::Widget* widget); gfx::Color getWidgetBgColor(ui::Widget* widget);
void drawText(ui::Graphics* g, const char *t, gfx::Color fg_color, gfx::Color bg_color, void drawText(ui::Graphics* g,
ui::Widget* widget, const gfx::Rect& rc, const char* t,
int selected_offset, int mnemonic); const gfx::Color fgColor,
const gfx::Color bgColor,
const ui::Widget* widget,
const gfx::Rect& rc,
const int textAlign,
const int mnemonic);
void drawEntryText(ui::Graphics* g, ui::Entry* widget); void drawEntryText(ui::Graphics* g, ui::Entry* widget);
std::string findThemePath(const std::string& themeId) const; std::string findThemePath(const std::string& themeId) const;

@ -215,20 +215,6 @@ not_used:;
return Widget::onProcessMessage(msg); return Widget::onProcessMessage(msg);
} }
void Slider::onSizeHint(SizeHintEvent& ev)
{
int min_w = font()->textLength(convertValueToText(m_min));
int max_w = font()->textLength(convertValueToText(m_max));
int w = std::max(min_w, max_w);
int h = textHeight();
w += border().width();
h += border().height();
ev.setSizeHint(w, h);
}
void Slider::onPaint(PaintEvent& ev) void Slider::onPaint(PaintEvent& ev)
{ {
theme()->paintSlider(ev); theme()->paintSlider(ev);

@ -1,4 +1,5 @@
// Aseprite UI Library // Aseprite UI Library
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
@ -46,7 +47,6 @@ namespace ui {
protected: protected:
// Events // Events
bool onProcessMessage(Message* msg) override; bool onProcessMessage(Message* msg) override;
void onSizeHint(SizeHintEvent& ev) override;
void onPaint(PaintEvent& ev) override; void onPaint(PaintEvent& ev) override;
// New events // New events

@ -490,15 +490,34 @@ gfx::Size Theme::calcSizeHint(const Widget* widget,
{ {
gfx::Size sizeHint; gfx::Size sizeHint;
gfx::Border borderHint; gfx::Border borderHint;
calcWidgetMetrics(widget, style, sizeHint, borderHint); gfx::Rect textHint;
int textAlign;
calcWidgetMetrics(widget, style, sizeHint, borderHint,
textHint, textAlign);
return sizeHint; return sizeHint;
} }
void Theme::calcTextInfo(const Widget* widget,
const Style* style,
const gfx::Rect& bounds,
gfx::Rect& textBounds, int& textAlign)
{
gfx::Size sizeHint;
gfx::Border borderHint;
gfx::Rect textHint;
calcWidgetMetrics(widget, style, sizeHint, borderHint,
textHint, textAlign);
textBounds = bounds;
textBounds.shrink(borderHint);
textBounds.offset(textHint.origin());
}
void Theme::measureLayer(const Widget* widget, void Theme::measureLayer(const Widget* widget,
const Style* style, const Style* style,
const Style::Layer& layer, const Style::Layer& layer,
gfx::Border& borderHint, gfx::Border& borderHint,
gfx::Size& textHint, int& textAlign, gfx::Rect& textHint, int& textAlign,
gfx::Size& iconHint, int& iconAlign) gfx::Size& iconHint, int& iconAlign)
{ {
ASSERT(style); ASSERT(style);
@ -531,6 +550,7 @@ void Theme::measureLayer(const Widget* widget,
gfx::Size textSize(Graphics::measureUITextLength(widget->text(), font), gfx::Size textSize(Graphics::measureUITextLength(widget->text(), font),
font->height()); font->height());
textHint.offset(layer.offset());
textHint.w = std::max(textHint.w, textSize.w+ABS(layer.offset().x)); textHint.w = std::max(textHint.w, textSize.w+ABS(layer.offset().x));
textHint.h = std::max(textHint.h, textSize.h+ABS(layer.offset().y)); textHint.h = std::max(textHint.h, textSize.h+ABS(layer.offset().y));
textAlign = layer.align(); textAlign = layer.align();
@ -555,7 +575,10 @@ gfx::Border Theme::calcBorder(const Widget* widget,
{ {
gfx::Size sizeHint; gfx::Size sizeHint;
gfx::Border borderHint; gfx::Border borderHint;
calcWidgetMetrics(widget, style, sizeHint, borderHint); gfx::Rect textHint;
int textAlign;
calcWidgetMetrics(widget, style, sizeHint, borderHint,
textHint, textAlign);
return borderHint; return borderHint;
} }
@ -610,7 +633,8 @@ gfx::Color Theme::calcBgColor(const Widget* widget,
void Theme::calcWidgetMetrics(const Widget* widget, void Theme::calcWidgetMetrics(const Widget* widget,
const Style* style, const Style* style,
gfx::Size& sizeHint, gfx::Size& sizeHint,
gfx::Border& borderHint) gfx::Border& borderHint,
gfx::Rect& textHint, int& textAlign)
{ {
ASSERT(widget); ASSERT(widget);
ASSERT(style); ASSERT(style);
@ -619,9 +643,11 @@ void Theme::calcWidgetMetrics(const Widget* widget,
borderHint = gfx::Border(0, 0, 0, 0); borderHint = gfx::Border(0, 0, 0, 0);
gfx::Border paddingHint(0, 0, 0, 0); gfx::Border paddingHint(0, 0, 0, 0);
gfx::Size textHint(0, 0);
textHint = gfx::Rect(0, 0, 0, 0);
textAlign = CENTER | MIDDLE;
gfx::Size iconHint(0, 0); gfx::Size iconHint(0, 0);
int textAlign = CENTER | MIDDLE;
int iconAlign = CENTER | MIDDLE; int iconAlign = CENTER | MIDDLE;
for_each_layer( for_each_layer(

@ -1,4 +1,5 @@
// Aseprite UI Library // Aseprite UI Library
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This file is released under the terms of the MIT license. // This file is released under the terms of the MIT license.
@ -109,6 +110,10 @@ namespace ui {
gfx::Size& topLeft, gfx::Size& topLeft,
gfx::Size& center, gfx::Size& center,
gfx::Size& bottomRight); gfx::Size& bottomRight);
virtual void calcTextInfo(const Widget* widget,
const Style* style,
const gfx::Rect& bounds,
gfx::Rect& textBounds, int& textAlign);
virtual gfx::Color calcBgColor(const Widget* widget, virtual gfx::Color calcBgColor(const Widget* widget,
const Style* style); const Style* style);
@ -139,12 +144,13 @@ namespace ui {
const Style* style, const Style* style,
const Style::Layer& layer, const Style::Layer& layer,
gfx::Border& borderHint, gfx::Border& borderHint,
gfx::Size& textHint, int& textAlign, gfx::Rect& textHint, int& textAlign,
gfx::Size& iconHint, int& iconAlign); gfx::Size& iconHint, int& iconAlign);
void calcWidgetMetrics(const Widget* widget, void calcWidgetMetrics(const Widget* widget,
const Style* style, const Style* style,
gfx::Size& sizeHint, gfx::Size& sizeHint,
gfx::Border& borderHint); gfx::Border& borderHint,
gfx::Rect& textHint, int& textAlign);
}; };
} // namespace ui } // namespace ui