Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/desktop-gpui/locales/de.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2462,6 +2462,11 @@ stereo = "Stereo"
advanced_shadow = "Erweiterte Schatteneinstellungen"
background = "Hintergrund"
corner_style = "Eckenstil"
crop = "Zuschneiden"
crop_bottom = "Unten"
crop_left = "Links"
crop_right = "Rechts"
crop_top = "Oben"
custom_position = "Eigene Position (auf der Leinwand verschoben)"
hide = "Kamera ausblenden"
keep_size_during_zoom = "Originalgröße beim Zoomen beibehalten"
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop-gpui/locales/en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2464,6 +2464,11 @@ stereo = "Stereo"
advanced_shadow = "Advanced shadow settings"
background = "Background"
corner_style = "Corner Style"
crop = "Crop"
crop_bottom = "Bottom"
crop_left = "Left"
crop_right = "Right"
crop_top = "Top"
custom_position = "Custom position (dragged on canvas)"
hide = "Hide Camera"
keep_size_during_zoom = "Keep original size during zoom"
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop-gpui/locales/es.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2462,6 +2462,11 @@ stereo = "Estéreo"
advanced_shadow = "Ajustes avanzados de sombra"
background = "Fondo"
corner_style = "Estilo de esquinas"
crop = "Recortar"
crop_bottom = "Abajo"
crop_left = "Izquierda"
crop_right = "Derecha"
crop_top = "Arriba"
custom_position = "Posición personalizada (arrastrada en el lienzo)"
hide = "Ocultar cámara"
keep_size_during_zoom = "Mantener el tamaño original durante el zoom"
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop-gpui/locales/fr.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2462,6 +2462,11 @@ stereo = "Stéréo"
advanced_shadow = "Réglages avancés de l'ombre"
background = "Arrière-plan"
corner_style = "Style des coins"
crop = "Recadrer"
crop_bottom = "Bas"
crop_left = "Gauche"
crop_right = "Droite"
crop_top = "Haut"
custom_position = "Position personnalisée (déplacée sur le canevas)"
hide = "Masquer la caméra"
keep_size_during_zoom = "Conserver la taille d'origine pendant le zoom"
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop-gpui/locales/hi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2462,6 +2462,11 @@ stereo = "स्टीरियो"
advanced_shadow = "छाया की एडवांस्ड सेटिंग्स"
background = "बैकग्राउंड"
corner_style = "कोने की स्टाइल"
crop = "क्रॉप"
crop_bottom = "नीचे"
crop_left = "बायाँ"
crop_right = "दायाँ"
crop_top = "ऊपर"
custom_position = "कस्टम पोज़िशन (कैनवास पर ड्रैग की गई)"
hide = "कैमरा छिपाएँ"
keep_size_during_zoom = "ज़ूम के दौरान मूल आकार बनाए रखें"
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop-gpui/locales/ja.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2462,6 +2462,11 @@ stereo = "ステレオ"
advanced_shadow = "影の詳細設定"
background = "背景"
corner_style = "角のスタイル"
crop = "切り抜き"
crop_bottom = "下"
crop_left = "左"
crop_right = "右"
crop_top = "上"
custom_position = "カスタム位置(キャンバス上でドラッグ)"
hide = "カメラを非表示"
keep_size_during_zoom = "ズーム中も元のサイズを保つ"
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop-gpui/locales/zh-CN.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2462,6 +2462,11 @@ stereo = "立体声"
advanced_shadow = "高级阴影设置"
background = "背景"
corner_style = "圆角样式"
crop = "裁剪"
crop_bottom = "下"
crop_left = "左"
crop_right = "右"
crop_top = "上"
custom_position = "自定义位置(在画布上拖动)"
hide = "隐藏摄像头"
keep_size_during_zoom = "缩放时保持原始大小"
Expand Down
62 changes: 61 additions & 1 deletion apps/desktop-gpui/src/editor_tabs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,10 @@ pub enum CameraSlider {
ShadowSize,
ShadowOpacity,
ShadowBlur,
CropLeft,
CropTop,
CropRight,
CropBottom,
}

impl CameraSlider {
Expand All @@ -408,7 +412,11 @@ impl CameraSlider {
| Self::Shadow
| Self::ShadowSize
| Self::ShadowOpacity
| Self::ShadowBlur => false,
| Self::ShadowBlur
| Self::CropLeft
| Self::CropTop
| Self::CropRight
| Self::CropBottom => false,
}
}

