issue-5-gamesystems #6
							
								
								
									
										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();
 | 
			
		||||
 | 
			
		||||
  })
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										37
									
								
								e2e/game-model/gamesystems/GamesystemTrainer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								e2e/game-model/gamesystems/GamesystemTrainer.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
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 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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +1,8 @@
 | 
			
		||||
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";
 | 
			
		||||
 | 
			
		||||
export class GameModel {
 | 
			
		||||
  private readonly _gameModelName: string
 | 
			
		||||
@ -48,4 +51,19 @@ export class GameModel {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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,14 +1,17 @@
 | 
			
		||||
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl">
 | 
			
		||||
<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>
 | 
			
		||||
  <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 disabled></button>
 | 
			
		||||
    <button mat-icon-button class="small-icon-button" [disabled]="true"></button>
 | 
			
		||||
    {{node.name}}
 | 
			
		||||
  </mat-tree-node>
 | 
			
		||||
  <!-- This is the tree node template for expandable nodes -->
 | 
			
		||||
  <mat-tree-node *matTreeNodeDef="let node;when: hasChild" matTreeNodePadding>
 | 
			
		||||
  <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">
 | 
			
		||||
            [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>
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import {Component, Input, OnInit} from '@angular/core';
 | 
			
		||||
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";
 | 
			
		||||
@ -15,6 +15,7 @@ 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 {
 | 
			
		||||
@ -30,6 +31,8 @@ interface FlatNode {
 | 
			
		||||
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;
 | 
			
		||||
@ -56,13 +59,15 @@ export class GamescriptOverviewComponent implements OnInit {
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
 | 
			
		||||
  selectedGamesystem: FlatNode | undefined;
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
  constructor(private electronService: ElectronService) {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  hasChild = (_: number, node: FlatNode) => node.expandable;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  isSimpleGamesystem(gamesystem: Gamesystem<State<any>, Transition<any>>) {
 | 
			
		||||
    return gamesystem instanceof SimpleGamesystem;
 | 
			
		||||
  }
 | 
			
		||||
@ -70,4 +75,16 @@ export class GamescriptOverviewComponent implements OnInit {
 | 
			
		||||
  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);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user