CGContextSetLineDash

does this declare no longer work? :frowning:
[Mojave, Xojo2019R1.1]

I have checked, and it is calling it with correct values, but still returns a solid line

Could you post the declare? The API method is not deprecated. I would suspect a 32Bit style declare, using singles instead of CGFloats.

single is wrong!
CGFloat is only single on 32-bit.

Sorry, itā€™s late.

CGFloat in C is CGFloat in Xojo. Have fun!

Yes, and the array of lengths should be an array of CGFloats too. If you change these, the declare should work again.

EDIT: And size_t is a variable size datatype too:
https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/64bitPorting/transition/transition.html

still doesnā€™t work in 64bit, but does in 32bit

#If TargetCocoa Then
  #If Target32Bit   /// **** ADDED THIS
    Const sizeOfSingle = 4
  #Else
    Const sizeOfSingle = 8
  #EndIf
  // ************************** //
  // **  Cocoa Pattern Line  ** //
  // ************************** //
  
  '
  Declare Sub CGContextSetLineDash Lib "Cocoa" ( context As Integer, phase As CGFloat, lengths As Ptr, count As UInt32)  // *** CHANGED THIS TO CGFLOAT
  '
  x=g.penwidth
  dash=x*3
  dot=x
  spc=dot
  g.AntiAlias=False
  Select Case pattern
  Case DashStyleDot
    lengths=Array(dot,spc) ' dotted line [.......]
  Case DashStyleDash
    lengths=Array(dash,spc) ' dashed line [- - - -]
  End Select
  //
  lengthArray=New MemoryBlock(sizeOfSingle*(1 + UBound(lengths)))
  For i = 0 To UBound(lengths)
    lengthArray.SingleValue(offset) = lengths(i)
    offset = offset + sizeOfSingle
  Next
  
  CGContextSetLineDash g.handle( g.HandleTypeCGContextRef ),0,lengthArray,lengths.Ubound+1
  //
  g.drawline x1,y1,x2,y2
  //
  CGContextSetLineDash g.handle( g.HandleTypeCGContextRef ),0,Nil,0 ' solid line
  //
  g.AntiAlias=aa_flag

Change Count to UInteger and

[quote=459280:@Dave S] lengthArray=New MemoryBlock(sizeOfSingle*(1 + UBound(lengths)))
For i = 0 To UBound(lengths)
lengthArray.SingleValue(offset) = lengths(i)
offset = offset + sizeOfSingle
Next[/quote]
Adapt this code to CGFloat (Doubles for 64 Bit) instead of singles.

Solved itā€¦ thanksā€¦

Public Sub drawDashedLine(g as graphics, x1 as integer, y1 as integer, x2 as integer, y2 as integer, pattern as integer = 0, scale as integer = -1)
  Const fake_it As Boolean=False
  Const DashStyleSolid = 0
  Const DashStyleDash = 1
  Const DashStyleDot = 2
  Dim dash As CGFloat
  Dim spc As CGFloat
  Dim i As Integer
  Dim lengths(-1) As CGFloat
  Dim lengthArray As MemoryBlock
  Dim offset As Integer = 0
  Dim aa_flag As Boolean=g.AntiAlias
  If scale<1 Then scale=g.scaleX
  x1=x1*scale
  y1=y1*scale
  x2=x2*scale
  y2=y2*scale
  If pattern<=DashStyleSolid  Then 
    // ** Solid Line is same regardless of Platform ** /
    g.drawline x1,y1,x2,y2
    Exit Sub
  Else
    Select Case pattern  ' dotted line [.......]
    Case DashStyleDot
      dash=1
      spc=3
    Case DashStyleDash 'lengths=Array(dash,spc) ' dashed line [- - - -]
      dash=5
      spc=5
    End Select
    //
    //
    #If TargetCocoa Then
      Declare Sub CGContextSetLineDash Lib "Cocoa" ( context As Integer, phase As CGFloat, lengths As Ptr, count As UInt32)
      #If Target32Bit
        Const sizeOfSingle = 4
      #Else
        Const sizeOfSingle = 8
      #EndIf
      
      g.AntiAlias=False
      lengths=Array(dash,spc) 
      //
      lengthArray=New MemoryBlock(sizeOfSingle*(1 + UBound(lengths)))
      For i = 0 To UBound(lengths)
        #If Target32Bit
          lengthArray.SingleValue(offset) = lengths(i)
        #Else
          lengthArray.DoubleValue(offset) = lengths(i)
        #EndIf
        offset = offset + sizeOfSingle
      Next
      //
      CGContextSetLineDash g.handle( g.HandleTypeCGContextRef ),0,lengthArray,lengths.Ubound+1
      //
      g.drawline x1,y1,x2,y2
      // return graphic context to original state
      CGContextSetLineDash g.handle( g.HandleTypeCGContextRef ),0,Nil,0 ' solid line
      g.AntiAlias=aa_flag
    #EndIf
  End If
End Sub

seems memoryblock needs a ā€œ.CGFloatValue(offset)ā€

wellā€¦ it worked, but it didnā€™t
seems it drew the correct line stylesā€¦ but it totally screwed any other routines that tried to draw on that same ā€œgā€ā€¦ it pushed everything down 670 px. I comment out all calls to the above routine, and it works fine again

nope doesnā€™t workā€¦ even in 32bit now

once it gets called onceā€¦ The ā€œYā€ coodinate of any other calls is pushed down

I donĀ’t see how it could be doing this. But if it is the case, saving the graphics state and pulling it back when you leave the dash routine should fix it if there is no other influence on your drawing properties hidden somewhere.

