Skip to content

Commit e2449eb

Browse files
committed
win32: Implement TextArea
closes #25
1 parent 2c8b29d commit e2449eb

File tree

1 file changed

+91
-8
lines changed

1 file changed

+91
-8
lines changed

src/backends/win32/backend.zig

Lines changed: 91 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ var hInst: HINSTANCE = undefined;
5555
/// anti-aliasing. So we take the real default caption font from
5656
/// NONFCLIENTEMETRICS and apply it manually to every widget.
5757
var captionFont: win32.HFONT = undefined;
58+
var monospaceFont: win32.HFONT = undefined;
5859
/// Default arrow cursor used to avoid components keeping the last cursor icon
5960
/// that's been set (which is usually the resize cursor or loading cursor)
6061
var defaultCursor: win32.HCURSOR = undefined;
@@ -101,6 +102,23 @@ pub fn init() !void {
101102
win32.SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS.initFlags(.{}),
102103
);
103104
captionFont = win32.CreateFontIndirectW(&ncMetrics.lfCaptionFont).?;
105+
monospaceFont = @ptrCast(win32.GetStockObject(win32.ANSI_FIXED_FONT));
106+
monospaceFont = win32.CreateFontW(
107+
ncMetrics.lfCaptionFont.lfHeight,
108+
ncMetrics.lfCaptionFont.lfWidth,
109+
0,
110+
0,
111+
win32.FW_REGULAR,
112+
0,
113+
0,
114+
0,
115+
win32.DEFAULT_CHARSET,
116+
win32.OUT_DEFAULT_PRECIS,
117+
win32.CLIP_DEFAULT_PRECIS,
118+
win32.DEFAULT_QUALITY,
119+
.MODERN,
120+
_T("Courier"),
121+
).?;
104122

105123
// Load the default arrow cursor so that components can use it
106124
// This avoids components keeping the last cursor (resize cursor or loading cursor)
@@ -834,6 +852,68 @@ pub const TextField = struct {
834852
}
835853
};
836854

