Skip to content

Commit

Permalink
Add GuiAdaptive{Color,Font,Style,StyleList}
Browse files Browse the repository at this point in the history
Configures Qt to use Neovim font/color settings.

`:GuiAdaptiveColor 1` will paint Qt Widgets with the neovim
foreground/background colors.

`:GuiAdaptiveFont 1` will set Qt font styling to the active neovim font.

`GuiAdaptiveStyle {name}` will override the Qt style.

`GuiAdaptiveStyleList {name}` will print all installed Qt Style names
  • Loading branch information
jgehrig committed Sep 8, 2020
1 parent 7a7b6b2 commit 05885ba
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 6 deletions.
143 changes: 142 additions & 1 deletion src/gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
#include <QCloseEvent>
#include <QLayout>
#include <QSettings>
#include <QStyleFactory>
#include <QToolBar>

namespace NeovimQt {

MainWindow::MainWindow(NeovimConnector* c, ShellOptions opts, QWidget* parent)
: QMainWindow(parent)
, m_shell_options(opts)
, m_defaultFont{ font() }
, m_defaultPalette{ palette() }
{
m_errorWidget = new ErrorWidget();
m_stack.addWidget(m_errorWidget);
Expand Down Expand Up @@ -124,6 +127,19 @@ void MainWindow::init(NeovimConnector *c)
this, &MainWindow::neovimSendPaste);
connect(m_actSelectAll, &QAction::triggered,
this, &MainWindow::neovimSendSelectAll);

// GuiAdaptive Color/Font/Style Signal/Slot Connections
connect(m_shell, &Shell::setGuiAdaptiveColorEnabled,
this, &MainWindow::setGuiAdaptiveColorEnabled);
connect(m_shell, &Shell::setGuiAdaptiveFontEnabled,
this, &MainWindow::setGuiAdaptiveFontEnabled);
connect(m_shell, &Shell::setGuiAdaptiveStyle,
this, &MainWindow::setGuiAdaptiveStyle);
connect(m_shell, &Shell::showGuiAdaptiveStyleList,
this, &MainWindow::showGuiAdaptiveStyleList);
connect(m_shell, &Shell::colorsChanged,
this, &MainWindow::updateAdaptiveColor);

m_shell->setFocus(Qt::OtherFocusReason);

if (m_nvim->errorCause()) {
Expand Down Expand Up @@ -416,4 +432,129 @@ void MainWindow::restoreWindowGeometry()
restoreState(settings.value("window_state").toByteArray());
}

} // namespace NeovimQt
void MainWindow::setGuiAdaptiveColorEnabled(bool isEnabled)
{
m_isAdaptiveColorEnabled = isEnabled;

updateAdaptiveColor();
}

void MainWindow::setGuiAdaptiveFontEnabled(bool isEnabled)
{
m_isAdaptiveFontEnabled = isEnabled;

updateAdaptiveFont();
}

void MainWindow::setGuiAdaptiveStyle(const QString& styleName)
{
// The style may be empty if the name is invalid. This appears to be safe,
// calling setStyle(nullptr) will restore the default Qt Style.
QStyle* pStyle{ QStyleFactory::create(styleName) };

auto childrenWidgets{ findChildren<QWidget*>() + m_shell->findChildren<QWidget*>() };

for (const auto childWidget : childrenWidgets) {
childWidget->setStyle(pStyle);
}

setStyle(pStyle);
}

void MainWindow::showGuiAdaptiveStyleList()
{
const QString styleKeys{ QStyleFactory::keys().join("\n") };
QString echoCommand{ R"(echo "%1")" };
m_nvim->api0()->vim_command(echoCommand.arg(styleKeys).toLatin1());
}

void MainWindow::updateAdaptiveFont() noexcept
{
if (!m_shell) {
return;
}

const QFont& font{ (m_isAdaptiveFontEnabled) ?
m_shell->font() : m_defaultFont };

setFont(font);

auto childrenWidgets{ findChildren<QWidget*>() + m_shell->findChildren<QWidget*>() };

for (const auto childWidget : childrenWidgets) {
// Do not call setFont() on ShellWidget objects
if (qobject_cast<ShellWidget*>(childWidget)) {
continue;
}

childWidget->setFont(font);
}
}

static QPalette CreatePaletteFromHighlightGroups(const Shell& shell) noexcept
{
const QColor& background{ shell.background() };
const QColor& foreground{ shell.foreground() };

QPalette palette;
palette.setColor(QPalette::Background, background);
palette.setColor(QPalette::Foreground, foreground);
palette.setColor(QPalette::Window, background);
palette.setColor(QPalette::WindowText, foreground);
palette.setColor(QPalette::Base, background);
palette.setColor(QPalette::Text, foreground);
palette.setColor(QPalette::Button, background);
palette.setColor(QPalette::ButtonText, foreground);

return palette;
}

