1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/os2/radiobox.cpp 
   4 // Author:      David Webster 
   8 // Copyright:   (c) David Webster 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  18     #include "wx/wxchar.h" 
  19     #include "wx/string.h" 
  20     #include "wx/bitmap.h" 
  22     #include "wx/radiobox.h" 
  25 #include "wx/os2/private.h" 
  27 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox
, wxControl
) 
  29 // --------------------------------------------------------------------------- 
  31 // --------------------------------------------------------------------------- 
  33 // wnd proc for radio buttons 
  34 MRESULT EXPENTRY 
wxRadioBtnWndProc( HWND hWnd
 
  39 MRESULT EXPENTRY 
wxRadioBoxWndProc( HWND   hWnd
 
  45 // --------------------------------------------------------------------------- 
  47 // --------------------------------------------------------------------------- 
  49 extern void  wxAssociateWinWithHandle( HWND         hWnd
 
  52 extern void wxRemoveHandleAssociation( wxWindowOS2 
*pWin 
); 
  53 // the pointer to standard radio button & box wnd procs 
  54 static WXFARPROC                    fnWndProcRadioBtn 
= NULL
; 
  55 static WXFARPROC                    fnWndProcRadioBox 
= NULL
; 
  57 // =========================================================================== 
  59 // =========================================================================== 
  61 // --------------------------------------------------------------------------- 
  63 // --------------------------------------------------------------------------- 
  66 wxRadioBox::wxRadioBox() 
  68     m_nSelectedButton 
= -1; 
  70     m_ahRadioButtons 
= NULL
; 
  71     m_pnRadioWidth 
= NULL
; 
  72     m_pnRadioHeight 
= NULL
; 
  73 } // end of wxRadioBox::wxRadioBox 
  75 wxRadioBox::~wxRadioBox() 
  77     m_isBeingDeleted 
= true; 
  80         wxRemoveHandleAssociation(this); 
  83         for (int i 
= 0; i 
< m_nNoItems
; i
++) 
  85             wxWindow
* pWin 
= wxFindWinFromHandle((WXHWND
)m_ahRadioButtons
[i
]); 
  86             wxRemoveHandleAssociation(pWin
); 
  88             ::WinDestroyWindow((HWND
)m_ahRadioButtons
[i
]); 
  90         delete[] m_ahRadioButtons
; 
  93         delete[] m_pnRadioWidth
; 
  95         delete[] m_pnRadioHeight
; 
  96 } // end of wxRadioBox::~wxRadioBox 
  98 void wxRadioBox::Command ( 
  99   wxCommandEvent
&                   rEvent
 
 102     SetSelection (rEvent
.GetInt()); 
 103     ProcessCommand(rEvent
); 
 104 } // end of wxRadioBox::Command 
 106 bool wxRadioBox::ContainsHWND( 
 110     size_t                          nCount 
= GetCount(); 
 113     for (i 
= 0; i 
< nCount
; i
++) 
 115         if (GetRadioButtons()[i
] == hWnd
) 
 119 } // end of wxRadioBox::ContainsHWND 
 121 bool wxRadioBox::Create( 
 124 , const wxString
&                   rsTitle
 
 125 , const wxPoint
&                    rPos
 
 126 , const wxSize
&                     rSize
 
 127 , const wxArrayString
&              asChoices
 
 130 , const wxValidator
&                rVal
 
 131 , const wxString
&                   rsName
 
 134     wxCArrayString 
chs(asChoices
); 
 136     return Create(pParent
, vId
, rsTitle
, rPos
, rSize
, chs
.GetCount(), 
 137                   chs
.GetStrings(), nMajorDim
, lStyle
, rVal
, rsName
); 
 140 bool wxRadioBox::Create( 
 143 , const wxString
&                   rsTitle
 
 144 , const wxPoint
&                    rPos
 
 145 , const wxSize
&                     rSize
 
 147 , const wxString                    asChoices
[] 
 150 , const wxValidator
&                rVal
 
 151 , const wxString
&                   rsName
 
 156     HWND                            hWndParent 
= GetHwndOf(pParent
); 
 158     vColour
.Set(wxString(wxT("BLACK"))); 
 159     m_backgroundColour 
= pParent
->GetBackgroundColour(); 
 160     m_nSelectedButton 
= -1; 
 164     // Common initialization 
 166     if (!CreateControl( pParent
 
 175     if (!OS2CreateControl( wxT("STATIC") 
 183     wxAssociateWinWithHandle(m_hWnd
, this); 
 186     // Now we can set m_nNoItems and let SetMajorDim set m_numCols/m_numRows 
 189     SetMajorDim(nMajorDim 
== 0 ? nNum 
: nMajorDim
, lStyle
); 
 191     m_ahRadioButtons 
= new WXHWND
[nNum
]; 
 192     m_pnRadioWidth   
= new int[nNum
]; 
 193     m_pnRadioHeight  
= new int[nNum
]; 
 195     for (int i 
= 0; i 
< nNum
; i
++) 
 197         m_pnRadioWidth
[i
] = m_pnRadioHeight
[i
] = -1; 
 198         long                        lStyleBtn 
= BS_AUTORADIOBUTTON 
| WS_VISIBLE
; 
 199         int                         nNewId 
= NewControlId(); 
 202             lStyleBtn 
|= WS_GROUP 
| WS_TABSTOP
; 
 204         wxString                    sLabel 
= ::wxPMTextToLabel(asChoices
[i
]); 
 206         HWND                        hWndBtn 
= (WXHWND
)::WinCreateWindow ( hWndParent
, 
 221         lColor 
= (LONG
)vColour
.GetPixel(); 
 222         ::WinSetPresParam( hWndBtn
 
 228         lColor 
= (LONG
)m_backgroundColour
.GetPixel(); 
 229         ::WinSetPresParam( hWndBtn
 
 234         m_ahRadioButtons
[i
] = (WXHWND
)hWndBtn
; 
 235         SubclassRadioButton((WXHWND
)hWndBtn
); 
 236         wxAssociateWinWithHandle(hWndBtn
, this); 
 237         wxOS2SetFont( hWndBtn
 
 240         ::WinSetWindowULong(hWndBtn
, QWL_USER
, (ULONG
)this); 
 241         m_aSubControls
.Add(nNewId
); 
 245     // Create a dummy control to end the group. 
 247     (void)::WinCreateWindow ( hWndParent
, 
 254                               (HMENU
)NewControlId(), 
 258     fnWndProcRadioBox 
= (WXFARPROC
)::WinSubclassWindow( GetHwnd() 
 259                                                        ,(PFNWP
)wxRadioBoxWndProc
 
 261     ::WinSetWindowULong(GetHwnd(), QWL_USER
, (ULONG
)this); 
 262     lColor 
= (LONG
)vColour
.GetPixel(); 
 263     ::WinSetPresParam( m_hWnd
 
 269     lColor 
= (LONG
)m_backgroundColour
.GetPixel(); 
 270     ::WinSetPresParam( m_hWnd
 
 284 } // end of wxRadioBox::Create 
 286 wxSize 
wxRadioBox::DoGetBestSize() const 
 288     return (GetTotalButtonSize(GetMaxButtonSize())); 
 289 } // end of wxRadioBox::DoGetBestSize 
 291 void wxRadioBox::DoSetSize( 
 300     // Input parameters assume wxWidgets coordinate system 
 312     wxSize                          vMaxSize 
= GetMaxButtonSize(); 
 320     wxFont                          vFont 
= GetFont(); 
 322     m_nSizeFlags 
= nSizeFlags
; 
 323     GetPosition( &nCurrentX
 
 330     if (nX 
== wxDefaultCoord 
&& !(nSizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 332     if (nY 
== wxDefaultCoord 
&& !(nSizeFlags 
& wxSIZE_ALLOW_MINUS_ONE
)) 
 339     wxGetCharSize( m_hWnd
 
 346     // Attempt to have a look coherent with other platforms: We compute the 
 347     // biggest toggle dim, then we align all items according this value. 
 349     vMaxSize   
= GetMaxButtonSize(); 
 350     nMaxWidth  
= vMaxSize
.x
; 
 351     nMaxHeight 
= vMaxSize
.y
; 
 353     vTotSize   
= GetTotalButtonSize(vMaxSize
); 
 354     nTotWidth  
= vTotSize
.x
; 
 355     nTotHeight 
= vTotSize
.y
; 
 358     // Only change our width/height if asked for 
 362         if (nSizeFlags 
& wxSIZE_AUTO_WIDTH 
) 
 370         if (nSizeFlags 
& wxSIZE_AUTO_HEIGHT
) 
 371             nHeight 
= nTotHeight
; 
 373             nHeight 
= nHeightOld
; 
 377     // Now convert to OS/2 coordinate system 
 379     wxWindowOS2
*                    pParent 
= (wxWindowOS2
*)GetParent(); 
 381         nYy 
= GetOS2ParentHeight(pParent
) - nYy 
- nHeight
; 
 385         ::WinQueryWindowRect(HWND_DESKTOP
, &vRect
); 
 386         nYy 
= vRect
.yTop 
- nYy 
- nHeight
; 
 388     nYOffset 
= nYy 
+ nHeight
; 
 389     ::WinSetWindowPos( GetHwnd() 
 395                       ,SWP_ZORDER 
| SWP_SIZE 
| SWP_MOVE 
| SWP_SHOW
 
 399     // Now position all the buttons: the current button will be put at 
 400     // wxPoint(x_offset, y_offset) and the new row/column will start at 
 401     // startX/startY. The size of all buttons will be the same wxSize(maxWidth, 
 402     // maxHeight) except for the buttons in the last column which should extend 
 403     // to the right border of radiobox and thus can be wider than this. 
 405     // Also, remember that wxRA_SPECIFY_COLS means that we arrange buttons in 
 406     // left to right order and m_majorDim is the number of columns while 
 407     // wxRA_SPECIFY_ROWS means that the buttons are arranged top to bottom and 
 408     // m_majorDim is the number of rows. 
 411     nYOffset 
-= (nMaxHeight 
+ ((3*nCy1
)/2)); 
 416     for (int i 
= 0; i 
< m_nNoItems
; i
++) 
 419         // The last button in the row may be wider than the other ones as the 
 420         // radiobox may be wider than the sum of the button widths (as it 
 421         // happens, for example, when the radiobox label is very long) 
 423         bool                        bIsLastInTheRow
; 
 425         if (m_windowStyle 
& wxRA_SPECIFY_COLS
) 
 428             // Item is the last in its row if it is a multiple of the number of 
 429             // columns or if it is just the last item 
 433             bIsLastInTheRow 
= ((n 
% GetMajorDim()) == 0) || (n 
== m_nNoItems
); 
 435         else // winRA_SPECIFY_ROWS 
 438             // Item is the last in the row if it is in the last columns 
 440             bIsLastInTheRow 
= i 
>= (m_nNoItems
/GetMajorDim()) * GetMajorDim(); 
 444         // Is this the start of new row/column? 
 446         if (i 
&& (i 
% GetMajorDim() == 0)) 
 448             if (m_windowStyle 
& wxRA_SPECIFY_ROWS
) 
 451                 // Start of new column 
 454                 nXOffset 
+= nMaxWidth 
+ nCx1
; 
 456             else // start of new row 
 459                 nYOffset 
-= nMaxHeight
; 
 460                 if (m_pnRadioWidth
[0] > 0L) 
 470             // Make the button go to the end of radio box 
 472             nWidthBtn 
= nStartX 
+ nWidth 
- nXOffset 
- (2 * nCx1
); 
 473             if (nWidthBtn 
< nMaxWidth
) 
 474                 nWidthBtn 
= nMaxWidth
; 
 479             // Normal button, always of the same size 
 481             nWidthBtn 
= nMaxWidth
; 
 485         // Make all buttons of the same, maximal size - like this they 
 486         // cover the radiobox entirely and the radiobox tooltips are always 
 487         // shown (otherwise they are not when the mouse pointer is in the 
 488         // radiobox part not belonging to any radiobutton) 
 490         ::WinSetWindowPos( (HWND
)m_ahRadioButtons
[i
] 
 496                           ,SWP_ZORDER 
| SWP_SIZE 
| SWP_MOVE 
| SWP_SHOW
 
 499         // Where do we put the next button? 
 501         if (m_windowStyle 
& wxRA_SPECIFY_ROWS
) 
 506             nYOffset 
-= nMaxHeight
; 
 507             if (m_pnRadioWidth
[0] > 0) 
 513             // To the right of this one 
 515             nXOffset 
+= nWidthBtn 
+ nCx1
; 
 518 } // end of wxRadioBox::DoSetSize 
 520 bool wxRadioBox::Enable(int nItem
, bool bEnable
) 
 522     wxCHECK_MSG( IsValid(nItem
), false, 
 523                  wxT("invalid item in wxRadioBox::Enable()") ); 
 525     ::WinEnableWindow((HWND
) m_ahRadioButtons
[nItem
], bEnable
); 
 527 } // end of wxRadioBox::Enable 
 529 bool wxRadioBox::Enable( 
 533     if ( !wxControl::Enable(bEnable
) ) 
 535     for (int i 
= 0; i 
< m_nNoItems
; i
++) 
 536         ::WinEnableWindow((HWND
)m_ahRadioButtons
[i
], bEnable
); 
 538 } // end of wxRadioBox::Enable 
 540 int wxRadioBox::GetCount() const 
 543 } // end of wxRadioBox::GetCount 
 545 wxString 
wxRadioBox::GetLabel(int nItem
) const 
 547     wxCHECK_MSG( IsValid(nItem
), wxEmptyString
, wxT("invalid radiobox index") ); 
 549     return wxGetWindowText(m_ahRadioButtons
[nItem
]); 
 550 } // end of wxRadioBox::GetLabel 
 552 wxSize 
wxRadioBox::GetMaxButtonSize() const 
 557     for (int i 
= 0 ; i 
< m_nNoItems
; i
++) 
 562         if (m_pnRadioWidth
[i
] < 0L) 
 564             GetTextExtent( wxGetWindowText(m_ahRadioButtons
[i
]) 
 570             // Adjust the size to take into account the radio box itself 
 571             // FIXME this is totally bogus! 
 573             nWidth  
+= RADIO_SIZE
; 
 579             nWidth  
= m_pnRadioWidth
[i
]; 
 580             nHeight 
= m_pnRadioHeight
[i
]; 
 582         if (nWidthMax 
< nWidth 
) 
 584         if (nHeightMax 
< nHeight 
) 
 585             nHeightMax 
= nHeight
; 
 587     wxSize 
maxsize( nWidthMax
, nHeightMax
); 
 589 } // end of wxRadioBox::GetMaxButtonSize 
 591 // Get single selection, for single choice list items 
 592 int wxRadioBox::GetSelection() const 
 594     return m_nSelectedButton
; 
 595 } // end of wxRadioBox::GetSelection 
 597 void wxRadioBox::GetSize( int* pnWidth
, int* pnHeight 
) const 
 607         wxFindMaxSize( m_hWnd
 
 611     for (int i 
= 0; i 
< m_nNoItems
; i
++) 
 612         wxFindMaxSize( m_ahRadioButtons
[i
] 
 617         *pnWidth  
= vRect
.xRight 
- vRect
.xLeft
; 
 619         *pnHeight 
= vRect
.yTop 
- vRect
.yBottom
; 
 620 } // end of wxRadioBox::GetSize 
 622 // Find string for position 
 623 wxString 
wxRadioBox::GetString( 
 627     wxCHECK_MSG( IsValid(nNum
), wxString(""), wxT("invalid radiobox index") ); 
 628     return wxGetWindowText(m_ahRadioButtons
[nNum
]); 
 629 } // end of wxRadioBox::GetString 
 631 // For single selection items only 
 632 wxString 
wxRadioBox::GetStringSelection() const 
 635     int                             nSel 
= GetSelection(); 
 638         sResult 
= GetString(nSel
); 
 640 } // end of wxRadioBox::GetStringSelection 
 642 wxSize 
wxRadioBox::GetTotalButtonSize( const wxSize
& rSizeBtn 
) const 
 650     nCx1 
= GetCharWidth(); 
 651     nCy1 
= GetCharHeight(); 
 652     nHeight 
= GetRowCount() * rSizeBtn
.y 
+ (2 * nCy1
); 
 653     nWidth  
= GetColumnCount() * (rSizeBtn
.x 
+ nCx1
) + nCx1
; 
 656     // And also wide enough for its label 
 658     wxString                        sStr 
= wxGetWindowText(GetHwnd()); 
 665         nWidthLabel 
+= 2*nCx1
; 
 667     if (nWidthLabel 
> nWidth
) 
 668         nWidth 
= nWidthLabel
; 
 670     wxSize 
total( nWidth
, nHeight 
); 
 672 } // end of wxRadioBox::GetTotalButtonSize 
 674 WXHBRUSH 
wxRadioBox::OnCtlColor( WXHDC    hwinDC
, 
 675                                  WXHWND   
WXUNUSED(hWnd
), 
 676                                  WXUINT   
WXUNUSED(uCtlColor
), 
 677                                  WXUINT   
WXUNUSED(uMessage
), 
 678                                  WXWPARAM 
WXUNUSED(wParam
), 
 679                                  WXLPARAM 
WXUNUSED(lParam
) ) 
 681     HPS hPS 
= (HPS
)hwinDC
; // pass in a PS handle in OS/2 
 683     if (GetParent()->GetTransparentBackground()) 
 684         ::GpiSetBackMix(hPS
, BM_LEAVEALONE
); 
 686         ::GpiSetBackMix(hPS
, BM_OVERPAINT
); 
 688     wxColour vColBack 
= GetBackgroundColour(); 
 690     ::GpiSetBackColor(hPS
, vColBack
.GetPixel()); 
 691     ::GpiSetColor(hPS
, vColBack
.GetPixel()); 
 693     wxBrush
* pBrush 
= wxTheBrushList
->FindOrCreateBrush( vColBack
, wxSOLID 
); 
 694     return ((WXHBRUSH
)pBrush
->GetResourceHandle()); 
 695 } // end of wxRadioBox::OnCtlColor 
 697 bool wxRadioBox::OS2Command( WXUINT uCmd
, 
 700     int nSelectedButton 
= -1; 
 702     if (uCmd 
== BN_CLICKED
) 
 707         for (int i 
= 0; i 
< m_nNoItems
; i
++) 
 709             if (wId 
== wxGetWindowId(m_ahRadioButtons
[i
])) 
 715         if (nSelectedButton 
== -1) 
 722         if (nSelectedButton 
!= m_nSelectedButton
) 
 724             m_nSelectedButton 
= nSelectedButton
; 
 725             SendNotificationEvent(); 
 731 } // end of wxRadioBox::OS2Command 
 733 void wxRadioBox::SendNotificationEvent() 
 735     wxCommandEvent                  
vEvent( wxEVT_COMMAND_RADIOBOX_SELECTED
 
 739     vEvent
.SetInt( m_nSelectedButton 
); 
 740     vEvent
.SetString( GetString(m_nSelectedButton
) ); 
 741     vEvent
.SetEventObject(this); 
 742     ProcessCommand(vEvent
); 
 743 } // end of wxRadioBox::SendNotificationEvent 
 745 void wxRadioBox::SetFocus() 
 749         if (m_nSelectedButton 
== -1) 
 750             ::WinSetFocus(HWND_DESKTOP
, (HWND
)m_ahRadioButtons
[0]); 
 752             ::WinSetFocus(HWND_DESKTOP
, (HWND
)m_ahRadioButtons
[m_nSelectedButton
]); 
 754 } // end of wxRadioBox::SetFocus 
 756 bool wxRadioBox::SetFont( 
 760     if (!wxControl::SetFont(rFont
)) 
 768     // Also set the font of our radio buttons 
 770     for (int n 
= 0; n 
< (int)m_nNoItems
; n
++) 
 772         HWND                        hWndBtn 
= (HWND
)m_ahRadioButtons
[n
]; 
 774         wxOS2SetFont( hWndBtn
 
 777         ::WinInvalidateRect(hWndBtn
, NULL
, FALSE
); 
 780 } // end of wxRadioBox::SetFont 
 782 void wxRadioBox::SetSelection( 
 786     wxCHECK_RET( IsValid(nNum
), wxT("invalid radiobox index") ); 
 788     if ( IsValid(m_nSelectedButton
) ) 
 789         ::WinSendMsg((HWND
)m_ahRadioButtons
[m_nSelectedButton
], BM_SETCHECK
, (MPARAM
)0, (MPARAM
)0); 
 791     ::WinSendMsg((HWND
)m_ahRadioButtons
[nNum
], BM_SETCHECK
, (MPARAM
)1, (MPARAM
)0); 
 792     ::WinSetFocus(HWND_DESKTOP
, (HWND
)m_ahRadioButtons
[nNum
]); 
 793     m_nSelectedButton 
= nNum
; 
 794 } // end of wxRadioBox::SetSelection 
 796 void wxRadioBox::SetString( 
 798 , const wxString
&                   rsLabel
 
 801     wxCHECK_RET( IsValid(nItem
), wxT("invalid radiobox index") ); 
 803     m_pnRadioWidth
[nItem
] = m_pnRadioHeight
[nItem
] = -1; 
 804     ::WinSetWindowText((HWND
)m_ahRadioButtons
[nItem
], (PSZ
)rsLabel
.c_str()); 
 805 } // end of wxRadioBox::SetString 
 807 bool wxRadioBox::SetStringSelection(const wxString
& rsStr
) 
 809     int nSel 
= FindString(rsStr
); 
 818 } // end of wxRadioBox::SetStringSelection 
 820 bool wxRadioBox::Show( 
 824     if (!wxControl::Show(bShow
)) 
 827     for (int i 
= 0; i 
< m_nNoItems
; i
++) 
 829         ::WinShowWindow((HWND
)m_ahRadioButtons
[i
], (BOOL
)bShow
); 
 832 } // end of wxRadioBox::Show 
 834 // Show a specific button 
 835 bool wxRadioBox::Show( 
 840     wxCHECK_MSG( IsValid(nItem
), false, 
 841                  wxT("invalid item in wxRadioBox::Show()") ); 
 843     ::WinShowWindow((HWND
)m_ahRadioButtons
[nItem
], bShow
); 
 846 } // end of wxRadioBox::Show 
 848 void wxRadioBox::SubclassRadioButton( 
 852     fnWndProcRadioBtn 
= (WXFARPROC
)::WinSubclassWindow(hWndBtn
, (PFNWP
)wxRadioBtnWndProc
); 
 853 } // end of wxRadioBox::SubclassRadioButton 
 855 MRESULT 
wxRadioBox::WindowProc( 
 861     return (wxControl::OS2WindowProc( uMsg
 
 865 } // end of wxRadioBox::WindowProc 
 867 // --------------------------------------------------------------------------- 
 868 // window proc for radio buttons 
 869 // --------------------------------------------------------------------------- 
 871 MRESULT 
wxRadioBtnWndProc( 
 882                 USHORT                  uKeyFlags 
= SHORT1FROMMP((MPARAM
)wParam
); 
 884                 if (!(uKeyFlags 
& KC_KEYUP
)) // Key Down event 
 886                     if (uKeyFlags 
& KC_VIRTUALKEY
) 
 888                         wxRadioBox
*             pRadiobox 
= (wxRadioBox 
*)::WinQueryWindowULong( hWnd
 
 891                         USHORT                  uVk 
= SHORT2FROMMP((MPARAM
)lParam
); 
 892                         bool                    bProcessed 
= true; 
 917                                 // Just to suppress the compiler warning 
 924                             int             nSelOld 
= pRadiobox
->GetSelection(); 
 925                             int             nSelNew 
= pRadiobox
->GetNextItem( nSelOld
 
 927                                                                              ,pRadiobox
->GetWindowStyleFlag() 
 930                             if (nSelNew 
!= nSelOld
) 
 932                                 pRadiobox
->SetSelection(nSelNew
); 
 935                                 // Emulate the button click 
 937                                 pRadiobox
->SendNotificationEvent(); 
 947     return fnWndProcRadioBtn( hWnd
 
 952 } // end of wxRadioBtnWndProc 
 954 MRESULT EXPENTRY 
wxRadioBoxWndProc( HWND hWnd
, 
 959     return (fnWndProcRadioBox( hWnd
, 
 964 } // end of wxRadioBoxWndProc