mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-30 15:32:38 +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:
parent
3555bbe29f
commit
cc7bdbcec4
@ -958,5 +958,11 @@
|
||||
<icon part="aseprite_face_mouse" state="mouse" />
|
||||
<icon part="aseprite_face_pushed" state="mouse selected" />
|
||||
</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>
|
||||
</theme>
|
||||
|
@ -57,6 +57,39 @@ using namespace ui;
|
||||
// TODO For backward compatibility, in future versions we should remove this (extensions are preferred)
|
||||
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] = {
|
||||
"null", // kNoCursor
|
||||
"normal", // kArrowCursor
|
||||
@ -224,7 +257,8 @@ void SkinTheme::onRegenerateTheme()
|
||||
// Then we load the selected theme to redefine default theme parts.
|
||||
if (pref.theme.selected.defaultValue() != pref.theme.selected()) {
|
||||
try {
|
||||
loadAll(pref.theme.selected());
|
||||
BackwardCompatibility backward;
|
||||
loadAll(pref.theme.selected(), &backward);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
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());
|
||||
|
||||
@ -277,7 +312,7 @@ void SkinTheme::loadAll(const std::string& themeId)
|
||||
throw base::Exception("Theme %s not found", themeId.c_str());
|
||||
|
||||
loadSheet();
|
||||
loadXml();
|
||||
loadXml(backward);
|
||||
}
|
||||
|
||||
void SkinTheme::loadSheet()
|
||||
@ -315,7 +350,7 @@ void SkinTheme::loadSheet()
|
||||
}
|
||||
}
|
||||
|
||||
void SkinTheme::loadXml()
|
||||
void SkinTheme::loadXml(BackwardCompatibility* backward)
|
||||
{
|
||||
const int scale = guiscale();
|
||||
|
||||
@ -515,6 +550,9 @@ void SkinTheme::loadXml()
|
||||
if (extends_id)
|
||||
base = m_styles[extends_id];
|
||||
|
||||
if (backward)
|
||||
backward->notifyStyleExistence(style_id);
|
||||
|
||||
ui::Style* style = m_styles[style_id];
|
||||
if (!style) {
|
||||
m_styles[style_id] = style = new ui::Style(base);
|
||||
@ -699,6 +737,9 @@ void SkinTheme::loadXml()
|
||||
}
|
||||
}
|
||||
|
||||
if (backward)
|
||||
backward->createMissingStyles(this);
|
||||
|
||||
ThemeFile<SkinTheme>::updateInternals();
|
||||
}
|
||||
|
||||
@ -851,13 +892,7 @@ void SkinTheme::initWidget(Widget* widget)
|
||||
break;
|
||||
|
||||
case kSliderWidget:
|
||||
BORDER4(
|
||||
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);
|
||||
widget->setStyle(styles.slider());
|
||||
break;
|
||||
|
||||
case kTextBoxWidget:
|
||||
@ -1100,7 +1135,7 @@ void SkinTheme::drawEntryText(ui::Graphics* g, ui::Entry* widget)
|
||||
drawText(
|
||||
g, widget->getSuffix().c_str(),
|
||||
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;
|
||||
if (!bar)
|
||||
pos.offset(widget->childSpacing()/2, 0);
|
||||
drawText(g, nullptr, fg, ColorNone, widget, pos, 0,
|
||||
widget->mnemonic());
|
||||
drawText(g, nullptr, fg, ColorNone, widget, pos,
|
||||
widget->align(), widget->mnemonic());
|
||||
|
||||
// For menu-box
|
||||
if (!bar) {
|
||||
@ -1225,7 +1260,7 @@ void SkinTheme::paintMenuItem(ui::PaintEvent& ev)
|
||||
std::string buf = appMenuItem->key()->accels().front().toString();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -1236,7 +1271,7 @@ void SkinTheme::paintSlider(PaintEvent& ev)
|
||||
{
|
||||
Graphics* g = ev.graphics();
|
||||
Slider* widget = static_cast<Slider*>(ev.getSource());
|
||||
Rect bounds = widget->clientBounds();
|
||||
const Rect bounds = widget->clientBounds();
|
||||
int min, max, value;
|
||||
|
||||
// Outside borders
|
||||
@ -1246,14 +1281,15 @@ void SkinTheme::paintSlider(PaintEvent& ev)
|
||||
|
||||
widget->getSliderThemeInfo(&min, &max, &value);
|
||||
|
||||
Rect rc(Rect(bounds).shrink(widget->border()));
|
||||
Rect rc = bounds;
|
||||
rc.shrink(widget->border());
|
||||
int x;
|
||||
if (min != max)
|
||||
x = rc.x + rc.w * (value-min) / (max-min);
|
||||
else
|
||||
x = rc.x;
|
||||
|
||||
rc = widget->clientBounds();
|
||||
rc = bounds;
|
||||
|
||||
// The mini-look is used for sliders with tiny borders.
|
||||
bool isMiniLook = false;
|
||||
@ -1328,12 +1364,16 @@ void SkinTheme::paintSlider(PaintEvent& ev)
|
||||
std::string old_text = widget->text();
|
||||
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) {
|
||||
drawText(g, nullptr,
|
||||
colors.sliderFullText(), ColorNone,
|
||||
widget, rc, 0, widget->mnemonic());
|
||||
widget, textrc, textAlign, widget->mnemonic());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1342,7 +1382,7 @@ void SkinTheme::paintSlider(PaintEvent& ev)
|
||||
if (clip) {
|
||||
drawText(g, nullptr,
|
||||
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();
|
||||
}
|
||||
|
||||
void SkinTheme::drawText(Graphics* g, const char *t, gfx::Color fg_color, gfx::Color bg_color,
|
||||
Widget* widget, const Rect& rc,
|
||||
int selected_offset, int mnemonic)
|
||||
void SkinTheme::drawText(Graphics* g, const char* t,
|
||||
const gfx::Color fgColor,
|
||||
const gfx::Color bgColor,
|
||||
const Widget* widget,
|
||||
const Rect& rc,
|
||||
const int textAlign,
|
||||
const int mnemonic)
|
||||
{
|
||||
if (t || widget->hasText()) {
|
||||
Rect textrc;
|
||||
@ -1416,33 +1460,28 @@ void SkinTheme::drawText(Graphics* g, const char *t, gfx::Color fg_color, gfx::C
|
||||
|
||||
// Horizontally text alignment
|
||||
|
||||
if (widget->align() & RIGHT)
|
||||
if (textAlign & RIGHT)
|
||||
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;
|
||||
else
|
||||
textrc.x = rc.x;
|
||||
|
||||
// Vertically text alignment
|
||||
|
||||
if (widget->align() & BOTTOM)
|
||||
if (textAlign & BOTTOM)
|
||||
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;
|
||||
else
|
||||
textrc.y = rc.y;
|
||||
|
||||
if (widget->isSelected()) {
|
||||
textrc.x += selected_offset;
|
||||
textrc.y += selected_offset;
|
||||
}
|
||||
|
||||
// Background
|
||||
if (!is_transparent(bg_color)) {
|
||||
if (!is_transparent(bgColor)) {
|
||||
if (!widget->isEnabled())
|
||||
g->fillRect(bg_color, Rect(textrc).inflate(guiscale(), guiscale()));
|
||||
g->fillRect(bgColor, Rect(textrc).inflate(guiscale(), guiscale()));
|
||||
else
|
||||
g->fillRect(bg_color, textrc);
|
||||
g->fillRect(bgColor, textrc);
|
||||
}
|
||||
|
||||
// Text
|
||||
@ -1467,9 +1506,9 @@ void SkinTheme::drawText(Graphics* g, const char *t, gfx::Color fg_color, gfx::C
|
||||
t,
|
||||
(!widget->isEnabled() ?
|
||||
colors.disabled():
|
||||
(gfx::geta(fg_color) > 0 ? fg_color :
|
||||
(gfx::geta(fgColor) > 0 ? fgColor :
|
||||
colors.text())),
|
||||
bg_color, textrc.origin(),
|
||||
bgColor, textrc.origin(),
|
||||
mnemonic);
|
||||
}
|
||||
}
|
||||
|
@ -130,16 +130,24 @@ namespace app {
|
||||
void onRegenerateTheme() override;
|
||||
|
||||
private:
|
||||
struct BackwardCompatibility;
|
||||
|
||||
void loadFontData();
|
||||
void loadAll(const std::string& themeId);
|
||||
void loadAll(const std::string& themeId,
|
||||
BackwardCompatibility* backward = nullptr);
|
||||
void loadSheet();
|
||||
void loadXml();
|
||||
void loadXml(BackwardCompatibility* backward);
|
||||
|
||||
os::Surface* sliceSheet(os::Surface* sur, const gfx::Rect& bounds);
|
||||
gfx::Color getWidgetBgColor(ui::Widget* widget);
|
||||
void drawText(ui::Graphics* g, const char *t, gfx::Color fg_color, gfx::Color bg_color,
|
||||
ui::Widget* widget, const gfx::Rect& rc,
|
||||
int selected_offset, int mnemonic);
|
||||
void drawText(ui::Graphics* g,
|
||||
const char* t,
|
||||
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);
|
||||
|
||||
std::string findThemePath(const std::string& themeId) const;
|
||||
|
@ -215,20 +215,6 @@ not_used:;
|
||||
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)
|
||||
{
|
||||
theme()->paintSlider(ev);
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -46,7 +47,6 @@ namespace ui {
|
||||
protected:
|
||||
// Events
|
||||
bool onProcessMessage(Message* msg) override;
|
||||
void onSizeHint(SizeHintEvent& ev) override;
|
||||
void onPaint(PaintEvent& ev) override;
|
||||
|
||||
// New events
|
||||
|
@ -490,15 +490,34 @@ gfx::Size Theme::calcSizeHint(const Widget* widget,
|
||||
{
|
||||
gfx::Size sizeHint;
|
||||
gfx::Border borderHint;
|
||||
calcWidgetMetrics(widget, style, sizeHint, borderHint);
|
||||
gfx::Rect textHint;
|
||||
int textAlign;
|
||||
calcWidgetMetrics(widget, style, sizeHint, borderHint,
|
||||
textHint, textAlign);
|
||||
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,
|
||||
const Style* style,
|
||||
const Style::Layer& layer,
|
||||
gfx::Border& borderHint,
|
||||
gfx::Size& textHint, int& textAlign,
|
||||
gfx::Rect& textHint, int& textAlign,
|
||||
gfx::Size& iconHint, int& iconAlign)
|
||||
{
|
||||
ASSERT(style);
|
||||
@ -531,6 +550,7 @@ void Theme::measureLayer(const Widget* widget,
|
||||
gfx::Size textSize(Graphics::measureUITextLength(widget->text(), font),
|
||||
font->height());
|
||||
|
||||
textHint.offset(layer.offset());
|
||||
textHint.w = std::max(textHint.w, textSize.w+ABS(layer.offset().x));
|
||||
textHint.h = std::max(textHint.h, textSize.h+ABS(layer.offset().y));
|
||||
textAlign = layer.align();
|
||||
@ -555,7 +575,10 @@ gfx::Border Theme::calcBorder(const Widget* widget,
|
||||
{
|
||||
gfx::Size sizeHint;
|
||||
gfx::Border borderHint;
|
||||
calcWidgetMetrics(widget, style, sizeHint, borderHint);
|
||||
gfx::Rect textHint;
|
||||
int textAlign;
|
||||
calcWidgetMetrics(widget, style, sizeHint, borderHint,
|
||||
textHint, textAlign);
|
||||
return borderHint;
|
||||
}
|
||||
|
||||
@ -610,7 +633,8 @@ gfx::Color Theme::calcBgColor(const Widget* widget,
|
||||
void Theme::calcWidgetMetrics(const Widget* widget,
|
||||
const Style* style,
|
||||
gfx::Size& sizeHint,
|
||||
gfx::Border& borderHint)
|
||||
gfx::Border& borderHint,
|
||||
gfx::Rect& textHint, int& textAlign)
|
||||
{
|
||||
ASSERT(widget);
|
||||
ASSERT(style);
|
||||
@ -619,9 +643,11 @@ void Theme::calcWidgetMetrics(const Widget* widget,
|
||||
|
||||
borderHint = gfx::Border(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);
|
||||
int textAlign = CENTER | MIDDLE;
|
||||
int iconAlign = CENTER | MIDDLE;
|
||||
|
||||
for_each_layer(
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -109,6 +110,10 @@ namespace ui {
|
||||
gfx::Size& topLeft,
|
||||
gfx::Size& center,
|
||||
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,
|
||||
const Style* style);
|
||||
|
||||
@ -139,12 +144,13 @@ namespace ui {
|
||||
const Style* style,
|
||||
const Style::Layer& layer,
|
||||
gfx::Border& borderHint,
|
||||
gfx::Size& textHint, int& textAlign,
|
||||
gfx::Rect& textHint, int& textAlign,
|
||||
gfx::Size& iconHint, int& iconAlign);
|
||||
void calcWidgetMetrics(const Widget* widget,
|
||||
const Style* style,
|
||||
gfx::Size& sizeHint,
|
||||
gfx::Border& borderHint);
|
||||
gfx::Border& borderHint,
|
||||
gfx::Rect& textHint, int& textAlign);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
Loading…
x
Reference in New Issue
Block a user