00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "paragui.h"
00030 #include "pgcolor.h"
00031
00032 #include "theme_priv.h"
00033 #include "pglog.h"
00034 #include "pgfilearchive.h"
00035 #include "pgdraw.h"
00036
00037 #include <string>
00038 #include <expat.h>
00039 #include <iostream>
00040
00041
00042 #ifdef XML_UNICODE
00043 #ifndef XML_UNICODE_WCHAR_T
00044 #error UNICODE version requires a 16-bit Unicode-compatible wchar_t=20
00045 #endif
00046 #define T(x) L ## x
00047 #define tcscmp wcscmp
00048 #else
00049 #define T(x) x
00050 #define tcscmp strcmp
00051 #endif
00052
00053 typedef struct _PARSE_INFO {
00054 int depth;
00055 int mode;
00056 THEME_THEME* theme;
00057 std::string str_currentWidget;
00058 std::string str_currentObject;
00059 THEME_WIDGET* p_currentWidget;
00060 THEME_OBJECT* p_currentObject;
00061 std::string themename;
00062 }
00063 PARSE_INFO;
00064
00065
00066 #define THEMEMODE_NONE 0
00067 #define THEMEMODE_THEME 1
00068 #define THEMEMODE_WIDGET 2
00069 #define THEMEMODE_OBJECT 3
00070
00071 #define THEME_SUFFIX ".theme"
00072
00073 #define BUFFSIZE 8192
00074
00075 static char* buff;
00076
00077 void parseGlobProps(PARSE_INFO* info, const XML_Char* name, const XML_Char** atts) {
00078
00079 if(strcmp(name, "theme") == 0) {
00080
00081 info->theme = new THEME_THEME;
00082 } else {
00083 std::cerr << "UNKNOWN PROP: " << name << std::endl;
00084 }
00085 }
00086
00087 void parseThemeProps(PARSE_INFO* info, const XML_Char* prop, const XML_Char** atts) {
00088 const XML_Char* val = atts[1];
00089 int i=0;
00090
00091 if(tcscmp(T(prop), T("title")) == 0) {
00092 info->theme->title = val;
00093 } else if (tcscmp(T(prop), T("description")) == 0) {
00094 info->theme->description = val;
00095 } else if (tcscmp(T(prop), T("author")) == 0) {
00096 info->theme->author = val;
00097 } else if (tcscmp(T(prop), T("email")) == 0) {
00098 info->theme->email = val;
00099 } else if (tcscmp(T(prop), T("widget")) == 0) {
00100 THEME_WIDGET* widget = new THEME_WIDGET;
00101 widget->type = "";
00102 info->p_currentWidget = widget;
00103 info->mode = THEMEMODE_WIDGET;
00104 } else if(tcscmp(T(prop), T("font")) == 0) {
00105 THEME_FONT* font = new THEME_FONT;
00106 font->size = 14;
00107
00108 for(i=0; atts[i]; i += 2) {
00109 if(tcscmp(T(atts[i]), T("name")) == 0) {
00110 font->name = atts[i+1];
00111 } else if(tcscmp(T(atts[i]), T("value")) == 0) {
00112 font->value = atts[i+1];
00113 } else if(tcscmp(T(atts[i]), T("size")) == 0) {
00114 font->size = atoi(atts[i+1]);
00115 } else {
00116 std::cerr << "UNKNOWN FONT ATTRIBUTE: " << atts[i] << std::endl;
00117 }
00118 }
00119
00120 info->theme->defaultfont = font;
00121 } else {
00122 std::cerr << "UNKNOWN THEME ATTRIBUTE: " << prop << std::endl;
00123 }
00124
00125 }
00126
00127 void parseWidgetProps(PARSE_INFO* info, const XML_Char* prop, const XML_Char** atts) {
00128 std::string val=atts[1];
00129
00130 if(tcscmp(T(prop), T("type")) == 0) {
00131 info->p_currentWidget->type = val;
00132 info->theme->widget[val] = info->p_currentWidget;
00133 } else if(tcscmp(T(prop), T("object")) == 0) {
00134 THEME_OBJECT* object = new THEME_OBJECT;
00135 object->type = "";
00136 object->name = "";
00137 info->p_currentObject = object;
00138 info->mode = THEMEMODE_OBJECT;
00139 } else {
00140 std::cerr << "UNKNOWN WIDGET ATTRIBUTE: " << prop << std::endl;
00141 }
00142 }
00143
00144 void parseObjectProps(PARSE_INFO* info, const XML_Char* prop, const XML_Char** atts) {
00145 std::string val=atts[1];
00146 int i;
00147 THEME_OBJECT* object = info->p_currentObject;
00148
00149
00150
00151
00152
00153 if(tcscmp(T(prop), T("type")) == 0) {
00154 object->type = val;
00155 }
00156
00157
00158
00159
00160
00161 else if(tcscmp(T(prop), T("name")) == 0) {
00162 object->name = val;
00163 info->p_currentWidget->object[object->name] = object;
00164 }
00165
00166
00167
00168
00169
00170 else if(tcscmp(T(prop), T("filename")) == 0) {
00171 THEME_FILENAME* filename = new THEME_FILENAME;
00172 filename->hasColorKey = false;
00173
00174 for(i=0; atts[i]; i += 2) {
00175 if(tcscmp(T(atts[i]), T("name")) == 0) {
00176 filename->name = atts[i+1];
00177 } else if(tcscmp(T(atts[i]), T("value")) == 0) {
00178 filename->value = atts[i+1];
00179 } else if(tcscmp(T(atts[i]), T("colorkey")) == 0) {
00180 sscanf(atts[i+1], "0x%08x", (unsigned int*)(&filename->colorkey));
00181 filename->hasColorKey = true;
00182 } else {
00183 std::cerr << "UNKNOWN FILENAME ATTRIBUTE: " << atts[i] << std::endl;
00184 }
00185 }
00186
00187
00188 filename->surface = PG_FileArchive::LoadSurface(filename->value, true);
00189
00190 if(filename->surface == NULL) {
00191 delete filename;
00192 return;
00193 }
00194
00195
00196 if(filename->hasColorKey && filename->surface) {
00197 PG_Color c = filename->colorkey;
00198 Uint32 key = c.MapRGB(filename->surface->format);
00199 SDL_SetColorKey(filename->surface, SDL_SRCCOLORKEY, key);
00200 }
00201 object->filename[filename->name] = filename;
00202 }
00203
00204
00205
00206
00207
00208 else if(tcscmp(T(prop), T("font")) == 0) {
00209 THEME_FONT* font = new THEME_FONT;
00210 font->size = 14;
00211
00212 for(i=0; atts[i]; i += 2) {
00213 if(tcscmp(T(atts[i]), T("name")) == 0) {
00214 font->name = atts[i+1];
00215 } else if(tcscmp(T(atts[i]), T("value")) == 0) {
00216 font->name = atts[i+1];
00217 font->value = atts[i+1];
00218 } else if(tcscmp(T(atts[i]), T("size")) == 0) {
00219 font->size = atoi(atts[i+1]);
00220 } else {
00221 std::cerr << "UNKNOWN FONT ATTRIBUTE: " << atts[i] << std::endl;
00222 }
00223 }
00224
00225 object->font = font;
00226 }
00227
00228
00229
00230
00231
00232 else if(tcscmp(T(prop), T("property")) == 0) {
00233 THEME_PROPERTY* property = new THEME_PROPERTY;
00234
00235 for(i=0; atts[i]; i += 2) {
00236 if(tcscmp(T(atts[i]), T("name")) == 0) {
00237 property->name = atts[i+1];
00238 } else if(tcscmp(T(atts[i]), T("value")) == 0) {
00239 if(tcscmp(T(atts[i+1]), T("TILE")) == 0) {
00240 property->value = PG_Draw::TILE;
00241 } else if(tcscmp(T(atts[i+1]), T("STRETCH")) == 0) {
00242 property->value = PG_Draw::STRETCH;
00243 } else if(tcscmp(T(atts[i+1]), T("3TILEH")) == 0) {
00244 property->value = PG_Draw::TILE3H;
00245 } else if(tcscmp(T(atts[i+1]), T("3TILEV")) == 0) {
00246 property->value = PG_Draw::TILE3V;
00247 } else if(tcscmp(T(atts[i+1]), T("9TILE")) == 0) {
00248 property->value = PG_Draw::TILE9;
00249 } else {
00250 property->value = atoi(atts[i+1]);
00251 }
00252 } else {
00253 std::cerr << "UNKNOWN PROPERTY ATTRIBUTE: " << atts[i] << std::endl;
00254 }
00255 }
00256 object->property[property->name] = property;
00257 }
00258
00259
00260
00261
00262
00263 else if(tcscmp(T(prop), T("color")) == 0) {
00264 THEME_PROPERTY* property = new THEME_PROPERTY;
00265
00266 for(i=0; atts[i]; i += 2) {
00267 if(tcscmp(T(atts[i]), T("name")) == 0) {
00268 property->name = atts[i+1];
00269 } else if(tcscmp(T(atts[i]), T("value")) == 0) {
00270 unsigned int value;
00271 sscanf(atts[i+1], "0x%08x", &value);
00272 property->value = value;
00273 } else {
00274 std::cerr << "UNKNOWN COLOR ATTRIBUTE: " << atts[i] << std::endl;
00275 }
00276 }
00277 object->property[property->name] = property;
00278 }
00279
00280
00281
00282
00283
00284 else if(tcscmp(T(prop), T("gradient")) == 0) {
00285 THEME_GRADIENT* gradient = new THEME_GRADIENT;
00286 Uint32 c;
00287 std::string val;
00288
00289 for(i=0; atts[i]; i += 2) {
00290
00291 if(tcscmp(T(atts[i]), T("name")) == 0) {
00292 gradient->name = atts[i+1];
00293 } else if(tcscmp(T(atts[i]), T("color0")) == 0) {
00294 val = atts[i+1];
00295 sscanf(val.c_str(), "0x%08x", &c);
00296 gradient->colors[0] = c;
00297 } else if(tcscmp(T(atts[i]), T("color1")) == 0) {
00298 val = atts[i+1];
00299 sscanf(val.c_str(), "0x%08x", &c);
00300 gradient->colors[1] = c;
00301 } else if(tcscmp(T(atts[i]), T("color2")) == 0) {
00302 val = atts[i+1];
00303 sscanf(val.c_str(), "0x%08x", &c);
00304 gradient->colors[2] = c;
00305 } else if(tcscmp(T(atts[i]), T("color3")) == 0) {
00306 val = atts[i+1];
00307 sscanf(val.c_str(), "0x%08x", &c);
00308 gradient->colors[3] = c;
00309 } else {
00310 std::cerr << "UNKNOWN PROPERTY ATTRIBUTE: " << atts[i] << std::endl;
00311 }
00312 }
00313
00314
00315
00316
00317
00318 object->gradient[gradient->name] = gradient;
00319 }
00320
00321
00322
00323
00324 else if(tcscmp(T(prop), T("string")) == 0) {
00325 THEME_STRING* str = new THEME_STRING;
00326
00327 for(i=0; atts[i]; i += 2) {
00328
00329 if(tcscmp(T(atts[i]), T("name")) == 0) {
00330 str->name = atts[i+1];
00331 } else if(tcscmp(T(atts[i]), T("value")) == 0) {
00332 str->value = atts[i+1];
00333 } else {
00334 std::cerr << "UNKNOWN STRING ATTRIBUTE: " << atts[i] << std::endl;
00335 }
00336 }
00337
00338 object->strings.insert(info->p_currentObject->strings.end(), str);
00339 }
00340
00341
00342
00343
00344
00345 else {
00346 std::cerr << "UNKNOWN OBJECT ATTRIBUTE: " << prop << std::endl;
00347 }
00348 }
00349
00350
00351 void handlerStart(void* userData, const XML_Char *name, const XML_Char** atts) {
00352 PARSE_INFO* info = (PARSE_INFO*)userData;
00353
00354 info->depth++;
00355
00356 switch(info->mode) {
00357 case THEMEMODE_NONE:
00358 parseGlobProps(info, name, atts);
00359 info->mode = THEMEMODE_THEME;
00360 break;
00361
00362 case THEMEMODE_THEME:
00363 parseThemeProps(info, name, atts);
00364 break;
00365
00366 case THEMEMODE_WIDGET:
00367 parseWidgetProps(info, name, atts);
00368 break;
00369
00370 case THEMEMODE_OBJECT:
00371 parseObjectProps(info, name, atts);
00372 break;
00373 }
00374 }
00375
00376 void handlerEnd(void* userData, const XML_Char* name) {
00377 PARSE_INFO* info = (PARSE_INFO*)userData;
00378
00379 if(tcscmp(T(name), T("object")) == 0) {
00380 info->mode = THEMEMODE_WIDGET;
00381 } else if(tcscmp(T(name), T("widget")) == 0) {
00382 info->mode = THEMEMODE_THEME;
00383 } else if(tcscmp(T(name), T("theme")) == 0) {
00384 info->mode = THEMEMODE_NONE;
00385 }
00386
00387 info->depth--;
00388 }
00389
00390 PG_Theme* PG_Theme::Load(const std::string& xmltheme) {
00391 std::string filename;
00392 buff = new char[BUFFSIZE];
00393
00394
00395 PARSE_INFO info;
00396
00397
00398 info.theme = NULL;
00399 info.p_currentWidget = NULL;
00400 info.p_currentObject = NULL;
00401 info.depth = 0;
00402 info.mode = THEMEMODE_NONE;
00403
00404 filename = xmltheme;
00405
00406
00407 filename = xmltheme + ".zip";
00408
00409
00410 if(PG_FileArchive::Exists(filename)) {
00411 const char* path = PG_FileArchive::GetRealDir(filename);
00412 char sep = PG_FileArchive::GetDirSeparator()[0];
00413
00414 std::string fullpath = (std::string)path;
00415 if(fullpath[fullpath.size()-1] != sep) {
00416 fullpath += sep;
00417 }
00418 fullpath += filename;
00419
00420 bool rc = PG_FileArchive::AddArchive(fullpath);
00421 if(rc) {
00422 PG_LogMSG("added '%s' to the searchpath", fullpath.c_str());
00423 } else {
00424 PG_LogWRN("failed to add '%s'", fullpath.c_str());
00425 PG_LogWRN("%s", PG_FileArchive::GetLastError());
00426 }
00427 }
00428
00429
00430
00431 filename = xmltheme + THEME_SUFFIX;
00432 if(!PG_FileArchive::Exists(filename)) {
00433 PG_LogERR("theme '%s' not found !", filename.c_str());
00434 return NULL;
00435 }
00436
00437 info.themename = xmltheme;
00438
00439
00440 XML_Parser p = XML_ParserCreate(NULL);
00441
00442
00443 XML_SetUserData(p, (void*)&info);
00444 XML_SetElementHandler(p, handlerStart, handlerEnd);
00445
00446
00447
00448 PG_File* file = PG_FileArchive::OpenFile(filename);
00449
00450 if(!file) {
00451 XML_ParserFree(p);
00452 delete[] buff;
00453 return NULL;
00454 }
00455
00456
00457 while (!file->eof()) {
00458 int done;
00459
00460 int n = file->read(buff, BUFFSIZE);
00461 done = file->eof();
00462
00463 if (! XML_Parse(p, buff, n, done)) {
00464 PG_LogERR("Parse error at line %i:", XML_GetCurrentLineNumber(p));
00465 PG_LogERR("%s", XML_ErrorString(XML_GetErrorCode(p)));
00466 XML_ParserFree(p);
00467 delete[] buff;
00468 return NULL;
00469 }
00470
00471 if(done) {
00472 break;
00473 }
00474 }
00475
00476
00477 XML_ParserFree(p);
00478
00479
00480 delete file;
00481 delete[] buff;
00482
00483 PG_LogMSG("theme '%s' loaded sucessfully", filename.c_str());
00484
00485 return info.theme;
00486 }
00487
00488 void PG_Theme::Unload(PG_Theme* theme) {
00489 delete theme;
00490 }