Jump to content
Sign in to follow this  
0Ethan0

How to achieve a responsive GUI while running a function with a loop?

Recommended Posts

Ahoy Autoit Community!

After many trials and errors I am unable to solve a problem I am facing and would appreciate any kind of input or better yet a solution :)

The Premise: An embeded slideshow viewer that runs after double-clicking an item in a ListView (each item will generate a different slideshow images).

The Setup: GUI with a ListView Control and a simple exit button.

The Issue: Once double clicked the slide plays however the GUI "locks"/non responsive until the slide is over. Same thing if I click on the "Test" button.

The Culprit: I believe since it's in the images loop it can't accept any other commands until that loop is over.

The Wish: I want to be able to use the GUI functions (selecting other items, clicking on button etc.) while the slideshow plays.

The Code (stripped and simplified as much as I could):

#include <GuiListView.au3>
#include <File.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1)

HotKeySet("{Esc}", "_Exit")

Global $c=0
Global $ssGDI[3], $ssGraphic[2], $ssImage
Global Const $bg_color = "000000"
Global Const $ssW = 480, $ssH = 320
Global $aFiles = _FileListToArrayRec("d:\testStage\", "*.jpg;*.png;*.bmp;*.gif;*.JPG;*.PNG;*.BMP;*.GIF", $FLTAR_FILES, $FLTAR_NORECUR ,$FLTAR_SORT ,$FLTAR_FULLPATH )


$guiW = 1200
$guiH = 726
$mainWindow = GUICreate("Slideshow Viewer", $guiW, $guiH, -1, -1, $WS_POPUP)
$Button1 = GUICtrlCreateButton("Exit", 0, 0, 50, 50)
GUICtrlSetOnEvent($Button1, "_Exit")
$Button1 = GUICtrlCreateButton("Test", 60, 0, 50, 50)
GUICtrlSetOnEvent($Button1, "Test")


Global $ListView = GUICtrlCreateListView("Entry Name|Category", 5, 75, 195, 280)
_GUICtrlListView_SetColumnWidth ($ListView, 0, 100)
_GUICtrlListView_SetColumnWidth ($ListView, 1, 100)
GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES)
GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_FULLROWSELECT, $LVS_EX_FULLROWSELECT)
GUICtrlCreateListViewItem("Name 1|Category 1", $ListView)
GUICtrlCreateListViewItem("Name 2|Category 2", $ListView)

screenshotWidgetInit($ssW,$ssH, 690, 100)
GUISetState(@SW_SHOW, $mainWindow)

GUIRegisterMsg($WM_NOTIFY, "WM_Notify_Events")

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            _Exit()
    EndSwitch
WEnd

Func Test()
    For $k = 1 To UBound($aFiles) - 1
        screenshotWidgetTransition($aFiles[$k])
    Next
EndFunc

Func ListView_Click()
    ConsoleWrite("Left Click")
EndFunc

Func ListView_DoubleClick()
    ConsoleWrite("Double Left Click")
    Test()
EndFunc

Func WM_Notify_Events($hWndGUI, $MsgID, $wParam, $lParam)
    #forceref $hWndGUI, $MsgID, $wParam
    Local $tagNMHDR, $event, $hwndFrom, $code
    $tagNMHDR = DllStructCreate("int;int;int", $lParam)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3)
    Select
    Case $wParam = $ListView
        Select
            Case $event = $NM_CLICK
                ListView_Click ()
            Case $event = $NM_DBLCLK
                ListView_DoubleClick ()
            EndSelect
    EndSelect
    Return $GUI_RUNDEFMSG
EndFunc

