Skip to content

Commit

Permalink
a coarse implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
eagleoflqj committed Jun 25, 2024
1 parent 5a01930 commit 66d9227
Show file tree
Hide file tree
Showing 11 changed files with 332 additions and 34 deletions.
24 changes: 21 additions & 3 deletions include/candidate_window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ enum theme_t { system = 0, light = 1, dark = 2 };

enum writing_mode_t { horizontal_tb = 0, vertical_rl = 1, vertical_lr = 2 };

enum scroll_state_t { none = 0, ready = 1, scrolling = 2 };

enum scroll_key_action_t {
one = 1,
two = 2,
three = 3,
four = 4,
five = 5,
six = 6,
up = 10, down = 11, left = 12, right = 13, home = 14, end = 15, expand = 16, collapse = 17 };

struct CandidateAction {
int id;
std::string text;
Expand All @@ -47,7 +58,9 @@ class CandidateWindow {
const formatted<std::string> &auxUp,
const formatted<std::string> &auxDown) = 0;
virtual void set_candidates(const std::vector<Candidate> &candidates,
int highlighted) = 0;
int highlighted,
scroll_state_t scroll_state, bool scroll_end) = 0;
virtual void scroll_key_action(scroll_key_action_t action) = 0;
virtual void set_highlight_callback(std::function<void(size_t index)>) = 0;
virtual void set_theme(theme_t theme) = 0;
virtual void set_writing_mode(writing_mode_t mode) = 0;
Expand All @@ -59,7 +72,7 @@ class CandidateWindow {
init_callback = callback;
}

