Moved all code here + adjusting code to work with new structure.

This commit is contained in:
Mr Finchum 2025-01-03 12:13:05 +01:00
parent a97cc3e2ee
commit 9ff18a7aef
11 changed files with 2426 additions and 0 deletions

282
src/OptimaLab35/gui.py Normal file
View file

@ -0,0 +1,282 @@
import sys
import os
from datetime import datetime
from optima35.core import OptimaManager
from OptimaLab35.utils.utility import Utilities
from OptimaLab35.ui.main_window import Ui_MainWindow
from OptimaLab35.ui.exif_handler_window import ExifEditor
from OptimaLab35.ui.simple_dialog import SimpleDialog # Import the SimpleDialog class
from PySide6 import QtWidgets
from PySide6.QtWidgets import (
QMessageBox,
QApplication,
QMainWindow,
QWidget,
QVBoxLayout,
QLabel,
QLineEdit,
QPushButton,
QCheckBox,
QFileDialog,
QHBoxLayout,
QSpinBox,
)
class OptimaLab35(QMainWindow, Ui_MainWindow):
def __init__(self):
super(OptimaLab35, self).__init__()
self.name = "OptimaLab35"
self.version = "0.0.3-a1"
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.o = OptimaManager()
self.u = Utilities()
self.u.program_configs()
self.exif_file = os.path.expanduser("~/.config/OptimaLab35/exif.yaml")
self.available_exif_data = None
self.settings = {}
self.setWindowTitle(f"{self.name} v{self.version}")
self._default_ui_layout()
self._define_gui_interaction()
self.sd = SimpleDialog()
self._change_statusbar(f"Using {self.o.name} v{self.o.version}", 5000)
def _default_ui_layout(self):
self.ui.png_quality_spinBox.setVisible(False)
def _define_gui_interaction(self):
self.ui.input_folder_button.clicked.connect(self._browse_input_folder)
self.ui.output_folder_button.clicked.connect(self._browse_output_folder)
self.ui.start_button.clicked.connect(self._process)
self.ui.image_type.currentIndexChanged.connect(self._update_quality_options)
self.ui.exif_checkbox.stateChanged.connect(
lambda state: self._handle_checkbox_state(state, 2, self._populate_exif)
)
self.ui.tabWidget.currentChanged.connect(self._on_tab_changed)
self.ui.edit_exif_button.clicked.connect(self._open_exif_editor)
self.ui.actionInfo.triggered.connect(self._info_window)
def _info_window(self):
self.sd.show_dialog(f"{self.name} v{self.version}", f"{self.name} v{self.version} is a GUI for {self.o.name} (v{self.o.version})")
def _process(self):
self.ui.start_button.setEnabled(False)
self._update_settings() # Get all user selected data
input_folder_valid = os.path.exists(self.settings["input_folder"])
output_folder_valid = os.path.exists(self.settings["output_folder"])
if not input_folder_valid or not output_folder_valid:
QMessageBox.warning(self, "Warning", f"Input location {input_folder_valid}\nOutput folder {output_folder_valid}...")
return
input_folder = self.settings["input_folder"]
output_folder = self.settings["output_folder"]
image_files = [
f for f in os.listdir(input_folder) if f.lower().endswith((".png", ".jpg", ".jpeg", ".webp"))
]
i = 1
for image_file in image_files:
input_path = os.path.join(input_folder, image_file)
if self.settings["new_file_names"] != False:
image_name = self.u.append_number_to_name(self.settings["new_file_names"], i, len(image_files), self.settings["invert_image_order"])
else:
image_name = os.path.splitext(image_file)[0]
output_path = os.path.join(output_folder, image_name)
self.o.process_image(
image_input_file = input_path,
image_output_file = output_path,
file_type = self.settings["file_format"],
quality = self.settings["jpg_quality"],
compressing = self.settings["png_compression"],
optimize = self.ui.optimize_checkBox.isChecked(),
resize = self.settings["resize"],
watermark = self.settings["watermark"],
font_size = self.settings["font_size"],
grayscale = self.settings["grayscale"],
brightness = self.settings["brightness"],
contrast = self.settings["contrast"],
dict_for_exif = self.user_selected_exif,
gps = self.settings["gps"],
copy_exif = self.settings["copy_exif"])
self._handle_qprogressbar(i, len(image_files))
i += 1
QMessageBox.information(self, "Information", "Finished")
self.ui.start_button.setEnabled(True)
self.ui.progressBar.setValue(0)
def _open_exif_editor(self):
"""Open the EXIF Editor."""
self.exif_editor = ExifEditor(self.available_exif_data)
self.exif_editor.exif_data_updated.connect(self._update_exif_data)
self.exif_editor.show()
def _update_exif_data(self, updated_exif_data):
"""Update the EXIF data."""
self.exif_data = updated_exif_data
self._populate_exif()
def _handle_checkbox_state(self, state, desired_state, action):
"""Perform an action based on the checkbox state and a desired state. Have to use lambda when calling."""
if state == desired_state:
action()
def _on_tab_changed(self, index):
"""Handle tab changes."""
# chatgpt
if index == 1: # EXIF Tab
self._handle_exif_file("read")
elif index == 0: # Main Tab
self._handle_exif_file("write")
def _handle_exif_file(self, do):
if do == "read":
self.available_exif_data = self.u.read_yaml(self.exif_file)
elif do == "write":
self.u.write_yaml(self.exif_file, self.available_exif_data)
def _populate_exif(self):
# partly chatGPT
# Mapping of EXIF fields to comboboxes in the UI
combo_mapping = {
"make": self.ui.make_comboBox,
"model": self.ui.model_comboBox,
"lens": self.ui.lens_comboBox,
"iso": self.ui.iso_comboBox,
"image_description": self.ui.image_description_comboBox,
"user_comment": self.ui.user_comment_comboBox,
"artist": self.ui.artist_comboBox,
"copyright_info": self.ui.copyright_info_comboBox,
}
self._populate_comboboxes(combo_mapping)
def _populate_comboboxes(self, combo_mapping):
"""Populate comboboxes with EXIF data."""
# ChatGPT
for field, comboBox in combo_mapping.items():
comboBox.clear() # Clear existing items
comboBox.addItems(map(str, self.available_exif_data.get(field, [])))
def _update_quality_options(self):
"""Update visibility of quality settings based on selected format."""
# ChatGPT
selected_format = self.ui.image_type.currentText()
# Hide all quality settings
self.ui.png_quality_spinBox.setVisible(False)
self.ui.jpg_quality_spinBox.setVisible(False)
# Show relevant settings
if selected_format == "jpg":
self.ui.jpg_quality_spinBox.setVisible(True)
elif selected_format == "webp":
self.ui.jpg_quality_spinBox.setVisible(True)
elif selected_format == "png":
self.ui.png_quality_spinBox.setVisible(True)
def _browse_input_folder(self):
folder = QFileDialog.getExistingDirectory(self, "Select Input Folder")
if folder:
self.ui.input_path.setText(folder)
def _browse_output_folder(self):
folder = QFileDialog.getExistingDirectory(self, "Select Output Folder")
if folder:
self.ui.output_path.setText(folder)
def _change_statusbar(self, msg, timeout = 500):
self.ui.statusBar.showMessage(msg, timeout)
def _handle_qprogressbar(self, current, total):
progress = int((100 / total) * current)
self.ui.progressBar.setValue(progress)
def _get_checkbox_value(self, checkbox, default=None):
"""Helper function to get the value of a checkbox or a default value."""
return checkbox.isChecked() if checkbox else default
def _get_spinbox_value(self, spinbox, default=None):
"""Helper function to get the value of a spinbox and handle empty input."""
return int(spinbox.text()) if spinbox.text() else default
def _get_combobox_value(self, combobox, default=None):
"""Helper function to get the value of a combobox."""
return combobox.currentIndex() + 1 if combobox.currentIndex() != -1 else default
def _get_text_value(self, lineedit, default=None):
"""Helper function to get the value of a text input field."""
return lineedit.text() if lineedit.text() else default
def _get_selected_exif(self):
"""Collect selected EXIF data and handle date and GPS if necessary."""
selected_exif = self._collect_selected_exif() if self.ui.exif_checkbox.isChecked() else None
if selected_exif:
if self.ui.add_date_checkBox.isChecked():
selected_exif["date_time_original"] = self._get_date()
if self.ui.gps_checkBox.isChecked():
self.settings["gps"] = [self.ui.lat_lineEdit.text(), self.ui.long_lineEdit.text()]
else:
self.settings["gps"] = None
return selected_exif
def _update_settings(self):
"""Update .settings from all GUI elements."""
# General settings
self.settings["input_folder"] = self._get_text_value(self.ui.input_path)
self.settings["output_folder"] = self._get_text_value(self.ui.output_path)
self.settings["file_format"] = self.ui.image_type.currentText()
self.settings["jpg_quality"] = self._get_spinbox_value(self.ui.jpg_quality_spinBox)
self.settings["png_compression"] = self._get_spinbox_value(self.ui.png_quality_spinBox)
self.settings["invert_image_order"] = self._get_checkbox_value(self.ui.revert_checkbox)
self.settings["grayscale"] = self._get_checkbox_value(self.ui.grayscale_checkBox)
self.settings["copy_exif"] = self._get_checkbox_value(self.ui.exif_copy_checkBox)
self.settings["own_exif"] = self._get_checkbox_value(self.ui.exif_checkbox)
self.settings["font_size"] = self._get_combobox_value(self.ui.font_size_comboBox)
self.settings["optimize"] = self._get_checkbox_value(self.ui.optimize_checkBox)
self.settings["own_date"] = self._get_checkbox_value(self.ui.add_date_checkBox)
# Conditional settings with logic
self.settings["resize"] = self._get_spinbox_value(self.ui.resize_spinBox) if self.ui.resize_checkbox.isChecked() else None
self.settings["brightness"] = self._get_spinbox_value(self.ui.brightness_spinBox) if self.ui.brightness_checkbox.isChecked() else None
self.settings["contrast"] = self._get_spinbox_value(self.ui.contrast_spinBox) if self.ui.contrast_checkbox.isChecked() else None
self.settings["new_file_names"] = self._get_text_value(self.ui.filename, False) if self.ui.rename_checkbox.isChecked() else False
self.settings["watermark"] = self._get_text_value(self.ui.watermark_lineEdit) if self.ui.watermark_checkbox.isChecked() else None
# Handle EXIF data selection
if self.settings["own_exif"]:
self.user_selected_exif = self._get_selected_exif()
else:
self.user_selected_exif = None
self.settings["gps"] = None
def _get_date(self):
date_input = self.ui.dateEdit.date().toString("yyyy-MM-dd")
new_date = datetime.strptime(date_input, "%Y-%m-%d")
return new_date.strftime("%Y:%m:%d 00:00:00")
def _collect_selected_exif(self):
user_data = {}
user_data["make"] = self.ui.make_comboBox.currentText()
user_data["model"] = self.ui.model_comboBox.currentText()
user_data["lens"] = self.ui.lens_comboBox.currentText()
user_data["iso"] = self.ui.iso_comboBox.currentText()
user_data["image_description"] = self.ui.image_description_comboBox.currentText()
user_data["user_comment"] = self.ui.user_comment_comboBox.currentText()
user_data["artist"] = self.ui.artist_comboBox.currentText()
user_data["copyright_info"] = self.ui.copyright_info_comboBox.currentText()
user_data["software"] = f"{self.o.name} {self.o.version}"
return user_data
def main():
app = QtWidgets.QApplication(sys.argv)
window = OptimaLab35()
window.show()
app.exec()
if __name__ == "__main__":
main()

