/*
 * Display Characters
 * Test Program for Vector Font Library VFlib 2
 *
 *  Programmed by Hirotsugu KAKUGAWA, Hiroshima University
 *  E-Mail:  kakugawa@se.hiroshima-u.ac.jp
 *
 * Edition History
 *  30 Jan 1994  
 *   8 Mar 1994  Added -F and -o options
 *  21 May 1994  Bug fixed. (by Yosuke Koshino tykoshin@tomcat.iijnet.or.jp)
 *  14 Mar 1996  Support for non-JIS encodings.
 *               Added -p option.
 *               Will now display exactly one plane per page. (WL)
 *  29 Mar 1996  Improved GUI. 
 */


/* This file is part of VFlib
 *
 * Copyright (C) 1994,1995,1996 Hirotsugu KAKUGAWA.   All rights reserved.
 *
 * VFlib is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
 * to anyone for the consequences of using it or for whether it serves any
 * particular purpose or works at all, unless he says so in writing.  Refer
 * to the GNU General Public License for full details.
 *
 * Everyone is granted permission to copy, modify and redistribute
 * VFlib, but only under the conditions described in the GNU
 * General Public License.  A copy of this license is supposed to have been
 * given to you along with VFlib so you can know your rights and
 * responsibilities.  It should be in a file named COPYING.  Among other
 * things, the copyright notice and this notice must be preserved on all
 * copies. 
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include "../src/config.h"
#include "../src/VF.h"
#include "../src/VFenc.h"
#include "str.h"


#define CHAR_PER_LINE  16
#define LINE_PER_PAGE   6
#define CHAR_PER_PAGE  96

int CharPerLine, LinePerPage, CharPerPage;

#define W_XDOTS     50
#define W_YDOTS     50

int  XDots, YDots, XBytes;
int  Page;
char *Ent;  /* font name */
int  InitDeinit;

void InitWin(), ClearWin(), PutBitmap();
int   CCode2Jis(), CCode2Big5(), UserCmd(), PollUserCmd();

int (*codeconv)() = CCode2Jis;

void usage(void);


int
main(argc, argv)
  int  argc;
  char **argv;
{
  int     Fd, Code, OutlineTest;
  int     jiscode, cmd;
  char    *Vfcap, *Buff;
  long    *vfdata;

  Vfcap  = NULL;
  Ent    = "min";
  XDots  = W_XDOTS;
  YDots  = W_YDOTS;
  CharPerLine = CHAR_PER_LINE;
  LinePerPage = LINE_PER_PAGE;
  CharPerPage = CHAR_PER_PAGE;
  OutlineTest = 0;
  InitDeinit = 0;
  Page = 0;

  argv++;
  argc--;
  while (argc > 0){
    if (strcmp(argv[0], "-f") == 0){
      if (--argc == 0)
	usage();
      Ent = *(++argv);
    } else if (strcmp(argv[0], "-d") == 0){      
      if (--argc == 0)
	usage();
      XDots = YDots = atoi(*(++argv)); 
    } else if ((strcmp(argv[0], "-x") == 0) 
	       || (strcmp(argv[0], "-dx") == 0)){      
      if (--argc == 0)
	  usage();
	XDots = atoi(*(++argv)); 
    } else if ((strcmp(argv[0], "-y") == 0) 
	       || (strcmp(argv[0], "-dy") == 0)){      
      if (--argc == 0)
	usage();
      YDots = atoi(*(++argv)); 
    } else if (strcmp(argv[0], "-o") == 0){
      OutlineTest = 1;
    } else if (strcmp(argv[0], "-v") == 0){
      if (--argc == 0)
	usage();
      Vfcap = *(++argv);
    } else if (strcmp(argv[0], "-p") == 0){
      argv++;
      argc--;
      Page = atoi(argv[0]);
    } else if (strcmp(argv[0], "-z") == 0){
      InitDeinit = 1;
    } else {
      usage();
    }
    argc--;
    argv++;
  }

  if (VF_Init(Vfcap) < 0){
    printf("Initializing VFlib: FAIL\n");
    exit(1);
  }
  printf("Initializing VFlib: OK\n");

  if ((Fd = VF_OpenFont(Ent)) < 0){
    fprintf(stderr, "Open Error: %s\n", Ent);
    exit(-1);
  }
  printf("Opening font: OK\n");

  XBytes = (XDots+7)/8;
  if ((Buff = malloc(XBytes*YDots)) == NULL){
    fprintf(stderr, "malloc err\n");
    exit(0);
  }

  if (VFE_GetEncoding(Fd) == ENC_BIG5){
    CharPerLine = 10;
    LinePerPage = 16;
    CharPerPage = 157;
    codeconv = CCode2Big5;
  }

  Page *= CharPerPage;

  InitWin(XDots*CharPerLine, YDots*LinePerPage);
  for (;;){
    ClearWin();
    if (InitDeinit == 1){
      VF_Deinit();
      printf("Deinit VFlib\n");
      printf("Init VFlib\n");
      if (VF_Init(Vfcap) < 0){
	printf("Initializing VFlib: FAIL\n");
	exit(1);
      }
      if ((Fd = VF_OpenFont(Ent)) < 0){
	fprintf(stderr, "open error; %s\n", Ent);
	exit(-1);
      }
    }
    for (Code = 0; Code < CharPerPage; Code++){
      if (PollUserCmd() == 1)
	goto Loop;
      bzero(Buff, XBytes*YDots);
      jiscode = codeconv(Page+Code);
      if (OutlineTest == 0){
	VF_GetBitmap(jiscode, Fd, XDots, YDots, XBytes, 0, Buff);
      } else {  /* OR */
	if ((vfdata = VF_GetOutline(jiscode, Fd)) == NULL){
	  ;  /* printf("Failed to get outline : %04x\n", jiscode); */
	} else {
	  VF_DrawOutline(vfdata, Fd, XDots, YDots, XBytes, 0, Buff);
	  VF_FreeOutline(vfdata, Fd);
	}

      }
      PutBitmap(Buff, XDots, YDots, XBytes, 
		Code%CharPerLine, Code/CharPerLine);
    }

Loop:
    cmd = UserCmd();
    switch (cmd){
    case -1:
      if (Page > 0){
	Page = Page - CharPerPage;
      } else 
	goto Loop;
      break;
    case 0:
      goto Exit;
    case 1:
      Page = Page + CharPerPage;
      break;
    case 2:
      if (Buff != NULL)
	free(Buff);
      XBytes    = (XDots+7)/8;
      if ((Buff = malloc(XBytes*YDots)) == NULL){
	fprintf(stderr, "malloc err\n");
	exit(0);
      }
      break;
    } 
  }

Exit:
  VF_CloseFont(Fd);
  printf("Closing font: OK\n");
  VF_Deinit();

  return 0;
}

