frontengine 1.0.73__tar.gz → 1.0.75__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 (278) hide show
  1. {frontengine-1.0.73 → frontengine-1.0.75}/PKG-INFO +1 -1
  2. frontengine-1.0.75/frontengine/show/freeze/freeze_widget.py +93 -0
  3. frontengine-1.0.75/frontengine/show/reference/reference_board.py +155 -0
  4. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/hotkey_settings_dialog.py +1 -0
  5. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/main_ui.py +11 -0
  6. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/image/image_setting_ui.py +52 -0
  7. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/presentation/presentation_setting_ui.py +74 -0
  8. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/user_setting/user_setting_file.py +1 -0
  9. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/multi_language/english.py +8 -0
  10. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/multi_language/france.py +8 -0
  11. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/multi_language/germany.py +8 -0
  12. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/multi_language/italy.py +8 -0
  13. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/multi_language/russian.py +8 -0
  14. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/multi_language/simplified_chinese.py +8 -0
  15. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/multi_language/traditional_chinese.py +8 -0
  16. frontengine-1.0.75/frontengine/utils/window_replica/__init__.py +0 -0
  17. frontengine-1.0.75/frontengine/utils/workshop/__init__.py +0 -0
  18. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine.egg-info/PKG-INFO +1 -1
  19. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine.egg-info/SOURCES.txt +4 -0
  20. {frontengine-1.0.73 → frontengine-1.0.75}/pyproject.toml +1 -1
  21. {frontengine-1.0.73 → frontengine-1.0.75}/LICENSE +0 -0
  22. {frontengine-1.0.73 → frontengine-1.0.75}/README.md +0 -0
  23. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/__init__.py +0 -0
  24. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/__main__.py +0 -0
  25. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/__init__.py +0 -0
  26. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/base_widget.py +0 -0
  27. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/camera/__init__.py +0 -0
  28. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/camera/camera_widget.py +0 -0
  29. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/canvas/__init__.py +0 -0
  30. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/canvas/whiteboard_widget.py +0 -0
  31. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/capture/__init__.py +0 -0
  32. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/capture/region_capture.py +0 -0
  33. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/draggable_window.py +0 -0
  34. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/focus_shield/__init__.py +0 -0
  35. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/focus_shield/focus_shield_widget.py +0 -0
  36. {frontengine-1.0.73/frontengine/show/gif → frontengine-1.0.75/frontengine/show/freeze}/__init__.py +0 -0
  37. {frontengine-1.0.73/frontengine/show/image → frontengine-1.0.75/frontengine/show/gif}/__init__.py +0 -0
  38. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/gif/paint_gif.py +0 -0
  39. {frontengine-1.0.73/frontengine/show/load → frontengine-1.0.75/frontengine/show/image}/__init__.py +0 -0
  40. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/image/paint_image.py +0 -0
  41. {frontengine-1.0.73/frontengine/show/measure → frontengine-1.0.75/frontengine/show/load}/__init__.py +0 -0
  42. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/load/load_someone_make_ui.py +0 -0
  43. {frontengine-1.0.73/frontengine/show/monitor → frontengine-1.0.75/frontengine/show/measure}/__init__.py +0 -0
  44. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/measure/measure_widget.py +0 -0
  45. {frontengine-1.0.73/frontengine/show/notes → frontengine-1.0.75/frontengine/show/monitor}/__init__.py +0 -0
  46. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/monitor/monitor_widget.py +0 -0
  47. {frontengine-1.0.73/frontengine/show/particle → frontengine-1.0.75/frontengine/show/notes}/__init__.py +0 -0
  48. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/notes/sticky_note_widget.py +0 -0
  49. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/overlay_factory.py +0 -0
  50. {frontengine-1.0.73/frontengine/show/pet → frontengine-1.0.75/frontengine/show/particle}/__init__.py +0 -0
  51. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/particle/particle_ui.py +0 -0
  52. {frontengine-1.0.73/frontengine/show/pinned → frontengine-1.0.75/frontengine/show/pet}/__init__.py +0 -0
  53. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/pet/desktop_pet.py +0 -0
  54. {frontengine-1.0.73/frontengine/show/presentation → frontengine-1.0.75/frontengine/show/pinned}/__init__.py +0 -0
  55. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/pinned/pinned_image.py +0 -0
  56. {frontengine-1.0.73/frontengine/show/replica → frontengine-1.0.75/frontengine/show/presentation}/__init__.py +0 -0
  57. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/presentation/annotation_overlay.py +0 -0
  58. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/presentation/cursor_effects.py +0 -0
  59. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/presentation/keystroke_display.py +0 -0
  60. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/presentation/magnifier.py +0 -0
  61. {frontengine-1.0.73/frontengine/show/scene → frontengine-1.0.75/frontengine/show/reference}/__init__.py +0 -0
  62. {frontengine-1.0.73/frontengine/show/screen_care → frontengine-1.0.75/frontengine/show/replica}/__init__.py +0 -0
  63. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/replica/replica_widget.py +0 -0
  64. {frontengine-1.0.73/frontengine/show/shortcuts → frontengine-1.0.75/frontengine/show/scene}/__init__.py +0 -0
  65. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/scene/extend_graphic_scene.py +0 -0
  66. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/scene/extend_graphic_view.py +0 -0
  67. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/scene/scene.py +0 -0
  68. {frontengine-1.0.73/frontengine/show/sound_player → frontengine-1.0.75/frontengine/show/screen_care}/__init__.py +0 -0
  69. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/screen_care/color_vision_widget.py +0 -0
  70. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/screen_care/screen_filter.py +0 -0
  71. {frontengine-1.0.73/frontengine/show/spectrum → frontengine-1.0.75/frontengine/show/shortcuts}/__init__.py +0 -0
  72. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/shortcuts/shortcut_sheet.py +0 -0
  73. {frontengine-1.0.73/frontengine/show/text → frontengine-1.0.75/frontengine/show/sound_player}/__init__.py +0 -0
  74. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/sound_player/sound_effect.py +0 -0
  75. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/sound_player/sound_player.py +0 -0
  76. {frontengine-1.0.73/frontengine/show/toast → frontengine-1.0.75/frontengine/show/spectrum}/__init__.py +0 -0
  77. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/spectrum/spectrum_widget.py +0 -0
  78. {frontengine-1.0.73/frontengine/show/video → frontengine-1.0.75/frontengine/show/text}/__init__.py +0 -0
  79. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/text/draw_text.py +0 -0
  80. {frontengine-1.0.73/frontengine/show/wallpaper → frontengine-1.0.75/frontengine/show/toast}/__init__.py +0 -0
  81. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/toast/toast_widget.py +0 -0
  82. {frontengine-1.0.73/frontengine/show/web → frontengine-1.0.75/frontengine/show/video}/__init__.py +0 -0
  83. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/video/video_player.py +0 -0
  84. {frontengine-1.0.73/frontengine/system_tray → frontengine-1.0.75/frontengine/show/wallpaper}/__init__.py +0 -0
  85. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/wallpaper/wallpaper_widget.py +0 -0
  86. {frontengine-1.0.73/frontengine/ui → frontengine-1.0.75/frontengine/show/web}/__init__.py +0 -0
  87. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/web/webview.py +0 -0
  88. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/show/window_helpers.py +0 -0
  89. {frontengine-1.0.73/frontengine/ui/color → frontengine-1.0.75/frontengine/system_tray}/__init__.py +0 -0
  90. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/system_tray/extend_system_tray.py +0 -0
  91. {frontengine-1.0.73/frontengine/ui/dialog → frontengine-1.0.75/frontengine/ui}/__init__.py +0 -0
  92. {frontengine-1.0.73/frontengine/ui/menu → frontengine-1.0.75/frontengine/ui/color}/__init__.py +0 -0
  93. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/color/global_color.py +0 -0
  94. {frontengine-1.0.73/frontengine/ui/nav → frontengine-1.0.75/frontengine/ui/dialog}/__init__.py +0 -0
  95. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/app_profile_dialog.py +0 -0
  96. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
  97. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/clipboard_dialog.py +0 -0
  98. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/how_to_use_dialog.py +0 -0
  99. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/preset_schedule_dialog.py +0 -0
  100. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/reminder_dialog.py +0 -0
  101. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/remote_control_dialog.py +0 -0
  102. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/screen_privacy_dialog.py +0 -0
  103. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/screen_text_dialog.py +0 -0
  104. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/screensaver_dialog.py +0 -0
  105. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/signage_dialog.py +0 -0
  106. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/smart_pause_dialog.py +0 -0
  107. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/usage_report_dialog.py +0 -0
  108. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/window_pin_dialog.py +0 -0
  109. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/dialog/window_replica_dialog.py +0 -0
  110. {frontengine-1.0.73/frontengine/ui/page → frontengine-1.0.75/frontengine/ui/menu}/__init__.py +0 -0
  111. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/menu/help_menu.py +0 -0
  112. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/menu/how_to_menu.py +0 -0
  113. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/menu/language_menu.py +0 -0
  114. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/menu/preset_menu.py +0 -0
  115. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/menu/settings_menu.py +0 -0
  116. {frontengine-1.0.73/frontengine/ui/page/control_center → frontengine-1.0.75/frontengine/ui/nav}/__init__.py +0 -0
  117. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/nav/sidebar.py +0 -0
  118. {frontengine-1.0.73/frontengine/ui/page/focus → frontengine-1.0.75/frontengine/ui/page}/__init__.py +0 -0
  119. {frontengine-1.0.73/frontengine/ui/page/gif → frontengine-1.0.75/frontengine/ui/page/control_center}/__init__.py +0 -0
  120. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/control_center/control_center_ui.py +0 -0
  121. {frontengine-1.0.73/frontengine/ui/page/image → frontengine-1.0.75/frontengine/ui/page/focus}/__init__.py +0 -0
  122. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/focus/focus_setting_ui.py +0 -0
  123. {frontengine-1.0.73/frontengine/ui/page/particle → frontengine-1.0.75/frontengine/ui/page/gif}/__init__.py +0 -0
  124. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
  125. {frontengine-1.0.73/frontengine/ui/page/pet → frontengine-1.0.75/frontengine/ui/page/image}/__init__.py +0 -0
  126. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/layout_kit.py +0 -0
  127. {frontengine-1.0.73/frontengine/ui/page/presentation → frontengine-1.0.75/frontengine/ui/page/particle}/__init__.py +0 -0
  128. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
  129. {frontengine-1.0.73/frontengine/ui/page/scene_setting → frontengine-1.0.75/frontengine/ui/page/pet}/__init__.py +0 -0
  130. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/pet/pet_setting_ui.py +0 -0
  131. {frontengine-1.0.73/frontengine/ui/page/scene_setting/scene_page → frontengine-1.0.75/frontengine/ui/page/presentation}/__init__.py +0 -0
  132. {frontengine-1.0.73/frontengine/ui/page/screen_care → frontengine-1.0.75/frontengine/ui/page/scene_setting}/__init__.py +0 -0
  133. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
  134. {frontengine-1.0.73/frontengine/ui/page/sound_player → frontengine-1.0.75/frontengine/ui/page/scene_setting/scene_page}/__init__.py +0 -0
  135. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
  136. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
  137. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
  138. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
  139. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
  140. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
  141. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
  142. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
  143. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
  144. {frontengine-1.0.73/frontengine/ui/page/text → frontengine-1.0.75/frontengine/ui/page/screen_care}/__init__.py +0 -0
  145. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/screen_care/screen_care_setting_ui.py +0 -0
  146. {frontengine-1.0.73/frontengine/ui/page/tools → frontengine-1.0.75/frontengine/ui/page/sound_player}/__init__.py +0 -0
  147. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
  148. {frontengine-1.0.73/frontengine/ui/page/video → frontengine-1.0.75/frontengine/ui/page/text}/__init__.py +0 -0
  149. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/text/text_setting_ui.py +0 -0
  150. {frontengine-1.0.73/frontengine/ui/page/wallpaper → frontengine-1.0.75/frontengine/ui/page/tools}/__init__.py +0 -0
  151. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/tools/tools_setting_ui.py +0 -0
  152. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/utils.py +0 -0
  153. {frontengine-1.0.73/frontengine/ui/page/web → frontengine-1.0.75/frontengine/ui/page/video}/__init__.py +0 -0
  154. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/video/video_setting_ui.py +0 -0
  155. {frontengine-1.0.73/frontengine/ui/page/widgets → frontengine-1.0.75/frontengine/ui/page/wallpaper}/__init__.py +0 -0
  156. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/wallpaper/wallpaper_setting_ui.py +0 -0
  157. {frontengine-1.0.73/frontengine/ui/style → frontengine-1.0.75/frontengine/ui/page/web}/__init__.py +0 -0
  158. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/web/web_setting_ui.py +0 -0
  159. {frontengine-1.0.73/frontengine/user_setting → frontengine-1.0.75/frontengine/ui/page/widgets}/__init__.py +0 -0
  160. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/page/widgets/widgets_setting_ui.py +0 -0
  161. {frontengine-1.0.73/frontengine/utils → frontengine-1.0.75/frontengine/ui/style}/__init__.py +0 -0
  162. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/ui/style/app_style.py +0 -0
  163. {frontengine-1.0.73/frontengine/utils/app_profile → frontengine-1.0.75/frontengine/user_setting}/__init__.py +0 -0
  164. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/user_setting/preset_repository.py +0 -0
  165. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/user_setting/scene_setting.py +0 -0
  166. {frontengine-1.0.73/frontengine/utils/audio_meter → frontengine-1.0.75/frontengine/utils}/__init__.py +0 -0
  167. {frontengine-1.0.73/frontengine/utils/autostart → frontengine-1.0.75/frontengine/utils/app_profile}/__init__.py +0 -0
  168. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/app_profile/app_profile_service.py +0 -0
  169. {frontengine-1.0.73/frontengine/utils/break_reminder → frontengine-1.0.75/frontengine/utils/audio_meter}/__init__.py +0 -0
  170. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/audio_meter/audio_envelope.py +0 -0
  171. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/audio_meter/loopback_capture.py +0 -0
  172. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/audio_meter/microphone_meter.py +0 -0
  173. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/audio_meter/screen_audio.py +0 -0
  174. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/audio_meter/spectrum_analyzer.py +0 -0
  175. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/audio_meter/system_audio_meter.py +0 -0
  176. {frontengine-1.0.73/frontengine/utils/browser → frontengine-1.0.75/frontengine/utils/autostart}/__init__.py +0 -0
  177. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/autostart/autostart_service.py +0 -0
  178. {frontengine-1.0.73/frontengine/utils/clipboard → frontengine-1.0.75/frontengine/utils/break_reminder}/__init__.py +0 -0
  179. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/break_reminder/break_reminder.py +0 -0
  180. {frontengine-1.0.73/frontengine/utils/color_vision → frontengine-1.0.75/frontengine/utils/browser}/__init__.py +0 -0
  181. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/browser/browser.py +0 -0
  182. {frontengine-1.0.73/frontengine/utils/critical_exit → frontengine-1.0.75/frontengine/utils/clipboard}/__init__.py +0 -0
  183. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/clipboard/clipboard_history.py +0 -0
  184. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/clipboard/clipboard_watcher.py +0 -0
  185. {frontengine-1.0.73/frontengine/utils/focus_shield → frontengine-1.0.75/frontengine/utils/color_vision}/__init__.py +0 -0
  186. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/color_vision/color_vision.py +0 -0
  187. {frontengine-1.0.73/frontengine/utils/focus_timer → frontengine-1.0.75/frontengine/utils/critical_exit}/__init__.py +0 -0
  188. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
  189. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/critical_exit/critical_exit.py +0 -0
  190. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/critical_exit/win32_vk.py +0 -0
  191. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/exception/__init__.py +0 -0
  192. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/exception/exception_tags.py +0 -0
  193. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/exception/exceptions.py +0 -0
  194. {frontengine-1.0.73/frontengine/utils/hotkey → frontengine-1.0.75/frontengine/utils/focus_shield}/__init__.py +0 -0
  195. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/focus_shield/focus_shield.py +0 -0
  196. {frontengine-1.0.73/frontengine/utils/input_watch → frontengine-1.0.75/frontengine/utils/focus_timer}/__init__.py +0 -0
  197. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/focus_timer/focus_timer.py +0 -0
  198. {frontengine-1.0.73/frontengine/utils/json → frontengine-1.0.75/frontengine/utils/hotkey}/__init__.py +0 -0
  199. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/hotkey/hotkey_service.py +0 -0
  200. {frontengine-1.0.73/frontengine/utils/keep_awake → frontengine-1.0.75/frontengine/utils/input_watch}/__init__.py +0 -0
  201. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/input_watch/input_watch_service.py +0 -0
  202. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/input_watch/typing_watch.py +0 -0
  203. {frontengine-1.0.73/frontengine/utils/logging → frontengine-1.0.75/frontengine/utils/json}/__init__.py +0 -0
  204. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/json/json_file.py +0 -0
  205. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/json/json_repository.py +0 -0
  206. {frontengine-1.0.73/frontengine/utils/measure → frontengine-1.0.75/frontengine/utils/keep_awake}/__init__.py +0 -0
  207. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/keep_awake/keep_awake.py +0 -0
  208. {frontengine-1.0.73/frontengine/utils/midi → frontengine-1.0.75/frontengine/utils/logging}/__init__.py +0 -0
  209. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/logging/loggin_instance.py +0 -0
  210. {frontengine-1.0.73/frontengine/utils/multi_language → frontengine-1.0.75/frontengine/utils/measure}/__init__.py +0 -0
  211. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/measure/measure.py +0 -0
  212. {frontengine-1.0.73/frontengine/utils/now_playing → frontengine-1.0.75/frontengine/utils/midi}/__init__.py +0 -0
  213. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/midi/midi_input.py +0 -0
  214. {frontengine-1.0.73/frontengine/utils/pet_chat → frontengine-1.0.75/frontengine/utils/multi_language}/__init__.py +0 -0
  215. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/multi_language/language_wrapper.py +0 -0
  216. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/multi_language/retranslate.py +0 -0
  217. {frontengine-1.0.73/frontengine/utils/platform_info → frontengine-1.0.75/frontengine/utils/now_playing}/__init__.py +0 -0
  218. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/now_playing/now_playing.py +0 -0
  219. {frontengine-1.0.73/frontengine/utils/playlist → frontengine-1.0.75/frontengine/utils/pet_chat}/__init__.py +0 -0
  220. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/pet_chat/pet_chat_service.py +0 -0
  221. {frontengine-1.0.73/frontengine/utils/plugins → frontengine-1.0.75/frontengine/utils/platform_info}/__init__.py +0 -0
  222. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/platform_info/platform_info.py +0 -0
  223. {frontengine-1.0.73/frontengine/utils/power_mode → frontengine-1.0.75/frontengine/utils/playlist}/__init__.py +0 -0
  224. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/playlist/playlist.py +0 -0
  225. {frontengine-1.0.73/frontengine/utils/preset_schedule → frontengine-1.0.75/frontengine/utils/plugins}/__init__.py +0 -0
  226. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/plugins/plugin_loader.py +0 -0
  227. {frontengine-1.0.73/frontengine/utils/recording → frontengine-1.0.75/frontengine/utils/power_mode}/__init__.py +0 -0
  228. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/power_mode/power_mode.py +0 -0
  229. {frontengine-1.0.73/frontengine/utils/redirect_manager → frontengine-1.0.75/frontengine/utils/preset_schedule}/__init__.py +0 -0
  230. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
  231. {frontengine-1.0.73/frontengine/utils/reminder → frontengine-1.0.75/frontengine/utils/recording}/__init__.py +0 -0
  232. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/recording/frame_recorder.py +0 -0
  233. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/recording/gif_writer.py +0 -0
  234. {frontengine-1.0.73/frontengine/utils/remote → frontengine-1.0.75/frontengine/utils/redirect_manager}/__init__.py +0 -0
  235. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
  236. {frontengine-1.0.73/frontengine/utils/screen_privacy → frontengine-1.0.75/frontengine/utils/reminder}/__init__.py +0 -0
  237. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/reminder/reminder_service.py +0 -0
  238. {frontengine-1.0.73/frontengine/utils/screen_text → frontengine-1.0.75/frontengine/utils/remote}/__init__.py +0 -0
  239. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/remote/remote_server.py +0 -0
  240. {frontengine-1.0.73/frontengine/utils/screensaver → frontengine-1.0.75/frontengine/utils/screen_privacy}/__init__.py +0 -0
  241. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/screen_privacy/capture_affinity.py +0 -0
  242. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/screen_privacy/share_watch.py +0 -0
  243. {frontengine-1.0.73/frontengine/utils/signage → frontengine-1.0.75/frontengine/utils/screen_text}/__init__.py +0 -0
  244. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/screen_text/screen_text_service.py +0 -0
  245. {frontengine-1.0.73/frontengine/utils/smart_pause → frontengine-1.0.75/frontengine/utils/screensaver}/__init__.py +0 -0
  246. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/screensaver/screensaver_service.py +0 -0
  247. {frontengine-1.0.73/frontengine/utils/steam → frontengine-1.0.75/frontengine/utils/signage}/__init__.py +0 -0
  248. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/signage/signage_service.py +0 -0
  249. {frontengine-1.0.73/frontengine/utils/system_stats → frontengine-1.0.75/frontengine/utils/smart_pause}/__init__.py +0 -0
  250. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/smart_pause/pause_rules.py +0 -0
  251. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
  252. {frontengine-1.0.73/frontengine/utils/text_source → frontengine-1.0.75/frontengine/utils/steam}/__init__.py +0 -0
  253. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/steam/steam_language.py +0 -0
  254. {frontengine-1.0.73/frontengine/utils/theme_schedule → frontengine-1.0.75/frontengine/utils/system_stats}/__init__.py +0 -0
  255. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/system_stats/system_stats.py +0 -0
  256. {frontengine-1.0.73/frontengine/utils/usage_tracking → frontengine-1.0.75/frontengine/utils/text_source}/__init__.py +0 -0
  257. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/text_source/text_source.py +0 -0
  258. {frontengine-1.0.73/frontengine/utils/virtual_camera → frontengine-1.0.75/frontengine/utils/theme_schedule}/__init__.py +0 -0
  259. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
  260. {frontengine-1.0.73/frontengine/utils/weather → frontengine-1.0.75/frontengine/utils/usage_tracking}/__init__.py +0 -0
  261. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/usage_tracking/usage_service.py +0 -0
  262. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/usage_tracking/usage_tracker.py +0 -0
  263. {frontengine-1.0.73/frontengine/utils/window_pin → frontengine-1.0.75/frontengine/utils/virtual_camera}/__init__.py +0 -0
  264. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/virtual_camera/camera_feed.py +0 -0
  265. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/virtual_camera/virtual_camera.py +0 -0
  266. {frontengine-1.0.73/frontengine/utils/window_replica → frontengine-1.0.75/frontengine/utils/weather}/__init__.py +0 -0
  267. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/weather/weather_service.py +0 -0
  268. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/web_url.py +0 -0
  269. {frontengine-1.0.73/frontengine/utils/workshop → frontengine-1.0.75/frontengine/utils/window_pin}/__init__.py +0 -0
  270. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/window_pin/window_layout.py +0 -0
  271. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/window_pin/window_pin.py +0 -0
  272. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/window_replica/dwm_thumbnail.py +0 -0
  273. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine/utils/workshop/workshop_content.py +0 -0
  274. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine.egg-info/dependency_links.txt +0 -0
  275. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine.egg-info/entry_points.txt +0 -0
  276. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine.egg-info/requires.txt +0 -0
  277. {frontengine-1.0.73 → frontengine-1.0.75}/frontengine.egg-info/top_level.txt +0 -0
  278. {frontengine-1.0.73 → frontengine-1.0.75}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.73
