 /*
Diplomova prace : Palubni pocitac

gui.c

Atmega128A 10 MHz XTAL

Autor: Ondrej Lutera

2011/2012

*/

#include "gui.h"

/* presipaci hodiny 16 x 22px */
const dog_pgm_uint8_t Imgwait [] = {
0b01111111,0b11111100,
0b01100000,0b00001100,
0b01111111,0b11111100,
0b00100000,0b00001000,
0b00100000,0b00001000,
0b00100101,0b01001000,
0b00100010,0b10001000,
0b00110001,0b00011000,
0b00011000,0b00110000,
0b00001101,0b01100000,
0b00000110,0b11000000,
0b00000110,0b11000000,
0b00001100,0b01100000,
0b00011001,0b00110000,
0b00110000,0b00011000,
0b00100001,0b00001000,
0b00100010,0b10001000,
0b00100101,0b01001000,
0b00101010,0b10101000,
0b01111111,0b11111100,
0b01100000,0b00001100,
0b01111111,0b11111100,
};

void ul2Str(char * txt,uint8_t txtSize,uint32_t val, unsigned char prec)
{

    char txtbuf[20];
    char format[]="%s,%01u";

    if(prec!=0 && prec<10)
    {

        unsigned int precval=1;
        unsigned char i;

        for(i=0; i<prec; i++)precval*=10;

        /* avr sprintf neumi 32bit, prepocet pres ultoa + desetinna mista pres sprintf */

        ultoa(val/precval,txtbuf,10);
        format[5]=prec+'0';

        snprintf(txt,txtSize,format,txtbuf,(unsigned int)(val%precval));

        //strcat(txt,txtbuf);

    }
    else
    {

        ultoa(val,txt,10);

    }


}

void drawWait(unsigned char x,unsigned char y){

    dog_SetBitmapP(x,y,Imgwait,16,22);

}

void drawRbox(unsigned char x,unsigned char y,unsigned char xsize,unsigned char ysize,item_t * item,DOG_PGM_P valFont,DOG_PGM_P textFont,DOG_PGM_P unitFont,uint8_t edit)
{

    char txt[40];
    pcf_t *t;
    int16_t prec;


    /* popis merene veliciny*/
    if(item->prec == FORMAT_TEMP)dog_DrawStr(x+2,y+ysize-dog_GetFontBBXHeight(textFont),textFont,item->text.ram);
    else dog_DrawStrP(x+2,y+ysize-dog_GetFontBBXHeight(textFont),textFont,item->text.flash);



    /*jednotka merene veliciny*/
    if(item->unit)
        dog_DrawStrP((x+xsize)-dog_GetStrWidthP(unitFont,item->unit),y+ysize-dog_GetFontBBXHeight(textFont),unitFont,item->unit);

    if(edit){

        dog_SetHLine(x+(xsize/2)-4,x+(xsize/2)+4,y+ysize-1);

    }

    /*vlastni hodnota*/
    switch(item->prec)
    {

    case FORMAT_TEMP:

        prec = item->value.temp%10;
        if(prec<0)prec*=(-1);

        snprintf_P(txt,40,PSTR("%i,%i"),item->value.temp/10,prec);

        break;

    case FORMAT_TIME:

        t = item->value.pTime;

        snprintf(txt,40,"%02u:%02u:%02u",t->hour,t->min,t->sec);

        break;

    default:
        ul2Str(txt,40,item->value.ui32,item->prec);


        break;

    }

    dog_DrawStr((x+(xsize)/2)-(dog_GetStrWidth(valFont,txt)/2),y+((ysize)/2)-dog_GetFontBBXHeight(valFont)/2,valFont,txt);

}

void drawFrame(void)
{

    dog_SetVLine(0,0,YMAX)    ;
    dog_SetVLine(XMAX,0,XMAX);
    dog_SetHLine(0,XMAX,0);
    dog_SetHLine(0,XMAX,YMAX);


}

