/** \file * \brief List Control * * See Copyright Notice in "iup.h" */ #include #include #include #include #include #include #include #include "iup.h" #include "iupcbs.h" #include "iup_object.h" #include "iup_attrib.h" #include "iup_str.h" #include "iup_drv.h" #include "iup_drvfont.h" #include "iup_mask.h" #include "iup_focus.h" #include "iup_list.h" #include "iupwin_drv.h" #include "iupwin_handle.h" #include "iupwin_draw.h" #ifndef EM_SETCUEBANNER /* defined only if _WIN32_WINNT >= 0x501 */ #define ECM_FIRST 0x1500 /* Edit control messages */ #define EM_SETCUEBANNER (ECM_FIRST + 1) #endif #define WM_CARET WM_APP+1 /* Custom IUP message */ #define WIN_GETCOUNT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETCOUNT: LB_GETCOUNT) #define WIN_GETTEXTLEN(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETLBTEXTLEN: LB_GETTEXTLEN) #define WIN_GETTEXT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETLBTEXT: LB_GETTEXT) #define WIN_ADDSTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_ADDSTRING: LB_ADDSTRING) #define WIN_DELETESTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_DELETESTRING: LB_DELETESTRING) #define WIN_INSERTSTRING(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_INSERTSTRING: LB_INSERTSTRING) #define WIN_RESETCONTENT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_RESETCONTENT: LB_RESETCONTENT) #define WIN_SETCURSEL(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETCURSEL: LB_SETCURSEL) #define WIN_GETCURSEL(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETCURSEL: LB_GETCURSEL) #define WIN_SETHORIZONTALEXTENT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETHORIZONTALEXTENT: LB_SETHORIZONTALEXTENT) #define WIN_SETITEMDATA(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETITEMDATA: LB_SETITEMDATA) #define WIN_GETITEMDATA(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_GETITEMDATA: LB_GETITEMDATA) #define WIN_SETTOPINDEX(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETTOPINDEX: LB_SETTOPINDEX) #define WIN_SETITEMHEIGHT(_ih) ((_ih->data->is_dropdown || _ih->data->has_editbox)? CB_SETITEMHEIGHT: LB_SETITEMHEIGHT) void iupdrvListAddItemSpace(Ihandle* ih, int *h) { (void)ih; (void)h; } void iupdrvListAddBorders(Ihandle* ih, int *x, int *y) { int border_size = 2*4; (*x) += border_size; (*y) += border_size; if (ih->data->is_dropdown) { (*x) += 3; /* extra space for the dropdown button */ if (ih->data->has_editbox) { /* extra border for the editbox */ int internal_border_size = 2*6; (*x) += internal_border_size; (*y) += internal_border_size; } } else { if (ih->data->has_editbox) (*y) += 2*3; /* internal border between editbox and list */ } } int iupdrvListGetCount(Ihandle* ih) { return SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0); } static int winListConvertXYToPos(Ihandle* ih, int x, int y) { int pos; if (ih->data->has_editbox) { HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); pos = SendMessage(cbedit, EM_CHARFROMPOS, 0, MAKELPARAM(x, y)); pos = LOWORD(pos); } if (ih->data->has_editbox) { HWND cblist = (HWND)iupAttribGet(ih, "_IUPWIN_LISTBOX"); pos = SendMessage(cblist, LB_ITEMFROMPOINT, 0, MAKELPARAM(x, y))+1; /* IUP Starts at 1 */ pos = LOWORD(pos); } else { pos = SendMessage(ih->handle, LB_ITEMFROMPOINT, 0, MAKELPARAM(x, y))+1; pos = LOWORD(pos); } return pos; } static int winListGetMaxWidth(Ihandle* ih) { int i, item_w, max_w = 0, count = SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0); for (i=0; ihandle, WIN_GETITEMDATA(ih), i, 0); if (item_w > max_w) max_w = item_w; } return max_w; } static void winListUpdateScrollWidth(Ihandle* ih) { if (ih->data->is_dropdown && iupAttribGetBoolean(ih, "DROPEXPAND")) { int w = 3+winListGetMaxWidth(ih)+iupdrvGetScrollbarSize()+3; SendMessage(ih->handle, CB_SETDROPPEDWIDTH, w, 0); } else SendMessage(ih->handle, WIN_SETHORIZONTALEXTENT(ih), winListGetMaxWidth(ih), 0); } void iupdrvListAppendItem(Ihandle* ih, const char* value) { int pos = SendMessage(ih->handle, WIN_ADDSTRING(ih), 0, (LPARAM)value); SendMessage(ih->handle, WIN_SETITEMDATA(ih), pos, (LPARAM)iupdrvFontGetStringWidth(ih, value)); winListUpdateScrollWidth(ih); } void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value) { SendMessage(ih->handle, WIN_INSERTSTRING(ih), pos, (LPARAM)value); SendMessage(ih->handle, WIN_SETITEMDATA(ih), pos, (LPARAM)iupdrvFontGetStringWidth(ih, value)); winListUpdateScrollWidth(ih); iupListUpdateOldValue(ih, pos, 0); } void iupdrvListRemoveItem(Ihandle* ih, int pos) { if (ih->data->is_dropdown && !ih->data->has_editbox) { /* must check if removing the current item */ int curpos = SendMessage(ih->handle, WIN_GETCURSEL(ih), 0, 0); if (pos == curpos) { if (curpos > 0) curpos--; else { curpos=1; if (iupdrvListGetCount(ih)==1) curpos = -1; /* remove the selection */ } SendMessage(ih->handle, WIN_SETCURSEL(ih), curpos, 0); } } SendMessage(ih->handle, WIN_DELETESTRING(ih), pos, 0L); winListUpdateScrollWidth(ih); iupListUpdateOldValue(ih, pos, 1); } void iupdrvListRemoveAllItems(Ihandle* ih) { SendMessage(ih->handle, WIN_RESETCONTENT(ih), 0, 0L); if (ih->data->is_dropdown && iupAttribGetBoolean(ih, "DROPEXPAND")) SendMessage(ih->handle, CB_SETDROPPEDWIDTH, 0, 0); else SendMessage(ih->handle, WIN_SETHORIZONTALEXTENT(ih), 0, 0); } static int winListGetCaretPos(HWND cbedit) { int pos = 0; POINT point; if (GetFocus() != cbedit || !GetCaretPos(&point)) { /* if does not have the focus, or could not get caret position, then use the selection start position */ SendMessage(cbedit, EM_GETSEL, (WPARAM)&pos, 0); } else { pos = SendMessage(cbedit, EM_CHARFROMPOS, 0, MAKELPARAM(point.x, point.y)); pos = LOWORD(pos); } return pos; } /*********************************************************************************/ static void winListUpdateItemWidth(Ihandle* ih) { int i, count = SendMessage(ih->handle, WIN_GETCOUNT(ih), 0, 0); for (i=0; ihandle, WIN_GETTEXTLEN(ih), (WPARAM)i, 0); char* str = iupStrGetMemory(len+1); SendMessage(ih->handle, WIN_GETTEXT(ih), (WPARAM)i, (LPARAM)str); SendMessage(ih->handle, WIN_SETITEMDATA(ih), i, (LPARAM)iupdrvFontGetStringWidth(ih, str)); } } static int winListSetBgColorAttrib(Ihandle *ih, const char *value) { (void)value; if (ih->handle) iupdrvPostRedraw(ih); return 1; } static int winListSetStandardFontAttrib(Ihandle* ih, const char* value) { iupdrvSetStandardFontAttrib(ih, value); if (ih->handle) { winListUpdateItemWidth(ih); winListUpdateScrollWidth(ih); } return 1; } static char* winListGetIdValueAttrib(Ihandle* ih, const char* name_id) { int pos = iupListGetPos(ih, name_id); if (pos >= 0) { int len = SendMessage(ih->handle, WIN_GETTEXTLEN(ih), (WPARAM)pos, 0); char* str = iupStrGetMemory(len+1); SendMessage(ih->handle, WIN_GETTEXT(ih), (WPARAM)pos, (LPARAM)str); return str; } return NULL; } static char* winListGetValueAttrib(Ihandle* ih) { if (ih->data->has_editbox) { int nc = GetWindowTextLength(ih->handle); if (nc) { char* str = iupStrGetMemory(nc+1); GetWindowText(ih->handle, str, nc+1); return str; } } else { if (ih->data->is_dropdown || !ih->data->is_multiple) { int pos = SendMessage(ih->handle, WIN_GETCURSEL(ih), 0, 0); char* str = iupStrGetMemory(50); sprintf(str, "%d", pos+1); /* IUP starts at 1 */ return str; } else { int i, count = SendMessage(ih->handle, LB_GETCOUNT, 0, 0); int* pos = malloc(sizeof(int)*count); int sel_count = SendMessage(ih->handle, LB_GETSELITEMS, count, (LPARAM)pos); char* str = iupStrGetMemory(count+1); memset(str, '-', count); str[count]=0; for (i=0; idata->has_editbox) { if (!value) value = ""; SetWindowText(ih->handle, value); } else { if (ih->data->is_dropdown || !ih->data->is_multiple) { int pos; if (iupStrToInt(value, &pos)==1) { SendMessage(ih->handle, WIN_SETCURSEL(ih), pos-1, 0); /* IUP starts at 1 */ iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos); } else { SendMessage(ih->handle, WIN_SETCURSEL(ih), (WPARAM)-1, 0); /* no selection */ iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); } } else { /* User has changed a multiple selection on a simple list. */ int i, len, count; /* Clear all selections */ SendMessage(ih->handle, LB_SETSEL, FALSE, -1); if (!value) { iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); return 0; } count = SendMessage(ih->handle, LB_GETCOUNT, 0, 0L); len = strlen(value); if (len < count) count = len; /* update selection list */ for (i = 0; ihandle, LB_SETSEL, TRUE, i); } iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value); } } return 0; } static int winListSetShowDropdownAttrib(Ihandle* ih, const char* value) { if (ih->data->is_dropdown) SendMessage(ih->handle, CB_SHOWDROPDOWN, iupStrBoolean(value), 0); return 0; } static int winListSetTopItemAttrib(Ihandle* ih, const char* value) { if (!ih->data->is_dropdown) { int pos = 1; if (iupStrToInt(value, &pos)) SendMessage(ih->handle, WIN_SETTOPINDEX(ih), pos-1, 0); /* IUP starts at 1 */ } return 0; } static int winListSetSpacingAttrib(Ihandle* ih, const char* value) { if (ih->data->is_dropdown) return 0; if (!iupStrToInt(value, &ih->data->spacing)) ih->data->spacing = 0; if (ih->handle) { int height; iupdrvFontGetCharSize(ih, NULL, &height); height += 2*ih->data->spacing; SendMessage(ih->handle, WIN_SETITEMHEIGHT(ih), 0, height); return 0; } else return 1; /* store until not mapped, when mapped will be set again */ } static int winListSetPaddingAttrib(Ihandle* ih, const char* value) { if (!ih->data->has_editbox) return 0; iupStrToIntInt(value, &(ih->data->horiz_padding), &(ih->data->vert_padding), 'x'); ih->data->vert_padding = 0; if (ih->handle) { HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELPARAM(ih->data->horiz_padding, ih->data->horiz_padding)); return 0; } else return 1; /* store until not mapped, when mapped will be set again */ } static int winListSetFilterAttrib(Ihandle *ih, const char *value) { int style = 0; if (!ih->data->has_editbox) return 0; if (iupStrEqualNoCase(value, "LOWERCASE")) style = ES_LOWERCASE; else if (iupStrEqualNoCase(value, "NUMBER")) style = ES_NUMBER; else if (iupStrEqualNoCase(value, "UPPERCASE")) style = ES_UPPERCASE; if (style) { HWND old_handle = ih->handle; ih->handle = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); iupwinMergeStyle(ih, ES_LOWERCASE|ES_NUMBER|ES_UPPERCASE, style); ih->handle = old_handle; } return 1; } static int winListSetCueBannerAttrib(Ihandle *ih, const char *value) { if (ih->data->has_editbox && iupwin_comctl32ver6) { WCHAR* wstr = iupwinStrChar2Wide(value); HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_SETCUEBANNER, (WPARAM)FALSE, (LPARAM)wstr); free(wstr); return 1; } return 0; } static int winListSetClipboardAttrib(Ihandle *ih, const char *value) { UINT msg = 0; if (!ih->data->has_editbox) return 0; if (iupStrEqualNoCase(value, "COPY")) msg = WM_COPY; else if (iupStrEqualNoCase(value, "CUT")) msg = WM_CUT; else if (iupStrEqualNoCase(value, "PASTE")) msg = WM_PASTE; else if (iupStrEqualNoCase(value, "CLEAR")) msg = WM_CLEAR; else if (iupStrEqualNoCase(value, "UNDO")) msg = WM_UNDO; if (msg) { HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, msg, 0, 0); } return 0; } static int winListSetSelectedTextAttrib(Ihandle* ih, const char* value) { if (!ih->data->has_editbox) return 0; if (value) { int start = 0, end = 0; HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); if (start == end) return 0; SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value); } return 0; } static char* winListGetSelectedTextAttrib(Ihandle* ih) { int nc; HWND cbedit; if (!ih->data->has_editbox) return 0; cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); nc = GetWindowTextLength(cbedit); if (nc) { int start = 0, end = 0; char* str; SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); if (start == end) return NULL; str = iupStrGetMemory(nc+1); GetWindowText(cbedit, str, nc+1); str[end] = 0; /* returns only the selected text */ str += start; return str; } else return NULL; } static int winListSetNCAttrib(Ihandle* ih, const char* value) { if (!ih->data->has_editbox) return 0; if (!iupStrToInt(value, &ih->data->nc)) ih->data->nc = 0; if (ih->handle) { HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_LIMITTEXT, ih->data->nc, 0L); return 0; } else return 1; /* store until not mapped, when mapped will be set again */ } static int winListSetSelectionAttrib(Ihandle* ih, const char* value) { HWND cbedit; int start=1, end=1; if (!ih->data->has_editbox) return 0; if (!value || iupStrEqualNoCase(value, "NONE")) { cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_SETSEL, (WPARAM)-1, (LPARAM)0); return 0; } if (iupStrEqualNoCase(value, "ALL")) { cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1); return 0; } if (iupStrToIntInt(value, &start, &end, ':')!=2) return 0; if(start<1 || end<1) return 0; start--; /* IUP starts at 1 */ end--; cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_SETSEL, (WPARAM)start, (LPARAM)end); return 0; } static char* winListGetSelectionAttrib(Ihandle* ih) { int start = 0, end = 0; char* str; HWND cbedit; if (!ih->data->has_editbox) return NULL; cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); if (start == end) return NULL; str = iupStrGetMemory(100); start++; /* IUP starts at 1 */ end++; sprintf(str, "%d:%d", start, end); return str; } static int winListSetSelectionPosAttrib(Ihandle* ih, const char* value) { int start=0, end=0; HWND cbedit; if (!ih->data->has_editbox) return 0; if (!value || iupStrEqualNoCase(value, "NONE")) { cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_SETSEL, (WPARAM)-1, (LPARAM)0); return 0; } if (iupStrEqualNoCase(value, "ALL")) { cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1); return 0; } if (iupStrToIntInt(value, &start, &end, ':')!=2) return 0; if(start<0 || end<0) return 0; cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_SETSEL, (WPARAM)start, (LPARAM)end); return 0; } static char* winListGetSelectionPosAttrib(Ihandle* ih) { int start = 0, end = 0; char* str; HWND cbedit; if (!ih->data->has_editbox) return NULL; cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); if (start == end) return NULL; str = iupStrGetMemory(100); sprintf(str, "%d:%d", start, end); return str; } static int winListSetInsertAttrib(Ihandle* ih, const char* value) { if (value && ih->data->has_editbox) { HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value); } return 0; } static int winListSetAppendAttrib(Ihandle* ih, const char* value) { int len; HWND cbedit; if (!ih->data->has_editbox) return 0; if (!value) value = ""; cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); len = GetWindowTextLength(cbedit)+1; SendMessage(cbedit, EM_SETSEL, (WPARAM)len, (LPARAM)len); SendMessage(cbedit, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)value); return 0; } static int winListSetReadOnlyAttrib(Ihandle* ih, const char* value) { HWND cbedit; if (!ih->data->has_editbox) return 0; cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_SETREADONLY, (WPARAM)iupStrBoolean(value), 0); return 0; } static char* winListGetReadOnlyAttrib(Ihandle* ih) { DWORD style; HWND cbedit; if (!ih->data->has_editbox) return NULL; cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); style = GetWindowLong(cbedit, GWL_STYLE); if (style & ES_READONLY) return "YES"; else return "NO"; } static int winListSetCaretAttrib(Ihandle* ih, const char* value) { int pos = 1; HWND cbedit; if (!ih->data->has_editbox) return 0; if (!value) return 0; sscanf(value,"%i",&pos); if (pos < 1) pos = 1; pos--; /* IUP starts at 1 */ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_SETSEL, (WPARAM)pos, (LPARAM)pos); SendMessage(cbedit, EM_SCROLLCARET, 0L, 0L); return 0; } static char* winListGetCaretAttrib(Ihandle* ih) { if (ih->data->has_editbox) { char* str = iupStrGetMemory(100); HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); sprintf(str, "%d", winListGetCaretPos(cbedit)+1); return str; } else return NULL; } static int winListSetCaretPosAttrib(Ihandle* ih, const char* value) { int pos = 0; HWND cbedit; if (!ih->data->has_editbox) return 0; if (!value) return 0; sscanf(value,"%i",&pos); /* be permissive in SetCaret, do not abort if invalid */ if (pos < 0) pos = 0; cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_SETSEL, (WPARAM)pos, (LPARAM)pos); SendMessage(cbedit, EM_SCROLLCARET, 0L, 0L); return 0; } static char* winListGetCaretPosAttrib(Ihandle* ih) { if (ih->data->has_editbox) { char* str = iupStrGetMemory(100); HWND cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); sprintf(str, "%d", winListGetCaretPos(cbedit)); return str; } else return NULL; } static int winListSetScrollToAttrib(Ihandle* ih, const char* value) { int pos = 1; HWND cbedit; if (!ih->data->has_editbox) return 0; if (!value) return 0; sscanf(value,"%i",&pos); if (pos < 1) pos = 1; pos--; /* return to Windows referece */ cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_LINESCROLL, (WPARAM)pos, (LPARAM)0); return 0; } static int winListSetScrollToPosAttrib(Ihandle* ih, const char* value) { int pos = 0; HWND cbedit; if (!ih->data->has_editbox) return 0; if (!value) return 0; sscanf(value,"%i",&pos); if (pos < 0) pos = 0; cbedit = (HWND)iupAttribGet(ih, "_IUPWIN_EDITBOX"); SendMessage(cbedit, EM_LINESCROLL, (WPARAM)pos, (LPARAM)0); return 0; } /*********************************************************************************/ static int winListCtlColor(Ihandle* ih, HDC hdc, LRESULT *result) { COLORREF cr; if (iupwinGetColorRef(ih, "FGCOLOR", &cr)) SetTextColor(hdc, cr); if (iupwinGetColorRef(ih, "BGCOLOR", &cr)) { SetBkColor(hdc, cr); SetDCBrushColor(hdc, cr); *result = (LRESULT)GetStockObject(DC_BRUSH); return 1; } return 0; } static int winListWmCommand(Ihandle* ih, WPARAM wp, LPARAM lp) { (void)lp; if (ih->data->is_dropdown || ih->data->has_editbox) { switch (HIWORD(wp)) { case CBN_EDITCHANGE: { iupBaseCallValueChangedCb(ih); break; } case CBN_SETFOCUS: iupwinWmSetFocus(ih); break; case CBN_KILLFOCUS: iupCallKillFocusCb(ih); break; case CBN_CLOSEUP: case CBN_DROPDOWN: { IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB"); if (cb) cb(ih, HIWORD(wp)==CBN_DROPDOWN? 1: 0); break; } case CBN_DBLCLK: { IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB"); if (cb) { int pos = SendMessage(ih->handle, CB_GETCURSEL, 0, 0); pos++; /* IUP starts at 1 */ iupListSingleCallDblClickCallback(ih, cb, pos); } break; } case CBN_SELCHANGE: { IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); if (cb) { int pos = SendMessage(ih->handle, CB_GETCURSEL, 0, 0); pos++; /* IUP starts at 1 */ iupListSingleCallActionCallback(ih, cb, pos); } iupBaseCallValueChangedCb(ih); break; } } } else { switch (HIWORD(wp)) { case LBN_DBLCLK: { IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB"); if (cb) { int pos = SendMessage(ih->handle, LB_GETCURSEL, 0, 0); pos++; /* IUP starts at 1 */ iupListSingleCallDblClickCallback(ih, cb, pos); } break; } case LBN_SELCHANGE: { if (!ih->data->is_multiple) { IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); if (cb) { int pos = SendMessage(ih->handle, LB_GETCURSEL, 0, 0); pos++; /* IUP starts at 1 */ iupListSingleCallActionCallback(ih, cb, pos); } } else { IFns multi_cb = (IFns)IupGetCallback(ih, "MULTISELECT_CB"); IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); if (multi_cb || cb) { int sel_count = SendMessage(ih->handle, LB_GETSELCOUNT, 0, 0); int* pos = malloc(sizeof(int)*sel_count); SendMessage(ih->handle, LB_GETSELITEMS, sel_count, (LPARAM)pos); iupListMultipleCallActionCallback(ih, cb, multi_cb, pos, sel_count); free(pos); } } iupBaseCallValueChangedCb(ih); break; } } } return 0; /* not used */ } static void winListCallCaretCb(Ihandle* ih, HWND cbedit) { int pos; IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); if (!cb) return; pos = winListGetCaretPos(cbedit); if (pos != ih->data->last_caret_pos) { ih->data->last_caret_pos = pos; cb(ih, 1, pos+1, pos); } } static int winListCallEditCb(Ihandle* ih, HWND cbedit, const char* insert_value, int key, int dir) { int start, end, ret = 1; char *value, *new_value; IFnis cb = (IFnis)IupGetCallback(ih, "EDIT_CB"); if (!cb && !ih->data->mask) return 1; SendMessage(cbedit, EM_GETSEL, (WPARAM)&start, (LPARAM)&end); value = winListGetValueAttrib(ih); if (!value) new_value = iupStrDup(insert_value); else if (insert_value) new_value = iupStrInsert(value, insert_value, start, end); else { new_value = value; iupStrRemove(value, start, end, dir); } if (!new_value) return 0; /* abort */ if (ih->data->nc && (int)strlen(new_value) > ih->data->nc) { if (new_value != value) free(new_value); return 0; /* abort */ } if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0) { if (new_value != value) free(new_value); return 0; /* abort */ } if (cb) { int cb_ret = cb(ih, key, (char*)new_value); if (cb_ret==IUP_IGNORE) ret = 0; /* abort processing */ else if (cb_ret==IUP_CLOSE) { IupExitLoop(); ret = 0; /* abort processing */ } else if (cb_ret!=0 && key!=0 && cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE) { WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB"); CallWindowProc(oldProc, cbedit, WM_CHAR, cb_ret, 0); /* replace key */ ret = 0; /* abort processing */ } } if (new_value != value) free(new_value); return ret; } static int winListEditProc(Ihandle* ih, HWND cbedit, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) { int ret = 0; if (msg==WM_KEYDOWN) /* process K_ANY before text callbacks */ { ret = iupwinBaseProc(ih, msg, wp, lp, result); if (ret) { iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", "1"); *result = 0; return 1; } else iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", NULL); } switch (msg) { case WM_CHAR: { if (iupAttribGet(ih, "_IUPWIN_IGNORE_CHAR")) { iupAttribSetStr(ih, "_IUPWIN_IGNORE_CHAR", NULL); *result = 0; return 1; } if ((char)wp == '\b') { if (!winListCallEditCb(ih, cbedit, NULL, 0, -1)) ret = 1; } else if ((char)wp == '\n' || (char)wp == '\r') { ret = 1; } else if (!(GetKeyState(VK_CONTROL) & 0x8000 || GetKeyState(VK_MENU) & 0x8000 || GetKeyState(VK_LWIN) & 0x8000 || GetKeyState(VK_RWIN) & 0x8000)) { char insert_value[2]; insert_value[0] = (char)wp; insert_value[1] = 0; if (!winListCallEditCb(ih, cbedit, insert_value, wp, 1)) ret = 1; } PostMessage(cbedit, WM_CARET, 0, 0L); if (wp==VK_TAB) /* the keys have the same definitions as the chars */ ret = 1; /* abort default processing to avoid beep */ break; } case WM_KEYDOWN: { if (wp == VK_DELETE) /* Del does not generates a WM_CHAR */ { if (!winListCallEditCb(ih, cbedit, NULL, 0, 1)) ret = 1; } else if (wp == 'A' && GetKeyState(VK_CONTROL) & 0x8000) /* Ctrl+A = Select All */ { SendMessage(cbedit, EM_SETSEL, (WPARAM)0, (LPARAM)-1); } PostMessage(cbedit, WM_CARET, 0, 0L); break; } case WM_CLEAR: { if (!winListCallEditCb(ih, cbedit, NULL, 0, 1)) ret = 1; PostMessage(cbedit, WM_CARET, 0, 0L); break; } case WM_CUT: { if (!winListCallEditCb(ih, cbedit, NULL, 0, 1)) ret = 1; PostMessage(cbedit, WM_CARET, 0, 0L); break; } case WM_PASTE: { if (IupGetCallback(ih, "EDIT_CB") || ih->data->mask) /* test before to avoid alocate clipboard text memory */ { char* insert_value = iupwinGetClipboardText(ih); if (insert_value) { if (!winListCallEditCb(ih, cbedit, insert_value, 0, 1)) ret = 1; free(insert_value); } } PostMessage(cbedit, WM_CARET, 0, 0L); break; } case WM_UNDO: { IFnis cb = (IFnis)IupGetCallback(ih, "EDIT_CB"); if (cb) { char* value; WNDPROC oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB"); CallWindowProc(oldProc, cbedit, WM_UNDO, 0, 0); value = winListGetValueAttrib(ih); cb(ih, 0, (char*)value); ret = 1; } PostMessage(cbedit, WM_CARET, 0, 0L); break; } case WM_KEYUP: case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONUP: case WM_RBUTTONUP: case WM_LBUTTONUP: PostMessage(cbedit, WM_CARET, 0, 0L); break; case WM_CARET: winListCallCaretCb(ih, cbedit); break; } if (ret) /* if abort processing, then the result is 0 */ { *result = 0; return 1; } else { if (msg==WM_KEYDOWN) return 0; else return iupwinBaseProc(ih, msg, wp, lp, result); } } static LRESULT CALLBACK winListEditWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { int ret = 0; LRESULT result = 0; WNDPROC oldProc; Ihandle *ih; ih = iupwinHandleGet(hwnd); if (!ih) return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */ /* retrieve the control previous procedure for subclassing */ oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_EDITOLDPROC_CB"); ret = winListEditProc(ih, hwnd, msg, wp, lp, &result); if (ret) return result; else return CallWindowProc(oldProc, hwnd, msg, wp, lp); } static int winListComboListProc(Ihandle* ih, HWND cblist, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) { (void)cblist; switch (msg) { case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: if (iupwinButtonDown(ih, msg, wp, lp)==-1) { *result = 0; return 1; } break; case WM_MBUTTONUP: case WM_RBUTTONUP: case WM_LBUTTONUP: if (iupwinButtonUp(ih, msg, wp, lp)==-1) { *result = 0; return 1; } break; case WM_MOUSEMOVE: iupwinMouseMove(ih, msg, wp, lp); iupwinBaseProc(ih, msg, wp, lp, result); /* to process ENTER/LEAVE */ break; case WM_MOUSELEAVE: iupwinBaseProc(ih, msg, wp, lp, result); /* to process ENTER/LEAVE */ break; } return 0; } static LRESULT CALLBACK winListComboListWinProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { int ret = 0; LRESULT result = 0; WNDPROC oldProc; Ihandle *ih; ih = iupwinHandleGet(hwnd); if (!ih) return DefWindowProc(hwnd, msg, wp, lp); /* should never happen */ /* retrieve the control previous procedure for subclassing */ oldProc = (WNDPROC)IupGetCallback(ih, "_IUPWIN_LISTOLDPROC_CB"); ret = winListComboListProc(ih, hwnd, msg, wp, lp, &result); if (ret) return result; else return CallWindowProc(oldProc, hwnd, msg, wp, lp); } static int winListProc(Ihandle* ih, UINT msg, WPARAM wp, LPARAM lp, LRESULT *result) { if (!ih->data->is_dropdown && !ih->data->has_editbox) { switch (msg) { case WM_LBUTTONDBLCLK: case WM_MBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: if (iupwinButtonDown(ih, msg, wp, lp)==-1) { *result = 0; return 1; } break; case WM_MBUTTONUP: case WM_RBUTTONUP: case WM_LBUTTONUP: if (iupwinButtonUp(ih, msg, wp, lp)==-1) { *result = 0; return 1; } break; case WM_MOUSEMOVE: iupwinMouseMove(ih, msg, wp, lp); break; } } switch (msg) { case WM_CHAR: if (GetKeyState(VK_CONTROL) & 0x8000) { /* avoid item search when Ctrl is pressed */ *result = 0; return 1; } case WM_SETFOCUS: case WM_KILLFOCUS: case WM_MOUSELEAVE: case WM_MOUSEMOVE: if (ih->data->has_editbox) return 0; /* do not call base procedure to avoid duplicate messages */ break; } return iupwinBaseProc(ih, msg, wp, lp, result); } /*********************************************************************************/ static void winListLayoutUpdateMethod(Ihandle *ih) { if (ih->data->is_dropdown) { /* Must add the dropdown area, or it will not be visible */ RECT rect; int charheight, calc_h, win_h, win_w, voptions; voptions = iupAttribGetInt(ih, "VISIBLE_ITEMS"); if (voptions <= 0) voptions = 1; iupdrvFontGetCharSize(ih, NULL, &charheight); calc_h = ih->currentheight + voptions*charheight; SendMessage(ih->handle, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)&rect); win_h = rect.bottom-rect.top; win_w = rect.right-rect.left; if (ih->currentwidth != win_w || calc_h != win_h) SetWindowPos(ih->handle, HWND_TOP, ih->x, ih->y, ih->currentwidth, calc_h, SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOOWNERZORDER); else SetWindowPos(ih->handle, HWND_TOP, ih->x, ih->y, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOOWNERZORDER); } else iupdrvBaseLayoutUpdateMethod(ih); } static int winListMapMethod(Ihandle* ih) { char* class_name; DWORD dwStyle = WS_CHILD|WS_CLIPSIBLINGS, dwExStyle = WS_EX_CLIENTEDGE; if (!ih->parent) return IUP_ERROR; if (ih->data->is_dropdown || ih->data->has_editbox) { class_name = "COMBOBOX"; dwStyle |= CBS_NOINTEGRALHEIGHT; if (ih->data->is_dropdown) dwStyle |= WS_VSCROLL|WS_HSCROLL; else if (ih->data->sb) { dwStyle |= WS_VSCROLL|WS_HSCROLL; if (!iupAttribGetBoolean(ih, "AUTOHIDE")) dwStyle |= CBS_DISABLENOSCROLL; } if (ih->data->has_editbox) { dwStyle |= CBS_AUTOHSCROLL; if (ih->data->is_dropdown) dwStyle |= CBS_DROPDOWN; /* hidden-list+edit */ else dwStyle |= CBS_SIMPLE; /* visible-list+edit */ } else dwStyle |= CBS_DROPDOWNLIST; /* hidden-list */ if (iupAttribGetBoolean(ih, "SORT")) dwStyle |= CBS_SORT; } else { class_name = "LISTBOX"; dwStyle |= LBS_NOINTEGRALHEIGHT|LBS_NOTIFY; if (ih->data->is_multiple) dwStyle |= LBS_EXTENDEDSEL; if (ih->data->sb) { dwStyle |= WS_VSCROLL|WS_HSCROLL; if (!iupAttribGetBoolean(ih, "AUTOHIDE")) dwStyle |= LBS_DISABLENOSCROLL; } if (iupAttribGetBoolean(ih, "SORT")) dwStyle |= LBS_SORT; } if (iupAttribGetBoolean(ih, "CANFOCUS")) dwStyle |= WS_TABSTOP; if (!iupwinCreateWindowEx(ih, class_name, dwExStyle, dwStyle)) return IUP_ERROR; /* Custom Procedure */ IupSetCallback(ih, "_IUPWIN_CTRLPROC_CB", (Icallback)winListProc); /* Process background color */ IupSetCallback(ih, "_IUPWIN_CTLCOLOR_CB", (Icallback)winListCtlColor); /* Process WM_COMMAND */ IupSetCallback(ih, "_IUPWIN_COMMAND_CB", (Icallback)winListWmCommand); if (ih->data->is_dropdown || ih->data->has_editbox) { COMBOBOXINFO boxinfo; ZeroMemory(&boxinfo, sizeof(COMBOBOXINFO)); boxinfo.cbSize = sizeof(COMBOBOXINFO); GetComboBoxInfo(ih->handle, &boxinfo); iupwinHandleAdd(ih, boxinfo.hwndList); iupAttribSetStr(ih, "_IUPWIN_LISTBOX", (char*)boxinfo.hwndList); /* subclass the list box. */ IupSetCallback(ih, "_IUPWIN_LISTOLDPROC_CB", (Icallback)GetWindowLongPtr(boxinfo.hwndList, GWLP_WNDPROC)); SetWindowLongPtr(boxinfo.hwndList, GWLP_WNDPROC, (LONG_PTR)winListComboListWinProc); if (ih->data->has_editbox) { iupwinHandleAdd(ih, boxinfo.hwndItem); iupAttribSetStr(ih, "_IUPWIN_EDITBOX", (char*)boxinfo.hwndItem); /* subclass the edit box. */ IupSetCallback(ih, "_IUPWIN_EDITOLDPROC_CB", (Icallback)GetWindowLongPtr(boxinfo.hwndItem, GWLP_WNDPROC)); SetWindowLongPtr(boxinfo.hwndItem, GWLP_WNDPROC, (LONG_PTR)winListEditWinProc); /* set defaults */ SendMessage(ih->handle, CB_LIMITTEXT, 0, 0L); } } /* configure for DRAG&DROP */ if (IupGetCallback(ih, "DROPFILES_CB")) iupAttribSetStr(ih, "DRAGDROP", "YES"); IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)winListConvertXYToPos); iupListSetInitialItems(ih); return IUP_NOERROR; } void iupdrvListInitClass(Iclass* ic) { /* Driver Dependent Class functions */ ic->Map = winListMapMethod; ic->LayoutUpdate = winListLayoutUpdateMethod; /* Driver Dependent Attribute functions */ iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, winListSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* Visual */ iupClassRegisterAttribute(ic, "BGCOLOR", NULL, winListSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_NOT_MAPPED); /* Special */ iupClassRegisterAttribute(ic, "FGCOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_NOT_MAPPED); /* IupList only */ iupClassRegisterAttributeId(ic, "IDVALUE", winListGetIdValueAttrib, iupListSetIdValueAttrib, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "VALUE", winListGetValueAttrib, winListSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "SHOWDROPDOWN", NULL, winListSetShowDropdownAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "TOPITEM", NULL, winListSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "VISIBLE_ITEMS", NULL, NULL, IUPAF_SAMEASSYSTEM, "5", IUPAF_DEFAULT); iupClassRegisterAttribute(ic, "DROPEXPAND", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupwinSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "SPACING", iupListGetSpacingAttrib, winListSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); iupClassRegisterAttribute(ic, "PADDING", iupListGetPaddingAttrib, winListSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); iupClassRegisterAttribute(ic, "SELECTEDTEXT", winListGetSelectedTextAttrib, winListSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "SELECTION", winListGetSelectionAttrib, winListSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "SELECTIONPOS", winListGetSelectionPosAttrib, winListSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "CARET", winListGetCaretAttrib, winListSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "CARETPOS", winListGetCaretPosAttrib, winListSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "INSERT", NULL, winListSetInsertAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "APPEND", NULL, winListSetAppendAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "READONLY", winListGetReadOnlyAttrib, winListSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT); iupClassRegisterAttribute(ic, "NC", iupListGetNCAttrib, winListSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED); iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, winListSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "SCROLLTO", NULL, winListSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, winListSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "CUEBANNER", NULL, winListSetCueBannerAttrib, NULL, NULL, IUPAF_NO_INHERIT); iupClassRegisterAttribute(ic, "FILTER", NULL, winListSetFilterAttrib, NULL, NULL, IUPAF_NO_INHERIT); }