/////////////////////////////////////////////////////////////////////////////// // // IMPORTANT NOTICE // // The following open source license statement does not apply to any // entity in the Exception List published by FMSoft. // // For more information, please visit: // // https://www.fmsoft.cn/exception-list // ////////////////////////////////////////////////////////////////////////////// /* * This file is part of MiniGUI, a mature cross-platform windowing * and Graphics User Interface (GUI) support system for embedded systems * and smart IoT devices. * * Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd. * Copyright (C) 1998~2002, WEI Yongming * * 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 3 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, see . * * Or, * * As this program is a library, any link to this program must follow * GNU General Public License version 3 (GPLv3). If you cannot accept * GPLv3, you need to be licensed from FMSoft. * * If you have got a commercial license of this program, please use it * under the terms and conditions of the commercial license. * * For more information about the commercial license, please refer to * . */ /* ** cobmobox.c: the cobmobox control. ** ** Created by Jiao Libo at 2001/08/06 */ #include #include #include #include "common.h" #ifdef _MGCTRL_COMBOBOX #include "minigui.h" #include "gdi.h" #include "window.h" #include "ctrl/ctrlhelper.h" #include "ctrl/edit.h" #include "ctrl/listbox.h" #include "ctrl/combobox.h" #include "cliprect.h" #include "internals.h" #include "ctrlclass.h" #include "combobox_impl.h" #include "ctrlmisc.h" #define LEN_SPINVALUE 50 #define IDC_CEDIT 100 #define IDC_CLISTBOX 101 #define INTER_EDIT_BUTTON 2 #define INTER_EDIT_LISTBOX 4 #define DEF_LISTHEIGHT 60 #define INC_BOX 1 #define DEC_BOX 2 static int mouse_old = 0; static LRESULT ComboBoxCtrlProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); BOOL RegisterComboBoxControl (void) { WNDCLASS WndClass; WndClass.spClassName = CTRL_COMBOBOX; WndClass.dwStyle = WS_NONE; WndClass.dwExStyle = WS_EX_NONE; WndClass.hCursor = GetSystemCursor (0); #ifdef _MGSCHEMA_COMPOSITING WndClass.dwBkColor = GetWindowElementAttr (HWND_NULL, WE_BGC_WINDOW); #else WndClass.iBkColor = GetWindowElementPixelEx (HWND_NULL, HDC_SCREEN, WE_BGC_WINDOW); #endif WndClass.WinProc = ComboBoxCtrlProc; return gui_AddNewControlClass (&WndClass) == ERR_OK; } static LRESULT AutoSpinEditBoxProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { WNDPROC old_edit_proc; if (message == MSG_CHAR) { if (wParam != 127 && (wParam < '0' || wParam > '9')) return 0; } old_edit_proc = (WNDPROC) GetWindowAdditionalData (hWnd); return (*old_edit_proc) (hWnd, message, wParam, lParam); } static int DefCBProc(HWND hWnd, int message, WPARAM wParam, LPARAM lParam); static void ComboBoxDrawSpinButton (HWND hwnd, HDC hdc , int which, int status) { PCOMBOBOXDATA pData; PCONTROL pCtrl; const WINDOWINFO *win_info; DWORD fg_3d; BOOL bGetDC = FALSE; if (hdc == 0) { bGetDC = TRUE; hdc = GetClientDC(hwnd); } pCtrl = gui_Control (hwnd); win_info = GetWindowInfo(hwnd); pData = (PCOMBOBOXDATA)pCtrl->dwAddData2; /* not used var DWORD main_3d; main_3d = GetWindowElementAttr(hwnd, WE_MAINC_THREED_BODY); */ fg_3d = GetWindowElementAttr(hwnd, WE_FGC_THREED_BODY); if(which == 0) status = LFRDR_BTN_STATUS_NORMAL; switch (pCtrl->dwStyle & CBS_TYPEMASK) { case CBS_SIMPLE: break; case CBS_SPINLIST: case CBS_AUTOSPIN: if (pCtrl->dwStyle & CBS_SPINARROW_LEFTRIGHT) { if(which == 0 || which == INC_BOX) { SelectClipRect (hdc, &(pData->IncSpinBox)); win_info->we_rdr->draw_arrow(hwnd, hdc, &(pData->IncSpinBox), fg_3d, status | LFRDR_ARROW_HAVESHELL | LFRDR_ARROW_RIGHT); } if(which == 0 || which == DEC_BOX) { SelectClipRect (hdc, &(pData->DecSpinBox)); win_info->we_rdr->draw_arrow(hwnd, hdc, &(pData->DecSpinBox), fg_3d, status | LFRDR_ARROW_HAVESHELL | LFRDR_ARROW_LEFT); } } else { if(which == 0 || which == INC_BOX) { SelectClipRect (hdc, &(pData->IncSpinBox)); win_info->we_rdr->draw_arrow(hwnd, hdc, &(pData->IncSpinBox), fg_3d, status | LFRDR_ARROW_HAVESHELL | LFRDR_ARROW_UP); } if(which == 0 || which == DEC_BOX) { SelectClipRect (hdc, &(pData->DecSpinBox)); win_info->we_rdr->draw_arrow(hwnd, hdc, &(pData->DecSpinBox), fg_3d, status | LFRDR_ARROW_HAVESHELL | LFRDR_ARROW_DOWN); } } break; default: SelectClipRect (hdc, &(pData->IncSpinBox)); win_info->we_rdr->draw_arrow(hwnd, hdc, &(pData->IncSpinBox), fg_3d, status | LFRDR_ARROW_HAVESHELL | LFRDR_ARROW_DOWN); break; } if(bGetDC) { ReleaseDC(hdc); } return ; } static void GetSpinBox (PCOMBOBOXDATA pData, DWORD dwStyle, const RECT* rect, RECT* edit_box) { int w, h; if (dwStyle & CBS_SPINARROW_TOPBOTTOM) { w = (rect->right - rect->left) > 16 ? 16 : (rect->right - rect->left); h = (rect->bottom - rect->top)>>1; h = h > (w>>1)? (w>>1) : h; edit_box->left = rect->left; edit_box->top = rect->top + h + INTER_EDIT_BUTTON; edit_box->right = rect->right; edit_box->bottom = rect->bottom - h - INTER_EDIT_BUTTON; pData->IncSpinBox.left = (rect->right - w)>>1; pData->IncSpinBox.right = pData->IncSpinBox.left + w; pData->IncSpinBox.top = rect->top; pData->IncSpinBox.bottom = rect->top + h; pData->DecSpinBox.left = pData->IncSpinBox.left; pData->DecSpinBox.right = pData->IncSpinBox.right; pData->DecSpinBox.top = rect->bottom - h; pData->DecSpinBox.bottom = rect->bottom; } else if (dwStyle & CBS_SPINARROW_LEFTRIGHT) { h = rect->bottom - rect->top; w = h < 16 ? h : 16; edit_box->left = rect->left + (w>>1) + INTER_EDIT_BUTTON; edit_box->top = rect->top; edit_box->bottom = rect->bottom; edit_box->right = rect->right - (w>>1) - INTER_EDIT_BUTTON; pData->DecSpinBox.left = rect->left; pData->DecSpinBox.top = rect->top + ((h-w)>>1); pData->DecSpinBox.right = rect->left + (w>>1); pData->DecSpinBox.bottom = pData->DecSpinBox.top + w; pData->IncSpinBox.left = rect->right - (w>>1); pData->IncSpinBox.top = pData->DecSpinBox.top; pData->IncSpinBox.right = rect->right; pData->IncSpinBox.bottom = pData->DecSpinBox.bottom; } else //updown button on the right { h = rect->bottom - rect->top; w = h < 16 ? h : 16; edit_box->left = rect->left; edit_box->top = rect->top; edit_box->bottom = rect->bottom; edit_box->right = rect->right - w - INTER_EDIT_BUTTON; pData->IncSpinBox.left = rect->right - w; pData->IncSpinBox.top = rect->top + (h>>1) - (w>>1); pData->IncSpinBox.right = rect->right; pData->IncSpinBox.bottom = rect->top + (h>>1) - 1; pData->DecSpinBox.left = rect->right - w; pData->DecSpinBox.top = rect->top + (h>>1) + 1; pData->DecSpinBox.right = rect->right; pData->DecSpinBox.bottom = rect->bottom - (h>>1) + (w >>1); } } static void OnSizeChanged (PCONTROL pCtrl, DWORD dwStyle, const RECT* rcClient) { PCOMBOBOXDATA pData; int tmpx, tmpy; int height, width; int w, h; RECT edit_box, rect; pData = (PCOMBOBOXDATA)pCtrl->dwAddData2; SetRect (&rect, 0, 0, RECTWP (rcClient), RECTHP (rcClient)); width = rect.right - rect.left; switch (dwStyle & CBS_TYPEMASK) { case CBS_SIMPLE: height = GetSysFontHeight (SYSLOGFONT_CONTROL) + MARGIN_EDIT_TOP + MARGIN_EDIT_BOTTOM + (WIDTH_EDIT_BORDER<<1); edit_box.left = rect.left; edit_box.top = rect.top; edit_box.right = rect.left + width; edit_box.bottom = rect.top + height; pData->ListBoxRect.left = rect.left; pData->ListBoxRect.right = rect.right - MARGIN_EDIT_RIGHT; pData->ListBoxRect.top = rect.top + height + INTER_EDIT_LISTBOX; pData->ListBoxRect.bottom = pData->ListBoxRect.top + pData->list_height; break; case CBS_SPINLIST: GetSpinBox (pData, dwStyle, &rect, &edit_box); pData->spin_pace = 1; pData->fastspin_pace = 5; break; case CBS_AUTOSPIN: GetSpinBox (pData, dwStyle, &rect, &edit_box); pData->spin_min = 0; pData->spin_max = 100; pData->spin_pace = 1; pData->fastspin_pace = 5; break; default: // now, for CBS_DROPDOWNLIST h = RECTH(rect); w = h < 16 ? h : 16; edit_box.left = rect.left; edit_box.top = rect.top; edit_box.bottom = rect.bottom; edit_box.right = rect.right - w - INTER_EDIT_BUTTON; pData->DecSpinBox.left = rect.right - w; pData->DecSpinBox.top = rect.top + ((h-w)>>1); pData->DecSpinBox.right = rect.right; pData->DecSpinBox.bottom = pData->DecSpinBox.top + w; pData->IncSpinBox.left = pData->DecSpinBox.left; pData->IncSpinBox.top = pData->DecSpinBox.top; pData->IncSpinBox.right = pData->DecSpinBox.right; pData->IncSpinBox.bottom = pData->DecSpinBox.bottom; pData->ListBoxRect.left = rect.left; pData->ListBoxRect.right = rect.right; pData->ListBoxRect.top = rect.bottom; pData->ListBoxRect.bottom = rect.bottom + pData->list_height; break; } tmpx = pData->ListBoxRect.right; tmpy = pData->ListBoxRect.bottom; ClientToScreen ((HWND)pCtrl, &tmpx, &tmpy); if (tmpy > g_rcScr.bottom) { pData->ListBoxRect.left = rect.left; pData->ListBoxRect.right = rect.right; pData->ListBoxRect.top = rect.top - pData->list_height; pData->ListBoxRect.bottom = rect.top; } if (pData->EditControl) { ShowWindow(pData->EditControl, SW_SHOW); MoveWindow (pData->EditControl, edit_box.left, edit_box.top, RECTW(edit_box), RECTH(edit_box), TRUE); } if (pData->ListBoxControl) { MoveWindow (pData->ListBoxControl, pData->ListBoxRect.left, pData->ListBoxRect.top, width, pData->list_height, TRUE); } } static LRESULT ComboBoxCtrlProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { PCONTROL pCtrl = gui_Control (hwnd); PCOMBOBOXDATA pData = (PCOMBOBOXDATA)pCtrl->dwAddData2; DWORD dwStyle = pCtrl->dwStyle; switch (message) { case MSG_CREATE: { const char* edit_text = GetWindowCaption (hwnd); DWORD list_style, edit_style; if (!(pData = calloc (1, sizeof (COMBOBOXDATA)))) { _ERR_PRINTF ("CONTROL>COMBOBOX: failed to allocate memory to create control instance!\n"); return -1; } pData->wStateFlags = 0; pData->nListItems = 0; pCtrl->dwAddData2 = (DWORD)pData; list_style = WS_VSCROLL | LBS_NOTIFY | WS_THINFRAME; if ((dwStyle & CBS_TYPEMASK) == CBS_DROPDOWNLIST) list_style |= LBS_MOUSEFOLLOW; if (dwStyle & CBS_SORT) list_style |= LBS_SORT; edit_style = WS_CHILD; if (!(dwStyle & CBS_EDITNOBORDER)) edit_style |= WS_BORDER; if (dwStyle & CBS_EDITBASELINE) edit_style |= ES_BASELINE; if (dwStyle & CBS_UPPERCASE) edit_style |= ES_UPPERCASE; if (dwStyle & CBS_LOWERCASE) edit_style |= ES_LOWERCASE; if (dwStyle & CBS_READONLY) edit_style |= ES_READONLY; switch (dwStyle & CBS_TYPEMASK) { case CBS_SIMPLE: list_style |= WS_VISIBLE | WS_BORDER; pData->list_height = (pCtrl->dwAddData > 0) ? pCtrl->dwAddData : DEF_LISTHEIGHT; break; case CBS_SPINLIST: pData->list_height = 0; pData->spin_pace = 1; pData->fastspin_pace = 5; break; case CBS_AUTOSPIN: pData->spin_min = 0; pData->spin_max = 100; pData->spin_pace = 1; pData->fastspin_pace = 5; pData->list_height = -1; break; default: pData->list_height = (pCtrl->dwAddData > 0) ? pCtrl->dwAddData : DEF_LISTHEIGHT; break; } if (pCtrl->dwExStyle & WS_EX_TRANSPARENT) pData->EditControl = CreateWindowEx (CTRL_SLEDIT, edit_text, edit_style, WS_EX_TRANSPARENT, IDC_CEDIT, 0, 0, 10, 10, hwnd, 0); else pData->EditControl = CreateWindow (CTRL_SLEDIT, edit_text, edit_style, IDC_CEDIT, 0, 0, 10, 10, hwnd, 0); if ((dwStyle & CBS_TYPEMASK) == CBS_AUTOSPIN) { WNDPROC old_edit_proc = SetWindowCallbackProc (pData->EditControl, AutoSpinEditBoxProc); SetWindowAdditionalData (pData->EditControl, (DWORD)old_edit_proc); pData->str_format = strdup ("%d"); } if (dwStyle & CBS_EDITNOBORDER) pCtrl->iBkColor = GetWindowBkColor(pData->EditControl); else pCtrl->iBkColor = GetWindowBkColor(GetParent(hwnd)); if (pData->list_height >= 0) { DWORD ex_style = WS_EX_NONE; if ((dwStyle & CBS_TYPEMASK) == CBS_SIMPLE) { ex_style |= (pCtrl->dwExStyle & WS_EX_TRANSPARENT); } else{ ex_style |= WS_EX_CTRLASMAINWIN; } pData->ListBoxControl = CreateWindowEx (CTRL_LISTBOX, "listbox", list_style, ex_style, IDC_CLISTBOX, 0, 0, 0, 0, hwnd, 0); } else { pData->ListBoxControl = 0; } break; } case MSG_DESTROY: DestroyAllControls (hwnd); free (pData->str_format); free (pData); return 0; case MSG_SIZECHANGING: { const RECT* rcExpect = (const RECT*)wParam; RECT* rcResult = (RECT*)lParam; if ((dwStyle & CBS_TYPEMASK) == CBS_SIMPLE) { int height = GetSysFontHeight (SYSLOGFONT_CONTROL) + MARGIN_EDIT_TOP + MARGIN_EDIT_BOTTOM + (WIDTH_EDIT_BORDER<<1); rcResult->left = rcExpect->left; rcResult->top = rcExpect->top; rcResult->right = rcExpect->right; rcResult->bottom = rcExpect->top + height; rcResult->bottom += pData->list_height + INTER_EDIT_LISTBOX*2; return 0; } break; } case MSG_SIZECHANGED: OnSizeChanged (pCtrl, dwStyle, (const RECT*)lParam); break; case MSG_CHILDHIDDEN: { int reason = wParam; int x = LOSWORD(lParam); int y = HISWORD(lParam); if (reason == RCTM_CLICK) ScreenToClient (hwnd, &x, &y); if (IS_SET (pData, CSF_HASDROPPED)) { CLEAR_STATE (pData, CSF_HASDROPPED); NotifyParent (hwnd, pCtrl->id, CBN_SELECTCANCEL); NotifyParent (hwnd, pCtrl->id, CBN_CLOSEUP); } if (((dwStyle & CBS_TYPEMASK) > CBS_AUTOSPIN) && PtInRect (&pData->IncSpinBox, x, y)) SET_STATE (pData, CSF_HASDROPPED); break; } case MSG_SETFOCUS: if (dwStyle & CBS_AUTOFOCUS || dwStyle & WS_TABSTOP) SetFocusChild (pData->EditControl); if (dwStyle & CBS_NOTIFY) NotifyParent (hwnd, pCtrl->id, CBN_SETFOCUS); break; case MSG_KILLFOCUS: if (((dwStyle & CBS_TYPEMASK) == CBS_DROPDOWNLIST) && IS_SET (pData, CSF_HASDROPPED)) { ShowWindow (pData->ListBoxControl, SW_HIDE); CLEAR_STATE (pData, CSF_HASDROPPED); if (dwStyle & CBS_NOTIFY) { NotifyParent (hwnd, pCtrl->id, CBN_SELECTCANCEL); NotifyParent (hwnd, pCtrl->id, CBN_CLOSEUP); } } if (dwStyle & CBS_NOTIFY) NotifyParent (hwnd, pCtrl->id, CBN_KILLFOCUS); break; case MSG_LBUTTONDOWN: { int x = LOSWORD(lParam); int y = HISWORD(lParam); BOOL inc = FALSE; if (PtInRect (&pData->IncSpinBox, x, y)) { inc = TRUE; //SendMessage(hwnd, MSG_PAINT, // MAKELONG(INC_BOX, LFRDR_BTN_STATUS_PRESSED), 0); ComboBoxDrawSpinButton(hwnd, 0, INC_BOX, LFRDR_BTN_STATUS_PRESSED); } else if (PtInRect (&pData->DecSpinBox, x, y)) { inc = FALSE; //SendMessage(hwnd, MSG_PAINT, // MAKELONG(DEC_BOX, LFRDR_BTN_STATUS_PRESSED), 0); ComboBoxDrawSpinButton(hwnd, 0, DEC_BOX, LFRDR_BTN_STATUS_PRESSED); } else break; switch (dwStyle & CBS_TYPEMASK) { case CBS_SPINLIST: SetCapture (hwnd); SendMessage (hwnd, CB_SPIN, inc, 0); SetAutoRepeatMessage (hwnd, CB_FASTSPIN, inc, 0); break; case CBS_AUTOSPIN: SetCapture (hwnd); SendMessage (hwnd, CB_SPIN, !inc, 0); SetAutoRepeatMessage (hwnd, CB_FASTSPIN, !inc, 0); break; case CBS_DROPDOWNLIST: if (IS_SET (pData, CSF_HASDROPPED)) { CLEAR_STATE (pData, CSF_HASDROPPED); } else { ShowWindow (pData->ListBoxControl, SW_SHOW); SetFocusChild (pData->ListBoxControl); SendNotifyMessage (pData->ListBoxControl, MSG_SETFOCUS, 0,0); SET_STATE (pData, CSF_HASDROPPED); if (dwStyle & CBS_NOTIFY) NotifyParent (hwnd, pCtrl->id, CBN_DROPDOWN); } break; } break; } case MSG_LBUTTONUP: { int x = LOSWORD(lParam); int y = HISWORD(lParam); if(!((dwStyle & CBS_TYPEMASK) == CBS_DROPDOWNLIST)) ScreenToClient(hwnd, &x, &y); if (PtInRect (&pData->IncSpinBox, x, y)) { //SendMessage(hwnd, MSG_PAINT, // MAKELONG(INC_BOX, LFRDR_BTN_STATUS_HILITE), 0); ComboBoxDrawSpinButton(hwnd, 0, INC_BOX, LFRDR_BTN_STATUS_HILITE); mouse_old = INC_BOX; } else if (PtInRect (&pData->DecSpinBox, x, y)) { //SendMessage(hwnd, MSG_PAINT, // MAKELONG(DEC_BOX, LFRDR_BTN_STATUS_HILITE), 0); ComboBoxDrawSpinButton(hwnd, 0, DEC_BOX, LFRDR_BTN_STATUS_HILITE); mouse_old = DEC_BOX; } switch (dwStyle & CBS_TYPEMASK) { case CBS_SPINLIST: if (IS_SET (pData, CSF_HASDROPPED)) { SetFocusChild (pData->ListBoxControl); } case CBS_AUTOSPIN: /* cancel repeat message */ SetAutoRepeatMessage (0, 0, 0, 0); ReleaseCapture (); } NotifyParent (hwnd, pCtrl->id, CBN_CLICKED); break; } case MSG_KEYDOWN: { switch (dwStyle & CBS_TYPEMASK) { case CBS_SPINLIST: case CBS_AUTOSPIN: switch (LOWORD(wParam)) { case SCANCODE_CURSORBLOCKUP: case SCANCODE_CURSORBLOCKDOWN: SendMessage (hwnd, CB_SPIN, (LOWORD(wParam) == SCANCODE_CURSORBLOCKDOWN), 0); break; case SCANCODE_PAGEUP: case SCANCODE_PAGEDOWN: SendMessage (hwnd, CB_FASTSPIN, (LOWORD(wParam) == SCANCODE_PAGEDOWN), 0); break; } break; case CBS_DROPDOWNLIST: switch (LOWORD(wParam)) { case SCANCODE_ESCAPE: if (IS_SET (pData, CSF_HASDROPPED)) { ShowWindow (pData->ListBoxControl, SW_HIDE); CLEAR_STATE (pData, CSF_HASDROPPED); if (dwStyle & CBS_NOTIFY) { NotifyParent (hwnd, pCtrl->id, CBN_SELECTCANCEL); NotifyParent (hwnd, pCtrl->id, CBN_CLOSEUP); } SetFocusChild (pData->EditControl); } break; case SCANCODE_KEYPADENTER: case SCANCODE_ENTER: if (IS_SET (pData, CSF_HASDROPPED)) { ShowWindow (pData->ListBoxControl, SW_HIDE); CLEAR_STATE (pData, CSF_HASDROPPED); if (dwStyle & CBS_NOTIFY) { NotifyParent (hwnd, pCtrl->id, CBN_SELECTOK); NotifyParent (hwnd, pCtrl->id, CBN_CLOSEUP); } SetFocusChild (pData->EditControl); } break; case SCANCODE_CURSORBLOCKUP: case SCANCODE_PAGEUP: case SCANCODE_CURSORBLOCKDOWN: case SCANCODE_PAGEDOWN: if (!IS_SET (pData, CSF_HASDROPPED)) { ShowWindow (pData->ListBoxControl, SW_SHOW); SetFocusChild (pData->ListBoxControl); SET_STATE (pData, CSF_HASDROPPED); if (dwStyle & CBS_NOTIFY) NotifyParent (hwnd, pCtrl->id, CBN_DROPDOWN); } break; } break; } } case MSG_COMMAND: { int len; char *buffer; int sel; int id = LOWORD(wParam); int code = HIWORD(wParam); switch (id) { case IDC_CLISTBOX: { if ((dwStyle & CBS_TYPEMASK) == CBS_DROPDOWNLIST && (code == LBN_CLICKED || code == LBN_KILLFOCUS)){ if (IS_SET (pData, CSF_HASDROPPED)) { ShowWindow (pData->ListBoxControl, SW_HIDE); CLEAR_STATE (pData, CSF_HASDROPPED); if (dwStyle & CBS_NOTIFY) { NotifyParent (hwnd, pCtrl->id, CBN_SELECTOK); NotifyParent (hwnd, pCtrl->id, CBN_CLOSEUP); } } break; } if (code == LBN_DBLCLK && (dwStyle & CBS_NOTIFY)) { NotifyParent (hwnd, pCtrl->id, CBN_DBLCLK); break; } if (code != LBN_SELCHANGE && dwStyle & CBS_READONLY) break; if ((sel = SendMessage (pData->ListBoxControl, LB_GETCURSEL, 0, 0)) >= 0) { len = SendMessage (pData->ListBoxControl, LB_GETTEXTLEN, sel, 0); buffer = ALLOCATE_LOCAL (len + 1); //buffer = FixStrAlloc (len + 1); SendMessage (pData->ListBoxControl, LB_GETTEXT, sel, (LPARAM)buffer); SendMessage (pData->EditControl, MSG_SETTEXT, 0, (LPARAM)buffer); DEALLOCATE_LOCAL(buffer); //FreeFixStr (buffer); } if (dwStyle & CBS_NOTIFY) NotifyParent (hwnd, pCtrl->id, CBN_SELCHANGE); break; } case IDC_CEDIT: if (code == EN_DBLCLK && dwStyle & CBS_NOTIFY) { NotifyParent (hwnd, pCtrl->id, CBN_DBLCLK); } else if (code == EN_CLICKED) { NotifyParent (hwnd, pCtrl->id, CBN_CLICKED); } else if (code == EN_CHANGE) { if (GetFocusChild(hwnd) == pData->EditControl) { if (pData->ListBoxControl) { int len = GetWindowTextLength(pData->EditControl); if ( len > 0) { #ifdef HAVE_ALLOCA char *str = (char*)alloca(len+1); #else char *str = (char*)malloc(len+1); #endif if(str){ GetWindowText (pData->EditControl, str, len); if ((sel = SendMessage (pData->ListBoxControl, LB_FINDSTRING, 0, (LPARAM)str)) >= 0) SendMessage (pData->ListBoxControl, LB_SETCURSEL, sel, 0); #ifndef HAVE_ALLOCA free(str); #endif } } } } if (dwStyle & CBS_NOTIFY) NotifyParent (hwnd, pCtrl->id, CBN_EDITCHANGE); } break; } break; } case MSG_GETDLGCODE: return DLGC_WANTARROWS | DLGC_WANTENTER; case MSG_FONTCHANGED: SetWindowFont (pData->EditControl, GetWindowFont (hwnd)); if (pData->ListBoxControl) SetWindowFont (pData->ListBoxControl, GetWindowFont (hwnd)); return 0; case MSG_MOUSEMOVEIN: mouse_old = 0; if(!(BOOL)wParam) //SendMessage(hwnd, MSG_PAINT, 0, 0); ComboBoxDrawSpinButton(hwnd, 0, 0, 0); break; case MSG_MOUSEMOVE: { int mouse = 0; int x_pos = LOSWORD (lParam); int y_pos = HISWORD (lParam); if(PtInRect(&pData->IncSpinBox, x_pos, y_pos)) mouse = INC_BOX; else if(PtInRect(&pData->DecSpinBox, x_pos, y_pos)) mouse = DEC_BOX; else mouse = 0; if(mouse != mouse_old) { //SendMessage(hwnd, MSG_PAINT, // MAKELONG(mouse, LFRDR_BTN_STATUS_HILITE), 0); ComboBoxDrawSpinButton(hwnd, 0, mouse, LFRDR_BTN_STATUS_HILITE); mouse_old = mouse; } break; } case MSG_PAINT: { HDC hdc; hdc = BeginPaint (hwnd); ComboBoxDrawSpinButton (hwnd, hdc, 0, 0); EndPaint (hwnd, hdc); return 0; } case CB_GETCHILDREN: { HWND* wnd_edit = (HWND*)wParam; HWND* wnd_listbox = (HWND*)lParam; *wnd_edit = pData->EditControl; *wnd_listbox = pData->ListBoxControl; return 0; } /* when click the up/down button, * spin the value of SIMPLE and AUTOSPIN combobox */ case CB_SPIN: switch (dwStyle & CBS_TYPEMASK) { case CBS_SPINLIST: if (wParam) SendMessage (pData->ListBoxControl, MSG_KEYDOWN, SCANCODE_CURSORBLOCKDOWN, 0); else SendMessage (pData->ListBoxControl, MSG_KEYDOWN, SCANCODE_CURSORBLOCKUP, 0); break; case CBS_AUTOSPIN: { char buffer [LEN_SPINVALUE+1]; int cur_value = 0; int new_value; GetWindowText (pData->EditControl, buffer, LEN_SPINVALUE); #if 0 cur_value = new_value = strtol (buffer, NULL, 0); #else sscanf (buffer, pData->str_format, &cur_value); new_value = cur_value; #endif if (wParam) { new_value -= pData->spin_pace; } else { new_value += pData->spin_pace; } if (dwStyle & CBS_AUTOLOOP) { if (new_value > pData->spin_max) new_value = pData->spin_min; else if (new_value < pData->spin_min) new_value = pData->spin_max; } else { if (new_value > pData->spin_max) new_value = pData->spin_max; else if (new_value < pData->spin_min) new_value = pData->spin_min; } if (new_value != cur_value) { snprintf (buffer, LEN_SPINVALUE, pData->str_format, new_value); SetWindowText (pData->EditControl, buffer); if (dwStyle & CBS_NOTIFY) NotifyParent (hwnd, pCtrl->id, CBN_EDITCHANGE); } break; } } break; case CB_FASTSPIN: switch (dwStyle & CBS_TYPEMASK) { case CBS_SPINLIST: if (wParam) SendMessage (pData->ListBoxControl, MSG_KEYDOWN, SCANCODE_PAGEDOWN, 0); else SendMessage (pData->ListBoxControl, MSG_KEYDOWN, SCANCODE_PAGEUP, 0); break; case CBS_AUTOSPIN: { char buffer [LEN_SPINVALUE+1]; int cur_value, new_value; GetWindowText (pData->EditControl, buffer, LEN_SPINVALUE); #if 0 cur_value = new_value = strtol (buffer, NULL, 0); #else sscanf (buffer, pData->str_format, &cur_value); new_value = cur_value; #endif if (wParam) { new_value -= pData->fastspin_pace; } else { new_value += pData->fastspin_pace; } if (dwStyle & CBS_AUTOLOOP) { if (new_value > pData->spin_max) new_value = pData->spin_min; else if (new_value < pData->spin_min) new_value = pData->spin_max; } else { if (new_value > pData->spin_max) new_value = pData->spin_max; else if (new_value < pData->spin_min) new_value = pData->spin_min; } if (new_value != cur_value) { snprintf (buffer, LEN_SPINVALUE, pData->str_format, new_value); SetWindowText (pData->EditControl, buffer); if (dwStyle & CBS_NOTIFY) NotifyParent (hwnd, pCtrl->id, CBN_EDITCHANGE); } break; } } break; break; } if ((dwStyle & CBS_TYPEMASK) == CBS_AUTOSPIN) { switch (message) { case CB_SETSPINFORMAT: { free (pData->str_format); if ((pData->str_format = strdup ((const char*)lParam))) return CB_OKAY; return CB_ERR; } case CB_SETSPINRANGE: { char buffer [LEN_SPINVALUE+1]; int new_min = (int)wParam; int new_max = (int)lParam; int cur_value; if (new_min > new_max) return CB_ERR; pData->spin_min = (int)wParam; pData->spin_max = (int)lParam; GetWindowText (pData->EditControl, buffer, LEN_SPINVALUE); #if 0 cur_value = strtol (buffer, NULL, 0); #else sscanf (buffer, pData->str_format, &cur_value); #endif if (cur_value < pData->spin_min) { snprintf (buffer, LEN_SPINVALUE, pData->str_format, pData->spin_min); SetWindowText (pData->EditControl, buffer); } else if (cur_value > pData->spin_max) { snprintf (buffer, LEN_SPINVALUE, pData->str_format, pData->spin_max); SetWindowText (pData->EditControl, buffer); } return CB_OKAY; } case CB_GETSPINRANGE: { int* spin_min = (int*)wParam; int* spin_max = (int*)lParam; if (spin_min) *spin_min = pData->spin_min; if (spin_max) *spin_max = pData->spin_max; return CB_OKAY; } case CB_SETSPINVALUE: { int new_value = (int)wParam; char buffer [LEN_SPINVALUE+1]; if (new_value < pData->spin_min || new_value > pData->spin_max) return CB_ERR; snprintf (buffer, LEN_SPINVALUE, pData->str_format, new_value); SetWindowText (pData->EditControl, buffer); return CB_OKAY; } case CB_GETSPINVALUE: { char buffer [LEN_SPINVALUE+1]; int value; GetWindowText (pData->EditControl, buffer, LEN_SPINVALUE); sscanf (buffer, pData->str_format, &value); return value; // return strtol (buffer, NULL, 0); } case CB_SETSPINPACE: { int pace = (int)wParam; int fastpace = (int)lParam; if (pace != 0) pData->spin_pace = pace; if (fastpace != 0) pData->fastspin_pace = fastpace; return CB_OKAY; } case CB_GETSPINPACE: { int *pace = (int*)wParam; int *fastpace = (int*)lParam; if (pace) *pace = pData->spin_pace; if (*fastpace) *fastpace = pData->fastspin_pace; return CB_OKAY; } } return DefaultControlProc (hwnd, message, wParam, lParam); } else return DefCBProc (hwnd, message, wParam, lParam); } static int DefCBProc (HWND hWnd, int message, WPARAM wParam, LPARAM lParam) { PCOMBOBOXDATA pData; int len, index; char *selection; int rc; pData = (COMBOBOXDATA *) gui_Control(hWnd)->dwAddData2; switch (message) { /* messages specific to the listbox control */ case CB_SETSTRCMPFUNC: return SendMessage (pData->ListBoxControl, LB_SETSTRCMPFUNC, wParam, lParam); case CB_ADDSTRING: rc = SendMessage (pData->ListBoxControl, LB_ADDSTRING, wParam, lParam); if (rc >= 0) pData->nListItems++; return rc; case CB_DELETESTRING: rc = SendMessage (pData->ListBoxControl, LB_DELETESTRING, wParam, lParam); if (rc == 0) { int idx; pData->nListItems--; if (pData->nListItems <= wParam) idx = pData->nListItems - 1; else idx = wParam; SendMessage (hWnd, CB_SETCURSEL, idx, 0); } return rc; case CB_DIR: return SendMessage (pData->ListBoxControl, LB_DIR, wParam, lParam); case CB_FINDSTRING: return SendMessage (pData->ListBoxControl, LB_FINDSTRING, wParam, lParam); case CB_FINDSTRINGEXACT: return SendMessage (pData->ListBoxControl, LB_FINDSTRINGEXACT, wParam, lParam); case CB_GETCOUNT: return SendMessage (pData->ListBoxControl, LB_GETCOUNT, wParam, lParam); case CB_GETITEMADDDATA: return SendMessage (pData->ListBoxControl, LB_GETITEMADDDATA, wParam, lParam); case CB_SETITEMADDDATA: return SendMessage (pData->ListBoxControl, LB_SETITEMADDDATA, wParam, lParam); case CB_GETITEMHEIGHT: return SendMessage (pData->ListBoxControl, LB_GETITEMHEIGHT, wParam, lParam); case CB_SETITEMHEIGHT: return SendMessage (pData->ListBoxControl, LB_SETITEMHEIGHT, wParam, lParam); case CB_GETLBTEXT: return SendMessage (pData->ListBoxControl, LB_GETTEXT, wParam, lParam); case CB_GETLBTEXTLEN: return SendMessage (pData->ListBoxControl, LB_GETTEXTLEN, wParam, lParam); case CB_INSERTSTRING: rc = SendMessage (pData->ListBoxControl, LB_INSERTSTRING, wParam, lParam); if (rc >= 0) pData->nListItems++; return rc; case CB_GETCURSEL: return SendMessage (pData->ListBoxControl, LB_GETCURSEL, wParam, lParam); case CB_SETCURSEL: if (SendMessage (pData->ListBoxControl, LB_SETCURSEL, wParam, lParam) == LB_ERR) { SetWindowText (pData->EditControl, ""); return CB_ERR; } index = SendMessage (pData->ListBoxControl, LB_GETCURSEL, wParam, lParam); len = SendMessage (pData->ListBoxControl, LB_GETTEXTLEN, index, 0); if (len <= 0) { SetWindowText (pData->EditControl, ""); return CB_ERR; } selection = FixStrAlloc (len + 1); SendMessage (pData->ListBoxControl, LB_GETTEXT, (WPARAM)index, (LPARAM)selection); SetWindowText (pData->EditControl, selection); FreeFixStr (selection); break; /* messages specific to the edit control */ case CB_GETEDITSEL: return SendMessage (pData->EditControl, EM_GETSEL, wParam, lParam); case CB_LIMITTEXT: return SendMessage (pData->EditControl, EM_LIMITTEXT, wParam, lParam); case CB_SETEDITSEL: return SendMessage (pData->EditControl, EM_SETSEL, wParam, lParam); case MSG_GETTEXTLENGTH: return SendMessage (pData->EditControl, MSG_GETTEXTLENGTH, wParam, lParam); case MSG_GETTEXT: return SendMessage (pData->EditControl, MSG_GETTEXT, wParam, lParam); case MSG_SETTEXT: return SendMessage (pData->EditControl, MSG_SETTEXT, wParam, lParam); /* messages handled by the combobox itself */ case CB_GETDROPPEDCONTROLRECT: if (pData->ListBoxControl) { CopyRect ((PRECT)lParam, &pData->ListBoxRect); return 0; } return CB_ERR; case CB_GETDROPPEDSTATE: return IS_SET (pData, CSF_CAPTUREACTIVE); case CB_RESETCONTENT: SendMessage (pData->ListBoxControl, LB_RESETCONTENT, 0, 0); SetWindowText (pData->EditControl, ""); return 0; case CB_SELECTSTRING: index = SendMessage (pData->ListBoxControl, LB_SELECTSTRING, wParam, lParam); if (index == LB_ERR) return CB_ERR; len = SendMessage (pData->ListBoxControl, LB_GETTEXTLEN, index, 0); if (len <= 0) return CB_ERR; selection = FixStrAlloc (len + 1); rc = SendMessage (pData->ListBoxControl, LB_GETTEXT, (WPARAM)index, (LPARAM)selection); SetWindowText (pData->EditControl, selection); FreeFixStr (selection); break; } return DefaultControlProc (hWnd, message, wParam, lParam); } #endif /* _MGCTRL_COMBOBOX */