void drawVscreen(vscreen_t * screen)
{

//    char txt[20];

    /* vykresleni delicich car */
    drawFrame();

    dog_SetVLine(BIGCOL,1,YMAX-1);
    dog_SetHLine(1,XMAX-1,ROWSIZE);
    dog_SetHLine(BIGCOL+1,XMAX-1,2*ROWSIZE);
    //dog_SetHLine(1,BIGCOL-1,BIGROW);

    /* vykresleni obsahu bunek */

    drawRbox(BIGCOL,2*ROWSIZE,XMAX-BIGCOL-1,ROWSIZE,&screen->item[4],screen->valFont,screen->textFont,screen->unitFont,screen->edit==5?1:0);
    drawRbox(BIGCOL,ROWSIZE,XMAX-BIGCOL-1,ROWSIZE,&screen->item[3],screen->valFont,screen->textFont,screen->unitFont,screen->edit==4?1:0);
    drawRbox(BIGCOL,0,XMAX-BIGCOL-1,ROWSIZE,&screen->item[2],screen->valFont,screen->textFont,screen->unitFont,screen->edit==3?1:0);

    drawRbox(0,0,BIGCOL-1,ROWSIZE,&screen->item[1],screen->valFont,screen->textFont,screen->unitFont,screen->edit==2?1:0);
    drawRbox(0,ROWSIZE,BIGCOL-1,2*ROWSIZE,&screen->item[0],screen->bigValFont,screen->textFont,screen->unitFont,screen->edit==1?1:0);

}

void drawCursor(unsigned char x,unsigned char y)
{

    if(x<= (XMAX-4) && y>1 && y <= (YMAX-2))
    {

        dog_SetHLine(x,x+4,y);
        dog_SetHLine(x+2,x+3,y-1);
        dog_SetHLine(x+2,x+3,y+1);
        dog_SetPixel(x+2,y-2);
        dog_SetPixel(x+2,y+2);
    }

}

/* vykresli Menu - seznam ktery obsahuje popis + pripadne zobrazenou hodnotu,
pres kterou se lze v edit modu "pohybovat" kurzorem..Edit atd zabezpeci user aplikace, stejne tak omezeni menu..

*/

