1// Aseprite
2// Copyright (C) 2020-2022 Igara Studio S.A.
3// Copyright (C) 2017-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifndef APP_EXTENSIONS_H_INCLUDED
9#define APP_EXTENSIONS_H_INCLUDED
10#pragma once
11
12#include "obs/signal.h"
13#include "render/dithering_matrix.h"
14
15#include <map>
16#include <string>
17#include <vector>
18
19namespace app {
20
21 // Key=id
22 // Value=path
23 using ExtensionItems = std::map<std::string, std::string>;
24
25 class Extensions;
26
27 struct ExtensionInfo {
28 std::string name;
29 std::string version;
30 std::string dstPath;
31 std::string commonPath;
32 };
33
34 enum DeletePluginPref { kNo, kYes };
35
36 class Extension {
37 friend class Extensions;
38 public:
39
40 enum class Category {
41 None,
42 Keys,
43 Languages,
44 Themes,
45 Scripts,
46 Palettes,
47 DitheringMatrices,
48 Multiple,
49 Max
50 };
51
52 class DitheringMatrixInfo {
53 public:
54 DitheringMatrixInfo();
55 DitheringMatrixInfo(const std::string& path,
56 const std::string& name);
57
58 const std::string& name() const { return m_name; }
59 const render::DitheringMatrix& matrix() const;
60
61 private:
62 std::string m_path;
63 std::string m_name;
64 mutable render::DitheringMatrix m_matrix;
65 mutable bool m_loaded = false;
66 };
67
68 struct ThemeInfo {
69 std::string path;
70 std::string variant;
71
72 ThemeInfo() = default;
73 ThemeInfo(const std::string& path,
74 const std::string& variant)
75 : path(path)
76 , variant(variant) { }
77 };
78
79 using Themes = std::map<std::string, ThemeInfo>;
80 using DitheringMatrices = std::map<std::string, DitheringMatrixInfo>;
81
82 Extension(const std::string& path,
83 const std::string& name,
84 const std::string& version,
85 const std::string& displayName,
86 const bool isEnabled,
87 const bool isBuiltinExtension);
88 ~Extension();
89
90 void executeInitActions();
91 void executeExitActions();
92
93 const std::string& path() const { return m_path; }
94 const std::string& name() const { return m_name; }
95 const std::string& version() const { return m_version; }
96 const std::string& displayName() const { return m_displayName; }
97 const Category category() const { return m_category; }
98
99 const ExtensionItems& keys() const { return m_keys; }
100 const ExtensionItems& languages() const { return m_languages; }
101 const Themes& themes() const { return m_themes; }
102 const ExtensionItems& palettes() const { return m_palettes; }
103
104 void addKeys(const std::string& id, const std::string& path);
105 void addLanguage(const std::string& id, const std::string& path);
106 void addTheme(const std::string& id, const std::string& path, const std::string& variant);
107 void addPalette(const std::string& id, const std::string& path);
108 void addDitheringMatrix(const std::string& id,
109 const std::string& path,
110 const std::string& name);
111#ifdef ENABLE_SCRIPTING
112 void addCommand(const std::string& id);
113 void removeCommand(const std::string& id);
114#endif
115
116 bool isEnabled() const { return m_isEnabled; }
117 bool isInstalled() const { return m_isInstalled; }
118 bool canBeDisabled() const;
119 bool canBeUninstalled() const;
120
121 bool hasKeys() const { return !m_keys.empty(); }
122 bool hasLanguages() const { return !m_languages.empty(); }
123 bool hasThemes() const { return !m_themes.empty(); }
124 bool hasPalettes() const { return !m_palettes.empty(); }
125 bool hasDitheringMatrices() const { return !m_ditheringMatrices.empty(); }
126#ifdef ENABLE_SCRIPTING
127 bool hasScripts() const { return !m_plugin.scripts.empty(); }
128 void addScript(const std::string& fn);
129#endif
130
131 bool isCurrentTheme() const;
132
133 private:
134 void enable(const bool state);
135 void uninstall(const DeletePluginPref delPref);
136 void uninstallFiles(const std::string& path,
137 const DeletePluginPref delPref);
138 bool isDefaultTheme() const;
139 void updateCategory(const Category newCategory);
140#ifdef ENABLE_SCRIPTING
141 void initScripts();
142 void exitScripts();
143#endif
144
145 ExtensionItems m_keys;
146 ExtensionItems m_languages;
147 Themes m_themes;
148 ExtensionItems m_palettes;
149 DitheringMatrices m_ditheringMatrices;
150
151#ifdef ENABLE_SCRIPTING
152 struct ScriptItem {
153 std::string fn;
154 int exitFunctionRef;
155 ScriptItem(const std::string& fn);
156 };
157 struct PluginItem {
158 enum Type { Command };
159 Type type;
160 std::string id;
161 };
162 struct Plugin {
163 int pluginRef;
164 std::vector<ScriptItem> scripts;
165 std::vector<PluginItem> items;
166 } m_plugin;
167#endif
168
169 std::string m_path;
170 std::string m_name;
171 std::string m_version;
172 std::string m_displayName;
173 Category m_category;
174 bool m_isEnabled;
175 bool m_isInstalled;
176 bool m_isBuiltinExtension;
177 };
178
179 class Extensions {
180 public:
181 typedef std::vector<Extension*> List;
182 typedef List::iterator iterator;
183
184 Extensions();
185 ~Extensions();
186
187 void executeInitActions();
188 void executeExitActions();
189
190 iterator begin() { return m_extensions.begin(); }
191 iterator end() { return m_extensions.end(); }
192
193 void enableExtension(Extension* extension, const bool state);
194 void uninstallExtension(Extension* extension,
195 const DeletePluginPref delPref);
196 ExtensionInfo getCompressedExtensionInfo(const std::string& zipFn);
197 Extension* installCompressedExtension(const std::string& zipFn,
198 const ExtensionInfo& info);
199
200 std::string languagePath(const std::string& langId);
201 std::string themePath(const std::string& themeId);
202 std::string palettePath(const std::string& palId);
203 ExtensionItems palettes() const;
204 const render::DitheringMatrix* ditheringMatrix(const std::string& matrixId);
205 std::vector<Extension::DitheringMatrixInfo> ditheringMatrices();
206
207 obs::signal<void(Extension*)> NewExtension;
208 obs::signal<void(Extension*)> KeysChange;
209 obs::signal<void(Extension*)> LanguagesChange;
210 obs::signal<void(Extension*)> ThemesChange;
211 obs::signal<void(Extension*)> PalettesChange;
212 obs::signal<void(Extension*)> DitheringMatricesChange;
213 obs::signal<void(Extension*)> ScriptsChange;
214
215 private:
216 Extension* loadExtension(const std::string& path,
217 const std::string& fullPackageFilename,
218 const bool isBuiltinExtension);
219 void generateExtensionSignals(Extension* extension);
220
221 List m_extensions;
222 std::string m_userExtensionsPath;
223 };
224
225} // namespace app
226
227#endif
228