'Mini Paint - A demonstration paint program for OZAmiga Magazine 
'             AMOS Tutorial #3.
'             By Neil McKnight 1993 - may be freely distributed. 

'Special features: 
'  - Easy to use, mouse operated.
'  - A variety of simple drawing tools.
'  - Save and Load your pictures.
'  - DPaint type "brush" drawing.
'  - UNDO that undoes right back to last drawing tool change.



'Storage for the control panel, so we can see the selected drawing mode.   

Dim Z(15,3)

'Make these global to all procedures as we will use them alot. 

Global X1,Y1,X2,Y2,Z()



'Create the control panel from a spacked screen. 
'  This will also set up the default palette for us. 

Unpack 10 To 0
Screen Display 0,,265,,



'Set up zones for the draw mode controls. Eg Line, Box etc.
'  I used DATA statements rather than calculating them because the 
'  calculations can be rather confusing if you don't know what's going on. 
'  NOTE: the palette zones are set up in SET_PALETTE 

Restore CONTROL_ZONE_DATA
Read NUMBER_CONTROLS
Reserve Zone NUMBER_CONTROLS+32

'I read in a string called GUFF$ which just lets me know what peice of data  
'  is for which button.  Look at the DATA statements.  

For L=1 To NUMBER_CONTROLS
   Read GUFF$,Z(L,0),Z(L,1),Z(L,2),Z(L,3)
   Set Zone L+32,Z(L,0),Z(L,1) To Z(L,2),Z(L,3)
Next 



'Set up undo screen as another screen identical to the drawing screen. 
'  I then copy the entire drawing screen to the undo screen whenever 
'  you change drawing modes.  This means you have control over where 
'  you UNDO to.  It's not the most memory efficient method, but I wrote
'  this at one sitting...

Screen Open 3,320,256,32,Lowres
Flash Off : Curs Off 
Get Palette 0
Cls 0
Screen Hide 



'Set up drawing screen.  We have to go through the same sequence as for
'  the Undo screen.  A simple SCREEN COPY won't work.  

Screen Open 1,320,256,32,Lowres
Flash Off : Curs Off 
Get Palette 0
Paper 0 : Pen 1
Cls 
Screen To Back 



'Setting up. 
'We make sure the mouse is free to roam the entire screen. 
'  NOTE: If you don't call Wait Vbl before Limit Mouse it is not always
'  reliable... 

Wait Vbl 
Limit Mouse 

'Show the current palette.   

SEE_PALETTE[2]

'Say hello.

Gosub HELLO

'Set the starting draw mode to DRAW FREEHAND and highlight it. 

COMMAND=3
OLD_COMMAND=COMMAND
SEE_CONTROL[COMMAND]



'The main loop.
'  Here we process the users selection, branching off to a different 
'  subroutine for each item.  Only the colour selection and a few
'  "kludges" are present in this loop.  A "Kludge" is something the
'  programmer does to make a certain function work correctly when the
'  normal method causes problems.
'  This loop will repeat until the user clicks the logo on the control 
'  panel.  This is the quit button.

QUIT=False
Repeat 

   'Wait for a mouse click. 

   CLICK

   'Go to the control panel screen and find out if a button is clicked on.

   Screen 0
   MZ=Mouse Zone

   'The lowest 32 buttons are the colour selections.  This makes life 
   '  easier to work out what colour they want. 

   If MZ>0 and MZ<33

      'A Colour was selected!  Make it the current colour. 

      SEE_PALETTE[MZ-1]

      'Kludge #1 - FILL tried to fill the entire screen if you changed 
      '  colours while in fill mode.  This stops it. 

      If OLD_COMMAND=2 : OLD_COMMAND=0 : End If 
   End If 
   If MZ>32

      'A Command was selected!  Work out which one and highlight it. 

      COMMAND=MZ-32
      SEE_CONTROL[COMMAND]

      'Copy the drawing screen to the Undo screen when the drawing 
      '  command changes.  Except if UNDO was selected of course...

      If COMMAND<>13
         Screen Copy 1 To 3

         'Kludge #2 - set a flag so that undo only works once.

         UNDONE=False
      End If 
   End If 

   'Jump to the drawing screen and do something!

   Screen 1
   On COMMAND Gosub USE_LINE,USE_FILL,USE_DRAW,USE_DOTTY,USE_CIRCLE,USE_ELLIPSE,USE_BOX,USE_BAR,USE_GRAB,USE_TEXT,PIC_LOAD,PIC_SAVE,PIC_UNDO,PIC_CLEAR,ENABLE_QUIT

   'Remember what it was we just did (see Kludges)

   OLD_COMMAND=COMMAND
