Semapp 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Semapp might be problematic. Click here for more details.
- semapp/Layout/__init__.py +26 -0
- semapp/Layout/create_button.py +496 -0
- semapp/Layout/main_window_att.py +54 -0
- semapp/Layout/settings.py +170 -0
- semapp/Layout/styles.py +152 -0
- semapp/Plot/__init__.py +8 -0
- semapp/Plot/frame_attributes.py +408 -0
- semapp/Plot/styles.py +40 -0
- semapp/Plot/utils.py +93 -0
- semapp/Processing/__init__.py +4 -0
- semapp/Processing/processing.py +599 -0
- semapp/__init__.py +0 -0
- semapp/main.py +86 -0
- semapp-1.0.0.dist-info/METADATA +21 -0
- semapp-1.0.0.dist-info/RECORD +19 -0
- semapp-1.0.0.dist-info/WHEEL +5 -0
- semapp-1.0.0.dist-info/entry_points.txt +2 -0
- semapp-1.0.0.dist-info/licenses/LICENSE +674 -0
- semapp-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""Module for settings window"""
|
|
2
|
+
# pylint: disable=no-name-in-module, trailing-whitespace, too-many-branches, too-many-statements
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
from PyQt5.QtWidgets import (
|
|
6
|
+
QDialog, QVBoxLayout, QTableWidget, QPushButton,
|
|
7
|
+
QTableWidgetItem
|
|
8
|
+
)
|
|
9
|
+
from PyQt5.QtCore import pyqtSignal
|
|
10
|
+
|
|
11
|
+
class SettingsWindow(QDialog):
|
|
12
|
+
"""Class for settings window"""
|
|
13
|
+
data_updated = pyqtSignal() # Signal emitted when data is updated
|
|
14
|
+
|
|
15
|
+
def __init__(self):
|
|
16
|
+
super().__init__()
|
|
17
|
+
self.setWindowTitle("Settings")
|
|
18
|
+
|
|
19
|
+
# Get the user's folder path (C:\Users\XXXXX)
|
|
20
|
+
self.user_folder = os.path.expanduser("~")
|
|
21
|
+
|
|
22
|
+
# Define the new folder "SEM" and the file to store settings
|
|
23
|
+
self.new_folder = os.path.join(self.user_folder, "SEM")
|
|
24
|
+
self.data_file = os.path.join(self.new_folder, "settings_data.json")
|
|
25
|
+
self.data = [] # Structure to store the table data
|
|
26
|
+
|
|
27
|
+
# Set up the UI layout
|
|
28
|
+
self.layout = QVBoxLayout()
|
|
29
|
+
self.setLayout(self.layout)
|
|
30
|
+
|
|
31
|
+
# Create and add the table and buttons to the layout
|
|
32
|
+
self.create_table()
|
|
33
|
+
self.create_buttons()
|
|
34
|
+
|
|
35
|
+
# Load data from the settings file
|
|
36
|
+
self.load_data()
|
|
37
|
+
|
|
38
|
+
def create_table(self):
|
|
39
|
+
"""Create the settings table."""
|
|
40
|
+
self.table = QTableWidget()
|
|
41
|
+
self.table.setColumnCount(2)
|
|
42
|
+
self.table.setHorizontalHeaderLabels(["Scale", "Image Type"])
|
|
43
|
+
|
|
44
|
+
# Temporarily block signals to prevent updates during initialization
|
|
45
|
+
self.table.blockSignals(True)
|
|
46
|
+
|
|
47
|
+
# Populate the table with existing data
|
|
48
|
+
for row_data in self.data:
|
|
49
|
+
if "Scale" in row_data and "Image Type" in row_data:
|
|
50
|
+
self.add_row(row_data["Scale"], row_data["Image Type"], update_data=False)
|
|
51
|
+
else:
|
|
52
|
+
print(f"Invalid row data: {row_data}")
|
|
53
|
+
|
|
54
|
+
# Re-enable signals after table population
|
|
55
|
+
self.table.blockSignals(False)
|
|
56
|
+
|
|
57
|
+
# Connect the itemChanged signal to update the data structure
|
|
58
|
+
self.table.itemChanged.connect(self.update_data)
|
|
59
|
+
self.layout.addWidget(self.table)
|
|
60
|
+
|
|
61
|
+
def create_buttons(self):
|
|
62
|
+
"""Create buttons to add and remove rows."""
|
|
63
|
+
add_button = QPushButton("Add Row")
|
|
64
|
+
remove_button = QPushButton("Remove Selected Row")
|
|
65
|
+
|
|
66
|
+
add_button.clicked.connect(self.add_row)
|
|
67
|
+
remove_button.clicked.connect(self.remove_selected_row)
|
|
68
|
+
|
|
69
|
+
self.layout.addWidget(add_button)
|
|
70
|
+
self.layout.addWidget(remove_button)
|
|
71
|
+
|
|
72
|
+
def add_row(self, scale="5x5", image_type="Type", update_data=True):
|
|
73
|
+
"""Add a new row to the table with default values."""
|
|
74
|
+
row_position = self.table.rowCount()
|
|
75
|
+
self.table.insertRow(row_position)
|
|
76
|
+
|
|
77
|
+
scale_item = QTableWidgetItem(scale)
|
|
78
|
+
image_type_item = QTableWidgetItem(image_type)
|
|
79
|
+
|
|
80
|
+
self.table.setItem(row_position, 0, scale_item)
|
|
81
|
+
self.table.setItem(row_position, 1, image_type_item)
|
|
82
|
+
|
|
83
|
+
if update_data:
|
|
84
|
+
self.data.append({"Scale": scale, "Image Type": image_type})
|
|
85
|
+
print("Row added:", self.data)
|
|
86
|
+
|
|
87
|
+
def remove_selected_row(self):
|
|
88
|
+
"""Remove the currently selected row from the table."""
|
|
89
|
+
current_row = self.table.currentRow()
|
|
90
|
+
if current_row != -1:
|
|
91
|
+
self.table.removeRow(current_row)
|
|
92
|
+
del self.data[current_row]
|
|
93
|
+
print("Row removed:", self.data)
|
|
94
|
+
|
|
95
|
+
def update_data(self, item):
|
|
96
|
+
"""Update the data structure when a cell value changes."""
|
|
97
|
+
try:
|
|
98
|
+
row = item.row()
|
|
99
|
+
column = item.column()
|
|
100
|
+
value = item.text().strip()
|
|
101
|
+
|
|
102
|
+
while len(self.data) <= row:
|
|
103
|
+
self.data.append({"Scale": "", "Image Type": ""})
|
|
104
|
+
|
|
105
|
+
if column == 0: # Update "Scale"
|
|
106
|
+
if not value.replace('.', '', 1).isdigit():
|
|
107
|
+
print(f"Invalid value for Scale: {value}")
|
|
108
|
+
return
|
|
109
|
+
self.data[row]["Scale"] = value
|
|
110
|
+
elif column == 1: # Update "Image Type"
|
|
111
|
+
self.data[row]["Image Type"] = value
|
|
112
|
+
else:
|
|
113
|
+
print(f"Unexpected column index: {column}")
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
self.save_data()
|
|
117
|
+
print(f"Data updated successfully: {self.data[row]}")
|
|
118
|
+
except Exception as e:
|
|
119
|
+
print(f"Error updating data: {e}")
|
|
120
|
+
|
|
121
|
+
def closeEvent(self, event):
|
|
122
|
+
"""Save data to a file when the dialog is closed."""
|
|
123
|
+
self.save_data()
|
|
124
|
+
self.data_updated.emit()
|
|
125
|
+
super().closeEvent(event)
|
|
126
|
+
|
|
127
|
+
def normalize_data(self):
|
|
128
|
+
"""Synchronize self.data with the actual table contents."""
|
|
129
|
+
self.data = self.get_table_data()
|
|
130
|
+
|
|
131
|
+
def save_data(self):
|
|
132
|
+
"""Save the table data to a JSON file."""
|
|
133
|
+
self.normalize_data()
|
|
134
|
+
with open(self.data_file, "w") as file:
|
|
135
|
+
json.dump(self.data, file, indent=4)
|
|
136
|
+
print("Data saved successfully.")
|
|
137
|
+
|
|
138
|
+
def load_data(self):
|
|
139
|
+
"""Load the table data from the JSON file."""
|
|
140
|
+
try:
|
|
141
|
+
with open(self.data_file, "r") as file:
|
|
142
|
+
self.data = json.load(file)
|
|
143
|
+
print("Data loaded successfully:", self.data)
|
|
144
|
+
except FileNotFoundError:
|
|
145
|
+
print("No previous data found. Starting fresh.")
|
|
146
|
+
self.data = []
|
|
147
|
+
except Exception as err:
|
|
148
|
+
print(f"Error loading data: {err}")
|
|
149
|
+
self.data = []
|
|
150
|
+
|
|
151
|
+
self.table.blockSignals(True)
|
|
152
|
+
self.table.setRowCount(0)
|
|
153
|
+
for row_data in self.data:
|
|
154
|
+
self.add_row(row_data.get("Scale", ""),
|
|
155
|
+
row_data.get("Image Type", ""), update_data=False)
|
|
156
|
+
self.table.blockSignals(False)
|
|
157
|
+
|
|
158
|
+
def get_table_data(self):
|
|
159
|
+
"""Get the current data from the table as a list of dictionaries."""
|
|
160
|
+
table_data = []
|
|
161
|
+
for row in range(self.table.rowCount()):
|
|
162
|
+
scale_item = self.table.item(row, 0)
|
|
163
|
+
image_type_item = self.table.item(row, 1)
|
|
164
|
+
|
|
165
|
+
if scale_item and image_type_item:
|
|
166
|
+
scale = scale_item.text()
|
|
167
|
+
image_type = image_type_item.text()
|
|
168
|
+
table_data.append({"Scale": scale, "Image Type": image_type})
|
|
169
|
+
|
|
170
|
+
return table_data
|
semapp/Layout/styles.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""Module containing all styles for the GUI"""
|
|
2
|
+
|
|
3
|
+
# Radio button styles
|
|
4
|
+
RADIO_BUTTON_STYLE = """
|
|
5
|
+
QRadioButton {
|
|
6
|
+
spacing: 0px;
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
}
|
|
9
|
+
QRadioButton::indicator {
|
|
10
|
+
width: 20px;
|
|
11
|
+
height: 20px;
|
|
12
|
+
}
|
|
13
|
+
QRadioButton::indicator:checked {
|
|
14
|
+
background-color: #f0ca41;
|
|
15
|
+
border: 2px solid black;
|
|
16
|
+
}
|
|
17
|
+
QRadioButton::indicator:unchecked {
|
|
18
|
+
background-color: white;
|
|
19
|
+
border: 2px solid #ccc;
|
|
20
|
+
}
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
# Settings button style
|
|
24
|
+
SETTINGS_BUTTON_STYLE = """
|
|
25
|
+
QPushButton {
|
|
26
|
+
font-size: 16px;
|
|
27
|
+
background-color: #b3e5fc;
|
|
28
|
+
border: 2px solid #8c8c8c;
|
|
29
|
+
border-radius: 10px;
|
|
30
|
+
padding: 5px;
|
|
31
|
+
height: 100px;
|
|
32
|
+
}
|
|
33
|
+
QPushButton:hover {
|
|
34
|
+
background-color: #64b5f6;
|
|
35
|
+
}
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
# Run button style
|
|
39
|
+
RUN_BUTTON_STYLE = """
|
|
40
|
+
QPushButton {
|
|
41
|
+
font-size: 16px;
|
|
42
|
+
background-color: #ffcc80;
|
|
43
|
+
border: 2px solid #8c8c8c;
|
|
44
|
+
border-radius: 10px;
|
|
45
|
+
padding: 5px;
|
|
46
|
+
height: 100px;
|
|
47
|
+
}
|
|
48
|
+
QPushButton:hover {
|
|
49
|
+
background-color: #ffb74d;
|
|
50
|
+
}
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
# Group box style
|
|
54
|
+
GROUP_BOX_STYLE = """
|
|
55
|
+
QGroupBox {
|
|
56
|
+
border: 1px solid black;
|
|
57
|
+
border-radius: 5px;
|
|
58
|
+
margin-top: 10px;
|
|
59
|
+
font-size: 20px;
|
|
60
|
+
font-weight: bold;
|
|
61
|
+
}
|
|
62
|
+
QGroupBox::title {
|
|
63
|
+
font-size: 14px;
|
|
64
|
+
font-weight: bold;
|
|
65
|
+
subcontrol-origin: margin;
|
|
66
|
+
subcontrol-position: top center;
|
|
67
|
+
}
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
# Wafer button styles
|
|
71
|
+
WAFER_BUTTON_DEFAULT_STYLE = """
|
|
72
|
+
QRadioButton {
|
|
73
|
+
spacing: 0px;
|
|
74
|
+
font-size: 16px;
|
|
75
|
+
}
|
|
76
|
+
QRadioButton::indicator {
|
|
77
|
+
width: 25px;
|
|
78
|
+
height: 25px;
|
|
79
|
+
}
|
|
80
|
+
QRadioButton::indicator:checked {
|
|
81
|
+
background-color: #ccffcc;
|
|
82
|
+
border: 2px solid black;
|
|
83
|
+
}
|
|
84
|
+
QRadioButton::indicator:unchecked {
|
|
85
|
+
background-color: white;
|
|
86
|
+
border: 2px solid #ccc;
|
|
87
|
+
}
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
WAFER_BUTTON_EXISTING_STYLE = """
|
|
91
|
+
QRadioButton {
|
|
92
|
+
spacing: 0px;
|
|
93
|
+
font-size: 16px;
|
|
94
|
+
}
|
|
95
|
+
QRadioButton::indicator {
|
|
96
|
+
width: 25px;
|
|
97
|
+
height: 25px;
|
|
98
|
+
border: 2px solid #ccc;
|
|
99
|
+
background-color: lightblue;
|
|
100
|
+
}
|
|
101
|
+
QRadioButton::indicator:checked {
|
|
102
|
+
background-color: #ccffcc;
|
|
103
|
+
border: 2px solid black;
|
|
104
|
+
}
|
|
105
|
+
QRadioButton::indicator:unchecked {
|
|
106
|
+
background-color: lightblue;
|
|
107
|
+
border: 2px solid #ccc;
|
|
108
|
+
}
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
WAFER_BUTTON_MISSING_STYLE = """
|
|
112
|
+
QRadioButton {
|
|
113
|
+
spacing: 0px;
|
|
114
|
+
font-size: 16px;
|
|
115
|
+
}
|
|
116
|
+
QRadioButton::indicator {
|
|
117
|
+
width: 25px;
|
|
118
|
+
height: 25px;
|
|
119
|
+
border: 2px solid #ccc;
|
|
120
|
+
background-color: lightcoral;
|
|
121
|
+
}
|
|
122
|
+
QRadioButton::indicator:checked {
|
|
123
|
+
background-color: #ccffcc;
|
|
124
|
+
border: 2px solid black;
|
|
125
|
+
}
|
|
126
|
+
QRadioButton::indicator:unchecked {
|
|
127
|
+
background-color: lightcoral;
|
|
128
|
+
border: 2px solid #ccc;
|
|
129
|
+
}
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
# Style pour les boutons de sélection de dossier/fichier
|
|
133
|
+
SELECT_BUTTON_STYLE = """
|
|
134
|
+
QPushButton {
|
|
135
|
+
font-size: 16px;
|
|
136
|
+
background-color: #b3e5fc;
|
|
137
|
+
border: 2px solid #8c8c8c;
|
|
138
|
+
border-radius: 10px;
|
|
139
|
+
padding: 10px;
|
|
140
|
+
}
|
|
141
|
+
QPushButton:hover {
|
|
142
|
+
background-color: #64b5f6;
|
|
143
|
+
}
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
# Style pour les labels de chemin
|
|
147
|
+
PATH_LABEL_STYLE = """
|
|
148
|
+
QLabel {
|
|
149
|
+
font-size: 14px;
|
|
150
|
+
padding: 5px;
|
|
151
|
+
}
|
|
152
|
+
"""
|