Sign in to follow this  
Followers 0
qwert

Looking for easier ways to navigate rich edits

14 posts in this topic

In working with multi-line rich text controls, I've found it difficult to navigate to individual lines and to characters within lines.  As an example, consider the following GUI.

1.  Is there a better method to navigate to the home position?

2.  Is there a better way to navigate to the next line?

;
;  Insert Line Numbers
;
#include <GuiRichEdit.au3>
#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

$text = "This is an example" & @CRLF & "of a five-line rich" & @CRLF & "text control ... to which" & @CRLF & "I would like to add" & @CRLF & "line number prefixes."

$hGUI = GUICreate("Sample RichEdit", 360, 220)
GUISetFont(12)
$hRichEdit = _GUICtrlRichEdit_Create($hGUI, $text, 10, 10, 230, 200, BitOR($WS_HSCROLL, $ES_AUTOVSCROLL, $ES_MULTILINE, $WS_VSCROLL))
_GUICtrlRichEdit_SetSel($hRichEdit, 0, -1)
_GUICtrlRichEdit_SetFont($hRichEdit, 12)
_GUICtrlRichEdit_SetSel($hRichEdit, -1, -1)     ; IS THERE A BETTER WAY TO NAVIGATE TO THE HOME POSITION?
_GUICtrlRichEdit_GotoCharPos($hRichEdit, 0)
$Button = GUICtrlCreateButton("Insert Nums", 250, 40, 100, 30)
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            _GUICtrlRichEdit_Destroy($hRichEdit)
            GUIDelete()
            ExitLoop
        Case $Button
            _InsertNums()
    EndSwitch
WEnd

Func _InsertNums()
Local $lines = _GUICtrlRichEdit_GetLineCount($hRichEdit)
_GUICtrlRichEdit_GotoCharPos($hRichEdit, 0)
    For $i = 1 to $lines Step 1
        _GUICtrlRichEdit_InsertText($hRichEdit, "Line " & $i & ": ")
;        _GUICtrlRichEdit_ScrollLines ($hRichEdit, 1)
        ControlSend($hGui, "", $hRichEdit, "{DOWN}")    ; IS THERE A BETTER WAY TO NAVIGATE TO THE NEXT LINE?
        ControlSend($hGui, "", $hRichEdit, "{HOME}")
    Next
EndFunc

Thanks in advance for any suggestions.

 

Share this post


Link to post
Share on other sites



 

Honestly I only know about autoit 20 days . After 1 time tinkering , it's first product , so I want to complete it . But knowledge is limited, can not be done

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Try this. I don't know of a better way to select to the end of the rich edit, SetSel is always what I've done. As for your _InsertNums, you use _GUICtrlRichEdit_GetFirstCharPosOnLIne to get the insert point.

#include <GuiRichEdit.au3>
#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

$text = "This is an example" & @CRLF & "of a five-line rich" & @CRLF & "text control ... to which" & @CRLF & "I would like to add" & @CRLF & "line number prefixes."

$hGUI = GUICreate("Sample RichEdit", 360, 220)
GUISetFont(12)
$hRichEdit = _GUICtrlRichEdit_Create($hGUI, $text, 10, 10, 230, 200, BitOR($WS_HSCROLL, $ES_AUTOVSCROLL, $ES_MULTILINE, $WS_VSCROLL))
_GUICtrlRichEdit_SetSel($hRichEdit, 0, -1)
_GUICtrlRichEdit_SetFont($hRichEdit, 12)
_GUICtrlRichEdit_SetSel($hRichEdit, -1, -1) ; IS THERE A BETTER WAY TO NAVIGATE TO THE HOME POSITION?
_GUICtrlRichEdit_GotoCharPos($hRichEdit, 0)
$Button = GUICtrlCreateButton("Insert Nums", 250, 40, 100, 30)
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            _GUICtrlRichEdit_Destroy($hRichEdit)
            GUIDelete()
            ExitLoop
        Case $Button
            _InsertNums()
    EndSwitch
WEnd

Func _InsertNums()
    Local $lines = _GUICtrlRichEdit_GetLineCount($hRichEdit)
    For $i = 1 To $lines Step 1
        _GUICtrlRichEdit_GotoCharPos($hRichEdit, _GUICtrlRichEdit_GetFirstCharPosOnLine($hRichEdit, $i))
        _GUICtrlRichEdit_InsertText($hRichEdit, "Line " & $i & ": ")
    Next
EndFunc   ;==>_InsertNums
Edited by InunoTaishou

Share this post


Link to post
Share on other sites
Quote

        _GUICtrlRichEdit_GotoCharPos($hRichEdit, _GUICtrlRichEdit_GetFirstCharPosOnLine($hRichEdit, $i))

Yes, that works ... and I like it much better than the ControlSend's.  In the future, maybe a UDF can provide some basic navigation, like "GoToNextLine".

Thanks for your help with this.

 

 

Share this post


