diff --git a/docs/configuration/profiles.md b/docs/configuration/profiles.md index 380a2aded0..220f314425 100644 --- a/docs/configuration/profiles.md +++ b/docs/configuration/profiles.md @@ -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` diff --git a/metainfo.xml b/metainfo.xml index e25b78ea89..def97a2ba7 100644 --- a/metainfo.xml +++ b/metainfo.xml @@ -111,6 +111,7 @@
  • Changes VT sequence `DECSCUSR` (`CSI ? 0 SP q` and `CSI ? SP q`) to reset to user-configured cursor style (#1377).
  • Remove `contour-latest` terminfo file. Please use `contour` terminfo instead.
  • Adds `Command` as modifier to input mappings on MacOS to work along with `Meta` for convenience reasons (#1379).
  • +
  • Adds config option `profiles.*.margins` to allow customizing the horizontal / vertical margins (#1384).
  • diff --git a/src/contour/Config.cpp b/src/contour/Config.cpp index aa0788b698..b587793f59 100644 --- a/src/contour/Config.cpp +++ b/src/contour/Config.cpp @@ -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, diff --git a/src/contour/Config.h b/src/contour/Config.h index 3c3e4e1eaa..d1354e2bff 100644 --- a/src/contour/Config.h +++ b/src/contour/Config.h @@ -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; @@ -407,4 +416,16 @@ struct fmt::formatter return fmt::format_to(ctx.out(), "{}", static_cast(value)); } }; + +template <> +struct fmt::formatter: public fmt::formatter +{ + using WindowMargins = contour::config::TerminalProfile::WindowMargins; + auto format(WindowMargins margins, format_context& ctx) -> format_context::iterator + { + return formatter::format(fmt::format("{}x+{}y", margins.horizontal, margins.vertical), + ctx); + } +}; + // }}} diff --git a/src/contour/TerminalSession.cpp b/src/contour/TerminalSession.cpp index 1f6550e04a..06b5f66f88 100644 --- a/src/contour/TerminalSession.cpp +++ b/src/contour/TerminalSession.cpp @@ -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) @@ -1493,13 +1493,8 @@ void TerminalSession::configureDisplay() _display->toggleFullScreen(); _terminal.setRefreshRate(_display->refreshRate()); - auto const pageSize = PageSize { - LineCount(unbox(_display->pixelSize().height) / unbox(_display->cellSize().height)), - ColumnCount(unbox(_display->pixelSize().width) / unbox(_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); diff --git a/src/contour/TerminalSession.h b/src/contour/TerminalSession.h index 6a1050a0db..a1ce9289da 100644 --- a/src/contour/TerminalSession.h +++ b/src/contour/TerminalSession.h @@ -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); diff --git a/src/contour/contour.yml b/src/contour/contour.yml index 843d115b68..85e2530eef 100644 --- a/src/contour/contour.yml +++ b/src/contour/contour.yml @@ -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 diff --git a/src/contour/display/TerminalDisplay.cpp b/src/contour/display/TerminalDisplay.cpp index 367ef2cdf9..ce0499fa30 100644 --- a/src/contour/display/TerminalDisplay.cpp +++ b/src/contour/display/TerminalDisplay.cpp @@ -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) @@ -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); @@ -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); } // }}} @@ -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(implicitViewSize.width)); - setImplicitHeight(unbox(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(requiredSize.width)); + setImplicitHeight(unbox(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(gridMetrics().cellSize.width) * *MinimumGridSize.columns), - Height::cast_from(unbox(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(), scaledMinSize.height.as())); + window()->setMinimumSize(QSize(unbox(minimumSize.width), unbox(minimumSize.height))); } // }}} @@ -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); @@ -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(pixelsAvailable.height) - / unbox(gridMetrics().cellSize.height)), - .columns = vtbackend::ColumnCount(unbox(pixelsAvailable.width) - / unbox(gridMetrics().cellSize.width)) }; - - auto const newPixelsUsed = vtbackend::ImageSize { - vtbackend::Width::cast_from(unbox(newPageSize.columns) * unbox(gridMetrics().cellSize.width)), - vtbackend::Height::cast_from(unbox(newPageSize.lines) * unbox(gridMetrics().cellSize.height)) - }; - - // setSizePolicy(QSizePolicy::Policy::Fixed, QSizePolicy::Policy::Fixed); - const_cast(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) @@ -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); @@ -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; diff --git a/src/contour/display/TerminalDisplay.h b/src/contour/display/TerminalDisplay.h index 7b46ec7003..3a420bdde5 100644 --- a/src/contour/display/TerminalDisplay.h +++ b/src/contour/display/TerminalDisplay.h @@ -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*/); @@ -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(); diff --git a/src/contour/helper.cpp b/src/contour/helper.cpp index f9182dd471..3b4122b44c 100644 --- a/src/contour/helper.cpp +++ b/src/contour/helper.cpp @@ -54,59 +54,68 @@ namespace { vtbackend::CellLocation makeMouseCellLocation(int x, int y, TerminalSession const& session) noexcept { - auto constexpr MarginTop = 0; - auto constexpr MarginLeft = 0; - auto const pageSize = session.terminal().totalPageSize(); auto const cellSize = session.display()->cellSize(); auto const dpr = session.contentScale(); + auto const marginTop = static_cast(session.profile().margins.vertical * dpr); + auto const marginLeft = static_cast(session.profile().margins.horizontal * dpr); + auto const sx = int(double(x) * dpr); auto const sy = int(double(y) * dpr); auto const row = vtbackend::LineOffset( - clamp((sy - MarginTop) / cellSize.height.as(), 0, *pageSize.lines - 1)); + clamp((sy - marginTop) / cellSize.height.as(), 0, *pageSize.lines - 1)); auto const col = vtbackend::ColumnOffset( - clamp((sx - MarginLeft) / cellSize.width.as(), 0, *pageSize.columns - 1)); + clamp((sx - marginLeft) / cellSize.width.as(), 0, *pageSize.columns - 1)); return { row, col }; } - PixelCoordinate makeMousePixelPosition(QHoverEvent* event, double dpr) noexcept + PixelCoordinate makeMousePixelPosition(QHoverEvent* event, + config::TerminalProfile::WindowMargins margins, + double dpr) noexcept { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) auto const position = event->position(); #else auto const position = event->pos(); #endif - // TODO: apply margin once supported - return PixelCoordinate { PixelCoordinate::X { int(double(position.x()) * dpr) }, - PixelCoordinate::Y { int(double(position.y()) * dpr) } }; + auto const marginLeft = static_cast(margins.horizontal * dpr); + auto const marginTop = static_cast(margins.vertical * dpr); + return PixelCoordinate { PixelCoordinate::X { int(double(position.x()) * dpr) - marginLeft }, + PixelCoordinate::Y { int(double(position.y()) * dpr) - marginTop } }; } - PixelCoordinate makeMousePixelPosition(QMouseEvent* event, double dpr) noexcept + PixelCoordinate makeMousePixelPosition(QMouseEvent* event, + config::TerminalProfile::WindowMargins margins, + double dpr) noexcept { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) auto const position = event->position(); #else auto const position = QPointF { static_cast(event->x()), static_cast(event->y()) }; #endif - // TODO: apply margin once supported - return PixelCoordinate { PixelCoordinate::X { int(double(position.x()) * dpr) }, - PixelCoordinate::Y { int(double(position.y()) * dpr) } }; + auto const marginLeft = static_cast(margins.horizontal * dpr); + auto const marginTop = static_cast(margins.vertical * dpr); + return PixelCoordinate { PixelCoordinate::X { int(double(position.x()) * dpr) - marginLeft }, + PixelCoordinate::Y { int(double(position.y()) * dpr) - marginTop } }; } - PixelCoordinate makeMousePixelPosition(QWheelEvent* event, double dpr) noexcept + PixelCoordinate makeMousePixelPosition(QWheelEvent* event, + config::TerminalProfile::WindowMargins margins, + double dpr) noexcept { #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) auto const position = event->position(); #else auto const position = event->posF(); #endif - // TODO: apply margin once supported - return PixelCoordinate { PixelCoordinate::X { int(double(position.x()) * dpr) }, - PixelCoordinate::Y { int(double(position.y()) * dpr) } }; + auto const marginLeft = static_cast(margins.horizontal * dpr); + auto const marginTop = static_cast(margins.vertical * dpr); + return PixelCoordinate { PixelCoordinate::X { int(double(position.x()) * dpr) - marginLeft }, + PixelCoordinate::Y { int(double(position.y()) * dpr) - marginTop } }; } int mouseWheelDelta(QWheelEvent* event) noexcept @@ -423,7 +432,8 @@ void sendWheelEvent(QWheelEvent* event, TerminalSession& session) { auto const modifier = makeModifiers(event->modifiers()); auto const button = xDelta > 0 ? VTMouseButton::WheelRight : VTMouseButton::WheelLeft; - auto const pixelPosition = makeMousePixelPosition(event, session.contentScale()); + auto const pixelPosition = + makeMousePixelPosition(event, session.profile().margins, session.contentScale()); session.sendMousePressEvent(modifier, button, pixelPosition); event->accept(); @@ -434,7 +444,8 @@ void sendWheelEvent(QWheelEvent* event, TerminalSession& session) { auto const modifier = makeModifiers(event->modifiers()); auto const button = yDelta > 0 ? VTMouseButton::WheelUp : VTMouseButton::WheelDown; - auto const pixelPosition = makeMousePixelPosition(event, session.contentScale()); + auto const pixelPosition = + makeMousePixelPosition(event, session.profile().margins, session.contentScale()); session.sendMousePressEvent(modifier, button, pixelPosition); event->accept(); @@ -443,25 +454,28 @@ void sendWheelEvent(QWheelEvent* event, TerminalSession& session) void sendMousePressEvent(QMouseEvent* event, TerminalSession& session) { - session.sendMousePressEvent(makeModifiers(event->modifiers()), - makeMouseButton(event->button()), - makeMousePixelPosition(event, session.contentScale())); + session.sendMousePressEvent( + makeModifiers(event->modifiers()), + makeMouseButton(event->button()), + makeMousePixelPosition(event, session.profile().margins, session.contentScale())); event->accept(); } void sendMouseReleaseEvent(QMouseEvent* event, TerminalSession& session) { - session.sendMouseReleaseEvent(makeModifiers(event->modifiers()), - makeMouseButton(event->button()), - makeMousePixelPosition(event, session.contentScale())); + session.sendMouseReleaseEvent( + makeModifiers(event->modifiers()), + makeMouseButton(event->button()), + makeMousePixelPosition(event, session.profile().margins, session.contentScale())); event->accept(); } void sendMouseMoveEvent(QMouseEvent* event, TerminalSession& session) { - session.sendMouseMoveEvent(makeModifiers(event->modifiers()), - makeMouseCellLocation(event->pos().x(), event->pos().y(), session), - makeMousePixelPosition(event, session.contentScale())); + session.sendMouseMoveEvent( + makeModifiers(event->modifiers()), + makeMouseCellLocation(event->pos().x(), event->pos().y(), session), + makeMousePixelPosition(event, session.profile().margins, session.contentScale())); event->accept(); } @@ -472,9 +486,10 @@ void sendMouseMoveEvent(QHoverEvent* event, TerminalSession& session) #else auto const position = event->pos(); #endif - session.sendMouseMoveEvent(makeModifiers(event->modifiers()), - makeMouseCellLocation(position.x(), position.y(), session), - makeMousePixelPosition(event, session.contentScale())); + session.sendMouseMoveEvent( + makeModifiers(event->modifiers()), + makeMouseCellLocation(position.x(), position.y(), session), + makeMousePixelPosition(event, session.profile().margins, session.contentScale())); event->accept(); } @@ -541,18 +556,19 @@ vtbackend::FontDef getFontDefinition(vtrasterizer::Renderer& renderer) renderer.fontDescriptions().emoji.toPattern() }; } -vtrasterizer::PageMargin computeMargin(ImageSize cellSize, PageSize charCells, ImageSize pixels) noexcept +vtrasterizer::PageMargin computeMargin(ImageSize cellSize, + PageSize charCells, + ImageSize displaySize, + config::TerminalProfile::WindowMargins minimumMargins) noexcept { auto const usedHeight = unbox(charCells.lines) * unbox(cellSize.height); - auto const freeHeight = unbox(pixels.height) - usedHeight; - auto const bottomMargin = freeHeight; - auto const topMargin = 0; - // auto const usedWidth = charCells.columns * regularFont_.maxAdvance(); - // auto const freeWidth = pixels.width - usedWidth; - auto constexpr LeftMargin = 0; + auto const topMargin = static_cast(minimumMargins.vertical); + auto const bottomMargin = static_cast( + std::min(unbox(displaySize.height) - usedHeight - topMargin, minimumMargins.vertical)); + auto const leftMargin = static_cast(minimumMargins.horizontal); - return { LeftMargin, topMargin, static_cast(bottomMargin) }; + return { .left = leftMargin, .top = topMargin, .bottom = bottomMargin }; } vtrasterizer::FontDescriptions sanitizeFontDescription(vtrasterizer::FontDescriptions fonts, text::DPI dpi) @@ -564,20 +580,14 @@ vtrasterizer::FontDescriptions sanitizeFontDescription(vtrasterizer::FontDescrip return fonts; } -bool applyFontDescription(ImageSize cellSize, - PageSize pageSize, - ImageSize pixelSize, - text::DPI dpi, +bool applyFontDescription(text::DPI dpi, vtrasterizer::Renderer& renderer, vtrasterizer::FontDescriptions fontDescriptions) { if (renderer.fontDescriptions() == fontDescriptions) return false; - auto const windowMargin = computeMargin(cellSize, pageSize, pixelSize); - renderer.setFonts(sanitizeFontDescription(std::move(fontDescriptions), dpi)); - renderer.setMargin(windowMargin); renderer.updateFontMetrics(); return true; @@ -591,14 +601,20 @@ void applyResize(vtbackend::ImageSize newPixelSize, return; auto const oldPageSize = session.terminal().pageSize(); - auto const newPageSize = pageSizeForPixels(newPixelSize, renderer.gridMetrics().cellSize); + auto const newPageSize = + pageSizeForPixels(newPixelSize, + renderer.gridMetrics().cellSize, + applyContentScale(session.profile().margins, session.contentScale())); vtbackend::Terminal& terminal = session.terminal(); vtbackend::ImageSize cellSize = renderer.gridMetrics().cellSize; Require(renderer.hasRenderTarget()); renderer.renderTarget().setRenderSize(newPixelSize); renderer.setPageSize(newPageSize); - renderer.setMargin(computeMargin(renderer.gridMetrics().cellSize, newPageSize, newPixelSize)); + renderer.setMargin(computeMargin(renderer.gridMetrics().cellSize, + newPageSize, + newPixelSize, + applyContentScale(session.profile().margins, session.contentScale()))); if (oldPageSize.lines != newPageSize.lines) emit session.lineCountChanged(newPageSize.lines.as()); @@ -607,9 +623,10 @@ void applyResize(vtbackend::ImageSize newPixelSize, emit session.columnsCountChanged(newPageSize.columns.as()); auto const viewSize = cellSize * newPageSize; - displayLog()("Applying resize {}/{} pixels and {} -> {} cells.", + displayLog()("Applying resize {}/{} pixels (margins {}) and {} -> {} cells.", viewSize, newPixelSize, + session.profile().margins, terminal.pageSize(), newPageSize); diff --git a/src/contour/helper.h b/src/contour/helper.h index eccda069d5..9f8be91b87 100644 --- a/src/contour/helper.h +++ b/src/contour/helper.h @@ -167,28 +167,49 @@ void spawnNewTerminal(std::string const& programPath, vtbackend::FontDef getFontDefinition(vtrasterizer::Renderer& renderer); +constexpr config::TerminalProfile::WindowMargins applyContentScale( + config::TerminalProfile::WindowMargins margins, double contentScale) noexcept +{ + return { .horizontal = static_cast(margins.horizontal * contentScale), + .vertical = static_cast(margins.vertical * contentScale) }; +} + vtrasterizer::PageMargin computeMargin(vtbackend::ImageSize cellSize, vtbackend::PageSize charCells, - vtbackend::ImageSize pixels) noexcept; + vtbackend::ImageSize displaySize, + config::TerminalProfile::WindowMargins minimumMargins) noexcept; vtrasterizer::FontDescriptions sanitizeFontDescription(vtrasterizer::FontDescriptions fonts, text::DPI screenDPI); -constexpr vtbackend::PageSize pageSizeForPixels(vtbackend::ImageSize viewSize, - vtbackend::ImageSize cellSize) noexcept +constexpr vtbackend::PageSize pageSizeForPixels(vtbackend::ImageSize totalViewSize, + vtbackend::ImageSize cellSize, + config::TerminalProfile::WindowMargins margins) { - return vtbackend::PageSize { boxed_cast((viewSize / cellSize).height), - boxed_cast((viewSize / cellSize).width) }; + // NB: Multiplied by 2, because margins are applied on both sides of the terminal. + auto const marginSize = vtbackend::ImageSize { vtbackend::Width::cast_from(2 * margins.horizontal), + vtbackend::Height::cast_from(2 * margins.vertical) }; + + auto const usableViewSize = totalViewSize - marginSize; + + auto const result = + vtbackend::PageSize { boxed_cast((usableViewSize / cellSize).height), + boxed_cast((usableViewSize / cellSize).width) }; + + fmt::print("calculatePageSize: totalViewSize: {}, cellSize: {}, margins: {}, usable: {}, result: {}\n", + totalViewSize, + cellSize, + marginSize, + usableViewSize, + result); + return result; } void applyResize(vtbackend::ImageSize newPixelSize, TerminalSession& session, vtrasterizer::Renderer& renderer); -bool applyFontDescription(vtbackend::ImageSize cellSize, - vtbackend::PageSize pageSize, - vtbackend::ImageSize pixelSize, - text::DPI dpi, +bool applyFontDescription(text::DPI dpi, vtrasterizer::Renderer& renderer, vtrasterizer::FontDescriptions fontDescriptions); diff --git a/src/contour/ui.template/main.qml.in b/src/contour/ui.template/main.qml.in index e4309a8d68..6c57faaf80 100644 --- a/src/contour/ui.template/main.qml.in +++ b/src/contour/ui.template/main.qml.in @@ -38,13 +38,13 @@ ApplicationWindow onWidthChanged : function() { vtui.width = width - vtui.session.requestWindowResize(width, height) + vtui.session.adaptToWidgetSize() vtui.updateSizeWidget() } onHeightChanged: function() { vtui.height = height - vtui.session.requestWindowResize(width, height) + vtui.session.adaptToWidgetSize() vtui.updateSizeWidget() }