From 4080ed23db3d8463c9c6aceddd3670dbed9c379e Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sat, 23 Feb 2019 15:06:01 +0300 Subject: Jabber: - fixes #1844 (Tab button doesn't work in Jabber registration form); - added Escape handler for any dynamic form to inform parent dialog; - massive dynamic forms-related XML code cleaning & reordering; - now form fiields without types are also processed; - vertical scrollbar is hidden if it's not needed; - hidden fields do not eat form space anymore --- protocols/JabberG/res/jabber.rc | 9 +- protocols/JabberG/src/jabber_adhoc.cpp | 10 +- protocols/JabberG/src/jabber_agent.cpp | 30 +- protocols/JabberG/src/jabber_form.cpp | 793 ++++++++++++++---------------- protocols/JabberG/src/jabber_iqid_muc.cpp | 8 +- protocols/JabberG/src/jabber_proto.h | 16 +- protocols/JabberG/src/jabber_search.cpp | 3 +- protocols/JabberG/src/jabber_strm_mgmt.h | 2 + protocols/JabberG/src/jabber_thread.cpp | 16 +- protocols/JabberG/src/resource.h | 1 - protocols/JabberG/src/stdafx.h | 61 ++- 11 files changed, 471 insertions(+), 478 deletions(-) diff --git a/protocols/JabberG/res/jabber.rc b/protocols/JabberG/res/jabber.rc index d11d1ea9c9..1d65978c6a 100644 --- a/protocols/JabberG/res/jabber.rc +++ b/protocols/JabberG/res/jabber.rc @@ -182,11 +182,10 @@ FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN CONTROL "",IDC_WHITERECT,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,0,0,258,25 LTEXT "Instruction:",IDC_TITLE,7,7,243,8,NOT WS_GROUP - EDITTEXT IDC_INSTRUCTION,17,17,233,1,ES_MULTILINE | ES_READONLY | NOT WS_BORDER + EDITTEXT IDC_INSTRUCTION,17,17,233,1,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP CONTROL "",IDC_FRAME1,"Static",SS_ETCHEDHORZ,0,26,258,1 CONTROL "",IDC_FRAME2,"Static",SS_ETCHEDHORZ,0,197,258,1 - LTEXT "",IDC_FRAME,0,27,250,169,NOT WS_GROUP - EDITTEXT IDC_FRAME_TEXT,18,101,220,33,ES_CENTER | ES_MULTILINE | ES_READONLY | NOT WS_BORDER + LTEXT "",IDC_FRAME,0,28,250,168,WS_TABSTOP SCROLLBAR IDC_VSCROLL,246,28,11,167,SBS_VERT DEFPUSHBUTTON "Submit",IDC_SUBMIT,146,203,50,14,WS_DISABLED PUSHBUTTON "Cancel",IDCANCEL,200,203,50,14 @@ -722,6 +721,10 @@ BEGIN BOTTOMMARGIN, 61 END + IDD_FORM, DIALOG + BEGIN + END + IDD_PASSWORD, DIALOG BEGIN RIGHTMARGIN, 286 diff --git a/protocols/JabberG/src/jabber_adhoc.cpp b/protocols/JabberG/src/jabber_adhoc.cpp index 61fa07179d..ea7e0a3b3e 100644 --- a/protocols/JabberG/src/jabber_adhoc.cpp +++ b/protocols/JabberG/src/jabber_adhoc.cpp @@ -213,7 +213,6 @@ int CJabberProto::AdHoc_OnJAHMProcessResult(HWND hwndDlg, TiXmlElement *workNode if ((xNode = commandNode->FirstChildElement("x"))) { // use jabber:x:data form HWND hFrame = GetDlgItem(hwndDlg, IDC_FRAME); - ShowWindow(GetDlgItem(hwndDlg, IDC_FRAME_TEXT), SW_HIDE); if (auto *pszText = XmlGetChildText(xNode, "instructions")) JabberFormSetInstruction(hwndDlg, pszText); else if (pszText = XmlGetChildText(xNode, "title")) @@ -225,7 +224,7 @@ int CJabberProto::AdHoc_OnJAHMProcessResult(HWND hwndDlg, TiXmlElement *workNode } else { // NO X FORM - int toHide[] = { IDC_FRAME_TEXT, IDC_FRAME, IDC_VSCROLL, 0 }; + int toHide[] = { IDC_FRAME, IDC_VSCROLL, 0 }; sttShowControls(hwndDlg, FALSE, toHide); auto *pszText = XmlGetChildText(commandNode, "note"); @@ -258,7 +257,7 @@ int CJabberProto::AdHoc_OnJAHMProcessResult(HWND hwndDlg, TiXmlElement *workNode } else if (!mir_strcmp(type, "error")) { // error occurred here - int toHide[] = { IDC_FRAME, IDC_FRAME_TEXT, IDC_VSCROLL, IDC_PREV, IDC_NEXT, IDC_COMPLETE, IDC_SUBMIT, 0 }; + int toHide[] = { IDC_FRAME, IDC_VSCROLL, IDC_PREV, IDC_NEXT, IDC_COMPLETE, IDC_SUBMIT, 0 }; sttShowControls(hwndDlg, FALSE, toHide); const char *code = ""; @@ -295,8 +294,7 @@ int CJabberProto::AdHoc_SubmitCommandForm(HWND hwndDlg, JabberAdHocData *dat, ch if (action) command << XATTR("action", action); - TiXmlElement *dataNode = JabberFormGetData(GetDlgItem(hwndDlg, IDC_FRAME), &iq, xNode); - command->InsertEndChild(dataNode); + JabberFormGetData(GetDlgItem(hwndDlg, IDC_FRAME), command, xNode); m_ThreadInfo->send(iq); JabberFormSetInstruction(hwndDlg, TranslateU("In progress. Please Wait...")); @@ -353,7 +351,7 @@ static INT_PTR CALLBACK JabberAdHoc_CommandDlgProc(HWND hwndDlg, UINT msg, WPARA frameExStyle |= WS_EX_CONTROLPARENT; SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FRAME), GWL_EXSTYLE, frameExStyle); - int toHide[] = { IDC_FRAME, IDC_VSCROLL, IDC_PREV, IDC_NEXT, IDC_COMPLETE, IDC_FRAME_TEXT, 0 }; + int toHide[] = { IDC_FRAME, IDC_VSCROLL, IDC_PREV, IDC_NEXT, IDC_COMPLETE, 0 }; sttShowControls(hwndDlg, FALSE, toHide); int toShow[] = { IDC_INSTRUCTION, IDC_SUBMIT, IDCANCEL, 0 }; diff --git a/protocols/JabberG/src/jabber_agent.cpp b/protocols/JabberG/src/jabber_agent.cpp index 61a7176bba..87d9fe01cd 100644 --- a/protocols/JabberG/src/jabber_agent.cpp +++ b/protocols/JabberG/src/jabber_agent.cpp @@ -87,6 +87,7 @@ class CAgentRegDlg : public CJabberDlgBase char *m_jid; CCtrlButton m_submit; + HWND m_statusBar; public: CAgentRegDlg(CJabberProto *_ppro, char *_jid) : @@ -104,7 +105,10 @@ public: m_proto->m_hwndAgentRegInput = m_hwnd; SetWindowText(m_hwnd, TranslateT("Jabber Agent Registration")); SetDlgItemText(m_hwnd, IDC_SUBMIT, TranslateT("Register")); - SetDlgItemText(m_hwnd, IDC_FRAME_TEXT, TranslateT("Please wait...")); + + m_statusBar = CreateWindowExW(0, STATUSCLASSNAME, nullptr, WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0, m_hwnd, nullptr, g_plugin.getInst(), nullptr); + SendMessage(m_statusBar, WM_SIZE, 0, 0); + SetWindowTextW(m_statusBar, TranslateT("Please wait...")); m_proto->m_ThreadInfo->send( XmlNodeIq(m_proto->AddIQ(&CJabberProto::OnIqResultGetRegister, JABBER_IQ_TYPE_GET, m_jid)) @@ -139,8 +143,8 @@ public: case WM_JABBER_REGINPUT_ACTIVATE: if (wParam == 1) { // success // lParam = node from agent JID as a result of "get jabber:iq:register" - HWND hFrame = GetDlgItem(m_hwnd, IDC_FRAME); - ShowWindow(GetDlgItem(m_hwnd, IDC_FRAME_TEXT), SW_HIDE); + HWND hwndFrame = GetDlgItem(m_hwnd, IDC_FRAME); + SetWindowTextW(m_statusBar, L""); if ((m_agentRegIqNode = (TiXmlElement*)lParam) == nullptr) return TRUE; @@ -164,11 +168,11 @@ public: if (const char *pszText = XmlGetChildText(xNode, "instructions")) JabberFormSetInstruction(m_hwnd, pszText); - JabberFormCreateUI(hFrame, xNode, &m_formHeight /*dummy*/); + JabberFormCreateUI(hwndFrame, xNode, &m_formHeight); } else { // use old registration information form - HJFORMLAYOUT layout_info = JabberFormCreateLayout(hFrame); + TJabberFormLayoutInfo layout_info(hwndFrame, false); for (auto *n : TiXmlEnum(queryNode)) { const char *pszName = n->Name(); if (pszName) { @@ -179,13 +183,12 @@ public: // do nothing } else if (!mir_strcmp(pszName, "password")) - JabberFormAppendControl(hFrame, layout_info, JFORM_CTYPE_TEXT_PRIVATE, pszName, n->GetText()); + layout_info.AppendControl(JFORM_CTYPE_TEXT_PRIVATE, pszName, n->GetText()); else // everything else is a normal text field - JabberFormAppendControl(hFrame, layout_info, JFORM_CTYPE_TEXT_SINGLE, pszName, n->GetText()); + layout_info.AppendControl(JFORM_CTYPE_TEXT_SINGLE, pszName, n->GetText()); } } - JabberFormLayoutControls(hFrame, layout_info, &m_formHeight); - mir_free(layout_info); + layout_info.OrderControls(&m_formHeight); } if (m_formHeight > m_frameHeight) { @@ -201,7 +204,7 @@ public: } else if (wParam == 0) { // lParam = error message - SetDlgItemText(m_hwnd, IDC_FRAME_TEXT, (const wchar_t *)lParam); + SetWindowText(m_statusBar, (const wchar_t *)lParam); } return TRUE; @@ -237,7 +240,7 @@ public: const char *from; if ((from = m_agentRegIqNode->Attribute("from")) == nullptr) return; if ((queryNode = m_agentRegIqNode->FirstChildElement("query")) == nullptr) return; - HWND hFrame = GetDlgItem(m_hwnd, IDC_FRAME); + HWND hwndFrame = GetDlgItem(m_hwnd, IDC_FRAME); wchar_t *str2 = (wchar_t*)alloca(sizeof(wchar_t) * 128); int id = 0; @@ -247,8 +250,7 @@ public: if (auto *xNode = queryNode->FirstChildElement("x")) { // use new jabber:x:data form - TiXmlElement *n = JabberFormGetData(hFrame, &iq, xNode); - query->InsertEndChild(n); + JabberFormGetData(hwndFrame, query, xNode); } else { // use old registration information form @@ -266,7 +268,7 @@ public: // do nothing, we will skip these } else { - GetDlgItemText(hFrame, id, str2, 128); + GetDlgItemText(hwndFrame, id, str2, 128); XmlAddChild(query, pszName, T2Utf(str2).get()); id++; } diff --git a/protocols/JabberG/src/jabber_form.cpp b/protocols/JabberG/src/jabber_form.cpp index b2566ad6a0..8637f66d91 100644 --- a/protocols/JabberG/src/jabber_form.cpp +++ b/protocols/JabberG/src/jabber_form.cpp @@ -25,7 +25,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "stdafx.h" #include "jabber_caps.h" -static LRESULT CALLBACK JabberFormMultiLineWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +struct TJabberFormControlInfo : public MZeroedObject +{ + TJabberFormControlType type; + int bRequired; + SIZE szBlock; + POINT ptLabel, ptCtrl; + HWND hLabel, hCtrl; +}; + +typedef LIST TJabberFormControlList; + +static LRESULT CALLBACK JabberFormItemWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_KEYDOWN: @@ -35,75 +46,221 @@ static LRESULT CALLBACK JabberFormMultiLineWndProc(HWND hwnd, UINT msg, WPARAM w }; break; } - return mir_callNextSubclass(hwnd, JabberFormMultiLineWndProc, msg, wParam, lParam); + return mir_callNextSubclass(hwnd, JabberFormItemWndProc, msg, wParam, lParam); } -struct TJabberFormControlInfo +///////////////////////////////////////////////////////////////////////////////////////// +// TJabberFormLayoutInfo class + +TJabberFormLayoutInfo::TJabberFormLayoutInfo(HWND hwndCtrl, bool bCompact) : + m_hwnd(hwndCtrl), + m_bCompact(bCompact) { - TJabberFormControlType type; - SIZE szBlock; - POINT ptLabel, ptCtrl; - HWND hLabel, hCtrl; -}; -typedef LIST TJabberFormControlList; + RECT frameRect; + GetClientRect(hwndCtrl, &frameRect); + + m_ctrlHeight = 20; + m_id = 0; + m_width = frameRect.right - frameRect.left - 20; + if (!bCompact) + m_width -= 10; + m_ySpacing = bCompact ? 1 : 5; + m_maxLabelWidth = m_width * 2 / 5; + m_offset = 10; + m_yPos = bCompact ? 0 : 14; +} -struct TJabberFormLayoutInfo +TJabberFormControlInfo* TJabberFormLayoutInfo::AppendControl(TJabberFormControlType type, const char *labelStr, const char *valueStr) { - int ctrlHeight; - int offset, width, maxLabelWidth; - int y_pos, y_spacing; - int id; - bool compact; -}; + TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(m_hwnd, GWLP_USERDATA); + if (!controls) { + controls = new TJabberFormControlList(5); + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)controls); + } + + TJabberFormControlInfo *item = (TJabberFormControlInfo *)mir_alloc(sizeof(TJabberFormControlInfo)); + item->type = type; + item->hLabel = item->hCtrl = nullptr; + Utf2T wszLabel(labelStr), wszValue(valueStr); + + switch (type) { + case JFORM_CTYPE_TEXT_PRIVATE: + item->hLabel = CreateLabel(wszLabel); + item->hCtrl = CreateWindowExW(WS_EX_CLIENTEDGE, L"edit", wszValue, + WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL | ES_PASSWORD, + 0, 0, 0, 0, + m_hwnd, (HMENU)m_id, g_plugin.getInst(), nullptr); + ++m_id; + break; + + case JFORM_CTYPE_TEXT_MULTI: + item->hLabel = CreateLabel(wszLabel); + item->hCtrl = CreateWindowExW(WS_EX_CLIENTEDGE, L"edit", wszValue, + WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN, + 0, 0, 0, 0, + m_hwnd, (HMENU)m_id, g_plugin.getInst(), nullptr); + ++m_id; + break; -void JabberFormCenterContent(HWND hwndStatic) + case JFORM_CTYPE_BOOLEAN: + item->hCtrl = CreateWindowExW(0, L"button", wszLabel, + WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX | BS_MULTILINE, + 0, 0, 0, 0, + m_hwnd, (HMENU)m_id, g_plugin.getInst(), nullptr); + if (valueStr && !mir_wstrcmp(wszValue, L"1")) + SendMessage(item->hCtrl, BM_SETCHECK, 1, 0); + ++m_id; + break; + + case JFORM_CTYPE_LIST_SINGLE: + item->hLabel = CreateLabel(wszLabel); + item->hCtrl = CreateWindowExW(WS_EX_CLIENTEDGE, L"combobox", nullptr, + WS_CHILD | WS_VISIBLE | WS_TABSTOP | CBS_DROPDOWNLIST, + 0, 0, 0, 0, + m_hwnd, (HMENU)m_id, g_plugin.getInst(), nullptr); + ++m_id; + break; + + case JFORM_CTYPE_LIST_MULTI: + item->hLabel = CreateLabel(wszLabel); + item->hCtrl = CreateWindowExW(WS_EX_CLIENTEDGE, L"listbox", + nullptr, WS_CHILD | WS_VISIBLE | WS_TABSTOP | LBS_MULTIPLESEL, + 0, 0, 0, 0, + m_hwnd, (HMENU)m_id, g_plugin.getInst(), nullptr); + ++m_id; + break; + + case JFORM_CTYPE_FIXED: + item->hCtrl = CreateWindowExW(0, L"edit", wszValue, + WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_READONLY | ES_AUTOHSCROLL, + 0, 0, 0, 0, + m_hwnd, (HMENU)-1, g_plugin.getInst(), nullptr); + break; + + case JFORM_CTYPE_HIDDEN: + break; + + case JFORM_CTYPE_TEXT_SINGLE: + item->hLabel = labelStr ? (CreateLabel(wszLabel)) : nullptr; + item->hCtrl = CreateWindowExW(WS_EX_CLIENTEDGE, L"edit", wszValue, + WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL, + 0, 0, 0, 0, + m_hwnd, (HMENU)m_id, g_plugin.getInst(), nullptr); + ++m_id; + break; + } + + HFONT hFont = (HFONT)SendMessage(GetParent(m_hwnd), WM_GETFONT, 0, 0); + if (item->hLabel) + SendMessage(item->hLabel, WM_SETFONT, (WPARAM)hFont, 0); + if (item->hCtrl) { + SendMessage(item->hCtrl, WM_SETFONT, (WPARAM)hFont, 0); + + if (GetWindowStyle(item->hCtrl) & WS_TABSTOP) + mir_subclassWindow(item->hCtrl, JabberFormItemWndProc); + } + + PositionControl(item, labelStr, valueStr); + + controls->insert(item); + return item; +} + +HWND TJabberFormLayoutInfo::CreateLabel(const wchar_t *pwszLabel) { - RECT rcWindow; - GetWindowRect(hwndStatic, &rcWindow); - int minX = rcWindow.right; - - HWND oldChild = nullptr; - HWND hWndChild = GetWindow(hwndStatic, GW_CHILD); - while (hWndChild != oldChild && hWndChild != nullptr) { - DWORD style = GetWindowLongPtr(hWndChild, GWL_STYLE); - RECT rc; - GetWindowRect(hWndChild, &rc); - if ((style & SS_RIGHT) && !(style & WS_TABSTOP)) { - RECT calcRect = rc; - int len = GetWindowTextLength(hWndChild); - wchar_t *text = (wchar_t*)_alloca(sizeof(wchar_t)*(len + 1)); - GetWindowText(hWndChild, text, len + 1); - HDC hdc = GetDC(hWndChild); - HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(hWndChild, WM_GETFONT, 0, 0)); - DrawText(hdc, text, -1, &calcRect, DT_CALCRECT | DT_WORDBREAK); - minX = min(minX, rc.right - (calcRect.right - calcRect.left)); - SelectObject(hdc, hfntSave); - ReleaseDC(hWndChild, hdc); - } - else minX = min(minX, rc.left); + return CreateWindowExW(0, L"static", pwszLabel, WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 0, 0, 0, 0, m_hwnd, (HMENU)-1, g_plugin.getInst(), nullptr); +} + +void TJabberFormLayoutInfo::OrderControls(int *formHeight) +{ + TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(m_hwnd, GWLP_USERDATA); + if (!controls) + return; + + for (auto &it : *controls) { + if (it->type == JFORM_CTYPE_HIDDEN) + continue; - oldChild = hWndChild; - hWndChild = GetWindow(hWndChild, GW_HWNDNEXT); + if (it->hLabel) + SetWindowPos(it->hLabel, nullptr, + m_offset + it->ptLabel.x, m_yPos + it->ptLabel.y, 0, 0, + SWP_NOZORDER | SWP_NOSIZE); + + if (it->hCtrl) + SetWindowPos(it->hCtrl, nullptr, + m_offset + it->ptCtrl.x, m_yPos + it->ptCtrl.y, 0, 0, + SWP_NOZORDER | SWP_NOSIZE); + + m_yPos += it->szBlock.cy; + m_yPos += m_ySpacing; } - if (minX > rcWindow.left + 5) { - int dx = (minX - rcWindow.left) / 2; - oldChild = nullptr; - hWndChild = GetWindow(hwndStatic, GW_CHILD); - while (hWndChild != oldChild && hWndChild != nullptr) { - DWORD style = GetWindowLongPtr(hWndChild, GWL_STYLE); - RECT rc; - GetWindowRect(hWndChild, &rc); - if ((style & SS_RIGHT) && !(style & WS_TABSTOP)) - MoveWindow(hWndChild, rc.left - rcWindow.left, rc.top - rcWindow.top, rc.right - rc.left - dx, rc.bottom - rc.top, TRUE); - else - MoveWindow(hWndChild, rc.left - dx - rcWindow.left, rc.top - rcWindow.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); - oldChild = hWndChild; - hWndChild = GetWindow(hWndChild, GW_HWNDNEXT); - } + *formHeight = m_yPos + (m_bCompact ? 0 : 9); +} + +void TJabberFormLayoutInfo::PositionControl(TJabberFormControlInfo *item, const char *labelStr, const char *valueStr) +{ + Utf2T wszLabel(labelStr), wszValue(valueStr); + + RECT rcLabel = { 0 }, rcCtrl = { 0 }; + if (item->hLabel) { + SetRect(&rcLabel, 0, 0, m_width, 0); + HDC hdc = GetDC(item->hLabel); + HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hLabel, WM_GETFONT, 0, 0)); + DrawTextW(hdc, wszLabel, -1, &rcLabel, DT_CALCRECT | DT_WORDBREAK); + SelectObject(hdc, hfntSave); + ReleaseDC(item->hLabel, hdc); + } + + int indent = m_bCompact ? 10 : 20; + + if ((m_bCompact && (item->type != JFORM_CTYPE_BOOLEAN) && (item->type != JFORM_CTYPE_FIXED)) || + (rcLabel.right >= m_maxLabelWidth) || + (rcLabel.bottom > m_ctrlHeight) || + (item->type == JFORM_CTYPE_LIST_MULTI) || + (item->type == JFORM_CTYPE_TEXT_MULTI)) { + int height = m_ctrlHeight; + if ((item->type == JFORM_CTYPE_LIST_MULTI) || (item->type == JFORM_CTYPE_TEXT_MULTI)) height *= 3; + SetRect(&rcCtrl, indent, rcLabel.bottom, m_width, rcLabel.bottom + height); + } + else if (item->type == JFORM_CTYPE_BOOLEAN) { + SetRect(&rcCtrl, 0, 0, m_width - 20, 0); + HDC hdc = GetDC(item->hCtrl); + HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hCtrl, WM_GETFONT, 0, 0)); + DrawText(hdc, wszLabel, -1, &rcCtrl, DT_CALCRECT | DT_RIGHT | DT_WORDBREAK); + SelectObject(hdc, hfntSave); + ReleaseDC(item->hCtrl, hdc); + rcCtrl.right += 20; } + else if (item->type == JFORM_CTYPE_FIXED) { + SetRect(&rcCtrl, 0, 0, m_width, 0); + HDC hdc = GetDC(item->hCtrl); + HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hCtrl, WM_GETFONT, 0, 0)); + DrawText(hdc, wszValue, -1, &rcCtrl, DT_CALCRECT | DT_EDITCONTROL); + rcCtrl.right += 20; + SelectObject(hdc, hfntSave); + ReleaseDC(item->hCtrl, hdc); + } + else { + SetRect(&rcCtrl, rcLabel.right + 5, 0, m_width, m_ctrlHeight); + rcLabel.bottom = rcCtrl.bottom; + } + + if (item->hLabel) + SetWindowPos(item->hLabel, nullptr, 0, 0, rcLabel.right - rcLabel.left, rcLabel.bottom - rcLabel.top, SWP_NOZORDER | SWP_NOMOVE); + if (item->hCtrl) + SetWindowPos(item->hCtrl, nullptr, 0, 0, rcCtrl.right - rcCtrl.left, rcCtrl.bottom - rcCtrl.top, SWP_NOZORDER | SWP_NOMOVE); + + item->ptLabel.x = rcLabel.left; + item->ptLabel.y = rcLabel.top; + item->ptCtrl.x = rcCtrl.left; + item->ptCtrl.y = rcCtrl.top; + item->szBlock.cx = m_width; + item->szBlock.cy = max(rcLabel.bottom, rcCtrl.bottom); } +///////////////////////////////////////////////////////////////////////////////////////// + void JabberFormSetInstruction(HWND hwndForm, const char *text) { CMStringW buf(text == nullptr ? "" : text); @@ -197,162 +354,6 @@ static TJabberFormControlType JabberFormTypeNameToId(const char *type) return JFORM_CTYPE_TEXT_SINGLE; } -void JabberFormLayoutSingleControl(TJabberFormControlInfo *item, TJabberFormLayoutInfo *layout_info, const char *labelStr, const char *valueStr) -{ - Utf2T wszLabel(labelStr), wszValue(valueStr); - - RECT rcLabel = { 0 }, rcCtrl = { 0 }; - if (item->hLabel) { - SetRect(&rcLabel, 0, 0, layout_info->width, 0); - HDC hdc = GetDC(item->hLabel); - HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hLabel, WM_GETFONT, 0, 0)); - DrawTextW(hdc, wszLabel, -1, &rcLabel, DT_CALCRECT | DT_WORDBREAK); - SelectObject(hdc, hfntSave); - ReleaseDC(item->hLabel, hdc); - } - - int indent = layout_info->compact ? 10 : 20; - - if ((layout_info->compact && (item->type != JFORM_CTYPE_BOOLEAN) && (item->type != JFORM_CTYPE_FIXED)) || - (rcLabel.right >= layout_info->maxLabelWidth) || - (rcLabel.bottom > layout_info->ctrlHeight) || - (item->type == JFORM_CTYPE_LIST_MULTI) || - (item->type == JFORM_CTYPE_TEXT_MULTI)) { - int height = layout_info->ctrlHeight; - if ((item->type == JFORM_CTYPE_LIST_MULTI) || (item->type == JFORM_CTYPE_TEXT_MULTI)) height *= 3; - SetRect(&rcCtrl, indent, rcLabel.bottom, layout_info->width, rcLabel.bottom + height); - } - else if (item->type == JFORM_CTYPE_BOOLEAN) { - SetRect(&rcCtrl, 0, 0, layout_info->width - 20, 0); - HDC hdc = GetDC(item->hCtrl); - HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hCtrl, WM_GETFONT, 0, 0)); - DrawText(hdc, wszLabel, -1, &rcCtrl, DT_CALCRECT | DT_RIGHT | DT_WORDBREAK); - SelectObject(hdc, hfntSave); - ReleaseDC(item->hCtrl, hdc); - rcCtrl.right += 20; - } - else if (item->type == JFORM_CTYPE_FIXED) { - SetRect(&rcCtrl, 0, 0, layout_info->width, 0); - HDC hdc = GetDC(item->hCtrl); - HFONT hfntSave = (HFONT)SelectObject(hdc, (HFONT)SendMessage(item->hCtrl, WM_GETFONT, 0, 0)); - DrawText(hdc, wszValue, -1, &rcCtrl, DT_CALCRECT | DT_EDITCONTROL); - rcCtrl.right += 20; - SelectObject(hdc, hfntSave); - ReleaseDC(item->hCtrl, hdc); - } - else { - SetRect(&rcCtrl, rcLabel.right + 5, 0, layout_info->width, layout_info->ctrlHeight); - rcLabel.bottom = rcCtrl.bottom; - } - - if (item->hLabel) - SetWindowPos(item->hLabel, nullptr, 0, 0, rcLabel.right - rcLabel.left, rcLabel.bottom - rcLabel.top, SWP_NOZORDER | SWP_NOMOVE); - if (item->hCtrl) - SetWindowPos(item->hCtrl, nullptr, 0, 0, rcCtrl.right - rcCtrl.left, rcCtrl.bottom - rcCtrl.top, SWP_NOZORDER | SWP_NOMOVE); - - item->ptLabel.x = rcLabel.left; - item->ptLabel.y = rcLabel.top; - item->ptCtrl.x = rcCtrl.left; - item->ptCtrl.y = rcCtrl.top; - item->szBlock.cx = layout_info->width; - item->szBlock.cy = max(rcLabel.bottom, rcCtrl.bottom); -} - -#define JabberFormCreateLabel() \ - CreateWindow(L"static", wszLabel, WS_CHILD|WS_VISIBLE|SS_CENTERIMAGE, \ - 0, 0, 0, 0, hwndStatic, (HMENU)-1, g_plugin.getInst(), nullptr) - -HJFORMCTRL JabberFormAppendControl(HWND hwndStatic, HJFORMLAYOUT layout_info, TJabberFormControlType type, const char *labelStr, const char *valueStr) -{ - TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(hwndStatic, GWLP_USERDATA); - if (!controls) { - controls = new TJabberFormControlList(5); - SetWindowLongPtr(hwndStatic, GWLP_USERDATA, (LONG_PTR)controls); - } - - TJabberFormControlInfo *item = (TJabberFormControlInfo *)mir_alloc(sizeof(TJabberFormControlInfo)); - item->type = type; - item->hLabel = item->hCtrl = nullptr; - Utf2T wszLabel(labelStr), wszValue(valueStr); - - switch (type) { - case JFORM_CTYPE_TEXT_PRIVATE: - item->hLabel = JabberFormCreateLabel(); - item->hCtrl = CreateWindowEx(WS_EX_CLIENTEDGE, L"edit", wszValue, - WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL | ES_PASSWORD, - 0, 0, 0, 0, - hwndStatic, (HMENU)layout_info->id, g_plugin.getInst(), nullptr); - ++layout_info->id; - break; - - case JFORM_CTYPE_TEXT_MULTI: - item->hLabel = JabberFormCreateLabel(); - item->hCtrl = CreateWindowEx(WS_EX_CLIENTEDGE, L"edit", wszValue, - WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN, - 0, 0, 0, 0, - hwndStatic, (HMENU)layout_info->id, g_plugin.getInst(), nullptr); - mir_subclassWindow(item->hCtrl, JabberFormMultiLineWndProc); - ++layout_info->id; - break; - - case JFORM_CTYPE_BOOLEAN: - item->hCtrl = CreateWindowEx(0, L"button", wszLabel, - WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_AUTOCHECKBOX | BS_MULTILINE, - 0, 0, 0, 0, - hwndStatic, (HMENU)layout_info->id, g_plugin.getInst(), nullptr); - if (valueStr && !mir_wstrcmp(wszValue, L"1")) - SendMessage(item->hCtrl, BM_SETCHECK, 1, 0); - ++layout_info->id; - break; - - case JFORM_CTYPE_LIST_SINGLE: - item->hLabel = JabberFormCreateLabel(); - item->hCtrl = CreateWindowExA(WS_EX_CLIENTEDGE, "combobox", nullptr, - WS_CHILD | WS_VISIBLE | WS_TABSTOP | CBS_DROPDOWNLIST, - 0, 0, 0, 0, - hwndStatic, (HMENU)layout_info->id, g_plugin.getInst(), nullptr); - ++layout_info->id; - break; - - case JFORM_CTYPE_LIST_MULTI: - item->hLabel = JabberFormCreateLabel(); - item->hCtrl = CreateWindowExA(WS_EX_CLIENTEDGE, "listbox", - nullptr, WS_CHILD | WS_VISIBLE | WS_TABSTOP | LBS_MULTIPLESEL, - 0, 0, 0, 0, - hwndStatic, (HMENU)layout_info->id, g_plugin.getInst(), nullptr); - ++layout_info->id; - break; - - case JFORM_CTYPE_FIXED: - item->hCtrl = CreateWindow(L"edit", wszValue, - WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_READONLY | ES_AUTOHSCROLL, - 0, 0, 0, 0, - hwndStatic, (HMENU)-1, g_plugin.getInst(), nullptr); - break; - - case JFORM_CTYPE_HIDDEN: - break; - - case JFORM_CTYPE_TEXT_SINGLE: - item->hLabel = labelStr ? (JabberFormCreateLabel()) : nullptr; - item->hCtrl = CreateWindowEx(WS_EX_CLIENTEDGE, L"edit", wszValue, - WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL, - 0, 0, 0, 0, - hwndStatic, (HMENU)layout_info->id, g_plugin.getInst(), nullptr); - ++layout_info->id; - break; - } - - HFONT hFont = (HFONT)SendMessage(GetParent(hwndStatic), WM_GETFONT, 0, 0); - if (item->hLabel) SendMessage(item->hLabel, WM_SETFONT, (WPARAM)hFont, 0); - if (item->hCtrl) SendMessage(item->hCtrl, WM_SETFONT, (WPARAM)hFont, 0); - - JabberFormLayoutSingleControl(item, layout_info, labelStr, valueStr); - - controls->insert(item); - return item; -} - static void JabberFormAddListItem(TJabberFormControlInfo *item, const char *text, bool selected) { Utf2T wszText(text); @@ -371,101 +372,45 @@ static void JabberFormAddListItem(TJabberFormControlInfo *item, const char *text } } -void JabberFormLayoutControls(HWND hwndStatic, HJFORMLAYOUT layout_info, int *formHeight) -{ - TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(hwndStatic, GWLP_USERDATA); - if (!controls) return; - - for (auto &it : *controls) { - if (it->hLabel) - SetWindowPos(it->hLabel, nullptr, - layout_info->offset + it->ptLabel.x, layout_info->y_pos + it->ptLabel.y, 0, 0, - SWP_NOZORDER | SWP_NOSIZE); - - if (it->hCtrl) - SetWindowPos(it->hCtrl, nullptr, - layout_info->offset + it->ptCtrl.x, layout_info->y_pos + it->ptCtrl.y, 0, 0, - SWP_NOZORDER | SWP_NOSIZE); - - layout_info->y_pos += it->szBlock.cy; - layout_info->y_pos += layout_info->y_spacing; - } - - *formHeight = layout_info->y_pos + (layout_info->compact ? 0 : 9); -} - -HJFORMLAYOUT JabberFormCreateLayout(HWND hwndStatic) -{ - RECT frameRect; - GetClientRect(hwndStatic, &frameRect); - - TJabberFormLayoutInfo *layout_info = (TJabberFormLayoutInfo *)mir_alloc(sizeof(TJabberFormLayoutInfo)); - layout_info->compact = false; - layout_info->ctrlHeight = 20; - layout_info->id = 0; - layout_info->width = frameRect.right - frameRect.left - 20 - 10; - layout_info->y_spacing = 5; - layout_info->maxLabelWidth = layout_info->width * 2 / 5; - layout_info->offset = 10; - layout_info->y_pos = 14; - return layout_info; -} - void JabberFormCreateUI(HWND hwndStatic, TiXmlElement *xNode, int *formHeight, BOOL bCompact) { JabberFormDestroyUI(hwndStatic); - const char *typeName, *str, *valueText, *labelStr; - char *valueStr; - if (xNode == nullptr || xNode->Name() == nullptr || mir_strcmp(xNode->Name(), "x") || hwndStatic == nullptr) return; - RECT frameRect; - GetClientRect(hwndStatic, &frameRect); - - TJabberFormLayoutInfo layout_info; - layout_info.compact = bCompact ? true : false; - layout_info.ctrlHeight = 20; - layout_info.id = 0; - layout_info.width = frameRect.right - frameRect.left - 20; - if (!bCompact) layout_info.width -= 10; - layout_info.y_spacing = bCompact ? 1 : 5; - layout_info.maxLabelWidth = layout_info.width * 2 / 5; - layout_info.offset = 10; - layout_info.y_pos = bCompact ? 0 : 14; - for (auto *n : TiXmlFilter(xNode, "field")) { - if ((typeName = n->Attribute("type")) == nullptr) - continue; + TJabberFormLayoutInfo layout_info(hwndStatic, bCompact); - if (auto *label = n->Attribute("label")) - labelStr = label; - else + CMStringA valueStr; + for (auto *n : TiXmlFilter(xNode, "field")) { + const char *labelStr = n->Attribute("label"); + if (labelStr == nullptr) labelStr = n->Attribute("var"); - TJabberFormControlType type = JabberFormTypeNameToId(typeName); + TJabberFormControlType type = JabberFormTypeNameToId(n->Attribute("type")); + const char *str, *valueText; if (auto *v = n->FirstChildElement("value")) { valueText = v->GetText(); if (type != JFORM_CTYPE_TEXT_MULTI) - valueStr = mir_strdup(valueText); + valueStr = valueText; else { - CMStringA tmp; + valueStr.Empty(); for (auto *it : TiXmlEnum(n)) { if (it->Name() && !mir_strcmp(it->Name(), "value") && it->GetText()) { - if (!tmp.IsEmpty()) - tmp.Append("\r\n"); - tmp.Append(it->GetText()); + if (!valueStr.IsEmpty()) + valueStr.Append("\r\n"); + valueStr.Append(it->GetText()); } } - valueStr = tmp.Detach(); } } - else valueText = valueStr = nullptr; + else valueText = nullptr, valueStr.Empty(); - TJabberFormControlInfo *item = JabberFormAppendControl(hwndStatic, &layout_info, type, labelStr, valueStr); + TJabberFormControlInfo *item = layout_info.AppendControl(type, labelStr, valueStr); - mir_free(valueStr); + if (n->FirstChildElement("required")) + item->bRequired = true; if (type == JFORM_CTYPE_LIST_SINGLE) { for (auto *o : TiXmlFilter(n, "option")) { @@ -504,7 +449,7 @@ void JabberFormCreateUI(HWND hwndStatic, TiXmlElement *xNode, int *formHeight, B } } - JabberFormLayoutControls(hwndStatic, &layout_info, formHeight); + layout_info.OrderControls(formHeight); } void JabberFormDestroyUI(HWND hwndStatic) @@ -518,23 +463,26 @@ void JabberFormDestroyUI(HWND hwndStatic) } } -TiXmlElement* JabberFormGetData(HWND hwndStatic, TiXmlDocument *doc, TiXmlElement *xNode) +void JabberFormGetData(HWND hwndStatic, TiXmlElement *xRoot, TiXmlElement *xNode) { - const char *varName, *type, *labelText, *str2; + const char *varName, *labelText, *str2; wchar_t *p, *q, *str; if (xNode == nullptr || xNode->Name() == nullptr || mir_strcmp(xNode->Name(), "x") || hwndStatic == nullptr) - return nullptr; + return; HWND hFrame = hwndStatic; int id = 0; - XmlNode x("x"); - x << XATTR("xmlns", JABBER_FEAT_DATA_FORMS) << XATTR("type", "submit"); + auto *x = xRoot << XCHILD("x") << XATTR("xmlns", JABBER_FEAT_DATA_FORMS) << XATTR("type", "submit"); for (auto *n : TiXmlFilter(xNode, "field")) { - if ((varName = n->Attribute("var")) == nullptr || (type = n->Attribute("type")) == nullptr) + if ((varName = n->Attribute("var")) == nullptr) continue; + const char *type = n->Attribute("type"); + if (type == nullptr) + type = "text-single"; + HWND hCtrl = GetDlgItem(hFrame, id); TiXmlElement *field = x << XCHILD("field") << XATTR("var", varName); @@ -617,164 +565,155 @@ TiXmlElement* JabberFormGetData(HWND hwndStatic, TiXmlDocument *doc, TiXmlElemen id++; } } - - return x.ToElement()->DeepClone(doc)->ToElement(); } -class CJabberFormDlg : public CJabberDlgBase +CJabberFormDlg::CJabberFormDlg(CJabberProto *ppro, const TiXmlElement *xNode, char *defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata) : + CSuper(ppro, IDD_FORM), + btnSubmit(this, IDC_SUBMIT), + btnCancel(this, IDCANCEL), + m_pfnSubmit(pfnSubmit), + m_pUserdata(userdata), + m_defTitle(mir_strdup(defTitle)) { - typedef CJabberDlgBase CSuper; + m_xNode = xNode->DeepClone(&m_doc)->ToElement(); - TiXmlDocument m_doc; - TiXmlElement *m_xNode; + btnSubmit.OnClick = Callback(this, &CJabberFormDlg::onClick_Submit); + btnCancel.OnClick = Callback(this, &CJabberFormDlg::onClick_Cancel); +} - ptrA m_defTitle; // Default title if no in xNode - JABBER_FORM_SUBMIT_FUNC m_pfnSubmit; - void *m_pUserdata; +bool CJabberFormDlg::OnInitDialog() +{ + // Set dialog title + if (auto *pszText = XmlGetChildText(m_xNode, "title")) + SetWindowTextUtf(m_hwnd, pszText); + else + SetWindowTextUtf(m_hwnd, TranslateU(m_defTitle)); + + // Set instruction field + if (auto *pszText = XmlGetChildText(m_xNode, "instructions")) + JabberFormSetInstruction(m_hwnd, pszText); + else if (pszText = XmlGetChildText(m_xNode, "title")) + JabberFormSetInstruction(m_hwnd, pszText); + else + JabberFormSetInstruction(m_hwnd, TranslateU(m_defTitle)); + + // Create form + if (m_xNode != nullptr) { + RECT rect; + GetClientRect(GetDlgItem(m_hwnd, IDC_FRAME), &m_frameRect); + GetClientRect(GetDlgItem(m_hwnd, IDC_VSCROLL), &rect); + m_frameRect.right -= (rect.right - rect.left); + GetClientRect(GetDlgItem(m_hwnd, IDC_FRAME), &rect); + m_frameHeight = rect.bottom - rect.top; + JabberFormCreateUI(GetDlgItem(m_hwnd, IDC_FRAME), m_xNode, &m_formHeight); + } - RECT m_frameRect; // Clipping region of the frame to scroll - int m_frameHeight; // Height of the frame (can be eliminated, redundant to frameRect) - int m_formHeight; // Actual height of the form - int m_curPos; // Current scroll position + m_curPos = 0; + HWND hwndScroll = GetDlgItem(m_hwnd, IDC_VSCROLL); + if (m_formHeight > m_frameHeight) { + EnableWindow(hwndScroll, TRUE); + SetScrollRange(hwndScroll, SB_CTL, 0, m_formHeight - m_frameHeight, FALSE); + } + else { + ShowWindow(hwndScroll, SW_HIDE); + SetScrollRange(hwndScroll, SB_CTL, 0, 0, FALSE); + } - CCtrlButton btnSubmit; + // Enable WS_EX_CONTROLPARENT on IDC_FRAME (so tab stop goes through all its children) + LONG frameExStyle = GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_FRAME), GWL_EXSTYLE); + frameExStyle |= WS_EX_CONTROLPARENT; + SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_FRAME), GWL_EXSTYLE, frameExStyle); -public: - CJabberFormDlg(CJabberProto *ppro, const TiXmlElement *xNode, char *defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata) : - CSuper(ppro, IDD_FORM), - btnSubmit(this, IDC_SUBMIT), - m_pfnSubmit(pfnSubmit), - m_pUserdata(userdata), - m_defTitle(mir_strdup(defTitle)) - { - m_xNode = xNode->DeepClone(&m_doc)->ToElement(); + if (m_pfnSubmit != nullptr) + EnableWindow(GetDlgItem(m_hwnd, IDC_SUBMIT), TRUE); + return true; +} - btnSubmit.OnClick = Callback(this, &CJabberFormDlg::onClick_Submit); - } +void CJabberFormDlg::OnDestroy() +{ + JabberFormDestroyUI(GetDlgItem(m_hwnd, IDC_FRAME)); + mir_free(m_pUserdata); +} - bool OnInitDialog() override - { - ShowWindow(GetDlgItem(m_hwnd, IDC_FRAME_TEXT), SW_HIDE); - - // Set dialog title - if (auto *pszText = XmlGetChildText(m_xNode, "title")) - SetWindowTextUtf(m_hwnd, pszText); - else - SetWindowTextUtf(m_hwnd, TranslateU(m_defTitle)); - - // Set instruction field - if (auto *pszText = XmlGetChildText(m_xNode, "instructions")) - JabberFormSetInstruction(m_hwnd, pszText); - else if (pszText = XmlGetChildText(m_xNode, "title")) - JabberFormSetInstruction(m_hwnd, pszText); - else - JabberFormSetInstruction(m_hwnd, TranslateU(m_defTitle)); - - // Create form - if (m_xNode != nullptr) { - RECT rect; - GetClientRect(GetDlgItem(m_hwnd, IDC_FRAME), &(m_frameRect)); - GetClientRect(GetDlgItem(m_hwnd, IDC_VSCROLL), &rect); - m_frameRect.right -= (rect.right - rect.left); - GetClientRect(GetDlgItem(m_hwnd, IDC_FRAME), &rect); - m_frameHeight = rect.bottom - rect.top; - JabberFormCreateUI(GetDlgItem(m_hwnd, IDC_FRAME), m_xNode, &(m_formHeight)); +INT_PTR CJabberFormDlg::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_CTLCOLORSTATIC: + if ((GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_WHITERECT) || + (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_INSTRUCTION) || + (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_TITLE)) { + return (INT_PTR)GetStockObject(WHITE_BRUSH); } - - if (m_formHeight > m_frameHeight) { - HWND hwndScroll = GetDlgItem(m_hwnd, IDC_VSCROLL); - EnableWindow(hwndScroll, TRUE); - SetScrollRange(hwndScroll, SB_CTL, 0, m_formHeight - m_frameHeight, FALSE); - m_curPos = 0; + return 0; + + case WM_MOUSEWHEEL: + { + short zDelta = GET_WHEEL_DELTA_WPARAM(wParam); + if (zDelta) { + int nScrollLines = 0; + SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, (void*)&nScrollLines, 0); + for (int i = 0; i < (nScrollLines + 1) / 2; i++) + SendMessage(m_hwnd, WM_VSCROLL, (zDelta < 0) ? SB_LINEDOWN : SB_LINEUP, 0); + } } + break; - // Enable WS_EX_CONTROLPARENT on IDC_FRAME (so tab stop goes through all its children) - LONG frameExStyle = GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_FRAME), GWL_EXSTYLE); - frameExStyle |= WS_EX_CONTROLPARENT; - SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_FRAME), GWL_EXSTYLE, frameExStyle); - - if (m_pfnSubmit != nullptr) - EnableWindow(GetDlgItem(m_hwnd, IDC_SUBMIT), TRUE); - return true; - } - - void OnDestroy() override - { - JabberFormDestroyUI(GetDlgItem(m_hwnd, IDC_FRAME)); - mir_free(m_pUserdata); - } - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override - { - switch (msg) { - case WM_CTLCOLORSTATIC: - if ((GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_WHITERECT) || - (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_INSTRUCTION) || - (GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_TITLE)) { - return (INT_PTR)GetStockObject(WHITE_BRUSH); - } - return 0; - - case WM_MOUSEWHEEL: - { - short zDelta = GET_WHEEL_DELTA_WPARAM(wParam); - if (zDelta) { - int nScrollLines = 0; - SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, (void*)&nScrollLines, 0); - for (int i = 0; i < (nScrollLines + 1) / 2; i++) - SendMessage(m_hwnd, WM_VSCROLL, (zDelta < 0) ? SB_LINEDOWN : SB_LINEUP, 0); - } - } + case WM_VSCROLL: + int pos = m_curPos; + switch (LOWORD(wParam)) { + case SB_LINEDOWN: + pos += 15; break; - - case WM_VSCROLL: - int pos = m_curPos; - switch (LOWORD(wParam)) { - case SB_LINEDOWN: - pos += 15; - break; - case SB_LINEUP: - pos -= 15; - break; - case SB_PAGEDOWN: - pos += (m_frameHeight - 10); - break; - case SB_PAGEUP: - pos -= (m_frameHeight - 10); - break; - case SB_THUMBTRACK: - pos = HIWORD(wParam); - break; - } - if (pos > (m_formHeight - m_frameHeight)) - pos = m_formHeight - m_frameHeight; - if (pos < 0) - pos = 0; - if (m_curPos != pos) { - ScrollWindow(GetDlgItem(m_hwnd, IDC_FRAME), 0, m_curPos - pos, nullptr, &(m_frameRect)); - SetScrollPos(GetDlgItem(m_hwnd, IDC_VSCROLL), SB_CTL, pos, TRUE); - m_curPos = pos; - } + case SB_LINEUP: + pos -= 15; + break; + case SB_PAGEDOWN: + pos += (m_frameHeight - 10); break; + case SB_PAGEUP: + pos -= (m_frameHeight - 10); + break; + case SB_THUMBTRACK: + pos = HIWORD(wParam); + break; + } + if (pos > (m_formHeight - m_frameHeight)) + pos = m_formHeight - m_frameHeight; + if (pos < 0) + pos = 0; + if (m_curPos != pos) { + ScrollWindow(GetDlgItem(m_hwnd, IDC_FRAME), 0, m_curPos - pos, nullptr, &(m_frameRect)); + SetScrollPos(GetDlgItem(m_hwnd, IDC_VSCROLL), SB_CTL, pos, TRUE); + m_curPos = pos; } - return CSuper::DlgProc(msg, wParam, lParam); + break; } + return CSuper::DlgProc(msg, wParam, lParam); +} - void onClick_Submit(CCtrlButton*) - { - TiXmlElement *n = JabberFormGetData(GetDlgItem(m_hwnd, IDC_FRAME), &m_doc, m_xNode); - (m_proto->*(m_pfnSubmit))(n, m_pUserdata); - Close(); - } -}; +void CJabberFormDlg::onClick_Submit(CCtrlButton*) +{ + (m_proto->*(m_pfnSubmit))(this, m_pUserdata); + Close(); +} + +void CJabberFormDlg::onClick_Cancel(CCtrlButton*) +{ + if (m_pfnCancel) + (m_proto->*(m_pfnCancel))(this, m_pUserdata); +} static void CALLBACK JabberFormCreateDialogApcProc(void *param) { ((CJabberFormDlg*)param)->Show(); } -void CJabberProto::FormCreateDialog(const TiXmlElement *xNode, char *defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata) +void CJabberFormDlg::GetData(TiXmlElement *xDest) +{ + JabberFormGetData(GetDlgItem(m_hwnd, IDC_FRAME), xDest, m_xNode); +} + +void CJabberFormDlg::Display() { - auto *pDlg = new CJabberFormDlg(this, xNode, defTitle, pfnSubmit, userdata); - CallFunctionAsync(JabberFormCreateDialogApcProc, pDlg); + CallFunctionAsync(JabberFormCreateDialogApcProc, this); } diff --git a/protocols/JabberG/src/jabber_iqid_muc.cpp b/protocols/JabberG/src/jabber_iqid_muc.cpp index 2043ac4b45..03c9fff902 100644 --- a/protocols/JabberG/src/jabber_iqid_muc.cpp +++ b/protocols/JabberG/src/jabber_iqid_muc.cpp @@ -27,12 +27,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "jabber_iq.h" #include "jabber_caps.h" -void CJabberProto::SetMucConfig(TiXmlElement *node, void *from) +void CJabberProto::SetMucConfig(CJabberFormDlg *pDlg, void *from) { if (m_ThreadInfo && from) { XmlNodeIq iq("set", SerialNext(), (char*)from); - TiXmlElement *query = iq << XQUERY(JABBER_FEAT_MUC_OWNER); - query->InsertEndChild(node); + auto *query = iq << XQUERY(JABBER_FEAT_MUC_OWNER); + pDlg->GetData(query); m_ThreadInfo->send(iq); } } @@ -50,7 +50,7 @@ void CJabberProto::OnIqResultGetMuc(const TiXmlElement *iqNode, CJabberIqInfo*) if (!mir_strcmp(type, "result")) if (auto *queryNode = XmlGetChildByTag(iqNode, "query", "xmlns", JABBER_FEAT_MUC_OWNER)) if (auto *xNode = XmlGetChildByTag(queryNode, "x", "xmlns", JABBER_FEAT_DATA_FORMS)) - FormCreateDialog(xNode, "Jabber Conference Room Configuration", &CJabberProto::SetMucConfig, mir_strdup(from)); + (new CJabberFormDlg(this, xNode, "Jabber Conference Room Configuration", &CJabberProto::SetMucConfig, mir_strdup(from)))->Display(); } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h index d0f42a7731..4714ce05fa 100755 --- a/protocols/JabberG/src/jabber_proto.h +++ b/protocols/JabberG/src/jabber_proto.h @@ -43,6 +43,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. struct CJabberProto; class CJabberMucJidListDlg; +class CJabberFormDlg; +typedef void (CJabberProto::*JABBER_FORM_SUBMIT_FUNC)(CJabberFormDlg *pDlg, void *userdata); + enum TJabberGcLogInfoType { INFO_BAN, INFO_STATUS, INFO_CONFIG, INFO_AFFILIATION, INFO_ROLE }; typedef UNIQUE_MAP<wchar_t, TCharKeyCmp> U_TCHAR_MAP; @@ -456,10 +459,6 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface void RenameParticipantNick(JABBER_LIST_ITEM *item, const char *oldNick, const TiXmlElement *itemNode); void AcceptGroupchatInvite(const char *roomJid, const char *reason, const char *password); - //---- jabber_form.c ----------------------------------------------------------------- - - void FormCreateDialog(const TiXmlElement *xNode, char* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata); - //---- jabber_ft.c ------------------------------------------------------------------- void __cdecl FileReceiveThread(filetransfer *ft); @@ -580,7 +579,7 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface CJabberMucJidListDlg *m_pDlgMucBanList, *m_pDlgMucAdminList, *m_pDlgMucOwnerList; CJabberMucJidListDlg *& GetMucDlg(JABBER_MUC_JIDLIST_TYPE); - void SetMucConfig(TiXmlElement *node, void *from); + void SetMucConfig(CJabberFormDlg *pDlg, void *from); void MucShutdown(void); void OnIqResultMucGetJidList(const TiXmlElement *iqNode, JABBER_MUC_JIDLIST_TYPE listType); @@ -779,10 +778,6 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface void OnProcessPresence(const TiXmlElement *node, ThreadData *info); void OnProcessPresenceCapabilites(const TiXmlElement *node, pResourceStatus &resource); void OnProcessPubsubEvent(const TiXmlElement *node); - //XEP-0198 specific types handlers - void OnProcessSMa(const TiXmlElement *node, ThreadData *info); - void OnProcessSMr(const TiXmlElement *node, ThreadData *info); - void OnProcessStreamOpening(const TiXmlElement *node, ThreadData *info); void OnProcessProtocol(const TiXmlElement *node, ThreadData *info); @@ -799,7 +794,8 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface BOOL OnProcessJingle(const TiXmlElement *node); void OnProcessIq(const TiXmlElement *node); - void SetRegConfig(TiXmlElement *node, void *from); + void SetRegConfig(CJabberFormDlg *pDlg, void *from); + void CancelRegConfig(CJabberFormDlg *pDlg, void *from); void OnProcessRegIq(const TiXmlElement *node, ThreadData *info); void OnPingReply(const TiXmlElement *node, CJabberIqInfo *pInfo); diff --git a/protocols/JabberG/src/jabber_search.cpp b/protocols/JabberG/src/jabber_search.cpp index 5d7b2f1f1a..05e19da136 100644 --- a/protocols/JabberG/src/jabber_search.cpp +++ b/protocols/JabberG/src/jabber_search.cpp @@ -743,8 +743,7 @@ HWND CJabberProto::SearchAdvanced(HWND hwndDlg) // Forms: XEP-0055 Example 7 if (dat->fSearchRequestIsXForm) { fRequestNotEmpty = TRUE; - TiXmlElement *n = JabberFormGetData(GetDlgItem(hwndDlg, IDC_FRAME), &iq, dat->xNode); - query->InsertEndChild(n); + JabberFormGetData(GetDlgItem(hwndDlg, IDC_FRAME), query, dat->xNode); } else { //and Simple fields: XEP-0055 Example 3 for (int i = 0; i < dat->nJSInfCount; i++) { diff --git a/protocols/JabberG/src/jabber_strm_mgmt.h b/protocols/JabberG/src/jabber_strm_mgmt.h index 5c249e6fad..4bab5e4045 100755 --- a/protocols/JabberG/src/jabber_strm_mgmt.h +++ b/protocols/JabberG/src/jabber_strm_mgmt.h @@ -27,6 +27,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. struct CJabberProto; +// XEP-0198 processing + class strm_mgmt { void OnProcessSMa(const TiXmlElement *node); diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp index 40c40ab336..439ed33d69 100755 --- a/protocols/JabberG/src/jabber_thread.cpp +++ b/protocols/JabberG/src/jabber_thread.cpp @@ -1891,7 +1891,13 @@ void CJabberProto::OnProcessIq(const TiXmlElement *node) } } -void CJabberProto::SetRegConfig(TiXmlElement *node, void *from) +void CJabberProto::CancelRegConfig(CJabberFormDlg*, void*) +{ + if (g_pRegInfo) + SendMessage(g_pRegInfo->conn.reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, (LPARAM)TranslateT("Registration canceled")); +} + +void CJabberProto::SetRegConfig(CJabberFormDlg *pDlg, void *from) { if (g_pRegInfo) { iqIdRegSetReg = SerialNext(); @@ -1901,7 +1907,7 @@ void CJabberProto::SetRegConfig(TiXmlElement *node, void *from) XmlNodeIq iq("set", iqIdRegSetReg, (const char*)from); iq << XATTR("from", text); TiXmlElement *query = iq << XQUERY(JABBER_FEAT_REGISTER); - query->InsertEndChild(node); + pDlg->GetData(query); g_pRegInfo->send(iq); } } @@ -1924,7 +1930,11 @@ void CJabberProto::OnProcessRegIq(const TiXmlElement *node, ThreadData *info) if (xNode != nullptr) { if (!mir_strcmp(xNode->Attribute("xmlns"), JABBER_FEAT_DATA_FORMS)) { g_pRegInfo = info; - FormCreateDialog(xNode, "Jabber register new user", &CJabberProto::SetRegConfig, mir_strdup(node->Attribute("from"))); + + auto *pDlg = new CJabberFormDlg(this, xNode, "Jabber register new user", &CJabberProto::SetRegConfig, mir_strdup(node->Attribute("from"))); + pDlg->SetParent(info->conn.reg_hwndDlg); + pDlg->SetCancel(&CJabberProto::CancelRegConfig); + pDlg->Display(); return; } } diff --git a/protocols/JabberG/src/resource.h b/protocols/JabberG/src/resource.h index c87ccee302..3c8e7fb5cf 100644 --- a/protocols/JabberG/src/resource.h +++ b/protocols/JabberG/src/resource.h @@ -105,7 +105,6 @@ #define IDC_AGENT_BROWSE 1029 #define IDC_INSTRUCTION 1030 #define IDC_FRAME 1037 -#define IDC_FRAME_TEXT 1038 #define IDC_SIMPLE 1041 #define IDC_KEEPALIVE 1042 #define IDC_HOST 1043 diff --git a/protocols/JabberG/src/stdafx.h b/protocols/JabberG/src/stdafx.h index 79dfd30f72..1700c5f231 100755 --- a/protocols/JabberG/src/stdafx.h +++ b/protocols/JabberG/src/stdafx.h @@ -511,8 +511,6 @@ struct JABBER_MUC_JIDLIST_INFO : public MZeroedObject wchar_t* type2str(void) const; }; -typedef void (CJabberProto::*JABBER_FORM_SUBMIT_FUNC)(TiXmlElement *values, void *userdata); - //---- jabber_treelist.c ------------------------------------------------ typedef struct TTreeList_ItemInfo *HTREELISTITEM; @@ -636,17 +634,64 @@ enum TJabberFormControlType JFORM_CTYPE_FIXED, JFORM_CTYPE_HIDDEN, JFORM_CTYPE_TEXT_SINGLE }; -typedef struct TJabberFormControlInfo *HJFORMCTRL; -typedef struct TJabberFormLayoutInfo *HJFORMLAYOUT; +struct TJabberFormControlInfo; + +struct TJabberFormLayoutInfo +{ + TJabberFormLayoutInfo(HWND hwndCtrl, bool bCompact); + + TJabberFormControlInfo* AppendControl(TJabberFormControlType type, const char *labelStr, const char *valueStr); + HWND CreateLabel(const wchar_t *pwszLabel); + void OrderControls(int *formHeight); + void PositionControl(TJabberFormControlInfo *item, const char *labelStr, const char *valueStr); + + HWND m_hwnd; + int m_ctrlHeight; + int m_offset, m_width, m_maxLabelWidth; + int m_yPos, m_ySpacing; + int m_id; + bool m_bCompact; +}; void JabberFormCreateUI(HWND hwndStatic, TiXmlElement *xNode, int *formHeight, BOOL bCompact = FALSE); void JabberFormDestroyUI(HWND hwndStatic); +void JabberFormGetData(HWND hwndStatic, TiXmlElement* pRoot, TiXmlElement *xNode); void JabberFormSetInstruction(HWND hwndForm, const char *text); -HJFORMLAYOUT JabberFormCreateLayout(HWND hwndStatic); // use mir_free to destroy -HJFORMCTRL JabberFormAppendControl(HWND hwndStatic, HJFORMLAYOUT layout_info, TJabberFormControlType type, const char *labelStr, const char *valueStr); -void JabberFormLayoutControls(HWND hwndStatic, HJFORMLAYOUT layout_info, int *formHeight); -TiXmlElement* JabberFormGetData(HWND hwndStatic, TiXmlDocument *doc, TiXmlElement *xNode); +class CJabberFormDlg : public CJabberDlgBase +{ + typedef CJabberDlgBase CSuper; + + TiXmlDocument m_doc; + TiXmlElement *m_xNode; + + ptrA m_defTitle; // Default title if no <title/> in xNode + JABBER_FORM_SUBMIT_FUNC m_pfnSubmit, m_pfnCancel = nullptr; + void *m_pUserdata; + + RECT m_frameRect; // Clipping region of the frame to scroll + int m_frameHeight; // Height of the frame (can be eliminated, redundant to frameRect) + int m_formHeight; // Actual height of the form + int m_curPos; // Current scroll position + + CCtrlButton btnSubmit, btnCancel; + void onClick_Submit(CCtrlButton*); + void onClick_Cancel(CCtrlButton*); + +public: + CJabberFormDlg(CJabberProto *ppro, const TiXmlElement *xNode, char *defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata); + + void Display(); + void GetData(TiXmlElement *xDest); + + void SetCancel(JABBER_FORM_SUBMIT_FUNC pFunc) { + m_pfnCancel = pFunc; + } + + bool OnInitDialog() override; + void OnDestroy() override; + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override; +}; //---- jabber_icolib.c ---------------------------------------------- -- cgit v1.2.3