void MainWindow::updateAdaptiveColor() noexcept
{
if (!m_shell) {
return;
}

auto setPaletteAllChildren = [&](const QPalette& palette) noexcept
{
setPalette(palette);
auto childrenWidgets{ findChildren<QWidget*>() + m_shell->findChildren<QWidget*>() };

for (const auto childWidget : childrenWidgets) {
childWidget->setPalette(palette);
}
};

if (!m_isAdaptiveColorEnabled) {
setPaletteAllChildren(m_defaultPalette);
return;
}

setPaletteAllChildren(CreatePaletteFromHighlightGroups(*m_shell));

// Some widgets support specialized palettes
PopupMenu& popupMenu{ m_shell->getPopupMenu() };
const bool isPopupMenuSupported { m_shell->IsHighlightGroup("Pmenu")
&& m_shell->IsHighlightGroup("PmenuSel") };
if (isPopupMenuSupported) {
QPalette palette;

const HighlightAttribute pmenu{ m_shell->GetHighlightGroup("Pmenu") };
palette.setColor(QPalette::Base, pmenu.GetBackgroundColor());
palette.setColor(QPalette::Text, pmenu.GetForegroundColor());

const HighlightAttribute pmenusel{ m_shell->GetHighlightGroup("PmenuSel") };
palette.setColor(QPalette::Highlight, pmenusel.GetBackgroundColor());
palette.setColor(QPalette::HighlightedText, pmenusel.GetForegroundColor());

auto childrenWidgets{ popupMenu.findChildren<QWidget*>() };

for (const auto childWidget : childrenWidgets) {
childWidget->setPalette(palette);
}

popupMenu.setPalette(palette);
}
}

} // namespace NeovimQt
19 changes: 15 additions & 4 deletions src/gui/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
#define NEOVIM_QT_MAINWINDOW

#include <QMainWindow>
#include <QPalette>
#include <QSplitter>
#include <QStackedWidget>
#include <QTabBar>
#include <QSplitter>
#include "treeview.h"
#include "neovimconnector.h"

#include "errorwidget.h"
#include "neovimconnector.h"
#include "scrollbar.h"
#include "shell.h"
#include "treeview.h"

namespace NeovimQt {

Expand Down Expand Up @@ -59,6 +61,12 @@ private slots:
void changeTab(int index);
void saveWindowGeometry();

// GuiAdaptive Color/Font/Style Slots
void setGuiAdaptiveColorEnabled(bool isEnabled);
void setGuiAdaptiveFontEnabled(bool isEnabled);
void setGuiAdaptiveStyle(const QString& style);
void showGuiAdaptiveStyleList();

private:
void init(NeovimConnector *);

Expand All @@ -81,11 +89,14 @@ private slots:
QAction* m_actSelectAll{ nullptr };
ScrollBar* m_scrollbar{ nullptr };

// GuiAdaptive Color/Font
// GuiAdaptive Color/Font/Style
bool m_isAdaptiveColorEnabled{ false };
bool m_isAdaptiveFontEnabled{ false };
QFont m_defaultFont;
QPalette m_defaultPalette;

void updateAdaptiveColor() noexcept;
void updateAdaptiveFont() noexcept;
};

} // Namespace
Expand Down
20 changes: 19 additions & 1 deletion src/gui/runtime/doc/nvim_gui_shim.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,25 @@ can be used in |ginit.vim| provided that
==============================================================================
1. Commands

