;*************************************************************************
;*  NB: SAVE THIS FILE FROM FULLVIEW MENU BEFORE USING IT TO UNCRUNCH IT
;*  SUBPROGRAM:     ColourWindow.asm
;*
;*  AUTHOR:         Original C version by Anders Bjerin (Amiga C Club)
;*
;*                  Ported to 68000 assembly by Mike Fuller
;*
;*                  Public Domain - NO RIGHTS RESERVED
;*
;*  DATE:           July 11, 1991 - Version 1.0
;*
;*  DESCRIPTION:    ColourWindow is a subprogram to create a colour
;*                  requester window and may be linked with any assembly
;*                  program to give the user control over its colours.
;*                  This is designed as an assembly language example
;*                  exercise that also produces something quite useful,
;*                  a colour requester that opens on any screen up to
;*                  5 bitplanes.  It can handle from 2 to 32 colours,
;*                  and has functions to copy, exchange, spread or undo
;*                  those colours.  It uses minimal CPU time and cleans
;*                  up completely after itself.
;*                  It was originally written by Anders Bjerin of the
;*                  Amiga C Club as an example in C and, like the rest
;*                  of the tutorials produced by them, it was very well
;*                  done.  There is, as far as I am aware, no similar
;*                  organisation devoted to assembly programming on the
;*                  Amiga, so this program is an attempt to initiate
;*                  interest in such an organisation.
;*                  The program is documented well throughout and
;*                  should be reasonably easy to follow by anyone
;*                  learning to program in assembly.  It may be used,
;*                  as is, in your program, or altered to suit your
;*                  needs.  If you're proficient in C, you can read the
;*                  equivalent program code and docs from the C Manual,
;*                  and compare the coding.
;*                  (The C Manual is a superb set of tutorials available
;*                  on Fish disks 456 and 457)
;*
;*  INPUT:          Before calling this subprogram from your program,
;*                  you need:
;*                      a pointer to the screen in register A0,
;*                      a pointer to the requester window title in A1,
;*                      the X (left) position of the requester in D0,
;*                      the Y (top) position of the requester in D1.
;*
;*                  eg.     movea.l Myscreen,a0
;*                          lea     Colwintitle,a1
;*                          move.l  #50,d0
;*                          move.l  #30,d1
;*                          jsr     ColourWindow
;*
;*                  If the workbench screen is being used, pass 0 in
;*                  register A0.
;*                  If you pass 0 in register A1, the default title
;*                  (Colour Window) will be used.
;*
;*  OUTPUT:         If the window opens and closes successfully, 0 will
;*                  be returned in register D0.
;*                  If it fails to open, 5 will be returned in D0.
;*
;*  ASSEMBLING:     This was originally assembled using A68K, the public
;*                  domain assembler by Charlie Gibbs.  The official
;*                  Commodore Include files (.i files) are also needed,
;*                  along with my Macros file, which should be included
;*                  with this program.
;*                  I have them in a directory which I assign as INCLUDE:
;*                  in my startup-sequence.
;*                  For example, my assembly is:
;*                          a68k ColourWindow.asm -iINCLUDE:
;*
;*  LINKING:        I use Blink, the public domain linker by the Software
;*                  Distillary.  An example to link it with your program:
;*
;*              Blink YourProg.o,ColourWindow.o to YourProg lib amiga.lib
;*
;*  PROGRAM NOTES:  I use certain conventions to make it easier to follow
;*                  my code. 
;*                      All my constants are in uppercase.  Any not
;*                      using this convention are Include definitions.
;*                      All program address labels begin in uppercase.
;*                      All my variables containing actual values are in
;*                      lowercase.  Pointers to variables or structures
;*                      (ie. are referred to as an address) begin with
;*                      an uppercase.
;*                  I also give my variables meaningful names (!!!);
;*                  it adds no more to the executable program and makes
;*                  debugging a lot simpler.  For the same reason, almost
;*                  all lines of code are commented appropriately.
;*                  Because it is sometimes difficult to follow logic
;*                  structure in assembly, pseudocode algorithms are
;*                  given where appropriate.
;*                  I wish more programmers would follow the MINIMUM
;*                  standards set out here and not expect everyone to
;*                  understand what was happening within the programmers
;*                  head at the time. (even the programmer him/herself
;*                  one week later)
;*
;*  LEGAL:          This program is public domain with NO RIGHTS RESERVED
;*                  and may be used freely by anyone.  Although it has
;*                  worked well for me, no responsibility is accepted for
;*                  any damage the program may cause.
;*                  Any bug reports, suggestions, improvements (there are
;*                  probably heaps) or interest in organising or
;*                  assisting with an Amiga Assembly Association
;*                  (can you think of a better name for starters?)
;*                  please contact me.
;*                              Mike Fuller
;*                              4 Sonego Avenue
;*                              Kelmscott
;*                              W.A.  6111
;*                              (09) 390 9350
;*
;*************************************************************************


;**************************** INCLUDE FILES ******************************

        INCLUDE "intuition/intuition.i"
        INCLUDE "macros"


;**************************** MACROS *************************************
;*
;*      The majority of the macros used in this program are contained in
;*      my macros file, which should be included with this program.
;*      Macro definitions specific to this program are placed here.

RGBval  MACRO                   ;determine RGB values from HorizPot
        moveq   #0,d0               ;clear buffer
        lea     \1_info,a0          ;get PropInfo pointer
        move.w  pi_HorizPot(a0),d0  ;get HorizPot value
        lsr.w   #6,d0
        lsr.w   #6,d0               ;get 1/15 value
        move.b  d0,\1               ;save in colour variable
        ENDM

;*      eg. RGBval  Red             ;get red value


Modprop MACRO                   ;modifies a prop. gadget
        lea     \1_gadget,a0        ;gadget structure pointer
        movea.l \2,a1               ;Window structure pointer
        suba.l  a2,a2               ;NULL in a2
        lea     \1_info,a3          ;PropInfo structure pointer
        move.w  (a3),d0             ;PropInfo structure flags
        moveq   #0,d1
        move.b  \3,d1               ;R,G or B value
        mulu    #$1111,d1           ;prepare Horizpot value
        moveq   #0,d2               ;VertPot, not needed
        movea.l a3,a4 
        adda.l  #pi_HorizBody,a4    ;HorizBody pointer
        move.w  (a4),d3             ;HorizBody value
        moveq   #0,d4               ;VertBody, not needed
        Syslib  ModifyProp,Intbase  ;modify red prop. gadget
        ENDM

;*      eg. Modprop Red,Colour_window,d5


Int2str MACRO                   ;convert an integer < 20 to a string
        lea     \1,a0               ;pointer to string buffer
        move.b  \2,d2               ;integer to convert
        cmpi.b  #10,d2              ;is integer > 10?
        blt     Blankchar\@         ;if not, blank first character
        move.b  #'1',(a0)           ;else, 1st character is a 1
        subi.b  #10,d2              ;get remaining digit
        bra     Lastchar\@
Blankchar\@:
        move.b  #' ',(a0)           ;blank 1st character
Lastchar\@:
        addi.b  #'0',d2             ;convert remaining digit
        move.b  d2,1(a0)            ;move it to buffer
        ENDM

;*      eg. Int2str Colour_string,Red   ;convert integer in red
;*      NOTE: This macro is limited to this module, and is used to
;*            convert the RGB values to a printable form.  It is
;*            certainly not intended for general integer conversion.
        

;**************************** EXTERNAL REFERENCES ************************
;*
;*      Uses the _LVO form of the system calls rather than the actual
;*      offsets, which can change with new operating systems.
;*      Link with amiga.lib to convert them to offset values.


        XDEF    ColourWindow        ;* Defines this program module

;*  System calls

        XREF    _AbsExecBase        ;* Exec library pointer
        XREF    _LVOOpenWindow      ;* Open a window
        XREF    _LVOCloseWindow     ;* Close a window
        XREF    _LVOMove            ;* Position drawing pen
        XREF    _LVODraw            ;* Draw line to position
        XREF    _LVOSetRGB4         ;* Change a colour
        XREF    _LVOSetAPen         ;* Set foreground pen colour
        XREF    _LVOSetBPen         ;* Set background pen colour
        XREF    _LVOSetPointer      ;* Change the pointer
        XREF    _LVOSetDrMd         ;* Set the drawing mode
        XREF    _LVOText            ;* Write to a window
        XREF    _LVOReadPixel       ;* Get pixel colour number
        XREF    _LVORectFill        ;* Draw a filled rectangle
        XREF    _LVOModifyProp      ;* Change a proportional gadget
        XREF    _LVOWait            ;* Wait for intuition message
        XREF    _LVOGetMsg          ;* Get Intuition message from queue
        XREF    _LVOReplyMsg        ;* Reply to intuition message

;*      The intuition and graphics libraries should be opened by your
;*      main program prior to calling ColourWindow.  I name the pointers
;*      to these libraries Intbase and Graphbase; you may wish to change
;*      these names to fit your own versions.

        XREF    Intbase              ;* Intuition library pointer
        XREF    Graphbase            ;* Graphics library pointer


        SECTION "Colwin",CODE

;**************************** CONSTANTS **********************************

;*      Error flags returned in D0

