1 line
17 KiB
C
Executable File
1 line
17 KiB
C
Executable File
/* Copyright (c) 2017, Computer History Museum
|
|
All rights reserved.
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to
|
|
the limitations in the disclaimer below) provided that the following conditions are met:
|
|
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
|
disclaimer in the documentation and/or other materials provided with the distribution.
|
|
* Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
|
|
COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
DAMAGE. */
|
|
|
|
#include "labelfield.h"
|
|
#define FILE_NUM 138
|
|
|
|
#pragma segment Util
|
|
|
|
#define kLabelFieldHorizontalMargin 4
|
|
#define kLabelFieldVerticalMargin 2
|
|
|
|
typedef struct {
|
|
short left; // Left coordinate
|
|
short top; // Top coordinate
|
|
short width; // Width (duh) of the label field
|
|
short height; // Height of the label field -- though this may be a fantasy we need to recalc
|
|
} LabelGeometryRec, *LabelGeometryPtr, **LabelGeometryHandle;
|
|
|
|
static void SetLabelGeometry (LabelGeometryPtr geometry, short left, short top, short width, short height);
|
|
static void LabelFieldGeometry (ControlHandle theControl, LabelGeometryPtr geometry, Rect *labelRect, Rect *pteRect);
|
|
static void LabelFieldGeometryVertical (ControlHandle theControl, LabelGeometryPtr geometry, Rect *labelRect, Rect *pteRect);
|
|
static void LabelFieldGeometryHorizontal (ControlHandle theControl, LabelGeometryPtr geometry, Rect *labelRect, Rect *pteRect);
|
|
static pascal void LabelFieldIdle (ControlHandle theControl);
|
|
static pascal void LabelFieldDraw (ControlHandle theControl, SInt16 part);
|
|
static pascal ControlPartCode LabelFieldKeyDown (ControlHandle control, SInt16 keyCode, SInt16 charCode, SInt16 modifiers);
|
|
static pascal ControlPartCode LabelFieldHitTest (ControlHandle theControl, Point where);
|
|
static pascal ControlPartCode LabelFieldFocus (ControlHandle theControl, ControlFocusPart action);
|
|
static pascal void LabelFieldBackground(ControlHandle theControl, ControlBackgroundPtr info);
|
|
|
|
extern void DoKeyDown(WindowPtr topWin,EventRecord *event);
|
|
|
|
//
|
|
// CreateLabelField
|
|
//
|
|
// Label fields are controls that contain both a PETE field and a nice labels in front
|
|
// of the editng field. Why something like this isn't in the toolbox by default, I'll
|
|
// never know...
|
|
//
|
|
// We overload a few of the ControlRecord fields like so:
|
|
//
|
|
// min = Upper 16 bits: label justification
|
|
// = Lower 16 bits: if labelDisplayAboveField is clear -> label width
|
|
// if labelDisplayAboveField is set -> pete height (now, that's clear, isn't it?)
|
|
// max = flags
|
|
// refcon = PETEHandle
|
|
//
|
|
|
|
ControlHandle CreateLabelField (MyWindowPtr win, Rect *boundsRect, Str255 title, short labelWidth, short labelJustification, LabelFieldFlagType flags, PETEDocInitInfoPtr initInfo, uLong pteFlags)
|
|
|
|
{
|
|
// PETEParaInfo pinfo;
|
|
PETEHandle pte;
|
|
LabelGeometryRec geometry;
|
|
ControlHandle theControl;
|
|
Rect contrlRect,
|
|
pteRect;
|
|
OSErr theError;
|
|
DECLARE_UPP(LabelFieldIdle,ControlUserPaneIdle);
|
|
DECLARE_UPP(LabelFieldDraw, ControlUserPaneDraw);
|
|
DECLARE_UPP(LabelFieldKeyDown, ControlUserPaneKeyDown);
|
|
DECLARE_UPP(LabelFieldHitTest, ControlUserPaneHitTest);
|
|
DECLARE_UPP(LabelFieldFocus, ControlUserPaneFocus);
|
|
DECLARE_UPP(LabelFieldBackground, ControlUserPaneBackground);
|
|
|
|
theError = noErr;
|
|
pte = nil;
|
|
|
|
if (boundsRect)
|
|
contrlRect = *boundsRect;
|
|
else
|
|
SetRect (&contrlRect, -50, -50, -20, -20);
|
|
|
|
// Set up the control
|
|
theControl = NewControlSmall (GetMyWindowWindowPtr(win),
|
|
&contrlRect,
|
|
title,
|
|
true,
|
|
kControlWantsIdle | kControlSupportsFocus | kControlGetsFocusOnClick | kControlSupportsEmbedding | kControlHasSpecialBackground,
|
|
0,
|
|
0,
|
|
kControlUserPaneProc,
|
|
nil);
|
|
|
|
if (theControl) {
|
|
if (gBetterAppearance) {
|
|
SetControl32BitMinimum (theControl, labelJustification << 16 | labelWidth);
|
|
SetControl32BitMaximum (theControl, flags);
|
|
}
|
|
else {
|
|
SetControlMinimum (theControl, labelJustification << 8 | (labelWidth & 0x00FF));
|
|
SetControlMaximum (theControl, (short) (flags & 0x0000FFFF));
|
|
}
|
|
// Setup procs to handle an assortment of events
|
|
INIT_UPP(LabelFieldIdle,ControlUserPaneIdle);
|
|
INIT_UPP(LabelFieldDraw, ControlUserPaneDraw);
|
|
INIT_UPP(LabelFieldKeyDown, ControlUserPaneKeyDown);
|
|
INIT_UPP(LabelFieldHitTest, ControlUserPaneHitTest);
|
|
INIT_UPP(LabelFieldFocus, ControlUserPaneFocus);
|
|
INIT_UPP(LabelFieldBackground, ControlUserPaneBackground);
|
|
|
|
theError = SetControlData (theControl, kControlEditTextPart, kControlUserPaneIdleProcTag, sizeof (ControlUserPaneIdleUPP), (void*) &LabelFieldIdleUPP);
|
|
if (!theError)
|
|
theError = SetControlData (theControl, kControlEditTextPart, kControlUserPaneKeyDownProcTag, sizeof (ControlUserPaneKeyDownUPP), (void*) &LabelFieldKeyDownUPP);
|
|
if (!theError)
|
|
theError = SetControlData (theControl, kControlEditTextPart, kControlUserPaneHitTestProcTag, sizeof (ControlUserPaneHitTestUPP), (void*) &LabelFieldHitTestUPP);
|
|
if (!theError)
|
|
theError = SetControlData (theControl, kControlEditTextPart, kControlUserPaneDrawProcTag, sizeof (ControlUserPaneDrawUPP), (void*) &LabelFieldDrawUPP);
|
|
if (!theError)
|
|
theError = SetControlData (theControl, kControlEditTextPart, kControlUserPaneFocusProcTag, sizeof (ControlUserPaneFocusUPP), (void*) &LabelFieldFocusUPP);
|
|
if (!theError)
|
|
theError = SetControlData (theControl, kControlEditTextPart, kControlUserPaneBackgroundProcTag, sizeof (ControlUserPaneBackgroundUPP), (void*) &LabelFieldBackgroundUPP);
|
|
|
|
// Create a PETEHandle that will be put into the user pane and assign it a 'pete' property
|
|
if (!theError) {
|
|
if (!(flags & labelWrapField))
|
|
initInfo->docWidth = REAL_BIG;
|
|
initInfo->containerControl = theControl; // embed pte scroll bars in this control
|
|
theError = PeteCreate (win, &pte, pteFlags, initInfo);
|
|
}
|
|
if (!theError) {
|
|
if (!(flags & labelWrapField))
|
|
(*PeteExtra(pte))->infinitelyWide = true;
|
|
theError = PeteFontAndSize (pte,GetPortTextFont(GetQDGlobalsThePort()),GetPortTextSize(GetQDGlobalsThePort()));
|
|
}
|
|
// if (!theError && !(flags & labelWrapField)) {
|
|
// pinfo.endMargin = REAL_BIG;
|
|
// theError = PETESetParaInfo (PETE, pte, -1, &pinfo, peEndMarginValid);
|
|
// }
|
|
if (!theError) {
|
|
// Place the PETEHandle into the control's refcon field, or cleanup if disaster has struck
|
|
SetControlReference (theControl, (long) pte);
|
|
|
|
// Size up the situation
|
|
SetLabelGeometry (&geometry, contrlRect.left, contrlRect.top, RectWi (contrlRect), RectHi (contrlRect));
|
|
LabelFieldGeometry (theControl, &geometry, nil, &pteRect);
|
|
PeteDidResize (pte, &pteRect);
|
|
(*PeteExtra (pte))->frame = true;
|
|
}
|
|
else
|
|
if (pte) {
|
|
PeteDispose (win, pte);
|
|
DisposeControl (theControl);
|
|
theControl = nil;
|
|
}
|
|
}
|
|
return (theControl);
|
|
}
|
|
|
|
static void SetLabelGeometry (LabelGeometryPtr geometry, short left, short top, short width, short height)
|
|
|
|
{
|
|
geometry->left = left;
|
|
geometry->top = top;
|
|
geometry->width = width;
|
|
geometry->height = height;
|
|
}
|
|
|
|
|
|
static void LabelFieldGeometry (ControlHandle theControl, LabelGeometryPtr geometry, Rect *labelRect, Rect *pteRect)
|
|
|
|
{
|
|
if (theControl) {
|
|
if (GetLabelFieldFlags (theControl) & labelDisplayAboveField)
|
|
LabelFieldGeometryVertical (theControl, geometry, labelRect, pteRect);
|
|
else
|
|
LabelFieldGeometryHorizontal (theControl, geometry, labelRect, pteRect);
|
|
}
|
|
}
|
|
|
|
static void LabelFieldGeometryHorizontal (ControlHandle theControl, LabelGeometryPtr geometry, Rect *labelRect, Rect *pteRect)
|
|
|
|
{
|
|
short labelWidth,
|
|
right,
|
|
bottom;
|
|
Str255 s;
|
|
|
|
labelWidth = GetLabelFieldLabelWidth (theControl);
|
|
right = geometry->left + geometry->width;
|
|
bottom = geometry->top + geometry->height;
|
|
if (GetLabelFieldFlags (theControl) & labelAutoSize)
|
|
{
|
|
GetControlTitle(theControl,s);
|
|
labelWidth = StringWidth(s);
|
|
}
|
|
if (labelRect)
|
|
SetRect (labelRect, geometry->left, geometry->top, geometry->left + labelWidth, bottom);
|
|
if (pteRect)
|
|
SetRect (pteRect, geometry->left + labelWidth + (labelWidth ? kLabelFieldHorizontalMargin : 0), geometry->top, right, bottom);
|
|
}
|
|
|
|
static void LabelFieldGeometryVertical (ControlHandle theControl, LabelGeometryPtr geometry, Rect *labelRect, Rect *pteRect)
|
|
|
|
{
|
|
FontInfo info;
|
|
short peteTop,
|
|
peteHeight,
|
|
labelHeight,
|
|
right;
|
|
Boolean autoSize = GetLabelFieldFlags (theControl) & labelAutoSizeFieldHeight ? true : false;
|
|
Str255 s;
|
|
|
|
GetFontInfo (&info);
|
|
right = geometry->left + geometry->width;
|
|
labelHeight = info.ascent + info.descent + info.leading;
|
|
peteHeight = autoSize ? geometry->height - labelHeight - kLabelFieldVerticalMargin : GetLabelFieldPeteHeight (theControl);
|
|
peteTop = geometry->top + labelHeight + kLabelFieldVerticalMargin;
|
|
if (labelRect)
|
|
{
|
|
GetControlTitle(theControl,s);
|
|
SetRect (labelRect, geometry->left, geometry->top, geometry->left + StringWidth(s), geometry->top + labelHeight);
|
|
}
|
|
if (pteRect)
|
|
SetRect (pteRect, geometry->left, peteTop, right, peteTop + peteHeight);
|
|
}
|
|
|
|
|
|
//
|
|
// DisposeLabelField
|
|
//
|
|
// Disposes of the PETEHandle inside of a Label Field -- but does NOT dispose of
|
|
// the ControlHandle itself!
|
|
//
|
|
|
|
void DisposeLabelField (ControlHandle theControl)
|
|
|
|
{
|
|
PETEHandle pte;
|
|
|
|
if (theControl)
|
|
if (pte = GetLabelFieldPete (theControl)) {
|
|
PeteDispose (GetWindowMyWindowPtr (GetControlOwner(theControl)), pte);
|
|
SetControlReference (theControl, (long) nil);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// MoveLabelField
|
|
//
|
|
// Moves the label field and its PETEHandle.
|
|
//
|
|
|
|
void MoveLabelField (ControlHandle theControl, int h, int v, int w, int t)
|
|
|
|
{
|
|
LabelGeometryRec geometry;
|
|
PETEHandle pte;
|
|
Rect contrlRect,
|
|
labelRect,
|
|
pteRect;
|
|
|
|
SetLabelGeometry (&geometry, h, v, w, t);
|
|
if (theControl)
|
|
if (pte = GetLabelFieldPete (theControl)) {
|
|
// Get the rectangles for both the label and the PETE
|
|
LabelFieldGeometry (theControl, &geometry, &labelRect, &pteRect);
|
|
|
|
// Move the control to its new location. Note that the new location is defined
|
|
// by the union of the label and PETE rects.
|
|
UnionRect (&labelRect, &pteRect, &contrlRect);
|
|
MoveMyCntl (theControl, contrlRect.left, contrlRect.top, RectWi (contrlRect), RectHi (contrlRect));
|
|
PeteDidResize (pte, &pteRect);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// LabelFieldIdle
|
|
//
|
|
// The idleProc for a Label Field. Our idle handling amounts to nothing more
|
|
// than giving time to the nickname watcher if the PETE supports nickname
|
|
// scanning.
|
|
//
|
|
// We only want to give idle time to the PETE that currently has the focus. So,
|
|
// once we've grabbed the PETEHandle we verify that this handle is the current
|
|
// PETE for this window.
|
|
//
|
|
// Note: In the future there might be more interesting things we'll want
|
|
// to do at idle time.
|
|
//
|
|
|
|
static pascal void LabelFieldIdle (ControlHandle theControl)
|
|
|
|
{
|
|
MyWindowPtr win;
|
|
PETEHandle pte;
|
|
|
|
if (pte = GetLabelFieldPete (theControl))
|
|
if (win = GetWindowMyWindowPtr (GetControlOwner(theControl)))
|
|
if ((*PeteExtra(pte))->win->pte == pte)
|
|
if (HasNickScanCapability (pte))
|
|
NicknameWatcherIdle (pte);
|
|
}
|
|
|
|
|
|
//
|
|
// LabelFieldKeyDown
|
|
//
|
|
// Key down handling for the label field.
|
|
//
|
|
|
|
static pascal ControlPartCode LabelFieldKeyDown (ControlHandle control, SInt16 keyCode, SInt16 charCode, SInt16 modifiers)
|
|
|
|
{
|
|
EventRecord fakeEvent;
|
|
|
|
fakeEvent.what = keyDown;
|
|
fakeEvent.message = (charCode & charCodeMask) | (keyCode << 8);
|
|
fakeEvent.modifiers = modifiers;
|
|
fakeEvent.when = TickCount ();
|
|
GetMouse (&fakeEvent.where);
|
|
LocalToGlobal (&fakeEvent.where);
|
|
DoKeyDown (GetControlOwner(control), &fakeEvent);
|
|
return (kControlEditTextPart);
|
|
}
|
|
|
|
|
|
//
|
|
// LabelFieldDraw
|
|
//
|
|
// The drawProc for a Label Field. We want to position and draw the label, as well
|
|
// as update the PETE.
|
|
//
|
|
|
|
static pascal void LabelFieldDraw (ControlHandle theControl, SInt16 part)
|
|
|
|
{
|
|
#pragma unused(part)
|
|
LabelGeometryRec geometry;
|
|
PETEHandle pte;
|
|
FontInfo theInfo;
|
|
Rect labelRect,rCntl;
|
|
short labelJustification;
|
|
Str255 sTitle;
|
|
MyWindowPtr win;
|
|
|
|
if (win = GetWindowMyWindowPtr(GetControlOwner(theControl)))
|
|
ConfigFontSetup(win);
|
|
|
|
GetFontInfo (&theInfo);
|
|
GetControlBounds(theControl,&rCntl);
|
|
SetLabelGeometry (&geometry,rCntl.left,rCntl.top, RectWi (rCntl), RectHi(rCntl));
|
|
LabelFieldGeometry (theControl, &geometry, &labelRect, nil);
|
|
labelJustification = GetLabelFieldLabelJustification (theControl);
|
|
GetControlTitle(theControl,sTitle);
|
|
if (labelJustification == teFlushDefault)
|
|
labelJustification = GetSysDirection () ? teFlushRight : teFlushLeft;
|
|
switch (labelJustification) {
|
|
case teFlushLeft:
|
|
MoveTo (labelRect.left, labelRect.top + theInfo.ascent);
|
|
break;
|
|
case teFlushRight:
|
|
MoveTo (labelRect.right - StringWidth (sTitle), labelRect.top + theInfo.ascent);
|
|
break;
|
|
case teCenter:
|
|
MoveTo (labelRect.left + (RectWi (labelRect) - StringWidth (sTitle)) >> 1, labelRect.top + theInfo.ascent);
|
|
}
|
|
|
|
if (!HaveTheDiseaseCalledOSX())
|
|
if (win = GetWindowMyWindowPtr(GetControlOwner(theControl)))
|
|
RGBBackColor(&win->backColor);
|
|
|
|
if (pte = GetLabelFieldPete (theControl)) {
|
|
if ((*PeteExtra(pte))->isInactive = !IsControlActive (theControl))
|
|
TextMode (grayishTextOr);
|
|
if (GetLabelFieldFlags (theControl) & labelWrapLabel) {
|
|
TETextBox (&sTitle[1], sTitle[0], &labelRect, labelJustification);
|
|
}
|
|
else
|
|
DrawString (sTitle);
|
|
PeteUpdate (pte);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// LabelFieldHitTest
|
|
//
|
|
|
|
static pascal ControlPartCode LabelFieldHitTest (ControlHandle theControl, Point where)
|
|
|
|
{
|
|
LabelGeometryRec geometry;
|
|
ControlPartCode part;
|
|
Rect labelRect,rCntl;
|
|
|
|
part = kControlNoPart;
|
|
if (PtInRect (where,GetControlBounds(theControl,&rCntl)) && IsControlActive (theControl)) {
|
|
SetLabelGeometry (&geometry,rCntl.left,rCntl.top, RectWi (rCntl), RectHi (rCntl));
|
|
LabelFieldGeometry (theControl, &geometry, &labelRect, nil);
|
|
if (PtInRect (where, &labelRect))
|
|
part = kControlLabelPart;
|
|
else
|
|
if (PtInPETEView (where, GetLabelFieldPete (theControl)))
|
|
part = kControlEditTextPart;
|
|
}
|
|
return (part);
|
|
}
|
|
|
|
|
|
static pascal ControlPartCode LabelFieldFocus (ControlHandle theControl, ControlFocusPart action)
|
|
|
|
{
|
|
ControlPartCode partCode;
|
|
PETEHandle pte;
|
|
MyWindowPtr win;
|
|
|
|
partCode = kControlNoPart;
|
|
if (pte = GetLabelFieldPete (theControl))
|
|
if (win = GetWindowMyWindowPtr(GetControlOwner(theControl)))
|
|
switch (action) {
|
|
case kControlFocusNoPart:
|
|
PeteSelect (win, pte, 0, 0);
|
|
PeteFocus (win, nil, true);
|
|
break;
|
|
case kControlEditTextPart:
|
|
if (!(*PeteExtra(pte))->isInactive) {
|
|
PeteFocus (win, pte, true);
|
|
partCode = kControlEditTextPart;
|
|
}
|
|
break;
|
|
}
|
|
return (partCode);
|
|
}
|
|
|
|
static pascal void LabelFieldBackground(ControlHandle theControl, ControlBackgroundPtr info)
|
|
{
|
|
MyWindowPtr win;
|
|
|
|
if (win = GetWindowMyWindowPtr(GetControlOwner(theControl)))
|
|
RGBBackColor(&win->backColor);
|
|
}
|
|
|
|
void SetLabelFieldText (ControlHandle theControl, UPtr text, long len)
|
|
|
|
{
|
|
PETEHandle pte;
|
|
|
|
if (pte = GetLabelFieldPete (theControl))
|
|
PeteSetTextPtr (pte, text, len);
|
|
}
|
|
|
|
Handle GetLabelFieldText (ControlHandle theControl)
|
|
|
|
{
|
|
PETEHandle pte;
|
|
UHandle text;
|
|
|
|
text = nil;
|
|
if (pte = GetLabelFieldPete (theControl))
|
|
PeteGetRawText (pte, &text);
|
|
return (text);
|
|
}
|
|
|
|
PStr GetLabelFieldString (ControlHandle theControl, PStr string)
|
|
|
|
{
|
|
PETEHandle pte;
|
|
|
|
if (pte = GetLabelFieldPete (theControl))
|
|
PeteString (string, pte);
|
|
return (string);
|
|
}
|
|
|
|
|
|
Rect *GetRelevantLabelFieldBounds (ControlHandle theControl, RelativeFlagsType flags, Rect *boundsRect)
|
|
|
|
{
|
|
LabelGeometryRec geometry;
|
|
Rect rCntl;
|
|
|
|
GetControlBounds(theControl,&rCntl);
|
|
SetLabelGeometry (&geometry,rCntl.left,rCntl.top,RectWi(rCntl), RectHi(rCntl));
|
|
if (flags & rfPETEPart)
|
|
LabelFieldGeometry (theControl, &geometry, nil, boundsRect);
|
|
else
|
|
if (flags & rfLabelPart)
|
|
LabelFieldGeometry (theControl, &geometry, boundsRect, nil);
|
|
return (boundsRect);
|
|
}
|