Link to post
Share on other sites

You mean, something like this?

Func _GUICtrlRichEdit_GoToNextLine($hWnd, $iSelPoint = -1, Const $bMoveToEnd = True)
    Local $iCpFirst = 0
    Local $iCurrentLine = 0
    Local $iCpNextLine = 0
    Local $aGetSel
    Local $sTextInRange = ""
    Local $sTextInCurrentLine = ""
    Local $sTextInNextLine = ""
    Local $iRangeLength = 0
    Local $iCurrentLineLength = 0
    Local $iNextLineLength = 0
    Local $iLineCount = _GUICtrlRichEdit_GetLineCount($hWnd)
    If (@error) Then Return SetError(@error, 0, False)

    $iCpFirst = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd)
    If (@error) Then Return SetError(@error, 0, False)
    $iCurrentLine = _GUICtrlRichEdit_GetLineNumberFromCharPos($hWnd, $iCpFirst)
    If (@error) Then Return SetError(@error, 0, False)

    If ($iLineCount < $iCurrentLine + 1) Then Return ($bMoveToEnd ? _GUICtrlRichEdit_SetSel($hWnd, -1, -1) : _GUICtrlRichEdit_GotoCharPos($hWnd, $iCpFirst))

    $iCpNextLine = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd, $iCurrentLine + 1)
    If (@error) Then Return SetError(@error, 0, False)

    If ($iSelPoint = -1) Then
        $aGetSel = _GUICtrlRichEdit_GetSel($hWnd)
        If (@error) Then Return SetError(@error, 0, False)

        If ($aGetSel[1] > 0 And $iCpFirst <> $aGetSel[1]) Then
            $sTextInRange = _GUICtrlRichEdit_GetTextInRange($hWnd, $iCpFirst, $aGetSel[1])
            If (@error) Then Return SetError(@error, 0, False)
            $sTextInCurrentLine = _GUICtrlRichEdit_GetTextInLine($hWnd, $iCurrentLine)
            If (@error) Then Return SetError(@error, 0, False)
            $sTextInNextLine = _GUICtrlRichEdit_GetTextInLine($hWnd, $iCurrentLine + 1)
            If (@error) Then Return SetError(@error, 0, False)
        EndIf

        $iRangeLength = StringLen($sTextInRange)
        $iCurrentLineLength = StringLen($sTextInCurrentLine)
        $iNextLineLength = StringLen($sTextInNextLine)

        If ($iRangeLength = $iCurrentLineLength) Then
            $iSelPoint = $iNextLineLength
        ElseIf ($iRangeLength > $iNextLineLength) Then
            $iSelPoint = $iNextLineLength
        ElseIf ($iRangeLength <= $iNextLineLength) Then
            $iSelPoint = $iRangeLength
        Else
            $iSelPoint = 0
        EndIf
    EndIf

    Return _GUICtrlRichEdit_GotoCharPos($hWnd, $iCpNextLine + $iSelPoint)
EndFunc   ;==>_GUICtrlRichEdit_GoToNextLine

Using -1 for the $iSelPoint will make the select point like if you had used the {Down} arrow. Using 0 for the $iSelPoint will move the selection to the beginning of the next line. Upon reaching the last line, calling GoToNextLine again will move the selection to the very end (this is not something RichEdit does but a lot of other editors will move the selection to the end of the line when you press {Down} on the last line.)

If you don't want it to move the selection to the end then you can use False for the first parameter.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

That is an excellent function ... and operates just as you said.  It certainly fills the need I have at the moment.

That said—and this is in no way meant to take away from what you've done—would you consider extending it to provide all line-level navigation? ... First Line ... Last Line ... Previous Line ... (and a specific line, of course) ... and all using the character position params you've defined.  I ask because you obviously have a good handle on the RichEdit function set.  As I stated in my original post, navigating rich edits has been a problem every time I've worked with them.

But in any event, thanks for providing the function.  It's a great benefit to have it.

 

 

 

 

Edited by qwert

Share this post


Link to post
Share on other sites

Well I did have the free time, I'm sure it'll be useful for others as well. Plus, RichEdit is my favorite thing to play with.

Changed it a little bit but it still works the same. You can use the $iCharPos to set where to go to on the line you're moving to. If it's -2 then it's treated the same way as using your {Up} and {Down} arrow keys in the edit, using -1 will move to the end of the line, and using 0 will move to the beginning of the line. Think of it the same way as _GUICtrlRichEdit_GoToCharPos except you can specify what line to move to.

#include <GuiRichEdit.au3>
#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

Global Const $sText = "This is a new example" & @CRLF & "using a richedit control with" & @CRLF & "a few extra navigation" & @CRLF & "functions. Allowing you to" & @CRLF & "navigate through a richedit" & @CRLF & "control!"

