From b441514ef31d61b9ea31b009a167269759b7a9ae Mon Sep 17 00:00:00 2001 From: Ruscher Date: Sun, 1 Mar 2026 04:58:29 -0300 Subject: [PATCH] Fine tuning --- README.md | 363 +++++++++++++++--- big_digicam/etc/modprobe.d/v4l2loopback.conf | 14 + etc/modprobe.d/v4l2loopback.conf | 4 +- usr/share/biglinux/bigcam/core/effects.py | 4 +- .../biglinux/bigcam/core/virtual_camera.py | 2 +- .../accessories-text-editor-symbolic.svg | 1 + .../hicolor/scalable/actions/adjustlevels.svg | 8 + .../actions/audio-volume-muted-symbolic.svg | 1 + .../scalable/actions/audio-volume-muted.svg | 8 + .../scalable/actions/bwtonal-symbolic.svg | 1 + .../img/hicolor/scalable/actions/bwtonal.svg | 8 + .../scalable/actions/call-start-symbolic.svg | 1 + .../hicolor/scalable/actions/call-start.svg | 10 + .../actions/color-select-symbolic.svg | 1 + .../hicolor/scalable/actions/color-select.svg | 8 + .../hicolor/scalable/actions/configure.svg | 8 + .../scalable/actions/contact-new-symbolic.svg | 1 + .../hicolor/scalable/actions/contact-new.svg | 10 + .../actions/dialog-error-symbolic.svg | 1 + .../hicolor/scalable/actions/dialog-error.svg | 6 + .../actions/dialog-information-symbolic.svg | 1 + .../scalable/actions/dialog-information.svg | 6 + .../actions/dialog-warning-symbolic.svg | 1 + .../scalable/actions/dialog-warning.svg | 6 + .../actions/document-save-symbolic.svg | 1 + .../scalable/actions/document-save.svg | 8 + .../scalable/actions/draw-watercolor.svg | 8 + .../scalable/actions/edit-copy-symbolic.svg | 1 + .../hicolor/scalable/actions/edit-copy.svg | 10 + .../scalable/actions/edit-select-symbolic.svg | 1 + .../hicolor/scalable/actions/edit-select.svg | 8 + .../scalable/actions/edit-undo-symbolic.svg | 1 + .../hicolor/scalable/actions/edit-undo.svg | 8 + .../actions/emblem-money-symbolic.svg | 1 + .../hicolor/scalable/actions/emblem-money.svg | 10 + .../actions/find-location-symbolic.svg | 1 + .../scalable/actions/find-location.svg | 11 + .../scalable/actions/folder-open-symbolic.svg | 1 + .../hicolor/scalable/actions/folder-open.svg | 10 + .../image-adjust-contrast-symbolic.svg | 1 + .../actions/image-adjust-contrast.svg | 8 + .../hicolor/scalable/actions/image-adjust.svg | 8 + .../actions/image-filter-symbolic.svg | 1 + .../hicolor/scalable/actions/image-filter.svg | 9 + .../actions/image-missing-symbolic.svg | 1 + .../scalable/actions/image-missing.svg | 8 + .../actions/image-sharpen-symbolic.svg | 1 + .../scalable/actions/image-sharpen.svg | 10 + .../scalable/actions/mail-send-symbolic.svg | 1 + .../hicolor/scalable/actions/mail-send.svg | 10 + .../scalable/actions/mail-unread-symbolic.svg | 1 + .../hicolor/scalable/actions/mail-unread.svg | 8 + .../actions/media-playback-start-symbolic.svg | 1 + .../scalable/actions/media-playback-start.svg | 10 + .../actions/media-playback-stop-symbolic.svg | 1 + .../scalable/actions/media-playback-stop.svg | 8 + .../actions/media-record-symbolic.svg | 1 + .../hicolor/scalable/actions/media-record.svg | 10 + .../scalable/actions/open-menu-symbolic.svg | 1 + .../hicolor/scalable/actions/open-menu.svg | 8 + .../scalable/actions/pan-up-symbolic.svg | 1 + .../img/hicolor/scalable/actions/pan-up.svg | 8 + .../actions/preferences-color-symbolic.svg | 63 +++ .../scalable/actions/send-to-symbolic.svg | 1 + .../img/hicolor/scalable/actions/send-to.svg | 8 + .../system-software-install-symbolic.svg | 1 + .../actions/system-software-install.svg | 8 + .../actions/system-users-symbolic.svg | 1 + .../hicolor/scalable/actions/system-users.svg | 8 + .../hicolor/scalable/actions/tag-symbolic.svg | 1 + .../img/hicolor/scalable/actions/tag.svg | 10 + .../scalable/actions/view-list-images.svg | 10 + .../scalable/actions/view-list-video.svg | 8 + .../actions/view-refresh-symbolic.svg | 1 + .../hicolor/scalable/actions/view-refresh.svg | 10 + .../scalable/actions/web-browser-symbolic.svg | 1 + .../hicolor/scalable/actions/web-browser.svg | 10 + .../actions/window-close-symbolic.svg | 1 + .../hicolor/scalable/actions/window-close.svg | 11 + .../img/hicolor/scalable/apps/bigcam.svg | 1 + .../applications-graphics-symbolic.svg | 4 + .../preferences-system-symbolic.svg | 4 + .../scalable/devices/audio-card-symbolic.svg | 1 + .../hicolor/scalable/devices/audio-card.svg | 31 ++ .../devices/camera-photo-symbolic.svg | 1 + .../hicolor/scalable/devices/camera-photo.svg | 14 + .../devices/camera-video-symbolic.svg | 1 + .../hicolor/scalable/devices/camera-video.svg | 25 ++ .../scalable/devices/camera-web-symbolic.svg | 1 + .../hicolor/scalable/devices/camera-web.svg | 15 + .../devices/network-server-symbolic.svg | 1 + .../scalable/devices/network-server.svg | 45 +++ .../devices/network-wireless-symbolic.svg | 1 + .../scalable/devices/network-wireless.svg | 9 + .../devices/video-display-symbolic.svg | 1 + .../scalable/devices/video-display.svg | 9 + .../emblems/emblem-default-symbolic.svg | 8 + .../emblems/emblem-important-symbolic.svg | 8 + .../scalable/emblems/emblem-ok-symbolic.svg | 8 + .../emblems/emblem-photos-symbolic.svg | 8 + .../emblems/emblem-system-symbolic.svg | 8 + .../scalable/emotes/face-laugh-symbolic.svg | 1 + .../scalable/emotes/face-smile-symbolic.svg | 1 + .../mimetypes/image-x-generic-symbolic.svg | 7 + .../mimetypes/text-x-generic-symbolic.svg | 4 + .../mimetypes/video-x-generic-symbolic.svg | 7 + .../mimetypes/x-office-calendar-symbolic.svg | 4 + .../scalable/places/user-trash-symbolic.svg | 1 + .../hicolor/scalable/places/user-trash.svg | 11 + .../status/channel-secure-symbolic.svg | 4 + .../status/display-brightness-symbolic.svg | 4 + .../status/weather-clear-symbolic.svg | 7 + usr/share/biglinux/bigcam/main.py | 13 +- .../biglinux/bigcam/script/run_webcam.sh | 2 +- .../bigcam/script/run_webcam_gphoto2.sh | 2 +- usr/share/biglinux/bigcam/style.css | 13 + usr/share/biglinux/bigcam/ui/effects_page.py | 69 +++- usr/share/biglinux/bigcam/ui/preview_area.py | 133 ++++++- usr/share/biglinux/bigcam/ui/settings_page.py | 92 +++++ usr/share/biglinux/bigcam/ui/window.py | 114 +++++- .../biglinux/bigcam/utils/settings_manager.py | 5 +- 121 files changed, 1414 insertions(+), 107 deletions(-) create mode 100644 big_digicam/etc/modprobe.d/v4l2loopback.conf create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/accessories-text-editor-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/adjustlevels.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/audio-volume-muted-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/audio-volume-muted.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/bwtonal-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/bwtonal.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/call-start-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/call-start.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/color-select-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/color-select.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/configure.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/contact-new-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/contact-new.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-error-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-error.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-information-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-information.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-warning-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-warning.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/document-save-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/document-save.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/draw-watercolor.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-copy-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-copy.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-select-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-select.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-undo-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-undo.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/emblem-money-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/emblem-money.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/find-location-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/find-location.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/folder-open-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/folder-open.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust-contrast-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust-contrast.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-filter-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-filter.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-missing-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-missing.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-sharpen-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-sharpen.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-send-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-send.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-unread-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-unread.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-start-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-start.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-stop-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-stop.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-record-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-record.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/open-menu-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/open-menu.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/pan-up-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/pan-up.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/preferences-color-symbolic.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/send-to-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/send-to.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-software-install-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-software-install.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-users-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-users.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/tag-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/tag.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-list-images.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-list-video.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-refresh-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-refresh.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/web-browser-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/web-browser.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/window-close-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/actions/window-close.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/apps/bigcam.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/categories/applications-graphics-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/categories/preferences-system-symbolic.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/audio-card-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/audio-card.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-photo-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-photo.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-video-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-video.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-web-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-web.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-server-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-server.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-wireless-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-wireless.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/video-display-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/devices/video-display.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-default-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-important-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-ok-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-photos-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-system-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/emotes/face-laugh-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/emotes/face-smile-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/image-x-generic-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/text-x-generic-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/video-x-generic-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/x-office-calendar-symbolic.svg create mode 120000 usr/share/biglinux/bigcam/img/hicolor/scalable/places/user-trash-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/places/user-trash.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/status/channel-secure-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/status/display-brightness-symbolic.svg create mode 100644 usr/share/biglinux/bigcam/img/hicolor/scalable/status/weather-clear-symbolic.svg diff --git a/README.md b/README.md index d445d42..2b6ed8e 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,20 @@ BigCam

