/*--------------------------------------------------------------------
 * FICHERO:  EFQL.c
 * OBJETIVO: Editar fuentes de letras de QL
 * AUTOR:    Pedro Reina
 * FECHA:    S.7.3.1998
 *------------------------------------------------------------------*/

/*--------------------------------------------------------------------
 * Ficheros de cabecera
 *------------------------------------------------------------------*/

#include <Olimpo.h>   /*  Versin 2.0  */
#include <string.h>   /*  strtok()     */

/*--------------------------------------------------------------------
 * Declaracin de funciones
 *------------------------------------------------------------------*/

void LeeConfig();

void Explica();
void ExplicaObjetivo();
void ExplicaManejo();
void ExplicaAutor();
void ExplicaTeclas();

void   Fichero();
void   LeeFuente();
void   GrabaFuente();
logico GrabaFuenteTextoC();

cadena NombreCompleto();
cadena EligeNombre();
int    ComparaCadena();
octeto PideFormato();
cadena PideNombre();
cadena PideDirectorio();
cadena PideMascara();
cadena PideExtension();

void     Edicion();
void     MuestraFuente();
contador PideNumero();
logico   PideDosNumeros();

void Opciones();

/*--------------------------------------------------------------------
 * Definicin de macros constantes
 *------------------------------------------------------------------*/

#define TAMANO_FUENTE 2306

#define TAM_CAR 9

#define LONG_DIRECTORIO  24
#define LONG_EXTENSION    3
#define LONG_NOMBRE      14
#define LONG_MASCARA      8

#define FORMATO_NATIVO (octeto)1
#define FORMATO_TEXTOC (octeto)2

#ifdef OLIMPO_QL
#define MARGEN_IZQ_GUIA  3
#define MARGEN_SUP_GUIA  1
#define SEPARACION_HZ   10
#define MARGEN_IZQ_CAR   0
#define MARGEN_SUP_CAR   1
#endif

#ifdef OLIMPO_PC
#define MARGEN_IZQ_GUIA  7
#define MARGEN_SUP_GUIA  8
#define SEPARACION_HZ   16
#define MARGEN_IZQ_CAR   2
#define MARGEN_SUP_CAR   3
#endif

/*--------------------------------------------------------------------
 * Variables globales
 *------------------------------------------------------------------*/

octeto Fuente[TAMANO_FUENTE];
logico HayQueMostrar = NO;
logico HayQueOrdenar = NO;

/*--------------------------------------------------------------------
 * Definicin de macros funciones
 *------------------------------------------------------------------*/

#define LimpiaZonaTrabajo()  Pan_Borra(NEGRO,4,0,21,79)
#define LimpiaZonaFichero()  Pan_Borra(NEGRO,11,0,21,79)

/*--------------------------------------------------------------------
 * MACRO:    Pos()
 * OBJETIVO: Calcular la posicin en que comienzan los datos de
 *           un carcter dentro de la fuente
 * ENTRADAS: El nmero de carcter
 * SALIDAS:  La posicin relativa al comienzo de la fuente
 *------------------------------------------------------------------*/
#define Pos(n)  (2+TAM_CAR*(n))

/*--------------------------------------------------------------------
 * Programa principal
 *------------------------------------------------------------------*/
void main (Narg, Arg)
int   Narg;
char *Arg[];
  {
  enum { SALIDA_ESC, SALIDA, EXPLICA, FICHERO, EDICION, OPCIONES };

  static cadena Principal[] = {">Salida", "E>xplica", ">Fichero",
                               ">Edicin", ">Opciones", NIL };
  cadena Nombre;
  entero Opcion=FICHERO;
  logico Sigue=SI;

  Pan_Define (PAN_GRAFICO);
  Prg_Presenta ( "Editor de fuentes QL", "1.1",
                 "Pedro Reina", "Marzo 1998" );

  if ( Pan_Modo() == PAN_TEXTO )
    { Usr_ErrorFatal ("Este ordenador no dispone de grficos"); }

  if ( Narg == 1 )
    {
    Nombre = Fch_Nombre ( "Efql","cnf");
    if ( Fch_Existe (Nombre) )
      { LeeConfig (Nombre); }
    }
  else
    {
    Nombre = Cad_Duplica ( Arg[1] );
    LeeConfig (Nombre);
    }
  Cad_Destruye (Nombre);

  Cdr_Caja (CDR_SIMPLE,1,0,3,79,NEGRO,VERDE);

  Fuente[0] = 0;
  Fuente[1] = 255;

  while ( Sigue )
    {
    Opcion = Men_Horizontal (2,2,77,Principal,Opcion);
    switch ( Opcion )
      {
      case SALIDA_ESC:
      case SALIDA:
           if ( Usr_Consulta ("Quieres terminar el programa?") )
             { Sigue = NO; }
           Opcion = SALIDA;
           break;
      case EXPLICA:       Explica();       break;
      case FICHERO:       Fichero();       break;
      case EDICION:       Edicion();
                          Cdr_Caja (CDR_SIMPLE,1,0,3,79,NEGRO,VERDE);
                          break;
      case OPCIONES:      Opciones();      break;
      }
    LimpiaZonaTrabajo();
    }

  Pan_Cierra();
  }

