Menus LCD TFT

Dependents:   Example_Menu_LCD_TFT

Menus.h

Committer:
Suky
Date:
2011-03-15
Revision:
0:310ed2337a8f

File content as of revision 0:310ed2337a8f:

/*
   \file Menus.h
   \version: 1.0
   
   \brief Este fichero contiene funciones para creación de Menus es LCD TFT.- 
   
   \web www.micros-designs.com.ar
   \date 15/03/11
   
 *- Version Log --------------------------------------------------------------*
 *   Fecha       Autor                Comentarios                             *
 *----------------------------------------------------------------------------*
 * 15/03/11      Suky        Original                                         *
 *----------------------------------------------------------------------------*/ 
///////////////////////////////////////////////////////////////////////////
////                                                                   ////
////                                                                   ////
////        (C) Copyright 2011 www.micros-designs.com.ar               ////
//// Este código puede ser usado, modificado y distribuido libremente  ////
//// sin eliminar esta cabecera y  sin garantía de ningún tipo.        ////
////                                                                   ////
////                                                                   ////
/////////////////////////////////////////////////////////////////////////// 
#ifndef __MENUS_H__
#define __MENUS_H__

#include "mbed.h"
#include "LCDTFT.h"
#include "Touch.h"
#include "GenericTypeDefs.h"
#include "Images.h"

// ****************************************************************************************
#define TOUCH_X_MIN 20
#define TOUCH_X_MAX 230
#define TOUCH_Y_MIN 15
#define TOUCH_Y_MAX 240
// ****************************************************************************************
#define MENU_FIN                0
#define MENU_COMANDO            1
#define MENU_SUBMENU            2
#define SUBMENU_ANTERIOR        3
#define MENU_MAIN               4
// ****************************************************************************************
#define MENSAJE_ATRAS_OK        1
#define MENSAJE_NO_SI           2
#define MENSAJE_ATRAS           3

#define MENSAJE_ACCION_ATRAS    1
#define MENSAJE_ACCION_OK       2
#define MENSAJE_ACCION_NO       3
#define MENSAJE_ACCION_SI       4

