Index: ps/trunk/binaries/data/mods/public/gui/pregame/BackgroundHandler.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/pregame/BackgroundHandler.js (revision 23092) +++ ps/trunk/binaries/data/mods/public/gui/pregame/BackgroundHandler.js (revision 23093) @@ -1,48 +1,72 @@ class BackgroundHandler { 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: ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js (revision 23092) +++ ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuItemHandler.js (revision 23093) @@ -1,108 +1,142 @@ +/** + * 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"); this.mainMenuButtons = Engine.GetGUIObjectByName("mainMenuButtons"); this.submenu = Engine.GetGUIObjectByName("submenu"); this.submenuButtons = Engine.GetGUIObjectByName("submenuButtons"); this.MainMenuPanelRightBorderTop = Engine.GetGUIObjectByName("MainMenuPanelRightBorderTop"); this.MainMenuPanelRightBorderBottom = Engine.GetGUIObjectByName("MainMenuPanelRightBorderBottom"); 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) { buttons.forEach((button, i) => { let item = menuItems[i]; button.hidden = !item; if (button.hidden) 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; button.enabled = item.enabled === undefined || item.enabled; button.onPress = () => { this.closeSubmenu(); if (item.onPress) item.onPress(); else this.openSubmenu(i); }; button.hidden = false; }); if (buttons.length < menuItems.length) error("GUI page has space for " + buttons.length + " menu buttons, but " + menuItems.length + " items are provided!"); } setupHotkeys(menuItems) { - for (let name in menuItems) + for (let i in menuItems) { - let item = menuItems[name]; - + let item = menuItems[i]; if (item.onPress && item.hotkey) - { Engine.SetGlobalHotkey(item.hotkey, () => { this.closeSubmenu(); item.onPress(); }); - } if (item.submenu) this.setupHotkeys(item.submenu); } } 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() { 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; if (this.submenu.hidden || offset <= 0) return; let size = this.submenu.size; size.left += offset; size.right += offset; 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: ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuPage.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuPage.js (nonexistent) +++ ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuPage.js (revision 23093) @@ -0,0 +1,60 @@ +/** + * This is the handler that coordinates all other handlers on this GUI page. + */ +class MainMenuPage +{ + 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); + + new MusicHandler(); + new ProjectInformationHandler(projectInformation); + new CommunityButtonHandler(communityButtons); + } + + getHotloadData() + { + return { + "splashScreenHandler": this.splashScreenHandler.getHotloadData() + }; + } +} + +class MusicHandler +{ + constructor() + { + initMusic(); + global.music.setState(global.music.states.MENU); + } +} + +class ProjectInformationHandler +{ + constructor(projectInformation) + { + for (let objectName in projectInformation) + for (let propertyName in projectInformation[objectName]) + Engine.GetGUIObjectByName(objectName)[propertyName] = projectInformation[objectName][propertyName]; + } +} + +class CommunityButtonHandler +{ + constructor(communityButtons) + { + let buttons = Engine.GetGUIObjectByName("communityButtons").children; + + communityButtons.forEach((buttonInfo, i) => { + let button = buttons[i]; + button.hidden = false; + for (let propertyName in buttonInfo) + button[propertyName] = buttonInfo[propertyName]; + }); + + if (buttons.length < communityButtons.length) + error("GUI page has space for " + buttons.length + " community buttons, but " + menuItems.length + " items are provided!"); + } +} Property changes on: ps/trunk/binaries/data/mods/public/gui/pregame/MainMenuPage.js ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/gui/pregame/SplashscreenHandler.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/pregame/SplashscreenHandler.js (revision 23092) +++ ps/trunk/binaries/data/mods/public/gui/pregame/SplashscreenHandler.js (revision 23093) @@ -1,62 +1,68 @@ class SplashScreenHandler { constructor(initData, hotloadData) { this.showSplashScreen = hotloadData ? hotloadData.showSplashScreen : initData && initData.isStartup; + + this.mainMenuPage = Engine.GetGUIObjectByName("mainMenuPage"); + this.mainMenuPage.onTick = this.onFirstTick.bind(this); } getHotloadData() { // Only show splash screen(s) once at startup, but not again after hotloading return { "showSplashScreen": this.showSplashScreen }; } // Don't call this from the init function in order to not crash when opening the new page on init on hotloading // and not possibly crash when opening the new page on init and throwing a JS error. - onTick() + onFirstTick() { if (this.showSplashScreen) this.openPage(); + + // TODO: support actually deleting the handler + this.mainMenuPage.onTick = () => {}; } openPage() { this.showSplashScreen = false; if (Engine.ConfigDB_GetValue("user", "gui.splashscreen.enable") === "true" || Engine.ConfigDB_GetValue("user", "gui.splashscreen.version") < Engine.GetFileMTime("gui/splashscreen/splashscreen.txt")) Engine.PushGuiPage("page_splashscreen.xml", {}, this.showRenderPathMessage); else this.showRenderPathMessage(); } showRenderPathMessage() { // Warn about removing fixed render path if (Engine.Renderer_GetRenderPath() != "fixed") return; messageBox( 600, 300, "[font=\"sans-bold-16\"]" + sprintf(translate("%(warning)s You appear to be using non-shader (fixed function) graphics. This option will be removed in a future 0 A.D. release, to allow for more advanced graphics features. We advise upgrading your graphics card to a more recent, shader-compatible model."), { "warning": coloredText("Warning:", "200 20 20") }) + "\n\n" + // Translation: This is the second paragraph of a warning. The // warning explains that the user is using “non-shader“ graphics, // and that in the future this will not be supported by the game, so // the user will need a better graphics card. translate("Please press \"Read More\" for more information or \"OK\" to continue."), translate("WARNING!"), [translate("OK"), translate("Read More")], [ null, () => { Engine.OpenURL("https://www.wildfiregames.com/forum/index.php?showtopic=16734"); } ]); } } Index: ps/trunk/binaries/data/mods/public/gui/pregame/backgrounds.xml =================================================================== --- ps/trunk/binaries/data/mods/public/gui/pregame/backgrounds.xml (revision 23092) +++ ps/trunk/binaries/data/mods/public/gui/pregame/backgrounds.xml (revision 23093) @@ -1,6 +1,6 @@ - + Index: ps/trunk/binaries/data/mods/public/gui/pregame/mainmenu.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/pregame/mainmenu.js (revision 23092) +++ ps/trunk/binaries/data/mods/public/gui/pregame/mainmenu.js (revision 23093) @@ -1,70 +1,26 @@ /** * Available backgrounds, added by the files in backgrounds/. */ var g_BackgroundLayerData = []; -var g_BackgroundHandler; -var g_MenuHandler; -var g_SplashScreenHandler; +/** + * This is the handler that coordinates all other handlers. + */ +var g_MainMenuPage; 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() -{ - g_MenuHandler.onTick(); - g_BackgroundHandler.onTick(); - g_SplashScreenHandler.onTick(); + g_MainMenuPage = + new MainMenuPage( + data, + hotloadData, + g_MainMenuItems, + g_BackgroundLayerData, + g_ProjectInformation, + g_CommunityButtons); } function getHotloadData() { - return { - "splashScreenHandler": g_SplashScreenHandler.getHotloadData() - }; -} - -class MusicHandler -{ - constructor() - { - initMusic(); - global.music.setState(global.music.states.MENU); - } -} - -class ProjectInformationHandler -{ - constructor(projectInformation) - { - for (let objectName in projectInformation) - for (let propertyName in projectInformation[objectName]) - Engine.GetGUIObjectByName(objectName)[propertyName] = projectInformation[objectName][propertyName]; - } -} - -class CommunityButtonHandler -{ - constructor() - { - let buttons = Engine.GetGUIObjectByName("communityButtons").children; - - g_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) - error("GUI page has space for " + buttons.length + " community buttons, but " + menuItems.length + " items are provided!"); - } + return g_MainMenuPage.getHotloadData(); } Index: ps/trunk/binaries/data/mods/public/gui/pregame/mainmenu.xml =================================================================== --- ps/trunk/binaries/data/mods/public/gui/pregame/mainmenu.xml (revision 23092) +++ ps/trunk/binaries/data/mods/public/gui/pregame/mainmenu.xml (revision 23093) @@ -1,17 +1,15 @@