/******************************************************************************* * Copyright (c) 2013 "Filippo Scognamiglio" * https://github.com/Swordfish90/cool-retro-term * * This file is part of cool-retro-term. * * cool-retro-term is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . *******************************************************************************/ import QtQuick 2.2 import QtQuick.Controls 1.1 import QMLTermWidget 1.0 import "utils.js" as Utils Item{ id: terminalContainer property size virtualResolution: Qt.size(kterminal.width, kterminal.height) property alias mainTerminal: kterminal property ShaderEffectSource mainSource: kterminalSource property ShaderEffectSource blurredSource: blurredSourceLoader.item property real fontWidth: 1.0 property real screenScaling: 1.0 property real scaleTexture: 1.0 property alias title: ksession.title property alias kterminal: kterminal anchors.leftMargin: frame.displacementLeft * appSettings.windowScaling anchors.rightMargin: frame.displacementRight * appSettings.windowScaling anchors.topMargin: frame.displacementTop * appSettings.windowScaling anchors.bottomMargin: frame.displacementBottom * appSettings.windowScaling //The blur effect has to take into account the framerate property real mBlur: Math.sqrt(appSettings.burnIn) property real motionBlurCoefficient: Utils.lint(_minBlurCoefficient, _maxBlurCoefficient, mBlur) property real _minBlurCoefficient: 0.2 property real _maxBlurCoefficient: 0.02 property size terminalSize: kterminal.terminalSize property size fontMetrics: kterminal.fontMetrics // Manage copy and paste Connections{ target: copyAction onTriggered: kterminal.copyClipboard(); } Connections{ target: pasteAction onTriggered: kterminal.pasteClipboard() } //When settings are updated sources need to be redrawn. Connections{ target: appSettings onFontScalingChanged: terminalContainer.updateSources(); onFontWidthChanged: terminalContainer.updateSources(); } Connections{ target: terminalContainer onWidthChanged: terminalContainer.updateSources(); onHeightChanged: terminalContainer.updateSources(); } function updateSources() { kterminal.update(); } QMLTermWidget { id: kterminal width: Math.floor(parent.width / (screenScaling * fontWidth)) height: Math.floor(parent.height / screenScaling) colorScheme: "cool-retro-term" smooth: !appSettings.lowResolutionFont enableBold: false fullCursorHeight: true session: QMLTermSession { id: ksession onFinished: { Qt.quit() } } QMLTermScrollbar { id: kterminalScrollbar terminal: kterminal anchors.margins: width * 0.5 width: terminal.fontMetrics.width * 0.75 Rectangle { anchors.fill: parent anchors.topMargin: 1 anchors.bottomMargin: 1 color: "white" radius: width * 0.25 opacity: 0.7 } } FontLoader{ id: fontLoader } function handleFontChange(fontSource, pixelSize, lineSpacing, screenScaling, fontWidth){ fontLoader.source = fontSource; kterminal.antialiasText = !appSettings.lowResolutionFont; font.pixelSize = pixelSize; font.family = fontLoader.name; terminalContainer.fontWidth = fontWidth; terminalContainer.screenScaling = screenScaling; scaleTexture = Math.max(1.0, Math.floor(screenScaling * appSettings.windowScaling)); kterminal.lineSpacing = lineSpacing; } Component.onCompleted: { appSettings.terminalFontChanged.connect(handleFontChange); // Retrieve the variable set in main.cpp if arguments are passed. if (defaultCmd) { ksession.setShellProgram(defaultCmd); ksession.setArgs(defaultCmdArgs); } else if (!defaultCmd && Qt.platform.os === "osx") { // OSX Requires the following default parameters for auto login. ksession.setArgs(["-i", "-l"]); } if (workdir) ksession.initialWorkingDirectory = workdir; ksession.startShellProgram(); forceActiveFocus(); } } Component { id: linuxContextMenu Menu{ id: contextmenu MenuItem{action: copyAction} MenuItem{action: pasteAction} MenuSeparator{} MenuItem{action: fullscreenAction} MenuItem{action: showMenubarAction} MenuSeparator{visible: !appSettings.showMenubar} CRTMainMenuBar{visible: !appSettings.showMenubar} } } Component { id: osxContextMenu Menu{ id: contextmenu MenuItem{action: copyAction} MenuItem{action: pasteAction} } } Loader { id: menuLoader sourceComponent: (Qt.platform.os === "osx" ? osxContextMenu : linuxContextMenu) } property alias contextmenu: menuLoader.item MouseArea{ acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton anchors.fill: parent cursorShape: Qt.IBeamCursor onWheel:{ if(wheel.modifiers & Qt.ControlModifier){ wheel.angleDelta.y > 0 ? zoomIn.trigger() : zoomOut.trigger(); } else { var coord = correctDistortion(wheel.x, wheel.y); kterminal.simulateWheel(coord.x, coord.y, wheel.buttons, wheel.modifiers, wheel.angleDelta); } } onDoubleClicked: { var coord = correctDistortion(mouse.x, mouse.y); kterminal.simulateMouseDoubleClick(coord.x, coord.y, mouse.button, mouse.buttons, mouse.modifiers); } onPressed: { if((!kterminal.terminalUsesMouse || mouse.modifiers & Qt.ShiftModifier) && mouse.button == Qt.RightButton) { contextmenu.popup(); } else { var coord = correctDistortion(mouse.x, mouse.y); kterminal.simulateMousePress(coord.x, coord.y, mouse.button, mouse.buttons, mouse.modifiers) } } onReleased: { var coord = correctDistortion(mouse.x, mouse.y); kterminal.simulateMouseRelease(coord.x, coord.y, mouse.button, mouse.buttons, mouse.modifiers); } onPositionChanged: { var coord = correctDistortion(mouse.x, mouse.y); kterminal.simulateMouseMove(coord.x, coord.y, mouse.button, mouse.buttons, mouse.modifiers); } function correctDistortion(x, y){ x = x / width; y = y / height; var cc = Qt.size(0.5 - x, 0.5 - y); var distortion = (cc.height * cc.height + cc.width * cc.width) * appSettings.screenCurvature; return Qt.point((x - cc.width * (1+distortion) * distortion) * kterminal.width, (y - cc.height * (1+distortion) * distortion) * kterminal.height) } } ShaderEffectSource{ id: kterminalSource sourceItem: kterminal hideSource: true wrapMode: ShaderEffectSource.ClampToEdge visible: false textureSize: Qt.size(kterminal.width * scaleTexture, kterminal.height * scaleTexture); } Loader{ id: blurredSourceLoader asynchronous: true active: mBlur !== 0 sourceComponent: ShaderEffectSource{ id: _blurredSourceEffect sourceItem: blurredTerminalLoader.item recursive: true live: true hideSource: true wrapMode: kterminalSource.wrapMode visible: false function restartBlurSource(){ livetimer.restart(); } Timer{ id: livetimer // The interval assumes 60 fps. This is the time needed burnout a white pixel. // We multiply 1.1 to have a little bit of margin over the theoretical value. // This solution is not extremely clean, but it's probably the best to avoid measuring fps. interval: (1 / motionBlurCoefficient) * 60 * 1.1 running: true onTriggered: _blurredSourceEffect.live = false; } Connections{ target: kterminal onImagePainted:{ _blurredSourceEffect.live = true; livetimer.restart(); } } // Restart blurred source settings change. Connections{ target: appSettings onBurnInChanged: _blurredSourceEffect.restartBlurSource(); onTerminalFontChanged: _blurredSourceEffect.restartBlurSource(); onRasterizationChanged: _blurredSourceEffect.restartBlurSource(); onBurnInQualityChanged: _blurredSourceEffect.restartBlurSource(); } Connections { target: kterminalScrollbar onOpacityChanged: _blurredSourceEffect.restartBlurSource(); } } } Loader{ id: blurredTerminalLoader property int burnInScaling: scaleTexture * appSettings.burnInQuality width: appSettings.lowResolutionFont ? kterminal.width * Math.max(1, burnInScaling) : kterminal.width * scaleTexture * appSettings.burnInQuality height: appSettings.lowResolutionFont ? kterminal.height * Math.max(1, burnInScaling) : kterminal.height * scaleTexture * appSettings.burnInQuality active: mBlur !== 0 asynchronous: true sourceComponent: ShaderEffect { property variant txt_source: kterminalSource property variant blurredSource: blurredSourceLoader.item property real blurCoefficient: motionBlurCoefficient blending: false fragmentShader: "uniform lowp float qt_Opacity;" + "uniform lowp sampler2D txt_source;" + "varying highp vec2 qt_TexCoord0; uniform lowp sampler2D blurredSource; uniform highp float blurCoefficient;" + "float rgb2grey(vec3 v){ return dot(v, vec3(0.21, 0.72, 0.04)); }" + "void main() {" + "vec2 coords = qt_TexCoord0;" + "vec3 origColor = texture2D(txt_source, coords).rgb;" + "vec3 blur_color = texture2D(blurredSource, coords).rgb - vec3(blurCoefficient);" + "vec3 color = min(origColor + blur_color, max(origColor, blur_color));" + "gl_FragColor = vec4(color, rgb2grey(color - origColor));" + "}" onStatusChanged: if (log) console.log(log) //Print warning messages } } }