Root/src/gmenu2x.cpp

1/***************************************************************************
2 * Copyright (C) 2006 by Massimiliano Torromeo *
3 * massimiliano.torromeo@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21#include <iostream>
22#include <sstream>
23#include <fstream>
24#include <algorithm>
25#include <stdlib.h>
26#include <unistd.h>
27#include <math.h>
28#include <SDL.h>
29#include <SDL_gfxPrimitives.h>
30#include <signal.h>
31
32#include <sys/statvfs.h>
33#include <errno.h>
34
35#include "gp2x.h"
36#include <sys/fcntl.h> //for battery
37
38//for browsing the filesystem
39#include <sys/stat.h>
40#include <sys/types.h>
41#include <dirent.h>
42
43//for soundcard
44#include <sys/ioctl.h>
45#include <linux/soundcard.h>
46
47#include "linkapp.h"
48#include "linkaction.h"
49#include "menu.h"
50#include "asfont.h"
51#include "surface.h"
52#include "filedialog.h"
53#include "gmenu2x.h"
54#include "filelister.h"
55
56#include "iconbutton.h"
57#include "messagebox.h"
58#include "inputdialog.h"
59#include "settingsdialog.h"
60#include "wallpaperdialog.h"
61#include "textdialog.h"
62#include "menusettingint.h"
63#include "menusettingbool.h"
64#include "menusettingrgba.h"
65#include "menusettingstring.h"
66#include "menusettingmultistring.h"
67#include "menusettingfile.h"
68#include "menusettingimage.h"
69#include "menusettingdir.h"
70
71#include "debug.h"
72
73#include <sys/mman.h>
74
75#ifdef TARGET_PANDORA
76//#include <pnd_container.h>
77//#include <pnd_conf.h>
78//#include <pnd_discovery.h>
79#endif
80
81#ifdef _CARD_ROOT
82const char *CARD_ROOT = _CARD_ROOT;
83#else
84const char *CARD_ROOT = "/card/"; //Note: Add a trailing /!
85#endif
86const int CARD_ROOT_LEN = 5;
87
88static GMenu2X *app;
89static string gmenu2x_home;
90
91using namespace std;
92using namespace fastdelegate;
93
94// Note: Keep this in sync with the enum!
95static const char *colorNames[NUM_COLORS] = {
96    "topBarBg",
97    "bottomBarBg",
98    "selectionBg",
99    "messageBoxBg",
100    "messageBoxBorder",
101    "messageBoxSelection",
102};
103
104static enum color stringToColor(const string &name)
105{
106    for (unsigned int i = 0; i < NUM_COLORS; i++) {
107        if (strcmp(colorNames[i], name.c_str()) == 0) {
108            return (enum color)i;
109        }
110    }
111    return (enum color)-1;
112}
113
114static const char *colorToString(enum color c)
115{
116    return colorNames[c];
117}
118
119static void quit_all(int err) {
120    delete app;
121    exit(err);
122}
123
124const string GMenu2X::getHome(void)
125{
126    return gmenu2x_home;
127}
128
129int main(int /*argc*/, char * /*argv*/[]) {
130    INFO("----\nGMenu2X starting: If you read this message in the logs, check http://gmenu2x.sourceforge.net/page/Troubleshooting for a solution\n----\n");
131
132    signal(SIGINT, &quit_all);
133    signal(SIGSEGV,&quit_all);
134    signal(SIGTERM,&quit_all);
135
136    char *home = getenv("HOME");
137    if (home == NULL) {
138        ERROR("Unable to find gmenu2x home directory. The $HOME variable is not defined.\n");
139        return 1;
140    }
141
142    gmenu2x_home = (string)home + (string)"/.gmenu2x";
143    if (!fileExists(gmenu2x_home) && mkdir(gmenu2x_home.c_str(), 0770) < 0) {
144        ERROR("Unable to create gmenu2x home directory.\n");
145        return 1;
146    }
147
148    DEBUG("Home path: %s.\n", gmenu2x_home.c_str());
149
150    app = new GMenu2X();
151    DEBUG("Starting main()\n");
152    app->main();
153
154    return 0;
155}
156
157void GMenu2X::gp2x_init() {
158#ifdef TARGET_GP2X
159/* gp2x_mem = open("/dev/mem", O_RDWR);
160    gp2x_memregs=(unsigned short *)mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_mem, 0xc0000000);
161    MEM_REG=&gp2x_memregs[0];
162    if (f200) {
163        //if wm97xx fails to open, set f200 to false to prevent any further access to the touchscreen
164        f200 = ts.init();
165    }*/
166    batteryHandle = fopen("/sys/class/power_supply/battery/capacity", "r");
167    usbHandle = fopen("/sys/class/power_supply/USB/online", "r");
168    acHandle = fopen("/sys/class/power_supply/ac/online", "r");
169    backlightHandle =
170        fopen("/sys/class/backlight/gpm940b0-bl/brightness", "w+");
171#endif
172}
173
174void GMenu2X::gp2x_deinit() {
175#ifdef TARGET_GP2X
176/* if (gp2x_mem!=0) {
177        gp2x_memregs[0x28DA>>1]=0x4AB;
178        gp2x_memregs[0x290C>>1]=640;
179        close(gp2x_mem);
180    }
181
182    if (f200) ts.deinit();*/
183#endif
184    if (batteryHandle) fclose(batteryHandle);
185    if (backlightHandle) fclose(backlightHandle);
186    if (usbHandle) fclose(usbHandle);
187    if (acHandle) fclose(acHandle);
188}
189
190void GMenu2X::gp2x_tvout_on(bool /*pal*/) {
191#ifdef TARGET_GP2X
192/* if (gp2x_mem!=0) {
193// Ioctl_Dummy_t *msg;
194// int TVHandle = ioctl(SDL_videofd, FBMMSP2CTRL, msg);
195        if (cx25874!=0) gp2x_tvout_off();
196        //if tv-out is enabled without cx25874 open, stop
197        //if (gp2x_memregs[0x2800>>1]&0x100) return;
198        cx25874 = open("/dev/cx25874",O_RDWR);
199        ioctl(cx25874, _IOW('v', 0x02, unsigned char), pal ? 4 : 3);
200        gp2x_memregs[0x2906>>1]=512;
201        gp2x_memregs[0x28E4>>1]=gp2x_memregs[0x290C>>1];
202        gp2x_memregs[0x28E8>>1]=239;
203    }*/
204#endif
205}
206
207void GMenu2X::gp2x_tvout_off() {
208#ifdef TARGET_GP2X
209/* if (gp2x_mem!=0) {
210        close(cx25874);
211        cx25874 = 0;
212        gp2x_memregs[0x2906>>1]=1024;
213    }*/
214#endif
215}
216
217
218GMenu2X::GMenu2X() {
219    //Detect firmware version and type
220    if (fileExists("/etc/open2x")) {
221        fwType = "open2x";
222        fwVersion = "";
223    } else {
224        fwType = "gph";
225        fwVersion = "";
226    }
227#ifdef TARGET_GP2X
228    f200 = fileExists("/dev/touchscreen/wm97xx");
229#else
230    f200 = true;
231#endif
232
233    //open2x
234    savedVolumeMode = 0;
235    volumeMode = VOLUME_MODE_NORMAL;
236    volumeScalerNormal = VOLUME_SCALER_NORMAL;
237    volumeScalerPhones = VOLUME_SCALER_PHONES;
238
239    o2x_usb_net_on_boot = false;
240    o2x_usb_net_ip = "";
241    o2x_ftp_on_boot = false;
242    o2x_telnet_on_boot = false;
243    o2x_gp2xjoy_on_boot = false;
244    o2x_usb_host_on_boot = false;
245    o2x_usb_hid_on_boot = false;
246    o2x_usb_storage_on_boot = false;
247
248    usbnet = samba = inet = web = false;
249    useSelectionPng = false;
250
251    //load config data
252    readConfig();
253    if (fwType=="open2x") {
254        readConfigOpen2x();
255        // VOLUME MODIFIER
256        switch(volumeMode) {
257            case VOLUME_MODE_MUTE: setVolumeScaler(VOLUME_SCALER_MUTE); break;
258            case VOLUME_MODE_PHONES: setVolumeScaler(volumeScalerPhones); break;
259            case VOLUME_MODE_NORMAL: setVolumeScaler(volumeScalerNormal); break;
260        }
261    } else
262        readCommonIni();
263
264    halfX = resX/2;
265    halfY = resY/2;
266    bottomBarIconY = resY-18;
267    bottomBarTextY = resY-10;
268
269    path = "";
270    getExePath();
271
272    batteryHandle = 0;
273    backlightHandle = 0;
274    usbHandle = 0;
275    acHandle = 0;
276
277
278#ifdef TARGET_GP2X
279    gp2x_mem = 0;
280    cx25874 = 0;
281    gp2x_init();
282
283    //Fix tv-out
284/* if (gp2x_mem!=0) {
285        if (gp2x_memregs[0x2800>>1]&0x100) {
286            gp2x_memregs[0x2906>>1]=512;
287            //gp2x_memregs[0x290C>>1]=640;
288            gp2x_memregs[0x28E4>>1]=gp2x_memregs[0x290C>>1];
289        }
290        gp2x_memregs[0x28E8>>1]=239;
291    }*/
292#endif
293
294    //Screen
295    if( SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_JOYSTICK|SDL_INIT_TIMER)<0 ) {
296        ERROR("Could not initialize SDL: %s\n", SDL_GetError());
297        quit();
298    }
299
300    s = new Surface();
301#ifdef TARGET_GP2X
302    {
303        //I use a tmp variable to hide the cursor as soon as possible (and create the double buffer surface only after that)
304        //I'm forced to use SW surfaces since with HW there are issuse with changing the clock frequency
305        SDL_Surface *tmps = SDL_SetVideoMode(resX, resY, confInt["videoBpp"], SDL_SWSURFACE);
306        SDL_ShowCursor(0);
307        s->enableVirtualDoubleBuffer(tmps);
308    }
309#else
310    s->raw = SDL_SetVideoMode(resX, resY, confInt["videoBpp"], SDL_HWSURFACE|SDL_DOUBLEBUF);
311#endif
312
313    bg = NULL;
314    font = NULL;
315    menu = NULL;
316    setSkin(confStr["skin"], false);
317    initMenu();
318
319    if (!fileExists(confStr["wallpaper"])) {
320        DEBUG("No wallpaper defined; we will take the default one.\n");
321        confStr["wallpaper"] = DEFAULT_WALLPAPER_PATH;
322    }
323
324    initBG();
325
326    /* If a user-specified input.conf file exists, we load it;
327     * otherwise, we load the default one. */
328    const char *input_file = (getHome() + "/input.conf").c_str();
329    if (fileExists(input_file)) {
330        DEBUG("Loading user-specific input.conf file: %s.\n", input_file);
331    } else {
332        input_file = GMENU2X_SYSTEM_DIR "/input.conf";
333        DEBUG("Loading system input.conf file: %s.\n", input_file);
334    }
335
336    input.init(input_file);
337    PowerSaver::getInstance()->setScreenTimeout( confInt["backlightTimeout"] );
338    setInputSpeed();
339    initServices();
340    setBacklight(confInt["backlight"]);
341    setVolume(confInt["globalVolume"]);
342    applyDefaultTimings();
343    setClock(confInt["menuClock"]);
344    //recover last session
345    readTmp();
346    if (lastSelectorElement>-1 && menu->selLinkApp()!=NULL && (!menu->selLinkApp()->getSelectorDir().empty() || !lastSelectorDir.empty()))
347        menu->selLinkApp()->selector(lastSelectorElement,lastSelectorDir);
348
349}
350
351GMenu2X::~GMenu2X() {
352    writeConfig();
353    if (fwType=="open2x") writeConfigOpen2x();
354
355    quit();
356
357    free(menu);
358    free(s);
359    free(font);
360}
361
362void GMenu2X::quit() {
363    fflush(NULL);
364    sc.clear();
365    s->free();
366    SDL_Quit();
367#ifdef TARGET_GP2X
368/* if (gp2x_mem!=0) {
369        //Fix tv-out
370        if (gp2x_memregs[0x2800>>1]&0x100) {
371            gp2x_memregs[0x2906>>1]=512;
372            gp2x_memregs[0x28E4>>1]=gp2x_memregs[0x290C>>1];
373        }
374        gp2x_deinit();
375    }*/
376#endif
377}
378
379void GMenu2X::initBG() {
380    sc.del("bgmain");
381
382    if (bg != NULL) free(bg);
383
384    if (!fileExists(confStr["wallpaper"])) {
385        bg = new Surface(s);
386        bg->box(0,0,resX,resY,0,0,0);
387    } else {
388        // Note: Copy constructor converts to display format.
389        bg = new Surface(Surface(confStr["wallpaper"]));
390    }
391
392    drawTopBar(bg);
393    drawBottomBar(bg);
394
395    Surface *bgmain = new Surface(bg);
396    sc.add(bgmain,"bgmain");
397
398    Surface sd("imgs/sd.png", confStr["skin"]);
399    Surface cpu("imgs/cpu.png", confStr["skin"]);
400    Surface volume("imgs/volume.png", confStr["skin"]);
401    string df = getDiskFree();
402
403    sd.blit( sc["bgmain"], 3, bottomBarIconY );
404    sc["bgmain"]->write( font, df, 22, bottomBarTextY, ASFont::HAlignLeft, ASFont::VAlignMiddle );
405    volumeX = 27+font->getTextWidth(df);
406    volume.blit( sc["bgmain"], volumeX, bottomBarIconY );
407    volumeX += 19;
408    cpuX = volumeX+font->getTextWidth("100")+5;
409    cpu.blit( sc["bgmain"], cpuX, bottomBarIconY );
410    cpuX += 19;
411    manualX = cpuX+font->getTextWidth("300Mhz")+5;
412
413    int serviceX = resX-38;
414    if (usbnet) {
415        if (web) {
416            Surface webserver("imgs/webserver.png", confStr["skin"]);
417            webserver.blit( sc["bgmain"], serviceX, bottomBarIconY );
418            serviceX -= 19;
419        }
420        if (samba) {
421            Surface sambaS("imgs/samba.png", confStr["skin"]);
422            sambaS.blit( sc["bgmain"], serviceX, bottomBarIconY );
423            serviceX -= 19;
424        }
425        if (inet) {
426            Surface inetS("imgs/inet.png", confStr["skin"]);
427            inetS.blit( sc["bgmain"], serviceX, bottomBarIconY );
428            serviceX -= 19;
429        }
430    }
431}
432
433void GMenu2X::initFont() {
434    if (font != NULL) {
435        free(font);
436        font = NULL;
437    }
438
439    string fontFile = sc.getSkinFilePath("imgs/font.png");
440    if (fontFile.empty()) {
441        ERROR("Font png not found!\n");
442        quit();
443        exit(-1);
444    }
445    font = new ASFont(fontFile);
446}
447
448void GMenu2X::initMenu() {
449    //Menu structure handler
450    menu = new Menu(this);
451    for (uint i=0; i<menu->getSections().size(); i++) {
452        //Add virtual links in the applications section
453        if (menu->getSections()[i]=="applications") {
454            menu->addActionLink(i,"Explorer",MakeDelegate(this,&GMenu2X::explorer),tr["Launch an application"],"skin:icons/explorer.png");
455        }
456
457        //Add virtual links in the setting section
458        else if (menu->getSections()[i]=="settings") {
459            menu->addActionLink(i,"GMenu2X",MakeDelegate(this,&GMenu2X::options),tr["Configure GMenu2X's options"],"skin:icons/configure.png");
460            if (fwType=="open2x")
461                menu->addActionLink(i,"Open2x",MakeDelegate(this,&GMenu2X::settingsOpen2x),tr["Configure Open2x system settings"],"skin:icons/o2xconfigure.png");
462            menu->addActionLink(i,tr["Skin"],MakeDelegate(this,&GMenu2X::skinMenu),tr["Configure skin"],"skin:icons/skin.png");
463            menu->addActionLink(i,tr["Wallpaper"],MakeDelegate(this,&GMenu2X::changeWallpaper),tr["Change GMenu2X wallpaper"],"skin:icons/wallpaper.png");
464#ifdef TARGET_GP2X
465/* menu->addActionLink(i,"TV",MakeDelegate(this,&GMenu2X::toggleTvOut),tr["Activate/deactivate tv-out"],"skin:icons/tv.png");
466            menu->addActionLink(i,"USB Sd",MakeDelegate(this,&GMenu2X::activateSdUsb),tr["Activate Usb on SD"],"skin:icons/usb.png");
467            if (fwType=="gph" && !f200)
468                menu->addActionLink(i,"USB Nand",MakeDelegate(this,&GMenu2X::activateNandUsb),tr["Activate Usb on Nand"],"skin:icons/usb.png");
469            //menu->addActionLink(i,"USB Root",MakeDelegate(this,&GMenu2X::activateRootUsb),tr["Activate Usb on the root of the Gp2x Filesystem"],"skin:icons/usb.png");*/
470#endif
471            if (fileExists(getHome()+"/log.txt"))
472                menu->addActionLink(i,tr["Log Viewer"],MakeDelegate(this,&GMenu2X::viewLog),tr["Displays last launched program's output"],"skin:icons/ebook.png");
473            menu->addActionLink(i,tr["About"],MakeDelegate(this,&GMenu2X::about),tr["Info about GMenu2X"],"skin:icons/about.png");
474        }
475    }
476
477    menu->setSectionIndex(confInt["section"]);
478    menu->setLinkIndex(confInt["link"]);
479
480    menu->loadIcons();
481
482    //DEBUG
483    //menu->addLink( CARD_ROOT, "sample.pxml", "applications" );
484}
485
486void GMenu2X::about() {
487    vector<string> text;
488    split(text,"GMenu2X is developed by Massimiliano \"Ryo\" Torromeo, and is released under the GPL-v2 license.\n\
489Website: http://gmenu2x.sourceforge.net\n\
490E-Mail & PayPal account: massimiliano.torromeo@gmail.com\n\
491\n\
492Thanks goes to...\n\
493\n\
494 Contributors\n\
495----\n\
496NoidZ for his gp2x' buttons graphics\n\
497\n\
498 Beta testers\n\
499----\n\
500Goemon4, PokeParadox, PSyMastR and Tripmonkey_uk\n\
501\n\
502 Translators\n\
503----\n\
504English & Italian by me\n\
505French by Yodaz\n\
506Danish by claus\n\
507Dutch by superfly\n\
508Spanish by pedator\n\
509Portuguese (Portugal) by NightShadow\n\
510Slovak by Jozef\n\
511Swedish by Esslan and Micket\n\
512German by fusion_power, johnnysnet and Waldteufel\n\
513Finnish by Jontte and Atte\n\
514Norwegian by cowai\n\
515Russian by XaMMaX90\n\
516\n\
517 Donors\n\
518----\n\
519EvilDragon (www.gp2x.de)\n\
520Tecnologie Creative (www.tecnologiecreative.it)\n\
521TelcoLou\n\
522gaterooze\n\
523deepmenace\n\
524superfly\n\
525halo9\n\
526sbock\n\
527b._.o._.b\n\
528Jacopastorius\n\
529lorystorm90\n\
530and all the anonymous donors...\n\
531(If I missed to list you or if you want to be removed, contact me.)","\n");
532    TextDialog td(this, "GMenu2X", tr.translate("Version $1 (Build date: $2)","0.10-test4",__DATE__,NULL), "icons/about.png", &text);
533    td.exec();
534}
535
536void GMenu2X::viewLog() {
537    string logfile = getHome()+"/log.txt";
538    if (fileExists(logfile)) {
539        ifstream inf(logfile.c_str(), ios_base::in);
540        if (inf.is_open()) {
541            vector<string> log;
542
543            string line;
544            while (getline(inf, line, '\n'))
545                log.push_back(line);
546            inf.close();
547
548            TextDialog td(this, tr["Log Viewer"], tr["Displays last launched program's output"], "icons/ebook.png", &log);
549            td.exec();
550
551            MessageBox mb(this, tr["Do you want to delete the log file?"], "icons/ebook.png");
552            mb.setButton(ACCEPT, tr["Yes"]);
553            mb.setButton(CLEAR, tr["No"]);
554            if (mb.exec() == ACCEPT) {
555                ledOn();
556                unlink(logfile.c_str());
557                sync();
558                menu->deleteSelectedLink();
559                ledOff();
560            }
561        }
562    }
563}
564
565void GMenu2X::readConfig() {
566    string conffile = getHome() + "/gmenu2x.conf";
567    if (fileExists(conffile)) {
568        ifstream inf(conffile.c_str(), ios_base::in);
569        if (inf.is_open()) {
570            string line;
571            while (getline(inf, line, '\n')) {
572                string::size_type pos = line.find("=");
573                string name = trim(line.substr(0,pos));
574                string value = trim(line.substr(pos+1,line.length()));
575
576                if (value.length()>1 && value.at(0)=='"' && value.at(value.length()-1)=='"')
577                    confStr[name] = value.substr(1,value.length()-2);
578                else
579                    confInt[name] = atoi(value.c_str());
580            }
581            inf.close();
582        }
583    }
584    if (!confStr["lang"].empty()) tr.setLang(confStr["lang"]);
585    if (!confStr["wallpaper"].empty() && !fileExists(confStr["wallpaper"])) confStr["wallpaper"] = "";
586    if (confStr["skin"].empty() || !fileExists("skins/"+confStr["skin"])) confStr["skin"] = "Default";
587
588    evalIntConf( &confInt["outputLogs"], 0, 0,1 );
589    evalIntConf( &confInt["maxClock"], 430, 30, 500 );
590    evalIntConf( &confInt["menuClock"], 200, 30, 430 );
591    evalIntConf( &confInt["globalVolume"], 67, 0,100 );
592    evalIntConf( &confInt["backlightTimeout"], 15, 0,120 );
593    evalIntConf( &confInt["backlight"], 100, 5,100 );
594    evalIntConf( &confInt["videoBpp"], 32,32,32 ); // 8,16
595
596    if (confStr["tvoutEncoding"] != "PAL") confStr["tvoutEncoding"] = "NTSC";
597    resX = constrain( confInt["resolutionX"], 320,1920 );
598    resY = constrain( confInt["resolutionY"], 240,1200 );
599}
600
601void GMenu2X::writeConfig() {
602    ledOn();
603    string conffile = getHome() + "/gmenu2x.conf";
604    ofstream inf(conffile.c_str());
605    if (inf.is_open()) {
606        ConfStrHash::iterator endS = confStr.end();
607        for(ConfStrHash::iterator curr = confStr.begin(); curr != endS; curr++)
608            inf << curr->first << "=\"" << curr->second << "\"" << endl;
609
610        ConfIntHash::iterator endI = confInt.end();
611        for(ConfIntHash::iterator curr = confInt.begin(); curr != endI; curr++)
612            inf << curr->first << "=" << curr->second << endl;
613
614        inf.close();
615        sync();
616    }
617    ledOff();
618}
619
620
621void GMenu2X::readConfigOpen2x() {
622    string conffile = "/etc/config/open2x.conf";
623    if (fileExists(conffile)) {
624        ifstream inf(conffile.c_str(), ios_base::in);
625        if (inf.is_open()) {
626            string line;
627            while (getline(inf, line, '\n')) {
628                string::size_type pos = line.find("=");
629                string name = trim(line.substr(0,pos));
630                string value = trim(line.substr(pos+1,line.length()));
631
632                if (name=="USB_NET_ON_BOOT") o2x_usb_net_on_boot = value == "y" ? true : false;
633                else if (name=="USB_NET_IP") o2x_usb_net_ip = value;
634                else if (name=="TELNET_ON_BOOT") o2x_telnet_on_boot = value == "y" ? true : false;
635                else if (name=="FTP_ON_BOOT") o2x_ftp_on_boot = value == "y" ? true : false;
636                else if (name=="GP2XJOY_ON_BOOT") o2x_gp2xjoy_on_boot = value == "y" ? true : false;
637                else if (name=="USB_HOST_ON_BOOT") o2x_usb_host_on_boot = value == "y" ? true : false;
638                else if (name=="USB_HID_ON_BOOT") o2x_usb_hid_on_boot = value == "y" ? true : false;
639                else if (name=="USB_STORAGE_ON_BOOT") o2x_usb_storage_on_boot = value == "y" ? true : false;
640                else if (name=="VOLUME_MODE") volumeMode = savedVolumeMode = constrain( atoi(value.c_str()), 0, 2);
641                else if (name=="PHONES_VALUE") volumeScalerPhones = constrain( atoi(value.c_str()), 0, 100);
642                else if (name=="NORMAL_VALUE") volumeScalerNormal = constrain( atoi(value.c_str()), 0, 150);
643            }
644            inf.close();
645        }
646    }
647}
648void GMenu2X::writeConfigOpen2x() {
649    ledOn();
650    string conffile = "/etc/config/open2x.conf";
651    ofstream inf(conffile.c_str());
652    if (inf.is_open()) {
653        inf << "USB_NET_ON_BOOT=" << ( o2x_usb_net_on_boot ? "y" : "n" ) << endl;
654        inf << "USB_NET_IP=" << o2x_usb_net_ip << endl;
655        inf << "TELNET_ON_BOOT=" << ( o2x_telnet_on_boot ? "y" : "n" ) << endl;
656        inf << "FTP_ON_BOOT=" << ( o2x_ftp_on_boot ? "y" : "n" ) << endl;
657        inf << "GP2XJOY_ON_BOOT=" << ( o2x_gp2xjoy_on_boot ? "y" : "n" ) << endl;
658        inf << "USB_HOST_ON_BOOT=" << ( (o2x_usb_host_on_boot || o2x_usb_hid_on_boot || o2x_usb_storage_on_boot) ? "y" : "n" ) << endl;
659        inf << "USB_HID_ON_BOOT=" << ( o2x_usb_hid_on_boot ? "y" : "n" ) << endl;
660        inf << "USB_STORAGE_ON_BOOT=" << ( o2x_usb_storage_on_boot ? "y" : "n" ) << endl;
661        inf << "VOLUME_MODE=" << volumeMode << endl;
662        if (volumeScalerPhones != VOLUME_SCALER_PHONES) inf << "PHONES_VALUE=" << volumeScalerPhones << endl;
663        if (volumeScalerNormal != VOLUME_SCALER_NORMAL) inf << "NORMAL_VALUE=" << volumeScalerNormal << endl;
664        inf.close();
665        sync();
666    }
667    ledOff();
668}
669
670void GMenu2X::writeSkinConfig() {
671    ledOn();
672
673    string conffile = getHome() + "/skins/";
674    if (!fileExists(conffile))
675      mkdir(conffile.c_str(), 0770);
676    conffile = conffile + confStr["skin"];
677    if (!fileExists(conffile))
678      mkdir(conffile.c_str(), 0770);
679    conffile = conffile + "/skin.conf";
680
681    ofstream inf(conffile.c_str());
682    if (inf.is_open()) {
683        ConfStrHash::iterator endS = skinConfStr.end();
684        for(ConfStrHash::iterator curr = skinConfStr.begin(); curr != endS; curr++)
685            inf << curr->first << "=\"" << curr->second << "\"" << endl;
686
687        ConfIntHash::iterator endI = skinConfInt.end();
688        for(ConfIntHash::iterator curr = skinConfInt.begin(); curr != endI; curr++)
689            inf << curr->first << "=" << curr->second << endl;
690
691        int i;
692        for (i = 0; i < NUM_COLORS; ++i) {
693            inf << colorToString((enum color)i) << "=#" << hex << skinConfColors[i].r << hex
694                << skinConfColors[i].g << hex << skinConfColors[i].b << hex
695                << skinConfColors[i].a << endl;
696        }
697
698        inf.close();
699        sync();
700    }
701    ledOff();
702}
703
704void GMenu2X::readCommonIni() {
705    if (fileExists("/usr/gp2x/common.ini")) {
706        ifstream inf("/usr/gp2x/common.ini", ios_base::in);
707        if (inf.is_open()) {
708            string line;
709            string section = "";
710            while (getline(inf, line, '\n')) {
711                line = trim(line);
712                if (line[0]=='[' && line[line.length()-1]==']') {
713                    section = line.substr(1,line.length()-2);
714                } else {
715                    string::size_type pos = line.find("=");
716                    string name = trim(line.substr(0,pos));
717                    string value = trim(line.substr(pos+1,line.length()));
718
719                    if (section=="usbnet") {
720                        if (name=="enable")
721                            usbnet = value=="true" ? true : false;
722                        else if (name=="ip")
723                            ip = value;
724
725                    } else if (section=="server") {
726                        if (name=="inet")
727                            inet = value=="true" ? true : false;
728                        else if (name=="samba")
729                            samba = value=="true" ? true : false;
730                        else if (name=="web")
731                            web = value=="true" ? true : false;
732                    }
733                }
734            }
735            inf.close();
736        }
737    }
738}
739
740void GMenu2X::writeCommonIni() {}
741
742void GMenu2X::readTmp() {
743    lastSelectorElement = -1;
744    if (fileExists("/tmp/gmenu2x.tmp")) {
745        ifstream inf("/tmp/gmenu2x.tmp", ios_base::in);
746        if (inf.is_open()) {
747            string line;
748            string section = "";
749            while (getline(inf, line, '\n')) {
750                string::size_type pos = line.find("=");
751                string name = trim(line.substr(0,pos));
752                string value = trim(line.substr(pos+1,line.length()));
753
754                if (name=="section")
755                    menu->setSectionIndex(atoi(value.c_str()));
756                else if (name=="link")
757                    menu->setLinkIndex(atoi(value.c_str()));
758                else if (name=="selectorelem")
759                    lastSelectorElement = atoi(value.c_str());
760                else if (name=="selectordir")
761                    lastSelectorDir = value;
762            }
763            inf.close();
764        }
765    }
766}
767
768void GMenu2X::writeTmp(int selelem, const string &selectordir) {
769    string conffile = "/tmp/gmenu2x.tmp";
770    ofstream inf(conffile.c_str());
771    if (inf.is_open()) {
772        inf << "section=" << menu->selSectionIndex() << endl;
773        inf << "link=" << menu->selLinkIndex() << endl;
774        if (selelem>-1)
775            inf << "selectorelem=" << selelem << endl;
776        if (selectordir!="")
777            inf << "selectordir=" << selectordir << endl;
778        inf.close();
779        sync();
780    }
781}
782
783void GMenu2X::initServices() {
784#ifdef TARGET_GP2X
785/* if (usbnet) {
786        string services = "scripts/services.sh "+ip+" "+(inet?"on":"off")+" "+(samba?"on":"off")+" "+(web?"on":"off")+" &";
787        system(services.c_str());
788    }*/
789#endif
790}
791
792void GMenu2X::ledOn() {
793#ifdef TARGET_GP2X
794// if (gp2x_mem!=0 && !f200) gp2x_memregs[0x106E >> 1] ^= 16;
795    //SDL_SYS_JoystickGp2xSys(joy.joystick, BATT_LED_ON);
796#endif
797}
798
799void GMenu2X::ledOff() {
800#ifdef TARGET_GP2X
801// if (gp2x_mem!=0 && !f200) gp2x_memregs[0x106E >> 1] ^= 16;
802    //SDL_SYS_JoystickGp2xSys(joy.joystick, BATT_LED_OFF);
803#endif
804}
805
806void GMenu2X::setBacklight(int val)
807{
808    if (backlightHandle) {
809        fprintf(backlightHandle, "%d", (val * 255) / 100);
810        fflush(backlightHandle);
811        rewind(backlightHandle);
812    }
813}
814
815int GMenu2X::getBackLight()
816{
817    int val = 255;
818    if (backlightHandle) {
819        fscanf(backlightHandle, "%d", &val);
820        rewind(backlightHandle);
821        val = (val * 100) / 255;
822        if (val < 0) val = 0; else if (val > 100) val = 100;
823    }
824    return val;
825}
826
827void GMenu2X::main() {
828    uint linksPerPage = linkColumns*linkRows;
829    int linkSpacingX = (resX-10 - linkColumns*skinConfInt["linkWidth"])/linkColumns;
830    int linkSpacingY = (resY-35 - skinConfInt["topBarHeight"] - linkRows*skinConfInt["linkHeight"])/linkRows;
831    uint sectionLinkPadding = (skinConfInt["topBarHeight"] - 32 - font->getLineHeight()) / 3;
832
833    bool quit = false;
834    int x,y, offset = menu->sectionLinks()->size()>linksPerPage ? 2 : 6, helpBoxHeight = fwType=="open2x" ? 154 : 139;
835    uint i;
836    long tickBattery = -60000, tickNow;
837    string batteryIcon = "imgs/battery/0.png";
838    stringstream ss;
839    uint sectionsCoordX = 24;
840    SDL_Rect re = {0,0,0,0};
841    bool helpDisplayed = false;
842#ifdef WITH_DEBUG
843    //framerate
844    long tickFPS = SDL_GetTicks();
845    int drawn_frames = 0;
846    string fps = "";
847#endif
848
849    IconButton btnContextMenu(this,"skin:imgs/menu.png");
850    btnContextMenu.setPosition(resX-38, bottomBarIconY);
851    btnContextMenu.setAction(MakeDelegate(this, &GMenu2X::contextMenu));
852
853    if (!fileExists(CARD_ROOT))
854        CARD_ROOT = "/";
855
856    while (!quit) {
857        tickNow = SDL_GetTicks();
858
859        //Background
860        sc["bgmain"]->blit(s,0,0);
861
862        //Sections
863        sectionsCoordX = halfX - (constrain((uint)menu->getSections().size(), 0 , linkColumns) * skinConfInt["linkWidth"]) / 2;
864        if (menu->firstDispSection()>0)
865            sc.skinRes("imgs/l_enabled.png")->blit(s,0,0);
866        else
867            sc.skinRes("imgs/l_disabled.png")->blit(s,0,0);
868        if (menu->firstDispSection()+linkColumns<menu->getSections().size())
869            sc.skinRes("imgs/r_enabled.png")->blit(s,resX-10,0);
870        else
871            sc.skinRes("imgs/r_disabled.png")->blit(s,resX-10,0);
872        for (i=menu->firstDispSection(); i<menu->getSections().size() && i<menu->firstDispSection()+linkColumns; i++) {
873            string sectionIcon = "skin:sections/"+menu->getSections()[i]+".png";
874            x = (i-menu->firstDispSection())*skinConfInt["linkWidth"]+sectionsCoordX;
875            if (menu->selSectionIndex()==(int)i)
876                s->box(x, 0, skinConfInt["linkWidth"],
877                skinConfInt["topBarHeight"], skinConfColors[COLOR_SELECTION_BG]);
878            x += skinConfInt["linkWidth"]/2;
879            if (sc.exists(sectionIcon))
880                sc[sectionIcon]->blit(s,x-16,sectionLinkPadding,32,32);
881            else
882                sc.skinRes("icons/section.png")->blit(s,x-16,sectionLinkPadding);
883            s->write( font, menu->getSections()[i], x, skinConfInt["topBarHeight"]-sectionLinkPadding, ASFont::HAlignCenter, ASFont::VAlignBottom );
884        }
885
886        //Links
887        s->setClipRect(offset,skinConfInt["topBarHeight"],resX-9,resY-74); //32*2+10
888        for (i=menu->firstDispRow()*linkColumns; i<(menu->firstDispRow()*linkColumns)+linksPerPage && i<menu->sectionLinks()->size(); i++) {
889            int ir = i-menu->firstDispRow()*linkColumns;
890            x = (ir%linkColumns)*(skinConfInt["linkWidth"]+linkSpacingX)+offset;
891            y = ir/linkColumns*(skinConfInt["linkHeight"]+linkSpacingY)+skinConfInt["topBarHeight"]+2;
892            menu->sectionLinks()->at(i)->setPosition(x,y);
893
894            if (i==(uint)menu->selLinkIndex())
895                menu->sectionLinks()->at(i)->paintHover();
896
897            menu->sectionLinks()->at(i)->paint();
898        }
899        s->clearClipRect();
900
901        drawScrollBar(linkRows,menu->sectionLinks()->size()/linkColumns + ((menu->sectionLinks()->size()%linkColumns==0) ? 0 : 1),menu->firstDispRow(),43,resY-81);
902
903        /*
904        switch(volumeMode) {
905            case VOLUME_MODE_MUTE: sc.skinRes("imgs/mute.png")->blit(s,279,bottomBarIconY); break;
906            case VOLUME_MODE_PHONES: sc.skinRes("imgs/phones.png")->blit(s,279,bottomBarIconY); break;
907            default: sc.skinRes("imgs/volume.png")->blit(s,279,bottomBarIconY); break;
908        }
909        */
910
911        if (menu->selLink()!=NULL) {
912            s->write ( font, menu->selLink()->getDescription(), halfX, resY-19, ASFont::HAlignCenter, ASFont::VAlignBottom );
913            if (menu->selLinkApp()!=NULL) {
914                s->write ( font, menu->selLinkApp()->clockStr(confInt["maxClock"]), cpuX, bottomBarTextY, ASFont::HAlignLeft, ASFont::VAlignMiddle );
915                s->write ( font, menu->selLinkApp()->volumeStr(), volumeX, bottomBarTextY, ASFont::HAlignLeft, ASFont::VAlignMiddle );
916                //Manual indicator
917                if (!menu->selLinkApp()->getManual().empty())
918                    sc.skinRes("imgs/manual.png")->blit(s,manualX,bottomBarIconY);
919            }
920        }
921
922        if (f200) {
923            btnContextMenu.paint();
924        }
925        //check battery status every 60 seconds
926        if (tickNow-tickBattery >= 60000) {
927            tickBattery = tickNow;
928            unsigned short battlevel = getBatteryLevel();
929            if (battlevel>5) {
930                batteryIcon = "imgs/battery/ac.png";
931            } else {
932                ss.clear();
933                ss << battlevel;
934                ss >> batteryIcon;
935                batteryIcon = "imgs/battery/"+batteryIcon+".png";
936            }
937        }
938        sc.skinRes(batteryIcon)->blit( s, resX-19, bottomBarIconY );
939        //s->write( font, tr[batstr.c_str()], 20, 170 );
940        //On Screen Help
941
942
943        if (helpDisplayed) {
944            s->box(10,50,300,143, skinConfColors[COLOR_MESSAGE_BOX_BG]);
945            s->rectangle( 12,52,296,helpBoxHeight,
946            skinConfColors[COLOR_MESSAGE_BOX_BORDER] );
947            s->write( font, tr["CONTROLS"], 20, 60 );
948            s->write( font, tr["B, Stick press: Launch link / Confirm action"], 20, 80 );
949            s->write( font, tr["L, R: Change section"], 20, 95 );
950            s->write( font, tr["Y: Show manual/readme"], 20, 110 );
951            s->write( font, tr["VOLUP, VOLDOWN: Change cpu clock"], 20, 125 );
952            s->write( font, tr["A+VOLUP, A+VOLDOWN: Change volume"], 20, 140 );
953            s->write( font, tr["SELECT: Show contextual menu"], 20, 155 );
954            s->write( font, tr["START: Show options menu"], 20, 170 );
955            if (fwType=="open2x") s->write( font, tr["X: Toggle speaker mode"], 20, 185 );
956
957        }
958
959#ifdef WITH_DEBUG
960        //framerate
961        drawn_frames++;
962        if (tickNow-tickFPS>=1000) {
963            ss.clear();
964            ss << drawn_frames*(tickNow-tickFPS+1)/1000;
965            ss >> fps;
966            tickFPS = tickNow;
967            drawn_frames = 0;
968        }
969        s->write( font, fps+" FPS", resX-1,1 ,ASFont::HAlignRight );
970#endif
971
972        s->flip();
973
974        //touchscreen
975        if (f200) {
976            ts.poll();
977            btnContextMenu.handleTS();
978            re.x = 0; re.y = 0; re.h = skinConfInt["topBarHeight"]; re.w = resX;
979            if (ts.pressed() && ts.inRect(re)) {
980                re.w = skinConfInt["linkWidth"];
981                sectionsCoordX = halfX - (constrain((uint)menu->getSections().size(), 0 , linkColumns) * skinConfInt["linkWidth"]) / 2;
982                for (i=menu->firstDispSection(); !ts.handled() && i<menu->getSections().size() && i<menu->firstDispSection()+linkColumns; i++) {
983                    re.x = (i-menu->firstDispSection())*re.w+sectionsCoordX;
984
985                    if (ts.inRect(re)) {
986                        menu->setSectionIndex(i);
987                        ts.setHandled();
988                    }
989                }
990            }
991
992            i=menu->firstDispRow()*linkColumns;
993            while ( i<(menu->firstDispRow()*linkColumns)+linksPerPage && i<menu->sectionLinks()->size()) {
994                if (menu->sectionLinks()->at(i)->isPressed())
995                    menu->setLinkIndex(i);
996                if (menu->sectionLinks()->at(i)->handleTS())
997                    i = menu->sectionLinks()->size();
998                i++;
999            }
1000        }
1001
1002//#ifdef TARGET_GP2X
1003        
1004        switch (input.waitForPressedButton()) {
1005            case ACCEPT:
1006                if (menu->selLink() != NULL) menu->selLink()->run();
1007                break;
1008            case CANCEL:
1009                helpDisplayed = ! helpDisplayed;
1010                break;
1011            case SETTINGS:
1012                options();
1013                break;
1014            case MENU:
1015                contextMenu();
1016                break;
1017            case UP:
1018                menu->linkUp();
1019                break;
1020            case DOWN:
1021                menu->linkDown();
1022                break;
1023            case LEFT:
1024                menu->linkLeft();
1025                break;
1026            case RIGHT:
1027                menu->linkRight();
1028                break;
1029            case MANUAL:
1030                menu->selLinkApp()->showManual();
1031                break;
1032            case ALTLEFT:
1033                menu->decSectionIndex();
1034                offset = menu->sectionLinks()->size()>linksPerPage ? 2 : 6;
1035                break;
1036            case ALTRIGHT:
1037                menu->incSectionIndex();
1038                offset = menu->sectionLinks()->size()>linksPerPage ? 2 : 6;
1039                break;
1040            default:
1041                break;
1042        }
1043
1044        /*
1045        while (!input.update())
1046            usleep(LOOP_DELAY);
1047        if ( input[ACCEPT] && menu->selLink()!=NULL ) menu->selLink()->run();
1048        else if ( input[SETTINGS] ) options();
1049        else if ( input[MENU] ) contextMenu();
1050        // VOLUME SCALE MODIFIER
1051        else if ( fwType=="open2x" && input[CLEAR] ) {
1052            volumeMode = constrain(volumeMode-1, -VOLUME_MODE_MUTE-1, VOLUME_MODE_NORMAL);
1053            if(volumeMode < VOLUME_MODE_MUTE)
1054                volumeMode = VOLUME_MODE_NORMAL;
1055            switch(volumeMode) {
1056                case VOLUME_MODE_MUTE: setVolumeScaler(VOLUME_SCALER_MUTE); break;
1057                case VOLUME_MODE_PHONES: setVolumeScaler(volumeScalerPhones); break;
1058                case VOLUME_MODE_NORMAL: setVolumeScaler(volumeScalerNormal); break;
1059            }
1060            setVolume(confInt["globalVolume"]);
1061        }
1062        // LINK NAVIGATION
1063        else if ( input[ALTLEFTEFT ] ) menu->linkLeft();
1064        else if ( input[ALTRIGHTIGHT] ) menu->linkRight();
1065        else if ( input[UP ] ) menu->linkUp();
1066        else if ( input[DOWN ] ) menu->linkDown();
1067        // SELLINKAPP SELECTED
1068        else if (menu->selLinkApp()!=NULL) {
1069            if ( input[MANUAL] ) menu->selLinkApp()->showManual();
1070            else if ( input.isActive(CANCEL) ) {
1071                // VOLUME
1072                if ( input[VOLDOWN] && !input.isActive(VOLUP) )
1073                    menu->selLinkApp()->setVolume( constrain(menu->selLinkApp()->volume()-1,0,100) );
1074                if ( input[VOLUP] && !input.isActive(VOLDOWN) )
1075                    menu->selLinkApp()->setVolume( constrain(menu->selLinkApp()->volume()+1,0,100) );;
1076                if ( input.isActive(VOLUP) && input.isActive(VOLDOWN) ) menu->selLinkApp()->setVolume(-1);
1077            } else {
1078                // CLOCK
1079                if ( input[VOLDOWN] && !input.isActive(VOLUP) )
1080                    menu->selLinkApp()->setClock( constrain(menu->selLinkApp()->clock()-1,200,confInt["maxClock"]) );
1081                if ( input[VOLUP] && !input.isActive(VOLDOWN) )
1082                    menu->selLinkApp()->setClock( constrain(menu->selLinkApp()->clock()+1,200,confInt["maxClock"]) );
1083                if ( input.isActive(VOLUP) && input.isActive(VOLDOWN) ) menu->selLinkApp()->setClock(336);
1084            }
1085        }
1086        if ( input.isActive(CANCEL) ) {
1087            if (input.isActive(ALTLEFT) && input.isActive(ALTRIGHT))
1088                saveScreenshot();
1089        } else {
1090            // SECTIONS
1091            if ( input[ALTLEFT ] ) {
1092                menu->decSectionIndex();
1093                offset = menu->sectionLinks()->size()>linksPerPage ? 2 : 6;
1094            } else if ( input[ALTRIGHT ] ) {
1095                menu->incSectionIndex();
1096                offset = menu->sectionLinks()->size()>linksPerPage ? 2 : 6;
1097            }
1098        }
1099        */
1100    }
1101}
1102
1103void GMenu2X::explorer() {
1104    FileDialog fd(this,tr["Select an application"],".gpu,.dge,.sh,");
1105    if (fd.exec()) {
1106        if (confInt["saveSelection"] && (confInt["section"]!=menu->selSectionIndex() || confInt["link"]!=menu->selLinkIndex()))
1107            writeConfig();
1108        if (fwType == "open2x" && savedVolumeMode != volumeMode)
1109            writeConfigOpen2x();
1110
1111        //string command = cmdclean(fd.path()+"/"+fd.file) + "; sync & cd "+cmdclean(getExePath())+"; exec ./gmenu2x";
1112        string command = cmdclean(fd.getPath()+"/"+fd.getFile());
1113        chdir(fd.getPath().c_str());
1114        quit();
1115        setClock(200);
1116        execlp("/bin/sh","/bin/sh","-c",command.c_str(),NULL);
1117
1118        //if execution continues then something went wrong and as we already called SDL_Quit we cannot continue
1119        //try relaunching gmenu2x
1120        ERROR("Error executing selected application, re-launching gmenu2x\n");
1121        chdir(getExePath().c_str());
1122        execlp("./gmenu2x", "./gmenu2x", NULL);
1123    }
1124}
1125
1126void GMenu2X::options() {
1127    int curMenuClock = confInt["menuClock"];
1128    int curGlobalVolume = confInt["globalVolume"];
1129    //G
1130    int prevbacklight = confInt["backlight"];
1131    bool showRootFolder = fileExists(CARD_ROOT);
1132
1133    FileLister fl_tr(getHome() + "/translations");
1134    fl_tr.browse();
1135    fl_tr.setPath(GMENU2X_SYSTEM_DIR "/translations", false);
1136    fl_tr.browse(false);
1137
1138    fl_tr.insertFile("English");
1139    string lang = tr.lang();
1140
1141    vector<string> encodings;
1142    encodings.push_back("NTSC");
1143    encodings.push_back("PAL");
1144
1145    SettingsDialog sd(this, input, ts, tr["Settings"]);
1146    sd.addSetting(new MenuSettingMultiString(this,tr["Language"],tr["Set the language used by GMenu2X"],&lang,&fl_tr.getFiles()));
1147    sd.addSetting(new MenuSettingBool(this,tr["Save last selection"],tr["Save the last selected link and section on exit"],&confInt["saveSelection"]));
1148    sd.addSetting(new MenuSettingInt(this,tr["Clock for GMenu2X"],tr["Set the cpu working frequency when running GMenu2X"],&confInt["menuClock"],200,430));
1149    sd.addSetting(new MenuSettingInt(this,tr["Maximum overclock"],tr["Set the maximum overclock for launching links"],&confInt["maxClock"],200,430));
1150    sd.addSetting(new MenuSettingInt(this,tr["Global Volume"],tr["Set the default volume for the gp2x soundcard"],&confInt["globalVolume"],0,100));
1151    sd.addSetting(new MenuSettingBool(this,tr["Output logs"],tr["Logs the output of the links. Use the Log Viewer to read them."],&confInt["outputLogs"]));
1152    //G
1153    sd.addSetting(new MenuSettingInt(this,tr["Lcd Backlight"],tr["Set dingoo's Lcd Backlight value (default: 100)"],&confInt["backlight"],5,100));
1154    sd.addSetting(new MenuSettingInt(this,tr["Screen Timeout"],tr["Set screen's backlight timeout in seconds"],&confInt["backlightTimeout"],0,120));
1155// sd.addSetting(new MenuSettingMultiString(this,tr["Tv-Out encoding"],tr["Encoding of the tv-out signal"],&confStr["tvoutEncoding"],&encodings));
1156    sd.addSetting(new MenuSettingBool(this,tr["Show root"],tr["Show root folder in the file selection dialogs"],&showRootFolder));
1157
1158    if (sd.exec() && sd.edited()) {
1159        //G
1160        if (prevbacklight != confInt["backlight"]) setBacklight(confInt["backlight"]);
1161        if (curMenuClock!=confInt["menuClock"]) setClock(confInt["menuClock"]);
1162        if (curGlobalVolume!=confInt["globalVolume"]) setVolume(confInt["globalVolume"]);
1163        PowerSaver::getInstance()->setScreenTimeout( confInt["backlightTimeout"] );
1164        if (lang == "English") lang = "";
1165        if (lang != tr.lang()) {
1166            tr.setLang(lang);
1167            confStr["lang"] = lang;
1168        }
1169        /*if (fileExists(CARD_ROOT) && !showRootFolder)
1170            unlink(CARD_ROOT);
1171        else if (!fileExists(CARD_ROOT) && showRootFolder)
1172            symlink("/", CARD_ROOT);*/
1173        //WARNING: the above might be dangerous with CARD_ROOT set to /
1174        writeConfig();
1175    }
1176}
1177
1178void GMenu2X::settingsOpen2x() {
1179    SettingsDialog sd(this, input, ts, tr["Open2x Settings"]);
1180    sd.addSetting(new MenuSettingBool(this,tr["USB net on boot"],tr["Allow USB networking to be started at boot time"],&o2x_usb_net_on_boot));
1181    sd.addSetting(new MenuSettingString(this,tr["USB net IP"],tr["IP address to be used for USB networking"],&o2x_usb_net_ip));
1182    sd.addSetting(new MenuSettingBool(this,tr["Telnet on boot"],tr["Allow telnet to be started at boot time"],&o2x_telnet_on_boot));
1183    sd.addSetting(new MenuSettingBool(this,tr["FTP on boot"],tr["Allow FTP to be started at boot time"],&o2x_ftp_on_boot));
1184    sd.addSetting(new MenuSettingBool(this,tr["GP2XJOY on boot"],tr["Create a js0 device for GP2X controls"],&o2x_gp2xjoy_on_boot));
1185    sd.addSetting(new MenuSettingBool(this,tr["USB host on boot"],tr["Allow USB host to be started at boot time"],&o2x_usb_host_on_boot));
1186    sd.addSetting(new MenuSettingBool(this,tr["USB HID on boot"],tr["Allow USB HID to be started at boot time"],&o2x_usb_hid_on_boot));
1187    sd.addSetting(new MenuSettingBool(this,tr["USB storage on boot"],tr["Allow USB storage to be started at boot time"],&o2x_usb_storage_on_boot));
1188    //sd.addSetting(new MenuSettingInt(this,tr["Speaker Mode on boot"],tr["Set Speaker mode. 0 = Mute, 1 = Phones, 2 = Speaker"],&volumeMode,0,2));
1189    sd.addSetting(new MenuSettingInt(this,tr["Speaker Scaler"],tr["Set the Speaker Mode scaling 0-150\% (default is 100\%)"],&volumeScalerNormal,0,150));
1190    sd.addSetting(new MenuSettingInt(this,tr["Headphones Scaler"],tr["Set the Headphones Mode scaling 0-100\% (default is 65\%)"],&volumeScalerPhones,0,100));
1191
1192    if (sd.exec() && sd.edited()) {
1193        writeConfigOpen2x();
1194        switch(volumeMode) {
1195            case VOLUME_MODE_MUTE: setVolumeScaler(VOLUME_SCALER_MUTE); break;
1196            case VOLUME_MODE_PHONES: setVolumeScaler(volumeScalerPhones); break;
1197            case VOLUME_MODE_NORMAL: setVolumeScaler(volumeScalerNormal); break;
1198        }
1199        setVolume(confInt["globalVolume"]);
1200    }
1201}
1202
1203void GMenu2X::skinMenu() {
1204    FileLister fl_sk(getHome() + "/skins", true, false);
1205    fl_sk.addExclude("..");
1206    fl_sk.browse();
1207    fl_sk.setPath(GMENU2X_SYSTEM_DIR "/skins", false);
1208    fl_sk.browse(false);
1209
1210    string curSkin = confStr["skin"];
1211
1212    SettingsDialog sd(this, input, ts, tr["Skin"]);
1213    sd.addSetting(new MenuSettingMultiString(this,tr["Skin"],tr["Set the skin used by GMenu2X"],&confStr["skin"],&fl_sk.getDirectories()));
1214    sd.addSetting(new MenuSettingRGBA(this,tr["Top Bar Color"],tr["Color of the top bar"],&skinConfColors[COLOR_TOP_BAR_BG]));
1215    sd.addSetting(new MenuSettingRGBA(this,tr["Bottom Bar Color"],tr["Color of the bottom bar"],&skinConfColors[COLOR_BOTTOM_BAR_BG]));
1216    sd.addSetting(new MenuSettingRGBA(this,tr["Selection Color"],tr["Color of the selection and other interface details"],&skinConfColors[COLOR_SELECTION_BG]));
1217    sd.addSetting(new MenuSettingRGBA(this,tr["Message Box Color"],tr["Background color of the message box"],&skinConfColors[COLOR_MESSAGE_BOX_BG]));
1218    sd.addSetting(new MenuSettingRGBA(this,tr["Message Box Border Color"],tr["Border color of the message box"],&skinConfColors[COLOR_MESSAGE_BOX_BORDER]));
1219    sd.addSetting(new MenuSettingRGBA(this,tr["Message Box Selection Color"],tr["Color of the selection of the message box"],&skinConfColors[COLOR_MESSAGE_BOX_SELECTION]));
1220
1221    if (sd.exec() && sd.edited()) {
1222        if (curSkin != confStr["skin"]) {
1223            setSkin(confStr["skin"]);
1224            writeConfig();
1225        }
1226        writeSkinConfig();
1227        initBG();
1228    }
1229}
1230
1231void GMenu2X::toggleTvOut() {
1232#ifdef TARGET_GP2X
1233/* if (cx25874!=0)
1234        gp2x_tvout_off();
1235    else
1236        gp2x_tvout_on(confStr["tvoutEncoding"] == "PAL");*/
1237#endif
1238}
1239
1240void GMenu2X::setSkin(const string &skin, bool setWallpaper) {
1241    confStr["skin"] = skin;
1242
1243    //Clear previous skin settings
1244    skinConfStr.clear();
1245    skinConfInt.clear();
1246
1247    //clear collection and change the skin path
1248    sc.clear();
1249    sc.setSkin(skin);
1250
1251    //reset colors to the default values
1252    skinConfColors[COLOR_TOP_BAR_BG] = (RGBAColor){255,255,255,130};
1253    skinConfColors[COLOR_BOTTOM_BAR_BG] = (RGBAColor){255,255,255,130};
1254    skinConfColors[COLOR_SELECTION_BG] = (RGBAColor){255,255,255,130};
1255    skinConfColors[COLOR_MESSAGE_BOX_BG] = (RGBAColor){255,255,255,255};
1256    skinConfColors[COLOR_MESSAGE_BOX_BORDER] = (RGBAColor){80,80,80,255};
1257    skinConfColors[COLOR_MESSAGE_BOX_SELECTION] = (RGBAColor){160,160,160,255};
1258
1259    /* Load skin settings from user directory if present,
1260     * or from the system directory. */
1261    string skinconfname = getHome() + "/skins/" + skin + "/skin.conf";
1262    if (!fileExists(skinconfname))
1263      skinconfname = GMENU2X_SYSTEM_DIR "/skins/" + skin + "/skin.conf";
1264
1265    if (fileExists(skinconfname)) {
1266        ifstream skinconf(skinconfname.c_str(), ios_base::in);
1267        if (skinconf.is_open()) {
1268            string line;
1269            while (getline(skinconf, line, '\n')) {
1270                line = trim(line);
1271                DEBUG("skinconf: '%s'\n", line.c_str());
1272                string::size_type pos = line.find("=");
1273                string name = trim(line.substr(0,pos));
1274                string value = trim(line.substr(pos+1,line.length()));
1275
1276                if (value.length()>0) {
1277                    if (value.length()>1 && value.at(0)=='"' && value.at(value.length()-1)=='"')
1278                        skinConfStr[name] = value.substr(1,value.length()-2);
1279                    else if (value.at(0) == '#')
1280                        skinConfColors[stringToColor(name)] = strtorgba( value.substr(1,value.length()) );
1281                    else
1282                        skinConfInt[name] = atoi(value.c_str());
1283                }
1284            }
1285            skinconf.close();
1286
1287            if (setWallpaper && !skinConfStr["wallpaper"].empty() && fileExists("skins/"+skin+"/wallpapers/"+skinConfStr["wallpaper"]))
1288                confStr["wallpaper"] = "skins/"+skin+"/wallpapers/"+skinConfStr["wallpaper"];
1289        }
1290    }
1291
1292    evalIntConf( &skinConfInt["topBarHeight"], 40, 32,120 );
1293    evalIntConf( &skinConfInt["linkHeight"], 40, 32,120 );
1294    evalIntConf( &skinConfInt["linkWidth"], 60, 32,120 );
1295
1296    //recalculate some coordinates based on the new element sizes
1297    linkColumns = (resX-10)/skinConfInt["linkWidth"];
1298    linkRows = (resY-35-skinConfInt["topBarHeight"])/skinConfInt["linkHeight"];
1299
1300    if (menu != NULL) menu->loadIcons();
1301
1302    //Selection png
1303    useSelectionPng = sc.addSkinRes("imgs/selection.png") != NULL;
1304
1305    //font
1306    initFont();
1307}
1308
1309/*
1310void GMenu2X::activateSdUsb() {
1311    if (usbnet) {
1312        MessageBox mb(this,tr["Operation not permitted."]+"\n"+tr["You should disable Usb Networking to do this."]);
1313        mb.exec();
1314    } else {
1315        system("scripts/usbon.sh sd");
1316        MessageBox mb(this,tr["USB Enabled (SD)"],"icons/usb.png");
1317        mb.setButton(ACCEPT, tr["Turn off"]);
1318        mb.exec();
1319        system("scripts/usboff.sh sd");
1320    }
1321}
1322
1323void GMenu2X::activateNandUsb() {
1324    if (usbnet) {
1325        MessageBox mb(this,tr["Operation not permitted."]+"\n"+tr["You should disable Usb Networking to do this."]);
1326        mb.exec();
1327    } else {
1328        system("scripts/usbon.sh nand");
1329        MessageBox mb(this,tr["USB Enabled (Nand)"],"icons/usb.png");
1330        mb.setButton(ACCEPT, tr["Turn off"]);
1331        mb.exec();
1332        system("scripts/usboff.sh nand");
1333    }
1334}
1335
1336void GMenu2X::activateRootUsb() {
1337    if (usbnet) {
1338        MessageBox mb(this,tr["Operation not permitted."]+"\n"+tr["You should disable Usb Networking to do this."]);
1339        mb.exec();
1340    } else {
1341        system("scripts/usbon.sh root");
1342        MessageBox mb(this,tr["USB Enabled (Root)"],"icons/usb.png");
1343        mb.setButton(ACCEPT, tr["Turn off"]);
1344        mb.exec();
1345        system("scripts/usboff.sh root");
1346    }
1347}
1348*/
1349void GMenu2X::contextMenu() {
1350    vector<MenuOption> voices;
1351    {
1352    MenuOption opt = {tr.translate("Add link in $1",menu->selSection().c_str(),NULL), MakeDelegate(this, &GMenu2X::addLink)};
1353    voices.push_back(opt);
1354    }
1355
1356    if (menu->selLinkApp()!=NULL) {
1357        {
1358        MenuOption opt = {tr.translate("Edit $1",menu->selLink()->getTitle().c_str(),NULL), MakeDelegate(this, &GMenu2X::editLink)};
1359        voices.push_back(opt);
1360        }{
1361        MenuOption opt = {tr.translate("Delete $1 link",menu->selLink()->getTitle().c_str(),NULL), MakeDelegate(this, &GMenu2X::deleteLink)};
1362        voices.push_back(opt);
1363        }
1364    }
1365
1366    {
1367    MenuOption opt = {tr["Add section"], MakeDelegate(this, &GMenu2X::addSection)};
1368    voices.push_back(opt);
1369    }{
1370    MenuOption opt = {tr["Rename section"], MakeDelegate(this, &GMenu2X::renameSection)};
1371    voices.push_back(opt);
1372    }{
1373    MenuOption opt = {tr["Delete section"], MakeDelegate(this, &GMenu2X::deleteSection)};
1374    voices.push_back(opt);
1375    }{
1376    MenuOption opt = {tr["Scan for applications and games"], MakeDelegate(this, &GMenu2X::scanner)};
1377    voices.push_back(opt);
1378    }
1379
1380    bool close = false;
1381    uint i, sel=0, fadeAlpha=0;
1382
1383    int h = font->getHeight();
1384    SDL_Rect box;
1385    box.h = (h+2)*voices.size()+8;
1386    box.w = 0;
1387    for (i=0; i<voices.size(); i++) {
1388        int w = font->getTextWidth(voices[i].text);
1389        if (w>box.w) box.w = w;
1390    }
1391    box.w += 23;
1392    box.x = halfX - box.w/2;
1393    box.y = halfY - box.h/2;
1394
1395    SDL_Rect selbox = {box.x+4, 0, box.w-8, h+2};
1396    long tickNow, tickStart = SDL_GetTicks();
1397
1398    Surface bg(s);
1399    /*//Darken background
1400    bg.box(0, 0, resX, resY, 0,0,0,150);
1401    bg.box(box.x, box.y, box.w, box.h, skinConfColors["messageBoxBg"]);
1402    bg.rectangle( box.x+2, box.y+2, box.w-4, box.h-4, skinConfColors["messageBoxBorder"] );*/
1403
1404    bevent_t event;
1405    while (!close) {
1406        tickNow = SDL_GetTicks();
1407
1408        selbox.y = box.y+4+(h+2)*sel;
1409        bg.blit(s,0,0);
1410
1411        if (fadeAlpha<200) fadeAlpha = intTransition(0,200,tickStart,500,tickNow);
1412        s->box(0, 0, resX, resY, 0,0,0,fadeAlpha);
1413        s->box(box.x, box.y, box.w, box.h, skinConfColors[COLOR_MESSAGE_BOX_BG]);
1414        s->rectangle( box.x+2, box.y+2, box.w-4, box.h-4, skinConfColors[COLOR_MESSAGE_BOX_BORDER] );
1415
1416
1417        //draw selection rect
1418        s->box( selbox.x, selbox.y, selbox.w, selbox.h, skinConfColors[COLOR_MESSAGE_BOX_SELECTION] );
1419        for (i=0; i<voices.size(); i++)
1420            s->write( font, voices[i].text, box.x+12, box.y+5+(h+2)*i, ASFont::HAlignLeft, ASFont::VAlignTop );
1421        s->flip();
1422
1423        //touchscreen
1424        if (f200) {
1425            ts.poll();
1426            if (ts.released()) {
1427                if (!ts.inRect(box))
1428                    close = true;
1429                else if (ts.getX() >= selbox.x
1430                      && ts.getX() <= selbox.x + selbox.w)
1431                    for (i=0; i<voices.size(); i++) {
1432                        selbox.y = box.y+4+(h+2)*i;
1433                        if (ts.getY() >= selbox.y
1434                         && ts.getY() <= selbox.y + selbox.h) {
1435                            voices[i].action();
1436                            close = true;
1437                            i = voices.size();
1438                        }
1439                    }
1440            } else if (ts.pressed() && ts.inRect(box)) {
1441                for (i=0; i<voices.size(); i++) {
1442                    selbox.y = box.y+4+(h+2)*i;
1443                    if (ts.getY() >= selbox.y
1444                     && ts.getY() <= selbox.y + selbox.h) {
1445                        sel = i;
1446                        i = voices.size();
1447                    }
1448                }
1449            }
1450        }
1451
1452        
1453        if (fadeAlpha < 200) {
1454            if (!input.pollEvent(&event) || event.state != PRESSED) continue;
1455        } else {
1456            event.button = input.waitForPressedButton();
1457        }
1458
1459        switch(event.button) {
1460            case MENU:
1461                close = true;
1462                break;
1463            case UP:
1464                sel = max(0, sel-1);
1465                break;
1466            case DOWN:
1467                sel = min((int)voices.size()-1, sel+1);
1468                break;
1469            case ACCEPT:
1470                voices[sel].action();
1471                close = true;
1472                break;
1473            default:
1474                break;
1475        }
1476    }
1477}
1478
1479void GMenu2X::changeWallpaper() {
1480    WallpaperDialog wp(this);
1481    if (wp.exec() && confStr["wallpaper"] != wp.wallpaper) {
1482        confStr["wallpaper"] = wp.wallpaper;
1483        initBG();
1484        writeConfig();
1485    }
1486}
1487
1488void GMenu2X::saveScreenshot() {
1489    ledOn();
1490    uint x = 0;
1491    stringstream ss;
1492    string fname;
1493    do {
1494        x++;
1495        fname = "";
1496        ss.clear();
1497        ss << x;
1498        ss >> fname;
1499        fname = "screen"+fname+".bmp";
1500    } while (fileExists(fname));
1501    SDL_SaveBMP(s->raw,fname.c_str());
1502    sync();
1503    ledOff();
1504}
1505
1506void GMenu2X::addLink() {
1507    FileDialog fd(this,tr["Select an application"]);
1508    if (fd.exec()) {
1509        ledOn();
1510        menu->addLink(fd.getPath(), fd.getFile());
1511        sync();
1512        ledOff();
1513    }
1514}
1515
1516void GMenu2X::editLink() {
1517    if (menu->selLinkApp()==NULL) return;
1518
1519    vector<string> pathV;
1520    split(pathV,menu->selLinkApp()->getFile(),"/");
1521    string oldSection = "";
1522    if (pathV.size()>1)
1523        oldSection = pathV[pathV.size()-2];
1524    string newSection = oldSection;
1525
1526    string linkTitle = menu->selLinkApp()->getTitle();
1527    string linkDescription = menu->selLinkApp()->getDescription();
1528    string linkIcon = menu->selLinkApp()->getIcon();
1529    string linkManual = menu->selLinkApp()->getManual();
1530    string linkParams = menu->selLinkApp()->getParams();
1531    string linkSelFilter = menu->selLinkApp()->getSelectorFilter();
1532    string linkSelDir = menu->selLinkApp()->getSelectorDir();
1533    bool linkSelBrowser = menu->selLinkApp()->getSelectorBrowser();
1534    bool linkUseRamTimings = menu->selLinkApp()->getUseRamTimings();
1535    string linkSelScreens = menu->selLinkApp()->getSelectorScreens();
1536    string linkSelAliases = menu->selLinkApp()->getAliasFile();
1537    int linkClock = menu->selLinkApp()->clock();
1538    int linkVolume = menu->selLinkApp()->volume();
1539    //G
1540    //int linkGamma = menu->selLinkApp()->gamma();
1541    int linkBacklight = menu->selLinkApp()->backlight();
1542
1543    string diagTitle = tr.translate("Edit link: $1",linkTitle.c_str(),NULL);
1544    string diagIcon = menu->selLinkApp()->getIconPath();
1545
1546    SettingsDialog sd(this, input, ts, diagTitle, diagIcon);
1547    sd.addSetting(new MenuSettingString(this,tr["Title"],tr["Link title"],&linkTitle, diagTitle,diagIcon));
1548    sd.addSetting(new MenuSettingString(this,tr["Description"],tr["Link description"],&linkDescription, diagTitle,diagIcon));
1549    sd.addSetting(new MenuSettingMultiString(this,tr["Section"],tr["The section this link belongs to"],&newSection,&menu->getSections()));
1550    sd.addSetting(new MenuSettingImage(this,tr["Icon"],tr.translate("Select an icon for the link: $1",linkTitle.c_str(),NULL),&linkIcon,".png,.bmp,.jpg,.jpeg"));
1551    sd.addSetting(new MenuSettingFile(this,tr["Manual"],tr["Select a graphic/textual manual or a readme"],&linkManual,".man.png,.txt"));
1552    sd.addSetting(new MenuSettingInt(this,tr["Clock (default: 336)"],tr["Cpu clock frequency to set when launching this link"],&linkClock,200,confInt["maxClock"]));
1553// sd.addSetting(new MenuSettingBool(this,tr["Tweak RAM Timings"],tr["This usually speeds up the application at the cost of stability"],&linkUseRamTimings));
1554    sd.addSetting(new MenuSettingInt(this,tr["Volume (default: -1)"],tr["Volume to set for this link"],&linkVolume,-1,100));
1555    sd.addSetting(new MenuSettingInt(this,tr["Backlight (default: -1)"],tr["LCD backlight value to set when launching this link"],&linkBacklight,-1,100));
1556    sd.addSetting(new MenuSettingString(this,tr["Parameters"],tr["Parameters to pass to the application"],&linkParams, diagTitle,diagIcon));
1557    sd.addSetting(new MenuSettingDir(this,tr["Selector Directory"],tr["Directory to scan for the selector"],&linkSelDir));
1558    sd.addSetting(new MenuSettingBool(this,tr["Selector Browser"],tr["Allow the selector to change directory"],&linkSelBrowser));
1559    sd.addSetting(new MenuSettingString(this,tr["Selector Filter"],tr["Filter for the selector (Separate values with a comma)"],&linkSelFilter, diagTitle,diagIcon));
1560    sd.addSetting(new MenuSettingDir(this,tr["Selector Screenshots"],tr["Directory of the screenshots for the selector"],&linkSelScreens));
1561    sd.addSetting(new MenuSettingFile(this,tr["Selector Aliases"],tr["File containing a list of aliases for the selector"],&linkSelAliases));
1562    //G
1563    sd.addSetting(new MenuSettingBool(this,tr["Wrapper"],tr["Explicitly relaunch GMenu2X after this link's execution ends"],&menu->selLinkApp()->needsWrapperRef()));
1564    sd.addSetting(new MenuSettingBool(this,tr["Don't Leave"],tr["Don't quit GMenu2X when launching this link"],&menu->selLinkApp()->runsInBackgroundRef()));
1565
1566    if (sd.exec() && sd.edited()) {
1567        ledOn();
1568
1569        menu->selLinkApp()->setTitle(linkTitle);
1570        menu->selLinkApp()->setDescription(linkDescription);
1571        menu->selLinkApp()->setIcon(linkIcon);
1572        menu->selLinkApp()->setManual(linkManual);
1573        menu->selLinkApp()->setParams(linkParams);
1574        menu->selLinkApp()->setSelectorFilter(linkSelFilter);
1575        menu->selLinkApp()->setSelectorDir(linkSelDir);
1576        menu->selLinkApp()->setSelectorBrowser(linkSelBrowser);
1577        menu->selLinkApp()->setUseRamTimings(linkUseRamTimings);
1578        menu->selLinkApp()->setSelectorScreens(linkSelScreens);
1579        menu->selLinkApp()->setAliasFile(linkSelAliases);
1580        menu->selLinkApp()->setClock(linkClock);
1581        menu->selLinkApp()->setVolume(linkVolume);
1582        //G
1583        if ((linkBacklight < 5) && (linkBacklight > -1))
1584            linkBacklight = 5;
1585        menu->selLinkApp()->setBacklight(linkBacklight);
1586
1587        INFO("New Section: '%s'\n", newSection.c_str());
1588
1589        //if section changed move file and update link->file
1590        if (oldSection!=newSection) {
1591            vector<string>::const_iterator newSectionIndex = find(menu->getSections().begin(),menu->getSections().end(),newSection);
1592            if (newSectionIndex==menu->getSections().end()) return;
1593            string newFileName = "sections/"+newSection+"/"+linkTitle;
1594            uint x=2;
1595            while (fileExists(newFileName)) {
1596                string id = "";
1597                stringstream ss; ss << x; ss >> id;
1598                newFileName = "sections/"+newSection+"/"+linkTitle+id;
1599                x++;
1600            }
1601            rename(menu->selLinkApp()->getFile().c_str(),newFileName.c_str());
1602            menu->selLinkApp()->renameFile(newFileName);
1603
1604            INFO("New section index: %i.\n", newSectionIndex - menu->getSections().begin());
1605
1606            menu->linkChangeSection(menu->selLinkIndex(), menu->selSectionIndex(), newSectionIndex - menu->getSections().begin());
1607        }
1608        menu->selLinkApp()->save();
1609        sync();
1610
1611        ledOff();
1612    }
1613}
1614
1615void GMenu2X::deleteLink() {
1616    if (menu->selLinkApp()!=NULL) {
1617        MessageBox mb(this, tr.translate("Deleting $1",menu->selLink()->getTitle().c_str(),NULL)+"\n"+tr["Are you sure?"], menu->selLink()->getIconPath());
1618        mb.setButton(ACCEPT, tr["Yes"]);
1619        mb.setButton(CLEAR, tr["No"]);
1620        if (mb.exec() == ACCEPT) {
1621            ledOn();
1622            menu->deleteSelectedLink();
1623            sync();
1624            ledOff();
1625        }
1626    }
1627}
1628
1629void GMenu2X::addSection() {
1630    InputDialog id(this, input, ts, tr["Insert a name for the new section"]);
1631    if (id.exec()) {
1632        //only if a section with the same name does not exist
1633        if (find(menu->getSections().begin(), menu->getSections().end(), id.getInput())
1634                == menu->getSections().end()) {
1635            //section directory doesn't exists
1636            ledOn();
1637            if (menu->addSection(id.getInput())) {
1638                menu->setSectionIndex( menu->getSections().size()-1 ); //switch to the new section
1639                sync();
1640            }
1641            ledOff();
1642        }
1643    }
1644}
1645
1646void GMenu2X::renameSection() {
1647    InputDialog id(this, input, ts, tr["Insert a new name for this section"],menu->selSection());
1648    if (id.exec()) {
1649        //only if a section with the same name does not exist & !samename
1650        if (menu->selSection() != id.getInput()
1651         && find(menu->getSections().begin(),menu->getSections().end(), id.getInput())
1652                == menu->getSections().end()) {
1653            //section directory doesn't exists
1654            string newsectiondir = getHome() + "/sections/" + id.getInput();
1655            string sectiondir = getHome() + "/sections/" + menu->selSection();
1656            ledOn();
1657
1658            if (!rename(sectiondir.c_str(), newsectiondir.c_str())) {
1659                string oldpng = menu->selSection() + ".png";
1660                string newpng = id.getInput() + ".png";
1661                string oldicon = sc.getSkinFilePath(oldpng);
1662                string newicon = sc.getSkinFilePath(newpng);
1663
1664                if (!oldicon.empty() && newicon.empty()) {
1665                    newicon = oldicon;
1666                    newicon.replace(newicon.find(oldpng), oldpng.length(), newpng);
1667
1668                    if (!fileExists(newicon)) {
1669                        rename(oldicon.c_str(), newicon.c_str());
1670                        sc.move("skin:"+oldpng, "skin:"+newpng);
1671                    }
1672                }
1673                menu->renameSection(menu->selSectionIndex(), id.getInput());
1674                sync();
1675            }
1676            ledOff();
1677        }
1678    }
1679}
1680
1681void GMenu2X::deleteSection() {
1682    MessageBox mb(this,tr["You will lose all the links in this section."]+"\n"+tr["Are you sure?"]);
1683    mb.setButton(ACCEPT, tr["Yes"]);
1684    mb.setButton(CLEAR, tr["No"]);
1685    if (mb.exec() == ACCEPT) {
1686        ledOn();
1687        if (rmtree(getHome() + "/sections/" + menu->selSection())) {
1688            menu->deleteSelectedSection();
1689            sync();
1690        }
1691        ledOff();
1692    }
1693}
1694
1695void GMenu2X::scanner() {
1696    Surface scanbg(bg);
1697    drawButton(&scanbg, "x", tr["Exit"],
1698    drawButton(&scanbg, "b", "", 5)-10);
1699    scanbg.write(font,tr["Link Scanner"],halfX,7,ASFont::HAlignCenter,ASFont::VAlignMiddle);
1700
1701    uint lineY = 42;
1702
1703#ifdef _TARGET_PANDORA
1704    //char *configpath = pnd_conf_query_searchpath();
1705#else
1706    if (confInt["menuClock"]<430) {
1707        setClock(336);
1708        scanbg.write(font,tr["Raising cpu clock to 336Mhz"],5,lineY);
1709        scanbg.blit(s,0,0);
1710        s->flip();
1711        lineY += 26;
1712    }
1713
1714    scanbg.write(font,tr["Scanning SD filesystem..."],5,lineY);
1715    scanbg.blit(s,0,0);
1716    s->flip();
1717    lineY += 26;
1718
1719    vector<string> files;
1720    scanPath(CARD_ROOT, &files);
1721
1722    //Onyl gph firmware has nand
1723/* if (fwType=="gph" && !f200) {
1724        scanbg.write(font,tr["Scanning NAND filesystem..."],5,lineY);
1725        scanbg.blit(s,0,0);
1726        s->flip();
1727        lineY += 26;
1728        scanPath("/boot/local/nand",&files);
1729    }
1730*/
1731    stringstream ss;
1732    ss << files.size();
1733    string str = "";
1734    ss >> str;
1735    scanbg.write(font,tr.translate("$1 files found.",str.c_str(),NULL),5,lineY);
1736    lineY += 26;
1737    scanbg.write(font,tr["Creating links..."],5,lineY);
1738    scanbg.blit(s,0,0);
1739    s->flip();
1740    lineY += 26;
1741
1742    string path, file;
1743    string::size_type pos;
1744    uint linkCount = 0;
1745
1746    ledOn();
1747    for (uint i = 0; i<files.size(); i++) {
1748        pos = files[i].rfind("/");
1749        if (pos!=string::npos && pos>0) {
1750            path = files[i].substr(0, pos+1);
1751            file = files[i].substr(pos+1, files[i].length());
1752            if (menu->addLink(path,file,"found "+file.substr(file.length()-3,3)))
1753                linkCount++;
1754        }
1755    }
1756
1757    ss.clear();
1758    ss << linkCount;
1759    ss >> str;
1760    scanbg.write(font,tr.translate("$1 links created.",str.c_str(),NULL),5,lineY);
1761    scanbg.blit(s,0,0);
1762    s->flip();
1763    lineY += 26;
1764
1765    if (confInt["menuClock"]<430) {
1766        setClock(confInt["menuClock"]);
1767        scanbg.write(font,tr["Decreasing cpu clock"],5,lineY);
1768        scanbg.blit(s,0,0);
1769        s->flip();
1770        lineY += 26;
1771    }
1772
1773    sync();
1774    ledOff();
1775#endif
1776
1777    buttontype_t button;
1778    do {
1779        button = input.waitForPressedButton();
1780    } while ((button != SETTINGS)
1781                && (button != ACCEPT)
1782                && (button != CLEAR));
1783
1784    /*
1785    bevent_t event;
1786    do {
1787        input.getEvent(&event, true);
1788    } while ((event.state != PRESSED) ||
1789                ( (event.button != SETTINGS)
1790                && (event.button != ACCEPT)
1791                && (event.button != CLEAR)));
1792                */
1793}
1794
1795void GMenu2X::scanPath(string path, vector<string> *files) {
1796    DIR *dirp;
1797    struct stat st;
1798    struct dirent *dptr;
1799    string filepath, ext;
1800
1801    if (path[path.length()-1]!='/') path += "/";
1802    if ((dirp = opendir(path.c_str())) == NULL) return;
1803
1804    while ((dptr = readdir(dirp))) {
1805        if (dptr->d_name[0]=='.')
1806            continue;
1807        filepath = path+dptr->d_name;
1808        int statRet = stat(filepath.c_str(), &st);
1809        if (S_ISDIR(st.st_mode))
1810            scanPath(filepath, files);
1811        if (statRet != -1) {
1812            ext = filepath.substr(filepath.length()-4,4);
1813#ifdef TARGET_GP2X
1814            if (ext==".gpu" || ext==".dge")
1815#else
1816            if (ext==".pxml")
1817#endif
1818                files->push_back(filepath);
1819        }
1820    }
1821
1822    closedir(dirp);
1823}
1824
1825unsigned short GMenu2X::getBatteryLevel() {
1826#ifdef TARGET_GP2X
1827/* if (batteryHandle<=0) return 0;
1828
1829    if (f200) {
1830        MMSP2ADC val;
1831        read(batteryHandle, &val, sizeof(MMSP2ADC));
1832
1833        if (val.batt==0) return 5;
1834        if (val.batt==1) return 3;
1835        if (val.batt==2) return 1;
1836        if (val.batt==3) return 0;
1837    } else {
1838        int battval = 0;
1839        unsigned short cbv, min=900, max=0;
1840
1841        for (int i = 0; i < BATTERY_READS; i ++) {
1842            if ( read(batteryHandle, &cbv, 2) == 2) {
1843                battval += cbv;
1844                if (cbv>max) max = cbv;
1845                if (cbv<min) min = cbv;
1846            }
1847        }
1848
1849        battval -= min+max;
1850        battval /= BATTERY_READS-2;
1851
1852        if (battval>=850) return 6;
1853        if (battval>780) return 5;
1854        if (battval>740) return 4;
1855        if (battval>700) return 3;
1856        if (battval>690) return 2;
1857        if (battval>680) return 1;
1858    }*/
1859    if (!batteryHandle) return 0;
1860    int battval = 0;
1861    char battvalcstr[5];
1862    fscanf(batteryHandle, "%s", &battvalcstr[0]);
1863    rewind(batteryHandle);
1864    battval = atoi(battvalcstr);
1865    if (battval>90) return 5;
1866    if (battval>70) return 4;
1867    if (battval>50) return 3;
1868    if (battval>30) return 2;
1869    if (battval>10) return 1;
1870
1871    if (!usbHandle) return 0;
1872    int usbval = 0;
1873    char usbvalcstr[5];
1874    fscanf(usbHandle, "%s", &usbvalcstr[0]);
1875    rewind(usbHandle);
1876    usbval = atoi(usbvalcstr);
1877    if (usbval==1) return 6;
1878
1879    return 0;
1880//#else
1881// return 6; //AC Power
1882#endif
1883}
1884
1885void GMenu2X::setInputSpeed() {
1886    /*
1887    input.setInterval(150);
1888    input.setInterval(30, VOLDOWN);
1889    input.setInterval(30, VOLUP );
1890    input.setInterval(30, CANCEL );
1891    input.setInterval(500, SETTINGS );
1892    input.setInterval(500, MENU );
1893    input.setInterval(300, CLEAR );
1894    input.setInterval(300, MANUAL );
1895    input.setInterval(1000,ACCEPT );
1896    //joy.setInterval(1000,ACTION_CLICK );
1897    input.setInterval(300, ALTLEFT );
1898    input.setInterval(300, ALTRIGHT );
1899    */
1900    SDL_EnableKeyRepeat(1,150);
1901}
1902
1903void GMenu2X::applyRamTimings() {
1904#ifdef TARGET_GP2X
1905    // 6 4 1 1 1 2 2
1906/* if (gp2x_mem!=0) {
1907        int tRC = 5, tRAS = 3, tWR = 0, tMRD = 0, tRFC = 0, tRP = 1, tRCD = 1;
1908        gp2x_memregs[0x3802>>1] = ((tMRD & 0xF) << 12) | ((tRFC & 0xF) << 8) | ((tRP & 0xF) << 4) | (tRCD & 0xF);
1909        gp2x_memregs[0x3804>>1] = ((tRC & 0xF) << 8) | ((tRAS & 0xF) << 4) | (tWR & 0xF);
1910    }*/
1911#endif
1912}
1913
1914void GMenu2X::applyDefaultTimings() {
1915#ifdef TARGET_GP2X
1916    // 8 16 3 8 8 8 8
1917/* if (gp2x_mem!=0) {
1918        int tRC = 7, tRAS = 15, tWR = 2, tMRD = 7, tRFC = 7, tRP = 7, tRCD = 7;
1919        gp2x_memregs[0x3802>>1] = ((tMRD & 0xF) << 12) | ((tRFC & 0xF) << 8) | ((tRP & 0xF) << 4) | (tRCD & 0xF);
1920        gp2x_memregs[0x3804>>1] = ((tRC & 0xF) << 8) | ((tRAS & 0xF) << 4) | (tWR & 0xF);
1921    }*/
1922#endif
1923}
1924
1925
1926
1927void GMenu2X::setClock(unsigned mhz) {
1928    mhz = constrain(mhz, 30, confInt["maxClock"]);
1929#ifdef TARGET_GP2X
1930    jz_cpuspeed(mhz);
1931#endif
1932}
1933
1934void GMenu2X::setGamma(int /*gamma*/) {
1935#ifdef TARGET_GP2X
1936/* float fgamma = (float)constrain(gamma,1,100)/10;
1937    fgamma = 1 / fgamma;
1938    MEM_REG[0x2880>>1]&=~(1<<12);
1939    MEM_REG[0x295C>>1]=0;
1940
1941    for (int i=0; i<256; i++) {
1942        unsigned char g = (unsigned char)(255.0*pow(i/255.0,fgamma));
1943        unsigned short s = (g<<8) | g;
1944        MEM_REG[0x295E>>1]= s;
1945        MEM_REG[0x295E>>1]= g;
1946    }*/
1947#endif
1948}
1949
1950int GMenu2X::getVolume() {
1951    unsigned long mixer;
1952        int basevolume = -1;
1953    mixer = open("/dev/mixer", O_RDONLY);
1954    if(mixer)
1955    {
1956        if (ioctl(mixer, SOUND_MIXER_READ_VOLUME, &basevolume) == -1) {
1957            ERROR("Failed opening mixer for read - VOLUME\n");
1958        }
1959        close(mixer);
1960        if(basevolume != -1)
1961            return (basevolume>>8) & basevolume ;
1962    }
1963    return basevolume;
1964}
1965
1966void GMenu2X::setVolume(int vol) {
1967    unsigned long mixer;
1968    int newvolume = vol;
1969    int oss_volume = newvolume | (newvolume << 8); // set volume for both channels
1970    mixer = open("/dev/mixer", O_WRONLY);
1971    if(mixer)
1972    {
1973        if (ioctl(mixer, SOUND_MIXER_WRITE_VOLUME, &oss_volume) == -1) {
1974            ERROR("Failed opening mixer for write - VOLUME\n");
1975        }
1976        close(mixer);
1977    }
1978
1979}
1980
1981void GMenu2X::setVolumeScaler(int scale) {
1982    scale = constrain(scale,0,MAX_VOLUME_SCALE_FACTOR);
1983    unsigned long soundDev = open("/dev/mixer", O_WRONLY);
1984    if (soundDev) {
1985        ioctl(soundDev, SOUND_MIXER_PRIVATE2, &scale);
1986        close(soundDev);
1987    }
1988}
1989
1990int GMenu2X::getVolumeScaler() {
1991    int currentscalefactor = -1;
1992    unsigned long soundDev = open("/dev/mixer", O_RDONLY);
1993    if (soundDev) {
1994        ioctl(soundDev, SOUND_MIXER_PRIVATE1, &currentscalefactor);
1995        close(soundDev);
1996    }
1997    return currentscalefactor;
1998}
1999
2000const string &GMenu2X::getExePath() {
2001    if (path.empty()) {
2002        char buf[255];
2003        memset(buf, 0, 255);
2004        int l = readlink("/proc/self/exe", buf, 255);
2005
2006        path = buf;
2007        path = path.substr(0,l);
2008        l = path.rfind("/");
2009        path = path.substr(0,l+1);
2010    }
2011    return path;
2012}
2013
2014string GMenu2X::getDiskFree() {
2015    stringstream ss;
2016    string df = "";
2017    struct statvfs b;
2018
2019    int ret = statvfs(CARD_ROOT, &b);
2020    if (ret==0) {
2021        // Make sure that the multiplication happens in 64 bits.
2022        unsigned long long free =
2023            ((unsigned long long)b.f_bfree * b.f_bsize) / 1048576;
2024        unsigned long long total =
2025            ((unsigned long long)b.f_blocks * b.f_frsize) / 1048576;
2026        ss << free << "/" << total << "MB";
2027        ss >> df;
2028    } else WARNING("statvfs failed with error '%s'.\n", strerror(errno));
2029    return df;
2030}
2031
2032int GMenu2X::drawButton(Button *btn, int x, int y) {
2033    if (y<0) y = resY+y;
2034    btn->setPosition(x, y-7);
2035    btn->paint();
2036    return x+btn->getRect().w+6;
2037}
2038
2039int GMenu2X::drawButton(Surface *s, const string &btn, const string &text, int x, int y) {
2040    if (y<0) y = resY+y;
2041    SDL_Rect re = {x, y-7, 0, 16};
2042    if (sc.skinRes("imgs/buttons/"+btn+".png") != NULL) {
2043        sc["imgs/buttons/"+btn+".png"]->blit(s, x, y-7);
2044        re.w = sc["imgs/buttons/"+btn+".png"]->raw->w+3;
2045        s->write(font, text, x+re.w, y, ASFont::HAlignLeft, ASFont::VAlignMiddle);
2046        re.w += font->getTextWidth(text);
2047    }
2048    return x+re.w+6;
2049}
2050
2051int GMenu2X::drawButtonRight(Surface *s, const string &btn, const string &text, int x, int y) {
2052    if (y<0) y = resY+y;
2053    if (sc.skinRes("imgs/buttons/"+btn+".png") != NULL) {
2054        x -= 16;
2055        sc["imgs/buttons/"+btn+".png"]->blit(s, x, y-7);
2056        x -= 3;
2057        s->write(font, text, x, y, ASFont::HAlignRight, ASFont::VAlignMiddle);
2058        return x-6-font->getTextWidth(text);
2059    }
2060    return x-6;
2061}
2062
2063void GMenu2X::drawScrollBar(uint pagesize, uint totalsize, uint pagepos, uint top, uint height) {
2064    if (totalsize<=pagesize) return;
2065
2066    s->rectangle(resX-8, top, 7, height, skinConfColors[COLOR_SELECTION_BG]);
2067
2068    //internal bar total height = height-2
2069    //bar size
2070    uint bs = (height-2) * pagesize / totalsize;
2071    //bar y position
2072    uint by = (height-2) * pagepos / totalsize;
2073    by = top+2+by;
2074    if (by+bs>top+height-2) by = top+height-2-bs;
2075
2076
2077    s->box(resX-6, by, 3, bs, skinConfColors[COLOR_SELECTION_BG]);
2078}
2079
2080void GMenu2X::drawTopBar(Surface *s) {
2081    if (s==NULL) s = this->s;
2082
2083    Surface *bar = sc.skinRes("imgs/topbar.png");
2084    if (bar != NULL)
2085        bar->blit(s, 0, 0);
2086    else
2087        s->box(0, 0, resX, skinConfInt["topBarHeight"],
2088        skinConfColors[COLOR_TOP_BAR_BG]);
2089}
2090
2091void GMenu2X::drawBottomBar(Surface *s) {
2092    if (s==NULL) s = this->s;
2093
2094    Surface *bar = sc.skinRes("imgs/bottombar.png");
2095    if (bar != NULL)
2096        bar->blit(s, 0, resY-bar->raw->h);
2097    else
2098        s->box(0, resY-20, resX, 20, skinConfColors[COLOR_BOTTOM_BAR_BG]);
2099}
2100

Archive Download this file



interactive