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
2016-06-06 18:51:46 -05:00
void ( * onSelected ) ( uiRadioButtons * , void * ) ;
void * onSelectedData ;
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 ) ;
}
2016-06-06 18:51:46 -05:00
( * ( r - > onSelected ) ) ( r , r - > onSelectedData ) ;
2015-05-21 14:48:16 -05:00
* lResult = 0 ;
return TRUE ;
}
2016-06-06 18:51:46 -05:00
static void defaultOnSelected ( uiRadioButtons * r , void * data )
{
// do nothing
}
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 ;
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 ;
intmax_t x , y , width , height ;
2016-05-21 21:17:29 -05:00
int height1 ;
uiWindowsSizing sizing ;
2016-04-29 13:12:01 -05:00
2016-05-21 21:17:29 -05:00
if ( r - > hwnds - > size ( ) = = 0 )
return ;
2016-04-29 13:12:01 -05:00
uiWindowsEnsureGetClientRect ( r - > hwnd , & client ) ;
x = client . left ;
y = client . top ;
width = client . right - client . left ;
2016-05-21 21:17:29 -05:00
height1 = radiobuttonHeight ;
uiWindowsGetSizing ( ( * ( r - > hwnds ) ) [ 0 ] , & sizing ) ;
uiWindowsSizingDlgUnitsToPixels ( & sizing , NULL , & height1 ) ;
height = height1 ;
2016-04-23 23:33:42 -05:00
for ( const HWND & hwnd : * ( r - > hwnds ) ) {
2016-05-21 21:17:29 -05:00
uiWindowsEnsureMoveWindowDuringResize ( hwnd , x , y , width , height ) ;
y + = height ;
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-06-06 18:51:46 -05:00
intmax_t uiRadioButtonsSelected ( uiRadioButtons * r )
{
size_t i ;
for ( i = 0 ; i < r - > hwnds - > size ( ) ; i + + )
if ( SendMessage ( ( * ( r - > hwnds ) ) [ i ] , BM_GETCHECK , 0 , 0 ) = = BST_CHECKED )
return i ;
return - 1 ;
}
void uiRadioButtonsSetSelected ( uiRadioButtons * r , intmax_t n )
{
intmax_t m ;
m = uiRadioButtonsSelected ( r ) ;
if ( m ! = - 1 )
SendMessage ( ( * ( r - > hwnds ) ) [ m ] , BM_SETCHECK , BST_UNCHECKED , 0 ) ;
if ( n ! = - 1 )
SendMessage ( ( * ( r - > hwnds ) ) [ n ] , BM_SETCHECK , BST_CHECKED , 0 ) ;
}
void uiRadioButtonsOnSelected ( uiRadioButtons * r , void ( * f ) ( uiRadioButtons * , void * ) , void * data )
{
r - > onSelected = f ;
r - > onSelectedData = data ;
}
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
2016-06-06 18:51:46 -05:00
uiRadioButtonsOnSelected ( r , defaultOnSelected , NULL ) ;
2015-08-30 21:08:25 -05:00
return r ;
2015-05-21 14:48:16 -05:00
}