me eitherā€¦ but it does, and I know it is the declare call, as commenting it out ā€œfixesā€ that particular issue

The question here isā€¦ how to do thatā€¦ as the ā€œstateā€ isnā€™t something this is a standard Xojo property, at least not in this case, because if it were, then we would have been able to determine what happened :frowning:

So from what you can see, I made ALL the required 64bit updatesā€¦ although now it seems to fail in the same manner for 32bit too :frowning:

I wonder if the drawing code in the call messes up the underlying CG context (or whatever it is that graphics.handle refers to in this case) So that then has follow on side effects

If so I doubt that saving Xojoā€™s graphics properties will have any significant impact since none includes anything like a ā€œcurrent drawing X and Yā€

that said hereā€™s mine

Module GraphicsExtensions
   Class GraphicsSavedState
		AntiAlias As boolean
		AntiAliasMode As graphics.AntiAliasModes
		Bold As boolean
		CharacterSpacing As Integer
		ForeColor As Color
		Italic As boolean
		PenHeight As Double
		PenWidth As Double
		ScaleX As Double
		ScaleY As Double
		TextFont As String
		TextUnit As FontUnits
		Underline As Boolean
   End Class

   Public Function State(extends g as Graphics) as GraphicsSavedState
     Dim state As New GraphicsExtensions.GraphicsSavedState
  
     state.AntiAlias = g.AntiAlias 
     state.AntiAliasMode = g.AntiAliasMode
     state.bold = g.Bold 
     state.CharacterSpacing = g.CharacterSpacing 
     state.ForeColor = g.ForeColor 
     state.Italic = g.Italic 
     state.PenHeight = g.PenHeight 
     state.PenWidth = g.PenWidth 
     state.ScaleX = g.ScaleX 
     state.ScaleY = g.ScaleY 
     state.TextFont = g.TextFont
     state.TextSize = g.TextSize
     state.TextUnit = g.TextUnit
     state.Underline = g.Underline
  
     Return state
  
   End Function

Public Sub State(extends g as Graphics, assigns savedState as GraphicsSavedState)
  g.AntiAlias = savedState.AntiAlias
  g.AntiAliasMode = savedState.AntiAliasMode
  g.Bold = savedState.bold
  g.CharacterSpacing = savedState.CharacterSpacing
  g.ForeColor = savedState.ForeColor
  g.Italic = savedState.Italic
  g.PenHeight = savedState.PenHeight
  g.PenWidth = savedState.PenWidth
  g.ScaleX = savedState.ScaleX
  g.ScaleY = savedState.ScaleY
  g.TextFont = savedState.TextFont
  g.TextSize = savedState.TextSize
  g.TextUnit = savedState.TextUnit 
  g.Underline = savedState.Underline 
  
End Sub

End Module

@Norman: I agree, an y offset sounds rather like the transform property not being identity.

@Dave: That would be https://developer.apple.com/documentation/coregraphics/1456156-cgcontextsavegstate and -restoregstate.

CG context save state and restore seems the right thing to do

However it didnā€™t help

#If TargetCocoa Then
  Declare Sub CGContextSaveGState     Lib "Cocoa" ( context As Integer)
  Declare Sub CGContextRestoreGState  Lib "Cocoa" ( context As Integer)
  Declare Sub CGContextSetLineDash Lib "Cocoa" ( context As Integer, phase As CGFloat, lengths As Ptr, count As UInt32)
  Dim context As Integer = g.handle( g.HandleTypeCGContextRef )
  
  #If Target32Bit
    Const sizeOfSingle = 4
  #Else
    Const sizeOfSingle = 8
  #EndIf
  
  g.AntiAlias=False
  lengths=Array(dash,spc) 
  //
  lengthArray=New MemoryBlock(sizeOfSingle*(1 + UBound(lengths)))
  For i = 0 To UBound(lengths)
    #If Target32Bit
      lengthArray.SingleValue(offset) = lengths(i)
    #Else
      lengthArray.DoubleValue(offset) = lengths(i)
    #EndIf
    offset = offset + sizeOfSingle
  Next
  //
  CGContextSaveGState context
  CGContextSetLineDash context,0,lengthArray,lengths.Ubound+1
  //
  g.drawline x1,y1,x2,y2
  // return graphic context to original state
  CGContextRestoreGState context
  //CGContextSetLineDash context,0,Nil,0 ' solid line
  g.AntiAlias=aa_flag
#EndIf

The issue is actually caused by THIS LINE

 Dim context As Integer = g.handle( g.HandleTypeCGContextRef )

This is what is SHOULD LOOK LIKE

This is what I get if the CGContext lines are active

Note the first call to the declare happens right after that FIRST white box is drawn

Alsoā€¦ ONLY on an RETINA screenā€¦ moving the window to a NON-RETINA screen restores it properly

I remember some problems when mixing CGContext calls with Xojo graphics methods Ā– some API calls seem to be overwritten by Xojo draw commands.
I cannot guarantee for it, but I would try to use CGContextStrokeLinesegments (which is a lot faster than single drawlines) or a similar CGContext line drawing command. Remember to invert the y axis before.

Thanks Ulrichā€¦ but the issue seems to stem from just getting the CONTEXT pointer

if I comment all but this

Dim context As Integer = g.handle( g.HandleTypeCGContextRef )

if still fails

#If TargetCocoa Then
  Dim context As Integer = g.handle( g.HandleTypeCGContextRef )
  g.AntiAlias=False
  g.drawline x1,y1,x2,y2
  g.AntiAlias=aa_flag
#EndIf

IĀ’m out. Not that I wouldnĀ’t believe you or would not like to help you. Just donĀ’t have any idea how that could mess up things. Sorry!