Global $hGUI = GUICreate("Sample RichEdit", 396, 232)
Global $hRichEdit = _GUICtrlRichEdit_Create($hGUI, $sText, 8, 8, 256, 192, BitOR($WS_HSCROLL, $ES_AUTOVSCROLL, $ES_MULTILINE, $WS_VSCROLL))
Global $btnGoToFirst = GUICtrlCreateButton("Go To First Line", 264, 8, 96, 24)
Global $btnPrevLine = GUICtrlCreateButton("Go To Prev Line", 264, 36, 96, 24)
Global $btnGoToLine = GUICtrlCreateButton("Go To Line", 264, 64, 96, 24)
Global $inpLineNum = GUICtrlCreateInput(5, 364, 64, 24, 24)
Global $btnNextLine = GUICtrlCreateButton("Go To Next Line", 264, 92, 96, 24)
Global $btnGoToLast = GUICtrlCreateButton("Go To Last Line", 264, 120, 96, 24)
Global $inpCharPos = GUICtrlCreateInput(-2, 364, 152, 24, 24)
Global $lblOutput = GUICtrlCreateLabel("", 8, 200, 216, 32)
GUICtrlCreateLabel("$iCharPos = ", 264, 152, 96, 24)
GUICtrlSetFont(-1, 10)

_GUICtrlRichEdit_SetSel($hRichEdit, 0, -1)
_GUICtrlRichEdit_SetFont($hRichEdit, 12, "Segoe UI")
_GUICtrlRichEdit_GotoCharPos($hRichEdit, 0)

GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            _GUICtrlRichEdit_Destroy($hRichEdit)
            GUIDelete()
            ExitLoop
        Case $btnGoToFirst
            _GUICtrlRichEdit_GoToFirstLine($hRichEdit, GUICtrlRead($inpCharPos))
            GUICtrlSetData($lblOutput, "Error returned from _GUICtrlRichEdit_GoToFirstLine: " & @Error)
        Case $btnPrevLine
            _GUICtrlRichEdit_GoToPrevLine($hRichEdit, GUICtrlRead($inpCharPos))
            GUICtrlSetData($lblOutput, "Error returned from _GUICtrlRichEdit_GoToPrevLine: " & @Error)
        Case $btnGoToLine
            _GUICtrlRichEdit_GoToLine($hRichEdit, GUICtrlRead($inpLineNum), GUICtrlRead($inpCharPos))
            GUICtrlSetData($lblOutput, "Error returned from _GUICtrlRichEdit_GoToLine: " & @Error)
        Case $btnNextLine
            _GUICtrlRichEdit_GoToNextLine($hRichEdit, GUICtrlRead($inpCharPos))
            GUICtrlSetData($lblOutput, "Error returned from _GUICtrlRichEdit_GoToNextLine: " & @Error)
        Case $btnGoToLast
            _GUICtrlRichEdit_GoToLastLine($hRichEdit, GUICtrlRead($inpCharPos))
            GUICtrlSetData($lblOutput, "Error returned from _GUICtrlRichEdit_GoToLastLine: " & @Error)
    EndSwitch
WEnd

Func _GUICtrlRichEdit_GoToNextLine($hWnd, $iCharPos = -2, Const $bMoveToEnd = True)
    Local $iCpFirst = 0
    Local $iCurrentLine = 0
    Local $iCpNextLine = 0
    Local $aGetSel
    Local $sTextInRange = ""
    Local $sTextInCurrentLine = ""
    Local $sTextInNextLine = ""
    Local $iRangeLength = 0
    Local $iCurrentLineLength = 0
    Local $iNextLineLength = 0
    Local $iLineCount = _GUICtrlRichEdit_GetLineCount($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)

    $iCpFirst = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)
    $iCurrentLine = _GUICtrlRichEdit_GetLineNumberFromCharPos($hWnd, $iCpFirst)
    If (@Error) Then Return SetError(@Error, 0, False)

    If ($iLineCount < $iCurrentLine + 1) Then Return ($bMoveToEnd ? _GUICtrlRichEdit_GotoCharPos($hWnd, -1) : _GUICtrlRichEdit_GotoCharPos($hWnd, $iCpFirst))

    $iCpNextLine = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd, $iCurrentLine + 1)
    If (@Error) Then Return SetError(@Error, 0, False)

    $aGetSel = _GUICtrlRichEdit_GetSel($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)

    If ($aGetSel[1] > 0 And $iCpFirst <> $aGetSel[1]) Then
        $sTextInRange = _GUICtrlRichEdit_GetTextInRange($hWnd, $iCpFirst, $aGetSel[1])
        If (@Error) Then Return SetError(@Error, 0, False)
    EndIf

    $sTextInCurrentLine = _GUICtrlRichEdit_GetTextInLine($hWnd, $iCurrentLine)
    If (@Error) Then Return SetError(@Error, 0, False)
    $sTextInNextLine = _GUICtrlRichEdit_GetTextInLine($hWnd, $iCurrentLine + 1)
    If (@Error) Then Return SetError(@Error, 0, False)

    $iRangeLength = StringLen($sTextInRange)
    $iCurrentLineLength = StringLen($sTextInCurrentLine)
    $iNextLineLength = StringLen($sTextInNextLine)

    If ($iCharPos = -2) Then
        If ($iRangeLength = $iCurrentLineLength Or $iRangeLength > $iNextLineLength) Then
            $iCharPos = $iNextLineLength
        ElseIf ($iRangeLength <= $iNextLineLength) Then
            $iCharPos = $iRangeLength
        Else
            $iCharPos = 0
        EndIf
    ElseIf (($iCharPos = -1) Or ($iCharPos > 0 And $iNextLineLength > $iCharPos)) Then
        $iCharPos = $iNextLineLength
    EndIf

    Return _GUICtrlRichEdit_GotoCharPos($hWnd, $iCpNextLine + $iCharPos)
