/* AmiIviewWindow.c - Low Level Window Objects for Amiga               */
/* Copyright (c) 1990 by J.K. Lindsey                                  */
/* Additions to XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney     */
/* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz    */
/* You may give out copies of this software; for conditions see the    */
/* file COPYING included with this distribution.                       */

#include <proto/intuition.h>
#include <proto/exec.h>
#include <exec/memory.h>
#include <stdlib.h>
#include <string.h>
#include "autil2.h"
#include "xlisp.h"
#include "osdef.h"
#include "xlproto.h"
#include "xlsproto.h"
#include "iviewproto.h"
#include "Stproto.h"
#include "osproto.h"
#include "amivar.h"
#include "xlsvar.h"

/* forward declarations */
void init_ami_cursors(void);

StGWWinInfo *IViewWindowWinInfo(struct Window *w){
   return(w?(StGWWinInfo *)w->UserData:0);}

/**************************************************************************/
/**                                                                      **/
/**                       Initialization Functions                       **/
/**                                                                      **/
/**************************************************************************/

void StInitGraphics(void){
   initialize_static_globals();
   init_ami_colors();
   init_ami_cursors();}

/**************************************************************************/
/**                                                                      **/
/**                       Window Creation Functions                      **/
/**                                                                      **/
/**************************************************************************/

void scroll_action(StGWWinInfo *gwinfo,int id){
   int left,top,width,height,value;
   if(id){
      value=((struct PropInfo *)gwinfo->vscroll->SpecialInfo)->VertPot;
      StGWSetScroll(gwinfo,gwinfo->view_h,value,0);}
   else {
      value=((struct PropInfo *)gwinfo->hscroll->SpecialInfo)->HorizPot;
      StGWSetScroll(gwinfo,value,gwinfo->view_v,0);}
   StGWGetViewRect(gwinfo,&left,&top,&width,&height);
   StGWStartBuffering(gwinfo);
   StGWObRedraw(gwinfo->Object);
   StGWBufferToScreen(gwinfo,left,top,width,height);}

void mouse_action(StGWWinInfo *gwinfo,unsigned short qualifier){
   struct Window *w;
   int x,y,width,height;
   MouseClickModifier mods;
   w=gwinfo->window;
   StGWGetViewRect(gwinfo,0,0,&width,&height);
   x=w->MouseX-w->BorderLeft;
   y=w->MouseY-w->BorderTop;
   if(x<0||y<0||x>width||y>height)return;
   scroll_clip(gwinfo,&x,&y);
   mods=(qualifier&SHIFTED)?ExtendModifier:NoModifiers;
   if(qualifier&ALT)mods+=2;
   StGWObDoMouse(gwinfo->Object,x,y,MouseClick,mods);}

void key_action(StGWWinInfo *gwinfo,char key,int mods){
   if(key=='\r')key='\n';
   StGWObDoKey(gwinfo->Object,key,mods&SHIFTED,mods&ALT);}

void graph_update_action(StGWWinInfo *gwinfo,int resized){
   LVAL object;
   struct Window *w;
   int width,height;
   unsigned short s;
   if(!gwinfo||!(w=gwinfo->window))return;
   object=gwinfo->Object;
   SetHardwareState(gwinfo);
   if(!gwinfo->initialized){
      resized=1;
      gwinfo->initialized=1;}
   StGWGetViewRect(gwinfo,0,0,&width,&height);
   if(resized){
      if(gwinfo->hasHscroll){
         gwinfo->view_h=s=(gwinfo->canvasWidth-width>0)?(MAXBODY*width)/gwinfo->canvasWidth:MAXBODY;
         NewModifyProp(gwinfo->hscroll,w,0,AUTOKNOB|FREEHORIZ,
         (short)gwinfo->view_h,MAXPOT,s,MAXBODY,1);}
      else gwinfo->canvasWidth=width;
      if(gwinfo->hasVscroll){
         gwinfo->view_v=s=(gwinfo->canvasHeight-height>0)?(MAXBODY*height)/gwinfo->canvasHeight:MAXBODY;
         NewModifyProp(gwinfo->vscroll,w,0,AUTOKNOB|FREEVERT,
         MAXPOT,(short)gwinfo->view_v,MAXBODY,s,1);}
      else gwinfo->canvasHeight=height;
      StGWObResize(object);}
   StGWObRedraw(object);}
/*
void graph_activate_action(StGWWinInfo *gwinfo,int active){
   if(active)ami_do_cursor(gwinfo);}

void clobber_action(StGWWinInfo *gwinfo){
   struct Window *w;
   w=gwinfo->window;
   if(IViewInternalIsLinked(w))IViewUnlinkWindow(w);
   StGWObDoClobber(gwinfo->Object);
   StGWRemove(gwinfo);}
*/
void idle_action(StGWWinInfo *gwinfo){
   struct Window *w;
   int old_x,old_y;
   w=gwinfo->window;
   old_x=gwinfo->mouse_x;
   old_y=gwinfo->mouse_y;
   gwinfo->mouse_x=w->MouseX;
   gwinfo->mouse_y=w->MouseY;
   if(old_x!=w->MouseX||old_y!=w->MouseY)
   StGWObDoMouse(gwinfo->Object,w->MouseX-w->BorderLeft,w->MouseY-w->BorderTop,MouseMove,0);
   if(gwinfo->idleOn)StGWObDoIdle(gwinfo->Object);}

