Improve terminal theming, cursor UX, and size negotiation

This commit is contained in:
Keith Smith
2026-03-01 10:14:43 -07:00
parent 20ee48db32
commit c3369b8e48
9 changed files with 141 additions and 24 deletions

View File

@@ -3,7 +3,11 @@
#include <QApplication>
#include <QClipboard>
#include <QColor>
#include <QFocusEvent>
#include <QFontMetrics>
#include <QKeyEvent>
#include <QResizeEvent>
#include <QTimer>
#include <QTextCursor>
#include <algorithm>
@@ -21,13 +25,21 @@ TerminalView::TerminalView(QWidget* parent)
m_hasFgColor(false),
m_hasBgColor(false)
{
setReadOnly(true);
setReadOnly(false);
setUndoRedoEnabled(false);
document()->setMaximumBlockCount(4000);
setAcceptRichText(false);
setLineWrapMode(QTextEdit::NoWrap);
setContextMenuPolicy(Qt::NoContextMenu);
setCursorWidth(2);
document()->setMaximumBlockCount(4000);
applyThemePalette(paletteByName(QStringLiteral("Dark")));
resetSgrState();
QTimer::singleShot(0, this, [this]() {
moveCursor(QTextCursor::End);
emitTerminalSize();
});
}
QStringList TerminalView::themeNames()
@@ -123,8 +135,19 @@ void TerminalView::keyPressEvent(QKeyEvent* event)
return;
}
moveCursor(QTextCursor::End);
const Qt::KeyboardModifiers modifiers = event->modifiers();
if (modifiers == (Qt::ControlModifier | Qt::ShiftModifier)
&& event->key() == Qt::Key_C) {
const QString selected = textCursor().selectedText();
if (!selected.isEmpty()) {
QApplication::clipboard()->setText(selected);
}
return;
}
if (modifiers == Qt::ControlModifier) {
switch (event->key()) {
case Qt::Key_C:
@@ -180,8 +203,18 @@ void TerminalView::keyPressEvent(QKeyEvent* event)
emit inputGenerated(text);
return;
}
}
QTextEdit::keyPressEvent(event);
void TerminalView::focusInEvent(QFocusEvent* event)
{
QTextEdit::focusInEvent(event);
moveCursor(QTextCursor::End);
}
void TerminalView::resizeEvent(QResizeEvent* event)
{
QTextEdit::resizeEvent(event);
emitTerminalSize();
}
TerminalView::ThemePalette TerminalView::paletteByName(const QString& themeName)
@@ -190,23 +223,23 @@ TerminalView::ThemePalette TerminalView::paletteByName(const QString& themeName)
if (theme == QStringLiteral("light")) {
return ThemePalette{QStringLiteral("Light"),
QColor(QStringLiteral("#fafafa")),
QColor(QStringLiteral("#202124")),
QColor(QStringLiteral("#ececec")),
QColor(QStringLiteral("#000000")),
{QColor(QStringLiteral("#000000")),
QColor(QStringLiteral("#a31515")),
QColor(QStringLiteral("#aa0000")),
QColor(QStringLiteral("#008000")),
QColor(QStringLiteral("#795e26")),
QColor(QStringLiteral("#0000ff")),
QColor(QStringLiteral("#af00db")),
QColor(QStringLiteral("#0451a5")),
QColor(QStringLiteral("#666666"))},
{QColor(QStringLiteral("#7f7f7f")),
QColor(QStringLiteral("#cd3131")),
QColor(QStringLiteral("#14a10e")),
QColor(QStringLiteral("#b5ba00")),
QColor(QStringLiteral("#0451a5")),
QColor(QStringLiteral("#bc05bc")),
QColor(QStringLiteral("#0598bc")),
QColor(QStringLiteral("#7a5f00")),
QColor(QStringLiteral("#0033cc")),
QColor(QStringLiteral("#8a00a8")),
QColor(QStringLiteral("#005f87")),
QColor(QStringLiteral("#333333"))},
{QColor(QStringLiteral("#5c5c5c")),
QColor(QStringLiteral("#d30000")),
QColor(QStringLiteral("#00a000")),
QColor(QStringLiteral("#9a7700")),
QColor(QStringLiteral("#0055ff")),
QColor(QStringLiteral("#b300db")),
QColor(QStringLiteral("#007ea7")),
QColor(QStringLiteral("#111111"))}};
}
@@ -338,7 +371,7 @@ void TerminalView::handleSgrSequence(const QString& params)
for (int i = 0; i < parts.size(); ++i) {
const QString part = parts.at(i).trimmed();
bool ok = false;
int code = part.isEmpty() ? 0 : part.toInt(&ok);
const int code = part.isEmpty() ? 0 : part.toInt(&ok);
if (!ok && !part.isEmpty()) {
continue;
}
@@ -399,7 +432,7 @@ void TerminalView::handleSgrSequence(const QString& params)
if (mode == 5 && i + 2 < parts.size()) {
const int index = parts.at(i + 2).toInt(&ok);
if (ok) {
QColor color = colorFrom256Index(index);
const QColor color = colorFrom256Index(index);
if (background) {
m_bgColor = color;
m_hasBgColor = true;
@@ -466,3 +499,22 @@ QColor TerminalView::paletteColor(bool, int index, bool bright) const
return bright ? m_palette.bright.at(static_cast<size_t>(safeIndex))
: m_palette.normal.at(static_cast<size_t>(safeIndex));
}
int TerminalView::terminalColumns() const
{
const QFontMetrics metrics(font());
const int cellWidth = std::max(1, metrics.horizontalAdvance(QChar::fromLatin1('M')));
return std::max(1, viewport()->width() / cellWidth);
}
int TerminalView::terminalRows() const
{
const QFontMetrics metrics(font());
const int cellHeight = std::max(1, metrics.lineSpacing());
return std::max(1, viewport()->height() / cellHeight);
}
void TerminalView::emitTerminalSize()
{
emit terminalSizeChanged(terminalColumns(), terminalRows());
}