Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 65 additions & 12 deletions src/renderer/qt/qt_window_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <cmath>
#include <cstddef>
#include <string>
#include <utility>

#include "absl/log/check.h"
#include "absl/log/log.h"
Expand All @@ -42,6 +43,7 @@
#include "client/client_interface.h"
#include "protocol/candidate_window.pb.h"
#include "protocol/commands.pb.h"
#include "protocol/renderer_style.pb.h"
#include "renderer/renderer_style_handler.h"
#include "renderer/window_util.h"

Expand Down Expand Up @@ -71,6 +73,30 @@ QBrush QBrushFromColor(const RendererStyle::RGBAColor& rgba) {

} // namespace

void FooterBackgroundDelegate::paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const {
// The footer is the last row of the candidate window.
if (index.row() == index.model()->rowCount() - 1) {
QRect rect = option.rect;

// Separator lines between the main content area and the footer.
for (int i = 0; i < separator_colors_.size(); ++i) {
painter->fillRect(QRect(rect.left(), rect.top() + i, rect.width(), 1),
separator_colors_[i]);
}
rect.adjust(0, separator_colors_.size(), 0, 0);

// The gradient is anchored to the remaining cell rectangle, which spans
// the full height of the footer row.
QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
gradient.setColorAt(0, top_);
gradient.setColorAt(1, bottom_);
painter->fillRect(rect, gradient);
}
QStyledItemDelegate::paint(painter, option, index);
}

QtWindowManager::QtWindowManager() {
RendererStyleHandler::GetRendererStyle(&style_);
}
Expand Down Expand Up @@ -113,6 +139,8 @@ void QtWindowManager::Initialize() {

candidates_ = new QTableWidget();
initialize_table(candidates_);
footer_delegate_ = new FooterBackgroundDelegate(candidates_);
candidates_->setItemDelegate(footer_delegate_);
QObject::connect(candidates_, &QTableWidget::cellClicked,
[&](int row, int col) { OnClicked(row, col); });

Expand All @@ -130,17 +158,39 @@ void QtWindowManager::ApplyStyleToWidgets() {
QColorFromColor(style_.candidate_style().background_color());
const QColor foreground =
QColorFromColor(style_.candidate_style().foreground_color());
const QColor border = QColorFromColor(style_.border_color());

// By default the QTableWidget frame and viewport are drawn by the widget
// style from the application palette, which does not necessarily match the
// renderer style. Override them with a style sheet. Note that these colors
// are deliberately not applied via QWidget::setPalette: palette changes are
// not reliably honored on widgets that have a style sheet, which would leave
// stale colors behind when the theme changes at runtime.
const QString sheet = QString(
"QTableWidget { border: %1px solid %2;"
" background-color: %3; color: %4; }")
.arg(style_.window_border())
.arg(border.name())
.arg(background.name())
.arg(foreground.name());

for (QTableWidget* table : {candidates_, infolist_}) {
if (table == nullptr) {
continue;
}
QPalette palette = table->palette();
palette.setColor(QPalette::Base, background);
palette.setColor(QPalette::Window, background);
palette.setColor(QPalette::Text, foreground);
palette.setColor(QPalette::WindowText, foreground);
table->setPalette(palette);
table->setStyleSheet(sheet);
}

if (footer_delegate_ != nullptr) {
footer_delegate_->SetGradientColors(
QColorFromColor(style_.footer_top_color()),
QColorFromColor(style_.footer_bottom_color()));
QList<QColor> separator_colors;
for (const RendererStyle::RGBAColor& color :
style_.footer_border_colors()) {
separator_colors.append(QColorFromColor(color));
}
footer_delegate_->SetSeparatorColors(std::move(separator_colors));
}
}

Expand Down Expand Up @@ -325,8 +375,6 @@ void FillCandidateWindow(const commands::CandidateWindow& candidate_window,
QBrushFromColor(style.candidate_style().foreground_color());
const QBrush description_brush =
QBrushFromColor(style.description_style().foreground_color());
const QBrush footer_bg_brush = QBrushFromColor(style.footer_bottom_color());

// Fill the candidates
std::string shortcut, value, description;
for (size_t i = 0; i < cands_size; ++i) {
Expand Down Expand Up @@ -362,17 +410,22 @@ void FillCandidateWindow(const commands::CandidateWindow& candidate_window,
total_height += height;
}

// Footer
// Footer. The background is painted by FooterBackgroundDelegate.
for (int i = 0; i < table->columnCount(); ++i) {
auto footer_item = new QTableWidgetItem();
footer_item->setBackground(footer_bg_brush);
table->setItem(cands_size, i, footer_item);
}
QTableWidgetItem* footer2 = table->item(cands_size, 2);
footer2->setText(QStr(GetIndexGuideString(candidate_window)));
footer2->setTextAlignment(Qt::AlignRight);
footer2->setForeground(
QBrushFromColor(style.footer_style().foreground_color()));
footer2->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
max_width2 = std::max(max_width2, GetItemWidth(*footer2));
const int footer_height = GetItemHeight(*footer2);
// The separator lines drawn by FooterBackgroundDelegate consume the top
// pixels of the footer cell; enlarge the row so that the visible footer
// content area keeps its height.
const int footer_height =
GetItemHeight(*footer2) + style.footer_border_colors_size();
table->setRowHeight(cands_size, footer_height);
total_height += footer_height;

Expand Down
38 changes: 35 additions & 3 deletions src/renderer/qt/qt_window_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#define MOZC_RENDERER_QT_QT_WINDOW_MANAGER_H_

#include <QtWidgets>
#include <utility>

#include "base/coordinates.h"
#include "client/client_interface.h"
Expand All @@ -40,6 +41,33 @@
namespace mozc {
namespace renderer {

// The gradient needs to be drawn by the delegate rather than set as the items'
// background brush, because gradient QBrush coordinate mapping is not reliable
// in the QTableWidget cell-background path.
class FooterBackgroundDelegate : public QStyledItemDelegate {
public:
explicit FooterBackgroundDelegate(QObject* parent = nullptr)
: QStyledItemDelegate(parent) {}

void SetGradientColors(const QColor& top, const QColor& bottom) {
top_ = top;
bottom_ = bottom;
}

// One 1-pixel separator line is drawn per color, from top to bottom.
void SetSeparatorColors(QList<QColor> colors) {
separator_colors_ = std::move(colors);
}

void paint(QPainter* painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const override;

private:
QColor top_;
QColor bottom_;
QList<QColor> separator_colors_;
};

class QtWindowManager {
public:
QtWindowManager();
Expand Down Expand Up @@ -83,15 +111,19 @@ class QtWindowManager {

void OnClicked(int row, int column);

// Applies the foreground / background colors of the current style_ to the
// candidate and infolist widgets' palettes, so that areas not covered by
// individual cells (e.g. the viewport) also follow the theme.
// Applies the colors of the current style_ to the candidate and infolist
// widgets via a style sheet, so that areas not covered by individual cells
// (e.g. the window border and the viewport) also follow the style.
void ApplyStyleToWidgets();

private:
QTableWidget *candidates_ = nullptr;
QTableWidget *infolist_ = nullptr;

// Does not have the ownership. `footer_delegate_` is a child QObject of
// `candidates_`, which is responsible for destroying it.
FooterBackgroundDelegate* footer_delegate_ = nullptr;
Comment thread
yukawa marked this conversation as resolved.

RendererStyle style_;
commands::RendererCommand prev_command_;
client::SendCommandInterface *send_command_interface_ = nullptr;
Expand Down