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
178 changes: 175 additions & 3 deletions RimeWithWeasel/RimeWithWeasel.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include <logging.h>
#include <RimeWithWeasel.h>
#include <StringAlgorithm.hpp>
Expand Down Expand Up @@ -268,6 +268,9 @@ BOOL RimeWithWeaselHandler::ProcessKeyEvent(KeyEvent keyEvent,
<< ", mask = " << keyEvent.mask << ", ipc_id = " << ipc_id;
if (m_disabled)
return FALSE;
BOOL grid_handled = FALSE;
if (_HandleGridKeyEvent(keyEvent, ipc_id, eat, grid_handled))
return grid_handled;
RimeSessionId session_id = to_session_id(ipc_id);
Bool handled = rime_api->process_key(session_id, keyEvent.keycode,
expand_ibus_modifier(keyEvent.mask));
Expand Down Expand Up @@ -472,6 +475,161 @@ void RimeWithWeaselHandler::_GetCandidateInfo(CandidateInfo& cinfo,
cinfo.is_last_page = ctx.menu.is_last_page;
}

void RimeWithWeaselHandler::_GetCandidateInfo(CandidateInfo& cinfo,
RimeSessionId session_id,
SessionStatus& session_status) {
RIME_STRUCT(RimeContext, ctx);
if (!rime_api->get_context(session_id, &ctx))
return;

if (!session_status.style.grid_layout || !ctx.menu.num_candidates) {
_GetCandidateInfo(cinfo, ctx);
rime_api->free_context(&ctx);
return;
}

const int columns = session_status.style.grid_columns;
const int visible_rows = session_status.style.grid_visible_rows;
const int visible_count = columns * visible_rows;
const int highlighted = ctx.menu.page_no * ctx.menu.page_size +
ctx.menu.highlighted_candidate_index;
if (session_status.grid_row_offset < 0)
session_status.grid_row_offset = 0;
if (session_status.grid_window_row_offset < 0)
session_status.grid_window_row_offset = 0;
if (highlighted < session_status.grid_window_row_offset * columns ||
highlighted >=
(session_status.grid_window_row_offset + visible_rows) * columns) {
session_status.grid_window_row_offset = max(0, highlighted / columns);
session_status.grid_row_offset = session_status.grid_window_row_offset;
}
const int start = session_status.grid_window_row_offset * columns;

RimeCandidateListIterator it = {0};
if (!rime_api->candidate_list_from_index(session_id, &it, start)) {
_GetCandidateInfo(cinfo, ctx);
rime_api->free_context(&ctx);
return;
}

int count = 0;
while (count < visible_count && rime_api->candidate_list_next(&it)) {
Text candidate;
candidate.str = escape_string(u8tow(it.candidate.text));
cinfo.candies.push_back(candidate);

Text comment;
if (it.candidate.comment)
comment.str = escape_string(u8tow(it.candidate.comment));
cinfo.comments.push_back(comment);

Text label;
label.str = std::to_wstring((count % columns) + 1);
cinfo.labels.push_back(label);
++count;
}
rime_api->candidate_list_end(&it);

cinfo.highlighted = highlighted >= start && highlighted < start + count
? highlighted - start
: 0;
cinfo.currentPage = session_status.grid_window_row_offset;
cinfo.is_last_page = count < visible_count;
rime_api->free_context(&ctx);
}

bool RimeWithWeaselHandler::_HandleGridKeyEvent(KeyEvent keyEvent,
WeaselSessionId ipc_id,
EatLine eat,
BOOL& handled) {
if ((keyEvent.mask & ibus::Modifier::RELEASE_MASK) || !ipc_id)
return false;
SessionStatus& session_status = get_session_status(ipc_id);
if (!session_status.style.grid_layout)
return false;

RimeSessionId session_id = session_status.session_id;
RIME_STRUCT(RimeContext, ctx);
if (!rime_api->get_context(session_id, &ctx))
return false;
const bool has_candidates = ctx.menu.num_candidates > 0;
rime_api->free_context(&ctx);
if (!has_candidates) {
session_status.grid_row_offset = 0;
session_status.grid_window_row_offset = 0;
return false;
}

const int columns = session_status.style.grid_columns;
const int visible_rows = session_status.style.grid_visible_rows;
const bool no_command_modifier =
(keyEvent.mask &
(ibus::Modifier::CONTROL_MASK | ibus::Modifier::ALT_MASK |
ibus::Modifier::META_MASK | ibus::Modifier::SUPER_MASK |
ibus::Modifier::HYPER_MASK)) == 0;
const bool plain =
no_command_modifier && !(keyEvent.mask & ibus::Modifier::SHIFT_MASK);

if (no_command_modifier &&
(keyEvent.keycode == '+' || keyEvent.keycode == '=' ||
keyEvent.keycode == ibus::KP_Add)) {
const int next_row_offset = session_status.grid_row_offset + 1;
RimeCandidateListIterator it = {0};
bool has_next_row = rime_api->candidate_list_from_index(
session_id, &it, next_row_offset * columns) &&
rime_api->candidate_list_next(&it);
rime_api->candidate_list_end(&it);
if (has_next_row) {
session_status.grid_row_offset = next_row_offset;
if (session_status.grid_row_offset >=
session_status.grid_window_row_offset + visible_rows) {
session_status.grid_window_row_offset =
session_status.grid_row_offset - visible_rows + 1;
}
}
rime_api->highlight_candidate(session_id,
session_status.grid_row_offset * columns);
_Respond(ipc_id, eat);
_UpdateUI(ipc_id);
m_active_session = ipc_id;
handled = TRUE;
return true;
}

if (plain &&
(keyEvent.keycode == '-' || keyEvent.keycode == ibus::KP_Subtract)) {
if (session_status.grid_row_offset > 0)
--session_status.grid_row_offset;
if (session_status.grid_row_offset < session_status.grid_window_row_offset)
session_status.grid_window_row_offset = session_status.grid_row_offset;
rime_api->highlight_candidate(session_id,
session_status.grid_row_offset * columns);
_Respond(ipc_id, eat);
_UpdateUI(ipc_id);
m_active_session = ipc_id;
handled = TRUE;
return true;
}

int digit = 0;
if (keyEvent.keycode >= '1' && keyEvent.keycode <= '9')
digit = keyEvent.keycode - '0';
else if (keyEvent.keycode >= ibus::KP_1 && keyEvent.keycode <= ibus::KP_9)
digit = keyEvent.keycode - ibus::KP_0;

if (plain && digit >= 1 && digit <= columns) {
const size_t index =
(size_t)(session_status.grid_row_offset * columns + digit - 1);
handled = (BOOL)rime_api->select_candidate(session_id, index);
_Respond(ipc_id, eat);
_UpdateUI(ipc_id);
m_active_session = ipc_id;
return true;
}

return false;
}

void RimeWithWeaselHandler::StartMaintenance() {
m_session_status_map.clear();
Finalize();
Expand Down Expand Up @@ -789,7 +947,7 @@ bool RimeWithWeaselHandler::_Respond(WeaselSessionId ipc_id, EatLine eat) {
bool has_candidates = ctx.menu.num_candidates > 0;
CandidateInfo cinfo;
if (has_candidates) {
_GetCandidateInfo(cinfo, ctx);
_GetCandidateInfo(cinfo, session_id, session_status);
}
if (is_composing) {
const auto& preedit = ctx.composition.preedit;
Expand Down Expand Up @@ -1282,6 +1440,19 @@ static void _UpdateUIStyle(RimeConfig* config, UI* ui, bool initialize) {
_RimeGetIntStr(config, "style/layout/spacing", style.spacing, 0, 0, _abs);
_RimeGetIntStr(config, "style/layout/candidate_spacing",
style.candidate_spacing, 0, 0, _abs);
_RimeGetBool(config, "style/layout/grid", false, style.grid_layout);
_RimeGetIntStr(config, "style/layout/grid_columns", style.grid_columns, 0, 0,
_abs);
if (style.grid_columns <= 0)
style.grid_columns = UIStyle::DEFAULT_GRID_COLUMNS;
_RimeGetIntStr(config, "style/layout/grid_visible_rows",
style.grid_visible_rows, 0, 0, _abs);
if (style.grid_visible_rows <= 0)
style.grid_visible_rows = UIStyle::DEFAULT_GRID_VISIBLE_ROWS;
_RimeGetIntStr(config, "style/layout/grid_cell_width", style.grid_cell_width,
0, 0, _abs);
_RimeGetIntStr(config, "style/layout/grid_cell_height",
style.grid_cell_height, 0, 0, _abs);
_RimeGetIntStr(config, "style/layout/hilite_spacing", style.hilite_spacing, 0,
0, _abs);
_RimeGetIntStr(config, "style/layout/hilite_padding_x",
Expand Down Expand Up @@ -1492,7 +1663,8 @@ void RimeWithWeaselHandler::_GetContext(Context& weasel_context,
}
if (ctx.menu.num_candidates) {
CandidateInfo& cinfo(weasel_context.cinfo);
_GetCandidateInfo(cinfo, ctx);
SessionStatus& session_status = get_session_status(m_active_session);
_GetCandidateInfo(cinfo, session_id, session_status);
}
rime_api->free_context(&ctx);
}
Expand Down
121 changes: 121 additions & 0 deletions WeaselUI/HorizontalLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,127 @@ void HorizontalLayout::DoLayout(CDCHandle dc, PDWR pDWR) {
width = max(width, real_margin_x * 2 + size.cx);
}

if (_style.grid_layout && candidates_count) {
int columns = min(max(_style.grid_columns, 1), MAX_CANDIDATES_COUNT);
int rows = (candidates_count + columns - 1) / columns;
int cell_width = _style.grid_cell_width;
int cell_height = _style.grid_cell_height;

for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) {
int natural_width = 0;
int natural_height = 0;

std::wstring label =
GetLabelText(labels, i, _style.label_text_format.c_str());
GetTextSizeDW(label, label.length(), pDWR->pLabelTextFormat, pDWR, &size);
_candidateLabelRects[i].SetRect(0, 0, size.cx * labelFontValid, size.cy);
natural_width += size.cx * labelFontValid;
natural_height = max(natural_height, size.cy);

const std::wstring& text = candidates.at(i).str;
GetTextSizeDW(text, text.length(), pDWR->pTextFormat, pDWR, &size);
_candidateTextRects[i].SetRect(0, 0, size.cx * textFontValid, size.cy);
natural_width += (size.cx + _style.hilite_spacing) * textFontValid;
natural_height = max(natural_height, size.cy);

bool cmtFontNotTrans =
(i == id && (_style.hilited_comment_text_color & 0xff000000)) ||
(i != id && (_style.comment_text_color & 0xff000000));
if (!comments.at(i).str.empty() && cmtFontValid && cmtFontNotTrans) {
const std::wstring& comment = comments.at(i).str;
GetTextSizeDW(comment, comment.length(), pDWR->pCommentTextFormat, pDWR,
&size);
_candidateCommentRects[i].SetRect(0, 0, size.cx * cmtFontValid,
size.cy);
natural_width += (size.cx + _style.hilite_spacing) * cmtFontValid;
natural_height = max(natural_height, size.cy);
} else {
_candidateCommentRects[i].SetRect(0, 0, 0, natural_height);
}

if (i == id)
natural_width += base_offset;
cell_width = max(cell_width, natural_width);
cell_height = max(cell_height, natural_height);
}

cell_width = max(cell_width, 1);
cell_height = max(cell_height, 1);

for (auto i = 0; i < candidates_count && i < MAX_CANDIDATES_COUNT; ++i) {
int col = i % columns;
int row = i / columns;
int cell_left = offsetX + real_margin_x +
col * (cell_width + _style.candidate_spacing);
int cell_top = height + row * (cell_height + _style.candidate_spacing);
int x = cell_left + (i == id ? base_offset : 0);

_candidateLabelRects[i].OffsetRect(x, cell_top);
x = _candidateLabelRects[i].right + _style.hilite_spacing;
_candidateTextRects[i].OffsetRect(x, cell_top);
x = _candidateTextRects[i].right;
if (!_candidateCommentRects[i].IsRectEmpty()) {
x += _style.hilite_spacing;
_candidateCommentRects[i].OffsetRect(x, cell_top);
} else {
_candidateCommentRects[i].OffsetRect(x, cell_top);
}

int ol = 0, ot = 0, oc = 0;
if (_style.align_type == UIStyle::ALIGN_CENTER) {
ol = (cell_height - _candidateLabelRects[i].Height()) / 2;
ot = (cell_height - _candidateTextRects[i].Height()) / 2;
oc = (cell_height - _candidateCommentRects[i].Height()) / 2;
} else if (_style.align_type == UIStyle::ALIGN_BOTTOM) {
ol = cell_height - _candidateLabelRects[i].Height();
ot = cell_height - _candidateTextRects[i].Height();
oc = cell_height - _candidateCommentRects[i].Height();
}
_candidateLabelRects[i].OffsetRect(0, ol);
_candidateTextRects[i].OffsetRect(0, ot);
_candidateCommentRects[i].OffsetRect(0, oc);

_candidateRects[i].SetRect(cell_left, cell_top, cell_left + cell_width,
cell_top + cell_height);
}

width = max(width, offsetX + real_margin_x + columns * cell_width +
max(0, columns - 1) * _style.candidate_spacing);
height += rows * cell_height + max(0, rows - 1) * _style.candidate_spacing -
offsetY;
width += real_margin_x;
height += real_margin_y;

width = max(width, _style.min_width);
height = max(height, _style.min_height);

_highlightRect = _candidateRects[id];
UpdateStatusIconLayout(&width, &height);
_contentSize.SetSize(width + offsetX, height + 2 * offsetY);
_contentRect.SetRect(0, 0, _contentSize.cx, _contentSize.cy);

if (page_en && !_style.inline_preedit) {
int _prex = _contentSize.cx - offsetX - real_margin_x +
_style.hilite_padding_x - pgw;
int _prey = (_preeditRect.top + _preeditRect.bottom) / 2 - pgszl.cy / 2;
_prePageRect.SetRect(_prex, _prey, _prex + pgszl.cx, _prey + pgszl.cy);
_nextPageRect.SetRect(
_prePageRect.right + _style.hilite_spacing, _prey,
_prePageRect.right + _style.hilite_spacing + pgszr.cx,
_prey + pgszr.cy);
if (ShouldDisplayStatusIcon()) {
_prePageRect.OffsetRect(-STATUS_ICON_SIZE, 0);
_nextPageRect.OffsetRect(-STATUS_ICON_SIZE, 0);
}
}

CopyRect(_bgRect, _contentRect);
_bgRect.DeflateRect(offsetX + 1, offsetY + 1);
_PrepareRoundInfo(dc);
_contentRect.DeflateRect(offsetX, offsetY);
return;
}

int row_cnt = 0;
int max_width_of_rows = 0;
int height_of_rows[MAX_CANDIDATES_COUNT] = {0}; // height of every row
Expand Down
2 changes: 2 additions & 0 deletions WeaselUI/Layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Layout::Layout(const UIStyle& style,
_style.margin_y = (int)(_style.margin_y * scale);
_style.spacing = (int)(_style.spacing * scale);
_style.candidate_spacing = (int)(_style.candidate_spacing * scale);
_style.grid_cell_width = (int)(_style.grid_cell_width * scale);
_style.grid_cell_height = (int)(_style.grid_cell_height * scale);
_style.hilite_spacing = (int)(_style.hilite_spacing * scale);
_style.hilite_padding_x = (int)(_style.hilite_padding_x * scale);
_style.hilite_padding_y = (int)(_style.hilite_padding_y * scale);
Expand Down
16 changes: 15 additions & 1 deletion include/RimeWithWeasel.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,20 @@ typedef std::map<std::string, AppOptions, CaseInsensitiveCompare>
AppOptionsByAppName;

struct SessionStatus {
SessionStatus() : style(weasel::UIStyle()), __synced(false), session_id(0) {
SessionStatus()
: style(weasel::UIStyle()),
__synced(false),
session_id(0),
grid_row_offset(0),
grid_window_row_offset(0) {
RIME_STRUCT(RimeStatus, status);
}
weasel::UIStyle style;
RimeStatus status;
bool __synced;
RimeSessionId session_id;
int grid_row_offset;
int grid_window_row_offset;
};
typedef std::map<DWORD, SessionStatus> SessionStatusMap;
typedef DWORD WeaselSessionId;
Expand Down Expand Up @@ -77,6 +84,13 @@ class RimeWithWeaselHandler : public weasel::RequestHandler {
bool _Respond(WeaselSessionId ipc_id, EatLine eat);
void _ReadClientInfo(WeaselSessionId ipc_id, LPWSTR buffer);
void _GetCandidateInfo(weasel::CandidateInfo& cinfo, RimeContext& ctx);
void _GetCandidateInfo(weasel::CandidateInfo& cinfo,
RimeSessionId session_id,
SessionStatus& session_status);
bool _HandleGridKeyEvent(weasel::KeyEvent keyEvent,
WeaselSessionId ipc_id,
EatLine eat,
BOOL& handled);
void _GetStatus(weasel::Status& stat,
WeaselSessionId ipc_id,
weasel::Context& ctx);
Expand Down
Loading
Loading