Gale,
As a first idea I think that we could use FWH functions ScreenWidth() and ScreenHeight() and a timer to control rotation.
I am thinking how to avoid the use of the timer...
Gale,
As a first idea I think that we could use FWH functions ScreenWidth() and ScreenHeight() and a timer to control rotation.
I am thinking how to avoid the use of the timer...
#include "FiveWin.ch"
function Main()
local oWnd
DEFINE WINDOW oWnd
oWnd:bResized = { || MsgBeep() }
ACTIVATE WINDOW oWnd MAXIMIZED
return nili will try it later. just thinking about it, if you want to try it without adding to handleevent then it might be better on paint. i am not sure the dialog/window size changes unless keyboard is visible and sometimes not even then. Windows 7 keyboard undocked does not resize dialog or screen.
Gale,
Then you may change in my example:
oWnd:bPainted = { || MsgBeep() }
thanks
bPainted does get called when you rotate display. bResized does not get called.
I cannot get accurate screen sizes when I use bPainted. screenwidth() and screenheight() are not always correct. Maybe it has something to do with buffer/dispbegin().
One of the things I need to do when screen is rotated is change the dialog/window position and size. This also affects bPainted.
If i modify tDialog with bOnRotate and I check screenwidth() and screenheight() in bOnRotate it returns correct sizes.
#include "fivewin.ch"
#define SM_TABLETPC 86
#define WM_DISPLAYCHANGE 0x007E
#define WM_SETTINGCHANGE WM_WININICHANGE
#ifndef SM_DIGITIZER
#define SM_DIGITIZER 94
#endif
#define SM_CMOUSEBUTTONS 43
static cMsg := ""
static oTimer
static cLog
//----------------------------------------------------------------------------//
function Main()
local oWnd
local oFont
cLog := cFileSetExt( ExeName(), "log" )
FErase( cLog )
DEFINE FONT oFont NAME "Segoe UI" SIZE 0,-30
oWnd := TMyWindow():New()
oWnd:SetColor( CLR_WHITE, CLR_GREEN )
oWnd:bRClicked := { || oWnd:Refresh() }
oWnd:bOnDisplayChange := { || oWnd:Refresh(), 0 }
oWnd:bOnSettingChange := { || WaitRefresh( oWnd ) }
ACTIVATE WINDOW oWnd CENTERED ;
ON PAINT oWnd:SayText( cMsg := DisplayMessage( oWnd ), , , oFont ) ;
ON RESIZE ( oWnd:Refresh() )
RELEASE FONT oFont
if oTimer != nil
oTimer:End()
endif
if File( cLog )
WinExec( "notepad.exe " + cLog )
endif
return nil
//----------------------------------------------------------------------------//
static function WaitRefresh( ownd )
static n := 0
if oTimer == nil
DEFINE TIMER oTimer OF oWnd INTERVAL 400 ;
ACTION ( n++, oWnd:Refresh(), If( n > 4, (oTimer:End(), oTimer := nil, n := 0), nil ) )
ACTIVATE TIMER oTimer
endif
return nil
//----------------------------------------------------------------------------//
static function DisplayMessage( oWnd )
local lPortrait := ScreenWidth() < ScreenHeight()
local lTabletMode := IsTabletMode()
local lTouch := ( GetSysMetrics( SM_DIGITIZER ) > 0 )
cMsg := If( IsWindows10(), If( lTabletMode, "TABLET MODE", "DESKTOP MODE" ) + CRLF, "" )
cMsg += If( lPortrait, "POTRAIT", "LANDSCAPE" ) + CRLF + ;
If( IsZoomed( oWnd:hWnd ), "MAXIMIZED", "NORMAL" ) + " WINDOW" + CRLF + ;
If( lTouch, "", "NO " ) + "TOUCH INPUT" + CRLF + ;
"MOUSE" + If( GetSysMetrics( SM_CMOUSEBUTTONS ) > 0, "", " NOT" ) + " PRESENT"
return cMsg
//----------------------------------------------------------------------------//
CLASS TMyWindow FROM TWindow
CLASSDATA lRegistered
DATA bOnDisplayChange
DATA bOnSettingChange
METHOD HandleEvent( nMsg, nWParam, nLParam )
ENDCLASS
METHOD HandleEvent( nMsg, nWParam, nLParam ) CLASS TMyWindow
do case
case nMsg == WM_DISPLAYCHANGE
if ValType( ::bOnDisplayChange ) == 'B'
return Eval( ::bOnDisplayChange, Self, nWParam, nLParam )
endif
case IsWindows10() .and. nMsg == WM_SETTINGCHANGE
if ValType( ::bOnSettingChange ) == 'B'
return Eval( ::bOnSettingChange, Self, nWParam, nLParam )
endif
endcase
return ::Super:HandleEvent( nMsg, nWParam, nLParam )
//----------------------------------------------------------------------------//
Is the function IsTabletMode() in later vesrion of FWH?
Gale FORd wrote:Is the function IsTabletMode() in later vesrion of FWH?
function IsTabletMode()
local oReg, lTabletMode := .f.
if IsWindows10()
oReg:= TReg32():New( HKEY_CURRENT_USER, "SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell" )
lTabletMode := ( oReg:Get( "TabletMode", 0 ) > 0 )
endif
return lTabletMode#include "fivewin.ch"
#define SM_TABLETPC 86
#define WM_DISPLAYCHANGE 0x007E
#define WM_SETTINGCHANGE WM_WININICHANGE
#ifndef SM_DIGITIZER
#define SM_DIGITIZER 94
#endif
#define SM_CMOUSEBUTTONS 43
static cMsg := ""
static oTimer
static cLog
static lUseWait
//----------------------------------------------------------------------------//
function Main()
local oWnd
local oFont
lUseWait := .t.
cLog := cFileSetExt( ExeName(), "log" )
FErase( cLog )
DEFINE FONT oFont NAME "Segoe UI" SIZE 0,-30
oWnd := TMyWindow():New()
oWnd:SetColor( CLR_WHITE, CLR_GREEN )
oWnd:bRClicked := { || oWnd:Refresh }
oWnd:blClicked := { || ( lUseWait := !luseWait, oWnd:Refresh() ) }
oWnd:bOnDisplayChange := { || WaitReSize( oWnd, 'DispChange' ), 0 }
//oWnd:bOnDisplayChange := { || oWnd:Refresh(), 0 }
oWnd:bOnSettingChange := { || WaitRefresh( oWnd ) }
ACTIVATE WINDOW oWnd CENTERED on INIT WaitReSize( oWnd, 'Init' );
ON PAINT oWnd:SayText( cMsg := DisplayMessage( oWnd ), , , oFont ) ;
ON RESIZE ( oWnd:Refresh() )
RELEASE FONT oFont
if oTimer != nil
oTimer:End()
endif
if File( cLog )
WinExec( "notepad.exe " + cLog )
endif
return nil
//----------------------------------------------------------------------------//
static function WaitRefresh( ownd )
static n := 0
TraceSize( 'WaitRefresh' )
if oTimer == nil
DEFINE TIMER oTimer OF oWnd INTERVAL 400 ;
ACTION ( n++, oWnd:Refresh(), If( n > 4, (oTimer:End(), oTimer := nil, n := 0), nil ) )
ACTIVATE TIMER oTimer
endif
return nil
static function WaitResize( oWnd, cAction )
static n := 0
if lUseWait
if oTimer == nil
DEFINE TIMER oTimer ;
INTERVAL 400 ACTION ( n++, if( n = 1, ReSize( oWnd, cAction ), (oTimer:End(), oTimer := nil, n := 0) ) )
oTimer:Activate()
endif
else
ReSize( oWnd, cAction )
endif
return nil
Static function ReSize( oWnd, cAction )
local nTop, nLeft, nWidth, nHeight
//sysrefresh()
TraceSize( cAction )
nTop := 40
nLeft := 40
nWidth := ScreenWidth() - ( nLeft*2 )
nHeight := ScreenHeight() - ( nTop*2 )
oWnd:Move( nTop, nLeft, nWidth, nHeight )
oWnd:Refresh()
return nil
Static Function TraceSize( cAction )
tracelog( cAction, lUseWait, ScreenWidth(), ScreenHeight(), ScreenWidth() < ScreenHeight() )
return nil
//----------------------------------------------------------------------------//
static function DisplayMessage( oWnd )
local lPortrait := ScreenWidth() < ScreenHeight()
local lTabletMode := IsTabletMode()
local lTouch := ( GetSysMetrics( SM_DIGITIZER ) > 0 )
cMsg := If( IsWindows10(), If( lTabletMode, "TABLET MODE", "DESKTOP MODE" ) + CRLF, "" )
cMsg += If( lPortrait, "POTRAIT", "LANDSCAPE" ) + CRLF + ;
If( IsZoomed( oWnd:hWnd ), "MAXIMIZED", "NORMAL" ) + " WINDOW" + CRLF + ;
If( lTouch, "", "NO " ) + "TOUCH INPUT" + CRLF + ;
"MOUSE" + If( GetSysMetrics( SM_CMOUSEBUTTONS ) > 0, "", " NOT" ) + " PRESENT" + CRLF + ;
If( lUseWait, "USE WAIT", "NO WAIT" ) + CRLF
return cMsg
//----------------------------------------------------------------------------//
CLASS TMyWindow FROM TWindow
CLASSDATA lRegistered
DATA bOnDisplayChange
DATA bOnSettingChange
METHOD HandleEvent( nMsg, nWParam, nLParam )
ENDCLASS
METHOD HandleEvent( nMsg, nWParam, nLParam ) CLASS TMyWindow
do case
case nMsg == WM_DISPLAYCHANGE
if ValType( ::bOnDisplayChange ) == 'B'
return Eval( ::bOnDisplayChange, Self, nWParam, nLParam )
endif
case IsWindows10() .and. nMsg == WM_SETTINGCHANGE
if ValType( ::bOnSettingChange ) == 'B'
return Eval( ::bOnSettingChange, Self, nWParam, nLParam )
endif
endcase
return ::Super:HandleEvent( nMsg, nWParam, nLParam )
//----------------------------------------------------------------------------//
#define HKEY_CURRENT_USER 2147483649
function IsTabletMode()
local oReg, lTabletMode := .f.
if IsWindows10()
oReg:= TReg32():New( HKEY_CURRENT_USER, "SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell" )
lTabletMode := ( oReg:Get( "TabletMode", 0 ) > 0 )
oReg:Close()
endif
return lTabletMode
#define HKEY_LOCAL_MACHINE 2147483650 // 0x80000002
function IsWindows10()
local oReg := TReg32():New( HKEY_LOCAL_MACHINE,;
"SOFTWARE\Microsoft\Windows NT\CurrentVersion",;
.f. )
local cProductName := oReg:Get( "ProductName" )
oReg:Close()
return "Windows 10" $ cProductName// To Check if Keyboard on Screen
if IsWindows10() .or. IsWin8()
lReturn := IsWindowEnabled( hWndInputPanel )
else
lReturn := IsWindowVisible( hWndInputPanel )
endif
// To get the correct screen height. IsKeyBoardVisible() is a function that contains code above. See full examples in code at end of this post.
if IsKeyboardVisible() .and. ( IsWindows10() .or. IsWin8() )
hWndInputPanel := FindWindow("IPTip_Main_Window")
aCoord := GetWndRect( hWndInputPanel )
nHeight := aCoord[ 1 ] - 1
else
nHeight := ScreenHeight()
endif#include "fivewin.ch"
#define SM_TABLETPC 86
#define WM_DISPLAYCHANGE 0x007E
#define WM_SETTINGCHANGE WM_WININICHANGE
#ifndef SM_DIGITIZER
#define SM_DIGITIZER 94
#endif
#define SM_CMOUSEBUTTONS 43
static cMsg := ""
static oTimer
static cLog
static lUseWait
//----------------------------------------------------------------------------//
function Main()
local oWnd
local oFont
lUseWait := .t.
cLog := cFileSetExt( ExeName(), "log" )
FErase( cLog )
DEFINE FONT oFont NAME "Segoe UI" SIZE 0,-30
oWnd := TMyWindow():New()
oWnd:SetColor( CLR_WHITE, CLR_GREEN )
oWnd:bRClicked := { || oWnd:Refresh }
oWnd:blClicked := { || ( lUseWait := !luseWait, oWnd:Refresh() ) }
oWnd:bOnDisplayChange := { || WaitReSize( oWnd, 'DispChange' ), 0 }
//oWnd:bOnDisplayChange := { || oWnd:Refresh(), 0 }
oWnd:bOnSettingChange := { || WaitRefresh( oWnd ) }
ACTIVATE WINDOW oWnd CENTERED on INIT WaitReSize( oWnd, 'Init' );
ON PAINT oWnd:SayText( cMsg := DisplayMessage( oWnd ), , , oFont ) ;
ON RESIZE ( oWnd:Refresh() )
RELEASE FONT oFont
if oTimer != nil
oTimer:End()
endif
if File( cLog )
WinExec( "notepad.exe " + cLog )
endif
return nil
//----------------------------------------------------------------------------//
static function WaitRefresh( ownd )
static n := 0
TraceSize( 'WaitRefresh' )
if oTimer == nil
DEFINE TIMER oTimer OF oWnd INTERVAL 400 ;
ACTION ( n++, oWnd:Refresh(), If( n > 4, (oTimer:End(), oTimer := nil, n := 0), nil ) )
ACTIVATE TIMER oTimer
endif
return nil
//----------------------------------------------------------------------------//
static function DisplayMessage( oWnd )
local lPortrait := ScreenWidth() < ScreenHeight()
local lTabletMode := IsTabletMode()
local lTouch := ( GetSysMetrics( SM_DIGITIZER ) > 0 )
local lKeyboardVisible := IsKeyboardVisible()
cMsg := If( IsWindows10(), If( lTabletMode, "TABLET MODE", "DESKTOP MODE" ) + CRLF, "" )
cMsg += If( lPortrait, "POTRAIT", "LANDSCAPE" ) + CRLF + ;
If( IsZoomed( oWnd:hWnd ), "MAXIMIZED", "NORMAL" ) + " WINDOW" + CRLF + ;
If( lTouch, "", "NO " ) + "TOUCH INPUT" + CRLF + ;
"MOUSE" + If( GetSysMetrics( SM_CMOUSEBUTTONS ) > 0, "", " NOT" ) + " PRESENT" + CRLF + ;
If( lUseWait, "USE WAIT", "NO WAIT" ) + CRLF + ;
If( lKeyboardVisible, "Keyboard Visable", "Keyboard Not Visable" )
return cMsg
//----------------------------------------------------------------------------//
CLASS TMyWindow FROM TWindow
CLASSDATA lRegistered
DATA bOnDisplayChange
DATA bOnSettingChange
METHOD HandleEvent( nMsg, nWParam, nLParam )
ENDCLASS
METHOD HandleEvent( nMsg, nWParam, nLParam ) CLASS TMyWindow
do case
case nMsg == WM_DISPLAYCHANGE
if ValType( ::bOnDisplayChange ) == 'B'
return Eval( ::bOnDisplayChange, Self, nWParam, nLParam )
endif
case IsWindows10() .and. nMsg == WM_SETTINGCHANGE
if ValType( ::bOnSettingChange ) == 'B'
return Eval( ::bOnSettingChange, Self, nWParam, nLParam )
endif
endcase
return ::Super:HandleEvent( nMsg, nWParam, nLParam )
//----------------------------------------------------------------------------//
static function WaitResize( oWnd, cAction )
static n := 0
if lUseWait
if oTimer == nil
DEFINE TIMER oTimer ;
INTERVAL 400 ACTION ( n++, if( n = 1, ReSize( oWnd, cAction ), (oTimer:End(), oTimer := nil, n := 0) ) )
oTimer:Activate()
endif
else
ReSize( oWnd, cAction )
endif
return nil
Static function ReSize( oWnd, cAction )
local nTop, nLeft, nWidth, nHeight
local lIsKeyboardVisible := IsKeyboardVisible()
//sysrefresh()
TraceSize( cAction )
nTop := 40
nLeft := 40
nWidth := ScreenWidth() - ( nLeft*2 )
nHeight := MyScreenHeight() - ( nTop*2 ) //ScreenHeight() - ( nTop*2 )
oWnd:Move( nTop, nLeft, nWidth, nHeight )
oWnd:Refresh()
return nil
Static Function TraceSize( cAction )
tracelog( cAction, if( lUseWait, 'UseWait', 'NotUseWait' ), if( gIsLandscape(), 'LandScape','Portrait' ), ScreenWidth(), ScreenHeight(), MyScreenHeight() )
return nil
#define HKEY_CURRENT_USER 2147483649
function IsTabletMode()
local oReg, lTabletMode := .f.
if IsWindows10()
oReg:= TReg32():New( HKEY_CURRENT_USER, "SOFTWARE\Microsoft\Windows\CurrentVersion\ImmersiveShell" )
lTabletMode := ( oReg:Get( "TabletMode", 0 ) > 0 )
oReg:Close()
endif
return lTabletMode
#define HKEY_LOCAL_MACHINE 2147483650 // 0x80000002
function IsWindows10()
local oReg := TReg32():New( HKEY_LOCAL_MACHINE,;
"SOFTWARE\Microsoft\Windows NT\CurrentVersion",;
.f. )
local cProductName := oReg:Get( "ProductName" )
oReg:Close()
return "Windows 10" $ cProductName
function IsKeyboardVisible()
Local hWndInputPanel
Local aCoord
Local lReturn := .f.
hWndInputPanel := FindWindow("IPTip_Main_Window")
aCoord := GetWndRect( hWndInputPanel )
if hWndInputPanel != 0
if IsWindows10() .or. IsWin8()
lReturn := IsWindowEnabled( hWndInputPanel )
else
lReturn := IsWindowVisible( hWndInputPanel )
endif
tracelog( 'Check Keyboard', if( lUseWait, 'UseWait', 'NotUseWait' ), if( gIsLandscape(), 'LandScape','Portrait' ), ScreenWidth(), ScreenHeight(), aCoord[1], aCoord[2], aCoord[3], aCoord[4], if( lReturn, 'Keyboard Visible', 'Keyboard Not Visible' ) )
endif
return lReturn
function MyScreenHeight()
Local hWndInputPanel
Local aCoord
Local nHeight
Local lReturn := .f.
if IsKeyboardVisible() .and. ( IsWindows10() .or. IsWin8() )
hWndInputPanel := FindWindow("IPTip_Main_Window")
aCoord := GetWndRect( hWndInputPanel )
nHeight := aCoord[ 1 ] - 1
else
nHeight := ScreenHeight()
endif
return nHeight
function gIsLandscape()
return( screenwidth() > screenheight() )The previous post works correctly if the on screen keyboard is docked. Some adjustments may need to be made if keyboard is not docked. Windows 7 looks like it works ok as is.
We would need to find out if keyboard docked on Windows 10 and 8.
Thanks for your input but we are way past that. We are talking about tablets when they rotate, not just starting the keyboard.
If our window/dialog is is in maximized mode, when the tablet is rotated, the window is automatically resized to fit the new orientation. We do not need to recalculate the dimensions of the window. I personally prefer to keep our program code to the minimum and depend more on the system.
Should we resize our window when the OSK popsup?
The normal practice on tablets is to have all windows/dialogs maximized and to keep input controls on the top half of the Window so that OSK, when pops up, does not cover the input controls. It is a good idea to keep input controls on the top and pure display controls on the bottom of the window. Please note that even on desktops, when the user switches from desktop mode to tablet mode, the window gets automatically maximized.
On rotation, we may still need to reposition some controls. For this purpose, we do not depend on ScreenHeight(), ScreenWidth() but on ClientRect of the window. That is accurate. This adjustment can be done in normal On Resize clause.
Note: We are also considering relative coordinate system for controls in future versions. Example:
@ 40, 0.25 GET ....... SIZE 0.50,20 PIXEL OF oWnd. (The meaning should be obvious)
With this change, we need not write specific code in our program in response to changes in modes / rotations.
even if the dialog is maximized screenheight() still has to be calculated to find the control positions so they are visible with on screen keyboard. Then you have popup dialog boxes that are not maximized. The problem of on screen keyboard and screen size will always be important.