MainMenu.qml 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. import QtQuick 2.15
  2. import QtQuick.Controls 2.15
  3. import QtQuick.Layouts 1.3
  4. import QtQuick.Window 2.15
  5. import StandardOfIron.UI 1.0
  6. Item {
  7. id: root
  8. signal openSkirmish()
  9. signal openSettings()
  10. signal loadSave()
  11. signal saveGame()
  12. signal exitRequested()
  13. anchors.fill: parent
  14. z: 10
  15. focus: true
  16. Keys.onPressed: function(event) {
  17. if (event.key === Qt.Key_Down) {
  18. container.selectedIndex = Math.min(container.selectedIndex + 1, menuModel.count - 1);
  19. event.accepted = true;
  20. } else if (event.key === Qt.Key_Up) {
  21. container.selectedIndex = Math.max(container.selectedIndex - 1, 0);
  22. event.accepted = true;
  23. } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
  24. var m = menuModel.get(container.selectedIndex);
  25. if (m.idStr === "skirmish")
  26. root.openSkirmish();
  27. else if (m.idStr === "save")
  28. root.saveGame();
  29. else if (m.idStr === "load")
  30. root.loadSave();
  31. else if (m.idStr === "settings")
  32. root.openSettings();
  33. else if (m.idStr === "exit")
  34. root.exitRequested();
  35. event.accepted = true;
  36. } else if (event.key === Qt.Key_Escape) {
  37. if (typeof mainWindow !== 'undefined' && mainWindow.menuVisible && mainWindow.gameStarted) {
  38. mainWindow.menuVisible = false;
  39. event.accepted = true;
  40. }
  41. }
  42. }
  43. Rectangle {
  44. anchors.fill: parent
  45. color: Theme.dim
  46. }
  47. Rectangle {
  48. id: container
  49. property int selectedIndex: 0
  50. width: Math.min(parent.width * 0.78, 1100)
  51. height: Math.min(parent.height * 0.78, 700)
  52. anchors.centerIn: parent
  53. radius: Theme.radiusPanel
  54. color: Theme.panelBase
  55. border.color: Theme.panelBr
  56. border.width: 1
  57. opacity: 0.98
  58. clip: true
  59. GridLayout {
  60. id: grid
  61. anchors.fill: parent
  62. anchors.margins: Theme.spacingXLarge
  63. rowSpacing: Theme.spacingMedium
  64. columnSpacing: 18
  65. columns: parent.width > 900 ? 2 : 1
  66. ColumnLayout {
  67. Layout.preferredWidth: parent.width > 900 ? parent.width * 0.45 : parent.width
  68. spacing: Theme.spacingLarge
  69. ColumnLayout {
  70. spacing: Theme.spacingSmall
  71. Label {
  72. text: "STANDARD OF IRON"
  73. color: Theme.textMain
  74. font.pointSize: Theme.fontSizeHero
  75. font.bold: true
  76. horizontalAlignment: Text.AlignLeft
  77. Layout.fillWidth: true
  78. elide: Label.ElideRight
  79. }
  80. Label {
  81. text: "A tiny but ambitious RTS"
  82. color: Theme.textSub
  83. font.pointSize: Theme.fontSizeMedium
  84. horizontalAlignment: Text.AlignLeft
  85. Layout.fillWidth: true
  86. elide: Label.ElideRight
  87. }
  88. }
  89. ListModel {
  90. id: menuModel
  91. ListElement {
  92. idStr: "skirmish"
  93. title: "Play — Skirmish"
  94. subtitle: "Select a map and start"
  95. }
  96. ListElement {
  97. idStr: "save"
  98. title: "Save Game"
  99. subtitle: "Save your current progress"
  100. }
  101. ListElement {
  102. idStr: "load"
  103. title: "Load Game"
  104. subtitle: "Resume a previous game"
  105. }
  106. ListElement {
  107. idStr: "settings"
  108. title: "Settings"
  109. subtitle: "Adjust graphics & controls"
  110. }
  111. ListElement {
  112. idStr: "exit"
  113. title: "Exit"
  114. subtitle: "Quit the game"
  115. }
  116. }
  117. Repeater {
  118. model: menuModel
  119. delegate: Item {
  120. id: menuItem
  121. property int idx: index
  122. Layout.fillWidth: true
  123. Layout.preferredHeight: container.width > 900 ? 64 : 56
  124. Rectangle {
  125. anchors.fill: parent
  126. radius: Theme.radiusLarge
  127. clip: true
  128. color: container.selectedIndex === idx ? Theme.selectedBg : menuItemMouse.containsPress ? Theme.hoverBg : Qt.rgba(0, 0, 0, 0)
  129. border.width: 1
  130. border.color: container.selectedIndex === idx ? Theme.selectedBr : Theme.cardBorder
  131. RowLayout {
  132. anchors.fill: parent
  133. anchors.margins: Theme.spacingSmall
  134. spacing: Theme.spacingMedium
  135. Item {
  136. Layout.fillWidth: true
  137. Layout.preferredWidth: 1
  138. }
  139. ColumnLayout {
  140. Layout.fillWidth: true
  141. spacing: Theme.spacingTiny
  142. Text {
  143. text: model.title
  144. Layout.fillWidth: true
  145. elide: Text.ElideRight
  146. color: container.selectedIndex === idx ? Theme.textMain : Theme.textBright
  147. font.pointSize: Theme.fontSizeLarge
  148. font.bold: container.selectedIndex === idx
  149. }
  150. Text {
  151. text: model.subtitle
  152. Layout.fillWidth: true
  153. elide: Text.ElideRight
  154. color: container.selectedIndex === idx ? Theme.accentBright : Theme.textSubLite
  155. font.pointSize: Theme.fontSizeSmall
  156. }
  157. }
  158. Text {
  159. text: "›"
  160. font.pointSize: Theme.fontSizeTitle
  161. color: container.selectedIndex === idx ? Theme.textMain : Theme.textHint
  162. }
  163. }
  164. Behavior on color {
  165. ColorAnimation {
  166. duration: Theme.animNormal
  167. }
  168. }
  169. Behavior on border.color {
  170. ColorAnimation {
  171. duration: Theme.animNormal
  172. }
  173. }
  174. }
  175. MouseArea {
  176. id: menuItemMouse
  177. anchors.fill: parent
  178. hoverEnabled: true
  179. acceptedButtons: Qt.LeftButton
  180. cursorShape: Qt.PointingHandCursor
  181. onEntered: container.selectedIndex = idx
  182. onClicked: {
  183. if (model.idStr === "skirmish")
  184. root.openSkirmish();
  185. else if (model.idStr === "save")
  186. root.saveGame();
  187. else if (model.idStr === "load")
  188. root.loadSave();
  189. else if (model.idStr === "settings")
  190. root.openSettings();
  191. else if (model.idStr === "exit")
  192. root.exitRequested();
  193. }
  194. }
  195. }
  196. }
  197. Item {
  198. Layout.fillHeight: true
  199. }
  200. RowLayout {
  201. spacing: Theme.spacingSmall
  202. Label {
  203. text: "v0.9 — prototype"
  204. color: Theme.textDim
  205. font.pointSize: Theme.fontSizeSmall
  206. }
  207. Item {
  208. Layout.fillWidth: true
  209. }
  210. Label {
  211. text: Qt.formatDateTime(new Date(), "yyyy-MM-dd")
  212. color: Theme.textHint
  213. font.pointSize: Theme.fontSizeSmall
  214. elide: Label.ElideRight
  215. }
  216. }
  217. }
  218. Rectangle {
  219. color: Qt.rgba(0, 0, 0, 0)
  220. radius: Theme.radiusMedium
  221. Layout.preferredWidth: parent.width > 900 ? parent.width * 0.45 : parent.width
  222. ColumnLayout {
  223. anchors.fill: parent
  224. anchors.margins: Theme.spacingSmall
  225. spacing: Theme.spacingMedium
  226. Rectangle {
  227. id: promo
  228. color: Theme.cardBase
  229. radius: Theme.radiusLarge
  230. border.color: Theme.border
  231. border.width: 1
  232. Layout.preferredHeight: 260
  233. clip: true
  234. ColumnLayout {
  235. anchors.fill: parent
  236. anchors.margins: Theme.spacingMedium
  237. spacing: Theme.spacingSmall
  238. Label {
  239. text: "Featured"
  240. color: Theme.accent
  241. font.pointSize: Theme.fontSizeMedium
  242. Layout.fillWidth: true
  243. elide: Label.ElideRight
  244. }
  245. Label {
  246. text: "Skirmish Mode"
  247. color: Theme.textMain
  248. font.pointSize: Theme.fontSizeTitle
  249. font.bold: true
  250. Layout.fillWidth: true
  251. elide: Label.ElideRight
  252. }
  253. Text {
  254. text: "Pick a map, adjust your forces and jump into battle. Modern controls and responsive UI."
  255. color: Theme.textSubLite
  256. wrapMode: Text.WordWrap
  257. maximumLineCount: 3
  258. elide: Text.ElideRight
  259. Layout.fillWidth: true
  260. }
  261. }
  262. }
  263. Rectangle {
  264. color: Theme.cardBase
  265. radius: Theme.radiusLarge
  266. border.color: Theme.border
  267. border.width: 1
  268. Layout.preferredHeight: 120
  269. clip: true
  270. ColumnLayout {
  271. anchors.fill: parent
  272. anchors.margins: Theme.spacingSmall
  273. spacing: Theme.spacingSmall
  274. Label {
  275. text: "Tips"
  276. color: Theme.accent
  277. font.pointSize: Theme.fontSizeMedium
  278. Layout.fillWidth: true
  279. elide: Label.ElideRight
  280. }
  281. Text {
  282. text: "Hover menu items or use Up/Down and Enter to navigate. Play opens map selection."
  283. color: Theme.textSubLite
  284. wrapMode: Text.WordWrap
  285. maximumLineCount: 3
  286. elide: Text.ElideRight
  287. Layout.fillWidth: true
  288. }
  289. }
  290. }
  291. }
  292. }
  293. }
  294. }
  295. }