5 #include <lib/gui/eskin.h>
6 #include <lib/gui/ewidget.h>
7 #include <lib/gdi/gfbdc.h>
8 #include <lib/gdi/glcddc.h>
9 #include <lib/gdi/epng.h>
10 #include <lib/base/eerror.h>
11 #include <lib/gdi/font.h>
12 #include <lib/base/eptrlist.h>
15 * Notes on images/colors:
17 * When loading images, the colors they use are parsed, and added to our palette.
18 * Because we only have room for 256 colors in our 8bit palette, we cannot simply
19 * allocate all required colors for every image.
20 * Therefore, only colors that are farther apart than a certain 'maxcolordistance',
21 * are added to the palette.
23 * Colors defined in the skin are always added to the palette first, and the remaining
24 * free slots in the palette are used for image colors.
25 * Images are parsed in the order in which they appear in the skin file, until
26 * the palette is completely filled.
28 * Skinmakers can influence color allocation in the following ways:
30 * -change the order in which the images are placed in the skin file
31 * -define a 'maxcolordistance' per image. When omitted, the maximum color distance
36 * -explicitly list all colors that need to be allocated
39 std::map
< eString
,tWidgetCreator
> eSkin::widget_creator
;
43 eNamedColor
*eSkin::searchColor(const eString
&name
)
45 for (std::list
<eNamedColor
>::iterator
i(colors
.begin()); i
!= colors
.end(); ++i
)
47 if (!i
->name
.compare(name
))
53 int eSkin::findColorDistance(const gRGB
&rgb
)
55 int difference
= 1 << 30;
56 for (int t
= 0; t
< maxcolors
; t
++)
58 if (!colorused
[t
]) break;
60 int td
= (signed)(rgb
.r
- palette
[t
].r
); td
*= td
; td
*= (255 - palette
[t
].a
);
62 if (ttd
>= difference
) continue;
63 td
= (signed)(rgb
.g
- palette
[t
].g
); td
*= td
; td
*= (255 - palette
[t
].a
);
65 if (ttd
>= difference
) continue;
66 td
= (signed)(rgb
.b
- palette
[t
].b
); td
*= td
; td
*= (255 - palette
[t
].a
);
68 if (ttd
>= difference
) continue;
69 td
= (signed)(rgb
.a
- palette
[t
].a
); td
*= td
; td
*= 255;
71 if (ttd
>= difference
) continue;
81 void eSkin::addWidgetCreator(const eString
&name
, tWidgetCreator creator
)
83 widget_creator
[name
] = creator
; // add this tWidgetCreator to map... if exist.. overwrite
86 void eSkin::removeWidgetCreator(const eString
&name
, tWidgetCreator creator
)
88 widget_creator
.erase(name
);
91 int eSkin::parseColor(const eString
&name
, const char* color
, gRGB
&col
)
96 if (sscanf(color
+1, "%lx", &vcol
)!=1)
98 eDebug("invalid color named \"%s\" (value: %s)", name
.c_str(), color
+1);
101 col
.r
=(vcol
>>16)&0xFF;
102 col
.g
=(vcol
>>8)&0xFF;
104 col
.a
=(vcol
>>24)&0xFF;
107 eNamedColor
*n
=searchColor(color
);
110 eDebug("invalid color named \"%s\" (alias to: \"%s\")", name
.c_str(), color
);
118 int eSkin::parseColors(XMLTreeNode
*xcolors
)
122 std::list
<eNamedColor
>::iterator newcolors
=colors
.end();
124 for (node
=xcolors
->GetChild(); node
; node
=node
->GetNext())
126 if (strcmp(node
->GetType(), "color"))
128 eDebug("junk found in colorsection (%s)", node
->GetType());
132 const char *name
=node
->GetAttributeValue("name"), *color
=node
->GetAttributeValue("color"), *end
=node
->GetAttributeValue("end");
136 eDebug("no color/name specified");
143 const char *size
=node
->GetAttributeValue("size");
153 if ((col
.size
>1) && (!end
))
155 eDebug("no end specified in \"%s\" but is gradient", name
);
159 if (parseColor(name
, color
, col
.value
))
162 if (end
&& parseColor(name
, end
, col
.end
))
165 colors
.push_back(col
);
166 if (newcolors
== colors
.end())
170 for (std::list
<eNamedColor
>::iterator
i(newcolors
); i
!= colors
.end(); ++i
)
174 for (d
=0; d
<maxcolors
; d
+=col
.size
)
177 for (s
=0; s
<col
.size
; s
++)
178 if ((d
+s
>maxcolors
) || colorused
[d
+s
])
186 for (int s
=0; s
<col
.size
; s
++, d
++)
191 int rdiff
=-col
.value
.r
+col
.end
.r
;
192 int gdiff
=-col
.value
.g
+col
.end
.g
;
193 int bdiff
=-col
.value
.b
+col
.end
.b
;
194 int adiff
=-col
.value
.a
+col
.end
.a
;
195 rdiff
*=s
; rdiff
/=(col
.size
-1);
196 gdiff
*=s
; gdiff
/=(col
.size
-1);
197 bdiff
*=s
; bdiff
/=(col
.size
-1);
198 adiff
*=s
; adiff
/=(col
.size
-1);
199 palette
[d
].r
=col
.value
.r
+rdiff
;
200 palette
[d
].g
=col
.value
.g
+gdiff
;
201 palette
[d
].b
=col
.value
.b
+bdiff
;
202 palette
[d
].a
=col
.value
.a
+adiff
;
204 palette
[d
]=col
.value
;
210 int eSkin::parseScheme(XMLTreeNode
*xscheme
)
213 for (node
=xscheme
->GetChild(); node
; node
=node
->GetNext())
215 if (strcmp(node
->GetType(), "map"))
217 eDebug("illegal scheme entry found: %s", node
->GetType());
220 char *name
=node
->GetAttributeValue("name"), *color
=node
->GetAttributeValue("color");
223 eDebug("no name or color specified in colorscheme");
228 if ((p
=base
.find('+'))!=-1)
230 offset
=atoi(base
.mid(p
).c_str());
233 eNamedColor
*n
=searchColor(base
);
236 eDebug("illegal color \"%s\" specified", base
.c_str());
239 scheme
[name
] = gColor(n
->index
+offset
);
244 int eSkin::parseFontAlias(XMLTreeNode
*xscheme
)
247 for (node
=xscheme
->GetChild(); node
; node
=node
->GetNext())
249 if (strcmp(node
->GetType(), "map"))
251 eDebug("illegal fontalias entry found: %s", node
->GetType());
254 char *font
=node
->GetAttributeValue("font"),
255 *name
=node
->GetAttributeValue("name"),
256 *size
=node
->GetAttributeValue("size");
258 if (!name
|| !font
|| !size
)
260 eDebug("no name, alias or size spezified in fontaliase");
264 std::map
<eString
, gFont
>::iterator it
= fontAlias
.find(name
);
265 if (it
!= fontAlias
.end())
267 eDebug("fontalias %s does exist, skip make alias for font %s", name
, font
);
271 std::map
<eString
, eString
>::iterator i
= fonts
.find(font
);
272 if (i
== fonts
.end())
274 eDebug("font %s not found, skip make alias %s", font
, name
);
277 fontAlias
[name
]=gFont(i
->second
, atoi(size
));
282 int eSkin::parseImages(XMLTreeNode
*inode
)
284 char *abasepath
=inode
->GetAttributeValue("basepath");
287 eString basepath
=eString("/enigma/pictures/");
288 if (abasepath
[0] == '/') // allow absolute paths
291 if (basepath
[basepath
.length()-1]!='/')
295 for (d
= 0; d
< maxcolors
; d
++)
297 if (!colorused
[d
]) break;
300 for (XMLTreeNode
*node
=inode
->GetChild(); node
; node
=node
->GetNext())
302 if (strcmp(node
->GetType(), "img"))
304 eDebug("illegal image entry found: %s", node
->GetType());
307 const char *name
=node
->GetAttributeValue("name");
310 eDebug("illegal <img> entry: no name");
313 const char *src
=node
->GetAttributeValue("src");
316 eDebug("image/img=\"%s\" no src given", name
);
319 std::map
<eString
, gPixmap
*>::iterator it
= images
.find(name
);
320 if (it
!= images
.end())
322 eDebug("Image with name %s already loaded, skip %s", name
, src
);
326 eString filename
=basepath
+ eString(src
);
327 if (abasepath
[0] != '/')
329 // search first in CONFIGDIR
330 image
=loadPNG((eString(CONFIGDIR
)+filename
).c_str());
332 image
=loadPNG((eString(TUXBOXDATADIR
)+filename
).c_str());
335 image
=loadPNG(filename
.c_str());
339 eDebug("image/img=\"%s\" - %s: file not found", name
, filename
.c_str());
345 int maxcolordistance
= 15500;
346 char *distance
= node
->GetAttributeValue("maxcolordistance");
347 if (distance
) maxcolordistance
= atoi(distance
);
349 /* add the image's colors to our palette, but only if they are not too close to colors we already have */
350 for (int i
= 0; i
< image
->clut
.colors
; i
++)
352 if (findColorDistance(image
->clut
.data
[i
]) > maxcolordistance
)
355 palette
[d
++] = image
->clut
.data
[i
];
356 if (d
>= maxcolors
) break;
360 if (paldummy
&& !node
->GetAttributeValue("nomerge"))
362 gPixmapDC
mydc(image
);
364 p
.mergePalette(*paldummy
);
366 images
[name
] = image
;
367 image
->cancompress
= true;
368 image
->compressdata();
373 int eSkin::parseImageAlias(XMLTreeNode
*xvalues
)
375 for (XMLTreeNode
*node
=xvalues
->GetChild(); node
; node
=node
->GetNext())
377 if (strcmp(node
->GetType(), "map"))
379 eDebug("illegal values entry %s", node
->GetType());
382 const char *name
=node
->GetAttributeValue("name"),
383 *img
=node
->GetAttributeValue("img");
386 eDebug("map entry has no name or img");
389 std::map
<eString
, eString
>::iterator it
= imageAlias
.find(name
);
390 if (it
!= imageAlias
.end())
392 eDebug("imagealias %s does exist, skip make alias for image %s", name
, img
);
395 std::map
<eString
, gPixmap
*>::iterator i
= images
.find(img
);
396 if (i
== images
.end())
398 eDebug("image %s not found, skip make alias %s", img
, name
);
401 imageAlias
[name
]=img
;
406 int eSkin::parseFonts(XMLTreeNode
*xfonts
)
408 const char *abasepath
=xfonts
->GetAttributeValue("basepath");
409 eString basepath
=abasepath
?abasepath
:FONTDIR
;
411 if (basepath
.length())
412 if (basepath
[basepath
.length()-1]!='/')
415 for (XMLTreeNode
*node
=xfonts
->GetChild(); node
; node
=node
->GetNext())
417 if (strcmp(node
->GetType(), "font"))
419 eDebug("illegal fonts entry %s", node
->GetType());
422 const char *file
=node
->GetAttributeValue("file");
425 eDebug("fonts entry has no file");
428 const char *name
=node
->GetAttributeValue("name");
431 eDebug("fonts entry has no name use filename %s as name", file
);
434 std::map
<eString
, eString
>::iterator it
= fonts
.find(name
);
435 const char *ascale
=node
->GetAttributeValue("scale");
441 if (it
!= fonts
.end())
443 eDebug("Font with name %s already loaded, skip %s", name
, file
);
446 fonts
[name
]=fontRenderClass::getInstance()->AddFont(basepath
+eString(file
), name
, scale
);
447 if (node
->GetAttributeValue("replacement"))
448 eTextPara::setReplacementFont(name
);
453 int eSkin::parseValues(XMLTreeNode
*xvalues
)
455 for (XMLTreeNode
*node
=xvalues
->GetChild(); node
; node
=node
->GetNext())
457 if (strcmp(node
->GetType(), "value"))
459 eDebug("illegal values entry %s", node
->GetType());
462 const char *name
=node
->GetAttributeValue("name");
465 eDebug("values entry has no name");
468 const char *value
=node
->GetAttributeValue("value");
471 eDebug("values entry has no value");
474 std::map
<eString
, int>::iterator it
= values
.find(name
);
475 if (it
!= values
.end())
477 eDebug("value %s does exist, skip make value %s=%i", name
, value
);
480 values
[name
]=atoi(value
);
485 gDC
*eSkin::getDCbyName(const char *name
)
488 if (!strcmp(name
, "fb"))
489 dc
=gFBDC::getInstance();
491 else if (!strcmp(name
, "lcd"))
492 dc
=gLCDDC::getInstance();
497 int eSkin::build(eWidget
*widget
, XMLTreeNode
*node
)
499 // eDebug("building a %s", node->GetType());
500 /* if (widget->getType() != node->GetType())
503 for (XMLAttribute
*attrib
=node
->GetAttributes(); attrib
; attrib
=attrib
->GetNext())
505 // eDebug("setting %s := %s", attrib->GetName(), attrib->GetValue());
506 if (widget
->setProperty(attrib
->GetName(), attrib
->GetValue()))
512 for (XMLTreeNode
*c
=node
->GetChild(); c
; c
=c
->GetNext())
516 const char *name
=c
->GetAttributeValue("name");
519 w
=widget
->search(name
);
523 std::map
< eString
, tWidgetCreator
>::iterator it
= widget_creator
.find(c
->GetType());
525 if ( it
== widget_creator
.end() )
527 eWarning("widget class %s does not exist", c
->GetType());
530 w
= (it
->second
)(widget
);
534 // eDebug("failed.");
539 if ((err
=build(w
, c
)))
551 palette
=new gRGB
[maxcolors
];
553 memset(palette
, 0, sizeof(gRGB
)*maxcolors
);
554 paldummy
=new gImage(eSize(1, 1), 8);
555 paldummy
->clut
.data
=palette
;
556 paldummy
->clut
.colors
=maxcolors
;
558 colorused
=new int[maxcolors
];
559 memset(colorused
, 0, maxcolors
*sizeof(int));
571 for (std::map
<eString
, gPixmap
*>::iterator
it(images
.begin()); it
!= images
.end(); ++it
)
578 int eSkin::load(const char *filename
)
580 eDebug("loading skin: %s", filename
);
581 FILE *in
=fopen(filename
, "rt");
585 parsers
.push_front(new XMLTreeParser("ISO-8859-1"));
586 parsers
.setAutoDelete(true);
587 XMLTreeParser
&parser
=*parsers
.first();
593 unsigned int len
=fread(buf
, 1, sizeof(buf
), in
);
594 done
=len
<sizeof(buf
);
595 if (!parser
.Parse(buf
, len
, done
))
597 eDebug("parse error: %s at line %d",
598 parser
.ErrorString(parser
.GetErrorCode()),
599 parser
.GetCurrentLineNumber());
607 XMLTreeNode
*root
=parser
.RootNode();
610 if (strcmp(root
->GetType(), "eskin"))
612 eDebug("not an eskin");
619 void eSkin::parseSkins()
621 for (ePtrList
<XMLTreeParser
>::reverse_iterator
it(parsers
); it
!= parsers
.rend(); it
++)
623 XMLTreeNode
*node
=it
->RootNode();
625 for (node
=node
->GetChild(); node
; node
=node
->GetNext())
626 if (!strcmp(node
->GetType(), "colors"))
630 for (ePtrList
<XMLTreeParser
>::reverse_iterator
it(parsers
); it
!= parsers
.rend(); it
++)
632 XMLTreeNode
*node
=it
->RootNode();
634 for (node
=node
->GetChild(); node
; node
=node
->GetNext())
635 if (!strcmp(node
->GetType(), "colorscheme"))
639 for (ePtrList
<XMLTreeParser
>::iterator
it(parsers
); it
!= parsers
.end(); it
++)
641 XMLTreeNode
*node
=it
->RootNode();
643 for (node
=node
->GetChild(); node
; node
=node
->GetNext())
644 if (!strcmp(node
->GetType(), "fonts"))
648 for (ePtrList
<XMLTreeParser
>::iterator
it(parsers
); it
!= parsers
.end(); it
++)
650 XMLTreeNode
*node
=it
->RootNode();
652 for (node
=node
->GetChild(); node
; node
=node
->GetNext())
653 if (!strcmp(node
->GetType(), "fontalias"))
654 parseFontAlias(node
);
657 for (ePtrList
<XMLTreeParser
>::iterator
it(parsers
); it
!= parsers
.end(); it
++)
659 XMLTreeNode
*node
=it
->RootNode();
661 for (node
=node
->GetChild(); node
; node
=node
->GetNext())
662 if (!strcmp(node
->GetType(), "images"))
667 for (ePtrList
<XMLTreeParser
>::iterator
it(parsers
); it
!= parsers
.end(); it
++)
669 XMLTreeNode
*node
=it
->RootNode();
671 for (node
=node
->GetChild(); node
; node
=node
->GetNext())
672 if (!strcmp(node
->GetType(), "imagealias"))
673 parseImageAlias(node
);
677 for (ePtrList
<XMLTreeParser
>::iterator
it(parsers
); it
!= parsers
.end(); it
++)
679 XMLTreeNode
*node
=it
->RootNode();
681 for (node
=node
->GetChild(); node
; node
=node
->GetNext())
682 if (!strcmp(node
->GetType(), "values"))
688 int eSkin::build(eWidget
*widget
, const char *name
)
690 for (parserList::iterator
i(parsers
.begin()); i
!=parsers
.end(); ++i
)
692 XMLTreeNode
*node
=i
->RootNode();
693 node
=node
->GetChild();
696 if (!strcmp(node
->GetType(), "object"))
698 const char *oname
=node
->GetAttributeValue("name");
699 if (!std::strcmp(name
, oname
))
701 node
=node
->GetChild();
702 return build(widget
, node
);
705 node
=node
->GetNext();
708 eDebug("didn't found it");
712 void eSkin::setPalette(gPixmapDC
*pal
)
717 p
.setPalette(palette
, 0, 256);
721 eSkin
*eSkin::getActive()
724 eFatal("no active skin");
728 void eSkin::makeActive()
733 gColor
eSkin::queryScheme(const eString
& name
) const
737 if ((p
=base
.find('+'))!=-1)
739 offset
=atoi(base
.mid(p
).c_str());
743 std::map
<eString
, gColor
>::const_iterator it
= scheme
.find(base
);
745 if (it
!= scheme
.end())
746 return it
->second
+ offset
;
748 // eWarning("%s does not exist", name.c_str());
753 gPixmap
*eSkin::queryImage(const eString
& name
) const
757 std::map
<eString
, eString
>::const_iterator i
= imageAlias
.find(name
);
759 if (i
!= imageAlias
.end())
764 std::map
<eString
, gPixmap
*>::const_iterator it
= images
.find(img
);
766 if (it
!= images
.end())
772 int eSkin::queryValue(const eString
& name
, int d
) const
774 std::map
<eString
, int>::const_iterator it
= values
.find(name
);
776 if (it
!= values
.end())
782 gColor
eSkin::queryColor(const eString
& name
)
786 int numcol
=strtol(name
.c_str(), &end
, 10);
789 return gColor(numcol
);
793 if ((p
=base
.find('+'))!=-1)
795 offset
=atoi(base
.mid(p
).c_str());
799 eNamedColor
*col
=searchColor(base
);
803 return queryScheme(name
);
805 return col
->index
+ offset
;
808 gFont
eSkin::queryFont(const eString
& name
)
810 std::map
<eString
, gFont
>::iterator it
= fontAlias
.find(name
); // check if name is a font alias
812 if ( it
!= fontAlias
.end() ) // font alias found
818 unsigned int sem
= name
.rfind(';'); // check if exist ';' in name
819 if (sem
!= eString::npos
) // then exist
821 family
=name
.left(sem
);
822 size
= atoi( name
.mid(sem
+1).c_str() );
827 std::map
<eString
, eString
>::iterator i
= fonts
.find(family
); // check if family is a font name
828 if ( i
!= fonts
.end() ) // font exist
829 return gFont(i
->second
, size
);
831 for (i
= fonts
.begin() ; i
!= fonts
.end(); i
++) // as last check if family name is a complete font Face
832 if ( i
->second
== family
)
833 return gFont(i
->second
, size
);
835 eFatal("Font %s does not exist", name
.c_str() ); // halt Programm now... Font does not exist