Jump to content

_GUICtrlEdit_GetSel() get anchor/active position


therks
 Share

Recommended Posts

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
Link to comment
Share on other sites

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..

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

 

Link to comment
Share on other sites

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..

Link to comment
Share on other sites

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. 😁

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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..

Link to comment
Share on other sites

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. 

Link to comment
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
 Share

×
×
  • Create New...