Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ serde_json = { version = "1.0.60", default-features = false, features = [
sha2 = { version = "0.11.0", default-features = false }
slab = { version = "0.4.9", default-features = false }
smallstr = { version = "0.3.0", default-features = false }
smallvec = { version = "1.15.1", default-features = false }
snafu = { version = "0.9.1", default-features = false }

# std
Expand Down
41 changes: 41 additions & 0 deletions capi/bind_gen/src/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,7 @@ export type SettingsDescriptionValueJson =
{ ColumnStartWith: ColumnStartWith } |
{ ColumnUpdateWith: ColumnUpdateWith } |
{ ColumnUpdateTrigger: ColumnUpdateTrigger } |
{ SubsplitDisplayMode: SubsplitDisplayMode } |
{ Hotkey: string } |
{ LayoutDirection: LayoutDirection } |
{ Font: Font | null } |
Expand Down Expand Up @@ -832,6 +833,12 @@ export type ColumnUpdateTrigger =
"Contextual" |
"OnEndingSegment";

/** Describes how native subsplits are displayed. */
export type SubsplitDisplayMode =
"Flat" |
"AllGroupsExpanded" |
"CurrentGroupExpanded";

/**
* The Accuracy describes how many digits to show for the fractional part of a
* time.
Expand Down Expand Up @@ -888,6 +895,8 @@ export interface RunEditorStateJson {
timing_method: TimingMethodJson,
/** The state of all the segments. */
segments: RunEditorRowJson[],
/** The segment groups of the run. */
segment_groups: RunEditorSegmentGroupJson[],
/** The names of all the custom comparisons that exist for this Run. */
comparison_names: string[],
/** Describes which actions are currently available. */
Expand Down Expand Up @@ -986,6 +995,16 @@ export interface RunEditorButtonsJson {
* moved.
*/
can_move_down: boolean,
/**
* Describes whether the currently selected segments can be turned into a
* segment group.
*/
can_create_segment_group: boolean,
/**
* Describes whether the currently selected segments are exactly one or more
* segment groups that can be removed.
*/
can_remove_segment_group: boolean,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about removing multiple groups?

}

/** Describes the current state of a segment. */
Expand All @@ -1012,6 +1031,28 @@ export interface RunEditorRowJson {
comparison_times: string[],
/** Describes the segment's selection state. */
selected: "NotSelected" | "Selected" | "Active",
/** The index of the group this segment belongs to, if any. */
segment_group_index: number | null,
}

/** Describes a segment group. */
export interface RunEditorSegmentGroupJson {
/** The first segment in the group. */
start: number,
/** The segment after the last segment in the group. */
end: number,
/**
* The explicit group name. If this is `null`, the major split name is the
* display name of the group.
*/
name: string | null,
/**
* The group display icon. This falls back to the major split icon if no
* explicit group icon is set.
*/
icon: ImageId,
/** Whether the group icon is explicitly set instead of inherited. */
has_explicit_icon: boolean,
Comment on lines +1053 to +1055

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels redundant, we don't do this for the segment icons either.

}

/**
Expand Down
18 changes: 17 additions & 1 deletion capi/bind_gen/src/wasm_bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -752,10 +752,16 @@ export class {class_name_ref_mut} extends {class_name_ref} {{"#,
this.setGameIcon(slice.ptr, slice.len);
dealloc(slice);
}
activeSetIconFromArray(data: Uint8Array) {
activeSetIconFromArray(data: Uint8Array): void {
const slice = allocUint8Array(data);
this.activeSetIcon(slice.ptr, slice.len);
dealloc(slice);
}
activeSetSegmentGroupIconFromArray(data: Uint8Array): boolean {
const slice = allocUint8Array(data);
const result = this.activeSetSegmentGroupIcon(slice.ptr, slice.len);
dealloc(slice);
return result;
}"#
)?;
} else {
Expand All @@ -778,6 +784,16 @@ export class {class_name_ref_mut} extends {class_name_ref} {{"#,
const slice = allocUint8Array(data);
this.activeSetIcon(slice.ptr, slice.len);
dealloc(slice);
}
/**
* @param {Uint8Array} data
* @returns {boolean}
*/
activeSetSegmentGroupIconFromArray(data) {
const slice = allocUint8Array(data);
const result = this.activeSetSegmentGroupIcon(slice.ptr, slice.len);
dealloc(slice);
return result;
}"#
)?;
}
Expand Down
58 changes: 58 additions & 0 deletions capi/src/run_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,64 @@ pub extern "C" fn RunEditor_move_segments_down(this: &mut RunEditor) {
this.move_segments_down();
}

/// Creates a native segment group from the currently selected contiguous
/// segment rows. Returns <FALSE> if the selection is not contiguous or empty.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn RunEditor_create_segment_group_from_selection(
this: &mut RunEditor,
name: *const c_char,
) -> bool {
// SAFETY: The caller guarantees that `name` is valid.
let name = unsafe { str(name) };
if name.is_empty() {
this.create_segment_group_from_selection::<String>(None)
} else {
this.create_segment_group_from_selection(Some(name))
}
}

/// Removes the selected native segment groups, while keeping all segments.
#[unsafe(no_mangle)]
pub extern "C" fn RunEditor_remove_active_segment_group(this: &mut RunEditor) -> bool {
this.remove_active_segment_group()
}

