Repository navigation
SysWin GdiPlus Line Caps
Home › All Categories › sys/win › sys/win/gdiplus › GDI+ line caps
Draws arrow heads and shapes of your own at the ends of lines drawn with a GDI+ pen.
Draws arrow heads and shapes of your own at the ends of lines drawn with a GDI+ pen.
A CGpPen has standard caps (LineCapRound, LineCapArrowAnchor …) that need no
object. For anything else, make a cap object and give it to the pen with SetCustomStartCap or
SetCustomEndCap:
- CGpAdjustableArrowCap is an arrow head whose height, width, notch and fill you choose.
- CGpCustomLineCap is any shape, given as a CGpGraphicsPath that is either filled or stroked.
The cap's coordinates. A cap is drawn in its own coordinate system: the origin is the end of the line, the positive y axis points onwards in the direction the line was going, and one unit is one pen width (times the width scale). So a stroke path from (-3, 0) to (0, 3) to (3, 0) draws a "V" whose point is three pen widths beyond the end of the line, and a cap drawn with a pen twice as wide is twice as big. The same cap at the start of a line points backwards, away from the line.
Lifetime. Each object wraps one GDI+ cap, which its constructor creates and the
CGpCustomLineCap destructor deletes. A pen keeps its own copy of a cap it is given, so the cap
object can go out of scope while the pen is in use, and changing the cap afterwards does not
change the pen: set it again. Never copy a cap object by value; pass its address, as in
dim b as CGpCustomLineCap = @a, or use Clone.
Status. The setters return a GpStatus: Ok (0) on success, otherwise the reason. The
status is also stored, and GetLastStatus(), which every CGp* class inherits, returns it;
getters that return a value store theirs too.
#import "sys/win"
#import "sys/win/gdiplus"
using win, gdiplusA window with four lines: a filled arrow head, an open one, a notched one, and a custom stroked "V" cap at both ends:
#import "sys/win"
#import "sys/win/gui"
#import "sys/win/gdiplus"
using win, gui, gdiplus
declare function WndProc( byval hwnd as HWND, byval uMsg as UINT, byval wParam as WPARAM, byval lParam as LPARAM ) as LRESULT
function main() as long
SetProcessDpiAwareness( PROCESS_SYSTEM_DPI_AWARE )
dim token as ULONG_PTR = gdiplus.Init()
dim pWindow as CWindow = "CapDemo"
pWindow.Create( NULL, "GDI+ line caps", @WndProc )
pWindow.SetClientSize( 360, 200 )
pWindow.Center()
dim nResult as long = pWindow.DoEvents( SW_NORMAL )
gdiplus.Uninit( token )
return nResult
end function
function WndProc( byval hwnd as HWND, byval uMsg as UINT, byval wParam as WPARAM, byval lParam as LPARAM ) as LRESULT
select case uMsg
case WM_PAINT
dim ps as PAINTSTRUCT
dim hdc as HDC = BeginPaint( hwnd, @ps )
scope
dim graphics as CGpGraphics = hdc
graphics.SetSmoothingMode( SmoothingModeAntiAlias )
graphics.Clear( ARGB_WHITE )
graphics.ScaleTransformForDpi()
dim pen as CGpPen = CGpPen( ARGB_DARKSLATEBLUE, 3 )
dim filled as CGpAdjustableArrowCap = CGpAdjustableArrowCap( 5, 4 )
pen.SetCustomEndCap( @filled )
graphics.DrawLine( @pen, 30, 30, 320, 30 )
dim hollow as CGpAdjustableArrowCap = CGpAdjustableArrowCap( 5, 4, FALSE )
pen.SetCustomEndCap( @hollow )
graphics.DrawLine( @pen, 30, 75, 320, 75 )
dim notched as CGpAdjustableArrowCap = CGpAdjustableArrowCap( 5, 4 )
notched.SetMiddleInset( 2 )
pen.SetCustomEndCap( @notched )
graphics.DrawLine( @pen, 30, 120, 320, 120 )
dim v as CGpGraphicsPath
v.AddLine( -2, 0, 0, 2 )
v.AddLine( 0, 2, 2, 0 )
dim vcap as CGpCustomLineCap = CGpCustomLineCap( NULL, @v )
vcap.SetStrokeCap( LineCapRound )
pen.SetCustomStartCap( @vcap )
pen.SetCustomEndCap( @vcap )
graphics.DrawLine( @pen, 40, 165, 310, 165 )
end scope
EndPaint( hwnd, @ps )
return 0
case WM_DESTROY
PostQuitMessage( 0 )
return 0
end select
return DefWindowProcW( hwnd, uMsg, wParam, lParam )
end function
end main()| Member | Does |
|---|---|
| CGpCustomLineCap | |
| Constructor | Creates an empty object, a copy, or a cap from a fill path or a stroke path. |
| Destructor | Deletes the GDI+ cap. |
| SetStrokeCaps, GetStrokeCaps | Sets or reads the caps of the lines a stroked cap is drawn with. |
| SetStrokeCap | Sets both of those caps to one style. |
| SetStrokeJoin, GetStrokeJoin | Sets or reads how the lines of a stroked cap are joined. |
| SetBaseCap, GetBaseCap | Sets or reads the standard cap drawn under the custom one. |
| SetBaseInset, GetBaseInset | Sets or reads how far the line is cut back for the cap. |
| SetWidthScale, GetWidthScale | Sets or reads the size of the cap relative to the pen width. |
| Clone | Copies this cap into another object. |
| CGpAdjustableArrowCap | |
| Constructor | Creates an arrow head of a given height and width, or a copy. |
| SetHeight, GetHeight | Sets or reads the length of the arrow head. |
| SetWidth, GetWidth | Sets or reads the width across the base of the arrow head. |
| SetMiddleInset, GetMiddleInset | Sets or reads how deep the notch in the base is. |
| SetFillState, IsFilled | Makes the arrow head filled or an outline, or reads which. |
A cap of any shape, defined by a path in the cap's coordinates. A fill path is filled with the
pen's colour; a stroke path is drawn with the pen, using the stroke caps
and join set here. Pass one of the two paths and NULL for the
other.
constructor
constructor( byval pCustomLineCap as CGpCustomLineCap ptr )
constructor( byval pFillPath as CGpGraphicsPath_ ptr, byval pStrokePath as CGpGraphicsPath_ ptr, byval baseCap as LineCap = LinecapFLat, byval baseInset as single = 0.0 )Creates the GDI+ cap.
- With no argument the object holds no cap: calls on it fail with
InvalidParameteruntil Clone or a pen'sGetCustomStartCap/GetCustomEndCapfills it. - With a pointer to another cap it is an independent copy. The pointer must not be
NULL. - With paths it is a cap of that shape. The cap keeps its own copy of the path.
| Parameter | Meaning |
|---|---|
pCustomLineCap |
The cap to copy. |
pFillPath |
A path to fill, or NULL. |
pStrokePath |
A path to stroke, or NULL. |
baseCap |
A standard cap drawn at the end of the line under the custom one: LineCapFlat (the default), LineCapSquare, LineCapRound or LineCapTriangle. |
baseInset |
How far, in pen widths, the line is cut back before the cap; 0 by default. |
Example
dim v as CGpGraphicsPath
v.AddLine( -3, 0, 0, 3 )
v.AddLine( 0, 3, 3, 0 )
dim cap as CGpCustomLineCap = CGpCustomLineCap( NULL, @v )
print cap.GetLastStatus(); cap.GetWidthScale() ' 0 1Microsoft Learn: CustomLineCap::CustomLineCap
destructorDeletes the GDI+ cap. Pens that were given the cap keep their own copy. CGpAdjustableArrowCap
uses this destructor.
Example
dim pCap as CGpAdjustableArrowCap ptr = new CGpAdjustableArrowCap( 5, 4 )
dim pen as CGpPen = CGpPen( ARGB_BLACK, 2 )
pen.SetCustomEndCap( pCap )
delete pCap ' the pen keeps its copyfunction SetStrokeCaps( byval startCap as LineCap, byval endCap as LineCap ) as GpStatus
function GetStrokeCaps( byval startCap as LineCap ptr, byval endCap as LineCap ptr ) as GpStatusA stroked cap is drawn as lines; these are the caps at the start and end of those lines, both
LineCapFlat for a new cap. GetStrokeCaps stores them in two variables.
| Parameter | Meaning |
|---|---|
startCap, endCap
|
The caps, or the variables that receive them. |
Returns Ok on success, otherwise the error.
Example
dim v as CGpGraphicsPath
v.AddLine( -3, 0, 0, 3 )
dim cap as CGpCustomLineCap = CGpCustomLineCap( NULL, @v )
cap.SetStrokeCaps( LineCapFlat, LineCapTriangle )
dim as LineCap s, e
cap.GetStrokeCaps( @s, @e )
print s; e ' 0 3Microsoft Learn: CustomLineCap::SetStrokeCaps
function SetStrokeCap( byval strokeCap as LineCap ) as GpStatusSets the start and end caps of a stroked cap's lines to the same style: LineCapRound softens
the ends of a "V".
Returns Ok on success, otherwise the error.
Example
dim v as CGpGraphicsPath
v.AddLine( -3, 0, 0, 3 )
dim cap as CGpCustomLineCap = CGpCustomLineCap( NULL, @v )
cap.SetStrokeCap( LineCapRound )
dim as LineCap s, e
cap.GetStrokeCaps( @s, @e )
print s; e ' 2 2Microsoft Learn: CustomLineCap::SetStrokeCap
function SetStrokeJoin( byval nLineJoin as LineJoin ) as GpStatus
function GetStrokeJoin() as LineJoinSetStrokeJoin sets how the lines of a stroked cap meet at corners: LineJoinMiter (the
default), LineJoinBevel, LineJoinRound or LineJoinMiterClipped. GetStrokeJoin returns
it.
| Parameter | Meaning |
|---|---|
nLineJoin |
The join. |
Returns SetStrokeJoin: Ok on success, otherwise the error. GetStrokeJoin: the join.
Example
dim v as CGpGraphicsPath
v.AddLine( -3, 0, 0, 3 )
v.AddLine( 0, 3, 3, 0 )
dim cap as CGpCustomLineCap = CGpCustomLineCap( NULL, @v )
cap.SetStrokeJoin( LineJoinRound )
print cap.GetStrokeJoin() ' 2Microsoft Learn: CustomLineCap::SetStrokeJoin
function SetBaseCap( byval baseCap as LineCap ) as GpStatus
function GetBaseCap() as LineCapSetBaseCap sets the standard cap drawn at the end of the line, under the custom shape.
GetBaseCap returns it: LineCapFlat (0) unless the constructor was given one, and
LineCapTriangle (3) for an arrow cap.
| Parameter | Meaning |
|---|---|
baseCap |
LineCapFlat, LineCapSquare, LineCapRound or LineCapTriangle. |
Returns SetBaseCap: Ok on success, otherwise the error. GetBaseCap: the cap.
Example
dim v as CGpGraphicsPath
v.AddLine( -3, 0, 0, 3 )
dim cap as CGpCustomLineCap = CGpCustomLineCap( NULL, @v )
cap.SetBaseCap( LineCapTriangle )
print cap.GetBaseCap() ' 3Microsoft Learn: CustomLineCap::SetBaseCap
function SetBaseInset( byval inset as single ) as GpStatus
function GetBaseInset() as singleSetBaseInset sets how far, in pen widths, the line stops short of its end point to make room
for the cap. GetBaseInset returns it: 0 for a new custom cap; an arrow cap works out its own.
| Parameter | Meaning |
|---|---|
inset |
The distance. |
Returns SetBaseInset: Ok on success, otherwise the error. GetBaseInset: the inset.
Example
dim v as CGpGraphicsPath
v.AddLine( -3, 0, 0, 3 )
dim cap as CGpCustomLineCap = CGpCustomLineCap( NULL, @v )
cap.SetBaseInset( 1.5 )
print cap.GetBaseInset() ' 1.5Microsoft Learn: CustomLineCap::SetBaseInset
function SetWidthScale( byval widthScale as single ) as GpStatus
function GetWidthScale() as singleSetWidthScale scales the cap relative to the pen width: with 2 the cap is twice as big as its
path says. GetWidthScale returns it, 1 for a new cap.
| Parameter | Meaning |
|---|---|
widthScale |
The scale. |
Returns SetWidthScale: Ok on success, otherwise the error. GetWidthScale: the scale,
or 0 when the object holds no cap.
Example
dim arrow as CGpAdjustableArrowCap = CGpAdjustableArrowCap( 5, 4 )
arrow.SetWidthScale( 2 )
print arrow.GetWidthScale() ' 2Microsoft Learn: CustomLineCap::SetWidthScale
function Clone( byval pCustomLineCap as CGpCustomLineCap ptr ) as GpStatusCopies this cap into the existing object that pCustomLineCap points to, usually an empty
CGpCustomLineCap. The GDI+ cap the target held is deleted first.
| Parameter | Meaning |
|---|---|
pCustomLineCap |
The object that receives the copy. |
Returns Ok on success; InvalidParameter when the pointer is NULL.
Example
dim arrow as CGpAdjustableArrowCap = CGpAdjustableArrowCap( 5, 4 )
arrow.SetWidthScale( 2 )
dim copy as CGpCustomLineCap
if arrow.Clone( @copy ) = Ok then print copy.GetWidthScale() ' 2Microsoft Learn: CustomLineCap::Clone
An arrow head, derived from CGpCustomLineCap, whose tip is at the end of the line. Its height
and width are in pen widths, like every cap. The members of CGpCustomLineCap work on it too.
constructor( byval pAdjustableArrowCap as CGpAdjustableArrowCap ptr )
constructor( byval nHeight as single, byval nWidth as single, byval isFilled as BOOL = CTRUE )Creates an arrow head nHeight pen widths long and nWidth pen widths across, filled unless
isFilled is FALSE, with no notch; or an independent copy of another arrow cap, whose pointer
must not be NULL. There is no constructor without arguments.
| Parameter | Meaning |
|---|---|
pAdjustableArrowCap |
The arrow cap to copy. |
nHeight |
The distance from the base of the arrow head to its tip. |
nWidth |
The width of the base. |
isFilled |
CTRUE (the default) for a solid arrow head, FALSE for an outline. |
Example
dim arrow as CGpAdjustableArrowCap = CGpAdjustableArrowCap( 6, 4 )
dim pen as CGpPen = CGpPen( ARGB_BLACK, 2 )
pen.SetCustomEndCap( @arrow )
print arrow.GetHeight(); arrow.GetWidth(); " "; arrow.IsFilled() ' 6 4 trueMicrosoft Learn: AdjustableArrowCap::AdjustableArrowCap
function SetHeight( byval nHeight as single ) as GpStatus
function GetHeight() as singleSetHeight sets the distance from the base of the arrow head to its tip, in pen widths.
GetHeight returns it.
| Parameter | Meaning |
|---|---|
nHeight |
The new height. |
Returns SetHeight: Ok on success, otherwise the error. GetHeight: the height.
Example
dim arrow as CGpAdjustableArrowCap = CGpAdjustableArrowCap( 6, 4 )
arrow.SetHeight( 10 )
print arrow.GetHeight() ' 10Microsoft Learn: AdjustableArrowCap::SetHeight
function SetWidth( byval nWidth as single ) as GpStatus
function GetWidth() as singleSetWidth sets the width of the arrow head's base, from one corner to the other, in pen widths.
GetWidth returns it.
| Parameter | Meaning |
|---|---|
nWidth |
The new width. |
Returns SetWidth: Ok on success, otherwise the error. GetWidth: the width.
Example
dim arrow as CGpAdjustableArrowCap = CGpAdjustableArrowCap( 6, 4 )
arrow.SetWidth( 8 )
print arrow.GetWidth() ' 8Microsoft Learn: AdjustableArrowCap::SetWidth
function SetMiddleInset( byval middleInset as single ) as GpStatus
function GetMiddleInset() as singleSetMiddleInset moves the middle of the base towards the tip by middleInset pen widths, which
cuts a notch in the back of the arrow head. GetMiddleInset returns it, 0 for a new arrow cap.
| Parameter | Meaning |
|---|---|
middleInset |
The depth of the notch. |
Returns SetMiddleInset: Ok on success, otherwise the error. GetMiddleInset: the inset.
Example
dim arrow as CGpAdjustableArrowCap = CGpAdjustableArrowCap( 6, 4 )
arrow.SetMiddleInset( 2 )
print arrow.GetMiddleInset() ' 2Microsoft Learn: AdjustableArrowCap::SetMiddleInset
function SetFillState( byval isFilled as BOOL ) as GpStatus
function IsFilled() as booleanSetFillState makes the arrow head solid (CTRUE) or an outline drawn with the pen (FALSE).
IsFilled tells which.
| Parameter | Meaning |
|---|---|
isFilled |
CTRUE or FALSE. |
Returns SetFillState: Ok on success, otherwise the error. IsFilled: true for a solid
arrow head.
Example
dim arrow as CGpAdjustableArrowCap = CGpAdjustableArrowCap( 6, 4 )
arrow.SetFillState( FALSE )
print arrow.IsFilled() ' falseMicrosoft Learn: AdjustableArrowCap::SetFillState
-
CGpPen, whose
SetCustomStartCapandSetCustomEndCaptake a cap - CGpGraphicsPath for the shape of a custom cap
- sys/win/gdiplus
tiko-lang · Home · Feature Index · Keyword Index · License
FreeBASIC manual pages reproduced under the GNU FDL 1.3.
- Generics
- Interfaces
- For Each
- Iterators
- Tuples
- Array Results
- Defer
- Lambdas
- Block Strings
- Partial Types
- String Slices
- Embed
- Typed Variadics
- C Header Import
- Foreign Library Linking
- UString
- Fixed-Width Types
- Nullptr
- String Library
- Format
- Array
- Map
- Set
- LinkedList
- OrderedMap
- OrderedSet
- Sorting
- Optional
- Result
- Smart Pointers
- Date and Time (Chrono)
- Filesystem
- File Streams
- Config (INI and TOML)
- Codec
- Hash
- UUID
- OS
- Process
- Net
- HTTP and TLS
- Math Library
- Finance
- Logging
- Terminal TUI Library
- PsControls
- tkControls
- sys/win
- Goroutines and Channels
- LLVM Backend
- tiko build
- TIKO_COMPILER
- Variable Declarations
- Standard Data Types
- User Defined Types
- Procedures
- Operators
- Control Flow Statements
- Converting Data Types
- Array Functions
- String Functions
- Mathematical Functions
- Bit Manipulation
- Date and Time Functions
- File I/O Functions
- Console Functions
- User Input (Runtime Library)
- User Input Functions (Graphics Library)
- Screen Functions
- 2D Drawing Functions
- Graphics Library Reference
- Graphics Keyword List
- Memory Functions
- Threading Support Functions
- Error Handling Functions
- Operating System Functions
- Preprocessor
- Intrinsic Defines
- Miscellaneous Keywords
- Modularizing