-

📸 BigCam

+

BigCam

- Transforme sua câmera digital (DSLR/Mirrorless) em uma poderosa webcam profissional para Linux + Universal webcam control center for Linux — turn any camera into a professional streaming device

- O BigCam é baseado no projeto libgphoto2, oferecendo suporte a mais de 2.500 modelos de câmeras. -

- -

- Funcionalidades • - Câmeras Suportadas • - Instalação • - Contribuições • - Licença + Features • + Supported Cameras • + Installation • + Architecture • + The Story • + Contributing • + License

@@ -30,87 +28,344 @@ --- -## 🌟 O Projeto +## The Story -O **BigCam** nasceu de uma necessidade real. O que começou como um pequeno script em shell criado por **Rafael Ruscher** e **Barnabé di Kartola** para permitir que o Ruscher usasse sua câmera Canon Rebel T3 em suas lives sobre o **BigLinux**, evoluiu para uma aplicação completa, elegante e robusta integrada ao ecossistema BigLinux. +**BigCam** was born from a real need. It started as a humble shell script written by **Rafael Ruscher** and **Barnabé di Kartola** so that Ruscher could use his Canon Rebel T3 as a webcam during his live streams about [BigLinux](https://www.biglinux.com.br/). That small hack proved so useful that it evolved — first into a more capable script, then into a full-blown GTK4/Adwaita application integrated into the BigLinux ecosystem. -Agradecemos imensamente aos pioneiros Rafael e Barnabé por iniciarem essa jornada que hoje ajuda milhares de usuários a terem qualidade de estúdio em suas videoconferências e produções de conteúdo. +Today BigCam supports USB webcams, DSLR/mirrorless cameras (2,500+ models via libgphoto2), CSI/ISP cameras (libcamera), PipeWire virtual cameras, and network IP cameras — all from a single, polished interface. + +We are grateful to Rafael and Barnabé for starting this journey. --- -## 🚀 Funcionalidades Principais +## Features + +### Live Preview & Streaming + +- **Professional quality**: stream at your camera's native resolution (up to 4K) to Zoom, Teams, Google Meet, OBS Studio, Discord, or any app that reads a V4L2 device. +- **Low latency pipeline**: GStreamer + FFmpeg with MPEG-TS over localhost UDP — optimised for minimal delay. +- **Multi-camera**: connect multiple cameras simultaneously and hot-swap between them without restarting the stream. Each gPhoto2 camera keeps its own persistent session. +- **Virtual camera output**: v4l2loopback integration exposes the active feed as a regular `/dev/video*` device. + +### Camera Backends + +| Backend | Devices | Detection | +|---------|---------|-----------| +| **V4L2** | USB/UVC webcams (95%+ coverage) | Automatic via `v4l2-ctl` | +| **gPhoto2** | DSLR/mirrorless (2,500+ models) | Automatic via `gphoto2 --auto-detect` | +| **libcamera** | Raspberry Pi CSI, Intel IPU6 | Automatic via `cam --list` | +| **PipeWire** | OBS virtual cam, XDG camera portal | Automatic via `pw-cli` | +| **IP** | RTSP/HTTP network cameras | Manual configuration | + +### Camera Controls + +Full per-camera control panel with sliders, switches, and menus — automatically adapted to each camera's capabilities: + +- **Image**: brightness, contrast, saturation, hue, gamma, sharpness, backlight compensation +- **Exposure**: auto/manual exposure, exposure time, gain, ISO +- **Focus**: auto/manual focus, focus distance +- **White Balance**: auto/manual, temperature +- **gPhoto2 extended**: all settings exposed by libgphoto2 (aperture, shutter speed, ISO, image quality, drive mode, etc.) + +### Real-Time Effects (OpenCV) + +17 effects organised in four categories, all combinable and adjustable in real-time: + +| Category | Effects | +|----------|---------| +| **Adjustments** | Brightness/Contrast, Gamma Correction, CLAHE Adaptive Contrast, Auto White Balance | +| **Filters** | Detail Enhance, Beauty/Soft Skin, Sharpen, Denoise | +| **Artistic** | Grayscale, Sepia, Negative, Pencil Sketch, Painting/Stylization, Cartoon, Edge Detection, Color Map (21 palettes), Vignette | +| **Advanced** | Background Blur (face-detection-based) | + +### Tools + +- **QR Code Scanner**: real-time detection using OpenCV WeChatQRCode with detailed result dialog (URL, WiFi, vCard, text). +- **Smile Capture**: automatic photo trigger on smile detection via Haar cascades. Configurable sensitivity and cooldown. + +### Photo & Video + +- **Remote photo capture**: click to capture, preview the result instantly, automatic download from DSLR. +- **Video recording**: records directly from the GStreamer pipeline (x264 ultrafast, MKV container) without interrupting the preview. +- **Photo gallery**: browse and manage captured images with thumbnails. Delete directly from the gallery. +- **Video gallery**: browse and play recorded videos. + +### Interface + +- **GTK4 + Libadwaita**: modern, native GNOME look-and-feel with full dark/light theme support. +- **Paned layout**: resizable preview + sidebar with collapsible pages (Controls, Effects, Tools, Settings, Gallery). +- **Responsive**: adapts to window size. +- **Keyboard navigation & accessibility**: labels on all interactive elements. + +### Settings -- **Webcam Profissional (4K/HD)**: Use a qualidade total do sensor da sua câmera em Zoom, Teams, Google Meet, OBS Studio e Skype. -- **Detecção Automática**: Conecte via USB e o BigCam detecta o modelo e as capacidades da sua câmera instantaneamente. -- **Fotografia Remota**: Capture imagens diretamente do computador com pré-visualização em tempo real e download automático. -- **Alta Performance**: Pipeline otimizado com FFmpeg e GStreamer para garantir o menor atraso (latency) possível. -- **Interface Libadwaita**: Design moderno, limpo e totalmente compatível com o tema escuro/claro do sistema. -- **Suporte Multicam**: Gerencie múltiplas câmeras conectadas simultaneamente. +- Theme preference (System / Light / Dark) +- Photo and video output directories (XDG-compliant) +- Mirror preview toggle +- FPS counter overlay +- QR Scanner and Smile Capture enable/disable +- Virtual camera management +- USB hotplug auto-detection + +### Internationalization + +Translated into **29 languages**: Bulgarian, Chinese, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hebrew, Hungarian, Icelandic, Italian, Japanese, Korean, Norwegian, Polish, Portuguese, Brazilian Portuguese, Romanian, Russian, Slovak, Swedish, Turkish, Ukrainian. --- -## 📸 Câmeras Suportadas +## Supported Cameras + +### USB Webcams (V4L2) + +Virtually any USB webcam that exposes a V4L2 device will work out of the box. + +### DSLR / Mirrorless (gPhoto2) -Graças ao driver `libgphoto2`, suportamos quase todas as câmeras DSLR e Mirrorless modernas que possuem porta USB. +Thanks to [libgphoto2](http://www.gphoto.org/proj/libgphoto2/), BigCam supports 2,500+ camera models: -### Marcas Principais -- **Canon EOS**: Rebel T3, T5, T6, T7, SL2, SL3, 80D, 90D, R5, R6, M50, etc. (Suporte nativo excelente). +- **Canon EOS**: Rebel T3/T5/T6/T7, SL2/SL3, 80D/90D, R5/R6, M50, 550D, 1100D, etc. - **Nikon**: D3200, D3500, D5300, D5600, D750, Z6, Z7, etc. -- **Sony Alpha**: A6000, A6400, A7III, A7R, ZV-E10 (requer modo "PC Remote"). -- **FujiFilm**: X-T3, X-T4, X-H2S, etc. -- **Panasonic/Olympus**: Diversos modelos compatíveis com PTP. +- **Sony Alpha**: A6000, A6400, A7III, A7R, ZV-E10 (PC Remote mode required). +- **Fujifilm**: X-T3, X-T4, X-H2S. +- **Panasonic / Olympus**: various PTP-compatible models. -> 🔗 **Verifique sua câmera**: [Lista Completa de Câmeras Suportadas](http://www.gphoto.org/proj/libgphoto2/support.php) +> Full list: [libgphoto2 supported cameras](http://www.gphoto.org/proj/libgphoto2/support.php) + +### CSI / ISP (libcamera) + +Raspberry Pi cameras, Intel IPU6, and other platform cameras detected via libcamera. + +### Network (IP) + +Any RTSP or HTTP camera stream — configure the URL manually. --- -## 📦 Instalação (Arch Linux / BigLinux) +## Installation -O BigCam já inclui um instalador automatizado que configura os drivers de kernel necessários (`v4l2loopback`). +### Arch Linux / BigLinux (recommended) ```bash -# Clone o repositório -git clone https://github.com/ruscher/cannon-rebel-t3-webcam-gphoto2-ffmpeg.git -cd cannon-rebel-t3-webcam-gphoto2-ffmpeg +# Clone the repository +git clone https://github.com/biglinux/bigcam.git +cd bigcam -# Execute o instalador (Arch/BigLinux) +# Run the automated installer chmod +x script/install-archlinux.sh ./script/install-archlinux.sh ``` +The installer handles all dependencies, kernel module configuration (v4l2loopback), and sudoers rules. + +### Manual / Other Distros + +Install the dependencies: + +**Required:** +``` +python python-gobject gtk4 libadwaita gstreamer gst-plugins-base +gst-plugins-good gst-plugin-gtk4 ffmpeg v4l-utils +``` + +**Optional (for specific features):** +``` +gphoto2 # DSLR / mirrorless cameras +libcamera # CSI / ISP cameras +pipewire # PipeWire virtual cameras +v4l2loopback-dkms # Virtual camera output +x264 # Video recording (H.264) +python-opencv # Effects, QR scanner, smile capture +``` + +Then run: +```bash +cd usr/share/biglinux/bigcam +python3 main.py +``` + +### PKGBUILD + +A ready-to-use `PKGBUILD` is available in [`pkgbuild/`](pkgbuild/PKGBUILD) for building an Arch Linux package. + +--- + +## Architecture + +``` +bigcam/ +├── usr/share/biglinux/bigcam/ # Application root +│ ├── main.py # Entry point (Adw.Application) +│ ├── constants.py # App ID, version, enums +│ ├── style.css # Custom CSS overrides +│ │ +│ ├── core/ # Business logic (no UI imports) +│ │ ├── camera_manager.py # Backend registry, detection +│ │ ├── camera_profiles.py # CameraInfo / VideoFormat models +│ │ ├── stream_engine.py # GStreamer pipeline management +│ │ ├── photo_capture.py # Photo capture orchestration +│ │ ├── video_recorder.py # H.264 video recording +│ │ ├── virtual_camera.py # v4l2loopback management +│ │ └── backends/ # One module per camera type +│ │ ├── v4l2_backend.py +│ │ ├── gphoto2_backend.py +│ │ ├── libcamera_backend.py +│ │ ├── pipewire_backend.py +│ │ └── ip_backend.py +│ │ +│ ├── ui/ # GTK4 / Adwaita interface +│ │ ├── window.py # Main window (paned layout) +│ │ ├── preview_area.py # Live camera preview + effects +│ │ ├── camera_selector.py # Camera list and switcher +│ │ ├── camera_controls_page.py # Dynamic control panel +│ │ ├── effects_page.py # Effects toggle and parameters +│ │ ├── tools_page.py # QR scanner, smile capture +│ │ ├── settings_page.py # App preferences +│ │ ├── photo_gallery.py # Photo browser with delete +│ │ ├── video_gallery.py # Video browser +│ │ ├── virtual_camera_page.py # Virtual camera controls +│ │ ├── ip_camera_dialog.py # IP camera configuration +│ │ ├── qr_dialog.py # QR code result display +│ │ ├── about_dialog.py # Adw.AboutDialog +│ │ └── notification.py # Adw.Banner notifications +│ │ +│ ├── utils/ # Shared utilities +│ │ ├── i18n.py # gettext internationalisation +│ │ ├── settings_manager.py # JSON config persistence +│ │ ├── async_worker.py # Background thread helper +│ │ ├── dependency_checker.py # Runtime dependency checks +│ │ └── xdg.py # XDG directory helpers +│ │ +│ ├── script/ # Shell scripts +│ │ ├── run_webcam_gphoto2.sh # gPhoto2 + FFmpeg pipeline +│ │ └── install-archlinux.sh # System setup +│ │ +│ ├── icons/ # App icons (SVG) +│ └── locale/ # Translations (29 languages) +│ +├── pkgbuild/ # Arch Linux packaging +│ ├── PKGBUILD +│ └── pkgbuild.install +│ +├── etc/ # System config templates +│ ├── modprobe.d/v4l2loopback.conf +│ └── sudoers.d/ +│ +└── COPYING # GPLv3 license +``` + +### Data Flow + +``` +Camera (USB/Network) + │ + ├─ V4L2 ──────────────┐ + ├─ gPhoto2 → FFmpeg ──┤ UDP (localhost) + ├─ libcamera ─────────┤ + ├─ PipeWire ──────────┤ + └─ IP (RTSP/HTTP) ────┘ + │ + GStreamer Pipeline + │ + ┌───────────┼───────────┐ + │ │ │ + GTK4 Preview Effects v4l2loopback + (Paintable) (OpenCV) (Virtual Cam) + │ │ │ + └───────────┼───────────┘ + │ + ┌──────┴──────┐ + │ │ + Video Recorder Photo Capture + (x264 → MKV) (JPEG → XDG) +``` + +--- + +## Configuration + +BigCam stores its configuration following the XDG Base Directory Specification: + +| Path | Content | +|------|---------| +| `~/.config/bigcam/settings.json` | User preferences | +| `~/Pictures/BigCam/` | Captured photos (default) | +| `~/Videos/BigCam/` | Recorded videos (default) | +| `~/.cache/bigcam/` | Temporary files | + --- -## 🛠 Arquitetura do Projeto +## Troubleshooting + +### Camera not detected (gPhoto2) + +GVFS may be claiming the camera. BigCam handles this automatically, but if you still have issues: -O projeto segue os padrões de desenvolvimento do BigLinux, inspirado na estrutura do `biglinux-settings`. +```bash +systemctl --user stop gvfs-gphoto2-volume-monitor.service +systemctl --user mask gvfs-gphoto2-volume-monitor.service +pkill -9 gvfsd-gphoto2 +``` + +### PTP Timeout (DSLR) + +The camera may be in the wrong mode. Ensure it is: +- Turned **on** and connected via USB +- Set to **M** (Manual) or **P** (Program) mode +- Not in **Video** mode (some cameras lock PTP in video mode) +- Not in **sleep/auto-off** mode + +### Virtual camera not appearing +The v4l2loopback kernel module must be loaded: + +```bash +sudo modprobe v4l2loopback devices=4 exclusive_caps=1 ``` -. -├── main.py # Entry point da aplicação -├── script/ # Scripts de sistema (Shell) -│ ├── run_webcam.sh # Gestão do pipeline FFmpeg/GPhoto2 -│ └── install-archlinux.sh # Script de setup e drivers -├── utils/ # Módulos Python auxiliares -│ └── i18n.py # Suporte a Internacionalização -├── locale/ # Arquivos de tradução (gettext) -└── etc/ # Configurações de sistema (sudoers/modprobe) + +### Permissions + +If `fuser` or `pkill` fails with "Operation not permitted", ensure your user is in the `video` group: + +```bash +sudo usermod -aG video $USER ``` --- -## 🤝 Contribuições +## Contributing + +BigCam is part of the [BigLinux](https://www.biglinux.com.br/) ecosystem. + +**Original creators:** +- **Rafael Ruscher** ([@ruscher](https://github.com/ruscher)) +- **Barnabé di Kartola** + +Contributions are welcome! Please open an issue or pull request on [GitHub](https://github.com/biglinux/bigcam). + +### Translating -Este projeto é parte integrante do esforço da comunidade **BigLinux** para fornecer ferramentas de alta qualidade para usuários Linux. +Translation files are in `locale/` using gettext PO format. To add or update a translation: -**Desenvolvedores Originais:** -- Rafael Ruscher ([@ruscher](https://github.com/ruscher)) -- Barnabé di Kartola +1. Copy an existing `.po` file and rename it to your language code +2. Translate the strings +3. Submit a pull request --- -## ⚖️ Licença +## License -Este projeto está licenciado sob a **GPLv3** (General Public License v3). Sendo software livre, você é encorajado a usar, modificar e distribuir. +This project is licensed under the **GNU General Public License v3.0** — see [COPYING](COPYING) for the full text. + +``` +BigCam — Universal webcam control center for Linux +Copyright (C) 2026 BigLinux Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. +``` --- -*© 2026 BigLinux Team* + +

