Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add paging indicators #953

Merged
merged 5 commits into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion .github/workflows/commit-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
run: brew install peripheryapp/periphery/periphery

- name: Check Unused Code
run: periphery scan --skip-build --index-store-path build/Index.noindex/DataStore
run: periphery scan --relative-results --skip-build --index-store-path build/Index.noindex/DataStore

- name: Upload Squirrel artifact
uses: actions/upload-artifact@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pull-request-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
run: brew install peripheryapp/periphery/periphery

- name: Check Unused Code
run: periphery scan --skip-build --index-store-path build/Index.noindex/DataStore
run: periphery scan --relative-results --skip-build --index-store-path build/Index.noindex/DataStore

- name: Upload Squirrel artifact
uses: actions/upload-artifact@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
run: brew install peripheryapp/periphery/periphery

- name: Check Unused Code
run: periphery scan --skip-build --index-store-path build/Index.noindex/DataStore
run: periphery scan --relative-results --skip-build --index-store-path build/Index.noindex/DataStore

- name: Build changelog
id: release_log
Expand Down
2 changes: 1 addition & 1 deletion action-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
set -e

rime_version=latest
rime_git_hash=6b1b41f
rime_git_hash=2f89098
sparkle_version=2.6.2

rime_archive="rime-${rime_git_hash}-macOS-universal.tar.bz2"
Expand Down
2 changes: 2 additions & 0 deletions data/squirrel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ style:
mutual_exclusive: false
# Whether to use a translucent background. Only visible when background color is transparent
translucency: false
# Enable to show small arrows that indicates if paging up/down is possible
show_paging: false

