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 }