text: // 20 may 2015
  #include "uipriv_windows.hpp"
  
  // desired behavior:
  // - tab moves between the radio buttons and the adjacent controls
  // - arrow keys navigate between radio buttons
  // - 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)
  // - clicking on a radio button draws a focus rect (TODO)
  
  struct uiRadioButtons {
  	uiWindowsControl c;
  	HWND hwnd;					// of the container
  	std::vector<HWND> *hwnds;		// of the buttons
  };
  
  static BOOL onWM_COMMAND(uiControl *c, HWND clicked, WORD code, LRESULT *lResult)
  {
  	uiRadioButtons *r = uiRadioButtons(c);
  	WPARAM check;
  	uintmax_t i;
  
  	if (code != BN_CLICKED)
  		return FALSE;
  	for (const HWND &hwnd : *(r->hwnds)) {
  		check = BST_UNCHECKED;
  		if (clicked == hwnd)
  			check = BST_CHECKED;
  		SendMessage(hwnd, BM_SETCHECK, check, 0);
  	}
  	*lResult = 0;
  	return TRUE;
  }
  
  static void uiRadioButtonsDestroy(uiControl *c)
  {
  	uiRadioButtons *r = uiRadioButtons(c);
  
  	for (const HWND &hwnd : *(r->hwnds)) {
  		uiWindowsUnregisterWM_COMMANDHandler(hwnd);
  		uiWindowsEnsureDestroyWindow(hwnd);
  	}
  	delete r->hwnds;
  	uiWindowsEnsureDestroyWindow(r->hwnd);
  	uiFreeControl(uiControl(r));
  }
  
  // TODO SyncEnableState
  uiWindowsControlAllDefaultsExceptDestroy(uiRadioButtons)
  
  // from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
  #define radiobuttonHeight 10
  // from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx
  #define radiobuttonXFromLeftOfBoxToLeftOfLabel 12
  
  static void uiRadioButtonsMinimumSize(uiWindowsControl *c, intmax_t *width, intmax_t *height)
  {
  	uiRadioButtons *r = uiRadioButtons(c);
  	intmax_t wid, maxwid;
  	uiWindowsSizing sizing;
  	int x, y;
  
  	if (r->hwnds->size() == 0) {
  		*width = 0;
  		*height = 0;
  		return;
  	}
  	maxwid = 0;
  	for (const HWND &hwnd : *(r->hwnds)) {
  		wid = uiWindowsWindowTextWidth(hwnd);
  		if (maxwid < wid)
  			maxwid = wid;
  	}
  
  	x = radiobuttonXFromLeftOfBoxToLeftOfLabel;
  	y = radiobuttonHeight;
  	uiWindowsGetSizing((*(r->hwnds))[0], &sizing);
  	uiWindowsSizingDlgUnitsToPixels(&sizing, &x, &y);
  
  	*width = x + maxwid;
  	*height = y * r->hwnds->size();
  }
  
  static void radiobuttonsRelayout(uiRadioButtons *r)
  {
  	RECT client;
  	intmax_t x, y, width, height;
  	int height1;
  	uiWindowsSizing sizing;
  
  	if (r->hwnds->size() == 0)
  		return;
  	uiWindowsEnsureGetClientRect(r->hwnd, &client);
  	x = client.left;
  	y = client.top;
  	width = client.right - client.left;
  	height1 = radiobuttonHeight;
  	uiWindowsGetSizing((*(r->hwnds))[0], &sizing);
  	uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &height1);
  	height = height1;
  	for (const HWND &hwnd : *(r->hwnds)) {
  		uiWindowsEnsureMoveWindowDuringResize(hwnd, x, y, width, height);
  		y += height;
  	}
  }
  
  static void radiobuttonsArrangeChildren(uiRadioButtons *r)
  {
  	LONG_PTR controlID;
  	HWND insertAfter;
  
  	controlID = 100;
  	insertAfter = NULL;
  	for (const HWND &hwnd : *(r->hwnds))
  		uiWindowsEnsureAssignControlIDZOrder(hwnd, &controlID, &insertAfter);
  }
  
  void uiRadioButtonsAppend(uiRadioButtons *r, const char *text)
  {
  	HWND hwnd;
  	WCHAR *wtext;
  	DWORD groupTabStop;
  
  	// the first radio button gets both WS_GROUP and WS_TABSTOP
  	// successive radio buttons get *neither*
  	groupTabStop = 0;
  	if (r->hwnds->size() == 0)
  		groupTabStop = WS_GROUP | WS_TABSTOP;
  
  	wtext = toUTF16(text);
  	hwnd = uiWindowsEnsureCreateControlHWND(0,
  		L"button", wtext,
  		BS_RADIOBUTTON | groupTabStop,
  		hInstance, NULL,
  		TRUE);
  	uiFree(wtext);
  	uiWindowsEnsureSetParentHWND(hwnd, r->hwnd);
  	uiWindowsRegisterWM_COMMANDHandler(hwnd, onWM_COMMAND, uiControl(r));
  	r->hwnds->push_back(hwnd);
  	radiobuttonsArrangeChildren(r);
  	uiWindowsControlMinimumSizeChanged(uiWindowsControl(r));
  }
  
  static void onResize(uiWindowsControl *c)
  {
  	radiobuttonsRelayout(uiRadioButtons(c));
  }
  
  uiRadioButtons *uiNewRadioButtons(void)
  {
  	uiRadioButtons *r;
  
  	uiWindowsNewControl(uiRadioButtons, r);
  
  	r->hwnd = uiWindowsMakeContainer(uiWindowsControl(r), onResize);
  
  	r->hwnds = new std::vector<HWND>;
  
  	return r;
  }
  