diff --git a/changes/2428.bugfix.rst b/changes/2428.bugfix.rst new file mode 100644 index 0000000000..0d4a26321c --- /dev/null +++ b/changes/2428.bugfix.rst @@ -0,0 +1 @@ +Issue with `visibility` on GTK and `display` on all platform. \ No newline at end of file diff --git a/core/src/toga/style/pack.py b/core/src/toga/style/pack.py index ac9787feeb..149685d888 100644 --- a/core/src/toga/style/pack.py +++ b/core/src/toga/style/pack.py @@ -86,7 +86,7 @@ def _debug(self, *args): # pragma: no cover @property def _hidden(self): "Does this style declaration define a object that should be hidden" - return self.visibility == HIDDEN + return self.visibility == HIDDEN or self.display == NONE def apply(self, prop, value): if self._applicator: @@ -104,8 +104,8 @@ def apply(self, prop, value): self._applicator.set_color(value) elif prop == "background_color": self._applicator.set_background_color(value) - elif prop == "visibility": - self._applicator.set_hidden(value == HIDDEN) + elif prop == "visibility" or prop == "display": + self._applicator.set_hidden(self._hidden) elif prop in ( "font_family", "font_size", @@ -275,6 +275,9 @@ def _layout_row_children( min_width = 0 remaining_width = available_width for child in node.children: + # Skip calculation if widget is not displayed + if child.style.display == NONE: + continue # self._debug(f"PASS 1 {child}") if child.style.width != NONE: # self._debug(f"- fixed width {child.style.width}") @@ -404,6 +407,9 @@ def _layout_row_children( # Pass 2: Lay out children with an intrinsic flexible width, # or no width specification at all. for child in node.children: + # Skip calculation if widget is not displayed + if child.style.display == NONE: + continue # self._debug(f"PASS 2 {child}") if child.style.width != NONE: # self._debug("- already laid out (explicit width)") @@ -489,6 +495,9 @@ def _layout_row_children( height = 0 min_height = 0 for child in node.children: + # Skip calculation if widget is not displayed + if child.style.display == NONE: + continue # self._debug(f"PASS 3: {child} AT HORIZONTAL {offset=}") if node.style.text_direction is RTL: # self._debug("- RTL") @@ -522,6 +531,9 @@ def _layout_row_children( # Pass 4: set vertical position of each child. for child in node.children: + # Skip calculation if widget is not displayed + if child.style.display == NONE: + continue # self._debug(f"PASS 4: {child}") extra = height - ( child.layout.content_height @@ -559,6 +571,9 @@ def _layout_column_children( min_height = 0 remaining_height = available_height for child in node.children: + # Skip calculation if widget is not displayed + if child.style.display == NONE: + continue # self._debug(f"PASS 1 {child}") if child.style.height != NONE: # self._debug(f"- fixed height {child.style.height}") @@ -689,6 +704,9 @@ def _layout_column_children( # Pass 2: Lay out children with an intrinsic flexible height, # or no height specification at all. for child in node.children: + # Skip calculation if widget is not displayed + if child.style.display == NONE: + continue # self._debug(f"PASS 2 {child}") if child.style.height != NONE: # self._debug("- already laid out (explicit height)") @@ -775,6 +793,9 @@ def _layout_column_children( width = 0 min_width = 0 for child in node.children: + # Skip calculation if widget is not displayed + if child.style.display == NONE: + continue # self._debug(f"PASS 3: {child} AT VERTICAL OFFSET {offset}") offset += child.style.padding_top child.layout.content_top = offset @@ -800,6 +821,9 @@ def _layout_column_children( # Pass 4: set horizontal position of each child. for child in node.children: + # Skip calculation if widget is not displayed + if child.style.display == NONE: + continue # self._debug(f"PASS 4: {child}") extra = width - ( child.layout.content_width diff --git a/gtk/src/toga_gtk/widgets/activityindicator.py b/gtk/src/toga_gtk/widgets/activityindicator.py index 54acfd3004..f8d2f7c342 100644 --- a/gtk/src/toga_gtk/widgets/activityindicator.py +++ b/gtk/src/toga_gtk/widgets/activityindicator.py @@ -16,9 +16,6 @@ def stop(self): self.native.stop() def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) - width = self.native.get_preferred_width() - height = self.native.get_preferred_height() - + width, height = self._get_preferred_size(self.native) self.interface.intrinsic.width = width[0] self.interface.intrinsic.height = height[0] diff --git a/gtk/src/toga_gtk/widgets/base.py b/gtk/src/toga_gtk/widgets/base.py index d397d25eeb..4c3f139538 100644 --- a/gtk/src/toga_gtk/widgets/base.py +++ b/gtk/src/toga_gtk/widgets/base.py @@ -57,7 +57,6 @@ def container(self, container): # setting container, adding self to container.native self._container = container self._container.add(self.native) - self.native.show_all() for child in self.interface.children: child._impl.container = container @@ -84,6 +83,18 @@ def get_tab_index(self): def set_tab_index(self, tab_index): self.interface.factory.not_implemented("Widget.set_tab_index()") + def _get_preferred_size(self, native): + # Utility function to get the preferred size of widget regardless of it's visibility. + visible = native.get_visible() + if not visible: + native.set_visible(True) + # print("REHINT", self, native.get_preferred_width(), native.get_preferred_height()) + width = native.get_preferred_width() + height = native.get_preferred_height() + if not visible: + native.set_visible(visible) + return width, height + ###################################################################### # CSS tools ###################################################################### @@ -185,9 +196,6 @@ def refresh(self): def rehint(self): # Perform the actual GTK rehint. - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) - width = self.native.get_preferred_width() - height = self.native.get_preferred_height() - + width, height = self._get_preferred_size(self.native) self.interface.intrinsic.width = at_least(width[0]) self.interface.intrinsic.height = at_least(height[0]) diff --git a/gtk/src/toga_gtk/widgets/button.py b/gtk/src/toga_gtk/widgets/button.py index cf26e6a6f1..ec4c959a30 100644 --- a/gtk/src/toga_gtk/widgets/button.py +++ b/gtk/src/toga_gtk/widgets/button.py @@ -41,10 +41,7 @@ def set_background_color(self, color): super().set_background_color(color) def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) - width = self.native.get_preferred_width() - height = self.native.get_preferred_height() - + width, height = self._get_preferred_size(self.native) self.interface.intrinsic.width = at_least(width[0]) self.interface.intrinsic.height = height[1] diff --git a/gtk/src/toga_gtk/widgets/canvas.py b/gtk/src/toga_gtk/widgets/canvas.py index 534c73e4f9..c2cf564041 100644 --- a/gtk/src/toga_gtk/widgets/canvas.py +++ b/gtk/src/toga_gtk/widgets/canvas.py @@ -299,7 +299,6 @@ def get_image_data(self): # Rehint def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) # width = self.native.get_allocation().width # height = self.native.get_allocation().height width = self.interface._MIN_WIDTH diff --git a/gtk/src/toga_gtk/widgets/divider.py b/gtk/src/toga_gtk/widgets/divider.py index 09f6fa491d..c095e5ea73 100644 --- a/gtk/src/toga_gtk/widgets/divider.py +++ b/gtk/src/toga_gtk/widgets/divider.py @@ -9,9 +9,7 @@ def create(self): self.native = Gtk.Separator() def rehint(self): - width = self.native.get_preferred_width() - height = self.native.get_preferred_height() - + width, height = self._get_preferred_size(self.native) if self.get_direction() == self.interface.VERTICAL: self.interface.intrinsic.width = width[0] self.interface.intrinsic.height = at_least(height[1]) diff --git a/gtk/src/toga_gtk/widgets/label.py b/gtk/src/toga_gtk/widgets/label.py index f6ca0135ef..6dd472610f 100644 --- a/gtk/src/toga_gtk/widgets/label.py +++ b/gtk/src/toga_gtk/widgets/label.py @@ -24,12 +24,6 @@ def set_text(self, value): self.native.set_text(value) def rehint(self): - # print("REHINT", self, - # self.native.get_preferred_width(), self.native.get_preferred_height(), - # getattr(self, '_fixed_height', False), getattr(self, '_fixed_width', False) - # ) - width = self.native.get_preferred_width() - height = self.native.get_preferred_height() - + width, height = self._get_preferred_size(self.native) self.interface.intrinsic.width = at_least(width[0]) self.interface.intrinsic.height = height[1] diff --git a/gtk/src/toga_gtk/widgets/numberinput.py b/gtk/src/toga_gtk/widgets/numberinput.py index 176825bf3a..e3a190d569 100644 --- a/gtk/src/toga_gtk/widgets/numberinput.py +++ b/gtk/src/toga_gtk/widgets/numberinput.py @@ -64,9 +64,7 @@ def set_alignment(self, value): self.native.set_alignment(xalign) def rehint(self): - width = self.native.get_preferred_width() - height = self.native.get_preferred_height() - + width, height = self._get_preferred_size(self.native) self.interface.intrinsic.width = at_least( max(self.interface._MIN_WIDTH, width[1]) ) diff --git a/gtk/src/toga_gtk/widgets/progressbar.py b/gtk/src/toga_gtk/widgets/progressbar.py index f44ea3b026..19328835ed 100644 --- a/gtk/src/toga_gtk/widgets/progressbar.py +++ b/gtk/src/toga_gtk/widgets/progressbar.py @@ -91,9 +91,6 @@ def stop(self): self._stop_indeterminate() def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) - width = self.native.get_preferred_width() - height = self.native.get_preferred_height() - + width, height = self._get_preferred_size(self.native) self.interface.intrinsic.width = at_least(width[0]) self.interface.intrinsic.height = height[0] diff --git a/gtk/src/toga_gtk/widgets/selection.py b/gtk/src/toga_gtk/widgets/selection.py index 7ff6ab2330..75cbaf309c 100644 --- a/gtk/src/toga_gtk/widgets/selection.py +++ b/gtk/src/toga_gtk/widgets/selection.py @@ -89,8 +89,7 @@ def get_selected_index(self): return index def rehint(self): - width = self.native.get_preferred_width() - height = self.native.get_preferred_height() + width, height = self._get_preferred_size(self.native) # FIXME: 2023-05-31 This will always provide a size that is big enough, # but sometimes it will be *too* big. For example, if you set the font size diff --git a/gtk/src/toga_gtk/widgets/slider.py b/gtk/src/toga_gtk/widgets/slider.py index 301cbfa356..02c645c9bd 100644 --- a/gtk/src/toga_gtk/widgets/slider.py +++ b/gtk/src/toga_gtk/widgets/slider.py @@ -82,8 +82,7 @@ def get_tick_count(self): return self.tick_count def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) - height = self.native.get_preferred_height() + width, height = self._get_preferred_size(self.native) # Set intrinsic width to at least the minimum width self.interface.intrinsic.width = at_least(self.interface._MIN_WIDTH) diff --git a/gtk/src/toga_gtk/widgets/switch.py b/gtk/src/toga_gtk/widgets/switch.py index 8c86d2bc1f..31450bac2d 100644 --- a/gtk/src/toga_gtk/widgets/switch.py +++ b/gtk/src/toga_gtk/widgets/switch.py @@ -52,12 +52,8 @@ def set_font(self, font): self.apply_css("font", get_font_css(font), native=self.native_label) def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) - label_width = self.native_label.get_preferred_width() - label_height = self.native_label.get_preferred_height() - - switch_width = self.native_switch.get_preferred_width() - switch_height = self.native_switch.get_preferred_height() + label_width, label_height = self._get_preferred_size(native=self.native_label) + switch_width, switch_height = self._get_preferred_size(native=self.native_label) # Set intrinsic width to at least the minimum width self.interface.intrinsic.width = at_least( diff --git a/gtk/src/toga_gtk/widgets/textinput.py b/gtk/src/toga_gtk/widgets/textinput.py index ecce9555d5..d149b30256 100644 --- a/gtk/src/toga_gtk/widgets/textinput.py +++ b/gtk/src/toga_gtk/widgets/textinput.py @@ -55,13 +55,7 @@ def set_value(self, value): self.native.set_text(value) def rehint(self): - # print("REHINT", self, - # self._impl.get_preferred_width(), self._impl.get_preferred_height(), - # getattr(self, '_fixed_height', False), getattr(self, '_fixed_width', False) - # ) - width = self.native.get_preferred_width() - height = self.native.get_preferred_height() - + width, height = self._get_preferred_size(self.native) self.interface.intrinsic.width = at_least( max(self.interface._MIN_WIDTH, width[1]) ) diff --git a/gtk/src/toga_gtk/window.py b/gtk/src/toga_gtk/window.py index 0273f62424..82cab211aa 100644 --- a/gtk/src/toga_gtk/window.py +++ b/gtk/src/toga_gtk/window.py @@ -144,7 +144,10 @@ def set_app(self, app): app.native.add_window(self.native) def show(self): - self.native.show_all() + # Avoid calling show_all() as it change the visibility of all children. + self.native.show() + self.layout.show() + self.container.show() ###################################################################### # Window content and resources