Vector Drawing: Put an Arrow endpoint on your arc

Share your advanced PureBasic knowledge/code with the community.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Vector Drawing: Put an Arrow endpoint on your arc

Post by netmaestro »

I have a project that draws a circular progress bar using gdiplus. It dawned on me today that with the Vector Drawing library at our disposal, we no longer have to dip into the gdiplus bare metal anymore, we can do most things with native PB. However, to my acute disappointment, there is no flag for StrokePath() that will draw your stroke ending in an arrow pointer. Gdiplus itself has this nice command: GdipSetPenEndCap(*pen1, #LineCapArrowAnchor) but there is no corresponding capability in StrokePath(). So - I worked out how to do it manually (with actually not that much trouble). Here is the result:

Code: Select all

; Vector Drawing Demo: Draw an endpoint on a partial circle 

Enumeration image
  #Base
  #Final
EndEnumeration

Declare RenderProgressBar(void)

If CreateImage(#Base, 200, 200, 24, RGB(255,255,255))
  If StartDrawing(ImageOutput(#Base))
    For j=0 To 180 Step 20
      For i=0 To 180 Step 20
        Box(i,j,10,10,RGB(220,220,220))
        Box(i+10,j+10,10,10,RGB(220,220,220))
      Next
    Next
    Box(40,40,120,120,RGB(0,0,0))
    Box(41,41,118,118,RGB(220,220,220))
    Box(50,50,100,100,RGB(0,0,0))
    Box(51,51,98,98,RGB(255,255,255))
    StopDrawing()
  EndIf
EndIf

If OpenWindow(0, 0, 0, 200, 200, "VectorDrawing", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  CopyImage(#Base, #Final)
  ImageGadget(0, 0, 0, 200, 200, ImageID(#Final))
  tid = CreateThread(@RenderProgressBar(), 0)
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf

Procedure RenderProgressBar(void)
  Delay(500)
  progress.d = -90.0 ; To start at the top
  While progress < 270.0
    CopyImage(#Base, #Final)
    If StartVectorDrawing(ImageVectorOutput(#Final))
      VectorSourceLinearGradient(0,0,200,200)
      VectorSourceGradientColor(RGBA(255, 0, 0, 255), 0.0)
      VectorSourceGradientColor(RGBA(255, 255, 0, 255), 1.0)
      
      ; partial circle
      AddPathCircle(100, 100, 90, -90, progress)
      
      ; Save needed values before clearing the path
      angle.d = PathPointAngle(PathLength())+90    
      x.d=PathCursorX()
      y.d=PathCursorY()
      StrokePath(10)
      
      ; Draw endcap arrow using saved coordinates
      If progress < 269 
        RotateCoordinates(x,y,angle)
        MovePathCursor(x-10,y)
        AddPathLine(x,y-20)
        AddPathLine(x+10,y)
        ClosePath()
        FillPath()
      EndIf
      StopVectorDrawing()
      progress + 0.1
    EndIf
    
    SetGadgetState(0, ImageID(#Final))
    Delay(1)
    
  Wend
  Delay(200)
  SetGadgetState(0, ImageID(#Base))
EndProcedure
BERESHEIT
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Vector Drawing: Put an Arrow endpoint on your arc

Post by davido »

@netmaestro,

Very nice and instructive demo.
Thank you for sharing. :D

Tested on MacBook Pro. PureBasic 5.50
DE AA EB
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Vector Drawing: Put an Arrow endpoint on your arc

Post by Kwai chang caine »

Nice one, and works very well here W7 X86 v5.50
Another way for waiting in circle like JAVA progressbar
I don't know if it's possible, but perhaps it's possible to show this progressbar with a transparent window for see just the arrow

Thanks for sahring 8)
ImageThe happiness is a road...
Not a destination
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Vector Drawing: Put an Arrow endpoint on your arc

Post by netmaestro »

For drawing just the progress bar to the desktop, draw it to a 32bit transparent image and render it to the screen with UpdateLayeredWindow.
BERESHEIT
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Vector Drawing: Put an Arrow endpoint on your arc

Post by Kwai chang caine »

Cool !!! That's a good news :D
Can be very usefull ...
Thanks again for your present and also for your answer 8)
ImageThe happiness is a road...
Not a destination
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Vector Drawing: Put an Arrow endpoint on your arc

Post by netmaestro »

Example for Windows of drawing progress directly to the desktop:

Code: Select all

#TIME_KILL_SYNCHRONOUS = $0100
#LineWidth = 10

Enumeration image
  #Base
  #Output
EndEnumeration

LoadFont(0, "Verdana", 8, #PB_Font_Bold)
Global displaydot$ = #Empty$

Procedure TimerPulse(uTimerID, uMsg, dwUser, dw1, dw2)
  Shared progress.d, x.d, y.d
  CopyImage(#base, #Output)
  vt$ = "Working"+displaydot$
  If StartVectorDrawing(ImageVectorOutput(#Output))
    VectorFont(FontID(0))
    VectorSourceColor(RGBA(128, 0, 255, 255))
    MovePathCursor(62,90)
    DrawVectorText(vt$)
    FillPath()
    VectorSourceLinearGradient(0,0,200,200)
    VectorSourceGradientColor(RGBA(255, 0, 0, 255), 0.0)
    VectorSourceGradientColor(RGBA(255, 255, 0, 255), 1.0)
    
    ; partial circle
    AddPathCircle(100, 100, 60, -90, progress)
    
    ; Save needed values before clearing the path
    angle.d = PathPointAngle(PathLength())+90    
    x.d=PathCursorX()
    y.d=PathCursorY()
    
    StrokePath(#LineWidth)
    
    ; Draw endcap arrow using saved coordinates
    If progress < 269 
      RotateCoordinates(x,y,angle)
      MovePathCursor(x-#LineWidth,y)
      AddPathLine(x,y-#LineWidth*2)
      AddPathLine(x+#LineWidth,y)
      ClosePath()
      FillPath()
    EndIf
    StopVectorDrawing()
    progress + 0.1
    
  EndIf
  
  hDC = StartDrawing(ImageOutput(#Output))
  If hDC
    With sz.SIZE
      \cx = ImageWidth(0)
      \cy = ImageHeight(0)
    EndWith
    ContextOffset.POINT
    With BlendMode.BLENDFUNCTION
      \SourceConstantAlpha = 255
      \AlphaFormat = 1
    EndWith
    UpdateLayeredWindow_(WindowID(0), 0, 0, sz, hDC, ContextOffset, 0, BlendMode, 2)
    StopDrawing()
  EndIf
  
EndProcedure

Procedure dots(void)
  Repeat
    displaydot$ = ""
    Delay(400)
    displaydot$ = "."
    Delay(100)
    displaydot$= ".."
    Delay(100)
    displaydot$= "..."
    Delay(100)
    displaydot$="...."
    Delay(400)
  ForEver
EndProcedure

OpenWindow(0,0,0,200,200,"",#PB_Window_BorderLess|#PB_Window_ScreenCentered|#PB_Window_Invisible)
SetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED|#WS_EX_TOOLWINDOW)
StickyWindow(0, 1)
CreateImage(#Base, 200,200, 32, RGBA(255,255,255,255))
progress.d = -90.0 ; To start at the top
timer = timeSetEvent_(2, 1, @TimerPulse(), 0, #TIME_PERIODIC|#TIME_KILL_SYNCHRONOUS)
HideWindow(0,0)
tid = CreateThread(@dots(),0)
Repeat : WaitWindowEvent(1) : Until progress > 270.0
timeKillEvent_(timer)
KillThread(tid)
WaitThread(tid)
End
BERESHEIT
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Vector Drawing: Put an Arrow endpoint on your arc

Post by Kwai chang caine »

MASTER....you are a mother for me !! 8)

Image

Really splendid !!!
Again more nice than the JAVA logo

One million of thanks for sharing this jewel 8)
ImageThe happiness is a road...
Not a destination
Post Reply