Func screenshotWidgetTransition($image, $delay = 0, $speed = 1, $sleep = 2000)
    Local $a, $d = $c, $iX, $iY
    $ssImage = _GDIPlus_ImageLoadFromFile($image)
    $iX = _GDIPlus_ImageGetWidth($ssImage)
    $iY = _GDIPlus_ImageGetHeight($ssImage)

    $FDesktop=$ssH/$ssW
    $Fact =1
    If $iX > $ssW And $FDesktop > ($iY/$iX) Then
        $Fact=$ssW/$iX
    ElseIf $iY > $ssH Then
        $Fact=$ssH/$iY
    EndIf
    $H1 = Round(($Fact * $iY),0)
    $W1 = Round(($Fact * $iX),0)

    _GDIPlus_GraphicsDrawImageRect($ssGraphic[$d], $ssImage,($ssW - $W1)/2, ($ssH - $H1) / 2,$W1,$H1)

    WinSetTrans($ssGDI[$d], "", 0)
    WinSetOnTop($ssGDI[$d], "", 1)
    For $a = 0 To 254 Step $speed
        WinSetTrans($ssGDI[$d], "", $a)
        Sleep($delay)
    Next
    WinSetTrans($ssGDI[$d], "", 254)
    WinSetOnTop($ssGDI[Not ($d)], "", 0)
    WinSetTrans($ssGDI[Not ($d)], "", 0)
    _GDIPlus_GraphicsClear($ssGraphic[Not ($d)])
    $c = 1 - $d

    _GDIPlus_ImageDispose ($ssImage) ; very important to realease the pics
    Sleep($sleep)
EndFunc   ;==>screenshotWidgetTransition

Func screenshotWidgetInit($ssW,$ssH,$ssX,$ssY)
    $ssGDI[2] = GUICreate("", $ssW, $ssH, $ssX, $ssY, $WS_POPUP, $WS_EX_MDICHILD, $mainWindow)
    $ssGDI[0] = GUICreate("", $ssW, $ssH, 3, 3, $WS_POPUP, $WS_EX_MDICHILD, $ssGDI[2])
    $ssGDI[1] = GUICreate("", $ssW, $ssH, 3, 3, $WS_POPUP, $WS_EX_MDICHILD, $ssGDI[2])
;    GUISetBkColor("0x" & $bg_color, $ssGDI[2])
    GUISetState(@SW_SHOW, $ssGDI[2])
    GUISetState(@SW_SHOW, $ssGDI[0])
    GUISetState(@SW_SHOW, $ssGDI[1])
    WinSetTrans($ssGDI[0], "", 0)
    WinSetTrans($ssGDI[1], "", 0)
    _GDIPlus_Startup()
    $ssGraphic[0] = _GDIPlus_GraphicsCreateFromHWND($ssGDI[0])
    $ssGraphic[1] = _GDIPlus_GraphicsCreateFromHWND($ssGDI[1])
    _GDIPlus_GraphicsClear($ssGraphic[0], "0xFF" & $bg_color)
    _GDIPlus_GraphicsClear($ssGraphic[1], "0xFF" & $bg_color)
EndFunc   ;==>screenshotWidgetInit

Func _Exit()
    _GDIPlus_ImageDispose($ssImage)
    _GDIPlus_GraphicsDispose($ssGraphic[0])
    _GDIPlus_GraphicsDispose($ssGraphic[1])
    GUIDelete($ssGDI[0])
    GUIDelete($ssGDI[1])
    GUIDelete($ssGDI[2])
    _GDIPlus_Shutdown()
    Exit
EndFunc   ;==>_Exit

I hope someone can shed light on this; perhaps a different approach is needed?

Thank you in advance!

P.S.
The script is patched from different scripts of different users in the forum - thank you again users! :)

Edited by 0Ethan0

Share this post


Link to post
Share on other sites

You have some blocking function in it like sleep.
Also Guioneventmode give some problem in your case.

I fixed it, see the code.

#include <GuiListView.au3>
#include <File.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

HotKeySet("{Esc}", "_Exit")

