Moved to new version of yat. Yat is no longer a submodule but is now integrated.

This commit is contained in:
Filippo Scognamiglio 2013-12-27 00:31:43 +01:00
parent bd39a63a64
commit 6b4b187df5
62 changed files with 14743 additions and 125 deletions

4
.gitmodules vendored
View File

@ -1,4 +0,0 @@
[submodule "yat"]
path = yat
url = https://github.com/Swordifish90/yat
branch = stable

View File

@ -1,4 +1,4 @@
QT += widgets quick
QT += widgets quick core-private gui-private qml-private quick quick-private
include(yat/yat_declarative/yat_declarative.pro)

View File

@ -1,3 +1,26 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
import QtQuick 2.0
Item {
@ -5,15 +28,19 @@ Item {
property real characterWidth: 0
property real characterHeight: 0
property int screenWidth: width / characterWidth
property int screenWidth: 0
property point start
property point end
property int startX
property int startY
property int endX
property int endY
property color color: "grey"
y: startY * characterHeight
width: parent.width
height: parent.height
height: (endY - startY + 1) * characterHeight
opacity: 0.8
@ -48,27 +75,29 @@ Item {
onCharacterHeightChanged: calculateRectangles();
onScreenWidthChanged: calculateRectangles();
onStartChanged: calculateRectangles();
onEndChanged: calculateRectangles();
onStartXChanged: calculateRectangles();
onStartYChanged: calculateRectangles();
onEndXChanged: calculateRectangles();
onEndYChanged: calculateRectangles();
function calculateRectangles() {
highlightArea.y = start.y * characterHeight;
begginning_rectangle.x = start.x * characterWidth;
if (start.y === end.y) {
highlightArea.y = startY * characterHeight;
begginning_rectangle.x = startX * characterWidth;
if (startY === endY) {
middle_rectangle.visible = false;
end_rectangle.visible = false
begginning_rectangle.width = (end.x - start.x) * characterWidth;
begginning_rectangle.width = (endX - startX) * characterWidth;
} else {
begginning_rectangle.width = (screenWidth - start.x) * characterWidth;
if (start.y === end.y - 1) {
begginning_rectangle.width = (screenWidth - startX) * characterWidth;
if (startY === endY - 1) {
middle_rectangle.height = 0;
middle_rectangle.visible = false;
}else {
middle_rectangle.visible = true;
middle_rectangle.height = (end.y - start.y - 1) * characterHeight;
middle_rectangle.height = (endY - startY - 1) * characterHeight;
}
end_rectangle.visible = true;
end_rectangle.width = end.x * characterWidth;
end_rectangle.width = endX * characterWidth;
}
}

View File

@ -0,0 +1,66 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
import QtQuick 2.0
import org.yat 1.0
ObjectDestructItem {
id: cursor
property real fontHeight
property real fontWidth
height: fontHeight
width: fontWidth
x: objectHandle.x * fontWidth
y: objectHandle.y * fontHeight
z: 1.1
visible: objectHandle.visible
ShaderEffect {
anchors.fill: parent
property variant source: fragmentSource
fragmentShader:
"uniform lowp float qt_Opacity;" +
"uniform sampler2D source;" +
"varying highp vec2 qt_TexCoord0;" +
"void main() {" +
" lowp vec4 color = texture2D(source, qt_TexCoord0 ) * qt_Opacity;" +
" gl_FragColor = vec4(1.0 - color.r, 1.0 - color.g, 1.0 - color.b, color.a);" +
"}"
ShaderEffectSource {
id: fragmentSource
sourceItem: background
live: true
sourceRect: Qt.rect(cursor.x,cursor.y,cursor.width,cursor.height);
}
}
}

View File

@ -1,4 +1,28 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
import QtQuick 2.0
import QtQuick.Controls 1.1
import org.yat 1.0
@ -10,10 +34,35 @@ TerminalScreen {
property real fontHeight: fontMetricText.paintedHeight
property var lineComponent : Qt.createComponent("TerminalLine.qml")
property var textComponent : Qt.createComponent("TerminalText.qml")
property var cursorComponent : Qt.createComponent("TerminalCursor.qml")
font.family: "Pet Me"
font.pointSize: 14
//font.bold: true
font.pixelSize: 20
focus: true
Action {
id: copyAction
shortcut: "Ctrl+Shift+C"
onTriggered: screen.selection.sendToClipboard()
}
Action {
id: paseAction
shortcut: "Ctrl+Shift+V"
onTriggered: screen.selection.pasteFromClipboard()
}
onActiveFocusChanged: {
if (activeFocus) {
Qt.inputMethod.show();
}
}
Keys.onPressed: {
if (event.text === "?") {
terminal.screen.printScreen()
}
}
Text {
id: fontMetricText
@ -23,10 +72,47 @@ TerminalScreen {
textFormat: Text.PlainText
}
Rectangle {
id: background
anchors.fill: parent
color: "black"
Flickable {
id: flickable
anchors.top: parent.top
anchors.left: parent.left
contentWidth: width
contentHeight: textContainer.height
interactive: true
flickableDirection: Flickable.VerticalFlick
contentY: ((screen.contentHeight - screen.height) * screenItem.fontHeight)
Item {
id: textContainer
width: parent.width
height: screen.contentHeight * screenItem.fontHeight
Rectangle {
id: background
anchors.fill: parent
color: terminal.screen.defaultBackgroundColor
}
HighlightArea {
characterHeight: fontHeight
characterWidth: fontWidth
screenWidth: terminalWindow.width
startX: screen.selection.startX
startY: screen.selection.startY
endX: screen.selection.endX
endY: screen.selection.endY
visible: screen.selection.enable
}
}
onContentYChanged: {
if (!atYEnd) {
var top_line = Math.floor(Math.max(contentY,0) / screenItem.fontHeight);
screen.ensureVisiblePages(top_line);
}
}
}
Connections {
@ -38,24 +124,44 @@ TerminalScreen {
flashAnimation.start()
}
onCursorPositionChanged: {
cursor.x = x * fontWidth;
cursor.y = y * fontHeight;
}
onReset: {
resetScreenItems();
}
onLineCreated: {
var lineVariable = lineComponent.createObject(screenItem,
onTextCreated: {
var textSegment = textComponent.createObject(screenItem,
{
"objectHandle" : line,
"font": screenItem.font,
"parent" : background,
"objectHandle" : text,
"font" : screenItem.font,
"fontWidth" : screenItem.fontWidth,
"fontHeight" : screenItem.fontHeight,
})
}
onCursorCreated: {
if (cursorComponent.status != Component.Ready) {
console.log(cursorComponent.errorString());
return;
}
var cursorVariable = cursorComponent.createObject(screenItem,
{
"parent" : textContainer,
"objectHandle" : cursor,
"fontWidth" : screenItem.fontWidth,
"fontHeight" : screenItem.fontHeight,
})
}
onRequestHeightChange: {
terminalWindow.height = newHeight * screenItem.fontHeight;
terminalWindow.contentItem.height = newHeight * screenItem.fontHeight;
}
onRequestWidthChange: {
terminalWindow.width = newWidth * screenItem.fontWidth;
terminalWindow.contentItem.width = newWidth * screenItem.fontWidth;
}
}
onFontChanged: {
@ -77,6 +183,7 @@ TerminalScreen {
function setTerminalWidth() {
if (fontWidth > 0) {
var pty_width = Math.floor(width / fontWidth);
flickable.width = pty_width * fontWidth;
screen.width = pty_width;
}
}
@ -84,50 +191,16 @@ TerminalScreen {
function setTerminalHeight() {
if (fontHeight > 0) {
var pty_height = Math.floor(height / fontHeight);
flickable.height = pty_height * fontHeight;
screen.height = pty_height;
}
}
Item {
id: keyHandler
focus: true
Keys.onPressed: {
terminal.screen.sendKey(event.text, event.key, event.modifiers);
if (event.text === "?") {
terminal.screen.printScreen()
}
}
}
HighlightArea {
characterHeight: fontHeight
characterWidth: fontWidth
start: screen.selectionAreaStart
end: screen.selectionAreaEnd
visible: screen.selectionEnabled
}
Rectangle {
id: cursor
width: fontWidth
height: fontHeight
x: 0
y: 0
color: "white"
// SequentialAnimation on opacity{
// NumberAnimation{from: 0; to: 1; duration: 500}
// NumberAnimation{from: 1; to: 0; duration: 500}
// loops: Animation.Infinite
// }
}
Rectangle {
id: flash
z: 1.2
anchors.fill: parent
color: "white"
color: "grey"
opacity: 0
SequentialAnimation {
id: flashAnimation
@ -149,39 +222,49 @@ TerminalScreen {
MouseArea {
id:mousArea
property point drag_start
property int drag_start_x
property int drag_start_y
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
onPressed: {
if (mouse.button == Qt.LeftButton) {
hoverEnabled = true;
var character = Math.floor((mouse.x / screen.charWidth));
var line = Math.floor(mouse.y / screen.lineHeight);
var transformed_mouse = mapToItem(textContainer, mouse.x, mouse.y);
var character = Math.floor((transformed_mouse.x / fontWidth));
var line = Math.floor(transformed_mouse.y / fontHeight);
var start = Qt.point(character,line);
drag_start = start;
screen.selectionAreaStart = start;
screen.selectionAreaEnd = start;
drag_start_x = character;
drag_start_y = line;
screen.selection.startX = character;
screen.selection.startY = line;
screen.selection.endX = character;
screen.selection.endY = line;
}
}
onPositionChanged: {
var character = Math.floor(mouse.x / screen.charWidth);
var line = Math.floor(mouse.y / screen.lineHeight);
var transformed_mouse = mapToItem(textContainer, mouse.x, mouse.y);
var character = Math.floor(transformed_mouse.x / fontWidth);
var line = Math.floor(transformed_mouse.y / fontHeight);
var current_pos = Qt.point(character,line);
if (line < drag_start.y || (line === drag_start.y && character < drag_start.x)) {
screen.selectionAreaStart = current_pos;
screen.selectionAreaEnd = drag_start;
if (line < drag_start_y || (line === drag_start_y && character < drag_start_x)) {
screen.selection.startX = character;
screen.selection.startY = line;
screen.selection.endX = drag_start_x;
screen.selection.endY = drag_start_y;
}else {
screen.selectionAreaEnd = current_pos;
screen.selectionAreaStart = drag_start;
screen.selection.startX = drag_start_x;
screen.selection.startY = drag_start_y;
screen.selection.endX = character;
screen.selection.endY = line;
}
}
onReleased: {
if (mouse.button == Qt.LeftButton) {
hoverEnabled = false;
screen.sendSelectionToSelection();
screen.selection.sendToSelection();
}
}
@ -190,10 +273,12 @@ TerminalScreen {
screen.pasteFromSelection();
}
}
onDoubleClicked: {
if (mouse.button == Qt.LeftButton) {
var character = Math.floor(mouse.x / screen.charWidth);
var line = Math.floor(mouse.y / screen.lineHeight);
var transformed_mouse = mapToItem(textContainer, mouse.x, mouse.y);
var character = Math.floor(transformed_mouse.x / fontWidth);
var line = Math.floor(transformed_mouse.y / fontHeight);
screen.doubleClicked(Qt.point(character,line));
}
}

View File

@ -29,9 +29,10 @@ ObjectDestructItem {
id: textItem
property font font
property real fontWidth
property real fontHeight
y: 0
x: 0
y: objectHandle.line * fontHeight;
x: objectHandle.index * fontWidth;
width: textElement.paintedWidth
height: textElement.paintedHeight
@ -40,39 +41,41 @@ ObjectDestructItem {
Rectangle {
anchors.fill: parent
color: textItem.objectHandle.backgroundColor
}
color: "black" //objectHandle.backgroundColor
MonoText {
id: textElement
anchors.fill: parent
text: objectHandle.text
color: "white" //objectHandle.foregroundColor
font.family: textItem.font.family
font.pixelSize: textItem.font.pixelSize
font.pointSize: textItem.font.pointSize
font.bold: objectHandle.bold
font.underline: objectHandle.underline
latin: objectHandle.latin
Text {
id: textElement
anchors.fill: parent
text: objectHandle.text
color: "white"
font: textItem.font
textFormat: Text.PlainText
}
Connections {
target: objectHandle
onIndexChanged: {
textItem.x = objectHandle.index * textItem.fontWidth;
SequentialAnimation {
running: objectHandle.blinking
loops: Animation.Infinite
onRunningChanged: {
if (running === false)
textElement.opacity = 1
}
NumberAnimation {
target: textElement
property: "opacity"
to: 0
duration: 250
}
NumberAnimation {
target: textElement
property: "opacity"
to: 1
duration: 250
}
}
}
}
//Component.onCompleted: {
// //color = randomBg();
//}
//function randomBg()
//{
// var hex1=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
// var hex2=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
// var hex3=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
// var hex4=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
// var hex5=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
// var hex6=new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
// var bg="#"+hex1[Math.floor(Math.random()*hex1.length)]+hex2[Math.floor(Math.random()*hex2.length)]+hex3[Math.floor(Math.random()*hex3.length)]+hex4[Math.floor(Math.random()*hex4.length)]+hex5[Math.floor(Math.random()*hex5.length)]+hex6[Math.floor(Math.random()*hex6.length)]
// return bg
//}
}

View File

@ -229,13 +229,12 @@ ApplicationWindow{
TerminalScreen {
id: terminal
anchors.centerIn: parent
width: mainwindow.width
height: mainwindow.height
visible: false
anchors.fill: parent
//FIXME: Ugly forced clear terminal at the beginning
Component.onCompleted: terminal.screen.sendKey("l", 76, 67108864);
Component.onCompleted: {
terminal.screen.sendKey("l", 76, 67108864);
}
}
RadialGradient{

1
yat

@ -1 +0,0 @@
Subproject commit fb2266d7a1ef32e36f6c74f986fa831d1fc73588

8
yat/README Normal file
View File

@ -0,0 +1,8 @@
forked at 8c3d6c85c3dc981bca817bd9052a693570e26e6e
YAT is a terminal emulator written in qml and c++
The main goal of the project was to find out if it was possible to use qml to
write a terminal emulator which performed on par with xterm and konsole.
Turns out, it's possible.

41
yat/backend/backend.pri Normal file
View File

@ -0,0 +1,41 @@
DEPENDPATH += $$PWD
INCLUDEPATH += $$PWD
LIBS += -lutil
CONFIG += c++11
MOC_DIR = .moc
OBJECTS_DIR = .obj
HEADERS += \
$$PWD/yat_pty.h \
$$PWD/text.h \
$$PWD/controll_chars.h \
$$PWD/parser.h \
$$PWD/screen.h \
$$PWD/block.h \
$$PWD/color_palette.h \
$$PWD/text_style.h \
$$PWD/screen_data.h \
$$PWD/cursor.h \
$$PWD/nrc_text_codec.h \
$$PWD/scrollback.h \
$$PWD/utf8_decoder.h \
$$PWD/selection.h
SOURCES += \
$$PWD/yat_pty.cpp \
$$PWD/text.cpp \
$$PWD/controll_chars.cpp \
$$PWD/parser.cpp \
$$PWD/screen.cpp \
$$PWD/block.cpp \
$$PWD/color_palette.cpp \
$$PWD/text_style.cpp \
$$PWD/screen_data.cpp \
$$PWD/cursor.cpp \
$$PWD/nrc_text_codec.cpp \
$$PWD/scrollback.cpp \
$$PWD/selection.cpp

557
yat/backend/block.cpp Normal file
View File

@ -0,0 +1,557 @@
/*******************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
******************************************************************************/
#include "block.h"
#include "text.h"
#include "screen.h"
#include <QtQuick/QQuickView>
#include <QtQuick/QQuickItem>
#include <QtCore/QDebug>
#include <algorithm>
Block::Block(Screen *screen)
: m_screen(screen)
, m_line(0)
, m_new_line(-1)
, m_screen_index(0)
, m_width(m_screen->width())
, m_visible(true)
, m_changed(true)
, m_only_latin(true)
{
clear();
}
Block::~Block()
{
for (int i = 0; i < m_style_list.size(); i++) {
m_style_list[i].releaseTextSegment(m_screen);
}
}
Screen *Block::screen() const
{
return m_screen;
}
void Block::clear()
{
m_text_line.clear();
for (int i = 0; i < m_style_list.size(); i++) {
m_style_list[i].releaseTextSegment(m_screen);
}
m_style_list.clear();
m_only_latin = true;
m_changed = true;
}
void Block::clearToEnd(int from)
{
clearCharacters(from, m_text_line.size() - 1);
}
void Block::clearCharacters(int from, int to)
{
if (from > m_text_line.size())
return;
QString empty(to+1-from, QChar(' '));
const TextStyle &defaultTextStyle = m_screen->defaultTextStyle();
replaceAtPos(from, empty, defaultTextStyle);
}
void Block::deleteCharacters(int from, int to)
{
m_changed = true;
int removed = 0;
const int size = (to + 1) - from;
bool found = false;
int last_index = -1;
for (int i = 0; i < m_style_list.size(); i++) {
TextStyleLine &current_style = m_style_list[i];
last_index = i;
if (found) {
current_style.start_index -= removed;
current_style.end_index -= removed;
current_style.index_dirty = true;
if (removed != size) {
int current_style_size = current_style.end_index + 1 - current_style.start_index;
if (current_style_size <= size - removed) {
removed += current_style.end_index + 1 - current_style.start_index;
current_style.releaseTextSegment(m_screen);
m_style_list.remove(i);
i--;
} else {
current_style.end_index -= size - removed;
removed = size;
}
}
} else {
if (current_style.start_index <= from && current_style.end_index >= from) {
found = true;
int left_in_style = (current_style.end_index + 1) - from;
int subtract = std::min(left_in_style, size);
current_style.end_index -= subtract;
current_style.text_dirty = true;
removed = subtract;
if (current_style.end_index < current_style.start_index) {
current_style.releaseTextSegment(m_screen);
m_style_list.remove(i);
i--;
}
}
}
}
if (last_index >= 0) {
TextStyleLine &last_modified = m_style_list[last_index];
TextStyle defaultStyle = m_screen->defaultTextStyle();
if (last_modified.isCompatible(defaultStyle)) {
last_modified.end_index += size;
last_modified.text_dirty = true;
} else {
m_style_list.insert(last_index + 1, TextStyleLine(defaultStyle,
last_modified.end_index + 1, last_modified.end_index + size));
}
}
m_text_line.remove(from, size);
}
void Block::deleteToEnd(int from)
{
deleteCharacters(from, m_text_line.size() - 1);
}
void Block::deleteLines(int from)
{
if (from > lineCount())
return;
}
void Block::replaceAtPos(int pos, const QString &text, const TextStyle &style, bool only_latin)
{
m_changed = true;
m_only_latin = m_only_latin && only_latin;
if (pos >= m_text_line.size()) {
if (pos > m_text_line.size()) {
int old_size = m_text_line.size();
QString filling(pos - m_text_line.size(), QChar(' '));
m_text_line.append(filling);
m_style_list.append(TextStyleLine(m_screen->defaultTextStyle(), old_size, old_size + filling.size() -1));
}
m_text_line.append(text);
m_style_list.append(TextStyleLine(style, pos, pos + text.size()-1));
return;
} else if (pos + text.size() > m_text_line.size()) {
m_style_list.append(TextStyleLine(m_screen->defaultTextStyle(), pos + text.size() - m_text_line.size(), pos + text.size() -1));
}
m_text_line.replace(pos,text.size(),text);
bool found = false;
for (int i = 0; i < m_style_list.size(); i++) {
TextStyleLine &current_style = m_style_list[i];
if (found) {
if (current_style.end_index <= pos + text.size() - 1) {
current_style.releaseTextSegment(m_screen);
m_style_list.remove(i);
i--;
} else if (current_style.start_index <= pos + text.size()) {
current_style.start_index = pos + text.size();
current_style.style_dirty = true;
current_style.text_dirty = true;
current_style.index_dirty = true;
} else {
break;
}
} else if (pos >= current_style.start_index && pos <= current_style.end_index) {
found = true;
if (pos + text.size() -1 <= current_style.end_index) {
if (current_style.isCompatible(style)) {
current_style.text_dirty = true;
} else {
if (current_style.start_index == pos && current_style.end_index == pos + text.size() - 1) {
current_style.setStyle(style);
current_style.text_dirty = true;
current_style.style_dirty = true;
} else if (current_style.start_index == pos) {
current_style.start_index = pos + text.size();
current_style.text_dirty = true;
m_style_list.insert(i, TextStyleLine(style,pos, pos+text.size() -1));
} else if (current_style.end_index == pos + text.size() - 1) {
current_style.end_index = pos - 1;
current_style.text_dirty = true;
m_style_list.insert(i+1, TextStyleLine(style,pos, pos + text.size() - 1));
} else {
int old_end = current_style.end_index;
current_style.end_index = pos - 1;
current_style.text_dirty = true;
m_style_list.insert(i+1, TextStyleLine(style,pos, pos + text.size() - 1));
if (pos + text.size() < m_text_line.size()) {
m_style_list.insert(i+2, TextStyleLine(current_style,pos + text.size(), old_end));
}
}
}
break;
} else {
if (current_style.isCompatible(style)) {
current_style.end_index = pos + text.size() - 1;
current_style.text_dirty = true;
} else {
if (current_style.start_index == pos) {
if (i > 0 && m_style_list.at(i-1).isCompatible(style)) {
TextStyleLine &previous_style = m_style_list[i -1];
previous_style.end_index+= text.size();
previous_style.text_dirty = true;
current_style.releaseTextSegment(m_screen);
m_style_list.remove(i);
i--;
} else {
current_style.end_index = pos + text.size() - 1;
current_style.style = style.style;
current_style.forground = style.forground;
current_style.background = style.background;
current_style.text_dirty = true;
current_style.style_dirty = true;
current_style.index_dirty = true;
}
} else {
current_style.end_index = pos - 1;
current_style.text_dirty = true;
m_style_list.insert(i+1, TextStyleLine(style, pos, pos + text.size() -1));
i++;
}
}
}
}
}
}
void Block::insertAtPos(int pos, const QString &text, const TextStyle &style, bool only_latin)
{
m_changed = true;
m_only_latin = m_only_latin && only_latin;
m_text_line.insert(pos,text);
bool found = false;
for (int i = 0; i < m_style_list.size(); i++) {
TextStyleLine &current_style = m_style_list[i];
if (found) {
current_style.start_index += text.size();
current_style.end_index += text.size();
current_style.index_dirty = true;
if (current_style.start_index >= m_text_line.size()) {
current_style.releaseTextSegment(m_screen);
m_style_list.remove(i);
i--;
} else if (current_style.end_index >= m_text_line.size()) {
current_style.end_index = m_text_line.size()-1;
}
} else if (pos >= current_style.start_index && pos <= current_style.end_index) {
found = true;
if (current_style.start_index == pos) {
current_style.start_index += text.size();
current_style.end_index += text.size();
current_style.index_dirty = true;
m_style_list.insert(i, TextStyleLine(style, pos, pos+ text.size() - 1));
i++;
} else if (current_style.end_index == pos) {
current_style.end_index--;
current_style.text_dirty = true;
m_style_list.insert(i+1, TextStyleLine(style, pos, pos+ text.size() - 1));
i++;
} else {
int old_end = current_style.end_index;
current_style.end_index = pos -1;
current_style.text_dirty = true;
m_style_list.insert(i+1, TextStyleLine(style, pos, pos + text.size() - 1));
if (pos + text.size() < m_text_line.size()) {
int segment_end = std::min(m_text_line.size() -1, old_end + text.size());
m_style_list.insert(i+2, TextStyleLine(current_style, pos + text.size(), segment_end));
i+=2;
} else {
i++;
}
}
}
}
}
QString *Block::textLine()
{
return &m_text_line;
}
void Block::setVisible(bool visible)
{
if (visible != m_visible) {
m_changed = true;
m_visible = visible;
for (int i = 0; i < m_style_list.size(); i++) {
if (m_style_list.at(i).text_segment) {
m_style_list.at(i).text_segment->setVisible(visible);
}
}
}
}
bool Block::visible() const
{
return m_visible;
}
Block *Block::split(int line)
{
if (line >= lineCount())
return nullptr;
m_changed = true;
Block *to_return = new Block(m_screen);
int start_index = line * m_width;
for (int i = 0; i < m_style_list.size(); i++) {
ensureStyleAlignWithLines(i);
TextStyleLine &current_style = m_style_list[i];
if (current_style.start_index >= start_index) {
current_style.start_index -= start_index;
current_style.old_index = current_style.start_index - 1;
current_style.end_index -= start_index;
current_style.index_dirty = true;
current_style.text_dirty = true;
current_style.index_dirty = true;
to_return->m_style_list.append(TextStyleLine(current_style, current_style.start_index,
current_style.end_index));
m_style_list.remove(i);
i--;
}
}
to_return->m_text_line = m_text_line.mid(start_index, m_text_line.size() - start_index);
m_text_line.remove(start_index, m_text_line.size() - start_index);
return to_return;
}
Block *Block::takeLine(int line)
{
if (line >= lineCount())
return nullptr;
m_changed = true;
Block *to_return = new Block(m_screen);
int start_index = line * m_width;
int end_index = start_index + (m_width - 1);
for (int i = 0; i < m_style_list.size(); i++) {
ensureStyleAlignWithLines(i);
TextStyleLine &current_style = m_style_list[i];
if (current_style.start_index >= start_index && current_style.end_index <= end_index) {
current_style.releaseTextSegment(m_screen);
current_style.start_index -= start_index;
current_style.end_index -= start_index;
current_style.index_dirty = true;
to_return->m_style_list.append(TextStyleLine(current_style, current_style.start_index,
current_style.end_index));
m_style_list.remove(i);
i--;
} else if (current_style.start_index > end_index) {
current_style.start_index -= (end_index + 1) - start_index;
current_style.end_index -= (end_index + 1) - start_index;
current_style.index_dirty = true;
current_style.text_dirty = true;
}
}
to_return->m_text_line = m_text_line.mid(start_index, m_width);
m_text_line.remove(start_index, m_width);
return to_return;
}
void Block::removeLine(int line)
{
if (line >= lineCount())
return;
m_changed = true;
int start_index = line * m_width;
int end_index = start_index + (m_width - 1);
for (int i = 0; i < m_style_list.size(); i++) {
ensureStyleAlignWithLines(i);
TextStyleLine &current_style = m_style_list[i];
if (current_style.start_index >= start_index && current_style.end_index <= end_index) {
current_style.releaseTextSegment(m_screen);
m_style_list.remove(i);
i--;
} else if (current_style.start_index > end_index) {
current_style.start_index -= (end_index + 1) - start_index;
current_style.end_index -= (end_index + 1) - start_index;
current_style.index_dirty = true;
current_style.text_dirty = true;
}
}
m_text_line.remove(start_index, m_width);
}
void Block::moveLinesFromBlock(Block *block, int start_line, int count)
{
Q_ASSERT(block);
Q_ASSERT(block->lineCount() >= start_line + count);
int start_char = block->width() * start_line;
int end_char = (block->width() * (start_line + count)) - 1;
for (int i = 0; i < block->m_style_list.size(); i++) {
TextStyleLine &current_style = block->m_style_list[i];
if (current_style.start_index >= start_char && current_style.end_index <= end_char) {
current_style.start_index += (-start_char + m_text_line.size());
current_style.end_index += (-start_char + m_text_line.size());
current_style.releaseTextSegment(m_screen);
m_style_list.append(TextStyleLine(current_style, current_style.start_index,
current_style.end_index));
block->m_style_list.remove(i);
i--;
} else if (current_style.start_index > end_char) {
current_style.start_index -= (end_char + 1) - start_char;
current_style.end_index -= (end_char + 1) - start_char;
current_style.index_dirty = true;
current_style.text_dirty = true;
}
}
m_text_line.append(block->m_text_line.mid(start_char, (end_char + 1) - start_char));
block->m_text_line.remove(start_char, (end_char + 1) - start_char);
m_changed = true;
block->m_changed = true;
}
void Block::dispatchEvents()
{
if (!m_changed) {
return;
}
mergeCompatibleStyles();
for (int i = 0; i < m_style_list.size(); i++) {
ensureStyleAlignWithLines(i);
TextStyleLine &current_style = m_style_list[i];
if (current_style.text_segment == 0) {
current_style.text_segment = m_screen->createTextSegment(current_style);
current_style.text_segment->setLine(m_new_line, m_width, &m_text_line);
} else if (m_new_line != m_line) {
current_style.text_segment->setLine(m_new_line, m_width, &m_text_line);
}
if (current_style.style_dirty) {
current_style.text_segment->setTextStyle(current_style);
current_style.style_dirty = false;
}
if (current_style.index_dirty || current_style.text_dirty) {
current_style.text_segment->setStringSegment(current_style.start_index, current_style.end_index, current_style.text_dirty);
current_style.index_dirty = false;
current_style.text_dirty = false;
}
current_style.text_segment->setLatin(m_only_latin);
current_style.text_segment->dispatchEvents();
}
m_changed = false;
m_line = m_new_line;
}
void Block::releaseTextObjects()
{
m_changed = true;
for (int i = 0; i < m_style_list.size(); i++) {
TextStyleLine &currentStyleLine = m_style_list[i];
currentStyleLine.releaseTextSegment(m_screen);
currentStyleLine.text_dirty = true;
currentStyleLine.style_dirty = true;
}
}
QVector<TextStyleLine> Block::style_list()
{
return m_style_list;
}
void Block::printStyleList() const
{
QDebug debug = qDebug();
printStyleList(debug);
}
void Block::printStyleList(QDebug &debug) const
{
QString text_line = m_text_line;
debug << " " << m_line << lineCount() << m_text_line.size() << (void *) this << text_line << "\n"; debug << "\t";
for (int i= 0; i < m_style_list.size(); i++) {
debug << m_style_list.at(i);
}
}
void Block::printStyleListWidthText() const
{
QString text_line = m_text_line;
for (int i= 0; i < m_style_list.size(); i++) {
const TextStyleLine &currentStyle = m_style_list.at(i);
QDebug debug = qDebug();
debug << m_text_line.mid(currentStyle.start_index, (currentStyle.end_index + 1) - currentStyle.start_index) << currentStyle;
}
}
void Block::mergeCompatibleStyles()
{
for (int i = 1; i < m_style_list.size(); i++) {
TextStyleLine &current = m_style_list[i];
if (m_style_list.at(i - 1).isCompatible(current) &&
current.start_index % m_width != 0) {
TextStyleLine &prev = m_style_list[i-1];
prev.end_index = current.end_index;
prev.text_dirty = true;
current.releaseTextSegment(m_screen);
m_style_list.remove(i);
i--;
}
}
}
void Block::ensureStyleAlignWithLines(int i)
{
int start_line = m_style_list[i].start_index / m_width;
int end_line = m_style_list[i].end_index / m_width;
if (start_line != end_line) {
int remainder_start_line = ((m_width * (start_line + 1))-1) - m_style_list[i].start_index;
int next_line_end_index = m_style_list[i].end_index;
m_style_list[i].end_index = m_style_list[i].start_index + remainder_start_line;
m_style_list.insert(i + 1, TextStyleLine(m_style_list[i], m_style_list[i].end_index + 1, next_line_end_index));
}
}

109
yat/backend/block.h Normal file
View File

@ -0,0 +1,109 @@
/*******************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#ifndef BLOCK_H
#define BLOCK_H
#include <QtCore/QObject>
#include "text_style.h"
class Text;
class Screen;
class Block
{
public:
Block(Screen *screen);
~Block();
Q_INVOKABLE Screen *screen() const;
void clear();
void clearToEnd(int from);
void clearCharacters(int from, int to);
void deleteCharacters(int from, int to);
void deleteToEnd(int from);
void deleteLines(int from);
void replaceAtPos(int i, const QString &text, const TextStyle &style, bool only_latin = true);
void insertAtPos(int i, const QString &text, const TextStyle &style, bool only_latin = true);
void setScreenIndex(int index) { m_screen_index = index; }
int screenIndex() const { return m_screen_index; }
size_t line() { return m_new_line; }
void setLine(size_t line) {
if (line != m_new_line) {
m_changed = true;
m_new_line = line;
}
}
QString *textLine();
int textSize() { return m_text_line.size(); }
int width() const { return m_width; }
void setWidth(int width) { m_changed = true; m_width = width; }
int lineCount() const { return (std::max((m_text_line.size() - 1),0) / m_width) + 1; }
int lineCountAfterModified(int from_char, int text_size, bool replace) {
int new_size = replace ? std::max(from_char + text_size, m_text_line.size())
: std::max(from_char, m_text_line.size()) + text_size;
return ((new_size - 1) / m_width) + 1;
}
void setVisible(bool visible);
bool visible() const;
Block *split(int line);
Block *takeLine(int line);
void removeLine(int line);
void moveLinesFromBlock(Block *block, int start_line, int count);
void dispatchEvents();
void releaseTextObjects();
QVector<TextStyleLine> style_list();
void printStyleList() const;
void printStyleList(QDebug &debug) const;
void printStyleListWidthText() const;
private:
void mergeCompatibleStyles();
void ensureStyleAlignWithLines(int i);
Screen *m_screen;
QString m_text_line;
QVector<TextStyleLine> m_style_list;
size_t m_line;
size_t m_new_line;
int m_screen_index;
int m_width;
bool m_visible;
bool m_changed;
bool m_only_latin;
};
#endif // BLOCK_H

View File

@ -0,0 +1,265 @@
/******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#include <QtCore/QString>
static const QChar dec_special_graphics_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0020,
/*0x60*/ 0x25c6,0x2592,0x2409,0x240c,0x240d,0x240a,0x00b0,0x00b1,
/*0x68*/ 0x2424,0x240b,0x2518,0x2510,0x250c,0x2514,0x253c,0x23ba,
/*0x70*/ 0x23bb,0x2500,0x23bc,0x23bd,0x251c,0x2524,0x2534,0x252c,
/*0x78*/ 0x2502,0x2264,0x2265,0x03c0,0x2260,0x00a3,0x00b7,0x0000,
};
static const QChar nrc_british_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x00a3,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x60*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x78*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
};
static const QChar nrc_norwegian_danish_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x00c4,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x00c6,0x00d8,0x00c5,0x00dc,0x0000,
/*0x60*/ 0x00e4,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x78*/ 0x0000,0x0000,0x0000,0x00e6,0x00f8,0x00e5,0x00fc,0x0000,
};
static const QChar nrc_dutch_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x00a3,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x00be,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x0133,0x00bd,0x007c,0x0000,0x0000,
/*0x60*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x78*/ 0x0000,0x0000,0x0000,0x00a8,0x0066,0x00bc,0x00b4,0x0000,
};
static const QChar nrc_finnish_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x00c4,0x00d6,0x00c5,0x00dc,0x0000,
/*0x60*/ 0x00e9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x78*/ 0x0000,0x0000,0x0000,0x00e4,0x00f6,0x00e5,0x00fc,0x0000,
};
static const QChar nrc_french_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x00a3,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x00e0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x00b0,0x00e7,0x00a7,0x0000,0x0000,
/*0x60*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x78*/ 0x0000,0x0000,0x0000,0x00e9,0x00f9,0x00e8,0x00a8,0x0000,
};
static const QChar nrc_french_canadian_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x00e0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x00e2,0x00e7,0x00ea,0x00ee,0x0000,
/*0x60*/ 0x00f4,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x78*/ 0x0000,0x0000,0x0000,0x00e9,0x00f9,0x00e8,0x00fb,0x0000,
};
static const QChar nrc_german_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x00a7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x00c4,0x00d6,0x00dc,0x0000,0x0000,
/*0x60*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x78*/ 0x0000,0x0000,0x0000,0x00e4,0x00f6,0x00fc,0x00df,0x0000,
};
static const QChar nrc_italian_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x00a3,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x00a7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x00b0,0x00e7,0x00e9,0x0000,0x0000,
/*0x60*/ 0x00f9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x78*/ 0x0000,0x0000,0x0000,0x00e0,0x00f2,0x00e8,0x00ec,0x0000,
};
static const QChar nrc_spanish_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x00a3,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x00a7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x00a1,0x00d1,0x00bf,0x0000,0x0000,
/*0x60*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x78*/ 0x0000,0x0000,0x0000,0x00b0,0x00f1,0x00e7,0x0000,0x0000,
};
static const QChar nrc_swedish_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x00c9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x00c4,0x00d6,0x00c5,0x00dc,0x0000,
/*0x60*/ 0x00e9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x78*/ 0x0000,0x0000,0x0000,0x00e4,0x00f6,0x00e5,0x00fc,0x0000,
};
static const QChar nrc_swiss_char_set[] =
{
/*0x00*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x08*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x10*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x18*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x20*/ 0x0000,0x0000,0x0000,0x00f9,0x0000,0x0000,0x0000,0x0000,
/*0x28*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x30*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x38*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x40*/ 0x00e0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x48*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x50*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x58*/ 0x0000,0x0000,0x0000,0x00e9,0x00e7,0x00ea,0x00ee,0x00e8,
/*0x60*/ 0x00f4,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x68*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x70*/ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
/*0x78*/ 0x0000,0x0000,0x0000,0x00e4,0x00f6,0x00fc,0x00fb,0x0000,
};

View File

@ -0,0 +1,66 @@
#include "color_palette.h"
#include <QDebug>
ColorPalette::ColorPalette(QObject *parent)
: QObject(parent)
, m_normalColors(numberOfColors)
, m_lightColors(numberOfColors)
, m_intenseColors(numberOfColors)
, m_inverse_default(false)
{
m_normalColors[0].setRgb(0,0,0);
m_normalColors[1].setRgb(194,54,33);
m_normalColors[2].setRgb(37,188,36);
m_normalColors[3].setRgb(173,173,39);
m_normalColors[4].setRgb(63,84,255);
m_normalColors[5].setRgb(211,56,211);
m_normalColors[6].setRgb(51,187,199);
m_normalColors[7].setRgb(229,229,229);
m_normalColors[8].setRgb(178,178,178);
m_normalColors[9].setRgb(0,0,0);
m_lightColors[0].setRgb(129,131,131);
m_lightColors[1].setRgb(252,57,31);
m_lightColors[2].setRgb(49,231,34);
m_lightColors[3].setRgb(234,236,35);
m_lightColors[4].setRgb(88,51,255);
m_lightColors[5].setRgb(249,53,248);
m_lightColors[6].setRgb(20,240,240);
m_lightColors[7].setRgb(233,233,233);
m_lightColors[8].setRgb(220,220,220);
m_lightColors[9].setRgb(50,50,50);
}
QColor ColorPalette::color(ColorPalette::Color color, bool bold) const
{
if (m_inverse_default) {
if (color == DefaultForground)
color = DefaultBackground;
else if (color == DefaultBackground)
color = DefaultForground;
}
if (bold)
return m_lightColors.at(color);
return m_normalColors.at(color);
}
QColor ColorPalette::normalColor(ColorPalette::Color color) const
{
return this->color(color, false);
}
QColor ColorPalette::lightColor(ColorPalette::Color color) const
{
return this->color(color,true);
}
void ColorPalette::setInverseDefaultColors(bool inverse)
{
bool emit_changed = inverse != m_inverse_default;
if (emit_changed) {
m_inverse_default = inverse;
emit changed();
}
}

View File

@ -0,0 +1,43 @@
#ifndef COLOR_PALETTE_H
#define COLOR_PALETTE_H
#include <QtCore/QVector>
#include <QtGui/QColor>
class ColorPalette : public QObject
{
Q_OBJECT
public:
ColorPalette(QObject *parent = 0);
enum Color {
Black,
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
DefaultForground,
DefaultBackground,
numberOfColors
};
QColor color(Color color, bool bold) const;
QColor normalColor(Color color) const;
QColor lightColor(Color color) const;
void setInverseDefaultColors(bool inverse);
signals:
void changed();
private:
QVector<QColor> m_normalColors;
QVector<QColor> m_lightColors;
QVector<QColor> m_intenseColors;
bool m_inverse_default;
};
#endif // COLOR_PALETTE_H

View File

@ -0,0 +1,798 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#include "controll_chars.h"
namespace C0 {
QDebug operator<<(QDebug debug, C0 character) {
bool insert_space = debug.autoInsertSpaces();
debug.setAutoInsertSpaces(false);
debug << "C0::";
switch (character) {
case NUL:
debug << "NUL";
break;
case SOH:
debug << "SOH";
break;
case STX:
debug << "STX";
break;
case ETX:
debug << "ETX";
break;
case EOT:
debug << "EOT";
break;
case ENQ:
debug << "ENQ";
break;
case ACK:
debug << "ACK";
break;
case BEL:
debug << "BEL";
break;
case BS:
debug << "BS";
break;
case HT:
debug << "HT";
break;
case LF:
debug << "LF";
break;
case VT:
debug << "VT";
break;
case FF:
debug << "FF";
break;
case CR:
debug << "CR";
break;
case SOorLS1:
debug << "SOorLS1";
break;
case SIorLS0:
debug << "SIorLS0";
break;
case DLE:
debug << "DLE";
break;
case DC1:
debug << "DC1";
break;
case DC2:
debug << "DC2";
break;
case DC3:
debug << "DC3";
break;
case DC4:
debug << "DC4";
break;
case NAK:
debug << "NAK";
break;
case SYN:
debug << "SYN";
break;
case ETB:
debug << "ETB";
break;
case CAN:
debug << "CAN";
break;
case EM:
debug << "EM";
break;
case SUB:
debug << "SUB";
break;
case ESC:
debug << "ESC";
break;
case IS4:
debug << "IS4";
break;
case IS3:
debug << "IS3";
break;
case IS2:
debug << "IS2";
break;
case IS1:
debug << "IS1";
break;
case C0_END:
debug << "C0_END";
break;
default:
debug << qPrintable(QString("0x%1").arg(character,0,16));
break;
}
debug.setAutoInsertSpaces(insert_space);
return debug;
}
}
namespace C1_7bit {
QDebug operator<<(QDebug debug, C1_7bit character) {
bool insert_space = debug.autoInsertSpaces();
debug.setAutoInsertSpaces(false);
debug << "C1_7bit::";
switch(character) {
case ESC:
debug << "ESC";
break;
case SCS_G0:
debug << "SCS_G0";
break;
case SCS_G1:
debug << "SCS_G1";
break;
case SCS_G2:
debug << "SCS_G2";
break;
case SCS_G3:
debug << "SCS_G3";
break;
case DECSC:
debug << "DECSC";
break;
case DECRC:
debug << "DECRC";
break;
case NOT_DEFINED:
debug << "NOT_DEFINED";
break;
case NOT_DEFINED1:
debug << "NOT_DEFINED1";
break;
case BPH:
debug << "BPH";
break;
case NBH:
debug << "NBH";
break;
case IND:
debug << "IND";
break;
case NEL:
debug << "NEL";
break;
case SSA:
debug << "SSA";
break;
case ESA:
debug << "ESA";
break;
case HTS:
debug << "HTS";
break;
case HTJ:
debug << "HTJ";
break;
case VTS:
debug << "VTS";
break;
case PLD:
debug << "PLD";
break;
case PLU:
debug << "PLU";
break;
case RI :
debug << "RI ";
break;
case SS2:
debug << "SS2";
break;
case SS3:
debug << "SS3";
break;
case DCS:
debug << "DCS";
break;
case PU1:
debug << "PU1";
break;
case PU2:
debug << "PU2";
break;
case STS:
debug << "STS";
break;
case CCH:
debug << "CCH";
break;
case MW :
debug << "MW ";
break;
case SPA:
debug << "SPA";
break;
case EPA:
debug << "EPA";
break;
case SOS:
debug << "SOS";
break;
case NOT_DEFINED3:
debug << "NOT_DEFINED3";
break;
case SCI:
debug << "SCI";
break;
case CSI:
debug << "CSI";
break;
case ST :
debug << "ST ";
break;
case OSC:
debug << "OSC";
break;
case PM :
debug << "PM ";
break;
case APC:
debug << "APC";
break;
case C1_7bit_Stop:
debug << "C1_7bit_Stop";
break;
default:
debug << qPrintable(QString("0x%1").arg(character,0,16));
break;
}
debug.setAutoInsertSpaces(insert_space);
return debug;
}
}
namespace C1_8bit {
QDebug operator<<(QDebug debug, C1_8bit character) {
bool insert_space = debug.autoInsertSpaces();
debug.setAutoInsertSpaces(false);
debug << "C1_8bit::";
switch(character) {
case NOT_DEFINED:
debug << "NOT_DEFINED";
break;
case NOT_DEFINED1:
debug << "NOT_DEFINED1";
break;
case BPH:
debug << "BPH";
break;
case NBH:
debug << "NBH";
break;
case NOT_DEFINED2:
debug << "NOT_DEFINED2";
break;
case NEL:
debug << "NEL";
break;
case SSA:
debug << "SSA";
break;
case ESA:
debug << "ESA";
break;
case HTS:
debug << "HTS";
break;
case HTJ:
debug << "HTJ";
break;
case VTS:
debug << "VTS";
break;
case PLD:
debug << "PLD";
break;
case PLU:
debug << "PLU";
break;
case RI :
debug << "RI ";
break;
case SS2:
debug << "SS2";
break;
case SS3:
debug << "SS3";
break;
case DCS:
debug << "DCS";
break;
case PU1:
debug << "PU1";
break;
case PU2C1_7bit:
debug << "PU2C1_7bit";
break;
case STS:
debug << "STS";
break;
case CCH:
debug << "CCH";
break;
case MW :
debug << "MW ";
break;
case SPA:
debug << "SPA";
break;
case EPA:
debug << "EPA";
break;
case SOS:
debug << "SOS";
break;
case NOT_DEFINED3:
debug << "NOT_DEFINED3";
break;
case SCI:
debug << "SCI";
break;
case CSI:
debug << "CSI";
break;
case ST :
debug << "ST ";
break;
case OSC:
debug << "OSC";
break;
case PM :
debug << "PM ";
break;
case APC:
debug << "APC";
break;
case C1_8bit_Stop:
debug << "C1_8bit_Stop";
break;
default:
debug << qPrintable(QString("0x%1").arg(character,0,16));
break;
}
debug.setAutoInsertSpaces(insert_space);
return debug;
}
}
namespace FinalBytesNoIntermediate {
QDebug operator<<(QDebug debug, FinalBytesNoIntermediate character) {
bool insert_space = debug.autoInsertSpaces();
debug.setAutoInsertSpaces(false);
debug << "FinalBytesNoIntermediate::";
switch(character) {
case ICH:
debug << "ICH";
break;
case CUU:
debug << "CUU";
break;
case CUD:
debug << "CUD";
break;
case CUF:
debug << "CUF";
break;
case CUB:
debug << "CUB";
break;
case CNL:
debug << "CNL";
break;
case CPL:
debug << "CPL";
break;
case CHA:
debug << "CHA";
break;
case CUP:
debug << "CUP";
break;
case CHT:
debug << "CHT";
break;
case ED:
debug << "ED";
break;
case EL:
debug << "EL";
break;
case IL:
debug << "IL";
break;
case DL:
debug << "DL";
break;
case EF:
debug << "EF";
break;
case EA:
debug << "EA";
break;
case DCH:
debug << "DCH";
break;
case SSE:
debug << "SSE";
break;
case CPR:
debug << "CPR";
break;
case SU:
debug << "SU";
break;
case SD:
debug << "SD";
break;
case NP:
debug << "NP";
break;
case PP:
debug << "PP";
break;
case CTC:
debug << "CTC";
break;
case ECH:
debug << "ECH";
break;
case CVT:
debug << "CVT";
break;
case CBT:
debug << "CBT";
break;
case SRS:
debug << "SRS";
break;
case PTX:
debug << "PTX";
break;
case SDS:
debug << "SDS";
break;
case SIMD:
debug << "SIMD";
break;
case NOT_DEFINED:
debug << "NOT_DEFINED";
break;
case HPA:
debug << "HPA";
break;
case HPR:
debug << "HPR";
break;
case REP:
debug << "REP";
break;
case DA:
debug << "DA";
break;
case VPA:
debug << "VPA";
break;
case VPR:
debug << "VPR";
break;
case HVP:
debug << "HVP";
break;
case TBC:
debug << "TBC";
break;
case SM:
debug << "SM";
break;
case MC:
debug << "MC";
break;
case HPB:
debug << "HPB";
break;
case VPB:
debug << "VPB";
break;
case RM:
debug << "RM";
break;
case SGR:
debug << "SGR";
break;
case DSR:
debug << "DSR";
break;
case DAQ:
debug << "DAQ";
break;
case Reserved0:
debug << "Reserved0";
break;
case Reserved1:
debug << "Reserved1";
break;
case DECSTBM:
debug << "DECSTBM";
break;
case Reserved3:
debug << "Reserved3";
break;
case Reserved4:
debug << "Reserved4";
break;
case Reserved5:
debug << "Reserved5";
break;
case Reserved6:
debug << "Reserved6";
break;
case Reserved7:
debug << "Reserved7";
break;
case Reserved8:
debug << "Reserved8";
break;
case Reserved9:
debug << "Reserved9";
break;
case Reserveda:
debug << "Reserveda";
break;
case Reservedb:
debug << "Reservedb";
break;
case Reservedc:
debug << "Reservedc";
break;
case Reservedd:
debug << "Reservedd";
break;
case Reservede:
debug << "Reservede";
break;
case Reservedf:
debug << "Reservedf";
break;
default:
debug << qPrintable(QString("0x%1").arg(character,0,16));
break;
}
debug.setAutoInsertSpaces(insert_space);
return debug;
}
}
namespace FinalBytesSingleIntermediate {
QDebug operator<<(QDebug debug, FinalBytesSingleIntermediate character)
{
bool insert_space = debug.autoInsertSpaces();
debug.setAutoInsertSpaces(false);
debug << "FinalBytesSingleIntermediate::";
switch(character) {
case SL:
debug << "SL";
break;
case SR:
debug << "SR";
break;
case GSM:
debug << "GSM";
break;
case GSS:
debug << "GSS";
break;
case FNT:
debug << "FNT";
break;
case TSS:
debug << "TSS";
break;
case JFY:
debug << "JFY";
break;
case SPI:
debug << "SPI";
break;
case QUAD:
debug << "QUAD";
break;
case SSU:
debug << "SSU";
break;
case PFS:
debug << "PFS";
break;
case SHS:
debug << "SHS";
break;
case SVS:
debug << "SVS";
break;
case IGS:
debug << "IGS";
break;
case NOT_DEFINED:
debug << "NOT_DEFINED";
break;
case IDCS:
debug << "IDCS";
break;
case PPA:
debug << "PPA";
break;
case PPR:
debug << "PPR";
break;
case PPB:
debug << "PPB";
break;
case SPD:
debug << "SPD";
break;
case DTA:
debug << "DTA";
break;
case SHL:
debug << "SHL";
break;
case SLL:
debug << "SLL";
break;
case FNK:
debug << "FNK";
break;
case SPQR:
debug << "SPQR";
break;
case SEF:
debug << "SEF";
break;
case PEC:
debug << "PEC";
break;
case SSW:
debug << "SSW";
break;
case SACS:
debug << "SACS";
break;
case SAPV:
debug << "SAPV";
break;
case STAB:
debug << "STAB";
break;
case GCC:
debug << "GCC";
break;
case TATE:
debug << "TATE";
break;
case TALE:
debug << "TALE";
break;
case TAC:
debug << "TAC";
break;
case TCC:
debug << "TCC";
break;
case TSR:
debug << "TSR";
break;
case SCO:
debug << "SCO";
break;
case SRCS:
debug << "SRCS";
break;
case SCS:
debug << "SCS";
break;
case SLS:
debug << "SLS";
break;
case NOT_DEFINED2:
debug << "NOT_DEFINED2";
break;
case NOT_DEFINED3:
debug << "NOT_DEFINED3";
break;
case SCP:
debug << "SCP";
break;
case NOT_DEFINED4:
debug << "NOT_DEFINED4";
break;
case NOT_DEFINED5:
debug << "NOT_DEFINED5";
break;
case NOT_DEFINED6:
debug << "NOT_DEFINED6";
break;
case NOT_DEFINED7:
debug << "NOT_DEFINED7";
break;
case Reserved0:
debug << "Reserved0";
break;
case Reserved1:
debug << "Reserved1";
break;
case Reserved2:
debug << "Reserved2";
break;
case Reserved3:
debug << "Reserved3";
break;
case Reserved4:
debug << "Reserved4";
break;
case Reserved5:
debug << "Reserved5";
break;
case Reserved6:
debug << "Reserved6";
break;
case Reserved7:
debug << "Reserved7";
break;
case Reserved8:
debug << "Reserved8";
break;
case Reserved9:
debug << "Reserved9";
break;
case Reserveda:
debug << "Reserveda";
break;
case Reservedb:
debug << "Reservedb";
break;
case Reservedc:
debug << "Reservedc";
break;
case Reservedd:
debug << "Reservedd";
break;
case Reservedf:
debug << "Reservedf";
break;
default:
debug << qPrintable(QString("0x%1").arg(character,0,16));
break;
}
debug.setAutoInsertSpaces(insert_space);
return debug;
}
}

View File

@ -0,0 +1,299 @@
/******************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#ifndef CONTROLL_CHARS_H
#define CONTROLL_CHARS_H
//This is taken largely from Standard ECMA-48
//http://www.ecma-international.org/publications/standards/Ecma-048.htm
//Also to heres a few handy references
//http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
//http://www.vt100.net/docs/vt100-ug/chapter3.html
#include <QtCore/QDebug>
namespace C0 {
enum C0 {
NUL = 0x00,
SOH = 0x01,
STX = 0x02,
ETX = 0x03,
EOT = 0x04,
ENQ = 0x05,
ACK = 0x06,
BEL = 0x07,
BS = 0x08,
HT = 0x09,
LF = 0x0a,
VT = 0x0b,
FF = 0x0c,
CR = 0x0d,
SOorLS1 = 0x0e,
SIorLS0 = 0x0f,
DLE = 0x10,
DC1 = 0x11,
DC2 = 0x12,
DC3 = 0x13,
DC4 = 0x14,
NAK = 0x15,
SYN = 0x16,
ETB = 0x17,
CAN = 0x18,
EM = 0x19,
SUB = 0x1a,
ESC = 0x1b,
IS4 = 0x1c,
IS3 = 0x1d,
IS2 = 0x1e,
IS1 = 0x1f,
C0_END = 0x20
};
QDebug operator<<(QDebug debug, C0 character);
}
namespace C1_7bit {
enum C1_7bit {
C1_7bit_Start = 0x1b,
ESC = 0x1b,
SCS_G0 = 0x28,
SCS_G1 = 0x29,
SCS_G2 = 0x2a,
SCS_G3 = 0x2b,
DECSC = 0x37,
DECRC = 0x38,
NOT_DEFINED = 0x40,
NOT_DEFINED1 = 0x41,
BPH = 0x42,
NBH = 0x43,
IND = 0x44,
NEL = 0x45,
SSA = 0x46,
ESA = 0x47,
HTS = 0x48,
HTJ = 0x49,
VTS = 0x4a,
PLD = 0x4b,
PLU = 0x4c,
RI = 0x4d,
SS2 = 0x4e,
SS3 = 0x4f,
DCS = 0x50,
PU1 = 0x51,
PU2 = 0x52,
STS = 0x53,
CCH = 0x54,
MW = 0x55,
SPA = 0x56,
EPA = 0x57,
SOS = 0x58,
NOT_DEFINED3 = 0x59,
SCI = 0x5a,
CSI = 0x5b,
ST = 0x5c,
OSC = 0x5d,
PM = 0x5e,
APC = 0x5f,
C1_7bit_Stop = 0x60
};
QDebug operator<<(QDebug debug, C1_7bit character);
}
namespace C1_8bit {
enum C1_8bit {
C1_8bit_Start = 0x80,
NOT_DEFINED = C1_8bit_Start,
NOT_DEFINED1 = 0x81,
BPH = 0x82,
NBH = 0x83,
NOT_DEFINED2 = 0x84,
NEL = 0x85,
SSA = 0x86,
ESA = 0x87,
HTS = 0x88,
HTJ = 0x89,
VTS = 0x8a,
PLD = 0x8b,
PLU = 0x8c,
RI = 0x8d,
SS2 = 0x8e,
SS3 = 0x8f,
DCS = 0x90,
PU1 = 0x91,
PU2C1_7bit = 0x92,
STS = 0x93,
CCH = 0x94,
MW = 0x95,
SPA = 0x96,
EPA = 0x97,
SOS = 0x98,
NOT_DEFINED3 = 0x99,
SCI = 0x9a,
CSI = 0x9b,
ST = 0x9c,
OSC = 0x9d,
PM = 0x9e,
APC = 0x9f,
C1_8bit_Stop = 0xa0
};
QDebug operator<<(QDebug debug, C1_8bit character);
}
namespace FinalBytesNoIntermediate {
enum FinalBytesNoIntermediate {
ICH = 0x40,
CUU = 0x41,
CUD = 0x42,
CUF = 0x43,
CUB = 0x44,
CNL = 0x45,
CPL = 0x46,
CHA = 0x47,
CUP = 0x48,
CHT = 0x49,
ED = 0x4a,
EL = 0x4b,
IL = 0x4c,
DL = 0x4d,
EF = 0x4e,
EA = 0x4f,
DCH = 0x50,
SSE = 0x51,
CPR = 0x52,
SU = 0x53,
SD = 0x54,
NP = 0x55,
PP = 0x56,
CTC = 0x57,
ECH = 0x58,
CVT = 0x59,
CBT = 0x5a,
SRS = 0x5b,
PTX = 0x5c,
SDS = 0x5d,
SIMD = 0x5e,
NOT_DEFINED = 0x5f,
HPA = 0x60,
HPR = 0x61,
REP = 0x62,
DA = 0x63,
VPA = 0x64,
VPR = 0x65,
HVP = 0x66,
TBC = 0x67,
SM = 0x68,
MC = 0x69,
HPB = 0x6a,
VPB = 0x6b,
RM = 0x6c,
SGR = 0x6d,
DSR = 0x6e,
DAQ = 0x6f,
Reserved0 = 0x70,
Reserved1 = 0x71,
DECSTBM = 0x72,
Reserved3 = 0x73,
Reserved4 = 0x74,
Reserved5 = 0x75,
Reserved6 = 0x76,
Reserved7 = 0x77,
Reserved8 = 0x78,
Reserved9 = 0x79,
Reserveda = 0x7a,
Reservedb = 0x7b,
Reservedc = 0x7c,
Reservedd = 0x7d,
Reservede = 0x7e,
Reservedf = 0x7f
};
QDebug operator<<(QDebug debug, FinalBytesNoIntermediate character);
}
namespace FinalBytesSingleIntermediate {
enum FinalBytesSingleIntermediate {
SL = 0x40,
SR = 0x41,
GSM = 0x42,
GSS = 0x43,
FNT = 0x44,
TSS = 0x45,
JFY = 0x46,
SPI = 0x47,
QUAD = 0x48,
SSU = 0x49,
PFS = 0x4a,
SHS = 0x4b,
SVS = 0x4c,
IGS = 0x4d,
NOT_DEFINED = 0x4e,
IDCS = 0x4f,
PPA = 0x50,
PPR = 0x51,
PPB = 0x52,
SPD = 0x53,
DTA = 0x54,
SHL = 0x55,
SLL = 0x56,
FNK = 0x57,
SPQR = 0x58,
SEF = 0x59,
PEC = 0x5a,
SSW = 0x5b,
SACS = 0x5c,
SAPV = 0x5d,
STAB = 0x5e,
GCC = 0x5f,
TATE = 0x60,
TALE = 0x61,
TAC = 0x62,
TCC = 0x63,
TSR = 0x64,
SCO = 0x65,
SRCS = 0x66,
SCS = 0x67,
SLS = 0x68,
NOT_DEFINED2 = 0x69,
NOT_DEFINED3 = 0x6a,
SCP = 0x6b,
NOT_DEFINED4 = 0x6c,
NOT_DEFINED5 = 0x6d,
NOT_DEFINED6 = 0x6e,
NOT_DEFINED7 = 0x6f,
Reserved0 = 0x70,
Reserved1 = 0x71,
Reserved2 = 0x72,
Reserved3 = 0x73,
Reserved4 = 0x74,
Reserved5 = 0x75,
Reserved6 = 0x76,
Reserved7 = 0x77,
Reserved8 = 0x78,
Reserved9 = 0x79,
Reserveda = 0x7a,
Reservedb = 0x7b,
Reservedc = 0x7c,
Reservedd = 0x7d,
Reservedf = 0x7f
};
QDebug operator<<(QDebug debug, FinalBytesSingleIntermediate character);
}
#endif // CONTROLL_CHARS_H

542
yat/backend/cursor.cpp Normal file
View File

@ -0,0 +1,542 @@
/******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#include "cursor.h"
#include "block.h"
#include "screen_data.h"
#include <QTextCodec>
Cursor::Cursor(Screen* screen)
: QObject(screen)
, m_screen(screen)
, m_current_text_style(screen->defaultTextStyle())
, m_position(0,0)
, m_new_position(0,0)
, m_document_width(screen->width())
, m_document_height(screen->height())
, m_top_margin(0)
, m_bottom_margin(0)
, m_scroll_margins_set(false)
, m_origin_at_margin(false)
, m_notified(false)
, m_visible(true)
, m_new_visibillity(true)
, m_blinking(false)
, m_new_blinking(false)
, m_wrap_around(true)
, m_content_height_changed(false)
, m_insert_mode(Replace)
{
connect(screen, SIGNAL(widthAboutToChange(int)), this, SLOT(setDocumentWidth(int)));
connect(screen, SIGNAL(heightAboutToChange(int, int, int)), this, SLOT(setDocumentHeight(int, int, int)));
connect(screen, SIGNAL(contentHeightChanged()), this, SLOT(contentHeightChanged()));
m_gl_text_codec = QTextCodec::codecForName("utf-8")->makeDecoder();
m_gr_text_codec = QTextCodec::codecForName("utf-8")->makeDecoder();
for (int i = 0; i < m_document_width; i++) {
if (i % 8 == 0) {
m_tab_stops.append(i);
}
}
}
Cursor::~Cursor()
{
}
void Cursor::setDocumentWidth(int width)
{
if (width > m_document_width) {
for (int i = m_document_width -1; i < width; i++) {
if (i % 8 == 0) {
m_tab_stops.append(i);
}
}
}
m_document_width = width;
if (new_x() >= width) {
new_rx() = width - 1;
notifyChanged();
}
}
void Cursor::setDocumentHeight(int height, int currentCursorBlock, int currentScrollBackHeight)
{
Q_UNUSED(currentCursorBlock);
resetScrollArea();
if (m_document_height > height) {
const int to_remove = m_document_height - height;
const int removeLinesBelowCursor =
std::min(m_document_height - new_y(), to_remove);
const int removeLinesAtTop = to_remove - removeLinesBelowCursor;
if (!removeLinesAtTop) {
new_ry() -= removeLinesAtTop;
notifyChanged();
}
} else {
int height_diff = height - m_document_height;
if (currentScrollBackHeight >= height_diff) {
new_ry() += height_diff;
} else if (currentScrollBackHeight > 0) {
const int move = height_diff - currentScrollBackHeight;
new_ry() += move;
}
}
m_document_height = height;
if (new_y() >= height) {
new_ry() = height - 1;
notifyChanged();
}
if (new_y() <= 0) {
new_ry() = 0;
}
}
bool Cursor::visible() const
{
return m_visible;
}
void Cursor::setVisible(bool visible)
{
m_new_visibillity = visible;
}
bool Cursor::blinking() const
{
return m_blinking;
}
void Cursor::setBlinking(bool blinking)
{
m_new_blinking = blinking;
}
void Cursor::setTextStyle(TextStyle::Style style, bool add)
{
if (add) {
m_current_text_style.style |= style;
} else {
m_current_text_style.style &= !style;
}
}
void Cursor::resetStyle()
{
m_current_text_style.background = ColorPalette::DefaultBackground;
m_current_text_style.forground = ColorPalette::DefaultForground;
m_current_text_style.style = TextStyle::Normal;
}
void Cursor::scrollUp(int lines)
{
if (new_y() < top() || new_y() > bottom())
return;
for (int i = 0; i < lines; i++) {
screen_data()->moveLine(bottom(), top());
}
}
void Cursor::scrollDown(int lines)
{
if (new_y() < top() || new_y() > bottom())
return;
for (int i = 0; i < lines; i++) {
screen_data()->moveLine(top(), bottom());
}
}
void Cursor::setTextCodec(QTextCodec *codec)
{
m_gl_text_codec = codec->makeDecoder();
}
void Cursor::setInsertMode(InsertMode mode)
{
m_insert_mode = mode;
}
TextStyle Cursor::currentTextStyle() const
{
return m_current_text_style;
}
void Cursor::setTextStyleColor(ushort color)
{
Q_ASSERT(color >= 30 && color < 50);
if (color < 38) {
m_current_text_style.forground = ColorPalette::Color(color - 30);
} else if (color == 39) {
m_current_text_style.forground = ColorPalette::DefaultForground;
} else if (color >= 40 && color < 48) {
m_current_text_style.background = ColorPalette::Color(color - 40);
} else if (color == 49) {
m_current_text_style.background = ColorPalette::DefaultBackground;
} else {
qDebug() << "Failed to set color";
}
}
ColorPalette *Cursor::colorPalette() const
{
return m_screen->colorPalette();
}
QPoint Cursor::position() const
{
return m_position;
}
int Cursor::x() const
{
return m_position.x();
}
int Cursor::y() const
{
return (m_screen->currentScreenData()->contentHeight() - m_screen->height()) + m_position.y();
}
void Cursor::moveOrigin()
{
m_new_position = QPoint(0,adjusted_top());
notifyChanged();
}
void Cursor::moveBeginningOfLine()
{
new_rx() = 0;
notifyChanged();
}
void Cursor::moveUp(int lines)
{
int adjusted_new_y = this->adjusted_new_y();
if (!adjusted_new_y || !lines)
return;
if (lines < adjusted_new_y) {
new_ry() -= lines;
} else {
new_ry() = adjusted_top();
}
notifyChanged();
}
void Cursor::moveDown(int lines)
{
int bottom = adjusted_bottom();
if (new_y() == bottom || !lines)
return;
if (new_y() + lines <= bottom) {
new_ry() += lines;
} else {
new_ry() = bottom;
}
notifyChanged();
}
void Cursor::moveLeft(int positions)
{
if (!new_x() || !positions)
return;
if (positions < new_x()) {
new_rx() -= positions;
} else {
new_rx() = 0;
}
notifyChanged();
}
void Cursor::moveRight(int positions)
{
int width = m_screen->width();
if (new_x() == width -1 || !positions)
return;
if (positions < width - new_x()) {
new_rx() += positions;
} else {
new_rx() = width -1;
}
notifyChanged();
}
void Cursor::move(int new_x, int new_y)
{
int width = m_screen->width();
if (m_origin_at_margin) {
new_y += m_top_margin;
}
if (new_x < 0) {
new_x = 0;
} else if (new_x >= width) {
new_x = width - 1;
}
if (new_y < adjusted_top()) {
new_y = adjusted_top();
} else if (new_y > adjusted_bottom()) {
new_y = adjusted_bottom();
}
if (this->new_y() != new_y || this->new_x() != new_x) {
m_new_position = QPoint(new_x, new_y);
notifyChanged();
}
}
void Cursor::moveToLine(int line)
{
const int height = m_screen->height();
if (line < adjusted_top()) {
line = 0;
} else if (line > adjusted_bottom()) {
line = height -1;
}
if (line != new_y()) {
new_rx() = line;
notifyChanged();
}
}
void Cursor::moveToCharacter(int character)
{
const int width = m_screen->width();
if (character < 0) {
character = 1;
} else if (character > width) {
character = width;
}
if (character != new_x()) {
new_rx() = character;
notifyChanged();
}
}
void Cursor::moveToNextTab()
{
for (int i = 0; i < m_tab_stops.size(); i++) {
if (new_x() < m_tab_stops.at(i)) {
moveToCharacter(std::min(m_tab_stops.at(i), m_document_width -1));
return;
}
}
moveToCharacter(m_document_width - 1);
}
void Cursor::setTabStop()
{
int i;
for (i = 0; i < m_tab_stops.size(); i++) {
if (new_x() == m_tab_stops.at(i))
return;
if (new_x() > m_tab_stops.at(i)) {
continue;
} else {
break;
}
}
m_tab_stops.insert(i,new_x());
}
void Cursor::removeTabStop()
{
for (int i = 0; i < m_tab_stops.size(); i++) {
if (new_x() == m_tab_stops.at(i)) {
m_tab_stops.remove(i);
return;
} else if (new_x() < m_tab_stops.at(i)) {
return;
}
}
}
void Cursor::clearTabStops()
{
m_tab_stops.clear();
}
void Cursor::clearToBeginningOfLine()
{
screen_data()->clearToBeginningOfLine(m_new_position);
}
void Cursor::clearToEndOfLine()
{
screen_data()->clearToEndOfLine(m_new_position);
}
void Cursor::clearToBeginningOfScreen()
{
clearToBeginningOfLine();
if (new_y() > 0)
screen_data()->clearToBeginningOfScreen(m_new_position.y()-1);
}
void Cursor::clearToEndOfScreen()
{
clearToEndOfLine();
if (new_y() < m_screen->height() -1) {
screen_data()->clearToEndOfScreen(m_new_position.y()+1);
}
}
void Cursor::clearLine()
{
screen_data()->clearLine(m_new_position);
}
void Cursor::deleteCharacters(int characters)
{
screen_data()->deleteCharacters(m_new_position, new_x() + characters -1);
}
void Cursor::setWrapAround(bool wrap)
{
m_wrap_around = wrap;
}
void Cursor::addAtCursor(const QByteArray &data, bool only_latin)
{
if (m_insert_mode == Replace) {
replaceAtCursor(data, only_latin);
} else {
insertAtCursor(data, only_latin);
}
}
void Cursor::replaceAtCursor(const QByteArray &data, bool only_latin)
{
const QString text = m_gl_text_codec->toUnicode(data);
if (!m_wrap_around && new_x() + text.size() > m_screen->width()) {
const int size = m_document_width - new_x();
QString toBlock = text.mid(0,size);
toBlock.replace(toBlock.size() - 1, 1, text.at(text.size()-1));
screen_data()->replace(m_new_position, toBlock, m_current_text_style, only_latin);
new_rx() += toBlock.size();
} else {
auto diff = screen_data()->replace(m_new_position, text, m_current_text_style, only_latin);
new_rx() += diff.character;
new_ry() += diff.line;
}
if (new_y() >= m_document_height)
new_ry() = m_document_height - 1;
notifyChanged();
}
void Cursor::insertAtCursor(const QByteArray &data, bool only_latin)
{
const QString text = m_gl_text_codec->toUnicode(data);
auto diff = screen_data()->insert(m_new_position, text, m_current_text_style, only_latin);
new_rx() += diff.character;
new_ry() += diff.line;
if (new_y() >= m_document_height)
new_ry() = m_document_height - 1;
if (new_x() >= m_document_width)
new_rx() = m_document_width - 1;
}
void Cursor::lineFeed()
{
if(new_y() >= bottom()) {
screen_data()->insertLine(bottom(), top());
} else {
new_ry()++;
notifyChanged();
}
}
void Cursor::reverseLineFeed()
{
if (new_y() == top()) {
scrollUp(1);
} else {
new_ry()--;
notifyChanged();
}
}
void Cursor::setOriginAtMargin(bool atMargin)
{
m_origin_at_margin = atMargin;
m_new_position = QPoint(0, adjusted_top());
notifyChanged();
}
void Cursor::setScrollArea(int from, int to)
{
m_top_margin = from;
m_bottom_margin = std::min(to,m_document_height -1);
m_scroll_margins_set = true;
}
void Cursor::resetScrollArea()
{
m_top_margin = 0;
m_bottom_margin = 0;
m_scroll_margins_set = false;
}
void Cursor::dispatchEvents()
{
if (m_new_position != m_position|| m_content_height_changed) {
bool emit_x_changed = m_new_position.x() != m_position.x();
bool emit_y_changed = m_new_position.y() != m_position.y();
m_position = m_new_position;
if (emit_x_changed)
emit xChanged();
if (emit_y_changed || m_content_height_changed)
emit yChanged();
}
if (m_new_visibillity != m_visible) {
m_visible = m_new_visibillity;
emit visibilityChanged();
}
if (m_new_blinking != m_blinking) {
m_blinking = m_new_blinking;
emit blinkingChanged();
}
}
void Cursor::contentHeightChanged()
{
m_content_height_changed = true;
}

175
yat/backend/cursor.h Normal file
View File

@ -0,0 +1,175 @@
/******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#ifndef CURSOR_H
#define CURSOR_H
#include "text_style.h"
#include "screen.h"
#include <QtCore/QObject>
class Cursor : public QObject
{
Q_OBJECT
Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibilityChanged)
Q_PROPERTY(bool blinking READ blinking WRITE setBlinking NOTIFY blinkingChanged)
Q_PROPERTY(int x READ x NOTIFY xChanged)
Q_PROPERTY(int y READ y NOTIFY yChanged)
public:
enum InsertMode {
Insert,
Replace
};
Cursor(Screen *screen);
~Cursor();
bool visible() const;
void setVisible(bool visible);
bool blinking() const;
void setBlinking(bool blinking);
void setTextStyle(TextStyle::Style style, bool add = true);
void resetStyle();
TextStyle currentTextStyle() const;
void setTextStyleColor(ushort color);
ColorPalette *colorPalette() const;
QPoint position() const;
int x() const;
int y() const;
int new_x() const { return m_new_position.x(); }
int new_y() const { return m_new_position.y(); }
void moveOrigin();
void moveBeginningOfLine();
void moveUp(int lines = 1);
void moveDown(int lines = 1);
void moveLeft(int positions = 1);
void moveRight(int positions = 1);
void move(int new_x, int new_y);
void moveToLine(int line);
void moveToCharacter(int character);
void moveToNextTab();
void setTabStop();
void removeTabStop();
void clearTabStops();
void clearToBeginningOfLine();
void clearToEndOfLine();
void clearToBeginningOfScreen();
void clearToEndOfScreen();
void clearLine();
void deleteCharacters(int characters);
void setWrapAround(bool wrap);
void addAtCursor(const QByteArray &text, bool only_latin = true);
void insertAtCursor(const QByteArray &text, bool only_latin = true);
void replaceAtCursor(const QByteArray &text, bool only_latin = true);
void lineFeed();
void reverseLineFeed();
void setOriginAtMargin(bool atMargin);
void setScrollArea(int from, int to);
void resetScrollArea();
void scrollUp(int lines);
void scrollDown(int lines);
void setTextCodec(QTextCodec *codec);
void setInsertMode(InsertMode mode);
inline void notifyChanged();
void dispatchEvents();
public slots:
void setDocumentWidth(int width);
void setDocumentHeight(int height, int currentCursorBlock, int currentScrollBackHeight);
signals:
void xChanged();
void yChanged();
void visibilityChanged();
void blinkingChanged();
private slots:
void contentHeightChanged();
private:
ScreenData *screen_data() const { return m_screen->currentScreenData(); }
int &new_rx() { return m_new_position.rx(); }
int &new_ry() { return m_new_position.ry(); }
int adjusted_new_x() const { return m_origin_at_margin ?
m_new_position.x() - m_top_margin : m_new_position.x(); }
int adjusted_new_y() const { return m_origin_at_margin ?
m_new_position.y() - m_top_margin : m_new_position.y(); }
int adjusted_top() const { return m_origin_at_margin ? m_top_margin : 0; }
int adjusted_bottom() const { return m_origin_at_margin ? m_bottom_margin : m_document_height - 1; }
int top() const { return m_scroll_margins_set ? m_top_margin : 0; }
int bottom() const { return m_scroll_margins_set ? m_bottom_margin : m_document_height - 1; }
Screen *m_screen;
TextStyle m_current_text_style;
QPoint m_position;
QPoint m_new_position;
int m_document_width;
int m_document_height;
int m_top_margin;
int m_bottom_margin;
bool m_scroll_margins_set;
bool m_origin_at_margin;
QVector<int> m_tab_stops;
bool m_notified;
bool m_visible;
bool m_new_visibillity;
bool m_blinking;
bool m_new_blinking;
bool m_wrap_around;
bool m_content_height_changed;
QTextDecoder *m_gl_text_codec;
QTextDecoder *m_gr_text_codec;
InsertMode m_insert_mode;
};
void Cursor::notifyChanged()
{
if (!m_notified) {
m_notified = true;
m_screen->scheduleEventDispatch();
}
}
#endif //CUROSOR_H

32
yat/backend/main.cpp Normal file
View File

@ -0,0 +1,32 @@
/**************************************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
***************************************************************************************************/
#include "terminal_state.h"
#include <QtGui/QGuiApplication>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
TerminalState state;
return app.exec();
}

View File

@ -0,0 +1,124 @@
/******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#include "nrc_text_codec.h"
static bool nrc_text_codec_init = false;
void NrcTextCodec::initialize()
{
if (!nrc_text_codec_init) {
nrc_text_codec_init = true;
new NrcTextCodec("dec_special_graphics", 500001, dec_special_graphics_char_set);
new NrcTextCodec("nrc_british", 500002, nrc_british_char_set);
new NrcTextCodec("nrc_norwegian_danish", 5002, nrc_norwegian_danish_char_set);
new NrcTextCodec("nrc_dutch", 5002, nrc_dutch_char_set);
new NrcTextCodec("nrc_finnish", 5002, nrc_finnish_char_set);
new NrcTextCodec("nrc_french", 5002, nrc_french_char_set);
new NrcTextCodec("nrc_french_canadian", 5002, nrc_french_canadian_char_set);
new NrcTextCodec("nrc_german", 5002, nrc_german_char_set);
new NrcTextCodec("nrc_italian", 5002, nrc_italian_char_set);
new NrcTextCodec("nrc_spanish", 5002, nrc_spanish_char_set);
new NrcTextCodec("nrc_swedish", 5002, nrc_swedish_char_set);
new NrcTextCodec("nrc_swiss", 5002, nrc_swiss_char_set);
}
}
NrcTextCodec::NrcTextCodec(const QByteArray &name, int mib, const QChar character_set[])
: QTextCodec()
, m_name(name)
, m_mib(mib)
, m_character_set(character_set)
{
}
QByteArray NrcTextCodec::name() const
{
return m_name;
}
int NrcTextCodec::mibEnum() const
{
return m_mib;
}
QString NrcTextCodec::convertToUnicode(const char *in, int length, QTextCodec::ConverterState *state) const
{
QString ret_str;
ret_str.reserve(length);
for (int i = 0; i < length; i++) {
uchar in_char = *(in + i);
if (in_char < 128) {
QChar unicode = m_character_set[in_char];
if (unicode.isNull())
unicode = QChar(in_char);
ret_str.append(unicode);
} else {
if (state) {
if (state->flags & QTextCodec::ConvertInvalidToNull) {
state->invalidChars++;
ret_str.append(0);
} else {
state->invalidChars++;
state->remainingChars = length - i;
return ret_str;
}
}
}
}
return ret_str;
}
QByteArray NrcTextCodec::convertFromUnicode(const QChar *in, int length, ConverterState *state) const
{
QByteArray ret_array;
ret_array.reserve(length);
for (int i = 0; i < length; i++) {
QChar out_char = *(in + i);
if (out_char.unicode() < 128) {
uchar out = out_char.unicode();
ret_array.append(out);
} else {
bool found = false;
for (uchar n = 0; n < 128; n++) {
if (m_character_set[n] == out_char) {
ret_array.append(n);
found = true;
break;
}
}
if (!found && state) {
if (state->flags & QTextCodec::ConvertInvalidToNull) {
state->invalidChars++;
ret_array.append(char(0));
} else {
state->invalidChars++;
state->remainingChars = length - i;
return ret_array;
}
}
}
}
return ret_array;
}

View File

@ -0,0 +1,45 @@
/******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#include "character_sets.h"
#include <QtCore/QString>
#include <QtCore/QTextCodec>
class NrcTextCodec : public QTextCodec
{
public:
NrcTextCodec(const QByteArray &name, int mib, const QChar character_set[]);
QByteArray name() const;
int mibEnum() const;
static void initialize();
protected:
QString convertToUnicode(const char *in, int length, ConverterState *state) const;
QByteArray convertFromUnicode(const QChar *in, int length, ConverterState *state) const;
private:
const QByteArray m_name;
const int m_mib;
const QChar *m_character_set;
};

1329
yat/backend/parser.cpp Normal file

File diff suppressed because it is too large Load Diff

110
yat/backend/parser.h Normal file
View File

@ -0,0 +1,110 @@
/*******************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#ifndef PARSER_H
#define PARSER_H
#include <QtCore/QString>
#include <QtCore/QVector>
#include <QtCore/QLinkedList>
#include "controll_chars.h"
#include "utf8_decoder.h"
class Screen;
class Parser
{
public:
Parser(Screen *screen);
void addData(const QByteArray &data);
private:
enum DecodeState {
PlainText,
DecodeC0,
DecodeC1_7bit,
DecodeCSI,
DecodeOSC,
DecodeCharacterSet,
DecodeFontSize
};
enum DecodeOSCState {
None,
ChangeWindowAndIconName,
ChangeIconTitle,
ChangeWindowTitle,
Unknown
};
void decodeC0(uchar character);
void decodeC1_7bit(uchar character);
void decodeParameters(uchar character);
void decodeCSI(uchar character);
void decodeOSC(uchar character);
void decodeCharacterSet(uchar character);
void decodeFontSize(uchar character);
void setMode(int mode);
void setDecMode(int mode);
void resetMode(int mode);
void resetDecMode(int mode);
void handleSGR();
void tokenFinished();
void appendParameter();
void handleDefaultParameters(int defaultValue);
DecodeState m_decode_state;
DecodeOSCState m_decode_osc_state;
QByteArray m_current_data;
int m_current_token_start;
int m_current_position;
QChar m_intermediate_char;
QByteArray m_parameter_string;
QVector<int> m_parameters;
bool m_parameters_expecting_more;
bool m_dec_mode;
bool m_gt_param;
bool m_lnm_mode_set;
bool m_contains_only_latin;
int m_decode_graphics_set;
QTextCodec *m_graphic_codecs[4];
Utf8Decoder m_utf8_decoder;
Screen *m_screen;
friend QDebug operator<<(QDebug debug, DecodeState decodeState);
};
QDebug operator<<(QDebug debug, Parser::DecodeState decodeState);
#endif // PARSER_H

620
yat/backend/screen.cpp Normal file
View File

@ -0,0 +1,620 @@
/******************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
******************************************************************************/
#include "screen.h"
#include "screen_data.h"
#include "block.h"
#include "cursor.h"
#include "text.h"
#include "scrollback.h"
#include "selection.h"
#include "controll_chars.h"
#include "character_sets.h"
#include <QtCore/QTimer>
#include <QtCore/QSocketNotifier>
#include <QtGui/QGuiApplication>
#include <QtCore/QDebug>
#include <float.h>
Screen::Screen(QObject *parent)
: QObject(parent)
, m_palette(new ColorPalette(this))
, m_parser(this)
, m_timer_event_id(0)
, m_width(1)
, m_height(0)
, m_primary_data(new ScreenData(500, this))
, m_alternate_data(new ScreenData(0, this))
, m_current_data(m_primary_data)
, m_old_current_data(m_primary_data)
, m_selection(new Selection(this))
, m_flash(false)
, m_cursor_changed(false)
, m_application_cursor_key_mode(false)
, m_fast_scroll(true)
, m_default_background(m_palette->normalColor(ColorPalette::DefaultBackground))
{
Cursor *cursor = new Cursor(this);
m_cursor_stack << cursor;
m_new_cursors << cursor;
connect(m_primary_data, SIGNAL(contentHeightChanged()), this, SIGNAL(contentHeightChanged()));
connect(m_primary_data, &ScreenData::contentModified,
this, &Screen::contentModified);
connect(m_palette, SIGNAL(changed()), this, SLOT(paletteChanged()));
setHeight(25);
setWidth(80);
connect(&m_pty, &YatPty::readyRead, this, &Screen::readData);
connect(&m_pty, SIGNAL(hangupReceived()),qGuiApp, SLOT(quit()));
}
Screen::~Screen()
{
for(int i = 0; i < m_to_delete.size(); i++) {
delete m_to_delete.at(i);
}
//m_to_delete.clear();
delete m_primary_data;
delete m_alternate_data;
}
QColor Screen::defaultForgroundColor() const
{
return m_palette->normalColor(ColorPalette::DefaultForground);
}
QColor Screen::defaultBackgroundColor() const
{
return m_palette->normalColor(ColorPalette::DefaultBackground);
}
void Screen::emitRequestHeight(int newHeight)
{
emit requestHeightChange(newHeight);
}
void Screen::setHeight(int height)
{
if (height == m_height)
return;
emit heightAboutToChange(height, currentCursor()->new_y(), currentScreenData()->scrollback()->height());
m_height = height;
m_pty.setHeight(height, height * 10);
emit heightChanged();
}
int Screen::height() const
{
return m_height;
}
int Screen::contentHeight() const
{
return currentScreenData()->contentHeight();
}
void Screen::emitRequestWidth(int newWidth)
{
emit requestWidthChange(newWidth);
}
void Screen::setWidth(int width)
{
if (width == m_width)
return;
emit widthAboutToChange(width);
m_width = width;
m_pty.setWidth(width, width * 10);
emit widthChanged();
}
int Screen::width() const
{
return m_width;
}
void Screen::useAlternateScreenBuffer()
{
if (m_current_data == m_primary_data) {
disconnect(m_primary_data, SIGNAL(contentHeightChanged()), this, SIGNAL(contentHeightChanged()));
disconnect(m_primary_data, &ScreenData::contentModified, this, &Screen::contentModified);
m_current_data = m_alternate_data;
m_current_data->clear();
connect(m_alternate_data, SIGNAL(contentHeightChanged()), this, SIGNAL(contentHeightChanged()));
connect(m_primary_data, &ScreenData::contentModified, this, &Screen::contentModified);
emit contentHeightChanged();
}
}
void Screen::useNormalScreenBuffer()
{
if (m_current_data == m_alternate_data) {
disconnect(m_alternate_data, SIGNAL(contentHeightChanged()), this, SIGNAL(contentHeightChanged()));
disconnect(m_alternate_data, &ScreenData::contentModified, this, &Screen::contentModified);
m_current_data = m_primary_data;
connect(m_primary_data, SIGNAL(contentHeightChanged()), this, SIGNAL(contentHeightChanged()));
connect(m_alternate_data, &ScreenData::contentModified, this, &Screen::contentModified);
emit contentHeightChanged();
}
}
TextStyle Screen::defaultTextStyle() const
{
TextStyle style;
style.style = TextStyle::Normal;
style.forground = ColorPalette::DefaultForground;
style.background = ColorPalette::DefaultBackground;
return style;
}
void Screen::saveCursor()
{
Cursor *new_cursor = new Cursor(this);
if (m_cursor_stack.size())
m_cursor_stack.last()->setVisible(false);
m_cursor_stack << new_cursor;
m_new_cursors << new_cursor;
}
void Screen::restoreCursor()
{
if (m_cursor_stack.size() <= 1)
return;
m_delete_cursors.append(m_cursor_stack.takeLast());
m_cursor_stack.last()->setVisible(true);
}
void Screen::clearScreen()
{
currentScreenData()->clear();
}
ColorPalette *Screen::colorPalette() const
{
return m_palette;
}
void Screen::fill(const QChar character)
{
currentScreenData()->fill(character);
}
void Screen::clear()
{
fill(QChar(' '));
}
void Screen::setFastScroll(bool fast)
{
m_fast_scroll = fast;
}
bool Screen::fastScroll() const
{
return m_fast_scroll;
}
Selection *Screen::selection() const
{
return m_selection;
}
void Screen::doubleClicked(const QPointF &clicked)
{
Q_UNUSED(clicked);
//int start, end;
//currentScreenData()->getDoubleClickSelectionArea(clicked, &start, &end);
//setSelectionAreaStart(QPointF(start,clicked.y()));
//setSelectionAreaEnd(QPointF(end,clicked.y()));
}
void Screen::setTitle(const QString &title)
{
m_title = title;
emit screenTitleChanged();
}
QString Screen::title() const
{
return m_title;
}
void Screen::scheduleFlash()
{
m_flash = true;
}
void Screen::printScreen() const
{
currentScreenData()->printStyleInformation();
qDebug() << "Total height: " << currentScreenData()->contentHeight();
}
void Screen::scheduleEventDispatch()
{
if (!m_timer_event_id) {
m_timer_event_id = startTimer(1);
m_time_since_initiated.restart();
}
m_time_since_parsed.restart();
}
void Screen::dispatchChanges()
{
if (m_old_current_data != m_current_data) {
m_old_current_data->releaseTextObjects();
m_old_current_data = m_current_data;
}
currentScreenData()->dispatchLineEvents();
emit dispatchTextSegmentChanges();
static int max_to_delete_size = 0;
if (max_to_delete_size < m_to_delete.size()) {
max_to_delete_size = m_to_delete.size();
qDebug() << "TO DELETE SIZE :" << max_to_delete_size;
}
if (m_flash) {
m_flash = false;
emit flash();
}
for (int i = 0; i < m_delete_cursors.size(); i++) {
int new_index = m_new_cursors.indexOf(m_delete_cursors.at(i));
if (new_index >= 0)
m_new_cursors.remove(new_index);
delete m_delete_cursors.at(i);
}
m_delete_cursors.clear();
for (int i = 0; i < m_new_cursors.size(); i++) {
emit cursorCreated(m_new_cursors.at(i));
}
m_new_cursors.clear();
for (int i = 0; i < m_cursor_stack.size(); i++) {
m_cursor_stack[i]->dispatchEvents();
}
m_selection->dispatchChanges();
}
void Screen::sendPrimaryDA()
{
m_pty.write(QByteArrayLiteral("\033[?6c"));
}
void Screen::sendSecondaryDA()
{
m_pty.write(QByteArrayLiteral("\033[>1;95;0c"));
}
void Screen::setApplicationCursorKeysMode(bool enable)
{
m_application_cursor_key_mode = enable;
}
bool Screen::applicationCursorKeyMode() const
{
return m_application_cursor_key_mode;
}
void Screen::ensureVisiblePages(int top_line)
{
currentScreenData()->ensureVisiblePages(top_line);
}
static bool hasControll(Qt::KeyboardModifiers modifiers)
{
#ifdef Q_OS_MAC
return modifiers & Qt::MetaModifier;
#else
return modifiers & Qt::ControlModifier;
#endif
}
static bool hasMeta(Qt::KeyboardModifiers modifiers)
{
#ifdef Q_OS_MAC
return modifiers & Qt::ControlModifier;
#else
return modifiers & Qt::MetaModifier;
#endif
}
void Screen::sendKey(const QString &text, Qt::Key key, Qt::KeyboardModifiers modifiers)
{
// if (key == Qt::Key_Control)
// printScreen();
/// UGH, this function should be re-written
char escape = '\0';
char control = '\0';
char code = '\0';
QVector<ushort> parameters;
bool found = true;
switch(key) {
case Qt::Key_Up:
escape = C0::ESC;
if (m_application_cursor_key_mode)
control = C1_7bit::SS3;
else
control = C1_7bit::CSI;
code = 'A';
break;
case Qt::Key_Right:
escape = C0::ESC;
if (m_application_cursor_key_mode)
control = C1_7bit::SS3;
else
control = C1_7bit::CSI;
code = 'C';
break;
case Qt::Key_Down:
escape = C0::ESC;
if (m_application_cursor_key_mode)
control = C1_7bit::SS3;
else
control = C1_7bit::CSI;
code = 'B';
break;
case Qt::Key_Left:
escape = C0::ESC;
if (m_application_cursor_key_mode)
control = C1_7bit::SS3;
else
control = C1_7bit::CSI;
code = 'D';
break;
case Qt::Key_Insert:
escape = C0::ESC;
control = C1_7bit::CSI;
parameters.append(2);
code = '~';
break;
case Qt::Key_Delete:
escape = C0::ESC;
control = C1_7bit::CSI;
parameters.append(3);
code = '~';
break;
case Qt::Key_Home:
escape = C0::ESC;
control = C1_7bit::CSI;
parameters.append(1);
code = '~';
break;
case Qt::Key_End:
escape = C0::ESC;
control = C1_7bit::CSI;
parameters.append(4);
code = '~';
break;
case Qt::Key_PageUp:
escape = C0::ESC;
control = C1_7bit::CSI;
parameters.append(5);
code = '~';
break;
case Qt::Key_PageDown:
escape = C0::ESC;
control = C1_7bit::CSI;
parameters.append(6);
code = '~';
break;
case Qt::Key_F1:
case Qt::Key_F2:
case Qt::Key_F3:
case Qt::Key_F4:
if (m_application_cursor_key_mode) {
parameters.append((key & 0xff) - 37);
escape = C0::ESC;
control = C1_7bit::CSI;
code = '~';
}
break;
case Qt::Key_F5:
case Qt::Key_F6:
case Qt::Key_F7:
case Qt::Key_F8:
case Qt::Key_F9:
case Qt::Key_F10:
case Qt::Key_F11:
case Qt::Key_F12:
if (m_application_cursor_key_mode) {
parameters.append((key & 0xff) - 36);
escape = C0::ESC;
control = C1_7bit::CSI;
code = '~';
}
break;
case Qt::Key_Control:
case Qt::Key_Shift:
case Qt::Key_Alt:
case Qt::Key_AltGr:
return;
break;
default:
found = false;
}
if (found) {
int term_mods = 0;
if (modifiers & Qt::ShiftModifier)
term_mods |= 1;
if (modifiers & Qt::AltModifier)
term_mods |= 2;
if (modifiers & Qt::ControlModifier)
term_mods |= 4;
QByteArray toPty;
if (term_mods) {
term_mods++;
parameters.append(term_mods);
}
if (escape)
toPty.append(escape);
if (control)
toPty.append(control);
if (parameters.size()) {
for (int i = 0; i < parameters.size(); i++) {
if (i)
toPty.append(';');
toPty.append(QByteArray::number(parameters.at(i)));
}
}
if (code)
toPty.append(code);
m_pty.write(toPty);
} else {
QString verifiedText = text.simplified();
if (verifiedText.isEmpty()) {
switch (key) {
case Qt::Key_Return:
case Qt::Key_Enter:
verifiedText = "\r";
break;
case Qt::Key_Backspace:
verifiedText = "\010";
break;
case Qt::Key_Tab:
verifiedText = "\t";
break;
case Qt::Key_Control:
case Qt::Key_Meta:
case Qt::Key_Alt:
case Qt::Key_Shift:
return;
case Qt::Key_Space:
verifiedText = " ";
break;
default:
return;
}
}
QByteArray to_pty;
QByteArray key_text;
if (hasControll(modifiers)) {
char key_char = verifiedText.toLocal8Bit().at(0);
key_text.append(key_char & 0x1F);
} else {
key_text = verifiedText.toUtf8();
}
if (modifiers & Qt::AltModifier) {
to_pty.append(C0::ESC);
}
if (hasMeta(modifiers)) {
to_pty.append(C0::ESC);
to_pty.append('@');
to_pty.append(FinalBytesNoIntermediate::Reserved3);
}
to_pty.append(key_text);
m_pty.write(to_pty);
}
}
YatPty *Screen::pty()
{
return &m_pty;
}
Text *Screen::createTextSegment(const TextStyleLine &style_line)
{
Q_UNUSED(style_line);
Text *to_return;
if (m_to_delete.size()) {
to_return = m_to_delete.takeLast();
to_return->setVisible(true);
} else {
to_return = new Text(this);
emit textCreated(to_return);
}
return to_return;
}
void Screen::releaseTextSegment(Text *text)
{
m_to_delete.append(text);
}
void Screen::readData(const QByteArray &data)
{
m_parser.addData(data);
scheduleEventDispatch();
}
void Screen::paletteChanged()
{
QColor new_default = m_palette->normalColor(ColorPalette::DefaultBackground);
if (new_default != m_default_background) {
m_default_background = new_default;
emit defaultBackgroundColorChanged();
}
}
void Screen::timerEvent(QTimerEvent *)
{
if (m_timer_event_id && (m_time_since_parsed.elapsed() > 3 || m_time_since_initiated.elapsed() > 8)) {
killTimer(m_timer_event_id);
m_timer_event_id = 0;
dispatchChanges();
}
}

188
yat/backend/screen.h Normal file
View File

@ -0,0 +1,188 @@
/*******************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#ifndef TERMINALSCREEN_H
#define TERMINALSCREEN_H
#include <QObject>
#include "color_palette.h"
#include "parser.h"
#include "yat_pty.h"
#include "text_style.h"
#include <QtCore/QPoint>
#include <QtCore/QSize>
#include <QtCore/QStack>
#include <QtCore/QElapsedTimer>
class Block;
class Cursor;
class Text;
class ScreenData;
class Selection;
class Screen : public QObject
{
Q_OBJECT
Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged)
Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
Q_PROPERTY(int contentHeight READ contentHeight NOTIFY contentHeightChanged)
Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY screenTitleChanged)
Q_PROPERTY(Selection *selection READ selection CONSTANT)
Q_PROPERTY(QColor defaultBackgroundColor READ defaultBackgroundColor NOTIFY defaultBackgroundColorChanged)
public:
explicit Screen(QObject *parent = 0);
~Screen();
void emitRequestHeight(int newHeight);
void setHeight(int height);
int height() const;
int contentHeight() const;
void emitRequestWidth(int newWidth);
void setWidth(int width);
int width() const;
ScreenData *currentScreenData() const { return m_current_data; }
void useAlternateScreenBuffer();
void useNormalScreenBuffer();
Cursor *currentCursor() const { return m_cursor_stack.last(); }
void saveCursor();
void restoreCursor();
TextStyle defaultTextStyle() const;
QColor defaultForgroundColor() const;
QColor defaultBackgroundColor() const;
ColorPalette *colorPalette() const;
void clearScreen();
void fill(const QChar character);
void clear();
void setFastScroll(bool fast);
bool fastScroll() const;
Selection *selection() const;
Q_INVOKABLE void doubleClicked(const QPointF &clicked);
void setTitle(const QString &title);
QString title() const;
void scheduleFlash();
Q_INVOKABLE void printScreen() const;
void scheduleEventDispatch();
void dispatchChanges();
void sendPrimaryDA();
void sendSecondaryDA();
void setApplicationCursorKeysMode(bool enable);
bool applicationCursorKeyMode() const;
Q_INVOKABLE void sendKey(const QString &text, Qt::Key key, Qt::KeyboardModifiers modifiers);
YatPty *pty();
Q_INVOKABLE void ensureVisiblePages(int top_line);
Text *createTextSegment(const TextStyleLine &style_line);
void releaseTextSegment(Text *text);
public slots:
void readData(const QByteArray &data);
void paletteChanged();
signals:
void reset();
void flash();
void dispatchLineChanges();
void dispatchTextSegmentChanges();
void screenTitleChanged();
void textCreated(Text *text);
void cursorCreated(Cursor *cursor);
void requestHeightChange(int newHeight);
void heightAboutToChange(int height, int currentCursorLine, int currentScrollBackHeight);
void heightChanged();
void contentHeightChanged();
void requestWidthChange(int newWidth);
void widthAboutToChange(int width);
void widthChanged();
void defaultBackgroundColorChanged();
void contentModified(size_t lineModified, int lineDiff, int contentDiff);
protected:
void timerEvent(QTimerEvent *);
private:
ColorPalette *m_palette;
YatPty m_pty;
Parser m_parser;
QElapsedTimer m_time_since_parsed;
QElapsedTimer m_time_since_initiated;
int m_timer_event_id;
int m_width;
int m_height;
ScreenData *m_primary_data;
ScreenData *m_alternate_data;
ScreenData *m_current_data;
ScreenData *m_old_current_data;
QVector<Cursor *> m_cursor_stack;
QVector<Cursor *> m_new_cursors;
QVector<Cursor *> m_delete_cursors;
QString m_title;
Selection *m_selection;
bool m_flash;
bool m_cursor_changed;
bool m_application_cursor_key_mode;
bool m_fast_scroll;
QVector<Text *> m_to_delete;
QColor m_default_background;
friend class ScreenData;
};
#endif // TERMINALSCREEN_H

530
yat/backend/screen_data.cpp Normal file
View File

@ -0,0 +1,530 @@
/*******************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#include "screen_data.h"
#include "block.h"
#include "screen.h"
#include "scrollback.h"
#include "cursor.h"
#include <stdio.h>
#include <QtGui/QGuiApplication>
#include <QtCore/QDebug>
ScreenData::ScreenData(size_t max_scrollback, Screen *screen)
: QObject(screen)
, m_screen(screen)
, m_scrollback(new Scrollback(max_scrollback, this))
, m_screen_height(0)
, m_height(0)
, m_width(0)
, m_block_count(0)
, m_old_total_lines(0)
{
connect(screen, SIGNAL(heightAboutToChange(int, int, int)), this, SLOT(setHeight(int, int, int)));
connect(screen, SIGNAL(widthAboutToChange(int)), this, SLOT(setWidth(int)));
}
ScreenData::~ScreenData()
{
for (auto it = m_screen_blocks.begin(); it != m_screen_blocks.end(); ++it) {
delete *it;
}
delete m_scrollback;
}
int ScreenData::contentHeight() const
{
return m_height + m_scrollback->height();
}
void ScreenData::setHeight(int height, int currentCursorLine, int currentContentHeight)
{
Q_UNUSED(currentContentHeight);
m_screen_height = height;
if (height == m_height)
return;
if (m_height > height) {
const int to_remove = m_height - height;
const int remove_from_end = std::min((m_height -1) - currentCursorLine, to_remove);
const int remove_from_start = to_remove - remove_from_end;
if (remove_from_end) {
remove_lines_from_end(remove_from_end);
}
if (remove_from_start) {
push_at_most_to_scrollback(remove_from_start);
}
} else {
ensure_at_least_height(height);
}
}
void ScreenData::setWidth(int width)
{
m_width = width;
for (Block *block : m_screen_blocks) {
int before_count = block->lineCount();
block->setWidth(width);
m_height += block->lineCount() - before_count;
}
if (m_height > m_screen_height) {
push_at_most_to_scrollback(m_height - m_screen_height);
} else {
ensure_at_least_height(m_screen_height);
}
m_scrollback->setWidth(width);
}
void ScreenData::clearToEndOfLine(const QPoint &point)
{
auto it = it_for_row_ensure_single_line_block(point.y());
(*it)->clearToEnd(point.x());
}
void ScreenData::clearToEndOfScreen(int y)
{
auto it = it_for_row_ensure_single_line_block(y);
while(it != m_screen_blocks.end()) {
clearBlock(it);
++it;
}
}
void ScreenData::clearToBeginningOfLine(const QPoint &point)
{
auto it = it_for_row_ensure_single_line_block(point.y());
(*it)->clearCharacters(0,point.x());
}
void ScreenData::clearToBeginningOfScreen(int y)
{
auto it = it_for_row_ensure_single_line_block(y);
if (it != m_screen_blocks.end())
(*it)->clear();
while(it != m_screen_blocks.begin()) {
--it;
clearBlock(it);
}
}
void ScreenData::clearLine(const QPoint &point)
{
(*it_for_row_ensure_single_line_block(point.y()))->clear();
}
void ScreenData::clear()
{
for (auto it = m_screen_blocks.begin(); it != m_screen_blocks.end(); ++it) {
clearBlock(it);
}
}
void ScreenData::releaseTextObjects()
{
for (auto it = m_screen_blocks.begin(); it != m_screen_blocks.end(); ++it) {
(*it)->releaseTextObjects();
}
}
void ScreenData::clearCharacters(const QPoint &point, int to)
{
auto it = it_for_row_ensure_single_line_block(point.y());
(*it)->clearCharacters(point.x(),to);
}
void ScreenData::deleteCharacters(const QPoint &point, int to)
{
auto it = it_for_row(point.y());
if (it == m_screen_blocks.end())
return;
int line_in_block = point.y() - (*it)->screenIndex();
int chars_to_line = line_in_block * m_width;
(*it)->deleteCharacters(chars_to_line + point.x(), chars_to_line + to);
}
CursorDiff ScreenData::replace(const QPoint &point, const QString &text, const TextStyle &style, bool only_latin)
{
return modify(point,text,style,true, only_latin);
}
CursorDiff ScreenData::insert(const QPoint &point, const QString &text, const TextStyle &style, bool only_latin)
{
return modify(point,text,style,false, only_latin);
}
void ScreenData::moveLine(int from, int to)
{
if (from == to)
return;
const size_t old_content_height = contentHeight();
const int orig_to = to;
if (to > from)
to++;
auto from_it = it_for_row_ensure_single_line_block(from);
auto to_it = it_for_row_ensure_single_line_block(to);
(*from_it)->clear();
m_screen_blocks.splice(to_it, m_screen_blocks, from_it);
qDebug() << Q_FUNC_INFO << to;
emit contentModified(m_scrollback->height() + to, 1, content_height_diff(old_content_height));
}
void ScreenData::insertLine(int row, int topMargin)
{
auto row_it = it_for_row(row + 1);
const size_t old_content_height = contentHeight();
if (!topMargin && m_height >= m_screen_height) {
push_at_most_to_scrollback(1);
} else {
auto row_top_margin = it_for_row_ensure_single_line_block(topMargin);
if (row == topMargin) {
(*row_top_margin)->clear();
return;
}
delete (*row_top_margin);
m_screen_blocks.erase(row_top_margin);
m_height--;
m_block_count--;
}
Block *block_to_insert = new Block(m_screen);
m_screen_blocks.insert(row_it,block_to_insert);
m_height++;
m_block_count++;
emit contentModified(m_scrollback->height() + row + 1, 1, content_height_diff(old_content_height));
}
void ScreenData::fill(const QChar &character)
{
clear();
auto it = --m_screen_blocks.end();
for (int i = 0; i < m_block_count; --it, i++) {
QString fill_str(m_screen->width(), character);
(*it)->replaceAtPos(0, fill_str, m_screen->defaultTextStyle());
}
}
void ScreenData::dispatchLineEvents()
{
if (!m_block_count)
return;
const int scrollback_height = m_scrollback->height();
int i = 0;
for (auto it = m_screen_blocks.begin(); it != m_screen_blocks.end(); ++it) {
int line = scrollback_height + i;
(*it)->setLine(line);
//(*it)->setScreenIndex(i);
(*it)->dispatchEvents();
i+= (*it)->lineCount();
}
if (contentHeight() != m_old_total_lines) {
m_old_total_lines = contentHeight();
emit contentHeightChanged();
}
}
void ScreenData::printRuler(QDebug &debug) const
{
QString ruler = QString("|----i----").repeated((m_width/10)+1).append("|");
debug << " " << (void *) this << ruler;
}
void ScreenData::printStyleInformation() const
{
auto it = m_screen_blocks.end();
std::advance(it, -m_block_count);
for (int i = 0; it != m_screen_blocks.end(); ++it, i++) {
if (i % 5 == 0) {
QDebug debug = qDebug();
debug << "Ruler:";
printRuler(debug);
}
QDebug debug = qDebug();
(*it)->printStyleList(debug);
}
qDebug() << "On screen height" << m_height;
}
Screen *ScreenData::screen() const
{
return m_screen;
}
void ScreenData::ensureVisiblePages(int top_line)
{
m_scrollback->ensureVisiblePages(top_line);
}
Scrollback *ScreenData::scrollback() const
{
return m_scrollback;
}
void ScreenData::sendSelectionToClipboard(const QPoint &start, const QPoint &end, QClipboard::Mode mode)
{
if (start.y() < 0)
return;
if (end.y() >= contentHeight())
return;
QString to_clip_board_buffer;
bool started_in_scrollback = false;
if (size_t(start.y()) < m_scrollback->height()) {
started_in_scrollback = true;
QPoint end_scrollback = end;
if (size_t(end.y()) >= m_scrollback->height()) {
end_scrollback = QPoint(m_width, m_scrollback->height() - 1);
}
to_clip_board_buffer = m_scrollback->selection(start, end_scrollback);
}
if (size_t(end.y()) >= m_scrollback->height()) {
QPoint start_in_screen;
if (started_in_scrollback) {
start_in_screen = QPoint(0,0);
} else {
start_in_screen = start;
start_in_screen.ry() -= m_scrollback->height();
}
QPoint end_in_screen = end;
end_in_screen.ry() -= m_scrollback->height();
auto it = it_for_row(start_in_screen.y());
size_t screen_index = (*it)->screenIndex();
int start_pos = (start_in_screen.y() - (*it)->screenIndex()) * m_width + start.x();
for (; it != m_screen_blocks.end(); ++it, start_pos = 0) {
int end_pos = (*it)->textSize();
bool should_break = false;
if (size_t(screen_index + (*it)->lineCount()) > size_t(end_in_screen.y())) {
end_pos = (end_in_screen.y() - screen_index) * m_width + end_in_screen.x();
should_break = true;
}
if (to_clip_board_buffer.size())
to_clip_board_buffer += '\n';
to_clip_board_buffer += (*it)->textLine()->mid(start_pos, end_pos - start_pos);
if (should_break)
break;
screen_index += (*it)->lineCount();
}
}
QGuiApplication::clipboard()->setText(to_clip_board_buffer, mode);
}
CursorDiff ScreenData::modify(const QPoint &point, const QString &text, const TextStyle &style, bool replace, bool only_latin)
{
auto it = it_for_row(point.y());
Block *block = *it;
const int start_char = (point.y() - block->screenIndex()) * m_width + point.x();
const size_t lines_before = block->lineCount();
const int lines_changed =
block->lineCountAfterModified(start_char, text.size(), replace) - lines_before;
const size_t old_content_height = contentHeight();
m_height += lines_changed;
if (lines_changed > 0) {
int removed = 0;
auto to_merge_inn = it;
++to_merge_inn;
while(removed < lines_changed && to_merge_inn != m_screen_blocks.end()) {
Block *to_be_reduced = *to_merge_inn;
bool remove_block = removed + to_be_reduced->lineCount() <= lines_changed;
int lines_to_remove = remove_block ? to_be_reduced->lineCount() : to_be_reduced->lineCount() - (lines_changed - removed);
block->moveLinesFromBlock(to_be_reduced, 0, lines_to_remove);
removed += lines_to_remove;
if (remove_block) {
delete to_be_reduced;
to_merge_inn = m_screen_blocks.erase(to_merge_inn);
m_block_count--;
} else {
++to_merge_inn;
}
}
m_height -= removed;
}
if (m_height > m_screen_height)
push_at_most_to_scrollback(m_height - m_screen_height);
if (replace) {
block->replaceAtPos(start_char, text, style, only_latin);
} else {
block->insertAtPos(start_char, text, style, only_latin);
}
int end_char = (start_char + text.size()) % m_width;
if (end_char == 0)
end_char = m_width -1;
emit contentModified(m_scrollback->height() + point.y(), lines_changed, content_height_diff(old_content_height));
return { lines_changed, end_char - point.x()};
}
void ScreenData::clearBlock(std::list<Block *>::iterator line)
{
int before_count = (*line)->lineCount();
(*line)->clear();
int diff_line = before_count - (*line)->lineCount();
if (diff_line > 0) {
++line;
for (int i = 0; i < diff_line; i++) {
m_screen_blocks.insert(line, new Block(m_screen));
}
m_block_count+=diff_line;
}
}
std::list<Block *>::iterator ScreenData::it_for_row_ensure_single_line_block(int row)
{
auto it = it_for_row(row);
const int index = (*it)->screenIndex();
const int lines = (*it)->lineCount();
if (index == row && lines == 1) {
return it;
}
int line_diff = row - index;
return split_out_row_from_block(it, line_diff);
}
std::list<Block *>::iterator ScreenData::split_out_row_from_block(std::list<Block *>::iterator it, int row_in_block)
{
int lines = (*it)->lineCount();
if (row_in_block == 0 && lines == 1)
return it;
if (row_in_block == 0) {
auto insert_before = (*it)->takeLine(0);
insert_before->setScreenIndex(row_in_block);
m_block_count++;
return m_screen_blocks.insert(it,insert_before);
} else if (row_in_block == lines -1) {
auto insert_after = (*it)->takeLine(lines -1);
insert_after->setScreenIndex(row_in_block);
++it;
m_block_count++;
return m_screen_blocks.insert(it, insert_after);
}
auto half = (*it)->split(row_in_block);
++it;
auto it_width_first = m_screen_blocks.insert(it, half);
auto the_one = half->takeLine(0);
m_block_count+=2;
return m_screen_blocks.insert(it_width_first,the_one);
}
void ScreenData::push_at_most_to_scrollback(int lines)
{
int pushed = 0;
auto it = m_screen_blocks.begin();
while (it != m_screen_blocks.end() && pushed + (*it)->lineCount() <= lines) {
m_block_count--;
const int block_height = (*it)->lineCount();
m_height -= block_height;
pushed += block_height;
m_scrollback->addBlock(*it);
it = m_screen_blocks.erase(it);
}
}
void ScreenData::reclaim_at_least(int lines)
{
int lines_reclaimed = 0;
while (m_scrollback->blockCount() && lines_reclaimed < lines) {
Block *block = m_scrollback->reclaimBlock();
m_height += block->lineCount();
lines_reclaimed += block->lineCount();
m_block_count++;
m_screen_blocks.push_front(block);
}
}
void ScreenData::remove_lines_from_end(int lines)
{
int removed = 0;
auto it = m_screen_blocks.end();
while (it != m_screen_blocks.begin() && removed < lines) {
--it;
const int block_height = (*it)->lineCount();
if (removed + block_height <= lines) {
removed += block_height;
m_height -= block_height;
m_block_count--;
delete (*it);
it = m_screen_blocks.erase(it);
} else {
const int to_remove = lines - removed;
removed += to_remove;
m_height -= to_remove;
Block *block = *it;
for (int i = 0; i < to_remove; i++) {
block->removeLine(block->lineCount()-1);
}
}
}
}
void ScreenData::ensure_at_least_height(int height)
{
if (m_height > height)
return;
int to_grow = height - m_height;
reclaim_at_least(to_grow);
if (height > m_height) {
int to_insert = height - m_height;
for (int i = 0; i < to_insert; i++) {
m_screen_blocks.push_back(new Block(m_screen));
}
m_height += to_insert;
m_block_count += to_insert;
}
}
int ScreenData::content_height_diff(size_t old_content_height)
{
const size_t content_height = contentHeight();
return old_content_height < content_height ? content_height - old_content_height :
- int(old_content_height - content_height);
}

138
yat/backend/screen_data.h Normal file
View File

@ -0,0 +1,138 @@
/*******************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#ifndef SCREENDATA_H
#define SCREENDATA_H
#include "text_style.h"
#include "block.h"
#include <QtCore/QVector>
#include <QtCore/QPoint>
#include <QtCore/QObject>
#include <QtGui/QClipboard>
#include <QtCore/QDebug>
class Screen;
class Scrollback;
class CursorDiff
{
public:
int line;
int character;
};
class ScreenData : public QObject
{
Q_OBJECT
public:
ScreenData(size_t max_scrollback, Screen *screen);
~ScreenData();
int contentHeight() const;
void clearToEndOfLine(const QPoint &pos);
void clearToEndOfScreen(int y);
void clearToBeginningOfLine(const QPoint &pos);
void clearToBeginningOfScreen(int y);
void clearLine(const QPoint &pos);
void clear();
void releaseTextObjects();
void clearCharacters(const QPoint &pos, int to);
void deleteCharacters(const QPoint &pos, int to);
CursorDiff replace(const QPoint &pos, const QString &text, const TextStyle &style, bool only_latin);
CursorDiff insert(const QPoint &pos, const QString &text, const TextStyle &style, bool only_latin);
void moveLine(int from, int to);
void insertLine(int insertAt, int topMargin);
void fill(const QChar &character);
void dispatchLineEvents();
void printRuler(QDebug &debug) const;
void printStyleInformation() const;
Screen *screen() const;
void ensureVisiblePages(int top_line);
Scrollback *scrollback() const;
void sendSelectionToClipboard(const QPoint &start, const QPoint &end, QClipboard::Mode mode);
inline std::list<Block *>::iterator it_for_row(int row);
public slots:
void setHeight(int height, int currentCursorLine, int currentContentHeight);
void setWidth(int width);
signals:
void contentHeightChanged();
void contentModified(size_t lineModified, int lineDiff, int contentDiff);
private:
CursorDiff modify(const QPoint &pos, const QString &text, const TextStyle &style, bool replace, bool only_latin);
void clearBlock(std::list<Block *>::iterator line);
std::list<Block *>::iterator it_for_row_ensure_single_line_block(int row);
std::list<Block *>::iterator split_out_row_from_block(std::list<Block *>::iterator block_it, int row_in_block);
void push_at_most_to_scrollback(int lines);
void reclaim_at_least(int lines);
void remove_lines_from_end(int lines);
void ensure_at_least_height(int height);
int content_height_diff(size_t old_content_height);
Screen *m_screen;
Scrollback *m_scrollback;
int m_screen_height;
int m_height;
int m_width;
int m_block_count;
int m_old_total_lines;
std::list<Block *> m_screen_blocks;
};
std::list<Block *>::iterator ScreenData::it_for_row(int row)
{
if (row >= m_screen_height) {
return m_screen_blocks.end();
}
auto it = m_screen_blocks.end();
int line_for_block = m_screen_height;
size_t abs_line = contentHeight();
while (it != m_screen_blocks.begin()) {
--it;
line_for_block -= (*it)->lineCount();
abs_line -= (*it)->lineCount();
if (line_for_block <= row) {
(*it)->setScreenIndex(line_for_block);
(*it)->setLine(abs_line);
return it;
}
}
return m_screen_blocks.end();
}
#endif // SCREENDATA_H

215
yat/backend/scrollback.cpp Normal file
View File

@ -0,0 +1,215 @@
/******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
******************************************************************************/
#include "scrollback.h"
#include "screen_data.h"
#include "screen.h"
#include "block.h"
#define P_VAR(variable) \
#variable ":" << variable
Scrollback::Scrollback(size_t max_size, ScreenData *screen_data)
: m_screen_data(screen_data)
, m_height(0)
, m_width(0)
, m_block_count(0)
, m_max_size(max_size)
, m_adjust_visible_pages(0)
{
}
void Scrollback::addBlock(Block *block)
{
if (!m_max_size) {
delete block;
return;
}
m_blocks.push_back(block);
block->releaseTextObjects();
m_block_count++;
m_height += m_blocks.back()->lineCount();
while (m_height - m_blocks.front()->lineCount() >= m_max_size) {
m_block_count--;
m_height -= m_blocks.front()->lineCount();
delete m_blocks.front();
m_blocks.pop_front();
m_adjust_visible_pages++;
}
m_visible_pages.clear();
}
Block *Scrollback::reclaimBlock()
{
if (m_blocks.empty())
return nullptr;
Block *last = m_blocks.back();
last->setWidth(m_width);
m_block_count--;
m_height -= last->lineCount();
m_blocks.pop_back();
m_visible_pages.clear();
return last;
}
void Scrollback::ensureVisiblePages(int top_line)
{
if (top_line < 0)
return;
if (size_t(top_line) >= m_height)
return;
uint height = std::max(m_screen_data->screen()->height(), 1);
int complete_pages = m_height / height;
int remainder = m_height - (complete_pages * height);
int top_page = top_line / height;
int bottom_page = top_page + 1;
std::set<int> pages_to_update;
pages_to_update.insert(top_page);
if (bottom_page * height < m_height)
pages_to_update.insert(bottom_page);
for (auto it = m_visible_pages.begin(); it != m_visible_pages.end(); ++it) {
Page &page = *it;
if (pages_to_update.count(page.page_no) != 0) {
if (page.page_no < complete_pages) {
ensurePageVisible(page, height);
} else if (page.page_no == complete_pages) {
ensurePageVisible(page, remainder);
}
pages_to_update.erase(page.page_no);
} else {
ensurePageNotVisible(page);
auto to_remove = it;
--it;
m_visible_pages.erase(to_remove);
}
}
for (auto it = pages_to_update.begin(); it != pages_to_update.end(); ++it) {
auto page_it = findIteratorForPage(*it);
m_visible_pages.push_back( { *it, 0, page_it } );
if (*it < complete_pages) {
ensurePageVisible(m_visible_pages.back(), height);
} else if (*it == complete_pages) {
ensurePageVisible(m_visible_pages.back(), remainder);
}
}
}
void Scrollback::ensurePageVisible(Page &page, int new_height)
{
if (page.size == new_height || !m_block_count)
return;
int line_no = page.page_no * m_screen_data->screen()->height();
auto it = page.it;
std::advance(it, page.size);
for (int i = page.size; i < new_height; ++it, i++) {
(*it)->setLine(line_no + i);
(*it)->dispatchEvents();
}
page.size = new_height;
}
void Scrollback::ensurePageNotVisible(Page &page)
{
auto it = page.it;
for (int i = 0; i < page.size; ++it, i++) {
(*it)->releaseTextObjects();
}
page.size = 0;
}
std::list<Block *>::iterator Scrollback::findIteratorForPage(int page_no)
{
uint line = page_no * m_screen_data->screen()->height();
Q_ASSERT(line < m_height);
for (auto it = m_visible_pages.begin(); it != m_visible_pages.end(); ++it) {
Page &page = *it;
int diff = page_no - page.page_no;
if (diff < 5 && diff > 5) {
auto to_return = page.it;
int advance = diff * m_screen_data->screen()->height();
std::advance(to_return, advance);
return to_return;
}
}
if (line > m_height / 2) {
auto to_return = m_blocks.end();
std::advance(to_return, line - m_height);
return to_return;
}
auto to_return = m_blocks.begin();
std::advance(to_return, line);
return to_return;
}
void Scrollback::adjustVisiblePages()
{
if (!m_adjust_visible_pages)
return;
for (auto it = m_visible_pages.begin(); it != m_visible_pages.end(); ++it) {
Page &page = *it;
const size_t line_for_page = page.page_no * m_screen_data->screen()->height();
if (line_for_page < m_adjust_visible_pages) {
auto to_remove = it;
--it;
m_visible_pages.erase(to_remove);
} else {
page.size = 0;
std::advance(page.it, m_adjust_visible_pages);
}
}
m_adjust_visible_pages = 0;
}
size_t Scrollback::height() const
{
return m_height;
}
void Scrollback::setWidth(int width)
{
m_width = width;
}
QString Scrollback::selection(const QPoint &start, const QPoint &end) const
{
Q_UNUSED(start);
Q_UNUSED(end);
return QString();
}

73
yat/backend/scrollback.h Normal file
View File

@ -0,0 +1,73 @@
/******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
******************************************************************************/
#ifndef SCROLLBACK_H
#define SCROLLBACK_H
#include <set>
#include <list>
#include <QtCore/qglobal.h>
#include <QtCore/QPoint>
class ScreenData;
class Block;
struct Page {
int page_no;
int size;
std::list<Block *>::iterator it;
};
class Scrollback
{
public:
Scrollback(size_t max_size, ScreenData *screen_data);
void addBlock(Block *block);
Block *reclaimBlock();
void ensureVisiblePages(int top_line);
size_t height() const;
void setWidth(int width);
size_t blockCount() { return m_block_count; }
QString selection(const QPoint &start, const QPoint &end) const;
private:
void ensurePageVisible(Page &page, int new_height);
void ensurePageNotVisible(Page &page);
std::list<Block *>::iterator findIteratorForPage(int page_no);
void adjustVisiblePages();
ScreenData *m_screen_data;
std::list<Block *> m_blocks;
std::list<Page> m_visible_pages;
size_t m_height;
size_t m_width;
size_t m_block_count;
size_t m_max_size;
size_t m_adjust_visible_pages;
};
#endif //SCROLLBACK_H

197
yat/backend/selection.cpp Normal file
View File

@ -0,0 +1,197 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#include "selection.h"
#include "screen.h"
#include "screen_data.h"
#include <QtGui/QGuiApplication>
Selection::Selection(Screen *screen)
: QObject(screen)
, m_screen(screen)
, m_new_start_x(0)
, m_start_x(0)
, m_new_start_y(0)
, m_start_y(0)
, m_new_end_x(0)
, m_end_x(0)
, m_new_end_y(0)
, m_end_y(0)
, m_new_enable(false)
{
connect(screen, &Screen::contentModified, this, &Selection::screenContentModified);
}
void Selection::setStartX(int x)
{
if (x != m_new_start_x) {
m_new_start_x = x;
setValidity();
m_screen->scheduleEventDispatch();
}
}
int Selection::startX() const
{
return m_start_x;
}
void Selection::setStartY(int y)
{
if (y != m_new_start_y) {
m_new_start_y = y;
setValidity();
m_screen->scheduleEventDispatch();
}
}
int Selection::startY() const
{
return m_start_y;
}
void Selection::setEndX(int x)
{
if (m_new_end_x != x) {
m_new_end_x = x;
setValidity();
m_screen->scheduleEventDispatch();
}
}
int Selection::endX() const
{
return m_end_x;
}
void Selection::setEndY(int y)
{
if (m_new_end_y != y) {
m_new_end_y = y;
setValidity();
m_screen->scheduleEventDispatch();
}
}
int Selection::endY() const
{
return m_end_y;
}
void Selection::setEnable(bool enable)
{
if (m_new_enable != enable) {
m_new_enable = enable;
m_screen->scheduleEventDispatch();
}
}
void Selection::screenContentModified(size_t lineModified, int lineDiff, int contentDiff)
{
if (!m_new_enable)
return;
if (lineModified >= size_t(m_new_start_y) && lineModified <= size_t(m_new_end_y)) {
setEnable(false);
return;
}
if (size_t(m_new_end_y) < lineModified && lineModified != contentDiff) {
m_new_end_y -= lineDiff - contentDiff;
m_new_start_y -= lineDiff - contentDiff;
if (m_new_end_y < 0) {
setEnable(false);
return;
}
if (m_new_start_y < 0) {
m_new_start_y = 0;
}
m_screen->scheduleEventDispatch();
}
}
void Selection::setValidity()
{
if (m_new_end_y > m_new_start_y ||
(m_new_end_y == m_new_start_y &&
m_new_end_x > m_new_start_x)) {
setEnable(true);
} else {
setEnable(false);
}
}
void Selection::sendToClipboard() const
{
m_screen->currentScreenData()->sendSelectionToClipboard(start_new_point(), end_new_point(), QClipboard::Clipboard);
}
void Selection::sendToSelection() const
{
m_screen->currentScreenData()->sendSelectionToClipboard(start_new_point(), end_new_point(), QClipboard::Selection);
}
void Selection::pasteFromSelection()
{
m_screen->pty()->write(QGuiApplication::clipboard()->text(QClipboard::Selection).toUtf8());
}
void Selection::pasteFromClipboard()
{
m_screen->pty()->write(QGuiApplication::clipboard()->text(QClipboard::Clipboard).toUtf8());
}
void Selection::dispatchChanges()
{
if (!m_new_enable && !m_enable)
return;
if (m_new_start_y != m_start_y) {
m_start_y = m_new_start_y;
emit startYChanged();
}
if (m_new_start_x != m_start_x) {
m_start_x = m_new_start_x;
emit startXChanged();
}
if (m_new_end_y != m_end_y) {
m_end_y = m_new_end_y;
emit endYChanged();
}
if (m_new_end_x != m_end_x) {
m_end_x = m_new_end_x;
emit endXChanged();
}
if (m_new_enable != m_enable) {
m_enable = m_new_enable;
emit enableChanged();
}
}
bool Selection::enable() const
{
return m_enable;
}

93
yat/backend/selection.h Normal file
View File

@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#ifndef SELECTION_H
#define SELECTION_H
#include <QtCore/QObject>
#include <QtCore/QPoint>
class Screen;
class Selection : public QObject
{
Q_OBJECT
Q_PROPERTY(int startX READ startX WRITE setStartX NOTIFY startXChanged)
Q_PROPERTY(int startY READ startY WRITE setStartY NOTIFY startYChanged)
Q_PROPERTY(int endX READ endX WRITE setEndX NOTIFY endXChanged)
Q_PROPERTY(int endY READ endY WRITE setEndY NOTIFY endYChanged)
Q_PROPERTY(bool enable READ enable WRITE setEnable NOTIFY enableChanged)
public:
explicit Selection(Screen *screen);
void setStartX(int x);
int startX() const;
void setStartY(int y);
int startY() const;
void setEndX(int x);
int endX() const;
void setEndY(int y);
int endY() const;
void setEnable(bool enabled);
bool enable() const;
Q_INVOKABLE void sendToClipboard() const;
Q_INVOKABLE void sendToSelection() const;
Q_INVOKABLE void pasteFromSelection();
Q_INVOKABLE void pasteFromClipboard();
void dispatchChanges();
signals:
void startXChanged();
void startYChanged();
void endXChanged();
void endYChanged();
void enableChanged();
private slots:
void screenContentModified(size_t lineModified, int lineDiff, int contentDiff);
private:
void setValidity();
QPoint start_new_point() const { return QPoint(m_new_start_x, m_new_start_y); }
QPoint end_new_point() const { return QPoint(m_new_end_x, m_new_end_y); }
Screen *m_screen;
int m_new_start_x;
int m_start_x;
int m_new_start_y;
int m_start_y;
int m_new_end_x;
int m_end_x;
int m_new_end_y;
int m_end_y;
bool m_new_enable;
bool m_enable;
};
#endif

255
yat/backend/text.cpp Normal file
View File

@ -0,0 +1,255 @@
/**************************************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
***************************************************************************************************/
#include "text.h"
#include "screen.h"
#include "block.h"
#include <QtQuick/QQuickItem>
#include <QtCore/QDebug>
Text::Text(Screen *screen)
: QObject(screen)
, m_screen(screen)
, m_text_line(0)
, m_start_index(0)
, m_old_start_index(0)
, m_end_index(0)
, m_line(0)
, m_old_line(0)
, m_width(1)
, m_style_dirty(true)
, m_text_dirty(true)
, m_visible(true)
, m_visible_old(true)
, m_latin(true)
, m_latin_old(true)
, m_forgroundColor(m_screen->defaultForgroundColor())
, m_backgroundColor(m_screen->defaultBackgroundColor())
{
connect(m_screen->colorPalette(), SIGNAL(changed()), this, SLOT(paletteChanged()));
connect(m_screen, SIGNAL(dispatchTextSegmentChanges()), this, SLOT(dispatchEvents()));
}
Text::~Text()
{
}
int Text::index() const
{
return m_start_index % m_width;
}
int Text::line() const
{
return m_line + (m_start_index / m_width);
}
void Text::setLine(int line, int width, const QString *textLine)
{
m_line = line;
m_width = width;
m_text_dirty = true;
m_text_line = textLine;
}
bool Text::visible() const
{
return m_visible;
}
void Text::setVisible(bool visible)
{
m_visible = visible;
}
QString Text::text() const
{
return m_text;
}
QColor Text::foregroundColor() const
{
return m_forgroundColor;
}
QColor Text::backgroundColor() const
{
return m_backgroundColor;
}
void Text::setStringSegment(int start_index, int end_index, bool text_changed)
{
m_start_index = start_index;
m_end_index = end_index;
m_text_dirty = text_changed;
}
void Text::setTextStyle(const TextStyle &style)
{
m_new_style = style;
m_style_dirty = true;
}
bool Text::bold() const
{
return m_style.style & TextStyle::Bold;
}
bool Text::blinking() const
{
return m_style.style & TextStyle::Blinking;
}
bool Text::underline() const
{
return m_style.style & TextStyle::Underlined;
}
void Text::setLatin(bool latin)
{
m_latin = latin;
}
bool Text::latin() const
{
return m_latin_old;
}
static bool differentStyle(TextStyle::Styles a, TextStyle::Styles b, TextStyle::Style style)
{
return (a & style) != (b & style);
}
void Text::dispatchEvents()
{
int old_line = m_old_line + (m_old_start_index / m_width);
int new_line = m_line + (m_start_index / m_width);
if (old_line != new_line) {
m_old_line = m_line;
emit lineChanged();
}
if (m_latin != m_latin_old) {
m_latin_old = m_latin;
emit latinChanged();
}
if (m_old_start_index != m_start_index
|| m_text_dirty) {
m_text_dirty = false;
QString old_text = m_text;
m_text = m_text_line->mid(m_start_index, m_end_index - m_start_index + 1);
if (m_old_start_index != m_start_index) {
m_old_start_index = m_start_index;
emit indexChanged();
}
emit textChanged();
}
if (m_style_dirty) {
m_style_dirty = false;
bool emit_forground = m_new_style.forground != m_style.forground;
bool emit_background = m_new_style.background != m_style.background;
TextStyle::Styles new_style = m_new_style.style;
TextStyle::Styles old_style = m_style.style;
bool emit_bold = false;
bool emit_blink = false;
bool emit_underline = false;
bool emit_inverse = false;
if (new_style != old_style) {
emit_bold = differentStyle(new_style, old_style, TextStyle::Bold);
emit_blink = differentStyle(new_style, old_style, TextStyle::Blinking);
emit_underline = differentStyle(new_style, old_style, TextStyle::Underlined);
emit_inverse = differentStyle(new_style, old_style, TextStyle::Inverse);
}
m_style = m_new_style;
if (emit_inverse) {
setForgroundColor();
setBackgroundColor();
} else {
if (emit_forground || emit_bold) {
setForgroundColor();
}
if (emit_background) {
setBackgroundColor();
}
}
if (emit_bold) {
emit boldChanged();
}
if (emit_blink) {
emit blinkingChanged();
}
if (emit_underline) {
emit underlineChanged();
}
}
if (m_visible_old != m_visible) {
m_visible_old = m_visible;
emit visibleChanged();
}
}
void Text::paletteChanged()
{
setBackgroundColor();
setForgroundColor();
}
void Text::setBackgroundColor()
{
QColor new_background;
if (m_style.style & TextStyle::Inverse) {
new_background = m_screen->colorPalette()->color(m_style.forground, false);
} else {
new_background = m_screen->colorPalette()->color(m_style.background, false);
}
if (new_background != m_backgroundColor) {
m_backgroundColor = new_background;
emit backgroundColorChanged();
}
}
void Text::setForgroundColor()
{
QColor new_forground;
if (m_style.style & TextStyle::Inverse) {
new_forground = m_screen->colorPalette()->color(m_style.background, false);
} else {
new_forground = m_screen->colorPalette()->color(m_style.forground, false);
}
if (new_forground != m_forgroundColor) {
m_forgroundColor = new_forground;
emit forgroundColorChanged();
}
}

121
yat/backend/text.h Normal file
View File

@ -0,0 +1,121 @@
/**************************************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
***************************************************************************************************/
#ifndef TEXT_SEGMENT_H
#define TEXT_SEGMENT_H
#include <QtCore/QString>
#include <QtGui/QColor>
#include <QtCore/QObject>
#include <QtCore/QSize>
#include "text_style.h"
class Screen;
class QQuickItem;
class Text : public QObject
{
Q_OBJECT
Q_PROPERTY(int index READ index NOTIFY indexChanged)
Q_PROPERTY(int line READ line NOTIFY lineChanged)
Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
Q_PROPERTY(QString text READ text NOTIFY textChanged)
Q_PROPERTY(QColor foregroundColor READ foregroundColor NOTIFY forgroundColorChanged)
Q_PROPERTY(QColor backgroundColor READ backgroundColor NOTIFY backgroundColorChanged)
Q_PROPERTY(bool bold READ bold NOTIFY boldChanged)
Q_PROPERTY(bool blinking READ blinking NOTIFY blinkingChanged)
Q_PROPERTY(bool underline READ underline NOTIFY underlineChanged)
Q_PROPERTY(bool latin READ latin NOTIFY latinChanged)
public:
Text(Screen *screen);
~Text();
int index() const;
int line() const;
void setLine(int line, int width, const QString *textLine);
bool visible() const;
void setVisible(bool visible);
QString text() const;
QColor foregroundColor() const;
QColor backgroundColor() const;
void setStringSegment(int start_index, int end_index, bool textChanged);
void setTextStyle(const TextStyle &style);
bool bold() const;
bool blinking() const;
bool underline() const;
void setLatin(bool latin);
bool latin() const;
QObject *item() const;
public slots:
void dispatchEvents();
signals:
void indexChanged();
void lineChanged();
void visibleChanged();
void textChanged();
void forgroundColorChanged();
void backgroundColorChanged();
void boldChanged();
void blinkingChanged();
void underlineChanged();
void latinChanged();
private slots:
void paletteChanged();
private:
void setBackgroundColor();
void setForgroundColor();
Screen *m_screen;
QString m_text;
const QString *m_text_line;
int m_start_index;
int m_old_start_index;
int m_end_index;
int m_line;
int m_old_line;
int m_width;
TextStyle m_style;
TextStyle m_new_style;
bool m_style_dirty;
bool m_text_dirty;
bool m_visible;
bool m_visible_old;
bool m_latin;
bool m_latin_old;
QColor m_forgroundColor;
QColor m_backgroundColor;
};
#endif // TEXT_SEGMENT_H

View File

@ -0,0 +1,36 @@
#include "text_style.h"
#include "screen.h"
#include "text.h"
#include <QtCore/QDebug>
TextStyle::TextStyle()
: style(Normal)
, forground(ColorPalette::DefaultForground)
, background(ColorPalette::DefaultBackground)
{
}
bool TextStyle::isCompatible(const TextStyle &other) const
{
return forground == other.forground
&& background == other.background
&& style == other.style;
}
QDebug operator<<(QDebug debug, TextStyleLine line)
{
debug << "[" << line.start_index << "(" << line.style << ":" << line.forground << ":" << line.background << ")" << line.end_index << "]";
return debug;
}
void TextStyleLine::releaseTextSegment(Screen *screen)
{
if (text_segment) {
text_segment->setVisible(false);
screen->releaseTextSegment(text_segment);
text_segment = 0;
}
}

85
yat/backend/text_style.h Normal file
View File

@ -0,0 +1,85 @@
#ifndef TEXT_STYLE_H
#define TEXT_STYLE_H
#include <QtGui/QColor>
#include "color_palette.h"
class Screen;
class TextStyle
{
public:
enum Style {
Normal = 0x0000,
Italic = 0x0001,
Bold = 0x0002,
Underlined = 0x0004,
Blinking = 0x0008,
FastBlinking = 0x0010,
Gothic = 0x0020,
DoubleUnderlined = 0x0040,
Framed = 0x0080,
Overlined = 0x0100,
Encircled = 0x0200,
Inverse = 0x0400
};
Q_DECLARE_FLAGS(Styles, Style)
TextStyle();
Styles style;
ColorPalette::Color forground;
ColorPalette::Color background;
bool isCompatible(const TextStyle &other) const;
};
class Text;
class TextStyleLine : public TextStyle {
public:
TextStyleLine(const TextStyle &style, int start_index, int end_index)
: TextStyle(style)
, start_index(start_index)
, end_index(end_index)
, old_index(-1)
, text_segment(0)
, style_dirty(true)
, index_dirty(true)
, text_dirty(true)
{
}
TextStyleLine()
: start_index(0)
, end_index(0)
, old_index(-1)
, text_segment(0)
, style_dirty(false)
, index_dirty(false)
, text_dirty(false)
{
}
void releaseTextSegment(Screen *screen);
int start_index;
int end_index;
int old_index;
Text *text_segment;
bool style_dirty;
bool index_dirty;
bool text_dirty;
void setStyle(const TextStyle &style) {
forground = style.forground;
background = style.background;
this->style = style.style;
}
};
QDebug operator<<(QDebug debug, TextStyleLine line);
#endif // TEXT_STYLE_H

109
yat/backend/utf8_decoder.h Normal file
View File

@ -0,0 +1,109 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#ifndef UTF8_DECODER
#define UTF8_DECODER
#include "controll_chars.h"
class Utf8Decoder
{
public:
inline Utf8Decoder();
inline void addChar(uchar character);
inline bool isLatin() const;
inline bool isC1() const;
inline void clear();
private:
short m_expected_length;
short m_length;
uint32_t m_unicode;
};
Utf8Decoder::Utf8Decoder()
{
clear();
}
void Utf8Decoder::addChar(uchar character)
{
if (m_length && m_length == m_expected_length) {
clear();
}
if (character < 0x80)
return;
fprintf(stderr, "Character: 0x%x\n", character);
if (m_expected_length == 0) {
//this is naive. There must be a faster way.
if ((character & 0xfc) == 0xfc) {
m_expected_length = 5;
m_unicode = character & 0x01;
} else if ((character & 0xf8) == 0xf8) {
m_expected_length = 4;
m_unicode = character & 0x03;
} else if ((character & 0xf0) == 0xf0) {
m_expected_length = 3;
m_unicode = character & 0x07;
} else if ((character & 0xe0) == 0xe0) {
m_expected_length = 2;
m_unicode = character & 0x0f;
} else if ((character & 0xc0) == 0xc0) {
m_expected_length = 1;
m_unicode = character & 0x1f;
} else {
m_expected_length = 0;
m_unicode = 0;
qWarning("Utf8Decoder: invalid decoder character");
}
} else {
fprintf(stderr, "Before 0x%x adding 0x%x pure 0x%x\n", m_unicode,(character & 0x3f), character);
m_unicode = (m_unicode << 6) | (character & 0x3f);
fprintf(stderr, "After 0x%x\n", m_unicode);
m_length++;
}
}
bool Utf8Decoder::isLatin() const
{
return m_expected_length < 2 && m_unicode < 0xff;
}
bool Utf8Decoder::isC1() const
{
return m_expected_length == 2 && m_length == m_expected_length &&
(m_unicode >= C1_8bit::C1_8bit_Start && m_unicode <= C1_8bit::C1_8bit_Stop);
}
void Utf8Decoder::clear()
{
m_expected_length = 0;
m_length = 0;
m_unicode = 0;
}
#endif

139
yat/backend/yat_pty.cpp Normal file
View File

@ -0,0 +1,139 @@
/**************************************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
***************************************************************************************************/
#include "yat_pty.h"
#include <fcntl.h>
#include <poll.h>
#ifdef LINUX
#include <sys/epoll.h>
#endif
#include <sys/ioctl.h>
#ifdef Q_OS_MAC
#include <util.h>
#else
#include <pty.h>
#endif
#include <utmp.h>
#include <QtCore/QSize>
#include <QtCore/QString>
#include <QtCore/QThread>
#include <QtCore/QSocketNotifier>
#include <QtCore/QDebug>
static char env_variables[][255] = {
"TERM=xterm-color",
"COLORTERM=xterm",
"COLORFGBG=15;0",
"LINES",
"COLUMNS",
"TERMCAP"
};
static int env_variables_size = sizeof(env_variables) / sizeof(env_variables[0]);
YatPty::YatPty()
: m_winsize(0)
{
m_terminal_pid = forkpty(&m_master_fd,
NULL,
NULL,
NULL);
if (m_terminal_pid == 0) {
for (int i = 0; i < env_variables_size; i++) {
::putenv(env_variables[i]);
}
::execl("/bin/bash", "/bin/bash", "--login", (const char *) 0);
exit(0);
}
QSocketNotifier *reader = new QSocketNotifier(m_master_fd,QSocketNotifier::Read,this);
connect(reader, &QSocketNotifier::activated, this, &YatPty::readData);
}
YatPty::~YatPty()
{
}
void YatPty::write(const QByteArray &data)
{
if (::write(m_master_fd, data.constData(), data.size()) < 0) {
qDebug() << "Something whent wrong when writing to m_master_fd";
}
}
void YatPty::setWidth(int width, int pixelWidth)
{
if (!m_winsize) {
m_winsize = new struct winsize;
m_winsize->ws_row = 25;
m_winsize->ws_ypixel = 0;
}
m_winsize->ws_col = width;
m_winsize->ws_xpixel = pixelWidth;
ioctl(m_master_fd, TIOCSWINSZ, m_winsize);
}
void YatPty::setHeight(int height, int pixelHeight)
{
if (!m_winsize) {
m_winsize = new struct winsize;
m_winsize->ws_col = 80;
m_winsize->ws_xpixel = 0;
}
m_winsize->ws_row = height;
m_winsize->ws_ypixel = pixelHeight;
ioctl(m_master_fd, TIOCSWINSZ, m_winsize);
}
QSize YatPty::size() const
{
if (!m_winsize) {
YatPty *that = const_cast<YatPty *>(this);
that->m_winsize = new struct winsize;
ioctl(m_master_fd, TIOCGWINSZ, m_winsize);
}
return QSize(m_winsize->ws_col, m_winsize->ws_row);
}
int YatPty::masterDevice() const
{
return m_master_fd;
}
void YatPty::readData()
{
int size_of_buffer = sizeof m_data_buffer / sizeof *m_data_buffer;
ssize_t read_size = ::read(m_master_fd,m_data_buffer,size_of_buffer);
if (read_size > 0) {
QByteArray to_return = QByteArray::fromRawData(m_data_buffer,read_size);
emit readyRead(to_return);
} else if (read_size < 0) {
emit hangupReceived();
} else {
emit hangupReceived();
}
}

59
yat/backend/yat_pty.h Normal file
View File

@ -0,0 +1,59 @@
/**************************************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
***************************************************************************************************/
#ifndef YAT_PTY_H
#define YAT_PTY_H
#include <unistd.h>
#include <QtCore/QObject>
#include <QtCore/QLinkedList>
#include <QtCore/QMutex>
class YatPty : public QObject
{
Q_OBJECT
public:
YatPty();
~YatPty();
void write(const QByteArray &data);
void setWidth(int width, int pixelWidth = 0);
void setHeight(int height, int pixelHeight = 0);
QSize size() const;
int masterDevice() const;
signals:
void hangupReceived();
void readyRead(const QByteArray &data);
private:
void readData();
pid_t m_terminal_pid;
int m_master_fd;
char m_slave_file_name[PATH_MAX];
struct winsize *m_winsize;
char m_data_buffer[1024];
};
#endif //YAT_PTY_H

BIN
yat/docs/Ecma-048.pdf Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

3
yat/tests/auto/auto.pro Normal file
View File

@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS = \
block

View File

@ -0,0 +1,8 @@
CONFIG += testcase
QT += testlib quick
include(../../../backend/backend.pri)
SOURCES += \
tst_block.cpp \

View File

@ -0,0 +1,950 @@
#include "../../../backend/block.h"
#include <QtTest/QtTest>
#include <QtQml/QQmlEngine>
#include "../../../backend/screen.h"
#include "../../../backend/screen_data.h"
class BlockHandler
{
public:
BlockHandler(bool fill) {
screen.setHeight(5);
int width = 100;
screen.setWidth(width);
(*screen.currentScreenData()->it_for_row(0))->clear();
if (fill) {
QString spaces(width, QChar(' '));
block()->replaceAtPos(0, spaces, screen.defaultTextStyle());
}
QCOMPARE(block()->style_list().size(), 1);
default_style = block()->style_list().at(0);
default_text_style = default_style.style;
}
Block *block() const
{
return *screen.currentScreenData()->it_for_row(0);
}
void doneChanges()
{
screen.dispatchChanges();
}
TextStyle default_style;
TextStyle::Styles default_text_style;
Screen screen;
};
class tst_Block: public QObject
{
Q_OBJECT
private slots:
void replaceStart();
void replaceEdgeOfStyle();
void replaceCompatibleStyle();
void replaceCompatiblePreviousStyle();
void replaceCompatiblePreviousStyleShouldRemove();
void replaceCompatibleCurrentStyleShouldRemove();
void replaceIncompatibleStyle();
void replaceIncompaitibleStylesCrossesBoundary();
void replace3IncompatibleStyles();
void replaceIncomaptibleStylesCrosses2Boundaries();
void replaceIncompatibleColor();
void replaceRemoveOverlappedStyles();
void replaceSwapStyles();
void replaceEndBlock();
void clearBlock();
void clearToEndOfBlock1Segment();
void clearToEndOfBlock3Segment();
void clearToEndOfBlockMiddle3Segment();
void deleteCharacters1Segment();
void deleteCharacters2Segments();
void deleteCharacters3Segments();
void deleteCharactersRemoveSegmentEnd();
void deleteCharactersRemoveSegmentBeginning();
void deleteCharactersRemoveMiddle();
void insertCharacters();
void insertCharacters2Segments();
void insertCharacters3Segments();
};
void tst_Block::replaceStart()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QVector<TextStyleLine> old_style_list = block->style_list();
QCOMPARE(old_style_list.size(), 1);
QString replace_text("This is a test");
TextStyle textStyle;
textStyle.style = TextStyle::Overlined;
block->replaceAtPos(0,replace_text, textStyle);
QVector<TextStyleLine> new_style_list = block->style_list();
TextStyleLine first_style = new_style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, replace_text.size() - 1);
QCOMPARE(new_style_list.size(), 2);
}
void tst_Block::replaceEdgeOfStyle()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString first_text("This is the First");
TextStyle textStyle;
textStyle.style = TextStyle::Overlined;
block->replaceAtPos(0,first_text, textStyle);
QString second_text("This is the Second");
textStyle.style = TextStyle::Bold;
block->replaceAtPos(first_text.size(), second_text, textStyle);
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 3);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.style, TextStyle::Overlined);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, first_text.size() - 1);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.style, TextStyle::Bold);
QCOMPARE(second_style.start_index, first_text.size());
QCOMPARE(second_style.end_index, first_text.size()+ second_text.size() - 1);
const TextStyleLine &third_style = style_list.at(2);
QCOMPARE(third_style.style, TextStyle::Normal);
QCOMPARE(third_style.start_index, first_text.size()+ second_text.size());
}
void tst_Block::replaceCompatibleStyle()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString replace_text("replaceed Text");
block->replaceAtPos(10, replace_text, blockHandler.default_style);
QVector<TextStyleLine> after_style_list = block->style_list();
QCOMPARE(after_style_list.size(), 1);
QCOMPARE(after_style_list.at(0).style, blockHandler.default_text_style);
}
void tst_Block::replaceCompatiblePreviousStyle()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
TextStyle first_style = blockHandler.default_style;
first_style.style = TextStyle::Blinking;
QString first_text("first");
block->replaceAtPos(0,first_text, first_style);
TextStyle second_style = blockHandler.default_style;
second_style.style = TextStyle::Bold;
QString second_text("this is the second text");
block->replaceAtPos(first_text.size(), second_text, second_style);
QString third_text("third");
block->replaceAtPos(first_text.size(), third_text,first_style);
blockHandler.doneChanges();
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 3);
const TextStyleLine &first_check_style = style_list.at(0);
QCOMPARE(first_check_style.start_index, 0);
QCOMPARE(first_check_style.end_index, (first_text.size() -1) + third_text.size());
const TextStyleLine &second_check_style = style_list.at(1);
QCOMPARE(second_check_style.start_index, first_text.size() + third_text.size());
QCOMPARE(second_check_style.end_index, (first_text.size() -1) + second_text.size());
const TextStyleLine &third_check_style = style_list.at(2);
QCOMPARE(third_check_style.start_index, first_text.size() + second_text.size());
}
void tst_Block::replaceCompatiblePreviousStyleShouldRemove()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
TextStyle first_style = blockHandler.default_style;
first_style.style = TextStyle::Blinking;
QString first_text("first");
block->replaceAtPos(0,first_text, first_style);
TextStyle second_style = blockHandler.default_style;
second_style.style = TextStyle::Bold;
QString second_text("second");
block->replaceAtPos(first_text.size(), second_text, second_style);
QString third_text("this is the third");
block->replaceAtPos(first_text.size(), third_text,first_style);
blockHandler.doneChanges();
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 2);
const TextStyleLine &first_check_style = style_list.at(0);
QCOMPARE(first_check_style.start_index, 0);
QCOMPARE(first_check_style.end_index, (first_text.size() -1) + third_text.size());
const TextStyleLine &second_check_style = style_list.at(1);
QCOMPARE(second_check_style.start_index, first_text.size() + third_text.size());
}
void tst_Block::replaceCompatibleCurrentStyleShouldRemove()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
TextStyle first_style = blockHandler.default_style;
first_style.style = TextStyle::Blinking;
QString first_text("first");
block->replaceAtPos(0,first_text, first_style);
TextStyle second_style = blockHandler.default_style;
second_style.style = TextStyle::Bold;
QString second_text("second");
block->replaceAtPos(first_text.size(), second_text, second_style);
QString third_text("second");
block->replaceAtPos(first_text.size(), third_text,first_style);
blockHandler.doneChanges();
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 2);
const TextStyleLine &first_check_style = style_list.at(0);
QCOMPARE(first_check_style.start_index, 0);
QCOMPARE(first_check_style.end_index, (first_text.size() -1) + third_text.size());
const TextStyleLine &second_check_style = style_list.at(1);
QCOMPARE(second_check_style.start_index, first_text.size() + third_text.size());
}
void tst_Block::replaceIncompatibleStyle()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString replace_text("replaceed Text");
TextStyle replace_style;
replace_style.style = TextStyle::Blinking;
block->replaceAtPos(10, replace_text, replace_style);
QVector<TextStyleLine> after_style_list = block->style_list();
QCOMPARE(after_style_list.size(), 3);
const TextStyleLine &first_style = after_style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, 9);
QCOMPARE(first_style.style, blockHandler.default_text_style);
const TextStyleLine &second_style = after_style_list.at(1);
QCOMPARE(second_style.start_index, 10);
QCOMPARE(second_style.end_index, 10 + replace_text.size() -1);
QCOMPARE(second_style.style, TextStyle::Blinking);
const TextStyleLine &third_style = after_style_list.at(2);
QCOMPARE(third_style.start_index, 10 + replace_text.size());
QCOMPARE(third_style.style, blockHandler.default_text_style);
}
void tst_Block::replaceIncompaitibleStylesCrossesBoundary()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString replace_text("replaceed Text");
TextStyle replace_style;
replace_style.style = TextStyle::Blinking;
block->replaceAtPos(0, replace_text, replace_style);
QString crosses_boundary("New incompatible text");
replace_style.style = TextStyle::Framed;
int replace_pos = replace_text.size()/2;
block->replaceAtPos(replace_pos, crosses_boundary, replace_style);
QVector<TextStyleLine> after_style_list = block->style_list();
QCOMPARE(after_style_list.size(), 3);
const TextStyleLine &first_style = after_style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, replace_pos -1);
QCOMPARE(first_style.style, TextStyle::Blinking);
const TextStyleLine &second_style = after_style_list.at(1);
QCOMPARE(second_style.start_index, replace_pos);
QCOMPARE(second_style.end_index, replace_pos + crosses_boundary.size() -1);
QCOMPARE(second_style.style, TextStyle::Framed);
const TextStyleLine &third_style = after_style_list.at(2);
QCOMPARE(third_style.start_index, replace_pos + crosses_boundary.size());
QCOMPARE(third_style.style, blockHandler.default_text_style);
}
void tst_Block::replace3IncompatibleStyles()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString first_text("First Text");
TextStyle replace_style;
replace_style.style = TextStyle::Blinking;
block->replaceAtPos(0, first_text, replace_style);
QString second_text("Second Text");
replace_style.style = TextStyle::Italic;
block->replaceAtPos(first_text.size(), second_text, replace_style);
QString third_text("Third Text");
replace_style.style = TextStyle::Encircled;
block->replaceAtPos(first_text.size() + second_text.size(), third_text, replace_style);
QCOMPARE(block->style_list().size(), 4);
QVector<TextStyleLine> after_style_list = block->style_list();
const TextStyleLine &first_style = after_style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, first_text.size() -1);
const TextStyleLine &second_style = after_style_list.at(1);
QCOMPARE(second_style.start_index, first_text.size());
QCOMPARE(second_style.end_index, first_text.size() + second_text.size() - 1);
QCOMPARE(second_style.style, TextStyle::Italic);
const TextStyleLine &third_style = after_style_list.at(2);
QCOMPARE(third_style.start_index, first_text.size() + second_text.size());
QCOMPARE(third_style.end_index, first_text.size() + second_text.size() + third_text.size() - 1);
QCOMPARE(third_style.style, TextStyle::Encircled);
const TextStyleLine &fourth_style = after_style_list.at(3);
QCOMPARE(fourth_style.start_index, first_text.size() + second_text.size() + third_text.size());
}
void tst_Block::replaceIncomaptibleStylesCrosses2Boundaries()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString first_text("First Text");
TextStyle replace_style;
replace_style.style = TextStyle::Blinking;
block->replaceAtPos(0, first_text, replace_style);
QString second_text("Second Text");
replace_style.style = TextStyle::Italic;
block->replaceAtPos(first_text.size(), second_text, replace_style);
QString third_text("Third Text");
replace_style.style = TextStyle::Encircled;
block->replaceAtPos(first_text.size() + second_text.size(), third_text, replace_style);
QCOMPARE(block->style_list().size(), 4);
QVector<TextStyleLine> before_style_list = block->style_list();
QString overlap_first_third;
overlap_first_third.fill(QChar('A'), second_text.size() + 4);
replace_style.style = TextStyle::DoubleUnderlined;
block->replaceAtPos(first_text.size() -2, overlap_first_third, replace_style);
QVector<TextStyleLine> after_style_list = block->style_list();
QCOMPARE(block->style_list().size(), 4);
const TextStyleLine &first_style = after_style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, first_text.size() - 3);
QCOMPARE(first_style.style, TextStyle::Blinking);
const TextStyleLine &second_style = after_style_list.at(1);
QCOMPARE(second_style.style, TextStyle::DoubleUnderlined);
QCOMPARE(second_style.start_index, first_text.size() - 2);
QCOMPARE(second_style.end_index, first_text.size() - 2 + overlap_first_third.size() -1);
const TextStyleLine &third_style = after_style_list.at(2);
QCOMPARE(third_style.style, TextStyle::Encircled);
QCOMPARE(third_style.start_index, first_text.size() - 2 + overlap_first_third.size());
QCOMPARE(third_style.end_index, first_text.size() - 2 + overlap_first_third.size() + third_text.size() - 1 - 2);
const TextStyleLine &fourth_style = after_style_list.at(3);
QCOMPARE(fourth_style.style, blockHandler.default_text_style);
QCOMPARE(fourth_style.start_index, first_text.size() - 2 + overlap_first_third.size() + third_text.size() - 2);
}
void tst_Block::replaceIncompatibleColor()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString first_text("291 ");
TextStyleLine replace_style;
replace_style.forground = ColorPalette::Yellow;
block->replaceAtPos(0,first_text, replace_style);
QString second_text("QPointF Screen::selectionAreaStart() ");
replace_style.forground = blockHandler.default_style.forground;
block->replaceAtPos(first_text.size(), second_text, replace_style);
QString third_text("const");
replace_style.forground = ColorPalette::Green;
block->replaceAtPos(first_text.size() + second_text.size(), third_text, replace_style);
QString brackets("()");
replace_style.forground = ColorPalette::Cyan;
block->replaceAtPos(38, brackets, replace_style);
QVector<TextStyleLine> after_style_list = block->style_list();
const TextStyleLine &first_style = after_style_list.at(0);
QCOMPARE(first_style.forground, ColorPalette::Yellow);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, first_text.size() - 1);
const TextStyleLine &second_style = after_style_list.at(1);
QCOMPARE(second_style.forground, blockHandler.default_style.forground);
QCOMPARE(second_style.start_index, first_text.size());
QCOMPARE(second_style.end_index, 37);
const TextStyleLine &third_style = after_style_list.at(2);
QCOMPARE(third_style.forground, ColorPalette::Cyan);
QCOMPARE(third_style.start_index, 38);
QCOMPARE(third_style.end_index, 38 + brackets.size() -1);
const TextStyleLine &fourth_style = after_style_list.at(3);
QCOMPARE(fourth_style.forground, blockHandler.default_style.forground);
QCOMPARE(fourth_style.start_index, 38 + brackets.size());
QCOMPARE(fourth_style.end_index, first_text.size() + second_text.size() -1);
}
void tst_Block::replaceRemoveOverlappedStyles()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString first_text("First Text");
TextStyle replace_style;
replace_style.style = TextStyle::Blinking;
block->replaceAtPos(0, first_text, replace_style);
QString second_text("Second Text");
replace_style.style = TextStyle::Italic;
block->replaceAtPos(first_text.size(), second_text, replace_style);
QString third_text("Third Text");
replace_style.style = TextStyle::Encircled;
block->replaceAtPos(first_text.size() + second_text.size(), third_text, replace_style);
QString fourth_text = third_text + second_text;
fourth_text.chop(1);
replace_style.style = TextStyle::Bold;
block->replaceAtPos(first_text.size(), fourth_text, replace_style);
QCOMPARE(block->style_list().size(), 4);
}
void tst_Block::replaceSwapStyles()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString first_text("First Text");
TextStyle replace_style;
replace_style.style = TextStyle::Blinking;
block->replaceAtPos(0, first_text, replace_style);
QString second_text("Second Text");
replace_style.style = TextStyle::Italic;
block->replaceAtPos(first_text.size(), second_text, replace_style);
QString third_text("Third Text");
replace_style.style = TextStyle::Encircled;
block->replaceAtPos(first_text.size() + second_text.size(), third_text, replace_style);
QString replace_second("Dnoces Text");
replace_style.style = TextStyle::Bold;
block->replaceAtPos(first_text.size(), replace_second, replace_style);
QCOMPARE(block->style_list().size(), 4);
}
void tst_Block::replaceEndBlock()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString *full_block = block->textLine();
int block_size = full_block->size();
QString replace_text("at the end of the string");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Bold;
block->replaceAtPos(block_size - replace_text.size(), replace_text, style);
QCOMPARE(block->textLine()->size(), block_size);
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 2);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, block_size - replace_text.size() -1);
QCOMPARE(first_style.style, blockHandler.default_text_style);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, block_size - replace_text.size());
QCOMPARE(second_style.end_index, block_size - 1);
QCOMPARE(second_style.style, TextStyle::Bold);
}
void tst_Block::clearBlock()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QVERIFY(block->textLine()->size() > 0);
QCOMPARE(block->textLine()->trimmed().size(), 0);
}
void tst_Block::clearToEndOfBlock1Segment()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString replace_text("To be replaceed");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Encircled;
block->replaceAtPos(0, replace_text, style);
int before_clear_size = block->textLine()->size();
block->clearCharacters(5, blockHandler.screen.width() -1);
blockHandler.doneChanges();
int after_clear_size = block->textLine()->size();
QCOMPARE(after_clear_size, before_clear_size);
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 2);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, 4);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, 5);
QString cleared("To be");
QCOMPARE(block->textLine()->trimmed(), cleared);
}
void tst_Block::clearToEndOfBlock3Segment()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString replace_text("To be");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Encircled;
block->replaceAtPos(0, replace_text, style);
QString replace_text2(" or not to be");
style.style = TextStyle::Bold;
block ->replaceAtPos(replace_text.size(), replace_text2, style);
block->clearCharacters(replace_text.size(), blockHandler.screen.width() - 1);
blockHandler.doneChanges();
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 2);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, replace_text.size() - 1);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, replace_text.size());
QCOMPARE(second_style.style, blockHandler.default_text_style);
}
void tst_Block::clearToEndOfBlockMiddle3Segment()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString replace_text("To be");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Encircled;
block->replaceAtPos(0, replace_text, style);
QString replace_text2(" or not to be");
style.style = TextStyle::Bold;
block ->replaceAtPos(replace_text.size(), replace_text2, style);
block->clearCharacters(replace_text.size() + 3, blockHandler.screen.width() - 1);
blockHandler.doneChanges();
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 3);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, replace_text.size() - 1);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, replace_text.size());
QCOMPARE(second_style.end_index, replace_text.size() + 2);
const TextStyleLine &third_style = style_list.at(2);
QCOMPARE(third_style.start_index, replace_text.size() + 3);
QCOMPARE(third_style.style, blockHandler.default_text_style);
}
void tst_Block::deleteCharacters1Segment()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString replace_text("replaceing some text");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Encircled;
block->replaceAtPos(0, replace_text, style);
QString *full_block = block->textLine();
int block_size = full_block->size();
block->deleteCharacters(10,14);
QCOMPARE(block->textLine()->size(), block_size - 5);
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 2);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, 14);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, 15);
QCOMPARE(second_style.style, blockHandler.default_text_style);
}
void tst_Block::deleteCharacters2Segments()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString replace_text("replaceing some text");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Encircled;
block->replaceAtPos(0, replace_text, style);
QString *full_block = block->textLine();
int block_size = full_block->size();
block->deleteCharacters(15,25);
QCOMPARE(block->textLine()->size(), block_size - 11);
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 2);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, 14);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, 15);
QCOMPARE(second_style.style, blockHandler.default_text_style);
}
void tst_Block::deleteCharacters3Segments()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString replace_text("replaceing some text");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Encircled;
block->replaceAtPos(0, replace_text, style);
QString replace_more_text("Some more text");
style.style = TextStyle::Bold;
block->replaceAtPos(replace_text.size(), replace_more_text, style);
QString *full_block = block->textLine();
int block_size = full_block->size();
block->deleteCharacters(10,15);
QCOMPARE(block->textLine()->size(), block_size - 6);
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 3);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, 13);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, 14);
QCOMPARE(second_style.end_index, 14 + replace_more_text.size() -1);
QCOMPARE(second_style.style, TextStyle::Bold);
const TextStyleLine &third_style = style_list.at(2);
QCOMPARE(third_style.start_index, 14 + replace_more_text.size());
QCOMPARE(third_style.style, blockHandler.default_text_style);
}
void tst_Block::deleteCharactersRemoveSegmentEnd()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString replace_text("replaceing some text");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Encircled;
block->replaceAtPos(0, replace_text, style);
QString replace_more_text("Some more text");
style.style = TextStyle::Bold;
block->replaceAtPos(replace_text.size(), replace_more_text, style);
QString *full_block = block->textLine();
int block_size = full_block->size();
block->deleteCharacters(16,33);
QCOMPARE(block->textLine()->size(), block_size - ((33 - 16) + 1));
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 2);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, 15);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, 16);
QCOMPARE(second_style.style, blockHandler.default_text_style);
}
void tst_Block::deleteCharactersRemoveSegmentBeginning()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString replace_text("replaceing some text");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Encircled;
block->replaceAtPos(0, replace_text, style);
QString replace_more_text("Some more text");
style.style = TextStyle::Bold;
block->replaceAtPos(replace_text.size(), replace_more_text, style);
QString *full_block = block->textLine();
int block_size = full_block->size();
block->deleteCharacters(replace_text.size(),replace_text.size() + replace_more_text.size() + 3);
int expected_size = block_size -1 - ((replace_text.size() + replace_more_text.size() + 3 ) - replace_text.size());
QCOMPARE(block->textLine()->size(), expected_size);
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 2);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, replace_text.size() - 1);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, replace_text.size());
QCOMPARE(second_style.style, blockHandler.default_text_style);
}
void tst_Block::deleteCharactersRemoveMiddle()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString insert_text('A');
int old_width = blockHandler.screen.width();
QString empty(old_width - 2, ' ');
insert_text += empty + 'B';
block->replaceAtPos(0, insert_text, blockHandler.default_style);
Q_ASSERT(old_width == blockHandler.screen.width());
Q_ASSERT(insert_text == *block->textLine());
block->deleteCharacters(1, old_width - 2);
Q_ASSERT(QString("AB") == block->textLine()->trimmed());
}
void tst_Block::insertCharacters()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString *full_block = block->textLine();
int block_size = full_block->size();
QString insert_text("inserting some text");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Encircled;
block->insertAtPos(5, insert_text, style);
int expected_size = block_size + insert_text.size();
QCOMPARE(block->textLine()->size(), expected_size);
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 3);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, 4);
QCOMPARE(first_style.style, blockHandler.default_text_style);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, 5);
QCOMPARE(second_style.end_index, 5 + insert_text.size() -1);
QCOMPARE(second_style.style, TextStyle::Encircled);
const TextStyleLine &third_style = style_list.at(2);
QCOMPARE(third_style.start_index, 5 + insert_text.size());
QCOMPARE(third_style.end_index, expected_size - 1);
QCOMPARE(third_style.style, blockHandler.default_text_style);
}
void tst_Block::insertCharacters2Segments()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString *full_block = block->textLine();
int block_size = full_block->size();
QString replace_text("at the end of the string");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Bold;
block->replaceAtPos(block_size - replace_text.size(), replace_text, style);
QString insert_text("inserting some text");
style.style = TextStyle::Encircled;
block->insertAtPos(5, insert_text, style);
int expected_size = block_size + insert_text.size();
QCOMPARE(block->textLine()->size(), expected_size);
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 4);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, 4);
QCOMPARE(first_style.style, blockHandler.default_text_style);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, 5);
QCOMPARE(second_style.end_index, 5 + insert_text.size() -1);
QCOMPARE(second_style.style, TextStyle::Encircled);
const TextStyleLine &third_style = style_list.at(2);
QCOMPARE(third_style.start_index, 5 + insert_text.size());
QCOMPARE(third_style.end_index, block_size -1 - replace_text.size() + insert_text.size());
QCOMPARE(third_style.style, blockHandler.default_text_style);
const TextStyleLine &fourth_style = style_list.at(3);
QCOMPARE(fourth_style.start_index, block_size - replace_text.size() + insert_text.size());
QCOMPARE(fourth_style.end_index, expected_size - 1 );
QCOMPARE(fourth_style.style, TextStyle::Bold);
}
void tst_Block::insertCharacters3Segments()
{
BlockHandler blockHandler(true);
Block *block = blockHandler.block();
QString *full_block = block->textLine();
int block_size = full_block->size();
QString replace_text("at the end of the string");
TextStyle style = blockHandler.default_style;
style.style = TextStyle::Bold;
block->replaceAtPos(block_size - replace_text.size(), replace_text, style);
QString replace_text2("somewhere in the string");
style.style = TextStyle::Encircled;
block->replaceAtPos(20,replace_text2, style);
QVector<TextStyleLine> tmp_style_list = block->style_list();
QCOMPARE(tmp_style_list.size(), 4);
QString insert_text("this text is longer than last segment");
style.style = TextStyle::Italic;
block->insertAtPos(10, insert_text, style);
blockHandler.doneChanges();
int expected_size = block_size + insert_text.size();
QCOMPARE(block->textLine()->size(), expected_size);
block->printStyleList();
QVector<TextStyleLine> style_list = block->style_list();
QCOMPARE(style_list.size(), 6);
const TextStyleLine &first_style = style_list.at(0);
QCOMPARE(first_style.start_index, 0);
QCOMPARE(first_style.end_index, 9);
QCOMPARE(first_style.style, blockHandler.default_text_style);
const TextStyleLine &second_style = style_list.at(1);
QCOMPARE(second_style.start_index, 10);
QCOMPARE(second_style.end_index, 10 + insert_text.size() -1);
QCOMPARE(second_style.style, TextStyle::Italic);
const TextStyleLine &third_style = style_list.at(2);
QCOMPARE(third_style.start_index, 10 + insert_text.size());
QCOMPARE(third_style.end_index, 20 + insert_text.size() - 1);
QCOMPARE(third_style.style, blockHandler.default_text_style);
const TextStyleLine &fourth_style = style_list.at(3);
QCOMPARE(fourth_style.start_index, 20 + insert_text.size());
QCOMPARE(fourth_style.end_index, 20 + insert_text.size() + replace_text2.size() - 1);
QCOMPARE(fourth_style.style, TextStyle::Encircled);
const TextStyleLine &fith_style = style_list.at(4);
QCOMPARE(fith_style.start_index, 20 + insert_text.size() + replace_text2.size());
QCOMPARE(fith_style.end_index, block_size - replace_text.size() + insert_text.size() - 1);
QCOMPARE(fith_style.style, blockHandler.default_text_style);
const TextStyleLine &sixth_style = style_list.at(5);
QCOMPARE(sixth_style.start_index, block_size - replace_text.size() + insert_text.size());
QCOMPARE(sixth_style.end_index, block_size + insert_text.size() - 1);
QCOMPARE(sixth_style.style, TextStyle::Bold);
}
#include <tst_block.moc>
QTEST_MAIN(tst_Block);