void usage(void)
{
  printf("ktest  - display characters.\n");
  printf("Usage ktest [options]\n");
  printf("Options: \n");
  printf(" -f FONT_ENTRY  : specify font entry name. %s\n",
	 "(`min' is default)");
  printf(" -d DOTS  : set character size. (same as '-x DOTS -y DOTS')\n");
  printf(" -x DOTS  : set character width. (default: 50)\n");
  printf(" -y DOTS  : set character height (default: 50).\n");
  printf(" -p PAGE  : select first page to display. (Default: 0)\n");
  printf(" -o       : use VF_Outline()/VF_DrawOutline() instead %s",
	 "of VF_GetBitmap().\n");
  printf(" -v       : set vfontcap file. (must be a absolute path)\n");
  printf("Mouse Left button (or 'b')   : go to previous page\n");
  printf("Mouse Middle button (or 'q') : exit\n");
  printf("Mouse Right button (or SPC)  : go to next page\n");
  exit(0);
}


int
CCode2Jis(ccode)
  int ccode;
{
  int hi, lo;
  
  hi = ccode/94 + 0x21;
  lo = ccode%94 + 0x21;
  return hi*0x100+lo;
}

int
CCode2Big5(ccode)
  int ccode;
{
  int hi, lo;

  hi = ccode/157 + 0xA1;
  lo = ccode%157;
  if (lo < 63)
    lo += 64;
  else
    lo += 98;
  return hi*0x100+lo;
}
  


/*------------------------*/
Display               *Disp;
Window                Win;
XEvent                xevent, *xev = NULL;
GC                    Gc;
XGCValues             GcVal;
XSetWindowAttributes  Att;
unsigned int          WinX, WinY, WinBorder, WinDepth;
char                  *DisplayName; 
char                  WindowName[256];


