1 // Aseprite
2 // Copyright (C) 2001-2018 David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include "app/doc.h"
12 #include "app/ini_file.h"
13 #include "app/pref/preferences.h"
14 #include "app/resource_finder.h"
15 #include "app/tools/ink.h"
16 #include "app/tools/tool.h"
17 #include "doc/sprite.h"
18 #include "she/system.h"
19
20 namespace app {
21
22 static Preferences* singleton = nullptr;
23
24 // static
instance()25 Preferences& Preferences::instance()
26 {
27 ASSERT(singleton);
28 return *singleton;
29 }
30
Preferences()31 Preferences::Preferences()
32 : app::gen::GlobalPref("")
33 {
34 ASSERT(!singleton);
35 singleton = this;
36
37 load();
38
39 // Hide the menu bar depending on:
40 // 1. the native menu bar is available
41 // 2. this is the first run of the program
42 if (she::instance()->menus() &&
43 updater.uuid().empty()) {
44 general.showMenuBar(false);
45 }
46 }
47
~Preferences()48 Preferences::~Preferences()
49 {
50 save();
51
52 for (auto& pair : m_tools)
53 delete pair.second;
54
55 for (auto& pair : m_docs)
56 delete pair.second;
57
58 ASSERT(singleton == this);
59 singleton = nullptr;
60 }
61
load()62 void Preferences::load()
63 {
64 app::gen::GlobalPref::load();
65 }
66
save()67 void Preferences::save()
68 {
69 app::gen::GlobalPref::save();
70
71 for (auto& pair : m_tools)
72 pair.second->save();
73
74 for (auto& pair : m_docs)
75 serializeDocPref(pair.first, pair.second, true);
76
77 flush_config_file();
78 }
79
isSet(OptionBase & opt) const80 bool Preferences::isSet(OptionBase& opt) const
81 {
82 return (get_config_string(opt.section(), opt.id(), nullptr) != nullptr);
83 }
84
tool(tools::Tool * tool)85 ToolPreferences& Preferences::tool(tools::Tool* tool)
86 {
87 ASSERT(tool != NULL);
88
89 auto it = m_tools.find(tool->getId());
90 if (it != m_tools.end()) {
91 return *it->second;
92 }
93 else {
94 std::string section = std::string("tool.") + tool->getId();
95 ToolPreferences* toolPref = new ToolPreferences(section);
96
97 // Default size for eraser, blur, etc.
98 if (tool->getInk(0)->isEraser() ||
99 tool->getInk(0)->isEffect()) {
100 toolPref->brush.size.setDefaultValue(8);
101 }
102
103 m_tools[tool->getId()] = toolPref;
104 toolPref->load();
105 return *toolPref;
106 }
107 }
108
document(const Doc * doc)109 DocumentPreferences& Preferences::document(const Doc* doc)
110 {
111 auto it = m_docs.find(doc);
112 if (it != m_docs.end()) {
113 return *it->second;
114 }
115 else {
116 DocumentPreferences* docPref;
117 if (doc) {
118 docPref = new DocumentPreferences("");
119
120 // The default preferences for this document are the current
121 // defaults for (document=nullptr).
122 DocumentPreferences& defPref = this->document(nullptr);
123 *docPref = defPref;
124
125 // Default values for symmetry
126 docPref->symmetry.xAxis.setDefaultValue(doc->sprite()->width()/2);
127 docPref->symmetry.yAxis.setDefaultValue(doc->sprite()->height()/2);
128 }
129 else
130 docPref = new DocumentPreferences("");
131
132 m_docs[doc] = docPref;
133
134 // Load document preferences
135 serializeDocPref(doc, docPref, false);
136
137 return *docPref;
138 }
139 }
140
removeDocument(Doc * doc)141 void Preferences::removeDocument(Doc* doc)
142 {
143 ASSERT(doc);
144
145 auto it = m_docs.find(doc);
146 if (it != m_docs.end()) {
147 serializeDocPref(it->first, it->second, true);
148 delete it->second;
149 m_docs.erase(it);
150 }
151 }
152
onRemoveDocument(Doc * doc)153 void Preferences::onRemoveDocument(Doc* doc)
154 {
155 removeDocument(doc);
156 }
157
docConfigFileName(const Doc * doc)158 std::string Preferences::docConfigFileName(const Doc* doc)
159 {
160 if (!doc)
161 return "";
162
163 ResourceFinder rf;
164 std::string fn = doc->filename();
165 for (size_t i=0; i<fn.size(); ++i) {
166 if (fn[i] == ' ' || fn[i] == '/' || fn[i] == '\\' || fn[i] == ':' || fn[i] == '.') {
167 fn[i] = '-';
168 }
169 }
170 rf.includeUserDir(("files/" + fn + ".ini").c_str());
171 return rf.getFirstOrCreateDefault();
172 }
173
serializeDocPref(const Doc * doc,app::DocumentPreferences * docPref,bool save)174 void Preferences::serializeDocPref(const Doc* doc, app::DocumentPreferences* docPref, bool save)
175 {
176 bool flush_config = false;
177
178 if (doc) {
179 // We do nothing if the document isn't associated to a file and we
180 // want to save its specific preferences.
181 if (save && !doc->isAssociatedToFile())
182 return;
183
184 // We always push a new configuration file in the stack to avoid
185 // modifying the default preferences when a document in "doc" is
186 // specified.
187 push_config_state();
188 if (doc->isAssociatedToFile()) {
189 set_config_file(docConfigFileName(doc).c_str());
190 flush_config = true;
191 }
192 }
193
194 if (save) {
195 docPref->save();
196 }
197 else {
198 // Load default preferences, or preferences from .ini file.
199 docPref->load();
200 }
201
202 if (doc) {
203 if (flush_config)
204 flush_config_file();
205
206 pop_config_state();
207 }
208 }
209
210 } // namespace app
211