home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #3
/
amigamamagazinepolishissue1998.iso
/
maksiu
/
extensions
/
jwindows.lha
/
Paint.asc
< prev
next >
Wrap
Text File
|
1996-04-25
|
15KB
|
438 lines
'Note:
' You may have trouble running this program from the editor. If so,
'change the Path$ variable in INITIALISE to point to the directory this
'example is in. This isn't a problem when compiled.
'********************************************************************
'*
'* Painter
'*
'********************************************************************
' This is a very simple paint program, an extension of the scribble
'example. It is, admittedly rather hampered by the lack of a fill command,
'but what the hell...
' Here we demonstrate a rather larger program than has been used before,
'involving two windows (two WHOLE windows??!), a painting area and a palette.
'It shows the use of super windows, gimme zero zero windows, and the custom
'scroller routines provided in the Scroller.amos example. We open a super
'window with an actual area the size and depth of the workbench screen,
'and then scroll around this using J Scroll Super Window. Other stuff has
'all been seen before, such as basic gadgets, menus and drawing commands.
'There are alot of extra IDCMP messages used here, such as INTUITICKS for
'the spray can, and the WA_MouseQueue tag for the window.
' Some changes have been made to the GadToolsBox source:
' The variable SD has been added to hold the default screen depth. The
'palette gadget will be drawn with this number of planes. The art window
'has been changed into a super window, the size and depth of the default
'screen. The J Close Window line in _FREE_WINDOW has been changed to
'J Close Super Window. This is safe to call on non-super windows.
' Other minor changes have been made for stuff I forget to add in the
'GadToolsBox program (bad planning).
' The scroller routines added are explained in the Scroller.amos program,
'the advantage being that they automatically resize and move when the window
'changes. They are handled as follows:
' The size of each scroller is the size of the drawing area the window
'contains. The visible area (the size of the widget on the scroller) is the
'actual size of the window.
' We then track the offset of the drawing area from the top left of the
'window using the variables _SBX,_SBY. Sliding the bottom scroller distance
'x to the right will put the top left of the drawing area distance -x from the top
'top left of the window, and _SBX is set to the value x.
' When the window is resized, we must change the size of the widget in the
'scroller to reflect the new area we are representing. We may also need to
'move the drawing area. This will occur when the user is looking at the bottom
'right of the drawing area, then enlarges the window. The drawing area must
'be moved right and down to prevent the window showing a region off the edge
'of the drawing area.
' A technique of use to other art program writers shown here is rubber
'banding. An interesting feature of Gr Writing 2 is that if you draw a shape,
'then draw exactly over it again, the image is restored exactly as it was.
'This allows us to rubber band shapes like lines or bars so the user can
'experiment with where the shape should go before placing it. The shape is
'then drawn with Gr Writing 0.
Global _SCRAPTAGS,SCRAPTAGS,_PORTLIST,_MESSLIST
Global PATH$,OSVER
'** SD was put here with the rest of the prefs
Global FHEIGHT,FWIDTH,MBAR,OX,OY,SW,SH,SD
Dim _ARTGADS(0)
Global _ARTGADS()
Global _ARTMENU,_ARTMENADD
Global _ARTWIND
Dim _PALETTEGADS(1)
Global _PALETTEGADS()
Global _PALETTE
Dim _PALETTEZOOM(1)
Global _PALETTEZOOM()
Global _PALETTEWIND
On Error Proc _CLEANUP
'** _SCRLLERS is used to represent the border scroller gadgets.
' _SBX, _SBY are the offset of the top left of the window from the top
' left of the drawing area.
Global _SCRLLERS
Global _SBX,_SBY
'** _DRAW is 1 when the LMB is pressed, 0 when it isn't.
' _TYPE is the drawing mode 0-6, in the same order the tools are on the
' tools menu. Defaults to free hand (1)
' _OX, _OY hold the origin of a drawing operation (a line, or whatever)
' _LX, _LY hold the position we last drew to so we can draw over it again
' for rubber banding purposes.
Global _DRAW,_TYPE,_OX,_OY,_LX,_LY
_TYPE=1
_INITIALIZE
_GUIDATA
_SETUPALL
_SETPORTS
'Make sure we draw to the right window
J This Window _ARTWIND
Do
K=J Wait Message
While K
C=J Tag Data(_MESSLIST,1)
If C=Equ("IDCMP_CLOSEWINDOW")
'Bring up a requester before quiting
If J Easy Request(_ARTWIND,"Quit"," Are you ure you"+Chr$(10)+"want to quit?"," Quit | Cancel ",0)
_CLEANUP
End If
Else If C=Equ("IDCMP_REFRESHWINDOW")
_DOREFRESH
Else If J Tag Data(_MESSLIST,9)=_ARTWIND
'There is a lot of handling, so I've stuck it in another procedure.
_HANDLE_ARTWIND[C]
Else If J Tag Data(_MESSLIST,9)=_PALETTEWIND
'The only interesting event from the palette window is the user
'picking a colour, so watch for this
If C=Equ("IDCMP_GADGETUP")
J This Window _ARTWIND
J Ink J Tag Data(_MESSLIST,2)
End If
End If
K=J Next Message
Wend
Loop
'This is the biggy...
Procedure _HANDLE_ARTWIND[C]
On Error Proc _CLEANUP
If C=Equ("IDCMP_IDCMPUPDATE")
'First off, deal with the scrollers being moved. We get the position
'of each (just to make sure we didn't miss anything), as X and Y.
'We then check they aren't both in the same place (don't move if you
'don't need to...)
'Finally, we move the scroll the window, and change _SBX and _SBY
_GETSCROLLERPOS[_SCRLLERS,True]
X=Param
_GETSCROLLERPOS[_SCRLLERS,False]
Y=Param
If X<>_SBX or Y<>_SBY
J Scroll Super Window _ARTWIND,X-_SBX,Y-_SBY
_SBX=X : _SBY=Y
End If
Else If C=Equ("IDCMP_NEWSIZE")
'Here we deal with the user resizing the window.
'First get the window's new size (inner size, that is)
IW=J Window Width-J X Offset-J Border Right-1
IH=J Window Height-J Y Offset-J Border Bottom-1
'Now we check if further scrolling is required to keep only the
'drawing area visible. I'm not even going to attempt explaining the
'twisted logic in these formulas - I can't remember, and I only wrote
'them half an hour ago...
DX=0 : DY=0
If IW>-_SBX+SW
DX=IW+_SBX-SW
End If
If IH>-_SBY+SH
DY=IH+_SBY-SH
End If
J Scroll Super Window _ARTWIND,-DX,-DY
_SBX=_SBX-DX : _SBY=_SBY-DY
'Finally, we adjust the size of the widget in the scrollers
J Tag SCRAPTAGS,1,Equ("PGA_Visible"),IW
J Tag 0,0
_SETSCROLLERDATA[_ARTWIND,_SCRLLERS,True,SCRAPTAGS]
J Tag SCRAPTAGS,1,Equ("PGA_Visible"),IH
_SETSCROLLERDATA[_ARTWIND,_SCRLLERS,False,SCRAPTAGS]
Else If C=Equ("IDCMP_MOUSEBUTTONS")
If J Tag Data(_MESSLIST,2)=Equ("SELECTDOWN")
'If the user pressed the LMB:
'Put us in drawing mode, and make the origin (_OX,_OY) this position
'We also move the graphics cursor to here and set the last position
'to here. Various of these are necessary for various drawing
'operations.
'We also change the drawing mode if this operation requires rubber
'banding.
_DRAW=1
_OX=J Tag Data(_MESSLIST,5)-J X Offset+_SBX
_OY=J Tag Data(_MESSLIST,6)-J Y Offset+_SBY
_LX=_OX : _LY=_OY
Gr Locate _OX,_OY
If _TYPE>1 and _TYPE<6
Gr Writing 2
Else
Gr Writing 0
End If
Else If J Tag Data(_MESSLIST,2)=Equ("SELECTUP")
'If the user released the LMB:
'Take us out of drawing mode.
'Fill in the shape. If there was rubber banding, we actually draw
'it twice, but this is a very minor bug.
_DRAW=0
_LX=J Tag Data(_MESSLIST,5)-J X Offset+_SBX
_LY=J Tag Data(_MESSLIST,6)-J Y Offset+_SBY
Gr Writing 0
_DRAW[_LX,_LY]
End If
Else If C=Equ("IDCMP_MOUSEMOVE") and _DRAW
'If the user has moved the mouse in drawing mode, we do the drawing
'operation.
_DRAW[J Tag Data(_MESSLIST,5)-J X Offset+_SBX,J Tag Data(_MESSLIST,6)-J Y Offset+_SBY]
Else If C=Equ("IDCMP_INTUITICKS") and _DRAW and _TYPE=6
'INTUITICKS sends about 5-10 messages a second, which we need for
'the spray can so the user can hold it in one place and spray.
_DRAW[J Tag Data(_MESSLIST,5)-J X Offset+_SBX,J Tag Data(_MESSLIST,6)-J Y Offset+_SBY]
Else If C=Equ("IDCMP_MENUPICK")
'Finally, the menus. Read them off in the normal way...
C=J Tag Data(_MESSLIST,2)
M=J Read Menu(C)
I=J Read Item(C)
If M=0
If I=0
'If New Project was selected, request then do it.
If J Easy Request(_ARTWIND,"Clear Screen","Sure you want to"+Chr$(10)+"clear the screen?"+Chr$(10)+"No undo is possible!"," Clear | Cancel ",0)
J This Window _ARTWIND
J Cls 0
End If
Else If I=2
'Quit, as usual, calls up a requester before doing it.
If J Easy Request(_ARTWIND,"Quit"," Are you ure you"+Chr$(10)+"want to quit?"," Quit | Cancel ",0)
_CLEANUP
End If
End If
Else If M=1
'Change the type of tool we're using at the moment.
_TYPE=I
End If
End If
End Proc
'another biggy...
Procedure _DRAW[X,Y]
On Error Proc _CLEANUP
'X,Y are the current mouse coordinates.
If _TYPE=0
'Dots: just put a point under the mouse
Plot X,Y
Else If _TYPE=1
'Free hand: Draw a line from where we last were to where we are now.
Draw To X,Y
Else If _TYPE=2
'Lines: First, draw to the last position. Because we're rubber banding,
'this will erase the last line. Then draw a new line.
Draw _OX,_OY To _LX,_LY
Draw _OX,_OY To X,Y
_LX=X : _LY=Y
Else If _TYPE=3
'Boxes: Just like Lines.
Box _OX,_OY To _LX,_LY
Box _OX,_OY To X,Y
_LX=X : _LY=Y
Else If _TYPE=4
'Ellipses: First, calculate x and y radii for the ellipse, then if
'these are both greater than 1, draw the ellipse. This is done twice
'for rubber banding.
RX=Abs(_OX-_LX) : RY=Abs(_OY-_LY)
If RX=>1 and RY=>1
Ellipse _OX,_OY,RX,RY
End If
RX=Abs(_OX-X) : RY=Abs(_OY-Y)
If RX=>1 and RY=>1
Ellipse _OX,_OY,RX,RY
End If
_LX=X : _LY=Y
Else If _TYPE=5
'Bars: Should be like boxes, but AMOS's bar command is over-sensitive.
'If the coordinates are the wrong way round, we must swap them, other
'wise an error is generated. This requiers two temporary variables.
'Also, the box must be at least 1x1 in size, so check that.
TX=_OX : TY=_OY
If TX>_LX : Swap TX,_LX : End If
If TY>_LY : Swap TY,_LY : End If
If _LX>TX and _LY>TY
Bar TX,TY To _LX,_LY
End If
_LX=X : _LY=Y
TX=_OX : TY=_OY
If TX>X : Swap TX,X : End If
If TY>Y : Swap TY,Y : End If
If X>TX and Y>TY
Bar TX,TY To X,Y
End If
Else If _TYPE=6
'Spray Can: This splatters pointers in a circle, radius 10. First
'we take a random point within 10 pixels of the cursor, then check
'this is within a circle radius 10 (otherwise, we get a square).
'The formula is x^2 + y^2 <= radius^2, which defines a circle
For I=0 To 4
DX=Rnd(20)-10 : DY=Rnd(20)-10
If DX^2+DY^2<=100
Plot X+DX,Y+DY
End If
Next I
End If
End Proc
Procedure _INITIALIZE
'** Added the SD=J Screen Depth line
Procedure _SETUPALL
Procedure _GUIDATA
Procedure _MAKEARTGADS
'** Changed to a super window, and added scrollers
Procedure _MAKEARTWIND[SC]
'** changed so depth of palette gadget = SD
Procedure _MAKEPALETTEGADS
Procedure _MAKEPALETTEWIND[SC]
Procedure _DOREFRESH
Procedure _SETPORTS
'** chaged J Close Window to J Close Super Window
Procedure _FREEWIND[W,G,M,A,C]
'** added line to free scrollers
Procedure _CLEANUP
'************************************************************************
' scrollers = _CREATESCROLLERS[ window, right total, right visible,
' botom total, bottom visible]
' When you get an IDCMP message from one of the scrollers, it will be of
'class IDCMP_IDCMPUPDATE, and the code field will contain 0 if it is the
'right slider or 1 if it's the bottom one. You can then get the slider height
'using _GETSCROLLERPOS.
Procedure _CREATESCROLLERS[W,RT,RV,BT,BV]
'************************************************************************
' _FREESCROLLERS[ scrollers ]
Procedure _FREESCROLLERS[G]
On Error Goto E
'quit if there is no gadget list
If G=False Then Goto E
'get the address of the map from the first gadget and free it.
T=Leek(G+Equ("gg_UserData"))
If T Then T=J Free Mem(T,12)
'get the address of the bottom gadget
N=Leek(G+Equ("gg_NextGadget"))
'free the right gadget
Areg(0)=G
V=Intcall(Lvo("DisposeObject"))
'free the bottom gadget (if it was successfully created).
If N
Areg(0)=N
V=Intcall(Lvo("DisposeObject"))
End If
E:
End Proc
'************************************************************************
' position = _GETSCROLLERPOS[ scrollers, which? ]
Procedure _GETSCROLLERPOS[G,X]
If G=0 Then Goto E
'the attribute we want
Dreg(0)=Equ("PGA_Top")
'the gadget we want
If X
G=Leek(G)
End If
Areg(0)=G
'the result is stored here
R=0
Areg(1)=Varptr(R)
'call the function
V=Intcall(Lvo("GetAttr"))
E:
End Proc[R]
'************************************************************************
' _SETSCROLLERDATA[ window, scrollers, which?, taglist ]
' Very similar to J Set Gadget Data, this command allows you to change
'the total area, visible area and slider position of a scroller. The tags
'to use are PGA_Total, PGA_Visible and PGA_Top, and provide a taglist just
'as for J Set Gadget Data.
Procedure _SETSCROLLERDATA[W,G,X,T]
'************************************************************************
' _ADDSCROLLERS[ window, scrollers ]
Procedure _ADDSCROLLERS[W,G]
On Error Goto E
If G=0 or W=0 Then Goto E
Areg(0)=W
Areg(1)=G
Dreg(0)=-1
Dreg(1)=-1
Areg(2)=False
V=Intcall(Lvo("AddGList"))
Areg(0)=G
Areg(1)=W
Areg(2)=False
Dreg(0)=-1
V=Intcall(Lvo("RefreshGList"))
E:
End Proc