MainMenu.qml 12 KB

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