Skip to content

Commit

Permalink
[contour] Implement config option profiles.*.margin
Browse files Browse the repository at this point in the history
... to allow customizing the horizontal / vertical margins
  • Loading branch information
christianparpart committed Dec 25, 2023
1 parent e1fcb13 commit 9a44caf
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 126 deletions.
13 changes: 13 additions & 0 deletions docs/configuration/profiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,19 @@ profiles:
maximized: false
```

### `margins`

Enforces a horizontal and vertical margin to respect on both sides of the terminal.
This is particularily useful on operating systems (like MacOS) that draw the border frame into the main widgets space,
or simply to create some artificial space to improve the user's focus.

```yaml
profiles:
profile_name:
margins:
horizontal: 5
vertical: 0
```


### `bell`
Expand Down
1 change: 1 addition & 0 deletions metainfo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
<li>Changes VT sequence `DECSCUSR` (`CSI ? 0 SP q` and `CSI ? SP q`) to reset to user-configured cursor style (#1377).</li>
<li>Remove `contour-latest` terminfo file. Please use `contour` terminfo instead.</li>
<li>Adds `Command` as modifier to input mappings on MacOS to work along with `Meta` for convenience reasons (#1379).</li>
<li>Adds config option `profiles.*.margins` to allow customizing the horizontal / vertical margins (#1384).</li>
</ul>
</description>
</release>
Expand Down
5 changes: 5 additions & 0 deletions src/contour/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1555,6 +1555,11 @@ namespace
else
logger()("Invalid Terminal ID \"{}\", specified", strValue);

tryLoadChildRelative(
usedKeys, profile, basePath, "margins.horizontal", terminalProfile.margins.horizontal, logger);
tryLoadChildRelative(
usedKeys, profile, basePath, "margins.vertical", terminalProfile.margins.vertical, logger);

tryLoadChildRelative(usedKeys,
profile,
basePath,
Expand Down
21 changes: 21 additions & 0 deletions src/contour/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,15 @@ struct TerminalProfile

std::string wmClass;

// Horizontal and vertical margins in pixels.
//
// Important, DPI is not yet applied to these values.
struct WindowMargins
{
unsigned horizontal = 0;
unsigned vertical = 0;
} margins;

vtbackend::PageSize terminalSize = { vtbackend::LineCount(10), vtbackend::ColumnCount(40) };
vtbackend::VTType terminalId = vtbackend::VTType::VT525;

Expand Down Expand Up @@ -407,4 +416,16 @@ struct fmt::formatter<contour::config::ScrollBarPosition>
return fmt::format_to(ctx.out(), "{}", static_cast<unsigned>(value));
}
};

template <>
struct fmt::formatter<contour::config::TerminalProfile::WindowMargins>: public fmt::formatter<std::string>
{
using WindowMargins = contour::config::TerminalProfile::WindowMargins;
auto format(WindowMargins margins, format_context& ctx) -> format_context::iterator
{
return formatter<std::string>::format(fmt::format("{}x+{}y", margins.horizontal, margins.vertical),
ctx);
}
};

// }}}
13 changes: 4 additions & 9 deletions src/contour/TerminalSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,10 +696,10 @@ void TerminalSession::requestWindowResize(LineCount lines, ColumnCount columns)
_display->post([this, lines, columns]() { _display->resizeWindow(lines, columns); });
}

void TerminalSession::requestWindowResize(QJSValue w, QJSValue h)
void TerminalSession::adaptToWidgetSize()
{
requestWindowResize(Width::cast_from(w.toNumber() * contentScale()),
Height::cast_from(h.toNumber() * contentScale()));
if (_display)
_display->post([this]() { _display->adaptToWidgetSize(); });
}

void TerminalSession::requestWindowResize(Width width, Height height)
Expand Down Expand Up @@ -1493,13 +1493,8 @@ void TerminalSession::configureDisplay()
_display->toggleFullScreen();

_terminal.setRefreshRate(_display->refreshRate());
auto const pageSize = PageSize {
LineCount(unbox<int>(_display->pixelSize().height) / unbox<int>(_display->cellSize().height)),
ColumnCount(unbox<int>(_display->pixelSize().width) / unbox<int>(_display->cellSize().width)),
};
_display->setPageSize(pageSize);
_display->setFonts(_profile.fonts);
// TODO: maybe update margin after this call?
adaptToWidgetSize();

_display->setHyperlinkDecoration(_profile.hyperlinkDecoration.normal, _profile.hyperlinkDecoration.hover);

Expand Down
2 changes: 1 addition & 1 deletion src/contour/TerminalSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ class TerminalSession: public QAbstractItemModel, public vtbackend::Terminal::Ev
Q_INVOKABLE void applyPendingFontChange(bool answer, bool remember);
Q_INVOKABLE void executePendingBufferCapture(bool answer, bool remember);
Q_INVOKABLE void executeShowHostWritableStatusLine(bool answer, bool remember);
Q_INVOKABLE void requestWindowResize(QJSValue w, QJSValue h);
Q_INVOKABLE void adaptToWidgetSize();

void updateColorPreference(vtbackend::ColorPreference preference);

Expand Down
10 changes: 10 additions & 0 deletions src/contour/contour.yml
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,16 @@ profiles:
columns: 80
lines: 25

# Window margins
#
# The margin values are applied on both sides and are given in pixels
# with DPI yet to be applied to these values.
margins:
# Horizontal (left/right) margins.
horizontal: 5
# Vertical (top/bottom) margins.
vertical: 5

history:
# Number of lines to preserve (-1 for infinite).
limit: 1000
Expand Down
105 changes: 51 additions & 54 deletions src/contour/display/TerminalDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,9 @@ void TerminalDisplay::sizeChanged()

auto const qtBaseDisplaySize =
vtbackend::ImageSize { Width::cast_from(width()), Height::cast_from(height()) };
auto const newPixelSize = qtBaseDisplaySize * contentScale();
displayLog()("Resizing view to {}x{} virtual ({} actual).", width(), height(), newPixelSize);
applyResize(newPixelSize, *_session, *_renderer);
auto const actualPixelSize = qtBaseDisplaySize * contentScale();
displayLog()("Resizing view to {}x{} virtual ({} actual).", width(), height(), actualPixelSize);
applyResize(actualPixelSize, *_session, *_renderer);
}

void TerminalDisplay::handleWindowChanged(QQuickWindow* newWindow)
Expand Down Expand Up @@ -444,7 +444,8 @@ void TerminalDisplay::applyFontDPI()
if (!_renderTarget)
return;

auto const newPixelSize = vtbackend::ImageSize { Width::cast_from(width()), Height::cast_from(height()) };
auto const newPixelSize =
vtbackend::ImageSize { Width::cast_from(width()), Height::cast_from(height()) } * contentScale();

// Apply resize on same window metrics propagates proper recalculations and repaint.
applyResize(newPixelSize, *_session, *_renderer);
Expand Down Expand Up @@ -615,9 +616,9 @@ void TerminalDisplay::createRenderer()
{
auto const qtBaseDisplaySize =
ImageSize { vtbackend::Width::cast_from(width()), vtbackend::Height::cast_from(height()) };
_renderer->setMargin(computeMargin(gridMetrics().cellSize, pageSize(), qtBaseDisplaySize));
// resize widget (same pixels, but adjusted terminal rows/columns and margin)

auto const actualDisplaySize = qtBaseDisplaySize * contentScale();

applyResize(actualDisplaySize, *_session, *_renderer);
}
// }}}
Expand Down Expand Up @@ -940,34 +941,48 @@ double TerminalDisplay::contentScale() const
return window()->devicePixelRatio();
}

/// Computes the required size of the widget to fit the given terminal size.
///
/// @param terminalSize the terminal size in rows and columns
/// @param cellSize the size of a single cell in pixels (with content scale already applied)
constexpr ImageSize computeRequiredSize(config::TerminalProfile::WindowMargins margins,
ImageSize cellSize,
PageSize totalPageSize) noexcept
{
// We multiply by 2 because the margins are applied to both sides of the terminal.
auto const marginSize = ImageSize { vtbackend::Width::cast_from(margins.horizontal * 2),
vtbackend::Height::cast_from(margins.vertical * 2) };

return (cellSize * totalPageSize + marginSize);
}

void TerminalDisplay::updateImplicitSize()
{
assert(_renderer);
assert(_session);
assert(window());

// implicit width/height
auto const dpr = contentScale();
auto const implicitViewSize = _renderer->cellSize() * _session->terminal().totalPageSize() * (1.0 / dpr);
setImplicitWidth(unbox<qreal>(implicitViewSize.width));
setImplicitHeight(unbox<qreal>(implicitViewSize.height));
auto const requiredSize = computeRequiredSize(_session->profile().margins,
_renderer->cellSize() * (1.0 / contentScale()),
_session->terminal().totalPageSize());

fmt::print("updateImplicitSize: {}, margin {}\n", requiredSize, _session->profile().margins);

setImplicitWidth(unbox<qreal>(requiredSize.width));
setImplicitHeight(unbox<qreal>(requiredSize.height));
}

void TerminalDisplay::updateMinimumSize()
{
Require(window());
Require(_renderer);
assert(_session);

Require(window());

// minimum size
auto constexpr MinimumGridSize = PageSize { LineCount(5), ColumnCount(10) };
auto const minSize =
ImageSize { Width::cast_from(unbox<int>(gridMetrics().cellSize.width) * *MinimumGridSize.columns),
Height::cast_from(unbox<int>(gridMetrics().cellSize.width) * *MinimumGridSize.lines) };
auto const scaledMinSize = minSize / contentScale();
auto constexpr MinimumTotalPageSize = PageSize { LineCount(5), ColumnCount(10) };
auto const minimumSize = computeRequiredSize(
_session->profile().margins, _renderer->cellSize() * (1.0 / contentScale()), MinimumTotalPageSize);

window()->setMinimumSize(QSize(scaledMinSize.width.as<int>(), scaledMinSize.height.as<int>()));
window()->setMinimumSize(QSize(unbox<int>(minimumSize.width), unbox<int>(minimumSize.height)));
}
// }}}

Expand Down Expand Up @@ -1136,6 +1151,18 @@ void TerminalDisplay::notify(std::string_view /*_title*/, std::string_view /*_bo
// TODO: showNotification callback to Controller?
}

void TerminalDisplay::adaptToWidgetSize()
{
// Resize widget (same pixels, but adjusted terminal rows/columns and margin)
Require(_renderer != nullptr);
Require(_session != nullptr);

auto const qtBaseDisplaySize =
ImageSize { vtbackend::Width::cast_from(width()), vtbackend::Height::cast_from(height()) };
auto const actualDisplaySize = qtBaseDisplaySize * contentScale();
applyResize(actualDisplaySize, *_session, *_renderer);
}

void TerminalDisplay::resizeWindow(vtbackend::Width newWidth, vtbackend::Height newHeight)
{
Require(_session != nullptr);
Expand All @@ -1146,26 +1173,7 @@ void TerminalDisplay::resizeWindow(vtbackend::Width newWidth, vtbackend::Height
return;
}

auto const pixelsAvailable =
vtbackend::ImageSize { vtbackend::Width::cast_from(*newWidth ? *newWidth : (unsigned) width()),
vtbackend::Height::cast_from(*newHeight ? *newHeight : (unsigned) height()) };

auto const newPageSize =
PageSize { .lines = vtbackend::LineCount(unbox<int>(pixelsAvailable.height)
/ unbox<int>(gridMetrics().cellSize.height)),
.columns = vtbackend::ColumnCount(unbox<int>(pixelsAvailable.width)
/ unbox<int>(gridMetrics().cellSize.width)) };

auto const newPixelsUsed = vtbackend::ImageSize {
vtbackend::Width::cast_from(unbox(newPageSize.columns) * unbox<int>(gridMetrics().cellSize.width)),
vtbackend::Height::cast_from(unbox(newPageSize.lines) * unbox<int>(gridMetrics().cellSize.height))
};

// setSizePolicy(QSizePolicy::Policy::Fixed, QSizePolicy::Policy::Fixed);
const_cast<config::TerminalProfile&>(profile()).terminalSize = newPageSize;
_renderer->setPageSize(newPageSize);
auto const l = scoped_lock { terminal() };
terminal().resizeScreen(newPageSize, newPixelsUsed);
applyResize(vtbackend::ImageSize { newWidth, newHeight }, *_session, *_renderer);
}

void TerminalDisplay::resizeWindow(vtbackend::LineCount newLineCount, vtbackend::ColumnCount newColumnCount)
Expand Down Expand Up @@ -1195,12 +1203,7 @@ void TerminalDisplay::setFonts(vtrasterizer::FontDescriptions fontDescriptions)
Require(_session != nullptr);
Require(_renderTarget != nullptr);

if (applyFontDescription(gridMetrics().cellSize,
pageSize(),
pixelSize(),
fontDPI(),
*_renderer,
std::move(fontDescriptions)))
if (applyFontDescription(fontDPI(), *_renderer, std::move(fontDescriptions)))
{
// resize widget (same pixels, but adjusted terminal rows/columns and margin)
applyResize(pixelSize(), *_session, *_renderer);
Expand All @@ -1210,20 +1213,14 @@ void TerminalDisplay::setFonts(vtrasterizer::FontDescriptions fontDescriptions)

bool TerminalDisplay::setFontSize(text::font_size newFontSize)
{
Require(_session != nullptr);
Require(_renderTarget != nullptr);
Require(_renderer != nullptr);

displayLog()("Setting display font size and recompute metrics: {}pt", newFontSize.pt);

if (!_renderer->setFontSize(newFontSize))
return false;

auto const qtBaseDisplaySize =
ImageSize { vtbackend::Width::cast_from(width()), vtbackend::Height::cast_from(height()) };
_renderer->setMargin(computeMargin(gridMetrics().cellSize, pageSize(), qtBaseDisplaySize));
// resize widget (same pixels, but adjusted terminal rows/columns and margin)
auto const actualDisplaySize = qtBaseDisplaySize * contentScale();
applyResize(actualDisplaySize, *_session, *_renderer);
adaptToWidgetSize();
updateMinimumSize();
// logDisplayInfo();
return true;
Expand Down
14 changes: 12 additions & 2 deletions src/contour/display/TerminalDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ class TerminalDisplay: public QQuickItem
[[nodiscard]] vtbackend::ImageSize pixelSize() const;
[[nodiscard]] vtbackend::ImageSize cellSize() const;

// general events
void adaptToWidgetSize();

// (user requested) actions
vtbackend::FontDef getFontDef();
static void copyToClipboard(std::string_view /*_data*/);
Expand Down Expand Up @@ -212,10 +215,17 @@ class TerminalDisplay: public QQuickItem
void watchKdeDpiSetting();
[[nodiscard]] float uptime() const noexcept;

[[nodiscard]] vtbackend::PageSize pageSize() const
[[nodiscard]] vtbackend::PageSize calculatePageSize() const
{
assert(_renderer);
return pageSizeForPixels(pixelSize(), _renderer->gridMetrics().cellSize);
assert(_session);

// auto const availablePixels = gridMetrics().cellSize * _session->terminal().pageSize();
auto const availablePixels = vtbackend::ImageSize { vtbackend::Width::cast_from(width()),
vtbackend::Height::cast_from(height()) };
return pageSizeForPixels(availablePixels,
_renderer->gridMetrics().cellSize,
applyContentScale(_session->profile().margins, _session->contentScale()));
}

void updateMinimumSize();
Expand Down
Loading

0 comments on commit 9a44caf

Please sign in to comment.