/*--------------------------------------------------------------------
 * Definicin de funciones
 *------------------------------------------------------------------*/

/*--------------------------------------------------------------------
 * FUNCION:  LeeConfig()
 * OBJETIVO: Leer el fichero de configuracion
 *------------------------------------------------------------------*/
void LeeConfig (Nombre)
cadena Nombre;
  {
  config    Config;
  cadena    Linea, Informe, Error;
  contador  Tipo;
  char     *Etiqueta, *Aux, NumeroLinea[80];

  Informe = "Leyendo configuracin";
  Usr_Informa (Informe);

  if ( Config = Cnf_Abre (Nombre) )
    {
    while ( Linea = Cnf_Lee (Config) )
      {
      if ( Etiqueta = strtok (Linea, " ") )
        {

        if ( Cad_Igual (Etiqueta,"Sonido") )
          {
          if ( Aux = strtok (NULL, " ") )
            {
            if ( toupper(Aux[0]) == 'S' ) { Son_Enciende(); }
            else                          { Son_Apaga(); }
            }
          }

        else if ( Cad_Igual (Etiqueta,"Mostrar") )
          {
          if ( Aux = strtok (NULL, " ") )
            { HayQueMostrar = toupper(Aux[0]) == 'S'; }
          }

        else if ( Cad_Igual (Etiqueta,"Ordenar") )
          {
          if ( Aux = strtok (NULL, " ") )
            { HayQueOrdenar = toupper(Aux[0]) == 'S'; }
          }

        else
          {
          Error = Cad_Crea (80);
          sprintf (NumeroLinea,
            "Opcin no reconocida en la lnea %d del fichero ",
            Cnf_Linea (Config));
          Error = Cad_Une (NumeroLinea, Nombre, CAD_FIN);
          Usr_Avisa (Error);
          Cad_Destruye (Error);
          Usr_Informa (Informe);
          }

        } /* Fin if Etiqueta */
      Cad_Destruye (Linea);
      } /* Fin while Linea */
    } /* Fin if Cnf_Abre() */
  }

/*--------------------------------------------------------------------
 * FUNCION:  Explica()
 * OBJETIVO: Dirigir las explicaciones
 *------------------------------------------------------------------*/
void Explica()
  {
  enum { SALIDA_ESC, OBJETIVO, MANEJO, AUTOR, TECLAS };
  static octeto MaxOpcion = 4;

  static cadena MenuExplica[] = { ">Objetivo del programa",
                                  ">Manejo de las opciones",
                                  ">Contactar con el autor",
                                  ">Teclas PC y teclas QL",
                                  NIL };

  static cadena Presentacion[] = {
    "Puedes pedir explicacin sobre diferentes aspectos",
    "de este programa. Elige el que desees y pulsa ESC",
    "cuando hayas terminado.",
    NIL };

  logico Sigue = SI;
  entero Opcion = 1, i;

  while ( Sigue )
    {
    LimpiaZonaTrabajo();
    Pan_Color (NEGRO,BLANCO);
    for ( i=0 ; Presentacion[i] ; i++ )
      { Pan_PonTexto (6+i,15,Presentacion[i]); }

    Opcion = Men_Vertical (11,29,14,52,MenuExplica,Opcion);
    LimpiaZonaTrabajo();
    switch ( Opcion )
      {
      case SALIDA_ESC:  Sigue = NO;         break;
      case OBJETIVO:    ExplicaObjetivo();  break;
      case MANEJO:      ExplicaManejo();    break;
      case AUTOR:       ExplicaAutor();     break;
      case TECLAS:      ExplicaTeclas();    break;
      }
    if ( Opcion )  { Usr_PulsaUnaTecla(""); }
    Opcion++;
    if ( Opcion > MaxOpcion )  { Opcion = 1; }
    }
  }

/*--------------------------------------------------------------------
 * FUNCION:  ExplicaObjetivo()
 * OBJETIVO: Explicar el objetivo del programa
 *------------------------------------------------------------------*/
void ExplicaObjetivo()
  {
  static cadena Mensaje[] = {
      "Este programa permite editar fuentes de letras para usar con un QL.",
      "Las fuentes deben contener los 256 caracteres, aunque el QL admite",
      "el uso de fuentes parciales.",
      "",
      "Para usar una fuente en formato nativo creada con este programa",
      "se pueden usar estas lneas en SuperBASIC:",
      "",
      "100 Base = RESPR (2306)",
      "110 LBYTES FLP1_Fuente_qls, Base",
      "120 CHAR_USE #1, Base, 0",
      "",
      "Naturalmente, adaptando los nombres a cada necesidad.",
      "",
      "Y para usar la fuente en formato C hay que usar la funcin del",
      "compilador C68 sd_fount().",
      NIL };

  octeto i;

  Pan_Color (NEGRO,BLANCO);
  for ( i=0 ; Mensaje[i] ; i++ )
    { Pan_PonTexto (6+i,6,Mensaje[i]); }
  }

/*--------------------------------------------------------------------
 * FUNCION:  ExplicaManejo()
 * OBJETIVO: Explicar cmo se maneja el programa
 *------------------------------------------------------------------*/
