SaveGamePanel.qml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. import QtQml 2.15
  2. import QtQuick 2.15
  3. import QtQuick.Controls 2.15
  4. import QtQuick.Layouts 1.3
  5. import StandardOfIron 1.0
  6. Item {
  7. id: root
  8. signal cancelled()
  9. signal saveRequested(string slotName)
  10. anchors.fill: parent
  11. z: 25
  12. onVisibleChanged: {
  13. if (!visible)
  14. return ;
  15. if (typeof saveListModel !== 'undefined')
  16. saveListModel.loadFromGame();
  17. if (typeof saveNameField !== 'undefined' && saveNameField)
  18. saveNameField.text = "Save_" + Qt.formatDateTime(new Date(), "yyyy-MM-dd_HH-mm");
  19. }
  20. Keys.onPressed: function(event) {
  21. if (event.key === Qt.Key_Escape) {
  22. root.cancelled();
  23. event.accepted = true;
  24. }
  25. }
  26. Component.onCompleted: {
  27. forceActiveFocus();
  28. }
  29. Connections {
  30. function onSaveSlotsChanged() {
  31. if (typeof saveListModel !== 'undefined')
  32. saveListModel.loadFromGame();
  33. }
  34. target: typeof game !== 'undefined' ? game : null
  35. }
  36. Rectangle {
  37. anchors.fill: parent
  38. color: Theme.dim
  39. }
  40. Rectangle {
  41. id: container
  42. width: Math.min(parent.width * 0.7, 900)
  43. height: Math.min(parent.height * 0.8, 600)
  44. anchors.centerIn: parent
  45. radius: Theme.radiusPanel
  46. color: Theme.panelBase
  47. border.color: Theme.panelBr
  48. border.width: 1
  49. opacity: 0.98
  50. ColumnLayout {
  51. anchors.fill: parent
  52. anchors.margins: Theme.spacingXLarge
  53. spacing: Theme.spacingLarge
  54. RowLayout {
  55. Layout.fillWidth: true
  56. spacing: Theme.spacingMedium
  57. Label {
  58. text: qsTr("Save Game")
  59. color: Theme.textMain
  60. font.pointSize: Theme.fontSizeHero
  61. font.bold: true
  62. Layout.fillWidth: true
  63. }
  64. Button {
  65. text: qsTr("Cancel")
  66. onClicked: root.cancelled()
  67. }
  68. }
  69. Rectangle {
  70. Layout.fillWidth: true
  71. Layout.preferredHeight: 1
  72. color: Theme.border
  73. }
  74. RowLayout {
  75. Layout.fillWidth: true
  76. spacing: Theme.spacingMedium
  77. Label {
  78. text: qsTr("Save Name:")
  79. color: Theme.textSub
  80. font.pointSize: Theme.fontSizeMedium
  81. }
  82. TextField {
  83. id: saveNameField
  84. Layout.fillWidth: true
  85. placeholderText: qsTr("Enter save name...")
  86. text: "Save_" + Qt.formatDateTime(new Date(), "yyyy-MM-dd_HH-mm")
  87. font.pointSize: Theme.fontSizeMedium
  88. color: Theme.textMain
  89. background: Rectangle {
  90. color: Theme.cardBase
  91. border.color: saveNameField.activeFocus ? Theme.accent : Theme.border
  92. border.width: 1
  93. radius: Theme.radiusMedium
  94. }
  95. }
  96. Button {
  97. text: qsTr("Save")
  98. enabled: saveNameField.text.length > 0
  99. highlighted: true
  100. onClicked: {
  101. if (saveListModel.slotExists(saveNameField.text)) {
  102. confirmOverwriteDialog.slotName = saveNameField.text;
  103. confirmOverwriteDialog.open();
  104. } else {
  105. root.saveRequested(saveNameField.text);
  106. }
  107. }
  108. }
  109. }
  110. Label {
  111. text: qsTr("Existing Saves")
  112. color: Theme.textSub
  113. font.pointSize: Theme.fontSizeMedium
  114. }
  115. Rectangle {
  116. Layout.fillWidth: true
  117. Layout.fillHeight: true
  118. color: Theme.cardBase
  119. border.color: Theme.border
  120. border.width: 1
  121. radius: Theme.radiusLarge
  122. ScrollView {
  123. anchors.fill: parent
  124. anchors.margins: Theme.spacingSmall
  125. clip: true
  126. ListView {
  127. id: saveListView
  128. spacing: Theme.spacingSmall
  129. model: ListModel {
  130. id: saveListModel
  131. function slotExists(name) {
  132. for (var i = 0; i < count; i++) {
  133. if (get(i).slotName === name)
  134. return true;
  135. }
  136. return false;
  137. }
  138. function loadFromGame() {
  139. clear();
  140. if (typeof game === 'undefined' || !game.get_save_slots)
  141. return ;
  142. var slots = game.get_save_slots();
  143. for (var i = 0; i < slots.length; i++) {
  144. append({
  145. "slotName": slots[i].slotName || slots[i].name,
  146. "title": slots[i].title || slots[i].name || slots[i].slotName || "Untitled Save",
  147. "timestamp": slots[i].timestamp,
  148. "map_name": slots[i].map_name || "Unknown Map",
  149. "thumbnail": slots[i].thumbnail || ""
  150. });
  151. }
  152. }
  153. Component.onCompleted: {
  154. loadFromGame();
  155. }
  156. }
  157. delegate: Rectangle {
  158. width: saveListView.width
  159. height: 80
  160. color: mouseArea.containsMouse ? Theme.hoverBg : Qt.rgba(0, 0, 0, 0)
  161. radius: Theme.radiusMedium
  162. border.color: Theme.cardBorder
  163. border.width: 1
  164. RowLayout {
  165. anchors.fill: parent
  166. anchors.margins: Theme.spacingMedium
  167. spacing: Theme.spacingMedium
  168. Rectangle {
  169. id: thumbnailContainer
  170. Layout.preferredWidth: 96
  171. Layout.preferredHeight: 64
  172. radius: Theme.radiusSmall
  173. color: Theme.cardBase
  174. border.color: Theme.cardBorder
  175. border.width: 1
  176. clip: true
  177. Image {
  178. id: thumbnailImage
  179. anchors.fill: parent
  180. anchors.margins: 2
  181. fillMode: Image.PreserveAspectCrop
  182. source: model.thumbnail && model.thumbnail.length > 0 ? "data:image/png;base64," + model.thumbnail : ""
  183. visible: source !== ""
  184. }
  185. Label {
  186. anchors.centerIn: parent
  187. visible: !thumbnailImage.visible
  188. text: qsTr("No Preview")
  189. color: Theme.textHint
  190. font.pointSize: Theme.fontSizeTiny
  191. }
  192. }
  193. ColumnLayout {
  194. Layout.fillWidth: true
  195. spacing: Theme.spacingTiny
  196. Label {
  197. text: model.title
  198. color: Theme.textMain
  199. font.pointSize: Theme.fontSizeLarge
  200. font.bold: true
  201. Layout.fillWidth: true
  202. elide: Label.ElideRight
  203. }
  204. Label {
  205. text: qsTr("Slot: %1").arg(model.slotName)
  206. color: Theme.textSub
  207. font.pointSize: Theme.fontSizeSmall
  208. Layout.fillWidth: true
  209. elide: Label.ElideRight
  210. }
  211. Label {
  212. text: model.map_name
  213. color: Theme.textSub
  214. font.pointSize: Theme.fontSizeSmall
  215. Layout.fillWidth: true
  216. elide: Label.ElideRight
  217. }
  218. Label {
  219. text: qsTr("Last saved: %1").arg(Qt.formatDateTime(new Date(model.timestamp), "yyyy-MM-dd hh:mm:ss"))
  220. color: Theme.textHint
  221. font.pointSize: Theme.fontSizeSmall
  222. Layout.fillWidth: true
  223. elide: Label.ElideRight
  224. }
  225. }
  226. Button {
  227. text: qsTr("Overwrite")
  228. onClicked: {
  229. confirmOverwriteDialog.slotName = model.slotName;
  230. confirmOverwriteDialog.open();
  231. }
  232. }
  233. }
  234. MouseArea {
  235. id: mouseArea
  236. anchors.fill: parent
  237. hoverEnabled: true
  238. onClicked: {
  239. saveNameField.text = model.slotName;
  240. }
  241. }
  242. }
  243. }
  244. }
  245. }
  246. }
  247. }
  248. Dialog {
  249. id: confirmOverwriteDialog
  250. property string slotName: ""
  251. anchors.centerIn: parent
  252. width: Math.min(parent.width * 0.5, 400)
  253. title: qsTr("Confirm Overwrite")
  254. modal: true
  255. standardButtons: Dialog.Yes | Dialog.No
  256. onAccepted: {
  257. root.saveRequested(slotName);
  258. }
  259. contentItem: Rectangle {
  260. color: Theme.cardBase
  261. implicitHeight: warningText.implicitHeight + 40
  262. ColumnLayout {
  263. anchors.fill: parent
  264. anchors.margins: Theme.spacingMedium
  265. spacing: Theme.spacingMedium
  266. Label {
  267. id: warningText
  268. text: qsTr("Are you sure you want to overwrite the save:\n\"%1\"?").arg(confirmOverwriteDialog.slotName)
  269. color: Theme.textMain
  270. wrapMode: Text.WordWrap
  271. Layout.fillWidth: true
  272. font.pointSize: Theme.fontSizeMedium
  273. }
  274. }
  275. }
  276. }
  277. }