3
yat/tests/tests.pro Normal file
View File

@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS = \
auto

5
yat/yat.pro Normal file
View File

@ -0,0 +1,5 @@
TEMPLATE=subdirs
CONFIG += ordered
SUBDIRS= \
yat_declarative \
tests

View File

@ -0,0 +1,46 @@
/**************************************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
***************************************************************************************************/
#include <QtGui/QGuiApplication>
#include <QtCore/QResource>
#include <QtCore/QThread>
#include <QQmlEngine>
#include "register_qml_types.h"
#include "terminal_screen.h"
#include "yat_pty.h"
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
register_qml_types();
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:/qml/yat_declarative/main.qml"));
auto errors = component.errors();
for (int i = 0; i < errors.size(); i++) {
qDebug() << errors.at(i).toString();
}
component.create();
return app.exec();
}

View File

@ -0,0 +1,249 @@
/******************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
******************************************************************************/
#include "mono_text.h"
#include <QtQuick/private/qsgadaptationlayer_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquicktextnode_p.h>
#include <QtGui/QTextLayout>
class MonoSGNode : public QSGTransformNode
{
public:
MonoSGNode(QQuickItem *owner)
: m_owner(owner)
{
}
void deleteContent()
{
QSGNode *subnode = firstChild();
while (subnode) {
// We can't delete the node now as it might be in the preprocess list
// It will be deleted in the next preprocess
m_nodes_to_delete.append(subnode);
subnode = subnode->nextSibling();
}
removeAllChildNodes();
}
void preprocess()
{
while (m_nodes_to_delete.count())
delete m_nodes_to_delete.takeLast();
}
void setLatinText(const QString &text, const QFont &font, const QColor &color) {
QRawFont raw_font = QRawFont::fromFont(font, QFontDatabase::Latin);
if (raw_font != m_raw_font) {
m_raw_font = raw_font;
m_positions.clear();
}
if (m_positions.size() < text.size()) {
qreal x_pos = 0;
qreal max_char_width = raw_font.averageCharWidth();
qreal ascent = raw_font.ascent();
if (m_positions.size())
x_pos = m_positions.last().x() + max_char_width;
int to_add = text.size() - m_positions.size();
for (int i = 0; i < to_add; i++) {
m_positions << QPointF(x_pos, ascent);
x_pos += max_char_width;
}
}
deleteContent();
QSGRenderContext *sgr = QQuickItemPrivate::get(m_owner)->sceneGraphRenderContext();
QSGGlyphNode *node = sgr->sceneGraphContext()->createGlyphNode(sgr);
node->setOwnerElement(m_owner);
node->geometry()->setIndexDataPattern(QSGGeometry::StaticPattern);
node->geometry()->setVertexDataPattern(QSGGeometry::StaticPattern);
node->setStyle(QQuickText::Normal);
node->setColor(color);
QGlyphRun glyphrun;
glyphrun.setRawFont(raw_font);
glyphrun.setGlyphIndexes(raw_font.glyphIndexesForString(text));
glyphrun.setPositions(m_positions);
node->setGlyphs(QPointF(0, raw_font.ascent()), glyphrun);
node->update();
appendChildNode(node);
}
void setUnicodeText(const QString &text, const QFont &font, const QColor &color)
{
deleteContent();
QRawFont raw_font = QRawFont::fromFont(font, QFontDatabase::Latin);
qreal line_width = raw_font.averageCharWidth() * text.size();
QSGRenderContext *sgr = QQuickItemPrivate::get(m_owner)->sceneGraphRenderContext();
QTextLayout layout(text,font);
layout.beginLayout();
QTextLine line = layout.createLine();
line.setLineWidth(line_width);
//Q_ASSERT(!layout.createLine().isValid());
layout.endLayout();
QList<QGlyphRun> glyphRuns = line.glyphRuns();
qreal xpos = 0;
for (int i = 0; i < glyphRuns.size(); i++) {
QSGGlyphNode *node = sgr->sceneGraphContext()->createGlyphNode(sgr);
node->setOwnerElement(m_owner);
node->geometry()->setIndexDataPattern(QSGGeometry::StaticPattern);
node->geometry()->setVertexDataPattern(QSGGeometry::StaticPattern);
node->setGlyphs(QPointF(xpos, raw_font.ascent()), glyphRuns.at(i));
node->setStyle(QQuickText::Normal);
node->setColor(color);
xpos += raw_font.averageCharWidth() * glyphRuns.at(i).positions().size();
node->update();
appendChildNode(node);
}
}
private:
QQuickItem *m_owner;
QVector<QPointF> m_positions;
QLinkedList<QSGNode *> m_nodes_to_delete;
QRawFont m_raw_font;
};
MonoText::MonoText(QQuickItem *parent)
: QQuickItem(parent)
, m_color_changed(false)
, m_latin(true)
, m_old_latin(true)
{
setFlag(ItemHasContents, true);
}
MonoText::~MonoText()
{
}
QString MonoText::text() const
{
return m_text;
}
void MonoText::setText(const QString &text)
{
if (m_text != text) {
m_text = text;
emit textChanged();
polish();
}
}
QFont MonoText::font() const
{
return m_font;
}
void MonoText::setFont(const QFont &font)
{
if (font != m_font) {
m_font = font;
emit fontChanged();
polish();
}
}
QColor MonoText::color() const
{
return m_color;
}
void MonoText::setColor(const QColor &color)
{
if (m_color != color) {
m_color = color;
emit colorChanged();
update();
}
}
qreal MonoText::paintedWidth() const
{
return implicitWidth();
}
qreal MonoText::paintedHeight() const
{
return implicitHeight();
}
bool MonoText::latin() const
{
return m_latin;
}
void MonoText::setLatin(bool latin)
{
if (latin == m_latin)
return;
m_latin = latin;
emit latinChanged();
}
QSGNode *MonoText::updatePaintNode(QSGNode *old, UpdatePaintNodeData *)
{
if (m_text.size() == 0 || m_text.trimmed().size() == 0) {
delete old;
return 0;
}
MonoSGNode *node = static_cast<MonoSGNode *>(old);
if (!node) {
node = new MonoSGNode(this);
}
if (m_latin) {
node->setLatinText(m_text, m_font, m_color);
} else {
node->setUnicodeText(m_text, m_font, m_color);
}
return node;
}
void MonoText::updatePolish()
{
QRawFont raw_font = QRawFont::fromFont(m_font, QFontDatabase::Latin);
qreal height = raw_font.descent() + raw_font.ascent() + raw_font.lineThickness();
qreal width = raw_font.averageCharWidth() * m_text.size();
bool emit_text_width_changed = width != implicitWidth();
bool emit_text_height_changed = height != implicitHeight();
setImplicitSize(width, height);
if (emit_text_width_changed)
emit paintedWidthChanged();
if (emit_text_height_changed)
emit paintedHeightChanged();
update();
}

