frontengine 1.0.58__tar.gz → 1.0.60__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.
Files changed (255) hide show
  1. {frontengine-1.0.58 → frontengine-1.0.60}/PKG-INFO +1 -1
  2. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/main_ui.py +78 -34
  3. frontengine-1.0.60/frontengine/ui/nav/sidebar.py +112 -0
  4. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/control_center/control_center_ui.py +29 -32
  5. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/focus/focus_setting_ui.py +25 -15
  6. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/gif/gif_setting_ui.py +22 -21
  7. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/image/image_setting_ui.py +25 -24
  8. frontengine-1.0.60/frontengine/ui/page/layout_kit.py +316 -0
  9. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/particle/particle_setting_ui.py +25 -24
  10. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/pet/pet_setting_ui.py +36 -40
  11. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/presentation/presentation_setting_ui.py +35 -27
  12. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/scene_setting/scene_setting_ui.py +12 -8
  13. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/screen_care/screen_care_setting_ui.py +34 -26
  14. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +18 -14
  15. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/text/text_setting_ui.py +31 -33
  16. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/tools/tools_setting_ui.py +50 -41
  17. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/video/video_setting_ui.py +26 -25
  18. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/wallpaper/wallpaper_setting_ui.py +27 -24
  19. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/web/web_setting_ui.py +28 -24
  20. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/widgets/widgets_setting_ui.py +25 -19
  21. frontengine-1.0.60/frontengine/ui/style/app_style.py +200 -0
  22. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/multi_language/english.py +55 -1
  23. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/multi_language/france.py +55 -1
  24. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/multi_language/germany.py +55 -1
  25. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/multi_language/italy.py +55 -1
  26. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/multi_language/russian.py +55 -1
  27. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/multi_language/simplified_chinese.py +55 -1
  28. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/multi_language/traditional_chinese.py +55 -1
  29. frontengine-1.0.60/frontengine/utils/window_pin/__init__.py +0 -0
  30. frontengine-1.0.60/frontengine/utils/workshop/__init__.py +0 -0
  31. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine.egg-info/PKG-INFO +1 -1
  32. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine.egg-info/SOURCES.txt +5 -0
  33. {frontengine-1.0.58 → frontengine-1.0.60}/pyproject.toml +1 -1
  34. {frontengine-1.0.58 → frontengine-1.0.60}/LICENSE +0 -0
  35. {frontengine-1.0.58 → frontengine-1.0.60}/README.md +0 -0
  36. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/__init__.py +0 -0
  37. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/__main__.py +0 -0
  38. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/__init__.py +0 -0
  39. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/base_widget.py +0 -0
  40. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/camera/__init__.py +0 -0
  41. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/camera/camera_widget.py +0 -0
  42. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/canvas/__init__.py +0 -0
  43. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/canvas/whiteboard_widget.py +0 -0
  44. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/capture/__init__.py +0 -0
  45. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/capture/region_capture.py +0 -0
  46. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/focus_shield/__init__.py +0 -0
  47. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/focus_shield/focus_shield_widget.py +0 -0
  48. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/gif/__init__.py +0 -0
  49. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/gif/paint_gif.py +0 -0
  50. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/image/__init__.py +0 -0
  51. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/image/paint_image.py +0 -0
  52. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/load/__init__.py +0 -0
  53. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/load/load_someone_make_ui.py +0 -0
  54. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/measure/__init__.py +0 -0
  55. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/measure/measure_widget.py +0 -0
  56. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/monitor/__init__.py +0 -0
  57. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/monitor/monitor_widget.py +0 -0
  58. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/notes/__init__.py +0 -0
  59. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/notes/sticky_note_widget.py +0 -0
  60. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/overlay_factory.py +0 -0
  61. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/particle/__init__.py +0 -0
  62. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/particle/particle_ui.py +0 -0
  63. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/pet/__init__.py +0 -0
  64. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/pet/desktop_pet.py +0 -0
  65. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/presentation/__init__.py +0 -0
  66. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/presentation/annotation_overlay.py +0 -0
  67. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/presentation/cursor_effects.py +0 -0
  68. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/presentation/keystroke_display.py +0 -0
  69. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/presentation/magnifier.py +0 -0
  70. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/scene/__init__.py +0 -0
  71. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/scene/extend_graphic_scene.py +0 -0
  72. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/scene/extend_graphic_view.py +0 -0
  73. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/scene/scene.py +0 -0
  74. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/screen_care/__init__.py +0 -0
  75. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/screen_care/color_vision_widget.py +0 -0
  76. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/screen_care/screen_filter.py +0 -0
  77. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/sound_player/__init__.py +0 -0
  78. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/sound_player/sound_effect.py +0 -0
  79. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/sound_player/sound_player.py +0 -0
  80. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/spectrum/__init__.py +0 -0
  81. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/spectrum/spectrum_widget.py +0 -0
  82. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/text/__init__.py +0 -0
  83. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/text/draw_text.py +0 -0
  84. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/toast/__init__.py +0 -0
  85. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/toast/toast_widget.py +0 -0
  86. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/video/__init__.py +0 -0
  87. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/video/video_player.py +0 -0
  88. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/wallpaper/__init__.py +0 -0
  89. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/wallpaper/wallpaper_widget.py +0 -0
  90. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/web/__init__.py +0 -0
  91. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/web/webview.py +0 -0
  92. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/show/window_helpers.py +0 -0
  93. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/system_tray/__init__.py +0 -0
  94. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/system_tray/extend_system_tray.py +0 -0
  95. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/__init__.py +0 -0
  96. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/color/__init__.py +0 -0
  97. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/color/global_color.py +0 -0
  98. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/__init__.py +0 -0
  99. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/app_profile_dialog.py +0 -0
  100. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
  101. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/clipboard_dialog.py +0 -0
  102. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
  103. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/how_to_use_dialog.py +0 -0
  104. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/reminder_dialog.py +0 -0
  105. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/remote_control_dialog.py +0 -0
  106. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/screen_privacy_dialog.py +0 -0
  107. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/screen_text_dialog.py +0 -0
  108. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/signage_dialog.py +0 -0
  109. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/smart_pause_dialog.py +0 -0
  110. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/usage_report_dialog.py +0 -0
  111. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/dialog/window_pin_dialog.py +0 -0
  112. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/menu/__init__.py +0 -0
  113. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/menu/help_menu.py +0 -0
  114. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/menu/how_to_menu.py +0 -0
  115. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/menu/language_menu.py +0 -0
  116. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/menu/preset_menu.py +0 -0
  117. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/menu/settings_menu.py +0 -0
  118. {frontengine-1.0.58/frontengine/ui/page → frontengine-1.0.60/frontengine/ui/nav}/__init__.py +0 -0
  119. {frontengine-1.0.58/frontengine/ui/page/control_center → frontengine-1.0.60/frontengine/ui/page}/__init__.py +0 -0
  120. {frontengine-1.0.58/frontengine/ui/page/focus → frontengine-1.0.60/frontengine/ui/page/control_center}/__init__.py +0 -0
  121. {frontengine-1.0.58/frontengine/ui/page/gif → frontengine-1.0.60/frontengine/ui/page/focus}/__init__.py +0 -0
  122. {frontengine-1.0.58/frontengine/ui/page/image → frontengine-1.0.60/frontengine/ui/page/gif}/__init__.py +0 -0
  123. {frontengine-1.0.58/frontengine/ui/page/particle → frontengine-1.0.60/frontengine/ui/page/image}/__init__.py +0 -0
  124. {frontengine-1.0.58/frontengine/ui/page/pet → frontengine-1.0.60/frontengine/ui/page/particle}/__init__.py +0 -0
  125. {frontengine-1.0.58/frontengine/ui/page/presentation → frontengine-1.0.60/frontengine/ui/page/pet}/__init__.py +0 -0
  126. {frontengine-1.0.58/frontengine/ui/page/scene_setting → frontengine-1.0.60/frontengine/ui/page/presentation}/__init__.py +0 -0
  127. {frontengine-1.0.58/frontengine/ui/page/scene_setting/scene_page → frontengine-1.0.60/frontengine/ui/page/scene_setting}/__init__.py +0 -0
  128. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
  129. {frontengine-1.0.58/frontengine/ui/page/screen_care → frontengine-1.0.60/frontengine/ui/page/scene_setting/scene_page}/__init__.py +0 -0
  130. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
  131. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
  132. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
  133. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
  134. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
  135. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
  136. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
  137. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
  138. {frontengine-1.0.58/frontengine/ui/page/sound_player → frontengine-1.0.60/frontengine/ui/page/screen_care}/__init__.py +0 -0
  139. {frontengine-1.0.58/frontengine/ui/page/text → frontengine-1.0.60/frontengine/ui/page/sound_player}/__init__.py +0 -0
  140. {frontengine-1.0.58/frontengine/ui/page/tools → frontengine-1.0.60/frontengine/ui/page/text}/__init__.py +0 -0
  141. {frontengine-1.0.58/frontengine/ui/page/video → frontengine-1.0.60/frontengine/ui/page/tools}/__init__.py +0 -0
  142. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/ui/page/utils.py +0 -0
  143. {frontengine-1.0.58/frontengine/ui/page/wallpaper → frontengine-1.0.60/frontengine/ui/page/video}/__init__.py +0 -0
  144. {frontengine-1.0.58/frontengine/ui/page/web → frontengine-1.0.60/frontengine/ui/page/wallpaper}/__init__.py +0 -0
  145. {frontengine-1.0.58/frontengine/ui/page/widgets → frontengine-1.0.60/frontengine/ui/page/web}/__init__.py +0 -0
  146. {frontengine-1.0.58/frontengine/user_setting → frontengine-1.0.60/frontengine/ui/page/widgets}/__init__.py +0 -0
  147. {frontengine-1.0.58/frontengine/utils → frontengine-1.0.60/frontengine/ui/style}/__init__.py +0 -0
  148. {frontengine-1.0.58/frontengine/utils/app_profile → frontengine-1.0.60/frontengine/user_setting}/__init__.py +0 -0
  149. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/user_setting/preset_repository.py +0 -0
  150. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/user_setting/scene_setting.py +0 -0
  151. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/user_setting/user_setting_file.py +0 -0
  152. {frontengine-1.0.58/frontengine/utils/audio_meter → frontengine-1.0.60/frontengine/utils}/__init__.py +0 -0
  153. {frontengine-1.0.58/frontengine/utils/autostart → frontengine-1.0.60/frontengine/utils/app_profile}/__init__.py +0 -0
  154. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/app_profile/app_profile_service.py +0 -0
  155. {frontengine-1.0.58/frontengine/utils/break_reminder → frontengine-1.0.60/frontengine/utils/audio_meter}/__init__.py +0 -0
  156. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/audio_meter/audio_envelope.py +0 -0
  157. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/audio_meter/loopback_capture.py +0 -0
  158. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/audio_meter/microphone_meter.py +0 -0
  159. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/audio_meter/screen_audio.py +0 -0
  160. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/audio_meter/spectrum_analyzer.py +0 -0
  161. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/audio_meter/system_audio_meter.py +0 -0
  162. {frontengine-1.0.58/frontengine/utils/browser → frontengine-1.0.60/frontengine/utils/autostart}/__init__.py +0 -0
  163. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/autostart/autostart_service.py +0 -0
  164. {frontengine-1.0.58/frontengine/utils/clipboard → frontengine-1.0.60/frontengine/utils/break_reminder}/__init__.py +0 -0
  165. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/break_reminder/break_reminder.py +0 -0
  166. {frontengine-1.0.58/frontengine/utils/color_vision → frontengine-1.0.60/frontengine/utils/browser}/__init__.py +0 -0
  167. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/browser/browser.py +0 -0
  168. {frontengine-1.0.58/frontengine/utils/critical_exit → frontengine-1.0.60/frontengine/utils/clipboard}/__init__.py +0 -0
  169. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/clipboard/clipboard_history.py +0 -0
  170. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/clipboard/clipboard_watcher.py +0 -0
  171. {frontengine-1.0.58/frontengine/utils/focus_shield → frontengine-1.0.60/frontengine/utils/color_vision}/__init__.py +0 -0
  172. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/color_vision/color_vision.py +0 -0
  173. {frontengine-1.0.58/frontengine/utils/focus_timer → frontengine-1.0.60/frontengine/utils/critical_exit}/__init__.py +0 -0
  174. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
  175. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/critical_exit/critical_exit.py +0 -0
  176. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/critical_exit/win32_vk.py +0 -0
  177. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/exception/__init__.py +0 -0
  178. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/exception/exception_tags.py +0 -0
  179. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/exception/exceptions.py +0 -0
  180. {frontengine-1.0.58/frontengine/utils/hotkey → frontengine-1.0.60/frontengine/utils/focus_shield}/__init__.py +0 -0
  181. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/focus_shield/focus_shield.py +0 -0
  182. {frontengine-1.0.58/frontengine/utils/input_watch → frontengine-1.0.60/frontengine/utils/focus_timer}/__init__.py +0 -0
  183. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/focus_timer/focus_timer.py +0 -0
  184. {frontengine-1.0.58/frontengine/utils/json → frontengine-1.0.60/frontengine/utils/hotkey}/__init__.py +0 -0
  185. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/hotkey/hotkey_service.py +0 -0
  186. {frontengine-1.0.58/frontengine/utils/logging → frontengine-1.0.60/frontengine/utils/input_watch}/__init__.py +0 -0
  187. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/input_watch/input_watch_service.py +0 -0
  188. {frontengine-1.0.58/frontengine/utils/measure → frontengine-1.0.60/frontengine/utils/json}/__init__.py +0 -0
  189. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/json/json_file.py +0 -0
  190. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/json/json_repository.py +0 -0
  191. {frontengine-1.0.58/frontengine/utils/midi → frontengine-1.0.60/frontengine/utils/logging}/__init__.py +0 -0
  192. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/logging/loggin_instance.py +0 -0
  193. {frontengine-1.0.58/frontengine/utils/multi_language → frontengine-1.0.60/frontengine/utils/measure}/__init__.py +0 -0
  194. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/measure/measure.py +0 -0
  195. {frontengine-1.0.58/frontengine/utils/now_playing → frontengine-1.0.60/frontengine/utils/midi}/__init__.py +0 -0
  196. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/midi/midi_input.py +0 -0
  197. {frontengine-1.0.58/frontengine/utils/pet_chat → frontengine-1.0.60/frontengine/utils/multi_language}/__init__.py +0 -0
  198. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/multi_language/language_wrapper.py +0 -0
  199. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/multi_language/retranslate.py +0 -0
  200. {frontengine-1.0.58/frontengine/utils/platform_info → frontengine-1.0.60/frontengine/utils/now_playing}/__init__.py +0 -0
  201. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/now_playing/now_playing.py +0 -0
  202. {frontengine-1.0.58/frontengine/utils/playlist → frontengine-1.0.60/frontengine/utils/pet_chat}/__init__.py +0 -0
  203. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/pet_chat/pet_chat_service.py +0 -0
  204. {frontengine-1.0.58/frontengine/utils/plugins → frontengine-1.0.60/frontengine/utils/platform_info}/__init__.py +0 -0
  205. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/platform_info/platform_info.py +0 -0
  206. {frontengine-1.0.58/frontengine/utils/power_mode → frontengine-1.0.60/frontengine/utils/playlist}/__init__.py +0 -0
  207. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/playlist/playlist.py +0 -0
  208. {frontengine-1.0.58/frontengine/utils/preset_schedule → frontengine-1.0.60/frontengine/utils/plugins}/__init__.py +0 -0
  209. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/plugins/plugin_loader.py +0 -0
  210. {frontengine-1.0.58/frontengine/utils/recording → frontengine-1.0.60/frontengine/utils/power_mode}/__init__.py +0 -0
  211. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/power_mode/power_mode.py +0 -0
  212. {frontengine-1.0.58/frontengine/utils/redirect_manager → frontengine-1.0.60/frontengine/utils/preset_schedule}/__init__.py +0 -0
  213. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
  214. {frontengine-1.0.58/frontengine/utils/reminder → frontengine-1.0.60/frontengine/utils/recording}/__init__.py +0 -0
  215. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/recording/frame_recorder.py +0 -0
  216. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/recording/gif_writer.py +0 -0
  217. {frontengine-1.0.58/frontengine/utils/remote → frontengine-1.0.60/frontengine/utils/redirect_manager}/__init__.py +0 -0
  218. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
  219. {frontengine-1.0.58/frontengine/utils/screen_privacy → frontengine-1.0.60/frontengine/utils/reminder}/__init__.py +0 -0
  220. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/reminder/reminder_service.py +0 -0
  221. {frontengine-1.0.58/frontengine/utils/screen_text → frontengine-1.0.60/frontengine/utils/remote}/__init__.py +0 -0
  222. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/remote/remote_server.py +0 -0
  223. {frontengine-1.0.58/frontengine/utils/signage → frontengine-1.0.60/frontengine/utils/screen_privacy}/__init__.py +0 -0
  224. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/screen_privacy/capture_affinity.py +0 -0
  225. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/screen_privacy/share_watch.py +0 -0
  226. {frontengine-1.0.58/frontengine/utils/smart_pause → frontengine-1.0.60/frontengine/utils/screen_text}/__init__.py +0 -0
  227. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/screen_text/screen_text_service.py +0 -0
  228. {frontengine-1.0.58/frontengine/utils/system_stats → frontengine-1.0.60/frontengine/utils/signage}/__init__.py +0 -0
  229. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/signage/signage_service.py +0 -0
  230. {frontengine-1.0.58/frontengine/utils/text_source → frontengine-1.0.60/frontengine/utils/smart_pause}/__init__.py +0 -0
  231. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/smart_pause/pause_rules.py +0 -0
  232. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
  233. {frontengine-1.0.58/frontengine/utils/theme_schedule → frontengine-1.0.60/frontengine/utils/system_stats}/__init__.py +0 -0
  234. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/system_stats/system_stats.py +0 -0
  235. {frontengine-1.0.58/frontengine/utils/usage_tracking → frontengine-1.0.60/frontengine/utils/text_source}/__init__.py +0 -0
  236. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/text_source/text_source.py +0 -0
  237. {frontengine-1.0.58/frontengine/utils/virtual_camera → frontengine-1.0.60/frontengine/utils/theme_schedule}/__init__.py +0 -0
  238. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
  239. {frontengine-1.0.58/frontengine/utils/weather → frontengine-1.0.60/frontengine/utils/usage_tracking}/__init__.py +0 -0
  240. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/usage_tracking/usage_service.py +0 -0
  241. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/usage_tracking/usage_tracker.py +0 -0
  242. {frontengine-1.0.58/frontengine/utils/window_pin → frontengine-1.0.60/frontengine/utils/virtual_camera}/__init__.py +0 -0
  243. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/virtual_camera/camera_feed.py +0 -0
  244. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/virtual_camera/virtual_camera.py +0 -0
  245. {frontengine-1.0.58/frontengine/utils/workshop → frontengine-1.0.60/frontengine/utils/weather}/__init__.py +0 -0
  246. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/weather/weather_service.py +0 -0
  247. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/web_url.py +0 -0
  248. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/window_pin/window_layout.py +0 -0
  249. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/window_pin/window_pin.py +0 -0
  250. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine/utils/workshop/workshop_content.py +0 -0
  251. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine.egg-info/dependency_links.txt +0 -0
  252. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine.egg-info/entry_points.txt +0 -0
  253. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine.egg-info/requires.txt +0 -0
  254. {frontengine-1.0.58 → frontengine-1.0.60}/frontengine.egg-info/top_level.txt +0 -0
  255. {frontengine-1.0.58 → frontengine-1.0.60}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.58
