feat: make gui?
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
Round 1
|
||||||
|
- Item name is announced in chat
|
||||||
|
- First person to find in inventory and send wins 1 point
|
||||||
|
|
||||||
|
Round 2
|
||||||
|
- Clues are given that relate to the item
|
||||||
|
- Person that guess the item win 1 point
|
||||||
|
- Then wait 1 min to showcase highest quantity
|
||||||
|
- Person with the most item quantity win 1 point
|
||||||
|
|
||||||
|
### Items
|
||||||
|
|
||||||
|
Round 1
|
||||||
|
1. Hero's Radiance
|
||||||
|
2. Jellyfish
|
||||||
|
3. Medal of Light (quest)
|
||||||
|
4. S2 Exquisite box
|
||||||
|
5. Focus Potion
|
||||||
|
6. Toy - ee chan fireworks
|
||||||
|
|
||||||
|
Round 2
|
||||||
|
1. Mixing Agent
|
||||||
|
2. Cheer up treat
|
||||||
|
3. Gold quicksand
|
||||||
|
4. Emerald apple
|
||||||
|
5. Honey
|
||||||
|
6. Slumberdream feathers
|
||||||
|
7. Lionfish
|
||||||
@@ -21,6 +21,7 @@ __all__ = (
|
|||||||
"ChitChatNtf",
|
"ChitChatNtf",
|
||||||
"HypertextVariant",
|
"HypertextVariant",
|
||||||
"decode_placeholder",
|
"decode_placeholder",
|
||||||
|
"ITEM_MAPPINGS",
|
||||||
"get_item_name"
|
"get_item_name"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -75,11 +76,11 @@ def decode_placeholder(placeholder: PlaceHolder) -> SupportedPlaceholders:
|
|||||||
return decoder.FromString(placeholder.bytesContent) # type: ignore[attr-defined]
|
return decoder.FromString(placeholder.bytesContent) # type: ignore[attr-defined]
|
||||||
|
|
||||||
|
|
||||||
ITEM_NAME = pl.read_json("./ref/StarResonanceData/ztable/ItemTable.json").transpose().unnest()
|
ITEM_MAPPINGS = pl.read_json("./ref/StarResonanceData/ztable/ItemTable.json").transpose().unnest()
|
||||||
|
|
||||||
|
|
||||||
def get_item_name(item_config_id: int) -> str | None:
|
def get_item_name(item_config_id: int) -> str | None:
|
||||||
try:
|
try:
|
||||||
return ITEM_NAME.filter(pl.col.Id == item_config_id).select("Name").item()
|
return ITEM_MAPPINGS.filter(pl.col.Id == item_config_id).select("Name").item()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ class Game:
|
|||||||
self.scapy = get_sniffer(sniffer)
|
self.scapy = get_sniffer(sniffer)
|
||||||
self.scapy.start()
|
self.scapy.start()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self) -> State:
|
||||||
|
return self._state
|
||||||
|
|
||||||
def set_state(self, state: State) -> None:
|
def set_state(self, state: State) -> None:
|
||||||
self._state = state
|
self._state = state
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import Qt.labs.qmlmodels
|
||||||
|
|
||||||
|
import InventoryWars
|
||||||
|
import Style
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
color: UIStyle.background
|
||||||
|
|
||||||
|
required property ListModel rounds
|
||||||
|
property QtObject selectedRound
|
||||||
|
|
||||||
|
signal roundSelected()
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 20
|
||||||
|
spacing: 20
|
||||||
|
|
||||||
|
Item { Layout.fillHeight: true }
|
||||||
|
|
||||||
|
Image {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.preferredWidth: 256
|
||||||
|
|
||||||
|
source: "images/modules.png"
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
font.pixelSize: UIStyle.fontSizeXL
|
||||||
|
color: UIStyle.titletextColor
|
||||||
|
|
||||||
|
text: "Start a round"
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: roundSelect
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
model: root.rounds
|
||||||
|
textRole: "name"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
buttonColor: UIStyle.highlightColor
|
||||||
|
buttonBorderColor: UIStyle.highlightBorderColor
|
||||||
|
textColor: UIStyle.textColor
|
||||||
|
|
||||||
|
text: "Start"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.selectedRound = rounds.get(roundSelect.currentIndex)
|
||||||
|
roundSelected()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TableView {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
columnSpacing: 1
|
||||||
|
rowSpacing: 1
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
border.width: 1
|
||||||
|
implicitHeight: 50
|
||||||
|
implicitWidth: 100
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: display
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model: TableModel {
|
||||||
|
rows: [
|
||||||
|
{
|
||||||
|
User: "me",
|
||||||
|
Score: "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
TableModelColumn {
|
||||||
|
display: "User"
|
||||||
|
}
|
||||||
|
|
||||||
|
TableModelColumn {
|
||||||
|
display: "Score"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillHeight: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import Qt.labs.qmlmodels
|
||||||
|
|
||||||
|
import InventoryWars
|
||||||
|
|
||||||
|
ApplicationWindow {
|
||||||
|
height: 480
|
||||||
|
title: "Inventory Wars"
|
||||||
|
visible: true
|
||||||
|
width: 640
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: rounds
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
name: "Round 1"
|
||||||
|
mode: GameService.GameScoring.FirstGuess
|
||||||
|
item_id: 100
|
||||||
|
item_name: "Item 1"
|
||||||
|
item_image: ""
|
||||||
|
clue: "Clue 1"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
name: "Round 2"
|
||||||
|
mode: GameService.GameScoring.FirstGuess
|
||||||
|
item_id: 100
|
||||||
|
item_name: "Item 2"
|
||||||
|
item_image: ""
|
||||||
|
clue: "Clue 2"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
name: "Round 3"
|
||||||
|
mode: GameService.GameScoring.FirstGuess
|
||||||
|
item_id: 100
|
||||||
|
item_name: "Item 3"
|
||||||
|
item_image: ""
|
||||||
|
clue: "Clue 3"
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
name: "Round 4"
|
||||||
|
mode: GameService.GameScoring.FirstGuess
|
||||||
|
item_id: 100
|
||||||
|
item_name: "Item 4"
|
||||||
|
item_image: ""
|
||||||
|
clue: "Clue 4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IdleView {
|
||||||
|
id: idleView
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
rounds: rounds
|
||||||
|
selectedRound: rounds.get(0)
|
||||||
|
onRoundSelected: {
|
||||||
|
idleView.visible = false
|
||||||
|
ongoingView.start()
|
||||||
|
ongoingView.visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OngoingView {
|
||||||
|
id: ongoingView
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
visible: false
|
||||||
|
round: idleView.selectedRound
|
||||||
|
gameService: gameService
|
||||||
|
onClose: {
|
||||||
|
idleView.visible = true
|
||||||
|
ongoingView.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameService {
|
||||||
|
id: gameService
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Shapes
|
||||||
|
import Qt.labs.qmlmodels
|
||||||
|
|
||||||
|
import InventoryWars
|
||||||
|
import Style
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
color: UIStyle.background
|
||||||
|
|
||||||
|
required property GameService gameService
|
||||||
|
required property QtObject round
|
||||||
|
property QtObject guessed: QtObject {
|
||||||
|
property string username
|
||||||
|
property double seconds
|
||||||
|
}
|
||||||
|
property QtObject highest: QtObject {
|
||||||
|
property string username
|
||||||
|
property int count
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
gameService.start(round.item_id, round.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
signal close()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.gameService
|
||||||
|
|
||||||
|
function onGuessed(username: str, seconds: double) {
|
||||||
|
root.guessed.username = username
|
||||||
|
root.guessed.seconds = seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
function onHighest(username: str, count: int) {
|
||||||
|
root.highest.username = username
|
||||||
|
root.highest.count = count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.bottomMargin: 10
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
ToolBar {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumHeight: 35
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 5
|
||||||
|
anchors.rightMargin: 5
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.preferredWidth: 25
|
||||||
|
Layout.preferredHeight: 25
|
||||||
|
|
||||||
|
icon.name: "back"
|
||||||
|
icon.source: "icons/x.svg"
|
||||||
|
|
||||||
|
onClicked: root.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||||
|
|
||||||
|
font.pixelSize: UIStyle.fontSizeM
|
||||||
|
font.bold: true
|
||||||
|
color: UIStyle.titletextColor
|
||||||
|
|
||||||
|
text: root.round.name
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillHeight: true }
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
font.pixelSize: UIStyle.fontSizeL
|
||||||
|
font.bold: true
|
||||||
|
color: UIStyle.titletextColor
|
||||||
|
|
||||||
|
text: "Current Item:"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
font.pixelSize: UIStyle.fontSizeM
|
||||||
|
color: UIStyle.textColor
|
||||||
|
|
||||||
|
text: root.gameService.state == GameService.Ongoing ? "???" : root.round.item_name
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.preferredWidth: 256
|
||||||
|
Layout.preferredHeight: 256
|
||||||
|
|
||||||
|
source: root.gameService.state == GameService.Ongoing ? "images/unknown.png" : root.round.item_image
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
font.pixelSize: UIStyle.fontSizeXL
|
||||||
|
font.bold: true
|
||||||
|
color: UIStyle.textColor
|
||||||
|
|
||||||
|
text: ""
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: elapsedTimer
|
||||||
|
interval: 10
|
||||||
|
running: root.gameService.state != GameService.Ended
|
||||||
|
repeat: true
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
parent.text = root.gameService.elapsedSeconds.toFixed(2) + "s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
font.pixelSize: UIStyle.fontSizeM
|
||||||
|
font.bold: true
|
||||||
|
color: UIStyle.textColor
|
||||||
|
visible: root.gameService.state == GameService.GameState.Hidden
|
||||||
|
|
||||||
|
text: "Clue: " + root.round.clue
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
font.pixelSize: UIStyle.fontSizeM
|
||||||
|
font.bold: true
|
||||||
|
color: UIStyle.textColor
|
||||||
|
visible: root.gameService.state != GameService.GameState.Hidden
|
||||||
|
|
||||||
|
text: "Fastest guess: " + root.guessed.seconds + "s (by " + root.guessed.username + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
font.pixelSize: UIStyle.fontSizeM
|
||||||
|
font.bold: true
|
||||||
|
color: UIStyle.textColor
|
||||||
|
visible: root.gameService.state != GameService.GameState.Hidden && root.round.mode == GameService.GameScoring.FirstGuessThenHighestAmount
|
||||||
|
|
||||||
|
text: "Highest count: " + root.highest.count + " (by " + root.highest.username + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillHeight: true }
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
visible: root.gameService.state != GameService.GameState.Ended
|
||||||
|
|
||||||
|
text: "End"
|
||||||
|
|
||||||
|
onClicked: root.gameService.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M504.6 148.5C515.9 134.9 514.1 114.7 500.5 103.4C486.9 92.1 466.7 93.9 455.4 107.5L320 270L184.6 107.5C173.3 93.9 153.1 92.1 139.5 103.4C125.9 114.7 124.1 134.9 135.4 148.5L278.3 320L135.4 491.5C124.1 505.1 125.9 525.3 139.5 536.6C153.1 547.9 173.3 546.1 184.6 532.5L320 370L455.4 532.5C466.7 546.1 486.9 547.9 500.5 536.6C514.1 525.3 515.9 505.1 504.6 491.5L361.7 320L504.6 148.5z"/></svg>
|
||||||
|
After Width: | Height: | Size: 613 B |
Binary file not shown.
|
After Width: | Height: | Size: 102 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
module InventoryWars
|
||||||
|
Main 1.0 Main.qml
|
||||||
|
IdleView 1.0 IdleView.qml
|
||||||
|
OngoingView 1.0 OngoingView.qml
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls.impl
|
||||||
|
import QtQuick.Templates as T
|
||||||
|
|
||||||
|
T.Button {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
property alias buttonColor: rect.color
|
||||||
|
property alias buttonBorderColor: rect.border.color
|
||||||
|
property alias textColor: label.color
|
||||||
|
|
||||||
|
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||||
|
implicitContentWidth + leftPadding + rightPadding)
|
||||||
|
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||||
|
implicitContentHeight + topPadding + bottomPadding)
|
||||||
|
|
||||||
|
leftPadding: 15
|
||||||
|
rightPadding: 15
|
||||||
|
topPadding: 10
|
||||||
|
bottomPadding: 10
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: rect
|
||||||
|
radius: 8
|
||||||
|
border.color: UIStyle.buttonOutline
|
||||||
|
border.width: 1
|
||||||
|
color: UIStyle.buttonBackground
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.width: 24
|
||||||
|
icon.height: 24
|
||||||
|
icon.color: UIStyle.textColor
|
||||||
|
|
||||||
|
contentItem: IconLabel {
|
||||||
|
id: label
|
||||||
|
spacing: control.spacing
|
||||||
|
mirrored: control.mirrored
|
||||||
|
display: control.display
|
||||||
|
|
||||||
|
icon: control.icon
|
||||||
|
text: control.text
|
||||||
|
font.pixelSize: UIStyle.fontSizeS
|
||||||
|
color: UIStyle.textColor
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
project(qtexamplestyle LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
|
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||||
|
set(INSTALL_EXAMPLESDIR "examples")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quickcontrols/colorpaletteclient/QtExampleStyle")
|
||||||
|
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS Core Gui Quick QuickControls2)
|
||||||
|
|
||||||
|
set_source_files_properties(UIStyle.qml
|
||||||
|
PROPERTIES
|
||||||
|
QT_QML_SINGLETON_TYPE TRUE
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_policy(SET QTP0001 NEW)
|
||||||
|
qt_add_qml_module(qtexamplestyle
|
||||||
|
URI QtExampleStyle
|
||||||
|
PLUGIN_TARGET qtexamplestyle
|
||||||
|
QML_FILES
|
||||||
|
Button.qml
|
||||||
|
Popup.qml
|
||||||
|
UIStyle.qml
|
||||||
|
TextField.qml
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(qtexamplestyle PUBLIC
|
||||||
|
Qt6::Core
|
||||||
|
Qt6::Gui
|
||||||
|
Qt6::Quick
|
||||||
|
Qt6::QuickControls2
|
||||||
|
)
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE AND CMAKE_CROSSCOMPILING)
|
||||||
|
find_package(Qt6 REQUIRED COMPONENTS QuickTemplates2)
|
||||||
|
|
||||||
|
# Work around QTBUG-86533
|
||||||
|
target_link_libraries(qtexamplestyle PRIVATE Qt6::QuickTemplates2)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS qtexamplestyle
|
||||||
|
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||||
|
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||||
|
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||||
|
)
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qmldir
|
||||||
|
DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||||
|
)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (C) 2026 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Templates as T
|
||||||
|
|
||||||
|
T.Label {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
font.pixelSize: UIStyle.fontSizeS
|
||||||
|
|
||||||
|
color: UIStyle.textColor
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Templates as T
|
||||||
|
|
||||||
|
T.Popup {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||||
|
implicitContentWidth + leftPadding + rightPadding)
|
||||||
|
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||||
|
implicitContentHeight + topPadding + bottomPadding)
|
||||||
|
|
||||||
|
leftPadding: 15
|
||||||
|
rightPadding: 15
|
||||||
|
topPadding: 10
|
||||||
|
bottomPadding: 10
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: bg
|
||||||
|
radius: 8
|
||||||
|
border.color: UIStyle.buttonOutline
|
||||||
|
border.width: 2
|
||||||
|
color: UIStyle.background
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Templates as T
|
||||||
|
|
||||||
|
T.TextField {
|
||||||
|
id: control
|
||||||
|
placeholderText: ""
|
||||||
|
|
||||||
|
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, contentWidth + leftPadding + rightPadding)
|
||||||
|
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||||
|
contentHeight + topPadding + bottomPadding)
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
implicitWidth: 200
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
color: control.readOnly
|
||||||
|
? UIStyle.buttonGray
|
||||||
|
: UIStyle.background
|
||||||
|
|
||||||
|
border.color: UIStyle.buttonOutline
|
||||||
|
}
|
||||||
|
|
||||||
|
color: control.readOnly
|
||||||
|
? Qt.rgba(UIStyle.textColor.r,
|
||||||
|
UIStyle.textColor.g,
|
||||||
|
UIStyle.textColor.b,
|
||||||
|
0.6)
|
||||||
|
: UIStyle.textColor
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (C) 2026 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Templates as T
|
||||||
|
|
||||||
|
T.ToolBar {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
implicitHeight: 25
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: UIStyle.buttonBackground
|
||||||
|
Rectangle {
|
||||||
|
height: 1
|
||||||
|
width: parent.width
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
color: UIStyle.buttonOutline
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
height: 1
|
||||||
|
width: parent.width
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
color: UIStyle.buttonOutline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (C) 2026 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls.impl
|
||||||
|
import QtQuick.Templates as T
|
||||||
|
|
||||||
|
T.ToolButton {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
property alias buttonColor: rect.color
|
||||||
|
property alias buttonBorderColor: rect.border.color
|
||||||
|
property alias textColor: label.color
|
||||||
|
|
||||||
|
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||||
|
implicitContentWidth + leftPadding + rightPadding)
|
||||||
|
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||||
|
implicitContentHeight + topPadding + bottomPadding)
|
||||||
|
|
||||||
|
leftPadding: 4
|
||||||
|
rightPadding: 4
|
||||||
|
topPadding: 4
|
||||||
|
bottomPadding: 4
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: rect
|
||||||
|
color: "transparent"
|
||||||
|
border.width: 1
|
||||||
|
radius: 3
|
||||||
|
border.color: control.hovered
|
||||||
|
? UIStyle.buttonOutline
|
||||||
|
: "transparent"
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.width: 15
|
||||||
|
icon.height: 15
|
||||||
|
icon.color: UIStyle.textColor
|
||||||
|
|
||||||
|
contentItem: IconLabel {
|
||||||
|
id: label
|
||||||
|
spacing: control.spacing
|
||||||
|
mirrored: control.mirrored
|
||||||
|
display: control.display
|
||||||
|
|
||||||
|
icon: control.icon
|
||||||
|
text: control.text
|
||||||
|
font.pixelSize: UIStyle.fontSizeS
|
||||||
|
color: UIStyle.textColor
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: uiStyle
|
||||||
|
|
||||||
|
property bool darkMode: (Application.styleHints.colorScheme === Qt.ColorScheme.Dark)
|
||||||
|
|
||||||
|
// Font Sizes
|
||||||
|
readonly property int fontSizeXXS: 8
|
||||||
|
readonly property int fontSizeXS: 10
|
||||||
|
readonly property int fontSizeS: 12
|
||||||
|
readonly property int fontSizeM: 16
|
||||||
|
readonly property int fontSizeL: 20
|
||||||
|
readonly property int fontSizeXL: 24
|
||||||
|
|
||||||
|
// Color Scheme
|
||||||
|
readonly property color colorRed: "#E91E63"
|
||||||
|
|
||||||
|
readonly property color buttonGray: darkMode ? "#808080" : "#f3f3f4"
|
||||||
|
readonly property color buttonGrayPressed: darkMode ? "#707070" : "#cecfd5"
|
||||||
|
readonly property color buttonGrayOutline: darkMode ? "#0D0D0D" : "#999999"
|
||||||
|
|
||||||
|
readonly property color buttonBackground: darkMode ? "#262626" : "#CCCCCC"
|
||||||
|
readonly property color buttonPressed: darkMode ? "#1E1E1E" : "#BEBEC4"
|
||||||
|
readonly property color buttonOutline: darkMode ? "#0D0D0D" : "#999999"
|
||||||
|
|
||||||
|
readonly property color background: darkMode ? "#262626" : "#E6E6E6"
|
||||||
|
readonly property color background1: darkMode ? "#00414A" : "#ceded6"
|
||||||
|
|
||||||
|
readonly property color textOnLightBackground: "#191919"
|
||||||
|
readonly property color textOnDarkBackground: "#E6E6E6"
|
||||||
|
|
||||||
|
readonly property color textColor: darkMode ? "#E6E6E6" : "#191919"
|
||||||
|
readonly property color titletextColor: darkMode ? "#2CDE85" : "#191919"
|
||||||
|
|
||||||
|
readonly property color highlightColor: darkMode ? "#33676E" : "#28C878"
|
||||||
|
readonly property color highlightBorderColor: darkMode ? "#4F8C95" : "#1FA05E"
|
||||||
|
|
||||||
|
function iconPath(baseImagePath) {
|
||||||
|
if (darkMode)
|
||||||
|
return `qrc:/qt/qml/ColorPalette/icons/${baseImagePath}_dark.svg`
|
||||||
|
else
|
||||||
|
return `qrc:/qt/qml/ColorPalette/icons/${baseImagePath}.svg`
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module Style
|
||||||
|
Button 1.0 Button.qml
|
||||||
|
Popup 1.0 Popup.qml
|
||||||
|
TextField 1.0 TextField.qml
|
||||||
|
singleton UIStyle 1.0 UIStyle.qml
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from PySide6.QtCore import QObject, Signal, Slot, Property, QEnum, QAbstractItemModel
|
||||||
|
from PySide6.QtGui import QGuiApplication
|
||||||
|
from PySide6.QtQml import QQmlApplicationEngine, QmlElement
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from star_resonance_tracer.proto.enum_chit_chat_channel_type_pb2 import ChitChatChannelType
|
||||||
|
|
||||||
|
from inventory_wars.game import Game
|
||||||
|
from inventory_wars.models import Base
|
||||||
|
from inventory_wars.scoring import Scoring, FirstGuess, FirstThenHighest
|
||||||
|
from inventory_wars.state import GameOngoing, GameIdle
|
||||||
|
|
||||||
|
QML_IMPORT_NAME = "InventoryWars"
|
||||||
|
QML_IMPORT_MAJOR_VERSION = 1
|
||||||
|
|
||||||
|
engine = create_engine("sqlite:///app.db")
|
||||||
|
Base.metadata.create_all(engine)
|
||||||
|
|
||||||
|
session = Session(engine)
|
||||||
|
|
||||||
|
|
||||||
|
class GameScoring(Enum):
|
||||||
|
FirstGuess = 0
|
||||||
|
FirstGuessThenHighestAmount = 1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def as_scoring(self) -> type[Scoring]:
|
||||||
|
match self:
|
||||||
|
case self.FirstGuess:
|
||||||
|
return FirstGuess
|
||||||
|
case self.FirstGuessThenHighestAmount:
|
||||||
|
return FirstThenHighest
|
||||||
|
case _:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
class GameState(Enum):
|
||||||
|
Hidden = 0
|
||||||
|
Revealed = 1
|
||||||
|
Ended = 3
|
||||||
|
|
||||||
|
@QmlElement
|
||||||
|
class GameService(QObject):
|
||||||
|
QEnum(GameScoring)
|
||||||
|
QEnum(GameState)
|
||||||
|
|
||||||
|
stateChanged = Signal()
|
||||||
|
guessed = Signal(str, float, arguments=["username", "seconds"])
|
||||||
|
highest = Signal(str, int, arguments=["username", "count"])
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self.m_game = Game(session, listening_channels=[ChitChatChannelType.ChannelTeam])
|
||||||
|
self.m_started_at: datetime | None = None
|
||||||
|
self.m_revealed_at: datetime | None = None
|
||||||
|
|
||||||
|
@Slot(int, int)
|
||||||
|
def start(self, item_id: int, mode: int):
|
||||||
|
mode = GameScoring(mode)
|
||||||
|
self.m_game.start(item_id, mode.as_scoring())
|
||||||
|
self.m_started_at = datetime.now()
|
||||||
|
self.m_revealed_at = None
|
||||||
|
self.stateChanged.emit()
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def end(self):
|
||||||
|
self.m_game.end()
|
||||||
|
self.stateChanged.emit()
|
||||||
|
|
||||||
|
@Property(GameState, notify=stateChanged)
|
||||||
|
def state(self) -> GameState:
|
||||||
|
match self.m_game.state:
|
||||||
|
case GameIdle():
|
||||||
|
return GameState.Ended
|
||||||
|
case GameOngoing():
|
||||||
|
if self.m_revealed_at is None:
|
||||||
|
return GameState.Hidden
|
||||||
|
return GameState.Revealed
|
||||||
|
case _:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@Property(float)
|
||||||
|
def elapsedSeconds(self) -> float | None:
|
||||||
|
if self.m_started_at:
|
||||||
|
return (datetime.now() - self.m_started_at).total_seconds()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
|
app = QGuiApplication(sys.argv)
|
||||||
|
|
||||||
|
engine = QQmlApplicationEngine()
|
||||||
|
engine.addImportPath(sys.path[1])
|
||||||
|
engine.loadFromModule("InventoryWars", "Main")
|
||||||
|
if not engine.rootObjects():
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
exit_code = app.exec()
|
||||||
|
del engine
|
||||||
|
sys.exit(exit_code)
|
||||||
Reference in New Issue
Block a user