diff --git a/image/button/tileicon/about.png b/image/button/tileicon/about.png new file mode 100644 index 00000000..630d6479 Binary files /dev/null and b/image/button/tileicon/about.png differ diff --git a/image/button/tileicon/card_overview.png b/image/button/tileicon/card_overview.png new file mode 100644 index 00000000..de02a46b Binary files /dev/null and b/image/button/tileicon/card_overview.png differ diff --git a/image/button/tileicon/configure.png b/image/button/tileicon/configure.png new file mode 100644 index 00000000..6262688d Binary files /dev/null and b/image/button/tileicon/configure.png differ diff --git a/image/button/tileicon/create_room.png b/image/button/tileicon/create_room.png new file mode 100644 index 00000000..3c719444 Binary files /dev/null and b/image/button/tileicon/create_room.png differ diff --git a/image/button/tileicon/general_overview.png b/image/button/tileicon/general_overview.png new file mode 100644 index 00000000..61c5b881 Binary files /dev/null and b/image/button/tileicon/general_overview.png differ diff --git a/image/button/tileicon/quit.png b/image/button/tileicon/quit.png new file mode 100644 index 00000000..3b4f1e3d Binary files /dev/null and b/image/button/tileicon/quit.png differ diff --git a/image/button/tileicon/replay.png b/image/button/tileicon/replay.png new file mode 100644 index 00000000..cc8473aa Binary files /dev/null and b/image/button/tileicon/replay.png differ diff --git a/image/button/tileicon/rule_summary.png b/image/button/tileicon/rule_summary.png new file mode 100644 index 00000000..d088ea41 Binary files /dev/null and b/image/button/tileicon/rule_summary.png differ diff --git a/image/button/tileicon/start_game.png b/image/button/tileicon/start_game.png new file mode 100644 index 00000000..7da1fc71 Binary files /dev/null and b/image/button/tileicon/start_game.png differ diff --git a/image/logo/freekill.png b/image/logo/freekill.png new file mode 100644 index 00000000..3f40fdf0 Binary files /dev/null and b/image/logo/freekill.png differ diff --git a/image/logo/gplv3.png b/image/logo/gplv3.png new file mode 100644 index 00000000..b44f609f Binary files /dev/null and b/image/logo/gplv3.png differ diff --git a/image/logo/lua.png b/image/logo/lua.png new file mode 100644 index 00000000..75234a6f Binary files /dev/null and b/image/logo/lua.png differ diff --git a/image/logo/ossl.png b/image/logo/ossl.png new file mode 100644 index 00000000..3cfe626c Binary files /dev/null and b/image/logo/ossl.png differ diff --git a/image/logo/qt.png b/image/logo/qt.png new file mode 100644 index 00000000..21c38d10 Binary files /dev/null and b/image/logo/qt.png differ diff --git a/image/logo/sqlite.png b/image/logo/sqlite.png new file mode 100644 index 00000000..fddedaee Binary files /dev/null and b/image/logo/sqlite.png differ diff --git a/lua/client/client_util.lua b/lua/client/client_util.lua index 96ded9e2..9419edf8 100644 --- a/lua/client/client_util.lua +++ b/lua/client/client_util.lua @@ -232,7 +232,32 @@ Fk:loadTranslationTable{ ["Generals Overview"] = "武将一览", ["Cards Overview"] = "卡牌一览", ["Scenarios Overview"] = "玩法一览", + ["Replay"] = "录像", ["About"] = "关于", + ["about_freekill_description"] = "关于FreeKill
" .. + "以便于DIY为首要目的的开源三国杀游戏。
" .. + "
项目链接: https://github.com/Notify-ctrl/FreeKill", + ["about_qt_description"] = "关于Qt
" .. + "Qt是一个C++图形界面应用程序开发框架,拥有强大的跨平台能力以及易于使用的API。
" .. + "
本程序使用Qt 6.2+,主要利用QtQuick开发UI,同时也使用Qt的网络库开发服务端程序。
" .. + "
官网: https://www.qt.io", + ["about_lua_description"] = "关于Lua
" .. + "Lua是一种小巧、灵活、高效的脚本语言,广泛用于游戏开发中。
" .. + "
本程序使用Lua 5.4,利用其完全实现了整个游戏逻辑。
" .. + "
官网: https://www.lua.org", + ["about_ossl_description"] = "关于OpenSSL
" .. + "OpenSSL是一个开源包,用来提供安全通信与各种加密支持。
" .. + "
本程序目前用到了crypto库,以获得RSA加密算法支持。
" .. + "
官网: https://www.openssl.org", + ["about_gplv3_description"] = "关于GPLv3
" .. + "GNU通用公共许可协议(简称GPL)是一个广泛使用的自由软件许可证条款,它确保广大用户自由地使用、学习、共享或修改软件。
" .. + "
由于Qt是按照GPLv3协议开源的库,与此同时本程序用到的readline库也属于GPLv3库,再加上QSanguosha也是以GPLv3协议开源的软件(从中借鉴了不少代码和思路),因此这个项目也使用GPLv3协议开源。
" .. + "
官网: https://gplv3.fsf.org", + ["about_sqlite_description"] = "关于SQLite
" .. + "SQLite是一个轻量级的数据库,具有占用资源低、运行效率快、嵌入性好等优点。
" .. + "
FreeKill使用sqlite3在服务端保存用户的各种信息。
" .. + "
官网: https://www.sqlite.org", + ["Exit Lobby"] = "退出大厅", ["OK"] = "确定", diff --git a/qml/Pages/About.qml b/qml/Pages/About.qml new file mode 100644 index 00000000..5b45d9b6 --- /dev/null +++ b/qml/Pages/About.qml @@ -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(); + } + } + +} diff --git a/qml/Pages/Lobby.qml b/qml/Pages/Lobby.qml index 9c272d3b..a6002afa 100644 --- a/qml/Pages/Lobby.qml +++ b/qml/Pages/Lobby.qml @@ -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."); diff --git a/qml/Pages/TileButton.qml b/qml/Pages/TileButton.qml new file mode 100644 index 00000000..b38fe053 --- /dev/null +++ b/qml/Pages/TileButton.qml @@ -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(); + } +} diff --git a/qml/Pages/skin-bank.js b/qml/Pages/skin-bank.js index cd6f7b54..130cfac5 100644 --- a/qml/Pages/skin-bank.js +++ b/qml/Pages/skin-bank.js @@ -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/" diff --git a/qml/main.qml b/qml/main.qml index 813618ab..dddb64e4 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -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 { diff --git a/src/main.cpp b/src/main.cpp index da7123cd..07865fc2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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); diff --git a/src/pch.h b/src/pch.h index d7851be5..bc19afce 100644 --- a/src/pch.h +++ b/src/pch.h @@ -18,4 +18,8 @@ typedef int LuaFunction; #include #include +#if !defined (Q_OS_ANDROID) && !defined (Q_OS_WASM) +#define DESKTOP_BUILD +#endif + #endif // _PCH_H