43
src/OptimaLab35/main.py Normal file
View file

@ -0,0 +1,43 @@
import os
from argparse import ArgumentParser
from OptimaLab35 import gui, tui
# Mainly from ChatGPT
def check_pyside_installed():
try:
import PySide6 # Replace with PySide2 if using that version
return True
except ImportError:
return False
def start_gui():
gui.main()
def start_tui():
tui.main()
def main():
parser = ArgumentParser(description="Start the Optima35 application.")
parser.add_argument("--tui", action="store_true", help="Start in terminal UI mode.")
args = parser.parse_args()
if args.tui:
print("Starting TUI...")
start_tui()
return
# Check OS and start GUI if on Windows
if os.name == "nt":
print("Detected Windows. Starting GUI...")
start_gui()
else:
# Non-Windows: Check if PySide is installed
if check_pyside_installed():
print("PySide detected. Starting GUI...")
start_gui()
else:
print("PySide is not installed. Falling back to TUI...")
start_tui()
if __name__ == "__main__":
main()

329
src/OptimaLab35/tui.py Normal file
View file

@ -0,0 +1,329 @@
import os
from datetime import datetime
# my packages
from optima35.core import OptimaManager
from OptimaLab35.utils.utility import Utilities
from OptimaLab35.ui.simple_tui import SimpleTUI
class OptimaLab35_lite():
def __init__(self):
self.name = "OptimaLab35-lite"
self.version = "0.0.3-a1"
self.o = OptimaManager()
self.u = Utilities()
self.tui = SimpleTUI()
self.u.program_configs()
self.exif_file = os.path.expanduser("~/.config/OptimaLab35/exif.yaml")
self.available_exif_data = self.u.read_yaml(self.exif_file)
self.setting_file = os.path.expanduser("~/.config/OptimaLab35/tui_settings.yaml")
self.settings = {
"input_folder": None,
"output_folder": None,
"file_format": None,
"resize": None,
"copy_exif": None,
"contrast": None,
"brightness": None,
"new_file_names": None,
"invert_image_order": False,
"watermark": None,
"gps": None,
"modifications": [],
}
self.settings_to_save = [
"resize",
"jpg_quality",
"png_compression",
"optimize",
"contrast",
"brightness"
]
def _process(self):
self._check_options() # Get all user selected data
input_folder_valid = os.path.exists(self.settings["input_folder"])
output_folder_valid = os.path.exists(self.settings["output_folder"])
if not input_folder_valid or not output_folder_valid:
print("Warning", f"Input location {input_folder_valid}\nOutput folder {output_folder_valid}...")
return
input_folder = self.settings["input_folder"]
output_folder = self.settings["output_folder"]
image_files = [
f for f in os.listdir(input_folder) if f.lower().endswith((".png", ".jpg", ".jpeg", ".webp"))
]
i = 1
for image_file in image_files:
input_path = os.path.join(input_folder, image_file)
if self.settings["new_file_names"] != False:
image_name = self.u.append_number_to_name(self.settings["new_file_names"], i, len(image_files), self.settings["invert_image_order"])
else:
image_name = os.path.splitext(image_file)[0]
output_path = os.path.join(output_folder, image_name)
self.o.process_image(
image_input_file = input_path,
image_output_file = output_path,
file_type = self.settings["file_format"],
quality = self.settings["jpg_quality"],
compressing = self.settings["png_compression"],
optimize = self.settings["optimize"],
resize = self.settings["resize"],
watermark = self.settings["watermark"],
font_size = self.settings["font_size"],
grayscale = self.settings["grayscale"],
brightness = self.settings["brightness"],
contrast = self.settings["contrast"],
dict_for_exif = self.selected_exif,
gps = self.settings["gps"],
copy_exif = self.settings["copy_exif"])
self.u.progress_bar(i, len(image_files))
i += 1
def _check_options(self):
try:
if "Resize image" in self.settings["modifications"]:
self.settings["resize"] = self.settings["resize"]
else:
self.settings["resize"] = None
if "Convert to grayscale" in self.settings["modifications"]:
self.settings["grayscale"] = True
else:
self.settings["grayscale"] = False
if "Change contrast" in self.settings["modifications"]:
self.settings["contrast"] = self.settings["contrast"]
else:
self.settings["contrast"] = None
if "Change brightness" in self.settings["modifications"]:
self.settings["brightness"] = self.settings["brightness"]
else:
self.settings["brightness"] = None
if "Rename images" in self.settings["modifications"]:
self.settings["new_file_names"] = self.settings["new_file_names"]
else:
self.settings["new_file_names"] = False
if "Invert image order" in self.settings["modifications"]:
self.settings["invert_image_order"] = True
else:
self.settings["invert_image_order"] = False
if "Add Watermark" in self.settings["modifications"]:
self.settings["watermark"] = self.settings["watermark"]
else:
self.settings["watermark"] = None
self.settings["optimize"] = self.settings["optimize"]
self.settings["png_compression"] = self.settings["png_compression"]
self.settings["jpg_quality"] = self.settings["jpg_quality"]
self.settings["input_folder"] = self.settings["input_folder"]
self.settings["output_folder"] = self.settings["output_folder"]
self.settings["file_format"] = self.settings["file_format"]
self.settings["font_size"] = 2 # need to add option to select size
self.settings["copy_exif"] = self.settings["copy_exif"]
if "Change EXIF" in self.settings["modifications"]: #missing
self.selected_exif = self._collect_exif_data() #
else:
self.selected_exif = None
except Exception as e:
print(f"Whoops: {e}")
def _load_or_ask_settings(self):
"""Load settings from a YAML file or ask the user if not present or incomplete."""
try:
if self._read_settings(self.settings_to_save):
for item in self.settings_to_save:
print(f"{item}: {self.settings[item]}")
use_saved = self.tui.yes_no_menu("Use these settings?")
if use_saved:
return
else:
print("No settings found...")
self._ask_for_settings()
except Exception as e:
print(f"Error: {e}")
self._ask_for_settings()
def _ask_for_settings(self):
print("Asking for new settings...\n")
print(f"Settings for {self.name} v{self.version} will be saved {self.setting_file}...")
self.settings["resize"] = self.take_input_and_validate(question = "Default resize percentage (below 100 downscale, above upscale): ", accepted_type = int, min_value = 10, max_value = 200)
self.settings["contrast"] = self.take_input_and_validate(question = "Default contrast percentage (negative = decrease, positive = increase): ", accepted_type = int, min_value = -100, max_value = 100)
self.settings["brightness"] = self.take_input_and_validate(question = "Default brighness percentage (negative = decrease, positive = increase): ", accepted_type = int, min_value = -100, max_value = 100)
self.settings["jpg_quality"] = self.take_input_and_validate(question = "JPEG quality (1-100, 80 default): ", accepted_type = int, min_value = 1, max_value = 100)
self.settings["png_compression"] = self.take_input_and_validate(question = "PNG compression level (0-9, 6 default): ", accepted_type = int, min_value = 0, max_value = 9)
self.settings["optimize"] = self.tui.yes_no_menu("Optimize images i.e. compressing?")
self._write_settings(self.settings_to_save)
def _write_settings(self, keys_to_save):
""""Write self.setting, but only specific values"""
keys = keys_to_save
filtered_settings = {key: self.settings[key] for key in keys if key in self.settings}
self.u.write_yaml(self.setting_file, filtered_settings)
print("New settings saved successfully.")
def _read_settings(self, keys_to_load):
"""
Read settings from the settings file and update self.settings
with the values for specific keys without overwriting existing values.
"""
# First draft by ChatGPT, adjusted to fit my needs.
keys = keys_to_load
if os.path.exists(self.setting_file):
loaded_settings = self.u.read_yaml(self.setting_file)
for key in keys:
if key in loaded_settings:
self.settings[key] = loaded_settings[key]
print("Settings loaded successfully.")
return True
else:
print("Settings file empty.")
return False
def _collect_exif_data(self):
"""Collect EXIF data based on user input."""
print(f"Exif file can be found {self.exif_file}...")
user_data = {}
fields = [
"make", "model", "lens", "iso", "image_description",
"user_comment", "artist", "copyright_info"
]
for field in fields:
choise = self.tui.choose_menu(f"Enter {field.replace('_', ' ').title()}", self.available_exif_data[field])
user_data[field] = choise
user_data["software"] = f"{self.o.name} {self.o.version}"
new_date = self._get_date_input()
if new_date:
user_data["date_time_original"] = new_date
self.settings["gps"] = self._get_gps_input(user_data)
return user_data
def _get_gps_input(self, test_exif):
while True:
lat = input("Enter Latitude (xx.xxxxxx): ")
if lat == "":
return None
long = input("Enter Longitude (xx.xxxxxx): ")
try:
self.o.exif_handler.add_geolocation_to_exif(test_exif, float(lat), float(long))
return [lat, long]
except Exception:
print("Invalid GPS formate, try again...")
def _get_date_input(self):
# Partially chatGPT
while True:
date_input = input("Enter a date (yyyy-mm-dd): ")
if date_input == "":
return None # Skip if input is empty
try:
new_date = datetime.strptime(date_input, "%Y-%m-%d")
return new_date.strftime("%Y:%m:%d 00:00:00")
except ValueError:
print("Invalid date format. Please enter the date in yyyy-mm-dd format.")
def _get_user_settings(self):
"""Get initial settings from the user."""
menu_options = [
"Resize image",
"Change EXIF",
"Convert to grayscale",
"Change contrast",
"Change brightness",
"Rename images",
"Invert image order",
"Add Watermark"
] # new option can be added here.
self.settings["input_folder"] = input("Enter path of input folder: ").strip() # Add: check if folder exists.
self.settings["output_folder"] = input("Enter path of output folder: ").strip()
self.settings["file_format"] = self.take_input_and_validate(question = "Enter export file format (jpg, png, webp): ", accepted_input = ["jpg", "png", "webp"], accepted_type = str)
self.settings["modifications"] = self.tui.multi_select_menu(
f"\n{self.name} v{self.version} for {self.o.name} v.{self.o.version} \nSelect what you want to do (esc or q to exit)",
menu_options
)
if "Change EXIF" not in self.settings["modifications"]:
self.settings["copy_exif"] = self.tui.yes_no_menu("Do you want to copy exif info from original file?")
if "Rename images" in self.settings["modifications"]:
self.settings["new_file_names"] = input("What should be the name for the new images? ") # Need
else:
self.settings["new_file_names"] = False
if "Invert image order" in self.settings["modifications"]:
self.settings["invert_image_order"] = True
else:
self.settings["invert_image_order"] = False
if "Add Watermark" in self.settings["modifications"]:
self.settings["watermark"] = input("Enter text for watermark. ")
else:
self.settings["watermark"] = False
os.makedirs(self.settings["output_folder"], exist_ok = True)
def take_input_and_validate(self, question, accepted_input = None, accepted_type = str, min_value = None, max_value = None):
"""
Asks the user a question, validates the input, and ensures it matches the specified criteria.
Args:
question (str): The question to ask the user.
accepted_input (list): A list of acceptable inputs (optional for non-numeric types).
accepted_type (type): The expected type of input (e.g., str, int, float).
min_value (int/float): Minimum value for numeric inputs (optional).
max_value (int/float): Maximum value for numeric inputs (optional).
Returns:
The validated user input.
"""
# Main layout by chatGPT, but modified.
while True:
user_input = input(question).strip()
try:
# Convert input to the desired type
if accepted_type in [int, float]:
user_input = accepted_type(user_input)
# Validate range for numeric types
if (min_value is not None and user_input < min_value) or (max_value is not None and user_input > max_value):
print(f"Input must be between {min_value} and {max_value}.")
continue
elif accepted_type == str:
# No conversion needed for strings
user_input = str(user_input)
else:
raise ValueError(f"Unsupported type: {accepted_type}")
# Validate against accepted inputs if provided
if accepted_input is not None and user_input not in accepted_input:
print(f"Invalid input. Must be one of: {', '.join(map(str, accepted_input))}.")
continue
return user_input # Input is valid
except ValueError:
print(f"Invalid input. Must be of type {accepted_type.__name__}.")
def run(self):
"""Run the main program."""
self._load_or_ask_settings()
self._get_user_settings()
self._process()
print("Done")
def main():
app = OptimaLab35_lite()
app.run()
if __name__ == "__main__":
main()

