1 /*
2 Drawpile - a collaborative drawing program.
3
4 Copyright (C) 2014-2021 Calle Laakkonen
5
6 Drawpile is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Drawpile is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Drawpile. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "inputpresetmodel.h"
20 #include "../../libshared/util/ulid.h"
21
22 namespace input {
23
PresetModel(QObject * parent)24 PresetModel::PresetModel(QObject *parent) :
25 QAbstractListModel{parent},
26 m_presets{}
27 {
28 }
29
getSharedInstance()30 PresetModel *PresetModel::getSharedInstance()
31 {
32 static PresetModel *instance;
33 if(!instance) {
34 instance = new PresetModel;
35 instance->restoreSettings();
36 }
37 return instance;
38 }
39
rowCount(const QModelIndex & parent) const40 int PresetModel::rowCount(const QModelIndex &parent) const
41 {
42 return parent.isValid() ? 0 : m_presets.size();
43 }
44
data(const QModelIndex & index,int role) const45 QVariant PresetModel::data(const QModelIndex &index, int role) const
46 {
47 if(index.isValid() && index.row() >= 0 && index.row() < m_presets.size()) {
48 switch(role) {
49 case Qt::DisplayRole:
50 case Qt::EditRole:
51 return m_presets.at(index.row()).name;
52 }
53 }
54 return QVariant();
55 }
56
setData(const QModelIndex & index,const QVariant & value,int role)57 bool PresetModel::setData(const QModelIndex &index, const QVariant &value, int role)
58 {
59 if(role==Qt::EditRole && index.isValid() && index.row() >= 0 && index.row() < m_presets.size()) {
60 const QString newname = value.toString().trimmed();
61
62 if(!newname.isEmpty()) {
63 auto &p = m_presets[index.row()];
64 if(p.name != newname) {
65 p.name = newname;
66 emit dataChanged(index, index);
67 return true;
68 }
69 }
70 }
71
72 return false;
73 }
74
flags(const QModelIndex & index) const75 Qt::ItemFlags PresetModel::flags(const QModelIndex &index) const
76 {
77 Qt::ItemFlags f = Qt::NoItemFlags;
78 if(index.isValid() && index.row() >= 0 && index.row() < m_presets.size()) {
79 f = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
80 }
81
82 return f;
83 }
84
removeRows(int row,int count,const QModelIndex & parent)85 bool PresetModel::removeRows(int row, int count, const QModelIndex &parent)
86 {
87 if(parent.isValid() || row < 0 || row+count > m_presets.size())
88 return false;
89
90 beginRemoveRows(parent, row, row+count-1);
91 m_presets.remove(row, count);
92 endRemoveRows();
93 return true;
94 }
95
at(int i) const96 const Preset *PresetModel::at(int i) const
97 {
98 return i >= 0 && i < m_presets.size() ? &m_presets.at(i) : nullptr;
99 }
100
searchIndexById(const QString & id) const101 int PresetModel::searchIndexById(const QString &id) const
102 {
103 for(int i = 0; i < m_presets.size(); ++i) {
104 if(m_presets.at(i).id == id) {
105 return i;
106 }
107 }
108 return -1;
109 }
110
searchPresetById(const QString & id) const111 const Preset *PresetModel::searchPresetById(const QString &id) const
112 {
113 const int i = searchIndexById(id);
114 return i >= 0 ? &m_presets.at(i) : nullptr;
115 }
116
117
add(const Preset & preset)118 void PresetModel::add(const Preset &preset)
119 {
120 int size = m_presets.size();
121 beginInsertRows(QModelIndex{}, size, size);
122 m_presets.append(preset);
123 if(preset.id.isEmpty())
124 m_presets.last().id = Ulid::make().toString();
125 endInsertRows();
126 }
127
update(int index,const Preset & preset)128 void PresetModel::update(int index, const Preset &preset)
129 {
130 if(index < 0 || index >= m_presets.size())
131 return;
132
133 m_presets[index] = preset;
134 const QModelIndex idx = this->index(index);
135 emit dataChanged(idx, idx);
136 emit presetChanged(preset.id);
137 }
138
restoreSettings()139 void PresetModel::restoreSettings()
140 {
141 beginResetModel();
142 QSettings cfg;
143 const int size = cfg.beginReadArray("inputpresets");
144 m_presets.resize(size);
145 for(int i = 0; i < size; ++i) {
146 cfg.setArrayIndex(i);
147 m_presets[i] = Preset::loadFromSettings(cfg);
148 }
149 cfg.endArray();
150
151 if (m_presets.isEmpty()) {
152 m_presets
153 << Preset {
154 Ulid::make().toString(),
155 "Stylus",
156 8,
157 PressureMapping {
158 PressureMapping::STYLUS,
159 KisCubicCurve(),
160 1.0
161 }
162 }
163 << Preset {
164 Ulid::make().toString(),
165 "Distance",
166 8,
167 PressureMapping {
168 PressureMapping::DISTANCE,
169 KisCubicCurve(),
170 1.0
171 }
172 }
173 << Preset {
174 Ulid::make().toString(),
175 "Velocity",
176 8,
177 PressureMapping {
178 PressureMapping::VELOCITY,
179 KisCubicCurve(),
180 1.0
181 }
182 };
183 }
184
185 endResetModel();
186 }
187
saveSettings()188 void PresetModel::saveSettings()
189 {
190 QSettings cfg;
191
192 const int size = m_presets.size();
193 cfg.beginWriteArray("inputpresets", size);
194 for(int i = 0; i < size; ++i) {
195 cfg.setArrayIndex(i);
196 m_presets.at(i).saveToSettings(cfg);
197 }
198 cfg.endArray();
199 }
200
201
loadFromSettings(const QSettings & cfg)202 Preset Preset::loadFromSettings(const QSettings &cfg)
203 {
204 Preset p;
205 p.id = cfg.value("id").toString();
206 if(p.id.isEmpty())
207 p.id = Ulid::make().toString();
208 p.name = cfg.value("name").toString();
209 p.smoothing = cfg.value("smoothing").toInt();
210 p.curve.mode = PressureMapping::Mode(cfg.value("mode").toInt());
211 p.curve.param = cfg.value("param").toReal();
212 p.curve.curve.fromString(cfg.value("curve").toString());
213 return p;
214 }
215
saveToSettings(QSettings & cfg) const216 void Preset::saveToSettings(QSettings &cfg) const
217 {
218 cfg.setValue("id", id);
219 cfg.setValue("name", name);
220 cfg.setValue("smoothing", smoothing);
221 cfg.setValue("mode", curve.mode);
222 cfg.setValue("param", curve.param);
223 cfg.setValue("curve", curve.curve.toString());
224 }
225
226 }
227