StGWWinInfoSize(void){
   return(sizeof(StGWWinInfo));}

void StGWInitWinInfo(LVAL object){
   StGWWinInfo *gwinfo=(StGWWinInfo *)StGWObWinInfo(object);
   gwinfo->Object=object;
   gwinfo->initialized=0;
   gwinfo->symbolMode=JAM2;
   gwinfo->canvasWidth=0;
   gwinfo->canvasHeight=0;
   gwinfo->hasHscroll=0;
   gwinfo->hasVscroll=0;
   gwinfo->hscroll=0;
   gwinfo->vscroll=0;
   gwinfo->view_h=0;
   gwinfo->view_v=0;
   gwinfo->h_scroll_inc[0]=1;
   gwinfo->h_scroll_inc[1]=50;
   gwinfo->v_scroll_inc[0]=1;
   gwinfo->v_scroll_inc[1]=50;
   gwinfo->lineType=0;
   gwinfo->drawMode=JAM1;
   gwinfo->backColor=WHITE;
   gwinfo->drawColor=BLACK;
   gwinfo->lineWidth=1;
   gwinfo->window=0;
   gwinfo->idleOn=0;
   gwinfo->use_color=1;
   gwinfo->cursor=0;
   gwinfo->clipped=0;
   gwinfo->RefCon=nil;}

IVIEW_WINDOW IViewWindowNew(LVAL object,int is_GW){
   char *title;
   static char deftitle[]="Graph Window";
   unsigned long flags,iflags;
   int left,top,width,height,goAway;
   StGWWinInfo *gwinfo;
   struct Window *w;
   struct NewWindow nw;
   StGWGetAllocInfo(object,&title,&left,&top,&width,&height,&goAway);
   width+=2*screen->WBorLeft;
   height+=2*screen->BarHeight+1;
   if((left-=screen->WBorLeft)<0)left=0;
   if((top-=screen->BarHeight+1)<0)top=0;
   if(left+width>screenw)width=screenw-left;
   if(top+height>screenh)height=screenh-top;
   iflags=GADGETUP|MENUPICK|NEWSIZE|MOUSEBUTTONS|VANILLAKEY|ACTIVEWINDOW|
   INACTIVEWINDOW|SIZEVERIFY;
   flags=WINDOWDRAG|WINDOWSIZING|ACTIVATE|WINDOWDEPTH|SIZEBBOTTOM
   |SMART_REFRESH|NOCAREREFRESH;
#ifdef RMOUSE
   iflags|=MOUSEMOVE;
   flags|=REPORTMOUSE;
#endif RMOUSE
   if(goAway){
      flags|=WINDOWCLOSE;
      iflags|=CLOSEWINDOW;}
   if(!title||strlen(title)<=0)title=deftitle;
   nw.LeftEdge=left;
   nw.TopEdge=top;
   nw.Width=width;
   nw.Height=height;
   nw.DetailPen=WHITE;
   nw.BlockPen=BLACK;
   nw.IDCMPFlags=iflags;
   nw.Flags=flags;
   nw.FirstGadget=0;
   nw.CheckMark=0;
   nw.Title=title;
   nw.Screen=screen;
   nw.BitMap=0;
   nw.MinWidth=100;
   nw.MinHeight=50;
   nw.MaxWidth=screenw;
   nw.MaxHeight=screenh;
   nw.Type=screentype;
   if(!(w=OpenWindow(&nw)))StPerror("window creation failed");
   gwinfo=(StGWWinInfo *)StGWObWinInfo(object);
   gwinfo->window=w;
   if(!gwinfo->hasHscroll)gwinfo->canvasWidth=width;
   if(!gwinfo->hasVscroll)gwinfo->canvasHeight=height;
   w->UserData=(char *)gwinfo;
   if(Menu_Ptr)StMObInstall(0);
   SetHardwareState(gwinfo);
   if(is_GW)set_iview_window_address(w,object);
   else set_iview_address(w,object);
   return(w);}

/**************************************************************************/
/**                                                                      **/
/**                          Clipping  Functions                         **/
/**                                                                      **/
/**************************************************************************/

void StGWSetClipRect(StGWWinInfo *gwinfo,int clipped,int left,int top,int width,int height){
   if(!gwinfo)return;
   gwinfo->clipped=clipped;
   if(clipped){
      gwinfo->clip_rect.left=left;
      gwinfo->clip_rect.top=top;
      gwinfo->clip_rect.width=width;
      gwinfo->clip_rect.height=height;}}

