├── .gitignore ├── README.md ├── backend ├── backend.pri ├── block.cpp ├── block.h ├── character_sets.h ├── color_palette.cpp ├── color_palette.h ├── controll_chars.cpp ├── controll_chars.h ├── cursor.cpp ├── cursor.h ├── main.cpp ├── nrc_text_codec.cpp ├── nrc_text_codec.h ├── parser.cpp ├── parser.h ├── screen.cpp ├── screen.h ├── screen_data.cpp ├── screen_data.h ├── scrollback.cpp ├── scrollback.h ├── selection.cpp ├── selection.h ├── text.cpp ├── text.h ├── text_style.cpp ├── text_style.h ├── utf8_decoder.h ├── yat_pty.cpp └── yat_pty.h ├── docs ├── Ecma-048.pdf └── Xterm Control Sequences.html ├── qml ├── Yat │ ├── Cursor.qml │ ├── Screen.qml │ ├── Selection.qml │ ├── Text.qml │ ├── Yat.pro │ ├── plugin │ │ ├── mono_text.cpp │ │ ├── mono_text.h │ │ ├── object_destruct_item.cpp │ │ ├── object_destruct_item.h │ │ ├── terminal_screen.cpp │ │ ├── terminal_screen.h │ │ ├── yat_extension_plugin.cpp │ │ └── yat_extension_plugin.h │ └── qmldir └── qml.pro ├── tests ├── auto │ ├── auto.pro │ └── block │ │ ├── block.pro │ │ └── tst_block.cpp └── tests.pro ├── yat.pro └── yat_app ├── main.cpp ├── yat.qml ├── yat.qrc └── yat_app.pro /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | .moc 3 | .obj 4 | yat 5 | yat.pro.user 6 | yat.pro.user.1.3 7 | yat.pro.user.2.6pre1 8 | yat_declarative/qrc_qml_sources.cpp 9 | *.o 10 | moc_* 11 | imports/Yat/* 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yat (yet another terminal) is a VT100-emulating terminal written with Qt Quick. 2 | 3 | Currently, master branch requires Qt 5.10; previous versions targeted older versions of Qt. 4 | 5 | ## To compile and try it out 6 | 7 | ``` 8 | qmake 9 | make 10 | qml -I imports yat_app/yat.qml 11 | ``` 12 | 13 | ## To install on your system 14 | 15 | First install the dependencies in your system Qt path, then install yat.qml somewhere in your PATH 16 | (use sudo if it gives you permission errors, and if you agree about the installation directory): 17 | 18 | ``` 19 | qmake 20 | make install 21 | cp yat_app/yat.qml /usr/bin/yat 22 | ``` 23 | 24 | yat.qml is a script starting with a shebang, so you can run it just like that, the same way 25 | you could run a Python script for example. And as with Python, the dependencies need to 26 | be installed too; ```make install``` will by default install in a directory called Yat 27 | under Qt's Qml2ImportsPath, which may be something like /usr/lib/qt/qml 28 | if you are using your distro's Qt packages. 29 | 30 | If the QML is installed in this way, yat can also be used as a component inside other applications. 31 | 32 | 33 | ## To build a self-contained executable 34 | 35 | This is not necessary, but if you prefer to make a self-contained executable instead of installing the QML files separately: 36 | 37 | ``` 38 | cd yat_app 39 | qmake 40 | make 41 | ``` 42 | 43 | It will incorporate the QML into the executable's resources, and you now have a moveable executable. 44 | But the downside is you cannot customize the QML at runtime - you need to compile it again 45 | if you make a change. 46 | 47 | -------------------------------------------------------------------------------- /backend/backend.pri: -------------------------------------------------------------------------------- 1 | DEPENDPATH += $$PWD 2 | INCLUDEPATH += $$PWD 3 | 4 | LIBS += -lutil 5 | 6 | CONFIG += c++11 7 | 8 | MOC_DIR = .moc 9 | OBJECTS_DIR = .obj 10 | 11 | HEADERS += \ 12 | $$PWD/yat_pty.h \ 13 | $$PWD/text.h \ 14 | $$PWD/controll_chars.h \ 15 | $$PWD/parser.h \ 16 | $$PWD/screen.h \ 17 | $$PWD/block.h \ 18 | $$PWD/color_palette.h \ 19 | $$PWD/text_style.h \ 20 | $$PWD/screen_data.h \ 21 | $$PWD/cursor.h \ 22 | $$PWD/nrc_text_codec.h \ 23 | $$PWD/scrollback.h \ 24 | $$PWD/utf8_decoder.h \ 25 | $$PWD/selection.h 26 | 27 | SOURCES += \ 28 | $$PWD/yat_pty.cpp \ 29 | $$PWD/text.cpp \ 30 | $$PWD/controll_chars.cpp \ 31 | $$PWD/parser.cpp \ 32 | $$PWD/screen.cpp \ 33 | $$PWD/block.cpp \ 34 | $$PWD/color_palette.cpp \ 35 | $$PWD/text_style.cpp \ 36 | $$PWD/screen_data.cpp \ 37 | $$PWD/cursor.cpp \ 38 | $$PWD/nrc_text_codec.cpp \ 39 | $$PWD/scrollback.cpp \ 40 | $$PWD/selection.cpp 41 | 42 | -------------------------------------------------------------------------------- /backend/block.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #ifndef BLOCK_H 25 | #define BLOCK_H 26 | 27 | #include 28 | 29 | #include "text_style.h" 30 | 31 | class Text; 32 | class Screen; 33 | 34 | class Block 35 | { 36 | public: 37 | Block(Screen *screen); 38 | ~Block(); 39 | 40 | Q_INVOKABLE Screen *screen() const; 41 | 42 | void clear(); 43 | void clearToEnd(int from); 44 | void clearCharacters(int from, int to); 45 | void deleteCharacters(int from, int to); 46 | void deleteToEnd(int from); 47 | void deleteLines(int from); 48 | 49 | void replaceAtPos(int i, const QString &text, const TextStyle &style, bool only_latin = true); 50 | void insertAtPos(int i, const QString &text, const TextStyle &style, bool only_latin = true); 51 | 52 | void setScreenIndex(int index) { m_screen_index = index; } 53 | int screenIndex() const { return m_screen_index; } 54 | size_t line() { return m_new_line; } 55 | void setLine(size_t line) { 56 | if (line != m_new_line) { 57 | m_changed = true; 58 | m_new_line = line; 59 | } 60 | } 61 | 62 | const QString &textLine() const; 63 | int textSize() { return m_text_line.size(); } 64 | 65 | int width() const { return m_width; } 66 | void setWidth(int width); 67 | int lineCount() const { return (std::max((m_text_line.size() - 1),0) / m_width) + 1; } 68 | int lineCountAfterModified(int from_char, int text_size, bool replace) { 69 | int new_size = replace ? std::max(from_char + text_size, m_text_line.size()) 70 | : std::max(from_char, m_text_line.size()) + text_size; 71 | return ((new_size - 1) / m_width) + 1; 72 | } 73 | 74 | void setVisible(bool visible); 75 | bool visible() const; 76 | 77 | Block *split(int line); 78 | Block *takeLine(int line); 79 | void removeLine(int line); 80 | 81 | void moveLinesFromBlock(Block *block, int start_line, int count); 82 | 83 | void dispatchEvents(); 84 | void releaseTextObjects(); 85 | 86 | QVector style_list(); 87 | 88 | void printStyleList() const; 89 | void printStyleList(QDebug &debug) const; 90 | void printStyleListWidthText() const; 91 | 92 | private: 93 | void mergeCompatibleStyles(); 94 | void ensureStyleAlignWithLines(int i); 95 | Screen *m_screen; 96 | QString m_text_line; 97 | QVector m_style_list; 98 | size_t m_line; 99 | size_t m_new_line; 100 | int m_screen_index; 101 | 102 | int m_width; 103 | 104 | bool m_visible; 105 | bool m_changed; 106 | bool m_only_latin; 107 | }; 108 | 109 | #endif // BLOCK_H 110 | -------------------------------------------------------------------------------- /backend/character_sets.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #include 25 | 26 | static const QChar dec_special_graphics_char_set[] = 27 | { 28 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 29 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 30 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 31 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 32 | /*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 33 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 34 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 35 | /*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 36 | /*0x40*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 37 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 38 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 39 | /*0x58*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0020, 40 | /*0x60*/ 0x25c6,0x2592,0x2409,0x240c,0x240d,0x240a,0x00b0,0x00b1, 41 | /*0x68*/ 0x2424,0x240b,0x2518,0x2510,0x250c,0x2514,0x253c,0x23ba, 42 | /*0x70*/ 0x23bb,0x2500,0x23bc,0x23bd,0x251c,0x2524,0x2534,0x252c, 43 | /*0x78*/ 0x2502,0x2264,0x2265,0x03c0,0x2260,0x00a3,0x00b7,0x0000, 44 | }; 45 | 46 | static const QChar nrc_british_char_set[] = 47 | { 48 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 49 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 50 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 51 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 52 | /*0x20*/ 0x0000,0x0000,0x0000,0x00a3,0x0000,0x0000,0x0000,0x0000, 53 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 54 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 55 | /*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 56 | /*0x40*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 57 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 58 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 59 | /*0x58*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 60 | /*0x60*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 61 | /*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 62 | /*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 63 | /*0x78*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 64 | }; 65 | 66 | static const QChar nrc_norwegian_danish_char_set[] = 67 | { 68 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 69 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 70 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 71 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 72 | /*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 73 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 74 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 75 | /*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 76 | /*0x40*/ 0x00c4,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 77 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 78 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 79 | /*0x58*/ 0x0000,0x0000,0x0000,0x00c6,0x00d8,0x00c5,0x00dc,0x0000, 80 | /*0x60*/ 0x00e4,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 81 | /*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 82 | /*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 83 | /*0x78*/ 0x0000,0x0000,0x0000,0x00e6,0x00f8,0x00e5,0x00fc,0x0000, 84 | }; 85 | 86 | static const QChar nrc_dutch_char_set[] = 87 | { 88 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 89 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 90 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 91 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 92 | /*0x20*/ 0x0000,0x0000,0x0000,0x00a3,0x0000,0x0000,0x0000,0x0000, 93 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 94 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 95 | /*0x38*/ 0x0000,0x0000,0x00be,0x0000,0x0000,0x0000,0x0000,0x0000, 96 | /*0x40*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 97 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 98 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 99 | /*0x58*/ 0x0000,0x0000,0x0000,0x0133,0x00bd,0x007c,0x0000,0x0000, 100 | /*0x60*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 101 | /*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 102 | /*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 103 | /*0x78*/ 0x0000,0x0000,0x0000,0x00a8,0x0066,0x00bc,0x00b4,0x0000, 104 | }; 105 | 106 | static const QChar nrc_finnish_char_set[] = 107 | { 108 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 109 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 110 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 111 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 112 | /*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 113 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 114 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 115 | /*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 116 | /*0x40*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 117 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 118 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 119 | /*0x58*/ 0x0000,0x0000,0x0000,0x00c4,0x00d6,0x00c5,0x00dc,0x0000, 120 | /*0x60*/ 0x00e9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 121 | /*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 122 | /*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 123 | /*0x78*/ 0x0000,0x0000,0x0000,0x00e4,0x00f6,0x00e5,0x00fc,0x0000, 124 | }; 125 | 126 | static const QChar nrc_french_char_set[] = 127 | { 128 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 129 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 130 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 131 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 132 | /*0x20*/ 0x0000,0x0000,0x0000,0x00a3,0x0000,0x0000,0x0000,0x0000, 133 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 134 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 135 | /*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 136 | /*0x40*/ 0x00e0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 137 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 138 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 139 | /*0x58*/ 0x0000,0x0000,0x0000,0x00b0,0x00e7,0x00a7,0x0000,0x0000, 140 | /*0x60*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 141 | /*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 142 | /*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 143 | /*0x78*/ 0x0000,0x0000,0x0000,0x00e9,0x00f9,0x00e8,0x00a8,0x0000, 144 | }; 145 | 146 | static const QChar nrc_french_canadian_char_set[] = 147 | { 148 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 149 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 150 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 151 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 152 | /*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 153 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 154 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 155 | /*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 156 | /*0x40*/ 0x00e0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 157 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 158 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 159 | /*0x58*/ 0x0000,0x0000,0x0000,0x00e2,0x00e7,0x00ea,0x00ee,0x0000, 160 | /*0x60*/ 0x00f4,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 161 | /*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 162 | /*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 163 | /*0x78*/ 0x0000,0x0000,0x0000,0x00e9,0x00f9,0x00e8,0x00fb,0x0000, 164 | }; 165 | 166 | static const QChar nrc_german_char_set[] = 167 | { 168 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 169 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 170 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 171 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 172 | /*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 173 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 174 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 175 | /*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 176 | /*0x40*/ 0x00a7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 177 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 178 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 179 | /*0x58*/ 0x0000,0x0000,0x0000,0x00c4,0x00d6,0x00dc,0x0000,0x0000, 180 | /*0x60*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 181 | /*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 182 | /*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 183 | /*0x78*/ 0x0000,0x0000,0x0000,0x00e4,0x00f6,0x00fc,0x00df,0x0000, 184 | }; 185 | 186 | static const QChar nrc_italian_char_set[] = 187 | { 188 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 189 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 190 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 191 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 192 | /*0x20*/ 0x0000,0x0000,0x0000,0x00a3,0x0000,0x0000,0x0000,0x0000, 193 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 194 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 195 | /*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 196 | /*0x40*/ 0x00a7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 197 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 198 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 199 | /*0x58*/ 0x0000,0x0000,0x0000,0x00b0,0x00e7,0x00e9,0x0000,0x0000, 200 | /*0x60*/ 0x00f9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 201 | /*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 202 | /*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 203 | /*0x78*/ 0x0000,0x0000,0x0000,0x00e0,0x00f2,0x00e8,0x00ec,0x0000, 204 | }; 205 | 206 | static const QChar nrc_spanish_char_set[] = 207 | { 208 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 209 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 210 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 211 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 212 | /*0x20*/ 0x0000,0x0000,0x0000,0x00a3,0x0000,0x0000,0x0000,0x0000, 213 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 214 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 215 | /*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 216 | /*0x40*/ 0x00a7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 217 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 218 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 219 | /*0x58*/ 0x0000,0x0000,0x0000,0x00a1,0x00d1,0x00bf,0x0000,0x0000, 220 | /*0x60*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 221 | /*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 222 | /*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 223 | /*0x78*/ 0x0000,0x0000,0x0000,0x00b0,0x00f1,0x00e7,0x0000,0x0000, 224 | }; 225 | 226 | static const QChar nrc_swedish_char_set[] = 227 | { 228 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 229 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 230 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 231 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 232 | /*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 233 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 234 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 235 | /*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 236 | /*0x40*/ 0x00c9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 237 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 238 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 239 | /*0x58*/ 0x0000,0x0000,0x0000,0x00c4,0x00d6,0x00c5,0x00dc,0x0000, 240 | /*0x60*/ 0x00e9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 241 | /*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 242 | /*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 243 | /*0x78*/ 0x0000,0x0000,0x0000,0x00e4,0x00f6,0x00e5,0x00fc,0x0000, 244 | }; 245 | 246 | static const QChar nrc_swiss_char_set[] = 247 | { 248 | /*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 249 | /*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 250 | /*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 251 | /*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 252 | /*0x20*/ 0x0000,0x0000,0x0000,0x00f9,0x0000,0x0000,0x0000,0x0000, 253 | /*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 254 | /*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 255 | /*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 256 | /*0x40*/ 0x00e0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 257 | /*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 258 | /*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 259 | /*0x58*/ 0x0000,0x0000,0x0000,0x00e9,0x00e7,0x00ea,0x00ee,0x00e8, 260 | /*0x60*/ 0x00f4,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 261 | /*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 262 | /*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, 263 | /*0x78*/ 0x0000,0x0000,0x0000,0x00e4,0x00f6,0x00fc,0x00fb,0x0000, 264 | }; 265 | 266 | -------------------------------------------------------------------------------- /backend/color_palette.cpp: -------------------------------------------------------------------------------- 1 | #include "color_palette.h" 2 | 3 | #include 4 | 5 | static QVector defaultXtermColors = { 6 | QColor(0,0,0).rgb(), // index 16 7 | QColor(0,0,95).rgb(), 8 | QColor(0,0,135).rgb(), 9 | QColor(0,0,175).rgb(), 10 | QColor(0,0,215).rgb(), 11 | QColor(0,0,255).rgb(), 12 | QColor(0,95,0).rgb(), 13 | QColor(0,95,95).rgb(), 14 | QColor(0,95,135).rgb(), 15 | QColor(0,95,175).rgb(), 16 | QColor(0,95,215).rgb(), 17 | QColor(0,95,255).rgb(), 18 | QColor(0,135,0).rgb(), 19 | QColor(0,135,95).rgb(), 20 | QColor(0,135,135).rgb(), 21 | QColor(0,135,175).rgb(), 22 | QColor(0,135,215).rgb(), 23 | QColor(0,135,255).rgb(), 24 | QColor(0,175,0).rgb(), 25 | QColor(0,175,95).rgb(), 26 | QColor(0,175,135).rgb(), 27 | QColor(0,175,175).rgb(), 28 | QColor(0,175,215).rgb(), 29 | QColor(0,175,255).rgb(), 30 | QColor(0,215,0).rgb(), 31 | QColor(0,215,95).rgb(), 32 | QColor(0,215,135).rgb(), 33 | QColor(0,215,175).rgb(), 34 | QColor(0,215,215).rgb(), 35 | QColor(0,215,255).rgb(), 36 | QColor(0,255,0).rgb(), 37 | QColor(0,255,95).rgb(), 38 | QColor(0,255,135).rgb(), 39 | QColor(0,255,175).rgb(), 40 | QColor(0,255,215).rgb(), 41 | QColor(0,255,255).rgb(), 42 | QColor(95,0,0).rgb(), 43 | QColor(95,0,95).rgb(), 44 | QColor(95,0,135).rgb(), 45 | QColor(95,0,175).rgb(), 46 | QColor(95,0,215).rgb(), 47 | QColor(95,0,255).rgb(), 48 | QColor(95,95,0).rgb(), 49 | QColor(95,95,95).rgb(), 50 | QColor(95,95,135).rgb(), 51 | QColor(95,95,175).rgb(), 52 | QColor(95,95,215).rgb(), 53 | QColor(95,95,255).rgb(), 54 | QColor(95,135,0).rgb(), 55 | QColor(95,135,95).rgb(), 56 | QColor(95,135,135).rgb(), 57 | QColor(95,135,175).rgb(), 58 | QColor(95,135,215).rgb(), 59 | QColor(95,135,255).rgb(), 60 | QColor(95,175,0).rgb(), 61 | QColor(95,175,95).rgb(), 62 | QColor(95,175,135).rgb(), 63 | QColor(95,175,175).rgb(), 64 | QColor(95,175,215).rgb(), 65 | QColor(95,175,255).rgb(), 66 | QColor(95,215,0).rgb(), 67 | QColor(95,215,95).rgb(), 68 | QColor(95,215,135).rgb(), 69 | QColor(95,215,175).rgb(), 70 | QColor(95,215,215).rgb(), 71 | QColor(95,215,255).rgb(), 72 | QColor(95,255,0).rgb(), 73 | QColor(95,255,95).rgb(), 74 | QColor(95,255,135).rgb(), 75 | QColor(95,255,175).rgb(), 76 | QColor(95,255,215).rgb(), 77 | QColor(95,255,255).rgb(), 78 | QColor(135,0,0).rgb(), 79 | QColor(135,0,95).rgb(), 80 | QColor(135,0,135).rgb(), 81 | QColor(135,0,175).rgb(), 82 | QColor(135,0,215).rgb(), 83 | QColor(135,0,255).rgb(), 84 | QColor(135,95,0).rgb(), 85 | QColor(135,95,95).rgb(), 86 | QColor(135,95,135).rgb(), 87 | QColor(135,95,175).rgb(), 88 | QColor(135,95,215).rgb(), 89 | QColor(135,95,255).rgb(), 90 | QColor(135,135,0).rgb(), 91 | QColor(135,135,95).rgb(), 92 | QColor(135,135,135).rgb(), 93 | QColor(135,135,175).rgb(), 94 | QColor(135,135,215).rgb(), 95 | QColor(135,135,255).rgb(), 96 | QColor(135,175,0).rgb(), 97 | QColor(135,175,95).rgb(), 98 | QColor(135,175,135).rgb(), 99 | QColor(135,175,175).rgb(), 100 | QColor(135,175,215).rgb(), 101 | QColor(135,175,255).rgb(), 102 | QColor(135,215,0).rgb(), 103 | QColor(135,215,95).rgb(), 104 | QColor(135,215,135).rgb(), 105 | QColor(135,215,175).rgb(), 106 | QColor(135,215,215).rgb(), 107 | QColor(135,215,255).rgb(), 108 | QColor(135,255,0).rgb(), 109 | QColor(135,255,95).rgb(), 110 | QColor(135,255,135).rgb(), 111 | QColor(135,255,175).rgb(), 112 | QColor(135,255,215).rgb(), 113 | QColor(135,255,255).rgb(), 114 | QColor(175,0,0).rgb(), 115 | QColor(175,0,95).rgb(), 116 | QColor(175,0,135).rgb(), 117 | QColor(175,0,175).rgb(), 118 | QColor(175,0,215).rgb(), 119 | QColor(175,0,255).rgb(), 120 | QColor(175,95,0).rgb(), 121 | QColor(175,95,95).rgb(), 122 | QColor(175,95,135).rgb(), 123 | QColor(175,95,175).rgb(), 124 | QColor(175,95,215).rgb(), 125 | QColor(175,95,255).rgb(), 126 | QColor(175,135,0).rgb(), 127 | QColor(175,135,95).rgb(), 128 | QColor(175,135,135).rgb(), 129 | QColor(175,135,175).rgb(), 130 | QColor(175,135,215).rgb(), 131 | QColor(175,135,255).rgb(), 132 | QColor(175,175,0).rgb(), 133 | QColor(175,175,95).rgb(), 134 | QColor(175,175,135).rgb(), 135 | QColor(175,175,175).rgb(), 136 | QColor(175,175,215).rgb(), 137 | QColor(175,175,255).rgb(), 138 | QColor(175,215,0).rgb(), 139 | QColor(175,215,95).rgb(), 140 | QColor(175,215,135).rgb(), 141 | QColor(175,215,175).rgb(), 142 | QColor(175,215,215).rgb(), 143 | QColor(175,215,255).rgb(), 144 | QColor(175,255,0).rgb(), 145 | QColor(175,255,95).rgb(), 146 | QColor(175,255,135).rgb(), 147 | QColor(175,255,175).rgb(), 148 | QColor(175,255,215).rgb(), 149 | QColor(175,255,255).rgb(), 150 | QColor(215,0,0).rgb(), 151 | QColor(215,0,95).rgb(), 152 | QColor(215,0,135).rgb(), 153 | QColor(215,0,175).rgb(), 154 | QColor(215,0,215).rgb(), 155 | QColor(215,0,255).rgb(), 156 | QColor(215,95,0).rgb(), 157 | QColor(215,95,95).rgb(), 158 | QColor(215,95,135).rgb(), 159 | QColor(215,95,175).rgb(), 160 | QColor(215,95,215).rgb(), 161 | QColor(215,95,255).rgb(), 162 | QColor(215,135,0).rgb(), 163 | QColor(215,135,95).rgb(), 164 | QColor(215,135,135).rgb(), 165 | QColor(215,135,175).rgb(), 166 | QColor(215,135,215).rgb(), 167 | QColor(215,135,255).rgb(), 168 | QColor(215,175,0).rgb(), 169 | QColor(215,175,95).rgb(), 170 | QColor(215,175,135).rgb(), 171 | QColor(215,175,175).rgb(), 172 | QColor(215,175,215).rgb(), 173 | QColor(215,175,255).rgb(), 174 | QColor(215,215,0).rgb(), 175 | QColor(215,215,95).rgb(), 176 | QColor(215,215,135).rgb(), 177 | QColor(215,215,175).rgb(), 178 | QColor(215,215,215).rgb(), 179 | QColor(215,215,255).rgb(), 180 | QColor(215,255,0).rgb(), 181 | QColor(215,255,95).rgb(), 182 | QColor(215,255,135).rgb(), 183 | QColor(215,255,175).rgb(), 184 | QColor(215,255,215).rgb(), 185 | QColor(215,255,255).rgb(), 186 | QColor(255,0,0).rgb(), 187 | QColor(255,0,95).rgb(), 188 | QColor(255,0,135).rgb(), 189 | QColor(255,0,175).rgb(), 190 | QColor(255,0,215).rgb(), 191 | QColor(255,0,255).rgb(), 192 | QColor(255,95,0).rgb(), 193 | QColor(255,95,95).rgb(), 194 | QColor(255,95,135).rgb(), 195 | QColor(255,95,175).rgb(), 196 | QColor(255,95,215).rgb(), 197 | QColor(255,95,255).rgb(), 198 | QColor(255,135,0).rgb(), 199 | QColor(255,135,95).rgb(), 200 | QColor(255,135,135).rgb(), 201 | QColor(255,135,175).rgb(), 202 | QColor(255,135,215).rgb(), 203 | QColor(255,135,255).rgb(), 204 | QColor(255,175,0).rgb(), 205 | QColor(255,175,95).rgb(), 206 | QColor(255,175,135).rgb(), 207 | QColor(255,175,175).rgb(), 208 | QColor(255,175,215).rgb(), 209 | QColor(255,175,255).rgb(), 210 | QColor(255,215,0).rgb(), 211 | QColor(255,215,95).rgb(), 212 | QColor(255,215,135).rgb(), 213 | QColor(255,215,175).rgb(), 214 | QColor(255,215,215).rgb(), 215 | QColor(255,215,255).rgb(), 216 | QColor(255,255,0).rgb(), 217 | QColor(255,255,95).rgb(), 218 | QColor(255,255,135).rgb(), 219 | QColor(255,255,175).rgb(), 220 | QColor(255,255,215).rgb(), 221 | QColor(255,255,255).rgb(), 222 | QColor(8,8,8).rgb(), 223 | QColor(18,18,18).rgb(), 224 | QColor(28,28,28).rgb(), 225 | QColor(38,38,38).rgb(), 226 | QColor(48,48,48).rgb(), 227 | QColor(58,58,58).rgb(), 228 | QColor(68,68,68).rgb(), 229 | QColor(78,78,78).rgb(), 230 | QColor(88,88,88).rgb(), 231 | QColor(98,98,98).rgb(), 232 | QColor(108,108,108).rgb(), 233 | QColor(118,118,118).rgb(), 234 | QColor(128,128,128).rgb(), 235 | QColor(138,138,138).rgb(), 236 | QColor(148,148,148).rgb(), 237 | QColor(158,158,158).rgb(), 238 | QColor(168,168,168).rgb(), 239 | QColor(178,178,178).rgb(), 240 | QColor(188,188,188).rgb(), 241 | QColor(198,198,198).rgb(), 242 | QColor(208,208,208).rgb(), 243 | QColor(218,218,218).rgb(), 244 | QColor(228,228,228).rgb(), 245 | QColor(238,238,238).rgb() // index 255 246 | }; 247 | 248 | 249 | ColorPalette::ColorPalette(QObject *parent) 250 | : QObject(parent) 251 | , m_normalColors(numberOfColors) 252 | , m_lightColors(numberOfColors) 253 | , m_xtermColors(defaultXtermColors) 254 | , m_inverse_default(false) 255 | { 256 | m_normalColors[0].setRgb(0,0,0); 257 | m_normalColors[1].setRgb(194,54,33); 258 | m_normalColors[2].setRgb(37,188,36); 259 | m_normalColors[3].setRgb(173,173,39); 260 | m_normalColors[4].setRgb(63,84,255); 261 | m_normalColors[5].setRgb(211,56,211); 262 | m_normalColors[6].setRgb(51,187,199); 263 | m_normalColors[7].setRgb(229,229,229); 264 | m_normalColors[8].setRgb(178,178,178); 265 | m_normalColors[9].setRgb(0,0,0); 266 | 267 | m_lightColors[0].setRgb(129,131,131); 268 | m_lightColors[1].setRgb(252,57,31); 269 | m_lightColors[2].setRgb(49,231,34); 270 | m_lightColors[3].setRgb(234,236,35); 271 | m_lightColors[4].setRgb(88,51,255); 272 | m_lightColors[5].setRgb(249,53,248); 273 | m_lightColors[6].setRgb(20,240,240); 274 | m_lightColors[7].setRgb(233,233,233); 275 | m_lightColors[8].setRgb(220,220,220); 276 | m_lightColors[9].setRgb(50,50,50); 277 | 278 | } 279 | 280 | QColor ColorPalette::color(ColorPalette::Color color, bool bold) const 281 | { 282 | if (m_inverse_default) { 283 | if (color == DefaultForeground) 284 | color = DefaultBackground; 285 | else if (color == DefaultBackground) 286 | color = DefaultForeground; 287 | } 288 | if (bold) 289 | return m_lightColors.at(color); 290 | 291 | return m_normalColors.at(color); 292 | } 293 | 294 | QColor ColorPalette::normalColor(ColorPalette::Color color) const 295 | { 296 | return this->color(color, false); 297 | } 298 | 299 | QColor ColorPalette::lightColor(ColorPalette::Color color) const 300 | { 301 | return this->color(color,true); 302 | } 303 | 304 | QRgb ColorPalette::normalRgb(int index) 305 | { 306 | return m_normalColors[index].rgb(); 307 | } 308 | 309 | QRgb ColorPalette::xtermRgb(int index) 310 | { 311 | Q_ASSERT(index >= 16); 312 | return m_xtermColors[index - 16]; 313 | } 314 | 315 | void ColorPalette::setInverseDefaultColors(bool inverse) 316 | { 317 | bool emit_changed = inverse != m_inverse_default; 318 | if (emit_changed) { 319 | m_inverse_default = inverse; 320 | emit changed(); 321 | emit defaultBackgroundColorChanged(); 322 | } 323 | } 324 | 325 | QColor ColorPalette::defaultForeground() const 326 | { 327 | return normalColor(DefaultForeground); 328 | } 329 | 330 | QColor ColorPalette::defaultBackground() const 331 | { 332 | return normalColor(DefaultBackground); 333 | } 334 | -------------------------------------------------------------------------------- /backend/color_palette.h: -------------------------------------------------------------------------------- 1 | #ifndef COLOR_PALETTE_H 2 | #define COLOR_PALETTE_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | 11 | class ColorPalette : public QObject 12 | { 13 | Q_OBJECT 14 | Q_PROPERTY(QColor defaultBackground READ defaultBackground NOTIFY defaultBackgroundColorChanged) 15 | public: 16 | ColorPalette(QObject *parent = 0); 17 | 18 | enum Color { 19 | Black, 20 | Red, 21 | Green, 22 | Yellow, 23 | Blue, 24 | Magenta, 25 | Cyan, 26 | White, 27 | DefaultForeground, 28 | DefaultBackground, 29 | numberOfColors 30 | }; 31 | Q_ENUM(Color) 32 | 33 | QColor color(Color color, bool bold = false) const; 34 | QColor normalColor(Color color) const; 35 | QColor lightColor(Color color) const; 36 | QRgb normalRgb(int index); 37 | QRgb xtermRgb(int index); 38 | 39 | void setInverseDefaultColors(bool inverse); 40 | 41 | QColor defaultForeground() const; 42 | QColor defaultBackground() const; 43 | signals: 44 | void changed(); 45 | void defaultBackgroundColorChanged(); 46 | 47 | private: 48 | QVector m_normalColors; 49 | QVector m_lightColors; 50 | QVector m_xtermColors; 51 | 52 | bool m_inverse_default; 53 | }; 54 | 55 | #endif // COLOR_PALETTE_H 56 | -------------------------------------------------------------------------------- /backend/controll_chars.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #ifndef CONTROLL_CHARS_H 25 | #define CONTROLL_CHARS_H 26 | 27 | //This is taken largely from Standard ECMA-48 28 | //http://www.ecma-international.org/publications/standards/Ecma-048.htm 29 | //Also to heres a few handy references 30 | //http://invisible-island.net/xterm/ctlseqs/ctlseqs.html 31 | //http://www.vt100.net/docs/vt100-ug/chapter3.html 32 | 33 | #include 34 | 35 | namespace C0 { 36 | enum C0 { 37 | NUL = 0x00, 38 | SOH = 0x01, 39 | STX = 0x02, 40 | ETX = 0x03, 41 | EOT = 0x04, 42 | ENQ = 0x05, 43 | ACK = 0x06, 44 | BEL = 0x07, 45 | BS = 0x08, 46 | HT = 0x09, 47 | LF = 0x0a, 48 | VT = 0x0b, 49 | FF = 0x0c, 50 | CR = 0x0d, 51 | SOorLS1 = 0x0e, 52 | SIorLS0 = 0x0f, 53 | DLE = 0x10, 54 | DC1 = 0x11, 55 | DC2 = 0x12, 56 | DC3 = 0x13, 57 | DC4 = 0x14, 58 | NAK = 0x15, 59 | SYN = 0x16, 60 | ETB = 0x17, 61 | CAN = 0x18, 62 | EM = 0x19, 63 | SUB = 0x1a, 64 | ESC = 0x1b, 65 | IS4 = 0x1c, 66 | IS3 = 0x1d, 67 | IS2 = 0x1e, 68 | IS1 = 0x1f, 69 | C0_END = 0x20 70 | }; 71 | QDebug operator<<(QDebug debug, C0 character); 72 | } 73 | 74 | namespace C1_7bit { 75 | enum C1_7bit { 76 | C1_7bit_Start = 0x1b, 77 | ESC = 0x1b, 78 | SCS_G0 = 0x28, 79 | SCS_G1 = 0x29, 80 | SCS_G2 = 0x2a, 81 | SCS_G3 = 0x2b, 82 | DECSC = 0x37, 83 | DECRC = 0x38, 84 | NOT_DEFINED = 0x40, 85 | NOT_DEFINED1 = 0x41, 86 | BPH = 0x42, 87 | NBH = 0x43, 88 | IND = 0x44, 89 | NEL = 0x45, 90 | SSA = 0x46, 91 | ESA = 0x47, 92 | HTS = 0x48, 93 | HTJ = 0x49, 94 | VTS = 0x4a, 95 | PLD = 0x4b, 96 | PLU = 0x4c, 97 | RI = 0x4d, 98 | SS2 = 0x4e, 99 | SS3 = 0x4f, 100 | DCS = 0x50, 101 | PU1 = 0x51, 102 | PU2 = 0x52, 103 | STS = 0x53, 104 | CCH = 0x54, 105 | MW = 0x55, 106 | SPA = 0x56, 107 | EPA = 0x57, 108 | SOS = 0x58, 109 | NOT_DEFINED3 = 0x59, 110 | SCI = 0x5a, 111 | CSI = 0x5b, 112 | ST = 0x5c, 113 | OSC = 0x5d, 114 | PM = 0x5e, 115 | APC = 0x5f, 116 | C1_7bit_Stop = 0x60 117 | }; 118 | QDebug operator<<(QDebug debug, C1_7bit character); 119 | } 120 | namespace C1_8bit { 121 | enum C1_8bit { 122 | C1_8bit_Start = 0x80, 123 | NOT_DEFINED = C1_8bit_Start, 124 | NOT_DEFINED1 = 0x81, 125 | BPH = 0x82, 126 | NBH = 0x83, 127 | NOT_DEFINED2 = 0x84, 128 | NEL = 0x85, 129 | SSA = 0x86, 130 | ESA = 0x87, 131 | HTS = 0x88, 132 | HTJ = 0x89, 133 | VTS = 0x8a, 134 | PLD = 0x8b, 135 | PLU = 0x8c, 136 | RI = 0x8d, 137 | SS2 = 0x8e, 138 | SS3 = 0x8f, 139 | DCS = 0x90, 140 | PU1 = 0x91, 141 | PU2C1_7bit = 0x92, 142 | STS = 0x93, 143 | CCH = 0x94, 144 | MW = 0x95, 145 | SPA = 0x96, 146 | EPA = 0x97, 147 | SOS = 0x98, 148 | NOT_DEFINED3 = 0x99, 149 | SCI = 0x9a, 150 | CSI = 0x9b, 151 | ST = 0x9c, 152 | OSC = 0x9d, 153 | PM = 0x9e, 154 | APC = 0x9f, 155 | C1_8bit_Stop = 0xa0 156 | }; 157 | QDebug operator<<(QDebug debug, C1_8bit character); 158 | } 159 | 160 | namespace FinalBytesNoIntermediate { 161 | enum FinalBytesNoIntermediate { 162 | ICH = 0x40, 163 | CUU = 0x41, 164 | CUD = 0x42, 165 | CUF = 0x43, 166 | CUB = 0x44, 167 | CNL = 0x45, 168 | CPL = 0x46, 169 | CHA = 0x47, 170 | CUP = 0x48, 171 | CHT = 0x49, 172 | ED = 0x4a, 173 | EL = 0x4b, 174 | IL = 0x4c, 175 | DL = 0x4d, 176 | EF = 0x4e, 177 | EA = 0x4f, 178 | DCH = 0x50, 179 | SSE = 0x51, 180 | CPR = 0x52, 181 | SU = 0x53, 182 | SD = 0x54, 183 | NP = 0x55, 184 | PP = 0x56, 185 | CTC = 0x57, 186 | ECH = 0x58, 187 | CVT = 0x59, 188 | CBT = 0x5a, 189 | SRS = 0x5b, 190 | PTX = 0x5c, 191 | SDS = 0x5d, 192 | SIMD = 0x5e, 193 | NOT_DEFINED = 0x5f, 194 | HPA = 0x60, 195 | HPR = 0x61, 196 | REP = 0x62, 197 | DA = 0x63, 198 | VPA = 0x64, 199 | VPR = 0x65, 200 | HVP = 0x66, 201 | TBC = 0x67, 202 | SM = 0x68, 203 | MC = 0x69, 204 | HPB = 0x6a, 205 | VPB = 0x6b, 206 | RM = 0x6c, 207 | SGR = 0x6d, 208 | DSR = 0x6e, 209 | DAQ = 0x6f, 210 | Reserved0 = 0x70, 211 | Reserved1 = 0x71, 212 | DECSTBM = 0x72, 213 | Reserved3 = 0x73, 214 | Reserved4 = 0x74, 215 | Reserved5 = 0x75, 216 | Reserved6 = 0x76, 217 | Reserved7 = 0x77, 218 | Reserved8 = 0x78, 219 | Reserved9 = 0x79, 220 | Reserveda = 0x7a, 221 | Reservedb = 0x7b, 222 | Reservedc = 0x7c, 223 | Reservedd = 0x7d, 224 | Reservede = 0x7e, 225 | Reservedf = 0x7f 226 | }; 227 | QDebug operator<<(QDebug debug, FinalBytesNoIntermediate character); 228 | } 229 | 230 | namespace FinalBytesSingleIntermediate { 231 | enum FinalBytesSingleIntermediate { 232 | SL = 0x40, 233 | SR = 0x41, 234 | GSM = 0x42, 235 | GSS = 0x43, 236 | FNT = 0x44, 237 | TSS = 0x45, 238 | JFY = 0x46, 239 | SPI = 0x47, 240 | QUAD = 0x48, 241 | SSU = 0x49, 242 | PFS = 0x4a, 243 | SHS = 0x4b, 244 | SVS = 0x4c, 245 | IGS = 0x4d, 246 | NOT_DEFINED = 0x4e, 247 | IDCS = 0x4f, 248 | PPA = 0x50, 249 | PPR = 0x51, 250 | PPB = 0x52, 251 | SPD = 0x53, 252 | DTA = 0x54, 253 | SHL = 0x55, 254 | SLL = 0x56, 255 | FNK = 0x57, 256 | SPQR = 0x58, 257 | SEF = 0x59, 258 | PEC = 0x5a, 259 | SSW = 0x5b, 260 | SACS = 0x5c, 261 | SAPV = 0x5d, 262 | STAB = 0x5e, 263 | GCC = 0x5f, 264 | TATE = 0x60, 265 | TALE = 0x61, 266 | TAC = 0x62, 267 | TCC = 0x63, 268 | TSR = 0x64, 269 | SCO = 0x65, 270 | SRCS = 0x66, 271 | SCS = 0x67, 272 | SLS = 0x68, 273 | NOT_DEFINED2 = 0x69, 274 | NOT_DEFINED3 = 0x6a, 275 | SCP = 0x6b, 276 | NOT_DEFINED4 = 0x6c, 277 | NOT_DEFINED5 = 0x6d, 278 | NOT_DEFINED6 = 0x6e, 279 | NOT_DEFINED7 = 0x6f, 280 | Reserved0 = 0x70, 281 | Reserved1 = 0x71, 282 | Reserved2 = 0x72, 283 | Reserved3 = 0x73, 284 | Reserved4 = 0x74, 285 | Reserved5 = 0x75, 286 | Reserved6 = 0x76, 287 | Reserved7 = 0x77, 288 | Reserved8 = 0x78, 289 | Reserved9 = 0x79, 290 | Reserveda = 0x7a, 291 | Reservedb = 0x7b, 292 | Reservedc = 0x7c, 293 | Reservedd = 0x7d, 294 | Reservedf = 0x7f 295 | }; 296 | QDebug operator<<(QDebug debug, FinalBytesSingleIntermediate character); 297 | } 298 | 299 | #endif // CONTROLL_CHARS_H 300 | -------------------------------------------------------------------------------- /backend/cursor.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #include "cursor.h" 25 | 26 | #include "block.h" 27 | #include "screen_data.h" 28 | 29 | #include 30 | #include 31 | 32 | Q_LOGGING_CATEGORY(lcCursor, "yat.cursor") 33 | 34 | Cursor::Cursor(Screen* screen) 35 | : QObject(screen) 36 | , m_screen(screen) 37 | , m_current_text_style(screen->defaultTextStyle()) 38 | , m_position(0,0) 39 | , m_new_position(0,0) 40 | , m_screen_width(screen->width()) 41 | , m_screen_height(screen->height()) 42 | , m_top_margin(0) 43 | , m_bottom_margin(0) 44 | , m_scroll_margins_set(false) 45 | , m_origin_at_margin(false) 46 | , m_notified(false) 47 | , m_visible(true) 48 | , m_new_visibillity(true) 49 | , m_blinking(false) 50 | , m_new_blinking(false) 51 | , m_wrap_around(true) 52 | , m_content_height_changed(false) 53 | , m_insert_mode(Replace) 54 | , m_resize_block(0) 55 | , m_current_pos_in_block(0) 56 | { 57 | connect(screen, &Screen::widthAboutToChange, this, &Cursor::setScreenWidthAboutToChange); 58 | connect(screen, &Screen::dataWidthChanged, this, &Cursor::setScreenWidth); 59 | connect(screen, &Screen::dataHeightChanged, this, &Cursor::setScreenHeight); 60 | connect(screen, &Screen::contentHeightChanged, this, &Cursor::contentHeightChanged); 61 | 62 | m_gl_text_codec = QTextCodec::codecForName("utf-8")->makeDecoder(); 63 | m_gr_text_codec = QTextCodec::codecForName("utf-8")->makeDecoder(); 64 | 65 | for (int i = 0; i < m_screen_width; i++) { 66 | if (i % 8 == 0) { 67 | m_tab_stops.append(i); 68 | } 69 | } 70 | } 71 | 72 | Cursor::~Cursor() 73 | { 74 | 75 | } 76 | 77 | void Cursor::setScreenWidthAboutToChange(int width) 78 | { 79 | Q_UNUSED(width); 80 | auto it = m_screen->currentScreenData()->it_for_row(new_y()); 81 | if (m_screen->currentScreenData()->it_is_end(it)) 82 | return; 83 | 84 | m_resize_block = *it; 85 | int line_diff = new_y() - m_resize_block->screenIndex(); 86 | m_current_pos_in_block = (line_diff * m_screen_width) + new_x(); 87 | } 88 | 89 | void Cursor::setScreenWidth(int newWidth, int removedBeginning, int reclaimed) 90 | { 91 | if (newWidth > m_screen_width) { 92 | for (int i = m_screen_width -1; i < newWidth; i++) { 93 | if (i % 8 == 0) { 94 | m_tab_stops.append(i); 95 | } 96 | } 97 | } 98 | 99 | m_screen_width = newWidth; 100 | 101 | auto it = m_screen->currentScreenData()->it_for_block(m_resize_block); 102 | if (m_screen->currentScreenData()->it_is_end(it)) { 103 | if (removedBeginning > reclaimed) { 104 | new_ry() = 0; 105 | new_rx() = 0; 106 | } else { 107 | new_ry() = m_screen_height - 1; 108 | new_rx() = 0; 109 | } 110 | } else { 111 | new_ry() = (*it)->screenIndex() + m_current_pos_in_block / newWidth; 112 | new_rx() = m_current_pos_in_block % newWidth; 113 | } 114 | m_resize_block = 0; 115 | m_current_pos_in_block = 0; 116 | notifyChanged(); 117 | } 118 | 119 | void Cursor::setScreenHeight(int newHeight, int removedBeginning, int reclaimed) 120 | { 121 | resetScrollArea(); 122 | m_screen_height = newHeight; 123 | new_ry() -= removedBeginning; 124 | new_ry() += reclaimed; 125 | if (new_y() <= 0) { 126 | new_ry() = 0; 127 | } 128 | } 129 | 130 | bool Cursor::visible() const 131 | { 132 | return m_visible; 133 | } 134 | void Cursor::setVisible(bool visible) 135 | { 136 | m_new_visibillity = visible; 137 | } 138 | 139 | bool Cursor::blinking() const 140 | { 141 | return m_blinking; 142 | } 143 | 144 | void Cursor::setBlinking(bool blinking) 145 | { 146 | m_new_blinking = blinking; 147 | } 148 | 149 | void Cursor::setTextStyle(TextStyle::Style style, bool add) 150 | { 151 | if (add) { 152 | m_current_text_style.style |= style; 153 | } else { 154 | m_current_text_style.style &= !style; 155 | } 156 | } 157 | 158 | void Cursor::resetStyle() 159 | { 160 | m_current_text_style.background = colorPalette()->defaultBackground().rgb(); 161 | m_current_text_style.foreground = colorPalette()->defaultForeground().rgb(); 162 | m_current_text_style.style = TextStyle::Normal; 163 | } 164 | 165 | void Cursor::scrollUp(int lines) 166 | { 167 | if (new_y() < top() || new_y() > bottom()) 168 | return; 169 | for (int i = 0; i < lines; i++) { 170 | screen_data()->moveLine(bottom(), top()); 171 | } 172 | } 173 | 174 | void Cursor::scrollDown(int lines) 175 | { 176 | if (new_y() < top() || new_y() > bottom()) 177 | return; 178 | for (int i = 0; i < lines; i++) { 179 | screen_data()->moveLine(top(), bottom()); 180 | } 181 | } 182 | 183 | void Cursor::setTextCodec(QTextCodec *codec) 184 | { 185 | m_gl_text_codec = codec->makeDecoder(); 186 | } 187 | 188 | void Cursor::setInsertMode(InsertMode mode) 189 | { 190 | m_insert_mode = mode; 191 | } 192 | 193 | TextStyle Cursor::currentTextStyle() const 194 | { 195 | return m_current_text_style; 196 | } 197 | 198 | void Cursor::setTextForegroundColor(QRgb color) 199 | { 200 | m_current_text_style.foreground = color; 201 | } 202 | 203 | void Cursor::setTextBackgroundColor(QRgb color) 204 | { 205 | m_current_text_style.background = color; 206 | } 207 | 208 | void Cursor::setTextForegroundColorIndex(ColorPalette::Color color) 209 | { 210 | qCDebug(lcCursor) << color; 211 | setTextForegroundColor(colorPalette()->color(color).rgb()); 212 | } 213 | 214 | void Cursor::setTextBackgroundColorIndex(ColorPalette::Color color) 215 | { 216 | qCDebug(lcCursor) << color; 217 | setTextBackgroundColor(colorPalette()->color(color).rgb()); 218 | } 219 | 220 | ColorPalette *Cursor::colorPalette() const 221 | { 222 | return m_screen->colorPalette(); 223 | } 224 | 225 | QPoint Cursor::position() const 226 | { 227 | return m_position; 228 | } 229 | 230 | int Cursor::x() const 231 | { 232 | return m_position.x(); 233 | } 234 | 235 | int Cursor::y() const 236 | { 237 | return (m_screen->currentScreenData()->contentHeight() - m_screen->height()) + m_position.y(); 238 | } 239 | 240 | void Cursor::moveOrigin() 241 | { 242 | m_new_position = QPoint(0,adjusted_top()); 243 | notifyChanged(); 244 | } 245 | 246 | void Cursor::moveBeginningOfLine() 247 | { 248 | new_rx() = 0; 249 | notifyChanged(); 250 | } 251 | 252 | void Cursor::moveUp(int lines) 253 | { 254 | int adjusted_new_y = this->adjusted_new_y(); 255 | if (!adjusted_new_y || !lines) 256 | return; 257 | 258 | if (lines < adjusted_new_y) { 259 | new_ry() -= lines; 260 | } else { 261 | new_ry() = adjusted_top(); 262 | } 263 | notifyChanged(); 264 | } 265 | 266 | void Cursor::moveDown(int lines) 267 | { 268 | int bottom = adjusted_bottom(); 269 | if (new_y() == bottom || !lines) 270 | return; 271 | 272 | if (new_y() + lines <= bottom) { 273 | new_ry() += lines; 274 | } else { 275 | new_ry() = bottom; 276 | } 277 | notifyChanged(); 278 | } 279 | 280 | void Cursor::moveLeft(int positions) 281 | { 282 | if (!new_x() || !positions) 283 | return; 284 | if (positions < new_x()) { 285 | new_rx() -= positions; 286 | } else { 287 | new_rx() = 0; 288 | } 289 | notifyChanged(); 290 | } 291 | 292 | void Cursor::moveRight(int positions) 293 | { 294 | int width = m_screen->width(); 295 | if (new_x() == width -1 || !positions) 296 | return; 297 | if (positions < width - new_x()) { 298 | new_rx() += positions; 299 | } else { 300 | new_rx() = width -1; 301 | } 302 | 303 | notifyChanged(); 304 | } 305 | 306 | void Cursor::move(int new_x, int new_y) 307 | { 308 | int width = m_screen->width(); 309 | 310 | if (m_origin_at_margin) { 311 | new_y += m_top_margin; 312 | } 313 | 314 | if (new_x < 0) { 315 | new_x = 0; 316 | } else if (new_x >= width) { 317 | new_x = width - 1; 318 | } 319 | 320 | if (new_y < adjusted_top()) { 321 | new_y = adjusted_top(); 322 | } else if (new_y > adjusted_bottom()) { 323 | new_y = adjusted_bottom(); 324 | } 325 | 326 | if (this->new_y() != new_y || this->new_x() != new_x) { 327 | m_new_position = QPoint(new_x, new_y); 328 | notifyChanged(); 329 | } 330 | } 331 | 332 | void Cursor::moveToLine(int line) 333 | { 334 | const int height = m_screen->height(); 335 | if (line < adjusted_top()) { 336 | line = 0; 337 | } else if (line > adjusted_bottom()) { 338 | line = height -1; 339 | } 340 | 341 | if (line != new_y()) { 342 | new_rx() = line; 343 | notifyChanged(); 344 | } 345 | } 346 | 347 | void Cursor::moveToCharacter(int character) 348 | { 349 | const int width = m_screen->width(); 350 | if (character < 0) { 351 | character = 1; 352 | } else if (character > width) { 353 | character = width; 354 | } 355 | if (character != new_x()) { 356 | new_rx() = character; 357 | notifyChanged(); 358 | } 359 | } 360 | 361 | void Cursor::moveToNextTab() 362 | { 363 | for (int i = 0; i < m_tab_stops.size(); i++) { 364 | if (new_x() < m_tab_stops.at(i)) { 365 | moveToCharacter(std::min(m_tab_stops.at(i), m_screen_width -1)); 366 | return; 367 | } 368 | } 369 | moveToCharacter(m_screen_width - 1); 370 | } 371 | 372 | void Cursor::setTabStop() 373 | { 374 | int i; 375 | for (i = 0; i < m_tab_stops.size(); i++) { 376 | if (new_x() == m_tab_stops.at(i)) 377 | return; 378 | if (new_x() > m_tab_stops.at(i)) { 379 | continue; 380 | } else { 381 | break; 382 | } 383 | } 384 | m_tab_stops.insert(i,new_x()); 385 | } 386 | 387 | void Cursor::removeTabStop() 388 | { 389 | for (int i = 0; i < m_tab_stops.size(); i++) { 390 | if (new_x() == m_tab_stops.at(i)) { 391 | m_tab_stops.remove(i); 392 | return; 393 | } else if (new_x() < m_tab_stops.at(i)) { 394 | return; 395 | } 396 | } 397 | } 398 | 399 | void Cursor::clearTabStops() 400 | { 401 | m_tab_stops.clear(); 402 | } 403 | 404 | void Cursor::clearToBeginningOfLine() 405 | { 406 | screen_data()->clearToBeginningOfLine(m_new_position); 407 | } 408 | 409 | void Cursor::clearToEndOfLine() 410 | { 411 | screen_data()->clearToEndOfLine(m_new_position); 412 | } 413 | 414 | void Cursor::clearToBeginningOfScreen() 415 | { 416 | clearToBeginningOfLine(); 417 | if (new_y() > 0) 418 | screen_data()->clearToBeginningOfScreen(m_new_position.y()-1); 419 | } 420 | 421 | void Cursor::clearToEndOfScreen() 422 | { 423 | clearToEndOfLine(); 424 | if (new_y() < m_screen->height() -1) { 425 | screen_data()->clearToEndOfScreen(m_new_position.y()+1); 426 | } 427 | } 428 | 429 | void Cursor::clearLine() 430 | { 431 | screen_data()->clearLine(m_new_position); 432 | } 433 | 434 | void Cursor::deleteCharacters(int characters) 435 | { 436 | screen_data()->deleteCharacters(m_new_position, new_x() + characters -1); 437 | } 438 | 439 | void Cursor::setWrapAround(bool wrap) 440 | { 441 | m_wrap_around = wrap; 442 | } 443 | 444 | void Cursor::addAtCursor(const QByteArray &data, bool only_latin) 445 | { 446 | if (m_insert_mode == Replace) { 447 | replaceAtCursor(data, only_latin); 448 | } else { 449 | insertAtCursor(data, only_latin); 450 | } 451 | } 452 | 453 | void Cursor::replaceAtCursor(const QByteArray &data, bool only_latin) 454 | { 455 | const QString text = m_gl_text_codec->toUnicode(data); 456 | 457 | if (!m_wrap_around && new_x() + text.size() > m_screen->width()) { 458 | const int size = m_screen_width - new_x(); 459 | QString toBlock = text.mid(0,size); 460 | toBlock.replace(toBlock.size() - 1, 1, text.at(text.size()-1)); 461 | screen_data()->replace(m_new_position, toBlock, m_current_text_style, only_latin); 462 | new_rx() += toBlock.size(); 463 | } else { 464 | auto diff = screen_data()->replace(m_new_position, text, m_current_text_style, only_latin); 465 | new_rx() += diff.character; 466 | new_ry() += diff.line; 467 | } 468 | 469 | if (new_y() >= m_screen_height) { 470 | new_ry() = m_screen_height - 1; 471 | } 472 | 473 | notifyChanged(); 474 | } 475 | 476 | void Cursor::insertAtCursor(const QByteArray &data, bool only_latin) 477 | { 478 | const QString text = m_gl_text_codec->toUnicode(data); 479 | auto diff = screen_data()->insert(m_new_position, text, m_current_text_style, only_latin); 480 | new_rx() += diff.character; 481 | new_ry() += diff.line; 482 | if (new_y() >= m_screen_height) 483 | new_ry() = m_screen_height - 1; 484 | if (new_x() >= m_screen_width) 485 | new_rx() = m_screen_width - 1; 486 | } 487 | 488 | void Cursor::lineFeed() 489 | { 490 | if(new_y() >= bottom()) { 491 | screen_data()->insertLine(bottom(), top()); 492 | } else { 493 | new_ry()++; 494 | notifyChanged(); 495 | } 496 | } 497 | 498 | void Cursor::reverseLineFeed() 499 | { 500 | if (new_y() == top()) { 501 | scrollUp(1); 502 | } else { 503 | new_ry()--; 504 | notifyChanged(); 505 | } 506 | } 507 | 508 | void Cursor::setOriginAtMargin(bool atMargin) 509 | { 510 | m_origin_at_margin = atMargin; 511 | m_new_position = QPoint(0, adjusted_top()); 512 | notifyChanged(); 513 | } 514 | 515 | void Cursor::setScrollArea(int from, int to) 516 | { 517 | m_top_margin = from; 518 | m_bottom_margin = std::min(to,m_screen_height -1); 519 | m_scroll_margins_set = true; 520 | } 521 | 522 | void Cursor::resetScrollArea() 523 | { 524 | m_top_margin = 0; 525 | m_bottom_margin = 0; 526 | m_scroll_margins_set = false; 527 | } 528 | 529 | void Cursor::dispatchEvents() 530 | { 531 | if (m_new_position != m_position|| m_content_height_changed) { 532 | bool emit_x_changed = m_new_position.x() != m_position.x(); 533 | bool emit_y_changed = m_new_position.y() != m_position.y(); 534 | m_position = m_new_position; 535 | if (emit_x_changed) 536 | emit xChanged(); 537 | if (emit_y_changed || m_content_height_changed) 538 | emit yChanged(); 539 | } 540 | 541 | if (m_new_visibillity != m_visible) { 542 | m_visible = m_new_visibillity; 543 | emit visibilityChanged(); 544 | } 545 | 546 | if (m_new_blinking != m_blinking) { 547 | m_blinking = m_new_blinking; 548 | emit blinkingChanged(); 549 | } 550 | } 551 | 552 | void Cursor::contentHeightChanged() 553 | { 554 | m_content_height_changed = true; 555 | } 556 | 557 | -------------------------------------------------------------------------------- /backend/cursor.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #ifndef CURSOR_H 25 | #define CURSOR_H 26 | 27 | #include "text_style.h" 28 | #include "screen.h" 29 | 30 | #include 31 | 32 | class Cursor : public QObject 33 | { 34 | Q_OBJECT 35 | 36 | Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibilityChanged) 37 | Q_PROPERTY(bool blinking READ blinking WRITE setBlinking NOTIFY blinkingChanged) 38 | Q_PROPERTY(int x READ x NOTIFY xChanged) 39 | Q_PROPERTY(int y READ y NOTIFY yChanged) 40 | public: 41 | enum InsertMode { 42 | Insert, 43 | Replace 44 | }; 45 | 46 | Cursor(Screen *screen); 47 | ~Cursor(); 48 | 49 | bool visible() const; 50 | void setVisible(bool visible); 51 | 52 | bool blinking() const; 53 | void setBlinking(bool blinking); 54 | 55 | void setTextStyle(TextStyle::Style style, bool add = true); 56 | void resetStyle(); 57 | TextStyle currentTextStyle() const; 58 | 59 | ColorPalette *colorPalette() const; 60 | void setTextForegroundColor(QRgb color); 61 | void setTextBackgroundColor(QRgb color); 62 | void setTextForegroundColorIndex(ColorPalette::Color color); 63 | void setTextBackgroundColorIndex(ColorPalette::Color color); 64 | 65 | QPoint position() const; 66 | int x() const; 67 | int y() const; 68 | int new_x() const { return m_new_position.x(); } 69 | int new_y() const { return m_new_position.y(); } 70 | 71 | void moveOrigin(); 72 | void moveBeginningOfLine(); 73 | void moveUp(int lines = 1); 74 | void moveDown(int lines = 1); 75 | void moveLeft(int positions = 1); 76 | void moveRight(int positions = 1); 77 | void move(int new_x, int new_y); 78 | void moveToLine(int line); 79 | void moveToCharacter(int character); 80 | 81 | void moveToNextTab(); 82 | void setTabStop(); 83 | void removeTabStop(); 84 | void clearTabStops(); 85 | 86 | void clearToBeginningOfLine(); 87 | void clearToEndOfLine(); 88 | void clearToBeginningOfScreen(); 89 | void clearToEndOfScreen(); 90 | void clearLine(); 91 | 92 | void deleteCharacters(int characters); 93 | 94 | void setWrapAround(bool wrap); 95 | void addAtCursor(const QByteArray &text, bool only_latin = true); 96 | void insertAtCursor(const QByteArray &text, bool only_latin = true); 97 | void replaceAtCursor(const QByteArray &text, bool only_latin = true); 98 | 99 | void lineFeed(); 100 | void reverseLineFeed(); 101 | 102 | void setOriginAtMargin(bool atMargin); 103 | void setScrollArea(int from, int to); 104 | void resetScrollArea(); 105 | 106 | void scrollUp(int lines); 107 | void scrollDown(int lines); 108 | 109 | void setTextCodec(QTextCodec *codec); 110 | 111 | void setInsertMode(InsertMode mode); 112 | 113 | inline void notifyChanged(); 114 | void dispatchEvents(); 115 | 116 | public slots: 117 | void setScreenWidthAboutToChange(int width); 118 | void setScreenWidth(int newWidth, int removedBeginning, int reclaimed); 119 | void setScreenHeight(int newHeight, int removedBeginning, int reclaimed); 120 | 121 | signals: 122 | void xChanged(); 123 | void yChanged(); 124 | void visibilityChanged(); 125 | void blinkingChanged(); 126 | 127 | private slots: 128 | void contentHeightChanged(); 129 | 130 | private: 131 | ScreenData *screen_data() const { return m_screen->currentScreenData(); } 132 | int &new_rx() { return m_new_position.rx(); } 133 | int &new_ry() { return m_new_position.ry(); } 134 | int adjusted_new_x() const { return m_origin_at_margin ? 135 | m_new_position.x() - m_top_margin : m_new_position.x(); } 136 | int adjusted_new_y() const { return m_origin_at_margin ? 137 | m_new_position.y() - m_top_margin : m_new_position.y(); } 138 | int adjusted_top() const { return m_origin_at_margin ? m_top_margin : 0; } 139 | int adjusted_bottom() const { return m_origin_at_margin ? m_bottom_margin : m_screen_height - 1; } 140 | int top() const { return m_scroll_margins_set ? m_top_margin : 0; } 141 | int bottom() const { return m_scroll_margins_set ? m_bottom_margin : m_screen_height - 1; } 142 | Screen *m_screen; 143 | TextStyle m_current_text_style; 144 | QPoint m_position; 145 | QPoint m_new_position; 146 | 147 | int m_screen_width; 148 | int m_screen_height; 149 | 150 | int m_top_margin; 151 | int m_bottom_margin; 152 | bool m_scroll_margins_set; 153 | bool m_origin_at_margin; 154 | 155 | QVector m_tab_stops; 156 | 157 | bool m_notified; 158 | bool m_visible; 159 | bool m_new_visibillity; 160 | bool m_blinking; 161 | bool m_new_blinking; 162 | bool m_wrap_around; 163 | bool m_content_height_changed; 164 | 165 | QTextDecoder *m_gl_text_codec; 166 | QTextDecoder *m_gr_text_codec; 167 | 168 | InsertMode m_insert_mode; 169 | 170 | Block *m_resize_block; 171 | int m_current_pos_in_block; 172 | }; 173 | 174 | void Cursor::notifyChanged() 175 | { 176 | if (!m_notified) { 177 | m_notified = true; 178 | m_screen->scheduleEventDispatch(); 179 | } 180 | } 181 | 182 | #endif //CUROSOR_H 183 | -------------------------------------------------------------------------------- /backend/main.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************************** 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | * associated documentation files (the "Software"), to deal in the Software without restriction, 6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 17 | * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | ***************************************************************************************************/ 20 | 21 | #include "terminal_state.h" 22 | 23 | #include 24 | 25 | int main(int argc, char *argv[]) 26 | { 27 | QGuiApplication app(argc, argv); 28 | 29 | TerminalState state; 30 | 31 | return app.exec(); 32 | } 33 | -------------------------------------------------------------------------------- /backend/nrc_text_codec.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #include "nrc_text_codec.h" 25 | 26 | static bool nrc_text_codec_init = false; 27 | void NrcTextCodec::initialize() 28 | { 29 | if (!nrc_text_codec_init) { 30 | nrc_text_codec_init = true; 31 | new NrcTextCodec("dec_special_graphics", 500001, dec_special_graphics_char_set); 32 | new NrcTextCodec("nrc_british", 500002, nrc_british_char_set); 33 | new NrcTextCodec("nrc_norwegian_danish", 5002, nrc_norwegian_danish_char_set); 34 | new NrcTextCodec("nrc_dutch", 5002, nrc_dutch_char_set); 35 | new NrcTextCodec("nrc_finnish", 5002, nrc_finnish_char_set); 36 | new NrcTextCodec("nrc_french", 5002, nrc_french_char_set); 37 | new NrcTextCodec("nrc_french_canadian", 5002, nrc_french_canadian_char_set); 38 | new NrcTextCodec("nrc_german", 5002, nrc_german_char_set); 39 | new NrcTextCodec("nrc_italian", 5002, nrc_italian_char_set); 40 | new NrcTextCodec("nrc_spanish", 5002, nrc_spanish_char_set); 41 | new NrcTextCodec("nrc_swedish", 5002, nrc_swedish_char_set); 42 | new NrcTextCodec("nrc_swiss", 5002, nrc_swiss_char_set); 43 | } 44 | } 45 | 46 | NrcTextCodec::NrcTextCodec(const QByteArray &name, int mib, const QChar character_set[]) 47 | : QTextCodec() 48 | , m_name(name) 49 | , m_mib(mib) 50 | , m_character_set(character_set) 51 | { 52 | } 53 | 54 | QByteArray NrcTextCodec::name() const 55 | { 56 | return m_name; 57 | } 58 | int NrcTextCodec::mibEnum() const 59 | { 60 | return m_mib; 61 | } 62 | 63 | QString NrcTextCodec::convertToUnicode(const char *in, int length, QTextCodec::ConverterState *state) const 64 | { 65 | QString ret_str; 66 | ret_str.reserve(length); 67 | for (int i = 0; i < length; i++) { 68 | uchar in_char = *(in + i); 69 | if (in_char < 128) { 70 | QChar unicode = m_character_set[in_char]; 71 | if (unicode.isNull()) 72 | unicode = QChar(in_char); 73 | ret_str.append(unicode); 74 | } else { 75 | if (state) { 76 | if (state->flags & QTextCodec::ConvertInvalidToNull) { 77 | state->invalidChars++; 78 | ret_str.append(0); 79 | } else { 80 | state->invalidChars++; 81 | state->remainingChars = length - i; 82 | return ret_str; 83 | } 84 | } 85 | } 86 | } 87 | return ret_str; 88 | } 89 | 90 | QByteArray NrcTextCodec::convertFromUnicode(const QChar *in, int length, ConverterState *state) const 91 | { 92 | QByteArray ret_array; 93 | ret_array.reserve(length); 94 | 95 | for (int i = 0; i < length; i++) { 96 | QChar out_char = *(in + i); 97 | if (out_char.unicode() < 128) { 98 | uchar out = out_char.unicode(); 99 | ret_array.append(out); 100 | } else { 101 | bool found = false; 102 | for (uchar n = 0; n < 128; n++) { 103 | if (m_character_set[n] == out_char) { 104 | ret_array.append(n); 105 | found = true; 106 | break; 107 | } 108 | } 109 | 110 | if (!found && state) { 111 | if (state->flags & QTextCodec::ConvertInvalidToNull) { 112 | state->invalidChars++; 113 | ret_array.append(char(0)); 114 | } else { 115 | state->invalidChars++; 116 | state->remainingChars = length - i; 117 | return ret_array; 118 | } 119 | } 120 | } 121 | } 122 | return ret_array; 123 | } 124 | 125 | -------------------------------------------------------------------------------- /backend/nrc_text_codec.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #include "character_sets.h" 25 | 26 | #include 27 | #include 28 | 29 | class NrcTextCodec : public QTextCodec 30 | { 31 | public: 32 | NrcTextCodec(const QByteArray &name, int mib, const QChar character_set[]); 33 | QByteArray name() const; 34 | int mibEnum() const; 35 | 36 | static void initialize(); 37 | protected: 38 | QString convertToUnicode(const char *in, int length, ConverterState *state) const; 39 | QByteArray convertFromUnicode(const QChar *in, int length, ConverterState *state) const; 40 | 41 | private: 42 | const QByteArray m_name; 43 | const int m_mib; 44 | const QChar *m_character_set; 45 | }; 46 | -------------------------------------------------------------------------------- /backend/parser.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #ifndef PARSER_H 25 | #define PARSER_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "controll_chars.h" 32 | #include "utf8_decoder.h" 33 | 34 | class Screen; 35 | 36 | class Parser 37 | { 38 | public: 39 | Parser(Screen *screen); 40 | 41 | void addData(const QByteArray &data); 42 | 43 | private: 44 | 45 | enum DecodeState { 46 | PlainText, 47 | DecodeC0, 48 | DecodeC1_7bit, 49 | DecodeCSI, 50 | DecodeOSC, 51 | DecodeCharacterSet, 52 | DecodeFontSize 53 | }; 54 | 55 | enum DecodeOSCState { 56 | None, 57 | ChangeWindowAndIconName, 58 | ChangeIconTitle, 59 | ChangeWindowTitle, 60 | FilePath, 61 | Unknown 62 | }; 63 | 64 | void decodeC0(uchar character); 65 | void decodeC1_7bit(uchar character); 66 | void decodeParameters(uchar character); 67 | void decodeCSI(uchar character); 68 | void decodeOSC(uchar character); 69 | void decodeCharacterSet(uchar character); 70 | void decodeFontSize(uchar character); 71 | 72 | void setMode(int mode); 73 | void setDecMode(int mode); 74 | void resetMode(int mode); 75 | void resetDecMode(int mode); 76 | 77 | void handleSGR(); 78 | int handleXtermColor(int param, int i); 79 | 80 | void tokenFinished(); 81 | 82 | void appendParameter(); 83 | void handleDefaultParameters(int defaultValue); 84 | 85 | DecodeState m_decode_state; 86 | DecodeOSCState m_decode_osc_state; 87 | QByteArray m_osc_data; 88 | 89 | QByteArray m_current_data; 90 | 91 | int m_current_token_start; 92 | int m_current_position; 93 | 94 | QChar m_intermediate_char; 95 | 96 | QByteArray m_parameter_string; 97 | QVector m_parameters; 98 | bool m_parameters_expecting_more; 99 | bool m_dec_mode; 100 | bool m_gt_param; 101 | bool m_lnm_mode_set; 102 | bool m_contains_only_latin; 103 | 104 | int m_decode_graphics_set; 105 | QTextCodec *m_graphic_codecs[4]; 106 | Utf8Decoder m_utf8_decoder; 107 | 108 | Screen *m_screen; 109 | friend QDebug operator<<(QDebug debug, DecodeState decodeState); 110 | }; 111 | QDebug operator<<(QDebug debug, Parser::DecodeState decodeState); 112 | 113 | #endif // PARSER_H 114 | -------------------------------------------------------------------------------- /backend/screen.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | ******************************************************************************/ 23 | 24 | #include "screen.h" 25 | 26 | #include "screen_data.h" 27 | #include "block.h" 28 | #include "cursor.h" 29 | #include "text.h" 30 | #include "scrollback.h" 31 | #include "selection.h" 32 | 33 | #include "controll_chars.h" 34 | #include "character_sets.h" 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | #include 43 | #include 44 | 45 | Screen::Screen(QObject *parent) 46 | : QObject(parent) 47 | , m_palette(new ColorPalette(this)) 48 | , m_parser(this) 49 | , m_timer_event_id(0) 50 | , m_width(1) 51 | , m_height(0) 52 | , m_primary_data(new ScreenData(500, this)) 53 | , m_alternate_data(new ScreenData(0, this)) 54 | , m_current_data(m_primary_data) 55 | , m_old_current_data(m_primary_data) 56 | , m_selection(new Selection(this)) 57 | , m_flash(false) 58 | , m_cursor_changed(false) 59 | , m_application_cursor_key_mode(false) 60 | , m_fast_scroll(true) 61 | , m_default_background(m_palette->normalColor(ColorPalette::DefaultBackground)) 62 | { 63 | Cursor *cursor = new Cursor(this); 64 | m_cursor_stack << cursor; 65 | m_new_cursors << cursor; 66 | 67 | connect(m_primary_data, SIGNAL(contentHeightChanged()), this, SIGNAL(contentHeightChanged())); 68 | connect(m_primary_data, &ScreenData::contentModified, this, &Screen::contentModified); 69 | connect(m_primary_data, &ScreenData::dataHeightChanged, this, &Screen::dataHeightChanged); 70 | connect(m_primary_data, &ScreenData::dataWidthChanged, this, &Screen::dataWidthChanged); 71 | connect(m_palette, SIGNAL(changed()), this, SLOT(paletteChanged())); 72 | 73 | setHeight(25); 74 | setWidth(80); 75 | 76 | connect(&m_pty, &YatPty::readyRead, this, &Screen::readData); 77 | connect(&m_pty, &YatPty::hangupReceived,this, &Screen::hangup); 78 | 79 | } 80 | 81 | Screen::~Screen() 82 | { 83 | 84 | for(int i = 0; i < m_to_delete.size(); i++) { 85 | delete m_to_delete.at(i); 86 | } 87 | //m_to_delete.clear(); 88 | 89 | delete m_primary_data; 90 | delete m_alternate_data; 91 | } 92 | 93 | 94 | QColor Screen::defaultForegroundColor() const 95 | { 96 | return m_palette->normalColor(ColorPalette::DefaultForeground); 97 | } 98 | 99 | QColor Screen::defaultBackgroundColor() const 100 | { 101 | return m_palette->normalColor(ColorPalette::DefaultBackground); 102 | } 103 | 104 | void Screen::emitRequestHeight(int newHeight) 105 | { 106 | emit requestHeightChange(newHeight); 107 | } 108 | 109 | void Screen::setHeight(int height) 110 | { 111 | height = std::max(1, height); 112 | if (height == m_height) 113 | return; 114 | 115 | m_height = height; 116 | 117 | m_primary_data->setHeight(height, currentCursor()->new_y()); 118 | m_alternate_data->setHeight(height, currentCursor()->new_y()); 119 | 120 | m_pty.setHeight(height, height * 10); 121 | 122 | emit heightChanged(); 123 | scheduleEventDispatch(); 124 | } 125 | 126 | int Screen::height() const 127 | { 128 | return m_height; 129 | } 130 | 131 | int Screen::contentHeight() const 132 | { 133 | return currentScreenData()->contentHeight(); 134 | } 135 | 136 | void Screen::emitRequestWidth(int newWidth) 137 | { 138 | emit requestWidthChange(newWidth); 139 | } 140 | 141 | void Screen::setWidth(int width) 142 | { 143 | width = std::max(1,width); 144 | if (width == m_width) 145 | return; 146 | 147 | emit widthAboutToChange(width); 148 | 149 | m_width = width; 150 | 151 | m_primary_data->setWidth(width); 152 | m_alternate_data->setWidth(width); 153 | 154 | m_pty.setWidth(width, width * 10); 155 | 156 | emit widthChanged(); 157 | scheduleEventDispatch(); 158 | } 159 | 160 | int Screen::width() const 161 | { 162 | return m_width; 163 | } 164 | 165 | void Screen::useAlternateScreenBuffer() 166 | { 167 | if (m_current_data == m_primary_data) { 168 | disconnect(m_primary_data, SIGNAL(contentHeightChanged()), this, SIGNAL(contentHeightChanged())); 169 | disconnect(m_primary_data, &ScreenData::contentModified, this, &Screen::contentModified); 170 | disconnect(m_primary_data, &ScreenData::dataHeightChanged, this, &Screen::dataHeightChanged); 171 | disconnect(m_primary_data, &ScreenData::dataWidthChanged, this, &Screen::dataWidthChanged); 172 | m_current_data = m_alternate_data; 173 | m_current_data->clear(); 174 | connect(m_alternate_data, SIGNAL(contentHeightChanged()), this, SIGNAL(contentHeightChanged())); 175 | connect(m_alternate_data, &ScreenData::contentModified, this, &Screen::contentModified); 176 | connect(m_alternate_data, &ScreenData::dataHeightChanged, this, &Screen::dataHeightChanged); 177 | connect(m_alternate_data, &ScreenData::dataWidthChanged, this, &Screen::dataWidthChanged); 178 | emit contentHeightChanged(); 179 | } 180 | } 181 | 182 | void Screen::useNormalScreenBuffer() 183 | { 184 | if (m_current_data == m_alternate_data) { 185 | disconnect(m_alternate_data, SIGNAL(contentHeightChanged()), this, SIGNAL(contentHeightChanged())); 186 | disconnect(m_alternate_data, &ScreenData::contentModified, this, &Screen::contentModified); 187 | disconnect(m_alternate_data, &ScreenData::dataHeightChanged, this, &Screen::dataHeightChanged); 188 | disconnect(m_alternate_data, &ScreenData::dataWidthChanged, this, &Screen::dataWidthChanged); 189 | m_current_data = m_primary_data; 190 | connect(m_primary_data, SIGNAL(contentHeightChanged()), this, SIGNAL(contentHeightChanged())); 191 | connect(m_primary_data, &ScreenData::contentModified, this, &Screen::contentModified); 192 | connect(m_primary_data, &ScreenData::dataHeightChanged, this, &Screen::dataHeightChanged); 193 | connect(m_primary_data, &ScreenData::dataWidthChanged, this, &Screen::dataWidthChanged); 194 | emit contentHeightChanged(); 195 | } 196 | } 197 | 198 | TextStyle Screen::defaultTextStyle() const 199 | { 200 | TextStyle style; 201 | style.style = TextStyle::Normal; 202 | style.foreground = colorPalette()->defaultForeground().rgb(); 203 | style.background = colorPalette()->defaultBackground().rgb(); 204 | return style; 205 | } 206 | 207 | void Screen::saveCursor() 208 | { 209 | Cursor *new_cursor = new Cursor(this); 210 | if (m_cursor_stack.size()) 211 | m_cursor_stack.last()->setVisible(false); 212 | m_cursor_stack << new_cursor; 213 | m_new_cursors << new_cursor; 214 | } 215 | 216 | void Screen::restoreCursor() 217 | { 218 | if (m_cursor_stack.size() <= 1) 219 | return; 220 | 221 | m_delete_cursors.append(m_cursor_stack.takeLast()); 222 | m_cursor_stack.last()->setVisible(true); 223 | } 224 | 225 | void Screen::clearScreen() 226 | { 227 | currentScreenData()->clear(); 228 | } 229 | 230 | 231 | ColorPalette *Screen::colorPalette() const 232 | { 233 | return m_palette; 234 | } 235 | 236 | void Screen::fill(const QChar character) 237 | { 238 | currentScreenData()->fill(character); 239 | } 240 | 241 | void Screen::clear() 242 | { 243 | fill(QChar(' ')); 244 | } 245 | 246 | void Screen::setFastScroll(bool fast) 247 | { 248 | m_fast_scroll = fast; 249 | } 250 | 251 | bool Screen::fastScroll() const 252 | { 253 | return m_fast_scroll; 254 | } 255 | 256 | Selection *Screen::selection() const 257 | { 258 | return m_selection; 259 | } 260 | 261 | void Screen::doubleClicked(double character, double line) 262 | { 263 | QPoint start, end; 264 | int64_t charInt = std::llround(character); 265 | int64_t lineInt = std::llround(line); 266 | Q_ASSERT(charInt >= 0); 267 | //Q_ASSERT(charInt < std::numeric_limits::max()); 268 | Q_ASSERT(lineInt >= 0); 269 | //Q_ASSERT(lineInt < std::numeric_limits::max()); 270 | auto selectionRange = currentScreenData()->getDoubleClickSelectionRange(charInt, lineInt); 271 | m_selection->setStartX(selectionRange.start.x()); 272 | m_selection->setStartY(selectionRange.start.y()); 273 | m_selection->setEndX(selectionRange.end.x()); 274 | m_selection->setEndY(selectionRange.end.y()); 275 | } 276 | 277 | void Screen::setTitle(const QString &title) 278 | { 279 | m_title = title; 280 | emit screenTitleChanged(); 281 | } 282 | 283 | QString Screen::title() const 284 | { 285 | return m_title; 286 | } 287 | 288 | QString Screen::platformName() const 289 | { 290 | return qGuiApp->platformName(); 291 | } 292 | 293 | void Screen::scheduleFlash() 294 | { 295 | m_flash = true; 296 | } 297 | 298 | void Screen::printScreen() const 299 | { 300 | currentScreenData()->printStyleInformation(); 301 | qDebug() << "Total height: " << currentScreenData()->contentHeight(); 302 | } 303 | 304 | void Screen::scheduleEventDispatch() 305 | { 306 | if (!m_timer_event_id) { 307 | m_timer_event_id = startTimer(1); 308 | m_time_since_initiated.restart(); 309 | } 310 | 311 | m_time_since_parsed.restart(); 312 | } 313 | 314 | void Screen::dispatchChanges() 315 | { 316 | if (m_old_current_data != m_current_data) { 317 | m_old_current_data->releaseTextObjects(); 318 | m_old_current_data = m_current_data; 319 | } 320 | 321 | currentScreenData()->dispatchLineEvents(); 322 | emit dispatchTextSegmentChanges(); 323 | 324 | //be smarter than this 325 | static int max_to_delete_size = 0; 326 | if (max_to_delete_size < m_to_delete.size()) { 327 | max_to_delete_size = m_to_delete.size(); 328 | } 329 | 330 | if (m_flash) { 331 | m_flash = false; 332 | emit flash(); 333 | } 334 | 335 | for (int i = 0; i < m_delete_cursors.size(); i++) { 336 | int new_index = m_new_cursors.indexOf(m_delete_cursors.at(i)); 337 | if (new_index >= 0) 338 | m_new_cursors.remove(new_index); 339 | delete m_delete_cursors.at(i); 340 | } 341 | m_delete_cursors.clear(); 342 | 343 | for (int i = 0; i < m_new_cursors.size(); i++) { 344 | emit cursorCreated(m_new_cursors.at(i)); 345 | } 346 | m_new_cursors.clear(); 347 | 348 | for (int i = 0; i < m_cursor_stack.size(); i++) { 349 | m_cursor_stack[i]->dispatchEvents(); 350 | } 351 | 352 | m_selection->dispatchChanges(); 353 | } 354 | 355 | void Screen::sendPrimaryDA() 356 | { 357 | m_pty.write(QByteArrayLiteral("\033[?6c")); 358 | 359 | } 360 | 361 | void Screen::sendSecondaryDA() 362 | { 363 | m_pty.write(QByteArrayLiteral("\033[>1;95;0c")); 364 | } 365 | 366 | void Screen::setApplicationCursorKeysMode(bool enable) 367 | { 368 | m_application_cursor_key_mode = enable; 369 | } 370 | 371 | bool Screen::applicationCursorKeyMode() const 372 | { 373 | return m_application_cursor_key_mode; 374 | } 375 | 376 | void Screen::ensureVisiblePages(int top_line) 377 | { 378 | currentScreenData()->ensureVisiblePages(top_line); 379 | } 380 | 381 | static bool hasControll(Qt::KeyboardModifiers modifiers) 382 | { 383 | #ifdef Q_OS_MAC 384 | return modifiers & Qt::MetaModifier; 385 | #else 386 | return modifiers & Qt::ControlModifier; 387 | #endif 388 | } 389 | 390 | static bool hasMeta(Qt::KeyboardModifiers modifiers) 391 | { 392 | #ifdef Q_OS_MAC 393 | return modifiers & Qt::ControlModifier; 394 | #else 395 | return modifiers & Qt::MetaModifier; 396 | #endif 397 | } 398 | 399 | void Screen::sendKey(const QString &text, Qt::Key key, Qt::KeyboardModifiers modifiers) 400 | { 401 | 402 | // if (key == Qt::Key_Control) 403 | // printScreen(); 404 | /// UGH, this function should be re-written 405 | char escape = '\0'; 406 | char control = '\0'; 407 | char code = '\0'; 408 | QVector parameters; 409 | bool found = true; 410 | 411 | switch(key) { 412 | case Qt::Key_Up: 413 | escape = C0::ESC; 414 | if (m_application_cursor_key_mode) 415 | control = C1_7bit::SS3; 416 | else 417 | control = C1_7bit::CSI; 418 | 419 | code = 'A'; 420 | break; 421 | case Qt::Key_Right: 422 | escape = C0::ESC; 423 | if (m_application_cursor_key_mode) 424 | control = C1_7bit::SS3; 425 | else 426 | control = C1_7bit::CSI; 427 | 428 | code = 'C'; 429 | break; 430 | case Qt::Key_Down: 431 | escape = C0::ESC; 432 | if (m_application_cursor_key_mode) 433 | control = C1_7bit::SS3; 434 | else 435 | control = C1_7bit::CSI; 436 | 437 | code = 'B'; 438 | break; 439 | case Qt::Key_Left: 440 | escape = C0::ESC; 441 | if (m_application_cursor_key_mode) 442 | control = C1_7bit::SS3; 443 | else 444 | control = C1_7bit::CSI; 445 | 446 | code = 'D'; 447 | break; 448 | case Qt::Key_Insert: 449 | escape = C0::ESC; 450 | control = C1_7bit::CSI; 451 | parameters.append(2); 452 | code = '~'; 453 | break; 454 | case Qt::Key_Delete: 455 | escape = C0::ESC; 456 | control = C1_7bit::CSI; 457 | parameters.append(3); 458 | code = '~'; 459 | break; 460 | case Qt::Key_Home: 461 | escape = C0::ESC; 462 | control = C1_7bit::CSI; 463 | parameters.append(1); 464 | code = '~'; 465 | break; 466 | case Qt::Key_End: 467 | escape = C0::ESC; 468 | control = C1_7bit::CSI; 469 | parameters.append(4); 470 | code = '~'; 471 | break; 472 | case Qt::Key_PageUp: 473 | escape = C0::ESC; 474 | control = C1_7bit::CSI; 475 | parameters.append(5); 476 | code = '~'; 477 | break; 478 | case Qt::Key_PageDown: 479 | escape = C0::ESC; 480 | control = C1_7bit::CSI; 481 | parameters.append(6); 482 | code = '~'; 483 | break; 484 | case Qt::Key_F1: 485 | case Qt::Key_F2: 486 | case Qt::Key_F3: 487 | case Qt::Key_F4: 488 | if (m_application_cursor_key_mode) { 489 | parameters.append((key & 0xff) - 37); 490 | escape = C0::ESC; 491 | control = C1_7bit::CSI; 492 | code = '~'; 493 | } 494 | break; 495 | case Qt::Key_F5: 496 | case Qt::Key_F6: 497 | case Qt::Key_F7: 498 | case Qt::Key_F8: 499 | case Qt::Key_F9: 500 | case Qt::Key_F10: 501 | case Qt::Key_F11: 502 | case Qt::Key_F12: 503 | if (m_application_cursor_key_mode) { 504 | parameters.append((key & 0xff) - 36); 505 | escape = C0::ESC; 506 | control = C1_7bit::CSI; 507 | code = '~'; 508 | } 509 | break; 510 | case Qt::Key_Control: 511 | case Qt::Key_Shift: 512 | case Qt::Key_Alt: 513 | case Qt::Key_AltGr: 514 | return; 515 | break; 516 | default: 517 | found = false; 518 | } 519 | 520 | if (found) { 521 | int term_mods = 0; 522 | if (modifiers & Qt::ShiftModifier) 523 | term_mods |= 1; 524 | if (modifiers & Qt::AltModifier) 525 | term_mods |= 2; 526 | if (modifiers & Qt::ControlModifier) 527 | term_mods |= 4; 528 | 529 | QByteArray toPty; 530 | 531 | if (term_mods) { 532 | term_mods++; 533 | parameters.append(term_mods); 534 | } 535 | if (escape) 536 | toPty.append(escape); 537 | if (control) 538 | toPty.append(control); 539 | if (parameters.size()) { 540 | for (int i = 0; i < parameters.size(); i++) { 541 | if (i) 542 | toPty.append(';'); 543 | toPty.append(QByteArray::number(parameters.at(i))); 544 | } 545 | } 546 | if (code) 547 | toPty.append(code); 548 | m_pty.write(toPty); 549 | 550 | } else { 551 | QString verifiedText = text.simplified(); 552 | if (verifiedText.isEmpty()) { 553 | switch (key) { 554 | case Qt::Key_Return: 555 | case Qt::Key_Enter: 556 | verifiedText = "\r"; 557 | break; 558 | case Qt::Key_Backspace: 559 | verifiedText = "\010"; 560 | break; 561 | case Qt::Key_Tab: 562 | verifiedText = "\t"; 563 | break; 564 | case Qt::Key_Control: 565 | case Qt::Key_Meta: 566 | case Qt::Key_Alt: 567 | case Qt::Key_Shift: 568 | return; 569 | case Qt::Key_Space: 570 | verifiedText = " "; 571 | break; 572 | default: 573 | return; 574 | } 575 | } 576 | QByteArray to_pty; 577 | QByteArray key_text; 578 | if (hasControll(modifiers)) { 579 | char key_char = verifiedText.toLocal8Bit().at(0); 580 | key_text.append(key_char & 0x1F); 581 | } else { 582 | key_text = verifiedText.toUtf8(); 583 | } 584 | 585 | if (modifiers & Qt::AltModifier) { 586 | to_pty.append(C0::ESC); 587 | } 588 | 589 | if (hasMeta(modifiers)) { 590 | to_pty.append(C0::ESC); 591 | to_pty.append('@'); 592 | to_pty.append(FinalBytesNoIntermediate::Reserved3); 593 | } 594 | 595 | to_pty.append(key_text); 596 | m_pty.write(to_pty); 597 | } 598 | } 599 | 600 | YatPty *Screen::pty() 601 | { 602 | return &m_pty; 603 | } 604 | 605 | Text *Screen::createTextSegment(const TextStyleLine &style_line) 606 | { 607 | Q_UNUSED(style_line); 608 | Text *to_return; 609 | if (m_to_delete.size()) { 610 | to_return = m_to_delete.takeLast(); 611 | to_return->setVisible(true); 612 | } else { 613 | to_return = new Text(this); 614 | emit textCreated(to_return); 615 | } 616 | 617 | return to_return; 618 | } 619 | 620 | void Screen::releaseTextSegment(Text *text) 621 | { 622 | m_to_delete.append(text); 623 | } 624 | 625 | void Screen::readData(const QByteArray &data) 626 | { 627 | m_parser.addData(data); 628 | 629 | scheduleEventDispatch(); 630 | } 631 | 632 | void Screen::paletteChanged() 633 | { 634 | QColor new_default = m_palette->normalColor(ColorPalette::DefaultBackground); 635 | if (new_default != m_default_background) { 636 | m_default_background = new_default; 637 | emit defaultBackgroundColorChanged(); 638 | } 639 | } 640 | 641 | void Screen::timerEvent(QTimerEvent *) 642 | { 643 | if (m_timer_event_id && (m_time_since_parsed.elapsed() > 3 || m_time_since_initiated.elapsed() > 25)) { 644 | killTimer(m_timer_event_id); 645 | m_timer_event_id = 0; 646 | dispatchChanges(); 647 | } 648 | } 649 | -------------------------------------------------------------------------------- /backend/screen.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #ifndef TERMINALSCREEN_H 25 | #define TERMINALSCREEN_H 26 | 27 | #include 28 | 29 | #include "color_palette.h" 30 | #include "parser.h" 31 | #include "yat_pty.h" 32 | #include "text_style.h" 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | class Block; 40 | class Cursor; 41 | class Text; 42 | class ScreenData; 43 | class Selection; 44 | 45 | class Screen : public QObject 46 | { 47 | Q_OBJECT 48 | 49 | Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged) 50 | Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged) 51 | Q_PROPERTY(int contentHeight READ contentHeight NOTIFY contentHeightChanged) 52 | Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY screenTitleChanged) 53 | Q_PROPERTY(Selection *selection READ selection CONSTANT) 54 | Q_PROPERTY(QColor defaultBackgroundColor READ defaultBackgroundColor NOTIFY defaultBackgroundColorChanged) 55 | Q_PROPERTY(QString platformName READ platformName CONSTANT) 56 | 57 | public: 58 | explicit Screen(QObject *parent = 0); 59 | ~Screen(); 60 | 61 | void emitRequestHeight(int newHeight); 62 | void setHeight(int height); 63 | int height() const; 64 | int contentHeight() const; 65 | 66 | void emitRequestWidth(int newWidth); 67 | void setWidth(int width); 68 | int width() const; 69 | 70 | ScreenData *currentScreenData() const { return m_current_data; } 71 | void useAlternateScreenBuffer(); 72 | void useNormalScreenBuffer(); 73 | 74 | Cursor *currentCursor() const { return m_cursor_stack.last(); } 75 | void saveCursor(); 76 | void restoreCursor(); 77 | 78 | TextStyle defaultTextStyle() const; 79 | 80 | QColor defaultForegroundColor() const; 81 | QColor defaultBackgroundColor() const; 82 | 83 | ColorPalette *colorPalette() const; 84 | 85 | void clearScreen(); 86 | 87 | void fill(const QChar character); 88 | void clear(); 89 | 90 | void setFastScroll(bool fast); 91 | bool fastScroll() const; 92 | 93 | Selection *selection() const; 94 | Q_INVOKABLE void doubleClicked(double character, double line); 95 | 96 | void setTitle(const QString &title); 97 | QString title() const; 98 | 99 | QString platformName() const; 100 | 101 | void scheduleFlash(); 102 | 103 | Q_INVOKABLE void printScreen() const; 104 | 105 | void scheduleEventDispatch(); 106 | void dispatchChanges(); 107 | 108 | void sendPrimaryDA(); 109 | void sendSecondaryDA(); 110 | 111 | void setApplicationCursorKeysMode(bool enable); 112 | bool applicationCursorKeyMode() const; 113 | 114 | Q_INVOKABLE void sendKey(const QString &text, Qt::Key key, Qt::KeyboardModifiers modifiers); 115 | 116 | YatPty *pty(); 117 | 118 | Q_INVOKABLE void ensureVisiblePages(int top_line); 119 | Text *createTextSegment(const TextStyleLine &style_line); 120 | void releaseTextSegment(Text *text); 121 | 122 | public slots: 123 | void readData(const QByteArray &data); 124 | void paletteChanged(); 125 | signals: 126 | void reset(); 127 | 128 | void flash(); 129 | 130 | void dispatchLineChanges(); 131 | void dispatchTextSegmentChanges(); 132 | 133 | void screenTitleChanged(); 134 | 135 | void textCreated(Text *text); 136 | void cursorCreated(Cursor *cursor); 137 | 138 | void requestHeightChange(int newHeight); 139 | void heightChanged(); 140 | void contentHeightChanged(); 141 | 142 | void requestWidthChange(int newWidth); 143 | void widthChanged(); 144 | 145 | void defaultBackgroundColorChanged(); 146 | 147 | void contentModified(size_t lineModified, int lineDiff, int contentDiff); 148 | void dataHeightChanged(int newHeight, int removedBeginning, int reclaimed); 149 | void widthAboutToChange(int width); 150 | void dataWidthChanged(int newWidth, int removedBeginning, int reclaimed); 151 | 152 | void hangup(); 153 | protected: 154 | void timerEvent(QTimerEvent *); 155 | 156 | private: 157 | ColorPalette *m_palette; 158 | YatPty m_pty; 159 | Parser m_parser; 160 | QElapsedTimer m_time_since_parsed; 161 | QElapsedTimer m_time_since_initiated; 162 | 163 | int m_timer_event_id; 164 | int m_width; 165 | int m_height; 166 | 167 | ScreenData *m_primary_data; 168 | ScreenData *m_alternate_data; 169 | ScreenData *m_current_data; 170 | ScreenData *m_old_current_data; 171 | 172 | QVector m_cursor_stack; 173 | QVector m_new_cursors; 174 | QVector m_delete_cursors; 175 | 176 | QString m_title; 177 | 178 | Selection *m_selection; 179 | 180 | bool m_flash; 181 | bool m_cursor_changed; 182 | bool m_application_cursor_key_mode; 183 | bool m_fast_scroll; 184 | 185 | QVector m_to_delete; 186 | 187 | QColor m_default_background; 188 | 189 | friend class ScreenData; 190 | }; 191 | 192 | #endif // TERMINALSCREEN_H 193 | -------------------------------------------------------------------------------- /backend/screen_data.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #include "screen_data.h" 25 | 26 | #include "block.h" 27 | #include "screen.h" 28 | #include "scrollback.h" 29 | #include "cursor.h" 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | ScreenData::ScreenData(size_t max_scrollback, Screen *screen) 37 | : QObject(screen) 38 | , m_screen(screen) 39 | , m_scrollback(new Scrollback(max_scrollback, this)) 40 | , m_screen_height(0) 41 | , m_height(0) 42 | , m_width(0) 43 | , m_block_count(0) 44 | , m_old_total_lines(0) 45 | { 46 | } 47 | 48 | ScreenData::~ScreenData() 49 | { 50 | for (auto it = m_screen_blocks.begin(); it != m_screen_blocks.end(); ++it) { 51 | delete *it; 52 | } 53 | delete m_scrollback; 54 | } 55 | 56 | 57 | int ScreenData::contentHeight() const 58 | { 59 | return m_height + m_scrollback->height(); 60 | } 61 | 62 | void ScreenData::setHeight(int height, int currentCursorLine) 63 | { 64 | if (m_screen_height == height) 65 | return; 66 | 67 | m_screen_height = height; 68 | 69 | int removed_beginning = 0; 70 | int removed_end = 0; 71 | int reclaimed = 0; 72 | 73 | if (m_height > height) { 74 | const int to_remove = m_height - height; 75 | const int remove_from_end = std::min(m_height - (currentCursorLine + 1), to_remove); 76 | const int remove_from_start = to_remove - remove_from_end; 77 | 78 | if (remove_from_end) { 79 | removed_end = remove_lines_from_end(remove_from_end); 80 | } 81 | if (remove_from_start) { 82 | removed_beginning = push_at_most_to_scrollback(remove_from_start); 83 | } 84 | } else { 85 | reclaimed = ensure_at_least_height(height); 86 | } 87 | 88 | emit dataHeightChanged(m_screen_height, removed_beginning, reclaimed); 89 | } 90 | 91 | void ScreenData::setWidth(int width) 92 | { 93 | m_width = width; 94 | 95 | for (Block *block : m_screen_blocks) { 96 | int before_count = block->lineCount(); 97 | block->setWidth(width); 98 | m_height += block->lineCount() - before_count; 99 | } 100 | 101 | int removed = 0; 102 | int reclaimed = 0; 103 | if (m_height > m_screen_height) { 104 | removed = push_at_most_to_scrollback(m_height - m_screen_height); 105 | } else { 106 | reclaimed = ensure_at_least_height(m_screen_height); 107 | } 108 | 109 | m_scrollback->setWidth(width); 110 | 111 | emit dataWidthChanged(m_width, removed, reclaimed); 112 | } 113 | 114 | 115 | void ScreenData::clearToEndOfLine(const QPoint &point) 116 | { 117 | auto it = it_for_row_ensure_single_line_block(point.y()); 118 | (*it)->clearToEnd(point.x()); 119 | } 120 | 121 | void ScreenData::clearToEndOfScreen(int y) 122 | { 123 | auto it = it_for_row_ensure_single_line_block(y); 124 | while(it != m_screen_blocks.end()) { 125 | clearBlock(it); 126 | ++it; 127 | } 128 | } 129 | 130 | void ScreenData::clearToBeginningOfLine(const QPoint &point) 131 | { 132 | auto it = it_for_row_ensure_single_line_block(point.y()); 133 | (*it)->clearCharacters(0,point.x()); 134 | } 135 | 136 | void ScreenData::clearToBeginningOfScreen(int y) 137 | { 138 | auto it = it_for_row_ensure_single_line_block(y); 139 | if (it != m_screen_blocks.end()) 140 | (*it)->clear(); 141 | while(it != m_screen_blocks.begin()) { 142 | --it; 143 | clearBlock(it); 144 | } 145 | } 146 | 147 | void ScreenData::clearLine(const QPoint &point) 148 | { 149 | (*it_for_row_ensure_single_line_block(point.y()))->clear(); 150 | } 151 | 152 | void ScreenData::clear() 153 | { 154 | for (auto it = m_screen_blocks.begin(); it != m_screen_blocks.end(); ++it) { 155 | clearBlock(it); 156 | } 157 | } 158 | 159 | void ScreenData::releaseTextObjects() 160 | { 161 | for (auto it = m_screen_blocks.begin(); it != m_screen_blocks.end(); ++it) { 162 | (*it)->releaseTextObjects(); 163 | } 164 | } 165 | 166 | void ScreenData::clearCharacters(const QPoint &point, int to) 167 | { 168 | auto it = it_for_row_ensure_single_line_block(point.y()); 169 | (*it)->clearCharacters(point.x(),to); 170 | } 171 | 172 | void ScreenData::deleteCharacters(const QPoint &point, int to) 173 | { 174 | auto it = it_for_row(point.y()); 175 | if (it == m_screen_blocks.end()) 176 | return; 177 | 178 | int line_in_block = point.y() - (*it)->screenIndex(); 179 | int chars_to_line = line_in_block * m_width; 180 | 181 | (*it)->deleteCharacters(chars_to_line + point.x(), chars_to_line + to); 182 | } 183 | 184 | const CursorDiff ScreenData::replace(const QPoint &point, const QString &text, const TextStyle &style, bool only_latin) 185 | { 186 | return modify(point,text,style,true, only_latin); 187 | } 188 | 189 | const CursorDiff ScreenData::insert(const QPoint &point, const QString &text, const TextStyle &style, bool only_latin) 190 | { 191 | return modify(point,text,style,false, only_latin); 192 | } 193 | 194 | 195 | void ScreenData::moveLine(int from, int to) 196 | { 197 | if (from == to) 198 | return; 199 | 200 | const size_t old_content_height = contentHeight(); 201 | if (to > from) 202 | to++; 203 | auto from_it = it_for_row_ensure_single_line_block(from); 204 | auto to_it = it_for_row_ensure_single_line_block(to); 205 | 206 | (*from_it)->clear(); 207 | m_screen_blocks.splice(to_it, m_screen_blocks, from_it); 208 | emit contentModified(m_scrollback->height() + to, 1, content_height_diff(old_content_height)); 209 | } 210 | 211 | void ScreenData::insertLine(int row, int topMargin) 212 | { 213 | auto row_it = it_for_row(row + 1); 214 | 215 | const size_t old_content_height = contentHeight(); 216 | 217 | if (!topMargin && m_height >= m_screen_height) { 218 | push_at_most_to_scrollback(1); 219 | } else { 220 | auto row_top_margin = it_for_row_ensure_single_line_block(topMargin); 221 | if (row == topMargin) { 222 | (*row_top_margin)->clear(); 223 | return; 224 | } 225 | delete (*row_top_margin); 226 | m_screen_blocks.erase(row_top_margin); 227 | m_height--; 228 | m_block_count--; 229 | } 230 | 231 | Block *block_to_insert = new Block(m_screen); 232 | m_screen_blocks.insert(row_it,block_to_insert); 233 | m_height++; 234 | m_block_count++; 235 | 236 | emit contentModified(m_scrollback->height() + row + 1, 1, content_height_diff(old_content_height)); 237 | } 238 | 239 | 240 | void ScreenData::fill(const QChar &character) 241 | { 242 | clear(); 243 | auto it = --m_screen_blocks.end(); 244 | for (int i = 0; i < m_block_count; --it, i++) { 245 | QString fill_str(m_screen->width(), character); 246 | (*it)->replaceAtPos(0, fill_str, m_screen->defaultTextStyle()); 247 | } 248 | } 249 | 250 | void ScreenData::dispatchLineEvents() 251 | { 252 | if (!m_block_count) 253 | return; 254 | const int scrollback_height = m_scrollback->height(); 255 | int i = 0; 256 | for (auto it = m_screen_blocks.begin(); it != m_screen_blocks.end(); ++it) { 257 | int line = scrollback_height + i; 258 | (*it)->setLine(line); 259 | //(*it)->setScreenIndex(i); 260 | (*it)->dispatchEvents(); 261 | i+= (*it)->lineCount(); 262 | } 263 | 264 | if (contentHeight() != m_old_total_lines) { 265 | m_old_total_lines = contentHeight(); 266 | emit contentHeightChanged(); 267 | } 268 | } 269 | 270 | void ScreenData::printRuler(QDebug &debug) const 271 | { 272 | QString ruler = QString("|----i----").repeated((m_width/10)+1).append("|"); 273 | debug << " " << (void *) this << ruler; 274 | } 275 | 276 | void ScreenData::printStyleInformation() const 277 | { 278 | auto it = m_screen_blocks.end(); 279 | std::advance(it, -m_block_count); 280 | for (int i = 0; it != m_screen_blocks.end(); ++it, i++) { 281 | if (i % 5 == 0) { 282 | QDebug debug = qDebug(); 283 | debug << "Ruler:"; 284 | printRuler(debug); 285 | } 286 | QDebug debug = qDebug(); 287 | (*it)->printStyleList(debug); 288 | } 289 | qDebug() << "On screen height" << m_height; 290 | } 291 | 292 | Screen *ScreenData::screen() const 293 | { 294 | return m_screen; 295 | } 296 | 297 | void ScreenData::ensureVisiblePages(int top_line) 298 | { 299 | m_scrollback->ensureVisiblePages(top_line); 300 | } 301 | 302 | Scrollback *ScreenData::scrollback() const 303 | { 304 | return m_scrollback; 305 | } 306 | 307 | void ScreenData::sendSelectionToClipboard(const QPoint &start, const QPoint &end, QClipboard::Mode mode) 308 | { 309 | if (start.y() < 0) 310 | return; 311 | if (end.y() >= contentHeight()) 312 | return; 313 | 314 | QString to_clip_board_buffer; 315 | 316 | bool started_in_scrollback = false; 317 | if (size_t(start.y()) < m_scrollback->height()) { 318 | started_in_scrollback = true; 319 | QPoint end_scrollback = end; 320 | if (size_t(end.y()) >= m_scrollback->height()) { 321 | end_scrollback = QPoint(m_width, m_scrollback->height() - 1); 322 | } 323 | to_clip_board_buffer = m_scrollback->selection(start, end_scrollback); 324 | } 325 | 326 | if (size_t(end.y()) >= m_scrollback->height()) { 327 | QPoint start_in_screen; 328 | if (started_in_scrollback) { 329 | start_in_screen = QPoint(0,0); 330 | } else { 331 | start_in_screen = start; 332 | start_in_screen.ry() -= m_scrollback->height(); 333 | } 334 | QPoint end_in_screen = end; 335 | end_in_screen.ry() -= m_scrollback->height(); 336 | 337 | auto it = it_for_row(start_in_screen.y()); 338 | size_t screen_index = (*it)->screenIndex(); 339 | int start_pos = (start_in_screen.y() - (*it)->screenIndex()) * m_width + start_in_screen.x(); 340 | for (; it != m_screen_blocks.end(); ++it, start_pos = 0) { 341 | int end_pos = (*it)->textSize(); 342 | bool should_break = false; 343 | if (size_t(screen_index + (*it)->lineCount()) > size_t(end_in_screen.y())) { 344 | end_pos = (end_in_screen.y() - screen_index) * m_width + end_in_screen.x(); 345 | should_break = true; 346 | } 347 | if (to_clip_board_buffer.size()) 348 | to_clip_board_buffer += '\n'; 349 | to_clip_board_buffer += (*it)->textLine().mid(start_pos, end_pos - start_pos); 350 | if (should_break) 351 | break; 352 | screen_index += (*it)->lineCount(); 353 | } 354 | } 355 | QGuiApplication::clipboard()->setText(to_clip_board_buffer, mode); 356 | } 357 | 358 | const SelectionRange ScreenData::getDoubleClickSelectionRange(size_t character, size_t line) 359 | { 360 | if (line < m_scrollback->height()) 361 | return m_scrollback->getDoubleClickSelectionRange(character, line); 362 | size_t screen_line = line - m_scrollback->height(); 363 | auto it = it_for_row(screen_line); 364 | if (it != m_screen_blocks.end()) 365 | return Selection::getDoubleClickRange(it, character, line, m_width); 366 | return { QPoint(), QPoint() }; 367 | } 368 | 369 | const CursorDiff ScreenData::modify(const QPoint &point, const QString &text, const TextStyle &style, bool replace, bool only_latin) 370 | { 371 | auto it = it_for_row(point.y()); 372 | if (it == m_screen_blocks.end()) 373 | return { 0, 0 }; 374 | Block *block = *it; 375 | const int start_char = (point.y() - block->screenIndex()) * m_width + point.x(); 376 | const size_t lines_before = block->lineCount(); 377 | const int lines_changed = 378 | block->lineCountAfterModified(start_char, text.size(), replace) - lines_before; 379 | const size_t old_content_height = contentHeight(); 380 | m_height += lines_changed; 381 | if (lines_changed > 0) { 382 | int removed = 0; 383 | auto to_merge_inn = it; 384 | ++to_merge_inn; 385 | while(removed < lines_changed && to_merge_inn != m_screen_blocks.end()) { 386 | Block *to_be_reduced = *to_merge_inn; 387 | bool remove_block = removed + to_be_reduced->lineCount() <= lines_changed; 388 | int lines_to_remove = remove_block ? to_be_reduced->lineCount() : to_be_reduced->lineCount() - (lines_changed - removed); 389 | block->moveLinesFromBlock(to_be_reduced, 0, lines_to_remove); 390 | removed += lines_to_remove; 391 | if (remove_block) { 392 | delete to_be_reduced; 393 | to_merge_inn = m_screen_blocks.erase(to_merge_inn); 394 | m_block_count--; 395 | } else { 396 | ++to_merge_inn; 397 | } 398 | } 399 | 400 | m_height -= removed; 401 | } 402 | 403 | if (m_height > m_screen_height) 404 | push_at_most_to_scrollback(m_height - m_screen_height); 405 | 406 | if (replace) { 407 | block->replaceAtPos(start_char, text, style, only_latin); 408 | } else { 409 | block->insertAtPos(start_char, text, style, only_latin); 410 | } 411 | int end_char = (start_char + text.size()) % m_width; 412 | if (end_char == 0) 413 | end_char = m_width -1; 414 | 415 | int end_line = (start_char + text.size()) / m_width; 416 | int line_diff = end_line - (start_char / m_width); 417 | emit contentModified(m_scrollback->height() + point.y(), lines_changed, content_height_diff(old_content_height)); 418 | return { line_diff, end_char - point.x()}; 419 | } 420 | 421 | void ScreenData::clearBlock(std::list::iterator line) 422 | { 423 | int before_count = (*line)->lineCount(); 424 | (*line)->clear(); 425 | int diff_line = before_count - (*line)->lineCount(); 426 | if (diff_line > 0) { 427 | ++line; 428 | for (int i = 0; i < diff_line; i++) { 429 | m_screen_blocks.insert(line, new Block(m_screen)); 430 | } 431 | m_block_count+=diff_line; 432 | } 433 | } 434 | 435 | std::list::iterator ScreenData::it_for_row_ensure_single_line_block(int row) 436 | { 437 | auto it = it_for_row(row); 438 | const int index = (*it)->screenIndex(); 439 | const int lines = (*it)->lineCount(); 440 | 441 | if (index == row && lines == 1) { 442 | return it; 443 | } 444 | 445 | int line_diff = row - index; 446 | return split_out_row_from_block(it, line_diff); 447 | } 448 | 449 | std::list::iterator ScreenData::split_out_row_from_block(std::list::iterator it, int row_in_block) 450 | { 451 | int lines = (*it)->lineCount(); 452 | 453 | if (row_in_block == 0 && lines == 1) 454 | return it; 455 | 456 | if (row_in_block == 0) { 457 | auto insert_before = (*it)->takeLine(0); 458 | insert_before->setScreenIndex(row_in_block); 459 | m_block_count++; 460 | return m_screen_blocks.insert(it,insert_before); 461 | } else if (row_in_block == lines -1) { 462 | auto insert_after = (*it)->takeLine(lines -1); 463 | insert_after->setScreenIndex(row_in_block); 464 | ++it; 465 | m_block_count++; 466 | return m_screen_blocks.insert(it, insert_after); 467 | } 468 | 469 | auto half = (*it)->split(row_in_block); 470 | ++it; 471 | auto it_width_first = m_screen_blocks.insert(it, half); 472 | auto the_one = half->takeLine(0); 473 | m_block_count+=2; 474 | return m_screen_blocks.insert(it_width_first,the_one); 475 | } 476 | 477 | int ScreenData::push_at_most_to_scrollback(int lines) 478 | { 479 | if (lines >= m_height) 480 | lines = m_height - 1; 481 | int pushed = 0; 482 | auto it = m_screen_blocks.begin(); 483 | while (it != m_screen_blocks.end() && pushed + (*it)->lineCount() <= lines) { 484 | m_block_count--; 485 | const int block_height = (*it)->lineCount(); 486 | m_height -= block_height; 487 | pushed += block_height; 488 | m_scrollback->addBlock(*it); 489 | it = m_screen_blocks.erase(it); 490 | } 491 | return pushed; 492 | } 493 | 494 | int ScreenData::reclaim_at_least(int lines) 495 | { 496 | int lines_reclaimed = 0; 497 | while (m_scrollback->blockCount() && lines_reclaimed < lines) { 498 | Block *block = m_scrollback->reclaimBlock(); 499 | m_height += block->lineCount(); 500 | lines_reclaimed += block->lineCount(); 501 | m_block_count++; 502 | m_screen_blocks.push_front(block); 503 | } 504 | return lines_reclaimed; 505 | } 506 | 507 | int ScreenData::remove_lines_from_end(int lines) 508 | { 509 | int removed = 0; 510 | auto it = m_screen_blocks.end(); 511 | while (it != m_screen_blocks.begin() && removed < lines) { 512 | --it; 513 | const int block_height = (*it)->lineCount(); 514 | if (removed + block_height <= lines) { 515 | removed += block_height; 516 | m_height -= block_height; 517 | m_block_count--; 518 | delete (*it); 519 | it = m_screen_blocks.erase(it); 520 | } else { 521 | const int to_remove = lines - removed; 522 | removed += to_remove; 523 | m_height -= to_remove; 524 | Block *block = *it; 525 | for (int i = 0; i < to_remove; i++) { 526 | block->removeLine(block->lineCount()-1); 527 | } 528 | } 529 | } 530 | return removed; 531 | } 532 | 533 | int ScreenData::ensure_at_least_height(int height) 534 | { 535 | if (m_height > height) 536 | return 0; 537 | 538 | int to_grow = height - m_height; 539 | int reclaimed = reclaim_at_least(to_grow); 540 | 541 | if (height > m_height) { 542 | int to_insert = height - m_height; 543 | for (int i = 0; i < to_insert; i++) { 544 | m_screen_blocks.push_back(new Block(m_screen)); 545 | } 546 | m_height += to_insert; 547 | m_block_count += to_insert; 548 | } 549 | return reclaimed; 550 | } 551 | 552 | int ScreenData::content_height_diff(size_t old_content_height) 553 | { 554 | const size_t content_height = contentHeight(); 555 | return old_content_height < content_height ? content_height - old_content_height : 556 | - int(old_content_height - content_height); 557 | } 558 | -------------------------------------------------------------------------------- /backend/screen_data.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #ifndef SCREENDATA_H 25 | #define SCREENDATA_H 26 | 27 | #include "text_style.h" 28 | #include "block.h" 29 | #include "selection.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | class Screen; 38 | class Scrollback; 39 | 40 | class CursorDiff 41 | { 42 | public: 43 | int line; 44 | int character; 45 | }; 46 | 47 | class ScreenData : public QObject 48 | { 49 | Q_OBJECT 50 | public: 51 | ScreenData(size_t max_scrollback, Screen *screen); 52 | ~ScreenData(); 53 | 54 | int contentHeight() const; 55 | 56 | void clearToEndOfLine(const QPoint &pos); 57 | void clearToEndOfScreen(int y); 58 | void clearToBeginningOfLine(const QPoint &pos); 59 | void clearToBeginningOfScreen(int y); 60 | void clearLine(const QPoint &pos); 61 | void clear(); 62 | void releaseTextObjects(); 63 | 64 | void clearCharacters(const QPoint &pos, int to); 65 | void deleteCharacters(const QPoint &pos, int to); 66 | 67 | const CursorDiff replace(const QPoint &pos, const QString &text, const TextStyle &style, bool only_latin); 68 | const CursorDiff insert(const QPoint &pos, const QString &text, const TextStyle &style, bool only_latin); 69 | 70 | void moveLine(int from, int to); 71 | void insertLine(int insertAt, int topMargin); 72 | 73 | void fill(const QChar &character); 74 | 75 | void dispatchLineEvents(); 76 | 77 | void printRuler(QDebug &debug) const; 78 | void printStyleInformation() const; 79 | 80 | Screen *screen() const; 81 | 82 | void ensureVisiblePages(int top_line); 83 | 84 | Scrollback *scrollback() const; 85 | 86 | void sendSelectionToClipboard(const QPoint &start, const QPoint &end, QClipboard::Mode mode); 87 | 88 | inline std::list::iterator it_for_row(int row); 89 | inline std::list::iterator it_for_block(Block *block); 90 | bool it_is_end(std::list::iterator it) const { return m_screen_blocks.end() == it; } 91 | 92 | const SelectionRange getDoubleClickSelectionRange(size_t character, size_t line); 93 | public slots: 94 | void setHeight(int height, int currentCursorLine); 95 | void setWidth(int width); 96 | 97 | signals: 98 | void contentHeightChanged(); 99 | void contentModified(size_t lineModified, int lineDiff, int contentDiff); 100 | void dataHeightChanged(int newHeight, int removedBeginning, int reclaimed); 101 | void dataWidthChanged(int newHeight, int removedBeginning, int reclaimed); 102 | 103 | private: 104 | const CursorDiff modify(const QPoint &pos, const QString &text, const TextStyle &style, bool replace, bool only_latin); 105 | void clearBlock(std::list::iterator line); 106 | std::list::iterator it_for_row_ensure_single_line_block(int row); 107 | std::list::iterator split_out_row_from_block(std::list::iterator block_it, int row_in_block); 108 | int push_at_most_to_scrollback(int lines); 109 | int reclaim_at_least(int lines); 110 | int remove_lines_from_end(int lines); 111 | int ensure_at_least_height(int height); 112 | int content_height_diff(size_t old_content_height); 113 | Screen *m_screen; 114 | Scrollback *m_scrollback; 115 | int m_screen_height; 116 | int m_height; 117 | int m_width; 118 | int m_block_count; 119 | int m_old_total_lines; 120 | 121 | std::list m_screen_blocks; 122 | }; 123 | 124 | std::list::iterator ScreenData::it_for_row(int row) 125 | { 126 | if (row >= m_screen_height) { 127 | return m_screen_blocks.end(); 128 | } 129 | auto it = m_screen_blocks.end(); 130 | int line_for_block = m_screen_height; 131 | size_t abs_line = contentHeight(); 132 | while (it != m_screen_blocks.begin()) { 133 | --it; 134 | line_for_block -= (*it)->lineCount(); 135 | abs_line -= (*it)->lineCount(); 136 | if (line_for_block <= row) { 137 | (*it)->setScreenIndex(line_for_block); 138 | (*it)->setLine(abs_line); 139 | return it; 140 | } 141 | } 142 | 143 | return m_screen_blocks.end(); 144 | } 145 | inline std::list::iterator ScreenData::it_for_block(Block *block) 146 | { 147 | if (!block) 148 | return m_screen_blocks.end(); 149 | auto it = m_screen_blocks.end(); 150 | int line_for_block = m_screen_height; 151 | size_t abs_line = contentHeight(); 152 | while(it != m_screen_blocks.begin()) { 153 | --it; 154 | line_for_block -= (*it)->lineCount(); 155 | abs_line -= (*it)->lineCount(); 156 | if (*it == block) { 157 | (*it)->setScreenIndex(line_for_block); 158 | (*it)->setLine(abs_line); 159 | return it; 160 | } 161 | } 162 | return m_screen_blocks.end(); 163 | } 164 | #endif // SCREENDATA_H 165 | -------------------------------------------------------------------------------- /backend/scrollback.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | ******************************************************************************/ 23 | 24 | #include "scrollback.h" 25 | 26 | #include "screen_data.h" 27 | #include "screen.h" 28 | #include "block.h" 29 | 30 | #include 31 | 32 | #define P_VAR(variable) \ 33 | #variable ":" << variable 34 | 35 | Scrollback::Scrollback(size_t max_size, ScreenData *screen_data) 36 | : m_screen_data(screen_data) 37 | , m_height(0) 38 | , m_width(0) 39 | , m_block_count(0) 40 | , m_max_size(max_size) 41 | , m_adjust_visible_pages(0) 42 | { 43 | } 44 | 45 | void Scrollback::addBlock(Block *block) 46 | { 47 | if (!m_max_size) { 48 | delete block; 49 | return; 50 | } 51 | 52 | m_blocks.push_back(block); 53 | block->releaseTextObjects(); 54 | m_block_count++; 55 | m_height += m_blocks.back()->lineCount(); 56 | 57 | while (m_blocks.front() != block && m_height - m_blocks.front()->lineCount() >= m_max_size) { 58 | m_block_count--; 59 | m_height -= std::min(m_blocks.front()->lineCount(), (int)m_height); 60 | delete m_blocks.front(); 61 | m_blocks.pop_front(); 62 | m_adjust_visible_pages++; 63 | } 64 | 65 | m_visible_pages.clear(); 66 | } 67 | 68 | Block *Scrollback::reclaimBlock() 69 | { 70 | if (m_blocks.empty()) 71 | return nullptr; 72 | 73 | Block *last = m_blocks.back(); 74 | last->setWidth(m_width); 75 | m_block_count--; 76 | m_height -= last->lineCount(); 77 | m_blocks.pop_back(); 78 | 79 | m_visible_pages.clear(); 80 | return last; 81 | } 82 | 83 | void Scrollback::ensureVisiblePages(int top_line) 84 | { 85 | if (top_line < 0) 86 | return; 87 | if (size_t(top_line) >= m_height) 88 | return; 89 | 90 | uint height = std::max(m_screen_data->screen()->height(), 1); 91 | 92 | int complete_pages = m_height / height; 93 | int remainder = m_height - (complete_pages * height); 94 | 95 | int top_page = top_line / height; 96 | int bottom_page = top_page + 1; 97 | 98 | std::set pages_to_update; 99 | pages_to_update.insert(top_page); 100 | if (bottom_page * height < m_height) 101 | pages_to_update.insert(bottom_page); 102 | 103 | for (auto it = m_visible_pages.begin(); it != m_visible_pages.end(); ++it) { 104 | Page &page = *it; 105 | if (pages_to_update.count(page.page_no) != 0) { 106 | if (page.page_no < complete_pages) { 107 | ensurePageVisible(page, height); 108 | } else if (page.page_no == complete_pages) { 109 | ensurePageVisible(page, remainder); 110 | } 111 | pages_to_update.erase(page.page_no); 112 | } else { 113 | ensurePageNotVisible(page); 114 | auto to_remove = it; 115 | --it; 116 | m_visible_pages.erase(to_remove); 117 | } 118 | } 119 | 120 | for (auto it = pages_to_update.begin(); it != pages_to_update.end(); ++it) { 121 | auto page_it = findIteratorForPage(*it); 122 | m_visible_pages.push_back( { *it, 0, page_it } ); 123 | if (*it < complete_pages) { 124 | ensurePageVisible(m_visible_pages.back(), height); 125 | } else if (*it == complete_pages) { 126 | ensurePageVisible(m_visible_pages.back(), remainder); 127 | } 128 | } 129 | } 130 | 131 | void Scrollback::ensurePageVisible(Page &page, int new_height) 132 | { 133 | if (page.size == new_height || !m_block_count) 134 | return; 135 | 136 | int line_no = page.page_no * m_screen_data->screen()->height(); 137 | auto it = page.it; 138 | std::advance(it, page.size); 139 | for (int i = page.size; i < new_height; ++it, i++) { 140 | (*it)->setLine(line_no + i); 141 | (*it)->dispatchEvents(); 142 | } 143 | page.size = new_height; 144 | } 145 | 146 | void Scrollback::ensurePageNotVisible(Page &page) 147 | { 148 | auto it = page.it; 149 | for (int i = 0; i < page.size; ++it, i++) { 150 | (*it)->releaseTextObjects(); 151 | } 152 | page.size = 0; 153 | } 154 | 155 | std::list::iterator Scrollback::findIteratorForPage(int page_no) 156 | { 157 | uint line = page_no * m_screen_data->screen()->height(); 158 | Q_ASSERT(line < m_height); 159 | for (auto it = m_visible_pages.begin(); it != m_visible_pages.end(); ++it) { 160 | Page &page = *it; 161 | int diff = page_no - page.page_no; 162 | if (diff < 5 && diff > 5) { 163 | auto to_return = page.it; 164 | int advance = diff * m_screen_data->screen()->height(); 165 | std::advance(to_return, advance); 166 | return to_return; 167 | } 168 | } 169 | 170 | if (line > m_height / 2) { 171 | auto to_return = m_blocks.end(); 172 | std::advance(to_return, line - m_height); 173 | return to_return; 174 | } 175 | 176 | auto to_return = m_blocks.begin(); 177 | std::advance(to_return, line); 178 | return to_return; 179 | } 180 | 181 | std::list::iterator Scrollback::findIteratorForLine(size_t line) 182 | { 183 | size_t current_line = m_height; 184 | auto it = m_blocks.end(); 185 | while (it != m_blocks.begin()) { 186 | --it; 187 | current_line -= (*it)->lineCount(); 188 | if (current_line <= line) 189 | return it; 190 | } 191 | return m_blocks.end(); 192 | } 193 | 194 | void Scrollback::adjustVisiblePages() 195 | { 196 | if (!m_adjust_visible_pages) 197 | return; 198 | 199 | for (auto it = m_visible_pages.begin(); it != m_visible_pages.end(); ++it) { 200 | Page &page = *it; 201 | const size_t line_for_page = page.page_no * m_screen_data->screen()->height(); 202 | if (line_for_page < m_adjust_visible_pages) { 203 | auto to_remove = it; 204 | --it; 205 | m_visible_pages.erase(to_remove); 206 | } else { 207 | page.size = 0; 208 | std::advance(page.it, m_adjust_visible_pages); 209 | } 210 | } 211 | 212 | m_adjust_visible_pages = 0; 213 | } 214 | 215 | size_t Scrollback::height() const 216 | { 217 | return m_height; 218 | } 219 | 220 | void Scrollback::setWidth(int width) 221 | { 222 | m_width = width; 223 | } 224 | 225 | QString Scrollback::selection(const QPoint &start, const QPoint &end) const 226 | { 227 | Q_ASSERT(start.y() >= 0); 228 | Q_ASSERT(end.y() >= 0); 229 | Q_ASSERT(size_t(end.y()) < m_height); 230 | QString return_string; 231 | 232 | size_t current_line = m_height; 233 | auto it = m_blocks.end(); 234 | 235 | bool should_continue = true; 236 | while (it != m_blocks.begin() && should_continue) { 237 | --it; 238 | const int block_height = (*it)->lineCount(); 239 | current_line -= block_height; 240 | if (current_line > size_t(end.y())) { 241 | continue; 242 | } 243 | 244 | int end_pos = (*it)->textSize(); 245 | if (current_line <= size_t(end.y()) && current_line + block_height >= size_t(end.y())) { 246 | size_t end_line_count = end.y() - current_line; 247 | end_pos = end_line_count * m_width + end.x(); 248 | } 249 | int start_pos = 0; 250 | if (current_line <= size_t(start.y()) && current_line + block_height >= size_t(start.y())) { 251 | size_t start_line_count = start.y() - current_line; 252 | start_pos = start_line_count * m_width + start.x(); 253 | should_continue = false; 254 | } else if (current_line + block_height < size_t(start.y())) { 255 | should_continue = false; 256 | } 257 | return_string.prepend((*it)->textLine().mid(start_pos, end_pos)); 258 | if (should_continue) 259 | return_string.prepend(QChar('\n')); 260 | } 261 | 262 | return return_string; 263 | } 264 | 265 | const SelectionRange Scrollback::getDoubleClickSelectionRange(size_t character, size_t line) 266 | { 267 | auto it = findIteratorForLine(line); 268 | if (it != m_blocks.end()) 269 | return Selection::getDoubleClickRange(it, character,line, m_width); 270 | return { QPoint(), QPoint() }; 271 | } 272 | -------------------------------------------------------------------------------- /backend/scrollback.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | ******************************************************************************/ 23 | 24 | #ifndef SCROLLBACK_H 25 | #define SCROLLBACK_H 26 | 27 | #include "selection.h" 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | class ScreenData; 34 | class Block; 35 | 36 | struct Page { 37 | int page_no; 38 | int size; 39 | std::list::iterator it; 40 | }; 41 | 42 | class Scrollback 43 | { 44 | public: 45 | Scrollback(size_t max_size, ScreenData *screen_data); 46 | 47 | void addBlock(Block *block); 48 | Block *reclaimBlock(); 49 | void ensureVisiblePages(int top_line); 50 | 51 | size_t height() const; 52 | 53 | void setWidth(int width); 54 | 55 | size_t blockCount() { return m_block_count; } 56 | 57 | QString selection(const QPoint &start, const QPoint &end) const; 58 | const SelectionRange getDoubleClickSelectionRange(size_t character, size_t line); 59 | private: 60 | void ensurePageVisible(Page &page, int new_height); 61 | void ensurePageNotVisible(Page &page); 62 | std::list::iterator findIteratorForPage(int page_no); 63 | std::list::iterator findIteratorForLine(size_t line); 64 | void adjustVisiblePages(); 65 | ScreenData *m_screen_data; 66 | 67 | std::list m_blocks; 68 | std::list m_visible_pages; 69 | size_t m_height; 70 | size_t m_width; 71 | size_t m_block_count; 72 | size_t m_max_size; 73 | size_t m_adjust_visible_pages; 74 | }; 75 | 76 | #endif //SCROLLBACK_H 77 | -------------------------------------------------------------------------------- /backend/selection.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #include "selection.h" 25 | 26 | #include "screen.h" 27 | #include "screen_data.h" 28 | #include "block.h" 29 | 30 | #include 31 | 32 | Selection::Selection(Screen *screen) 33 | : QObject(screen) 34 | , m_screen(screen) 35 | , m_new_start_x(0) 36 | , m_start_x(0) 37 | , m_new_start_y(0) 38 | , m_start_y(0) 39 | , m_new_end_x(0) 40 | , m_end_x(0) 41 | , m_new_end_y(0) 42 | , m_end_y(0) 43 | , m_new_enable(false) 44 | { 45 | connect(screen, &Screen::contentModified, this, &Selection::screenContentModified); 46 | 47 | } 48 | 49 | void Selection::setStartX(int x) 50 | { 51 | if (x != m_new_start_x) { 52 | m_new_start_x = x; 53 | setValidity(); 54 | m_screen->scheduleEventDispatch(); 55 | } 56 | } 57 | 58 | int Selection::startX() const 59 | { 60 | return m_start_x; 61 | } 62 | 63 | void Selection::setStartY(int y) 64 | { 65 | if (y != m_new_start_y) { 66 | m_new_start_y = y; 67 | setValidity(); 68 | m_screen->scheduleEventDispatch(); 69 | } 70 | } 71 | 72 | int Selection::startY() const 73 | { 74 | return m_start_y; 75 | } 76 | 77 | void Selection::setEndX(int x) 78 | { 79 | if (m_new_end_x != x) { 80 | m_new_end_x = x; 81 | setValidity(); 82 | m_screen->scheduleEventDispatch(); 83 | } 84 | } 85 | 86 | int Selection::endX() const 87 | { 88 | return m_end_x; 89 | } 90 | 91 | void Selection::setEndY(int y) 92 | { 93 | if (m_new_end_y != y) { 94 | m_new_end_y = y; 95 | setValidity(); 96 | m_screen->scheduleEventDispatch(); 97 | } 98 | } 99 | 100 | int Selection::endY() const 101 | { 102 | return m_end_y; 103 | } 104 | 105 | void Selection::setEnable(bool enable) 106 | { 107 | if (m_new_enable != enable) { 108 | m_new_enable = enable; 109 | m_screen->scheduleEventDispatch(); 110 | } 111 | } 112 | 113 | void Selection::screenContentModified(size_t lineModified, int lineDiff, int contentDiff) 114 | { 115 | if (!m_new_enable) 116 | return; 117 | 118 | if (lineModified >= size_t(m_new_start_y) && lineModified <= size_t(m_new_end_y)) { 119 | setEnable(false); 120 | return; 121 | } 122 | 123 | if (size_t(m_new_end_y) < lineModified && lineDiff != contentDiff) { 124 | m_new_end_y -= lineDiff - contentDiff; 125 | m_new_start_y -= lineDiff - contentDiff; 126 | if (m_new_end_y < 0) { 127 | setEnable(false); 128 | return; 129 | } 130 | if (m_new_start_y < 0) { 131 | m_new_start_y = 0; 132 | } 133 | m_screen->scheduleEventDispatch(); 134 | } 135 | } 136 | 137 | void Selection::setValidity() 138 | { 139 | if (m_new_end_y > m_new_start_y || 140 | (m_new_end_y == m_new_start_y && 141 | m_new_end_x > m_new_start_x)) { 142 | setEnable(true); 143 | } else { 144 | setEnable(false); 145 | } 146 | } 147 | 148 | void Selection::sendToClipboard() const 149 | { 150 | m_screen->currentScreenData()->sendSelectionToClipboard(start_new_point(), end_new_point(), QClipboard::Clipboard); 151 | } 152 | 153 | void Selection::sendToSelection() const 154 | { 155 | m_screen->currentScreenData()->sendSelectionToClipboard(start_new_point(), end_new_point(), QClipboard::Selection); 156 | } 157 | 158 | void Selection::pasteFromSelection() 159 | { 160 | m_screen->pty()->write(QGuiApplication::clipboard()->text(QClipboard::Selection).toUtf8()); 161 | } 162 | 163 | void Selection::pasteFromClipboard() 164 | { 165 | m_screen->pty()->write(QGuiApplication::clipboard()->text(QClipboard::Clipboard).toUtf8()); 166 | } 167 | 168 | void Selection::dispatchChanges() 169 | { 170 | if (!m_new_enable && !m_enable) 171 | return; 172 | 173 | if (m_new_start_y != m_start_y) { 174 | m_start_y = m_new_start_y; 175 | emit startYChanged(); 176 | } 177 | if (m_new_start_x != m_start_x) { 178 | m_start_x = m_new_start_x; 179 | emit startXChanged(); 180 | } 181 | if (m_new_end_y != m_end_y) { 182 | m_end_y = m_new_end_y; 183 | emit endYChanged(); 184 | } 185 | if (m_new_end_x != m_end_x) { 186 | m_end_x = m_new_end_x; 187 | emit endXChanged(); 188 | } 189 | if (m_new_enable != m_enable) { 190 | m_enable = m_new_enable; 191 | emit enableChanged(); 192 | } 193 | } 194 | 195 | static const QChar delimiter_array[] = { ' ', '\n', '{', '(', '[', '}', ')', ']' }; 196 | static const size_t delimiter_array_size = sizeof(delimiter_array) / sizeof(delimiter_array[0]); 197 | const SelectionRange Selection::getDoubleClickRange(std::list::iterator it, size_t character, size_t line, int width) 198 | { 199 | const QString &string = (*it)->textLine(); 200 | size_t start_pos = ((line - (*it)->line()) * width) + character; 201 | if (start_pos > size_t(string.size())) 202 | return { QPoint(), QPoint() }; 203 | size_t end_pos = start_pos + 1; 204 | for (bool found = false; start_pos > 0; start_pos--) { 205 | for (size_t i = 0; i < delimiter_array_size; i++) { 206 | if (string.at(start_pos - 1) == delimiter_array[i]) { 207 | found = true; 208 | break; 209 | } 210 | } 211 | if (found) 212 | break; 213 | } 214 | 215 | for (bool found = false; end_pos < size_t(string.size()); end_pos++) { 216 | for (size_t i = 0; i < delimiter_array_size; i++) { 217 | if (string.at(end_pos) == delimiter_array[i]) { 218 | found = true; 219 | break; 220 | } 221 | } 222 | if (found) 223 | break; 224 | } 225 | 226 | size_t start_line = (start_pos / width) + (*it)->line(); 227 | size_t end_line = (end_pos / width) + (*it)->line(); 228 | 229 | return { QPoint(static_cast(start_pos), static_cast(start_line)), 230 | QPoint(static_cast(end_pos) , static_cast(end_line)) }; 231 | } 232 | bool Selection::enable() const 233 | { 234 | return m_enable; 235 | } 236 | -------------------------------------------------------------------------------- /backend/selection.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #ifndef SELECTION_H 25 | #define SELECTION_H 26 | 27 | #include 28 | #include 29 | 30 | class Screen; 31 | class Block; 32 | 33 | class SelectionRange 34 | { 35 | public: 36 | QPoint start; 37 | QPoint end; 38 | }; 39 | 40 | class Selection : public QObject 41 | { 42 | Q_OBJECT 43 | 44 | Q_PROPERTY(int startX READ startX WRITE setStartX NOTIFY startXChanged) 45 | Q_PROPERTY(int startY READ startY WRITE setStartY NOTIFY startYChanged) 46 | Q_PROPERTY(int endX READ endX WRITE setEndX NOTIFY endXChanged) 47 | Q_PROPERTY(int endY READ endY WRITE setEndY NOTIFY endYChanged) 48 | Q_PROPERTY(bool enable READ enable WRITE setEnable NOTIFY enableChanged) 49 | 50 | public: 51 | explicit Selection(Screen *screen); 52 | 53 | void setStartX(int x); 54 | int startX() const; 55 | 56 | void setStartY(int y); 57 | int startY() const; 58 | 59 | void setEndX(int x); 60 | int endX() const; 61 | 62 | void setEndY(int y); 63 | int endY() const; 64 | 65 | void setEnable(bool enabled); 66 | bool enable() const; 67 | 68 | Q_INVOKABLE void sendToClipboard() const; 69 | Q_INVOKABLE void sendToSelection() const; 70 | Q_INVOKABLE void pasteFromSelection(); 71 | Q_INVOKABLE void pasteFromClipboard(); 72 | 73 | void dispatchChanges(); 74 | 75 | static const SelectionRange getDoubleClickRange(std::list::iterator it, size_t character, size_t line, int width); 76 | signals: 77 | void startXChanged(); 78 | void startYChanged(); 79 | void endXChanged(); 80 | void endYChanged(); 81 | void enableChanged(); 82 | 83 | private slots: 84 | void screenContentModified(size_t lineModified, int lineDiff, int contentDiff); 85 | 86 | private: 87 | void setValidity(); 88 | QPoint start_new_point() const { return QPoint(m_new_start_x, m_new_start_y); } 89 | QPoint end_new_point() const { return QPoint(m_new_end_x, m_new_end_y); } 90 | 91 | Screen *m_screen; 92 | int m_new_start_x; 93 | int m_start_x; 94 | int m_new_start_y; 95 | int m_start_y; 96 | int m_new_end_x; 97 | int m_end_x; 98 | int m_new_end_y; 99 | int m_end_y; 100 | bool m_new_enable; 101 | bool m_enable; 102 | }; 103 | #endif 104 | -------------------------------------------------------------------------------- /backend/text.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************************** 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | * associated documentation files (the "Software"), to deal in the Software without restriction, 6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 17 | * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | ***************************************************************************************************/ 20 | 21 | #include "text.h" 22 | 23 | #include "screen.h" 24 | #include "block.h" 25 | #include 26 | 27 | #include 28 | 29 | Text::Text(Screen *screen) 30 | : QObject(screen) 31 | , m_screen(screen) 32 | , m_text_line(0) 33 | , m_start_index(0) 34 | , m_old_start_index(0) 35 | , m_end_index(0) 36 | , m_line(0) 37 | , m_old_line(0) 38 | , m_width(1) 39 | , m_style(screen->defaultTextStyle()) 40 | , m_new_style(screen->defaultTextStyle()) 41 | , m_style_dirty(true) 42 | , m_text_dirty(true) 43 | , m_visible(true) 44 | , m_visible_old(true) 45 | , m_latin(true) 46 | , m_latin_old(true) 47 | , m_foregroundColor(m_screen->defaultForegroundColor()) 48 | , m_backgroundColor(m_screen->defaultBackgroundColor()) 49 | { 50 | connect(m_screen->colorPalette(), SIGNAL(changed()), this, SLOT(paletteChanged())); 51 | connect(m_screen, SIGNAL(dispatchTextSegmentChanges()), this, SLOT(dispatchEvents())); 52 | } 53 | 54 | Text::~Text() 55 | { 56 | } 57 | 58 | int Text::index() const 59 | { 60 | return m_start_index % m_width; 61 | } 62 | 63 | int Text::line() const 64 | { 65 | return m_line + (m_start_index / m_width); 66 | } 67 | 68 | void Text::setLine(int line, int width, const QString *textLine) 69 | { 70 | m_line = line; 71 | m_width = width; 72 | m_text_dirty = true; 73 | m_text_line = textLine; 74 | } 75 | 76 | bool Text::visible() const 77 | { 78 | return m_visible; 79 | } 80 | 81 | void Text::setVisible(bool visible) 82 | { 83 | m_visible = visible; 84 | } 85 | 86 | QString Text::text() const 87 | { 88 | return m_text; 89 | } 90 | 91 | QColor Text::foregroundColor() const 92 | { 93 | return m_foregroundColor; 94 | } 95 | 96 | 97 | QColor Text::backgroundColor() const 98 | { 99 | return m_backgroundColor; 100 | } 101 | 102 | void Text::setStringSegment(int start_index, int end_index, bool text_changed) 103 | { 104 | m_start_index = start_index; 105 | m_end_index = end_index; 106 | 107 | m_text_dirty = text_changed; 108 | } 109 | 110 | void Text::setTextStyle(const TextStyle &style) 111 | { 112 | m_new_style = style; 113 | m_style_dirty = true; 114 | } 115 | 116 | bool Text::bold() const 117 | { 118 | return m_style.style & TextStyle::Bold; 119 | } 120 | 121 | bool Text::blinking() const 122 | { 123 | return m_style.style & TextStyle::Blinking; 124 | } 125 | 126 | bool Text::underline() const 127 | { 128 | return m_style.style & TextStyle::Underlined; 129 | } 130 | 131 | void Text::setLatin(bool latin) 132 | { 133 | m_latin = latin; 134 | } 135 | 136 | bool Text::latin() const 137 | { 138 | return m_latin_old; 139 | } 140 | 141 | static bool differentStyle(TextStyle::Styles a, TextStyle::Styles b, TextStyle::Style style) 142 | { 143 | return (a & style) != (b & style); 144 | } 145 | 146 | void Text::dispatchEvents() 147 | { 148 | int old_line = m_old_line + (m_old_start_index / m_width); 149 | int new_line = m_line + (m_start_index / m_width); 150 | if (old_line != new_line) { 151 | m_old_line = m_line; 152 | emit lineChanged(); 153 | } 154 | 155 | if (m_latin != m_latin_old) { 156 | m_latin_old = m_latin; 157 | emit latinChanged(); 158 | } 159 | 160 | if (m_old_start_index != m_start_index 161 | || m_text_dirty) { 162 | m_text_dirty = false; 163 | QString old_text = m_text; 164 | m_text = m_text_line->mid(m_start_index, m_end_index - m_start_index + 1); 165 | if (m_old_start_index != m_start_index) { 166 | m_old_start_index = m_start_index; 167 | emit indexChanged(); 168 | } 169 | emit textChanged(); 170 | } 171 | 172 | if (m_style_dirty) { 173 | m_style_dirty = false; 174 | 175 | bool emit_foreground = m_new_style.foreground != m_style.foreground; 176 | bool emit_background = m_new_style.background != m_style.background; 177 | TextStyle::Styles new_style = m_new_style.style; 178 | TextStyle::Styles old_style = m_style.style; 179 | 180 | bool emit_bold = false; 181 | bool emit_blink = false; 182 | bool emit_underline = false; 183 | bool emit_inverse = false; 184 | if (new_style != old_style) { 185 | emit_bold = differentStyle(new_style, old_style, TextStyle::Bold); 186 | emit_blink = differentStyle(new_style, old_style, TextStyle::Blinking); 187 | emit_underline = differentStyle(new_style, old_style, TextStyle::Underlined); 188 | emit_inverse = differentStyle(new_style, old_style, TextStyle::Inverse); 189 | } 190 | 191 | m_style = m_new_style; 192 | if (emit_inverse) { 193 | setForegroundColor(); 194 | setBackgroundColor(); 195 | } else { 196 | if (emit_foreground || emit_bold) { 197 | setForegroundColor(); 198 | } 199 | if (emit_background) { 200 | setBackgroundColor(); 201 | } 202 | } 203 | 204 | if (emit_bold) { 205 | emit boldChanged(); 206 | } 207 | 208 | if (emit_blink) { 209 | emit blinkingChanged(); 210 | } 211 | 212 | if (emit_underline) { 213 | emit underlineChanged(); 214 | } 215 | 216 | } 217 | 218 | 219 | if (m_visible_old != m_visible) { 220 | m_visible_old = m_visible; 221 | emit visibleChanged(); 222 | } 223 | } 224 | 225 | void Text::paletteChanged() 226 | { 227 | setBackgroundColor(); 228 | setForegroundColor(); 229 | } 230 | 231 | void Text::setBackgroundColor() 232 | { 233 | QColor new_background; 234 | if (m_style.style & TextStyle::Inverse) { 235 | new_background = m_style.foreground; 236 | } else { 237 | new_background = m_style.background; 238 | } 239 | if (new_background != m_backgroundColor) { 240 | m_backgroundColor = new_background; 241 | emit backgroundColorChanged(); 242 | } 243 | } 244 | 245 | void Text::setForegroundColor() 246 | { 247 | QColor new_foreground; 248 | if (m_style.style & TextStyle::Inverse) { 249 | new_foreground = m_style.background; 250 | } else { 251 | new_foreground = m_style.foreground; 252 | } 253 | if (new_foreground != m_foregroundColor) { 254 | m_foregroundColor = new_foreground; 255 | emit foregroundColorChanged(); 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /backend/text.h: -------------------------------------------------------------------------------- 1 | /************************************************************************************************** 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | * associated documentation files (the "Software"), to deal in the Software without restriction, 6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 17 | * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | ***************************************************************************************************/ 20 | 21 | #ifndef TEXT_SEGMENT_H 22 | #define TEXT_SEGMENT_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "text_style.h" 30 | 31 | class Screen; 32 | class QQuickItem; 33 | 34 | class Text : public QObject 35 | { 36 | Q_OBJECT 37 | Q_PROPERTY(int index READ index NOTIFY indexChanged) 38 | Q_PROPERTY(int line READ line NOTIFY lineChanged) 39 | Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged) 40 | Q_PROPERTY(QString text READ text NOTIFY textChanged) 41 | Q_PROPERTY(QColor foregroundColor READ foregroundColor NOTIFY foregroundColorChanged) 42 | Q_PROPERTY(QColor backgroundColor READ backgroundColor NOTIFY backgroundColorChanged) 43 | Q_PROPERTY(bool bold READ bold NOTIFY boldChanged) 44 | Q_PROPERTY(bool blinking READ blinking NOTIFY blinkingChanged) 45 | Q_PROPERTY(bool underline READ underline NOTIFY underlineChanged) 46 | Q_PROPERTY(bool latin READ latin NOTIFY latinChanged) 47 | public: 48 | Text(Screen *screen); 49 | ~Text(); 50 | 51 | int index() const; 52 | 53 | int line() const; 54 | void setLine(int line, int width, const QString *textLine); 55 | 56 | bool visible() const; 57 | void setVisible(bool visible); 58 | 59 | QString text() const; 60 | QColor foregroundColor() const; 61 | QColor backgroundColor() const; 62 | 63 | void setStringSegment(int start_index, int end_index, bool textChanged); 64 | void setTextStyle(const TextStyle &style); 65 | 66 | bool bold() const; 67 | bool blinking() const; 68 | bool underline() const; 69 | 70 | void setLatin(bool latin); 71 | bool latin() const; 72 | 73 | QObject *item() const; 74 | 75 | public slots: 76 | void dispatchEvents(); 77 | 78 | signals: 79 | void indexChanged(); 80 | void lineChanged(); 81 | void visibleChanged(); 82 | void textChanged(); 83 | void foregroundColorChanged(); 84 | void backgroundColorChanged(); 85 | void boldChanged(); 86 | void blinkingChanged(); 87 | void underlineChanged(); 88 | void latinChanged(); 89 | 90 | private slots: 91 | void paletteChanged(); 92 | 93 | private: 94 | void setBackgroundColor(); 95 | void setForegroundColor(); 96 | 97 | Screen *m_screen; 98 | QString m_text; 99 | const QString *m_text_line; 100 | int m_start_index; 101 | int m_old_start_index; 102 | int m_end_index; 103 | int m_line; 104 | int m_old_line; 105 | int m_width; 106 | 107 | TextStyle m_style; 108 | TextStyle m_new_style; 109 | 110 | bool m_style_dirty; 111 | bool m_text_dirty; 112 | bool m_visible; 113 | bool m_visible_old; 114 | bool m_latin; 115 | bool m_latin_old; 116 | 117 | QColor m_foregroundColor; 118 | QColor m_backgroundColor; 119 | }; 120 | 121 | #endif // TEXT_SEGMENT_H 122 | -------------------------------------------------------------------------------- /backend/text_style.cpp: -------------------------------------------------------------------------------- 1 | #include "text_style.h" 2 | 3 | #include "screen.h" 4 | #include "text.h" 5 | 6 | #include 7 | 8 | TextStyle::TextStyle() 9 | : style(Normal) 10 | , foreground(0) 11 | , background(0) 12 | { 13 | } 14 | 15 | bool TextStyle::isCompatible(const TextStyle &other) const 16 | { 17 | return foreground == other.foreground 18 | && background == other.background 19 | && style == other.style; 20 | } 21 | 22 | QDebug operator<<(QDebug debug, TextStyleLine line) 23 | { 24 | debug << "[" << line.start_index << "(" << line.style << ":" << line.foreground << ":" << line.background << ")" << line.end_index << "]"; 25 | return debug; 26 | } 27 | 28 | void TextStyleLine::releaseTextSegment(Screen *screen) 29 | { 30 | if (text_segment) { 31 | text_segment->setVisible(false); 32 | screen->releaseTextSegment(text_segment); 33 | text_segment = 0; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /backend/text_style.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXT_STYLE_H 2 | #define TEXT_STYLE_H 3 | 4 | #include 5 | 6 | #include "color_palette.h" 7 | 8 | class Screen; 9 | 10 | class TextStyle 11 | { 12 | public: 13 | enum Style { 14 | Normal = 0x0000, 15 | Italic = 0x0001, 16 | Bold = 0x0002, 17 | Underlined = 0x0004, 18 | Blinking = 0x0008, 19 | FastBlinking = 0x0010, 20 | Gothic = 0x0020, 21 | DoubleUnderlined = 0x0040, 22 | Framed = 0x0080, 23 | Overlined = 0x0100, 24 | Encircled = 0x0200, 25 | Inverse = 0x0400 26 | }; 27 | Q_DECLARE_FLAGS(Styles, Style) 28 | 29 | TextStyle(); 30 | 31 | Styles style; 32 | QRgb foreground; 33 | QRgb background; 34 | 35 | bool isCompatible(const TextStyle &other) const; 36 | }; 37 | 38 | class Text; 39 | class TextStyleLine : public TextStyle { 40 | public: 41 | TextStyleLine(const TextStyle &style, int start_index, int end_index) 42 | : TextStyle(style) 43 | , start_index(start_index) 44 | , end_index(end_index) 45 | , old_index(-1) 46 | , text_segment(0) 47 | , style_dirty(true) 48 | , index_dirty(true) 49 | , text_dirty(true) 50 | { 51 | } 52 | 53 | TextStyleLine() 54 | : start_index(0) 55 | , end_index(0) 56 | , old_index(-1) 57 | , text_segment(0) 58 | , style_dirty(false) 59 | , index_dirty(false) 60 | , text_dirty(false) 61 | { 62 | 63 | } 64 | 65 | void releaseTextSegment(Screen *screen); 66 | 67 | int start_index; 68 | int end_index; 69 | 70 | int old_index; 71 | Text *text_segment; 72 | bool style_dirty; 73 | bool index_dirty; 74 | bool text_dirty; 75 | 76 | void setStyle(const TextStyle &style) { 77 | foreground = style.foreground; 78 | background = style.background; 79 | this->style = style.style; 80 | } 81 | }; 82 | QDebug operator<<(QDebug debug, TextStyleLine line); 83 | 84 | 85 | #endif // TEXT_STYLE_H 86 | -------------------------------------------------------------------------------- /backend/utf8_decoder.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #ifndef UTF8_DECODER 25 | #define UTF8_DECODER 26 | 27 | #include "controll_chars.h" 28 | 29 | class Utf8Decoder 30 | { 31 | public: 32 | inline Utf8Decoder(); 33 | 34 | inline void addChar(uchar character); 35 | 36 | inline bool isLatin() const; 37 | inline bool isC1() const; 38 | 39 | inline void clear(); 40 | private: 41 | short m_expected_length; 42 | short m_length; 43 | uint32_t m_unicode; 44 | }; 45 | 46 | Utf8Decoder::Utf8Decoder() 47 | { 48 | clear(); 49 | } 50 | 51 | void Utf8Decoder::addChar(uchar character) 52 | { 53 | if (m_length && m_length == m_expected_length) { 54 | clear(); 55 | } 56 | 57 | if (character < 0x80) 58 | return; 59 | 60 | fprintf(stderr, "Character: 0x%x\n", character); 61 | if (m_expected_length == 0) { 62 | //this is naive. There must be a faster way. 63 | if ((character & 0xfc) == 0xfc) { 64 | m_expected_length = 5; 65 | m_unicode = character & 0x01; 66 | } else if ((character & 0xf8) == 0xf8) { 67 | m_expected_length = 4; 68 | m_unicode = character & 0x03; 69 | } else if ((character & 0xf0) == 0xf0) { 70 | m_expected_length = 3; 71 | m_unicode = character & 0x07; 72 | } else if ((character & 0xe0) == 0xe0) { 73 | m_expected_length = 2; 74 | m_unicode = character & 0x0f; 75 | } else if ((character & 0xc0) == 0xc0) { 76 | m_expected_length = 1; 77 | m_unicode = character & 0x1f; 78 | } else { 79 | m_expected_length = 0; 80 | m_unicode = 0; 81 | qWarning("Utf8Decoder: invalid decoder character"); 82 | } 83 | } else { 84 | fprintf(stderr, "Before 0x%x adding 0x%x pure 0x%x\n", m_unicode,(character & 0x3f), character); 85 | m_unicode = (m_unicode << 6) | (character & 0x3f); 86 | fprintf(stderr, "After 0x%x\n", m_unicode); 87 | m_length++; 88 | } 89 | } 90 | 91 | bool Utf8Decoder::isLatin() const 92 | { 93 | return m_expected_length < 2 && m_unicode < 0xff; 94 | } 95 | 96 | bool Utf8Decoder::isC1() const 97 | { 98 | return m_expected_length == 2 && m_length == m_expected_length && 99 | (m_unicode >= C1_8bit::C1_8bit_Start && m_unicode <= C1_8bit::C1_8bit_Stop); 100 | } 101 | 102 | void Utf8Decoder::clear() 103 | { 104 | m_expected_length = 0; 105 | m_length = 0; 106 | m_unicode = 0; 107 | } 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /backend/yat_pty.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************************** 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | * associated documentation files (the "Software"), to deal in the Software without restriction, 6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 17 | * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | ***************************************************************************************************/ 20 | 21 | #include "yat_pty.h" 22 | 23 | #include 24 | #include 25 | 26 | #ifdef LINUX 27 | #include 28 | #endif 29 | 30 | #include 31 | #ifdef Q_OS_MAC 32 | #include 33 | #else 34 | #include 35 | #endif 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | static char env_variables[][255] = { 45 | "TERM=xterm-color", 46 | "COLORTERM=xterm", 47 | "COLORFGBG=15;0", 48 | "LINES", 49 | "COLUMNS", 50 | "TERMCAP" 51 | }; 52 | static int env_variables_size = sizeof(env_variables) / sizeof(env_variables[0]); 53 | 54 | YatPty::YatPty() 55 | : m_winsize(0) 56 | { 57 | m_terminal_pid = forkpty(&m_master_fd, 58 | NULL, 59 | NULL, 60 | NULL); 61 | 62 | if (m_terminal_pid == 0) { 63 | for (int i = 0; i < env_variables_size; i++) { 64 | ::putenv(env_variables[i]); 65 | } 66 | ::execl("/bin/bash", "/bin/bash", "--login", (const char *) 0); 67 | exit(0); 68 | } 69 | 70 | m_reader = new QSocketNotifier(m_master_fd,QSocketNotifier::Read,this); 71 | connect(m_reader, &QSocketNotifier::activated, this, &YatPty::readData); 72 | } 73 | 74 | YatPty::~YatPty() 75 | { 76 | } 77 | 78 | void YatPty::write(const QByteArray &data) 79 | { 80 | if (::write(m_master_fd, data.constData(), data.size()) < 0) { 81 | qDebug() << "Something whent wrong when writing to m_master_fd"; 82 | } 83 | } 84 | 85 | void YatPty::setWidth(int width, int pixelWidth) 86 | { 87 | if (!m_winsize) { 88 | m_winsize = new struct winsize; 89 | m_winsize->ws_row = 25; 90 | m_winsize->ws_ypixel = 0; 91 | } 92 | 93 | m_winsize->ws_col = width; 94 | m_winsize->ws_xpixel = pixelWidth; 95 | ioctl(m_master_fd, TIOCSWINSZ, m_winsize); 96 | } 97 | 98 | void YatPty::setHeight(int height, int pixelHeight) 99 | { 100 | if (!m_winsize) { 101 | m_winsize = new struct winsize; 102 | m_winsize->ws_col = 80; 103 | m_winsize->ws_xpixel = 0; 104 | } 105 | m_winsize->ws_row = height; 106 | m_winsize->ws_ypixel = pixelHeight; 107 | ioctl(m_master_fd, TIOCSWINSZ, m_winsize); 108 | 109 | } 110 | 111 | QSize YatPty::size() const 112 | { 113 | if (!m_winsize) { 114 | YatPty *that = const_cast(this); 115 | that->m_winsize = new struct winsize; 116 | ioctl(m_master_fd, TIOCGWINSZ, m_winsize); 117 | } 118 | return QSize(m_winsize->ws_col, m_winsize->ws_row); 119 | } 120 | 121 | int YatPty::masterDevice() const 122 | { 123 | return m_master_fd; 124 | } 125 | 126 | 127 | void YatPty::readData() 128 | { 129 | int size_of_buffer = sizeof m_data_buffer / sizeof *m_data_buffer; 130 | ssize_t read_size = ::read(m_master_fd,m_data_buffer,size_of_buffer); 131 | if (read_size > 0) { 132 | QByteArray to_return = QByteArray::fromRawData(m_data_buffer,read_size); 133 | emit readyRead(to_return); 134 | } else if (read_size <= 0) { 135 | delete m_reader; 136 | emit hangupReceived(); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /backend/yat_pty.h: -------------------------------------------------------------------------------- 1 | /************************************************************************************************** 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | * associated documentation files (the "Software"), to deal in the Software without restriction, 6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 17 | * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | ***************************************************************************************************/ 20 | 21 | #ifndef YAT_PTY_H 22 | #define YAT_PTY_H 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | class QSocketNotifier; 31 | 32 | class YatPty : public QObject 33 | { 34 | Q_OBJECT 35 | public: 36 | YatPty(); 37 | ~YatPty(); 38 | 39 | void write(const QByteArray &data); 40 | 41 | void setWidth(int width, int pixelWidth = 0); 42 | void setHeight(int height, int pixelHeight = 0); 43 | QSize size() const; 44 | 45 | int masterDevice() const; 46 | 47 | signals: 48 | void hangupReceived(); 49 | void readyRead(const QByteArray &data); 50 | 51 | private: 52 | void readData(); 53 | 54 | pid_t m_terminal_pid; 55 | int m_master_fd; 56 | char m_slave_file_name[PATH_MAX]; 57 | struct winsize *m_winsize; 58 | char m_data_buffer[1024]; 59 | QSocketNotifier *m_reader; 60 | }; 61 | 62 | #endif //YAT_PTY_H 63 | -------------------------------------------------------------------------------- /docs/Ecma-048.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jorgen/yat/9d2de573c74d963fff4e67ed4f2e4ff10fee1095/docs/Ecma-048.pdf -------------------------------------------------------------------------------- /qml/Yat/Cursor.qml: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | import QtQuick 2.0 25 | 26 | import Yat 1.0 27 | 28 | ObjectDestructItem { 29 | id: cursor 30 | 31 | property real fontHeight 32 | property real fontWidth 33 | 34 | height: fontHeight 35 | width: fontWidth 36 | x: objectHandle.x * fontWidth 37 | y: objectHandle.y * fontHeight 38 | z: 1.1 39 | 40 | visible: objectHandle.visible 41 | 42 | ShaderEffect { 43 | anchors.fill: parent 44 | 45 | property variant source: fragmentSource 46 | 47 | fragmentShader: 48 | "uniform lowp float qt_Opacity;" + 49 | "uniform sampler2D source;" + 50 | "varying highp vec2 qt_TexCoord0;" + 51 | 52 | "void main() {" + 53 | " lowp vec4 color = texture2D(source, qt_TexCoord0 ) * qt_Opacity;" + 54 | " gl_FragColor = vec4(1.0 - color.r, 1.0 - color.g, 1.0 - color.b, color.a);" + 55 | "}" 56 | 57 | ShaderEffectSource { 58 | id: fragmentSource 59 | 60 | sourceItem: textContainer 61 | live: true 62 | 63 | sourceRect: Qt.rect(cursor.x,cursor.y,cursor.width,cursor.height); 64 | } 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /qml/Yat/Screen.qml: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | import QtQuick 2.10 25 | import QtQuick.Controls 2.2 26 | import Qt.labs.handlers 1.0 27 | import Yat 1.0 as Yat 28 | 29 | Yat.TerminalScreen { 30 | id: screenItem 31 | 32 | property font font 33 | property real fontWidth: fontMetricText.paintedWidth 34 | property real fontHeight: fontMetricText.paintedHeight 35 | 36 | font.family: screen.platformName != "cocoa" ? "monospace" : "menlo" 37 | anchors.fill: parent 38 | focus: true 39 | 40 | Component { 41 | id: textComponent 42 | Yat.Text { } 43 | } 44 | Component { 45 | id: cursorComponent 46 | Yat.Cursor { } 47 | } 48 | Shortcut { 49 | sequence: "Ctrl+Shift+C" 50 | onActivated: screen.selection.sendToClipboard() 51 | } 52 | Shortcut { 53 | sequence: "Ctrl+Shift+V" 54 | onActivated: screen.selection.pasteFromClipboard() 55 | } 56 | Shortcut { 57 | sequence: "Shift+Insert" 58 | onActivated: screen.selection.pasteFromSelection() 59 | } 60 | 61 | onActiveFocusChanged: { 62 | if (activeFocus) 63 | Qt.inputMethod.show(); 64 | } 65 | 66 | Keys.onPressed: { 67 | if (event.text === "?") 68 | screen.printScreen() 69 | screen.sendKey(event.text, event.key, event.modifiers); 70 | } 71 | 72 | Text { 73 | id: fontMetricText 74 | text: "B" 75 | font: parent.font 76 | visible: false 77 | textFormat: Text.PlainText 78 | } 79 | 80 | Rectangle { 81 | id: background 82 | anchors.fill: parent 83 | color: screen.defaultBackgroundColor 84 | } 85 | Flickable { 86 | id: flickable 87 | anchors.top: parent.top 88 | anchors.left: parent.left 89 | contentWidth: width 90 | contentHeight: textContainer.height 91 | interactive: true 92 | flickableDirection: Flickable.VerticalFlick 93 | contentY: ((screen.contentHeight - screen.height) * screenItem.fontHeight) 94 | ScrollBar.vertical: ScrollBar { } 95 | 96 | Item { 97 | id: textContainer 98 | width: parent.width 99 | height: screen.contentHeight * screenItem.fontHeight 100 | 101 | Selection { 102 | characterHeight: fontHeight 103 | characterWidth: fontWidth 104 | screenWidth: screenItem.width 105 | 106 | startX: screen.selection.startX 107 | startY: screen.selection.startY 108 | 109 | endX: screen.selection.endX 110 | endY: screen.selection.endY 111 | visible: screen.selection.enable 112 | z: 1 113 | } 114 | 115 | DragHandler { 116 | target: null 117 | acceptedDevices: PointerDevice.Mouse 118 | property int drag_start_x 119 | property int drag_start_y 120 | onActiveChanged: { 121 | if (active) { 122 | drag_start_x = Math.floor((point.pressPosition.x / fontWidth)); 123 | drag_start_y = Math.floor(point.pressPosition.y / fontHeight); 124 | screen.selection.startX = drag_start_x; 125 | screen.selection.startY = drag_start_y; 126 | screen.selection.endX = drag_start_x; 127 | screen.selection.endY = drag_start_y; 128 | } else { 129 | screen.selection.sendToSelection(); 130 | } 131 | } 132 | onPointChanged: if (active) { 133 | var character = Math.floor(point.position.x / fontWidth); 134 | var line = Math.floor(point.position.y / fontHeight); 135 | var current_pos = Qt.point(character,line); 136 | if (line < drag_start_y || (line === drag_start_y && character < drag_start_x)) { 137 | screen.selection.startX = character; 138 | screen.selection.startY = line; 139 | screen.selection.endX = drag_start_x; 140 | screen.selection.endY = drag_start_y; 141 | } else { 142 | screen.selection.startX = drag_start_x; 143 | screen.selection.startY = drag_start_y; 144 | screen.selection.endX = character; 145 | screen.selection.endY = line; 146 | } 147 | } 148 | } 149 | 150 | TapHandler { 151 | acceptedButtons: Qt.MiddleButton 152 | gesturePolicy: TapHandler.DragThreshold 153 | onTapped: screen.selection.pasteFromSelection() 154 | } 155 | 156 | TapHandler { 157 | gesturePolicy: TapHandler.DragThreshold 158 | onTapped: { 159 | switch (tapCount) { 160 | case 1: 161 | screen.selection.startX = 0; 162 | screen.selection.startY = 0; 163 | screen.selection.endX = 0; 164 | screen.selection.endY = 0; 165 | break; 166 | case 2: 167 | var character = Math.floor(point.position.x / fontWidth); 168 | var line = Math.floor(point.position.y / fontHeight); 169 | screen.doubleClicked(character,line); 170 | screen.selection.sendToSelection(); 171 | break; 172 | } 173 | } 174 | } 175 | } 176 | 177 | Item { 178 | id: cursorContainer 179 | width: textContainer.width 180 | height: textContainer.height 181 | } 182 | 183 | onContentYChanged: { 184 | if (!atYEnd) { 185 | var top_line = Math.floor(Math.max(contentY,0) / screenItem.fontHeight); 186 | screen.ensureVisiblePages(top_line); 187 | } 188 | } 189 | } 190 | 191 | Connections { 192 | id: connections 193 | target: screen 194 | onFlash: flashAnimation.start() 195 | onReset: resetScreenItems(); 196 | 197 | onTextCreated: { 198 | var textSegment = textComponent.createObject(screenItem, 199 | { 200 | "parent" : textContainer, 201 | "objectHandle" : text, 202 | "font" : screenItem.font, 203 | "fontWidth" : screenItem.fontWidth, 204 | "fontHeight" : screenItem.fontHeight, 205 | }); 206 | } 207 | 208 | onCursorCreated: { 209 | if (cursorComponent.status != Component.Ready) { 210 | console.log(cursorComponent.errorString()); 211 | return; 212 | } 213 | var cursorVariable = cursorComponent.createObject(screenItem, 214 | { 215 | "parent" : cursorContainer, 216 | "objectHandle" : cursor, 217 | "fontWidth" : screenItem.fontWidth, 218 | "fontHeight" : screenItem.fontHeight, 219 | }) 220 | } 221 | 222 | onRequestHeightChange: { 223 | terminalWindow.height = newHeight * screenItem.fontHeight; 224 | terminalWindow.contentItem.height = newHeight * screenItem.fontHeight; 225 | } 226 | 227 | onRequestWidthChange: { 228 | terminalWindow.width = newWidth * screenItem.fontWidth; 229 | terminalWindow.contentItem.width = newWidth * screenItem.fontWidth; 230 | } 231 | } 232 | 233 | onFontChanged: { 234 | setTerminalHeight(); 235 | setTerminalWidth(); 236 | } 237 | 238 | onWidthChanged: setTerminalWidth(); 239 | 240 | onHeightChanged: setTerminalHeight(); 241 | 242 | function setTerminalWidth() { 243 | if (fontWidth > 0) { 244 | var pty_width = Math.floor(width / fontWidth); 245 | flickable.width = pty_width * fontWidth; 246 | screen.width = pty_width; 247 | } 248 | } 249 | 250 | function setTerminalHeight() { 251 | if (fontHeight > 0) { 252 | var pty_height = Math.floor(height / fontHeight); 253 | flickable.height = pty_height * fontHeight; 254 | screen.height = pty_height; 255 | } 256 | } 257 | 258 | Rectangle { 259 | id: flash 260 | z: 1.2 261 | anchors.fill: parent 262 | color: "grey" 263 | opacity: 0 264 | SequentialAnimation { 265 | id: flashAnimation 266 | NumberAnimation { 267 | target: flash 268 | property: "opacity" 269 | to: 1 270 | duration: 75 271 | } 272 | NumberAnimation { 273 | target: flash 274 | property: "opacity" 275 | to: 0 276 | duration: 75 277 | } 278 | } 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /qml/Yat/Selection.qml: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | import QtQuick 2.0 25 | 26 | Item { 27 | id: highlightArea 28 | 29 | property real characterWidth: 0 30 | property real characterHeight: 0 31 | property int screenWidth: 0 32 | 33 | property int startX 34 | property int startY 35 | 36 | property int endX 37 | property int endY 38 | 39 | property color color: "grey" 40 | 41 | y: startY * characterHeight 42 | width: parent.width 43 | height: (endY - startY + 1) * characterHeight 44 | 45 | opacity: 0.8 46 | 47 | Rectangle { 48 | id: begginning_rectangle 49 | color: parent.color 50 | opacity: parent.opacity 51 | y:0 52 | height: characterHeight 53 | } 54 | 55 | Rectangle { 56 | id: middle_rectangle 57 | color: parent.color 58 | opacity: parent.opacity 59 | width: parent.width 60 | x: 0 61 | anchors.top: begginning_rectangle.bottom 62 | 63 | } 64 | 65 | Rectangle { 66 | id: end_rectangle 67 | color: parent.color 68 | opacity: parent.opacity 69 | x: 0 70 | height: characterHeight 71 | anchors.top: middle_rectangle.bottom 72 | } 73 | 74 | onCharacterWidthChanged: calculateRectangles(); 75 | onCharacterHeightChanged: calculateRectangles(); 76 | onScreenWidthChanged: calculateRectangles(); 77 | 78 | onStartXChanged: calculateRectangles(); 79 | onStartYChanged: calculateRectangles(); 80 | onEndXChanged: calculateRectangles(); 81 | onEndYChanged: calculateRectangles(); 82 | 83 | function calculateRectangles() { 84 | highlightArea.y = startY * characterHeight; 85 | begginning_rectangle.x = startX * characterWidth; 86 | if (startY === endY) { 87 | middle_rectangle.visible = false; 88 | end_rectangle.visible = false 89 | begginning_rectangle.width = (endX - startX) * characterWidth; 90 | } else { 91 | begginning_rectangle.width = (screenWidth - startX) * characterWidth; 92 | if (startY === endY - 1) { 93 | middle_rectangle.height = 0; 94 | middle_rectangle.visible = false; 95 | }else { 96 | middle_rectangle.visible = true; 97 | middle_rectangle.height = (endY - startY - 1) * characterHeight; 98 | } 99 | end_rectangle.visible = true; 100 | end_rectangle.width = endX * characterWidth; 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /qml/Yat/Text.qml: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | import QtQuick 2.0 25 | 26 | import Yat 1.0 27 | 28 | ObjectDestructItem { 29 | id: textItem 30 | property font font 31 | property real fontWidth 32 | property real fontHeight 33 | 34 | y: objectHandle.line * fontHeight; 35 | x: objectHandle.index * fontWidth; 36 | 37 | width: textElement.paintedWidth 38 | height: textElement.paintedHeight 39 | 40 | visible: objectHandle.visible 41 | 42 | Rectangle { 43 | anchors.fill: parent 44 | color: objectHandle.backgroundColor 45 | 46 | MonoText { 47 | id: textElement 48 | anchors.fill: parent 49 | text: objectHandle.text 50 | color: objectHandle.foregroundColor 51 | font.family: textItem.font.family 52 | font.pixelSize: textItem.font.pixelSize 53 | font.bold: objectHandle.bold 54 | font.underline: objectHandle.underline 55 | latin: objectHandle.latin 56 | 57 | onTextChanged: { 58 | } 59 | SequentialAnimation { 60 | running: objectHandle.blinking 61 | loops: Animation.Infinite 62 | onRunningChanged: { 63 | if (running === false) 64 | textElement.opacity = 1 65 | } 66 | NumberAnimation { 67 | target: textElement 68 | property: "opacity" 69 | to: 0 70 | duration: 250 71 | } 72 | NumberAnimation { 73 | target: textElement 74 | property: "opacity" 75 | to: 1 76 | duration: 250 77 | } 78 | } 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /qml/Yat/Yat.pro: -------------------------------------------------------------------------------- 1 | QT += core-private gui-private qml-private quick quick-private 2 | TARGET = yat 3 | TEMPLATE = lib 4 | CONFIG += plugin 5 | TARGETPATH = Yat 6 | DESTDIR = ../../imports/$$TARGETPATH 7 | 8 | include(../../backend/backend.pri) 9 | 10 | SOURCES += \ 11 | plugin/terminal_screen.cpp \ 12 | plugin/object_destruct_item.cpp \ 13 | plugin/mono_text.cpp \ 14 | plugin/yat_extension_plugin.cpp \ 15 | 16 | HEADERS += \ 17 | plugin/terminal_screen.h \ 18 | plugin/object_destruct_item.h \ 19 | plugin/mono_text.h \ 20 | plugin/yat_extension_plugin.h \ 21 | 22 | OTHER_FILES = \ 23 | qmldir \ 24 | Cursor.qml \ 25 | Text.qml \ 26 | Screen.qml \ 27 | Selection.qml 28 | 29 | isEmpty(YAT_INSTALL_QML):YAT_INSTALL_QML = $$[QT_INSTALL_QML] 30 | 31 | target.path = $$YAT_INSTALL_QML/$$TARGETPATH 32 | INSTALLS += target 33 | 34 | other_files.files = $$OTHER_FILES 35 | other_files.path = $$YAT_INSTALL_QML/$$TARGETPATH 36 | INSTALLS += other_files 37 | 38 | for(other_file, OTHER_FILES) { 39 | ARGUMENTS = $${PWD}$${QMAKE_DIR_SEP}$$other_file $$DESTDIR 40 | !isEmpty(QMAKE_POST_LINK):QMAKE_POST_LINK += && 41 | QMAKE_POST_LINK += $$QMAKE_COPY $$replace(ARGUMENTS, /, $$QMAKE_DIR_SEP) 42 | } 43 | -------------------------------------------------------------------------------- /qml/Yat/plugin/mono_text.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | ******************************************************************************/ 23 | 24 | #include "mono_text.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | class MonoSGNode : public QSGTransformNode 33 | { 34 | public: 35 | MonoSGNode(QQuickItem *owner) 36 | : m_owner(owner) 37 | { 38 | } 39 | 40 | void deleteContent() 41 | { 42 | QSGNode *subnode = firstChild(); 43 | while (subnode) { 44 | // We can't delete the node now as it might be in the preprocess list 45 | // It will be deleted in the next preprocess 46 | m_nodes_to_delete.append(subnode); 47 | subnode = subnode->nextSibling(); 48 | } 49 | removeAllChildNodes(); 50 | } 51 | 52 | void preprocess() 53 | { 54 | while (m_nodes_to_delete.count()) 55 | delete m_nodes_to_delete.takeLast(); 56 | } 57 | 58 | void setLatinText(const QString &text, const QFont &font, const QColor &color) { 59 | QRawFont raw_font = QRawFont::fromFont(font, QFontDatabase::Latin); 60 | 61 | if (raw_font != m_raw_font) { 62 | m_raw_font = raw_font; 63 | m_positions.clear(); 64 | } 65 | 66 | if (m_positions.size() < text.size()) { 67 | qreal x_pos = 0; 68 | qreal max_char_width = raw_font.averageCharWidth(); 69 | qreal ascent = raw_font.ascent(); 70 | if (m_positions.size()) 71 | x_pos = m_positions.last().x() + max_char_width; 72 | int to_add = text.size() - m_positions.size(); 73 | for (int i = 0; i < to_add; i++) { 74 | m_positions << QPointF(x_pos, ascent); 75 | x_pos += max_char_width; 76 | } 77 | } 78 | 79 | deleteContent(); 80 | QSGRenderContext *sgr = QQuickItemPrivate::get(m_owner)->sceneGraphRenderContext(); 81 | QSGGlyphNode *node = sgr->sceneGraphContext()->createGlyphNode(sgr, false); 82 | node->setOwnerElement(m_owner); 83 | node->geometry()->setIndexDataPattern(QSGGeometry::StaticPattern); 84 | node->geometry()->setVertexDataPattern(QSGGeometry::StaticPattern); 85 | node->setStyle(QQuickText::Normal); 86 | 87 | node->setColor(color); 88 | QGlyphRun glyphrun; 89 | glyphrun.setRawFont(raw_font); 90 | glyphrun.setGlyphIndexes(raw_font.glyphIndexesForString(text)); 91 | 92 | glyphrun.setPositions(m_positions); 93 | node->setGlyphs(QPointF(0, raw_font.ascent()), glyphrun); 94 | node->update(); 95 | appendChildNode(node); 96 | } 97 | 98 | void setUnicodeText(const QString &text, const QFont &font, const QColor &color) 99 | { 100 | deleteContent(); 101 | QRawFont raw_font = QRawFont::fromFont(font, QFontDatabase::Latin); 102 | qreal line_width = raw_font.averageCharWidth() * text.size(); 103 | QSGRenderContext *sgr = QQuickItemPrivate::get(m_owner)->sceneGraphRenderContext(); 104 | QTextLayout layout(text,font); 105 | layout.beginLayout(); 106 | QTextLine line = layout.createLine(); 107 | line.setLineWidth(line_width); 108 | //Q_ASSERT(!layout.createLine().isValid()); 109 | layout.endLayout(); 110 | QList glyphRuns = line.glyphRuns(); 111 | qreal xpos = 0; 112 | for (int i = 0; i < glyphRuns.size(); i++) { 113 | QSGGlyphNode *node = sgr->sceneGraphContext()->createGlyphNode(sgr, false); 114 | node->setOwnerElement(m_owner); 115 | node->geometry()->setIndexDataPattern(QSGGeometry::StaticPattern); 116 | node->geometry()->setVertexDataPattern(QSGGeometry::StaticPattern); 117 | node->setGlyphs(QPointF(xpos, raw_font.ascent()), glyphRuns.at(i)); 118 | node->setStyle(QQuickText::Normal); 119 | node->setColor(color); 120 | xpos += raw_font.averageCharWidth() * glyphRuns.at(i).positions().size(); 121 | node->update(); 122 | appendChildNode(node); 123 | } 124 | } 125 | private: 126 | QQuickItem *m_owner; 127 | QVector m_positions; 128 | QLinkedList m_nodes_to_delete; 129 | QRawFont m_raw_font; 130 | }; 131 | 132 | MonoText::MonoText(QQuickItem *parent) 133 | : QQuickItem(parent) 134 | , m_color_changed(false) 135 | , m_latin(true) 136 | , m_old_latin(true) 137 | { 138 | setFlag(ItemHasContents, true); 139 | } 140 | 141 | MonoText::~MonoText() 142 | { 143 | 144 | } 145 | 146 | QString MonoText::text() const 147 | { 148 | return m_text; 149 | } 150 | 151 | void MonoText::setText(const QString &text) 152 | { 153 | if (m_text != text) { 154 | m_text = text; 155 | emit textChanged(); 156 | polish(); 157 | } 158 | } 159 | 160 | QFont MonoText::font() const 161 | { 162 | return m_font; 163 | } 164 | 165 | void MonoText::setFont(const QFont &font) 166 | { 167 | if (font != m_font) { 168 | m_font = font; 169 | emit fontChanged(); 170 | polish(); 171 | } 172 | } 173 | 174 | QColor MonoText::color() const 175 | { 176 | return m_color; 177 | } 178 | 179 | void MonoText::setColor(const QColor &color) 180 | { 181 | if (m_color != color) { 182 | m_color = color; 183 | emit colorChanged(); 184 | update(); 185 | } 186 | } 187 | 188 | qreal MonoText::paintedWidth() const 189 | { 190 | return implicitWidth(); 191 | } 192 | 193 | qreal MonoText::paintedHeight() const 194 | { 195 | return implicitHeight(); 196 | } 197 | 198 | bool MonoText::latin() const 199 | { 200 | return m_latin; 201 | } 202 | 203 | void MonoText::setLatin(bool latin) 204 | { 205 | if (latin == m_latin) 206 | return; 207 | 208 | m_latin = latin; 209 | emit latinChanged(); 210 | } 211 | 212 | QSGNode *MonoText::updatePaintNode(QSGNode *old, UpdatePaintNodeData *) 213 | { 214 | if (m_text.size() == 0 || m_text.trimmed().size() == 0) { 215 | delete old; 216 | return 0; 217 | } 218 | MonoSGNode *node = static_cast(old); 219 | if (!node) { 220 | node = new MonoSGNode(this); 221 | } 222 | 223 | if (m_latin) { 224 | node->setLatinText(m_text, m_font, m_color); 225 | } else { 226 | node->setUnicodeText(m_text, m_font, m_color); 227 | } 228 | 229 | return node; 230 | } 231 | 232 | void MonoText::updatePolish() 233 | { 234 | QRawFont raw_font = QRawFont::fromFont(m_font, QFontDatabase::Latin); 235 | 236 | qreal height = raw_font.descent() + raw_font.ascent() + raw_font.lineThickness(); 237 | qreal width = raw_font.averageCharWidth() * m_text.size(); 238 | 239 | bool emit_text_width_changed = width != implicitWidth(); 240 | bool emit_text_height_changed = height != implicitHeight(); 241 | setImplicitSize(width, height); 242 | 243 | if (emit_text_width_changed) 244 | emit paintedWidthChanged(); 245 | if (emit_text_height_changed) 246 | emit paintedHeightChanged(); 247 | 248 | update(); 249 | } 250 | -------------------------------------------------------------------------------- /qml/Yat/plugin/mono_text.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | ******************************************************************************/ 23 | 24 | #ifndef MONO_TEXT_H 25 | #define MONO_TEXT_H 26 | 27 | #include 28 | #include 29 | 30 | class MonoText : public QQuickItem 31 | { 32 | Q_OBJECT 33 | Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) 34 | Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) 35 | Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) 36 | Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedWidthChanged) 37 | Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedHeightChanged) 38 | Q_PROPERTY(bool latin READ latin WRITE setLatin NOTIFY latinChanged); 39 | public: 40 | MonoText(QQuickItem *parent=0); 41 | ~MonoText(); 42 | 43 | QString text() const; 44 | void setText(const QString &text); 45 | 46 | QFont font() const; 47 | void setFont(const QFont &font); 48 | 49 | QColor color() const; 50 | void setColor(const QColor &color); 51 | 52 | qreal paintedWidth() const; 53 | qreal paintedHeight() const; 54 | 55 | bool latin() const; 56 | void setLatin(bool latin); 57 | 58 | signals: 59 | void textChanged(); 60 | void fontChanged(); 61 | void colorChanged(); 62 | void paintedWidthChanged(); 63 | void paintedHeightChanged(); 64 | void latinChanged(); 65 | protected: 66 | QSGNode *updatePaintNode(QSGNode *old, UpdatePaintNodeData *data) Q_DECL_OVERRIDE; 67 | void updatePolish() Q_DECL_OVERRIDE; 68 | private: 69 | Q_DISABLE_COPY(MonoText); 70 | void updateSize(); 71 | 72 | QString m_text; 73 | QFont m_font; 74 | QColor m_color; 75 | bool m_color_changed; 76 | bool m_latin; 77 | bool m_old_latin; 78 | QSizeF m_text_size; 79 | }; 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /qml/Yat/plugin/object_destruct_item.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #include "object_destruct_item.h" 25 | 26 | ObjectDestructItem::ObjectDestructItem(QQuickItem *parent) 27 | : QQuickItem(parent) 28 | , m_object(0) 29 | { 30 | } 31 | 32 | QObject *ObjectDestructItem::objectHandle() const 33 | { 34 | return m_object; 35 | } 36 | 37 | void ObjectDestructItem::setObjectHandle(QObject *object) 38 | { 39 | bool emit_changed = m_object != object; 40 | if (m_object) { 41 | m_object->disconnect(this); 42 | } 43 | 44 | m_object = object; 45 | connect(m_object, SIGNAL(destroyed()), this, SLOT(objectDestroyed())); 46 | 47 | if (emit_changed) 48 | emit objectHandleChanged(); 49 | } 50 | 51 | void ObjectDestructItem::objectDestroyed() 52 | { 53 | delete this; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /qml/Yat/plugin/object_destruct_item.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #ifndef OBJECT_DESTRUCT_ITEM_H 25 | #define OBJECT_DESTRUCT_ITEM_H 26 | 27 | #include 28 | #include 29 | 30 | class ObjectDestructItem : public QQuickItem 31 | { 32 | Q_OBJECT 33 | 34 | Q_PROPERTY(QObject *objectHandle READ objectHandle WRITE setObjectHandle NOTIFY objectHandleChanged) 35 | 36 | public: 37 | ObjectDestructItem(QQuickItem *parent = 0); 38 | 39 | QObject *objectHandle() const; 40 | void setObjectHandle(QObject *line); 41 | 42 | signals: 43 | void objectHandleChanged(); 44 | 45 | private slots: 46 | void objectDestroyed(); 47 | 48 | private: 49 | QObject *m_object; 50 | }; 51 | 52 | #endif //OBJECT_DESTRUCT_ITEM_H 53 | -------------------------------------------------------------------------------- /qml/Yat/plugin/terminal_screen.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************************************** 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | * associated documentation files (the "Software"), to deal in the Software without restriction, 6 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 17 | * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | ***************************************************************************************************/ 20 | 21 | #include "terminal_screen.h" 22 | 23 | TerminalScreen::TerminalScreen(QQuickItem *parent) 24 | : QQuickItem(parent) 25 | , m_screen(new Screen(this)) 26 | { 27 | setFlag(QQuickItem::ItemAcceptsInputMethod); 28 | connect(m_screen, &Screen::hangup, this, &TerminalScreen::hangupReceived); 29 | } 30 | 31 | TerminalScreen::~TerminalScreen() 32 | { 33 | delete m_screen; 34 | } 35 | 36 | Screen *TerminalScreen::screen() const 37 | { 38 | return m_screen; 39 | } 40 | 41 | QVariant TerminalScreen::inputMethodQuery(Qt::InputMethodQuery query) const 42 | { 43 | switch (query) { 44 | case Qt::ImEnabled: 45 | return QVariant(true); 46 | case Qt::ImHints: 47 | return QVariant(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); 48 | default: 49 | return QVariant(); 50 | } 51 | } 52 | 53 | void TerminalScreen::inputMethodEvent(QInputMethodEvent *event) 54 | { 55 | QString commitString = event->commitString(); 56 | if (commitString.isEmpty()) { 57 | return; 58 | } 59 | 60 | Qt::Key key = Qt::Key_unknown; 61 | if (commitString == " ") { 62 | key = Qt::Key_Space; // screen requires 63 | } 64 | 65 | m_screen->sendKey(commitString, key, 0); 66 | } 67 | 68 | void TerminalScreen::hangupReceived() 69 | { 70 | emit aboutToBeDestroyed(this); 71 | deleteLater(); 72 | } 73 | -------------------------------------------------------------------------------- /qml/Yat/plugin/terminal_screen.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2012 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | ******************************************************************************/ 23 | 24 | #ifndef TERMINALITEM_H 25 | #define TERMINALITEM_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "screen.h" 33 | 34 | class TerminalScreen : public QQuickItem 35 | { 36 | Q_OBJECT 37 | 38 | Q_PROPERTY(Screen *screen READ screen CONSTANT) 39 | public: 40 | TerminalScreen(QQuickItem *parent = 0); 41 | ~TerminalScreen(); 42 | 43 | Screen *screen() const; 44 | 45 | QVariant inputMethodQuery(Qt::InputMethodQuery query) const; 46 | 47 | public slots: 48 | void hangupReceived(); 49 | signals: 50 | void aboutToBeDestroyed(TerminalScreen *screen); 51 | 52 | protected: 53 | void inputMethodEvent(QInputMethodEvent *event); 54 | 55 | private: 56 | Screen *m_screen; 57 | }; 58 | 59 | #endif // TERMINALITEM_H 60 | -------------------------------------------------------------------------------- /qml/Yat/plugin/yat_extension_plugin.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #include "yat_extension_plugin.h" 25 | 26 | #include 27 | 28 | #include 29 | 30 | #include "terminal_screen.h" 31 | #include "object_destruct_item.h" 32 | #include "screen.h" 33 | #include "text.h" 34 | #include "cursor.h" 35 | #include "mono_text.h" 36 | #include "selection.h" 37 | 38 | static const struct { 39 | const char *type; 40 | int major, minor; 41 | } qmldir [] = { 42 | { "Screen", 1, 0}, 43 | { "Text", 1, 0}, 44 | { "Cursor", 1, 0}, 45 | { "Selection", 1, 0}, 46 | }; 47 | 48 | void YatExtensionPlugin::registerTypes(const char *uri) 49 | { 50 | Q_ASSERT(uri == QByteArrayLiteral("Yat")); 51 | qmlRegisterType("Yat", 1, 0, "TerminalScreen"); 52 | qmlRegisterType("Yat", 1, 0, "ObjectDestructItem"); 53 | qmlRegisterType("Yat", 1, 0, "MonoText"); 54 | qmlRegisterType(); 55 | qmlRegisterType(); 56 | qmlRegisterType(); 57 | qmlRegisterType(); 58 | 59 | const QString filesLocation = baseUrl().toString(); 60 | for (int i = 0; i < int(sizeof(qmldir)/sizeof(qmldir[0])); i++) 61 | qmlRegisterType(QUrl(filesLocation + "/" + qmldir[i].type + ".qml"), uri, qmldir[i].major, qmldir[i].minor, qmldir[i].type); 62 | } 63 | 64 | void YatExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri) 65 | { 66 | Q_UNUSED(uri); 67 | Q_UNUSED(engine); 68 | } 69 | -------------------------------------------------------------------------------- /qml/Yat/plugin/yat_extension_plugin.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014 Jørgen Lind 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | *******************************************************************************/ 23 | 24 | #ifndef YAT_EXTENSION_PLUGIN 25 | #define YAT_EXTENSION_PLUGIN 26 | 27 | #include 28 | 29 | class YatExtensionPlugin : public QQmlExtensionPlugin 30 | { 31 | Q_OBJECT 32 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") 33 | public: 34 | void registerTypes(const char *uri); 35 | void initializeEngine(QQmlEngine *engine, const char *uri); 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /qml/Yat/qmldir: -------------------------------------------------------------------------------- 1 | module Yat 2 | plugin yat 3 | classname YatExtensionPlugin 4 | -------------------------------------------------------------------------------- /qml/qml.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE=subdirs 2 | SUBDIRS= \ 3 | Yat \ 4 | -------------------------------------------------------------------------------- /tests/auto/auto.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = \ 3 | block 4 | -------------------------------------------------------------------------------- /tests/auto/block/block.pro: -------------------------------------------------------------------------------- 1 | CONFIG += testcase 2 | QT += testlib quick 3 | 4 | include(../../../backend/backend.pri) 5 | 6 | SOURCES += \ 7 | tst_block.cpp \ 8 | 9 | -------------------------------------------------------------------------------- /tests/tests.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | SUBDIRS = \ 3 | auto 4 | -------------------------------------------------------------------------------- /yat.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE=subdirs 2 | CONFIG += ordered 3 | 4 | !no_tests { 5 | SUBDIRS += tests 6 | } else { 7 | message(Tests are disabled) 8 | } 9 | 10 | SUBDIRS += qml 11 | 12 | CONFIG_VARS = $${OUT_PWD}$${QMAKE_DIR_SEP}.config.vars 13 | QMAKE_CACHE = $${OUT_PWD}$${QMAKE_DIR_SEP}.qmake.cache 14 | 15 | exists($$CONFIG_VARS) { 16 | system(echo include\\\($$CONFIG_VARS\\\) >> $$QMAKE_CACHE) 17 | } 18 | -------------------------------------------------------------------------------- /yat_app/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char* argv[]) 8 | { 9 | // do this before constructing QGuiApplication so that the custom logging rules will override the setFilterRules below 10 | qputenv("QT_LOGGING_CONF", QDir::homePath().toLocal8Bit() + "/.config/QtProject/qtlogging.ini"); 11 | QGuiApplication app(argc, argv); 12 | QLoggingCategory::setFilterRules(QStringLiteral("yat.*.debug=false\nyat.*.info=false")); 13 | QQmlApplicationEngine engine(QUrl("qrc:///yat.qml")); 14 | return app.exec(); 15 | } 16 | -------------------------------------------------------------------------------- /yat_app/yat.qml: -------------------------------------------------------------------------------- 1 | #!/bin/env qml 2 | /******************************************************************************* 3 | * Copyright (c) 2013 Jørgen Lind 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | * SOFTWARE. 22 | * 23 | *******************************************************************************/ 24 | 25 | import QtQuick 2.0 26 | import QtQuick.Window 2.0 27 | 28 | import Yat 1.0 as Yat 29 | 30 | Window { 31 | id: terminalWindow 32 | Yat.Screen { 33 | id: terminal 34 | anchors.fill: parent 35 | Component.onCompleted: terminalWindow.visible = true 36 | onAboutToBeDestroyed: Qt.quit() 37 | } 38 | width: 800 39 | height: 600 40 | color: terminal.screen.defaultBackgroundColor 41 | } 42 | -------------------------------------------------------------------------------- /yat_app/yat.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | yat.qml 4 | 5 | 6 | -------------------------------------------------------------------------------- /yat_app/yat_app.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | TARGET = yat 3 | 4 | QT += qml quick 5 | SOURCES += main.cpp 6 | 7 | RESOURCES += yat.qrc 8 | 9 | --------------------------------------------------------------------------------