#ifndef WX_PRECOMP
#include "wx/settings.h"
#include "wx/log.h"
+ // for wxEVT_COMMAND_TEXT_ENTER
+ #include "wx/textctrl.h"
#endif
#include "wx/combobox.h"
#include "wx/msw/private.h"
#if wxUSE_TOOLTIPS
- #ifndef __GNUWIN32_OLD__
+ #if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__)
#include <commctrl.h>
#endif
#include "wx/tooltip.h"
switch ( message )
{
- // forward some messages to the combobox
+ // forward some messages to the combobox to generate the appropriate
+ // wxEvents from them
case WM_KEYUP:
case WM_KEYDOWN:
case WM_CHAR:
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
{
wxComboBox *combo = wxDynamicCast(win, wxComboBox);
- wxCHECK_MSG( combo, 0, _T("should have combo as parent") );
-
- if ( combo->MSWProcessEditMsg(message, wParam, lParam) )
+ if ( !combo )
+ {
+ // we can get WM_KILLFOCUS while our parent is already half
+ // destroyed and hence doesn't look like a combobx any
+ // longer, check for it to avoid bogus assert failures
+ if ( !win->IsBeingDeleted() )
+ {
+ wxFAIL_MSG( _T("should have combo as parent") );
+ }
+ }
+ else if ( combo->MSWProcessEditMsg(message, wParam, lParam) )
+ {
+ // handled by parent
return 0;
+ }
}
break;
-#if 0
case WM_GETDLGCODE:
{
wxCHECK_MSG( win, 0, _T("should have a parent") );
}
}
break;
-#endif // 0
// deal with tooltips here
-#if wxUSE_TOOLTIPS
+#if wxUSE_TOOLTIPS && defined(TTN_NEEDTEXT)
case WM_NOTIFY:
{
wxCHECK_MSG( win, 0, _T("should have a parent") );
NMHDR* hdr = (NMHDR *)lParam;
- if ( (int)hdr->code == TTN_NEEDTEXT )
+ if ( hdr->code == TTN_NEEDTEXT )
{
wxToolTip *tooltip = win->GetToolTip();
if ( tooltip )
wxColour colBack = GetBackgroundColour();
if (!IsEnabled())
- colBack = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE);
+ colBack = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
::SetBkColor(hdc, wxColourToRGB(colBack));
::SetTextColor(hdc, wxColourToRGB(GetForegroundColour()));
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());
+ ProcessCommand(event);
+ }
+
return HandleChar(wParam, lParam, TRUE /* isASCII */);
-
+
case WM_KEYDOWN:
return HandleKeyDown(wParam, lParam);
case WM_KEYUP:
return HandleKeyUp(wParam, lParam);
+
+ case WM_SETFOCUS:
+ return HandleSetFocus((WXHWND)wParam);
+
+ case WM_KILLFOCUS:
+ return HandleKillFocus((WXHWND)wParam);
}
return FALSE;
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)
- wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
- event.SetString(sel == -1 ? GetValue() : value);
+ if ( sel == -1 )
+ {
+ value = GetValue();
+ }
+ else // we're synthesizing text updated event from sel change
+ {
+ // we need to do this because the user code expects
+ // wxComboBox::GetValue() to return the new value from
+ // "text updated" handler but it hadn't been updated yet
+ SetValue(value);
+ }
+
+ event.SetString(value);
event.SetEventObject(this);
ProcessCommand(event);
}
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;
+
// first create wxWin object
if ( !CreateControl(parent, id, pos, size, style, validator, name) )
return FALSE;
if ( style & wxCB_SORT )
msStyle |= CBS_SORT;
+ if ( style & wxCLIP_SIBLINGS )
+ msStyle |= WS_CLIPSIBLINGS;
+
+
// and now create the MSW control
if ( !MSWCreateControl(_T("COMBOBOX"), msStyle) )
return FALSE;
- SetSize(pos.x, pos.y, size.x, size.y);
-
// A choice/combobox normally has a white background (or other, depending
// on global settings) rather than inheriting the parent's background colour.
- SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
+ SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
for ( int i = 0; i < n; i++ )
{
SetValue(value);
}
+ // do this after appending the values to the combobox so that autosizing
+ // works correctly
+ SetSize(pos.x, pos.y, size.x, size.y);
+
// 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
);
}
+ // and finally, show the control
+ Show(TRUE);
+
return TRUE;
}
-// TODO: update and clear all this horrible mess (VZ)
-
void wxComboBox::SetValue(const wxString& value)
{
- // If newlines are denoted by just 10, must stick 13 in front.
- int singletons = 0;
- int len = value.Length();
- int i;
- for (i = 0; i < len; i ++)
- {
- if ((i > 0) && (value[i] == 10) && (value[i-1] != 13))
- singletons ++;
- }
- if (singletons > 0)
- {
- wxChar *tmp = new wxChar[len + singletons + 1];
- int j = 0;
- for (i = 0; i < len; i ++)
- {
- if ((i > 0) && (value[i] == 10) && (value[i-1] != 13))
- {
- tmp[j] = 13;
- j ++;
- }
- tmp[j] = value[i];
- j ++;
- }
- tmp[j] = 0;
- SetWindowText(GetHwnd(), tmp);
- delete[] tmp;
- }
- else
- SetWindowText(GetHwnd(), value);
+ if ( HasFlag(wxCB_READONLY) )
+ SetStringSelection(value);
+ else
+ SetWindowText(GetHwnd(), value.c_str());
}
// Clipboard operations
void wxComboBox::Copy()
{
- HWND hWnd = GetHwnd();
- SendMessage(hWnd, WM_COPY, 0, 0L);
+ SendMessage(GetHwnd(), WM_COPY, 0, 0L);
}
void wxComboBox::Cut()
{
- HWND hWnd = GetHwnd();
- SendMessage(hWnd, WM_CUT, 0, 0L);
+ SendMessage(GetHwnd(), WM_CUT, 0, 0L);
}
void wxComboBox::Paste()
{
- HWND hWnd = GetHwnd();
- SendMessage(hWnd, WM_PASTE, 0, 0L);
+ SendMessage(GetHwnd(), WM_PASTE, 0, 0L);
}
void wxComboBox::SetEditable(bool WXUNUSED(editable))
}
}
-void wxComboBox::DoMoveWindow(int x, int y, int width, int height)
-{
- // here is why this is necessary: if the width is negative, the combobox
- // window proc makes the window of the size width*height instead of
- // interpreting height in the usual manner (meaning the height of the drop
- // down list - usually the height specified in the call to MoveWindow()
- // will not change the height of combo box per se)
- //
- // this behaviour is not documented anywhere, but this is just how it is
- // here (NT 4.4) and, anyhow, the check shouldn't hurt - however without
- // the check, constraints/sizers using combos may break the height
- // constraint will have not at all the same value as expected
- if ( width < 0 )
- return;
-
- int cx, cy;
- wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
-
- // what should the height of the drop down list be? we choose 10 items by
- // default and also 10 items max (if we always use n, the list will never
- // have vertical scrollbar)
- int n = GetCount();
- if ( !n || (n > 10) )
- n = 10;
-
- height = (n + 1)* EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
-
- wxControl::DoMoveWindow(x, y, width, height);
-}
-
-wxSize wxComboBox::DoGetBestSize() const
-{
- // the choice calculates the horz size correctly, but not the vertical
- // component: correct it
- wxSize size = wxChoice::DoGetBestSize();
-
- int cx, cy;
- wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
- size.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
-
- return size;
-}
-
#endif
// wxUSE_COMBOBOX