From 193c2225ada3390c5d169f24b668393b192da8a7 Mon Sep 17 00:00:00 2001 From: Maurilio Longo Date: Tue, 2 May 2000 22:07:12 +0000 Subject: [PATCH] 20000503-00:01 GMT+2 Maurilio Longo --- harbour/ChangeLog | 45 ++++-- harbour/source/rtl/memoedit.prg | 26 +-- harbour/source/rtl/teditor.prg | 277 ++++++++++++++++++-------------- 3 files changed, 200 insertions(+), 148 deletions(-) diff --git a/harbour/ChangeLog b/harbour/ChangeLog index b8074a2d53..4733b91416 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,13 +1,24 @@ +20000503-00:01 GMT+2 Maurilio Longo + + * source/rtl/teditor.prg + + added word wrapping capabilities + * text is saved if user presses K_ALT_W (sorry) this deviates from clipper + but until we find a way to detect real K_CTRL_W it's better than nothing. + ! fixed a bug in text splitting when on last line of text + * source/rtl/memoedit.prg + * changed to match new TEditor capabilities + 20000502-22:04 GMT+1 Victor Szakats * source/lang/msges.c ! Updated by Jose Lalin + 20000502-19:28 GMT+1 Victor Szakats * source/vm/hvm.c % hb_vmFunction() and hb_vmSendFunc() "inlined". - Note that hb_vmFunction() is still there since it's used from one + Note that hb_vmFunction() is still there since it's used from one places in classes.c. - Redundant declaration removed. @@ -24,8 +35,8 @@ ! Typo. * make_gnu.cmd - + Error output redirection readded to be in sync with the other make - files. If you need to customize this for your own taste, please make + + Error output redirection readded to be in sync with the other make + files. If you need to customize this for your own taste, please make a local copy of it before. 20000502-17:15 GMT+1 Ryszard Glab @@ -35,29 +46,29 @@ *source/vm/Makefile -source/rtl/eval.c +source/vm/eval.c - * fixed bug in EVAL function when a parameter was passed using - the reference - * since the EVAL function is using a direct stack access instead - of hb_param() function the file eval.c is now moved into - VM directory - + * fixed bug in EVAL function when a parameter was passed using + the reference + * since the EVAL function is using a direct stack access instead + of hb_param() function the file eval.c is now moved into + VM directory + 20000502-16:22 GMT+1 Ryszard Glab *source/compiler/harbour.l - * fixed syntax: - RETURN ++variable + * fixed syntax: + RETURN ++variable 20000502-16:07 GMT+1 Ryszard Glab *source/compiler/hbpcode.c - * increased buffers size used by sprintf to avoid GPF/code dumps - + * increased buffers size used by sprintf to avoid GPF/code dumps + 20000502-14:55 GMT+1 Ryszard Glab *source/vm/hvm.c - * fixed bug during accessing a constant arrays caused by - the optimization - { 1, 2, 3 }[ n ] + * fixed bug during accessing a constant arrays caused by + the optimization - { 1, 2, 3 }[ n ] 20000502-14:25 GMT+1 Ryszard Glab @@ -75,8 +86,8 @@ * source/compiler/hbfix.c * source/compiler/genc.c * source/vm/hvm.c - + HB_P_SEND and HB_P_SENDSHORT pcodes added. At this moment they are - exactly the same as HB_P_FUNCTION[SHORT]. More work is needed to + + HB_P_SEND and HB_P_SENDSHORT pcodes added. At this moment they are + exactly the same as HB_P_FUNCTION[SHORT]. More work is needed to optimize the stack usage for SEND/DO/FUNCTION. + hb_vmSend() function added. diff --git a/harbour/source/rtl/memoedit.prg b/harbour/source/rtl/memoedit.prg index 146b379094..c608e0efee 100644 --- a/harbour/source/rtl/memoedit.prg +++ b/harbour/source/rtl/memoedit.prg @@ -38,17 +38,17 @@ #include "common.ch" -FUNCTION MemoEdit( cString,; - nTop, nLeft,; - nBottom, nRight,; - lEditMode,; - cUserFunction,; - nLineLength,; - nTabSize,; - nTextBuffRow,; - nTextBuffColumn,; - nWindowRow,; - nWindowColumn ) +FUNCTION MemoEdit(cString,; + nTop, nLeft,; + nBottom, nRight,; + lEditMode,; + cUserFunction,; + nLineLength,; + nTabSize,; + nTextBuffRow,; + nTextBuffColumn,; + nWindowRow,; + nWindowColumn) LOCAL oEd @@ -64,10 +64,10 @@ FUNCTION MemoEdit( cString,; DEFAULT nWindowRow TO 0 DEFAULT nWindowColumn TO nTextBuffColumn - oEd := TEditor():New( cString, nTop, nLeft, nBottom, nRight, lEditMode ) + oEd := TEditor():New(cString, nTop, nLeft, nBottom, nRight, lEditMode, nil, nLineLength, nTabSize) oEd:RefreshWindow() - if ! ISLOGICAL( cUserFunction ) .OR. cUserFunction == .T. + if ! ISLOGICAL(cUserFunction) .OR. cUserFunction == .T. oEd:Edit() if oEd:lSaved cString := oEd:GetText() diff --git a/harbour/source/rtl/teditor.prg b/harbour/source/rtl/teditor.prg index a9fa116fae..d16f593983 100644 --- a/harbour/source/rtl/teditor.prg +++ b/harbour/source/rtl/teditor.prg @@ -43,38 +43,40 @@ CLASS TEditor - DATA cFile INIT "" // name of file being edited + DATA cFile INIT "" // name of file being edited - DATA aText INIT {} // array with lines of text being edited - DATA naTextLen INIT 0 // number of lines of text inside aText. Len function is not OK since deleting elements from - // array creates NIL elements at array end which kill every text funcion (like substr) used on - // array elements + DATA aText INIT {} // array with lines of text being edited + DATA naTextLen INIT 0 // number of lines of text inside aText. Len function is not OK since deleting elements from + // array creates NIL elements at array end which kill every text funcion (like substr) used on + // array elements - DATA nTop // boundaries of editor window, without box around + DATA nTop // boundaries of editor window, without box around DATA nLeft DATA nBottom DATA nRight - DATA nFirstCol INIT 1 // FirstCol/Row of current text visible inside editor window - DATA nFirstRow INIT 1 - DATA nRow INIT 1 // Cursor position inside aText (nRow) and inside current line of text (nCol) - DATA nCol INIT 1 - DATA nNumCols INIT 1 // How many columns / rows can be displayed inside editor window - DATA nNumRows INIT 1 + DATA nFirstCol INIT 1 // FirstCol/Row of current text visible inside editor window + DATA nFirstRow INIT 1 + DATA nRow INIT 1 // Cursor position inside aText (nRow) and inside current line of text (nCol) + DATA nCol INIT 1 + DATA nNumCols INIT 1 // How many columns / rows can be displayed inside editor window + DATA nNumRows INIT 1 - DATA lInsert INIT .F. // Is editor in Insert mode or in Overstrike one? - DATA nTabWidth INIT 8 // Size of Tab chars - DATA lEditAllow INIT .T. // Are changes to text allowed? - DATA lSaved INIT .F. // True if user exited editor with K_CTRL_W + DATA lInsert INIT .F. // Is editor in Insert mode or in Overstrike one? + DATA nTabWidth INIT 8 // Size of Tab chars + DATA lEditAllow INIT .T. // Are changes to text allowed? + DATA lSaved INIT .F. // True if user exited editor with K_CTRL_W + DATA lWordWrap INIT .F. // True if word wrapping is active + DATA nWordWrapCol INIT 0 // At which column word wrapping occurs - METHOD New(cString, nTop, nLeft, nBottom, nRight, lEditMode) + METHOD New(cString, nTop, nLeft, nBottom, nRight, lEditMode, cUdF, nLineLength, nTabSize) METHOD GetText() // Returns aText as a string (for MemoEdit()) METHOD RefreshWindow() METHOD RefreshLine() METHOD RefreshColumn() METHOD MoveCursor(nKey) METHOD InsertState(lInsState) // Changes lInsert value and insertion / overstrike mode of editor - METHOD Edit() + METHOD Edit(nPassedKey) ENDCLASS @@ -125,7 +127,7 @@ METHOD GetText() CLASS TEditor return cString -METHOD New(cString, nTop, nLeft, nBottom, nRight, lEditMode) CLASS TEditor +METHOD New(cString, nTop, nLeft, nBottom, nRight, lEditMode, cUdF, nLineLength, nTabSize) CLASS TEditor ::aText := Text2Array(cString) ::naTextLen := Len(::aText) @@ -149,6 +151,17 @@ METHOD New(cString, nTop, nLeft, nBottom, nRight, lEditMode) CLASS TEditor ::InsertState(::lInsert) endif + // is word wrap required? + if !nLineLength == NIL + ::lWordWrap := .T. + ::nWordWrapCol := nLineLength + endif + + // how many spaces for each tab? + if !nTabSize == NIL + ::nTabWidth := nTabSize + endif + // Empty area of screen which will hold editor window Scroll(nTop, nLeft, nBottom, nRight) @@ -392,117 +405,145 @@ METHOD InsertState(lInsState) CLASS TEditor return Self +// if editing isn't allowed we enter this loop which +// handles only movement keys and discards all the others +STATIC procedure BrowseText(oSelf) + + LOCAL nKey + + while (nKey := InKey(0)) <> K_ESC + oSelf:MoveCursor(nKey) + enddo + +return + + // Edits text -METHOD Edit() CLASS TEditor +METHOD Edit(nPassedKey) CLASS TEditor - LOCAL i, nKey + LOCAL i, nKey, lOldInsert + LOCAL lKeepGoing := .T. - /* NOTE: changing EditMode SHOULD NOT be allowed from inside editor. Edit() method relies upon lEditAllow - being fixed for current editing session */ - while ::lEditAllow + if !::lEditAllow + BrowseText(Self) - nKey := InKey(0) - do case - case (nKey >= 32 .AND. nKey < 256) - // insert char if in insert mode or at end of current line - if ::lInsert .OR. (::nCol > Len(::aText[::nRow])) - ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 0, Chr(nKey)) - else - ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 1, Chr(nKey)) - endif - ::MoveCursor(K_RIGHT) - ::RefreshLine() + else - case (nKey == K_RETURN) - if ::lInsert .OR. ::nRow == ::naTextLen - AAdd(::aText, "") - if ::nRow < ::naTextLen - AIns(::aText, ::nRow + 1) - if Len(::aText[::nRow]) > 0 - // Split current line at cursor position - ::aText[::nRow + 1] := Right(::aText[::nRow], Len(::aText[::nRow]) - ::nCol + 1) - ::aText[::nRow] := Left(::aText[::nRow], ::nCol - 1) - else - ::aText[::nRow + 1] := "" - endif + while lKeepGoing + + // If I've been called with a key already preset, evaluate this key and then exit + if nPassedKey == NIL + nKey := InKey(0) + else + lKeepGoing := .F. + nKey := nPassedKey + endif + + do case + case (nKey >= 32 .AND. nKey <= 255) + // insert char if in insert mode or at end of current line + if ::lInsert .OR. (::nCol > Len(::aText[::nRow])) + ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 0, Chr(nKey)) + else + ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 1, Chr(nKey)) endif - ::naTextLen++ - endif - ::MoveCursor(K_DOWN) - ::MoveCursor(K_HOME) - - case (nKey == K_INS) - ::InsertState(!::lInsert) - - case (nKey == K_DEL) - ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 1, "") - ::RefreshLine() - if Len(::aText[::nRow]) == 0 - KEYBOARD Chr(K_CTRL_Y) - endif - - case (nKey == K_TAB) - // insert char if in insert mode or at end of current line - if ::lInsert .OR. (::nCol == Len(::aText[::nRow])) - ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 0, Space(::nTabWidth)) - endif - for i := 1 to ::nTabWidth ::MoveCursor(K_RIGHT) - next - ::RefreshLine() - - case (nKey == K_BS) - // delete previous character - ::aText[::nRow] := Stuff(::aText[::nRow], --::nCol, 1, "") - // correct column position for next call to MoveCursor() - ::nCol++ - ::MoveCursor(K_LEFT) - ::RefreshLine() - - case (nKey == K_CTRL_Y) - if ::naTextLen > 1 - // delete current line of text - ADel(::aText, ::nRow) - ASize(::aText, --::naTextLen) - // if we now have less than a screen full of text, adjust nFirstRow position - if ::nFirstRow + ::nNumRows > ::naTextLen - ::nFirstRow := Max(::nFirstRow - 1, 1) - // if we have less lines of text than our current position on scree, up one line - if ::nRow > ::naTextLen - ::nRow := Max(::nRow - 1, 1) - SetPos(Max(Row() -1, ::nTop), Col()) - endif - endif - ::RefreshWindow() - else - ::aText[::nRow] := "" ::RefreshLine() - endif - case (::MoveCursor(nKey)) - // if it's a movement key ::MoveCursor() handles it + // if we need to word wrap a word we simulate a word left + return + if ::lWordWrap .AND. (::nCol > ::nWordWrapCol) + ::MoveCursor(K_CTRL_LEFT) + ::MoveCursor(K_CTRL_RIGHT) + lOldInsert := ::lInsert + ::lInsert := .T. + ::Edit(K_RETURN) + ::lInsert := lOldInsert + ::MoveCursor(K_CTRL_RIGHT) + endif - case (nKey == K_CTRL_W) - ::lSaved := .T. - exit + case (nKey == K_RETURN) + if ::lInsert .OR. ::nRow == ::naTextLen + AAdd(::aText, "") + if ::nRow <= ::naTextLen + AIns(::aText, ::nRow + 1) + if Len(::aText[::nRow]) > 0 + // Split current line at cursor position + ::aText[::nRow + 1] := Right(::aText[::nRow], Len(::aText[::nRow]) - ::nCol + 1) + ::aText[::nRow] := Left(::aText[::nRow], ::nCol - 1) + else + ::aText[::nRow + 1] := "" + endif + endif + // I increment naTextLen only here because now there is a "real" line of text, before + // this point we have only added some "space" to split current line + ::naTextLen++ + endif + ::MoveCursor(K_DOWN) + ::MoveCursor(K_HOME) - case (nKey == K_ESC) - exit + case (nKey == K_INS) + ::InsertState(!::lInsert) - otherwise - /* TODO: Here we should call an user defined function (to match memoedit() behaviour) */ + case (nKey == K_DEL) + ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 1, "") + ::RefreshLine() + if Len(::aText[::nRow]) == 0 + KEYBOARD Chr(K_CTRL_Y) + endif + + case (nKey == K_TAB) + // insert char if in insert mode or at end of current line + if ::lInsert .OR. (::nCol == Len(::aText[::nRow])) + ::aText[::nRow] := Stuff(::aText[::nRow], ::nCol, 0, Space(::nTabWidth)) + endif + for i := 1 to ::nTabWidth + ::MoveCursor(K_RIGHT) + next + ::RefreshLine() + + case (nKey == K_BS) + // delete previous character + ::aText[::nRow] := Stuff(::aText[::nRow], --::nCol, 1, "") + // correct column position for next call to MoveCursor() + ::nCol++ + ::MoveCursor(K_LEFT) + ::RefreshLine() + + case (nKey == K_CTRL_Y) + if ::naTextLen > 1 + // delete current line of text + ADel(::aText, ::nRow) + ASize(::aText, --::naTextLen) + // if we now have less than a screen full of text, adjust nFirstRow position + if ::nFirstRow + ::nNumRows > ::naTextLen + ::nFirstRow := Max(::nFirstRow - 1, 1) + // if we have less lines of text than our current position on scree, up one line + if ::nRow > ::naTextLen + ::nRow := Max(::nRow - 1, 1) + SetPos(Max(Row() -1, ::nTop), Col()) + endif + endif + ::RefreshWindow() + else + ::aText[::nRow] := "" + ::RefreshLine() + endif + + case (::MoveCursor(nKey)) + // if it's a movement key ::MoveCursor() handles it + + case (nKey == K_ALT_W) + /* TOFIX: Not clipper compatible */ + ::lSaved := .T. + lKeepGoing := .F. + + case (nKey == K_ESC) + lKeepGoing := .F. + + otherwise + /* TODO: Here we should call an user defined function (to match memoedit() behaviour) */ endcase - enddo - - // if editing isn't allowed we enter this loop (instead of the previous one), this loop - // handles only movement keys and discards all the others - while !::lEditAllow - nKey := InKey(0) - if nKey <> K_ESC - ::MoveCursor(nKey) - else - exit - endif - enddo + enddo + endif return Self