NOERROR equ     0                   ;* No error to return
WINDOWERR equ   5                   ;* Could not open window

;*      Program-specific values

OK      equ     10                  ;* Ok flag
CANCEL  equ     20                  ;* Cancel flag
QUIT    equ     30                  ;* Quit flag
WORKING equ     50                  ;* Working flag
NOTHING equ     0                   ;* Nothing flag
COPY    equ     10                  ;* Copy flag
EXCHANGE equ    20                  ;* Exchange flag
SPREAD  equ     30                  ;* Spread flag
NUMCOL  equ     32                  ;* Maximum number of colours
RMASK   equ     $F00                ;* Red mask from RGB register
GMASK   equ     $0F0                ;* Green mask from RGB register
BMASK   equ     $00F                ;* Blue mask from RGB register

;*      System-specific values

NULL    equ     0                   ;* Null
TRUE    equ     1                   ;* True flag
FALSE   equ     0                   ;* False flag
JAM1    equ     $0                  ;* Jam1 drawing mode
JAM2    equ     $1                  ;* Jam2 drawing mode
MEMF_PUBLIC equ $1                  ;* Public memory mask
MEMF_CHIP   equ $2                  ;* Chip memory mask
MEMF_FAST   equ $4                  ;* Fast memory mask
MEMF_CLEAR  equ $10000              ;* Clear allocated memory mask

;**************************** COLOURWINDOW *******************************
;*
;*  Colour window's mainline module.
;*
;*  INPUT:      Pointer to screen in A0
;*              Pointer to ColourWindow title in A1
;*              X position in D0
;*              Y position in D1
;*
;*  OUTPUT:     Error code in D0 - 0 if no error
;*
;*  ALGORITHM:  Open window
;*              While order = WORKING
;*                  Wait for intuition message
;*                  While messages queued
;*                      Get next message
;*                      Save message values
;*                      Reply to message
;*                      If message class = MOUSEBUTTONS
;*                          check colours
;*                      Elseif message class = GADGETDOWN
;*                          change mode to NOTHING
;*                          change pointer
;*                      Elseif message class = GADGETUP
;*                          check which gadget
;*                      Elseif message class = CLOSEWINDOW
;*                          order = QUIT
;*                  Endwhile (message)
;*                  Calculate new RGB values
;*                  Change current colour
;*                  Print RGB values
;*              Endwhile (order)
;*              If order = CANCEL or QUIT
;*                  restore original colours
;*              If window opened
;*                  close it
;*              Return error code to main program
;*

ColourWindow:

        Push    a2-a6/d2-d7         ;save non-scratch registers
        jsr     Initcolwin          ;initialize and open the colour window

;*      Main working loop - remain in this until the user has selected
;*      the CLOSEWINDOW, CANCEL or OK gadget.

Mainloop:

        cmpi.b  #WORKING,order      ;has order changed?
        bne     Endmainloop         ;if yes, close the window

;*      Wait until a message has been received.  The Wait function
;*      does not tie up the CPU, leaving you to multitask freely.

        moveq   #0,d1               ;clear register
        movea.l Colour_window,a2    ;pointer to Window structure
        movea.l wd_UserPort(a2),a2  ;pointer to user port
        move.b  MP_SIGBIT(a2),d1    ;signal bit number - set up the
        moveq   #1,d0               ;   actual signal set by shifting
        lsl.l   d1,d0               ;   a 1 in D0 by this number
        Syslib  Wait,_AbsExecBase   ;wait for signal

;*      There may be more messages while we are processing this one,
;*      so we stay in another loop until it pauses.

Messageloop:

        movea.l Colour_window,a0    ;pointer to Window structure
        movea.l wd_UserPort(a0),a0  ;pointer to Window's UserPort
        Syslib  GetMsg,_AbsExecBase ;get intuimessage
        tst.l   d0                  ;check if message present
        beq     Endmessage          ;if no message, end loop
        move.l  d0,a1               ;else, save its pointer

;*      Save some important values from the message

        move.l  im_Class(a1),class  ;IDCMP flag
        move.w  im_Code(a1),code    ;extra information
        move.l  im_IAddress(a1),Address ;pointer to gadget
        move.w  im_MouseX(a1),mousex    ;x mouse position
        move.w  im_MouseY(a1),mousey    ;y mouse position

;*      Reply as fast as possible to prevent Intuition grabbing
;*      unrecoverable memory.  We also don't read the message after
;*      we have replied, it may have changed.

        Syslib  ReplyMsg,_AbsExecBase   ;reply to message

;*      Check which IDCMP flag was set

        cmpi.l  #MOUSEBUTTONS,class ;was mouse clicked inside window?
        bne     Gadgdown            ;if not, check GADGETDOWN
        jsr     Mousebutton         ;else, check colours
        bra     EndIflag            ;and get next message

Gadgdown:
        cmpi.l  #GADGETDOWN,class   ;has prop. gadget been selected?
        bne     Gadgup              ;if not, check GADGETUP
        move.b  #NOTHING,mode       ;else, revert to NOTHING mode
                                    ;   and change pointer
        Setpointer  Colour_window,Two_pointer,#16,#16,#-1,#-1
        bra     EndIflag            ;and get next message

Gadgup:
        cmpi.l  #GADGETUP,class     ;has gadget been released?
        bne     Closewin            ;if not, check CLOSEWINDOW
        jsr     Gadgetup            ;else, check which gadget
        bra     EndIflag            ;and get next message

Closewin:
        cmpi.l  #CLOSEWINDOW,class  ;is close window gadget selected?
        bne     EndIflag            ;if not, calculate new values
        move.b  #QUIT,order         ;else, order to quit

EndIflag:

        bra     Messageloop         ;check for another message


Endmessage:

;*      Calculate the new RGB values with the prop. gadget values

        RGBval  Red                 ;calculate red value
        RGBval  Green               ;calculate green value
        RGBval  Blue                ;calculate blue value

;*      Change the colour and print the RGB values

        movea.l Graphbase,a6        ;needs graphics library
        SetRGB  Vport,colour,Red,Green,Blue ;change current colour

        Int2str Colour_string,Red   ;convert red value to string
        Wtext   Rport,Colour_string,#2,#174,#19     ;print it

        Int2str Colour_string,Green   ;convert green value to string
        Wtext   Rport,Colour_string,#2,#174,#31     ;print it

        Int2str Colour_string,Blue   ;convert blue value to string
        Wtext   Rport,Colour_string,#2,#174,#43     ;print it

        bra     Mainloop            ;wait for next message


Endmainloop:

;*      If user has selected CANCEL or CLOSEWINDOW gadgets, restore
;*      the colours using the master backup.

        moveq   #NOERROR,d6         ;return no error flag
        cmpi.b  #QUIT,order         ;was quit selected?
        beq     Fullrestore         ;if yes, restore colours
        cmpi.b  #CANCEL,order       ;was cancel selected?
        bne     Colwinfinish        ;if not, clean up

Fullrestore:
        movea.l Graphbase,a6        ;needs graphics library
        lea     Rgb1,a3             ;master RGB backup
        moveq   #0,d4               ;initialize loop counter
Restoreloop:
        SetRGB  Vport,d4,(a3)+,(a3)+,(a3)+  ;change colour
        addq    #1,d4               ;increment colour counter
        cmp.b   count,d4            ;finished colours?
        blt     Restoreloop         ;if not, restore next one

Colwinfinish:

;*      Close the window, if opened.

        cmpi.b  #WINDOWERR,d6       ;if window not opened
        beq     Endwin              ;don't close it
        movea.l Colour_window,a0    ;else, get pointer to window
        Syslib  CloseWindow,Intbase ;and close the window

;*      Reset the order for another invocation of the requester

        move.b  #WORKING,order

Endwin:
        move.b  d6,d0               ;return-error code (byte size)
        Pop     a2-a6/d2-d7         ;restore non-scratch registers
        rts                         ;return to calling program

;**************************** END OF COLOURWINDOW MAINLINE ***************


;**************************** INITCOLWIN *********************************
;*
;*  Initializes and opens the colour window ready to receive a user
;*  message.
;*
;*  INPUT:      The arguments passed to the ColourWindow subroutine.
;*              (see mainline documentation)
;*
;*  OUTPUT:     If there is an error opening the window, an error number
;*              is passed in D6 and the subroutine terminates.
;*
;*  ALGORITHM:  Save screen pointer
;*              Check and set X/Y positions
;*              If valid title
;*                  move title to window
;*              Open window
;*              If error
;*                  set error code
;*                  finish
;*              Save viewport, rastport and colourtable pointers
;*              Change the pointer
;*              Update the prop. gadgets
;*              Draw the colour boxes
;*              Set drawing mode
;*              Draw RGB value boxes
;*              Draw the prop. gadget scale
;*              Get RGB values and print them
;*              Backup the colour table
;*              Return to mainline
;*

Initcolwin:

;*      Use arguments passed to ColourWindow subroutine

        moveq   #0,d4               ;clear buffers
        moveq   #0,d5
        lea     Colour_window_data,a2   ;pointer to NewWindow structure
        move.l  a0,Wscreen          ;save screen pointer
        move.l  a0,nw_Screen(a2)    ;alter window's screen pointer
        beq     Wbscreen            ;if WBScreen, leave window Type
        move.w  #CUSTOMSCREEN,nw_Type(a2)  ;else change to CUSTOMSCREEN
        move.w  sc_Width(a0),d4     ;get screen width
        move.w  sc_Height(a0),d5    ;and height
        bra     Alttitle            ;and check title