void ExplicaManejo()
  {
  static cadena Mensaje[] = {
    "La opcin Fichero admite leer una fuente y grabarla con dos formatos",
    "distintos: el nativo del QL y en forma de texto vlido para usarlo",
    "en un programa en C.",
    "",
    "La opcin Edicin permite modificar la fuente. Con Carcter se accede",
    "a la forma de un carcter. Con Fuente se pueden ver todos los caracteres",
    "que forman la fuente. Con Copiar se copia un carcter sobre otro. Con",
    "Aadir se aaden los puntos de un caracter sobre los de otro. Con Borrar",
    "se borra la fuente en memoria completa. Al terminar de hacer cambios en",
    "en una fuente, hay que grabarla.",
    "",
    "En Opciones se pueden definir tres cosas: si el sonido est encendido",
    "o apagado, si el juego completo de caracteres debe estar siempre",
    "visible y actualizado y si se desea ver por orden alfabtico los",
    "ficheros cuando se va a leer uno.",
      NIL };

  octeto i;

  Pan_Color (NEGRO,BLANCO);
  for ( i=0 ; Mensaje[i] ; i++ )
    { Pan_PonTexto (5+i,4,Mensaje[i]); }
  }

/*--------------------------------------------------------------------
 * FUNCION:  ExplicaAutor()
 * OBJETIVO: Explicar quin es el autor y cmo contactar con l
 *------------------------------------------------------------------*/
void ExplicaAutor()
  {
  static cadena Mensaje[] = {
    "Este programa es de Dominio Pblico. Lo puedes usar, distribuir",
    "y modificar como desees.",
    "",
    "Ha sido escrito en C usando el sistema de programacin Olimpo;",
    "si no dispones de la versin 2.0 de Olimpo, puedes cargarla",
    "directamente desde mi sede web o pedrmela si no dispones de",
    "acceso a Internet.",
    "",
    "Si tienes cualquier duda o consulta, cuntamela e intentar ayudarte.",
    "",
    "Mis datos:",
    "",
    "Pedro Reina",
    "c/ Marquesa de Argeso, 4      Telfono: 91 565 17 59",
    "28019 Madrid                   Correo electrnico: pedro@anit.es",
    "Espaa                         Web: www.anit.es/pedro",
    NIL };

  octeto i;

  Pan_Color (NEGRO,BLANCO);
  for ( i=0 ; Mensaje[i] ; i++ )
    { Pan_PonTexto (5+i,5,Mensaje[i]); }
  }

/*--------------------------------------------------------------------
 * FUNCION:  ExplicaTeclas()
 * OBJETIVO: Explicar las teclas que son distintas en QL y en PC
 *------------------------------------------------------------------*/
void ExplicaTeclas()
  {
  static cadena Mensaje[] = {
      "El QL y el PC tienen distintos teclados y algunas teclas",
      "no tienen correspondiente directo.",
      "",
      "Este programa asigna a ciertas combinaciones de teclas del QL",
      "la funcin de algunas teclas del PC. sta es la relacin:",
      "",
      "         Tecla PC        Equivalente QL",
      "         --------        --------------",
      "",
      "         Inicio          Alt-Izquierda",
      "         Fin             Alt-Derecha",
      "         RePag           Alt-Arriba",
      "         AvPag           Alt-Abajo",
      "         Insert          Maysculas-Fijamaysculas",
      "         Supr            Ctrl-Derecha",
      "         Retroceso       Ctrl-Izquierda",
       NIL };

  octeto i;

  Pan_Color (NEGRO,BLANCO);
  for ( i=0 ; Mensaje[i] ; i++ )
    { Pan_PonTexto (5+i,9,Mensaje[i]); }
  }

/*--------------------------------------------------------------------
 * FUNCION:  Fichero()
 * OBJETIVO: Presentar y manejar las opciones de manejo de ficheros
 * ENTRADAS: Ninguna
 * SALIDAS:  La fuente se puede modificar
 *------------------------------------------------------------------*/
