Skip to content

Instantly share code, notes, and snippets.

@G33kDude G33kDude/GDI.ahk
Last active Aug 11, 2019

Embed
What would you like to do?
GDI wrapper for AutoHotkey
class GDI
{
__New(hWnd, CliWidth=0, CliHeight=0)
{
if !(CliWidth && CliHeight)
{
VarSetCapacity(Rect, 16, 0)
DllCall("GetClientRect", "Ptr", hWnd, "Ptr", &Rect)
CliWidth := NumGet(Rect, 8, "Int")
CliHeight := NumGet(Rect, 12, "Int")
}
this.CliWidth := CliWidth
this.CliHeight := CliHeight
this.hWnd := hWnd
this.hDC := DllCall("GetDC", "UPtr", hWnd, "UPtr")
this.hMemDC := DllCall("CreateCompatibleDC", "UPtr", this.hDC, "UPtr")
this.hBitmap := DllCall("CreateCompatibleBitmap", "UPtr", this.hDC, "Int", CliWidth, "Int", CliHeight, "UPtr")
this.hOriginalBitmap := DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", this.hBitmap)
}
__Delete()
{
DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", this.hOriginalBitmap)
DllCall("DeleteObject", "UPtr", this.hBitmap)
DllCall("DeleteObject", "UPtr", this.hMemDC)
DllCall("ReleaseDC", "UPtr", this.hWnd, "UPtr", this.hDC)
}
BitBlt(x=0, y=0, w=0, h=0)
{
w := w ? w : this.CliWidth
h := h ? h : this.CliHeight
DllCall("BitBlt", "UPtr", this.hDC, "Int", x, "Int", y
, "Int", w, "Int", h, "UPtr", this.hMemDC, "Int", 0, "Int", 0, "UInt", 0xCC0020) ;SRCCOPY
}
DrawLine(x, y, x2, y2, Color)
{
Pen := new GDI.Pen(Color)
DllCall("MoveToEx", "UPtr", this.hMemDC, "Int", this.TranslateX(x), "Int", this.TranslateY(y), "UPtr", 0)
hOriginalPen := DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", Pen.Handle, "UPtr")
DllCall("LineTo", "UPtr", this.hMemDC, "Int", this.TranslateX(x2), "Int", this.TranslateY(y2))
DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", hOriginalPen, "UPtr")
}
SetPixel(x, y, Color, Fast=False)
{
x := this.TranslateX(x)
y := this.TranslateY(y, this.Invert) ; Move up 1 px if inverted (drawing "up" instead of down)
DllCall("SetPixel" (Fast?"V":""), "UPtr", this.hMemDC, "Int", x, "Int", y, "UInt", Color)
}
DrawText(x, y, w, h, Text, Color, Typeface, TextHeight, Align="LT", Weight=500, Style=0)
{
AlignH := {"L": 0x00, "C": 0x01, "R": 0x02}
AlignV := {"C": 0x24, "B": 0x28, "T": 0x00}
Align := StrSplit(Align)
Font := new GDI.Font(Typeface, TextHeight, Weight, Style)
; Transparent background, no color needed
DllCall("SetBkMode", "UPtr", this.hMemDC, "Int", 1)
;DllCall("SetBkColor", "UPtr", this.hMemDC, "UInt", 0xFFFFFF)
DllCall("SetTextColor", "UPtr", this.hMemDC, "UInt", Color)
hOriginalFont := DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", Font.Handle, "UPtr")
x1 := this.TranslateX(x)
y1 := this.TranslateY(y)
x2 := this.TranslateX(x+w)
y2 := this.TranslateY(y+h)
if (y1 > y2) ; Fix the coordinates when inverted
tmp := y1, y1 := y2, y2 := tmp
; TODO: abstract RECTs
VarSetCapacity(Rect, 16, 0)
NumPut(x1, Rect, 0, "Int"), NumPut(y1, Rect, 4, "Int")
NumPut(x2, Rect, 8, "Int"), NumPut(y2, Rect, 12, "Int")
DllCall("DrawText", "UPtr", this.hMemDC, "Str", Text, "Int", -1, "UPtr", &Rect, "UInt", AlignH[Align[1]] | AlignV[Align[2]])
DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", hOriginalFont, "UPtr")
}
FillRectangle(x, y, w, h, Color, BorderColor=-1)
{
if (w == 1 && h == 1)
return this.SetPixel(x, y, Color)
Pen := new this.Pen(BorderColor < 0 ? Color : BorderColor)
Brush := new this.Brush(Color)
; Replace the original pen and brush with our own
hOriginalPen := DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", Pen.Handle, "UPtr")
hOriginalBrush := DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", Brush.Handle, "UPtr")
x1 := this.TranslateX(x)
x2 := this.TranslateX(x+w)
y1 := this.TranslateY(y)
y2 := this.TranslateY(y+h)
DllCall("Rectangle", "UPtr", this.hMemDC
, "Int", x1, "Int", y1
, "Int", x2, "Int", y2)
; Reselect the original pen and brush
DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", hOriginalPen, "UPtr")
DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", hOriginalBrush, "UPtr")
}
FillEllipse(x, y, w, h, Color, BorderColor=-1)
{
Pen := new this.Pen(BorderColor < 0 ? Color : BorderColor)
Brush := new this.Brush(Color)
; Replace the original pen and brush with our own
hOriginalPen := DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", Pen.Handle, "UPtr")
hOriginalBrush := DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", Brush.Handle, "UPtr")
x1 := this.TranslateX(x)
x2 := this.TranslateX(x+w)
y1 := this.TranslateY(y)
y2 := this.TranslateY(y+h)
DllCall("Ellipse", "UPtr", this.hMemDC
, "Int", x1, "Int", y1
, "Int", x2, "Int", y2)
; Reselect the original pen and brush
DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", hOriginalPen, "UPtr")
DllCall("SelectObject", "UPtr", this.hMemDC, "UPtr", hOriginalBrush, "UPtr")
}
TranslateX(X)
{
return Floor(X)
}
TranslateY(Y, Offset=0)
{
if this.Invert
return this.CliHeight - Floor(Y) - Offset
return Floor(Y)
}
class Pen
{
__New(Color, Width=1, Style=0)
{
this.Handle := DllCall("CreatePen", "Int", Style, "Int", Width, "UInt", Color, "UPtr")
}
__Delete()
{
DllCall("DeleteObject", "UPtr", this.Handle)
}
}
class Brush
{
__New(Color)
{
this.Handle := DllCall("CreateSolidBrush", "UInt", Color, "UPtr")
}
__Delete()
{
DllCall("DeleteObject", "UPtr", this.Handle)
}
}
class Font
{
__New(Typeface, Height, Weight, Style)
{
this.Handle := DllCall("CreateFont"
, "Int", Height ;height
, "Int", 0 ;width
, "Int", 0 ;angle of string (0.1 degrees)
, "Int", 0 ;angle of each character (0.1 degrees)
, "Int", Weight ;font weight
, "UInt", Style&1 ;font italic
, "UInt", Style&2 ;font underline
, "UInt", Style&4 ;font strikeout
, "UInt", 1 ;DEFAULT_CHARSET: character set
, "UInt", 0 ;OUT_DEFAULT_PRECIS: output precision
, "UInt", 0 ;CLIP_DEFAULT_PRECIS: clipping precision
, "UInt", 0 ;DEFAULT_QUALITY: output quality
, "UInt", 0 ;DEFAULT_PITCH | (FF_DONTCARE << 16): font pitch and family
, "Str", Typeface ;typeface name
, "UPtr")
}
__Delete()
{
DllCall("DeleteObject", "UPtr", this.Handle)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.