EndFunc   ;==>_GUICtrlRichEdit_GoToNextLine

Func _GUICtrlRichEdit_GoToPrevLine($hWnd, $iCharPos = -2, Const $bMoveToBegin = True)
    Local $iCpFirst = 0
    Local $iCurrentLine = 0
    Local $iCpPrevLine = 0
    Local $aGetSel
    Local $sTextInRange = ""
    Local $sTextInCurrentLine = ""
    Local $sTextInPrevLine = ""
    Local $iRangeLength = 0
    Local $iCurrentLineLength = 0
    Local $iPrevLineLength = 0
    Local $iLineCount = _GUICtrlRichEdit_GetLineCount($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)

    $aGetSel = _GUICtrlRichEdit_GetSel($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)

    $iCpFirst = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)
    $iCurrentLine = _GUICtrlRichEdit_GetLineNumberFromCharPos($hWnd, $iCpFirst)
    If (@Error) Then Return SetError(@Error, 0, False)

    If ($iCurrentLine = 1) Then Return ($bMoveToBegin ? _GUICtrlRichEdit_GotoCharPos($hWnd, 0) : _GUICtrlRichEdit_GotoCharPos($hWnd, $aGetSel[1]))

    $iCpPrevLine = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd, $iCurrentLine - 1)
    If (@Error) Then Return SetError(@Error, 0, False)


    If ($aGetSel[1] > 0 And $iCpFirst <> $aGetSel[1]) Then
        $sTextInRange = _GUICtrlRichEdit_GetTextInRange($hWnd, $iCpFirst, $aGetSel[1])
        If (@Error) Then Return SetError(@Error, 0, False)
    EndIf

    $sTextInCurrentLine = _GUICtrlRichEdit_GetTextInLine($hWnd, $iCurrentLine)
    If (@Error) Then Return SetError(@Error, 0, False)
    $sTextInPrevLine = _GUICtrlRichEdit_GetTextInLine($hWnd, $iCurrentLine - 1)
    If (@Error) Then Return SetError(@Error, 0, False)

    $iRangeLength = StringLen($sTextInRange)
    $iCurrentLineLength = StringLen($sTextInCurrentLine)
    $iPrevLineLength = StringLen($sTextInPrevLine)

    If ($iCharPos = -2) Then
        If ($iRangeLength = $iCurrentLineLength Or $iRangeLength > $iPrevLineLength) Then
            $iCharPos = $iPrevLineLength
        ElseIf ($iRangeLength <= $iPrevLineLength) Then
            $iCharPos = $iRangeLength
        Else
            $iCharPos = 0
        EndIf
    ElseIf (($iCharPos = -1) Or ($iCharPos > 0 And $iPrevLineLength > $iCharPos)) Then
        $iCharPos = $iPrevLineLength
    EndIf

    Return _GUICtrlRichEdit_GotoCharPos($hWnd, $iCpPrevLine + $iCharPos)
EndFunc   ;==>_GUICtrlRichEdit_GoToPrevLine

Func _GUICtrlRichEdit_GoToFirstLine($hWnd, $iCharPos = -2, Const $bMoveToBegin = True)
    Local $bRet = _GUICtrlRichEdit_GoToLine($hWnd, 1, $iCharPos, $bMoveToBegin)
    Return (@Error ? SetError(@Error, 0, $bRet) : $bRet)
EndFunc   ;==>_GUICtrlRichEdit_GoToFirstLine

Func _GUICtrlRichEdit_GoToLastLine($hWnd, $iCharPos = -2, Const $bMoveToEnd = True)
    Local $iLineCount = _GUICtrlRichEdit_GetLineCount($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)
    Local $bRet = _GUICtrlRichEdit_GoToLine($hWnd, $iLineCount, $iCharPos, $bMoveToEnd)
    Return (@Error ? SetError(@Error, 0, $bRet) : $bRet)
EndFunc   ;==>_GUICtrlRichEdit_GoToLastLine

