Add theme variants to switch easily between Light/Dark themes

This commit is contained in:
David Capello 2021-05-22 00:42:36 -03:00
parent e7f0832ff3
commit c99000a2c3
5 changed files with 143 additions and 34 deletions

View File

@ -1,9 +1,9 @@
{
"name": "aseprite-theme",
"displayName": "Aseprite Default Theme",
"description": "Default Aseprite Pixel-Art Theme",
"description": "Default Aseprite Pixel-Art Themes",
"version": "1.0",
"author": { "name": "David Capello", "email": "davidcapello@gmail.com", "url": "http://davidcapello.com/" },
"author": { "name": "David Capello", "email": "david@igarastudio.com", "url": "http://davidcapello.com/" },
"contributors": [
{ "name": "Ilija Melentijevic", "url": "http://ilkke.blogspot.com/" },
{ "name": "Nicolas Desilets", "url": "https://twitter.com/MapleGecko" }
@ -15,8 +15,8 @@
],
"contributes": {
"themes": [
{ "id": "default", "path": "." },
{ "id": "default-dark", "path": "./dark" }
{ "id": "default", "path": ".", "variant": "Light" },
{ "id": "default-dark", "path": "./dark", "variant": "Dark" }
]
}
}

View File

@ -39,7 +39,7 @@
<listitem text="300%" value="3" />
<listitem text="400%" value="4" />
</combobox>
<boxfiller />
<hbox id="theme_variants" />
<label text="@.ui_scaling" />
<combobox id="ui_scale">

View File

@ -110,11 +110,13 @@ class OptionsWindow : public app::gen::Options {
class ThemeItem : public ListItem {
public:
ThemeItem(const std::string& path,
const std::string& name)
: ListItem(name.empty() ? "-- " + path + " --": name),
ThemeItem(const std::string& id,
const std::string& path,
const std::string& displayName = std::string(),
const std::string& variant = std::string())
: ListItem(createLabel(path, id, displayName, variant)),
m_path(path),
m_name(name) {
m_name(id) {
}
const std::string& themePath() const { return m_path; }
@ -129,6 +131,30 @@ class OptionsWindow : public app::gen::Options {
}
private:
static std::string createLabel(const std::string& path,
const std::string& id,
const std::string& displayName,
const std::string& variant) {
if (displayName.empty()) {
if (id.empty())
return fmt::format("-- {} --", path);
else
return id;
}
else if (id == displayName) {
if (variant.empty())
return id;
else
return fmt::format("{} - {}", id, variant);
}
else {
if (variant.empty())
return displayName;
else
return fmt::format("{} - {}", displayName, variant);
}
}
std::string m_path;
std::string m_name;
};
@ -190,6 +216,24 @@ class OptionsWindow : public app::gen::Options {
Extension* m_extension;
};
class ThemeVariantItem : public ButtonSet::Item {
public:
ThemeVariantItem(OptionsWindow* options,
const std::string& id,
const std::string& variant)
: m_options(options)
, m_themeId(id) {
setText(variant);
}
private:
void onClick() override {
m_options->setUITheme(m_themeId, true,
false); // Don't recreate variants
}
OptionsWindow* m_options;
std::string m_themeId;
};
public:
OptionsWindow(Context* context, int& curSection)
: m_context(context)
@ -204,6 +248,9 @@ public:
{
sectionListbox()->Change.connect([this]{ onChangeSection(); });
// Theme variants
fillThemeVariants();
// Default extension to save files
fillExtensionsCombobox(defaultExtension(), m_pref.saveFile.defaultExtension());
fillExtensionsCombobox(exportImageDefaultExtension(), m_pref.exportFile.imageDefaultExtension());
@ -823,6 +870,42 @@ public:
private:
void fillThemeVariants() {
ButtonSet* list = nullptr;
for (Extension* ext : App::instance()->extensions()) {
if (ext->isCurrentTheme()) {
// Number of variants
int c = 0;
for (auto it : ext->themes()) {
if (!it.second.variant.empty())
++c;
}
if (c >= 2) {
list = new ButtonSet(c);
for (auto it : ext->themes()) {
if (!it.second.variant.empty()) {
auto item = list->addItem(
new ThemeVariantItem(this, it.first, it.second.variant));
if (it.first == Preferences::instance().theme.selected())
list->setSelectedItem(item, false);
}
}
}
break;
}
}
if (list) {
themeVariants()->addChild(list);
}
if (m_themeVars) {
themeVariants()->removeChild(m_themeVars);
m_themeVars->deferDelete();
}
m_themeVars = list;
}
void fillExtensionsCombobox(ui::ComboBox* combobox,
const std::string& defExt) {
base::paths exts = get_writable_extensions();
@ -1196,7 +1279,7 @@ private:
new SeparatorInView(base::normalize_path(path), HORIZONTAL));
}
ThemeItem* item = new ThemeItem(fullPath, fn);
ThemeItem* item = new ThemeItem(fn, fullPath);
themeList()->addChild(item);
// Selected theme
@ -1221,11 +1304,14 @@ private:
}
for (auto it : ext->themes()) {
ThemeItem* item = new ThemeItem(it.second, it.first);
ThemeItem* item = new ThemeItem(it.first,
it.second.path,
ext->displayName(),
it.second.variant);
themeList()->addChild(item);
// Selected theme
if (it.second == selectedPath)
if (it.second.path == selectedPath)
themeList()->selectChild(item);
}
}
@ -1296,7 +1382,8 @@ private:
}
void setUITheme(const std::string& themeName,
const bool updateScaling) {
const bool updateScaling,
const bool recreateVariantsFields = true) {
try {
if (themeName != m_pref.theme.selected()) {
auto theme = static_cast<skin::SkinTheme*>(ui::get_theme());
@ -1343,6 +1430,9 @@ private:
selectScalingItems();
}
}
if (recreateVariantsFields)
fillThemeVariants();
}
}
catch (const std::exception& ex) {
@ -1618,6 +1708,7 @@ private:
std::vector<os::ColorSpaceRef> m_colorSpaces;
std::string m_templateTextForDisplayCS;
RgbMapAlgorithmSelector m_rgbmapAlgorithmSelector;
ButtonSet* m_themeVars = nullptr;
};
class OptionsCommand : public Command {

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2020-2021 Igara Studio S.A.
// Copyright (C) 2017-2018 David Capello
//
// This program is distributed under the terms of
@ -263,9 +263,9 @@ void Extension::addLanguage(const std::string& id, const std::string& path)
updateCategory(Category::Languages);
}
void Extension::addTheme(const std::string& id, const std::string& path)
void Extension::addTheme(const std::string& id, const std::string& path, const std::string& variant)
{
m_themes[id] = path;
m_themes[id] = ThemeInfo(path, variant);
updateCategory(Category::Themes);
}
@ -789,7 +789,7 @@ std::string Extensions::themePath(const std::string& themeId)
auto it = ext->themes().find(themeId);
if (it != ext->themes().end())
return it->second;
return it->second.path;
}
return std::string();
}
@ -1026,7 +1026,7 @@ Extension* Extensions::loadExtension(const std::string& path,
// The path must be always relative to the extension
langPath = base::join_path(path, langPath);
LOG("EXT: New language '%s' in '%s'\n",
LOG("EXT: New language id=%s path=%s\n",
langId.c_str(),
langPath.c_str());
@ -1040,15 +1040,17 @@ Extension* Extensions::loadExtension(const std::string& path,
for (const auto& theme : themes.array_items()) {
std::string themeId = theme["id"].string_value();
std::string themePath = theme["path"].string_value();
std::string themeVariant = theme["variant"].string_value();
// The path must be always relative to the extension
themePath = base::join_path(path, themePath);
LOG("EXT: New theme '%s' in '%s'\n",
LOG("EXT: New theme id=%s path=%s variant=%s\n",
themeId.c_str(),
themePath.c_str());
themePath.c_str(),
themeVariant.c_str());
extension->addTheme(themeId, themePath);
extension->addTheme(themeId, themePath, themeVariant);
}
}
@ -1062,7 +1064,7 @@ Extension* Extensions::loadExtension(const std::string& path,
// The path must be always relative to the extension
palPath = base::join_path(path, palPath);
LOG("EXT: New palette '%s' in '%s'\n",
LOG("EXT: New palette id=%s path=%s\n",
palId.c_str(),
palPath.c_str());
@ -1083,7 +1085,7 @@ Extension* Extensions::loadExtension(const std::string& path,
// The path must be always relative to the extension
matPath = base::join_path(path, matPath);
LOG("EXT: New dithering matrix '%s' in '%s'\n",
LOG("EXT: New dithering matrix id=%s path=%s\n",
matId.c_str(),
matPath.c_str());
@ -1103,7 +1105,7 @@ Extension* Extensions::loadExtension(const std::string& path,
// The path must be always relative to the extension
scriptPath = base::join_path(path, scriptPath);
LOG("EXT: New script '%s'\n", scriptPath.c_str());
LOG("EXT: New script path=%s\n", scriptPath.c_str());
extension->addScript(scriptPath);
}
@ -1116,7 +1118,7 @@ Extension* Extensions::loadExtension(const std::string& path,
// The path must be always relative to the extension
scriptPath = base::join_path(path, scriptPath);
LOG("EXT: New script '%s'\n", scriptPath.c_str());
LOG("EXT: New script path=%s\n", scriptPath.c_str());
extension->addScript(scriptPath);
}

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2020-2021 Igara Studio S.A.
// Copyright (C) 2017-2018 David Capello
//
// This program is distributed under the terms of
@ -18,9 +18,9 @@
namespace app {
// Key=theme/palette/etc. id
// Value=theme/palette/etc. path
typedef std::map<std::string, std::string> ExtensionItems;
// Key=id
// Value=path
using ExtensionItems = std::map<std::string, std::string>;
class Extensions;
@ -34,6 +34,7 @@ namespace app {
class Extension {
friend class Extensions;
public:
enum class Category {
None,
Languages,
@ -61,6 +62,20 @@ namespace app {
mutable bool m_loaded = false;
};
struct ThemeInfo {
std::string path;
std::string variant;
ThemeInfo() = default;
ThemeInfo(const std::string& path,
const std::string& variant)
: path(path)
, variant(variant) { }
};
using Themes = std::map<std::string, ThemeInfo>;
using DitheringMatrices = std::map<std::string, DitheringMatrixInfo>;
Extension(const std::string& path,
const std::string& name,
const std::string& version,
@ -79,11 +94,11 @@ namespace app {
const Category category() const { return m_category; }
const ExtensionItems& languages() const { return m_languages; }
const ExtensionItems& themes() const { return m_themes; }
const Themes& themes() const { return m_themes; }
const ExtensionItems& palettes() const { return m_palettes; }
void addLanguage(const std::string& id, const std::string& path);
void addTheme(const std::string& id, const std::string& path);
void addTheme(const std::string& id, const std::string& path, const std::string& variant);
void addPalette(const std::string& id, const std::string& path);
void addDitheringMatrix(const std::string& id,
const std::string& path,
@ -107,11 +122,12 @@ namespace app {
void addScript(const std::string& fn);
#endif
bool isCurrentTheme() const;
private:
void enable(const bool state);
void uninstall();
void uninstallFiles(const std::string& path);
bool isCurrentTheme() const;
bool isDefaultTheme() const;
void updateCategory(const Category newCategory);
#ifdef ENABLE_SCRIPTING
@ -120,9 +136,9 @@ namespace app {
#endif
ExtensionItems m_languages;
ExtensionItems m_themes;
Themes m_themes;
ExtensionItems m_palettes;
std::map<std::string, DitheringMatrixInfo> m_ditheringMatrices;
DitheringMatrices m_ditheringMatrices;
#ifdef ENABLE_SCRIPTING
struct ScriptItem {