Commit | Line | Data |
---|---|---|
a3b510ab NR |
1 | /* |
2 | * This file is part of lanterna (http://code.google.com/p/lanterna/). | |
3 | * | |
4 | * lanterna is free software: you can redistribute it and/or modify | |
5 | * it under the terms of the GNU Lesser General Public License as published by | |
6 | * the Free Software Foundation, either version 3 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU Lesser General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU Lesser General Public License | |
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | * | |
17 | * Copyright (C) 2010-2015 Martin | |
18 | */ | |
19 | package com.googlecode.lanterna.terminal.swing; | |
20 | ||
21 | import com.googlecode.lanterna.TerminalTextUtils; | |
22 | import com.googlecode.lanterna.TextCharacter; | |
23 | import com.googlecode.lanterna.TerminalPosition; | |
24 | import com.googlecode.lanterna.TerminalSize; | |
25 | import java.util.ArrayList; | |
26 | import java.util.Iterator; | |
27 | import java.util.LinkedList; | |
28 | import java.util.List; | |
29 | import java.util.ListIterator; | |
30 | ||
31 | /** | |
32 | * Contains an entire text buffer used by Swing terminal | |
33 | * @author martin | |
34 | */ | |
35 | class TextBuffer { | |
36 | private final int backlog; | |
37 | private final LinkedList<List<TextCharacter>> lineBuffer; | |
38 | private final TextCharacter fillCharacter; | |
39 | ||
40 | TextBuffer(int backlog) { | |
41 | this.backlog = backlog; | |
42 | this.lineBuffer = new LinkedList<List<TextCharacter>>(); | |
43 | this.fillCharacter = TextCharacter.DEFAULT_CHARACTER; | |
44 | ||
45 | //Initialize the content to one line | |
46 | newLine(); | |
47 | } | |
48 | ||
49 | void clear() { | |
50 | lineBuffer.clear(); | |
51 | newLine(); | |
52 | } | |
53 | ||
54 | void newLine() { | |
55 | ArrayList<TextCharacter> line = new ArrayList<TextCharacter>(200); | |
56 | line.add(fillCharacter); | |
57 | lineBuffer.addFirst(line); | |
58 | } | |
59 | ||
60 | ||
61 | Iterable<List<TextCharacter>> getVisibleLines(final int visibleRows, final int scrollOffset) { | |
62 | final int length = Math.min(visibleRows, lineBuffer.size()); | |
63 | return new Iterable<List<TextCharacter>>() { | |
64 | @Override | |
65 | public Iterator<List<TextCharacter>> iterator() { | |
66 | return new Iterator<List<TextCharacter>>() { | |
67 | private final ListIterator<List<TextCharacter>> listIterator = lineBuffer.subList(scrollOffset, scrollOffset + length).listIterator(length); | |
68 | @Override | |
69 | public boolean hasNext() { return listIterator.hasPrevious(); } | |
70 | @Override | |
71 | public List<TextCharacter> next() { return listIterator.previous(); } | |
72 | @Override | |
73 | public void remove() { listIterator.remove(); } | |
74 | }; | |
75 | } | |
76 | }; | |
77 | } | |
78 | ||
79 | int getNumberOfLines() { | |
80 | return lineBuffer.size(); | |
81 | } | |
82 | ||
83 | void trimBacklog(int terminalHeight) { | |
84 | while(lineBuffer.size() - terminalHeight > backlog) { | |
85 | lineBuffer.removeLast(); | |
86 | } | |
87 | } | |
88 | ||
89 | void ensurePosition(TerminalSize terminalSize, TerminalPosition position) { | |
90 | getLine(terminalSize, position); | |
91 | } | |
92 | ||
93 | public TextCharacter getCharacter(TerminalSize terminalSize, TerminalPosition position) { | |
94 | return getLine(terminalSize, position).get(position.getColumn()); | |
95 | } | |
96 | ||
97 | void setCharacter(TerminalSize terminalSize, TerminalPosition currentPosition, TextCharacter terminalCharacter) { | |
98 | List<TextCharacter> line = getLine(terminalSize, currentPosition); | |
99 | ||
100 | //If we are replacing a CJK character with a non-CJK character, make the following character empty | |
101 | if(TerminalTextUtils.isCharCJK(line.get(currentPosition.getColumn()).getCharacter()) && | |
102 | !TerminalTextUtils.isCharCJK(terminalCharacter.getCharacter())) { | |
103 | line.set(currentPosition.getColumn() + 1, terminalCharacter.withCharacter(' ')); | |
104 | } | |
105 | ||
106 | //Set the character in the buffer | |
107 | line.set(currentPosition.getColumn(), terminalCharacter); | |
108 | ||
109 | //Pad CJK character with a trailing space | |
110 | if(TerminalTextUtils.isCharCJK(terminalCharacter.getCharacter()) && currentPosition.getColumn() + 1 < line.size()) { | |
111 | ensurePosition(terminalSize, currentPosition.withRelativeColumn(1)); | |
112 | line.set(currentPosition.getColumn() + 1, terminalCharacter.withCharacter(' ')); | |
113 | } | |
114 | //If there's a CJK character immediately to our left, reset it | |
115 | if(currentPosition.getColumn() > 0 && TerminalTextUtils.isCharCJK(line.get(currentPosition.getColumn() - 1).getCharacter())) { | |
116 | line.set(currentPosition.getColumn() - 1, line.get(currentPosition.getColumn() - 1).withCharacter(' ')); | |
117 | } | |
118 | } | |
119 | ||
120 | private List<TextCharacter> getLine(TerminalSize terminalSize, TerminalPosition position) { | |
121 | while(position.getRow() >= lineBuffer.size()) { | |
122 | newLine(); | |
123 | } | |
124 | int lineIndex = Math.min(terminalSize.getRows(), lineBuffer.size()) - 1 - position.getRow(); | |
125 | List<TextCharacter> line = lineBuffer.get(lineIndex); | |
126 | while(line.size() <= position.getColumn()) { | |
127 | line.add(fillCharacter); | |
128 | } | |
129 | return line; | |
130 | } | |
131 | } |