Func _GUICtrlRichEdit_GoToLine($hWnd, $iGoToLine, $iCharPos = -2, Const $bMoveToStartEnd = True)
    Local $iCpFirst = 0
    Local $iCurrentLine = 0
    Local $iCpGoToLine = 0
    Local $aGetSel
    Local $sTextInRange = ""
    Local $sTextInCurrentLine = ""
    Local $sTextInGoToLine = ""
    Local $iRangeLength = 0
    Local $iCurrentLineLength = 0
    Local $iGoToLineLength = 0
    Local $iLineCount

    If ($iGoToLine < 1) Then Return SetError(-1021, 0, False)

    $iLineCount = _GUICtrlRichEdit_GetLineCount($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)

    $aGetSel = _GUICtrlRichEdit_GetSel($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)

    $iCpFirst = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)

    $iCurrentLine = _GUICtrlRichEdit_GetLineNumberFromCharPos($hWnd, $iCpFirst)
    If (@Error) Then Return SetError(@Error, 0, False)
    
    If ($iGoToLine >= $iLineCount) Then $iGoToLine = $iLineCount
    If ($iGoToLine = $iLineCount And $iCurrentLine = $iLineCount) Then Return ($bMoveToStartEnd ? _GUICtrlRichEdit_GotoCharPos($hWnd, -1) : _GUICtrlRichEdit_GotoCharPos($hWnd, $aGetSel[1]))
    If ($iGoToLine = 1 And $iCurrentLine = 1) Then Return ($bMoveToStartEnd ? _GUICtrlRichEdit_GotoCharPos($hWnd, 0) : _GUICtrlRichEdit_GotoCharPos($hWnd, $aGetSel[1]))

    $iCpGoToLine = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd, $iGoToLine)
    If (@Error) Then Return SetError(@Error, 0, False)

    If ($aGetSel[1] > 0 And $iCpFirst <> $aGetSel[1]) Then
        $sTextInRange = _GUICtrlRichEdit_GetTextInRange($hWnd, $iCpFirst, $aGetSel[1])
        If (@Error) Then Return SetError(@Error, 0, False)
    EndIf

    $sTextInCurrentLine = _GUICtrlRichEdit_GetTextInLine($hWnd, $iCurrentLine)
    If (@Error) Then Return SetError(@Error, 0, False)
    $sTextInGoToLine = _GUICtrlRichEdit_GetTextInLine($hWnd, $iGoToLine)
    If (@Error) Then Return SetError(@Error, 0, False)

    $iRangeLength = StringLen($sTextInRange)
    $iCurrentLineLength = StringLen($sTextInCurrentLine)
    $iGoToLineLength = StringLen($sTextInGoToLine)

    If ($iCharPos = -2) Then
        If ($iRangeLength = $iCurrentLineLength Or $iRangeLength > $iGoToLineLength) Then
            $iCharPos = $iGoToLineLength
        ElseIf ($iRangeLength <= $iGoToLineLength) Then
            $iCharPos = $iRangeLength
        Else
            $iCharPos = 0
        EndIf
    ElseIf (($iCharPos = -1) Or ($iCharPos > 0 And $iGoToLineLength > $iCharPos)) Then
        $iCharPos = $iGoToLineLength
    EndIf

    Return _GUICtrlRichEdit_GotoCharPos($hWnd, $iCpGoToLine + $iCharPos)
EndFunc   ;==>_GUICtrlRichEdit_GoToLine

 

Share this post


Link to post
Share on other sites

Thank you.  These are great functions.  RichEdit navigation now makes sense.

The only tiny thing I found was that the end-of-line condition is "sticky".  IOW, on line 5, if you have the cursor between the t and e of "navigate" and go next line, previous line, the cursor stays at that character position.  But if you change it to just after the e in "navigate" and do the same next/prev actions, the cursor changes to end-of-line mode.  You might want to have it go straight above (above the "!"), if that's possible.  Or maybe it's fine, as is.  I can see a case for both.

Nonetheless, after a few days of testing, this should be formalized to a UDF!  Anyone working with multi-line richedit controls should use it.

Share this post


Link to post
Share on other sites

I see what you mean. It could be fixed but it looks like it would require a global variable to detect if the position is being moved from end to end or if the position was moving from not at the end of a line to the end of the line of the line moving to. The reason it does that is because "navigate" is 8 chars long, and "control!" is 8 chars long, so it moves it to the end. When you go the next position using -2 for the $iCharPos parameter then it's recognizing that the caret (the blinking cursor) is at the end of the line, so it needs to move to the end.

If you want to preserve where the caret is per line then store the current position on the line yourself and use that for the $iCharPos parameter when you need it

$iCpFirst = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)
    $aGetSel = _GUICtrlRichEdit_GetSel($hWnd)
    If (@Error) Then Return SetError(@Error, 0, False)

    If ($aGetSel[1] > 0 And $iCpFirst <> $aGetSel[1]) Then
        $sTextInRange = _GUICtrlRichEdit_GetTextInRange($hWnd, $iCpFirst, $aGetSel[1])
        If (@Error) Then Return SetError(@Error, 0, False)
    EndIf
    
    $iRangeLength = StringLen($sTextInRange)

