Misc code cleanup

This commit is contained in:
Emil Ernerfeldt 2020-12-16 21:59:33 +01:00
parent 56502405f5
commit e4afba3bb8
3 changed files with 98 additions and 87 deletions

View file

@ -63,18 +63,15 @@ impl State {
add_contents: impl FnOnce(&mut Ui) -> R,
) -> Option<(R, Response)> {
let openness = self.openness(ui.ctx(), id);
let animate = 0.0 < openness && openness < 1.0;
if animate {
if openness <= 0.0 {
None
} else if openness < 1.0 {
Some(ui.wrap(|child_ui| {
let max_height = if self.open {
if let Some(full_height) = self.open_height {
remap_clamp(openness, 0.0..=1.0, 0.0..=full_height)
} else {
// First frame of expansion.
// We don't know full height yet, but we will next frame.
// Just use a placeholder value that shows some movement:
10.0
}
let max_height = if self.open && self.open_height.is_none() {
// First frame of expansion.
// We don't know full height yet, but we will next frame.
// Just use a placeholder value that shows some movement:
10.0
} else {
let full_height = self.open_height.unwrap_or_default();
remap_clamp(openness, 0.0..=1.0, 0.0..=full_height)
@ -84,23 +81,21 @@ impl State {
clip_rect.max.y = clip_rect.max.y.min(child_ui.max_rect().top() + max_height);
child_ui.set_clip_rect(clip_rect);
let r = add_contents(child_ui);
let ret = add_contents(child_ui);
self.open_height = Some(child_ui.min_size().y);
// Pretend children took up less space:
let mut min_rect = child_ui.min_rect();
min_rect.max.y = min_rect.max.y.min(min_rect.top() + max_height);
self.open_height = Some(min_rect.height());
// Pretend children took up at most `max_height` space:
min_rect.max.y = min_rect.max.y.at_most(min_rect.top() + max_height);
child_ui.force_set_min_rect(min_rect);
r
ret
}))
} else if self.open || ui.memory().all_collpasing_are_open {
} else {
let (ret, response) = ui.wrap(add_contents);
let full_size = response.rect.size();
self.open_height = Some(full_size.y);
Some((ret, response))
} else {
None
}
}
}

View file

@ -25,7 +25,7 @@ pub struct Window<'open> {
}
impl<'open> Window<'open> {
// TODO: Into<Label>
/// The winodw title must be unique, and should not change.
pub fn new(title: impl Into<String>) -> Self {
let title = title.into();
let area = Area::new(&title);
@ -40,7 +40,7 @@ impl<'open> Window<'open> {
resize: Resize::default()
.with_stroke(false)
.min_size([96.0, 32.0])
.default_size([420.0, 420.0]),
.default_size([420.0, 420.0]), // Default inner size of a winodw
scroll: None,
collapsible: true,
}
@ -219,10 +219,6 @@ impl<'open> Window<'open> {
// First interact (move etc) to avoid frame delay:
let last_frame_outer_rect = area.state().rect();
let interaction = if possible.movable || possible.resizable {
let title_bar_height = title_label.font_height(ctx.fonts(), &ctx.style())
+ 1.0 * ctx.style().spacing.item_spacing.y; // this could be better
let margins = 2.0 * frame.margin + vec2(0.0, title_bar_height);
window_interaction(
ctx,
possible,
@ -231,6 +227,11 @@ impl<'open> Window<'open> {
last_frame_outer_rect,
)
.and_then(|window_interaction| {
// Calculate roughly how much larger the window size is compared to the inner rect
let title_bar_height = title_label.font_height(ctx.fonts(), &ctx.style())
+ 1.0 * ctx.style().spacing.item_spacing.y; // this could be better
let margins = 2.0 * frame.margin + vec2(0.0, title_bar_height);
interact(
window_interaction,
ctx,
@ -276,9 +277,9 @@ impl<'open> Window<'open> {
ui.allocate_space(ui.style().spacing.item_spacing);
if let Some(scroll) = scroll {
scroll.show(ui, add_contents)
scroll.show(ui, add_contents);
} else {
add_contents(ui)
add_contents(ui);
}
})
})
@ -685,6 +686,7 @@ impl TitleBar {
let left = outer_rect.left();
let right = outer_rect.right();
let y = content_response.rect.top() + ui.style().spacing.item_spacing.y * 0.5;
// let y = lerp(self.rect.bottom()..=content_response.rect.top(), 0.5);
ui.painter().line_segment(
[pos2(left, y), pos2(right, y)],
ui.style().visuals.widgets.inactive.bg_stroke,

View file

@ -673,10 +673,10 @@ fn mul_color(color: Srgba, factor: f32) -> Srgba {
/// * `scratchpad_path`: if you plan to run `tessellate_paint_command`
/// many times, pass it a reference to the same `Path` to avoid excessive allocations.
fn tessellate_paint_command(
clip_rect: Rect,
command: PaintCmd,
options: TesselationOptions,
fonts: &Fonts,
clip_rect: Rect,
command: PaintCmd,
out: &mut Triangles,
scratchpad_points: &mut Vec<Pos2>,
scratchpad_path: &mut Path,
@ -773,63 +773,77 @@ fn tessellate_paint_command(
text_style,
color,
} => {
if color == TRANSPARENT {
return;
}
galley.sanity_check();
let num_chars = galley.text.chars().count();
out.reserve_triangles(num_chars * 2);
out.reserve_vertices(num_chars * 4);
let tex_w = fonts.texture().width as f32;
let tex_h = fonts.texture().height as f32;
let text_offset = vec2(0.0, 1.0); // Eye-balled for buttons. TODO: why is this needed?
let clip_rect = clip_rect.expand(2.0); // Some fudge to handle letters that are slightly larger than expected.
let font = &fonts[text_style];
let mut chars = galley.text.chars();
for line in &galley.rows {
let line_min_y = pos.y + line.y_min + text_offset.x;
let line_max_y = line_min_y + font.row_height();
let is_line_visible =
line_max_y >= clip_rect.min.y && line_min_y <= clip_rect.max.y;
for x_offset in line.x_offsets.iter().take(line.x_offsets.len() - 1) {
let c = chars.next().unwrap();
if options.coarse_tessellation_culling && !is_line_visible {
// culling individual lines of text is important, since a single `PaintCmd::Text`
// can span hundreds of lines.
continue;
}
if let Some(glyph) = font.uv_rect(c) {
let mut left_top =
pos + glyph.offset + vec2(*x_offset, line.y_min) + text_offset;
left_top.x = font.round_to_pixel(left_top.x); // Pixel-perfection.
left_top.y = font.round_to_pixel(left_top.y); // Pixel-perfection.
let pos = Rect::from_min_max(left_top, left_top + glyph.size);
let uv = Rect::from_min_max(
pos2(glyph.min.0 as f32 / tex_w, glyph.min.1 as f32 / tex_h),
pos2(glyph.max.0 as f32 / tex_w, glyph.max.1 as f32 / tex_h),
);
out.add_rect_with_uv(pos, uv, color);
}
}
if line.ends_with_newline {
let newline = chars.next().unwrap();
debug_assert_eq!(newline, '\n');
}
}
assert_eq!(chars.next(), None);
tesselate_text(
options, fonts, clip_rect, pos, &galley, text_style, color, out,
);
}
}
}
#[allow(clippy::too_many_arguments)]
fn tesselate_text(
options: TesselationOptions,
fonts: &Fonts,
clip_rect: Rect,
pos: Pos2,
galley: &super::Galley,
text_style: super::TextStyle,
color: Srgba,
out: &mut Triangles,
) {
if color == TRANSPARENT {
return;
}
galley.sanity_check();
let num_chars = galley.text.chars().count();
out.reserve_triangles(num_chars * 2);
out.reserve_vertices(num_chars * 4);
let tex_w = fonts.texture().width as f32;
let tex_h = fonts.texture().height as f32;
let text_offset = vec2(0.0, 1.0); // Eye-balled for buttons. TODO: why is this needed?
let clip_rect = clip_rect.expand(2.0); // Some fudge to handle letters that are slightly larger than expected.
let font = &fonts[text_style];
let mut chars = galley.text.chars();
for line in &galley.rows {
let line_min_y = pos.y + line.y_min + text_offset.x;
let line_max_y = line_min_y + font.row_height();
let is_line_visible = line_max_y >= clip_rect.min.y && line_min_y <= clip_rect.max.y;
for x_offset in line.x_offsets.iter().take(line.x_offsets.len() - 1) {
let c = chars.next().unwrap();
if options.coarse_tessellation_culling && !is_line_visible {
// culling individual lines of text is important, since a single `PaintCmd::Text`
// can span hundreds of lines.
continue;
}
if let Some(glyph) = font.uv_rect(c) {
let mut left_top = pos + glyph.offset + vec2(*x_offset, line.y_min) + text_offset;
left_top.x = font.round_to_pixel(left_top.x); // Pixel-perfection.
left_top.y = font.round_to_pixel(left_top.y); // Pixel-perfection.
let pos = Rect::from_min_max(left_top, left_top + glyph.size);
let uv = Rect::from_min_max(
pos2(glyph.min.0 as f32 / tex_w, glyph.min.1 as f32 / tex_h),
pos2(glyph.max.0 as f32 / tex_w, glyph.max.1 as f32 / tex_h),
);
out.add_rect_with_uv(pos, uv, color);
}
}
if line.ends_with_newline {
let newline = chars.next().unwrap();
debug_assert_eq!(newline, '\n');
}
}
assert_eq!(chars.next(), None);
}
/// Turns `PaintCmd`:s into sets of triangles.
///
/// The given commands will be painted back-to-front (painters algorithm).
@ -862,10 +876,10 @@ pub fn tessellate_paint_commands(
let out = &mut jobs.last_mut().unwrap().1;
tessellate_paint_command(
clip_rect,
cmd,
options,
fonts,
clip_rect,
cmd,
out,
&mut scratchpad_points,
&mut scratchpad_path,
@ -875,6 +889,8 @@ pub fn tessellate_paint_commands(
if options.debug_paint_clip_rects {
for (clip_rect, triangles) in &mut jobs {
tessellate_paint_command(
options,
fonts,
Rect::everything(),
PaintCmd::Rect {
rect: *clip_rect,
@ -882,8 +898,6 @@ pub fn tessellate_paint_commands(
fill: Default::default(),
stroke: Stroke::new(2.0, srgba(150, 255, 150, 255)),
},
options,
fonts,
triangles,
&mut scratchpad_points,
&mut scratchpad_path,