corner_radius: 7
hilited_corner_radius: 0
Expand Down
23 changes: 23 additions & 0 deletions sources/BridgingFunctions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,26 @@ func ?=<T>(left: inout T?, right: T?) {
extension NSRange {
static let empty = NSRange(location: NSNotFound, length: 0)
}

extension NSPoint {
static func += (lhs: inout Self, rhs: Self) {
lhs.x += rhs.x
lhs.y += rhs.y
}
static func - (lhs: Self, rhs: Self) -> Self {
Self.init(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
}
static func -= (lhs: inout Self, rhs: Self) {
lhs.x -= rhs.x
lhs.y -= rhs.y
}
static func * (lhs: Self, rhs: CGFloat) -> Self {
Self.init(x: lhs.x * rhs, y: lhs.y * rhs)
}
static func / (lhs: Self, rhs: CGFloat) -> Self {
Self.init(x: lhs.x / rhs, y: lhs.y / rhs)
}
var length: CGFloat {
sqrt(pow(self.x, 2) + pow(self.y, 2))
}
}
10 changes: 7 additions & 3 deletions sources/SquirrelInputController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -501,10 +501,13 @@ private extension SquirrelInputController {
}
}
// swiftlint:enable identifier_name
let page = Int(ctx.menu.page_no)
let lastPage = ctx.menu.is_last_page

let selRange = NSRange(location: start.utf16Offset(in: preedit), length: preedit.utf16.distance(from: start, to: end))
showPanel(preedit: inlinePreedit ? "" : preedit, selRange: selRange, caretPos: caretPos.utf16Offset(in: preedit),
candidates: candidates, comments: comments, labels: labels, highlighted: Int(ctx.menu.highlighted_candidate_index))
candidates: candidates, comments: comments, labels: labels, highlighted: Int(ctx.menu.highlighted_candidate_index),
page: page, lastPage: lastPage)
_ = rimeAPI.free_context(&ctx)
} else {
hidePalettes()
Expand Down Expand Up @@ -544,15 +547,16 @@ private extension SquirrelInputController {
}

// swiftlint:disable:next function_parameter_count
func showPanel(preedit: String, selRange: NSRange, caretPos: Int, candidates: [String], comments: [String], labels: [String], highlighted: Int) {
func showPanel(preedit: String, selRange: NSRange, caretPos: Int, candidates: [String], comments: [String], labels: [String], highlighted: Int, page: Int, lastPage: Bool) {
// print("[DEBUG] showPanelWithPreedit:...:")
guard let client = client else { return }
var inputPos = NSRect()
client.attributes(forCharacterIndex: 0, lineHeightRectangle: &inputPos)
if let panel = NSApp.squirrelAppDelegate.panel {
panel.position = inputPos
panel.inputController = self
panel.update(preedit: preedit, selRange: selRange, caretPos: caretPos, candidates: candidates, comments: comments, labels: labels, highlighted: highlighted, update: true)
panel.update(preedit: preedit, selRange: selRange, caretPos: caretPos, candidates: candidates, comments: comments, labels: labels,
highlighted: highlighted, page: page, lastPage: lastPage, update: true)
}
}
}
50 changes: 36 additions & 14 deletions sources/SquirrelPanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ final class SquirrelPanel: NSPanel {
private var cursorIndex: Int = 0
private var scrollDirection: CGVector = .zero
private var scrollTime: Date = .distantPast
private var page: Int = 0
private var lastPage: Bool = true
private var pagingUp: Bool?

init(position: NSRect) {
self.position = position
Expand Down Expand Up @@ -68,33 +71,45 @@ final class SquirrelPanel: NSPanel {
override func sendEvent(_ event: NSEvent) {
switch event.type {
case .leftMouseDown:
let (index, _) = view.click(at: mousePosition())
if let index = index, index >= 0 && index < candidates.count {
let (index, _, pagingUp) = view.click(at: mousePosition())
if let pagingUp {
self.pagingUp = pagingUp
} else {
self.pagingUp = nil
}
if let index, index >= 0 && index < candidates.count {
self.index = index
}
case .leftMouseUp:
let (index, preeditIndex) = view.click(at: mousePosition())
if let preeditIndex = preeditIndex, preeditIndex >= 0 && preeditIndex < preedit.utf16.count {
let (index, preeditIndex, pagingUp) = view.click(at: mousePosition())

if let pagingUp, pagingUp == self.pagingUp {
_ = inputController?.page(up: pagingUp)
} else {
self.pagingUp = nil
}
if let preeditIndex, preeditIndex >= 0 && preeditIndex < preedit.utf16.count {
if preeditIndex < caretPos {
_ = inputController?.moveCaret(forward: true)
} else if preeditIndex > caretPos {
_ = inputController?.moveCaret(forward: false)
}
}
if let index = index, index == self.index && index >= 0 && index < candidates.count {
if let index, index == self.index && index >= 0 && index < candidates.count {
_ = inputController?.selectCandidate(index)
}
case .mouseEntered:
acceptsMouseMovedEvents = true
case .mouseExited:
acceptsMouseMovedEvents = false
if cursorIndex != index {
update(preedit: preedit, selRange: selRange, caretPos: caretPos, candidates: candidates, comments: comments, labels: labels, highlighted: index, update: false)
update(preedit: preedit, selRange: selRange, caretPos: caretPos, candidates: candidates, comments: comments, labels: labels, highlighted: index, page: page, lastPage: lastPage, update: false)
}
pagingUp = nil
case .mouseMoved:
let (index, _) = view.click(at: mousePosition())
let (index, _, _) = view.click(at: mousePosition())
if let index = index, cursorIndex != index && index >= 0 && index < candidates.count {
update(preedit: preedit, selRange: selRange, caretPos: caretPos, candidates: candidates, comments: comments, labels: labels, highlighted: index, update: false)
update(preedit: preedit, selRange: selRange, caretPos: caretPos, candidates: candidates, comments: comments, labels: labels, highlighted: index, page: page, lastPage: lastPage, update: false)
}
case .scrollWheel:
if event.phase == .began {
Expand Down Expand Up @@ -141,7 +156,7 @@ final class SquirrelPanel: NSPanel {

// Main function to add attributes to text output from librime
// swiftlint:disable:next cyclomatic_complexity function_parameter_count
func update(preedit: String, selRange: NSRange, caretPos: Int, candidates: [String], comments: [String], labels: [String], highlighted index: Int, update: Bool) {
func update(preedit: String, selRange: NSRange, caretPos: Int, candidates: [String], comments: [String], labels: [String], highlighted index: Int, page: Int, lastPage: Bool, update: Bool) {
if update {
self.preedit = preedit
self.selRange = selRange
Expand All @@ -150,6 +165,8 @@ final class SquirrelPanel: NSPanel {
self.comments = comments
self.labels = labels
self.index = index
self.page = page
self.lastPage = lastPage
}
cursorIndex = index

Expand Down Expand Up @@ -266,7 +283,7 @@ final class SquirrelPanel: NSPanel {
// text done!
view.textView.textContentStorage?.attributedString = text
view.textView.setLayoutOrientation(vertical ? .vertical : .horizontal)
view.drawView(candidateRanges: candidateRanges, hilightedIndex: index, preeditRange: preeditRange, highlightedPreeditRange: highlightedPreeditRange)
view.drawView(candidateRanges: candidateRanges, hilightedIndex: index, preeditRange: preeditRange, highlightedPreeditRange: highlightedPreeditRange, canPageUp: page > 0, canPageDown: !lastPage)
show()
}

Expand Down Expand Up @@ -359,11 +376,12 @@ private extension SquirrelPanel {

if vertical {
panelRect.size = NSSize(width: min(0.95 * screenRect.width, contentRect.height + theme.edgeInset.height * 2),
height: min(0.95 * screenRect.height, contentRect.width + theme.edgeInset.width * 2))
height: min(0.95 * screenRect.height, contentRect.width + theme.edgeInset.width * 2) + theme.pagingOffset)

// To avoid jumping up and down while typing, use the lower screen when
// typing on upper, and vice versa
if position.midY / screenRect.height >= 0.5 {
panelRect.origin.y = position.minY - SquirrelTheme.offsetHeight - panelRect.height
panelRect.origin.y = position.minY - SquirrelTheme.offsetHeight - panelRect.height + theme.pagingOffset
} else {
panelRect.origin.y = position.maxY + SquirrelTheme.offsetHeight
}
Expand All @@ -376,7 +394,8 @@ private extension SquirrelPanel {
} else {
panelRect.size = NSSize(width: min(0.95 * screenRect.width, contentRect.width + theme.edgeInset.width * 2),
height: min(0.95 * screenRect.height, contentRect.height + theme.edgeInset.height * 2))
panelRect.origin = NSPoint(x: position.minX, y: position.minY - SquirrelTheme.offsetHeight - panelRect.height)
panelRect.size.width += theme.pagingOffset
panelRect.origin = NSPoint(x: position.minX - theme.pagingOffset, y: position.minY - SquirrelTheme.offsetHeight - panelRect.height)
}
if panelRect.maxX > screenRect.maxX {
panelRect.origin.x = screenRect.maxX - panelRect.width
Expand Down Expand Up @@ -412,10 +431,13 @@ private extension SquirrelPanel {

view.frame = contentView!.bounds
view.textView.frame = contentView!.bounds
view.textView.frame.size.width -= theme.pagingOffset
view.textView.frame.origin.x += theme.pagingOffset
view.textView.textContainerInset = theme.edgeInset

if theme.translucency {
back.frame = contentView!.bounds
back.frame.size.width += theme.pagingOffset
back.appearance = NSApp.effectiveAppearance
back.isHidden = false
} else {
Expand All @@ -434,7 +456,7 @@ private extension SquirrelPanel {
view.textContentStorage.attributedString = text
view.textView.setLayoutOrientation(vertical ? .vertical : .horizontal)
view.drawView(candidateRanges: [NSRange(location: 0, length: text.length)], hilightedIndex: -1,
preeditRange: .empty, highlightedPreeditRange: .empty)
preeditRange: .empty, highlightedPreeditRange: .empty, canPageUp: false, canPageDown: false)
show()

statusTimer?.invalidate()
Expand Down
6 changes: 6 additions & 0 deletions sources/SquirrelTheme.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ final class SquirrelTheme {
private(set) var vertical = false
private(set) var inlinePreedit = false
private(set) var inlineCandidate = false
private(set) var showPaging = false

private var fonts = [NSFont]()
private var labelFonts = [NSFont]()
Expand Down Expand Up @@ -182,6 +183,9 @@ final class SquirrelTheme {
_candidateFormat = newTemplate
}
}
var pagingOffset: CGFloat {
(labelFontSize ?? fontSize ?? Self.defaultFontSize) * 1.5
}

func load(config: SquirrelConfig, dark: Bool) {
linear ?= config.getString("style/candidate_list_layout").map { $0 == "linear" }
Expand All @@ -191,6 +195,7 @@ final class SquirrelTheme {
translucency ?= config.getBool("style/translucency")
mutualExclusive ?= config.getBool("style/mutual_exclusive")
memorizeSize ?= config.getBool("style/memorize_size")
showPaging ?= config.getBool("style/show_paging")

statusMessageType ?= .init(rawValue: config.getString("style/status_message_type") ?? "")
candidateFormat ?= config.getString("style/candidate_format")
Expand Down Expand Up @@ -244,6 +249,7 @@ final class SquirrelTheme {
inlineCandidate ?= config.getBool("\(prefix)/inline_candidate")
translucency ?= config.getBool("\(prefix)/translucency")
mutualExclusive ?= config.getBool("\(prefix)/mutual_exclusive")
showPaging ?= config.getBool("\(prefix)/show_paging")
candidateFormat ?= config.getString("\(prefix)/candidate_format")
fontName ?= config.getString("\(prefix)/font_face")
fontSize ?= config.getDouble("\(prefix)/font_point")
Expand Down
Loading
Loading