forked from eden-emu/eden
carousel/list view
Signed-off-by: crueter <swurl@swurl.xyz>
This commit is contained in:
parent
0e13a362f1
commit
97d648cac6
9 changed files with 244 additions and 65 deletions
|
@ -282,13 +282,13 @@ void QtConfig::ReadUIGamelistValues() {
|
||||||
|
|
||||||
ReadCategory(Settings::Category::UiGameList);
|
ReadCategory(Settings::Category::UiGameList);
|
||||||
|
|
||||||
const int favorites_size = BeginArray("favorites");
|
// const int favorites_size = BeginArray("favorites");
|
||||||
for (int i = 0; i < favorites_size; i++) {
|
// for (int i = 0; i < favorites_size; i++) {
|
||||||
SetArrayIndex(i);
|
// SetArrayIndex(i);
|
||||||
UISettings::values.favorited_ids.append(
|
// UISettings::values.favorited_ids.append(
|
||||||
ReadUnsignedIntegerSetting(std::string("program_id")));
|
// ReadUnsignedIntegerSetting(std::string("program_id")));
|
||||||
}
|
// }
|
||||||
EndArray();
|
// EndArray();
|
||||||
|
|
||||||
EndGroup();
|
EndGroup();
|
||||||
}
|
}
|
||||||
|
@ -490,12 +490,12 @@ void QtConfig::SaveUIGamelistValues()
|
||||||
|
|
||||||
WriteCategory(Settings::Category::UiGameList);
|
WriteCategory(Settings::Category::UiGameList);
|
||||||
|
|
||||||
BeginArray(std::string("favorites"));
|
// BeginArray(std::string("favorites"));
|
||||||
for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) {
|
// for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) {
|
||||||
SetArrayIndex(i);
|
// SetArrayIndex(i);
|
||||||
WriteIntegerSetting(std::string("program_id"), UISettings::values.favorited_ids[i]);
|
// WriteIntegerSetting(std::string("program_id"), UISettings::values.favorited_ids[i]);
|
||||||
}
|
// }
|
||||||
EndArray(); // favorites
|
// EndArray(); // favorites
|
||||||
|
|
||||||
EndGroup();
|
EndGroup();
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,12 @@ enum class Theme {
|
||||||
MidnightBlueColorful,
|
MidnightBlueColorful,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GameView {
|
||||||
|
Grid,
|
||||||
|
List,
|
||||||
|
Carousel,
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr Theme default_theme{
|
static constexpr Theme default_theme{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
Theme::DarkColorful
|
Theme::DarkColorful
|
||||||
|
@ -192,15 +198,15 @@ struct Values {
|
||||||
std::pair<std::vector<std::string>, std::vector<std::string>> multiplayer_ban_list;
|
std::pair<std::vector<std::string>, std::vector<std::string>> multiplayer_ban_list;
|
||||||
|
|
||||||
// Game List
|
// Game List
|
||||||
Setting<bool> show_add_ons{linkage, true, "show_add_ons", Category::UiGameList};
|
// Setting<bool> show_add_ons{linkage, true, "show_add_ons", Category::UiGameList};
|
||||||
Setting<u32> game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList};
|
// Setting<u32> game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList};
|
||||||
Setting<u32> folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList};
|
// Setting<u32> folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList};
|
||||||
Setting<u8> row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList};
|
// Setting<u8> row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList};
|
||||||
Setting<u8> row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList};
|
// Setting<u8> row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList};
|
||||||
std::atomic_bool is_game_list_reload_pending{false};
|
// std::atomic_bool is_game_list_reload_pending{false};
|
||||||
Setting<bool> cache_game_list{linkage, true, "cache_game_list", Category::UiGameList};
|
// Setting<bool> cache_game_list{linkage, true, "cache_game_list", Category::UiGameList};
|
||||||
Setting<bool> favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList};
|
// Setting<bool> favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList};
|
||||||
QVector<u64> favorited_ids;
|
// QVector<u64> favorited_ids;
|
||||||
|
|
||||||
Setting<u8, true> grid_columns{linkage, 4, 1, 8, "grid_columns", Category::UiGameList};
|
Setting<u8, true> grid_columns{linkage, 4, 1, 8, "grid_columns", Category::UiGameList};
|
||||||
|
|
||||||
|
|
|
@ -56,9 +56,6 @@ void GameListModel::reload()
|
||||||
qreal size = entry.size();
|
qreal size = entry.size();
|
||||||
QString sizeString = QLocale::system().formattedDataSize(size);
|
QString sizeString = QLocale::system().formattedDataSize(size);
|
||||||
|
|
||||||
qDebug() << path << name << size;
|
|
||||||
// m_data << Game{path, name, size};
|
|
||||||
|
|
||||||
QStandardItem *game = new QStandardItem(name);
|
QStandardItem *game = new QStandardItem(name);
|
||||||
game->setData(path, GLMRoleTypes::PATH);
|
game->setData(path, GLMRoleTypes::PATH);
|
||||||
game->setData(sizeString, GLMRoleTypes::FILESIZE);
|
game->setData(sizeString, GLMRoleTypes::FILESIZE);
|
||||||
|
|
|
@ -9,5 +9,10 @@ qt_add_qml_module(edenMain
|
||||||
Main.qml
|
Main.qml
|
||||||
StatusBar.qml
|
StatusBar.qml
|
||||||
GameList.qml
|
GameList.qml
|
||||||
GamePreview.qml
|
GameGridCard.qml
|
||||||
|
MarqueeText.qml
|
||||||
|
GameGrid.qml
|
||||||
|
|
||||||
|
GameCarouselCard.qml
|
||||||
|
GameCarousel.qml
|
||||||
)
|
)
|
||||||
|
|
94
src/eden/qml/main/GameCarousel.qml
Normal file
94
src/eden/qml/main/GameCarousel.qml
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Qt.labs.platform
|
||||||
|
import QtCore
|
||||||
|
|
||||||
|
import org.eden_emu.constants
|
||||||
|
import org.eden_emu.interface
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: carousel
|
||||||
|
|
||||||
|
focus: true
|
||||||
|
focusPolicy: Qt.StrongFocus
|
||||||
|
|
||||||
|
model: EdenGameList
|
||||||
|
orientation: ListView.Horizontal
|
||||||
|
clip: false
|
||||||
|
flickDeceleration: 1000
|
||||||
|
snapMode: ListView.SnapToItem
|
||||||
|
|
||||||
|
onHeightChanged: console.log(width, height)
|
||||||
|
|
||||||
|
spacing: 20
|
||||||
|
|
||||||
|
Keys.enabled: true
|
||||||
|
Keys.onRightPressed: incrementCurrentIndex()
|
||||||
|
Keys.onLeftPressed: decrementCurrentIndex()
|
||||||
|
|
||||||
|
onCurrentIndexChanged: scrollToCenter()
|
||||||
|
|
||||||
|
highlight: Rectangle {
|
||||||
|
id: hg
|
||||||
|
clip: false
|
||||||
|
z: 3
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
border {
|
||||||
|
color: "deepskyblue"
|
||||||
|
width: 4 * Constants.scalar
|
||||||
|
}
|
||||||
|
|
||||||
|
radius: 8 * Constants.scalar
|
||||||
|
|
||||||
|
// TODO: marquee
|
||||||
|
Text {
|
||||||
|
function toTitleCase(str) {
|
||||||
|
return str.replace(/\w\S*/g, text => text.charAt(0).toUpperCase(
|
||||||
|
) + text.substring(1).toLowerCase())
|
||||||
|
}
|
||||||
|
|
||||||
|
property var item: carousel.currentItem
|
||||||
|
|
||||||
|
text: toTitleCase(item.title)
|
||||||
|
font.pixelSize: 22 * Constants.scalar
|
||||||
|
color: "lightblue"
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
bottom: hg.top
|
||||||
|
|
||||||
|
bottomMargin: 10 * Constants.scalar
|
||||||
|
left: hg.left
|
||||||
|
right: hg.right
|
||||||
|
}
|
||||||
|
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
highlightFollowsCurrentItem: true
|
||||||
|
highlightMoveDuration: 300
|
||||||
|
highlightMoveVelocity: -1
|
||||||
|
|
||||||
|
delegate: GameCarouselCard {
|
||||||
|
id: game
|
||||||
|
width: 300
|
||||||
|
height: 300
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollToCenter() {
|
||||||
|
let targetX = currentIndex * 320 - (width - 320) / 2
|
||||||
|
let min = 0
|
||||||
|
let max = contentWidth
|
||||||
|
|
||||||
|
contentX = Math.max(min, Math.min(max, targetX))
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on contentX {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 300
|
||||||
|
easing.type: Easing.OutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
src/eden/qml/main/GameGrid.qml
Normal file
44
src/eden/qml/main/GameGrid.qml
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Qt.labs.platform
|
||||||
|
import QtCore
|
||||||
|
|
||||||
|
import org.eden_emu.constants
|
||||||
|
import org.eden_emu.interface
|
||||||
|
import org.eden_emu.gamepad
|
||||||
|
|
||||||
|
GridView {
|
||||||
|
property var setting
|
||||||
|
id: grid
|
||||||
|
|
||||||
|
property int cellSize: Math.floor(width / setting.value)
|
||||||
|
|
||||||
|
highlightFollowsCurrentItem: true
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
cellWidth: cellSize
|
||||||
|
cellHeight: cellSize + 60 * Constants.scalar
|
||||||
|
|
||||||
|
model: EdenGameList
|
||||||
|
|
||||||
|
delegate: GameGridCard {
|
||||||
|
id: game
|
||||||
|
|
||||||
|
width: grid.cellSize - 20 * Constants.scalar
|
||||||
|
height: grid.cellHeight - 20 * Constants.scalar
|
||||||
|
}
|
||||||
|
|
||||||
|
highlight: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
z: 5
|
||||||
|
|
||||||
|
radius: 16 * Constants.scalar
|
||||||
|
border {
|
||||||
|
color: Constants.text
|
||||||
|
width: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
focus: true
|
||||||
|
focusPolicy: "StrongFocus"
|
||||||
|
}
|
|
@ -20,15 +20,16 @@ Rectangle {
|
||||||
|
|
||||||
color: Constants.bg
|
color: Constants.bg
|
||||||
|
|
||||||
// TODO: make this optional.
|
// TODO: use the original yuzu backend for dis
|
||||||
// Probably just make a Gamepad frontend/backend split with a null backend
|
|
||||||
Gamepad {
|
Gamepad {
|
||||||
id: gamepad
|
id: gamepad
|
||||||
|
|
||||||
onUpPressed: grid.moveCurrentIndexUp()
|
// onUpPressed: grid.moveCurrentIndexUp()
|
||||||
onDownPressed: grid.moveCurrentIndexDown()
|
// onDownPressed: grid.moveCurrentIndexDown()
|
||||||
onLeftPressed: grid.moveCurrentIndexLeft()
|
// onLeftPressed: grid.moveCurrentIndexLeft()
|
||||||
onRightPressed: grid.moveCurrentIndexRight()
|
// onRightPressed: grid.moveCurrentIndexRight()
|
||||||
|
onLeftPressed: carousel.decrementCurrentIndex()
|
||||||
|
onRightPressed: carousel.incrementCurrentIndex()
|
||||||
onAPressed: console.log("A pressed")
|
onAPressed: console.log("A pressed")
|
||||||
onLeftStickMoved: (x, y) => {
|
onLeftStickMoved: (x, y) => {
|
||||||
gx = x
|
gx = x
|
||||||
|
@ -54,67 +55,56 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
interval: 16
|
interval: 16
|
||||||
running: true
|
running: true
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: gamepad.pollEvents()
|
onTriggered: gamepad.pollEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderDialog {
|
FolderDialog {
|
||||||
id: openDir
|
id: openDir
|
||||||
folder: StandardPaths.writableLocation(StandardPaths.HomeLocation)
|
folder: StandardPaths.writableLocation(StandardPaths.HomeLocation)
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
button.visible = false
|
button.visible = false
|
||||||
grid.anchors.bottom = root.bottom
|
view.anchors.bottom = root.bottom
|
||||||
EdenGameList.addDir(folder)
|
EdenGameList.addDir(folder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GridView {
|
// GameGrid {
|
||||||
id: grid
|
// setting: parent.setting
|
||||||
|
|
||||||
property int cellSize: Math.floor(width / setting.value)
|
// id: grid
|
||||||
|
|
||||||
highlightFollowsCurrentItem: true
|
// anchors.bottom: button.top
|
||||||
clip: true
|
// anchors.left: parent.left
|
||||||
|
// anchors.margins: 8
|
||||||
cellWidth: cellSize
|
// anchors.right: parent.right
|
||||||
cellHeight: cellSize + 60 * Constants.scalar
|
// anchors.top: parent.top
|
||||||
|
// }
|
||||||
|
Item {
|
||||||
|
id: view
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: parent.top
|
bottom: button.top
|
||||||
left: parent.left
|
left: parent.left
|
||||||
right: parent.right
|
right: parent.right
|
||||||
|
top: parent.top
|
||||||
bottom: button.top
|
margins: 8 * Constants.scalar
|
||||||
|
|
||||||
margins: 8
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model: EdenGameList
|
GameCarousel {
|
||||||
|
id: carousel
|
||||||
|
|
||||||
delegate: GamePreview {
|
height: 300
|
||||||
id: game
|
|
||||||
|
|
||||||
width: grid.cellSize - 20 * Constants.scalar
|
anchors {
|
||||||
height: grid.cellHeight - 20 * Constants.scalar
|
right: view.right
|
||||||
}
|
left: view.left
|
||||||
|
|
||||||
highlight: Rectangle {
|
verticalCenter: view.verticalCenter
|
||||||
color: "transparent"
|
|
||||||
z: 5
|
|
||||||
|
|
||||||
radius: 16 * Constants.scalar
|
|
||||||
border {
|
|
||||||
color: Constants.text
|
|
||||||
width: 3
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
focus: true
|
|
||||||
focusPolicy: "StrongFocus"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
|
43
src/eden/qml/main/MarqueeText.qml
Normal file
43
src/eden/qml/main/MarqueeText.qml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Item {
|
||||||
|
required property string text
|
||||||
|
|
||||||
|
property int spacing: 30
|
||||||
|
property int startDelay: 2000
|
||||||
|
property int speed: 40
|
||||||
|
|
||||||
|
property alias font: t1.font
|
||||||
|
property alias color: t1.color
|
||||||
|
|
||||||
|
id: root
|
||||||
|
|
||||||
|
width: t1.width + spacing
|
||||||
|
height: t1.height
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: t1
|
||||||
|
|
||||||
|
SequentialAnimation on x {
|
||||||
|
loops: Animation.Infinite
|
||||||
|
running: true
|
||||||
|
|
||||||
|
PauseAnimation {
|
||||||
|
duration: root.startDelay
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
from: root.width
|
||||||
|
to: -t1.width
|
||||||
|
duration: (root.width + t1.width) * 1000 / root.speed
|
||||||
|
easing.type: Easing.Linear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
x: root.width
|
||||||
|
text: t1.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue