diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index dc6b4d43..cfcd8712 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -7,7 +7,8 @@ jobs:
fail-fast: false
matrix:
include:
- - os: ubuntu-latest
+ - name: Ubuntu Debug
+ os: ubuntu-20.04
buildtype: 'Debug'
cc: clang-12
cxx: clang++-12
@@ -15,7 +16,8 @@ jobs:
upload: false
cmakeflags: '-DBUILD_TESTS=ON'
- - os: ubuntu-latest
+ - name: Ubuntu Release
+ os: ubuntu-20.04
buildtype: 'Release'
cc: clang-12
cxx: clang++-12
@@ -24,7 +26,8 @@ jobs:
use_vcpkg: true
cmakeflags: ''
- - os: macos-10.15
+ - name: Macos Debug
+ os: macos-10.15
buildtype: 'Debug'
cc: clang
cxx: clang++
@@ -32,7 +35,8 @@ jobs:
upload: false
cmakeflags: '-DBUILD_TESTS=ON'
- - os: macos-10.15
+ - name: Macos Release
+ os: macos-10.15
buildtype: 'Release'
cc: clang
cxx: clang++
@@ -76,24 +80,36 @@ jobs:
- name: Ubuntu - Install vcpkg dependencies
if: startsWith(matrix.os, 'ubuntu') && matrix.use_vcpkg
run: >
- sudo apt-get install gperf autoconf build-essential libtool
- libgl1-mesa-dev libxi-dev libx11-dev libxext-dev
- libxkbcommon-x11-dev libglu1-mesa-dev libx11-xcb-dev
- '^libxcb.*-dev' libxrender-dev ninja-build curl
- zip unzip tar autopoint python
+ sudo apt-get install git curl zip unzip tar at libxt-dev gperf libxaw7-dev cifs-utils
+ build-essential g++ gfortran libx11-dev libxkbcommon-x11-dev libxi-dev
+ libgl1-mesa-dev libglu1-mesa-dev mesa-common-dev libxinerama-dev libxxf86vm-dev
+ libxcursor-dev yasm libnuma1 libnuma-dev libtool-bin
+ flex bison libbison-dev autoconf libudev-dev libncurses5-dev libtool libxrandr-dev
+ xutils-dev dh-autoreconf autoconf-archive libgles2-mesa-dev ruby-full
+ libxext-dev libxfixes-dev libxrender-dev
+ libxcb1-dev libx11-xcb-dev libxcb-glx0-dev meson nasm cmake ninja-build
+ libxkbcommon-dev libxcb-keysyms1-dev
+ libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev
+ libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev
+ libxcb-render-util0-dev libxcb-xinerama0-dev libxcb-xkb-dev libxcb-xinput-dev
+ libxcb-cursor-dev libkrb5-dev libxcb-res0-dev libxcb-keysyms1-dev libxcb-xkb-dev libxcb-record0-dev
+ python3-setuptools python3-mako python3-pip python3-venv nodejs libwayland-dev python2 python-is-python3
+ guile-2.2-dev libxdamage-dev libdbus-1-dev libxtst-dev haskell-stack libkrb5-3 zlib1g
+ libxcb-util0-dev pkg-config libicu66
+ # python-yaml
- name: Mac - Install vcpkg dependencies
if: startsWith(matrix.os, 'macos') && matrix.use_vcpkg
run: |
- brew install automake
+ brew install automake autoconf-archive libtool
- - name: Restore vcpkg packages
- if: matrix.use_vcpkg
- uses: actions/cache@v2
- with:
- path: |
- build/vcpkg_installed
- key: ${{ matrix.os }}-${{ hashFiles('vcpkg.json') }}-${{ env.CC }}-${{ env.CXX }}
+ #- name: Restore vcpkg packages
+ #if: matrix.use_vcpkg
+ #uses: actions/cache@v2
+ #with:
+ #path: |
+ #build/vcpkg_installed
+ #key: ${{ matrix.os }}-${{ hashFiles('vcpkg.json') }}-${{ env.CC }}-${{ env.CXX }}
- name: Ubuntu - Install dependencies from system package manager
if: ${{ startsWith(matrix.os, 'ubuntu') && !matrix.use_vcpkg }}
@@ -101,13 +117,13 @@ jobs:
sudo apt-get install libmsgpack-dev libfmt-dev libboost-all-dev
mesa-common-dev libglu1-mesa-dev
- - name: Ubuntu - Install Catch2
- if: ${{ startsWith(matrix.os, 'ubuntu') && !matrix.use_vcpkg }}
+ - name: Ubuntu & MacOS Debug - Build & install Catch2 from source
+ if: ${{ !matrix.use_vcpkg }}
run: |
git clone https://github.com/catchorg/Catch2.git
cd Catch2
- git checkout v2.x
- cmake -B build -H. -DBUILD_TESTING=OFF
+ git checkout devel
+ cmake -B build -H. -DBUILD_TESTING=OFF -DCMAKE_CXX_STANDARD=17
cd build
sudo make install
@@ -130,7 +146,7 @@ jobs:
- name: Mac - Install dependencies
if: ${{ startsWith(matrix.os, 'macos') && !matrix.use_vcpkg }}
run: |
- brew install fmt boost qt@5 msgpack-cxx catch2
+ brew install fmt boost qt@5 msgpack-cxx
sudo ln -s /usr/local/Cellar/qt@5/5.15.2/plugins /usr/local/plugins
- name: Mac - Set environment variables
@@ -160,13 +176,22 @@ jobs:
if: matrix.test
run: ./build/nvui_test
- - name: Package (Ubuntu & Mac)
- if: matrix.upload
+ - name: Package (Ubuntu)
+ if: matrix.upload && startsWith(matrix.os, 'ubuntu')
run: |
ls build
chmod +x ./scripts/linux/package.sh
./scripts/linux/package.sh
+ - name: Package (macOS)
+ if: matrix.upload && startsWith(matrix.os, 'macos')
+ run: |
+ cd build
+ mkdir packaged
+ mkdir packaged/bin
+ cp -r nvui.app packaged/bin
+ cp -r ../vim packaged
+
- name: Ubuntu - Upload artifact
uses: actions/upload-artifact@v2
if: matrix.upload && startsWith(matrix.os, 'ubuntu')
@@ -216,78 +241,128 @@ jobs:
tag: ${{ github.ref }}
overwrite: false
body: "Automated release by Github Actions."
- windows-debug:
- runs-on: windows-latest
+ windows:
strategy:
fail-fast: false
+ matrix:
+ include:
+ - name: Windows Release
+ os: windows-latest
+ buildtype: 'Release'
+ debug: false
+ upload: true
+ cmakeflags: ''
+ c: clang
+ cpp: clang++
+ gen: Ninja
+
+ - name: Windows Debug
+ os: windows-latest
+ buildtype: 'Debug'
+ debug: true
+ upload: false
+ cmakeflags: '-DBUILD_TESTS=ON'
+ c: clang
+ cpp: clang++
+ gen: Ninja
+ runs-on: ${{ matrix.os }}
timeout-minutes: 500
- env:
- buildDir: '${{ github.workspace }}/build'
steps:
- - uses: actions/checkout@v2
- with:
- submodules: 'recursive'
+ - name: Set last commit hash as environment variable (push)
+ if: ${{ github.event_name == 'push' }}
+ run: |
+ "COMMIT_SHA=${{ github.sha }}" >> $env:GITHUB_ENV
+ - name: Set last commit hash as environment variable (pull request)
+ if: ${{ github.event_name == 'pull_request' }}
+ run: |
+ "COMMIT_SHA=${{ github.event.pull_request.head.sha }}" >> $env:GITHUB_ENV
+
+ - name: Clone repo to C drive
+ run: |
+ git clone --recurse-submodules https://github.com/rohit-px2/nvui.git C:\nvui
+ cd C:\nvui
+ git checkout $env:COMMIT_SHA
+ git submodule init
+ git submodule update
+
- uses: ilammy/msvc-dev-cmd@v1
with:
sdk: 10.0.19041.0
+
- name: Install Neovim Stable
+ if: matrix.debug
run: choco install -y neovim
+
- name: Add Neovim to PATH
- run: echo "C:\tools\neovim\Neovim\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- - name: Restore deps from cache if they exist
- uses: actions/cache@v2
- with:
- path: |
- build/vcpkg_installed
- key: ${{ runner.os }}-${{ hashFiles('vcpkg.json') }}
- restore-keys: |
- ${{ runner.os }}-build-debug-${{ hashFiles('vcpkg.json') }}
- - name: Build nvui and nvui_test
- run: .\scripts\windows\build-debug.ps1
+ if: matrix.debug
+ run: |
+ echo "C:\tools\neovim\nvim-win64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+ #- name: Restore deps from cache if they exist
+ #uses: actions/cache@v2
+ #with:
+ #path: |
+ #build/vcpkg_installed
+ #key: ${{ runner.os }}-${{ hashFiles('vcpkg.json') }}
+ #restore-keys: |
+ #${{ runner.os }}-build-release-${{ hashFiles('vcpkg.json') }}
+
+ # Step was taken from Neovim-Qt's github actions workflow file
+ # at https://github.com/equalsraf/neovim-qt/blob/master/.github/workflows/build-test.yml
+ #- name: Install Qt5
+ #env:
+ #QT_DIR: ${{ github.workspace }}\Qt\5.15.2\msvc2019_64
+ #run: |
+ #python -m pip install aqtinstall
+ #python -m aqt install-qt -O ./Qt windows desktop 5.15.2 win64_msvc2019_64
+ #"Qt5_DIR=$env:QT_DIR\lib\cmake\Qt5" >> $env:GITHUB_ENV
+ #"${{ env.qt_dir }}" >> $env:GITHUB_PATH
+ #"${{ env.qt_dir }}" >> $env:GITHUB_PATH
+
+ - name: Bootstrap vcpkg before build
+ working-directory: C:/nvui
+ run: .\vcpkg\bootstrap-vcpkg.bat -disableMetrics
+
+ - name: Build nvui (& nvui_test in Debug mode)
+ working-directory: C:/nvui
+ run: |
+ cmake -B build . -DCMAKE_TOOLCHAIN_FILE=.\vcpkg\scripts\buildsystems\vcpkg.cmake -DCMAKE_BUILD_TYPE=${{ matrix.buildtype }} ${{ matrix.cmakeflags }} -DCMAKE_C_COMPILER=${{ matrix.c }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp }} -G ${{ matrix.gen }}
+ cmake --build build --config ${{ matrix.buildtype }}
+ shell: cmd
+
- name: Run tests
+ working-directory: C:/nvui
+ if: matrix.debug
run: |
cd build
.\nvui_test
shell: cmd
- windows-release:
- runs-on: windows-latest
- strategy:
- fail-fast: false
- timeout-minutes: 500
- env:
- buildDir: '${{ github.workspace }}/build'
- steps:
- - uses: actions/checkout@v2
- with:
- submodules: 'recursive'
- - uses: ilammy/msvc-dev-cmd@v1
- with:
- sdk: 10.0.19041.0
- - name: Restore deps from cache if they exist
- uses: actions/cache@v2
- with:
- path: |
- build/vcpkg_installed
- key: ${{ runner.os }}-${{ hashFiles('vcpkg.json') }}
- restore-keys: |
- ${{ runner.os }}-build-release-${{ hashFiles('vcpkg.json') }}
- - name: Package into a zip
- run: .\scripts\windows\package.ps1
+
+ - name: Package nvui (Release)
+ working-directory: C:/nvui
+ if: ${{ !matrix.debug }}
+ run: |
+ .\scripts\windows\package.ps1
+
- name: Upload artifact
+ if: matrix.upload
uses: actions/upload-artifact@v2
with:
name: nvui-win64
if-no-files-found: ignore
path: build/nvui
+
- name: Rename nvui.zip to nvui-win64.zip for release upload
- if: startsWith(github.ref, 'refs/tags/')
- run: ren nvui.zip nvui-win64.zip
+ working-directory: C:/nvui
+ if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.upload }}
+ run: |
+ ren nvui.zip nvui-win64.zip
+
- name: Upload Release asset
- if: startsWith(github.ref, 'refs/tags/')
+ if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.upload }}
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
- file: nvui-win64.zip
+ file: C:\nvui\nvui-win64.zip
tag: ${{ github.ref }}
overwrite: false
body: "Automated release by Github Actions."
diff --git a/.gitignore b/.gitignore
index e087b38a..2db02f9f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@ CMakeLists.txt.user
.ccls-cache/
CMakeSettings.json
.ignore
+vcpkg_installed/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac0d7c7f..58c5b78d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -122,6 +122,12 @@ endif()
target_link_libraries(nvui PRIVATE
${Boost_LIBRARIES}
)
+if(APPLE)
+ set_target_properties(nvui PROPERTIES
+ MACOSX_BUNDLE TRUE
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/assets/resources/macos/Info.plist
+ )
+endif()
include(CheckIPOSupported)
check_ipo_supported(RESULT LTOAvailable)
if(LTOAvailable)
@@ -160,8 +166,7 @@ if(BUILD_TESTS)
target_include_directories(nvui_test PRIVATE ${Boost_INCLUDE_DIR})
endif()
target_link_libraries(nvui_test PRIVATE
- Boost::thread
- Boost::filesystem
+ ${Boost_LIBRARIES}
)
include(CTest)
include(Catch)
diff --git a/assets/resources/macos/Info.plist b/assets/resources/macos/Info.plist
new file mode 100644
index 00000000..cb16414d
--- /dev/null
+++ b/assets/resources/macos/Info.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ NSPrincipalClass
+ NSApplication
+ NSHighResolutionCapable
+
+
+
diff --git a/scripts/linux/package.sh b/scripts/linux/package.sh
index 189e86b4..d424c941 100644
--- a/scripts/linux/package.sh
+++ b/scripts/linux/package.sh
@@ -3,6 +3,4 @@ cd build
mkdir packaged
mkdir packaged/bin
cp nvui packaged/bin
-cp -r ../assets packaged
-rm -rf packaged/assets/display
cp -r ../vim packaged
diff --git a/scripts/windows/build-debug.ps1 b/scripts/windows/build-debug.ps1
index 70668604..f4a66a57 100644
--- a/scripts/windows/build-debug.ps1
+++ b/scripts/windows/build-debug.ps1
@@ -4,6 +4,6 @@ param(
[string]$gen = "Ninja"
)
$generator = '"{0}"' -f $gen
-$cmd = Write-Output "cmake . -B build -DCMAKE_TOOLCHAIN_FILE=.\vcpkg\scripts\buildsystems\vcpkg.cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=$cc -DCMAKE_CXX_COMPILER=$cxx -G $generator -DBUILD_TESTS=ON"
+$cmd = Write-Output "cmake . -B build -DQt5_DIR=$env:Qt5_DIR -DCMAKE_TOOLCHAIN_FILE=.\vcpkg\scripts\buildsystems\vcpkg.cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=$cc -DCMAKE_CXX_COMPILER=$cxx -G $generator -DBUILD_TESTS=ON"
cmd /C $cmd
cmake --build build --config Debug
diff --git a/scripts/windows/build-release.ps1 b/scripts/windows/build-release.ps1
index c7686879..4c376081 100644
--- a/scripts/windows/build-release.ps1
+++ b/scripts/windows/build-release.ps1
@@ -4,6 +4,6 @@ param(
[string]$gen = "Ninja"
)
$generator = '"{0}"' -f $gen
-$cmd = Write-Output "cmake . -B build -DCMAKE_TOOLCHAIN_FILE=.\vcpkg\scripts\buildsystems\vcpkg.cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=$cc -DCMAKE_CXX_COMPILER=$cxx -G $generator"
+$cmd = Write-Output "cmake . -B build -DQt5_DIR=$env:Qt5_DIR -DCMAKE_TOOLCHAIN_FILE=.\vcpkg\scripts\buildsystems\vcpkg.cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=$cc -DCMAKE_CXX_COMPILER=$cxx -G $generator"
cmd /C $cmd
cmake --build build --config Release
diff --git a/scripts/windows/package.ps1 b/scripts/windows/package.ps1
index 46f7b37b..8e6fc7b6 100644
--- a/scripts/windows/package.ps1
+++ b/scripts/windows/package.ps1
@@ -1,4 +1,3 @@
-./scripts/windows/build-release.ps1
cd build
mkdir nvui
cd nvui
@@ -6,9 +5,7 @@ mkdir bin
cd ..
(gci -Path ./* -Include nvui.exe, *.dll, *.conf).fullname | foreach {Copy-Item -Force -Path $_ -Destination nvui/bin}
Copy-Item -Force -Recurse -Path plugins -Destination nvui/bin
-Copy-Item -Force -Recurse -Path ../assets -Destination nvui
Copy-Item -Force -Recurse -Path ../vim -Destination nvui
-Remove-Item -Force -Recurse -Path nvui/assets/display
Compress-Archive -Force -Path nvui -DestinationPath nvui.zip
Move-Item -Force -Path nvui.zip -Destination ../
cd ..
diff --git a/src/cmdline.cpp b/src/cmdline.cpp
index ffc0d794..d75f606f 100644
--- a/src/cmdline.cpp
+++ b/src/cmdline.cpp
@@ -313,9 +313,9 @@ static std::tuple draw_pos(
int CmdlineQ::fitting_height() const
{
+ QFontMetricsF fm {cmd_font, this};
int maxwidth = width() - (border_width + padding) * 2;
auto contentstring = get_content_string();
- QFontMetricsF fm {cmd_font};
auto maxheight = fm.height() * contentstring.size();
QRectF constraint(0, 0, maxwidth, maxheight);
float pad = border_width + padding;
@@ -341,7 +341,7 @@ void CmdlineQ::draw_cursor(QPainter& p, const Cursor& cursor)
QString contentstring = get_content_string();
int upto = contentstring.size() - cur_content_length + cursor_pos;
float pad = border_width + padding;
- QFontMetricsF fm {cmd_font};
+ const auto fm = p.fontMetrics();
float left = pad;
float top = pad;
const auto adv_x = [&](float adv) {
@@ -352,7 +352,7 @@ void CmdlineQ::draw_cursor(QPainter& p, const Cursor& cursor)
if (contentstring[i] == '\n') { left = pad; top += fm.height(); }
else
{
- adv_x(fm.horizontalAdvance(contentstring[i]));
+ adv_x(p.fontMetrics().horizontalAdvance(contentstring[i]));
}
}
auto [rect, id, drawtext, opacity] = cursor.rect(
@@ -366,10 +366,10 @@ void CmdlineQ::draw_cursor(QPainter& p, const Cursor& cursor)
void CmdlineQ::paintEvent(QPaintEvent*)
{
- QFontMetricsF fm {cmd_font};
- int offset = fm.ascent();
QPainter p(this);
p.setFont(cmd_font);
+ const auto fm = p.fontMetrics();
+ int offset = fm.ascent();
auto contentstring = get_content_string();
QColor bg = inner_bg.value_or(hl_state.default_bg()).qcolor();
QColor fg = inner_fg.value_or(hl_state.default_fg()).qcolor();
diff --git a/src/main.cpp b/src/main.cpp
index 86fe32ad..bdb3defc 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,6 +19,11 @@
#include
#include
#include
+#include
+
+#ifdef Q_OS_MAC
+#include "platform/macos/macos_utils.hpp"
+#endif // Q_OS_MAC
#include "config.hpp"
using std::string;
@@ -128,6 +133,12 @@ bool is_executable(std::string_view path)
int main(int argc, char** argv)
{
QCoreApplication::setApplicationName("nvui");
+#ifdef USE_QPAINTER
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+#endif
+#ifdef Q_OS_MAC
+ macos_utils::set_env_vars();
+#endif
QApplication app {argc, argv};
Config::init();
const auto args = get_args(argc, argv);
diff --git a/src/platform/macos/macos_utils.hpp b/src/platform/macos/macos_utils.hpp
new file mode 100644
index 00000000..c490ec6c
--- /dev/null
+++ b/src/platform/macos/macos_utils.hpp
@@ -0,0 +1,39 @@
+#ifndef NVUI_PLATFORM_MACOS_UTILS_HPP
+#define NVUI_PLATFORM_MACOS_UTILS_HPP
+
+#include
+
+namespace macos_utils
+{
+
+inline void set_env_vars()
+{
+ QProcess env_printer;
+ auto shell = qgetenv("SHELL");
+ if (shell.isEmpty()) shell = "/bin/bash";
+ // Ported from Goneovim's editor.go at
+ // https://github.com/akiyosi/goneovim/blob/981f41440935542ed35b3ef93cfdcd17744a4e1a/editor/editor.go#L548
+ // When nvui is compiled into a .app file and run, there are differences
+ // between the environment when it is run by clicking vs. running from command line.
+ // When run by clicking the PATH doesn't contain the Neovim executable path
+ // even if it was set by the user.
+ // Thus we have to print out the path in an external process and set it ourselves.
+ env_printer.start(shell, {"-lc", "env", "-i"});
+ if (!env_printer.waitForFinished(5000))
+ {
+ return;
+ }
+ auto out = env_printer.readAllStandardOutput().split('\n');
+ for(const auto& line : out)
+ {
+ // The name of the environment variable, and then its value.
+ // Separated by an '=' sign.
+ auto s = line.split('=');
+ if (s.size() < 2) continue;
+ qputenv(s[0], s[1]);
+ }
+}
+
+} // namespace macos_utils
+
+#endif // NVUI_PLATFORM_MACOS_UTILS_HPP
diff --git a/src/platform/windows/d2deditor.cpp b/src/platform/windows/d2deditor.cpp
index 22337f47..a253443a 100644
--- a/src/platform/windows/d2deditor.cpp
+++ b/src/platform/windows/d2deditor.cpp
@@ -39,7 +39,8 @@ D2DEditor::D2DEditor(
)
: QWidget(parent),
QtEditorUIBase(*this, cols, rows, std::move(capabilities),
- std::move(nvim_path), std::move(nvim_args))
+ std::move(nvim_path), std::move(nvim_args)),
+ win_dpi(GetDpiForWindow((HWND) winId()))
{
setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_InputMethodEnabled);
@@ -80,6 +81,12 @@ D2DEditor::~D2DEditor() = default;
void D2DEditor::resizeEvent(QResizeEvent* event)
{
Base::handle_nvim_resize(event);
+ auto maybe_new_dpi = GetDpiForWindow((HWND) winId());
+ if (maybe_new_dpi != win_dpi)
+ {
+ win_dpi = maybe_new_dpi;
+ set_fonts(guifonts);
+ }
hwnd_target->Resize(D2D1::SizeU(width(), height()));
QWidget::resizeEvent(event);
}
@@ -139,6 +146,7 @@ D2DEditor::create_render_target(u32 width, u32 height)
D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS,
&target
);
+ target->SetDpi(default_dpi, default_dpi);
target->CreateBitmap(
size, nullptr, 0,
D2D1::BitmapProperties1(
@@ -153,7 +161,6 @@ D2DEditor::create_render_target(u32 width, u32 height)
target->SetTarget(bitmap.Get());
target->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
target->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
- target->SetDpi(default_dpi, default_dpi);
return {target, bitmap};
}
@@ -290,7 +297,7 @@ void D2DEditor::set_fonts(std::span fontlist)
continue;
}
dw_formats.emplace_back(
- dwrite_factory(), wcname, current_point_size, default_dpi,
+ dwrite_factory(), wcname, current_point_size * scale_factor(), default_dpi,
default_font_weight(), default_font_style()
);
dw_fonts.emplace_back(std::move(font));
@@ -301,14 +308,19 @@ void D2DEditor::set_fonts(std::span fontlist)
static const auto default_font_name = default_font_family().toStdWString();
dw_fonts.push_back(font_from_name(default_font_name, font_collection.Get()));
dw_formats.emplace_back(
- dwrite_factory(), default_font_name, current_point_size, default_dpi,
- default_font_weight(), default_font_style()
+ dwrite_factory(), default_font_name, current_point_size * scale_factor(),
+ default_dpi, default_font_weight(), default_font_style()
);
}
update_font_metrics();
emit layouts_invalidated();
}
+float D2DEditor::scale_factor() const
+{
+ return win_dpi / default_dpi;
+}
+
void D2DEditor::linespace_changed(float)
{
update_font_metrics();
@@ -335,7 +347,7 @@ void D2DEditor::update_font_metrics()
format->GetFontFamilyName(name.data(), (UINT32) name.size());
QFont f;
f.setFamily(QString::fromWCharArray(name.c_str()));
- f.setPointSizeF(current_point_size);
+ f.setPointSizeF(current_point_size * scale_factor());
f.setLetterSpacing(QFont::AbsoluteSpacing, charspace);
popup->font_changed(f, font_dimensions());
}
diff --git a/src/platform/windows/d2deditor.hpp b/src/platform/windows/d2deditor.hpp
index 95b52587..af0d0055 100644
--- a/src/platform/windows/d2deditor.hpp
+++ b/src/platform/windows/d2deditor.hpp
@@ -74,6 +74,9 @@ class D2DEditor : public QWidget, public QtEditorUIBase
void create_grid(u32 x, u32 y, u32 w, u32 h, u64 id) override;
void set_fonts(std::span fonts) override;
u32 calc_fallback_index(u32 ucs);
+ // The scale factor for the current monitor, based on dpi divided
+ // by the default dpi (96).
+ float scale_factor() const;
private:
std::unordered_map fallback_indices {};
std::vector> dw_fonts;
@@ -85,6 +88,7 @@ class D2DEditor : public QWidget, public QtEditorUIBase
ComPtr device = nullptr;
float current_point_size = 12.0f;
bool vsync = true;
+ u32 win_dpi;
};
#endif // NVUI_D2DEDITOR_HPP
diff --git a/src/popupmenu.cpp b/src/popupmenu.cpp
index 901b1829..995a05da 100644
--- a/src/popupmenu.cpp
+++ b/src/popupmenu.cpp
@@ -358,8 +358,12 @@ void PopupMenuQ::paintEvent(QPaintEvent*)
QPainter p(this);
int pad = border_width;
QRect r(pad, pad, width() - 2 * pad, height() - 2 * pad);
+ auto dpr = devicePixelRatioF();
+ QRect pixmap_rect = QRect(
+ r.x() * dpr, r.y() * dpr, r.width() * dpr, r.height() * dpr
+ );
p.fillRect(rect(), border_color.qcolor());
- p.drawPixmap(r, pixmap, r);
+ p.drawPixmap(r, pixmap, pixmap_rect);
}
void PopupMenuQ::update_dimensions()
@@ -403,7 +407,8 @@ void PopupMenuQ::update_dimensions()
auto new_pixmap_size = pixmap.size().expandedTo({width, height});
if (new_pixmap_size != pixmap.size())
{
- pixmap = QPixmap(width, height);
+ pixmap = QPixmap(width * devicePixelRatioF(), height * devicePixelRatioF());
+ pixmap.setDevicePixelRatio(devicePixelRatioF());
}
resize(width, height);
if (pmenu) pixmap.fill(hl_state->colors_for(*pmenu).bg.qcolor());
diff --git a/src/qeditor.cpp b/src/qeditor.cpp
index 0de15ce9..dff28e71 100644
--- a/src/qeditor.cpp
+++ b/src/qeditor.cpp
@@ -19,7 +19,7 @@ static void set_relative_font_size(
const double tolerance,
const std::size_t max_iterations
)
-{
+{
constexpr auto width = [](const QFontMetricsF& m) {
return m.horizontalAdvance('a');
};
@@ -53,7 +53,8 @@ QEditor::QEditor(
)
: QWidget(parent),
QtEditorUIBase(*this, cols, rows, std::move(capabilities),
- std::move(nvim_path), std::move(nvim_args))
+ std::move(nvim_path), std::move(nvim_args)),
+ device_pixelratio(devicePixelRatioF())
{
first_font.setFamily(default_font_family());
first_font.setPointSizeF(11.25);
@@ -87,6 +88,11 @@ std::unique_ptr QEditor::cmdline_new()
void QEditor::resizeEvent(QResizeEvent* ev)
{
Base::handle_nvim_resize(ev);
+ if (device_pixelratio != devicePixelRatioF())
+ {
+ device_pixelratio = devicePixelRatioF();
+ update_font_metrics();
+ }
update();
}
@@ -192,7 +198,7 @@ void QEditor::set_fonts(std::span fontdescs)
void QEditor::update_font_metrics()
{
first_font.setLetterSpacing(QFont::AbsoluteSpacing, charspace);
- QFontMetricsF metrics {first_font};
+ QFontMetricsF metrics {first_font, this};
float combined_height = std::max(metrics.height(), metrics.lineSpacing());
double font_height = combined_height + linespacing();
constexpr QChar any_char = 'W';
@@ -231,8 +237,11 @@ void QEditor::paintEvent(QPaintEvent*)
auto* grid = static_cast(grid_base.get());
if (!grid->hidden)
{
- QSize size = grid->buffer().size();
- auto r = QRectF(grid->pos(), size).intersected(grid_clip_rect);
+ auto bf_dpr = grid->buffer().devicePixelRatioF();
+ QSize sz = grid->buffer().size();
+ sz.rwidth() /= bf_dpr;
+ sz.rheight() /= bf_dpr;
+ auto r = QRectF(grid->pos(), sz).intersected(grid_clip_rect);
p.setClipRect(r);
grid->process_events();
grid->render(p);
diff --git a/src/qeditor.hpp b/src/qeditor.hpp
index 5161e660..54bb7129 100644
--- a/src/qeditor.hpp
+++ b/src/qeditor.hpp
@@ -55,6 +55,7 @@ class QEditor : public QWidget, public QtEditorUIBase
void update_font_metrics();
QFont first_font;
std::vector fonts;
+ double device_pixelratio;
};
#endif // NVUI_QEDITOR_HPP
diff --git a/src/qpaintgrid.cpp b/src/qpaintgrid.cpp
index 47be3477..8a4a0933 100644
--- a/src/qpaintgrid.cpp
+++ b/src/qpaintgrid.cpp
@@ -73,7 +73,12 @@ static void set_pen_width(QPainter& painter, double w)
void QPaintGrid::update_pixmap_size()
{
auto&& [font_width, font_height] = editor_area->font_dimensions();
- pixmap = QPixmap(cols * font_width, rows * font_height);
+ pixmap = QPixmap(
+ cols * font_width * editor_area->devicePixelRatioF(),
+ rows * font_height * editor_area->devicePixelRatioF()
+ );
+ pixmap.fill(editor_area->default_bg().qcolor());
+ pixmap.setDevicePixelRatio(editor_area->devicePixelRatioF());
send_redraw();
}
@@ -192,7 +197,7 @@ void QPaintGrid::draw_text_and_bg(
QRectF rect = {start, end};
painter.setClipRect(rect);
painter.fillRect(rect, bg.qcolor());
- rect.setWidth(rect.width() * 3.);
+ rect.setWidth(rect.width() + 1.0);
draw_text(
painter, text, fg, sp, rect, attr.font_opts, font, font_width, font_height
);
@@ -307,13 +312,16 @@ void QPaintGrid::process_events()
break;
case PaintKind::Scroll:
{
+ auto dpr = editor_area->devicePixelRatioF();
auto [font_width, font_height] = editor_area->font_dimensions();
const auto& [rect, dx, dy] = evt.scroll_info();
+ // I love how the rectangle coordinates aren't automatically scaled
+ // by the pixmap's device pixel ratio
QRect r(
- rect.x() * font_width,
- rect.y() * font_height,
- rect.width() * font_width,
- rect.height() * font_height
+ rect.x() * font_width * dpr,
+ rect.y() * font_height * dpr,
+ rect.width() * font_width * dpr,
+ rect.height() * font_height * dpr
);
// This would probably be faster using QPixmap::scroll
// but it doesn't want to work
@@ -331,14 +339,20 @@ void QPaintGrid::process_events()
void QPaintGrid::render(QPainter& p)
{
- auto&& [font_width, font_height] = editor_area->font_dimensions();
- QRectF rect(top_left.x(), top_left.y(), pixmap.width(), pixmap.height());
- auto snapshot_height = pixmap.height();
+ auto [font_width, font_height] = editor_area->font_dimensions();
+ // p (the editor painter) scales ITS OWN coordinates (the QPoint/QPointF)
+ // that's the first parameter in every call) by the device pixel ratio
+ // However, the coordinates of the grid pixmap are not scaled by the DPR.
+ // So we have to take this into account when interacting with the painter.
+ auto pixmap_height = pixmap.height() / editor_area->devicePixelRatioF();
+ auto pixmap_width = pixmap.width() / editor_area->devicePixelRatioF();
+ QRectF rect {top_left, QSize(pixmap_width, pixmap_height)};
if (!editor_area->animations_enabled() || !is_scrolling)
{
p.drawPixmap(pos(), pixmap);
return;
}
+ QPointF topleft_text = QPointF(top_left.x() / font_width, top_left.y() / font_height);
p.fillRect(rect, editor_area->hlstate().default_bg().qcolor());
float cur_scroll_y = current_scroll_y * font_height;
float cur_snapshot_top = viewport.topline * font_height;
@@ -347,32 +361,38 @@ void QPaintGrid::render(QPainter& p)
for(auto it = snapshots.rbegin(); it != snapshots.rend(); ++it)
{
const auto& snapshot = *it;
- QRectF r;
- float snapshot_top = snapshot.vp.topline * font_height;
- float offset = snapshot_top - cur_scroll_y;
- auto pixmap_top = top_left.y() + offset;
- QPointF pt;
+ float offset = snapshot.vp.topline - current_scroll_y;
+ QRectF px_rect;
+ QPointF px_pt;
+ float top_row = topleft_text.y() + offset;
if (snapshot.vp.topline < min_topline)
{
- auto height = (min_topline - snapshot.vp.topline) * font_height;
- height = std::min(height, float(snapshot_height));
+ float height = (min_topline - snapshot.vp.topline);
+ height = std::min(height, float(rows));
min_topline = snapshot.vp.topline;
- r = QRect(0, 0, pixmap.width(), height);
- pt = {top_left.x(), pixmap_top};
+ px_rect = QRectF(0, 0, cols, height);
+ px_pt = QPointF(topleft_text.x(), top_row);
}
else if (snapshot.vp.botline > max_botline)
{
- auto height = (snapshot.vp.botline - max_botline) * font_height;
- height = std::min(height, float(snapshot_height));
+ float height = (snapshot.vp.botline - max_botline);
+ height = std::min(height, float(rows));
max_botline = snapshot.vp.botline;
- r = QRect(0, snapshot_height - height, pixmap.width(), height);
- pt = {top_left.x(), pixmap_top + pixmap.height() - height};
- }
- QRectF draw_rect = {top_left, r.size()};
- if (!r.isNull() && rect.contains(draw_rect))
- {
- p.drawPixmap(pt, snapshot.image, r);
+ px_rect = QRectF(0, (rows - height), cols, height);
+ px_pt = QPointF(topleft_text.x(), top_row + (rows - height));
}
+ else continue;
+ double dpr = editor_area->devicePixelRatioF();
+ p.drawPixmap(
+ QPointF {px_pt.x() * font_width, px_pt.y() * font_height},
+ snapshot.image,
+ QRectF {
+ px_rect.x() * font_width * dpr,
+ px_rect.y() * font_height * dpr,
+ px_rect.width() * font_width * dpr,
+ px_rect.height() * font_height * dpr
+ }
+ );
}
float offset = cur_snapshot_top - cur_scroll_y;
QPointF pt = {top_left.x(), top_left.y() + offset};
@@ -417,7 +437,7 @@ void QPaintGrid::update_position(double new_x, double new_y)
top_left = {new_x * font_width, new_y * font_height};
}
-void QPaintGrid::initialize_cache()
+void QPaintGrid::init_connections()
{
QObject::connect(editor_area, &QEditor::font_changed, this, [&] {
text_cache.clear();
diff --git a/src/qpaintgrid.hpp b/src/qpaintgrid.hpp
index 89fe99a7..17e199f1 100644
--- a/src/qpaintgrid.hpp
+++ b/src/qpaintgrid.hpp
@@ -36,7 +36,7 @@ class QPaintGrid : public GridBase
{
update_pixmap_size();
update_position(x, y);
- initialize_cache();
+ init_connections();
initialize_scroll_animation();
initialize_move_animation();
}
@@ -85,8 +85,8 @@ class QPaintGrid : public GridBase
);
/// Update the pixmap size
void update_pixmap_size();
- /// Initialize the cache
- void initialize_cache();
+ /// Create necessary connections between editor and grid
+ void init_connections();
/// Initialize scroll animation timer
void initialize_scroll_animation();
/// Initialize move animation timer
diff --git a/src/utils.hpp b/src/utils.hpp
index 31c31c6c..2d561605 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -133,7 +133,7 @@ msgpack::object_handle pack(const T& obj)
inline QString default_font_family()
{
#if defined(Q_OS_MAC)
- return "Courier New";
+ return "Menlo";
#elif defined(Q_OS_WIN)
return "Consolas";
#else
diff --git a/test/test_default_colors.cpp b/test/test_default_colors.cpp
index ebd8a67b..35b822f2 100644
--- a/test/test_default_colors.cpp
+++ b/test/test_default_colors.cpp
@@ -1,4 +1,4 @@
-#include
+#include
#include
#include "hlstate.hpp"
#include "object.hpp"
diff --git a/test/test_hl_attr_from_object.cpp b/test/test_hl_attr_from_object.cpp
index 58a90c2d..8bc1af22 100644
--- a/test/test_hl_attr_from_object.cpp
+++ b/test/test_hl_attr_from_object.cpp
@@ -1,6 +1,6 @@
#include "object.hpp"
#include "hlstate.hpp"
-#include
+#include
#include
#include
#include
diff --git a/test/test_main.cpp b/test/test_main.cpp
index 4ed06df1..927523ec 100644
--- a/test/test_main.cpp
+++ b/test/test_main.cpp
@@ -1,2 +1,7 @@
-#define CATCH_CONFIG_MAIN
-#include
+#include
+
+int main(int argc, char** argv)
+{
+ int result = Catch::Session().run(argc, argv);
+ return result;
+}
diff --git a/test/test_nvim_eval.cpp b/test/test_nvim_eval.cpp
index a6300d40..5a4eee46 100644
--- a/test/test_nvim_eval.cpp
+++ b/test/test_nvim_eval.cpp
@@ -1,6 +1,6 @@
#include "nvim.hpp"
#include "utils.hpp"
-#include
+#include
#include
#include
#include
diff --git a/test/test_nvim_set_var.cpp b/test/test_nvim_set_var.cpp
index 47d7a87b..fb5d8e67 100644
--- a/test/test_nvim_set_var.cpp
+++ b/test/test_nvim_set_var.cpp
@@ -1,6 +1,6 @@
#include "nvim.hpp"
#include "utils.hpp"
-#include
+#include
#include
#include
#include
diff --git a/test/test_object.cpp b/test/test_object.cpp
index bacf2591..07472486 100644
--- a/test/test_object.cpp
+++ b/test/test_object.cpp
@@ -1,6 +1,6 @@
#include
#include "object.hpp"
-#include
+#include
#include
#include
diff --git a/test/test_object_deserialization_msgpack.cpp b/test/test_object_deserialization_msgpack.cpp
index 1c9f4d6c..d3fe2f71 100644
--- a/test/test_object_deserialization_msgpack.cpp
+++ b/test/test_object_deserialization_msgpack.cpp
@@ -1,4 +1,4 @@
-#include
+#include
#include "object.hpp"
#include
#include
diff --git a/vcpkg b/vcpkg
index 03ca9b59..89e38172 160000
--- a/vcpkg
+++ b/vcpkg
@@ -1 +1 @@
-Subproject commit 03ca9b59af1506a86840e3a3a01a092f3333a29b
+Subproject commit 89e38172980b10200c2170a1914300643b352b85
diff --git a/vcpkg.json b/vcpkg.json
index f22d4471..d58e5125 100644
--- a/vcpkg.json
+++ b/vcpkg.json
@@ -5,8 +5,12 @@
"dependencies": [
"fmt",
"msgpack",
- "qt5-base",
- "qt5-svg",
+ {
+ "name": "qt5-base"
+ },
+ {
+ "name": "qt5-svg"
+ },
"boost-process",
"boost-container"
],