#include "H\General.H"
#include "H\Teclado.H"


/***********************************************************************
 * 							Definiciones
 ***********************************************************************/
typedef struct DPsB  { UInt16 x,y,w,h; } PsB;
Tecl 		*xtec=NULL;
MemHandle 	mtec;

Char 	LetraTecla		(UInt16,Boolean,Boolean)			ES2;
void 	PosDimBT		(UInt16,PsB*)						ES2;
void 	PonLetra		(Char,UInt16,UInt16,UInt16,UInt16)	ES2;
void 	PintaTec		(UInt16,UInt16,UInt16,UInt16,UInt16)ES2;
void 	PintaBoton		(UInt16,Boolean)					ES2;
void 	PintaTeclado	(UInt16,Boolean)					ES2;
void 	AgregaTexto		(Char)								ES2;
void 	BorraTexto		(void)								ES2;
Boolean EnPos			(UInt16,UInt16,UInt16)				ES2;
UInt16 	EnTeclado		(UInt16,UInt16)						ES2;
void 	OperaTeclado	(void)								ES2;
void 	FinTecladoX		(int,FormType*)						ES2;
void 	MemTeclado		(void)								ES2;

/***********************************************************************
 * 							Funciones
 ***********************************************************************/
// Rutinas de memoria --------------------------------------------------
void MemTeclado(void) {
	mtec=MemHandleNew(sizeof(Tecl));
	xtec=(Tecl *)MemHandleLock(mtec);
}
void FinalizaTeclado(void) {
  if (xtec!=NULL) { MemHandleUnlock(mtec); MemHandleFree(mtec); xtec=NULL; }
}
// Rutinas de conversión -----------------------------------------------
Char LetraTecla(UInt16 tp, Boolean alt, Boolean ace) {
Boolean ma,ac;
    if (alt) { if (xtec->cap) ma=!(xtec->alt); else ma=xtec->alt; } 
    else ma=false;
    if (ace) { ac=xtec->ace; } else ac=false;
	switch(tp) {
   	  case  1: return((ma)?'Q':'q'); break;
   	  case  2: return((ma)?'W':'w'); break;
   	  case  3: return((ma)?((ac)?chrCapital_E_Acute:'E'):((ac)?chrSmall_E_Acute:'e')); break;
   	  case  4: return((ma)?'R':'r'); break;
   	  case  5: return((ma)?'T':'t'); break;
   	  case  6: return((ma)?'Y':'y'); break;
   	  case  7: return((ma)?((ac)?chrCapital_U_Acute:'U'):((ac)?chrSmall_U_Acute:'u')); break;
   	  case  8: return((ma)?((ac)?chrCapital_I_Acute:'I'):((ac)?chrSmall_I_Acute:'i')); break;
   	  case  9: return((ma)?((ac)?chrCapital_O_Acute:'O'):((ac)?chrSmall_O_Acute:'o')); break;
   	  case 10: return((ma)?'P':'p'); break;
   	  case 11: return((ma)?((ac)?chrCapital_A_Acute:'A'):((ac)?chrSmall_A_Acute:'a')); break;
   	  case 12: return((ma)?'S':'s'); break;
   	  case 13: return((ma)?'D':'d'); break;
   	  case 14: return((ma)?'F':'f'); break;
   	  case 15: return((ma)?'G':'g'); break;
   	  case 16: return((ma)?'H':'h'); break;
   	  case 17: return((ma)?'J':'j'); break;
   	  case 18: return((ma)?'K':'k'); break;
   	  case 19: return((ma)?'L':'l'); break;
   	  case 20: return((ma)?chrCapital_N_Tilde:chrSmall_N_Tilde); break;
   	  case 22: return((ma)?'Z':'z'); break;
   	  case 23: return((ma)?'X':'x'); break;
   	  case 24: return((ma)?'C':'c'); break;
   	  case 25: return((ma)?'V':'v'); break;
   	  case 26: return((ma)?'B':'b'); break;
   	  case 27: return((ma)?'N':'n'); break;
   	  case 28: return((ma)?'M':'m'); break;
   	  case 32: return(' '); break;
   	  case 51: return('1'); break;
   	  case 52: return('2'); break;
   	  case 53: return('3'); break;
   	  case 54: return('4'); break;
   	  case 55: return('5'); break;
   	  case 56: return('6'); break;
   	  case 57: return('7'); break;
   	  case 58: return('8'); break;
   	  case 59: return('9'); break;
   	  case 60: return('0'); break;
   	  case 61: return('!'); break;
   	  case 62: return('@'); break;
   	  case 63: return('#'); break;
   	  case 64: return('$'); break;
   	  case 65: return('"'); break;
   	  case 66: return('_'); break;
   	  case 67: return('&'); break;
   	  case 68: return('?'); break;
   	  case 69: return('<'); break;
   	  case 70: return('>'); break;
   	  case 72: return('['); break;
   	  case 73: return(']'); break;
   	  case 74: return('('); break;
   	  case 75: return(')'); break;
   	  case 76: return(';'); break;
   	  case 77: return(':'); break;
   	  case 78: return(','); break;
   	  case 79: return('.'); break;
   	  case 81: return('%'); break;
   	  case 82: return('/'); break;
   	  case 83: return('*'); break;
   	  case 84: return(' '); break;
   	  case 85: return('-'); break;
   	  case 86: return('+'); break;
   	  case 87: return('='); break;
   	  case 29: return chrAcuteAccent; break;
	}
	return ' ';
}
// Rutinas de pintar ----------------------------------------------------
void PosDimBT(UInt16 tp, PsB *p) {
UInt16  x,y,w,h,s,wt;
    wt=xtec->wt; w=xtec->w+1; h=xtec->h; s=wt-(10*w)-3;
    switch(tp) {
    	case  1: case 51: x=0;        y=0; break;
    	case  2: case 52: x=w;        y=0; break;
    	case  3: case 53: x=(w*2);    y=0; break;
    	case  4: case 54: x=(w*3);    y=0; break;
    	case  5: case 55: x=(w*4);    y=0; break;
    	case  6: case 56: x=(w*5);    y=0; break;
    	case  7: case 57: x=(w*6);    y=0; break;
    	case  8: case 58: x=(w*7);    y=0; break;
    	case  9: case 59: x=(w*8);    y=0; break;
    	case 10: case 60: x=(w*9);    y=0; break;
    	case 11: case 61: x=s;        y=h; break;
    	case 12: case 62: x=s+w;      y=h; break;
    	case 13: case 63: x=s+(w*2);  y=h; break;
    	case 14: case 64: x=s+(w*3);  y=h; break;
    	case 15: case 65: x=s+(w*4);  y=h; break;
    	case 16: case 66: x=s+(w*5);  y=h; break;
    	case 17: case 67: x=s+(w*6);  y=h; break;
    	case 18: case 68: x=s+(w*7);  y=h; break;
    	case 19: case 69: x=s+(w*8);  y=h; break;
    	case 20: case 70: x=s+(w*9);  y=h; break;
    	case 21: case 71: x=0;        y=(2*h); break;
    	case 22: case 72: x=w;        y=(2*h); break;
    	case 23: case 73: x=(w*2);    y=(2*h); break;
    	case 24: case 74: x=(w*3);    y=(2*h); break;
    	case 25: case 75: x=(w*4);    y=(2*h); break;
    	case 26: case 76: x=(w*5);    y=(2*h); break;
    	case 27: case 77: x=(w*6);    y=(2*h); break;
    	case 28: case 78: x=(w*7);    y=(2*h); break;
    	case 29: case 79: x=(w*8);    y=(2*h); break;
    	case 30: case 80: x=(w*9);    y=(2*h); w=wt-(9*w)-3; break;
    	case 31: x=0;            y=(3*h); w=(2*w); break;
    	case 32: x=(2*w);        y=(3*h); w=wt-(4*w)-3; break;
    	case 33: x=wt-(2*w)-3;   y=(3*h); w=(2*w); break;
    	case 81: x=0;            y=(3*h); break;
    	case 82: x=w;            y=(3*h); break;
    	case 83: x=(w*2);        y=(3*h); break;
    	case 84: x=(w*3);        y=(3*h); w=wt-(6*w)-3; break;
    	case 85: x=wt-(w*3)-3;   y=(3*h); break;
    	case 86: x=wt-(w*2)-3;   y=(3*h); break;
    	case 87: x=wt-w-3;       y=(3*h); break;
    }
    p->x=x+xtec->x; p->y=y+xtec->y; p->w=w; p->h=h;
}
void PonLetra(Char l, UInt16 x, UInt16 y, UInt16 W, UInt16 H) {
UInt16 w,h;
    h=(UInt16)FntCharHeight()-2; w=(UInt16)FntCharWidth(l);
   	x+=((W-w)/2); y+=((H-h)/2); y-=1; 
   	WinSetTextColor(xtec->c5); WinDrawChar(l,x,y);
}
void PintaTec(UInt16 tp, UInt16 x, UInt16 y, UInt16 W, UInt16 H) {
    WinSetForeColor(xtec->c5);
    switch(tp) {
    	case 21:
    	case 71: x+=4;
    			 WinDrawLine(x,y+10,x+4,y+10);
    			 WinDrawLine(x+4,y+10,x+4,y+4);
    			 WinDrawLine(x+2,y+6,x+6,y+6);
    			 WinDrawLine(x+3,y+5,x+5,y+5);
    	         break;
        case 29:
    	case 79: x+=(W/2)-2; y+=(H/2);
    	         WinDrawLine(x,y,x+3,y-3);
    	         break;
    	case 30:
    	case 80: x+=3; y+=(H/2);
    	         WinDrawLine(x,y,x+9,y); WinDrawLine(x,y+1,x+9,y+1);
    	         x++; y--; WinDrawLine(x,y,x,y+3);
    	         x++; y--; WinDrawLine(x,y,x,y+5);
                 break;    	        
        case 31: x+=7; y+=7;
    	         WinDrawLine(x,y,x,y+4); WinDrawLine(x+5,y,x+5,y+4); 
    	         WinDrawLine(x,y,x+5,y); WinDrawLine(x,y+4,x+5,y+4);
                 WinDrawLine(x+1,y,x+1,y-3); WinDrawLine(x+4,y,x+4,y-3);
                 WinDrawLine(x+2,y-4,x+3,y-4);
    	         WinSetForeColor(xtec->c1);
    	         WinDrawLine(x+1,y+1,x+4,y+1);
    	         WinDrawLine(x+1,y+2,x+4,y+2);
    	         WinDrawLine(x+1,y+3,x+4,y+3);
    	         WinSetForeColor(xtec->c5);
    	         x+=8;
    	case 33: if (tp==33) { x+=(2*(xtec->w+1))-10; y+=7; }
    	         WinDrawLine(x,y,x+2,y); 
    	         WinDrawLine(x+2,y,x+2,y+4); 
    	         WinDrawLine(x+2,y+4,x+4,y+4); 
                 WinDrawLine(x+4,y+4,x+4,y); 
    	         WinDrawLine(x+4,y,x+6,y); 
    	         WinDrawLine(x+6,y,x+3,y-3); 
    	         WinDrawLine(x+3,y-3,x,y); 
                 break;
    }
}
void PintaBoton(UInt16 tp, Boolean ap) {
RectangleType  r;
PsB            p;
UInt16          x,y;
    if (tp==31 && xtec->cap) ap=true;
    if (tp==71) ap=true;
	PosDimBT(tp,&p); x=p.x; y=p.y; p.w--; p.h--;
    r.topLeft.x=x; r.topLeft.y=y; r.extent.x=p.w; r.extent.y=p.h;
    if (tp==21 || tp==71) WinSetBackColor(xtec->c2);
    else WinSetBackColor(xtec->c3); 
    WinEraseRectangle(&r,0);
    if (ap) { x++; y++; }
    switch(tp) { 
   	  case 21: 
   	  case 30: 
   	  case 31: 
   	  case 33: 
   	  case 71: 
   	  case 80: PintaTec(tp,x,y,p.w,p.h);  break;
      default: PonLetra(LetraTecla(tp,false,false),x,y,p.w,p.h); break;
    }
    if (ap) {
	    x--; y--;
	    WinSetForeColor(xtec->c0); WinDrawLine(x,       y,       x+p.w,   y);       
	                               WinDrawLine(x,       y,       x,       y+p.h);
	    WinSetForeColor(xtec->c3); WinDrawLine(x+1,     y+1,     x+p.w-1, y+1);     
	                               WinDrawLine(x+1,     y+1,     x+1,     y+p.h-1);
	    WinSetForeColor(xtec->c4); WinDrawLine(x+1,     y+p.h,   x+p.w,   y+p.h);       
	                               WinDrawLine(x+p.w,   y+p.h,   x+p.w,   y+1);
    }
    else {
	    WinSetForeColor(xtec->c0); WinDrawLine(x,       y,       x+p.w,   y);       
	                               WinDrawLine(x,       y,       x,       y+p.h);
	    WinSetForeColor(xtec->c4); WinDrawLine(x+1,     y+1,     x+p.w-1, y+1);     
	                               WinDrawLine(x+1,     y+1,     x+1,     y+p.h-1);
	    WinSetForeColor(xtec->c1); WinDrawLine(x+1,     y+p.h,   x+p.w,   y+p.h);       
	                               WinDrawLine(x+p.w,   y+p.h,   x+p.w,   y+1);
	    if (tp==21 || tp==71) WinSetForeColor(xtec->c3); else WinSetForeColor(xtec->c2); 
	                               WinDrawLine(x+2,     y+p.h-1, x+p.w-1, y+p.h-1); 
	                               WinDrawLine(x+p.w-1, y+p.h-1, x+p.w-1, y+2);
    }
}
void PintaTeclado(UInt16 tp, Boolean ap) {
UInt16 i,s;
    if (tp==0) {
        s=((xtec->esp)?50:0);
		for (i=1;i<11;i++) PintaBoton(i+s,   false);
		for (i=1;i<11;i++) PintaBoton(i+10+s,false);
		for (i=1;i<11;i++) PintaBoton(i+20+s,false);
		for (i=1;i<((xtec->esp)?8:4);i++) PintaBoton(i+30+s,false);
    }
    else { PintaBoton(tp,ap); if (ap) xtec->tec=tp; else xtec->tec=0; }
	WinSetBackColor(xtec->c4);
}
// Rutinas del teclado --------------------------------------------------
void AgregaTexto(Char c) {
Char Cx[1];
	Cx[0]=c; FldInsert(xtec->p,Cx,1);
}
void BorraTexto() {
UInt16 ini,fin,p;
   FldGetSelection(xtec->p,&ini,&fin);
   if (fin<=ini) {
     p=FldGetInsPtPosition(xtec->p);
     ini=p-1; fin=p;
   }
   FldDelete(xtec->p,ini,fin);
}
// Rutinas de control e inicialización ----------------------------------
void IniciaTeclado(UInt8 tp, FormType *f, Int16 id, Boolean init) {
RGBColorType   r;
RectangleType  rc;
Coord          cx,cy;
UInt16         h;
    if (init) MemTeclado();
    switch(PrefGen(1)) {
    	case  1: r.r=r.g=r.b=0;   xtec->c0=WinRGBToIndex(&r);
    			 xtec->c1=xtec->c2=xtec->c0;
    			 r.r=r.g=r.b=255; xtec->c4=WinRGBToIndex(&r);
    			 xtec->c3=xtec->c4;
    			 xtec->c5=xtec->c0;
    			 break;
    	default: r.r=r.g=r.b=0;   xtec->c0=WinRGBToIndex(&r);
    			 r.r=r.g=r.b=128; xtec->c1=WinRGBToIndex(&r);
    			 r.r=r.g=r.b=160; xtec->c2=WinRGBToIndex(&r);
    			 r.r=r.g=r.b=192; xtec->c3=WinRGBToIndex(&r);
    			 r.r=r.g=r.b=255; xtec->c4=WinRGBToIndex(&r);
    			 xtec->c5=xtec->c0;
    			 break;
    }
	xtec->tec=0; xtec->esp=false; xtec->alt=false; xtec->cap=false; 
	xtec->p=GetObjPtr(f,id);      xtec->ace=false; 
	FldSetInsPtPosition(xtec->p,FldGetTextLength(xtec->p));
	WinGetWindowExtent(&cx,&cy);
	xtec->wt=156; xtec->w=14; xtec->h=15;
	xtec->x=((tp==1)?3:1); 
	h=(15*4)+((tp==1)?4:1);
	xtec->y=cy-h;
	rc.topLeft.x=0;  rc.topLeft.y=xtec->y;
	rc.extent.x=cx;  rc.extent.y=h;
	WinSetBackColor(xtec->c3); WinEraseRectangle(&rc,0);
	if (tp==1) {
		WinSetForeColor(xtec->c0); WinDrawLine(  0,xtec->y,159,xtec->y); 
		                           WinDrawLine(  0,xtec->y,  0,159); 
		                           WinDrawLine(159,xtec->y,159,159); 
		                           WinDrawLine(  0,159,159,159);
		                           xtec->y++;
		WinSetForeColor(xtec->c4); WinDrawLine(  1,xtec->y,158,xtec->y);
		                           WinDrawLine(  1,xtec->y,  1,159); 
		                           WinDrawLine(158,xtec->y,158,159); 
		                           xtec->y++;
	}
	PintaTeclado(0,false);
	FrmSetFocus(f,FrmGetObjectIndex(f,id));
}
Boolean EnPos(UInt16 i, UInt16 x, UInt16 y) {
PsB p;
	PosDimBT(i,&p);
	return (x>=p.x && y>=p.y && x<=p.x+p.w && y<=p.y+p.h);
}
UInt16 EnTeclado(UInt16 x, UInt16 y) {
UInt16 i,s;
    s=((xtec->esp)?50:0);
	for (i=1;i<11;i++) if (EnPos(i+s,x,y))    return i+s;
	for (i=1;i<11;i++) if (EnPos(i+10+s,x,y)) return i+10+s;
	for (i=1;i<11;i++) if (EnPos(i+20+s,x,y)) return i+20+s;
	for (i=1;i<((xtec->esp)?8:4);i++) if (EnPos(i+30+s,x,y)) return i+30+s;
	return 0;
}
void OperaTeclado() {
	switch(xtec->tec) {
	  case 21: 
	  case 71: xtec->esp=!xtec->esp;
	           if (xtec->alt) xtec->alt=false;
	           PintaTeclado(0,false); xtec->tec=0; break;
   	  case 29: xtec->ace=!xtec->ace; 
   	           if (!xtec->ace) PintaTeclado(xtec->tec,false); break;
   	  case 30: 
   	  case 80: BorraTexto(); PintaTeclado(xtec->tec,false); break;
   	  case 31: xtec->cap=!xtec->cap; 
   	           if (!xtec->cap) PintaTeclado(xtec->tec,false); break;
   	  case 33: xtec->alt=!xtec->alt; 
   	           if (!xtec->alt) PintaTeclado(xtec->tec,false); break;
	  default: AgregaTexto(LetraTecla(xtec->tec,true,true));
	           PintaTeclado(xtec->tec,false); 
	           if (xtec->ace) { xtec->ace=false; PintaTeclado(29,false); }
	           if (xtec->alt) { xtec->alt=false; PintaTeclado(33,false); }
	           break;
	}
}
Boolean EventoTeclado(EventType* pEvent) {
Boolean	r=false;
UInt16  tec;
	switch (pEvent->eType) {
        case penDownEvent:
            tec=EnTeclado(pEvent->screenX,pEvent->screenY);
            if (tec!=0) { PintaTeclado(tec,true); r=true; }
            break; 
        case penUpEvent:
            tec=EnTeclado(pEvent->screenX,pEvent->screenY);
            if (tec!=0 && tec==xtec->tec) { OperaTeclado(); r=true; }
            else if (xtec->tec!=0) { PintaTeclado(xtec->tec,false); r=true; }
            break;
        case penMoveEvent:
            if (xtec->tec!=0) {
            	tec=EnTeclado(pEvent->screenX,pEvent->screenY);
            	if (tec!=xtec->tec)
            	    PintaTeclado(xtec->tec,false);
            	r=true;
            }
            break;
        default: break;
	}
	return r;
}

