How can i style my GUI as Aero Glass GUI with AutoIt? - user-interface

How can i get the Aero Glass effect for my Autoit GUI?
I am playing a bit with AutoIt to increase my knowledge about GUI stuff. Usually i just create scripts without the usage of a GUI, but i would like to have a nice looking areo glass GUI when i just start to work with.
I already experiment with WinSetTrans but this is not exactly what i want. It should look more like the image below.
My current code is:
#include <GUIConstants.au3>
$iWidthGui = 450
$iHeightGui = 300
$hGui = GUICreate("Glass GUI", $iWidthGui, $iHeightGui, -1, -1, -1, $WS_EX_TOPMOST)
$cExit = GUICtrlCreateButton("Exit", $iWidthGui / 2 - 50, $iHeightGui / 2 - 15, 100, 30)
GUISetState( #SW_SHOW )
WinSetTrans($hGui, "", 180)
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE, $cExit
GUIDelete($hGui)
ExitLoop
EndSwitch
WEnd
Is it possible with Autoit? How can i do that?

Yes it is possible. This should work at least for Windows 7. I couldn't test the script on a Windows 10 machine.
Improved code:
#include-once
#include <GUIConstants.au3>
Global $iWidthGui = 450
Global $iHeightGui = 300
Global $hGui = GUICreate("Glass GUI", $iWidthGui, $iHeightGui, -1, -1, -1, $WS_EX_TOPMOST)
Global $cExit = GUICtrlCreateButton("Exit", $iWidthGui / 2 - 50, $iHeightGui / 2 - 15, 100, 30)
GUISetState( #SW_SHOW, $hGui )
Func _aeroGlassEffect( $hWnd, $iLeft = #DesktopWidth, $iRight = #DesktopWidth, $iTop = #DesktopWidth, $iBottom = #DesktopWidth )
$hStruct = DllStructCreate( 'int left; int right; int height; int bottom;' )
DllStructSetData( $hStruct, 'left', $iLeft )
DllStructSetData( $hStruct, 'right', $iRight )
DllStructSetData( $hStruct, 'height', $iTop )
DllStructSetData( $hStruct, 'bottom', $iBottom )
GUISetBkColor( '0x000000' )
Return DllCall( 'dwmapi.dll', 'int', 'DwmExtendFrameIntoClientArea', 'hWnd', $hWnd, 'ptr', DllStructGetPtr( $hStruct ) )
EndFunc
_aeroGlassEffect( $hGui )
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE, $cExit
GUIDelete($hGui)
ExitLoop
EndSwitch
WEnd
I switched WinSetTrans() for _aeroGlassEffect(). You can change the function parameters $iLeft, $iRight, $iTop, $iBottom.

Related

Optimizing Tab Control With AutoIT

So I wrote this to simulate a program that would have a start and stop feature, and has a tab design. Right now there is a tab that has a RichEdit object intended to be a running log.
As you can see, after we "start" the program I put just some milliseconds of sleep to simulate running instructions. I created a function to check for requests that would be called on a larger scale randomly throughout code to ping the GUI per say.
#include <GUIConstantsEx.au3>
#include <GuiRichEdit.au3>
#include <WindowsConstants.au3>
Global Const $h_numOfTabs = 2
Global Enum $H_TAB_1, $H_TAB_2, $H_TAB_END
Global $hGui, $h_logRichEdit, $iMsg, $h_tabs, $h_startButton, $h_stopButton
Example()
Func Example()
$hGui = GUICreate("Example (" & StringTrimRight(#ScriptName, StringLen(".exe")) & ")", 400, 550, -1, -1)
; ADD START AND STOP BUTTONS
$h_startButton = GUICtrlCreateButton( "Start", 50, 450 )
$h_stopButton = GUICtrlCreateButton( "Stop", 150, 450 )
$h_tabs = GUICtrlCreateTab( 5, 5, 390,375 )
; LOG TAB
GUICtrlCreateTabItem( "Log" )
$h_logRichEdit = _GUICtrlRichEdit_Create ( $hGui, "", 8, 30, 384, 347, BitOR( $ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL, $ES_READONLY ) )
; STATS TAB
GUICtrlCreateTabItem( "Stats" )
; Close TABS
GUICtrlCreateTabItem( "" )
GUISetState( #SW_SHOW ) ; initialize the gui
While True
CheckRequests()
WEnd
EndFunc ;==>Example
Func Start()
while true
Sleep(100)
CheckRequests()
WEnd
EndFunc
Func Stop()
EndFunc
Func CheckRequests()
$iMsg = GUIGetMsg()
while $iMsg <> 0
Select
Case $iMsg = $GUI_EVENT_CLOSE
_GUICtrlRichEdit_Destroy($h_logRichEdit) ; needed unless script crashes
; GUIDelete() ; is OK too
Exit
Case $iMsg = $h_tabs
Switch GUICtrlRead( $h_tabs )
Case $H_TAB_1
ControlShow( $hGui, "", $h_logRichEdit )
Case Else
ControlHide( $hGui, "", $h_logRichEdit )
EndSwitch
Case $iMsg = $h_startButton
Start()
Case $iMsg = $h_stopButton
Stop()
EndSelect
$iMsg = GUIGetMsg()
WEnd
EndFunc
At about 500ms sleep, the lag when switching tabs is visible.
My question: On a larger scale, is this how we would handle/update things that are specific to a tab while running a larger program? If not, what would be a more efficient way of updating tab specific properties while running a larger overall program.
I have also seen a design recently where all the tabs and related components were their own GUI's but I am not sure the relevance of everything being its own GUI and if it pertains to this question.
Any help or clarification is greatly appreciated, I am new to AutoIT and trying to figure out some do's and dont's as well as efficiency.
#include <GUIConstantsEx.au3>
#include <GuiRichEdit.au3>
#include <WindowsConstants.au3>
Global Const $h_numOfTabs = 2
Global Enum $H_TAB_1, $H_TAB_2, $H_TAB_END
Global $hGui, $h_logRichEdit, $iMsg, $h_tabs, $h_startButton, $h_stopButton
Example()
Func Example()
$hGui = GUICreate("Example (" & StringTrimRight(#ScriptName, StringLen(".exe")) & ")", 400, 550, -1, -1)
; ADD START AND STOP BUTTONS
$h_startButton = GUICtrlCreateButton( "Start", 50, 450 )
$h_stopButton = GUICtrlCreateButton( "Stop", 150, 450 )
$h_tabs = GUICtrlCreateTab( 5, 5, 390,375 )
; LOG TAB
GUICtrlCreateTabItem( "Log" )
$h_logRichEdit = _GUICtrlRichEdit_Create ( $hGui, "", 8, 30, 384, 347, BitOR( $ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL, $ES_READONLY ) )
_GUICtrlRichEdit_AppendText($h_logRichEdit, "{\rtf {Showing \b1 Rich Text \b0}")
; STATS TAB
GUICtrlCreateTabItem( "Stats" )
; Close TABS
GUICtrlCreateTabItem( "" )
; Register Windows message.
GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
GUISetState( #SW_SHOW ) ; initialize the gui
GuiMessageLoop()
EndFunc
Func GuiMessageLoop()
While 1
$iMsg = GUIGetMsg()
Switch $iMsg
Case $GUI_EVENT_CLOSE
_GUICtrlRichEdit_Destroy($h_logRichEdit) ; needed unless script crashes
; GUIDelete() ; is OK too
Exit
Case $h_startButton
Start()
Case $h_stopButton
Stop()
EndSwitch
WEnd
EndFunc
Func Start()
ConsoleWrite('# Sleep' & #CRLF)
Sleep(5000)
ConsoleWrite('# Awake' & #CRLF)
EndFunc
Func Stop()
EndFunc
Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
Local $iLoWord = _WinAPI_LoWord($lParam)
Local $iHiWord = _WinAPI_HiWord($lParam)
ConsoleWrite('- WM_NOTIFY' & ' ' & $iLoWord & ' ' & $iHiWord & #CRLF)
Switch GUICtrlRead( $h_tabs )
Case $H_TAB_1
ControlShow( $hGui, "", $h_logRichEdit )
Case Else
ControlHide( $hGui, "", $h_logRichEdit )
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc
Try this example. It uses GuiRegisterMessage to capture
WM_NOTIFY Windows messages. WM_NOTIFY is not an ideal
message code for this, though have not found something
more suitable for only changing Tabs.
The code to hide and show the Rich Edit control has been
moved into the WM_NOTIFY function so that each time a
message is received, the Tab hide and show code executes.
ConsoleWrite is used to show what the events of interest
are doing during testing. If your editor has a output
console pane, then you may be able to view the writes to
the console pane.
If an event such as function Start takes a long time,
then multi-processing may help to allow the Gui to
remain responsive with the message loop.
Want a do don't, avoid (cyclic) recursive function
calls and avoid getting trapped in loops.
Additional References:
Windows Message Codes
AutoIt Wiki about Tabs

Button at the end of array in AutoIT

I am working on a program that pulls data from AD via a linked table in SQL and lets the user copy an email address to the clipboard. I am using an array to dynamically display a button beside each row. The problem is that, when I try and put labels or buttons inside the for loop, they don't show up. Is it just that I'm doing it wrong. My code is as follows:
#include <GUIConstantsEx.au3>
#include <mssql.au3>
#include <MsgBoxConstants.au3>
#include <Array.au3>
#include <WindowsConstants.au3>
global $title = "E-Mail address lookup"
global $sqlCon = _MSSQL_Con("server", "user", "Directory3=", "password")
global $name = InputBox($title,"Please type the name of the person you wish to find")
global $result = _MSSQL_GetRecord($sqlCon, "autoit_view","*", "WHERE cn LIKE '%" & StringStripWS($name,3) & "%'")
if StringLen(StringStripWS($name,3)) < 1 then
MsgBox(0, $title, "Name cannot be empty")
Else
Global $ControlID = GUICreate($title, 530, 500)
GUISetState(#SW_SHOW)
Local $iOldOpt = Opt("GUICoordMode", 2)
GUICtrlCreateLabel(" ", 0, 0, 80)
GUICtrlCreateLabel("E-Mail Address", 20, -1, 100)
GUICtrlCreateLabel("Name", 20, -1, 50)
GUICtrlCreateLabel("Department", 20, -1, 100)
GUICtrlCreateLabel("Telephone Number", 20, -1, 200)
for $i = 1 To UBound($result) Step 1
GUICtrlCreateButton("Copy", 0, $i, 30, 20)
Next
GUISetState()
While 1
Global $Msg = GUIGetMsg()
Switch $Msg
Case -3, $ControlID
Exit
EndSwitch
WEnd
EndIf
I would have expected one button to show up on a new line on every iteration of the loop
I recommend to use another mode:
#include <GUIConstantsEx.au3>
;~ #include <mssql.au3>
#include <MsgBoxConstants.au3>
#include <Array.au3>
#include <WindowsConstants.au3>
Global $title = "E-Mail address lookup"
;~ global $sqlCon = _MSSQL_Con("server", "user", "Directory3=", "password")
;~ global $name = InputBox($title,"Please type the name of the person you wish to find")
;~ global $result = _MSSQL_GetRecord($sqlCon, "autoit_view","*", "WHERE cn LIKE '%" & StringStripWS($name,3) & "%'")
Global $result = StringSplit('1,2,3,4,5,6,7,8', ',')
;~ if StringLen(StringStripWS($name,3)) < 1 then
;~ MsgBox(0, $title, "Name cannot be empty")
;~ Else
;~ _ArrayDisplay($result)
Global $ControlID = GUICreate($title, 530, 500)
;~ Local $iOldOpt = Opt("GUICoordMode", 2)
GUICtrlCreateLabel(" ", 0, 0, 80)
GUICtrlCreateLabel("E-Mail Address", 20, -1, 100)
GUICtrlCreateLabel("Name", 20, -1, 50)
GUICtrlCreateLabel("Department", 20, -1, 100)
GUICtrlCreateLabel("Telephone Number", 20, -1, 200)
For $i = 1 To UBound($result) - 1
GUICtrlCreateButton("Copy", 20, $i * 20, 350, 20)
Next
GUISetState()
While 1
$Msg = GUIGetMsg()
Switch $Msg
Case -3, $ControlID
Exit
EndSwitch
WEnd

Improper width and height for second monitor from GetMonitorInfo and GetDeviceCaps

I am trying to get the top left x,y and bottom right x,y. And calculat the width and height of displays.
My secondary monitor is 1920x1080 as seen in my display settings screenshot:
I am getting the monitor dimensions in two ways. The code below is js-ctypes but I simplified out all the error checking and other ctypes stuff and tried to make it look like c. But this is a winapi issue not ctypes hence I didn't tag the topic with it.
First approach:
cPoint = POINT();
GetCursorPos(&cPoint);
cMon = MonitorFromPoint(cPoint, MONITOR_DEFAULTTONEAREST);
cMonInfo = MONITORINFOEX();
cMonInfo.cbSize = MONITORINFOEX.size;
GetMonitorInfo(cMon, &cMonInfo);
lpszDriver = null;
lpszDevice = cMonInfo.szDevice;
xTopLeft = cMonInfo.rcMonitor.left;
yTopLeft = cMonInfo.rcMonitor.top;
nWidth = cMonInfo.rcMonitor.right - xTopLeft;
nHeight = cMonInfo.rcMonitor.bottom - yTopLeft;
This is giving me a rect of the following:
_RECT(-1920, -1080, -640, -360)
Doing right - left gives 1280
Doing bottom - top gives 720
The dimensions are definitely wrong. It should have been width of 1920 and height of 1080.
I then try the second method:
hdcScreen = CreateDC(lpszDriver, lpszDevice, null, null);
nWidth = GetDeviceCaps(hdcScreen, HORZRES);
nHeight = GetDeviceCaps(hdcScreen, VERTRES);
This gives me the same thing, width of 1280 and height of 720. My mind is boggled! How can I get 1920x1080?
This same method gives me correct dimensions for my primary monitor, so I am very confused.
EDIT
I just now tried a third method, and still same issues:
var jsMonitorEnumProc = function(hMonitor, hdcMonitor, lprcMonitor, dwData) {
xTopLeft = lprcMonitor.contents.left;
yTopLeft = lprcMonitor.contents.top;
nWidth = lprcMonitor.contents.right - xTopLeft;
nHeight = lprcMonitor.contents.bottom - yTopLeft;
return true;
}
EnumDisplayMonitors(null, null, jsMonitorEnumProc, 0);
This gives me rects of the following:
_RECT(0, 0, 1280, 1024)
_RECT(-1920, -1080, -640, -360)
The first one is my primary monitor and we see doing bottom - top gives 1280 and right - left gives 1024 which is correct my primary monitor is 1280 x 1024.
But the second monitor again is -360 - -1080 for 720 height and -640 - -1920 for 1280 width. I am using this to take screenshots of all the monitors and second ones is coming out clipped.
In my non-dpi aware app 32bit Firefox on Win 8.1 64bit, I was able to get the proper dimensions by using EnumDisplaySettings using the DISPLAY_DEVICE struct of size 220.
js-ctypes:
// start - get all monitor resolutions
var iDevNum = -1;
while (true) {
iDevNum++;
var lpDisplayDevice = ostypes.TYPE.DISPLAY_DEVICE();
lpDisplayDevice.cb = ostypes.TYPE.DISPLAY_DEVICE.size;
var rez_EnumDisplayDevices = ostypes.API('EnumDisplayDevices')(null, iDevNum, lpDisplayDevice.address(), 0);
//console.info('rez_EnumDisplayDevices:', rez_EnumDisplayDevices.toString(), uneval(rez_EnumDisplayDevices), cutils.jscGetDeepest(rez_EnumDisplayDevices));
if (cutils.jscEqual(rez_EnumDisplayDevices, 0)) { // ctypes.winLastError != 0
// iDevNum is greater than the largest device index.
break;
}
console.info('lpDisplayDevice.DeviceName:', lpDisplayDevice.DeviceName.readString()); // "\\.\DISPLAY1" till "\\.\DISPLAY4"
if (lpDisplayDevice.StateFlags & ostypes.CONST.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) {
console.log('is monitor');
var dm = ostypes.TYPE.DEVMODE(); // SIZEOF_DEVMODE = 148
console.info('dm.size:', ostypes.TYPE.DEVMODE.size);
//dm.dmFields = ostypes.CONST.DM_PELSWIDTH;
//dm.dmSize = ostypes.TYPE.DEVMODE.size;
console.log('iDevNum:', iDevNum, lpDisplayDevice.DeviceName.readString());
var rez_EnumDisplaySettings = ostypes.API('EnumDisplaySettings')(lpDisplayDevice.DeviceName, ostypes.CONST.ENUM_CURRENT_SETTINGS, dm.address());
//console.info('rez_EnumDisplaySettings:', rez_EnumDisplaySettings.toString(), uneval(rez_EnumDisplaySettings), cutils.jscGetDeepest(rez_EnumDisplaySettings));
//console.info('dm:', dm.toString());
collMonInfos.push({
x: parseInt(cutils.jscGetDeepest(dm.u.dmPosition.x)),
y: parseInt(cutils.jscGetDeepest(dm.u.dmPosition.y)),
w: parseInt(cutils.jscGetDeepest(dm.dmPelsWidth)),
h: parseInt(cutils.jscGetDeepest(dm.dmPelsHeight)),
screenshot: null, // for winnt, each collMonInfos entry has screenshot data
otherInfo: {
nBPP: parseInt(cutils.jscGetDeepest(dm.dmBitsPerPel)),
lpszDriver: null,
lpszDevice: lpDisplayDevice.DeviceName
}
});
}
}
// end - get all monitor resolutions

AutoIT script - Compare Paint's Rotated Image with GDI's rotated image

I have an image and rotate it with both MS Paint and GDI. I want to show that the rotated image from both methods are the same.
Here is the code I have to rotate image with GDI
#include <GDIPlus.au3>
_GDIPlus_Startup()
$hImage1 = _GDIPlus_ImageLoadFromFile(#ScriptDir & "\Picture.gif")
$hGraphic1 = _GDIPlus_ImageGetGraphicsContext($hImage1)
$hImage2 = _GDIPlus_BitmapCreateFromGraphics(_GDIPlus_ImageGetWidth($hImage1), _GDIPlus_ImageGetHeight($hImage1), $hGraphic1)
$hGraphic2 = _GDIPlus_ImageGetGraphicsContext($hImage2)
$matrix = _GDIPlus_MatrixCreate()
_GDIPlus_MatrixRotate($matrix,90)
_GDIPlus_GraphicsSetTransform($hGraphic2, $matrix)
_GDIPlus_GraphicsDrawImage($hGraphic2, $hImage1, 0, -590)
_GDIPlus_ImageSaveToFile($hImage2, #ScriptDir & "\out.gif")
_GDIPlus_MatrixDispose($matrix)
_GDIPlus_GraphicsDispose($hGraphic1)
_GDIPlus_GraphicsDispose($hGraphic2)
_GDIPlus_ImageDispose($hImage1)
_GDIPlus_ImageDispose($hImage2)
_GDIPlus_ShutDown ()
Then I used this code to compare 2 images:
$bm1 = _GDIPlus_ImageLoadFromFile(#ScriptDir & "\Picture1.gif")
$bm2 = _GDIPlus_ImageLoadFromFile(#ScriptDir & "\out.gif")
if ComparePicture($bm1, $bm2) == True Then
MsgBox(0, "Test result", "Same image!")
Else
MsgBox(0, "Test result", "Different image!")
EndIf
_GDIPlus_ImageDispose($bm1)
_GDIPlus_ImageDispose($bm2)
_GDIPlus_Shutdown()
Func ComparePicture($bm1, $bm2)
$Bm1W = _GDIPlus_ImageGetWidth($bm1)
$Bm1H = _GDIPlus_ImageGetHeight($bm1)
$BitmapData1 = _GDIPlus_BitmapLockBits($bm1, 0, 0, $Bm1W, $Bm1H, $GDIP_ILMREAD, $GDIP_PXF08INDEXED )
$Stride = DllStructGetData($BitmapData1, "Stride")
$Scan0 = DllStructGetData($BitmapData1, "Scan0")
$ptr1 = $Scan0
$size1 = ($Bm1H - 1) * $Stride + ($Bm1W - 1) * 4
$Bm2W = _GDIPlus_ImageGetWidth($bm2)
$Bm2H = _GDIPlus_ImageGetHeight($bm2)
$BitmapData2 = _GDIPlus_BitmapLockBits($bm2, 0, 0, $Bm2W, $Bm2H, $GDIP_ILMREAD, $GDIP_PXF08INDEXED)
$Stride = DllStructGetData($BitmapData2, "Stride")
$Scan0 = DllStructGetData($BitmapData2, "Scan0")
$ptr2 = $Scan0
$size2 = ($Bm2H - 1) * $Stride + ($Bm2W - 1) * 4
$smallest = $size1
If $size2 < $smallest Then $smallest = $size2
$call = DllCall("msvcrt.dll", "int:cdecl", "memcmp", "ptr", $ptr1, "ptr", $ptr2, "int", $smallest)
_GDIPlus_BitmapUnlockBits($bm1, $BitmapData1)
_GDIPlus_BitmapUnlockBits($bm2, $BitmapData2)
Return ($call[0]=0)
EndFunc
I tried changing the file type, color depth, etc. but I could not get the code to show that they are the same. When I do not rotate the picture i.e
_GDIPlus_MatrixRotate($matrix,0)
then it recognize the same image. When I rotate right 90, it doesn't. Does anyone knows what might be going on?
Thanks
For reference, this question has also been asked on the AutoIt forums here.
I think $GDIP_PXF08INDEXED is modifying the images differently. Try it without setting it and it should work.
Furthermore, you can use this code to flip the image:
$hImage1 = _GDIPlus_ImageLoadFromFile(#ScriptDir & "\Picture1.gif")
_GDIPlus_ImageRotateFlip($hImage1, 1) ;90°
_GDIPlus_ImageSaveToFile($hImage1, #ScriptDir & "\out.gif")
_GDIPlus_ImageDispose($hImage1)
Br,
UEZ

WindowEx: setting the background color to transparent

I'm using the following code:
#include <WinAPI.au3>
#include <WindowsConstants.au3>
Global Const $WC_LINK = "SysLink"
Global Const $WC_LINKA = $WC_LINK
Global Const $WC_LINKW = $WC_LINK
$g_hLink = _WinAPI_CreateWindowEx(0, $WC_LINK, _
'Test, [url="http://www.microsoft.com"]click here[/url], [url="http://www.microsoft.com"]here[/url] or [url=""]here[/url]', _
BitOR($WS_VISIBLE, $WS_CHILD, $WS_TABSTOP), _
10, 10, 300, 60, $Form2 _
)
GUIRegisterMsg($WM_NOTIFY, "MY_LINK_NOTIFY")
Func MY_LINK_NOTIFY($hWnd, $Msg, $wParam, $lParam)
Local Const $tagNMLINK = $tagNMHDR & ";" & "UINT mask; int iLink; UINT state; UINT stateMask; WCHAR szID[48]; WCHAR szUrl[2083];"
Local $NMHDR = DllStructCreate($tagNMHDR, $lParam)
Local $hwndFrom = DllStructGetData($NMHDR, "hwndFrom");
Switch $hwndFrom
Case $g_hLink
Switch DllStructGetData($NMHDR, "code")
Case $NM_CLICK
ContinueCase
Case $NM_RETURN
$NMHDR = DllStructCreate($tagNMLINK, $lParam)
Local $iLink = DllStructGetData($NMHDR, "iLink")
Local $szURL = DllStructGetData($NMHDR, "szURL")
Local $szID = DllStructGetData($NMHDR, "szID")
If $szURL <> "" Then
ShellExecute($szURL, "", "", "open", #SW_SHOW);
EndIf
EndSwitch
EndSwitch
EndFunc
To make my syslinks clickable:
The problem is that I want it to display only the text... and set this white/gray background to transparent.
How can I do this?
It seems that it's impossible.
There is the LWS_TRANSPARENT style, but it doesn't make SysLink transparent, it just set its background color to the window background color.
Also, SysLink supports the WM_CTLCOLORSTATIC message, but you can't make background color transparent with it.

Resources