Skip to content

Commit c79615a

Browse files
committed
improve ui and getting caret pos
1 parent 545b920 commit c79615a

File tree

5 files changed

+91
-31
lines changed

5 files changed

+91
-31
lines changed

src/core/config.zig

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ pub const UI = struct {
33
/// Font height for suggestion window
44
pub const SUGGESTION_FONT_HEIGHT = 16;
55
/// Window padding
6-
pub const WINDOW_PADDING = 2;
6+
pub const WINDOW_PADDING = 4;
77
/// Background color (white)
8-
pub const BG_COLOR = 0x00FFFFFF;
8+
pub const BG_COLOR = 0x00FAFAFA;
99
/// Selected item background color (light blue)
10-
pub const SELECTED_BG_COLOR = 0x00B3D9FF;
10+
pub const SELECTED_BG_COLOR = 0x002B5DFC;
1111
/// Text color (black)
12-
pub const TEXT_COLOR = 0x00000000;
12+
pub const TEXT_COLOR = 0x00303030;
13+
/// Selected item text color (white)
14+
pub const SELECTED_TEXT_COLOR = 0x00FFFFFF;
1315
};
1416

1517
/// Text handling configuration

src/ui/position.zig

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,48 @@ const debug = sysinput.core.debug;
88
pub fn getCaretPosition() api.POINT {
99
var pt = api.POINT{ .x = 0, .y = 0 };
1010

11-
// Try getting actual caret position
11+
// First try using GUI thread info which is more reliable
1212
const focus_hwnd = api.getFocus();
1313
if (focus_hwnd != null) {
14-
// First try to get caret position directly
14+
// Get thread ID for the window
15+
const thread_id = api.getWindowThreadProcessId(focus_hwnd.?, null);
16+
17+
// Initialize GUITHREADINFO structure
18+
var gui_info = api.GUITHREADINFO{
19+
.cbSize = @sizeOf(api.GUITHREADINFO),
20+
.flags = 0,
21+
.hwndActive = null,
22+
.hwndFocus = null,
23+
.hwndCapture = null,
24+
.hwndMenuOwner = null,
25+
.hwndMoveSize = null,
26+
.hwndCaret = null,
27+
.rcCaret = api.RECT{ .left = 0, .top = 0, .right = 0, .bottom = 0 },
28+
};
29+
30+
// Try to get GUI thread info
31+
if (api.getGUIThreadInfo(thread_id, &gui_info) != 0) {
32+
if (gui_info.hwndCaret != null) {
33+
// Use caret rectangle from GUI thread info
34+
pt.x = gui_info.rcCaret.left;
35+
pt.y = gui_info.rcCaret.bottom; // Use bottom for better positioning
36+
37+
// Convert to screen coordinates - properly handle the optional
38+
_ = api.clientToScreen(gui_info.hwndCaret.?, &pt);
39+
debug.debugPrint("Got caret position from GUITHREADINFO: {d},{d}\n", .{ pt.x, pt.y });
40+
return applyPositionOffset(pt);
41+
}
42+
}
43+
44+
// If GUI thread info failed, try direct caret position
1545
if (api.getCaretPos(&pt) != 0) {
1646
// Convert from client to screen coordinates
1747
_ = api.clientToScreen(focus_hwnd.?, &pt);
1848
debug.debugPrint("Got caret position directly: {d},{d}\n", .{ pt.x, pt.y });
19-
20-
// Add slight offset below caret
21-
pt.y += 20;
22-
return pt;
49+
return applyPositionOffset(pt);
2350
}
2451

25-
// If that fails, try getting position from selection
52+
// Try using EM_POSFROMCHAR as a fallback for Edit controls
2653
const selection = api.sendMessage(focus_hwnd.?, api.EM_GETSEL, 0, 0);
2754
const sel_u64: u64 = @bitCast(selection);
2855
const sel_end: u32 = @truncate((sel_u64 >> 16) & 0xFFFF);
@@ -35,20 +62,23 @@ pub fn getCaretPosition() api.POINT {
3562
pt.y = @intCast((char_pos >> 16) & 0xFFFF);
3663
_ = api.clientToScreen(focus_hwnd.?, &pt);
3764
debug.debugPrint("Got caret position from selection: {d},{d}\n", .{ pt.x, pt.y });
38-
39-
// Add slight offset below caret
40-
pt.y += 20;
41-
return pt;
65+
return applyPositionOffset(pt);
4266
}
4367
}
4468

4569
// Fall back to cursor position if everything else fails
4670
_ = api.getCursorPos(&pt);
4771
debug.debugPrint("Falling back to cursor position: {d},{d}\n", .{ pt.x, pt.y });
72+
return applyPositionOffset(pt);
73+
}
74+
75+
fn applyPositionOffset(pt: api.POINT) api.POINT {
76+
var result = pt;
77+
78+
// Simple fixed offset
79+
result.y += 20;
4880

49-
// Add offset to position suggestions below cursor
50-
pt.y += 20;
51-
return pt;
81+
return result;
5282
}
5383