void set_select_callback(std::function<void(size_t index)> callback) {
void set_select_callback(std::function<void(int index)> callback) {
select_callback = callback;
}

Expand All @@ -72,6 +85,10 @@ class CandidateWindow {
page_callback = callback;
}

void set_scroll_callback(std::function<void(int, int)> callback) {
scroll_callback = callback;
}

void set_paging_buttons(bool pageable, bool has_prev, bool has_next) {
pageable_ = pageable;
has_prev_ = has_prev;
Expand All @@ -85,8 +102,9 @@ class CandidateWindow {

protected:
std::function<void()> init_callback = []() {};
std::function<void(size_t index)> select_callback = [](size_t) {};
std::function<void(int index)> select_callback = [](int) {};
std::function<void(bool next)> page_callback = [](bool) {};
std::function<void(int, int)> scroll_callback = [](int, int) {};
std::function<void(size_t index, int id)> action_callback = [](int, int) {};
std::string cursor_text_ = "";
std::string highlight_mark_text_ = "";
Expand Down
4 changes: 3 additions & 1 deletion include/webview_candidate_window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ class WebviewCandidateWindow : public CandidateWindow {
const formatted<std::string> &auxUp,
const formatted<std::string> &auxDown) override;
void set_candidates(const std::vector<Candidate> &candidates,
int highlighted) override;
int highlighted,
scroll_state_t scroll_state, bool scroll_end) override;
void scroll_key_action(scroll_key_action_t action) override;
void set_highlight_callback(std::function<void(size_t index)>) override {}
void set_theme(theme_t theme) override;
void set_writing_mode(writing_mode_t mode) override;
Expand Down
46 changes: 41 additions & 5 deletions page/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ import {
} from './theme'
import { setStyle } from './customize'
import { fcitxLog } from './log'
import {
getScrollState,
setScrollState,
setScrollEnd,
recalculateScroll,
scrollKeyAction,
fetchComplete
} from './scroll'

window.fcitxLog = fcitxLog
window._onload && window._onload()
Expand Down Expand Up @@ -83,8 +91,21 @@ const caretRight = common.replace('{}', '0 0 192 512').replace('{}', 'M0 384.662
const arrowBack = common.replace('{}', '0 0 24 24').replace('{}', 'M16.62 2.99a1.25 1.25 0 0 0-1.77 0L6.54 11.3a.996.996 0 0 0 0 1.41l8.31 8.31c.49.49 1.28.49 1.77 0s.49-1.28 0-1.77L9.38 12l7.25-7.25c.48-.48.48-1.28-.01-1.76z')
const arrowForward = common.replace('{}', '0 0 24 24').replace('{}', 'M7.38 21.01c.49.49 1.28.49 1.77 0l8.31-8.31a.996.996 0 0 0 0-1.41L9.15 2.98c-.49-.49-1.28-.49-1.77 0s-.49 1.28 0 1.77L14.62 12l-7.25 7.25c-.48.48-.48 1.28.01 1.76z')

function setCandidates (cands: Candidate[], highlighted: number, markText: string, pageable: boolean, hasPrev: boolean, hasNext: boolean) {
hoverables.innerHTML = ''
function setCandidates (cands: Candidate[], highlighted: number, markText: string, pageable: boolean, hasPrev: boolean, hasNext: boolean, scrollState: SCROLL_STATE, scrollEnd: boolean) {
// Keep existing candidates only when both old and new state are scrolling.
if (!(getScrollState() === 2 && scrollState === 2)) {
hoverables.innerHTML = ''
hoverables.scrollTop = 0 // Otherwise last scroll position will be kept.
} else {
fetchComplete()
}
if (scrollState === 2) {
hoverables.classList.add('horizontal-scroll')
setScrollEnd(scrollEnd)
} else {
hoverables.classList.remove('horizontal-scroll')
}
setScrollState(scrollState)
for (let i = 0; i < cands.length; ++i) {
const candidate = div('candidate', 'hoverable')
if (i === 0) {
Expand Down Expand Up @@ -112,9 +133,9 @@ function setCandidates (cands: Candidate[], highlighted: number, markText: strin
candidateInner.append(mark)
}

if (cands[i].label) {
if (cands[i].label || scrollState === 2) {
const label = div('label')
label.innerHTML = escapeWS(cands[i].label)
label.innerHTML = escapeWS(cands[i].label || '0')
candidateInner.append(label)
}

Expand All @@ -134,7 +155,14 @@ function setCandidates (cands: Candidate[], highlighted: number, markText: strin

setActions(cands.map(c => c.actions))

if (pageable) {
if (scrollState === 1) {
hoverables.append(divider(true))
const expand = div('expand', 'hoverable-inner')
expand.innerHTML = arrowForward
const paging = div('paging', 'scroll', 'hoverable')
paging.append(expand)
hoverables.append(paging)
} else if (scrollState === 0 && pageable) {
const isArrow = getPagingButtonsStyle() === 'Arrow'
hoverables.append(divider(true))

Expand Down Expand Up @@ -163,6 +191,10 @@ function setCandidates (cands: Candidate[], highlighted: number, markText: strin
paging.appendChild(prev)
paging.appendChild(next)
hoverables.appendChild(paging)
} else if (scrollState === 2) {
window.requestAnimationFrame(() => {
recalculateScroll()
})
}

for (const hoverable of hoverables.querySelectorAll('.hoverable')) {
Expand Down Expand Up @@ -207,6 +239,9 @@ hoverables.addEventListener('mouseleave', () => {
})

hoverables.addEventListener('wheel', e => {
if (getScrollState() === 2) {
return
}
window._page((<WheelEvent>e).deltaY > 0)
})

Expand All @@ -222,3 +257,4 @@ window.setAccentColor = setAccentColor
window.setStyle = setStyle
window.setWritingMode = setWritingMode
window.copyHTML = copyHTML
window.scrollKeyAction = scrollKeyAction
81 changes: 62 additions & 19 deletions page/generic.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ body {
}
}

.candidate-inner {
display: flex;
gap: 6px;
align-items: center; /* English words have lower height */
line-height: 1em; /* align label and candidates */
position: relative; /* for absolute position of mark */
}

.label {
/* Label is usually a single number. Will look ugly when all parts have vertical writing mode. */
writing-mode: horizontal-tb;
}

.hoverables {
display: flex;

Expand All @@ -50,30 +63,49 @@ body {
&.horizontal {
flex-direction: row;

.candidate {
/* When horizontal and there is multi-line candidate,
make sure other candidates are vertical centered.
Don't enable it for vertical. It will shrink highlight. */
display: flex;
}

.divider {
flex-direction: column;
}
}
}

.horizontal .candidate {
/* When horizontal and there is multi-line candidate,
make sure other candidates are vertical centered.
Don't enable it for vertical. It will shrink highlight. */
display: flex;
}
&.horizontal-scroll {
block-size: 180px;
inline-size: 400px;
flex-wrap: wrap;
overflow-y: auto;
overscroll-behavior: none;

.candidate-inner {
display: flex;
gap: 6px;
align-items: center; /* English words have lower height */
line-height: 1em; /* align label and candidates */
position: relative; /* for absolute position of mark */
.candidate {
min-inline-size: 60px;
}

.candidate-inner {
width: 100%;
}

.label {
opacity: 0;
}

.highlighted-row .label {
opacity: 1;
}

.divider {
flex-grow: 1;
}
}
}

.label {
/* Label is usually a single number. Will look ugly when all parts have vertical writing mode. */
writing-mode: horizontal-tb;
:is(.vertical-rl, .vertical-lr) .paging svg {
transform: rotate(90deg);
}

.paging {
Expand All @@ -88,10 +120,21 @@ body {
block-size: 16px;
inline-size: 16px;
}
}

:is(.vertical-rl, .vertical-lr) .paging svg {
transform: rotate(90deg);
&.scroll {
.expand {
block-size: 18px;
inline-size: 18px;
display: flex;
justify-content: center;
align-items: center;

svg {
transform: rotate(90deg);
width: 16px;
}
}
}
}

/* When horizontal, paging is shorter than candidates, so need to centralize them. */
Expand Down
9 changes: 8 additions & 1 deletion page/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,24 @@ declare global {
actions: CandidateAction[]
}

type SCROLL_STATE = 0 | 1 | 2
type SCROLL_SELECT = 1 | 2 | 3 | 4 | 5 | 6
type SCROLL_MOVE_HIGHLIGHT = 10 | 11 | 12 | 13 | 14 | 15
type SCROLL_KEY_ACTION = SCROLL_SELECT | SCROLL_MOVE_HIGHLIGHT

interface Window {
// C++ APIs that api.ts calls
_onload?: () => void
_log: (s: string) => void
_copyHTML: (html: string) => void
_select: (index: number) => void
_page: (next: boolean) => void
_scroll: (start: number, length: number) => void
_action: (index: number, id: number) => void
_resize: (dx: number, dy: number, shadowTop: number, shadowRight: number, shadowBottom: number, shadowLeft: number, fullWidth: number, fullHeight: number, enlargedWidth: number, enlargedHeight: number, dragging: boolean) => void

// JavaScript APIs that webview_candidate_window.mm calls
setCandidates: (cands: Candidate[], highlighted: number, markText: string, pageable: boolean, hasPrev: boolean, hasNext: boolean) => void
setCandidates: (cands: Candidate[], highlighted: number, markText: string, pageable: boolean, hasPrev: boolean, hasNext: boolean, scrollState: SCROLL_STATE, scrollEnd: boolean) => void
setLayout: (layout: 0 | 1) => void
updateInputPanel: (preeditHTML: string, auxUpHTML: string, auxDownHTML: string) => void
resize: (dx: number, dy: number, dragging: boolean, hasContextmenu: boolean) => void
Expand All @@ -31,6 +37,7 @@ declare global {
setStyle: (style: string) => void
setWritingMode: (mode: 0 | 1 | 2) => void
copyHTML: () => void
scrollKeyAction: (action: SCROLL_KEY_ACTION) => void

// Utility functions globally available
fcitxLog: (...args: unknown[]) => void
Expand Down
17 changes: 16 additions & 1 deletion page/macos.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ $dark-graphite: rgb(105 105 105);
.panel {
transform: translate(25px, 25px); /* leave top and left for shadow */

&:has(.horizontal .paging.arrow) {
&:has(.horizontal .paging:is(.arrow, .scroll)) {
border-start-end-radius: 15px;
border-end-end-radius: 15px;
}
Expand All @@ -62,6 +62,12 @@ $dark-graphite: rgb(105 105 105);
}
}

.paging.scroll {
inline-size: 28px;
justify-content: center;
align-items: center;
}

.contextmenu {
backdrop-filter: blur(16px);
}
Expand Down Expand Up @@ -220,6 +226,10 @@ $dark-graphite: rgb(105 105 105);
background-color: $vertical-border-color-light;
}
}

.hoverables.horizontal-scroll .divider .divider-middle {
background-color: $panel-color-light;
}
}

.macos.dark {
Expand Down Expand Up @@ -312,10 +322,15 @@ $dark-graphite: rgb(105 105 105);
background-color: $panel-color-dark;
}

/* stylelint-disable-next-line no-descending-specificity */
.divider-middle {
background-color: $vertical-border-color-dark;
}
}

.hoverables.horizontal-scroll .divider .divider-middle {
background-color: $panel-color-dark;
}
}

.macos.light, .macos.dark {
Expand Down
Loading

0 comments on commit 66d9227

Please sign in to comment.