void Fichero()
  {
  enum { SALIDA_ESC, LEER, GRABAR, DIRECTORIO, MASCARA, EXTENSION };
  static cadena MenuFich[] = {">Leer", ">Grabar", ">Directorio",
                              ">Mscara", ">Extensin", NIL };

  static char Directorio[LONG_DIRECTORIO+1] = "";
  static char Nombre[LONG_NOMBRE+1]         = "";
  static char Mascara[LONG_MASCARA+1]       = "*";
  static char Extension[LONG_EXTENSION+1]   = "qls";

  cadena Aux;
  region Region;
  octeto Formato;
  entero Opcion = LEER;
  logico Sigue = SI, Refresca = SI;

  if ( Region = Reg_Crea (4,20,10,61) )
    {
    Reg_Borde (Region,CDR_SIMPLE,NEGRO,VERDE);
    Reg_Color (Region,NEGRO,VERDE);
    while ( Sigue )
      {
      if ( Refresca )
        {
        Pan_Borra (NEGRO,Reg_FilSup(Region)+1, Reg_ColIzq(Region)+15,
                         Reg_FilInf(Region)-1, Reg_ColDer(Region)-1);
        Reg_PonTexto (Region,3,15,Directorio);
        Reg_PonTexto (Region,4,15,Mascara);
        Reg_PonTexto (Region,5,15,Extension);
        Refresca = NO;
        }

      Opcion = Men_Vertical (Reg_FilSup(Region)+1, Reg_ColIzq(Region)+1,
                             Reg_FilInf(Region)-1, Reg_ColIzq(Region)+14,
                             MenuFich, Opcion);
      switch ( Opcion )
        {
        case SALIDA_ESC:  Sigue = NO;      break;

        case LEER:        Aux = EligeNombre(Directorio,Mascara,Extension);
                          if ( Tec_Ultima() == TEC_ENTER )
                            {
                            if ( Cad_Longitud(Aux) > LONG_NOMBRE )
                              { Aux[LONG_NOMBRE] = NULO; }
                            Cad_Copia (Nombre,Aux);
                            LeeFuente (Directorio,Nombre,Extension);
                            }
                          Cad_Destruye (Aux);
                          break;

        case GRABAR:      if ( Formato = PideFormato() )
                            {
                            Aux = PideNombre(Nombre);
                            if ( Tec_Ultima() != TEC_ESC )
                              {
                              Cad_Copia (Nombre,Aux);
                              GrabaFuente (Directorio,Nombre,Extension,Formato);
                              }
                            Cad_Destruye (Aux);
                            }
                          break;

        case DIRECTORIO:  Aux = PideDirectorio(Directorio);
                          if ( Tec_Ultima() != TEC_ESC )
                            {
                            Cad_Copia (Directorio,Aux);
                            Refresca = SI;
                            }
                          Cad_Destruye (Aux);
                          break;

        case MASCARA:     Aux = PideMascara(Mascara);
                          if ( Tec_Ultima() != TEC_ESC )
                            {
                            Cad_Copia (Mascara,Aux);
                            Refresca = SI;
                            }
                          Cad_Destruye (Aux);
                          break;

        case EXTENSION:   Aux = PideExtension(Extension);
                          if ( Tec_Ultima() != TEC_ESC )
                            {
                            Cad_Copia (Extension,Aux);
                            Refresca = SI;
                            }
                          Cad_Destruye (Aux);
                          break;
        }
      LimpiaZonaFichero();
      }
    }
  else  { Usr_Avisa ("Falta memoria"); }
  }

/*--------------------------------------------------------------------
 * FUNCION:  LeeFuente()
 * OBJETIVO: Leer una fuente
 * ENTRADAS: Directorio, nombre y extensin del fichero con la fuente
 * SALIDAS:  La variable Fuente puede quedar modificada
 *------------------------------------------------------------------*/
void LeeFuente (Dir,Nom,Ext)
cadena Dir,Nom,Ext;
  {
  fichero Fichero;
  cadena  Completo;
  logico  TodoBien=NO;
  octeto  Aux[2];

  Completo = NombreCompleto(Dir,Nom,Ext);

  if ( Fichero = Fch_AbreLeer (Completo, FCH_BINARIO) )
    {
    Usr_Informa ("Leyendo fuente");
    if ( Fch_LeeOcteto (Fichero, Aux, 2) &&
         Aux[0] == 0 && Aux[1] == 255 &&
         Fch_ColocaFinal (Fichero) &&
         Fch_Posicion (Fichero) == TAMANO_FUENTE &&
         Fch_Coloca (Fichero,0) &&
         Fch_LeeOcteto (Fichero, Fuente, TAMANO_FUENTE) )
      { TodoBien = SI; }

    Fch_Cierra (Fichero);
    if ( TodoBien )
      { Usr_PulsaUnaTecla ("Fuente leda"); }
    else
      { Usr_Avisa ("El fichero no tiene formato correcto"); }
    }

  Cad_Destruye (Completo);
  }

/*--------------------------------------------------------------------
 * FUNCION:  GrabaFuente()
 * OBJETIVO: Grabar una fuente
 * ENTRADAS: Directorio, nombre y extensin del fichero donde dejar
 *           la fuente y el formato
 * SALIDAS:  Ninguna
 *------------------------------------------------------------------*/
void GrabaFuente (Dir,Nom,Ext,Formato)
cadena Dir,Nom,Ext;
octeto Formato;
  {
  static cadena Mensaje = "Grabando fuente";
  fichero Fichero;
  cadena  Completo;
  logico  TodoBien;

  if ( Formato == FORMATO_NATIVO )
    {
    Completo = NombreCompleto(Dir,Nom,Ext);
    if ( Fichero = Fch_AbreGrabar (Completo, FCH_BINARIO) )
      {
      Usr_Informa (Mensaje);
      TodoBien = Fch_EscribeOcteto (Fichero, Fuente, TAMANO_FUENTE);
      }
    }
  else
    {
    Completo = NombreCompleto(Dir,Nom,"c");
    if ( Fichero = Fch_AbreGrabar (Completo, FCH_TEXTO) )
      {
      Usr_Informa (Mensaje);
      TodoBien = GrabaFuenteTextoC (Fichero, Fuente);
      }
    }

  if ( Fichero )
    {
    Fch_Cierra (Fichero);
    if ( TodoBien )
      { Usr_PulsaUnaTecla ("Fuente grabada"); }
    else
      { Usr_Avisa ("La fuente no se ha podido grabar"); }
    }

  Cad_Destruye (Completo);
  }

