#include "osedit_win.inl"
#include "osgui_win.inl"
#include "oscontrol_win.inl"
#include "ospanel_win.inl"
#include "oswindow_win.inl"
#include "../osedit.h"
#include "../osedit.inl"
#include "../osgui.inl"
#include <draw2d/font.h>
#include <core/event.h>
#include <core/heap.h>
#include <core/strings.h>
#include <sewer/cassert.h>
#include <sewer/ptr.h>
#include <sewer/unicode.h>
#if !defined(__WINDOWS__)
#error This file is only for Windows
#endif
struct _osedit_t
{
OSControl control;
uint32_t flags;
Font *font;
bool_t launch_event;
bool_t focused;
COLORREF color;
COLORREF bgcolor;
HBRUSH bgbrush;
RECT border;
uint32_t vpadding;
real32_t rpadding;
INT wpadding;
Listener *OnFilter;
Listener *OnChange;
Listener *OnFocus;
UINT_PTR timer;
};
static LRESULT CALLBACK i_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
OSEdit *edit = cast(GetWindowLongPtr(hwnd, GWLP_USERDATA), OSEdit);
LRESULT res;
cassert_no_null(edit);
switch (uMsg)
{
case WM_ERASEBKGND:
return 1;
case WM_NCCALCSIZE:
return _osgui_nccalcsize(hwnd, wParam, lParam, TRUE, edit->wpadding, &edit->border);
case WM_NCPAINT:
return _osgui_ncpaint(hwnd, edit->focused, &edit->border, edit->bgbrush);
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
if (_oswindow_mouse_down(cast(edit, OSControl)) == TRUE)
break;
return 0;
}
res = CallWindowProc(edit->control.def_wnd_proc, hwnd, uMsg, wParam, lParam);
if (uMsg == WM_LBUTTONDOWN)
{
if (BIT_TEST(edit->flags, ekEDIT_AUTOSEL) == TRUE)
SendMessage(hwnd, EM_SETSEL, 0, -1);
}
return res;
}
static DWORD i_flags(const edit_flag_t flags)
{
if (edit_get_type(flags) == ekEDIT_MULTI)
return ES_MULTILINE | ES_AUTOVSCROLL;
else
return ES_AUTOHSCROLL;
}
static void i_update_vpadding(OSEdit *edit)
{
real32_t width, height;
uint32_t defpadding = 0;
cassert_no_null(edit);
font_extents(edit->font, "O", -1.f, &width, &height);
defpadding = (uint32_t)((.3f * height) + .5f);
if (defpadding % 2 == 1)
defpadding += 1;
if (defpadding < 5)
defpadding = 5;
if (edit->vpadding == UINT32_MAX)
{
edit->rpadding = (real32_t)defpadding;
edit->wpadding = 0;
}
else
{
real32_t leading = font_leading(edit->font);
uint32_t padding = (uint32_t)(edit->vpadding + leading);
if (padding % 2 == 1)
padding += 1;
if (padding < 4)
padding = 4;
if (padding > defpadding)
edit->wpadding = (padding - defpadding) / 2;
else
edit->wpadding = 0;
edit->rpadding = (real32_t)padding;
}
}
OSEdit *osedit_create(const uint32_t flags)
{
OSEdit *edit = heap_new0(OSEdit);
DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | _oscontrol_halign(ekLEFT) | i_flags(flags);
edit->control.type = ekGUI_TYPE_EDITBOX;
edit->flags = flags;
_oscontrol_init(cast(edit, OSControl), PARAM(dwExStyle, WS_EX_NOPARENTNOTIFY ), dwStyle, L"edit", 0, 0, i_WndProc, kDEFAULT_PARENT_WINDOW);
edit->font = _osgui_create_default_font();
edit->launch_event = TRUE;
edit->focused = FALSE;
edit->vpadding = UINT32_MAX;
edit->timer = 0;
i_update_vpadding(edit);
_oscontrol_set_font(cast(edit, OSControl), edit->font);
return edit;
}
void osedit_destroy(OSEdit **edit)
{
cassert_no_null(edit);
cassert_no_null(*edit);
font_destroy(&(*edit)->font);
listener_destroy(&(*edit)->OnFilter);
listener_destroy(&(*edit)->OnChange);
listener_destroy(&(*edit)->OnFocus);
_oscontrol_destroy_brush(&(*edit)->bgbrush);
_oscontrol_destroy(&(*edit)->control);
heap_delete(edit, OSEdit);
}
void osedit_OnFilter(OSEdit *edit, Listener *listener)
{
cassert_no_null(edit);
listener_update(&edit->OnFilter, listener);
}
void osedit_OnChange(OSEdit *edit, Listener *listener)
{
cassert_no_null(edit);
listener_update(&edit->OnChange, listener);
}
void osedit_OnFocus(OSEdit *edit, Listener *listener)
{
cassert_no_null(edit);
listener_update(&edit->OnFocus, listener);
}
void osedit_text(OSEdit *edit, const char_t *text)
{
cassert_no_null(edit);
edit->launch_event = FALSE;
_oscontrol_set_text(cast(edit, OSControl), text);
edit->launch_event = TRUE;
}
void osedit_font(OSEdit *edit, const Font *font)
{
cassert_no_null(edit);
_oscontrol_update_font(cast(edit, OSControl), &edit->font, font);
i_update_vpadding(edit);
}
void osedit_tooltip(OSEdit *edit, const char_t *text)
{
_oscontrol_set_tooltip(cast(edit, OSControl), text);
}
void osedit_align(OSEdit *edit, const align_t align)
{
DWORD dwStyle = 0;
cassert_no_null(edit);
dwStyle = (DWORD)GetWindowLongPtr(edit->control.hwnd, GWL_STYLE);
dwStyle &= ~SS_LEFT;
dwStyle &= ~SS_CENTER;
dwStyle &= ~SS_RIGHT;
dwStyle |= _oscontrol_halign(align);
SetWindowLongPtr(edit->control.hwnd, GWL_STYLE, dwStyle);
}
void osedit_passmode(OSEdit *edit, const bool_t passmode)
{
cassert_no_null(edit);
if (passmode == TRUE)
{
wchar_t pchar = L'\x2022';
SendMessage(edit->control.hwnd, EM_SETPASSWORDCHAR, (WPARAM)pchar, (LPARAM)0);
}
else
{
SendMessage(edit->control.hwnd, EM_SETPASSWORDCHAR, (WPARAM)0, (LPARAM)0);
}
}
void osedit_editable(OSEdit *edit, const bool_t is_editable)
{
LRESULT res = 0;
cassert_no_null(edit);
res = SendMessage(edit->control.hwnd, EM_SETREADONLY, (WPARAM)!is_editable, (LPARAM)0);
cassert_unref(res != 0, res);
}
void osedit_autoselect(OSEdit *edit, const bool_t autoselect)
{
cassert_no_null(edit);
if (autoselect == TRUE)
BIT_SET(edit->flags, ekEDIT_AUTOSEL);
else
BIT_CLEAR(edit->flags, ekEDIT_AUTOSEL);
}
void osedit_select(OSEdit *edit, const int32_t start, const int32_t end)
{
int32_t platform_st, platform_ed;
cassert_no_null(edit);
_osgui_select_text(start, end, &platform_st, &platform_ed);
SendMessage(edit->control.hwnd, EM_SETSEL, (WPARAM)platform_st, (LPARAM)platform_ed);
}
void osedit_color(OSEdit *edit, const color_t color)
{
cassert_no_null(edit);
edit->color = _oscontrol_colorref(color);
}
void osedit_bgcolor(OSEdit *edit, const color_t color)
{
cassert_no_null(edit);
_oscontrol_update_brush(color, &edit->bgbrush, &edit->bgcolor);
}
void osedit_vpadding(OSEdit *edit, const real32_t padding)
{
cassert_no_null(edit);
cassert(padding >= 0);
edit->vpadding = (padding < 0) ? UINT32_MAX : (uint32_t)padding;
i_update_vpadding(edit);
}
void osedit_bounds(const OSEdit *edit, const real32_t refwidth, const uint32_t lines, real32_t *width, real32_t *height)
{
cassert_no_null(edit);
cassert_no_null(width);
cassert_no_null(height);
cassert_unref(lines == 1, lines);
if (edit_get_type(edit->flags) == ekEDIT_SINGLE)
font_extents(edit->font, "O", -1.f, width, height);
else
font_extents(edit->font, "O\nO", -1.f, width, height);
*width = refwidth;
*height += edit->rpadding;
}
void osedit_clipboard(OSEdit *edit, const clipboard_t clipboard)
{
cassert_no_null(edit);
switch (clipboard)
{
case ekCLIPBOARD_COPY:
SendMessage(edit->control.hwnd, WM_COPY, (WPARAM)0, (LPARAM)0);
break;
case ekCLIPBOARD_PASTE:
SendMessage(edit->control.hwnd, WM_PASTE, (WPARAM)0, (LPARAM)0);
break;
case ekCLIPBOARD_CUT:
SendMessage(edit->control.hwnd, WM_CUT, (WPARAM)0, (LPARAM)0);
break;
cassert_default();
}
}
void osedit_attach(OSEdit *edit, OSPanel *panel)
{
_ospanel_attach_control(panel, cast(edit, OSControl));
}
void osedit_detach(OSEdit *edit, OSPanel *panel)
{
_ospanel_detach_control(panel, cast(edit, OSControl));
}
void osedit_visible(OSEdit *edit, const bool_t visible)
{
_oscontrol_set_visible(cast(edit, OSControl), visible);
}
void osedit_enabled(OSEdit *edit, const bool_t enabled)
{
_oscontrol_set_enabled(cast(edit, OSControl), enabled);
}
void osedit_size(const OSEdit *edit, real32_t *width, real32_t *height)
{
_oscontrol_get_size(cast_const(edit, OSControl), width, height);
}
void osedit_origin(const OSEdit *edit, real32_t *x, real32_t *y)
{
_oscontrol_get_origin(cast_const(edit, OSControl), x, y);
}
void osedit_frame(OSEdit *edit, const real32_t x, const real32_t y, const real32_t width, const real32_t height)
{
_oscontrol_set_frame(cast(edit, OSControl), x, y, width, height);
}
static uint32_t i_get_cursor_pos(HWND hwnd)
{
DWORD start;
SendMessage(hwnd, EM_GETSEL, (WPARAM)&start, (LPARAM)NULL);
return (uint32_t)start;
}
static void i_set_cursor_pos(HWND hwnd, const uint32_t pos)
{
SendMessage(hwnd, EM_SETSEL, (WPARAM)pos, (LPARAM)pos);
}
void _osedit_command(OSEdit *edit, WPARAM wParam)
{
cassert_no_null(edit);
if (HIWORD(wParam) == EN_UPDATE)
{
if (edit->launch_event == TRUE && IsWindowEnabled(edit->control.hwnd) && edit->OnFilter != NULL)
{
char_t *edit_text;
uint32_t tsize;
EvText params;
EvTextFilter result;
edit_text = _oscontrol_get_text(cast_const(edit, OSControl), &tsize, NULL);
params.text = cast_const(edit_text, char_t);
params.cpos = i_get_cursor_pos(edit->control.hwnd);
params.len = INT32_MAX;
result.apply = FALSE;
result.text[0] = '\0';
result.cpos = UINT32_MAX;
listener_event(edit->OnFilter, ekGUI_EVENT_TXTFILTER, edit, ¶ms, &result, OSEdit, EvText, EvTextFilter);
heap_free(dcast(&edit_text, byte_t), tsize, "OSControlGetText");
if (result.apply == TRUE)
{
bool_t prev = edit->launch_event;
edit->launch_event = FALSE;
_oscontrol_set_text(&edit->control, result.text);
edit->launch_event = prev;
}
if (result.cpos != UINT32_MAX)
i_set_cursor_pos(edit->control.hwnd, result.cpos);
else
i_set_cursor_pos(edit->control.hwnd, params.cpos);
}
}
}
COLORREF _osedit_color(const OSEdit *edit)
{
cassert_no_null(edit);
return edit->color;
}
HBRUSH _osedit_background_color(const OSEdit *edit, COLORREF *color)
{
cassert_no_null(edit);
if (edit->bgbrush != NULL)
{
*color = edit->bgcolor & 0x00FFFFFF;
return edit->bgbrush;
}
return NULL;
}
bool_t _osedit_resign_focus(const OSEdit *edit)
{
bool_t lost_focus = TRUE;
cassert_no_null(edit);
if (edit->OnChange != NULL)
{
char_t *edit_text = NULL;
uint32_t tsize = 0;
uint32_t nchars = 0;
EvText params;
edit_text = _oscontrol_get_text(cast_const(edit, OSControl), &tsize, &nchars);
params.text = cast_const(edit_text, char_t);
params.cpos = i_get_cursor_pos(edit->control.hwnd);
params.len = (int32_t)nchars;
listener_event(edit->OnChange, ekGUI_EVENT_TXTCHANGE, edit, ¶ms, &lost_focus, OSEdit, EvText, bool_t);
heap_free(dcast(&edit_text, byte_t), tsize, "OSControlGetText");
}
return lost_focus;
}
void _osedit_focus(OSEdit *edit, const bool_t focus)
{
cassert_no_null(edit);
edit->focused = focus;
if (edit->OnFocus != NULL)
{
bool_t params = focus;
listener_event(edit->OnFocus, ekGUI_EVENT_FOCUS, edit, ¶ms, NULL, OSEdit, bool_t, void);
}
if (focus == TRUE)
{
if (BIT_TEST(edit->flags, ekEDIT_AUTOSEL) == TRUE)
SendMessage(edit->control.hwnd, EM_SETSEL, 0, -1);
}
}