diff --git a/CHANGELOG.md b/CHANGELOG.md index bf81afa0b7..76006efc24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `SelectionList` option IDs are usable as soon as the widget is instantiated https://github.com/Textualize/textual/issues/3903 - Fix issue with `Strip.crop` when crop window start aligned with strip end https://github.com/Textualize/textual/pull/3998 - Fixed Strip.crop_extend https://github.com/Textualize/textual/pull/4011 +- Fix for percentage dimensions https://github.com/Textualize/textual/pull/4037 - Fixed a crash if the `TextArea` language was set but tree-sitter language binaries were not installed https://github.com/Textualize/textual/issues/4045 - Ensuring `TextArea.SelectionChanged` message only sends when the updated selection is different https://github.com/Textualize/textual/pull/3933 - Fixed declaration after nested rule set causing a parse error https://github.com/Textualize/textual/pull/4012 diff --git a/src/textual/_arrange.py b/src/textual/_arrange.py index 87879573af..97d8abbe4a 100644 --- a/src/textual/_arrange.py +++ b/src/textual/_arrange.py @@ -160,5 +160,4 @@ def _arrange_dock_widgets( _WidgetPlacement(dock_region, null_spacing, dock_widget, top_z, True) ) dock_spacing = Spacing(top, right, bottom, left) - return (placements, dock_spacing) diff --git a/src/textual/css/scalar.py b/src/textual/css/scalar.py index 044fce1161..0ef332c571 100644 --- a/src/textual/css/scalar.py +++ b/src/textual/css/scalar.py @@ -37,8 +37,6 @@ class Unit(Enum): AUTO = 8 -UNIT_EXCLUDES_BORDER = {Unit.CELLS, Unit.FRACTION, Unit.VIEW_WIDTH, Unit.VIEW_HEIGHT} - UNIT_SYMBOL = { Unit.CELLS: "", Unit.FRACTION: "fr", @@ -206,10 +204,6 @@ def is_fraction(self) -> bool: """Check if the unit is a fraction.""" return self.unit == Unit.FRACTION - @property - def excludes_border(self) -> bool: - return self.unit in UNIT_EXCLUDES_BORDER - @property def cells(self) -> int | None: """Check if the unit is explicit cells.""" diff --git a/src/textual/layouts/horizontal.py b/src/textual/layouts/horizontal.py index 9d5697f0fe..02672ae879 100644 --- a/src/textual/layouts/horizontal.py +++ b/src/textual/layouts/horizontal.py @@ -26,7 +26,9 @@ def arrange( add_placement = placements.append child_styles = [child.styles for child in children] - box_margins: list[Spacing] = [styles.margin for styles in child_styles] + box_margins: list[Spacing] = [ + styles.margin for styles in child_styles if styles.overlay != "screen" + ] if box_margins: resolve_margin = Size( sum( @@ -36,7 +38,7 @@ def arrange( ] ) + (box_margins[0].left + box_margins[-1].right), - max( + min( [ margin_top + margin_bottom for margin_top, _, margin_bottom, _ in box_margins diff --git a/src/textual/layouts/vertical.py b/src/textual/layouts/vertical.py index a81518f1d2..995b135439 100644 --- a/src/textual/layouts/vertical.py +++ b/src/textual/layouts/vertical.py @@ -29,7 +29,7 @@ def arrange( ] if box_margins: resolve_margin = Size( - max( + min( [ margin_right + margin_left for _, margin_right, _, margin_left in box_margins diff --git a/src/textual/widget.py b/src/textual/widget.py index d5d01d99b2..943df445fd 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -1071,8 +1071,6 @@ def _get_box_model( # Container minus padding and border content_container = container - gutter.totals - # The container including the content - sizing_container = content_container if is_border_box else container if styles.width is None: # No width specified, fill available space @@ -1080,9 +1078,7 @@ def _get_box_model( elif is_auto_width: # When width is auto, we want enough space to always fit the content content_width = Fraction( - self.get_content_width( - content_container - styles.margin.totals, viewport - ) + self.get_content_width(content_container - margin.totals, viewport) ) if styles.scrollbar_gutter == "stable" and styles.overflow_x == "auto": content_width += styles.scrollbar_size_vertical @@ -1095,15 +1091,15 @@ def _get_box_model( # An explicit width styles_width = styles.width content_width = styles_width.resolve( - sizing_container - styles.margin.totals, viewport, width_fraction + container - margin.totals, viewport, width_fraction ) - if is_border_box and styles_width.excludes_border: + if is_border_box: content_width -= gutter.width if styles.min_width is not None: # Restrict to minimum width, if set min_width = styles.min_width.resolve( - content_container, viewport, width_fraction + container - margin.totals, viewport, width_fraction ) if is_border_box: min_width -= gutter.width @@ -1112,7 +1108,7 @@ def _get_box_model( if styles.max_width is not None: # Restrict to maximum width, if set max_width = styles.max_width.resolve( - content_container, viewport, width_fraction + container - margin.totals, viewport, width_fraction ) if is_border_box: max_width -= gutter.width @@ -1139,15 +1135,15 @@ def _get_box_model( styles_height = styles.height # Explicit height set content_height = styles_height.resolve( - sizing_container - styles.margin.totals, viewport, height_fraction + container - margin.totals, viewport, height_fraction ) - if is_border_box and styles_height.excludes_border: + if is_border_box: content_height -= gutter.height if styles.min_height is not None: # Restrict to minimum height, if set min_height = styles.min_height.resolve( - content_container, viewport, height_fraction + container - margin.totals, viewport, height_fraction ) if is_border_box: min_height -= gutter.height @@ -1156,7 +1152,7 @@ def _get_box_model( if styles.max_height is not None: # Restrict maximum height, if set max_height = styles.max_height.resolve( - content_container, viewport, height_fraction + container - margin.totals, viewport, height_fraction ) if is_border_box: max_height -= gutter.height diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index 423e981e67..5824f20be7 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -19466,6 +19466,166 @@ ''' # --- +# name: test_input_percentage_width + ''' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + InputVsTextArea + + + + + + + + + + 01234567890123456789012345678901234567890123456789012345678901234567890123456789 + ────────────────────────────────────── + + + + ────────────────────────────────────── + ────────────────────────────────────── + + + + + ────────────────────────────────────── + ────────────────────────────────────── + + + + + ────────────────────────────────────── + ────────────────────────────────────── + + Button + + + ────────────────────────────────────── + + + + + ''' +# --- # name: test_input_suggestions ''' @@ -20286,136 +20446,136 @@ font-weight: 700; } - .terminal-2540665408-matrix { + .terminal-3085198851-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2540665408-title { + .terminal-3085198851-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2540665408-r1 { fill: #c5c8c6 } - .terminal-2540665408-r2 { fill: #e3e3e3 } - .terminal-2540665408-r3 { fill: #e1e1e1 } - .terminal-2540665408-r4 { fill: #ff0000 } - .terminal-2540665408-r5 { fill: #dde8f3;font-weight: bold } - .terminal-2540665408-r6 { fill: #ddedf9 } + .terminal-3085198851-r1 { fill: #c5c8c6 } + .terminal-3085198851-r2 { fill: #e3e3e3 } + .terminal-3085198851-r3 { fill: #e1e1e1 } + .terminal-3085198851-r4 { fill: #ff0000 } + .terminal-3085198851-r5 { fill: #dde8f3;font-weight: bold } + .terminal-3085198851-r6 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - DialogIssueApp + DialogIssueApp - - - - DialogIssueApp - - - - - - ─────────────────────────────────────── - - - - - - This should not cause a scrollbar to ap - - - - - - ─────────────────────────────────────── - - - - -  D  Toggle the dialog  + + + + DialogIssueApp + + + + + + ────────────────────────────────────── + + + + + This should not cause a scrollbar to a + + + + + + ────────────────────────────────────── + + + + + +  D  Toggle the dialog  @@ -22685,133 +22845,133 @@ font-weight: 700; } - .terminal-1197668808-matrix { + .terminal-1136068071-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1197668808-title { + .terminal-1136068071-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1197668808-r1 { fill: #e1e1e1 } - .terminal-1197668808-r2 { fill: #c5c8c6 } - .terminal-1197668808-r3 { fill: #00ff00 } - .terminal-1197668808-r4 { fill: #ffdddd } + .terminal-1136068071-r1 { fill: #e1e1e1 } + .terminal-1136068071-r2 { fill: #c5c8c6 } + .terminal-1136068071-r3 { fill: #00ff00 } + .terminal-1136068071-r4 { fill: #ffdddd } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - BrokenClassesApp + BrokenClassesApp - - - - - - - - - ─────────────────────────────────────── - This should have a red background - - - - - - - - - - - ─────────────────────────────────────── - - - - - + + + + + + + + + + ────────────────────────────────────── + This should have a red background + + + + + + + + + + ────────────────────────────────────── + + + + + @@ -23474,135 +23634,135 @@ font-weight: 700; } - .terminal-1795141768-matrix { + .terminal-2734338184-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1795141768-title { + .terminal-2734338184-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1795141768-r1 { fill: #e1e1e1 } - .terminal-1795141768-r2 { fill: #c5c8c6 } - .terminal-1795141768-r3 { fill: #56c278 } - .terminal-1795141768-r4 { fill: #1d1d1d } - .terminal-1795141768-r5 { fill: #e3e4e4 } - .terminal-1795141768-r6 { fill: #e3e4e4;text-decoration: underline; } + .terminal-2734338184-r1 { fill: #e1e1e1 } + .terminal-2734338184-r2 { fill: #c5c8c6 } + .terminal-2734338184-r3 { fill: #56c278 } + .terminal-2734338184-r4 { fill: #1d1d1d } + .terminal-2734338184-r5 { fill: #e3e4e4 } + .terminal-2734338184-r6 { fill: #e3e4e4;text-decoration: underline; } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - NotifyWithInlineLinkApp + NotifyWithInlineLinkApp - - - - - - - - - - - - - - - - - - - - - - - - - Click here for the bell sound. - + + + + + + + + + + + + + + + + + + + + + + + + + Click here for the bell sound. + @@ -23633,135 +23793,135 @@ font-weight: 700; } - .terminal-3756307740-matrix { + .terminal-500610332-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3756307740-title { + .terminal-500610332-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3756307740-r1 { fill: #e1e1e1 } - .terminal-3756307740-r2 { fill: #c5c8c6 } - .terminal-3756307740-r3 { fill: #56c278 } - .terminal-3756307740-r4 { fill: #1d1d1d } - .terminal-3756307740-r5 { fill: #e3e4e4 } - .terminal-3756307740-r6 { fill: #ddedf9;font-weight: bold } + .terminal-500610332-r1 { fill: #e1e1e1 } + .terminal-500610332-r2 { fill: #c5c8c6 } + .terminal-500610332-r3 { fill: #56c278 } + .terminal-500610332-r4 { fill: #1d1d1d } + .terminal-500610332-r5 { fill: #e3e4e4 } + .terminal-500610332-r6 { fill: #ddedf9;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - NotifyWithInlineLinkApp + NotifyWithInlineLinkApp - - - - - - - - - - - - - - - - - - - - - - - - - Click here for the bell sound. - + + + + + + + + + + + + + + + + + + + + + + + + + Click here for the bell sound. + @@ -23792,139 +23952,139 @@ font-weight: 700; } - .terminal-99275963-matrix { + .terminal-3535066299-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-99275963-title { + .terminal-3535066299-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-99275963-r1 { fill: #e1e1e1 } - .terminal-99275963-r2 { fill: #c5c8c6 } - .terminal-99275963-r3 { fill: #56c278 } - .terminal-99275963-r4 { fill: #1d1d1d } - .terminal-99275963-r5 { fill: #e3e4e4 } - .terminal-99275963-r6 { fill: #feaa35 } - .terminal-99275963-r7 { fill: #e89719;font-weight: bold } - .terminal-99275963-r8 { fill: #e3e4e4;font-weight: bold } - .terminal-99275963-r9 { fill: #e3e4e4;font-weight: bold;font-style: italic; } - .terminal-99275963-r10 { fill: #bc4563 } + .terminal-3535066299-r1 { fill: #e1e1e1 } + .terminal-3535066299-r2 { fill: #c5c8c6 } + .terminal-3535066299-r3 { fill: #56c278 } + .terminal-3535066299-r4 { fill: #1d1d1d } + .terminal-3535066299-r5 { fill: #e3e4e4 } + .terminal-3535066299-r6 { fill: #feaa35 } + .terminal-3535066299-r7 { fill: #e89719;font-weight: bold } + .terminal-3535066299-r8 { fill: #e3e4e4;font-weight: bold } + .terminal-3535066299-r9 { fill: #e3e4e4;font-weight: bold;font-style: italic; } + .terminal-3535066299-r10 { fill: #bc4563 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - ToastApp + ToastApp - - - - - - - - It's an older code, sir, but it  - checks out. - - - - Possible trap detected - Now witness the firepower of this - fully ARMED and OPERATIONAL - battle station! - - - - It's a trap! - - - - It's against my programming to  - impersonate a deity. - + + + + + + + + It's an older code, sir, but it  + checks out. + + + + Possible trap detected + Now witness the firepower of this  + fully ARMED and OPERATIONAL battle  + station! + + + + It's a trap! + + + + It's against my programming to  + impersonate a deity. + @@ -23955,117 +24115,117 @@ font-weight: 700; } - .terminal-61440561-matrix { + .terminal-4012933681-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-61440561-title { + .terminal-4012933681-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-61440561-r1 { fill: #c5c8c6 } - .terminal-61440561-r2 { fill: #56c278 } - .terminal-61440561-r3 { fill: #1d1d1d } - .terminal-61440561-r4 { fill: #e3e4e4 } + .terminal-4012933681-r1 { fill: #c5c8c6 } + .terminal-4012933681-r2 { fill: #56c278 } + .terminal-4012933681-r3 { fill: #1d1d1d } + .terminal-4012933681-r4 { fill: #e3e4e4 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - LoadingOverlayApp + LoadingOverlayApp - - - - - - - - - - - This is a big notification. - This is a big notification. - This is a big notification. - This is a big notification. - This is a big notification. - This is a big notification. - This is a big notification. - This is a big notification. - This is a big notification. - This is a big notification. - - + + + + + + + + + + + This is a big notification. + This is a big notification. + This is a big notification. + This is a big notification. + This is a big notification. + This is a big notification. + This is a big notification. + This is a big notification. + This is a big notification. + This is a big notification. + + @@ -24096,134 +24256,134 @@ font-weight: 700; } - .terminal-2569815150-matrix { + .terminal-1373062254-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2569815150-title { + .terminal-1373062254-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2569815150-r1 { fill: #e1e1e1 } - .terminal-2569815150-r2 { fill: #56c278 } - .terminal-2569815150-r3 { fill: #c5c8c6 } - .terminal-2569815150-r4 { fill: #1d1d1d } - .terminal-2569815150-r5 { fill: #e3e4e4 } + .terminal-1373062254-r1 { fill: #e1e1e1 } + .terminal-1373062254-r2 { fill: #56c278 } + .terminal-1373062254-r3 { fill: #c5c8c6 } + .terminal-1373062254-r4 { fill: #1d1d1d } + .terminal-1373062254-r5 { fill: #e3e4e4 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - NotifyThroughModesApp + NotifyThroughModesApp - - - - This is a mode screen - 4 - - - - 5 - - - - 6 - - - - 7 - - - - 8 - - - - 9 - + + + + This is a mode screen + 4 + + + + 5 + + + + 6 + + + + 7 + + + + 8 + + + + 9 + @@ -24254,134 +24414,134 @@ font-weight: 700; } - .terminal-4257366247-matrix { + .terminal-3060613351-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-4257366247-title { + .terminal-3060613351-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-4257366247-r1 { fill: #e1e1e1 } - .terminal-4257366247-r2 { fill: #56c278 } - .terminal-4257366247-r3 { fill: #c5c8c6 } - .terminal-4257366247-r4 { fill: #1d1d1d } - .terminal-4257366247-r5 { fill: #e3e4e4 } + .terminal-3060613351-r1 { fill: #e1e1e1 } + .terminal-3060613351-r2 { fill: #56c278 } + .terminal-3060613351-r3 { fill: #c5c8c6 } + .terminal-3060613351-r4 { fill: #1d1d1d } + .terminal-3060613351-r5 { fill: #e3e4e4 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - NotifyDownScreensApp + NotifyDownScreensApp - - - - Screen 10 - 4 - - - - 5 - - - - 6 - - - - 7 - - - - 8 - - - - 9 - + + + + Screen 10 + 4 + + + + 5 + + + + 6 + + + + 7 + + + + 8 + + + + 9 + @@ -24731,140 +24891,140 @@ font-weight: 700; } - .terminal-371403050-matrix { + .terminal-2682133191-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-371403050-title { + .terminal-2682133191-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-371403050-r1 { fill: #c5c8c6 } - .terminal-371403050-r2 { fill: #e3e3e3 } - .terminal-371403050-r3 { fill: #e1e1e1 } - .terminal-371403050-r4 { fill: #1e1e1e } - .terminal-371403050-r5 { fill: #0178d4 } - .terminal-371403050-r6 { fill: #ddedf9;font-weight: bold } - .terminal-371403050-r7 { fill: #e2e2e2 } - .terminal-371403050-r8 { fill: #434343 } - .terminal-371403050-r9 { fill: #787878 } - .terminal-371403050-r10 { fill: #14191f } - .terminal-371403050-r11 { fill: #ddedf9 } + .terminal-2682133191-r1 { fill: #c5c8c6 } + .terminal-2682133191-r2 { fill: #e3e3e3 } + .terminal-2682133191-r3 { fill: #e1e1e1 } + .terminal-2682133191-r4 { fill: #1e1e1e } + .terminal-2682133191-r5 { fill: #0178d4 } + .terminal-2682133191-r6 { fill: #ddedf9;font-weight: bold } + .terminal-2682133191-r7 { fill: #e2e2e2 } + .terminal-2682133191-r8 { fill: #434343 } + .terminal-2682133191-r9 { fill: #787878 } + .terminal-2682133191-r10 { fill: #14191f } + .terminal-2682133191-r11 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OptionListApp + OptionListApp - - - - OptionListApp - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Aerilon - Aquaria - ─────────────────────────────────────────────────── - Canceron - Caprica - ─────────────────────────────────────────────────── - Gemenon - ─────────────────────────────────────────────────── - Leonis - Libran - ─────────────────────────────────────────────────── - Picon - ─────────────────────────────────────────────────── - Sagittaron▄▄ - Scorpia - ─────────────────────────────────────────────────── - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - + + + + OptionListApp + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Aerilon + Aquaria + ────────────────────────────────────────────────── + Canceron + Caprica + ────────────────────────────────────────────────── + Gemenon + ────────────────────────────────────────────────── + Leonis + Libran + ────────────────────────────────────────────────── + Picon▁▁ + ────────────────────────────────────────────────── + Sagittaron + Scorpia + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + @@ -25378,137 +25538,137 @@ font-weight: 700; } - .terminal-2341816165-matrix { + .terminal-534841697-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2341816165-title { + .terminal-534841697-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2341816165-r1 { fill: #c5c8c6 } - .terminal-2341816165-r2 { fill: #e3e3e3 } - .terminal-2341816165-r3 { fill: #e1e1e1 } - .terminal-2341816165-r4 { fill: #1e1e1e } - .terminal-2341816165-r5 { fill: #0178d4 } - .terminal-2341816165-r6 { fill: #ddedf9;font-weight: bold } - .terminal-2341816165-r7 { fill: #e2e2e2 } - .terminal-2341816165-r8 { fill: #ddedf9 } + .terminal-534841697-r1 { fill: #c5c8c6 } + .terminal-534841697-r2 { fill: #e3e3e3 } + .terminal-534841697-r3 { fill: #e1e1e1 } + .terminal-534841697-r4 { fill: #1e1e1e } + .terminal-534841697-r5 { fill: #0178d4 } + .terminal-534841697-r6 { fill: #ddedf9;font-weight: bold } + .terminal-534841697-r7 { fill: #e2e2e2 } + .terminal-534841697-r8 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OptionListApp + OptionListApp - - - - OptionListApp - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Aerilon - Aquaria - Canceron - Caprica - Gemenon - Leonis - Libran - Picon - Sagittaron - Scorpia - Tauron - Virgon - - - - - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - + + + + OptionListApp + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Aerilon + Aquaria + Canceron + Caprica + Gemenon + Leonis + Libran + Picon + Sagittaron + Scorpia + Tauron + Virgon + + + + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + @@ -25539,141 +25699,141 @@ font-weight: 700; } - .terminal-228828675-matrix { + .terminal-1755547624-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-228828675-title { + .terminal-1755547624-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-228828675-r1 { fill: #c5c8c6 } - .terminal-228828675-r2 { fill: #e3e3e3 } - .terminal-228828675-r3 { fill: #e1e1e1 } - .terminal-228828675-r4 { fill: #1e1e1e } - .terminal-228828675-r5 { fill: #0178d4 } - .terminal-228828675-r6 { fill: #ddedf9;font-weight: bold;font-style: italic; } - .terminal-228828675-r7 { fill: #e2e2e2 } - .terminal-228828675-r8 { fill: #ddedf9;font-weight: bold } - .terminal-228828675-r9 { fill: #14191f } - .terminal-228828675-r10 { fill: #e2e2e2;font-style: italic; } - .terminal-228828675-r11 { fill: #e2e2e2;font-weight: bold } - .terminal-228828675-r12 { fill: #ddedf9 } + .terminal-1755547624-r1 { fill: #c5c8c6 } + .terminal-1755547624-r2 { fill: #e3e3e3 } + .terminal-1755547624-r3 { fill: #e1e1e1 } + .terminal-1755547624-r4 { fill: #1e1e1e } + .terminal-1755547624-r5 { fill: #0178d4 } + .terminal-1755547624-r6 { fill: #ddedf9;font-weight: bold;font-style: italic; } + .terminal-1755547624-r7 { fill: #e2e2e2 } + .terminal-1755547624-r8 { fill: #ddedf9;font-weight: bold } + .terminal-1755547624-r9 { fill: #14191f } + .terminal-1755547624-r10 { fill: #e2e2e2;font-style: italic; } + .terminal-1755547624-r11 { fill: #e2e2e2;font-weight: bold } + .terminal-1755547624-r12 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OptionListApp + OptionListApp - - - - OptionListApp - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ -                  Data for Aerilon                   - ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓ - Patron God   Population    Capital City   - ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩▃▃ - Demeter      1.2 Billion   Gaoth          - └───────────────┴────────────────┴────────────────┘ -                  Data for Aquaria                   - ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ - Patron God   Population   Capital City    - ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩ - Hermes       75,000       None            - └───────────────┴───────────────┴─────────────────┘ -                  Data for Canceron                  - ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓ - Patron God   Population    Capital City   - ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩ - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - + + + + OptionListApp + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ +                  Data for Aerilon                  + ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓ + Patron God   Population   Capital City   + ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩▇▇ + Demeter      1.2 Billion  Gaoth          + └───────────────┴───────────────┴────────────────┘ +                  Data for Aquaria                  + ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓ + Patron God   Population   Capital City   + ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩ + Hermes       75,000       None           + └───────────────┴───────────────┴────────────────┘ +                 Data for Canceron                  + ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓ + Patron God   Population   Capital City   + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + @@ -27616,139 +27776,139 @@ font-weight: 700; } - .terminal-3755206349-matrix { + .terminal-2068636424-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3755206349-title { + .terminal-2068636424-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3755206349-r1 { fill: #e1e1e1 } - .terminal-3755206349-r2 { fill: #c5c8c6 } - .terminal-3755206349-r3 { fill: #1e1e1e } - .terminal-3755206349-r4 { fill: #0178d4 } - .terminal-3755206349-r5 { fill: #575757 } - .terminal-3755206349-r6 { fill: #262626;font-weight: bold } - .terminal-3755206349-r7 { fill: #e2e2e2 } - .terminal-3755206349-r8 { fill: #e2e2e2;text-decoration: underline; } - .terminal-3755206349-r9 { fill: #434343 } - .terminal-3755206349-r10 { fill: #4ebf71;font-weight: bold } + .terminal-2068636424-r1 { fill: #e1e1e1 } + .terminal-2068636424-r2 { fill: #c5c8c6 } + .terminal-2068636424-r3 { fill: #1e1e1e } + .terminal-2068636424-r4 { fill: #0178d4 } + .terminal-2068636424-r5 { fill: #575757 } + .terminal-2068636424-r6 { fill: #262626;font-weight: bold } + .terminal-2068636424-r7 { fill: #e2e2e2 } + .terminal-2068636424-r8 { fill: #e2e2e2;text-decoration: underline; } + .terminal-2068636424-r9 { fill: #434343 } + .terminal-2068636424-r10 { fill: #4ebf71;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - RadioChoicesApp + RadioChoicesApp - - - - - - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Battlestar Galactica -  Dune 1984 -  Dune 2021 -  Serenity -  Star Trek: The Motion Picture -  Star Wars: A New Hope -  The Last Starfighter -  Total Recall 👉 🔴 -  Wing Commander - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - - - + + + + + + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Battlestar Galactica +  Dune 1984 +  Dune 2021 +  Serenity +  Star Trek: The Motion Picture +  Star Wars: A New Hope +  The Last Starfighter +  Total Recall 👉 🔴 +  Wing Commander + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + @@ -27779,140 +27939,140 @@ font-weight: 700; } - .terminal-3259211563-matrix { + .terminal-2449642391-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3259211563-title { + .terminal-2449642391-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3259211563-r1 { fill: #e1e1e1 } - .terminal-3259211563-r2 { fill: #c5c8c6 } - .terminal-3259211563-r3 { fill: #1e1e1e } - .terminal-3259211563-r4 { fill: #0178d4 } - .terminal-3259211563-r5 { fill: #575757 } - .terminal-3259211563-r6 { fill: #262626;font-weight: bold } - .terminal-3259211563-r7 { fill: #e2e2e2 } - .terminal-3259211563-r8 { fill: #e2e2e2;text-decoration: underline; } - .terminal-3259211563-r9 { fill: #434343 } - .terminal-3259211563-r10 { fill: #4ebf71;font-weight: bold } - .terminal-3259211563-r11 { fill: #cc555a;font-weight: bold;font-style: italic; } + .terminal-2449642391-r1 { fill: #e1e1e1 } + .terminal-2449642391-r2 { fill: #c5c8c6 } + .terminal-2449642391-r3 { fill: #1e1e1e } + .terminal-2449642391-r4 { fill: #0178d4 } + .terminal-2449642391-r5 { fill: #575757 } + .terminal-2449642391-r6 { fill: #262626;font-weight: bold } + .terminal-2449642391-r7 { fill: #e2e2e2 } + .terminal-2449642391-r8 { fill: #e2e2e2;text-decoration: underline; } + .terminal-2449642391-r9 { fill: #434343 } + .terminal-2449642391-r10 { fill: #4ebf71;font-weight: bold } + .terminal-2449642391-r11 { fill: #cc555a;font-weight: bold;font-style: italic; } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - RadioChoicesApp + RadioChoicesApp - - - - - - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Battlestar Galactica Amanda -  Dune 1984 Connor MacLeod -  Dune 2021 Duncan MacLeod -  Serenity Heather MacLeod -  Star Trek: The Motion Picture Joe Dawson -  Star Wars: A New Hope Kurgan, The -  The Last Starfighter Methos -  Total Recall 👉 🔴 Rachel Ellenstein -  Wing Commander Ramírez - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - - - + + + + + + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Battlestar Galactica Amanda +  Dune 1984 Connor MacLeod +  Dune 2021 Duncan MacLeod +  Serenity Heather MacLeod +  Star Trek: The Motion Pictur Joe Dawson +  Star Wars: A New Hope Kurgan, The +  The Last Starfighter Methos +  Total Recall 👉 🔴 Rachel Ellenstein +  Wing Commander Ramírez + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + @@ -30976,139 +31136,139 @@ font-weight: 700; } - .terminal-3401996005-matrix { + .terminal-2928221602-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3401996005-title { + .terminal-2928221602-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3401996005-r1 { fill: #c5c8c6 } - .terminal-3401996005-r2 { fill: #e3e3e3 } - .terminal-3401996005-r3 { fill: #e1e1e1 } - .terminal-3401996005-r4 { fill: #0178d4 } - .terminal-3401996005-r5 { fill: #575757 } - .terminal-3401996005-r6 { fill: #4ebf71;font-weight: bold } - .terminal-3401996005-r7 { fill: #ddedf9;font-weight: bold } - .terminal-3401996005-r8 { fill: #262626;font-weight: bold } - .terminal-3401996005-r9 { fill: #e2e2e2 } - .terminal-3401996005-r10 { fill: #ddedf9 } + .terminal-2928221602-r1 { fill: #c5c8c6 } + .terminal-2928221602-r2 { fill: #e3e3e3 } + .terminal-2928221602-r3 { fill: #e1e1e1 } + .terminal-2928221602-r4 { fill: #0178d4 } + .terminal-2928221602-r5 { fill: #575757 } + .terminal-2928221602-r6 { fill: #4ebf71;font-weight: bold } + .terminal-2928221602-r7 { fill: #ddedf9;font-weight: bold } + .terminal-2928221602-r8 { fill: #262626;font-weight: bold } + .terminal-2928221602-r9 { fill: #e2e2e2 } + .terminal-2928221602-r10 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - SelectionListApp + SelectionListApp - - - - SelectionListApp - - -  Shall we play some games? ────────────────────────────────── - - XFalken's Maze - XBlack Jack - XGin Rummy - XHearts - XBridge - XCheckers - XChess - XPoker - XFighter Combat - - - - - - - ────────────────────────────────────────────────────────────── - - + + + + SelectionListApp + + +  Shall we play some games? ────────────────────────────────── + + XFalken's Maze + XBlack Jack + XGin Rummy + XHearts + XBridge + XCheckers + XChess + XPoker + XFighter Combat + + + + + + ────────────────────────────────────────────────────────────── + + + @@ -31139,139 +31299,139 @@ font-weight: 700; } - .terminal-3401996005-matrix { + .terminal-2928221602-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3401996005-title { + .terminal-2928221602-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3401996005-r1 { fill: #c5c8c6 } - .terminal-3401996005-r2 { fill: #e3e3e3 } - .terminal-3401996005-r3 { fill: #e1e1e1 } - .terminal-3401996005-r4 { fill: #0178d4 } - .terminal-3401996005-r5 { fill: #575757 } - .terminal-3401996005-r6 { fill: #4ebf71;font-weight: bold } - .terminal-3401996005-r7 { fill: #ddedf9;font-weight: bold } - .terminal-3401996005-r8 { fill: #262626;font-weight: bold } - .terminal-3401996005-r9 { fill: #e2e2e2 } - .terminal-3401996005-r10 { fill: #ddedf9 } + .terminal-2928221602-r1 { fill: #c5c8c6 } + .terminal-2928221602-r2 { fill: #e3e3e3 } + .terminal-2928221602-r3 { fill: #e1e1e1 } + .terminal-2928221602-r4 { fill: #0178d4 } + .terminal-2928221602-r5 { fill: #575757 } + .terminal-2928221602-r6 { fill: #4ebf71;font-weight: bold } + .terminal-2928221602-r7 { fill: #ddedf9;font-weight: bold } + .terminal-2928221602-r8 { fill: #262626;font-weight: bold } + .terminal-2928221602-r9 { fill: #e2e2e2 } + .terminal-2928221602-r10 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - SelectionListApp + SelectionListApp - - - - SelectionListApp - - -  Shall we play some games? ────────────────────────────────── - - XFalken's Maze - XBlack Jack - XGin Rummy - XHearts - XBridge - XCheckers - XChess - XPoker - XFighter Combat - - - - - - - ────────────────────────────────────────────────────────────── - - + + + + SelectionListApp + + +  Shall we play some games? ────────────────────────────────── + + XFalken's Maze + XBlack Jack + XGin Rummy + XHearts + XBridge + XCheckers + XChess + XPoker + XFighter Combat + + + + + + ────────────────────────────────────────────────────────────── + + + diff --git a/tests/snapshot_tests/snapshot_apps/input_percentage_width.py b/tests/snapshot_tests/snapshot_apps/input_percentage_width.py new file mode 100644 index 0000000000..f20b2ddd29 --- /dev/null +++ b/tests/snapshot_tests/snapshot_apps/input_percentage_width.py @@ -0,0 +1,35 @@ +from textual.app import App, ComposeResult +from textual.widgets import Input, TextArea, Static, Button, Label + + +class InputVsTextArea(App[None]): + CSS = """ + Screen > *, Screen > *:focus { + width: 50%; + height: 1fr; + border: solid red; + } + App #ruler { + width: 1fr; + height: 1; + border: none; + } + """ + + def compose(self) -> ComposeResult: + yield Label("[reverse]0123456789[/]0123456789" * 4, id="ruler") + + input = Input() + input.cursor_blink = False + yield input + + text_area = TextArea() + text_area.cursor_blink = False + yield text_area + + yield Static() + yield Button() + + +if __name__ == "__main__": + InputVsTextArea().run() diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index 72e64cfdc3..f79f9be42a 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -992,3 +992,9 @@ def test_nested_specificity(snap_compare): def test_tab_rename(snap_compare): """Test setting a new label for a tab amongst a TabbedContent.""" assert snap_compare(SNAPSHOT_APPS_DIR / "tab_rename.py") + + +def test_input_percentage_width(snap_compare): + """Check percentage widths work correctly.""" + # https://github.com/Textualize/textual/issues/3721 + assert snap_compare(SNAPSHOT_APPS_DIR / "input_percentage_width.py") diff --git a/tests/test_box_model.py b/tests/test_box_model.py index 8f59c8a82f..d775dc9be9 100644 --- a/tests/test_box_model.py +++ b/tests/test_box_model.py @@ -90,7 +90,7 @@ def get_content_height(self, container: Size, parent: Size, width: int) -> int: styles.max_width = "50%" box_model = widget._get_box_model(Size(60, 20), Size(80, 24), one, one) - assert box_model == BoxModel(Fraction(30), Fraction(16), Spacing(1, 2, 3, 4)) + assert box_model == BoxModel(Fraction(27), Fraction(16), Spacing(1, 2, 3, 4)) def test_height(): @@ -141,7 +141,7 @@ def get_content_height(self, container: Size, parent: Size, width: int) -> int: styles.max_height = "50%" box_model = widget._get_box_model(Size(60, 20), Size(80, 24), one, one) - assert box_model == BoxModel(Fraction(54), Fraction(10), Spacing(1, 2, 3, 4)) + assert box_model == BoxModel(Fraction(54), Fraction(8), Spacing(1, 2, 3, 4)) def test_max():