3
+ Version: 1.0.75
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
@@ -0,0 +1,93 @@
1
+ """
2
+ 凍結畫面:把某個螢幕現在的樣子拍下來,鋪滿那個螢幕蓋在最上層。
3
+
4
+ 用途是講解的節奏控制——切去別的地方操作、開別的檔案、把東西準備好,而投影出去
5
+ 或被分享的那個畫面停在原地。
6
+
7
+ **一定要能在看不見主視窗的情況下解除。** 凍結之後畫面上就只剩那張靜止圖,
8
+ FrontEngine 的視窗在它後面,按鈕點不到。所以解除的出口有三個:Escape、雙擊、
9
+ 以及全域快速鍵;三個都不通的話,使用者只剩工作管理員。
10
+
11
+ Freeze the screen: photograph a display as it is now and cover that display with
12
+ the picture.
13
+
14
+ It is for pacing an explanation - stepping away to open something, getting the
15
+ next thing ready - while what is projected or shared stays where it was.
16
+
17
+ **Unfreezing must work without seeing the main window.** Once frozen, the still
18
+ image is all there is; FrontEngine's own window is behind it and its buttons
19
+ cannot be clicked. So there are three ways out - Escape, a double-click, and the
20
+ global shortcut - because with none of them the user is left with the task
21
+ manager.
22
+ """
23
+ from __future__ import annotations
24
+
25
+ from typing import Optional
26
+
27
+ from PySide6.QtCore import Qt
28
+ from PySide6.QtGui import QPainter, QPixmap, QScreen
29
+ from PySide6.QtWidgets import QWidget
30
+
31
+ from frontengine.utils.logging.loggin_instance import front_engine_logger
32
+
33
+
34
+ def capture_screen(screen: Optional[QScreen]) -> QPixmap:
35
+ """
36
+ 把整個螢幕拍成一張圖。拍不到就回傳空的 QPixmap,呼叫端負責不要顯示它。
37
+ Photograph a whole screen. An unavailable screen gives a null pixmap and the
38
+ caller is responsible for not showing it.
39
+ """
40
+ if screen is None:
41
+ return QPixmap()
42
+ try:
43
+ geometry = screen.geometry()
44
+ return screen.grabWindow(0, 0, 0, geometry.width(), geometry.height())
45
+ except Exception as error: # pragma: no cover - platform boundary
46
+ front_engine_logger.warning(f"[Freeze] capture failed: {error!r}")
47
+ return QPixmap()
48
+
49
+
50
+ class FreezeWidget(QWidget):
51
+ """一張靜止的螢幕畫面,鋪滿目標螢幕。"""
52
+
53
+ def __init__(self, pixmap: QPixmap, parent: Optional[QWidget] = None) -> None:
54
+ super().__init__(parent)
55
+ self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
56
+ # 不用 Tool:Tool 視窗在部分平台不吃鍵盤焦點,那樣 Escape 就按不掉了。
57
+ # Not a Tool window: on some platforms those do not take keyboard focus,
58
+ # which is exactly how Escape would stop working.
59
+ self.setWindowFlags(
60
+ Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
61
+ self.setWindowTitle("FrontEngine")
62
+ self.pixmap = pixmap if pixmap is not None else QPixmap()
63
+ front_engine_logger.info(
64
+ f"[FreezeWidget] Init | size=({self.pixmap.width()}, {self.pixmap.height()})")
65
+
66
+ def show_on(self, screen: Optional[QScreen]) -> None:
67
+ """在指定螢幕上鋪滿顯示,並取得鍵盤焦點好讓 Escape 有效。"""
68
+ if screen is not None:
69
+ self.setScreen(screen)
70
+ self.setGeometry(screen.geometry())
71
+ self.showFullScreen()
72
+ self.raise_()
73
+ self.activateWindow()
74
+ self.setFocus(Qt.FocusReason.OtherFocusReason)
75
+
76
+ def paintEvent(self, event) -> None:
77
+ if self.pixmap.isNull():
78
+ return
79
+ painter = QPainter(self)
80
+ painter.drawPixmap(self.rect(), self.pixmap)
81
+
82
+ def mouseDoubleClickEvent(self, event) -> None:
83
+ self.close()
84
+ event.accept()
85
+
86
+ def keyPressEvent(self, event) -> None:
87
+ # 任何鍵都解除,不只是 Escape。畫面被一張靜止圖蓋住的時候,使用者最可能做的
88
+ # 就是「隨便按一個鍵看看」,那時候應該要有反應。
89
+ # Any key unfreezes, not only Escape. Faced with a screen that has stopped
90
+ # responding, pressing something at random is the first thing anyone tries,
91
+ # and it should work.
92
+ self.close()
93
+ event.accept()
@@ -0,0 +1,155 @@
1
+ """
2
+ 參考圖板:一塊畫布上放好幾張圖,各自可以搬動,整塊可以縮放平移。
3
+
4
+ 和「圖片覆蓋層」的差別是數量與擺法:覆蓋層是把一張圖固定在某個位置當背景,圖板
5
+ 是把一疊參考資料攤開來排在手邊——畫圖的、做設計的、對著規格寫程式的都在做這件事。
6
+
7
+ 視圖行為(無邊框、置頂、透明、滾輪縮放、拖曳平移)沿用場景功能的
8
+ `ExtendGraphicView`,這裡只負責「放什麼進去、一開始怎麼排」。
9
+
10
+ A reference board: several images on one canvas, each movable, the whole thing
11
+ zoomable and pannable.
12
+
13
+ It differs from the image overlay in number and arrangement: the overlay fixes one
14
+ picture in place as a backdrop, while a board spreads a pile of references out
15
+ within reach - what illustrators, designers and anyone coding against a
16
+ specification actually do.
17
+
18
+ The view behaviour - frameless, on top, transparent, wheel zoom, drag to pan -
19
+ comes from the scene feature's `ExtendGraphicView`; this only decides what goes on
20
+ it and how it is laid out to begin with.
21
+ """
22
+ from __future__ import annotations
23
+
24
+ from pathlib import Path
25
+ from typing import List, Sequence, Tuple
26
+
27
+ from PySide6.QtCore import Qt
28
+ from PySide6.QtGui import QPixmap
29
+ from PySide6.QtWidgets import QGraphicsPixmapItem, QGraphicsScene
30
+
31
+ from frontengine.show.scene.extend_graphic_view import ExtendGraphicView
32
+ from frontengine.utils.logging.loggin_instance import front_engine_logger
33
+
34
+ BOARD_EXTENSIONS = (".png", ".jpg", ".jpeg", ".webp", ".bmp", ".gif")
35
+ DEFAULT_COLUMNS = 3
36
+ DEFAULT_ITEM_SIZE = 320
37
+ ITEM_GAP = 24
38
+
39
+
40
+ def columns_for(count: int, preferred: int = DEFAULT_COLUMNS) -> int:
41
+ """
42
+ 幾張圖排幾欄。張數比預設欄數少時就照張數排,免得三張圖被排成一欄兩列、
43
+ 右邊空一大塊。
44
+ How many columns for this many images. Fewer images than the preferred column
45
+ count simply use their own number, so three pictures are not laid out as a
46
+ row of two with a gap beside them.
47
+ """
48
+ count = max(0, int(count))
49
+ if count == 0:
50
+ return 0
51
+ return max(1, min(int(preferred), count))
52
+
53
+
54
+ def grid_positions(count: int, item_size: int = DEFAULT_ITEM_SIZE,
55
+ columns: int = DEFAULT_COLUMNS,
56
+ gap: int = ITEM_GAP) -> List[Tuple[int, int]]:
57
+ """
58
+ 一開始把圖排成網格的座標。純算術,所以排版不必開視窗就能驗。
59
+
60
+ 先排好再讓使用者自己搬:全部疊在原點的話,開起來看到的是一張圖,其他幾張都
61
+ 藏在下面,使用者會以為只載入了一張。
62
+ The initial grid coordinates. Pure arithmetic, so the layout can be checked
63
+ without a window.
64
+
65
+ They are arranged before the user rearranges them: stacked at the origin, the
66
+ board would open showing one picture with the rest hidden underneath, and it
67
+ would look as though only one had loaded.
68
+ """
69
+ count = max(0, int(count))
70
+ if count == 0:
71
+ return []
72
+ column_count = columns_for(count, columns)
73
+ step = max(1, int(item_size)) + max(0, int(gap))
74
+ return [((index % column_count) * step, (index // column_count) * step)
75
+ for index in range(count)]
76
+
77
+
78
+ def readable_images(paths: Sequence[str]) -> List[str]:
79
+ """
80
+ 留下副檔名認得、而且真的讀得進來的圖。
81
+
82
+ 壞掉或不是圖片的檔案要在這裡就擋下來:讓 QPixmap 靜靜產生一張空圖的話,圖板
83
+ 上會出現一塊看不見的空白,使用者只會覺得「有一張圖不見了」。
84
+ Keep the files whose suffix is known and that actually load.
85
+
86
+ A broken or non-image file is dropped here: letting QPixmap quietly produce a
87
+ null pixmap puts an invisible blank on the board, and all the user sees is
88
+ that one of their pictures is missing.
89
+ """
90
+ kept = []
91
+ for path in paths or ():
92
+ try:
93
+ candidate = Path(str(path))
94
+ if candidate.suffix.lower() not in BOARD_EXTENSIONS:
95
+ continue
96
+ if not candidate.is_file():
97
+ continue
98
+ except OSError: # pragma: no cover - filesystem boundary
99
+ continue
100
+ if QPixmap(str(candidate)).isNull():
101
+ front_engine_logger.info(f"[ReferenceBoard] skipped unreadable image: {candidate}")
102
+ continue
103
+ kept.append(str(candidate))
104
+ return kept
105
+
106
+
107
+ class ReferenceBoardWidget(ExtendGraphicView):
108
+ """好幾張參考圖放在同一塊畫布上,各自可以搬動。"""
109
+
110
+ def __init__(self, item_size: int = DEFAULT_ITEM_SIZE, columns: int = DEFAULT_COLUMNS):
111
+ front_engine_logger.info("[ReferenceBoardWidget] Init")
112
+ self.board_scene = QGraphicsScene()
113
+ super().__init__(self.board_scene)
114
+ self.item_size = max(64, int(item_size))
115
+ self.columns = max(1, int(columns))
116
+ self.items: List[QGraphicsPixmapItem] = []
117
+
118
+ def add_images(self, paths: Sequence[str]) -> int:
119
+ """把圖加進圖板並排好,回傳實際加進去的張數。"""
120
+ usable = readable_images(paths)
121
+ positions = grid_positions(len(usable), self.item_size, self.columns)
122
+ for path, (x, y) in zip(usable, positions):
123
+ pixmap = QPixmap(path).scaled(
124
+ self.item_size, self.item_size,
125
+ Qt.AspectRatioMode.KeepAspectRatio,
126
+ Qt.TransformationMode.SmoothTransformation)
127
+ item = QGraphicsPixmapItem(pixmap)
128
+ # 每張圖各自可以搬:圖板的用途就是把它們排成自己看得順的位置。
129
+ # Each picture moves on its own: arranging them is the whole point.
130
+ item.setFlag(QGraphicsPixmapItem.GraphicsItemFlag.ItemIsMovable, True)
131
+ item.setFlag(QGraphicsPixmapItem.GraphicsItemFlag.ItemIsSelectable, True)
132
+ item.setPos(x, y)
133
+ self.board_scene.addItem(item)
134
+ self.items.append(item)
135
+ front_engine_logger.info(f"[ReferenceBoardWidget] added {len(usable)} of {len(paths or ())}")
136
+ return len(usable)
137
+
138
+ def remove_selected(self) -> int:
139
+ """把選起來的圖從圖板上拿掉,回傳拿掉幾張。"""
140
+ removed = 0
141
+ for item in list(self.items):
142
+ if item.isSelected():
143
+ self.board_scene.removeItem(item)
144
+ self.items.remove(item)
145
+ removed += 1
146
+ return removed
147
+
148
+ def keyPressEvent(self, event) -> None:
149
+ if event.key() == Qt.Key.Key_Escape:
150
+ self.close()
151
+ return
152
+ if event.key() in (Qt.Key.Key_Delete, Qt.Key.Key_Backspace):
153
+ self.remove_selected()
154
+ return
155
+ super().keyPressEvent(event)
@@ -33,6 +33,7 @@ _ACTION_LABELS: Dict[str, Tuple[str, str]] = {
33
33
  "dashboard_next": ("web_dashboard_next", "Next page"),
34
34
  "toggle_lock": ("hotkey_toggle_lock", "Lock / unlock overlays"),
35
35
  "show_shortcuts": ("hotkey_show_shortcuts", "Show this shortcut list"),
36
+ "toggle_freeze": ("hotkey_toggle_freeze", "Freeze / unfreeze the screen"),
36
37
  }
37
38
 
38
39
 
@@ -402,6 +402,10 @@ class FrontEngineMainUI(QMainWindow):
402
402
  "pinned_widget_list"):
403
403
  self.control_center_ui.register_overlay_source(
404
404
  lambda attribute=attribute: getattr(self.tools_setting_ui, attribute, []))
405
+ # 參考圖板也要進控制中心,否則「全部關閉」關不掉它
406
+ # The reference boards belong here too, or "close all" cannot reach them
407
+ self.control_center_ui.register_overlay_source(
408
+ lambda: getattr(self.image_setting_ui, "board_widget_list", []))
405
409
 
406
410
  # 螢幕保護能顯示哪些分頁:來源名稱 -> (頁面屬性, 啟動方法, 覆蓋層清單屬性)
407
411
  # What the screensaver can show: source -> (page attribute, start method,
@@ -694,6 +698,13 @@ class FrontEngineMainUI(QMainWindow):
694
698
  self.control_center_ui.toggle_lock_all()
695
699
  elif action == "show_shortcuts":
696
700
  self.toggle_shortcut_sheet()
701
+ elif action == "toggle_freeze":
702
+ # 畫面被凍結時,主視窗就在那張靜止圖後面,按鈕點不到——所以這個
703
+ # 快速鍵是唯一保證按得到的解除方式。
704
+ # While frozen the main window is behind the still image and its
705
+ # buttons cannot be reached; this shortcut is the way out that is
706
+ # always available.
707
+ self.presentation_setting_ui.toggle_freeze()
697
708
 
698
709
  def toggle_shortcut_sheet(self) -> None:
699
710
  """
@@ -6,6 +6,7 @@ from PySide6.QtWidgets import (
6
6
  )
7
7
 
8
8
  from frontengine.show.image.paint_image import ImageWidget
9
+ from frontengine.show.reference.reference_board import ReferenceBoardWidget
9
10
  from frontengine.ui.dialog.choose_file_dialog import choose_image
10
11
  from frontengine.ui.page.layout_kit import SettingPage
11
12
  from frontengine.ui.page.utils import (
@@ -97,6 +98,21 @@ class ImageSettingUI(SettingPage):
97
98
  self.slideshow_interval_combobox.addItems(["3", "5", "10", "15", "30", "60"])
98
99
  self.slideshow_interval_combobox.setCurrentText("5")
99
100
  self.slideshow_shuffle_checkbox = tr(QCheckBox(), "slideshow_shuffle", "Shuffle")
101
+ # 參考圖板:好幾張圖攤在同一塊畫布上,各自可以搬動
102
+ # Reference board: several pictures on one canvas, each movable
103
+ self.board_widget_list: list = []
104
+ self.board_choose_button = tr(QPushButton(), "image_board_choose",
105
+ "Open reference board...")
106
+ self.board_choose_button.clicked.connect(self.open_reference_board)
107
+ self.board_close_button = tr(QPushButton(), "image_board_close", "Close boards")
108
+ self.board_close_button.clicked.connect(self.close_reference_boards)
109
+ self.board_hint_label = tr(
110
+ QLabel(), "image_board_hint",
111
+ "Pick several pictures at once. Drag each one to arrange it, drag the "
112
+ "background to pan, scroll to zoom, Delete removes the selected one and "
113
+ "Escape closes the board.")
114
+ self.board_hint_label.setWordWrap(True)
115
+
100
116
  self.slideshow_recursive_checkbox = tr(QCheckBox(), "slideshow_recursive",
101
117
  "Include subfolders")
102
118
 
@@ -117,6 +133,10 @@ class ImageSettingUI(SettingPage):
117
133
  slideshow.add_row(self.slideshow_interval_label, self.slideshow_interval_combobox)
118
134
  slideshow.add_inline(self.slideshow_shuffle_checkbox, self.slideshow_recursive_checkbox)
119
135
 
136
+ board = self.add_section("image_board_label", "Reference board")
137
+ board.add_inline(self.board_choose_button, self.board_close_button)
138
+ board.add_widget(self.board_hint_label)
139
+
120
140
  where = self.add_section("section_where", "Where")
121
141
  where.add_row(self.target_monitor_label, self.target_monitor_combobox)
122
142
  where.add_inline(self.show_on_all_screen_checkbox, self.show_on_bottom_checkbox,
@@ -125,6 +145,38 @@ class ImageSettingUI(SettingPage):
125
145
  self.finish_body()
126
146
  self.set_footer(primary=self.start_button, status=self.ready_label)
127
147
 
148
+ def open_reference_board(self):
149
+ """
150
+ 挑幾張圖開一塊參考圖板。一張都沒挑就不要開空白畫布——那看起來像壞掉。
151
+ Open a board from several chosen pictures. Nothing chosen opens nothing:
152
+ an empty canvas reads as a fault.
153
+ """
154
+ paths, _ = QFileDialog.getOpenFileNames(
155
+ self,
156
+ language_wrapper.language_word_dict.get("image_board_choose", "Open reference board..."),
157
+ "",
158
+ "Images (*.png *.jpg *.jpeg *.webp *.bmp *.gif)")
159
+ if not paths:
160
+ return None
161
+ board = ReferenceBoardWidget()
162
+ if board.add_images(paths) == 0:
163
+ # 全部讀不進來就不要留一塊空畫布在畫面上。
164
+ # With nothing readable, do not leave an empty canvas on screen.
165
+ board.close()
166
+ return None
167
+ board.showMaximized()
168
+ self.board_widget_list.append(board)
169
+ return board
170
+
171
+ def close_reference_boards(self) -> None:
172
+ """關掉開過的參考圖板。"""
173
+ for board in list(self.board_widget_list):
174
+ try:
175
+ board.close()
176
+ except RuntimeError: # pragma: no cover - 底層物件已消失
177
+ pass
178
+ self.board_widget_list.clear()
179
+
128
180
  def set_show_all_screen(self) -> None:
129
181
  front_engine_logger.info("[ImageSettingUI] set_show_all_screen")
130
182
  self.show_all_screen = self.show_on_all_screen_checkbox.isChecked()
@@ -22,6 +22,7 @@ from frontengine.show.presentation.annotation_overlay import (
22
22
  from frontengine.show.presentation.cursor_effects import CursorEffectWidget
23
23
  from frontengine.show.presentation.keystroke_display import KeystrokeDisplayWidget
24
24
  from frontengine.show.presentation.magnifier import MagnifierWidget
25
+ from frontengine.show.freeze.freeze_widget import FreezeWidget, capture_screen
25
26
  from frontengine.ui.page.utils import build_target_monitor_combobox, coerce_int, resolve_preferred_monitor
26
27
  from frontengine.utils.input_watch.input_watch_service import InputWatchService
27
28
  from frontengine.ui.page.layout_kit import SettingPage
@@ -106,6 +107,14 @@ class PresentationSettingUI(SettingPage):
106
107
  self.whiteboard_save_button.clicked.connect(self.save_whiteboard)
107
108
  self.target_monitor_label = tr(QLabel(), "target_monitor_label", "Target monitor")
108
109
  self.target_monitor_combobox = build_target_monitor_combobox()
110
+
111
+ # 凍結畫面:把目標螢幕現在的樣子拍下來蓋上去,講解時可以先停住畫面
112
+ # Freeze: cover the target screen with a photograph of itself, so an
113
+ # explanation can be paced without the audience watching you work.
114
+ self.freeze_widget_list: list = []
115
+ self.freeze_label = tr(QLabel(), "presentation_freeze_label", "Freeze screen")
116
+ self.freeze_button = tr(QPushButton(), "presentation_freeze_start", "Freeze")
117
+ self.freeze_button.clicked.connect(self.toggle_freeze)
109
118
  self.hint_label = tr(QLabel(), "presentation_hint",
110
119
  "Drawing takes the mouse while it is on; the other overlays pass clicks through.")
111
120
  self.hint_label.setWordWrap(True)
@@ -137,6 +146,9 @@ class PresentationSettingUI(SettingPage):
137
146
  whiteboard.add_inline(self.whiteboard_button, self.whiteboard_save_button)
138
147
 
139
148
  where = self.add_section("section_where", "Where")
149
+ freeze = self.add_section(self.freeze_label)
150
+ freeze.add_inline(self.freeze_button)
151
+
140
152
  where.add_row(self.target_monitor_label, self.target_monitor_combobox)
141
153
 
142
154
  self.add_body_widget(self.hint_label)
@@ -340,6 +352,68 @@ class PresentationSettingUI(SettingPage):
340
352
  else:
341
353
  self.start_whiteboard()
342
354
 
355
+ def toggle_freeze(self):
356
+ """
357
+ 凍結/解除目標螢幕。已經凍結就解除,所以同一顆按鈕(和同一個快速鍵)
358
+ 兩種方向都走得通。
359
+ Freeze or unfreeze the target screen. Frozen already means unfreeze, so
360
+ the same button - and the same shortcut - works both ways.
361
+ """
362
+ if self.freeze_widget_list:
363
+ self.unfreeze()
364
+ return None
365
+
366
+ screens = QGuiApplication.screens()
367
+ index = resolve_preferred_monitor(self.target_monitor_combobox)
368
+ screen = screens[index] if index is not None and 0 <= index < len(screens) else QGuiApplication.primaryScreen()
369
+
370
+ pixmap = capture_screen(screen)
371
+ if pixmap.isNull():
372
+ # 拍不到就不要蓋一塊空白上去:那會讓整個螢幕變成一片黑,而且看起來
373
+ # 像當機而不是「凍結失敗」。
374
+ # Without a picture, do not cover anything: a blank sheet turns the
375
+ # screen black and reads as a crash rather than a failed freeze.
376
+ front_engine_logger.info("[PresentationSettingUI] nothing captured, not freezing")
377
+ return None
378
+
379
+ widget = FreezeWidget(pixmap)
380
+ widget.destroyed.connect(lambda: self._forget_freeze(widget))
381
+ widget.show_on(screen)
382
+ self.freeze_widget_list.append(widget)
383
+ retranslator.set_text(self.freeze_button, "presentation_freeze_stop", "Unfreeze")
384
+ return widget
385
+
386
+ def unfreeze(self) -> None:
387
+ """解除凍結。"""
388
+ for widget in self.freeze_widget_list[:]:
389
+ try:
390
+ widget.close()
391
+ except RuntimeError: # pragma: no cover - 底層物件已消失
392
+ pass
393
+ self.freeze_widget_list.clear()
394
+ retranslator.set_text(self.freeze_button, "presentation_freeze_start", "Freeze")
395
+
396
+ def _forget_freeze(self, widget) -> None:
397
+ """
398
+ 使用者自己按 Escape 或雙擊關掉時也要回到「凍結」字樣,否則按鈕會一直
399
+ 寫著「解除凍結」,而畫面上根本沒有凍結的東西。
400
+ Coming back to "Freeze" when the user dismissed it themselves; otherwise
401
+ the button keeps offering to unfreeze something that is no longer there.
402
+ """
403
+ if widget in self.freeze_widget_list:
404
+ self.freeze_widget_list.remove(widget)
405
+ if self.freeze_widget_list:
406
+ return
407
+ try:
408
+ retranslator.set_text(self.freeze_button, "presentation_freeze_start", "Freeze")
409
+ except RuntimeError:
410
+ # destroyed 是在 C++ 物件消失之後才送到的,關閉程式時這一頁可能已經
411
+ # 先走了。那時候沒有按鈕可以改,也不需要改。
412
+ # destroyed arrives after the C++ object is gone, and on shutdown this
413
+ # page may already have followed it. There is no button left to
414
+ # relabel, and nothing that needs relabelling.
415
+ pass
416
+
343
417
  def start_whiteboard(self) -> None:
344
418
  """開一塊無限畫布(可平移縮放,畫過的東西留在畫布座標上)。"""
345
419
  front_engine_logger.info("[PresentationSettingUI] start_whiteboard")
@@ -18,6 +18,7 @@ default_hotkeys: Dict[str, str] = {
18
18
  "dashboard_next": "<ctrl>+<shift>+<right>",
19
19
  "toggle_lock": "<ctrl>+<shift>+l",
20
20
  "show_shortcuts": "<ctrl>+<shift>+<f8>",
21
+ "toggle_freeze": "<ctrl>+<shift>+<f7>",
21
22
  }
22
23
 
23
24
  user_setting_dict: Dict[str, Any] = {
@@ -31,6 +31,10 @@ english_word_dict = {
31
31
  "screen_care_band": "Band",
32
32
  "screen_care_strength": "Strength",
33
33
  "screen_care_type": "Type",
34
+ "presentation_freeze_label": "Freeze screen",
35
+ "presentation_freeze_start": "Freeze",
36
+ "presentation_freeze_stop": "Unfreeze",
37
+ "hotkey_toggle_freeze": "Freeze / unfreeze the screen",
34
38
  "presentation_tool": "Tool",
35
39
  "presentation_colour": "Colour",
36
40
  "presentation_width": "Width",
@@ -171,6 +175,10 @@ english_word_dict = {
171
175
  "web_setting_open_enable_input": "Enable input",
172
176
  # Scene UI
173
177
  "tab_scene_text": "Scene",
178
+ "image_board_label": "REFERENCE BOARD",
179
+ "image_board_choose": "Open reference board...",
180
+ "image_board_close": "Close boards",
181
+ "image_board_hint": "Pick several pictures at once. Drag each one to arrange it, drag the background to pan, scroll to zoom, Delete removes the selected one and Escape closes the board.",
174
182
  "scene_start": "Start scene",
175
183
  "scene_table_view_type": "Type",
176
184
  "scene_file_path": "File path",
@@ -32,6 +32,10 @@ french_word_dict = {
32
32
  "screen_care_band": "Largeur",
33
33
  "screen_care_strength": "Intensité",
34
34
  "screen_care_type": "Type",
35
+ "presentation_freeze_label": "Figer l'écran",
36
+ "presentation_freeze_start": "Figer",
37
+ "presentation_freeze_stop": "Libérer",
38
+ "hotkey_toggle_freeze": "Figer / libérer l'écran",
35
39
  "presentation_tool": "Outil",
36
40
  "presentation_colour": "Couleur",
37
41
  "presentation_width": "Épaisseur",
@@ -171,6 +175,10 @@ french_word_dict = {
171
175
  "web_setting_open_enable_input": "Activer l'entrée",
172
176
  # Scene UI
173
177
  "tab_scene_text": "Scène",
178
+ "image_board_label": "PLANCHE DE RÉFÉRENCE",
179
+ "image_board_choose": "Ouvrir une planche...",
180
+ "image_board_close": "Fermer les planches",
181
+ "image_board_hint": "Choisissez plusieurs images à la fois. Faites glisser chacune pour l'arranger, le fond pour vous déplacer, la molette pour zoomer ; Suppr retire l'image sélectionnée et Échap ferme la planche.",
174
182
  "scene_start": "Commencer la scène",
175
183
  "scene_table_view_type": "Type",
176
184
  "scene_file_path": "Chemin du fichier",
@@ -32,6 +32,10 @@ germany_word_dict = {
32
32
  "screen_care_band": "Breite",
33
33
  "screen_care_strength": "Stärke",
34
34
  "screen_care_type": "Typ",
35
+ "presentation_freeze_label": "Bild einfrieren",
36
+ "presentation_freeze_start": "Einfrieren",
37
+ "presentation_freeze_stop": "Auftauen",
38
+ "hotkey_toggle_freeze": "Bild einfrieren / auftauen",
35
39
  "presentation_tool": "Werkzeug",
36
40
  "presentation_colour": "Farbe",
37
41
  "presentation_width": "Breite",
@@ -171,6 +175,10 @@ germany_word_dict = {
171
175
  "web_setting_open_enable_input": "Eingabe aktivieren",
172
176
  # Szenen-UI
173
177
  "tab_scene_text": "Szene",
178
+ "image_board_label": "REFERENZTAFEL",
179
+ "image_board_choose": "Referenztafel öffnen...",
180
+ "image_board_close": "Tafeln schließen",
181
+ "image_board_hint": "Mehrere Bilder auf einmal wählen. Einzelne ziehen zum Anordnen, den Hintergrund ziehen zum Verschieben, Mausrad zum Zoomen, Entf entfernt das gewählte Bild, Escape schließt die Tafel.",
174
182
  "scene_start": "Szene starten",
175
183
  "scene_table_view_type": "Typ",
176
184
  "scene_file_path": "Dateipfad",
@@ -32,6 +32,10 @@ italian_word_dict = {
32
32
  "screen_care_band": "Larghezza",
33
33
  "screen_care_strength": "Intensità",
34
34
  "screen_care_type": "Tipo",
35
+ "presentation_freeze_label": "Congela lo schermo",
36
+ "presentation_freeze_start": "Congela",
37
+ "presentation_freeze_stop": "Scongela",
38
+ "hotkey_toggle_freeze": "Congela / scongela lo schermo",
35
39
  "presentation_tool": "Strumento",
36
40
  "presentation_colour": "Colore",
37
41
  "presentation_width": "Spessore",
@@ -171,6 +175,10 @@ italian_word_dict = {
171
175
  "web_setting_open_enable_input": "Abilita input",
172
176
  # Scene UI
173
177
  "tab_scene_text": "Scena",
178
+ "image_board_label": "TAVOLA DI RIFERIMENTO",
179
+ "image_board_choose": "Apri tavola di riferimento...",
180
+ "image_board_close": "Chiudi le tavole",
181
+ "image_board_hint": "Scegli più immagini insieme. Trascina ciascuna per disporla, trascina lo sfondo per spostarti, rotellina per lo zoom, Canc toglie quella selezionata ed Esc chiude la tavola.",
174
182
  "scene_start": "Inizia la scena",
175
183
  "scene_table_view_type": "Tipo",
176
184
  "scene_file_path": "Percorso del file",
@@ -32,6 +32,10 @@ russian_word_dict = {
32
32
  "screen_care_band": "Ширина",
33
33
  "screen_care_strength": "Сила",
34
34
  "screen_care_type": "Тип",
35
+ "presentation_freeze_label": "Заморозить экран",
36
+ "presentation_freeze_start": "Заморозить",
37
+ "presentation_freeze_stop": "Разморозить",
38
+ "hotkey_toggle_freeze": "Заморозить / разморозить экран",
35
39
  "presentation_tool": "Инструмент",
36
40
  "presentation_colour": "Цвет",
37
41
  "presentation_width": "Толщина",
@@ -171,6 +175,10 @@ russian_word_dict = {
171
175
  "web_setting_open_enable_input": "Включить ввод",
172
176
  # Scene UI
173
177
  "tab_scene_text": "Сцена",
178
+ "image_board_label": "ДОСКА РЕФЕРЕНСОВ",
179
+ "image_board_choose": "Открыть доску референсов...",
180
+ "image_board_close": "Закрыть доски",
181
+ "image_board_hint": "Выберите сразу несколько изображений. Перетаскивайте каждое, чтобы расставить, фон - чтобы сдвинуть вид, колесо - масштаб; Delete убирает выбранное, Escape закрывает доску.",
174
182
  "scene_start": "Начать сцену",
175
183
  "scene_table_view_type": "Тип",
176
184
  "scene_file_path": "Путь файла",
@@ -32,6 +32,10 @@ simplified_chinese_word_dict = {
32
32
  "screen_care_band": "宽度",
33
33
  "screen_care_strength": "强度",
34
34
  "screen_care_type": "类型",
35
+ "presentation_freeze_label": "冻结画面",
36
+ "presentation_freeze_start": "冻结",
37
+ "presentation_freeze_stop": "解除冻结",
38
+ "hotkey_toggle_freeze": "冻结/解除冻结画面",
35
39
  "presentation_tool": "工具",
36
40
  "presentation_colour": "颜色",
37
41
  "presentation_width": "粗细",
@@ -171,6 +175,10 @@ simplified_chinese_word_dict = {
171
175
  "web_setting_open_enable_input": "启用输入",
172
176
  # Scene UI
173
177
  "tab_scene_text": "场景",
178
+ "image_board_label": "参考图板",
179
+ "image_board_choose": "打开参考图板⋯",
180
+ "image_board_close": "关闭图板",
181
+ "image_board_hint": "一次挑多张图。拖动单张可以排位置,拖背景可以平移,滚轮缩放,Delete 移除选中的那张,Escape 关闭图板。",
174
182
  "scene_start": "开始场景",
175
183
  "scene_table_view_type": "类型",
176
184
  "scene_file_path": "文件路径",
@@ -32,6 +32,10 @@ traditional_chinese_word_dict = {
32
32
  "screen_care_band": "寬度",
33
33
  "screen_care_strength": "強度",
34
34
  "screen_care_type": "類型",
35
+ "presentation_freeze_label": "凍結畫面",
36
+ "presentation_freeze_start": "凍結",
37
+ "presentation_freeze_stop": "解除凍結",
38
+ "hotkey_toggle_freeze": "凍結/解除凍結畫面",
35
39
  "presentation_tool": "工具",
36
40
  "presentation_colour": "顏色",
37
41
  "presentation_width": "粗細",
@@ -171,6 +175,10 @@ traditional_chinese_word_dict = {
171
175
  "web_setting_open_enable_input": "啟用輸入",
172
176
  # Scene UI
173
177
  "tab_scene_text": "場景",
178
+ "image_board_label": "參考圖板",
179
+ "image_board_choose": "開啟參考圖板⋯",
180
+ "image_board_close": "關閉圖板",
181
+ "image_board_hint": "一次挑多張圖。拖曳單張可以排位置,拖背景可以平移,滾輪縮放,Delete 移除選取的那張,Escape 關閉圖板。",
174
182
  "scene_start": "開始場景",
175
183
  "scene_table_view_type": "類型",
176
184
  "scene_file_path": "檔案路徑",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.73
3
+ Version: 1.0.75
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