HUDTop.qml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. import QtQuick 2.15
  2. import QtQuick.Controls 2.15
  3. import QtQuick.Layouts 2.15
  4. Item {
  5. id: topRoot
  6. property bool gameIsPaused: false
  7. property real currentSpeed: 1
  8. readonly property int barMinHeight: 72
  9. readonly property bool compact: width < 800
  10. readonly property bool ultraCompact: width < 560
  11. signal pauseToggled()
  12. signal speedChanged(real speed)
  13. Rectangle {
  14. id: topPanel
  15. anchors.left: parent.left
  16. anchors.right: parent.right
  17. anchors.top: parent.top
  18. height: barMinHeight
  19. color: "#1a1a1a"
  20. opacity: 0.98
  21. clip: true
  22. Rectangle {
  23. anchors.fill: parent
  24. opacity: 0.9
  25. gradient: Gradient {
  26. GradientStop {
  27. position: 0
  28. color: "#22303a"
  29. }
  30. GradientStop {
  31. position: 1
  32. color: "#0f1a22"
  33. }
  34. }
  35. }
  36. Rectangle {
  37. anchors.left: parent.left
  38. anchors.right: parent.right
  39. anchors.bottom: parent.bottom
  40. height: 2
  41. gradient: Gradient {
  42. GradientStop {
  43. position: 0
  44. color: "transparent"
  45. }
  46. GradientStop {
  47. position: 0.5
  48. color: "#3498db"
  49. }
  50. GradientStop {
  51. position: 1
  52. color: "transparent"
  53. }
  54. }
  55. }
  56. RowLayout {
  57. id: barRow
  58. anchors.fill: parent
  59. anchors.margins: 8
  60. spacing: 12
  61. RowLayout {
  62. id: leftGroup
  63. spacing: 10
  64. Layout.alignment: Qt.AlignVCenter
  65. Button {
  66. id: pauseBtn
  67. Layout.preferredWidth: topRoot.compact ? 48 : 56
  68. Layout.preferredHeight: Math.min(40, topPanel.height - 12)
  69. text: topRoot.gameIsPaused ? "\u25B6" : "\u23F8"
  70. font.pixelSize: 26
  71. font.bold: true
  72. focusPolicy: Qt.NoFocus
  73. onClicked: topRoot.pauseToggled()
  74. background: Rectangle {
  75. color: parent.pressed ? "#e74c3c" : parent.hovered ? "#c0392b" : "#34495e"
  76. radius: 6
  77. border.color: "#2c3e50"
  78. border.width: 1
  79. }
  80. contentItem: Text {
  81. text: parent.text
  82. font: parent.font
  83. color: "#ecf0f1"
  84. horizontalAlignment: Text.AlignHCenter
  85. verticalAlignment: Text.AlignVCenter
  86. }
  87. }
  88. Rectangle {
  89. width: 2
  90. Layout.fillHeight: true
  91. radius: 1
  92. visible: !topRoot.compact
  93. gradient: Gradient {
  94. GradientStop {
  95. position: 0
  96. color: "transparent"
  97. }
  98. GradientStop {
  99. position: 0.5
  100. color: "#34495e"
  101. }
  102. GradientStop {
  103. position: 1
  104. color: "transparent"
  105. }
  106. }
  107. }
  108. RowLayout {
  109. spacing: 8
  110. Layout.alignment: Qt.AlignVCenter
  111. Label {
  112. text: "Speed:"
  113. visible: !topRoot.compact
  114. color: "#ecf0f1"
  115. font.pixelSize: 14
  116. font.bold: true
  117. verticalAlignment: Text.AlignVCenter
  118. }
  119. Row {
  120. id: speedRow
  121. property var options: [0.5, 1, 2]
  122. spacing: 8
  123. visible: !topRoot.compact
  124. ButtonGroup {
  125. id: speedGroup
  126. }
  127. Repeater {
  128. model: speedRow.options
  129. delegate: Button {
  130. Layout.minimumWidth: 48
  131. width: 56
  132. height: Math.min(34, topPanel.height - 16)
  133. checkable: true
  134. enabled: !topRoot.gameIsPaused
  135. checked: (topRoot.currentSpeed === modelData) && !topRoot.gameIsPaused
  136. focusPolicy: Qt.NoFocus
  137. text: modelData + "x"
  138. ButtonGroup.group: speedGroup
  139. onClicked: topRoot.speedChanged(modelData)
  140. background: Rectangle {
  141. color: parent.checked ? "#27ae60" : parent.hovered ? "#34495e" : "#2c3e50"
  142. radius: 6
  143. border.color: parent.checked ? "#229954" : "#1a252f"
  144. border.width: 1
  145. }
  146. contentItem: Text {
  147. text: parent.text
  148. font.pixelSize: 13
  149. font.bold: true
  150. color: parent.enabled ? "#ecf0f1" : "#7f8c8d"
  151. horizontalAlignment: Text.AlignHCenter
  152. verticalAlignment: Text.AlignVCenter
  153. }
  154. }
  155. }
  156. }
  157. ComboBox {
  158. id: speedCombo
  159. visible: topRoot.compact
  160. Layout.preferredWidth: 120
  161. model: ["0.5x", "1x", "2x"]
  162. currentIndex: topRoot.currentSpeed === 0.5 ? 0 : topRoot.currentSpeed === 1 ? 1 : 2
  163. enabled: !topRoot.gameIsPaused
  164. font.pixelSize: 13
  165. onActivated: function(i) {
  166. var v = i === 0 ? 0.5 : (i === 1 ? 1 : 2);
  167. topRoot.speedChanged(v);
  168. }
  169. }
  170. }
  171. Rectangle {
  172. width: 2
  173. Layout.fillHeight: true
  174. radius: 1
  175. visible: !topRoot.compact
  176. gradient: Gradient {
  177. GradientStop {
  178. position: 0
  179. color: "transparent"
  180. }
  181. GradientStop {
  182. position: 0.5
  183. color: "#34495e"
  184. }
  185. GradientStop {
  186. position: 1
  187. color: "transparent"
  188. }
  189. }
  190. }
  191. RowLayout {
  192. spacing: 8
  193. Layout.alignment: Qt.AlignVCenter
  194. Label {
  195. text: "Camera:"
  196. visible: !topRoot.compact
  197. color: "#ecf0f1"
  198. font.pixelSize: 14
  199. font.bold: true
  200. verticalAlignment: Text.AlignVCenter
  201. }
  202. Button {
  203. id: followBtn
  204. Layout.preferredWidth: topRoot.compact ? 44 : 80
  205. Layout.preferredHeight: Math.min(34, topPanel.height - 16)
  206. checkable: true
  207. text: topRoot.compact ? "\u2609" : "Follow"
  208. font.pixelSize: 13
  209. focusPolicy: Qt.NoFocus
  210. onToggled: {
  211. if (typeof game !== 'undefined' && game.cameraFollowSelection)
  212. game.cameraFollowSelection(checked);
  213. }
  214. background: Rectangle {
  215. color: parent.checked ? "#3498db" : parent.hovered ? "#34495e" : "#2c3e50"
  216. radius: 6
  217. border.color: parent.checked ? "#2980b9" : "#1a252f"
  218. border.width: 1
  219. }
  220. contentItem: Text {
  221. text: parent.text
  222. font: parent.font
  223. color: "#ecf0f1"
  224. horizontalAlignment: Text.AlignHCenter
  225. verticalAlignment: Text.AlignVCenter
  226. }
  227. }
  228. Button {
  229. id: resetBtn
  230. Layout.preferredWidth: topRoot.compact ? 44 : 80
  231. Layout.preferredHeight: Math.min(34, topPanel.height - 16)
  232. text: topRoot.compact ? "\u21BA" : "Reset"
  233. font.pixelSize: 13
  234. focusPolicy: Qt.NoFocus
  235. onClicked: {
  236. if (typeof game !== 'undefined' && game.resetCamera)
  237. game.resetCamera();
  238. }
  239. background: Rectangle {
  240. color: parent.hovered ? "#34495e" : "#2c3e50"
  241. radius: 6
  242. border.color: "#1a252f"
  243. border.width: 1
  244. }
  245. contentItem: Text {
  246. text: parent.text
  247. font: parent.font
  248. color: "#ecf0f1"
  249. horizontalAlignment: Text.AlignHCenter
  250. verticalAlignment: Text.AlignVCenter
  251. }
  252. }
  253. }
  254. }
  255. Item {
  256. Layout.fillWidth: true
  257. }
  258. RowLayout {
  259. id: rightGroup
  260. spacing: 12
  261. Layout.alignment: Qt.AlignVCenter
  262. Row {
  263. id: statsRow
  264. spacing: 10
  265. Layout.alignment: Qt.AlignVCenter
  266. Label {
  267. id: playerLbl
  268. text: "🗡️ " + (typeof game !== 'undefined' ? game.playerTroopCount : 0) + " / " + (typeof game !== 'undefined' ? game.maxTroopsPerPlayer : 0)
  269. color: {
  270. if (typeof game === 'undefined')
  271. return "#95a5a6";
  272. var count = game.playerTroopCount;
  273. var max = game.maxTroopsPerPlayer;
  274. if (count >= max)
  275. return "#e74c3c";
  276. if (count >= max * 0.8)
  277. return "#f39c12";
  278. return "#2ecc71";
  279. }
  280. font.pixelSize: 14
  281. font.bold: true
  282. elide: Text.ElideRight
  283. verticalAlignment: Text.AlignVCenter
  284. }
  285. Rectangle {
  286. width: 2
  287. height: 24
  288. color: "#34495e"
  289. opacity: 0.5
  290. visible: !topRoot.compact
  291. }
  292. Label {
  293. id: ownersLbl
  294. text: {
  295. if (typeof game === 'undefined')
  296. return "Players: 0";
  297. var owners = game.ownerInfo;
  298. var playerCount = 0;
  299. var aiCount = 0;
  300. for (var i = 0; i < owners.length; i++) {
  301. if (owners[i].type === "Player")
  302. playerCount++;
  303. else if (owners[i].type === "AI")
  304. aiCount++;
  305. }
  306. return "👥 " + playerCount + " | 🤖 " + aiCount;
  307. }
  308. color: "#ecf0f1"
  309. font.pixelSize: 13
  310. font.bold: false
  311. visible: !topRoot.compact
  312. verticalAlignment: Text.AlignVCenter
  313. ToolTip.visible: ma.containsMouse
  314. ToolTip.delay: 500
  315. ToolTip.text: {
  316. if (typeof game === 'undefined')
  317. return "";
  318. var owners = game.ownerInfo;
  319. var tip = "Owner IDs:\n";
  320. for (var i = 0; i < owners.length; i++) {
  321. tip += owners[i].id + ": " + owners[i].name + " (" + owners[i].type + ")";
  322. if (owners[i].isLocal)
  323. tip += " [You]";
  324. tip += "\n";
  325. }
  326. return tip;
  327. }
  328. MouseArea {
  329. id: ma
  330. anchors.fill: parent
  331. hoverEnabled: true
  332. }
  333. }
  334. Label {
  335. id: enemyLbl
  336. text: "💀 " + (typeof game !== 'undefined' ? game.enemyTroopsDefeated : 0)
  337. color: "#ecf0f1"
  338. font.pixelSize: 14
  339. elide: Text.ElideRight
  340. verticalAlignment: Text.AlignVCenter
  341. }
  342. }
  343. Item {
  344. id: miniWrap
  345. visible: !topRoot.ultraCompact
  346. Layout.preferredWidth: Math.round(topPanel.height * 2.2)
  347. Layout.minimumWidth: Math.round(topPanel.height * 1.6)
  348. Layout.preferredHeight: topPanel.height - 8
  349. Rectangle {
  350. anchors.fill: parent
  351. color: "#0f1a22"
  352. radius: 8
  353. border.width: 2
  354. border.color: "#3498db"
  355. Rectangle {
  356. anchors.fill: parent
  357. anchors.margins: 3
  358. radius: 6
  359. color: "#0a0f14"
  360. Label {
  361. anchors.centerIn: parent
  362. text: "MINIMAP"
  363. color: "#3f5362"
  364. font.pixelSize: 12
  365. font.bold: true
  366. }
  367. }
  368. }
  369. }
  370. }
  371. }
  372. }
  373. }