Until QUIT
End 



'LINE tool - draws rays originating from the start point.
'  Note the mouse coord -> screen coord conversion.

USE_LINE:
X1=X Screen(X Mouse) : Y1=Y Screen(Y Mouse)
Repeat 
   Draw X1,Y1 To X Screen(X Mouse),Y Screen(Y Mouse)
   Wait Vbl 
Until Mouse Key=0
Return 



'FILL tool - fills an enclosed area with current drawing colour. 
'  Kludge #3 - the first fill has an extra mouse click added so it 
'  doesn't try to fill the entire screen before you click somewhere. 
'  This means you should select the fill colour, BEFORE selecting the  
'  Fill tool.  The routine expects the first click to select the area  
'  to fill.
'  Otherwise, the area under the palette selection will be filled, 
'  and you will need to Undo it. 
'  You can change colours as much as you like between fills. 

USE_FILL:
If OLD_COMMAND<>2 Then CLICK
Paint X Screen(X Mouse),Y Screen(Y Mouse)
Return 



'FREEHAND DRAW tool - lets you draw wiggly lines all over the screen.
'  The Plot is where you click.  Note the Wait Vbl instruction.  It is 
'  needed to slow down the loop so things have time to update correctly. 

USE_DRAW:
Plot X Screen(X Mouse),Y Screen(Y Mouse)
Repeat 
   Draw To X Screen(X Mouse),Y Screen(Y Mouse)
   Wait Vbl 
Until Mouse Key=0
Return 



'DOTTY DRAW tool - like Freehand Draw, but draws dots. 

USE_DOTTY:
Repeat 
   Plot X Screen(X Mouse),Y Screen(Y Mouse)
   Wait Vbl 
Until Mouse Key=0
Return 



'CIRCLE tool - calls Rubber_Box to find out where you want to put it,
'  then works out where the centre goes and starts from there. 
'  The diameter is taken as the largest measurement of the box.

USE_CIRCLE:
RUBBER_BOX
XX=(X2-X1)/2 : YY=(Y2-Y1)/2
Circle X1+XX,Y1+YY,Max(XX,YY)+1
Return 



'ELLIPSE tool - work just like Circle, but makes the ellipse fit inside
'  the Rubber Box. 

USE_ELLIPSE:
RUBBER_BOX
XX=(X2-X1)/2 : YY=(Y2-Y1)/2
Ellipse X1+XX,Y1+YY,XX+1,YY+1
Return 



'HOLLOW BOX tool - Uses Rubber Box to determine the position and size of 
'  the box, then draws one there.

USE_BOX:
RUBBER_BOX
Box X1,Y1 To X2,Y2
Return 



'FILLED BOX tool - same as Hollow Box, but uses Bar command. 

USE_BAR:
RUBBER_BOX
Bar X1,Y1 To X2,Y2
Return 



'BRUSH tool - a la Deluxe Paint brushes.  Select an area of the screen 
'  using a Rubber Box, then draw with it.  Uses bob commands.
'  Hot Spot sets the "handle" to the middle of the area. 
'  Put Bob is the command that stamps the image onto the drawing screen. 
'  It would be simple to convert this to remember a number of different  
'  brushes instead of just one.
'  NOTE: turn this off by pressing the RIGHT mouse button. 

USE_GRAB:
RUBBER_BOX
Get Bob 1,X1,Y1 To X2,Y2
Hot Spot 1,$11
Repeat 
   Repeat 
      Bob 1,X Screen(X Mouse),Y Screen(Y Mouse),1
      Wait Vbl 
      MK=Mouse Key
   Until MK<>0
   If MK=1 Then Put Bob 1
Until MK=2
Bob Off 1
Return 



'TEXT tool - type some text, then place it on the screen.
'  This uses Gr Writing to change the drawing mode so that the 
'  background of the text is transparent.

