BigEasy/BigEasyControls.c

/*
    File:       BigEasyControls.c
 
    Copyright:  © 1990-1991, 1994 by Apple Computer, Inc., all rights reserved.
 
    This file is used in these builds: Warhol
 
    Change History (most recent first):
 
        <10>    11-10-94    dvb     
         <9>     6/10/94    dvb     nil control list behaves better.
         <8>     4/13/92    dvb     Minor bugs (empty controllist, &c)
         <7>      4/3/92    dvb     New calls.
         <6>     5/28/91    JB      Added prototypes for BigEasy Proc Ptrs
         <5>     5/22/91    PH      new style prototypes
         <4>     4/25/91    JB      Changing to new THINK_C interface files
         <3>     12/5/90    GW      Fix dispose easycontrol
         <2>    11/17/90    dvb     Return unprocessed key-actions
        <1>     11/17/90    dvb     New again after 1st CD!
 
    To Do:
*/
 
/*
  * file: BigEasyControls.c
  *
  * started 25 May 1990 12:07:24 Friday at 310 Nobel
  * 
  * david van brink
  *
  */
 
/************************************
* Inclusions
************************************/
 
#include <Memory.h>
#include <QuickDraw.h>
#include <Events.h>
 
#define privateEasyControls
#include "BigEasy2.h"
#include "BigEasyGrafish.h"
#include "BigEasyTextish.h"
#include "BigEasyControls.h"
 
 
/************************************
* Globals
************************************/
 
static short defaultColors[6] =
    {
    0,
    PackColor555(46035,46035,46035),
    PackColor555(25535,65535,25535),
    PackColor555(24000,0,0),
    0,
    0
    };
 
/************************************
* Prototypes
************************************/
static void SelectEasyControl(easyControl ech, easyControlList list);
static void UnhighlightSelection(easyControlList list);
static void WalkDrawEasyControlList(easyControlList list,long,long);
static void WalkInvalEasyControlList(easyControlList list,long,long);
static short GetControlNumber(easyControl ech);
 
static void SetListText(easyControlList listH);
 
/************************************
* Routines
************************************/
easyControl NewEasyControl(easyControlType *type,Rect *r, long variation, void *style,
        long refcon,long id,long value,easyControlList list)
/*
  * Make a new handle for an easy control, and call the
  * init routine for that control. Then, add it to the
  * list passed in.
  */
    {
    easyControl ech;
    register easyControlPtr ec;
    register easyControl w;
    easyControlListPtr l;
 
    ech = (easyControl)NewHandle(sizeof(easyControlRecord));
    FailNil(ech);
 
    HLock((Handle)ech);
    ec = *ech;
 
    ec->next = nil;
    ec->list = list;
    l = *list;
    w = l->firstControl;
    if(!w)
        {
        ec->prev = nil;
        l->firstControl = ech;
        }
    else
        {
        while((**w).next)
            w = (**w).next;
        (**w).next = ech;
        ec->prev = w;
        }
 
    ec->type = type;
    ec->rect = *r;
    ec->flags = easyControlActive;
    ec->refcon = refcon;
    ec->id = id;
    ec->variation = variation;
    ec->value = value;
    ec->style = style;
    ec->state = nil;
 
    ec->color[0] = defaultColors[0];
    ec->color[1] = defaultColors[1];
    ec->color[2] = defaultColors[2];
    ec->color[3] = defaultColors[3];
    ec->color[4] = defaultColors[4];
    ec->color[5] = defaultColors[5];
 
    ec->actionProc = nil;
    ec->initActionProc = nil;
    ec->doneActionProc = nil;
    ec->valueProc = nil;
/*  ec->keyProc = nil; */
 
    ec->low = 0;
    ec->high = 100;
 
    SetListText(list);
 
    (*type->newProc)(ec);
 
    HUnlock((Handle)ech);
    return ech;
    }
 
