Jump to content
therks

_GUICtrlEdit_GetSel() get anchor/active position

Recommended Posts

therks
Posted (edited)

So I'm needing a (better) way to get the selection in an edit control, while knowing which end of the selection is active vs anchor (ie, if you're holding shift while moving with the arrow keys, which end of the selection is moving and which is not). Since _GUICtrlEdit_GetSel() only returns the start and end positions, in the order of smallest to largest, if you were to pass that back to the _GUICtrlEdit_SetSel(), the user's selection could end up "backwards".

My solution has been this function:

Func _GUICtrlEdit_GetSelByAnchor($hWnd)
    ; Get selection range with anchor in first index
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
    Local $aActive, $aSelection = _GUICtrlEdit_GetSel($hWnd) ; Get base selection
    If $aSelection[0] <> $aSelection[1] Then ; Only proceed if actual selection range
        _GUICtrlEdit_SetSel($hWnd, -1, 0) ; Deselect, leaving only the active point
        $aActive = _GUICtrlEdit_GetSel($hWnd) ; Record the active point
        If $aActive[0] = $aSelection[0] Then ; If the active point is equal to the original first index
            ; Swap the original selection points (putting the anchor in [0] and active in [1])
            $aSelection[0] = $aSelection[1]
            $aSelection[1] = $aActive[0]
        EndIf
        _GUICtrlEdit_SetSel($hWnd, $aSelection[0], $aSelection[1]) ; Reset selection to the original points
    EndIf
    Return $aSelection
EndFunc

The problem with this, as you may have already guessed from the two SetSel calls, is that calling it in a tight loop causes a lot of flickering. Is there a better, more reliable way to do what I'm looking for?

Edited by therks

Share this post


Link to post
Share on other sites
corz

And what are you looking for?

Maybe if you provided a working example of what you are trying to actually do, you would get a better response.

My first thought was that this some kind of Rube Goldberg machine, in code.  A joke that no one got.

;o) Cor


nothing is foolproof to the sufficiently talented fool..

Share this post


Link to post
Share on other sites
therks

Sorry, I thought I was pretty clear about what I wanted here:

On 4/9/2018 at 6:46 PM, therks said:

So I'm needing a (better) way to get the selection in an edit control, while knowing which end of the selection is active vs anchor (ie, if you're holding shift while moving with the arrow keys, which end of the selection is moving and which is not).

But for an example, I want to do something like this without all the blinking and reselecting:

#include <GUIConstants.au3>
#include <GUIEdit.au3>

$hGUI = GUICreate('Test', 500, 320)
$ed_Main = GUICtrlCreateEdit(FileRead(@ScriptFullPath), 0, 0, 500, 300)
$lb_Status = GUICtrlCreateLabel('', 0, 300, 500, 20, BitOR($SS_SUNKEN, $SS_CENTERIMAGE))
GUISetState()

Dim $aSelMem[2]

_GUICtrlEdit_SetSel($ed_Main, 100, 10)

While 1
    $aSel = _GUICtrlEdit_GetSelByAnchor($ed_Main)
    If $aSel[0] <> $aSelMem[0] Or $aSel[1] <> $aSelMem[1] Then
        GUICtrlSetData($lb_Status, 'Selection anchor: ' & $aSel[0] & '. Selection active: ' & $aSel[1])
        $aSelMem = $aSel
    EndIf

    $iGUIGetMsg = GUIGetMsg()
    Switch $iGUIGetMsg
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd

Func _GUICtrlEdit_GetSelByAnchor($hWnd)
    ; Get selection range with anchor in first index
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
    Local $aActive, $aSelection = _GUICtrlEdit_GetSel($hWnd) ; Get base selection
    If $aSelection[0] <> $aSelection[1] Then ; Only proceed if actual selection range
        _GUICtrlEdit_SetSel($hWnd, -1, 0) ; Deselect, leaving only the active point
        $aActive = _GUICtrlEdit_GetSel($hWnd) ; Record the active point
        If $aActive[0] = $aSelection[0] Then ; If the active point is equal to the original first index
            ; Swap the original selection points (putting the anchor in [0] and active in [1])
            $aSelection[0] = $aSelection[1]
            $aSelection[1] = $aActive[0]
        EndIf
        _GUICtrlEdit_SetSel($hWnd, $aSelection[0], $aSelection[1]) ; Reset selection to the original points
    EndIf
    Return $aSelection
EndFunc

Try running that and then making a variety of different selections with the mouse or keyboard.

Share this post


Link to post
Share on other sites
Subz

The issue is calling _GuiCtrlEditSelAnchor() in a loop and then the following  code in the function.

If $aSelection[0] <> $aSelection[1] Then

One option is to store it into a Global variable so that it can check if it's already been set previously for example:

#include <GUIConstants.au3>
#include <GUIEdit.au3>

Global $aSel, $aSelMem[2]
Global $aSelectionMem[2]
$hGUI = GUICreate('Test', 500, 320)
$ed_Main = GUICtrlCreateEdit(FileRead(@ScriptFullPath), 0, 0, 500, 300)
$lb_Status = GUICtrlCreateLabel('', 0, 300, 500, 20, BitOR($SS_SUNKEN, $SS_CENTERIMAGE))
GUISetState()