void IniTecladoX(FormType *f, Char *val, Int16 maxc, Char *t) {
Int16 i;
	MemTeclado();
	xtec->f=f; xtec->val=val; xtec->mc=maxc; StrCopy(xtec->tit,t);
	while(val[0]==' ') for (i=0;i<StrLen(val);i++) val[i]=val[i+1];
	FrmPopupForm(FTecladoX);
}

void FinTecladoX(int opc, FormType *ft) {
UInt16    m;
Char      *f;
MemHandle mh;
	if (xtec!=NULL) {
		if (opc==1) {
        	m=FldGetTextLength(GetObjPtr(ft,102));	
	        if (m>0) { 
				mh=FldGetTextHandle(GetObjPtr(ft,102)); 
				f=(Char *)MemHandleLock(mh); 
				StrCopy(xtec->val,f);
				MemHandleUnlock(mh);
	        }
        }
        if (StrLen(xtec->val)==0) StrCopy(xtec->val," ");
		FrmUpdateForm(FrmGetFormId(xtec->f),70);
	    FrmReturnToForm(0); FinalizaTeclado();
	}
}

Boolean TecladoX(EventType* pEvent) {
	switch (pEvent->eType) {
		case frmOpenEvent:
			FrmDrawForm(FrmGetActiveForm());
			FrmCopyTitle(FrmGetActiveForm(),xtec->tit);
			IniciaTeclado(1,FrmGetActiveForm(),102,false);
			FldInsert(xtec->p,xtec->val,StrLen(xtec->val));
			FldSetMaxChars(GetObjPtr(FrmGetActiveForm(),102),xtec->mc);
			FrmSetFocus(FrmGetActiveForm(),FrmGetObjectIndex(FrmGetActiveForm(),102));
			return true;
		case frmCloseEvent:
			FinTecladoX(0,FrmGetActiveForm());
			return true;
		case ctlSelectEvent:
		    switch(pEvent->data.ctlSelect.controlID) { 
		    case BAce: FinTecladoX(1,FrmGetActiveForm()); return true;
		    case BCan: FinTecladoX(0,FrmGetActiveForm()); return true;
		    }
		    break;
		default:  
			if (EventoTeclado(pEvent)) return true;
		    break;
	}
	return false;
}
