X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4afd752902ae7c44f4b3dc2edb11d7c24f95ed54..71fe5c01eb5072bfbaf940f6675acbabc6d8913b:/src/msw/radiobox.cpp diff --git a/src/msw/radiobox.cpp b/src/msw/radiobox.cpp index 20ce47a197..dc5c3c5926 100644 --- a/src/msw/radiobox.cpp +++ b/src/msw/radiobox.cpp @@ -38,23 +38,36 @@ #include "wx/msw/private.h" #if wxUSE_TOOLTIPS - #include - + #ifndef __GNUWIN32_OLD__ + #include + #endif #include "wx/tooltip.h" #endif // wxUSE_TOOLTIPS -#if !USE_SHARED_LIBRARY - IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl) -#endif +IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxControl) -// VZ: the new behaviour is to create the radio buttons as children of the -// radiobox instead of creating them as children of the radiobox' parent. +// there are two possible ways to create the radio buttons: either as children +// of the radiobox or as siblings of it - allow playing with both variants for +// now, eventually we will choose the best one for our purposes +// +// two main problems are the keyboard navigation inside the radiobox (arrows +// should switch between buttons, not pass focus to the next control) and the +// tooltips - a tooltip is associated with the radiobox itself, not the +// children... // -// This seems more logical, more consistent with what other frameworks do -// and allows tooltips to work with radioboxes, so there should be no -// reason to revert to the backward compatible behaviour - but I still -// leave this possibility just in case. -#define RADIOBTN_PARENT_IS_RADIOBOX 1 +// the problems with setting this to 1: +// a) Alt- isn't handled properly by IsDialogMessage() +// because it sets focus to the next control accepting it which is not a +// radio button but a radiobox sibling in this case - the only solution to +// this would be to handle Alt- ourselves +// b) the problems with setting radiobox colours under Win98/2K were reported +// but I couldn't reproduce it so I have no idea about what causes it +// +// the problems with setting this to 0: +// a) the tooltips are not shown for the radiobox - possible solution: make +// TTM_WINDOWFROMPOS handling code in msw/tooltip.cpp work (easier said than +// done because I don't know why it doesn't work) +#define RADIOBTN_PARENT_IS_RADIOBOX 0 // --------------------------------------------------------------------------- // private functions @@ -72,7 +85,7 @@ LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hWnd, // --------------------------------------------------------------------------- // the pointer to standard radio button wnd proc -static WXFARPROC s_wndprocRadioBtn = (WXFARPROC)NULL; +static WNDPROC s_wndprocRadioBtn = (WNDPROC)NULL; #endif // __WIN32__ @@ -154,7 +167,7 @@ wxRadioBox::wxRadioBox(wxWindow *parent, wxFunction func, const char *title, delete choices2; } -#endif +#endif // WXWIN_COMPATIBILITY // Radio box item wxRadioBox::wxRadioBox() @@ -192,7 +205,8 @@ bool wxRadioBox::Create(wxWindow *parent, return FALSE; // create the static box - if ( !MSWCreateControl(wxT("BUTTON"), BS_GROUPBOX, pos, size, title, 0) ) + if ( !MSWCreateControl(wxT("BUTTON"), BS_GROUPBOX | WS_GROUP, + pos, size, title, 0) ) return FALSE; // and now create the buttons @@ -220,7 +234,7 @@ bool wxRadioBox::Create(wxWindow *parent, { m_radioWidth[i] = m_radioHeight[i] = -1; - long styleBtn = BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE; + long styleBtn = BS_AUTORADIOBUTTON | WS_TABSTOP | WS_CHILD | WS_VISIBLE; if ( i == 0 && style == 0 ) styleBtn |= WS_GROUP; @@ -359,9 +373,9 @@ void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags) int xx = x; int yy = y; - if (x == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) + if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) xx = currentX; - if (y == -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) + if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) yy = currentY; #if RADIOBTN_PARENT_IS_RADIOBOX @@ -665,15 +679,17 @@ void wxRadioBox::Command(wxCommandEvent & event) ProcessCommand (event); } +// NB: if this code is changed, wxGetWindowForHWND() which relies on having the +// radiobox pointer in GWL_USERDATA for radio buttons must be updated too! void wxRadioBox::SubclassRadioButton(WXHWND hWndBtn) { + // No GWL_USERDATA in Win16, so omit this subclassing. #ifdef __WIN32__ HWND hwndBtn = (HWND)hWndBtn; if ( !s_wndprocRadioBtn ) - s_wndprocRadioBtn = (WXFARPROC)::GetWindowLong(hwndBtn, GWL_WNDPROC); + s_wndprocRadioBtn = (WNDPROC)::GetWindowLong(hwndBtn, GWL_WNDPROC); - // No GWL_USERDATA in Win16, so omit this subclassing. ::SetWindowLong(hwndBtn, GWL_WNDPROC, (long)wxRadioBtnWndProc); ::SetWindowLong(hwndBtn, GWL_USERDATA, (long)this); #endif // __WIN32__ @@ -703,24 +719,51 @@ bool wxRadioBox::SetFont(const wxFont& font) ::SendMessage((HWND)m_radioButtons[n], WM_SETFONT, (WPARAM)hfont, 0L); } + // this is needed because otherwise the buttons are not redrawn correctly + Refresh(); + return TRUE; } +// ---------------------------------------------------------------------------- +// our window proc +// ---------------------------------------------------------------------------- + long wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { - // This is required for the radiobox to be sensitive to mouse input, - // e.g. for Dialog Editor. - if (nMsg == WM_NCHITTEST) + switch ( nMsg ) { - int xPos = LOWORD(lParam); // horizontal position of cursor - int yPos = HIWORD(lParam); // vertical position of cursor +#ifdef __WIN32__ + case WM_CTLCOLORSTATIC: + // set the colour of the radio buttons to be the same as ours + { + HDC hdc = (HDC)wParam; + + const wxColour& colBack = GetBackgroundColour(); + ::SetBkColor(hdc, wxColourToRGB(colBack)); + ::SetTextColor(hdc, wxColourToRGB(GetForegroundColour())); - ScreenToClient(&xPos, &yPos); + wxBrush *brush = wxTheBrushList->FindOrCreateBrush(colBack, wxSOLID); - // Make sure you can drag by the top of the groupbox, but let - // other (enclosed) controls get mouse events also - if (yPos < 10) - return (long)HTCLIENT; + return (WXHBRUSH)brush->GetResourceHandle(); + } +#endif // Win32 + + // This is required for the radiobox to be sensitive to mouse input, + // e.g. for Dialog Editor. + case WM_NCHITTEST: + { + int xPos = LOWORD(lParam); // horizontal position of cursor + int yPos = HIWORD(lParam); // vertical position of cursor + + ScreenToClient(&xPos, &yPos); + + // Make sure you can drag by the top of the groupbox, but let + // other (enclosed) controls get mouse events also + if (yPos < 10) + return (long)HTCLIENT; + } + break; } return wxControl::MSWWindowProc(nMsg, wParam, lParam); @@ -733,95 +776,104 @@ long wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) #ifdef __WIN32__ LRESULT APIENTRY _EXPORT wxRadioBtnWndProc(HWND hwnd, - UINT msg, + UINT message, WPARAM wParam, LPARAM lParam) { - bool processed = FALSE; - if ( msg == WM_KEYDOWN -#if wxUSE_TOOLTIPS - || msg == WM_NOTIFY -#endif // wxUSE_TOOLTIPS - ) + switch ( message ) { - wxRadioBox *radiobox = (wxRadioBox *)::GetWindowLong(hwnd, GWL_USERDATA); + case WM_GETDLGCODE: + // we must tell IsDialogMessage()/our kbd processing code that we + // want to process arrows ourselves because neither of them is + // smart enough to handle arrows properly for us + { + long lDlgCode = ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd, + message, wParam, lParam); - wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") ); + return lDlgCode | DLGC_WANTARROWS; + } #if wxUSE_TOOLTIPS - if ( msg == WM_NOTIFY ) - { - NMHDR* hdr = (NMHDR *)lParam; - if ( (int)hdr->code == TTN_NEEDTEXT ) + case WM_NOTIFY: { - wxToolTip *tt = radiobox->GetToolTip(); - if ( tt ) + NMHDR* hdr = (NMHDR *)lParam; + if ( (int)hdr->code == TTN_NEEDTEXT ) { - TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam; - ttt->lpszText = (wxChar *)tt->GetTip().c_str(); + wxRadioBox *radiobox = (wxRadioBox *) + ::GetWindowLong(hwnd, GWL_USERDATA); + + wxCHECK_MSG( radiobox, 0, + wxT("radio button without radio box?") ); + + wxToolTip *tooltip = radiobox->GetToolTip(); + if ( tooltip ) + { + TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam; + ttt->lpszText = (wxChar *)tooltip->GetTip().c_str(); + } - processed = TRUE; + // processed + return 0; } } - } - else // msg == WM_KEYDOWN + break; #endif // wxUSE_TOOLTIPS - { - processed = TRUE; - - int sel = radiobox->GetSelection(); - switch ( wParam ) + case WM_KEYDOWN: { - case VK_UP: - sel--; - break; + wxRadioBox *radiobox = (wxRadioBox *) + ::GetWindowLong(hwnd, GWL_USERDATA); - case VK_LEFT: - sel -= radiobox->GetNumVer(); - break; + wxCHECK_MSG( radiobox, 0, wxT("radio button without radio box?") ); - case VK_DOWN: - sel++; - break; + bool processed = TRUE; - case VK_RIGHT: - sel += radiobox->GetNumVer(); - break; + int selOld = radiobox->GetSelection(); + int selNew = selOld; - case VK_TAB: - { - wxNavigationKeyEvent event; - event.SetDirection(!(::GetKeyState(VK_SHIFT) & 0x100)); - event.SetWindowChange(FALSE); - event.SetEventObject(radiobox); + switch ( wParam ) + { + case VK_UP: + selNew--; + break; - if ( radiobox->GetEventHandler()->ProcessEvent(event) ) - return 0; - } - // fall through + case VK_LEFT: + selNew -= radiobox->GetNumVer(); + break; - default: - processed = FALSE; - } + case VK_DOWN: + selNew++; + break; - if ( processed ) - { - if ( sel >= 0 && sel < radiobox->Number() ) + case VK_RIGHT: + selNew += radiobox->GetNumVer(); + break; + + default: + processed = FALSE; + } + + if ( processed ) { - radiobox->SetSelection(sel); + // ensure that selNew is in range [0..num) + int num = radiobox->Number(); + selNew += num; + selNew %= num; - // emulate the button click - radiobox->SendNotificationEvent(); + if ( selNew != selOld ) + { + radiobox->SetSelection(selNew); + + // emulate the button click + radiobox->SendNotificationEvent(); + + return 0; + } } } - } } - if ( processed ) - return 0; - - return ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd, msg, wParam, lParam); + return ::CallWindowProc(CASTWNDPROC s_wndprocRadioBtn, hwnd, message, wParam, lParam); } #endif // __WIN32__