void DisposeEasyControl(easyControl ech, easyControlList list)
/*
  * remove a control from the list passed
  */
    {
    register easyControl *w;
    register easyControlPtr ec;
    register easyControlListPtr l;
    easyControl last;
 
    l = *list;
    last = nil;
    ec = *ech;
    w = &l->firstControl;
 
    while(*w)
        {
        if(*w == ech)
            {
            *w = ec->next;
            if (*w != nil)  /* Make sure its not nil - GW */
                (**(ec->next)).prev = last;
            goto goHome;
            }
        else
            {
            last = *w;
            w = &(***w).next;
            }
        }
goHome:;
    DisposHandle((Handle)ech);
    }
 
void DisposeEasyControlList(easyControlList list)
    {
    register easyControl w,n;
 
    w = (**list).firstControl;
    while(w)
        {
        n = (**w).next;
        DisposeEasyControl(w,list);
        w = n;
        }
    DisposHandle((Handle)list);
    }
 
easyControlList NewEasyControlList(WindowPtr w,long refcon)
    {
    easyControlList listH;
    easyControlListPtr list;
 
    listH = (easyControlList)NewHandle(sizeof(easyControlListRecord));
    list = *listH;
    list->firstControl = nil;
    list->selectedControl = nil;
    list->nextSelectedControl = nil;
    list->ownerWindow = w;
    list->refcon = refcon;
    list->textFont = 3; /* geneva */
    list->textSize = 9;
    list->textFace = 0;
    list->nextIdle = 0;
    list->ticksPerIdle = 30;
 
    return listH;
    }
 
void SetListText(easyControlList listH)
    {
    TextFont((**listH).textFont);
    TextFace((**listH).textFace);
    TextSize((**listH).textSize);
    }
 
void KeyEasyControlList(easyControlList listH,short key,short mods,controlClickResult *ccr)
/*
  * Pass a keypress to the currently
  * selected control. we swipe "tab"s
  * to skip from control to control, and
  * "esc" to say "no control selected".
  */
    {
    register easyControl ech;
    register easyControlPtr ec;
    register easyControlListPtr list;
    short listHState;
    Boolean tookKey;
 
    listHState = HGetState((Handle)listH);
    HLock((Handle)listH);
    list = *listH;
 
    if(ccr)
        {
        ccr->whichControl = nil;
        ccr->tracked = false;
        ccr->value = 0;
        ccr->refcon = 0;
        ccr->id = 0;
        }
 
    ech = list->selectedControl;
    if(key == '\t')
        {
    nextEch:
        if(ech)
            {
            if(mods & shiftKey)
                ech = (**ech).prev;
            else
                ech =(**ech).next;
            }
        else
            {
            ech = list->firstControl;
            if(mods & shiftKey && ech)
                while((**ech).next)
                    ech = (**ech).next;
            }
        if(list->nextSelectedControl)
            {
            ech = list->nextSelectedControl;
            list->nextSelectedControl = nil;
            }
 
        if(ech && !(**ech).type->keyProc)       /* if its got no keyproc, it doesn't do keypresses */
            goto nextEch;
        SelectEasyControl(ech,listH);
        }
    else if(key == 27)          /* the escape key */
        {
        SelectEasyControl(nil,listH);
        list->nextSelectedControl = ech;
        }
    else
        {
        if(ech)
            {
            HLock((Handle)ech);
            ec = *ech;
            (*ec->type->keyProc)(ec,key,mods,&tookKey);
 
            if(ccr)
                {
                ccr->whichControl = ech;
                ccr->tracked = tookKey;
                ccr->value = ec->value;
                ccr->refcon = ec->refcon;
                ccr->id = ec->id;
                }
 
            HUnlock((Handle)ech);
 
            UnhighlightSelection(listH);            /* and forestall the next idle-blink for a while */
            }
        }
    HSetState((Handle)listH,listHState);
    }
 
short GetControlNumber(register easyControl ech)
/*
  * return the position in whatever list owns this control
  */
    {
    short n;
 
    n = 1;
    while( (**ech).prev)
        {
        n++;
        ech = (**ech).prev;
        }
    return n;
    }
 
 
