Shox extensions in different categories in the Preferences dialog

This commit is contained in:
David Capello 2020-04-20 14:20:07 -03:00
parent ff3e9504fd
commit 5affdbbae1
6 changed files with 154 additions and 12 deletions

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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;