/*LINTLIBRARY*/

/*  @(#)sunview.c 1.7 90/04/10
 *
 *  SunView dependent graphics routines used by othello.
 *
 *  Original SunView version by Ed Falk - Sun Microsystems Inc.
 *
 *  Rewritten for independent use by
 *          Rich Burridge, Sun Microsystems, Australia
 *
 *  Copyright (c) Ed Falk & Rich Burridge - Sun Microsystems.
 *                                          All rights reserved.
 *
 *  Permission is given to distribute these sources, as long as the
 *  introductory messages are not removed, and no monies are exchanged.
 *
 *  No responsibility is taken for any errors or inaccuracies inherent
 *  either to the comments or the code of this program, but if reported
 *  to me, then an attempt will be made to fix them.
 */

#include "color.h"
#include "othello.h"
#include "extern.h"
#include "images.h"
#include <suntool/sunview.h>
#include <suntool/canvas.h>

#define  CURSOR_SET          (void) cursor_set
#define  ICON_SET            (void) icon_set
#define  MENU_SET            (void) menu_set
#define  PW_LOCK             (void) pw_lock
#define  PW_ROP              (void) pw_rop
#define  PW_SETCMSNAME       (void) pw_setcmsname
#define  PW_STENCIL          (void) pw_stencil
#define  PW_PUTCOLORMAP      (void) pw_putcolormap
#define  PW_REVERSEVIDEO     (void) pw_reversevideo
#define  PW_TTEXT            (void) pw_ttext
#define  PW_UNLOCK           (void) pw_unlock
#define  PW_VECTOR           (void) pw_vector
#define  PW_WRITEBACKGROUND  (void) pw_writebackground
#define  WINDOW_DONE         (void) window_done
#define  WINDOW_SET          (void) window_set

#define  NORMALFONT          "/usr/lib/fonts/fixedwidthfonts/screen.r.12"
#define  BOLDFONT            "/usr/lib/fonts/fixedwidthfonts/screen.b.12"

mpr_static(button_stencil_pr, 64, 64, 1, button_stencil_image) ;
mpr_static(button_invert_pr,  64, 64, 1, button_invert_image) ;
mpr_static(button_normal_pr,  64, 64, 1, button_normal_image) ;
mpr_static(cycle_glyph_pr,    64, 64, 1, cycle_glyph_image) ;
mpr_static(cycle_stencil_pr,  64, 64, 1, cycle_stencil_image) ;
mpr_static(cycle_linvert_pr,  64, 64, 1, cycle_linvert_image) ;
mpr_static(cycle_rinvert_pr,  64, 64, 1, cycle_rinvert_image) ;
mpr_static(icon_pr,           64, 64, 1, icon_image) ;
mpr_static(cicon_pr,          64, 64, 8, cicon_image) ;
mpr_static(white_icon_pr,     64, 64, 1, white_image) ;
mpr_static(black_icon_pr,     64, 64, 1, black_image) ;

mpr_static(hglass_pr,         16, 16, 1, hglass_image) ;
mpr_static(nocur_pr,          16, 16, 1, nocur_image) ;

Canvas canvas ;
Cursor cursor[MAXCURSORS] ;
Event *cur_event ;
Frame frame ;
Icon othello_icon ;
Menu menus[MAXMENUS] ;
Pixfont *font[MAXFONTS] ;
Pixrect *images[MAXIMAGES] ;
Pixwin *cpw ;

void pw_batch() ;
int opvals[3] ;         /* Pixrect rasterop values. */


batch(state)            /* Turn graphics batching on or off. */
enum bltype state ;
{
  switch (state)
    {
      case IS_ON  : pw_batch_on(cpw) ;
                    break ;
      case IS_OFF : pw_batch_off(cpw) ;
    }
}


/*ARGSUSED*/
void
canvas_proc(canvas, event)
Canvas canvas ;
Event *event ;
{
  cur_event = event ;
  process_event() ;       /* Determine what kind of event it is. */
  handle_event() ;        /* And do the appropriate action. */
}


close_frame()        /* Iconise Othello window. */
{
  WINDOW_SET(frame, FRAME_CLOSED, TRUE, 0) ;
}


color_area(x, y, width, height, color)
int x, y, width, height, color ;
{
  PW_WRITEBACKGROUND(cpw, x, y, width, height, PIX_SRC | PIX_COLOR(color)) ;
}


create_menu(mtype, values)    /* Create popup menus for cycle items. */
enum panel_type mtype ;
char *values[] ;
{
  int i = 0 ;
  int menuno ;     /* Current menu number. */
  int more = 1 ;   /* Cleared when current menu is complete.*/

  menuno = (int) mtype - (int) COMPUTER_PLAYS ;
  menus[menuno] = menu_create(MENU_FONT, font[(int) NFONT], 0) ;
  do
    {
      if (values[i] != NULL)
        MENU_SET(menus[menuno], MENU_STRING_ITEM, values[i], i+1, 0) ;
      else more = 0 ;
      i++ ;
    }
  while (more) ;
}