#define MODIFICADOR_ACEPTAR     1
#define MODIFICADOR_CANCELAR    2
// ****************************************************************************************
#define IMAGEN_FONDO_MENU       10
// ****************************************************************************************
#define BOTON_NORMAL            1
#define BOTON_PRES_IZQ          2
#define BOTON_PRES_DER          3
#define ITEM_NORMAL             4
#define ITEM_PRES               5
// ****************************************************************************************
#define COLOR_LETRA_BOTON       ColorAqua
#define COLOR_LETRA_BOTON_PRES  ColorWhite
#define COLOR_FONDO_LETRA       ColorGray
#define COLOR_MSJ               ColorWhite
// ****************************************************************************************
#define JUST_IZQ                1
#define JUST_DER                2
#define JUST_CENTRADO           3
// ****************************************************************************************
#define AREA_BTN_INF_DER()       (Coordenadas.x<235 && Coordenadas.x>135) && (Coordenadas.y<320 && Coordenadas.y>290)
#define AREA_BTN_INF_IZQ()       (Coordenadas.x<105 && Coordenadas.x>5) && (Coordenadas.y<320 && Coordenadas.y>290)
// ****************************************************************************************
TouchScreenADS7843 MyTouch(p9,p10,p12,p11,p8); // ADS7843-> SDO,SDI,SCK,CS,IRQ
BusOut    MyBus(p13,p14,p15,p16,p17,p18,p19,p20,p30,p29,p28,p27,p26,p25,p24,p23);
LCDTFT    MyLCD(p5,p6,p7,p22,p21,&MyBus);
// ****************************************************************************************
typedef struct{
    UINT8 TipoMenu;
    const UINT8 *TextoMenu;
    UINT8 *Menu;
    void (*PtrFuncionSeleccion)(void);
    const UINT16 *PtrIcono;
}MENU;
// ****************************************************************************************
struct{
    const MENU *PtrMenu;
    UINT8 ElementoSeleccionActual; 
    void (*FuncionActualEjecucion)(void);
    UINT8 CantElementosMenu;
}MenuActual;
// ****************************************************************************************
struct{
    float ValorInicial;
    float ValorActual;
    UINT8 String[15];
    UINT8 Ptr;
    void (*FuncionActualEjecucion)(UINT8,float);
}ModificadorVariable;
// ****************************************************************************************
struct{
    UINT8 TipoMensajePantalla;
    void (*MensajeFuncionEjecutar)(UINT8);
}MensajePantalla;
// ****************************************************************************************
TOUCH_DATA Coordenadas;
volatile bool kbhit_irq=0;
volatile bool kbhit_tratament=0;
// ****************************************************************************************
void vSeteoFuncionEjecutar(void (*PtrNuevaFuncion)(void));
void vEjecutaEventosMenu(void);
void vSeleccionarMenuAnterior(void);
void vSeleccionMenu(const MENU *Menu,UINT8 ElementoMenuSeleccion);
void vEventosSubMenu(void);
void vDibujarImagenFondo(UINT8 Seleccion);
void vDibujarMenuInferior(const UINT8 *TextoIzq,const UINT8 *TextoDer, UINT8 Status);
void vDibujarElementoMenu(UINT8 NElemento,UINT8 Status);
void vMensajePantalla(const UINT8 *Mensaje,UINT16 YInicial,UINT8 TipoMensaje,void (*FuncionEjecutar)(UINT8));
void vEventosPantallaMensaje(void);
void vModificadorVariables(const UINT8 *NombreVariable,float ValorInicial,void (*PtrFuncion)(UINT8,float));
void vEventosModificadorVariables(void);
void vTextoJustificado(const unsigned char *PtrTexto,unsigned short ExtremoIzq, unsigned short ExtremoDer, unsigned short y, unsigned char Just,const char (*Fuente)[5],unsigned char Alto, unsigned short Color);
void vEscribirMensaje(unsigned short YInicial,const unsigned char *Mensaje,const char (*Fuente)[5],unsigned char Just, unsigned short Color);
// ****************************************************************************************
// Rutina de atencion de interrupcion.-
void vISRTouchIRQ(){
    UINT_COORDxy Temp;
    
    
    MyTouch.vTestTouchPanel(&Coordenadas);
    // Coordenadas dentro del rango de pantalla LCD:
    if((Coordenadas.x>TOUCH_X_MIN && Coordenadas.x<TOUCH_X_MAX) && (Coordenadas.y>TOUCH_Y_MIN && Coordenadas.y<TOUCH_Y_MAX)){
        if(kbhit_tratament==0){            
            // Cambio de coordenda y escala:
            Temp=Coordenadas.y;
            Coordenadas.y=((float)((255.0-TOUCH_X_MIN)-Coordenadas.x)*(320.0/(TOUCH_X_MAX-TOUCH_X_MIN)));
            Coordenadas.x=((float)(Temp-TOUCH_Y_MIN)*(240.0/(TOUCH_Y_MAX-TOUCH_Y_MIN)));
            kbhit_irq=1;
        }
    }    
}
// ****************************************************************************************
void vInitLCDTFTAndTouch(void){
    MyTouch.vInitADS7843(USE_8BITS,&vISRTouchIRQ);
    MyLCD.vLCDTFTInit();
    Led1=0;
    Led2=0;
}
// ****************************************************************************************
// ****************************************************************************************
/* ** Se carga en puntero la funcion que se ejecutara dentro del while ** */
void vSeteamosFuncionEjecutar(void (*PtrNuevaFuncion)(void)){    
    MenuActual.FuncionActualEjecucion = PtrNuevaFuncion;
}
/* ** Ejecuta funcion que se encuentra apuntada ** */
void vEjecutaEventosMenu(void){
    (*MenuActual.FuncionActualEjecucion)();
}
/* ** Selecciona Menu anterior a mostrar despues de un comando ** */
void vSeleccionarMenuAnterior(void){
    vSeleccionMenu(MenuActual.PtrMenu,MenuActual.ElementoSeleccionActual);
}
    
