Tweaked theme and started working on porting quest editor to the new UI system.

This commit is contained in:
Daan Vanden Bosch 2019-08-21 22:04:08 +02:00
parent 3185737cd9
commit dbd5dba682
36 changed files with 242 additions and 104 deletions

View File

@ -3,7 +3,7 @@ import { writeFileSync } from "fs";
import "isomorphic-fetch";
import Logger from "js-logger";
import { ASSETS_DIR } from ".";
import { Difficulty, SectionId, SectionIds } from "../src/old/core/domain";
import { Difficulty, SectionId, SectionIds } from "../src/core/domain";
import { BoxDropDto, EnemyDropDto, ItemTypeDto } from "../src/old/core/dto";
import {
name_and_episode_to_npc_type,

View File

@ -5,7 +5,7 @@ import { BufferCursor } from "../src/core/data_formats/cursor/BufferCursor";
import { ItemPmt, parse_item_pmt } from "../src/core/data_formats/parsing/itempmt";
import { parse_quest } from "../src/core/data_formats/parsing/quest";
import { parse_unitxt, Unitxt } from "../src/core/data_formats/parsing/unitxt";
import { Difficulties, Difficulty, SectionId, SectionIds } from "../src/old/core/domain";
import { Difficulties, Difficulty, SectionId, SectionIds } from "../src/core/domain";
import { BoxDropDto, EnemyDropDto, ItemTypeDto, QuestDto } from "../src/old/core/dto";
import { update_drops_from_website } from "./update_drops_ephinea";
import { Episode, EPISODES } from "../src/core/data_formats/parsing/quest/Episode";

View File

@ -1,12 +1,14 @@
import { create_el } from "../../core/gui/dom";
import { View } from "../../core/gui/View";
import { gui_store, GuiTool } from "../../core/stores/GuiStore";
import { LazyView } from "../../core/gui/LazyView";
import { Resizable } from "../../core/gui/Resizable";
import { ResizableView } from "../../core/gui/ResizableView";
const TOOLS: [GuiTool, () => Promise<View & Resizable>][] = [
const TOOLS: [GuiTool, () => Promise<ResizableView>][] = [
[GuiTool.Viewer, async () => new (await import("../../viewer/gui/ViewerView")).ViewerView()],
[
GuiTool.QuestEditor,
async () => new (await import("../../quest_editor/gui/QuestEditorView")).QuestEditorView(),
],
];
export class MainContentView extends ResizableView {

View File

@ -3,7 +3,7 @@
display: flex;
flex-direction: row;
align-items: stretch;
background-color: hsl(0, 0%, 12%);
background-color: hsl(0, 0%, 10%);
border-bottom: solid 2px var(--bg-color);
}
@ -14,18 +14,19 @@
.application_ToolButton label {
box-sizing: border-box;
display: inline-block;
font-size: 16px;
font-size: 15px;
height: 100%;
padding: 0 20px;
line-height: 40px;
line-height: 29px;
color: hsl(0, 0%, 65%);
}
.application_ToolButton label:hover {
color: hsl(200, 25%, 85%);
background-color: hsl(0, 0%, 16%);
color: hsl(0, 0%, 85%);
background-color: hsl(0, 0%, 12%);
}
.application_ToolButton input:checked + label {
color: hsl(200, 50%, 85%);
background-color: hsl(0, 0%, 20%);
color: hsl(0, 0%, 85%);
background-color: var(--bg-color);
}

View File

@ -11,7 +11,7 @@ const TOOLS: [GuiTool, string][] = [
export class NavigationView extends View {
element = create_el("div", "application_NavigationView");
height = 40;
height = 30;
private buttons = new Map<GuiTool, ToolButton>(
TOOLS.map(([value, text]) => [value, this.disposable(new ToolButton(value, text))]),

View File

@ -1,4 +1,4 @@
import { enum_values } from "../../../core/enums";
import { enum_values } from "../enums";
export const RARE_ENEMY_PROB = 1 / 512;
export const KONDRIEU_PROB = 1 / 10;

View File

@ -1,21 +1,30 @@
.core_Button {
display: inline-block;
box-sizing: border-box;
background-color: #404040;
height: 26px;
padding: 2px 8px;
border: solid 1px #606060;
color: #f0f0f0;
padding: 0;
border: solid 1px hsl(0, 0%, 10%);
color: hsl(0, 0%, 80%);
outline: none;
}
.core_Button:hover {
background-color: #505050;
border-color: #707070;
.core_Button .core_Button_inner {
display: inline-block;
box-sizing: border-box;
background-color: hsl(0, 0%, 20%);
height: 24px;
line-height: 17px;
padding: 3px 8px;
border: solid 1px hsl(0, 0%, 35%);
}
.core_Button:active {
background-color: #404040;
border-color: #606060;
color: #e0e0e0;
.core_Button:hover .core_Button_inner {
background-color: hsl(0, 0%, 25%);
border-color: hsl(0, 0%, 40%);
color: hsl(0, 0%, 90%);
}
.core_Button:active .core_Button_inner {
background-color: hsl(0, 0%, 20%);
border-color: hsl(0, 0%, 30%);
color: hsl(0, 0%, 75%);
}

View File

@ -13,7 +13,10 @@ export class Button extends View {
constructor(text: string) {
super();
this.element.textContent = text;
const inner_element = create_el("span", "core_Button_inner");
inner_element.textContent = text;
this.element.append(inner_element);
this.element.onclick = (e: MouseEvent) => this._click.emit(e, undefined);
}

View File

@ -26,7 +26,9 @@ export class FileButton extends View {
}
};
this.element.textContent = text;
this.element.append(this.input);
const inner_element = create_el("span", "core_FileButton_inner core_Button_inner");
inner_element.textContent = text;
this.element.append(inner_element, this.input);
}
}

View File

@ -1,23 +1,32 @@
.core_Input {
box-sizing: border-box;
height: 26px;
border: solid 1px hsl(0, 0%, 25%);
}
.core_Input .core_Input_inner {
box-sizing: border-box;
width: 100%;
height: 24px;
padding: 0 3px;
border: solid 1px var(--border-color);
background-color: var(--input-bg-color);
color: var(--text-color);
border: solid 1px hsl(0, 0%, 0%);
background-color: hsl(0, 0%, 12%);
color: hsl(0, 0%, 75%);
outline: none;
}
.core_Input:hover {
border: solid 1px var(--border-color-hover);
border-color: hsl(0, 0%, 35%);
}
.core_Input:focus {
border: solid 1px var(--border-color-focus);
.core_Input:focus-within {
border-color: hsl(0, 0%, 45%);
}
.core_Input:disabled {
.core_Input.disabled {
border: solid 1px hsl(0, 0%, 20%);
}
.core_Input.disabled .core_Input_inner {
background-color: hsl(0, 0%, 15%);
color: var(--text-color-disabled);
background-color: var(--input-bg-color-disabled);
border: solid 1px var(--border-color);
}

View File

@ -1,3 +1,3 @@
.core_NumberInput {
.core_NumberInput .core_NumberInput_inner {
text-align: right;
}

View File

@ -7,12 +7,17 @@ import { LabelledControl } from "./LabelledControl";
import { is_any_property, Property } from "../observable/Property";
export class NumberInput extends LabelledControl {
readonly element: HTMLInputElement = create_el("input", "core_NumberInput core_Input");
readonly element = create_el("span", "core_NumberInput core_Input");
readonly value: WritableProperty<number> = property(0);
readonly preferred_label_position = "left";
private readonly input: HTMLInputElement = create_el(
"input",
"core_NumberInput_inner core_Input_inner",
);
constructor(
value = 0,
label?: string,
@ -22,29 +27,40 @@ export class NumberInput extends LabelledControl {
) {
super(label);
this.element.type = "number";
this.element.valueAsNumber = value;
this.element.style.width = "50px";
this.input.type = "number";
this.input.valueAsNumber = value;
this.set_prop("min", min);
this.set_prop("max", max);
this.set_prop("step", step);
this.element.onchange = () => this.value.set(this.element.valueAsNumber);
this.input.onchange = () => this.value.set(this.input.valueAsNumber);
this.element.append(this.input);
this.disposables(
this.value.observe(value => (this.element.valueAsNumber = value)),
this.value.observe(value => (this.input.valueAsNumber = value)),
this.enabled.observe(enabled => (this.element.disabled = !enabled)),
this.enabled.observe(enabled => {
this.input.disabled = !enabled;
if (enabled) {
this.element.classList.remove("disabled");
} else {
this.element.classList.add("disabled");
}
}),
);
this.element.style.width = "50px";
}
private set_prop<T>(prop: "min" | "max" | "step", value: T | Property<T>): void {
if (is_any_property(value)) {
this.element[prop] = String(value.get());
this.disposable(value.observe(v => (this.element[prop] = String(v))));
this.input[prop] = String(value.get());
this.disposable(value.observe(v => (this.input[prop] = String(v))));
} else {
this.element[prop] = String(value);
this.input[prop] = String(value);
}
}
}

View File

@ -1,6 +1,5 @@
.core_TabContainer_Bar {
box-sizing: border-box;
background-color: hsl(0, 0%, 16%);
padding: 3px 0 0 0;
border-bottom: solid 1px var(--border-color);
}
@ -13,7 +12,8 @@
padding: 0 10px;
border: solid 1px var(--border-color);
margin: 0 1px -1px 1px;
color: #c0c0c0;
background-color: hsl(0, 0%, 12%);
color: hsl(0, 0%, 75%);
font-size: 15px;
}

View File

@ -7,10 +7,11 @@
}
.core_ToolBar > * {
margin: 2px 4px;
margin: 2px 1px;
}
.core_ToolBar > .core_ToolBar_group {
margin: 2px 3px;
display: flex;
flex-direction: row;
align-items: center;
@ -19,19 +20,3 @@
.core_ToolBar > .core_ToolBar_group > * {
margin: 0 2px;
}
.core_ToolBar .core_Button {
background-color: transparent;
border-color: transparent;
}
.core_ToolBar .core_Button:hover {
background-color: #404040;
border-color: #505050;
}
.core_ToolBar .core_Button:active {
background-color: #383838;
border-color: #404040;
color: #d0d0d0;
}

View File

@ -5,7 +5,7 @@ import { LabelledControl } from "./LabelledControl";
export class ToolBar extends View {
readonly element = create_el("div", "core_ToolBar");
readonly height = 35;
readonly height = 33;
constructor(...children: View[]) {
super();

View File

@ -15,12 +15,11 @@ export abstract class View implements Disposable {
private disposer = new Disposer();
protected disposable<T extends Disposable>(disposable: T): T {
this.disposer.add(disposable);
return disposable;
return this.disposer.add(disposable);
}
protected disposables(...disposables: Disposable[]): void {
this.disposer.add(...disposables);
this.disposer.add_all(...disposables);
}
dispose(): void {

View File

@ -6,7 +6,12 @@ const logger = Logger.get("core/observable/Disposer");
export class Disposer implements Disposable {
private readonly disposables: Disposable[] = [];
add(...disposable: Disposable[]): this {
add<T extends Disposable>(disposable: T): T {
this.disposables.push(disposable);
return disposable;
}
add_all(...disposable: Disposable[]): this {
this.disposables.push(...disposable);
return this;
}

View File

@ -1,7 +1,7 @@
import Logger from "js-logger";
import { Server } from "./domain";
const logger = Logger.get("persistence/Persister");
const logger = Logger.get("core/persistence/Persister");
export abstract class Persister {
protected persist_for_server(server: Server, key: string, data: any): void {

View File

@ -1,16 +1,11 @@
:root {
--bg-color: hsl(0, 0%, 20%);
--text-color: hsl(0, 0%, 85%);
--bg-color: hsl(0, 0%, 15%);
--text-color: hsl(0, 0%, 80%);
--text-color-disabled: hsl(0, 0%, 55%);
--border-color: hsl(0, 0%, 30%);
--border-color-hover: hsl(0, 0%, 40%);
--border-color-focus: hsl(0, 0%, 50%);
--border-color: hsl(0, 0%, 25%);
--scrollbar-color: hsl(0, 0%, 17%);
--scrollbar-thumb-color: hsl(0, 0%, 23%);
--input-bg-color: hsl(0, 0%, 15%);
--input-bg-color-disabled: hsl(0, 0%, 20%);
--scrollbar-color: hsl(0, 0%, 13%);
--scrollbar-thumb-color: hsl(0, 0%, 17%);
}
* {

View File

@ -10,7 +10,7 @@ import {
import { Loadable } from "../Loadable";
import { ServerMap } from "./ServerMap";
import { ItemTypeDto } from "../dto";
import { Server } from "../domain";
import { Server } from "../../../core/domain";
export class ItemTypeStore {
private id_to_item_type: ItemType[] = [];

View File

@ -1,5 +1,5 @@
import { computed } from "mobx";
import { Server } from "../domain";
import { Server } from "../../../core/domain";
import { EnumMap } from "../../../core/enums";
/**

View File

@ -1,5 +1,5 @@
import React from "react";
import { SectionId } from "../domain";
import { SectionId } from "../../../core/domain";
export function SectionIdIcon({
section_id,

View File

@ -2,7 +2,7 @@ import { Episode } from "../../../core/data_formats/parsing/quest/Episode";
import { NpcType } from "../../../core/data_formats/parsing/quest/npc_types";
import { computed, observable } from "mobx";
import { ItemType } from "../../core/domain/items";
import { Difficulty, SectionId } from "../../core/domain";
import { Difficulty, SectionId } from "../../../core/domain";
export class HuntMethod {
readonly id: string;

View File

@ -1,5 +1,5 @@
import { Persister } from "../../core/persistence";
import { Server } from "../../core/domain";
import { Persister } from "../../../core/persistence";
import { Server } from "../../../core/domain";
import { HuntMethod } from "../domain";
const METHOD_USER_TIMES_KEY = "HuntMethodStore.methodUserTimes";

View File

@ -1,7 +1,7 @@
import { Server } from "../../core/domain";
import { Server } from "../../../core/domain";
import { WantedItem } from "../stores/HuntOptimizerStore";
import { item_type_stores } from "../../core/stores/ItemTypeStore";
import { Persister } from "../../core/persistence";
import { Persister } from "../../../core/persistence";
const WANTED_ITEMS_KEY = "HuntOptimizerStore.wantedItems";

View File

@ -1,6 +1,6 @@
import Logger from "js-logger";
import { autorun, IReactionDisposer, observable } from "mobx";
import { Server } from "../../core/domain";
import { Server } from "../../../core/domain";
import { QuestDto } from "../../core/dto";
import { Loadable } from "../../core/Loadable";
import { hunt_method_persister } from "../persistence/HuntMethodPersister";

View File

@ -8,7 +8,7 @@ import {
SectionId,
SectionIds,
Server,
} from "../../core/domain";
} from "../../../core/domain";
import { hunt_optimizer_persister } from "../persistence/HuntOptimizerPersister";
import { hunt_method_store } from "./HuntMethodStore";
import { item_drop_stores } from "./ItemDropStore";

View File

@ -1,5 +1,5 @@
import { observable } from "mobx";
import { Difficulties, Difficulty, SectionId, SectionIds, Server } from "../../core/domain";
import { Difficulties, Difficulty, SectionId, SectionIds, Server } from "../../../core/domain";
import { EnemyDropDto } from "../../core/dto";
import { Loadable } from "../../core/Loadable";
import { item_type_stores } from "../../core/stores/ItemTypeStore";

View File

@ -2,7 +2,7 @@ import { computed } from "mobx";
import { observer } from "mobx-react";
import React, { Component, ReactNode } from "react";
import { AutoSizer, Index } from "react-virtualized";
import { Difficulty, SectionId } from "../../core/domain";
import { Difficulty, SectionId } from "../../../core/domain";
import { hunt_optimizer_store, OptimalMethod } from "../stores/HuntOptimizerStore";
import { BigTable, Column } from "../../core/ui/BigTable";
import { SectionIdIcon } from "../../core/ui/SectionIdIcon";

View File

@ -2,7 +2,7 @@ import GoldenLayout, { ContentItem, ItemConfigType } from "golden-layout";
import Logger from "js-logger";
import { observer } from "mobx-react";
import React, { Component, createRef, FocusEvent, ReactNode } from "react";
import { quest_editor_ui_persister } from "../persistence/QuestEditorUiPersister";
import { quest_editor_ui_persister } from "../../../quest_editor/persistence/QuestEditorUiPersister";
import { quest_editor_store } from "../stores/QuestEditorStore";
import { AssemblyEditorComponent } from "./AssemblyEditorComponent";
import { EntityInfoComponent } from "./EntityInfoComponent";

View File

@ -0,0 +1,88 @@
import { ResizableView } from "../../core/gui/ResizableView";
import { create_el } from "../../core/gui/dom";
import { ToolBarView } from "./ToolBarView";
import GoldenLayout, { ContentItem } from "golden-layout";
import { quest_editor_ui_persister } from "../persistence/QuestEditorUiPersister";
import { AssemblyEditorComponent } from "../../old/quest_editor/ui/AssemblyEditorComponent";
import { quest_editor_store } from "../../old/quest_editor/stores/QuestEditorStore";
import Logger = require("js-logger");
const logger = Logger.get("quest_editor/gui/QuestEditorView");
const DEFAULT_LAYOUT_CONFIG = {
settings: {
showPopoutIcon: false,
},
dimensions: {
headerHeight: 28,
},
labels: {
close: "Close",
maximise: "Maximise",
minimise: "Minimise",
popout: "Open in new window",
},
};
export class QuestEditorView extends ResizableView {
readonly element = create_el("div");
private readonly tool_bar_view = this.disposable(new ToolBarView());
private layout_element = create_el("div");
// private layout: GoldenLayout;
constructor() {
super();
// const content = await quest_editor_ui_persister.load_layout_config(
// [...CMP_TO_NAME.values()],
// DEFAULT_LAYOUT_CONTENT,
// );
//
// const config: GoldenLayout.Config = {
// ...DEFAULT_LAYOUT_CONFIG,
// content,
// };
//
// try {
// this.layout = new GoldenLayout(config, this.layout_element);
// } catch (e) {
// logger.warn("Couldn't initialize golden layout with persisted layout.", e);
//
// this.layout = new GoldenLayout(
// {
// ...DEFAULT_LAYOUT_CONFIG,
// content: DEFAULT_LAYOUT_CONTENT,
// },
// this.layout_element,
// );
// }
//
// for (const [component, name] of CMP_TO_NAME) {
// this.layout.registerComponent(name, component);
// }
//
// this.layout.on("stateChanged", () => {
// if (this.layout) {
// quest_editor_ui_persister.persist_layout_config(this.layout.toConfig().content);
// }
// });
//
// this.layout.on("stackCreated", (stack: ContentItem) => {
// stack.on("activeContentItemChanged", (item: ContentItem) => {
// if ("component" in item.config) {
// if (item.config.component === CMP_TO_NAME.get(AssemblyEditorComponent)) {
// quest_editor_store.script_undo.make_current();
// } else {
// quest_editor_store.undo.make_current();
// }
// }
// });
// });
//
// this.layout.init();
this.element.append(this.tool_bar_view.element, this.layout_element);
}
}

View File

@ -0,0 +1,24 @@
import { View } from "../../core/gui/View";
import { ToolBar } from "../../core/gui/ToolBar";
import { FileButton } from "../../core/gui/FileButton";
import { Button } from "../../core/gui/Button";
export class ToolBarView extends View {
private readonly open_file_button = new FileButton("Open file...", ".qst");
private readonly save_as_button = new Button("Save as...");
private readonly undo_button = new Button("Undo");
private readonly redo_button = new Button("Redo");
private readonly tool_bar = new ToolBar(
this.open_file_button,
this.save_as_button,
this.undo_button,
this.redo_button,
);
readonly element = this.tool_bar.element;
get height(): number {
return this.tool_bar.height;
}
}

View File

@ -16,11 +16,11 @@
}
.viewer_ModelSelectListView li:hover {
color: hsl(200, 25%, 85%);
background-color: hsl(0, 0%, 25%);
color: hsl(0, 0%, 90%);
background-color: hsl(0, 0%, 18%);
}
.viewer_ModelSelectListView li.active {
color: hsl(200, 50%, 85%);
background-color: hsl(0, 0%, 30%);
color: hsl(0, 0%, 90%);
background-color: hsl(0, 0%, 21%);
}

View File

@ -42,7 +42,7 @@ export class ModelRenderer extends Renderer implements Disposable {
this.perspective_camera = this.camera as PerspectiveCamera;
this.disposer.add(
this.disposer.add_all(
model_store.current_nj_data.observe(this.nj_data_or_xvm_changed),
model_store.current_xvm.observe(this.nj_data_or_xvm_changed),
model_store.current_nj_motion.observe(this.nj_motion_changed),

View File

@ -31,7 +31,7 @@ export class TextureRenderer extends Renderer implements Disposable {
this.controls.azimuthRotateSpeed = 0;
this.controls.polarRotateSpeed = 0;
this.disposer.add(
this.disposer.add_all(
texture_store.current_xvm.observe(xvm => {
this.scene.remove(...this.quad_meshes);