]>
Commit | Line | Data |
---|---|---|
2bda0e17 KB |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Name: listbox.cpp | |
3 | // Purpose: wxListBox | |
4 | // Author: Julian Smart | |
5 | // Modified by: Vadim Zeitlin (owner drawn stuff) | |
6 | // Created: | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) Julian Smart | |
9 | // Licence: wxWindows license | |
10 | /////////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | #ifdef __GNUG__ | |
13 | #pragma implementation "listbox.h" | |
14 | #endif | |
15 | ||
16 | // For compilers that support precompilation, includes "wx.h". | |
17 | #include "wx/wxprec.h" | |
18 | ||
19 | #ifdef __BORLANDC__ | |
20 | #pragma hdrstop | |
21 | #endif | |
22 | ||
23 | #ifndef WX_PRECOMP | |
24 | #include "wx/listbox.h" | |
25 | #include "wx/settings.h" | |
2432b92d JS |
26 | #include "wx/brush.h" |
27 | #include "wx/font.h" | |
28 | #include "wx/dc.h" | |
2bda0e17 KB |
29 | #endif |
30 | ||
31 | #include "wx/msw/private.h" | |
32 | ||
33 | #include <windows.h> | |
34 | #include <windowsx.h> | |
35 | ||
36 | #ifdef __GNUWIN32__ | |
37 | #include <wx/msw/gnuwin32/extra.h> | |
38 | #endif | |
39 | ||
40 | #ifdef GetCharWidth | |
41 | #undef GetCharWidth | |
42 | #endif | |
43 | ||
47d67540 | 44 | #if wxUSE_OWNER_DRAWN |
2bda0e17 KB |
45 | #include "wx/ownerdrw.h" |
46 | #endif | |
47 | ||
14483330 VZ |
48 | #include "wx/dynarray.h" |
49 | #include "wx/log.h" | |
50 | ||
2bda0e17 KB |
51 | #if !USE_SHARED_LIBRARY |
52 | IMPLEMENT_DYNAMIC_CLASS(wxListBox, wxControl) | |
53 | #endif | |
54 | ||
55 | // ============================================================================ | |
56 | // list box item declaration and implementation | |
57 | // ============================================================================ | |
58 | ||
47d67540 | 59 | #if wxUSE_OWNER_DRAWN |
2bda0e17 KB |
60 | |
61 | class wxListBoxItem : public wxOwnerDrawn | |
62 | { | |
63 | public: | |
64 | wxListBoxItem(const wxString& str = ""); | |
65 | }; | |
66 | ||
67 | wxListBoxItem::wxListBoxItem(const wxString& str) : wxOwnerDrawn(str, FALSE) | |
68 | { | |
69 | // no bitmaps/checkmarks | |
70 | SetMarginWidth(0); | |
71 | } | |
72 | ||
c86f1403 | 73 | wxOwnerDrawn *wxListBox::CreateItem(size_t n) |
2bda0e17 KB |
74 | { |
75 | return new wxListBoxItem(); | |
76 | } | |
77 | ||
78 | #endif //USE_OWNER_DRAWN | |
79 | ||
80 | // ============================================================================ | |
81 | // list box control implementation | |
82 | // ============================================================================ | |
83 | ||
84 | // this macro is dangerous but still better than tons of (HWND)GetHWND() | |
85 | #define hwnd (HWND)GetHWND() | |
86 | ||
debe6624 | 87 | bool wxListBox::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) |
2bda0e17 KB |
88 | { |
89 | /* | |
90 | if (param == LBN_SELCANCEL) | |
91 | { | |
92 | event.extraLong = FALSE; | |
93 | } | |
94 | */ | |
95 | if (param == LBN_SELCHANGE) | |
96 | { | |
97 | wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, m_windowId); | |
14483330 VZ |
98 | wxArrayInt aSelections; |
99 | int count = GetSelections(aSelections); | |
100 | if ( count > 0 ) | |
2bda0e17 | 101 | { |
14483330 | 102 | event.m_commandInt = aSelections[0] ; |
2bda0e17 KB |
103 | event.m_clientData = GetClientData(event.m_commandInt); |
104 | wxString str(GetString(event.m_commandInt)); | |
105 | if (str != "") | |
106 | event.m_commandString = copystring((char *)(const char *)str); | |
107 | } | |
108 | else | |
109 | { | |
110 | event.m_commandInt = -1 ; | |
111 | event.m_commandString = copystring("") ; | |
112 | } | |
113 | ||
114 | event.SetEventObject( this ); | |
115 | ProcessCommand(event); | |
116 | if (event.m_commandString) | |
117 | delete[] event.m_commandString ; | |
118 | return TRUE; | |
119 | } | |
120 | else if (param == LBN_DBLCLK) | |
121 | { | |
122 | wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, m_windowId); | |
123 | event.SetEventObject( this ); | |
debe6624 JS |
124 | GetEventHandler()->ProcessEvent(event) ; |
125 | return TRUE; | |
126 | /* | |
2bda0e17 KB |
127 | { |
128 | #if WXWIN_COMPATIBILITY | |
129 | wxWindow *parent = (wxWindow *)GetParent(); | |
130 | if (parent) | |
131 | parent->GetEventHandler()->OnDefaultAction(this); | |
132 | #endif | |
133 | return TRUE; | |
134 | } | |
debe6624 | 135 | */ |
2bda0e17 KB |
136 | } |
137 | return FALSE; | |
138 | } | |
139 | ||
140 | // Listbox item | |
141 | wxListBox::wxListBox(void) | |
142 | { | |
143 | m_noItems = 0; | |
144 | m_selected = 0; | |
2bda0e17 KB |
145 | } |
146 | ||
debe6624 | 147 | bool wxListBox::Create(wxWindow *parent, wxWindowID id, |
2bda0e17 KB |
148 | const wxPoint& pos, |
149 | const wxSize& size, | |
debe6624 JS |
150 | int n, const wxString choices[], |
151 | long style, | |
2bda0e17 KB |
152 | const wxValidator& validator, |
153 | const wxString& name) | |
154 | { | |
e6460682 | 155 | m_noItems = 0; |
2bda0e17 KB |
156 | m_hWnd = 0; |
157 | m_selected = 0; | |
2bda0e17 KB |
158 | |
159 | SetName(name); | |
160 | SetValidator(validator); | |
161 | ||
162 | if (parent) parent->AddChild(this); | |
163 | ||
164 | wxSystemSettings settings; | |
165 | SetBackgroundColour(settings.GetSystemColour(wxSYS_COLOUR_WINDOW)); | |
fd71308f | 166 | SetForegroundColour(parent->GetForegroundColour()); |
2bda0e17 KB |
167 | |
168 | m_windowId = ( id == -1 ) ? (int)NewControlId() : id; | |
169 | ||
170 | int x = pos.x; | |
171 | int y = pos.y; | |
172 | int width = size.x; | |
173 | int height = size.y; | |
174 | m_windowStyle = style; | |
175 | ||
176 | DWORD wstyle = WS_VSCROLL | WS_TABSTOP | LBS_NOTIFY | LBS_HASSTRINGS; | |
177 | if (m_windowStyle & wxLB_MULTIPLE) | |
178 | wstyle |= LBS_MULTIPLESEL; | |
179 | else if (m_windowStyle & wxLB_EXTENDED) | |
180 | wstyle |= LBS_EXTENDEDSEL; | |
181 | ||
182 | if (m_windowStyle & wxLB_ALWAYS_SB) | |
183 | wstyle |= LBS_DISABLENOSCROLL ; | |
184 | if (m_windowStyle & wxLB_HSCROLL) | |
185 | wstyle |= WS_HSCROLL; | |
186 | if (m_windowStyle & wxLB_SORT) | |
187 | wstyle |= LBS_SORT; | |
188 | ||
47d67540 | 189 | #if wxUSE_OWNER_DRAWN |
2bda0e17 KB |
190 | if ( m_windowStyle & wxLB_OWNERDRAW ) { |
191 | // we don't support LBS_OWNERDRAWVARIABLE yet | |
192 | wstyle |= LBS_OWNERDRAWFIXED; | |
193 | } | |
2bda0e17 | 194 | #endif |
40e1a9c0 JS |
195 | // Without this style, you get unexpected heights, so e.g. constraint layout |
196 | // doesn't work properly | |
197 | wstyle |= LBS_NOINTEGRALHEIGHT; | |
2bda0e17 KB |
198 | |
199 | bool want3D; | |
200 | WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D) ; | |
201 | ||
202 | // Even with extended styles, need to combine with WS_BORDER | |
203 | // for them to look right. | |
c085e333 VZ |
204 | if ( want3D || wxStyleHasBorder(m_windowStyle) ) |
205 | { | |
2bda0e17 KB |
206 | wstyle |= WS_BORDER; |
207 | } | |
208 | ||
c085e333 | 209 | m_hWnd = (WXHWND)::CreateWindowEx(exStyle, "LISTBOX", NULL, |
2bda0e17 KB |
210 | wstyle | WS_CHILD, |
211 | 0, 0, 0, 0, | |
212 | (HWND)parent->GetHWND(), (HMENU)m_windowId, | |
213 | wxGetInstance(), NULL); | |
1c089c47 | 214 | |
c085e333 | 215 | wxCHECK_MSG( m_hWnd, FALSE, "Failed to create listbox" ); |
1c089c47 | 216 | |
2bda0e17 KB |
217 | #if CTL3D |
218 | if (want3D) | |
219 | { | |
c085e333 | 220 | Ctl3dSubclassCtl(hwnd); |
2bda0e17 KB |
221 | m_useCtl3D = TRUE; |
222 | } | |
223 | #endif | |
224 | ||
1c089c47 | 225 | // Subclass again to catch messages |
c085e333 | 226 | SubclassWin(m_hWnd); |
1c089c47 | 227 | |
c86f1403 VZ |
228 | size_t ui; |
229 | for (ui = 0; ui < (size_t)n; ui++) { | |
c085e333 | 230 | Append(choices[ui]); |
2bda0e17 KB |
231 | } |
232 | ||
e6460682 | 233 | /* Not needed -- done in Append |
47d67540 | 234 | #if wxUSE_OWNER_DRAWN |
2bda0e17 | 235 | if ( m_windowStyle & wxLB_OWNERDRAW ) { |
c86f1403 | 236 | for (ui = 0; ui < (size_t)n; ui++) { |
2bda0e17 KB |
237 | // create new item which will process WM_{DRAW|MEASURE}ITEM messages |
238 | wxOwnerDrawn *pNewItem = CreateItem(ui); | |
239 | pNewItem->SetName(choices[ui]); | |
240 | m_aItems.Add(pNewItem); | |
c085e333 | 241 | ListBox_SetItemData(hwnd, ui, pNewItem); |
2bda0e17 KB |
242 | } |
243 | } | |
1c089c47 | 244 | #endif |
e6460682 | 245 | */ |
2bda0e17 | 246 | |
c085e333 VZ |
247 | if ( (m_windowStyle & wxLB_MULTIPLE) == 0 ) |
248 | SendMessage(hwnd, LB_SETCURSEL, 0, 0); | |
2bda0e17 | 249 | |
c0ed460c | 250 | SetFont(parent->GetFont()); |
2bda0e17 KB |
251 | |
252 | SetSize(x, y, width, height); | |
253 | ||
c085e333 | 254 | Show(TRUE); |
1c089c47 | 255 | |
2bda0e17 KB |
256 | return TRUE; |
257 | } | |
258 | ||
259 | wxListBox::~wxListBox(void) | |
260 | { | |
47d67540 | 261 | #if wxUSE_OWNER_DRAWN |
c86f1403 | 262 | size_t uiCount = m_aItems.Count(); |
2bda0e17 KB |
263 | while ( uiCount-- != 0 ) { |
264 | delete m_aItems[uiCount]; | |
265 | } | |
1c089c47 | 266 | #endif |
2bda0e17 KB |
267 | } |
268 | ||
269 | void wxListBox::SetupColours(void) | |
270 | { | |
271 | SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW)); | |
fd71308f | 272 | SetForegroundColour(GetParent()->GetForegroundColour()); |
2bda0e17 KB |
273 | } |
274 | ||
debe6624 | 275 | void wxListBox::SetFirstItem(int N) |
2bda0e17 KB |
276 | { |
277 | SendMessage(hwnd,LB_SETTOPINDEX,(WPARAM)N,(LPARAM)0) ; | |
278 | } | |
279 | ||
280 | void wxListBox::SetFirstItem(const wxString& s) | |
281 | { | |
282 | int N = FindString(s) ; | |
283 | ||
284 | if (N>=0) | |
285 | SetFirstItem(N) ; | |
286 | } | |
287 | ||
debe6624 | 288 | void wxListBox::Delete(int N) |
2bda0e17 KB |
289 | { |
290 | SendMessage(hwnd, LB_DELETESTRING, N, 0); | |
291 | m_noItems --; | |
292 | SetHorizontalExtent(""); | |
293 | } | |
294 | ||
295 | void wxListBox::Append(const wxString& item) | |
296 | { | |
297 | int index = ListBox_AddString(hwnd, item); | |
298 | m_noItems ++; | |
299 | ||
47d67540 | 300 | #if wxUSE_OWNER_DRAWN |
2bda0e17 | 301 | if ( m_windowStyle & wxLB_OWNERDRAW ) { |
49884e3e | 302 | wxOwnerDrawn *pNewItem = CreateItem(index); // dummy argument |
2bda0e17 KB |
303 | pNewItem->SetName(item); |
304 | m_aItems.Add(pNewItem); | |
305 | ListBox_SetItemData(hwnd, index, pNewItem); | |
306 | } | |
1c089c47 | 307 | #endif |
2bda0e17 KB |
308 | |
309 | SetHorizontalExtent(item); | |
310 | } | |
311 | ||
312 | void wxListBox::Append(const wxString& item, char *Client_data) | |
313 | { | |
314 | int index = ListBox_AddString(hwnd, item); | |
315 | m_noItems ++; | |
316 | ||
47d67540 | 317 | #if wxUSE_OWNER_DRAWN |
2bda0e17 KB |
318 | if ( m_windowStyle & wxLB_OWNERDRAW ) { |
319 | // client data must be pointer to wxOwnerDrawn, otherwise we would crash | |
320 | // in OnMeasure/OnDraw. | |
321 | wxFAIL_MSG("Can't use client data with owner-drawn listboxes"); | |
322 | } | |
323 | else | |
1c089c47 | 324 | #endif |
2bda0e17 KB |
325 | ListBox_SetItemData(hwnd, index, Client_data); |
326 | ||
327 | SetHorizontalExtent(item); | |
328 | } | |
329 | ||
debe6624 | 330 | void wxListBox::Set(int n, const wxString *choices, char** clientData) |
2bda0e17 KB |
331 | { |
332 | ShowWindow(hwnd, SW_HIDE); | |
333 | ListBox_ResetContent(hwnd); | |
334 | int i; | |
335 | for (i = 0; i < n; i++) | |
336 | { | |
337 | ListBox_AddString(hwnd, choices[i]); | |
338 | if ( clientData ) | |
339 | ListBox_SetItemData(hwnd, i, clientData[i]); | |
340 | } | |
341 | m_noItems = n; | |
342 | ||
47d67540 | 343 | #if wxUSE_OWNER_DRAWN |
2bda0e17 KB |
344 | if ( m_windowStyle & wxLB_OWNERDRAW ) { |
345 | // first delete old items | |
c86f1403 | 346 | size_t ui = m_aItems.Count(); |
2bda0e17 KB |
347 | while ( ui-- != 0 ) { |
348 | delete m_aItems[ui]; | |
349 | } | |
350 | m_aItems.Empty(); | |
351 | ||
352 | // then create new ones | |
c86f1403 | 353 | for (ui = 0; ui < (size_t)n; ui++) { |
2bda0e17 KB |
354 | wxOwnerDrawn *pNewItem = CreateItem(ui); |
355 | pNewItem->SetName(choices[ui]); | |
356 | m_aItems.Add(pNewItem); | |
357 | ListBox_SetItemData(hwnd, ui, pNewItem); | |
358 | ||
359 | wxASSERT_MSG(clientData[ui] == NULL, | |
360 | "Can't use client data with owner-drawn listboxes"); | |
361 | } | |
362 | } | |
1c089c47 | 363 | #endif |
2bda0e17 KB |
364 | |
365 | SetHorizontalExtent(""); | |
366 | ShowWindow(hwnd, SW_SHOW); | |
367 | } | |
368 | ||
369 | int wxListBox::FindString(const wxString& s) const | |
370 | { | |
371 | int pos = ListBox_FindStringExact(hwnd, (WPARAM)-1, s); | |
372 | if (pos == LB_ERR) | |
373 | return -1; | |
374 | else | |
375 | return pos; | |
376 | } | |
377 | ||
378 | void wxListBox::Clear(void) | |
379 | { | |
380 | ListBox_ResetContent(hwnd); | |
381 | ||
382 | m_noItems = 0; | |
383 | ListBox_GetHorizontalExtent(hwnd); | |
384 | } | |
385 | ||
debe6624 | 386 | void wxListBox::SetSelection(int N, bool select) |
2bda0e17 KB |
387 | { |
388 | if ((m_windowStyle & wxLB_MULTIPLE) || (m_windowStyle & wxLB_EXTENDED)) | |
389 | SendMessage(hwnd, LB_SETSEL, select, N); | |
390 | else | |
391 | { | |
392 | int N1 = N; | |
393 | if (!select) | |
394 | N1 = -1; | |
395 | SendMessage(hwnd, LB_SETCURSEL, N1, 0); | |
396 | } | |
397 | } | |
398 | ||
debe6624 | 399 | bool wxListBox::Selected(int N) const |
2bda0e17 KB |
400 | { |
401 | return SendMessage(hwnd, LB_GETSEL, N, 0) == 0 ? FALSE : TRUE; | |
402 | } | |
403 | ||
debe6624 | 404 | void wxListBox::Deselect(int N) |
2bda0e17 KB |
405 | { |
406 | if ((m_windowStyle & wxLB_MULTIPLE) || (m_windowStyle & wxLB_EXTENDED)) | |
407 | SendMessage(hwnd, LB_SETSEL, FALSE, N); | |
408 | } | |
409 | ||
debe6624 | 410 | char *wxListBox::GetClientData(int N) const |
2bda0e17 KB |
411 | { |
412 | return (char *)SendMessage(hwnd, LB_GETITEMDATA, N, 0); | |
413 | } | |
414 | ||
debe6624 | 415 | void wxListBox::SetClientData(int N, char *Client_data) |
2bda0e17 | 416 | { |
14483330 VZ |
417 | if ( ListBox_SetItemData(hwnd, N, Client_data) == LB_ERR ) |
418 | wxLogDebug("LB_SETITEMDATA failed"); | |
2bda0e17 KB |
419 | } |
420 | ||
421 | // Return number of selections and an array of selected integers | |
14483330 | 422 | int wxListBox::GetSelections(wxArrayInt& aSelections) const |
2bda0e17 | 423 | { |
14483330 VZ |
424 | aSelections.Empty(); |
425 | ||
2bda0e17 KB |
426 | if ((m_windowStyle & wxLB_MULTIPLE) || (m_windowStyle & wxLB_EXTENDED)) |
427 | { | |
14483330 VZ |
428 | int no_sel = ListBox_GetSelCount(hwnd); |
429 | if (no_sel != 0) { | |
430 | int *selections = new int[no_sel]; | |
431 | if ( ListBox_GetSelItems(hwnd, no_sel, selections) == LB_ERR ) { | |
432 | wxFAIL_MSG("This listbox can't have single-selection style!"); | |
433 | } | |
434 | ||
435 | aSelections.Alloc(no_sel); | |
436 | for ( int n = 0; n < no_sel; n++ ) | |
437 | aSelections.Add(selections[n]); | |
438 | ||
439 | delete [] selections; | |
440 | } | |
441 | ||
2bda0e17 KB |
442 | return no_sel; |
443 | } | |
14483330 | 444 | else // single-selection listbox |
2bda0e17 | 445 | { |
14483330 VZ |
446 | aSelections.Add(ListBox_GetCurSel(hwnd)); |
447 | ||
2bda0e17 KB |
448 | return 1; |
449 | } | |
450 | } | |
451 | ||
452 | // Get single selection, for single choice list items | |
14483330 | 453 | int wxListBox::GetSelection() const |
2bda0e17 | 454 | { |
14483330 VZ |
455 | wxCHECK_MSG( !(m_windowStyle & wxLB_MULTIPLE) && |
456 | !(m_windowStyle & wxLB_EXTENDED), | |
457 | -1, | |
458 | "GetSelection() can't be used with multiple-selection " | |
459 | "listboxes, use GetSelections() instead." ); | |
460 | ||
461 | return ListBox_GetCurSel(hwnd); | |
2bda0e17 KB |
462 | } |
463 | ||
464 | // Find string for position | |
debe6624 | 465 | wxString wxListBox::GetString(int N) const |
2bda0e17 KB |
466 | { |
467 | if (N < 0 || N > m_noItems) | |
468 | return wxString(""); | |
469 | ||
470 | int len = (int)SendMessage(hwnd, LB_GETTEXT, N, (LONG)wxBuffer); | |
471 | wxBuffer[len] = 0; | |
472 | return wxString(wxBuffer); | |
473 | } | |
474 | ||
debe6624 | 475 | void wxListBox::SetSize(int x, int y, int width, int height, int sizeFlags) |
2bda0e17 KB |
476 | { |
477 | int currentX, currentY; | |
478 | GetPosition(¤tX, ¤tY); | |
479 | ||
480 | int x1 = x; | |
481 | int y1 = y; | |
482 | int w1 = width; | |
483 | int h1 = height; | |
484 | ||
485 | if (x == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) | |
486 | x1 = currentX; | |
487 | if (y == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) | |
488 | y1 = currentY; | |
489 | ||
81d66cf3 JS |
490 | AdjustForParentClientOrigin(x1, y1, sizeFlags); |
491 | ||
2bda0e17 KB |
492 | // If we're prepared to use the existing size, then... |
493 | if (width == -1 && height == -1 && ((sizeFlags & wxSIZE_AUTO) != wxSIZE_AUTO)) | |
494 | { | |
495 | GetSize(&w1, &h1); | |
496 | } | |
497 | ||
498 | int cx; // button font dimensions | |
499 | int cy; | |
500 | ||
c0ed460c | 501 | wxGetCharSize(GetHWND(), &cx, &cy, & GetFont()); |
2bda0e17 KB |
502 | |
503 | float control_width, control_height, control_x, control_y; | |
504 | ||
505 | // Deal with default size (using -1 values) | |
506 | if (w1<=0) | |
507 | w1 = DEFAULT_ITEM_WIDTH; | |
508 | ||
509 | if (h1<=0) | |
510 | h1 = DEFAULT_ITEM_HEIGHT; | |
511 | ||
512 | control_x = (float)x1; | |
513 | control_y = (float)y1; | |
514 | control_width = (float)w1; | |
515 | control_height = (float)h1; | |
516 | ||
517 | // Calculations may have made size too small | |
518 | if (control_height <= 0) | |
519 | control_height = (float)DEFAULT_ITEM_HEIGHT; | |
520 | ||
521 | if (control_width <= 0) | |
522 | control_width = (float)DEFAULT_ITEM_WIDTH; | |
523 | ||
524 | // wxDebugMsg("About to set the listbox height to %d", (int)control_height); | |
525 | MoveWindow(hwnd, (int)control_x, (int)control_y, | |
526 | (int)control_width, (int)control_height, TRUE); | |
527 | ||
2bda0e17 KB |
528 | } |
529 | ||
530 | // Windows-specific code to set the horizontal extent of | |
531 | // the listbox, if necessary. If s is non-NULL, it's | |
532 | // used to calculate the horizontal extent. | |
533 | // Otherwise, all strings are used. | |
534 | void wxListBox::SetHorizontalExtent(const wxString& s) | |
535 | { | |
536 | // Only necessary if we want a horizontal scrollbar | |
537 | if (!(m_windowStyle & wxHSCROLL)) | |
538 | return; | |
539 | TEXTMETRIC lpTextMetric; | |
540 | ||
541 | if (s != "") | |
542 | { | |
543 | int existingExtent = (int)SendMessage(hwnd, LB_GETHORIZONTALEXTENT, 0, 0L); | |
544 | HDC dc = GetWindowDC(hwnd); | |
545 | HFONT oldFont = 0; | |
c0ed460c JS |
546 | if (GetFont().Ok() && GetFont().GetResourceHandle()) |
547 | oldFont = (HFONT) ::SelectObject(dc, (HFONT) GetFont().GetResourceHandle()); | |
2bda0e17 KB |
548 | |
549 | GetTextMetrics(dc, &lpTextMetric); | |
550 | SIZE extentXY; | |
551 | ::GetTextExtentPoint(dc, (LPSTR) (const char *)s, s.Length(), &extentXY); | |
552 | int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth); | |
553 | ||
554 | if (oldFont) | |
555 | ::SelectObject(dc, oldFont); | |
556 | ||
557 | ReleaseDC(hwnd, dc); | |
558 | if (extentX > existingExtent) | |
559 | SendMessage(hwnd, LB_SETHORIZONTALEXTENT, LOWORD(extentX), 0L); | |
560 | return; | |
561 | } | |
562 | else | |
563 | { | |
564 | int largestExtent = 0; | |
565 | HDC dc = GetWindowDC(hwnd); | |
566 | HFONT oldFont = 0; | |
c0ed460c JS |
567 | if (GetFont().Ok() && GetFont().GetResourceHandle()) |
568 | oldFont = (HFONT) ::SelectObject(dc, (HFONT) GetFont().GetResourceHandle()); | |
2bda0e17 KB |
569 | |
570 | GetTextMetrics(dc, &lpTextMetric); | |
571 | int i; | |
572 | for (i = 0; i < m_noItems; i++) | |
573 | { | |
574 | int len = (int)SendMessage(hwnd, LB_GETTEXT, i, (LONG)wxBuffer); | |
575 | wxBuffer[len] = 0; | |
576 | SIZE extentXY; | |
577 | ::GetTextExtentPoint(dc, (LPSTR)wxBuffer, len, &extentXY); | |
578 | int extentX = (int)(extentXY.cx + lpTextMetric.tmAveCharWidth); | |
579 | if (extentX > largestExtent) | |
580 | largestExtent = extentX; | |
581 | } | |
582 | if (oldFont) | |
583 | ::SelectObject(dc, oldFont); | |
584 | ||
585 | ReleaseDC(hwnd, dc); | |
586 | SendMessage(hwnd, LB_SETHORIZONTALEXTENT, LOWORD(largestExtent), 0L); | |
587 | } | |
588 | } | |
589 | ||
590 | void | |
debe6624 | 591 | wxListBox::InsertItems(int nItems, const wxString items[], int pos) |
2bda0e17 KB |
592 | { |
593 | int i; | |
594 | for (i = 0; i < nItems; i++) | |
595 | ListBox_InsertString(hwnd, i + pos, items[i]); | |
596 | m_noItems += nItems; | |
597 | ||
47d67540 | 598 | #if wxUSE_OWNER_DRAWN |
2bda0e17 KB |
599 | if ( m_windowStyle & wxLB_OWNERDRAW ) { |
600 | for ( i = 0; i < nItems; i++ ) { | |
c86f1403 | 601 | wxOwnerDrawn *pNewItem = CreateItem((size_t)(pos + i)); |
2bda0e17 | 602 | pNewItem->SetName(items[i]); |
c86f1403 | 603 | m_aItems.Insert(pNewItem, (size_t)(pos + i)); |
2bda0e17 KB |
604 | ListBox_SetItemData(hwnd, i, pNewItem); |
605 | } | |
606 | } | |
607 | #endif | |
608 | ||
609 | SetHorizontalExtent(""); | |
610 | } | |
611 | ||
debe6624 | 612 | void wxListBox::SetString(int N, const wxString& s) |
2bda0e17 | 613 | { |
400735a8 JS |
614 | int sel = -1; |
615 | if (!(m_windowStyle & wxLB_MULTIPLE) && !(m_windowStyle & wxLB_EXTENDED)) | |
616 | sel = GetSelection(); | |
2bda0e17 KB |
617 | |
618 | char *oldData = (char *)wxListBox::GetClientData(N); | |
619 | ||
620 | SendMessage(hwnd, LB_DELETESTRING, N, 0); | |
621 | ||
622 | int newN = N; | |
623 | if (N == (m_noItems - 1)) | |
624 | newN = -1; | |
625 | ||
626 | SendMessage(hwnd, LB_INSERTSTRING, newN, (LPARAM) (const char *)s); | |
627 | if (oldData) | |
628 | wxListBox::SetClientData(N, oldData); | |
629 | ||
630 | // Selection may have changed | |
631 | if (sel >= 0) | |
632 | SetSelection(sel); | |
633 | ||
47d67540 | 634 | #if wxUSE_OWNER_DRAWN |
e1d1da03 JS |
635 | if ( m_windowStyle & wxLB_OWNERDRAW ) |
636 | // update item's text | |
637 | m_aItems[N]->SetName(s); | |
638 | #endif //USE_OWNER_DRAWN | |
2bda0e17 KB |
639 | } |
640 | ||
641 | int wxListBox::Number (void) const | |
642 | { | |
643 | return m_noItems; | |
644 | } | |
645 | ||
646 | // For single selection items only | |
647 | wxString wxListBox::GetStringSelection (void) const | |
648 | { | |
649 | int sel = GetSelection (); | |
650 | if (sel > -1) | |
651 | return this->GetString (sel); | |
652 | else | |
653 | return wxString(""); | |
654 | } | |
655 | ||
debe6624 | 656 | bool wxListBox::SetStringSelection (const wxString& s, bool flag) |
2bda0e17 KB |
657 | { |
658 | int sel = FindString (s); | |
659 | if (sel > -1) | |
660 | { | |
661 | SetSelection (sel, flag); | |
662 | return TRUE; | |
663 | } | |
664 | else | |
665 | return FALSE; | |
666 | } | |
667 | ||
668 | // Is this the right thing? Won't setselection generate a command | |
669 | // event too? No! It'll just generate a setselection event. | |
670 | // But we still can't have this being called whenever a real command | |
671 | // is generated, because it sets the selection, which will already | |
672 | // have been done! (Unless we have an optional argument for calling | |
673 | // by the actual window system, or a separate function, ProcessCommand) | |
674 | void wxListBox::Command (wxCommandEvent & event) | |
675 | { | |
676 | if (event.m_extraLong) | |
677 | SetSelection (event.m_commandInt); | |
678 | else | |
679 | { | |
680 | Deselect (event.m_commandInt); | |
681 | return; | |
682 | } | |
683 | ProcessCommand (event); | |
684 | } | |
685 | ||
debe6624 | 686 | WXHBRUSH wxListBox::OnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor, |
2bda0e17 KB |
687 | WXUINT message, WXWPARAM wParam, WXLPARAM lParam) |
688 | { | |
689 | #if CTL3D | |
690 | if ( m_useCtl3D ) | |
691 | { | |
692 | HBRUSH hbrush = Ctl3dCtlColorEx(message, wParam, lParam); | |
693 | return (WXHBRUSH) hbrush; | |
694 | } | |
695 | #endif | |
696 | ||
697 | if (GetParent()->GetTransparentBackground()) | |
698 | SetBkMode((HDC) pDC, TRANSPARENT); | |
699 | else | |
700 | SetBkMode((HDC) pDC, OPAQUE); | |
701 | ||
702 | ::SetBkColor((HDC) pDC, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue())); | |
703 | ::SetTextColor((HDC) pDC, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue())); | |
704 | ||
705 | wxBrush *backgroundBrush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID); | |
706 | ||
707 | // Note that this will be cleaned up in wxApp::OnIdle, if backgroundBrush | |
708 | // has a zero usage count. | |
709 | backgroundBrush->RealizeResource(); | |
710 | return (WXHBRUSH) backgroundBrush->GetResourceHandle(); | |
711 | } | |
712 | ||
713 | long wxListBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) | |
714 | { | |
dabeb021 | 715 | #if 0 |
2bda0e17 KB |
716 | switch (nMsg) |
717 | { | |
718 | case WM_INITDIALOG: | |
719 | case WM_ACTIVATE: | |
720 | case WM_SETFOCUS: | |
721 | case WM_KILLFOCUS: | |
722 | case WM_CREATE: | |
723 | case WM_PAINT: | |
724 | case WM_QUERYDRAGICON: | |
725 | case WM_SIZE: | |
726 | case WM_RBUTTONDOWN: | |
727 | case WM_RBUTTONUP: | |
728 | case WM_RBUTTONDBLCLK: | |
729 | case WM_MBUTTONDOWN: | |
730 | case WM_MBUTTONUP: | |
731 | case WM_MBUTTONDBLCLK: | |
732 | case WM_LBUTTONDOWN: | |
733 | case WM_LBUTTONUP: | |
1c089c47 | 734 | case WM_LBUTTONDBLCLK: |
2bda0e17 | 735 | case WM_MOUSEMOVE: |
2bda0e17 KB |
736 | case WM_COMMAND: |
737 | case WM_NOTIFY: | |
debe6624 | 738 | case WM_DESTROY: |
2bda0e17 KB |
739 | case WM_MENUSELECT: |
740 | case WM_INITMENUPOPUP: | |
741 | case WM_DRAWITEM: | |
742 | case WM_MEASUREITEM: | |
743 | case WM_KEYDOWN: | |
744 | case WM_KEYUP: | |
745 | case WM_CHAR: // Always an ASCII character | |
746 | case WM_HSCROLL: | |
747 | case WM_VSCROLL: | |
748 | case WM_CTLCOLORBTN: | |
749 | case WM_CTLCOLORDLG: | |
750 | case WM_CTLCOLORLISTBOX: | |
751 | case WM_CTLCOLORMSGBOX: | |
752 | case WM_CTLCOLORSCROLLBAR: | |
753 | case WM_CTLCOLORSTATIC: | |
754 | case WM_CTLCOLOREDIT: | |
755 | case WM_SYSCOLORCHANGE: | |
756 | case WM_ERASEBKGND: | |
757 | case WM_MDIACTIVATE: | |
758 | case WM_DROPFILES: | |
759 | case WM_QUERYENDSESSION: | |
760 | case WM_CLOSE: | |
761 | case WM_GETMINMAXINFO: | |
762 | case WM_NCHITTEST: | |
763 | return MSWDefWindowProc(nMsg, wParam, lParam ); | |
764 | } | |
dabeb021 | 765 | #endif |
debe6624 | 766 | |
2bda0e17 KB |
767 | return wxControl::MSWWindowProc(nMsg, wParam, lParam); |
768 | } | |
769 | ||
47d67540 | 770 | #if wxUSE_OWNER_DRAWN |
2bda0e17 KB |
771 | |
772 | // drawing | |
773 | // ------- | |
774 | ||
775 | // space beneath/above each row in pixels | |
776 | // "standard" checklistbox use 1 here, some might prefer 2. 0 is ugly. | |
777 | #define OWNER_DRAWN_LISTBOX_EXTRA_SPACE (1) | |
778 | ||
779 | // the height is the same for all items | |
780 | // ## should be changed for LBS_OWNERDRAWVARIABLE style listboxes | |
781 | // NB: can't forward this to wxListBoxItem because LB_SETITEMDATA | |
782 | // message is not yet sent when we get here! | |
783 | bool wxListBox::MSWOnMeasure(WXMEASUREITEMSTRUCT *item) | |
784 | { | |
785 | // only owner-drawn control should receive this message | |
14483330 | 786 | wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), FALSE ); |
2bda0e17 KB |
787 | |
788 | MEASUREITEMSTRUCT *pStruct = (MEASUREITEMSTRUCT *)item; | |
789 | ||
790 | wxDC dc; | |
791 | dc.SetHDC((WXHDC)CreateIC("DISPLAY", NULL, NULL, 0)); | |
792 | dc.SetFont(wxSystemSettings::GetSystemFont(wxSYS_ANSI_VAR_FONT)); | |
793 | ||
794 | pStruct->itemHeight = dc.GetCharHeight() + 2*OWNER_DRAWN_LISTBOX_EXTRA_SPACE; | |
795 | pStruct->itemWidth = dc.GetCharWidth(); | |
796 | ||
797 | return TRUE; | |
798 | } | |
799 | ||
800 | // forward the message to the appropriate item | |
801 | bool wxListBox::MSWOnDraw(WXDRAWITEMSTRUCT *item) | |
802 | { | |
803 | // only owner-drawn control should receive this message | |
14483330 | 804 | wxCHECK( ((m_windowStyle & wxLB_OWNERDRAW) == wxLB_OWNERDRAW), FALSE ); |
2bda0e17 KB |
805 | |
806 | DRAWITEMSTRUCT *pStruct = (DRAWITEMSTRUCT *)item; | |
807 | wxListBoxItem *pItem = (wxListBoxItem *)SendMessage(hwnd, LB_GETITEMDATA, | |
808 | pStruct->itemID, 0); | |
809 | ||
14483330 | 810 | wxCHECK( (int)pItem != LB_ERR, FALSE ); |
2bda0e17 KB |
811 | |
812 | wxDC dc; | |
813 | dc.SetHDC((WXHDC)pStruct->hDC, FALSE); | |
814 | wxRect rect(pStruct->rcItem.left, pStruct->rcItem.top, | |
815 | pStruct->rcItem.right - pStruct->rcItem.left, | |
816 | pStruct->rcItem.bottom - pStruct->rcItem.top); | |
817 | ||
818 | return pItem->OnDrawItem(dc, rect, | |
819 | (wxOwnerDrawn::wxODAction)pStruct->itemAction, | |
820 | (wxOwnerDrawn::wxODStatus)pStruct->itemState); | |
821 | } | |
822 | ||
823 | #endif | |
47d67540 | 824 | // wxUSE_OWNER_DRAWN |