/// Renames the native segment group containing the active segment.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn RunEditor_rename_active_segment_group(
this: &mut RunEditor,
name: *const c_char,
) -> bool {
// SAFETY: The caller guarantees that `name` is valid.
let name = unsafe { str(name) };
if name.is_empty() {
this.rename_active_segment_group::<String>(None)
} else {
this.rename_active_segment_group(Some(name))
}
}

/// Sets the icon of the native segment group containing the active segment.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn RunEditor_active_set_segment_group_icon(
this: &mut RunEditor,
data: *const u8,
length: usize,
) -> bool {
// SAFETY: The caller guarantees that `data` is valid for `length`.
this.set_active_segment_group_icon(Image::new(
unsafe { slice(data, length).into() },
Image::ICON,
))
}

/// Removes the explicit icon of the native segment group containing the active
/// segment.
#[unsafe(no_mangle)]
pub extern "C" fn RunEditor_active_remove_segment_group_icon(this: &mut RunEditor) -> bool {
this.remove_active_segment_group_icon()
}

/// Sets the icon of the active segment.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn RunEditor_active_set_icon(
Expand Down
19 changes: 18 additions & 1 deletion capi/src/setting_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{Json, output_vec, str};
use livesplit_core::{
TimingMethod,
component::{
splits::{ColumnStartWith, ColumnUpdateTrigger, ColumnUpdateWith},
splits::{ColumnStartWith, ColumnUpdateTrigger, ColumnUpdateWith, SubsplitDisplayMode},
timer::DeltaGradient,
},
layout::LayoutDirection,
Expand Down Expand Up @@ -330,6 +330,23 @@ pub unsafe extern "C" fn SettingValue_from_column_update_trigger(
Some(Box::new(value.into()))
}

/// Creates a new setting value from the subsplit display mode. If it doesn't
/// match a known subsplit display mode, <NULL> is returned.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn SettingValue_from_subsplit_display_mode(
value: *const c_char,
) -> NullableOwnedSettingValue {
// SAFETY: The caller guarantees that `value` is valid.
let value = unsafe { str(value) };
let value = match value {
"Flat" => SubsplitDisplayMode::Flat,
"AllGroupsExpanded" => SubsplitDisplayMode::AllGroupsExpanded,
"CurrentGroupExpanded" => SubsplitDisplayMode::CurrentGroupExpanded,
_ => return None,
};
Some(Box::new(value.into()))
}

/// Creates a new setting value from the layout direction. If it doesn't
/// match a known layout direction, <NULL> is returned.
#[unsafe(no_mangle)]
Expand Down
10 changes: 10 additions & 0 deletions capi/src/splits_component_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ pub extern "C" fn SplitsComponentState_is_current_split(
this.splits[index].is_current_split
}

/// Describes if the segment with the specified index is the segment selected
/// by manually scrolling through subsplit groups.
#[unsafe(no_mangle)]
pub extern "C" fn SplitsComponentState_is_scrolled_to_split(
this: &SplitsComponentState,
index: usize,
) -> bool {
this.splits[index].is_scrolled_to_split
}

/// Describes if the columns have labels that are meant to be shown. If this is
/// `false`, no labels are supposed to be visualized.
#[unsafe(no_mangle)]
Expand Down
12 changes: 8 additions & 4 deletions crates/livesplit-hotkey/src/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,25 +456,29 @@ unsafe extern "C" fn callback(
let modifier_flags = unsafe { CGEventGetFlags(event) };
let mut modifiers = Modifiers::empty();

if modifier_flags.intersects(EventFlags::SHIFT | EventFlags::LEFT_SHIFT | EventFlags::RIGHT_SHIFT)
if modifier_flags
.intersects(EventFlags::SHIFT | EventFlags::LEFT_SHIFT | EventFlags::RIGHT_SHIFT)
&& !matches!(key_code, KeyCode::ShiftLeft | KeyCode::ShiftRight)
{
modifiers.insert(Modifiers::SHIFT);
}

if modifier_flags.intersects(EventFlags::CONTROL | EventFlags::LEFT_CONTROL | EventFlags::RIGHT_CONTROL)
if modifier_flags
.intersects(EventFlags::CONTROL | EventFlags::LEFT_CONTROL | EventFlags::RIGHT_CONTROL)
&& !matches!(key_code, KeyCode::ControlLeft | KeyCode::ControlRight)
{
modifiers.insert(Modifiers::CONTROL);
}

if modifier_flags.intersects(EventFlags::OPTION | EventFlags::LEFT_OPTION | EventFlags::RIGHT_OPTION)
if modifier_flags
.intersects(EventFlags::OPTION | EventFlags::LEFT_OPTION | EventFlags::RIGHT_OPTION)
&& !matches!(key_code, KeyCode::AltLeft | KeyCode::AltRight)
{
modifiers.insert(Modifiers::ALT);
}

if modifier_flags.intersects(EventFlags::COMMAND | EventFlags::LEFT_COMMAND | EventFlags::RIGHT_COMMAND)
if modifier_flags
.intersects(EventFlags::COMMAND | EventFlags::LEFT_COMMAND | EventFlags::RIGHT_COMMAND)
&& !matches!(key_code, KeyCode::MetaLeft | KeyCode::MetaRight)
{
modifiers.insert(Modifiers::META);
Expand Down
Loading
Loading