/* Jabber Protocol Plugin for Miranda IM Copyright (C) 2002-04 Santithorn Bunchua Copyright (C) 2005-12 George Hazan Copyright (C) 2012-13 Miranda NG Project This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "jabber.h" #include "jabber_caps.h" static LRESULT CALLBACK JabberFormMultiLineWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { //case WM_GETDLGCODE: // return DLGC_WANTARROWS|DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTALLKEYS; case WM_KEYDOWN: if (wParam == VK_TAB) { SetFocus(GetNextDlgTabItem(GetParent(GetParent(hwnd)), hwnd, GetKeyState(VK_SHIFT)<0?TRUE:FALSE)); return TRUE; }; break; } return mir_callNextSubclass(hwnd, JabberFormMultiLineWndProc, msg, wParam, lParam); } struct TJabberFormControlInfo { TJabberFormControlType type; SIZE szBlock; POINT ptLabel, ptCtrl; HWND hLabel, hCtrl; }; typedef LIST TJabberFormControlList; struct TJabberFormLayoutInfo { int ctrlHeight; int offset, width, maxLabelWidth; int y_pos, y_spacing; int id; bool compact; }; void JabberFormCenterContent(HWND hwndStatic) { RECT rcWindow; int minX; GetWindowRect(hwndStatic,&rcWindow); minX=rcWindow.right; HWND oldChild=NULL; HWND hWndChild=GetWindow(hwndStatic,GW_CHILD); while (hWndChild!=oldChild && hWndChild!=NULL) { DWORD style=GetWindowLongPtr(hWndChild, GWL_STYLE); RECT rc; GetWindowRect(hWndChild,&rc); if ((style&SS_RIGHT) && !(style&WS_TABSTOP)) { TCHAR * text; RECT calcRect=rc; int len=GetWindowTextLength(hWndChild); text=(TCHAR*)malloc(sizeof(TCHAR)*(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); } oldChild=hWndChild; hWndChild=GetWindow(hWndChild,GW_HWNDNEXT); } if (minX>rcWindow.left+5) { int dx=(minX-rcWindow.left)/2; oldChild=NULL; hWndChild=GetWindow(hwndStatic,GW_CHILD); while (hWndChild!=oldChild && hWndChild!=NULL) { 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); } } } void JabberFormSetInstruction(HWND hwndForm, const TCHAR *text) { if ( !text) text = _T(""); int len = lstrlen(text); int fixedLen = len; for (int i = 1; i < len; i++) if ((text[i - 1] == _T('\n')) && (text[i] != _T('\r'))) ++fixedLen; TCHAR *fixedText = NULL; if (fixedLen != len) { fixedText = (TCHAR *)mir_alloc(sizeof(TCHAR) * (fixedLen+1)); TCHAR *p = fixedText; for (int i = 0; i < len; i++) { *p = text[i]; if (i && (text[i] == _T('\n')) && (text[i] != _T('\r'))) { *p++ = _T('\r'); *p = _T('\n'); } ++p; } *p = 0; text = fixedText; } SetDlgItemText(hwndForm, IDC_INSTRUCTION, text); RECT rcText; GetWindowRect(GetDlgItem(hwndForm, IDC_INSTRUCTION), &rcText); int oldWidth = rcText.right-rcText.left; int deltaHeight = -(rcText.bottom-rcText.top); SetRect(&rcText, 0, 0, rcText.right-rcText.left, 0); HDC hdcEdit = GetDC(GetDlgItem(hwndForm, IDC_INSTRUCTION)); HFONT hfntSave = (HFONT)SelectObject(hdcEdit, (HFONT)SendDlgItemMessage(hwndForm, IDC_INSTRUCTION, WM_GETFONT, 0, 0)); DrawTextEx(hdcEdit, (TCHAR *)text, lstrlen(text), &rcText, DT_CALCRECT|DT_EDITCONTROL|DT_TOP|DT_WORDBREAK, NULL); SelectObject(hdcEdit, hfntSave); ReleaseDC(GetDlgItem(hwndForm, IDC_INSTRUCTION), hdcEdit); RECT rcWindow; GetClientRect(hwndForm, &rcWindow); if (rcText.bottom-rcText.top > (rcWindow.bottom-rcWindow.top)/5) { HWND hwndEdit = GetDlgItem(hwndForm, IDC_INSTRUCTION); SetWindowLongPtr(hwndEdit, GWL_STYLE, WS_VSCROLL | GetWindowLongPtr(hwndEdit, GWL_STYLE)); rcText.bottom = rcText.top + (rcWindow.bottom-rcWindow.top)/5; } else { HWND hwndEdit = GetDlgItem(hwndForm, IDC_INSTRUCTION); SetWindowLongPtr(hwndEdit, GWL_STYLE, ~WS_VSCROLL & GetWindowLongPtr(hwndEdit, GWL_STYLE)); } deltaHeight += rcText.bottom-rcText.top; SetWindowPos(GetDlgItem(hwndForm, IDC_INSTRUCTION), 0, 0, 0, oldWidth, rcText.bottom-rcText.top, SWP_NOMOVE|SWP_NOZORDER); GetWindowRect(GetDlgItem(hwndForm, IDC_WHITERECT), &rcText); MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); rcText.bottom += deltaHeight; SetWindowPos(GetDlgItem(hwndForm, IDC_WHITERECT), 0, 0, 0, rcText.right-rcText.left, rcText.bottom-rcText.top, SWP_NOMOVE|SWP_NOZORDER); GetWindowRect(GetDlgItem(hwndForm, IDC_FRAME1), &rcText); MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); rcText.top += deltaHeight; SetWindowPos(GetDlgItem(hwndForm, IDC_FRAME1), 0, rcText.left, rcText.top, 0, 0, SWP_NOSIZE|SWP_NOZORDER); GetWindowRect(GetDlgItem(hwndForm, IDC_FRAME), &rcText); MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); rcText.top += deltaHeight; SetWindowPos(GetDlgItem(hwndForm, IDC_FRAME), 0, rcText.left, rcText.top, rcText.right-rcText.left, rcText.bottom-rcText.top, SWP_NOZORDER); GetWindowRect(GetDlgItem(hwndForm, IDC_VSCROLL), &rcText); MapWindowPoints(NULL, hwndForm, (LPPOINT)&rcText, 2); rcText.top += deltaHeight; SetWindowPos(GetDlgItem(hwndForm, IDC_VSCROLL), 0, rcText.left, rcText.top, rcText.right-rcText.left, rcText.bottom-rcText.top, SWP_NOZORDER); if (fixedText) mir_free(fixedText); } static TJabberFormControlType JabberFormTypeNameToId(const TCHAR *type) { if ( !_tcscmp(type, _T("text-private"))) return JFORM_CTYPE_TEXT_PRIVATE; if ( !_tcscmp(type, _T("text-multi")) || !_tcscmp(type, _T("jid-multi"))) return JFORM_CTYPE_TEXT_MULTI; if ( !_tcscmp(type, _T("boolean"))) return JFORM_CTYPE_BOOLEAN; if ( !_tcscmp(type, _T("list-single"))) return JFORM_CTYPE_LIST_SINGLE; if ( !_tcscmp(type, _T("list-multi"))) return JFORM_CTYPE_LIST_MULTI; if ( !_tcscmp(type, _T("fixed"))) return JFORM_CTYPE_FIXED; if ( !_tcscmp(type, _T("hidden"))) return JFORM_CTYPE_HIDDEN; // else return JFORM_CTYPE_TEXT_SINGLE; } void JabberFormLayoutSingleControl(TJabberFormControlInfo *item, TJabberFormLayoutInfo *layout_info, const TCHAR *labelStr, const TCHAR *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)); DrawText(hdc, labelStr, -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, labelStr, -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, valueStr, -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, 0, 0, 0, rcLabel.right-rcLabel.left, rcLabel.bottom-rcLabel.top, SWP_NOZORDER|SWP_NOMOVE); if (item->hCtrl) SetWindowPos(item->hCtrl, 0, 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(_T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_CENTERIMAGE, \ 0, 0, 0, 0, hwndStatic, (HMENU)-1, hInst, NULL) TJabberFormControlInfo *JabberFormAppendControl(HWND hwndStatic, TJabberFormLayoutInfo *layout_info, TJabberFormControlType type, const TCHAR *labelStr, const TCHAR *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 = NULL; switch (type) { case JFORM_CTYPE_TEXT_PRIVATE: { item->hLabel = JabberFormCreateLabel(); item->hCtrl = CreateWindowEx(WS_EX_CLIENTEDGE, _T("edit"), valueStr, WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL|ES_PASSWORD, 0, 0, 0, 0, hwndStatic, (HMENU) layout_info->id, hInst, NULL); ++layout_info->id; break; } case JFORM_CTYPE_TEXT_MULTI: { item->hLabel = JabberFormCreateLabel(); item->hCtrl = CreateWindowEx(WS_EX_CLIENTEDGE, _T("edit"), valueStr, 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, hInst, NULL); mir_subclassWindow(item->hCtrl, JabberFormMultiLineWndProc); ++layout_info->id; break; } case JFORM_CTYPE_BOOLEAN: { item->hCtrl = CreateWindowEx(0, _T("button"), labelStr, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX|BS_MULTILINE, 0, 0, 0, 0, hwndStatic, (HMENU) layout_info->id, hInst, NULL); if (valueStr && !_tcscmp(valueStr, _T("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", NULL, WS_CHILD|WS_VISIBLE|WS_TABSTOP|CBS_DROPDOWNLIST, 0, 0, 0, 0, hwndStatic, (HMENU) layout_info->id, hInst, NULL); ++layout_info->id; break; } case JFORM_CTYPE_LIST_MULTI: { item->hLabel = JabberFormCreateLabel(); item->hCtrl = CreateWindowExA(WS_EX_CLIENTEDGE, "listbox", NULL, WS_CHILD|WS_VISIBLE|WS_TABSTOP|LBS_MULTIPLESEL, 0, 0, 0, 0, hwndStatic, (HMENU) layout_info->id, hInst, NULL); ++layout_info->id; break; } case JFORM_CTYPE_FIXED: { item->hCtrl = CreateWindow(_T("edit"), valueStr, WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_READONLY|ES_AUTOHSCROLL, 0, 0, 0, 0, hwndStatic, (HMENU)-1, hInst, NULL); break; } case JFORM_CTYPE_HIDDEN: { break; } case JFORM_CTYPE_TEXT_SINGLE: { item->hLabel = labelStr ? (JabberFormCreateLabel()) : NULL; item->hCtrl = CreateWindowEx(WS_EX_CLIENTEDGE, _T("edit"), valueStr, WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL, 0, 0, 0, 0, hwndStatic, (HMENU) layout_info->id, hInst, NULL); ++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; } void JabberFormAddListItem(TJabberFormControlInfo *item, TCHAR *text, bool selected) { DWORD dwIndex; switch (item->type) { case JFORM_CTYPE_LIST_MULTI: dwIndex = SendMessage(item->hCtrl, LB_ADDSTRING, 0, (LPARAM)text); if (selected) SendMessage(item->hCtrl, LB_SETSEL, TRUE, dwIndex); break; case JFORM_CTYPE_LIST_SINGLE: dwIndex = SendMessage(item->hCtrl, CB_ADDSTRING, 0, (LPARAM)text); if (selected) SendMessage(item->hCtrl, CB_SETCURSEL, dwIndex, 0); break; } } void JabberFormLayoutControls(HWND hwndStatic, TJabberFormLayoutInfo *layout_info, int *formHeight) { TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(hwndStatic, GWLP_USERDATA); if ( !controls) return; for (int i = 0; i < controls->getCount(); i++) { if ((*controls)[i]->hLabel) SetWindowPos((*controls)[i]->hLabel, 0, layout_info->offset+(*controls)[i]->ptLabel.x, layout_info->y_pos+(*controls)[i]->ptLabel.y, 0, 0, SWP_NOZORDER|SWP_NOSIZE); if ((*controls)[i]->hCtrl) SetWindowPos((*controls)[i]->hCtrl, 0, layout_info->offset+(*controls)[i]->ptCtrl.x, layout_info->y_pos+(*controls)[i]->ptCtrl.y, 0, 0, SWP_NOZORDER|SWP_NOSIZE); layout_info->y_pos += (*controls)[i]->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, HXML xNode, int *formHeight, BOOL bCompact) { JabberFormDestroyUI(hwndStatic); HXML v, o, vs; int i, j, k; const TCHAR *label, *typeName, *varStr, *str, *valueText; TCHAR *labelStr, *valueStr, *p; RECT frameRect; if (xNode==NULL || xmlGetName(xNode)==NULL || lstrcmp(xmlGetName(xNode), _T("x")) || hwndStatic==NULL) return; 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 (i=0; ; i++) { HXML n = xmlGetChild(xNode ,i); if ( !n) break; if (xmlGetName(n)) { if ( !lstrcmp(xmlGetName(n), _T("field"))) { varStr = xmlGetAttrValue(n, _T("var")); if ((typeName = xmlGetAttrValue(n, _T("type"))) != NULL) { if ((label = xmlGetAttrValue(n, _T("label"))) != NULL) labelStr = mir_tstrdup(label); else labelStr = mir_tstrdup(varStr); TJabberFormControlType type = JabberFormTypeNameToId(typeName); if ((v = xmlGetChild(n , "value")) != NULL) { valueText = xmlGetText(v); if (type != JFORM_CTYPE_TEXT_MULTI) { valueStr = mir_tstrdup(valueText); } else { size_t size = 1; for (j=0; ; j++) { v = xmlGetChild(n ,j); if ( !v) break; if (xmlGetName(v) && !lstrcmp(xmlGetName(v), _T("value")) && xmlGetText(v)) size += _tcslen(xmlGetText(v)) + 2; } valueStr = (TCHAR*)mir_alloc(sizeof(TCHAR)*size); valueStr[0] = '\0'; for (j=0; ; j++) { v = xmlGetChild(n ,j); if ( !v) break; if (xmlGetName(v) && !lstrcmp(xmlGetName(v), _T("value")) && xmlGetText(v)) { if (valueStr[0]) _tcscat(valueStr, _T("\r\n")); _tcscat(valueStr, xmlGetText(v)); } } } } else { valueText = valueStr = NULL; } TJabberFormControlInfo *item = JabberFormAppendControl(hwndStatic, &layout_info, type, labelStr, valueStr); mir_free(labelStr); mir_free(valueStr); if (type == JFORM_CTYPE_LIST_SINGLE) { for (j=0; ; j++) { o = xmlGetChild(n ,j); if ( !o) break; if (xmlGetName(o) && !lstrcmp(xmlGetName(o), _T("option"))) { if ((v = xmlGetChild(o , "value")) != NULL && xmlGetText(v)) { if ((str = xmlGetAttrValue(o, _T("label"))) == NULL) str = xmlGetText(v); if ((p = mir_tstrdup(str)) != NULL) { bool selected = false; if (valueText != NULL && !_tcscmp(valueText, xmlGetText(v))) selected = true; JabberFormAddListItem(item, p, selected); mir_free(p); } } } } } else if (type == JFORM_CTYPE_LIST_MULTI) { for (j=0; ; j++) { o = xmlGetChild(n ,j); if ( !o) break; if (xmlGetName(o) && !lstrcmp(xmlGetName(o), _T("option"))) { if ((v = xmlGetChild(o , "value")) != NULL && xmlGetText(v)) { if ((str = xmlGetAttrValue(o, _T("label"))) == NULL) str = xmlGetText(v); if ((p = mir_tstrdup(str)) != NULL) { bool selected = false; for (k=0; ; k++) { vs = xmlGetChild(n ,k); if ( !vs) break; if ( !lstrcmp(xmlGetName(vs), _T("value")) && xmlGetText(vs) && !_tcscmp(xmlGetText(vs), xmlGetText(v))) { selected = true; break; } } JabberFormAddListItem(item, p, selected); mir_free(p); } } } } } } } } } JabberFormLayoutControls(hwndStatic, &layout_info, formHeight); } void JabberFormDestroyUI(HWND hwndStatic) { TJabberFormControlList *controls = (TJabberFormControlList *)GetWindowLongPtr(hwndStatic, GWLP_USERDATA); if (controls) { for (int i = 0; i < controls->getCount(); i++) mir_free((*controls)[i]); controls->destroy(); delete controls; SetWindowLongPtr(hwndStatic, GWLP_USERDATA, 0); } } HXML JabberFormGetData(HWND hwndStatic, HXML xNode) { HWND hFrame, hCtrl; HXML n, v, o; int id, j, k, len; const TCHAR *varName, *type, *fieldStr, *labelText, *str2; TCHAR *p, *q, *str; if (xNode == NULL || xmlGetName(xNode) == NULL || lstrcmp(xmlGetName(xNode), _T("x")) || hwndStatic == NULL) return NULL; hFrame = hwndStatic; id = 0; XmlNode x(_T("x")); x << XATTR(_T("xmlns"), _T(JABBER_FEAT_DATA_FORMS)) << XATTR(_T("type"), _T("submit")); for (int i=0; ; i++) { n = xmlGetChild(xNode ,i); if ( !n) break; fieldStr = NULL; if (lstrcmp(xmlGetName(n), _T("field"))) continue; if ((varName = xmlGetAttrValue(n, _T("var"))) == NULL || (type = xmlGetAttrValue(n, _T("type"))) == NULL) continue; hCtrl = GetDlgItem(hFrame, id); HXML field = x << XCHILD(_T("field")) << XATTR(_T("var"), varName); if ( !_tcscmp(type, _T("text-multi")) || !_tcscmp(type, _T("jid-multi"))) { len = GetWindowTextLength(GetDlgItem(hFrame, id)); str = (TCHAR*)mir_alloc(sizeof(TCHAR)*(len+1)); GetDlgItemText(hFrame, id, str, len+1); p = str; while (p != NULL) { if ((q = _tcsstr(p, _T("\r\n"))) != NULL) *q = '\0'; field << XCHILD(_T("value"), p); p = q ? q+2 : NULL; } mir_free(str); id++; } else if ( !_tcscmp(type, _T("boolean"))) { TCHAR buf[ 10 ]; _itot(IsDlgButtonChecked(hFrame, id) == BST_CHECKED ? 1 : 0, buf, 10); field << XCHILD(_T("value"), buf); id++; } else if ( !_tcscmp(type, _T("list-single"))) { len = GetWindowTextLength(GetDlgItem(hFrame, id)); str = (TCHAR*)mir_alloc(sizeof(TCHAR)*(len+1)); GetDlgItemText(hFrame, id, str, len+1); v = NULL; for (j=0; ; j++) { o = xmlGetChild(n ,j); if ( !o) break; if ( !lstrcmp(xmlGetName(o), _T("option"))) { if ((v = xmlGetChild(o , "value")) != NULL && xmlGetText(v)) { if ((str2 = xmlGetAttrValue(o, _T("label"))) == NULL) str2 = xmlGetText(v); if ( !lstrcmp(str2, str)) break; } } } if (o) field << XCHILD(_T("value"), xmlGetText(v)); mir_free(str); id++; } else if ( !_tcscmp(type, _T("list-multi"))) { int count = SendMessage(hCtrl, LB_GETCOUNT, 0, 0); for (j=0; j 0) { // an entry is selected len = SendMessage(hCtrl, LB_GETTEXTLEN, j, 0); if ((str = (TCHAR*)mir_alloc((len+1)*sizeof(TCHAR))) != NULL) { SendMessage(hCtrl, LB_GETTEXT, j, (LPARAM)str); for (k=0; ; k++) { o = xmlGetChild(n ,k); if ( !o) break; if (xmlGetName(o) && !lstrcmp(xmlGetName(o), _T("option"))) { if ((v = xmlGetChild(o , "value")) != NULL && xmlGetText(v)) { if ((labelText = xmlGetAttrValue(o, _T("label"))) == NULL) labelText = xmlGetText(v); if ( !lstrcmp(labelText, str)) field << XCHILD(_T("value"), xmlGetText(v)); } } } mir_free(str); } } } id++; } else if ( !_tcscmp(type, _T("fixed")) || !_tcscmp(type, _T("hidden"))) { v = xmlGetChild(n , "value"); if (v != NULL && xmlGetText(v) != NULL) field << XCHILD(_T("value"), xmlGetText(v)); } else { // everything else is considered "text-single" or "text-private" len = GetWindowTextLength(GetDlgItem(hFrame, id)); str = (TCHAR*)mir_alloc(sizeof(TCHAR)*(len+1)); GetDlgItemText(hFrame, id, str, len+1); field << XCHILD(_T("value"), str); mir_free(str); id++; } } return xi.copyNode(x); } struct JABBER_FORM_INFO { ~JABBER_FORM_INFO(); CJabberProto* ppro; HXML xNode; TCHAR defTitle[128]; // Default title if no in xNode RECT frameRect; // Clipping region of the frame to scroll int frameHeight; // Height of the frame (can be eliminated, redundant to frameRect) int formHeight; // Actual height of the form int curPos; // Current scroll position JABBER_FORM_SUBMIT_FUNC pfnSubmit; void *userdata; }; static INT_PTR CALLBACK JabberFormDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { JABBER_FORM_INFO *jfi; switch (msg) { case WM_INITDIALOG: { HXML n; LONG frameExStyle; // lParam is (JABBER_FORM_INFO *) TranslateDialogDefault(hwndDlg); ShowWindow(GetDlgItem(hwndDlg, IDC_FRAME_TEXT), SW_HIDE); jfi = (JABBER_FORM_INFO *) lParam; if (jfi != NULL) { // Set dialog title if (jfi->xNode!=NULL && (n = xmlGetChild(jfi->xNode , "title")) != NULL && xmlGetText(n) != NULL) SetWindowText(hwndDlg, xmlGetText(n)); else if (jfi->defTitle != NULL) SetWindowText(hwndDlg, TranslateTS(jfi->defTitle)); // Set instruction field if (jfi->xNode!=NULL && (n = xmlGetChild(jfi->xNode , "instructions")) != NULL && xmlGetText(n) != NULL) JabberFormSetInstruction(hwndDlg, xmlGetText(n)); else { if (jfi->xNode != NULL && (n = xmlGetChild(jfi->xNode , "title")) != NULL && xmlGetText(n) != NULL) JabberFormSetInstruction(hwndDlg, xmlGetText(n)); else if (jfi->defTitle != NULL) JabberFormSetInstruction(hwndDlg, TranslateTS(jfi->defTitle)); } // Create form if (jfi->xNode != NULL) { RECT rect; GetClientRect(GetDlgItem(hwndDlg, IDC_FRAME), &(jfi->frameRect)); GetClientRect(GetDlgItem(hwndDlg, IDC_VSCROLL), &rect); jfi->frameRect.right -= (rect.right - rect.left); GetClientRect(GetDlgItem(hwndDlg, IDC_FRAME), &rect); jfi->frameHeight = rect.bottom - rect.top; JabberFormCreateUI(GetDlgItem(hwndDlg, IDC_FRAME), jfi->xNode, &(jfi->formHeight)); } } if (jfi->formHeight > jfi->frameHeight) { HWND hwndScroll; hwndScroll = GetDlgItem(hwndDlg, IDC_VSCROLL); EnableWindow(hwndScroll, TRUE); SetScrollRange(hwndScroll, SB_CTL, 0, jfi->formHeight - jfi->frameHeight, FALSE); jfi->curPos = 0; } // Enable WS_EX_CONTROLPARENT on IDC_FRAME (so tab stop goes through all its children) frameExStyle = GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FRAME), GWL_EXSTYLE); frameExStyle |= WS_EX_CONTROLPARENT; SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FRAME), GWL_EXSTYLE, frameExStyle); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) jfi); if (jfi->pfnSubmit != NULL) EnableWindow(GetDlgItem(hwndDlg, IDC_SUBMIT), TRUE); } return TRUE; 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 NULL; case WM_MOUSEWHEEL: { int 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(hwndDlg, WM_VSCROLL, (zDelta < 0) ? SB_LINEDOWN : SB_LINEUP, 0); } } break; case WM_VSCROLL: jfi = (JABBER_FORM_INFO *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); if (jfi != NULL) { int pos = jfi->curPos; switch (LOWORD(wParam)) { case SB_LINEDOWN: pos += 15; break; case SB_LINEUP: pos -= 15; break; case SB_PAGEDOWN: pos += (jfi->frameHeight - 10); break; case SB_PAGEUP: pos -= (jfi->frameHeight - 10); break; case SB_THUMBTRACK: pos = HIWORD(wParam); break; } if (pos > (jfi->formHeight - jfi->frameHeight)) pos = jfi->formHeight - jfi->frameHeight; if (pos < 0) pos = 0; if (jfi->curPos != pos) { ScrollWindow(GetDlgItem(hwndDlg, IDC_FRAME), 0, jfi->curPos - pos, NULL, &(jfi->frameRect)); SetScrollPos(GetDlgItem(hwndDlg, IDC_VSCROLL), SB_CTL, pos, TRUE); jfi->curPos = pos; } } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_SUBMIT: jfi = (JABBER_FORM_INFO *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); if (jfi != NULL) { HXML n = JabberFormGetData(GetDlgItem(hwndDlg, IDC_FRAME), jfi->xNode); (jfi->ppro->*(jfi->pfnSubmit))(n, jfi->userdata); xi.destroyNode(n); } // fall through case IDCANCEL: case IDCLOSE: DestroyWindow(hwndDlg); return TRUE; } break; case WM_CLOSE: DestroyWindow(hwndDlg); break; case WM_DESTROY: JabberFormDestroyUI(GetDlgItem(hwndDlg, IDC_FRAME)); jfi = (JABBER_FORM_INFO *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); delete jfi; break; } return FALSE; } static VOID CALLBACK JabberFormCreateDialogApcProc(void* param) { CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_FORM), NULL, JabberFormDlgProc, (LPARAM)param); } void CJabberProto::FormCreateDialog(HXML xNode, TCHAR* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata) { JABBER_FORM_INFO *jfi = new JABBER_FORM_INFO; memset(jfi, 0, sizeof(JABBER_FORM_INFO)); jfi->ppro = this; jfi->xNode = xi.copyNode(xNode); if (defTitle) _tcsncpy(jfi->defTitle, defTitle, SIZEOF(jfi->defTitle)); jfi->pfnSubmit = pfnSubmit; jfi->userdata = userdata; CallFunctionAsync(JabberFormCreateDialogApcProc, jfi); } //======================================================================================= JABBER_FORM_INFO::~JABBER_FORM_INFO() { xi.destroyNode(xNode); mir_free(userdata); }