diff --git a/config.json b/config.json index 1e4436b2..6d6d639b 100644 --- a/config.json +++ b/config.json @@ -16,7 +16,7 @@ "author": "Kartoza", "email": "info@kartoza.com", "description": "Gender Enabling Environments Spatial Tool", - "version": "0.4.6", + "version": "0.4.7", "changelog": "", "server": false } diff --git a/geest/gui/dialogs/analysis_aggregation_dialog.py b/geest/gui/dialogs/analysis_aggregation_dialog.py index 847ec799..b6b33583 100644 --- a/geest/gui/dialogs/analysis_aggregation_dialog.py +++ b/geest/gui/dialogs/analysis_aggregation_dialog.py @@ -634,8 +634,8 @@ def load_combo_from_model( if layer: combo.setLayer(layer) if item.attribute(f"{prefix}_shapefile", False): - lineedit.setText(self.attributes[f"{prefix}_shapefile"]) + lineedit.setText(self.item.attribute[f"{prefix}_shapefile"]) lineedit.setVisible(True) if item.attribute(f"{prefix}_raster", False): - lineedit.setText(self.attributes[f"{prefix}_raster"]) + lineedit.setText(self.item.attribute[f"{prefix}_raster"]) lineedit.setVisible(True) diff --git a/geest/gui/panels/tree_panel.py b/geest/gui/panels/tree_panel.py index 82a9b1c4..71efccd7 100644 --- a/geest/gui/panels/tree_panel.py +++ b/geest/gui/panels/tree_panel.py @@ -709,7 +709,10 @@ def show_attributes(self, item): dialog = QDialog() dialog.setWindowState(Qt.WindowMaximized) dialog.setWindowTitle("Attributes") - dialog.resize(600, 400) + dialog.resize( + int(QApplication.desktop().screenGeometry().width() * 0.9), + int(QApplication.desktop().screenGeometry().height() * 0.9), + ) layout = QVBoxLayout() dialog.setLayout(layout) @@ -1077,6 +1080,10 @@ def add_to_map( def edit_analysis_aggregation(self, analysis_item): """Open the AnalysisAggregationDialog for editing the weightings of factors in the analysis.""" dialog = AnalysisAggregationDialog(analysis_item, parent=self) + dialog.resize( + int(QApplication.desktop().screenGeometry().width() * 0.9), + int(QApplication.desktop().screenGeometry().height() * 0.9), + ) if dialog.exec_(): # If OK was clicked dialog.saveWeightingsToModel() self.save_json_to_working_directory() # Save changes to the JSON if necessary @@ -1090,6 +1097,10 @@ def edit_dimension_aggregation(self, dimension_item): dialog = DimensionAggregationDialog( dimension_name, dimension_data, dimension_item, parent=self ) + dialog.resize( + int(QApplication.desktop().screenGeometry().width() * 0.9), + int(QApplication.desktop().screenGeometry().height() * 0.9), + ) if dialog.exec_(): # If OK was clicked dialog.saveWeightingsToModel() self.save_json_to_working_directory() # Save changes to the JSON if necessary @@ -1103,6 +1114,10 @@ def edit_factor_aggregation(self, factor_item): dialog = FactorAggregationDialog( factor_name, factor_data, factor_item, parent=self ) + dialog.resize( + int(QApplication.desktop().screenGeometry().width() * 0.9), + int(QApplication.desktop().screenGeometry().height() * 0.9), + ) if dialog.exec_(): # If OK was clicked dialog.save_weightings_to_model() self.save_json_to_working_directory() # Save changes to the JSON if necessary diff --git a/geest/gui/toggle_switch.py b/geest/gui/toggle_switch.py index d23b8a1c..b0922269 100644 --- a/geest/gui/toggle_switch.py +++ b/geest/gui/toggle_switch.py @@ -1,5 +1,5 @@ from qgis.PyQt.QtWidgets import QWidget -from qgis.PyQt.QtCore import Qt, pyqtSignal, QSize +from qgis.PyQt.QtCore import Qt, pyqtSignal, QSize, QRect from qgis.PyQt.QtGui import QColor, QPainter @@ -10,7 +10,7 @@ class ToggleSwitch(QWidget): def __init__(self, initial_value=False, parent=None): super().__init__(parent) - self.setFixedSize(QSize(40, 20)) # Size of the toggle switch + self.setFixedSize(QSize(60, 26)) # Size of the toggle switch self.checked = initial_value def paintEvent(self, event): @@ -21,20 +21,22 @@ def paintEvent(self, event): # Background color based on state if self.checked: painter.setBrush( - QColor("#002244") + QColor("#fffdcf") ) # Active state color (blue) from WB Style Guide else: - painter.setBrush(QColor("#ADB5BD")) # Inactive state color (gray) + painter.setBrush(QColor("#fffdcf")) # Inactive state color (gray) # Draw the rounded rectangle as the background painter.setRenderHint(QPainter.Antialiasing) - painter.drawRoundedRect(rect, rect.height() // 2, rect.height() // 2) + painter.drawRoundedRect(rect, rect.height() // 4, rect.height() // 4) # Draw the circle (slider knob) - knob_radius = rect.height() - 6 - knob_x = rect.x() + 3 if not self.checked else rect.right() - knob_radius - 3 - painter.setBrush(QColor("#009CA7")) # From WB Style Guide - painter.drawEllipse(knob_x, rect.y() + 3, knob_radius, knob_radius) + knob_radius = rect.height() // 4 + knob_x = rect.x() if not self.checked else rect.right() - 30 + knob_rect = QRect(knob_x, rect.y(), 30, 26) + # knob_rect.setWidth(30) + painter.setBrush(QColor("#6FB7B5")) # From WB Style Guide + painter.drawRoundedRect(knob_rect, knob_radius, knob_radius) def mousePressEvent(self, event): """Toggle the switch on mouse click.""" diff --git a/geest/gui/widgets/datasource_widgets/vector_datasource_widget.py b/geest/gui/widgets/datasource_widgets/vector_datasource_widget.py index f53b9d1a..ae43355a 100644 --- a/geest/gui/widgets/datasource_widgets/vector_datasource_widget.py +++ b/geest/gui/widgets/datasource_widgets/vector_datasource_widget.py @@ -4,11 +4,12 @@ QToolButton, QFileDialog, ) +from qgis.PyQt.QtGui import QIcon +from qgis.PyQt.QtCore import QSettings, QEvent, Qt from qgis.gui import QgsMapLayerComboBox from .base_datasource_widget import BaseDataSourceWidget -from qgis.core import QgsMapLayerProxyModel, QgsProject, QgsVectorLayer -from qgis.PyQt.QtCore import QSettings -from geest.utilities import log_message +from qgis.core import QgsMapLayerProxyModel, QgsProject, Qgis +from geest.utilities import log_message, resources_path class VectorDataSourceWidget(BaseDataSourceWidget): @@ -69,6 +70,21 @@ def add_internal_widgets(self) -> None: self.shapefile_line_edit = QLineEdit() self.shapefile_line_edit.setVisible(False) # Hide initially + # Add clear button inside the line edit + self.clear_button = QToolButton(self.shapefile_line_edit) + clear_icon = QIcon(resources_path("resources", "icons", "clear.svg")) + self.clear_button.setIcon(clear_icon) + self.clear_button.setToolTip("Clear") + self.clear_button.setCursor(Qt.ArrowCursor) + self.clear_button.setStyleSheet("border: 0px; padding: 0px;") + self.clear_button.clicked.connect(self.clear_shapefile) + self.clear_button.setVisible(False) + + self.shapefile_line_edit.textChanged.connect( + lambda text: self.clear_button.setVisible(bool(text)) + ) + self.shapefile_line_edit.textChanged.connect(self.resize_clear_button) + # Add a button to select a shapefile self.shapefile_button = QToolButton() self.shapefile_button.setText("...") self.shapefile_button.clicked.connect(self.select_shapefile) @@ -77,7 +93,11 @@ def add_internal_widgets(self) -> None: self.attributes[f"{self.widget_key}_shapefile"] ) self.shapefile_line_edit.setVisible(True) + self.layer_combo.setVisible(False) + else: + self.layer_combo.setVisible(True) self.layout.addWidget(self.shapefile_line_edit) + self.resize_clear_button() self.layout.addWidget(self.shapefile_button) # Emit the data_changed signal when any widget is changed @@ -90,6 +110,31 @@ def add_internal_widgets(self) -> None: log_message(traceback.format_exc(), level=Qgis.Critical) + def resizeEvent(self, event): + """ + Handle resize events for the parent container. + + Args: + event: The resize event. + """ + super().resizeEvent(event) + self.resize_clear_button() + + def resize_clear_button(self): + """Reposition the clear button when the line edit is resized.""" + log_message("Resizing clear button") + # Position the clear button inside the line edit + frame_width = self.shapefile_line_edit.style().pixelMetric( + self.shapefile_line_edit.style().PM_DefaultFrameWidth + ) + self.shapefile_line_edit.setStyleSheet( + f"QLineEdit {{ padding-right: {self.clear_button.sizeHint().width() + frame_width}px; }}" + ) + sz = self.clear_button.sizeHint() + self.clear_button.move( + self.shapefile_line_edit.width() - sz.width() - frame_width - 5, 6 + ) + def select_shapefile(self): """ Opens a file dialog to select a shapefile and stores the last directory in QSettings. @@ -105,14 +150,28 @@ def select_shapefile(self): if file_path: # Update the line edit with the selected file path - self.shapefile_line_edit.setText(file_path) + # ⚠️ Be careful about changing the order of the following lines + # It could cause the clear button to render in the incorrect place + self.layer_combo.setVisible(False) self.shapefile_line_edit.setVisible(True) + self.shapefile_line_edit.setText(file_path) + # Trigger resize event explicitly + self.resizeEvent(None) # Save the directory of the selected file to QSettings settings.setValue("Geest/lastShapefileDir", os.path.dirname(file_path)) except Exception as e: log_message(f"Error selecting shapefile: {e}", level=Qgis.Critical) + def clear_shapefile(self): + """ + Clears the shapefile line edit and hides it along with the clear button. + """ + self.shapefile_line_edit.clear() + self.shapefile_line_edit.setVisible(False) + self.layer_combo.setVisible(True) + self.update_attributes() + def update_attributes(self): """ Updates the attributes dict to match the current state of the widget. diff --git a/geest/resources/icons/clear.svg b/geest/resources/icons/clear.svg new file mode 100644 index 00000000..dc43a6af --- /dev/null +++ b/geest/resources/icons/clear.svg @@ -0,0 +1,47 @@ + + + + + + + + diff --git a/geest/resources/images/clear.png b/geest/resources/images/clear.png new file mode 100644 index 00000000..a080ebdf Binary files /dev/null and b/geest/resources/images/clear.png differ