3
+ Version: 1.0.60
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
@@ -7,10 +7,14 @@ from typing import Any, Dict, Optional, Type
7
7
  from PySide6.QtCore import QByteArray, QTimer
8
8
  from PySide6.QtGui import QIcon, Qt
9
9
  from PySide6.QtWidgets import (
10
- QMainWindow, QApplication, QGridLayout, QStyle, QTabWidget, QMenuBar, QWidget,
10
+ QMainWindow, QApplication, QGridLayout, QHBoxLayout, QStackedWidget, QStyle,
11
+ QMenuBar, QWidget,
11
12
  )
12
13
  from qt_material import apply_stylesheet
13
14
 
15
+ from frontengine.ui.nav.sidebar import NavigationSidebar
16
+ from frontengine.ui.style.app_style import apply_app_style
17
+
14
18
  from frontengine.show.toast.toast_widget import show_toast
15
19
  from frontengine.system_tray.extend_system_tray import ExtendSystemTray
16
20
  from frontengine.ui.menu.help_menu import build_help_menu
@@ -48,7 +52,7 @@ from frontengine.utils.critical_exit.win32_vk import keyboard_keys_table
48
52
  from frontengine.utils.hotkey.hotkey_service import HotkeyService
49
53
  from frontengine.utils.logging.loggin_instance import front_engine_logger
