Author | Topic: XbpMle Question | |
---|---|---|
Carlos A Beling | XbpMle Question on Tue, 16 Mar 2021 18:37:40 -0300 Good night. Please how can I find a string's position in XbpMle():editbuffer() for to mark it? Fraternally Beling | |
Andreas Gehrs-Pahl | Re: XbpMle Question on Tue, 16 Mar 2021 22:17:57 -0400 Carlos, >Please how can I find a string's position in XbpMle():editbuffer() for >to mark it? The following three methods are copied from my custom MLE class "AGP_Text". They include calls to a lot of functions and procedures that you won't have or need, so you can't compile them, but the code should explain how to do this in principle. The ::Find_Text() method finds the first or next occurrence of a string in the MLE and optionally displays a dialog to enter a new search string. The ::Set_Cursor() method calculates and stores the positions of the text to be displayed and any highlighted area. The ::Restore_Cursor() method moves the cursor to a particular position in the MLE, and if necessary, scrolls the required text into view, and also optionally highlights a particular area. This is also used when focus is restored from a different dialog. The only standard MLE methods that you really need to use are: * ::CharFromLine() * ::LineFromChar() * ::QueryFirstChar() * ::QueryMarked() * ::SetFirstChar() * ::SetMarked() They are all documented in the Xbase++ online documentation. Some longer lines of the following source code will probably wrap. ****************************** * AGP_Text: Find_Text Method * ****************************** Method AGP_Text:Find_Text(lNewSearch) LOCAL nLines := int(::CurrentSize()[2] / ::SetFont():Height) LOCAL nPos := ::Pos() LOCAL aText := {010, 050, 070, 320, , 'Search Text:', 'cText', 40, replicate('X', 40), {|x| Validate_Trim(x), .t.}, , , , , .f.} LOCAL cMarked := Get_Text_From_ClipBoard() PRIVATE cText := ::cFindText if empty(cText) .or. lNewSearch if ::CopyMarked() > 0 cText := Get_Text_From_ClipBoard() else Save_Text_to_ClipBoard(cMarked) endif if .not. Input_Dialog('Find Text:', , {440, 100}, {aText}, '~Search', , 'Cancel Text Search?', 1, .t., ID_FIND_TEXT_DIALOG) cText := '' endif endif if .not. empty(cText) ::cFindText := cText nPos := at(upper(cText), upper(::EditBuffer()), nPos + 1) if nPos == 0 nPos := at(upper(cText), upper(::EditBuffer())) endif if nPos > 0 ::nLastPos := nPos ::nLastTopPos := ::CharFromLine(max(1, ::LineFromChar(nPos) - int(nLines / 3))) ::Set_Cursor(nPos, nPos + len(cText)) endif endif return (Self) ******************************* * AGP_Text: Set_Cursor Method * ******************************* Method AGP_Text:Set_Cursor(nPos, nMark) LOCAL nLines := int(::CurrentSize()[2] / ::SetFont():Height) LOCAL nMarkPos := iif(empty(nMark), nPos, nMark) ::nLastPos := nPos if (nPos < ::QueryFirstChar()) .or. (::LineFromChar(nPos) >= (nLines + ::LineFromChar(::QueryFirstChar()))) ::nLastTopPos := nPos endif ::aLastMarked := {nPos, nMarkPos} ::Restore_Cursor() return (::Pos() == nPos) *********************************** * AGP_Text: Restore_Cursor Method * *********************************** Method AGP_Text:Restore_Cursor() LOCAL aMarked := ::aLastMarked LOCAL nCurTop := max(1, ::nLastTopPos) LOCAL nCurPos := max(1, ::nLastPos) LOCAL nMaxPos := max(1, len(::EditBuffer()) + iif(Set(_SET_INSERT), 1, 0)) LOCAL nCols := int(::CurrentSize()[1] / ::SetFont():Width) LOCAL nCurCol := nCurPos - ::CharFromLine(::LineFromChar(nCurPos)) LOCAL nOffset := max(0, int(nCurCol - (nCols / 2))) LOCAL nTopLine := ::LineFromChar(nCurTop) LOCAL nCurLine := ::LineFromChar(nCurPos) ************************************************************************ * Position the Cursor at the Last active Position in the Input Buffer, display the same part of the Input Buffer as was shown previously, and mark the same Text that was previously marked (if any). * ************************************************************************ if empty(::EditBuffer()) aMarked := {1, 1} elseif nCurPos > nMaxPos aMarked := {nMaxPos, nMaxPos} endif if ::WordWrap .or. .not. ::HorizScroll ::SetFirstChar(nCurTop) else while nTopLine < nCurLine if abs(::CharFromLine(nTopLine) - ::CharFromLine(nTopLine + 1)) >= nOffset ::SetFirstChar(::CharFromLine(nTopLine) + nOffset) ; exit else nTopLine++ endif enddo if nTopLine == nCurLine ::SetFirstChar(::CharFromLine(nCurLine) + nOffset) endif endif ::SetMarked(aMarked) return (Self) Hope that helps, Andreas Andreas Gehrs-Pahl Absolute Software, LLC phone: (989) 723-9927 email: Andreas@AbsoluteSoftwareLLC.com web: http://www.AbsoluteSoftwareLLC.com [L]: https://www.LinkedIn.com/in/AndreasGehrsPahl [F]: https://www.FaceBook.com/AbsoluteSoftwareLLC | |
Carlos A Beling | Re: XbpMle Question on Wed, 17 Mar 2021 10:10:50 -0300 HI Andreas. God day. Again many thanks. Just one question: In the code below: > nPos := at(upper(cText), upper(::EditBuffer()), nPos + 1) > if nPos == 0 > nPos := at(upper(cText), upper(::EditBuffer())) > endif I think that at(upper(cText), upper(::EditBuffer()), nPos + 1) will return a position considering the CRLF existing in ::EditBuffer(). If that is true, may the method ::LineFromChar(nPos) return unreal line number? Fraternally Beling On 16/03/2021 23:17, Andreas Gehrs-Pahl wrote: > Carlos, > >> Please how can I find a string's position in XbpMle():editbuffer() for >> to mark it? > > The following three methods are copied from my custom MLE class "AGP_Text". > They include calls to a lot of functions and procedures that you won't have > or need, so you can't compile them, but the code should explain how to do > this in principle. > > The ::Find_Text() method finds the first or next occurrence of a string in > the MLE and optionally displays a dialog to enter a new search string. > > The ::Set_Cursor() method calculates and stores the positions of the text to > be displayed and any highlighted area. > > The ::Restore_Cursor() method moves the cursor to a particular position in > the MLE, and if necessary, scrolls the required text into view, and also > optionally highlights a particular area. This is also used when focus is > restored from a different dialog. > > The only standard MLE methods that you really need to use are: > * ::CharFromLine() > * ::LineFromChar() > * ::QueryFirstChar() > * ::QueryMarked() > * ::SetFirstChar() > * ::SetMarked() > > They are all documented in the Xbase++ online documentation. > > Some longer lines of the following source code will probably wrap. > > ****************************** > * AGP_Text: Find_Text Method * > ****************************** > Method AGP_Text:Find_Text(lNewSearch) > LOCAL nLines := int(::CurrentSize()[2] / ::SetFont():Height) > LOCAL nPos := ::Pos() > LOCAL aText := {010, 050, 070, 320, , 'Search Text:', 'cText', 40, replicate('X', 40), {|x| Validate_Trim(x), .t.}, , , , , .f.} > LOCAL cMarked := Get_Text_From_ClipBoard() > PRIVATE cText := ::cFindText > if empty(cText) .or. lNewSearch > if ::CopyMarked() > 0 > cText := Get_Text_From_ClipBoard() > else > Save_Text_to_ClipBoard(cMarked) > endif > if .not. Input_Dialog('Find Text:', , {440, 100}, {aText}, '~Search', , 'Cancel Text Search?', 1, .t., ID_FIND_TEXT_DIALOG) > cText := '' > endif > endif > if .not. empty(cText) > ::cFindText := cText > nPos := at(upper(cText), upper(::EditBuffer()), nPos + 1) > if nPos == 0 > nPos := at(upper(cText), upper(::EditBuffer())) > endif > if nPos > 0 > ::nLastPos := nPos > ::nLastTopPos := ::CharFromLine(max(1, ::LineFromChar(nPos) - int(nLines / 3))) > ::Set_Cursor(nPos, nPos + len(cText)) > endif > endif > return (Self) > > ******************************* > * AGP_Text: Set_Cursor Method * > ******************************* > Method AGP_Text:Set_Cursor(nPos, nMark) > LOCAL nLines := int(::CurrentSize()[2] / ::SetFont():Height) > LOCAL nMarkPos := iif(empty(nMark), nPos, nMark) > ::nLastPos := nPos > if (nPos < ::QueryFirstChar()) .or. (::LineFromChar(nPos) >= (nLines + ::LineFromChar(::QueryFirstChar()))) > ::nLastTopPos := nPos > endif > ::aLastMarked := {nPos, nMarkPos} > ::Restore_Cursor() > return (::Pos() == nPos) > > *********************************** > * AGP_Text: Restore_Cursor Method * > *********************************** > Method AGP_Text:Restore_Cursor() > LOCAL aMarked := ::aLastMarked > LOCAL nCurTop := max(1, ::nLastTopPos) > LOCAL nCurPos := max(1, ::nLastPos) > LOCAL nMaxPos := max(1, len(::EditBuffer()) + iif(Set(_SET_INSERT), 1, 0)) > LOCAL nCols := int(::CurrentSize()[1] / ::SetFont():Width) > LOCAL nCurCol := nCurPos - ::CharFromLine(::LineFromChar(nCurPos)) > LOCAL nOffset := max(0, int(nCurCol - (nCols / 2))) > LOCAL nTopLine := ::LineFromChar(nCurTop) > LOCAL nCurLine := ::LineFromChar(nCurPos) > ************************************************************************ > * Position the Cursor at the Last active Position in the Input Buffer, * > * display the same part of the Input Buffer as was shown previously, * > * and mark the same Text that was previously marked (if any). * > ************************************************************************ > if empty(::EditBuffer()) > aMarked := {1, 1} > elseif nCurPos > nMaxPos > aMarked := {nMaxPos, nMaxPos} > endif > if ::WordWrap .or. .not. ::HorizScroll > ::SetFirstChar(nCurTop) > else > while nTopLine < nCurLine > if abs(::CharFromLine(nTopLine) - ::CharFromLine(nTopLine + 1)) >= nOffset > ::SetFirstChar(::CharFromLine(nTopLine) + nOffset) ; exit > else > nTopLine++ > endif > enddo > if nTopLine == nCurLine > ::SetFirstChar(::CharFromLine(nCurLine) + nOffset) > endif > endif > ::SetMarked(aMarked) > return (Self) > > Hope that helps, > > Andreas > | |
Andreas Gehrs-Pahl | Re: XbpMle Question on Thu, 18 Mar 2021 14:04:36 -0400 Carlos, >I think that at(upper(cText), upper(::EditBuffer()), nPos + 1) will >return a position considering the CRLF existing in ::EditBuffer(). >If that is true, may the method ::LineFromChar(nPos) return unreal line >number? This line will check for the NEXT occurrence of the search string "cText" in the :EditBuffer() of the MLE, starting one character "+ 1" after the current (last found) position "nPos". If there is no (further) match, the next three lines will check for the FIRST occurrence of the search string "cText" in the :EditBuffer() of the MLE. After that, "nPos" will either be 0 (Zero), if no match was found, or the number of the first character position of "cText" in the :EditBuffer() of the MLE. If there are any CRLF characters in the :EditBuffer() or not, shouldn't make any difference. Also, CRLFs don't determine the actual line numbers, unless the ::WordWrap iVar (property) is set to FALSE and ::HorizScroll is set to TRUE -- or all lines are short enough to be displayed in a separate line in the MLE. For more details, see the documentation for the "At()" function as well as for the "XbpMLE()" class. Hope that helps, Andreas Andreas Gehrs-Pahl Absolute Software, LLC phone: (989) 723-9927 email: Andreas@AbsoluteSoftwareLLC.com web: http://www.AbsoluteSoftwareLLC.com [L]: https://www.LinkedIn.com/in/AndreasGehrsPahl [F]: https://www.FaceBook.com/AbsoluteSoftwareLLC | |
Carlos A Beling | Re: XbpMle Question on Thu, 18 Mar 2021 15:52:17 -0300 Hi Andreas: Good afternoon. Many thanks again. Fraternally Beling On 18/03/2021 15:04, Andreas Gehrs-Pahl wrote: > Carlos, > >> I think that at(upper(cText), upper(::EditBuffer()), nPos + 1) will >> return a position considering the CRLF existing in ::EditBuffer(). >> If that is true, may the method ::LineFromChar(nPos) return unreal line >> number? > > This line will check for the NEXT occurrence of the search string "cText" in > the :EditBuffer() of the MLE, starting one character "+ 1" after the current > (last found) position "nPos". If there is no (further) match, the next three > lines will check for the FIRST occurrence of the search string "cText" in > the :EditBuffer() of the MLE. > > After that, "nPos" will either be 0 (Zero), if no match was found, or the > number of the first character position of "cText" in the :EditBuffer() of > the MLE. > > If there are any CRLF characters in the :EditBuffer() or not, shouldn't make > any difference. Also, CRLFs don't determine the actual line numbers, unless > the ::WordWrap iVar (property) is set to FALSE and ::HorizScroll is set to > TRUE -- or all lines are short enough to be displayed in a separate line in > the MLE. > > For more details, see the documentation for the "At()" function as well as > for the "XbpMLE()" class. > > Hope that helps, > > Andreas > |