void
InitWin(x, y)
  int x, y;
{
  DisplayName = NULL;

  WinX = x; WinY = y;
  Disp = XOpenDisplay(DisplayName);
  if (Disp == NULL){
    fprintf(stderr, "Can't open display\n"); 
    exit(1);
  }
  Win = XCreateSimpleWindow(Disp, RootWindow(Disp, 0), 
			    0, 0, x, y, 2,
			    BlackPixel(Disp, 0), WhitePixel(Disp, 0));
  Gc     = XCreateGC(Disp, Win, 0, 0);
  Att.override_redirect = True;
  Att.backing_store     = Always;
  /*XChangeWindowAttributes(Disp, Win, CWOverrideRedirect, &Att);*/
  XChangeWindowAttributes(Disp, Win, CWBackingStore, &Att);
  XSelectInput(Disp, Win, KeyPressMask|ButtonPressMask|StructureNotifyMask);
  XMapWindow(Disp, Win);
  ClearWin();
  XFlush(Disp);
}

void
ClearWin()
{
  sprintf(WindowName, "VFlib Character Table: %s (%04x-%04x)",
	  Ent, codeconv(Page), codeconv(Page+CharPerPage-1));
  XStoreName(Disp, Win, WindowName);
  XFillRectangle(Disp, Win, Gc, 0, 0, WinX, WinY);
}

void
PutBitmap(s, xdots, ydots, yyy, x, y)
  unsigned char *s;
  int           xdots, ydots, yyy, x, y; 
{
  int     ix, iy, i;
  char    d, *xbitmap;
  Pixmap  pix;
  static unsigned char  
    tb1[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01},
    tb2[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
  unsigned long fg, bg;
  unsigned int depth;

  depth = DefaultDepth(Disp, DefaultScreen(Disp));
  fg = BlackPixel(Disp, DefaultScreen(Disp));
  bg = WhitePixel(Disp, DefaultScreen(Disp));

  if ((xbitmap = malloc(ydots*((xdots+7)/8))) == NULL){
    fprintf(stderr, "Malloc err\n");
    return;
  }
  bzero(xbitmap, ydots*((xdots+7)/8));

  for (iy = 0; iy < ydots; iy++)
    for (ix = 0; ix < (xdots+7)/8; ix++){
      d = 0;
      for (i = 0; i < 8; i++)
	if ((tb1[i] & s[ix+iy*yyy]) != 0)
	  d |= tb2[i];
      xbitmap[ix+iy*((xdots+7)/8)] = d;
    }
  pix = XCreatePixmapFromBitmapData(Disp, Win, xbitmap, xdots, ydots, 
				    fg, bg, depth);
  XCopyArea(Disp, pix, Win, Gc, 0, 0, xdots, ydots, x*xdots, y*ydots);
  XFreePixmap(Disp, pix);
  free(xbitmap);
}

int
UserCmd()
{
  int    x, y;
  char   str[10];
  KeySym k;

  for (;;){
    if (xev == NULL)
      XNextEvent(Disp, &xevent);
    xev = NULL; 
    switch(xevent.type){
    case ButtonPress:
      switch (xevent.xbutton.button){
      case 1:
	if (Page > 0)
	  return -1;
	break;
      case 2:
	return 0;
      case 3:
	return 1;
      }
      break;
    case ConfigureNotify:
      x = xevent.xconfigure.width;
      y = xevent.xconfigure.height;
      if ((WinX != x) || (y != WinY)){
	WinX = x;
	WinY = y;
	XDots = WinX / CharPerLine;
	YDots = WinY / LinePerPage;
	return 2;
      }
      break;
    case KeyPress:
      if (XLookupString(&xevent.xkey, str, 10, &k, NULL) == 1){
	switch (k){
	case XK_b:
	  if (Page > 0)
	    return -1;
	  break;
	case XK_space:
	  return 1;
	case XK_q:
	  return 0;
	}
	break;
      }
    default:
      break;
    }
  }
}

int
PollUserCmd()
{
  char   str[10];
  KeySym k;

  if (XCheckWindowEvent(Disp, Win, 
			(KeyPressMask|ButtonPressMask|ConfigureNotify), 
			&xevent) 
      == False)
    return 0;

  switch(xevent.type){
  case ButtonPress:
    switch (xevent.xbutton.button){
    case 1:
      if (Page == 0)
	return 0;
    case 3:
      xev = &xevent;
      return 1;
    }
    break;
  case ConfigureNotify:
    if    ((WinX != xevent.xconfigure.width)
	|| (WinY != xevent.xconfigure.height)){
      xev = &xevent;
      return 1;
    }
    break;    
  case KeyPress:
    if (XLookupString(&xevent.xkey, str, 10, &k, NULL) == 1){
      switch (k){
      case XK_b:
	if (Page == 0)
	  return 0;
      case XK_space:
	xev = &xevent;
	return 1;
      case XK_q:
	xev = &xevent;
	return 1;
      }
    break;
    }
  }
  xev = NULL;
  return 0;
}

/*EOF*/
