X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTEditorWidget.java;h=dcf5e9e6d267380d3b541bf275d4cdef67f8dcea;hb=7d922e0dfd9a6da42b84e01d52adeec6fff10025;hp=361ed83b9be4bc8355c53f9ad4318746e78363b8;hpb=e8a11f986bfe2556e450d7b8ad6ef0059b369bbc;p=fanfix.git diff --git a/src/jexer/TEditorWidget.java b/src/jexer/TEditorWidget.java index 361ed83..dcf5e9e 100644 --- a/src/jexer/TEditorWidget.java +++ b/src/jexer/TEditorWidget.java @@ -28,6 +28,8 @@ */ package jexer; +import java.io.IOException; + import jexer.bits.CellAttributes; import jexer.event.TKeypressEvent; import jexer.event.TMouseEvent; @@ -41,7 +43,12 @@ import static jexer.TKeypress.*; * TEditorWidget displays an editable text document. It is unaware of * scrolling behavior, but can respond to mouse and keyboard events. */ -public final class TEditorWidget extends TWidget { +public class TEditorWidget extends TWidget { + + /** + * The number of lines to scroll on mouse wheel up/down. + */ + private static final int wheelScrollSize = 3; /** * The document being edited. @@ -110,7 +117,6 @@ public final class TEditorWidget extends TWidget { } } } - } /** @@ -121,33 +127,19 @@ public final class TEditorWidget extends TWidget { @Override public void onMouseDown(final TMouseEvent mouse) { if (mouse.isMouseWheelUp()) { - if (getCursorY() == getHeight() - 1) { - if (document.up()) { - if (topLine > 0) { - topLine--; - } - alignCursor(); - } - } else { + for (int i = 0; i < wheelScrollSize; i++) { if (topLine > 0) { topLine--; - setCursorY(getCursorY() + 1); + alignDocument(false); } } return; } if (mouse.isMouseWheelDown()) { - if (getCursorY() == 0) { - if (document.down()) { - if (topLine < document.getLineNumber()) { - topLine++; - } - alignCursor(); - } - } else { - if (topLine < document.getLineCount() - getHeight()) { + for (int i = 0; i < wheelScrollSize; i++) { + if (topLine < document.getLineCount() - 1) { topLine++; - setCursorY(getCursorY() - 1); + alignDocument(true); } } return; @@ -157,14 +149,14 @@ public final class TEditorWidget extends TWidget { // Set the row and column int newLine = topLine + mouse.getY(); int newX = leftColumn + mouse.getX(); - if (newLine > document.getLineCount()) { + if (newLine > document.getLineCount() - 1) { // Go to the end document.setLineNumber(document.getLineCount() - 1); document.end(); - if (document.getLineCount() > getHeight()) { - setCursorY(getHeight() - 1); + if (newLine > document.getLineCount() - 1) { + setCursorY(document.getLineCount() - 1 - topLine); } else { - setCursorY(document.getLineCount() - 1); + setCursorY(mouse.getY()); } alignCursor(); return; @@ -172,10 +164,11 @@ public final class TEditorWidget extends TWidget { document.setLineNumber(newLine); setCursorY(mouse.getY()); - if (newX > document.getCurrentLine().getDisplayLength()) { + if (newX >= document.getCurrentLine().getDisplayLength()) { document.end(); alignCursor(); } else { + document.setCursor(newX); setCursorX(mouse.getX()); } return; @@ -185,6 +178,73 @@ public final class TEditorWidget extends TWidget { super.onMouseDown(mouse); } + /** + * Align visible area with document current line. + * + * @param topLineIsTop if true, make the top visible line the document + * current line if it was off-screen. If false, make the bottom visible + * line the document current line. + */ + private void alignTopLine(final boolean topLineIsTop) { + int line = document.getLineNumber(); + + if ((line < topLine) || (line > topLine + getHeight() - 1)) { + // Need to move topLine to bring document back into view. + if (topLineIsTop) { + topLine = line - (getHeight() - 1); + if (topLine < 0) { + topLine = 0; + } + assert (topLine >= 0); + } else { + topLine = line; + assert (topLine >= 0); + } + } + + /* + System.err.println("line " + line + " topLine " + topLine); + */ + + // Document is in view, let's set cursorY + assert (line >= topLine); + setCursorY(line - topLine); + alignCursor(); + } + + /** + * Align document current line with visible area. + * + * @param topLineIsTop if true, make the top visible line the document + * current line if it was off-screen. If false, make the bottom visible + * line the document current line. + */ + private void alignDocument(final boolean topLineIsTop) { + int line = document.getLineNumber(); + int cursor = document.getCursor(); + + if ((line < topLine) || (line > topLine + getHeight() - 1)) { + // Need to move document to ensure it fits view. + if (topLineIsTop) { + document.setLineNumber(topLine); + } else { + document.setLineNumber(topLine + (getHeight() - 1)); + } + if (cursor < document.getCurrentLine().getDisplayLength()) { + document.setCursor(cursor); + } + } + + /* + System.err.println("getLineNumber() " + document.getLineNumber() + + " topLine " + topLine); + */ + + // Document is in view, let's set cursorY + setCursorY(document.getLineNumber() - topLine); + alignCursor(); + } + /** * Align visible cursor with document cursor. */ @@ -203,7 +263,8 @@ public final class TEditorWidget extends TWidget { /* System.err.println("document cursor " + document.getCursor() + " leftColumn " + leftColumn); - */ + */ + setCursorX(document.getCursor() - leftColumn); } @@ -216,65 +277,23 @@ public final class TEditorWidget extends TWidget { @Override public void onKeypress(final TKeypressEvent keypress) { if (keypress.equals(kbLeft)) { - if (document.left()) { - alignCursor(); - } + document.left(); + alignTopLine(false); } else if (keypress.equals(kbRight)) { - if (document.right()) { - alignCursor(); - } + document.right(); + alignTopLine(true); } else if (keypress.equals(kbUp)) { - if (document.up()) { - if (getCursorY() > 0) { - setCursorY(getCursorY() - 1); - } else { - if (topLine > 0) { - topLine--; - } - } - alignCursor(); - } + document.up(); + alignTopLine(false); } else if (keypress.equals(kbDown)) { - if (document.down()) { - if (getCursorY() < getHeight() - 1) { - setCursorY(getCursorY() + 1); - } else { - if (topLine < document.getLineCount() - getHeight()) { - topLine++; - } - } - alignCursor(); - } + document.down(); + alignTopLine(true); } else if (keypress.equals(kbPgUp)) { - for (int i = 0; i < getHeight() - 1; i++) { - if (document.up()) { - if (getCursorY() > 0) { - setCursorY(getCursorY() - 1); - } else { - if (topLine > 0) { - topLine--; - } - } - alignCursor(); - } else { - break; - } - } + document.up(getHeight() - 1); + alignTopLine(false); } else if (keypress.equals(kbPgDn)) { - for (int i = 0; i < getHeight() - 1; i++) { - if (document.down()) { - if (getCursorY() < getHeight() - 1) { - setCursorY(getCursorY() + 1); - } else { - if (topLine < document.getLineCount() - getHeight()) { - topLine++; - } - } - alignCursor(); - } else { - break; - } - } + document.down(getHeight() - 1); + alignTopLine(true); } else if (keypress.equals(kbHome)) { if (document.home()) { leftColumn = 0; @@ -297,29 +316,32 @@ public final class TEditorWidget extends TWidget { } else if (keypress.equals(kbCtrlEnd)) { document.setLineNumber(document.getLineCount() - 1); document.end(); - topLine = document.getLineCount() - getHeight(); - if (topLine < 0) { - topLine = 0; - } - if (document.getLineCount() > getHeight()) { - setCursorY(getHeight() - 1); - } else { - setCursorY(document.getLineCount() - 1); - } - alignCursor(); + alignTopLine(false); } else if (keypress.equals(kbIns)) { document.setOverwrite(!document.getOverwrite()); } else if (keypress.equals(kbDel)) { document.del(); + alignCursor(); } else if (keypress.equals(kbBackspace)) { document.backspace(); + alignTopLine(false); + } else if (keypress.equals(kbTab)) { + // TODO: tab character. For now just add spaces until we hit + // modulo 8. + for (int i = document.getCursor(); (i + 1) % 8 != 0; i++) { + document.addChar(' '); + } alignCursor(); + } else if (keypress.equals(kbEnter)) { + document.enter(); + alignTopLine(true); } else if (!keypress.getKey().isFnKey() && !keypress.getKey().isAlt() && !keypress.getKey().isCtrl() ) { // Plain old keystroke, process it document.addChar(keypress.getKey().getChar()); + alignCursor(); } else { // Pass other keys (tab etc.) on to TWidget super.onKeypress(keypress); @@ -354,4 +376,116 @@ public final class TEditorWidget extends TWidget { } } + /** + * Get the number of lines in the underlying Document. + * + * @return the number of lines + */ + public int getLineCount() { + return document.getLineCount(); + } + + /** + * Get the current visible top row number. 1-based. + * + * @return the visible top row number. Row 1 is the first row. + */ + public int getVisibleRowNumber() { + return topLine + 1; + } + + /** + * Set the current visible row number. 1-based. + * + * @param row the new visible row number. Row 1 is the first row. + */ + public void setVisibleRowNumber(final int row) { + assert (row > 0); + if ((row > 0) && (row < document.getLineCount())) { + topLine = row - 1; + alignDocument(true); + } + } + + /** + * Get the current editing row number. 1-based. + * + * @return the editing row number. Row 1 is the first row. + */ + public int getEditingRowNumber() { + return document.getLineNumber() + 1; + } + + /** + * Set the current editing row number. 1-based. + * + * @param row the new editing row number. Row 1 is the first row. + */ + public void setEditingRowNumber(final int row) { + assert (row > 0); + if ((row > 0) && (row < document.getLineCount())) { + document.setLineNumber(row - 1); + alignTopLine(true); + } + } + + /** + * Get the current editing column number. 1-based. + * + * @return the editing column number. Column 1 is the first column. + */ + public int getEditingColumnNumber() { + return document.getCursor() + 1; + } + + /** + * Set the current editing column number. 1-based. + * + * @param column the new editing column number. Column 1 is the first + * column. + */ + public void setEditingColumnNumber(final int column) { + if ((column > 0) && (column < document.getLineLength())) { + document.setCursor(column - 1); + alignCursor(); + } + } + + /** + * Get the maximum possible row number. 1-based. + * + * @return the maximum row number. Row 1 is the first row. + */ + public int getMaximumRowNumber() { + return document.getLineCount() + 1; + } + + /** + * Get the maximum possible column number. 1-based. + * + * @return the maximum column number. Column 1 is the first column. + */ + public int getMaximumColumnNumber() { + return document.getLineLengthMax() + 1; + } + + /** + * Get the dirty value. + * + * @return true if the buffer is dirty + */ + public boolean isDirty() { + return document.isDirty(); + } + + /** + * Save contents to file. + * + * @param filename file to save to + * @throws IOException if a java.io operation throws + */ + public void saveToFilename(final String filename) throws IOException { + document.saveToFilename(filename); + } + }