_GUICtrlEdit_SetSel($ed_Main, 100, 10)

While 1
    _GUICtrlEdit_GetSelByAnchor($ed_Main)
    If $aSel[0] <> $aSelMem[0] Or $aSel[1] <> $aSelMem[1] Then
        GUICtrlSetData($lb_Status, 'Selection anchor: ' & $aSel[0] & '. Selection active: ' & $aSel[1])
        $aSelMem = $aSel
    EndIf
    $iGUIGetMsg = GUIGetMsg()
    Switch $iGUIGetMsg
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd

Func _GUICtrlEdit_GetSelByAnchor($hWnd)
    ; Get selection range with anchor in first index
    If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
    Local $aActive, $aSelection = _GUICtrlEdit_GetSel($hWnd) ; Get base selection
    If $aSelection[0] = $aSelectionMem[0] And $aSelection[1] = $aSelectionMem[1] Then Return
    If $aSelection[0] <> $aSelection[1] Then ; Only proceed if actual selection range
        $aSelectionMem = $aSelection
        _GUICtrlEdit_SetSel($hWnd, -1, 0) ; Deselect, leaving only the active point
        $aActive = _GUICtrlEdit_GetSel($hWnd) ; Record the active point
        If $aActive[0] = $aSelection[0] Then ; If the active point is equal to the original first index
            ; Swap the original selection points (putting the anchor in [0] and active in [1])
            $aSelection[0] = $aSelection[1]
            $aSelection[1] = $aActive[0]
        EndIf
        _GUICtrlEdit_SetSel($hWnd, $aSelection[0], $aSelection[1]) ; Reset selection to the original points
    EndIf
    $aSel = $aSelection
EndFunc

 

Share this post


Link to post
Share on other sites
corz

I don't see what extra functionality your function involves. Why set a selection which is already set? _GUICtrlEdit_GetSel looks to me to have all you need. 

#include <GUIConstants.au3>
#include <GUIEdit.au3>

$hGUI = GUICreate('Test', 500, 320)
$ed_Main = GUICtrlCreateEdit(FileRead(@ScriptFullPath), 0, 0, 500, 300)
$lb_Status = GUICtrlCreateLabel('', 0, 300, 500, 20, BitOR($SS_SUNKEN, $SS_CENTERIMAGE))
GUISetState()

Dim $aSelMem[2]

_GUICtrlEdit_SetSel($ed_Main, 100, 10)

While 1
    $aSel = _GUICtrlEdit_GetSel($ed_Main)
    select
        case $aSel[0] <> $aSelMem[0] 
            GUICtrlSetData($lb_Status, 'Selection anchor: ' & $aSel[1] & '. Selection active: ' & $aSel[0])
        case $aSel[1] <> $aSelMem[1] 
            GUICtrlSetData($lb_Status, 'Selection anchor: ' & $aSel[0] & '. Selection active: ' & $aSel[1])
    endselect
    $aSelMem = $aSel

    $iGUIGetMsg = GUIGetMsg()
    Switch $iGUIGetMsg
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd

I'm obviously missing something.

;o) Cor


nothing is foolproof to the sufficiently talented fool..

Share this post


Link to post
Share on other sites
therks

GetSel doesn't tell you which end of the selection the actual cursor is at. So for example, if you want to alter the text in a selection (make it all uppercase for example), you can't reliably restore the user's selection. Because if their selection goes from char 100, back to character 10, GetSel returns [10, 100] instead of [100, 10].

I would post an example but I'm already in bed, typing this out on my phone. 😁

Share this post


Link to post
Share on other sites
corz

The example I posted tells you which end is the "Anchor".

;o) Cor


nothing is foolproof to the sufficiently talented fool..

Share this post


Link to post
Share on other sites
therks

Ok, well the issue with your example, was the core issue I was trying to deal with. It doesn't work for new selections where neither index matches. ie: If you double click on a word/line, or if _GUICtrlEdit_SetSel is used. There's no natural way to determine which end is active.

Using your example, try clicking that Test button a few times and you'll see the issue I'm talking about.

#include <GUIConstants.au3>
#include <GUIEdit.au3>

$hGUI = GUICreate('Test', 500, 320)
$bt_Test = GUICtrlCreateButton('Test', 0, 0, 500, 20)
$ed_Main = GUICtrlCreateEdit(FileRead(@ScriptFullPath), 0, 20, 500, 280)
$lb_Status = GUICtrlCreateLabel('', 0, 300, 500, 20, BitOR($SS_SUNKEN, $SS_CENTERIMAGE))
GUISetState()

Dim $aSelMem[2]

_GUICtrlEdit_SetSel($ed_Main, 100, 10)