Expand All @@ -417,6 +425,7 @@ impl CameraSlider {
// `minValue={20} maxValue={80} step={0.1}` (`:3204-3206`).
Self::Size => (20., 80., 0.1),
Self::ZoomSize => (10., 100., 0.1),
Self::CropLeft | Self::CropTop | Self::CropRight | Self::CropBottom => (0., 45., 0.5),
_ => (0., 100., 0.1),
}
}
Expand All @@ -432,6 +441,10 @@ impl CameraSlider {
Self::ShadowSize => shadow.map_or(UI_SHADOW_FALLBACK.size, |s| s.size),
Self::ShadowOpacity => shadow.map_or(UI_SHADOW_FALLBACK.opacity, |s| s.opacity),
Self::ShadowBlur => shadow.map_or(UI_SHADOW_FALLBACK.blur, |s| s.blur),
Self::CropLeft => camera.crop.map_or(0., |c| (c.left * 100.) as f32),
Self::CropTop => camera.crop.map_or(0., |c| (c.top * 100.) as f32),
Self::CropRight => camera.crop.map_or(0., |c| (c.right * 100.) as f32),
Self::CropBottom => camera.crop.map_or(0., |c| (c.bottom * 100.) as f32),
}
}
}
Expand Down Expand Up @@ -1226,6 +1239,20 @@ impl EditorWindow {
}
camera.advanced_shadow = Some(shadow);
}
CameraSlider::CropLeft
| CameraSlider::CropTop
| CameraSlider::CropRight
| CameraSlider::CropBottom => {
let mut crop = camera.crop.unwrap_or_default();
let fraction = f64::from(value) / 100.;
match slider {
CameraSlider::CropLeft => crop.left = fraction,
CameraSlider::CropTop => crop.top = fraction,
CameraSlider::CropRight => crop.right = fraction,
_ => crop.bottom = fraction,
}
camera.crop = (crop != cap_project::CameraCrop::default()).then_some(crop);
}
}
true
},
Expand Down Expand Up @@ -1518,6 +1545,39 @@ impl EditorWindow {
)
// `<div class="w-full border-t border-dashed border-gray-5" />`
.child(dashed_divider(Hsla::from(theme.editor.line)))
.child(
ui::Field::section(&theme, tr::editor::tabs::camera::crop()).child(
div()
.flex()
.flex_col()
.gap(px(10.))
.child(self.slider_field(
tr::editor::tabs::camera::crop_left(),
SliderKey::Camera(CameraSlider::CropLeft),
"%",
cx,
))
.child(self.slider_field(
tr::editor::tabs::camera::crop_right(),
SliderKey::Camera(CameraSlider::CropRight),
"%",
cx,
))
.child(self.slider_field(
tr::editor::tabs::camera::crop_top(),
SliderKey::Camera(CameraSlider::CropTop),
"%",
cx,
))
.child(self.slider_field(
tr::editor::tabs::camera::crop_bottom(),
SliderKey::Camera(CameraSlider::CropBottom),
"%",
cx,
)),
),
)
.child(dashed_divider(Hsla::from(theme.editor.line)))
.child(self.slider_field(
tr::editor::tabs::camera::size_label(),
SliderKey::Camera(CameraSlider::Size),
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop-gpui/src/i18n/editor_shell_surface_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,11 @@ fn editor_shell_surfaces_match_the_literals_they_replaced() {
"Keep original size during zoom",
),
(tr::editor::tabs::camera::mirror(), "Mirror Camera"),
(tr::editor::tabs::camera::crop(), "Crop"),
(tr::editor::tabs::camera::crop_bottom(), "Bottom"),
(tr::editor::tabs::camera::crop_left(), "Left"),
(tr::editor::tabs::camera::crop_right(), "Right"),
(tr::editor::tabs::camera::crop_top(), "Top"),
(tr::editor::tabs::camera::position(), "Position"),
(tr::editor::tabs::camera::reset(), "Reset"),
(
Expand Down
3 changes: 2 additions & 1 deletion apps/desktop/src/utils/tauri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ export type Camera = { hide: boolean; mirror: boolean; position: CameraPosition;
* Normalized (0-1) center of the camera rect in output-frame space.
* Overrides `position` when set.
*/
manualPosition: XY<number> | null; size: number; zoomSize: number | null; rounding: number; shadow: number; advancedShadow: ShadowConfiguration | null; shape: CameraShape; roundingType: CornerStyle; scaleDuringZoom?: number; backgroundBlur?: BackgroundBlurConfig }
manualPosition: XY<number> | null; size: number; zoomSize: number | null; rounding: number; shadow: number; advancedShadow: ShadowConfiguration | null; shape: CameraShape; roundingType: CornerStyle; scaleDuringZoom?: number; backgroundBlur?: BackgroundBlurConfig; crop?: CameraCrop | null }
/**
* Screen-space focus blur applied over the composed frame while a 3d segment
* is active (a UV-mask variable blur, not a depth-of-field). `strength` is a
Expand Down Expand Up @@ -878,6 +878,7 @@ transitionOut?: number }
* after its last keyframe.
*/
export type Camera3DTracks = { tiltX: Camera3DKeyframe[]; tiltY: Camera3DKeyframe[]; roll: Camera3DKeyframe[]; rotateX: Camera3DKeyframe[]; rotateY: Camera3DKeyframe[]; fov: Camera3DKeyframe[]; zoom: Camera3DKeyframe[]; panX: Camera3DKeyframe[]; panY: Camera3DKeyframe[]; blurStrength: Camera3DKeyframe[]; blurFalloff: Camera3DKeyframe[]; blurFocusSize: Camera3DKeyframe[]; blurFocusX: Camera3DKeyframe[]; blurFocusY: Camera3DKeyframe[]; blurAngle: Camera3DKeyframe[]; blurDirPosition: Camera3DKeyframe[] }
export type CameraCrop = { left: number; top: number; right: number; bottom: number }
export type CameraDeviceSettings = { width: number | null; height: number | null; frameRate: number | null }
export type CameraFormatInfo = { width: number; height: number; frameRate: number }
export type CameraInfo = { device_id: string; model_id: ModelIDType | null; display_name: string }
Expand Down
67 changes: 67 additions & 0 deletions crates/project/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,46 @@ pub struct Camera {
pub scale_during_zoom: f32,
#[serde(default)]
pub background_blur: BackgroundBlurConfig,
#[serde(default)]
pub crop: Option<CameraCrop>,
Comment on lines +568 to +569

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Camera bindings omit crop

Camera now exports crop and the new CameraCrop type, but the committed Camera in apps/desktop/src/utils/tauri.ts still ends at backgroundBlur. TypeScript callers therefore see the old camera settings.

AGENTS.md requires generated binding changes to be committed alongside the Rust change that produced them. Regenerate and commit these bindings before merging.

Context Used: AGENTS.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/project/src/configuration.rs
Line: 564-565

Comment:
**Camera bindings omit crop**

`Camera` now exports `crop` and the new `CameraCrop` type, but the committed `Camera` in `apps/desktop/src/utils/tauri.ts` still ends at `backgroundBlur`. TypeScript callers therefore see the old camera settings.

`AGENTS.md` requires generated binding changes to be committed alongside the Rust change that produced them. Regenerate and commit these bindings before merging.

**Context Used:** AGENTS.md ([source](https://github.com/capsoftware/cap/blob/main/AGENTS.md))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

}

#[derive(Type, Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Default)]
#[serde(rename_all = "camelCase", default)]
pub struct CameraCrop {
pub left: f64,
pub top: f64,
pub right: f64,
pub bottom: f64,
}

impl CameraCrop {
pub const MAX_TOTAL: f64 = 0.9;

pub fn region(&self) -> [f64; 4] {
let axis = |start: f64, end: f64| {
let start = if start.is_finite() {
start.clamp(0.0, 1.0)
} else {
0.0
};
let end = if end.is_finite() {
end.clamp(0.0, 1.0)
} else {
0.0
};
let total = start + end;
let scale = if total > Self::MAX_TOTAL {
Self::MAX_TOTAL / total
} else {
1.0
};
(start * scale, 1.0 - end * scale)
};
let (x0, x1) = axis(self.left, self.right);
let (y0, y1) = axis(self.top, self.bottom);
[x0, y0, x1, y1]
}
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, Type, Default)]
Expand Down Expand Up @@ -609,6 +649,7 @@ impl Default for Camera {
rounding_type: CornerStyle::default(),
scale_during_zoom: Self::default_scale_during_zoom(),
background_blur: BackgroundBlurConfig::default(),
crop: None,
}
}
}
Expand Down Expand Up @@ -3263,6 +3304,32 @@ mod tests {
use super::*;
use serde_json::Value;

#[test]
fn camera_crop_region_keeps_part_of_the_image() {
let crop = CameraCrop {
left: 0.1,
top: 0.2,
right: 0.3,
bottom: 0.0,
};
let region = crop.region();
assert!((region[0] - 0.1).abs() < 1e-9);
assert!((region[1] - 0.2).abs() < 1e-9);
assert!((region[2] - 0.7).abs() < 1e-9);
assert!((region[3] - 1.0).abs() < 1e-9);

let extreme = CameraCrop {
left: 0.8,
right: 0.8,
..Default::default()
}
.region();
assert!(extreme[2] - extreme[0] > 0.09);

let legacy: Camera = serde_json::from_str(r#"{ "mirror": true }"#).unwrap();
assert!(legacy.crop.is_none());
}

#[test]
fn studio_sound_defaults_old_projects_to_balanced_and_round_trips_tiers() {
let legacy: AudioConfiguration =
Expand Down
Loading
Loading