View File

@ -0,0 +1,81 @@
/******************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
******************************************************************************/
#ifndef MONO_TEXT_H
#define MONO_TEXT_H
#include <QtQuick/QQuickItem>
#include <QtGui/QRawFont>
class MonoText : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedWidthChanged)
Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedHeightChanged)
Q_PROPERTY(bool latin READ latin WRITE setLatin NOTIFY latinChanged);
public:
MonoText(QQuickItem *parent=0);
~MonoText();
QString text() const;
void setText(const QString &text);
QFont font() const;
void setFont(const QFont &font);
QColor color() const;
void setColor(const QColor &color);
qreal paintedWidth() const;
qreal paintedHeight() const;
bool latin() const;
void setLatin(bool latin);
signals:
void textChanged();
void fontChanged();
void colorChanged();
void paintedWidthChanged();
void paintedHeightChanged();
void latinChanged();
protected:
QSGNode *updatePaintNode(QSGNode *old, UpdatePaintNodeData *data) Q_DECL_OVERRIDE;
void updatePolish() Q_DECL_OVERRIDE;
private:
Q_DISABLE_COPY(MonoText);
void updateSize();
QString m_text;
QFont m_font;
QColor m_color;
bool m_color_changed;
bool m_latin;
bool m_old_latin;
QSizeF m_text_size;
};
#endif