While 1
    $aSel = _GUICtrlEdit_GetSel($ed_Main)
    select
        case $aSel[0] <> $aSelMem[0] 
            GUICtrlSetData($lb_Status, 'Selection anchor: ' & $aSel[1] & '. Selection active: ' & $aSel[0])
        case $aSel[1] <> $aSelMem[1] 
            GUICtrlSetData($lb_Status, 'Selection anchor: ' & $aSel[0] & '. Selection active: ' & $aSel[1])
    endselect
    $aSelMem = $aSel

    $iGUIGetMsg = GUIGetMsg()
    Switch $iGUIGetMsg
        Case $bt_Test
            $iR1 = Random(0, _GUICtrlEdit_GetTextLen($ed_Main), 1)
            $iR2 = Random(0, _GUICtrlEdit_GetTextLen($ed_Main), 1)
            _GUICtrlEdit_SetSel($ed_Main, $iR1, $iR2)
            GUICtrlSetData($bt_Test, 'Test - Anchor: ' & $iR1 & '. Active: ' & $iR2)
        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd

I realize it is a rather niche issue. Regardless, I have figured out a way to write the function with minimal blinking using a Global variable to track the selection, as @Subz suggested. I would post it here but I'm still fine tuning it at the moment.

Share this post


Link to post
Share on other sites
corz

Niche is good. Though I wish I knew what you were trying to actually DO. Is it a secret?

With _GUICtrlEdit_SetSel() The first point set is the anchor - it says so in your version of the script. The "natural" way to tell is to look how you coded it! Or read the info in the GUI. And with double-click, the left point is always the anchor (in L2R languages).

I don't get it. But then, I have no idea what you actually need that the above example doesn't provide.

;o) Cor


nothing is foolproof to the sufficiently talented fool..

Share this post


Link to post
Share on other sites
therks

I have this sort of IDE for AutoIt I've been working on for a few years. I'm trying to handle things like indenting & un-indenting selections, find/replace in selection, ctrl+shift+arrow keys, etc. A lot of that relies on user selections and I was trying to have things work as smoothly as possible. I also have a status bar with info like Scite, and I was getting incorrect results just relying on the default _GetSel() function. 

I also wanted to have the function written to be stand-alone so that I can easily #include it in any other project I want to in the future. 

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

  • Similar Content

    • ahha
      By ahha
      I'm using the excellent _Excel UDF to read a whole spreadsheet into an array I want to operate on.  I can read a specified range without a problem.  What I'd like to do is allow the user in Excel to select a range (contiguous is fine) and be able to read that range so that I know what range to operate on without having the user input the range via a keyboard.  I'm stuck and any hints greatly appreciated.  The code below uses the Helpfile .xls to illustrate where I crash.
      ; #AutoIt3Wrapper_run_debug_mode=Y ; use this to debug in console window <--- LOOK #include <Excel.au3> #include <MsgBoxConstants.au3> #include <Debug.au3> ;for _DebugArrayDisplay $sExcelFullFileName = "C:\Program Files (x86)\AutoIt3\Examples\Helpfile\Extras\_Excel1.xls" ;use Autoit test for example $oExcel = _Excel_Open() ;Create application object and open an Excel workbook $oWorkbook = _Excel_BookOpen($oExcel, $sExcelFullFileName) $aExcelArray = _Excel_RangeRead($oWorkbook, Default) _DebugArrayDisplay($aExcelArray, $aExcelArray) ;let's look at it $aI5K6 = _Excel_RangeRead($oWorkbook, Default,"I5:K6") ;read a rangeI5:K6 and return value _DebugArrayDisplay($aI5K6, $aI5K6) ;let's look at range it ;rather than defining the range explicity I'd like to read the selection in Excel and use it ;need a function like _Excel_SelectionRead ;try hacking Excel.au3 _Excel_RangeRead to see if can create _Excel_SelectionRead looks like .Selection .Value .Text and .Address possible MsgBox($MB_SYSTEMMODAL, "Info", "Select cells in Excel then click OK") ;ACTUALLY get range of the selection and this will suffice for us to use on the $aExcelArray $vRange = $oWorkbook.ActiveSheet.Selection.Address($vRange) ;tried all sorts of permutations and clearly I need help _DebugArrayDisplay($vRange, $vRange) ;let's look at range it ;$vResult = $oExcel.Transpose($vRange.Value) ;_DebugArrayDisplay($vResult, $vResult) ;let's look at range it _Excel_Close($oExcel, False, True) Exit  
    • bbProg
      By bbProg
      Hi,
       
      how can I wait activate for windows with information as in the photos attached?
      Class is not being recognized by the script.
       
      thanks in advanced.



    • ur
      By ur
      Is there any UDF to remove all anchor tags <a> with a particular class (and also its sub elements completely) in a html document.
      Here the classes are browse and breadcrumbs
      Like in the below image.


       
      I am not able to find that option in IE.au3
       
      Please suggest.
    • Shirdish_chakravarthi
      By Shirdish_chakravarthi
      Hello Friends i am new to autoit and i am stuck in middle of automation of flashing tool..
      my requirement is i have a window and i have to get the value present in that window (below is the picture)

      in the above window i need to get the value of the highlighted field.the value of this filed keeps on changing...ii need to get the current value present in the field..below are the details of the window and field..

       
      CAN it be done?
       
      thanks

    • spuuunit
      By spuuunit
      Is it possible to know if a textbox is active in FireFox?
       
      This is what I want:
      if (Textbox in FireFox == Active) { }
×