mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-30 15:32:38 +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",
|
"name": "aseprite-theme",
|
||||||
"displayName": "Aseprite Default Theme",
|
"displayName": "Aseprite Default Theme",
|
||||||
"description": "Default Aseprite Pixel-Art Theme",
|
"description": "Default Aseprite Pixel-Art Themes",
|
||||||
"version": "1.0",
|
"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": [
|
"contributors": [
|
||||||
{ "name": "Ilija Melentijevic", "url": "http://ilkke.blogspot.com/" },
|
{ "name": "Ilija Melentijevic", "url": "http://ilkke.blogspot.com/" },
|
||||||
{ "name": "Nicolas Desilets", "url": "https://twitter.com/MapleGecko" }
|
{ "name": "Nicolas Desilets", "url": "https://twitter.com/MapleGecko" }
|
||||||
@ -15,8 +15,8 @@
|
|||||||
],
|
],
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"themes": [
|
"themes": [
|
||||||
{ "id": "default", "path": "." },
|
{ "id": "default", "path": ".", "variant": "Light" },
|
||||||
{ "id": "default-dark", "path": "./dark" }
|
{ "id": "default-dark", "path": "./dark", "variant": "Dark" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
<listitem text="300%" value="3" />
|
<listitem text="300%" value="3" />
|
||||||
<listitem text="400%" value="4" />
|
<listitem text="400%" value="4" />
|
||||||
</combobox>
|
</combobox>
|
||||||
<boxfiller />
|
<hbox id="theme_variants" />
|
||||||
|
|
||||||
<label text="@.ui_scaling" />
|
<label text="@.ui_scaling" />
|
||||||
<combobox id="ui_scale">
|
<combobox id="ui_scale">
|
||||||
|
@ -110,11 +110,13 @@ class OptionsWindow : public app::gen::Options {
|
|||||||
|
|
||||||
class ThemeItem : public ListItem {
|
class ThemeItem : public ListItem {
|
||||||
public:
|
public:
|
||||||
ThemeItem(const std::string& path,
|
ThemeItem(const std::string& id,
|
||||||
const std::string& name)
|
const std::string& path,
|
||||||
: ListItem(name.empty() ? "-- " + path + " --": name),
|
const std::string& displayName = std::string(),
|
||||||
|
const std::string& variant = std::string())
|
||||||
|
: ListItem(createLabel(path, id, displayName, variant)),
|
||||||
m_path(path),
|
m_path(path),
|
||||||
m_name(name) {
|
m_name(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& themePath() const { return m_path; }
|
const std::string& themePath() const { return m_path; }
|
||||||
@ -129,6 +131,30 @@ class OptionsWindow : public app::gen::Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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_path;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
};
|
};
|
||||||
@ -190,6 +216,24 @@ class OptionsWindow : public app::gen::Options {
|
|||||||
Extension* m_extension;
|
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:
|
public:
|
||||||
OptionsWindow(Context* context, int& curSection)
|
OptionsWindow(Context* context, int& curSection)
|
||||||
: m_context(context)
|
: m_context(context)
|
||||||
@ -204,6 +248,9 @@ public:
|
|||||||
{
|
{
|
||||||
sectionListbox()->Change.connect([this]{ onChangeSection(); });
|
sectionListbox()->Change.connect([this]{ onChangeSection(); });
|
||||||
|
|
||||||
|
// Theme variants
|
||||||
|
fillThemeVariants();
|
||||||
|
|
||||||
// Default extension to save files
|
// Default extension to save files
|
||||||
fillExtensionsCombobox(defaultExtension(), m_pref.saveFile.defaultExtension());
|
fillExtensionsCombobox(defaultExtension(), m_pref.saveFile.defaultExtension());
|
||||||
fillExtensionsCombobox(exportImageDefaultExtension(), m_pref.exportFile.imageDefaultExtension());
|
fillExtensionsCombobox(exportImageDefaultExtension(), m_pref.exportFile.imageDefaultExtension());
|
||||||
@ -823,6 +870,42 @@ public:
|
|||||||
|
|
||||||
private:
|
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,
|
void fillExtensionsCombobox(ui::ComboBox* combobox,
|
||||||
const std::string& defExt) {
|
const std::string& defExt) {
|
||||||
base::paths exts = get_writable_extensions();
|
base::paths exts = get_writable_extensions();
|
||||||
@ -1196,7 +1279,7 @@ private:
|
|||||||
new SeparatorInView(base::normalize_path(path), HORIZONTAL));
|
new SeparatorInView(base::normalize_path(path), HORIZONTAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeItem* item = new ThemeItem(fullPath, fn);
|
ThemeItem* item = new ThemeItem(fn, fullPath);
|
||||||
themeList()->addChild(item);
|
themeList()->addChild(item);
|
||||||
|
|
||||||
// Selected theme
|
// Selected theme
|
||||||
@ -1221,11 +1304,14 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto it : ext->themes()) {
|
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);
|
themeList()->addChild(item);
|
||||||
|
|
||||||
// Selected theme
|
// Selected theme
|
||||||
if (it.second == selectedPath)
|
if (it.second.path == selectedPath)
|
||||||
themeList()->selectChild(item);
|
themeList()->selectChild(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1296,7 +1382,8 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setUITheme(const std::string& themeName,
|
void setUITheme(const std::string& themeName,
|
||||||
const bool updateScaling) {
|
const bool updateScaling,
|
||||||
|
const bool recreateVariantsFields = true) {
|
||||||
try {
|
try {
|
||||||
if (themeName != m_pref.theme.selected()) {
|
if (themeName != m_pref.theme.selected()) {
|
||||||
auto theme = static_cast<skin::SkinTheme*>(ui::get_theme());
|
auto theme = static_cast<skin::SkinTheme*>(ui::get_theme());
|
||||||
@ -1343,6 +1430,9 @@ private:
|
|||||||
selectScalingItems();
|
selectScalingItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (recreateVariantsFields)
|
||||||
|
fillThemeVariants();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& ex) {
|
catch (const std::exception& ex) {
|
||||||
@ -1618,6 +1708,7 @@ private:
|
|||||||
std::vector<os::ColorSpaceRef> m_colorSpaces;
|
std::vector<os::ColorSpaceRef> m_colorSpaces;
|
||||||
std::string m_templateTextForDisplayCS;
|
std::string m_templateTextForDisplayCS;
|
||||||
RgbMapAlgorithmSelector m_rgbmapAlgorithmSelector;
|
RgbMapAlgorithmSelector m_rgbmapAlgorithmSelector;
|
||||||
|
ButtonSet* m_themeVars = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OptionsCommand : public Command {
|
class OptionsCommand : public Command {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2020 Igara Studio S.A.
|
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||||
// Copyright (C) 2017-2018 David Capello
|
// Copyright (C) 2017-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// 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);
|
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);
|
updateCategory(Category::Themes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -789,7 +789,7 @@ std::string Extensions::themePath(const std::string& themeId)
|
|||||||
|
|
||||||
auto it = ext->themes().find(themeId);
|
auto it = ext->themes().find(themeId);
|
||||||
if (it != ext->themes().end())
|
if (it != ext->themes().end())
|
||||||
return it->second;
|
return it->second.path;
|
||||||
}
|
}
|
||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
@ -1026,7 +1026,7 @@ Extension* Extensions::loadExtension(const std::string& path,
|
|||||||
// The path must be always relative to the extension
|
// The path must be always relative to the extension
|
||||||
langPath = base::join_path(path, langPath);
|
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(),
|
langId.c_str(),
|
||||||
langPath.c_str());
|
langPath.c_str());
|
||||||
|
|
||||||
@ -1040,15 +1040,17 @@ Extension* Extensions::loadExtension(const std::string& path,
|
|||||||
for (const auto& theme : themes.array_items()) {
|
for (const auto& theme : themes.array_items()) {
|
||||||
std::string themeId = theme["id"].string_value();
|
std::string themeId = theme["id"].string_value();
|
||||||
std::string themePath = theme["path"].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
|
// The path must be always relative to the extension
|
||||||
themePath = base::join_path(path, themePath);
|
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(),
|
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
|
// The path must be always relative to the extension
|
||||||
palPath = base::join_path(path, palPath);
|
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(),
|
palId.c_str(),
|
||||||
palPath.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
|
// The path must be always relative to the extension
|
||||||
matPath = base::join_path(path, matPath);
|
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(),
|
matId.c_str(),
|
||||||
matPath.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
|
// The path must be always relative to the extension
|
||||||
scriptPath = base::join_path(path, scriptPath);
|
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);
|
extension->addScript(scriptPath);
|
||||||
}
|
}
|
||||||
@ -1116,7 +1118,7 @@ Extension* Extensions::loadExtension(const std::string& path,
|
|||||||
// The path must be always relative to the extension
|
// The path must be always relative to the extension
|
||||||
scriptPath = base::join_path(path, scriptPath);
|
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);
|
extension->addScript(scriptPath);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2020 Igara Studio S.A.
|
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||||
// Copyright (C) 2017-2018 David Capello
|
// Copyright (C) 2017-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -18,9 +18,9 @@
|
|||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
// Key=theme/palette/etc. id
|
// Key=id
|
||||||
// Value=theme/palette/etc. path
|
// Value=path
|
||||||
typedef std::map<std::string, std::string> ExtensionItems;
|
using ExtensionItems = std::map<std::string, std::string>;
|
||||||
|
|
||||||
class Extensions;
|
class Extensions;
|
||||||
|
|
||||||
@ -34,6 +34,7 @@ namespace app {
|
|||||||
class Extension {
|
class Extension {
|
||||||
friend class Extensions;
|
friend class Extensions;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum class Category {
|
enum class Category {
|
||||||
None,
|
None,
|
||||||
Languages,
|
Languages,
|
||||||
@ -61,6 +62,20 @@ namespace app {
|
|||||||
mutable bool m_loaded = false;
|
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,
|
Extension(const std::string& path,
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
const std::string& version,
|
const std::string& version,
|
||||||
@ -79,11 +94,11 @@ namespace app {
|
|||||||
const Category category() const { return m_category; }
|
const Category category() const { return m_category; }
|
||||||
|
|
||||||
const ExtensionItems& languages() const { return m_languages; }
|
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; }
|
const ExtensionItems& palettes() const { return m_palettes; }
|
||||||
|
|
||||||
void addLanguage(const std::string& id, const std::string& path);
|
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 addPalette(const std::string& id, const std::string& path);
|
||||||
void addDitheringMatrix(const std::string& id,
|
void addDitheringMatrix(const std::string& id,
|
||||||
const std::string& path,
|
const std::string& path,
|
||||||
@ -107,11 +122,12 @@ namespace app {
|
|||||||
void addScript(const std::string& fn);
|
void addScript(const std::string& fn);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool isCurrentTheme() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void enable(const bool state);
|
void enable(const bool state);
|
||||||
void uninstall();
|
void uninstall();
|
||||||
void uninstallFiles(const std::string& path);
|
void uninstallFiles(const std::string& path);
|
||||||
bool isCurrentTheme() const;
|
|
||||||
bool isDefaultTheme() const;
|
bool isDefaultTheme() const;
|
||||||
void updateCategory(const Category newCategory);
|
void updateCategory(const Category newCategory);
|
||||||
#ifdef ENABLE_SCRIPTING
|
#ifdef ENABLE_SCRIPTING
|
||||||
@ -120,9 +136,9 @@ namespace app {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
ExtensionItems m_languages;
|
ExtensionItems m_languages;
|
||||||
ExtensionItems m_themes;
|
Themes m_themes;
|
||||||
ExtensionItems m_palettes;
|
ExtensionItems m_palettes;
|
||||||
std::map<std::string, DitheringMatrixInfo> m_ditheringMatrices;
|
DitheringMatrices m_ditheringMatrices;
|
||||||
|
|
||||||
#ifdef ENABLE_SCRIPTING
|
#ifdef ENABLE_SCRIPTING
|
||||||
struct ScriptItem {
|
struct ScriptItem {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user