destroy_frame()        /* Destroy Othello window. */
{
  WINDOW_DONE(frame) ;
}


do_menu(mtype)      /* Popup appropriate cycle menu and get value. */
enum panel_type mtype ;
{
  int menuno ;

  menuno = (int) mtype - (int) COMPUTER_PLAYS ;
  return((int) menu_show(menus[menuno], canvas,
                          canvas_window_event(canvas, cur_event), 0)) ;
}


draw_image(x, y, width, height, image)
int x, y, width, height ;               
enum image_type image ;   
{                        
  PW_ROP(cpw, x, y, width, height, PIX_SRC | PIX_DST,
         images[(int) image], 0, 0) ;
}


draw_line(x1, y1, x2, y2, op, color)
int x1, y1, x2, y2, color ;
enum optype op ;
{
  int rop ;

  rop = opvals[(int) op] ;
  PW_VECTOR(cpw, x1, y1, x2, y2, rop | PIX_COLOR(color), 1) ;
}


draw_stencil(x, y, width, height, op, color, stencil, image)
int x, y, width, height, color ;
enum optype op ;
enum image_type stencil, image ;
{
  int rop ;

  rop = opvals[(int) op] | PIX_COLOR(color) ;
  PW_STENCIL(cpw, x, y, width, height, rop,
             images[(int) stencil], 0, 0, images[(int) image], 0, 0) ;
}


draw_text(x, y, ftype, color, str)
enum font_type ftype ;
int x, y, color ;
char *str ;
{
  PW_TTEXT(cpw, x, y, PIX_SRC | PIX_COLOR(color), font[(int) ftype], str) ;
}


Pixfont *
get_font(name)
char *name ;
{
  Pixfont *f ;

  f = pf_open(name) ;
  if (f == NULL) f = pf_default() ;
  if (f == NULL)
    {
      perror("couldn't get the default font.") ;
      exit(1) ;
    }
  return f ;
}


get_strwidth(ftype, str)    /* Get width in pixels of string value. */
enum font_type ftype ;
char *str ;
{
  struct pr_size size ;

  size = pf_textwidth(strlen(str), font[(int) ftype], str) ;
  return(size.x) ;
}


init_fonts()         /* Open the normal and bold fonts. */
{
  font[(int) BFONT] = get_font(BOLDFONT) ;
  font[(int) NFONT] = get_font(NORMALFONT) ;
  bfont_height = font[(int) BFONT]->pf_defaultsize.y ;
  nfont_height = font[(int) NFONT]->pf_defaultsize.y ;
}


init_ws_type()
{
  if (getenv("WINDOW_PARENT") == NULL)
    {
      FPRINTF(stderr,"%s: Not a native SunView window\n", progname) ;
      return -1 ;
    }
  move_delta = 5 ;      /* Delta for computer animate move. */
  return 0 ;
}


load_colors()      /* Create and load othello color map. */
{
  Pixwin *frame_pw ;
  char colorname[CMS_NAMESIZE] ;
  u_char red[OTH_COLORSIZE], green[OTH_COLORSIZE], blue[OTH_COLORSIZE] ;

  iscolor = (cpw->pw_pixrect->pr_depth == 8) ? 1 : 0 ;
  SPRINTF(colorname, "%s%D", OTH_COLOR, getpid()) ;
  PW_SETCMSNAME(cpw, colorname) ;

  oth_colorsetup(red, green, blue) ;
  PW_PUTCOLORMAP(cpw, 0, OTH_COLORSIZE, red, green, blue) ;
  if (inv_video) PW_REVERSEVIDEO(cpw, 0, OTH_COLORSIZE) ;

  if (iscolor)
    {
      frame_pw = (Pixwin *) window_get(frame, WIN_PIXWIN) ;
      PW_SETCMSNAME(frame_pw, colorname) ;
      PW_PUTCOLORMAP(frame_pw, 0, OTH_COLORSIZE, red, green, blue) ;
    }
}


lock_screen(state)   /* Turn graphics locking on or off. */
enum bltype state ;
{
  static struct rect r = { 0, 0, TOTAL_WIDTH+1, TOTAL_WIDTH+1 } ;

  switch (state)
    {
      case IS_ON  : PW_LOCK(cpw, &r) ;
                    break ;
      case IS_OFF : PW_UNLOCK(cpw) ;
    }
}


make_canvas()               /* Create canvas for game board. */
{
  canvas = window_create(frame, CANVAS,
                         CANVAS_RETAINED, FALSE,
                         WIN_HEIGHT,      TOTAL_HEIGHT,
                         WIN_WIDTH,       TOTAL_WIDTH,
                         WIN_CONSUME_PICK_EVENTS,
                           MS_LEFT, MS_MIDDLE, MS_RIGHT,
                           LOC_MOVE, LOC_DRAG, LOC_TRAJECTORY,
                           LOC_WINENTER, LOC_WINEXIT,
                           0,
                         WIN_CONSUME_KBD_EVENTS,
                           KBD_USE, KBD_DONE, WIN_ASCII_EVENTS, WIN_UP_EVENTS,
                           0,
                         WIN_EVENT_PROC, canvas_proc,
                         0) ;
  cpw = (Pixwin *) window_get(canvas, CANVAS_PIXWIN) ;
  cursor[(int) CANVASCUR] = window_get(canvas, WIN_CURSOR) ;
  CURSOR_SET(cursor[(int) CANVASCUR], CURSOR_OP, PIX_SRC ^ PIX_DST, 0) ;
  cursor[(int) HOURGLASS] = cursor_create(CURSOR_IMAGE, &hglass_pr, 0) ;
  CURSOR_SET(cursor[(int) HOURGLASS], CURSOR_OP, PIX_SRC ^ PIX_DST, 0) ;
  cursor[(int) NOCURSOR]  = cursor_create(CURSOR_IMAGE, &nocur_pr, 0) ;
  CURSOR_SET(cursor[(int) NOCURSOR], CURSOR_OP, PIX_SRC ^ PIX_DST, 0) ;
  load_colors() ;

  images[(int) BUT_STENCIL] = &button_stencil_pr ;
  images[(int) BUT_INVERT]  = &button_invert_pr ;
  images[(int) BUT_NORMAL]  = &button_normal_pr ;
  images[(int) CY_NORMAL]   = &cycle_glyph_pr ;
  images[(int) CY_STENCIL]  = &cycle_stencil_pr ;
  images[(int) CY_LINVERT]  = &cycle_linvert_pr ;
  images[(int) CY_RINVERT]  = &cycle_rinvert_pr ;
  images[(int) P_WHITE]     = &white_icon_pr ;
  images[(int) P_BLACK]     = &black_icon_pr ;
}


make_frame(argc, argv)      /* Create othello window. */
int argc ;
char *argv[] ;
{
  opvals[(int) RCLR] = PIX_CLR ;
  opvals[(int) RSRC] = PIX_SRC ;
  opvals[(int) RINV] = PIX_SRC ^ PIX_DST ;

  frame = window_create((Window) NULL, FRAME,
                         FRAME_ICON, othello_icon,
                         FRAME_LABEL, line,
                         FRAME_SUBWINDOWS_ADJUSTABLE, FALSE,
                         WIN_ERROR_MSG, "Can't create window.",
                         FRAME_ARGS, argc, argv,
                         0) ;
}


make_icon()
{
  othello_icon = icon_create(ICON_IMAGE, &icon_pr, 0) ;
}


process_event()       /* Process the next canvas event. */
{
  int id ;

  id = (event_id(cur_event)) ;
  curx = event_x(cur_event) ;
  cury = event_y(cur_event) ;

  if (event_is_button(cur_event) && event_is_down(cur_event))
    {
           if (id == MS_LEFT) nextc = LEFT_DOWN ;
      else if (id == MS_MIDDLE) nextc = MIDDLE_DOWN ;
      else if (id == MS_RIGHT) nextc = RIGHT_DOWN ;
    }
  else if (event_is_button(cur_event) && event_is_up(cur_event))
    {
           if (id == MS_LEFT) nextc = LEFT_UP ;
      else if (id == MS_MIDDLE) nextc = MIDDLE_UP ;
      else if (id == MS_RIGHT) nextc = RIGHT_UP ;
    }
  else if (event_is_ascii(cur_event))
    {
      cur_ch = id ;
      nextc = KEYBOARD ;
    }
  else if (id == KBD_DONE || id == LOC_WINEXIT ||
           id == WIN_STOP || id == LOC_RGNEXIT) nextc = EXIT_WINDOW ;
  else if (id == LOC_WINENTER || id == LOC_RGNENTER) nextc = ENTER_WINDOW ;
  else if (id == LOC_MOVE || id == LOC_DRAG || id == LOC_TRAJECTORY)
    nextc = MOUSE_MOVING ;
  else if (id == WIN_REPAINT) nextc = FRAME_REPAINT ;
}


set_cursor(ctype)
enum curtype ctype ;
{
  WINDOW_SET(canvas, WIN_CURSOR, cursor[(int) ctype], 0) ;
}


start_tool()      /* Display window and start the notifier. */
{
  if (iscolor)
    {
      othello_icon = (Icon) window_get(frame, FRAME_ICON) ;
      ICON_SET(othello_icon, ICON_IMAGE, &cicon_pr, 0) ;
      WINDOW_SET(frame, FRAME_ICON, othello_icon, 0) ;
    }
  window_fit(frame) ;
  window_main_loop(frame) ;
}