/* ** Selecciona y dibuja un submenu, luego carga en puntero funcion que atiende sus eventos ** */
void vSeleccionMenu(const MENU *Menu,UINT8 ElementoMenuSeleccion){
UINT8 NElemento;

    /* ** Guardamos el Menu actual que se visualiza y trabaja ** */
    MenuActual.PtrMenu=Menu;
    MenuActual.ElementoSeleccionActual=ElementoMenuSeleccion;

    /* ** Borramos pantalla y dibujamos elementos del menu** */
    vDibujarImagenFondo(IMAGEN_FONDO_MENU);
    
    /* ** Dibujamos barra con titulo ** */
    MyLCD.vLCDTFTDrawImage(0,0,WIDTH_TITULO,HEIGH_TITULO,LENGTH_TITULO,&Titulo[0]);
    vTextoJustificado(MenuActual.PtrMenu[0].TextoMenu,5,234,4,JUST_CENTRADO,&ARIAL[0],2,ColorAzulMarino);
    /* ** Dibujamos Items ** */
    NElemento=1;
    while(MenuActual.PtrMenu[NElemento].TipoMenu!=MENU_FIN){    
        vDibujarElementoMenu(NElemento-1,ITEM_NORMAL);
        NElemento++;
    }
    MenuActual.CantElementosMenu=NElemento-1;
    
    if(MenuActual.PtrMenu[0].TipoMenu==MENU_MAIN){
        vDibujarMenuInferior(" ","Menu",BOTON_NORMAL);
    }else{
        vDibujarMenuInferior("Atras"," ",BOTON_NORMAL);
    }
    /* ** Cargamos en puntero funci&#65533;n que atiende eventos del Submenu (Funci&#65533;n en while del main)** */
    vSeteamosFuncionEjecutar(vEventosSubMenu);
}