You could make a function with this to save where the $iCharPos should be when you want to start moving. It wouldn't matter if the line you're going to is shorter than the saved position because I made it so that if the value you pass in $iCharPos is greater than the line length you're moving to, it will default to the end of that line.

A lot of this code can be shortened too, since each function does the same thing, just different lines. I'll probably end up re-doing it tomorrow to clean it up and store all the repetitive stuff in a function. Looking at it again, I think the other thing I didn't account for is if the $iCharPos is < -2, which will move the caret one line behind where you want to go, so I'll probably fix that too.

Share this post


Link to post
Share on other sites
8 hours ago, InunoTaishou said:

When you go the next position using -2 for the $iCharPos parameter then it's recognizing that the caret (the blinking cursor) is at the end of the line, so it needs to move to the end.

Wouldn't that be appropriate for -1, instead?  That way, -2 would be saying "work at the character level ... and -1 would be "work at the line level".  That's just my thought.  Internally, it may need to be different.

Share this post


Link to post
Share on other sites

-1 will move it to the end regardless of the length of the line you're moving to. -2 will just check to make sure that the line you're moving to is at least as long as where the caret is for the line it's currently on. Since the caret is at the end of "navigate" (8 chars long) and it's trying to move to the next line, which is only the word "control!" (8 chars long), it sees that it can move to that line at the correct character position--the end of the line.

Share this post


Link to post
Share on other sites

Just as a test, in _GUICtrlRichEdit_GoToPrevLine, I changed:

If ($iCharPos = -2) Then
        If ($iRangeLength = $iCurrentLineLength Or $iRangeLength > $iPrevLineLength) Then

To this:

If ($iCharPos = -2) Then
        If ($iRangeLength > $iPrevLineLength) Then

It causes the cursor to move directly above if there is an "above" ... otherwise it moves to the end of the previous line.

I may be oversimplifying, but this gives the behavior I was talking about.  It's just a suggestion, but I think it makes movements more intuitive.  Let me know if there are other considerations.

 

Share this post


Link to post
Share on other sites

Ah yes, you're right. I was thinking about that this morning when I was driving. I have adjusted it. Now it should work as desired. Also shortened it and threw some of the repetitive stuff in a separate functions.

Spoiler
Quote

-2 Works the same as {Up} and {Down} arrows.

-1 Moves caret to the end of specified line.

0 Moves caret to the beginning of specified line.

@Error -1021 is line requested is <1 or > the line count.

@Error -1022 is the $iCharPos used is < -2

 

#include <GuiRichEdit.au3>
#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

Global Const $sText = "This is a new example" & @CRLF & "using a richedit control with" & @CRLF & "a few extra navigation" & @CRLF & "functions. Allowing you to" & @CRLF & "navigate through a richedit" & @CRLF & "control!"

Global $hGUI = GUICreate("Sample RichEdit", 396, 232)
Global $hRichEdit = _GUICtrlRichEdit_Create($hGUI, $sText, 8, 8, 256, 192, BitOR($WS_HSCROLL, $ES_AUTOVSCROLL, $ES_MULTILINE, $WS_VSCROLL))
Global $btnGoToFirst = GUICtrlCreateButton("Go To First Line", 264, 8, 96, 24)
Global $btnPrevLine = GUICtrlCreateButton("Go To Prev Line", 264, 36, 96, 24)
Global $btnGoToLine = GUICtrlCreateButton("Go To Line", 264, 64, 96, 24)
Global $inpLineNum = GUICtrlCreateInput(5, 364, 64, 24, 24)
Global $btnNextLine = GUICtrlCreateButton("Go To Next Line", 264, 92, 96, 24)
Global $btnGoToLast = GUICtrlCreateButton("Go To Last Line", 264, 120, 96, 24)
Global $inpCharPos = GUICtrlCreateInput(-2, 364, 152, 24, 24)
Global $lblOutput = GUICtrlCreateLabel("", 8, 200, 216, 32)
GUICtrlCreateLabel("$iCharPos = ", 264, 152, 96, 24)
GUICtrlSetFont(-1, 10)

_GUICtrlRichEdit_SetSel($hRichEdit, 0, -1)
_GUICtrlRichEdit_SetFont($hRichEdit, 12, "Segoe UI")
_GUICtrlRichEdit_GotoCharPos($hRichEdit, 0)

GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            _GUICtrlRichEdit_Destroy($hRichEdit)
            GUIDelete()
            ExitLoop
        Case $btnGoToFirst
            _GUICtrlRichEdit_GoToFirstLine($hRichEdit, GUICtrlRead($inpCharPos))
            GUICtrlSetData($lblOutput, "Error returned from _GUICtrlRichEdit_GoToFirstLine: " & @error)
        Case $btnPrevLine
            _GUICtrlRichEdit_GoToPrevLine($hRichEdit, GUICtrlRead($inpCharPos))
            GUICtrlSetData($lblOutput, "Error returned from _GUICtrlRichEdit_GoToPrevLine: " & @error)
        Case $btnGoToLine
            _GUICtrlRichEdit_GoToLine($hRichEdit, GUICtrlRead($inpLineNum), GUICtrlRead($inpCharPos))
            GUICtrlSetData($lblOutput, "Error returned from _GUICtrlRichEdit_GoToLine: " & @error)
        Case $btnNextLine
            _GUICtrlRichEdit_GoToNextLine($hRichEdit, GUICtrlRead($inpCharPos))
            GUICtrlSetData($lblOutput, "Error returned from _GUICtrlRichEdit_GoToNextLine: " & @error)
        Case $btnGoToLast
            _GUICtrlRichEdit_GoToLastLine($hRichEdit, GUICtrlRead($inpCharPos))
            GUICtrlSetData($lblOutput, "Error returned from _GUICtrlRichEdit_GoToLastLine: " & @error)
    EndSwitch
WEnd

Func _GUICtrlRichEdit_GoToNextLine($hWnd, $iCharPos = -2, Const $bMoveToEnd = True)
    Local $iCpFirst = 0
    Local $iCurrentLine = 0
    Local $iCpNextLine = 0
    Local $iLineCount = _GUICtrlRichEdit_GetLineCount($hWnd)
    If (@error) Then Return SetError(@error, 0, False)

    $iCurrentLine = _GUICtrlRichEdit_GetCurrentLine($hWnd, $iCpFirst)
    If (@error) Then Return SetError(@error, 0, False)

    If ($iLineCount < $iCurrentLine + 1) Then Return ($bMoveToEnd ? _GUICtrlRichEdit_GotoCharPos($hWnd, -1) : _GUICtrlRichEdit_GotoCharPos($hWnd, $iCpFirst))

    $iCpNextLine = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd, $iCurrentLine + 1)
    If (@error) Then Return SetError(@error, 0, False)

    $iCharPos = _GUICtrlRichEdit_GetCharPosForLine($hWnd, $iCharPos, $iCurrentLine + 1)
    If (@error) Then Return SetError(@error, 0, False)

    Return _GUICtrlRichEdit_GotoCharPos($hWnd, $iCpNextLine + $iCharPos)
EndFunc   ;==>_GUICtrlRichEdit_GoToNextLine

Func _GUICtrlRichEdit_GoToPrevLine($hWnd, $iCharPos = -2, Const $bMoveToBegin = True)
    Local $iCpFirst = 0
    Local $iCurrentLine = 0
    Local $iCpPrevLine = 0
    Local $aGetSel

    $iCurrentLine = _GUICtrlRichEdit_GetCurrentLine($hWnd, $iCpFirst)
    If (@error) Then Return SetError(@error, 0, False)

    $aGetSel = _GUICtrlRichEdit_GetSel($hWnd)
    If (@error) Then Return SetError(@error, 0, False)

    If ($iCurrentLine = 1) Then Return ($bMoveToBegin ? _GUICtrlRichEdit_GotoCharPos($hWnd, 0) : _GUICtrlRichEdit_GotoCharPos($hWnd, $aGetSel[1]))

    $iCpPrevLine = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd, $iCurrentLine - 1)
    If (@error) Then Return SetError(@error, 0, False)

    $iCharPos = _GUICtrlRichEdit_GetCharPosForLine($hWnd, $iCharPos, $iCurrentLine - 1)

    If (@error) Then Return SetError(@error, 0, False)

    Return _GUICtrlRichEdit_GotoCharPos($hWnd, $iCpPrevLine + $iCharPos)
EndFunc   ;==>_GUICtrlRichEdit_GoToPrevLine

Func _GUICtrlRichEdit_GoToFirstLine($hWnd, $iCharPos = -2, Const $bMoveToBegin = True)
    Local $bRet = _GUICtrlRichEdit_GoToLine($hWnd, 1, $iCharPos, $bMoveToBegin)
    Return (@error ? SetError(@error, 0, $bRet) : $bRet)
EndFunc   ;==>_GUICtrlRichEdit_GoToFirstLine

Func _GUICtrlRichEdit_GoToLastLine($hWnd, $iCharPos = -2, Const $bMoveToEnd = True)
    Local $iLineCount = _GUICtrlRichEdit_GetLineCount($hWnd)
    If (@error) Then Return SetError(@error, 0, False)
    Local $bRet = _GUICtrlRichEdit_GoToLine($hWnd, $iLineCount, $iCharPos, $bMoveToEnd)
    Return (@error ? SetError(@error, 0, $bRet) : $bRet)
EndFunc   ;==>_GUICtrlRichEdit_GoToLastLine

