1 /** @file
2 * @brief EGE paint definition
3 */
4 /* ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is Eek Color Definition.
18 *
19 * The Initial Developer of the Original Code is
20 * Jon A. Cruz.
21 * Portions created by the Initial Developer are Copyright (C) 2006
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
40 #include "config.h"
42 #ifdef HAVE_LIBINTL_H
43 #include <libintl.h>
44 #endif
46 #include <stdint.h>
47 #include <string>
48 #include <iostream>
49 #include <sstream>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <stdio.h>
54 #if !defined(_)
55 #define _(s) gettext(s)
56 #endif // !defined(_)
58 #include "ege-paint-def.h"
60 namespace ege
61 {
63 static std::string mimeTEXT("text/plain");
64 static std::string mimeX_COLOR("application/x-color");
65 static std::string mimeOSWB_COLOR("application/x-oswb-color");
67 static std::string doubleToStr(double d);
69 PaintDef::PaintDef() :
70 descr(_("none")),
71 type(NONE),
72 r(0),
73 g(0),
74 b(0),
75 editable(false)
76 {
77 }
79 PaintDef::PaintDef( ColorType type ) :
80 descr(),
81 type(type),
82 r(0),
83 g(0),
84 b(0),
85 editable(false)
86 {
87 switch (type) {
88 case CLEAR:
89 descr = _("remove");
90 break;
91 case NONE:
92 descr = _("none");
93 break;
94 case RGB:
95 descr = "";
96 break;
97 }
98 }
100 PaintDef::PaintDef( unsigned int r, unsigned int g, unsigned int b, const std::string& description ) :
101 descr(description),
102 type(RGB),
103 r(r),
104 g(g),
105 b(b),
106 editable(false)
107 {
108 }
110 PaintDef::~PaintDef()
111 {
112 }
114 PaintDef::PaintDef( PaintDef const &other )
115 {
116 if ( this != &other ) {
117 *this = other;
118 }
119 }
121 PaintDef& PaintDef::operator=( PaintDef const &other )
122 {
123 if ( this != & other )
124 {
125 type = other.type;
126 r = other.r;
127 g = other.g;
128 b = other.b;
129 descr = other.descr;
130 editable = other.editable;
131 }
132 return *this;
133 }
135 class PaintDef::HookData {
136 public:
137 HookData( ColorCallback cb, void* data ) {_cb = cb; _data = data;}
138 ColorCallback _cb;
139 void* _data;
140 };
143 std::vector<std::string> PaintDef::getMIMETypes()
144 {
145 std::vector<std::string> listing;
146 listing.push_back(mimeOSWB_COLOR);
147 listing.push_back(mimeX_COLOR);
148 listing.push_back(mimeTEXT);
149 return listing;
150 }
152 void PaintDef::getMIMEData(std::string const & type, char*& dest, int& len, int& format)
153 {
154 if ( type == mimeTEXT ) {
155 dest = new char[8];
156 snprintf( dest, 8, "#%02x%02x%02x", getR(), getG(), getB() );
157 dest[7] = 0;
158 len = 8;
159 format = 8;
160 } else if ( type == mimeX_COLOR ) {
161 uint16_t* tmp = new uint16_t[4];
162 tmp[0] = (getR() << 8) | getR();
163 tmp[1] = (getG() << 8) | getG();
164 tmp[2] = (getB() << 8) | getB();
165 tmp[3] = 0xffff;
166 dest = reinterpret_cast<char*>(tmp);
167 len = 8;
168 format = 16;
169 } else if ( type == mimeOSWB_COLOR ) {
170 std::string tmp("<paint>");
171 switch ( getType() ) {
172 case ege::PaintDef::NONE:
173 {
174 tmp += "<nocolor/>";
175 }
176 break;
177 case ege::PaintDef::CLEAR:
178 {
179 tmp += "<clear/>";
180 }
181 break;
182 default:
183 {
184 tmp += std::string("<color name=\"") + descr + "\">";
185 tmp += "<sRGB r=\"";
186 tmp += doubleToStr(getR()/255.0);
187 tmp += "\" g=\"";
188 tmp += doubleToStr(getG()/255.0);
189 tmp += "\" b=\"";
190 tmp += doubleToStr(getB()/255.0);
191 tmp += "\"/>";
192 tmp += "</color>";
193 }
194 }
195 tmp += "</paint>";
196 len = tmp.size();
197 dest = new char[len];
198 // Note that this is not null-terminated:
199 memcpy(dest, tmp.c_str(), len);
200 format = 8;
201 } else {
202 // nothing
203 dest = 0;
204 len = 0;
205 }
206 }
208 bool PaintDef::fromMIMEData(std::string const & type, char const * data, int len, int /*format*/)
209 {
210 bool worked = false;
211 bool changed = false;
212 if ( type == mimeTEXT ) {
213 } else if ( type == mimeX_COLOR ) {
214 } else if ( type == mimeOSWB_COLOR ) {
215 std::string xml(data, len);
216 if ( xml.find("<nocolor/>") != std::string::npos ) {
217 if ( (this->type != ege::PaintDef::NONE)
218 || (this->r != 0)
219 || (this->g != 0)
220 || (this->b != 0) ) {
221 this->type = ege::PaintDef::NONE;
222 this->r = 0;
223 this->g = 0;
224 this->b = 0;
225 changed = true;
226 }
227 worked = true;
228 } else {
229 size_t pos = xml.find("<sRGB");
230 if ( pos != std::string::npos ) {
231 size_t endPos = xml.find(">", pos);
232 std::string srgb = xml.substr(pos, endPos);
233 this->type = ege::PaintDef::RGB;
234 size_t numPos = srgb.find("r=");
235 if (numPos != std::string::npos) {
236 char* endPtr = 0;
237 double dbl = strtod(srgb.c_str() + numPos + 3, &endPtr);
238 this->r = static_cast<int>(255 * dbl);
239 }
240 numPos = srgb.find("g=");
241 if (numPos != std::string::npos) {
242 char* endPtr = 0;
243 double dbl = strtod(srgb.c_str() + numPos + 3, &endPtr);
244 this->g = static_cast<int>(255 * dbl);
245 }
246 numPos = srgb.find("b=");
247 if (numPos != std::string::npos) {
248 char* endPtr = 0;
249 double dbl = strtod(srgb.c_str() + numPos + 3, &endPtr);
250 this->b = static_cast<int>(255 * dbl);
251 }
253 size_t pos = xml.find("<color ");
254 if ( pos != std::string::npos ) {
255 size_t endPos = xml.find(">", pos);
256 std::string colorTag = xml.substr(pos, endPos);
258 size_t namePos = colorTag.find("name=");
259 if (namePos != std::string::npos) {
260 char quote = colorTag[namePos + 5];
261 endPos = colorTag.find(quote, namePos + 6);
262 descr = colorTag.substr(namePos + 6, endPos - (namePos + 6));
263 }
264 }
265 changed = true;
266 worked = true;
267 }
268 }
269 }
270 if ( changed ) {
271 // beware of callbacks changing things
272 for ( std::vector<HookData*>::iterator it = _listeners.begin(); it != _listeners.end(); ++it )
273 {
274 if ( (*it)->_cb )
275 {
276 (*it)->_cb( (*it)->_data );
277 }
278 }
279 }
280 return worked;
281 }
283 void PaintDef::setRGB( unsigned int r, unsigned int g, unsigned int b )
284 {
285 if ( r != this->r || g != this->g || b != this->b ) {
286 this->r = r;
287 this->g = g;
288 this->b = b;
290 // beware of callbacks changing things
291 for ( std::vector<HookData*>::iterator it = _listeners.begin(); it != _listeners.end(); ++it )
292 {
293 if ( (*it)->_cb )
294 {
295 (*it)->_cb( (*it)->_data );
296 }
297 }
298 }
299 }
301 void PaintDef::addCallback( ColorCallback cb, void* data )
302 {
303 _listeners.push_back( new HookData(cb, data) );
304 }
306 void PaintDef::removeCallback( ColorCallback /*cb*/, void* /*data*/ )
307 {
308 }
310 static std::string doubleToStr(double d)
311 {
312 // TODO ensure "." is used for decimal separator.
313 std::stringstream out;
314 out << d;
315 return out.str();
316 }
318 } // namespace ege
320 /*
321 Local Variables:
322 mode:c++
323 c-file-style:"stroustrup"
324 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
325 indent-tabs-mode:nil
326 fill-column:99
327 End:
328 */
329 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :