Commit 1b37eb37 authored by Exc404's avatar Exc404

Merge branch 'main' into Анимации

parents ffeb4b7e 9a49b9d1
......@@ -7,12 +7,13 @@ Use the following commands in UNIX shell:
```shell
# Prepare and activate virtual environment
python -m venv .venv
source .venv/bin/activate
python -m pip install --user pipx
python -m pipx ensurepath
pipx install poetry
# Install requirements
pip install -r requirements.txt
poetry install
# Run
python src/main.py
poetry run main
```
\ No newline at end of file
import sys
from pathlib import Path
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
from ingame.models.App import App
from ingame.models.GamesModel import GamesModel
from models.App import App
from models.GamesModel import GamesModel
# TODO: add VirtualKeyboard
if __name__ == "__main__":
def main():
app = QGuiApplication(sys.argv)
app_model = App()
app.aboutToQuit.connect(app_model.close_event)
qml_file = Path(__file__).resolve().parent / "../qml/qml.qml"
engine = QQmlApplicationEngine()
app_model = App()
context = engine.rootContext()
context.setContextProperty("core_app", app_model)
......@@ -23,3 +25,7 @@ if __name__ == "__main__":
sys.exit(-1)
sys.exit(app.exec())
if __name__ == "__main__":
main()
import threading
import glob
import os.path
import subprocess
from time import sleep
from pathlib import Path
from typing import AnyStr, Union
from PySide6 import QtCore
from os.path import expanduser
import glob
from desktop_parser import DesktopFile
import os.path
from pathlib import Path
from ingame.models.Gamepad import Gamepad
from ingame.models.GamesModel import Game, GamesModel
from PySide6.QtCore import Property, Signal, Slot, QObject, Qt
from models.GamesModel import Game, GamesModel
import subprocess
class GameShortcut:
......@@ -23,13 +26,27 @@ class App(QtCore.QObject):
game_started = Signal(bool, name="gameStarted")
game_ended = Signal(bool, name="gameEnded")
gamepad_clicked_LB = Signal(bool, name="gamepadClickedLB")
gamepad_clicked_RB = Signal(bool, name="gamepadClickedRB")
gamepad_clicked_apply = Signal(bool, name="gamepadClickedApply")
gamepad_axis_left = Signal(bool, name="gamepadAxisLeft")
gamepad_axis_right = Signal(bool, name="gamepadAxisRight")
def __init__(self):
super().__init__()
self.games_model = GamesModel()
self.home = expanduser('~')
self.config_location = '/.config/PortProton.conf'
self.portproton_location = ''
self.running_game_process = None
self.games_model: GamesModel = GamesModel()
self.home: AnyStr = expanduser('~')
self.config_location: str = '/.config/PortProton.conf'
self.portproton_location: str = ''
self.running_game_process: Union[subprocess.Popen, None] = None
self.gamepad: Gamepad = Gamepad()
self.gamepad.lb_clicked = lambda: self.gamepad_clicked_LB.emit(True)
self.gamepad.rb_clicked = lambda: self.gamepad_clicked_RB.emit(True)
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.setup()
def setup(self):
......@@ -46,15 +63,15 @@ class App(QtCore.QObject):
data = desktop_file.data
entry = data['Desktop Entry']
name = entry['Name'] or 'generic'
exec = 'Exec' in entry and entry['Exec'] or ''
icon = entry['Icon']
_name = entry['Name'] or 'generic'
_exec = 'Exec' in entry and entry['Exec'] or ''
_icon = entry['Icon']
assert (isinstance(name, str)
and isinstance(exec, str)
and isinstance(icon, str))
assert (isinstance(_name, str)
and isinstance(_exec, str)
and isinstance(_icon, str))
exec_split = exec.split(' ')
exec_split = _exec.split(' ')
# Ignore extra non-related desktop entries
if (len(exec_split) <= 1 or
......@@ -63,12 +80,17 @@ class App(QtCore.QObject):
# TODO parse product name
icon = (os.path.isfile(icon) and icon
or os.path.realpath(f"{Path(__file__).resolve().parent}../../../qml/images/game_icon.png"))
_icon = (os.path.isfile(_icon) and _icon
or os.path.realpath(f"{Path(__file__).resolve().parent}../../../qml/images/PUBG.png"))
# Автозапуск игры:
# PW_GUI_DISABLED_CS=1
# START_FROM_STEAM=1
_exec = f"env START_FROM_STEAM=1 {_exec}"
# Тест карточек
icon = os.path.realpath(f"{Path(__file__).resolve().parent}../../../qml/images/PUBG.png")
self.games_model.add_game(Game(name=name, icon=icon, exec=exec))
self.games_model.add_game(Game(name=_name, icon=_icon, exec=_exec))
self.gamepad.run()
except FileNotFoundError:
print('File not found')
......@@ -76,6 +98,16 @@ class App(QtCore.QObject):
print('An error occurred', e)
pass
### CALLBACKS ###
def close_event(self):
# do stuff
# if can_exit:
self.gamepad.terminate()
# event.accept() # let the window close
# else:
# event.ignore()
### SLOTS ###
@Slot(str)
......
import subprocess
import threading
from typing import Union
import pygame
from pygame.joystick import Joystick
class Gamepad:
LB_BUTTON = 4
RB_BUTTON = 5
LEFT_RIGHT_AXIS = 0
LEFT_RIGHT_AXIS_SENSITIVITY = 0.7
APPLY_BUTTON = 0
def __init__(self):
self.joystick: Union[Joystick, None] = None
self.terminated: bool = False
self.last_rb_clicked: bool = False
self.last_lb_clicked: bool = False
self.last_apply_clicked: bool = False
self.last_left_clicked: bool = False
self.last_right_clicked: bool = False
self.lb_clicked: () = lambda: None
self.rb_clicked: () = lambda: None
self.l_clicked: () = lambda: None
self.r_clicked: () = lambda: None
self.apply_clicked: () = lambda: None
self.thread: Union[threading.Thread, None] = None
pygame.init()
pygame.joystick.init()
def run(self):
joystick_count = pygame.joystick.get_count()
if joystick_count == 0:
print("No joysticks found.")
else:
self.joystick = pygame.joystick.Joystick(0)
self.joystick.init()
self.thread = threading.Thread(target=lambda t, _exec: t.cycle(), args=(self, exec))
self.thread.start()
def cycle(self):
try:
# TODO: use this instead:
# events = pygame.event.get()
# for event in events:
# if event.type == pygame.JOYBUTTONDOWN:
while not self.terminated:
# pygame.event.pump()
pygame.event.wait()
lb_button = self.joystick.get_button(self.LB_BUTTON)
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)
# LB
if lb_button and not self.last_lb_clicked:
self.last_lb_clicked = not self.last_lb_clicked
self.lb_clicked()
if not lb_button and self.last_lb_clicked:
self.last_lb_clicked = not self.last_lb_clicked
# RB
if rb_button and not self.last_rb_clicked:
self.last_rb_clicked = not self.last_rb_clicked
self.rb_clicked()
if not rb_button and self.last_rb_clicked:
self.last_rb_clicked = not self.last_rb_clicked
# APPLY
if apply_button and not self.last_apply_clicked:
self.last_apply_clicked = not self.last_apply_clicked
self.apply_clicked()
if not apply_button and self.last_apply_clicked:
self.last_apply_clicked = not self.last_apply_clicked
# LEFT
if (left_right_axis <= -self.LEFT_RIGHT_AXIS_SENSITIVITY) and not self.last_left_clicked:
self.last_left_clicked = not self.last_left_clicked
self.l_clicked()
if not (left_right_axis <= -self.LEFT_RIGHT_AXIS_SENSITIVITY) and self.last_left_clicked:
self.last_left_clicked = not self.last_left_clicked
# RIGHT
if (left_right_axis >= self.LEFT_RIGHT_AXIS_SENSITIVITY) and not self.last_right_clicked:
self.last_right_clicked = not self.last_right_clicked
self.r_clicked()
if (not left_right_axis >= self.LEFT_RIGHT_AXIS_SENSITIVITY) and self.last_right_clicked:
self.last_right_clicked = not self.last_right_clicked
# print(f"Button {self.LB_BUTTON}: {lb_button}")
# print(f"Button {self.RB_BUTTON}: {rb_button}")
# for i in range(self.joystick.get_numaxes()):
# axis = self.joystick.get_axis(i)
# print(f"Axis {i}: {axis}")
# for i in range(self.joystick.get_numbuttons()):
# button = self.joystick.get_button(i)
# print(f"Button {i}: {button}")
except pygame.error:
pass
def terminate(self):
self.terminated = True
pygame.quit()
pass
pass
import typing
from dataclasses import dataclass, fields
from PySide6.QtCore import QAbstractListModel, QModelIndex, Qt, QByteArray
......
This diff is collapsed. Click to expand it.
[tool.poetry]
name = "ingame"
version = "0.1.0"
description = ""
authors = ["Mikhail Tergoev <57610802+castro-fidel@users.noreply.github.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = ">=3.11,<3.13"
PySide6 = "^6.7.0"
PySide6-Essentials = "^6.7.0"
PySide6-Addons = "^6.7.0"
shiboken6 = "^6.7.0"
pyqtgraph = "^0.13.6"
requests = "^2.31.0"
desktop-parser = "^0.1.1"
pygame = "^2.5.2"
[tool.poetry.group.dev.dependencies]
mypy = "^1.9.0"
[tool.poetry.scripts]
main = 'ingame.main:main'
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
......@@ -223,6 +223,75 @@ Rectangle {
// LOGIC
property int focusedTabs: 0;
property int focusedItems: 0;
function applyTabsFocus(inc){
if(!visible)
return;
let c = row.children;
tabs.focusedTabs += inc;
if(tabs.focusedTabs >= c.length)
tabs.focusedTabs = 0;
if(tabs.focusedTabs < 0)
tabs.focusedTabs = c.length - 1;
c[tabs.focusedTabs].forceActiveFocus();
c[tabs.focusedTabs].clicked();
/* if (c[i].focus) {
console.log("focus found");
c[i].nextItemInFocusChain().forceActiveFocus()
break
} */
}
function applyItemsFocus(inc){
if(!gamesScroller.visible)
return;
let c = gamesGrid.children;
tabs.focusedItems += inc;
if(tabs.focusedItems >= c.length)
tabs.focusedItems = 0;
if(tabs.focusedItems < 0)
tabs.focusedItems = c.length - 1;
c[tabs.focusedItems].forceActiveFocus();
// gamesScroller.contentY = c[tabs.focusedItems].y; // not working
// c[tabs.focusedItems].clicked();
}
Connections {
target: core_app
function onGamepadClickedLB(done){
if(!visible) return;
tabs.applyTabsFocus(-1)
}
function onGamepadClickedRB(done){
if(!visible) return;
tabs.applyTabsFocus(1)
}
function onGamepadAxisLeft(done){
if(!visible) return;
tabs.applyItemsFocus(-1)
}
function onGamepadAxisRight(done){
if(!visible) return;
tabs.applyItemsFocus(1)
}
function onGamepadClickedApply(done){
if(!visible) return;
let c = gamesGrid.children;
c[tabs.focusedItems].clicked();
}
}
}
......
......@@ -11,13 +11,32 @@ Window {
Connections {
target: core_app
function onGameStarted(done) {
console.log("gameStarted!!");
console.log("core_app: gameStarted");
window.scene = SceneConstants.runningScene;
}
function onGameEnded(done) {
console.log("gameEnded!!");
console.log("core_app: gameEnded");
window.scene = SceneConstants.gameInfoScene;
}
function onGamepadClickedLB(done){
// console.log("core_app: onGamepadClickedLB");
}
function onGamepadClickedRB(done){
// console.log("core_app: onGamepadClickedRB");
}
function onGamepadAxisLeft(done){
// console.log("core_app: onGamepadAxisLeft");
}
function onGamepadAxisRight(done){
// console.log("core_app: onGamepadAxisRight");
}
function onGamepadClickedApply(done){
// console.log("core_app: onGamepadClickedApply");
}
}
Component.onDestruction: {
console.log("Desctructing window");
}
id: window
......
......@@ -79,4 +79,38 @@ Rectangle {
}
}
// LOGIC
property int focusedItems: 0;
function applyItemsFocus(inc){
let c = children;
focusedItems += inc;
if(focusedItems >= c.length)
focusedItems = 0;
if(focusedItems < 0)
focusedItems = c.length - 1;
c[focusedItems].forceActiveFocus();
// c[focusedItems].clicked();
}
Connections {
target: core_app
function onGamepadAxisLeft(done){
if(!visible) return;
container.applyItemsFocus(-1)
}
function onGamepadAxisRight(done){
if(!visible) return;
container.applyItemsFocus(1)
}
function onGamepadClickedApply(done){
if(!visible) return;
let c = container.children;
c[container.focusedItems].clicked();
}
}
}
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