WinPosition to __DialogX= and __DialogY=

Started by galaara98, September 25, 2014, 02:20:08 PM

Previous topic - Next topic

galaara98

So I have read the article Screen Coordinates explained (http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/tsleft.web+Tutorials+Screen~Coordinates~Explained.txt)

and I have even understood it  :) .. but today, I'm stressed .. and tired.. and I can't get the math to work.

I have a Winbatch Dialog (with custom handler) that I would like to write down its coordinates when the user closes it, because it will be back soon.

Currently I am doing this by
   OldCoords = WinPosition(MyTitle)
   OldX = ItemExtract(1,OldCoords,",")
   OldY = ItemExtract(2,OldCoords,",")
   OldCoords = OldX : "," : OldY: ",@NORESIZE,@NORESIZE"

and then later, AFTER the dialog is formed, but still in it's init
    Case 0 ; Init - yes im one of those weirdos that is still using "magic numbers" for DialogMessage because I memorized them eons ago
         WinPlace(OldCoords,MyTitle)


This works... and it's... OK.  but there is a flash when the Dialog first appears   ... where the __DialogX and __DialogY say it is to appear
(in this case Centered on main monitor, but could have been any cords)

    MyDialogCaption=`PeopleSearch Lite - v<MyVersion>`
    MyDialogX=-01
    MyDialogY=-01
    MyDialogWidth=514
    MyDialogHeight=246


But what I would LIKE it to do is
    ConvertedX = OldX * something related to Pixels, Winmetric, 1000 and other math concepts my brain will not do today
    ConvertedY = OldY * something

    MyDialogCaption=`PeopleSearch Lite - v<MyVersion>`
    MyDialogX=ConvertedX
    MyDialogY=ConvertedY
    MyDialogWidth=514
    MyDialogHeight=246


and have the dialog open right back up where it last was

would someone be so kind as to help me do the math to make this work.

Aaron

PS. in case someone gets sidetracked by the noresize... the dialog I am bringing back may or may not be the same dialog that the user closed
     it would be one of a few that are ALMOST the same size, hence why I only grab the UpperLeftX,UpperleftY and not pass on all the data to winplace()

td

Using -1 for a dialogs origin (x and y variables) will cause the next dialog displayed to use the previous dialog's origin.  The one caveat being that you cannot allow any dialog 'cancel' processing.  A dialogs origin is not saved when the dialog is canceled. You can prevent 'cancel' processing by making sure your dialog callback procedure returns a positive integer when either the escape key is pressed or the Cancel button is pressed.  Note that pressing the escape key is treated as if the Cancel button was pressed so your callback will receive a Cancel button event when the escape key is pressed, if your dialog has a Cancel button. If you dialog dose not have a Cancel button, the escape key is ignored. The Cancel button is the button with a value attribute of integer 0.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

I should have also mentioned that the dialog origin is save between calls to the Dialog function when the calls occur in the same WinBatch process.  The dialog origin is not automatically saved between processes, i.e., starts of the WinBatch.exe program.

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

galaara98

:) that's the side track I didn't want.  Because technically there are 3 different Dialogs, with 3 different titles, in 2 different EXE that use this coordinates.  So the builtin -1 is not enough.  I need to be able to record where the dialog is using my own process and return all of the 3 dialogs to that same point.

Like I said, I am achieving the results I need... I just would like to avoid the flashing pop that happens when the Dialog is first created and when the Winplace moves it.  But I for the life of me cannot get the math to work.

The issue lies on the fact that I create a very simple dialog
WinPosition says the UpperLeftX = 312 and the UpperLeftY = 555
but the MyDialog says UpperLeftX = 250 and UpperLeftY = 250

So how do I reconcile what WinPosition recorded and translate it into what the DialogX and DialogY want
====





Gosub UDFs

; **************************************************************************************************
; BEGIN MAIN()
; **************************************************************************************************
IntControl(12,5,"",0,0) ; Allow Close and "logout/shutdown" without any dialog/prompts from Winbatch
IntControl(1002, 0, 0, 0, 0) ; HIDE WinBatch Icon
IntControl(1008,0,0,0,0) ; Disable Close via Menu
IntControl(1003, 0, 0, 0, 0)  ; Prevents the WinBatch ICON from being opened



MyExe = IntControl(1004, 0, 0, 0, 0)         ; Get fully qualified name of the current WB program
MyMD5 = FileDigest(MyExe,"MD5",0)
MyVersion = Strreplace(FileVerInfo(MyExe, "", "#FileVersion" ),",",".")
MyFolder = strLower(FilePath(MyExe))
MyExt = FileExtension(MyExe)

if strLower(MyExt) == "wbt" then
   MyVersion = "DEBUG"
   MyFolder = "P:\Applications\PeopleSearch\bin"
   DirChange(MyFolder)
end if

if RegExistValue(@REGCURRENT,"Software\MyCompany\MyProduct[LastCoords]") then
   ShouldbeWinPos_Coords = RegQueryValue(@REGCURRENT,"Software\MyCompany\MyProduct[LastCoords]")
   ShouldbeX = ItemExtract(1,ShouldbeWinPos_Coords,",")
   ShouldbeY = ItemExtract(2,ShouldbeWinPos_Coords,",")
   if ItemCount(ShouldbeWinPos_Coords,",") != 4 || !isInt(ShouldbeX) || !isInt(ShouldbeY) then
      ShouldbeWinPos_Coords = ""
   end if
else
   ShouldbeWinPos_Coords = ""
end if

; this helps us control the soon to be create Dialog, in a real script these would be deduced from sometting more complex
ThisDialogCoordsX = 250
ThisDialogCoordsY = 250
ThisDialogWidth = 200
ThisDialogHeight = 80
ThisDialogTitle = "Test Dialog v" : MyVersion


MyDialogFormat=`WWWDLGED,6.2`

MyDialogCaption=`Test Dialog v10.10.10.10`
MyDialogX=250
MyDialogY=250
MyDialogWidth=196
MyDialogHeight=074
MyDialogNumControls=004
MyDialogProcedure=`TestDialogProc`
MyDialogFont=`DEFAULT`
MyDialogTextColor=`DEFAULT`
MyDialogBackground=`DEFAULT,DEFAULT`
MyDialogConfig=0

MyDialog001=`095,055,036,012,PUSHBUTTON,"PushButton_OK",DEFAULT,"OK",1,10,32,DEFAULT,DEFAULT,DEFAULT`
MyDialog002=`141,055,036,012,PUSHBUTTON,"PushButton_Cancel",DEFAULT,"Cancel",999,20,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MyDialog003=`015,005,156,012,VARYTEXT,"Dialog_Coords",Dialog_Coords,DEFAULT,DEFAULT,30,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MyDialog004=`015,021,156,012,VARYTEXT,"WinPos_Coords",WinPos_Coords,DEFAULT,DEFAULT,40,DEFAULT,DEFAULT,DEFAULT,DEFAULT`

;ButtonPushed=Dialog("MyDialog")
; ^ Preserved to allow Clipboard import and export into WIL Dialog Editor

MyDialogCaption = ThisDialogTitle
MyDialogX = ThisDialogCoordsX
MyDialogY = ThisDialogCoordsY
MyDialogWidth = ThisDialogWidth
MyDialogHeight = ThisDialogHeight

Dialog_Coords = MyDialogX : "," : MyDialogY : "," : MyDialogWidth : "," : MyDialogHeight


ButtonPushed=Dialog("MyDialog")


Exit
; **************************************************************************************************
; END MAIN()
; **************************************************************************************************



; **********************************************
; BEGIN OF UDFs Definition Block
; **********************************************

:UDFs
#DefineSubroutine TestDialogProc(Handle,DialogMessage,ControlName,EventInfo,ChangeInfo)
   Switch DialogMessage
      Case 0 ; Init dialog
         WinPos_Coords = WinPosition(ThisDialogTitle)
         DialogProcOptions( Handle, 1002, 2) ; Enable Close and Minimize buttons in titlebar
         DialogProcOptions( handle,  1, 333) ; we Care about Timer Ticks of 333ms
         DialogProcOptions( handle,  2, 1) ; we Care about Buttons
         DialogProcOptions( Handle, 11, 1) ; We care about the Close button "X" in Titlebar


         DialogControlSet(handle,"WinPos_Coords",4,WinPos_Coords)


         ; ***********************************************************************************************
         ; If we can't find a way to calculate MyDialogX and MyDialogY based on ShouldbeWinPos_Coords then
            if ShouldbeWinPos_Coords != "" then
               WinPlace(%ShouldbeWinPos_Coords%,ThisDialogTitle)
            end if
         ;************************************************************************************************'
         Return(-2)
         break
      Case 1 ; Timer
         NewWinPos_Coords = WinPosition(ThisDialogTitle)
         if NewWinPos_Coords != WinPos_Coords then
            WinPos_Coords = NewWinPos_Coords
            DialogControlSet(handle,"WinPos_Coords",4,WinPos_Coords)
         end if
         ;I cannot find a way to query the dialog for its coords in the same format that
         ;MyDialogX= and MyDialogY= uses
         ;NewDialog_Coords = ?
         ;if NewDialog_Coords != Dialog_Coords then
         ;   Dialog_Coords = NewDialog_Coords
         ;   DialogControlSet(handle,"Dialog_Coords",4,Dialog_Coords)
         ;end if
      Case 2; Button
         if ControlName == "PushButton_Cancel" then
            WinPos_Coords = WinPosition(ThisDialogTitle)
            LastCoords = ItemExtract(1,WinPos_Coords,",") : "," : ItemExtract(2,WinPos_Coords,",") : ",@NORESIZE,@NORESIZE"
            RegSetValue(@REGCURRENT,"Software\MyCompany\MyProduct[LastCoords]",LastCoords)
            Return(0)
         end if
         return(-2)
         break
      Case 11 ; Close Button in Title
         WinPos_Coords = WinPosition(ThisDialogTitle)
         LastCoords = ItemExtract(1,WinPos_Coords,",") : "," : ItemExtract(2,WinPos_Coords,",") : ",@NORESIZE,@NORESIZE"
         RegSetValue(@REGCURRENT,"Software\MyCompany\MyProduct[LastCoords]",LastCoords)
         Return(0)
         break
      ; End Cases
   End Switch
   Return (-2)

#EndSubroutine




return
; **********************************************
; END OF UDFs Definition Block
; **********************************************




snowsnowsnow

Doesn't IntControl(75) have something to do with this?

td

The arithmetic  to convert from WIL virtual coordinates to dialog units is relative straight forward.  However, it will not likely produce a satisfactory result because of rounding and representational error.

As Snow++ suggests (many thanks for reminding us of that), you could use  IntControl(75) to write the last WIL dialog origin to the registry but this would necessitate using the technique I describe above to prevent the dialog from being canceled and the call to IntControl(75) would have to be made after the dialog has terminated.  This is because the origin will not be saved when a dialog is canceled and the origin values are only updated as part of the dialog shutdown process.

IntControl(75) is the best approach, if you are not put off by any of the above restrictions. If for some reason you cannot comply with the restrictions then the following UDF may be of some use.

Code (winbatch) Select

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DlgUnitOrigin
;;
;; Converts the current origin of the passed in WIL Dialog
;; from pixils to dialog units suitable for locating the
;; WIL dialog on redisplay
;;
;; hDialog  - (In) window handle to a WIL dialog
;; nX       - (Out) Dialog x origin in dialog units
;; nY       - (Out) Dialog y origin in dialog units
;;
;; No error handling!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
#DefineFunction DlgUnitOrigin(_hDialog, _pnX, _pnY)

   ; Get a handle to the user32.dll system dll.
   hUser32 = DllLoad("USER32") ; Keep snow++ happy.

   ; Get the current origin.
   hRect = binaryalloc(16)
   DllCall(hUser32,  long:"GetWindowRect", long:_hDialog, lpbinary:hRect)     
   nX = BinaryPeek4(hRect, 0)
   nY = BinaryPeek4(hRect, 4)
   BinaryFree(hRect)
   
   ; Convert to Dialog units.
   nBaseUnits = DllCall(hUser32, long:"GetDialogBaseUnits")
   DllFree(hUser32)
   hKernel32 = DllLoad("Kernel32") ; Keep snow++ happy.
   *_pnX = DllCall(hKernel32,long:"MulDiv",long:nX, long:4, long:nBaseUnits&65535)
   *_pnY = DllCall(hKernel32,long:"MulDiv",long:nY, long:8, long:(nBaseUnits>>16)&65535)
   DllFree(hKernel32)
   return 1
#EndFunction

; Simple callback complete with magic numbers to be used to
; test the quick and dirty UDF.
#DefineSubroutine DlgUnitsCallbackProc(_Handle,_Event,_Name,_EventInfo,_ChangeInfo)
   switch _Event                                 
      case 0                                     
         DialogProcOptions(_Handle,2,@TRUE)
         return(-1)
        case 2                               
         if _Name == "PushButton_Test"
            nX = 0
            nY = 0
            DlgUnitOrigin(_Handle, &nX, &nY)
            DialogControlSet(_Handle,"StaticText_1", 4, "Original: x = ":DlgUnitsX:" y = ":DlgUnitsY:@CrLf:"Calculated: x = ":nX:" y = ":nY)
            return(-2)
         endif
   endswitch                                           
   return(-1)