5484
/// Calculate suggestion window size based on suggestions

src/ui/suggestion_ui.zig

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,9 @@ pub const AutocompleteUI = struct {
107107
// Add DPI-aware padding below the caret
108108
suggested_pos.y += @intFromFloat(@as(f32, 20.0 * dpi));
109109

110-
// Calculate window size based on suggestions
111-
const size = position.calculateSuggestionWindowSize(self.suggestions, config.UI.SUGGESTION_FONT_HEIGHT, window.WINDOW_PADDING);
110+
// Calculate window size based on suggestions - use constants directly from the file
111+
const size = position.calculateSuggestionWindowSize(self.suggestions, config.UI.SUGGESTION_FONT_HEIGHT, // Use the fully qualified path
112+
sysinput.ui.window.WINDOW_PADDING);
112113

113114
// Adjust for screen boundaries
114115
const screen_width = api.GetSystemMetrics(api.SM_CXSCREEN);
@@ -131,9 +132,9 @@ pub const AutocompleteUI = struct {
131132

132133
const new_window = api.CreateWindowExA(
133134
api.WS_EX_TOPMOST | api.WS_EX_TOOLWINDOW | api.WS_EX_NOACTIVATE,
134-
window.SUGGESTION_WINDOW_CLASS,
135+
sysinput.ui.window.SUGGESTION_WINDOW_CLASS,
135136
"Suggestions\x00",
136-
api.WS_POPUP | api.WS_BORDER,
137+
api.WS_POPUP | api.WS_BORDER, // Keep border for now to avoid layout issues
137138
suggested_pos.x,
138139
suggested_pos.y,
139140
size.width,
@@ -163,7 +164,7 @@ pub const AutocompleteUI = struct {
163164
);
164165
}
165166

166-
// Show the window
167+
// Simple show without animation for now
167168
_ = api.ShowWindow(self.suggestion_window.?, api.SW_SHOWNOACTIVATE);
168169
_ = api.UpdateWindow(self.suggestion_window.?);
169170
}

src/ui/window.zig

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub fn suggestionWindowProc(
3636
api.WM_CREATE => {
3737
debug.debugPrint("Suggestion window created\n", .{});
3838

39-
// Create a font for the suggestions
39+
// Create a font for the suggestions - using Segoe UI for modern look
4040
g_ui_state.font = api.CreateFontA(
4141
config.UI.SUGGESTION_FONT_HEIGHT, // height
4242
0, // width (0 = auto)
@@ -49,7 +49,7 @@ pub fn suggestionWindowProc(
4949
api.ANSI_CHARSET, // charset
5050
api.OUT_DEFAULT_PRECIS, // output precision
5151
api.CLIP_DEFAULT_PRECIS, // clipping precision
52-
api.DEFAULT_QUALITY, // quality
52+
api.CLEARTYPE_QUALITY, // quality - use ClearType for crisp text
5353
api.DEFAULT_PITCH | api.FF_DONTCARE, // pitch and family
5454
"Segoe UI\x00", // face name (null-terminated)
5555
);
@@ -78,13 +78,14 @@ pub fn suggestionWindowProc(
7878
_ = api.SelectObject(hdc, font);
7979
}
8080

81-
// Clear background
81+
// Set text settings for better appearance
8282
_ = api.SetBkMode(hdc, api.TRANSPARENT);
83+
_ = api.SetTextColor(hdc, config.UI.TEXT_COLOR);
8384

8485
// Draw each suggestion
8586
var i: usize = 0;
8687
var y: i32 = WINDOW_PADDING;
87-
const line_height = config.UI.SUGGESTION_FONT_HEIGHT + 4; // Add some padding
88+
const line_height = config.UI.SUGGESTION_FONT_HEIGHT + 8; // More padding
8889

8990
while (i < g_ui_state.suggestions.len) : (i += 1) {
9091
const is_selected = g_ui_state.selected_index == @as(i32, @intCast(i));
@@ -98,23 +99,27 @@ pub fn suggestionWindowProc(
9899
.bottom = y + line_height,
99100
};
100101

101-
// Draw background for selection
102+
// Draw background for selection (simplified to avoid errors)
102103
if (is_selected) {
103104
const brush = api.CreateSolidBrush(config.UI.SELECTED_BG_COLOR);
104105
if (brush != null) {
105106
defer _ = api.DeleteObject(brush.?);
106107
_ = api.FillRect(hdc, &rect, brush.?);
108+
109+
// Use white text for selected item with a constant
110+
_ = api.SetTextColor(hdc, 0x00FFFFFF); // White
107111
}
112+
} else {
113+
_ = api.SetTextColor(hdc, config.UI.TEXT_COLOR);
108114
}
109115

110116
// Draw suggestion text
111-
_ = api.SetTextColor(hdc, config.UI.TEXT_COLOR);
112-
113-
// Convert to wchar if needed or use multibyte version
114117
var buffer: [config.TEXT.MAX_SUGGESTION_LEN:0]u8 = undefined;
115118
std.mem.copyForwards(u8, &buffer, suggestion);
116119
buffer[suggestion.len] = 0; // Null terminate
117120

121+
// Add padding for text
122+
rect.left += 8;
118123
_ = api.DrawTextA(hdc, &buffer, @intCast(suggestion.len), &rect, api.DT_LEFT | api.DT_SINGLELINE | api.DT_VCENTER);
119124

120125
y += line_height;

src/win32/api.zig

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ pub const DT_SINGLELINE = 0x00000020;
135135
pub const DT_VCENTER = 0x00000004;
136136
pub const TRANSPARENT = 1;
137137

138+
// Drawing constants
139+
pub const NULL_PEN = 8;
140+
pub const CLEARTYPE_QUALITY = 5;
141+
pub const BYTE = u8;
142+
138143
// Font constants
139144
pub const FW_NORMAL = 400;
140145
pub const ANSI_CHARSET = 0;
@@ -384,6 +389,23 @@ pub extern "user32" fn GetFocus() callconv(.C) ?HWND;
384389
pub extern "user32" fn SendMessageA(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) callconv(.C) LRESULT;
385390
pub extern "user32" fn PostMessageA(hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) callconv(.C) BOOL;
386391

392+
pub extern "user32" fn SetLayeredWindowAttributes(
393+
hwnd: HWND,
394+
crKey: COLORREF,
395+
bAlpha: BYTE,
396+
dwFlags: DWORD,
397+
) callconv(.C) BOOL;
398+
399+
pub extern "gdi32" fn RoundRect(
400+
hdc: HDC,
401+
left: c_int,
402+
top: c_int,
403+
right: c_int,
404+
bottom: c_int,
405+
width: c_int,
406+
height: c_int,
407+
) callconv(.C) BOOL;
408+
387409
//=============================================================================
388410
// INPUT AND CURSOR FUNCTIONS
389411
//=============================================================================

0 commit comments

Comments
 (0)