Wbscreen:
        move.w  #640,d4             ;width of WB screen
        move.w  #256,d5             ;height of WB screen

;*      Check for title

Alttitle:
        cmpa.l  #0,a1               ;new title requested?
        beq     Checkwinpos         ;if not, use default
        move.l  a1,nw_Title(a2)     ;else, alter window's title

;*      Window position - this checks that the coordinates passed in D0
;*      and D1 will allow the requester window to fit on the screen.
;*      If not, the window will be positioned as close as possible to
;*      the register values.

Checkwinpos:
        subi.w  #278,d4             ;subtract colour window width
        subi.w  #80,d5              ;subtract colour window height
        cmpi.w  #0,d0               ;is X position too small?
        bge     CheckXbig           ;if not, check if too big
        moveq   #0,d0               ;else, X pos = min
        bra     CheckYsmall         ;and check Y position
CheckXbig:
        cmp.w   d4,d0               ;is X position too big?
        blt     CheckYsmall         ;if not, check Y position
        move.w  d4,d0               ;else, X pos = max
CheckYsmall:
        cmpi.w  #0,d1               ;is Y position too small?
        bge     CheckYbig           ;if not, check if too big
        moveq   #0,d1               ;else, Y pos = min
        bra     ChangeXYpos         ;and alter window coordinates
CheckYbig:
        cmp.w   d5,d1               ;is Y position too big?
        ble     ChangeXYpos         ;if not, alter window coordinates
        move.w  d5,d1               ;else, Y pos = max

;*      Alter window coordinates and open colour window

ChangeXYpos:
        move.w  d0,nw_LeftEdge(a2)  ;else, alter window's left edge
        move.w  d1,nw_TopEdge(a2)   ;and window's top edge
        lea     Colour_window_data,a0   ;NewWindow structure address
        Syslib  OpenWindow,Intbase  ;open colour window
        move.l  d0,Colour_window    ;save pointer to Window structure
        bne     Screencheck         ;continue if successful opening
        move.b  #WINDOWERR,d6       ;else set error flag
        bra     Endwin              ;and quit

Screencheck:
        move.l  d0,a0               ;Window structure address
        move.l  wd_RPort(a0),Rport  ;save Window rastport
        cmpi.l  #0,Wscreen          ;check screen
        bne     Getcoltable         ;if valid, continue
        move.l  wd_WScreen(a0),Wscreen ;else, get screen from open window

;*      Get viewport and pointer to colour table from screen.
;*      (ColorTable is within ColorMap structure, within ViewPort
;*      structure, within Wscreen structure!)

Getcoltable:
        movea.l Wscreen,a3          ;valid pointer to screen
        adda.l  #sc_ViewPort,a3     ;screen viewport
        move.l  a3,Vport            ;save it
        adda.l  #vp_ColorMap,a3     ;pointer to ColorMap
        movea.l (a3),a3
        move.l  cm_ColorTable(a3),a3   ;pointer to ColorTable
        move.l  a3,Colour_table     ;and finally, save it

;*      Change the pointer and update the prop. gadgets values

        Setpointer  Colour_window,Normal_pointer,#16,#16,#-1,#-1
        jsr     Fixprop

;*      Draw colour boxes and select colour 0

        movea.l Graphbase,a6        ;need graphics library
        jsr     Drawcolourboxes
        jsr     Selectcolour

;*      Prepare the pens and drawing mode

        movea.l Graphbase,a6        ;graphics library pointer
        Setpen  A,Rport,#1          ;set foreground to colour 1
        Setpen  B,Rport,#0          ;set background to colour 0
        movea.l Rport,a1            ;Window rastport
        move.l  #JAM2,d0            ;JAM2 mode
        Syslib  SetDrMd             ;set drawing mode

;*      Draw the RGB value boxes

        Drawbox Rport,#171,#11,#191,#21 ;box for red values
        Drawbox Rport,#171,#23,#191,#33 ;box for green values
        Drawbox Rport,#171,#35,#191,#45 ;box for blue values
        Drawbox Rport,#195,#11,#271,#21 ;box for selected colour

;*      Draw the scale under the proportional gadget scale

        jsr     Drawscale           ;draw the scale

;*      Initialize the RGB values from prop. gadgets and print them

        RGBval  Red                 ;initialize red value
        Int2str Colour_string,Red   ;convert to string
        Wtext   Rport,Colour_string,#2,#174,#19     ;print it

        RGBval  Green               ;initialize green value
        Int2str Colour_string,Green ;convert to string
        Wtext   Rport,Colour_string,#2,#174,#31     ;print it

        RGBval  Blue                ;initialize blue value
        Int2str Colour_string,Blue  ;convert to string
        Wtext   Rport,Colour_string,#2,#174,#43     ;print it

;*      Make backups of the screen's colour tables

        lea     Rgb1,a3             ;master backup pointer
        lea     Rgb2,a4             ;UNDO backup pointer
        movea.l Colour_table,a2     ;screen colour table pointer
        moveq   #0,d0               ;loop counter

Colloop:
        move.w  (a2)+,d2            ;get RGB value
        move.w  d2,d3               ;save it
        andi.w  #RMASK,d3           ;mask out GB values
        lsr.w   #8,d3               ;position red value
        move.b  d3,(a3)+            ;save it to master backup
        move.b  d3,(a4)+            ;and the UNDO backup

        move.w  d2,d3               ;retrieve RGB value 
        andi.w  #GMASK,d3           ;mask out RB values
        lsr.w   #4,d3               ;position green value
        move.b  d3,(a3)+            ;save it to master backup
        move.b  d3,(a4)+            ;and the UNDO backup

        andi.w  #BMASK,d2           ;mask out RG values
        move.b  d2,(a3)+            ;save blue to master backup
        move.b  d2,(a4)+            ;and the UNDO backup

        addq    #1,d0               ;increment colour counter
        cmp.b   count,d0            ;any more colours?
        blt     Colloop             ;if yes, get next one

        rts                         ;return to mainline


;**************************** MOUSEBUTTON ********************************
;*
;*  The mousebutton was clicked inside the colour window.
;*  We need to check what colours, if any, need to be changed.
;*
;*  ALGORITHM:  Change to normal pointer
;*              If left mouse button pressed then
;*                  If colour changed then
;*                      Backup colour table
;*                      If copy mode then
;*                          set colour
;*                      Elseif exchange mode then
;*                          swap old and current colour
;*                      Elseif spread mode then
;*                          spread colour range
;*                      Endif
;*                      Select and show new colour
;*                      Update the prop. gadgets
;*                  Change to nothing mode
;*              Return to mainline
;*

Mousebutton:

;*      Change the pointer to 'normal' and check if the left mouse
;*      button was pressed.

        Setpointer Colour_window,Normal_pointer,#16,#16,#-1,#-1
        cmpi.w  #SELECTDOWN,code    ;was it pressed?
        bne     Endmousebutton      ;if not, return

;*      Check if colour selected

        move.b  colour,old_colour   ;save colour
        movea.l Rport,a1            ;get window's rastport
        move.w  mousex,d0           ;get mouse position
        move.w  mousey,d1
        Syslib  ReadPixel,Graphbase ;check colour
        move.b  d0,colour           ;and save it
        cmp.b   old_colour,d0       ;has colour changed?
        beq     Nothingmousemode    ;if not, change mode and return

;*      New colour selected - backup colour table

Backupundo:
        lea     Rgb2,a0             ;UNDO backup pointer
        movea.l Colour_table,a2     ;screen colour table pointer
        moveq   #0,d0               ;loop counter

Backuploop:
        move.w  (a2)+,d2            ;get RGB value
        move.w  d2,d3               ;save it
        andi.w  #RMASK,d3           ;mask out GB values
        lsr.w   #8,d3               ;position red value
        move.b  d3,(a0)+            ;save it to UNDO backup

        move.w  d2,d3               ;retrieve RGB value 
        andi.w  #GMASK,d3           ;mask out RB values
        lsr.w   #4,d3               ;position green value
        move.b  d3,(a0)+            ;save it to UNDO backup

        andi.w  #BMASK,d2           ;mask out RG values
        move.b  d2,(a0)+            ;save blue to UNDO backup

        addq    #1,d0               ;next colour
        cmp.b   count,d0            ;any more colours?
        blt     Backuploop          ;if yes, get next one

;*      Check the action mode

Copymode:
        cmpi.b  #COPY,mode          ;copy colours?
        bne     Exchgmode           ;if not, check exchange
        SetRGB  Vport,colour,Red,Green,Blue     ;else, set colour
        bra     Selectcol           ;and select it

