From 983c5ac518db7fce3143c05d590813222bfa2625 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Thu, 25 Mar 2021 15:33:17 +0300 Subject: EnterString dialog -> UI classes (also fixes crash in #2803) --- src/mir_app/src/enterstring.cpp | 385 +++++++++++++++++++++------------------- 1 file changed, 199 insertions(+), 186 deletions(-) (limited to 'src/mir_app') diff --git a/src/mir_app/src/enterstring.cpp b/src/mir_app/src/enterstring.cpp index 0614ab882a..c4acdceac8 100644 --- a/src/mir_app/src/enterstring.cpp +++ b/src/mir_app/src/enterstring.cpp @@ -24,11 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "stdafx.h" -struct EnterStringFormParam : public ENTER_STRING -{ - int idcControl; - int height; -}; +#define WM_MODULE_UNLOAD (WM_USER + 1) static int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton) { @@ -37,230 +33,247 @@ static int UIEmulateBtnClick(HWND hwndDlg, UINT idcButton) return 0; } -static int sttEnterStringResizer(HWND, LPARAM, UTILRESIZECONTROL *urc) +struct CCtrlMemo : public CCtrlRichEdit { - switch (urc->wId) { - case IDC_TXT_MULTILINE: - case IDC_TXT_COMBO: - case IDC_TXT_RICHEDIT: - return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; - - case IDOK: - case IDCANCEL: - return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; + CCtrlMemo(CDlgBase *dlg, int ctrlId) : + CCtrlRichEdit(dlg, ctrlId) + {} + + BOOL OnNotify(int, NMHDR *pnmhdr) override + { + ENLINK *param = (ENLINK *)pnmhdr; + if (pnmhdr->code == EN_LINK && param->msg == WM_LBUTTONUP) { + CHARRANGE sel; + SendMessage(param->nmhdr.hwndFrom, EM_EXGETSEL, 0, (LPARAM)&sel); + if (sel.cpMin == sel.cpMax) { // allow link selection + TEXTRANGE tr; + tr.chrg = param->chrg; + tr.lpstrText = (wchar_t *)mir_alloc(sizeof(wchar_t) * (tr.chrg.cpMax - tr.chrg.cpMin + 2)); + SendMessage(param->nmhdr.hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&tr); + + Utils_OpenUrlW(tr.lpstrText); + mir_free(tr.lpstrText); + } + return TRUE; + } + return FALSE; } - return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; -} +}; -static void ComboLoadRecentStrings(HWND hwndDlg, EnterStringFormParam *pForm) +class CEnterStringDlg : public CDlgBase { - for (int i = 0; i < pForm->recentCount; i++) { - char setting[MAXMODULELABELLENGTH]; - mir_snprintf(setting, "%s%d", pForm->szDataPrefix, i); - ptrW tszRecent(db_get_wsa(0, pForm->szModuleName, setting)); - if (tszRecent != nullptr) - SendDlgItemMessage(hwndDlg, pForm->idcControl, CB_ADDSTRING, 0, tszRecent); + int idcControl = 0; + HANDLE m_hEvent = nullptr; + ENTER_STRING m_param; + + void ComboLoadRecentStrings() + { + for (int i = 0; i < m_param.recentCount; i++) { + char setting[MAXMODULELABELLENGTH]; + mir_snprintf(setting, "%s%d", m_param.szDataPrefix, i); + ptrW tszRecent(db_get_wsa(0, m_param.szModuleName, setting)); + if (tszRecent != nullptr) + combo.AddString(tszRecent); + } + + if (!combo.GetCount()) + combo.AddString(L""); } - if (!SendDlgItemMessage(hwndDlg, pForm->idcControl, CB_GETCOUNT, 0, 0)) - SendDlgItemMessage(hwndDlg, pForm->idcControl, CB_ADDSTRING, 0, (LPARAM)L""); -} + void ComboAddRecentString() + { + wchar_t *string = m_param.ptszResult; + if (!string || !*string) + return; -static void ComboAddRecentString(HWND hwndDlg, EnterStringFormParam *pForm) -{ - wchar_t *string = pForm->ptszResult; - if (!string || !*string) - return; - - if (SendDlgItemMessage(hwndDlg, pForm->idcControl, CB_FINDSTRING, (WPARAM)-1, (LPARAM)string) != CB_ERR) - return; - - int id; - SendDlgItemMessage(hwndDlg, pForm->idcControl, CB_ADDSTRING, 0, (LPARAM)string); - if ((id = SendDlgItemMessage(hwndDlg, pForm->idcControl, CB_FINDSTRING, (WPARAM)-1, (LPARAM)L"")) != CB_ERR) - SendDlgItemMessage(hwndDlg, pForm->idcControl, CB_DELETESTRING, id, 0); - - id = db_get_b(0, pForm->szModuleName, pForm->szDataPrefix, 0); - char setting[MAXMODULELABELLENGTH]; - mir_snprintf(setting, "%s%d", pForm->szDataPrefix, id); - db_set_ws(0, pForm->szModuleName, setting, string); - db_set_b(0, pForm->szModuleName, pForm->szDataPrefix, (id + 1) % pForm->idcControl); -} + if (combo.FindString(string) != -1) + return; -static INT_PTR CALLBACK sttEnterStringDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - EnterStringFormParam *params = (EnterStringFormParam *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - Window_SetSkinIcon_IcoLib(hwndDlg, SKINICON_OTHER_RENAME); - params = (EnterStringFormParam *)lParam; - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)params); - SetWindowText(hwndDlg, params->caption); - { - RECT rc; GetWindowRect(hwndDlg, &rc); - switch (params->type) { - case ESF_PASSWORD: - params->idcControl = IDC_TXT_PASSWORD; - params->height = rc.bottom - rc.top; - break; - - case ESF_MULTILINE: - params->idcControl = IDC_TXT_MULTILINE; - params->height = 0; - rc.bottom += (rc.bottom - rc.top) * 2; - SetWindowPos(hwndDlg, nullptr, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOREPOSITION); - break; - - case ESF_COMBO: - params->idcControl = IDC_TXT_COMBO; - params->height = rc.bottom - rc.top; - if (params->szDataPrefix && params->recentCount) - ComboLoadRecentStrings(hwndDlg, params); - break; - - case ESF_RICHEDIT: - params->idcControl = IDC_TXT_RICHEDIT; - SendDlgItemMessage(hwndDlg, IDC_TXT_RICHEDIT, EM_AUTOURLDETECT, TRUE, 0); - SendDlgItemMessage(hwndDlg, IDC_TXT_RICHEDIT, EM_SETEVENTMASK, 0, ENM_LINK); - params->height = 0; - rc.bottom += (rc.bottom - rc.top) * 2; - SetWindowPos(hwndDlg, nullptr, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOREPOSITION); - break; - - default: // single string edit field - params->idcControl = IDC_TXT_SIMPLE; - params->height = rc.bottom - rc.top; - } - } - ShowWindow(GetDlgItem(hwndDlg, params->idcControl), SW_SHOW); - if (params->ptszInitVal) - SetDlgItemText(hwndDlg, params->idcControl, params->ptszInitVal); + int id; + combo.AddString(string); + if ((id = combo.FindString(L"")) != CB_ERR) + combo.DeleteString(id); + + id = db_get_b(0, m_param.szModuleName, m_param.szDataPrefix, 0); + char setting[MAXMODULELABELLENGTH]; + mir_snprintf(setting, "%s%d", m_param.szDataPrefix, id); + db_set_ws(0, m_param.szModuleName, setting, string); + db_set_b(0, m_param.szModuleName, m_param.szDataPrefix, (id + 1) % idcControl); + } - if (params->szDataPrefix) - Utils_RestoreWindowPosition(hwndDlg, 0, params->szModuleName, params->szDataPrefix); + LRESULT onModuleUnload(UINT, WPARAM wParam, LPARAM) + { + auto *pPlugin = (HPLUGIN)wParam; + if (!mir_strcmp(m_param.szModuleName, pPlugin->getModule())) + EndModal(0); + return 0; + } - SetTimer(hwndDlg, 1000, 50, nullptr); + UI_MESSAGE_MAP(CEnterStringDlg, CDlgBase); + UI_MESSAGE(WM_MODULE_UNLOAD, onModuleUnload); + UI_MESSAGE_MAP_END(); + + CTimer m_timer1, m_timer2; + CCtrlEdit edit1, edit2; + CCtrlMemo memo; + CCtrlCombo combo; + +public: + CEnterStringDlg(const ENTER_STRING ¶m) : + CDlgBase(g_plugin, IDD_ENTER_STRING), + m_param(param), + memo(this, IDC_TXT_RICHEDIT), + edit1(this, IDC_TXT_SIMPLE), + edit2(this, IDC_TXT_MULTILINE), + combo(this, IDC_TXT_COMBO), + m_timer1(this, 1001), + m_timer2(this, 1002) + { + m_timer1.OnEvent = Callback(this, &CEnterStringDlg::onTimer1); + m_timer2.OnEvent = Callback(this, &CEnterStringDlg::onTimer2); + + memo.OnChange = edit1.OnChange = edit2.OnChange = combo.OnChange = Callback(this, &CEnterStringDlg::onChange_Field); + } - if (params->timeout > 0) { - SetTimer(hwndDlg, 1001, 1000, nullptr); - wchar_t buf[128]; - mir_snwprintf(buf, TranslateT("OK (%d)"), params->timeout); - SetDlgItemText(hwndDlg, IDOK, buf); - } + bool OnInitDialog() override + { + Window_SetSkinIcon_IcoLib(m_hwnd, SKINICON_OTHER_RENAME); + SetCaption(m_param.caption); - return TRUE; + RECT rc; + GetWindowRect(m_hwnd, &rc); - case WM_DESTROY: - Window_FreeIcon_IcoLib(hwndDlg); - break; + if (m_param.szModuleName) + m_hEvent = HookEventMessage(ME_SYSTEM_MODULEUNLOAD, m_hwnd, WM_MODULE_UNLOAD); - case WM_TIMER: - switch (wParam) { - case 1000: - KillTimer(hwndDlg, 1000); - EnableWindow(GetParent(hwndDlg), TRUE); + switch (m_param.type) { + case ESF_PASSWORD: + idcControl = IDC_TXT_PASSWORD; + SetMinSize(rc.right - rc.left, rc.bottom - rc.top); break; - case 1001: - wchar_t buf[128]; - mir_snwprintf(buf, TranslateT("OK (%d)"), --params->timeout); - SetDlgItemText(hwndDlg, IDOK, buf); + case ESF_MULTILINE: + idcControl = IDC_TXT_MULTILINE; + rc.bottom += (rc.bottom - rc.top) * 2; + SetWindowPos(m_hwnd, nullptr, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOREPOSITION); + break; - if (params->timeout < 0) { - KillTimer(hwndDlg, 1001); - UIEmulateBtnClick(hwndDlg, IDOK); - } - } - return TRUE; + case ESF_COMBO: + idcControl = IDC_TXT_COMBO; + SetMinSize(rc.right - rc.left, rc.bottom - rc.top); + if (m_param.szDataPrefix && m_param.recentCount) + ComboLoadRecentStrings(); + break; - case WM_SIZE: - Utils_ResizeDialog(hwndDlg, g_plugin.getInst(), MAKEINTRESOURCEA(IDD_ENTER_STRING), sttEnterStringResizer); - break; + case ESF_RICHEDIT: + idcControl = IDC_TXT_RICHEDIT; + SendDlgItemMessage(m_hwnd, IDC_TXT_RICHEDIT, EM_AUTOURLDETECT, TRUE, 0); + SendDlgItemMessage(m_hwnd, IDC_TXT_RICHEDIT, EM_SETEVENTMASK, 0, ENM_LINK); + rc.bottom += (rc.bottom - rc.top) * 2; + SetWindowPos(m_hwnd, nullptr, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOREPOSITION); + break; - case WM_GETMINMAXINFO: - { - LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; - if (params && params->height) - lpmmi->ptMaxSize.y = lpmmi->ptMaxTrackSize.y = params->height; + default: // single string edit field + idcControl = IDC_TXT_SIMPLE; + SetMinSize(rc.right - rc.left, rc.bottom - rc.top); } - break; - case WM_NOTIFY: - { - ENLINK *param = (ENLINK *)lParam; - if (param->nmhdr.idFrom != IDC_TXT_RICHEDIT) break; - if (param->nmhdr.code != EN_LINK) break; - if (param->msg != WM_LBUTTONUP) break; + ShowWindow(GetDlgItem(m_hwnd, idcControl), SW_SHOW); + if (m_param.ptszInitVal) + SetDlgItemText(m_hwnd, idcControl, m_param.ptszInitVal); - CHARRANGE sel; - SendMessage(param->nmhdr.hwndFrom, EM_EXGETSEL, 0, (LPARAM)& sel); - if (sel.cpMin != sel.cpMax) break; // allow link selection + if (m_param.szDataPrefix) + Utils_RestoreWindowPosition(m_hwnd, 0, m_param.szModuleName, m_param.szDataPrefix); - TEXTRANGE tr; - tr.chrg = param->chrg; - tr.lpstrText = (wchar_t *)mir_alloc(sizeof(wchar_t)*(tr.chrg.cpMax - tr.chrg.cpMin + 2)); - SendMessage(param->nmhdr.hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&tr); + SetTimer(m_hwnd, 1000, 50, nullptr); - Utils_OpenUrlW(tr.lpstrText); - mir_free(tr.lpstrText); + if (m_param.timeout > 0) { + m_timer2.Start(1000); + + wchar_t buf[128]; + mir_snwprintf(buf, TranslateT("OK (%d)"), m_param.timeout); + SetDlgItemText(m_hwnd, IDOK, buf); } - return TRUE; - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_TXT_MULTILINE: - case IDC_TXT_RICHEDIT: - if ((HIWORD(wParam) != EN_SETFOCUS) && (HIWORD(wParam) != EN_KILLFOCUS)) { - SetDlgItemText(hwndDlg, IDOK, TranslateT("OK")); - KillTimer(hwndDlg, 1001); - } - break; + return true; + } - case IDC_TXT_COMBO: - if ((HIWORD(wParam) != CBN_SETFOCUS) && (HIWORD(wParam) != CBN_KILLFOCUS)) { - SetDlgItemText(hwndDlg, IDOK, TranslateT("OK")); - KillTimer(hwndDlg, 1001); - } - break; + bool OnApply() override + { + HWND hWnd = GetDlgItem(m_hwnd, idcControl); + int len = GetWindowTextLength(hWnd)+1; + m_param.ptszResult = (LPTSTR)mir_alloc(sizeof(wchar_t)*len); + GetWindowText(hWnd, m_param.ptszResult, len); - case IDCANCEL: - if (params->szDataPrefix) - Utils_SaveWindowPosition(hwndDlg, 0, params->szModuleName, params->szDataPrefix); + if ((m_param.type == ESF_COMBO) && m_param.szDataPrefix && m_param.recentCount) + ComboAddRecentString(); + return true; + } - EndDialog(hwndDlg, 0); - break; + void OnDestroy() override + { + if (m_param.szDataPrefix) + Utils_SaveWindowPosition(m_hwnd, 0, m_param.szModuleName, m_param.szDataPrefix); + + Window_FreeIcon_IcoLib(m_hwnd); + UnhookEvent(m_hEvent); + } + + int Resizer(UTILRESIZECONTROL *urc) override + { + switch (urc->wId) { + case IDC_TXT_MULTILINE: + case IDC_TXT_COMBO: + case IDC_TXT_RICHEDIT: + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; case IDOK: - HWND hWnd = GetDlgItem(hwndDlg, params->idcControl); - int len = GetWindowTextLength(hWnd)+1; - params->ptszResult = (LPTSTR)mir_alloc(sizeof(wchar_t)*len); - GetWindowText(hWnd, params->ptszResult, len); + case IDCANCEL: + return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; + } + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; + } + + void onTimer1(CTimer *) + { + m_timer1.Stop(); + EnableWindow(GetParent(m_hwnd), TRUE); + } - if ((params->type == ESF_COMBO) && params->szDataPrefix && params->recentCount) - ComboAddRecentString(hwndDlg, params); - if (params->szDataPrefix) - Utils_SaveWindowPosition(hwndDlg, 0, params->szModuleName, params->szDataPrefix); + void onTimer2(CTimer *) + { + wchar_t buf[128]; + mir_snwprintf(buf, TranslateT("OK (%d)"), --m_param.timeout); + SetDlgItemText(m_hwnd, IDOK, buf); - EndDialog(hwndDlg, 1); - break; + if (m_param.timeout < 0) { + m_timer1.Stop(); + UIEmulateBtnClick(m_hwnd, IDOK); } } - return FALSE; -} + void onChange_Field(CCtrlData*) + { + SetDlgItemText(m_hwnd, IDOK, TranslateT("OK")); + m_timer1.Stop(); + } + + wchar_t* GetResult() const + { + return m_param.ptszResult; + } +}; MIR_APP_DLL(bool) EnterString(ENTER_STRING *pForm) { if (pForm == nullptr) return false; - EnterStringFormParam param = {}; - memcpy(¶m, pForm, sizeof(ENTER_STRING)); - if (!DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_ENTER_STRING), GetForegroundWindow(), sttEnterStringDlgProc, LPARAM(¶m))) + CEnterStringDlg dlg(*pForm); + dlg.SetParent(GetForegroundWindow()); + if (!dlg.DoModal()) return false; - pForm->ptszResult = param.ptszResult; + pForm->ptszResult = dlg.GetResult(); return true; } -- cgit v1.2.3