1 | /* |
2 | * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com) |
3 | * |
4 | * This program is free software: you can redistribute it and/or modify |
5 | * it under the terms of the GNU 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 General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
16 | */ |
17 | #ifndef QCONSOLE_H |
18 | #define QCONSOLE_H |
19 | |
20 | #include <QAbstractScrollArea> |
21 | #include <QVector> |
22 | #include <memory> |
23 | |
24 | struct ConsoleLine { |
25 | QString text; |
26 | QStringList fragments; |
27 | int maxColumns; |
28 | }; |
29 | |
30 | enum class ConsoleCaretType { |
31 | ctVerticalLine,ctHorizontalLine,ctBlock,ctHalfBlock |
32 | }; |
33 | |
34 | using PConsoleLine = std::shared_ptr<ConsoleLine>; |
35 | |
36 | using ConsoleLineList = QVector<PConsoleLine>; |
37 | |
38 | /** |
39 | * @brief The RowColumn struct |
40 | * column and row are 0-based |
41 | */ |
42 | struct RowColumn { |
43 | int column; |
44 | int row; |
45 | }; |
46 | |
47 | /** |
48 | * @brief The LineChar struct |
49 | * line and ch are 0-based |
50 | */ |
51 | struct LineChar { |
52 | int ch; |
53 | int line; |
54 | }; |
55 | |
56 | class QConsole; |
57 | class ConsoleLines : public QObject{ |
58 | Q_OBJECT |
59 | public: |
60 | explicit ConsoleLines(QConsole* console); |
61 | void addLine(const QString& line); |
62 | void RemoveLastLine(); |
63 | void changeLastLine(const QString& newLine); |
64 | QString getLastLine(); |
65 | QString getLine(int line); |
66 | QChar getChar(int line,int ch); |
67 | QChar getChar(const LineChar& lineChar); |
68 | /** |
69 | * @brief getRows |
70 | * @param startRow 1-based |
71 | * @param endRow 1-based |
72 | * @return |
73 | */ |
74 | QStringList getRows(int startRow, int endRow); |
75 | |
76 | LineChar rowColumnToLineChar(const RowColumn& rowColumn); |
77 | LineChar rowColumnToLineChar(int row ,int column); |
78 | RowColumn lineCharToRowColumn(const LineChar& lineChar); |
79 | RowColumn lineCharToRowColumn(int line, int ch); |
80 | int rows() const; |
81 | int lines() const; |
82 | bool layouting() const; |
83 | int maxLines() const; |
84 | void setMaxLines(int maxLines); |
85 | void clear(); |
86 | |
87 | int getMaxLines() const; |
88 | public slots: |
89 | void layout(); |
90 | signals: |
91 | void layoutStarted(); |
92 | void layoutFinished(); |
93 | void needRelayout(); |
94 | void rowsAdded(int rowCount); |
95 | void lastRowsRemoved(int rowCount); |
96 | void lastRowsChanged(int rowCount); |
97 | private: |
98 | int breakLine(const QString& line, QStringList& fragments); |
99 | private: |
100 | ConsoleLineList mLines; |
101 | int mRows; |
102 | bool mLayouting; |
103 | bool mNeedRelayout; |
104 | int mOldTabSize; |
105 | QConsole* mConsole; |
106 | int mMaxLines; |
107 | }; |
108 | |
109 | |
110 | class QConsole : public QAbstractScrollArea |
111 | { |
112 | Q_OBJECT |
113 | public: |
114 | explicit QConsole(QWidget* parent = nullptr); |
115 | int historySize() const; |
116 | void setHistorySize(int historySize); |
117 | |
118 | int tabSize() const; |
119 | |
120 | int columnsPerRow() const; |
121 | |
122 | int rowsInWindow() const; |
123 | int charColumns(QChar ch, int columnsBefore) const; |
124 | |
125 | void invalidate(); |
126 | void invalidateRows(int startRow,int endRow); |
127 | void invalidateRect(const QRect& rect); |
128 | |
129 | void addLine(const QString& line); |
130 | void addText(const QString& text); |
131 | void removeLastLine(); |
132 | void changeLastLine(const QString& line); |
133 | QString getLastLine(); |
134 | void clear(); |
135 | void copy(); |
136 | void paste(); |
137 | void selectAll(); |
138 | QString selText(); |
139 | |
140 | signals: |
141 | void commandInput(const QString& command); |
142 | private: |
143 | ConsoleLines mContents; |
144 | QStringList mCommandHistory; |
145 | int mHistorySize; |
146 | int mHistoryIndex; |
147 | QString mCommand; |
148 | QString mCurrentEditableLine; |
149 | // bool mIndex; |
150 | int mRowHeight; |
151 | int mTopRow; // 1-based |
152 | int mRowsInWindow; |
153 | int mColumnsPerRow; |
154 | int mColumnWidth; |
155 | bool mReadonly; |
156 | LineChar mSelectionBegin; |
157 | LineChar mSelectionEnd; |
158 | int mCaretChar; |
159 | QColor mBackground; |
160 | QColor mForeground; |
161 | QColor mSelectionBackground; |
162 | QColor mSelectionForeground; |
163 | QColor mInactiveSelectionBackground; |
164 | QColor mInactiveSelectionForeground; |
165 | int mTabSize; |
166 | std::shared_ptr<QImage> mContentImage; |
167 | int mBlinkTimerId; |
168 | int mBlinkStatus; |
169 | QTimer* mScrollTimer; |
170 | int mScrollDeltaY; |
171 | private: |
172 | void fontChanged(); |
173 | void recalcCharExtent(); |
174 | void sizeOrFontChanged(bool bFont); |
175 | int clientWidth(); |
176 | int clientHeight(); |
177 | /** |
178 | * @brief setTopRow |
179 | * @param value 1-based |
180 | */ |
181 | void setTopRow(int value); |
182 | int maxScrollHeight(); |
183 | void updateScrollbars(); |
184 | void paintRows(QPainter& painter, int row1,int row2); |
185 | void ensureCaretVisible(); |
186 | void showCaret(); |
187 | void hideCaret(); |
188 | void updateCaret(); |
189 | LineChar caretPos(); |
190 | RowColumn caretRowColumn(); |
191 | QPoint rowColumnToPixels(const RowColumn& rowColumn); |
192 | QRect getCaretRect(); |
193 | void paintCaret(QPainter &painter, const QRect rcClip); |
194 | void textInputed(const QString& text); |
195 | void loadCommandFromHistory(); |
196 | LineChar selectionBegin(); |
197 | LineChar selectionEnd(); |
198 | void setCaretChar(int newCaretChar, bool resetSelection); |
199 | bool caretInSelection(); |
200 | QString removeSelection(); |
201 | bool hasSelection(); |
202 | int computeScrollY(int Y); |
203 | RowColumn pixelsToNearestRowColumn(int x,int y); |
204 | QString lineBreak(); |
205 | |
206 | |
207 | private slots: |
208 | void doScrolled(); |
209 | void contentsLayouted(); |
210 | void contentsRowsAdded(int rowCount); |
211 | void contentsLastRowsRemoved(int rowCount); |
212 | void contentsLastRowsChanged(int rowCount); |
213 | void scrollTimerHandler(); |
214 | |
215 | // QWidget interface |
216 | protected: |
217 | void mousePressEvent(QMouseEvent *event) override; |
218 | void mouseReleaseEvent(QMouseEvent *event) override; |
219 | void mouseMoveEvent(QMouseEvent *event) override; |
220 | void keyPressEvent(QKeyEvent *event) override; |
221 | void focusInEvent(QFocusEvent *event) override; |
222 | void focusOutEvent(QFocusEvent *event) override; |
223 | void paintEvent(QPaintEvent *event) override; |
224 | bool event(QEvent *event) override; |
225 | |
226 | |
227 | // QWidget interface |
228 | protected: |
229 | void resizeEvent(QResizeEvent *event) override; |
230 | |
231 | // QObject interface |
232 | protected: |
233 | void timerEvent(QTimerEvent *event) override; |
234 | |
235 | // QWidget interface |
236 | protected: |
237 | void inputMethodEvent(QInputMethodEvent *event) override; |
238 | void wheelEvent(QWheelEvent *event) override; |
239 | }; |
240 | |
241 | |
242 | #endif // QCONSOLE_H |
243 | |