void drawMenu(menu_t * menu)
{

    char txt[20];
    char * pTxt = txt;
    list_t *pList;
    unsigned char height = (dog_GetFontBBXHeight(menu->font)-1);
    unsigned char width = dog_GetFontBBXWidth(menu->font);
    unsigned char h = YMAX-dog_GetFontBBXHeight(menu->titleFont)+1;
    unsigned char first_line = h - height -4 ;
    unsigned char index = 0;
    unsigned char listIndex = 0;
    unsigned char valPx;
    static unsigned char lastBegin = 0;
    unsigned char maxItems = first_line/height;

    drawFrame();

    dog_SetHLine(0,XMAX,h);

    dog_DrawStr((XMAX/2)-(dog_GetStrWidth(menu->titleFont,menu->titleText)/2),h+2,menu->titleFont,menu->titleText);

    listIndex = lastBegin;

    if((menu->cursor-listIndex) > maxItems)
    {

        listIndex = menu->cursor - maxItems ;
        lastBegin = listIndex;

    }

    if(menu->cursor < lastBegin)
    {

        listIndex = menu->cursor;
        lastBegin = listIndex;

    }

    if(menu->cursor < menu->list_size)
    {

        if(menu->flags&F_EDIT)
        {
            drawCursor(MENU_TEXT_OFFSET+dog_GetStrWidthP(menu->font,menu->list[menu->cursor].text),first_line-(height*(menu->cursor-lastBegin))+(height/2));
        }
        else
        {
            drawCursor(CURSOR_OFFSET,first_line-(height*(menu->cursor-lastBegin))+(height/2));
        }
    }

    do
    {
        pList = ((menu->list)+listIndex);

        dog_DrawStrP(MENU_TEXT_OFFSET,first_line-height*index,menu->font,pList->text);

        pTxt = NULL;

        switch(pList->mode)
        {

        case MODE_UCHAR:
            if(pList->edit.ui8!=NULL){

                ul2Str(txt,20,*(pList->edit.ui8),pList->prec);
                pTxt = txt;


            }

            break;

        case MODE_UINT:
            if(pList->edit.val!=NULL)
            {

                ul2Str(txt,20,*(pList->edit.val),pList->prec);
                pTxt = txt;


            }
            break;
        case MODE_UI32:
            if(pList->edit.val!=NULL)
            {

                ul2Str(txt,20,*(pList->edit.ui32),pList->prec);
                pTxt = txt;


            }
            break;

        case MODE_SINT:
            if(pList->edit.val!=NULL)
            {
                char * format = "%i,%01i";
                uint16_t precval=1;
                format[5]=pList->prec + '0';

                for(uint8_t i=0; i<pList->prec; i++)precval*=10;

                uint16_t tmp = *pList->edit.sval%precval;

                if(tmp<0)tmp=-tmp;

                snprintf(txt,20,format,*pList->edit.sval/precval,tmp);

                pTxt = txt;

            }
            break;

        case MODE_TEXT:
            if(pList->edit.text!=NULL)
            {
                pTxt = pList->edit.text;

            }
            break;

        case MODE_TIME:

            if(pList->edit.time!=NULL)
            {



                sprintf_P(txt,PSTR("%02u:%02u:%02u"),      pList->edit.time->hour,
                                                                    pList->edit.time->min,
                                                                    pList->edit.time->sec);
                pTxt = txt;

            }

            break;
        case MODE_DATE:

            if(pList->edit.time!=NULL)
            {


                sprintf_P(txt,PSTR("%02u/%02u/%04u"),pList->edit.time->day,
                                                                    pList->edit.time->month,
                                                                    pList->edit.time->year);

                pTxt = txt;

            }

            break;


        }

        valPx = dog_GetStrWidth(menu->font,pTxt);

        dog_DrawStr(MENU_VAL_OFFSET-valPx,first_line-height*index,menu->font,pTxt);

        if(menu->flags & F_EDIT && menu->cursor == listIndex)
        {

            unsigned char edit_pos = menu->edit_pos;


            if(pList->mode==MODE_TIME ){


                if(menu->edit_pos > 1)edit_pos++;
                if(menu->edit_pos > 3)edit_pos++;

            }else if(pList->mode==MODE_DATE){

                if(menu->edit_pos > 3)edit_pos++;
                if(menu->edit_pos > 5)edit_pos++;


            }else if(pList->prec>0 && menu->edit_pos >= pList->prec)edit_pos++;


            unsigned char offset;

            //if(edit_pos < strlen(txt))
            if(pList->mode!=MODE_TEXT) offset = edit_pos*width;
            else offset = valPx - (edit_pos+1)*width;


            dog_SetHLine(MENU_VAL_OFFSET-offset-width,MENU_VAL_OFFSET-offset,first_line-height*index);


        }

        index++;
        listIndex++;


    }
    while((height*index)<YMAX && index < (maxItems+1) && listIndex<menu->list_size);




}

unsigned char getMaxDay(pcf_t *time){

switch(time->month){

                    case 2:
                            if(time->year%100==0 && time->year%400==0) return 29;
                            else if(time->year%4==0) return 29;
                            else return 28;

                            break;
                    case 4:
                    case 6:
                    case 9:
                    case 11:

                            return 30;

                            break;
                    default:

                            break;


                    }

    return 31;
}

/* vraci 1 pokud doslo k opusteni editacniho modu, jinak 0 */

/* backup umoznuje predulozeni editovane hodnoty pro vraceni.. 0 ignoruje, 1 uklada, 2 maze ulozene */

