Prevent unsafe thread change of local settings using synfig::ChangeLocale class
[synfig.git] / synfig-studio / src / synfigapp / inputdevice.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file inputdevice.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "inputdevice.h"
33 #include "settings.h"
34 #include <cstdio>
35 #include <ETL/stringf>
36 #include "main.h"
37
38 #include "general.h"
39
40 #endif
41
42 /* === U S I N G =========================================================== */
43
44 using namespace std;
45 using namespace etl;
46 using namespace synfig;
47 using namespace synfigapp;
48
49 /* === M A C R O S ========================================================= */
50
51 /* === G L O B A L S ======================================================= */
52
53 class DeviceSettings : public Settings
54 {
55         InputDevice* input_device;
56 public:
57         DeviceSettings(InputDevice* input_device):
58                 input_device(input_device) { }
59
60
61         virtual bool get_value(const synfig::String& key, synfig::String& value)const
62         {
63                 try
64                 {
65                         synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
66                         if(key=="state")
67                         {
68                                 value=input_device->get_state();
69                                 return true;
70                         }
71                         if(key=="bline_width")
72                         {
73                                 value=strprintf("%s",input_device->get_bline_width().get_string().c_str());
74                                 return true;
75                         }
76                         if(key=="opacity")
77                         {
78                                 value=strprintf("%f",(float)input_device->get_opacity());
79                                 return true;
80                         }
81                         if(key=="blend_method")
82                         {
83                                 value=strprintf("%i",(int)input_device->get_blend_method());
84                                 return true;
85                         }
86                         if(key=="outline_color")
87                         {
88                                 Color c(input_device->get_outline_color());
89                                 value=strprintf("%f %f %f %f",(float)c.get_r(),(float)c.get_g(),(float)c.get_b(),(float)c.get_a());
90
91                                 return true;
92                         }
93                         if(key=="fill_color")
94                         {
95                                 Color c(input_device->get_fill_color());
96                                 value=strprintf("%f %f %f %f",(float)c.get_r(),(float)c.get_g(),(float)c.get_b(),(float)c.get_a());
97
98                                 return true;
99                         }
100                         if(key=="mode")
101                         {
102                                 get_mode_value(value);
103                                 return true;
104                         }
105                         if(key=="axes")
106                         {
107                                 get_axes_value(value);
108                                 return true;
109                         }
110                         if(key=="keys")
111                         {
112                                 get_keys_value(value);
113                                 return true;
114                         }
115                 }
116                 catch(...)
117                 {
118                         synfig::warning("DeviceSettings: Caught exception when attempting to get value.");
119                 }
120                 return Settings::get_value(key, value);
121         }
122
123         void get_mode_value(synfig::String & value) const
124         {
125                 if (input_device->get_mode() == InputDevice::MODE_SCREEN)
126                         value = "screen";
127                 else if (input_device->get_mode() == InputDevice::MODE_WINDOW)
128                         value = "window";
129                 else
130                         value = "disabled";
131         }
132
133         void get_axes_value(synfig::String & value) const
134         {
135                 vector<InputDevice::AxisUse> axes = input_device->get_axes();
136                 value = strprintf("%u", axes.size());
137                 vector<InputDevice::AxisUse>::const_iterator itr;
138                 for (itr = axes.begin(); itr != axes.end(); itr++)
139                         value += strprintf(" %u", (unsigned int) *itr);
140         }
141
142         void get_keys_value(synfig::String & value) const
143         {
144                 vector<InputDevice::DeviceKey> keys = input_device->get_keys();
145                 value = strprintf("%u", keys.size());
146                 vector<InputDevice::DeviceKey>::const_iterator itr;
147                 for (itr = keys.begin(); itr != keys.end(); itr++)
148                         value += strprintf(" %u %u", itr->keyval, itr->modifiers);
149         }
150
151         virtual bool set_value(const synfig::String& key,const synfig::String& value)
152         {
153                 try
154                 {
155                         synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
156                         if(key=="state")
157                         {
158                                 input_device->set_state(value);
159                                 return true;
160                         }
161                         if(key=="bline_width")
162                         {
163                                 input_device->set_bline_width(synfig::Distance(value));
164                                 return true;
165                         }
166                         if(key=="opacity")
167                         {
168                                 input_device->set_opacity(atof(value.c_str()));
169                                 return true;
170                         }
171                         if(key=="blend_method")
172                         {
173                                 input_device->set_blend_method(Color::BlendMethod(atoi(value.c_str())));
174                                 return true;
175                         }
176                         if(key=="outline_color")
177                         {
178                                 float r=0,g=0,b=0,a=1;
179                                 if(!strscanf(value,"%f %f %f %f",&r,&g,&b,&a))
180                                         return false;
181                                 input_device->set_outline_color(synfig::Color(r,g,b,a));
182                                 return true;
183                         }
184                         if(key=="fill_color")
185                         {
186                                 float r=0,g=0,b=0,a=1;
187                                 if(!strscanf(value,"%f %f %f %f",&r,&g,&b,&a))
188                                         return false;
189                                 input_device->set_fill_color(synfig::Color(r,g,b,a));
190                                 return true;
191                         }
192                         if(key=="mode")
193                         {
194                                 set_mode_value(value);
195                                 return true;
196                         }
197                         if(key=="axes")
198                         {
199                                 set_axes_value(value);
200                                 return true;
201                         }
202                         if(key=="keys")
203                         {
204                                 set_keys_value(value);
205                                 return true;
206                         }
207                 }
208                 catch(...)
209                 {
210                         synfig::warning("DeviceSettings: Caught exception when attempting to set value.");
211                 }
212                 return Settings::set_value(key, value);
213         }
214
215         void set_mode_value(const synfig::String & value)
216         {
217                 InputDevice::Mode mode;
218                 if (value == "screen")
219                         mode = InputDevice::MODE_SCREEN;
220                 else if (value == "window")
221                         mode = InputDevice::MODE_WINDOW;
222                 else
223                         mode = InputDevice::MODE_DISABLED;
224
225                 input_device->set_mode(mode);
226         }
227
228         void set_axes_value(const synfig::String & value)
229         {
230                 std::vector<InputDevice::AxisUse> axes;
231
232                 unsigned pos = value.find(' ', 0);
233                 if (pos < value.size()) {
234                         int num_axes = atoi(value.substr(0, pos).c_str());
235                         axes.resize(num_axes);
236
237                         for (int axis = 0; axis < num_axes; axis++) {
238                                 int last = pos;
239                                 pos = value.find(' ', pos + 1);
240                                 axes[axis] = InputDevice::AxisUse(atoi(value.substr(last, pos).c_str()));
241                         }
242                 }
243
244                 input_device->set_axes(axes);
245         }
246
247         void set_keys_value(const synfig::String & value)
248         {
249                 std::vector<InputDevice::DeviceKey> keys;
250
251                 unsigned pos = value.find(' ', 0);
252                 if (pos < value.size()) {
253                         int num_keys = atoi(value.substr(0, pos).c_str());
254                         keys.resize(num_keys);
255
256                         for (int key = 0; key < num_keys; key++) {
257                                 int last = pos;
258                                 pos = value.find(' ', pos + 1);
259                                 keys[key].keyval = (unsigned int) atol(value.substr(last, pos).c_str());
260                                 last = pos;
261                                 pos = value.find(' ', pos + 1);
262                                 keys[key].modifiers = (unsigned int) atol(value.substr(last, pos).c_str());
263                         }
264                 }
265
266                 input_device->set_keys(keys);
267         }
268
269         virtual KeyList get_key_list()const
270         {
271                 KeyList ret(Settings::get_key_list());
272                 ret.push_back("outline_color");
273                 ret.push_back("fill_color");
274                 ret.push_back("state");
275                 ret.push_back("bline_width");
276                 ret.push_back("blend_method");
277                 ret.push_back("opacity");
278                 ret.push_back("mode");
279                 ret.push_back("axes");
280                 ret.push_back("keys");
281                 return ret;
282         }
283 };
284
285 /* === P R O C E D U R E S ================================================= */
286
287 /* === M E T H O D S ======================================================= */
288
289 InputDevice::InputDevice(const synfig::String id_, Type type_):
290         id_(id_),
291         type_(type_),
292         state_((type_==TYPE_PEN)?"draw":"normal"),
293         outline_color_(Color::black()),
294         fill_color_(Color::white()),
295         bline_width_(Distance(1,Distance::SYSTEM_POINTS)),
296         opacity_(1.0f),
297         blend_method_(Color::BLEND_BY_LAYER),
298         mode_(MODE_DISABLED)
299 {
300         device_settings=new DeviceSettings(this);
301         Main::settings().add_domain(device_settings,"input_device."+id_);
302 }
303
304 InputDevice::~InputDevice()
305 {
306         Main::settings().remove_domain("input_device."+id_);
307         delete device_settings;
308 }
309
310 Settings&
311 InputDevice::settings()
312 {
313         return *device_settings;
314 }
315
316 const Settings&
317 InputDevice::settings()const
318 {
319         return *device_settings;
320 }