From 7ead0e8d6fe70dd563727d494d826aa9b9f0253b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 01:54:56 +0000 Subject: [PATCH 1/3] Initial plan From 305b36d8525c0b842d536d4863942235c7e60c19 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 01:58:11 +0000 Subject: [PATCH 2/3] Replace full widget background color with color button indicator Co-authored-by: lachlangrose <7371904+lachlangrose@users.noreply.github.com> --- .../stratigraphic_unit.py | 25 +++++++---- .../stratigraphic_unit.ui | 44 ++++++++++++++----- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.py b/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.py index 539f716..d8be3ab 100644 --- a/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.py +++ b/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.py @@ -43,11 +43,13 @@ def __init__( else: self.colour = "" self.thickness = thickness # Optional thickness attribute - # Add delete button + # Connect buttons self.buttonDelete.clicked.connect(self.request_delete) + self.buttonColour.clicked.connect(self.onColourSelectClicked) self.lineEditName.editingFinished.connect(self.onNameChanged) self.spinBoxThickness.valueChanged.connect(self.onThicknessChanged) - self.setStyleSheet(f"background-color: {self.colour};" if self.colour else "") + # Set color button style instead of widget background + self._update_colour_button() @property def name(self): @@ -69,6 +71,15 @@ def set_thickness(self, thickness: float): self.spinBoxThickness.setValue(thickness) self.validateFields() + def _update_colour_button(self): + """Update the color button's appearance to show the current color.""" + if self.colour: + self.buttonColour.setStyleSheet( + f"background-color: {self.colour}; border: 1px solid #999;" + ) + else: + self.buttonColour.setStyleSheet("background-color: #cccccc; border: 1px solid #999;") + def onColourSelectClicked(self): """Open a color dialog to select a color for the stratigraphic unit.""" from PyQt5.QtWidgets import QColorDialog @@ -76,7 +87,7 @@ def onColourSelectClicked(self): color = QColorDialog.getColor() if color.isValid(): self.colour = color.name() - self.setStyleSheet(f"background-color: {self.colour};") + self._update_colour_button() self.colourChanged.emit(self.colour) def onThicknessChanged(self, thickness: float): @@ -103,10 +114,6 @@ def request_delete(self): self.deleteRequested.emit(self) - def mouseDoubleClickEvent(self, event): - """Handle double-click event to open color selection dialog.""" - self.onColourSelectClicked() - def validateFields(self): """Validate the widget fields and update UI hints.""" # Reset all styles first @@ -161,7 +168,7 @@ def setData(self, data: Optional[dict] = None): # Widget has been deleted; abort GUI updates return try: - self.setStyleSheet(f"background-color: {self.colour};" if self.colour else "") + self._update_colour_button() except RuntimeError: return else: @@ -171,7 +178,7 @@ def setData(self, data: Optional[dict] = None): except RuntimeError: return try: - self.setStyleSheet("") + self._update_colour_button() except RuntimeError: return diff --git a/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.ui b/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.ui index 9272c68..b5613bc 100644 --- a/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.ui +++ b/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.ui @@ -11,7 +11,39 @@ + + + + Click to change color + + + + + + + 40 + 0 + + + + + 40 + 16777215 + + + + + + + + + + Thickness: + + + + m @@ -27,17 +59,7 @@ - - - - - - - Thickness: - - - - + Delete this unit From 1a1e1956c1b1c847530aedc279a7a164d61c3c52 Mon Sep 17 00:00:00 2001 From: lachlangrose Date: Thu, 19 Feb 2026 13:59:45 +1100 Subject: [PATCH 3/3] refactor: streamline colour conversion logic and enhance documentation --- .../stratigraphic_unit.py | 58 +++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.py b/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.py index d8be3ab..0dd8204 100644 --- a/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.py +++ b/loopstructural/gui/modelling/stratigraphic_column/stratigraphic_unit.py @@ -25,32 +25,53 @@ def __init__( uic.loadUi(os.path.join(os.path.dirname(__file__), "stratigraphic_unit.ui"), self) self.uuid = uuid self._name = name if name is not None else "" - # Convert colour from RGB tuple or string to Qt-compatible hex string - if colour is not None: - if ( - isinstance(colour, tuple) - or isinstance(colour, list) - or isinstance(colour, np.ndarray) - ) and len(colour) == 3: - # Convert (r, g, b) to "#RRGGBB" - if all(isinstance(c, float) and 0.0 <= c <= 1.0 for c in colour): - rgb = [int(c * 255) for c in colour] - else: - rgb = [int(c) for c in colour] - self.colour = "#{:02x}{:02x}{:02x}".format(*rgb) - else: - self.colour = str(colour) - else: - self.colour = "" + # Convert colour using helper method + self.colour = self._convert_colour(colour) self.thickness = thickness # Optional thickness attribute # Connect buttons self.buttonDelete.clicked.connect(self.request_delete) self.buttonColour.clicked.connect(self.onColourSelectClicked) self.lineEditName.editingFinished.connect(self.onNameChanged) self.spinBoxThickness.valueChanged.connect(self.onThicknessChanged) + # Initialize UI widgets with the provided values + self.lineEditName.setText(self._name) + self.spinBoxThickness.setValue(self.thickness) # Set color button style instead of widget background self._update_colour_button() + def _convert_colour(self, colour): + """Convert colour from various formats to Qt-compatible hex string. + + Parameters + ---------- + colour : str, tuple, list, np.ndarray, or None + Colour in various formats: hex string, RGB tuple/list/array + + Returns + ------- + str + Hex color string in format "#RRGGBB", or empty string if None + """ + if colour is None: + return "" + + # If it's already a string, return it + if isinstance(colour, str): + return colour + + # Handle tuple, list, or numpy array of RGB values + if (isinstance(colour, (tuple, list)) or isinstance(colour, np.ndarray)) and len(colour) >= 3: + # Convert (r, g, b) to "#RRGGBB" + # Check if values are normalized floats (0.0-1.0) or integers (0-255) + if all(isinstance(c, float) and 0.0 <= c <= 1.0 for c in colour[:3]): + rgb = [int(c * 255) for c in colour[:3]] + else: + rgb = [int(c) for c in colour[:3]] + return "#{:02x}{:02x}{:02x}".format(*rgb) + + # Fallback: try to convert to string + return str(colour) + @property def name(self): return str(self._name) @@ -140,7 +161,8 @@ def setData(self, data: Optional[dict] = None): # Safely update internal state first if data: self.name = str(data.get("name", "")) - self.colour = data.get("colour", "") + # Convert colour using helper method to handle various formats + self.colour = self._convert_colour(data.get("colour")) # If a thickness value is provided, update the widget's thickness if 'thickness' in data and data.get('thickness') is not None: try: