Unverified Commit dc1d1add authored by Gleb Orlov's avatar Gleb Orlov Committed by GitHub

Merge branch 'Castro-Fidel:main' into main

parents 57492c08 557445f9
......@@ -17,6 +17,7 @@ from ingame.models.GameEntry import GameEntry
from ingame.models.GameAgent import GameAgent
from PySide6.QtCore import Property, Signal, Slot, QObject, Qt
class App(QtCore.QObject):
app_name = "ingame"
app_author = "foss"
......@@ -30,6 +31,8 @@ class App(QtCore.QObject):
gamepad_clicked_RB = Signal(bool, name="gamepadClickedRB")
gamepad_clicked_apply = Signal(bool, name="gamepadClickedApply")
gamepad_clicked_back = Signal(bool, name="gamepadClickedBack")
gamepad_axis_up = Signal(bool, name="gamepadAxisUp")
gamepad_axis_down = Signal(bool, name="gamepadAxisDown")
gamepad_axis_left = Signal(bool, name="gamepadAxisLeft")
gamepad_axis_right = Signal(bool, name="gamepadAxisRight")
......@@ -39,7 +42,8 @@ class App(QtCore.QObject):
self.config_path = user_config_dir(App.app_name, App.app_author)
self.cache_path = user_cache_dir(App.app_name, App.app_author)
self.games_model: GamesModel = GamesModel()
self.portproton_games_model: GamesModel = GamesModel()
self.native_games_model: GamesModel = GamesModel()
self.portproton_config_location: str = '/.config/PortProton.conf'
self.portproton_location: str = ''
self.running_game_process: Union[subprocess.Popen, None] = None
......@@ -50,6 +54,8 @@ class App(QtCore.QObject):
self.gamepad.apply_clicked = lambda: self.gamepad_clicked_apply.emit(True)
self.gamepad.l_clicked = lambda: self.gamepad_axis_left.emit(True)
self.gamepad.r_clicked = lambda: self.gamepad_axis_right.emit(True)
self.gamepad.u_clicked = lambda: self.gamepad_axis_up.emit(True)
self.gamepad.d_clicked = lambda: self.gamepad_axis_down.emit(True)
self.gamepad.back_clicked = lambda: self.gamepad_clicked_back.emit(True)
self.agent = GameAgent(self.config_path, self.cache_path)
......@@ -61,11 +67,51 @@ class App(QtCore.QObject):
with open(self.home + self.portproton_config_location, 'r') as file:
self.portproton_location = file.read().strip()
print(f'Current PortProton location: {self.portproton_location}')
self.__portproton_games_setup(glob.glob(f"{self.portproton_location}/*.desktop"))
except FileNotFoundError:
print('File not found')
except Exception as e:
print('An error occurred', e)
self.__native_games_setup()
self.gamepad.run()
self.retrieve_games_details()
self.games_model.clear()
files = glob.glob(f"{self.portproton_location}/*.desktop")
def __native_games_setup(self):
# Reference: https://askubuntu.com/a/490398
# TODO: replace with DesktopFile instance
self.native_games_model.clear()
for val in files:
for val in glob.glob("/usr/share/applications/*.desktop"):
try:
desktop_file = DesktopFile.from_file(val)
desktop_file_data = desktop_file.data
desktop_entry = desktop_file_data['Desktop Entry']
if 'Categories' not in desktop_entry:
continue
# Game;ArcadeGame;
entry_categories = desktop_entry['Categories'] or ''
if "Game" not in entry_categories:
continue
entry_name = desktop_entry['Name'] or 'generic'
entry_exec = 'Exec' in desktop_entry and desktop_entry['Exec'] or ''
entry_icon = '' # desktop_entry['Icon']
assert (isinstance(entry_name, str)
and isinstance(entry_exec, str)
and isinstance(entry_icon, str))
self.native_games_model.add_game(GameEntry(name=entry_name, icon=entry_icon, exec=entry_exec))
except:
continue
def __portproton_games_setup(self, files):
self.portproton_games_model.clear()
for val in files:
try:
desktop_file = DesktopFile.from_file(val)
desktop_file_data = desktop_file.data
desktop_entry = desktop_file_data['Desktop Entry']
......@@ -92,31 +138,28 @@ class App(QtCore.QObject):
# Remove extra env in the beginning
entry_exec = f"env START_FROM_STEAM=1 {entry_exec[4:len(entry_exec)]}"
self.games_model.add_game(GameEntry(name=entry_name, icon=entry_icon, exec=entry_exec))
self.gamepad.run()
self.retrieve_games_details()
except FileNotFoundError:
print('File not found')
except Exception as e:
print('An error occurred', e)
pass
self.portproton_games_model.add_game(GameEntry(name=entry_name, icon=entry_icon, exec=entry_exec))
except:
continue
# TODO: fix: progress=1.0 not emitted if details already cached/downloaded
def retrieve_games_details(self):
def retrieve_games_details_thread(t):
def retrieve_games_details_thread(t, model):
t.game_list_details_retrieving_progress.emit(0.0)
all_count: int = len(self.games_model.games_list)
all_count: int = len(model.games_list)
game_entry: GameEntry
i: int = 0
for game_entry in self.games_model.games_list:
for game_entry in model.games_list:
game_description = t.agent.retrieve_game_description(game_entry.name)
game_entry.icon = game_description['image_location_path'] or game_entry.icon
t.game_list_details_retrieving_progress.emit(float(i) / all_count)
i += 1
t.game_list_details_retrieving_progress.emit(1.0)
thread = threading.Thread(target=retrieve_games_details_thread, args=(self,))
thread = threading.Thread(target=retrieve_games_details_thread, args=(self, self.portproton_games_model))
thread.start()
thread = threading.Thread(target=retrieve_games_details_thread, args=(self, self.native_games_model))
thread.start()
''' CALLBACKS '''
......@@ -161,4 +204,8 @@ class App(QtCore.QObject):
@Property(QObject, constant=True)
def games(self):
return self.games_model
return self.portproton_games_model
@Property(QObject, constant=True)
def native_games(self):
return self.native_games_model
......@@ -11,6 +11,8 @@ class Gamepad:
RB_BUTTON = 5
LEFT_RIGHT_AXIS = 0
LEFT_RIGHT_AXIS_SENSITIVITY = 0.7
UP_DOWN_AXIS = 1
UP_DOWN_AXIS_SENSITIVITY = 0.7
APPLY_BUTTON = 0
BACK_BUTTON = 1
......@@ -23,12 +25,16 @@ class Gamepad:
self.last_apply_clicked: bool = False
self.last_left_clicked: bool = False
self.last_right_clicked: bool = False
self.last_up_clicked: bool = False
self.last_down_clicked: bool = False
self.last_back_clicked: bool = False
self.lb_clicked: () = lambda: None
self.rb_clicked: () = lambda: None
self.l_clicked: () = lambda: None
self.r_clicked: () = lambda: None
self.u_clicked: () = lambda: None
self.d_clicked: () = lambda: None
self.back_clicked: () = lambda: None
self.apply_clicked: () = lambda: None
......@@ -64,6 +70,7 @@ class Gamepad:
rb_button = self.joystick.get_button(self.RB_BUTTON)
apply_button = self.joystick.get_button(self.APPLY_BUTTON)
left_right_axis = self.joystick.get_axis(self.LEFT_RIGHT_AXIS)
up_down_axis = self.joystick.get_axis(self.UP_DOWN_AXIS)
back_button = self.joystick.get_button(self.BACK_BUTTON)
# LB
......@@ -110,6 +117,23 @@ class Gamepad:
if (not left_right_axis >= self.LEFT_RIGHT_AXIS_SENSITIVITY) and self.last_right_clicked:
self.last_right_clicked = not self.last_right_clicked
# UP
if (up_down_axis <= -self.UP_DOWN_AXIS_SENSITIVITY) and not self.last_up_clicked:
self.last_up_clicked = not self.last_up_clicked
self.u_clicked()
if not (up_down_axis <= -self.UP_DOWN_AXIS_SENSITIVITY) and self.last_up_clicked:
self.last_up_clicked = not self.last_up_clicked
# DOWN
if (up_down_axis >= self.UP_DOWN_AXIS_SENSITIVITY) and not self.last_down_clicked:
self.last_down_clicked = not self.last_down_clicked
self.d_clicked()
if (not up_down_axis >= self.UP_DOWN_AXIS_SENSITIVITY) and self.last_down_clicked:
self.last_down_clicked = not self.last_down_clicked
# BACK
if back_button and not self.last_back_clicked:
self.last_back_clicked = not self.last_back_clicked
......
var systemManagementTab = "System";
var gamesTab = "Games";
var nativeGamesTab = "Native";
......@@ -46,6 +46,12 @@ Window {
function onGamepadAxisRight(done){
window._trigger("onGamepadAxisRight", done);
}
function onGamepadAxisUp(done){
window._trigger("onGamepadAxisUp", done);
}
function onGamepadAxisDown(done){
window._trigger("onGamepadAxisDown", done);
}
function onGamepadClickedApply(done){
window._trigger("onGamepadClickedApply", done);
}
......@@ -65,6 +71,8 @@ Window {
let d = scenes[scene];
// console.log("CALLUP " + _method);
if(d !== null && d[_method] !== undefined && d[_method] !== null)
d[_method](args);
}
......
......@@ -95,7 +95,7 @@ Rectangle {
}
ColumnLayout{
ColumnLayout {
// anchors.fill:parent
anchors.left: parent.left
anchors.top: parent.top
......@@ -107,7 +107,7 @@ Rectangle {
anchors.topMargin: parent.height / 100 * 3
spacing: 6
ItemGroup{
ItemGroup {
id: topPanel
Button {
id: back
......@@ -178,7 +178,7 @@ Rectangle {
}
}
}
Rectangle{
Rectangle {
// Start pos
Layout.fillWidth: true
Layout.fillHeight: true
......@@ -390,6 +390,13 @@ Rectangle {
description.text = "Наименование игры:\n" + result['title'] + "\n\nОписание игры:\n" + result['desc']
}
function onGamepadAxisUp(done){
root.onGamepadAxisLeft(done);
}
function onGamepadAxisDown(done){
root.onGamepadAxisRight(done);
}
function onGamepadAxisLeft(done){
if(window.scene !== S.gameInfoScene) return;
root.applyItemsFocus(-1)
......
......@@ -11,6 +11,7 @@ Rectangle {
color: "#00000000"
onVisibleChanged: {
tabs.visible = container.visible;
}
......@@ -59,5 +60,11 @@ Rectangle {
function onGameListDetailsRetrievingProgress(args){
tabs.onGameListDetailsRetrievingProgress(args)
}
function onGamepadAxisUp(args){
tabs.onGamepadAxisUp(args)
}
function onGamepadAxisDown(args){
tabs.onGamepadAxisDown(args)
}
}
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import "../delegates"
import "../constants/tabs.js" as TabConstants
import "../constants/style.js" as Style
import "../components" as TopMenuBut
import "../constants/scene.js" as S
ScrollView {
property var model: buttonGames
id: gamesScroller
anchors.fill: parent
anchors.topMargin: topNavigation.height
ScrollBar.vertical: ScrollBar {
id: scrolV;
height: parent.height
opacity: 0
position: 0
property double fromAnim: 0.0
property double toAnim: 0.0
}
function scrollToY(y, HItem) {
scrolV.fromAnim = scrolV.position;
scrolV.position = (1.0 - scrolV.size) * y / gamesScroller.height;
scrolV.toAnim = (1.0 - scrolV.size) * y / gamesScroller.height;
if(scrolV.toAnim != scrolV.fromAnim) {
scrollAnimation.start();
}
}
// Анимация авто скролла
PropertyAnimation {
to: scrolV.toAnim;
from: scrolV.fromAnim;
target: scrolV;
id: scrollAnimation;
property: "position";
duration: 200;
}
GridLayout {
id: gamesGrid
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
columns: 5
rows: Math.max(Math.ceil(children.length / columns), 1)
anchors.rightMargin: rowSpacing * 2
anchors.leftMargin: rowSpacing * 2
anchors.bottomMargin : 90
anchors.topMargin: Math.floor( gamesScroller.width / 100 * 3)
rowSpacing: Math.floor( gamesScroller.width / 100 * 3)
columnSpacing: rowSpacing
// Повторитель
Repeater {
id: gamesGridRepeater
model: gamesScroller.model
// Карточка игры
Game {
id: game
gameTitle: model.name
gameExec: model.exec
gameIcon: model.icon
Layout.bottomMargin :
(index - index % gamesGrid.columns) /
gamesGrid.columns === gamesGrid.rows - 1 ? gamesGrid.rowSpacing * 2 : 0
onFocusChanged: if(focus) {
gamesScroller.scrollToY(y);
}
Layout.preferredWidth:
(gamesScroller.width - (gamesGrid.columns -1) *
gamesGrid.rowSpacing - gamesGrid.anchors.rightMargin - gamesGrid.anchors.leftMargin)
/ gamesGrid.columns
Layout.preferredHeight: Layout.preferredWidth / 2 * 3
// Component.onCompleted: {a3.start()}
// SequentialAnimation {
// id:a3
// NumberAnimation {
// property:Layout.topMargin;
// easing.type: Easing.InOutQuad;
// duration: 300;
// from: 100//Layout.preferredHeight;
// to: 0;
// }
// NumberAnimation {
// property:Layout.topMargin;
// easing.type: Easing.InOutQuad;
// duration: 300;
// from: 0//Layout.preferredHeight;
// to: 100;
// }
// loops: Animation.Infinite
// }
// Layout.topMargin: Layout.preferredHeight
}
}
}
// LOGIC
property int focusedItems: 0;
function applyItemsFocus(inc){
if(window.scene !== S.homeScene) return;
let c = gamesGrid.children;
let l = c.length - 1; // exclude QQuickRepeater
if(gamesScroller.focusedItems + inc >= l) {
gamesScroller.focusedItems = (gamesScroller.focusedItems + inc === l - 1) ? 0 : l - 1;
} else if(gamesScroller.focusedItems + inc < 0) {
gamesScroller.focusedItems = (gamesScroller.focusedItems + inc === 0) ? l - 1 : 0; //;
} else {
gamesScroller.focusedItems += inc;
}
if(c[gamesScroller.focusedItems] !== undefined) {
c[gamesScroller.focusedItems].forceActiveFocus();
}
}
function applyItemsFocusByLine(inc){
gamesScroller.applyItemsFocus(inc * gamesGrid.columns);
}
function pressFocusedItem(){
let c = gamesGrid.children;
if(c[gamesScroller.focusedItems] !== undefined) {
c[gamesScroller.focusedItems].press();
}
}
function refreshItems(data){
gamesGridRepeater.model = [];
gamesGridRepeater.model = data;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment