Main.qml (7920B)
1 import QtQuick 2 import QtQuick.Controls 3 import QtQuick.Layouts 4 5 Window { 6 id: mainWindow 7 8 width: 800 9 height: 600 10 visible: true 11 title: "Nissy 3.0 - Preview" 12 13 SplitView { 14 id: splitView 15 anchors.fill: parent 16 orientation: Qt.Vertical 17 18 handle: Rectangle { 19 implicitHeight: 3 20 color: SplitHandle.hovered ? "black" : "#AAAAAA" 21 } 22 23 component MyScrollBar: ScrollBar { 24 orientation: Qt.Vertical 25 size: parent.height 26 policy: ScrollBar.AlwaysOn 27 anchors.right: parent.right 28 anchors.top: parent.top 29 anchors.bottom: parent.bottom 30 contentItem: Rectangle { 31 implicitWidth: 4 32 radius: implicitWidth/2 33 color: "black" 34 } 35 background: Rectangle { 36 implicitWidth: 4 37 radius: implicitWidth/2 38 color: "#AAAAAA" 39 } 40 } 41 42 ColumnLayout { 43 id: mainArea 44 45 property alias scramble: scrambleRow.scramble 46 property alias solver: solverCfg.solver 47 property alias minmoves: solverCfg.minmoves 48 property alias maxmoves: solverCfg.maxmoves 49 property alias maxsolutions: solverCfg.maxsolutions 50 property alias optimal: solverCfg.optimal 51 property alias sols: sols.text 52 property alias solsHeader: solsHeader.text 53 54 property bool solutionsLoading: false 55 56 anchors.top: parent.top 57 anchors.left: parent.left 58 anchors.right: parent.right 59 anchors.bottom: logView.top 60 anchors.margins: 6 61 spacing: 10 62 63 SplitView.minimumHeight: 180 64 SplitView.preferredHeight: 500 65 66 component Separator: Rectangle { 67 height: 1 68 Layout.fillWidth: true 69 color: "black" 70 } 71 72 component OptionalValue: RowLayout { 73 property alias currentValue: valueRect.value 74 property alias from: spinBox.from 75 property alias to: spinBox.to 76 property alias defaultValue: spinBox.value 77 property alias defaultEnabled: sw.checked 78 property alias label: sw.text 79 property int defaultSavedValue: 1 80 property int savedValue: defaultSavedValue 81 82 Switch { 83 id: sw 84 85 checked: true 86 87 onToggled: () => { 88 if (checked) { 89 currentValue = savedValue 90 } else { 91 savedValue = currentValue 92 currentValue = spinBox.to 93 } 94 } 95 } 96 97 Rectangle { 98 id: valueRect 99 100 property alias enabled: sw.checked 101 property alias value: spinBox.value 102 103 width: 65 104 height: 20 105 106 SpinBox { 107 id: spinBox 108 109 width: parent.width 110 editable: true 111 enabled: parent.enabled 112 } 113 } 114 } 115 116 ColumnLayout { 117 id: scrambleRow 118 119 property alias scramble: scrambleRowLayout.scramble 120 121 RowLayout { 122 id: scrambleRowLayout 123 124 property alias scramble: scrambleEditor.text 125 126 spacing: 6 127 128 TextField { 129 id: scrambleEditor 130 131 placeholderText: "Enter scramble here" 132 Layout.fillWidth: true 133 padding: 4 134 135 readonly property bool empty: text.trim().length == 0 136 readonly property bool valid: NissyAdapter.isValidScramble(text) 137 138 onAccepted: if (!empty && valid) submitScramble() 139 } 140 141 Button { 142 id: solveButton 143 144 enabled: !scrambleEditor.empty && scrambleEditor.valid && 145 !mainArea.solutionsLoading 146 text: "Solve!" 147 148 onPressed: submitScramble() 149 } 150 } 151 152 Label { 153 id: invalidScrambleWarning 154 text: scrambleEditor.empty || scrambleEditor.valid ? 155 "" : "Invalid Scramble" 156 } 157 } 158 159 Separator {} 160 161 ColumnLayout { 162 id: solverCfg 163 164 property alias minmoves: minMaxRow.min 165 property alias maxmoves: minMaxRow.max 166 property alias maxsolutions: maxSols.currentValue 167 property alias optimal: optimal.currentValue 168 property alias solver: solverRow.solver 169 170 RowLayout { 171 id: solverRow 172 173 property alias solver: comboBox.currentValue 174 175 Label { text: "Solver" } 176 ComboBox { 177 id: comboBox 178 179 currentIndex: 3 180 textRole: "text" 181 valueRole: "name" 182 implicitContentWidthPolicy: ComboBox.WidestTextWhenCompleted 183 184 model: ListModel { 185 ListElement { text: "h48 h=0, k=4 (59 Mb)"; name: "h48h0k4" } 186 ListElement { text: "h48 h=1, k=2 (115 Mb)"; name: "h48h1k2" } 187 ListElement { text: "h48 h=2, k=2 (171 Mb)"; name: "h48h2k2" } 188 ListElement { text: "h48 h=3, k=2 (283 Mb)"; name: "h48h3k2" } 189 ListElement { text: "h48 h=7, k=2 (3.6 Gb)"; name: "h48h7k2" } 190 } 191 } 192 } 193 194 RowLayout { 195 id: minMaxRow 196 197 property alias min: slider.min 198 property alias max: slider.max 199 200 Rectangle { 201 width: 100 202 height: 20 203 Label { text: "Min moves: " + slider.min } 204 } 205 RangeSlider { 206 id: slider 207 from: 0 208 to: 20 209 first.value: from 210 second.value: to 211 stepSize: 1 212 snapMode: RangeSlider.SnapAlways 213 214 readonly property int min: Math.round(first.value) 215 readonly property int max: Math.round(second.value) 216 } 217 Rectangle { 218 width: 100 219 height: 20 220 Label { text: "Max moves: " + slider.max } 221 } 222 } 223 224 OptionalValue { 225 id: optimal 226 227 label: "Above optimal by at most" 228 from: 0 229 to: 20 230 defaultValue: 20 231 defaultEnabled: false 232 defaultSavedValue: 0 233 } 234 235 OptionalValue { 236 id: maxSols 237 238 label: "Limit number of solutions to" 239 from: 1 240 to: 999 241 defaultValue: 1 242 defaultEnabled: true 243 defaultSavedValue: 1 244 } 245 } 246 247 Separator {} 248 249 StackLayout { 250 Layout.maximumHeight: 30 251 currentIndex: mainArea.solutionsLoading ? 0 : 1 252 253 BusyIndicator { running: mainArea.solutionsLoading } 254 Label { id: solsHeader } 255 } 256 257 ScrollView { 258 Layout.fillHeight: true 259 Layout.fillWidth: true 260 Layout.bottomMargin: 10 261 ScrollBar.vertical: MyScrollBar {} 262 263 TextEdit { 264 id: sols 265 readOnly: true 266 font.family: "Monospace" 267 } 268 } 269 } 270 271 ScrollView { 272 id: logView 273 274 property alias text: logText.text 275 276 anchors.left: parent.left 277 anchors.right: parent.right 278 anchors.bottom: parent.bottom 279 anchors.margins: 6 280 281 SplitView.preferredHeight: 300 282 283 background: Rectangle { 284 color: "#404040" 285 radius: 4 286 } 287 288 ScrollBar.vertical: MyScrollBar { 289 id: scrollBar 290 position: 1.0 - size 291 } 292 Label { 293 id: logText 294 295 font.family: "Monospace" 296 color: "white" 297 } 298 } 299 } 300 301 function submitScramble() { 302 mainArea.solutionsLoading = true; 303 mainArea.solsHeader = "" 304 mainArea.sols = "" 305 logView.text = "" 306 NissyAdapter.requestSolve( 307 mainArea.scramble, 308 mainArea.solver, 309 mainArea.minmoves, 310 mainArea.maxmoves, 311 mainArea.maxsolutions, 312 mainArea.optimal 313 ) 314 } 315 316 Connections { 317 target: NissyAdapter 318 function onSolutionsReady(header, sols) { 319 mainArea.solutionsLoading = false 320 mainArea.solsHeader = header 321 mainArea.sols = sols 322 } 323 function onSolverError(msg) { 324 mainArea.solutionsLoading = false 325 mainArea.solsHeader = msg 326 mainArea.sols = "" 327 } 328 function onAppendLog(msg) { 329 logView.text += msg 330 } 331 } 332 }