+ // set these variables so that they could be also fixed in
+ // CBN_EDITCHANGE below
+ sel = GetSelection();
+ value = GetStringSelection();
+
+ // this string is going to become the new combobox value soon but
+ // we need it to be done right now, otherwise the event handler
+ // could get a wrong value when it calls our GetValue()
+ ::SetWindowText(GetHwnd(), value.wx_str());
+
+ {
+ wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, GetId());
+ event.SetInt(sel);
+ event.SetString(value);
+ InitCommandEventWithItems(event, sel);
+
+ ProcessCommand(event);
+ }
+
+ // fall through: for compability with wxGTK, also send the text
+ // update event when the selection changes (this also seems more
+ // logical as the text does change)
+
+ case CBN_EDITCHANGE:
+ if ( m_allowTextEvents )
+ {
+ wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
+
+ // if sel != -1, value was already initialized above
+ if ( sel == -1 )
+ {
+ value = wxGetWindowText(GetHwnd());
+ }
+
+ event.SetString(value);
+ InitCommandEventWithItems(event, sel);
+
+ ProcessCommand(event);
+ }
+ break;
+
+ default:
+ return wxChoice::MSWCommand(param, id);
+ }
+
+ // skip wxChoice version as it would generate its own events for
+ // CBN_SELENDOK and also interfere with our handling of CBN_DROPDOWN
+ return true;
+}
+
+bool wxComboBox::MSWShouldPreProcessMessage(WXMSG *pMsg)
+{
+ // prevent command accelerators from stealing editing
+ // hotkeys when we have the focus
+ if (wxIsCtrlDown())
+ {
+ WPARAM vkey = pMsg->wParam;
+
+ switch (vkey)
+ {
+ case 'C':
+ case 'V':
+ case 'X':
+ case VK_INSERT:
+ case VK_DELETE:
+ case VK_HOME:
+ case VK_END:
+ return false;
+ }
+ }
+
+ return wxChoice::MSWShouldPreProcessMessage(pMsg);
+}
+
+WXHWND wxComboBox::GetEditHWNDIfAvailable() const
+{
+#if wxUSE_DYNLIB_CLASS
+#if defined(WINVER) && WINVER >= 0x0500
+ typedef BOOL (WINAPI *GetComboBoxInfo_t)(HWND, COMBOBOXINFO*);
+ static GetComboBoxInfo_t s_pfnGetComboBoxInfo = NULL;
+ static bool s_triedToLoad = false;
+ if ( !s_triedToLoad )
+ {
+ s_triedToLoad = true;
+ wxLoadedDLL dllUser32("user32.dll");
+ wxDL_INIT_FUNC(s_pfn, GetComboBoxInfo, dllUser32);
+ }
+
+ if ( s_pfnGetComboBoxInfo )
+ {
+ WinStruct<COMBOBOXINFO> info;
+ (*s_pfnGetComboBoxInfo)(GetHwnd(), &info);
+ return info.hwndItem;
+ }
+#endif // WINVER >= 0x0500
+#endif // wxUSE_DYNLIB_CLASS
+
+ if (HasFlag(wxCB_SIMPLE))
+ {
+ POINT pt;
+ pt.x = pt.y = 4;
+ return (WXHWND) ::ChildWindowFromPoint(GetHwnd(), pt);
+ }
+
+ // notice that a slightly safer alternative could be to use FindWindowEx()
+ // but it's not available under WinCE so just take the first child for now
+ // to keep one version of the code for all platforms and fix it later if
+ // problems are discovered
+
+ // we assume that the only child of the combobox is the edit window
+ return (WXHWND)::GetWindow(GetHwnd(), GW_CHILD);
+}
+
+WXHWND wxComboBox::GetEditHWND() const
+{
+ // this function should not be called for wxCB_READONLY controls, it is
+ // the callers responsibility to check this
+ wxASSERT_MSG( !HasFlag(wxCB_READONLY),
+ wxT("read-only combobox doesn't have any edit control") );
+
+ WXHWND hWndEdit = GetEditHWNDIfAvailable();
+ wxASSERT_MSG( hWndEdit, wxT("combobox without edit control?") );
+
+ return hWndEdit;
+}
+
+wxWindow *wxComboBox::GetEditableWindow()
+{
+ wxASSERT_MSG( !HasFlag(wxCB_READONLY),
+ wxT("read-only combobox doesn't have any edit control") );
+
+ return this;
+}
+
+// ----------------------------------------------------------------------------
+// wxComboBox creation
+// ----------------------------------------------------------------------------
+
+bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
+ const wxString& value,
+ const wxPoint& pos,
+ const wxSize& size,
+ int n, const wxString choices[],
+ long style,
+ const wxValidator& validator,
+ const wxString& name)
+{
+ // pretend that wxComboBox is hidden while it is positioned and resized and
+ // show it only right before leaving this method because otherwise there is
+ // some noticeable flicker while the control rearranges itself
+ m_isShown = false;
+
+ if ( !CreateAndInit(parent, id, pos, size, n, choices, style,
+ validator, name) )
+ return false;
+
+ // we shouldn't call SetValue() for an empty string because this would
+ // (correctly) result in an assert with a read only combobox and is useless
+ // for the other ones anyhow
+ if ( !value.empty() )
+ SetValue(value);
+
+ // a (not read only) combobox is, in fact, 2 controls: the combobox itself
+ // and an edit control inside it and if we want to catch events from this
+ // edit control, we must subclass it as well
+ if ( !(style & wxCB_READONLY) )
+ {
+ gs_wndprocEdit = wxSetWindowProc((HWND)GetEditHWND(), wxComboEditWndProc);
+ }
+
+ // and finally, show the control
+ Show(true);
+
+ return true;
+}
+
+bool wxComboBox::Create(wxWindow *parent, wxWindowID id,
+ const wxString& value,
+ const wxPoint& pos,
+ const wxSize& size,
+ const wxArrayString& choices,
+ long style,
+ const wxValidator& validator,
+ const wxString& name)
+{
+ wxCArrayString chs(choices);
+ return Create(parent, id, value, pos, size, chs.GetCount(),
+ chs.GetStrings(), style, validator, name);
+}