#EndSubroutine                                           
DlgUnitsFormat=`WWWDLGED,6.2`

DlgUnitsCaption=`Test Unit Conversion`
DlgUnitsX=213
DlgUnitsY=084
DlgUnitsWidth=195
DlgUnitsHeight=104
DlgUnitsNumControls=003
DlgUnitsProcedure=`DlgUnitsCallbackProc`
DlgUnitsFont=`DEFAULT`
DlgUnitsTextColor=`DEFAULT`
DlgUnitsBackground=`DEFAULT,DEFAULT`
DlgUnitsConfig=0

DlgUnits001=`042,052,107,011,PUSHBUTTON,"PushButton_Test",DEFAULT,"Test",1,10,32,DEFAULT,DEFAULT,DEFAULT`
DlgUnits002=`071,089,032,011,PUSHBUTTON,"PushButton_Quit",DEFAULT,"Quit",0,20,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
DlgUnits003=`017,015,158,030,STATICTEXT,"StaticText_1",DEFAULT,"Press Test",DEFAULT,30,DEFAULT,DEFAULT,DEFAULT,DEFAULT`

ButtonPushed=Dialog("DlgUnits")

   
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

Quote
; Get a handle to the user32.dll system dll.
   hUser32 = DllLoad("USER32") ; Keep snow++ happy.

; ...
   
   DllFree(hUser32)
   hKernel32 = DllLoad("Kernel32") ; Keep snow++ happy.

Glad to see you're coming around to my way of doing things!

But to get the full snow++ seal of approval, you've got to do two more things:

1) Make these variables global, rather than function local, so that you don't have to recalculate them each time the function is called (on the assumption that this function might be called multiple times).  There are, of course, various ways of making global variables, that have been discussed over the years, the easiest of course is to make it a UDS instead of a UDF.

2) I think there's no point in DllFree'ing them, because, remember these are handles to already opened DLLs (the main WinBatch executable will already have opened and be using both of these two key DLLs).  So, the free is pretty much a no-op.  And, of course, if you make them global, then you can't be freeing them.

td

Discussions of coding style tend to produce more heat than light on this forum so I wont get into a discussion of why I would not write the UDF as you suggest.  But to each his own. 

Truth be told I would normally skip both the DllLoads and DllFrees in the above function given its purpose.  Just thought I would pay homage to one of your previous mini-rants. 

And thanks again for the IntControl reminder.

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

Heh heh.  Rants (mini- and otherwise) my speciality.

Glad the IC(75) suggestion helped.

galaara98

Quote from: td on September 27, 2014, 09:34:26 AM
The arithmetic  to convert from WIL virtual coordinates to dialog units is relative straight forward.  However, it will not likely produce a satisfactory result because of rounding and representational error.

As Snow++ suggests (many thanks for reminding us of that), you could use  IntControl(75) to write the last WIL dialog origin to the registry but this would necessitate using the technique I describe above to prevent the dialog from being canceled and the call to IntControl(75) would have to be made after the dialog has terminated.  This is because the origin will not be saved when a dialog is canceled and the origin values are only updated as part of the dialog shutdown process.

IntControl(75) is the best approach, if you are not put off by any of the above restrictions. If for some reason you cannot comply with the restrictions then the following UDF may be of some use.
   

I apologize I didn't chime in.  The reason I needed this was because I was under duress, and when your busy and tired and frustrated you often forget to give thanks.

Everyone,
   Thank you so much... I have used winbatch for probably 10 years now.. I have compiled automation applications still functional from back them, and I have massive dialog based applications that are my pride and joy.  and I can say I never noticed IntControl(75 ... but that's my own fault.

TR,
   Thanks.  -- insert flowery expressions of gratitude for your time and effort --'
   But really, just thanks... both the IntControl and your UDF proved successful for certain needs.
   I just wanted you to know: 
        I see you around (and value the time you provide to the community),
        I like your sharp and frank wit,
        I like it when you indicate you are mulling and considering some frivolous wish I have proposed
               (but I know that it takes more votes then just me selfishly wanting something easier or "my way") 
       and I like your solutions.. I tend to never cut and paste others thoughts, so I have to be able to comprehend the what and how of the source, to use it for my own reasons... and I find that generally easy to do with your suggestions.

          [now I cant argue with Deana's _ever_ helpful style.. I think we ALL love that!  (I would never want to alienate one source of help in favor of another), but I admit sometimes I personally would rather be told that I am doing it wrong, and the answer is: do it right/better and then come back and ask your question... but that's just me ]


Aaron