50
54
  from frontengine.utils.multi_language.language_wrapper import language_wrapper
51
- from frontengine.utils.multi_language.retranslate import retranslator, translate
55
+ from frontengine.utils.multi_language.retranslate import retranslator
52
56
  from frontengine.utils.plugins.plugin_loader import load_plugins
53
57
  from frontengine.utils.preset_schedule.preset_schedule_service import PresetScheduleService
54
58
  from frontengine.ui.dialog.remote_control_dialog import (
@@ -133,10 +137,20 @@ class FrontEngineMainUI(QMainWindow):
133
137
  self.grid_layout = QGridLayout()
134
138
  self.grid_layout.setContentsMargins(0, 0, 0, 0)
135
139
 
136
- # Tab Widget 作為主介面
137
- # Tab widget as main interface
138
- self.tab_widget = QTabWidget(self)
139
- self.setCentralWidget(self.tab_widget)
140
+ # 主介面:左側導覽 + 右側頁面堆疊
141
+ # Main interface: navigation on the left, the page stack on the right
142
+ self.sidebar = NavigationSidebar(self)
143
+ self.page_stack = QStackedWidget(self)
144
+ self.page_stack.setObjectName("pageBody")
145
+ self.sidebar.page_requested.connect(self.page_stack.setCurrentIndex)
146
+
147
+ central = QWidget(self)
148
+ central_layout = QHBoxLayout(central)
149
+ central_layout.setContentsMargins(0, 0, 0, 0)
150
+ central_layout.setSpacing(0)
151
+ central_layout.addWidget(self.sidebar)
152
+ central_layout.addWidget(self.page_stack, 1)
153
+ self.setCentralWidget(central)
140
154
 
141
155
  # 各功能頁面初始化
142
156
  # Initialize each functional page
@@ -368,36 +382,61 @@ class FrontEngineMainUI(QMainWindow):
368
382
  lambda attribute=attribute: getattr(self.tools_setting_ui, attribute, []))