View File

@ -0,0 +1,55 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#include "object_destruct_item.h"
ObjectDestructItem::ObjectDestructItem(QQuickItem *parent)
: QQuickItem(parent)
, m_object(0)
{
}
QObject *ObjectDestructItem::objectHandle() const
{
return m_object;
}
void ObjectDestructItem::setObjectHandle(QObject *object)
{
bool emit_changed = m_object != object;
if (m_object) {
m_object->disconnect(this);
}
m_object = object;
connect(m_object, SIGNAL(destroyed()), this, SLOT(objectDestroyed()));
if (emit_changed)
emit objectHandleChanged();
}
void ObjectDestructItem::objectDestroyed()
{
delete this;
}

View File

@ -0,0 +1,52 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
#ifndef OBJECT_DESTRUCT_ITEM_H
#define OBJECT_DESTRUCT_ITEM_H
#include <QtQuick/QQuickItem>
#include <QtCore/QObject>
class ObjectDestructItem : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QObject *objectHandle READ objectHandle WRITE setObjectHandle NOTIFY objectHandleChanged)
public:
ObjectDestructItem(QQuickItem *parent = 0);
QObject *objectHandle() const;
void setObjectHandle(QObject *line);
signals:
void objectHandleChanged();
private slots:
void objectDestroyed();
private:
QObject *m_object;
};
#endif //OBJECT_DESTRUCT_ITEM_H

View File

@ -0,0 +1,104 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
import QtQuick 2.0
Item {
id: highlightArea
property real characterWidth: 0
property real characterHeight: 0
property int screenWidth: 0
property int startX
property int startY
property int endX
property int endY
property color color: "grey"
y: startY * characterHeight
width: parent.width
height: (endY - startY + 1) * characterHeight
opacity: 0.8
Rectangle {
id: begginning_rectangle
color: parent.color
opacity: parent.opacity
y:0
height: characterHeight
}
Rectangle {
id: middle_rectangle
color: parent.color
opacity: parent.opacity
width: parent.width
x: 0
anchors.top: begginning_rectangle.bottom
}
Rectangle {
id: end_rectangle
color: parent.color
opacity: parent.opacity
x: 0
height: characterHeight
anchors.top: middle_rectangle.bottom
}
onCharacterWidthChanged: calculateRectangles();
onCharacterHeightChanged: calculateRectangles();
onScreenWidthChanged: calculateRectangles();
onStartXChanged: calculateRectangles();
onStartYChanged: calculateRectangles();
onEndXChanged: calculateRectangles();
onEndYChanged: calculateRectangles();
function calculateRectangles() {
highlightArea.y = startY * characterHeight;
begginning_rectangle.x = startX * characterWidth;
if (startY === endY) {
middle_rectangle.visible = false;
end_rectangle.visible = false
begginning_rectangle.width = (endX - startX) * characterWidth;
} else {
begginning_rectangle.width = (screenWidth - startX) * characterWidth;
if (startY === endY - 1) {
middle_rectangle.height = 0;
middle_rectangle.visible = false;
}else {
middle_rectangle.visible = true;
middle_rectangle.height = (endY - startY - 1) * characterHeight;
}
end_rectangle.visible = true;
end_rectangle.width = endX * characterWidth;
}
}
}