/*--------------------------------------------------------------------
 * FUNCION:  GrabaFuenteTextoC()
 * OBJETIVO: Grabar una fuente como texto C
 * ENTRADAS: Un fichero y la direccin donde comienza la fuente
 * SALIDAS:  Lgica, que indica si todo ha ido bien
 *------------------------------------------------------------------*/
logico GrabaFuenteTextoC (Fichero,Fuente)
fichero Fichero;
memoria Fuente;
  {
  contador i=2, j, Num;
  caracter Linea[81], Aux[8];

  sprintf (Linea, "{ /* Cabecera     */  %d, %d,", Fuente[0], Fuente[1]);
  Fch_EscribeLinea (Fichero, Linea);

  for ( Num=0 ; Num<256 ; Num++ )
    {
    Cad_Copia (Linea, "  /* Carcter ");
    sprintf (Aux, "%3d */ ", Num);
    strcat (Linea, Aux);
    for ( j=0 ; j<TAM_CAR ; j++ )
      {
      if ( Num==255 && j==TAM_CAR-1 )
        { sprintf (Aux, "%3d", Fuente[i++]); }
      else
        { sprintf (Aux, "%3d, ", Fuente[i++]); }
      strcat (Linea, Aux);
      }
    Fch_EscribeLinea (Fichero, Linea);
    }

  return ( Fch_EscribeLinea (Fichero, "};") );
  }

/*--------------------------------------------------------------------
 * FUNCION:  NombreCompleto()
 * OBJETIVO: Devolver el nombre completo de un fichero
 * ENTRADAS: Directorio, nombre y extensin del fichero
 * SALIDAS:  Una cadena con el nombre completo
 * NOTA:     La cadena hay que destruirla cuando no sea necesaria
 *------------------------------------------------------------------*/
cadena NombreCompleto (Dir,Nom,Ext)
cadena Dir,Nom,Ext;
  {
  cadena Respuesta, Aux;

  Aux = Fch_Nombre (Nom,Ext);
  Respuesta = Cad_Une (Dir,Aux,CAD_FIN);
  Cad_Destruye (Aux);

  return ( Respuesta );
  }

/*--------------------------------------------------------------------
 * FUNCION:  EligeNombre()
 * OBJETIVO: Elegir un nombre de fichero de entre los posibles
 * ENTRADAS: Directorio, mscara y extensin del fichero
 * SALIDAS:  Un nombre, sin directorio ni extensin
 * NOTA:     El nombre hay que destruirlo cuando no sea necesario
 *------------------------------------------------------------------*/
cadena EligeNombre (Dir,Mas,Ext)
cadena Dir,Mas,Ext;
  {
  cadena   Respuesta, Completo, Mensaje;
  lista    Posible;
  entero   Elegido;
  region   Region;
  menu     Eleccion;
  caracter Aux[81];
  octeto   i;
  logico   Visto = NO;

  Region = Reg_Crea (11,30,21,50);
  Reg_Borde (Region, CDR_SIMPLE, NEGRO, VERDE);
  Completo = NombreCompleto(Dir,Mas,Ext);
  Usr_Informa ("Buscando ficheros");
  if ( Posible = Fch_ListaNombre (Completo) )
    {
    if ( HayQueOrdenar )
      { Posible = Lis_Ordena (Posible, ComparaCadena); }
    Eleccion = Men_Crea (MEN_VERTICAL,
                         Reg_FilSup(Region)+1, Reg_ColIzq(Region)+1,
                         Reg_FilInf(Region)-1, Reg_ColDer(Region)-1,
                         Lis_Total(Posible), MEN_LISTA, (memoria)Posible);
    if ( Elegido = Men_Ejecuta (Eleccion,(entero)1,
                   "Elige uno de los ficheros") )
      {
      Men_Texto (Eleccion, Elegido, Aux);
      for ( i=Cad_Longitud(Aux)-1 ; i && !Visto ; i-- )
        {
        if ( Aux[i] == Fch_Separador() )
          {
          Aux[i] = NULO;
          Visto = SI;
          }
        }
      Respuesta = Cad_Duplica (Aux);
      }
    else  { Respuesta = Cad_Duplica (""); }

    Lis_Destruye (Posible);
    Men_Destruye (Eleccion);
    }

  else
    {
    Mensaje = Cad_Une ("No se encontrado ningn fichero ","\"",Completo,
                       "\"", CAD_FIN);
    Usr_PulsaUnaTecla (Mensaje);
    Cad_Destruye (Mensaje);
    Respuesta = Cad_Duplica ("");
    }

  Reg_Destruye (Region);
  Cad_Destruye (Completo);

  return ( Respuesta );
  }

/*--------------------------------------------------------------------
 * FUNCION:  ComparaCadena()
 * OBJETIVO: Comparar dos cadenas
 * ENTRADAS: Los punteros a las dos cadenas
 * SALIDAS:  Un int que indica qu cadena es menor
 *------------------------------------------------------------------*/
int ComparaCadena (Cad1,Cad2)
cadena *Cad1, *Cad2;
  {
  return ( Cad_Compara (*Cad1,*Cad2) );
  }

/*--------------------------------------------------------------------
 * FUNCION:  PideFormato()
 * OBJETIVO: Pedir al usuario el formato en que grabar una fuente
 * ENTRADAS: Ninguna
 * SALIDAS:  El formato, o 0
 *------------------------------------------------------------------*/
