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