void UnhighlightSelection(easyControlList listH)
/*
  * if there's a selected control,
  * put it in the unhighlighted phase
  */
    {
    register easyControl ech;
    register easyControlPtr ec;
    easyControlListPtr list;
    short listHState;
 
    listHState = HGetState((Handle)listH);
    HLock((Handle)listH);
    list = *listH;
 
    ech = list->selectedControl;
    if(ech)
        {
        list->nextIdle = TickCount()+list->ticksPerIdle;        /* reset the idling phase to normal */
        HLock((Handle)ech);
        ec = *ech;
        list->idleRef = 0;
        SetPort((*ec->list)->ownerWindow);
        (*ec->type->idleProc)(ec,&list->idleRef);
        HUnlock((Handle)ech);
        }
    HSetState((Handle)listH,listHState);
    }
 
easyControl ClickEasyControlList(easyControlList listH,Point p,
        controlClickResult *ccr,short mods)
    {
    register easyControl w;
    register easyControlPtr ec;
    easyControlListPtr list;
    short trackResult;
    short whichControl;
    short listHState;
 
    listHState = HGetState((Handle)listH);
    HLock((Handle)listH);
 
    list = *listH;
 
    w = list->firstControl;
    whichControl = 0;
 
    if(ccr)
        {
        ccr->whichControl = nil;
        ccr->tracked = false;
        ccr->value = 0;
        ccr->refcon = 0;
        ccr->id = 0;
        }
 
    while(w)
        {
        whichControl++;
        if(PtInRect(p,&(**w).rect) && (**w).type->trackProc)        /* in rect and mouse sensitive */
            {
            SelectEasyControl(nil,listH);
            HLock((Handle)w);
            ec = *w;
            ec->flags |= easyControlTracking;
            if(ec->type->keyProc)                           /* never select keyless control */
                list->nextSelectedControl = w;
            trackResult = 0;
            ec->flags |= easyControlSetValue;
            (*ec->type->trackProc)(ec,p,&trackResult,mods);
            if(trackResult && ec->valueProc)
                (*ec->valueProc)(w);
            ec->flags &= ~easyControlSetValue;
 
            if(ccr)
                {
                ccr->whichControl = w;
                ccr->tracked = true;
                ccr->value = ec->value;
                ccr->refcon = ec->refcon;
                ccr->id = ec->id;
                }
 
            ec->flags &= ~easyControlTracking;
            (*ec->type->drawValueProc)(ec);
            HUnlock((Handle)w);
            goto goHome;
            }
        else
            w = (**w).next;
        }
goHome:;
    HSetState((Handle)listH,listHState);
    return w;
    }
 
void DrawEasyControlList(register easyControlList list)
    {
    WalkDrawEasyControlList(list,~0,0);
    }
 
void DeactivateEasyControlList(easyControlList list)
/*
  * A window should call this when it
  * becomes un-frontmost
  */
    {
    WalkDrawEasyControlList(list,~0,easyControlBack);
    }
 
void ActivateEasyControlList(easyControlList list)
/*
  * A window should call this when it
  * becomes frontmost
  */
    {
    WalkInvalEasyControlList(list,~easyControlBack,0);
    }
 
 
void WalkDrawEasyControlList(easyControlList listH,long and,long or)
/*
  * The gut routine of Draw, Activate, and DeactivateEasyControlList
  */
    {
    register easyControlPtr ec;
    register easyControl w;
    register easyControlListPtr list;
    short listHState;
    GrafPtr oldPort;
 
    if(!listH)
        goto goHome;
 
    GetPort(&oldPort);
 
    listHState = HGetState((Handle)listH);
    HLock((Handle)listH);
 
    list = *listH;
 
    SetPort(list->ownerWindow);
 
    SetListText(listH);
 
    w = list->firstControl;
    while (w)
        {
        HLock((Handle)w);
        ec = *w;
        ec->flags &= and;
        ec->flags |= or;
        (*ec->type->drawProc)(ec);
        ValidRect(&ec->rect);
        HUnlock((Handle)w);
        w = ec->next;
        }
    HSetState((Handle)listH,listHState);
 
    SetPort(oldPort);
goHome:;
    }
 
 
void WalkInvalEasyControlList(easyControlList listH,long and,long or)
/*
  * The gut routine of Draw, Activate, and DeactivateEasyControlList
  */
    {
    register easyControlPtr ec;
    register easyControl w;
    register easyControlListPtr list;
    short listHState;
 
    listHState = HGetState((Handle)listH);
    HLock((Handle)listH);
 
    list = *listH;
 
    SetPort(list->ownerWindow);
    w = list->firstControl;
    while (w)
        {
        HLock((Handle)w);
        ec = *w;
        ec->flags &= and;
        ec->flags |= or;
        InvalRect(&ec->rect);
        HUnlock((Handle)w);
        w = ec->next;
        }
    HSetState((Handle)listH,listHState);
    }
 
 
 
