mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-16 04:13:50 +00:00
Shox extensions in different categories in the Preferences dialog
This commit is contained in:
parent
ff3e9504fd
commit
5affdbbae1
@ -1209,6 +1209,12 @@ available_themes = Available Themes
|
||||
select_theme = &Select
|
||||
download_themes = Download Themes
|
||||
open_theme_folder = Open &Folder
|
||||
language_extensions = Languages
|
||||
theme_extensions = Themes
|
||||
script_extensions = Scripts
|
||||
palette_extensions = Palettes
|
||||
dithering_matrix_extensions = Dithering Matrices
|
||||
multiple_extensions = Multiple Categories
|
||||
add_extension = &Add Extension
|
||||
add_extension_title = Add Extension
|
||||
enable_extension = &Enable
|
||||
|
@ -71,6 +71,25 @@ app::gen::ColorProfileBehavior missingCsMap[] = {
|
||||
app::gen::ColorProfileBehavior::ASK,
|
||||
};
|
||||
|
||||
class ExtensionCategorySeparator : public SeparatorInView {
|
||||
public:
|
||||
ExtensionCategorySeparator(const Extension::Category category,
|
||||
const std::string& text)
|
||||
: SeparatorInView(text, ui::HORIZONTAL)
|
||||
, m_category(category) {
|
||||
InitTheme.connect(
|
||||
[this]{
|
||||
auto b = this->border();
|
||||
b.top(2*b.top());
|
||||
b.bottom(2*b.bottom());
|
||||
this->setBorder(b);
|
||||
});
|
||||
}
|
||||
Extension::Category category() const { return m_category; }
|
||||
private:
|
||||
Extension::Category m_category;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
using namespace ui;
|
||||
@ -123,6 +142,11 @@ class OptionsWindow : public app::gen::Options {
|
||||
|
||||
Extension* extension() { return m_extension; }
|
||||
|
||||
Extension::Category category() const {
|
||||
ASSERT(m_extension);
|
||||
return m_extension->category();
|
||||
}
|
||||
|
||||
bool isEnabled() const {
|
||||
ASSERT(m_extension);
|
||||
return m_extension->isEnabled();
|
||||
@ -1133,16 +1157,51 @@ private:
|
||||
themeList()->layout();
|
||||
}
|
||||
|
||||
void loadExtensionsByCategory(const Extension::Category category,
|
||||
const std::string& label) {
|
||||
bool hasItems = false;
|
||||
auto sep = new ExtensionCategorySeparator(category, label);
|
||||
extensionsList()->addChild(sep);
|
||||
for (auto e : App::instance()->extensions()) {
|
||||
if (e->category() == category) {
|
||||
ExtensionItem* item = new ExtensionItem(e);
|
||||
extensionsList()->addChild(item);
|
||||
hasItems = true;
|
||||
}
|
||||
}
|
||||
sep->setVisible(hasItems);
|
||||
}
|
||||
|
||||
void loadExtensions() {
|
||||
// Extensions already loaded
|
||||
if (extensionsList()->getItemsCount() > 0)
|
||||
return;
|
||||
|
||||
for (auto extension : App::instance()->extensions()) {
|
||||
ExtensionItem* item = new ExtensionItem(extension);
|
||||
extensionsList()->addChild(item);
|
||||
}
|
||||
extensionsList()->sortItems();
|
||||
loadExtensionsByCategory(
|
||||
Extension::Category::Languages,
|
||||
Strings::options_language_extensions());
|
||||
|
||||
loadExtensionsByCategory(
|
||||
Extension::Category::Themes,
|
||||
Strings::options_theme_extensions());
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
loadExtensionsByCategory(
|
||||
Extension::Category::Scripts,
|
||||
Strings::options_script_extensions());
|
||||
#endif
|
||||
|
||||
loadExtensionsByCategory(
|
||||
Extension::Category::Palettes,
|
||||
Strings::options_palette_extensions());
|
||||
|
||||
loadExtensionsByCategory(
|
||||
Extension::Category::DitheringMatrices,
|
||||
Strings::options_dithering_matrix_extensions());
|
||||
|
||||
loadExtensionsByCategory(
|
||||
Extension::Category::Multiple,
|
||||
Strings::options_multiple_extensions());
|
||||
|
||||
onExtensionChange();
|
||||
extensionsList()->layout();
|
||||
@ -1299,7 +1358,33 @@ private:
|
||||
// Add the new extension in the listbox
|
||||
ExtensionItem* item = new ExtensionItem(ext);
|
||||
extensionsList()->addChild(item);
|
||||
extensionsList()->sortItems();
|
||||
updateCategoryVisibility();
|
||||
extensionsList()->sortItems(
|
||||
[](Widget* a, Widget* b){
|
||||
auto aSep = dynamic_cast<ExtensionCategorySeparator*>(a);
|
||||
auto bSep = dynamic_cast<ExtensionCategorySeparator*>(b);
|
||||
auto aItem = dynamic_cast<ExtensionItem*>(a);
|
||||
auto bItem = dynamic_cast<ExtensionItem*>(b);
|
||||
auto aCat = (aSep ? aSep->category():
|
||||
aItem ? aItem->category(): Extension::Category::None);
|
||||
auto bCat = (bSep ? bSep->category():
|
||||
bItem ? bItem->category(): Extension::Category::None);
|
||||
if (aCat < bCat)
|
||||
return true;
|
||||
else if (aCat == bCat) {
|
||||
// There are no two separators with same category.
|
||||
ASSERT(!(aSep && bSep));
|
||||
|
||||
if (aSep && !bSep)
|
||||
return true;
|
||||
else if (!aSep && bSep)
|
||||
return false;
|
||||
else
|
||||
return (base::compare_filenames(a->text(), b->text()) < 0);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
});
|
||||
extensionsList()->layout();
|
||||
extensionsList()->selectChild(item);
|
||||
}
|
||||
@ -1339,6 +1424,7 @@ private:
|
||||
void deleteExtensionItem(ExtensionItem* item) {
|
||||
// Remove the item from the list
|
||||
extensionsList()->removeChild(item);
|
||||
updateCategoryVisibility();
|
||||
extensionsList()->layout();
|
||||
item->deferDelete();
|
||||
}
|
||||
@ -1404,6 +1490,21 @@ private:
|
||||
return paths;
|
||||
}
|
||||
|
||||
void updateCategoryVisibility() {
|
||||
bool visibleCategories[int(Extension::Category::Max)];
|
||||
for (auto& v : visibleCategories)
|
||||
v = false;
|
||||
for (auto w : extensionsList()->children()) {
|
||||
if (auto item = dynamic_cast<ExtensionItem*>(w)) {
|
||||
visibleCategories[int(item->category())] = true;
|
||||
}
|
||||
}
|
||||
for (auto w : extensionsList()->children()) {
|
||||
if (auto sep = dynamic_cast<ExtensionCategorySeparator*>(w))
|
||||
sep->setVisible(visibleCategories[int(sep->category())]);
|
||||
}
|
||||
}
|
||||
|
||||
Context* m_context;
|
||||
Preferences& m_pref;
|
||||
DocumentPreferences& m_globPref;
|
||||
|
@ -222,6 +222,7 @@ Extension::Extension(const std::string& path,
|
||||
, m_name(name)
|
||||
, m_version(version)
|
||||
, m_displayName(displayName)
|
||||
, m_category(Category::None)
|
||||
, m_isEnabled(isEnabled)
|
||||
, m_isInstalled(true)
|
||||
, m_isBuiltinExtension(isBuiltinExtension)
|
||||
@ -257,16 +258,19 @@ void Extension::executeExitActions()
|
||||
void Extension::addLanguage(const std::string& id, const std::string& path)
|
||||
{
|
||||
m_languages[id] = path;
|
||||
updateCategory(Category::Languages);
|
||||
}
|
||||
|
||||
void Extension::addTheme(const std::string& id, const std::string& path)
|
||||
{
|
||||
m_themes[id] = path;
|
||||
updateCategory(Category::Themes);
|
||||
}
|
||||
|
||||
void Extension::addPalette(const std::string& id, const std::string& path)
|
||||
{
|
||||
m_palettes[id] = path;
|
||||
updateCategory(Category::Palettes);
|
||||
}
|
||||
|
||||
void Extension::addDitheringMatrix(const std::string& id,
|
||||
@ -275,6 +279,7 @@ void Extension::addDitheringMatrix(const std::string& id,
|
||||
{
|
||||
DitheringMatrixInfo info(path, name);
|
||||
m_ditheringMatrices[id] = info;
|
||||
updateCategory(Category::DitheringMatrices);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
@ -447,6 +452,14 @@ bool Extension::isDefaultTheme() const
|
||||
return (name() == kAsepriteDefaultThemeExtensionName);
|
||||
}
|
||||
|
||||
void Extension::updateCategory(const Category newCategory)
|
||||
{
|
||||
if (m_category == Category::None)
|
||||
m_category = newCategory;
|
||||
else if (m_category != newCategory)
|
||||
m_category = Category::Multiple;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
|
||||
// TODO move this to app/script/tableutils.h
|
||||
@ -669,6 +682,7 @@ void Extension::exitScripts()
|
||||
void Extension::addScript(const std::string& fn)
|
||||
{
|
||||
m_plugin.scripts.push_back(ScriptItem(fn));
|
||||
updateCategory(Category::Scripts);
|
||||
}
|
||||
|
||||
#endif // ENABLE_SCRIPTING
|
||||
|
@ -37,6 +37,17 @@ namespace app {
|
||||
class Extension {
|
||||
friend class Extensions;
|
||||
public:
|
||||
enum class Category {
|
||||
None,
|
||||
Languages,
|
||||
Themes,
|
||||
Scripts,
|
||||
Palettes,
|
||||
DitheringMatrices,
|
||||
Multiple,
|
||||
Max
|
||||
};
|
||||
|
||||
class DitheringMatrixInfo {
|
||||
public:
|
||||
DitheringMatrixInfo() : m_matrix(nullptr) { }
|
||||
@ -69,6 +80,7 @@ namespace app {
|
||||
const std::string& name() const { return m_name; }
|
||||
const std::string& version() const { return m_version; }
|
||||
const std::string& displayName() const { return m_displayName; }
|
||||
const Category category() const { return m_category; }
|
||||
|
||||
const ExtensionItems& languages() const { return m_languages; }
|
||||
const ExtensionItems& themes() const { return m_themes; }
|
||||
@ -105,6 +117,7 @@ namespace app {
|
||||
void uninstallFiles(const std::string& path);
|
||||
bool isCurrentTheme() const;
|
||||
bool isDefaultTheme() const;
|
||||
void updateCategory(const Category newCategory);
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
void initScripts();
|
||||
void exitScripts();
|
||||
@ -137,6 +150,7 @@ namespace app {
|
||||
std::string m_name;
|
||||
std::string m_version;
|
||||
std::string m_displayName;
|
||||
Category m_category;
|
||||
bool m_isEnabled;
|
||||
bool m_isInstalled;
|
||||
bool m_isBuiltinExtension;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite UI Library
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -26,6 +26,10 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
static inline bool sort_by_text(Widget* a, Widget* b) {
|
||||
return (base::compare_filenames(a->text(), b->text()) < 0);
|
||||
}
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
ListBox::ListBox()
|
||||
@ -185,14 +189,15 @@ void ListBox::centerScroll()
|
||||
}
|
||||
}
|
||||
|
||||
inline bool sort_by_text(Widget* a, Widget* b) {
|
||||
return (base::compare_filenames(a->text(), b->text()) < 0);
|
||||
}
|
||||
|
||||
void ListBox::sortItems()
|
||||
{
|
||||
sortItems(&sort_by_text);
|
||||
}
|
||||
|
||||
void ListBox::sortItems(bool (*cmp)(Widget* a, Widget* b))
|
||||
{
|
||||
WidgetsList widgets = children();
|
||||
std::sort(widgets.begin(), widgets.end(), &sort_by_text);
|
||||
std::sort(widgets.begin(), widgets.end(), cmp);
|
||||
|
||||
// Remove all children and add then again.
|
||||
removeAllChildren();
|
||||
|
@ -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.
|
||||
@ -35,6 +36,7 @@ namespace ui {
|
||||
void makeChildVisible(Widget* item);
|
||||
void centerScroll();
|
||||
void sortItems();
|
||||
void sortItems(bool (*cmp)(Widget* a, Widget* b));
|
||||
|
||||
obs::signal<void()> Change;
|
||||
obs::signal<void()> DoubleClickItem;
|
||||
|
Loading…
Reference in New Issue
Block a user