Func _GUICtrlRichEdit_GoToLine($hWnd, $iGoToLine, $iCharPos = -2, Const $bMoveToStartEnd = True)
    Local $iCpFirst = 0
    Local $iCurrentLine = 0
    Local $iCpGoToLine = 0
    Local $aGetSel
    Local $iLineCount = _GUICtrlRichEdit_GetLineCount($hWnd)
    If (@error) Then Return SetError(@error, 0, False)

    $iCurrentLine = _GUICtrlRichEdit_GetCurrentLine($hWnd, $iCpFirst)
    If (@error) Then Return SetError(@error, 0, False)

    $aGetSel = _GUICtrlRichEdit_GetSel($hWnd)
    If (@error) Then Return SetError(@error, 0, False)

    If ($iGoToLine = $iLineCount And $iCurrentLine = $iLineCount) Then Return ($bMoveToStartEnd ? _GUICtrlRichEdit_GotoCharPos($hWnd, -1) : _GUICtrlRichEdit_GotoCharPos($hWnd, $aGetSel[1]))
    If ($iGoToLine = 1 And $iCurrentLine = 1) Then Return ($bMoveToStartEnd ? _GUICtrlRichEdit_GotoCharPos($hWnd, 0) : _GUICtrlRichEdit_GotoCharPos($hWnd, $aGetSel[1]))

    $iCpGoToLine = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd, $iGoToLine)
    If (@error) Then Return SetError(@error, 0, False)

    $iCharPos = _GUICtrlRichEdit_GetCharPosForLine($hWnd, $iCharPos, $iCurrentLine - 1)
    If (@error) Then Return SetError(@error, 0, False)

    Return _GUICtrlRichEdit_GotoCharPos($hWnd, $iCpGoToLine + $iCharPos)
EndFunc   ;==>_GUICtrlRichEdit_GoToLine

Func _GUICtrlRichEdit_GetCharPosForLine($hWnd, $iCharPos, Const $iLine)
    Local $iCpFirst = 0
    Local $iCurrentLine = 0
    Local $iCpLine = 0
    Local $aGetSel
    Local $sTextInRange = ""
    Local $sTextInCurrentLine = ""
    Local $sTextInLine = ""
    Local $iRangeLength = 0
    Local $iCurrentLineLength = 0
    Local $iLineLength = 0
    Local $iLineCount = 0

    $iLineCount = _GUICtrlRichEdit_GetLineCount($hWnd)
    If (@error) Then Return SetError(@error, 0, False)

    If ($iLine < 1 Or $iLine > $iLineCount) Then Return SetError(-1021, 0, False)

    $aGetSel = _GUICtrlRichEdit_GetSel($hWnd)
    If (@error) Then Return SetError(@error, 0, False)

    $iCurrentLine = _GUICtrlRichEdit_GetCurrentLine($hWnd, $iCpFirst)

    If ($iLine = $iCurrentLine) Then Return SetError(-1, 0, $iCharPos)

    $iCpLine = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd, $iLine)
    If (@error) Then Return SetError(@error, 0, False)

    If ($aGetSel[1] > 0 And $iCpFirst <> $aGetSel[1]) Then
        $sTextInRange = _GUICtrlRichEdit_GetTextInRange($hWnd, $iCpFirst, $aGetSel[1])
        If (@error) Then Return SetError(@error, 0, False)
    EndIf

    $sTextInCurrentLine = _GUICtrlRichEdit_GetTextInLine($hWnd, $iCurrentLine)
    If (@error) Then Return SetError(@error, 0, False)

    $sTextInLine = _GUICtrlRichEdit_GetTextInLine($hWnd, $iLine)
    If (@error) Then Return SetError(@error, 0, False)

    $iRangeLength = StringLen($sTextInRange)
    $iCurrentLineLength = StringLen($sTextInCurrentLine)
    $iLineLength = StringLen($sTextInLine)

    If ($iCharPos = -2) Then
        If ($iRangeLength > $iLineLength) Then
            $iCharPos = $iLineLength
        ElseIf ($iRangeLength <= $iLineLength) Then
            $iCharPos = $iRangeLength
        EndIf
    ElseIf ($iCharPos = -1) Then
        $iCharPos = $iLineLength
    ElseIf ($iCharPos > 0 And $iLineLength > $iCharPos) Then
        $iCharPos = $iLineLength
    EndIf

    Return $iCharPos
EndFunc   ;==>_GUICtrlRichEdit_GetCharPosForLine

Func _GUICtrlRichEdit_GetCurrentLine($hWnd, ByRef $iCpFirst)
    $iCpFirst = _GUICtrlRichEdit_GetFirstCharPosOnLine($hWnd)
    If (@error) Then Return SetError(@error, 0, False)

    Return _GUICtrlRichEdit_GetLineNumberFromCharPos($hWnd, $iCpFirst)
EndFunc   ;==>_GUICtrlRichEdit_GetCurrentLine

 

Share this post


Link to post
Share on other sites

Excellent.  Five Stars from me!

Thanks, again.

 

 

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  
Followers 0