USE_TEXT:

'Open a tiny screen for inputting the text.

Screen Open 2,640,10,2,Hires
Screen Display 2,,140,,
Palette $9,$FFF
Input At(10,)+"Enter Text: ";A$
Screen Close 2

'Find position, then print it. 

RUBBER_BOX
Gr Writing 0
Text X1,Y1+7,A$
Gr Writing 1
Return 



'LOAD tool - loads any IFF picture onto the drawing screen.
'  NOTE: although you can load any picture and view it, none of the
'  drawing routines have any way of detecting the change in screen 
'  size, depth or mode.  This means that only 320 x 256 x 32 colour
'  screens have been catered for.
'  However, the correct palette will be displayed. 
'  Sorry, but this IS only an example... 

PIC_LOAD:
FILE$=Fsel$("","","Load A Picture...")
If FILE$>""
   If Exist(FILE$)
      Load Iff FILE$,1
      Screen To Back 
      SEE_PALETTE[HUE]
      COMMAND=3
   End If 
End If 
Return 



'SAVE tool - save your masterpeice as a standard IFF picture.
'  This is what Load was meant to read...

PIC_SAVE:
FILE$=Fsel$("","","Save Picture As...")
If FILE$>""
   Screen 1
   Save Iff FILE$
   Screen 0
End If 
Return 


'UNDO tool - returns the screen back to how it was before you last 
'  changed drawing mode.  This means if you draw three lines, then ten 
'  circles, then hit Undo, ALL the circles will disappear. 
'  You can force Undo to remember only after a particular point simply 
'  by changing drawing modes.
'  NOTE: the UNDONE flag is so undo cannot be triggered more than once.

PIC_UNDO:
If Not UNDONE
   Screen Copy 3 To 1
   UNDONE=True
End If 
Return 



'CLEAR tool - clears the screen back to colour 0.
'  Sorry, there is no way to Clear to another colour (unless you add it).

PIC_CLEAR:
Screen 1
Cls 
Return 



'QUIT tool - the user wants to quit, so let them.
'  Sorry, there is no confirm.  Add one here.

ENABLE_QUIT:
QUIT=True
Return 



'Title Messages - for startup. 
'  Reads DATA statements, displays them on the screen, then waits for
'  a mouse click or keypress.

HELLO:
Restore HELP_DATA
Read NL
Screen 1
P=1
For L=1 To NL
   Read A$
   If A$>""
      Inc P
      Centre At(,L*2+1)+Pen$(P)+A$
   End If 
Next 
Repeat : Multi Wait : Until Mouse Key>0 or(Inkey$>"")
Cls 
Return 



'Data for the various drawing tools. 
'  These define the areas of the screen to be set up as "zones" so we can
'  simulate some sort of button. 
'  The strings are just so we know what each set of numbers is for.

CONTROL_ZONE_DATA:
Data 15
Data "Line",0,2,23,17
Data "Fill",0,18,23,33
Data "Draw",24,2,47,17
Data "Dotty",24,18,47,33
Data "Circle",48,2,71,17
Data "Ellipse",48,18,71,33
Data "Box",72,2,95,17
Data "Bar",72,18,95,33
Data "Grab",96,2,119,17
Data "Text",96,18,119,33
Data "Load",248,2,271,17
Data "Save",248,18,271,33
Data "Undo",272,2,295,17
Data "Clear",272,18,295,33
Data "Quit",296,2,319,33



'Data for the startup messages.

HELP_DATA:
Data 10
Data "M I N I   P A I N T","","A Demonstration Program"
Data "for OZAmiga AMOS Tutoral #3.",""
Data "By Neil McKnight 1993",""
Data "May be freely distributed.",""
Data "Click on logo to quit."



'Displays the palette area of the control panel. 
'  It also sets up the selection zones for each colour and highlights
'  the current drawing colour. 

