+// ----------------------------------------------------------------------------
+// wxComboBox callbacks
+// ----------------------------------------------------------------------------
+
+WXLRESULT wxComboBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
+{
+ // TODO: handle WM_CTLCOLOR messages from our EDIT control to be able to
+ // set its colour correctly (to be the same as our own one)
+
+ switch ( nMsg )
+ {
+ case CB_SETCURSEL:
+ // Selection was set with SetSelection. Update the value too.
+ if ((int)wParam > GetCount())
+ m_value.clear();
+ else
+ m_value = GetString(wParam);
+ m_selectionOld = -1;
+ break;
+
+ case WM_SIZE:
+ // wxStaticBox can generate this message, when modifying the control's style.
+ // This causes the content of the combobox to be selected, for some reason.
+ case WM_STYLECHANGED:
+ {
+ // combobox selection sometimes spontaneously changes when its
+ // size changes, restore it to the old value if necessary
+ long fromOld, toOld;
+ GetSelection(&fromOld, &toOld);
+ WXLRESULT result = wxChoice::MSWWindowProc(nMsg, wParam, lParam);
+
+ long fromNew, toNew;
+ GetSelection(&fromNew, &toNew);
+
+ if ( fromOld != fromNew || toOld != toNew )
+ {
+ SetSelection(fromOld, toOld);
+ }
+
+ return result;
+ }
+ }
+
+ return wxChoice::MSWWindowProc(nMsg, wParam, lParam);
+}
+
+bool wxComboBox::MSWProcessEditMsg(WXUINT msg, WXWPARAM wParam, WXLPARAM lParam)
+{
+ switch ( msg )
+ {
+ case WM_CHAR:
+ // for compatibility with wxTextCtrl, generate a special message
+ // when Enter is pressed
+ if ( wParam == VK_RETURN )
+ {
+ wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
+ InitCommandEvent(event);
+ event.SetString(GetValue());
+ event.SetInt(GetSelection());
+ if ( ProcessCommand(event) )
+ {
+ // don't let the event through to the native control
+ // because it doesn't need it and may generate an annoying
+ // beep if it gets it
+ return true;
+ }
+ }
+ // fall through
+
+ case WM_SYSCHAR:
+ return HandleChar(wParam, lParam, true /* isASCII */);
+
+ case WM_SYSKEYDOWN:
+ case WM_KEYDOWN:
+ return HandleKeyDown(wParam, lParam);
+
+ case WM_SYSKEYUP:
+ case WM_KEYUP:
+ return HandleKeyUp(wParam, lParam);
+
+ case WM_SETFOCUS:
+ return HandleSetFocus((WXHWND)wParam);
+
+ case WM_KILLFOCUS:
+ return HandleKillFocus((WXHWND)wParam);
+ }
+
+ return false;
+}
+
+bool wxComboBox::MSWCommand(WXUINT param, WXWORD id)
+{
+ wxString value;
+ int sel = -1;
+ switch ( param )
+ {
+ case CBN_SELENDOK:
+ case CBN_SELCHANGE:
+ sel = GetSelection();
+
+ // we may sometimes get 2 CBN_SELCHANGE events or a CBN_SELENDOK
+ // before CBN_SELCHANGE with the same index when the user selects
+ // an item in the combobox -- ignore duplicates
+ if ( sel > -1 && sel != m_selectionOld )
+ {
+ m_selectionOld = sel;
+
+ // GetValue() would still return the old value from here but
+ // according to the docs we should return the new value if the
+ // user calls it in his event handler, so update internal
+ // m_value
+ m_value = GetString(sel);
+
+ wxCommandEvent event(wxEVT_COMMAND_COMBOBOX_SELECTED, GetId());
+ event.SetInt(sel);
+ event.SetEventObject(this);
+ event.SetString(m_value);
+ ProcessCommand(event);
+ }
+ else // no valid selection
+ {
+ m_selectionOld = sel;
+
+ // hence no EVT_TEXT neither
+ break;
+ }
+
+ // 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:
+ {
+ wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
+
+ // if sel != -1, value was initialized above (and we can't use
+ // GetValue() here as it would return the old selection and we
+ // want the new one)
+ if ( sel == -1 )
+ {
+ m_value = wxGetWindowText(GetHwnd());
+ m_selectionOld = -1;
+ }
+ else // we're synthesizing text updated event from sel change
+ {
+ // We need to retrieve the current selection because the
+ // user may have changed it in the previous handler (for
+ // CBN_SELCHANGE above).
+ sel = GetSelection();
+ if ( sel > -1 )
+ {
+ m_value = GetString(sel);
+ }
+ }
+
+ event.SetString(m_value);
+ event.SetEventObject(this);
+ ProcessCommand(event);
+ }
+ break;
+
+ default:
+ return wxChoice::MSWCommand(param, id);
+ }
+
+ // let the def window proc have it by returning false, but do not pass the
+ // message we've already handled here (notably CBN_SELCHANGE) to the base
+ // class as it would generate another event for them
+ return false;
+}
+
+WXHWND wxComboBox::GetEditHWND() const
+{
+ // this function should not be called for wxCB_READONLY controls, it is
+ // the callers responsability to check this
+ wxASSERT_MSG( !(GetWindowStyle() & wxCB_READONLY),
+ _T("read-only combobox doesn't have any edit control") );
+
+ POINT pt;
+ pt.x = pt.y = 4;
+ HWND hwndEdit = ::ChildWindowFromPoint(GetHwnd(), pt);
+ if ( !hwndEdit || hwndEdit == GetHwnd() )
+ {
+ wxFAIL_MSG(_T("not read only combobox without edit control?"));
+ }
+
+ return (WXHWND)hwndEdit;
+}
+
+// ----------------------------------------------------------------------------
+// wxComboBox creation
+// ----------------------------------------------------------------------------
+