void vDibujarImagenFondo(UINT8 Seleccion){

    switch(Seleccion){
        case IMAGEN_FONDO_MENU:
            for(short k=0;k<320;k+=10){
                MyLCD.vLCDTFTDrawImage(0,k,WIDTH_FONDO,HEIGH_FONDO,LENGTH_FONDO,&Fondo[0]);
            }
        break;
    }
}
/* ** Dibuja barra inferior de botones ** */ 
void vDibujarMenuInferior(const UINT8 *TextoIzq,const UINT8 *TextoDer, UINT8 Status){

    
    switch(Status){
        case BOTON_PRES_IZQ:
            vTextoJustificado(TextoIzq,5,105,296,JUST_CENTRADO,&ARIAL[0],2,COLOR_LETRA_BOTON_PRES);
        break;
        case BOTON_PRES_DER:
            vTextoJustificado(TextoDer,135,234,296,JUST_CENTRADO,&ARIAL[0],2,COLOR_LETRA_BOTON_PRES);
        break;
        case BOTON_NORMAL:
            MyLCD.vLCDTFTDrawImage(0,289,WIDTH_BOTONES,HEIGH_BOTONES,LENGTH_BOTONES,&Botones[0]);
            vTextoJustificado(TextoIzq,5,105,296,JUST_CENTRADO,&ARIAL[0],2,COLOR_LETRA_BOTON);
            vTextoJustificado(TextoDer,135,234,296,JUST_CENTRADO,&ARIAL[0],2,COLOR_LETRA_BOTON);
        break;
    }
}
/* ** Dibuja elementos del submenu ** */
void vDibujarElementoMenu(UINT8 NElemento,UINT8 Status){

    if(Status==ITEM_NORMAL){
        if((NElemento%2)==0){
            MyLCD.vLCDTFTDrawImage(35,28+((((NElemento+2)/2)-1)*65),WIDTH_ICONO,HEIGH_ICONO,LENGTH_ICONO,MenuActual.PtrMenu[NElemento+1].PtrIcono);
            MyLCD.vLCDTFTRectangle(5,81+((((NElemento+2)/2)-1)*65),114,90+((((NElemento+2)/2)-1)*65),1,COLOR_FONDO_LETRA);
            vTextoJustificado(MenuActual.PtrMenu[NElemento+1].TextoMenu,5,114,82+((((NElemento+2)/2)-1)*65),JUST_CENTRADO,&ARIAL[0],1,COLOR_LETRA_BOTON);
        }else{
            MyLCD.vLCDTFTDrawImage(155,28+((((NElemento+2)/2)-1)*65),WIDTH_ICONO,HEIGH_ICONO,LENGTH_ICONO,MenuActual.PtrMenu[NElemento+1].PtrIcono);  
            MyLCD.vLCDTFTRectangle(125,81+((((NElemento+2)/2)-1)*65),234,90+((((NElemento+2)/2)-1)*65),1,COLOR_FONDO_LETRA);
            vTextoJustificado(MenuActual.PtrMenu[NElemento+1].TextoMenu,125,234,82+((((NElemento+2)/2)-1)*65),JUST_CENTRADO,&ARIAL[0],1,COLOR_LETRA_BOTON);  
        }
    }else{
        if((NElemento%2)==0){
            vTextoJustificado(MenuActual.PtrMenu[NElemento+1].TextoMenu,5,114,82+((((NElemento+2)/2)-1)*65),JUST_CENTRADO,&ARIAL[0],1,COLOR_LETRA_BOTON_PRES);
        }else{
            vTextoJustificado(MenuActual.PtrMenu[NElemento+1].TextoMenu,125,234,82+((((NElemento+2)/2)-1)*65),JUST_CENTRADO,&ARIAL[0],1,COLOR_LETRA_BOTON_PRES);  
        }
    }
}
// ****************************************************************************************
// ****************************************************************************************
void vEventosSubMenu(void){
    const MENU *SubMenu;
    void (*PtrComando)(void);
    
    if(kbhit_irq==1){
        kbhit_irq=0;
        kbhit_tratament=1;
        
        if(MenuActual.PtrMenu[0].TipoMenu==MENU_MAIN){
            if(AREA_BTN_INF_DER()){
                vDibujarMenuInferior(" ","Menu",BOTON_PRES_DER);
                wait_ms(300);
                SubMenu=(MENU *)MenuActual.PtrMenu[0].Menu;
                vSeleccionMenu(SubMenu,1);
            }
            kbhit_tratament=0;
        }else{
            for(char k=0;k<MenuActual.CantElementosMenu;k++){
                if((k%2)==0){
                    if((Coordenadas.x<85 && Coordenadas.x>35) && (Coordenadas.y<(78+((((k+2)/2)-1)*65)) && Coordenadas.y>(28+((((k+2)/2)-1)*65)))){
                        vDibujarElementoMenu(k,ITEM_PRES);
                        wait_ms(300);
                        MenuActual.ElementoSeleccionActual=k+1;
                        /* ** Abrimos otro submenu o ejecutamos comando ** */
                        switch(MenuActual.PtrMenu[k+1].TipoMenu){
                            case MENU_COMANDO:
                                PtrComando=(void(*)(void))MenuActual.PtrMenu[k+1].PtrFuncionSeleccion;
                                kbhit_tratament=0;
                                if(PtrComando!=NULL) (*PtrComando)();
                            break;
                            case MENU_SUBMENU:
                                SubMenu=(MENU *)MenuActual.PtrMenu[k+1].Menu;
                                vSeleccionMenu(SubMenu,1);
                            break;
                        }
                    }
                }else{
                    if((Coordenadas.x<205 && Coordenadas.x>155) && (Coordenadas.y<(78+((((k+2)/2)-1)*65)) && Coordenadas.y>(28+((((k+2)/2)-1)*65)))){
                        vDibujarElementoMenu(k,ITEM_PRES);
                        wait_ms(300);
                        MenuActual.ElementoSeleccionActual=k+1;
                        /* ** Abrimos otro submenu o ejecutamos comando ** */
                        switch(MenuActual.PtrMenu[k+1].TipoMenu){
                            case MENU_COMANDO:
                                PtrComando=(void(*)(void))MenuActual.PtrMenu[k+1].PtrFuncionSeleccion;
                                kbhit_tratament=0; 
                                if(PtrComando!=NULL) (*PtrComando)();
                            break;
                            case MENU_SUBMENU:
                                SubMenu=(MENU *)MenuActual.PtrMenu[k+1].Menu;
                                vSeleccionMenu(SubMenu,1);
                            break;
                        }
                    }
                }                
            }
            
            if(AREA_BTN_INF_IZQ()){
                vDibujarMenuInferior("Atras"," ",BOTON_PRES_IZQ);
                wait_ms(300);
                SubMenu=(MENU *)MenuActual.PtrMenu[0].Menu;
                vSeleccionMenu(SubMenu,1);
            }
            kbhit_tratament=0;        
        }
    }    
} 
// ********************************************************************************************************************************
// ****************************************** MENSAJES EN PANTALLA ****************************************************************
// ********************************************************************************************************************************
/* ** Se escribe un mensaje en pantalla para elemento del tipo comando, presentando en barra inferior opcion a elegir ** */
void vMensajePantalla(const UINT8 *Mensaje,UINT16 YInicial,UINT8 TipoMensaje,void (*FuncionEjecutar)(UINT8)){

    MensajePantalla.MensajeFuncionEjecutar=FuncionEjecutar;
    MensajePantalla.TipoMensajePantalla=TipoMensaje;

    vDibujarImagenFondo(IMAGEN_FONDO_MENU);
    MyLCD.vLCDTFTDrawImage(0,0,WIDTH_TITULO,HEIGH_TITULO,LENGTH_TITULO,&Titulo[0]);
    vTextoJustificado(MenuActual.PtrMenu[MenuActual.ElementoSeleccionActual].TextoMenu,5,234,4,JUST_CENTRADO,&ARIAL[0],2,ColorAzulMarino);
    
    MyLCD.vLCDTFTRectangle(5,30,234,284,1,ColorGray);
    MyLCD.vLCDTFTRectangle(5,30,234,31,1,ColorWhite);
    MyLCD.vLCDTFTRectangle(5,283,234,284,1,ColorBlack);
    MyLCD.vLCDTFTRectangle(5,30,6,284,1,ColorWhite);
    MyLCD.vLCDTFTRectangle(233,30,234,284,1,ColorWhite);
    
    vEscribirMensaje(YInicial,Mensaje,&ARIAL[0],JUST_CENTRADO,COLOR_MSJ);

    switch(TipoMensaje){
        case MENSAJE_ATRAS_OK:
            vDibujarMenuInferior("Atras", "Ok",BOTON_NORMAL);
        break;        
        case MENSAJE_NO_SI:
            vDibujarMenuInferior("No", "Si",BOTON_NORMAL);
        break;        
        case MENSAJE_ATRAS:
            vDibujarMenuInferior("Atras", " ",BOTON_NORMAL);
        break;
    }
    vSeteamosFuncionEjecutar(vEventosPantallaMensaje);
}

