Skip to content

Commit 4a9ca72

Browse files
fix main indentations
1 parent e628ada commit 4a9ca72

1 file changed

Lines changed: 45 additions & 140 deletions

File tree

pica/main.py

Lines changed: 45 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# BUILD VERSION: 1.0.0
21
'''
32
===============================================================================
43
PROGRAM: PICA Launcher
@@ -24,6 +23,7 @@
2423
import multiprocessing
2524
from multiprocessing import Process
2625

26+
# Ensure this import exists in your project structure
2727
from pica.utils.GPIB_Instrument_Scanner_GUI import GPIB_Instrument_Scanner_GUI
2828

2929
try:
@@ -34,7 +34,7 @@
3434

3535
try:
3636
import pyvisa
37-
import pyvisa.errors # Import pyvisa.errors
37+
import pyvisa.errors
3838
PYVISA_AVAILABLE = True
3939
except ImportError:
4040
PYVISA_AVAILABLE = False
@@ -57,14 +57,10 @@ def run_script_process(script_path):
5757
def launch_plotter_utility():
5858
"""
5959
Finds and launches the plotter utility script in a new process.
60-
This function is designed to be imported and used by other frontends.
6160
"""
6261
try:
63-
# Assuming the plotter is in a standard location relative to other
64-
# scripts
6562
script_dir = os.path.dirname(os.path.abspath(__file__))
66-
plotter_path = os.path.join(
67-
script_dir, "utils", "PlotterUtil_GUI.py")
63+
plotter_path = os.path.join(script_dir, "utils", "PlotterUtil_GUI.py")
6864
Process(target=run_script_process, args=(plotter_path,)).start()
6965
except Exception as e:
7066
print(f"Failed to launch plotter: {e}")
@@ -73,8 +69,6 @@ def launch_plotter_utility():
7369
def resource_path(relative_path):
7470
"""
7571
Get absolute path to resource, works for dev and for PyInstaller.
76-
It checks for resources in the application's root directory when running
77-
from source, and within the package directory when installed.
7872
"""
7973
try:
8074
base_path = sys._MEIPASS
@@ -107,14 +101,12 @@ class PICALauncherApp:
107101
FONT_SIZE_BASE = 12
108102
FONT_BASE = ('Segoe UI', FONT_SIZE_BASE)
109103
FONT_TITLE = ('Segoe UI', FONT_SIZE_BASE + 10, 'bold')
110-
FONT_SUBTITLE = ('Segoe UI', FONT_SIZE_BASE + 1, 'bold') # Reduced size from +2
111-
FONT_INSTITUTE = (
112-
'Segoe UI',
113-
FONT_SIZE_BASE + 6,
114-
'bold') # New font for institute
104+
FONT_SUBTITLE = ('Segoe UI', FONT_SIZE_BASE + 1, 'bold')
105+
FONT_INSTITUTE = ('Segoe UI', FONT_SIZE_BASE + 6, 'bold')
115106
FONT_CONSOLE = ('Consolas', 10)
116107
FONT_INFO = ('Segoe UI', FONT_SIZE_BASE)
117108
FONT_INFO_ITALIC = ('Segoe UI', FONT_SIZE_BASE, 'italic')
109+
118110
LOGO_FILE = resource_path("assets/LOGO/UGC_DAE_CSR_NBG.jpeg")
119111
MANUAL_FILE = resource_path("docs/User_Manual.md")
120112
README_FILE = resource_path("README.md")
@@ -127,92 +119,45 @@ class PICALauncherApp:
127119
# Based on Updates.md, using the latest versions of scripts.
128120
"Delta Mode I-V Sweep": resource_path("keithley/delta_mode/IV_K6221_DC_Sweep_GUI.py"),
129121
"Delta Mode R-T": resource_path("keithley/delta_mode/Delta_RT_K6221_K2182_L350_T_Control_GUI.py"),
130-
"Delta Mode R-T (T_Sensing)": resource_path(
131-
"keithley/delta_mode/Delta_RT_K6221_K2182_L350_Sensing_GUI.py"),
122+
"Delta Mode R-T (T_Sensing)": resource_path("keithley/delta_mode/Delta_RT_K6221_K2182_L350_Sensing_GUI.py"),
132123
"K2400 I-V": resource_path("keithley/k2400/IV_K2400_GUI.py"),
133124
"K2400 R-T": resource_path("keithley/k2400/RT_K2400_L350_T_Control_GUI.py"),
134125
"K2400 R-T (T_Sensing)": resource_path("keithley/k2400/RT_K2400_L350_T_Sensing_GUI.py"),
135126
"K2400_2182 I-V": resource_path("keithley/k2400_2182/IV_K2400_K2182_GUI.py"),
136127
"K2400_2182 R-T": resource_path("keithley/k2400_2182/RT_K2400_K2182_T_Control_GUI.py"),
137-
"K2400_2182 R-T (T_Sensing)": resource_path(
138-
"keithley/k2400_2182/RT_K2400_K2182_L350_T_Sensing_GUI.py"),
128+
"K2400_2182 R-T (T_Sensing)": resource_path("keithley/k2400_2182/RT_K2400_K2182_L350_T_Sensing_GUI.py"),
139129
"K6517B I-V": resource_path("keithley/k6517b/High_Resistance/IV_K6517B_GUI.py"),
140130
"K6517B R-T": resource_path("keithley/k6517b/High_Resistance/RT_K6517B_L350_T_Control_GUI.py"),
141131
"K6517B R-T (T_Sensing)": resource_path("keithley/k6517b/High_Resistance/RT_K6517B_L350_T_Sensing_GUI.py"),
142132
"Pyroelectric Current": resource_path("keithley/k6517b/Pyroelectricity/Pyroelectric_K6517B_L350_GUI.py"),
143133
"Lakeshore Temp Control": resource_path("lakeshore/T_Control_L350_RangeControl_GUI.py"),
144134
"Lakeshore Temp Monitor": resource_path("lakeshore/T_Sensing_L350_GUI.py"),
145135
"LCR C-V Measurement": resource_path("keysight/CV_KE4980A_GUI.py"),
146-
"Plotter Utility": resource_path("utils/PlotterUtil_GUI.py"),
147-
"GPIB Scanner": resource_path("utils/GPIB_Instrument_Scanner_GUI.py"),
148-
"PICA Help": resource_path("README.md"),
149-
}
150-
151-
152-
def launch_pica_script(script_key):
153-
"""
154-
Globally accessible function to launch PICA scripts by their key.
155-
This uses the same resource_path and Process logic as PICALauncherApp
156-
to ensure consistency and correct path resolution for installed packages.
157-
"""
158-
if script_key not in PICALauncherApp.SCRIPT_PATHS:
159-
print(f"ERROR: Script key '{script_key}' not found in PICA SCRIPT_PATHS.")
160-
messagebox.showwarning(
161-
"Script Not Found",
162-
f"The script key '{script_key}' is not defined in the main application's script paths.")
163-
return
164-
165-
script_path = PICALauncherApp.SCRIPT_PATHS[script_key]
166-
print(f"Launching external script: {os.path.basename(script_path)}")
167-
abs_path = os.path.abspath(script_path)
168-
169-
if not os.path.exists(abs_path):
170-
print(f"ERROR: Script not found at {abs_path}")
171-
messagebox.showerror(
172-
"File Not Found",
173-
f"Script not found:\n\n{abs_path}")
174-
return
175-
176-
try:
177-
proc = Process(target=run_script_process, args=(abs_path,))
178-
proc.start()
179-
print(f"Successfully launched '{os.path.basename(script_path)}' in a new process.")
180-
except Exception as e:
181-
print(f"ERROR: Failed to launch script '{script_key}'. Reason: {e}")
182-
messagebox.showerror(
183-
"Launch Error",
184-
f"An error occurred while launching the script '{script_key}':\n\n{e}")
185-
186-
187-
class PICALauncherApp:
188-
189-
PROGRAM_VERSION = "1.0.0"
190-
CLR_BG_DARK = '#2B3D4F'
191-
CLR_FRAME_BG = '#3A506B'
192-
CLR_ACCENT_GOLD = '#FFC107'
193-
CLR_ACCENT_GREEN = '#A7C957'
194-
CLR_TEXT = '#EDF2F4'
195-
CLR_TEXT_DARK = '#1A1A1A'
196-
CLR_CONSOLE_BG = '#1E2B38'
197-
CLR_LINK = '#87CEEB' # Sky Blue, for better contrast
198-
FONT_SIZE_BASE = 12
199-
FONT_BASE = ('Segoe UI', FONT_SIZE_BASE)
200-
FONT_TITLE = ('Segoe UI', FONT_SIZE_BASE + 10, 'bold')
201-
FONT_SUBTITLE = ('Segoe UI', FONT_SIZE_BASE + 1, 'bold') # Reduced size from +2
202-
FONT_INSTITUTE = (
203-
'Segoe UI',
204-
FONT_SIZE_BASE + 6,
205-
'bold') # New font for institute
206-
FONT_CONSOLE = ('Consolas', 10)
207-
FONT_INFO = ('Segoe UI', FONT_SIZE_BASE)
208-
FONT_INFO_ITALIC = ('Segoe UI', FONT_SIZE_BASE, 'italic')
209-
LOGO_FILE = resource_path("assets/LOGO/UGC_DAE_CSR_NBG.jpeg")
210-
MANUAL_FILE = resource_path("docs/User_Manual.md")
211-
README_FILE = resource_path("README.md")
212-
LICENSE_FILE = resource_path("LICENSE")
213-
UPDATES_FILE = resource_path("CHANGELOG.md")
214-
REPO_URL = "https://github.com/prathameshnium/PICA-Python-Instrument-Control-and-Automation/tree/main"
215-
LOGO_SIZE = 140
136+
"Plotter Utility": resource_path("utils/PlotterUtil_GUI.py"),
137+
"GPIB Scanner": resource_path("utils/GPIB_Instrument_Scanner_GUI.py"),
138+
"PICA Help": resource_path("README.md"),
139+
}
140+
141+
def __init__(self, root):
142+
"""Constructor to initialize the main application window."""
143+
self.root = root
144+
self.root.title(f"PICA Launcher - v{self.PROGRAM_VERSION}")
145+
self.root.geometry("1100x750")
146+
self.root.configure(bg=self.CLR_BG_DARK)
147+
148+
# Initialize internal variables
149+
self.logo_image = None
150+
self.console_widget = None
151+
self._md_cache = {}
152+
153+
# Setup UI
154+
self.setup_styles()
155+
self.create_widgets()
156+
157+
# Background tasks
158+
self._pre_cache_markdown_files()
159+
self.log(f"PICA Launcher initialized (v{self.PROGRAM_VERSION})")
160+
216161
def setup_styles(self):
217162
style = ttk.Style(self.root)
218163
style.theme_use('clam')
@@ -241,9 +186,7 @@ def setup_styles(self):
241186
style.configure(
242187
'App.TButton',
243188
font=self.FONT_BASE,
244-
padding=(
245-
10,
246-
5),
189+
padding=(10, 5),
247190
foreground=self.CLR_ACCENT_GOLD,
248191
background=self.CLR_FRAME_BG,
249192
borderwidth=0,
@@ -256,22 +199,16 @@ def setup_styles(self):
256199
style.configure(
257200
'Scan.TButton',
258201
font=self.FONT_BASE,
259-
padding=(
260-
10,
261-
9),
202+
padding=(10, 9),
262203
foreground=self.CLR_TEXT_DARK,
263204
background=self.CLR_ACCENT_GREEN)
264205
style.map(
265206
'Scan.TButton', background=[
266207
('active', '#8AB845'), ('hover', '#8AB845')])
267208
style.configure(
268209
'Icon.TButton',
269-
font=(
270-
'Segoe UI',
271-
12),
272-
padding=(
273-
5,
274-
9),
210+
font=('Segoe UI', 12),
211+
padding=(5, 9),
275212
foreground=self.CLR_ACCENT_GOLD,
276213
background=self.CLR_FRAME_BG,
277214
borderwidth=0)
@@ -320,9 +257,7 @@ def create_resource_panel(self, parent):
320257
font=self.FONT_INSTITUTE,
321258
justify='center',
322259
anchor='center').pack(
323-
pady=(
324-
0,
325-
15))
260+
pady=(0, 15))
326261

327262
ttk.Label(
328263
info_frame,
@@ -331,9 +266,7 @@ def create_resource_panel(self, parent):
331266
foreground=self.CLR_ACCENT_GOLD,
332267
justify='center',
333268
anchor='center').pack(
334-
pady=(
335-
0,
336-
15))
269+
pady=(0, 15))
337270

338271
desc_text = "A modular software suite for automating laboratory measurements in physics research."
339272
ttk.Label(
@@ -343,9 +276,7 @@ def create_resource_panel(self, parent):
343276
wraplength=360,
344277
justify='center',
345278
anchor='center').pack(
346-
pady=(
347-
0,
348-
10))
279+
pady=(0, 10))
349280

350281
# --- Create a bold font for names ---
351282
bold_font = font.Font(
@@ -359,18 +290,14 @@ def create_resource_panel(self, parent):
359290
font=bold_font,
360291
justify='center',
361292
anchor='center').pack(
362-
pady=(
363-
5,
364-
0))
293+
pady=(5, 0))
365294
ttk.Label(
366295
info_frame,
367296
text="Vision & Guidance by Dr. Sudip Mukherjee",
368297
font=bold_font,
369298
justify='center',
370299
anchor='center').pack(
371-
pady=(
372-
0,
373-
15))
300+
pady=(0, 15))
374301

375302
ttk.Separator(info_frame, orient='horizontal').pack(fill='x', pady=10)
376303
util_frame = ttk.Frame(info_frame)
@@ -527,13 +454,10 @@ def _on_mousewheel_linux_macos(event):
527454

528455
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
529456
canvas.configure(yscrollcommand=scrollbar.set)
530-
# Bind scrolling only to relevant widgets for better performance and to
531-
# enable it
532-
# For Windows and some Linux
457+
458+
# Bind scrolling
533459
canvas.bind("<MouseWheel>", _on_mousewheel_windows)
534-
# For Linux and macOS
535460
canvas.bind("<Button-4>", _on_mousewheel_linux_macos)
536-
# For Linux and macOS
537461
canvas.bind("<Button-5>", _on_mousewheel_linux_macos)
538462

539463
canvas.grid(row=0, column=0, sticky='nsew', pady=10)
@@ -633,7 +557,6 @@ def _create_suite_frame(
633557
instruments_text,
634558
buttons):
635559
"""Helper to create a measurement suite frame, reducing code duplication."""
636-
# Reduce vertical padding to make the card smaller
637560
frame = ttk.LabelFrame(parent, text=title, style='TLabelframe')
638561
frame.pack(fill='x', expand=True, pady=5)
639562
frame.columnconfigure(0, weight=1)
@@ -661,9 +584,6 @@ def _create_suite_frame(
661584
badge.pack(side='left', anchor='w')
662585

663586
if instruments_text:
664-
# Use a Label that can wrap text to prevent truncation.
665-
# The wraplength is an estimate; it will wrap if the text exceeds
666-
# this width.
667587
instrument_label = ttk.Label(
668588
left_header,
669589
text=instruments_text,
@@ -728,19 +648,10 @@ def _open_path(self, path):
728648
messagebox.showerror(
729649
"Error", f"Could not open path: {path}\n\nError: {e}")
730650

731-
# =========================================================================
732-
# === THIS FUNCTION IS NOW UPDATED WITH THE MARKDOWN PARSER ==============
733-
# =========================================================================
734651
def _parse_markdown(self, content):
735652
"""
736653
Parses markdown content into a list of (text, tags) for rendering.
737-
This is a placeholder for a more sophisticated parser if needed.
738-
For now, we just split by lines as the original did.
739-
The key is that this runs only once per file.
740654
"""
741-
# This is a placeholder for a more sophisticated parser if needed.
742-
# For now, we just split by lines as the original did.
743-
# The key is that this runs only once per file.
744655
return content.split('\n')
745656

746657
def _show_file_in_window(self, file_path, title):
@@ -842,8 +753,7 @@ def run_gpib_test(self):
842753

843754
def _pre_cache_markdown_files(self):
844755
"""
845-
Reads and parses key markdown/text files in the background to make
846-
the documentation windows open instantly.
756+
Reads and parses key markdown/text files in the background.
847757
"""
848758
files_to_cache = [
849759
(self.README_FILE, "README"),
@@ -972,8 +882,6 @@ def _render_markdown_content(self, text_area, lines):
972882
text_area.insert('end', '\n')
973883

974884

975-
976-
977885
def main():
978886
"""Initializes and runs the main application."""
979887
root = tk.Tk()
@@ -983,9 +891,6 @@ def main():
983891

984892
if __name__ == '__main__':
985893
# This is ESSENTIAL for multiprocessing to work in a bundled executable
986-
# and ensures a consistent, stable process creation method across platforms.
987-
# 'spawn' is the most robust method for GUI apps, though it is the default
988-
# on Windows and macOS.
989894
multiprocessing.set_start_method('spawn', force=True)
990895
multiprocessing.freeze_support()
991896

0 commit comments

Comments
 (0)