void IdleEasyControlList(register easyControlList listH)
    {
    register easyControl ech;
    easyControlPtr ec;
    register easyControlListPtr list;
    long t;
    short listHState;
 
    listHState = HGetState((Handle)listH);
    HLock((Handle)listH);
    list = *listH;
 
    ech = list->selectedControl;
    if(ech)
        {
        t = TickCount();
        if(t > list->nextIdle)
            {
            list->nextIdle = t+list->ticksPerIdle;
            list->idleRef++;
            HLock((Handle)ech);
            ec = *ech;
            SetPort((*ec->list)->ownerWindow);
            (*ec->type->idleProc)(ec,&list->idleRef);
            HUnlock((Handle)ech);
            }
        }
    HSetState((Handle)listH,listHState);
    }
 
void SetEasyControlValue(register easyControl ech,long v)
    {
    register easyControlPtr ec;
    becSetValueProcPtr svp;
 
    HLock((Handle)ech);
    ec = *ech;
    SetPort((**ec->list).ownerWindow);
    svp = ec->type->setValueProc;
    if(svp)
        (*svp)(ec,v);
    else
        ec->value = v;
    ec->flags |= easyControlSetValue;
    SetListText(ec->list);
    (*ec->type->drawValueProc)(ec);
    ec->flags &= ~easyControlSetValue;
    HUnlock((Handle)ech);
    }
 
long GetEasyControlValue(easyControl ech)
    {
    return (**ech).value;
    }
 
long GetEasyControlRefcon(easyControl ech)
    {
    return (**ech).refcon;
    }
 
long GetEasyControlID(easyControl ech)
    {
    return (**ech).id;
    }
 
 
 
void SetEasyControlRange(easyControl ech,long l,long h)
    {
    register easyControlPtr ec;
 
    ec = *ech;
    ec->low = l;
    ec->high = h;
    }
 
void SetEasyControlValueProc(easyControl ech,becValueProcPtr proc)
    {
    register easyControlPtr ec;
 
    ec = *ech;
    ec->valueProc = proc;
    }
 
void SetEasyControlActionProc(easyControl ech,becActionProcPtr proc)
    {
    register easyControlPtr ec;
 
    ec = *ech;
    ec->actionProc = proc;
    }
 
void SetEasyControlInitActionProc(easyControl ech,becInitActionProcPtr proc)
    {
    register easyControlPtr ec;
 
    ec = *ech;
    ec->initActionProc = proc;
    }
 
void SetEasyControlDoneActionProc(easyControl ech,becDoneActionProcPtr proc)
    {
    register easyControlPtr ec;
 
    ec = *ech;
    ec->doneActionProc = proc;
    }
 
void GetEasyControlColors(easyControl ech,register short *colors)
    {
    register short i;
    register short *src;
 
    if(ech)
        src = &(**ech).color[0];
    else
        src = &defaultColors[0];
    for(i = 5; i>=0; i--)
        *colors++ = *src++;
    }
 
void SetEasyControlColors(easyControl ech,register short *colors)
    {
    register short i;
    register short *dst;
 
    if(ech)
        dst = &(**ech).color[0];
    else
        dst = &defaultColors[0];
    for(i = 5; i>=0; i--)
        *dst++ = *colors++;
    }
 
 
void SelectEasyControl(easyControl ech,easyControlList listH)
/*
  * Unselect the current one (if any)
  * and start the new one blinking.
  */
    {
    register easyControlListPtr list;
    short listHState;
 
    listHState = HGetState((Handle)listH);
    HLock((Handle)listH);
    list = *listH;
 
    list->idleRef = 0;
    UnhighlightSelection(listH);
    list->selectedControl = ech;
    list->nextIdle = 0;
    IdleEasyControlList(listH);
 
    HSetState((Handle)listH,listHState);
    }
 