View file

View file

@ -0,0 +1,87 @@
from PySide6.QtCore import Signal
from PySide6.QtWidgets import (
QMainWindow, QWidget, QVBoxLayout, QComboBox, QListWidget,
QLineEdit, QHBoxLayout, QPushButton, QMessageBox
)
# By ChatGPT
class ExifEditor(QMainWindow):
# Signal to emit the updated EXIF data
exif_data_updated = Signal(dict)
def __init__(self, exif_data):
super().__init__()
self.exif_data = exif_data
self.current_key = None
self.setWindowTitle("EXIF Editor")
self.resize(400, 300)
# Main widget and layout
main_widget = QWidget()
main_layout = QVBoxLayout()
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
# ComboBox to select lists
self.combo_box = QComboBox()
self.combo_box.addItems(self.exif_data.keys())
self.combo_box.currentTextChanged.connect(self.load_list)
main_layout.addWidget(self.combo_box)
# List widget to display items
self.list_widget = QListWidget()
main_layout.addWidget(self.list_widget)
# Line edit for adding items
self.line_edit = QLineEdit()
self.line_edit.setPlaceholderText("Enter new item...")
main_layout.addWidget(self.line_edit)
# Buttons: Add, Delete, Cancel
button_layout = QHBoxLayout()
self.add_button = QPushButton("Add")
self.add_button.clicked.connect(self.add_item)
self.delete_button = QPushButton("Delete")
self.delete_button.clicked.connect(self.delete_item)
self.cancel_button = QPushButton("Close")
self.cancel_button.clicked.connect(self.close_editor)
button_layout.addWidget(self.add_button)
button_layout.addWidget(self.delete_button)
button_layout.addWidget(self.cancel_button)
main_layout.addLayout(button_layout)
# Load the first list by default
self.load_list(self.combo_box.currentText())
def load_list(self, key):
"""Load the selected list into the list widget."""
self.current_key = key
self.list_widget.clear()
if key in self.exif_data:
self.list_widget.addItems(self.exif_data[key])
def add_item(self):
"""Add a new item to the selected list."""
new_item = self.line_edit.text().strip()
if new_item:
self.exif_data[self.current_key].append(new_item)
self.list_widget.addItem(new_item)
self.line_edit.clear()
else:
QMessageBox.warning(self, "Warning", "Cannot add an empty item.")
def delete_item(self):
"""Delete the selected item from the list."""
selected_item = self.list_widget.currentItem()
if selected_item:
item_text = selected_item.text()
self.exif_data[self.current_key].remove(item_text)
self.list_widget.takeItem(self.list_widget.row(selected_item))
else:
QMessageBox.warning(self, "Warning", "No item selected to delete.")
def close_editor(self):
"""Emit the updated exif_data and close the editor."""
self.exif_data_updated.emit(self.exif_data)
self.close()

