/* Thanks go out to David Swasbrook, who gave me an example  of how to use GTLZ_CallBack */

#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/text.h>
#include <clib/intuition_protos.h>
#include <string.h>
#include <intuition/imageclass.h>
#include <libraries/gadtools.h>
#include <clib/graphics_protos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <stdio.h>
#include <graphics/gfxmacros.h>

#include "CheckBoxListView.h"

#include "WBStartup+Prefs.h"


#define	LVRASTPORT	l->lvdm_RastPort
#define	LVPEN		l->lvdm_DrawInfo->dri_Pens
#define	XOFF		2
WORD 	xoff;		/* Offset to start printing text at */
WORD	yoff;		/* Vertical offset */
APTR	CheckMarkObj = NULL;
BYTE	FillPen,FillTextPen;
BYTE	BgPen,FgPen;
struct IntuiText CheckBoxList_it = { 1,0,0,0,0,NULL, NULL, NULL};
struct TextAttr ChecklistFont = { NULL,0,0 };

ULONG __chip Crosshatch = 0x5555AAAA;
ULONG __chip SolidLine = 0xFFFFFFFF;


void FillIntuiTextLen(struct IntuiText *it, char *source, char *buffer, ULONG len)
{
  /* Puts a string in it->IText which is less than or equal to len pixels long. */

  /* IntuitText *it  Must be preloaded (except IText) to determine the string pixel length  */
  /* char *source    The string to start from.  */
  /* char *buffer    The final string.  */
  /* ULONG len       The # of pixels which the source string is cropped to.  */

  WORD lb, ub, mid, l;

  it->IText = source;
  if (IntuiTextLength(it) <= len)
    return;

  strcpy(buffer, source);

  lb = 0;
  ub = strlen(buffer);

  it->IText = buffer;

  /* Is a binary search method for efficiency */
	while (lb < ub)
  {
	  mid = (ub-lb) / 2 + lb;
	  strncpy(buffer,source,mid);
	  strcpy(&buffer[mid],">");  /* Put a '>' and a NULL in the right place */
	  l = IntuiTextLength(it);

	  if (l < len)
    {
		  lb = mid;
		  if (lb == ub-1)
        lb = ub;
	  }
    else if (l > len)
    {
		  ub = mid;
	  }
    else
      lb = ub;
  }
}


BOOL CheckBoxList_CallBack_SetUp(WORD h, struct DrawInfo *di, struct IntuiText *it)
{
  /* Sets the global pen values, and creates/allocates the checkbox image to use in */
  /* the list view. */
  /* WORD h         The height if the list view cell */
  /* DrawInfo *di   DrawInfo to use in the checkbox creation */
  /* IntuiText *it  IntuiText defining the font which is used is the listview */
  /* RETURNS  TRUE if the checkmark box was created, false otherwise */

	CheckBoxList_it.ITextFont = &ChecklistFont;
	xoff = CheckBoxList_it.ITextFont->ta_YSize+6;	        /* Width of checkbox */
	yoff = (h-CheckBoxList_it.ITextFont->ta_YSize+1)/2;   /* Height of checkbox */

  /* Set global pen values */
	FillTextPen = di->dri_Pens[FILLTEXTPEN];
	FillPen = di->dri_Pens[FILLPEN];
	FgPen = di->dri_Pens[TEXTPEN];
	BgPen = di->dri_Pens[BACKGROUNDPEN];

  /* Create the check box image to use in the list view */
	CheckMarkObj = NewObject(NULL, SYSICLASS,
      IA_Width,xoff-3,
      IA_Height,h-1,
      SYSIA_Which,CHECKIMAGE,
      SYSIA_DrawInfo,di,
      TAG_DONE);

	if (CheckMarkObj)
    return(TRUE);

	return(FALSE);
}

void CheckBoxList_CallBack_CleanUp(void)
{
  /* Deallocate the checkbox image */

	if (CheckMarkObj)
  {
    DisposeObject(CheckMarkObj);
    CheckMarkObj = NULL;
  }
}


