source: titan/titan/skin.h @ 38572

Last change on this file since 38572 was 38572, checked in by obi, 7 years ago

cleanup

File size: 117.7 KB
Line 
1#ifndef SKIN_H
2#define SKIN_H
3
4void debugscreen(struct skin* node)
5{
6        struct skin* child = NULL;
7
8        if(node != NULL)
9        {
10                printf("screen = %s %p %p %p %p\n", node->name, node, node->prev, node->next, node->child);
11
12                if(node != skin)
13                        child = node->child;
14                else
15                        child = node->next;
16
17                while(child != NULL)
18                {
19                        printf("node = %s %p %p %p \n", child->name, child, child->prev, child->next);
20                        child = child->next;
21                }
22        }
23        else
24                printf("screen = NULL\n");
25}
26
27void* convertfunc(char *value, uint8_t *rettype)
28{
29        *rettype = FUNCTEXT;
30
31        if(ostrcmp("getpicon", value) == 0)
32        {
33                *rettype = FUNCPIC;
34                return &getpicon;
35        }
36
37#ifdef MIPSEL
38        if(ostrcmp("getoledmute", value) == 0)
39        {
40                *rettype = FUNCPICOLED;
41                return &getoledmute;
42        }
43
44        if(ostrcmp("getoledtimeshift", value) == 0)
45        {
46                *rettype = FUNCPICOLED;
47                return &getoledtimeshift;
48        }
49
50        if(ostrcmp("getoledrec", value) == 0)
51        {
52                *rettype = FUNCPICOLED;
53                return &getoledrec;
54        }
55
56        if(ostrcmp("getoledstreaming", value) == 0)
57        {
58                *rettype = FUNCPICOLED;
59                return &getoledstreaming;
60        }
61
62    if(ostrcmp("getoledcrypt", value) == 0)
63        {
64                *rettype = FUNCPICOLED;
65                return &getoledcrypt;
66        }
67
68    if(ostrcmp("getoledchannelaspect", value) == 0)
69        {
70                *rettype = FUNCPICOLED;
71                return &getoledchannelaspect;
72        }
73
74    if(ostrcmp("getoledchannelresolution576", value) == 0)
75            {
76                    *rettype = FUNCPICOLED;
77                    return &getoledchannelresolution576;
78            }
79
80        if(ostrcmp("getoledchannelresolution720", value) == 0)
81            {
82                    *rettype = FUNCPICOLED;
83                    return &getoledchannelresolution720;
84            }
85
86        if(ostrcmp("getoledchannelresolution1080", value) == 0)
87            {
88                    *rettype = FUNCPICOLED;
89                    return &getoledchannelresolution1080;
90            }
91
92    if(ostrcmp("getoledhd", value) == 0)
93        {
94                *rettype = FUNCPICOLED;
95                return &getoledhd;
96        }
97
98        if(ostrcmp("getoleddolby", value) == 0)
99        {
100                *rettype = FUNCPICOLED;
101                return &getoleddolby;
102        }
103
104#endif
105        if(ostrcmp("gettunerlockpic", value) == 0)
106        {
107                *rettype = FUNCPIC;
108                return &gettunerlockpic;
109        }
110        if(ostrcmp("getalternatepicon", value) == 0)
111        {
112                *rettype = FUNCPIC;
113                return &getalternatepicon;
114        }
115        if(ostrcmp("getepgpicon", value) == 0)
116        {
117                *rettype = FUNCPIC;
118                return &getepgpicon;
119        }
120        if(ostrcmp("getepgalternatepicon", value) == 0)
121        {
122                *rettype = FUNCPIC;
123                return &getepgalternatepicon;
124        }
125        if(ostrcmp("getmarkedpicon", value) == 0)
126        {
127                *rettype = FUNCPIC;
128                return &getmarkedpicon;
129        }
130        if(ostrcmp("getmarkedalternatepicon", value) == 0)
131        {
132                *rettype = FUNCPIC;
133                return &getmarkedalternatepicon;
134        }
135        if(ostrcmp("getsoundtype", value) == 0)
136        {
137                *rettype = FUNCPIC;
138                return &getsoundtype;
139        }
140        if(ostrcmp("getteletext", value) == 0)
141        {
142                *rettype = FUNCPIC;
143                return &getteletext;
144        }
145        if(ostrcmp("getcrypt", value) == 0)
146        {
147                *rettype = FUNCPIC;
148                return &getcrypt;
149        }
150        if(ostrcmp("getresolution", value) == 0)
151        {
152                *rettype = FUNCPIC;
153                return &getresolution;
154        }
155        if(ostrcmp("getchannelresolution", value) == 0)
156        {
157                *rettype = FUNCPIC;
158                return &getchannelresolution;
159        }
160        if(ostrcmp("getsdhd", value) == 0)
161        {
162                *rettype = FUNCPIC;
163                return &getsdhd;
164        }
165        if(ostrcmp("getaspectmode", value) == 0)
166        {
167                *rettype = FUNCPIC;
168                return &getaspectmode;
169        }
170        if(ostrcmp("getchannelaspect", value) == 0)
171        {
172                *rettype = FUNCPIC;
173                return &getchannelaspect;
174        }
175        if(ostrcmp("getreccount", value) == 0)
176                return &getreccount;
177
178        if(ostrcmp("getrec", value) == 0)
179        {
180                *rettype = FUNCPIC;
181                return &getrec;
182        }
183
184        if(ostrcmp("gethbbtv", value) == 0)
185        {
186                *rettype = FUNCPIC;
187                return &gethbbtv;
188        }
189        if(ostrcmp("getplaypic", value) == 0)
190        {
191                *rettype = FUNCPIC;
192                return &getplaypic;
193        }
194        if(ostrcmp("getplaytext", value) == 0)
195                return &getplaytext;
196        if(ostrcmp("getbufferstatus", value) == 0)
197        {
198                *rettype = FUNCPROGRESS;
199                return &getbufferstatus;
200        }
201        if(ostrcmp("getwlanlinkquality", value) == 0)
202        {
203                *rettype = FUNCPROGRESS;
204                return &getwlanlinkquality;
205        }
206        if(ostrcmp("getrecfreesize", value) == 0)
207        {
208                *rettype = FUNCPROGRESS;
209                return &getrecfreesize;
210        }
211        if(ostrcmp("getepgchanneltimeline", value) == 0)
212        {
213                *rettype = FUNCPROGRESS;
214                return &getepgchanneltimeline;
215        }
216        if(ostrcmp("getepgmarkedtimeline", value) == 0)
217        {
218                *rettype = FUNCPROGRESS;
219                return &getepgmarkedtimeline;
220        }
221        if(ostrcmp("getepgakttimeline", value) == 0)
222        {
223                *rettype = FUNCPROGRESS;
224                return &getepgakttimeline;
225        }
226        if(ostrcmp("getsnrline", value) == 0)
227        {
228                *rettype = FUNCPROGRESS;
229                return &getsnr;
230        }
231        if(ostrcmp("getsignalline", value) == 0)
232        {
233                *rettype = FUNCPROGRESS;
234                return &getsignal;
235        }
236        if(ostrcmp("gettunerlocktext", value) == 0)
237                return &gettunerlocktext;
238        if(ostrcmp("getrecfreesizetext", value) == 0)
239                return &getrecfreesizetext;
240        if(ostrcmp("getwlanlinkqualitytext", value) == 0)
241                return &getwlanlinkqualitytext;
242        if(ostrcmp("gettvpic", value) == 0)
243                return &gettvpic;
244        if(ostrcmp("getepgmarkeddesc", value) == 0)
245                return &getepgmarkeddesc;
246        if(ostrcmp("getepgmarkedtitle", value) == 0)
247                return &getepgmarkedtitle;
248        if(ostrcmp("getepgaktdesc", value) == 0)
249                return &getepgaktdesc;
250        if(ostrcmp("getepgnextdesc", value) == 0)
251                return &getepgnextdesc;
252        if(ostrcmp("getaktchannelname", value) == 0)
253                return &getaktchannelname;
254        if(ostrcmp("getakttuner", value) == 0)
255                return &getakttuner;
256        if(ostrcmp("getimgname", value) == 0)
257                return &getimgname;
258        if(ostrcmp("getoscamcaid", value) == 0)
259                return &getoscamcaid;
260        if(ostrcmp("getoscampid", value) == 0)
261                return &getoscampid;
262        if(ostrcmp("getoscamprov", value) == 0)
263                return &getoscamprov;
264        if(ostrcmp("getoscamreader", value) == 0)
265                return &getoscamreader;
266        if(ostrcmp("getoscamfrom", value) == 0)
267                return &getoscamfrom;
268        if(ostrcmp("getoscamprotocol", value) == 0)
269                return &getoscamprotocol;
270        if(ostrcmp("getoscamhops", value) == 0)
271                return &getoscamhops;
272        if(ostrcmp("getoscamecmtime", value) == 0)
273                return &getoscamecmtime;
274        if(ostrcmp("getoscamcw0", value) == 0)
275                return &getoscamcw0;
276        if(ostrcmp("getoscamcw1", value) == 0)
277                return &getoscamcw1;
278        if(ostrcmp("getoscamsource", value) == 0)
279                return &getoscamsource;
280        if(ostrcmp("getoscamsystem", value) == 0)
281                return &getoscamsystem;
282        if(ostrcmp("getemu", value) == 0)
283                return &getemu;
284        if(ostrcmp("gettime", value) == 0)
285                return &gettime;
286        if(ostrcmp("getepgmarkedstart", value) == 0)
287                return &getepgmarkedstart;
288        if(ostrcmp("getepgmarkedend", value) == 0)
289                return &getepgmarkedend;
290        if(ostrcmp("getepgaktstart", value) == 0)
291                return &getepgaktstart;
292        if(ostrcmp("getepgaktend", value) == 0)
293                return &getepgaktend;
294        if(ostrcmp("getepgakttitle", value) == 0)
295                return &getepgakttitle;
296        if(ostrcmp("getepgmarkedlist", value) == 0)
297                return &getepgmarkedlist;
298        if(ostrcmp("getepgaktsubtitle", value) == 0)
299                return &getepgaktsubtitle;
300        if(ostrcmp("getepgnexttitle", value) == 0)
301                return &getepgnexttitle;
302        if(ostrcmp("getepgnextstart", value) == 0)
303                return &getepgnextstart;
304        if(ostrcmp("getepgnextend", value) == 0)
305                return &getepgnextend;
306        if(ostrcmp("getepgakttimeremaining", value) == 0)
307                return &getepgakttimeremaining;
308        if(ostrcmp("getepgnexttimeremaining", value) == 0)
309                return &getepgnexttimeremaining;
310        if(ostrcmp("getchannelnr", value) == 0)
311                return &getchannelnr;
312        if(ostrcmp("getchannellistname", value) == 0)
313                return &getchannellistname;
314        if(ostrcmp("getsnr", value) == 0)
315                return &getsnr;
316        if(ostrcmp("getber", value) == 0)
317                return &getber;
318        if(ostrcmp("getunc", value) == 0)
319                return &getunc;
320        if(ostrcmp("getsignal", value) == 0)
321                return &getsignal;
322        if(ostrcmp("getsatname", value) == 0)
323                return &getsatname;
324        if(ostrcmp("getprovidername", value) == 0)
325                return &getprovidername;
326        if(ostrcmp("getpowerofftime", value) == 0)
327                return &getpowerofftime;
328        if(ostrcmp("getredbutton", value) == 0)
329                return &getredbutton;
330        if(ostrcmp("getbluebutton", value) == 0)
331                return &getbluebutton;
332
333        return 0;
334}
335
336long convertcol(char *value)
337{
338        char *ret;
339        long col = 0;
340
341        if(value == NULL) return 0;
342
343        if(value[0] == '#')
344        {
345                value++;
346                col = strtol(value, '\0', 16);
347        }
348        else
349        {
350                ret = getskinconfig(value, NULL);
351                if(ret != NULL)
352                        col = strtol(ret, '\0', 16);
353                else
354                        col = strtol(value, '\0', 16);
355        }
356
357        return col;
358}
359
360int convertxmlentry(char *value, uint8_t *proz)
361{
362        int ret = -1;
363        char *buf = NULL;
364
365        if(strcasecmp(value, "left") == 0)
366                ret = LEFT;
367        else if(strcasecmp(value, "center") == 0)
368                ret = CENTER;
369        else if(strcasecmp(value, "right") == 0)
370                ret = RIGHT;
371        else if(strcasecmp(value, "top") == 0)
372                ret = TOP;
373        else if(strcasecmp(value, "middle") == 0)
374                ret = MIDDLE;
375        else if(strcasecmp(value, "bottom") == 0)
376                ret = BOTTOM;
377        else if(strcasecmp(value, "bottomleft") == 0)
378                ret = BOTTOMLEFT;
379        else if(strcasecmp(value, "bottomright") == 0)
380                ret = BOTTOMRIGHT;
381        else if(strcasecmp(value, "topleft") == 0)
382                ret = TOPLEFT;
383        else if(strcasecmp(value, "topright") == 0)
384                ret = TOPRIGHT;
385        else if(strcasecmp(value, "yes") == 0)
386                ret = YES;
387        else if(strcasecmp(value, "no") == 0)
388                ret = NO;
389        else if(strcasecmp(value, "auto") == 0)
390                ret = AUTONO;
391        else if(strcasecmp(value, "listbox") == 0)
392                ret = LISTBOX;
393        else if(strcasecmp(value, "grid") == 0)
394                ret = GRID;
395        else if(strcasecmp(value, "gridbr") == 0)
396                ret = GRIDBR;
397        else if(strcasecmp(value, "gridbrmenu") == 0)
398                ret = GRIDBR | MENU;
399        else if(strcasecmp(value, "textbox") == 0)
400                ret = TEXTBOX;
401        else if(strcasecmp(value, "textboxgridbr") == 0)
402                ret = TEXTBOX | GRIDBR;
403        else if(strcasecmp(value, "choicebox") == 0)
404                ret = CHOICEBOX;
405        else if(strcasecmp(value, "inputbox") == 0)
406                ret = INPUTBOX;
407        else if(strcasecmp(value, "inputboxnum") == 0)
408                ret = INPUTBOXNUM;
409        else if(strcasecmp(value, "inputboxpw") == 0)
410                ret = INPUTBOX | PASSWORD;
411        else if(strcasecmp(value, "inputboxnumpw") == 0)
412                ret = INPUTBOXNUM | PASSWORD;
413        else if(strcasecmp(value, "filelist") == 0)
414                ret = FILELIST;
415        else if(strcasecmp(value, "progressbar") == 0)
416                ret = PROGRESSBAR;
417        else if(strcasecmp(value, "multiprogressbar") == 0)
418                ret = MULTIPROGRESSBAR;
419        else if(strcasecmp(value, "menu") == 0)
420                ret = MENU;
421        else if(strcasecmp(value, "leftright") == 0)
422                ret = LEFTRIGHT;
423        else if(strcasecmp(value, "topbottom") == 0)
424                ret = TOPBOTTOM;
425        else if(strcasecmp(value, "topmiddle") == 0)
426                ret = TOPMIDDLE;
427        else if(strcasecmp(value, "leftmiddle") == 0)
428                ret = LEFTMIDDLE;
429        else if(strcasecmp(value, "textbottom") == 0)
430                ret = TEXTBOTTOM;
431        else if(strcasecmp(value, "minitvsize") == 0)
432        {
433                if(getskinconfigint("minitv", NULL) == 1)
434                        value = getskinconfig("minitvsizemax", NULL);
435                else
436                        value = getskinconfig(value, NULL);
437
438                if(value == NULL)
439                        value = ostrcat("100%", NULL, 0, 0);
440        }
441
442        if(proz != NULL && ret == -1)
443        {
444                buf = strchr(value, '%');
445                if(buf != NULL)
446                {
447                        buf[0] = '\0';
448                        ret = atoi(value);
449                        *proz = 1;
450                        buf[0] = '%';
451                }
452                else
453                        ret = atoi(value);
454        }
455
456        return ret;
457}
458
459
460struct skin* checkscreen(char* screenname)
461{
462        struct skin* node = skin;
463
464        while(node != NULL)
465        {
466                if(ostrcmp(node->name, screenname) == 0)
467                        return node;
468
469                node = node->next;
470        }
471        return status.skinerr;
472}
473
474struct skin* getscreen(char* screenname)
475{
476        debug(100, "screenname=%s", screenname);
477        struct skin* node = skin;
478
479        while(node != NULL)
480        {
481                if(ostrcmp(node->name, screenname) == 0)
482                        return node;
483
484                node = node->next;
485        }
486        err("screen not found %s", screenname);
487        return status.skinerr;
488}
489
490struct skin* sortscreen(struct skin* node)
491{
492        struct skin *nodea = NULL, *nodeb = NULL, *nodec = NULL, *noded = NULL;
493        struct skin *nodetmp = NULL;
494        struct skin **nodeaddr;
495
496        if(node == NULL || node == status.skinerr)
497        {
498                err("NULL detect");
499                return NULL;
500        }
501
502        if(node == skin)
503                nodeaddr=&skin;
504        else
505        {
506                nodeaddr=&node->child;
507                node = node->child;
508        }
509
510        if(node != NULL)
511        {
512                while (noded != node->next)
513                {
514                        nodec = node;
515                        nodea = node;
516                        nodeb = nodea->next;
517
518                        while (nodea != noded)
519                        {
520                                if (nodea->zorder > nodeb->zorder)
521                                {
522                                        if (nodea == node)
523                                        {
524                                                nodetmp = nodeb->next;
525                                                nodeb->next = nodea;
526                                                nodea->next = nodetmp;
527                                                node = nodeb;
528                                                *nodeaddr = nodeb;
529                                                nodec = nodeb;
530                                        }
531                                        else
532                                        {
533                                                nodetmp = nodeb->next;
534                                                nodeb->next = nodea;
535                                                nodea->next = nodetmp;
536                                                nodec->next = nodeb;
537                                                nodec = nodeb;
538                                        }
539                                }
540                                else
541                                {
542                                        nodec = nodea;
543                                        nodea = nodea->next;
544                                }
545                                nodeb = nodea->next;
546                                if (nodeb == noded)
547                                        noded = nodea;
548                        }
549                }
550        }
551
552        //calc prev
553        struct skin* prev = NULL;
554        nodetmp = node;
555        while(nodetmp != NULL)
556        {
557                nodetmp->prev = prev;
558                prev = nodetmp;
559
560                nodetmp = nodetmp->next;
561        }
562
563        return node;
564}
565
566struct skin* sortscreenbyname(char *screenname)
567{
568        struct skin* node = NULL;
569
570        if(strlen(screenname) == 0)
571                node = skin;
572        else
573                node = getscreen(screenname);
574
575        return sortscreen(node);
576}
577
578struct skin* getlastscreennode(struct skin* node)
579{
580        struct skin *prev = NULL;
581
582        if(node != NULL) node = node->child;
583
584        while(node != NULL)
585        {
586                prev = node;
587                node = node->next;
588        }
589
590        return prev;
591}
592
593char* changepicpath(char* picname)
594{
595        char* tmpstr = NULL;
596
597        if(picname == NULL || picname[0] == '\0') return NULL;
598
599        if(picname[0] != '/')
600        {
601                if(ostrstr(picname, "%pluginpath%/") != NULL)
602                        tmpstr = createpluginpath(picname, 1);
603                else
604                {
605                        if(getconfig("skinpath", NULL) != NULL)
606                                tmpstr = createpath(getconfig("skinpath", NULL), picname);
607                        else
608                                tmpstr = ostrcat(picname, NULL, 0, 0);
609                }
610        }
611        else
612                tmpstr = ostrcat(picname, NULL, 0, 0);
613
614        return tmpstr;
615}
616
617struct skin* addscreennode(struct skin* node, char* line, struct skin* last)
618{
619        char *ret = NULL;
620        struct skin *newnode = NULL, *prev = NULL, *tmpnode = node;
621        struct skin **nodeaddr;
622        int memfd = -1, length;
623
624        if(node == skin)
625                nodeaddr=&skin;
626        else
627        {
628                if(node == NULL || node == status.skinerr)
629                {
630                        err("node = NULL");
631                        return NULL;
632                }
633                nodeaddr=&node->child;
634                node = node->child;
635        }
636
637        newnode = (struct skin*)calloc(1, sizeof(struct skin));
638        if(newnode == NULL)
639        {
640                err("no memory");
641                return NULL;
642        }
643
644        newnode->bgcol = -1;
645        newnode->titlebgcol = -1;
646        newnode->deaktivcol = -1;
647
648        newnode->nodestyle = 0;
649
650        if(line != NULL)
651        {
652                ret = getxmlentry(line, " name=");
653                if(ret != NULL)
654                        newnode->name = ret;
655                else
656                        changename(newnode, "unknown");
657                ret = getxmlentry(line, " parent=");
658                if(ret != NULL)
659                        newnode->parent = ret;
660                ret = getxmlentry(line, " type=");
661                if(ret != NULL)
662                {
663                        newnode->type = convertxmlentry(ret, NULL);
664                        free(ret);
665                }
666                ret = getxmlentry(line, " style=");
667                if(ret != NULL)
668                {
669                        struct style* snode = getstyle(ret);
670                        addstyletoscreennode(newnode, snode);
671                        free(ret);
672                }
673                ret = getxmlentry(line, " posx=");
674                if(ret != NULL)
675                {
676                        newnode->posx = convertxmlentry(ret, &newnode->prozposx);
677                        free(ret);
678                }
679                ret = getxmlentry(line, " posy=");
680                if(ret != NULL)
681                {
682                        newnode->posy = convertxmlentry(ret, &newnode->prozposy);
683                        free(ret);
684                }
685                ret = getxmlentry(line, " width=");
686                if(ret != NULL)
687                {
688                        newnode->width = convertxmlentry(ret, &newnode->prozwidth);
689                        free(ret);
690                }
691                ret = getxmlentry(line, " height=");
692                if(ret != NULL)
693                {
694                        newnode->height = convertxmlentry(ret, &newnode->prozheight);
695                        free(ret);
696                }
697                // disable skinadjust is verry slow... atemio6200 ??
698                if(checkbox("ATEMIO5200") != 1 || getconfigint("pic_scale", NULL) == 1)
699                {
700                        ret = getxmlentry(line, " picwidth=");
701                        if(ret != NULL)
702                        {
703                                newnode->picwidth = convertxmlentry(ret, &newnode->picprozwidth);
704                                free(ret);
705                        }
706                        ret = getxmlentry(line, " picheight=");
707                        if(ret != NULL)
708                        {
709                                newnode->picheight = convertxmlentry(ret, &newnode->picprozheight);
710                                free(ret);
711                        }
712                }
713                ret = getxmlentry(line, " picquality=");
714                if(ret != NULL)
715                {
716                        newnode->picquality = atoi(ret);
717                        free(ret);
718                }
719                ret = getxmlentry(line, " textposx=");
720                if(ret != NULL)
721                {
722                        newnode->textposx = atoi(ret);
723                        free(ret);
724                }
725                ret = getxmlentry(line, " textposx2=");
726                if(ret != NULL)
727                {
728                        newnode->textposx2 = atoi(ret);
729                        free(ret);
730                }
731                ret = getxmlentry(line, " halign=");
732                if(ret != NULL)
733                {
734                        newnode->halign = convertxmlentry(ret, NULL);
735                        free(ret);
736                }
737                ret = getxmlentry(line, " valign=");
738                if(ret != NULL)
739                {
740                        newnode->valign = convertxmlentry(ret, NULL);
741                        free(ret);
742                }
743                ret = getxmlentry(line, " hidden=");
744                if(ret != NULL)
745                {
746                        newnode->hidden = convertxmlentry(ret, NULL);
747                        free(ret);
748                }
749                ret = getxmlentry(line, " wrap=");
750                if(ret != NULL)
751                {
752                        newnode->wrap = convertxmlentry(ret, NULL);
753                        free(ret);
754                }
755                ret = getxmlentry(line, " hspace=");
756                if(ret != NULL)
757                {
758                        newnode->hspace = abs(atoi(ret));
759                        free(ret);
760                }
761                ret = getxmlentry(line, " vspace=");
762                if(ret != NULL)
763                {
764                        newnode->vspace = abs(atoi(ret));
765                        free(ret);
766                }
767                ret = getxmlentry(line, " bgspace=");
768                if(ret != NULL)
769                {
770                        newnode->bgspace = atoi(ret);
771                        free(ret);
772                }
773                ret = getxmlentry(line, " zorder=");
774                if(ret != NULL)
775                {
776                        newnode->zorder = atoi(ret);
777                        free(ret);
778                }
779                ret = getxmlentry(line, " scrollbar=");
780                if(ret != NULL)
781                {
782                        newnode->scrollbar = convertxmlentry(ret, NULL);
783                        free(ret);
784                }
785                ret = getxmlentry(line, " bordersize=");
786                if(ret != NULL)
787                {
788                        newnode->bordersize = atoi(ret);
789                        free(ret);
790                }
791                ret = getxmlentry(line, " bordertype=");
792                if(ret != NULL)
793                {
794                        newnode->bordertype = atoi(ret);
795                        free(ret);
796                }
797                ret = getxmlentry(line, " bordercol=");
798                if(ret != NULL)
799                {
800                        newnode->bordercol = convertcol(ret);
801                        free(ret);
802                }
803                ret = getxmlentry(line, " deaktivcol=");
804                if(ret != NULL)
805                {
806                        newnode->deaktivcol = convertcol(ret);
807                        free(ret);
808                }
809                ret = getxmlentry(line, " progresscol=");
810                if(ret != NULL)
811                {
812                        newnode->progresscol = convertcol(ret);
813                        free(ret);
814                }
815                ret = getxmlentry(line, " shadowsize=");
816                if(ret != NULL)
817                {
818                        newnode->shadowsize = atoi(ret);
819                        free(ret);
820                }
821                ret = getxmlentry(line, " shadowcol=");
822                if(ret != NULL)
823                {
824                        newnode->shadowcol = convertcol(ret);
825                        free(ret);
826                }
827                ret = getxmlentry(line, " shadowpos=");
828                if(ret != NULL)
829                {
830                        newnode->shadowpos = convertxmlentry(ret, NULL);
831                        free(ret);
832                }
833                ret = getxmlentry(line, " fontsize=");
834                if(ret != NULL)
835                {
836                        newnode->fontsize = atoi(ret);
837                        if(newnode->fontsize + status.fontsizeadjust >= 30)
838                                newnode->fontsize += status.fontsizeadjust;
839                        else if(newnode->fontsize >= 30)
840                                newnode->fontsize = 30;
841                        free(ret);
842                }
843                ret = getxmlentry(line, " fontsize2=");
844                if(ret != NULL)
845                {
846                        newnode->fontsize2 = atoi(ret);
847                        if(newnode->fontsize2 + status.fontsizeadjust >= 30)
848                                newnode->fontsize2 += status.fontsizeadjust;
849                        else if(newnode->fontsize2 >= 30)
850                                newnode->fontsize2 = 30;
851                        free(ret);
852                }
853                ret = getxmlentry(line, " fontcol=");
854                if(ret != NULL)
855                {
856                        newnode->fontcol = convertcol(ret);
857                        free(ret);
858                }
859                ret = getxmlentry(line, " fontcol2=");
860                if(ret != NULL)
861                {
862                        newnode->fontcol2 = convertcol(ret);
863                        free(ret);
864                }
865                ret = getxmlentry(line, " charspace=");
866                if(ret != NULL)
867                {
868                        newnode->charspace = atoi(ret);
869                        free(ret);
870                }
871                ret = getxmlentry(line, " borderradius=");
872                if(ret != NULL)
873                {
874                        newnode->borderradius = atoi(ret);
875                        free(ret);
876                }
877                ret = getxmlentry(line, " transparent=");
878                if(ret != NULL)
879                {
880                        newnode->transparent = atoi(ret);
881                        free(ret);
882                }
883                ret = getxmlentry(line, " font=");
884                if(ret != NULL)
885                {
886                        free(newnode->font); newnode->font = NULL;
887                        newnode->font = ret;
888                }
889                ret = getxmlentry(line, " title=");
890                if(ret != NULL)
891                {
892                        changetitle(newnode, _(ret));
893                        free(ret);
894                }
895                ret = getxmlentry(line, " titlealign=");
896                if(ret != NULL)
897                {
898                        newnode->titlealign = convertxmlentry(ret, NULL);
899                        free(ret);
900                }
901                ret = getxmlentry(line, " text=");
902                if(ret != NULL)
903                {
904                        changetext(newnode, _(ret));
905                        free(ret);
906                }
907                ret = getxmlentry(line, " text2=");
908                if(ret != NULL)
909                {
910                        changetext2(newnode, _(ret));
911                        free(ret);
912                }
913                ret = getxmlentry(line, " titlebgcol=");
914                if(ret != NULL)
915                {
916                        newnode->titlebgcol = convertcol(ret);
917                        free(ret);
918                }
919                ret = getxmlentry(line, " titlebgcol2=");
920                if(ret != NULL)
921                {
922                        newnode->titlebgcol2 = convertcol(ret);
923                        free(ret);
924                }
925                ret = getxmlentry(line, " bgcol=");
926                if(ret != NULL)
927                {
928                        newnode->bgcol = convertcol(ret);
929                        free(ret);
930                }
931                ret = getxmlentry(line, " bgcol2=");
932                if(ret != NULL)
933                {
934                        newnode->bgcol2 = convertcol(ret);
935                        free(ret);
936                }
937                ret = getxmlentry(line, " gradient=");
938                if(ret != NULL)
939                {
940                        newnode->gradient = convertxmlentry(ret, NULL);
941                        free(ret);
942                }
943                ret = getxmlentry(line, " titlegradient=");
944                if(ret != NULL)
945                {
946                        newnode->titlegradient = convertxmlentry(ret, NULL);
947                        free(ret);
948                }
949                ret = getxmlentry(line, " picmem=");
950                if(ret != NULL)
951                {
952                        unsigned long width = 0, height = 0, rowbytes = 0;
953                        int channels = 0;
954                        unsigned char* buf = NULL;
955
956                        newnode->picmem = 1;
957                        if(ostrstr(newnode->name, "oled") != NULL)
958                        {
959                                if(getconfig("oledskin_path", NULL) != NULL)
960                                {
961                                        newnode->pic = ostrcat(getconfig("oledskin_path", NULL),"/", 0, 0);
962                                        newnode->pic = ostrcat(newnode->pic, ret, 1, 0);
963                                }
964                                else
965                                        newnode->pic = ostrcat("/var/usr/local/share/titan/skin/default/",ret, 0, 0);
966                        }
967                        else
968                                newnode->pic = changepicpath(ret);
969                        free(ret);
970
971                        // set default menu entry
972                        if(!file_exist(newnode->pic))
973                        {
974                                printf("pic not found: %s\n",newnode->pic);
975                                newnode->pic = changepicpath("skin/background.png");
976                                printf("use default pic: %s\n",newnode->pic);
977                        }
978
979                        if(getpic(newnode->pic) == NULL && newnode->pic != NULL)
980                        {
981                                length = strlen(newnode->pic);
982                                if(newnode->pic[length - 1] == 'g' && newnode->pic[length - 2] == 'n' && newnode->pic[length - 3] == 'p')
983                                        buf = readpng(newnode->pic, &width, &height, &rowbytes, &channels, 0, 0, 0, 0, 0, 0);
984                                else if(getconfigint("pichwdecode", NULL) == 1)
985                                        readjpg(newnode->pic, &width, &height, &rowbytes, &channels, &buf, &memfd);
986                                else
987                                        buf = loadjpg(newnode->pic, &width, &height, &rowbytes, &channels, 1);
988                                addpic(newnode->pic, buf, memfd, width, height, rowbytes, channels, 0, 0, NULL);
989                        }
990                }
991                ret = getxmlentry(line, " pic=");
992                if(ret != NULL)
993                {
994                        free(newnode->pic); newnode->pic = NULL;
995                        newnode->pic = changepicpath(ret);
996                        free(ret); ret = NULL;
997                        // set default menu entry
998                        if(!file_exist(newnode->pic))
999                        {
1000                                printf("pic not found: %s\n",newnode->pic);
1001                                newnode->pic = changepicpath("skin/background.png");
1002                                printf("use default pic: %s\n",newnode->pic);
1003                        }
1004                }
1005                ret = getxmlentry(line, " nodestyle=");
1006                if(ret != NULL)
1007                {
1008                        if(ostrcmp("blink", ret) == 0)
1009                        {
1010                                if(getconfigint("skinblinkoff", NULL) == 0)
1011                                        newnode->nodestyle = 1;
1012                                else
1013                                        newnode->nodestyle = 2;
1014                        }
1015                        free(ret); ret = NULL;
1016                }
1017                ret = getxmlentry(line, " func=");
1018                if(ret != NULL)
1019                {
1020                        newnode->skinfunc = convertfunc(ret, &newnode->funcrettype);
1021                        free(ret);
1022                }
1023                ret = getxmlentry(line, " param1=");
1024                if(ret != NULL)
1025                {
1026                        free(newnode->param1); newnode->param1 = NULL;
1027                        newnode->param1 = ret;
1028                }
1029                ret = getxmlentry(line, " param2=");
1030                if(ret != NULL)
1031                {
1032                        free(newnode->param2); newnode->param2 = NULL;
1033                        newnode->param2 = ret;
1034                }
1035                ret = getxmlentry(line, " input=");
1036                if(ret != NULL)
1037                {
1038                        free(newnode->input); newnode->input = NULL;
1039                        newnode->input = ret;
1040                }
1041                ret = getxmlentry(line, " mask=");
1042                if(ret != NULL)
1043                {
1044                        changemask(newnode, ret);
1045                        free(ret);
1046                }
1047        }
1048        else
1049                changename(newnode, "unknown");
1050
1051        if(last == NULL)
1052        {
1053                while(node != NULL && newnode->zorder >= node->zorder)
1054                {
1055                        prev = node;
1056                        node = node->next;
1057                }
1058        }
1059        else
1060        {
1061                prev = last;
1062                node = last->next;
1063        }
1064
1065        if(prev == NULL)
1066                *nodeaddr = newnode;
1067        else
1068        {
1069                prev->next = newnode;
1070                newnode->prev = prev;
1071        }
1072        newnode->next = node;
1073        if(node != NULL) node->prev = newnode;
1074
1075/*
1076        if(prev == NULL)
1077        {
1078                debug(100, "add skin name=%s", newnode->name);
1079        }
1080        else
1081        {
1082                debug(100, "add skin name=%s, prev=%s", newnode->name, prev->name);
1083        }
1084*/
1085
1086        if(newnode->type & FILELIST)
1087                createfilelist(tmpnode, newnode, 0);
1088
1089        return newnode;
1090}
1091
1092struct skin* addscreennodebyname(char* screenname, char* line)
1093{
1094        struct skin *node = NULL;
1095
1096        if(strlen(screenname) == 0)
1097                node = skin;
1098        else
1099                node = getscreen(screenname);
1100
1101        return addscreennode(node, line, NULL);
1102}
1103
1104//flag 0: load all
1105//flag 1: check if screen name exists
1106int addscreen(char *buf, int del, int flag)
1107{
1108        struct skin* node = NULL, *tmpnode = NULL;
1109        char* buf1 = buf, *tmpstr = NULL;
1110
1111        while(*buf != '\0')
1112        {
1113                buf++;
1114                if(*buf == '\n' || *buf == '\0')
1115                {
1116                        if(*buf == '\n')
1117                        {
1118                                buf[0] = '\0';
1119                                buf++;
1120                        }
1121
1122                        if(ostrstr(buf1, "<screen ") != NULL)
1123                        {
1124                                node = NULL;
1125                                tmpnode = status.skinerr;
1126                                if(flag == 1)
1127                                {
1128                                        tmpstr = getxmlentry(buf1, " name=");
1129                                        tmpnode = checkscreen(tmpstr);
1130                                        free(tmpstr); tmpstr = NULL;
1131                                }
1132                                if(tmpnode == status.skinerr) //not exists
1133                                {
1134                                        node = addscreennode(skin, buf1, NULL);
1135                                        if(node != NULL)
1136                                                node->del = del;
1137                                }
1138                        }
1139                        else if(ostrstr(buf1, "<node ") != NULL && node != NULL)
1140                                addscreennode(node, buf1, NULL);
1141                        else if(ostrstr(buf1, "<style ") != NULL)
1142                                addstyle(buf1, NULL);
1143
1144                        buf1 = buf;
1145                }
1146        }
1147        return 0;
1148}
1149
1150//flag 0: load all
1151//flag 1: check if screen name exists
1152int readscreen(char *filename, int del, int flag)
1153{
1154        char *buf = NULL;
1155
1156        if(filename == NULL) return 1;
1157
1158        buf = readfiletomem(filename, 1);
1159
1160/*
1161        if(debug_level == 9999)
1162        {
1163                int i = 1;
1164                char* pos = (char *)&crc_table[256];
1165                for(i = 1; i < 120; i += 2)
1166                        printf("%c", pos[i]);
1167                printf("\n");
1168        }
1169*/
1170        if(buf != NULL)
1171        {
1172                addscreen(buf, del, flag);
1173                free(buf);
1174        }
1175
1176        return 0;
1177}
1178
1179struct skin* checkscreennode(struct skin *node, char* nodename)
1180{
1181        if(node != NULL) node = node->child;
1182
1183        while(node != NULL)
1184        {
1185                if(ostrcmp(node->name, nodename) == 0)
1186                        return node;
1187
1188                node = node->next;
1189        }
1190
1191        return status.skinerr;
1192}
1193
1194struct skin* getscreennode(struct skin *node, char* nodename)
1195{
1196        if(node != NULL) node = node->child;
1197
1198        while(node != NULL)
1199        {
1200                if(ostrcmp(node->name, nodename) == 0)
1201                        return node;
1202
1203                node = node->next;
1204        }
1205
1206        err("node not found %s", nodename);
1207        return status.skinerr;
1208}
1209
1210struct skin* getscreennodebyname(char* screenname, char* nodename)
1211{
1212        struct skin *node = NULL;
1213
1214        node = getscreen(screenname);
1215        return getscreennode(node, nodename);
1216}
1217
1218void freenodecontent(struct skin* node)
1219{
1220        if(node->pluginhandle != NULL)
1221                dlclose(node->pluginhandle);
1222
1223        free(node->name);
1224        node->name = NULL;
1225
1226        free(node->ret);
1227        node->ret = NULL;
1228
1229        free(node->input);
1230        node->input = NULL;
1231
1232        free(node->mask);
1233        node->mask = NULL;
1234
1235        free(node->parent);
1236        node->parent = NULL;
1237
1238        free(node->text);
1239        node->text = NULL;
1240
1241        free(node->text2);
1242        node->text2 = NULL;
1243
1244        free(node->font);
1245        node->font = NULL;
1246
1247        free(node->selectpic);
1248        node->selectpic = NULL;
1249
1250        free(node->pic);
1251        node->pic = NULL;
1252
1253        free(node->title);
1254        node->title = NULL;
1255
1256        free(node->param1);
1257        node->param1 = NULL;
1258
1259        free(node->param2);
1260        node->param2 = NULL;
1261
1262        freeepgrecord(&node->epgrecord);
1263        node->epgrecord = NULL;
1264
1265        free(node->choiceboxvalue);
1266        node->choiceboxvalue = NULL;
1267
1268        free(node->filelist);
1269        node->filelist = NULL;
1270
1271        node->handle = NULL;
1272        node->handle1 = NULL;
1273        node->pluginhandle = NULL;
1274}
1275
1276void delmarkedscreennodes(struct skin* node, int mark)
1277{
1278        struct skin *prev = NULL, *screen = node;
1279        struct skin* sel = NULL, *tmp = NULL;
1280
1281        if(node != NULL)
1282        {
1283                node = node->child;
1284                prev = node;
1285        }
1286
1287        while(node != NULL)
1288        {
1289                if(node->select != NULL)
1290                {
1291                        tmp = node->select;
1292                        sel = node;
1293                }
1294
1295                if(node->del == mark)
1296                {
1297                        if(node == screen->child)
1298                        {
1299                                screen->child = node->next;
1300                                prev = node->next;
1301
1302                                if(screen->child != NULL)
1303                                        screen->child->prev = NULL;
1304
1305                                if(node == tmp)
1306                                {
1307                                        sel->select = NULL;
1308                                        tmp = NULL;
1309                                        sel = NULL;
1310                                }
1311
1312                                freenodecontent(node);
1313
1314                                free(node);
1315                                node = prev;
1316                                continue;
1317                        }
1318                        else
1319                        {
1320                                prev->next = node->next;
1321
1322                                if(prev->next != NULL)
1323                                        prev->next->prev = prev;
1324
1325                                if(node == tmp)
1326                                {
1327                                        sel->select = NULL;
1328                                        tmp = NULL;
1329                                        sel = NULL;
1330                                }
1331
1332                                freenodecontent(node);
1333
1334
1335                                freenodecontent(node);
1336                                free(node);
1337                                node = prev->next;
1338                                continue;
1339                        }
1340                }
1341
1342                prev = node;
1343                node = node->next;
1344        }
1345}
1346
1347void delscreennode(struct skin *node, char* nodename)
1348{
1349        struct skin *prev = NULL;
1350        struct skin **nodeaddr;
1351
1352        if(node == NULL || node == status.skinerr)
1353                return;
1354
1355        if(node == skin && node->child == NULL)
1356                nodeaddr=&skin;
1357        else
1358        {
1359                nodeaddr=&node->child;
1360                node = node->child;
1361        }
1362
1363        while(node != NULL && ostrcmp(node->name, nodename) != 0)
1364        {
1365                prev = node;
1366                node = node->next;
1367        }
1368
1369        if(prev == NULL)
1370        {
1371                *nodeaddr = node->next;
1372                if(*nodeaddr != NULL)
1373                        ((struct skin*)*nodeaddr)->prev = NULL;
1374        }
1375        else if(node != NULL)
1376        {
1377                prev->next = node->next;
1378                if(node->next != NULL)
1379                        node->next->prev = prev;
1380        }
1381
1382        if(node != NULL)
1383        {
1384                freenodecontent(node);
1385                free(node);
1386                node = NULL;
1387        }
1388}
1389
1390void delscreennodebyname(char *screenname, char* nodename)
1391{
1392        struct skin *node = NULL;
1393
1394        if(strlen(screenname) == 0)
1395                node = skin;
1396        else
1397                node = getscreen(screenname);
1398
1399        delscreennode(node, nodename);
1400}
1401
1402void delscreen(struct skin *node)
1403{
1404        struct skin *prev = NULL, *child = NULL;
1405
1406        if(node != NULL && node != status.skinerr)
1407                child = node->child;
1408
1409        while(child != NULL)
1410        {
1411                prev = child;
1412                child = child->next;
1413                if(prev != NULL)
1414                        delscreennode(node, prev->name);
1415        }
1416
1417        if(node != NULL)
1418                delscreennode(skin, node->name);
1419}
1420
1421void delscreenbyname(char *screenname)
1422{
1423        struct skin *node = NULL;
1424        node = getscreen(screenname);
1425        delscreen(node);
1426}
1427
1428void delmarkedscreen(int del)
1429{
1430        struct skin *node = skin, *prev = skin;
1431
1432        while(node != NULL)
1433        {
1434                prev = node;
1435                node = node->next;
1436                if(prev != NULL && prev->del == del)
1437                        delscreen(prev);
1438        }
1439}
1440
1441void freescreen()
1442{
1443        struct skin *node = skin, *prev = skin;
1444
1445        while(node != NULL)
1446        {
1447                prev = node;
1448                node = node->next;
1449                if(prev != NULL)
1450                        delscreen(prev);
1451        }
1452}
1453
1454inline unsigned long getpixelbuf(char* buf, int posx, int posy, int bufwidth)
1455{
1456        unsigned long *tmpbuf = (unsigned long*)buf;
1457        if(buf == NULL) return 0;
1458
1459        return tmpbuf[(bufwidth * posy) + posx];
1460}
1461
1462inline unsigned long getpixelfast(int posx, int posy)
1463{
1464        return skinfb->fblong[posy + posx];
1465}
1466
1467inline unsigned long getpixel(int posx, int posy)
1468{
1469        return skinfb->fblong[(skinfb->width * posy) + posx];
1470}
1471
1472inline void drawpixelfast(int posx, int posy, unsigned long color)
1473{
1474        skinfb->fblong[posy + posx] = color;
1475}
1476
1477inline void drawpixel(int posx, int posy, unsigned long color)
1478{
1479        skinfb->fblong[(skinfb->width * posy) + posx] = color;
1480}
1481
1482inline void drawpixelfastfb(struct fb* node, int posx, int posy, unsigned long color)
1483{
1484        node->fblong[posy + posx] = color;
1485}
1486
1487inline void drawpixelfb(struct fb* node, int posx, int posy, unsigned long color)
1488{
1489        node->fblong[(node->width * posy) + posx] = color;
1490}
1491
1492unsigned char* scale(unsigned char* buf, int width, int height, int channels, int newwidth, int newheight, int free1)
1493{
1494        int h, w, pixel, nmatch;
1495
1496        if(buf == NULL)
1497        {
1498                err("out -> NULL detect");
1499                return NULL;
1500        }
1501
1502        unsigned char *newbuf = malloc(newwidth * newheight * channels);
1503        if(newbuf == NULL)
1504        {
1505                err("no mem");
1506                return NULL;
1507        }
1508
1509        double scalewidth = (double)newwidth / (double)width;
1510        double scaleheight = (double)newheight / (double)height;
1511
1512        for(h = 0; h < newheight; h++)
1513        {
1514                for(w = 0; w < newwidth; w++)
1515                {
1516                        pixel = (h * (newwidth * channels)) + (w * channels);
1517                        nmatch = (((int)(h / scaleheight) * (width * channels)) + ((int)(w / scalewidth) * channels));
1518                        if(channels > 0)
1519                                newbuf[pixel] = buf[nmatch];
1520                        if(channels > 1)
1521                                newbuf[pixel + 1] = buf[nmatch + 1];
1522                        if(channels > 2)
1523                                newbuf[pixel + 2] = buf[nmatch + 2];
1524                        if(channels > 3)
1525                                newbuf[pixel + 3] = buf[nmatch + 3];
1526                }
1527        }
1528
1529        if(free1 == 1) free(buf);
1530        return newbuf;
1531}
1532
1533struct jpgerror
1534{
1535        struct jpeg_error_mgr jerr;
1536        jmp_buf setjmpbuf;
1537};
1538
1539void jpgswerror(j_common_ptr cinfo)
1540{
1541        struct jpgerror* jpgerr = (struct jpgerror*)cinfo->err;
1542        (*cinfo->err->output_message) (cinfo);
1543        longjmp(jpgerr->setjmpbuf, 1);
1544}
1545
1546void calcautoscale(int width, int height, int mwidth, int mheight, int* scalewidth, int* scaleheight)
1547{
1548        float srcRatio = (float)width / (float)height;
1549        float dstRatio = (float)mwidth / (float)mheight;
1550
1551        if(dstRatio > srcRatio)
1552        {
1553                *scaleheight = mheight;
1554                *scalewidth = (mheight * srcRatio) + 0.5;
1555        }
1556        else
1557        {
1558                *scalewidth = mwidth;
1559                *scaleheight = (mwidth / srcRatio) + 0.5;
1560        }
1561}
1562
1563unsigned char *loadjpg(char *filename, unsigned long *width, unsigned long *height, unsigned long *rowbytes, int *channels, int denom)
1564{
1565        struct jpeg_decompress_struct cinfo;
1566        struct jpeg_decompress_struct *ciptr = &cinfo;
1567        struct jpgerror jerr;
1568        FILE *fd = NULL;
1569        unsigned char *buf = NULL;
1570
1571        fd = fopen(filename, "rb");
1572        if(fd == NULL)
1573        {
1574                perr("open jpg file %s", filename);
1575                return NULL;
1576        }
1577
1578        ciptr->err = jpeg_std_error(&jerr.jerr);
1579        jerr.jerr.error_exit = jpgswerror;
1580        if(setjmp(jerr.setjmpbuf))
1581        {
1582                jpeg_destroy_decompress(ciptr);
1583                fclose(fd);
1584                return NULL;
1585        }
1586
1587        jpeg_create_decompress(ciptr);
1588        jpeg_stdio_src(ciptr, fd);
1589        jpeg_read_header(ciptr, TRUE);
1590        ciptr->out_color_space = JCS_RGB;
1591
1592        //faster but less quality
1593        ciptr->dct_method = JDCT_IFAST;
1594        ciptr->do_fancy_upsampling = FALSE;
1595        ciptr->two_pass_quantize = FALSE;
1596        ciptr->dither_mode = JDITHER_ORDERED;
1597
1598        if(denom < 1) denom = 1;
1599        if(denom > 16) denom = 16;
1600        ciptr->scale_num = 1;
1601        ciptr->scale_denom = denom;
1602
1603        jpeg_start_decompress(ciptr);
1604
1605        *width = ciptr->output_width;
1606        *height = ciptr->output_height;
1607        *channels = ciptr->output_components;
1608        *rowbytes = ciptr->output_width * ciptr->output_components;
1609
1610        if(ciptr->output_components == 3)
1611        {
1612                JSAMPLE *lb = (JSAMPLE *)(*ciptr->mem->alloc_small)((j_common_ptr) ciptr, JPOOL_PERMANENT, ciptr->output_width * ciptr->output_components);
1613                buf = malloc(ciptr->output_height * ciptr->output_width * ciptr->output_components);
1614                if(buf == NULL)
1615                {
1616                        err("no mem");
1617                        jpeg_destroy_decompress(ciptr);
1618                        fclose(fd);
1619                        return NULL;
1620                }
1621
1622                unsigned char *bp = buf;
1623
1624                while(ciptr->output_scanline < ciptr->output_height)
1625                {
1626                        jpeg_read_scanlines(ciptr, &lb, 1);
1627                        memcpy(bp, lb, ciptr->output_width * ciptr->output_components);
1628                        bp += ciptr->output_width * ciptr->output_components;
1629                }
1630        }
1631
1632        jpeg_finish_decompress(ciptr);
1633        jpeg_destroy_decompress(ciptr);
1634        fclose(fd);
1635        return(buf);
1636}
1637
1638unsigned char* savejpg(char* filename, int width, int height, int channels, int newwidth, int newheight, int quality, unsigned char *buf)
1639{
1640        struct jpeg_compress_struct cinfo;
1641        struct jpeg_error_mgr jerr;
1642        FILE* outfile = NULL;
1643        JSAMPROW pointer[1];
1644        int stride;
1645
1646        if(buf == NULL) return buf;
1647
1648        if((outfile = fopen(filename, "wb")) == NULL)
1649        {
1650                perr("jpeg can't open %s", filename);
1651                return buf;
1652        }
1653
1654        if(width != newwidth || height != newheight)
1655        {
1656                buf = scale(buf, width, height, channels, newwidth, newheight, 1);
1657                if(buf == NULL)
1658                {
1659                        fclose(outfile);
1660                        return buf;
1661                }
1662        }
1663
1664        cinfo.err = jpeg_std_error(&jerr);
1665        jpeg_create_compress(&cinfo);
1666        jpeg_stdio_dest(&cinfo, outfile);
1667
1668        cinfo.image_width = newwidth;
1669        cinfo.image_height = newheight;
1670        cinfo.input_components = channels;
1671        cinfo.in_color_space = JCS_RGB;
1672        jpeg_set_defaults(&cinfo);
1673        jpeg_set_quality(&cinfo, quality, TRUE);
1674        jpeg_start_compress(&cinfo, TRUE);
1675        stride = newwidth * channels;
1676
1677        while(cinfo.next_scanline < cinfo.image_height)
1678        {
1679                pointer[0] = &buf[cinfo.next_scanline * stride];
1680                jpeg_write_scanlines(&cinfo, pointer, 1);
1681        }
1682
1683        jpeg_finish_compress(&cinfo);
1684        fclose(outfile);
1685        jpeg_destroy_compress(&cinfo);
1686        return buf;
1687}
1688
1689int drawjpgsw(struct jpeg_decompress_struct* cinfo, unsigned char* buf, int posx, int posy, int width, int height, int colbytes, int mwidth, int mheight, int scalewidth, int scaleheight, int halign, int valign)
1690{
1691        int aktline = 0, x = 0, py = 0, px = 0, row_stride = 0, pyw = 0;
1692        int width4 = width * 4, width8 = width * 8, aktline1 = 0;
1693        unsigned char red, green, blue;
1694        unsigned long color = 0;
1695        JSAMPARRAY buffer = NULL;
1696        unsigned char *tmpbuf = NULL;
1697        unsigned char *scalebuf = NULL;
1698
1699        if(cinfo == NULL && buf == NULL) return 1;
1700
1701        if(cinfo != NULL)
1702        {
1703                row_stride = cinfo->output_width * cinfo->output_components;
1704                buffer = (cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, JPOOL_IMAGE, row_stride, 1);
1705        }
1706        else
1707                row_stride = width * colbytes;
1708
1709        if(accelfb != NULL && accelfb->varfbsize > width8 && (scalewidth != 0 || scaleheight != 0) && (scalewidth != width || scaleheight != height))
1710        {
1711                if(halign == CENTER)
1712                        posx += (mwidth >> 1) - (scalewidth >> 1);
1713                else if(halign == RIGHT)
1714                        posx += mwidth - scalewidth;
1715                if(valign == MIDDLE)
1716                        posy += (mheight >> 1) - (scaleheight >> 1);
1717                else if(valign == BOTTOM)
1718                        posy += mheight - scaleheight;
1719
1720                int nposy = posy;
1721                py = -1;
1722
1723                m_lock(&status.accelfbmutex, 16);
1724                if(cinfo != NULL) aktline = cinfo->output_scanline;
1725
1726                if(cinfo != NULL)
1727                {
1728                        while(aktline < height)
1729                        {
1730                                jpeg_read_scanlines(cinfo, buffer, 1);
1731                                aktline = cinfo->output_scanline;
1732
1733                                py++;
1734                                pyw = width * py;
1735                                for(x = 0; x < width; x++)
1736                                {
1737                                        px = colbytes * x;
1738                                        red = buffer[0][px];
1739                                        if(colbytes > 2)
1740                                        {
1741                                                green = buffer[0][px + 1];
1742                                                blue = buffer[0][px + 2];
1743                                                color = (255 << 24) | (red << 16) | (green << 8) | blue;
1744                                        }
1745                                        else
1746                                                color = (255 << 24) | (red << 16) | (red << 8) | red;
1747
1748                                        drawpixelfb(accelfb, pyw + x, 0, color);
1749                                }
1750
1751                                if((py * width4) + (width8) >= accelfb->varfbsize)
1752                                {
1753                                        py++;
1754                                        if(scaleheight > 0)
1755                                        {
1756                                                float tmp = (float)height / (float)scaleheight;
1757                                                if(tmp > 0)
1758                                                {
1759                                                        tmp = (float)py / tmp;
1760                                                        blitscale(posx, nposy, width, py, scalewidth, (int)(tmp + 0.5), 0);
1761                                                        nposy += (int)(tmp + 0.5);
1762                                                }
1763                                        }
1764                                        py = -1;
1765                                }
1766                        }
1767                }
1768                else
1769                {
1770                        while(aktline < height)
1771                        {
1772                                aktline1 = aktline * row_stride;
1773                                aktline++;
1774
1775                                py++;
1776                                pyw = width * py;
1777                                for(x = 0; x < width; x++)
1778                                {
1779                                        px = colbytes * x;
1780                                        red = buf[aktline1 + px];
1781                                        if(colbytes > 2)
1782                                        {
1783                                                green = buf[aktline1 + (px + 1)];
1784                                                blue = buf[aktline1 + (px + 2)];
1785                                                color = (255 << 24) | (red << 16) | (green << 8) | blue;
1786                                        }
1787                                        else
1788                                                color = (255 << 24) | (red << 16) | (red << 8) | red;
1789
1790                                        drawpixelfb(accelfb, pyw + x, 0, color);
1791                                }
1792
1793                                if((py * width4) + (width8) >= accelfb->varfbsize)
1794                                {
1795                                        py++;
1796                                        if(scaleheight > 0)
1797                                        {
1798                                                float tmp = (float)height / (float)scaleheight;
1799                                                if(tmp > 0)
1800                                                {
1801                                                        tmp = (float)py / tmp;
1802                                                        blitscale(posx, nposy, width, py, scalewidth, (int)(tmp + 0.5), 0);
1803                                                        nposy += (int)(tmp + 0.5);
1804                                                }
1805                                        }
1806                                        py = -1;
1807                                }
1808                        }
1809                }
1810
1811                //blit the rest
1812                if(py > -1 && scaleheight > 0)
1813                {
1814                        int tmp = scaleheight - (nposy - posy);
1815                        blitscale(posx, nposy, width, py, scalewidth, tmp, 0);
1816                }
1817                m_unlock(&status.accelfbmutex, 16);
1818        }
1819        else if((scalewidth != 0 || scaleheight != 0) && (scalewidth != width || scaleheight != height) && cinfo != NULL)
1820        {
1821                if(halign == CENTER)
1822                        posx += (mwidth >> 1) - (scalewidth >> 1);
1823                else if(halign == RIGHT)
1824                        posx += mwidth - scalewidth;
1825                if(valign == MIDDLE)
1826                        posy += (mheight >> 1) - (scaleheight >> 1);
1827                else if(valign == BOTTOM)
1828                        posy += mheight - scaleheight;
1829
1830                int i = 0;
1831                int location = 0;
1832                tmpbuf = (unsigned char*)malloc(width*height*3);
1833                aktline = cinfo->output_scanline;
1834                while(aktline < height)
1835                {
1836                        jpeg_read_scanlines(cinfo, buffer, 1);
1837                        aktline = cinfo->output_scanline;
1838                        for(i=0; i<width*3; i++)
1839                                tmpbuf[location++] = buffer[0][i];
1840                }
1841                //extendet_scale wegen schreibfehler in alter config
1842                if(getconfigint("extended_scale", NULL) == 1 || getconfigint("extendet_scale", NULL) == 1)
1843                        scalebuf = resize(tmpbuf, width, height, scalewidth, scaleheight, 2, NULL, 1);
1844                else
1845                        scalebuf = resize(tmpbuf, width, height, scalewidth, scaleheight, 1, NULL, 1);
1846
1847                aktline = 0;
1848                while(aktline < scaleheight)
1849                {
1850                        py = (posy + aktline) * skinfb->width;
1851                        aktline1 = aktline * scalewidth * colbytes;
1852                        for(x = 0; x < scalewidth; x++)
1853                        {
1854                                px = colbytes * x;
1855                                red = scalebuf[px + aktline1];
1856
1857                                if(colbytes > 2)
1858                                {
1859                                        green = scalebuf[aktline1 + (px + 1)];
1860                                        blue = scalebuf[aktline1 + (px + 2)];
1861                                        color = (255 << 24) | (red << 16) | (green << 8) | blue;
1862                                }
1863                                else
1864                                        color = (255 << 24) | (red << 16) | (red << 8) | red;
1865
1866                                drawpixelfast(posx + x, py, color);
1867                        }
1868                        aktline++;
1869                }
1870                free(scalebuf);
1871        }
1872        else
1873        {
1874                if(width > mwidth) width = mwidth;
1875                if(height > mheight) height = mheight;
1876
1877                if(halign == CENTER)
1878                        posx += (mwidth >> 1) - (width >> 1);
1879                else if(halign == RIGHT)
1880                        posx += mwidth - width;
1881                if(valign == MIDDLE)
1882                        posy += (mheight >> 1) - (height >> 1);
1883                else if(valign == BOTTOM)
1884                        posy += mheight - height;
1885
1886                if(cinfo != NULL) aktline = cinfo->output_scanline;
1887                while(aktline < height)
1888                {
1889                        if(cinfo != NULL)
1890                        {
1891                                jpeg_read_scanlines(cinfo, buffer, 1);
1892                                aktline = cinfo->output_scanline;
1893                        }
1894                        else
1895                                aktline++;
1896
1897                        aktline1 = (aktline - 1) * row_stride;
1898
1899                        py = (posy + aktline - 1) * skinfb->width;
1900                        for(x = 0; x < width; x++)
1901                        {
1902                                px = colbytes * x;
1903
1904                                if(cinfo != NULL)
1905                                        red = buffer[0][px];
1906                                else
1907                                        red = buf[aktline1 + px];
1908
1909                                if(colbytes > 2)
1910                                {
1911                                        if(cinfo != NULL)
1912                                        {
1913                                                green = buffer[0][px + 1];
1914                                                blue = buffer[0][px + 2];
1915                                                color = (255 << 24) | (red << 16) | (green << 8) | blue;
1916                                        }
1917                                        else
1918                                        {
1919                                                green = buf[aktline1 + (px + 1)];
1920                                                blue = buf[aktline1 + (px + 2)];
1921                                                color = (255 << 24) | (red << 16) | (green << 8) | blue;
1922                                        }
1923                                }
1924                                else
1925                                        color = (255 << 24) | (red << 16) | (red << 8) | red;
1926
1927                                drawpixelfast(posx + x, py, color);
1928                        }
1929                }
1930        }
1931
1932        return 0;
1933}
1934
1935int readjpgsw(const char* filename, int posx, int posy, int mwidth, int mheight, int scalewidth, int scaleheight, int halign, int valign, int quality)
1936{
1937        struct jpeg_decompress_struct cinfo;
1938        struct jpgerror jerr;
1939        FILE* fd = NULL;
1940        int width = 0, height = 0;
1941
1942        fd = fopen(filename, "rb");
1943        if(fd == NULL)
1944        {
1945                perr("open jpg file %s", filename);
1946                return 1;
1947        }
1948
1949        cinfo.err = jpeg_std_error(&jerr.jerr);
1950        jerr.jerr.error_exit = jpgswerror;
1951        if(setjmp(jerr.setjmpbuf))
1952        {
1953                jpeg_destroy_decompress(&cinfo);
1954                fclose(fd);
1955                return 1;
1956        }
1957
1958        jpeg_create_decompress(&cinfo);
1959        jpeg_stdio_src(&cinfo, fd);
1960        jpeg_read_header(&cinfo, TRUE);
1961
1962        cinfo.out_color_space = JCS_RGB;
1963
1964        if(quality == 0)
1965        {
1966                cinfo.dct_method = JDCT_IFAST;
1967                cinfo.do_fancy_upsampling = FALSE;
1968                cinfo.two_pass_quantize = FALSE;
1969                cinfo.dither_mode = JDITHER_ORDERED;
1970        }
1971
1972        cinfo.scale_num = 1;
1973        cinfo.scale_denom = 1;
1974
1975        width = cinfo.image_width;
1976        height = cinfo.image_height;
1977
1978        if(scalewidth != 0 || scaleheight != 0)
1979        {
1980                //auto scale to mwidth / mheight
1981                if(scalewidth == 1 && scaleheight == 1)
1982                        calcautoscale(width, height, mwidth, mheight, &scalewidth, &scaleheight);
1983                else if(scalewidth == 2 && scaleheight == 2)
1984                        calcautoscale(width, height, mwidth, mheight - 25, &scalewidth, &scaleheight);
1985
1986                if(scalewidth == 0) scalewidth = width;
1987                if(scaleheight == 0) scaleheight = height;
1988                if(scalewidth > mwidth) scalewidth = mwidth;
1989                if(scaleheight > mheight) scaleheight = mheight;
1990
1991                if(quality == 0 || quality == 1)
1992                {
1993                        int tmpwidth = width;
1994                        int tmpheight = height;
1995                        while(scalewidth < tmpwidth || scaleheight < tmpheight)
1996                        {
1997                                tmpwidth /= 2; tmpheight /= 2; cinfo.scale_denom *= 2;
1998                                if(cinfo.scale_denom > 8) break;
1999                        }
2000                }
2001        }
2002
2003        jpeg_start_decompress(&cinfo);
2004        width = cinfo.output_width;
2005        height = cinfo.output_height;
2006
2007        drawjpgsw(&cinfo, NULL, posx, posy, width, height, cinfo.output_components, mwidth, mheight, scalewidth, scaleheight, halign, valign);
2008
2009        jpeg_finish_decompress(&cinfo);
2010        jpeg_destroy_decompress(&cinfo);
2011        fclose(fd);
2012        return 0;
2013}
2014
2015unsigned char* readpng(const char* filename, unsigned long* width, unsigned long* height, unsigned long* rowbytes, int* channels, int posx, int posy, int mwidth, int mheight, int halign, int valign)
2016{
2017        FILE *fd = NULL;
2018        int ret, bit_depth, color_type;
2019        unsigned char *buf = NULL;
2020        static png_structp png_ptr = NULL;
2021        static png_infop info_ptr = NULL;
2022        double gamma;
2023        png_uint_32 y;
2024        png_bytepp row_pointers = NULL;
2025        png_bytep sig = NULL;
2026
2027        fd = fopen(filename, "rb");
2028        if(fd == NULL)
2029        {
2030                perr("open png file %s", filename);
2031                return NULL;
2032        }
2033
2034        sig = malloc(8);
2035        if(sig == NULL)
2036        {
2037                err("no memory");
2038                fclose(fd);
2039                return NULL;
2040        }
2041
2042        fread(sig, 1, 8, fd);
2043        ret = png_check_sig(sig, 8);
2044        if(ret == 0)
2045        {
2046                err("%s is not a PNG file", filename);
2047                free(sig);
2048                fclose(fd);
2049                return NULL;
2050        }
2051
2052        png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
2053        if(png_ptr == NULL)
2054        {
2055                err("%s no memory", filename);
2056                free(sig);
2057                fclose(fd);
2058                return NULL;
2059        }
2060
2061        info_ptr = png_create_info_struct(png_ptr);
2062        if(info_ptr == NULL)
2063        {
2064                png_destroy_read_struct(&png_ptr, NULL, NULL);
2065                err("%s no memory", filename);
2066                free(sig);
2067                fclose(fd);
2068                return NULL;
2069        }
2070
2071        if(png_jmpbuf(png_ptr) == NULL)
2072        {
2073                png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
2074                err("%s unknown error (png_jmpbuf = NULL)", filename);
2075                free(sig);
2076                fclose(fd);
2077                return NULL;
2078        }
2079
2080        ret = setjmp(png_jmpbuf(png_ptr));
2081        if(ret != 0)
2082        {
2083                png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
2084                err("%s unknown error (libpng longjmp)", filename);
2085                free(sig);
2086                fclose(fd);
2087                return NULL;
2088        }
2089
2090        png_init_io(png_ptr, fd);
2091        png_set_sig_bytes(png_ptr, 8);
2092        png_read_info(png_ptr, info_ptr);
2093        png_get_IHDR(png_ptr, info_ptr, (png_uint_32*)width, (png_uint_32*)height, &bit_depth, &color_type, NULL, NULL, NULL);
2094
2095        if(color_type == PNG_COLOR_TYPE_PALETTE)
2096                png_set_expand(png_ptr);
2097        if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
2098                png_set_expand(png_ptr);
2099        if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
2100                png_set_expand(png_ptr);
2101        if(bit_depth == 16)
2102                png_set_strip_16(png_ptr);
2103        if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2104                png_set_gray_to_rgb(png_ptr);
2105        if(png_get_gAMA(png_ptr, info_ptr, &gamma))
2106                png_set_gamma(png_ptr, 2.2, gamma);
2107
2108        png_read_update_info(png_ptr, info_ptr);
2109        *rowbytes = png_get_rowbytes(png_ptr, info_ptr);
2110        *channels = (int)png_get_channels(png_ptr, info_ptr);
2111
2112        buf = malloc((*rowbytes) * (*height));
2113        if(buf == NULL)
2114        {
2115                png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
2116                err("%s no memory", filename);
2117                free(sig);
2118                fclose(fd);
2119                return NULL;
2120        }
2121
2122        row_pointers = (png_bytepp)malloc((*height) * sizeof(png_bytep));
2123        if(row_pointers == NULL)
2124        {
2125                png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
2126                err("%s unknown error", filename);
2127                free(sig);
2128                fclose(fd);
2129                return NULL;
2130        }
2131
2132        for (y = 0; y < (*height); ++y)
2133                row_pointers[y] = (png_bytep)buf + y * (*rowbytes);
2134
2135        png_read_image(png_ptr, row_pointers);
2136        free(row_pointers);
2137        row_pointers = NULL;
2138
2139        png_read_end(png_ptr, NULL);
2140        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
2141
2142        free(sig);
2143        fclose(fd);
2144
2145        debug(100, "png width=%ld height=%ld channels=%d rowbytes=%ld", *width, *height, *channels, *rowbytes);
2146
2147        return buf;
2148}
2149
2150void drawpic(const char* filename, int posx, int posy, int scalewidth, int scaleheight, int mwidth, int mheight, int halign, int valign, int transparent, int quality, int add)
2151{
2152        unsigned char *buf = NULL, *scalebuf = NULL;
2153        int memfd = -1, py = 0, pyh = 0, pxw = 0, diff = 0;
2154        unsigned long width, height, rowbytes;
2155        int channels, length;
2156        unsigned char *src;
2157        png_uint_32 y, x;
2158        struct pic* picnode = NULL;
2159        int decoding = getconfigint("pichwdecode", NULL);
2160        int pictype = 0; //0 = png, 1 = jpg HW, 2 = jpg SW
2161        unsigned char r = 0, g = 0, b = 0, ralpha = 0;
2162
2163        if(filename == NULL) return;
2164
2165        length = strlen(filename);
2166        if(filename[length - 1] == 'g' && filename[length - 2] == 'n' && filename[length - 3] == 'p')
2167                pictype = 0;
2168        else if(decoding == 1)
2169                pictype = 1;
2170        else
2171                pictype = 2;
2172
2173        picnode = getpic((char*)filename);
2174        if(picnode == NULL)
2175        {
2176                if(pictype == 0)
2177                        buf = readpng(filename, &width, &height, &rowbytes, &channels, 0, 0, 0, 0, 0, 0);
2178                else if(pictype == 1)
2179                        readjpg(filename, &width, &height, &rowbytes, &channels, &buf, &memfd);
2180                else if(pictype == 2 && add == 0)
2181                        readjpgsw(filename, posx, posy, mwidth, mheight, scalewidth, scaleheight, halign, valign, quality);
2182                else if(pictype == 2 && add == 1)
2183                        buf = loadjpg((char*)filename, &width, &height, &rowbytes, &channels, 1);
2184                if(add == 1)
2185                        picnode = addpic((char*)filename, buf, memfd, width, height, rowbytes, channels, 0, 0, NULL);
2186        }
2187        else
2188        {
2189                buf = picnode->picbuf;
2190                width = picnode->width;
2191                height = picnode->height;
2192                rowbytes = picnode->rowbytes;
2193                channels = picnode->channels;
2194                memfd = picnode->memfd;
2195        }
2196
2197        if(buf == NULL) return;
2198
2199        if(pictype == 0 && (scalewidth != 0 || scaleheight != 0) && (scalewidth != width || scaleheight != height))
2200        {
2201                //auto scale to mwidth / mheight
2202                if(scalewidth == 1 && scaleheight == 1)
2203                        calcautoscale(width, height, mwidth, mheight, &scalewidth, &scaleheight);
2204                else if(scalewidth == 2 && scaleheight == 2)
2205                        calcautoscale(width, height, mwidth, mheight - 25, &scalewidth, &scaleheight);
2206
2207                if(scalewidth == 0) scalewidth = width;
2208                if(scaleheight == 0) scaleheight = height;
2209                if(picnode == NULL)
2210                        scalebuf = scale(buf, rowbytes / channels, height, channels, scalewidth, scaleheight, 1);
2211                else
2212                {
2213                        scalebuf = scale(buf, rowbytes / channels, height, channels, scalewidth, scaleheight, 0);
2214                        buf = NULL;
2215                        picnode = NULL;
2216                }
2217                if(scalebuf != NULL)
2218                {
2219                        buf = scalebuf;
2220                        width = scalewidth;
2221                        height = scaleheight;
2222                        rowbytes = scalewidth * (channels);
2223                }
2224        }
2225
2226        if(pictype == 0)
2227        {
2228                if(width > mwidth) width = mwidth;
2229                if(height > mheight) height = mheight;
2230
2231                if(halign == CENTER)
2232                        posx += (mwidth >> 1) - (width >> 1);
2233                else if(halign == RIGHT)
2234                        posx += mwidth - width;
2235                if(valign == MIDDLE)
2236                        posy += (mheight >> 1) - (height >> 1);
2237                else if(valign == BOTTOM)
2238                        posy += mheight - height;
2239
2240                py = (posy * skinfb->width) + posx;
2241                pyh = py + (height * skinfb->width);
2242                src = buf;
2243                diff = rowbytes - (width * channels);
2244
2245                if(channels == 3)
2246                {
2247                        for(y = py; y < pyh; y += skinfb->width)
2248                        {
2249                                pxw = y + width;
2250                                for(x = y; x < pxw; x++)
2251                                {
2252                                        skinfb->fblong[x] = (255 << 24) | (src[0] << 16) | (src[1] << 8) | src[2];
2253                                        src += 3;
2254                                }
2255                                src += diff;
2256                        }
2257                }
2258                else
2259                {
2260                        for(y = py; y < pyh; y += skinfb->width)
2261                        {
2262                                pxw = y + width;
2263
2264                                if(transparent == 1)
2265                                {
2266                                        for(x = y; x < pxw; x++)
2267                                        {
2268                                                if(src[3] < 10)
2269                                                {
2270                                                        src += 4;
2271                                                        continue;
2272                                                }
2273                                                skinfb->fblong[x] = (src[3] << 24) | (src[0] << 16) | (src[1] << 8) | src[2];
2274                                                src += 4;
2275                                        }
2276                                }
2277                                else
2278                                {
2279                                        for(x = y; x < pxw; x++)
2280                                        {
2281                                                //renderquality 255-0 = best
2282                                                if(src[3] > 200)
2283                                                        skinfb->fblong[x] = (255 << 24) | (src[0] << 16) | (src[1] << 8) | src[2];
2284                                                else if(src[3] < 50)
2285                                                {
2286                                                        src += 4;
2287                                                        continue;
2288                                                }
2289                                                else
2290                                                {
2291                                                        ralpha = 255 - src[3];
2292                                                        alpha_composite(r, src[0], src[3], ralpha, (skinfb->fblong[x] & 0xff0000) >> 16);
2293                                                        alpha_composite(g, src[1], src[3], ralpha, (skinfb->fblong[x] & 0x00ff00) >> 8);
2294                                                        alpha_composite(b, src[2], src[3], ralpha, skinfb->fblong[x] & 0xff);
2295                                                        skinfb->fblong[x] = (255 << 24) | r << 16 | g << 8 | b;
2296                                                }
2297                                                src += 4;
2298                                        }
2299                                }
2300                                src += diff;
2301                        }
2302                }
2303        }
2304        else if(pictype == 1 && memfd > -1)
2305                blitjpg(buf, posx, posy, width, height, scalewidth, scaleheight, mwidth, mheight, halign, valign);
2306        else if(pictype == 2 && picnode != NULL)
2307                drawjpgsw(NULL, buf, posx, posy, width, height, rowbytes / width, mwidth, mheight, scalewidth, scaleheight, halign, valign);
2308
2309        if(picnode == NULL)
2310        {
2311                if(pictype == 0)
2312                        free(buf);
2313                else if(pictype == 1)
2314                        freebpamem(memfd, buf, width * height * 3);
2315        }
2316}
2317
2318//flag 0: don't del outside
2319//flag 1: del outside
2320void drawcircle(int x0, int y0, int radius, int startangle, int endangle, long color, int transparent, char* bg, int flag)
2321{
2322        float d = (5/4.0) - radius, theta;
2323        int x = 0, y = radius, px = 0, py = 0;
2324
2325        transparent = (transparent - 255) * -1;
2326        unsigned long tmpcol = color | ((transparent & 0xff) << 24);
2327
2328        while(y > x)
2329        {
2330                if(d < 0)
2331                        d += 2 * x + 3;
2332                else
2333                {
2334                        d += (2 * x) - (2 * y) + 5;
2335                        y--;
2336                }
2337                x++;
2338
2339                theta = (atan((float)y / x)) * (180 / 3.14);
2340
2341                //rt2
2342                if(theta >= startangle && theta <= endangle)
2343                {
2344                        px = x0 + x;
2345                        py = (y0 - y) * skinfb->width;
2346                        drawpixelfast(px, py, tmpcol);
2347                        if(flag == 1)
2348                        {
2349                                int i = radius - x;
2350                                int r = radius - y;
2351                                for(; i > 0; i--)
2352                                        drawpixelfast(px + i, py, getpixelbuf(bg, x + i - 1, r, radius));
2353                        }
2354                }
2355                //rb2
2356                if(360 - theta >= startangle && 360 - theta <= endangle)
2357                {
2358                        px = x0 + x;
2359                        py = (y0 + y) * skinfb->width;
2360                        drawpixelfast(px, py, tmpcol);
2361                        if(flag == 1)
2362                        {
2363                                int i = radius - x;
2364                                int r = y - 1;
2365                                for(; i > 0; i--)
2366                                        drawpixelfast(px + i, py, getpixelbuf(bg, x + i - 1, r, radius));
2367                        }
2368                }
2369                //rt1
2370                if(90 - theta >= startangle && 90 - theta <= endangle)
2371                {
2372                        px = x0 + y;
2373                        py = (y0 - x) * skinfb->width;
2374                        drawpixelfast(px, py, tmpcol);
2375                        if(flag == 1)
2376                        {
2377                                int i = radius - y;
2378                                int r = radius - x;
2379                                for(; i > 0; i--)
2380                                        drawpixelfast(px + i, py, getpixelbuf(bg, y + i - 1, r, radius));
2381                        }
2382                }
2383                //rb1
2384                if(270 + theta >= startangle && 270 + theta <= endangle)
2385                {
2386                        px = x0 + y;
2387                        py = (y0 + x) * skinfb->width;
2388                        drawpixelfast(px, py, tmpcol);
2389                        if(flag == 1)
2390                        {
2391                                int i = radius - y;
2392                                int r = x - 1;
2393                                for(; i > 0; i--)
2394                                        drawpixelfast(px + i, py, getpixelbuf(bg, y + i - 1, r, radius));
2395                        }
2396                }
2397                //lt2
2398                if(180 - theta >= startangle && 180 - theta <= endangle)
2399                {
2400                        px = x0 - x;
2401                        py = (y0 - y) * skinfb->width;
2402                        drawpixelfast(px, py, tmpcol);
2403                        if(flag == 1)
2404                        {
2405                                int i = radius - x;
2406                                int r = radius - y;
2407                                for(; i > 0; i--)
2408                                        drawpixelfast(px - i, py, getpixelbuf(bg, radius - x - i, r, radius));
2409                        }
2410                }
2411                //lb2
2412                if(180 + theta >= startangle && 180 + theta <= endangle)
2413                {
2414                        px = x0 - x;
2415                        py = (y0 + y) * skinfb->width;
2416                        drawpixelfast(px, py, tmpcol);
2417                        if(flag == 1)
2418                        {
2419                                int i = radius - x;
2420                                int r = y - 1;
2421                                for(; i > 0; i--)
2422                                        drawpixelfast(px - i, py, getpixelbuf(bg, radius - x - i, r, radius));
2423                        }
2424                }
2425                //lt1
2426                if(90 + theta >= startangle && 90 + theta <= endangle)
2427                {
2428                        px = x0 - y;
2429                        py = (y0 - x) * skinfb->width;
2430                        drawpixelfast(px, py, tmpcol);
2431                        if(flag == 1)
2432                        {
2433                                int i = radius - y;
2434                                int r = radius - x;
2435                                for(; i > 0; i--)
2436                                        drawpixelfast(px - i, py, getpixelbuf(bg, radius - y - i, r, radius));
2437                        }
2438                }
2439                //lb1
2440                if(270 - theta >= startangle && 270 - theta <= endangle)
2441                {
2442                        px = x0 - y;
2443                        py = (y0 + x) * skinfb->width;
2444                        drawpixelfast(px, py, tmpcol);
2445                        if(flag == 1)
2446                        {
2447                                int i = radius - y;
2448                                int r = x - 1;
2449                                for(; i > 0; i--)
2450                                        drawpixelfast(px - i, py, getpixelbuf(bg, radius - y - i , r, radius));
2451                        }
2452                }
2453        }
2454}
2455
2456int drawchar(struct font* font, FT_ULong currentchar, int posx, int posy, int mwidth, int height, long color, int transparent, int charspace, int test)
2457{
2458        int space = 0, y = 0, x = 0, py = 0, pxw = 0, pyh = 0, max = 220, min = 35;
2459        FT_UInt glyphindex;
2460        FT_Vector kerning;
2461        FT_Error ret;
2462        FTC_SBit sbit;
2463        unsigned long tmpcol = 0;
2464        unsigned char red, green, blue, r, g, b;
2465        unsigned char* src = NULL;
2466        unsigned char ralpha = 0;
2467
2468        if(currentchar == 32) space = 1;
2469
2470        glyphindex = FT_Get_Char_Index(font->face, currentchar);
2471        if(glyphindex == 0)
2472        {
2473                debug(100, "FT_Get_Char_Index for char %x %c failed", (int)currentchar, (int)currentchar);
2474                return 0;
2475        }
2476
2477        FTC_Node anode;
2478        ret = FTC_SBitCache_Lookup(font->cache, &font->desc, glyphindex, &sbit, &anode);
2479        if(ret != 0)
2480        {
2481                err("FTC_SBitCache_Lookup for char %x %c failed. Error: 0x%.2X", (int)currentchar, (int)currentchar, ret);
2482                return 0;
2483        }
2484
2485        if(font->use_kerning)
2486        {
2487                FT_Get_Kerning(font->face, font->prev_glyphindex, glyphindex, ft_kerning_default, &kerning);
2488                font->prev_glyphindex = glyphindex;
2489                kerning.x >>= 6;
2490        }
2491        else
2492                kerning.x = 0;
2493
2494        if(test == 1 || space == 1)
2495                return sbit->xadvance + kerning.x + charspace;
2496
2497        if(posx + sbit->xadvance > mwidth)
2498                return -1;
2499
2500        if(status.fasttextrender == 1)
2501        {
2502                max = 150;
2503                min = 100;
2504        }
2505
2506        red = (color & 0xff0000) >> 16;
2507        green = (color & 0x00ff00) >> 8;
2508        blue = color & 0xff;
2509        transparent = transparent & 0xff;
2510        tmpcol = color | transparent << 24;
2511        posy = posy + height - sbit->top;
2512        posx = posx + sbit->left + kerning.x;
2513
2514        py = (posy * skinfb->width) + posx;
2515        pyh = py + (sbit->height * skinfb->width);
2516        src = sbit->buffer;
2517
2518        for(y = py; y < pyh; y += skinfb->width)
2519        {
2520                pxw = y + sbit->pitch;
2521                for(x = y; x < pxw; x++)
2522                {
2523                        if(src[0] > min)
2524                        {
2525                                //renderquality 255-0 = best
2526                                if(src[0] > max)
2527                                        skinfb->fblong[x] = tmpcol;
2528                                else
2529                                {
2530                                        ralpha = 255 - src[0];
2531                                        alpha_composite(r, red, src[0], ralpha, (skinfb->fblong[x] & 0xff0000) >> 16);
2532                                        alpha_composite(g, green, src[0], ralpha, (skinfb->fblong[x] & 0x00ff00) >> 8);
2533                                        alpha_composite(b, blue, src[0], ralpha, skinfb->fblong[x] & 0xff);
2534                                        skinfb->fblong[x] = transparent << 24 | r << 16 | g << 8 | b;
2535                                }
2536                        }
2537                        src++;
2538                }
2539        }
2540
2541        return sbit->xadvance + kerning.x + charspace;
2542}
2543
2544void getstringwh(struct font* font, char *string, int *stringwidth, int *stringheight, int charspace)
2545{
2546        FT_ULong cret = 0;
2547        if(string == NULL) return;
2548
2549        while(*string != '\0' && *string != '\n')
2550        {
2551                string += strfreetype(string, &cret);
2552                *stringwidth += drawchar(font, cret, 0, 0, 0, 0, 0, 0, charspace, 1);
2553                string++;
2554        }
2555}
2556
2557int calcstrhalign(struct font* aktfont, char *string, int posx, int mwidth, int halign, int charspace)
2558{
2559        int stringwidth = 0, stringheight = 0;
2560        if(string == NULL) return 0;
2561
2562        switch(halign)
2563        {
2564                case TEXTCENTER:
2565                case CENTER:
2566                        getstringwh(aktfont, string, &stringwidth, &stringheight, charspace);
2567                        if(stringwidth < mwidth) posx += ((mwidth - stringwidth) >> 1);
2568                        break;
2569                case TEXTRIGHT:
2570                case RIGHT:
2571                        getstringwh(aktfont, string, &stringwidth, &stringheight, charspace);
2572                        if(stringwidth < mwidth) posx += mwidth - stringwidth;
2573                        break;
2574        }
2575        return posx;
2576}
2577
2578int calcstrvalign(char *string, int posy, int oldposy, int mheight, int fontsize, int linecount, int valign)
2579{
2580        if(string == NULL) return 0;
2581
2582        switch(valign)
2583        {
2584                case TEXTMIDDLE:
2585                case MIDDLE:
2586                        posy += (mheight >> 1) - ((fontsize * linecount) >> 1);
2587                        if(posy < oldposy) posy = oldposy;
2588                        break;
2589                case TEXTBOTTOM:
2590                case BOTTOM:
2591                        posy += mheight - (fontsize * linecount);
2592                        if(posy < oldposy) posy = oldposy;
2593                        break;
2594        }
2595
2596        return posy;
2597}
2598
2599struct font* setaktfont(char* fontname, int fontsize)
2600{
2601        struct font* aktfont = NULL;
2602
2603        if(fontname != NULL) aktfont = getfont(fontname);
2604        if(aktfont == NULL) aktfont = font;
2605
2606        aktfont->desc.width = fontsize;
2607        aktfont->desc.height = fontsize;
2608        aktfont->desc.flags = FT_LOAD_DEFAULT;
2609        aktfont->prev_glyphindex = 0;
2610
2611        return aktfont;
2612}
2613
2614void wrapstr(char* string, char* fontname, int fontsize, int mwidth, int charspace)
2615{
2616        int posx = 0;
2617        int stringheight = 0, stringwidth = 0;
2618        struct font* aktfont = NULL;
2619        char* tmpstr = NULL, *origstr = string;
2620        unsigned char c = 0;
2621
2622        if(string == NULL) return;
2623        aktfont = setaktfont(fontname, fontsize);
2624
2625        while(*string != '\0')
2626        {
2627                stringheight = 0; stringwidth = 0;
2628
2629                tmpstr = string;
2630
2631                while(*string != '\0' && *string != '\n' && *string != ' ' && *string != '-')
2632                        string++;
2633                if(*string == '\n')
2634                {
2635                        string++;
2636                        posx = 0;
2637                }
2638                else
2639                {
2640                        if(*string != '\0') string++;
2641                        c = *string; *string = '\0';
2642
2643                        getstringwh(aktfont, tmpstr, &stringwidth, &stringheight, charspace);
2644                        *string = c;
2645
2646                        posx += stringwidth;
2647                }
2648
2649                if(posx > mwidth && tmpstr > origstr)
2650                {
2651                        tmpstr--;
2652                        *tmpstr = '\n';
2653                        posx = stringwidth;
2654                }
2655        }
2656}
2657
2658//flag 0: normal
2659//flag 1: password
2660//flag 2: color
2661int drawstring(char* string, unsigned long linecount, unsigned int poscount, unsigned int markpos, int posx, int posy, int mwidth, int mheight, int halign, int valign, char* fontname, int fontsize, long color, int transparent, int wrap, int* lastposx, int* lastposy, int* len, int charspace, int flag)
2662{
2663        int charwidth = 0, lineend = 0;
2664        int charcount = 0;
2665        if(lastposy == NULL || *lastposy == 0) posy=posy + FONTPOSYOFFSET;
2666        int oldposx = posx, aktheight = 0, ret = 0;
2667        int oldposy = posy, oldmwidth = mwidth;
2668        struct font* aktfont = NULL;
2669        long tmpcol = color;
2670        FT_ULong cret = 0;
2671        char* tmpstr = NULL;
2672
2673        if(string == NULL || color == -1) return 1;
2674
2675        if(flag == 1)
2676        {
2677                string = mask(NULL, strlen(string), "*");
2678                tmpstr = string;
2679        }
2680
2681        if(flag == 2)
2682        {
2683                color = convertcol(string);
2684        }
2685
2686        transparent = (transparent - 255) * -1;
2687
2688        if(linecount < 2 && (fontsize == 0 || fontsize > mheight))
2689                fontsize = mheight;
2690
2691        aktfont = setaktfont(fontname, fontsize);
2692
2693        string = string + poscount;
2694
2695        if(fontsize < 5)
2696        {
2697                err("fontsize to small");
2698                if(flag == 1) free(tmpstr);
2699                return 1;
2700        }
2701
2702        posx = calcstrhalign(aktfont, string, posx, oldmwidth, halign, charspace);
2703        posy = calcstrvalign(string, posy, oldposy, mheight, fontsize, linecount, valign);
2704
2705        mwidth = posx + mwidth;
2706        aktheight += fontsize;
2707        if(aktheight > mheight)
2708        {
2709                err("to many textlines");
2710                if(flag == 1) free(tmpstr);
2711                return 1;
2712        }
2713
2714
2715
2716        while(*string != '\0')
2717        {
2718                charcount++;
2719                if(flag != 2)
2720                {
2721                        if(markpos == charcount)
2722                                color = status.markcol;
2723                        else
2724                                color = tmpcol;
2725                }
2726
2727                if(*string == '\n')
2728                {
2729                        if(linecount < 2) break;
2730                        lineend = 0;
2731                        aktheight += fontsize;
2732                        if(aktheight > mheight)
2733                        {
2734                                ret = 1;
2735                                break;
2736                        }
2737                        posy = posy + fontsize;
2738                        posx = oldposx;
2739                        string++;
2740                        posx = calcstrhalign(aktfont, string, posx, oldmwidth, halign, charspace);
2741                        continue;
2742                }
2743
2744                if(lineend == 1)
2745                {
2746                        string++;
2747                        continue;
2748                }
2749
2750                string += strfreetype(string, &cret);
2751
2752                if((charwidth = drawchar(aktfont, cret, posx, posy, mwidth, fontsize, color, transparent, charspace, 0)) == -1)
2753                        lineend = 1;
2754
2755                posx += charwidth;
2756                if(len != NULL) *len += charwidth;
2757                string++;
2758        }
2759        if(lastposx != NULL) *lastposx = posx;
2760        if(lastposy != NULL) *lastposy = posy + fontsize;
2761
2762        if(flag == 1) free(tmpstr);
2763        return ret;
2764}
2765
2766char* saverect(int posx, int posy, int width, int height)
2767{
2768        char* buf;
2769        int y = 0, len = width * skinfb->colbytes, px = posx * skinfb->colbytes;
2770
2771        buf = malloc(len * height);
2772        if(buf == NULL)
2773        {
2774                err("no memory");
2775                return NULL;
2776        }
2777
2778        for(y = 0; y < height; y++)
2779                memcpy(buf + len * y, skinfb->fb + ((y + posy) * skinfb->pitch) + px, len);
2780
2781        return buf;
2782}
2783
2784char* savescreen(struct skin* node)
2785{
2786        return saverect(node->rposx - node->shadowsize, node->rposy - node->shadowsize, node->rwidth + (node->shadowsize << 1), node->rheight + (node->shadowsize << 1));
2787}
2788
2789//flag 0: no free
2790//flag 1: free
2791void restorerectcheck(char* buf, int posx, int posy, int width, int height, int flag)
2792{
2793        int y = 0, len = width * skinfb->colbytes, px = posx * skinfb->colbytes;
2794
2795        if(buf != NULL)
2796        {
2797                for(y = 0; y < height; y++)
2798                        memcpy(skinfb->fb + ((y + posy) * skinfb->pitch) + px, buf + len * y,  len);
2799
2800                if(flag == 1)
2801                {
2802                        free(buf);
2803                        buf = NULL;
2804                }
2805        }
2806}
2807
2808void restorerect(char* buf, int posx, int posy, int width, int height)
2809{
2810        restorerectcheck(buf, posx, posy, width, height, 1);
2811}
2812
2813void restorescreen(char* buf, struct skin* node)
2814{
2815        restorerectcheck(buf, node->rposx - node->shadowsize, node->rposy - node->shadowsize, node->rwidth + (node->shadowsize << 1), node->rheight + (node->shadowsize << 1), 1);
2816}
2817
2818void restorescreennofree(char* buf, struct skin* node)
2819{
2820        restorerectcheck(buf, node->rposx - node->shadowsize, node->rposy - node->shadowsize, node->rwidth + (node->shadowsize << 1), node->rheight + (node->shadowsize << 1), 0);
2821}
2822
2823//*************** GOST LCD
2824void lcd_fillrect(int posx, int posy, int width, int height, long color, int transparent)
2825{
2826        int y, x;
2827        unsigned long tmpcol;
2828
2829        if(posx < 0) posx = 0;
2830        if(posx > skinfb->width) posx = skinfb->width;
2831        if(posy < 0) posy = 0;
2832        if(posy > skinfb->height) posy = skinfb->height;
2833        if(posx + width > skinfb->width) width = skinfb->width - posx;
2834        if(posy + height > skinfb->height) height = skinfb->height - posy;
2835
2836        if(width <= 0 || height <= 0) return;
2837
2838        transparent = (transparent - 255) * -1;
2839        tmpcol = color | ((transparent & 0xff) << 24);
2840
2841        for(y = 0; y < height; y++)
2842                for(x = 0; x < width; x++)
2843                        drawpixel(posx + x, posy + y, tmpcol);
2844}
2845
2846void lcd_drawrect(int posx, int posy, int width, int height, long color, int transparent)
2847{
2848        fillrect(posx, posy, width, 1, color, transparent);
2849        fillrect(posx, posy + height - 1, width, 1, color, transparent);
2850        fillrect(posx, posy, 1, height, color, transparent);
2851        fillrect(posx + width - 1, posy, 1, height, color, transparent);
2852}
2853//*************** GOST LCD
2854
2855/*
2856void fillrect(int posx, int posy, int width, int height, long color, int transparent)
2857{
2858        int r, g, b;
2859
2860        r = (color >> 16) & 0xFF;
2861        g = (color >> 8) & 0xFF;
2862        b = color & 0xFF;
2863
2864        primary->SetDrawingFlags(primary, DSDRAW_NOFX);
2865        primary->SetColor(primary, r, g, b, transparent);
2866        primary->FillRectangle(primary, posx, posy, width, height);
2867        primary->Flip(primary, NULL, DSFLIP_WAITFORSYNC);
2868}
2869
2870void drawrect(int posx, int posy, int width, int height, long color, int transparent)
2871{
2872        int r, g, b;
2873
2874        r = (color >> 16) & 0xFF;
2875        g = (color >> 8) & 0xFF;
2876        b = color & 0xFF;
2877
2878        primary->SetDrawingFlags(primary, DSDRAW_NOFX);
2879        primary->SetColor(primary, r, g, b, transparent);
2880        primary->DrawRectangle(primary, posx, posy, width, height);
2881        primary->Flip(primary, NULL, DSFLIP_WAITFORSYNC);
2882}
2883*/
2884
2885void fillrect(int posx, int posy, int width, int height, long color, int transparent)
2886{
2887        if(skinfb != lcdskinfb && skinfb != oledskinfb)
2888                blitrect(posx, posy, width, height, color, transparent, 0);
2889        else
2890                lcd_fillrect(posx, posy, width, height, color, transparent);
2891}
2892
2893void drawrect(int posx, int posy, int width, int height, long color, int transparent)
2894{
2895        if(skinfb != lcdskinfb && skinfb != oledskinfb)
2896                blitrect(posx, posy, width, height, color, transparent, 1);
2897        else
2898                lcd_drawrect(posx, posy, width, height, color, transparent);
2899}
2900
2901void clearrect(int posx, int posy, int width, int height)
2902{
2903        fillrect(posx, posy, width, height, 0, 255);
2904}
2905
2906void clearscreen(struct skin* node)
2907{
2908        m_lock(&status.drawingmutex, 0);
2909        clearrect(node->rposx, node->rposy, node->rwidth, node->rheight);
2910        clearshadow(node);
2911        m_unlock(&status.drawingmutex, 0);
2912}
2913
2914void clearscreennolock(struct skin* node)
2915{
2916        clearrect(node->rposx, node->rposy, node->rwidth, node->rheight);
2917        clearshadow(node);
2918}
2919
2920//flag 0 = horizontal
2921//flag 1 = vertical
2922//flag 2 = horizontal (begin to middle, middle to end)
2923//flag 3 = vertical (begin to middle, middle to end)
2924void drawgradient(int posx, int posy, int width, int height, long col1, long col2, int transparent, int flag)
2925{
2926        int p, i, x, y, steps, xstep, ystep, tmp = 0, r = 0;
2927        int xcount = 0, ycount = 0, owidth = width, oheight = height;
2928        unsigned char r3, g3, b3;
2929        unsigned long col = 0;
2930
2931        transparent = (transparent - 255) * -1;
2932
2933        if(flag == LEFTRIGHT || flag == LEFTMIDDLE)
2934        {
2935                if(flag == LEFTMIDDLE) width = width / 2;
2936                if(width < 10)
2937                        steps = width;
2938                if(width < 100)
2939                        steps = width / 2;
2940                else
2941                        steps = width / 5;
2942                xstep = width / steps;
2943                ystep = height;
2944        }
2945        else
2946        {
2947                if(flag == TOPMIDDLE) height = height / 2;
2948                if(height < 10)
2949                        steps = height;
2950                else if(height < 100)
2951                        steps = height / 2;
2952                else
2953                        steps = height / 5;
2954                xstep = width;
2955                ystep = height / steps;
2956        }
2957
2958        unsigned char r1 = (col1 >> 16) & 0xff;
2959        unsigned char g1 = (col1 >> 8) & 0xff;
2960        unsigned char b1 = col1 & 0xff;
2961
2962        unsigned char r2 = (col2 >> 16) & 0xff;
2963        unsigned char g2 = (col2 >> 8) & 0xff;
2964        unsigned char b2 = col2 & 0xff;
2965
2966        int yend = (posy + ystep) * skinfb->width;
2967        int xend = posx + xstep;
2968        posy *= skinfb->width;
2969
2970        for(i = 0; i < steps; i++)
2971        {
2972                p = steps - i;
2973                r3 = (r1 * p + r2 * i) / steps;
2974                g3 = (g1 * p + g2 * i) / steps;
2975                b3 = (b1 * p + b2 * i) / steps;
2976                col = (transparent << 24) | (r3 << 16) | (g3 << 8) | b3;
2977
2978                r = 0;
2979                for(y = posy; y < yend; y += skinfb->width)
2980                {
2981                        if(r == 0)
2982                        {
2983                                r = 1;
2984                                for(x = posx; x < xend; x++)
2985                                        drawpixelfast(x, y, col);
2986                        }
2987                        else
2988                                memcpy(skinfb->fb + (y + posx) * skinfb->colbytes, skinfb->fb + (posy + posx) * skinfb->colbytes, (xend - posx) * skinfb->colbytes);
2989                }
2990
2991                if(flag == LEFTRIGHT || flag == LEFTMIDDLE)
2992                {
2993                        posx += xstep;
2994                        xcount += xstep;
2995                        xend = posx + xstep;
2996                }
2997                else
2998                {
2999                        tmp = ystep * skinfb->width;
3000                        posy += tmp;
3001                        ycount += ystep;
3002                        yend = posy + tmp;
3003                }
3004        }
3005
3006        if(flag == LEFTMIDDLE || flag == TOPMIDDLE)
3007        {
3008                for(i = 0; i < steps; i++)
3009                {
3010                        p = steps - i;
3011                        r3 = (r2 * p + r1 * i) / steps;
3012                        g3 = (g2 * p + g1 * i) / steps;
3013                        b3 = (b2 * p + b1 * i) / steps;
3014                        col = (transparent << 24) | (r3 << 16) | (g3 << 8) | b3;
3015
3016                        r = 0;
3017                        for(y = posy; y < yend; y += skinfb->width)
3018                        {
3019                                if(r == 0)
3020                                {
3021                                        r = 1;
3022                                        for(x = posx; x < xend; x++)
3023                                                drawpixelfast(x, y, col);
3024                                }
3025                                else
3026                                        memcpy(skinfb->fb + (y + posx) * skinfb->colbytes, skinfb->fb + (posy + posx) * skinfb->colbytes, (xend - posx) * skinfb->colbytes);
3027                        }
3028
3029                        if(flag == LEFTMIDDLE)
3030                        {
3031                                posx += xstep;
3032                                xcount += xstep;
3033                                xend = posx + xstep;
3034                        }
3035                        else
3036                        {
3037                                tmp = ystep * skinfb->width;
3038                                posy += tmp;
3039                                ycount += ystep;
3040                                yend = posy + tmp;
3041                        }
3042                }
3043        }
3044
3045        if(flag == LEFTRIGHT || flag == LEFTMIDDLE)
3046        {
3047                if(owidth > xcount)
3048                {
3049                        int tmp = posx + (owidth - xcount);
3050                        for(y = posy; y < yend; y += skinfb->width)
3051                                for(x = posx; x < tmp; x++)
3052                                        drawpixelfast(x, y, col);
3053                }
3054        }
3055        if(flag == TOPBOTTOM || flag == TOPMIDDLE)
3056        {
3057                if(oheight > ycount)
3058                {
3059                        int tmp = posy + ((oheight - ycount) * skinfb->width);
3060                        for(y = posy; y < tmp; y += skinfb->width)
3061                                for(x = posx; x < xend; x++)
3062                                        drawpixelfast(x, y, col);
3063                }
3064        }
3065}
3066
3067void drawtitlebggradient(struct skin* node)
3068{
3069        if(status.picbordersize > 0)
3070                drawgradient(node->rposx + status.picbordersize, node->rposy + status.picbordersize, node->rwidth - (status.picbordersize << 1), node->rheight - (node->rheight - node->titlesize), node->titlebgcol, node->titlebgcol2, node->transparent, node->titlegradient);
3071        else
3072                drawgradient(node->rposx, node->rposy, node->rwidth, node->rheight - (node->rheight - node->titlesize), node->titlebgcol, node->titlebgcol2, node->transparent, node->titlegradient);
3073}
3074
3075void drawbggradient(struct skin* node)
3076{
3077        drawgradient(node->rposx, node->rposy, node->rwidth, node->rheight, node->bgcol, node->bgcol2, node->transparent, node->gradient);
3078}
3079
3080void drawtitlebgcol(struct skin* node)
3081{
3082        if(status.picbordersize > 0)
3083                fillrect(node->rposx + status.picbordersize, node->rposy + status.picbordersize, node->rwidth - (status.picbordersize << 1), node->rheight - (node->rheight - node->titlesize), node->titlebgcol, node->transparent);
3084        else
3085                fillrect(node->rposx, node->rposy, node->rwidth, node->rheight - (node->rheight - node->titlesize), node->titlebgcol, node->transparent);
3086}
3087
3088void drawbginnercol(struct skin* node)
3089{
3090        fillrect(node->rposx + node->bordersize, node->rposy + node->bordersize, node->rwidth - (node->bordersize << 1), node->rheight - (node->bordersize << 1), node->bgcol, node->transparent);
3091}
3092
3093void drawbgcol(struct skin* node)
3094{
3095        fillrect(node->rposx + node->bgspace, node->rposy + node->bgspace, node->rwidth - (node->bgspace << 1), node->rheight - (node->bgspace << 1), node->bgcol, node->transparent);
3096}
3097
3098void drawtitle(struct skin* node)
3099{
3100        if(status.titlelinesize > 0)
3101                drawstring(node->title, 1, 0, -1, node->iposx, node->rposy + node->bordersize, node->iwidth, node->titlesize - status.titlelinesize, node->titlealign, MIDDLE, node->font, node->fontsize, node->fontcol, node->transparent, 0, NULL, NULL, NULL, node->charspace, 0);
3102        else
3103                drawstring(node->title, 1, 0, -1, node->iposx, node->rposy + node->bordersize, node->iwidth, node->titlesize - node->bordersize, node->titlealign, MIDDLE, node->font, node->fontsize, node->fontcol, node->transparent, 0, NULL, NULL, NULL, node->charspace, 0);
3104        if(status.titlelinesize > 0)
3105                fillrect(node->rposx, node->rposy + node->titlesize + status.picbordersize, node->rwidth, status.titlelinesize, node->bordercol, node->transparent);
3106        else if(node->bordersize > 0)
3107                fillrect(node->rposx, node->rposy + node->titlesize, node->rwidth, node->bordersize, node->bordercol, node->transparent);
3108}
3109
3110void drawprogressbar(struct skin* node)
3111{
3112        int val = 0;
3113
3114        if(node->progresssize > 100) node->progresssize = 100;
3115        val = (((node->iwidth * 100) / 100) * node->progresssize) / 100;
3116        fillrect(node->rposx + node->bordersize, node->rposy + node->bordersize, val, node->iheight, node->progresscol, node->transparent);
3117}
3118
3119void drawmultiprogressbar(struct skin* node)
3120{
3121        struct epgrecord* epgrecord = node->epgrecord;
3122        int val1 = 0, val2 = 0;
3123
3124        while(epgrecord != NULL)
3125        {
3126
3127                if(epgrecord->posx > 100) epgrecord->posx = 100;
3128                val1 = (((node->iwidth * 100) / 100) * epgrecord->posx) / 100;
3129                if(epgrecord->size > 100) epgrecord->size = 100;
3130                val2 = (((node->iwidth * 100) / 100) * epgrecord->size) / 100;
3131
3132                if(val2 > val1)
3133                        fillrect(node->rposx + node->bordersize + node->bgspace + val1, node->rposy + node->bgspace + node->bordersize, val2 - val1 + (node->bgspace << 1), node->iheight + (node->bgspace << 1), node->progresscol, node->transparent);
3134                epgrecord = epgrecord->next;
3135        }
3136}
3137
3138void drawroundborder(struct skin* node, char* bglt, char* bglb, char* bgrt, char* bgrb)
3139{
3140        int i, rad = status.borderradius;
3141
3142        if(node->borderradius > 0) rad = node->borderradius;
3143        if(rad > (node->rheight >> 1)) rad = (node->rheight >> 1);
3144        int tmpbordersize = rad - node->bordersize;
3145
3146        //left - top
3147        for(i = rad; i > tmpbordersize; i--)
3148                drawcircle(node->rposx + rad, node->rposy + rad, i, 90, 180, node->bordercol, node->transparent, bglt, i == rad);
3149        //left - bottom
3150        for(i = rad; i > tmpbordersize; i--)
3151                drawcircle(node->rposx + rad, node->rposy + node->rheight - 1 - rad, i, 180, 270, node->bordercol, node->transparent, bglb, i == rad);
3152        //right - top
3153        for(i = rad; i > tmpbordersize; i--)
3154                drawcircle(node->rposx + node->rwidth - 1 - rad, node->rposy + rad, i, 0, 90, node->bordercol, node->transparent, bgrt, i == rad);
3155        //right - bottom
3156        for(i = rad; i > tmpbordersize; i--)
3157                drawcircle(node->rposx + node->rwidth - 1 - rad, node->rposy + node->rheight - 1 - rad, i, 270, 360, node->bordercol, node->transparent, bgrb, i == rad);
3158}
3159
3160//TODO: not full implemented
3161void drawpicborder(struct skin* node)
3162{
3163        int borderwidth = status.picbordersize;
3164        int borderheight = status.picbordersize;
3165
3166        //top-left
3167        //drawpic("/home/nit/titan/skin/bs_tl.png", node->rposx + node->bordersize - borderwidth, node->rposy + node->bordersize - borderheight, 0, 0, borderwidth, borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3168        drawpic("/home/nit/titan/skin/bs_tl.png", node->rposx, node->rposy, 0, 0, borderwidth, borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3169        //top-right
3170        //drawpic("/home/nit/titan/skin/bs_tr.png", node->rposx - node->bordersize + node->rwidth, node->rposy + node->bordersize - borderheight, 0, 0, borderwidth, borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3171        drawpic("/home/nit/titan/skin/bs_tr.png", node->rposx + node->rwidth - borderwidth, node->rposy, 0, 0, borderwidth, borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3172        //bottom-left
3173        //drawpic("/home/nit/titan/skin/bs_bl.png", node->rposx + node->bordersize - borderwidth, node->rposy - node->bordersize + node->rheight, 0, 0, borderwidth, borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3174        drawpic("/home/nit/titan/skin/bs_bl.png", node->rposx, node->rposy + node->rheight - borderheight, 0, 0, borderwidth, borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3175        //bottom-right
3176        //drawpic("/home/nit/titan/skin/bs_br.png", node->rposx - node->bordersize + node->rwidth, node->rposy - node->bordersize + node->rheight, 0, 0, borderwidth, borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3177        drawpic("/home/nit/titan/skin/bs_br.png", node->rposx + node->rwidth - borderwidth, node->rposy + node->rheight - borderheight, 0, 0, borderwidth, borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3178
3179        //top
3180        //drawpic("/home/nit/titan/skin/bs_t.png", node->rposx + node->bordersize, node->rposy + node->bordersize - borderheight, node->rwidth - (node->bordersize << 1), 0, node->rwidth - (node->bordersize << 1), borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3181        drawpic("/home/nit/titan/skin/bs_t.png", node->rposx + borderwidth, node->rposy, node->rwidth - (borderwidth << 1), 0, node->rwidth - (borderwidth << 1), borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3182        //bottom
3183        //drawpic("/home/nit/titan/skin/bs_b.png", node->rposx + node->bordersize, node->rposy - node->bordersize + node->rheight, node->rwidth - (node->bordersize << 1), 0, node->rwidth - (node->bordersize << 1), borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3184        drawpic("/home/nit/titan/skin/bs_b.png", node->rposx + borderwidth, node->rposy + node->rheight - borderheight, node->rwidth - (borderwidth << 1), 0, node->rwidth - (node->bordersize << 1), borderheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3185        //left
3186        //drawpic("/home/nit/titan/skin/bs_l.png", node->rposx + node->bordersize - borderwidth, node->rposy + node->bordersize, 0, node->rheight - (node->bordersize << 1), borderwidth, node->rheight - (node->bordersize << 1), LEFT, TOP, node->transparent, node->picquality, node->picmem);
3187        drawpic("/home/nit/titan/skin/bs_l.png", node->rposx, node->rposy + borderheight, 0, node->rheight - (borderheight << 1), borderwidth, node->rheight - (borderheight << 1), LEFT, TOP, node->transparent, node->picquality, node->picmem);
3188        //right
3189        //drawpic("/home/nit/titan/skin/bs_r.png", node->rposx - node->bordersize + node->rwidth, node->rposy + node->bordersize, 0, node->rheight - (node->bordersize << 1), borderwidth, node->rheight - (node->bordersize << 1), LEFT, TOP, node->transparent, node->picquality, node->picmem);
3190        drawpic("/home/nit/titan/skin/bs_r.png", node->rposx + node->rwidth - borderwidth, node->rposy + borderheight, 0, node->rheight - (borderheight << 1), borderwidth, node->rheight - (borderheight << 1), LEFT, TOP, node->transparent, node->picquality, node->picmem);
3191}
3192
3193void drawborder(struct skin* node)
3194{
3195        if(node->bordersize == 1 && node->rheight > 2 && node->bordertype == 0)
3196                drawrect(node->rposx, node->rposy, node->rwidth, node->rheight, node->bordercol, node->transparent);
3197        else if(node->bordersize == 1 && node->rheight <= 2 && node->bordertype == 0)
3198                fillrect(node->rposx, node->rposy, node->rwidth, node->rheight, node->bordercol, node->transparent);
3199        else
3200        {
3201                if(node->bordertype == 0 || checkbit(node->bordertype, 0) == 1)
3202                        fillrect(node->rposx, node->rposy, node->rwidth, node->bordersize, node->bordercol, node->transparent);
3203                if(node->bordertype == 0 || checkbit(node->bordertype, 1) == 1)
3204                        fillrect(node->rposx, node->rposy + node->rheight - node->bordersize, node->rwidth, node->bordersize, node->bordercol, node->transparent);
3205                if(node->bordertype == 0 || checkbit(node->bordertype, 2) == 1)
3206                        fillrect(node->rposx, node->rposy, node->bordersize, node->rheight, node->bordercol, node->transparent);
3207                if(node->bordertype == 0 || checkbit(node->bordertype, 3) == 1)
3208                        fillrect(node->rposx + node->rwidth - node->bordersize, node->rposy, node->bordersize, node->rheight, node->bordercol, node->transparent);
3209        }
3210}
3211
3212void drawscrollbar(struct skin* node)
3213{
3214        if(node->bordersize == 0)
3215                drawrect(node->rposx + node->rwidth - node->bordersize - node->scrollbarwidth, node->iposy, node->scrollbarwidth, node->iheight, node->bordercol, node->transparent);
3216        else
3217                fillrect(node->rposx + node->rwidth - node->bordersize - node->scrollbarwidth, node->iposy, node->scrollbarbordersize, node->iheight, node->bordercol, node->transparent);
3218
3219        fillrect(node->rposx + node->rwidth - node->bordersize - node->scrollbarwidth, node->iposy + node->scrollbarpos, node->scrollbarwidth, node->scrollbarheight, node->bordercol, node->transparent);
3220}
3221
3222void clearshadow(struct skin* node)
3223{
3224        if(node->shadowsize < 1) return;
3225        switch(node->shadowpos)
3226        {
3227                case BOTTOMLEFT:
3228                        clearrect(node->rposx - node->shadowsize, node->rposy + node->rheight, node->rwidth, node->shadowsize);
3229                        clearrect(node->rposx - node->shadowsize, node->rposy + node->shadowsize, node->shadowsize, node->rheight);
3230                        break;
3231                case BOTTOMRIGHT:
3232                        clearrect(node->rposx + node->shadowsize, node->rposy + node->rheight, node->rwidth, node->shadowsize);
3233                        clearrect(node->rposx + node->rwidth, node->rposy + node->shadowsize, node->shadowsize, node->rheight);
3234                        break;
3235                case TOPLEFT:
3236                        clearrect(node->rposx - node->shadowsize, node->rposy - node->shadowsize, node->rwidth, node->shadowsize);
3237                        clearrect(node->rposx - node->shadowsize, node->rposy - node->shadowsize, node->shadowsize, node->rheight);
3238                        break;
3239                default:
3240                        clearrect(node->rposx + node->shadowsize, node->rposy - node->shadowsize, node->rwidth, node->shadowsize);
3241                        clearrect(node->rposx + node->rwidth, node->rposy - node->shadowsize, node->shadowsize, node->rheight);
3242                        break;
3243        }
3244}
3245
3246void drawshadow(struct skin* node)
3247{
3248        switch(node->shadowpos)
3249        {
3250                case BOTTOMLEFT:
3251                        fillrect(node->rposx - node->shadowsize, node->rposy + node->rheight, node->rwidth, node->shadowsize, node->shadowcol, node->transparent);
3252                        fillrect(node->rposx - node->shadowsize, node->rposy + node->shadowsize, node->shadowsize, node->rheight, node->shadowcol, node->transparent);
3253                        break;
3254                case BOTTOMRIGHT:
3255                        fillrect(node->rposx + node->shadowsize, node->rposy + node->rheight, node->rwidth, node->shadowsize, node->shadowcol, node->transparent);
3256                        fillrect(node->rposx + node->rwidth, node->rposy + node->shadowsize, node->shadowsize, node->rheight, node->shadowcol, node->transparent);
3257                        break;
3258                case TOPLEFT:
3259                        fillrect(node->rposx - node->shadowsize, node->rposy - node->shadowsize, node->rwidth, node->shadowsize, node->shadowcol, node->transparent);
3260                        fillrect(node->rposx - node->shadowsize, node->rposy - node->shadowsize, node->shadowsize, node->rheight, node->shadowcol, node->transparent);
3261                        break;
3262                default:
3263                        fillrect(node->rposx + node->shadowsize, node->rposy - node->shadowsize, node->rwidth, node->shadowsize, node->shadowcol, node->transparent);
3264                        fillrect(node->rposx + node->rwidth, node->rposy - node->shadowsize, node->shadowsize, node->rheight, node->shadowcol, node->transparent);
3265                        break;
3266        }
3267}
3268
3269//flag 0: del background
3270//flag 1: don't del background
3271void drawnode(struct skin* node, int flag)
3272{
3273        long color = 0, color2 = 0;
3274        int len = 0;
3275        char* bglt = NULL, *bglb = NULL, *bgrt = NULL, *bgrb = NULL;
3276
3277        node->flag = setbit(node->flag, 0);
3278
3279        if(node->bordersize > 0)
3280        {
3281                if((node->child != NULL && status.borderradius > 0) || node->borderradius > 0)
3282                {
3283                        int rad = status.borderradius;
3284
3285                        if(node->borderradius > 0) rad = node->borderradius;
3286                        if(rad > (node->rheight >> 1)) rad = (node->rheight >> 1);
3287
3288                        bglt = saverect(node->rposx, node->rposy, rad, rad);
3289                        bglb = saverect(node->rposx, node->rposy + node->rheight - rad, rad, rad);
3290                        bgrt = saverect(node->rposx + node->rwidth - rad, node->rposy, rad, rad);
3291                        bgrb = saverect(node->rposx + node->rwidth - rad, node->rposy + node->rheight - rad, rad, rad);
3292                }
3293        }
3294
3295        if(flag == 0 && node->bgcol == -1)
3296        {
3297                if(node->child != NULL && status.picbordersize > 0)
3298                        clearrect(node->rposx + node->bordersize, node->rposy + node->bordersize, node->rwidth - (node->bordersize << 1), node->rheight - (node->bordersize << 1));
3299                else
3300                        clearscreennolock(node);
3301        }
3302
3303        if(node->deaktivcol > -1)
3304        {
3305                color = node->deaktivcol;
3306                color2 = node->deaktivcol;
3307        }
3308        else
3309        {
3310                color = node->fontcol;
3311                color2 = node->fontcol2;
3312        }
3313
3314        if(node->shadowsize > 0)
3315                drawshadow(node);
3316        if(node->bgcol > -1)
3317        {
3318                if(node->child != NULL && status.picbordersize > 0)
3319                        drawbginnercol(node);
3320                else
3321                        drawbgcol(node);
3322        }
3323        if(node->child != NULL && status.bgpic != NULL)
3324                drawpic(status.bgpic, node->iposx, node->iposy, node->iwidth, node->iheight, node->iwidth, node->iheight, node->halign, node->valign, node->transparent, node->picquality, node->picmem);
3325        if(node->gradient > 0)
3326                drawbggradient(node);
3327        if(node->titlebgcol > -1)
3328                drawtitlebgcol(node);
3329        if(node->titlegradient > 0)
3330                drawtitlebggradient(node);
3331        if(node->progresssize > 0)
3332                drawprogressbar(node);
3333        if(node->type & MULTIPROGRESSBAR)
3334                drawmultiprogressbar(node);
3335        if(node->selectpic != NULL && !(node->type & FILELIST))
3336                drawpic(node->selectpic, node->iposx, node->iposy, node->iwidth, node->iheight, node->iwidth, node->iheight, LEFT, TOP, node->transparent, node->picquality, node->picmem);
3337        if(node->pic != NULL && !(node->type & FILELIST))
3338                drawpic(node->pic, node->iposx, node->iposy, node->rpicwidth, node->rpicheight, node->iwidth, node->iheight, node->halign, node->valign, node->transparent, node->picquality, node->picmem);
3339
3340        if(node->input != NULL)
3341        {
3342                if(node->type & CHOICEBOX)
3343                {
3344                        if(node->fontcol2 != 0 )
3345                                drawstring(node->input, 1, node->poscount, -1, node->iposx, node->iposy, node->iwidth, node->iheight, RIGHT, node->valign, node->font, node->fontsize, node->fontcol2, node->transparent, 0, NULL, NULL, &len, node->charspace, 0);
3346                        else
3347                                drawstring(node->input, 1, node->poscount, -1, node->iposx, node->iposy, node->iwidth, node->iheight, RIGHT, node->valign, node->font, node->fontsize, color, node->transparent, 0, NULL, NULL, &len, node->charspace, 0);
3348                }
3349                if((node->type & INPUTBOX) || (node->type & INPUTBOXNUM))
3350                {
3351                        if(node->type & PASSWORD)
3352                                drawstring(node->input, 1, node->poscount, node->aktpage, node->iposx, node->iposy, node->iwidth, node->iheight, RIGHT, node->valign, node->font, node->fontsize, color, node->transparent, 0, NULL, NULL, &len, node->charspace, 1);
3353                        else
3354                                drawstring(node->input, 1, node->poscount, node->aktpage, node->iposx, node->iposy, node->iwidth, node->iheight, RIGHT, node->valign, node->font, node->fontsize, color, node->transparent, 0, NULL, NULL, &len, node->charspace, 0);
3355                }
3356        }
3357        if(node->text != NULL)
3358        {
3359                if(node->type & TEXTBOX)
3360                {
3361                        int lastposy = 0;
3362                        drawstring(node->text, node->linecount, node->poscount, -1, node->iposx + node->textposx, node->iposy, node->iwidth - node->textposx, node->iheight, node->halign, node->valign, node->font, node->fontsize, color, node->transparent, node->wrap, NULL, &lastposy, NULL, node->charspace, 0);
3363                        drawstring(node->text2, node->linecount, node->poscount, -1, node->iposx + node->textposx2, lastposy, node->iwidth - node->textposx2, node->iheight - (lastposy - node->iposy), node->halign, node->valign, node->font, node->fontsize2, color2, node->transparent, node->wrap, NULL, &lastposy, NULL, node->charspace, 0);
3364                }
3365                else
3366                {
3367                        int lastposx = 0;
3368                        if(node->textposx2 > 0)
3369                        {
3370                                drawstring(node->text, 1, 0, -1, node->iposx + node->textposx, node->iposy, node->iwidth - node->textposx - (node->iwidth - node->textposx2) - len, node->iheight, node->halign, node->valign, node->font, node->fontsize, color, node->transparent, 0, &lastposx, NULL, NULL, node->charspace, 0);
3371                                drawstring(node->text2, 1, 0, -1, node->iposx + node->textposx2, node->iposy, node->iwidth - node->textposx2 - len, node->iheight, node->halign, node->valign, node->font, node->fontsize2, color2, node->transparent, 0, NULL, NULL, NULL, node->charspace, 0);
3372                        }
3373                        else
3374                        {
3375                                drawstring(node->text, 1, 0, -1, node->iposx + node->textposx, node->iposy, node->iwidth - node->textposx - len, node->iheight, node->halign, node->valign, node->font, node->fontsize, color, node->transparent, 0, &lastposx, NULL, NULL, node->charspace, 0);
3376                                drawstring(node->text2, 1, 0, -1, lastposx, node->iposy, node->iwidth - (lastposx - node->iposx) - len, node->iheight, node->halign, node->valign, node->font, node->fontsize2, color2, node->transparent, 0, NULL, NULL, NULL, node->charspace, 0);
3377                        }
3378                }
3379        }
3380        if(node->filelist != NULL && node->filelist->view > 3)
3381        {
3382                char* tmpnr = NULL;
3383
3384                if(node->filelist->view == 4)
3385                {
3386                        if(node->filelist->size >= 1073741824)
3387                        {
3388                                tmpnr = oftoa64((double)node->filelist->size / 1073741824, "2");
3389                                tmpnr = ostrcat(tmpnr, "G", 1, 0);
3390                        }
3391                        else if(node->filelist->size >= 1048576)
3392                        {
3393                                tmpnr = oftoa64((double)node->filelist->size / 1048576, "2");
3394                                tmpnr = ostrcat(tmpnr, "M", 1, 0);
3395                        }
3396                        else if(node->filelist->size >= 1024)
3397                        {
3398                                tmpnr = oftoa64((double)node->filelist->size / 1024, "2");
3399                                tmpnr = ostrcat(tmpnr, "K", 1, 0);
3400                        }
3401                        else
3402                        {
3403                                tmpnr = oitoa64(node->filelist->size);
3404                                tmpnr = ostrcat(tmpnr, "B", 1, 0);
3405                        }
3406                }
3407                if(node->filelist->view == 5)
3408                {
3409                        tmpnr = malloc(MINMALLOC);
3410                        if(tmpnr == NULL)
3411                        {
3412                                err("no mem");
3413                                return;
3414                        }
3415
3416                        struct tm* loctime = olocaltime(&node->filelist->date);
3417                        if(loctime != NULL)
3418                                strftime(tmpnr, MINMALLOC, "%H:%M %d-%m-%Y", loctime);
3419                        free(loctime);
3420                }
3421                drawstring(tmpnr, 1, node->poscount, -1, node->iposx, node->iposy, node->iwidth, node->iheight, RIGHT, node->valign, node->font, node->fontsize, node->fontcol, node->transparent, 0, NULL, NULL, NULL, node->charspace, 0);
3422                free(tmpnr);
3423        }
3424        if(node->title != NULL && node->fontsize > 1)
3425                drawtitle(node);
3426        if(node->scrollbar == YES || node->scrollbar == AUTOYES)
3427                drawscrollbar(node);
3428        if(node->bordersize > 0)
3429        {
3430                if(node->child != NULL && status.picbordersize > 0)
3431                        drawpicborder(node);
3432                else
3433                        drawborder(node);
3434                if((node->child != NULL && status.borderradius > 0) || node->borderradius > 0)
3435                        drawroundborder(node, bglt, bglb, bgrt, bgrb);
3436        }
3437
3438        free(bglt); free(bglb); free(bgrt); free(bgrb);
3439}
3440
3441void calcscrollbar(struct skin* node)
3442{
3443        node->scrollbarheight = node->iheight;
3444
3445        if(node->pagecount > 1)
3446        {
3447                node->scrollbarheight = (float)node->iheight / node->pagecount;
3448                node->scrollbarpos = ((float)node->iheight / node->pagecount) * (node->aktpage - 1);
3449                if(node->scrollbar == AUTONO) node->scrollbar = AUTOYES;
3450        }
3451        else if(node->scrollbar == AUTOYES)
3452                node->scrollbar = AUTONO;
3453
3454        if(node->scrollbar == YES || node->scrollbar == AUTOYES)
3455        {
3456                node->iwidth -= (SCROLLBARWIDTH + 5);
3457                node->scrollbarwidth = SCROLLBARWIDTH;
3458                node->scrollbarbordersize = SCROLLBARBORDERSIZE;
3459                if(node->iposy + node->scrollbarpos > node->iposy + node->iheight) node->scrollbarpos = node->iposy + node->iheight;
3460                if(node->scrollbarpos < 0) node->scrollbarpos = 0;
3461                if(node->iposy + node->scrollbarpos + node->scrollbarheight > node->iposy + node->iheight) node->scrollbarheight = node->iheight - node->scrollbarpos;
3462                if(node->scrollbarheight < 1) node->scrollbarheight = 1;
3463        }
3464}
3465
3466void calclistboxchild(struct skin* node, struct skin* parent)
3467{
3468        if((parent->type & GRID) && (node->type & GRIDBR))
3469        {
3470                if(parent->poscount > 0) parent->poscount += node->rheight;
3471                if(parent->poscount == 0) parent->poscount = 1;
3472        }
3473        node->rposy = node->rposy + parent->poscount;
3474        node->iposy = node->iposy + parent->poscount;
3475        if((parent->type & LISTBOX) || ((parent->type & FILELIST) && !(parent->type & GRID)))
3476                parent->poscount += node->rheight;
3477}
3478
3479int calclistbox(struct skin* node)
3480{
3481        struct skin* child = NULL, *last = NULL, *found = NULL;
3482        int selcol = 0;
3483
3484        if(node->type == FILELIST)
3485                selcol = status.filelistselectcol;
3486        else
3487                selcol = status.listboxselectcol;
3488
3489        node->poscount = 0;
3490        if(node->aktline == 0) node->aktline = 1;
3491        node->pagecount = 1;
3492        node->linecount = 0;
3493
3494        child = node->next;
3495        while(child != NULL)
3496        {
3497                if(child->parentpointer == NULL)
3498                {
3499                        if(child->parent == NULL)
3500                        {
3501                                child = child->next;
3502                                continue;
3503                        }
3504                        else if(ostrcmp(child->parent, node->name) != 0 || child->hidden == YES)
3505                        {
3506                                child = child->next;
3507                                continue;
3508                        }
3509                }
3510                else if(child->parentpointer != node || child->hidden == YES)
3511                {
3512                        child = child->next;
3513                        continue;
3514                }
3515
3516                if(child->locked == YES)
3517                {
3518                        child = child->next;
3519                        continue;
3520                }
3521
3522                calcrheight(child, node);
3523
3524                if((node->type & LISTBOX) || ((node->type & FILELIST) && !(node->type & GRID)) || ((node->type & GRID) && (child->type & GRIDBR)))
3525                        node->poscount = node->poscount + child->posy + child->rheight;
3526
3527                if(node->poscount > node->iheight)
3528                {
3529                        node->pagecount++;
3530                        node->poscount = child->rheight;
3531                }
3532
3533                child->pagecount = node->pagecount;
3534
3535                if(child->deaktivcol > -1)
3536                {
3537                        child = child->next;
3538                        continue;
3539                }
3540
3541                node->linecount++;
3542                last = child;
3543
3544                if(node->aktline == -1 && child->pagecount == node->aktpage)
3545                {
3546                        node->aktline = node->linecount;
3547                        found = child;
3548                }
3549                else if(node->aktline == node->linecount)
3550                        found = child;
3551
3552                child->bordersize = 0;
3553                if(status.listboxselecttype == 3)
3554                {
3555                        changeselectpic(child, NULL);
3556                        if(child->bgcol == status.markcol)
3557                                child->bgcol = child->bordercol;
3558                }
3559                if(child->bgcol == selcol || child->bgcol == status.markcol) //&& status.listboxselecttype == 1)
3560                        child->bgcol = child->bordercol;
3561                if(child->fontcol == selcol || child->fontcol == status.markcol) //&& status.listboxselecttype == 2)
3562                        child->fontcol = child->bordercol;
3563
3564                child = child->next;
3565        }
3566
3567        if(found == NULL)
3568        {
3569                found = last;
3570                node->aktline = node->linecount;
3571        }
3572
3573        if(found != NULL)
3574        {
3575                if(node->aktline == -2) node->aktline = node->linecount;
3576                if(status.listboxselecttype == 0)
3577                {
3578                        found->bordersize = 1;
3579                        if(status.markmodus > 0)
3580                        {
3581                                found->bordercol = status.markcol;
3582                                int i = 0;
3583                                struct skin* tmpskin = found;
3584                                for(i = 0; i < status.moveblockcount; i++)
3585                                {
3586                                        tmpskin = tmpskin->next;
3587                                        if(tmpskin != NULL)
3588                                                tmpskin->bordercol = status.markcol;
3589                                        else
3590                                                break;
3591                                }
3592                        }
3593                        else
3594                                found->bordercol = selcol;
3595                }
3596                else if(status.listboxselecttype == 1)
3597                {
3598                        if(found->bgcol != selcol && found->bgcol != status.markcol)
3599                        {
3600                                found->bordercol = found->bgcol;
3601                                int i = 0;
3602                                struct skin* tmpskin = found;
3603                                for(i = 0; i < status.moveblockcount; i++)
3604                                {
3605                                        tmpskin = tmpskin->next;
3606                                        if(tmpskin != NULL)
3607                                                tmpskin->bordercol = found->bgcol;
3608                                        else
3609                                                break;
3610                                }
3611                        }
3612                        if(status.markmodus > 0)
3613                        {
3614                                found->bgcol = status.markcol;
3615                                int i = 0;
3616                                struct skin* tmpskin = found;
3617                                for(i = 0; i < status.moveblockcount; i++)
3618                                {
3619                                        tmpskin = tmpskin->next;
3620                                        if(tmpskin != NULL)
3621                                                tmpskin->bgcol = status.markcol;
3622                                        else
3623                                                break;
3624                                }
3625                        }
3626                        else
3627                                found->bgcol = selcol;
3628                }
3629                else if(status.listboxselecttype == 2)
3630                {
3631                        if(found->fontcol != selcol && found->fontcol != status.markcol)
3632                        {
3633                                found->bordercol = found->fontcol;
3634                                int i = 0;
3635                                struct skin* tmpskin = found;
3636                                for(i = 0; i < status.moveblockcount; i++)
3637                                {
3638                                        tmpskin = tmpskin->next;
3639                                        if(tmpskin != NULL)
3640                                                tmpskin->bordercol = found->fontcol;
3641                                        else
3642                                                break;
3643                                }
3644                        }
3645                        if(status.markmodus > 0)
3646                        {
3647                                found->fontcol = status.markcol;
3648                                int i = 0;
3649                                struct skin* tmpskin = found;
3650                                for(i = 0; i < status.moveblockcount; i++)
3651                                {
3652                                        tmpskin = tmpskin->next;
3653                                        if(tmpskin != NULL)
3654                                                tmpskin->fontcol = status.markcol;
3655                                        else
3656                                                break;
3657                                }
3658                        }
3659                        else
3660                                found->fontcol = selcol;
3661                }
3662                else if(status.listboxselecttype == 3)
3663                {
3664                        if(status.markmodus > 0)
3665                        {
3666                                found->bordersize = 1;
3667                                found->bordercol = status.markcol;
3668                                int i = 0;
3669                                struct skin* tmpskin = found;
3670                                for(i = 0; i < status.moveblockcount; i++)
3671                                {
3672                                        tmpskin = tmpskin->next;
3673                                        if(tmpskin != NULL)
3674                                        {
3675                                                tmpskin->bordersize = 1;
3676                                                tmpskin->bordercol = status.markcol;
3677                                        }
3678                                        else
3679                                                break;
3680                                }
3681                        }
3682                        else
3683                                changeselectpic(found, status.selectpic);
3684                }
3685
3686                if(node->aktpage == -1)
3687                        node->aktpage = found->pagecount;
3688                node->select = found;
3689        }
3690
3691        if(node->aktpage == -1) node->aktpage = 0;
3692        if(node->aktpage > node->pagecount)
3693        {
3694                if(node->pagecount == 0) node->aktpage = 0;
3695                else node->aktpage = 1;
3696        }
3697        node->poscount = 0;
3698        return 0;
3699}
3700
3701int calcrwidth(struct skin* node, struct skin* parent)
3702{
3703        int scrollbarwidth = 0;
3704
3705        if(node->prozwidth == 1)
3706                node->rwidth = (((parent->iwidth * 100) / 100) * node->width) / 100;
3707        else
3708                node->rwidth = node->width;
3709
3710        if(node->scrollbar == YES || node->scrollbar == AUTOYES || node->scrollbar == AUTONO) scrollbarwidth = SCROLLBARWIDTH;
3711
3712        if(node->rwidth < (node->bordersize << 1) + scrollbarwidth) node->rwidth = (node->bordersize << 1) + scrollbarwidth;
3713
3714        return 0;
3715}
3716
3717int calcrheight(struct skin* node, struct skin* parent)
3718{
3719        if(node->prozheight == 1)
3720                node->rheight = (((parent->iheight * 100) / 100) * node->height) / 100;
3721        else
3722        {
3723                node->rheight = node->height;
3724                if(node->fontsize == 0) node->fontsize = parent->fontsize;
3725                if(node->fontsize == 0) node->fontsize = 1;
3726                if(node->rheight == 0) node->rheight = node->fontsize + 2;
3727        }
3728
3729        if(node->rheight < (node->bordersize << 1) + node->titlesize) node->rheight = (node->bordersize << 1) + node->titlesize;
3730
3731        return 0;
3732}
3733
3734int calcrposx(struct skin* node, struct skin* parent)
3735{
3736        if(node->prozposx == 1)
3737                node->rposx = (((parent->iwidth * 100) / 100) * node->posx) / 100;
3738        else
3739                node->rposx = node->posx;
3740
3741        if(node->posx == CENTER || (node->posx == 0 && parent->halign == CENTER))
3742                node->rposx = parent->iposx + (parent->iwidth >> 1) - (node->rwidth >> 1);
3743        else if(node->posx == LEFT)
3744                node->rposx = parent->iposx;
3745        else if(node->posx == RIGHT || (node->posx == 0 && parent->halign == RIGHT))
3746                node->rposx = parent->iposx + parent->iwidth - node->rwidth;
3747        else
3748                node->rposx = parent->iposx + node->rposx;
3749
3750        if(node->rposx > parent->iposx + parent->iwidth)
3751                node->rposx = parent->iposx + parent->iwidth;
3752
3753        return 0;
3754}
3755
3756int calcrposy(struct skin* node, struct skin* parent)
3757{
3758        if(node->prozposy == 1)
3759                node->rposy = (((parent->iheight * 100) / 100) * node->posy) / 100;
3760        else
3761                node->rposy = node->posy;
3762
3763        if(node->posy == MIDDLE || (node->posy == 0 && parent->valign == MIDDLE))
3764                node->rposy = parent->iposy + (parent->iheight >> 1) - (node->rheight >> 1);
3765        else if(node->posy == TOP)
3766                node->rposy = parent->iposy;
3767        else if(node->posy == BOTTOM || (node->posy ==0 && parent->valign == BOTTOM))
3768                node->rposy = parent->iposy + parent->iheight - node->rheight;
3769        else
3770                node->rposy = parent->iposy + node->rposy;
3771
3772        if(node->rposy > parent->iposy + parent->iheight)
3773                node->rposy = parent->iposy + parent->iheight;
3774
3775        return 0;
3776}
3777
3778int setnodeattr(struct skin* node, struct skin* parent, int screencalc)
3779{
3780        if(node != skin) node->flag = clearbit(node->flag, 0);
3781        if((parent->type & LISTBOX) || (parent->type & FILELIST) || (parent->type & GRID))
3782                if(node->pagecount != parent->aktpage) return 1;
3783
3784        int shadowlx = 0, shadowrx = 0, shadowoy = 0, shadowuy = 0;
3785        unsigned int linecount = 0, pagecount = 0, poscount = 0;
3786        char* tmpstr = NULL;
3787
3788        if(node->child != NULL && status.picbordersize > 0)
3789                node->bordersize = status.picbordersize;
3790
3791        if(node->nodestyle != 0)
3792        {
3793                if(node->nodestyle == 2 && getconfigint("skinblinkoff", NULL) == 0)
3794                        node->nodestyle = 1;
3795                else if(node->nodestyle == 1 && getconfigint("skinblinkoff", NULL) == 1)
3796                        node->nodestyle = 2;
3797                if(node->nodestyle == 1)
3798                        setblink(node);
3799        }
3800
3801        if(node->skinfunc != NULL)
3802        {
3803                if(node->funcrettype == FUNCPIC)
3804                {
3805                        tmpstr = node->skinfunc(node, node->param1, node->param2);
3806                        changepic(node, tmpstr);
3807                }
3808                else if(node->funcrettype == FUNCPICOLED)
3809                {
3810                        tmpstr = node->skinfunc(node, node->param1, node->param2);
3811                        if(tmpstr != NULL)
3812                                changepic(node, tmpstr);
3813                }
3814                else if(node->funcrettype == FUNCPROGRESS)
3815                {
3816                        tmpstr = node->skinfunc(node, node->param1, node->param2);
3817                        if(tmpstr != NULL)
3818                        {
3819                                node->hidden = NO;
3820                                node->progresssize = atoi(tmpstr);
3821                        }
3822                        else
3823                                node->hidden = YES;
3824                }
3825                else
3826                {
3827                        tmpstr = node->skinfunc(node, node->param1, node->param2);
3828                        changetext(node, _(tmpstr));
3829                }
3830                free(tmpstr);
3831        }
3832
3833        if(screencalc != 2)
3834        {
3835                if(node->hidden == YES || parent->hidden == YES || node->locked == YES || parent->locked == YES) return 1;
3836                if(checkbit(parent->flag, 0) == 0) return 1;
3837        }
3838
3839        calcrwidth(node, parent);
3840        if(!(parent->type & LISTBOX) && !(parent->type & FILELIST) && !(parent->type & GRID))
3841                calcrheight(node, parent);
3842        calcrposx(node, parent);
3843        calcrposy(node, parent);
3844
3845        if(node->height < 0)
3846                node->rheight = parent->iheight + node->height - (node->rposy - parent->iposy);
3847        if(node->width < 0)
3848                node->rwidth = parent->iwidth + node->width - (node->rposx - parent->iposx);
3849
3850        node->iposx = node->rposx + node->bordersize + node->hspace;
3851        node->iposy = node->rposy + node->bordersize + node->titlesize + node->vspace;
3852        node->iwidth = node->rwidth - (node->bordersize << 1) - (node->hspace << 1);
3853        node->iheight = node->rheight - (node->bordersize << 1) - node->titlesize - (node->vspace << 1);
3854
3855        switch(node->shadowpos)
3856        {
3857                case BOTTOMLEFT: shadowlx = shadowuy = node->shadowsize; break;
3858                case BOTTOMRIGHT: shadowrx = shadowuy = node->shadowsize; break;
3859                case TOPLEFT: shadowlx = shadowoy = node->shadowsize; break;
3860                default: shadowrx = shadowoy = node->shadowsize; break;
3861        }
3862
3863        if((parent->type & LISTBOX) || (parent->type & FILELIST) || (parent->type & GRID))
3864                calclistboxchild(node, parent);
3865
3866        if(node->picprozwidth == 1)
3867                node->rpicwidth = (((node->iwidth * 100) / 100) * node->picwidth) / 100;
3868        else
3869                node->rpicwidth = node->picwidth;
3870        if(node->picprozheight == 1)
3871                node->rpicheight = (((node->iheight * 100) / 100) * node->picheight) / 100;
3872        else
3873                node->rpicheight = node->picheight;
3874
3875        if(node->rposx - shadowlx < parent->iposx)
3876        {
3877                if(screencalc == 0) err("node (%s posx=%d) out of parent (%s posx=%d)", node->name, node->rposx - shadowlx, parent->name, parent->iposx);
3878                node->rposx = parent->iposx + shadowlx;
3879                //return 1;
3880        }
3881        if(node->rposy - shadowoy < parent->iposy)
3882        {
3883                if(screencalc == 0) err("node (%s posy=%d) out of parent (%s posy=%d)", node->name, node->rposy - shadowoy, parent->name, parent->iposy);
3884                node->rposy = parent->iposy + shadowoy;
3885                //return 1;
3886        }
3887        if(node->rposx + node->rwidth + shadowrx > parent->iposx + parent->iwidth)
3888        {
3889                if(screencalc == 0) err("node (%s posxx=%d) out of parent (%s posxx=%d)", node->name, node->rposx + node->rwidth + shadowrx, parent->name, parent->iposx + parent->iwidth);
3890                node->rwidth = parent->iwidth - node->rposx - shadowrx;
3891                //return 1;
3892        }
3893        if(node->rposy + node->rheight + shadowuy > parent->iposy + parent->iheight)
3894        {
3895                if(screencalc == 0) err("node (%s posyy=%d) out of parent (%s posyy=%d)", node->name, node->rposy + node->rheight + shadowuy, parent->name, parent->iposy + parent->iheight);
3896                node->rheight = parent->iheight - node->rposy - shadowuy;
3897                //return 1;
3898        }
3899
3900        if(node->font == NULL && parent->font != NULL)
3901        {
3902                changefont(node, parent->font);
3903                if(node->font == NULL)
3904                {
3905                        err("no memory");
3906                }
3907        }
3908
3909        if(node->fontsize == 0) node->fontsize = parent->fontsize;
3910        if(node->fontsize == 0) node->fontsize = 1;
3911        if(node->fontsize2 == 0) node->fontsize2 = parent->fontsize2;
3912        if(node->fontsize2 == 0) node->fontsize2 = 1;
3913        if(node->fontcol == 0) node->fontcol = parent->fontcol;
3914        if(node->fontcol2 == 0) node->fontcol2 = parent->fontcol2;
3915
3916        if((node->type & INPUTBOX) || (node->type & INPUTBOXNUM))
3917        {
3918                if(node->aktpage < 1) node->aktpage = 1;
3919                checkinputboxnumright(node);
3920                changeret(node, node->input);
3921        }
3922
3923        if((node->type & LISTBOX) || (node->type & FILELIST) || (node->type & GRID))
3924        {
3925                if(node->aktpage == 0) node->aktpage = 1;
3926                calclistbox(node);
3927                if(node->scrollbar != NO)
3928                        calcscrollbar(node);
3929        }
3930        if(node->type & TEXTBOX)
3931        {
3932                if(node->aktpage < 1) node->aktpage = 1;
3933                if(node->text == NULL && node->text2 == NULL)
3934                        node->pagecount = 0;
3935                else
3936                {
3937                        if(node->wrap == YES)
3938                        {
3939                                wrapstr(node->text, node->font, node->fontsize, node->iwidth, node->charspace);
3940                                wrapstr(node->text2, node->font, node->fontsize2, node->iwidth, node->charspace);
3941                        }
3942                        calctext(node->text, node->text2, &node->linecount, &node->pagecount, &node->poscount, node->iheight / node->fontsize, node->aktpage);
3943                }
3944                if(node->text2 != NULL) node->scrollbar = NO;
3945                if(node->scrollbar != NO)
3946                        calcscrollbar(node);
3947        }
3948
3949        if((node->type & CHOICEBOX) && node->input != NULL)
3950        {
3951                char* pos = NULL;
3952                calctext(node->input, NULL, &node->linecount, &node->pagecount, &node->poscount, 1, node->aktpage);
3953
3954                free(node->ret);
3955                node->ret = NULL;
3956
3957                if(node->choiceboxvalue != NULL)
3958                {
3959                        calctext(node->choiceboxvalue, NULL, &linecount, &pagecount, &poscount, 1, node->aktpage);
3960                        pos = strchr(node->choiceboxvalue + poscount, '\n');
3961                        if(pos == NULL)
3962                                changeret(node, node->choiceboxvalue + poscount);
3963                        else
3964                                node->ret = strndup(node->choiceboxvalue + poscount, pos - (node->choiceboxvalue + poscount));
3965                }
3966                else if(node->input != NULL)
3967                {
3968                        pos = strchr(node->input + node->poscount, '\n');
3969                        if(pos == NULL)
3970                                changeret(node, node->input + node->poscount);
3971                        else
3972                                node->ret = strndup(node->input + node->poscount, pos - (node->input + node->poscount));
3973                }
3974        }
3975
3976        //set parent transparent to child
3977        //if(node->transparent == 0 && parent != skin)
3978                //node->transparent = parent->transparent;
3979
3980        return 0;
3981}
3982
3983int clearscreenalways()
3984{
3985        int i, ret = 0;
3986        int tmp = sizeof(status.drawallways) / sizeof(skin);
3987
3988        for(i = 0; i < tmp; i++)
3989        {
3990                if(status.drawallways[i] != NULL)
3991                {
3992                        clearrect(status.drawallways[i]->rposx, status.drawallways[i]->rposy, status.drawallways[i]->rwidth, status.drawallways[i]->rheight);
3993                }
3994        }
3995
3996        return ret;
3997}
3998
3999int drawscreenalways(struct skin* node, int screencalc)
4000{
4001        int i, ret = 0;
4002        int tmp = sizeof(status.drawallways) / sizeof(skin);
4003
4004        m_lock(&status.oledmutex, 25);
4005        for(i = 0; i < tmp; i++)
4006        {
4007                if(status.drawallways[i] != NULL)
4008                {
4009                        if(node != status.drawallways[i])
4010                        {
4011                                if(status.drawallwaysbg[i] != NULL)
4012                                        free(status.drawallwaysbg[i]);
4013                                status.drawallwaysbg[i] = savescreen(status.drawallways[i]);
4014       
4015                                ret = drawscreen(status.drawallways[i], screencalc, 1);
4016                        }
4017                }
4018        }
4019        m_unlock(&status.oledmutex, 25);
4020
4021        return ret;
4022}
4023
4024int drawscreennode(struct skin *node, char* nodename, int screencalc)
4025{
4026        node = getscreennode(node, nodename);
4027
4028        m_lock(&status.drawingmutex, 0);
4029        if(node != status.skinerr)
4030                drawnode(node, 1);
4031        drawscreenalways(node, screencalc);
4032
4033        blitfb(0);
4034        m_unlock(&status.drawingmutex, 0);
4035
4036        return 0;
4037}
4038
4039int drawscreennodebyname(char* screenname, char* nodename, int screencalc)
4040{
4041        struct skin *node;
4042
4043        node = getscreennodebyname(screenname, nodename);
4044        m_lock(&status.drawingmutex, 0);
4045        if(node != status.skinerr)
4046                drawnode(node, 1);
4047
4048        drawscreenalways(node, screencalc);
4049        blitfb(0);
4050        m_unlock(&status.drawingmutex, 0);
4051
4052        return 0;
4053}
4054
4055//flag 0: draw normal with allways
4056//flag 1: draw without allways
4057//flag 2: from thread (mutex is set in thread)
4058//flag 3: unused
4059//flag 4: same as 0 but animate
4060//screencalc 0: calculate and draw
4061//screencalc 1: only calculate without hidden nodes
4062//screencalc 2: only calculate hidden nodes
4063int drawscreen(struct skin* node, int screencalc, int flag)
4064{
4065        struct fb* merkskinfb = NULL;
4066        int ret;
4067        struct skin *child = NULL, *parent = NULL, *oldparent = NULL;
4068
4069        if(node == NULL)
4070        {
4071                err("node = NULL");
4072                return 1;
4073        }
4074
4075        if(status.skinblink == 0)
4076                status.skinblink = 1;
4077        else
4078                status.skinblink = 0;
4079
4080        if(flag == 0 || flag == 4)
4081                m_lock(&status.drawingmutex, 0);
4082
4083        parent = skin;
4084
4085        ret = setnodeattr(node, parent, screencalc);
4086        if(ret == 1)
4087        {
4088                if(flag == 0 || flag == 4)
4089                        m_unlock(&status.drawingmutex, 0);
4090                err("setnodeattr ret = 1");
4091                return 1;
4092        }
4093        debug(100, "start drawscreen with screenname=%s", node->name);
4094        if(node->name != NULL && ostrstr(node->name, "LCD_") != NULL)
4095        {
4096                m_lock(&status.oledmutex, 25);
4097                if(lcdskinfb == NULL) {
4098#ifndef MIPSEL
4099                        if(node->name != NULL && ostrstr(node->name, "LCD_spf87") != NULL) {
4100                                unsigned char *newskinfb = calloc(1, 4 * 800 * 480);
4101                                if(newskinfb == NULL)
4102                                {
4103                                        if(flag == 0 || flag == 4)
4104                                                m_unlock(&status.drawingmutex, 0);
4105                                        m_unlock(&status.oledmutex, 25);
4106                                        return -2;
4107                                }
4108                                lcdskinfb = addfb("lcdskinfb", 999, 800, 480, 4, -1, newskinfb, 4 * 800 * 480, 0);
4109                        }
4110                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf72") != NULL) {
4111                                unsigned char *newskinfb = calloc(1, 4 * 800 * 480);
4112                                if(newskinfb == NULL)
4113                                {
4114                                        if(flag == 0 || flag == 4)
4115                                                m_unlock(&status.drawingmutex, 0);
4116                                        m_unlock(&status.oledmutex, 25);
4117                                        return -2;
4118                                }
4119                                lcdskinfb = addfb("lcdskinfb", 999, 800, 480, 4, -1, newskinfb, 4 * 800 * 480, 0);
4120                        }
4121                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf83") != NULL) {
4122                                unsigned char *newskinfb = calloc(1, 4 * 800 * 600);
4123                                if(newskinfb == NULL)
4124                                {
4125                                        if(flag == 0 || flag == 4)
4126                                                m_unlock(&status.drawingmutex, 0);
4127                                        m_unlock(&status.oledmutex, 25);
4128                                        return -2;
4129                                }
4130                                lcdskinfb = addfb("lcdskinfb", 999, 800, 600, 4, -1, newskinfb, 4 * 800 * 600, 0);
4131                        }
4132                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf85") != NULL) {
4133                                unsigned char *newskinfb = calloc(1, 4 * 800 * 600);
4134                                if(newskinfb == NULL)
4135                                {
4136                                        if(flag == 0 || flag == 4)
4137                                                m_unlock(&status.drawingmutex, 0);
4138                                        m_unlock(&status.oledmutex, 25);
4139                                        return -2;
4140                                }
4141                                lcdskinfb = addfb("lcdskinfb", 999, 800, 600, 4, -1, newskinfb, 4 * 800 * 600, 0);
4142                        }
4143                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf75") != NULL) {
4144                                unsigned char *newskinfb = calloc(1, 4 * 800 * 480);
4145                                if(newskinfb == NULL)
4146                                {
4147                                        if(flag == 0 || flag == 4)
4148                                                m_unlock(&status.drawingmutex, 0);
4149                                        m_unlock(&status.oledmutex, 25);
4150                                        return -2;
4151                                }
4152                                lcdskinfb = addfb("lcdskinfb", 999, 800, 480, 4, -1, newskinfb, 4 * 800 * 480, 0);
4153                        }
4154                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf107") != NULL) {
4155                                unsigned char *newskinfb = calloc(1, 4 * 1024 * 600);
4156                                if(newskinfb == NULL)
4157                                {
4158                                        if(flag == 0 || flag == 4)
4159                                                m_unlock(&status.drawingmutex, 0);
4160                                        m_unlock(&status.oledmutex, 25);
4161                                        return -2;
4162                                }
4163                                lcdskinfb = addfb("lcdskinfb", 999, 1024, 600, 4, -1, newskinfb, 4 * 1024 * 600, 0);
4164                        }
4165                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf105") != NULL) {
4166                                unsigned char *newskinfb = calloc(1, 4 * 1024 * 600);
4167                                if(newskinfb == NULL)
4168                                {
4169                                        if(flag == 0 || flag == 4)
4170                                                m_unlock(&status.drawingmutex, 0);
4171                                        m_unlock(&status.oledmutex, 25);
4172                                        return -2;
4173                                }
4174                                lcdskinfb = addfb("lcdskinfb", 999, 1024, 600, 4, -1, newskinfb, 4 * 1024 * 600, 0);
4175                        }
4176                        else {
4177                                unsigned char *newskinfb = calloc(1, 4 * 320 * 240);
4178                                if(newskinfb == NULL)
4179                                {
4180                                        if(flag == 0 || flag == 4)
4181                                                m_unlock(&status.drawingmutex, 0);
4182                                        m_unlock(&status.oledmutex, 25);
4183                                        return -2;
4184                                }
4185                                lcdskinfb = addfb("lcdskinfb", 999, 320, 240, 4, -1, newskinfb, 4 * 320 * 240, 0);
4186                        }
4187#else
4188                        if(node->name != NULL && ostrstr(node->name, "LCD_spf87") != NULL)
4189                                lcdskinfb = oledaddfb(800, 480);
4190                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf72") != NULL)
4191                                lcdskinfb = oledaddfb(800, 480);
4192                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf83") != NULL)
4193                                lcdskinfb = oledaddfb(800, 600);
4194                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf85") != NULL)
4195                                lcdskinfb = oledaddfb(800, 600);
4196                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf75") != NULL)
4197                                lcdskinfb = oledaddfb(800, 480);
4198                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf107") != NULL)
4199                                lcdskinfb = oledaddfb(1024, 600);
4200                        else if(node->name != NULL && ostrstr(node->name, "LCD_spf105") != NULL)
4201                                lcdskinfb = oledaddfb(1024, 600);
4202                        else
4203                                lcdskinfb = oledaddfb(320, 240);
4204                        if(lcdskinfb == NULL)
4205                        {
4206                                if(flag == 0 || flag == 4)
4207                                        m_unlock(&status.drawingmutex, 0);
4208                                m_unlock(&status.oledmutex, 25);
4209                                return -2;
4210                        }
4211#endif
4212                }
4213                merkskinfb = skinfb;
4214                //memset(lcdskinfb->fb, 0, lcdskinfb->varfbsize);
4215                skinfb = lcdskinfb;
4216        }
4217        else if(node->name != NULL && ostrstr(node->name, "OLED_") != NULL)
4218        {
4219                m_lock(&status.oledmutex, 25);
4220                if(oledskinfb == NULL) {
4221                        if(node->name != NULL && ostrstr(node->name, "OLED_nemesis") != NULL) {
4222                                debug(100, "alloc OLED_nemesis framebuffer");
4223                                oledskinfb = oledaddfb(256, 64);
4224                                if(oledskinfb == NULL)
4225                                {
4226                                        if(flag == 0 || flag == 4)
4227                                                m_unlock(&status.drawingmutex, 0);
4228                                        return -2;
4229                                }
4230                        }
4231                        else if(node->name != NULL && ostrstr(node->name, "OLED_dream1") != NULL) {
4232                                debug(100, "alloc OLED_dream1 framebuffer");
4233                                oledskinfb = oledaddfb(128, 64);
4234                                if(oledskinfb == NULL)
4235                                {
4236                                        if(flag == 0 || flag == 4)
4237                                                m_unlock(&status.drawingmutex, 0);
4238                                        return -2;
4239                                }
4240                        }
4241                }
4242                merkskinfb = skinfb;
4243                skinfb = oledskinfb;
4244        }
4245
4246        if(screencalc == 0 || flag == 4)
4247        {
4248                if(flag == 0 || flag == 2 || flag == 4) clearscreenalways();
4249                drawnode(node, 0);
4250        }
4251        parent = node;
4252        oldparent = node;
4253        child = node->child;
4254
4255        while(child != NULL)
4256        {
4257                if(child->parentpointer != NULL)
4258                        parent = child->parentpointer;
4259                else if(child->parent != NULL)
4260                {
4261                        parent = getscreennode(node, child->parent);
4262                        if(parent == status.skinerr) parent = oldparent;
4263                }
4264                else
4265                        parent = oldparent;
4266
4267                // hid minitvbg
4268                if(child->name != NULL && ostrstr(child->name, "minitvbg") != NULL && getskinconfigint("minitv", NULL) == 1)
4269                        child->hidden = YES;
4270
4271                if(setnodeattr(child, parent, screencalc) == 0 && screencalc == 0)
4272                        drawnode(child, 1);
4273                child = child->next;
4274        }
4275
4276        if(flag == 0 || flag == 2 || flag == 4)
4277        {
4278                if(screencalc == 0)
4279                {
4280                        if(merkskinfb != NULL)
4281                        {
4282                                if(node->name != NULL && ostrstr(node->name, "LCD_spf") != NULL)
4283                                        write_FB_to_JPEG_file(skinfb->fb, skinfb->width, skinfb->height, "/tmp/titanlcd.jpg", 75);
4284                                else if(node->name != NULL && ostrstr(node->name, "OLED_") != NULL)
4285                                        write2oled(skinfb->fb, skinfb->width, skinfb->height);
4286                                else
4287                                        pngforlcd(skinfb->fb, skinfb->width, skinfb->height);
4288                        }
4289                        else
4290                        {
4291                                status.drawscreencount++;
4292                                drawscreenalways(node, screencalc);
4293                                if(flag == 4)
4294                                        blitfb(1);
4295                                else
4296                                        blitfb(0);
4297                        }
4298                }
4299        }
4300
4301        if(merkskinfb != NULL)
4302        {
4303                debug(100, "no framebuffer screenname=%s", node->name);
4304                /*delete temporary FB*/
4305#ifndef MIPSEL
4306                if(skinfb == oledskinfb)
4307#else
4308                if(skinfb == oledskinfb || skinfb == lcdskinfb)
4309#endif
4310                {
4311                        skinfb = merkskinfb;
4312                        merkskinfb = NULL;
4313                }
4314                else
4315                {
4316                        debug(100, "free lcdskinfb");
4317                        free(skinfb->fb); skinfb->fb = NULL;
4318                        skinfb = merkskinfb;
4319                        merkskinfb = NULL;
4320                        delfb("lcdskinfb");
4321                        lcdskinfb = NULL;
4322                }
4323                debug(100, "no framebuffer end");
4324                m_unlock(&status.oledmutex, 25);
4325        }
4326        //else
4327        //{
4328        //      if(ostrcmp(getconfig("write_fb_to_jpeg", NULL), "yes") == 0)
4329        //              write_FB_to_JPEG_file(skinfb->fb, skinfb->width, skinfb->height, "/tmp/fb.jpg", 3);
4330        //}
4331        if(flag == 0 || flag == 4)
4332                m_unlock(&status.drawingmutex, 0);
4333        debug(100, "ende drawscreen with screenname=%s", node->name);
4334        return 0;
4335}
4336
4337int drawscreenbyname(char* screenname, int screencalc, int flag)
4338{
4339        int ret;
4340        struct skin* node = NULL;
4341
4342        node = getscreen(screenname);
4343        if(node == status.skinerr)
4344        {
4345                err("screen not found (%s)", screenname);
4346                return 1;
4347        }
4348
4349        ret = drawscreen(node, screencalc, flag);
4350        return ret;
4351}
4352
4353int changeinput(struct skin* node, char* text)
4354{
4355        int ret = 1;
4356
4357        if(node != NULL)
4358        {
4359                free(node->input);
4360                if(text != NULL)
4361                {
4362                        if((node->type & INPUTBOXNUM) && node->mask != NULL && strlen(text) == 0)
4363                                node->input = strdup(node->mask);
4364                        else
4365                                node->input = strdup(text);
4366                }
4367                else
4368                {
4369                        if((node->type & INPUTBOXNUM) && node->mask != NULL)
4370                                node->input = strdup(node->mask);
4371                        else
4372                                node->input = text;
4373                }
4374                ret = 0;
4375        }
4376
4377        return ret;
4378}
4379
4380int changetext(struct skin* node, char* text)
4381{
4382        int ret = 1;
4383
4384        if(node != NULL)
4385        {
4386                free(node->text);
4387                if(text != NULL)
4388                        node->text = strdup(text);
4389                else
4390                        node->text = text;
4391                ret = 0;
4392        }
4393
4394        return ret;
4395}
4396
4397int changetext2(struct skin* node, char* text)
4398{
4399        int ret = 1;
4400
4401        if(node != NULL)
4402        {
4403                free(node->text2);
4404                if(text != NULL)
4405                        node->text2 = strdup(text);
4406                else
4407                        node->text2 = text;
4408                ret = 0;
4409        }
4410
4411        return ret;
4412}
4413
4414
4415int changename(struct skin* node, char* text)
4416{
4417        int ret = 1;
4418
4419        if(node != NULL)
4420        {
4421                free(node->name);
4422                if(text != NULL)
4423                        node->name = strdup(text);
4424                else
4425                        node->name = strdup("unknown");
4426                ret = 0;
4427        }
4428
4429        return ret;
4430}
4431
4432int changepicmem(struct skin* node, char* text, int timeout, int del)
4433{
4434        unsigned long width = 0, height = 0, rowbytes = 0;
4435        int ret = 1, channels = 0, memfd = -1, length = 0;
4436        unsigned char* buf = NULL;
4437
4438        if(node != NULL)
4439        {
4440                free(node->pic);
4441                if(text != NULL)
4442                {
4443                        node->picmem = 1;
4444                        node->pic = changepicpath(text);
4445
4446                        if(getpic(node->pic) == NULL)
4447                        {
4448                                length = strlen(node->pic);
4449                                if(node->pic[length - 1] == 'g' && node->pic[length - 2] == 'n' && node->pic[length - 3] == 'p')
4450                                        buf = readpng(node->pic, &width, &height, &rowbytes, &channels, 0, 0, 0, 0, 0, 0);
4451                                else if(getconfigint("pichwdecode", NULL) == 1)
4452                                        readjpg(node->pic, &width, &height, &rowbytes, &channels, &buf, &memfd);
4453                                else
4454                                        buf = loadjpg(node->pic, &width, &height, &rowbytes, &channels, 1);
4455                                addpic(node->pic, buf, memfd, width, height, rowbytes, channels, timeout, del, NULL);
4456                        }
4457                }
4458                else
4459                        node->pic = text;
4460                ret = 0;
4461        }
4462
4463        return ret;
4464}
4465
4466int changepic(struct skin* node, char* text)
4467{
4468        int ret = 1;
4469
4470        if(node != NULL)
4471        {
4472                node->picmem = 0;
4473                free(node->pic);
4474                if(text != NULL)
4475                        node->pic = changepicpath(text);
4476                else
4477                        node->pic = text;
4478                ret = 0;
4479        }
4480
4481        return ret;
4482}
4483
4484int changeselectpic(struct skin* node, char* text)
4485{
4486        int ret = 1;
4487
4488        if(node != NULL)
4489        {
4490                free(node->selectpic);
4491                if(text != NULL)
4492                        node->selectpic = changepicpath(text);
4493                else
4494                        node->selectpic = text;
4495                ret = 0;
4496        }
4497
4498        return ret;
4499}
4500
4501int changetitle(struct skin* node, char* text)
4502{
4503        int ret = 1;
4504
4505        struct skin* titletext = getscreennode(node, "titletext");
4506        if( (text != NULL) && (titletext != status.skinerr) )
4507                changetext(titletext, text);
4508        else
4509                debug(10, "failed titletext=%s", text);
4510
4511        if(node != NULL)
4512        {
4513                free(node->title);
4514                if( (text != NULL) && (node->fontsize > 1) )
4515                {
4516                        node->title = strdup(text);
4517                        node->titlesize = node->fontsize + 6;
4518                }
4519                else
4520                {
4521                        node->title = NULL;
4522                        node->titlesize = 0;
4523                }
4524                ret = 0;
4525        }
4526
4527        return ret;
4528}
4529
4530int changemask(struct skin* node, char* text)
4531{
4532        int ret = 1;
4533
4534        if(node != NULL)
4535        {
4536                free(node->mask);
4537                if(text != NULL)
4538                {
4539                        if((node->type & INPUTBOXNUM) && (node->input == NULL || strlen(node->input) == 0))
4540                        {
4541                                node->mask = strdup(text);
4542                                free(node->input);
4543                                node->input = strdup(text);
4544                        }
4545                        else
4546                                node->mask = strdup(text);
4547                }
4548                else
4549                        node->mask = text;
4550                ret = 0;
4551        }
4552
4553        return ret;
4554}
4555
4556int changeret(struct skin* node, char* text)
4557{
4558        int ret = 1;
4559
4560        if(node != NULL)
4561        {
4562                free(node->ret);
4563                if(text != NULL)
4564                        node->ret = strdup(text);
4565                else
4566                        node->ret = text;
4567                ret = 0;
4568        }
4569
4570        return ret;
4571}
4572
4573int changeparent(struct skin* node, char* text)
4574{
4575        int ret = 1;
4576
4577        if(node != NULL)
4578        {
4579                free(node->parent);
4580                if(text != NULL)
4581                        node->parent = strdup(text);
4582                else
4583                        node->parent = text;
4584                ret = 0;
4585        }
4586
4587        return ret;
4588}
4589
4590int changefont(struct skin* node, char* text)
4591{
4592        int ret = 1;
4593
4594        if(node != NULL)
4595        {
4596                free(node->font);
4597                if(text != NULL)
4598                        node->font = strdup(text);
4599                else
4600                        node->font = text;
4601                ret = 0;
4602        }
4603
4604        return ret;
4605}
4606
4607int changeparam1(struct skin* node, char* text)
4608{
4609        int ret = 1;
4610
4611        if(node != NULL)
4612        {
4613                free(node->param1);
4614                if(text != NULL)
4615                        node->param1 = strdup(text);
4616                else
4617                        node->param1 = text;
4618                ret = 0;
4619        }
4620
4621        return ret;
4622}
4623
4624int changeparam2(struct skin* node, char* text)
4625{
4626        int ret = 1;
4627
4628        if(node != NULL)
4629        {
4630                free(node->param2);
4631                if(text != NULL)
4632                        node->param2 = strdup(text);
4633                else
4634                        node->param2 = text;
4635                ret = 0;
4636        }
4637
4638        return ret;
4639}
4640
4641int changechoiceboxvalue(struct skin* node, char* text)
4642{
4643        int ret = 1;
4644
4645        if(node != NULL)
4646        {
4647                free(node->choiceboxvalue);
4648                if(text != NULL)
4649                        node->choiceboxvalue = strdup(text);
4650                else
4651                        node->choiceboxvalue = text;
4652                ret = 0;
4653        }
4654
4655        return ret;
4656}
4657
4658unsigned char * resize(unsigned char *origin, int ox, int oy, int dx, int dy, int type, unsigned char * dst, int flag)
4659{
4660        unsigned char * cr;
4661
4662        if(dst == NULL)
4663        {
4664                cr = (unsigned char*) malloc(dx*dy*3);
4665
4666                if(cr == NULL)
4667                {
4668                        printf("Error: malloc\n");
4669                        return(origin);
4670                }
4671        }
4672        else
4673                cr = dst;
4674
4675        if(type == 1)
4676        {
4677                unsigned char *p,*l;
4678                int i,j,k,ip;
4679                l = cr;
4680
4681                for(j=0; j<dy; j++, l += dx*3)
4682                {
4683                        p = origin + (j*oy/dy*ox*3);
4684                        for(i=0, k=0; i<dx; i++, k+=3)
4685                        {
4686                                ip=i*ox/dx*3;
4687                                memmove(l+k, p+ip, 3);
4688                        }
4689                }
4690        }
4691        else
4692        {
4693                unsigned char *p,*q;
4694                int i,j,k,l,ya,yb;
4695                int sq,r,g,b;
4696
4697                p=cr;
4698
4699                int xa_v[dx];
4700                for(i=0;i<dx;i++)
4701                        xa_v[i] = i*ox/dx;
4702                int xb_v[dx+1];
4703
4704                for(i=0;i<dx;i++)
4705                {
4706                        xb_v[i]= (i+1)*ox/dx;
4707                        if(xb_v[i]>=ox)
4708                                xb_v[i]=ox-1;
4709                }
4710
4711                for(j=0;j<dy;j++)
4712                {
4713                        ya= j*oy/dy;
4714                        yb= (j+1)*oy/dy; if(yb>=oy) yb=oy-1;
4715                        for(i=0;i<dx;i++,p+=3)
4716                        {
4717                                for(l=ya,r=0,g=0,b=0,sq=0;l<=yb;l++)
4718                                {
4719                                        q=origin+((l*ox+xa_v[i])*3);
4720                                        for(k=xa_v[i];k<=xb_v[i];k++,q+=3,sq++)
4721                                        {
4722                                                r+=q[0]; g+=q[1]; b+=q[2];
4723                                        }
4724                                }
4725                                p[0]=r/sq; p[1]=g/sq; p[2]=b/sq;
4726                        }
4727                }
4728        }
4729
4730        if(flag == 1)
4731                free(origin);
4732
4733        return(cr);
4734}
4735
4736#endif
Note: See TracBrowser for help on using the repository browser.