frontengine 1.0.38__tar.gz → 1.0.39__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {frontengine-1.0.38 → frontengine-1.0.39}/PKG-INFO +12 -1
- {frontengine-1.0.38 → frontengine-1.0.39}/README.md +11 -0
- frontengine-1.0.39/frontengine/ui/dialog/screen_text_dialog.py +120 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/tools/tools_setting_ui.py +206 -16
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/user_setting/user_setting_file.py +3 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/multi_language/english.py +19 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/multi_language/traditional_chinese.py +19 -0
- frontengine-1.0.39/frontengine/utils/recording/frame_recorder.py +199 -0
- frontengine-1.0.39/frontengine/utils/recording/gif_writer.py +203 -0
- frontengine-1.0.39/frontengine/worker/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine.egg-info/PKG-INFO +12 -1
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine.egg-info/SOURCES.txt +4 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/pyproject.toml +1 -1
- {frontengine-1.0.38 → frontengine-1.0.39}/LICENSE +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/__main__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/base_widget.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/camera/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/camera/camera_widget.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/capture/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/capture/region_capture.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/focus_shield/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/focus_shield/focus_shield_widget.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/gif/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/gif/paint_gif.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/image/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/image/paint_image.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/load/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/load/load_someone_make_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/measure/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/measure/measure_widget.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/monitor/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/monitor/monitor_widget.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/notes/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/notes/sticky_note_widget.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/overlay_factory.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/particle/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/particle/particle_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/pet/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/pet/desktop_pet.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/presentation/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/presentation/annotation_overlay.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/presentation/cursor_effects.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/presentation/keystroke_display.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/presentation/magnifier.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/scene/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/scene/extend_graphic_scene.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/scene/extend_graphic_view.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/scene/scene.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/screen_care/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/screen_care/color_vision_widget.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/screen_care/screen_filter.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/sound_player/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/sound_player/sound_effect.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/sound_player/sound_player.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/spectrum/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/spectrum/spectrum_widget.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/text/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/text/draw_text.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/toast/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/toast/toast_widget.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/video/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/video/video_player.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/wallpaper/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/wallpaper/wallpaper_widget.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/web/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/web/webview.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/show/window_helpers.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/system_tray/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/system_tray/extend_system_tray.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/color/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/color/global_color.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/dialog/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/dialog/app_profile_dialog.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/dialog/clipboard_dialog.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/dialog/reminder_dialog.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/dialog/save_file_dialog.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/dialog/smart_pause_dialog.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/dialog/usage_report_dialog.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/dialog/window_pin_dialog.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/main_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/menu/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/menu/help_menu.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/menu/how_to_menu.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/menu/language_menu.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/menu/preset_menu.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/menu/settings_menu.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/control_center/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/control_center/control_center_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/focus/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/focus/focus_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/gif/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/image/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/image/image_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/particle/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/pet/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/pet/pet_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/presentation/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/presentation/presentation_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/scene_page/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/screen_care/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/screen_care/screen_care_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/sound_player/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/text/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/text/text_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/tools/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/utils.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/video/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/video/video_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/wallpaper/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/wallpaper/wallpaper_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/web/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/web/web_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/widgets/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/ui/page/widgets/widgets_setting_ui.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/user_setting/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/user_setting/preset_repository.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/user_setting/scene_setting.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/app_profile/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/app_profile/app_profile_service.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/audio_meter/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/audio_meter/audio_envelope.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/audio_meter/loopback_capture.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/audio_meter/screen_audio.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/audio_meter/spectrum_analyzer.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/audio_meter/system_audio_meter.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/autostart/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/autostart/autostart_service.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/break_reminder/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/break_reminder/break_reminder.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/browser/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/browser/browser.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/clipboard/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/clipboard/clipboard_history.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/clipboard/clipboard_watcher.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/color_vision/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/color_vision/color_vision.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/critical_exit/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/critical_exit/critical_exit.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/critical_exit/win32_vk.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/exception/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/exception/exception_tags.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/exception/exceptions.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/file/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/file/open/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/file/open/open_file.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/file/save/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/file/save/save_file.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/focus_shield/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/focus_shield/focus_shield.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/focus_timer/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/focus_timer/focus_timer.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/hotkey/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/hotkey/hotkey_service.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/input_watch/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/input_watch/input_watch_service.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/json/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/json/json_file.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/json/json_repository.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/json_format/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/json_format/json_process.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/logging/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/logging/loggin_instance.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/measure/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/measure/measure.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/multi_language/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/multi_language/france.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/multi_language/germany.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/multi_language/italy.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/multi_language/language_wrapper.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/multi_language/russian.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/now_playing/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/now_playing/now_playing.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/pet_chat/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/pet_chat/pet_chat_service.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/platform_info/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/platform_info/platform_info.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/playlist/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/playlist/playlist.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/plugins/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/plugins/plugin_loader.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/power_mode/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/power_mode/power_mode.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/preset_schedule/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
- {frontengine-1.0.38/frontengine/utils/redirect_manager → frontengine-1.0.39/frontengine/utils/recording}/__init__.py +0 -0
- {frontengine-1.0.38/frontengine/utils/reminder → frontengine-1.0.39/frontengine/utils/redirect_manager}/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
- {frontengine-1.0.38/frontengine/utils/smart_pause → frontengine-1.0.39/frontengine/utils/reminder}/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/reminder/reminder_service.py +0 -0
- {frontengine-1.0.38/frontengine/utils/system_stats → frontengine-1.0.39/frontengine/utils/smart_pause}/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/smart_pause/pause_rules.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
- {frontengine-1.0.38/frontengine/utils/text_source → frontengine-1.0.39/frontengine/utils/system_stats}/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/system_stats/system_stats.py +0 -0
- {frontengine-1.0.38/frontengine/utils/theme_schedule → frontengine-1.0.39/frontengine/utils/text_source}/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/text_source/text_source.py +0 -0
- {frontengine-1.0.38/frontengine/utils/usage_tracking → frontengine-1.0.39/frontengine/utils/theme_schedule}/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
- {frontengine-1.0.38/frontengine/utils/weather → frontengine-1.0.39/frontengine/utils/usage_tracking}/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/usage_tracking/usage_service.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/usage_tracking/usage_tracker.py +0 -0
- {frontengine-1.0.38/frontengine/utils/window_pin → frontengine-1.0.39/frontengine/utils/weather}/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/weather/weather_service.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/web_url.py +0 -0
- {frontengine-1.0.38/frontengine/utils/workshop → frontengine-1.0.39/frontengine/utils/window_pin}/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/window_pin/window_layout.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/window_pin/window_pin.py +0 -0
- {frontengine-1.0.38/frontengine/worker → frontengine-1.0.39/frontengine/utils/workshop}/__init__.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/workshop/workshop_content.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine/worker/qthread_worker.py +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine.egg-info/dependency_links.txt +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine.egg-info/entry_points.txt +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine.egg-info/requires.txt +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/frontengine.egg-info/top_level.txt +0 -0
- {frontengine-1.0.38 → frontengine-1.0.39}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: frontengine
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.39
|
|
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
|
|
@@ -143,6 +143,17 @@ Measuring and capture tools on the **Tools** tab:
|
|
|
143
143
|
`hsl(...)` or a CSS custom property.
|
|
144
144
|
- **Region capture** — drag out an area; it lands on the clipboard and can be
|
|
145
145
|
saved to a file.
|
|
146
|
+
- **Read text** — drag out an area to copy the text in it, translate it, or ask
|
|
147
|
+
a question about it.
|
|
148
|
+
> This is the **only** feature here that sends screen content off the
|
|
149
|
+
> machine: the selection goes to Anthropic's API using your own
|
|
150
|
+
> `ANTHROPIC_API_KEY`. It asks once before the first send, remembers the
|
|
151
|
+
> answer, and the consent can be withdrawn from the result window at any
|
|
152
|
+
> time. Without consent or without a key, nothing is sent.
|
|
153
|
+
- **Record area** — drag out an area and record it to an animated GIF, with the
|
|
154
|
+
camera composited into the corner if you want the reaction-video look.
|
|
155
|
+
Recording is capped by both length and frame count, because every frame is
|
|
156
|
+
held in memory.
|
|
146
157
|
- **Pin a window** — keep another program's window on top, or fade it, while
|
|
147
158
|
you work against it. Only stacking and opacity are touched, never window
|
|
148
159
|
content. Windows only.
|
|
@@ -119,6 +119,17 @@ Measuring and capture tools on the **Tools** tab:
|
|
|
119
119
|
`hsl(...)` or a CSS custom property.
|
|
120
120
|
- **Region capture** — drag out an area; it lands on the clipboard and can be
|
|
121
121
|
saved to a file.
|
|
122
|
+
- **Read text** — drag out an area to copy the text in it, translate it, or ask
|
|
123
|
+
a question about it.
|
|
124
|
+
> This is the **only** feature here that sends screen content off the
|
|
125
|
+
> machine: the selection goes to Anthropic's API using your own
|
|
126
|
+
> `ANTHROPIC_API_KEY`. It asks once before the first send, remembers the
|
|
127
|
+
> answer, and the consent can be withdrawn from the result window at any
|
|
128
|
+
> time. Without consent or without a key, nothing is sent.
|
|
129
|
+
- **Record area** — drag out an area and record it to an animated GIF, with the
|
|
130
|
+
camera composited into the corner if you want the reaction-video look.
|
|
131
|
+
Recording is capped by both length and frame count, because every frame is
|
|
132
|
+
held in memory.
|
|
122
133
|
- **Pin a window** — keep another program's window on top, or fade it, while
|
|
123
134
|
you work against it. Only stacking and opacity are touched, never window
|
|
124
135
|
content. Windows only.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""
|
|
2
|
+
畫面文字視窗:顯示 Claude 從截圖讀出來的結果,並提供複製。
|
|
3
|
+
|
|
4
|
+
第一次使用會先問一次「要把截圖送到 Anthropic 的 API 嗎」,同意後才會送,
|
|
5
|
+
而且這個選擇記在設定裡,隨時可以在這裡收回。
|
|
6
|
+
|
|
7
|
+
The screen-text window: show what Claude read from the capture, and offer to
|
|
8
|
+
copy it.
|
|
9
|
+
|
|
10
|
+
The first use asks whether the screenshot may be sent to Anthropic's API.
|
|
11
|
+
Nothing is sent before that is answered, the choice is remembered, and it can
|
|
12
|
+
be withdrawn from right here.
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import Optional
|
|
17
|
+
|
|
18
|
+
from PySide6.QtGui import QGuiApplication
|
|
19
|
+
from PySide6.QtWidgets import (
|
|
20
|
+
QCheckBox, QDialog, QDialogButtonBox, QGridLayout, QLabel, QMessageBox, QPlainTextEdit,
|
|
21
|
+
QPushButton, QWidget,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
from frontengine.user_setting.user_setting_file import user_setting_dict, write_user_setting
|
|
25
|
+
from frontengine.utils.logging.loggin_instance import front_engine_logger
|
|
26
|
+
from frontengine.utils.multi_language.language_wrapper import language_wrapper
|
|
27
|
+
from frontengine.utils.screen_text.screen_text_service import API_KEY_ENV, api_key
|
|
28
|
+
|
|
29
|
+
CONSENT_KEY = "screen_text_consent"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _t(key: str, fallback: str) -> str:
|
|
33
|
+
return language_wrapper.language_word_dict.get(key, fallback)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def has_consent() -> bool:
|
|
37
|
+
"""使用者是否已經同意把截圖送出去。"""
|
|
38
|
+
return bool(user_setting_dict.get(CONSENT_KEY))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def set_consent(granted: bool) -> None:
|
|
42
|
+
"""記住(或收回)同意。"""
|
|
43
|
+
user_setting_dict[CONSENT_KEY] = bool(granted)
|
|
44
|
+
write_user_setting()
|
|
45
|
+
front_engine_logger.info(f"[ScreenText] consent = {bool(granted)}")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def ask_for_consent(parent: Optional[QWidget] = None) -> bool:
|
|
49
|
+
"""
|
|
50
|
+
問使用者要不要把截圖送到 Anthropic。已經同意過就直接回 True,不再打擾。
|
|
51
|
+
Ask whether screenshots may go to Anthropic. Already-granted consent returns
|
|
52
|
+
True without asking again.
|
|
53
|
+
"""
|
|
54
|
+
if has_consent():
|
|
55
|
+
return True
|
|
56
|
+
answer = QMessageBox.question(
|
|
57
|
+
parent,
|
|
58
|
+
_t("screen_text_consent_title", "Send this screenshot?"),
|
|
59
|
+
_t("screen_text_consent_body",
|
|
60
|
+
"Reading text needs the captured area sent to Anthropic's API. It leaves this "
|
|
61
|
+
"machine, and anything visible in the selection goes with it. Your own "
|
|
62
|
+
"ANTHROPIC_API_KEY is used. Send captures?"),
|
|
63
|
+
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
|
64
|
+
QMessageBox.StandardButton.No)
|
|
65
|
+
granted = answer == QMessageBox.StandardButton.Yes
|
|
66
|
+
set_consent(granted)
|
|
67
|
+
return granted
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class ScreenTextDialog(QDialog):
|
|
71
|
+
"""顯示讀到的文字,可複製,也可以在這裡收回同意。"""
|
|
72
|
+
|
|
73
|
+
def __init__(self, text: str = "", parent: Optional[QWidget] = None) -> None:
|
|
74
|
+
front_engine_logger.info("[ScreenTextDialog] Init")
|
|
75
|
+
super().__init__(parent)
|
|
76
|
+
self.setWindowTitle(_t("screen_text_title", "Text on screen"))
|
|
77
|
+
|
|
78
|
+
self.text_edit = QPlainTextEdit(str(text))
|
|
79
|
+
self.text_edit.setReadOnly(False)
|
|
80
|
+
self.copy_button = QPushButton(_t("screen_text_copy", "Copy"))
|
|
81
|
+
self.copy_button.clicked.connect(self.copy_text)
|
|
82
|
+
self.consent_checkbox = QCheckBox(
|
|
83
|
+
_t("screen_text_consent_toggle", "Allow sending captures to Anthropic"))
|
|
84
|
+
self.consent_checkbox.setChecked(has_consent())
|
|
85
|
+
self.consent_checkbox.toggled.connect(set_consent)
|
|
86
|
+
self.hint_label = QLabel(self.status_text())
|
|
87
|
+
self.hint_label.setWordWrap(True)
|
|
88
|
+
|
|
89
|
+
self.button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Close)
|
|
90
|
+
self.button_box.rejected.connect(self.reject)
|
|
91
|
+
|
|
92
|
+
layout = QGridLayout(self)
|
|
93
|
+
layout.addWidget(self.text_edit, 0, 0, 1, 2)
|
|
94
|
+
layout.addWidget(self.copy_button, 1, 0)
|
|
95
|
+
layout.addWidget(self.consent_checkbox, 1, 1)
|
|
96
|
+
layout.addWidget(self.hint_label, 2, 0, 1, 2)
|
|
97
|
+
layout.addWidget(self.button_box, 3, 0, 1, 2)
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def status_text() -> str:
|
|
101
|
+
"""說明目前為什麼可用或不可用。"""
|
|
102
|
+
if api_key() is None:
|
|
103
|
+
return _t("screen_text_no_key",
|
|
104
|
+
"Set {env} in your environment to use this.").format(env=API_KEY_ENV)
|
|
105
|
+
return _t("screen_text_ready",
|
|
106
|
+
"Captures are sent to Anthropic only while the box above is ticked.")
|
|
107
|
+
|
|
108
|
+
def set_text(self, text: str) -> None:
|
|
109
|
+
self.text_edit.setPlainText(str(text or ""))
|
|
110
|
+
|
|
111
|
+
def text(self) -> str:
|
|
112
|
+
return self.text_edit.toPlainText()
|
|
113
|
+
|
|
114
|
+
def copy_text(self) -> bool:
|
|
115
|
+
"""把結果放到剪貼簿。"""
|
|
116
|
+
clipboard = QGuiApplication.clipboard()
|
|
117
|
+
if clipboard is None: # pragma: no cover - no clipboard at all
|
|
118
|
+
return False
|
|
119
|
+
clipboard.setText(self.text())
|
|
120
|
+
return True
|
|
@@ -8,18 +8,23 @@ arranging - as opposed to the other pages, which are for showing.
|
|
|
8
8
|
"""
|
|
9
9
|
from typing import List, Optional
|
|
10
10
|
|
|
11
|
+
from PySide6.QtCore import QBuffer, QIODevice, QTimer
|
|
11
12
|
from PySide6.QtGui import QGuiApplication
|
|
12
13
|
from PySide6.QtWidgets import (
|
|
13
|
-
QCheckBox, QComboBox, QGridLayout, QLabel, QLineEdit, QPushButton, QSpinBox,
|
|
14
|
+
QCheckBox, QComboBox, QFileDialog, QGridLayout, QLabel, QLineEdit, QPushButton, QSpinBox,
|
|
15
|
+
QWidget,
|
|
14
16
|
)
|
|
15
17
|
|
|
16
18
|
from frontengine.show.camera.camera_widget import (
|
|
17
19
|
SHAPE_CIRCLE, SHAPE_RECTANGLE, SHAPE_ROUNDED, CameraWidget, list_cameras,
|
|
18
20
|
)
|
|
19
|
-
from frontengine.show.capture.region_capture import RegionCaptureWidget
|
|
21
|
+
from frontengine.show.capture.region_capture import RegionCaptureWidget, is_usable
|
|
20
22
|
from frontengine.show.measure.measure_widget import (
|
|
21
23
|
MODE_ANGLE, MODE_COLOR, MODE_RULER, MeasureWidget,
|
|
22
24
|
)
|
|
25
|
+
from frontengine.ui.dialog.screen_text_dialog import (
|
|
26
|
+
ScreenTextDialog, ask_for_consent, has_consent,
|
|
27
|
+
)
|
|
23
28
|
from frontengine.ui.dialog.window_pin_dialog import WindowPinDialog
|
|
24
29
|
from frontengine.user_setting.user_setting_file import user_setting_dict, write_user_setting
|
|
25
30
|
from frontengine.ui.page.utils import coerce_int
|
|
@@ -28,6 +33,12 @@ from frontengine.utils.measure.measure import (
|
|
|
28
33
|
FORMAT_CSS_VAR, FORMAT_HEX, FORMAT_HSL, FORMAT_RGB,
|
|
29
34
|
)
|
|
30
35
|
from frontengine.utils.multi_language.language_wrapper import language_wrapper
|
|
36
|
+
from frontengine.utils.screen_text.screen_text_service import (
|
|
37
|
+
ACTION_ASK, ACTION_EXTRACT, ACTION_TRANSLATE, DEFAULT_LANGUAGE, ScreenTextService,
|
|
38
|
+
)
|
|
39
|
+
from frontengine.utils.recording.frame_recorder import (
|
|
40
|
+
DEFAULT_FPS, DEFAULT_MAX_SECONDS, MAX_FPS, MIN_FPS, FrameRecorder,
|
|
41
|
+
)
|
|
31
42
|
from frontengine.utils.window_pin import window_pin
|
|
32
43
|
from frontengine.utils.window_pin.window_layout import capture_layout, restore_layout
|
|
33
44
|
|
|
@@ -46,6 +57,10 @@ class ToolsSettingUI(QWidget):
|
|
|
46
57
|
self.grid_layout.setContentsMargins(0, 0, 0, 0)
|
|
47
58
|
|
|
48
59
|
self.measure_widget_list: List[MeasureWidget] = []
|
|
60
|
+
self.recorder = FrameRecorder(self)
|
|
61
|
+
self.screen_text_service = ScreenTextService(consent_provider=has_consent)
|
|
62
|
+
self.last_screen_text: Optional[str] = None
|
|
63
|
+
self.last_recording: Optional[str] = None
|
|
49
64
|
self.capture_widget_list: List[RegionCaptureWidget] = []
|
|
50
65
|
self.camera_widget_list: List[CameraWidget] = []
|
|
51
66
|
self.last_capture: Optional[RegionCaptureWidget] = None
|
|
@@ -53,6 +68,8 @@ class ToolsSettingUI(QWidget):
|
|
|
53
68
|
|
|
54
69
|
self._build_measure_row()
|
|
55
70
|
self._build_capture_row()
|
|
71
|
+
self._build_screen_text_row()
|
|
72
|
+
self._build_record_row()
|
|
56
73
|
self._build_camera_row()
|
|
57
74
|
self.pin_button = QPushButton(_t("tools_pin_window", "Pin a window..."))
|
|
58
75
|
self.pin_button.clicked.connect(self.open_pin_dialog)
|
|
@@ -84,20 +101,29 @@ class ToolsSettingUI(QWidget):
|
|
|
84
101
|
self.grid_layout.addWidget(self.capture_label, 2, 0)
|
|
85
102
|
self.grid_layout.addWidget(self.capture_button, 2, 1)
|
|
86
103
|
self.grid_layout.addWidget(self.capture_copy_button, 2, 2)
|
|
87
|
-
self.grid_layout.addWidget(self.
|
|
88
|
-
self.grid_layout.addWidget(self.
|
|
89
|
-
self.grid_layout.addWidget(self.
|
|
90
|
-
self.grid_layout.addWidget(self.
|
|
91
|
-
self.grid_layout.addWidget(self.
|
|
92
|
-
self.grid_layout.addWidget(self.
|
|
93
|
-
self.grid_layout.addWidget(self.
|
|
94
|
-
self.grid_layout.addWidget(self.
|
|
95
|
-
self.grid_layout.addWidget(self.
|
|
96
|
-
self.grid_layout.addWidget(self.
|
|
97
|
-
self.grid_layout.addWidget(self.
|
|
98
|
-
self.grid_layout.addWidget(self.
|
|
99
|
-
self.grid_layout.addWidget(self.
|
|
100
|
-
self.grid_layout.addWidget(self.
|
|
104
|
+
self.grid_layout.addWidget(self.screen_text_label, 3, 0)
|
|
105
|
+
self.grid_layout.addWidget(self.screen_text_combobox, 3, 1)
|
|
106
|
+
self.grid_layout.addWidget(self.screen_text_button, 3, 2)
|
|
107
|
+
self.grid_layout.addWidget(self.screen_text_input, 4, 1, 1, 2)
|
|
108
|
+
self.grid_layout.addWidget(self.record_label, 5, 0)
|
|
109
|
+
self.grid_layout.addWidget(self.record_fps_spinbox, 5, 1)
|
|
110
|
+
self.grid_layout.addWidget(self.record_button, 5, 2)
|
|
111
|
+
self.grid_layout.addWidget(self.record_seconds_spinbox, 6, 1)
|
|
112
|
+
self.grid_layout.addWidget(self.record_camera_checkbox, 6, 2)
|
|
113
|
+
self.grid_layout.addWidget(self.camera_label, 7, 0)
|
|
114
|
+
self.grid_layout.addWidget(self.camera_shape_combobox, 7, 1)
|
|
115
|
+
self.grid_layout.addWidget(self.camera_button, 7, 2)
|
|
116
|
+
self.grid_layout.addWidget(self.camera_device_combobox, 8, 0, 1, 2)
|
|
117
|
+
self.grid_layout.addWidget(self.camera_mirror_checkbox, 8, 2)
|
|
118
|
+
self.grid_layout.addWidget(self.camera_border_label, 9, 0)
|
|
119
|
+
self.grid_layout.addWidget(self.camera_border_spinbox, 9, 1)
|
|
120
|
+
self.grid_layout.addWidget(self.pin_button, 10, 0)
|
|
121
|
+
self.grid_layout.addWidget(self.layout_label, 11, 0)
|
|
122
|
+
self.grid_layout.addWidget(self.layout_name_edit, 11, 1)
|
|
123
|
+
self.grid_layout.addWidget(self.layout_save_button, 11, 2)
|
|
124
|
+
self.grid_layout.addWidget(self.layout_combobox, 12, 0, 1, 2)
|
|
125
|
+
self.grid_layout.addWidget(self.layout_restore_button, 12, 2)
|
|
126
|
+
self.grid_layout.addWidget(self.hint_label, 13, 0, 1, 3)
|
|
101
127
|
|
|
102
128
|
# --- construction helpers -------------------------------------------
|
|
103
129
|
def _build_measure_row(self) -> None:
|
|
@@ -124,6 +150,32 @@ class ToolsSettingUI(QWidget):
|
|
|
124
150
|
self.capture_copy_button = QPushButton(_t("tools_capture_copy", "Copy last"))
|
|
125
151
|
self.capture_copy_button.clicked.connect(self.copy_last_capture)
|
|
126
152
|
|
|
153
|
+
def _build_screen_text_row(self) -> None:
|
|
154
|
+
self.screen_text_label = QLabel(_t("tools_screen_text_label", "Read text"))
|
|
155
|
+
self.screen_text_combobox = QComboBox()
|
|
156
|
+
for action, key, fallback in ((ACTION_EXTRACT, "tools_screen_text_extract", "Copy text"),
|
|
157
|
+
(ACTION_TRANSLATE, "tools_screen_text_translate", "Translate"),
|
|
158
|
+
(ACTION_ASK, "tools_screen_text_ask", "Ask about it")):
|
|
159
|
+
self.screen_text_combobox.addItem(_t(key, fallback), action)
|
|
160
|
+
self.screen_text_input = QLineEdit()
|
|
161
|
+
self.screen_text_input.setPlaceholderText(
|
|
162
|
+
_t("tools_screen_text_input", "Language, or your question"))
|
|
163
|
+
self.screen_text_input.setText(DEFAULT_LANGUAGE)
|
|
164
|
+
self.screen_text_button = QPushButton(_t("tools_screen_text_start", "Read an area"))
|
|
165
|
+
self.screen_text_button.clicked.connect(self.start_screen_text)
|
|
166
|
+
|
|
167
|
+
def _build_record_row(self) -> None:
|
|
168
|
+
self.record_label = QLabel(_t("tools_record_label", "Record area"))
|
|
169
|
+
self.record_fps_spinbox = QSpinBox()
|
|
170
|
+
self.record_fps_spinbox.setRange(MIN_FPS, MAX_FPS)
|
|
171
|
+
self.record_fps_spinbox.setValue(DEFAULT_FPS)
|
|
172
|
+
self.record_seconds_spinbox = QSpinBox()
|
|
173
|
+
self.record_seconds_spinbox.setRange(1, 120)
|
|
174
|
+
self.record_seconds_spinbox.setValue(DEFAULT_MAX_SECONDS)
|
|
175
|
+
self.record_camera_checkbox = QCheckBox(_t("tools_record_camera", "Include camera"))
|
|
176
|
+
self.record_button = QPushButton(_t("tools_record_start", "Record area"))
|
|
177
|
+
self.record_button.clicked.connect(self.toggle_recording)
|
|
178
|
+
|
|
127
179
|
def _build_camera_row(self) -> None:
|
|
128
180
|
self.camera_label = QLabel(_t("tools_camera_label", "Camera"))
|
|
129
181
|
self.camera_shape_combobox = QComboBox()
|
|
@@ -275,6 +327,104 @@ class ToolsSettingUI(QWidget):
|
|
|
275
327
|
except RuntimeError:
|
|
276
328
|
self.pin_dialog = None
|
|
277
329
|
|
|
330
|
+
# --- reading text on screen ------------------------------------------
|
|
331
|
+
def start_screen_text(self):
|
|
332
|
+
"""
|
|
333
|
+
框一塊畫面來讀文字。第一次會先問過同意,沒同意就什麼都不做——
|
|
334
|
+
這是唯一會把畫面內容送出機器的功能。
|
|
335
|
+
Pick an area to read. The first use asks for consent and does nothing
|
|
336
|
+
without it: this is the only feature that sends screen content off the
|
|
337
|
+
machine.
|
|
338
|
+
"""
|
|
339
|
+
if not ask_for_consent(self):
|
|
340
|
+
front_engine_logger.info("[ToolsSettingUI] screen text cancelled: no consent")
|
|
341
|
+
return None
|
|
342
|
+
picker = RegionCaptureWidget(on_captured=lambda pixmap, rect: self._read_capture(pixmap))
|
|
343
|
+
screen = QGuiApplication.primaryScreen()
|
|
344
|
+
if screen is not None:
|
|
345
|
+
picker.setGeometry(screen.geometry())
|
|
346
|
+
picker.setMouseTracking(True)
|
|
347
|
+
picker.show()
|
|
348
|
+
self.capture_widget_list.append(picker)
|
|
349
|
+
return picker
|
|
350
|
+
|
|
351
|
+
def _read_capture(self, pixmap) -> None:
|
|
352
|
+
"""把框到的畫面送出去讀(在背景執行緒,UI 不會卡住)。"""
|
|
353
|
+
data = pixmap_to_png(pixmap)
|
|
354
|
+
if not data:
|
|
355
|
+
return
|
|
356
|
+
self.screen_text_service.read_async(
|
|
357
|
+
data, self.show_screen_text,
|
|
358
|
+
action=self.screen_text_combobox.currentData(),
|
|
359
|
+
language=self.screen_text_input.text(),
|
|
360
|
+
question=self.screen_text_input.text())
|
|
361
|
+
|
|
362
|
+
def show_screen_text(self, text) -> None:
|
|
363
|
+
"""收到結果:切回 UI 執行緒再開視窗(回呼來自背景執行緒)。"""
|
|
364
|
+
self.last_screen_text = text
|
|
365
|
+
QTimer.singleShot(0, lambda: self._present_screen_text(text))
|
|
366
|
+
|
|
367
|
+
def _present_screen_text(self, text):
|
|
368
|
+
dialog = ScreenTextDialog(
|
|
369
|
+
text or _t("tools_screen_text_empty", "Nothing came back."), self)
|
|
370
|
+
dialog.exec()
|
|
371
|
+
return dialog
|
|
372
|
+
|
|
373
|
+
# --- recording -------------------------------------------------------
|
|
374
|
+
def toggle_recording(self) -> None:
|
|
375
|
+
if self.recorder.running:
|
|
376
|
+
self.finish_recording()
|
|
377
|
+
else:
|
|
378
|
+
self.start_recording()
|
|
379
|
+
|
|
380
|
+
def start_recording(self) -> RegionCaptureWidget:
|
|
381
|
+
"""先框一塊範圍,放開滑鼠後就從那塊開始錄。"""
|
|
382
|
+
front_engine_logger.info("[ToolsSettingUI] start_recording")
|
|
383
|
+
picker = RegionCaptureWidget()
|
|
384
|
+
picker.finish = _recording_region_picker(self, picker)
|
|
385
|
+
screen = QGuiApplication.primaryScreen()
|
|
386
|
+
if screen is not None:
|
|
387
|
+
picker.setGeometry(screen.geometry())
|
|
388
|
+
picker.setMouseTracking(True)
|
|
389
|
+
picker.show()
|
|
390
|
+
self.capture_widget_list.append(picker)
|
|
391
|
+
return picker
|
|
392
|
+
|
|
393
|
+
def begin_recording(self, region) -> bool:
|
|
394
|
+
"""對指定範圍開始錄製。"""
|
|
395
|
+
inset = self.camera_inset if self.record_camera_checkbox.isChecked() else None
|
|
396
|
+
self.recorder.set_inset_provider(inset)
|
|
397
|
+
started = self.recorder.start(region, self.record_fps_spinbox.value(),
|
|
398
|
+
self.record_seconds_spinbox.value())
|
|
399
|
+
if started:
|
|
400
|
+
self.record_button.setText(_t("tools_record_stop", "Stop recording"))
|
|
401
|
+
return started
|
|
402
|
+
|
|
403
|
+
def camera_inset(self) -> Optional[object]:
|
|
404
|
+
"""錄影時要疊上去的攝影機畫面(沒開攝影機就沒有)。"""
|
|
405
|
+
for widget in list(self.camera_widget_list):
|
|
406
|
+
try:
|
|
407
|
+
if widget.frame is not None:
|
|
408
|
+
return widget.frame
|
|
409
|
+
except RuntimeError:
|
|
410
|
+
self.camera_widget_list.remove(widget)
|
|
411
|
+
return None
|
|
412
|
+
|
|
413
|
+
def finish_recording(self) -> Optional[str]:
|
|
414
|
+
"""停止錄製並存成 GIF,回傳檔案路徑。"""
|
|
415
|
+
self.recorder.stop()
|
|
416
|
+
self.record_button.setText(_t("tools_record_start", "Record area"))
|
|
417
|
+
if not self.recorder.frames:
|
|
418
|
+
return None
|
|
419
|
+
target = QFileDialog.getSaveFileName(
|
|
420
|
+
self, _t("tools_record_save", "Save recording"), "recording.gif", "GIF (*.gif)")[0]
|
|
421
|
+
if not target:
|
|
422
|
+
self.recorder.clear()
|
|
423
|
+
return None
|
|
424
|
+
self.last_recording = self.recorder.save_gif(target)
|
|
425
|
+
self.recorder.clear()
|
|
426
|
+
return self.last_recording
|
|
427
|
+
|
|
278
428
|
# --- window layouts --------------------------------------------------
|
|
279
429
|
def saved_layouts(self) -> dict:
|
|
280
430
|
"""設定裡目前存了哪些版面。"""
|
|
@@ -336,3 +486,43 @@ class ToolsSettingUI(QWidget):
|
|
|
336
486
|
self.camera_border_spinbox.setValue(max(0, min(20, border)))
|
|
337
487
|
if "camera_mirror" in state:
|
|
338
488
|
self.camera_mirror_checkbox.setChecked(bool(state["camera_mirror"]))
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def _recording_region_picker(page: "ToolsSettingUI", picker: RegionCaptureWidget):
|
|
492
|
+
"""
|
|
493
|
+
把框選層的 finish() 換成「不擷取畫面、只回報範圍給錄影」。錄影要的是
|
|
494
|
+
連續的畫面,不是放開當下那一張。
|
|
495
|
+
Replace the picker's finish() so it reports the region to the recorder
|
|
496
|
+
instead of grabbing one still: a recording wants the frames that follow.
|
|
497
|
+
"""
|
|
498
|
+
original_close = picker.close
|
|
499
|
+
|
|
500
|
+
def finish(point):
|
|
501
|
+
picker.extend(point)
|
|
502
|
+
region = picker.selection()
|
|
503
|
+
picker.origin = picker.current = None
|
|
504
|
+
if picker in page.capture_widget_list:
|
|
505
|
+
page.capture_widget_list.remove(picker)
|
|
506
|
+
original_close()
|
|
507
|
+
if region is not None and is_usable(region):
|
|
508
|
+
page.begin_recording(region)
|
|
509
|
+
return None
|
|
510
|
+
|
|
511
|
+
return finish
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def pixmap_to_png(pixmap) -> bytes:
|
|
515
|
+
"""
|
|
516
|
+
把擷取到的畫面轉成 PNG 位元組(送出去用)。轉不出來就回傳空的,
|
|
517
|
+
呼叫端會因此什麼都不送。
|
|
518
|
+
The capture as PNG bytes, ready to send. An empty result means nothing is
|
|
519
|
+
sent at all.
|
|
520
|
+
"""
|
|
521
|
+
if pixmap is None or pixmap.isNull():
|
|
522
|
+
return b""
|
|
523
|
+
buffer = QBuffer()
|
|
524
|
+
buffer.open(QIODevice.OpenModeFlag.WriteOnly)
|
|
525
|
+
saved = pixmap.save(buffer, "PNG")
|
|
526
|
+
data = bytes(buffer.data()) if saved else b""
|
|
527
|
+
buffer.close()
|
|
528
|
+
return data
|
|
@@ -66,6 +66,9 @@ user_setting_dict: Dict[str, Any] = {
|
|
|
66
66
|
# 已儲存的視窗版面:名稱 -> [{title, x, y, width, height}]
|
|
67
67
|
# Saved window layouts: name -> [{title, x, y, width, height}]
|
|
68
68
|
"window_layouts": {},
|
|
69
|
+
# 是否同意把擷取畫面送到 Anthropic 讀取文字(預設不同意)
|
|
70
|
+
# Consent to send captures to Anthropic for reading text (off by default).
|
|
71
|
+
"screen_text_consent": False,
|
|
69
72
|
# 覆蓋層畫質檔位:high / balanced / saver
|
|
70
73
|
# Overlay quality tier: high / balanced / saver.
|
|
71
74
|
"quality_tier": "high",
|
|
@@ -499,4 +499,23 @@ english_word_dict = {
|
|
|
499
499
|
"tools_layout_name": 'Layout name',
|
|
500
500
|
"tools_layout_save": 'Save layout',
|
|
501
501
|
"tools_layout_restore": 'Restore',
|
|
502
|
+
"tools_record_label": 'Record area',
|
|
503
|
+
"tools_record_start": 'Record area',
|
|
504
|
+
"tools_record_stop": 'Stop recording',
|
|
505
|
+
"tools_record_camera": 'Include camera',
|
|
506
|
+
"tools_record_save": 'Save recording',
|
|
507
|
+
"tools_screen_text_label": 'Read text',
|
|
508
|
+
"tools_screen_text_extract": 'Copy text',
|
|
509
|
+
"tools_screen_text_translate": 'Translate',
|
|
510
|
+
"tools_screen_text_ask": 'Ask about it',
|
|
511
|
+
"tools_screen_text_input": 'Language, or your question',
|
|
512
|
+
"tools_screen_text_start": 'Read an area',
|
|
513
|
+
"tools_screen_text_empty": 'Nothing came back.',
|
|
514
|
+
"screen_text_title": 'Text on screen',
|
|
515
|
+
"screen_text_copy": 'Copy',
|
|
516
|
+
"screen_text_consent_toggle": 'Allow sending captures to Anthropic',
|
|
517
|
+
"screen_text_consent_title": 'Send this screenshot?',
|
|
518
|
+
"screen_text_consent_body": "Reading text needs the captured area sent to Anthropic's API. It leaves this machine, and anything visible in the selection goes with it. Your own ANTHROPIC_API_KEY is used. Send captures?",
|
|
519
|
+
"screen_text_no_key": 'Set {env} in your environment to use this.',
|
|
520
|
+
"screen_text_ready": 'Captures are sent to Anthropic only while the box above is ticked.',
|
|
502
521
|
}
|
{frontengine-1.0.38 → frontengine-1.0.39}/frontengine/utils/multi_language/traditional_chinese.py
RENAMED
|
@@ -498,4 +498,23 @@ traditional_chinese_word_dict = {
|
|
|
498
498
|
"tools_layout_name": '版面名稱',
|
|
499
499
|
"tools_layout_save": '儲存版面',
|
|
500
500
|
"tools_layout_restore": '還原',
|
|
501
|
+
"tools_record_label": '區域錄影',
|
|
502
|
+
"tools_record_start": '框選錄影',
|
|
503
|
+
"tools_record_stop": '停止錄影',
|
|
504
|
+
"tools_record_camera": '疊上攝影機',
|
|
505
|
+
"tools_record_save": '儲存錄影',
|
|
506
|
+
"tools_screen_text_label": '讀取文字',
|
|
507
|
+
"tools_screen_text_extract": '複製文字',
|
|
508
|
+
"tools_screen_text_translate": '翻譯',
|
|
509
|
+
"tools_screen_text_ask": '問它問題',
|
|
510
|
+
"tools_screen_text_input": '語言,或你的問題',
|
|
511
|
+
"tools_screen_text_start": '框選讀取',
|
|
512
|
+
"tools_screen_text_empty": '沒有得到結果。',
|
|
513
|
+
"screen_text_title": '畫面上的文字',
|
|
514
|
+
"screen_text_copy": '複製',
|
|
515
|
+
"screen_text_consent_toggle": '允許把擷取畫面送到 Anthropic',
|
|
516
|
+
"screen_text_consent_title": '要送出這張截圖嗎?',
|
|
517
|
+
"screen_text_consent_body": '讀取文字需要把框選到的畫面送到 Anthropic 的 API。這份畫面會離開這台電腦,框選範圍內看得到的東西都會一起送出,使用的是你自己的 ANTHROPIC_API_KEY。要送出嗎?',
|
|
518
|
+
"screen_text_no_key": '請先在環境變數設定 {env} 才能使用。',
|
|
519
|
+
"screen_text_ready": '只有在上面那個選項打勾時,擷取畫面才會送到 Anthropic。',
|
|
501
520
|
}
|