unsigned char editMenuVal(menu_t * menu,key_t *keys, unsigned char backup)
{

    static unsigned int val;     /* jakasi zaloha */
    static unsigned char stored=0;
    static char text[20];
    static pcf_t timeDate;

    unsigned char index = menu->cursor;
    list_t * pList;
    unsigned int delta=1;
    unsigned char i;
    unsigned char t;


    if(menu==NULL)
    {

        stored = 0;
        return 1;

    }

    if(index<menu->list_size) pList = (menu->list)+index;
    else
    {
        menu->flags &=~F_EDIT;
        return 1;
    }

    if(backup<2 && !stored)
    {
        switch(pList->mode)
        {
        case MODE_UCHAR:
            val=*(pList->edit.ui8);

            break;

        case MODE_UINT:
            val=*(pList->edit.val);
            break;
        case MODE_SINT:
            val=*(pList->edit.sval);
            break;
        case MODE_TEXT:

            strncpy(text,pList->edit.text,20);

            break;

        case MODE_TIME:

            timeDate.hour = pList->edit.time->hour;
            timeDate.min = pList->edit.time->min;
            timeDate.sec = pList->edit.time->sec;

            break;

        case MODE_DATE:

            timeDate.year = pList->edit.time->year;
            timeDate.month = pList->edit.time->month;
            timeDate.day = pList->edit.time->day;

            break;

        }

        stored = 1;

    }
    if(backup>1)stored=0;

    if(keys->keys&OK)
    {

        if(menu->edit_pos < menu->max_edit_pos)menu->edit_pos++;
        else
        {

            stored = 0;
            menu->flags &=~F_EDIT;
            return  1;

        }

    }

    if(keys->keys&MENU && pList->mode == MODE_TEXT)
    {


        pList->edit.text[menu->edit_pos]='\0';

    }

    if(keys->keys&ESC)
    {

        if(stored)
        {

            switch(pList->mode)
            {
            case MODE_UCHAR:
                *(pList->edit.ui8) = (uint8_t)val;
                break;

            case MODE_UINT:
                *(pList->edit.val) = val;
                break;
            case MODE_SINT:
                *(pList->edit.sval) = val;
                break;
            case MODE_TEXT:
                /* zde nesmi byt strncpy */
                strcpy(pList->edit.text,text);
                break;
            case MODE_TIME:
                pList->edit.time->hour = timeDate.hour;
                pList->edit.time->min = timeDate.min;
                pList->edit.time->sec = timeDate.sec;
                break;
            case MODE_DATE:
                pList->edit.time->year = timeDate.year;
                pList->edit.time->day = timeDate.day ;
                pList->edit.time->month = timeDate.month;
                break;
            }
        }
        stored = 0;
        menu->flags &=~F_EDIT;
        return 0;


    }

    menu->flags |=F_EDIT;

    if(menu->edit_pos)  for(i=0; i<menu->edit_pos; i++)delta*=10;

    if(pList->mode==MODE_DATE){


    if(menu->edit_pos > 3){

        if(menu->edit_pos%2)delta=10;
        else delta=1;

    }

    }

    if(menu->edit_pos%2) t=10;
    else t=1;



    while(keys->key_up)
    {
        switch(pList->mode)
        {
        case MODE_UCHAR:
            if((VAL_T_MAX-delta)>=*pList->edit.ui8)    *pList->edit.ui8+=delta;
            else keys->key_up=1;
            break;

        case MODE_UINT:
            if((VAL_T_MAX-delta)>=*pList->edit.val)    *pList->edit.val+=delta;
            else keys->key_up=1;
            break;
        case MODE_SINT:
            if((VAL_T_MAX-delta)>=*pList->edit.sval)    *pList->edit.sval+=delta;
            else keys->key_up=1;
            break;
        case MODE_TEXT:

            if(pList->edit.text[menu->edit_pos]=='\0')pList->edit.text[menu->edit_pos+1]='\0';

            pList->edit.text[menu->edit_pos]++;

            if(pList->edit.text[menu->edit_pos] > 'z') pList->edit.text[menu->edit_pos] = 'A';

            if(pList->edit.text[menu->edit_pos] < 'A') pList->edit.text[menu->edit_pos] = 'z';

            break;
        case MODE_TIME:

                switch(menu->edit_pos){

                case 0:
                case 1:

                    pList->edit.time->sec+=t;

                    if(pList->edit.time->sec>59)pList->edit.time->sec-=60;

                    break;

                case 2:
                case 3:

                    pList->edit.time->min+=t;

                    if(pList->edit.time->min>59)pList->edit.time->min-=60;

                    break;

                case 4:
                case 5:

                    if(pList->edit.time->hour+t>23)
                            pList->edit.time->hour%=10;
                    else pList->edit.time->hour+=t;


                    break;
                }

                break;
            case MODE_DATE:

                switch(menu->edit_pos){

                case 0:
                case 1:
                case 2:
                case 3:

                    if((2999-delta)>=pList->edit.time->year)   pList->edit.time->year+=delta;


                    break;

                case 4:
                case 5:

                    if((12-delta)>=pList->edit.time->month)   pList->edit.time->month+=delta;

                    break;

                case 6:
                case 7:

                    t = getMaxDay(pList->edit.time);

                    if((t-delta)>=pList->edit.time->day)   pList->edit.time->day+=delta;

                    break;
                }

                break;



        }
        keys->key_up--;

    }

    while(keys->key_down)
    {
        switch(pList->mode)
        {
            case MODE_UCHAR:
            if(*pList->edit.ui8>=delta)    *pList->edit.ui8-=delta;
            else keys->key_down = 1;
            break;

        case MODE_UINT:
            if(*pList->edit.val>=delta)    *pList->edit.val-=delta;
            else keys->key_down = 1;
            break;
        case MODE_SINT:
            if(*pList->edit.sval>=delta)    *pList->edit.sval-=delta;
            else keys->key_down = 1;
            break;

        case MODE_TEXT:

            if(pList->edit.text[menu->edit_pos]=='\0')pList->edit.text[menu->edit_pos+1]='\0';

            pList->edit.text[menu->edit_pos]--;

            if(pList->edit.text[menu->edit_pos] < 'A') pList->edit.text[menu->edit_pos] = 'z';

            if(pList->edit.text[menu->edit_pos] > 'z') pList->edit.text[menu->edit_pos] = 'A';

            break;
         case MODE_TIME:

                switch(menu->edit_pos){

                case 0:
                case 1:

                    if(pList->edit.time->sec>=t)
                              pList->edit.time->sec-=t;
                    else pList->edit.time->sec = 60 - t + pList->edit.time->sec%10;;


                    break;

                case 2:
                case 3:
                   if(pList->edit.time->min>=t)
                              pList->edit.time->min-=t;
                    else pList->edit.time->min = 60 - t + pList->edit.time->min%10;


                    break;

                case 4:
                case 5:
                    if(pList->edit.time->hour>=t)
                              pList->edit.time->hour-=t;
                    else pList->edit.time->hour= (t>1?20:24) - t + pList->edit.time->hour%10;


                    break;
                }

                break;
        case MODE_DATE:

                switch(menu->edit_pos){

                case 0:
                case 1:
                case 2:
                case 3:

                    if(pList->edit.time->year>=delta)   pList->edit.time->year-=delta;


                    break;

                case 4:
                case 5:

                    if(pList->edit.time->month>=delta)   pList->edit.time->month-=delta;

                    break;

                case 6:
                case 7:



                    if(pList->edit.time->day>=delta)   pList->edit.time->day-=delta;

                    break;
                }

                break;

        }
        keys->key_down --;

    }



    return 0;

}


