source: titan/titan/skin.h @ 38559

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

fix

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