Made with care for the Linux desktop community

diff --git a/big_digicam/etc/modprobe.d/v4l2loopback.conf b/big_digicam/etc/modprobe.d/v4l2loopback.conf new file mode 100644 index 0000000..85f28a8 --- /dev/null +++ b/big_digicam/etc/modprobe.d/v4l2loopback.conf @@ -0,0 +1,14 @@ +# v4l2loopback configuration for BigCam +# exclusive_caps=1 allows WebRTC apps (Chrome, Google Meet, Zoom) to detect the camera +# +# Parameters: +# devices=2 - Create 2 virtual video devices (sharing + gphoto2) +# exclusive_caps=1 - Allow browsers/WebRTC apps to see the camera +# max_buffers=4 - Buffer size for smooth streaming +# video_nr=10,11 - Use /dev/video10 and /dev/video11 +# card_label - Friendly name shown in apps +# +# To apply: sudo modprobe -r v4l2loopback && sudo modprobe v4l2loopback +# Or copy to /etc/modprobe.d/ for persistence + +options v4l2loopback devices=2 exclusive_caps=1 max_buffers=4 video_nr=10,11 card_label="BigCam Virtual","BigCam Virtual (v4l2)" diff --git a/etc/modprobe.d/v4l2loopback.conf b/etc/modprobe.d/v4l2loopback.conf index cc81575..85f28a8 100644 --- a/etc/modprobe.d/v4l2loopback.conf +++ b/etc/modprobe.d/v4l2loopback.conf @@ -1,4 +1,4 @@ -# v4l2loopback configuration for Big Digicam +# v4l2loopback configuration for BigCam # exclusive_caps=1 allows WebRTC apps (Chrome, Google Meet, Zoom) to detect the camera # # Parameters: @@ -11,4 +11,4 @@ # To apply: sudo modprobe -r v4l2loopback && sudo modprobe v4l2loopback # Or copy to /etc/modprobe.d/ for persistence -options v4l2loopback devices=2 exclusive_caps=1 max_buffers=4 video_nr=10,11 card_label="Big Digicam Virtual Camera","Big Digicam Virtual Camera (v4l2)" +options v4l2loopback devices=2 exclusive_caps=1 max_buffers=4 video_nr=10,11 card_label="BigCam Virtual","BigCam Virtual (v4l2)" diff --git a/usr/share/biglinux/bigcam/core/effects.py b/usr/share/biglinux/bigcam/core/effects.py index 71b10ad..501ef5d 100644 --- a/usr/share/biglinux/bigcam/core/effects.py +++ b/usr/share/biglinux/bigcam/core/effects.py @@ -271,7 +271,7 @@ def _register_effects() -> None: (EffectInfo( effect_id="clahe", name="CLAHE (Adaptive Contrast)", - icon="image-adjust-contrast-symbolic", + icon="image-adjust-contrast", category=EffectCategory.ADJUST, params=[ EffectParam("clip_limit", "Clip Limit", 1.0, 10.0, 2.0, 0.5), @@ -333,7 +333,7 @@ def _register_effects() -> None: (EffectInfo( effect_id="grayscale", name="Grayscale", - icon="image-missing-symbolic", + icon="bwtonal", category=EffectCategory.ARTISTIC, ), _apply_grayscale), diff --git a/usr/share/biglinux/bigcam/core/virtual_camera.py b/usr/share/biglinux/bigcam/core/virtual_camera.py index 7c2427b..abf99f2 100644 --- a/usr/share/biglinux/bigcam/core/virtual_camera.py +++ b/usr/share/biglinux/bigcam/core/virtual_camera.py @@ -60,7 +60,7 @@ def load_module(cls, card_label: str | None = None) -> bool: Device 10: BigCam virtual camera output (for sharing) Device 11: Reserved for gPhoto2 streaming """ - label = card_label or "Big Digicam Virtual Camera" + label = card_label or "BigCam Virtual" safe_label = label.replace('"', '').replace('\\', '') try: subprocess.run( diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/accessories-text-editor-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/accessories-text-editor-symbolic.svg new file mode 100644 index 0000000..85b0ddc --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/accessories-text-editor-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/adjustlevels.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/adjustlevels.svg new file mode 100644 index 0000000..4822878 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/adjustlevels.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/audio-volume-muted-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/audio-volume-muted-symbolic.svg new file mode 120000 index 0000000..157d72e --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/audio-volume-muted-symbolic.svg @@ -0,0 +1 @@ +audio-volume-muted.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/audio-volume-muted.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/audio-volume-muted.svg new file mode 100644 index 0000000..c5b9014 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/audio-volume-muted.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/bwtonal-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/bwtonal-symbolic.svg new file mode 120000 index 0000000..489b2ad --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/bwtonal-symbolic.svg @@ -0,0 +1 @@ +bwtonal.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/bwtonal.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/bwtonal.svg new file mode 100644 index 0000000..300d22e --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/bwtonal.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/call-start-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/call-start-symbolic.svg new file mode 120000 index 0000000..93fe29a --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/call-start-symbolic.svg @@ -0,0 +1 @@ +call-start.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/call-start.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/call-start.svg new file mode 100644 index 0000000..2b0ee6c --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/call-start.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/color-select-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/color-select-symbolic.svg new file mode 120000 index 0000000..1f41e7e --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/color-select-symbolic.svg @@ -0,0 +1 @@ +color-select.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/color-select.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/color-select.svg new file mode 100644 index 0000000..1bd3c2a --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/color-select.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/configure.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/configure.svg new file mode 100644 index 0000000..18d9c28 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/configure.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/contact-new-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/contact-new-symbolic.svg new file mode 120000 index 0000000..f8389fb --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/contact-new-symbolic.svg @@ -0,0 +1 @@ +contact-new.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/contact-new.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/contact-new.svg new file mode 100644 index 0000000..d6ccbfe --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/contact-new.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-error-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-error-symbolic.svg new file mode 120000 index 0000000..3b41d91 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-error-symbolic.svg @@ -0,0 +1 @@ +dialog-error.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-error.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-error.svg new file mode 100644 index 0000000..8030f24 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-error.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-information-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-information-symbolic.svg new file mode 120000 index 0000000..015e95b --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-information-symbolic.svg @@ -0,0 +1 @@ +dialog-information.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-information.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-information.svg new file mode 100644 index 0000000..e37ef61 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-information.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-warning-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-warning-symbolic.svg new file mode 120000 index 0000000..a626e0c --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-warning-symbolic.svg @@ -0,0 +1 @@ +dialog-warning.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-warning.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-warning.svg new file mode 100644 index 0000000..947acd6 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/dialog-warning.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/document-save-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/document-save-symbolic.svg new file mode 120000 index 0000000..e2277db --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/document-save-symbolic.svg @@ -0,0 +1 @@ +document-save.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/document-save.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/document-save.svg new file mode 100644 index 0000000..6fed9e1 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/document-save.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/draw-watercolor.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/draw-watercolor.svg new file mode 100644 index 0000000..7d45b52 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/draw-watercolor.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-copy-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-copy-symbolic.svg new file mode 120000 index 0000000..d423a33 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-copy-symbolic.svg @@ -0,0 +1 @@ +edit-copy.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-copy.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-copy.svg new file mode 100644 index 0000000..58d1e55 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-copy.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-select-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-select-symbolic.svg new file mode 120000 index 0000000..925eb22 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-select-symbolic.svg @@ -0,0 +1 @@ +edit-select.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-select.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-select.svg new file mode 100644 index 0000000..3fc5de5 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-select.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-undo-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-undo-symbolic.svg new file mode 120000 index 0000000..88a18b6 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-undo-symbolic.svg @@ -0,0 +1 @@ +edit-undo.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-undo.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-undo.svg new file mode 100644 index 0000000..9c258e6 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/edit-undo.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/emblem-money-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/emblem-money-symbolic.svg new file mode 120000 index 0000000..9c9625d --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/emblem-money-symbolic.svg @@ -0,0 +1 @@ +emblem-money.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/emblem-money.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/emblem-money.svg new file mode 100644 index 0000000..52ac401 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/emblem-money.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/find-location-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/find-location-symbolic.svg new file mode 120000 index 0000000..21f9f3c --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/find-location-symbolic.svg @@ -0,0 +1 @@ +find-location.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/find-location.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/find-location.svg new file mode 100644 index 0000000..bc93164 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/find-location.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/folder-open-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/folder-open-symbolic.svg new file mode 120000 index 0000000..cde3e2e --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/folder-open-symbolic.svg @@ -0,0 +1 @@ +folder-open.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/folder-open.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/folder-open.svg new file mode 100644 index 0000000..c8ab167 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/folder-open.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust-contrast-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust-contrast-symbolic.svg new file mode 120000 index 0000000..c6a0c64 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust-contrast-symbolic.svg @@ -0,0 +1 @@ +image-adjust-contrast.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust-contrast.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust-contrast.svg new file mode 100644 index 0000000..06eff90 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust-contrast.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust.svg new file mode 100644 index 0000000..4822878 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-adjust.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-filter-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-filter-symbolic.svg new file mode 120000 index 0000000..7351f47 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-filter-symbolic.svg @@ -0,0 +1 @@ +image-filter.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-filter.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-filter.svg new file mode 100644 index 0000000..d24bf73 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-filter.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-missing-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-missing-symbolic.svg new file mode 120000 index 0000000..28389ba --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-missing-symbolic.svg @@ -0,0 +1 @@ +image-missing.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-missing.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-missing.svg new file mode 100644 index 0000000..a38e148 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-missing.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-sharpen-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-sharpen-symbolic.svg new file mode 120000 index 0000000..44710fd --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-sharpen-symbolic.svg @@ -0,0 +1 @@ +image-sharpen.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-sharpen.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-sharpen.svg new file mode 100644 index 0000000..0d48ef6 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/image-sharpen.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-send-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-send-symbolic.svg new file mode 120000 index 0000000..771b1c8 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-send-symbolic.svg @@ -0,0 +1 @@ +mail-send.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-send.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-send.svg new file mode 100644 index 0000000..b280092 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-send.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-unread-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-unread-symbolic.svg new file mode 120000 index 0000000..3e375c2 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-unread-symbolic.svg @@ -0,0 +1 @@ +mail-unread.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-unread.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-unread.svg new file mode 100644 index 0000000..949d469 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/mail-unread.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-start-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-start-symbolic.svg new file mode 120000 index 0000000..1e939c9 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-start-symbolic.svg @@ -0,0 +1 @@ +media-playback-start.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-start.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-start.svg new file mode 100644 index 0000000..1657a91 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-start.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-stop-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-stop-symbolic.svg new file mode 120000 index 0000000..9718795 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-stop-symbolic.svg @@ -0,0 +1 @@ +media-playback-stop.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-stop.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-stop.svg new file mode 100644 index 0000000..56d4881 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-playback-stop.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-record-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-record-symbolic.svg new file mode 120000 index 0000000..8ca2d43 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-record-symbolic.svg @@ -0,0 +1 @@ +media-record.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-record.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-record.svg new file mode 100644 index 0000000..61ace3d --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/media-record.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/open-menu-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/open-menu-symbolic.svg new file mode 120000 index 0000000..57642f4 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/open-menu-symbolic.svg @@ -0,0 +1 @@ +open-menu.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/open-menu.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/open-menu.svg new file mode 100644 index 0000000..e626ee8 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/open-menu.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/pan-up-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/pan-up-symbolic.svg new file mode 120000 index 0000000..687a8fb --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/pan-up-symbolic.svg @@ -0,0 +1 @@ +pan-up.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/pan-up.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/pan-up.svg new file mode 100644 index 0000000..69fb954 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/pan-up.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/preferences-color-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/preferences-color-symbolic.svg new file mode 100644 index 0000000..a499d62 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/preferences-color-symbolic.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/send-to-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/send-to-symbolic.svg new file mode 120000 index 0000000..52cda52 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/send-to-symbolic.svg @@ -0,0 +1 @@ +send-to.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/send-to.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/send-to.svg new file mode 100644 index 0000000..0b2ee84 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/send-to.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-software-install-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-software-install-symbolic.svg new file mode 120000 index 0000000..7e458b8 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-software-install-symbolic.svg @@ -0,0 +1 @@ +system-software-install.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-software-install.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-software-install.svg new file mode 100644 index 0000000..3682760 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-software-install.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-users-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-users-symbolic.svg new file mode 120000 index 0000000..12ff0ec --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-users-symbolic.svg @@ -0,0 +1 @@ +system-users.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-users.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-users.svg new file mode 100644 index 0000000..19d61e3 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/system-users.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/tag-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/tag-symbolic.svg new file mode 120000 index 0000000..2bb4152 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/tag-symbolic.svg @@ -0,0 +1 @@ +tag.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/tag.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/tag.svg new file mode 100644 index 0000000..aa247bb --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/tag.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-list-images.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-list-images.svg new file mode 100644 index 0000000..7648555 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-list-images.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-list-video.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-list-video.svg new file mode 100644 index 0000000..85aac39 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-list-video.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-refresh-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-refresh-symbolic.svg new file mode 120000 index 0000000..4e680c2 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-refresh-symbolic.svg @@ -0,0 +1 @@ +view-refresh.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-refresh.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-refresh.svg new file mode 100644 index 0000000..fc1e895 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/view-refresh.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/web-browser-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/web-browser-symbolic.svg new file mode 120000 index 0000000..76b91b8 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/web-browser-symbolic.svg @@ -0,0 +1 @@ +web-browser.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/web-browser.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/web-browser.svg new file mode 100644 index 0000000..560cc4b --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/web-browser.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/window-close-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/window-close-symbolic.svg new file mode 120000 index 0000000..b943971 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/window-close-symbolic.svg @@ -0,0 +1 @@ +window-close.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/window-close.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/window-close.svg new file mode 100644 index 0000000..70b7aa5 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/actions/window-close.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/apps/bigcam.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/apps/bigcam.svg new file mode 100644 index 0000000..06f6293 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/apps/bigcam.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/categories/applications-graphics-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/categories/applications-graphics-symbolic.svg new file mode 100644 index 0000000..8736eae --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/categories/applications-graphics-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/categories/preferences-system-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/categories/preferences-system-symbolic.svg new file mode 100644 index 0000000..5336b8d --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/categories/preferences-system-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/audio-card-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/audio-card-symbolic.svg new file mode 120000 index 0000000..1de6f80 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/audio-card-symbolic.svg @@ -0,0 +1 @@ +audio-card.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/audio-card.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/audio-card.svg new file mode 100644 index 0000000..5c0a569 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/audio-card.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-photo-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-photo-symbolic.svg new file mode 120000 index 0000000..2849f93 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-photo-symbolic.svg @@ -0,0 +1 @@ +camera-photo.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-photo.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-photo.svg new file mode 100644 index 0000000..4bb79d3 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-photo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-video-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-video-symbolic.svg new file mode 120000 index 0000000..d3ef9a8 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-video-symbolic.svg @@ -0,0 +1 @@ +camera-video.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-video.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-video.svg new file mode 100644 index 0000000..27fa1e4 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-video.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-web-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-web-symbolic.svg new file mode 120000 index 0000000..a1fe883 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-web-symbolic.svg @@ -0,0 +1 @@ +camera-web.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-web.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-web.svg new file mode 100644 index 0000000..4578851 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/camera-web.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-server-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-server-symbolic.svg new file mode 120000 index 0000000..7fdd2d9 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-server-symbolic.svg @@ -0,0 +1 @@ +network-server.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-server.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-server.svg new file mode 100644 index 0000000..fb0558c --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-server.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-wireless-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-wireless-symbolic.svg new file mode 120000 index 0000000..012a667 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-wireless-symbolic.svg @@ -0,0 +1 @@ +network-wireless.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-wireless.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-wireless.svg new file mode 100644 index 0000000..0176184 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/network-wireless.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/video-display-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/video-display-symbolic.svg new file mode 120000 index 0000000..a19a201 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/video-display-symbolic.svg @@ -0,0 +1 @@ +video-display.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/video-display.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/video-display.svg new file mode 100644 index 0000000..c5af0e9 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/devices/video-display.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-default-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-default-symbolic.svg new file mode 100644 index 0000000..e08b992 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-default-symbolic.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-important-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-important-symbolic.svg new file mode 100644 index 0000000..a348026 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-important-symbolic.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-ok-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-ok-symbolic.svg new file mode 100644 index 0000000..5c36d8e --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-ok-symbolic.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-photos-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-photos-symbolic.svg new file mode 100644 index 0000000..08581b7 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-photos-symbolic.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-system-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-system-symbolic.svg new file mode 100644 index 0000000..b800c9c --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/emblems/emblem-system-symbolic.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/emotes/face-laugh-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/emotes/face-laugh-symbolic.svg new file mode 100644 index 0000000..e83b9ed --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/emotes/face-laugh-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/emotes/face-smile-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/emotes/face-smile-symbolic.svg new file mode 100644 index 0000000..ab25cd7 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/emotes/face-smile-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/image-x-generic-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/image-x-generic-symbolic.svg new file mode 100644 index 0000000..ef66b7f --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/image-x-generic-symbolic.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/text-x-generic-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/text-x-generic-symbolic.svg new file mode 100644 index 0000000..11795be --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/text-x-generic-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/video-x-generic-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/video-x-generic-symbolic.svg new file mode 100644 index 0000000..5bdb4b8 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/video-x-generic-symbolic.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/x-office-calendar-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/x-office-calendar-symbolic.svg new file mode 100644 index 0000000..2aac276 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/mimetypes/x-office-calendar-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/places/user-trash-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/places/user-trash-symbolic.svg new file mode 120000 index 0000000..a5a5bd8 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/places/user-trash-symbolic.svg @@ -0,0 +1 @@ +user-trash.svg \ No newline at end of file diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/places/user-trash.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/places/user-trash.svg new file mode 100644 index 0000000..8e0d22a --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/places/user-trash.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/status/channel-secure-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/status/channel-secure-symbolic.svg new file mode 100644 index 0000000..e12554e --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/status/channel-secure-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/status/display-brightness-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/status/display-brightness-symbolic.svg new file mode 100644 index 0000000..e9b7707 --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/status/display-brightness-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/usr/share/biglinux/bigcam/img/hicolor/scalable/status/weather-clear-symbolic.svg b/usr/share/biglinux/bigcam/img/hicolor/scalable/status/weather-clear-symbolic.svg new file mode 100644 index 0000000..a45570b --- /dev/null +++ b/usr/share/biglinux/bigcam/img/hicolor/scalable/status/weather-clear-symbolic.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/usr/share/biglinux/bigcam/main.py b/usr/share/biglinux/bigcam/main.py index 418fc0d..c36c101 100644 --- a/usr/share/biglinux/bigcam/main.py +++ b/usr/share/biglinux/bigcam/main.py @@ -44,11 +44,14 @@ def do_startup(self) -> None: from gi.repository import Gtk, Gdk - # Register app icon in theme search path - icons_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "icons") - if os.path.isdir(icons_dir): - icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()) - icon_theme.add_search_path(icons_dir) + # Register local icon directories (prepend so they take priority) + base_dir = os.path.dirname(os.path.realpath(__file__)) + icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()) + img_dir = os.path.join(base_dir, "img") + icons_dir = os.path.join(base_dir, "icons") + existing = list(icon_theme.get_search_path()) + prepend = [d for d in (img_dir, icons_dir) if os.path.isdir(d)] + icon_theme.set_search_path(prepend + existing) # Load CSS css_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "style.css") diff --git a/usr/share/biglinux/bigcam/script/run_webcam.sh b/usr/share/biglinux/bigcam/script/run_webcam.sh index e21c30f..303554e 100755 --- a/usr/share/biglinux/bigcam/script/run_webcam.sh +++ b/usr/share/biglinux/bigcam/script/run_webcam.sh @@ -6,7 +6,7 @@ UDP_PORT="${2:-5000}" CAM_NAME="${3:-Canon DSLR}" # Remove commas to prevent modprobe array parsing errors CAM_NAME="${CAM_NAME//,/}" -CARD_LABELS="${CAM_NAME} (v4l2),${CAM_NAME} 2 (v4l2),${CAM_NAME} 3 (v4l2),${CAM_NAME} 4 (v4l2)" +CARD_LABELS="BigCam Virtual,BigCam Virtual 2,BigCam Virtual 3,BigCam Virtual 4" if [ -n "$USB_PORT" ]; then diff --git a/usr/share/biglinux/bigcam/script/run_webcam_gphoto2.sh b/usr/share/biglinux/bigcam/script/run_webcam_gphoto2.sh index a20fc43..99f0b57 100755 --- a/usr/share/biglinux/bigcam/script/run_webcam_gphoto2.sh +++ b/usr/share/biglinux/bigcam/script/run_webcam_gphoto2.sh @@ -32,7 +32,7 @@ gio mount -u gphoto2://* 2>/dev/null sleep 1 # ── Step 3: Load v4l2loopback ── -CARD_LABELS="${CAM_NAME} (v4l2),${CAM_NAME} 2 (v4l2),${CAM_NAME} 3 (v4l2),${CAM_NAME} 4 (v4l2)" +CARD_LABELS="BigCam Virtual,BigCam Virtual 2,BigCam Virtual 3,BigCam Virtual 4" if ! lsmod | grep -q v4l2loopback; then bigsudo modprobe v4l2loopback devices=4 exclusive_caps=1 max_buffers=4 \ "card_label=$CARD_LABELS" diff --git a/usr/share/biglinux/bigcam/style.css b/usr/share/biglinux/bigcam/style.css index 669f113..065d2ea 100644 --- a/usr/share/biglinux/bigcam/style.css +++ b/usr/share/biglinux/bigcam/style.css @@ -31,3 +31,16 @@ .delete-thumb-btn:hover { opacity: 1; } + +/* Countdown overlay (big centered number) */ +.countdown-overlay { + font-size: 96px; + font-weight: 800; + color: white; + text-shadow: 0 2px 12px rgba(0,0,0,0.7); +} + +/* ExpanderRow arrow indicator */ +row.expander image.expander-row-arrow { + -gtk-icon-source: -gtk-icontheme("pan-up-symbolic"); +} diff --git a/usr/share/biglinux/bigcam/ui/effects_page.py b/usr/share/biglinux/bigcam/ui/effects_page.py index 5a3187c..2c04af4 100644 --- a/usr/share/biglinux/bigcam/ui/effects_page.py +++ b/usr/share/biglinux/bigcam/ui/effects_page.py @@ -108,25 +108,43 @@ def _make_reset_button(self, cat: EffectCategory, def _add_effect_rows(self, group: Adw.PreferencesGroup, effect: EffectInfo) -> None: - # Toggle row for the effect - toggle_row = Adw.SwitchRow( - title=effect.name, - subtitle=effect.description if hasattr(effect, "description") else "", - ) - if effect.icon: - toggle_row.set_icon_name(effect.icon) - toggle_row.set_active(effect.enabled) - toggle_row.update_property( - [Gtk.AccessibleProperty.LABEL], [effect.name], - ) - toggle_row.connect("notify::active", self._on_toggle, effect) - group.add(toggle_row) - - # Parameter rows (always visible) if effect.params: + # ExpanderRow with independent switch as suffix + expander = Adw.ExpanderRow( + title=effect.name, + subtitle=effect.description if hasattr(effect, "description") else "", + ) + if effect.icon: + expander.set_icon_name(effect.icon) + expander.update_property( + [Gtk.AccessibleProperty.LABEL], [effect.name], + ) + # Add switch as suffix (independent of expansion) + switch = Gtk.Switch() + switch.set_active(effect.enabled) + switch.set_valign(Gtk.Align.CENTER) + switch.connect("notify::active", self._on_switch_toggle, effect) + expander.add_suffix(switch) + # Replace internal arrow icon + self._replace_arrow_icon(expander, "pan-up-symbolic") for param in effect.params: param_row = self._make_param_row(effect, param) - group.add(param_row) + expander.add_row(param_row) + group.add(expander) + else: + # Simple toggle for effects without parameters + toggle_row = Adw.SwitchRow( + title=effect.name, + subtitle=effect.description if hasattr(effect, "description") else "", + ) + if effect.icon: + toggle_row.set_icon_name(effect.icon) + toggle_row.set_active(effect.enabled) + toggle_row.update_property( + [Gtk.AccessibleProperty.LABEL], [effect.name], + ) + toggle_row.connect("notify::active", self._on_toggle, effect) + group.add(toggle_row) def _make_param_row(self, effect: EffectInfo, param: EffectParam) -> Adw.ActionRow: row = Adw.ActionRow(title=param.label) @@ -169,6 +187,25 @@ def _on_toggle(self, row: Adw.SwitchRow, _pspec: Any, self._pipeline.set_enabled(effect.effect_id, enabled) self.emit("effect-changed") + def _on_switch_toggle(self, switch: Gtk.Switch, _pspec: Any, + effect: EffectInfo) -> None: + enabled = switch.get_active() + effect.enabled = enabled + self._pipeline.set_enabled(effect.effect_id, enabled) + self.emit("effect-changed") + + @staticmethod + def _replace_arrow_icon(widget: Gtk.Widget, icon_name: str) -> None: + """Walk the ExpanderRow widget tree and replace the arrow icon.""" + child = widget.get_first_child() + while child: + if isinstance(child, Gtk.Image): + if "expander-row-arrow" in (child.get_css_classes() or []): + child.set_from_icon_name(icon_name) + return + EffectsPage._replace_arrow_icon(child, icon_name) + child = child.get_next_sibling() + def _on_param_changed(self, adj: Gtk.Adjustment, effect: EffectInfo, param: EffectParam) -> None: key = f"{effect.effect_id}_{param.name}" diff --git a/usr/share/biglinux/bigcam/ui/preview_area.py b/usr/share/biglinux/bigcam/ui/preview_area.py index e9bb418..315191d 100644 --- a/usr/share/biglinux/bigcam/ui/preview_area.py +++ b/usr/share/biglinux/bigcam/ui/preview_area.py @@ -30,6 +30,7 @@ def __init__(self, stream_engine: StreamEngine) -> None: self._fps_timer: int | None = None self._show_fps: bool = True self._last_error: str = "" + self._progress_pulse_id: int | None = None self.add_css_class("preview-area") @@ -80,8 +81,16 @@ def __init__(self, stream_engine: StreamEngine) -> None: self._banner.set_revealed(False) self._banner_timeout: int | None = None - # Pack banner + toast_overlay vertically + # -- progress bar (top, thin, loading indicator) --------------------- + self._top_progress = Gtk.ProgressBar() + self._top_progress.add_css_class("osd") + self._top_progress.set_halign(Gtk.Align.FILL) + self._top_progress.set_hexpand(True) + self._top_progress.set_visible(False) + + # Pack progress + banner + toast_overlay vertically content_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + content_box.append(self._top_progress) content_box.append(self._banner) content_box.append(self._toast_overlay) self._toast_overlay.set_vexpand(True) @@ -105,6 +114,26 @@ def __init__(self, stream_engine: StreamEngine) -> None: self._toolbar.set_margin_bottom(16) self.add_overlay(self._toolbar) + # -- countdown label (big centered number) -------------------------- + self._countdown_label = Gtk.Label(label="") + self._countdown_label.add_css_class("countdown-overlay") + self._countdown_label.set_halign(Gtk.Align.CENTER) + self._countdown_label.set_valign(Gtk.Align.CENTER) + self._countdown_label.set_visible(False) + self.add_overlay(self._countdown_label) + self._countdown_timer_id: int | None = None + + # -- grid overlay (rule-of-thirds) ---------------------------------- + self._grid_drawing = Gtk.DrawingArea() + self._grid_drawing.set_draw_func(self._draw_grid) + self._grid_drawing.set_halign(Gtk.Align.FILL) + self._grid_drawing.set_valign(Gtk.Align.FILL) + self._grid_drawing.set_hexpand(True) + self._grid_drawing.set_vexpand(True) + self._grid_drawing.set_can_target(False) + self._grid_drawing.set_visible(False) + self.add_overlay(self._grid_drawing) + # -- engine signals -------------------------------------------------- self._engine.connect("state-changed", self._on_state_changed) self._engine.connect("error", self._on_error) @@ -151,6 +180,7 @@ def _build_floating_toolbar(self) -> Gtk.Box: def _on_state_changed(self, _engine: StreamEngine, state: str) -> None: if state == "playing": + self._stop_progress_pulse() paintable = self._engine.paintable if paintable: self._picture.set_paintable(paintable) @@ -214,10 +244,12 @@ def notification(self) -> "PreviewArea": ``preview.notification.notify_user(...)`` keeps working.""" return self - def notify_user(self, message: str, level: str = "info", timeout_ms: int = 3000) -> None: + def notify_user(self, message: str, level: str = "info", timeout_ms: int = 3000, + progress: bool = False) -> None: """Show a banner at the top of the preview area. If *timeout_ms* is 0, the banner stays until ``dismiss()`` is called. + If *progress* is True, show the pulsing progress bar at top. """ if self._banner_timeout is not None: GLib.source_remove(self._banner_timeout) @@ -226,9 +258,12 @@ def notify_user(self, message: str, level: str = "info", timeout_ms: int = 3000) self._banner.set_title(message) self._banner.set_revealed(True) - # Show spinner on status page for persistent info messages (loading) - if timeout_ms == 0 and level == "info": - self._show_loading(message) + if progress: + self._stop_progress_pulse() + self._top_progress.set_visible(True) + self._progress_pulse_id = GLib.timeout_add(80, self._pulse_progress) + else: + self._stop_progress_pulse() if timeout_ms > 0: self._banner_timeout = GLib.timeout_add( @@ -236,21 +271,39 @@ def notify_user(self, message: str, level: str = "info", timeout_ms: int = 3000) ) def _show_loading(self, message: str) -> None: - self._status.set_title(message) - self._status.set_description("") - self._status.set_icon_name("") - spinner = Gtk.Spinner(spinning=True, width_request=48, height_request=48) - spinner.set_halign(Gtk.Align.CENTER) - self._status.set_child(spinner) + self._status.set_icon_name("camera-web-symbolic") + self._status.set_title(_("Please wait…")) + self._status.set_description(message) + self._status.set_child(None) self._retry_btn.set_visible(False) self._stack.set_visible_child_name("status") + # Show pulsing progress bar at the top + self._stop_progress_pulse() + self._top_progress.set_visible(True) + self._progress_pulse_id = GLib.timeout_add(80, self._pulse_progress) + + def _pulse_progress(self) -> bool: + if self._top_progress.get_visible(): + self._top_progress.pulse() + return True + self._progress_pulse_id = None + return False + + def _stop_progress_pulse(self) -> None: + tid = self._progress_pulse_id + self._progress_pulse_id = None + if tid is not None: + GLib.source_remove(tid) + self._top_progress.set_visible(False) + def dismiss(self) -> None: """Hide the banner and restore status page.""" if self._banner_timeout is not None: GLib.source_remove(self._banner_timeout) self._banner_timeout = None self._banner.set_revealed(False) + self._stop_progress_pulse() # Restore status page defaults after loading self._status.set_icon_name("camera-web-symbolic") self._status.set_child(self._retry_btn) @@ -261,7 +314,12 @@ def _auto_dismiss_banner(self) -> bool: return GLib.SOURCE_REMOVE def show_status(self, title: str, description: str = "", - icon: str = "camera-web-symbolic") -> None: + icon: str = "camera-web-symbolic", + loading: bool = False) -> None: + if loading: + self._show_loading(description) + return + self._stop_progress_pulse() self._status.set_title(title) self._status.set_description(description) self._status.set_icon_name(icon) @@ -309,3 +367,54 @@ def set_recording_state(self, recording: bool) -> None: self._record_btn.set_icon_name("media-record-symbolic") self._record_btn.remove_css_class("destructive-action") self._record_btn.set_tooltip_text(_("Record video")) + + # -- grid overlay -------------------------------------------------------- + + def set_grid_visible(self, visible: bool) -> None: + self._grid_drawing.set_visible(visible) + + def _draw_grid(self, area: Gtk.DrawingArea, cr, width: int, height: int) -> None: + """Draw rule-of-thirds grid lines.""" + cr.set_source_rgba(1.0, 1.0, 1.0, 0.4) + cr.set_line_width(1.0) + # Vertical lines at 1/3 and 2/3 + for i in (1, 2): + x = width * i / 3 + cr.move_to(x, 0) + cr.line_to(x, height) + # Horizontal lines at 1/3 and 2/3 + for i in (1, 2): + y = height * i / 3 + cr.move_to(0, y) + cr.line_to(width, y) + cr.stroke() + + # -- countdown timer ----------------------------------------------------- + + def start_countdown(self, seconds: int, callback) -> None: + """Show a countdown overlay, then call *callback* when it reaches 0.""" + self._cancel_countdown() + self._countdown_remaining = seconds + self._countdown_callback = callback + self._countdown_label.set_label(str(seconds)) + self._countdown_label.set_visible(True) + self._countdown_timer_id = GLib.timeout_add(1000, self._tick_countdown) + + def _tick_countdown(self) -> bool: + self._countdown_remaining -= 1 + if self._countdown_remaining > 0: + self._countdown_label.set_label(str(self._countdown_remaining)) + return True + self._countdown_label.set_visible(False) + self._countdown_timer_id = None + if self._countdown_callback: + self._countdown_callback() + self._countdown_callback = None + return False + + def _cancel_countdown(self) -> None: + if self._countdown_timer_id is not None: + GLib.source_remove(self._countdown_timer_id) + self._countdown_timer_id = None + self._countdown_label.set_visible(False) + self._countdown_callback = None diff --git a/usr/share/biglinux/bigcam/ui/settings_page.py b/usr/share/biglinux/bigcam/ui/settings_page.py index db898b4..30ad2c9 100644 --- a/usr/share/biglinux/bigcam/ui/settings_page.py +++ b/usr/share/biglinux/bigcam/ui/settings_page.py @@ -35,6 +35,12 @@ class SettingsPage(Gtk.ScrolledWindow): "smile-captured": (GObject.SignalFlags.RUN_LAST, None, (str,)), "qr-detected": (GObject.SignalFlags.RUN_LAST, None, (str,)), "virtual-camera-toggled": (GObject.SignalFlags.RUN_LAST, None, (bool,)), + "resolution-changed": (GObject.SignalFlags.RUN_LAST, None, (str,)), + "fps-limit-changed": (GObject.SignalFlags.RUN_LAST, None, (int,)), + "grid-overlay-changed": (GObject.SignalFlags.RUN_LAST, None, (bool,)), + "resolution-changed": (GObject.SignalFlags.RUN_LAST, None, (str,)), + "fps-limit-changed": (GObject.SignalFlags.RUN_LAST, None, (int,)), + "grid-overlay-changed": (GObject.SignalFlags.RUN_LAST, None, (bool,)), } def __init__(self, settings: SettingsManager, stream_engine=None) -> None: @@ -153,8 +159,69 @@ def _build_preview(self, content: Gtk.Box) -> None: show_fps_row.connect("notify::active", self._on_show_fps) preview.add(show_fps_row) + grid_row = Adw.SwitchRow( + title=_("Grid overlay"), + subtitle=_("Show a rule-of-thirds grid over the preview."), + ) + grid_row.set_active(self._settings.get("grid_overlay")) + grid_row.connect("notify::active", self._on_grid_overlay) + preview.add(grid_row) + content.append(preview) + # -- Camera group (resolution, FPS, timer) --------------------------- + camera_group = Adw.PreferencesGroup(title=_("Camera")) + + # Resolution + self._res_combo = Adw.ComboRow(title=_("Resolution")) + res_model = Gtk.StringList() + for label in (_("Auto"), "640×480", "1280×720", "1920×1080", "3840×2160"): + res_model.append(label) + self._res_combo.set_model(res_model) + _RES_VALUES = ["", "480", "720", "1080", "2160"] + current_res = self._settings.get("preferred-resolution") + try: + self._res_combo.set_selected(_RES_VALUES.index(current_res)) + except ValueError: + self._res_combo.set_selected(0) + self._res_combo.connect("notify::selected", self._on_resolution) + camera_group.add(self._res_combo) + + # FPS limit + self._fps_combo = Adw.ComboRow(title=_("FPS limit")) + fps_model = Gtk.StringList() + for label in (_("Auto"), "15", "24", "30", "60"): + fps_model.append(label) + self._fps_combo.set_model(fps_model) + _FPS_VALUES = [0, 15, 24, 30, 60] + current_fps = self._settings.get("fps-limit") + try: + self._fps_combo.set_selected(_FPS_VALUES.index(current_fps)) + except ValueError: + self._fps_combo.set_selected(0) + self._fps_combo.connect("notify::selected", self._on_fps_limit) + camera_group.add(self._fps_combo) + + # Capture timer + timer_row = Adw.ComboRow( + title=_("Capture timer"), + subtitle=_("Countdown before taking a photo."), + ) + timer_model = Gtk.StringList() + for label in (_("Off"), "3s", "5s", "10s"): + timer_model.append(label) + timer_row.set_model(timer_model) + _TIMER_VALUES = [0, 3, 5, 10] + current_timer = self._settings.get("capture-timer") + try: + timer_row.set_selected(_TIMER_VALUES.index(current_timer)) + except ValueError: + timer_row.set_selected(0) + timer_row.connect("notify::selected", self._on_capture_timer) + camera_group.add(timer_row) + + content.append(camera_group) + def _build_advanced(self, content: Gtk.Box) -> None: advanced = Adw.PreferencesGroup(title=_("Advanced")) @@ -266,6 +333,31 @@ def _on_show_fps(self, row: Adw.SwitchRow, _pspec) -> None: def _on_hotplug(self, row: Adw.SwitchRow, _pspec) -> None: self._settings.set("hotplug_enabled", row.get_active()) + def _on_resolution(self, row: Adw.ComboRow, _pspec) -> None: + _RES_VALUES = ["", "480", "720", "1080", "2160"] + idx = row.get_selected() + value = _RES_VALUES[idx] if idx < len(_RES_VALUES) else "" + self._settings.set("preferred-resolution", value) + self.emit("resolution-changed", value) + + def _on_fps_limit(self, row: Adw.ComboRow, _pspec) -> None: + _FPS_VALUES = [0, 15, 24, 30, 60] + idx = row.get_selected() + value = _FPS_VALUES[idx] if idx < len(_FPS_VALUES) else 0 + self._settings.set("fps-limit", value) + self.emit("fps-limit-changed", value) + + def _on_capture_timer(self, row: Adw.ComboRow, _pspec) -> None: + _TIMER_VALUES = [0, 3, 5, 10] + idx = row.get_selected() + value = _TIMER_VALUES[idx] if idx < len(_TIMER_VALUES) else 0 + self._settings.set("capture-timer", value) + + def _on_grid_overlay(self, row: Adw.SwitchRow, _pspec) -> None: + active = row.get_active() + self._settings.set("grid_overlay", active) + self.emit("grid-overlay-changed", active) + @staticmethod def _open_directory(path: str) -> None: import subprocess diff --git a/usr/share/biglinux/bigcam/ui/window.py b/usr/share/biglinux/bigcam/ui/window.py index 98d14d6..67d8b19 100644 --- a/usr/share/biglinux/bigcam/ui/window.py +++ b/usr/share/biglinux/bigcam/ui/window.py @@ -119,6 +119,7 @@ def _build_ui(self) -> None: # LEFT: preview self._preview = PreviewArea(self._stream_engine) self._preview.set_show_fps(self._settings.get("show_fps")) + self._preview.set_grid_visible(self._settings.get("grid_overlay")) self._paned.set_start_child(self._preview) # RIGHT: sidebar with ViewStack @@ -133,28 +134,28 @@ def _build_ui(self) -> None: self._controls_page = CameraControlsPage(self._camera_manager) self._view_stack.add_titled_with_icon( self._controls_page, "controls", - _("Controls"), "emblem-system-symbolic", + _("Controls"), "adjustlevels", ) # Effects page self._effects_page = EffectsPage(self._stream_engine.effects) self._view_stack.add_titled_with_icon( self._effects_page, "effects", - _("Effects"), "color-select-symbolic", + _("Effects"), "draw-watercolor", ) # Photo gallery page self._gallery = PhotoGallery() self._view_stack.add_titled_with_icon( self._gallery, "gallery", - _("Photos"), "image-x-generic-symbolic", + _("Photos"), "view-list-images", ) # Video gallery page self._video_gallery = VideoGallery() self._view_stack.add_titled_with_icon( self._video_gallery, "videos", - _("Videos"), "video-x-generic-symbolic", + _("Videos"), "view-list-video", ) # Settings page (includes Tools and Virtual Camera) @@ -162,6 +163,9 @@ def _build_ui(self) -> None: self._settings_page.connect("smile-captured", self._on_smile_captured) self._settings_page.connect("qr-detected", self._on_qr_detected) self._settings_page.connect("virtual-camera-toggled", self._on_virtual_camera_toggled) + self._settings_page.connect("resolution-changed", self._on_resolution_changed) + self._settings_page.connect("fps-limit-changed", self._on_fps_limit_changed) + self._settings_page.connect("grid-overlay-changed", self._on_grid_overlay_changed) # Restore virtual camera enabled state from settings if self._settings.get("virtual-camera-enabled"): @@ -170,7 +174,7 @@ def _build_ui(self) -> None: self._view_stack.add_titled_with_icon( self._settings_page, "settings", - _("Settings"), "preferences-system-symbolic", + _("Settings"), "configure", ) switcher = Adw.ViewSwitcherBar(stack=self._view_stack, reveal=True) @@ -251,8 +255,60 @@ def _connect_signals(self) -> None: # Cache controls per camera to avoid PTP re-access _controls_cache: dict[str, list] = {} + def _pick_preferred_format(self, camera: CameraInfo): + """Return a VideoFormat matching user resolution/FPS preferences, or None.""" + from core.camera_backend import VideoFormat + + res_pref = self._settings.get("preferred-resolution") # "" / "480" / "720" / "1080" / "2160" + fps_pref = self._settings.get("fps-limit") # 0=auto / 15 / 24 / 30 / 60 + + if not res_pref and not fps_pref: + return None # auto + + if not camera.formats: + return None + + _RES_MAP = {"480": 480, "720": 720, "1080": 1080, "2160": 2160} + target_h = _RES_MAP.get(res_pref, 0) + + candidates = camera.formats + if target_h: + # Find formats matching the target height + exact = [f for f in candidates if f.height == target_h] + if exact: + candidates = exact + else: + # Pick closest height + candidates = sorted(candidates, key=lambda f: abs(f.height - target_h)) + closest_h = candidates[0].height + candidates = [f for f in candidates if f.height == closest_h] + + if fps_pref and fps_pref > 0: + # Filter formats that support the desired FPS (or closest) + best = None + for fmt in candidates: + if fps_pref in fmt.fps or any(f >= fps_pref for f in fmt.fps): + best = fmt + break + if best is None and candidates: + best = candidates[0] + if best is not None: + # Create a copy with fps capped to the preference + capped_fps = [f for f in best.fps if f <= fps_pref] + if not capped_fps: + capped_fps = best.fps + return VideoFormat( + width=best.width, height=best.height, + fps=capped_fps, pixel_format=best.pixel_format, + description=best.description, + ) + return None + + return candidates[0] if candidates else None + def _on_camera_selected(self, _selector: CameraSelector, camera: CameraInfo) -> None: self._active_camera = camera + self._settings.set("last-camera-id", camera.id) title_widget = self._header.get_title_widget() if isinstance(title_widget, Adw.WindowTitle): title_widget.set_subtitle(camera.name) @@ -292,8 +348,10 @@ def _on_camera_selected(self, _selector: CameraSelector, camera: CameraInfo) -> # Stop only the GStreamer pipeline, keep other cameras' backend alive self._stream_engine.stop(stop_backend=False) - self._preview.notification.notify_user( - _("Starting camera stream…"), "info", 0 + self._preview.show_status( + _("Please wait…"), + _("Starting camera stream…"), + loading=True, ) def do_controls_then_stream() -> tuple[bool, list]: @@ -353,7 +411,8 @@ def on_done(result: tuple[bool, list]) -> None: # Start the V4L2 camera immediately self._controls_page.set_camera(camera) - self._stream_engine.play(camera) + preferred_fmt = self._pick_preferred_format(camera) + self._stream_engine.play(camera, fmt=preferred_fmt) # Stop old backend (gphoto2) in background — has time.sleep() calls if old_backend_obj and hasattr(old_backend_obj, "stop_streaming"): @@ -381,6 +440,19 @@ def _on_mirror_changed(self, _page, mirror: bool) -> None: self._stream_engine.stop() self._on_camera_selected(self._camera_selector, self._active_camera) + def _on_resolution_changed(self, _page, value: str) -> None: + if self._active_camera: + self._stream_engine.stop() + self._on_camera_selected(self._camera_selector, self._active_camera) + + def _on_fps_limit_changed(self, _page, value: int) -> None: + if self._active_camera: + self._stream_engine.stop() + self._on_camera_selected(self._camera_selector, self._active_camera) + + def _on_grid_overlay_changed(self, _page, visible: bool) -> None: + self._preview.set_grid_visible(visible) + # -- Tools signals ------------------------------------------------------- def _on_smile_captured(self, _page: Any, path: str) -> None: @@ -403,9 +475,17 @@ def _on_capture(self, _preview: PreviewArea) -> None: ) return + timer = self._settings.get("capture-timer") + if timer and timer > 0: + self._preview.start_countdown(timer, self._do_capture_after_timer) + return + + self._do_capture_after_timer() + + def _do_capture_after_timer(self) -> None: from constants import BackendType - if self._active_camera.backend == BackendType.GPHOTO2: + if self._active_camera and self._active_camera.backend == BackendType.GPHOTO2: dialog = Adw.AlertDialog.new( _("Choose capture mode"), _("You can take a screenshot from the current preview " @@ -467,6 +547,7 @@ def _do_native_capture(self) -> None: _("Please wait…"), _("Switching to photography mode."), "camera-photo-symbolic", + loading=True, ) def _capture_in_thread() -> str | None: @@ -498,6 +579,7 @@ def _on_done(result: str | None) -> None: _("Please wait…"), _("Resuming camera streaming…"), "camera-web-symbolic", + loading=True, ) self._on_camera_selected(self._camera_selector, camera) @@ -551,7 +633,7 @@ def _on_record_toggle(self, *_args) -> None: if path: self._preview.set_recording_state(True) self._preview.notification.notify_user( - _("Recording…"), "info", 0 + _("Recording…"), "info", 0, progress=True ) else: self._preview.notification.notify_user( @@ -596,9 +678,17 @@ def _on_load_profile(self, *_args) -> None: # -- auto-start preview -------------------------------------------------- def _on_cameras_changed_auto_start(self, _manager: CameraManager) -> None: - """Auto-start preview with the first camera if none is active.""" + """Auto-start preview with the last used camera, or the first available.""" if self._active_camera is None and self._camera_manager.cameras: - cam = self._camera_manager.cameras[0] + last_id = self._settings.get("last-camera-id") + cam = None + if last_id: + cam = next( + (c for c in self._camera_manager.cameras if c.id == last_id), + None, + ) + if cam is None: + cam = self._camera_manager.cameras[0] self._on_camera_selected(self._camera_selector, cam) def _on_close(self, _window: Adw.ApplicationWindow) -> bool: diff --git a/usr/share/biglinux/bigcam/utils/settings_manager.py b/usr/share/biglinux/bigcam/utils/settings_manager.py index 513e477..e782ac0 100644 --- a/usr/share/biglinux/bigcam/utils/settings_manager.py +++ b/usr/share/biglinux/bigcam/utils/settings_manager.py @@ -14,8 +14,10 @@ "sidebar-position": 420, # Preview "preferred-resolution": "", - "fps-limit": 30, + "fps-limit": 0, "mirror_preview": False, + "capture-timer": 0, + "grid_overlay": False, # Photo "photo-directory": "", "photo-format": "jpg", @@ -28,6 +30,7 @@ "theme": "system", "auto-start-preview": True, "hotplug_enabled": True, + "last-camera-id": "", # Virtual camera "virtual-camera-enabled": False, # IP Cameras (list serialised as JSON array)