[comp.sys.mac.programmer] How to highlight buttons

jsl@bii.UUCP (jsl) (03/01/90)

I have been trying to figure out how to highlight the default
buttons in a dialog.  However I have been unsuccessfull.  Can
anyone tell me what I am doing wrong.  Below is the code segment
I am using to do this.  Thanks in advance for any help.

    int ItemHit, ItemType;
    DialogPtr AcquDLOG;
    Handle ItemHandle;
    Rect ItemRect;
    GrafPtr SavePort;

    AcquDLOG = GetNewDialog(rParmAcquDLOG, NIL_POINTER, MOVE_TO_FRONT);
    GetPort(&SavePort);
    SetPort(AcquDLOG);
    /*
    Highlight the default button
    */
    GetDItem (AcquDLOG, iAcquOK, &ItemType, &ItemHandle, &ItemRect);
    PenSize (3,3);
    InsetRect(&ItemRect, -4, -4);
    OffsetRect(&ItemRect, 50, 50);
    FrameRoundRect(&ItemRect, 16, 16);
    PenSize (1,1);

======================================================================
Joseph S. Laughlin                                      (508) 667-9739
Sr. NMR Software Specialist                         jsl@bii.bruker.com
======================================================================

Jim.Spencer@p5.f22.n282.z1.FIDONET.ORG (Jim Spencer) (03/03/90)

 >
 >
 >I have been trying to figure out how to highlight the default
 >buttons in a dialog.  However I have been unsuccessfull.  Can
 >anyone tell me what I am doing wrong.  Below is the code segment
 >I am using to do this.  Thanks in advance for any help.
 >...
 >    GetDItem (AcquDLOG, iAcquOK, &ItemType, &ItemHandle, &ItemRect);
 >    PenSize (3,3);
 >    InsetRect(&ItemRect, -4, -4);
 >    OffsetRect(&ItemRect, 50, 50);
 >    FrameRoundRect(&ItemRect, 16, 16);
 >    PenSize (1,1);


I'm probably missing something but why are you calling OffsetRect?

--  
Jim Spencer - via FidoNet node 1:282/33
UUCP: ...!uunet!imagery!22.5!Jim.Spencer
ARPA: Jim.Spencer@p5.f22.n282.z1.FIDONET.ORG

tim@hoptoad.uucp (Tim Maroney) (03/04/90)

In article <288@bii.UUCP> jsl@bii.UUCP (jsl) writes:
>I have been trying to figure out how to highlight the default
>buttons in a dialog.  However I have been unsuccessful.
>
>    GetDItem (AcquDLOG, iAcquOK, &ItemType, &ItemHandle, &ItemRect);
>    PenSize (3,3);
>    InsetRect(&ItemRect, -4, -4);
>    OffsetRect(&ItemRect, 50, 50);
>    FrameRoundRect(&ItemRect, 16, 16);

What's the OffsetRect for?  That is moving your rectangle 50 pixels down and
to the right of where you want it to be.  If the OK button is near the
bottom of the dialog, then you are probably drawing the round rectangle
outside the window.

I do something messy, but convenient, to outline default buttons.
Every dialog has an external dialog information resource that tries to
describe the dialog's behavior non-procedurally as much as possible.
One of the fields is an outline item id.  When I see this on creating a
dialog, I add a new user item to the dialog item list in memory, and
bind a drawing procedure to it.  It goes like this:


typedef struct {
	ProcPtr p;
	Rect r;
	char type;
	char length;
} AUserItem;

	
	if ((*extra)->defButton) {
		AUserItem user;		/* add outline user item */
		GetIRect(dialog, (*extra)->defButton, &user.r);
		InsetRect(&user.r, -4, -4);
		user.p = (ProcPtr)DrawRoundRect;
		user.type = userItem | itemDisable;
		user.length = 0;
		PtrAndHand((Ptr)&user, ((DialogPeek)dialog)->items,
				sizeof(AUserItem));
		(**(short **)(((DialogPeek)dialog)->items))++;
	}


pascal void DrawRoundRect(DialogPtr dialog, short item)
{	Rect r; PenState state;
	GetPenState(&state); PenSize(3, 3);
	GetIRect(dialog, item, &r);
	FrameRoundRect(&r, 16, 16);
	SetPenState(&state);
}

void GetIRect(DialogPtr dialog, short item, Rect *r)
{	short type; Handle h;
	GetDItem(dialog, item, &type, &h, r);
}
-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com

"There's a real world out there, with real people.  Go out and play there for
 a while and give the Usenet sandbox a rest.  It will lower your stress
 levels and make the world a happier place for us all." -- Gene Spafford

jeremyr@cs.qmw.ac.uk (Jeremy Roussak) (03/05/90)