Exchgmode:
        cmpi.b  #EXCHANGE,mode      ;exchange colours?
        bne     Spreadmode          ;if not, check spread

        movea.l Colour_table,a0     ;else, get colour table
        moveq   #0,d5               ;clear colour number buffer
        move.b  colour,d5           ;get colour
        lsl.w   #1,d5               ;multiply by word-to-byte factor
        move.w  0(a0,d5),d3         ;get RGB value
        move.w  d3,d4               ;save it
        andi.w  #RMASK,d4           ;mask out GB values
        lsr.w   #8,d4               ;position red value
        move.b  d4,d1               ;and save it
        move.w  d3,d4               ;save RGB value
        andi.w  #GMASK,d4           ;mask out RB values
        lsr.w   #4,d4               ;position green value
        move.b  d4,d2               ;and save it
        andi.w  #BMASK,d3           ;mask out RB values

        movea.l Vport,a0            ;get viewport pointer
        move.b  old_colour,d0       ;old colour number
        Syslib  SetRGB4,Graphbase   ;change old colour

        SetRGB  Vport,colour,Red,Green,Blue     ;change new colour
        bra     Selectcol           ;and select it

Spreadmode:
        cmpi.b  #SPREAD,mode        ;spread colours?
        bne     Selectcol           ;if not, select colour
        jsr     Spread              ;else, spread colours

;*      Select the new colour, show it and update prop. gadgets

Selectcol:

        movea.l Graphbase,a6        ;graphics library pointer
        jsr     Selectcolour        ;select the new colour
        Recfill Rport,colour,#196,#12,#270,#20  ;show colour
        Setpen  A,Rport,#1          ;reselect drawing pen
        jsr     Fixprop             ;update prop. gadgets

Nothingmousemode:
        move.b  #NOTHING,mode       ;change mode
        
Endmousebutton:

        rts                         ;return to mainline


;**************************** GADGETUP ***********************************
;*
;*      Checks which gadget was released and takes appropriate action.
;*
;*  ALGORITHM:  Change to nothing mode
;*              Set normal pointer
;*              If copy gadget
;*                  set To pointer
;*                  change to copy mode
;*              Elseif exchange gadget
;*                  set To pointer
;*                  change to exchange mode
;*              Elseif spread gadget
;*                  set To pointer
;*                  change to spread mode
;*              Elseif undo gadget
;*                  reset colours from undo backup
;*                  update the prop. gadgets
;*              Elseif ok gadget
;*                  change order to OK
;*              Elseif cancel gadget
;*                  change order to cancel
;*              Endif
;*              Return to mainline
;*

Gadgetup:

;*      Change mode and set pointer to 'normal'

        move.b  #NOTHING,mode       ;change to NOTHING mode
        Setpointer  Colour_window,Normal_pointer,#16,#16,#-1,#-1

;*      Check gadgets

        move.l  #Copy_gadget,d0     ;copy gadget pointer
        cmp.l   Address,d0          ;was copy gadget released?
        bne     Exgad               ;if not, check ex gadget
                                    ;else, change pointer
        Setpointer  Colour_window,To_pointer,#16,#16,#-1,#-1
        move.b  #COPY,mode          ;change mode
        bra     Endgadgetup         ;and forget other gadgets

Exgad:
        move.l  #Ex_gadget,d0       ;ex gadget pointer
        cmp.l   Address,d0          ;was ex gadget released?
        bne     Spreadgad           ;if not, check spread gadget
                                    ;else, change pointer
        Setpointer  Colour_window,To_pointer,#16,#16,#-1,#-1
        move.b  #EXCHANGE,mode      ;change mode
        bra     Endgadgetup         ;and forget other gadgets

Spreadgad:
        move.l  #Spread_gadget,d0   ;spread gadget pointer
        cmp.l   Address,d0          ;was spread gadget released?
        bne     Undogad             ;if not, check undo gadget
                                    ;else, change pointer
        Setpointer  Colour_window,To_pointer,#16,#16,#-1,#-1
        move.b  #SPREAD,mode        ;change mode
        bra     Endgadgetup         ;and forget other gadgets

Undogad:
        move.l  #Undo_gadget,d0     ;undo gadget pointer
        cmp.l   Address,d0          ;was undo gadget released?
        bne     Okgad               ;if not, check ok gadget

;*      If UNDO, restore colours and fix prop. gadgets

        movea.l Graphbase,a6        ;needs graphics library
        lea     Rgb2,a3             ;pointer to UNDO RGB backup
        moveq   #0,d4               ;initialize loop counter

Undoloop:
        SetRGB  Vport,d4,(a3)+,(a3)+,(a3)+  ;restore colour
        addq    #1,d4               ;increment colour counter
        cmp.b   count,d4            ;finished colours?
        blt     Undoloop            ;if not, undo next one

        jsr     Fixprop             ;update the prop. gadgets
        bra     Endgadgetup         ;and forget other gadgets

Okgad:
        move.l  #Ok_gadget,d0       ;ok gadget pointer
        cmp.l   Address,d0          ;was ok gadget released?
        bne     Cancelgad           ;if not, check cancel gadget
        move.b  #OK,order           ;else, order OK
        bra     Endgadgetup         ;and forget other gadgets

Cancelgad:
        move.l  #Cancel_gadget,d0   ;cancel gadget pointer
        cmp.l   Address,d0          ;was cancel gadget released?
        bne     Endgadgetup         ;if not, forget it
        move.b  #CANCEL,order       ;else, order CANCEL

Endgadgetup:

        rts                         ;return to mainline


;**************************** DRAWSCALE **********************************
;*
;*      Draws the scale under the proportional gadgets.
;*      This is a subroutine only for mainline neatness.

Drawscale:

        moveq   #0,d3               ;loop counter

Scaleloop:
        moveq   #50,d5              ;initial y Draw position
        move.b  d3,d4               ;get loop number
        lsl.b   #3,d4
        add.b   d3,d4               ;multiply it by 9
        addi.b  #19,d4              ;x position
        btst    #0,d3               ;is loop counter even?
        bne     Posscale            ;if not, use small notch
        addq    #2,d5               ;else, use big notch
Posscale:
        Pos     Rport,d4,#48,Move   ;position pen
        Pos     Rport,d4,d5,Draw    ;draw notch
        addq    #1,d3               ;increment loop
        cmpi.b  #17,d3              ;finished notches?
        blt     Scaleloop           ;if not, draw another one

        rts                         ;else, return


;**************************** DRAWCOLOURBOXES ****************************
;*
;*      Calculates the number of colours and draws the colour boxes at
;*      the bottom of the window.
;*
;*  OUTPUT:     Returns the number of colours in count.
;*
;*  ALGORITHM:  Get count of colours from screen depth
;*              If depth = 5
;*                  For row from 1 to 2
;*                      For col from 1 to 16
;*                          colour = row*16 + col
;*                          draw box
;*              Elseif depth = 4
;*                  For col from 1 to 16
;*                      draw box
;*              Elseif depth = 3
;*                  For col from 1 to 8
;*                      draw box
;*              Elseif depth = 2
;*                  For col from 1 to 4
;*                      draw box
;*              Elseif depth = 1
;*                  For col from 1 to 2
;*                      draw box
;*              Endif
;*              Return
;*
;*  NOTE:       This subroutine demonstrates some of the tediousness
;*              associated with assembly.  I could have done some 'clever'
;*              programming to make it smaller but it would have been
;*              harder to follow.  C is a far easier alternative in 
;*              these situations.


Drawcolourboxes:

;*      Calculate the number of colours

        movea.l Wscreen,a0          ;screen pointer
        move.b  sc_BitMap+bm_Depth(a0),d0   ;get screen depth
        moveq   #1,d1
        lsl.b   d0,d1               ;count = 2^depth
        move.b  d1,count            ;save count of colours

;*      Draw colour boxes depending on depth of screen

        moveq   #0,d4               ;loop1 counter

Depth5:
        cmpi.b  #5,d0               ;is depth 5?
        bne     Depth4              ;if not; check next one

D5outloop:
        moveq   #0,d5               ;loop2 counter
D5inloop:
        move.l  d4,d6               ;loop1 number
        lsl.l   #4,d6
        add.l   d5,d6               ;loop1 * 16 + loop2
        Setpen  A,Rport,d6          ;set colour

;*      Set up coordinates for Rectfill

        move.l  d5,d6               ;loop2 counter
        mulu    #11,d6              ;loop2 * 11
        move.l  d6,d0
        addi.l  #6,d0               ;x1 position
        move.l  d6,d2
        addi.l  #15,d2              ;x2 position

        move.l  d4,d6               ;loop1 counter
        mulu    #10,d6              ;loop1 * 10
        move.l  d6,d1
        addi.l  #57,d1              ;y1 position
        move.l  d6,d3
        addi.l  #65,d3              ;y2 position

;*      Draw box

        movea.l Rport,a1            ;rastport
        Syslib  RectFill            ;draw filled box

;*      Check loop counters

        addq    #1,d5               ;increment loop2
        cmpi.l  #15,d5              ;finished row of boxes?
        ble     D5inloop            ;if not, draw another
        addq    #1,d4               ;else, next row
        cmpi.l  #1,d4               ;finished rows
        ble     D5outloop           ;if not, do next one
        bra     Endboxes            ;else, end routine

Depth4:
        cmpi.b  #4,d0               ;is depth 4?
        bne     Depth3              ;if not, try 3