View File

@ -0,0 +1,66 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
import QtQuick 2.0
import org.yat 1.0
ObjectDestructItem {
id: cursor
property real fontHeight
property real fontWidth
height: fontHeight
width: fontWidth
x: objectHandle.x * fontWidth
y: objectHandle.y * fontHeight
z: 1.1
visible: objectHandle.visible
ShaderEffect {
anchors.fill: parent
property variant source: fragmentSource
fragmentShader:
"uniform lowp float qt_Opacity;" +
"uniform sampler2D source;" +
"varying highp vec2 qt_TexCoord0;" +
"void main() {" +
" lowp vec4 color = texture2D(source, qt_TexCoord0 ) * qt_Opacity;" +
" gl_FragColor = vec4(1.0 - color.r, 1.0 - color.g, 1.0 - color.b, color.a);" +
"}"
ShaderEffectSource {
id: fragmentSource
sourceItem: background
live: true
sourceRect: Qt.rect(cursor.x,cursor.y,cursor.width,cursor.height);
}
}
}

View File

@ -0,0 +1,285 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
import QtQuick 2.0
import QtQuick.Controls 1.1
import org.yat 1.0
TerminalScreen {
id: screenItem
property font font
property real fontWidth: fontMetricText.paintedWidth
property real fontHeight: fontMetricText.paintedHeight
property var lineComponent : Qt.createComponent("TerminalLine.qml")
property var textComponent : Qt.createComponent("TerminalText.qml")
property var cursorComponent : Qt.createComponent("TerminalCursor.qml")
font.family: "menlo"
focus: true
Action {
id: copyAction
shortcut: "Ctrl+Shift+C"
onTriggered: screen.selection.sendToClipboard()
}
Action {
id: paseAction
shortcut: "Ctrl+Shift+V"
onTriggered: screen.selection.pasteFromClipboard()
}
onActiveFocusChanged: {
if (activeFocus) {
Qt.inputMethod.show();
}
}
Keys.onPressed: {
if (event.text === "?") {
terminal.screen.printScreen()
}
}
Text {
id: fontMetricText
text: "B"
font: parent.font
visible: false
textFormat: Text.PlainText
}
Flickable {
id: flickable
anchors.top: parent.top
anchors.left: parent.left
contentWidth: width
contentHeight: textContainer.height
interactive: true
flickableDirection: Flickable.VerticalFlick
contentY: ((screen.contentHeight - screen.height) * screenItem.fontHeight)
Item {
id: textContainer
width: parent.width
height: screen.contentHeight * screenItem.fontHeight
Rectangle {
id: background
anchors.fill: parent
color: terminal.screen.defaultBackgroundColor
}
HighlightArea {
characterHeight: fontHeight
characterWidth: fontWidth
screenWidth: terminalWindow.width
startX: screen.selection.startX
startY: screen.selection.startY
endX: screen.selection.endX
endY: screen.selection.endY
visible: screen.selection.enable
}
}
onContentYChanged: {
if (!atYEnd) {
var top_line = Math.floor(Math.max(contentY,0) / screenItem.fontHeight);
screen.ensureVisiblePages(top_line);
}
}
}
Connections {
id: connections
target: terminal.screen
onFlash: {
flashAnimation.start()
}
onReset: {
resetScreenItems();
}
onTextCreated: {
var textSegment = textComponent.createObject(screenItem,
{
"parent" : background,
"objectHandle" : text,
"font" : screenItem.font,
"fontWidth" : screenItem.fontWidth,
"fontHeight" : screenItem.fontHeight,
})
}
onCursorCreated: {
if (cursorComponent.status != Component.Ready) {
console.log(cursorComponent.errorString());
return;
}
var cursorVariable = cursorComponent.createObject(screenItem,
{
"parent" : textContainer,
"objectHandle" : cursor,
"fontWidth" : screenItem.fontWidth,
"fontHeight" : screenItem.fontHeight,
})
}
onRequestHeightChange: {
terminalWindow.height = newHeight * screenItem.fontHeight;
terminalWindow.contentItem.height = newHeight * screenItem.fontHeight;
}
onRequestWidthChange: {
terminalWindow.width = newWidth * screenItem.fontWidth;
terminalWindow.contentItem.width = newWidth * screenItem.fontWidth;
}
}
onFontChanged: {
setTerminalHeight();
setTerminalWidth();
}
onWidthChanged: {
setTerminalWidth();
}
onHeightChanged: {
setTerminalHeight();
}
Component.onCompleted: {
setTerminalWidth();
setTerminalHeight();
}
function setTerminalWidth() {
if (fontWidth > 0) {
var pty_width = Math.floor(width / fontWidth);
flickable.width = pty_width * fontWidth;
screen.width = pty_width;
}
}
function setTerminalHeight() {
if (fontHeight > 0) {
var pty_height = Math.floor(height / fontHeight);
flickable.height = pty_height * fontHeight;
screen.height = pty_height;
}
}
Rectangle {
id: flash
z: 1.2
anchors.fill: parent
color: "grey"
opacity: 0
SequentialAnimation {
id: flashAnimation
NumberAnimation {
target: flash
property: "opacity"
to: 1
duration: 75
}
NumberAnimation {
target: flash
property: "opacity"
to: 0
duration: 75
}
}
}
MouseArea {
id:mousArea
property int drag_start_x
property int drag_start_y
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
onPressed: {
if (mouse.button == Qt.LeftButton) {
hoverEnabled = true;
var transformed_mouse = mapToItem(textContainer, mouse.x, mouse.y);
var character = Math.floor((transformed_mouse.x / fontWidth));
var line = Math.floor(transformed_mouse.y / fontHeight);
var start = Qt.point(character,line);
drag_start_x = character;
drag_start_y = line;
screen.selection.startX = character;
screen.selection.startY = line;
screen.selection.endX = character;
screen.selection.endY = line;
}
}
onPositionChanged: {
var transformed_mouse = mapToItem(textContainer, mouse.x, mouse.y);
var character = Math.floor(transformed_mouse.x / fontWidth);
var line = Math.floor(transformed_mouse.y / fontHeight);
var current_pos = Qt.point(character,line);
if (line < drag_start_y || (line === drag_start_y && character < drag_start_x)) {
screen.selection.startX = character;
screen.selection.startY = line;
screen.selection.endX = drag_start_x;
screen.selection.endY = drag_start_y;
}else {
screen.selection.startX = drag_start_x;
screen.selection.startY = drag_start_y;
screen.selection.endX = character;
screen.selection.endY = line;
}
}
onReleased: {
if (mouse.button == Qt.LeftButton) {
hoverEnabled = false;
screen.selection.sendToSelection();
}
}
onClicked: {
if (mouse.button == Qt.MiddleButton) {
screen.pasteFromSelection();
}
}
onDoubleClicked: {
if (mouse.button == Qt.LeftButton) {
var transformed_mouse = mapToItem(textContainer, mouse.x, mouse.y);
var character = Math.floor(transformed_mouse.x / fontWidth);
var line = Math.floor(transformed_mouse.y / fontHeight);
screen.doubleClicked(Qt.point(character,line));
}
}
}
}

