BIN
image/button/tileicon/about.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
image/button/tileicon/card_overview.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
image/button/tileicon/configure.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
image/button/tileicon/create_room.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
image/button/tileicon/general_overview.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
image/button/tileicon/quit.png
Normal file
After Width: | Height: | Size: 785 B |
BIN
image/button/tileicon/replay.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
image/button/tileicon/rule_summary.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
image/button/tileicon/start_game.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
image/logo/freekill.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
image/logo/gplv3.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
image/logo/lua.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
image/logo/ossl.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
image/logo/qt.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
image/logo/sqlite.png
Normal file
After Width: | Height: | Size: 21 KiB |
|
@ -232,7 +232,32 @@ Fk:loadTranslationTable{
|
|||
["Generals Overview"] = "武将一览",
|
||||
["Cards Overview"] = "卡牌一览",
|
||||
["Scenarios Overview"] = "玩法一览",
|
||||
["Replay"] = "录像",
|
||||
["About"] = "关于",
|
||||
["about_freekill_description"] = "<b>关于FreeKill</b><br/>" ..
|
||||
"以便于DIY为首要目的的开源三国杀游戏。<br/>" ..
|
||||
"<br/>项目链接: https://github.com/Notify-ctrl/FreeKill",
|
||||
["about_qt_description"] = "<b>关于Qt</b><br/>" ..
|
||||
"Qt是一个C++图形界面应用程序开发框架,拥有强大的跨平台能力以及易于使用的API。<br/>" ..
|
||||
"<br/>本程序使用Qt 6.2+,主要利用QtQuick开发UI,同时也使用Qt的网络库开发服务端程序。<br/>" ..
|
||||
"<br/>官网: https://www.qt.io",
|
||||
["about_lua_description"] = "<b>关于Lua</b><br/>" ..
|
||||
"Lua是一种小巧、灵活、高效的脚本语言,广泛用于游戏开发中。<br/>" ..
|
||||
"<br/>本程序使用Lua 5.4,利用其完全实现了整个游戏逻辑。<br/>" ..
|
||||
"<br/>官网: https://www.lua.org",
|
||||
["about_ossl_description"] = "<b>关于OpenSSL</b><br/>" ..
|
||||
"OpenSSL是一个开源包,用来提供安全通信与各种加密支持。<br/>" ..
|
||||
"<br/>本程序目前用到了crypto库,以获得RSA加密算法支持。<br/>" ..
|
||||
"<br/>官网: https://www.openssl.org",
|
||||
["about_gplv3_description"] = "<b>关于GPLv3</b><br/>" ..
|
||||
"GNU通用公共许可协议(简称GPL)是一个广泛使用的自由软件许可证条款,它确保广大用户自由地使用、学习、共享或修改软件。<br/>" ..
|
||||
"<br/>由于Qt是按照GPLv3协议开源的库,与此同时本程序用到的readline库也属于GPLv3库,再加上QSanguosha也是以GPLv3协议开源的软件(从中借鉴了不少代码和思路),因此这个项目也使用GPLv3协议开源。<br/>" ..
|
||||
"<br/>官网: https://gplv3.fsf.org",
|
||||
["about_sqlite_description"] = "<b>关于SQLite</b><br/>" ..
|
||||
"SQLite是一个轻量级的数据库,具有占用资源低、运行效率快、嵌入性好等优点。<br/>" ..
|
||||
"<br/>FreeKill使用sqlite3在服务端保存用户的各种信息。<br/>" ..
|
||||
"<br/>官网: https://www.sqlite.org",
|
||||
|
||||
["Exit Lobby"] = "退出大厅",
|
||||
|
||||
["OK"] = "确定",
|
||||
|
|
80
qml/Pages/About.qml
Normal file
|
@ -0,0 +1,80 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
ListModel {
|
||||
id: aboutModel
|
||||
ListElement { dest: "freekill" }
|
||||
ListElement { dest: "qt" }
|
||||
ListElement { dest: "lua" }
|
||||
ListElement { dest: "gplv3" }
|
||||
ListElement { dest: "sqlite" }
|
||||
ListElement { dest: "ossl" }
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
SwipeView {
|
||||
id: swipe
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
currentIndex: indicator.currentIndex
|
||||
Repeater {
|
||||
model: aboutModel
|
||||
Item {
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
color: "#88888888"
|
||||
radius: 2
|
||||
width: root.width * 0.8
|
||||
height: root.height * 0.8
|
||||
|
||||
Image {
|
||||
id: logo
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
source: AppPath + "/image/logo/" + dest
|
||||
width: parent.width * 0.3
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: logo.right
|
||||
anchors.leftMargin: 16
|
||||
width: parent.width * 0.65
|
||||
text: Backend.translate("about_" + dest + "_description")
|
||||
wrapMode: Text.WordWrap
|
||||
textFormat: Text.RichText
|
||||
font.pixelSize: 18
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PageIndicator {
|
||||
id: indicator
|
||||
|
||||
count: swipe.count
|
||||
currentIndex: swipe.currentIndex
|
||||
interactive: true
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: Backend.translate("Quit")
|
||||
anchors.right: parent.right
|
||||
onClicked: {
|
||||
swipe.opacity = 0;
|
||||
mainStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -69,7 +69,7 @@ Item {
|
|||
RowLayout {
|
||||
anchors.fill: parent
|
||||
Item {
|
||||
Layout.preferredWidth: root.width * 0.7
|
||||
Layout.preferredWidth: root.width * 0.6
|
||||
Layout.fillHeight: true
|
||||
Rectangle {
|
||||
width: parent.width * 0.8
|
||||
|
@ -95,42 +95,58 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Button {
|
||||
GridLayout {
|
||||
flow: GridLayout.TopToBottom
|
||||
rows: 4
|
||||
TileButton {
|
||||
iconSource: "configure"
|
||||
text: Backend.translate("Edit Profile")
|
||||
onClicked: {
|
||||
globalPopup.source = "EditProfile.qml";
|
||||
globalPopup.open();
|
||||
}
|
||||
}
|
||||
Button {
|
||||
TileButton {
|
||||
iconSource: "create_room"
|
||||
text: Backend.translate("Create Room")
|
||||
onClicked: {
|
||||
globalPopup.source = "CreateRoom.qml";
|
||||
globalPopup.open();
|
||||
}
|
||||
}
|
||||
Button {
|
||||
TileButton {
|
||||
iconSource: "general_overview"
|
||||
text: Backend.translate("Generals Overview")
|
||||
onClicked: {
|
||||
mainStack.push(mainWindow.generalsOverviewPage);
|
||||
mainStack.currentItem.loadPackages();
|
||||
}
|
||||
}
|
||||
Button {
|
||||
TileButton {
|
||||
iconSource: "card_overview"
|
||||
text: Backend.translate("Cards Overview")
|
||||
onClicked: {
|
||||
mainStack.push(mainWindow.cardsOverviewPage);
|
||||
mainStack.currentItem.loadPackages();
|
||||
}
|
||||
}
|
||||
Button {
|
||||
TileButton {
|
||||
iconSource: "rule_summary"
|
||||
text: Backend.translate("Scenarios Overview")
|
||||
}
|
||||
Button {
|
||||
text: Backend.translate("About")
|
||||
TileButton {
|
||||
iconSource: "replay"
|
||||
text: Backend.translate("Replay")
|
||||
}
|
||||
Button {
|
||||
TileButton {
|
||||
iconSource: "about"
|
||||
text: Backend.translate("About")
|
||||
onClicked: {
|
||||
mainStack.push(mainWindow.aboutPage);
|
||||
}
|
||||
}
|
||||
TileButton {
|
||||
iconSource: "quit"
|
||||
text: Backend.translate("Exit Lobby")
|
||||
onClicked: {
|
||||
toast.show("Goodbye.");
|
||||
|
|
175
qml/Pages/TileButton.qml
Normal file
|
@ -0,0 +1,175 @@
|
|||
import QtQuick
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import "skin-bank.js" as SkinBank
|
||||
|
||||
Item {
|
||||
property alias text: labelText.text
|
||||
property alias textColor: labelText.color
|
||||
property alias textFont: labelText.font
|
||||
property string iconSource
|
||||
property alias backgroundColor: rect.color
|
||||
property alias border: rect.border
|
||||
property bool autoHideText: true
|
||||
|
||||
signal clicked
|
||||
|
||||
id: button
|
||||
width: 124
|
||||
height: 124
|
||||
antialiasing: true
|
||||
|
||||
RectangularGlow {
|
||||
anchors.fill: rect
|
||||
glowRadius: 1
|
||||
spread: 1.0
|
||||
visible: mouse.containsMouse || parent.focus
|
||||
antialiasing: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: rect
|
||||
anchors.fill: parent
|
||||
color: "#78D478"
|
||||
antialiasing: true
|
||||
border.width: 1
|
||||
border.color: "#8CDA8C"
|
||||
}
|
||||
|
||||
transform: [
|
||||
Rotation {
|
||||
id: rotationTransform
|
||||
|
||||
angle: 0
|
||||
|
||||
axis.x: 0
|
||||
axis.y: 0
|
||||
axis.z: 0
|
||||
|
||||
origin.x: button.width / 2.0
|
||||
origin.y: button.height / 2.0
|
||||
|
||||
Behavior on angle {
|
||||
NumberAnimation { duration: 100 }
|
||||
}
|
||||
},
|
||||
|
||||
Scale {
|
||||
id: scaleTransform
|
||||
|
||||
xScale: 1
|
||||
yScale: 1
|
||||
|
||||
origin.x: button.width / 2.0
|
||||
origin.y: button.height / 2.0
|
||||
|
||||
Behavior on xScale {
|
||||
NumberAnimation { duration: 100 }
|
||||
}
|
||||
|
||||
Behavior on yScale {
|
||||
NumberAnimation { duration: 100 }
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
Image {
|
||||
id: icon
|
||||
anchors.centerIn: parent
|
||||
source: SkinBank.TILE_ICON_DIR + iconSource
|
||||
scale: 0.8
|
||||
}
|
||||
|
||||
Text {
|
||||
id: labelText
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 3
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 3
|
||||
|
||||
visible: !autoHideText || mouse.containsMouse
|
||||
|
||||
color: "white"
|
||||
font.pixelSize: 16
|
||||
font.family: "WenQuanYi Micro Hei"
|
||||
|
||||
text: "Button"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
property bool down: false
|
||||
|
||||
onPressed: {
|
||||
down = true;
|
||||
|
||||
rotationTransform.axis.x = 0;
|
||||
rotationTransform.axis.y = 0;
|
||||
rotationTransform.origin.x = button.width / 2.0
|
||||
rotationTransform.origin.y = button.height / 2.0
|
||||
|
||||
if (mouseX > parent.width - 30)
|
||||
{
|
||||
rotationTransform.origin.x = 0;
|
||||
rotationTransform.axis.y = 1;
|
||||
rotationTransform.angle = 15;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouseX < 30) {
|
||||
rotationTransform.origin.x = button.width;
|
||||
rotationTransform.axis.y = 1;
|
||||
rotationTransform.angle = -15;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouseY < 30) {
|
||||
rotationTransform.origin.y = button.height;
|
||||
rotationTransform.axis.x = 1;
|
||||
rotationTransform.angle = 15;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouseY > parent.height - 30) {
|
||||
rotationTransform.origin.y = 0;
|
||||
rotationTransform.axis.x = 1;
|
||||
rotationTransform.angle = -15;
|
||||
return;
|
||||
}
|
||||
|
||||
scaleTransform.xScale = 0.95;
|
||||
scaleTransform.yScale = 0.95;
|
||||
}
|
||||
|
||||
onCanceled: {
|
||||
reset();
|
||||
down = false;
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
reset();
|
||||
if (down) {
|
||||
button.clicked();
|
||||
}
|
||||
}
|
||||
|
||||
onExited: {
|
||||
reset();
|
||||
down = false;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
scaleTransform.xScale = 1;
|
||||
scaleTransform.yScale = 1;
|
||||
rotationTransform.angle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
button.clicked();
|
||||
}
|
||||
}
|
|
@ -13,3 +13,4 @@ var CARD_SUIT_DIR = AppPath + "/image/card/suit/";
|
|||
var DELAYED_TRICK_DIR = AppPath + "/image/card/delayedTrick/";
|
||||
var EQUIP_ICON_DIR = AppPath + "/image/card/equipIcon/";
|
||||
var PIXANIM_DIR = AppPath + "/image/anim/"
|
||||
var TILE_ICON_DIR = AppPath + "/image/button/tileicon/"
|
||||
|
|
|
@ -47,9 +47,11 @@ Item {
|
|||
Component { id: generalsOverview; GeneralsOverview {} }
|
||||
Component { id: cardsOverview; CardsOverview {} }
|
||||
Component { id: room; Room {} }
|
||||
Component { id: aboutPage; About {} }
|
||||
|
||||
property var generalsOverviewPage
|
||||
property var cardsOverviewPage
|
||||
property alias aboutPage: aboutPage
|
||||
|
||||
property bool busy: false
|
||||
BusyIndicator {
|
||||
|
|
|
@ -114,6 +114,9 @@ int main(int argc, char *argv[])
|
|||
#endif
|
||||
|
||||
app = new QApplication(argc, argv);
|
||||
#ifdef DESKTOP_BUILD
|
||||
((QApplication *)app)->setWindowIcon(QIcon("image/icon.png"));
|
||||
#endif
|
||||
|
||||
#define SHOW_SPLASH_MSG(msg) \
|
||||
splash.showMessage(msg, Qt::AlignHCenter | Qt::AlignBottom);
|
||||
|
|