Procedure SEE_PALETTE[HUE]

   'Go to control panel and load the palette of the drawing screen. 

   Screen 0
   Get Palette 1

   'Draw a sample of each colour. 

   For L=0 To 31

      'Work out the coordinated of the colour sample.

      X1=120+(L mod 16)*8
      Y1=2-(L>15)*16
      X2=X1+7 : Y2=Y1+15

      'Put a selection zone around it. 

      Set Zone L+1,X1,Y1 To X2,Y2

      'Draw a small box of that colour as a sample.

      Ink L
      Bar X1+2,Y1+2 To X2-2,Y2-2

      'If it's to be the new drawing colour, highlight it, then set it 
      '  as the Current drawing coloiur on the drawing screen. 

      If L=HUE
         Ink 0
         Box X1+2,Y1+2 To X2-2,Y2-2
         Screen 1
         Ink HUE
         Screen 0
      End If 
   Next 
End Proc



'Allows the user to select an area of the screen of variable size and
'  position, without disturbing the background underneath. 
'  Return the coordinates of the area to the drawing routines. 

Procedure RUBBER_BOX

   'Go to the drawing screen and wait until the user lets go of the 
   '  mouse buttons.

   Screen 1
   Repeat : Multi Wait : Until Mouse Key=0

   'Set the drawing mode to Exclusive OR - eg. lines are draw in such a   
   '  way that the backgound can be returned to normal by redrawing the 
   '  same line in the same place a second time.  

   Gr Writing 2

   'Draw a set of cross hairs to the mouse position.

   X1=X Screen(X Mouse) : Y1=Y Screen(Y Mouse)
   OX=X1 : OY=Y1
   Draw OX,0 To OX,256
   Draw 0,OY To 640,OY

   'Track the mouse until the starting position is selected.

   Repeat 
      X1=X Screen(X Mouse) : Y1=Y Screen(Y Mouse)

      'Only redraw the lines if the mouse has moved. 

      If OX<>X1 or OY<>Y1

         'Redraw the OLD lines first to erase them. 

         Draw OX,0 To OX,256
         Draw 0,OY To 640,OY

         'Then draw lines for the current position. 

         Draw X1,0 To X1,256
         Draw 0,Y1 To 640,Y1
      End If 

      'Remember the current position for later.

      OX=X1 : OY=Y1
      Wait Vbl 
   Until Mouse Key=1

   'User has click where the area is to start, so erase the cross hairs.

   Draw X1,0 To X1,256
   Draw 0,Y1 To 640,Y1

   'Do the same sort of line drawing, but with a variable sized box.

   Repeat 

      'Track the mouse position as before. 

      X2=X Screen(X Mouse) : Y2=Y Screen(Y Mouse)

      'Redraw the box only when it changes.

      If OX<>X2 or OY<>Y2
         Box X1,Y1 To OX,OY
         Box X1,Y1 To X2,Y2
      End If 

      'Remember the coordinate for later.

      OX=X2 : OY=Y2
      Wait Vbl 
   Until Mouse Key=0

   'The area has been defined, so erase the box.

   Box X1,Y1 To X2,Y2

   'As the Box routine actually overlaps the starting point, it tends 
   '  to hang around as a dot.  This gets rid of it.

   Plot X1,Y1

   'Return the drawing mode back to normal. 

   Gr Writing 1

   'Adjust the coordinates selected so that the X1,Y1 is top left and 
   '  that a zero sized area is not returned.  Eg. the Bar command will 
   '  die if the coordinates are wrong. 

   If X1>X2 Then Swap X1,X2
   If Y1>Y2 Then Swap Y1,Y2
   If X2-X1=0 Then Inc X2
   If Y2-Y1=0 Then Inc Y2
End Proc



'Provides a click-and-release function.

Procedure CLICK
   Repeat : Multi Wait : Until Mouse Key=0
   Repeat : Multi Wait : Until Mouse Key=1
End Proc



'Show which drawing tool is being used.

Procedure SEE_CONTROL[COM]
   Shared OLD_COMMAND

   'Go to the control panel.

   Screen 0

   'Erase the little highlight on the old tool. 

   Ink 27
   Bar Z(OLD_COMMAND,0)+1,Z(OLD_COMMAND,1)+1 To Z(OLD_COMMAND,0)+3,Z(OLD_COMMAND,1)+2

   'Place new highlight on the current one. 

   Ink 2
   Bar Z(COM,0)+1,Z(COM,1)+1 To Z(COM,0)+3,Z(COM,1)+2
End Proc