D4loop:
        Setpen  A,Rport,d4          ;set colour

        move.l  d4,d5               ;loop1 counter
        mulu    #11,d5              ;loop1 * 11
        move.l  d5,d0
        addi.l  #6,d0               ;x1 position
        move.l  d5,d2
        addi.l  #15,d2              ;x2 position
        move.l  #57,d1              ;y1 position
        move.l  #75,d3              ;y2 position

        movea.l Rport,a1            ;rastport
        Syslib  RectFill            ;draw filled box

        addq    #1,d4               ;increment loop1
        cmpi.l  #16,d4              ;finished row?
        blt     D4loop              ;if not, draw another box
        bra     Endboxes            ;else, end routine

Depth3:
        cmpi.b  #3,d0               ;is depth 3?
        bne     Depth2              ;if not, try 2

D3loop:
        Setpen  A,Rport,d4          ;set colour

        move.l  d4,d5               ;loop1 counter
        mulu    #22,d5              ;loop1 * 11
        move.l  d5,d0
        addi.l  #6,d0               ;x1 position
        move.l  d5,d2
        addi.l  #26,d2              ;x2 position
        move.l  #57,d1              ;y1 position
        move.l  #75,d3              ;y2 position

        movea.l Rport,a1            ;rastport
        Syslib  RectFill            ;draw filled box

        addq    #1,d4               ;increment loop1
        cmpi.l  #8,d4               ;finished row?
        blt     D3loop              ;if not, draw another box
        bra     Endboxes            ;else, end routine

Depth2:
        cmpi.b  #2,d0               ;is depth 2?
        bne     Depth1              ;if not, try 1

D2loop:
        Setpen  A,Rport,d4          ;set colour

        move.l  d4,d5               ;loop1 counter
        mulu    #44,d5              ;loop1 * 11
        move.l  d5,d0
        addi.l  #6,d0               ;x1 position
        move.l  d5,d2
        addi.l  #48,d2              ;x2 position
        move.l  #57,d1              ;y1 position
        move.l  #75,d3              ;y2 position

        movea.l Rport,a1            ;rastport
        Syslib  RectFill            ;draw filled box

        addq    #1,d4               ;increment loop1
        cmpi.l  #4,d4               ;finished row?
        blt     D2loop              ;if not, draw another box
        bra     Endboxes            ;else, end routine

Depth1:
        Setpen  A,Rport,d4          ;set colour

        move.l  d4,d5               ;loop1 counter
        mulu    #88,d5              ;loop1 * 11
        move.l  d5,d0
        addi.l  #6,d0               ;x1 position
        move.l  d5,d2
        addi.l  #92,d2              ;x2 position
        move.l  #57,d1              ;y1 position
        move.l  #75,d3              ;y2 position

        movea.l Rport,a1            ;rastport
        Syslib  RectFill            ;draw filled box

        addq    #1,d4               ;increment loop1
        cmpi.l  #2,d4               ;finished row?
        blt     Depth1              ;if not, draw another box

Endboxes:
        rts                         ;return


;**************************** SELECTCOLOUR *******************************
;*
;*      Draws a box around the selected colour, after clearing the box
;*      from the old colour.
;*
;*  ALGORITHM:  If 32 colours then
;*                  Set pen to background colour
;*                  If old colour < 16 then
;*                      clear old-colour box in top row
;*                  Else
;*                      clear old-colour box in bottom row
;*                  Set pen to foreground colour
;*                  If new colour < 16 then
;*                      draw new-colour box in top row
;*                  Else
;*                      draw new-colour box in bottom row
;*              Elseif < 32 colours then
;*                  Set pen to background colour
;*                  Clear old-colour box
;*                  Set pen to foreground colour
;*                  Draw new-colour box
;*              Endif
;*              Return
;*


Selectcolour:

        moveq   #0,d3               ;old colour register
        moveq   #0,d4               ;selected color register
        move.b  count,d0            ;number of colours

        cmpi.b  #32,d0              ;32 colours?
        bne     Count16             ;if not, try 16

;*      Clear old colour

        Setpen  A,Rport,#0          ;background colour
        move.l  #56,d6              ;Y coordinates
        move.l  #66,d7
        move.b  old_colour,d3       ;get old colour number
        cmpi.b  #16,d3              ;is it < 16?
        blt     Oldlt16             ;if yes, leave number and coordinates
        subi.b  #16,d3              ;else, limit number
        addi.l  #10,d6              ;and change Y coordinates
        addi.l  #10,d7

Oldlt16:
        mulu    #11,d3              ; number * 11
        move.l  d3,d5
        addi.l  #5,d5               ;x1 position
        addi.l  #16,d3              ;x2 position
        Drawbox Rport,d5,d6,d3,d7   ;clear old box

;*      Draw selected box

        Setpen  A,Rport,#1          ;highlight colour
        move.l  #56,d6              ;Y coordinates
        move.l  #66,d7
        move.b  colour,d3           ;get selected colour number
        cmpi.b  #16,d3              ;is it < 16?
        blt     Sellt16             ;if yes, leave number and coordinates
        subi.b  #16,d3              ;else, limit number
        addi.l  #10,d6              ;and change Y coordinates
        addi.l  #10,d7
Sellt16:
        mulu    #11,d3              ; number * 11
        move.l  d3,d5
        addi.l  #5,d5               ;x1 position
        addi.l  #16,d3              ;x2 position
        Drawbox Rport,d5,d6,d3,d7   ;draw selected box
        bra     Endselect           ;end routine

Count16:
        cmpi.b  #16,d0              ;16 colours?
        bne     Count8              ;if not try 8

;*      Clear old colour

        Setpen  A,Rport,#0          ;background colour
        move.b  old_colour,d3       ;get old colour number
        mulu    #11,d3              ;number * 11
        move.l  d3,d5
        addi.l  #5,d5               ;x1 position
        addi.l  #16,d3              ;x2 position
        Drawbox Rport,d5,#56,d3,#76 ;clear old box

;*      Draw selected box

        Setpen  A,Rport,#1          ;highlight colour
        move.b  colour,d3           ;get selected colour number
        mulu    #11,d3              ; number * 11
        move.l  d3,d5
        addi.l  #5,d5               ;x1 position
        addi.l  #16,d3              ;x2 position
        Drawbox Rport,d5,#56,d3,#76 ;draw selected box
        bra     Endselect           ;end routine

Count8:
        cmpi.b  #8,d0               ;8 colours?
        bne     Count4              ;if not try 4

;*      Clear old colour

        Setpen  A,Rport,#0          ;background colour
        move.b  old_colour,d3       ;get old colour number
        mulu    #22,d3              ;number * 22
        move.l  d3,d5
        addi.l  #5,d5               ;x1 position
        addi.l  #27,d3              ;x2 position
        Drawbox Rport,d5,#56,d3,#76 ;clear old box

;*      Draw selected box

        Setpen  A,Rport,#1          ;highlight colour
        move.b  colour,d3           ;get selected colour number
        mulu    #22,d3              ; number * 22
        move.l  d3,d5
        addi.l  #5,d5               ;x1 position
        addi.l  #27,d3              ;x2 position
        Drawbox Rport,d5,#56,d3,#76 ;draw selected box
        bra     Endselect           ;end routine

Count4:
        cmpi.b  #4,d0               ;4 colours?
        bne     Count4              ;if not try 4

;*      Clear old colour

        Setpen  A,Rport,#0          ;background colour
        move.b  old_colour,d3       ;get old colour number
        mulu    #44,d3              ;number * 44
        move.l  d3,d5
        addi.l  #5,d5               ;x1 position
        addi.l  #49,d3              ;x2 position
        Drawbox Rport,d5,#56,d3,#76 ;clear old box

;*      Draw selected box

        Setpen  A,Rport,#1          ;highlight colour
        move.b  colour,d3           ;get selected colour number
        mulu    #44,d3              ;number * 44
        move.l  d3,d5
        addi.l  #5,d5               ;x1 position
        addi.l  #49,d3              ;x2 position
        Drawbox Rport,d5,#56,d3,#76 ;draw selected box
        bra     Endselect           ;end routine

Count2:

;*      Clear old colour

        Setpen  A,Rport,#0          ;background colour
        move.b  old_colour,d3       ;get old colour number
        mulu    #88,d3              ;number * 88
        move.l  d3,d5
        addi.l  #5,d5               ;x1 position
        addi.l  #93,d3              ;x2 position
        Drawbox Rport,d5,#56,d3,#76 ;clear old box

;*      Draw selected box

        Setpen  A,Rport,#1          ;highlight colour
        move.b  colour,d3           ;get selected colour number
        mulu    #88,d3              ;number * 88
        move.l  d3,d5
        addi.l  #5,d5               ;x1 position
        addi.l  #93,d3              ;x2 position
        Drawbox Rport,d5,#56,d3,#76 ;draw selected box

Endselect:
        rts                         ;return


;**************************** FIXPROP ************************************
;*
;*      Update the proportional gadgets.

Fixprop:

        movea.l Intbase,a6          ;needs intuition library
        movea.l Colour_table,a2     ;screen colour table pointer
        moveq   #0,d1
        move.b  colour,d1           ;get selected colour number
        lsl.w   #1,d1               ;multiply by byte-to-word factor
        move.w  0(a2,d1),d0         ;get colour RGB value

;*      Calculate HorizPot values

        move.w  d0,d5
        andi.w  #RMASK,d5           ;mask out GB values
        lsr.w   #8,d5               ;position red value
        
        move.w  d0,d6
        andi.w  #GMASK,d6           ;mask out RB values
        lsr.w   #4,d6               ;position green value

        move.w  d0,d7
        andi.w  #BMASK,d7           ;mask out RG values

;*      Modify proportional gadgets

        Modprop Red,Colour_window,d5    ;modify red prop. gadget
        Modprop Green,Colour_window,d6  ;modify green prop. gadget
        Modprop Blue,Colour_window,d7   ;modify blue prop. gadget

        rts                         ;return


;**************************** SPREAD *************************************
;*
;*      Calculates the colour values between the new and the old colour
;*      registers.  This routine is my algorithm to avoid any floating
;*      point maths.  There may be better ones available, but this works.
;*
;*  ALGORITHM:  RGB negative flags = false
;*              If colour > old colour then
;*                  C1 = old colour register number
;*                  C2 = colour register number
;*              Else
;*                  C1 = colour register number
;*                  C2 = old colour register number
;*              Diff = C2 - C1
;*              For each red, green and blue value
;*                  Diffvalue = C2[value] - C1[value]
;*                  If Diffvalue < 0 then
;*                      Diffvalue = -(Diffvalue)
;*                      Set negative flag = true
;*                  Floatvalue = C1[value] * Diff
;*              For counter from C1+1 to C2-1
;*                  For each red, green and blue Floatvalue
;*                      If negative flag = true then
;*                          Floatvalue = Floatvalue - Diffvalue
;*                      Else
;*                          Floatvalue = Floatvalue + Diffvalue
;*                      New RGB value = Floatvalue / Diff
;*                      If Diff <= (2 * remainder) then
;*                          New RGB value = New RGB value + 1
;*                  Set colour[counter] using new RGB values
;*

Spread:

        movea.l Colour_table,a0     ;screen colour table pointer
        movea.l Graphbase,a6        ;routine needs graphics library

;*      Set RGB negative flags

        move.b  #FALSE,rneg
        move.b  #FALSE,gneg
        move.b  #FALSE,bneg

;*      Clear buffers - necessary because we're working with different
;*                      sizes of registers and negative numbers.

        moveq   #0,d0
        moveq   #0,d1
        moveq   #0,d2
        moveq   #0,d3
        moveq   #0,d4
        moveq   #0,d5
        moveq   #0,d6

;*      Calculate difference between colour registers, leaving the
;*      lowest register number in d1, highest in d2.

        move.b  colour,d2           ;selected colour register
        cmp.b   old_colour,d2       ;old <> selected ?
        blt     Highlowreg          ;if old < selected
        move.b  old_colour,d1       ;then save it
        bra     Getdif              ;and get difference
Highlowreg:
        move.b  d2,d1               ;else swap registers
        move.b  old_colour,d2
Getdif:
        move.b  d2,d0               ;get high register
        sub.b   d1,d0               ;and subtract low for difference

;*      Get the RGB values of both registers

        lsl.w   #1,d1               ;byte-to-word factor
        lsl.w   #1,d2               ;for both colours

        move.w  0(a0,d1),d3         ;lower RGB value
        move.w  d3,d4               ;save it
        andi.w  #RMASK,d4           ;mask out GB values
        lsr.w   #8,d4               ;position red value
        move.w  d4,r1               ;and save it

        move.w  d3,d4               ;save RGB value
        andi.w  #GMASK,d4           ;mask out RB values
        lsr.w   #4,d4               ;position green value
        move.w  d4,g1               ;and save it

        andi.w  #BMASK,d3           ;mask out RG values
        move.w  d3,b1               ;save blue value

        move.w  0(a0,d2),d3         ;higher RGB value
        move.w  d3,d4               ;save it
        andi.w  #RMASK,d4           ;mask out GB values
        lsr.w   #8,d4               ;position red value
        move.w  d4,d5               ;and save it

        move.w  d3,d4               ;save RGB value
        andi.w  #GMASK,d4           ;mask out RB values
        lsr.w   #4,d4               ;position green value
        move.w  d4,d6               ;and save it

        andi.w  #BMASK,d3           ;mask out RG values
        move.w  d3,d7               ;save blue value

;*      Calculate the difference between the RGB values

        sub.w   r1,d5               ;red difference
        bge     Rdiff               ;if >= 0, save it unchanged
        move.b  #TRUE,rneg          ;else, set red negative flag
        neg.w   d5                  ;and make it positive
Rdiff:
        move.w  d5,dr               ;save it

        sub.w   g1,d6               ;green difference
        bge     Gdiff               ;if >= 0, save it unchanged
        move.b  #TRUE,gneg          ;else, set green negative flag
        neg.w   d6                  ;and make it positive
Gdiff:
        move.w  d6,dg               ;save it

        sub.w   b1,d7               ;blue difference
        bge     Bdiff               ;if >= 0, save it unchanged
        move.b  #TRUE,bneg          ;else, set blue negative flag
        neg.w   d7                  ;and make it positive
Bdiff:
        move.w  d7,db               ;save it

;*      Initialize the 'float' RGB values

        move.w  d0,d6               ;save difference factor

        clr.l   d0                  ;clear buffer
        move.w  r1,d0               ;initial red value
        muls    d6,d0               ;* diff
        move.w  d0,fr               ;'float' red

        clr.l   d0                  ;clear buffer
        move.w  g1,d0               ;initial green value
        muls    d6,d0               ;* diff
        move.w  d0,fg               ;'float' green

        clr.l   d0                  ;clear buffer
        move.w  b1,d0               ;initial blue value
        muls    d6,d0               ;* diff
        move.w  d0,fb               ;'float' blue

;*      Set up loop counters

        lsr.w   #1,d1               ;reset to low register number
        lsr.w   #1,d2               ;reset to high register number
        moveq   #0,d4               ;clear loop counter
        move.b  d1,d4               ;load with low reg. number
        move.b  d2,d5               ;high register as loop terminator

Spreadloop:

;*      Check the loop

        addq    #1,d4               ;next colour register
        cmp.b   d5,d4               ;high register reached?
        bge     Endspread           ;if yes, end the spread

;*      Clear buffers - they can be altered by SetRGB4

        moveq   #0,d0
        moveq   #0,d1

;*      Add (or subtract) the red difference

        move.w  fr,d1               ;'float' red
        cmpi.b  #TRUE,rneg          ;is R difference negative?
        bne     AddRdiff            ;if not, add difference
        sub.w   dr,d1               ;else, subtract it
        bra     DivR                ;and convert it

AddRdiff:
        add.w   dr,d1               ;add difference
DivR:
        move.w  d1,fr               ;save new 'float'
        divs    d6,d1               ;divide by difference factor
        swap    d1
        move.w  d1,d0               ;get remainder in buffer
        clr.w   d1                  ;remove remainder
        swap    d1                  ;new red value

        lsl.w   #1,d0               ;remainder * 2
        cmp.w   d6,d0               ;remainder >= 0.5?
        blt     Greendiff           ;if not, check green
        addq    #1,d1               ;else, add 1 to red value

;*      Add the green difference

Greendiff:
        move.w  fg,d2               ;'float' green
        cmpi.b  #TRUE,gneg          ;is G difference negative?
        bne     AddGdiff            ;if not, add difference
        sub.w   dg,d2               ;else, subtract it
        bra     DivG                ;and convert it

AddGdiff:
        add.w   dg,d2               ;add difference
DivG:
        move.w  d2,fg               ;save new 'float'
        divs    d6,d2               ;divide by difference factor
        swap    d2
        move.w  d2,d0               ;get remainder
        clr.w   d2                  ;remove remainder
        swap    d2                  ;new green value

        lsl.w   #1,d0               ;remainder * 2
        cmp.w   d6,d0               ;remainder >= 0.5?
        blt     Bluediff            ;if not, check blue
        addq    #1,d2               ;else, add 1 to green value

;*      Add the blue difference

Bluediff:
        move.w  fb,d3               ;'float' blue
        cmpi.b  #TRUE,bneg          ;is B difference negative?
        bne     AddBdiff            ;if not, add difference
        sub.w   db,d3               ;else, subtract it
        bra     DivB                ;and convert it

AddBdiff:
        add.w   db,d3               ;add difference
DivB:
        move.w  d3,fb               ;save new 'float'
        divs    d6,d3               ;divide by difference factor
        swap    d3
        move.w  d3,d0               ;get remainder
        clr.w   d3                  ;remove remainder
        swap    d3                  ;new blue value

        lsl.w   #1,d0               ;remainder * 2
        cmp.w   d6,d0               ;remainder >= 0.5
        blt     Changecolour        ;if not, leave as is
        addq    #1,d3               ;else, add 1 to blue value

;*      Change the colour

Changecolour:
        move.l  d4,d0               ;colour register number
        movea.l Vport,a0            ;screen viewport
        Syslib  SetRGB4             ;set the colour
        bra     Spreadloop          ;next colour

Endspread:
        rts                         ;return


;**************************** CHIP DATA SECTION **************************

        SECTION "Colchip",DATA,CHIP

;*      Sprite Data for the three pointers. We require CHIP memory for
;*      pointers.

