You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
329 lines
7.6 KiB
329 lines
7.6 KiB
/* |
|
SPDX-FileCopyrightText: 2007 Robert Knight <robertknight@gmail.com> |
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later |
|
*/ |
|
|
|
// Own |
|
#include "ScreenWindow.h" |
|
|
|
// Konsole |
|
|
|
using namespace Konsole; |
|
|
|
ScreenWindow::ScreenWindow(Screen *screen, QObject *parent) |
|
: QObject(parent) |
|
, _screen(nullptr) |
|
, _windowBuffer(nullptr) |
|
, _windowBufferSize(0) |
|
, _bufferNeedsUpdate(true) |
|
, _windowLines(1) |
|
, _currentLine(0) |
|
, _currentResultLine(-1) |
|
, _trackOutput(true) |
|
, _scrollCount(0) |
|
{ |
|
setScreen(screen); |
|
} |
|
|
|
ScreenWindow::~ScreenWindow() |
|
{ |
|
delete[] _windowBuffer; |
|
} |
|
|
|
void ScreenWindow::setScreen(Screen *screen) |
|
{ |
|
Q_ASSERT(screen); |
|
|
|
if (screen == _screen) { |
|
return; |
|
} |
|
|
|
Q_EMIT screenAboutToChange(); |
|
_screen = screen; |
|
} |
|
|
|
Screen *ScreenWindow::screen() const |
|
{ |
|
return _screen; |
|
} |
|
|
|
Character *ScreenWindow::getImage() |
|
{ |
|
// reallocate internal buffer if the window size has changed |
|
int size = windowLines() * windowColumns(); |
|
if (_windowBuffer == nullptr || _windowBufferSize != size) { |
|
delete[] _windowBuffer; |
|
_windowBufferSize = size; |
|
_windowBuffer = new Character[size]; |
|
_bufferNeedsUpdate = true; |
|
} |
|
|
|
if (!_bufferNeedsUpdate) { |
|
return _windowBuffer; |
|
} |
|
|
|
_screen->getImage(_windowBuffer, size, currentLine(), endWindowLine()); |
|
|
|
// this window may look beyond the end of the screen, in which |
|
// case there will be an unused area which needs to be filled |
|
// with blank characters |
|
fillUnusedArea(); |
|
|
|
_bufferNeedsUpdate = false; |
|
return _windowBuffer; |
|
} |
|
|
|
void ScreenWindow::fillUnusedArea() |
|
{ |
|
int screenEndLine = _screen->getHistLines() + _screen->getLines() - 1; |
|
int windowEndLine = currentLine() + windowLines() - 1; |
|
|
|
int unusedLines = windowEndLine - screenEndLine; |
|
|
|
// stop when unusedLines is negative; there is an issue w/ charsToFill |
|
// being greater than an int can hold |
|
if (unusedLines <= 0) { |
|
return; |
|
} |
|
|
|
int charsToFill = unusedLines * windowColumns(); |
|
|
|
Screen::fillWithDefaultChar(_windowBuffer + _windowBufferSize - charsToFill, charsToFill); |
|
} |
|
|
|
// return the index of the line at the end of this window, or if this window |
|
// goes beyond the end of the screen, the index of the line at the end |
|
// of the screen. |
|
// |
|
// when passing a line number to a Screen method, the line number should |
|
// never be more than endWindowLine() |
|
// |
|
int ScreenWindow::endWindowLine() const |
|
{ |
|
return qMin(currentLine() + windowLines() - 1, lineCount() - 1); |
|
} |
|
|
|
QVector<LineProperty> ScreenWindow::getLineProperties() |
|
{ |
|
QVector<LineProperty> result = _screen->getLineProperties(currentLine(), endWindowLine()); |
|
|
|
if (result.count() != windowLines()) { |
|
result.resize(windowLines()); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
QString ScreenWindow::selectedText(const Screen::DecodingOptions options) const |
|
{ |
|
return _screen->selectedText(options); |
|
} |
|
|
|
void ScreenWindow::getSelectionStart(int &column, int &line) |
|
{ |
|
_screen->getSelectionStart(column, line); |
|
line -= currentLine(); |
|
} |
|
|
|
void ScreenWindow::getSelectionEnd(int &column, int &line) |
|
{ |
|
_screen->getSelectionEnd(column, line); |
|
line -= currentLine(); |
|
} |
|
|
|
void ScreenWindow::setSelectionStart(int column, int line, bool columnMode) |
|
{ |
|
_screen->setSelectionStart(column, line + currentLine(), columnMode); |
|
|
|
_bufferNeedsUpdate = true; |
|
Q_EMIT selectionChanged(); |
|
} |
|
|
|
void ScreenWindow::setSelectionEnd(int column, int line) |
|
{ |
|
_screen->setSelectionEnd(column, line + currentLine()); |
|
|
|
_bufferNeedsUpdate = true; |
|
Q_EMIT selectionChanged(); |
|
} |
|
|
|
void ScreenWindow::setSelectionByLineRange(int start, int end) |
|
{ |
|
clearSelection(); |
|
|
|
_screen->setSelectionStart(0, start, false); |
|
_screen->setSelectionEnd(windowColumns(), end); |
|
|
|
_bufferNeedsUpdate = true; |
|
Q_EMIT selectionChanged(); |
|
} |
|
|
|
bool ScreenWindow::isSelected(int column, int line) |
|
{ |
|
return _screen->isSelected(column, qMin(line + currentLine(), endWindowLine())); |
|
} |
|
|
|
void ScreenWindow::clearSelection() |
|
{ |
|
_screen->clearSelection(); |
|
|
|
Q_EMIT selectionChanged(); |
|
} |
|
|
|
void ScreenWindow::setWindowLines(int lines) |
|
{ |
|
Q_ASSERT(lines > 0); |
|
_windowLines = lines; |
|
} |
|
|
|
int ScreenWindow::windowLines() const |
|
{ |
|
return _windowLines; |
|
} |
|
|
|
int ScreenWindow::windowColumns() const |
|
{ |
|
return _screen->getColumns(); |
|
} |
|
|
|
int ScreenWindow::lineCount() const |
|
{ |
|
return _screen->getHistLines() + _screen->getLines(); |
|
} |
|
|
|
int ScreenWindow::columnCount() const |
|
{ |
|
return _screen->getColumns(); |
|
} |
|
|
|
QPoint ScreenWindow::cursorPosition() const |
|
{ |
|
QPoint position; |
|
|
|
position.setX(_screen->getCursorX()); |
|
position.setY(_screen->getCursorY()); |
|
|
|
return position; |
|
} |
|
|
|
int ScreenWindow::currentLine() const |
|
{ |
|
return qBound(0, _currentLine, lineCount() - windowLines()); |
|
} |
|
|
|
int ScreenWindow::currentResultLine() const |
|
{ |
|
return _currentResultLine; |
|
} |
|
|
|
void ScreenWindow::setCurrentResultLine(int line) |
|
{ |
|
if (_currentResultLine == line) { |
|
return; |
|
} |
|
|
|
_currentResultLine = line; |
|
Q_EMIT currentResultLineChanged(); |
|
} |
|
|
|
void ScreenWindow::scrollBy(RelativeScrollMode mode, int amount, bool fullPage) |
|
{ |
|
if (mode == ScrollLines) { |
|
scrollTo(currentLine() + amount); |
|
} else if (mode == ScrollPages) { |
|
if (fullPage) { |
|
scrollTo(currentLine() + amount * (windowLines())); |
|
} else { |
|
scrollTo(currentLine() + amount * (windowLines() / 2)); |
|
} |
|
} |
|
} |
|
|
|
bool ScreenWindow::atEndOfOutput() const |
|
{ |
|
return currentLine() == (lineCount() - windowLines()); |
|
} |
|
|
|
void ScreenWindow::scrollTo(int line) |
|
{ |
|
int maxCurrentLineNumber = lineCount() - windowLines(); |
|
line = qBound(0, line, maxCurrentLineNumber); |
|
|
|
const int delta = line - _currentLine; |
|
_currentLine = line; |
|
|
|
// keep track of number of lines scrolled by, |
|
// this can be reset by calling resetScrollCount() |
|
_scrollCount += delta; |
|
|
|
_bufferNeedsUpdate = true; |
|
|
|
Q_EMIT scrolled(_currentLine); |
|
} |
|
|
|
void ScreenWindow::setTrackOutput(bool trackOutput) |
|
{ |
|
_trackOutput = trackOutput; |
|
} |
|
|
|
bool ScreenWindow::trackOutput() const |
|
{ |
|
return _trackOutput; |
|
} |
|
|
|
int ScreenWindow::scrollCount() const |
|
{ |
|
return _scrollCount; |
|
} |
|
|
|
void ScreenWindow::resetScrollCount() |
|
{ |
|
_scrollCount = 0; |
|
} |
|
|
|
QRect ScreenWindow::scrollRegion() const |
|
{ |
|
bool equalToScreenSize = windowLines() == _screen->getLines(); |
|
|
|
if (atEndOfOutput() && equalToScreenSize) { |
|
return _screen->lastScrolledRegion(); |
|
} |
|
return {0, 0, windowColumns(), windowLines()}; |
|
} |
|
|
|
void ScreenWindow::updateCurrentLine() |
|
{ |
|
if (!_screen->isResize()) { |
|
return; |
|
} |
|
if (_currentLine > 0) { |
|
_currentLine -= _screen->getOldTotalLines() - lineCount(); |
|
} |
|
_currentLine = qBound(0, _currentLine, lineCount() - windowLines()); |
|
} |
|
|
|
void ScreenWindow::notifyOutputChanged() |
|
{ |
|
// move window to the bottom of the screen and update scroll count |
|
// if this window is currently tracking the bottom of the screen |
|
if (_trackOutput) { |
|
_scrollCount -= _screen->scrolledLines(); |
|
_currentLine = qMax(0, _screen->getHistLines() - (windowLines() - _screen->getLines())); |
|
} else { |
|
// if the history is not unlimited then it may |
|
// have run out of space and dropped the oldest |
|
// lines of output - in this case the screen |
|
// window's current line number will need to |
|
// be adjusted - otherwise the output will scroll |
|
_currentLine = qMax(0, _currentLine - _screen->droppedLines()); |
|
|
|
// ensure that the screen window's current position does |
|
// not go beyond the bottom of the screen |
|
_currentLine = qMin(_currentLine, _screen->getHistLines()); |
|
} |
|
|
|
_bufferNeedsUpdate = true; |
|
|
|
Q_EMIT outputChanged(); |
|
}
|
|
|