frontengine 1.0.1__tar.gz → 1.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {frontengine-1.0.1 → frontengine-1.0.3}/PKG-INFO +1 -1
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/__init__.py +3 -1
- frontengine-1.0.3/frontengine/show/pet/desktop_pet.py +297 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/dialog/choose_file_dialog.py +10 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/main_ui.py +6 -1
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/menu/preset_menu.py +1 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/control_center/control_center_ui.py +9 -2
- frontengine-1.0.3/frontengine/ui/page/pet/pet_setting_ui.py +168 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/multi_language/english.py +11 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/multi_language/traditional_chinese.py +11 -0
- frontengine-1.0.3/frontengine/utils/theme_schedule/__init__.py +0 -0
- frontengine-1.0.3/frontengine/worker/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine.egg-info/PKG-INFO +1 -1
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine.egg-info/SOURCES.txt +4 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/pyproject.toml +1 -1
- {frontengine-1.0.1 → frontengine-1.0.3}/LICENSE +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/README.md +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/__main__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/base_widget.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/gif/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/gif/paint_gif.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/image/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/image/paint_image.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/load/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/load/load_someone_make_ui.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/overlay_factory.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/particle/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/particle/particle_ui.py +0 -0
- {frontengine-1.0.1/frontengine/show/scene → frontengine-1.0.3/frontengine/show/pet}/__init__.py +0 -0
- {frontengine-1.0.1/frontengine/show/sound_player → frontengine-1.0.3/frontengine/show/scene}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/scene/extend_graphic_scene.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/scene/extend_graphic_view.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/scene/scene.py +0 -0
- {frontengine-1.0.1/frontengine/show/text → frontengine-1.0.3/frontengine/show/sound_player}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/sound_player/sound_effect.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/sound_player/sound_player.py +0 -0
- {frontengine-1.0.1/frontengine/show/video → frontengine-1.0.3/frontengine/show/text}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/text/draw_text.py +0 -0
- {frontengine-1.0.1/frontengine/show/web → frontengine-1.0.3/frontengine/show/video}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/video/video_player.py +0 -0
- {frontengine-1.0.1/frontengine/system_tray → frontengine-1.0.3/frontengine/show/web}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/web/webview.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/show/window_helpers.py +0 -0
- {frontengine-1.0.1/frontengine/ui → frontengine-1.0.3/frontengine/system_tray}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/system_tray/extend_system_tray.py +0 -0
- {frontengine-1.0.1/frontengine/ui/color → frontengine-1.0.3/frontengine/ui}/__init__.py +0 -0
- {frontengine-1.0.1/frontengine/ui/dialog → frontengine-1.0.3/frontengine/ui/color}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/color/global_color.py +0 -0
- {frontengine-1.0.1/frontengine/ui/menu → frontengine-1.0.3/frontengine/ui/dialog}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/dialog/save_file_dialog.py +0 -0
- {frontengine-1.0.1/frontengine/ui/page → frontengine-1.0.3/frontengine/ui/menu}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/menu/help_menu.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/menu/how_to_menu.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/menu/language_menu.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/menu/settings_menu.py +0 -0
- {frontengine-1.0.1/frontengine/ui/page/control_center → frontengine-1.0.3/frontengine/ui/page}/__init__.py +0 -0
- {frontengine-1.0.1/frontengine/ui/page/gif → frontengine-1.0.3/frontengine/ui/page/control_center}/__init__.py +0 -0
- {frontengine-1.0.1/frontengine/ui/page/image → frontengine-1.0.3/frontengine/ui/page/gif}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
- {frontengine-1.0.1/frontengine/ui/page/particle → frontengine-1.0.3/frontengine/ui/page/image}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/image/image_setting_ui.py +0 -0
- {frontengine-1.0.1/frontengine/ui/page/scene_setting → frontengine-1.0.3/frontengine/ui/page/particle}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
- {frontengine-1.0.1/frontengine/ui/page/scene_setting/scene_page → frontengine-1.0.3/frontengine/ui/page/pet}/__init__.py +0 -0
- {frontengine-1.0.1/frontengine/ui/page/sound_player → frontengine-1.0.3/frontengine/ui/page/scene_setting}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
- {frontengine-1.0.1/frontengine/ui/page/text → frontengine-1.0.3/frontengine/ui/page/scene_setting/scene_page}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
- {frontengine-1.0.1/frontengine/ui/page/video → frontengine-1.0.3/frontengine/ui/page/sound_player}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
- {frontengine-1.0.1/frontengine/ui/page/web → frontengine-1.0.3/frontengine/ui/page/text}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/text/text_setting_ui.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/utils.py +0 -0
- {frontengine-1.0.1/frontengine/user_setting → frontengine-1.0.3/frontengine/ui/page/video}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/video/video_setting_ui.py +0 -0
- {frontengine-1.0.1/frontengine/utils → frontengine-1.0.3/frontengine/ui/page/web}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/web/web_setting_ui.py +0 -0
- {frontengine-1.0.1/frontengine/utils/browser → frontengine-1.0.3/frontengine/user_setting}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/user_setting/preset_repository.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/user_setting/scene_setting.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/user_setting/user_setting_file.py +0 -0
- {frontengine-1.0.1/frontengine/utils/critical_exit → frontengine-1.0.3/frontengine/utils}/__init__.py +0 -0
- {frontengine-1.0.1/frontengine/utils/file → frontengine-1.0.3/frontengine/utils/browser}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/browser/browser.py +0 -0
- {frontengine-1.0.1/frontengine/utils/hotkey → frontengine-1.0.3/frontengine/utils/critical_exit}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/critical_exit/critical_exit.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/critical_exit/win32_vk.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/exception/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/exception/exception_tags.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/exception/exceptions.py +0 -0
- {frontengine-1.0.1/frontengine/utils/json → frontengine-1.0.3/frontengine/utils/file}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/file/open/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/file/open/open_file.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/file/save/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/file/save/save_file.py +0 -0
- {frontengine-1.0.1/frontengine/utils/logging → frontengine-1.0.3/frontengine/utils/hotkey}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/hotkey/hotkey_service.py +0 -0
- {frontengine-1.0.1/frontengine/utils/multi_language → frontengine-1.0.3/frontengine/utils/json}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/json/json_file.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/json/json_repository.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/json_format/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/json_format/json_process.py +0 -0
- {frontengine-1.0.1/frontengine/utils/preset_schedule → frontengine-1.0.3/frontengine/utils/logging}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/logging/loggin_instance.py +0 -0
- {frontengine-1.0.1/frontengine/utils/redirect_manager → frontengine-1.0.3/frontengine/utils/multi_language}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/multi_language/france.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/multi_language/germany.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/multi_language/italy.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/multi_language/language_wrapper.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/multi_language/russian.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
- {frontengine-1.0.1/frontengine/utils/smart_pause → frontengine-1.0.3/frontengine/utils/preset_schedule}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
- {frontengine-1.0.1/frontengine/utils/theme_schedule → frontengine-1.0.3/frontengine/utils/redirect_manager}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
- {frontengine-1.0.1/frontengine/worker → frontengine-1.0.3/frontengine/utils/smart_pause}/__init__.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/web_url.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine/worker/qthread_worker.py +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine.egg-info/dependency_links.txt +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine.egg-info/entry_points.txt +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine.egg-info/requires.txt +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/frontengine.egg-info/top_level.txt +0 -0
- {frontengine-1.0.1 → frontengine-1.0.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: frontengine
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: FrontEngine is use-define frontview or only use like screen saver
|
|
5
5
|
Author-email: JE-Chen <jechenmailman@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/Intergration-Automation-Testing/FrontEngine
|
|
@@ -4,6 +4,7 @@ from frontengine.show.load.load_someone_make_ui import load_extend_ui_file
|
|
|
4
4
|
from frontengine.show.load.load_someone_make_ui import load_ui_file
|
|
5
5
|
from frontengine.show.sound_player.sound_effect import SoundEffectWidget
|
|
6
6
|
from frontengine.show.sound_player.sound_player import SoundPlayer
|
|
7
|
+
from frontengine.show.pet.desktop_pet import DesktopPetWidget
|
|
7
8
|
from frontengine.show.text.draw_text import TextWidget
|
|
8
9
|
from frontengine.show.video.video_player import VideoWidget
|
|
9
10
|
from frontengine.show.web.webview import WebWidget
|
|
@@ -16,6 +17,7 @@ from frontengine.ui.page.image.image_setting_ui import ImageSettingUI
|
|
|
16
17
|
from frontengine.ui.page.sound_player.sound_player_setting_ui import SoundPlayerSettingUI
|
|
17
18
|
from frontengine.ui.page.video.video_setting_ui import VideoSettingUI
|
|
18
19
|
from frontengine.ui.page.control_center.control_center_ui import ControlCenterUI
|
|
20
|
+
from frontengine.ui.page.pet.pet_setting_ui import PetSettingUI
|
|
19
21
|
from frontengine.ui.page.scene_setting.scene_setting_ui import SceneSettingUI
|
|
20
22
|
from frontengine.ui.main_ui import FrontEngineMainUI
|
|
21
23
|
from frontengine.ui.main_ui import FrontEngine_EXTEND_TAB
|
|
@@ -26,5 +28,5 @@ __all__ = [
|
|
|
26
28
|
"WebWidget", "ImageWidget", "VideoWidget", "language_wrapper", "load_extend_ui_file", "load_ui_file",
|
|
27
29
|
"TextSettingUI", "WEBSettingUI", "GIFSettingUI", "ImageSettingUI", "SoundPlayerSettingUI",
|
|
28
30
|
"VideoSettingUI", "ControlCenterUI", "SceneSettingUI", "FrontEngineMainUI",
|
|
29
|
-
"FrontEngine_EXTEND_TAB", "RedirectManager"
|
|
31
|
+
"FrontEngine_EXTEND_TAB", "RedirectManager", "DesktopPetWidget", "PetSettingUI"
|
|
30
32
|
]
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import random as _random_module
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Optional, Tuple
|
|
4
|
+
|
|
5
|
+
from PySide6.QtCore import Qt, QRect, QTimer
|
|
6
|
+
from PySide6.QtGui import QAction, QCursor, QMovie, QPainter, QPixmap, QTransform
|
|
7
|
+
from PySide6.QtWidgets import QMenu, QMessageBox
|
|
8
|
+
|
|
9
|
+
from frontengine.show.base_widget import BaseWidget
|
|
10
|
+
from frontengine.show.window_helpers import apply_overlay_window_flags
|
|
11
|
+
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
12
|
+
from frontengine.utils.multi_language.language_wrapper import language_wrapper
|
|
13
|
+
|
|
14
|
+
# 行為模式 / Behaviour modes
|
|
15
|
+
BEHAVIOUR_FLOOR = "floor" # walk on the floor with gravity, throw & bounce
|
|
16
|
+
BEHAVIOUR_WANDER = "wander" # free 2D bounce, no gravity
|
|
17
|
+
BEHAVIOUR_CHASE = "chase" # chase the mouse cursor, sleep when caught
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PetMotion:
|
|
21
|
+
"""
|
|
22
|
+
純邏輯的寵物移動模型(不依賴 Qt,完全可測試)。包含:
|
|
23
|
+
- 重力落下、落地、彈跳(受動量丟出後)
|
|
24
|
+
- 走路/發呆的隨機行為狀態機(rng 可注入以利測試)
|
|
25
|
+
- 追逐游標模式(追到後進入睡眠,游標移動即醒)
|
|
26
|
+
A pure, Qt-free motion model: gravity fall/land/bounce (after a throw),
|
|
27
|
+
a random walk/idle behaviour state machine (injectable rng), and a
|
|
28
|
+
cursor-chase mode that sleeps once it catches the target.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
GRAVITY = 2.0
|
|
32
|
+
BOUNCE_DAMPING = 0.55
|
|
33
|
+
WALL_DAMPING = 0.6
|
|
34
|
+
BOUNCE_THRESHOLD = 8.0
|
|
35
|
+
CHASE_STOP_DISTANCE = 10.0
|
|
36
|
+
CHASE_SPEED_FACTOR = 2.0
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
x: int,
|
|
41
|
+
y: int,
|
|
42
|
+
width: int,
|
|
43
|
+
height: int,
|
|
44
|
+
bounds: Tuple[int, int, int, int],
|
|
45
|
+
speed: int = 3,
|
|
46
|
+
behaviour: str = BEHAVIOUR_FLOOR,
|
|
47
|
+
rng=None,
|
|
48
|
+
) -> None:
|
|
49
|
+
self.x = float(x)
|
|
50
|
+
self.y = float(y)
|
|
51
|
+
self.width = int(width)
|
|
52
|
+
self.height = int(height)
|
|
53
|
+
self.bounds = bounds # (left, top, right, bottom)
|
|
54
|
+
self.speed = max(1, int(speed))
|
|
55
|
+
self.behaviour = behaviour
|
|
56
|
+
self._rng = rng if rng is not None else _random_module.SystemRandom()
|
|
57
|
+
self.vx = float(self.speed)
|
|
58
|
+
self.vy = 0.0 if behaviour != BEHAVIOUR_WANDER else float(self.speed)
|
|
59
|
+
self._airborne = False
|
|
60
|
+
self.state = "walk" # walk | idle
|
|
61
|
+
self._state_ticks = 0
|
|
62
|
+
self.target: Optional[Tuple[float, float]] = None
|
|
63
|
+
self.asleep = False
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def facing_left(self) -> bool:
|
|
67
|
+
return self.vx < 0
|
|
68
|
+
|
|
69
|
+
def set_bounds(self, bounds: Tuple[int, int, int, int]) -> None:
|
|
70
|
+
self.bounds = bounds
|
|
71
|
+
|
|
72
|
+
def set_target(self, x: float, y: float) -> None:
|
|
73
|
+
self.target = (float(x), float(y))
|
|
74
|
+
|
|
75
|
+
def throw(self, vx: float, vy: float) -> None:
|
|
76
|
+
"""拖曳放開後以動量丟出(只在重力模式有意義)。"""
|
|
77
|
+
self.vx = float(vx)
|
|
78
|
+
self.vy = float(vy)
|
|
79
|
+
self._airborne = True
|
|
80
|
+
self.asleep = False
|
|
81
|
+
|
|
82
|
+
def step(self) -> Tuple[int, int]:
|
|
83
|
+
left, top, right, bottom = self.bounds
|
|
84
|
+
floor_y = bottom - self.height
|
|
85
|
+
if self.behaviour == BEHAVIOUR_CHASE:
|
|
86
|
+
return self._step_chase(left, top, right, bottom)
|
|
87
|
+
if self.behaviour == BEHAVIOUR_WANDER:
|
|
88
|
+
return self._step_wander(left, top, right, bottom)
|
|
89
|
+
return self._step_floor(left, top, right, bottom, floor_y)
|
|
90
|
+
|
|
91
|
+
# --- floor / gravity ---
|
|
92
|
+
def _step_floor(self, left, top, right, bottom, floor_y) -> Tuple[int, int]:
|
|
93
|
+
airborne = self._airborne or self.y < floor_y - 0.5
|
|
94
|
+
if airborne:
|
|
95
|
+
self.vy += self.GRAVITY
|
|
96
|
+
self.x += self.vx
|
|
97
|
+
self.y += self.vy
|
|
98
|
+
if self.x <= left:
|
|
99
|
+
self.x = float(left)
|
|
100
|
+
self.vx = abs(self.vx) * self.WALL_DAMPING
|
|
101
|
+
elif self.x + self.width >= right:
|
|
102
|
+
self.x = float(right - self.width)
|
|
103
|
+
self.vx = -abs(self.vx) * self.WALL_DAMPING
|
|
104
|
+
if self.y <= top:
|
|
105
|
+
self.y = float(top)
|
|
106
|
+
self.vy = abs(self.vy) * self.WALL_DAMPING
|
|
107
|
+
if self.y >= floor_y:
|
|
108
|
+
self.y = float(floor_y)
|
|
109
|
+
if abs(self.vy) > self.BOUNCE_THRESHOLD:
|
|
110
|
+
self.vy = -self.vy * self.BOUNCE_DAMPING
|
|
111
|
+
else:
|
|
112
|
+
self.vy = 0.0
|
|
113
|
+
self._airborne = False
|
|
114
|
+
self.vx = float(self.speed) if self.vx >= 0 else float(-self.speed)
|
|
115
|
+
self._new_state(force_walk=True)
|
|
116
|
+
return int(self.x), int(self.y)
|
|
117
|
+
|
|
118
|
+
# grounded: random walk / idle
|
|
119
|
+
self.y = float(floor_y)
|
|
120
|
+
if self._state_ticks <= 0:
|
|
121
|
+
self._new_state()
|
|
122
|
+
self._state_ticks -= 1
|
|
123
|
+
if self.state == "walk":
|
|
124
|
+
self.x += self.vx
|
|
125
|
+
if self.x <= left:
|
|
126
|
+
self.x = float(left)
|
|
127
|
+
self.vx = abs(self.vx)
|
|
128
|
+
elif self.x + self.width >= right:
|
|
129
|
+
self.x = float(right - self.width)
|
|
130
|
+
self.vx = -abs(self.vx)
|
|
131
|
+
return int(self.x), int(self.y)
|
|
132
|
+
|
|
133
|
+
def _new_state(self, force_walk: bool = False) -> None:
|
|
134
|
+
if force_walk or self._rng.random() < 0.65:
|
|
135
|
+
self.state = "walk"
|
|
136
|
+
if not force_walk:
|
|
137
|
+
self.vx = float(self.speed) if self._rng.random() < 0.5 else float(-self.speed)
|
|
138
|
+
self._state_ticks = self._rng.randint(30, 120)
|
|
139
|
+
else:
|
|
140
|
+
self.state = "idle"
|
|
141
|
+
self._state_ticks = self._rng.randint(20, 80)
|
|
142
|
+
|
|
143
|
+
# --- free wander ---
|
|
144
|
+
def _step_wander(self, left, top, right, bottom) -> Tuple[int, int]:
|
|
145
|
+
if abs(self.vy) < 1e-9:
|
|
146
|
+
self.vy = float(self.speed)
|
|
147
|
+
self.x += self.vx
|
|
148
|
+
self.y += self.vy
|
|
149
|
+
if self.x <= left:
|
|
150
|
+
self.x = float(left)
|
|
151
|
+
self.vx = abs(self.vx)
|
|
152
|
+
elif self.x + self.width >= right:
|
|
153
|
+
self.x = float(right - self.width)
|
|
154
|
+
self.vx = -abs(self.vx)
|
|
155
|
+
if self.y <= top:
|
|
156
|
+
self.y = float(top)
|
|
157
|
+
self.vy = abs(self.vy)
|
|
158
|
+
elif self.y + self.height >= bottom:
|
|
159
|
+
self.y = float(bottom - self.height)
|
|
160
|
+
self.vy = -abs(self.vy)
|
|
161
|
+
return int(self.x), int(self.y)
|
|
162
|
+
|
|
163
|
+
# --- chase cursor ---
|
|
164
|
+
def _step_chase(self, left, top, right, bottom) -> Tuple[int, int]:
|
|
165
|
+
if self.target is None:
|
|
166
|
+
return int(self.x), int(self.y)
|
|
167
|
+
target_x, target_y = self.target
|
|
168
|
+
dx = target_x - (self.x + self.width / 2)
|
|
169
|
+
dy = target_y - (self.y + self.height / 2)
|
|
170
|
+
distance = (dx * dx + dy * dy) ** 0.5
|
|
171
|
+
if distance <= self.CHASE_STOP_DISTANCE:
|
|
172
|
+
self.asleep = True
|
|
173
|
+
return int(self.x), int(self.y)
|
|
174
|
+
self.asleep = False
|
|
175
|
+
step = float(self.speed) * self.CHASE_SPEED_FACTOR
|
|
176
|
+
self.x += step * (dx / distance)
|
|
177
|
+
self.y += step * (dy / distance)
|
|
178
|
+
self.vx = abs(self.vx) if dx >= 0 else -abs(self.vx)
|
|
179
|
+
self.x = min(max(self.x, float(left)), float(right - self.width))
|
|
180
|
+
self.y = min(max(self.y, float(top)), float(bottom - self.height))
|
|
181
|
+
return int(self.x), int(self.y)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class DesktopPetWidget(BaseWidget):
|
|
185
|
+
"""
|
|
186
|
+
桌面寵物:可自主走動、可拖曳丟出、可追游標的動畫精靈。支援 GIF 與靜態圖。
|
|
187
|
+
A draggable, throwable, cursor-chasing animated sprite (GIF or image).
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
def __init__(self, image_path: str, size: int = 128, speed: int = 3,
|
|
191
|
+
behaviour: str = BEHAVIOUR_FLOOR):
|
|
192
|
+
front_engine_logger.info(
|
|
193
|
+
f"[DesktopPetWidget] Init | path={image_path}, size={size}, speed={speed}, behaviour={behaviour}"
|
|
194
|
+
)
|
|
195
|
+
super().__init__()
|
|
196
|
+
self.opacity = 1.0
|
|
197
|
+
self.pet_size: int = max(16, int(size))
|
|
198
|
+
self.image_path: Path = Path(image_path)
|
|
199
|
+
self.movie: Optional[QMovie] = None
|
|
200
|
+
self.pixmap: Optional[QPixmap] = None
|
|
201
|
+
self._dragging: bool = False
|
|
202
|
+
self._drag_offset = None
|
|
203
|
+
self._last_move_delta: Tuple[int, int] = (0, 0)
|
|
204
|
+
|
|
205
|
+
if self.image_path.exists() and self.image_path.is_file():
|
|
206
|
+
if self.image_path.suffix.lower() in (".gif", ".webp"):
|
|
207
|
+
self.movie = QMovie(str(self.image_path))
|
|
208
|
+
self.movie.frameChanged.connect(self.update)
|
|
209
|
+
self.movie.start()
|
|
210
|
+
else:
|
|
211
|
+
self.pixmap = QPixmap(str(self.image_path))
|
|
212
|
+
else:
|
|
213
|
+
front_engine_logger.error(f"[DesktopPetWidget] File not found: {self.image_path}")
|
|
214
|
+
message_box = QMessageBox(self)
|
|
215
|
+
message_box.setText(language_wrapper.language_word_dict.get("pet_message_box_text", "Pet image not found"))
|
|
216
|
+
message_box.show()
|
|
217
|
+
|
|
218
|
+
self.resize(self.pet_size, self.pet_size)
|
|
219
|
+
self.motion = PetMotion(0, 0, self.pet_size, self.pet_size, (0, 0, 1920, 1080), speed, behaviour)
|
|
220
|
+
|
|
221
|
+
self._timer = QTimer(self)
|
|
222
|
+
self._timer.timeout.connect(self._on_tick)
|
|
223
|
+
|
|
224
|
+
self.close_action = QAction(language_wrapper.language_word_dict.get("control_center_close_all", "Close"), self)
|
|
225
|
+
self.close_action.triggered.connect(self.close)
|
|
226
|
+
self.menu = QMenu(self)
|
|
227
|
+
self.menu.addAction(self.close_action)
|
|
228
|
+
|
|
229
|
+
def set_pet_window_flag(self) -> None:
|
|
230
|
+
"""寵物需接收滑鼠以便拖曳,故 allow_input=True 並置頂。"""
|
|
231
|
+
apply_overlay_window_flags(self, show_on_bottom=False, allow_input=True)
|
|
232
|
+
|
|
233
|
+
def _current_pixmap(self) -> Optional[QPixmap]:
|
|
234
|
+
if self.movie is not None:
|
|
235
|
+
return self.movie.currentPixmap()
|
|
236
|
+
return self.pixmap
|
|
237
|
+
|
|
238
|
+
def draw_content(self, painter: QPainter) -> None:
|
|
239
|
+
pixmap = self._current_pixmap()
|
|
240
|
+
if pixmap is None or pixmap.isNull():
|
|
241
|
+
return
|
|
242
|
+
if self.motion.facing_left:
|
|
243
|
+
pixmap = pixmap.transformed(QTransform().scale(-1, 1))
|
|
244
|
+
painter.drawPixmap(QRect(0, 0, self.width(), self.height()), pixmap)
|
|
245
|
+
|
|
246
|
+
def start_moving(self, bounds: Tuple[int, int, int, int], interval_ms: int = 33) -> None:
|
|
247
|
+
front_engine_logger.info(f"[DesktopPetWidget] start_moving | bounds={bounds}")
|
|
248
|
+
left, top, right, bottom = bounds
|
|
249
|
+
self.motion.set_bounds(bounds)
|
|
250
|
+
self.motion.x = float(left)
|
|
251
|
+
self.motion.y = float(bottom - self.pet_size)
|
|
252
|
+
self.move(int(self.motion.x), int(self.motion.y))
|
|
253
|
+
self._timer.start(max(10, int(interval_ms)))
|
|
254
|
+
|
|
255
|
+
def _on_tick(self) -> None:
|
|
256
|
+
if self._dragging:
|
|
257
|
+
return
|
|
258
|
+
if self.motion.behaviour == BEHAVIOUR_CHASE:
|
|
259
|
+
cursor = QCursor.pos()
|
|
260
|
+
self.motion.set_target(cursor.x(), cursor.y())
|
|
261
|
+
x, y = self.motion.step()
|
|
262
|
+
self.move(x, y)
|
|
263
|
+
|
|
264
|
+
# --- dragging + throwing ---
|
|
265
|
+
def mousePressEvent(self, event) -> None:
|
|
266
|
+
if event.button() == Qt.MouseButton.LeftButton:
|
|
267
|
+
self._dragging = True
|
|
268
|
+
self._last_move_delta = (0, 0)
|
|
269
|
+
self._drag_offset = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
|
|
270
|
+
super().mousePressEvent(event)
|
|
271
|
+
|
|
272
|
+
def mouseMoveEvent(self, event) -> None:
|
|
273
|
+
if self._dragging and self._drag_offset is not None:
|
|
274
|
+
new_top_left = event.globalPosition().toPoint() - self._drag_offset
|
|
275
|
+
self._last_move_delta = (new_top_left.x() - self.x(), new_top_left.y() - self.y())
|
|
276
|
+
self.move(new_top_left)
|
|
277
|
+
super().mouseMoveEvent(event)
|
|
278
|
+
|
|
279
|
+
def mouseReleaseEvent(self, event) -> None:
|
|
280
|
+
if self._dragging:
|
|
281
|
+
self._dragging = False
|
|
282
|
+
self.motion.x = float(self.x())
|
|
283
|
+
self.motion.y = float(self.y())
|
|
284
|
+
# Fling with the momentum of the last drag movement (floor mode).
|
|
285
|
+
if self.motion.behaviour == BEHAVIOUR_FLOOR:
|
|
286
|
+
self.motion.throw(self._last_move_delta[0], self._last_move_delta[1])
|
|
287
|
+
super().mouseReleaseEvent(event)
|
|
288
|
+
|
|
289
|
+
def contextMenuEvent(self, event) -> None:
|
|
290
|
+
self.menu.popup(event.globalPos())
|
|
291
|
+
|
|
292
|
+
def closeEvent(self, event) -> None:
|
|
293
|
+
if self._timer.isActive():
|
|
294
|
+
self._timer.stop()
|
|
295
|
+
if self.movie is not None:
|
|
296
|
+
self.movie.stop()
|
|
297
|
+
super().closeEvent(event)
|
|
@@ -85,6 +85,16 @@ def choose_player_sound(trigger_ui: QWidget) -> Optional[str]:
|
|
|
85
85
|
)
|
|
86
86
|
|
|
87
87
|
|
|
88
|
+
def choose_pet(trigger_ui: QWidget) -> Optional[str]:
|
|
89
|
+
"""選擇桌面寵物圖片 (gif/webp/png/jpg) / Choose a desktop-pet sprite."""
|
|
90
|
+
return choose_file(
|
|
91
|
+
trigger_ui,
|
|
92
|
+
file_filter="Pet sprite (*.gif;*.webp;*.png;*.jpg)",
|
|
93
|
+
extensions=[".gif", ".webp", ".png", ".jpg"],
|
|
94
|
+
warning_message=language_wrapper.language_word_dict.get("gif_setting_message_box")
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
88
98
|
def choose_video(trigger_ui: QWidget) -> Optional[str]:
|
|
89
99
|
"""選擇影片檔案 (mp4) / Choose video file"""
|
|
90
100
|
return choose_file(
|
|
@@ -18,6 +18,7 @@ from frontengine.ui.page.control_center.control_center_ui import ControlCenterUI
|
|
|
18
18
|
from frontengine.ui.page.gif.gif_setting_ui import GIFSettingUI
|
|
19
19
|
from frontengine.ui.page.image.image_setting_ui import ImageSettingUI
|
|
20
20
|
from frontengine.ui.page.particle.particle_setting_ui import ParticleSettingUI
|
|
21
|
+
from frontengine.ui.page.pet.pet_setting_ui import PetSettingUI
|
|
21
22
|
from frontengine.ui.page.scene_setting.scene_setting_ui import SceneSettingUI
|
|
22
23
|
from frontengine.ui.page.sound_player.sound_player_setting_ui import SoundPlayerSettingUI
|
|
23
24
|
from frontengine.ui.page.text.text_setting_ui import TextSettingUI
|
|
@@ -98,6 +99,7 @@ class FrontEngineMainUI(QMainWindow):
|
|
|
98
99
|
self.text_setting_ui = TextSettingUI()
|
|
99
100
|
self.scene_setting_ui = SceneSettingUI()
|
|
100
101
|
self.particle_setting_ui = ParticleSettingUI()
|
|
102
|
+
self.pet_setting_ui = PetSettingUI()
|
|
101
103
|
|
|
102
104
|
# 控制中心
|
|
103
105
|
# Control Center
|
|
@@ -110,7 +112,8 @@ class FrontEngineMainUI(QMainWindow):
|
|
|
110
112
|
self.text_setting_ui,
|
|
111
113
|
self.scene_setting_ui,
|
|
112
114
|
self.particle_setting_ui,
|
|
113
|
-
redirect_output
|
|
115
|
+
redirect_output,
|
|
116
|
+
pet_setting_ui=self.pet_setting_ui,
|
|
114
117
|
)
|
|
115
118
|
|
|
116
119
|
# Menu Bar
|
|
@@ -200,6 +203,7 @@ class FrontEngineMainUI(QMainWindow):
|
|
|
200
203
|
(self.text_setting_ui, "tab_text_text"),
|
|
201
204
|
(self.scene_setting_ui, "tab_scene_text"),
|
|
202
205
|
(self.particle_setting_ui, "tab_particle_text"),
|
|
206
|
+
(self.pet_setting_ui, "tab_pet_text"),
|
|
203
207
|
(self.control_center_ui, "tab_control_center_text"),
|
|
204
208
|
]
|
|
205
209
|
|
|
@@ -351,6 +355,7 @@ class FrontEngineMainUI(QMainWindow):
|
|
|
351
355
|
self.sound_player_setting_ui.sound_widget_list.clear()
|
|
352
356
|
self.text_setting_ui.text_widget_list.clear()
|
|
353
357
|
self.particle_setting_ui.particle_list.clear()
|
|
358
|
+
self.pet_setting_ui.pet_list.clear()
|
|
354
359
|
self.scene_setting_ui.close_scene()
|
|
355
360
|
super().close()
|
|
356
361
|
if self.main_app:
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/control_center/control_center_ui.py
RENAMED
|
@@ -31,7 +31,8 @@ class ControlCenterUI(QWidget):
|
|
|
31
31
|
text_setting_ui: TextSettingUI,
|
|
32
32
|
scene_setting_ui: SceneSettingUI,
|
|
33
33
|
particle_setting_ui: ParticleSettingUI,
|
|
34
|
-
redirect_output: bool = True
|
|
34
|
+
redirect_output: bool = True,
|
|
35
|
+
pet_setting_ui=None,
|
|
35
36
|
):
|
|
36
37
|
front_engine_logger.info(
|
|
37
38
|
f"[ControlCenterUI] Init | video={video_setting_ui}, image={image_setting_ui}, web={web_setting_ui}, "
|
|
@@ -54,6 +55,7 @@ class ControlCenterUI(QWidget):
|
|
|
54
55
|
self.text_setting_ui = text_setting_ui
|
|
55
56
|
self.scene_setting_ui = scene_setting_ui
|
|
56
57
|
self.particle_setting_ui = particle_setting_ui
|
|
58
|
+
self.pet_setting_ui = pet_setting_ui
|
|
57
59
|
|
|
58
60
|
# Buttons
|
|
59
61
|
self.clear_video_button = self._create_button("control_center_close_all_video", self.clear_video)
|
|
@@ -151,11 +153,13 @@ class ControlCenterUI(QWidget):
|
|
|
151
153
|
self.sound_player_setting_ui.sound_widget_list.clear()
|
|
152
154
|
self.text_setting_ui.text_widget_list.clear()
|
|
153
155
|
self.particle_setting_ui.particle_list.clear()
|
|
156
|
+
if self.pet_setting_ui is not None:
|
|
157
|
+
self.pet_setting_ui.pet_list.clear()
|
|
154
158
|
self.scene_setting_ui.close_scene()
|
|
155
159
|
|
|
156
160
|
def _all_overlay_widget_lists(self) -> list:
|
|
157
161
|
"""回傳所有覆蓋層 widget 清單 / All overlay widget lists."""
|
|
158
|
-
|
|
162
|
+
lists = [
|
|
159
163
|
self.video_setting_ui.video_widget_list,
|
|
160
164
|
self.image_setting_ui.image_widget_list,
|
|
161
165
|
self.web_setting_ui.web_widget_list,
|
|
@@ -164,6 +168,9 @@ class ControlCenterUI(QWidget):
|
|
|
164
168
|
self.text_setting_ui.text_widget_list,
|
|
165
169
|
self.particle_setting_ui.particle_list,
|
|
166
170
|
]
|
|
171
|
+
if self.pet_setting_ui is not None:
|
|
172
|
+
lists.append(self.pet_setting_ui.pet_list)
|
|
173
|
+
return lists
|
|
167
174
|
|
|
168
175
|
def _for_each_overlay(self, action) -> None:
|
|
169
176
|
"""
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from PySide6.QtGui import QGuiApplication
|
|
4
|
+
from PySide6.QtWidgets import (
|
|
5
|
+
QWidget, QGridLayout, QLabel, QPushButton, QMessageBox, QComboBox,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
from frontengine.show.pet.desktop_pet import (
|
|
9
|
+
DesktopPetWidget, BEHAVIOUR_FLOOR, BEHAVIOUR_WANDER, BEHAVIOUR_CHASE,
|
|
10
|
+
)
|
|
11
|
+
from frontengine.ui.dialog.choose_file_dialog import choose_pet
|
|
12
|
+
from frontengine.ui.page.utils import (
|
|
13
|
+
build_recent_combobox,
|
|
14
|
+
enable_file_drop,
|
|
15
|
+
reload_recent_combobox,
|
|
16
|
+
)
|
|
17
|
+
from frontengine.user_setting.user_setting_file import add_recent_file
|
|
18
|
+
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
19
|
+
from frontengine.utils.multi_language.language_wrapper import language_wrapper
|
|
20
|
+
|
|
21
|
+
_PET_EXTENSIONS = (".gif", ".webp", ".png", ".jpg")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PetSettingUI(QWidget):
|
|
25
|
+
def __init__(self):
|
|
26
|
+
front_engine_logger.info("[PetSettingUI] Init")
|
|
27
|
+
super().__init__()
|
|
28
|
+
self.grid_layout = QGridLayout(self)
|
|
29
|
+
self.grid_layout.setContentsMargins(0, 0, 0, 0)
|
|
30
|
+
|
|
31
|
+
# Init variable
|
|
32
|
+
self.pet_list: list = []
|
|
33
|
+
self.ready_to_play = False
|
|
34
|
+
self.pet_image_path: Optional[str] = None
|
|
35
|
+
|
|
36
|
+
# Choose file
|
|
37
|
+
self.choose_file_button = QPushButton(
|
|
38
|
+
language_wrapper.language_word_dict.get("pet_choose_file", "Choose pet sprite")
|
|
39
|
+
)
|
|
40
|
+
self.choose_file_button.clicked.connect(self.choose_and_play)
|
|
41
|
+
self.ready_label = QLabel(language_wrapper.language_word_dict.get("Not Ready"))
|
|
42
|
+
|
|
43
|
+
# Size
|
|
44
|
+
self.size_label = QLabel(language_wrapper.language_word_dict.get("pet_size_label", "Size"))
|
|
45
|
+
self.size_combobox = QComboBox()
|
|
46
|
+
self.size_combobox.addItems(["64", "96", "128", "192", "256"])
|
|
47
|
+
self.size_combobox.setCurrentText("128")
|
|
48
|
+
|
|
49
|
+
# Speed
|
|
50
|
+
self.speed_label = QLabel(language_wrapper.language_word_dict.get("pet_speed_label", "Speed"))
|
|
51
|
+
self.speed_combobox = QComboBox()
|
|
52
|
+
self.speed_combobox.addItems([str(n) for n in range(1, 11)])
|
|
53
|
+
self.speed_combobox.setCurrentText("3")
|
|
54
|
+
|
|
55
|
+
# Behaviour
|
|
56
|
+
self.behaviour_label = QLabel(language_wrapper.language_word_dict.get("pet_behaviour_label", "Behaviour"))
|
|
57
|
+
self.behaviour_combobox = QComboBox()
|
|
58
|
+
self.behaviour_combobox.addItem(
|
|
59
|
+
language_wrapper.language_word_dict.get("pet_behaviour_floor", "Walk on floor"), BEHAVIOUR_FLOOR)
|
|
60
|
+
self.behaviour_combobox.addItem(
|
|
61
|
+
language_wrapper.language_word_dict.get("pet_behaviour_wander", "Free wander"), BEHAVIOUR_WANDER)
|
|
62
|
+
self.behaviour_combobox.addItem(
|
|
63
|
+
language_wrapper.language_word_dict.get("pet_behaviour_chase", "Chase cursor"), BEHAVIOUR_CHASE)
|
|
64
|
+
|
|
65
|
+
# Start
|
|
66
|
+
self.start_button = QPushButton(language_wrapper.language_word_dict.get("pet_start", "Spawn pet"))
|
|
67
|
+
self.start_button.clicked.connect(self.start_play_pet)
|
|
68
|
+
|
|
69
|
+
# Recent files
|
|
70
|
+
self.recent_files_label = QLabel(language_wrapper.language_word_dict.get("recent_files_label", "Recent"))
|
|
71
|
+
self.recent_files_combobox = build_recent_combobox("pet")
|
|
72
|
+
self.recent_files_combobox.activated.connect(self._apply_recent_file)
|
|
73
|
+
|
|
74
|
+
# Drag and drop
|
|
75
|
+
self._drop_filter = enable_file_drop(self, _PET_EXTENSIONS, self._on_file_dropped)
|
|
76
|
+
|
|
77
|
+
# Layout
|
|
78
|
+
self.grid_layout.addWidget(self.choose_file_button, 0, 0)
|
|
79
|
+
self.grid_layout.addWidget(self.ready_label, 0, 1)
|
|
80
|
+
self.grid_layout.addWidget(self.size_label, 1, 0)
|
|
81
|
+
self.grid_layout.addWidget(self.size_combobox, 1, 1)
|
|
82
|
+
self.grid_layout.addWidget(self.speed_label, 2, 0)
|
|
83
|
+
self.grid_layout.addWidget(self.speed_combobox, 2, 1)
|
|
84
|
+
self.grid_layout.addWidget(self.behaviour_label, 3, 0)
|
|
85
|
+
self.grid_layout.addWidget(self.behaviour_combobox, 3, 1)
|
|
86
|
+
self.grid_layout.addWidget(self.start_button, 4, 0)
|
|
87
|
+
self.grid_layout.addWidget(self.recent_files_label, 5, 0)
|
|
88
|
+
self.grid_layout.addWidget(self.recent_files_combobox, 5, 1)
|
|
89
|
+
|
|
90
|
+
def _create_pet_widget(self) -> DesktopPetWidget:
|
|
91
|
+
pet = DesktopPetWidget(
|
|
92
|
+
image_path=self.pet_image_path,
|
|
93
|
+
size=int(self.size_combobox.currentText()),
|
|
94
|
+
speed=int(self.speed_combobox.currentText()),
|
|
95
|
+
behaviour=self.behaviour_combobox.currentData(),
|
|
96
|
+
)
|
|
97
|
+
pet.set_pet_window_flag()
|
|
98
|
+
self.pet_list.append(pet)
|
|
99
|
+
return pet
|
|
100
|
+
|
|
101
|
+
def start_play_pet(self) -> None:
|
|
102
|
+
front_engine_logger.info("[PetSettingUI] start_play_pet")
|
|
103
|
+
if not self.pet_image_path or not self.ready_to_play:
|
|
104
|
+
message_box = QMessageBox(self)
|
|
105
|
+
message_box.setText(language_wrapper.language_word_dict.get("not_prepare"))
|
|
106
|
+
message_box.exec()
|
|
107
|
+
return
|
|
108
|
+
pet = self._create_pet_widget()
|
|
109
|
+
screen = QGuiApplication.primaryScreen()
|
|
110
|
+
geometry = screen.availableGeometry() if screen is not None else None
|
|
111
|
+
pet.show()
|
|
112
|
+
if geometry is not None:
|
|
113
|
+
bounds = (geometry.left(), geometry.top(), geometry.right(), geometry.bottom())
|
|
114
|
+
pet.start_moving(bounds)
|
|
115
|
+
|
|
116
|
+
def choose_and_play(self) -> None:
|
|
117
|
+
front_engine_logger.info("[PetSettingUI] choose_and_play")
|
|
118
|
+
self.ready_label.setText(language_wrapper.language_word_dict.get("Not Ready"))
|
|
119
|
+
self.ready_to_play = False
|
|
120
|
+
self.pet_image_path = choose_pet(self)
|
|
121
|
+
if self.pet_image_path:
|
|
122
|
+
self.ready_label.setText(language_wrapper.language_word_dict.get("Ready"))
|
|
123
|
+
self.ready_to_play = True
|
|
124
|
+
add_recent_file("pet", self.pet_image_path)
|
|
125
|
+
reload_recent_combobox(self.recent_files_combobox, "pet")
|
|
126
|
+
|
|
127
|
+
def _apply_recent_file(self, _index: int = 0) -> None:
|
|
128
|
+
path = self.recent_files_combobox.currentData()
|
|
129
|
+
self.recent_files_combobox.setCurrentIndex(0)
|
|
130
|
+
if not path:
|
|
131
|
+
return
|
|
132
|
+
self.pet_image_path = path
|
|
133
|
+
self.ready_to_play = True
|
|
134
|
+
self.ready_label.setText(language_wrapper.language_word_dict.get("Ready"))
|
|
135
|
+
|
|
136
|
+
def _on_file_dropped(self, path: str) -> None:
|
|
137
|
+
front_engine_logger.info(f"[PetSettingUI] _on_file_dropped | path={path}")
|
|
138
|
+
self.pet_image_path = path
|
|
139
|
+
self.ready_to_play = True
|
|
140
|
+
self.ready_label.setText(language_wrapper.language_word_dict.get("Ready"))
|
|
141
|
+
add_recent_file("pet", path)
|
|
142
|
+
reload_recent_combobox(self.recent_files_combobox, "pet")
|
|
143
|
+
|
|
144
|
+
def get_state(self) -> dict:
|
|
145
|
+
return {
|
|
146
|
+
"pet_image_path": self.pet_image_path,
|
|
147
|
+
"size": self.size_combobox.currentText(),
|
|
148
|
+
"speed": self.speed_combobox.currentText(),
|
|
149
|
+
"behaviour": self.behaviour_combobox.currentData(),
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
def set_state(self, state: dict) -> None:
|
|
153
|
+
if state.get("pet_image_path"):
|
|
154
|
+
self.pet_image_path = state["pet_image_path"]
|
|
155
|
+
self.ready_to_play = True
|
|
156
|
+
self.ready_label.setText(language_wrapper.language_word_dict.get("Ready"))
|
|
157
|
+
for combobox, key in ((self.size_combobox, "size"), (self.speed_combobox, "speed")):
|
|
158
|
+
if state.get(key) is not None:
|
|
159
|
+
index = combobox.findText(str(state[key]))
|
|
160
|
+
if index >= 0:
|
|
161
|
+
combobox.setCurrentIndex(index)
|
|
162
|
+
behaviour = state.get("behaviour")
|
|
163
|
+
if behaviour is None and "gravity" in state: # back-compat with old presets
|
|
164
|
+
behaviour = BEHAVIOUR_FLOOR if state.get("gravity") else BEHAVIOUR_WANDER
|
|
165
|
+
if behaviour is not None:
|
|
166
|
+
index = self.behaviour_combobox.findData(behaviour)
|
|
167
|
+
if index >= 0:
|
|
168
|
+
self.behaviour_combobox.setCurrentIndex(index)
|
|
@@ -214,4 +214,15 @@ english_word_dict = {
|
|
|
214
214
|
"web_zoom_label": "Zoom",
|
|
215
215
|
"web_refresh_label": "Auto refresh",
|
|
216
216
|
"web_refresh_off": "Off",
|
|
217
|
+
# Desktop pet
|
|
218
|
+
"tab_pet_text": "Pet",
|
|
219
|
+
"pet_choose_file": "Choose pet sprite",
|
|
220
|
+
"pet_size_label": "Size",
|
|
221
|
+
"pet_speed_label": "Speed",
|
|
222
|
+
"pet_behaviour_label": "Behaviour",
|
|
223
|
+
"pet_behaviour_floor": "Walk on floor",
|
|
224
|
+
"pet_behaviour_wander": "Free wander",
|
|
225
|
+
"pet_behaviour_chase": "Chase cursor",
|
|
226
|
+
"pet_start": "Spawn pet",
|
|
227
|
+
"pet_message_box_text": "Pet image not found",
|
|
217
228
|
}
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/multi_language/traditional_chinese.py
RENAMED
|
@@ -215,4 +215,15 @@ traditional_chinese_word_dict = {
|
|
|
215
215
|
"web_zoom_label": "縮放",
|
|
216
216
|
"web_refresh_label": "自動重新整理",
|
|
217
217
|
"web_refresh_off": "關閉",
|
|
218
|
+
# Desktop pet
|
|
219
|
+
"tab_pet_text": "桌面寵物",
|
|
220
|
+
"pet_choose_file": "選擇寵物圖片",
|
|
221
|
+
"pet_size_label": "大小",
|
|
222
|
+
"pet_speed_label": "速度",
|
|
223
|
+
"pet_behaviour_label": "行為",
|
|
224
|
+
"pet_behaviour_floor": "沿底部行走",
|
|
225
|
+
"pet_behaviour_wander": "自由漫遊",
|
|
226
|
+
"pet_behaviour_chase": "追逐游標",
|
|
227
|
+
"pet_start": "召喚寵物",
|
|
228
|
+
"pet_message_box_text": "找不到寵物圖片",
|
|
218
229
|
}
|
|
File without changes
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: frontengine
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: FrontEngine is use-define frontview or only use like screen saver
|
|
5
5
|
Author-email: JE-Chen <jechenmailman@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/Intergration-Automation-Testing/FrontEngine
|
|
@@ -21,6 +21,8 @@ frontengine/show/load/__init__.py
|
|
|
21
21
|
frontengine/show/load/load_someone_make_ui.py
|
|
22
22
|
frontengine/show/particle/__init__.py
|
|
23
23
|
frontengine/show/particle/particle_ui.py
|
|
24
|
+
frontengine/show/pet/__init__.py
|
|
25
|
+
frontengine/show/pet/desktop_pet.py
|
|
24
26
|
frontengine/show/scene/__init__.py
|
|
25
27
|
frontengine/show/scene/extend_graphic_scene.py
|
|
26
28
|
frontengine/show/scene/extend_graphic_view.py
|
|
@@ -60,6 +62,8 @@ frontengine/ui/page/image/__init__.py
|
|
|
60
62
|
frontengine/ui/page/image/image_setting_ui.py
|
|
61
63
|
frontengine/ui/page/particle/__init__.py
|
|
62
64
|
frontengine/ui/page/particle/particle_setting_ui.py
|
|
65
|
+
frontengine/ui/page/pet/__init__.py
|
|
66
|
+
frontengine/ui/page/pet/pet_setting_ui.py
|
|
63
67
|
frontengine/ui/page/scene_setting/__init__.py
|
|
64
68
|
frontengine/ui/page/scene_setting/scene_manager.py
|
|
65
69
|
frontengine/ui/page/scene_setting/scene_setting_ui.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1/frontengine/show/scene → frontengine-1.0.3/frontengine/show/pet}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1/frontengine/show/video → frontengine-1.0.3/frontengine/show/text}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1/frontengine/show/web → frontengine-1.0.3/frontengine/show/video}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1/frontengine/system_tray → frontengine-1.0.3/frontengine/show/web}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1/frontengine/ui/dialog → frontengine-1.0.3/frontengine/ui/color}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1/frontengine/ui/menu → frontengine-1.0.3/frontengine/ui/dialog}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/image.py
RENAMED
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/registry.py
RENAMED
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/sound.py
RENAMED
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/text.py
RENAMED
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_page/video.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/scene_setting/scene_setting_ui.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/ui/page/sound_player/sound_player_setting_ui.py
RENAMED
|
File without changes
|
{frontengine-1.0.1/frontengine/ui/page/web → frontengine-1.0.3/frontengine/ui/page/text}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1/frontengine/utils → frontengine-1.0.3/frontengine/ui/page/web}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1/frontengine/utils/file → frontengine-1.0.3/frontengine/utils/browser}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/critical_exit/check_key_is_press.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1/frontengine/utils/json → frontengine-1.0.3/frontengine/utils/file}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/multi_language/language_wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/multi_language/simplified_chinese.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/preset_schedule/preset_schedule_service.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/redirect_manager/redirect_manager_class.py
RENAMED
|
File without changes
|
{frontengine-1.0.1/frontengine/worker → frontengine-1.0.3/frontengine/utils/smart_pause}/__init__.py
RENAMED
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/smart_pause/smart_pause_service.py
RENAMED
|
File without changes
|
{frontengine-1.0.1 → frontengine-1.0.3}/frontengine/utils/theme_schedule/theme_schedule_service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|