chore: Fix several style lints (#17488)

It's not comprehensive enough to start linting on `style` group, but
hey, it's a start.

Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz 2024-09-06 11:58:39 +02:00 committed by GitHub
parent 93249fc82b
commit e6c1c51b37
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
361 changed files with 3530 additions and 3587 deletions

View file

@ -187,7 +187,7 @@ pub enum DockPosition {
}
impl DockPosition {
fn to_label(&self) -> &'static str {
fn label(&self) -> &'static str {
match self {
Self::Left => "left",
Self::Bottom => "bottom",
@ -485,7 +485,7 @@ impl Dock {
self.set_open(serialized.visible, cx);
return true;
}
return false;
false
}
pub fn remove_panel<T: Panel>(&mut self, panel: &View<T>, cx: &mut ViewContext<Self>) {
@ -494,11 +494,15 @@ impl Dock {
.iter()
.position(|entry| entry.panel.panel_id() == Entity::entity_id(panel))
{
if panel_ix == self.active_panel_index {
self.active_panel_index = 0;
self.set_open(false, cx);
} else if panel_ix < self.active_panel_index {
self.active_panel_index -= 1;
match panel_ix.cmp(&self.active_panel_index) {
std::cmp::Ordering::Less => {
self.active_panel_index -= 1;
}
std::cmp::Ordering::Equal => {
self.active_panel_index = 0;
self.set_open(false, cx);
}
std::cmp::Ordering::Greater => {}
}
self.panel_entries.remove(panel_ix);
cx.notify();
@ -726,7 +730,7 @@ impl Render for PanelButtons {
let action = dock.toggle_action();
let tooltip: SharedString =
format!("Close {} dock", dock.position.to_label()).into();
format!("Close {} dock", dock.position.label()).into();
(action, tooltip)
} else {
@ -751,7 +755,7 @@ impl Render for PanelButtons {
{
let panel = panel.clone();
menu = menu.entry(
format!("Dock {}", position.to_label()),
format!("Dock {}", position.label()),
None,
move |cx| {
panel.set_position(position, cx);

View file

@ -685,7 +685,6 @@ impl<T: Item> ItemHandle for View<T> {
pane.close_item_by_id(item.item_id(), crate::SaveIntent::Close, cx)
})
.detach_and_log_err(cx);
return;
}
ItemEvent::UpdateTab => {

View file

@ -48,6 +48,12 @@ pub struct ModalLayer {
dismiss_on_focus_lost: bool,
}
impl Default for ModalLayer {
fn default() -> Self {
Self::new()
}
}
impl ModalLayer {
pub fn new() -> Self {
Self {

View file

@ -657,14 +657,14 @@ where
if let Err(err) = result.as_ref() {
log::error!("{err:?}");
if let Ok(prompt) = cx.update(|cx| {
let detail = f(&err, cx).unwrap_or_else(|| format!("{err}. Please try again."));
let detail = f(err, cx).unwrap_or_else(|| format!("{err}. Please try again."));
cx.prompt(PromptLevel::Critical, &msg, Some(&detail), &["Ok"])
}) {
prompt.await.ok();
}
return None;
}
return Some(result.unwrap());
Some(result.unwrap())
})
}

View file

@ -484,10 +484,8 @@ impl Pane {
.find_position(|item| item.item_id() == alternative.id());
if let Some((ix, _)) = existing {
self.activate_item(ix, true, true, cx);
} else {
if let Some(upgraded) = alternative.upgrade() {
self.add_item(upgraded, true, true, None, cx);
}
} else if let Some(upgraded) = alternative.upgrade() {
self.add_item(upgraded, true, true, None, cx);
}
}
}
@ -781,9 +779,7 @@ impl Pane {
}
pub fn close_current_preview_item(&mut self, cx: &mut ViewContext<Self>) -> Option<usize> {
let Some(item_idx) = self.preview_item_idx() else {
return None;
};
let item_idx = self.preview_item_idx()?;
let prev_active_item_index = self.active_item_index;
self.remove_item(item_idx, false, false, cx);
@ -805,7 +801,7 @@ impl Pane {
cx: &mut ViewContext<Self>,
) {
if item.is_singleton(cx) {
if let Some(&entry_id) = item.project_entry_ids(cx).get(0) {
if let Some(&entry_id) = item.project_entry_ids(cx).first() {
let project = self.project.read(cx);
if let Some(project_path) = project.path_for_entry(entry_id, cx) {
let abs_path = project.absolute_path(&project_path, cx);
@ -831,7 +827,7 @@ impl Pane {
// Does the item already exist?
let project_entry_id = if item.is_singleton(cx) {
item.project_entry_ids(cx).get(0).copied()
item.project_entry_ids(cx).first().copied()
} else {
None
};
@ -842,7 +838,7 @@ impl Pane {
} else if existing_item.is_singleton(cx) {
existing_item
.project_entry_ids(cx)
.get(0)
.first()
.map_or(false, |existing_entry_id| {
Some(existing_entry_id) == project_entry_id.as_ref()
})
@ -1600,12 +1596,10 @@ impl Pane {
project: Model<Project>,
cx: &mut WindowContext,
) -> Task<Result<()>> {
let format =
if let AutosaveSetting::AfterDelay { .. } = item.workspace_settings(cx).autosave {
false
} else {
true
};
let format = !matches!(
item.workspace_settings(cx).autosave,
AutosaveSetting::AfterDelay { .. }
);
if Self::can_autosave_item(item, cx) {
item.save(format, project, cx)
} else {
@ -1817,7 +1811,7 @@ impl Pane {
let icon_color = if ItemSettings::get_global(cx).git_status {
project_path
.as_ref()
.and_then(|path| self.project.read(cx).entry_for_path(&path, cx))
.and_then(|path| self.project.read(cx).entry_for_path(path, cx))
.map(|entry| {
Self::git_aware_icon_color(entry.git_status, entry.is_ignored, is_active)
})
@ -2458,20 +2452,17 @@ impl Pane {
split_direction = None;
}
if let Some(open_task) = workspace
.update(&mut cx, |workspace, cx| {
if let Some(split_direction) = split_direction {
to_pane = workspace.split_pane(to_pane, split_direction, cx);
}
workspace.open_paths(
paths,
OpenVisible::OnlyDirectories,
Some(to_pane.downgrade()),
cx,
)
})
.ok()
{
if let Ok(open_task) = workspace.update(&mut cx, |workspace, cx| {
if let Some(split_direction) = split_direction {
to_pane = workspace.split_pane(to_pane, split_direction, cx);
}
workspace.open_paths(
paths,
OpenVisible::OnlyDirectories,
Some(to_pane.downgrade()),
cx,
)
}) {
let opened_items: Vec<_> = open_task.await;
_ = workspace.update(&mut cx, |workspace, cx| {
for item in opened_items.into_iter().flatten() {
@ -2887,14 +2878,14 @@ fn dirty_message_for(buffer_path: Option<ProjectPath>) -> String {
.and_then(|p| {
p.path
.to_str()
.and_then(|s| if s == "" { None } else { Some(s) })
.and_then(|s| if s.is_empty() { None } else { Some(s) })
})
.unwrap_or("This buffer");
let path = truncate_and_remove_front(path, 80);
format!("{path} contains unsaved edits. Do you want to save it?")
}
pub fn tab_details(items: &Vec<Box<dyn ItemHandle>>, cx: &AppContext) -> Vec<usize> {
pub fn tab_details(items: &[Box<dyn ItemHandle>], cx: &AppContext) -> Vec<usize> {
let mut tab_details = items.iter().map(|_| 0).collect::<Vec<_>>();
let mut tab_descriptions = HashMap::default();
let mut done = false;
@ -2942,6 +2933,25 @@ pub fn render_item_indicator(item: Box<dyn ItemHandle>, cx: &WindowContext) -> O
})
}
impl Render for DraggedTab {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let ui_font = ThemeSettings::get_global(cx).ui_font.clone();
let label = self.item.tab_content(
TabContentParams {
detail: Some(self.detail),
selected: false,
preview: false,
},
cx,
);
Tab::new("")
.selected(self.is_active)
.child(label)
.render(cx)
.font(ui_font)
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -3484,22 +3494,3 @@ mod tests {
})
}
}
impl Render for DraggedTab {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let ui_font = ThemeSettings::get_global(cx).ui_font.clone();
let label = self.item.tab_content(
TabContentParams {
detail: Some(self.detail),
selected: false,
preview: false,
},
cx,
);
Tab::new("")
.selected(self.is_active)
.child(label)
.render(cx)
.font(ui_font)
}
}

View file

@ -631,7 +631,7 @@ mod element {
use std::{cell::RefCell, iter, rc::Rc, sync::Arc};
use gpui::{
px, relative, Along, AnyElement, Axis, Bounds, Element, GlobalElementId, IntoElement,
px, relative, size, Along, AnyElement, Axis, Bounds, Element, GlobalElementId, IntoElement,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Size, Style,
WeakView, WindowContext,
};
@ -838,12 +838,13 @@ mod element {
_global_id: Option<&GlobalElementId>,
cx: &mut ui::prelude::WindowContext,
) -> (gpui::LayoutId, Self::RequestLayoutState) {
let mut style = Style::default();
style.flex_grow = 1.;
style.flex_shrink = 1.;
style.flex_basis = relative(0.).into();
style.size.width = relative(1.).into();
style.size.height = relative(1.).into();
let style = Style {
flex_grow: 1.,
flex_shrink: 1.,
flex_basis: relative(0.).into(),
size: size(relative(1.).into(), relative(1.).into()),
..Style::default()
};
(cx.request_layout(style, None), ())
}
@ -922,11 +923,9 @@ mod element {
}
for (ix, child_layout) in layout.children.iter_mut().enumerate() {
if active_pane_magnification.is_none() {
if ix < len - 1 {
child_layout.handle =
Some(Self::layout_handle(self.axis, child_layout.bounds, cx));
}
if active_pane_magnification.is_none() && ix < len - 1 {
child_layout.handle =
Some(Self::layout_handle(self.axis, child_layout.bounds, cx));
}
}
@ -986,19 +985,17 @@ mod element {
let axis = self.axis;
move |e: &MouseMoveEvent, phase, cx| {
let dragged_handle = dragged_handle.borrow();
if phase.bubble() {
if *dragged_handle == Some(ix) {
Self::compute_resize(
&flexes,
e,
ix,
axis,
child_bounds.origin,
bounds.size,
workspace.clone(),
cx,
)
}
if phase.bubble() && *dragged_handle == Some(ix) {
Self::compute_resize(
&flexes,
e,
ix,
axis,
child_bounds.origin,
bounds.size,
workspace.clone(),
cx,
)
}
}
});

View file

@ -731,7 +731,7 @@ impl WorkspaceDb {
LIMIT 1
))?;
let result = prepared_query()?;
Ok(result.into_iter().next().unwrap_or_else(|| (None, None)))
Ok(result.into_iter().next().unwrap_or((None, None)))
}
query! {
@ -819,7 +819,7 @@ impl WorkspaceDb {
if location.paths().iter().all(|path| path.exists())
&& location.paths().iter().any(|path| path.is_dir())
{
workspaces.push((location, window_id.map(|id| WindowId::from(id))));
workspaces.push((location, window_id.map(WindowId::from)));
}
}
@ -1330,7 +1330,7 @@ mod tests {
let mut workspace_3 = SerializedWorkspace {
id: WorkspaceId(3),
location: SerializedWorkspaceLocation::Local(
LocalPaths::new(&["/tmp", "/tmp2"]),
LocalPaths::new(["/tmp", "/tmp2"]),
LocalPathsOrder::new([1, 0]),
),
center_group: Default::default(),

View file

@ -356,7 +356,11 @@ impl SerializedPaneGroup {
if pane.update(cx, |pane, _| pane.items_len() != 0).log_err()? {
let pane = pane.upgrade()?;
Some((Member::Pane(pane.clone()), active.then(|| pane), new_items))
Some((
Member::Pane(pane.clone()),
active.then_some(pane),
new_items,
))
} else {
let pane = pane.upgrade()?;
workspace

View file

@ -121,7 +121,7 @@ impl StatusBar {
return Some(index + self.left_items.len());
}
}
return None;
None
}
pub fn insert_item_after<T>(

View file

@ -139,6 +139,12 @@ impl Render for Toolbar {
}
}
impl Default for Toolbar {
fn default() -> Self {
Self::new()
}
}
impl Toolbar {
pub fn new() -> Self {
Self {

View file

@ -300,9 +300,9 @@ impl Column for WorkspaceId {
.with_context(|| format!("Failed to read WorkspaceId at index {start_index}"))
}
}
impl Into<i64> for WorkspaceId {
fn into(self) -> i64 {
self.0
impl From<WorkspaceId> for i64 {
fn from(val: WorkspaceId) -> Self {
val.0
}
}
@ -383,12 +383,12 @@ impl Global for ProjectItemOpeners {}
pub fn register_project_item<I: ProjectItem>(cx: &mut AppContext) {
let builders = cx.default_global::<ProjectItemOpeners>();
builders.push(|project, project_path, cx| {
let project_item = <I::Item as project::Item>::try_open(&project, project_path, cx)?;
let project_item = <I::Item as project::Item>::try_open(project, project_path, cx)?;
let project = project.clone();
Some(cx.spawn(|cx| async move {
let project_item = project_item.await?;
let project_entry_id: Option<ProjectEntryId> =
project_item.read_with(&cx, |item, cx| project::Item::entry_id(item, cx))?;
project_item.read_with(&cx, project::Item::entry_id)?;
let build_workspace_item = Box::new(|cx: &mut ViewContext<Pane>| {
Box::new(cx.new_view(|cx| I::for_project_item(project, project_item, cx)))
as Box<dyn ItemHandle>
@ -963,7 +963,7 @@ impl Workspace {
.await;
this.update(&mut cx, |this, cx| {
if let Some(display) = cx.display() {
if let Some(display_uuid) = display.uuid().ok() {
if let Ok(display_uuid) = display.uuid() {
let window_bounds = cx.window_bounds();
if let Some(database_id) = workspace_id {
cx.background_executor()
@ -1782,7 +1782,7 @@ impl Workspace {
let project = self.project.clone();
cx.spawn(|workspace, mut cx| async move {
let dirty_items = if save_intent == SaveIntent::Close && dirty_items.len() > 0 {
let dirty_items = if save_intent == SaveIntent::Close && !dirty_items.is_empty() {
let (serialize_tasks, remaining_dirty_items) =
workspace.update(&mut cx, |workspace, cx| {
let mut remaining_dirty_items = Vec::new();
@ -2877,9 +2877,7 @@ impl Workspace {
direction: SplitDirection,
cx: &WindowContext,
) -> Option<View<Pane>> {
let Some(bounding_box) = self.center.bounding_box_for_pane(&self.active_pane) else {
return None;
};
let bounding_box = self.center.bounding_box_for_pane(&self.active_pane)?;
let cursor = self.active_pane.read(cx).pixel_position_of_cursor(cx);
let center = match cursor {
Some(cursor) if bounding_box.contains(&cursor) => cursor,
@ -2910,10 +2908,7 @@ impl Workspace {
direction: SplitDirection,
cx: &mut ViewContext<Self>,
) {
if let Some(to) = self
.find_pane_in_direction(direction, cx)
.map(|pane| pane.clone())
{
if let Some(to) = self.find_pane_in_direction(direction, cx) {
self.center.swap(&self.active_pane.clone(), &to);
cx.notify();
}
@ -3355,7 +3350,7 @@ impl Workspace {
// if you're already following, find the right pane and focus it.
if let Some(follower_state) = self.follower_states.get(&leader_id) {
cx.focus_view(&follower_state.pane());
cx.focus_view(follower_state.pane());
return;
}
@ -3621,7 +3616,7 @@ impl Workspace {
return Err(anyhow!("no id for view"));
};
let id = ViewId::from_proto(id)?;
let panel_id = view.panel_id.and_then(|id| proto::PanelId::from_i32(id));
let panel_id = view.panel_id.and_then(proto::PanelId::from_i32);
let pane = this.update(cx, |this, _cx| {
let state = this
@ -4143,7 +4138,7 @@ impl Workspace {
let dev_server_project = SerializedDevServerProject {
id: dev_server_project_id,
dev_server_name: dev_server.name.to_string(),
paths: project.paths.iter().map(|path| path.clone()).collect(),
paths: project.paths.to_vec(),
};
Some(SerializedWorkspaceLocation::DevServer(dev_server_project))
})
@ -4961,7 +4956,7 @@ impl ViewId {
})
}
pub(crate) fn to_proto(&self) -> proto::ViewId {
pub(crate) fn to_proto(self) -> proto::ViewId {
proto::ViewId {
creator: Some(self.creator),
id: self.id,
@ -5061,7 +5056,7 @@ async fn join_channel_internal(
let already_in_channel = room.channel_id() == Some(channel_id);
let should_prompt = room.is_sharing_project()
&& room.remote_participants().len() > 0
&& !room.remote_participants().is_empty()
&& !already_in_channel;
let open_room = if already_in_channel {
active_call.room().cloned()
@ -5266,7 +5261,7 @@ pub fn join_channel(
}
// return ok, we showed the error to the user.
return anyhow::Ok(());
anyhow::Ok(())
})
}
@ -5468,7 +5463,7 @@ pub fn join_hosted_project(
.is_ok_and(|workspace| {
workspace.project().read(cx).hosted_project_id() == Some(hosted_project_id)
})
.then(|| workspace)
.then_some(workspace)
})
})?;
@ -5488,8 +5483,7 @@ pub fn join_hosted_project(
let window_bounds_override = window_bounds_env_override();
cx.update(|cx| {
let mut options = (app_state.build_window_options)(None, cx);
options.window_bounds =
window_bounds_override.map(|bounds| WindowBounds::Windowed(bounds));
options.window_bounds = window_bounds_override.map(WindowBounds::Windowed);
cx.open_window(options, |cx| {
cx.new_view(|cx| {
Workspace::new(Default::default(), project, app_state.clone(), cx)
@ -5563,8 +5557,7 @@ pub fn join_dev_server_project(
let window_bounds_override = window_bounds_env_override();
cx.update(|cx| {
let mut options = (app_state.build_window_options)(None, cx);
options.window_bounds =
window_bounds_override.map(|bounds| WindowBounds::Windowed(bounds));
options.window_bounds = window_bounds_override.map(WindowBounds::Windowed);
cx.open_window(options, |cx| {
cx.new_view(|cx| {
Workspace::new(Some(workspace_id), project, app_state.clone(), cx)
@ -5626,8 +5619,7 @@ pub fn join_in_room_project(
let window_bounds_override = window_bounds_env_override();
cx.update(|cx| {
let mut options = (app_state.build_window_options)(None, cx);
options.window_bounds =
window_bounds_override.map(|bounds| WindowBounds::Windowed(bounds));
options.window_bounds = window_bounds_override.map(WindowBounds::Windowed);
cx.open_window(options, |cx| {
cx.new_view(|cx| {
Workspace::new(Default::default(), project, app_state.clone(), cx)
@ -5733,6 +5725,224 @@ fn parse_pixel_size_env_var(value: &str) -> Option<Size<Pixels>> {
Some(size(px(width as f32), px(height as f32)))
}
pub fn client_side_decorations(element: impl IntoElement, cx: &mut WindowContext) -> Stateful<Div> {
const BORDER_SIZE: Pixels = px(1.0);
let decorations = cx.window_decorations();
if matches!(decorations, Decorations::Client { .. }) {
cx.set_client_inset(theme::CLIENT_SIDE_DECORATION_SHADOW);
}
struct GlobalResizeEdge(ResizeEdge);
impl Global for GlobalResizeEdge {}
div()
.id("window-backdrop")
.bg(transparent_black())
.map(|div| match decorations {
Decorations::Server => div,
Decorations::Client { tiling, .. } => div
.when(!(tiling.top || tiling.right), |div| {
div.rounded_tr(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.top || tiling.left), |div| {
div.rounded_tl(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.bottom || tiling.right), |div| {
div.rounded_br(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.bottom || tiling.left), |div| {
div.rounded_bl(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!tiling.top, |div| {
div.pt(theme::CLIENT_SIDE_DECORATION_SHADOW)
})
.when(!tiling.bottom, |div| {
div.pb(theme::CLIENT_SIDE_DECORATION_SHADOW)
})
.when(!tiling.left, |div| {
div.pl(theme::CLIENT_SIDE_DECORATION_SHADOW)
})
.when(!tiling.right, |div| {
div.pr(theme::CLIENT_SIDE_DECORATION_SHADOW)
})
.on_mouse_move(move |e, cx| {
let size = cx.window_bounds().get_bounds().size;
let pos = e.position;
let new_edge =
resize_edge(pos, theme::CLIENT_SIDE_DECORATION_SHADOW, size, tiling);
let edge = cx.try_global::<GlobalResizeEdge>();
if new_edge != edge.map(|edge| edge.0) {
cx.window_handle()
.update(cx, |workspace, cx| cx.notify(workspace.entity_id()))
.ok();
}
})
.on_mouse_down(MouseButton::Left, move |e, cx| {
let size = cx.window_bounds().get_bounds().size;
let pos = e.position;
let edge = match resize_edge(
pos,
theme::CLIENT_SIDE_DECORATION_SHADOW,
size,
tiling,
) {
Some(value) => value,
None => return,
};
cx.start_window_resize(edge);
}),
})
.size_full()
.child(
div()
.cursor(CursorStyle::Arrow)
.map(|div| match decorations {
Decorations::Server => div,
Decorations::Client { tiling } => div
.border_color(cx.theme().colors().border)
.when(!(tiling.top || tiling.right), |div| {
div.rounded_tr(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.top || tiling.left), |div| {
div.rounded_tl(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.bottom || tiling.right), |div| {
div.rounded_br(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.bottom || tiling.left), |div| {
div.rounded_bl(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!tiling.top, |div| div.border_t(BORDER_SIZE))
.when(!tiling.bottom, |div| div.border_b(BORDER_SIZE))
.when(!tiling.left, |div| div.border_l(BORDER_SIZE))
.when(!tiling.right, |div| div.border_r(BORDER_SIZE))
.when(!tiling.is_tiled(), |div| {
div.shadow(smallvec::smallvec![gpui::BoxShadow {
color: Hsla {
h: 0.,
s: 0.,
l: 0.,
a: 0.4,
},
blur_radius: theme::CLIENT_SIDE_DECORATION_SHADOW / 2.,
spread_radius: px(0.),
offset: point(px(0.0), px(0.0)),
}])
}),
})
.on_mouse_move(|_e, cx| {
cx.stop_propagation();
})
.size_full()
.child(element),
)
.map(|div| match decorations {
Decorations::Server => div,
Decorations::Client { tiling, .. } => div.child(
canvas(
|_bounds, cx| {
cx.insert_hitbox(
Bounds::new(
point(px(0.0), px(0.0)),
cx.window_bounds().get_bounds().size,
),
false,
)
},
move |_bounds, hitbox, cx| {
let mouse = cx.mouse_position();
let size = cx.window_bounds().get_bounds().size;
let Some(edge) =
resize_edge(mouse, theme::CLIENT_SIDE_DECORATION_SHADOW, size, tiling)
else {
return;
};
cx.set_global(GlobalResizeEdge(edge));
cx.set_cursor_style(
match edge {
ResizeEdge::Top | ResizeEdge::Bottom => CursorStyle::ResizeUpDown,
ResizeEdge::Left | ResizeEdge::Right => {
CursorStyle::ResizeLeftRight
}
ResizeEdge::TopLeft | ResizeEdge::BottomRight => {
CursorStyle::ResizeUpLeftDownRight
}
ResizeEdge::TopRight | ResizeEdge::BottomLeft => {
CursorStyle::ResizeUpRightDownLeft
}
},
&hitbox,
);
},
)
.size_full()
.absolute(),
),
})
}
fn resize_edge(
pos: Point<Pixels>,
shadow_size: Pixels,
window_size: Size<Pixels>,
tiling: Tiling,
) -> Option<ResizeEdge> {
let bounds = Bounds::new(Point::default(), window_size).inset(shadow_size * 1.5);
if bounds.contains(&pos) {
return None;
}
let corner_size = size(shadow_size * 1.5, shadow_size * 1.5);
let top_left_bounds = Bounds::new(Point::new(px(0.), px(0.)), corner_size);
if !tiling.top && top_left_bounds.contains(&pos) {
return Some(ResizeEdge::TopLeft);
}
let top_right_bounds = Bounds::new(
Point::new(window_size.width - corner_size.width, px(0.)),
corner_size,
);
if !tiling.top && top_right_bounds.contains(&pos) {
return Some(ResizeEdge::TopRight);
}
let bottom_left_bounds = Bounds::new(
Point::new(px(0.), window_size.height - corner_size.height),
corner_size,
);
if !tiling.bottom && bottom_left_bounds.contains(&pos) {
return Some(ResizeEdge::BottomLeft);
}
let bottom_right_bounds = Bounds::new(
Point::new(
window_size.width - corner_size.width,
window_size.height - corner_size.height,
),
corner_size,
);
if !tiling.bottom && bottom_right_bounds.contains(&pos) {
return Some(ResizeEdge::BottomRight);
}
if !tiling.top && pos.y < shadow_size {
Some(ResizeEdge::Top)
} else if !tiling.bottom && pos.y > window_size.height - shadow_size {
Some(ResizeEdge::Bottom)
} else if !tiling.left && pos.x < shadow_size {
Some(ResizeEdge::Left)
} else if !tiling.right && pos.x > window_size.width - shadow_size {
Some(ResizeEdge::Right)
} else {
None
}
}
#[cfg(test)]
mod tests {
use std::{cell::RefCell, rc::Rc};
@ -5906,7 +6116,7 @@ mod tests {
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
// When there are no dirty items, there's nothing to do.
let item1 = cx.new_view(|cx| TestItem::new(cx));
let item1 = cx.new_view(TestItem::new);
workspace.update(cx, |w, cx| {
w.add_item_to_active_pane(Box::new(item1.clone()), None, true, cx)
});
@ -6381,7 +6591,7 @@ mod tests {
let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone());
pane.update(cx, |pane, cx| {
let item = cx.new_view(|cx| TestItem::new(cx));
let item = cx.new_view(TestItem::new);
pane.add_item(Box::new(item), true, true, None, cx);
});
@ -7189,221 +7399,3 @@ mod tests {
});
}
}
pub fn client_side_decorations(element: impl IntoElement, cx: &mut WindowContext) -> Stateful<Div> {
const BORDER_SIZE: Pixels = px(1.0);
let decorations = cx.window_decorations();
if matches!(decorations, Decorations::Client { .. }) {
cx.set_client_inset(theme::CLIENT_SIDE_DECORATION_SHADOW);
}
struct GlobalResizeEdge(ResizeEdge);
impl Global for GlobalResizeEdge {}
div()
.id("window-backdrop")
.bg(transparent_black())
.map(|div| match decorations {
Decorations::Server => div,
Decorations::Client { tiling, .. } => div
.when(!(tiling.top || tiling.right), |div| {
div.rounded_tr(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.top || tiling.left), |div| {
div.rounded_tl(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.bottom || tiling.right), |div| {
div.rounded_br(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.bottom || tiling.left), |div| {
div.rounded_bl(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!tiling.top, |div| {
div.pt(theme::CLIENT_SIDE_DECORATION_SHADOW)
})
.when(!tiling.bottom, |div| {
div.pb(theme::CLIENT_SIDE_DECORATION_SHADOW)
})
.when(!tiling.left, |div| {
div.pl(theme::CLIENT_SIDE_DECORATION_SHADOW)
})
.when(!tiling.right, |div| {
div.pr(theme::CLIENT_SIDE_DECORATION_SHADOW)
})
.on_mouse_move(move |e, cx| {
let size = cx.window_bounds().get_bounds().size;
let pos = e.position;
let new_edge =
resize_edge(pos, theme::CLIENT_SIDE_DECORATION_SHADOW, size, tiling);
let edge = cx.try_global::<GlobalResizeEdge>();
if new_edge != edge.map(|edge| edge.0) {
cx.window_handle()
.update(cx, |workspace, cx| cx.notify(workspace.entity_id()))
.ok();
}
})
.on_mouse_down(MouseButton::Left, move |e, cx| {
let size = cx.window_bounds().get_bounds().size;
let pos = e.position;
let edge = match resize_edge(
pos,
theme::CLIENT_SIDE_DECORATION_SHADOW,
size,
tiling,
) {
Some(value) => value,
None => return,
};
cx.start_window_resize(edge);
}),
})
.size_full()
.child(
div()
.cursor(CursorStyle::Arrow)
.map(|div| match decorations {
Decorations::Server => div,
Decorations::Client { tiling } => div
.border_color(cx.theme().colors().border)
.when(!(tiling.top || tiling.right), |div| {
div.rounded_tr(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.top || tiling.left), |div| {
div.rounded_tl(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.bottom || tiling.right), |div| {
div.rounded_br(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!(tiling.bottom || tiling.left), |div| {
div.rounded_bl(theme::CLIENT_SIDE_DECORATION_ROUNDING)
})
.when(!tiling.top, |div| div.border_t(BORDER_SIZE))
.when(!tiling.bottom, |div| div.border_b(BORDER_SIZE))
.when(!tiling.left, |div| div.border_l(BORDER_SIZE))
.when(!tiling.right, |div| div.border_r(BORDER_SIZE))
.when(!tiling.is_tiled(), |div| {
div.shadow(smallvec::smallvec![gpui::BoxShadow {
color: Hsla {
h: 0.,
s: 0.,
l: 0.,
a: 0.4,
},
blur_radius: theme::CLIENT_SIDE_DECORATION_SHADOW / 2.,
spread_radius: px(0.),
offset: point(px(0.0), px(0.0)),
}])
}),
})
.on_mouse_move(|_e, cx| {
cx.stop_propagation();
})
.size_full()
.child(element),
)
.map(|div| match decorations {
Decorations::Server => div,
Decorations::Client { tiling, .. } => div.child(
canvas(
|_bounds, cx| {
cx.insert_hitbox(
Bounds::new(
point(px(0.0), px(0.0)),
cx.window_bounds().get_bounds().size,
),
false,
)
},
move |_bounds, hitbox, cx| {
let mouse = cx.mouse_position();
let size = cx.window_bounds().get_bounds().size;
let Some(edge) =
resize_edge(mouse, theme::CLIENT_SIDE_DECORATION_SHADOW, size, tiling)
else {
return;
};
cx.set_global(GlobalResizeEdge(edge));
cx.set_cursor_style(
match edge {
ResizeEdge::Top | ResizeEdge::Bottom => CursorStyle::ResizeUpDown,
ResizeEdge::Left | ResizeEdge::Right => {
CursorStyle::ResizeLeftRight
}
ResizeEdge::TopLeft | ResizeEdge::BottomRight => {
CursorStyle::ResizeUpLeftDownRight
}
ResizeEdge::TopRight | ResizeEdge::BottomLeft => {
CursorStyle::ResizeUpRightDownLeft
}
},
&hitbox,
);
},
)
.size_full()
.absolute(),
),
})
}
fn resize_edge(
pos: Point<Pixels>,
shadow_size: Pixels,
window_size: Size<Pixels>,
tiling: Tiling,
) -> Option<ResizeEdge> {
let bounds = Bounds::new(Point::default(), window_size).inset(shadow_size * 1.5);
if bounds.contains(&pos) {
return None;
}
let corner_size = size(shadow_size * 1.5, shadow_size * 1.5);
let top_left_bounds = Bounds::new(Point::new(px(0.), px(0.)), corner_size);
if !tiling.top && top_left_bounds.contains(&pos) {
return Some(ResizeEdge::TopLeft);
}
let top_right_bounds = Bounds::new(
Point::new(window_size.width - corner_size.width, px(0.)),
corner_size,
);
if !tiling.top && top_right_bounds.contains(&pos) {
return Some(ResizeEdge::TopRight);
}
let bottom_left_bounds = Bounds::new(
Point::new(px(0.), window_size.height - corner_size.height),
corner_size,
);
if !tiling.bottom && bottom_left_bounds.contains(&pos) {
return Some(ResizeEdge::BottomLeft);
}
let bottom_right_bounds = Bounds::new(
Point::new(
window_size.width - corner_size.width,
window_size.height - corner_size.height,
),
corner_size,
);
if !tiling.bottom && bottom_right_bounds.contains(&pos) {
return Some(ResizeEdge::BottomRight);
}
if !tiling.top && pos.y < shadow_size {
Some(ResizeEdge::Top)
} else if !tiling.bottom && pos.y > window_size.height - shadow_size {
Some(ResizeEdge::Bottom)
} else if !tiling.left && pos.x < shadow_size {
Some(ResizeEdge::Left)
} else if !tiling.right && pos.x > window_size.width - shadow_size {
Some(ResizeEdge::Right)
} else {
None
}
}