diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 019bc1c7..d6362b37 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -6,6 +6,7 @@ on:
- main
jobs:
+ # Job 1: Linters for Pull Requests
linters:
runs-on: windows-latest
strategy:
@@ -27,3 +28,29 @@ jobs:
run: flake8 parallax tests
continue-on-error: true
+ # Job 2: Build Documentation for Pushes to Main
+ build-docs:
+ runs-on: ubuntu-latest
+ steps:
+ # Step 1: Checkout the repository
+ - name: Checkout Repository
+ uses: actions/checkout@v3
+
+ # Step 2: Set up Python
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.8'
+
+ # Step 3: Install dependencies (including Sphinx)
+ - name: Install Dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r docs/requirements.txt
+
+ # Step 4: Build the documentation
+ - name: Build Documentation
+ run: |
+ sphinx-build -b html docs/source docs/_build
+ # Fail the workflow if documentation build fails
+ continue-on-error: false
diff --git a/parallax/__init__.py b/parallax/__init__.py
index 3f9c7742..642a0470 100644
--- a/parallax/__init__.py
+++ b/parallax/__init__.py
@@ -4,7 +4,7 @@
import os
-__version__ = "0.37.27"
+__version__ = "0.37.29"
# allow multiple OpenMP instances
os.environ["KMP_DUPLICATE_LIB_OK"] = "True"
diff --git a/parallax/calculator.py b/parallax/calculator.py
index 2b6ae8da..61383965 100644
--- a/parallax/calculator.py
+++ b/parallax/calculator.py
@@ -20,7 +20,7 @@ def __init__(self, model, reticle_selector, stage_controller):
self.reticle = None
self.stage_controller = stage_controller
- self.ui = loadUi(os.path.join(ui_dir, "calc_move.ui"), self)
+ self.ui = loadUi(os.path.join(ui_dir, "calc.ui"), self)
self.setWindowTitle(f"Calculator")
self.setWindowFlags(Qt.Window | Qt.WindowMinimizeButtonHint | \
Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint)
@@ -236,7 +236,7 @@ def _disable(self, sn):
group_box = self.findChild(QGroupBox, f"groupBox_{sn}")
group_box.setEnabled(False)
group_box.setStyleSheet("background-color: #333333;")
- group_box.setTitle(f"{sn} (Uncalibrated)")
+ group_box.setTitle(f"(Uncalibrated) {sn}")
def _enable(self, sn):
# Find the QGroupBox for the stage
@@ -251,11 +251,11 @@ def _create_stage_groupboxes(self):
for sn in self.model.stages.keys():
# Load the QGroupBox from the calc_QGroupBox.ui file
group_box = QGroupBox(self)
- #loadUi(os.path.join(ui_dir, "calc_QGroupBox.ui"), group_box) # TODO
- loadUi(os.path.join(ui_dir, "calc_QGroupBox_move.ui"), group_box)
+ loadUi(os.path.join(ui_dir, "calc_QGroupBox.ui"), group_box)
# Set the visible title of the QGroupBox to sn
group_box.setTitle(f"{sn}")
+ group_box.setAlignment(Qt.AlignRight) # title alignment to the right
# Append _{sn} to the QGroupBox object name
group_box.setObjectName(f"groupBox_{sn}")
@@ -274,7 +274,6 @@ def _create_stage_groupboxes(self):
# Add the newly created QGroupBox to the layout
widget_count = self.ui.verticalLayout_QBox.count()
self.ui.verticalLayout_QBox.insertWidget(widget_count - 1, group_box)
- #self.ui.verticalLayout_QBox.addWidget(group_box)
def _connect_move_stage_buttons(self):
stop_button = self.ui.findChild(QPushButton, f"stopAllStages")
@@ -302,11 +301,16 @@ def _move_stage(self, stage_sn, move_type):
# Convert the text to float, round it, then cast to int
x = float(self.findChild(QLineEdit, f"localX_{stage_sn}").text())/1000
y = float(self.findChild(QLineEdit, f"localY_{stage_sn}").text())/1000
- z = 15.0
+ z = 15.0 # Z is inverted in the server.
except ValueError as e:
logger.warning(f"Invalid input for stage {stage_sn}: {e}")
return # Optionally handle the error gracefully (e.g., show a message to the user)
+ # Safety Check: Check z=15 is high position of stage.
+ if not self._is_z_safe_pos(stage_sn, x, y, z):
+ logger.warning(f"Invalid z position for stage {stage_sn}")
+ return
+
# Use the confirm_move_stage function to ask for confirmation
if self._confirm_move_stage(x, y):
# If the user confirms, proceed with moving the stage
@@ -323,6 +327,41 @@ def _move_stage(self, stage_sn, move_type):
# If the user cancels, do nothing
print("Stage move canceled by user.")
+ def _is_z_safe_pos(self, stage_sn, x, y, z):
+ """
+ Check if the Z=15 position is safe for the stage. (z=15 is the top of the stage)
+
+ Args:
+ stage_sn (str): The serial number of the stage.
+ x (float): The x-coordinate of the stage.
+ y (float): The y-coordinate of the stage.
+ z (float): The z-coordinate (set to 15.0).
+
+ Returns:
+ bool: True if the Z position is safe, False otherwise.
+ """
+ # Z is inverted in the server
+ local_pts_z15 = [float(x)*1000, float(y)*1000, float(15.0 - z)*1000] # Should be top of the stage
+ local_pts_z0 = [float(x)*1000, float(y)*1000, 15.0*1000] # Should be bottom
+ for sn, item in self.model.transforms.items():
+ if sn != stage_sn:
+ continue
+
+ transM, scale = item[0], item[1]
+ if transM is not None:
+ try:
+ # Apply transformations to get global points for Z=15 and Z=0
+ global_pts_z15 = self._apply_transformation(local_pts_z15, transM, scale)
+ global_pts_z0 = self._apply_transformation(local_pts_z0, transM, scale)
+
+ # Ensure that Z=15 is higher than Z=0 and Z=15 is positive
+ if global_pts_z15[2] > global_pts_z0[2] and global_pts_z15[2] > 0:
+ return True
+ except Exception as e:
+ logger.error(f"Error applying transformation for stage {stage_sn}: {e}")
+ return False
+ return False
+
def _confirm_move_stage(self, x, y):
"""
Displays a confirmation dialog asking the user if they are sure about moving the stage.
diff --git a/parallax/camera.py b/parallax/camera.py
index 7fa16205..77456813 100755
--- a/parallax/camera.py
+++ b/parallax/camera.py
@@ -21,8 +21,7 @@
import PySpin
except ImportError:
PySpin = None
- logger.warn("Could not import PySpin.")
-
+ logger.warning("Could not import PySpin.")
def list_cameras(dummy=False, version="V1"):
"""
@@ -254,22 +253,23 @@ def set_wb(self, channel, wb=1.2):
Args:
- wb (float): The desired white balance value. min:1.8, max:2.5
"""
- if self.device_color_type == "Color":
- self.node_wbauto_mode.SetIntValue(
- self.node_wbauto_mode_off.GetValue()
- )
- if channel == "Red":
- self.node_balanceratio_mode.SetIntValue(
- self.node_balanceratio_mode_red.GetValue()
- )
- self.node_wb.SetValue(wb)
- elif channel == "Blue":
- self.node_balanceratio_mode.SetIntValue(
- self.node_balanceratio_mode_blue.GetValue()
+ try:
+ if self.device_color_type == "Color":
+ self.node_wbauto_mode.SetIntValue(
+ self.node_wbauto_mode_off.GetValue()
)
- self.node_wb.SetValue(wb)
- else:
- pass
+ if channel == "Red":
+ self.node_balanceratio_mode.SetIntValue(
+ self.node_balanceratio_mode_red.GetValue()
+ )
+ self.node_wb.SetValue(wb)
+ elif channel == "Blue":
+ self.node_balanceratio_mode.SetIntValue(
+ self.node_balanceratio_mode_blue.GetValue()
+ )
+ self.node_wb.SetValue(wb)
+ except Exception as e:
+ logger.error(f"An error occurred while setting the white balance: {e}")
def get_wb(self, channel):
"""
@@ -302,8 +302,11 @@ def set_gamma(self, gamma=1.0):
Args:
- gamma (float): The desired gamma value. min:0.25 max:1.25
"""
- self.node_gammaenable_mode.SetValue(True)
- self.node_gamma.SetValue(gamma)
+ try:
+ self.node_gammaenable_mode.SetValue(True)
+ self.node_gamma.SetValue(gamma)
+ except Exception as e:
+ logger.error(f"An error occurred while setting the gamma: {e}")
def disable_gamma(self):
"""
@@ -318,10 +321,13 @@ def set_gain(self, gain=20.0):
Args:
- gain (float): The desired gain value. min:0, max:27.0
"""
- self.node_gainauto_mode.SetIntValue(
- self.node_gainauto_mode_off.GetValue()
- )
- self.node_gain.SetValue(gain)
+ try:
+ self.node_gainauto_mode.SetIntValue(
+ self.node_gainauto_mode_off.GetValue()
+ )
+ self.node_gain.SetValue(gain)
+ except Exception as e:
+ logger.error(f"An error occurred while setting the gain: {e}")
def get_gain(self):
"""
@@ -346,10 +352,13 @@ def set_exposure(self, expTime=16000):
Args:
- expTime (int): The desired exposure time in microseconds.
"""
- self.node_expauto_mode.SetIntValue(
- self.node_expauto_mode_off.GetValue()
- ) # Return back to manual mode
- self.node_exptime.SetValue(expTime)
+ try:
+ self.node_expauto_mode.SetIntValue(
+ self.node_expauto_mode_off.GetValue()
+ ) # Return back to manual mode
+ self.node_exptime.SetValue(expTime)
+ except Exception as e:
+ logger.error(f"An error occurred while setting the exposure: {e}")
def get_exposure(self):
"""
@@ -434,26 +443,30 @@ def begin_continuous_acquisition(self):
print("Error: camera is already running")
return -1
- # set acquisition mode continuous (continuous stream of images)
- node_acquisition_mode = PySpin.CEnumerationPtr(
- self.node_map.GetNode("AcquisitionMode")
- )
- node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName(
- "Continuous"
- )
- acquisition_mode_continuous = (
- node_acquisition_mode_continuous.GetValue()
- )
- node_acquisition_mode.SetIntValue(acquisition_mode_continuous)
-
- # Begin Acquisition: Image acquisition must be ended when no more images are needed.
- self.camera.BeginAcquisition()
- logger.debug(f"BeginAcquisition {self.name(sn_only=True)} ")
- self.running = True
- self.capture_thread = threading.Thread(
- target=self.capture_loop, daemon=True
- )
- self.capture_thread.start()
+ try:
+ # set acquisition mode continuous (continuous stream of images)
+ node_acquisition_mode = PySpin.CEnumerationPtr(
+ self.node_map.GetNode("AcquisitionMode")
+ )
+ node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName(
+ "Continuous"
+ )
+ acquisition_mode_continuous = (
+ node_acquisition_mode_continuous.GetValue()
+ )
+ node_acquisition_mode.SetIntValue(acquisition_mode_continuous)
+
+ # Begin Acquisition: Image acquisition must be ended when no more images are needed.
+ self.camera.BeginAcquisition()
+ logger.debug(f"BeginAcquisition {self.name(sn_only=True)} ")
+ self.running = True
+ self.capture_thread = threading.Thread(
+ target=self.capture_loop, daemon=True
+ )
+ self.capture_thread.start()
+ except Exception as e:
+ logger.error(f"An error occurred while starting the camera: {e}")
+ print(f"Error: An error occurred while starting the camera {e}")
def capture_loop(self):
"""
@@ -537,8 +550,7 @@ def get_last_capture_time(self, millisecond=False):
)
def save_last_image(
- self, filepath, isTimestamp=False, custom_name="Microscope_"
- ):
+ self, filepath, isTimestamp=False, custom_name="Microscope_"):
"""
Saves the last captured image to the specified file path.
diff --git a/parallax/probe_calibration.py b/parallax/probe_calibration.py
index cf9f2eab..282d2638 100644
--- a/parallax/probe_calibration.py
+++ b/parallax/probe_calibration.py
@@ -7,7 +7,7 @@
import csv
import logging
import os
-
+import datetime
import numpy as np
import pandas as pd
from PyQt5.QtCore import QObject, pyqtSignal
@@ -89,8 +89,11 @@ def __init__(self, model, stage_listener):
self.origin, self.R, self.scale = None, None, np.array([1, 1, 1])
self.avg_err = None
self.last_row = None
+
+ # create file for points.csv
+ self.log_dir = None
self._create_file()
-
+
def reset_calib(self, sn=None):
"""
Resets calibration to its initial state, clearing any stored min and max values.
@@ -119,9 +122,10 @@ def _create_file(self):
Creates or clears the CSV file used to store local and global points during calibration.
"""
package_dir = os.path.dirname(os.path.abspath(__file__))
- debug_dir = os.path.join(os.path.dirname(package_dir), "debug")
- os.makedirs(debug_dir, exist_ok=True)
- self.csv_file = os.path.join(debug_dir, "points.csv")
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
+ self.log_dir = os.path.join(os.path.dirname(package_dir), f"debug/log_{timestamp}")
+ os.makedirs(self.log_dir, exist_ok=True) # Create the log directory if it doesn't exist
+ self.csv_file = os.path.join(self.log_dir, "points.csv")
# Check if the file exists and remove it if it does
if os.path.exists(self.csv_file):
@@ -523,11 +527,12 @@ def _save_df_to_csv(self, df, file_name):
Args:
filtered_df (pd.DataFrame): DataFrame containing filtered local and global points.
"""
+ if self.log_dir is None:
+ logger.error("log_dir is not initialized.")
+ return
+
# Save the updated DataFrame back to the CSV file
- package_dir = os.path.dirname(os.path.abspath(__file__))
- debug_dir = os.path.join(os.path.dirname(package_dir), "debug")
- os.makedirs(debug_dir, exist_ok=True)
- csv_file = os.path.join(debug_dir, file_name)
+ csv_file = os.path.join(self.log_dir, file_name)
df.to_csv(csv_file, index=False)
return csv_file
@@ -618,7 +623,8 @@ def update(self, stage, debug_info=None):
def complete_calibration(self, filtered_df):
# save the filtered points to a new file
print("ProbeCalibration: complete_calibration")
- self.file_name = f"points_{self.stage.sn}.csv"
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
+ self.file_name = f"points_{self.stage.sn}_{timestamp}.csv"
self.transM_LR = self._get_transM(filtered_df, save_to_csv=True, file_name=self.file_name, noise_threshold=20)
if self.transM_LR is None:
@@ -628,7 +634,7 @@ def complete_calibration(self, filtered_df):
self._print_formatted_transM()
print("=========================================================")
self._update_info_ui(disp_avg_error=True, save_to_csv=True, \
- file_name = f"transM_{self.stage.sn}.csv")
+ file_name = f"transM_{self.stage.sn}_{timestamp}.csv")
if self.model.bundle_adjustment:
self.old_transM, self.old_scale = self.transM_LR, self.scale
@@ -639,7 +645,7 @@ def complete_calibration(self, filtered_df):
self._print_formatted_transM()
print("=========================================================")
self._update_info_ui(disp_avg_error=True, save_to_csv=True, \
- file_name = f"transM_BA_{self.stage.sn}.csv")
+ file_name = f"transM_BA_{self.stage.sn}_{timestamp}.csv")
else:
return
diff --git a/parallax/screen_coords_mapper.py b/parallax/screen_coords_mapper.py
index 01d27655..dab11eee 100644
--- a/parallax/screen_coords_mapper.py
+++ b/parallax/screen_coords_mapper.py
@@ -26,7 +26,7 @@ def _clicked_position(self, camera_name, pos):
global_coords = self._get_global_coords_BA(camera_name, pos)
if global_coords is None:
return
-
+
global_coords = np.round(global_coords*1000, decimals=1)
reticle_name = self.reticle_selector.currentText()
if "Proj" not in reticle_name:
diff --git a/parallax/stage_controller.py b/parallax/stage_controller.py
index ad51cd6c..299b3ee5 100644
--- a/parallax/stage_controller.py
+++ b/parallax/stage_controller.py
@@ -98,7 +98,9 @@ def move_request(self, command):
def _check_z_position(self, probe_index, target_z, command):
"""Check Z position and proceed with X, Y movement once target is reached."""
self.timer_count += 1
- if self.timer_count > 30: # 30 * 500 ms = 15 seconds
+ # Outside software might control the stage and never reached to z target.
+ # Thus, stop the timer after 20 seconds.
+ if self.timer_count > 40: # 40 * 500 ms = 20 seconds
if hasattr(self, 'timer') and self.timer.isActive():
self.timer.stop()
logger.warning("Timer stopped due to timeout.")
diff --git a/ui/calc.ui b/ui/calc.ui
index 85598f30..7c05ff4b 100644
--- a/ui/calc.ui
+++ b/ui/calc.ui
@@ -6,8 +6,8 @@
0
0
- 890
- 347
+ 953
+ 638
@@ -39,6 +39,23 @@ QPushButton#startButton:disabled:checked {
}
QPushButton#startButton:disabled:!checked {
background-color: lightGreen;
+}
+QMessageBox {
+ background-color: rgb(00,00,00);
+ color: #FFFFFF;
+}
+QMessageBox QLabel {
+ color: #FFFFFF;
+}
+QMessageBox QPushButton {
+ background-color: rgb(50,50,50);
+ color: #FFFFFF;
+}
+QMessageBox QPushButton:hover {
+ background-color: rgb(100, 30, 30);
+}
+QMessageBox QPushButton:pressed {
+ background-color: rgb(224, 0, 0);
}
@@ -46,8 +63,8 @@ QPushButton#startButton:disabled:!checked {
10
10
- 861
- 621
+ 921
+ 601
@@ -105,7 +122,7 @@ QPushButton#startButton:disabled:!checked {
}
- (x, y, z)
+ (x, y, z)
Qt::AlignCenter
@@ -132,6 +149,40 @@ QPushButton#startButton:disabled:!checked {
10
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+
+
+
+ resources/stop-sign.pngresources/stop-sign.png
+
+
+
+ 64
+ 64
+
+
+
+
+
+
-
diff --git a/ui/calc_QGroupBox.ui b/ui/calc_QGroupBox.ui
index 8c9ac62e..fa8a18ed 100644
--- a/ui/calc_QGroupBox.ui
+++ b/ui/calc_QGroupBox.ui
@@ -6,14 +6,14 @@
0
0
- 829
- 123
+ 914
+ 130
750
- 100
+ 130
@@ -41,13 +41,31 @@ QPushButton#startButton:disabled:checked {
}
QPushButton#startButton:disabled:!checked {
background-color: lightGreen;
+}
+
+QMessageBox {
+ background-color: rgb(00,00,00);
+ color: #FFFFFF;
+}
+QMessageBox QLabel {
+ color: #FFFFFF;
+}
+QMessageBox QPushButton {
+ background-color: rgb(50,50,50);
+ color: #FFFFFF;
+}
+QMessageBox QPushButton:hover {
+ background-color: rgb(100, 30, 30);
+}
+QMessageBox QPushButton:pressed {
+ background-color: rgb(224, 0, 0);
}
- 140
- 40
+ 130
+ 58
100
40
@@ -72,8 +90,8 @@ QPushButton#startButton:disabled:!checked {
- 250
- 40
+ 240
+ 58
100
40
@@ -98,8 +116,8 @@ QPushButton#startButton:disabled:!checked {
- 30
- 40
+ 20
+ 58
100
40
@@ -124,8 +142,8 @@ QPushButton#startButton:disabled:!checked {
- 410
- 40
+ 400
+ 58
100
40
@@ -145,8 +163,8 @@ QPushButton#startButton:disabled:!checked {
- 360
- 50
+ 350
+ 68
40
21
@@ -175,8 +193,8 @@ QPushButton#startButton:disabled:!checked {
- 630
- 40
+ 620
+ 58
100
40
@@ -202,8 +220,8 @@ QPushButton#startButton:disabled:!checked {
- 520
- 40
+ 510
+ 58
100
40
@@ -229,9 +247,9 @@ QPushButton#startButton:disabled:!checked {
- 750
- 50
- 61
+ 740
+ 68
+ 51
23
@@ -250,6 +268,34 @@ QPushButton#startButton:disabled:!checked {
Clear
+
+
+
+ 810
+ 58
+ 61
+ 41
+
+
+
+
+ 7
+
+
+
+
+
+
+
+ resources/move_xy0.pngresources/move_xy0.png
+
+
+
+ 64
+ 64
+
+
+
globalX
diff --git a/ui/calc_QGroupBox_move.ui b/ui/calc_QGroupBox_move.ui
deleted file mode 100644
index 0e27780c..00000000
--- a/ui/calc_QGroupBox_move.ui
+++ /dev/null
@@ -1,311 +0,0 @@
-
-
- SN
-
-
-
- 0
- 0
- 914
- 123
-
-
-
-
- 750
- 100
-
-
-
- GroupBox
-
-
- QWidget{
-background-color: rgb(00,00,00);
-color: #FFFFFF;
-}
-QPushButton{
- background-color: black;
-}
- QPushButton:pressed {
- background-color: rgb(224, 0, 0);
-}
-QPushButton:hover {
- background-color: rgb(100, 30, 30);
-}
-QPushButton#startButton:disabled:checked {
- color: gray;
-}
-QPushButton#startButton:disabled:checked {
- background-color: #ffaaaa;
-}
-QPushButton#startButton:disabled:!checked {
- background-color: lightGreen;
-}
-
-QMessageBox {
- background-color: rgb(00,00,00);
- color: #FFFFFF;
-}
-QMessageBox QLabel {
- color: #FFFFFF;
-}
-QMessageBox QPushButton {
- background-color: rgb(50,50,50);
- color: #FFFFFF;
-}
-QMessageBox QPushButton:hover {
- background-color: rgb(100, 30, 30);
-}
-QMessageBox QPushButton:pressed {
- background-color: rgb(224, 0, 0);
-}
-
-
-
-
- 140
- 40
- 100
- 40
-
-
-
-
- 100
- 40
-
-
-
-
- 8
-
-
-
- QLineEdit {
- color: yellow;
-}
-
-
-
-
-
- 250
- 40
- 100
- 40
-
-
-
-
- 100
- 40
-
-
-
-
- 8
-
-
-
- QLineEdit {
- color: yellow;
-}
-
-
-
-
-
- 30
- 40
- 100
- 40
-
-
-
-
- 100
- 40
-
-
-
-
- 8
-
-
-
- QLineEdit {
- color: yellow;
-}
-
-
-
-
-
- 410
- 40
- 100
- 40
-
-
-
-
- 100
- 40
-
-
-
-
- 8
-
-
-
-
-
-
- 360
- 50
- 40
- 21
-
-
-
-
- 40
- 0
-
-
-
-
- 40
- 16777215
-
-
-
-
- 12
-
-
-
- ↔
-
-
-
-
-
- 630
- 40
- 100
- 40
-
-
-
-
- 100
- 40
-
-
-
-
- 200
- 16777215
-
-
-
-
- 8
-
-
-
-
-
-
- 520
- 40
- 100
- 40
-
-
-
-
- 100
- 40
-
-
-
-
- 200
- 16777215
-
-
-
-
- 8
-
-
-
-
-
-
- 750
- 50
- 51
- 23
-
-
-
-
- 40
- 0
-
-
-
-
- 7
-
-
-
- Clear
-
-
-
-
-
- 820
- 40
- 61
- 41
-
-
-
-
- 7
-
-
-
-
-
-
-
- resources/move_xy0.pngresources/move_xy0.png
-
-
-
- 64
- 64
-
-
-
-
-
- globalX
- globalY
- globalZ
- convert
- localX
- localY
- localZ
-
-
-
-
diff --git a/ui/calc_move.ui b/ui/calc_move.ui
deleted file mode 100644
index 02feeb39..00000000
--- a/ui/calc_move.ui
+++ /dev/null
@@ -1,206 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 953
- 638
-
-
-
- Form
-
-
-
- resources/calc.pngresources/calc.png
-
-
- QWidget{
-background-color: rgb(00,00,00);
-color: #FFFFFF;
-}
-QPushButton{
- background-color: black;
-}
- QPushButton:pressed {
- background-color: rgb(224, 0, 0);
-}
-QPushButton:hover {
- background-color: rgb(100, 30, 30);
-}
-QPushButton#startButton:disabled:checked {
- color: gray;
-}
-QPushButton#startButton:disabled:checked {
- background-color: #ffaaaa;
-}
-QPushButton#startButton:disabled:!checked {
- background-color: lightGreen;
-}
-QMessageBox {
- background-color: rgb(00,00,00);
- color: #FFFFFF;
-}
-QMessageBox QLabel {
- color: #FFFFFF;
-}
-QMessageBox QPushButton {
- background-color: rgb(50,50,50);
- color: #FFFFFF;
-}
-QMessageBox QPushButton:hover {
- background-color: rgb(100, 30, 30);
-}
-QMessageBox QPushButton:pressed {
- background-color: rgb(224, 0, 0);
-}
-
-
-
-
- 10
- 10
- 921
- 601
-
-
-
-
- 10
-
-
-
-
-
-
-
-
-
- 16777215
- 50
-
-
-
- QLabel {
- color: yellow;
-}
-
-
- Global
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
- 16777215
- 50
-
-
-
- Local
-
-
- Qt::AlignCenter
-
-
-
-
-
- -
-
-
-
-
-
- QLabel {
- color: yellow;
-}
-
-
- (x, y, z)
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- (x, y, z)
-
-
- Qt::AlignCenter
-
-
-
-
-
- -
-
-
- 20
-
-
- 10
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
-
-
-
- resources/stop-sign.pngresources/stop-sign.png
-
-
-
- 64
- 64
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
-
diff --git a/ui/reticle_QGroupBox.ui b/ui/reticle_QGroupBox.ui
index 6c91580c..40a8a663 100644
--- a/ui/reticle_QGroupBox.ui
+++ b/ui/reticle_QGroupBox.ui
@@ -6,7 +6,7 @@
0
0
- 1109
+ 829
150
@@ -142,11 +142,11 @@ QPushButton#startButton:disabled:!checked {
- 7
+ 8
- RotDegrees
+ Rotate Degrees (CCW)
@@ -160,7 +160,7 @@ QPushButton#startButton:disabled:!checked {
- 7
+ 8
@@ -200,11 +200,11 @@ QPushButton#startButton:disabled:!checked {
- 7
+ 8
- ReticleName
+ Reticle Name
@@ -218,7 +218,7 @@ QPushButton#startButton:disabled:!checked {
- 7
+ 8
@@ -236,7 +236,7 @@ QPushButton#startButton:disabled:!checked {
- 7
+ 8
@@ -248,16 +248,27 @@ QPushButton#startButton:disabled:!checked {
770
70
- 30
- 31
+ 40
+ 40
+
+
+ 40
+ 40
+
+
- 30
- 16777215
+ 40
+ 40
+
+
+ 10
+
+
-
diff --git a/ui/reticle_metadata.ui b/ui/reticle_metadata.ui
index cd3832e3..0d2ff551 100644
--- a/ui/reticle_metadata.ui
+++ b/ui/reticle_metadata.ui
@@ -6,8 +6,8 @@
0
0
- 890
- 183
+ 881
+ 303
@@ -52,7 +52,7 @@ QPushButton#startButton:disabled:!checked {
10
10
- 861
+ 851
831
@@ -89,6 +89,11 @@ QPushButton#startButton:disabled:!checked {
16777215
+
+
+ 15
+
+
+
@@ -102,6 +107,11 @@ QPushButton#startButton:disabled:!checked {
16777215
+
+
+ 10
+
+
Update