*Guifont* *GuiFont*
*GuiAdaptiveColor*
GuiAdaptiveColor Use the neovim `colorscheme` to style the GUI.
>
:GuiAdaptiveColor 1
<
*GuiAdaptiveFont*
GuiAdaptiveFont Use the current `GuiFont`` to decorate the GUI.
>
:GuiAdaptiveFont 1
<
*GuiAdaptiveStyle*
GuiAdaptiveStyle Override the default Qt Style/Theme. See
>
:GuiAdaptiveStyle Fusion
<
*GuiAdaptiveStyleList*
GuiAdaptiveStyleList Shows the list of available Qt Styles.

*GuiFont*
GuiFont When called with no arguments this command display the
current font used by the GUI.

Expand Down
24 changes: 24 additions & 0 deletions src/gui/runtime/plugin/nvim_gui_shim.vim
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,27 @@ function! s:GuiScrollBar(enable) abort
endfunction

command! -nargs=1 GuiScrollBar call s:GuiScrollBar(<args>)

" Use Neovim theming for Qt Widgets
function! s:GuiAdaptiveColor(enable) abort
call rpcnotify(0, 'Gui', 'AdaptiveColor', a:enable)
endfunction
command! -nargs=1 GuiAdaptiveColor call s:GuiAdaptiveColor(<args>)

" Use Neovim font for Qt Widgets
function! s:GuiAdaptiveFont(enable) abort
call rpcnotify(0, 'Gui', 'AdaptiveFont', a:enable)
endfunction
command! -nargs=1 GuiAdaptiveFont call s:GuiAdaptiveFont(<args>)

" Override default Qt Style using QStyleFactory
function! s:GuiAdaptiveStyle(styleName, ...) abort
call rpcnotify(0, 'Gui', 'AdaptiveStyle', a:styleName)
endfunction
command! -nargs=? GuiAdaptiveStyle call s:GuiAdaptiveStyle("<args>")

" Print a list of available Qt Styles
function! s:GuiAdaptiveStyleList() abort
call rpcnotify(0, 'Gui', 'AdaptiveStyleList')
endfunction
command! -nargs=0 GuiAdaptiveStyleList call s:GuiAdaptiveStyleList()
68 changes: 68 additions & 0 deletions src/gui/shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ void Shell::handleRedraw(const QByteArray& name, const QVariantList& opargs)
} else if (name == "grid_scroll") {
handleGridScroll(opargs);
} else if (name == "hl_group_set") {
handleHighlightGroupSet(opargs);
} else if (name == "win_viewport") {
} else {
qDebug() << "Received unknown redraw notification" << name << opargs;
Expand Down Expand Up @@ -818,6 +819,14 @@ void Shell::handleNeovimNotification(const QByteArray &name, const QVariantList&
QGuiApplication::clipboard()->setMimeData(clipData, clipboard);
} else if (guiEvName == "ShowContextMenu") {
emit neovimShowContextMenu();
} else if (guiEvName == "AdaptiveColor") {
handleGuiAdaptiveColor(args);
} else if (guiEvName == "AdaptiveFont") {
handleGuiAdaptiveFont(args);
} else if (guiEvName == "AdaptiveStyle") {
handleGuiAdaptiveStyle(args);
} else if (guiEvName == "AdaptiveStyleList") {
handleGuiAdaptiveStyleList();
}
return;
} else if (name != "redraw") {
Expand Down Expand Up @@ -964,6 +973,7 @@ void Shell::handleDefaultColorsSet(const QVariantList& opargs)

// Cells drawn with the default colors require a re-paint
update();
emit colorsChanged();
}

void Shell::handleHighlightAttributeDefine(const QVariantList& opargs)
Expand All @@ -986,6 +996,20 @@ void Shell::handleHighlightAttributeDefine(const QVariantList& opargs)
m_highlightMap.insert(id, hl_attr);
}

void Shell::handleHighlightGroupSet(const QVariantList& opargs) noexcept
{
if (opargs.size() < 2
|| opargs.at(0).type() != QVariant::Type::ByteArray
|| !opargs.at(1).canConvert<uint64_t>()) {
qWarning() << "Unexpected arguments for hl_group_set:" << opargs;
return;
}

const QString name{ m_nvim->decode(opargs.at(0).toByteArray()) };
const uint64_t hl_id{ opargs.at(1).toULongLong() };

m_highlightGroupNameMap.insert(name, hl_id);
}

void Shell::handleGridLine(const QVariantList& opargs)
{
Expand Down Expand Up @@ -1095,6 +1119,50 @@ void Shell::handleGridScroll(const QVariantList& opargs)
update(neovimCursorRect());
}

void Shell::handleGuiAdaptiveColor(const QVariantList& opargs) noexcept
{
if (opargs.size() < 2
|| !opargs.at(1).canConvert<bool>()) {
qWarning() << "Unexpected arguments for GuiAdaptiveColor:" << opargs;
return;
}

const bool isEnabled{ opargs.at(1).toBool() };

emit setGuiAdaptiveColorEnabled(isEnabled);
}

void Shell::handleGuiAdaptiveFont(const QVariantList& opargs) noexcept
{
if (opargs.size() < 2
|| !opargs.at(1).canConvert<bool>()) {
qWarning() << "Unexpected arguments for GuiAdaptiveFont:" << opargs;
return;
}

const bool isEnabled{ opargs.at(1).toBool() };

emit setGuiAdaptiveFontEnabled(isEnabled);
}

void Shell::handleGuiAdaptiveStyle(const QVariantList& opargs) noexcept
{
if (opargs.size() < 2
|| !opargs.at(1).canConvert<QByteArray>()) {
qWarning() << "Unexpected arguments for GuiAdaptiveStyle:" << opargs;
return;
}

const QString styleName { opargs.at(1).toByteArray() };

emit setGuiAdaptiveStyle(styleName);
}

void Shell::handleGuiAdaptiveStyleList() noexcept
{
emit showGuiAdaptiveStyleList();
}

void Shell::paintEvent(QPaintEvent *ev)
{
if (!m_attached) {
Expand Down

0 comments on commit 05885ba

Please sign in to comment.