octeto PideFormato()
  {
  static cadena MenuFormato[] = {">Nativo", ">Texto C", NIL };
  entero Opcion = 1;
  region Region;
  octeto Respuesta=0;

  if ( Region = Reg_Crea (11,20,17,33) )
    {
    Reg_Borde (Region,CDR_SIMPLE,NEGRO,VERDE);
    Pan_Color (NEGRO, VERDE);
    Reg_TextoCentrado (Region,"Formato:",1);
    Opcion = Men_Vertical (Reg_FilSup(Region)+3, Reg_ColIzq(Region)+2,
                           Reg_FilInf(Region)-1, Reg_ColDer(Region)-1,
                           MenuFormato, Opcion);
    switch ( Opcion )
      {
      case 1: Respuesta = FORMATO_NATIVO;  break;
      case 2: Respuesta = FORMATO_TEXTOC;  break;
      }
    Reg_Destruye (Region);
    }
  else  { Usr_Avisa ("Falta memoria"); }

  return ( Respuesta );
  }

/*--------------------------------------------------------------------
 * FUNCION:  PideNombre()
 * OBJETIVO: Pedir al usuario un nombre
 * ENTRADAS: El nombre propuesto
 * SALIDAS:  El nuevo nombre
 *------------------------------------------------------------------*/
cadena PideNombre (Nombre)
cadena Nombre;
  {
  region Region;
  cadena Respuesta;

  Region = Reg_Crea (11,34,17,61);
  Reg_Borde (Region,CDR_SIMPLE,NEGRO,VERDE);
  Pan_Color (NEGRO,VERDE);
  Reg_TextoCentrado (Region,"Escribe el nombre:",2);
  Respuesta = Usr_Texto (Nombre, LONG_NOMBRE,
                         Reg_FilSup(Region)+4,Reg_ColIzq(Region)+7,
                         ROJO, BLANCO);

  return ( Respuesta );
  }

/*--------------------------------------------------------------------
 * FUNCION:  PideDirectorio()
 * OBJETIVO: Pedir al usuario un directorio
 * ENTRADAS: El directorio propuesto
 * SALIDAS:  El nuevo directorio
 *------------------------------------------------------------------*/
cadena PideDirectorio (Dir)
cadena Dir;
  {
  region Region;
  cadena Respuesta;

  Region = Reg_Crea (11,22,17,59);
  Reg_Borde (Region,CDR_SIMPLE,NEGRO,VERDE);
  Pan_Color (NEGRO,VERDE);
  Reg_TextoCentrado (Region,"Escribe el directorio:",2);
  Respuesta = Usr_Texto (Dir, LONG_DIRECTORIO,
                         Reg_FilSup(Region)+4,Reg_ColIzq(Region)+7,
                         ROJO, BLANCO);

  return ( Respuesta );
  }

/*--------------------------------------------------------------------
 * FUNCION:  PideMascara()
 * OBJETIVO: Pedir al usuario una mscara
 * ENTRADAS: La mscara propuesta
 * SALIDAS:  La nueva mscara
 *------------------------------------------------------------------*/
cadena PideMascara (Mascara)
cadena Mascara;
  {
  region Region;
  cadena Respuesta;

  Region = Reg_Crea (11,22,17,59);
  Reg_Borde (Region,CDR_SIMPLE,NEGRO,VERDE);
  Pan_Color (NEGRO,VERDE);
  Reg_TextoCentrado (Region,"Escribe la mscara:",2);
  Respuesta = Usr_Texto (Mascara, LONG_MASCARA,
                         Reg_FilSup(Region)+4,Reg_ColIzq(Region)+14,
                         ROJO, BLANCO);

  return ( Respuesta );
  }

/*--------------------------------------------------------------------
 * FUNCION:  PideExtension()
 * OBJETIVO: Pedir al usuario una extensin
 * ENTRADAS: La extensin propuesta
 * SALIDAS:  La nueva extensin
 *------------------------------------------------------------------*/
cadena PideExtension (Extension)
cadena Extension;
  {
  region Region;
  cadena Respuesta;

  Region = Reg_Crea (11,22,17,59);
  Reg_Borde (Region,CDR_SIMPLE,NEGRO,VERDE);
  Pan_Color (NEGRO,VERDE);
  Reg_TextoCentrado (Region,"Escribe la extensin:",2);
  Respuesta = Usr_Texto (Extension, LONG_EXTENSION,
                         Reg_FilSup(Region)+4,Reg_ColIzq(Region)+16,
                         ROJO, BLANCO);

  return ( Respuesta );
  }

/*--------------------------------------------------------------------
 * FUNCION:  Edicion()
 * OBJETIVO: Manejar las opciones de edicin
 * ENTRADAS: Ninguna
 * SALIDAS:  La fuente puede modificarse
 *------------------------------------------------------------------*/