void GetEasyControlRect(easyControl ech,Rect *r)
/*
  * Return the current bounds of the control
  */
    {
    *r = (**ech).rect;
    }
 
void SetEasyControlRect(easyControl ech,Rect *r)
/*
  * Move the control to the newly specified rectangle
  */
    {
    register easyControlPtr ec;
 
    HLock((Handle)ech);
    ec = *ech;
    SetPort((*ec->list)->ownerWindow);
    InvalRect(&ec->rect);
    ec->rect = *r;
    ec->flags |= easyControlMoved;
    InvalRect(&ec->rect);
    HUnlock((Handle)ech);
    }
 
unsigned short Replicate555(register unsigned short x)
    {
    x &= 0x001F;
    return (x<<11) | (x<<6) | (x<<1) | (x>>4);
    }
 
void Color555(register short x,register RGBColor *c)
    {
    c->red = Replicate555(x>>10);
    c->green = Replicate555(x>>5);
    c->blue = Replicate555(x);
    }
 
void Fore555(register short x)
    {
    RGBColor c;
 
    Color555(x,&c);
    RGBForeColor(&c);
    RGBBackColor(&c);
    }
 
#define kGrade 24000
static long PinAdd(long,long);
static long PinAdd(register long a,register long b)
    {
    a+= b;
    if(a > 65535)
        a = 65535;
    else if(a < 0)
        a = 0;
    return a;
    }
 
void Fore555Light(register short x)
    {
    RGBColor c;
 
    Color555(x,&c);
    c.red = PinAdd(c.red,kGrade);
    c.green = PinAdd(c.green,kGrade);
    c.blue = PinAdd(c.blue,kGrade);
/*
    c.green = (c.green + 65535L)>>1;
    c.blue = (c.blue + 65535L)>>1;*/
    RGBForeColor(&c);
    }
 
void Fore555Dark(register short x)
    {
    RGBColor c;
 
    Color555(x,&c);
    c.red = PinAdd(c.red,-kGrade);
    c.green = PinAdd(c.green,-kGrade);
    c.blue = PinAdd(c.blue,-kGrade);
/*  c.red = c.red >> 1;
    c.green = c.green >> 1;
    c.blue = c.blue >> 1;*/
    RGBForeColor(&c);
    }
 
#define kCCEdge 10000
void Fore555Contrast(register short x)
/*
  * Make a color that contrasts well with
  * the passed color: invert if close to a
  * side of the color cube, or shift by 32768
  */
    {
    RGBColor c;
 
    Color555(x,&c);
    if(c.red < kCCEdge || c.red > (65535-kCCEdge) ||
            c.green < kCCEdge || c.green > (65535-kCCEdge) ||
            c.blue < kCCEdge || c.blue > (65535-kCCEdge) )
        {
        c.red = ~c.red;
        c.green = ~c.green;
        c.blue = ~c.blue;
        }
    else
        {
        c.red += 32768;
        c.green += 32768;
        c.blue += 32768;
        }
    RGBForeColor(&c);
    }
 
void RaisedRect(register Rect *r,register short x)
/*
  * Draw rectangle r with a 1 pixel highlight
  * to raise it off the screen
  */
    {
    Fore555(x);
    if( ((r->right - r->left) <= 2) || ((r->bottom - r->top) <= 2) )
        PaintRect(r);
    else
        {
        PenSize(1,1);
        PaintRect(r);
        Fore555Light(x);
        MoveTo(r->left,r->bottom-1);
        LineTo(r->left,r->top);
        LineTo(r->right-1,r->top);
        Fore555Dark(x);
        LineTo(r->right-1,r->bottom-1);
        LineTo(r->left,r->bottom-1);
        }
    }
 
void LoweredRect(Rect *r,register short x)
/*
  * Draw rectangle r with a 1 pixel highlight
  * to raise it off the screen
  */
    {
    PenSize(1,1);
    Fore555(x);
    PaintRect(r);
    Fore555Dark(x);
    MoveTo(r->left,r->bottom-1);
    LineTo(r->left,r->top);
    LineTo(r->right-1,r->top);
    Fore555Light(x);
    LineTo(r->right-1,r->bottom-1);
    LineTo(r->left,r->bottom-1);
    }