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-08-30 21:08:25 -05:00
static void onDestroy ( uiRadioButtons * ) ;
2015-08-31 11:33:44 -05:00
uiWindowsDefineControlWithOnDestroy (
uiRadioButtons , // type name
2016-04-23 15:52:53 -05:00
onDestroy ( me ) ; // on destroy
2015-08-31 11:33:44 -05:00
)
2015-05-30 01:14:13 -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 ;
}
2015-08-30 21:08:25 -05:00
static void onDestroy ( uiRadioButtons * r )
2015-05-21 14:48:16 -05:00
{
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 ;
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
2015-08-31 16:50:23 -05:00
static void minimumSize ( uiWindowsControl * c , uiWindowsSizing * d , 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 ;
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 ;
}
2015-08-30 21:08:25 -05:00
* width = uiWindowsDlgUnitsToX ( radiobuttonXFromLeftOfBoxToLeftOfLabel , d - > BaseX ) + maxwid ;
2016-04-23 23:33:42 -05:00
* height = uiWindowsDlgUnitsToY ( radiobuttonHeight , d - > BaseY ) * r - > hwnds - > size ( ) ;
2015-05-21 14:48:16 -05:00
}
2015-08-31 16:50:23 -05:00
static void radiobuttonsRelayout ( uiWindowsControl * c , intmax_t x , intmax_t y , intmax_t width , intmax_t height )
2015-05-21 14:48:16 -05:00
{
2015-09-01 15:10:29 -05:00
uiRadioButtons * r = uiRadioButtons ( c ) ;
uiWindowsSizing * d ;
2015-05-21 14:48:16 -05:00
intmax_t height1 ;
2015-06-04 22:39:11 -05:00
intmax_t h ;
2015-05-21 14:48:16 -05:00
2016-04-23 21:23:07 -05:00
uiWindowsEnsureMoveWindowDuringResize ( r - > hwnd , x , y , width , height ) ;
2015-08-30 21:08:25 -05:00
2015-09-01 15:10:29 -05:00
x = 0 ;
y = 0 ;
d = uiWindowsNewSizing ( r - > hwnd ) ;
height1 = uiWindowsDlgUnitsToY ( radiobuttonHeight , d - > BaseY ) ;
uiWindowsFreeSizing ( d ) ;
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
}
}
2015-09-01 15:10:29 -05:00
// TODO commit enable/disable
2015-05-21 14:48:16 -05:00
2015-09-02 17:26:48 -05:00
static void redoControlIDsZOrder ( 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-23 23:33:42 -05:00
for ( const HWND & hwnd : * ( r - > hwnds ) ) {
2015-09-02 17:26:48 -05:00
uiWindowsEnsureAssignControlIDZOrder ( hwnd , controlID , insertAfter ) ;
controlID + + ;
insertAfter = hwnd ;
2015-06-04 22:31:43 -05:00
}
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 ) ;
2015-09-01 15:10:29 -05:00
uiWindowsEnsureSetParent ( 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 ) ;
2015-09-02 17:26:48 -05:00
redoControlIDsZOrder ( r ) ;
2015-09-01 15:10:29 -05:00
uiWindowsControlQueueRelayout ( uiWindowsControl ( r ) ) ;
2015-05-21 14:48:16 -05:00
}
uiRadioButtons * uiNewRadioButtons ( void )
{
2015-08-30 21:08:25 -05:00
uiRadioButtons * r ;
2016-04-24 16:38:48 -05:00
r = ( uiRadioButtons * ) uiNewControl ( uiRadioButtons ) ;
2015-05-21 14:48:16 -05:00
2015-08-30 21:08:25 -05:00
r - > hwnd = newContainer ( ) ;
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-31 11:33:44 -05:00
uiWindowsFinishNewControl ( r , uiRadioButtons ) ;
2015-08-31 16:50:23 -05:00
uiWindowsControl ( r ) - > Relayout = radiobuttonsRelayout ;
2015-08-31 11:33:44 -05:00
2015-08-30 21:08:25 -05:00
return r ;
2015-05-21 14:48:16 -05:00
}