View file

@ -0,0 +1,559 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'main_window.ui'
##
## Created by: Qt User Interface Compiler version 6.8.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
QCursor, QFont, QFontDatabase, QGradient,
QIcon, QImage, QKeySequence, QLinearGradient,
QPainter, QPalette, QPixmap, QRadialGradient,
QTransform)
from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QDateEdit,
QFrame, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMainWindow, QMenu,
QMenuBar, QProgressBar, QPushButton, QSizePolicy,
QSpinBox, QStatusBar, QTabWidget, QVBoxLayout,
QWidget)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(450, 708)
MainWindow.setMinimumSize(QSize(350, 677))
MainWindow.setMaximumSize(QSize(500, 1000))
self.actionInfo = QAction(MainWindow)
self.actionInfo.setObjectName(u"actionInfo")
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.gridLayout = QGridLayout(self.centralwidget)
self.gridLayout.setObjectName(u"gridLayout")
self.tabWidget = QTabWidget(self.centralwidget)
self.tabWidget.setObjectName(u"tabWidget")
self.tabWidget.setMaximumSize(QSize(500, 16777215))
self.tab_1 = QWidget()
self.tab_1.setObjectName(u"tab_1")
self.verticalLayout_10 = QVBoxLayout(self.tab_1)
self.verticalLayout_10.setObjectName(u"verticalLayout_10")
self.folder_group = QFrame(self.tab_1)
self.folder_group.setObjectName(u"folder_group")
self.folder_group.setMaximumSize(QSize(400, 16777215))
self.gridLayout_5 = QGridLayout(self.folder_group)
self.gridLayout_5.setObjectName(u"gridLayout_5")
self.input_path = QLineEdit(self.folder_group)
self.input_path.setObjectName(u"input_path")
self.gridLayout_5.addWidget(self.input_path, 0, 0, 1, 1)
self.output_path = QLineEdit(self.folder_group)
self.output_path.setObjectName(u"output_path")
self.gridLayout_5.addWidget(self.output_path, 0, 1, 1, 1)
self.input_folder_button = QPushButton(self.folder_group)
self.input_folder_button.setObjectName(u"input_folder_button")
self.gridLayout_5.addWidget(self.input_folder_button, 1, 0, 1, 1)
self.output_folder_button = QPushButton(self.folder_group)
self.output_folder_button.setObjectName(u"output_folder_button")
self.gridLayout_5.addWidget(self.output_folder_button, 1, 1, 1, 1)
self.verticalLayout_10.addWidget(self.folder_group)
self.groupBox = QGroupBox(self.tab_1)
self.groupBox.setObjectName(u"groupBox")
self.groupBox.setMaximumSize(QSize(400, 16777215))
self.gridLayout_4 = QGridLayout(self.groupBox)
self.gridLayout_4.setObjectName(u"gridLayout_4")
self.resize_checkbox = QCheckBox(self.groupBox)
self.resize_checkbox.setObjectName(u"resize_checkbox")
self.gridLayout_4.addWidget(self.resize_checkbox, 0, 0, 1, 1)
self.resize_spinBox = QSpinBox(self.groupBox)
self.resize_spinBox.setObjectName(u"resize_spinBox")
self.resize_spinBox.setEnabled(False)
self.resize_spinBox.setMinimum(1)
self.resize_spinBox.setMaximum(200)
self.resize_spinBox.setSingleStep(1)
self.resize_spinBox.setValue(80)
self.gridLayout_4.addWidget(self.resize_spinBox, 0, 1, 1, 1)
self.image_type = QComboBox(self.groupBox)
self.image_type.addItem(u"jpg")
self.image_type.addItem(u"png")
self.image_type.addItem(u"webp")
self.image_type.setObjectName(u"image_type")
self.gridLayout_4.addWidget(self.image_type, 1, 0, 1, 1)
self.jpg_quality_spinBox = QSpinBox(self.groupBox)
self.jpg_quality_spinBox.setObjectName(u"jpg_quality_spinBox")
self.jpg_quality_spinBox.setMinimum(1)
self.jpg_quality_spinBox.setMaximum(100)
self.jpg_quality_spinBox.setValue(80)
self.gridLayout_4.addWidget(self.jpg_quality_spinBox, 1, 1, 1, 1)
self.png_quality_spinBox = QSpinBox(self.groupBox)
self.png_quality_spinBox.setObjectName(u"png_quality_spinBox")
self.png_quality_spinBox.setEnabled(True)
self.png_quality_spinBox.setMinimum(1)
self.png_quality_spinBox.setMaximum(9)
self.png_quality_spinBox.setValue(6)
self.gridLayout_4.addWidget(self.png_quality_spinBox, 1, 2, 1, 1)
self.optimize_checkBox = QCheckBox(self.groupBox)
self.optimize_checkBox.setObjectName(u"optimize_checkBox")
self.gridLayout_4.addWidget(self.optimize_checkBox, 0, 2, 1, 1)
self.png_quality_spinBox.raise_()
self.resize_checkbox.raise_()
self.resize_spinBox.raise_()
self.image_type.raise_()
self.jpg_quality_spinBox.raise_()
self.optimize_checkBox.raise_()
self.verticalLayout_10.addWidget(self.groupBox)
self.groupBox_2 = QGroupBox(self.tab_1)
self.groupBox_2.setObjectName(u"groupBox_2")
self.groupBox_2.setMaximumSize(QSize(400, 16777215))
self.gridLayout_3 = QGridLayout(self.groupBox_2)
self.gridLayout_3.setObjectName(u"gridLayout_3")
self.watermark_lineEdit = QLineEdit(self.groupBox_2)
self.watermark_lineEdit.setObjectName(u"watermark_lineEdit")
self.watermark_lineEdit.setEnabled(False)
self.gridLayout_3.addWidget(self.watermark_lineEdit, 3, 0, 1, 3)
self.brightness_checkbox = QCheckBox(self.groupBox_2)
self.brightness_checkbox.setObjectName(u"brightness_checkbox")
self.gridLayout_3.addWidget(self.brightness_checkbox, 0, 0, 1, 1)
self.grayscale_checkBox = QCheckBox(self.groupBox_2)
self.grayscale_checkBox.setObjectName(u"grayscale_checkBox")
self.gridLayout_3.addWidget(self.grayscale_checkBox, 0, 2, 1, 1)
self.contrast_spinBox = QSpinBox(self.groupBox_2)
self.contrast_spinBox.setObjectName(u"contrast_spinBox")
self.contrast_spinBox.setEnabled(False)
self.contrast_spinBox.setMinimum(-100)
self.contrast_spinBox.setMaximum(100)
self.contrast_spinBox.setValue(10)
self.gridLayout_3.addWidget(self.contrast_spinBox, 1, 1, 1, 1)
self.watermark_checkbox = QCheckBox(self.groupBox_2)
self.watermark_checkbox.setObjectName(u"watermark_checkbox")
self.gridLayout_3.addWidget(self.watermark_checkbox, 2, 0, 1, 1)
self.brightness_spinBox = QSpinBox(self.groupBox_2)
self.brightness_spinBox.setObjectName(u"brightness_spinBox")
self.brightness_spinBox.setEnabled(False)
self.brightness_spinBox.setMinimum(-100)
self.brightness_spinBox.setMaximum(100)
self.brightness_spinBox.setValue(-10)
self.gridLayout_3.addWidget(self.brightness_spinBox, 0, 1, 1, 1)
self.contrast_checkbox = QCheckBox(self.groupBox_2)
self.contrast_checkbox.setObjectName(u"contrast_checkbox")
self.gridLayout_3.addWidget(self.contrast_checkbox, 1, 0, 1, 1)
self.font_size_comboBox = QComboBox(self.groupBox_2)
self.font_size_comboBox.addItem("")
self.font_size_comboBox.addItem("")
self.font_size_comboBox.addItem("")
self.font_size_comboBox.addItem("")
self.font_size_comboBox.addItem("")
self.font_size_comboBox.setObjectName(u"font_size_comboBox")
self.gridLayout_3.addWidget(self.font_size_comboBox, 2, 1, 1, 1)
self.verticalLayout_10.addWidget(self.groupBox_2)
self.rename_group = QGroupBox(self.tab_1)
self.rename_group.setObjectName(u"rename_group")
self.rename_group.setMaximumSize(QSize(400, 16777215))
self.gridLayout_6 = QGridLayout(self.rename_group)
self.gridLayout_6.setObjectName(u"gridLayout_6")
self.rename_checkbox = QCheckBox(self.rename_group)
self.rename_checkbox.setObjectName(u"rename_checkbox")
self.gridLayout_6.addWidget(self.rename_checkbox, 0, 0, 1, 1)
self.revert_checkbox = QCheckBox(self.rename_group)
self.revert_checkbox.setObjectName(u"revert_checkbox")
self.gridLayout_6.addWidget(self.revert_checkbox, 0, 1, 1, 1)
self.filename = QLineEdit(self.rename_group)
self.filename.setObjectName(u"filename")
self.filename.setEnabled(False)
self.gridLayout_6.addWidget(self.filename, 1, 0, 1, 2)
self.verticalLayout_10.addWidget(self.rename_group)
self.widget_9 = QWidget(self.tab_1)
self.widget_9.setObjectName(u"widget_9")
self.widget_9.setMaximumSize(QSize(400, 50))
self.horizontalLayout_3 = QHBoxLayout(self.widget_9)
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
self.progressBar = QProgressBar(self.widget_9)
self.progressBar.setObjectName(u"progressBar")
self.progressBar.setEnabled(True)
self.progressBar.setValue(0)
self.horizontalLayout_3.addWidget(self.progressBar)
self.start_button = QPushButton(self.widget_9)
self.start_button.setObjectName(u"start_button")
self.start_button.setEnabled(True)
self.horizontalLayout_3.addWidget(self.start_button)
self.verticalLayout_10.addWidget(self.widget_9)
self.tabWidget.addTab(self.tab_1, "")
self.tab_2 = QWidget()
self.tab_2.setObjectName(u"tab_2")
self.verticalLayout_9 = QVBoxLayout(self.tab_2)
self.verticalLayout_9.setObjectName(u"verticalLayout_9")
self.exif_group = QGroupBox(self.tab_2)
self.exif_group.setObjectName(u"exif_group")
self.horizontalLayout = QHBoxLayout(self.exif_group)
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.exif_checkbox = QCheckBox(self.exif_group)
self.exif_checkbox.setObjectName(u"exif_checkbox")
self.exif_checkbox.setEnabled(True)
self.horizontalLayout.addWidget(self.exif_checkbox)
self.exif_copy_checkBox = QCheckBox(self.exif_group)
self.exif_copy_checkBox.setObjectName(u"exif_copy_checkBox")
self.horizontalLayout.addWidget(self.exif_copy_checkBox)
self.edit_exif_button = QPushButton(self.exif_group)
self.edit_exif_button.setObjectName(u"edit_exif_button")
self.edit_exif_button.setEnabled(False)
self.horizontalLayout.addWidget(self.edit_exif_button)
self.verticalLayout_9.addWidget(self.exif_group)
self.exif_options_group = QGroupBox(self.tab_2)
self.exif_options_group.setObjectName(u"exif_options_group")
self.exif_options_group.setEnabled(False)
self.gridLayout_7 = QGridLayout(self.exif_options_group)
self.gridLayout_7.setObjectName(u"gridLayout_7")
self.widget_7 = QWidget(self.exif_options_group)
self.widget_7.setObjectName(u"widget_7")
self.verticalLayout_7 = QVBoxLayout(self.widget_7)
self.verticalLayout_7.setObjectName(u"verticalLayout_7")
self.label_7 = QLabel(self.widget_7)
self.label_7.setObjectName(u"label_7")
self.verticalLayout_7.addWidget(self.label_7)
self.artist_comboBox = QComboBox(self.widget_7)
self.artist_comboBox.setObjectName(u"artist_comboBox")
self.verticalLayout_7.addWidget(self.artist_comboBox)
self.gridLayout_7.addWidget(self.widget_7, 3, 0, 1, 1)
self.widget_4 = QWidget(self.exif_options_group)
self.widget_4.setObjectName(u"widget_4")
self.verticalLayout_4 = QVBoxLayout(self.widget_4)
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
self.label_4 = QLabel(self.widget_4)
self.label_4.setObjectName(u"label_4")
self.verticalLayout_4.addWidget(self.label_4)
self.iso_comboBox = QComboBox(self.widget_4)
self.iso_comboBox.setObjectName(u"iso_comboBox")
self.verticalLayout_4.addWidget(self.iso_comboBox)
self.gridLayout_7.addWidget(self.widget_4, 1, 1, 1, 1)
self.widget_6 = QWidget(self.exif_options_group)
self.widget_6.setObjectName(u"widget_6")
self.verticalLayout_6 = QVBoxLayout(self.widget_6)
self.verticalLayout_6.setObjectName(u"verticalLayout_6")
self.label_6 = QLabel(self.widget_6)
self.label_6.setObjectName(u"label_6")
self.verticalLayout_6.addWidget(self.label_6)
self.user_comment_comboBox = QComboBox(self.widget_6)
self.user_comment_comboBox.setObjectName(u"user_comment_comboBox")
self.verticalLayout_6.addWidget(self.user_comment_comboBox)
self.gridLayout_7.addWidget(self.widget_6, 2, 1, 1, 1)
self.widget_2 = QWidget(self.exif_options_group)
self.widget_2.setObjectName(u"widget_2")
self.verticalLayout_2 = QVBoxLayout(self.widget_2)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.label_2 = QLabel(self.widget_2)
self.label_2.setObjectName(u"label_2")
self.verticalLayout_2.addWidget(self.label_2)
self.lens_comboBox = QComboBox(self.widget_2)
self.lens_comboBox.setObjectName(u"lens_comboBox")
self.verticalLayout_2.addWidget(self.lens_comboBox)
self.gridLayout_7.addWidget(self.widget_2, 1, 0, 1, 1)
self.widget_5 = QWidget(self.exif_options_group)
self.widget_5.setObjectName(u"widget_5")
self.verticalLayout_5 = QVBoxLayout(self.widget_5)
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
self.label_5 = QLabel(self.widget_5)
self.label_5.setObjectName(u"label_5")
self.verticalLayout_5.addWidget(self.label_5)
self.image_description_comboBox = QComboBox(self.widget_5)
self.image_description_comboBox.setObjectName(u"image_description_comboBox")
self.verticalLayout_5.addWidget(self.image_description_comboBox)
self.gridLayout_7.addWidget(self.widget_5, 2, 0, 1, 1)
self.widget = QWidget(self.exif_options_group)
self.widget.setObjectName(u"widget")
self.verticalLayout = QVBoxLayout(self.widget)
self.verticalLayout.setObjectName(u"verticalLayout")
self.label = QLabel(self.widget)
self.label.setObjectName(u"label")
self.verticalLayout.addWidget(self.label)
self.make_comboBox = QComboBox(self.widget)
self.make_comboBox.setObjectName(u"make_comboBox")
self.verticalLayout.addWidget(self.make_comboBox)
self.gridLayout_7.addWidget(self.widget, 0, 0, 1, 1)
self.widget_3 = QWidget(self.exif_options_group)
self.widget_3.setObjectName(u"widget_3")
self.verticalLayout_3 = QVBoxLayout(self.widget_3)
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
self.label_3 = QLabel(self.widget_3)
self.label_3.setObjectName(u"label_3")
self.verticalLayout_3.addWidget(self.label_3)
self.model_comboBox = QComboBox(self.widget_3)
self.model_comboBox.setObjectName(u"model_comboBox")
self.verticalLayout_3.addWidget(self.model_comboBox)
self.gridLayout_7.addWidget(self.widget_3, 0, 1, 1, 1)
self.widget_8 = QWidget(self.exif_options_group)
self.widget_8.setObjectName(u"widget_8")
self.verticalLayout_8 = QVBoxLayout(self.widget_8)
self.verticalLayout_8.setObjectName(u"verticalLayout_8")
self.label_8 = QLabel(self.widget_8)
self.label_8.setObjectName(u"label_8")
self.verticalLayout_8.addWidget(self.label_8)
self.copyright_info_comboBox = QComboBox(self.widget_8)
self.copyright_info_comboBox.setObjectName(u"copyright_info_comboBox")
self.verticalLayout_8.addWidget(self.copyright_info_comboBox)
self.gridLayout_7.addWidget(self.widget_8, 3, 1, 1, 1)
self.verticalLayout_9.addWidget(self.exif_options_group)
self.gps_groupBox = QGroupBox(self.tab_2)
self.gps_groupBox.setObjectName(u"gps_groupBox")
self.gps_groupBox.setEnabled(False)
self.horizontalLayout_4 = QHBoxLayout(self.gps_groupBox)
self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
self.gps_checkBox = QCheckBox(self.gps_groupBox)
self.gps_checkBox.setObjectName(u"gps_checkBox")
self.horizontalLayout_4.addWidget(self.gps_checkBox)
self.lat_lineEdit = QLineEdit(self.gps_groupBox)
self.lat_lineEdit.setObjectName(u"lat_lineEdit")
self.lat_lineEdit.setEnabled(False)
self.horizontalLayout_4.addWidget(self.lat_lineEdit)
self.long_lineEdit = QLineEdit(self.gps_groupBox)
self.long_lineEdit.setObjectName(u"long_lineEdit")
self.long_lineEdit.setEnabled(False)
self.horizontalLayout_4.addWidget(self.long_lineEdit)
self.verticalLayout_9.addWidget(self.gps_groupBox)
self.date_groupBox = QGroupBox(self.tab_2)
self.date_groupBox.setObjectName(u"date_groupBox")
self.date_groupBox.setEnabled(False)
self.horizontalLayout_2 = QHBoxLayout(self.date_groupBox)
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.add_date_checkBox = QCheckBox(self.date_groupBox)
self.add_date_checkBox.setObjectName(u"add_date_checkBox")
self.horizontalLayout_2.addWidget(self.add_date_checkBox)
self.dateEdit = QDateEdit(self.date_groupBox)
self.dateEdit.setObjectName(u"dateEdit")
self.dateEdit.setEnabled(False)
self.dateEdit.setDateTime(QDateTime(QDate(2025, 1, 1), QTime(0, 0, 0)))
self.horizontalLayout_2.addWidget(self.dateEdit)
self.verticalLayout_9.addWidget(self.date_groupBox)
self.tabWidget.addTab(self.tab_2, "")
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.statusBar = QStatusBar(MainWindow)
self.statusBar.setObjectName(u"statusBar")
MainWindow.setStatusBar(self.statusBar)
self.menuBar = QMenuBar(MainWindow)
self.menuBar.setObjectName(u"menuBar")
self.menuBar.setGeometry(QRect(0, 0, 450, 27))
self.menuInfo = QMenu(self.menuBar)
self.menuInfo.setObjectName(u"menuInfo")
MainWindow.setMenuBar(self.menuBar)
self.menuBar.addAction(self.menuInfo.menuAction())
self.menuInfo.addAction(self.actionInfo)
self.retranslateUi(MainWindow)
self.resize_checkbox.toggled.connect(self.resize_spinBox.setEnabled)
self.brightness_checkbox.toggled.connect(self.brightness_spinBox.setEnabled)
self.contrast_checkbox.toggled.connect(self.contrast_spinBox.setEnabled)
self.watermark_checkbox.toggled.connect(self.watermark_lineEdit.setEnabled)
self.rename_checkbox.toggled.connect(self.filename.setEnabled)
self.exif_checkbox.toggled.connect(self.exif_options_group.setEnabled)
self.exif_checkbox.toggled.connect(self.exif_copy_checkBox.setDisabled)
self.exif_copy_checkBox.toggled.connect(self.exif_checkbox.setDisabled)
self.exif_checkbox.toggled.connect(self.edit_exif_button.setEnabled)
self.add_date_checkBox.toggled.connect(self.dateEdit.setEnabled)
self.exif_checkbox.toggled.connect(self.date_groupBox.setEnabled)
self.exif_checkbox.toggled.connect(self.gps_groupBox.setEnabled)
self.gps_checkBox.toggled.connect(self.lat_lineEdit.setEnabled)
self.gps_checkBox.toggled.connect(self.long_lineEdit.setEnabled)
self.tabWidget.setCurrentIndex(0)
self.font_size_comboBox.setCurrentIndex(2)
QMetaObject.connectSlotsByName(MainWindow)
# setupUi
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"OPTIMA-35", None))
self.actionInfo.setText(QCoreApplication.translate("MainWindow", u"Info", None))
self.input_path.setText("")
self.input_path.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Enter input folder", None))
self.output_path.setText("")
self.output_path.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Enter output folder", None))
self.input_folder_button.setText(QCoreApplication.translate("MainWindow", u"input", None))
self.output_folder_button.setText(QCoreApplication.translate("MainWindow", u"output", None))
self.groupBox.setTitle(QCoreApplication.translate("MainWindow", u"Essential group", None))
self.resize_checkbox.setText(QCoreApplication.translate("MainWindow", u"Resize", None))
self.optimize_checkBox.setText(QCoreApplication.translate("MainWindow", u"optimize", None))
self.groupBox_2.setTitle(QCoreApplication.translate("MainWindow", u"Extra stuff", None))
self.watermark_lineEdit.setText("")
self.watermark_lineEdit.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Enter Watermark", None))
self.brightness_checkbox.setText(QCoreApplication.translate("MainWindow", u"Brightness", None))
self.grayscale_checkBox.setText(QCoreApplication.translate("MainWindow", u"Grayscale", None))
self.watermark_checkbox.setText(QCoreApplication.translate("MainWindow", u"Watermark", None))
self.contrast_checkbox.setText(QCoreApplication.translate("MainWindow", u"Contrast", None))
self.font_size_comboBox.setItemText(0, QCoreApplication.translate("MainWindow", u"Tiny", None))
self.font_size_comboBox.setItemText(1, QCoreApplication.translate("MainWindow", u"Small", None))
self.font_size_comboBox.setItemText(2, QCoreApplication.translate("MainWindow", u"Normal", None))
self.font_size_comboBox.setItemText(3, QCoreApplication.translate("MainWindow", u"Large", None))
self.font_size_comboBox.setItemText(4, QCoreApplication.translate("MainWindow", u"Huge", None))
self.font_size_comboBox.setCurrentText(QCoreApplication.translate("MainWindow", u"Normal", None))
self.rename_group.setTitle(QCoreApplication.translate("MainWindow", u"files", None))
self.rename_checkbox.setText(QCoreApplication.translate("MainWindow", u"Rename", None))
self.revert_checkbox.setText(QCoreApplication.translate("MainWindow", u"Revert order", None))
self.filename.setText("")
self.filename.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Enter file name", None))
self.start_button.setText(QCoreApplication.translate("MainWindow", u"Convert", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_1), QCoreApplication.translate("MainWindow", u"Main", None))
self.exif_group.setTitle(QCoreApplication.translate("MainWindow", u"EXIF EXPERIMENTAL", None))
self.exif_checkbox.setText(QCoreApplication.translate("MainWindow", u"own exif", None))
self.exif_copy_checkBox.setText(QCoreApplication.translate("MainWindow", u"copy exif", None))
self.edit_exif_button.setText(QCoreApplication.translate("MainWindow", u"edit exif", None))
self.exif_options_group.setTitle(QCoreApplication.translate("MainWindow", u"Must", None))
self.label_7.setText(QCoreApplication.translate("MainWindow", u"Artist", None))
self.label_4.setText(QCoreApplication.translate("MainWindow", u"ISO", None))
self.label_6.setText(QCoreApplication.translate("MainWindow", u"Scanner", None))
self.label_2.setText(QCoreApplication.translate("MainWindow", u"Lens", None))
self.label_5.setText(QCoreApplication.translate("MainWindow", u"Film", None))
self.label.setText(QCoreApplication.translate("MainWindow", u"Make", None))
self.make_comboBox.setCurrentText("")
self.make_comboBox.setPlaceholderText("")
self.label_3.setText(QCoreApplication.translate("MainWindow", u"Model", None))
self.label_8.setText(QCoreApplication.translate("MainWindow", u"Copyright", None))
self.gps_groupBox.setTitle(QCoreApplication.translate("MainWindow", u"GPS", None))
self.gps_checkBox.setText(QCoreApplication.translate("MainWindow", u"add gps", None))
self.lat_lineEdit.setText("")
self.lat_lineEdit.setPlaceholderText(QCoreApplication.translate("MainWindow", u"latitude [S, N]", None))
self.long_lineEdit.setText("")
self.long_lineEdit.setPlaceholderText(QCoreApplication.translate("MainWindow", u"longitude [W, E]", None))
self.date_groupBox.setTitle(QCoreApplication.translate("MainWindow", u"Optional", None))
self.add_date_checkBox.setText(QCoreApplication.translate("MainWindow", u"add date", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QCoreApplication.translate("MainWindow", u"EXIF", None))
self.menuInfo.setTitle(QCoreApplication.translate("MainWindow", u"Info", None))
# retranslateUi

View file

@ -0,0 +1,919 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>708</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>350</width>
<height>677</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>500</width>
<height>1000</height>
</size>
</property>
<property name="windowTitle">
<string>OPTIMA-35</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="maximumSize">
<size>
<width>500</width>
<height>16777215</height>
</size>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_1">
<attribute name="title">
<string>Main</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QFrame" name="folder_group">
<property name="maximumSize">
<size>
<width>400</width>
<height>16777215</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QLineEdit" name="input_path">
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>Enter input folder</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="output_path">
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>Enter output folder</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="input_folder_button">
<property name="text">
<string>input</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="output_folder_button">
<property name="text">
<string>output</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="maximumSize">
<size>
<width>400</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Essential group</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="resize_checkbox">
<property name="text">
<string>Resize</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="resize_spinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>200</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>80</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="image_type">
<item>
<property name="text">
<string notr="true">jpg</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">png</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">webp</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="jpg_quality_spinBox">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>80</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="png_quality_spinBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9</number>
</property>
<property name="value">
<number>6</number>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="optimize_checkBox">
<property name="text">
<string>optimize</string>
</property>
</widget>
</item>
</layout>
<zorder>png_quality_spinBox</zorder>
<zorder>resize_checkbox</zorder>
<zorder>resize_spinBox</zorder>
<zorder>image_type</zorder>
<zorder>jpg_quality_spinBox</zorder>
<zorder>optimize_checkBox</zorder>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="maximumSize">
<size>
<width>400</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Extra stuff</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="3" column="0" colspan="3">
<widget class="QLineEdit" name="watermark_lineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>Enter Watermark</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="brightness_checkbox">
<property name="text">
<string>Brightness</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="grayscale_checkBox">
<property name="text">
<string>Grayscale</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="contrast_spinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="watermark_checkbox">
<property name="text">
<string>Watermark</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="brightness_spinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>-100</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>-10</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="contrast_checkbox">
<property name="text">
<string>Contrast</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="font_size_comboBox">
<property name="currentText">
<string>Normal</string>
</property>
<property name="currentIndex">
<number>2</number>
</property>
<item>
<property name="text">
<string>Tiny</string>
</property>
</item>
<item>
<property name="text">
<string>Small</string>
</property>
</item>
<item>
<property name="text">
<string>Normal</string>
</property>
</item>
<item>
<property name="text">
<string>Large</string>
</property>
</item>
<item>
<property name="text">
<string>Huge</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="rename_group">
<property name="maximumSize">
<size>
<width>400</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>files</string>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<widget class="QCheckBox" name="rename_checkbox">
<property name="text">
<string>Rename</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="revert_checkbox">
<property name="text">
<string>Revert order</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLineEdit" name="filename">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>Enter file name</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_9" native="true">
<property name="maximumSize">
<size>
<width>400</width>
<height>50</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QProgressBar" name="progressBar">
<property name="enabled">
<bool>true</bool>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="start_button">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Convert</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>EXIF</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QGroupBox" name="exif_group">
<property name="title">
<string>EXIF EXPERIMENTAL</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="exif_checkbox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>own exif</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="exif_copy_checkBox">
<property name="text">
<string>copy exif</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="edit_exif_button">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>edit exif</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="exif_options_group">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string>Must</string>
</property>
<layout class="QGridLayout" name="gridLayout_7">
<item row="3" column="0">
<widget class="QWidget" name="widget_7" native="true">
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Artist</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="artist_comboBox"/>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QWidget" name="widget_4" native="true">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>ISO</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="iso_comboBox"/>
</item>
</layout>
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="widget_6" native="true">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Scanner</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="user_comment_comboBox"/>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QWidget" name="widget_2" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Lens</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="lens_comboBox"/>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QWidget" name="widget_5" native="true">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Film</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="image_description_comboBox"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QWidget" name="widget" native="true">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Make</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="make_comboBox">
<property name="currentText">
<string/>
</property>
<property name="placeholderText">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QWidget" name="widget_3" native="true">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Model</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="model_comboBox"/>
</item>
</layout>
</widget>
</item>
<item row="3" column="1">
<widget class="QWidget" name="widget_8" native="true">
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Copyright</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="copyright_info_comboBox"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gps_groupBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string>GPS</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="gps_checkBox">
<property name="text">
<string>add gps</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lat_lineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>latitude [S, N]</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="long_lineEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
<property name="placeholderText">
<string>longitude [W, E]</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="date_groupBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string>Optional</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="add_date_checkBox">
<property name="text">
<string>add date</string>
</property>
</widget>
</item>
<item>
<widget class="QDateEdit" name="dateEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="dateTime">
<datetime>
<hour>0</hour>
<minute>0</minute>
<second>0</second>
<year>2025</year>
<month>1</month>
<day>1</day>
</datetime>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>27</height>
</rect>
</property>
<widget class="QMenu" name="menuInfo">
<property name="title">
<string>Info</string>
</property>
<addaction name="actionInfo"/>
</widget>
<addaction name="menuInfo"/>
</widget>
<action name="actionInfo">
<property name="text">
<string>Info</string>
</property>
</action>
</widget>
<resources/>
<connections>
<connection>
<sender>resize_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>resize_spinBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>75</x>
<y>96</y>
</hint>
<hint type="destinationlabel">
<x>196</x>
<y>118</y>
</hint>
</hints>
</connection>
<connection>
<sender>brightness_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>brightness_spinBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>83</x>
<y>363</y>
</hint>
<hint type="destinationlabel">
<x>83</x>
<y>399</y>
</hint>
</hints>
</connection>
<connection>
<sender>contrast_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>contrast_spinBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>185</x>
<y>363</y>
</hint>
<hint type="destinationlabel">
<x>185</x>
<y>399</y>
</hint>
</hints>
</connection>
<connection>
<sender>watermark_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>watermark_lineEdit</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>83</x>
<y>435</y>
</hint>
<hint type="destinationlabel">
<x>237</x>
<y>435</y>
</hint>
</hints>
</connection>
<connection>
<sender>rename_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>filename</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>105</x>
<y>522</y>
</hint>
<hint type="destinationlabel">
<x>182</x>
<y>560</y>
</hint>
</hints>
</connection>
<connection>
<sender>exif_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>exif_options_group</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>130</x>
<y>105</y>
</hint>
<hint type="destinationlabel">
<x>236</x>
<y>328</y>
</hint>
</hints>
</connection>
<connection>
<sender>exif_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>exif_copy_checkBox</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>130</x>
<y>105</y>
</hint>
<hint type="destinationlabel">
<x>332</x>
<y>105</y>
</hint>
</hints>
</connection>
<connection>
<sender>exif_copy_checkBox</sender>
<signal>toggled(bool)</signal>
<receiver>exif_checkbox</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>332</x>
<y>105</y>
</hint>
<hint type="destinationlabel">
<x>130</x>
<y>105</y>
</hint>
</hints>
</connection>
<connection>
<sender>exif_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>edit_exif_button</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>134</x>
<y>107</y>
</hint>
<hint type="destinationlabel">
<x>79</x>
<y>170</y>
</hint>
</hints>
</connection>
<connection>
<sender>add_date_checkBox</sender>
<signal>toggled(bool)</signal>
<receiver>dateEdit</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>94</x>
<y>601</y>
</hint>
<hint type="destinationlabel">
<x>224</x>
<y>602</y>
</hint>
</hints>
</connection>
<connection>
<sender>exif_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>date_groupBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>126</x>
<y>103</y>
</hint>
<hint type="destinationlabel">
<x>224</x>
<y>589</y>
</hint>
</hints>
</connection>
<connection>
<sender>exif_checkbox</sender>
<signal>toggled(bool)</signal>
<receiver>gps_groupBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>94</x>
<y>103</y>
</hint>
<hint type="destinationlabel">
<x>224</x>
<y>535</y>
</hint>
</hints>
</connection>
<connection>
<sender>gps_checkBox</sender>
<signal>toggled(bool)</signal>
<receiver>lat_lineEdit</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>72</x>
<y>547</y>
</hint>
<hint type="destinationlabel">
<x>192</x>
<y>547</y>
</hint>
</hints>
</connection>
<connection>
<sender>gps_checkBox</sender>
<signal>toggled(bool)</signal>
<receiver>long_lineEdit</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>72</x>
<y>547</y>
</hint>
<hint type="destinationlabel">
<x>344</x>
<y>547</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -0,0 +1,30 @@
from PySide6.QtWidgets import QApplication, QDialog, QVBoxLayout, QLineEdit, QPushButton, QLabel
# ChatGPT
class SimpleDialog(QDialog):
def __init__(self):
super().__init__()
# Set default properties
self.setGeometry(100, 100, 300, 100)
# Create the layout
layout = QVBoxLayout()
# Create the label for the message
self.message_label = QLabel(self)
# Create the close button
close_button = QPushButton("Close", self)
close_button.clicked.connect(self.close)
# Add widgets to layout
layout.addWidget(self.message_label)
layout.addWidget(close_button)
# Set layout for the dialog
self.setLayout(layout)
def show_dialog(self, title: str, message: str):
self.setWindowTitle(title) # Set the window title
self.message_label.setText(message) # Set the message text
self.exec() # Open the dialog as a modal window

View file

@ -0,0 +1,60 @@
from simple_term_menu import TerminalMenu
class SimpleTUI:
"""TUI parts using library simple_term_menu"""
def __init__(self):
pass
def choose_menu(self, menu_title, choices):
""" Dynamic function to display content of a list and returnes which was selected."""
menu_options = choices
menu = TerminalMenu(
menu_entries = menu_options,
title = menu_title,
menu_cursor = "> ",
menu_cursor_style = ("fg_gray", "bold"),
menu_highlight_style = ("bg_gray", "fg_black"),
cycle_cursor = True,
clear_screen = False
)
menu.show()
return menu.chosen_menu_entry
def multi_select_menu(self, menu_title, choices):
""" Dynamic function to display content of a list and returnes which was selected."""
menu_options = choices
menu = TerminalMenu(
menu_entries = menu_options,
title = menu_title,
multi_select=True,
show_multi_select_hint=True,
menu_cursor_style = ("fg_gray", "bold"),
menu_highlight_style = ("bg_gray", "fg_black"),
cycle_cursor = True,
clear_screen = False
)
menu.show()
choisen_values = menu.chosen_menu_entries
if choisen_values == None:
print("Exiting...")
exit()
else:
return menu.chosen_menu_entries
def yes_no_menu(self, message): # oh
menu_options = ["[y] yes", "[n] no"]
menu = TerminalMenu(
menu_entries = menu_options,
title = f"{message}",
menu_cursor = "> ",
menu_cursor_style = ("fg_red", "bold"),
menu_highlight_style = ("bg_gray", "fg_black"),
cycle_cursor = True,
clear_screen = False
)
menu_entry_index = menu.show()
if menu_entry_index == 0:
return True
elif menu_entry_index == 1:
return False

View file

View file

@ -0,0 +1,117 @@
import yaml
import os
class Utilities:
def __init__(self):
pass
def read_yaml(self, yaml_file):
try:
with open(yaml_file, "r") as file:
data = yaml.safe_load(file)
return data
except (FileNotFoundError, PermissionError) as e:
print(f"Error loading settings file: {e}")
return
def write_yaml(self, yaml_file, data):
try:
with open(yaml_file, "w") as file:
yaml.dump(data, file)
except PermissionError as e:
print(f"Error saving setings: {e}")
def program_configs(self):
"""Prepear folder for config and generate default exif if non aviable"""
program_folder = self._ensure_program_folder_exists()
if not os.path.isfile(f"{program_folder}/exif.yaml"):
self._default_exif(f"{program_folder}/exif.yaml")
def _ensure_program_folder_exists(self):
program_folder = os.path.expanduser("~/.config/OptimaLab35")
print(program_folder)
if not os.path.exists(program_folder):
print("in not, make folder")
os.makedirs(program_folder)
return program_folder
def _default_exif(self, file):
"""Makes a default exif file."""
print("Making default")
def_exif = {
"artist": [
"Mr Finchum",
"John Doe"
],
"copyright_info": [
"All Rights Reserved",
"CC BY-NC 4.0",
"No Copyright"
],
"image_description": [
"ILFORD DELTA 3200",
"ILFORD ILFOCOLOR",
"LomoChrome Turquoise",
"Kodak 200"
],
"iso": [
"200",
"400",
"1600",
"3200"
],
"lens": [
"Nikon LENS SERIES E 50mm",
"AF NIKKOR 35-70mm",
"Canon FD 50mm f/1.4 S.S.C"
],
"make": [
"Nikon",
"Canon"
],
"model": [
"FG",
"F50",
"AE-1"
],
"user_comment": [
"Scanner.NORITSU-KOKI",
"Scanner.NA"
]
}
self.write_yaml(file, def_exif)
def append_number_to_name(self, base_name: str, current_image: int, total_images: int, invert: bool):
""""Returns name, combination of base_name and ending number."""
total_digits = len(str(total_images))
if invert:
ending_number = total_images - (current_image - 1)
else:
ending_number = current_image
ending = f"{ending_number:0{total_digits}}"
return f"{base_name}_{ending}"
def yes_no(self, str):
"""Ask user y/n question"""
while True:
choice = input(f"{str} (y/n): ")
if choice == "y":
return True
elif choice == "n":
return False
else:
print("Not a valid option, try again.")
def progress_bar(self, current, total, barsize = 50):
if current > total:
print("\033[91mThis bar has exceeded its limits!\033[0m Maybe the current value needs some restraint?")
return
progress = int((barsize / total) * current)
rest = barsize - progress
if rest <= 2: rest = 0
# Determine the number of digits in total
total_digits = len(str(total))
# Format current with leading zeros
current_formatted = f"{current:0{total_digits}}"
print(f"{current_formatted}|{progress * '-'}>{rest * ' '}|{total}", end="\r")
if current == total: print("")