1 /** 2 * Copyright © Novelate 2020 3 * License: MIT (https://github.com/Novelate/NovelateEngine/blob/master/LICENSE) 4 * Author: Jacob Jensen (bausshf) 5 * Website: https://novelate.com/ 6 * ------ 7 * Novelate is a free and open-source visual novel engine and framework written in the D programming language. 8 * It can be used freely for both personal and commercial projects. 9 * ------ 10 * Module Description: 11 * This is the module for displaying the main menu. 12 */ 13 module novelate.screens.mainmenu; 14 15 import std.conv : to; 16 17 import novelate.config; 18 import novelate.ui.imagecomponent; 19 import novelate.ui.animatedimage; 20 import novelate.media; 21 import novelate.ui.label; 22 import novelate.colormanager; 23 import novelate.screens.layer; 24 import novelate.screens.screen; 25 import novelate.external; 26 27 import novelate.core : LayerType, changeActiveScreen, StandardScreen; 28 import novelate.state : exitGame, playScene; 29 30 /// The main menu screen. 31 final class MainMenuScreen : Screen 32 { 33 public: 34 final: 35 /// Creates a new main menu screen. 36 this() 37 { 38 super(StandardScreen.mainMenu); 39 } 40 41 /// See: Screen.update() 42 override void update(string[] data) 43 { 44 updateBackground(config.menuBackground); 45 46 auto logoFrames = config.menuLogoImage; 47 48 if (logoFrames && logoFrames.frames && logoFrames.frames.length) 49 { 50 string[] logoImages = []; 51 52 auto frameSpeed = logoFrames.frames[0].nextFrameTime; 53 54 foreach (frame; logoFrames.frames) 55 { 56 logoImages ~= getMediaFile(frame.image).relativePath(super.width); 57 } 58 59 if (logoImages && logoImages.length) 60 { 61 auto image = new AnimatedImage(logoImages); 62 image.animationSpeed = frameSpeed; 63 image.fadeIn(20); 64 image.position = FloatVector(config.menuLogoImageX800, config.menuLogoImageY800); 65 66 addComponent(LayerType.front, image, "logo"); 67 } 68 } 69 70 AltValue!(ptrdiff_t, string) menuBoxOffsetX; 71 AltValue!(ptrdiff_t, string) menuBoxOffsetY; 72 73 if (super.width == 800) 74 { 75 menuBoxOffsetX = config.menuBox_X800; 76 menuBoxOffsetY = config.menuBox_Y800; 77 } 78 else if (super.width == 1024) 79 { 80 menuBoxOffsetX = config.menuBox_X1024; 81 menuBoxOffsetY = config.menuBox_Y1024; 82 } 83 else if (super.width == 1280) 84 { 85 menuBoxOffsetX = config.menuBox_X1280; 86 menuBoxOffsetY = config.menuBox_Y1280; 87 } 88 89 ptrdiff_t offsetX = 0; 90 ptrdiff_t offsetY = 0; 91 92 if (menuBoxOffsetX.value2 && menuBoxOffsetX.value2.length) 93 { 94 switch (menuBoxOffsetX.value2) 95 { 96 case "C": 97 case "Center": 98 offsetX = (super.width / 2); 99 break; 100 101 default: break; 102 } 103 } 104 else 105 { 106 offsetX = menuBoxOffsetX.value1; 107 } 108 109 Label[] labels = []; 110 111 Label thisLabel; 112 thisLabel = createLabel(config.menuItem_Play.text, (b, ref s) 113 { 114 changeActiveScreen(StandardScreen.scene, [playScene]); 115 }, offsetX); 116 117 labels ~= thisLabel; 118 119 labels ~= createLabel(config.menuItem_Load.text, (b, ref s) 120 { 121 changeActiveScreen(StandardScreen.load); 122 }, offsetX); 123 124 labels ~= createLabel(config.menuItem_Save.text, (b, ref s) 125 { 126 changeActiveScreen(StandardScreen.save); 127 }, offsetX); 128 129 labels ~= createLabel(config.menuItem_About.text, (b, ref s) 130 { 131 changeActiveScreen(StandardScreen.about); 132 }, offsetX); 133 134 labels ~= createLabel(config.menuItem_Characters.text, (b, ref s) 135 { 136 changeActiveScreen(StandardScreen.characters); 137 }, offsetX); 138 139 labels ~= createLabel(config.menuItem_Exit.text, (b, ref s) 140 { 141 exitGame = true; 142 }, offsetX); 143 144 if (menuBoxOffsetY.value2 && menuBoxOffsetY.value2.length) 145 { 146 size_t totalHeight = 0; 147 148 foreach (label; labels) 149 { 150 totalHeight += label.height; 151 totalHeight += cast(size_t)(cast(double)label.fontSize * 0.5); 152 } 153 154 switch (menuBoxOffsetY.value2) 155 { 156 case "B": 157 case "Bottom": 158 totalHeight += cast(size_t)(cast(double)labels[0].fontSize * 1.5); 159 160 offsetY = (super.height - totalHeight); 161 break; 162 case "T": 163 case "Top": 164 offsetY = cast(ptrdiff_t)(cast(double)labels[0].fontSize * 1.5); 165 break; 166 167 case "C": 168 case "Center": 169 offsetY = cast(ptrdiff_t)((super.height / 2) - (totalHeight / 2)); 170 break; 171 172 default: break; 173 } 174 } 175 else 176 { 177 offsetY = menuBoxOffsetY.value1; 178 } 179 180 foreach (label; labels) 181 { 182 label.position = FloatVector(label.x, offsetY); 183 184 offsetY += label.height; 185 offsetY += cast(size_t)(cast(double)label.fontSize * 0.5); 186 187 addComponent(LayerType.dialogueBoxInteraction, label, to!string(label.text)); 188 } 189 } 190 191 /** 192 * Creates a label for the menu. 193 * Params: 194 * text = The text of the label. 195 * mouseRelease = Handler for when the label is pressed. 196 * offsetX = The x offset of the label. 197 */ 198 private Label createLabel(string text, void delegate(MouseButton button, ref bool stopEvent) mouseRelease, ptrdiff_t offsetX) 199 { 200 auto label = new Label; 201 label.color = colorFromString(config.defaultDialogueColor); 202 label.fontSize = 48; 203 if (config.defaultFont && config.defaultFont.length) 204 { 205 label.fontName = config.defaultFont; 206 } 207 label.text = to!dstring(text); 208 label.position = FloatVector(offsetX - (label.width / 2), 50000); 209 label.mouseRelease = mouseRelease; 210 211 return label; 212 } 213 }