2026-04-29 09:28:35 +02:00
|
|
|
type statetype
|
|
|
|
|
tool as long
|
|
|
|
|
fcolor as long
|
|
|
|
|
bcolor as long
|
2026-05-20 10:24:07 +02:00
|
|
|
offsetx as long
|
|
|
|
|
offsety as long
|
2026-05-27 11:03:51 +02:00
|
|
|
zoom as long
|
2026-04-30 13:16:00 +02:00
|
|
|
brushsize as integer
|
2026-05-20 10:24:07 +02:00
|
|
|
startx as long
|
|
|
|
|
starty as long
|
|
|
|
|
isdrawing as integer
|
2026-04-29 09:28:35 +02:00
|
|
|
end type
|
2026-06-08 12:23:37 +02:00
|
|
|
|
2026-04-29 09:28:35 +02:00
|
|
|
type layertype
|
|
|
|
|
ihandle as long
|
|
|
|
|
blendmode as long
|
|
|
|
|
filter as long
|
2026-04-29 12:36:31 +02:00
|
|
|
kind as long
|
2026-04-29 09:28:35 +02:00
|
|
|
end type
|
|
|
|
|
|
2026-05-01 00:30:34 +02:00
|
|
|
redim shared layers(3) as layertype
|
2026-04-29 09:28:35 +02:00
|
|
|
dim shared state as statetype
|
2026-05-06 13:28:56 +02:00
|
|
|
redim shared commands(0) as string
|
2026-05-20 10:24:07 +02:00
|
|
|
dim shared showtoolbox as _byte:showtoolbox=-1
|
|
|
|
|
dim shared showcolorpicker as _byte:showcolorpicker=-1
|
|
|
|
|
dim shared showcommands as _byte:showcommands=0
|
2026-04-29 09:28:35 +02:00
|
|
|
|
|
|
|
|
dim shared mouseclicked as integer
|
|
|
|
|
dim shared mousedown as integer
|
2026-04-29 12:36:31 +02:00
|
|
|
dim shared rmouseclicked as integer
|
|
|
|
|
dim shared rmousedown as integer
|
2026-04-30 10:09:05 +02:00
|
|
|
|
2026-04-29 12:36:31 +02:00
|
|
|
$resize:on
|
2026-04-30 08:23:26 +02:00
|
|
|
screen _newimage(750,480,32)
|
2026-04-29 12:36:31 +02:00
|
|
|
_delay 0.1
|
2026-06-08 12:23:37 +02:00
|
|
|
dim temp as long:temp=_resize
|
2026-04-29 12:36:31 +02:00
|
|
|
redim shared pal(0) as _unsigned long
|
2026-05-22 12:58:45 +02:00
|
|
|
|
|
|
|
|
loadpalette"custodian-8",pal()
|
2026-05-04 12:14:29 +02:00
|
|
|
layers(0).ihandle=_newimage(320,320,32)
|
|
|
|
|
layers(1).ihandle=_newimage(320,320,32)
|
|
|
|
|
layers(2).ihandle=_newimage(320,320,32)
|
|
|
|
|
layers(3).ihandle=_newimage(320,320,32)
|
2026-05-01 00:30:34 +02:00
|
|
|
|
2026-04-29 21:17:20 +02:00
|
|
|
_dest layers(0).ihandle
|
2026-05-20 10:24:07 +02:00
|
|
|
addcommand"canvas ("+tst(_width)+","+tst(_height)+")"
|
|
|
|
|
for y=0 to _height-16 step 16
|
|
|
|
|
for x=0 to _width-16 step 16
|
|
|
|
|
if ((x+y)/16 and 1)=0 then
|
|
|
|
|
line (x,y)-(x+16,y+16),_rgb32(127),bf
|
2026-05-11 11:39:10 +02:00
|
|
|
else
|
2026-05-20 10:24:07 +02:00
|
|
|
line (x,y)-(x+16,y+16),_rgb32(192),bf
|
2026-05-11 11:39:10 +02:00
|
|
|
end if
|
|
|
|
|
next
|
|
|
|
|
next
|
2026-04-29 21:17:20 +02:00
|
|
|
_dest 0
|
2026-05-20 10:24:07 +02:00
|
|
|
state.tool=1
|
2026-05-27 11:03:51 +02:00
|
|
|
state.zoom=1
|
2026-05-20 10:24:07 +02:00
|
|
|
state.offsetx=70+20
|
|
|
|
|
state.offsety=20
|
|
|
|
|
state. brushsize=1
|
2026-05-11 10:03:44 +02:00
|
|
|
state.fcolor=closestcolor(_rgb32(0,0,0),pal())
|
|
|
|
|
state.bcolor=closestcolor(_rgb32(255,255,255),pal())
|
2026-05-20 10:24:07 +02:00
|
|
|
addcommand"fcolor ("+hex$(state.fcolor)+")"
|
|
|
|
|
addcommand"bcolor ("+hex$(state.bcolor)+")"
|
2026-05-11 10:03:44 +02:00
|
|
|
|
2026-06-08 12:30:31 +02:00
|
|
|
dim shared fonthandles(1 to 10) as integer
|
|
|
|
|
dim shared activefontindex as integer:activefontindex=1
|
|
|
|
|
dim shared activefontsize as single:activefontsize=16
|
|
|
|
|
dim shared texttoolstring as string
|
|
|
|
|
|
|
|
|
|
fonthandles(1)=loadbgifont("./fonts/SIMP.CHR")
|
|
|
|
|
fonthandles(2)=loadbgifont("./fonts/BOLD.CHR")
|
|
|
|
|
fonthandles(3)=loadbgifont("./fonts/EURO.CHR")
|
|
|
|
|
fonthandles(4)=loadbgifont("./fonts/GOTH.CHR")
|
|
|
|
|
fonthandles(5)=loadbgifont("./fonts/LCOM.CHR")
|
|
|
|
|
fonthandles(6)=loadbgifont("./fonts/LITT.CHR")
|
|
|
|
|
fonthandles(7)=loadbgifont("./fonts/SANS.CHR")
|
|
|
|
|
fonthandles(8)=loadbgifont("./fonts/SCRI.CHR")
|
|
|
|
|
fonthandles(9)=loadbgifont("./fonts/TRIP.CHR")
|
|
|
|
|
fonthandles(10)=loadbgifont("./fonts/TSCR.CHR")
|
2026-05-28 14:07:51 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
dim lastmx,lastmy
|
2026-04-30 13:16:00 +02:00
|
|
|
dim keyin as string
|
2026-05-27 11:03:51 +02:00
|
|
|
dim mouseworldy as long
|
|
|
|
|
dim mouseworldx as long
|
2026-05-20 10:24:07 +02:00
|
|
|
|
|
|
|
|
dim diffx as integer
|
|
|
|
|
dim diffy as integer
|
|
|
|
|
dim oldwidth as integer
|
|
|
|
|
dim oldheight as integer
|
|
|
|
|
oldwidth=_width
|
|
|
|
|
oldheight=_height
|
2026-04-29 09:28:35 +02:00
|
|
|
do
|
2026-05-27 13:52:39 +02:00
|
|
|
' Check for window resizing first
|
2026-05-20 10:24:07 +02:00
|
|
|
if checkresize(_source)=-1 then
|
|
|
|
|
diffx=_width-oldwidth
|
|
|
|
|
diffy=_height-oldheight
|
|
|
|
|
state.offsetx=state.offsetx+(diffx/2)
|
|
|
|
|
state.offsety=state.offsety+(diffy/2)
|
|
|
|
|
oldwidth=_width
|
|
|
|
|
oldheight=_height
|
2026-04-30 10:09:05 +02:00
|
|
|
end if
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-05-27 22:43:07 +02:00
|
|
|
cls,backgroundcolor1
|
2026-05-11 10:03:44 +02:00
|
|
|
|
2026-05-27 13:52:39 +02:00
|
|
|
' Process all inputs and update offsets
|
2026-04-30 13:16:00 +02:00
|
|
|
while _mouseinput:mw=mw+_mousewheel:wend
|
2026-05-20 10:24:07 +02:00
|
|
|
mouseclicked=0
|
|
|
|
|
rmouseclicked=0
|
|
|
|
|
if mousedown=-1 and _mousebutton(1)=0 then mouseclicked=-1
|
|
|
|
|
if rmousedown=-1 and _mousebutton(2)=0 then rmouseclicked=-1
|
|
|
|
|
mousedown=_mousebutton(1)
|
|
|
|
|
rmousedown=_mousebutton(2)
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-05-27 13:52:39 +02:00
|
|
|
' Panning
|
2026-04-30 10:09:05 +02:00
|
|
|
if _mousebutton(3) then
|
2026-05-27 11:03:51 +02:00
|
|
|
state.offsetx=state.offsetx+(_mousex-lastmx)
|
|
|
|
|
state.offsety=state.offsety+(_mousey-lastmy)
|
2026-04-30 10:09:05 +02:00
|
|
|
end if
|
2026-05-20 10:24:07 +02:00
|
|
|
lastmx=_mousex:lastmy=_mousey
|
2026-05-04 11:24:14 +02:00
|
|
|
|
2026-04-30 10:09:05 +02:00
|
|
|
' Zooming
|
2026-05-20 10:24:07 +02:00
|
|
|
if mw<>0 then
|
|
|
|
|
mouseworldx=(_mousex-state.offsetx)/state.zoom
|
|
|
|
|
mouseworldy=(_mousey-state.offsety)/state.zoom
|
2026-05-27 11:03:51 +02:00
|
|
|
if mw>0 then state.zoom=state.zoom+1 else state.zoom=state.zoom-1
|
2026-05-20 10:24:07 +02:00
|
|
|
if state.zoom<1 then state.zoom=1
|
|
|
|
|
if state.zoom>20 then state.zoom=20
|
|
|
|
|
state.offsetx=_mousex-(mouseworldx*state.zoom)
|
|
|
|
|
state.offsety=_mousey-(mouseworldy*state.zoom)
|
|
|
|
|
mw=0
|
2026-05-19 12:23:01 +02:00
|
|
|
end if
|
2026-04-30 13:16:00 +02:00
|
|
|
|
|
|
|
|
' Keyboarding
|
2026-05-28 14:07:51 +02:00
|
|
|
if not state.tool=16 and not state.isdrawing then
|
2026-06-08 12:30:31 +02:00
|
|
|
keyin=inkey$
|
|
|
|
|
select case keyin
|
|
|
|
|
case chr$(27)
|
|
|
|
|
menu
|
|
|
|
|
case "+"
|
|
|
|
|
state.brushsize=state.brushsize+1
|
2026-05-27 11:11:55 +02:00
|
|
|
addcommand"brushsize ("+tst(state.brushsize)+")"
|
2026-06-08 12:30:31 +02:00
|
|
|
case "-"
|
|
|
|
|
if state.brushsize>1 then
|
|
|
|
|
state.brushsize=state.brushsize-1
|
|
|
|
|
addcommand"brushsize ("+tst(state.brushsize)+")"
|
|
|
|
|
end if
|
|
|
|
|
case "h"
|
|
|
|
|
state.zoom=1
|
|
|
|
|
state.offsetx=(_width/2)-(_width(layers(0).ihandle)/2)
|
|
|
|
|
state.offsety=(_height/2)-(_height(layers(0).ihandle)/2)
|
|
|
|
|
|
|
|
|
|
case "f","F"
|
|
|
|
|
' --- ZOOM TO FIT ("f") OR OVERFLOW SHORTEST SIDE ("F") ---
|
|
|
|
|
' 1. Calculate and choose the fitting ratio based on the lowercase/uppercase state
|
|
|
|
|
if (((_width-(showtoolbox and 70)-(showcommands and 250)) \ _width(layers(0).ihandle))<((_height-(showcolorpicker and 20)) \ _height(layers(0).ihandle)) xor (keyin="F")) then
|
|
|
|
|
state.zoom=((_width-(showtoolbox and 70)-(showcommands and 250)) \ _width(layers(0).ihandle))
|
|
|
|
|
else
|
|
|
|
|
state.zoom=((_height-(showcolorpicker and 20)) \ _height(layers(0).ihandle))
|
|
|
|
|
end if
|
2026-05-27 22:43:07 +02:00
|
|
|
|
2026-06-08 12:30:31 +02:00
|
|
|
' 2. Clamp the zoom factor within safe limits (1 to 20)
|
|
|
|
|
if state.zoom<1 then state.zoom=1 else if state.zoom>20 then state.zoom=20
|
|
|
|
|
|
|
|
|
|
' 3. Center the canvas inside the viewport (overflowing sides will center-clip perfectly)
|
|
|
|
|
state.offsetx=(showtoolbox and 70)+(((_width-(showtoolbox and 70)-(showcommands and 250)) \ 2)-((_width(layers(0).ihandle)*state.zoom) \ 2))
|
|
|
|
|
state.offsety=(((_height-(showcolorpicker and 20)) \ 2)-((_height(layers(0).ihandle)*state.zoom) \ 2))
|
|
|
|
|
|
|
|
|
|
case "t"
|
|
|
|
|
showtoolbox=not showtoolbox
|
|
|
|
|
case "c"
|
|
|
|
|
showcolorpicker=not showcolorpicker
|
|
|
|
|
case "l"
|
|
|
|
|
showcommands=not showcommands
|
|
|
|
|
case chr$(26) ' Ctrl+Z
|
|
|
|
|
if ubound(commands)>3 then
|
|
|
|
|
' Drop the trailing empty slot and the last valid command
|
|
|
|
|
redim _preserve commands(ubound(commands)-2) as string
|
|
|
|
|
' Re-create the empty trailing slot required by addcommand
|
|
|
|
|
redim _preserve commands(ubound(commands)+1) as string
|
|
|
|
|
redraw
|
|
|
|
|
end if
|
|
|
|
|
end select
|
2026-05-28 14:07:51 +02:00
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
|
2026-05-27 11:03:51 +02:00
|
|
|
canvas
|
|
|
|
|
if showtoolbox then toolbox
|
|
|
|
|
if showcolorpicker then colorpicker
|
2026-06-08 12:30:31 +02:00
|
|
|
if state.tool=12 then drawtexttoolpanel
|
2026-05-29 10:10:01 +02:00
|
|
|
if showcommands then commandlist
|
2026-04-29 09:28:35 +02:00
|
|
|
_limit 30
|
|
|
|
|
_display
|
|
|
|
|
loop
|
|
|
|
|
|
2026-05-06 13:28:56 +02:00
|
|
|
sub commandlist
|
|
|
|
|
dim i as long
|
2026-05-20 10:24:07 +02:00
|
|
|
dim listwidth as integer:listwidth=250
|
|
|
|
|
dim x as integer:x=_width-listwidth
|
2026-05-12 09:29:36 +02:00
|
|
|
|
2026-05-06 13:28:56 +02:00
|
|
|
' Draw background for the list
|
2026-05-20 10:24:07 +02:00
|
|
|
line (x,0)-(_width-1,_height-1),backgroundcolor1,bf
|
2026-05-11 10:03:44 +02:00
|
|
|
line (x,0)-(x,_height-1),backgroundcolor2
|
2026-05-12 09:29:36 +02:00
|
|
|
|
2026-05-06 13:28:56 +02:00
|
|
|
_printmode _keepbackground
|
2026-05-11 10:03:44 +02:00
|
|
|
dim y as integer
|
2026-05-20 10:24:07 +02:00
|
|
|
for i=ubound(commands)-1 to 0 step -1
|
|
|
|
|
y=(ubound(commands)-i)*16
|
|
|
|
|
if y<_height-20 then
|
2026-06-08 12:08:22 +02:00
|
|
|
select case link(x+5,y+5,left$(commands(i),31))
|
|
|
|
|
case -1 ' Left-Click triggers the inline text rename input box
|
|
|
|
|
commands(i)=textinput(x+5,y+5,248,23,commands(i))
|
|
|
|
|
case -2 ' Right-Click opens the context menu layout overlay
|
2026-06-08 12:30:31 +02:00
|
|
|
listcontextmenu i,_mousex,_mousey
|
2026-06-08 12:08:22 +02:00
|
|
|
exit sub
|
|
|
|
|
end select
|
2026-05-06 13:28:56 +02:00
|
|
|
end if
|
|
|
|
|
next i
|
2026-05-20 10:24:07 +02:00
|
|
|
if button(x,_height-25,60,23,"redraw") then redraw
|
2026-05-12 10:17:52 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-06-08 12:30:31 +02:00
|
|
|
sub listcontextmenu (index as long,mx as integer,my as integer)
|
|
|
|
|
if index<0 or index>=ubound(commands) then exit sub
|
|
|
|
|
|
|
|
|
|
dim done as integer:done=0
|
|
|
|
|
dim menuw as integer:menuw=120
|
|
|
|
|
dim menuh as integer:menuh=6*24+4 ' 6 items at 24px layout spacing
|
2026-06-08 12:08:22 +02:00
|
|
|
|
|
|
|
|
' Position correction so context panels don't clip outside screens
|
2026-06-08 12:30:31 +02:00
|
|
|
dim x as integer:x=mx
|
|
|
|
|
if x+menuw>_width then x=_width-menuw
|
|
|
|
|
dim y as integer:y=my
|
|
|
|
|
if y+menuh>_height then y=_height-menuh
|
2026-06-08 12:08:22 +02:00
|
|
|
|
|
|
|
|
do
|
|
|
|
|
' UI Backdrop reconstruction stack to prevent flickering frames
|
2026-06-08 12:30:31 +02:00
|
|
|
cls,backgroundcolor1
|
2026-06-08 12:08:22 +02:00
|
|
|
canvas
|
|
|
|
|
if showtoolbox then toolbox
|
|
|
|
|
if showcolorpicker then colorpicker
|
2026-06-08 12:30:31 +02:00
|
|
|
if state.tool=12 then drawtexttoolpanel
|
|
|
|
|
|
2026-06-08 12:08:22 +02:00
|
|
|
' Manual render block for command list data under the active frame
|
2026-06-08 12:30:31 +02:00
|
|
|
dim lx as integer:lx=_width-250
|
|
|
|
|
line (lx,0)-(_width-1,_height-1),backgroundcolor1,bf
|
|
|
|
|
line (lx,0)-(lx,_height-1),backgroundcolor2
|
2026-06-08 12:08:22 +02:00
|
|
|
_printmode _keepbackground
|
2026-06-08 12:30:31 +02:00
|
|
|
dim ly as integer,i as long
|
|
|
|
|
for i=ubound(commands)-1 to 0 step -1
|
|
|
|
|
ly=(ubound(commands)-i)*16
|
|
|
|
|
if ly<_height-20 then
|
|
|
|
|
_printstring (lx+5,ly+5),left$(commands(i),31)
|
2026-06-08 12:08:22 +02:00
|
|
|
end if
|
|
|
|
|
next i
|
2026-06-08 12:30:31 +02:00
|
|
|
if button(lx,_height-25,60,23,"redraw") then redraw
|
2026-06-08 12:08:22 +02:00
|
|
|
|
|
|
|
|
' Render Context Container Box
|
2026-06-08 12:30:31 +02:00
|
|
|
line (x,y)-(x+menuw,y+menuh),backgroundcolor1,bf
|
|
|
|
|
line (x,y)-(x+menuw,y+menuh),highlightcolor,b
|
2026-06-08 12:08:22 +02:00
|
|
|
|
|
|
|
|
' Standard poll for incoming click state loops
|
2026-06-08 12:30:31 +02:00
|
|
|
while _mouseinput:wend
|
|
|
|
|
mouseclicked=0:rmouseclicked=0
|
|
|
|
|
if mousedown=-1 and _mousebutton(1)=0 then mouseclicked=-1
|
|
|
|
|
if rmousedown=-1 and _mousebutton(2)=0 then rmouseclicked=-1
|
|
|
|
|
mousedown=_mousebutton(1)
|
|
|
|
|
rmousedown=_mousebutton(2)
|
2026-06-08 12:08:22 +02:00
|
|
|
|
|
|
|
|
' Clicking completely outside the menu closes the context window
|
|
|
|
|
if mouseclicked or rmouseclicked then
|
2026-06-08 12:30:31 +02:00
|
|
|
if not (_mousex>x and _mousex<x+menuw and _mousey>y and _mousey<y+menuh) then
|
|
|
|
|
done=-1
|
2026-06-08 12:08:22 +02:00
|
|
|
end if
|
|
|
|
|
end if
|
|
|
|
|
|
2026-06-08 12:30:31 +02:00
|
|
|
dim bx as integer:bx=x+2
|
|
|
|
|
dim by as integer:by=y+2
|
|
|
|
|
dim bw as integer:bw=menuw-4
|
|
|
|
|
dim bh as integer:bh=22
|
2026-06-08 12:08:22 +02:00
|
|
|
|
|
|
|
|
' Item 1: Delete
|
2026-06-08 12:30:31 +02:00
|
|
|
if button(bx,by,bw,bh,"Delete") then
|
2026-06-08 12:08:22 +02:00
|
|
|
dim k as long
|
2026-06-08 12:30:31 +02:00
|
|
|
for k=index to ubound(commands)-1
|
|
|
|
|
commands(k)=commands(k+1)
|
2026-06-08 12:08:22 +02:00
|
|
|
next k
|
2026-06-08 12:30:31 +02:00
|
|
|
redim _preserve commands(ubound(commands)-1) as string
|
2026-06-08 12:08:22 +02:00
|
|
|
redraw
|
2026-06-08 12:30:31 +02:00
|
|
|
done=-1
|
2026-06-08 12:08:22 +02:00
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
by=by+24
|
2026-06-08 12:08:22 +02:00
|
|
|
' Item 2: Move Up (moves toward end of array visually)
|
2026-06-08 12:30:31 +02:00
|
|
|
if button(bx,by,bw,bh,"Move Up") then
|
|
|
|
|
if index<ubound(commands)-2 then
|
|
|
|
|
dim tempcmd as string
|
|
|
|
|
tempcmd=commands(index)
|
|
|
|
|
commands(index)=commands(index+1)
|
|
|
|
|
commands(index+1)=tempcmd
|
2026-06-08 12:08:22 +02:00
|
|
|
redraw
|
|
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
done=-1
|
2026-06-08 12:08:22 +02:00
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
by=by+24
|
2026-06-08 12:08:22 +02:00
|
|
|
|
|
|
|
|
' Item 3: Move Down (moves toward array index 0)
|
2026-06-08 12:30:31 +02:00
|
|
|
if button(bx,by,bw,bh,"Move Down") then
|
|
|
|
|
if index>0 then
|
|
|
|
|
tempcmd=commands(index)
|
|
|
|
|
commands(index)=commands(index-1)
|
|
|
|
|
commands(index-1)=tempcmd
|
2026-06-08 12:08:22 +02:00
|
|
|
redraw
|
|
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
done=-1
|
2026-06-08 12:08:22 +02:00
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
by=by+24
|
2026-06-08 12:08:22 +02:00
|
|
|
|
|
|
|
|
' Item 4: Insert Above
|
2026-06-08 12:30:31 +02:00
|
|
|
if button(bx,by,bw,bh,"Insert Above") then
|
|
|
|
|
redim _preserve commands(ubound(commands)+1) as string
|
|
|
|
|
for k=ubound(commands)-1 to index+2 step -1
|
|
|
|
|
commands(k)=commands(k-1)
|
2026-06-08 12:08:22 +02:00
|
|
|
next k
|
2026-06-08 12:30:31 +02:00
|
|
|
commands(index+1)=""
|
2026-06-08 12:08:22 +02:00
|
|
|
redraw
|
2026-06-08 12:30:31 +02:00
|
|
|
done=-1
|
2026-06-08 12:08:22 +02:00
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
by=by+24
|
2026-06-08 12:08:22 +02:00
|
|
|
|
|
|
|
|
' Item 5: Insert Below
|
2026-06-08 12:30:31 +02:00
|
|
|
if button(bx,by,bw,bh,"Insert Below") then
|
|
|
|
|
redim _preserve commands(ubound(commands)+1) as string
|
|
|
|
|
for k=ubound(commands)-1 to index+1 step -1
|
|
|
|
|
commands(k)=commands(k-1)
|
2026-06-08 12:08:22 +02:00
|
|
|
next k
|
2026-06-08 12:30:31 +02:00
|
|
|
commands(index)=""
|
2026-06-08 12:08:22 +02:00
|
|
|
redraw
|
2026-06-08 12:30:31 +02:00
|
|
|
done=-1
|
2026-06-08 12:08:22 +02:00
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
by=by+24
|
2026-06-08 12:08:22 +02:00
|
|
|
|
|
|
|
|
' Item 6: Copy to OS Clipboard
|
2026-06-08 12:30:31 +02:00
|
|
|
if button(bx,by,bw,bh,"Copy") then
|
|
|
|
|
_clipboard$=commands(index)
|
|
|
|
|
done=-1
|
2026-06-08 12:08:22 +02:00
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
_limit 30
|
|
|
|
|
_display
|
|
|
|
|
loop until done or _keydown(27)
|
2026-06-08 12:30:31 +02:00
|
|
|
|
2026-06-08 12:08:22 +02:00
|
|
|
' Flush trailing triggers so the next loop cycle doesn't draw accidental strokes
|
2026-06-08 12:30:31 +02:00
|
|
|
mouseclicked=0
|
|
|
|
|
rmouseclicked=0
|
2026-06-08 12:08:22 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-06-08 12:30:31 +02:00
|
|
|
sub drawtexttoolpanel
|
|
|
|
|
dim panelwidth as integer:panelwidth=160
|
|
|
|
|
dim x as integer:x=_width-panelwidth
|
|
|
|
|
static showfontlist as integer ' Tracks the expanding drop-down list state
|
2026-05-28 14:07:51 +02:00
|
|
|
|
2026-05-29 10:10:01 +02:00
|
|
|
if showcommands then
|
2026-06-08 12:30:31 +02:00
|
|
|
x=_width-panelwidth-250
|
2026-05-29 10:10:01 +02:00
|
|
|
else
|
2026-06-08 12:30:31 +02:00
|
|
|
x=_width-panelwidth
|
2026-05-29 10:10:01 +02:00
|
|
|
end if
|
|
|
|
|
|
2026-05-28 14:07:51 +02:00
|
|
|
' Draw the side panel background card block
|
2026-06-08 12:30:31 +02:00
|
|
|
line (x,0)-(_width-1,_height-1),backgroundcolor1,bf
|
|
|
|
|
line (x,0)-(x,_height-1),backgroundcolor2
|
|
|
|
|
|
2026-05-28 14:07:51 +02:00
|
|
|
_printmode _keepbackground
|
2026-06-08 12:30:31 +02:00
|
|
|
_printstring (x+10,15),"TEXT TOOL OPTIONS"
|
|
|
|
|
line (x+10,30)-(x+140,30),backgroundcolor2
|
2026-05-28 14:07:51 +02:00
|
|
|
|
|
|
|
|
' --- Font Size Controls ---
|
2026-06-08 12:30:31 +02:00
|
|
|
_printstring (x+10,45),"Size: "+tst(int(activefontsize))
|
|
|
|
|
if button(x+85,42,24,20,"-") then
|
|
|
|
|
if activefontsize>4 then activefontsize=activefontsize-2
|
2026-05-28 14:07:51 +02:00
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
if button(x+115,42,24,20,"+") then
|
|
|
|
|
if activefontsize<120 then activefontsize=activefontsize+2
|
2026-05-28 14:07:51 +02:00
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
' --- Expandable Font Selection Links ---
|
2026-06-08 12:30:31 +02:00
|
|
|
dim currentfontname as string
|
|
|
|
|
select case activefontindex
|
|
|
|
|
case 1:currentfontname="SIMP.CHR"
|
|
|
|
|
case 2:currentfontname="BOLD.CHR"
|
|
|
|
|
case 3:currentfontname="EURO.CHR"
|
|
|
|
|
case 4:currentfontname="GOTH.CHR"
|
|
|
|
|
case 5:currentfontname="LCOM.CHR"
|
|
|
|
|
case 6:currentfontname="LITT.CHR"
|
|
|
|
|
case 7:currentfontname="SANS.CHR"
|
|
|
|
|
case 8:currentfontname="SCRI.CHR"
|
|
|
|
|
case 9:currentfontname="TRIP.CHR"
|
|
|
|
|
case 10:currentfontname="TSCR.CHR"
|
2026-05-28 14:07:51 +02:00
|
|
|
end select
|
|
|
|
|
|
2026-06-08 12:30:31 +02:00
|
|
|
_printstring (x+10,80),"Font: "
|
|
|
|
|
if link(x+55,80,"["+currentfontname+" ]") then
|
|
|
|
|
showfontlist=not showfontlist ' Toggle expansion list visibility
|
2026-05-28 14:07:51 +02:00
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
' Render the drop-down links when expanded
|
2026-06-08 12:30:31 +02:00
|
|
|
if showfontlist then
|
|
|
|
|
dim fontnames(1 to 10) as string
|
|
|
|
|
fontnames(1)="Simplex":fontnames(2)="Bold":fontnames(3)="Euro"
|
|
|
|
|
fontnames(4)="Gothic":fontnames(5)="Complex":fontnames(6)="Little"
|
|
|
|
|
fontnames(7)="Sans":fontnames(8)="Script":fontnames(9)="Triplex"
|
|
|
|
|
fontnames(10)="TScript"
|
|
|
|
|
|
|
|
|
|
dim ly as integer,idx as integer
|
|
|
|
|
for idx=1 to 10
|
|
|
|
|
ly=80+(idx*20)
|
2026-05-28 14:07:51 +02:00
|
|
|
' Highlight the currently active font selection with an asterisk
|
2026-06-08 12:30:31 +02:00
|
|
|
dim itemprefix as string
|
|
|
|
|
if idx=activefontindex then itemprefix="* "else itemprefix=" "
|
|
|
|
|
|
|
|
|
|
if link(x+20,ly,itemprefix+fontnames(idx)) then
|
|
|
|
|
activefontindex=idx
|
|
|
|
|
showfontlist=0 ' Auto-collapse list upon selection
|
2026-05-28 14:07:51 +02:00
|
|
|
end if
|
|
|
|
|
next idx
|
|
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
|
2026-05-28 14:07:51 +02:00
|
|
|
' Guard the UI boundaries so clicks on this panel do not draw on the canvas below it
|
2026-06-08 12:30:31 +02:00
|
|
|
if _mousex>=x then
|
|
|
|
|
if _mousebutton(1) or _mousebutton(2) then mouseclicked=0:rmouseclicked=0
|
2026-05-28 14:07:51 +02:00
|
|
|
end if
|
|
|
|
|
end sub
|
|
|
|
|
|
2026-05-12 10:17:52 +02:00
|
|
|
sub redraw
|
|
|
|
|
redim numarr(0) as long
|
2026-05-18 14:05:35 +02:00
|
|
|
dim i as integer
|
|
|
|
|
dim j as integer
|
|
|
|
|
dim x as long
|
|
|
|
|
dim y as long
|
2026-05-12 11:47:31 +02:00
|
|
|
_dest layers(1).ihandle
|
|
|
|
|
_source layers(1).ihandle
|
2026-05-20 10:24:07 +02:00
|
|
|
cls,_rgb32(255)
|
2026-05-12 11:47:31 +02:00
|
|
|
_clearcolor _rgb32(255)
|
2026-05-12 10:17:52 +02:00
|
|
|
for i=lbound(commands) to ubound(commands)
|
2026-05-12 11:47:31 +02:00
|
|
|
getnums commands(i),numarr()
|
|
|
|
|
_dest layers(1).ihandle
|
2026-05-20 09:06:25 +02:00
|
|
|
_source layers(1).ihandle
|
2026-05-12 10:17:52 +02:00
|
|
|
select case lcase$(_trim$(left$(commands(i),instr(commands(i),"(")-1)))
|
2026-05-19 12:23:01 +02:00
|
|
|
case "canvas"
|
|
|
|
|
for j=0 to 3
|
2026-05-20 10:24:07 +02:00
|
|
|
if layers(j).ihandle<>0 then _freeimage layers(j).ihandle
|
|
|
|
|
layers(j).ihandle=_newimage(numarr(0),numarr(1),32)
|
2026-05-19 12:23:01 +02:00
|
|
|
next j
|
|
|
|
|
_dest layers(0).ihandle
|
2026-05-20 10:24:07 +02:00
|
|
|
for y=0 to _height-16 step 16
|
|
|
|
|
for x=0 to _width-16 step 16
|
|
|
|
|
if ((x+y)/16 and 1)=0 then
|
|
|
|
|
line (x,y)-(x+16,y+16),_rgb32(127),bf
|
2026-05-19 12:23:01 +02:00
|
|
|
else
|
2026-05-20 10:24:07 +02:00
|
|
|
line (x,y)-(x+16,y+16),_rgb32(192),bf
|
2026-05-19 12:23:01 +02:00
|
|
|
end if
|
|
|
|
|
next
|
2026-05-18 14:05:35 +02:00
|
|
|
next
|
2026-05-19 12:23:01 +02:00
|
|
|
|
|
|
|
|
case "fcolor"
|
|
|
|
|
state.fcolor=numarr(0)
|
|
|
|
|
case "bcolor"
|
|
|
|
|
state.bcolor=numarr(0)
|
|
|
|
|
case "brushsize"
|
|
|
|
|
state.brushsize=numarr(0)
|
|
|
|
|
case "pixel"
|
|
|
|
|
thickpixel numarr(0),numarr(1),numarr(2)
|
|
|
|
|
case "line"
|
|
|
|
|
thickline numarr(0),numarr(1),numarr(2),numarr(3),numarr(4)
|
|
|
|
|
case "box"
|
|
|
|
|
thickbox numarr(0),numarr(1),numarr(2),numarr(3),numarr(4)
|
|
|
|
|
case "fbox"
|
|
|
|
|
filledbox numarr(0),numarr(1),numarr(2),numarr(3),numarr(4)
|
|
|
|
|
case "circle"
|
|
|
|
|
thickcircle numarr(0),numarr(1),numarr(2),numarr(3)
|
|
|
|
|
case "fcircle"
|
|
|
|
|
filledcircle numarr(0),numarr(1),numarr(2),numarr(3)
|
|
|
|
|
case "polygon"
|
|
|
|
|
polygon numarr(),state.fcolor
|
|
|
|
|
case "fpolygon"
|
2026-05-20 10:24:07 +02:00
|
|
|
filledpolygon numarr(),state.fcolor
|
2026-05-19 12:23:01 +02:00
|
|
|
case "floodfill"
|
2026-05-20 10:24:07 +02:00
|
|
|
floodfill numarr(0),numarr(1),numarr(2)
|
2026-05-22 12:58:45 +02:00
|
|
|
case "boundaryfill"
|
|
|
|
|
boundaryfill numarr(0),numarr(1),numarr(2),numarr(3)
|
2026-05-21 09:22:52 +02:00
|
|
|
case "gradient"
|
|
|
|
|
ditheredgradient numarr(0),numarr(1),numarr(2),numarr(3),state.fcolor,state.bcolor
|
2026-05-28 14:07:51 +02:00
|
|
|
case "gradient"
|
2026-06-08 12:30:31 +02:00
|
|
|
ditheredgradient numarr(0),numarr(1),numarr(2),numarr(3),state.fcolor,state.bcolor
|
|
|
|
|
|
2026-05-28 14:07:51 +02:00
|
|
|
case "text"
|
2026-06-08 12:30:31 +02:00
|
|
|
' Extract the string parameter from the command structure manually
|
2026-05-28 14:07:51 +02:00
|
|
|
' e.g., text (X, Y, FontHandleIndex, FontSize, FColor, Your String Content)
|
2026-06-08 12:30:31 +02:00
|
|
|
dim txtstart as integer:txtstart=instr(commands(i),",")
|
2026-05-28 14:07:51 +02:00
|
|
|
' Advance past the first 5 commas to isolate the text string
|
2026-06-08 12:30:31 +02:00
|
|
|
dim commacount as integer:commacount=0
|
|
|
|
|
dim searchpos as integer:searchpos=1
|
|
|
|
|
while commacount<5
|
|
|
|
|
searchpos=instr(searchpos,commands(i),",")
|
|
|
|
|
if searchpos>0 then
|
|
|
|
|
commacount=commacount+1
|
|
|
|
|
searchpos=searchpos+1
|
2026-05-28 14:07:51 +02:00
|
|
|
else
|
|
|
|
|
exit while
|
|
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
wend
|
|
|
|
|
if commacount=5 then
|
|
|
|
|
dim textmsg as string
|
|
|
|
|
textmsg=mid$(commands(i),searchpos,instr(searchpos,commands(i),")")-searchpos)
|
2026-05-28 14:07:51 +02:00
|
|
|
' Draw text to the drawing layer directly
|
2026-06-08 12:30:31 +02:00
|
|
|
displaybgitext fonthandles(numarr(2)),numarr(0),numarr(1),textmsg,numarr(3),numarr(4)
|
2026-05-28 14:07:51 +02:00
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
|
2026-05-19 12:23:01 +02:00
|
|
|
case ""
|
|
|
|
|
' blank line do nothing
|
|
|
|
|
case else
|
|
|
|
|
'debug info
|
2026-05-20 10:24:07 +02:00
|
|
|
print"'"+lcase$(_trim$(left$(commands(i),instr(commands(i),"(")-1)))+"'"
|
2026-05-12 10:17:52 +02:00
|
|
|
end select
|
|
|
|
|
next i
|
2026-05-12 11:47:31 +02:00
|
|
|
_dest 0
|
|
|
|
|
_source 0
|
2026-05-06 13:28:56 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
sub getnums (inputstr$,numarray() as long)
|
2026-05-12 11:47:31 +02:00
|
|
|
' 1. Extract inner content
|
2026-05-20 10:24:07 +02:00
|
|
|
spos=instr(inputstr$,"(")
|
|
|
|
|
epos=instr(inputstr$,")")
|
|
|
|
|
if spos=0 or epos<=spos then exit sub
|
2026-05-19 12:23:01 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
content$=mid$(inputstr$,spos+1,epos-spos-1)
|
|
|
|
|
idx=-1 ' Start at -1 so the first increment hits 0
|
2026-05-12 11:47:31 +02:00
|
|
|
|
|
|
|
|
' 2. Parse segments
|
2026-05-19 12:23:01 +02:00
|
|
|
do
|
2026-05-20 10:24:07 +02:00
|
|
|
cpos=instr(content$,",")
|
|
|
|
|
if cpos>0 then
|
|
|
|
|
part$=ltrim$(rtrim$(left$(content$,cpos-1)))
|
|
|
|
|
content$=mid$(content$,cpos+1)
|
2026-05-19 12:23:01 +02:00
|
|
|
else
|
2026-05-20 10:24:07 +02:00
|
|
|
part$=ltrim$(rtrim$(content$))
|
|
|
|
|
content$=""
|
2026-05-19 12:23:01 +02:00
|
|
|
end if
|
2026-05-12 11:47:31 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
if len(part$)>0 then
|
|
|
|
|
idx=idx+1
|
|
|
|
|
redim _preserve numarray(idx) as long
|
2026-05-19 12:23:01 +02:00
|
|
|
|
2026-05-12 11:47:31 +02:00
|
|
|
' Determine if part is Hex (contains A-F)
|
2026-05-20 10:24:07 +02:00
|
|
|
ishex=0
|
|
|
|
|
for i=1 to len(part$)
|
|
|
|
|
c$=ucase$(mid$(part$,i,1))
|
|
|
|
|
if c$>="A"and c$<="F"then
|
|
|
|
|
ishex=1
|
2026-05-19 12:23:01 +02:00
|
|
|
exit for
|
|
|
|
|
end if
|
|
|
|
|
next i
|
|
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
if ishex then
|
|
|
|
|
numarray(idx)=val("&H"+part$)
|
2026-05-19 12:23:01 +02:00
|
|
|
else
|
2026-05-20 10:24:07 +02:00
|
|
|
numarray(idx)=val(part$)
|
2026-05-19 12:23:01 +02:00
|
|
|
end if
|
|
|
|
|
end if
|
2026-05-20 10:24:07 +02:00
|
|
|
loop while len(content$)>0
|
2026-05-19 12:23:01 +02:00
|
|
|
end sub
|
2026-05-12 11:47:31 +02:00
|
|
|
|
2026-04-29 09:28:35 +02:00
|
|
|
sub toolbox
|
2026-05-20 10:24:07 +02:00
|
|
|
dim i,x,y
|
|
|
|
|
dim btnsize:btnsize=32
|
|
|
|
|
dim spacing:spacing=1
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
for i=0 to 19
|
|
|
|
|
x=(i mod 2)*(btnsize+spacing)
|
|
|
|
|
y=int(i/2)*(btnsize+spacing)
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
if imagebutton(x,y,btnsize,btnsize,icon(i)) then
|
|
|
|
|
state.tool=i+1
|
2026-04-30 10:09:05 +02:00
|
|
|
end if
|
|
|
|
|
next
|
2026-05-11 10:03:44 +02:00
|
|
|
|
|
|
|
|
'colorindicator
|
2026-05-20 10:24:07 +02:00
|
|
|
y=y+btnsize+16
|
2026-05-11 10:03:44 +02:00
|
|
|
line (16,y+16)-(64,y+64),state.bcolor,bf
|
|
|
|
|
line (16,y+16)-(64,y+64),highlightcolor,b
|
|
|
|
|
line (0,y)-(48,y+48),state.fcolor,bf
|
|
|
|
|
line (0,y)-(48,y+48),highlightcolor,b
|
2026-05-20 10:24:07 +02:00
|
|
|
if clickregion(0,y,48,48) then
|
2026-05-11 12:41:20 +02:00
|
|
|
palettemanager state.fcolor
|
2026-05-20 10:24:07 +02:00
|
|
|
elseif clickregion(16,y+16,48,48) then
|
2026-05-11 12:41:20 +02:00
|
|
|
palettemanager state.bcolor
|
|
|
|
|
end if
|
|
|
|
|
end sub
|
|
|
|
|
|
2026-04-29 09:28:35 +02:00
|
|
|
sub colorpicker
|
2026-05-20 11:30:31 +02:00
|
|
|
static img as long
|
|
|
|
|
if img=0 then img=_newimage(16,16,32)
|
2026-04-29 12:36:31 +02:00
|
|
|
for i=0 to ubound(pal)
|
|
|
|
|
_dest img
|
2026-05-20 10:24:07 +02:00
|
|
|
cls,pal(i)
|
2026-04-29 12:36:31 +02:00
|
|
|
line (0,0)-(_width-1,height-1),pal(i),bf
|
|
|
|
|
_dest 0
|
|
|
|
|
select case imagebutton(i*16,_height-17,16,16,img)
|
|
|
|
|
case -1
|
|
|
|
|
state.fcolor=pal(i)
|
2026-05-20 10:24:07 +02:00
|
|
|
addcommand"fcolor ("+hex$(pal(i))+")"
|
2026-04-29 12:36:31 +02:00
|
|
|
case -2
|
|
|
|
|
state.bcolor=pal(i)
|
2026-05-20 10:24:07 +02:00
|
|
|
addcommand"bcolor ("+hex$(pal(i))+")"
|
2026-05-04 13:49:56 +02:00
|
|
|
end select
|
2026-04-29 12:36:31 +02:00
|
|
|
next i
|
2026-04-29 09:28:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-06 13:28:56 +02:00
|
|
|
sub addcommand(cmd as string)
|
|
|
|
|
'this check is probably more clever than good is.
|
|
|
|
|
if commands(ubound(commands)+(ubound(commands)>0))<>cmd then
|
|
|
|
|
commands(ubound(commands))=cmd
|
|
|
|
|
redim _preserve commands(ubound(commands)+1) as string
|
|
|
|
|
end if
|
|
|
|
|
end sub
|
|
|
|
|
|
|
|
|
|
sub canvas
|
2026-05-04 11:24:14 +02:00
|
|
|
' 1. Define the Viewport (The "Window" on your screen)
|
2026-05-20 10:24:07 +02:00
|
|
|
dim viewx1 as integer
|
|
|
|
|
if showtoolbox then viewx1=70 else viewx1=0
|
|
|
|
|
dim viewy1 as integer:viewy1=0
|
|
|
|
|
dim viewx2 as integer
|
|
|
|
|
if showcommands then viewx2=_width-151 else viewx2=_width-1
|
|
|
|
|
dim viewy2 as integer
|
|
|
|
|
if showcolorpicker then viewy2=_height-20 else viewy2=_height-1
|
2026-05-01 00:30:34 +02:00
|
|
|
_dest 0
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-05-27 11:08:49 +02:00
|
|
|
' 2. Render Layers (Let QB64 handle the viewport clipping natively)
|
|
|
|
|
dim i as integer
|
|
|
|
|
for i=0 to ubound(layers)
|
|
|
|
|
dim img as long:img=layers(i).ihandle
|
|
|
|
|
dim imgw as integer:imgw=_width(img)
|
|
|
|
|
dim imgh as integer:imgh=_height(img)
|
|
|
|
|
|
|
|
|
|
' Calculate the absolute unclipped destination positions
|
|
|
|
|
drawx1=state.offsetx
|
|
|
|
|
drawy1=state.offsety
|
|
|
|
|
drawx2=state.offsetx+(imgw*state.zoom)
|
|
|
|
|
drawy2=state.offsety+(imgh*state.zoom)
|
|
|
|
|
|
|
|
|
|
' Direct 1:1 mapping of the entire source asset
|
|
|
|
|
srcx1=0
|
|
|
|
|
srcy1=0
|
|
|
|
|
srcx2=imgw
|
|
|
|
|
srcy2=imgh
|
|
|
|
|
|
|
|
|
|
' Only draw if the asset is within the general view window range
|
|
|
|
|
if drawx2>viewx1 and drawx1<viewx2 and drawy2>viewy1 and drawy1<viewy2 then
|
|
|
|
|
_putimage (drawx1,drawy1)-(drawx2,drawy2),img,0,(srcx1,srcy1)-(srcx2,srcy2)
|
|
|
|
|
end if
|
|
|
|
|
next
|
2026-05-20 10:24:07 +02:00
|
|
|
_dest layers(2).ihandle:cls,0:_dest 0
|
2026-05-28 14:07:51 +02:00
|
|
|
' 2.5 Check if the mouse pointer is hitting the UI boundaries
|
2026-06-08 12:30:31 +02:00
|
|
|
dim mouseinui as _byte
|
|
|
|
|
mouseinui=0
|
|
|
|
|
|
|
|
|
|
if showtoolbox and (_mousex>=0 and _mousex<=70) then mouseinui=-1
|
|
|
|
|
if showcolorpicker and (_mousey>=_height-20) then mouseinui=-1
|
|
|
|
|
if showcommands and (_mousex>=drawx2) then mouseinui=-1
|
|
|
|
|
|
|
|
|
|
' 3. Calculate Canvas Coordinates (Center-aligned to the zoom block)
|
|
|
|
|
dim canx as long
|
|
|
|
|
dim cany as long
|
|
|
|
|
|
|
|
|
|
canx=int((_mousex-state.offsetx+(state.zoom \ 2))/state.zoom)
|
|
|
|
|
cany=int((_mousey-state.offsety+(state.zoom \ 2))/state.zoom)
|
|
|
|
|
|
|
|
|
|
static drawcol
|
|
|
|
|
if _mousebutton(1) then drawcol=state.fcolor
|
|
|
|
|
if _mousebutton(2) then drawcol=state.bcolor
|
|
|
|
|
|
|
|
|
|
' ONLY initiate drawing actions if the mouse is NOT in the UI
|
|
|
|
|
if mouseinui=0 then
|
|
|
|
|
if (mousedown or rmousedown) and state.isdrawing=0 then
|
|
|
|
|
state.startx=canx
|
|
|
|
|
state.starty=cany
|
|
|
|
|
state.isdrawing=-1
|
2026-05-06 13:28:56 +02:00
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
' Bypass tool execution for regular click-and-drag shapes,
|
|
|
|
|
' but ALWAYS allow text tool (12) to pass through so it draws the live overlay
|
|
|
|
|
if mouseinui=0 or state.tool=12 then
|
|
|
|
|
select case state.tool
|
|
|
|
|
case 1
|
|
|
|
|
do.pencil canx,cany,drawcol
|
|
|
|
|
case 2
|
|
|
|
|
do.line state.startx,state.starty,canx,cany,drawcol
|
|
|
|
|
case 3
|
|
|
|
|
do.circle state.startx,state.starty,canx,cany,drawcol
|
|
|
|
|
case 4
|
|
|
|
|
do.fcircle state.startx,state.starty,canx,cany,drawcol
|
|
|
|
|
case 5
|
|
|
|
|
do.box state.startx,state.starty,canx,cany,drawcol
|
|
|
|
|
case 6
|
|
|
|
|
do.fbox state.startx,state.starty,canx,cany,drawcol
|
|
|
|
|
case 7
|
|
|
|
|
do.polygon canx,cany
|
|
|
|
|
case 8
|
|
|
|
|
do.fpolygon canx,cany
|
|
|
|
|
case 9
|
|
|
|
|
do.floodfill canx,cany,drawcol
|
|
|
|
|
case 10
|
|
|
|
|
do.eyedropper canx,cany
|
|
|
|
|
case 11
|
|
|
|
|
do.gradient state.startx,state.starty,canx,cany
|
|
|
|
|
case 12
|
|
|
|
|
do.text canx,cany,drawcol
|
|
|
|
|
end select
|
|
|
|
|
end if
|
2026-04-29 09:28:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
sub do.pencil(x as long,y as long,col as long)
|
2026-05-19 12:23:01 +02:00
|
|
|
dim osource as long
|
|
|
|
|
dim odest as long
|
2026-05-20 10:24:07 +02:00
|
|
|
osource=_source
|
|
|
|
|
odest=_dest
|
2026-05-19 12:23:01 +02:00
|
|
|
_dest layers(1).ihandle
|
|
|
|
|
if _mousebutton(1) or _mousebutton(2) then
|
|
|
|
|
thickpixel x,y,col
|
2026-05-20 10:24:07 +02:00
|
|
|
addcommand"pixel ("+tst(x)+","+tst(y)+","+hex$(col)+")"
|
2026-05-19 12:23:01 +02:00
|
|
|
end if
|
2026-05-20 10:24:07 +02:00
|
|
|
state.isdrawing=0
|
2026-05-19 12:23:01 +02:00
|
|
|
_dest odest
|
2026-05-18 14:05:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
|
|
|
|
sub do.line(sx as long,sy as long,ex as long,ey as long,col as long)
|
2026-05-19 12:23:01 +02:00
|
|
|
dim osource as long
|
|
|
|
|
dim odest as long
|
2026-05-22 13:10:54 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
if state.isdrawing then
|
|
|
|
|
osource=_source
|
|
|
|
|
odest=_dest
|
2026-05-22 13:10:54 +02:00
|
|
|
|
|
|
|
|
if _keydown(100303) or _keydown(100304) then
|
|
|
|
|
dim dx as single:dx=ex-sx
|
|
|
|
|
dim dy as single:dy=ey-sy
|
|
|
|
|
if dx<>0 or dy<>0 then
|
|
|
|
|
dim linelen as single:linelen=sqr(dx*dx+dy*dy)
|
|
|
|
|
dim angle as single:angle=_atan2(dy,dx)
|
2026-05-22 13:56:25 +02:00
|
|
|
dim degrees as single:degrees=angle*(180.0/_pi)
|
2026-05-22 13:10:54 +02:00
|
|
|
dim snappeddegrees as single:snappeddegrees=int((degrees+22.5)/45.0)*45.0
|
2026-05-22 13:56:25 +02:00
|
|
|
dim snappedangle as single:snappedangle=snappeddegrees*(_pi/180.0)
|
2026-05-22 13:10:54 +02:00
|
|
|
ex=sx+_round(linelen*cos(snappedangle))
|
|
|
|
|
ey=sy+_round(linelen*sin(snappedangle))
|
|
|
|
|
end if
|
|
|
|
|
end if
|
|
|
|
|
|
2026-05-19 12:23:01 +02:00
|
|
|
if mouseclicked or rmouseclicked then
|
|
|
|
|
_dest layers(1).ihandle
|
2026-05-20 10:24:07 +02:00
|
|
|
addcommand"line ("+tst(sx)+","+tst(sy)+","+tst(ex)+","+tst(ey)+","+hex$(col)+")"
|
|
|
|
|
state.isdrawing=0
|
2026-05-19 12:23:01 +02:00
|
|
|
else
|
|
|
|
|
_dest layers(2).ihandle
|
|
|
|
|
end if
|
2026-05-22 13:10:54 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
thickline sx,sy,ex,ey,col
|
2026-05-19 12:23:01 +02:00
|
|
|
_source osource
|
|
|
|
|
_dest odest
|
|
|
|
|
end if
|
2026-05-18 14:05:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-22 13:56:25 +02:00
|
|
|
sub do.circle (sx as long,sy as long,ex as long,ey as long,col as long)
|
2026-05-19 12:23:01 +02:00
|
|
|
dim osource as long
|
|
|
|
|
dim odest as long
|
2026-05-22 13:56:25 +02:00
|
|
|
dim x as long,y as long,r as long
|
2026-05-27 11:08:49 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
if state.isdrawing then
|
|
|
|
|
osource=_source
|
|
|
|
|
odest=_dest
|
2026-05-27 11:08:49 +02:00
|
|
|
|
2026-05-22 13:56:25 +02:00
|
|
|
if _keydown(100303) or _keydown(100304) then
|
|
|
|
|
' --- Shift Held: Locked Edge Diameter Mode ---
|
|
|
|
|
' Calculate the full distance from the start click to the mouse pointer
|
|
|
|
|
dim diameter as single
|
2026-05-27 11:08:49 +02:00
|
|
|
diameter=sqr((ex-sx) ^ 2+(ey-sy) ^ 2)
|
|
|
|
|
|
|
|
|
|
r=_round(diameter/2)
|
|
|
|
|
|
2026-05-22 13:56:25 +02:00
|
|
|
' The center is the exact midpoint between the click and the cursor
|
2026-05-27 11:08:49 +02:00
|
|
|
x=_round((sx+ex)/2)
|
|
|
|
|
y=_round((sy+ey)/2)
|
2026-05-22 13:56:25 +02:00
|
|
|
else
|
|
|
|
|
' --- No Shift: Default Center-Radius Mode ---
|
2026-05-27 11:08:49 +02:00
|
|
|
x=sx
|
|
|
|
|
y=sy
|
|
|
|
|
r=_round(sqr((ex-sx) ^ 2+(ey-sy) ^ 2))
|
2026-05-22 13:56:25 +02:00
|
|
|
end if
|
|
|
|
|
|
2026-05-19 12:23:01 +02:00
|
|
|
if mouseclicked or rmouseclicked then
|
|
|
|
|
_dest layers(1).ihandle
|
2026-05-20 10:24:07 +02:00
|
|
|
addcommand"circle ("+tst(x)+","+tst(y)+","+tst(int(r))+","+hex$(col)+")"
|
|
|
|
|
state.isdrawing=0
|
2026-05-19 12:23:01 +02:00
|
|
|
else
|
|
|
|
|
_dest layers(2).ihandle
|
|
|
|
|
end if
|
2026-05-20 10:24:07 +02:00
|
|
|
thickcircle x,y,r,col
|
2026-05-19 12:23:01 +02:00
|
|
|
_source osource
|
|
|
|
|
_dest odest
|
|
|
|
|
end if
|
2026-05-18 14:05:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-22 13:56:25 +02:00
|
|
|
sub do.fcircle (sx as long,sy as long,ex as long,ey as long,col as long)
|
2026-05-19 12:23:01 +02:00
|
|
|
dim osource as long
|
|
|
|
|
dim odest as long
|
2026-05-22 13:56:25 +02:00
|
|
|
dim x as long,y as long,r as long
|
2026-05-27 11:08:49 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
if state.isdrawing then
|
|
|
|
|
osource=_source
|
|
|
|
|
odest=_dest
|
2026-05-27 11:08:49 +02:00
|
|
|
|
2026-05-22 13:56:25 +02:00
|
|
|
if _keydown(100303) or _keydown(100304) then
|
|
|
|
|
' --- Shift Held: Locked Edge Diameter Mode ---
|
|
|
|
|
' Calculate the full distance from the start click to the mouse pointer
|
|
|
|
|
dim diameter as single
|
2026-05-27 11:08:49 +02:00
|
|
|
diameter=sqr((ex-sx) ^ 2+(ey-sy) ^ 2)
|
|
|
|
|
|
|
|
|
|
r=_round(diameter/2)
|
|
|
|
|
|
2026-05-22 13:56:25 +02:00
|
|
|
' The center is the exact midpoint between the click and the cursor
|
2026-05-27 11:08:49 +02:00
|
|
|
x=_round((sx+ex)/2)
|
|
|
|
|
y=_round((sy+ey)/2)
|
2026-05-22 13:56:25 +02:00
|
|
|
else
|
|
|
|
|
' --- No Shift: Default Center-Radius Mode ---
|
2026-05-27 11:08:49 +02:00
|
|
|
x=sx
|
|
|
|
|
y=sy
|
|
|
|
|
r=_round(sqr((ex-sx) ^ 2+(ey-sy) ^ 2))
|
2026-05-22 13:56:25 +02:00
|
|
|
end if
|
|
|
|
|
|
2026-05-19 12:23:01 +02:00
|
|
|
if mouseclicked or rmouseclicked then
|
|
|
|
|
_dest layers(1).ihandle
|
2026-05-20 10:24:07 +02:00
|
|
|
addcommand"fcircle ("+tst(x)+","+tst(y)+","+tst(int(r))+","+hex$(col)+")"
|
|
|
|
|
state.isdrawing=0
|
2026-05-19 12:23:01 +02:00
|
|
|
else
|
|
|
|
|
_dest layers(2).ihandle
|
|
|
|
|
end if
|
2026-05-20 10:24:07 +02:00
|
|
|
filledcircle x,y,r,col
|
2026-05-19 12:23:01 +02:00
|
|
|
_source osource
|
|
|
|
|
_dest odest
|
|
|
|
|
end if
|
2026-05-18 14:05:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-22 13:59:15 +02:00
|
|
|
sub do.box (sx as long,sy as long,ex as long,ey as long,col as long)
|
2026-05-19 12:23:01 +02:00
|
|
|
dim osource as long
|
|
|
|
|
dim odest as long
|
2026-05-27 11:08:49 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
if state.isdrawing then
|
|
|
|
|
osource=_source
|
|
|
|
|
odest=_dest
|
2026-05-27 11:08:49 +02:00
|
|
|
|
2026-05-22 13:59:15 +02:00
|
|
|
' --- Shift Held: Perfect Square Constraint ---
|
|
|
|
|
if _keydown(100303) or _keydown(100304) then
|
2026-05-27 11:08:49 +02:00
|
|
|
dim dx as long:dx=ex-sx
|
|
|
|
|
dim dy as long:dy=ey-sy
|
|
|
|
|
|
2026-05-22 13:59:15 +02:00
|
|
|
' Determine the longest side to use as the square dimensions
|
|
|
|
|
dim size as long
|
2026-05-27 11:08:49 +02:00
|
|
|
if abs(dx)>abs(dy) then size=abs(dx) else size=abs(dy)
|
|
|
|
|
|
2026-05-22 13:59:15 +02:00
|
|
|
' Shift coordinates relative to the direction of the drag
|
2026-05-27 11:08:49 +02:00
|
|
|
dim signx as long:if dx>=0 then signx=1 else signx=-1
|
|
|
|
|
dim signy as long:if dy>=0 then signy=1 else signy=-1
|
|
|
|
|
|
|
|
|
|
ex=sx+(size*signx)
|
|
|
|
|
ey=sy+(size*signy)
|
2026-05-22 13:59:15 +02:00
|
|
|
end if
|
|
|
|
|
' ---------------------------------------------
|
|
|
|
|
|
2026-05-19 12:23:01 +02:00
|
|
|
if mouseclicked or rmouseclicked then
|
|
|
|
|
_dest layers(1).ihandle
|
2026-05-20 10:24:07 +02:00
|
|
|
addcommand"box ("+tst(sx)+","+tst(sy)+","+tst(ex)+","+tst(ey)+","+hex$(col)+")"
|
|
|
|
|
state.isdrawing=0
|
2026-05-19 12:23:01 +02:00
|
|
|
else
|
|
|
|
|
_dest layers(2).ihandle
|
|
|
|
|
end if
|
|
|
|
|
thickbox sx,sy,ex,ey,col
|
|
|
|
|
_source osource
|
|
|
|
|
_dest odest
|
|
|
|
|
end if
|
2026-05-18 14:05:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-22 13:59:15 +02:00
|
|
|
sub do.fbox (sx as long,sy as long,ex as long,ey as long,col as long)
|
2026-05-19 12:23:01 +02:00
|
|
|
dim osource as long
|
|
|
|
|
dim odest as long
|
2026-05-27 11:08:49 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
if state.isdrawing then
|
|
|
|
|
osource=_source
|
|
|
|
|
odest=_dest
|
2026-05-27 11:08:49 +02:00
|
|
|
|
2026-05-22 13:59:15 +02:00
|
|
|
' --- Shift Held: Perfect Square Constraint ---
|
|
|
|
|
if _keydown(100303) or _keydown(100304) then
|
2026-05-27 11:08:49 +02:00
|
|
|
dim dx as long:dx=ex-sx
|
|
|
|
|
dim dy as long:dy=ey-sy
|
|
|
|
|
|
2026-05-22 13:59:15 +02:00
|
|
|
' Determine the longest side to use as the square dimensions
|
|
|
|
|
dim size as long
|
2026-05-27 11:08:49 +02:00
|
|
|
if abs(dx)>abs(dy) then size=abs(dx) else size=abs(dy)
|
|
|
|
|
|
2026-05-22 13:59:15 +02:00
|
|
|
' Shift coordinates relative to the direction of the drag
|
2026-05-27 11:08:49 +02:00
|
|
|
dim signx as long:if dx>=0 then signx=1 else signx=-1
|
|
|
|
|
dim signy as long:if dy>=0 then signy=1 else signy=-1
|
|
|
|
|
|
|
|
|
|
ex=sx+(size*signx)
|
|
|
|
|
ey=sy+(size*signy)
|
2026-05-22 13:59:15 +02:00
|
|
|
end if
|
|
|
|
|
' ---------------------------------------------
|
|
|
|
|
|
2026-05-19 12:23:01 +02:00
|
|
|
if mouseclicked or rmouseclicked then
|
|
|
|
|
_dest layers(1).ihandle
|
2026-05-20 10:24:07 +02:00
|
|
|
addcommand"fbox ("+tst(sx)+","+tst(sy)+","+tst(ex)+","+tst(ey)+","+hex$(col)+")"
|
|
|
|
|
state.isdrawing=0
|
2026-05-19 12:23:01 +02:00
|
|
|
else
|
|
|
|
|
_dest layers(2).ihandle
|
|
|
|
|
end if
|
|
|
|
|
filledbox sx,sy,ex,ey,col
|
|
|
|
|
_source osource
|
|
|
|
|
_dest odest
|
|
|
|
|
end if
|
2026-05-18 14:05:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
sub do.polygon(x as long,y as long)
|
2026-05-19 12:23:01 +02:00
|
|
|
' 1. Internalized State Memory
|
|
|
|
|
static polypoints(500) as long
|
2026-05-20 10:24:07 +02:00
|
|
|
static pointcount as integer
|
2026-05-19 10:34:20 +02:00
|
|
|
|
2026-05-19 12:23:01 +02:00
|
|
|
dim osource as long
|
|
|
|
|
dim odest as long
|
|
|
|
|
dim p as integer
|
|
|
|
|
dim i as integer
|
|
|
|
|
dim tmpstr as string
|
2026-05-18 14:05:35 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
if state.isdrawing then
|
|
|
|
|
osource=_source
|
|
|
|
|
odest=_dest
|
2026-05-19 12:23:01 +02:00
|
|
|
|
|
|
|
|
' If left-clicked, add the coordinate to this routine's local array
|
|
|
|
|
if mouseclicked then
|
2026-05-20 10:24:07 +02:00
|
|
|
polypoints(pointcount*2)=x
|
|
|
|
|
polypoints(pointcount*2+1)=y
|
|
|
|
|
pointcount=pointcount+1
|
2026-05-19 10:34:20 +02:00
|
|
|
end if
|
2026-05-19 12:23:01 +02:00
|
|
|
|
|
|
|
|
' Finish shape on Right-Click
|
2026-05-20 10:24:07 +02:00
|
|
|
if rmouseclicked and pointcount>2 then
|
2026-05-19 12:23:01 +02:00
|
|
|
_dest layers(1).ihandle
|
|
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
redim finalp(pointcount*2-1) as long
|
|
|
|
|
for p=0 to (pointcount*2)-1:finalp(p)=polypoints(p):next
|
2026-05-19 12:23:01 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
polygon finalp(),state.fcolor
|
2026-05-19 12:23:01 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
tmpstr="polygon ("
|
|
|
|
|
for i=0 to ubound(finalp)-1
|
|
|
|
|
tmpstr=tmpstr+tst(finalp(i))+","
|
2026-05-19 12:23:01 +02:00
|
|
|
next i
|
2026-05-20 10:24:07 +02:00
|
|
|
tmpstr=tmpstr+tst(finalp(i))+")"
|
2026-05-19 12:23:01 +02:00
|
|
|
addcommand tmpstr
|
|
|
|
|
|
|
|
|
|
' Clean up local tool state
|
2026-05-20 10:24:07 +02:00
|
|
|
state.isdrawing=0
|
|
|
|
|
pointcount=0
|
2026-05-19 12:23:01 +02:00
|
|
|
else
|
|
|
|
|
' Live preview rendering loop
|
|
|
|
|
_dest layers(2).ihandle
|
2026-05-20 10:24:07 +02:00
|
|
|
if pointcount>0 then
|
|
|
|
|
for p=1 to pointcount-1
|
|
|
|
|
thickline polypoints((p-1)*2),polypoints((p-1)*2+1),polypoints(p*2),polypoints(p*2+1),state.fcolor
|
2026-05-19 12:23:01 +02:00
|
|
|
next p
|
2026-05-20 10:24:07 +02:00
|
|
|
thickline polypoints((pointcount-1)*2),polypoints((pointcount-1)*2+1),x,y,state.fcolor
|
2026-05-19 12:23:01 +02:00
|
|
|
end if
|
|
|
|
|
end if
|
|
|
|
|
_source osource
|
|
|
|
|
_dest odest
|
2026-05-19 10:34:20 +02:00
|
|
|
end if
|
2026-05-18 14:05:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
sub do.fpolygon(x as long,y as long)
|
2026-05-19 12:23:01 +02:00
|
|
|
' 1. Internalized State Memory
|
|
|
|
|
static polypoints(500) as long
|
2026-05-20 10:24:07 +02:00
|
|
|
static pointcount as integer
|
2026-05-19 10:34:20 +02:00
|
|
|
|
2026-05-19 12:23:01 +02:00
|
|
|
dim osource as long
|
|
|
|
|
dim odest as long
|
|
|
|
|
dim p as integer
|
|
|
|
|
dim i as integer
|
|
|
|
|
dim tmpstr as string
|
2026-05-18 14:05:35 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
if state.isdrawing then
|
|
|
|
|
osource=_source
|
|
|
|
|
odest=_dest
|
2026-05-19 12:23:01 +02:00
|
|
|
|
|
|
|
|
' If left-clicked, add the coordinate to this routine's local array
|
|
|
|
|
if mouseclicked then
|
2026-05-20 10:24:07 +02:00
|
|
|
polypoints(pointcount*2)=x
|
|
|
|
|
polypoints(pointcount*2+1)=y
|
|
|
|
|
pointcount=pointcount+1
|
2026-05-19 12:23:01 +02:00
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
' Finish shape on Right-Click
|
2026-05-20 10:24:07 +02:00
|
|
|
if rmouseclicked and pointcount>2 then
|
2026-05-19 12:23:01 +02:00
|
|
|
_dest layers(1).ihandle
|
|
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
redim finalp(pointcount*2-1) as long
|
|
|
|
|
for p=0 to (pointcount*2)-1:finalp(p)=polypoints(p):next
|
2026-05-19 12:23:01 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
filledpolygon finalp(),state.fcolor
|
2026-05-19 12:23:01 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
tmpstr="fpolygon ("
|
|
|
|
|
for i=0 to ubound(finalp)-1
|
|
|
|
|
tmpstr=tmpstr+tst(finalp(i))+","
|
2026-05-19 12:23:01 +02:00
|
|
|
next i
|
2026-05-20 10:24:07 +02:00
|
|
|
tmpstr=tmpstr+tst(finalp(i))+")"
|
2026-05-19 12:23:01 +02:00
|
|
|
addcommand tmpstr
|
|
|
|
|
|
|
|
|
|
' Clean up local tool state
|
2026-05-20 10:24:07 +02:00
|
|
|
state.isdrawing=0
|
|
|
|
|
pointcount=0
|
2026-05-19 12:23:01 +02:00
|
|
|
else
|
|
|
|
|
' Live preview rendering loop
|
|
|
|
|
_dest layers(2).ihandle
|
2026-05-20 10:24:07 +02:00
|
|
|
if pointcount>0 then
|
|
|
|
|
for p=1 to pointcount-1
|
|
|
|
|
thickline polypoints((p-1)*2),polypoints((p-1)*2+1),polypoints(p*2),polypoints(p*2+1),state.fcolor
|
2026-05-19 12:23:01 +02:00
|
|
|
next p
|
2026-05-20 10:24:07 +02:00
|
|
|
thickline polypoints((pointcount-1)*2),polypoints((pointcount-1)*2+1),x,y,state.fcolor
|
2026-05-19 12:23:01 +02:00
|
|
|
end if
|
2026-05-19 10:34:20 +02:00
|
|
|
end if
|
2026-05-19 12:23:01 +02:00
|
|
|
|
|
|
|
|
_source osource
|
|
|
|
|
_dest odest
|
2026-05-19 10:34:20 +02:00
|
|
|
end if
|
2026-05-18 14:05:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
sub do.floodfill(x as long,y as long,col as long)
|
2026-05-19 12:23:01 +02:00
|
|
|
dim osource as long
|
|
|
|
|
dim odest as long
|
2026-05-20 10:24:07 +02:00
|
|
|
osource=_source
|
|
|
|
|
odest=_dest
|
2026-05-19 12:23:01 +02:00
|
|
|
if mouseclicked or rmouseclicked then
|
|
|
|
|
_source layers(1).ihandle
|
|
|
|
|
_dest layers(1).ihandle
|
2026-05-22 13:10:54 +02:00
|
|
|
|
2026-05-22 12:58:45 +02:00
|
|
|
' Check if either Left Shift (100303) or Right Shift (100304) is held down
|
|
|
|
|
if _keydown(100303) or _keydown(100304) then
|
|
|
|
|
' Fill until it hits the background color as a border
|
|
|
|
|
boundaryfill x,y,col,state.bcolor
|
|
|
|
|
addcommand"boundaryfill ("+tst(x)+","+tst(y)+","+hex$(col)+","+hex$(state.bcolor)+")"
|
|
|
|
|
else
|
|
|
|
|
' Standard color-replace flood fill
|
|
|
|
|
floodfill x,y,col
|
|
|
|
|
addcommand"floodfill ("+tst(x)+","+tst(y)+","+hex$(col)+")"
|
|
|
|
|
end if
|
2026-05-22 13:10:54 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
state.isdrawing=0
|
2026-05-19 12:23:01 +02:00
|
|
|
_source osource
|
|
|
|
|
_dest odest
|
|
|
|
|
end if
|
2026-05-18 14:05:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
sub do.eyedropper(x as long,y as long)
|
2026-05-19 12:23:01 +02:00
|
|
|
dim osource as long
|
2026-05-20 09:06:25 +02:00
|
|
|
if _mousebutton(1) or _mousebutton(2) then
|
2026-05-20 10:24:07 +02:00
|
|
|
osource=_source
|
2026-05-20 09:06:25 +02:00
|
|
|
_source layers(1).ihandle ' Read from the main drawing layer
|
|
|
|
|
' Ensure the coordinates are within the canvas boundaries
|
2026-05-20 10:24:07 +02:00
|
|
|
if x>=0 and x<_width(layers(1).ihandle) and y>=0 and y<_height(layers(1).ihandle) then
|
2026-05-20 09:06:25 +02:00
|
|
|
' Left click sets foreground color, Right click sets background color
|
|
|
|
|
if _mousebutton(1) then
|
2026-05-20 10:24:07 +02:00
|
|
|
state.fcolor=point(x,y)
|
|
|
|
|
addcommand"fcolor ("+hex$(point(x,y))+")"
|
2026-05-20 09:06:25 +02:00
|
|
|
elseif _mousebutton(2) then
|
2026-05-20 10:24:07 +02:00
|
|
|
state.bcolor=point(x,y)
|
|
|
|
|
addcommand"bcolor ("+hex$(point(x,y))+")"
|
2026-05-20 09:06:25 +02:00
|
|
|
end if
|
|
|
|
|
end if
|
2026-05-20 10:24:07 +02:00
|
|
|
state.isdrawing=0
|
2026-05-20 09:06:25 +02:00
|
|
|
_source osource
|
|
|
|
|
end if
|
2026-05-18 14:05:35 +02:00
|
|
|
end sub
|
|
|
|
|
|
2026-05-21 09:22:52 +02:00
|
|
|
sub do.gradient(sx as long,sy as long,ex as long,ey as long)
|
|
|
|
|
dim osource as long
|
|
|
|
|
dim odest as long
|
|
|
|
|
if state.isdrawing then
|
|
|
|
|
osource=_source
|
|
|
|
|
odest=_dest
|
2026-05-28 14:07:51 +02:00
|
|
|
|
|
|
|
|
if _keydown(100303) or _keydown(100304) then
|
|
|
|
|
dim dx as single:dx=ex-sx
|
|
|
|
|
dim dy as single:dy=ey-sy
|
|
|
|
|
if dx<>0 or dy<>0 then
|
|
|
|
|
dim linelen as single:linelen=sqr(dx*dx+dy*dy)
|
|
|
|
|
dim angle as single:angle=_atan2(dy,dx)
|
|
|
|
|
dim degrees as single:degrees=angle*(180.0/_pi)
|
|
|
|
|
dim snappeddegrees as single:snappeddegrees=int((degrees+22.5)/45.0)*45.0
|
|
|
|
|
dim snappedangle as single:snappedangle=snappeddegrees*(_pi/180.0)
|
|
|
|
|
ex=sx+_round(linelen*cos(snappedangle))
|
|
|
|
|
ey=sy+_round(linelen*sin(snappedangle))
|
|
|
|
|
end if
|
|
|
|
|
end if
|
2026-06-08 12:30:31 +02:00
|
|
|
|
2026-05-21 09:22:52 +02:00
|
|
|
if mouseclicked or rmouseclicked then
|
|
|
|
|
_dest layers(1).ihandle
|
|
|
|
|
addcommand"gradient ("+tst(sx)+","+tst(sy)+","+tst(ex)+","+tst(ey)+")"
|
|
|
|
|
state.isdrawing=0
|
|
|
|
|
ditheredgradient sx,sy,ex,ey,state.fcolor,state.bcolor
|
|
|
|
|
else
|
|
|
|
|
_dest layers(2).ihandle
|
|
|
|
|
thickline sx,sy,ex,ey,state.fcolor
|
|
|
|
|
end if
|
|
|
|
|
_source osource
|
|
|
|
|
_dest odest
|
|
|
|
|
end if
|
|
|
|
|
end sub
|
|
|
|
|
|
2026-06-08 12:30:31 +02:00
|
|
|
sub do.text (x as long,y as long,col as long)
|
2026-05-28 14:07:51 +02:00
|
|
|
dim osource as long
|
|
|
|
|
dim odest as long
|
|
|
|
|
|
|
|
|
|
' 1. Mouse Click on Canvas initiates the Typing Focus Lock
|
2026-06-08 12:30:31 +02:00
|
|
|
if (mouseclicked) and state.isdrawing=0 then
|
|
|
|
|
state.startx=x
|
|
|
|
|
state.starty=y
|
|
|
|
|
state.isdrawing=-1
|
|
|
|
|
texttoolstring="" ' Clear typing input buffer
|
|
|
|
|
_keyclear ' Flush background buffer lines
|
2026-05-28 14:07:51 +02:00
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
if state.isdrawing then
|
2026-06-08 12:30:31 +02:00
|
|
|
osource=_source
|
|
|
|
|
odest=_dest
|
2026-05-28 14:07:51 +02:00
|
|
|
' 2. Intercept keyboard streams directly inside the active lock state
|
|
|
|
|
dim k as long
|
|
|
|
|
do
|
2026-06-08 12:30:31 +02:00
|
|
|
k=_keyhit
|
|
|
|
|
if k=0 then exit do
|
2026-05-28 14:07:51 +02:00
|
|
|
' Character keys range check
|
2026-06-08 12:30:31 +02:00
|
|
|
if k>=32 and k<=126 then
|
|
|
|
|
texttoolstring=texttoolstring+chr$(k)
|
|
|
|
|
elseif k=8 and len(texttoolstring)>0 then ' Backspace behavior
|
|
|
|
|
texttoolstring=left$(texttoolstring,len(texttoolstring)-1)
|
|
|
|
|
elseif k=13 then
|
2026-05-28 14:07:51 +02:00
|
|
|
_dest layers(1).ihandle
|
2026-06-08 12:30:31 +02:00
|
|
|
displaybgitext fonthandles(activefontindex),state.startx,state.starty,texttoolstring,activefontsize,col
|
|
|
|
|
addcommand"text ("+tst(state.startx)+","+tst(state.starty)+","+tst(activefontindex)+","+tst(int(activefontsize))+","+hex$(col)+","+texttoolstring+")"
|
|
|
|
|
state.isdrawing=0
|
2026-05-28 14:07:51 +02:00
|
|
|
_dest odest
|
|
|
|
|
_source osource
|
|
|
|
|
while inkey$<>"":wend
|
|
|
|
|
exit sub
|
2026-06-08 12:30:31 +02:00
|
|
|
elseif k=27 then
|
|
|
|
|
state.isdrawing=0
|
2026-05-28 14:07:51 +02:00
|
|
|
exit sub
|
|
|
|
|
end if
|
|
|
|
|
loop
|
|
|
|
|
' 3. Render dynamic typing string overlay to active live preview layer (layer 2)
|
|
|
|
|
_dest layers(2).ihandle
|
2026-06-08 12:30:31 +02:00
|
|
|
displaybgitext fonthandles(activefontindex),state.startx,state.starty,texttoolstring+"_",activefontsize,col
|
2026-05-28 14:07:51 +02:00
|
|
|
_source osource
|
|
|
|
|
_dest odest
|
|
|
|
|
end if
|
|
|
|
|
end sub
|
|
|
|
|
|
2026-04-30 10:09:05 +02:00
|
|
|
function icon (index as long)
|
2026-04-29 09:28:35 +02:00
|
|
|
static init as integer
|
|
|
|
|
static icons() as long
|
|
|
|
|
if not init then
|
2026-04-30 10:09:05 +02:00
|
|
|
redim icons(19) as long ' Room for 20 icons
|
2026-05-20 22:38:36 +02:00
|
|
|
dim c as _unsigned long:c=highlightcolor ' Main icon color
|
2026-05-20 09:27:54 +02:00
|
|
|
|
|
|
|
|
' --- 1. Pencil Tool ---
|
2026-05-20 10:24:07 +02:00
|
|
|
icons(0)=_newimage(32,32,32):_dest icons(0)
|
|
|
|
|
line (6,26)-(22,10),c
|
|
|
|
|
line (22,10)-(26,6),c
|
|
|
|
|
line (26,6)-(26,10),c
|
|
|
|
|
line (26,10)-(10,26),c
|
|
|
|
|
line (10,26)-(6,26),c
|
|
|
|
|
pset (7,25),c ' Tip point
|
2026-05-20 09:27:54 +02:00
|
|
|
_dest 0
|
|
|
|
|
|
|
|
|
|
' --- 2. Line Tool ---
|
2026-05-20 10:24:07 +02:00
|
|
|
icons(1)=_newimage(32,32,32):_dest icons(1)
|
|
|
|
|
line (5,27)-(27,5),c
|
2026-05-20 09:27:54 +02:00
|
|
|
_dest 0
|
|
|
|
|
|
|
|
|
|
' --- 3. Hollow Circle ---
|
2026-05-20 10:24:07 +02:00
|
|
|
icons(2)=_newimage(32,32,32):_dest icons(2)
|
|
|
|
|
circle (16,16),11,c
|
2026-05-20 09:27:54 +02:00
|
|
|
_dest 0
|
|
|
|
|
|
|
|
|
|
' --- 4. Filled Circle ---
|
2026-05-20 10:24:07 +02:00
|
|
|
icons(3)=_newimage(32,32,32):_dest icons(3)
|
2026-05-20 22:38:36 +02:00
|
|
|
filledcircle 16,16,11,c
|
2026-05-20 09:27:54 +02:00
|
|
|
_dest 0
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-05-20 09:27:54 +02:00
|
|
|
' --- 5. Hollow Box ---
|
2026-05-20 10:24:07 +02:00
|
|
|
icons(4)=_newimage(32,32,32):_dest icons(4)
|
|
|
|
|
line (6,6)-(26,26),c,b
|
2026-05-01 00:30:34 +02:00
|
|
|
_dest 0
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-05-20 09:27:54 +02:00
|
|
|
' --- 6. Filled Box ---
|
2026-05-20 10:24:07 +02:00
|
|
|
icons(5)=_newimage(32,32,32):_dest icons(5)
|
|
|
|
|
line (6,6)-(26,26),c,bf
|
2026-05-20 09:27:54 +02:00
|
|
|
_dest 0
|
|
|
|
|
|
|
|
|
|
' --- 7. Hollow Polygon (Triangle Blueprint) ---
|
2026-05-20 10:24:07 +02:00
|
|
|
icons(6)=_newimage(32,32,32):_dest icons(6)
|
|
|
|
|
line (16,5)-(6,25),c
|
|
|
|
|
line (6,25)-(26,25),c
|
|
|
|
|
line (26,25)-(16,5),c
|
2026-05-20 09:27:54 +02:00
|
|
|
_dest 0
|
|
|
|
|
|
|
|
|
|
' --- 8. Filled Polygon ---
|
2026-05-20 10:24:07 +02:00
|
|
|
icons(7)=_newimage(32,32,32):_dest icons(7)
|
2026-05-20 09:27:54 +02:00
|
|
|
dim py as integer
|
2026-05-20 10:24:07 +02:00
|
|
|
for py=5 to 25
|
|
|
|
|
dim hw as integer:hw=(py-5)*10/20
|
|
|
|
|
line (16-hw,py)-(16+hw,py),c
|
2026-05-20 09:27:54 +02:00
|
|
|
next py
|
2026-05-01 00:30:34 +02:00
|
|
|
_dest 0
|
2026-05-20 09:27:54 +02:00
|
|
|
|
|
|
|
|
' --- 9. Floodfill (Paint Bucket) ---
|
2026-05-20 10:24:07 +02:00
|
|
|
icons(8)=_newimage(32,32,32):_dest icons(8)
|
|
|
|
|
line (8,14)-(20,26),c ' Main body tilt left
|
|
|
|
|
line (20,26)-(26,20),c
|
|
|
|
|
line (26,20)-(14,8),c
|
|
|
|
|
line (14,8)-(8,14),c
|
2026-05-20 22:38:36 +02:00
|
|
|
circle (14,11),6,c,_pi(1.5),_pi(1)
|
2026-05-20 10:24:07 +02:00
|
|
|
pset (6,28),c ' Spilling drip point
|
2026-05-01 13:58:36 +02:00
|
|
|
_dest 0
|
2026-05-20 09:27:54 +02:00
|
|
|
|
|
|
|
|
' --- 10. Eyedropper ---
|
2026-05-20 10:24:07 +02:00
|
|
|
icons(9)=_newimage(32,32,32):_dest icons(9)
|
|
|
|
|
line (6,26)-(10,22),c ' Pipette tip
|
|
|
|
|
line (10,22)-(22,10),c ' Shaft side A
|
|
|
|
|
line (6,26)-(18,14),c ' Bottom point accent
|
|
|
|
|
line (14,18)-(26,6),c ' Shaft side B
|
|
|
|
|
line (22,10)-(26,6),c ' Squeeze bulb cap
|
2026-05-20 09:27:54 +02:00
|
|
|
_dest 0
|
|
|
|
|
|
2026-05-28 14:07:51 +02:00
|
|
|
icons(10)=_newimage(32,32,32):_dest icons(10)
|
2026-06-08 12:30:31 +02:00
|
|
|
ditheredgradient 6,6,26,26,highlightcolor,backgroundcolor1
|
|
|
|
|
|
|
|
|
|
icons(11)=_newimage(32,32,32):_dest icons(11)
|
|
|
|
|
line (8,8)-(24,8),c
|
|
|
|
|
line (16,8)-(16,24),c
|
|
|
|
|
line (12,24)-(20,24),c
|
|
|
|
|
_dest 0
|
2026-05-28 14:07:51 +02:00
|
|
|
|
2026-05-20 09:27:54 +02:00
|
|
|
' Fill remaining fallback slots (10-19) with clean blank images
|
2026-04-30 10:09:05 +02:00
|
|
|
dim j as integer
|
2026-05-28 14:07:51 +02:00
|
|
|
for j=11 to 19
|
2026-05-20 10:24:07 +02:00
|
|
|
if icons(j)=0 then icons(j)=_newimage(32,32,32)
|
2026-04-30 10:09:05 +02:00
|
|
|
next
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
init=-1
|
2026-04-29 09:28:35 +02:00
|
|
|
end if
|
2026-04-30 10:09:05 +02:00
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
if index>=0 and index<=19 then
|
|
|
|
|
icon=icons(index)
|
2026-04-30 10:09:05 +02:00
|
|
|
else
|
2026-05-20 10:24:07 +02:00
|
|
|
icon=icons(9)
|
2026-04-29 09:28:35 +02:00
|
|
|
end if
|
|
|
|
|
end function
|
|
|
|
|
|
|
|
|
|
'$include: 'include/ui.bm'
|
|
|
|
|
'$include: 'include/imgout.bm'
|
|
|
|
|
'$include: 'include/palette.bm'
|
2026-04-30 13:16:00 +02:00
|
|
|
'$include: 'include/tools.bm'
|
2026-05-28 14:07:51 +02:00
|
|
|
'$include: 'include/bgifnt.bm'
|
2026-05-04 11:24:14 +02:00
|
|
|
''$include: 'include/effects.bm'
|
2026-04-29 09:28:35 +02:00
|
|
|
|
|
|
|
|
function adduiicon(imagehandle as long)
|
|
|
|
|
dim unknown as long
|
|
|
|
|
adduiicon=__internaluiicon(unknown,imagehandle,1)
|
|
|
|
|
end function
|
|
|
|
|
|
|
|
|
|
function adduiiconfromfile(filename as string)
|
|
|
|
|
dim unknown as long
|
|
|
|
|
adduiiconfromfile=__internaluiicon(unknown,_loadimage(filename),1)
|
|
|
|
|
end function
|
|
|
|
|
|
|
|
|
|
function uiicon(index)
|
|
|
|
|
dim unknown as long
|
|
|
|
|
uiicon=internaluiicon(index,unknown,2)
|
|
|
|
|
end function
|
|
|
|
|
|
|
|
|
|
function __internaluiicon&(index as long,imagehandle as long,mode as integer)
|
|
|
|
|
static init as integer
|
|
|
|
|
static icons() as long
|
|
|
|
|
if not init or mode=3 then
|
2026-05-04 13:49:56 +02:00
|
|
|
if mode<3 then
|
2026-04-29 09:28:35 +02:00
|
|
|
redim icons(3) as long
|
|
|
|
|
else
|
|
|
|
|
_freeimage icons(0)
|
|
|
|
|
_freeimage icons(1)
|
|
|
|
|
_freeimage icons(2)
|
|
|
|
|
_freeimage icons(3)
|
|
|
|
|
end if
|
|
|
|
|
icons(0)=_newimage(23,23,32) 'Up arrow'
|
|
|
|
|
_dest icons(0)
|
|
|
|
|
color textcolor
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-04-29 09:28:35 +02:00
|
|
|
icons(1)=_newimage(23,23,32) 'Down arrow'
|
|
|
|
|
_dest icons(1)
|
|
|
|
|
color textcolor
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-04-29 09:28:35 +02:00
|
|
|
icons(2)=_newimage(23,23,32) 'Left arrow'
|
|
|
|
|
_dest icons(2)
|
|
|
|
|
color textcolor
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-04-29 09:28:35 +02:00
|
|
|
icons(3)=_newimage(23,23,32) 'Right arrow'
|
2026-05-04 13:49:56 +02:00
|
|
|
_dest icons(3)
|
2026-04-29 09:28:35 +02:00
|
|
|
color textcolor
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-04-29 09:28:35 +02:00
|
|
|
_dest 0
|
|
|
|
|
init=-1
|
|
|
|
|
end if
|
2026-05-04 13:49:56 +02:00
|
|
|
|
2026-04-29 09:28:35 +02:00
|
|
|
select case mode
|
|
|
|
|
case 1
|
|
|
|
|
redim _preserve icons(ubound(icons)+1)
|
|
|
|
|
icons(ubound(icons))=imagehandle
|
|
|
|
|
__internaluiicon=ubound(icons)
|
|
|
|
|
case 2
|
|
|
|
|
__internaluiicon=icons(index)
|
|
|
|
|
end select
|
|
|
|
|
end function
|
2026-04-29 12:36:31 +02:00
|
|
|
|
|
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
function checkresize (currentscreen as _unsigned long) 'pulled straight out of the wiki'
|
|
|
|
|
dim tempscreen as _unsigned long
|
|
|
|
|
checkresize=0
|
2026-05-19 12:23:01 +02:00
|
|
|
if _resize then
|
2026-05-20 10:24:07 +02:00
|
|
|
tempscreen=_copyimage(currentscreen,32)
|
|
|
|
|
screen tempscreen
|
|
|
|
|
_freeimage currentscreen
|
|
|
|
|
currentscreen=_newimage(_resizewidth,_resizeheight,32)
|
|
|
|
|
screen currentscreen
|
|
|
|
|
_putimage (0,0),tempscreen,currentscreen
|
2026-05-19 12:23:01 +02:00
|
|
|
_display
|
2026-05-20 10:24:07 +02:00
|
|
|
_freeimage tempscreen
|
|
|
|
|
checkresize=-1
|
2026-05-19 12:23:01 +02:00
|
|
|
end if
|
|
|
|
|
end function
|
2026-05-04 13:49:56 +02:00
|
|
|
|
|
|
|
|
sub menu()
|
2026-05-19 12:23:01 +02:00
|
|
|
dim logo as long
|
|
|
|
|
dim filename as string
|
|
|
|
|
' A logo is needed'
|
|
|
|
|
'logo=_loadimage("logo.png")
|
|
|
|
|
line (0,0)-(_width-1,_height-1),_rgb32(0,192),bf
|
|
|
|
|
'_putimage ((_width(0)-_width(logo))/2,10),logo
|
|
|
|
|
dim i as integer
|
|
|
|
|
dim fh as integer
|
|
|
|
|
do until done
|
|
|
|
|
k$=inkey$
|
|
|
|
|
while _mouseinput:wend
|
|
|
|
|
mouseclicked=mbd and not _mousebutton(1)
|
|
|
|
|
mbd=_mousebutton(1)
|
|
|
|
|
|
|
|
|
|
if link(10,10,"open") then
|
|
|
|
|
filename=textinput(10,10,100,23,"")
|
2026-05-20 10:24:07 +02:00
|
|
|
if filename=""then exit sub
|
|
|
|
|
fh=freefile
|
2026-05-19 12:23:01 +02:00
|
|
|
redim commands(2000) as string
|
|
|
|
|
open filename for input as fh
|
|
|
|
|
do until eof(fh)
|
2026-05-20 10:24:07 +02:00
|
|
|
line input #fh,commands(i)
|
2026-05-19 12:23:01 +02:00
|
|
|
i=i+1
|
|
|
|
|
if i>ubound(commands) then redim _preserve commands(ubound(commands)*2) as string
|
|
|
|
|
loop
|
|
|
|
|
close fh
|
|
|
|
|
redim _preserve commands(i-1) as string
|
|
|
|
|
redraw
|
|
|
|
|
done=-1
|
|
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
if link(10,34,"save") then
|
|
|
|
|
filename=textinput(1,34,100,23,"")
|
2026-05-20 10:24:07 +02:00
|
|
|
if filename=""then exit sub
|
|
|
|
|
fh=freefile
|
2026-05-19 12:23:01 +02:00
|
|
|
open filename for output as fh
|
|
|
|
|
for i=0 to ubound(commands)
|
2026-05-20 10:24:07 +02:00
|
|
|
print #fh,commands(i)
|
2026-05-19 12:23:01 +02:00
|
|
|
next i
|
|
|
|
|
close fh
|
|
|
|
|
done=-1
|
|
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
if link(10,56,"export") then
|
|
|
|
|
filename=textinput(10,56,100,23,"")
|
2026-05-20 10:24:07 +02:00
|
|
|
if filename=""then exit sub
|
2026-05-19 12:23:01 +02:00
|
|
|
select case lcase$(right$(filename,4))
|
|
|
|
|
case ".png"
|
2026-05-20 10:24:07 +02:00
|
|
|
save32bitpng layers(1).ihandle,filename
|
2026-05-19 12:23:01 +02:00
|
|
|
case ".bmp"
|
2026-05-20 10:24:07 +02:00
|
|
|
save24bitbmp layers(1).ihandle,filename
|
2026-05-19 12:23:01 +02:00
|
|
|
case ".ppm"
|
2026-05-20 10:24:07 +02:00
|
|
|
savebinaryppm layers(1).ihandle,filename
|
2026-05-19 12:23:01 +02:00
|
|
|
case else
|
2026-05-20 10:24:07 +02:00
|
|
|
save32bitpng layers(1).ihandle,filename
|
2026-05-19 12:23:01 +02:00
|
|
|
end select
|
|
|
|
|
done=-1
|
|
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
if link(10,78,"refenece img") then
|
|
|
|
|
filename=textinput(10,78,100,23,"")
|
2026-05-20 10:24:07 +02:00
|
|
|
if filename=""then exit sub
|
2026-05-19 12:23:01 +02:00
|
|
|
if not _fileexists(filename) then exit sub
|
2026-05-20 10:24:07 +02:00
|
|
|
if layers(3).ihandle<>0 then _freeimage layers(3).ihandle
|
2026-05-19 12:23:01 +02:00
|
|
|
layers(3).ihandle=_loadimage(filename)
|
2026-05-20 10:24:07 +02:00
|
|
|
_setalpha 20,layers(3).ihandle
|
2026-05-19 12:23:01 +02:00
|
|
|
done=-1
|
|
|
|
|
end if
|
|
|
|
|
|
|
|
|
|
if link(10,100,"exit") then system
|
|
|
|
|
|
|
|
|
|
if k$=chr$(27) then done=-1
|
|
|
|
|
_limit 30
|
|
|
|
|
_display
|
|
|
|
|
loop
|
2026-05-04 13:49:56 +02:00
|
|
|
end sub
|
2026-05-11 10:03:44 +02:00
|
|
|
|
2026-05-12 09:29:36 +02:00
|
|
|
sub palettemanager(col as _unsigned long)
|
|
|
|
|
line (0,0)-(_width-1,_height-1),col,bf
|
|
|
|
|
'TODO: build palette mamager ui
|
|
|
|
|
end sub
|
|
|
|
|
|
2026-05-20 10:24:07 +02:00
|
|
|
function closestcolor~& (colour as _unsigned long,carr() as _unsigned long)
|
|
|
|
|
dim r as integer
|
|
|
|
|
dim g as integer
|
|
|
|
|
dim b as integer
|
2026-05-19 12:23:01 +02:00
|
|
|
dim ar as integer
|
|
|
|
|
dim ag as integer
|
|
|
|
|
dim ab as integer
|
2026-05-20 10:24:07 +02:00
|
|
|
dim i as integer
|
2026-05-19 12:23:01 +02:00
|
|
|
dim nearest as integer
|
|
|
|
|
dim shortestdistance as integer
|
|
|
|
|
dim distance as integer
|
2026-05-20 10:24:07 +02:00
|
|
|
r=_red (colour)
|
|
|
|
|
g=_green(colour)
|
|
|
|
|
b=_blue (colour)
|
|
|
|
|
shortestdistance=443
|
|
|
|
|
for i=0 to ubound(carr)
|
|
|
|
|
ar=_red (carr(i))
|
|
|
|
|
ag=_green(carr(i))
|
|
|
|
|
ab=_blue (carr(i))
|
|
|
|
|
distance=sqr((r-ar) ^ 2+(g-ag) ^ 2+(b-ab) ^ 2)
|
|
|
|
|
if distance<=shortestdistance then shortestdistance=distance:nearest=i
|
2026-05-19 12:23:01 +02:00
|
|
|
next i
|
2026-05-20 10:24:07 +02:00
|
|
|
closestcolor=carr(nearest)
|
2026-05-19 12:23:01 +02:00
|
|
|
end function
|
2026-05-12 09:29:36 +02:00
|
|
|
|
|
|
|
|
' trimmed str$
|
|
|
|
|
function tst$(numb)
|
|
|
|
|
tst=_trim$(str$(numb))
|
|
|
|
|
end function
|