>In article <288@bii.UUCP> jsl@bii.UUCP (jsl) writes:
>I have been trying to figure out how to highlight the default
>buttons in a dialog.  However I have been unsuccessful.
>
[code deleted]

The *very* simple way is to use Default CDEF, a handy utility.  I can't
recall who wrote it (sorry, old chap), but it's free.  All you have
to do is to copy it into your app and put at "at" sign (@) at the
end of the title of your default button.  The @ is removed and the
button highlighted in the recommended manner.  It seems to work
perfectly.

Default CDEF arrived here on comp.binaries.mac a few weeks ago.

Jeremy Roussak

lim@iris.ucdavis.edu (Lloyd Lim) (03/06/90)

In article <288@bii.UUCP> jsl@bii.UUCP (jsl) writes:
>I have been trying to figure out how to highlight the default
>buttons in a dialog.  However I have been unsuccessfull.  Can
>anyone tell me what I am doing wrong.  Below is the code segment
>I am using to do this.  Thanks in advance for any help.
>
>[...]
>    OffsetRect(&ItemRect, 50, 50);

I don't think you need this line.

My Default CDEF also draws outlines for you automatically, with the proper
color and even for unusual sizes.  Plus, it's free!

Disclaimer - Yeah, I wrote it, so what should I disclaim?

+++
Lloyd Lim     Internet: lim@iris.ucdavis.edu (128.120.57.20)
              Compuserve: 72647,660
              US Mail: 146 Lysle Leach Hall, U.C. Davis, Davis, CA 95616

philip@Kermit.Stanford.EDU (Philip Machanick) (03/06/90)

In article <6929@ucdavis.ucdavis.edu>, lim@iris.ucdavis.edu (Lloyd Lim) writes:

> My Default CDEF also draws outlines for you automatically, with the proper
> color and even for unusual sizes.  Plus, it's free!

Sounds good. Since the original posting, I hacked together a quick attempt at
a CDEF to draw the outline around a standard button. It could do with a bit
of work, but it's a nice simple illustration of basics of CDEFs. In
essence, I just special case drawing the control, and pass everything else to
the standard CDEF. If anyone would like to see the human-readable (i.e.,
Pascal) source, e-mail me. I'll post it if there are enough requests.

This thing is really pretty simple, if one doesn't want to get too fancy.
Why doesn't Apple add it as an extra variation on a button? It would then be
a small extension to the dialog manager for it to pick up such a control as
the default item, no matter what its item number (well, if there was only
one such in the dialog).

Philip Machanick
philip@pescadero.stanford.edu

philip@Kermit.Stanford.EDU (Philip Machanick) (03/07/90)

I've had a few requests for this, so here is the source code. I've marked
places I haven't checked on with comments; you should do a bit of testing
before using this (seems ok when I tried it).

This is just a quick hack. I've tried to avoid doing anything
but drawing the highlight, and to pass anything else to the deafult CDEF.
Complication: CDEFs are identified when you ask for a new control by a
number which is 16 times the resource ID of the underlying CDEF (see Inside
Mac Vol 1).

The following was developed in Think Pascal. The project type is Code Resource,
with Purgeable turned on, and resource ID=4). The output is a file
containing a CDEF. Paste this into a resource file for an application, and
create CNTL resources with proc ID 4 (I hope I'm getting this right - my Mac
is at home). You can then paste such resources into dialog boxes. Note that
you need to make a new CNTL resource for each button you need. Alternatively,
you can create the control directly in your program. Examples follow.

-----------listing 1---------------------

unit defaultButton;
interface

function main (varCode: integer;
       theControl: controlHandle;
       message: integer;
       param: longint): longint;

implementation

function callDefProc (varCode: integer;
        theControl: controlHandle;
        message: integer;
        param: longint;
        theProc: ptr): longint;
inline
 $205F,  { movea.L (A7)+}
 $4E90;  { A0  jsr(A0) }