View File

@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
import QtQuick 2.0
import org.yat 1.0
ObjectDestructItem {
id: textItem
property font font
property real fontWidth
property real fontHeight
y: objectHandle.line * fontHeight;
x: objectHandle.index * fontWidth;
width: textElement.paintedWidth
height: textElement.paintedHeight
visible: objectHandle.visible
Rectangle {
anchors.fill: parent
color: objectHandle.backgroundColor
MonoText {
id: textElement
anchors.fill: parent
text: objectHandle.text
color: objectHandle.foregroundColor
font.family: textItem.font.family
font.pixelSize: textItem.font.pixelSize
font.pointSize: textItem.font.pointSize
font.bold: objectHandle.bold
font.underline: objectHandle.underline
latin: objectHandle.latin
SequentialAnimation {
running: objectHandle.blinking
loops: Animation.Infinite
onRunningChanged: {
if (running === false)
textElement.opacity = 1
}
NumberAnimation {
target: textElement
property: "opacity"
to: 0
duration: 250
}
NumberAnimation {
target: textElement
property: "opacity"
to: 1
duration: 250
}
}
}
}
}

View File

@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright (c) 2013 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*******************************************************************************/
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
id: terminalWindow
TerminalScreen {
id: terminal
anchors.fill: parent
Component.onCompleted: terminalWindow.visible = true
}
width: 800
height: 600
color: terminal.screen.defaultBackgroundColor
}