Global $c=0
Global $ssGDI[3], $ssGraphic[2], $ssImage
Global Const $bg_color = "000000"
Global Const $ssW = 480, $ssH = 320
Global $aFiles = _FileListToArrayRec("d:\testStage\", "*.jpg;*.png;*.bmp;*.gif;*.JPG;*.PNG;*.BMP;*.GIF", $FLTAR_FILES, $FLTAR_NORECUR ,$FLTAR_SORT ,$FLTAR_FULLPATH )


$guiW = 1200
$guiH = 726
$mainWindow = GUICreate("Slideshow Viewer", $guiW, $guiH, -1, -1, $WS_POPUP)
$Button1 = GUICtrlCreateButton("Exit", 0, 0, 50, 50)
$Button2 = GUICtrlCreateButton("Test", 60, 0, 50, 50)


Global $ListView = GUICtrlCreateListView("Entry Name|Category", 5, 75, 195, 280)
_GUICtrlListView_SetColumnWidth ($ListView, 0, 100)
_GUICtrlListView_SetColumnWidth ($ListView, 1, 100)
GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES)
GUICtrlSendMsg($ListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_FULLROWSELECT, $LVS_EX_FULLROWSELECT)
GUICtrlCreateListViewItem("Name 1|Category 1", $ListView)
GUICtrlCreateListViewItem("Name 2|Category 2", $ListView)

screenshotWidgetInit($ssW,$ssH, 690, 100)
GUISetState(@SW_SHOW, $mainWindow)

GUIRegisterMsg($WM_NOTIFY, "WM_Notify_Events")

While 1
   _Check_MSG()
WEnd

Func _Check_MSG()
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            _Exit()
        Case $Button1
            _Exit()
        Case $Button2
            Test()
    EndSwitch
EndFunc

Func Test()
    For $k = 1 To UBound($aFiles) - 1
        screenshotWidgetTransition($aFiles[$k])
    Next
EndFunc

Func ListView_Click()
    ConsoleWrite("Left Click")
EndFunc

Func ListView_DoubleClick()
    ConsoleWrite("Double Left Click")
    Test()
EndFunc

Func WM_Notify_Events($hWndGUI, $MsgID, $wParam, $lParam)
    #forceref $hWndGUI, $MsgID, $wParam
    Local $tagNMHDR, $event, $hwndFrom, $code
    $tagNMHDR = DllStructCreate("int;int;int", $lParam)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3)
    Select
    Case $wParam = $ListView
        Select
            Case $event = $NM_CLICK
                ListView_Click ()
            Case $event = $NM_DBLCLK
                ListView_DoubleClick ()
            EndSelect
    EndSelect
    Return $GUI_RUNDEFMSG
EndFunc

Func screenshotWidgetTransition($image, $delay = 0, $speed = 1, $sleep = 2000)
    Local $a, $d = $c, $iX, $iY
    $ssImage = _GDIPlus_ImageLoadFromFile($image)
    $iX = _GDIPlus_ImageGetWidth($ssImage)
    $iY = _GDIPlus_ImageGetHeight($ssImage)

    $FDesktop=$ssH/$ssW
    $Fact =1
    If $iX > $ssW And $FDesktop > ($iY/$iX) Then
        $Fact=$ssW/$iX
    ElseIf $iY > $ssH Then
        $Fact=$ssH/$iY
    EndIf
    $H1 = Round(($Fact * $iY),0)
    $W1 = Round(($Fact * $iX),0)

    _GDIPlus_GraphicsDrawImageRect($ssGraphic[$d], $ssImage,($ssW - $W1)/2, ($ssH - $H1) / 2,$W1,$H1)

    WinSetTrans($ssGDI[$d], "", 0)
    WinSetOnTop($ssGDI[$d], "", 1)
    For $a = 0 To 254 Step $speed
        WinSetTrans($ssGDI[$d], "", $a)
        _Check_MSG()
        Sleep($delay)
    Next
    WinSetTrans($ssGDI[$d], "", 254)
    WinSetOnTop($ssGDI[Not ($d)], "", 0)
    WinSetTrans($ssGDI[Not ($d)], "", 0)
    _GDIPlus_GraphicsClear($ssGraphic[Not ($d)])
    $c = 1 - $d

    _GDIPlus_ImageDispose ($ssImage) ; very important to realease the pics
    $timer = TimerInit()
    While TimerDiff($timer) < $sleep
        _Check_MSG()
    WEnd

