Index: binaries/data/mods/public/gui/pregame/BackgroundHandler.js =================================================================== --- binaries/data/mods/public/gui/pregame/BackgroundHandler.js +++ binaries/data/mods/public/gui/pregame/BackgroundHandler.js @@ -2,47 +2,71 @@ { constructor(layers) { + this.backgroundLayers = layers.map((layer, i) => + new BackgroundLayer(layer, i)); + this.initTime = Date.now(); - this.layerSet = layers; - this.initBackgrounds(); + this.backgrounds = Engine.GetGUIObjectByName("backgrounds"); + this.backgrounds.onTick = this.onTick.bind(this); + this.backgrounds.onWindowResized = this.onWindowResized.bind(this); + this.onWindowResized(); } - initBackgrounds() + onWindowResized() { - this.layerSet.forEach((layer, i) => { - - let background = Engine.GetGUIObjectByName("background[" + i + "]"); - background.sprite = layer.sprite; - background.z = i; - background.hidden = false; - }); + let size = this.backgrounds.getComputedSize(); + this.backgroundsSize = deepfreeze(new GUISize(size.top, size.left, size.right, size.bottom)); } onTick() { - let now = Date.now(); + let time = Date.now() - this.initTime; + for (let background of this.backgroundLayers) + background.update(time, this.backgroundsSize); + } +} - this.layerSet.forEach((layer, i) => { +class BackgroundLayer +{ + constructor(layer, i) + { + this.layer = layer; - let background = Engine.GetGUIObjectByName("background[" + i + "]"); + this.background = Engine.GetGUIObjectByName("background[" + i + "]"); + this.background.sprite = this.layer.sprite; + this.background.z = i; + this.background.hidden = false; + } - let screen = background.parent.getComputedSize(); - let h = screen.bottom - screen.top; - let w = h * 16/9; - let iw = h * 2; - - let offset = layer.offset((now - this.initTime) / 1000, w); - - if (layer.tiling) - { - let left = offset % iw; - if (left >= 0) - left -= iw; - background.size = new GUISize(left, screen.top, screen.right, screen.bottom); - } - else - background.size = new GUISize(screen.right/2 - h + offset, screen.top, screen.right/2 + h + offset, screen.bottom); - }); + update(time, backgroundsSize) + { + let height = backgroundsSize.bottom - backgroundsSize.top; + let width = height * this.AspectRatio; + let offset = this.layer.offset(time / 1000, width); + + if (this.layer.tiling) + { + let iw = height * 2; + let left = offset % iw; + if (left >= 0) + left -= iw; + this.background.size = new GUISize( + left, + backgroundsSize.top, + backgroundsSize.right, + backgroundsSize.bottom); + } + else + { + let right = backgroundsSize.right / 2 + offset; + this.background.size = new GUISize( + right - height, + backgroundsSize.top, + right + height, + backgroundsSize.bottom); + } } } + +BackgroundLayer.prototype.AspectRatio = 16 / 9; Index: binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js =================================================================== --- binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js +++ binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js @@ -1,11 +1,12 @@ +/** + * This class sets up the main menu buttons, animates submenu that opens when + * clicking on category buttons, assigns the defined actions and hotkeys to every button. + */ class MainMenuItemHandler { - constructor(menuItems, menuSpeed = 1.2, margin = 4, buttonHeight = 28) + constructor(menuItems) { this.menuItems = menuItems; - this.menuSpeed = menuSpeed; - this.margin = margin; - this.buttonHeight = buttonHeight; this.lastTickTime = Date.now(); this.mainMenu = Engine.GetGUIObjectByName("mainMenu"); @@ -17,7 +18,9 @@ this.setupMenuButtons(this.mainMenuButtons.children, this.menuItems); this.setupHotkeys(this.menuItems); - Engine.GetGUIObjectByName("closeMenuButton").onPress = () => { this.closeSubmenu(); }; + + this.mainMenu.onTick = this.onTick.bind(this); + Engine.GetGUIObjectByName("closeMenuButton").onPress = this.closeSubmenu.bind(this); } setupMenuButtons(buttons, menuItems) @@ -29,8 +32,8 @@ return; button.size = new GUISize( - 0, (this.buttonHeight + this.margin) * i, - 0, (this.buttonHeight + this.margin) * i + this.buttonHeight, + 0, (this.ButtonHeight + this.Margin) * i, + 0, (this.ButtonHeight + this.Margin) * i + this.ButtonHeight, 0, 0, 100, 0); button.caption = item.caption; button.tooltip = item.tooltip; @@ -57,12 +60,10 @@ let item = menuItems[name]; if (item.onPress && item.hotkey) - { Engine.SetGlobalHotkey(item.hotkey, () => { this.closeSubmenu(); item.onPress(); }); - } if (item.submenu) this.setupHotkeys(item.submenu); @@ -72,20 +73,39 @@ openSubmenu(i) { this.setupMenuButtons(this.submenuButtons.children, this.menuItems[i].submenu); + let top = this.mainMenuButtons.size.top + this.mainMenuButtons.children[i].size.top; + this.submenu.size = new GUISize( - this.submenu.size.left, top - this.margin, - this.submenu.size.right, top + ((this.buttonHeight + this.margin) * this.menuItems[i].submenu.length)); + this.submenu.size.left, top - this.Margin, + this.submenu.size.right, top + (this.ButtonHeight + this.Margin) * this.menuItems[i].submenu.length); + this.submenu.hidden = false; - this.MainMenuPanelRightBorderTop.size = "100%-2 0 100% " + (this.submenu.size.top + this.margin); - this.MainMenuPanelRightBorderBottom.size = "100%-2 " + this.submenu.size.bottom + " 100% 100%"; + + { + let size = this.MainMenuPanelRightBorderTop.size; + size.bottom = this.submenu.size.top + this.Margin; + size.rbottom = 0; + this.MainMenuPanelRightBorderTop.size = size; + } + + { + let size = this.MainMenuPanelRightBorderBottom.size; + size.top = this.submenu.size.bottom; + this.MainMenuPanelRightBorderBottom.size = size; + } } closeSubmenu() { this.submenu.hidden = true; this.submenu.size = this.mainMenu.size; - this.MainMenuPanelRightBorderTop.size = "100%-2 0 100% 100%"; + + let size = this.MainMenuPanelRightBorderTop.size; + size.top = 0; + size.bottom = 0; + size.rbottom = 100; + this.MainMenuPanelRightBorderTop.size = size; } onTick() @@ -93,7 +113,7 @@ let now = Date.now(); let maxOffset = this.mainMenu.size.right - this.submenu.size.left; - let offset = Math.min(this.menuSpeed * (now - this.lastTickTime), maxOffset); + let offset = Math.min(this.MenuSpeed * (now - this.lastTickTime), maxOffset); this.lastTickTime = now; @@ -106,3 +126,18 @@ this.submenu.size = size; } } + +/** + * Vertical size per button. + */ +MainMenuItemHandler.prototype.ButtonHeight = 28; + +/** + * Distance between consecutive buttons. + */ +MainMenuItemHandler.prototype.Margin = 4; + +/** + * Collapse / expansion speed in pixels per milliseconds used when animating the button menu size. + */ +MainMenuItemHandler.prototype.MenuSpeed = 1.2; Index: binaries/data/mods/public/gui/pregame/MainMenuPage.js =================================================================== --- binaries/data/mods/public/gui/pregame/MainMenuPage.js +++ binaries/data/mods/public/gui/pregame/MainMenuPage.js @@ -1,35 +1,24 @@ /** - * Available backgrounds, added by the files in backgrounds/. + * This is the handler that coordinates all other handlers on this GUI page. */ -var g_BackgroundLayerData = []; - -var g_BackgroundHandler; -var g_MenuHandler; -var g_SplashScreenHandler; - -function init(data, hotloadData) -{ - g_MenuHandler = new MainMenuItemHandler(g_MainMenuItems); - g_BackgroundHandler = new BackgroundHandler(pickRandom(g_BackgroundLayerData)); - g_SplashScreenHandler = new SplashScreenHandler(data, hotloadData && hotloadData.splashScreenHandler); - - new MusicHandler(); - new ProjectInformationHandler(g_ProjectInformation); - new CommunityButtonHandler(); -} - -function onTick() +class MainMenuPage { - g_MenuHandler.onTick(); - g_BackgroundHandler.onTick(); - g_SplashScreenHandler.onTick(); -} + constructor(data, hotloadData, mainMenuItems, backgroundLayerData, projectInformation, communityButtons) + { + this.backgroundHandler = new BackgroundHandler(pickRandom(backgroundLayerData)); + this.menuHandler = new MainMenuItemHandler(mainMenuItems); + this.splashScreenHandler = new SplashScreenHandler(data, hotloadData && hotloadData.splashScreenHandler); + this.musicHandler = new MusicHandler(); + this.projectInformationHandler = new ProjectInformationHandler(projectInformation); + this.communityButtonHandler = new CommunityButtonHandler(communityButtons); + } -function getHotloadData() -{ - return { - "splashScreenHandler": g_SplashScreenHandler.getHotloadData() - }; + getHotloadData() + { + return { + "splashScreenHandler": this.splashScreenHandler.getHotloadData() + }; + } } class MusicHandler @@ -53,18 +42,18 @@ class CommunityButtonHandler { - constructor() + constructor(communityButtons) { let buttons = Engine.GetGUIObjectByName("communityButtons").children; - g_CommunityButtons.forEach((buttonInfo, i) => { + communityButtons.forEach((buttonInfo, i) => { let button = buttons[i]; button.hidden = false; for (let propertyName in buttonInfo) button[propertyName] = buttonInfo[propertyName]; }); - if (buttons.length < g_CommunityButtons.length) + if (buttons.length < communityButtons.length) error("GUI page has space for " + buttons.length + " community buttons, but " + menuItems.length + " items are provided!"); } } Index: binaries/data/mods/public/gui/pregame/backgrounds.xml =================================================================== --- binaries/data/mods/public/gui/pregame/backgrounds.xml +++ binaries/data/mods/public/gui/pregame/backgrounds.xml @@ -1,5 +1,5 @@ - + Index: binaries/data/mods/public/gui/pregame/menupanel.xml =================================================================== --- binaries/data/mods/public/gui/pregame/menupanel.xml +++ binaries/data/mods/public/gui/pregame/menupanel.xml @@ -12,7 +12,7 @@ - +