Skip to content

Commit 34b8e83

Browse files
committed
refine chart resolution and parameter spacing
1 parent 1b8405b commit 34b8e83

3 files changed

Lines changed: 48 additions & 6 deletions

File tree

‎sharp_frames/ui/screens/selection.py‎

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class SharpnessChart(ScrollView):
3333
"""Horizontally scrollable frame-by-frame sharpness timeline."""
3434

3535
FRAME_STRIDE = 2
36+
BAR_GLYPHS = (" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█")
37+
VERTICAL_SUBDIVISIONS = len(BAR_GLYPHS) - 1
3638
can_focus = True
3739

3840
BINDINGS = [
@@ -53,7 +55,7 @@ class SharpnessChart(ScrollView):
5355

5456
DEFAULT_CSS = """
5557
SharpnessChart {
56-
height: 12;
58+
height: 13;
5759
width: 100%;
5860
border: solid $primary;
5961
margin: 1 0;
@@ -212,16 +214,30 @@ def _render_timeline_column(
212214

213215
frame = self.frames[frame_position]
214216
normalized = (frame.sharpness_score - self.min_score) / self.score_range
215-
bar_height = 1 + int(normalized * (chart_height - 1))
216-
if (chart_height - 1 - chart_y) >= bar_height:
217+
glyph = self._bar_glyph(normalized, chart_y, chart_height)
218+
if glyph == " ":
217219
return Segment(" ", blank_style)
218220

219221
style = (
220222
selected_style
221223
if frame.index in self.selected_indices
222224
else unselected_style
223225
)
224-
return Segment("█", style)
226+
return Segment(glyph, style)
227+
228+
@classmethod
229+
def _bar_glyph(
230+
cls, normalized: float, chart_y: int, chart_height: int
231+
) -> str:
232+
"""Render a bar cell with eighth-row vertical precision."""
233+
subdivisions = cls.VERTICAL_SUBDIVISIONS
234+
available_units = max(chart_height * subdivisions, 1)
235+
clamped = max(0.0, min(float(normalized), 1.0))
236+
filled_units = max(1, int((clamped * available_units) + 0.5))
237+
row_from_bottom = chart_height - 1 - chart_y
238+
units_in_row = filled_units - (row_from_bottom * subdivisions)
239+
units_in_row = max(0, min(units_in_row, subdivisions))
240+
return cls.BAR_GLYPHS[units_in_row]
225241

226242
def _visible_frame_range(self, width: int) -> tuple[int, int]:
227243
"""Return the frame positions represented by the visible viewport."""

‎sharp_frames/ui/styles.py‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@
421421
422422
/* Sharpness chart */
423423
SharpnessChart {
424-
height: 12;
424+
height: 13;
425425
width: 100%;
426426
border: solid $primary;
427427
margin: 1 0;
@@ -488,6 +488,25 @@
488488
margin: 0 0 1 0;
489489
}
490490
491+
/* Keep the parameter panel dense so its controls sit close to the title and
492+
the panel does not leave an oversized empty footer. */
493+
#parameter_container {
494+
padding: 1 2 0 1;
495+
min-height: 10;
496+
}
497+
498+
#parameter_container .control_label,
499+
#parameter_container .parameter_inputs,
500+
#parameter_container .param_label,
501+
#parameter_container .param_input_with_controls,
502+
#parameter_container InputWithControls {
503+
margin: 0;
504+
}
505+
506+
#parameter_container .parameter_inputs {
507+
min-height: 0;
508+
}
509+
491510
InputWithControls Input {
492511
width: 20;
493512
margin: 0 1 0 0;

‎tests/ui/test_selection_screen.py‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@ def test_chart_normalizes_scores_without_discarding_frames(extraction_result):
185185
assert chart.border_title == "Frame selection"
186186

187187

188+
def test_chart_uses_fractional_blocks_for_sub_row_precision():
189+
assert SharpnessChart._bar_glyph(0.0, chart_y=2, chart_height=3) == "▁"
190+
assert SharpnessChart._bar_glyph(1.0, chart_y=0, chart_height=3) == "█"
191+
assert SharpnessChart._bar_glyph(0.5, chart_y=1, chart_height=3) == "▄"
192+
assert SharpnessChart._bar_glyph(0.5, chart_y=0, chart_height=3) == " "
193+
194+
188195
@pytest.mark.asyncio
189196
async def test_chart_scrolls_across_thousands_of_frames():
190197
frames = [
@@ -220,7 +227,7 @@ def compose(self) -> ComposeResult:
220227
for segment in title_line
221228
)
222229
bottom_line = chart.render_line(chart.scrollable_content_region.height - 1)
223-
assert bottom_line.text[:8] == "█ █ █ █ "
230+
assert bottom_line.text[:8] == "▁ ▁ ▁ ▁ "
224231

225232
chart.focus()
226233
await pilot.press("right")

0 commit comments

Comments
 (0)