Merge pull request 'issue-5-gamesystems' (#6) from issue-5-gamesystems into main
All checks were successful
E2E Testing / test (push) Successful in 1m27s
All checks were successful
E2E Testing / test (push) Successful in 1m27s
Reviewed-on: #6
This commit is contained in:
commit
1cde7f2939
@ -57,7 +57,7 @@ function createWindow(): BrowserWindow {
|
||||
{
|
||||
label: "Gamesystem",
|
||||
click: () => {
|
||||
win!.webContents.send('context-menu', "new-location");
|
||||
win!.webContents.send('context-menu', "new-gamesystem");
|
||||
}
|
||||
},
|
||||
{
|
||||
|
53
e2e/game-model/gamesystems/CreateGamesystem.spec.ts
Normal file
53
e2e/game-model/gamesystems/CreateGamesystem.spec.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
|
||||
import { test, expect } from '@playwright/test';
|
||||
import * as PATH from 'path';
|
||||
import {GameModel} from "../../../src/app/game-model/GameModel";
|
||||
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
|
||||
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
|
||||
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
|
||||
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
|
||||
import exp = require("node:constants");
|
||||
import {end} from "electron-debug";
|
||||
import {GamesystemTrainer} from "./GamesystemTrainer";
|
||||
import {ProductGamesystem} from "../../../src/app/game-model/gamesystems/ProductGamesystem";
|
||||
test.describe('Test Create Gamesystems', () => {
|
||||
|
||||
test('Test creating gamesystem with invalid name', async => {
|
||||
const gameModel = GamesystemTrainer.givenEmptyGameModel();
|
||||
let result = gameModel.createGamesystem(undefined, undefined);
|
||||
expect(result).toBeUndefined();
|
||||
|
||||
result = gameModel.createGamesystem(null, undefined);
|
||||
expect(result).toBeUndefined();
|
||||
})
|
||||
|
||||
test("Test creating gamesystem with valid name but without parent", async => {
|
||||
const gameModel = GamesystemTrainer.givenEmptyGameModel();
|
||||
let result = gameModel.createGamesystem(GamesystemTrainer.SIMPLEGAMESYSTEMNAME, undefined);
|
||||
expect(result).toBeDefined();
|
||||
expect(gameModel.gamesystems.length).toEqual(1);
|
||||
expect(gameModel.findGamesystem(GamesystemTrainer.SIMPLEGAMESYSTEMNAME)).toBeDefined();
|
||||
})
|
||||
|
||||
test("Test creating Gamesystem with valid name but with Product Parent", async => {
|
||||
const gameModel = GamesystemTrainer.givenGameModelWithProductGamesytemOnTopLayer();
|
||||
let result = gameModel.createGamesystem(GamesystemTrainer.SIMPLEGAMESYSTEM_LEAF_LEFT, GamesystemTrainer.TOP_PRODUCT_GAMESYSTEM_NAME);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.parentGamesystem!.componentName).toEqual(GamesystemTrainer.TOP_PRODUCT_GAMESYSTEM_NAME);
|
||||
expect(result.parentGamesystem!.innerGamesystems.length).toEqual(3);
|
||||
expect(result.parentGamesystem!.innerGamesystems.includes(result)).toBeTruthy();
|
||||
})
|
||||
|
||||
test("Test creating Gamesystem with valid name but with Simple Parent", async() => {
|
||||
const gameModel = GamesystemTrainer.givenGameModelWithSimpleGamesystemOnTopLayer();
|
||||
let result = gameModel.createGamesystem(GamesystemTrainer.SIMPLEGAMESYSTEM_LEAF_LEFT, GamesystemTrainer.SIMPLEGAMESYSTEMNAME);
|
||||
expect(result).toBeDefined();
|
||||
expect(gameModel.gamesystems.length).toEqual(1);
|
||||
expect(gameModel.gamesystems[0]).toBeInstanceOf(ProductGamesystem);
|
||||
expect(gameModel.gamesystems[0]).toEqual(result.parentGamesystem);
|
||||
expect((gameModel.gamesystems[0] as ProductGamesystem).innerGamesystems.length).toEqual(1);
|
||||
expect((gameModel.gamesystems[0] as ProductGamesystem).innerGamesystems.includes(result)).toBeTruthy();
|
||||
})
|
||||
|
||||
|
||||
});
|
50
e2e/game-model/gamesystems/FindGamesystem.spec.ts
Normal file
50
e2e/game-model/gamesystems/FindGamesystem.spec.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
|
||||
import { test, expect } from '@playwright/test';
|
||||
import * as PATH from 'path';
|
||||
import {GameModel} from "../../../src/app/game-model/GameModel";
|
||||
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
|
||||
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
|
||||
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
|
||||
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
|
||||
import exp = require("node:constants");
|
||||
import {end} from "electron-debug";
|
||||
import {GamesystemTrainer} from "./GamesystemTrainer";
|
||||
test.describe('Test Find Gamesystems', () => {
|
||||
const GAMEMODELNAME: string = "GameModel";
|
||||
const SIMPLEGAMESYSTEM_NAME: string = "Simple Gamesystem";
|
||||
|
||||
|
||||
test('Find null or undefined Gamesystem', async () => {
|
||||
const gameModel = new GameModel(GAMEMODELNAME);
|
||||
expect(gameModel.findGamesystem(null)).toBeUndefined();
|
||||
expect(gameModel.findGamesystem(undefined)).toBeUndefined();
|
||||
})
|
||||
|
||||
test('Find non existend Gamesystem', async () => {
|
||||
const gameModel = new GameModel(GAMEMODELNAME);
|
||||
expect(gameModel.findGamesystem("Gamesystem")).toBeUndefined();
|
||||
})
|
||||
|
||||
test("Find existend simple Gamesystem on top layer", async () => {
|
||||
const gameModel = new GameModel(GAMEMODELNAME);
|
||||
const gamesystem = new SimpleGamesystem(SIMPLEGAMESYSTEM_NAME);
|
||||
gameModel.addGamesystem(gamesystem);
|
||||
|
||||
expect(gameModel.findGamesystem(SIMPLEGAMESYSTEM_NAME)).toBeDefined();
|
||||
expect(gameModel.findGamesystem(SIMPLEGAMESYSTEM_NAME)).toEqual(gamesystem);
|
||||
})
|
||||
|
||||
test('Find existent product gamesystem on top layer', async () => {
|
||||
const gameModel = GamesystemTrainer.givenGameModelWithProductGamesytemOnTopLayer();
|
||||
const result = gameModel.findGamesystem(GamesystemTrainer.TOP_PRODUCT_GAMESYSTEM_NAME);
|
||||
expect(result).toBeDefined();
|
||||
|
||||
})
|
||||
|
||||
test('Find existent simple gamesystem on lower layer', async () => {
|
||||
const gameModel = GamesystemTrainer.givenGameModelWithProductGamesytemOnTopLayer();
|
||||
const result = gameModel.findGamesystem(GamesystemTrainer.SIMPLEGAMESYSTEMNAME);
|
||||
expect(result).toBeDefined();
|
||||
|
||||
})
|
||||
});
|
55
e2e/game-model/gamesystems/GamesystemTrainer.ts
Normal file
55
e2e/game-model/gamesystems/GamesystemTrainer.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import {GameModel} from "../../../src/app/game-model/GameModel";
|
||||
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
|
||||
import {ProductGamesystem} from "../../../src/app/game-model/gamesystems/ProductGamesystem";
|
||||
|
||||
export class GamesystemTrainer {
|
||||
|
||||
static GAMEMODELNAME: string = "GAMEMODEL";
|
||||
static SIMPLEGAMESYSTEMNAME: string = "SIMPLE GAMESYSTEM";
|
||||
static TOP_PRODUCT_GAMESYSTEM_NAME: string = "Top Product Gamesystem"
|
||||
|
||||
static SIMPLEGAMESYSTEM2: string = "Simple Gamesystem Leaf 2";
|
||||
static SIMPLEGAMESYSTEM_LEAF_LEFT: string = "Leaf Gamesystem Left"
|
||||
static SIMPLEGAMESYSTEM_LEAF_RIGHT: string = "Leaf Gamesystem Right";
|
||||
|
||||
static givenEmptyGameModel() {
|
||||
return new GameModel(GamesystemTrainer.GAMEMODELNAME);
|
||||
}
|
||||
|
||||
static givenGameModelWithSimpleGamesystemOnTopLayer() {
|
||||
const gameModel = new GameModel(GamesystemTrainer.GAMEMODELNAME);
|
||||
const gamesytem = new SimpleGamesystem(GamesystemTrainer.SIMPLEGAMESYSTEMNAME);
|
||||
gameModel.addGamesystem(gamesytem);
|
||||
|
||||
return gameModel;
|
||||
}
|
||||
|
||||
static givenGameModelWithProductGamesytemOnTopLayer() {
|
||||
const gameModel = new GameModel(GamesystemTrainer.GAMEMODELNAME);
|
||||
const productGamesystem = new ProductGamesystem(this.TOP_PRODUCT_GAMESYSTEM_NAME);
|
||||
const leaf1 = new SimpleGamesystem(this.SIMPLEGAMESYSTEMNAME);
|
||||
const leaf2 = new SimpleGamesystem(this.SIMPLEGAMESYSTEM2);
|
||||
productGamesystem.innerGamesystems.push(leaf1);
|
||||
productGamesystem.innerGamesystems.push(leaf2);
|
||||
gameModel.addGamesystem(productGamesystem);
|
||||
|
||||
return gameModel;
|
||||
}
|
||||
|
||||
static givenGameModelWithProductGamesystemOnLowerLayer() {
|
||||
const gameModel = new GameModel(GamesystemTrainer.GAMEMODELNAME);
|
||||
const top_productGamesystem = new ProductGamesystem(this.TOP_PRODUCT_GAMESYSTEM_NAME);
|
||||
const leaf1 = new ProductGamesystem(this.SIMPLEGAMESYSTEMNAME);
|
||||
const leaf2 = new SimpleGamesystem(this.SIMPLEGAMESYSTEM2);
|
||||
top_productGamesystem.innerGamesystems.push(leaf1);
|
||||
top_productGamesystem.innerGamesystems.push(leaf2);
|
||||
gameModel.addGamesystem(top_productGamesystem);
|
||||
|
||||
const leaf_1_1 = new SimpleGamesystem(this.SIMPLEGAMESYSTEM_LEAF_LEFT);
|
||||
leaf1.addChildGamesystem(leaf_1_1);
|
||||
const leaf_1_2 = new SimpleGamesystem(this.SIMPLEGAMESYSTEM_LEAF_RIGHT);
|
||||
leaf1.addChildGamesystem(leaf_1_2);
|
||||
}
|
||||
|
||||
|
||||
}
|
172
e2e/game-model/gamesystems/SimpleGamesystem.spec.ts
Normal file
172
e2e/game-model/gamesystems/SimpleGamesystem.spec.ts
Normal file
@ -0,0 +1,172 @@
|
||||
import { BrowserContext, ElectronApplication, Page, _electron as electron } from 'playwright';
|
||||
import { test, expect } from '@playwright/test';
|
||||
import * as PATH from 'path';
|
||||
import {GameModel} from "../../../src/app/game-model/GameModel";
|
||||
import {Gamesystem} from "../../src/app/game-model/gamesystems/Gamesystem";
|
||||
import {ScriptAccount} from "../../../src/app/game-model/scriptAccounts/ScriptAccount";
|
||||
import {ModelComponentType} from "../../../src/app/game-model/ModelComponentType";
|
||||
import {SimpleGamesystem} from "../../../src/app/game-model/gamesystems/SimpleGamesystem";
|
||||
import exp = require("node:constants");
|
||||
import {end} from "electron-debug";
|
||||
|
||||
test.describe('Test SimpleGamesystem', () => {
|
||||
|
||||
test("Create SimpleState", async () => {
|
||||
const gamesystem = new SimpleGamesystem();
|
||||
let state = gamesystem.createState("Test", "Test2");
|
||||
expect(state.stateLabel).toEqual("Test");
|
||||
expect(state.stateDescription).toEqual("Test2");
|
||||
expect(state.incomingTransitions.length).toEqual(0);
|
||||
expect(state.outgoingTransitions.length).toEqual(0);
|
||||
expect(gamesystem.states.includes(state)).toBeTruthy();
|
||||
|
||||
state = gamesystem.createState(null, null);
|
||||
expect(state).toBeUndefined();
|
||||
expect(gamesystem.states.includes(state)).toBeFalsy();
|
||||
|
||||
state = gamesystem.createState(null, "test2");
|
||||
expect(state).toBeUndefined()
|
||||
expect(gamesystem.states.includes(state)).toBeFalsy();
|
||||
|
||||
state = gamesystem.createState("test2", null);
|
||||
expect(state).toBeDefined();
|
||||
expect(state.stateLabel).toEqual("test2");
|
||||
expect(state.stateDescription).toEqual("");
|
||||
expect(gamesystem.states.includes(state)).toBeTruthy();
|
||||
|
||||
state = gamesystem.createState(undefined, "State");
|
||||
expect(state).toBeUndefined();
|
||||
expect(gamesystem.states.includes(state)).toBeFalsy();
|
||||
|
||||
state = gamesystem.createState("Test3", undefined);
|
||||
expect(state).toBeDefined();
|
||||
expect(state.stateLabel).toEqual("Test3");
|
||||
expect(state.stateDescription).toEqual("");
|
||||
expect(gamesystem.states.includes(state)).toBeTruthy();
|
||||
|
||||
state = gamesystem.createState("", "");
|
||||
expect(state).toBeDefined();
|
||||
expect(state.stateLabel).toEqual("");
|
||||
expect(state.stateDescription).toEqual("");
|
||||
expect(gamesystem.states.includes(state)).toBeTruthy();
|
||||
|
||||
state = gamesystem.createState("Test3", "");
|
||||
expect(state).toBeUndefined();
|
||||
expect(gamesystem.states.includes(state)).toBeFalsy();
|
||||
})
|
||||
|
||||
test("Create SimpleTransition", async () => {
|
||||
const gamesystem = new SimpleGamesystem();
|
||||
const startingState = gamesystem.createState("StartingState", "")!;
|
||||
const endingState = gamesystem.createState("EndingState", "")!
|
||||
|
||||
let transition = gamesystem.createTransition(startingState, endingState);
|
||||
expect(transition).toBeDefined();
|
||||
expect(transition.startingState).toEqual(startingState);
|
||||
expect(transition.endingState).toEqual(endingState);
|
||||
expect(startingState.outgoingTransitions.includes(transition)).toBeTruthy();
|
||||
expect(endingState.incomingTransitions.includes(transition)).toBeTruthy();
|
||||
expect(gamesystem.transitions.includes(transition)).toBeTruthy();
|
||||
|
||||
transition = gamesystem.createTransition(null, null);
|
||||
expect(transition).toBeUndefined();
|
||||
|
||||
transition = gamesystem.createTransition(null, endingState);
|
||||
expect(transition).toBeUndefined();
|
||||
|
||||
transition = gamesystem.createTransition(undefined, undefined);
|
||||
expect(transition).toBeUndefined();
|
||||
|
||||
transition = gamesystem.createTransition(undefined, endingState);
|
||||
expect(transition).toBeUndefined();
|
||||
|
||||
transition = gamesystem.createTransition(startingState, null);
|
||||
expect(transition).toBeUndefined();
|
||||
|
||||
transition = gamesystem.createTransition(startingState, undefined);
|
||||
expect(transition).toBeUndefined();
|
||||
|
||||
transition = gamesystem.createTransition(startingState, startingState);
|
||||
expect(transition).toBeUndefined();
|
||||
|
||||
transition = gamesystem.createTransition(startingState, endingState);
|
||||
expect(transition).toBeUndefined();
|
||||
|
||||
})
|
||||
|
||||
test("Remove SimpleState", async () => {
|
||||
const gamesystem = new SimpleGamesystem("Test");
|
||||
const state1 = gamesystem.createState("State1", "");
|
||||
|
||||
const state1_delete = gamesystem.removeState(state1);
|
||||
expect(state1_delete).toBeTruthy();
|
||||
expect(gamesystem.states.includes(state1)).toBeFalsy();
|
||||
|
||||
let startingState = gamesystem.createState("Start", "End");
|
||||
let endingState = gamesystem.createState("End", "");
|
||||
let transition = gamesystem.createTransition(startingState, endingState);
|
||||
let result = gamesystem.removeState(startingState);
|
||||
expect(result).toBeTruthy();
|
||||
expect(gamesystem.states.includes(startingState)).toBeFalsy();
|
||||
expect(gamesystem.states.includes(endingState)).toBeTruthy();
|
||||
expect(gamesystem.transitions.length).toEqual(0);
|
||||
|
||||
startingState = gamesystem.createState("Start");
|
||||
transition = gamesystem.createTransition(startingState, endingState);
|
||||
gamesystem.removeState(endingState);
|
||||
expect(result).toBeTruthy();
|
||||
expect(gamesystem.states.includes(startingState)).toBeTruthy();
|
||||
expect(gamesystem.states.includes(endingState)).toBeFalsy();
|
||||
expect(gamesystem.transitions.length).toEqual(0);
|
||||
|
||||
endingState = gamesystem.createState("End");
|
||||
transition = gamesystem.createTransition(startingState, endingState);
|
||||
const testingState = gamesystem.createState("TestingState", "");
|
||||
result = gamesystem.removeState(testingState);
|
||||
expect(result).toBeTruthy();
|
||||
expect(gamesystem.transitions.includes(transition)).toBeTruthy();
|
||||
|
||||
const gamesystem2 = new SimpleGamesystem("test2");
|
||||
const state2 = gamesystem2.createState("Test", "");
|
||||
result = gamesystem.removeState(state2);
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
result = gamesystem.removeState(null);
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
result = gamesystem.removeState(undefined);
|
||||
expect(result).toBeFalsy();
|
||||
})
|
||||
|
||||
test("Remove SimpleTransition", async () => {
|
||||
const gamesystem = new SimpleGamesystem("Gamesystem");
|
||||
const A = gamesystem.createState("A");
|
||||
const B = gamesystem.createState("B");
|
||||
let AB = gamesystem.createTransition(A, B);
|
||||
|
||||
let result = gamesystem.removeTransition(AB);
|
||||
expect(result).toBeTruthy();
|
||||
expect(gamesystem.transitions.includes(AB)).toBeFalsy();
|
||||
|
||||
AB = gamesystem.createTransition(A, B);
|
||||
const C = gamesystem.createState("C");
|
||||
const D = gamesystem.createState("D");
|
||||
let CD = gamesystem.createTransition(C, D);
|
||||
|
||||
result = gamesystem.removeTransition(AB);
|
||||
expect(result).toBeTruthy();
|
||||
expect(gamesystem.transitions.includes(AB)).toBeFalsy();
|
||||
expect(gamesystem.transitions.includes(CD)).toBeTruthy();
|
||||
|
||||
let BA = gamesystem.createTransition(B, A);
|
||||
AB = gamesystem.createTransition(A, B);
|
||||
result = gamesystem.removeTransition(AB);
|
||||
expect(result).toBeTruthy();
|
||||
expect(gamesystem.transitions.includes(AB)).toBeFalsy();
|
||||
expect(gamesystem.transitions.includes(BA)).toBeTruthy();
|
||||
|
||||
result = gamesystem.removeTransition(AB);
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
})
|
||||
});
|
@ -21,24 +21,24 @@ test.describe('Test ScriptAccounts', () => {
|
||||
test("Test Adding ScriptAccounts", async () => {
|
||||
const gameModel: GameModel = new GameModel("GameModel");
|
||||
|
||||
let scriptAccount =gameModel.addScriptAccount("ScriptAccount");
|
||||
let scriptAccount =gameModel.createScriptAccount("ScriptAccount");
|
||||
expect(scriptAccount).toBeDefined();
|
||||
expect(gameModel.scriptAccounts.length).toEqual(1);
|
||||
expect(gameModel.scriptAccounts.includes(scriptAccount)).toBeTruthy();
|
||||
|
||||
//Test adding scriptAccount with already existing name
|
||||
const scriptAccount2 = gameModel.addScriptAccount("ScriptAccount")
|
||||
const scriptAccount2 = gameModel.createScriptAccount("ScriptAccount")
|
||||
expect(scriptAccount2).toBeUndefined();
|
||||
expect(gameModel.scriptAccounts.length).toEqual(1);
|
||||
|
||||
//Test for adding invalid names as scriptaccount names (null/undefined/empty)
|
||||
let result = gameModel.addScriptAccount(null);
|
||||
let result = gameModel.createScriptAccount(null);
|
||||
expect(result).toBeUndefined();
|
||||
expect(gameModel.scriptAccounts.length).toEqual(1);
|
||||
result = gameModel.addScriptAccount(undefined);
|
||||
result = gameModel.createScriptAccount(undefined);
|
||||
expect(result).toBeUndefined();
|
||||
expect(gameModel.scriptAccounts.length).toEqual(1);
|
||||
result = gameModel.addScriptAccount("");
|
||||
result = gameModel.createScriptAccount("");
|
||||
expect(result).toBeUndefined();
|
||||
expect(gameModel.scriptAccounts.length).toEqual(1);
|
||||
})
|
||||
@ -50,7 +50,7 @@ test.describe('Test ScriptAccounts', () => {
|
||||
gameModel.removeScriptAccount(scriptAccount);
|
||||
expect(gameModel.scriptAccounts.length).toEqual(0);
|
||||
|
||||
scriptAccount = gameModel.addScriptAccount("ScriptAccount");
|
||||
scriptAccount = gameModel.createScriptAccount("ScriptAccount");
|
||||
gameModel.removeScriptAccount(scriptAccount);
|
||||
expect(gameModel.scriptAccounts.length).toEqual(0);
|
||||
|
||||
@ -60,8 +60,8 @@ test.describe('Test ScriptAccounts', () => {
|
||||
gameModel.removeScriptAccount(null);
|
||||
expect(gameModel.scriptAccounts.length).toEqual(0);
|
||||
|
||||
scriptAccount = gameModel.addScriptAccount(scriptAccount);
|
||||
let scriptAccount2 = gameModel.addScriptAccount("ScriptAccount 2");
|
||||
scriptAccount = gameModel.createScriptAccount(scriptAccount);
|
||||
let scriptAccount2 = gameModel.createScriptAccount("ScriptAccount 2");
|
||||
|
||||
gameModel.removeScriptAccount(scriptAccount);
|
||||
expect(gameModel.scriptAccounts.length).toEqual(1);
|
||||
|
@ -2,6 +2,8 @@
|
||||
<div class="full-height-container">
|
||||
<button mat-icon-button class="small-icon-button" [ngClass]="openContent === ModelComponentType.SCRIPTACCOUNT ? 'selected':''"
|
||||
(click)="openScriptAccountsOverview()"><mat-icon>inventory_2</mat-icon></button>
|
||||
<button mat-icon-button class="small-icon-button" [ngClass]="openContent === ModelComponentType.GAMESYTEM ? 'selected':''"
|
||||
(click)="openGamesystemsOverview()"><mat-icon>manufacturing</mat-icon></button>
|
||||
</div>
|
||||
|
||||
|
||||
@ -17,13 +19,15 @@
|
||||
<button mat-icon-button class="small-icon-button close-sidenav-btn" (click)="closeContentOverview()"><mat-icon>close</mat-icon></button>
|
||||
<mat-menu #contentMenu="matMenu">
|
||||
<button mat-menu-item (click)="openScriptAccountsOverview()">{{ModelComponentTypeUtillities.toString(ModelComponentType.SCRIPTACCOUNT)}}</button>
|
||||
<button mat-menu-item (click)="openGamesystemsOverview()">{{ModelComponentTypeUtillities.toString(ModelComponentType.GAMESYTEM)}}</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
<app-script-account-overview #scriptAccountOverview [gameModel]="gameModel" (onOpenScriptAccount)="openModelComponent($event)"></app-script-account-overview>
|
||||
<app-script-account-overview *ngIf="openContent == ModelComponentType.SCRIPTACCOUNT" #scriptAccountOverview [gameModel]="gameModel" (onOpenScriptAccount)="openModelComponent($event)"></app-script-account-overview>
|
||||
<app-gamescript-overview *ngIf="openContent == ModelComponentType.GAMESYTEM" #gamesystemOverview [gameModel]="gameModel" (openGamesystemEditor)="openModelComponent($event)"></app-gamescript-overview>
|
||||
</mat-drawer>
|
||||
|
||||
<div class="example-sidenav-content">
|
||||
<app-editor #editor></app-editor>
|
||||
<app-editor #editor (onModelNameUpdate)="onModelNameUpdate()"></app-editor>
|
||||
</div>
|
||||
|
||||
</mat-drawer-container>
|
||||
|
@ -13,6 +13,8 @@ import {
|
||||
import {MatDialog} from "@angular/material/dialog";
|
||||
import {DeleteConfirmationDialogComponent} from "./delete-confirmation-dialog/delete-confirmation-dialog.component";
|
||||
import {ScriptAccount} from "./game-model/scriptAccounts/ScriptAccount";
|
||||
import {GamescriptOverviewComponent} from "./side-overviews/gamescript-overview/gamescript-overview.component";
|
||||
import {SimpleGamesystem} from "./game-model/gamesystems/SimpleGamesystem";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
@ -25,6 +27,7 @@ export class AppComponent implements OnInit{
|
||||
@ViewChild('drawer') drawer: MatDrawerContainer|undefined
|
||||
@ViewChild('editor') editor: EditorComponent|undefined
|
||||
@ViewChild('scriptAccountOverview') scriptAccountOverview: ScriptAccountOverviewComponent | undefined
|
||||
@ViewChild('gamesystemOverview') gamesystemOverview: GamescriptOverviewComponent | undefined
|
||||
|
||||
gameModel: GameModel | undefined
|
||||
|
||||
@ -42,29 +45,89 @@ export class AppComponent implements OnInit{
|
||||
|
||||
electronService.ipcRenderer.on('context-menu', (event: any, message: string) => {
|
||||
this.zone.run(() => {
|
||||
if(message == "edit") {
|
||||
if(this.openContent == ModelComponentType.SCRIPTACCOUNT && this.scriptAccountOverview != undefined && this.scriptAccountOverview.selectedScriptAccount != undefined) {
|
||||
this.editor!.openGameModelComponent(this.scriptAccountOverview.selectedScriptAccount!);
|
||||
}
|
||||
} else if(message == "delete") {
|
||||
const affectedModelComponent = this.getSelectedModelComponent();
|
||||
const dialogRef = this.dialog.open(DeleteConfirmationDialogComponent, {data: affectedModelComponent, minWidth: "400px"});
|
||||
|
||||
dialogRef.afterClosed().subscribe(res => {
|
||||
if(res != undefined && res) {
|
||||
if(affectedModelComponent instanceof ScriptAccount) {
|
||||
this.gameModel!.removeScriptAccount(affectedModelComponent);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
this.onContextMenuMessageRecieved(message);
|
||||
});
|
||||
})
|
||||
} else {
|
||||
console.log('Run in browser');
|
||||
}
|
||||
}
|
||||
|
||||
onContextMenuMessageRecieved(message: string) {
|
||||
if(message == "edit") {
|
||||
this.onEditModelComponent();
|
||||
} else if(message == "delete") {
|
||||
this.onDeleteModelComponent();
|
||||
} else if(message.startsWith("new")) {
|
||||
const splittedMessage = message.split("-");
|
||||
const modelComponentType = ModelComponentTypeUtillities.fromString(splittedMessage[1]);
|
||||
if(modelComponentType != undefined) {
|
||||
this.onCreateModelComponent(modelComponentType);
|
||||
} else {
|
||||
console.log("[ERROR] [App-Component] Unknown Context-Menu Command!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onEditModelComponent() {
|
||||
switch (this.openContent!) {
|
||||
case ModelComponentType.SCRIPTACCOUNT: {
|
||||
if(this.scriptAccountOverview!.selectedScriptAccount != undefined) {
|
||||
this.editor!.openGameModelComponent(this.scriptAccountOverview!.selectedScriptAccount);
|
||||
}
|
||||
} break;
|
||||
case ModelComponentType.GAMESYTEM: {
|
||||
if(this.gamesystemOverview!.selectedGamesystem != undefined) {
|
||||
const gamesystem = this.gameModel!.findGamesystem(this.gamesystemOverview!.selectedGamesystemName!);
|
||||
this.editor!.openGameModelComponent(gamesystem!);
|
||||
}
|
||||
} break
|
||||
}
|
||||
}
|
||||
|
||||
private onDeleteModelComponent() {
|
||||
const affectedModelComponent = this.getSelectedModelComponent();
|
||||
const dialogRef = this.dialog.open(DeleteConfirmationDialogComponent, {data: affectedModelComponent, minWidth: "400px"});
|
||||
|
||||
dialogRef.afterClosed().subscribe(res => {
|
||||
if(res != undefined && res) {
|
||||
if(affectedModelComponent instanceof ScriptAccount) {
|
||||
this.gameModel!.removeScriptAccount(affectedModelComponent);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private onCreateModelComponent(modelComponentType: ModelComponentType) {
|
||||
switch (modelComponentType) {
|
||||
case ModelComponentType.SCRIPTACCOUNT: this.onCreateNewScriptAccount(); break
|
||||
case ModelComponentType.GAMESYTEM: this.onCreateNewGamesystem(); break
|
||||
}
|
||||
}
|
||||
|
||||
private onCreateNewScriptAccount() {
|
||||
const createdScriptAccount = this.gameModel!.createScriptAccount("New ScriptAccount");
|
||||
if(createdScriptAccount != undefined) {
|
||||
this.editor?.openGameModelComponent(createdScriptAccount);
|
||||
} else {
|
||||
console.log("[DEBUG] [App-Component] ScriptAccount could not be created (Name not unique)");
|
||||
}
|
||||
}
|
||||
|
||||
private onCreateNewGamesystem() {
|
||||
let parentGamesystemName = undefined
|
||||
if(this.openContent != ModelComponentType.GAMESYTEM) {
|
||||
this.openGamesystemsOverview();
|
||||
} else {
|
||||
parentGamesystemName = this.gamesystemOverview!.selectedGamesystemName;
|
||||
}
|
||||
const createdGamesystem = this.gameModel!.createGamesystem("New Gamesystem", parentGamesystemName);
|
||||
if(createdGamesystem != undefined) {
|
||||
this.gamesystemOverview!.refresh();
|
||||
this.editor?.openGameModelComponent(createdGamesystem!);
|
||||
}
|
||||
}
|
||||
|
||||
private getSelectedModelComponent(): ModelComponent | undefined {
|
||||
if(this.openContent == ModelComponentType.SCRIPTACCOUNT) {
|
||||
if(this.scriptAccountOverview != undefined) {
|
||||
@ -78,8 +141,19 @@ export class AppComponent implements OnInit{
|
||||
|
||||
ngOnInit() {
|
||||
this.gameModel = new GameModel("No More");
|
||||
this.gameModel.addScriptAccount("Temperature");
|
||||
this.gameModel.addScriptAccount("Luftfeuchtigkeit");
|
||||
this.gameModel.createScriptAccount("Temperature");
|
||||
this.gameModel.createScriptAccount("Luftfeuchtigkeit");
|
||||
|
||||
const weather = new SimpleGamesystem("Weather");
|
||||
const season = new SimpleGamesystem("Season");
|
||||
|
||||
const springState = season.createState("Spring", "Spring, also known as springtime, is one of the four temperate seasons, succeeding winter and preceding summer.");
|
||||
const summerState = season.createState("Summer", "Summer is the hottest and brightest of the four temperate seasons, occurring after spring and before autumn. ");
|
||||
|
||||
season.createTransition(springState!, summerState!);
|
||||
|
||||
this.gameModel.addGamesystem(weather)
|
||||
this.gameModel.addGamesystem(season);
|
||||
}
|
||||
|
||||
openScriptAccountsOverview() {
|
||||
@ -87,6 +161,11 @@ export class AppComponent implements OnInit{
|
||||
this.drawer!.open();
|
||||
}
|
||||
|
||||
openGamesystemsOverview() {
|
||||
this.openContent = ModelComponentType.GAMESYTEM;
|
||||
this.drawer!.open();
|
||||
}
|
||||
|
||||
protected readonly ModelComponentType = ModelComponentType;
|
||||
|
||||
closeContentOverview() {
|
||||
@ -102,6 +181,11 @@ export class AppComponent implements OnInit{
|
||||
} else {
|
||||
console.log("[WARN] [App.Component] Editor is undefined")
|
||||
}
|
||||
}
|
||||
|
||||
onModelNameUpdate() {
|
||||
if(this.openContent == ModelComponentType.GAMESYTEM) {
|
||||
this.gamesystemOverview!.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import {MatIcon} from "@angular/material/icon";
|
||||
import {MatToolbar} from "@angular/material/toolbar";
|
||||
import {MatButton, MatIconButton, MatMiniFabButton} from "@angular/material/button";
|
||||
import {MatError, MatFormField, MatLabel} from "@angular/material/form-field";
|
||||
import {MatError, MatFormField, MatHint, MatLabel} from "@angular/material/form-field";
|
||||
import {MatInput} from "@angular/material/input";
|
||||
import {MatDrawer, MatDrawerContainer} from "@angular/material/sidenav";
|
||||
import {MatMenu, MatMenuItem, MatMenuTrigger} from "@angular/material/menu";
|
||||
@ -28,6 +28,29 @@ import {ScriptAccountEditorComponent} from "./editor/script-account-editor/scrip
|
||||
import {ModelComponentEditorComponent} from "./editor/model-component-editor/model-component-editor.component";
|
||||
import {DeleteConfirmationDialogComponent} from "./delete-confirmation-dialog/delete-confirmation-dialog.component";
|
||||
import {MatDialogActions, MatDialogContent, MatDialogTitle} from "@angular/material/dialog";
|
||||
import {GamescriptOverviewComponent} from "./side-overviews/gamescript-overview/gamescript-overview.component";
|
||||
import {MatTree, MatTreeModule} from "@angular/material/tree";
|
||||
import {GamesystemEditorComponent} from "./editor/gamesystem-editor/gamesystem-editor.component";
|
||||
import {
|
||||
SimpleGamesystemEditorComponent
|
||||
} from "./editor/gamesystem-editor/simple-gamesystem-editor/simple-gamesystem-editor.component";
|
||||
import {
|
||||
SimpleStateEditorComponent
|
||||
} from "./editor/gamesystem-editor/state-editor/simple-state-editor/simple-state-editor.component";
|
||||
import {
|
||||
MatCell,
|
||||
MatCellDef,
|
||||
MatColumnDef,
|
||||
MatHeaderCell,
|
||||
MatHeaderCellDef,
|
||||
MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef,
|
||||
MatTable
|
||||
} from "@angular/material/table";
|
||||
import {MatCheckbox} from "@angular/material/checkbox";
|
||||
import {
|
||||
SimpleTransitionEditorComponent
|
||||
} from "./editor/gamesystem-editor/transition-editor/simple-transition-editor/simple-transition-editor.component";
|
||||
import {MatOption, MatSelect} from "@angular/material/select";
|
||||
|
||||
// AoT requires an exported function for factories
|
||||
const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
||||
@ -39,7 +62,12 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new Transl
|
||||
EditorComponent,
|
||||
ScriptAccountEditorComponent,
|
||||
ModelComponentEditorComponent,
|
||||
DeleteConfirmationDialogComponent
|
||||
DeleteConfirmationDialogComponent,
|
||||
GamescriptOverviewComponent,
|
||||
GamesystemEditorComponent,
|
||||
SimpleGamesystemEditorComponent,
|
||||
SimpleStateEditorComponent,
|
||||
SimpleTransitionEditorComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
@ -79,6 +107,21 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new Transl
|
||||
MatDialogContent,
|
||||
MatDialogActions,
|
||||
MatMiniFabButton,
|
||||
MatTreeModule,
|
||||
MatTable,
|
||||
MatColumnDef,
|
||||
MatHeaderCell,
|
||||
MatHeaderCellDef,
|
||||
MatCellDef,
|
||||
MatCell,
|
||||
MatHeaderRow,
|
||||
MatRow,
|
||||
MatHeaderRowDef,
|
||||
MatRowDef,
|
||||
MatCheckbox,
|
||||
MatSelect,
|
||||
MatOption,
|
||||
MatHint
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
|
@ -1,13 +1,17 @@
|
||||
<mat-tab-group>
|
||||
<mat-tab *ngFor="let modelComponent of gameModelComponents">
|
||||
<ng-template mat-tab-label>
|
||||
<mat-icon class="example-tab-icon unsaved" [ngClass]="modelComponent.unsaved? 'unsaved':'saved'">inventory_2</mat-icon>
|
||||
<mat-icon class="example-tab-icon unsaved" *ngIf="modelComponent.type === ModelComponentType.SCRIPTACCOUNT" [ngClass]="modelComponent.unsaved? 'unsaved':'saved'">inventory_2</mat-icon>
|
||||
<mat-icon class="example-tab-icon unsaved" *ngIf="modelComponent.type === ModelComponentType.GAMESYTEM" [ngClass]="modelComponent.unsaved? 'unsaved':'saved'">code</mat-icon>
|
||||
|
||||
<span [ngClass]="modelComponent.unsaved? 'unsaved':'saved'">{{modelComponent.componentName}}</span>
|
||||
<button class="content-label close-btn" mat-icon-button (click)="closeGameModelComponent(modelComponent)"><mat-icon>close</mat-icon></button>
|
||||
</ng-template>
|
||||
<app-model-component-editor [modelComponent]="modelComponent"></app-model-component-editor>
|
||||
<app-model-component-editor [modelComponent]="modelComponent" (onModelNameUpdated)="onModelNameUpdate()"></app-model-component-editor>
|
||||
<app-script-account-editor *ngIf="modelComponent.type === ModelComponentType.SCRIPTACCOUNT"
|
||||
[scriptAccount]="convertModelComponentToScriptAccount(modelComponent)"></app-script-account-editor>
|
||||
<app-gamesystem-editor *ngIf="modelComponent.type == ModelComponentType.GAMESYTEM"
|
||||
[gamesystem]="convertModelComponentToGamesystem(modelComponent)"></app-gamesystem-editor>
|
||||
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
|
@ -1,8 +1,11 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
||||
import {GameModel} from "../game-model/GameModel";
|
||||
import {ModelComponent} from "../game-model/ModelComponent";
|
||||
import {ModelComponentType} from "../game-model/ModelComponentType";
|
||||
import {ScriptAccount} from "../game-model/scriptAccounts/ScriptAccount";
|
||||
import {Gamesystem} from "../game-model/gamesystems/Gamesystem";
|
||||
import {State} from "../game-model/gamesystems/State";
|
||||
import {Transition} from "../game-model/gamesystems/Transition";
|
||||
|
||||
@Component({
|
||||
selector: 'app-editor',
|
||||
@ -11,6 +14,7 @@ import {ScriptAccount} from "../game-model/scriptAccounts/ScriptAccount";
|
||||
})
|
||||
export class EditorComponent {
|
||||
gameModelComponents: ModelComponent[] = [];
|
||||
@Output("onModelNameUpdate") onModelNameUpdateEmitter = new EventEmitter<boolean>();
|
||||
|
||||
openGameModelComponent(gameModelComponent: ModelComponent) {
|
||||
if(!this.gameModelComponents.includes(gameModelComponent)) {
|
||||
@ -28,5 +32,15 @@ export class EditorComponent {
|
||||
}
|
||||
}
|
||||
|
||||
convertModelComponentToGamesystem(modelComponent: ModelComponent) {
|
||||
if(modelComponent instanceof Gamesystem) {
|
||||
return modelComponent as Gamesystem<State<any>, Transition<any>>;
|
||||
}
|
||||
}
|
||||
|
||||
protected readonly ModelComponentType = ModelComponentType;
|
||||
|
||||
onModelNameUpdate() {
|
||||
this.onModelNameUpdateEmitter.emit(true);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
<app-simple-gamesystem-editor *ngIf="isSimpleGamesystem()" [simpleGamesystem]="convertGamesystemToSimpleGamesystem()"></app-simple-gamesystem-editor>
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GamesystemEditorComponent } from './gamesystem-editor.component';
|
||||
|
||||
describe('GamesystemEditorComponent', () => {
|
||||
let component: GamesystemEditorComponent;
|
||||
let fixture: ComponentFixture<GamesystemEditorComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [GamesystemEditorComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GamesystemEditorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,33 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {GameModel} from "../../game-model/GameModel";
|
||||
import {Gamesystem} from "../../game-model/gamesystems/Gamesystem";
|
||||
import {State} from "../../game-model/gamesystems/State";
|
||||
import {Transition} from "../../game-model/gamesystems/Transition";
|
||||
import {SimpleGamesystem} from "../../game-model/gamesystems/SimpleGamesystem";
|
||||
import {ProductGamesystem} from "../../game-model/gamesystems/ProductGamesystem";
|
||||
|
||||
@Component({
|
||||
selector: 'app-gamesystem-editor',
|
||||
templateUrl: './gamesystem-editor.component.html',
|
||||
styleUrl: './gamesystem-editor.component.scss'
|
||||
})
|
||||
export class GamesystemEditorComponent {
|
||||
|
||||
@Input() gamesystem: Gamesystem<State<any>, Transition<any>> | undefined
|
||||
|
||||
isSimpleGamesystem() {
|
||||
return this.gamesystem instanceof SimpleGamesystem;
|
||||
}
|
||||
|
||||
convertGamesystemToSimpleGamesystem() {
|
||||
if(this.gamesystem instanceof SimpleGamesystem) {
|
||||
return this.gamesystem as SimpleGamesystem;
|
||||
}
|
||||
}
|
||||
|
||||
convertGamesystemToProductGamesystem() {
|
||||
if(this.gamesystem instanceof ProductGamesystem) {
|
||||
return this.gamesystem as ProductGamesystem;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
<app-simple-state-editor [states]="simpleGamesystem!.states" [gamesystem]="simpleGamesystem"></app-simple-state-editor>
|
||||
<app-simple-transition-editor class="transition-editor" [gamesystem]="simpleGamesystem"></app-simple-transition-editor>
|
@ -0,0 +1,3 @@
|
||||
.transition-editor {
|
||||
margin-top: 15px;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SimpleGamesystemEditorComponent } from './simple-gamesystem-editor.component';
|
||||
|
||||
describe('SimpleGamesystemEditorComponent', () => {
|
||||
let component: SimpleGamesystemEditorComponent;
|
||||
let fixture: ComponentFixture<SimpleGamesystemEditorComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [SimpleGamesystemEditorComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SimpleGamesystemEditorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,16 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {SimpleGamesystem} from "../../../game-model/gamesystems/SimpleGamesystem";
|
||||
import {MatTableDataSource} from "@angular/material/table";
|
||||
|
||||
@Component({
|
||||
selector: 'app-simple-gamesystem-editor',
|
||||
templateUrl: './simple-gamesystem-editor.component.html',
|
||||
styleUrl: './simple-gamesystem-editor.component.scss'
|
||||
})
|
||||
export class SimpleGamesystemEditorComponent {
|
||||
|
||||
@Input() simpleGamesystem: SimpleGamesystem | undefined
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" multiTemplateDataRows>
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef>Label</th>
|
||||
<td mat-cell *matCellDef="let state">
|
||||
<span *ngIf="editedElement !== state"> {{state.stateLabel}}</span>
|
||||
<mat-form-field appearance="fill" class="long-form" *ngIf="editedElement === state">
|
||||
<input matInput [(ngModel)]="state.stateLabel" (ngModelChange)="onStateChange()">
|
||||
<mat-hint class="mat-error" *ngIf="editedStateLabelError"><mat-icon class="warning-icon">warning</mat-icon>Missing State-Label Information</mat-hint>
|
||||
</mat-form-field>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
|
||||
<ng-container matColumnDef="expandedDetail">
|
||||
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length">
|
||||
<div class="example-element-detail" [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
|
||||
<p *ngIf="editedElement !== element">{{element.stateDescription}}</p>
|
||||
<mat-form-field appearance="fill" class="long-form" *ngIf="element === editedElement">
|
||||
<mat-label>Description</mat-label>
|
||||
<textarea matInput [(ngModel)]="element.stateDescription" rows="3" (ngModelChange)="onStateChange()"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
|
||||
<ng-container matColumnDef="initial">
|
||||
<th mat-header-cell *matHeaderCellDef>Initial</th>
|
||||
<td mat-cell *matCellDef="let state">
|
||||
<div *ngIf="editedElement !== state">
|
||||
<mat-icon *ngIf="state.initial">done</mat-icon>
|
||||
<mat-icon *ngIf="!state.initial">close</mat-icon>
|
||||
</div>
|
||||
<mat-checkbox *ngIf="editedElement === state" [(ngModel)]="state.initial" (ngModelChange)="onStateChange()"></mat-checkbox>
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="edit">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let state">
|
||||
<button mat-icon-button color="primary" *ngIf="editedElement !== state" (click)="editState(state)" [disabled]="editedElement !== null"><mat-icon>edit</mat-icon></button>
|
||||
<button mat-icon-button color="primary" (click)="finishEditing()" *ngIf="editedElement === state"><mat-icon>done</mat-icon></button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="delete">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let state">
|
||||
<button mat-icon-button color="warn" (click)="deleteState(state)"><mat-icon>delete</mat-icon></button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="expand">
|
||||
<th mat-header-cell *matHeaderCellDef aria-label="row actions">
|
||||
<button mat-icon-button (click)="addState()"><mat-icon>add</mat-icon></button>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<button mat-icon-button aria-label="expand row" (click)="(expandedElement = expandedElement === element ? null : element); $event.stopPropagation()">
|
||||
@if (expandedElement === element) {
|
||||
<mat-icon>keyboard_arrow_up</mat-icon>
|
||||
} @else {
|
||||
<mat-icon>keyboard_arrow_down</mat-icon>
|
||||
}
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr>
|
||||
<tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;"
|
||||
class="example-element-row"
|
||||
[class.example-expanded-row]="expandedElement === element"
|
||||
(click)="expandedElement = expandedElement === element ? null : element">
|
||||
</tr>
|
||||
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
|
||||
</table>
|
@ -0,0 +1,63 @@
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
tr.example-detail-row {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
tr.example-element-row:not(.example-expanded-row):hover {
|
||||
background: #545456
|
||||
}
|
||||
|
||||
tr.example-element-row:not(.example-expanded-row):active {
|
||||
background: #545456;
|
||||
}
|
||||
|
||||
.example-element-row td {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
.example-element-detail {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.example-element-diagram {
|
||||
min-width: 80px;
|
||||
border: 2px solid black;
|
||||
padding: 8px;
|
||||
font-weight: lighter;
|
||||
margin: 8px 0;
|
||||
height: 104px;
|
||||
}
|
||||
|
||||
.example-element-symbol {
|
||||
font-weight: bold;
|
||||
font-size: 40px;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.example-element-description {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.example-element-description-attribution {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.mat-column-edit, .mat-column-delete, .mat-column-expand {
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.long-form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mat-error {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.warning-icon {
|
||||
margin-right: 5px;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SimpleStateEditorComponent } from './simple-state-editor.component';
|
||||
|
||||
describe('SimpleStateEditorComponent', () => {
|
||||
let component: SimpleStateEditorComponent;
|
||||
let fixture: ComponentFixture<SimpleStateEditorComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [SimpleStateEditorComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SimpleStateEditorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,86 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {SimpleState} from "../../../../game-model/gamesystems/SimpleState";
|
||||
import {MatTableDataSource} from "@angular/material/table";
|
||||
import {animate, state, style, transition, trigger} from "@angular/animations";
|
||||
import {MatSnackBar} from "@angular/material/snack-bar";
|
||||
import {SimpleGamesystem} from "../../../../game-model/gamesystems/SimpleGamesystem";
|
||||
|
||||
@Component({
|
||||
selector: 'app-simple-state-editor',
|
||||
templateUrl: './simple-state-editor.component.html',
|
||||
styleUrl: './simple-state-editor.component.scss',
|
||||
animations: [
|
||||
trigger('detailExpand', [
|
||||
state('collapsed,void', style({height: '0px', minHeight: '0'})),
|
||||
state('expanded', style({height: '*'})),
|
||||
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class SimpleStateEditorComponent implements OnInit{
|
||||
|
||||
@Input() states: SimpleState[] = [];
|
||||
@Input() gamesystem: SimpleGamesystem | undefined
|
||||
dataSource = new MatTableDataSource();
|
||||
displayedColumns = ["name", "initial", "edit", "delete"];
|
||||
columnsToDisplayWithExpand = [...this.displayedColumns, 'expand'];
|
||||
expandedElement: SimpleState | null = null;
|
||||
editedElement: SimpleState | null = null;
|
||||
|
||||
editedStateLabelError: boolean = false;
|
||||
|
||||
constructor(private snackbar: MatSnackBar) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.dataSource.data = this.states;
|
||||
}
|
||||
|
||||
editState(state: SimpleState) {
|
||||
if(this.editedElement === state) {
|
||||
this.editedElement = null;
|
||||
} else {
|
||||
this.editedElement = state;
|
||||
}
|
||||
}
|
||||
|
||||
finishEditing() {
|
||||
if(this.isEditedStateValid()) {
|
||||
this.editedElement = null;
|
||||
}
|
||||
}
|
||||
|
||||
isEditedStateValid(): boolean {
|
||||
if(this.editedElement!.stateLabel.length > 0) {
|
||||
this.editedStateLabelError = false;
|
||||
return true;
|
||||
} else {
|
||||
this.editedStateLabelError = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
deleteState(state: SimpleState) {
|
||||
if(this.gamesystem == undefined || this.gamesystem.parentGamesystem == undefined) {
|
||||
this.gamesystem?.removeState(state);
|
||||
this.dataSource.data = this.gamesystem!.states
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
addState() {
|
||||
if(this.gamesystem != undefined) {
|
||||
const simpleState = this.gamesystem.createState("New State", "");
|
||||
if(simpleState != undefined) {
|
||||
this.dataSource.data = this.gamesystem.states;
|
||||
this.editedElement = simpleState;
|
||||
this.expandedElement = simpleState;
|
||||
this.onStateChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
onStateChange() {
|
||||
this.gamesystem!.onModifyContent();
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" multiTemplateDataRows>
|
||||
<ng-container matColumnDef="starting-state">
|
||||
<th mat-header-cell *matHeaderCellDef>Starting State</th>
|
||||
<td mat-cell *matCellDef="let transition">
|
||||
<span *ngIf="editedTransition !== transition">{{transition.startingState.stateLabel}}</span>
|
||||
<mat-form-field appearance="fill" class="long-form" *ngIf="editedTransition == transition">
|
||||
<mat-select [(ngModel)]="editedTransition!.startingState" (ngModelChange)="validateEditedTransition()">
|
||||
<mat-option *ngFor="let state of gamesystem!.states" [value]="state"
|
||||
(onSelectionChange)="validateEditedTransition()">{{state.stateLabel}}</mat-option>
|
||||
</mat-select>
|
||||
<mat-hint class="mat-error" *ngIf="transitionError"><mat-icon class="warning-icon">warning</mat-icon> Starting and Ending State cannot be the same!</mat-hint>
|
||||
<mat-hint class="mat-error" *ngIf="!transitionError && transitionStartingStateError"><mat-icon class="warning-icon">warning</mat-icon> Select a valid Starting State!</mat-hint>
|
||||
</mat-form-field>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="ending-state">
|
||||
<th mat-header-cell *matHeaderCellDef>Ending State</th>
|
||||
<td mat-cell *matCellDef="let transition">
|
||||
<span *ngIf="editedTransition !== transition">{{transition.endingState.stateLabel}}</span>
|
||||
<mat-form-field appearance="fill" class="long-form" *ngIf="editedTransition == transition">
|
||||
<mat-select [(ngModel)]="editedTransition!.endingState" (ngModelChange)="validateEditedTransition()">
|
||||
<mat-option *ngFor="let state of gamesystem!.states" [value]="state"
|
||||
(onSelectionChange)="validateEditedTransition()">{{state.stateLabel}}</mat-option>
|
||||
</mat-select>
|
||||
<mat-hint class="mat-error" *ngIf="transitionError"><mat-icon class="warning-icon">warning</mat-icon> Starting and Ending State cannot be the same!</mat-hint>
|
||||
<mat-hint class="mat-error" *ngIf="!transitionError && transitionEndingStateError"> <mat-icon class="warning-icon">warning</mat-icon> Select a valid Ending State!</mat-hint>
|
||||
</mat-form-field>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="expandedDetail">
|
||||
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length">
|
||||
<div class="example-element-detail"
|
||||
[@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
|
||||
<p>Expanded Detail</p>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="edit">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let transition">
|
||||
<button mat-icon-button color="primary" *ngIf="editedTransition !== transition" [disabled]="editedTransition != undefined"><mat-icon>edit</mat-icon></button>
|
||||
<button mat-icon-button color="primary" *ngIf="editedTransition === transition"
|
||||
[disabled]="transitionError || transitionStartingStateError || transitionEndingStateError" (click)="finishEditing()"
|
||||
><mat-icon>done</mat-icon></button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="delete">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let transition">
|
||||
<button mat-icon-button color="warn" (click)="deleteTransition(transition)"><mat-icon>delete</mat-icon></button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="expand">
|
||||
<th mat-header-cell *matHeaderCellDef aria-label="row actions">
|
||||
<button mat-icon-button (click)="addTransition()" [disabled]="editedTransition != undefined"><mat-icon>add</mat-icon></button>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<button mat-icon-button aria-label="expand row" (click)="(expandedElement = expandedElement === element ? null : element); $event.stopPropagation()">
|
||||
@if (expandedElement === element) {
|
||||
<mat-icon>keyboard_arrow_up</mat-icon>
|
||||
} @else {
|
||||
<mat-icon>keyboard_arrow_down</mat-icon>
|
||||
}
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr>
|
||||
<tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;"
|
||||
class="example-element-row"
|
||||
[class.example-expanded-row]="expandedElement === element"
|
||||
(click)="expandedElement = expandedElement === element ? null : element">
|
||||
</tr>
|
||||
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
|
||||
</table>
|
@ -0,0 +1,63 @@
|
||||
table {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.mat-column-edit, .mat-column-delete, .mat-column-expand {
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
tr.example-detail-row {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
tr.example-element-row:not(.example-expanded-row):hover {
|
||||
background: #545456;
|
||||
}
|
||||
|
||||
tr.example-element-row:not(.example-expanded-row):active {
|
||||
background: #545456;
|
||||
}
|
||||
|
||||
.example-element-row td {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
.example-element-detail {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.example-element-diagram {
|
||||
min-width: 80px;
|
||||
border: 2px solid black;
|
||||
padding: 8px;
|
||||
font-weight: lighter;
|
||||
margin: 8px 0;
|
||||
height: 104px;
|
||||
}
|
||||
|
||||
.example-element-symbol {
|
||||
font-weight: bold;
|
||||
font-size: 40px;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.example-element-description {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.example-element-description-attribution {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.long-form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.warning-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.mat-error {
|
||||
color: red;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SimpleTransitionEditorComponent } from './simple-transition-editor.component';
|
||||
|
||||
describe('SimpleTransitionEditorComponent', () => {
|
||||
let component: SimpleTransitionEditorComponent;
|
||||
let fixture: ComponentFixture<SimpleTransitionEditorComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [SimpleTransitionEditorComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SimpleTransitionEditorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,86 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {GameModel} from "../../../../game-model/GameModel";
|
||||
import {SimpleGamesystem} from "../../../../game-model/gamesystems/SimpleGamesystem";
|
||||
import {
|
||||
MatCell,
|
||||
MatCellDef,
|
||||
MatColumnDef,
|
||||
MatHeaderCell,
|
||||
MatHeaderCellDef, MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef,
|
||||
MatTable,
|
||||
MatTableDataSource
|
||||
} from "@angular/material/table";
|
||||
import {SimpleTransition} from "../../../../game-model/gamesystems/SimpleTransition";
|
||||
import {animate, state, style, transition, trigger} from "@angular/animations";
|
||||
import {SimpleState} from "../../../../game-model/gamesystems/SimpleState";
|
||||
|
||||
@Component({
|
||||
selector: 'app-simple-transition-editor',
|
||||
templateUrl: './simple-transition-editor.component.html',
|
||||
styleUrl: './simple-transition-editor.component.scss',
|
||||
animations: [
|
||||
trigger('detailExpand', [
|
||||
state('collapsed,void', style({height: '0px', minHeight: '0'})),
|
||||
state('expanded', style({height: '*'})),
|
||||
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
|
||||
]),
|
||||
],
|
||||
})
|
||||
export class SimpleTransitionEditorComponent implements OnInit {
|
||||
|
||||
@Input() gamesystem: SimpleGamesystem | undefined
|
||||
displayedColumns: string[] = ["starting-state", "ending-state", "edit", "delete"];
|
||||
dataSource = new MatTableDataSource<SimpleTransition>();
|
||||
columnsToDisplayWithExpand = [...this.displayedColumns, 'expand'];
|
||||
expandedElement: SimpleTransition | null = null;
|
||||
editedTransition: SimpleTransition | undefined
|
||||
editedTransitionIndex = -1;
|
||||
|
||||
defaultStartingState: SimpleState = new SimpleState("None", "");
|
||||
defaultEndingState: SimpleState = new SimpleState("None", "");
|
||||
|
||||
transitionError: boolean = false;
|
||||
transitionStartingStateError = true;
|
||||
transitionEndingStateError = true;
|
||||
ngOnInit() {
|
||||
this.dataSource.data = this.gamesystem!.transitions;
|
||||
}
|
||||
|
||||
addTransition() {
|
||||
this.editedTransition = new SimpleTransition(this.defaultStartingState, this.defaultEndingState);
|
||||
const updatedData = this.dataSource.data;
|
||||
updatedData.push(this.editedTransition);
|
||||
this.dataSource.data = updatedData;
|
||||
this.editedTransitionIndex = this.dataSource.data.length;
|
||||
}
|
||||
|
||||
validateEditedTransition() {
|
||||
this.transitionError = false;
|
||||
this.transitionStartingStateError = false;
|
||||
this.transitionEndingStateError = false;
|
||||
if(this.editedTransition!.startingState === this.editedTransition!.endingState) {
|
||||
this.transitionError = true;
|
||||
} else if(this.editedTransition!.startingState == this.defaultStartingState) {
|
||||
this.transitionStartingStateError = true;
|
||||
} else if(this.editedTransition!.endingState == this.defaultEndingState) {
|
||||
this.transitionEndingStateError = true;
|
||||
}
|
||||
}
|
||||
|
||||
finishEditing() {
|
||||
this.validateEditedTransition();
|
||||
if(this.transitionError || this.transitionStartingStateError || this.transitionEndingStateError) {
|
||||
return;
|
||||
}
|
||||
this.gamesystem?.createTransition(this.editedTransition!.startingState, this.editedTransition!.endingState);
|
||||
this.dataSource.data = this.gamesystem!.transitions;
|
||||
this.editedTransition = undefined;
|
||||
}
|
||||
|
||||
deleteTransition(transition: SimpleTransition) {
|
||||
if(this.gamesystem!.parentGamesystem == undefined) {
|
||||
this.gamesystem!.removeTransition(transition);
|
||||
this.dataSource.data = this.gamesystem!.transitions;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||
import {ModelComponent} from "../../game-model/ModelComponent";
|
||||
import {FormControl, Validators} from "@angular/forms";
|
||||
|
||||
@ -9,6 +9,7 @@ import {FormControl, Validators} from "@angular/forms";
|
||||
})
|
||||
export class ModelComponentEditorComponent implements OnInit{
|
||||
@Input('modelComponent') modelComponent: ModelComponent | undefined
|
||||
@Output("onModelNameUpdated") onModelNameUpdateEmitter = new EventEmitter<boolean>();
|
||||
|
||||
nameCtrl: FormControl = new FormControl('', [Validators.required]);
|
||||
descriptionCtrl: FormControl = new FormControl('' );
|
||||
@ -21,6 +22,7 @@ export class ModelComponentEditorComponent implements OnInit{
|
||||
onUpdateName() {
|
||||
this.modelComponent!.componentName = this.nameCtrl.value;
|
||||
this.modelComponent!.onModifyContent();
|
||||
this.onModelNameUpdateEmitter.emit(true);
|
||||
}
|
||||
|
||||
onUpdateDescription() {
|
||||
|
@ -1,10 +1,14 @@
|
||||
import {Gamesystem} from "./gamesystems/Gamesystem";
|
||||
import {ScriptAccount} from "./scriptAccounts/ScriptAccount";
|
||||
import {Transition} from "./gamesystems/Transition";
|
||||
import {State} from "./gamesystems/State";
|
||||
import {ProductGamesystem} from "./gamesystems/ProductGamesystem";
|
||||
import {SimpleGamesystem} from "./gamesystems/SimpleGamesystem";
|
||||
|
||||
export class GameModel {
|
||||
private readonly _gameModelName: string
|
||||
|
||||
private _gamesystems: Gamesystem[] = [];
|
||||
private _gamesystems: Gamesystem<any, any>[] = [];
|
||||
private _scriptAccounts: ScriptAccount[] = [];
|
||||
|
||||
constructor(gameModelName: string) {
|
||||
@ -13,26 +17,25 @@ export class GameModel {
|
||||
get gameModelName(): string {
|
||||
return this._gameModelName;
|
||||
}
|
||||
|
||||
|
||||
get gamesystems(): Gamesystem[] {
|
||||
get gamesystems(): Gamesystem<any, any>[] {
|
||||
return this._gamesystems;
|
||||
}
|
||||
get scriptAccounts(): ScriptAccount[] {
|
||||
return this._scriptAccounts;
|
||||
}
|
||||
|
||||
addGamesystem(gamesystem: Gamesystem) {
|
||||
if(!this.gamesystems.includes(gamesystem)) {
|
||||
addGamesystem(gamesystem: Gamesystem<any, any>) {
|
||||
if(this.findGamesystem(gamesystem.componentName) == undefined) {
|
||||
this._gamesystems.push(gamesystem);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
removeGamesystem(gamesystem : Gamesystem) {
|
||||
removeGamesystem(gamesystem : Gamesystem<any, any>) {
|
||||
this._gamesystems = this._gamesystems.filter(g => g !== gamesystem);
|
||||
}
|
||||
|
||||
addScriptAccount(scriptAccountName: string) {
|
||||
createScriptAccount(scriptAccountName: string) {
|
||||
if(scriptAccountName != undefined && scriptAccountName.length > 0) {
|
||||
const scriptAccount = new ScriptAccount(scriptAccountName, "");
|
||||
const searchedScriptAccount = this.scriptAccounts.find(s => s.componentName === scriptAccount.componentName);
|
||||
@ -44,10 +47,47 @@ export class GameModel {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
createGamesystem(gamesystemName: string, parentGamesystemName: string | undefined) {
|
||||
if(gamesystemName != undefined && this.findGamesystem(gamesystemName) == undefined) {
|
||||
const simpleGamesystem = new SimpleGamesystem(gamesystemName);
|
||||
if(parentGamesystemName != undefined) {
|
||||
const parentGamesystem = this.findGamesystem(parentGamesystemName);
|
||||
if(parentGamesystem instanceof SimpleGamesystem) {
|
||||
const parentProductGamesystem = ProductGamesystem.constructFromSimpleGamesystem(parentGamesystem, this);
|
||||
parentProductGamesystem.addChildGamesystem(simpleGamesystem);
|
||||
simpleGamesystem.parentGamesystem = parentProductGamesystem;
|
||||
} else {
|
||||
const productParentGamesystem = parentGamesystem as ProductGamesystem;
|
||||
productParentGamesystem.addChildGamesystem(simpleGamesystem);
|
||||
simpleGamesystem.parentGamesystem = productParentGamesystem;
|
||||
}
|
||||
} else {
|
||||
this.gamesystems.push(simpleGamesystem);
|
||||
|
||||
}
|
||||
return simpleGamesystem;
|
||||
}
|
||||
}
|
||||
|
||||
removeScriptAccount(scriptAccount: ScriptAccount) {
|
||||
if(scriptAccount != undefined) {
|
||||
this._scriptAccounts = this.scriptAccounts.filter(s => s != scriptAccount);
|
||||
}
|
||||
}
|
||||
|
||||
findGamesystem(gamesystemName: string) {
|
||||
const gamesystemQueue : Gamesystem<State<any>, Transition<any>>[] = [];
|
||||
this.gamesystems.forEach(gamesystem => gamesystemQueue.push(gamesystem));
|
||||
|
||||
while(gamesystemQueue.length > 0) {
|
||||
const currentGamesystem = gamesystemQueue.shift()!;
|
||||
if(currentGamesystem.componentName == gamesystemName) {
|
||||
return currentGamesystem;
|
||||
} else if(currentGamesystem instanceof ProductGamesystem) {
|
||||
const currentProductGamesystem = currentGamesystem as ProductGamesystem;
|
||||
currentProductGamesystem.innerGamesystems.forEach(gamesystem => gamesystemQueue.push(gamesystem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export enum ModelComponentType {
|
||||
SCRIPTACCOUNT
|
||||
|
||||
SCRIPTACCOUNT,
|
||||
GAMESYTEM
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import {ModelComponentType} from "./ModelComponentType";
|
||||
import {ModelComponent} from "./ModelComponent";
|
||||
|
||||
export class ModelComponentTypeUtillities {
|
||||
static toString(modelComponentType: ModelComponentType | undefined): string {
|
||||
switch (modelComponentType) {
|
||||
case ModelComponentType.SCRIPTACCOUNT: return "ScriptAccounts";
|
||||
case ModelComponentType.GAMESYTEM: return "Gamesystems";
|
||||
default: return "Undefined";
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,15 @@ export class ModelComponentTypeUtillities {
|
||||
static toSingleString(modelComponentType: ModelComponentType | undefined): string {
|
||||
switch (modelComponentType) {
|
||||
case ModelComponentType.SCRIPTACCOUNT: return "ScriptAccount";
|
||||
case ModelComponentType.GAMESYTEM: return "Gamesystem";
|
||||
default: return "Undefined";
|
||||
}
|
||||
}
|
||||
|
||||
static fromString(string: string) : ModelComponentType | undefined {
|
||||
switch (string) {
|
||||
case "gamesystem": return ModelComponentType.GAMESYTEM;
|
||||
case "scriptaccount": return ModelComponentType.SCRIPTACCOUNT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,35 @@
|
||||
export class Gamesystem {
|
||||
gamesystemName: string
|
||||
import {SimpleGamesystem} from "./SimpleGamesystem";
|
||||
import {ProductGamesystem} from "./ProductGamesystem";
|
||||
import {ModelComponent} from "../ModelComponent";
|
||||
import {ModelComponentType} from "../ModelComponentType";
|
||||
|
||||
export abstract class Gamesystem<S, T> extends ModelComponent{
|
||||
|
||||
states: S[] = [];
|
||||
transitions: T[] = [];
|
||||
constructor(gamesystemName: string) {
|
||||
this.gamesystemName = gamesystemName;
|
||||
super(gamesystemName, "", ModelComponentType.GAMESYTEM);
|
||||
}
|
||||
|
||||
abstract createState(label: string, description: string): S|undefined;
|
||||
|
||||
abstract createTransition(startingState: S, endingState: S): T|undefined;
|
||||
|
||||
abstract removeState(state: S): boolean;
|
||||
|
||||
removeTransition(transition: T): boolean {
|
||||
const updatedTransitions = this.transitions.filter(t => t !== transition);
|
||||
if(updatedTransitions.length == this.transitions.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.transitions = updatedTransitions;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
save() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
60
src/app/game-model/gamesystems/ProductGamesystem.ts
Normal file
60
src/app/game-model/gamesystems/ProductGamesystem.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import {Gamesystem} from "./Gamesystem";
|
||||
import {ProductState} from "./ProductState";
|
||||
import {ProductTransition} from "./ProductTransition";
|
||||
import {State} from "./State";
|
||||
import {Transition} from "./Transition";
|
||||
import {SimpleState} from "./SimpleState";
|
||||
import {SimpleGamesystem} from "./SimpleGamesystem";
|
||||
import {GameModel} from "../GameModel";
|
||||
|
||||
export class ProductGamesystem extends Gamesystem<ProductState, ProductTransition> {
|
||||
|
||||
innerGamesystems: Gamesystem<State<any>, Transition<any>>[] = [];
|
||||
parentGamesystem: ProductGamesystem | undefined
|
||||
|
||||
static constructFromSimpleGamesystem(simpleGamesystem: SimpleGamesystem, gameModel: GameModel) {
|
||||
const productGamesystem = new ProductGamesystem(simpleGamesystem.componentName);
|
||||
const parentGamesystem = simpleGamesystem.parentGamesystem;
|
||||
|
||||
if(simpleGamesystem.states.length > 0) {
|
||||
simpleGamesystem.componentName += "(Child)";
|
||||
productGamesystem.addChildGamesystem(simpleGamesystem);
|
||||
}
|
||||
|
||||
|
||||
if(parentGamesystem != undefined) {
|
||||
parentGamesystem.removeChildGamesystem(simpleGamesystem);
|
||||
parentGamesystem.addChildGamesystem(productGamesystem);
|
||||
} else {
|
||||
gameModel.removeGamesystem(simpleGamesystem);
|
||||
gameModel.addGamesystem(productGamesystem);
|
||||
}
|
||||
|
||||
return productGamesystem;
|
||||
}
|
||||
|
||||
createState(label: string, description: string): ProductState | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
createTransition(startingState: ProductState, endingState: ProductState): ProductTransition | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
removeState(state: ProductState): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeInnerState(state: SimpleState) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
addChildGamesystem(gamesystem: Gamesystem<State<any>, Transition<any>>) {
|
||||
this.innerGamesystems.push(gamesystem);
|
||||
}
|
||||
|
||||
private removeChildGamesystem(gamesystem: Gamesystem<State<any>, Transition<any>>) {
|
||||
this.innerGamesystems = this.innerGamesystems.filter(childSystem => childSystem != gamesystem);
|
||||
}
|
||||
}
|
7
src/app/game-model/gamesystems/ProductState.ts
Normal file
7
src/app/game-model/gamesystems/ProductState.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import {ProductTransition} from "./ProductTransition";
|
||||
import {State} from "./State";
|
||||
import {SimpleState} from "./SimpleState";
|
||||
|
||||
export class ProductState extends State<ProductTransition> {
|
||||
innerStates: SimpleState[] = [];
|
||||
}
|
6
src/app/game-model/gamesystems/ProductTransition.ts
Normal file
6
src/app/game-model/gamesystems/ProductTransition.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import {Transition} from "./Transition";
|
||||
import {ProductState} from "./ProductState";
|
||||
|
||||
export class ProductTransition extends Transition<ProductState> {
|
||||
|
||||
}
|
60
src/app/game-model/gamesystems/SimpleGamesystem.ts
Normal file
60
src/app/game-model/gamesystems/SimpleGamesystem.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import {Gamesystem} from "./Gamesystem";
|
||||
import {SimpleState} from "./SimpleState";
|
||||
import {SimpleTransition} from "./SimpleTransition";
|
||||
import {State} from "./State";
|
||||
import {Transition} from "./Transition";
|
||||
import {ProductState} from "./ProductState";
|
||||
import {ProductTransition} from "./ProductTransition";
|
||||
import {ProductGamesystem} from "./ProductGamesystem";
|
||||
export class SimpleGamesystem extends Gamesystem<SimpleState, SimpleTransition> {
|
||||
|
||||
parentGamesystem: ProductGamesystem | undefined
|
||||
|
||||
createState(label: string, description: string): SimpleState | undefined {
|
||||
if(label == null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if(description == null) {
|
||||
description = "";
|
||||
}
|
||||
|
||||
const state = new SimpleState(label, description);
|
||||
if(this.states.find(s => s.stateLabel == label) == undefined) {
|
||||
this.states.push(state);
|
||||
return state;
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
createTransition(startingState: SimpleState, endingState: SimpleState): SimpleTransition | undefined{
|
||||
if((startingState == null || endingState == null) || startingState === endingState) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const transition = new SimpleTransition(startingState, endingState);
|
||||
if(this.transitions.find(t => t.startingState === startingState && t.endingState === endingState) == undefined) {
|
||||
this.transitions.push(transition)
|
||||
return transition;
|
||||
} else {
|
||||
startingState.removeOutgoingTransition(transition);
|
||||
endingState.removeIncomingTransition(transition);
|
||||
return undefined
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
removeState(state: SimpleState): boolean {
|
||||
const updatedStates = this.states.filter(s => s !== state);
|
||||
const updated = updatedStates.length != this.states.length;
|
||||
this.states = updatedStates;
|
||||
|
||||
this.transitions = this.transitions.filter(t => t.startingState !== state && t.endingState !== state);
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
|
||||
}
|
6
src/app/game-model/gamesystems/SimpleState.ts
Normal file
6
src/app/game-model/gamesystems/SimpleState.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import {State} from "./State";
|
||||
import {SimpleTransition} from "./SimpleTransition";
|
||||
|
||||
export class SimpleState extends State<SimpleTransition> {
|
||||
|
||||
}
|
6
src/app/game-model/gamesystems/SimpleTransition.ts
Normal file
6
src/app/game-model/gamesystems/SimpleTransition.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import {SimpleState} from "./SimpleState";
|
||||
import {Transition} from "./Transition";
|
||||
|
||||
export class SimpleTransition extends Transition<SimpleState> {
|
||||
|
||||
}
|
32
src/app/game-model/gamesystems/State.ts
Normal file
32
src/app/game-model/gamesystems/State.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import {Transition} from "./Transition";
|
||||
|
||||
export abstract class State<T extends Transition<any>> {
|
||||
stateLabel: string = "";
|
||||
stateDescription: string = "";
|
||||
incomingTransitions: T[] =[];
|
||||
outgoingTransitions: T[] =[];
|
||||
|
||||
initial: boolean = false;
|
||||
|
||||
|
||||
constructor(stateLabel: string, stateDescription: string) {
|
||||
this.stateLabel = stateLabel;
|
||||
this.stateDescription = stateDescription;
|
||||
}
|
||||
|
||||
addIncomingTransition(transition: T) {
|
||||
this.incomingTransitions.push(transition);
|
||||
}
|
||||
|
||||
addOutgoingTransition(transition: T) {
|
||||
this.outgoingTransitions.push(transition);
|
||||
}
|
||||
|
||||
removeIncomingTransition(transition: T) {
|
||||
|
||||
}
|
||||
|
||||
removeOutgoingTransition(transition: T) {
|
||||
|
||||
}
|
||||
}
|
15
src/app/game-model/gamesystems/Transition.ts
Normal file
15
src/app/game-model/gamesystems/Transition.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import {State} from "./State";
|
||||
|
||||
export abstract class Transition<S extends State<any>> {
|
||||
startingState: S
|
||||
endingState: S
|
||||
|
||||
|
||||
constructor(startingState: S, endingState: S) {
|
||||
this.startingState = startingState;
|
||||
this.endingState = endingState;
|
||||
|
||||
this.startingState.addOutgoingTransition(this);
|
||||
this.endingState.addIncomingTransition(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" (contextmenu)="onContextMenu($event)">
|
||||
<!-- This is the tree node template for leaf nodes -->
|
||||
<mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding matTreeNodePaddingIndent="10" [ngClass]="selectedGamesystem === node ? 'selected-node':''"
|
||||
(click)="onSelectGamesystem(node)" (contextmenu)="onSelectGamesystem(node)" (dblclick)="openGamesystemEditor(node)">
|
||||
<!-- use a disabled button to provide padding for tree leaf -->
|
||||
<button mat-icon-button class="small-icon-button" [disabled]="true"></button>
|
||||
<div>
|
||||
<button mat-icon-button class="small-icon-button"><mat-icon>code</mat-icon></button>
|
||||
<span>{{node.name}}</span>
|
||||
</div>
|
||||
</mat-tree-node>
|
||||
<!-- This is the tree node template for expandable nodes -->
|
||||
<mat-tree-node *matTreeNodeDef="let node;when: hasChild" matTreeNodePadding matTreeNodePaddingIndent="10"
|
||||
(click)="onSelectGamesystem(node)" (contextmenu)="onSelectGamesystem(node)" [ngClass]="selectedGamesystem === node ? 'selected-node':''"
|
||||
(dblclick)="openGamesystemEditor(node)">
|
||||
<button mat-icon-button matTreeNodeToggle
|
||||
[attr.aria-label]="'Toggle ' + node.name" class="small-icon-button">
|
||||
<mat-icon class="mat-icon-rtl-mirror">
|
||||
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
|
||||
</mat-icon>
|
||||
</button>
|
||||
<div>
|
||||
<button mat-icon-button class="small-icon-button"><mat-icon>code</mat-icon></button>
|
||||
<span>{{node.name}}</span>
|
||||
</div>
|
||||
</mat-tree-node>
|
||||
</mat-tree>
|
@ -0,0 +1,40 @@
|
||||
.mat-tree-node {
|
||||
min-height: 1.8em !important;
|
||||
height: 1.8em;
|
||||
}
|
||||
|
||||
|
||||
.small-icon-button {
|
||||
width: 26px !important;
|
||||
height: 26px !important;
|
||||
padding: 0px !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: 5px;
|
||||
margin-bottom: 2px;
|
||||
|
||||
& > *[role=img] {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
font-size: 18px;
|
||||
|
||||
svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-mdc-button-touch-target {
|
||||
width: 22px !important;
|
||||
height: 22px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.small-icon-button mat-icon {
|
||||
color: whitesmoke;
|
||||
}
|
||||
|
||||
.selected-node {
|
||||
background-color: #545456
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GamescriptOverviewComponent } from './gamescript-overview.component';
|
||||
|
||||
describe('GamescriptOverviewComponent', () => {
|
||||
let component: GamescriptOverviewComponent;
|
||||
let fixture: ComponentFixture<GamescriptOverviewComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [GamescriptOverviewComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(GamescriptOverviewComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,106 @@
|
||||
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||
import {Gamesystem} from "../../game-model/gamesystems/Gamesystem";
|
||||
import {State} from "../../game-model/gamesystems/State";
|
||||
import {Transition} from "../../game-model/gamesystems/Transition";
|
||||
import {ProductGamesystem} from "../../game-model/gamesystems/ProductGamesystem";
|
||||
import {FlatTreeControl} from "@angular/cdk/tree";
|
||||
import {
|
||||
MatTree,
|
||||
MatTreeFlatDataSource,
|
||||
MatTreeFlattener,
|
||||
MatTreeNode, MatTreeNodeDef,
|
||||
MatTreeNodePadding, MatTreeNodeToggle
|
||||
} from "@angular/material/tree";
|
||||
import {MatIcon} from "@angular/material/icon";
|
||||
import {MatIconButton} from "@angular/material/button";
|
||||
import {SimpleGamesystem} from "../../game-model/gamesystems/SimpleGamesystem";
|
||||
import {GameModel} from "../../game-model/GameModel";
|
||||
import {ElectronService} from "../../core/services";
|
||||
|
||||
|
||||
interface FlatNode {
|
||||
expandable: boolean,
|
||||
name: string,
|
||||
level: number
|
||||
}
|
||||
@Component({
|
||||
selector: 'app-gamescript-overview',
|
||||
templateUrl: './gamescript-overview.component.html',
|
||||
styleUrl: './gamescript-overview.component.scss'
|
||||
})
|
||||
export class GamescriptOverviewComponent implements OnInit {
|
||||
|
||||
@Input('gameModel') gameModel: GameModel | undefined
|
||||
@Output('openGamesystemEditor') openGamesystemEmitter : EventEmitter<Gamesystem<State<any>, Transition<any>>> = new EventEmitter<Gamesystem<State<any>, Transition<any>>>();
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.dataSource.data = this.gameModel!.gamesystems;
|
||||
}
|
||||
|
||||
private _transformer = (node: Gamesystem<State<any>, Transition<any>>, level: number) => {
|
||||
return {
|
||||
expandable: this.isProductGamesystem(node) && !!(node as ProductGamesystem).innerGamesystems && (node as ProductGamesystem).innerGamesystems.length > 0,
|
||||
name: node.componentName,
|
||||
level: level
|
||||
}
|
||||
}
|
||||
|
||||
treeControl = new FlatTreeControl<FlatNode>(
|
||||
node => node.level,
|
||||
node => node.expandable
|
||||
)
|
||||
|
||||
treeFlattener = new MatTreeFlattener(
|
||||
this._transformer,
|
||||
node => node.level,
|
||||
node => node.expandable,
|
||||
node => this.isSimpleGamesystem(node)? []: (node as ProductGamesystem).innerGamesystems
|
||||
);
|
||||
|
||||
dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
|
||||
selectedGamesystem: FlatNode | undefined;
|
||||
|
||||
constructor(private electronService: ElectronService) {
|
||||
|
||||
}
|
||||
|
||||
hasChild = (_: number, node: FlatNode) => node.expandable;
|
||||
|
||||
|
||||
isSimpleGamesystem(gamesystem: Gamesystem<State<any>, Transition<any>>) {
|
||||
return gamesystem instanceof SimpleGamesystem;
|
||||
}
|
||||
|
||||
isProductGamesystem(gamesystem: Gamesystem<State<any>, Transition<any>>) {
|
||||
return gamesystem instanceof ProductGamesystem;
|
||||
}
|
||||
|
||||
onSelectGamesystem(node: FlatNode) {
|
||||
this.selectedGamesystem = node;
|
||||
}
|
||||
|
||||
onContextMenu(event: MouseEvent) {
|
||||
this.electronService.ipcRenderer.send('context-menu', {x: event.x, y: event.y});
|
||||
}
|
||||
|
||||
openGamesystemEditor(node: FlatNode) {
|
||||
const gamesystem: Gamesystem<State<any>, Transition<any>>| undefined= this.gameModel!.findGamesystem(node.name);
|
||||
if(gamesystem != undefined) {
|
||||
gamesystem.unsaved = false;
|
||||
this.openGamesystemEmitter.emit(gamesystem);
|
||||
}
|
||||
}
|
||||
|
||||
get selectedGamesystemName() {
|
||||
if(this.selectedGamesystem == undefined) {
|
||||
return undefined
|
||||
} else {
|
||||
return this.selectedGamesystem!.name
|
||||
}
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.dataSource.data = this.gameModel!.gamesystems;
|
||||
}
|
||||
}
|
@ -14,17 +14,7 @@ export class ScriptAccountOverviewComponent {
|
||||
|
||||
selectedScriptAccount: ScriptAccount | undefined
|
||||
|
||||
constructor(private electronService: ElectronService,
|
||||
private zone: NgZone) {
|
||||
if(electronService.isElectron) {
|
||||
this.electronService.ipcRenderer.on('context-menu', (event: any, message: string) => {
|
||||
this.zone.run(() => {
|
||||
if(message == "new-scriptaccount") {
|
||||
this.onCreateNewScriptAccount()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
constructor() {
|
||||
}
|
||||
|
||||
onOpenScriptAccount(scriptAccount: ScriptAccount) {
|
||||
@ -32,12 +22,6 @@ export class ScriptAccountOverviewComponent {
|
||||
this.openScriptAccountEmitter.emit(scriptAccount);
|
||||
}
|
||||
|
||||
onCreateNewScriptAccount() {
|
||||
const scriptAccount = this.gameModel!.addScriptAccount("New ScriptAccount");
|
||||
if(scriptAccount != undefined) {
|
||||
this.openScriptAccountEmitter.emit(scriptAccount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
selectScriptAccount(scriptAccount: ScriptAccount) {
|
||||
|
Loading…
Reference in New Issue
Block a user