Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
ValueControls ƒ/ValueControls.c
#include <Printing.h> |
#include <Windows.h> |
#include <Fonts.h> |
#include <Devices.h> |
#include <ToolUtils.h> |
#include <TextUtils.h> |
#include <LowMem.h> |
#include <SegLoad.h> |
#include <fp.h> |
#include "ValueControls.h" |
#define kVCHeight 12 |
#define kVCWidth 192 |
#define kValuePos 142 // right edge (right flush) |
#define kDecHitPos 156 |
#define kIncHitPos 172 |
#define kResetWidth 36 |
enum { |
kSettingsDlog = 1280 |
}; |
enum { |
iVCtitle = 3, |
iMinValue, |
iMaxValue, |
iStepSize, |
iCurrentV |
}; |
// private structures |
struct ValueCtlRec { |
Str255 title; |
float initV; |
float currV; |
float mini; |
float maxi; |
float delta; |
Point titlePos; // absolute window coordinates; initialized from ValueCtlCluster |
Point valuePos; |
Rect wholeRect; |
Rect incrHit; |
Rect decrHit; |
long lastClick; |
Boolean isCheckBox; |
}; |
typedef struct ValueCtlRec ValueCtlRec, *VcPtr; |
struct ValueCtlCluster { |
OSType idTag; |
Str255 vTitle; |
long howMany; // 1-based |
Rect frame; // tries to position controls by itself; |
// may add scrollbars if required, later. |
Rect resetHit; |
long vcHeight; // height of one ValueCtlRec in pixels |
long maxEntries; // 1-based |
VcPtr vCtls[1]; // 0-based |
}; |
typedef struct ValueCtlCluster ValueCtlCluster; |
static VcPtr NewValueCtl(Str255 title, float initV, float mini, float maxi, float delta); |
static void DrawValueCtl(VcPtr v); |
static void IncrementVC(VcPtr v); |
static void DecrementVC(VcPtr v); |
static Boolean DoSettingsDialog(VcPtr v); |
// from TextUtils.h: |
extern pascal StringPtr C2PStr(Ptr cString); |
extern pascal Ptr P2CStr(StringPtr pString); |
// from my dialog utilities: |
void PutFloat(DialogPtr dlg, short item, float value); |
float GetFloat(DialogPtr dlg, short item); |
//---------------------------------------------------------------------- |
VcPtr NewValueCtl(Str255 title, float initV, float mini, float maxi, float delta) |
{ |
VcPtr v; |
Rect r; |
v = (VcPtr)NewPtr(sizeof(ValueCtlRec)); |
if (v != nil) { |
BlockMove((Ptr)title, (Ptr)v->title, (long)title[0]+1); |
v->initV = initV; |
v->currV = initV; |
v->mini = mini; |
v->maxi = maxi; |
v->delta = delta; |
v->titlePos.h = 4; |
v->titlePos.v = kVCHeight - 2; |
v->valuePos.h = kValuePos; |
v->valuePos.v = kVCHeight - 2; |
SetRect(&v->wholeRect, 0, 0, kVCWidth, kVCHeight); |
SetRect(&r, 0, 0, kVCHeight - 2, kVCHeight - 2); |
OffsetRect(&r, kDecHitPos, 1); |
v->decrHit = r; |
OffsetRect(&r, kIncHitPos - kDecHitPos, 0); |
v->incrHit = r; |
v->lastClick = 0; |
v->isCheckBox = ((mini == 0.0) && (maxi == 1.0) && (delta == 1.0)); |
} |
return v; |
} |
//---------------------------------------------------------------------- |
VccPtr NewVCluster(long tag, Str255 title, long numEntries, Rect *bounds) |
{ |
Rect r = *bounds; // avoid side effects on bounds parameter! |
long size; |
VccPtr vcc; |
InsetRect(&r, 4, 4); |
r.top += 4; |
if ( (numEntries + 1) * kVCHeight > (r.bottom - r.top) ) |
return nil; // don't have enough space |
r.bottom = r.top + numEntries * kVCHeight + 10; |
size = sizeof(ValueCtlCluster) + (numEntries - 1) * sizeof(VcPtr); |
vcc = (VccPtr)NewPtr(size); |
if (vcc != nil) { |
vcc->idTag = tag; |
BlockMove((Ptr)title, (Ptr)vcc->vTitle, (long)title[0] + 1); |
vcc->howMany = 0; |
vcc->frame = r; |
vcc->vcHeight = kVCHeight; |
vcc->maxEntries = numEntries; |
SetRect(&r, 0, 0, kResetWidth, kVCHeight - 1); |
OffsetRect(&r, vcc->frame.right - kResetWidth - 6, vcc->frame.top - 6); |
vcc->resetHit = r; |
} |
return vcc; |
} |
//---------------------------------------------------------------------- |
void AddValueCtl(VccPtr vcc, Str255 title, float initV, float mini, float maxi, float delta) |
{ |
VcPtr v; |
Point offset; |
if (vcc->howMany >= vcc->maxEntries) |
return; |
v = NewValueCtl(title, initV, mini, maxi, delta); |
if (!v) |
return; |
offset.v = vcc->frame.top + (vcc->howMany + 1) * (vcc->vcHeight) - 6; |
offset.h = vcc->frame.left + 2; |
AddPt(offset, &v->titlePos); |
AddPt(offset, &v->valuePos); |
OffsetRect(&v->wholeRect, offset.h, offset.v); |
SectRect(&vcc->frame, &v->wholeRect, &v->wholeRect); |
v->wholeRect.right -= 2; |
OffsetRect(&v->incrHit, offset.h, offset.v); |
OffsetRect(&v->decrHit, offset.h, offset.v); |
vcc->vCtls[vcc->howMany] = v; |
vcc->howMany++; |
} |
//---------------------------------------------------------------------- |
void AddSeparator(VccPtr vcc) |
{ |
AddValueCtl(vcc, "\p------------", 0.0, 0.0, 0.0, 0.0); |
} |
//---------------------------------------------------------------------- |
Boolean TakeHit(Point clickPt, VccPtr vcc) |
{ |
long i, ticks; |
Rect r; |
Boolean isDblClick = false; |
i = 0; |
r = vcc->resetHit; |
if ( PtInRect(clickPt, &r) ) { // an afterthought ... |
InvertRect(&r); |
do { |
vcc->vCtls[i]->currV = vcc->vCtls[i]->initV; |
DrawValueCtl(vcc->vCtls[i]); |
} while (++i < vcc->howMany); |
InvertRect(&r); |
return true; |
} |
// i = 0; |
do { |
if ((vcc->vCtls)[i]->mini < (vcc->vCtls)[i]->maxi) { |
// take hits only in real control lines |
r = (vcc->vCtls)[i]->incrHit; |
if ( PtInRect(clickPt, &r) ) { |
InvertRect(&r); |
IncrementVC((vcc->vCtls)[i]); |
goto newValue; |
} |
r = (vcc->vCtls)[i]->decrHit; |
if ( PtInRect(clickPt, &r) ) { |
InvertRect(&r); |
DecrementVC((vcc->vCtls)[i]); |
goto newValue; |
} |
r = (vcc->vCtls)[i]->wholeRect; |
if ( PtInRect(clickPt, &r) ) { |
ticks = ((vcc->vCtls)[i])->lastClick; |
isDblClick = (TickCount() - ticks < LMGetDoubleTime()); |
((vcc->vCtls)[i])->lastClick = TickCount(); |
} |
if ((isDblClick) && DoSettingsDialog((vcc->vCtls)[i])) { |
DrawValueCtl((vcc->vCtls)[i]); |
return true; |
} |
else |
isDblClick = false; |
} |
} while ( (++i < vcc->howMany) ); |
return false; |
newValue: |
Delay(6, &ticks); |
InvertRect(&r); |
((vcc->vCtls)[i])->lastClick = TickCount(); |
DrawValueCtl((vcc->vCtls)[i]); |
return true; |
} |
//---------------------------------------------------------------------- |
static void DrawValueCtl(VcPtr v) |
{ |
Str255 s; |
Str255 st = "\ptrue"; |
Str255 sf = "\pfalse"; |
Rect r; |
long w; |
decimal d; |
decform df; |
EraseRect(&v->wholeRect); |
TextFont(geneva); |
TextSize(9); |
TextFace(0); |
MoveTo(v->titlePos.h, v->titlePos.v); |
DrawString(v->title); |
if (v->mini == v->maxi) // separator |
return; |
if (v->isCheckBox) { |
if (v->currV == 1.0) |
BlockMove(st, s, st[0]+1); |
else |
BlockMove(sf, s, sf[0]+1); |
} |
else { |
df.style = FIXEDDECIMAL; |
df.digits = 2; |
num2dec(&df, v->currV, &d); |
dec2str(&df, &d, (char *)s); |
C2PStr((Ptr)s); |
} |
TextFace(bold); |
w = StringWidth(s); |
MoveTo(v->valuePos.h - w, v->valuePos.v); |
DrawString(s); |
r = v->incrHit; |
FrameRect(&r); |
if (v->isCheckBox) { |
if (v->currV == 1.0) { |
MoveTo(r.left, r.top); |
LineTo(r.right - 1, r.bottom - 1); |
MoveTo(r.left, r.bottom - 1); |
LineTo(r.right - 1, r.top); |
} |
} |
else { |
MoveTo( r.left + 2, r.bottom - 2); |
DrawChar('+'); |
r = v->decrHit; |
FrameRect(&r); |
MoveTo(r.left + 2, r.bottom - 2); |
DrawChar('-'); |
} |
} |
//----------------------------------- |
static void IncrementVC(VcPtr v) |
{ |
if (v->isCheckBox) { |
if (v->currV == 0.0) |
v->currV = 1.0; |
else |
v->currV = 0.0; |
} |
else { |
v->currV += v->delta; |
if (v->currV > v->maxi) |
v->currV = v->maxi; |
} |
} |
//----------------------------------- |
static void DecrementVC(VcPtr v) |
{ |
v->currV -= v->delta; |
if (v->currV < v->mini) |
v->currV = v->mini; |
} |
//---------------------------------------------------------------------- |
//--------------------- ValueControlCluster routines ------------------- |
//---------------------------------------------------------------------- |
void DrawVCluster(VccPtr vcc) |
{ |
long i; |
Rect r; |
FrameRect(&vcc->frame); |
MoveTo(vcc->frame.left + 12, vcc->frame.top + 3); |
TextFont(geneva); |
TextSize(9); |
TextFace(bold); |
TextMode(srcCopy); |
DrawChar(' '); DrawString(vcc->vTitle); DrawChar(' '); |
r = vcc->resetHit; |
EraseRect(&r); |
FrameRect(&r); |
MoveTo(r.left + 3, r.bottom - 2); |
TextMode(srcOr); |
DrawString("\pReset"); |
for (i = 0; i < vcc->howMany; i++) |
DrawValueCtl(vcc->vCtls[i]); |
} |
//---------------------------------------------------------------------- |
void DisposeVCluster(VccPtr vcc) |
{ |
long i; |
for (i = 0; i < vcc->howMany; i++) |
DisposePtr((Ptr)(&vcc->vCtls[i])); |
DisposePtr((Ptr)vcc); |
} |
//---------------------------------------------------------------------- |
OSType GetIdTag(VccPtr vcc) |
{ |
return vcc->idTag; |
} |
//---------------------------------------------------------------------- |
float GetCurrentValue(VccPtr vcc, long index) |
{ |
if ((index >= 0) && (index < vcc->howMany)) |
return (vcc->vCtls[index])->currV; |
else { |
SysBeep(10); |
return 0; |
} |
} |
//---------------------------------------------------------------------- |
void SetResetValue(VccPtr vcc, long index, float value) |
{ |
if ((index >= 0) && (index < vcc->howMany)) |
(vcc->vCtls[index])->initV = value; |
else { |
SysBeep(10); |
} |
} |
//---------------------------------------------------------------------- |
//--------------------- SettingsDialog routines ------------------- |
//---------------------------------------------------------------------- |
static Boolean DoSettingsDialog(VcPtr v) |
{ |
DialogPtr dlg; |
GrafPtr savePort; |
ModalFilterUPP filterProc; |
OSErr err; |
short item, kind; |
Handle h; |
Rect r; |
GetPort(&savePort); |
dlg = GetNewDialog(kSettingsDlog, nil, (WindowPtr)(-1)); |
if (!dlg) |
return false; |
SetPort(dlg); |
err = GetStdFilterProc(&filterProc); |
err = SetDialogDefaultItem(dlg, ok); |
err = SetDialogCancelItem(dlg, cancel); |
err = SetDialogTracksCursor(dlg, true); |
GetDialogItem(dlg, iVCtitle, &kind, &h, &r); |
SetDialogItemText(h, v->title); |
PutFloat(dlg, iMinValue, v->mini); |
PutFloat(dlg, iMaxValue, v->maxi); |
PutFloat(dlg, iStepSize, v->delta); |
PutFloat(dlg, iCurrentV, v->currV); |
do { |
ModalDialog(filterProc, &item); |
switch (item) { |
case ok: |
// range checks |
break; |
case iMinValue: |
// range check |
break; |
case iMaxValue: |
// range check |
break; |
case iStepSize: |
// range check |
break; |
case iCurrentV: |
// range check |
break; |
} |
if (item == ok) { |
v->mini = GetFloat(dlg, iMinValue); |
v->maxi = GetFloat(dlg, iMaxValue); |
v->delta = GetFloat(dlg, iStepSize); |
v->currV = GetFloat(dlg, iCurrentV); |
} |
} while ((item != cancel) && (item != ok)); |
DisposeDialog(dlg); |
SetPort(savePort); |
return (item == ok); |
} |
//---------------------------------------------------------------------- |
void PutFloat(DialogPtr dlg, short item, float value) |
{ |
Str255 s; |
Handle h; |
Rect r; |
decimal d; |
decform df; |
short kind; |
df.style = FIXEDDECIMAL; |
df.digits = 2; |
num2dec(&df, value, &d); |
dec2str(&df, &d, (char *)s); |
C2PStr((Ptr)s); |
GetDialogItem(dlg, item, &kind, &h, &r); |
SetDialogItemText(h, s); |
} |
//---------------------------------------------------------------------- |
float GetFloat(DialogPtr dlg, short item) |
{ |
Str255 s; |
Handle h; |
Rect r; |
decimal d; |
decform df; |
float value = 0.0; |
short kind; |
short ix, vp; |
GetDialogItem(dlg, item, &kind, &h, &r); |
if (h) { |
GetDialogItemText(h, s); |
P2CStr(s); |
ix = 0; |
str2dec((char *)s, &ix, &d, &vp); |
if (vp) |
value = dec2f(&d); |
} |
return value; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14