/* ** Se atiende eventos de pantalla con mensaje ** */
void vEventosPantallaMensaje(void){    
    UINT8 AccionPulsIzq,AccionPulsDer;
    const UINT8 *TextDer,*TextIzq;

    switch(MensajePantalla.TipoMensajePantalla){
        case MENSAJE_ATRAS_OK:
            AccionPulsIzq = MENSAJE_ACCION_ATRAS;
            AccionPulsDer = MENSAJE_ACCION_OK;
            TextDer="Atras";
            TextIzq="Ok";
        break;

        case MENSAJE_NO_SI:
            AccionPulsIzq = MENSAJE_ACCION_NO;
            AccionPulsDer = MENSAJE_ACCION_SI;
            TextDer="No";
            TextIzq="Si";
        break;
        
        default:
            AccionPulsIzq = MENSAJE_ACCION_ATRAS;
            AccionPulsDer = MENSAJE_ACCION_ATRAS;
            TextDer="Atras";
            TextIzq=" ";
    }
    if(kbhit_irq==1){
        kbhit_irq=0;
        kbhit_tratament=1;
        
        if(AREA_BTN_INF_DER()){
            vDibujarMenuInferior(TextIzq,TextDer,BOTON_PRES_DER);
            wait_ms(300);
            (*MensajePantalla.MensajeFuncionEjecutar)(AccionPulsIzq);
        }
        if(AREA_BTN_INF_IZQ()){
            vDibujarMenuInferior(TextIzq,TextDer,BOTON_PRES_IZQ);
            wait_ms(300);
            (*MensajePantalla.MensajeFuncionEjecutar)(AccionPulsDer);
        }
        kbhit_tratament=0;
    }
}

