frontengine 1.0.21__tar.gz → 1.0.23__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.21 → frontengine-1.0.23}/PKG-INFO +1 -1
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/pet/desktop_pet.py +119 -3
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/pet/pet_setting_ui.py +7 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/user_setting/user_setting_file.py +3 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/multi_language/english.py +1 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/multi_language/traditional_chinese.py +1 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine.egg-info/PKG-INFO +1 -1
- {frontengine-1.0.21 → frontengine-1.0.23}/pyproject.toml +1 -1
- {frontengine-1.0.21 → frontengine-1.0.23}/LICENSE +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/README.md +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/__main__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/base_widget.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/gif/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/gif/paint_gif.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/image/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/image/paint_image.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/load/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/load/load_someone_make_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/overlay_factory.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/particle/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/particle/particle_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/pet/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/scene/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/scene/extend_graphic_scene.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/scene/extend_graphic_view.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/scene/scene.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/sound_player/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/sound_player/sound_effect.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/sound_player/sound_player.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/text/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/text/draw_text.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/video/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/video/video_player.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/web/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/web/webview.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/show/window_helpers.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/system_tray/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/system_tray/extend_system_tray.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/color/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/color/global_color.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/dialog/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/dialog/save_file_dialog.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/main_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/menu/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/menu/help_menu.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/menu/how_to_menu.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/menu/language_menu.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/menu/preset_menu.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/menu/settings_menu.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/control_center/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/control_center/control_center_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/gif/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/image/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/image/image_setting_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/particle/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/pet/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/sound_player/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/text/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/text/text_setting_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/utils.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/video/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/video/video_setting_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/web/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/web/web_setting_ui.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/user_setting/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/user_setting/preset_repository.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/user_setting/scene_setting.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/browser/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/browser/browser.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/critical_exit/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/critical_exit/critical_exit.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/critical_exit/win32_vk.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/exception/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/exception/exception_tags.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/exception/exceptions.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/file/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/file/open/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/file/open/open_file.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/file/save/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/file/save/save_file.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/hotkey/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/hotkey/hotkey_service.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/json/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/json/json_file.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/json/json_repository.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/json_format/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/json_format/json_process.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/logging/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/logging/loggin_instance.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/multi_language/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/multi_language/france.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/multi_language/germany.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/multi_language/italy.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/multi_language/language_wrapper.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/multi_language/russian.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/preset_schedule/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/redirect_manager/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/smart_pause/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/theme_schedule/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/web_url.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/worker/__init__.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine/worker/qthread_worker.py +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine.egg-info/SOURCES.txt +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine.egg-info/dependency_links.txt +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine.egg-info/entry_points.txt +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine.egg-info/requires.txt +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/frontengine.egg-info/top_level.txt +0 -0
- {frontengine-1.0.21 → frontengine-1.0.23}/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.23
|
|
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
|
|
@@ -168,6 +168,46 @@ def idle_seconds():
|
|
|
168
168
|
return None
|
|
169
169
|
|
|
170
170
|
|
|
171
|
+
class PetTimeline:
|
|
172
|
+
"""
|
|
173
|
+
寵物動作時間軸:一連串 (offset_seconds, action_dict),依經過秒數依序觸發。
|
|
174
|
+
A scene-timeline of (offset_seconds, action_dict) events fired in order as
|
|
175
|
+
elapsed time passes. Events are sorted; pop_due advances an internal index.
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
def __init__(self, events) -> None:
|
|
179
|
+
self._events = sorted(list(events), key=lambda item: item[0])
|
|
180
|
+
self._index = 0
|
|
181
|
+
|
|
182
|
+
def __len__(self) -> int:
|
|
183
|
+
return len(self._events)
|
|
184
|
+
|
|
185
|
+
def reset(self) -> None:
|
|
186
|
+
self._index = 0
|
|
187
|
+
|
|
188
|
+
def pop_due(self, elapsed: float) -> list:
|
|
189
|
+
due = []
|
|
190
|
+
while self._index < len(self._events) and self._events[self._index][0] <= elapsed:
|
|
191
|
+
due.append(self._events[self._index][1])
|
|
192
|
+
self._index += 1
|
|
193
|
+
return due
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def parse_timeline(raw) -> list:
|
|
197
|
+
"""把設定裡的 [{'at': 秒, ...}] 轉成 (offset, action_dict) 清單,忽略格式錯誤者。"""
|
|
198
|
+
events = []
|
|
199
|
+
if isinstance(raw, list):
|
|
200
|
+
for item in raw:
|
|
201
|
+
if not isinstance(item, dict) or "at" not in item:
|
|
202
|
+
continue
|
|
203
|
+
try:
|
|
204
|
+
offset = float(item["at"])
|
|
205
|
+
except (TypeError, ValueError):
|
|
206
|
+
continue
|
|
207
|
+
events.append((offset, item))
|
|
208
|
+
return events
|
|
209
|
+
|
|
210
|
+
|
|
171
211
|
def pop_due_reminders(now, reminders):
|
|
172
212
|
"""
|
|
173
213
|
依 now 分出已到期與未到期的提醒。reminders 為 (due_datetime, text) 清單。
|
|
@@ -329,6 +369,15 @@ def format_status(level: int, mood_level: str, hunger_level: str, labels: dict)
|
|
|
329
369
|
return f"{level_label}{level} · {mood_text} · {hunger_text}"
|
|
330
370
|
|
|
331
371
|
|
|
372
|
+
def audio_pulse_scale(level, base: float = 0.7, amplitude: float = 0.3) -> float:
|
|
373
|
+
"""把音訊音量 (0~1) 轉成脈動縮放比例 / Map an audio level (0..1) to a pulse scale."""
|
|
374
|
+
try:
|
|
375
|
+
clamped = max(0.0, min(1.0, float(level)))
|
|
376
|
+
except (TypeError, ValueError):
|
|
377
|
+
return 1.0
|
|
378
|
+
return base + amplitude * clamped
|
|
379
|
+
|
|
380
|
+
|
|
332
381
|
def size_for_level(base_size: int, level: int) -> int:
|
|
333
382
|
"""依等級放大基礎尺寸(每級 +8%,上限 +50%)/ Grow base size by level (cap +50%)."""
|
|
334
383
|
factor = min(1.5, 1.0 + 0.08 * max(0, int(level) - 1))
|
|
@@ -798,7 +847,7 @@ class DesktopPetWidget(BaseWidget):
|
|
|
798
847
|
def __init__(self, image_path: str, size: int = 128, speed: int = 3,
|
|
799
848
|
behaviour: str = BEHAVIOUR_FLOOR, climb: bool = True, talk: bool = True,
|
|
800
849
|
sound_path: Optional[str] = None, sit_on_windows: bool = True,
|
|
801
|
-
volume: float = 1.0):
|
|
850
|
+
volume: float = 1.0, audio_react: bool = False):
|
|
802
851
|
front_engine_logger.info(
|
|
803
852
|
f"[DesktopPetWidget] Init | path={image_path}, size={size}, speed={speed}, "
|
|
804
853
|
f"behaviour={behaviour}, climb={climb}, talk={talk}, sound={sound_path}, "
|
|
@@ -848,6 +897,10 @@ class DesktopPetWidget(BaseWidget):
|
|
|
848
897
|
self._init_sound(sound_path)
|
|
849
898
|
self._sit_on_windows = bool(sit_on_windows)
|
|
850
899
|
self._platform_tick = 0
|
|
900
|
+
# 音訊視覺化:依可注入的音量 provider 脈動 / Audio-reactive pulse
|
|
901
|
+
self._audio_react = bool(audio_react)
|
|
902
|
+
self._audio_level_provider = None # callable -> level 0..1 or None
|
|
903
|
+
self._audio_scale = 1.0
|
|
851
904
|
# 多寵物互動 / Multi-pet interaction
|
|
852
905
|
self._peers_provider = None
|
|
853
906
|
self._peer_greeted = False
|
|
@@ -862,7 +915,10 @@ class DesktopPetWidget(BaseWidget):
|
|
|
862
915
|
self._now_provider = datetime.now
|
|
863
916
|
self._reminders: list = []
|
|
864
917
|
self._reminder_timer = QTimer(self)
|
|
865
|
-
self._reminder_timer.timeout.connect(self.
|
|
918
|
+
self._reminder_timer.timeout.connect(self._on_schedule_tick)
|
|
919
|
+
# 場景時間軸 / Scene timeline of scheduled actions
|
|
920
|
+
self._timeline = PetTimeline(parse_timeline(user_setting_dict.get("pet_timeline", [])))
|
|
921
|
+
self._timeline_start = None
|
|
866
922
|
self._bubble = SpeechBubble()
|
|
867
923
|
self._chatter_timer = QTimer(self)
|
|
868
924
|
self._chatter_timer.setSingleShot(True)
|
|
@@ -983,13 +1039,35 @@ class DesktopPetWidget(BaseWidget):
|
|
|
983
1039
|
kind, obj = self._active
|
|
984
1040
|
return obj.currentPixmap() if kind == "movie" else obj
|
|
985
1041
|
|
|
1042
|
+
def set_audio_level_provider(self, provider) -> None:
|
|
1043
|
+
"""設定回傳目前音量 (0~1 或 None) 的函式 / Provider of the current audio level."""
|
|
1044
|
+
self._audio_level_provider = provider
|
|
1045
|
+
|
|
1046
|
+
def _update_audio_scale(self) -> None:
|
|
1047
|
+
if not self._audio_react or self._audio_level_provider is None:
|
|
1048
|
+
self._audio_scale = 1.0
|
|
1049
|
+
return
|
|
1050
|
+
try:
|
|
1051
|
+
level = self._audio_level_provider()
|
|
1052
|
+
except Exception: # pragma: no cover - defensive
|
|
1053
|
+
level = None
|
|
1054
|
+
self._audio_scale = 1.0 if level is None else audio_pulse_scale(level)
|
|
1055
|
+
|
|
986
1056
|
def draw_content(self, painter: QPainter) -> None:
|
|
987
1057
|
pixmap = self._current_pixmap()
|
|
988
1058
|
if pixmap is None or pixmap.isNull():
|
|
989
1059
|
return
|
|
990
1060
|
if self.motion.facing_left:
|
|
991
1061
|
pixmap = pixmap.transformed(QTransform().scale(-1, 1))
|
|
992
|
-
|
|
1062
|
+
scale = self._audio_scale if self._audio_react else 1.0
|
|
1063
|
+
if scale >= 0.999:
|
|
1064
|
+
painter.drawPixmap(QRect(0, 0, self.width(), self.height()), pixmap)
|
|
1065
|
+
else:
|
|
1066
|
+
# Anchor to the bottom so the feet stay on the ground while it pulses.
|
|
1067
|
+
width = int(self.width() * scale)
|
|
1068
|
+
height = int(self.height() * scale)
|
|
1069
|
+
painter.drawPixmap(
|
|
1070
|
+
QRect((self.width() - width) // 2, self.height() - height, width, height), pixmap)
|
|
993
1071
|
|
|
994
1072
|
def start_moving(self, bounds: Tuple[int, int, int, int], interval_ms: int = 33) -> None:
|
|
995
1073
|
front_engine_logger.info(f"[DesktopPetWidget] start_moving | bounds={bounds}")
|
|
@@ -1001,6 +1079,8 @@ class DesktopPetWidget(BaseWidget):
|
|
|
1001
1079
|
self._timer.start(max(10, int(interval_ms)))
|
|
1002
1080
|
self._schedule_chatter()
|
|
1003
1081
|
self._reminder_timer.start(10000)
|
|
1082
|
+
if self._timeline_start is None:
|
|
1083
|
+
self._timeline_start = self._now_provider()
|
|
1004
1084
|
|
|
1005
1085
|
def _load_messages(self) -> dict:
|
|
1006
1086
|
d = language_wrapper.language_word_dict
|
|
@@ -1069,6 +1149,39 @@ class DesktopPetWidget(BaseWidget):
|
|
|
1069
1149
|
self._reminders.append((due, str(text)))
|
|
1070
1150
|
front_engine_logger.info(f"[DesktopPetWidget] reminder set | due={due}, text={text}")
|
|
1071
1151
|
|
|
1152
|
+
def _on_schedule_tick(self) -> None:
|
|
1153
|
+
self._check_reminders()
|
|
1154
|
+
self._check_timeline()
|
|
1155
|
+
|
|
1156
|
+
def set_timeline(self, raw) -> None:
|
|
1157
|
+
"""設定場景時間軸並從現在起算 / Set the timeline and start its clock now."""
|
|
1158
|
+
self._timeline = PetTimeline(parse_timeline(raw))
|
|
1159
|
+
self._timeline_start = self._now_provider()
|
|
1160
|
+
|
|
1161
|
+
def _check_timeline(self) -> None:
|
|
1162
|
+
if self._timeline is None or self._timeline_start is None or len(self._timeline) == 0:
|
|
1163
|
+
return
|
|
1164
|
+
elapsed = (self._now_provider() - self._timeline_start).total_seconds()
|
|
1165
|
+
for action in self._timeline.pop_due(elapsed):
|
|
1166
|
+
self._run_timeline_action(action)
|
|
1167
|
+
|
|
1168
|
+
def _run_timeline_action(self, action) -> None:
|
|
1169
|
+
if not isinstance(action, dict):
|
|
1170
|
+
return
|
|
1171
|
+
if action.get("say"):
|
|
1172
|
+
self.say(str(action["say"]))
|
|
1173
|
+
if action.get("sleep"):
|
|
1174
|
+
self.motion.sleep()
|
|
1175
|
+
if action.get("wake"):
|
|
1176
|
+
self.motion.wake()
|
|
1177
|
+
if action.get("feed"):
|
|
1178
|
+
self.feed()
|
|
1179
|
+
if action.get("status"):
|
|
1180
|
+
self.show_status()
|
|
1181
|
+
behaviour = action.get("behaviour")
|
|
1182
|
+
if behaviour in (BEHAVIOUR_FLOOR, BEHAVIOUR_WANDER, BEHAVIOUR_CHASE):
|
|
1183
|
+
self.motion.behaviour = behaviour
|
|
1184
|
+
|
|
1072
1185
|
def _check_reminders(self) -> None:
|
|
1073
1186
|
if not self._reminders:
|
|
1074
1187
|
return
|
|
@@ -1228,6 +1341,9 @@ class DesktopPetWidget(BaseWidget):
|
|
|
1228
1341
|
x, y = self.motion.step()
|
|
1229
1342
|
self.move(x, y)
|
|
1230
1343
|
self._set_active_sprite(self._visual_state())
|
|
1344
|
+
if self._audio_react:
|
|
1345
|
+
self._update_audio_scale()
|
|
1346
|
+
self.update()
|
|
1231
1347
|
self._peer_tick += 1
|
|
1232
1348
|
if self._peer_tick >= 5:
|
|
1233
1349
|
self._peer_tick = 0
|
|
@@ -90,6 +90,8 @@ class PetSettingUI(QWidget):
|
|
|
90
90
|
for label, value in (("0%", 0), ("25%", 25), ("50%", 50), ("75%", 75), ("100%", 100)):
|
|
91
91
|
self.volume_combobox.addItem(label, value)
|
|
92
92
|
self.volume_combobox.setCurrentText("100%")
|
|
93
|
+
self.audio_react_checkbox = QCheckBox(
|
|
94
|
+
language_wrapper.language_word_dict.get("pet_audio_label", "React to audio"))
|
|
93
95
|
|
|
94
96
|
# Start
|
|
95
97
|
self.start_button = QPushButton(language_wrapper.language_word_dict.get("pet_start", "Spawn pet"))
|
|
@@ -124,6 +126,7 @@ class PetSettingUI(QWidget):
|
|
|
124
126
|
self.grid_layout.addWidget(self.target_monitor_combobox, 6, 1)
|
|
125
127
|
self.grid_layout.addWidget(self.volume_label, 6, 2)
|
|
126
128
|
self.grid_layout.addWidget(self.volume_combobox, 7, 2)
|
|
129
|
+
self.grid_layout.addWidget(self.audio_react_checkbox, 7, 0)
|
|
127
130
|
|
|
128
131
|
def _spawn_pet(self) -> None:
|
|
129
132
|
"""建立、顯示並開始移動一隻寵物(供 Start 與右鍵複製共用)。"""
|
|
@@ -139,6 +142,7 @@ class PetSettingUI(QWidget):
|
|
|
139
142
|
sound_path=self.pet_sound_path,
|
|
140
143
|
sit_on_windows=self.sit_checkbox.isChecked(),
|
|
141
144
|
volume=int(self.volume_combobox.currentData()) / 100.0,
|
|
145
|
+
audio_react=self.audio_react_checkbox.isChecked(),
|
|
142
146
|
)
|
|
143
147
|
pet.clone_requested.connect(self._spawn_pet)
|
|
144
148
|
pet.set_peers_provider(lambda me=pet: self._peer_centers(me))
|
|
@@ -253,6 +257,7 @@ class PetSettingUI(QWidget):
|
|
|
253
257
|
"sit": self.sit_checkbox.isChecked(),
|
|
254
258
|
"target_monitor": self.target_monitor_combobox.currentText(),
|
|
255
259
|
"volume": self.volume_combobox.currentText(),
|
|
260
|
+
"audio_react": self.audio_react_checkbox.isChecked(),
|
|
256
261
|
}
|
|
257
262
|
|
|
258
263
|
def set_state(self, state: dict) -> None:
|
|
@@ -288,3 +293,5 @@ class PetSettingUI(QWidget):
|
|
|
288
293
|
index = self.volume_combobox.findText(str(state["volume"]))
|
|
289
294
|
if index >= 0:
|
|
290
295
|
self.volume_combobox.setCurrentIndex(index)
|
|
296
|
+
if "audio_react" in state:
|
|
297
|
+
self.audio_react_checkbox.setChecked(bool(state["audio_react"]))
|
|
@@ -42,6 +42,9 @@ user_setting_dict: Dict[str, Any] = {
|
|
|
42
42
|
# 桌面寵物親密度(累積互動)
|
|
43
43
|
# Desktop pet affection (accumulated interactions)
|
|
44
44
|
"pet_affection": 0,
|
|
45
|
+
# 桌面寵物場景時間軸:[{"at": 秒, "say"/"sleep"/"feed"/"behaviour": ...}, ...]
|
|
46
|
+
# Desktop pet scene timeline of scheduled actions
|
|
47
|
+
"pet_timeline": [],
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
|
|
@@ -247,6 +247,7 @@ english_word_dict = {
|
|
|
247
247
|
"pet_talk_label": "Speech bubbles",
|
|
248
248
|
"pet_sit_label": "Sit on windows",
|
|
249
249
|
"pet_volume_label": "Volume",
|
|
250
|
+
"pet_audio_label": "React to audio",
|
|
250
251
|
"pet_chatter_morning": "Good morning!|Rise and shine!|Ready for the day?",
|
|
251
252
|
"pet_chatter_afternoon": "Good afternoon!|Taking a break?|Keep it up!",
|
|
252
253
|
"pet_chatter_evening": "Good evening!|How was your day?|Almost done?",
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/multi_language/traditional_chinese.py
RENAMED
|
@@ -248,6 +248,7 @@ traditional_chinese_word_dict = {
|
|
|
248
248
|
"pet_talk_label": "對話泡泡",
|
|
249
249
|
"pet_sit_label": "站在視窗上",
|
|
250
250
|
"pet_volume_label": "音量",
|
|
251
|
+
"pet_audio_label": "隨音訊律動",
|
|
251
252
|
"pet_chatter_morning": "早安!|新的一天開始囉!|準備好了嗎?",
|
|
252
253
|
"pet_chatter_afternoon": "午安!|要不要休息一下?|繼續加油!",
|
|
253
254
|
"pet_chatter_evening": "晚上好!|今天過得如何?|快完成了嗎?",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: frontengine
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.23
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/control_center/control_center_ui.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/particle/particle_setting_ui.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_manager.py
RENAMED
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/gif.py
RENAMED
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/image.py
RENAMED
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/registry.py
RENAMED
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/sound.py
RENAMED
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/text.py
RENAMED
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/video.py
RENAMED
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_page/web.py
RENAMED
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/ui/page/scene_setting/scene_setting_ui.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
|
{frontengine-1.0.21 → frontengine-1.0.23}/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
|
|
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.21 → frontengine-1.0.23}/frontengine/utils/multi_language/language_wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/multi_language/simplified_chinese.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/frontengine/utils/smart_pause/smart_pause_service.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.21 → frontengine-1.0.23}/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
|
|
File without changes
|
|
File without changes
|