Vector Curve Designer (RAD Tool)

Share your advanced PureBasic knowledge/code with the community.
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Vector Curve Designer (RAD Tool)

Post by Little John »

Hello netmaestro,

thanks again for this cool tool!

I encountered a problem with the code in the first post (last edited on Tue Jun 02, 2020 3:24 am), using PB 5.73 on Windows 10:
After starting the code, I just moved the mouse cursor a bit around, and then the program crashed on line 976

Code: Select all

Select Point(cursorx, cursory)
with the error message: "Point() is outside the drawing area."

Inserting these lines before and after the Select block seems to fix the problem:

Code: Select all

cursorx = GetGadgetAttribute(canvas, #PB_Canvas_MouseX)
cursory = GetGadgetAttribute(canvas, #PB_Canvas_MouseY)
If Not moveinprogress
   StartDrawing(ImageOutput(imgLayers(zoomlevel)))
   If cursorx >= 0 And cursorx < OutputWidth() And cursory >= 0 And cursory < OutputHeight()  ; <= Fix
      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
   EndIf                                                                                      ; <= Fix
   StopDrawing()
EndIf
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8422
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Vector Curve Designer (RAD Tool)

Post by netmaestro »

You're most welcome. I find myself using it all the time. And sometimes I think "holy crap I wrote this?"
BERESHEIT
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Vector Curve Designer (RAD Tool)

Post by Little John »

I've got a new convertible, and I thought it would be even more fun to use this program with a touch screen and a stylus rather than a mouse. Unfortunately, it doesn't work properly: I can add a new curve, but after that I can't “grab” and move the red dots with the active stylus. Have special things to be taken into account when programming for touch screen operation?
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8422
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Vector Curve Designer (RAD Tool)

Post by netmaestro »

Unfortunately I don't have any touch-capable windows devices and have never tested that. If touch isn't working for this, I am without ideas. Maybe someone else on the forum could suggest a solution, in which case I'll be glad to implement it in the current code. Thanks in advance for any help!
BERESHEIT
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8422
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Vector Curve Designer (RAD Tool)

Post by netmaestro »

There is a bugfix update to this code today. The bug hid for so long because all I ever designed with it were square images where cx = cy. The other day I did an image that was taller than it was wide and WHAT?! so I had to dig into code written two years ago to find the bug. At my age two years ago might as well be a lifetime. I could barely remember what the thing did, let alone find a bug. But find it I did and as one might suspect, I had some lines of code where cx was coded where cy belonged. All appears to work as expected now so whew!

Anyway the code in the OP is updated if anyone is using this tool. I know I am.
BERESHEIT
User avatar
luis
Addict
Addict
Posts: 3876
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Vector Curve Designer (RAD Tool)

Post by luis »

This looks like a pretty amazing tool, great job NM.
"Have you tried turning it off and on again ?"
A little PureBasic review
User avatar
IceSoft
Addict
Addict
Posts: 1616
Joined: Thu Jun 24, 2004 8:51 am
Location: Germany

Re: Vector Curve Designer (RAD Tool)

Post by IceSoft »

An idea:
It will be great if the tool detect the edges and create the lines itself (for later manually fine tuning).
Also for Curve Type: continuation of last curve
Belive!
<Wrapper>4PB, PB<game>, =QONK=, PetriDish, Movie2Image, PictureManager,...
Jeromyal
Enthusiast
Enthusiast
Posts: 204
Joined: Wed Jul 17, 2013 8:49 am

Re: Vector Curve Designer (RAD Tool)

Post by Jeromyal »

changed 1099 CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux to CompilerIf #PB_Compiler_OS = #PB_OS_Linux
and added line 1104 CompilerEndIf
because raspberry pi complained #image was not initialized.

Code: Select all

CompilerIf  #PB_Compiler_OS = #PB_OS_Linux
    
    Define *cursor.GdkCursor = gdk_cursor_new_from_pixbuf_(gdk_display_get_default_(), ImageID(color), 16, 16)
    
    ProcedureReturn *cursor
    CompilerEndIf
now it launches and seems work great.
DrShrek
New User
New User
Posts: 7
Joined: Thu Jan 26, 2023 8:43 pm

Re: Vector Curve Designer (RAD Tool)

Post by DrShrek »

[NEW] Button: Connect To First Curve
[NEW] Button: Clear (all)
[FIX] Redrawing of the preview section (small zoom window)

Code: Select all

;///////////////////////////////////////////////////
; Project:      Curve Designer
; Author:       Lloyd Gallant (netmaestro)
; Contributors: Idle (Linux cursor creation)
;               wombats (MacOS cursor creation)
;               Version 1.1  Jan 27, 2023 (DrShrek aka IceSoft)
; Date:         May 14,2020, last update (bugfix): April 18, 2022
;               Jan 27, 2023 (DrShek aka IceSoft)
; Target OS:    Windows
; Compiler:     PureBasic 6.0 
; License:      Unrestricted, do as you like
; What it is:   WYSIWYG Vector curve designer
;               (RAD tool for quick drawing)
; Version:      1.1
;////////////////////////////////////////////////////

EnableExplicit

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 CloseCurveHandler()
Declare CopyHandler()
Declare LogCurves()
Declare ResizeHandler()
Declare ConvertCurvesToOutput()
Declare ConvertCurvesFromOutput()
Declare InitializeCanvas()
Declare UndoHandler()
Declare RedoHandler()
Declare ClearHandler()

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  
  Declare InsertHandler()
  
CompilerEndIf

Declare ZoomHandler()
Declare ScrollHandler()


Structure pointd
  x.d
  y.d
EndStructure

Structure curve
  moverequired.i
  startpoint.pointd
  firstpoint.pointd
  secondpoint.pointd
  endpoint.pointd
EndStructure

; Control points
Global.pointd startpoint,firstpoint,secondpoint,endpoint,oldstartpoint,oldfirstpoint,oldsecondpoint,oldendpoint
Global.curve *last, *first

; Dimensions
Global.d width_viewport,height_viewport,oldwidth_viewport,oldheight_viewport,oldcx,oldcy,outputcx,outputcy
Global.d max_viewport,max_zoom=1800,width_zoom,height_zoom,szIcon
Global Dim cx.d(1)
Global Dim cy.d(1)
Global Dim cxborder.d(1)
Global Dim cyborder.d(1)

; Images
Global.i imgCursor=CreateCursor(),imgOriginalBackground,imgOutput,imgZoomed,imgZoomNormal,imgZoomViewport,imgUndo,imgRedo,imgClear
Global Dim imgBackgrounds.i(1)
Global Dim imgLayers.i(1)

; Gadgets
Global.i gadget_output,option1,option2,option3,option4,option5,option6,option7,gadget_cx, gadget_cy,label_cx,label_cy,canvas
Global.i testcanvas,ccontainer,button_commit,button_closeCurve,button_newimage,button_copy,gadget_undo,gadget_redo,gadget_clear,button_insert
Global.i gadget_zoom,gadget_zoom_viewport

; Logic Flow variables
Global.i moveinprogress,curveactive,newcurve,on1,on2,on3,on4,zoomlevel=0

; Fonts
Define.i output_font

Global NewList codelines.s()
Global NewList curves.curve()
Global NewList displaycurves.curve()
Global NewList trashcurves.curve()
Global NewList trashdisplaycurves.curve()

OpenWindow(0,0,0,1024,710,"Vector Curve Designer Version 1.1",#PB_Window_ScreenCentered |
                                                              #PB_Window_SystemMenu        |
                                                              #PB_Window_SizeGadget        |
                                                              #PB_Window_MinimizeGadget    |
                                                              #PB_Window_MaximizeGadget)
StickyWindow(0,1)
WindowBounds(0,780,470,#PB_Default,#PB_Default)
width_viewport=WindowHeight(0)-10
height_viewport=width_viewport
BindEvent(#PB_Event_SizeWindow, @ResizeHandler())

; Left side control panel
szIcon=24
imgUndo=CreateImage(#PB_Any,szIcon,szIcon,32,#PB_Image_Transparent)
imgRedo=CreateImage(#PB_Any, szIcon,szIcon,32,#PB_Image_Transparent)
StartVectorDrawing(ImageVectorOutput(imgUndo))
VectorSourceColor(RGBA(255,255,255,255))
FillVectorOutput()
VectorSourceColor(RGBA(0,0,0,255))
AddPathCircle(0.5000*szIcon,0.6000*szIcon,0.2100*szIcon,40,240,#PB_Path_CounterClockwise)
SaveVectorState()     
RotateCoordinates(0.5000*szIcon,0.5000*szIcon, PathPointAngle(PathLength()))
AddPathLine(0.0000*szIcon,-0.1000*szIcon, #PB_Path_Relative)
AddPathLine(0.1333*szIcon,0.0667*szIcon, #PB_Path_Relative)
AddPathLine(-0.1333*szIcon,0.1000*szIcon, #PB_Path_Relative)
AddPathLine(0.0000*szIcon,-0.1000*szIcon,#PB_Path_Relative)
RestoreVectorState()   
StrokePath(0.0933*szIcon)
StopVectorDrawing()

StartVectorDrawing(ImageVectorOutput(imgRedo))
FlipCoordinatesX(0.5000*szIcon)
MovePathCursor(0,0)
DrawVectorImage(ImageID(imgUndo))
StopVectorDrawing()

imgZoomNormal=CreateImage(#PB_Any,szIcon,szIcon,24,#White)
StartVectorDrawing(ImageVectorOutput(imgZoomNormal))
AddPathCircle(0.4667*szIcon,0.4667*szIcon,0.3000*szIcon)
StrokePath(0.0800*szIcon)
MovePathCursor(0.7167*szIcon,0.7167*szIcon)
AddPathLine(0.8667*szIcon,0.8667*szIcon)
VectorSourceColor(RGBA(0,0,0,255))
StrokePath(0.2000*szIcon,#PB_Path_RoundCorner|#PB_Path_RoundEnd)
MovePathCursor(0.4667*szIcon,0.3333*szIcon)
AddPathLine(0.4667*szIcon,0.6000*szIcon)
MovePathCursor(0.3333*szIcon,0.4667*szIcon)
AddPathLine(0.6000*szIcon,0.4667*szIcon)
StrokePath(0.0800*szIcon,#PB_Path_RoundCorner|#PB_Path_RoundEnd)
StopVectorDrawing()

imgZoomed=CreateImage(#PB_Any,szIcon,szIcon,24,#White)
StartVectorDrawing(ImageVectorOutput(imgZoomed))
VectorSourceColor(RGBA(255,0,0,255))
AddPathCircle(0.4667*szIcon,0.4667*szIcon,0.3000*szIcon)
StrokePath(0.0800*szIcon)
MovePathCursor(0.7167*szIcon,0.7167*szIcon)
AddPathLine(0.8667*szIcon,0.8667*szIcon)
StrokePath(0.2000*szIcon,#PB_Path_RoundCorner|#PB_Path_RoundEnd)
MovePathCursor(0.4667*szIcon,0.3333*szIcon)
AddPathLine(0.4667*szIcon,0.6000*szIcon)
MovePathCursor(0.3333*szIcon,0.4667*szIcon)
AddPathLine(0.6000*szIcon,0.4667*szIcon)
StrokePath(0.0800*szIcon,#PB_Path_RoundCorner|#PB_Path_RoundEnd)
StopVectorDrawing()

imgClear=CreateImage(#PB_Any,szIcon,szIcon,24,#White)
StartVectorDrawing(ImageVectorOutput(imgZoomed))
VectorSourceColor(RGBA(255,0,0,255))
StrokePath(0.0800*szIcon,#PB_Path_RoundCorner|#PB_Path_RoundEnd)
StopVectorDrawing()

FrameGadget(#PB_Any,10,10,270,36,"",#PB_Frame_Flat)
gadget_undo=ButtonImageGadget(#PB_Any, 12,12,32,32,ImageID(imgUndo))
gadget_redo=ButtonImageGadget(#PB_Any, 44,12,32,32,ImageID(imgRedo))
gadget_zoom=ButtonImageGadget(#PB_Any, 78,12,32,32,ImageID(imgZoomNormal),#PB_Button_Toggle)
gadget_clear=ButtonImageGadget(#PB_Any, 110,12,32,32,ImageID(imgClear))
BindGadgetEvent(gadget_undo, @UndoHandler())
BindGadgetEvent(gadget_redo, @RedoHandler())
BindGadgetEvent(gadget_zoom, @ZoomHandler())
BindGadgetEvent(gadget_clear, @ClearHandler())

button_newimage=ButtonGadget(#PB_Any, 10,50,270,20,"Load Image")
BindGadgetEvent(button_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)
button_commit=ButtonGadget(#PB_Any, 10,380,135,20,"Commit This Curve")
DisableGadget(button_commit, 1)
BindGadgetEvent(button_commit, @CommitHandler())
button_closeCurve=ButtonGadget(#PB_Any, 10+135,380,135,20,"Connect To First Curve")
DisableGadget(button_closeCurve, 1)
BindGadgetEvent(button_closeCurve, @CloseCurveHandler())
button_copy=ButtonGadget(#PB_Any, 10,410,270,20,"Copy Code To Clipboard")
BindGadgetEvent(button_copy, @CopyHandler())

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  
  button_insert=ButtonGadget(#PB_Any, 10,440,270,20,"Insert Code To IDE")
  BindGadgetEvent(button_insert, @InsertHandler())
  
CompilerEndIf

gadget_zoom_viewport = ImageGadget(#PB_Any,60,480,0,0,0,#PB_Image_Raised)
HideGadget(gadget_zoom_viewport, 1)

; Edit window
ccontainer=ScrollAreaGadget(#PB_Any,315,0,702,702,700,700,10,#PB_ScrollArea_Flat)
BindGadgetEvent(ccontainer, @ScrollHandler())
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)
gadget_output = EditorGadget(#PB_Any, 316,1,700,700)
SetGadgetFont(gadget_output, FontID(output_font))
HideGadget(gadget_output,1)
HideGadget(testcanvas,1)
imgOriginalBackground=CreateImage(#PB_Any, WindowHeight(0)-2,WindowHeight(0)-2,24)
InitializeCanvas()

SetActiveGadget(canvas)

Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow

;===============================================
;              PROCEDURE SECTION
;===============================================

Procedure ScrollHandler()
  Protected.d cxsmall,cysmall,x,y
  Protected.i imgZoomViewportOutput
  If Not IsImage(imgZoomViewport)
    imgZoomViewport=CreateImage(#PB_Any, ImageWidth(imgBackgrounds(0))*0.2,ImageHeight(imgBackgrounds(0))*0.2)
    StartVectorDrawing(ImageVectorOutput(imgZoomViewport))
    MovePathCursor(0,0)
    DrawVectorImage(ImageID(imgBackgrounds(0)),255,ImageWidth(imgZoomViewport),ImageHeight(imgZoomViewport))
    StopVectorDrawing()
    ResizeGadget(gadget_zoom_viewport,#PB_Ignore,#PB_Ignore,ImageWidth(imgZoomViewport),ImageHeight(imgZoomViewport))
    SetGadgetState(gadget_zoom_viewport, ImageID(imgZoomViewport))
  EndIf
  
  cxsmall.d = ImageWidth(imgZoomViewport)
  cysmall.d = ImageHeight(imgZoomViewport)
  x.d = GetGadgetAttribute(ccontainer, #PB_ScrollArea_X)
  y.d = GetGadgetAttribute(ccontainer, #PB_ScrollArea_Y)
  imgZoomViewportOutput = CopyImage(imgZoomViewport, #PB_Any)
  StartVectorDrawing(ImageVectorOutput(imgZoomViewportOutput))
  MovePathCursor(0,0)
  DrawVectorImage(ImageID(imgLayers(1)),255,cxsmall,cysmall)   
  AddPathBox(x/ImageWidth(imgBackgrounds(1))*cxsmall+1,
             y/ImageHeight(imgBackgrounds(1))*cysmall+1,
             width_viewport/ImageWidth(imgBackgrounds(1))*cxsmall,
             height_viewport/ImageHeight(imgBackgrounds(1))*cysmall)
  VectorSourceColor(RGBA(255,0,0,255))
  StrokePath(1)
  StopVectorDrawing()
  SetGadgetState(gadget_zoom_viewport, ImageID(imgZoomViewportOutput))
  
EndProcedure

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  
  Procedure InsertHandler()
    Protected.i scintilla
    Protected *textBuffer
    scintilla = Val(GetEnvironmentVariable("PB_Tool_Scintilla"))
    If Not IsWindowVisible_(scintilla)
      MessageRequester("Notice","You can only add the generated code"+#CRLF$             +
                                "to the file you launched the tool from."+#CRLF$+#CRLF$  +
                                "To deposit the code elsewhere, use the"+#CRLF$          +
                                "copy button and paste the code manually")
    Else
      If scintilla
        *textBuffer = UTF8(#CRLF$+"; Code inserted by Vector Curve Designer" +
                           #CRLF$+GetGadgetText(gadget_output)+#CRLF$ +
                           "; End of Curve Designer Code"+#CRLF$)
        SendMessage_(scintilla, #EM_REPLACESEL, 0, *textBuffer)
        Delay(10)
        FreeMemory(*textBuffer)
      Else
        MessageRequester("Notice:","Scintilla editor not found!"+#CRLF$+#CRLF$ +
                                   "Invoke Curve Designer tool from the PureBasic IDE for this feature.")
      EndIf
    EndIf
  EndProcedure
  
CompilerEndIf

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(button_commit, 1)
  ConvertCurvesToOutput()
  LogCurves()
  UpdateTestCanvas()
  SetActiveGadget(canvas)
  If ListSize(curves())=0
    New()
  EndIf
  ConvertCurvesFromOutput()
  RedrawCurves()
  If ListSize(curves()) >= 2 And *first\startpoint\x <> *last\endpoint\x And *first\startpoint\y <> *last\endpoint\y And *first\startpoint\x <> *last\startpoint\x And *first\startpoint\y <> *last\startpoint\y
    DisableGadget(button_closeCurve, 0)
  Else
    DisableGadget(button_closeCurve, 1)
  EndIf
  ScrollHandler()
EndProcedure

Procedure RedoHandler()
  If ListSize(trashcurves())
    LastElement(trashcurves())
    LastElement(curves())
    AddElement(curves())
    curves()=trashcurves()
    DeleteElement(trashcurves())
    curveactive=0
    DisableGadget(button_commit, 1)
  EndIf
  ConvertCurvesToOutput()
  LogCurves()
  UpdateTestCanvas()
  SetActiveGadget(canvas)
  If ListSize(curves())=0
    New()
  EndIf
  curveactive=0
  newcurve=0
  SetGadgetState(option7,1)
  DisableGadget(button_commit,1)
  ConvertCurvesFromOutput()
  RedrawCurves()
  If ListSize(curves()) >= 2 And *first\startpoint\x <> *last\endpoint\x And *first\startpoint\y <> *last\endpoint\y And *first\startpoint\x <> *last\startpoint\x And *first\startpoint\y <> *last\startpoint\y
    DisableGadget(button_closeCurve, 0)
  Else
    DisableGadget(button_closeCurve, 1)
  EndIf
  ScrollHandler()
EndProcedure

Procedure ClearHandler()
  InitializeCanvas()
  SetGadgetState(gadget_zoom,0)
  If GetGadgetAttribute(gadget_zoom, #PB_Button_Image) = ImageID(imgZoomed)
    SetGadgetAttribute(gadget_zoom, #PB_Button_Image, ImageID(imgZoomNormal))
  EndIf
  zoomlevel=0
  HideGadget(gadget_zoom_viewport, 1)
  SetGadgetAttribute(ccontainer,#PB_ScrollArea_InnerWidth,GadgetWidth(canvas))
  SetGadgetAttribute(ccontainer,#PB_ScrollArea_InnerHeight,GadgetHeight(canvas))
  
  SetActiveGadget(canvas)
  ScrollHandler()
EndProcedure


Procedure InitializeCanvas()
  Protected max_viewport.d,w.d,h.d
  ClearList(curves())
  ClearList(displaycurves())
  ClearList(trashcurves())
  ClearList(codelines())
  ClearGadgetItems(gadget_output)
  ClearStructure(startpoint, pointd)
  ClearStructure(firstpoint, pointd)
  ClearStructure(secondpoint, pointd)
  ClearStructure(endpoint, pointd)
  
  
  StartVectorDrawing(CanvasVectorOutput(testcanvas))
  VectorSourceColor(RGBA(255,255,255,255))
  StopVectorDrawing()
  New()
  SetGadgetState(option1,1)
  HideGadget(gadget_output,1)
  HideGadget(testcanvas,1)
  HideGadget(ccontainer,0)
  SetGadgetState(option3,1)
  SetGadgetState(option6,1)
  w.d = ImageWidth(imgOriginalBackground)
  h.d = ImageHeight(imgOriginalBackground)
  If h>w
    height_zoom.d=max_zoom
    width_zoom.d=w/h*max_zoom
  Else
    width_zoom.d=max_zoom
    height_zoom.d=h/w*max_zoom   
  EndIf
  cxborder(1)=width_zoom*0.2
  cyborder(1)=height_zoom*0.2
  cx(1)=0.6*width_zoom
  cy(1)=0.6*height_zoom 
  outputcx=w
  outputcy=h
  ResizeGadget(testcanvas,316,1,outputcx,outputcy)
  SetGadgetText(gadget_cx, Str(outputcx))
  SetGadgetText(gadget_cy, Str(outputcy))
  max_viewport=WindowHeight(0)-10
  If h>w
    height_viewport.d=max_viewport
    width_viewport.d=w/h*max_viewport
  Else
    width_viewport.d=max_viewport
    height_viewport.d=h/w*max_viewport   
  EndIf
  oldwidth_viewport=width_viewport
  oldheight_viewport=height_viewport
  cxborder(0)=width_viewport*0.2
  cyborder(0)=height_viewport*0.2
  cx(0)=0.6*width_viewport
  cy(0)=0.6*height_viewport
  oldcx=cx(0)
  oldcy=cy(0)
  If IsImage(imgBackgrounds(0)) : FreeImage(imgBackgrounds(0)) : EndIf
  imgBackgrounds(0) = CreateImage(#PB_Any,width_viewport,height_viewport,24,#White)
  StartVectorDrawing(ImageVectorOutput(imgBackgrounds(0)))
  VectorSourceColor(RGBA(255,255,255,255))
  FillVectorOutput()
  MovePathCursor(cxborder(0),cyborder(0))
  DrawVectorImage(ImageID(imgOriginalBackground),80,cx(0),cy(0))
  AddPathBox(cxborder(0),cyborder(0),cx(0),cy(0))
  VectorSourceColor(RGBA(100,100,255,255))
  DashPath(1,4)
  StopVectorDrawing()
  If IsImage(imgBackgrounds(1)) : FreeImage(imgBackgrounds(1)) : EndIf
  imgBackgrounds(1) = CreateImage(#PB_Any,width_zoom,height_zoom,24,#White)
  StartVectorDrawing(ImageVectorOutput(imgBackgrounds(1)))
  MovePathCursor(0,0)
  DrawVectorImage(ImageID(imgBackgrounds(0)),255,ImageWidth(imgBackgrounds(1)),ImageHeight(imgBackgrounds(1)))
  StopVectorDrawing()
  If IsImage(imgLayers(0)) : FreeImage(imgLayers(0)) : EndIf
  imgLayers(0) = CreateImage(#PB_Any, width_viewport,height_viewport,32,#PB_Image_Transparent)
  If IsImage(imgLayers(1)) : FreeImage(imgLayers(1)) : EndIf
  imgLayers(1) = CreateImage(#PB_Any,ImageWidth(imgBackgrounds(1)),ImageHeight(imgBackgrounds(1)),32,#PB_Image_Transparent)
  ResizeGadget(canvas, #PB_Ignore,#PB_Ignore,width_viewport,height_viewport)
  SetGadgetAttribute(canvas, #PB_Canvas_Image, ImageID(imgBackgrounds(0)))
  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(zoomlevel))/cx(zoomlevel)*outputcx
      \startpoint\y  = (curves()\startpoint\y-cyborder(zoomlevel))/cy(zoomlevel)*outputcy
      \firstpoint\x  = (curves()\firstpoint\x-cxborder(zoomlevel))/cx(zoomlevel)*outputcx
      \firstpoint\y  = (curves()\firstpoint\y-cyborder(zoomlevel))/cy(zoomlevel)*outputcy
      \secondpoint\x = (curves()\secondpoint\x-cxborder(zoomlevel))/cx(zoomlevel)*outputcx
      \secondpoint\y = (curves()\secondpoint\y-cyborder(zoomlevel))/cy(zoomlevel)*outputcy
      \endpoint\x    = (curves()\endpoint\x-cxborder(zoomlevel))/cx(zoomlevel)*outputcx
      \endpoint\y    = (curves()\endpoint\y-cyborder(zoomlevel))/cy(zoomlevel)*outputcy     
    EndWith
  Next
  ClearList(trashdisplaycurves()) 
  ForEach trashcurves()
    AddElement(trashdisplaycurves())
    With trashdisplaycurves()
      \moverequired  = trashcurves()\moverequired
      \startpoint\x  = (trashcurves()\startpoint\x-cxborder(zoomlevel))/cx(zoomlevel)*outputcx
      \startpoint\y  = (trashcurves()\startpoint\y-cyborder(zoomlevel))/cy(zoomlevel)*outputcy
      \firstpoint\x  = (trashcurves()\firstpoint\x-cxborder(zoomlevel))/cx(zoomlevel)*outputcx
      \firstpoint\y  = (trashcurves()\firstpoint\y-cyborder(zoomlevel))/cy(zoomlevel)*outputcy
      \secondpoint\x = (trashcurves()\secondpoint\x-cxborder(zoomlevel))/cx(zoomlevel)*outputcx
      \secondpoint\y = (trashcurves()\secondpoint\y-cyborder(zoomlevel))/cy(zoomlevel)*outputcy
      \endpoint\x    = (trashcurves()\endpoint\x-cxborder(zoomlevel))/cx(zoomlevel)*outputcx
      \endpoint\y    = (trashcurves()\endpoint\y-cyborder(zoomlevel))/cy(zoomlevel)*outputcy     
    EndWith
  Next
EndProcedure

Procedure ConvertCurvesFromOutput()
  ClearList(curves())
  ForEach displaycurves()
    AddElement(curves())
    With curves()
      \moverequired  = displaycurves()\moverequired
      \startpoint\x  = displaycurves()\startpoint\x*cx(zoomlevel)/outputcx+cxborder(zoomlevel)
      \startpoint\y  = displaycurves()\startpoint\y*cy(zoomlevel)/outputcy+cyborder(zoomlevel)
      \firstpoint\x  = displaycurves()\firstpoint\x*cx(zoomlevel)/outputcx+cxborder(zoomlevel)
      \firstpoint\y  = displaycurves()\firstpoint\y*cy(zoomlevel)/outputcy+cyborder(zoomlevel)
      \secondpoint\x = displaycurves()\secondpoint\x*cx(zoomlevel)/outputcx+cxborder(zoomlevel)
      \secondpoint\y = displaycurves()\secondpoint\y*cy(zoomlevel)/outputcy+cyborder(zoomlevel)
      \endpoint\x    = displaycurves()\endpoint\x*cx(zoomlevel)/outputcx+cxborder(zoomlevel)
      \endpoint\y    = displaycurves()\endpoint\y*cy(zoomlevel)/outputcy+cyborder(zoomlevel)   
    EndWith
  Next
  ClearList(trashcurves())
  ForEach trashdisplaycurves()
    AddElement(trashcurves())
    With trashcurves()
      \moverequired  = trashdisplaycurves()\moverequired
      \startpoint\x  = trashdisplaycurves()\startpoint\x*cx(zoomlevel)/outputcx+cxborder(zoomlevel)
      \startpoint\y  = trashdisplaycurves()\startpoint\y*cy(zoomlevel)/outputcy+cyborder(zoomlevel)
      \firstpoint\x  = trashdisplaycurves()\firstpoint\x*cx(zoomlevel)/outputcx+cxborder(zoomlevel)
      \firstpoint\y  = trashdisplaycurves()\firstpoint\y*cy(zoomlevel)/outputcy+cyborder(zoomlevel)
      \secondpoint\x = trashdisplaycurves()\secondpoint\x*cx(zoomlevel)/outputcx+cxborder(zoomlevel)
      \secondpoint\y = trashdisplaycurves()\secondpoint\y*cy(zoomlevel)/outputcy+cyborder(zoomlevel)
      \endpoint\x    = trashdisplaycurves()\endpoint\x*cx(zoomlevel)/outputcx+cxborder(zoomlevel)
      \endpoint\y    = trashdisplaycurves()\endpoint\y*cy(zoomlevel)/outputcy+cyborder(zoomlevel)   
    EndWith
  Next
EndProcedure

Procedure ResizeHandler()
  Protected.d w,h,max_viewport
  
  ConvertCurvesToOutput()
  w=ImageWidth(imgOriginalBackground)
  h=ImageHeight(imgOriginalBackground)
  max_viewport=WindowHeight(0)-10
  If h>w
    height_viewport.d=max_viewport
    width_viewport.d=w/h*max_viewport
  Else
    width_viewport.d=max_viewport
    height_viewport.d=h/w*max_viewport   
  EndIf
  cxborder(0)=width_viewport*0.2
  cyborder(0)=height_viewport*0.2
  cx(0)=0.6*width_viewport
  cy(0)=0.6*height_viewport
  
  If zoomlevel=0 
    If curveactive
      startpoint\x  = (oldstartpoint\x/oldwidth_viewport)*width_viewport
      startpoint\y  = (oldstartpoint\y/oldheight_viewport)*height_viewport
      endpoint\x    = (oldendpoint\x/oldwidth_viewport)*width_viewport
      endpoint\y    = (oldendpoint\y/oldheight_viewport)*height_viewport
      firstpoint\x  = (oldfirstpoint\x/oldwidth_viewport)*width_viewport
      firstpoint\y  = (oldfirstpoint\y/oldheight_viewport)*height_viewport
      secondpoint\x = (oldsecondpoint\x/oldwidth_viewport)*width_viewport
      secondpoint\y = (oldsecondpoint\y/oldheight_viewport)*height_viewport
    EndIf
  EndIf
  
  If IsImage(imgBackgrounds(0)) : FreeImage(imgBackgrounds(0)) : EndIf
  imgBackgrounds(0) = CreateImage(#PB_Any,width_viewport,height_viewport,24,#White)
  StartVectorDrawing(ImageVectorOutput(imgBackgrounds(0)))
  VectorSourceColor(RGBA(255,255,255,255))
  FillVectorOutput()
  MovePathCursor(cxborder(0),cyborder(0))
  DrawVectorImage(ImageID(imgOriginalBackground),80,cx(0),cy(0))
  AddPathBox(cxborder(0),cyborder(0),cx(0),cy(0))
  VectorSourceColor(RGBA(100,100,255,255))
  DashPath(1,4)
  StopVectorDrawing()
  ResizeGadget(canvas, 1,1,ImageWidth(imgBackgrounds(zoomlevel)),ImageHeight(imgBackgrounds(zoomlevel)))
  SetGadgetAttribute(canvas,#PB_Canvas_Image,ImageID(imgBackgrounds(zoomlevel))) 
  ResizeGadget(ccontainer, 316,1,width_viewport+2,height_viewport+2)
  SetGadgetAttribute(ccontainer, #PB_ScrollArea_InnerWidth, ImageWidth(imgBackgrounds(zoomlevel)))
  SetGadgetAttribute(ccontainer, #PB_ScrollArea_InnerHeight, ImageHeight(imgBackgrounds(zoomlevel)))
  If IsImage(imgLayers(0)) : FreeImage(imgLayers(0)) : EndIf
  imgLayers(0) = CreateImage(#PB_Any, width_viewport,height_viewport,32,#PB_Image_Transparent)
  
  If curveactive
    oldstartpoint=startpoint
    oldfirstpoint=firstpoint
    oldsecondpoint=secondpoint
    oldendpoint=endpoint
  EndIf   
  oldwidth_viewport=width_viewport
  oldheight_viewport=height_viewport
  oldcx=cx(0)
  oldcy=cy(0)
  SetActiveGadget(canvas)
  ConvertCurvesFromOutput()
  RedrawCurves()
  
EndProcedure

Procedure CopyHandler()
  Protected.s code
  code = "; Code inserted by Vector Curve Designer"+#CRLF$ +
         GetGadgetText(gadget_output)+#CRLF$               +
         "; End of Vector Curve Designer code"
  If GetGadgetText(gadget_output)<>""
    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,saved_zoomlevel.i
  Protected.s s1,s2,p1,p2,p3,p4,p5,p6
  ConvertCurvesToOutput()
  saved_zoomlevel=zoomlevel
  zoomlevel=0
  ConvertCurvesFromOutput()
  zoomlevel=saved_zoomlevel
  ClearList(codelines())
  ForEach curves()
    If GetGadgetState(option1)
      If curves()\moverequired
        s1.s=StrD((curves()\startpoint\x-cxborder(0))/cx(0)*outputcx,2)
        s2.s=StrD((curves()\startpoint\y-cyborder(0))/cy(0)*outputcy,2)
        currentcodestring="MovePathCursor("+s1+","+s2+")"+#CRLF$
      Else
        currentcodestring=""
      EndIf
      p1.s=StrD((curves()\firstpoint\x-cxborder(0))/cx(0)*outputcx,2)+","
      p2.s=StrD((curves()\firstpoint\y-cyborder(0))/cy(0)*outputcy,2)+","
      p3.s=StrD((curves()\secondpoint\x-cxborder(0))/cx(0)*outputcx,2)+","
      p4.s=StrD((curves()\secondpoint\y-cyborder(0))/cy(0)*outputcy,2)+","
      p5.s=StrD((curves()\endpoint\x-cxborder(0))/cx(0)*outputcx,2)+","
      p6.s=StrD((curves()\endpoint\y-cyborder(0))/cy(0)*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(0))/cx(0)*outputcx,#PB_Round_Nearest)/outputcx,4)+"*cx"
      s2.s=StrD(Round((curves()\startpoint\y-cyborder(0))/cy(0)*outputcy,#PB_Round_Nearest)/outputcy,4)+"*cy"
      If curves()\moverequired
        currentcodestring+"MovePathCursor("+s1+","+s2+")"+#CRLF$
      EndIf
      p1.s=StrD(Round((curves()\firstpoint\x-cxborder(0))/cx(0)*outputcx,#PB_Round_Nearest)/outputcx,4)+"*cx"+","
      p2.s=StrD(Round((curves()\firstpoint\y-cyborder(0))/cy(0)*outputcy,#PB_Round_Nearest)/outputcy,4)+"*cy"+","
      p3.s=StrD(Round((curves()\secondpoint\x-cxborder(0))/cx(0)*outputcx,#PB_Round_Nearest)/outputcx,4)+"*cx"+","
      p4.s=StrD(Round((curves()\secondpoint\y-cyborder(0))/cy(0)*outputcy,#PB_Round_Nearest)/outputcy,4)+"*cy"+","
      p5.s=StrD(Round((curves()\endpoint\x-cxborder(0))/cx(0)*outputcx,#PB_Round_Nearest)/outputcx,4)+"*cx"+","
      p6.s=StrD(Round((curves()\endpoint\y-cyborder(0))/cy(0)*outputcy,#PB_Round_Nearest)/outputcy,4)+"*cy"
      currentcodestring+"AddPathCurve("+p1+p2+p3+p4+p5+p6+")"
      AddElement(codelines())
      codelines()=currentcodestring
    EndIf
  Next
  ClearGadgetItems(gadget_output)
  ForEach codelines()
    AddGadgetItem(gadget_output, -1, codelines())
  Next
EndProcedure

Procedure CommitHandler()
  ClearList(trashcurves())
  SetGadgetState(option7, 1)
  DisableGadget(button_commit, 1)
  If Not newcurve
    LastElement(curves())
    curves()\endpoint\x=startpoint\x
    curves()\endpoint\y=startpoint\y
  EndIf
  AddElement(curves())
  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
  EndWith
  ConvertCurvesToOutput()
  LogCurves()
  startpoint\x=0:startpoint\y=0:endpoint\x=0:endpoint\y=0
  ClearStructure(firstpoint,pointd)
  ClearStructure(secondpoint,pointd)
  curveactive=0
  ConvertCurvesFromOutput()
  RedrawCurves()
  newcurve=0
  SetActiveGadget(canvas)
  *last = LastElement(curves())
  *first = FirstElement(curves())
  If ListSize(curves()) >= 2 And *first\startpoint\x <> *last\endpoint\x And *first\startpoint\y <> *last\endpoint\y And *first\startpoint\x <> *last\startpoint\x And *first\startpoint\y <> *last\startpoint\y
    DisableGadget(button_closeCurve, 0)
  EndIf
  ScrollHandler()
EndProcedure


Procedure CloseCurveHandler()
  DisableGadget(button_closeCurve, 1)
  DisableGadget(button_commit, 0)
  If ListSize(curves())
    LastElement(curves())
    startpoint\x=curves()\endpoint\x
    startpoint\y=curves()\endpoint\y
    
    FirstElement(curves())
    endpoint\x=curves()\startpoint\x
    endpoint\y=curves()\startpoint\y
  EndIf
  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
  oldstartpoint\x=startpoint\x
  oldstartpoint\y=startpoint\y
  oldfirstpoint=firstpoint
  oldsecondpoint=secondpoint
  oldendpoint\x=endpoint\x
  oldendpoint\y=endpoint\y
  curveactive=1
  RedrawCurves()
  ScrollHandler()
EndProcedure

Procedure New()
  curveactive=0
  newcurve=1
  DisableGadget(button_commit, 1)
  DisableGadget(button_closeCurve, 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(gadget_output, 1)
      HideGadget(testcanvas,1)
    Case option4
      HideGadget(gadget_output, 0)
      HideGadget(ccontainer, 1)
      HideGadget(testcanvas,1)
    Case option5
      UpdateTestCanvas()
      HideGadget(testcanvas,0)
      HideGadget(gadget_output, 1)
      HideGadget(ccontainer, 1)
    Case option6
      New()
    Case option7
      If ListSize(curves())=0
        MessageRequester("Notice:", "No curves to continue!")
        SetGadgetState(option6, 1)
      Else
        newcurve=0
      EndIf
  EndSelect
  SetActiveGadget(canvas)
  
EndProcedure

Procedure RedrawCurves()
  StartDrawing(ImageOutput(imgLayers(zoomlevel)))
  DrawingMode(#PB_2DDrawing_AllChannels)
  Box(0,0,ImageWidth(imgLayers(zoomlevel)),ImageHeight(imgLayers(zoomlevel)),RGBA(0,0,0,0))
  StopDrawing()
  StartVectorDrawing(ImageVectorOutput(imgLayers(zoomlevel)))
  ForEach curves()
    With curves()
      MovePathCursor(\startpoint\x,\startpoint\y)
      AddPathCurve(\firstpoint\x,\firstpoint\y,\secondpoint\x,\secondpoint\y,\endpoint\x,\endpoint\y)
      VectorSourceColor(RGBA(255,0,0,255))
      If zoomlevel
        StrokePath(6,#PB_Path_RoundCorner|#PB_Path_RoundEnd)
      Else
        StrokePath(2)
      EndIf
    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 ZoomHandler()
  Protected.i imgZoomViewportOutput
  Protected.d cxsmall,cysmall,x,y
  ConvertCurvesToOutput()
  If GetGadgetAttribute(gadget_zoom, #PB_Button_Image) = ImageID(imgZoomed)
    SetGadgetAttribute(gadget_zoom, #PB_Button_Image, ImageID(imgZoomNormal))
    zoomlevel=0
  Else
    SetGadgetAttribute(gadget_zoom, #PB_Button_Image, ImageID(imgZoomed))
    zoomlevel=1
  EndIf
  Select zoomlevel
    Case 0
      ResizeGadget(canvas,#PB_Ignore,#PB_Ignore, width_viewport, height_viewport)
    Case 1
      ResizeGadget(canvas,#PB_Ignore,#PB_Ignore, ImageWidth(imgBackgrounds(1)),ImageHeight(imgBackgrounds(1)))
  EndSelect
  SetGadgetAttribute(ccontainer,#PB_ScrollArea_InnerWidth,GadgetWidth(canvas))
  SetGadgetAttribute(ccontainer,#PB_ScrollArea_InnerHeight,GadgetHeight(canvas))
  SetGadgetAttribute(canvas, #PB_Canvas_Image, ImageID(imgBackgrounds(zoomlevel)))
  SetGadgetAttribute(canvas, #PB_Canvas_CustomCursor, imgCursor)
  
  
  
  If IsImage(imgZoomViewport):FreeImage(imgZoomViewport):EndIf
  imgZoomViewport=CreateImage(#PB_Any, ImageWidth(imgBackgrounds(0))*0.2,ImageHeight(imgBackgrounds(0))*0.2)
  StartVectorDrawing(ImageVectorOutput(imgZoomViewport))
  MovePathCursor(0,0)
  DrawVectorImage(ImageID(imgBackgrounds(0)),255,ImageWidth(imgZoomViewport),ImageHeight(imgZoomViewport))
  StopVectorDrawing()
  ResizeGadget(gadget_zoom_viewport,#PB_Ignore,#PB_Ignore,ImageWidth(imgZoomViewport),ImageHeight(imgZoomViewport))
  SetGadgetState(gadget_zoom_viewport, ImageID(imgZoomViewport))
  RedrawCurves()
  cxsmall.d = ImageWidth(imgZoomViewport)
  cysmall.d = ImageHeight(imgZoomViewport)
  x.d = GetGadgetAttribute(ccontainer, #PB_ScrollArea_X)
  y.d = GetGadgetAttribute(ccontainer, #PB_ScrollArea_Y)
  imgZoomViewportOutput = CopyImage(imgZoomViewport, #PB_Any)
  StartVectorDrawing(ImageVectorOutput(imgZoomViewportOutput))
  MovePathCursor(0,0)
  DrawVectorImage(ImageID(imgLayers(1)),255,cxsmall,cysmall)   
  AddPathBox(x/ImageWidth(imgBackgrounds(1))*cxsmall+1,
             y/ImageHeight(imgBackgrounds(1))*cysmall+1,
             width_viewport/ImageWidth(imgBackgrounds(1))*cxsmall,
             height_viewport/ImageHeight(imgBackgrounds(1))*cysmall)
  VectorSourceColor(RGBA(255,0,0,255))
  StrokePath(1)
  StopVectorDrawing()
  SetGadgetState(gadget_zoom_viewport, ImageID(imgZoomViewportOutput))
  
  If zoomlevel
    HideGadget(gadget_zoom_viewport, 0)
    If curveactive
      startpoint\x  = startpoint\x/ImageWidth(imgBackgrounds(0))*ImageWidth(imgBackgrounds(1))
      startpoint\y  = startpoint\y/ImageHeight(imgBackgrounds(0))*ImageHeight(imgBackgrounds(1))
      firstpoint\x  = firstpoint\x/ImageWidth(imgBackgrounds(0))*ImageWidth(imgBackgrounds(1))
      firstpoint\y  = firstpoint\y/ImageHeight(imgBackgrounds(0))*ImageHeight(imgBackgrounds(1))
      secondpoint\x = secondpoint\x/ImageWidth(imgBackgrounds(0))*ImageWidth(imgBackgrounds(1))
      secondpoint\y = secondpoint\y/ImageHeight(imgBackgrounds(0))*ImageHeight(imgBackgrounds(1))
      endpoint\x    = endpoint\x/ImageWidth(imgBackgrounds(0))*ImageWidth(imgBackgrounds(1))
      endpoint\y    = endpoint\y/ImageHeight(imgBackgrounds(0))*ImageHeight(imgBackgrounds(1))
      oldstartpoint=startpoint
      oldfirstpoint=firstpoint
      oldsecondpoint=secondpoint
      oldendpoint=endpoint
    EndIf
  Else
    HideGadget(gadget_zoom_viewport, 1)
    If curveactive
      startpoint\x  = startpoint\x/ImageWidth(imgBackgrounds(1))*ImageWidth(imgBackgrounds(0))
      startpoint\y  = startpoint\y/ImageHeight(imgBackgrounds(1))*ImageHeight(imgBackgrounds(0))
      firstpoint\x  = firstpoint\x/ImageWidth(imgBackgrounds(1))*ImageWidth(imgBackgrounds(0))
      firstpoint\y  = firstpoint\y/ImageHeight(imgBackgrounds(1))*ImageHeight(imgBackgrounds(0))
      secondpoint\x = secondpoint\x/ImageWidth(imgBackgrounds(1))*ImageWidth(imgBackgrounds(0))
      secondpoint\y = secondpoint\y/ImageHeight(imgBackgrounds(1))*ImageHeight(imgBackgrounds(0))
      endpoint\x    = endpoint\x/ImageWidth(imgBackgrounds(1))*ImageWidth(imgBackgrounds(0))
      endpoint\y    = endpoint\y/ImageHeight(imgBackgrounds(1))*ImageHeight(imgBackgrounds(0))
      oldstartpoint=startpoint
      oldfirstpoint=firstpoint
      oldsecondpoint=secondpoint
      oldendpoint=endpoint
    EndIf
  EndIf
  
  ConvertCurvesFromOutput()
  RedrawCurves()
  ScrollHandler()
EndProcedure

Procedure CanvasHandler()
  Protected.i cursorx,cursory
  
  Select EventType()
      
    Case #PB_EventType_LeftButtonDown
      If IsImage(imgLayers(zoomlevel)) And IsImage(imgBackgrounds(zoomlevel))
        If Not curveactive
          If startpoint\x=0 And startpoint\y=0
            If newcurve
              startpoint\x = GetGadgetAttribute(canvas, #PB_Canvas_MouseX)
              startpoint\y = GetGadgetAttribute(canvas, #PB_Canvas_MouseY)
              oldstartpoint\x=startpoint\x
              oldstartpoint\y=startpoint\y
              StartVectorDrawing(ImageVectorOutput(imgLayers(zoomlevel)))
              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
                \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(button_commit, 0)
            EndIf
            If ListSize(curves()) >= 2 And *first\startpoint\x <> *last\endpoint\x And *first\startpoint\y <> *last\endpoint\y And *first\startpoint\x <> *last\startpoint\x And *first\startpoint\y <> *last\startpoint\y
              DisableGadget(button_closeCurve, 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(button_commit, 0)
          EndIf
          If ListSize(curves()) >= 2 And *first\startpoint\x <> *last\endpoint\x And *first\startpoint\y <> *last\endpoint\y And *first\startpoint\x <> *last\startpoint\x And *first\startpoint\y <> *last\startpoint\y
            DisableGadget(button_closeCurve, 0)
          EndIf
        EndIf
      EndIf
      
    Case #PB_EventType_LeftButtonUp
      moveinprogress=0
      on1=0 : on2=0 : on3=0 : on4=0
      ScrollHandler()
      
    Case #PB_EventType_MouseMove
      If IsImage(imgLayers(zoomlevel)) And IsImage(imgBackgrounds(zoomlevel))
        cursorx = GetGadgetAttribute(canvas, #PB_Canvas_MouseX)
        cursory = GetGadgetAttribute(canvas, #PB_Canvas_MouseY)
        If Not moveinprogress
          StartDrawing(ImageOutput(imgLayers(zoomlevel)))
          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()
  Protected file$, ext$
  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) = 0
      imgOriginalBackground=CreateImage(#PB_Any, max_viewport,max_viewport,24)
    EndIf
  EndIf
  InitializeCanvas()
  SetGadgetState(gadget_zoom,0)
  If GetGadgetAttribute(gadget_zoom, #PB_Button_Image) = ImageID(imgZoomed)
    SetGadgetAttribute(gadget_zoom, #PB_Button_Image, ImageID(imgZoomNormal))
  EndIf
  zoomlevel=0
  HideGadget(gadget_zoom_viewport, 1)
  SetGadgetAttribute(ccontainer,#PB_ScrollArea_InnerWidth,GadgetWidth(canvas))
  SetGadgetAttribute(ccontainer,#PB_ScrollArea_InnerHeight,GadgetHeight(canvas))
  
  SetActiveGadget(canvas)
EndProcedure

Procedure CreateCursor()
  Protected.i color,mask
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    Protected icoInf.ICONINFO
    
    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()
    
    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(imgBackgrounds(zoomlevel),#PB_Any)
  StartVectorDrawing(ImageVectorOutput(imgOutput))
  MovePathCursor(0,0)
  DrawVectorImage(ImageID(imgLayers(zoomlevel)))
  StopVectorDrawing()
  SetGadgetAttribute(canvas, #PB_Canvas_Image, ImageID(imgOutput))
EndProcedure
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8422
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Vector Curve Designer (RAD Tool)

Post by netmaestro »

DrShrek aka IceSoft, has kindly made some excellent contributions to this project and with his help this is now at version 1.1. Code in first post is changed to this. Thanks DrShrek.
BERESHEIT
User avatar
Paul
PureBasic Expert
PureBasic Expert
Posts: 1243
Joined: Fri Apr 25, 2003 4:34 pm
Location: Canada
Contact:

Re: Vector Curve Designer (RAD Tool)

Post by Paul »

Program is not compatible with DPI_aware enabled.
Tested with 4k monitor, Windows Display 4096x2160, Scale 175%, DPI aware enabled.

Run program and move cursor past bottom or right of draw area... crash... Point() is outside of drawing area
Image Image
User avatar
IceSoft
Addict
Addict
Posts: 1616
Joined: Thu Jun 24, 2004 8:51 am
Location: Germany

Re: Vector Curve Designer (RAD Tool)

Post by IceSoft »

netmaestro wrote: Sat Jan 28, 2023 6:52 pm DrShrek aka IceSoft, has kindly made some excellent contributions to this project and with his help this is now at version 1.1. Code in first post is changed to this. Thanks DrShrek.
No prob ;)
Paul wrote: Sat Jan 28, 2023 8:33 pm Program is not compatible with DPI_aware enabled.
Tested with 4k monitor, Windows Display 4096x2160, Scale 175%, DPI aware enabled.

Run program and move cursor past bottom or right of draw area... crash... Point() is outside of drawing area
Works here without any crash (PB6.01b1)
4k monitor (LG 82UN85006LA) , Windows Display 4096x2160, Scale 175%, DPI aware enabled (Scale 100% and 300% works also)
Belive!
<Wrapper>4PB, PB<game>, =QONK=, PetriDish, Movie2Image, PictureManager,...
User avatar
Paul
PureBasic Expert
PureBasic Expert
Posts: 1243
Joined: Fri Apr 25, 2003 4:34 pm
Location: Canada
Contact:

Re: Vector Curve Designer (RAD Tool)

Post by Paul »

IceSoft wrote: Sun Jan 29, 2023 10:46 am Works here without any crash (PB6.01b1)
4k monitor (LG 82UN85006LA) , Windows Display 4096x2160, Scale 175%, DPI aware enabled (Scale 100% and 300% works also)

Crashes every time here and have to use "Kill Program" button in IDE to stop it...

Image
Image Image
User avatar
IceSoft
Addict
Addict
Posts: 1616
Joined: Thu Jun 24, 2004 8:51 am
Location: Germany

Re: Vector Curve Designer (RAD Tool)

Post by IceSoft »

@Paul can you add this debug line before Select point (e.g.: line 1069) ?

Code: Select all

          Debug "Point(" +Str(cursorx) + "," +Str(cursory)+ ")"        
          Select Point(cursorx, cursory)
Should be always >= 0

or better this one (checks StartDrawing() return value):

Code: Select all

    Case #PB_EventType_MouseMove
      If IsImage(imgLayers(zoomlevel)) And IsImage(imgBackgrounds(zoomlevel))
        cursorx = GetGadgetAttribute(canvas, #PB_Canvas_MouseX)
        cursory = GetGadgetAttribute(canvas, #PB_Canvas_MouseY)
        If Not moveinprogress
          Debug "zoomlevel: " + Str(zoomlevel)
          Debug "imgLayers(zoomlevel): " + Str(imgLayers(zoomlevel))
          Debug "ImageOutput(imgLayers(zoomlevel)): " + Str(ImageOutput(imgLayers(zoomlevel)))
          If StartDrawing(ImageOutput(imgLayers(zoomlevel)))         
            Debug "Point(" +Str(cursorx) + "," +Str(cursory)+ ")"        
            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()
          Else
            Debug "Cant use StartDrawing(ImageOutput(imgLayers(zoomlevel)))"
          EndIf           
        EndIf
        
        If GetGadgetAttribute(EventGadget(),#PB_Canvas_Buttons) & #PB_Canvas_LeftButton
Belive!
<Wrapper>4PB, PB<game>, =QONK=, PetriDish, Movie2Image, PictureManager,...
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: Vector Curve Designer (RAD Tool)

Post by Mijikai »

Thank you for this great tool @netmaestro and all who have contributed.
Version 1.1 works for me (Win 10 x64 no DPI).
Post Reply