function main (varCode: integer;
        theControl: controlHandle;
        message: integer;
        param: longint): longint;
 const
  buttonDefProcID = 0;
 var
  itsRect: rect;
  oldPenState: PenState;
  defaultProc: handle;
 begin
  itsRect := theControl^^.contrlRect;
 {in all other cases, fool real button into thinking its rect is smaller}
  if message <> calcCRgns then begin
{haven't checked if this is necessary... an exercise for the reader}
   InsetRect(itsRect, 4, 4);
 {must do extra step because contrlRect is a component of a packed record}
   theControl^^.contrlRect := itsRect;
  end; {if}
  defaultProc := getResource('CDEF', buttonDefProcID);
  hLock(handle(defaultProc));
  main := callDefProc(varCode, theControl, message, param, ptr(defaultProc^));
  hUnlock(handle(defaultProc));
  if message <> calcCRgns then begin {revert saved version of rect to
actual size}
   InsetRect(itsRect, -4, -4);
   theControl^^.contrlRect := itsRect;
  end; {if}
  if message = drawCntl then begin
{not sure how much of this is necessary, e.g., whether pen is guaranteed to}
{be in penNormal state when CDEF is called}
   getPenState(oldPenState);
   penMode(patCopy);
   penSize(3, 3);
   frameRoundRect(itsRect, 16, 16);
   setPenState(oldPenState);
  end; {if}
 end; {main}

end. {defaultButton}

-----------end listing 1---------------------

The following example requires a resource file with a DLOG ID=100, with an
item no. 1 in it. If that item is one of these special new buttons, it will
appear on the DLOG, and behave exactly like a button, except it will be
outlined.

Missing: because the new control is not a button as far as the dialog manager
is concerned, pressing RETURN or ENTER does not select it automatically if
it's item 1 (sigh).

-----------listing 2---------------------

program tryDefButton;
const
 tryDialogID = 100;
 highlightItem = 1;
 CDEFid = 64;  {NB: NOT the resource ID; the CDEF resource ID is this
number / 16 = 4}

 var
  DLOGStorage: DialogRecord;
  oldPort: GrafPtr;
  tryDialog: DialogPtr;
  item: integer;
{ itsRect: rect; itsType: integer;  ignoreHandle: handle; }
{ theControl : controlHandle; }

begin
 getPort(oldPort);
 tryDialog := GetNewDialog(tryDialogID, @DLOGStorage, WindowPtr(-1));
{if you want to create the control dynamically, e.g., replace a userItem,}
{reinstate the following 3 lines, and declaration of itsRect etc. above}
{getDItem(tryDialog, highlightItem, itsType, ignoreHandle, itsRect);}
{theControl := newControl(tryDialog, itsRect, 'button', true, 0, 0, 1,
CDEFid, 0);}
{setDItem(tryDialog, highlightItem, ctrlItem, handle(theControl), itsRect);}
 showWindow(tryDialog);
 setPort(tryDialog);
 repeat
  ModalDialog(nil, item);
{ do something }
  if not eof then
   readln
 until eof; {in Think, signalled by ENTER}
 setPort(oldPort);
end. {tryDefButton}

-----------end listing 2---------------------

Philip Machanick
philip@pescadero.stanford.edu

lim@iris.ucdavis.edu (Lloyd Lim) (03/08/90)

In article <1990Mar6.195441.6794@Neon.Stanford.EDU> philip@pescadero.stanford.edu writes:
>I've had a few requests for this, so here is the source code. I've marked
>places I haven't checked on with comments; you should do a bit of testing
>before using this (seems ok when I tried it).
>
>This is just a quick hack. I've tried to avoid doing anything
>but drawing the highlight, and to pass anything else to the deafult CDEF.
>Complication: CDEFs are identified when you ask for a new control by a
>number which is 16 times the resource ID of the underlying CDEF (see Inside
>Mac Vol 1).
>
>[...]
>
>Missing: because the new control is not a button as far as the dialog manager
>is concerned, pressing RETURN or ENTER does not select it automatically if
>it's item 1 (sigh).
>
>[...]
>
>Philip Machanick
>philip@pescadero.stanford.edu

There are a few other things I considered when I wrote my Default CDEF:
(that I can remember of the top of my head)

- it's a little better to use HGetState and HSetState just in case
- the outline grays if the button is disabled
- the outline is the same color as the button frame
- the outline looks correct even if the button isn't 16 pixels high

Also, Default is a real button so there's no problem with CNTLs or pressing
return or enter.  It also lets you change buttons on the fly, so you could
add an outline to the Open button in the SFGetFile dialog just by changing
the title to Open@.

I've been asking $5 for the source to Default but if you really are writing
your own, you might as well benefit from the testing I did.  So if you ask
me nicely, I will send the source to you free via e-mail (requests via
regular mail are still $5).  I prefer however to make the source available on
request only and also prefer that you not redistribute the source.

The source is really only useful for DAs and such since you can't attach a
CDEF 0 in that case.  The Default source is not helpful in writing a CDEF for
your own type of control because Default doesn't act like any normal control.
About the only useful thing you'd get out of the source is the CDEF routine
declaration and its parameters.

Actually, I would be glad if Apple got its act together and eliminated the
need for this stuff by just defining another variation code and adding a few
lines of code to the standard CDEF 0.  I think Default should work with any
System but Apple is the only one who can guarantee things like that.

+++
Lloyd Lim     Internet: lim@iris.ucdavis.edu (128.120.57.20)
              Compuserve: 72647,660
              US Mail: 146 Lysle Leach Hall, U.C. Davis, Davis, CA 95616