To_pointer:

        dc.w    $0000,$0000,

        dc.w    $0000,$fc00,
        dc.w    $7c00,$fe00,
        dc.w    $7c00,$8600,
        dc.w    $7800,$8c00,
        dc.w    $7c00,$8600,
        dc.w    $6e00,$9300,
        dc.w    $0700,$6980,
        dc.w    $0380,$04c0,
        dc.w    $01c0,$0260,
        dc.w    $0080,$0140,
        dc.w    $0000,$0080,
        dc.w    $3e70,$0108,
        dc.w    $0888,$0444,
        dc.w    $0888,$0444,
        dc.w    $0888,$0444,
        dc.w    $0870,$0408,

        dc.w    $0000,$0000

Two_pointer:

        dc.w    $0000,$0000,

        dc.w    $0000,$0c30,
        dc.w    $0810,$1c38,
        dc.w    $1818,$2fec,
        dc.w    $3ffc,$47e6,
        dc.w    $7ffe,$8003,
        dc.w    $3ffc,$4002,
        dc.w    $1818,$27e4,
        dc.w    $0810,$1428,
        dc.w    $0000,$0c30,
        dc.w    $0000,$0000,
        dc.w    $0000,$0000,
        dc.w    $0000,$0000,
        dc.w    $0000,$0000,
        dc.w    $0000,$0000,
        dc.w    $0000,$0000,
        dc.w    $0000,$0000,

        dc.w    $0000,$0000

Normal_pointer:

        dc.w    $0000,$0000,

        dc.w    $0000,$fc00,
        dc.w    $7c00,$fe00,
        dc.w    $7c00,$8600,
        dc.w    $7800,$8c00,
        dc.w    $7c00,$8600,
        dc.w    $6e00,$9300,
        dc.w    $0700,$6980,
        dc.w    $0380,$04c0,
        dc.w    $01c0,$0260,
        dc.w    $0080,$0140,
        dc.w    $0000,$0080,
        dc.w    $0000,$0000,
        dc.w    $0000,$0000,
        dc.w    $0000,$0000,
        dc.w    $0000,$0000,
        dc.w    $0000,$0000,

        dc.w    $0000,$0000


;**************************** DATA SECTION *******************************

        SECTION "Coldata",DATA

;*      String variables

Defaulttitle dc.b 'Colour Window',0 ;* Default colour window title

Fontname dc.b   'topaz.font',0  ;* Go with a ROM font

Rtext   dc.b    'R',0           ;* Proportional gadget text strings
Gtext   dc.b    'G',0
Btext   dc.b    'B',0

SpreadIText dc.b 'SPREAD',0     ;* Boolean gadget text strings
ExIText dc.b    'EX',0
CopyIText dc.b  'COPY',0
UndoIText dc.b  'UNDO',0
OkIText dc.b    'OK',0
CancelIText dc.b 'CANCEL',0

Colour_string   dc.b    '  '    ;* Text buffer for RGB integer values

        even

Rgb1    ds.b    NUMCOL*3        ;* Master RGB backup array
Rgb2    ds.b    NUMCOL*3        ;* UNDO RGB backup array

Red     dc.b    0               ;* Current RGB colour values
Green   dc.b    0               ;*      These begin with uppercase to
Blue    dc.b    0               ;*      comply with some of the macros.

colour      dc.b    0           ;* Colour register we are working with.
old_colour  dc.b    0           ;* Colour register we worked with.
count       dc.b    0           ;* Number of colours

;*      Program message flags

order   dc.b    WORKING         ;* WORKING, CANCEL, QUIT or OK.
mode    dc.b    NOTHING         ;* NOTHING, COPY, EXCHANGE, SPREAD.

;*      Spread subroutine variables

r1      dc.w    0               ;* RGB buffers
g1      dc.w    0
b1      dc.w    0

dr      dc.w    0               ;* RGB increment buffers
dg      dc.w    0
db      dc.w    0

fr      dc.w    0               ;* RGB 'float' buffers
fg      dc.w    0
fb      dc.w    0

rneg    dc.b    FALSE           ;* RGB negative difference flags
gneg    dc.b    FALSE
bneg    dc.b    FALSE

        even

Colour_table    dc.l    0       ;* Pointer to the screen's colour table.

;*      IntuiMessage variables

class   dc.l    0               ;* IDCMP flag.
code    dc.w    0               ;* Extra information. (SELECTDOWN)
Address dc.l    0               ;* Pointer to IAddress
mousex  dc.w    0               ;* Mouse x position.
mousey  dc.w    0               ;* Mouse y position.

;*      Proportional gadget declarations

Rom_font:                           ;* TextAttr structure
        dc.l    Fontname            ;* The name of the font.
        dc.w    TOPAZ_EIGHTY        ;* 80 characters/line.
        dc.b    FS_NORMAL           ;* Normal (plain) style.
        dc.b    FPF_ROMFONT         ;* ROM font.

Red_text:                           ;* IntuiText structure
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    0                   ;* Word alignment filler
        dc.w    -10,2               ;* Left, top edge
        dc.l    Rom_font            ;* ITextFont
        dc.l    Rtext               ;* IText
        dc.l    NULL                ;* NextText

Red_knob ds.b   ig_SIZEOF           ;* Red Image structure

Red_info:                           ;* PropInfo structure
        dc.w    AUTOKNOB|FREEHORIZ  ;* Flags
        dc.w    0                   ;* HorizPot
        dc.w    0                   ;* VertPot
        dc.w    MAXBODY/16          ;* HorizBody
        dc.w    0                   ;* VertBody
        dc.w    0,0,0,0,0,0         ;* Maintained by Intuition

Red_gadget:                         ;* Gadget structure
        dc.l    NULL                ;* NextGadget
        dc.w    15                  ;* LeftEdge
        dc.w    11                  ;* TopEdge
        dc.w    153                 ;* Width
        dc.w    11                  ;* Height
        dc.w    GADGHCOMP           ;* Flags
        dc.w    GADGIMMEDIATE|RELVERIFY|FOLLOWMOUSE    ;* Activation
        dc.w    PROPGADGET          ;* GadgetType
        dc.l    Red_knob            ;* GadgetRender
        dc.l    NULL                ;* SelectRender
        dc.l    Red_text            ;* GadgetText
        dc.l    0                   ;* MutualExclude
        dc.l    Red_info            ;* SpecialInfo
        dc.w    0                   ;* GadgetID
        dc.l    NULL                ;* UserData

Green_text:                         ;* IntuiText structure
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    0                   ;* Word alignment filler
        dc.w    -10,2               ;* Left, top edge
        dc.l    Rom_font            ;* ITextFont
        dc.l    Gtext               ;* IText
        dc.l    NULL                ;* NextText

Green_knob ds.b ig_SIZEOF           ;* Green Image structure

Green_info:                         ;* PropInfo structure
        dc.w    AUTOKNOB|FREEHORIZ  ;* Flags
        dc.w    0                   ;* HorizPot
        dc.w    0                   ;* VertPot
        dc.w    MAXBODY/16          ;* HorizBody
        dc.w    0                   ;* VertBody
        dc.w    0,0,0,0,0,0         ;* Maintained by Intuition

Green_gadget:                       ;* Gadget structure
        dc.l    Red_gadget          ;* NextGadget
        dc.w    15                  ;* LeftEdge
        dc.w    23                  ;* TopEdge
        dc.w    153                 ;* Width
        dc.w    11                  ;* Height
        dc.w    GADGHCOMP           ;* Flags
        dc.w    GADGIMMEDIATE|RELVERIFY|FOLLOWMOUSE    ;* Activation
        dc.w    PROPGADGET          ;* GadgetType
        dc.l    Green_knob          ;* GadgetRender
        dc.l    NULL                ;* SelectRender
        dc.l    Green_text          ;* GadgetText
        dc.l    0                   ;* MutualExclude
        dc.l    Green_info          ;* SpecialInfo
        dc.w    0                   ;* GadgetID
        dc.l    NULL                ;* UserData

Blue_text:                          ;* IntuiText structure
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    0                   ;* Word alignment filler
        dc.w    -10,2               ;* Left, top edge
        dc.l    Rom_font            ;* ITextFont
        dc.l    Btext               ;* IText
        dc.l    NULL                ;* NextText

Blue_knob ds.b  ig_SIZEOF           ;* Blue Image structure

Blue_info:                          ;* PropInfo structure
        dc.w    AUTOKNOB|FREEHORIZ  ;* Flags
        dc.w    0                   ;* HorizPot
        dc.w    0                   ;* VertPot
        dc.w    MAXBODY/16          ;* HorizBody
        dc.w    0                   ;* VertBody
        dc.w    0,0,0,0,0,0         ;* Maintained by Intuition

Blue_gadget:                        ;* Gadget structure
        dc.l    Green_gadget        ;* NextGadget
        dc.w    15                  ;* LeftEdge
        dc.w    35                  ;* TopEdge
        dc.w    153                 ;* Width
        dc.w    11                  ;* Height
        dc.w    GADGHCOMP           ;* Flags
        dc.w    GADGIMMEDIATE|RELVERIFY|FOLLOWMOUSE    ;* Activation
        dc.w    PROPGADGET          ;* GadgetType
        dc.l    Blue_knob           ;* GadgetRender
        dc.l    NULL                ;* SelectRender
        dc.l    Blue_text           ;* GadgetText
        dc.l    0                   ;* MutualExclude
        dc.l    Blue_info           ;* SpecialInfo
        dc.w    0                   ;* GadgetID
        dc.l    NULL                ;* UserData


