mirror of
https://github.com/zed-industries/zed.git
synced 2026-07-09 16:00:35 +00:00
git_graph: Add design adjustments (#60469)
This PR adds adjustments to the tree view, making it more consistent with all other tree view displays in the app (e.g., displaying indent guides, removing chevron toggle, etc.), and also fixes an issue where the commit message scrollbar was scrolling up with the message. Release Notes: - N/A
This commit is contained in:
parent
f360136f19
commit
a94fa5cf19
7 changed files with 137 additions and 148 deletions
|
|
@ -52,7 +52,7 @@ use theme::AccentColors;
|
|||
use time::{OffsetDateTime, UtcOffset, format_description::BorrowedFormatItem};
|
||||
use ui::{
|
||||
Chip, ColumnWidthConfig, CommonAnimationExt as _, ContextMenu, ContextMenuEntry, DiffStat,
|
||||
Divider, HeaderResizeInfo, HighlightedLabel, ListItem, ListItemSpacing,
|
||||
Divider, HeaderResizeInfo, HighlightedLabel, IndentGuideColors, ListItem, ListItemSpacing,
|
||||
RedistributableColumnsState, ScrollableHandle, Table, TableInteractionState,
|
||||
TableRenderContext, TableResizeBehavior, Tooltip, WithScrollbar, bind_redistributable_columns,
|
||||
prelude::*, redistribute_hidden_fractions, redistribute_hidden_widths,
|
||||
|
|
@ -73,9 +73,8 @@ const RESIZE_HANDLE_WIDTH: f32 = 8.0;
|
|||
const COPIED_STATE_DURATION: Duration = Duration::from_secs(2);
|
||||
const COMMIT_TAG_LIST_WIDTH_IN_REMS: Rems = rems(10.);
|
||||
const CUSTOM_GIT_COMMANDS_DOCS_SLUG: &str = "tasks#custom-git-commands";
|
||||
const TREE_INDENT: f32 = 20.0;
|
||||
const TABLE_COLUMN_COUNT: usize = 4;
|
||||
// Extra vertical breathing room added to the UI line height when computing
|
||||
// the git graph's row height, so commit dots and lines have space around them.
|
||||
const ROW_VERTICAL_PADDING: Pixels = px(4.0);
|
||||
|
||||
struct CopiedState {
|
||||
|
|
@ -278,8 +277,6 @@ impl ChangedFileEntry {
|
|||
workspace: WeakEntity<Workspace>,
|
||||
_cx: &App,
|
||||
) -> AnyElement {
|
||||
const TREE_INDENT: f32 = 12.0;
|
||||
|
||||
let file_name = self.file_name.clone();
|
||||
let dir_path = self.dir_path.clone();
|
||||
|
||||
|
|
@ -358,8 +355,6 @@ struct ChangedFileDirectoryEntry {
|
|||
|
||||
impl ChangedFileDirectoryEntry {
|
||||
fn render(&self, ix: usize, git_graph: WeakEntity<GitGraph>, cx: &App) -> AnyElement {
|
||||
const TREE_INDENT: f32 = 12.0;
|
||||
|
||||
let path = self.path.clone();
|
||||
let expanded = self.expanded;
|
||||
let folder_icon = FileIcons::get_folder_icon(expanded, path.as_std_path(), cx)
|
||||
|
|
@ -381,22 +376,6 @@ impl ChangedFileDirectoryEntry {
|
|||
.spacing(ListItemSpacing::Sparse)
|
||||
.indent_level(self.depth)
|
||||
.indent_step_size(px(TREE_INDENT))
|
||||
.toggle(Some(expanded))
|
||||
.always_show_disclosure_icon(true)
|
||||
.on_toggle({
|
||||
let path = path.clone();
|
||||
let git_graph = git_graph.clone();
|
||||
move |_, _, cx| {
|
||||
git_graph
|
||||
.update(cx, |git_graph, cx| {
|
||||
git_graph
|
||||
.changed_files_expanded_dirs
|
||||
.insert(path.clone(), !expanded);
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.start_slot(folder_icon)
|
||||
.child(
|
||||
Label::new(self.name.clone())
|
||||
|
|
@ -3018,7 +2997,7 @@ impl GitGraph {
|
|||
};
|
||||
|
||||
CommitAvatar::new(&full_sha, author_email_for_avatar, remote.as_ref())
|
||||
.size(px(40.))
|
||||
.size(px(32.))
|
||||
.render(window, cx)
|
||||
};
|
||||
|
||||
|
|
@ -3056,6 +3035,25 @@ impl GitGraph {
|
|||
Rc::default()
|
||||
};
|
||||
|
||||
let is_tree_view = self.changed_files_view_mode.is_tree();
|
||||
let view_toggle = IconButton::new("toggle-changed-files-view", IconName::ListTree)
|
||||
.icon_size(IconSize::Small)
|
||||
.toggle_state(self.changed_files_view_mode.is_tree())
|
||||
.tooltip({
|
||||
let tooltip = if is_tree_view {
|
||||
"Show Flat View"
|
||||
} else {
|
||||
"Show Tree View"
|
||||
};
|
||||
move |_, cx| Tooltip::for_action(tooltip, &ToggleChangedFilesView, cx)
|
||||
})
|
||||
.on_click(cx.listener(|this, _, _window, cx| {
|
||||
this.changed_files_view_mode = this.changed_files_view_mode.toggled();
|
||||
this.changed_files_scroll_handle
|
||||
.scroll_to_item(0, ScrollStrategy::Top);
|
||||
cx.notify();
|
||||
}));
|
||||
|
||||
v_flex()
|
||||
.min_w(px(300.))
|
||||
.h_full()
|
||||
|
|
@ -3090,17 +3088,12 @@ impl GitGraph {
|
|||
.py_1()
|
||||
.w_full()
|
||||
.items_center()
|
||||
.gap_1()
|
||||
.child(avatar)
|
||||
.child(Label::new(author_name).mt_1p5())
|
||||
.child(
|
||||
v_flex()
|
||||
.items_center()
|
||||
.child(Label::new(author_name))
|
||||
.child(
|
||||
Label::new(date_string)
|
||||
.color(Color::Muted)
|
||||
.size(LabelSize::Small),
|
||||
),
|
||||
Label::new(date_string)
|
||||
.color(Color::Muted)
|
||||
.size(LabelSize::Small),
|
||||
),
|
||||
)
|
||||
.children((!ref_names.is_empty()).then(|| {
|
||||
|
|
@ -3258,69 +3251,40 @@ impl GitGraph {
|
|||
.child(
|
||||
v_flex()
|
||||
.min_w_0()
|
||||
.p_2()
|
||||
.flex_1()
|
||||
.gap_1()
|
||||
.overflow_hidden()
|
||||
.child(
|
||||
h_flex()
|
||||
.p_2()
|
||||
.pr_3()
|
||||
.pb_1()
|
||||
.gap_1()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.child(
|
||||
Label::new(format!(
|
||||
"{} Changed {}",
|
||||
changed_files_count,
|
||||
if changed_files_count == 1 {
|
||||
"File"
|
||||
} else {
|
||||
"Files"
|
||||
}
|
||||
))
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(DiffStat::new(
|
||||
"commit-diff-stat",
|
||||
total_lines_added,
|
||||
total_lines_removed,
|
||||
))
|
||||
.child(
|
||||
IconButton::new(
|
||||
"toggle-changed-files-view",
|
||||
IconName::ListTree,
|
||||
)
|
||||
.shape(ui::IconButtonShape::Square)
|
||||
.icon_size(IconSize::Small)
|
||||
.toggle_state(self.changed_files_view_mode.is_tree())
|
||||
.tooltip({
|
||||
let tooltip = if self.changed_files_view_mode.is_tree()
|
||||
{
|
||||
"Show Flat View"
|
||||
Label::new(format!(
|
||||
"{} Changed {}",
|
||||
changed_files_count,
|
||||
if changed_files_count == 1 {
|
||||
"File"
|
||||
} else {
|
||||
"Show Tree View"
|
||||
};
|
||||
move |_, cx| {
|
||||
Tooltip::for_action(
|
||||
tooltip,
|
||||
&ToggleChangedFilesView,
|
||||
cx,
|
||||
)
|
||||
"Files"
|
||||
}
|
||||
})
|
||||
.on_click(
|
||||
cx.listener(|this, _, _window, cx| {
|
||||
this.changed_files_view_mode =
|
||||
this.changed_files_view_mode.toggled();
|
||||
this.changed_files_scroll_handle
|
||||
.scroll_to_item(0, ScrollStrategy::Top);
|
||||
cx.notify();
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
))
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child(Divider::vertical())
|
||||
.child(view_toggle),
|
||||
)
|
||||
.child(DiffStat::new(
|
||||
"commit-diff-stat",
|
||||
total_lines_added,
|
||||
total_lines_removed,
|
||||
)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
|
|
@ -3329,7 +3293,7 @@ impl GitGraph {
|
|||
.min_h_0()
|
||||
.child({
|
||||
let flat_entries = changed_file_entries;
|
||||
let is_tree_view = self.changed_files_view_mode.is_tree();
|
||||
|
||||
let entry_count = if is_tree_view {
|
||||
tree_entries.len()
|
||||
} else {
|
||||
|
|
@ -3339,6 +3303,8 @@ impl GitGraph {
|
|||
let repository = repository.downgrade();
|
||||
let workspace = self.workspace.clone();
|
||||
let git_graph = cx.weak_entity();
|
||||
let indent_tree_entries = tree_entries.clone();
|
||||
|
||||
uniform_list(
|
||||
"changed-files-list",
|
||||
entry_count,
|
||||
|
|
@ -3381,8 +3347,34 @@ impl GitGraph {
|
|||
.collect()
|
||||
},
|
||||
)
|
||||
.when(is_tree_view, |list| {
|
||||
list.with_decoration(
|
||||
ui::indent_guides(
|
||||
px(TREE_INDENT),
|
||||
IndentGuideColors::panel(cx),
|
||||
)
|
||||
.with_left_offset(
|
||||
ui::LIST_ITEM_INDENT_GUIDE_LEFT_OFFSET - px(2.),
|
||||
)
|
||||
.with_compute_indents_fn(
|
||||
cx.entity(),
|
||||
move |_, range, _window, _cx| {
|
||||
range
|
||||
.map(|ix| match indent_tree_entries.get(ix) {
|
||||
Some(ChangedFileTreeEntry::Directory(
|
||||
entry,
|
||||
)) => entry.depth,
|
||||
Some(ChangedFileTreeEntry::File(entry)) => {
|
||||
entry.depth
|
||||
}
|
||||
None => 0,
|
||||
})
|
||||
.collect()
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
.size_full()
|
||||
.ml_neg_1()
|
||||
.track_scroll(&self.changed_files_scroll_handle)
|
||||
})
|
||||
.vertical_scrollbar_for(&self.changed_files_scroll_handle, window, cx),
|
||||
|
|
@ -3393,6 +3385,11 @@ impl GitGraph {
|
|||
h_flex().p_1p5().w_full().child(
|
||||
Button::new("view-commit", "View Commit")
|
||||
.full_width()
|
||||
.start_icon(
|
||||
Icon::new(IconName::GitCommit)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.style(ButtonStyle::OutlinedGhost)
|
||||
.on_click(cx.listener(|this, _, window, cx| {
|
||||
this.open_selected_commit_view(window, cx);
|
||||
|
|
@ -3912,22 +3909,26 @@ impl GitGraph {
|
|||
// which causes problems with text reflow when using flexbox.
|
||||
// grid, on the other hand, doesn't appear to give taffy the same
|
||||
// problems.
|
||||
.grid()
|
||||
.w_full()
|
||||
.max_h(line_height * 12.)
|
||||
.py_2()
|
||||
.pl_2()
|
||||
.w_full()
|
||||
.gap_1()
|
||||
.grid()
|
||||
.grid_cols(1)
|
||||
// Value of 12 taken from ./commit_view.rs:725
|
||||
.max_h(line_height * 12.)
|
||||
.gap_1()
|
||||
.child(
|
||||
div()
|
||||
.id("commit-message")
|
||||
.text_sm()
|
||||
.relative()
|
||||
.size_full()
|
||||
.overflow_y_scroll()
|
||||
.track_scroll(scroll_handle)
|
||||
.child(MarkdownElement::new(message.clone(), message_style))
|
||||
.child(
|
||||
div()
|
||||
.id("commit-message")
|
||||
.text_sm()
|
||||
.size_full()
|
||||
.overflow_y_scroll()
|
||||
.track_scroll(scroll_handle)
|
||||
.child(MarkdownElement::new(message.clone(), message_style)),
|
||||
)
|
||||
.vertical_scrollbar_for(scroll_handle, window, cx),
|
||||
)
|
||||
.into_any_element()
|
||||
|
|
@ -3961,11 +3962,10 @@ impl Render for GitGraph {
|
|||
let label = Label::new(message)
|
||||
.color(Color::Muted)
|
||||
.size(LabelSize::Large);
|
||||
div()
|
||||
|
||||
h_flex()
|
||||
.size_full()
|
||||
.h_flex()
|
||||
.gap_1()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.child(label)
|
||||
.when(is_loading && error.is_none(), |this| {
|
||||
|
|
@ -4013,7 +4013,7 @@ impl Render for GitGraph {
|
|||
h_flex()
|
||||
.size_full()
|
||||
.child(
|
||||
div()
|
||||
v_flex()
|
||||
.flex_1()
|
||||
.min_w_0()
|
||||
.size_full()
|
||||
|
|
|
|||
|
|
@ -39,11 +39,10 @@ use git::{
|
|||
ViewFile, parse_git_remote_url,
|
||||
};
|
||||
use gpui::{
|
||||
AbsoluteLength, Action, Anchor, AnyElement, AsyncApp, AsyncWindowContext, Bounds, ClickEvent,
|
||||
AbsoluteLength, Action, Anchor, AnyElement, AsyncApp, AsyncWindowContext, ClickEvent,
|
||||
DismissEvent, Empty, Entity, EventEmitter, FocusHandle, Focusable, KeyContext, MouseButton,
|
||||
MouseDownEvent, Pixels, Point, PromptLevel, ScrollStrategy, Subscription, Task, TaskExt,
|
||||
TextStyle, UniformListScrollHandle, WeakEntity, actions, anchored, deferred, point, size,
|
||||
uniform_list,
|
||||
TextStyle, UniformListScrollHandle, WeakEntity, actions, anchored, deferred, uniform_list,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use language::{Buffer, BufferEvent, File};
|
||||
|
|
@ -82,9 +81,8 @@ use theme_settings::ThemeSettings;
|
|||
use time::OffsetDateTime;
|
||||
use ui::{
|
||||
ButtonLike, Checkbox, ContextMenu, ContextMenuEntry, Divider, ElevationIndex,
|
||||
IndentGuideColors, KeyBinding, PopoverMenu, PopoverMenuHandle, ProjectEmptyState,
|
||||
RenderedIndentGuide, ScrollAxes, Scrollbars, SplitButton, Tab, TintColor, Tooltip,
|
||||
WithScrollbar, prelude::*,
|
||||
IndentGuideColors, KeyBinding, PopoverMenu, PopoverMenuHandle, ProjectEmptyState, ScrollAxes,
|
||||
Scrollbars, SplitButton, Tab, TintColor, Tooltip, WithScrollbar, prelude::*,
|
||||
};
|
||||
use util::paths::PathStyle;
|
||||
use util::{ResultExt, TryFutureExt, markdown::MarkdownInlineCode, maybe, rel_path::RelPath};
|
||||
|
|
@ -100,6 +98,8 @@ const GIT_PANEL_KEY: &str = "GitPanel";
|
|||
const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
|
||||
// TODO: We should revise this part. It seems the indentation width is not aligned with the one in project panel
|
||||
const TREE_INDENT: f32 = 16.0;
|
||||
// Horizontal offset that aligns the tree indent guides with the row icon column.
|
||||
const INDENT_GUIDE_LEFT_OFFSET: gpui::Pixels = gpui::px(19.);
|
||||
|
||||
actions!(
|
||||
git_panel,
|
||||
|
|
@ -6381,43 +6381,15 @@ impl GitPanel {
|
|||
}),
|
||||
)
|
||||
.when(is_tree_view, |list| {
|
||||
let indent_size = px(TREE_INDENT);
|
||||
list.with_decoration(
|
||||
ui::indent_guides(indent_size, IndentGuideColors::panel(cx))
|
||||
ui::indent_guides(px(TREE_INDENT), IndentGuideColors::panel(cx))
|
||||
.with_left_offset(INDENT_GUIDE_LEFT_OFFSET)
|
||||
.with_compute_indents_fn(
|
||||
cx.entity(),
|
||||
|this, range, _window, _cx| {
|
||||
this.compute_visible_depths(range)
|
||||
},
|
||||
)
|
||||
.with_render_fn(cx.entity(), |_, params, _, _| {
|
||||
// Magic number to align the tree item is 3 here
|
||||
// because we're using 12px as the left-side padding
|
||||
// and 3 makes the alignment work with the bounding box of the icon
|
||||
let left_offset = px(TREE_INDENT + 3_f32);
|
||||
let indent_size = params.indent_size;
|
||||
let item_height = params.item_height;
|
||||
|
||||
params
|
||||
.indent_guides
|
||||
.into_iter()
|
||||
.map(|layout| {
|
||||
let bounds = Bounds::new(
|
||||
point(
|
||||
layout.offset.x * indent_size + left_offset,
|
||||
layout.offset.y * item_height,
|
||||
),
|
||||
size(px(1.), layout.length * item_height),
|
||||
);
|
||||
RenderedIndentGuide {
|
||||
bounds,
|
||||
layout,
|
||||
is_active: false,
|
||||
hitbox: None,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
),
|
||||
)
|
||||
})
|
||||
.group("entries")
|
||||
|
|
|
|||
|
|
@ -799,6 +799,8 @@ impl Render for ProjectDiffToolbar {
|
|||
let (additions, deletions) = project_diff.read(cx).calculate_changed_lines(cx);
|
||||
let is_multibuffer_empty = project_diff.read(cx).multibuffer(cx).read(cx).is_empty();
|
||||
|
||||
let stage_all_button_width = rems(5.);
|
||||
|
||||
h_flex()
|
||||
.my_neg_1()
|
||||
.py_1()
|
||||
|
|
@ -894,7 +896,7 @@ impl Render for ProjectDiffToolbar {
|
|||
|this| {
|
||||
this.child(
|
||||
Button::new("unstage-all", "Unstage All")
|
||||
.width(rems_from_px(80.))
|
||||
.width(stage_all_button_width)
|
||||
.tooltip(Tooltip::for_action_title_in(
|
||||
"Unstage All Changes",
|
||||
&UnstageAll,
|
||||
|
|
@ -911,7 +913,7 @@ impl Render for ProjectDiffToolbar {
|
|||
|this| {
|
||||
this.child(
|
||||
Button::new("stage-all", "Stage All")
|
||||
.width(rems_from_px(80.))
|
||||
.width(stage_all_button_width)
|
||||
.disabled(!button_states.stage_all)
|
||||
.tooltip(Tooltip::for_action_title_in(
|
||||
"Stage All Changes",
|
||||
|
|
|
|||
|
|
@ -4752,7 +4752,7 @@ impl OutlinePanel {
|
|||
}
|
||||
})
|
||||
.with_render_fn(cx.entity(), move |outline_panel, params, _, _| {
|
||||
const LEFT_OFFSET: Pixels = px(14.);
|
||||
const LEFT_OFFSET: Pixels = ui::LIST_ITEM_INDENT_GUIDE_LEFT_OFFSET;
|
||||
|
||||
let indent_size = params.indent_size;
|
||||
let item_height = params.item_height;
|
||||
|
|
|
|||
|
|
@ -7083,7 +7083,8 @@ impl Render for ProjectPanel {
|
|||
.with_render_fn(
|
||||
cx.entity(),
|
||||
move |this, params, _, cx| {
|
||||
const LEFT_OFFSET: Pixels = px(14.);
|
||||
const LEFT_OFFSET: Pixels =
|
||||
ui::LIST_ITEM_INDENT_GUIDE_LEFT_OFFSET;
|
||||
const PADDING_Y: Pixels = px(4.);
|
||||
const HITBOX_OVERDRAW: Pixels = px(3.);
|
||||
|
||||
|
|
@ -7179,7 +7180,8 @@ impl Render for ProjectPanel {
|
|||
.with_render_fn(
|
||||
cx.entity(),
|
||||
move |_, params, _, _| {
|
||||
const LEFT_OFFSET: Pixels = px(14.);
|
||||
const LEFT_OFFSET: Pixels =
|
||||
ui::LIST_ITEM_INDENT_GUIDE_LEFT_OFFSET;
|
||||
|
||||
let indent_size = params.indent_size;
|
||||
let item_height = params.item_height;
|
||||
|
|
|
|||
|
|
@ -750,13 +750,11 @@ pub fn render_table_header(
|
|||
let shared_element_id: SharedString = format!("table-{}", element_id).into();
|
||||
let pinned_cols = table_context.pinned_cols;
|
||||
|
||||
let outer = div()
|
||||
.flex()
|
||||
.flex_row()
|
||||
.items_center()
|
||||
let outer = h_flex()
|
||||
.py_1()
|
||||
.w_full()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border);
|
||||
.border_color(cx.theme().colors().border_variant);
|
||||
|
||||
let use_ui_font = table_context.use_ui_font;
|
||||
let resize_info_ref = resize_info.as_ref();
|
||||
|
|
|
|||
|
|
@ -28,9 +28,14 @@ impl IndentGuideColors {
|
|||
}
|
||||
}
|
||||
|
||||
/// Horizontal offset that lines an indent guide up with the icon column of a
|
||||
/// standard [`ListItem`](crate::ListItem)-based row.
|
||||
pub const LIST_ITEM_INDENT_GUIDE_LEFT_OFFSET: Pixels = px(15.);
|
||||
|
||||
pub struct IndentGuides {
|
||||
colors: IndentGuideColors,
|
||||
indent_size: Pixels,
|
||||
left_offset: Pixels,
|
||||
compute_indents_fn:
|
||||
Option<Box<dyn Fn(Range<usize>, &mut Window, &mut App) -> SmallVec<[usize; 64]>>>,
|
||||
render_fn: Option<
|
||||
|
|
@ -49,6 +54,7 @@ pub fn indent_guides(indent_size: Pixels, colors: IndentGuideColors) -> IndentGu
|
|||
IndentGuides {
|
||||
colors,
|
||||
indent_size,
|
||||
left_offset: px(0.),
|
||||
compute_indents_fn: None,
|
||||
render_fn: None,
|
||||
on_click: None,
|
||||
|
|
@ -56,6 +62,15 @@ pub fn indent_guides(indent_size: Pixels, colors: IndentGuideColors) -> IndentGu
|
|||
}
|
||||
|
||||
impl IndentGuides {
|
||||
/// Sets a horizontal offset applied to every guide, used to line the guides
|
||||
/// up with the icon column of the list's rows. Ignored when a custom render
|
||||
/// function is set via [`Self::with_render_fn`], which is responsible for its
|
||||
/// own positioning.
|
||||
pub fn with_left_offset(mut self, left_offset: Pixels) -> Self {
|
||||
self.left_offset = left_offset;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the callback that will be called when the user clicks on an indent guide.
|
||||
pub fn on_click(
|
||||
mut self,
|
||||
|
|
@ -124,7 +139,7 @@ impl IndentGuides {
|
|||
.map(|layout| RenderedIndentGuide {
|
||||
bounds: Bounds::new(
|
||||
point(
|
||||
layout.offset.x * self.indent_size,
|
||||
layout.offset.x * self.indent_size + self.left_offset,
|
||||
layout.offset.y * item_height,
|
||||
),
|
||||
size(px(1.), layout.length * item_height),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue