2015-05-20 16:52:21 -05:00
// 20 may 2015
2016-04-22 19:37:28 -05:00
# include "uipriv_windows.hpp"
2015-05-20 16:52:21 -05:00
2015-06-05 09:23:31 -05:00
// desired behavior:
2015-09-02 17:26:48 -05:00
// - tab moves between the radio buttons and the adjacent controls
2015-06-05 09:23:31 -05:00
// - arrow keys navigate between radio buttons
2015-09-02 17:26:48 -05:00
// - arrow keys do not leave the radio buttons (this is done in control.c)
// - arrow keys wrap around bare groups (if the previous control has WS_GROUP but the first radio button doesn't, then it doesn't; since our radio buttons are all in their own child window we can't do that)
2015-09-02 17:29:14 -05:00
// - clicking on a radio button draws a focus rect (TODO)
2015-06-05 09:23:31 -05:00
2015-08-30 21:08:25 -05:00
struct uiRadioButtons {
uiWindowsControl c ;
2016-04-22 19:37:28 -05:00
HWND hwnd ; // of the container
std : : vector < HWND > * hwnds ; // of the buttons
2015-05-20 16:52:21 -05:00
} ;
2015-05-21 14:48:16 -05:00
2015-05-21 14:52:59 -05:00
static BOOL onWM_COMMAND ( uiControl * c , HWND clicked , WORD code , LRESULT * lResult )
2015-05-21 14:48:16 -05:00
{
2015-08-30 21:08:25 -05:00
uiRadioButtons * r = uiRadioButtons ( c ) ;
2015-05-21 14:52:59 -05:00
WPARAM check ;
uintmax_t i ;
2015-05-21 14:48:16 -05:00
if ( code ! = BN_CLICKED )
return FALSE ;
2016-04-23 23:33:42 -05:00
for ( const HWND & hwnd : * ( r - > hwnds ) ) {
2015-05-21 14:52:59 -05:00
check = BST_UNCHECKED ;
if ( clicked = = hwnd )
check = BST_CHECKED ;
SendMessage ( hwnd , BM_SETCHECK , check , 0 ) ;
}
2015-05-21 14:48:16 -05:00
* lResult = 0 ;
return TRUE ;
}
2016-04-29 13:12:01 -05:00
static void uiRadioButtonsDestroy ( uiControl * c )
2015-05-21 14:48:16 -05:00
{
2016-04-29 13:12:01 -05:00
uiRadioButtons * r = uiRadioButtons ( c ) ;
2016-04-23 23:33:42 -05:00
for ( const HWND & hwnd : * ( r - > hwnds ) ) {
2015-06-01 17:06:15 -05:00
uiWindowsUnregisterWM_COMMANDHandler ( hwnd ) ;
2015-09-01 06:33:13 -05:00
uiWindowsEnsureDestroyWindow ( hwnd ) ;
2015-06-01 17:06:15 -05:00
}
2016-04-22 19:37:28 -05:00
delete r - > hwnds ;
2016-04-29 13:12:01 -05:00
uiWindowsEnsureDestroyWindow ( r - > hwnd ) ;
uiFreeControl ( uiControl ( r ) ) ;
2015-05-21 14:48:16 -05:00
}
2016-04-29 13:12:01 -05:00
// TODO SyncEnableState
uiWindowsControlAllDefaultsExceptDestroy ( uiRadioButtons )
2015-05-21 14:48:16 -05:00
// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
2015-05-21 16:26:25 -05:00
# define radiobuttonHeight 10
2015-05-21 14:48:16 -05:00
// from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx
2015-05-21 16:26:25 -05:00
# define radiobuttonXFromLeftOfBoxToLeftOfLabel 12
2016-04-29 13:12:01 -05:00
static void uiRadioButtonsMinimumSize ( uiWindowsControl * c , intmax_t * width , intmax_t * height )
2015-05-21 14:48:16 -05:00
{
2015-08-30 21:08:25 -05:00
uiRadioButtons * r = uiRadioButtons ( c ) ;
2015-05-21 14:48:16 -05:00
intmax_t wid , maxwid ;
2016-04-29 13:12:01 -05:00
uiWindowsSizing sizing ;
int x , y ;
2015-05-21 14:48:16 -05:00
2016-04-29 13:12:01 -05:00
if ( r - > hwnds - > size ( ) = = 0 ) {
* width = 0 ;
* height = 0 ;
return ;
}
2015-05-21 14:48:16 -05:00
maxwid = 0 ;
2016-04-22 19:37:28 -05:00
for ( const HWND & hwnd : * ( r - > hwnds ) ) {
wid = uiWindowsWindowTextWidth ( hwnd ) ;
2015-05-21 14:48:16 -05:00
if ( maxwid < wid )
maxwid = wid ;
}
2016-04-29 13:12:01 -05:00
x = radiobuttonXFromLeftOfBoxToLeftOfLabel ;
y = radiobuttonHeight ;
// get it for the radio button itself since that's what counts
// TODO for all of them?
uiWindowsGetSizing ( ( * ( r - > hwnds ) ) [ 0 ] , & sizing ) ;
uiWindowsSizingDlgUnitsToPixels ( & sizing , & x , & y ) ;
* width = x + maxwid ;
* height = y * r - > hwnds - > size ( ) ;
2015-05-21 14:48:16 -05:00
}
2016-04-29 13:12:01 -05:00
static void radiobuttonsRelayout ( uiRadioButtons * r )
2015-05-21 14:48:16 -05:00
{
2016-04-29 13:12:01 -05:00
RECT client ;
2015-05-21 14:48:16 -05:00
intmax_t height1 ;
2015-06-04 22:39:11 -05:00
intmax_t h ;
2016-04-29 13:12:01 -05:00
intmax_t x , y , width , height ;
uiWindowsEnsureGetClientRect ( r - > hwnd , & client ) ;
x = client . left ;
y = client . top ;
width = client . right - client . left ;
height = client . bottom - client . top ;
// TODO compute the real height1
height1 = 25 ;
2016-04-23 23:33:42 -05:00
for ( const HWND & hwnd : * ( r - > hwnds ) ) {
2015-06-04 22:39:11 -05:00
h = height1 ;
if ( h > height ) // clip to height
h = height ;
2016-04-23 21:23:07 -05:00
uiWindowsEnsureMoveWindowDuringResize ( hwnd , x , y , width , h ) ;
2015-05-21 14:48:16 -05:00
y + = height1 ;
2015-06-04 22:39:11 -05:00
height - = height1 ;
if ( height < = 0 ) // clip to height
break ;
2016-04-22 19:37:28 -05:00
// TODO don't do the above to avoid overlap
// TODO in fact, only do this on add/remove/change labels/etc.
2015-05-21 14:48:16 -05:00
}
}
2016-04-29 13:12:01 -05:00
static void radiobuttonsArrangeChildren ( uiRadioButtons * r )
2015-05-21 14:48:16 -05:00
{
2015-09-02 17:26:48 -05:00
LONG_PTR controlID ;
HWND insertAfter ;
2015-06-04 22:31:43 -05:00
2015-09-02 17:26:48 -05:00
controlID = 100 ;
insertAfter = NULL ;
2016-04-29 13:12:01 -05:00
for ( const HWND & hwnd : * ( r - > hwnds ) )
uiWindowsEnsureAssignControlIDZOrder ( hwnd , & controlID , & insertAfter ) ;
2015-05-30 18:23:05 -05:00
}
2015-08-30 21:08:25 -05:00
void uiRadioButtonsAppend ( uiRadioButtons * r , const char * text )
2015-05-21 14:48:16 -05:00
{
2015-05-30 20:54:52 -05:00
HWND hwnd ;
2015-05-21 14:48:16 -05:00
WCHAR * wtext ;
2015-09-02 17:26:48 -05:00
DWORD groupTabStop ;
// the first radio button gets both WS_GROUP and WS_TABSTOP
// successive radio buttons get *neither*
groupTabStop = 0 ;
2016-04-22 19:37:28 -05:00
if ( r - > hwnds - > size ( ) = = 0 )
2015-09-02 17:26:48 -05:00
groupTabStop = WS_GROUP | WS_TABSTOP ;
2015-05-21 14:48:16 -05:00
wtext = toUTF16 ( text ) ;
2015-08-31 11:33:44 -05:00
hwnd = uiWindowsEnsureCreateControlHWND ( 0 ,
2015-05-21 14:48:16 -05:00
L " button " , wtext ,
2015-09-02 17:26:48 -05:00
BS_RADIOBUTTON | groupTabStop ,
2015-05-30 20:54:52 -05:00
hInstance , NULL ,
TRUE ) ;
2015-06-01 17:06:15 -05:00
uiFree ( wtext ) ;
2016-04-29 16:08:31 -05:00
uiWindowsEnsureSetParentHWND ( hwnd , r - > hwnd ) ;
2015-05-21 14:52:59 -05:00
uiWindowsRegisterWM_COMMANDHandler ( hwnd , onWM_COMMAND , uiControl ( r ) ) ;
2016-04-22 19:37:28 -05:00
r - > hwnds - > push_back ( hwnd ) ;
2016-04-29 13:12:01 -05:00
radiobuttonsArrangeChildren ( r ) ;
2016-04-29 11:20:41 -05:00
uiWindowsControlMinimumSizeChanged ( uiWindowsControl ( r ) ) ;
2015-05-21 14:48:16 -05:00
}
2016-04-29 16:08:31 -05:00
static void onResize ( uiWindowsControl * c )
2016-04-29 13:12:01 -05:00
{
radiobuttonsRelayout ( uiRadioButtons ( c ) ) ;
}
2015-05-21 14:48:16 -05:00
uiRadioButtons * uiNewRadioButtons ( void )
{
2015-08-30 21:08:25 -05:00
uiRadioButtons * r ;
2016-04-29 13:12:01 -05:00
uiWindowsNewControl ( uiRadioButtons , r ) ;
2015-05-21 14:48:16 -05:00
2016-04-29 16:08:31 -05:00
r - > hwnd = uiWindowsMakeContainer ( uiWindowsControl ( r ) , onResize ) ;
2015-05-21 14:48:16 -05:00
2016-04-22 19:37:28 -05:00
r - > hwnds = new std : : vector < HWND > ;
2015-05-21 14:48:16 -05:00
2015-08-30 21:08:25 -05:00
return r ;
2015-05-21 14:48:16 -05:00
}