;*      Border declarations

points6 dc.w    0,0,52,0,52,10,0,10,0,0     ;* Data for a 6-letter box
points4 dc.w    0,0,36,0,36,10,0,10,0,0     ;* Data for a 4-letter box
points2 dc.w    0,0,20,0,20,10,0,10,0,0     ;* Data for a 2-letter box

Box6:                               ;* Border structure
        dc.w    0                   ;* LeftEdge
        dc.w    0                   ;* TopEdge
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    5                   ;* Count
        dc.l    points6             ;* XY
        dc.l    NULL                ;* NextBorder

Box4:                               ;* Border structure
        dc.w    0                   ;* LeftEdge
        dc.w    0                   ;* TopEdge
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    5                   ;* Count
        dc.l    points4             ;* XY
        dc.l    NULL                ;* NextBorder

Box2:                               ;* Border structure
        dc.w    0                   ;* LeftEdge
        dc.w    0                   ;* TopEdge
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    5                   ;* Count
        dc.l    points2             ;* XY
        dc.l    NULL                ;* NextBorder


;*      Boolean gadget declarations

Spread_text:                        ;* IntuiText structure
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    0                   ;* Word filler
        dc.w    3,2                 ;* Left, top edge
        dc.l    Rom_font            ;* ITextFont
        dc.l    SpreadIText         ;* IText
        dc.l    NULL                ;* NextText

Spread_gadget:                      ;* Gadget structure
        dc.l    Blue_gadget         ;* NextGadget
        dc.w    195                 ;* LeftEdge
        dc.w    23                  ;* TopEdge
        dc.w    53                  ;* Width
        dc.w    11                  ;* Height
        dc.w    GADGHCOMP           ;* Flags
        dc.w    RELVERIFY           ;* Activation
        dc.w    BOOLGADGET          ;* GadgetType
        dc.l    Box6                ;* GadgetRender
        dc.l    NULL                ;* SelectRender
        dc.l    Spread_text         ;* GadgetText
        dc.l    0                   ;* MutualExclude
        dc.l    NULL                ;* SpecialInfo
        dc.w    0                   ;* GadgetID
        dc.l    NULL                ;* UserData

Ex_text:                            ;* IntuiText structure
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    0                   ;* Word filler
        dc.w    3,2                 ;* Left, top edge
        dc.l    Rom_font            ;* ITextFont
        dc.l    ExIText             ;* IText
        dc.l    NULL                ;* NextText

Ex_gadget:                          ;* Gadget structure
        dc.l    Spread_gadget       ;* NextGadget
        dc.w    251                 ;* LeftEdge
        dc.w    23                  ;* TopEdge
        dc.w    21                  ;* Width
        dc.w    11                  ;* Height
        dc.w    GADGHCOMP           ;* Flags
        dc.w    RELVERIFY           ;* Activation
        dc.w    BOOLGADGET          ;* GadgetType
        dc.l    Box2                ;* GadgetRender
        dc.l    NULL                ;* SelectRender
        dc.l    Ex_text             ;* GadgetText
        dc.l    0                   ;* MutualExclude
        dc.l    NULL                ;* SpecialInfo
        dc.w    0                   ;* GadgetID
        dc.l    NULL                ;* UserData

Copy_text:                          ;* IntuiText structure
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    0                   ;* Word filler
        dc.w    3,2                 ;* Left, top edge
        dc.l    Rom_font            ;* ITextFont
        dc.l    CopyIText           ;* IText
        dc.l    NULL                ;* NextText

Copy_gadget:                        ;* Gadget structure
        dc.l    Ex_gadget           ;* NextGadget
        dc.w    195                 ;* LeftEdge
        dc.w    35                  ;* TopEdge
        dc.w    37                  ;* Width
        dc.w    11                  ;* Height
        dc.w    GADGHCOMP           ;* Flags
        dc.w    RELVERIFY           ;* Activation
        dc.w    BOOLGADGET          ;* GadgetType
        dc.l    Box4                ;* GadgetRender
        dc.l    NULL                ;* SelectRender
        dc.l    Copy_text           ;* GadgetText
        dc.l    0                   ;* MutualExclude
        dc.l    NULL                ;* SpecialInfo
        dc.w    0                   ;* GadgetID
        dc.l    NULL                ;* UserData

Undo_text:                          ;* IntuiText structure
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    0                   ;* Word filler
        dc.w    3,2                 ;* Left, top edge
        dc.l    Rom_font            ;* ITextFont
        dc.l    UndoIText           ;* IText
        dc.l    NULL                ;* NextText

Undo_gadget:                        ;* Gadget structure
        dc.l    Copy_gadget         ;* NextGadget
        dc.w    235                 ;* LeftEdge
        dc.w    35                  ;* TopEdge
        dc.w    37                  ;* Width
        dc.w    11                  ;* Height
        dc.w    GADGHCOMP           ;* Flags
        dc.w    RELVERIFY           ;* Activation
        dc.w    BOOLGADGET          ;* GadgetType
        dc.l    Box4                ;* GadgetRender
        dc.l    NULL                ;* SelectRender
        dc.l    Undo_text           ;* GadgetText
        dc.l    0                   ;* MutualExclude
        dc.l    NULL                ;* SpecialInfo
        dc.w    0                   ;* GadgetID
        dc.l    NULL                ;* UserData

Ok_text:                            ;* IntuiText structure
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    0                   ;* Word filler
        dc.w    3,2                 ;* Left, top edge
        dc.l    Rom_font            ;* ITextFont
        dc.l    OkIText             ;* IText
        dc.l    NULL                ;* NextText

Ok_gadget:                          ;* Gadget structure
        dc.l    Undo_gadget         ;* NextGadget
        dc.w    195                 ;* LeftEdge
        dc.w    65                  ;* TopEdge
        dc.w    21                  ;* Width
        dc.w    11                  ;* Height
        dc.w    GADGHCOMP           ;* Flags
        dc.w    RELVERIFY           ;* Activation
        dc.w    BOOLGADGET          ;* GadgetType
        dc.l    Box2                ;* GadgetRender
        dc.l    NULL                ;* SelectRender
        dc.l    Ok_text             ;* GadgetText
        dc.l    0                   ;* MutualExclude
        dc.l    NULL                ;* SpecialInfo
        dc.w    0                   ;* GadgetID
        dc.l    NULL                ;* UserData

Cancel_text:                        ;* IntuiText structure
        dc.b    1                   ;* FrontPen
        dc.b    0                   ;* BackPen
        dc.b    JAM1                ;* DrawMode
        dc.b    0                   ;* Word filler
        dc.w    3,2                 ;* Left, top edge
        dc.l    Rom_font            ;* ITextFont
        dc.l    CancelIText         ;* IText
        dc.l    NULL                ;* NextText

Cancel_gadget:                      ;* Gadget structure
        dc.l    Ok_gadget           ;* NextGadget
        dc.w    219                 ;* LeftEdge
        dc.w    65                  ;* TopEdge
        dc.w    53                  ;* Width
        dc.w    11                  ;* Height
        dc.w    GADGHCOMP           ;* Flags
        dc.w    RELVERIFY           ;* Activation
        dc.w    BOOLGADGET          ;* GadgetType
        dc.l    Box6                ;* GadgetRender
        dc.l    NULL                ;* SelectRender
        dc.l    Cancel_text         ;* GadgetText
        dc.l    0                   ;* MutualExclude
        dc.l    NULL                ;* SpecialInfo
        dc.w    0                   ;* GadgetID
        dc.l    NULL                ;* UserData


;*      ColourWindow data structure - this is how you want the window
;*                                    set up.

Colour_window_data:             ;* NewWindow structure
        dc.w    0               ;* LeftEdge  x position, will be changed.
        dc.w    0               ;* TopEdge   y position, will be changed.
        dc.w    277             ;* Width       277 pixels wide.
        dc.w    80              ;* Height      80 lines high.
        dc.b    0               ;* DetailPen
        dc.b    1               ;* BlockPen
        dc.l    MOUSEMOVE|MOUSEBUTTONS|GADGETDOWN|GADGETUP|CLOSEWINDOW
        dc.l    SMART_REFRESH|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|ACTIVATE|RMBTRAP
        dc.l    Cancel_gadget   ;* FirstGadget pointer
        dc.l    NULL            ;* CheckMark, use Intuition's default.
        dc.l    Defaulttitle    ;* Title, may be changed
        dc.l    NULL            ;* Screen pointer, will be changed.
        dc.l    NULL            ;* BitMap      No Custom BitMap.
        dc.w    0,0,0,0         ;* Min and max sizes - no sizing gadget
        dc.w    WBENCHSCREEN    ;* Type, may be changed.

Colour_window dc.l  0           ;* Pointer to Window structure - this
                                ;*   results when you open the window.
Rport   dc.l    0               ;* Pointer to Colour_window rastport

Wscreen dc.l    0               ;* Pointer to screen
Vport   dc.l    0               ;* Pointer to screen viewport


;*************************************************************************

        END
