Hi Jose,
I am re-writing my JellyFish Editor for FreeBASIC and I implemented code to move line(s) in the edit window using the keyboard shortcuts CTRL+SHIFT+UP and CTRL+SHIFT+DOWN. It is a very convenient feature because otherwise you need to cut the line, move cursor to insert line, and then paste. It also works with multiple lines.
I have been stealing so much from your CSED Editor (especially the Scintilla stuff) that I thought I would post it here in case you would ever like to add it to your editor. This code is based on C++ code found in the NotePad++ editor.
My code uses the SendMessage functionality rather than the Scintilla direct function pointers.
' call the functions
' Case IDC_FRMMAIN_MNUMOVEUPCURRENTLINE
' Function = Doc_MoveCurrentLines(GetCodeWindowFromCurrentTab, False)
' Case IDC_FRMMAIN_MNUMOVEDOWNCURRENTLINE
' Function = Doc_MoveCurrentLines(GetCodeWindowFromCurrentTab, True)
''
''
Function Doc_GetSelectedLineRange( ByVal hWindow as HWnd, _
ByRef startLine as Integer, _
ByRef endLine as Integer, _
ByRef startPos as Integer, _
ByRef endPos as Integer _
) as Integer
startPos = SendMessage(hWindow, SCI_GETSELECTIONSTART, 0, 0)
endPos = SendMessage(hWindow, SCI_GETSELECTIONEND, 0, 0)
startLine = SendMessage(hWindow, SCI_LINEFROMPOSITION, startPos, 0)
endLine = SendMessage(hWindow, SCI_LINEFROMPOSITION, endPos, 0)
Dim nCol as Integer = SendMessage(hWindow, SCI_GETCOLUMN, endPos, 0)
If (nCol = 0) And (endLine > startLine) Then endLine = endLine - 1
Function = 0
End Function
''
''
Function Doc_CurrentLineUp( ByVal hWindow as HWnd ) as Integer
Dim currentLine as Integer = Doc_GetCurrentLineNumber(hWindow)
If (currentLine <> 0) Then
SendMessage(hWindow, SCI_BEGINUNDOACTION, 0, 0)
currentLine = currentLine -1
SendMessage(hWindow, SCI_LINETRANSPOSE, 0, 0)
SendMessage(hWindow, SCI_GOTOLINE, currentLine, 0)
SendMessage(hWindow, SCI_ENDUNDOACTION, 0, 0)
End If
Function = 0
End Function
''
''
Function Doc_CurrentLineDown( ByVal hWindow as HWnd ) as Integer
Dim currentLine as Integer = Doc_GetCurrentLineNumber(hWindow)
If currentLine <> SendMessage(hWindow, SCI_GETLINECOUNT, 0, 0) - 1 Then
SendMessage(hWindow, SCI_BEGINUNDOACTION, 0, 0)
currentLine = currentLine + 1
SendMessage(hWindow, SCI_GOTOLINE, currentLine, 0)
SendMessage(hWindow, SCI_LINETRANSPOSE, 0, 0)
SendMessage(hWindow, SCI_ENDUNDOACTION, 0, 0)
End If
Function = 0
End Function
''
''
Function Doc_MoveCurrentLines( ByVal hWindow as HWnd, ByVal flagMoveDown as Integer ) as Integer
Dim startPos as Integer ' // Starting position
Dim endPos as Integer ' // Ending position
Dim startLine as Integer ' // Starting line
Dim endLine as Integer ' // Ending line
Dim line2swap as Integer
Dim nbChar as Integer
Dim nTextLen as Integer
Doc_GetSelectedLineRange( hWindow, startLine, endLine, startPos, endPos )
Dim noSel as Integer = (startLine = endLine)
Dim nbSelLines as Integer = (endLine - startLine + 1)
If flagMoveDown Then
nTextLen = SendMessage(hWindow, SCI_GETTEXTLENGTH, 0, 0)
If (startLine = -1) Or (endLine >= SendMessage(hWindow, SCI_LINEFROMPOSITION, nTextLen, 0)) Then
Exit Function
End If
line2swap = endLine + 1
If (line2swap + 1) = SendMessage(hWindow, SCI_GETLINECOUNT, 0, 0) Then nbChar += 2 ' cr/lf
Else
If (startLine <= 0) Then Exit Function
line2swap = startLine - 1
End If
nbChar = nbChar + SendMessage(hWindow, SCI_LINELENGTH, line2swap, 0)
SendMessage(hWindow, SCI_BEGINUNDOACTION, 0, 0)
SendMessage(hWindow, SCI_GOTOLINE, line2swap, 0)
For i as Integer = 0 To nbSelLines - 1
If flagMoveDown Then
Doc_CurrentLineUp(hWindow)
Else
Doc_CurrentLineDown(hWindow)
End If
Next
SendMessage(hWindow, SCI_ENDUNDOACTION, 0, 0)
If flagMoveDown Then
SendMessage(hWindow, SCI_SETSELECTIONSTART, startPos + nbChar, 0)
SendMessage(hWindow, SCI_SETSELECTIONEND, IIf(noSel, startPos + nbChar, endPos + nbChar), 0)
Else
SendMessage(hWindow, SCI_SETSELECTIONSTART, startPos - nbChar, 0)
SendMessage(hWindow, SCI_SETSELECTIONEND, IIf(noSel, startPos - nbChar, endPos - nbChar), 0)
End If
Function = 0
End Function
Good tip. Thanks for sharing.
I'm no longer in the business of making code editors. Too time consuming.
So if you are writing one in FreeBasic, maybe I will end using it. Currently, I'm using an adaptation of CSED for my FreeBasic tests.
I wrote CSED for PB during the beta testing of the PBWin 10 / PBCC 6 compilers as a non trivial way of thorughly testing both the compilers and my new headers. This is why it uses many of the new features, such classes, unicode, collections, etc. This way, I discovered many bugs that maybe I could have not discover using trivial tests.
When I released it, I said that it was a "template" that others could use as a starting point to build other versions.