2014-10-09 09:11:36 -05:00
// 9 october 2014
2015-01-06 21:02:04 -06:00
# include "../wininclude_windows.h"
2014-10-11 10:00:56 -05:00
# include "popover.h"
2014-10-09 09:11:36 -05:00
2014-10-09 09:51:35 -05:00
// #qo LIBS: user32 kernel32 gdi32
2014-10-09 10:01:24 -05:00
// TODO
// - should the parent window appear deactivated?
2014-10-11 10:00:56 -05:00
HWND popoverWindow ;
2014-10-09 10:01:24 -05:00
2014-10-10 09:47:37 -05:00
void xpanic ( char * msg , DWORD err )
{
printf ( " %d | %s \n " , err , msg ) ;
abort ( ) ;
}
2014-10-11 10:00:56 -05:00
popover * p ;
2014-10-10 11:25:14 -05:00
2014-10-09 18:00:58 -05:00
HRGN makePopoverRegion ( HDC dc , LONG width , LONG height )
{
2014-10-11 10:00:56 -05:00
popoverPoint ppt [ 20 ] ;
2014-10-10 10:43:12 -05:00
POINT pt [ 20 ] ;
2014-10-11 10:00:56 -05:00
int i , n ;
2014-10-10 09:47:37 -05:00
HRGN region ;
2014-10-09 18:00:58 -05:00
2014-10-11 10:00:56 -05:00
n = popoverMakeFramePoints ( p , ( intptr_t ) width , ( intptr_t ) height , ppt ) ;
for ( i = 0 ; i < n ; i + + ) {
pt [ i ] . x = ( LONG ) ( ppt [ i ] . x ) ;
pt [ i ] . y = ( LONG ) ( ppt [ i ] . y ) ;
2014-10-10 10:43:12 -05:00
}
2014-10-11 10:00:56 -05:00
if ( BeginPath ( dc ) = = 0 )
xpanic ( " error beginning path for Popover shape " , GetLastError ( ) ) ;
2014-10-10 10:43:12 -05:00
if ( Polyline ( dc , pt , n ) = = 0 )
2014-10-10 10:17:47 -05:00
xpanic ( " error drawing lines in Popover shape " , GetLastError ( ) ) ;
2014-10-10 09:47:37 -05:00
if ( EndPath ( dc ) = = 0 )
xpanic ( " error ending path for Popover shape " , GetLastError ( ) ) ;
region = PathToRegion ( dc ) ;
2014-10-10 10:12:19 -05:00
if ( region = = NULL )
xpanic ( " error converting Popover shape path to region " , GetLastError ( ) ) ;
2014-10-10 09:47:37 -05:00
return region ;
2014-10-09 18:00:58 -05:00
}
2014-10-10 15:56:18 -05:00
# define msgPopoverPrepareLeftRight (WM_APP+50)
# define msgPopoverPrepareTopBottom (WM_APP+51)
2014-10-09 09:51:35 -05:00
LRESULT CALLBACK popoverproc ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
PAINTSTRUCT ps ;
HDC dc ;
HRGN region ;
2014-10-09 13:10:29 -05:00
RECT r ;
2014-10-09 14:16:32 -05:00
LONG width ;
LONG height ;
2014-10-09 18:00:58 -05:00
WINDOWPOS * wp ;
2014-10-10 11:25:14 -05:00
HBRUSH brush ;
2014-10-09 09:51:35 -05:00
switch ( uMsg ) {
2014-10-09 13:10:29 -05:00
case WM_NCPAINT :
2014-10-10 09:47:37 -05:00
if ( GetWindowRect ( hwnd , & r ) = = 0 )
xpanic ( " error getting Popover window rect for shape redraw " , GetLastError ( ) ) ;
2014-10-09 14:16:32 -05:00
width = r . right - r . left ;
height = r . bottom - r . top ;
2014-10-09 18:00:58 -05:00
dc = GetWindowDC ( hwnd ) ;
2014-10-10 10:12:19 -05:00
if ( dc = = NULL )
xpanic ( " error getting Popover window DC for drawing border " , GetLastError ( ) ) ;
2014-10-09 18:00:58 -05:00
region = makePopoverRegion ( dc , width , height ) ;
2014-10-10 20:26:51 -05:00
// don't call FillRgn(); WM_ERASEBKGND seems to do this to the non-client area for us already :S (TODO confirm)
// TODO arrow is black in wine
2014-10-10 11:25:14 -05:00
brush = ( HBRUSH ) GetStockObject ( BLACK_BRUSH ) ;
if ( brush = = NULL )
xpanic ( " error getting Popover border brush " , GetLastError ( ) ) ;
if ( FrameRgn ( dc , region , brush , 1 , 1 ) = = 0 )
2014-10-10 10:12:19 -05:00
xpanic ( " error drawing Popover border " , GetLastError ( ) ) ;
if ( DeleteObject ( region ) = = 0 )
xpanic ( " error deleting Popover shape region " , GetLastError ( ) ) ;
if ( ReleaseDC ( hwnd , dc ) = = 0 )
xpanic ( " error releasing Popover window DC for shape drawing " , GetLastError ( ) ) ;
2014-10-09 09:51:35 -05:00
return 0 ;
2014-10-09 18:00:58 -05:00
case WM_WINDOWPOSCHANGED :
// this must be here; if it's in WM_NCPAINT weird things happen (see http://stackoverflow.com/questions/26288303/why-is-my-client-rectangle-drawing-behaving-bizarrely-pictures-provided-if-i-t)
wp = ( WINDOWPOS * ) lParam ;
if ( ( wp - > flags & SWP_NOSIZE ) = = 0 ) {
dc = GetWindowDC ( hwnd ) ;
2014-10-10 10:12:19 -05:00
if ( dc = = NULL )
xpanic ( " error getting Popover window DC for reshaping " , GetLastError ( ) ) ;
2014-10-09 18:00:58 -05:00
region = makePopoverRegion ( dc , wp - > cx , wp - > cy ) ;
2014-10-10 09:47:37 -05:00
if ( SetWindowRgn ( hwnd , region , TRUE ) = = 0 )
xpanic ( " error setting Popover shape " , GetLastError ( ) ) ;
2014-10-09 18:00:58 -05:00
// don't delete the region; the window manager owns it now
2014-10-10 10:12:19 -05:00
if ( ReleaseDC ( hwnd , dc ) = = 0 )
xpanic ( " error releasing Popover window DC for reshaping " , GetLastError ( ) ) ;
2014-10-09 18:00:58 -05:00
}
break ; // defer to DefWindowProc()
2014-10-09 15:24:07 -05:00
case WM_NCCALCSIZE :
{
RECT * r = ( RECT * ) lParam ;
NCCALCSIZE_PARAMS * np = ( NCCALCSIZE_PARAMS * ) lParam ;
2014-10-11 10:00:56 -05:00
popoverRect pr ;
2014-10-09 15:24:07 -05:00
if ( wParam ! = FALSE )
r = & np - > rgrc [ 0 ] ;
2014-10-11 10:00:56 -05:00
pr . left = ( intptr_t ) ( r - > left ) ;
pr . top = ( intptr_t ) ( r - > top ) ;
pr . right = ( intptr_t ) ( r - > right ) ;
pr . bottom = ( intptr_t ) ( r - > bottom ) ;
popoverWindowSizeToClientSize ( p , & pr ) ;
r - > left = ( LONG ) ( pr . left ) ;
r - > top = ( LONG ) ( pr . top ) ;
r - > right = ( LONG ) ( pr . right ) ;
r - > bottom = ( LONG ) ( pr . bottom ) ;
2014-10-09 15:24:07 -05:00
return 0 ;
}
2014-10-09 13:10:29 -05:00
case WM_PAINT :
2014-10-10 10:12:19 -05:00
dc = BeginPaint ( hwnd , & ps ) ;
2014-10-09 13:10:29 -05:00
GetClientRect ( hwnd , & r ) ;
FillRect ( dc , & r , GetSysColorBrush ( COLOR_ACTIVECAPTION ) ) ;
2014-10-10 11:25:14 -05:00
FrameRect ( dc , & r , GetStockPen ( WHITE_BRUSH ) ) ;
2014-10-09 13:10:29 -05:00
EndPaint ( hwnd , & ps ) ;
2014-10-10 10:12:19 -05:00
return 0 ;
2014-10-10 15:56:18 -05:00
case msgPopoverPrepareLeftRight :
case msgPopoverPrepareTopBottom :
2014-10-10 16:02:33 -05:00
// TODO window edge detection
2014-10-10 15:56:18 -05:00
{
RECT r ;
LONG width = 200 , height = 200 ;
2014-10-11 10:00:56 -05:00
popoverRect control ;
uintptr_t side ;
popoverRect out ;
2014-10-10 15:56:18 -05:00
if ( GetWindowRect ( ( HWND ) wParam , & r ) = = 0 )
xpanic ( " error getting window rect of Popover target " , GetLastError ( ) ) ;
2014-10-11 10:00:56 -05:00
control . left = ( intptr_t ) ( r . left ) ;
control . top = ( intptr_t ) ( r . top ) ;
control . right = ( intptr_t ) ( r . right ) ;
control . bottom = ( intptr_t ) ( r . bottom ) ;
switch ( uMsg ) {
case msgPopoverPrepareLeftRight :
side = popoverPointLeft ;
break ;
case msgPopoverPrepareTopBottom :
side = popoverPointTop ;
break ;
2014-10-10 15:56:18 -05:00
}
2014-10-11 10:00:56 -05:00
out = popoverPointAt ( p , control , ( intptr_t ) width , ( intptr_t ) height , side ) ;
if ( MoveWindow ( hwnd , out . left , out . top , out . right - out . left , out . bottom - out . top , TRUE ) = = 0 )
2014-10-10 15:56:18 -05:00
xpanic ( " error repositioning Popover " , GetLastError ( ) ) ;
}
return 0 ;
2014-10-09 09:51:35 -05:00
}
return DefWindowProcW ( hwnd , uMsg , wParam , lParam ) ;
}
2014-10-10 15:56:18 -05:00
HWND button ;
2014-10-09 09:11:36 -05:00
LRESULT CALLBACK wndproc ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
switch ( uMsg ) {
case WM_COMMAND :
if ( HIWORD ( wParam ) = = BN_CLICKED & & LOWORD ( wParam ) = = 100 ) {
2014-10-11 10:00:56 -05:00
SendMessageW ( popoverWindow , msgPopoverPrepareLeftRight , ( WPARAM ) button , 0 ) ;
ShowWindow ( popoverWindow , SW_SHOW ) ;
UpdateWindow ( popoverWindow ) ;
2014-10-09 09:11:36 -05:00
return 0 ;
}
break ;
case WM_CLOSE :
PostQuitMessage ( 0 ) ;
return 0 ;
}
return DefWindowProcW ( hwnd , uMsg , wParam , lParam ) ;
}
int main ( int argc , char * argv [ ] )
{
WNDCLASSW wc ;
2014-10-10 15:56:18 -05:00
HWND mainwin ;
2014-10-09 09:11:36 -05:00
MSG msg ;
2014-10-11 10:00:56 -05:00
p = popoverDataNew ( NULL ) ;
// TODO null check
2014-10-09 09:11:36 -05:00
ZeroMemory ( & wc , sizeof ( WNDCLASSW ) ) ;
wc . lpszClassName = L " popover " ;
2014-10-09 09:51:35 -05:00
wc . lpfnWndProc = popoverproc ;
2014-10-09 09:11:36 -05:00
wc . hbrBackground = ( HBRUSH ) ( COLOR_BTNFACE + 1 ) ;
wc . style = CS_DROPSHADOW | CS_NOCLOSE ;
if ( RegisterClassW ( & wc ) = = 0 )
abort ( ) ;
2014-10-11 10:00:56 -05:00
popoverWindow = CreateWindowExW ( WS_EX_TOPMOST ,
2014-10-09 09:11:36 -05:00
L " popover " , L " " ,
2014-10-09 09:51:35 -05:00
WS_POPUP ,
2014-10-09 09:11:36 -05:00
0 , 0 , 150 , 100 ,
NULL , NULL , NULL , NULL ) ;
2014-10-11 10:00:56 -05:00
if ( popoverWindow = = NULL )
2014-10-09 09:11:36 -05:00
abort ( ) ;
ZeroMemory ( & wc , sizeof ( WNDCLASSW ) ) ;
wc . lpszClassName = L " mainwin " ;
wc . lpfnWndProc = wndproc ;
wc . hbrBackground = ( HBRUSH ) ( COLOR_BTNFACE + 1 ) ;
if ( RegisterClassW ( & wc ) = = 0 )
abort ( ) ;
mainwin = CreateWindowExW ( 0 ,
L " mainwin " , L " Main Window " ,
WS_OVERLAPPEDWINDOW ,
0 , 0 , 150 , 100 ,
NULL , NULL , NULL , NULL ) ;
if ( mainwin = = NULL )
abort ( ) ;
button = CreateWindowExW ( 0 ,
L " button " , L " Click Me " ,
BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE ,
20 , 20 , 100 , 40 ,
mainwin , ( HMENU ) 100 , NULL , NULL ) ;
if ( button = = NULL )
abort ( ) ;
ShowWindow ( mainwin , SW_SHOWDEFAULT ) ;
if ( UpdateWindow ( mainwin ) = = 0 )
abort ( ) ;
while ( GetMessageW ( & msg , NULL , 0 , 0 ) > 0 ) {
TranslateMessage ( & msg ) ;
DispatchMessageW ( & msg ) ;
}
return 0 ;
}