BUTTONS ------------------------------------------------------------- Buttons are things that you attach to frames. Pressing a button (by pointing with the mouse cursor and pressing the left mouse button) is an event, so a button must have an associated event-handler. Procedure DefineSquareButtonText(ifs : ImageStkPtr; x1, y1, x2, y2, rx, ry: Word; Msg: String; Event: CallProc); This will draw a square button on the frame ifs. x1, y1, x2, y2 are relative coordinates on the frame where the button will be drawn. rx and ry are offsets to draw the text msg at. Event is the event-handler to call when the button is pressed. Function VisualSquareButtonPress(ifs: ImageStkPtr; ms: MsClickPtr): Boolean; This function presses a squarebutton down and then returns TRUE if the mouse button was released while the mouse pointer was over the button. This function should be called from within an event-handler and would be passed the same parameters that were passed to the event-handler. The event-handler would use the return value to determine if an action is required (i.e. if TRUE). If so then the first thing that should be done is a call to ReleaseSquareButton which will pop the button back up. If VisualSquareButtonPress returns FALSE then ReleaseSquareButton is called automatically and the event-handler should not call it. Procedure ReleaseSquareButton(ifs: ImageStkPtr; ms: MsClickPtr); This will release a button that was previously pressed by VisualSquareButtonPress. This example shows the complete use of a button attached to a frame. When the button is pressed and released then the frame is disposed of. BEGINFILE> button1.pas {-- button1.pas} {$F+} USES teglunit,teglmain; VAR ifs : ImageStkPtr; function cancelevent(frame: ImageStkPtr; mouse: MsClickPtr): Word; BEGIN {-- if true then the button has been released } if VisualSquareButtonPress(frame,mouse) then begin {-- this will pop the button back up } ReleaseSquareButton(frame,mouse); {-- and dispose of the frame. } dropstackimage(ifs); end; END; BEGIN easytegl; easyout; PushImage(50,50,200,150); ShadowBox(50,50,200,150); ifs := StackPtr; DefineSquareButtonText(ifs,30,35,120,65,5,5,'PRESS ME',cancelevent); TeglSupervisor; END. ENDFILE> Buttons can have more than text displayed on them. In true GUI fashion buttons might have appropriate icons displayed on them to indicate their purpose. Procedure DefineSquareButtonClick(ifs: ImageStkPtr; x1, y1, x2, y2, rx, ry: Word; button: pointer; event: CallProc); DefineSquareButtonClick is the same as DefineSquareButtonText above except that an icon is displayed on the button instead of text. This example creates a frame with squarebutton that shows a lightbulb icon. BEGINFILE> button2.pas {-- button2.pas} {$F+} USES moreicon,teglunit,teglmain; VAR ifs : ImageStkPtr; function cancelevent(frame: ImageStkPtr; mouse: MsClickPtr): Word; BEGIN {-- if true then the button has been released } if VisualSquareButtonPress(frame,mouse) then begin {-- this will pop the button back up } ReleaseSquareButton(frame,mouse); {-- and dispose of the frame. } dropstackimage(ifs); end; END; BEGIN easytegl; easyout; PushImage(50,50,200,150); ShadowBox(50,50,200,150); ifs := StackPtr; DefineSquareButtonClick(ifs,30,35,120,65,35,5,@ImageBulb,cancelevent); TeglSupervisor; END. ENDFILE> It may be useful at some time to have a button floating around by itself. The easyout button that is displayed at the bottom right corner of the screen is just such a button. In fact it is a frame with a button that is the full size of the frame. We can use these for other purposes. This example places two floating buttons on the screen, one with a 5.25" floppy disk icon and the other with a 3.5" floppy disk icon. BEGINFILE> button3.pas {-- button3.pas} {$F+} USES moreicon,teglunit,teglmain; function Disk35event(frame: ImageStkPtr; mouse: MsClickPtr): Word; BEGIN {-- if true then the button has been released } if VisualSquareButtonPress(frame,mouse) then begin {-- this will pop the button back up } ReleaseSquareButton(frame,mouse); end; END; function Diskevent(frame: ImageStkPtr; mouse: MsClickPtr): Word; BEGIN {-- if true then the button has been released } if VisualSquareButtonPress(frame,mouse) then begin {-- this will pop the button back up } { ReleaseSquareButton(frame,mouse); } end; END; BEGIN easytegl; easyout; PushImage(0,09,39,49); DefineSquareButtonClick(stackptr,0,0,39,39,5,5,@ImageDisk,diskevent); PushImage(0,49,39,89); DefineSquareButtonClick(stackptr,0,0,39,39,5,5,@ImageDisk35,disk35event); TeglSupervisor; END. ENDFILE> One of the things that can go wrong is forgetting to release a square button once it is pressed. Try commenting out one of the ReleaseSquareButton calls from the previous program and see what happens when the button is pressed repeatedly. The next example gives a complete illustration of a floating button that opens up a window to do something. Important items to note here are: * the use of a control variable to keep track of a frame that you don't want more than one instance running. * setting the viewport to cover a frame, you don't have to calculate the relative displacement for text or graphics then. * using more than one button on a frame. Each with its own event. BEGINFILE> button4.pas {-- button4.pas} {$F+} USES teglfont,moreicon,fastgrph,tgraph,teglunit,teglmain; {-- a control variable to make sure that only one instance of the } {-- format frame is displayed } CONST FormatInstance : Boolean = FALSE; function FormatEvent(frame: ImageStkPtr; Mouse: MsClickPtr): Word; BEGIN if VisualSquareButtonPress(frame,mouse) then BEGIN ReleaseSquareButton(frame,mouse); SetViewPort(0,0,Getmaxx,getmaxy,clipoff); ErrMess(GetMaxx DIV 4,GetMaxy DIV 4,'Function not compete!'); END; END; function CancelEvent(frame: ImageStkPtr; Mouse: MsClickPtr): Word; BEGIN if VisualSquareButtonPress(frame,mouse) then BEGIN ReleaseSquareButton(frame,mouse); DropStackImage(frame); FormatInstance := FALSE; END; END; function Diskevent(frame: ImageStkPtr; mouse: MsClickPtr): Word; VAR ifs : ImageStkPtr; BEGIN {-- if true then the button has been released } if VisualSquareButtonPress(frame,mouse) then begin {-- this will pop the button back up } ReleaseSquareButton(frame,mouse); if FormatInstance THEN BEGIN SetViewPort(0,0,GetMaxx,GetMaxy,clipoff); ErrMess(200,100,'The format window is open'); exit; END; FormatInstance := TRUE; SetViewPort(0,0,getmaxx,getmaxy,clipoff); {-- fullscreen } QuickFrame(ifs, 100, 100, {-- upper corner } 200, 100); {-- width & height } SetTeglFont(@Font14); {-- setting the viewport to the frame makes it easy } {-- for outputting text and graphics. } PrepareForUpdate(ifs); SetViewPort(ifs^.x,ifs^.y,ifs^.x1, ifs^.y1,clipon); SetTextJustify(centertext,toptext); OutTextXY(100,20,'Format a disk?'); SetTextJustify(lefttext,toptext); CommitUpdate; DefineSquareButtonText(ifs,20,70,60,90,10,5,'OK',FormatEvent); DefineSquareButtonText(ifs,110,70,180,90,10,5,'CANCEL',CancelEvent); end; END; BEGIN easytegl; easyout; setautorotate(TRUE); PushImage(0,09,39,49); DefineSquareButtonClick(stackptr,0,0,39,39,6,4,@ImageDisk,diskevent); SetTeglFont(@f5x6norm); SetColor(Black); OutTextXy(4,33,'Format'); OutTextXy(9,40,'Disk'); TeglSupervisor; END. ENDFILE> This example illustrates how mouse click numbers are associated with a button. It draws frame with fifty number buttons on it that display their button numbers when clicked on. This shows how easy it is to set up a matrix of buttons. The important part of this program is how the event-handler (ShowNumber) can determine which button was pressed. Consider how straight forward it would be to implement a calculator. BEGINFILE> button5.pas {-- button5.pas} {$F+} USES teglfont,moreicon,fastgrph,tgraph,teglunit,teglmain; function itos(i : Integer): String; VAR s : String; BEGIN str(i,s); itos := s; END; function ShowNumber(frame: ImageStkPtr; mouse: MsClickPtr): Word; BEGIN {-- if true then the button has been released } if VisualSquareButtonPress(frame,mouse) then begin {-- this will pop the button back up } ReleaseSquareButton(frame,mouse); PrepareForUpdate(frame); SetViewPort(frame^.x,frame^.y,frame^.x1,frame^.y1,clipon); setfillstyle(solidfill,white); bar(5,110,210,130); setteglfont(@f8x12bol); {-- the mouse pointer contains what clicknumber it was } {-- assigned to. } OutTextXY(5,112,'Button '+itos(mouse^.clickNumber)); CommitUpDate; end; END; Procedure ButtonBunch; VAR i,xd,yd : integer; ifs : ImageStkPtr; BEGIN SetViewPort(0,0,Getmaxx,getmaxy,clipoff); QuickFrame(ifs,100,100,222,140); xd := 0; yd := 0; for i := 1 to 50 do BEGIN {-- as we define each button we put its clicknumber on it} {-- note that MsClickCount would only be the correct on return} {-- so we add one to it. } SetTeglFont(@f7x7bold); DefineSquareButtonText(ifs,xd,yd,xd+20,yd+20,3,8, itos(ifs^.MsclickCount+1),ShowNumber); xd := xd + 22; if xd > 200 then begin xd := 0; yd := yd + 22; end; END; END; BEGIN easytegl; easyout; buttonbunch; TeglSupervisor; END. ENDFILE> Things to remember! * Square button arguments are RELATIVE to the frame they are being attached to. * A square button is just another mouse click on a frame. The ImageStkPtr that is passed to DefineSquareButtonClick or DefineSquareButtonText will contain the clicknumber of the on return in the MsClickCount field. * You can make floating buttons by making the button and the frame the same size. * Beware of viewport settings. Many routines assume that the viewport and text settings are the startup defaults. If in doubt do a SetViewPort(0,0,Getmaxx,Getmaxy,Clipoff) and SetTextJustify(LeftText,TopText). ---------------------------------------------------------- END buttons.txt