int StGWGetClipRect(StGWWinInfo *gwinfo,int *left,int *top,int *width,int *height){
   if(gwinfo){
      if(left)*left=gwinfo->clip_rect.left;
      if(top)*top=gwinfo->clip_rect.top;
      if(width)*width=gwinfo->clip_rect.width;
      if(height)*height=gwinfo->clip_rect.height;
      return(gwinfo->clipped);}
   else return(0);}

/**************************************************************************/
/**                                                                      **/
/**                         Miscellaneous Functions                      **/
/**                                                                      **/
/**************************************************************************/

#define NumBasicCursors 9

static int NumCursors;

typedef struct {
   unsigned short *curs;
   int h,v;
   LVAL refcon;}
cursor_entry;

static cursor_entry *curstab;

static void init_ami_cursors(void){
  NumCursors=NumBasicCursors;
  curstab=(cursor_entry *)StCalloc(NumCursors,sizeof(cursor_entry));}

void StGWSetCursRefCon(int index,LVAL rc){
  if(index<NumCursors)curstab[index].refcon=rc;}

LVAL StGWGetCursRefCon(int index){
  if(index<NumCursors)return(curstab[index].refcon);
  else return(0);}

static void set_image_bits(short *bits,char *image,char *mask){
   int i,j;
   for(i=0;i<16;i++)for(j=0;j<16;j++){
      if(image[i*16+j])bits[2*i+2]|=(1<<j);
      if(mask&&mask[i*16+j])bits[2*i+3]|=(1<<j);}}

StGWMakeCursor(int n,char *image,char *mask,int h,int v,LVAL refcon){
   int index;
   char *temp;
   cursor_entry *c;
   if(n!=16||!image)return(-1);
   for(index=0;index<NumCursors&&StGWGetCursRefCon(index);index++);
   if(index>=NumCursors){
      temp=realloc(curstab,(NumCursors+1)*sizeof(cursor_entry));
      if(!temp)return(-1);
      curstab=(cursor_entry *)temp;
      NumCursors++;
      c=&curstab[index];
      c->curs=0;
      c->refcon=0;}
   else c=&curstab[index];
   if(!c->curs&&!(c->curs=AllocMem(72,MEMF_CHIP|MEMF_CLEAR)))return(-1);
   set_image_bits(c->curs,image,mask);
   curstab[index].h=-h;
   curstab[index].v=-v;
   curstab[index].refcon=refcon;
   return(index);}
   
int StGWMakeResCursor(char *name,int num,LVAL refcon){
   return(0);}

void StGWFreeCursor(int index){
   cursor_entry *c=&curstab[index];
   if(index<NumCursors&&index>=NumBasicCursors){
      if(c->curs)FreeMem(c->curs,72);
      c->curs=0;
      c->refcon=0;}}

#include "pointer.h"
static unsigned short *get_cursor(int index,int *x,int *y){
   unsigned short *curs=0;
   if(index<NumBasicCursors){
      switch (index) {
         case ARROW_CURSOR: {
            curs=nil;
            break;}
         case WATCH_CURSOR: {
            curs=snooze;
            *x=snoozex;
            *y=snoozey;
            break;}
         case CROSS_CURSOR: {
            curs=cross;
            *x=crossx;
            *y=crossy;
            break;}
         case BRUSH_CURSOR: {
            curs=brush;
            *x=brushx;
            *y=brushy;
            break;}
         case HAND_CURSOR: {
            curs=hand;
            *x=handx;
            *y=handy;
            break;}
         case FINGER_CURSOR: {
            curs=finger;
            *x=fingerx;
            *y=fingery;
            break;}
         case HOUR_GLASS_CURSOR: {
            curs=glass;
            *x=glassx;
            *y=glassy;
            break;}
         case TRASH_BAG_CURSOR: {
            curs=bag;
            *x=bagx;
            *y=bagy;
            break;}
         case TRASH_CAN_CURSOR: {
            curs=can;
            *x=canx;
            *y=cany;
            break;}}}
   else if(index<NumCursors){
      curs=curstab[index].curs;
      *x=curstab[index].h;
      *y=curstab[index].v;}
   return(curs);}
  
void ami_do_cursor(StGWWinInfo *gwinfo){
   unsigned short *curs;
   struct Window *w;
   int x,y,l;
   w=gwinfo->window;
   l=(gwinfo->cursor==WATCH_CURSOR)?22:16;
   if(curs=get_cursor(gwinfo->cursor,&x,&y))SetPointer(w,curs,l,16,x,y);
   else ClearPointer(w);}

void StGWSetCursor(StGWWinInfo *gwinfo,int cursor){
   if(gwinfo)gwinfo->cursor=cursor;}

StGWCursor(StGWWinInfo *gwinfo){
   return(gwinfo?gwinfo->cursor:0);}

