mirror of
https://github.com/ApfelTeeSaft/LiveSplitOne.git
synced 2026-09-02 19:20:05 +00:00
Implement Component Settings
This commit is contained in:
+48
-3
@@ -78,6 +78,13 @@ button.toggle-right {
|
||||
text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.5);
|
||||
margin: 10px;
|
||||
margin-bottom: 5px;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.previous-segment,
|
||||
@@ -606,7 +613,7 @@ input.name {
|
||||
|
||||
}
|
||||
|
||||
form > div > input {
|
||||
input {
|
||||
font-size: 15px;
|
||||
border: none;
|
||||
border-bottom: 1px solid hsl(0, 0%, 25%);
|
||||
@@ -616,11 +623,16 @@ form > div > input {
|
||||
font-family: 'fira', sans-serif;
|
||||
}
|
||||
|
||||
input.number {
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
form > div > input:not(.name) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
.timing-selection > button {
|
||||
font-size: 15px;
|
||||
height: 30px;
|
||||
@@ -656,7 +668,7 @@ svg {
|
||||
|
||||
.layout-editor {
|
||||
margin: 20px;
|
||||
width: 300px;
|
||||
width: 445px;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
@@ -700,6 +712,10 @@ svg {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.layout-editor-component {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.react-contextmenu-item--divider {
|
||||
margin-bottom: 3px;
|
||||
padding: 2px 0;
|
||||
@@ -710,3 +726,32 @@ svg {
|
||||
.react-contextmenu-item--selected {
|
||||
background: rgba(0, 67, 255, 0.26);
|
||||
}
|
||||
|
||||
.component-settings {
|
||||
margin-left: 20px;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.component-settings > tbody > tr {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.component-settings > tbody > tr > td:nth-child(1) {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.component-settings > tbody > tr > td:nth-child(2) > input,
|
||||
.component-settings > tbody > tr > td:nth-child(2) > span,
|
||||
.component-settings > tbody > tr > td:nth-child(2) > select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
select {
|
||||
background: hsla(0, 0%, 9%, 1);
|
||||
font-size: 15px;
|
||||
border: none;
|
||||
border-bottom: 1px solid hsl(0, 0%, 25%);
|
||||
color: white;
|
||||
text-overflow: ellipsis;
|
||||
font-family: 'fira', sans-serif;
|
||||
}
|
||||
|
||||
+1
-1
Submodule livesplit-core updated: 1566f241a6...f4b91547a1
+186
-51
@@ -91,60 +91,195 @@ export class LayoutEditor extends React.Component<Props, State> {
|
||||
}
|
||||
};
|
||||
|
||||
let settingsRows: any[] = [];
|
||||
|
||||
this.state.editor.settings_description.fields.forEach((field, valueIndex) => {
|
||||
var component;
|
||||
let value: any = field.value;
|
||||
switch (Object.keys(value)[0]) {
|
||||
case "Bool": {
|
||||
component =
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={value.Bool}
|
||||
onChange={(e) => {
|
||||
this.props.editor.setComponentSettingsBool(valueIndex, e.target.checked);
|
||||
this.update();
|
||||
}}
|
||||
/>;
|
||||
break;
|
||||
}
|
||||
case "UInt": {
|
||||
component =
|
||||
<input
|
||||
type="number"
|
||||
className="number"
|
||||
value={value.UInt}
|
||||
min="0"
|
||||
onChange={(e) => {
|
||||
this.props.editor.setComponentSettingsUint(valueIndex, e.target.valueAsNumber);
|
||||
this.update();
|
||||
}}
|
||||
/>;
|
||||
break;
|
||||
}
|
||||
case "Int": {
|
||||
component =
|
||||
<input
|
||||
type="number"
|
||||
className="number"
|
||||
value={value.Int}
|
||||
onChange={(e) => {
|
||||
this.props.editor.setComponentSettingsInt(valueIndex, e.target.valueAsNumber);
|
||||
this.update();
|
||||
}}
|
||||
/>;
|
||||
break;
|
||||
}
|
||||
case "String": {
|
||||
component =
|
||||
<input
|
||||
value={value.String}
|
||||
onChange={(e) => {
|
||||
this.props.editor.setComponentSettingsString(valueIndex, e.target.value);
|
||||
this.update();
|
||||
}}
|
||||
/>;
|
||||
break;
|
||||
}
|
||||
case "OptionalString": {
|
||||
let children = [
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={value.OptionalString != null}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
this.props.editor.setComponentSettingsOptionalString(valueIndex, "");
|
||||
} else {
|
||||
this.props.editor.setComponentSettingsOptionalStringToEmpty(valueIndex);
|
||||
}
|
||||
this.update();
|
||||
}}
|
||||
/>
|
||||
];
|
||||
|
||||
if (value.OptionalString != null) {
|
||||
children.push(
|
||||
<input
|
||||
value={value.OptionalString}
|
||||
disabled={value.OptionalString == null}
|
||||
onChange={(e) => {
|
||||
this.props.editor.setComponentSettingsOptionalString(valueIndex, e.target.value);
|
||||
this.update();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
component =
|
||||
<span>
|
||||
{children}
|
||||
</span>;
|
||||
break;
|
||||
}
|
||||
case "Float": {
|
||||
component =
|
||||
<input
|
||||
type="number"
|
||||
value={value.Float}
|
||||
className="number"
|
||||
onChange={(e) => {
|
||||
this.props.editor.setComponentSettingsFloat(valueIndex, e.target.valueAsNumber);
|
||||
this.update();
|
||||
}}
|
||||
/>;
|
||||
break;
|
||||
}
|
||||
case "Accuracy": {
|
||||
component =
|
||||
<select
|
||||
value={value.Accuracy}
|
||||
onChange={(e) => {
|
||||
this.props.editor.setComponentSettingsAccuracy(valueIndex, e.target.value);
|
||||
this.update();
|
||||
}}
|
||||
>
|
||||
<option value="Seconds">Seconds</option>
|
||||
<option value="Tenths">Tenths</option>
|
||||
<option value="Hundredths">Hundredths</option>
|
||||
</select>;
|
||||
break;
|
||||
}
|
||||
}
|
||||
settingsRows.push(
|
||||
<tr>
|
||||
<td>{field.text}</td>
|
||||
<td>{component}</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="layout-editor">
|
||||
<div className="btn-group">
|
||||
<ContextMenuTrigger id="add-button-context-menu" ref={c => contextTrigger = c}>
|
||||
<button onClick={toggleMenu}><i className="fa fa-plus" aria-hidden="true"></i></button>
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenu id="add-button-context-menu">
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.CurrentComparisonComponent)}>
|
||||
Current Comparison
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.CurrentPaceComponent)}>
|
||||
Current Pace
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.DeltaComponent)}>
|
||||
Delta
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.DetailedTimerComponent)}>
|
||||
Detailed Timer
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.GraphComponent)}>
|
||||
Graph
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.PossibleTimeSaveComponent)}>
|
||||
Possible Time Save
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.PreviousSegmentComponent)}>
|
||||
Previous Segment
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.SplitsComponent)}>
|
||||
Splits
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.SumOfBestComponent)}>
|
||||
Sum of Best
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.TextComponent)}>
|
||||
Text
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.TimerComponent)}>
|
||||
Timer
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.TitleComponent)}>
|
||||
Title
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.TotalPlaytimeComponent)}>
|
||||
Total Playtime
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
<button onClick={(e) => this.removeComponent()}><i className="fa fa-minus" aria-hidden="true"></i></button>
|
||||
<button onClick={(e) => this.moveComponentUp()}><i className="fa fa-arrow-up" aria-hidden="true"></i></button>
|
||||
<button onClick={(e) => this.moveComponentDown()}><i className="fa fa-arrow-down" aria-hidden="true"></i></button>
|
||||
<div>
|
||||
<div className="layout-editor">
|
||||
<div className="btn-group">
|
||||
<ContextMenuTrigger id="add-button-context-menu" ref={c => contextTrigger = c}>
|
||||
<button onClick={toggleMenu}><i className="fa fa-plus" aria-hidden="true"></i></button>
|
||||
</ContextMenuTrigger>
|
||||
<ContextMenu id="add-button-context-menu">
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.CurrentComparisonComponent)}>
|
||||
Current Comparison
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.CurrentPaceComponent)}>
|
||||
Current Pace
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.DeltaComponent)}>
|
||||
Delta
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.DetailedTimerComponent)}>
|
||||
Detailed Timer
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.GraphComponent)}>
|
||||
Graph
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.PossibleTimeSaveComponent)}>
|
||||
Possible Time Save
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.PreviousSegmentComponent)}>
|
||||
Previous Segment
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.SplitsComponent)}>
|
||||
Splits
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.SumOfBestComponent)}>
|
||||
Sum of Best
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.TextComponent)}>
|
||||
Text
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.TimerComponent)}>
|
||||
Timer
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.TitleComponent)}>
|
||||
Title
|
||||
</MenuItem>
|
||||
<MenuItem onClick={(e) => this.addComponent(LiveSplit.TotalPlaytimeComponent)}>
|
||||
Total Playtime
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
<button onClick={(e) => this.removeComponent()}><i className="fa fa-minus" aria-hidden="true"></i></button>
|
||||
<button onClick={(e) => this.moveComponentUp()}><i className="fa fa-arrow-up" aria-hidden="true"></i></button>
|
||||
<button onClick={(e) => this.moveComponentDown()}><i className="fa fa-arrow-down" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
<table className="layout-editor-component-list table">
|
||||
<tbody className="table-body">
|
||||
{components}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<table className="layout-editor-component-list table">
|
||||
<table className="component-settings table">
|
||||
<tbody className="table-body">
|
||||
{components}
|
||||
{settingsRows}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -276,11 +276,11 @@ export class RunEditor extends React.Component<Props, State> {
|
||||
this.state.editor.segments.map((s: any, i: number) =>
|
||||
<form key={i.toString()} className={(s.selected == "Selected" || s.selected == "CurrentRow") ? "selected" : ""} onClick={(e) => this.changeSegmentSelection(e, i)}>
|
||||
<div><input className="name" type="text" value={s.name} onFocus={(e) => this.focusSegment(i)} onChange={(e) => this.handleSegmentNameChange(e)} /></div>
|
||||
<div><input className={this.state.rowState.index != i || this.state.rowState.splitTimeIsValid ? "" : "invalid"}
|
||||
<div><input className={this.state.rowState.index != i || this.state.rowState.splitTimeIsValid ? "number" : "number invalid"}
|
||||
type="text" value={s.split_time} onFocus={(e) => this.focusSegment(i)} onChange={(e) => this.handleSplitTimeChange(e)} onBlur={(e) => this.handleSplitTimeBlur(e)} /></div>
|
||||
<div><input className={this.state.rowState.index != i || this.state.rowState.segmentTimeIsValid ? "" : "invalid"}
|
||||
<div><input className={this.state.rowState.index != i || this.state.rowState.segmentTimeIsValid ? "number" : "number invalid"}
|
||||
type="text" value={s.segment_time} onFocus={(e) => this.focusSegment(i)} onChange={(e) => this.handleSegmentTimeChange(e)} onBlur={(e) => this.handleSegmentTimeBlur(e)} /></div>
|
||||
<div><input className={this.state.rowState.index != i || this.state.rowState.bestSegmentTimeIsValid ? "" : "invalid"}
|
||||
<div><input className={this.state.rowState.index != i || this.state.rowState.bestSegmentTimeIsValid ? "number" : "number invalid"}
|
||||
type="text" value={s.best_segment_time} onFocus={(e) => this.focusSegment(i)} onChange={(e) => this.handleBestSegmentTimeChange(e)} onBlur={(e) => this.handleBestSegmentTimeBlur(e)} /></div>
|
||||
</form>
|
||||
)
|
||||
|
||||
@@ -121,6 +121,7 @@ export interface LayoutEditorStateJson {
|
||||
components: string[],
|
||||
buttons: LayoutEditorButtonsJson,
|
||||
selected_component: number,
|
||||
settings_description: SettingsDescriptionJson,
|
||||
}
|
||||
|
||||
export interface LayoutEditorButtonsJson {
|
||||
@@ -129,6 +130,26 @@ export interface LayoutEditorButtonsJson {
|
||||
can_move_down: boolean,
|
||||
}
|
||||
|
||||
export interface SettingsDescriptionJson {
|
||||
fields: SettingsDescriptionFieldJson[],
|
||||
}
|
||||
|
||||
export interface SettingsDescriptionFieldJson {
|
||||
text: string,
|
||||
value: SettingsDescriptionValueJson,
|
||||
}
|
||||
|
||||
export type SettingsDescriptionValueJson =
|
||||
{ Bool: boolean } |
|
||||
{ UInt: number } |
|
||||
{ Int: number } |
|
||||
{ String: string } |
|
||||
{ OptionalString: string } |
|
||||
{ Float: number } |
|
||||
{ Accuracy: AccuracyJson };
|
||||
|
||||
export type AccuracyJson = "Seconds" | "Tenths" | "Hundredths";
|
||||
|
||||
export interface RunEditorStateJson {
|
||||
icon_change?: string,
|
||||
game: string,
|
||||
@@ -256,6 +277,14 @@ liveSplitCoreNative.LayoutEditor_remove_component = emscriptenModule.cwrap('Layo
|
||||
liveSplitCoreNative.LayoutEditor_move_component_up = emscriptenModule.cwrap('LayoutEditor_move_component_up', null, ["number"]);
|
||||
liveSplitCoreNative.LayoutEditor_move_component_down = emscriptenModule.cwrap('LayoutEditor_move_component_down', null, ["number"]);
|
||||
liveSplitCoreNative.LayoutEditor_move_component = emscriptenModule.cwrap('LayoutEditor_move_component', null, ["number", "number"]);
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_bool = emscriptenModule.cwrap('LayoutEditor_set_component_settings_bool', null, ["number", "number", "number"]);
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_uint = emscriptenModule.cwrap('LayoutEditor_set_component_settings_uint', null, ["number", "number", "number"]);
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_int = emscriptenModule.cwrap('LayoutEditor_set_component_settings_int', null, ["number", "number", "number"]);
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_string = emscriptenModule.cwrap('LayoutEditor_set_component_settings_string', null, ["number", "number", "string"]);
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_optional_string = emscriptenModule.cwrap('LayoutEditor_set_component_settings_optional_string', null, ["number", "number", "string"]);
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_optional_string_to_empty = emscriptenModule.cwrap('LayoutEditor_set_component_settings_optional_string_to_empty', null, ["number", "number"]);
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_float = emscriptenModule.cwrap('LayoutEditor_set_component_settings_float', null, ["number", "number", "number"]);
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_accuracy = emscriptenModule.cwrap('LayoutEditor_set_component_settings_accuracy', null, ["number", "number", "string"]);
|
||||
liveSplitCoreNative.PossibleTimeSaveComponent_new = emscriptenModule.cwrap('PossibleTimeSaveComponent_new', "number", []);
|
||||
liveSplitCoreNative.PossibleTimeSaveComponent_drop = emscriptenModule.cwrap('PossibleTimeSaveComponent_drop', null, ["number"]);
|
||||
liveSplitCoreNative.PossibleTimeSaveComponent_into_generic = emscriptenModule.cwrap('PossibleTimeSaveComponent_into_generic', "number", ["number"]);
|
||||
@@ -1449,6 +1478,54 @@ export class LayoutEditorRefMut extends LayoutEditorRef {
|
||||
}
|
||||
liveSplitCoreNative.LayoutEditor_move_component(this.ptr, dstIndex);
|
||||
}
|
||||
setComponentSettingsBool(index: number, value: boolean) {
|
||||
if (this.ptr == 0) {
|
||||
throw "this is disposed";
|
||||
}
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_bool(this.ptr, index, value ? 1 : 0);
|
||||
}
|
||||
setComponentSettingsUint(index: number, value: number) {
|
||||
if (this.ptr == 0) {
|
||||
throw "this is disposed";
|
||||
}
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_uint(this.ptr, index, value);
|
||||
}
|
||||
setComponentSettingsInt(index: number, value: number) {
|
||||
if (this.ptr == 0) {
|
||||
throw "this is disposed";
|
||||
}
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_int(this.ptr, index, value);
|
||||
}
|
||||
setComponentSettingsString(index: number, value: string) {
|
||||
if (this.ptr == 0) {
|
||||
throw "this is disposed";
|
||||
}
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_string(this.ptr, index, value);
|
||||
}
|
||||
setComponentSettingsOptionalString(index: number, value: string) {
|
||||
if (this.ptr == 0) {
|
||||
throw "this is disposed";
|
||||
}
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_optional_string(this.ptr, index, value);
|
||||
}
|
||||
setComponentSettingsOptionalStringToEmpty(index: number) {
|
||||
if (this.ptr == 0) {
|
||||
throw "this is disposed";
|
||||
}
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_optional_string_to_empty(this.ptr, index);
|
||||
}
|
||||
setComponentSettingsFloat(index: number, value: number) {
|
||||
if (this.ptr == 0) {
|
||||
throw "this is disposed";
|
||||
}
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_float(this.ptr, index, value);
|
||||
}
|
||||
setComponentSettingsAccuracy(index: number, value: string) {
|
||||
if (this.ptr == 0) {
|
||||
throw "this is disposed";
|
||||
}
|
||||
liveSplitCoreNative.LayoutEditor_set_component_settings_accuracy(this.ptr, index, value);
|
||||
}
|
||||
}
|
||||
|
||||
export class LayoutEditor extends LayoutEditorRefMut {
|
||||
|
||||
Reference in New Issue
Block a user