void vModificadorVariables(const UINT8 *NombreVariable,float ValorInicial,void (*PtrFuncion)(UINT8,float)){
    const UINT8 PtrLetras[13][2]={"7","8","9","4","5","6","1","2","3",".","0","c"};
    UINT8 Ptr=0,Fmt[30]; 

    ModificadorVariable.ValorInicial=ValorInicial;
    ModificadorVariable.ValorActual=0.0;
    memset(&ModificadorVariable.String[0],0,15);
    ModificadorVariable.Ptr=0;
    ModificadorVariable.FuncionActualEjecucion=PtrFuncion;
    
    vDibujarImagenFondo(IMAGEN_FONDO_MENU);
    MyLCD.vLCDTFTDrawImage(0,0,WIDTH_TITULO,HEIGH_TITULO,LENGTH_TITULO,&Titulo[0]);
    vTextoJustificado(NombreVariable,5,234,4,JUST_CENTRADO,&ARIAL[0],2,ColorAzulMarino);
    
    MyLCD.vLCDTFTRectangle(22,122,217,148,1,ColorWhite);
    MyLCD.vLCDTFTRectangle(20,120,219,121,1,ColorGray);
    MyLCD.vLCDTFTRectangle(20,120,21,150,1,ColorGray);
    MyLCD.vLCDTFTRectangle(218,120,219,150,1,ColorGray);
    MyLCD.vLCDTFTRectangle(20,149,219,150,1,ColorBlack);
    sprintf((char *)&Fmt[0],"%f",ValorInicial);
    vTextoJustificado((const UINT8 *)&Fmt[0],20,219,128,JUST_CENTRADO,&ARIAL[0],2,ColorAzulMarino);
    
    // Dibuja pad Numerico:
    for(int k=209;k<289;k+=20){
        for(int j=0;j<240;j+=80){
            MyLCD.vLCDTFTDrawImage(j,k,WIDTH_TECLAS,HEIGH_TECLAS,LENGTH_TECLAS,&Teclas[0]);
            vTextoJustificado(&PtrLetras[Ptr++][0],j,j+79,k+3,JUST_CENTRADO,&ARIAL[0],2,ColorCian);
        }
    }
    vDibujarMenuInferior("Cancelar","Aceptar",BOTON_NORMAL);
    
    vSeteamosFuncionEjecutar(vEventosModificadorVariables);
}