void Edicion()
  {
  enum { SALIDA_ESC, CARACTER, FUENTE, COPIAR, ANADIR, BORRAR };
  static cadena OpcEdicion[] = {">Carcter", ">Fuente", "Co>piar",
                                ">Aadir", ">Borrar" };

  static octeto Guia[] = {
  /* Nmero  0 */ 126,  66,  66,  66,  66,  66,  66,  66, 126,
  /* Nmero  1 */   8,  24,   8,   8,   8,   8,   8,   8,  28,
  /* Nmero  2 */ 126,   2,   2,   2, 126,  64,  64,  64, 126,
  /* Nmero  3 */ 126,   2,   2,   2,  62,   2,   2,   2, 126,
  /* Nmero  4 */  66,  66,  66,  66, 126,   2,   2,   2,   2,
  /* Nmero  5 */ 126,  64,  64,  64, 126,   2,   2,   2, 126,
  /* Nmero  6 */  64,  64,  64,  64, 126,  66,  66,  66, 126,
  /* Nmero  7 */ 126,   2,   2,   4,   4,   4,   4,   4,   4,
  /* Nmero  8 */ 126,  66,  66,  66, 126,  66,  66,  66, 126,
  /* Nmero  9 */ 126,  66,  66,  66, 126,   2,   2,   2, 126,
  /* Nmero 10 */  79, 201,  73,  73,  73,  73,  73,  73, 239,
  /* Nmero 11 */  68, 204,  68,  68,  68,  68,  68,  68, 238,
  /* Nmero 12 */  79, 193,  65,  65,  79,  72,  72,  72, 239,
  /* Nmero 13 */  79, 193,  65,  65,  71,  65,  65,  65, 239,
  /* Nmero 14 */  73, 201,  73,  73,  79,  65,  65,  65, 225,
  /* Nmero 15 */  79, 200,  72,  72,  79,  65,  65,  65, 239 };

  static contador Numero=0, Origen=0, Destino=0;

  entero  Opcion = CARACTER;
  menu    MenuEdicion;
  logico  Sigue = SI;
  region  Dialogo;
  zona    Uno, Todo;
  diblane Caracter;
  octeto  i;

  Pan_Borra (NEGRO,1,0,3,79);

  Caracter = Dbn_Crea ((entero)8,(entero)9);

  Dialogo = Reg_Crea (2,0,4,31);
  Reg_Borde (Dialogo, CDR_SIMPLE, NEGRO, ROJO);
  Reg_Color (Dialogo, NEGRO, VERDE);

  Cdr_Caja (CDR_SIMPLE, 5,0,21,31, NEGRO, ROJO);
  Uno = Zon_Crea (6,1,20,30);

  Cdr_Caja (CDR_SIMPLE, 2,32,21,79, NEGRO, ROJO);
  Pan_Color (NEGRO, VERDE);
  Todo = Zon_Crea (3,33,20,78);
  for ( i=0 ; i<16 ; i++ )
    {
    Mem_Copia (Dbn_Dato(Caracter), Guia + i*TAM_CAR, TAM_CAR);
    Dbn_Coloca (Caracter, Todo, MARGEN_IZQ_GUIA+2*i, MARGEN_SUP_GUIA,
                NEGRO, VERDE);
    Pan_PonEntero (5+i,33+MARGEN_IZQ_CAR,16*i,3);
    }

  MenuEdicion = Men_Crea (MEN_HORIZONTAL, 1,0,1,79, (entero)5, MEN_VECTOR,
                          (memoria) OpcEdicion);
  Men_Color (MenuEdicion, BLANCO, NEGRO, ROJO, BLANCO,
                          VERDE, VERDE, NEGRO, NEGRO);

  while ( Sigue )
    {
    if ( HayQueMostrar )
      { MuestraFuente (Todo, Caracter); }

    Opcion = Men_Ejecuta (MenuEdicion, Opcion, "Elige una de las opciones");
    switch ( Opcion )
      {
      case SALIDA_ESC: Sigue = NO; break;

      case CARACTER:   Numero = PideNumero (Dialogo, Numero);
                       if ( Tec_Ultima() != TEC_ESC )
                         {
                         Mem_Copia (Dbn_Dato(Caracter),
                                    Fuente + Pos(Numero), TAM_CAR);
                         Dbn_Edita (Caracter, Uno);
                         Mem_Copia (Fuente + Pos(Numero),
                                    Dbn_Dato(Caracter), TAM_CAR);
                         }
                       Zon_Borra (Uno, NEGRO);
                       Reg_LimpiaInterior (Dialogo, NEGRO);
                       break;

      case FUENTE:     MuestraFuente (Todo, Caracter);
                       Usr_PulsaUnaTecla ("As est la fuente ahora");
                       break;

      case COPIAR:     if ( PideDosNumeros (Dialogo, &Origen, &Destino) )
                         {
                         Mem_Copia (Fuente + Pos(Destino),
                                    Fuente + Pos(Origen), TAM_CAR);
                         Usr_PulsaUnaTecla ("Carcter copiado");
                         }
                       Reg_LimpiaInterior (Dialogo, NEGRO);
                       break;

      case ANADIR:     if ( PideDosNumeros (Dialogo, &Origen, &Destino) )
                         {
                         for ( i=0 ; i<TAM_CAR ; i++ )
                           {
                           *(Fuente + Pos(Destino) + i) |=
                             *(Fuente + Pos(Origen) + i);
                           }
                         Usr_PulsaUnaTecla ("Carcter aadido");
                         }
                       Reg_LimpiaInterior (Dialogo, NEGRO);
                       break;

      case BORRAR:     if ( Usr_Consulta (
                            "Quieres borrar la fuente completa?") )
                         {
                         Mem_Asigna (Fuente+2,0,TAMANO_FUENTE-2);
                         Usr_PulsaUnaTecla ("Fuente borrada");
                         }
                       break;
      }
    }

  Men_Destruye (MenuEdicion);
  Zon_Destruye (Uno);
  Zon_Destruye (Todo);
  Reg_Destruye (Dialogo);
  Dbn_Destruye (Caracter);
  }

