From a79fdf37599ced7ffce61bf6eded9b472c4e4f8d Mon Sep 17 00:00:00 2001 From: Quality App Developer Date: Wed, 4 Feb 2026 17:21:53 +0200 Subject: [PATCH] Update label printer GUI with improved preview layout - 50% larger canvas, proportional barcodes, 25 char limit, 0.5cm left margin --- FILE_GUIDE.md => documentation/FILE_GUIDE.md | 0 .../GETTING_STARTED.md | 0 .../IMPLEMENTATION_SUMMARY.md | 0 INDEX.md => documentation/INDEX.md | 0 README_GUI.md => documentation/README_GUI.md | 0 .../TECHNICAL_DOCS.md | 0 .../TESTING_SUMMARY.txt | 0 .../TEST_REPORT.md | 0 readme.md => documentation/readme.md | 0 label_barcode_tmp.png | Bin 0 -> 787 bytes label_printer_gui.py | 388 ++++++------------ main.py | 0 12 files changed, 126 insertions(+), 262 deletions(-) rename FILE_GUIDE.md => documentation/FILE_GUIDE.md (100%) rename GETTING_STARTED.md => documentation/GETTING_STARTED.md (100%) rename IMPLEMENTATION_SUMMARY.md => documentation/IMPLEMENTATION_SUMMARY.md (100%) rename INDEX.md => documentation/INDEX.md (100%) rename README_GUI.md => documentation/README_GUI.md (100%) rename TECHNICAL_DOCS.md => documentation/TECHNICAL_DOCS.md (100%) rename TESTING_SUMMARY.txt => documentation/TESTING_SUMMARY.txt (100%) rename TEST_REPORT.md => documentation/TEST_REPORT.md (100%) rename readme.md => documentation/readme.md (100%) create mode 100644 label_barcode_tmp.png delete mode 100644 main.py diff --git a/FILE_GUIDE.md b/documentation/FILE_GUIDE.md similarity index 100% rename from FILE_GUIDE.md rename to documentation/FILE_GUIDE.md diff --git a/GETTING_STARTED.md b/documentation/GETTING_STARTED.md similarity index 100% rename from GETTING_STARTED.md rename to documentation/GETTING_STARTED.md diff --git a/IMPLEMENTATION_SUMMARY.md b/documentation/IMPLEMENTATION_SUMMARY.md similarity index 100% rename from IMPLEMENTATION_SUMMARY.md rename to documentation/IMPLEMENTATION_SUMMARY.md diff --git a/INDEX.md b/documentation/INDEX.md similarity index 100% rename from INDEX.md rename to documentation/INDEX.md diff --git a/README_GUI.md b/documentation/README_GUI.md similarity index 100% rename from README_GUI.md rename to documentation/README_GUI.md diff --git a/TECHNICAL_DOCS.md b/documentation/TECHNICAL_DOCS.md similarity index 100% rename from TECHNICAL_DOCS.md rename to documentation/TECHNICAL_DOCS.md diff --git a/TESTING_SUMMARY.txt b/documentation/TESTING_SUMMARY.txt similarity index 100% rename from TESTING_SUMMARY.txt rename to documentation/TESTING_SUMMARY.txt diff --git a/TEST_REPORT.md b/documentation/TEST_REPORT.md similarity index 100% rename from TEST_REPORT.md rename to documentation/TEST_REPORT.md diff --git a/readme.md b/documentation/readme.md similarity index 100% rename from readme.md rename to documentation/readme.md diff --git a/label_barcode_tmp.png b/label_barcode_tmp.png new file mode 100644 index 0000000000000000000000000000000000000000..30e1f9e045d0cdf8c0ca998d81975c1c1c7aacd2 GIT binary patch literal 787 zcmeAS@N?(olHy`uVBq!ia0y~yU~&SomvS%xNqcEl7ofl`PZ!6KiaBrZICdR25MVfX zb<_XMCezP;os+)h0f#J+a35G-?HisEKi~?%O3@uo= z_0xSKvuppH`5nFf-u}{0X=^5L{g?UXq#)bsc%u{>_3{?sX5Rai_U!u)y;)jV9@pvJ z_u)-_;)C0ImsFGe#b(L=N%_>U+>qf=3QvQ9B(s9gF$RvwqukNZ*s%3`T@^or!IMm4 c62=?WI+GyRTHiyTfr*{L)78&qol`;+0QAi6XaE2J literal 0 HcmV?d00001 diff --git a/label_printer_gui.py b/label_printer_gui.py index b9e66cc..a472835 100644 --- a/label_printer_gui.py +++ b/label_printer_gui.py @@ -24,50 +24,145 @@ import cups import io import os import threading +import tempfile +import time from print_label import create_label_image, print_label_standalone +from kivy.clock import Clock # Set window size Window.size = (1600, 900) -class LabelPreviewWidget(ScatterLayout): - """Widget for displaying the label preview""" +class LabelPreviewWidget(BoxLayout): + """Widget for displaying the warehouse identification label preview""" def __init__(self, **kwargs): super().__init__(**kwargs) - self.label_image = None - self.temp_preview_path = None + self.orientation = 'vertical' + self.temp_file_path = None - def update_preview(self, text): - """Update the preview with new label image""" - if text: - try: - self.label_image = create_label_image(text) - self.display_preview() - except Exception as e: - print(f"Error creating preview: {e}") + def update_preview(self, sap_nr, cantitate, lot_number): + """Update preview with label and barcode information""" + try: + # Create label with article info + label_text = f"{sap_nr}|{cantitate}|{lot_number}" + self.generate_and_display_preview(sap_nr, cantitate, lot_number, label_text) + except Exception as e: + print(f"Error updating preview: {e}") - def display_preview(self): - """Display the preview image""" - if self.label_image: - # Save to temporary file - import tempfile - if self.temp_preview_path and os.path.exists(self.temp_preview_path): + def generate_and_display_preview(self, sap_nr, cantitate, lot_number, barcode_text): + """Generate preview showing alternating text and barcode rows""" + from PIL import Image, ImageDraw, ImageFont + import barcode + from barcode.writer import ImageWriter + + # Canvas dimensions (11.5cm x 8cm) * 1.5 = 17.25cm x 12cm + # At 96 DPI: 11.5cm ≈ 435px, 8cm ≈ 303px + # Increased by 50%: 652px x 454px + canvas_width = 650 + canvas_height = 450 + + # Left margin: 0.5cm ≈ 19px * 1.5 = 28px + left_margin = 28 + usable_width = canvas_width - left_margin + + # Create canvas + canvas = Image.new('RGB', (canvas_width, canvas_height), 'white') + draw = ImageDraw.Draw(canvas) + + # 6 rows total + row_height = canvas_height // 6 + + # Font for text (larger for bigger canvas) + try: + label_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20) + value_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16) + except: + label_font = ImageFont.load_default() + value_font = ImageFont.load_default() + + # Row definitions: (label_text, barcode_value, row_index) + rows_data = [ + ("SAP-Nr. Article", sap_nr, 0), + (None, sap_nr, 1), # Barcode row + ("Cantitate", cantitate, 2), + (None, cantitate, 3), # Barcode row + ("ID rola cablu", lot_number, 4), + (None, lot_number, 5), # Barcode row + ] + + for label_text, value, row_idx in rows_data: + row_y = row_idx * row_height + + # Draw row border + draw.rectangle( + [(0, row_y), (canvas_width, row_y + row_height)], + outline='black', + width=1 + ) + + if label_text: + # Text row: show label and value + draw.text( + (left_margin + 8, row_y + 8), + f"{label_text}: {value if value else '(empty)'}", + fill='black', + font=label_font + ) + else: + # Barcode row + if value and value.strip(): + try: + # Limit barcode text to 25 characters + barcode_value = str(value)[:25] + + CODE128 = barcode.get_barcode_class('code128') + writer_options = { + "write_text": False, + "module_width": 0.5, + "module_height": 12, # Smaller height for better fit + "quiet_zone": 2, + "font_size": 0 + } + code = CODE128(barcode_value, writer=ImageWriter()) + filename = code.save('label_barcode_tmp', options=writer_options) + barcode_img = Image.open(filename) + + # Use standard barcode size, don't resize to fit width + canvas.paste(barcode_img, (left_margin + 4, row_y + 12)) + except Exception as e: + print(f"Barcode error: {e}") + draw.text( + (left_margin + 8, row_y + row_height // 2 - 10), + "Barcode: " + str(value)[:25], + fill='black', + font=value_font + ) + else: + draw.text( + (left_margin + 8, row_y + row_height // 2 - 10), + "(no data)", + fill='gray', + font=value_font + ) + + # Save and display + with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp: + canvas.save(tmp.name) + + # Clean up old file + if self.temp_file_path and os.path.exists(self.temp_file_path): try: - os.remove(self.temp_preview_path) + os.remove(self.temp_file_path) except: pass - with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp: - self.label_image.save(tmp.name) - self.temp_preview_path = tmp.name + self.temp_file_path = tmp.name - # Clear and recreate children + # Update display self.clear_widgets() - - # Add image - img = KivyImage(source=self.temp_preview_path, size_hint=(1, 1)) - self.add_widget(img) + img_widget = KivyImage(source=tmp.name, size_hint=(1, 1)) + self.add_widget(img_widget) class LabelPrinterApp(App): @@ -145,7 +240,6 @@ class LabelPrinterApp(App): size_hint_y=None, height=50, font_size='16sp', - input_filter='int', background_color=(0.95, 0.95, 0.95, 1) ) self.qty_input.bind(text=self.on_input_change) @@ -203,7 +297,7 @@ class LabelPrinterApp(App): container = BoxLayout(orientation='vertical', size_hint_x=0.6, spacing=10) # Title - title = Label(text='[b]Label Preview (11.5cm x 8cm)[/b]', markup=True, + title = Label(text='[b]Label Preview[/b]', markup=True, size_hint_y=0.08, font_size='18sp') container.add_widget(title) @@ -217,241 +311,11 @@ class LabelPrinterApp(App): """Update preview when input changes""" # Get all input values sap_nr = self.sap_input.text - quantity = self.qty_input.text + cantitate = self.qty_input.text # This is actually the barcode/cantitate field cable_id = self.cable_id_input.text - # Create label text combining all fields - if sap_nr or quantity or cable_id: - label_text = f"{sap_nr}|{quantity}|{cable_id}" - self.preview_widget.update_preview(label_text) - - def print_label(self, instance): - """Handle print button press""" - sap_nr = self.sap_input.text.strip() - quantity = self.qty_input.text.strip() - cable_id = self.cable_id_input.text.strip() - printer = self.printer_spinner.text - - # Validate input - if not sap_nr and not quantity and not cable_id: - self.show_popup("Error", "Please enter at least one field") - return - - # Create combined label text - label_text = f"{sap_nr}|{quantity}|{cable_id}" - - # Show loading popup - popup = Popup( - title='Printing', - content=BoxLayout( - orientation='vertical', - padding=10, - spacing=10 - ), - size_hint=(0.6, 0.3) - ) - - popup.content.add_widget(Label(text='Printing label...\nPlease wait')) - popup.open() - - # Print in background thread - def print_thread(): - try: - success = print_label_standalone(label_text, printer, preview=0) - if success: - popup.dismiss() - self.show_popup("Success", "Label printed successfully!") - else: - popup.dismiss() - self.show_popup("Error", "Failed to print label") - except Exception as e: - popup.dismiss() - self.show_popup("Error", f"Print error: {str(e)}") - - thread = threading.Thread(target=print_thread) - thread.daemon = True - thread.start() - - def show_popup(self, title, message): - """Show a popup message""" - popup = Popup( - title=title, - content=BoxLayout( - orientation='vertical', - padding=10, - spacing=10 - ), - size_hint=(0.6, 0.3) - ) - - popup.content.add_widget(Label(text=message)) - - close_button = Button(text='OK', size_hint_y=0.3) - close_button.bind(on_press=popup.dismiss) - popup.content.add_widget(close_button) - - popup.open() - - -if __name__ == '__main__': - app = LabelPrinterApp() - app.run() - - -class LabelPrinterApp(App): - """Main Kivy application for label printing""" - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.available_printers = self.get_available_printers() - self.preview_widget = None - - def get_available_printers(self): - """Get list of available printers from CUPS""" - try: - conn = cups.Connection() - printers = conn.getPrinters() - return list(printers.keys()) if printers else ["PDF"] - except Exception as e: - print(f"Error getting printers: {e}") - return ["PDF"] - - def build(self): - """Build the main UI""" - self.title = "Label Printer Interface" - - # Main layout - horizontal split between input and preview - main_layout = BoxLayout(orientation='horizontal', spacing=10, padding=10) - - # Left column - Input form - left_column = self.create_input_column() - - # Right column - Preview - right_column = self.create_preview_column() - - main_layout.add_widget(left_column) - main_layout.add_widget(right_column) - - return main_layout - - def create_input_column(self): - """Create the left column with input fields""" - container = BoxLayout(orientation='vertical', size_hint_x=0.4, spacing=10) - - # Title - title = Label(text='[b]Label Information[/b]', markup=True, size_hint_y=0.08, - font_size='18sp') - container.add_widget(title) - - # Scroll view for form - scroll = ScrollView(size_hint_y=0.85) - form_layout = GridLayout(cols=1, spacing=10, size_hint_y=None, padding=10) - form_layout.bind(minimum_height=form_layout.setter('height')) - - # SAP-Nr. Articol - sap_label = Label(text='SAP-Nr. Articol:', size_hint_y=None, height=40, - font_size='14sp') - form_layout.add_widget(sap_label) - - self.sap_input = TextInput( - multiline=False, - size_hint_y=None, - height=50, - font_size='16sp', - background_color=(0.95, 0.95, 0.95, 1) - ) - self.sap_input.bind(text=self.on_input_change) - form_layout.add_widget(self.sap_input) - - # Cantitate - qty_label = Label(text='Cantitate:', size_hint_y=None, height=40, - font_size='14sp') - form_layout.add_widget(qty_label) - - self.qty_input = TextInput( - multiline=False, - size_hint_y=None, - height=50, - font_size='16sp', - input_filter='int', - background_color=(0.95, 0.95, 0.95, 1) - ) - self.qty_input.bind(text=self.on_input_change) - form_layout.add_widget(self.qty_input) - - # ID rola cablu - cable_id_label = Label(text='ID rola cablu:', size_hint_y=None, height=40, - font_size='14sp') - form_layout.add_widget(cable_id_label) - - self.cable_id_input = TextInput( - multiline=False, - size_hint_y=None, - height=50, - font_size='16sp', - background_color=(0.95, 0.95, 0.95, 1) - ) - self.cable_id_input.bind(text=self.on_input_change) - form_layout.add_widget(self.cable_id_input) - - # Printer selection - printer_label = Label(text='Select Printer:', size_hint_y=None, height=40, - font_size='14sp') - form_layout.add_widget(printer_label) - - printer_spinner = Spinner( - text=self.available_printers[0] if self.available_printers else "No Printers", - values=self.available_printers, - size_hint_y=None, - height=50, - font_size='14sp' - ) - self.printer_spinner = printer_spinner - form_layout.add_widget(printer_spinner) - - scroll.add_widget(form_layout) - container.add_widget(scroll) - - # Print button - print_button = Button( - text='PRINT LABEL', - size_hint_y=0.15, - font_size='16sp', - background_color=(0.2, 0.6, 0.2, 1), - background_normal='', - bold=True - ) - print_button.bind(on_press=self.print_label) - container.add_widget(print_button) - - return container - - def create_preview_column(self): - """Create the right column with preview""" - container = BoxLayout(orientation='vertical', size_hint_x=0.6, spacing=10) - - # Title - title = Label(text='[b]Label Preview (11.5cm x 8cm)[/b]', markup=True, - size_hint_y=0.08, font_size='18sp') - container.add_widget(title) - - # Preview canvas - self.preview_widget = LabelPreviewWidget(size_hint_y=0.92) - container.add_widget(self.preview_widget) - - return container - - def on_input_change(self, instance, value): - """Update preview when input changes""" - # Get all input values - sap_nr = self.sap_input.text - quantity = self.qty_input.text - cable_id = self.cable_id_input.text - - # Create label text combining all fields - if sap_nr or quantity or cable_id: - label_text = f"{sap_nr}|{quantity}|{cable_id}" - self.preview_widget.update_preview(label_text) + # Update preview + self.preview_widget.update_preview(sap_nr, cantitate, cable_id) def print_label(self, instance): """Handle print button press""" diff --git a/main.py b/main.py deleted file mode 100644 index e69de29..0000000