void vEventosModificadorVariables(void){
    const UINT8 PtrLetras[12][2]={"7","8","9","4","5","6","1","2","3",".","0","c"};
    UINT8 PtrTecla;
    float Temp;

    if(kbhit_irq==1){
        kbhit_irq=0;
        kbhit_tratament=1;
        
        // Testea Pad Numerico.-
        PtrTecla=0;
        for(int k=209;k<289;k+=20){
            for(int j=0;j<240;j+=80){
                if((Coordenadas.x<(j+74)) && (Coordenadas.x>(j+5)) && (Coordenadas.y<(k+15)) && (Coordenadas.y>(k+5))){
                    vTextoJustificado(&PtrLetras[PtrTecla][0],j,j+79,k+3,JUST_CENTRADO,&ARIAL[0],2,ColorWhite);
                    wait_ms(300);
                    vTextoJustificado(&PtrLetras[PtrTecla][0],j,j+79,k+3,JUST_CENTRADO,&ARIAL[0],2,ColorCian);
                    // Borrar?
                    if(PtrTecla==11){
                        if(ModificadorVariable.Ptr!=0){
                            ModificadorVariable.Ptr--;
                            ModificadorVariable.String[ModificadorVariable.Ptr]='\0';
                        }
                    }else{
                        ModificadorVariable.String[ModificadorVariable.Ptr++]=((UINT8)PtrLetras[PtrTecla][0]);
                    }
                    MyLCD.vLCDTFTRectangle(22,122,217,148,1,ColorWhite);
                    vTextoJustificado((const UINT8 *)&ModificadorVariable.String[0],20,219,128,JUST_CENTRADO,&ARIAL[0],2,ColorAzulMarino);
                    kbhit_tratament=0;
                    return;
                }
                PtrTecla++;
            }
        }
        
        if(AREA_BTN_INF_DER()){
            vDibujarMenuInferior("Cancelar","Aceptar",BOTON_PRES_DER);
            wait_ms(300);
            Temp=atof((const char *)&ModificadorVariable.String[0]);
            (*ModificadorVariable.FuncionActualEjecucion)(MODIFICADOR_ACEPTAR,Temp);
           
        }
        if(AREA_BTN_INF_IZQ()){
            vDibujarMenuInferior("Cancelar","Aceptar",BOTON_PRES_IZQ);
            wait_ms(300);
            (*ModificadorVariable.FuncionActualEjecucion)(MODIFICADOR_CANCELAR,0.0);
        }
        kbhit_tratament=0;
    }
}
// ************************************************************************************************
void vTextoJustificado(const unsigned char *PtrTexto,unsigned short ExtremoIzq, unsigned short ExtremoDer, unsigned short y, unsigned char Just,const char (*Fuente)[5],unsigned char Alto, unsigned short Color){
    unsigned char x,NCaracteres;
    const unsigned char *Ptr;

    if(Just!=JUST_IZQ){
        for(Ptr=PtrTexto;*Ptr!='\0';Ptr++);
        NCaracteres=Ptr - PtrTexto;
    }
    switch(Just){
        case JUST_IZQ:
            x=ExtremoIzq+5;
        break;
        case JUST_DER:
            x=ExtremoDer-NCaracteres*(5*Alto+1)-4;
        break;
        case JUST_CENTRADO:
            x=((ExtremoIzq+ExtremoDer-NCaracteres*(5*Alto+1))/2);
        break;
    }
    MyLCD.vLCDTFTText(x,y,(const char *)PtrTexto,Fuente,Alto,Color);
}
/* ** Escribe mensaje en pantalla multilinea justificado ** */
void vEscribirMensaje(unsigned short YInicial,const unsigned char *Mensaje,const char (*Fuente)[5],unsigned char Just, unsigned short Color){
    char Texto[50],k,dy=0;
    
    while(*Mensaje!='\0'){
        k=0;
        do{
            Texto[k++]=*Mensaje++;
        }while(*Mensaje!='\0' && *Mensaje!='\n');
        if(*Mensaje=='\n') *Mensaje++;
        if(k<50){while(k<50){Texto[k++]='\0';}}
        vTextoJustificado((const unsigned char *)&Texto[0],0,239,YInicial+dy,Just,Fuente,1,Color);
        dy+=11;
    }
}
#endif