View File

@ -0,0 +1,9 @@
<RCC>
<qresource prefix="/">
<file>qml/yat_declarative/main.qml</file>
<file>qml/yat_declarative/TerminalScreen.qml</file>
<file>qml/yat_declarative/TerminalText.qml</file>
<file>qml/yat_declarative/TerminalCursor.qml</file>
<file>qml/yat_declarative/HighlightArea.qml</file>
</qresource>
</RCC>

View File

@ -0,0 +1,22 @@
#include "register_qml_types.h"
#include <QtQml>
#include "terminal_screen.h"
#include "object_destruct_item.h"
#include "screen.h"
#include "text.h"
#include "cursor.h"
#include "mono_text.h"
#include "selection.h"
void register_qml_types()
{
qmlRegisterType<TerminalScreen>("org.yat", 1, 0, "TerminalScreen");
qmlRegisterType<ObjectDestructItem>("org.yat", 1, 0, "ObjectDestructItem");
qmlRegisterType<MonoText>("org.yat", 1, 0, "MonoText");
qmlRegisterType<Screen>();
qmlRegisterType<Text>();
qmlRegisterType<Cursor>();
qmlRegisterType<Selection>();
}

View File

@ -0,0 +1,6 @@
#ifndef REGISTER_QML_TYPES_H
#define REGISTER_QML_TYPES_H
void register_qml_types();
#endif // REGISTER_QML_TYPES_H

View File

@ -0,0 +1,65 @@
/**************************************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
***************************************************************************************************/
#include "terminal_screen.h"
TerminalScreen::TerminalScreen(QQuickItem *parent)
: QQuickItem(parent)
, m_screen(new Screen(this))
{
setFlag(QQuickItem::ItemAcceptsInputMethod);
}
Screen *TerminalScreen::screen() const
{
return m_screen;
}
QVariant TerminalScreen::inputMethodQuery(Qt::InputMethodQuery query) const
{
switch (query) {
case Qt::ImEnabled:
return QVariant(true);
case Qt::ImHints:
return QVariant(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
default:
return QVariant();
}
}
void TerminalScreen::inputMethodEvent(QInputMethodEvent *event)
{
QString commitString = event->commitString();
if (commitString.isEmpty()) {
return;
}
Qt::Key key = Qt::Key_unknown;
if (commitString == " ") {
key = Qt::Key_Space; // screen requires
}
m_screen->sendKey(commitString, key, 0);
}
void TerminalScreen::keyPressEvent(QKeyEvent *event)
{
m_screen->sendKey(event->text(), Qt::Key(event->key()), event->modifiers());
}

View File

@ -0,0 +1,54 @@
/******************************************************************************
* Copyright (c) 2012 Jørgen Lind
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
******************************************************************************/
#ifndef TERMINALITEM_H
#define TERMINALITEM_H
#include <QtCore/QObject>
#include <QtQuick/QQuickItem>
#include <QInputMethodEvent>
#include <QKeyEvent>
#include "screen.h"
class TerminalScreen : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(Screen *screen READ screen CONSTANT)
public:
TerminalScreen(QQuickItem *parent = 0);
Screen *screen() const;
QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
protected:
void inputMethodEvent(QInputMethodEvent *event);
void keyPressEvent(QKeyEvent *event);
private:
Screen *m_screen;
};
#endif // TERMINALITEM_H

View File

@ -0,0 +1,18 @@
QT += gui quick
TARGET = yat
include(../backend/backend.pri)
INCLUDEPATH += $$PWD
SOURCES += $$PWD/terminal_screen.cpp \
$$PWD/object_destruct_item.cpp \
$$PWD/register_qml_types.cpp \
$$PWD/mono_text.cpp \
HEADERS += \
$$PWD/terminal_screen.h \
$$PWD/object_destruct_item.h \
$$PWD/register_qml_types.h \
$$PWD/mono_text.h \