EndFunc   ;==>screenshotWidgetTransition

Func screenshotWidgetInit($ssW,$ssH,$ssX,$ssY)
    $ssGDI[2] = GUICreate("", $ssW, $ssH, $ssX, $ssY, $WS_POPUP, $WS_EX_MDICHILD, $mainWindow)
    $ssGDI[0] = GUICreate("", $ssW, $ssH, 3, 3, $WS_POPUP, $WS_EX_MDICHILD, $ssGDI[2])
    $ssGDI[1] = GUICreate("", $ssW, $ssH, 3, 3, $WS_POPUP, $WS_EX_MDICHILD, $ssGDI[2])
;    GUISetBkColor("0x" & $bg_color, $ssGDI[2])
    GUISetState(@SW_SHOW, $ssGDI[2])
    GUISetState(@SW_SHOW, $ssGDI[0])
    GUISetState(@SW_SHOW, $ssGDI[1])
    WinSetTrans($ssGDI[0], "", 0)
    WinSetTrans($ssGDI[1], "", 0)
    _GDIPlus_Startup()
    $ssGraphic[0] = _GDIPlus_GraphicsCreateFromHWND($ssGDI[0])
    $ssGraphic[1] = _GDIPlus_GraphicsCreateFromHWND($ssGDI[1])
    _GDIPlus_GraphicsClear($ssGraphic[0], "0xFF" & $bg_color)
    _GDIPlus_GraphicsClear($ssGraphic[1], "0xFF" & $bg_color)
EndFunc   ;==>screenshotWidgetInit

Func _Exit()
    _GDIPlus_ImageDispose($ssImage)
    _GDIPlus_GraphicsDispose($ssGraphic[0])
    _GDIPlus_GraphicsDispose($ssGraphic[1])
    GUIDelete($ssGDI[0])
    GUIDelete($ssGDI[1])
    GUIDelete($ssGDI[2])
    _GDIPlus_Shutdown()
    Exit
EndFunc   ;==>_Exit

 

Edited by nend

Share this post


Link to post
Share on other sites

nend, Thank you so much for the reply and the code - it gave me a clearer concept of how things work behind the Autoit scene : )

I also read in the Wiki about the exact problem I was facing --> https://www.autoitscript.com/wiki/Interrupting_a_running_function

