2015-12-18 11:00:46 -06:00
// 8 september 2015
2016-04-23 14:39:51 -05:00
# include "uipriv_windows.hpp"
# include "area.hpp"
2015-12-18 11:00:46 -06:00
static HRESULT doPaint ( uiArea * a , ID2D1RenderTarget * rt , RECT * clip )
{
uiAreaHandler * ah = a - > ah ;
uiAreaDrawParams dp ;
COLORREF bgcolorref ;
D2D1_COLOR_F bgcolor ;
2015-12-18 21:06:48 -06:00
D2D1_MATRIX_3X2_F scrollTransform ;
2015-12-18 11:00:46 -06:00
2015-12-18 21:06:48 -06:00
// no need to save or restore the graphics state to reset transformations; it's handled by resetTarget() in draw.c, called during the following
2015-12-18 11:00:46 -06:00
dp . Context = newContext ( rt ) ;
2015-12-18 20:38:27 -06:00
loadAreaSize ( a , rt , & ( dp . AreaWidth ) , & ( dp . AreaHeight ) ) ;
2015-12-18 11:00:46 -06:00
dp . ClipX = clip - > left ;
dp . ClipY = clip - > top ;
dp . ClipWidth = clip - > right - clip - > left ;
dp . ClipHeight = clip - > bottom - clip - > top ;
2015-12-18 21:06:48 -06:00
if ( a - > scrolling ) {
dp . ClipX + = a - > hscrollpos ;
dp . ClipY + = a - > vscrollpos ;
}
2015-12-18 11:00:46 -06:00
2016-04-23 14:39:51 -05:00
rt - > BeginDraw ( ) ;
2015-12-18 11:00:46 -06:00
2015-12-18 21:06:48 -06:00
if ( a - > scrolling ) {
ZeroMemory ( & scrollTransform , sizeof ( D2D1_MATRIX_3X2_F ) ) ;
scrollTransform . _11 = 1 ;
scrollTransform . _22 = 1 ;
2015-12-19 13:43:34 -06:00
// negative because we want nonzero scroll positions to move the drawing area up/left
scrollTransform . _31 = - a - > hscrollpos ;
scrollTransform . _32 = - a - > vscrollpos ;
2016-04-23 14:39:51 -05:00
rt - > SetTransform ( & scrollTransform ) ;
2015-12-18 21:06:48 -06:00
}
// TODO push axis aligned clip
2015-12-18 11:00:46 -06:00
// TODO only clear the clip area
// TODO clear with actual background brush
bgcolorref = GetSysColor ( COLOR_BTNFACE ) ;
bgcolor . r = ( ( float ) GetRValue ( bgcolorref ) ) / 255.0 ;
// due to utter apathy on Microsoft's part, GetGValue() does not work with MSVC's Run-Time Error Checks
// it has not worked since 2008 and they have *never* fixed it
2016-05-13 14:13:41 -05:00
// TODO now that -RTCc has just been deprecated entirely, should we switch back?
2015-12-18 11:00:46 -06:00
bgcolor . g = ( ( float ) ( ( BYTE ) ( ( bgcolorref & 0xFF00 ) > > 8 ) ) ) / 255.0 ;
bgcolor . b = ( ( float ) GetBValue ( bgcolorref ) ) / 255.0 ;
bgcolor . a = 1.0 ;
2016-04-23 14:39:51 -05:00
rt - > Clear ( & bgcolor ) ;
2015-12-18 11:00:46 -06:00
( * ( ah - > Draw ) ) ( ah , a , & dp ) ;
freeContext ( dp . Context ) ;
2015-12-18 21:06:48 -06:00
// TODO pop axis aligned clip
2016-04-23 14:39:51 -05:00
return rt - > EndDraw ( NULL , NULL ) ;
2015-12-18 11:00:46 -06:00
}
static void onWM_PAINT ( uiArea * a )
{
RECT clip ;
HRESULT hr ;
// do not clear the update rect; we do that ourselves in doPaint()
if ( GetUpdateRect ( a - > hwnd , & clip , FALSE ) = = 0 ) {
// set a zero clip rect just in case GetUpdateRect() didn't change clip
clip . left = 0 ;
clip . top = 0 ;
clip . right = 0 ;
clip . bottom = 0 ;
}
2016-05-22 15:16:20 -05:00
hr = doPaint ( a , a - > rt , & clip ) ;
2015-12-18 11:00:46 -06:00
switch ( hr ) {
case S_OK :
if ( ValidateRect ( a - > hwnd , NULL ) = = 0 )
2016-04-23 14:39:51 -05:00
logLastError ( L " error validating rect " ) ;
2015-12-18 11:00:46 -06:00
break ;
case D2DERR_RECREATE_TARGET :
// DON'T validate the rect
// instead, simply drop the render target
// we'll get another WM_PAINT and make the render target again
// TODO would this require us to invalidate the entire client area?
2016-04-23 20:25:56 -05:00
a - > rt - > Release ( ) ; ;
2015-12-18 11:00:46 -06:00
a - > rt = NULL ;
break ;
default :
2016-04-23 14:39:51 -05:00
logHRESULT ( L " error painting " , hr ) ;
2015-12-18 11:00:46 -06:00
}
}
2016-05-22 15:16:20 -05:00
static void onWM_PRINTCLIENT ( uiArea * a , HDC dc )
2015-12-18 11:00:46 -06:00
{
2016-05-22 15:16:20 -05:00
ID2D1DCRenderTarget * rt ;
2015-12-18 11:00:46 -06:00
RECT client ;
2016-05-22 15:16:20 -05:00
HRESULT hr ;
2015-12-18 11:00:46 -06:00
2016-04-29 16:08:31 -05:00
uiWindowsEnsureGetClientRect ( a - > hwnd , & client ) ;
2016-05-22 15:16:20 -05:00
rt = makeHDCRenderTarget ( dc , & client ) ;
hr = doPaint ( a , rt , & client ) ;
if ( hr ! = S_OK )
logHRESULT ( L " error printing uiArea client area " , hr ) ;
rt - > Release ( ) ;
2015-12-18 11:00:46 -06:00
}
BOOL areaDoDraw ( uiArea * a , UINT uMsg , WPARAM wParam , LPARAM lParam , LRESULT * lResult )
{
switch ( uMsg ) {
case WM_PAINT :
onWM_PAINT ( a ) ;
* lResult = 0 ;
return TRUE ;
case WM_PRINTCLIENT :
2016-05-22 15:16:20 -05:00
onWM_PRINTCLIENT ( a , ( HDC ) wParam ) ;
2015-12-18 11:00:46 -06:00
* lResult = 0 ;
return TRUE ;
}
return FALSE ;
}
// TODO only if the render target wasn't just created?
void areaDrawOnResize ( uiArea * a , RECT * newClient )
{
D2D1_SIZE_U size ;
size . width = newClient - > right - newClient - > left ;
size . height = newClient - > bottom - newClient - > top ;
// don't track the error; we'll get that in EndDraw()
// see https://msdn.microsoft.com/en-us/library/windows/desktop/dd370994%28v=vs.85%29.aspx
2016-04-23 20:25:56 -05:00
a - > rt - > Resize ( & size ) ;
2015-12-18 11:00:46 -06:00
// according to Rick Brewster, we must always redraw the entire client area after calling ID2D1RenderTarget::Resize() (see http://stackoverflow.com/a/33222983/3408572)
// we used to have a uiAreaHandler.RedrawOnResize() method to decide this; now you know why we don't anymore
2016-05-17 11:41:41 -05:00
invalidateRect ( a - > hwnd , NULL , TRUE ) ;
2015-12-18 11:00:46 -06:00
}