/*--------------------------------------------------------------------
 * FUNCION:  MuestraFuente()
 * OBJETIVO: Mostrar todos los caracteres de la fuente
 * ENTRADAS: Una zona donde trabajar y un diblane para usarlo
 * SALIDAS:  Ninguna
 *------------------------------------------------------------------*/
void MuestraFuente (Zona, Car)
zona    Zona;
diblane Car;
  {
  contador i, j;

  Usr_Informa ("Mostrando fuente");
  for ( i=0 ; i<16 ; i++ )
    {
    for ( j=0 ; j<16 ; j++ )
      {
      Mem_Copia (Dbn_Dato(Car), Fuente + Pos(16*i + j), TAM_CAR);
      Dbn_Coloca (Car, Zona,
                  MARGEN_IZQ_GUIA+2*j, MARGEN_SUP_CAR+SEPARACION_HZ*(i+2),
                  NEGRO, BLANCO);
      }
    }
  }

/*--------------------------------------------------------------------
 * FUNCION:  PideNumero()
 * OBJETIVO: Pedir al usuario un nmero
 * ENTRADAS: Una regin para trabajar y el nmero propuesto
 * SALIDAS:  El nuevo nmero
 *------------------------------------------------------------------*/
contador PideNumero (Region, Numero)
region   Region;
contador Numero;
  {
  Reg_PonTexto (Region,1,10,"Nmero:");
  return ( Usr_Entero (Numero, 3, 0, 255,
                       Reg_FilSup(Region)+1,Reg_ColIzq(Region)+18,
                       ROJO, BLANCO) );
  }

/*--------------------------------------------------------------------
 * FUNCION:  PideDosNumeros()
 * OBJETIVO: Pedir al usuario dos nmeros
 * ENTRADAS: Una regin para trabajar y las direcciones de los nmeros
 * SALIDAS:  Lgica, que indica que el usuario ha dado los dos nmeros
 *------------------------------------------------------------------*/
logico PideDosNumeros (Region, Origen, Destino)
region    Region;
contador *Origen, *Destino;
  {
  logico Respuesta=NO;

  Reg_PonTexto (Region,1,3,"Origen:");
  *Origen = Usr_Entero (*Origen, 3, 0, 255,
                        Reg_FilSup(Region)+1,Reg_ColIzq(Region)+11,
                        ROJO, BLANCO);
  if ( Tec_Ultima() != TEC_ESC )
    {
    Reg_PonTexto (Region,1,17,"Destino:");
    *Destino = Usr_Entero (*Destino, 3, 0, 255,
                           Reg_FilSup(Region)+1,Reg_ColIzq(Region)+26,
                           ROJO, BLANCO);
    Respuesta = Tec_Ultima() != TEC_ESC;
    }

  return ( Respuesta );
  }

/*--------------------------------------------------------------------
 * FUNCION:  Opciones()
 * OBJETIVO: Seleccionar las opciones del programa
 * ENTRADAS: Ninguna
 * SALIDAS:  Las variables globales pueden modificarse
 *------------------------------------------------------------------*/
void Opciones()
  {
  enum { SALIDA_ESC, SONIDO, JUEGO, ORDEN };
  static cadena MenuOpc[] = {">Sonido", ">Juego", ">Orden", NIL };
  entero Opcion = SONIDO;
  logico Sigue = SI;
  region Region;

  if ( Region = Reg_Crea (4,59,8,79) )
    {
    Reg_Borde (Region,CDR_SIMPLE,NEGRO,VERDE);
    while ( Sigue )
      {
      Pan_Color (NEGRO, VERDE);
      Reg_Cursor (Region,1,10);
      if ( Son_Estado() )  { Pan_Texto ("Encendido"); }
      else                 { Pan_Texto ("Apagado  "); }

      Reg_Cursor (Region,2,10);
      if ( HayQueMostrar )  { Pan_Texto ("Visible"); }
      else                  { Pan_Texto ("Oculto "); }

      Reg_Cursor (Region,3,10);
      if ( HayQueOrdenar )  { Pan_Texto ("S"); }
      else                  { Pan_Texto ("No"); }

      Opcion = Men_Vertical (Reg_FilSup(Region)+1, Reg_ColIzq(Region)+1,
                             Reg_FilInf(Region)-1, Reg_ColIzq(Region)+9,
                             MenuOpc, Opcion);
      switch ( Opcion )
        {
        case SALIDA_ESC: Sigue = NO;                      break;
        case SONIDO:     Son_Cambia();                    break;
        case JUEGO:      HayQueMostrar = !HayQueMostrar;  break;
        case ORDEN:      HayQueOrdenar = !HayQueOrdenar;  break;
        }
      }
    Reg_Destruye (Region);
    }
  else  { Usr_Avisa ("Falta memoria"); }
  }