855+
pub const TextArea = struct {
856+
peer: HWND,
857+
arena: std.heap.ArenaAllocator,
858+
859+
pub usingnamespace Events(TextArea);
860+
861+
pub fn create() !TextArea {
862+
const hwnd = win32.CreateWindowExW(win32.WS_EX_LEFT, // dwExtStyle
863+
_T("EDIT"), // lpClassName
864+
_T(""), // lpWindowName
865+
@as(win32.WINDOW_STYLE, @enumFromInt(@intFromEnum(win32.WS_TABSTOP) | @intFromEnum(win32.WS_CHILD) | @intFromEnum(win32.WS_BORDER) | win32.ES_MULTILINE | win32.ES_AUTOVSCROLL | win32.ES_WANTRETURN)), // dwStyle
866+
0, // X
867+
0, // Y
868+
100, // nWidth
869+
100, // nHeight
870+
defaultWHWND, // hWindParent
871+
null, // hMenu
872+
hInst, // hInstance
873+
null // lpParam
874+
) orelse return Win32Error.InitializationError;
875+
try TextArea.setupEvents(hwnd);
876+
_ = win32.SendMessageW(hwnd, win32.WM_SETFONT, @intFromPtr(captionFont), 1);
877+
878+
return TextArea{ .peer = hwnd, .arena = std.heap.ArenaAllocator.init(lib.internal.lasting_allocator) };
879+
}
880+
881+
pub fn setText(self: *TextArea, text: []const u8) void {
882+
const allocator = lib.internal.scratch_allocator;
883+
const wide = std.unicode.utf8ToUtf16LeWithNull(allocator, text) catch return; // invalid utf8 or not enough memory
884+
defer allocator.free(wide);
885+
if (win32.SetWindowTextW(self.peer, wide) == 0) {
886+
std.os.windows.unexpectedError(transWinError(win32.GetLastError())) catch {};
887+
}
888+
889+
const len = win32.GetWindowTextLengthW(self.peer);
890+
getEventUserData(self.peer).last_text_len = len;
891+
}
892+
893+
pub fn getText(self: *TextArea) [:0]const u8 {
894+
const allocator = self.arena.allocator();
895+
const len = win32.GetWindowTextLengthW(self.peer);
896+
var buf = allocator.allocSentinel(u16, @as(usize, @intCast(len)), 0) catch unreachable; // TODO return error
897+
defer allocator.free(buf);
898+
const realLen = @as(usize, @intCast(win32.GetWindowTextW(self.peer, buf.ptr, len + 1)));
899+
const utf16Slice = buf[0..realLen];
900+
const text = std.unicode.utf16leToUtf8AllocZ(allocator, utf16Slice) catch unreachable; // TODO return error
901+
return text;
902+
}
903+
904+
pub fn setReadOnly(self: *TextArea, readOnly: bool) void {
905+
_ = win32.SendMessageW(self.peer, win32.EM_SETREADONLY, @intFromBool(readOnly), undefined);
906+
}
907+
908+
pub fn setMonospaced(self: *TextArea, monospaced: bool) void {
909+
if (monospaced) {
910+
_ = win32.SendMessageW(self.peer, win32.WM_SETFONT, @intFromPtr(monospaceFont), 1);
911+
} else {
912+
_ = win32.SendMessageW(self.peer, win32.WM_SETFONT, @intFromPtr(captionFont), 1);
913+
}
914+
}
915+
};
916+
837917
pub const Button = struct {
838918
peer: HWND,
839919
arena: std.heap.ArenaAllocator,
@@ -892,10 +972,10 @@ pub const CheckBox = struct {
892972
pub usingnamespace Events(CheckBox);
893973

894974
pub fn create() !CheckBox {
895-
const hwnd = win32.CreateWindowEx(win32.WS_EX_LEFT, // dwExtStyle
896-
"BUTTON", // lpClassName
897-
"", // lpWindowName
898-
win32.WS_TABSTOP | win32.WS_CHILD | win32.BS_AUTOCHECKBOX, // dwStyle
975+
const hwnd = win32.CreateWindowExW(win32.WS_EX_LEFT, // dwExtStyle
976+
_T("BUTTON"), // lpClassName
977+
_T(""), // lpWindowName
978+
@as(win32.WINDOW_STYLE, @enumFromInt(@intFromEnum(win32.WS_TABSTOP) | @intFromEnum(win32.WS_CHILD) | win32.BS_AUTOCHECKBOX)), // dwStyle
899979
0, // X
900980
0, // Y
901981
100, // nWidth
@@ -904,7 +984,7 @@ pub const CheckBox = struct {
904984
null, // hMenu
905985
hInst, // hInstance
906986
null // lpParam
907-
);
987+
) orelse return Win32Error.InitializationError;
908988
try CheckBox.setupEvents(hwnd);
909989
_ = win32.SendMessageW(hwnd, win32.WM_SETFONT, @intFromPtr(captionFont), 1);
910990

@@ -926,14 +1006,17 @@ pub const CheckBox = struct {
9261006

9271007
pub fn setChecked(self: *CheckBox, checked: bool) void {
9281008
const state: win32.WPARAM = switch (checked) {
929-
true => win32.BST_CHECKED,
930-
false => win32.BST_UNCHECKED,
1009+
true => @intFromEnum(win32.BST_CHECKED),
1010+
false => @intFromEnum(win32.BST_UNCHECKED),
9311011
};
9321012
_ = win32.SendMessageW(self.peer, win32.BM_SETCHECK, state, 0);
9331013
}
9341014

9351015
pub fn isChecked(self: *CheckBox) bool {
936-
return win32.SendMessageW(self.peer, win32.BM_GETCHECK, 0, 0) != win32.BST_UNCHECKED;
1016+
const state: win32.DLG_BUTTON_CHECK_STATE = @enumFromInt(
1017+
win32.SendMessageW(self.peer, win32.BM_GETCHECK, 0, 0),
1018+
);
1019+
return state != win32.BST_UNCHECKED;
9371020
}
9381021
};
9391022

0 commit comments

Comments
 (0)