FILE COMPARISON
Produced: 2/18/2011 1:25:47 PM
   
Mode:  All Lines  
   
Left file: C:\Documents and Settings\krollins\My Documents\Admin\OpenSource\eRCP\eSWT\current\source\modified\original\Combo.c  
Right file: C:\Documents and Settings\krollins\My Documents\Admin\OpenSource\eRCP\eSWT\current\source\modified\Combo.c  
1 /******************************************************************************* = 1 /*******************************************************************************
2 * Copyright (c) 2000, 2005 IBM Corporation and others.   2 * Copyright (c) 2000, 2005 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials   3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0   4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at   5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html   6 * http://www.eclipse.org/legal/epl-v10.html
7 *   7 *
8 * Contributors:   8 * Contributors:
9 *     IBM Corporation - initial API and implementation   9 *     IBM Corporation - initial API and implementation
10 *******************************************************************************/   10 *******************************************************************************/
    <> 11 /*******************************************************************************
      12 * Additions/modifications to this source file by Oracle America, Inc. 2011
      13 *******************************************************************************/
11   = 14  
12 #include "ugl_win32.h"   15 #include "ugl_win32.h"
13 #include "UGL_Win32_Widget.h"   16 #include "UGL_Win32_Widget.h"
14 #include "UGL_win32_display.h"   17 #include "UGL_win32_display.h"
15 #include "UGL_Win32_DC.h"   18 #include "UGL_Win32_DC.h"
16     19  
17 #include "Widget.h"   20 #include "Widget.h"
18 #include "Control.h"   21 #include "Control.h"
19 #include "Choice.h"   22 #include "Choice.h"
20 #include "Combo.h"   23 #include "Combo.h"
21 #include "VerifyHelpers.h"   24 #include "VerifyHelpers.h"
22     25  
23 //========================================================================================   26 //========================================================================================
24 #define CBID_EDIT       1001   27 #define CBID_EDIT       1001
25 #define CBID_LIST       1000   28 #define CBID_LIST       1000
26 static UGL_Int _Combo_ExStyle(UGL_Int ugl_style);   29 static UGL_Int _Combo_ExStyle(UGL_Int ugl_style);
27 static UGL_Int _Combo_Style(UGL_Int ugl_style);   30 static UGL_Int _Combo_Style(UGL_Int ugl_style);
28 void _Dispose_Combo(UGL_Int handle, UGL_Error uglError);   31 void _Dispose_Combo(UGL_Int handle, UGL_Error uglError);
29 int _Combo_CTLCOLOR(PUGL_Control parent_control, HDC hdc, PUGL_Control color_control);   32 int _Combo_CTLCOLOR(PUGL_Control parent_control, HDC hdc, PUGL_Control color_control);
30 LRESULT _Combo_CommandChild(PUGL_Control ugl_control, WPARAM wParam, HWND hWnd);   33 LRESULT _Combo_CommandChild(PUGL_Control ugl_control, WPARAM wParam, HWND hWnd);
31 void _Combo_SetBounds(PUGL_Control ugl_control, LPRECT bounds);   34 void _Combo_SetBounds(PUGL_Control ugl_control, LPRECT bounds);
32     35  
33 static LRESULT CALLBACK _Combo_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);   36 static LRESULT CALLBACK _Combo_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
34 void _Combo_GetMinimumSize(UGL_Int handle, POINT *point, UGL_Error uglError);   37 void _Combo_GetMinimumSize(UGL_Int handle, POINT *point, UGL_Error uglError);
35 LRESULT CALLBACK _Combo_Text_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);   38 LRESULT CALLBACK _Combo_Text_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
36 LRESULT CALLBACK _Combo_List_Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);   39 LRESULT CALLBACK _Combo_List_Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
37     40  
38 UGL_Boolean _Combo_SendKeyEvent(PUGL_Control control, UGL_Int type, UGL_Char character, UGL_Int keycode, UGL_Int modifiers);   41 UGL_Boolean _Combo_SendKeyEvent(PUGL_Control control, UGL_Int type, UGL_Char character, UGL_Int keycode, UGL_Int modifiers);
39     42  
40 UGL_Boolean _Combo_Text_ProcessWmChar(PUGL_Control ugl_control, TCHAR ch);   43 UGL_Boolean _Combo_Text_ProcessWmChar(PUGL_Control ugl_control, TCHAR ch);
41 void _Combo_Text_CombineNewString(TCHAR *curStr, TCHAR *newStr, int pos1, int pos2, TCHAR ch);   44 void _Combo_Text_CombineNewString(TCHAR *curStr, TCHAR *newStr, int pos1, int pos2, TCHAR ch);
42 UGL_Boolean _Combo_Text_FindAndSelectItem(HWND hwnd, LPCSTR str);   45 UGL_Boolean _Combo_Text_FindAndSelectItem(HWND hwnd, LPCSTR str);
43 void _Combo_Text_RestoreText(PUGL_Control ugl_control);   46 void _Combo_Text_RestoreText(PUGL_Control ugl_control);
44 void _Combo_Text_SaveText(PUGL_Control ugl_control);   47 void _Combo_Text_SaveText(PUGL_Control ugl_control);
45 HWND comboHwnd = NULL; +-    
46 //======================================================================================== = 48 //========================================================================================
47     49  
48 void Combo_ReplaceText(UGL_Int handle, UGL_String text, int start, int end, UGL_Error uglError) {   50 void Combo_ReplaceText(UGL_Int handle, UGL_String text, int start, int end, UGL_Error uglError) {
49     PUGL_Control ugl_combo = (PUGL_Control)handle;   51     PUGL_Control ugl_combo = (PUGL_Control)handle;
50     HWND textHWnd = GetDlgItem(ugl_combo->hWnd, CBID_EDIT);   52     HWND textHWnd = GetDlgItem(ugl_combo->hWnd, CBID_EDIT);
51       53    
52     SendMessage(textHWnd, EM_SETSEL, start, end);   54     SendMessage(textHWnd, EM_SETSEL, start, end);
53     SendMessage(textHWnd, EM_SCROLLCARET, 0, 0);   55     SendMessage(textHWnd, EM_SCROLLCARET, 0, 0);
54     56  
55     UGL_COMBO(handle)->ignoreChange = TRUE;   57     UGL_COMBO(handle)->ignoreChange = TRUE;
56     SendMessage(textHWnd, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)text);   58     SendMessage(textHWnd, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)text);
57     UGL_COMBO(handle)->ignoreChange = FALSE;   59     UGL_COMBO(handle)->ignoreChange = FALSE;
58 }   60 }
59     61  
60 //========================================================================================   62 //========================================================================================
61     63  
62 UGL_String Combo_GetText(UGL_Int handle, UGL_Boolean* shouldFreeResult, UGL_Error uglError) {   64 UGL_String Combo_GetText(UGL_Int handle, UGL_Boolean* shouldFreeResult, UGL_Error uglError) {
63     PUGL_Control ugl_combo = (PUGL_Control)handle;   65     PUGL_Control ugl_combo = (PUGL_Control)handle;
64     UGL_String text = NULL;   66     UGL_String text = NULL;
65     int length = GetWindowTextLength(ugl_combo->hWnd);   67     int length = GetWindowTextLength(ugl_combo->hWnd);
66       68    
67     if (length == 0) {   69     if (length == 0) {
68         *shouldFreeResult = FALSE;   70         *shouldFreeResult = FALSE;
69         return _T("");   71         return _T("");
70     }   72     }
71     73  
72     text = (UGL_String)calloc(sizeof(TCHAR), length+1);   74     text = (UGL_String)calloc(sizeof(TCHAR), length+1);
73     if (text == NULL) {   75     if (text == NULL) {
74         Win32Error_SetError(uglError, UGL_ERROR_OUT_OF_MEMORY, _T("Unable to allocate memory for text"));   76         Win32Error_SetError(uglError, UGL_ERROR_OUT_OF_MEMORY, _T("Unable to allocate memory for text"));
75         return (UGL_String)NULL;   77         return (UGL_String)NULL;
76     }   78     }
77     79  
78     GetWindowText(ugl_combo->hWnd, (LPTSTR)text, length + 1);   80     GetWindowText(ugl_combo->hWnd, (LPTSTR)text, length + 1);
79       81    
80     *shouldFreeResult = TRUE;   82     *shouldFreeResult = TRUE;
81     return text;   83     return text;
82 }   84 }
83 //========================================================================================   85 //========================================================================================
84     86  
85 UGL_Int Combo_GetDefaultTextLimit(UGL_Error uglError) {   87 UGL_Int Combo_GetDefaultTextLimit(UGL_Error uglError) {
86     OSVERSIONINFO info;   88     OSVERSIONINFO info;
87           89        
88     GetVersionEx((LPOSVERSIONINFO)&info);   90     GetVersionEx((LPOSVERSIONINFO)&info);
89     return (info.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 0x7FFFFFFF : 0x7FFF;   91     return (info.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 0x7FFFFFFF : 0x7FFF;
90 }   92 }
91 //========================================================================================   93 //========================================================================================
92     94  
93 UGL_Int Combo_GetTextHeight(UGL_Int handle, UGL_Error uglError) {   95 UGL_Int Combo_GetTextHeight(UGL_Int handle, UGL_Error uglError) {
94     PUGL_Control ugl_combo = (PUGL_Control)handle;   96     PUGL_Control ugl_combo = (PUGL_Control)handle;
95     97  
96     int result = SendMessage(ugl_combo->hWnd, CB_GETITEMHEIGHT, -1, 0);   98     int result = SendMessage(ugl_combo->hWnd, CB_GETITEMHEIGHT, -1, 0);
97     if (result == CB_ERR) {   99     if (result == CB_ERR) {
98         Win32Error_SetError(uglError, GetLastError(), _T("Unable to get item height"));   100         Win32Error_SetError(uglError, GetLastError(), _T("Unable to get item height"));
99         return 0;   101         return 0;
100     }   102     }
101       103    
102     // why the +6? SWT does it, no other reason...   104     // why the +6? SWT does it, no other reason...
103     return result + 6;   105     return result + 6;
104 }   106 }
105 //========================================================================================   107 //========================================================================================
106     108  
107 void Combo_SetTextLimit(UGL_Int handle, UGL_Int limit, UGL_Error uglError) {   109 void Combo_SetTextLimit(UGL_Int handle, UGL_Int limit, UGL_Error uglError) {
108     PUGL_Control ugl_combo = (PUGL_Control)handle;   110     PUGL_Control ugl_combo = (PUGL_Control)handle;
109     111  
110     if (limit == 0) {   112     if (limit == 0) {
111         Win32Error_SetError(uglError, UGL_ERROR_OTHER, _T("Limit can not be 0 for combo"));   113         Win32Error_SetError(uglError, UGL_ERROR_OTHER, _T("Limit can not be 0 for combo"));
112         return;   114         return;
113     }   115     }
114     116  
115     SendMessage(ugl_combo->hWnd, CB_LIMITTEXT, limit, 0);   117     SendMessage(ugl_combo->hWnd, CB_LIMITTEXT, limit, 0);
116 }   118 }
117 //========================================================================================   119 //========================================================================================
118     120  
119 UGL_Int Combo_GetItemHeight(UGL_Int handle, UGL_Error uglError) {   121 UGL_Int Combo_GetItemHeight(UGL_Int handle, UGL_Error uglError) {
120     PUGL_Control ugl_combo = (PUGL_Control)handle;   122     PUGL_Control ugl_combo = (PUGL_Control)handle;
121     123  
122     int result = SendMessage(ugl_combo->hWnd, CB_GETITEMHEIGHT, 0, 0);   124     int result = SendMessage(ugl_combo->hWnd, CB_GETITEMHEIGHT, 0, 0);
123     if (result == CB_ERR) {   125     if (result == CB_ERR) {
124         Win32Error_SetError(uglError, GetLastError(), _T("Unable to get item height from combo"));   126         Win32Error_SetError(uglError, GetLastError(), _T("Unable to get item height from combo"));
125         return 0;   127         return 0;
126     } else {   128     } else {
127         return result;   129         return result;
128     }   130     }
129 }   131 }
130 //========================================================================================   132 //========================================================================================
131     133  
132 void Combo_DeselectItem(UGL_Int handle, UGL_Int index, UGL_Error uglError) {   134 void Combo_DeselectItem(UGL_Int handle, UGL_Int index, UGL_Error uglError) {
133     PUGL_Control ugl_combo = (PUGL_Control)handle;   135     PUGL_Control ugl_combo = (PUGL_Control)handle;
134     int selection = SendMessage(ugl_combo->hWnd, CB_GETCURSEL, 0, 0);   136     int selection = SendMessage(ugl_combo->hWnd, CB_GETCURSEL, 0, 0);
135     137  
136     if (index != selection) return;   138     if (index != selection) return;
137     SendMessage(ugl_combo->hWnd, CB_SETCURSEL, -1, 0);   139     SendMessage(ugl_combo->hWnd, CB_SETCURSEL, -1, 0);
138 }   140 }
139 //========================================================================================   141 //========================================================================================
140     142  
141 void Combo_DeselectAllItems(UGL_Int handle, UGL_Error uglError) {   143 void Combo_DeselectAllItems(UGL_Int handle, UGL_Error uglError) {
142     PUGL_Control ugl_combo = (PUGL_Control)handle;   144     PUGL_Control ugl_combo = (PUGL_Control)handle;
143       145    
144     SendMessage(ugl_combo->hWnd, CB_SETCURSEL, -1, 0);   146     SendMessage(ugl_combo->hWnd, CB_SETCURSEL, -1, 0);
145 }   147 }
146 //========================================================================================   148 //========================================================================================
147     149  
148 void Combo_SetText(UGL_Int handle, UGL_String string, UGL_Error uglError) {   150 void Combo_SetText(UGL_Int handle, UGL_String string, UGL_Error uglError) {
149     PUGL_Control ugl_combo = (PUGL_Control)handle;   151     PUGL_Control ugl_combo = (PUGL_Control)handle;
150     152  
151     // this is desired behavior?   153     // this is desired behavior?
152     if (((PUGL_Combo)ugl_combo)->is_read_only) {   154     if (((PUGL_Combo)ugl_combo)->is_read_only) {
153         //int index = indexOf (string);   155         //int index = indexOf (string);
154         //if (index != -1) select (index);   156         //if (index != -1) select (index);
155         return;   157         return;
156     }   158     }
157     159  
158     SetWindowText(ugl_combo->hWnd, string);   160     SetWindowText(ugl_combo->hWnd, string);
159 }   161 }
160 //========================================================================================   162 //========================================================================================
161     163  
162 void Combo_SetOrientation(UGL_Int handle, UGL_Int orientation, UGL_Error uglError) {   164 void Combo_SetOrientation(UGL_Int handle, UGL_Int orientation, UGL_Error uglError) {
163     PUGL_Combo ugl_combo = UGL_COMBO(handle);   165     PUGL_Combo ugl_combo = UGL_COMBO(handle);
164     166  
165 #ifdef _WIN32_WCE   167 #ifdef _WIN32_WCE
166     return;   168     return;
167 #else   169 #else
168     //if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) return;   170     //if ((OS.WIN32_MAJOR << 16 | OS.WIN32_MINOR) < (4 << 16 | 10)) return;
169     int flags = UGL_STYLE_LEFT_TO_RIGHT | UGL_STYLE_RIGHT_TO_LEFT;   171     int flags = UGL_STYLE_LEFT_TO_RIGHT | UGL_STYLE_RIGHT_TO_LEFT;
170     int bits = 0;   172     int bits = 0;
171     HWND hwndList, hwndText, hwnd;   173     HWND hwndList, hwndText, hwnd;
172     174  
173     hwnd = UGL_CONTROL(ugl_combo)->hWnd;   175     hwnd = UGL_CONTROL(ugl_combo)->hWnd;
174     if ((orientation & flags) == 0 || (orientation & flags) == flags) return;   176     if ((orientation & flags) == 0 || (orientation & flags) == flags) return;
175     UGL_WIDGET(ugl_combo)->ugl_style &= ~flags;   177     UGL_WIDGET(ugl_combo)->ugl_style &= ~flags;
176     UGL_WIDGET(ugl_combo)->ugl_style |= orientation & flags;   178     UGL_WIDGET(ugl_combo)->ugl_style |= orientation & flags;
177       179    
178     bits = GetWindowLong(hwnd, GWL_EXSTYLE);   180     bits = GetWindowLong(hwnd, GWL_EXSTYLE);
179     if (IS_FLAG_SET(orientation, UGL_STYLE_RIGHT_TO_LEFT)) {   181     if (IS_FLAG_SET(orientation, UGL_STYLE_RIGHT_TO_LEFT)) {
180         //style |= SWT.MIRRORED;   182         //style |= SWT.MIRRORED;
181         bits |= WS_EX_LAYOUTRTL;   183         bits |= WS_EX_LAYOUTRTL;
182     } else {   184     } else {
183         //style &= ~SWT.MIRRORED;   185         //style &= ~SWT.MIRRORED;
184         bits &= ~WS_EX_LAYOUTRTL;   186         bits &= ~WS_EX_LAYOUTRTL;
185     }   187     }
186     188  
187     SetWindowLong(hwnd, GWL_EXSTYLE, bits);   189     SetWindowLong(hwnd, GWL_EXSTYLE, bits);
188     190  
189     hwndList = GetDlgItem(hwnd, CBID_LIST);   191     hwndList = GetDlgItem(hwnd, CBID_LIST);
190     hwndText = GetDlgItem(hwnd, CBID_EDIT);   192     hwndText = GetDlgItem(hwnd, CBID_EDIT);
191     193  
192     if (hwndText != NULL) {   194     if (hwndText != NULL) {
193         int bits_exstyle = GetWindowLong(hwndText, GWL_EXSTYLE);   195         int bits_exstyle = GetWindowLong(hwndText, GWL_EXSTYLE);
194         int bits_style = GetWindowLong(hwndText, GWL_STYLE);   196         int bits_style = GetWindowLong(hwndText, GWL_STYLE);
195         if (IS_FLAG_SET(orientation, UGL_STYLE_RIGHT_TO_LEFT)) {   197         if (IS_FLAG_SET(orientation, UGL_STYLE_RIGHT_TO_LEFT)) {
196             bits_exstyle |= WS_EX_RIGHT | WS_EX_RTLREADING;   198             bits_exstyle |= WS_EX_RIGHT | WS_EX_RTLREADING;
197             bits_style |= ES_RIGHT;   199             bits_style |= ES_RIGHT;
198         } else {   200         } else {
199             bits_exstyle &= ~(WS_EX_RIGHT | WS_EX_RTLREADING);   201             bits_exstyle &= ~(WS_EX_RIGHT | WS_EX_RTLREADING);
200             bits_style &= ~ES_RIGHT;   202             bits_style &= ~ES_RIGHT;
201         }   203         }
202         SetWindowLong(hwndText, GWL_EXSTYLE, bits_exstyle);   204         SetWindowLong(hwndText, GWL_EXSTYLE, bits_exstyle);
203         SetWindowLong(hwndText, GWL_STYLE, bits_style);   205         SetWindowLong(hwndText, GWL_STYLE, bits_style);
204           206        
205         /*   207         /*
206         * Bug in Windows.  For some reason, the single line text field   208         * Bug in Windows.  For some reason, the single line text field
207         * portion of the combo box does not redraw to reflect the new   209         * portion of the combo box does not redraw to reflect the new
208         * style bits.  The fix is to force the widget to be resized by   210         * style bits.  The fix is to force the widget to be resized by
209         * temporarily shrinking and then growing the width and height.   211         * temporarily shrinking and then growing the width and height.
210         */   212         */
211     213  
212         InvalidateRect(hwndText, NULL, TRUE);   214         InvalidateRect(hwndText, NULL, TRUE);
213         //RECT rect = new RECT ();   215         //RECT rect = new RECT ();
214         //OS.GetWindowRect (hwndText, rect);   216         //OS.GetWindowRect (hwndText, rect);
215         //int width = rect.right - rect.left, height = rect.bottom - rect.top;   217         //int width = rect.right - rect.left, height = rect.bottom - rect.top;
216         //OS.GetWindowRect (handle, rect);   218         //OS.GetWindowRect (handle, rect);
217         //int widthCombo = rect.right - rect.left, heightCombo = rect.bottom - rect.top;   219         //int widthCombo = rect.right - rect.left, heightCombo = rect.bottom - rect.top;
218         //int uFlags = OS.SWP_NOMOVE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE;   220         //int uFlags = OS.SWP_NOMOVE | OS.SWP_NOZORDER | OS.SWP_NOACTIVATE;
219         //SetWindowPos (hwndText, 0, 0, 0, width - 1, height - 1, uFlags);   221         //SetWindowPos (hwndText, 0, 0, 0, width - 1, height - 1, uFlags);
220         //SetWindowPos (handle, 0, 0, 0, widthCombo - 1, heightCombo - 1, uFlags);   222         //SetWindowPos (handle, 0, 0, 0, widthCombo - 1, heightCombo - 1, uFlags);
221         //SetWindowPos (hwndText, 0, 0, 0, width, height, uFlags);   223         //SetWindowPos (hwndText, 0, 0, 0, width, height, uFlags);
222         //SetWindowPos (handle, 0, 0, 0, widthCombo, heightCombo, uFlags);   224         //SetWindowPos (handle, 0, 0, 0, widthCombo, heightCombo, uFlags);
223         //OS.InvalidateRect (handle, null, true);   225         //OS.InvalidateRect (handle, null, true);
224     }     226     }  
225     if (hwndList != NULL) {   227     if (hwndList != NULL) {
226         int bits_exstyle = GetWindowLong(hwndList, GWL_EXSTYLE);          228         int bits_exstyle = GetWindowLong(hwndList, GWL_EXSTYLE);       
227         if (IS_FLAG_SET(orientation, UGL_STYLE_RIGHT_TO_LEFT)) {   229         if (IS_FLAG_SET(orientation, UGL_STYLE_RIGHT_TO_LEFT)) {
228             bits_exstyle |= WS_EX_LAYOUTRTL;   230             bits_exstyle |= WS_EX_LAYOUTRTL;
229         } else {   231         } else {
230             bits_exstyle &= ~WS_EX_LAYOUTRTL;   232             bits_exstyle &= ~WS_EX_LAYOUTRTL;
231         }   233         }
232         SetWindowLong(hwndList, GWL_EXSTYLE, bits_exstyle);   234         SetWindowLong(hwndList, GWL_EXSTYLE, bits_exstyle);
233     }   235     }
234 #endif // defined _WIN32_WCE   236 #endif // defined _WIN32_WCE
235 }   237 }
236 //========================================================================================   238 //========================================================================================
237     239  
238 void Combo_SetTextSelection(UGL_Int handle, UGL_Int start, UGL_Int end, UGL_Error uglError) {   240 void Combo_SetTextSelection(UGL_Int handle, UGL_Int start, UGL_Int end, UGL_Error uglError) {
239     PUGL_Combo ugl_combo = UGL_COMBO(handle);   241     PUGL_Combo ugl_combo = UGL_COMBO(handle);
240     242  
241     int bits = start | (end << 16);   243     int bits = start | (end << 16);
242     SendMessage(UGL_CONTROL(ugl_combo)->hWnd, CB_SETEDITSEL, 0, bits);   244     SendMessage(UGL_CONTROL(ugl_combo)->hWnd, CB_SETEDITSEL, 0, bits);
243 }   245 }
244 //========================================================================================   246 //========================================================================================
245     247  
246 UGL_Int Combo_New(UGL_Int parentHandle, UGL_Int ugl_style, UGL_Error uglError) {   248 UGL_Int Combo_New(UGL_Int parentHandle, UGL_Int ugl_style, UGL_Error uglError) {
247     return _Combo_New(parentHandle, ugl_style, uglError);   249     return _Combo_New(parentHandle, ugl_style, uglError);
248 }   250 }
249     251  
250 UGL_Int _Combo_New(UGL_Int parentHandle, UGL_Int ugl_style, UGL_Error uglError) {   252 UGL_Int _Combo_New(UGL_Int parentHandle, UGL_Int ugl_style, UGL_Error uglError) {
251     int style = _Combo_Style(ugl_style);   253     int style = _Combo_Style(ugl_style);
252     int extended_style = _Combo_ExStyle(ugl_style);   254     int extended_style = _Combo_ExStyle(ugl_style);
253     HWND textHWnd, listHWnd;   255     HWND textHWnd, listHWnd;
254     256  
255     PUGL_Control ugl_control = _Control_New(_T("COMBOBOX"), sizeof(UGL_Combo), _Combo_Proc,   257     PUGL_Control ugl_control = _Control_New(_T("COMBOBOX"), sizeof(UGL_Combo), _Combo_Proc,
256                         parentHandle, ugl_style, style, extended_style, uglError);   258                         parentHandle, ugl_style, style, extended_style, uglError);
257     259  
258 // TODO check return conditions!   260 // TODO check return conditions!
259     UGL_COMBO(ugl_control)->is_read_only = (IS_FLAG_SET(ugl_style, UGL_STYLE_READ_ONLY));   261     UGL_COMBO(ugl_control)->is_read_only = (IS_FLAG_SET(ugl_style, UGL_STYLE_READ_ONLY));
260     262  
261     UGL_WIDGET(ugl_control)->widget_dispose = _Dispose_Combo;   263     UGL_WIDGET(ugl_control)->widget_dispose = _Dispose_Combo;
262     ugl_control->sendKeyEvent = _Combo_SendKeyEvent;   264     ugl_control->sendKeyEvent = _Combo_SendKeyEvent;
263       265    
264     textHWnd = GetDlgItem(ugl_control->hWnd, CBID_EDIT);   266     textHWnd = GetDlgItem(ugl_control->hWnd, CBID_EDIT);
265     listHWnd = GetDlgItem(ugl_control->hWnd, CBID_LIST);   267     listHWnd = GetDlgItem(ugl_control->hWnd, CBID_LIST);
266     268  
267     if (textHWnd != NULL) {   269     if (textHWnd != NULL) {
268         SetWindowLong(textHWnd, GWL_USERDATA, (LONG)ugl_control);   270         SetWindowLong(textHWnd, GWL_USERDATA, (LONG)ugl_control);
269         UGL_COMBO(ugl_control)->textProc = (WNDPROC)GetWindowLong(textHWnd, GWL_WNDPROC);   271         UGL_COMBO(ugl_control)->textProc = (WNDPROC)GetWindowLong(textHWnd, GWL_WNDPROC);
270         SetWindowLong(textHWnd, GWL_WNDPROC, (LONG)(_Combo_Text_Proc));   272         SetWindowLong(textHWnd, GWL_WNDPROC, (LONG)(_Combo_Text_Proc));
271     }   273     }
272     274  
273     if (listHWnd != NULL) {   275     if (listHWnd != NULL) {
274         /*   276         /*
275          * listHWnd is almost always NULL   277          * listHWnd is almost always NULL
276          */   278          */
277         SetWindowLong(listHWnd, GWL_USERDATA, (LONG)ugl_control);   279         SetWindowLong(listHWnd, GWL_USERDATA, (LONG)ugl_control);
278         UGL_COMBO(ugl_control)->listProc = (WNDPROC)GetWindowLong(listHWnd, GWL_WNDPROC);   280         UGL_COMBO(ugl_control)->listProc = (WNDPROC)GetWindowLong(listHWnd, GWL_WNDPROC);
279     }   281     }
280     282  
281     /*   283     /*
282      * We default to 7 for PPro to mimic the JDK. SWT prefers 5, but it isn't spec'd.   284      * We default to 7 for PPro to mimic the JDK. SWT prefers 5, but it isn't spec'd.
283      */   285      */
284     UGL_COMBO(ugl_control)->visibleItems = 7;   286     UGL_COMBO(ugl_control)->visibleItems = 7;
285     287  
286     return (UGL_Int)ugl_control;   288     return (UGL_Int)ugl_control;
287 }   289 }
288 //========================================================================================   290 //========================================================================================
289     291  
290 void Combo_GetTextSelection(UGL_Int handle, UGL_Int* returnX, UGL_Int* returnY, UGL_Error uglError) {   292 void Combo_GetTextSelection(UGL_Int handle, UGL_Int* returnX, UGL_Int* returnY, UGL_Error uglError) {
291     PUGL_Control ugl_combo = (PUGL_Control)handle;   293     PUGL_Control ugl_combo = (PUGL_Control)handle;
292     294  
293     //if ((style & SWT.DROP_DOWN) != 0 && (style & SWT.READ_ONLY) != 0) {   295     //if ((style & SWT.DROP_DOWN) != 0 && (style & SWT.READ_ONLY) != 0) {
294     if (((PUGL_Combo)ugl_combo)->is_read_only) {   296     if (((PUGL_Combo)ugl_combo)->is_read_only) {
295         *returnX = 0;   297         *returnX = 0;
296         *returnY = GetWindowTextLength(ugl_combo->hWnd);   298         *returnY = GetWindowTextLength(ugl_combo->hWnd);
297     }   299     }
298     300  
299     SendMessage(ugl_combo->hWnd, CB_GETEDITSEL, (WPARAM)returnX, (LPARAM)returnY);   301     SendMessage(ugl_combo->hWnd, CB_GETEDITSEL, (WPARAM)returnX, (LPARAM)returnY);
300 }   302 }
301 //========================================================================================   303 //========================================================================================
302     304  
303 void Combo_SetItem(UGL_Int handle, UGL_String string, UGL_Int index, UGL_Error uglError) {   305 void Combo_SetItem(UGL_Int handle, UGL_String string, UGL_Int index, UGL_Error uglError) {
304     Choice_RemoveItem(handle, index, uglError);   306     Choice_RemoveItem(handle, index, uglError);
305     Choice_AddItem(handle, string, index, uglError);   307     Choice_AddItem(handle, string, index, uglError);
306 }   308 }
307 //========================================================================================   309 //========================================================================================
308     310  
309 UGL_Int Combo_GetVisibleItemCount(UGL_Int handle, UGL_Error uglError) {   311 UGL_Int Combo_GetVisibleItemCount(UGL_Int handle, UGL_Error uglError) {
310     PUGL_Combo ugl_control = UGL_COMBO(handle);   312     PUGL_Combo ugl_control = UGL_COMBO(handle);
311     return ugl_control->visibleItems;   313     return ugl_control->visibleItems;
312     314  
313 }   315 }
314 //========================================================================================   316 //========================================================================================
315     317  
316 void Combo_SetVisibleItemCount(UGL_Int handle, UGL_Int count, UGL_Error uglError) {   318 void Combo_SetVisibleItemCount(UGL_Int handle, UGL_Int count, UGL_Error uglError) {
317     PUGL_Combo ugl_combo = UGL_COMBO(handle);   319     PUGL_Combo ugl_combo = UGL_COMBO(handle);
318     PUGL_Control ugl_control = (PUGL_Control)ugl_combo;   320     PUGL_Control ugl_control = (PUGL_Control)ugl_combo;
319     int numItems = SendMessage(ugl_control->hWnd, CB_GETCOUNT, 0, 0);   321     int numItems = SendMessage(ugl_control->hWnd, CB_GETCOUNT, 0, 0);
320     if (count < 0) return; //error   322     if (count < 0) return; //error
321     ugl_combo->visibleItems = count; //don't care if it's greater than numItems and don't have to repaint   323     ugl_combo->visibleItems = count; //don't care if it's greater than numItems and don't have to repaint
322       324    
323 }   325 }
324 //========================================================================================   326 //========================================================================================
325     327  
326 UGL_Int _Combo_Style(UGL_Int ugl_style) {   328 UGL_Int _Combo_Style(UGL_Int ugl_style) {
327     int bits = _Control_Style(ugl_style);   329     int bits = _Control_Style(ugl_style);
328       330    
329     bits |= CBS_AUTOHSCROLL | CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP;   331     bits |= CBS_AUTOHSCROLL | CBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP;
330     332  
331     //if (IS_FLAG_SET(ugl_style, UGL_STYLE_SIMPLE)) return bits | CBS_SIMPLE;   333     //if (IS_FLAG_SET(ugl_style, UGL_STYLE_SIMPLE)) return bits | CBS_SIMPLE;
332     if (IS_FLAG_SET(ugl_style, UGL_STYLE_READ_ONLY)) return bits | CBS_DROPDOWNLIST;   334     if (IS_FLAG_SET(ugl_style, UGL_STYLE_READ_ONLY)) return bits | CBS_DROPDOWNLIST;
333     return bits | CBS_DROPDOWN;   335     return bits | CBS_DROPDOWN;
334 }   336 }
335 //========================================================================================   337 //========================================================================================
336     338  
337 UGL_Int _Combo_ExStyle(UGL_Int ugl_style) {   339 UGL_Int _Combo_ExStyle(UGL_Int ugl_style) {
338     int bits = 0;   340     int bits = 0;
339     return bits;   341     return bits;
340 }   342 }
341 //=======================================================================================   343 //=======================================================================================
342     344  
343 LRESULT CALLBACK _Combo_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {   345 LRESULT CALLBACK _Combo_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
344     PUGL_Combo ugl_combo = (PUGL_Combo)GetWindowLong(hwnd, GWL_USERDATA);   346     PUGL_Combo ugl_combo = (PUGL_Combo)GetWindowLong(hwnd, GWL_USERDATA);
345     comboHwnd = hwnd; +-    
346     switch (message) { = 347     switch (message) {
347         case WM_CTLCOLOREDIT:   348         case WM_CTLCOLOREDIT:
348         case WM_CTLCOLORLISTBOX: {   349         case WM_CTLCOLORLISTBOX: {
349             HWND color_widget_hWnd = (HWND)lParam;   350             HWND color_widget_hWnd = (HWND)lParam;
350             PUGL_Control color_widget = (PUGL_Control)GetWindowLong(color_widget_hWnd, GWL_USERDATA);   351             PUGL_Control color_widget = (PUGL_Control)GetWindowLong(color_widget_hWnd, GWL_USERDATA);
351             PUGL_Control parent_control = (PUGL_Control)GetWindowLong(hwnd, GWL_USERDATA);   352             PUGL_Control parent_control = (PUGL_Control)GetWindowLong(hwnd, GWL_USERDATA);
352             if (color_widget == NULL) {   353             if (color_widget == NULL) {
353                 return _Combo_CTLCOLOR(parent_control, (HDC)wParam, color_widget);   354                 return _Combo_CTLCOLOR(parent_control, (HDC)wParam, color_widget);
354             }   355             }
355         } break;   356         } break;
356         case UI_GET_MINIMUM_SIZE: {   357         case UI_GET_MINIMUM_SIZE: {
357             PUGL_Control ugl_control = (PUGL_Control)GetWindowLong(hwnd, GWL_USERDATA);   358             PUGL_Control ugl_control = (PUGL_Control)GetWindowLong(hwnd, GWL_USERDATA);
358             UGL_Int handle = (UGL_Int)ugl_control;   359             UGL_Int handle = (UGL_Int)ugl_control;
359             POINT* point = (POINT*)wParam;   360             POINT* point = (POINT*)wParam;
360             _Combo_GetMinimumSize(handle, point, (UGL_Error)lParam);   361             _Combo_GetMinimumSize(handle, point, (UGL_Error)lParam);
361             return 0;   362             return 0;
362         } break;   363         } break;
363         case UI_COMMAND_CHILD: {   364         case UI_COMMAND_CHILD: {
364             PUGL_Control ugl_control = (PUGL_Control)GetWindowLong(hwnd, GWL_USERDATA);   365             PUGL_Control ugl_control = (PUGL_Control)GetWindowLong(hwnd, GWL_USERDATA);
365             return _Combo_CommandChild(ugl_control, wParam, hwnd);   366             return _Combo_CommandChild(ugl_control, wParam, hwnd);
366         } break;   367         } break;
367         case UI_SET_BOUNDS: {   368         case UI_SET_BOUNDS: {
368             /*   369             /*
369              * What's going on here is that when we call SetWindowPos() on a Combo,   370              * What's going on here is that when we call SetWindowPos() on a Combo,
370              * Windows takes those bounds and constrains the whole Combo, including the   371              * Windows takes those bounds and constrains the whole Combo, including the
371              * drop-down list to them. So if we pass along the size that we want for the   372              * drop-down list to them. So if we pass along the size that we want for the
372              * 'minimized' Combo, then it will be useless because the drop-down list will   373              * 'minimized' Combo, then it will be useless because the drop-down list will
373              * never be visible because it will go outside of the bounds we're giving to   374              * never be visible because it will go outside of the bounds we're giving to
374              * Windows.   375              * Windows.
375              * The fix is to return the minimum size of an un-expanded Combo box in   376              * The fix is to return the minimum size of an un-expanded Combo box in
376              * _Combo_GetMinimumSize(), but to always override the height passed to   377              * _Combo_GetMinimumSize(), but to always override the height passed to
377              * SetBounds and set it to the size necessary to show the elements of the list.   378              * SetBounds and set it to the size necessary to show the elements of the list.
378              * This way, the list is expandable, but the layouts to think that the Combo   379              * This way, the list is expandable, but the layouts to think that the Combo
379              * is the size of the text plus the list.   380              * is the size of the text plus the list.
380              */   381              */
381             PUGL_Control ugl_control = (PUGL_Control)GetWindowLong(hwnd, GWL_USERDATA);   382             PUGL_Control ugl_control = (PUGL_Control)GetWindowLong(hwnd, GWL_USERDATA);
382             UGL_Int handle = (UGL_Int)ugl_control;   383             UGL_Int handle = (UGL_Int)ugl_control;
383             LPRECT bounds = (LPRECT)wParam;   384             LPRECT bounds = (LPRECT)wParam;
384             _Combo_SetBounds(ugl_control, bounds);   385             _Combo_SetBounds(ugl_control, bounds);
385     386  
386         } break; //we want to let this pass through to ultimately go through _Control_SetBounds   387         } break; //we want to let this pass through to ultimately go through _Control_SetBounds
387         case WM_KILLFOCUS: {   388         case WM_KILLFOCUS: {
388             /*   389             /*
389              * When _Control_ForceFocus() is called on a Combo, the native call to   390              * When _Control_ForceFocus() is called on a Combo, the native call to
390              * setFocus() sends a WM_SETFOCUS message to the combo, and it immediately   391              * setFocus() sends a WM_SETFOCUS message to the combo, and it immediately
391              * bounces the focus to the text component, which causes a WM_KILLFOCUS message   392              * bounces the focus to the text component, which causes a WM_KILLFOCUS message
392              * to be sent to the Combo and a WM_SETFOCUS to go to the text component.   393              * to be sent to the Combo and a WM_SETFOCUS to go to the text component.
393              * This results in three focus callbacks reported by the combo in java:   394              * This results in three focus callbacks reported by the combo in java:
394              * (focus in, focus out, focus in).   395              * (focus in, focus out, focus in).
395              * So here and in WM_SETFOCUS, we suppress the callbacks for the first two messages   396              * So here and in WM_SETFOCUS, we suppress the callbacks for the first two messages
396              * using the fact that the WPARAM parameter is the HWND of the window gaining or   397              * using the fact that the WPARAM parameter is the HWND of the window gaining or
397              * losing focus (gaining on a WM_KILLFOCUS, losing on a WM_SETFOCUS)   398              * losing focus (gaining on a WM_KILLFOCUS, losing on a WM_SETFOCUS)
398              */   399              */
399             PUGL_Control ugl_control = (PUGL_Control)GetWindowLong(hwnd, GWL_USERDATA);   400             PUGL_Control ugl_control = (PUGL_Control)GetWindowLong(hwnd, GWL_USERDATA);
400             HWND lastFocusWind = (HWND)wParam;   401             HWND lastFocusWind = (HWND)wParam;
401             PUGL_Control lastFocusControl = (PUGL_Control)GetWindowLong(lastFocusWind, GWL_USERDATA);   402             PUGL_Control lastFocusControl = (PUGL_Control)GetWindowLong(lastFocusWind, GWL_USERDATA);
402             UGL_Boolean ignoreFocusEvent = (ugl_control == lastFocusControl);   403             UGL_Boolean ignoreFocusEvent = (ugl_control == lastFocusControl);
403             if (ignoreFocusEvent) {   404             if (ignoreFocusEvent) {
404                 if (ugl_control->widgetProc != NULL) return CallWindowProc(ugl_control->widgetProc, hwnd, message, wParam, lParam);   405                 if (ugl_control->widgetProc != NULL) return CallWindowProc(ugl_control->widgetProc, hwnd, message, wParam, lParam);
405                 else return DefWindowProc(hwnd, message, wParam, lParam);   406                 else return DefWindowProc(hwnd, message, wParam, lParam);
406             }   407             }
407         } break;   408         } break;
408         case WM_SETFOCUS: {   409         case WM_SETFOCUS: {
409             PUGL_Control ugl_control = (PUGL_Control)ugl_combo;   410             PUGL_Control ugl_control = (PUGL_Control)ugl_combo;
410             HWND lastFocusWind = (HWND)wParam;   411             HWND lastFocusWind = (HWND)wParam;
411             int selection, count, style;   412             int selection, count, style;
412             PUGL_Control lastFocusControl = (PUGL_Control)GetWindowLong(lastFocusWind, GWL_USERDATA);   413             PUGL_Control lastFocusControl = (PUGL_Control)GetWindowLong(lastFocusWind, GWL_USERDATA);
413             UGL_Boolean ignoreFocusEvent = (ugl_control == lastFocusControl);   414             UGL_Boolean ignoreFocusEvent = (ugl_control == lastFocusControl);
414             if (ignoreFocusEvent) {   415             if (ignoreFocusEvent) {
415                 if (ugl_control->widgetProc != NULL) return CallWindowProc(ugl_control->widgetProc, hwnd, message, wParam, lParam);   416                 if (ugl_control->widgetProc != NULL) return CallWindowProc(ugl_control->widgetProc, hwnd, message, wParam, lParam);
416                 else return DefWindowProc(hwnd, message, wParam, lParam);   417                 else return DefWindowProc(hwnd, message, wParam, lParam);
417             }   418             }
418               419            
419             //Fot read-only combo, while combo is focused, to select the first item if it existes and nothing was selected before.   420             //Fot read-only combo, while combo is focused, to select the first item if it existes and nothing was selected before.
420             style = GetWindowLong(ugl_control->hWnd, GWL_STYLE);   421             style = GetWindowLong(ugl_control->hWnd, GWL_STYLE);
421             if (IS_FLAG_SET(style, CBS_DROPDOWNLIST)) {   422             if (IS_FLAG_SET(style, CBS_DROPDOWNLIST)) {
422                 count = SendMessage(ugl_control->hWnd, CB_GETCOUNT, 0, 0);   423                 count = SendMessage(ugl_control->hWnd, CB_GETCOUNT, 0, 0);
423                 if (count > 1) {   424                 if (count > 1) {
424                     selection = SendMessage(ugl_control->hWnd, CB_GETCURSEL, 0, 0);   425                     selection = SendMessage(ugl_control->hWnd, CB_GETCURSEL, 0, 0);
425                     if (selection < 0)   426                     if (selection < 0)
426                      SendMessage(ugl_control->hWnd, CB_SETCURSEL, 0, 0);   427                      SendMessage(ugl_control->hWnd, CB_SETCURSEL, 0, 0);
427                 }   428                 }
428             }   429             }
429     430  
430         } break;   431         } break;
431     432  
432     }   433     }
433     return _Control_Proc(hwnd, message, wParam, lParam);   434     return _Control_Proc(hwnd, message, wParam, lParam);
434 }   435 }
435     436  
436 //========================================================================================   437 //========================================================================================
437     438  
438 void _Combo_SetBounds(PUGL_Control ugl_control, LPRECT bounds){   439 void _Combo_SetBounds(PUGL_Control ugl_control, LPRECT bounds){
439     /*   440     /*
440      * The height should be the height of an item times the user-requested number of   441      * The height should be the height of an item times the user-requested number of
441      * visible items. If that number exceeds the actual number of items in Combo, we   442      * visible items. If that number exceeds the actual number of items in Combo, we
442      * still make the Combo this size and Windows fills up the difference with white space.   443      * still make the Combo this size and Windows fills up the difference with white space.
443      */   444      */
444     HWND hwnd = ugl_control->hWnd;   445     HWND hwnd = ugl_control->hWnd;
445     UGL_Int height = SendMessage(hwnd, CB_GETITEMHEIGHT, 1, 0);   446     UGL_Int height = SendMessage(hwnd, CB_GETITEMHEIGHT, 1, 0);
446     int visibleNum = ((PUGL_Combo)ugl_control)->visibleItems;   447     int visibleNum = ((PUGL_Combo)ugl_control)->visibleItems;
447     height = height * visibleNum;   448     height = height * visibleNum;
448     bounds->bottom = bounds->bottom + height + 2;   449     bounds->bottom = bounds->bottom + height + 2;
449 }   450 }
450     451  
451 UGL_Boolean _Combo_SendKeyEvent(PUGL_Control control, UGL_Int type, UGL_Char character, UGL_Int keycode, UGL_Int modifiers) {   452 UGL_Boolean _Combo_SendKeyEvent(PUGL_Control control, UGL_Int type, UGL_Char character, UGL_Int keycode, UGL_Int modifiers) {
452     return VerifyHelper_SendKeyEvent(control, GetDlgItem(control->hWnd, CBID_EDIT), type, character, keycode, modifiers);   453     return VerifyHelper_SendKeyEvent(control, GetDlgItem(control->hWnd, CBID_EDIT), type, character, keycode, modifiers);
453 }   454 }
454     455  
455 //========================================================================================   456 //========================================================================================
456 LRESULT CALLBACK _Combo_List_Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {   457 LRESULT CALLBACK _Combo_List_Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
457     /*   458     /*
458      * I don't think we ever get a handle on the List Proc, but if we did, we would point it here   459      * I don't think we ever get a handle on the List Proc, but if we did, we would point it here
459      */   460      */
460     PUGL_Combo ugl_combo = (PUGL_Combo)GetWindowLong(hWnd, GWL_USERDATA);   461     PUGL_Combo ugl_combo = (PUGL_Combo)GetWindowLong(hWnd, GWL_USERDATA);
461     if (ugl_combo != NULL) return ugl_combo->listProc(hWnd, message, wParam, lParam);   462     if (ugl_combo != NULL) return ugl_combo->listProc(hWnd, message, wParam, lParam);
462     return 0;   463     return 0;
463 }   464 }
464 //========================================================================================   465 //========================================================================================
465 LRESULT CALLBACK _Combo_Text_Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {   466 LRESULT CALLBACK _Combo_Text_Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
466     /*   467     /*
467      * This is set in _Combo_New()   468      * This is set in _Combo_New()
468      *   469      *
469      * Because Combos are complex widgets, some messages go to the HWND of the combo,   470      * Because Combos are complex widgets, some messages go to the HWND of the combo,
470      * and some go to the HWND of the text component of the combo.   471      * and some go to the HWND of the text component of the combo.
471      * This proc handles some of the messages that go to the text component.   472      * This proc handles some of the messages that go to the text component.
472      */   473      */
473     PUGL_Control ugl_control = (PUGL_Control)GetWindowLong(hWnd, GWL_USERDATA); //this is the parent (the Combo)   474     PUGL_Control ugl_control = (PUGL_Control)GetWindowLong(hWnd, GWL_USERDATA); //this is the parent (the Combo)
474     int result = 0;   475     int result = 0;
475     switch (message) {   476     switch (message) {
476         case WM_KEYDOWN: {   477         case WM_KEYDOWN: {
477             if(SendMessage(ugl_control->hWnd, CB_GETDROPPEDSTATE, 0, 0) && wParam == VK_RETURN) {   478             if(SendMessage(ugl_control->hWnd, CB_GETDROPPEDSTATE, 0, 0) && wParam == VK_RETURN) {
478                 return 0;   479                 return 0;
479             }   480             }
480             result = _Control_ProcessWmKeyDown(ugl_control->hWnd, wParam, lParam);   481             result = _Control_ProcessWmKeyDown(ugl_control->hWnd, wParam, lParam);
481             if(wParam == VK_DELETE) {   482             if(wParam == VK_DELETE) {
482                 _Combo_Text_ProcessWmChar(ugl_control, VK_DELETE);   483                 _Combo_Text_ProcessWmChar(ugl_control, VK_DELETE);
483                 return 0;   484                 return 0;
484             }   485             }
485         } break;   486         } break;
486     487  
487         case WM_KEYUP: {   488         case WM_KEYUP: {
488             if(SendMessage(ugl_control->hWnd, CB_GETDROPPEDSTATE, 0, 0) && wParam == VK_RETURN) {   489             if(SendMessage(ugl_control->hWnd, CB_GETDROPPEDSTATE, 0, 0) && wParam == VK_RETURN) {
489                 return 0;   490                 return 0;
490             }   491             }
491             result = _Control_ProcessWmKeyUp(ugl_control->hWnd, wParam, lParam);   492             result = _Control_ProcessWmKeyUp(ugl_control->hWnd, wParam, lParam);
492         } break;   493         } break;
493           494        
494         case WM_CHAR: {   495         case WM_CHAR: {
495             if(wParam != VK_RETURN) {   496             if(wParam != VK_RETURN) {
496                 result = _Control_ProcessWmChar(ugl_control->hWnd, wParam, lParam);   497                 result = _Control_ProcessWmChar(ugl_control->hWnd, wParam, lParam);
497             }   498             }
498             switch (wParam){   499             switch (wParam){
499                 case VK_TAB: {   500                 case VK_TAB: {
500                     return 0;   501                     return 0;
501                 } break;   502                 } break;
502                 case VK_RETURN: {   503                 case VK_RETURN: {
503                     if(SendMessage(ugl_control->hWnd, CB_GETDROPPEDSTATE, 0, 0)) {   504                     if(SendMessage(ugl_control->hWnd, CB_GETDROPPEDSTATE, 0, 0)) {
504                         _Combo_Text_ProcessWmChar(ugl_control, VK_RETURN);   505                         _Combo_Text_ProcessWmChar(ugl_control, VK_RETURN);
505                     } else {   506                     } else {
506                         MessageBeep(MB_OK);   507                         MessageBeep(MB_OK);
507                         result = _Control_ProcessWmChar(ugl_control->hWnd, wParam, lParam);   508                         result = _Control_ProcessWmChar(ugl_control->hWnd, wParam, lParam);
508                         ComboCallback(ugl_control->widget.callback_target, UGL_EVENT_COMBO_DEFAULTSELECTION);   509                         ComboCallback(ugl_control->widget.callback_target, UGL_EVENT_COMBO_DEFAULTSELECTION);
509                     }   510                     }
510                     return 0;   511                     return 0;
511                 } break;   512                 } break;
512                 case VK_ESCAPE: {   513                 case VK_ESCAPE: {
513                     int style = GetWindowLong(hWnd, GWL_STYLE);   514                     int style = GetWindowLong(hWnd, GWL_STYLE);
514                     SendMessage(ugl_control->hWnd, CB_SHOWDROPDOWN, FALSE, 0);   515                     SendMessage(ugl_control->hWnd, CB_SHOWDROPDOWN, FALSE, 0);
515                     if ((style & UGL_STYLE_DROP_DOWN) != 0) {   516                     if ((style & UGL_STYLE_DROP_DOWN) != 0) {
516                         if (SendMessage(hWnd, CB_GETDROPPEDSTATE, wParam, lParam) == 0){   517                         if (SendMessage(hWnd, CB_GETDROPPEDSTATE, wParam, lParam) == 0){
517                             return 0;   518                             return 0;
518                         };   519                         };
519                           520                        
520                     }   521                     }
521                 } break;   522                 } break;
522                 default : {   523                 default : {
523                     _Combo_Text_ProcessWmChar(ugl_control, wParam);   524                     _Combo_Text_ProcessWmChar(ugl_control, wParam);
524                     return 0;   525                     return 0;
525                 } break;   526                 } break;
526             }   527             }
527         } break;   528         } break;
528     529  
529         case WM_CLEAR:   530         case WM_CLEAR:
530         case WM_CUT: {   531         case WM_CUT: {
531             if (VerifyHelper_HandleCut(ugl_control, hWnd, ((PUGL_Combo)ugl_control)->textProc, message) == FALSE) return 0;   532             if (VerifyHelper_HandleCut(ugl_control, hWnd, ((PUGL_Combo)ugl_control)->textProc, message) == FALSE) return 0;
532             break;   533             break;
533         }   534         }
534     535  
535         case WM_PASTE: {   536         case WM_PASTE: {
536             if (VerifyHelper_HandlePaste(ugl_control, hWnd) == FALSE) return 0;   537             if (VerifyHelper_HandlePaste(ugl_control, hWnd) == FALSE) return 0;
537             break;   538             break;
538         }   539         }
539     540  
540         case WM_SETFOCUS: {   541         case WM_SETFOCUS: {
541             /*   542             /*
542              * When _Control_ForceFocus() is called on a Combo, the native call to   543              * When _Control_ForceFocus() is called on a Combo, the native call to
543              * setFocus() sends a WM_SETFOCUS message to the combo, and it immediately   544              * setFocus() sends a WM_SETFOCUS message to the combo, and it immediately
544              * bounces the focus to the text component, which causes a WM_KILLFOCUS message   545              * bounces the focus to the text component, which causes a WM_KILLFOCUS message
545              * to be sent to the Combo and a WM_SETFOCUS to go to the text component.   546              * to be sent to the Combo and a WM_SETFOCUS to go to the text component.
546              * This results in three focus callbacks reported by the combo in java:   547              * This results in three focus callbacks reported by the combo in java:
547              * (focus in, focus out, focus in).   548              * (focus in, focus out, focus in).
548              */   549              */
549             HWND lastFocusWind = (HWND)wParam;   550             HWND lastFocusWind = (HWND)wParam;
550             UGL_Boolean ignoreFocusEvent = (lastFocusWind == ugl_control->hWnd);   551             UGL_Boolean ignoreFocusEvent = (lastFocusWind == ugl_control->hWnd);
551     552  
552             _Combo_Text_RestoreText(ugl_control);   553             _Combo_Text_RestoreText(ugl_control);
553     554  
554             if (!ignoreFocusEvent) {   555             if (!ignoreFocusEvent) {
555                 FocusCallback(UGL_WIDGET(ugl_control)->callback_target, UGL_EVENT_FOCUS_IN);   556                 FocusCallback(UGL_WIDGET(ugl_control)->callback_target, UGL_EVENT_FOCUS_IN);
556                 //only send the event if the combo didn't already do it   557                 //only send the event if the combo didn't already do it
557             }   558             }
558         } break;   559         } break;
559     560  
560         case WM_KILLFOCUS: {   561         case WM_KILLFOCUS: {
561             HWND lastFocusWind = (HWND)wParam;   562             HWND lastFocusWind = (HWND)wParam;
562             UGL_Boolean ignoreFocusEvent = (lastFocusWind == ugl_control->hWnd);   563             UGL_Boolean ignoreFocusEvent = (lastFocusWind == ugl_control->hWnd);
563     564  
564             _Combo_Text_SaveText(ugl_control);   565             _Combo_Text_SaveText(ugl_control);
565     566  
566             if (!ignoreFocusEvent) {   567             if (!ignoreFocusEvent) {
567                 FocusCallback(UGL_WIDGET(ugl_control)->callback_target, UGL_EVENT_FOCUS_OUT);   568                 FocusCallback(UGL_WIDGET(ugl_control)->callback_target, UGL_EVENT_FOCUS_OUT);
568                 //only send the event if the combo didn't already do it   569                 //only send the event if the combo didn't already do it
569             }   570             }
570         } break;   571         } break;
571     }   572     }
572       573    
573     if (result != 0) return result;   574     if (result != 0) return result;
574     else return CallWindowProc(((PUGL_Combo)ugl_control)->textProc, hWnd, message, wParam, lParam);   575     else return CallWindowProc(((PUGL_Combo)ugl_control)->textProc, hWnd, message, wParam, lParam);
575 }   576 }
576 //========================================================================================   577 //========================================================================================
577     578  
578 LRESULT _Combo_CommandChild(PUGL_Control ugl_control, WPARAM wParam, HWND hWnd){   579 LRESULT _Combo_CommandChild(PUGL_Control ugl_control, WPARAM wParam, HWND hWnd){
579     UGL_Int handle = (UGL_Int)ugl_control;   580     UGL_Int handle = (UGL_Int)ugl_control;
580     PUGL_Combo ugl_combo = UGL_COMBO(handle);   581     PUGL_Combo ugl_combo = UGL_COMBO(handle);
581     LRESULT result = 1;   582     LRESULT result = 1;
582     HWND textHWnd = GetDlgItem(ugl_control->hWnd, CBID_EDIT);   583     HWND textHWnd = GetDlgItem(ugl_control->hWnd, CBID_EDIT);
583     HWND listHWnd = GetDlgItem(ugl_control->hWnd, CBID_LIST);   584     HWND listHWnd = GetDlgItem(ugl_control->hWnd, CBID_LIST);
584     int code = HIWORD(wParam);   585     int code = HIWORD(wParam);
585     int current_control = LOWORD(wParam);   586     int current_control = LOWORD(wParam);
586     /*   587     /*
587      * This is weird. For starters, we have a really quarky way of sizing Combos.   588      * This is weird. For starters, we have a really quarky way of sizing Combos.
588      * We have to return the size of an unexpanded Combo from _Combo_GetMinimumSize()   589      * We have to return the size of an unexpanded Combo from _Combo_GetMinimumSize()
589      * so that the Java layouts work correctly. But we have to return the size of an   590      * so that the Java layouts work correctly. But we have to return the size of an
590      * expanded Combo from _Control_GetBounds(), otherwise the OS won't give us enough room   591      * expanded Combo from _Control_GetBounds(), otherwise the OS won't give us enough room
591      * to show an expanded Combo. We do this by causing Control_SetBounds() to go through the   592      * to show an expanded Combo. We do this by causing Control_SetBounds() to go through the
592      * procs and override UI_SET_BOUNDS in _Combo_Proc to take the bounds set in _Combo_GetMinimumSize()   593      * procs and override UI_SET_BOUNDS in _Combo_Proc to take the bounds set in _Combo_GetMinimumSize()
593      * and increase the height to account for the expanded Combo.   594      * and increase the height to account for the expanded Combo.
594      * That brings us to the next few lines of code. They are necessary because of a Windows bug. It   595      * That brings us to the next few lines of code. They are necessary because of a Windows bug. It
595      * seems that no matter what we set the bounds of the window to be in UI_SET_BOUNDS, and eventually   596      * seems that no matter what we set the bounds of the window to be in UI_SET_BOUNDS, and eventually
596      * _Control_SetBounds(), Windows always resets the height according to some other constraint. But we   597      * _Control_SetBounds(), Windows always resets the height according to some other constraint. But we
597      * have to control this to satisfy the eSWT Get/SetVisibleItemCount() API. So the fix is to resize the   598      * have to control this to satisfy the eSWT Get/SetVisibleItemCount() API. So the fix is to resize the
598      * drop-down window after Windows ignores our request, which we do here, right after the user presses   599      * drop-down window after Windows ignores our request, which we do here, right after the user presses
599      * the drop-down button.   600      * the drop-down button.
600      */   601      */
601     int x, y, width, height = 0;   602     int x, y, width, height = 0;
602     RECT boundsRect;   603     RECT boundsRect;
603     UGL_Error error = NULL;   604     UGL_Error error = NULL;
604     Control_GetBounds((UGL_Int)ugl_control, &x, &y, &width, &height, error);   605     Control_GetBounds((UGL_Int)ugl_control, &x, &y, &width, &height, error);
605     boundsRect.left = x;   606     boundsRect.left = x;
606     boundsRect.right = x + width;   607     boundsRect.right = x + width;
607     boundsRect.top = y;   608     boundsRect.top = y;
608     boundsRect.bottom = y + height;   609     boundsRect.bottom = y + height;
609     SendMessage(ugl_control->hWnd, UI_SET_BOUNDS, (WPARAM)&boundsRect, (LPARAM)&error);   610     SendMessage(ugl_control->hWnd, UI_SET_BOUNDS, (WPARAM)&boundsRect, (LPARAM)&error);
610     611  
611     switch (code) {   612     switch (code) {
612         case CBN_SELCHANGE: {   613         case CBN_SELCHANGE: {
613             int current_item = SendMessage(hWnd, CB_GETCURSEL, 0, 0);   614             int current_item = SendMessage(hWnd, CB_GETCURSEL, 0, 0);
614               615            
615             if (current_item == 0) {   616             if (current_item == 0) {
616                 int count = SendMessage(hWnd, CB_GETCOUNT, 0, 0);   617                 int count = SendMessage(hWnd, CB_GETCOUNT, 0, 0);
617                 if (count == 0) current_item = -1;   618                 if (count == 0) current_item = -1;
618             }   619             }
619     620  
620             if (current_control != CBID_LIST) {   621             if (current_control != CBID_LIST) {
621                 /*   622                 /*
622                  * This is necessary because this message comes through twice per item   623                  * This is necessary because this message comes through twice per item
623                  * selection: once for the list and once for something else.   624                  * selection: once for the list and once for something else.
624                  * It doesn't seem that the second one is for the text, because   625                  * It doesn't seem that the second one is for the text, because
625                  * the value of current_control is 0, not CBID_TEXT (1001).   626                  * the value of current_control is 0, not CBID_TEXT (1001).
626                  * Regardless of why the second call comes through, we're only interested   627                  * Regardless of why the second call comes through, we're only interested
627                  * in the one for the list control.   628                  * in the one for the list control.
628                  * Also note that we don't change the result variable, which means that   629                  * Also note that we don't change the result variable, which means that
629                  * processing on this message will end here, but that's OK because the   630                  * processing on this message will end here, but that's OK because the
630                  * processing that occurs for the list control is sufficient.   631                  * processing that occurs for the list control is sufficient.
631                  */   632                  */
632                 break;   633                 break;
633             }   634             }
634     635  
635             ChoiceCallback(UGL_WIDGET(ugl_combo)->callback_target, current_item);   636             ChoiceCallback(UGL_WIDGET(ugl_combo)->callback_target, current_item);
636             //don't mess with result -- if we return 0 we skip important processings   637             //don't mess with result -- if we return 0 we skip important processings
637     638  
638         } break;   639         } break;
639     640  
640         case CBN_EDITCHANGE: {   641         case CBN_EDITCHANGE: {
641         } break;   642         } break;
642     643  
643         case CBN_SELENDOK: {   644         case CBN_SELENDOK: {
644             //This called whenever the user selects an item from the list   645             //This called whenever the user selects an item from the list
645             //(using the mouse or the keyboard)   646             //(using the mouse or the keyboard)
646             ComboCallback(UGL_WIDGET(ugl_combo)->callback_target, UGL_EVENT_COMBO_TEXT);      647             ComboCallback(UGL_WIDGET(ugl_combo)->callback_target, UGL_EVENT_COMBO_TEXT);   
647         } break;   648         } break;
648         case CBN_SETFOCUS: {   649         case CBN_SETFOCUS: {
649             _Combo_Text_RestoreText(ugl_control);   650             _Combo_Text_RestoreText(ugl_control);
650         } break;   651         } break;
651         case CBN_KILLFOCUS: {   652         case CBN_KILLFOCUS: {
652             _Combo_Text_RestoreText(ugl_control);   653             _Combo_Text_RestoreText(ugl_control);
653         } break;   654         } break;
654         case CBN_DROPDOWN: {   655         case CBN_DROPDOWN: {
655             _Combo_Text_RestoreText(ugl_control);   656             _Combo_Text_RestoreText(ugl_control);
656             return 0;   657             return 0;
657         } break;   658         } break;
658         case CBN_CLOSEUP: {   659         case CBN_CLOSEUP: {
659             _Combo_Text_RestoreText(ugl_control);   660             _Combo_Text_RestoreText(ugl_control);
660             return 0;   661             return 0;
661         } break;   662         } break;
662         case CBN_SELENDCANCEL: {   663         case CBN_SELENDCANCEL: {
663             if(!UGL_COMBO(ugl_control)->is_read_only &&   664             if(!UGL_COMBO(ugl_control)->is_read_only &&
664                 SendMessage(ugl_control->hWnd, CB_GETDROPPEDSTATE, 0, 0)) {   665                 SendMessage(ugl_control->hWnd, CB_GETDROPPEDSTATE, 0, 0)) {
665                 _Combo_Text_SaveText(ugl_control);   666                 _Combo_Text_SaveText(ugl_control);
666             }   667             }
667         } break;   668         } break;
668         default:{   669         default:{
669                   670                
670                 } break;   671                 } break;
671     }   672     }
672     return result;   673     return result;
673       674    
674 }   675 }
675     676  
676 //========================================================================================   677 //========================================================================================
677     678  
678 int _Combo_CTLCOLOR(PUGL_Control parent_control, HDC hdc, PUGL_Control color_control){   679 int _Combo_CTLCOLOR(PUGL_Control parent_control, HDC hdc, PUGL_Control color_control){
679     /*   680     /*
680      * This function gets called whenever a WM_CTLCOLOREDIT or WM_CTLCOLORLISTBOX messsage   681      * This function gets called whenever a WM_CTLCOLOREDIT or WM_CTLCOLORLISTBOX messsage
681      * comes through the ComboProc and doesn't map to a UGL_Control. It means that the   682      * comes through the ComboProc and doesn't map to a UGL_Control. It means that the
682      * current control is the child text or child list of a combo. That means that we need   683      * current control is the child text or child list of a combo. That means that we need
683      * to get the correct background and foreground color information from the parent, where   684      * to get the correct background and foreground color information from the parent, where
684      * it gets stored on a Control_SetBackground() or Control_SetForeGround() call.   685      * it gets stored on a Control_SetBackground() or Control_SetForeGround() call.
685      */   686      */
686       687    
687     COLORREF foreground;   688     COLORREF foreground;
688     COLORREF background;   689     COLORREF background;
689     HGDIOBJ background_brush;   690     HGDIOBJ background_brush;
690     691  
691     /*   692     /*
692         * We don't have any special logic to set the foreground   693         * We don't have any special logic to set the foreground
693         * because all the controls use COLOR_WINDOWTEXT.   694         * because all the controls use COLOR_WINDOWTEXT.
694         */   695         */
695     foreground = (parent_control->foreground_color != NULL) ? parent_control->foreground_color->color : GetSysColor(COLOR_WINDOWTEXT);   696     foreground = (parent_control->foreground_color != NULL) ? parent_control->foreground_color->color : GetSysColor(COLOR_WINDOWTEXT);
696     697  
697     if (parent_control->background_color != NULL) {   698     if (parent_control->background_color != NULL) {
698         background_brush = Color_GetBrush(parent_control->background_color);   699         background_brush = Color_GetBrush(parent_control->background_color);
699         background = parent_control->background_color->color;   700         background = parent_control->background_color->color;
700     } else {   701     } else {
701         background_brush = GetSysColorBrush(COLOR_WINDOW);   702         background_brush = GetSysColorBrush(COLOR_WINDOW);
702         background = GetSysColor(COLOR_WINDOW);   703         background = GetSysColor(COLOR_WINDOW);
703     704  
704     }   705     }
705     706  
706     SetTextColor(hdc, foreground);   707     SetTextColor(hdc, foreground);
707     SetBkColor(hdc, background);   708     SetBkColor(hdc, background);
708     return (int)background_brush;   709     return (int)background_brush;
709 }   710 }
710     711  
711 //========================================================================================   712 //========================================================================================
712     713  
713 void _Combo_GetMinimumSize(UGL_Int handle, POINT *point, UGL_Error uglError) {   714 void _Combo_GetMinimumSize(UGL_Int handle, POINT *point, UGL_Error uglError) {
714     /*   715     /*
715      * This is a rough mimic of how they do things in SWT.   716      * This is a rough mimic of how they do things in SWT.
716      * The logic goes something like this:   717      * The logic goes something like this:
717      * For width: find the longest item in the combo, draw that string   718      * For width: find the longest item in the combo, draw that string
718      * to an HDC using the current font, figure out the width of the rect   719      * to an HDC using the current font, figure out the width of the rect
719      * that surrounds the text you just drew, and add the width of the drop-   720      * that surrounds the text you just drew, and add the width of the drop-
720      * down button plus a little buffer just so things aren't cramped.   721      * down button plus a little buffer just so things aren't cramped.
721      * For height: find the height of the button on the combo, plus a little breathing room.   722      * For height: find the height of the button on the combo, plus a little breathing room.
722      * Don't worry about how many items are in the drop-down list. We take care of that in   723      * Don't worry about how many items are in the drop-down list. We take care of that in
723      * SetBounds(). If we return that size here, then the layouts will always   724      * SetBounds(). If we return that size here, then the layouts will always
724      * treat the Combo like its size is its expanded size.   725      * treat the Combo like its size is its expanded size.
725      * The exceptions are that we only show the first six items in the combo   726      * The exceptions are that we only show the first six items in the combo
726      * if there are more than 6, and we scale to the width of the second-   727      * if there are more than 6, and we scale to the width of the second-
727      * longest item in the combo if the longest item is 15 or more chars longer   728      * longest item in the combo if the longest item is 15 or more chars longer
728      * than the second-longest.   729      * than the second-longest.
729      *   730      *
730      * We probably need to do a bit of error handling on the OS calls.   731      * We probably need to do a bit of error handling on the OS calls.
731      * We use a default CBSize of 52, that is hard-coded in SWT. That may   732      * We use a default CBSize of 52, that is hard-coded in SWT. That may
732      * cause some problems sooner or later.   733      * cause some problems sooner or later.
733      */   734      */
734       735    
735     PUGL_Control ugl_control = UGL_CONTROL(handle);   736     PUGL_Control ugl_control = UGL_CONTROL(handle);
736     HWND hWnd = ugl_control->hWnd;   737     HWND hWnd = ugl_control->hWnd;
737     int width = 0;   738     int width = 0;
738     int height = 0;   739     int height = 0;
739     int num_items = SendMessage(hWnd, CB_GETCOUNT, 0, 0);   740     int num_items = SendMessage(hWnd, CB_GETCOUNT, 0, 0);
740     int max_length = 0;   741     int max_length = 0;
741     int current_length = 0;   742     int current_length = 0;
742     int second_longest = 0;   743     int second_longest = 0;
743     TEXTMETRIC tm;   744     TEXTMETRIC tm;
744     HDC hDC = GetDC(hWnd);   745     HDC hDC = GetDC(hWnd);
745     int working_vertical_count = 0;   746     int working_vertical_count = 0;
746     int i = 0;   747     int i = 0;
747     int max_viewable_items = 6;   748     int max_viewable_items = 6;
748     COMBOBOXINFO pcbi;   749     COMBOBOXINFO pcbi;
749     int presetCBSize = 52; //from SWT Default   750     int presetCBSize = 52; //from SWT Default
750     RECT text_size_rect;   751     RECT text_size_rect;
751     HGDIOBJ newFont = 0;   752     HGDIOBJ newFont = 0;
752     int flags = DT_CALCRECT | DT_NOPREFIX;   753     int flags = DT_CALCRECT | DT_NOPREFIX;
753     int first_index = 0;   754     int first_index = 0;
754     int second_index = 0;   755     int second_index = 0;
755     int widthBuffer = 10; //based on testing   756     int widthBuffer = 10; //based on testing
756     int heightBuffer = 3;   757     int heightBuffer = 3;
757     758  
758       759    
759     /*   760     /*
760      * Find and record the number of chars and indexes of the longest and second-   761      * Find and record the number of chars and indexes of the longest and second-
761      * longest strings in the combo   762      * longest strings in the combo
762      */   763      */
763     for (i = 0; i<num_items; i++){   764     for (i = 0; i<num_items; i++){
764         current_length = SendMessage(hWnd, CB_GETLBTEXTLEN, i, 0);   765         current_length = SendMessage(hWnd, CB_GETLBTEXTLEN, i, 0);
765         if (current_length > max_length) {   766         if (current_length > max_length) {
766             second_longest = max_length;   767             second_longest = max_length;
767             max_length = current_length;   768             max_length = current_length;
768             second_index = first_index;   769             second_index = first_index;
769             first_index = i;   770             first_index = i;
770         }   771         }
771     }   772     }
772     773  
773     /*   774     /*
774      * Now determine whether you want to use the longest or second-longest, and   775      * Now determine whether you want to use the longest or second-longest, and
775      * find the width in pixels, based on drawing that string to the screen in the   776      * find the width in pixels, based on drawing that string to the screen in the
776      * current font.   777      * current font.
777      * No need to bother with all the overhead if we know that the combo is empty.   778      * No need to bother with all the overhead if we know that the combo is empty.
778      */   779      */
779     if (num_items != 0) {   780     if (num_items != 0) {
780         UGL_String text;   781         UGL_String text;
781         int working_horizontal_count = 0;   782         int working_horizontal_count = 0;
782     783  
783         if (second_longest != 0 && (max_length - second_longest) > 15) {   784         if (second_longest != 0 && (max_length - second_longest) > 15) {
784             working_horizontal_count = second_longest;   785             working_horizontal_count = second_longest;
785             text = (UGL_String)calloc(sizeof(TCHAR), working_horizontal_count+1);   786             text = (UGL_String)calloc(sizeof(TCHAR), working_horizontal_count+1);
786             SendMessage(hWnd, CB_GETLBTEXT, second_index, (LPARAM)text);   787             SendMessage(hWnd, CB_GETLBTEXT, second_index, (LPARAM)text);
787             /*SendMessage(hWnd, CB_SETDROPPEDWIDTH, tm.tmAveCharWidth * max_length * 0.80, 0);*/   788             /*SendMessage(hWnd, CB_SETDROPPEDWIDTH, tm.tmAveCharWidth * max_length * 0.80, 0);*/
788         }   789         }
789         else {   790         else {
790             working_horizontal_count = max_length;   791             working_horizontal_count = max_length;
791             text = (UGL_String)calloc(sizeof(TCHAR), working_horizontal_count+1);   792             text = (UGL_String)calloc(sizeof(TCHAR), working_horizontal_count+1);
792             SendMessage(hWnd, CB_GETLBTEXT, first_index, (LPARAM)text);   793             SendMessage(hWnd, CB_GETLBTEXT, first_index, (LPARAM)text);
793         }   794         }
794     795  
795         newFont = (HGDIOBJ)SendMessage(hWnd, WM_GETFONT, 0, 0);   796         newFont = (HGDIOBJ)SendMessage(hWnd, WM_GETFONT, 0, 0);
796         SelectObject(hDC, newFont);   797         SelectObject(hDC, newFont);
797         DrawText(hDC, text, working_horizontal_count, (LPRECT)&text_size_rect, flags);   798         DrawText(hDC, text, working_horizontal_count, (LPRECT)&text_size_rect, flags);
798         width = text_size_rect.right - text_size_rect.left;   799         width = text_size_rect.right - text_size_rect.left;
799         width += widthBuffer; //Just so everything isn't really cramped   800         width += widthBuffer; //Just so everything isn't really cramped
800         free(text);   801         free(text);
801     }   802     }
802     else {   803     else {
803         /*   804         /*
804          * Since the combo is empty, make it the size of a six-character string   805          * Since the combo is empty, make it the size of a six-character string
805          * in the default font.   806          * in the default font.
806          */   807          */
807         GetTextMetrics(hDC, (LPTEXTMETRIC)&tm);   808         GetTextMetrics(hDC, (LPTEXTMETRIC)&tm);
808         width = tm.tmAveCharWidth * 6;   809         width = tm.tmAveCharWidth * 6;
809     }   810     }
810     811  
811     pcbi.cbSize = presetCBSize;   812     pcbi.cbSize = presetCBSize;
812     813  
813     /**   814     /**
814      * WinCE does not have the GetComboBoxInfo method so the message has to be   815      * WinCE does not have the GetComboBoxInfo method so the message has to be
815      * used directly instead.   816      * used directly instead.
816      */   817      */
817 #ifdef _WIN32_WCE   818 #ifdef _WIN32_WCE
818     if (SendMessage(hWnd, CB_GETCOMBOBOXINFO, (WPARAM)0, (LPARAM)&pcbi)) {   819     if (SendMessage(hWnd, CB_GETCOMBOBOXINFO, (WPARAM)0, (LPARAM)&pcbi)) {
819 #else   820 #else
820     if (GetComboBoxInfo(hWnd, &pcbi)) {   821     if (GetComboBoxInfo(hWnd, &pcbi)) {
821 #endif   822 #endif
822         width += pcbi.rcItem.left + (pcbi.rcButton.right - pcbi.rcButton.left);   823         width += pcbi.rcItem.left + (pcbi.rcButton.right - pcbi.rcButton.left);
823         height = pcbi.rcButton.bottom - pcbi.rcButton.top;   824         height = pcbi.rcButton.bottom - pcbi.rcButton.top;
824         height += heightBuffer;   825         height += heightBuffer;
825     }   826     }
826     else {   827     else {
827         /*   828         /*
828          * If the call fails, which it shouldn't, just return the default values   829          * If the call fails, which it shouldn't, just return the default values
829          * that _Control_GetMinimumSize returns.   830          * that _Control_GetMinimumSize returns.
830          */   831          */
831         width = 64;   832         width = 64;
832         height = 64;   833         height = 64;
833     }   834     }
834     835  
835     ReleaseDC (hWnd, hDC);   836     ReleaseDC (hWnd, hDC);
836     837  
837     point->x = width;   838     point->x = width;
838     point->y = height;   839     point->y = height;
839       840    
840 }   841 }
841     842  
842 //========================================================================================   843 //========================================================================================
843     844  
844 void _Dispose_Combo(UGL_Int handle, UGL_Error uglError){   845 void _Dispose_Combo(UGL_Int handle, UGL_Error uglError){
845     PUGL_Combo ugl_combo = UGL_COMBO(handle);   846     PUGL_Combo ugl_combo = UGL_COMBO(handle);
846     if(ugl_combo->text != NULL)   847     if(ugl_combo->text != NULL)
847         free(ugl_combo->text);   848         free(ugl_combo->text);
848     if(comboHwnd != NULL) +-    
849         free(comboHwnd);      
850     _Dispose_Scrollable(handle, uglError); = 849     _Dispose_Scrollable(handle, uglError);
851 }   850 }
852     851  
853 UGL_Boolean _Combo_Text_ProcessWmChar(PUGL_Control ugl_control, TCHAR ch) {   852 UGL_Boolean _Combo_Text_ProcessWmChar(PUGL_Control ugl_control, TCHAR ch) {
854     TCHAR *curStr=NULL, *newStr=NULL;   853     TCHAR *curStr=NULL, *newStr=NULL;
855     UGL_Boolean modify = FALSE;   854     UGL_Boolean modify = FALSE;
856     DWORD rs;   855     DWORD rs;
857     int start, end, len;   856     int start, end, len;
858     857  
859     rs = (DWORD)SendMessage(ugl_control->hWnd, CB_GETEDITSEL, 0, 0);   858     rs = (DWORD)SendMessage(ugl_control->hWnd, CB_GETEDITSEL, 0, 0);
860     start = LOWORD(rs);   859     start = LOWORD(rs);
861     end = HIWORD(rs);   860     end = HIWORD(rs);
862     861  
863     len = GetWindowTextLength(ugl_control->hWnd);   862     len = GetWindowTextLength(ugl_control->hWnd);
864     curStr = (TCHAR *)calloc(len + 1, sizeof(TCHAR));   863     curStr = (TCHAR *)calloc(len + 1, sizeof(TCHAR));
865     if(curStr == NULL)   864     if(curStr == NULL)
866         return FALSE;   865         return FALSE;
867     newStr = (TCHAR *)calloc(len + 2, sizeof(TCHAR));   866     newStr = (TCHAR *)calloc(len + 2, sizeof(TCHAR));
868     if(newStr == NULL) {   867     if(newStr == NULL) {
869         free(curStr);   868         free(curStr);
870         return FALSE;   869         return FALSE;
871     }   870     }
872     871  
873     GetWindowText(ugl_control->hWnd, (LPTSTR)curStr, len + 1);   872     GetWindowText(ugl_control->hWnd, (LPTSTR)curStr, len + 1);
874     switch(ch) {   873     switch(ch) {
875         case VK_RETURN: {   874         case VK_RETURN: {
876             SendMessage(ugl_control->hWnd, CB_SHOWDROPDOWN, FALSE, 0);   875             SendMessage(ugl_control->hWnd, CB_SHOWDROPDOWN, FALSE, 0);
877             SetWindowText(ugl_control->hWnd, (LPTSTR)curStr);   876             SetWindowText(ugl_control->hWnd, (LPTSTR)curStr);
878             SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(len, len));   877             SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(len, len));
879         } break;   878         } break;
880         case VK_DELETE : {   879         case VK_DELETE : {
881             if(len == start) {   880             if(len == start) {
882                 break;   881                 break;
883             }   882             }
884     883  
885             modify = TRUE;   884             modify = TRUE;
886             if(start == end) {   885             if(start == end) {
887                 _Combo_Text_CombineNewString(curStr, newStr, start, end+1, 0);   886                 _Combo_Text_CombineNewString(curStr, newStr, start, end+1, 0);
888             } else {   887             } else {
889                 _Combo_Text_CombineNewString(curStr, newStr, start, end, 0);   888                 _Combo_Text_CombineNewString(curStr, newStr, start, end, 0);
890             }   889             }
891             len = _tcslen(newStr);   890             len = _tcslen(newStr);
892             if(len == 0) {   891             if(len == 0) {
893                 SetWindowText(ugl_control->hWnd, (LPTSTR)newStr);   892                 SetWindowText(ugl_control->hWnd, (LPTSTR)newStr);
894                 break;   893                 break;
895             }   894             }
896     895  
897             SendMessage(ugl_control->hWnd, CB_SHOWDROPDOWN, TRUE, 0);   896             SendMessage(ugl_control->hWnd, CB_SHOWDROPDOWN, TRUE, 0);
898             _Combo_Text_FindAndSelectItem(ugl_control->hWnd, (LPCSTR)newStr);   897             _Combo_Text_FindAndSelectItem(ugl_control->hWnd, (LPCSTR)newStr);
899             SetWindowText(ugl_control->hWnd, (LPTSTR)newStr);   898             SetWindowText(ugl_control->hWnd, (LPTSTR)newStr);
900             SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(start, start));   899             SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(start, start));
901         } break;   900         } break;
902         case VK_BACK : {   901         case VK_BACK : {
903             if(end == 0) {   902             if(end == 0) {
904                 break;   903                 break;
905             }   904             }
906     905  
907             modify = TRUE;   906             modify = TRUE;
908             if(start == end) {   907             if(start == end) {
909                 _Combo_Text_CombineNewString(curStr, newStr, start-1, end, 0);   908                 _Combo_Text_CombineNewString(curStr, newStr, start-1, end, 0);
910             } else {   909             } else {
911                 _Combo_Text_CombineNewString(curStr, newStr, start, end, 0);   910                 _Combo_Text_CombineNewString(curStr, newStr, start, end, 0);
912             }   911             }
913             len = _tcslen(newStr);   912             len = _tcslen(newStr);
914             if(len == 0) {   913             if(len == 0) {
915                 SetWindowText(ugl_control->hWnd, (LPTSTR)newStr);   914                 SetWindowText(ugl_control->hWnd, (LPTSTR)newStr);
916                 break;   915                 break;
917             }   916             }
918     917  
919             SendMessage(ugl_control->hWnd, CB_SHOWDROPDOWN, TRUE, 0);   918             SendMessage(ugl_control->hWnd, CB_SHOWDROPDOWN, TRUE, 0);
920             _Combo_Text_FindAndSelectItem(ugl_control->hWnd, (LPCSTR)newStr);   919             _Combo_Text_FindAndSelectItem(ugl_control->hWnd, (LPCSTR)newStr);
921             SetWindowText(ugl_control->hWnd, (LPTSTR)newStr);   920             SetWindowText(ugl_control->hWnd, (LPTSTR)newStr);
922     921  
923             if(start == end) {   922             if(start == end) {
924                 SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(start-1, start-1));   923                 SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(start-1, start-1));
925             } else {   924             } else {
926                 SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(start, start));   925                 SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(start, start));
927             }   926             }
928         } break;   927         } break;
929         default : {   928         default : {
930             if(_istcntrl(ch)) {   929             if(_istcntrl(ch)) {
931                 break;   930                 break;
932             }   931             }
933     932  
934             modify = TRUE;   933             modify = TRUE;
935             SendMessage(ugl_control->hWnd, CB_SHOWDROPDOWN, TRUE, 0);   934             SendMessage(ugl_control->hWnd, CB_SHOWDROPDOWN, TRUE, 0);
936             _Combo_Text_CombineNewString(curStr, newStr, start, end, ch);   935             _Combo_Text_CombineNewString(curStr, newStr, start, end, ch);
937             SetWindowText(ugl_control->hWnd, (LPTSTR)newStr);   936             SetWindowText(ugl_control->hWnd, (LPTSTR)newStr);
938             if(_Combo_Text_FindAndSelectItem(ugl_control->hWnd, (LPCSTR)newStr)) {   937             if(_Combo_Text_FindAndSelectItem(ugl_control->hWnd, (LPCSTR)newStr)) {
939                 SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(start+1, -1));   938                 SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(start+1, -1));
940             } else {   939             } else {
941                 SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(start+1, start+1));   940                 SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(start+1, start+1));
942             }   941             }
943         } break;   942         } break;
944     }   943     }
945     944  
946     free(curStr);   945     free(curStr);
947     free(newStr);   946     free(newStr);
948     947  
949     if(modify) {   948     if(modify) {
950         ComboCallback(UGL_WIDGET(ugl_control)->callback_target, UGL_EVENT_COMBO_TEXT);   949         ComboCallback(UGL_WIDGET(ugl_control)->callback_target, UGL_EVENT_COMBO_TEXT);
951     }   950     }
952     951  
953     return modify;   952     return modify;
954 }   953 }
955     954  
956 void _Combo_Text_CombineNewString(TCHAR *curStr, TCHAR *newStr, int pos1, int pos2, TCHAR ch) {   955 void _Combo_Text_CombineNewString(TCHAR *curStr, TCHAR *newStr, int pos1, int pos2, TCHAR ch) {
957     int off = 0;   956     int off = 0;
958     int len = _tcslen(curStr);   957     int len = _tcslen(curStr);
959     958  
960     _tcsncpy(newStr, curStr, pos1);   959     _tcsncpy(newStr, curStr, pos1);
961     off = pos1;   960     off = pos1;
962     if(ch != 0) {   961     if(ch != 0) {
963         newStr[off++] = ch;   962         newStr[off++] = ch;
964     }   963     }
965     _tcsncpy(newStr+off, curStr+pos2, len-pos2);   964     _tcsncpy(newStr+off, curStr+pos2, len-pos2);
966     off += len-pos2;   965     off += len-pos2;
967     newStr[off] = 0;   966     newStr[off] = 0;
968 }   967 }
969     968  
970 UGL_Boolean _Combo_Text_FindAndSelectItem(HWND hwnd, LPCSTR str) {   969 UGL_Boolean _Combo_Text_FindAndSelectItem(HWND hwnd, LPCSTR str) {
971     return FALSE;   970     return FALSE;
972     /*   971     /*
973     int index;   972     int index;
974       973    
975     index = SendMessage(hwnd, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)str);   974     index = SendMessage(hwnd, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)str);
976     if(index == CB_ERR) {   975     if(index == CB_ERR) {
977         index = SendMessage(hwnd, CB_FINDSTRING, (WPARAM)-1, (LPARAM)str);   976         index = SendMessage(hwnd, CB_FINDSTRING, (WPARAM)-1, (LPARAM)str);
978     }   977     }
979     978  
980     if(index != CB_ERR) {   979     if(index != CB_ERR) {
981         SendMessage(hwnd, CB_SETCURSEL, (WPARAM)index, (LPARAM)0);   980         SendMessage(hwnd, CB_SETCURSEL, (WPARAM)index, (LPARAM)0);
982     }   981     }
983     982  
984     return (index != CB_ERR);   983     return (index != CB_ERR);
985 */   984 */
986 }   985 }
987     986  
988 void _Combo_Text_SaveText(PUGL_Control ugl_control) {   987 void _Combo_Text_SaveText(PUGL_Control ugl_control) {
989     DWORD rs;   988     DWORD rs;
990     int len;   989     int len;
991     if(UGL_COMBO(ugl_control)->is_read_only) {   990     if(UGL_COMBO(ugl_control)->is_read_only) {
992         return;   991         return;
993     }   992     }
994     993  
995     len = GetWindowTextLength(ugl_control->hWnd);   994     len = GetWindowTextLength(ugl_control->hWnd);
996     995  
997     if(UGL_COMBO(ugl_control)->text != NULL)   996     if(UGL_COMBO(ugl_control)->text != NULL)
998         free(UGL_COMBO(ugl_control)->text);   997         free(UGL_COMBO(ugl_control)->text);
999     998  
1000     UGL_COMBO(ugl_control)->text = (TCHAR *)calloc(len + 1, sizeof(TCHAR));   999     UGL_COMBO(ugl_control)->text = (TCHAR *)calloc(len + 1, sizeof(TCHAR));
1001     if(UGL_COMBO(ugl_control)->text == NULL) {   1000     if(UGL_COMBO(ugl_control)->text == NULL) {
1002         return;   1001         return;
1003     }   1002     }
1004     GetWindowText(ugl_control->hWnd, (LPTSTR)(UGL_COMBO(ugl_control)->text), len + 1);   1003     GetWindowText(ugl_control->hWnd, (LPTSTR)(UGL_COMBO(ugl_control)->text), len + 1);
1005     1004  
1006     rs = (DWORD)SendMessage(ugl_control->hWnd, CB_GETEDITSEL, 0, 0);   1005     rs = (DWORD)SendMessage(ugl_control->hWnd, CB_GETEDITSEL, 0, 0);
1007     UGL_COMBO(ugl_control)->selStart = LOWORD(rs);   1006     UGL_COMBO(ugl_control)->selStart = LOWORD(rs);
1008     UGL_COMBO(ugl_control)->selEnd = HIWORD(rs);   1007     UGL_COMBO(ugl_control)->selEnd = HIWORD(rs);
1009 }   1008 }
1010 void _Combo_Text_RestoreText(PUGL_Control ugl_control) {   1009 void _Combo_Text_RestoreText(PUGL_Control ugl_control) {
1011     if(UGL_COMBO(ugl_control)->is_read_only) {   1010     if(UGL_COMBO(ugl_control)->is_read_only) {
1012         return;   1011         return;
1013     }   1012     }
1014     1013  
1015     if(UGL_COMBO(ugl_control)->text != NULL) {   1014     if(UGL_COMBO(ugl_control)->text != NULL) {
1016         SetWindowText(ugl_control->hWnd, (LPTSTR)(UGL_COMBO(ugl_control)->text));   1015         SetWindowText(ugl_control->hWnd, (LPTSTR)(UGL_COMBO(ugl_control)->text));
1017     1016  
1018         #if !defined(WIN32_PLATFORM_WFSP)   1017         #if !defined(WIN32_PLATFORM_WFSP)
1019             SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(UGL_COMBO(ugl_control)->selStart, UGL_COMBO(ugl_control)->selEnd));   1018             SendMessage(ugl_control->hWnd, CB_SETEDITSEL, (WPARAM)0, (LPARAM)MAKELPARAM(UGL_COMBO(ugl_control)->selStart, UGL_COMBO(ugl_control)->selEnd));
1020         #endif   1019         #endif
1021     }   1020     }
1022 }   1021 }