ULONG __saveds __asm CheckBoxList_CallBack(register __a0 struct Hook *hook, register __a1 struct LVDrawMsg *l, register __a2 struct Node *n)
{
  /* Render a cell in the listview in the cells current state */
  /* Hook *hook   Hook structure */
  /* LVDrawMsg *l  Listview message explaining cell state */
  /* Node *n  Pointer to the WBSP_Node for the cell to draw */
  /* RETURNS  LVCB_OK if the lv draw method is LV_DRAW, LVCB_UNKNOWN otherwise */

	ULONG res = LVCB_UNKNOWN;
	BYTE pen;
	UBYTE temp[256];
	WORD x,y,w,h,ids;
  UBYTE oldstyle;
	struct IntuiText *it = &CheckBoxList_it;
  char prioritystring[10];
  char *ptr;


	x = l->lvdm_Bounds.MinX;
	y = l->lvdm_Bounds.MinY;
	w = l->lvdm_Bounds.MaxX - x;
	h = l->lvdm_Bounds.MaxY - y;

	if(l->lvdm_MethodID==LV_DRAW)
  {
		if(!(CheckMarkObj))
      CheckBoxList_CallBack_SetUp(h,l->lvdm_DrawInfo,it);

    /* Clear The box with the back ground color */
    SetAPen(LVRASTPORT,BgPen);
    SetAfPt(LVRASTPORT, NULL, 0);
    RectFill(LVRASTPORT,x,y,x+w,y+h);

		switch(l->lvdm_State)
    {
			case LVR_NORMAL:
        break;
			case LVR_SELECTED:
        SetAPen(LVRASTPORT,FillPen);
        SetAfPt(LVRASTPORT,(UWORD *)&Crosshatch,1);
        RectFill(LVRASTPORT,x,y,x+w,y+h);
        break;
		}

		switch(l->lvdm_State)
    {
			case LVR_NORMAL: pen = FgPen; break;
			case LVR_SELECTED: pen = FillTextPen; break;
		}
		it->FrontPen = pen;

    /* Draw vertical line before priority */
    SetAPen(LVRASTPORT,LVPEN[SHINEPEN]);
    Move(LVRASTPORT,x+PRIORITYEDGE,y-1); Draw(LVRASTPORT,x+PRIORITYEDGE,y+h);
    SetAPen(LVRASTPORT,LVPEN[SHADOWPEN]);
    Move(LVRASTPORT,x+PRIORITYEDGE+1,y); Draw(LVRASTPORT,x+PRIORITYEDGE+1,y+h+1);

    if (n->ln_Type == TITLE)
    {
  		/* Draw horizontal line under title */
	  	SetAPen(LVRASTPORT,LVPEN[SHINEPEN]);
		  Move(LVRASTPORT,x,y+h-1); Draw(LVRASTPORT,x+w,y+h-1);
  		SetAPen(LVRASTPORT,LVPEN[SHADOWPEN]);
	  	Move(LVRASTPORT,x,y+h); Draw(LVRASTPORT,x+w,y+h);

      oldstyle = it->ITextFont->ta_Style;
      it->ITextFont->ta_Style = FSF_BOLD;

      if (ptr=strchr(n->ln_Name,','))
        *ptr=NULL;

      FillIntuiTextLen(it, n->ln_Name, &*temp, w-4-(w-PRIORITYEDGE));
	  	PrintIText(LVRASTPORT, it, x+4, y+yoff);

      if (ptr)
      {
        FillIntuiTextLen(it, ptr+1, &*temp, w-6-PRIORITYEDGE);
	    	PrintIText(LVRASTPORT, it, x+6+PRIORITYEDGE, y+yoff);
        *ptr=',';
      }

      it->ITextFont->ta_Style = oldstyle;
    }
    else  /* not a title */
    {
  		FillIntuiTextLen(it,n->ln_Name,&*temp,w-xoff-4-(w-PRIORITYEDGE));
	  	PrintIText(LVRASTPORT, it, x+xoff+4, y+yoff);

  		if (n->ln_Type)
        ids = IDS_SELECTED;
	  	else
        ids = IDS_NORMAL;

  		DrawImageState(LVRASTPORT,CheckMarkObj,x+2,y+1,ids,l->lvdm_DrawInfo);

      /* Draw priority text */
      stci_d(prioritystring,(int)n->ln_Pri);
  		FillIntuiTextLen(it,prioritystring,&*temp,w-6-PRIORITYEDGE);
      PrintIText(LVRASTPORT, it, x+6+PRIORITYEDGE, y+yoff);
    }

		res = LVCB_OK;
	}

	return(res);
}



void InitHook(struct Hook *hook, ULONG (*c_function)(), APTR userdata)
{
    hook->h_Entry	= c_function;
    hook->h_SubEntry = NULL;
    hook->h_Data	= userdata;
}


