UI: add cursor options to the script editor (#615)

This commit is contained in:
Aleksei Bezrodnov 2023-06-19 03:17:15 +02:00 committed by GitHub
parent 709875d9ca
commit 9e75621cd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 70 additions and 16 deletions

@ -1,6 +1,7 @@
import React, { useEffect, useRef } from "react";
import * as monaco from "monaco-editor"; import * as monaco from "monaco-editor";
import * as React from "react";
import { useEffect, useRef } from "react";
import { useScriptEditorContext } from "./ScriptEditorContext"; import { useScriptEditorContext } from "./ScriptEditorContext";
interface EditorProps { interface EditorProps {

@ -1,19 +1,19 @@
import type { editor, Position } from "monaco-editor";
import type { ContentFilePath } from "../../Paths/ContentFile"; import type { ContentFilePath } from "../../Paths/ContentFile";
import * as monaco from "monaco-editor"; type ITextModel = editor.ITextModel;
type ITextModel = monaco.editor.ITextModel;
// Holds all the data for a open script // Holds all the data for a open script
export class OpenScript { export class OpenScript {
path: ContentFilePath; path: ContentFilePath;
code: string; code: string;
hostname: string; hostname: string;
lastPosition: monaco.Position; lastPosition: Position;
model: ITextModel; model: ITextModel;
isTxt: boolean; isTxt: boolean;
constructor(path: ContentFilePath, code: string, hostname: string, lastPosition: monaco.Position, model: ITextModel) { constructor(path: ContentFilePath, code: string, hostname: string, lastPosition: Position, model: ITextModel) {
this.path = path; this.path = path;
this.code = code; this.code = code;
this.hostname = hostname; this.hostname = hostname;

@ -1,4 +1,10 @@
import type { editor } from "monaco-editor";
export type WordWrapOptions = "on" | "off" | "bounded" | "wordWrapColumn"; export type WordWrapOptions = "on" | "off" | "bounded" | "wordWrapColumn";
export type CursorStyle = editor.IEditorOptions["cursorStyle"];
export type CursorBlinking = editor.IEditorOptions["cursorBlinking"];
export interface Options { export interface Options {
theme: string; theme: string;
insertSpaces: boolean; insertSpaces: boolean;
@ -9,4 +15,6 @@ export interface Options {
fontLigatures: boolean; fontLigatures: boolean;
wordWrap: WordWrapOptions; wordWrap: WordWrapOptions;
vim: boolean; vim: boolean;
cursorStyle: CursorStyle;
cursorBlinking: CursorBlinking;
} }

@ -1,4 +1,4 @@
import React from "react"; import React, { ReactElement } from "react";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
@ -11,7 +11,10 @@ import EditIcon from "@mui/icons-material/Edit";
import { useBoolean } from "../../ui/React/hooks"; import { useBoolean } from "../../ui/React/hooks";
import { Modal } from "../../ui/React/Modal"; import { Modal } from "../../ui/React/Modal";
import { ThemeEditorModal } from "./ThemeEditorModal"; import { ThemeEditorModal } from "./ThemeEditorModal";
import { Options } from "./Options"; import { CursorBlinking, CursorStyle, Options } from "./Options";
const CURSOR_STYLES: CursorStyle[] = ["line", "block", "underline", "line-thin", "block-outline", "underline-thin"];
const CURSOR_BLINKING_MODES: CursorBlinking[] = ["blink", "smooth", "phase", "expand", "solid"];
export type OptionsModalProps = { export type OptionsModalProps = {
open: boolean; open: boolean;
@ -21,7 +24,7 @@ export type OptionsModalProps = {
onThemeChange: () => void; onThemeChange: () => void;
}; };
export function OptionsModal(props: OptionsModalProps): React.ReactElement { export function OptionsModal(props: OptionsModalProps): ReactElement {
const [themeEditorOpen, { on: openThemeEditor, off: closeThemeEditor }] = useBoolean(false); const [themeEditorOpen, { on: openThemeEditor, off: closeThemeEditor }] = useBoolean(false);
const onFontSizeChange = (event: React.ChangeEvent<HTMLInputElement>) => { const onFontSizeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
@ -116,6 +119,34 @@ export function OptionsModal(props: OptionsModalProps): React.ReactElement {
checked={props.options.fontLigatures} checked={props.options.fontLigatures}
/> />
</div> </div>
<div style={{ display: "flex", alignItems: "center" }}>
<Typography marginRight={"auto"}>Cursor style: </Typography>
<Select
onChange={(event) => props.onOptionChange("cursorStyle", event.target.value)}
value={props.options.cursorStyle}
>
{CURSOR_STYLES.map((cursorStyle) => (
<MenuItem key={cursorStyle} value={cursorStyle}>
{cursorStyle}
</MenuItem>
))}
</Select>
</div>
<div style={{ display: "flex", alignItems: "center" }}>
<Typography marginRight={"auto"}>Cursor blinking: </Typography>
<Select
onChange={(event) => props.onOptionChange("cursorBlinking", event.target.value as CursorBlinking)}
value={props.options.cursorBlinking}
>
{CURSOR_BLINKING_MODES.map((cursorBlinking) => (
<MenuItem key={cursorBlinking} value={cursorBlinking}>
{cursorBlinking}
</MenuItem>
))}
</Select>
</div>
</Modal> </Modal>
); );
} }

@ -79,6 +79,8 @@ export function ScriptEditorContextProvider({ children, vim }: { children: React
fontLigatures: Settings.MonacoFontLigatures, fontLigatures: Settings.MonacoFontLigatures,
wordWrap: Settings.MonacoWordWrap, wordWrap: Settings.MonacoWordWrap,
vim: vim || Settings.MonacoVim, vim: vim || Settings.MonacoVim,
cursorStyle: Settings.MonacoCursorStyle,
cursorBlinking: Settings.MonacoCursorBlinking,
}); });
function saveOptions(options: Options) { function saveOptions(options: Options) {
@ -90,6 +92,8 @@ export function ScriptEditorContextProvider({ children, vim }: { children: React
Settings.MonacoFontFamily = options.fontFamily; Settings.MonacoFontFamily = options.fontFamily;
Settings.MonacoFontSize = options.fontSize; Settings.MonacoFontSize = options.fontSize;
Settings.MonacoFontLigatures = options.fontLigatures; Settings.MonacoFontLigatures = options.fontLigatures;
Settings.MonacoCursorStyle = options.cursorStyle;
Settings.MonacoCursorBlinking = options.cursorBlinking;
Settings.MonacoWordWrap = options.wordWrap; Settings.MonacoWordWrap = options.wordWrap;
Settings.MonacoVim = options.vim; Settings.MonacoVim = options.vim;
} }

@ -1,7 +1,8 @@
import React, { useEffect, useRef } from "react"; import React, { useEffect, useRef } from "react";
import { Editor } from "./Editor";
import * as monaco from "monaco-editor"; import * as monaco from "monaco-editor";
import { Editor } from "./Editor";
type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor; type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor;
import { Router } from "../../ui/GameRoot"; import { Router } from "../../ui/GameRoot";

@ -40,8 +40,13 @@ export function Toolbar({ editor, onSave }: IProps) {
const { ram, ramEntries, isUpdatingRAM, options, saveOptions } = useScriptEditorContext(); const { ram, ramEntries, isUpdatingRAM, options, saveOptions } = useScriptEditorContext();
const onOptionChange: OptionsModalProps["onOptionChange"] = (option, value) => { const onOptionChange: OptionsModalProps["onOptionChange"] = (option, value) => {
saveOptions({ ...options, [option]: value }); const newOptions = { ...options, [option]: value };
editor?.updateOptions(options); saveOptions(newOptions);
// delaying editor options update to avoid an issue
// where switching between vim and regular modes causes some settings to be reset
setTimeout(() => {
editor?.updateOptions(newOptions);
}, 100);
}; };
const onThemeChange = () => { const onThemeChange = () => {

@ -1,8 +1,8 @@
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
// @ts-expect-error This library does not have types. // @ts-expect-error This library does not have types.
import * as MonacoVim from "monaco-vim"; import * as MonacoVim from "monaco-vim";
import * as monaco from "monaco-editor"; import type { editor } from "monaco-editor";
type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor; type IStandaloneCodeEditor = editor.IStandaloneCodeEditor;
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";

@ -1,7 +1,7 @@
import { OwnedAugmentationsOrderSetting, PurchaseAugmentationsOrderSetting } from "./SettingEnums"; import { OwnedAugmentationsOrderSetting, PurchaseAugmentationsOrderSetting } from "./SettingEnums";
import { defaultTheme } from "../Themes/Themes"; import { defaultTheme } from "../Themes/Themes";
import { defaultStyles } from "../Themes/Styles"; import { defaultStyles } from "../Themes/Styles";
import { WordWrapOptions } from "../ScriptEditor/ui/Options"; import { CursorStyle, CursorBlinking, WordWrapOptions } from "../ScriptEditor/ui/Options";
import { defaultMonacoTheme } from "../ScriptEditor/ui/themes"; import { defaultMonacoTheme } from "../ScriptEditor/ui/themes";
/** The current options the player has customized to their play style. */ /** The current options the player has customized to their play style. */
@ -96,6 +96,10 @@ export const Settings = {
MonacoVim: false, MonacoVim: false,
/** Word wrap setting for Script Editor. */ /** Word wrap setting for Script Editor. */
MonacoWordWrap: "off" as WordWrapOptions, MonacoWordWrap: "off" as WordWrapOptions,
/** Control the cursor style*/
MonacoCursorStyle: "line" as CursorStyle,
/** Control the cursor animation style */
MonacoCursorBlinking: "blink" as CursorBlinking,
/** Whether to hide trailing zeroes on fractional part of decimal */ /** Whether to hide trailing zeroes on fractional part of decimal */
hideTrailingDecimalZeros: false, hideTrailingDecimalZeros: false,
/** Whether to hide thousands separators. */ /** Whether to hide thousands separators. */