I hope it's OK to share the link here, just for others who stumble upon this topic can have a better understanding.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Vikramjeet
      include-once #include <File.au3> #include <Excel.au3> #include <String.au3> #include <MsgBoxConstants.au3> Local $file = "TEST.log" FileOpen($file, 0) $TTLPax = 1 For $i = _FileCountLines($file) - $TTLPax to _FileCountLines($file) $line = FileReadLine($file, $i) Global $TktNo = StringMid($line, 8, 13) ; reads 13 characters from $Line starting from the 8th character msgbox(0,'',$TktNo) ; This is just for me to debug For $NoOfPax = 1 to 2 local $TTLSeg = 2 msgbox(0,'',$TTLSeg) msgbox(0,'',"7ABC"& $TktNo &"'N"& $NoOfPax &".1'C1,2'S1,2'B") ; This makes 7ABC1234567890123'N1.1'C1,2'S1,2'B ;But in the next loop I want the value to be 7ABC1234567890333'N2.1'C1,2'S1,2'B Next ExitLoop Next *TEST
      JAMES BAKER
        1.NYC-23JAN
        2.TJ 1234567890123
        3.TJ 1234567890333
      I am reading a file with last 5 lines as above. I want to be able to loop through and pick the values as follows
      1- Pick 1234567890123
      2- Use it to build a format with N1.1
      3- Pick 1234567890333
      2- Use it to build a format with N2.1
      Need help with the loop. Thank You
       
       
    • By Vikramjeet
      For $A1 = 12 To 11 + $Total For $B1 = 1 To ($oExcel.Application.Cells($A1,6).Value) ; This value is from the Excel file. It can be from 1 - 9. For $N1 = 7 To ??? ; This is based on the value of $B1 ((1 = 7, 2 = 17, 3 = 27, 4 = 37, 5 = 47) Send("-"& ($oExcel.Application.Cells($A1,$N1).Value) &"/"& ($oExcel.Application.Cells($A1,$N1+1).Value)) Sleep(400) Send("{ENTER}") Sleep(700) Next Next Next I am not able to figure how to loop $N1 as follows
      If the Value of $B1 = 1 then $N1 = 7
      If the Value of $B1 = 2 then $N1 = 17
      If the Value of $B1 = 3 then $N1 = 27
      If the Value of $B1 = 4 then $N1 = 37  
      The value of $N1 comes from $B1 where 1 = 7, 2 = 17, 3 = 27, 4 = 37, 5 = 47)
      Thank You
    • By paw
      I use SetSoundDevice to control my audio devices but the UI was either
       
      blurry like this:
      or unusable like this:

      so I made this horrible thing to add scaling to the GUI:
      #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Change2CUI=y #AutoIt3Wrapper_Res_HiDpi=y #AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 #AutoIt3Wrapper_Run_Au3Stripper=y #Au3Stripper_Parameters=/sf /sv /rm #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <File.au3> ;~ _convertGUI("") If $CmdLine[0] <> 0 Then _convertGUI($CmdLine[1]) Func _convertGUI($sFilePath) If $sFilePath <> "" Then Local $aArray = FileReadToArray($sFilePath) Else ;TEST DATA Local $aArray[6] = ['$H_Res_Language = GUICtrlCreateProgress(5, 120, 210 + 25, 480, 20, BitOR($GUI_SS_DEFAULT_COMBO, $CBS_SIMPLE)) ; $CBS_DROPDOWNLIST)', _ 'Local $h_Ok = GUICtrlCreateButton("Ok", 72, 224, 81, 33, 0)', _ 'GUICreate($Warning_TiTle, 700, 310, -1, -1, $WS_SIZEBOX + $WS_SYSMENU + $WS_MINIMIZEBOX)', _ 'GUICtrlCreateLabel("Output type: ", 30, 130, 65, 20) ;, $SS_RIGHT)', _ '$H_FieldNameEdit = GUICtrlCreateEdit($INP_FieldNameEdit, 100,260+25, 500, 150 - 25) ;comment', 'Local $H_CANCEL = GUICtrlCreateGraphic("Cancel", 224, 224, 97, 33, 0)'] EndIf Local $hTimer = TimerInit(), $iGUIElementCount = 0, $sResult = "", $sFileName = "", $sDrive = "", $sDir = "", $sExtension = "" If @Compiled Then _PathSplit($sFilePath, $sDrive, $sDir, $sFileName, $sExtension) $sFileName = StringRegExpReplace($sFilePath, "^.*\\", "") EndIf For $i = 0 To (UBound($aArray) - 1) If StringRegExp($aArray[$i], "GUICtrlCreate|GUICreate") Then $sResult = _splitComma($aArray[$i]) If Not @error Then $aArray[$i] = $sResult $iGUIElementCount += 1 EndIf Next ConsoleWrite("t = " & TimerDiff($hTimer) & " GUI elements = " & $iGUIElementCount & " lines = " & (UBound($aArray) - 1) & @CRLF) If $sFileName <> "" Then Local $hFile = FileOpen("edited." & $sFileName, 2) _FileWriteFromArray("edited." & $sFileName, $aArray) FileClose($hFile) EndIf Exit EndFunc ;==>_convertGUI Func _splitComma($sString) Local $sSplitResult = "", $sTrimmedR = "", $sTrimmedL = "" Local $aSplit = StringSplit($sString, ',') If Not @error Then $sTrimmedR = "" $sTrimmedL = "" For $j = 1 To $aSplit[0] If StringRegExp($aSplit[1], "(?:.GUICtrlCreateGraphic|GUICtrlCreateProgress|GUICtrlCreateSlider|GUICtrlCreateTab|GUICtrlCreateTreeView)") Then If $j = 1 Then While StringLeft($aSplit[$j], 1) <> '(' $sTrimmedL &= StringLeft($aSplit[$j], 1) $aSplit[$j] = StringTrimLeft($aSplit[$j], 1) WEnd $aSplit[$j] = StringTrimLeft($aSplit[$j], 1) EndIf EndIf If $j = $aSplit[0] Then While StringRight($aSplit[$j], 1) <> ')' $sTrimmedR &= StringRight($aSplit[$j], 1) $aSplit[$j] = StringTrimRight($aSplit[$j], 1) WEnd $aSplit[$j] = StringTrimRight($aSplit[$j], 1) EndIf If StringRegExp($aSplit[$j], "[0-9]") And $aSplit[$j] <> -1 And $aSplit[$j] <> 0 And $aSplit[$j] <> 1 And Not StringInStr($aSplit[$j], ')') Then If StringRegExp($aSplit[$j], "\-|\+") Then ;put parenthesis around + or - $aSplit[$j] = '(' & $aSplit[$j] & ")*$g_DPI" Else $aSplit[$j] = $aSplit[$j] & "*$g_DPI" EndIf EndIf If $j < $aSplit[0] Then $sSplitResult &= $aSplit[$j] & ',' ElseIf $j = $aSplit[0] Then $sSplitResult &= $aSplit[$j] & ')' Else $sSplitResult &= $aSplit[$j] EndIf Next If $sTrimmedR <> "" Then $sSplitResult &= StringReverse($sTrimmedR) If $sTrimmedL <> "" Then $sSplitResult = $sTrimmedL & '(' & $sSplitResult Else SetError(1) Return EndIf ConsoleWrite($sSplitResult & @CRLF) Return $sSplitResult EndFunc ;==>_splitComma
      And now it looks good: 
      but it doesn't work on everything, for example the "GUICtrlCreateLabel("Output type: ", 30, 130, 65, 20) ;, $SS_RIGHT)" (from the autoit3wrapper gui)
      because the comment contains a parenthesis and it would break completely if there were variables as parameters..
      Is there some kind of parser around that I could use instead or maybe someone who has already done something like this?
    • By UEZ
      This project has been discontinued!
       
      Here a small tool I wrote to update my Sysinternal tools collection without the need to download always the whole package or visiting the site to check for updates. I know that there are several tools available (also some tools written in AutoIt) but here another one for the collection. It was good exercise for me to code it.
       
       
        
       
       
      Some files from the live web site cannot be downloaded although they are visible!
       
      Here the download link of the source code only: AutoIt Sysinternal Tools Synchronizer v0.99.6 build 2020-09-23 beta.7z  (1557 downloads previously)
      -=> Requires AutoIt version 3.3.13.20 or higher / tested on Win8.1 real machine and some VMs: Win7 / Vista / Win10
       
      Compiled exe only: @MediaFire
       
      Just select the Sysinternal Tools folder or create one and press the synchronize button to download the selected items. Click on AutoIt label (near to left upper corner) to open menu.
       
      Special thanks to LarsJ, Melba23 and mesale0077 for their help. 
       
      I've still some ideas to implement which are more gimmick related, so it is not finished yet...
      If you want to add your language please check out #Region Language. Thanks. 
       
      Please report any bug or if you have any suggestions.
       
      The language of the tool tip from each of the executable in the left list view were automatically created using Google translator and weren't checked for correctness.
       
      Br,
      UEZ
    • By TXTechie
      Hello Everyone,
      I've developed my own GUI using AutoIt and I'm allowing users to minimize the GUI, but I also want to include some kind of timer so that it will automatically restore the GUI after something like 30 minutes or an hour. However, I also want them to be able to manually restore the GUI by clicking the application's icon in the taskbar.
      I've searched through the forums, but I'm not sure how to get started.
      Any ideas or functions to research are appreciated!
      Regards,
      TX Techie
×
×
  • Create New...