diff options
Diffstat (limited to 'Src/Wasabi/api/wnd/wndclass/editwnd.cpp')
-rw-r--r-- | Src/Wasabi/api/wnd/wndclass/editwnd.cpp | 1001 |
1 files changed, 1001 insertions, 0 deletions
diff --git a/Src/Wasabi/api/wnd/wndclass/editwnd.cpp b/Src/Wasabi/api/wnd/wndclass/editwnd.cpp new file mode 100644 index 00000000..8bde39d8 --- /dev/null +++ b/Src/Wasabi/api/wnd/wndclass/editwnd.cpp @@ -0,0 +1,1001 @@ +#include <precomp.h> +#include "editwnd.h" + +#include <tataki/canvas/canvas.h> +#include <api/wnd/notifmsg.h> + +#include <bfc/assert.h> + +#define ID_EDITCHILD 12 + +enum { IDLETIMER = 8, DELETETIMER = 10 }; +#define IDLETIME 350 // comprimises suck ;) + + +#if UTF8 +#ifdef WANT_UTF8_WARNINGS +#pragma CHAT("mig", "all", "UTF8 is enabled in editwnd.cpp -- Things might be screwy till it's all debugged?") +#endif +# include <bfc/string/encodedstr.h> +#endif + +#ifdef WIN32 +#include <commctrl.h> +#endif + + +#ifdef WIN32 +static LRESULT CALLBACK static_editWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + EditWnd *editwnd = (EditWnd *)GetWindowLongPtrW(hWnd, GWLP_USERDATA); + if (editwnd == NULL) return DefWindowProcW(hWnd, uMsg, wParam, lParam); + return editwnd->editWndProc(hWnd, uMsg, wParam, lParam); +} +#endif + +EditWnd::EditWnd(wchar_t *buffer, int buflen) +{ + wantfocus = 1; + nextenterfaked = 0; + idleenabled = 1; + beforefirstresize = 1; + editWnd = NULL; + prevWndProc = NULL; + setBuffer(buffer, buflen); + maxlen = 0; + retcode = EDITWND_RETURN_NOTHING; + modal = 0; + autoenter = 0; + autoselect = 0; + outbuf = NULL; + // bordered = 0; + idletimelen = IDLETIME; + multiline = 0; + readonly = 0; + password = 0; + autohscroll = 1; + autovscroll = 1; + vscroll = 0; +#ifdef WIN32 + oldbrush = NULL; +#endif +#ifdef LINUX + selstart = selend = 0; + cursorpos = 0; + selectmode = 0; + viewstart = 0; +#endif +#ifdef WASABI_EDITWND_LISTCOLORS + if (WASABI_API_SKIN->skin_getColorElementRef(L"wasabi.list.text")) + textcolor = L"wasabi.list.text"; + else + textcolor = L"wasabi.edit.text"; + if (WASABI_API_SKIN->skin_getColorElementRef(L"wasabi.list.background")) + backgroundcolor = L"wasabi.list.background"; + else + textcolor.setColor(WASABI_API_SKIN->skin_getBitmapColor(L"wasabi.list.background")); +#else + backgroundcolor = "wasabi.edit.background"; + textcolor = "wasabi.edit.text"; +#endif + selectioncolor = L"wasabi.edit.selection"; + setVirtual(0); +} + +EditWnd::~EditWnd() +{ + killTimer(IDLETIMER); +#ifdef WIN32 + if (oldbrush != NULL) + DeleteObject(oldbrush); + oldbrush = NULL; + if (editWnd != NULL) + { + SetWindowLong(editWnd, GWLP_USERDATA, (LONG_PTR)0); + SetWindowLongPtrW(editWnd, GWLP_WNDPROC, (LONG_PTR)prevWndProc); + DestroyWindow(editWnd); + } +#endif + notifyParent(ChildNotify::RETURN_CODE, retcode); +} + +int EditWnd::onInit() +{ + EDITWND_PARENT::onInit(); + +#ifdef WIN32 + RECT r = clientRect(); + + editWnd = CreateWindowW(L"EDIT", NULL, + WS_CHILD + | (autohscroll ? ES_AUTOHSCROLL : 0) + | (readonly ? ES_READONLY : 0) + | (multiline ? ES_MULTILINE : 0) + | (password ? ES_PASSWORD : 0) + | (autovscroll ? ES_AUTOVSCROLL : 0) + | (vscroll ? WS_VSCROLL : 0), + r.left, r.top, r.right - r.left, r.bottom - r.top, + gethWnd(), (HMENU)ID_EDITCHILD, + getOsModuleHandle(), NULL); + ASSERT(editWnd != NULL); + + if ((maxlen != 0) && (outbuf != NULL)) + { + setBuffer(outbuf, maxlen); + } + + // stash a pointer to us + SetWindowLongPtrW(editWnd, GWLP_USERDATA, (LONG_PTR)this); + // subclass the edit control -- either by 8 or by 16 + + prevWndProc = (WNDPROC)SetWindowLongPtrW(editWnd, GWLP_WNDPROC, (LONG_PTR)static_editWndProc); + + + SendMessageW(editWnd, WM_SETFONT, (WPARAM)GetStockObject(ANSI_VAR_FONT), FALSE); + ShowWindow(editWnd, !getStartHidden() ? SW_NORMAL : SW_HIDE); +#endif + + return 1; +} + +void EditWnd::onSetVisible(int show) +{ + EDITWND_PARENT::onSetVisible(show); + if (editWnd == NULL) return ; +#ifdef WIN32 + ShowWindow(editWnd, show ? SW_NORMAL : SW_HIDE); +#endif +} + +int EditWnd::onPaint(Canvas *canvas) +{ + // if (!bordered) return EDITWND_PARENT::onPaint(canvas); + + PaintCanvas paintcanvas; + if (canvas == NULL) + { + if (!paintcanvas.beginPaint(this)) return 0; + canvas = &paintcanvas; + } + EDITWND_PARENT::onPaint(canvas); + + RECT r; + getClientRect(&r); + canvas->fillRect(&r, backgroundcolor); //SKIN + +#ifdef LINUX + char *str = STRDUP((const char *)inbuf + viewstart); + canvas->setTextColor(textcolor); + canvas->setTextSize(r.bottom - r.top); + canvas->setTextOpaque(FALSE); + char save; + if (selstart != selend) + { + RECT selrect = r; + int start = MAX(MIN(selstart, selend) - viewstart, 0); + int end = MAX(MAX(selstart, selend) - viewstart, 0); + + save = str[ start ]; + str[start] = '\0'; + selrect.left = r.left + canvas->getTextWidth(str); + str[start] = save; + + save = str[ end ]; + str[end] = '\0'; + selrect.right = r.left + canvas->getTextWidth(str); + str[end] = save; + + canvas->fillRect(&selrect, selectioncolor); + } + + save = str[cursorpos - viewstart]; + str[cursorpos - viewstart] = '\0'; + RECT cursor = r; + cursor.left = cursor.right = r.left + canvas->getTextWidth(str); + str[cursorpos - viewstart] = save; + canvas->drawRect(&cursor, TRUE, 0xffffff); + + canvas->textOut(r.left, r.top, r.right - r.left, r.bottom - r.top, str); + + FREE(str); +#endif + + return 1; +} + +int EditWnd::onResize() +{ + EDITWND_PARENT::onResize(); +#ifdef WIN32 + RECT r = clientRect(); + if (1 /*bordered*/) + { + r.top++; + r.bottom--; + r.left++; + r.right--; + } + MoveWindow(editWnd, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE); + + if (beforefirstresize) + { + ShowWindow(editWnd, SW_NORMAL); beforefirstresize = 0; + if (modal) + { + SetFocus(editWnd); + if (getAutoSelect()) + SendMessageW(editWnd, EM_SETSEL, 0, -1); + } + } +#endif + + return TRUE; +} + +#ifdef WIN32 +LRESULT EditWnd::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CTLCOLOREDIT: + { + HDC hdc = (HDC)wParam; + SetTextColor(hdc, textcolor); + SetBkColor(hdc, backgroundcolor); + if (oldbrush != NULL) + { + DeleteObject(oldbrush); + oldbrush = NULL; + } + oldbrush = CreateSolidBrush(backgroundcolor); + return (LRESULT)oldbrush; + } + + case WM_MOUSEACTIVATE: + WASABI_API_WND->popupexit_check(this); + break; + + case WM_COMMAND: + { + switch (HIWORD(wParam)) + { + case EN_CHANGE: + { + if (maxlen > 0) + { + GetWindowTextW(editWnd, outbuf, maxlen); + onEditUpdate(); + } + } + break; + case EN_SETFOCUS: + if (getAutoSelect()) + SendMessageW(editWnd, EM_SETSEL, (WPARAM)0, (LPARAM) - 1); + break; + case EN_KILLFOCUS: + onLoseFocus(); + break; + } + } + break; + } + + return EDITWND_PARENT::wndProc(hWnd, uMsg, wParam, lParam); +} +#endif + +void EditWnd::setBuffer(wchar_t *buffer, int len) +{ +#ifdef LINUX + if (buffer == NULL || len <= 1) + { + inbuf = ""; + return ; + } +#endif + if (buffer == NULL || len <= 1) return ; + ASSERT(len > 1); + ASSERT(len < 0x7ffe); + ASSERT((int)wcslen(buffer) <= len); + +#ifdef WIN32 +#define USE_INTERNAL_BUFFER 0 + +#if USE_INTERNAL_BUFFER + buffer8.setSize(len + 1); + outbuf = buffer8.getMemory(); + if (len) + { + STRNCPY(outbuf, buffer, len); + } + outbuf[len] = 0; +#else + outbuf = buffer; +#endif + + if (editWnd != NULL) + { + SetWindowTextW(editWnd, buffer); + + // This is going to be problematic. This is where utf8 sucks. + // Just how many characters CAN we save in our buffer, eh? + // (shrug) Oh well. Can't be helped. At most this many. + SendMessageW(editWnd, EM_LIMITTEXT, (WPARAM)len - 1, (LPARAM)0); + // hooray for halcyon7 + + /* if (getAutoSelect()) { + SetFocus(editWnd); + SendMessageW(editWnd, EM_SETSEL, (WPARAM)0, (LPARAM)-1); + }*/ + } + + maxlen = len; +#else + outbuf = buffer; + maxlen = len; + inbuf = buffer; + cursorpos = len; + invalidate(); +#endif +} + +void EditWnd::selectAll() +{ +#ifdef WIN32 + PostMessage(editWnd, EM_SETSEL, 0, -1); +#else + selstart = 0; selend = inbuf.len(); +#endif +} + +void EditWnd::enter() +{ + onEnter(); +} + +void EditWnd::getBuffer(wchar_t *buf, int _len) +{ + if (_len > maxlen) _len = maxlen; + // SendMessageW(editWnd, WM_GETTEXT, (WPARAM)_len, (LPARAM)buf); + WCSCPYN(buf, outbuf, _len); +} + +void EditWnd::setModal(int _modal) +{ + modal = _modal; +} + +void setBorder(int border) +{ + // bordered = border; +} + +int EditWnd::isEditorKey(int vk) +{ + if (vk >= VK_F1) return 0; + if ((vk == VK_UP || vk == VK_DOWN) || ((Std::keyDown(VK_CONTROL) || Std::keyDown(VK_MENU)) && (vk == VK_LEFT || vk == VK_RIGHT))) + return 0; + if (vk == VK_RETURN && Std::keyDown(VK_CONTROL)) return 0; + if (vk == VK_CONTROL || vk == VK_MENU) return 0; + return 1; +} + +LRESULT EditWnd::editWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_KEYDOWN: + if (!isEditorKey((int)wParam) && !onKeyDown((int)wParam)) + { +#ifdef WASABI_COMPILE_WND + WASABI_API_WND->forwardOnKeyDown(this, (int) wParam, (int)lParam); +#endif + + } + break; + case WM_KEYUP: + if (!isEditorKey((int)wParam) && !onKeyUp((int)wParam)) + { +#ifdef WASABI_COMPILE_WND + WASABI_API_WND->forwardOnKeyUp(this, (int) wParam, (int)lParam); +#endif + + } + break; + case WM_CHAR: + if (!(wParam == VK_RETURN && nextenterfaked && !autoenter)) + { + notifyParent(ChildNotify::EDITWND_KEY_PRESSED, wParam); + onChar((TCHAR)wParam); + } + if (wParam == VK_RETURN) + { + if (!(nextenterfaked && !autoenter)) + if (onEnter()) return 0; + nextenterfaked = 0; + return 0; + } + else if (wParam == VK_ESCAPE) + { + if (onAbort()) return 0; + } + else if (wParam == VK_TAB && multiline) + { + return 0; + } + break; + case WM_SETFOCUS: + onSetRootFocus(this); + // fall thru + case WM_KILLFOCUS: + invalidate(); + break; + } +#ifdef WIN32 + return CallWindowProc(prevWndProc, hWnd, uMsg, wParam, lParam); +#else + DebugString("portme -- EditWnd::editWndProc\n"); + return 0; +#endif +} + +void EditWnd::timerCallback(int id) +{ + switch (id) + { + case IDLETIMER: + killTimer(IDLETIMER); + if (idleenabled) onIdleEditUpdate(); + break; + case DELETETIMER: + killTimer(DELETETIMER); + delete this; + break; + default: + EDITWND_PARENT::timerCallback(id); + } +} + +void EditWnd::onEditUpdate() +{ +#ifdef LINUX + STRNCPY(outbuf, inbuf, maxlen); + outbuf[maxlen] = '\0'; + + RECT r; + getClientRect(&r); + + SysCanvas sysc; + sysc.setTextSize(r.bottom - r.top); + sysc.getTextWidth(inbuf); + + char *str = STRDUP(inbuf); + + if (cursorpos < viewstart) + viewstart = cursorpos; + + char save = str[cursorpos]; + str[cursorpos] = '\0'; + while (sysc.getTextWidth(str + viewstart) > r.right - r.left) + { + viewstart++; + } + str[cursorpos] = save; + + invalidate(); +#endif + killTimer(IDLETIMER); + setTimer(IDLETIMER, idletimelen); + notifyParent(ChildNotify::EDITWND_DATA_MODIFIED); +} + +void EditWnd::onIdleEditUpdate() +{ + notifyParent(ChildNotify::EDITWND_DATA_MODIFIED_ONIDLE); +} + +int EditWnd::onEnter() +{ + notifyParent(ChildNotify::EDITWND_ENTER_PRESSED); + if (modal) + { + retcode = EDITWND_RETURN_OK; + delete this; + //CUT setTimer(DELETETIMER, 1); + return 1; + } + return 0; +} + +int EditWnd::onAbort() +{ + notifyParent(ChildNotify::EDITWND_CANCEL_PRESSED); + if (modal) + { + retcode = EDITWND_RETURN_CANCEL; + delete this; + //CUT setTimer(DELETETIMER, 1); + return 1; + } + return 0; +} + +int EditWnd::onLoseFocus() +{ // fake an onEnter() +#ifdef WIN32 + if (autoenter) + { + nextenterfaked = 1; + PostMessage(editWnd, WM_CHAR, VK_RETURN, 0); + } +#else + invalidate(); + selstart = selend = 0; +#endif + return 0; +} + +void EditWnd::setAutoEnter(int a) +{ + autoenter = a; +} + +void EditWnd::setAutoSelect(int a) +{ + autoselect = a; +}; + +void EditWnd::setIdleTimerLen(int ms) +{ + if (ms < 0) ms = 0; + idletimelen = ms; +} + +int EditWnd::getTextLength() +{ // TOTALLY NONPORTABLE AND TOTALLY DIRTY +#ifdef WIN32 + HFONT font = (HFONT)SendMessageW(editWnd, WM_GETFONT, 0, 0); + + HDC sdc = GetDC(NULL); + HDC dc = CreateCompatibleDC(sdc); + ReleaseDC(NULL, sdc); + + HFONT oldfont = (HFONT)SelectObject(dc, font); + + SIZE s; + GetTextExtentPoint32W(dc, outbuf, wcslen(outbuf), &s); + SelectObject(dc, oldfont); + DeleteDC(dc); + return s.cx + SendMessageW(editWnd, EM_GETMARGINS, 0, 0)*2 + 2; +#else + if (inbuf.isempty()) + return 0; + + RECT r; + getClientRect(&r); + + SysCanvas sysc; + sysc.setTextSize(r.bottom - r.top); + return sysc.getTextWidth(inbuf); +#endif +} + +HWND EditWnd::getEditWnd() +{ + return editWnd; +} + +#ifndef WIN32 +enum { + ES_MULTILINE, + ES_WANTRETURN, + ES_AUTOHSCROLL, + ES_AUTOVSCROLL, + WS_VSCROLL, +}; +#endif + +void EditWnd::setMultiline(int ml) +{ + multiline = ml; + setStyle(ES_MULTILINE | ES_WANTRETURN, ml); +} + +void EditWnd::setReadOnly(int ro) +{ + readonly = ro; + setStyle(ES_READONLY, ro); +} + +void EditWnd::setPassword(int pw) +{ + password = pw; + setStyle(ES_PASSWORD, pw); +} + +void EditWnd::setAutoHScroll(int hs) +{ + autohscroll = hs; + setStyle(ES_AUTOHSCROLL, hs); +} + +void EditWnd::setAutoVScroll(int vs) +{ + autovscroll = vs; + setStyle(ES_AUTOVSCROLL, vs); +} + +void EditWnd::setVScroll(int vs) +{ + vscroll = vs; + setStyle(WS_VSCROLL, vs); +} + +void EditWnd::setStyle(LONG style, int set) +{ +#ifdef WIN32 + if (editWnd) + { + LONG s = GetWindowLong(editWnd, GWL_STYLE); + if (set) s |= style; + else s &= ~style; + SetWindowLong(editWnd, GWL_STYLE, s); + } +#else + DebugString("portme -- EditWnd::setStyle\n"); +#endif +} + +int EditWnd::onGetFocus() +{ + int r = EDITWND_PARENT::onGetFocus(); +#ifdef WIN32 + if (editWnd != NULL) + SetFocus(editWnd); +#endif + return r; +} + +int EditWnd::wantFocus() +{ + return wantfocus; +} + +int EditWnd::gotFocus() +{ + return (GetFocus() == editWnd); +} + +void EditWnd::setBackgroundColor(COLORREF c) +{ + backgroundcolor.setColor(c); +} + +void EditWnd::setTextColor(COLORREF c) +{ + textcolor.setColor(c); +} + +void EditWnd::invalidate() +{ + EDITWND_PARENT::invalidate(); + InvalidateRect(editWnd, NULL, TRUE); +} + +#ifdef LINUX +int EditWnd::textposFromCoord(int x, int y) +{ + RECT r; + getClientRect(&r); + + SysCanvas canvas; + + canvas.setTextColor(textcolor); + canvas.setTextSize(r.bottom - r.top); + canvas.setTextOpaque(FALSE); + + x -= r.left; + + int i; + + char *str = STRDUP(inbuf); + + if (x > canvas.getTextWidth(str + viewstart)) + return inbuf.len(); + + for (i = viewstart + 1; str[i]; i++) + { + char save = str[i]; + str[i] = '\0'; + if (x < canvas.getTextWidth(str + viewstart)) + { + str[i] = save; + break; + } + str[i] = save; + } + + FREE(str); + + return i - 1; +} + +int EditWnd::onLeftButtonDown(int x, int y) +{ + EDITWND_PARENT::onLeftButtonDown(x, y); + + // Add check for double/triple click... + + cursorpos = textposFromCoord(x, y); + selstart = selend = cursorpos; + + selectmode = 1; + + return 1; +} + +int EditWnd::onLeftButtonUp(int x, int y) +{ + EDITWND_PARENT::onLeftButtonUp(x, y); + + selectmode = 0; + + return 1; +} + +int EditWnd::onMouseMove(int x, int y) +{ + EDITWND_PARENT::onMouseMove(x, y); + + switch (selectmode) + { + case 0: + // Do nothing + break; + case 1: + selend = textposFromCoord(x, y); + cursorpos = selend; + onEditUpdate(); + break; + default: + DebugString("selectmode %d not available\n", selectmode); + break; + } + + return selectmode; +} + +int EditWnd::onKeyDown(int key) +{ + EDITWND_PARENT::onKeyDown(key); + + if (Std::keyDown(VK_CONTROL)) + { + switch (key) + { + case 'a': + case 'A': + selectAll(); + break; + + default: + return 0; + } + } + else + { + switch (key) + { + case XK_Home: + if (Std::keyDown(VK_SHIFT)) + { + if (selstart == selend) + { + selstart = selend = cursorpos; + } + selend = 0; + } + else + { + selstart = selend = 0; + } + cursorpos = 0; + break; + + case XK_End: + if (Std::keyDown(VK_SHIFT)) + { + if (selstart == selend) + { + selstart = selend = cursorpos; + } + selend = inbuf.len(); + } + else + { + selstart = selend = 0; + } + cursorpos = inbuf.len(); + break; + + case XK_Right: + if (Std::keyDown(VK_SHIFT)) + { + if (selstart == selend) + { + selstart = selend = cursorpos; + } + selend++; + if (selend > inbuf.len()) selend = inbuf.len(); + } + else + { + selstart = selend = 0; + } + cursorpos++; + if (cursorpos > inbuf.len()) cursorpos = inbuf.len(); + break; + + case XK_Left: + if (Std::keyDown(VK_SHIFT)) + { + if (selstart == selend) + { + selstart = selend = cursorpos; + } + selend--; + if (selend < 0) selend = 0; + } + else + { + selstart = selend = 0; + } + cursorpos--; + if (cursorpos < 0) cursorpos = 0; + break; + + case XK_Escape: + onAbort(); + break; + + case XK_Return: + onEnter(); + break; + + case XK_Delete: + if (selstart != selend) + { + int start = MIN(selstart, selend); + int end = MAX(selstart, selend); + + String add; + + if (end < inbuf.len()) + { + add = (const char *)inbuf + end; + } + else + { + add = ""; + } + + inbuf.trunc(start); + inbuf += add; + + cursorpos = start; + selstart = selend = 0; + + } + else + { + if (cursorpos >= 0) + { + if (cursorpos < inbuf.len() - 1) + { + String tmp = inbuf; + tmp.trunc(cursorpos); + inbuf = tmp + ((const char *)inbuf + cursorpos + 1); + } + else if (cursorpos == inbuf.len() - 1) + { + inbuf.trunc(cursorpos); + } + } + } + break; + + case VK_BACK: + if (selstart != selend) + { + int start = MIN(selstart, selend); + int end = MAX(selstart, selend); + + String add; + + if (end < inbuf.len()) + { + add = (const char *)inbuf + end; + } + else + { + add = ""; + } + + inbuf.trunc(start); + inbuf += add; + + cursorpos = start; + selstart = selend = 0; + } + else + { + if (cursorpos > 0) + { + if (cursorpos >= inbuf.len()) + { + inbuf.trunc(cursorpos - 1); + cursorpos--; + } + else + { + String tmp = inbuf; + tmp.trunc(cursorpos - 1); + inbuf = tmp + ((const char *)inbuf + cursorpos); + cursorpos--; + } + } + } + break; + + default: + if (key < 0x20 || key > 0x7e) + return 0; + + if (selstart != selend) + { + int start = MIN(selstart, selend); + int end = MAX(selstart, selend); + + String add; + + if (end < inbuf.len()) + { + add = (const char *)inbuf + end; + } + else + { + add = ""; + } + + inbuf.trunc(start); + inbuf += add; + + cursorpos = start; + selstart = selend = 0; + } + + String tmp; + + if (cursorpos >= inbuf.len()) + { + tmp = ""; + } + else + { + tmp = (const char *)inbuf + cursorpos; + } + + inbuf.trunc(cursorpos); + + inbuf += (char)key; + inbuf += tmp; + + cursorpos++; + } + } + + onEditUpdate(); + + return 1; +} +#endif |