1 line
14 KiB
C
Executable File
1 line
14 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 "peteuserpane.h"
|
|
#define FILE_NUM 119
|
|
|
|
#pragma segment Util
|
|
|
|
static pascal void PeteUserPaneIdle (ControlHandle theControl);
|
|
static pascal void PeteUserPaneDraw (ControlHandle theControl, SInt16 part);
|
|
static pascal ControlPartCode PeteUserPaneKeyDown (ControlHandle control, SInt16 keyCode, SInt16 charCode, SInt16 modifiers);
|
|
static pascal ControlPartCode PeteUserPaneFocus (ControlHandle control, ControlFocusPart action);
|
|
|
|
extern void DoKeyDown(WindowPtr topWin,EventRecord *event);
|
|
|
|
//
|
|
// CreatePeteUserPane
|
|
//
|
|
// Creates a user pane that contains a PETE field. This allows fields in dialogs to act
|
|
// like PETE fields instead of TE fields. PETE user panes are given a control property
|
|
// with the tag 'pete' (and the boolean value, true) so that we can easily determine that
|
|
// this is a PETE control. Ordinarily, this might not be all that important since (for
|
|
// instance) a window might be able to easily specify which of it's controls are or are
|
|
// not of a specific type. In a dialog, however, this is not quite so easy since most
|
|
// dialog handling code is bottlenecked to handle most of the dialog processing in an
|
|
// application. By assigning a unique property to these controls the bottle neck routines
|
|
// are able to look at a ControlHandle and determine whether or not it is a PETE user pane.
|
|
//
|
|
// We also set up a number of user pane procs to handle a the processing of a PETE control
|
|
// in response to idle, keyDown and draw events.
|
|
//
|
|
// Lastly, the PETEHandle itself is stuffed into the control's refcon field.
|
|
//
|
|
// If we are unable to create the PETE user pane, we dispose of the PETE and return nil.
|
|
//
|
|
// Note: In order to use a PETE in a user pane of a dialog, you'll need to do the following
|
|
// to your dialog and control:
|
|
// 1. Create a 'CNTL' resource with a procID of 256
|
|
// 2. Your dialog must have a root control. This means that the dialog
|
|
// must have the "use control hierarchy" bit set, so you'll have to
|
|
// add your dialog to the 'hlist' variable in AddDlgx.
|
|
// 3. After creating your dialog (with GetNewMyDialog), call CreatePeteUserPane
|
|
// for any controls that are to contain PETE's.
|
|
// 4. Initialize the win->pte pointer for your dialog to point to the PETEHandle
|
|
// returned from CreatePeteUserPane.
|
|
//
|
|
// To get to the PETEHandle itself, use GetPeteDItem.
|
|
//
|
|
// Don't forget to PeteDispose the PETEHandle _before_ you dispose of your dialog!!
|
|
//
|
|
|
|
PETEHandle CreatePeteUserPane (ControlHandle theControl, uLong flags, PETEDocInitInfoPtr initInfo, Boolean noWrap)
|
|
|
|
{
|
|
MyWindowPtr win;
|
|
PETEParaInfo pinfo;
|
|
PETEHandle pte;
|
|
OSErr theError;
|
|
// Boolean isPete;
|
|
Rect rCntl;
|
|
DECLARE_UPP(PeteUserPaneIdle,ControlUserPaneIdle);
|
|
DECLARE_UPP(PeteUserPaneDraw, ControlUserPaneDraw);
|
|
DECLARE_UPP(PeteUserPaneKeyDown, ControlUserPaneKeyDown);
|
|
DECLARE_UPP(PeteUserPaneFocus, ControlUserPaneFocus);
|
|
|
|
if (!theControl)
|
|
return (nil);
|
|
|
|
win = GetWindowMyWindowPtr (GetControlOwner(theControl));
|
|
pte = nil;
|
|
|
|
SetControlValue (theControl, kControlWantsIdle | kControlSupportsFocus | kControlGetsFocusOnClick);
|
|
|
|
// Create a PETEHandle that will be put into the user pane and assign it a 'pete' property
|
|
theError = PeteCreate (win, &pte, flags, initInfo);
|
|
if (!theError)
|
|
if (noWrap) {
|
|
pinfo.endMargin = REAL_BIG;
|
|
theError = PETESetParaInfo (PETE, pte, -1, &pinfo, peEndMarginValid);
|
|
}
|
|
if (!theError) {
|
|
(*PeteExtra (pte))->frame = true;
|
|
PeteDidResize (pte,GetControlBounds(theControl,&rCntl));
|
|
|
|
// Commented out for now because control properties are not supported on 68K
|
|
// isPete = true;
|
|
// theError = SetControlProperty (theControl, CREATOR, kPETEComponentSubType, sizeof (isPete), (void*) &isPete);
|
|
//
|
|
// Instead, because 'GetControlData' is BROKEN for early versions of appearance, we're going to brand PETE controls
|
|
// with some "pete" in the contrlTitle field (grrrr...)
|
|
SetControlTitle (theControl, kPeteUserPaneTitleIDString);
|
|
}
|
|
|
|
// Setup procs to handle an assortment of events
|
|
INIT_UPP(PeteUserPaneIdle,ControlUserPaneIdle);
|
|
INIT_UPP(PeteUserPaneDraw, ControlUserPaneDraw);
|
|
INIT_UPP(PeteUserPaneKeyDown, ControlUserPaneKeyDown);
|
|
INIT_UPP(PeteUserPaneFocus, ControlUserPaneFocus);
|
|
if (!theError)
|
|
theError = SetControlData (theControl, kControlEditTextPart, kControlUserPaneIdleProcTag, sizeof (ControlUserPaneIdleUPP), (void*) &PeteUserPaneIdleUPP);
|
|
if (!theError)
|
|
theError = SetControlData (theControl, kControlEditTextPart, kControlUserPaneKeyDownProcTag, sizeof (ControlUserPaneKeyDownUPP), (void*) &PeteUserPaneKeyDownUPP);
|
|
if (!theError)
|
|
theError = SetControlData (theControl, kControlEditTextPart, kControlUserPaneDrawProcTag, sizeof (ControlUserPaneDrawUPP), (void*) &PeteUserPaneDrawUPP);
|
|
if (!theError)
|
|
theError = SetControlData (theControl, kControlEditTextPart, kControlUserPaneFocusProcTag, sizeof (ControlUserPaneFocusUPP), (void*) &PeteUserPaneFocusUPP);
|
|
|
|
// Place the PETEHandle into the control's refcon field, or cleanup if disaster has struck
|
|
if (!theError)
|
|
SetControlReference (theControl, (long) pte);
|
|
else
|
|
if (pte) {
|
|
PeteDispose (win, pte);
|
|
pte = nil;
|
|
}
|
|
return (pte);
|
|
}
|
|
|
|
|
|
//
|
|
// DisposePeteUserPaneItem
|
|
//
|
|
// Disposes of a PETE user pane item by disposing of its associated PETEHandle.
|
|
//
|
|
|
|
void DisposePeteUserPaneItem (MyWindowPtr dgPtr, short item)
|
|
|
|
{
|
|
PETEHandle pte;
|
|
|
|
if (pte = GetPeteDItem (dgPtr, item))
|
|
PeteDispose (dgPtr, pte);
|
|
}
|
|
|
|
|
|
//
|
|
// IsPeteControl
|
|
//
|
|
// Checks to see if a given control is a PETE user pane by retrieving the 'pete'
|
|
// property (if this control even has such a property) and verifying that this
|
|
// boolean value is true.
|
|
//
|
|
|
|
Boolean IsPeteControl (ControlHandle theControl)
|
|
|
|
{
|
|
Str255 title;
|
|
Boolean isPete;
|
|
|
|
isPete = false;
|
|
|
|
// Commented out for now because control properties are not supported on 68K
|
|
// if (theControl)
|
|
// (void) GetControlProperty (theControl, CREATOR, kPETEComponentSubType, sizeof (isPete), &actualSize, (void*) &isPete);
|
|
|
|
// Instead, we're going to check to see if the control gas a keyDown proc
|
|
// and check to see if it is the same as the PeteUserPaneKeyDown proc. :(
|
|
// if (theControl) {
|
|
// if (!GetControlData (theControl, 0,kControlUserPaneKeyDownProcTag, sizeof (ControlUserPaneKeyDownUPP), (void*) ¤tKeyDownUPP, &actualSize))
|
|
// isPete = currentKeyDownUPP == PeteUserPaneKeyDownUPP;
|
|
// }
|
|
|
|
// Strike Two... GetControlData is broken for versions of Appearance earlier than 1.1 (great).
|
|
if (theControl) {
|
|
GetControlTitle (theControl, title);
|
|
isPete = StringSame (title, kPeteUserPaneTitleIDString);
|
|
}
|
|
return (isPete);
|
|
}
|
|
|
|
|
|
//
|
|
// PeteUserPaneIdle
|
|
//
|
|
// The idleProc for a PETE user pane. Our idle handling amounts to nothing more
|
|
// than giving time to the nickname watcher if this 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 PeteUserPaneIdle (ControlHandle theControl)
|
|
{
|
|
MyWindowPtr win;
|
|
PETEHandle pte;
|
|
|
|
if (pte = (PETEHandle) GetControlReference (theControl))
|
|
if (win = GetWindowMyWindowPtr(GetControlOwner(theControl)))
|
|
if ((*PeteExtra(pte))->win->pte == pte)
|
|
if (HasNickScanCapability (pte))
|
|
NicknameWatcherIdle (pte);
|
|
}
|
|
|
|
|
|
//
|
|
// PeteUserPaneDraw
|
|
//
|
|
// The drawProc for a PETE user pane. All we need to do is update the PETE
|
|
// if we have a valid PETEHandle.
|
|
//
|
|
|
|
static pascal void PeteUserPaneDraw (ControlHandle theControl, SInt16 part)
|
|
{
|
|
#pragma unused(part)
|
|
PETEHandle pte;
|
|
|
|
if (pte = (PETEHandle) GetControlReference (theControl))
|
|
PeteUpdate (pte);
|
|
}
|
|
|
|
|
|
//
|
|
// PeteUserPaneKeyDown
|
|
//
|
|
// Key down handling for the PETE user pane. We need to handle tabbing ourselves
|
|
// if the user pane is in a dialog, so we do. Everything else gets passed to the
|
|
// normal key down handler in a scary fake event.
|
|
//
|
|
|
|
static pascal ControlPartCode PeteUserPaneKeyDown (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);
|
|
}
|
|
|
|
|
|
static pascal ControlPartCode PeteUserPaneFocus (ControlHandle control, ControlFocusPart action)
|
|
|
|
{
|
|
MyWindowPtr win;
|
|
|
|
win = GetWindowMyWindowPtr(GetControlOwner(control));
|
|
if (!win)
|
|
return (0);
|
|
|
|
PeteSelect (win, win->pte, 0, 0);
|
|
|
|
switch (action) {
|
|
case kControlFocusNextPart:
|
|
PeteFocusNext (win);
|
|
break;
|
|
case kControlFocusPrevPart:
|
|
PeteFocusPrevious (win);
|
|
break;
|
|
}
|
|
PeteSelectAll (win, win->pte);
|
|
return (kControlEditTextPart);
|
|
}
|
|
|
|
//
|
|
// GetPeteDItem
|
|
//
|
|
// Retrieves the PETEHandle from a dialog item. This sure as baked potatos
|
|
// better be a PETE user pane, or all bets are off. (Well, actually, we'll
|
|
// return 'nil)
|
|
//
|
|
|
|
PETEHandle GetPeteDItem (MyWindowPtr dPtr, short itemNo)
|
|
|
|
{
|
|
PETEHandle pte;
|
|
ControlHandle theControl;
|
|
|
|
pte = nil;
|
|
if (theControl = GetDItemCtl (GetMyWindowDialogPtr(dPtr), itemNo))
|
|
if (IsPeteControl (theControl))
|
|
pte = (PETEHandle) GetControlReference (theControl);
|
|
if (!PeteIsValid(pte)) pte = nil;
|
|
return (pte);
|
|
}
|
|
|
|
|
|
//
|
|
// GetPeteDItemTextH
|
|
//
|
|
// Grabs the text from a PETE user pane item, returning it in a Handle
|
|
//
|
|
|
|
Handle GetPeteDItemTextH (MyWindowPtr dPtr, int item)
|
|
|
|
{
|
|
PETEHandle pte;
|
|
Handle hText,
|
|
textH;
|
|
|
|
textH = nil;
|
|
if (pte = GetPeteDItem (dPtr, item)) {
|
|
PeteGetRawText (pte, &hText);
|
|
if (hText) {
|
|
textH = hText;
|
|
HandToHand (&textH);
|
|
}
|
|
}
|
|
return (textH);
|
|
}
|
|
|
|
|
|
//
|
|
// GetPeteDItemText
|
|
//
|
|
// Grabs the text from a PETE user pane item, returning it in a PStr
|
|
//
|
|
|
|
void GetPeteDItemText (MyWindowPtr dPtr, int item, PStr text)
|
|
|
|
{
|
|
PETEHandle pte;
|
|
Handle hText;
|
|
|
|
*text = 0;
|
|
if (pte = GetPeteDItem (dPtr, item)) {
|
|
PeteGetRawText (pte, &hText);
|
|
if (hText) {
|
|
*text = MIN (GetHandleSize (hText),255);
|
|
BlockMoveData (*hText, text + 1, *text);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// SetPeteDItemText
|
|
//
|
|
// Sets the text of a PETE user pane item to a given string.
|
|
//
|
|
|
|
void SetPeteDItemText (MyWindowPtr dPtr, int item, PStr text)
|
|
|
|
{
|
|
PETEHandle pte;
|
|
|
|
if (pte = GetPeteDItem (dPtr, item))
|
|
PeteSetString (text, pte);
|
|
}
|
|
|
|
|
|
//
|
|
// GetControlFromPete
|
|
//
|
|
// Given a PETEHandle, find its user pane control, or 'nil' if no such PETE
|
|
// can be found
|
|
//
|
|
|
|
ControlHandle GetControlFromPete (PETEHandle pte)
|
|
|
|
{
|
|
WindowPtr pteWinWP = GetMyWindowWindowPtr ((*PeteExtra(pte))->win);
|
|
ControlHandle theControl;
|
|
|
|
for (theControl = GetControlList(pteWinWP); theControl; theControl = GetNextControl(theControl))
|
|
if (IsPeteControl (theControl))
|
|
if ((PETEHandle) GetControlReference (theControl) == pte)
|
|
return (theControl);
|
|
return (theControl);
|
|
}
|
|
|
|
|
|
//
|
|
// AllWeAreSayingIsGivePeteAChance
|
|
//
|
|
// Everybody's talkin' 'bout mouse-ism, key-ism, null-ism,
|
|
// modifiers, message masks, concurrent tasks...
|
|
//
|
|
// All we are saaaaaaaying... is give Pete a chance... (repeat)
|
|
//
|
|
// Actually, what we're doing here is giving any PETE user panes a shot
|
|
// at an event that occurs inside of the dialog manager. We do this here
|
|
// (where we are called by MovableModalDialog) so that we don't have to
|
|
// put PETE user pane handling code in lots of different filter procs.
|
|
//
|
|
// Note: Could this function completely go away by just allowing the
|
|
// standard filter proc to hand off events to us via the user
|
|
// pane procs?
|
|
//
|
|
// For now, all we do is check for a click in a PETE user pane, set the
|
|
// item to the item hit, and return true.
|
|
|
|
Boolean AllWeAreSayingIsGivePeteAChance (MyWindowPtr win, EventRecord *event, short *peteItemHit)
|
|
|
|
{
|
|
WindowPtr winWP = GetMyWindowWindowPtr (win);
|
|
Point where;
|
|
short item;
|
|
Boolean hitPETEUserPane;
|
|
|
|
hitPETEUserPane = false;
|
|
|
|
// Make sure this is one of our windows (not a plain old dialog) and check
|
|
// to see whether or not a mouse down event occurred in a PETE field.
|
|
if (IsMyWindow (winWP))
|
|
if (event->what == mouseDown) {
|
|
SetPort (GetWindowPort(winWP));
|
|
where = event->where;
|
|
GlobalToLocal (&where);
|
|
if (item = FindDialogItem (GetMyWindowDialogPtr(win), where) + 1)
|
|
if (GetPeteDItem (win, item)) {
|
|
*peteItemHit = item;
|
|
hitPETEUserPane = true;
|
|
}
|
|
}
|
|
return (hitPETEUserPane);
|
|
}
|