369
383
 
370
384
  def _add_tabs(self) -> None:
371
- """加入所有內建與擴充的 Tab / Add all built-in and extended tabs"""
372
- tabs = [
373
- (self.video_setting_ui, "tab_video_text"),
374
- (self.image_setting_ui, "tab_image_text"),
375
- (self.web_setting_ui, "tab_web_text"),
376
- (self.gif_setting_ui, "tab_gif_text"),
377
- (self.sound_player_setting_ui, "tab_sound_text"),
378
- (self.text_setting_ui, "tab_text_text"),
379
- (self.scene_setting_ui, "tab_scene_text"),
380
- (self.particle_setting_ui, "tab_particle_text"),
381
- (self.pet_setting_ui, "tab_pet_text"),
382
- (self.screen_care_setting_ui, "tab_screen_care_text"),
383
- (self.presentation_setting_ui, "tab_presentation_text"),
384
- (self.wallpaper_setting_ui, "tab_wallpaper_text"),
385
- (self.focus_setting_ui, "tab_focus_text"),
386
- (self.widgets_setting_ui, "tab_widgets_text"),
387
- (self.tools_setting_ui, "tab_tools_text"),
388
- (self.control_center_ui, "tab_control_center_text"),
385
+ """
386
+ 建立左側導覽與頁面堆疊 / Build the sidebar and the page stack.
387
+
388
+ 分頁依用途分組。先前十六個分頁擠成一排,視窗一窄就長出捲動箭頭,而且並排
389
+ 的十六個詞看不出誰跟誰是一類;分組之後「我要放東西上螢幕」和「我要專心
390
+ 工作」是兩件不同的事,找起來不必逐一讀過去。
391
+ The pages are grouped by what they are for. Sixteen tabs in one row grew
392
+ scroll arrows as soon as the window narrowed, and gave no clue which
393
+ belonged together; grouped, "put something on screen" and "help me
394
+ concentrate" are visibly different errands rather than sixteen words to
395
+ read through.
396
+ """
397
+ groups = [
398
+ ("nav_group_on_screen", "On screen", [
399
+ (self.video_setting_ui, "tab_video_text"),
400
+ (self.image_setting_ui, "tab_image_text"),
401
+ (self.web_setting_ui, "tab_web_text"),
402
+ (self.gif_setting_ui, "tab_gif_text"),
403
+ (self.text_setting_ui, "tab_text_text"),
404
+ (self.sound_player_setting_ui, "tab_sound_text"),
405
+ (self.scene_setting_ui, "tab_scene_text"),
406
+ (self.particle_setting_ui, "tab_particle_text"),
407
+ ]),
408
+ ("nav_group_desktop", "Desktop", [
409
+ (self.pet_setting_ui, "tab_pet_text"),
410
+ (self.wallpaper_setting_ui, "tab_wallpaper_text"),
411
+ (self.widgets_setting_ui, "tab_widgets_text"),
412
+ ]),
413
+ ("nav_group_work", "Work", [
414
+ (self.focus_setting_ui, "tab_focus_text"),
415
+ (self.screen_care_setting_ui, "tab_screen_care_text"),
416
+ (self.presentation_setting_ui, "tab_presentation_text"),
417
+ (self.tools_setting_ui, "tab_tools_text"),
418
+ ]),
419
+ ("nav_group_control", "Control", [
420
+ (self.control_center_ui, "tab_control_center_text"),
421
+ ]),
389
422
  ]
390
423
 
391
- for index, (widget, lang_key) in enumerate(tabs):
392
- self.tab_widget.addTab(widget, translate(lang_key))
393
- # setTabText 需要索引,所以索引跟著這筆登記一起記下來
394
- # setTabText needs the index, so it travels with the entry.
395
- retranslator.bind(self.tab_widget, lang_key, "", "setTabText", index)
424
+ for group_key, group_fallback, entries in groups:
425
+ self.sidebar.add_group(group_key, group_fallback)
426
+ for widget, lang_key in entries:
427
+ index = self.page_stack.addWidget(widget)
428
+ self.sidebar.add_page(lang_key, index)
429
+
430
+ # 外掛註冊的分頁自成一組,使用者才看得出哪些不是內建的
431
+ # Plugin tabs get their own group, so it is visible which pages did not
432
+ # ship with the application.
433
+ if FrontEngine_EXTEND_TAB:
434
+ self.sidebar.add_group("nav_group_extensions", "Extensions")
435
+ for widget_name, widget in FrontEngine_EXTEND_TAB.items():
436
+ index = self.page_stack.addWidget(widget())
437
+ self.sidebar.add_page(widget_name, index, widget_name)
396
438
 
397
- # 加入外部擴充 Tab
398
- # Add external extension tabs
399
- for widget_name, widget in FrontEngine_EXTEND_TAB.items():
400
- self.tab_widget.addTab(widget(), widget_name)
439
+ self.sidebar.select_page(0)
401
440
 
402
441
  def _setup_icon(self, show_system_tray_ray: bool) -> None:
403
442
  """設定視窗 Icon 與系統托盤 / Setup window icon and system tray"""
@@ -427,7 +466,11 @@ class FrontEngineMainUI(QMainWindow):
427
466
  def startup_setting(self) -> None:
428
467
  """啟動時套用樣式並還原視窗大小/位置(無記錄時最大化) / Apply stylesheet
429
468
  and restore the saved window geometry (maximize when none is stored)."""
430
- apply_stylesheet(self, theme=user_setting_dict.get("theme"))
469
+ theme = user_setting_dict.get("theme")
470
+ apply_stylesheet(self, theme=theme)
471
+ # qt-material 會把樣式表整份寫掉,所以自訂樣式一定要接在它後面
472
+ # apply_stylesheet replaces the whole stylesheet, so ours goes after it
473
+ apply_app_style(self, theme)
431
474
  # 還原上次選的畫質檔位(設定檔一直有存,只是從來沒有人讀回來)
432
475
  # Restore the quality tier chosen last time: it was always written to the
433
476
  # settings file, just never read back.
@@ -483,6 +526,7 @@ class FrontEngineMainUI(QMainWindow):
483
526
  front_engine_logger.info(f"[FrontEngineMainUI] _apply_theme | theme={theme}")
484
527
  try:
485
528
  apply_stylesheet(self, theme=theme)
529
+ apply_app_style(self, theme)
486
530
  user_setting_dict["theme"] = theme
487
531
  except Exception as error:
488
532
  front_engine_logger.warning(f"[FrontEngineMainUI] apply theme failed: {error!r}")
@@ -0,0 +1,112 @@
1
+ """
2
+ 左側導覽:分組的分頁清單。
3
+
4
+ 先前十六個分頁擠在一排,視窗一窄就出現捲動箭頭,而且十六個並排的詞看不出誰跟
5
+ 誰是一類的。改成側邊欄之後:永遠不會溢出、目前在哪一頁隨時看得到、之後再加功
6
+ 能也只是清單多一列。
7
+
8
+ 清單項目不是 QWidget,沒辦法交給 retranslator 的 bind() 用弱參考持有,所以改用
9
+ bind_call() 這個逃生口——換語言時整份重寫一次。
10
+
11
+ The left-hand navigation: the pages as a grouped list.
12
+
13
+ Sixteen tabs in one row grew scroll arrows as soon as the window narrowed, and
14
+ sixteen words side by side gave no clue which belonged together. As a sidebar it
15
+ cannot overflow, the current page is always visible, and a new feature later is
16
+ one more line in a list.
17
+
18
+ List items are not QWidgets, so the retranslator cannot hold them weakly through
19
+ bind(); this uses the bind_call() escape hatch and rewrites the lot on a
20
+ language change.
21
+ """
22
+ from __future__ import annotations
23
+
24
+ from typing import List, Optional, Tuple
25
+
26
+ from PySide6.QtCore import QSize, Qt, Signal
27
+ from PySide6.QtWidgets import QListWidget, QListWidgetItem
28
+
29
+ from frontengine.utils.multi_language.retranslate import retranslator, translate
30
+
31
+ SIDEBAR_WIDTH = 208
32
+
33
+ # 群組標題與分頁列用 UserRole 區分,樣式與點擊行為都看這個值。
34
+ # Group headings and page rows are told apart by this UserRole value, which
35
+ # drives both styling and what a click does.
36
+ ROLE_KIND = Qt.ItemDataRole.UserRole
37
+ ROLE_PAGE_INDEX = Qt.ItemDataRole.UserRole + 1
38
+ KIND_GROUP = "group"
39
+ KIND_PAGE = "page"
40
+
41
+
42
+ class NavigationSidebar(QListWidget):
43
+ """分組的分頁清單,選到某一頁時送出 page_requested。"""
44
+
45
+ page_requested = Signal(int)
46
+
47
+ def __init__(self, parent=None):
48
+ super().__init__(parent)
49
+ self.setObjectName("navSidebar")
50
+ self.setFixedWidth(SIDEBAR_WIDTH)
51
+ self.setFrameShape(QListWidget.Shape.NoFrame)
52
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
53
+ self.setVerticalScrollMode(QListWidget.ScrollMode.ScrollPerPixel)
54
+ # 分頁列之間不需要虛線焦點框,選取本身已經夠明顯。
55
+ self.setUniformItemSizes(False)
56
+
57
+ # (item, key, fallback),換語言時照這張表重寫
58
+ self._labels: List[Tuple[QListWidgetItem, str, str]] = []
59
+ self.currentItemChanged.connect(self._on_current_item_changed)
60
+ retranslator.bind_call(self._retranslate)
61
+
62
+ def add_group(self, title_key: str, fallback: str = "") -> QListWidgetItem:
63
+ """加一列群組標題。標題不能被選取,點了也不會換頁。"""
64
+ item = QListWidgetItem(translate(title_key, fallback))
65
+ item.setData(ROLE_KIND, KIND_GROUP)
66
+ item.setFlags(Qt.ItemFlag.NoItemFlags)
67
+ item.setSizeHint(QSize(SIDEBAR_WIDTH, 34))
68
+ self.addItem(item)
69
+ self._labels.append((item, title_key, fallback))
70
+ return item
71
+
72
+ def add_page(self, title_key: str, page_index: int, fallback: str = "") -> QListWidgetItem:
73
+ """加一列分頁。page_index 對應 QStackedWidget 裡的索引。"""
74
+ item = QListWidgetItem(translate(title_key, fallback))
75
+ item.setData(ROLE_KIND, KIND_PAGE)
76
+ item.setData(ROLE_PAGE_INDEX, page_index)
77
+ item.setSizeHint(QSize(SIDEBAR_WIDTH, 32))
78
+ self.addItem(item)
79
+ self._labels.append((item, title_key, fallback))
80
+ return item
81
+
82
+ def select_page(self, page_index: int) -> bool:
83
+ """選取對應某個堆疊索引的那一列;找不到就回傳 False。"""
84
+ for row in range(self.count()):
85
+ item = self.item(row)
86
+ if item.data(ROLE_KIND) == KIND_PAGE and item.data(ROLE_PAGE_INDEX) == page_index:
87
+ self.setCurrentItem(item)
88
+ return True
89
+ return False
90
+
91
+ def page_label(self, page_index: int) -> str:
92
+ """某個堆疊索引目前顯示的文字(測試與記錄用)。"""
93
+ for row in range(self.count()):
94
+ item = self.item(row)
95
+ if item.data(ROLE_KIND) == KIND_PAGE and item.data(ROLE_PAGE_INDEX) == page_index:
96
+ return item.text()
97
+ return ""
98
+
99
+ def _on_current_item_changed(self, current: Optional[QListWidgetItem], _previous) -> None:
100
+ if current is None or current.data(ROLE_KIND) != KIND_PAGE:
101
+ return
102
+ index = current.data(ROLE_PAGE_INDEX)
103
+ if isinstance(index, int):
104
+ self.page_requested.emit(index)
105
+
106
+ def _retranslate(self) -> None:
107
+ """換語言時把每一列的文字重寫一次。"""
108
+ for item, key, fallback in self._labels:
109
+ try:
110
+ item.setText(translate(key, fallback))
111
+ except RuntimeError: # pragma: no cover - 底層物件已消失
112
+ continue
@@ -2,7 +2,7 @@ from typing import Callable
2
2
 
3
3
  from PySide6.QtCore import QTimer, Qt
4
4
  from PySide6.QtWidgets import (
5
- QComboBox, QGridLayout, QLabel, QPushButton, QScrollArea, QTextEdit, QWidget,
5
+ QComboBox, QLabel, QPushButton, QScrollArea, QTextEdit, QWidget,
6
6
  )
7
7
 
8
8
  from frontengine.show.window_helpers import set_overlay_locked
@@ -16,6 +16,7 @@ from frontengine.ui.page.text.text_setting_ui import TextSettingUI
16
16
  from frontengine.ui.page.video.video_setting_ui import VideoSettingUI
17
17
  from frontengine.ui.page.web.web_setting_ui import WEBSettingUI
18
18
  from frontengine.user_setting.user_setting_file import clear_overlay_geometry, user_setting_dict
19
+ from frontengine.ui.page.layout_kit import SettingPage
19
20
  from frontengine.utils.logging.loggin_instance import front_engine_logger
20
21
  from frontengine.utils.multi_language.language_wrapper import language_wrapper
21
22
  from frontengine.utils.multi_language.retranslate import retranslator, tr, translate
@@ -26,7 +27,7 @@ from frontengine.utils.power_mode.power_mode import (
26
27
  from frontengine.utils.redirect_manager.redirect_manager_class import redirect_manager_instance
27
28
 
28
29
 
29
- class ControlCenterUI(QWidget):
30
+ class ControlCenterUI(SettingPage):
30
31
  """
31
32
  ControlCenterUI: 控制中心面板,集中管理各種 widget 與 log panel
32
33
  ControlCenterUI: Control center panel to manage widgets and log panel
@@ -50,11 +51,11 @@ class ControlCenterUI(QWidget):
50
51
  f"gif={gif_setting_ui}, sound={sound_player_setting_ui}, text={text_setting_ui}, "
51
52
  f"scene={scene_setting_ui}, particle={particle_setting_ui}, redirect_output={redirect_output}"
52
53
  )
53
- super().__init__()
54
+ super().__init__("tab_control_center_text", "page_subtitle_control_center",
55
+ "Control Center",
56
+ "Reach every overlay on screen, whichever page opened it.")
54
57
 
55
58
  # Layout
56
- self.grid_layout = QGridLayout()
57
- self.grid_layout.setContentsMargins(0, 0, 0, 0)
58
59
  self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
59
60
 
60
61
  # UI instance
@@ -125,33 +126,29 @@ class ControlCenterUI(QWidget):
125
126
  self.log_panel_scroll_area.setViewportMargins(0, 0, 0, 0)
126
127
  self.log_panel_scroll_area.setWidget(self.log_panel)
127
128
 
128
- # Add to layout
129
- self.grid_layout.addWidget(self.clear_video_button, 0, 0)
130
- self.grid_layout.addWidget(self.clear_image_button, 1, 0)
131
- self.grid_layout.addWidget(self.clear_gif_button, 2, 0)
132
- self.grid_layout.addWidget(self.clear_web_button, 3, 0)
133
- self.grid_layout.addWidget(self.clear_sound_button, 4, 0)
134
- self.grid_layout.addWidget(self.clear_text_button, 5, 0)
135
- # 這顆按鈕本來建好、翻好、也接上了處理函式,卻沒有加進版面,所以畫面上
136
- # 根本沒有「只關閉場景」這個選項,只能用會一併關掉其他所有東西的「全部關閉」。
137
- # This button was built, translated and wired, but never added to the
138
- # layout - so there was no way to close just the scene, only the "close
139
- # all" that takes every other overlay down with it.
140
- self.grid_layout.addWidget(self.clear_scene_button, 6, 0)
141
- self.grid_layout.addWidget(self.clear_redirect_button, 7, 0)
142
- self.grid_layout.addWidget(self.hide_all_button, 8, 0)
143
- self.grid_layout.addWidget(self.show_all_button, 9, 0)
144
- self.grid_layout.addWidget(self.mute_all_button, 10, 0)
145
- self.grid_layout.addWidget(self.lock_all_button, 11, 0)
146
- self.grid_layout.addWidget(self.chroma_key_button, 12, 0)
147
- self.grid_layout.addWidget(self.reset_positions_button, 13, 0)
148
- self.grid_layout.addWidget(self.low_power_button, 14, 0)
149
- self.grid_layout.addWidget(self.quality_label, 15, 0)
150
- self.grid_layout.addWidget(self.quality_combobox, 16, 0)
151
- self.grid_layout.addWidget(self.capture_button, 17, 0)
152
- self.grid_layout.addWidget(self.clear_all_button, 18, 0)
153
- self.grid_layout.addWidget(self.log_panel_scroll_area, 0, 1, 19, 1) # rowSpan covers every button
154
- self.setLayout(self.grid_layout)
129
+ # 「關掉某一種」和「一次對全部做某件事」是兩種不同的動作,先前十九顆按鈕
130
+ # 疊成單獨一直行,兩者混在一起而且比視窗還高。
131
+ # Closing one kind and doing something to everything at once are two
132
+ # different actions; as a single column of nineteen buttons they were
133
+ # mixed together and taller than the window.
134
+ closing = self.add_section("section_close", "Close")
135
+ closing.add_button_grid(
136
+ self.clear_video_button, self.clear_image_button, self.clear_gif_button,
137
+ self.clear_web_button, self.clear_sound_button, self.clear_text_button,
138
+ self.clear_scene_button, self.clear_redirect_button)
139
+
140
+ everything = self.add_section("section_everything", "Everything at once")
141
+ everything.add_button_grid(
142
+ self.hide_all_button, self.show_all_button, self.mute_all_button,
143
+ self.lock_all_button, self.chroma_key_button, self.reset_positions_button,
144
+ self.low_power_button, self.capture_button)
145
+ everything.add_row(self.quality_label, self.quality_combobox)
146
+
147
+ log = self.add_section("section_log", "Messages")
148
+ log.add_widget(self.log_panel_scroll_area)
149
+
150
+ self.finish_body()
151
+ self.set_footer(primary=self.clear_all_button)
155
152
 
156
153
  # Redirect
157
154
  if redirect_output:
@@ -10,7 +10,9 @@ from typing import List
10
10
 
11
11
  from PySide6.QtCore import Qt
12
12
  from PySide6.QtGui import QGuiApplication
13
- from PySide6.QtWidgets import QComboBox, QGridLayout, QLabel, QPushButton, QSlider, QWidget
13
+ from PySide6.QtWidgets import QComboBox, QLabel, QPushButton, QSlider
14
+
15
+ from frontengine.ui.page.layout_kit import SettingPage
14
16
 
15
17
  from frontengine.show.focus_shield.focus_shield_widget import (
16
18
  DimBackgroundWidget, DistractionMaskWidget,
@@ -24,14 +26,13 @@ from frontengine.utils.multi_language.language_wrapper import language_wrapper
24
26
  from frontengine.utils.multi_language.retranslate import retranslator, tr
25
27
 
26
28
 
27
- class FocusSettingUI(QWidget):
29
+ class FocusSettingUI(SettingPage):
28
30
  """專注設定頁 / The focus settings page."""
29
31
 
30
32
  def __init__(self):
31
33
  front_engine_logger.info("[FocusSettingUI] Init")
32
- super().__init__()
33
- self.grid_layout = QGridLayout(self)
34
- self.grid_layout.setContentsMargins(0, 0, 0, 0)
34
+ super().__init__("tab_focus_text", "page_subtitle_focus",
35
+ "Focus", "Dim or cover whatever competes for your attention.")
35
36
 
36
37
  self.dim_widget_list: List[DimBackgroundWidget] = []
37
38
  self.mask_widget_list: List[DistractionMaskWidget] = []
@@ -73,16 +74,25 @@ class FocusSettingUI(QWidget):
73
74
  self.hint_label.setWordWrap(True)
74
75
 
75
76
  # Layout
76
- self.grid_layout.addWidget(self.dim_label, 0, 0)
77
- self.grid_layout.addWidget(self.dim_slider, 0, 1)
78
- self.grid_layout.addWidget(self.dim_button, 0, 2)
79
- self.grid_layout.addWidget(self.mask_label, 1, 0)
80
- self.grid_layout.addWidget(self.mask_region_combobox, 1, 1)
81
- self.grid_layout.addWidget(self.mask_button, 1, 2)
82
- self.grid_layout.addWidget(self.mask_percent_slider, 2, 1, 1, 2)
83
- self.grid_layout.addWidget(self.target_monitor_label, 3, 0)
84
- self.grid_layout.addWidget(self.target_monitor_combobox, 3, 1)
85
- self.grid_layout.addWidget(self.hint_label, 4, 0, 1, 3)
77
+ # 「調暗其他視窗」和「遮住某一塊」是兩個獨立開關,各自有自己的按鈕,
78
+ # 混在一格網格裡看起來像同一組設定。
79
+ # Dimming the other windows and covering one region are independent
80
+ # switches with a button each; sharing one grid made them read as one
81
+ # group of settings.
82
+ dim = self.add_section("section_options", "Dim background windows")
83
+ dim.add_row(self.dim_label, self.dim_slider)
84
+ dim.add_inline(self.dim_button)
85
+
86
+ mask = self.add_section("section_behaviour", "Cover a distraction")
87
+ mask.add_row(self.mask_label, self.mask_region_combobox)
88
+ mask.add_row("focus_mask_size_label", self.mask_percent_slider, "Size")
89
+ mask.add_inline(self.mask_button)
90
+
91
+ where = self.add_section("section_where", "Where")
92
+ where.add_row(self.target_monitor_label, self.target_monitor_combobox)
93
+
94
+ self.add_body_widget(self.hint_label)
95
+ self.finish_body()
86
96
 
87
97
  # --- shared ----------------------------------------------------------
88
98
  def target_screen(self):
@@ -1,10 +1,11 @@
1
1
  from typing import Optional
2
2
 
3
3
  from PySide6.QtCore import Qt
4
- from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QSlider, QPushButton, QMessageBox, QCheckBox
4
+ from PySide6.QtWidgets import QLabel, QSlider, QPushButton, QMessageBox, QCheckBox
5
5
 
6
6
  from frontengine.show.gif.paint_gif import GifWidget
7
7
  from frontengine.ui.dialog.choose_file_dialog import choose_gif
8
+ from frontengine.ui.page.layout_kit import SettingPage
8
9
  from frontengine.ui.page.utils import (
9
10
  build_recent_combobox,
10
11
  build_target_monitor_combobox,
@@ -22,12 +23,11 @@ from frontengine.utils.multi_language.language_wrapper import language_wrapper
22
23
  from frontengine.utils.multi_language.retranslate import tr
23
24
 
24
25
 
25
- class GIFSettingUI(QWidget):
26
+ class GIFSettingUI(SettingPage):
26
27
  def __init__(self):
27
28
  front_engine_logger.info("[GIFSettingUI] Init")
28
- super().__init__()
29
- self.grid_layout = QGridLayout(self)
30
- self.grid_layout.setContentsMargins(0, 0, 0, 0)
29
+ super().__init__("tab_gif_text", "page_subtitle_gif",
30
+ "GIF and WEBP", "Put an animation on top of everything else.")
31
31
  self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
32
32
 
33
33
  # Init variable
@@ -85,22 +85,23 @@ class GIFSettingUI(QWidget):
85
85
  self._drop_filter = enable_file_drop(self, (".gif", ".webp"), self._on_file_dropped)
86
86
 
87
87
  # Layout
88
- self.grid_layout.addWidget(self.opacity_label, 0, 0)
89
- self.grid_layout.addWidget(self.opacity_slider_value_label, 0, 1)
90
- self.grid_layout.addWidget(self.opacity_slider, 0, 2)
91
- self.grid_layout.addWidget(self.speed_label, 1, 0)
92
- self.grid_layout.addWidget(self.speed_slider_value_label, 1, 1)
93
- self.grid_layout.addWidget(self.speed_slider, 1, 2)
94
- self.grid_layout.addWidget(self.choose_file_button, 2, 0)
95
- self.grid_layout.addWidget(self.ready_label, 2, 1)
96
- self.grid_layout.addWidget(self.fullscreen_checkbox, 2, 2)
97
- self.grid_layout.addWidget(self.start_button, 3, 0)
98
- self.grid_layout.addWidget(self.show_on_all_screen_checkbox, 3, 1)
99
- self.grid_layout.addWidget(self.show_on_bottom_checkbox, 3, 2)
100
- self.grid_layout.addWidget(self.target_monitor_label, 4, 0)
101
- self.grid_layout.addWidget(self.target_monitor_combobox, 4, 1)
102
- self.grid_layout.addWidget(self.recent_files_label, 5, 0)
103
- self.grid_layout.addWidget(self.recent_files_combobox, 5, 1)
88
+ source = self.add_section("section_source", "Source")
89
+ source.add_inline(self.choose_file_button)
90
+ source.add_row(self.recent_files_label, self.recent_files_combobox)
91
+
92
+ appearance = self.add_section("section_appearance", "Appearance")
93
+ appearance.add_slider_row(
94
+ self.opacity_label, self.opacity_slider, self.opacity_slider_value_label)
95
+ appearance.add_slider_row(
96
+ self.speed_label, self.speed_slider, self.speed_slider_value_label)
97
+
98
+ where = self.add_section("section_where", "Where")
99
+ where.add_row(self.target_monitor_label, self.target_monitor_combobox)
100
+ where.add_inline(self.show_on_all_screen_checkbox, self.show_on_bottom_checkbox,
101
+ self.fullscreen_checkbox)
102
+
103
+ self.finish_body()
104
+ self.set_footer(primary=self.start_button, status=self.ready_label)
104
105
 
105
106
  def set_show_all_screen(self) -> None:
106
107
  front_engine_logger.info("[GIFSettingUI] set_show_all_screen")
@@ -2,11 +2,12 @@ from typing import Optional
2
2
 
3
3
  from PySide6.QtCore import Qt, QTimer
4
4
  from PySide6.QtWidgets import (
5
- QWidget, QGridLayout, QSlider, QLabel, QPushButton, QMessageBox, QCheckBox, QComboBox, QFileDialog,
5
+ QSlider, QLabel, QPushButton, QMessageBox, QCheckBox, QComboBox, QFileDialog,
6
6
  )
7
7
 
8
8
  from frontengine.show.image.paint_image import ImageWidget
9
9
  from frontengine.ui.dialog.choose_file_dialog import choose_image
10
+ from frontengine.ui.page.layout_kit import SettingPage
10
11
  from frontengine.ui.page.utils import (
11
12
  build_recent_combobox,
12
13
  build_target_monitor_combobox,
@@ -28,12 +29,11 @@ from frontengine.utils.multi_language.language_wrapper import language_wrapper
28
29
  from frontengine.utils.multi_language.retranslate import tr
29
30
 
30
31
 
31
- class ImageSettingUI(QWidget):
32
+ class ImageSettingUI(SettingPage):
32
33
  def __init__(self):
33
34
  front_engine_logger.info("[ImageSettingUI] Init")
34
- super().__init__()
35
- self.grid_layout = QGridLayout(self)
36
- self.grid_layout.setContentsMargins(0, 0, 0, 0)
35
+ super().__init__("tab_image_text", "page_subtitle_image",
36
+ "Image", "Put a picture on top of everything else.")
37
37
  self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
38
38
 
39
39
  # Init variable
@@ -103,25 +103,26 @@ class ImageSettingUI(QWidget):
103
103
  self._drop_filter = enable_file_drop(self, _SLIDESHOW_EXTENSIONS, self._on_file_dropped)
104
104
 
105
105
  # Layout
106
- self.grid_layout.addWidget(self.opacity_label, 0, 0)
107
- self.grid_layout.addWidget(self.opacity_slider_value_label, 0, 1)
108
- self.grid_layout.addWidget(self.opacity_slider, 0, 2)
109
- self.grid_layout.addWidget(self.choose_file_button, 1, 0)
110
- self.grid_layout.addWidget(self.ready_label, 1, 1)
111
- self.grid_layout.addWidget(self.fullscreen_checkbox, 1, 2)
112
- self.grid_layout.addWidget(self.start_button, 2, 0)
113
- self.grid_layout.addWidget(self.show_on_all_screen_checkbox, 2, 1)
114
- self.grid_layout.addWidget(self.show_on_bottom_checkbox, 2, 2)
115
- self.grid_layout.addWidget(self.target_monitor_label, 3, 0)
116
- self.grid_layout.addWidget(self.target_monitor_combobox, 3, 1)
117
- self.grid_layout.addWidget(self.recent_files_label, 4, 0)
118
- self.grid_layout.addWidget(self.recent_files_combobox, 4, 1)
119
- self.grid_layout.addWidget(self.slideshow_checkbox, 5, 0)
120
- self.grid_layout.addWidget(self.slideshow_folder_button, 5, 1)
121
- self.grid_layout.addWidget(self.slideshow_interval_label, 6, 0)
122
- self.grid_layout.addWidget(self.slideshow_interval_combobox, 6, 1)
123
- self.grid_layout.addWidget(self.slideshow_shuffle_checkbox, 7, 0)
124
- self.grid_layout.addWidget(self.slideshow_recursive_checkbox, 7, 1)
106
+ source = self.add_section("section_source", "Source")
107
+ source.add_inline(self.choose_file_button)
108
+ source.add_row(self.recent_files_label, self.recent_files_combobox)
109
+
110
+ appearance = self.add_section("section_appearance", "Appearance")
111
+ appearance.add_slider_row(
112
+ self.opacity_label, self.opacity_slider, self.opacity_slider_value_label)
113
+
114
+ slideshow = self.add_section("section_options", "Options")
115
+ slideshow.add_inline(self.slideshow_checkbox, self.slideshow_folder_button)
116
+ slideshow.add_row(self.slideshow_interval_label, self.slideshow_interval_combobox)
117
+ slideshow.add_inline(self.slideshow_shuffle_checkbox, self.slideshow_recursive_checkbox)
118
+
119
+ where = self.add_section("section_where", "Where")
120
+ where.add_row(self.target_monitor_label, self.target_monitor_combobox)
121
+ where.add_inline(self.show_on_all_screen_checkbox, self.show_on_bottom_checkbox,
122
+ self.fullscreen_checkbox)
123
+
124
+ self.finish_body()
125
+ self.set_footer(primary=self.start_button, status=self.ready_label)
125
126
 
126
127
  def set_show_all_screen(self) -> None:
127
128
  front_engine_logger.info("[ImageSettingUI] set_show_all_screen")