mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-29 21:33:12 +00:00
Add theme variants to switch easily between Light/Dark themes
This commit is contained in:
parent
e7f0832ff3
commit
c99000a2c3
@ -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" }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -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">
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user