Would think about two changes for fine tuning...
Allowing to edit commited curves - at least the two control points for tuning the curves:
- it would be simple to reimport edited values from the code view to the structure
- adding a label to each curve could allow to select a certain curve by the mouse for editing it (just a quick starter is done below, don't zoom
Try to continue a curves direction for smoother shapes...
- I've added a simple posibility but it's just a quick hack, so recognizing the shift key works only for windows...
Code: Select all
;///////////////////////////////////////////////////
; Project: Curve Designer
; Author: Lloyd Gallant (netmaestro)
; Contributors: Idle (Linux cursor creation)
; wombats (MacOS cursor creation)
; Date: May 14,2020
; Target OS: Windows
; Compiler: PureBasic 5.72 x86
; License: Unrestricted, do as you like
; What it is: WSIWYG Vector curve designer
; (RAD tool for quick drawing)
; Version: It's a very early alpha
; All suggestions (and especially code)
; welcomed.
;////////////////////////////////////////////////////
#BoxSize=20
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
CompilerIf Defined(ICONINFO, #PB_Structure)=0
Structure ICONINFO
fIcon.l
xHotspot.l
yHotspot.l
hbmMask.i
hbmColor.i
EndStructure
CompilerEndIf
Import "user32.lib"
CreateIconIndirect(*lptICONINFO)
EndImport
CompilerEndIf
Declare NewImageButtonHandler()
Declare CanvasHandler()
Declare CreateCursor()
Declare UpdateCanvas()
Declare RedrawCurves()
Declare OptionHandler()
Declare StringHandler()
Declare New()
Declare CommitHandler()
Declare CopyHandler()
Declare LogCurves()
Declare ResizeHandler()
Declare ConvertCurvesToOutput()
Declare InitializeCanvas()
Declare UndoHandler()
Declare RedoHandler()
Declare ZoomIn()
Declare ZoomOut()
Structure pointd
x.d
y.d
EndStructure
Structure curve
moverequired.i
startpoint.pointd
firstpoint.pointd
secondpoint.pointd
endpoint.pointd
label.point
id.i
EndStructure
; Control points
Global.pointd startpoint,firstpoint,secondpoint,endpoint,oldstartpoint,oldfirstpoint,oldsecondpoint,oldendpoint
Global.pointd vector
; Dimensions
Global.d nw,nh,oldnw,oldnh,cx,cy,oldcx,oldcy,outputcx,outputcy,cxborder,cyborder
; Images
Global.i imgCursor=CreateCursor(),imgLayer,imgBackground,imgOriginalBackground,imgOutput
; Gadgets
Global.i output,option1,option2,option3,option4,option5,option6,option7,gadget_cx, gadget_cy,label_cx,label_cy
Global.i canvas,testcanvas,ccontainer,commit,newimage,copy,frame,gadget_undo,gadget_redo
; Logic Flow variables
Global.i moveinprogress,curveactive,newcurve,on1,on2,on3,on4
Global NewList codelines.s()
Global NewList curves.curve()
Global NewList displaycurves.curve()
Global NewList trashcurves.curve()
Global output_font
Global editcurve,hovercurve
flags.i=#PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget
OpenWindow(0,0,0,1024,710,"Curve Designer",flags)
nw=WindowHeight(0)-10
nh=nw
BindEvent(#PB_Event_SizeWindow, @ResizeHandler())
newimage=ButtonGadget(#PB_Any, 10,50,270,20,"Load Image")
BindGadgetEvent(newimage, @NewImageButtonHandler())
FrameGadget(#PB_Any, 10,85,270,80,"Output Type")
option1=OptionGadget(#PB_Any,40,110,90,20,"Fixed size")
option2=OptionGadget(#PB_Any,40,130,90,20,"proportional")
SetGadgetState(option1,1)
BindGadgetEvent(option1,@OptionHandler())
BindGadgetEvent(option2,@OptionHandler())
label_cx=TextGadget(#PB_Any, 140,112,15,20,"W:")
gadget_cx=StringGadget(#PB_Any,158,110,35,20,"")
label_cy=TextGadget(#PB_Any, 204,112,15,20,"H:")
gadget_cy=StringGadget(#PB_Any,220,110,35,20,"")
DisableGadget(gadget_cx, 0)
DisableGadget(gadget_cy, 0)
DisableGadget(label_cx, 0)
DisableGadget(label_cy, 0)
BindGadgetEvent(gadget_cx, @StringHandler())
BindGadgetEvent(gadget_cy, @StringHandler())
FrameGadget(#PB_Any, 10,180,270,90,"View")
option3=OptionGadget(#PB_Any,40,200,90,20,"Design View")
option4=OptionGadget(#PB_Any,40,220,90,20,"Code View")
option5=OptionGadget(#PB_Any,40,240,90,20,"Test View")
BindGadgetEvent(option3, @OptionHandler())
BindGadgetEvent(option4, @OptionHandler())
BindGadgetEvent(option5, @OptionHandler())
SetGadgetState(option3, 1)
FrameGadget(#PB_Any, 10,290,270,80,"Curve Type")
option6=OptionGadget(#PB_Any,40,310,190,20,"Independent curve")
option7=OptionGadget(#PB_Any,40,330,190,20,"Continuation of last curve")
BindGadgetEvent(option6, @OptionHandler())
BindGadgetEvent(option7, @OptionHandler())
SetGadgetState(option6,1)
commit=ButtonGadget(#PB_Any, 10,380,270,20,"Commit This Curve")
DisableGadget(commit, 1)
BindGadgetEvent(commit, @CommitHandler())
copy=ButtonGadget(#PB_Any, 10,410,270,20,"Copy Code To Clipboard")
BindGadgetEvent(copy, @CopyHandler())
frame=FrameGadget(#PB_Any,315,0,702,702,"",#PB_Frame_Flat)
ccontainer=ContainerGadget(#PB_Any, 316,1,700,700)
canvas=CanvasGadget(#PB_Any,0,0,700,700,#PB_Canvas_Keyboard|#PB_Canvas_ClipMouse)
CloseGadgetList()
BindGadgetEvent(canvas, @CanvasHandler())
testcanvas=CanvasGadget(#PB_Any,321,1,WindowHeight(0)-2,WindowHeight(0)-2)
output_font=LoadFont(#PB_Any, "consolas", 11)
output = EditorGadget(#PB_Any, 316,1,700,700)
SetGadgetFont(output, FontID(output_font))
HideGadget(output,1)
HideGadget(testcanvas,1)
imgOriginalBackground=CreateImage(#PB_Any, WindowHeight(0)-2,WindowHeight(0)-2,24)
InitializeCanvas()
sz.d=24
undo=CreateImage(#PB_Any,sz,sz,32,#PB_Image_Transparent)
redo=CreateImage(#PB_Any, sz,sz,32,#PB_Image_Transparent)
StartVectorDrawing(ImageVectorOutput(undo))
VectorSourceColor(RGBA(255,255,255,255))
FillVectorOutput()
VectorSourceColor(RGBA(0,0,0,255))
AddPathCircle(0.5000*sz,0.6000*sz,0.2100*sz,40,240,#PB_Path_CounterClockwise)
angle.d = PathPointAngle(PathLength())
SaveVectorState()
RotateCoordinates(0.5000*sz,0.5000*sz, angle)
AddPathLine(0.0000*sz,-0.1000*sz, #PB_Path_Relative)
AddPathLine(0.1333*sz,0.0667*sz, #PB_Path_Relative)
AddPathLine(-0.1333*sz,0.1000*sz, #PB_Path_Relative)
AddPathLine(0.0000*sz,-0.1000*sz,#PB_Path_Relative)
RestoreVectorState()
StrokePath(0.0933*sz)
StopVectorDrawing()
StartVectorDrawing(ImageVectorOutput(redo))
FlipCoordinatesX(0.5000*sz)
MovePathCursor(0,0)
DrawVectorImage(ImageID(undo))
StopVectorDrawing()
FrameGadget(#PB_Any,10,10,270,28,"",#PB_Frame_Flat)
gadget_undo=ButtonImageGadget(#PB_Any, 12,12,24,24,ImageID(undo))
gadget_redo=ButtonImageGadget(#PB_Any, 38,12,24,24,ImageID(redo))
BindGadgetEvent(gadget_undo, @UndoHandler())
BindGadgetEvent(gadget_redo, @RedoHandler())
SetActiveGadget(canvas)
Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
;===============================================
; PROCEDURE SECTION
;===============================================
Procedure UpdateTestCanvas()
StartVectorDrawing(CanvasVectorOutput(testcanvas))
VectorSourceColor(RGBA(255,255,255,255))
FillVectorOutput()
ForEach displaycurves()
With displaycurves()
If \moverequired
MovePathCursor(\startpoint\x, \startpoint\y)
EndIf
AddPathCurve(\firstpoint\x,\firstpoint\y,\secondpoint\x,\secondpoint\y,\endpoint\x,\endpoint\y)
EndWith
Next
VectorSourceColor(RGBA(0,0,0,255))
StrokePath(3,#PB_Path_RoundCorner|#PB_Path_RoundEnd)
StopVectorDrawing()
EndProcedure
Procedure UndoHandler()
If curveactive Or (startpoint\x<>0 And startpoint\y<>0 And endpoint\x=0 And endpoint\y=0)
ClearStructure(startpoint, pointd)
ClearStructure(firstpoint, pointd)
ClearStructure(secondpoint, pointd)
ClearStructure(endpoint, pointd)
curveactive=0
RedrawCurves()
Else
If ListSize(curves())
LastElement(curves())
If curves()\moverequired
New()
Else
moveinprogress=0
newcurve=0
SetGadgetState(option7,1)
EndIf
AddElement(trashcurves())
trashcurves()=curves()
DeleteElement(curves())
RedrawCurves()
EndIf
EndIf
curveactive=0
DisableGadget(commit, 1)
ConvertCurvesToOutput()
LogCurves()
UpdateTestCanvas()
SetActiveGadget(canvas)
If ListSize(curves())=0
New()
EndIf
EndProcedure
Procedure RedoHandler()
Static lastredo
If ListSize(trashcurves())
LastElement(trashcurves())
If PreviousElement(trashcurves())
If trashcurves()\moverequired
lastredo=1
Else
lastredo=0
EndIf
EndIf
LastElement(trashcurves())
LastElement(curves())
AddElement(curves())
curves()=trashcurves()
DeleteElement(trashcurves())
RedrawCurves()
curveactive=0
DisableGadget(commit, 1)
EndIf
ConvertCurvesToOutput()
LogCurves()
UpdateTestCanvas()
SetActiveGadget(canvas)
If ListSize(curves())=0
New()
Else
If lastredo
newcurve=1
SetGadgetState(option6,1)
Else
newcurve=0
SetGadgetState(option7,1)
EndIf
EndIf
curveactive=0
DisableGadget(commit,1)
EndProcedure
Procedure InitializeCanvas()
ClearList(curves())
ClearList(displaycurves())
ClearList(trashcurves())
ClearList(codelines())
ClearGadgetItems(output)
StartVectorDrawing(CanvasVectorOutput(testcanvas))
VectorSourceColor(RGBA(255,255,255,255))
StopVectorDrawing()
New()
SetGadgetState(option1,1)
HideGadget(output,1)
HideGadget(testcanvas,1)
HideGadget(ccontainer,0)
SetGadgetState(option3,1)
SetGadgetState(option6,1)
w.d = ImageWidth(imgOriginalBackground)
h.d = ImageHeight(imgOriginalBackground)
outputcx=w
outputcy=h
ResizeGadget(testcanvas,316,1,outputcx,outputcy)
SetGadgetText(gadget_cx, Str(outputcx))
SetGadgetText(gadget_cy, Str(outputcy))
; Resize working image to all available screen area
; Image will be drawn at 2/3 this size to allow room
; for pulling control points around
max=WindowHeight(0)-10
If h>w
nh.d=max
nw.d=w/h*max
Else
nw.d=max
nh.d=h/w*max
EndIf
oldnw=nw
oldnh=nh
cxborder=nw*0.2
cyborder=nh*0.2
cx=0.6*nw
cy=0.6*nh
oldcx=cx
oldcy=cy
If IsImage(imgBackground) : FreeImage(imgBackground) : EndIf
imgBackground = CreateImage(#PB_Any,nw,nh,24,#White)
StartVectorDrawing(ImageVectorOutput(imgBackground))
VectorSourceColor(RGBA(255,255,255,255))
FillVectorOutput()
MovePathCursor(cxborder,cyborder)
DrawVectorImage(ImageID(imgOriginalBackground),80,cx,cy)
AddPathBox(cxborder,cyborder,cx,cy)
VectorSourceColor(RGBA(100,100,255,255))
DashPath(1,4)
StopVectorDrawing()
If IsImage(imgLayer) : FreeImage(imgLayer) : EndIf
imgLayer = CreateImage(#PB_Any, nw,nh,32,#PB_Image_Transparent)
ResizeGadget(canvas, #PB_Ignore,#PB_Ignore,nw,nh)
SetGadgetAttribute(canvas, #PB_Canvas_Image, ImageID(imgBackground))
SetGadgetAttribute(canvas, #PB_Canvas_CustomCursor, imgCursor)
EndProcedure
Procedure ConvertCurvesToOutput()
ClearList(displaycurves())
ForEach curves()
AddElement(displaycurves())
With displaycurves()
\moverequired = curves()\moverequired
\startpoint\x = (curves()\startpoint\x-cxborder)/cx*outputcx
\startpoint\y = (curves()\startpoint\y-cyborder)/cy*outputcy
\firstpoint\x = (curves()\firstpoint\x-cxborder)/cx*outputcx
\firstpoint\y = (curves()\firstpoint\y-cyborder)/cy*outputcy
\secondpoint\x = (curves()\secondpoint\x-cxborder)/cx*outputcx
\secondpoint\y = (curves()\secondpoint\y-cyborder)/cy*outputcy
\endpoint\x = (curves()\endpoint\x-cxborder)/cx*outputcx
\endpoint\y = (curves()\endpoint\y-cyborder)/cy*outputcy
EndWith
Next
EndProcedure
Procedure ConvertCurvesFromOutput()
ClearList(curves())
ForEach displaycurves()
AddElement(curves())
With curves()
\moverequired = displaycurves()\moverequired
\startpoint\x = displaycurves()\startpoint\x*cx/outputcx+cxborder
\startpoint\y = displaycurves()\startpoint\y*cx/outputcx+cxborder
\firstpoint\x = displaycurves()\firstpoint\x*cx/outputcx+cxborder
\firstpoint\y = displaycurves()\firstpoint\y*cx/outputcx+cxborder
\secondpoint\x = displaycurves()\secondpoint\x*cx/outputcx+cxborder
\secondpoint\y = displaycurves()\secondpoint\y*cx/outputcx+cxborder
\endpoint\x = displaycurves()\endpoint\x*cx/outputcx+cxborder
\endpoint\y = displaycurves()\endpoint\y*cx/outputcx+cxborder
EndWith
Next
EndProcedure
Procedure ResizeHandler()
w=ImageWidth(imgOriginalBackground)
h=ImageHeight(imgOriginalBackground)
max=WindowHeight(0)-10
If h>w
nh.d=max
nw.d=w/h*max
Else
nw.d=max
nh.d=h/w*max
EndIf
cxborder=nw*0.2
cyborder=nh*0.2
cx=0.6*nw
cy=0.6*nh
If curveactive
startpoint\x=(oldstartpoint\x/oldnw)*nw
startpoint\y=(oldstartpoint\y/oldnh)*nh
endpoint\x=(oldendpoint\x/oldnw)*nw
endpoint\y=(oldendpoint\y/oldnh)*nh
firstpoint\x = (oldfirstpoint\x/oldnw)*nw
firstpoint\y = (oldfirstpoint\y/oldnh)*nh
secondpoint\x = (oldsecondpoint\x/oldnw)*nw
secondpoint\y = (oldsecondpoint\y/oldnh)*nh
EndIf
ResizeGadget(frame,315,0,nw+2,nh+2)
ResizeGadget(ccontainer, 316,1,nw,nh)
ResizeGadget(canvas, 0,0,GadgetWidth(ccontainer),GadgetHeight(ccontainer))
If IsImage(imgBackground) : FreeImage(imgBackground) : EndIf
imgBackground = CreateImage(#PB_Any,nw,nh,24,#White)
StartVectorDrawing(ImageVectorOutput(imgBackground))
VectorSourceColor(RGBA(255,255,255,255))
FillVectorOutput()
MovePathCursor(cxborder,cyborder)
DrawVectorImage(ImageID(imgOriginalBackground),80,cx,cy)
AddPathBox(cxborder,cyborder,cx,cy)
VectorSourceColor(RGBA(100,100,255,255))
DashPath(1,4)
StopVectorDrawing()
If IsImage(imgLayer) : FreeImage(imgLayer) : EndIf
imgLayer = CreateImage(#PB_Any, nw,nh,32,#PB_Image_Transparent)
ConvertCurvesFromOutput()
UpdateCanvas()
RedrawCurves()
If curveactive
oldstartpoint\x=startpoint\x
oldstartpoint\y=startpoint\y
oldendpoint\x=endpoint\x
oldendpoint\y=endpoint\y
oldfirstpoint=firstpoint
oldsecondpoint=secondpoint
EndIf
oldnw=nw
oldnh=nh
oldcx=cx
oldcy=cy
SetActiveGadget(canvas)
EndProcedure
Procedure CopyHandler()
code$ = GetGadgetText(output)
If code$<>""
SetClipboardText(code$+#CRLF$)
MessageRequester("Notice:", "Code is on the clipboard")
Else
MessageRequester("Notice:", "Nothing to copy!")
EndIf
SetActiveGadget(canvas)
EndProcedure
Procedure LogCurves() ; Build list of codeline strings from Curves() list and display them
Protected currentcodestring.s
ClearList(codelines())
ForEach curves()
If GetGadgetState(option1)
If curves()\moverequired
s1.s=StrD((curves()\startpoint\x-cxborder)/cx*outputcx,2)
s2.s=StrD((curves()\startpoint\y-cyborder)/cy*outputcy,2)
currentcodestring="MovePathCursor("+s1+","+s2+")"+#CRLF$
Else
currentcodestring=""
EndIf
p1.s=StrD((curves()\firstpoint\x-cxborder)/cx*outputcx,2)+","
p2.s=StrD((curves()\firstpoint\y-cyborder)/cy*outputcy,2)+","
p3.s=StrD((curves()\secondpoint\x-cxborder)/cx*outputcx,2)+","
p4.s=StrD((curves()\secondpoint\y-cyborder)/cy*outputcy,2)+","
p5.s=StrD((curves()\endpoint\x-cxborder)/cx*outputcx,2)+","
p6.s=StrD((curves()\endpoint\y-cyborder)/cy*outputcy,2)
currentcodestring+"AddPathCurve("+p1+p2+p3+p4+p5+p6+")"
AddElement(codelines())
codelines()=currentcodestring
Else
If ListSize(codelines())=0
currentcodestring="cx.d="+Str(outputcx)+" : "+"cy.d="+Str(outputcy)+#CRLF$
Else
currentcodestring=""
EndIf
s1.s=StrD(Round((curves()\startpoint\x-cxborder)/cx*outputcx,#PB_Round_Nearest)/outputcx,4)+"*cx"
s2.s=StrD(Round((curves()\startpoint\y-cyborder)/cy*outputcy,#PB_Round_Nearest)/outputcy,4)+"*cy"
If curves()\moverequired
currentcodestring+"MovePathCursor("+s1+","+s2+")"+#CRLF$
EndIf
p1.s=StrD(Round((curves()\firstpoint\x-cxborder)/cx*outputcx,#PB_Round_Nearest)/outputcx,4)+"*cx"+","
p2.s=StrD(Round((curves()\firstpoint\y-cyborder)/cy*outputcy,#PB_Round_Nearest)/outputcx,4)+"*cy"+","
p3.s=StrD(Round((curves()\secondpoint\x-cxborder)/cx*outputcx,#PB_Round_Nearest)/outputcx,4)+"*cx"+","
p4.s=StrD(Round((curves()\secondpoint\y-cyborder)/cy*outputcy,#PB_Round_Nearest)/outputcx,4)+"*cy"+","
p5.s=StrD(Round((curves()\endpoint\x-cxborder)/cx*outputcx,#PB_Round_Nearest)/outputcx,4)+"*cx"+","
p6.s=StrD(Round((curves()\endpoint\y-cyborder)/cy*outputcy,#PB_Round_Nearest)/outputcx,4)+"*cy"
currentcodestring+"AddPathCurve("+p1+p2+p3+p4+p5+p6+")"
AddElement(codelines())
codelines()=currentcodestring
EndIf
Next
ClearGadgetItems(output)
ForEach codelines()
AddGadgetItem(output, -1, codelines())
Next
EndProcedure
Procedure CommitHandler()
Protected len.d
ClearList(trashcurves())
SetGadgetState(option7, 1)
DisableGadget(commit, 1)
If Not newcurve
LastElement(curves())
curves()\endpoint\x=startpoint\x
curves()\endpoint\y=startpoint\y
EndIf
If editcurve
SelectElement(curves(),editcurve-1)
Else
AddElement(curves())
EndIf
With curves()
If newcurve
\moverequired=1
Else
\moverequired=0
EndIf
\startpoint\x=startpoint\x
\startpoint\y=startpoint\y
\firstpoint\x=firstpoint\x
\firstpoint\y=firstpoint\y
\secondpoint\x=secondpoint\x
\secondpoint\y=secondpoint\y
\endpoint\x=endpoint\x
\endpoint\y=endpoint\y
len=Sqr(Pow(\startpoint\x-\endpoint\x,2)+Pow(\startpoint\y-\endpoint\y,2))
\label\x=\startpoint\x+(\startpoint\y-\endpoint\y)/len*#BoxSize*2
\label\y=\startpoint\y+(\startpoint\x-\endpoint\x)/len*#BoxSize*2
EndWith
ConvertCurvesToOutput()
LogCurves()
startpoint\x=0:startpoint\y=0:endpoint\x=0:endpoint\y=0
ClearStructure(firstpoint,pointd)
ClearStructure(secondpoint,pointd)
curveactive=0
RedrawCurves()
newcurve=0
SetActiveGadget(canvas)
EndProcedure
Procedure New()
curveactive=0
newcurve=1
DisableGadget(commit, 1)
SetGadgetState(option6,1)
EndProcedure
Procedure StringHandler()
outputcx = Val(GetGadgetText(gadget_cx))
outputcy = Val(GetGadgetText(gadget_cy))
SetActiveGadget(canvas)
EndProcedure
Procedure OptionHandler()
Select EventGadget()
Case option1
DisableGadget(gadget_cx, 0)
DisableGadget(gadget_cy, 0)
DisableGadget(label_cx, 0)
DisableGadget(label_cy, 0)
LogCurves()
Case option2
DisableGadget(gadget_cx, 1)
DisableGadget(gadget_cy, 1)
DisableGadget(label_cx, 1)
DisableGadget(label_cy, 1)
LogCurves()
Case option3
HideGadget(ccontainer, 0)
HideGadget(output, 1)
HideGadget(testcanvas,1)
Case option4
HideGadget(output, 0)
HideGadget(ccontainer, 1)
HideGadget(testcanvas,1)
Case option5
UpdateTestCanvas()
HideGadget(testcanvas,0)
HideGadget(output, 1)
HideGadget(ccontainer, 1)
Case option6
New()
Case option7
If ListSize(curves())=0
MessageRequester("Notice:", "No curves to continue!")
SetGadgetState(option6, 1)
EndIf
EndSelect
SetActiveGadget(canvas)
EndProcedure
Procedure RedrawCurves()
Protected id.s
StartDrawing(ImageOutput(imgLayer))
DrawingMode(#PB_2DDrawing_AllChannels)
Box(0,0,nw,nh,RGBA(0,0,0,0))
StopDrawing()
StartVectorDrawing(ImageVectorOutput(imgLayer))
VectorFont(FontID(output_font))
ForEach curves()
With curves()
MovePathCursor(\startpoint\x,\startpoint\y)
AddPathCurve(\firstpoint\x,\firstpoint\y,\secondpoint\x,\secondpoint\y,\endpoint\x,\endpoint\y)
If hovercurve=ListIndex(curves())+1
VectorSourceColor(RGBA(255,220,75,255))
StrokePath(6,#PB_Path_Preserve)
EndIf
VectorSourceColor(RGBA(255,0,0,255))
StrokePath(2)
MovePathCursor(\startpoint\x, \startpoint\y)
AddPathLine(\label\x,\label\y)
VectorSourceColor(RGBA(0,0,255,255))
StrokePath(1)
AddPathBox(\label\x-#BoxSize/2,\label\y-#BoxSize/2,#BoxSize,#BoxSize)
VectorSourceColor(RGBA(255,255,255,255))
FillPath(#PB_Path_Preserve)
VectorSourceColor(RGBA(0,0,255,255))
StrokePath(1)
id=Str(ListIndex(curves())+1)
MovePathCursor(\label\x-VectorTextWidth(id)/2,\label\y-VectorTextHeight(id)/2)
DrawVectorText(id)
EndWith
Next
If curveactive
MovePathCursor(startpoint\x,startpoint\y)
AddPathCurve(firstpoint\x,firstpoint\y,secondpoint\x,secondpoint\y,endpoint\x,endpoint\y)
VectorSourceColor(RGBA(255,0,0,255))
DashPath(1,2)
AddPathCircle(startpoint\x,startpoint\y,4)
VectorSourceColor(RGBA(250,0,0,255))
FillPath()
AddPathCircle(firstpoint\x,firstpoint\y,4)
VectorSourceColor(RGBA(248,0,0,255))
FillPath()
AddPathCircle(secondpoint\x,secondpoint\y,4)
VectorSourceColor(RGBA(246,0,0,255))
FillPath()
AddPathCircle(endpoint\x,endpoint\y,4)
VectorSourceColor(RGBA(244,0,0,255))
FillPath()
EndIf
StopVectorDrawing()
UpdateCanvas()
EndProcedure
Procedure ZoomIn()
Debug "zoom in"
EndProcedure
Procedure ZoomOut()
Debug "zoom out"
EndProcedure
Procedure GetCurveId(x,y)
Protected n
ForEach curves()
With curves()
If x>\label\x-#BoxSize/2 And x<\label\x+#BoxSize/2
If y>\label\y-#BoxSize/2 And y<\label\y+#BoxSize/2
n=ListIndex(curves())+1
EndIf
EndIf
EndWith
Next
ProcedureReturn n
EndProcedure
Procedure CanvasHandler()
Protected x,y
Select EventType()
Case #PB_EventType_KeyDown
Select GetGadgetAttribute(canvas, #PB_Canvas_Key)
Case #PB_Shortcut_Add
If GetGadgetAttribute(canvas, #PB_Canvas_Modifiers) & #PB_Canvas_Control
ZoomIn()
EndIf
Case #PB_Shortcut_Subtract
If GetGadgetAttribute(canvas, #PB_Canvas_Modifiers) & #PB_Canvas_Control
ZoomOut()
EndIf
EndSelect
Case #PB_EventType_LeftButtonDown
If IsImage(imgLayer) And IsImage(imgBackground)
If Not curveactive
x=GetGadgetAttribute(canvas, #PB_Canvas_MouseX)
y=GetGadgetAttribute(canvas, #PB_Canvas_MouseY)
editcurve=GetCurveId(x,y)
If editcurve
SelectElement(curves(),editcurve-1)
With curves()
startpoint\x = \startpoint\x
startpoint\y = \startpoint\y
endpoint\x = \endpoint\x
endpoint\y = \endpoint\y
firstpoint\x=\firstpoint\x
firstpoint\y=\firstpoint\y
secondpoint\x=\secondpoint\x
secondpoint\y=\secondpoint\y
EndWith
curveactive=1
RedrawCurves()
DisableGadget(commit, 0)
ElseIf startpoint\x=0 And startpoint\y=0
If newcurve
startpoint\x = x
startpoint\y = y
oldstartpoint\x=startpoint\x
oldstartpoint\y=startpoint\y
StartVectorDrawing(ImageVectorOutput(imgLayer))
VectorSourceColor(RGBA(250,0,0,255))
AddPathCircle(startpoint\x,startpoint\y,4)
FillPath()
StopVectorDrawing()
UpdateCanvas()
Else
If ListSize(curves())
LastElement(curves())
startpoint\x=curves()\endpoint\x
startpoint\y=curves()\endpoint\y
oldstartpoint\x=startpoint\x
oldstartpoint\y=startpoint\y
EndIf
endpoint\x = GetGadgetAttribute(canvas, #PB_Canvas_MouseX)
endpoint\y = GetGadgetAttribute(canvas, #PB_Canvas_MouseY)
oldendpoint\x=endpoint\x
oldendpoint\y=endpoint\y
With firstpoint
If GetKeyState_(#VK_SHIFT)&128
vector\x=curves()\endpoint\x-curves()\secondpoint\x
vector\y=curves()\endpoint\y-curves()\secondpoint\y
\x=startpoint\x + vector\x
\y=startpoint\y + vector\y
Else
\x=startpoint\x + (endpoint\x-startpoint\x)/3
\y=startpoint\y + (endpoint\y-startpoint\y)/3
EndIf
EndWith
With secondpoint
If GetKeyState_(#VK_SHIFT)&128
\x=endpoint\x + vector\x
\y=endpoint\y + vector\y
Else
\x=startpoint\x + ((endpoint\x-startpoint\x)/3)*2
\y=startpoint\y + ((endpoint\y-startpoint\y)/3)*2
EndIf
EndWith
oldfirstpoint=firstpoint
oldsecondpoint=secondpoint
curveactive=1
RedrawCurves()
DisableGadget(commit, 0)
EndIf
ElseIf endpoint\x=0 And endpoint\y=0
endpoint\x = GetGadgetAttribute(canvas, #PB_Canvas_MouseX)
endpoint\y = GetGadgetAttribute(canvas, #PB_Canvas_MouseY)
oldendpoint\x=endpoint\x
oldendpoint\y=endpoint\y
With firstpoint
\x=startpoint\x + (endpoint\x-startpoint\x)/3
\y=startpoint\y + (endpoint\y-startpoint\y)/3
EndWith
With secondpoint
\x=startpoint\x + ((endpoint\x-startpoint\x)/3)*2
\y=startpoint\y + ((endpoint\y-startpoint\y)/3)*2
EndWith
oldfirstpoint=firstpoint
oldsecondpoint=secondpoint
curveactive=1
RedrawCurves()
DisableGadget(commit, 0)
EndIf
EndIf
EndIf
Case #PB_EventType_LeftButtonUp
moveinprogress=0
on1=0 : on2=0 : on3=0 : on4=0
Case #PB_EventType_MouseMove
If IsImage(imgLayer) And IsImage(imgBackground)
cursorx = GetGadgetAttribute(canvas, #PB_Canvas_MouseX)
cursory = GetGadgetAttribute(canvas, #PB_Canvas_MouseY)
Protected n
n=GetCurveId(cursorx,cursory)
If n<>hovercurve
hovercurve=n
Debug "Curve #"+Str(hovercurve)
RedrawCurves()
EndIf
If Not moveinprogress
StartDrawing(ImageOutput(imgLayer))
Select Point(cursorx, cursory)
Case RGB(250,0,0)
on1=1 : on2=0 : on3=0 : on4=0
Case RGB(248,0,0)
on2=1 : on1=0 : on3=0 : on4=0
Case RGB(246,0,0)
on3=1 : on1=0 : on2=0 : on4=0
Case RGB(244,0,0)
on4=1 : on1=0 : on2=0 : on3=0
Default
on1=0 : on2=0 : on3=0 : on4=0
EndSelect
StopDrawing()
EndIf
If GetGadgetAttribute(EventGadget(),#PB_Canvas_Buttons) & #PB_Canvas_LeftButton
If curveactive
moveinprogress=1
If on1
startpoint\x=cursorx : startpoint\y=cursory
oldstartpoint=startpoint
RedrawCurves()
ElseIf on2
firstpoint\x=cursorx : firstpoint\y=cursory
oldfirstpoint=firstpoint
RedrawCurves()
ElseIf on3
secondpoint\x=cursorx : secondpoint\y=cursory
oldsecondpoint=secondpoint
RedrawCurves()
ElseIf on4
endpoint\x=cursorx : endpoint\y=cursory
oldendpoint=endpoint
RedrawCurves()
EndIf
EndIf
Else
moveinprogress=0
EndIf
EndIf
EndSelect
EndProcedure
Procedure NewImageButtonHandler()
file$ = OpenFileRequester("Select an image","", "Image |*.jpg;*.png;*.bmp",0)
If file$
ext$ = GetExtensionPart(file$)
Select LCase(ext$)
Case "png"
UsePNGImageDecoder()
Case "jpg"
UseJPEGImageDecoder()
EndSelect
FreeImage(imgOriginalBackground)
imgOriginalBackground = LoadImage(#PB_Any,file$)
If IsImage(imgOriginalBackground)
InitializeCanvas()
Else
imgOriginalBackground=CreateImage(#PB_Any, max,max,24)
EndIf
EndIf
SetActiveGadget(canvas)
EndProcedure
Procedure CreateCursor()
color = CreateImage(#PB_Any, 32,32,32,#PB_Image_Transparent)
StartVectorDrawing(ImageVectorOutput(color))
AddPathCircle(15.5,15.5,2)
AddPathCircle(15.5,15.5,15)
MovePathCursor(15.5,13.5)
AddPathLine(15.5,1.5)
MovePathCursor(15.5,17.5)
AddPathLine(15.5,30.5)
MovePathCursor(13.5,15.5)
AddPathLine(1.5,15.5)
MovePathCursor(17.5,15.5)
AddPathLine(30.5,15.5)
VectorSourceColor(RGBA(255,0,0,255))
StrokePath(1)
StopVectorDrawing()
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
mask = CreateImage(#PB_Any, 32,32,32,#PB_Image_Transparent)
StartVectorDrawing(ImageVectorOutput(mask))
AddPathCircle(15.5,15.5,2)
AddPathCircle(15.5,15.5,15)
MovePathCursor(15.5,13.5)
AddPathLine(15.5,1.5)
MovePathCursor(15.5,17.5)
AddPathLine(15.5,30.5)
MovePathCursor(13.5,15.5)
AddPathLine(1.5,15.5)
MovePathCursor(17.5,15.5)
AddPathLine(30.5,15.5)
VectorSourceColor(RGBA(255,255,255,255))
StrokePath(1)
StopVectorDrawing()
With icoInf.ICONINFO
\fIcon = #False
\xHotspot = 15
\yHotspot = 15
\hbmMask = ImageID(mask)
\hbmColor = ImageID(color)
EndWith
ProcedureReturn CreateIconIndirect(icoInf)
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
Define *cursor.GdkCursor = gdk_cursor_new_from_pixbuf_(gdk_display_get_default_(), ImageID(color), 16, 16)
ProcedureReturn *cursor
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
Define hotSpot.NSPoint
hotSpot\x = 16
hotSpot\y = 16
Define *cursor = CocoaMessage(0, 0, "NSCursor alloc")
CocoaMessage(0, *cursor, "initWithImage:", ImageID(color), "hotSpot:@", @hotSpot)
ProcedureReturn *cursor
CompilerEndIf
EndProcedure
Procedure UpdateCanvas()
If IsImage(imgOutput)
FreeImage(imgOutput)
EndIf
imgOutput = CopyImage(imgBackground,#PB_Any)
StartVectorDrawing(ImageVectorOutput(imgOutput))
MovePathCursor(0,0)
DrawVectorImage(ImageID(imgLayer))
StopVectorDrawing()
SetGadgetAttribute(canvas, #PB_Canvas_Image, ImageID(imgOutput))
EndProcedure