# Threading library for timer events import time, threading # OS library for accessing os functions import os # tkinter GUI library import tkinter as tk from tkinter import messagebox # date time library used for clock and time durations from datetime import datetime, timedelta # Python Imaging Library from PIL import ImageTk, Image # Hardware library for accessing scanner hardware from lib import Hardware # NetworkComms library for all network communications from lib import NetworkComms # UI functions common across all libraries from lib import UICommon # Functions related to orders from lib import Orders # Functions related to Products from lib import Products # Functions related to Parts from lib import Parts # Config global variables from lib import Config class UI(): #region Variable and Object decloration root = tk.Tk() system_path = "" # UI component objects # titlebar objects title_frame = tk.Frame() clock_label = tk.Label() power_label = tk.Label() power_icon = tk.Label() wifi_icon = tk.Label() wifi_status = 0 wifi_image = ImageTk.PhotoImage(Image.new("RGB", (25, 25), "black")) battery_status = 0 battery_image = ImageTk.PhotoImage(Image.new("RGB", (25, 25), "black")) #tab bar objects tabbar_frame = tk.Frame() orders_button = tk.Label() products_button = tk.Label() parts_button = tk.Label() power_button = tk.Label() power_dialog = tk.Frame() ordersicon = ImageTk.PhotoImage(Image.new("RGB", (90, 50), "black")) productsicon = ImageTk.PhotoImage(Image.new("RGB", (90, 50), "black")) partsicon = ImageTk.PhotoImage(Image.new("RGB", (90, 50), "black")) #content objects content_frame = tk.Frame() content_scroll_frame = tk.Frame() #content variables cursor_start_position = 0 frame_start_position = 0 frame_end_position = 0 scroll_enabled = False is_scrolling = False current_tab = "orders" #footer objects footer_frame = tk.Frame() # object initialisation hardware = Hardware.Hardware() uicommon = UICommon.UICommon(root) communication = NetworkComms.Communication() orders = Orders.Orders(root, content_scroll_frame) products = Products.Products(root, content_scroll_frame) parts = Parts.Parts(root, content_scroll_frame) def __init__(self): # # UI Class initialisation # # set the root frame to open full screen with cursor disabled w, h = self.root.winfo_screenwidth(), self.root.winfo_screenheight() self.root.overrideredirect(1) self.root.geometry("%dx%d+0+0" % (w, h)) self.root.config(cursor='none') # start timer to update the titlebar self.root.after(1000, self.__titlebar_update_event) # initialse the UI self.__init_ui() # check if there is a network connection if (self.communication.ping("google.com")): Config.network_status = True else: self.uicommon.message_box(self.root, "Communication Error", "No network connection") # set the orders tab to be active and get the latest orders self.__orders_tab_clicked() # run the main UI loop self.root.mainloop() #endregion #region UI initialisation def __init_ui(self): # # initialise the primary UI elements # self.system_path = os.path.dirname(os.path.abspath(__file__)).replace("lib", "") + "graphics/" #self.root.pack(fill=tk.BOTH, expand=1) # initialise the title bar objects self.title_frame = tk.Frame(self.root, height=25, width=320, background="black" ) self.title_frame.pack_propagate(0) self.title_frame.pack(fill=tk.X) self.clock_label = tk.Label(self.title_frame, text="00:00 01:01:2000", background="black", foreground="white") self.clock_label.place(x=3, y=3) self.wifi_icon = tk.Label(self.title_frame, image=self.wifi_image, borderwidth=0) self.wifi_icon.place(x=200, y=0) self.power_icon = tk.Label(self.title_frame, image=self.battery_image, borderwidth=0) self.power_icon.place(x=255, y=0) self.power_label = tk.Label(self.title_frame, text="", background="black", foreground="white") self.power_label.place(x=280, y=3) # initialise the tab bar objects self.tabbar_frame = tk.Frame(self.root, height=50, width=320, background="grey" ) self.tabbar_frame.pack_propagate(0) self.tabbar_frame.pack(fill=tk.X) # initialise the orders tab button self.ordersicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-orders.bmp")) self.orders_button = tk.Button(self.tabbar_frame, width=88, height=50, image=self.ordersicon,borderwidth=0, highlightthickness=0, command=self.__orders_tab_clicked) self.orders_button.image = self.ordersicon self.orders_button.grid(row=0, column=0) # initialise the products tab button self.productsicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-products.bmp")) self.products_button = tk.Button(self.tabbar_frame, width=88, height=50, image=self.productsicon,borderwidth=0, highlightthickness=0, command=self.__products_tab_clicked) self.products_button.image = self.productsicon self.products_button.grid(row=0, column=1) # initialise the parts tab button self.partsicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-parts.bmp")) self.parts_button = tk.Button(self.tabbar_frame, width=88, height=50, image=self.partsicon,borderwidth=0, highlightthickness=0, command=self.__parts_tab_clicked) self.parts_button.image = self.partsicon self.parts_button.grid(row=0, column=2) # initialise the power tab button power_icon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-power.bmp")) self.power_button = tk.Button(self.tabbar_frame, width=50, height=50, image=power_icon,borderwidth=0, highlightthickness=0, command=self.__power_tab_clicked) self.power_button.image = power_icon self.power_button.grid(row=0, column=3) # initialise the content frame objects self.content_frame = tk.Frame(self.root, height=330, width=320, background="white" ) self.content_frame.pack_propagate(0) self.content_frame.pack(fill=tk.X) # initialise the content scroll frame self.content_scroll_frame = tk.Frame(self.content_frame) self.content_scroll_frame.place(x=0, y=0, width=320) #self.orders.orders_list(self.content_scroll_frame) # initialise the footer bar objects self.footer_frame = tk.Frame(self.root, height=75, width=320, background="green" ) self.footer_frame.pack_propagate(0) self.footer_frame.pack(fill=tk.X) self.scan_button = tk.Button(self.footer_frame, height=75, width=320, font="DejaVuSans 36 normal", foreground="white", activeforeground="white", background="#7cbc0a",activebackground="#7cbc0a", text="SCAN", command=self.__scan_barcode) self.scan_button.pack(fill=tk.BOTH, expand=True) # add the button events for content scrolling self.root.bind('<ButtonPress-1>', self.__scroll_start) self.root.bind('<ButtonRelease-1>', self.__scroll_end) #endregion #region primary UI events def __scan_barcode(self): # # Calls the barcode scanner hardware and processes the returned barcode # print("scanning") barcode = self.hardware.scan() print(barcode) code_type = self.uicommon.barcode_type(barcode) print(code_type) # Parse barcode if (Config.scanning_mode == 0): # default mode if (code_type == "order"): self.__select_tab_from_barcode("orders") self.orders.process_barcode(barcode, frame=self.content_scroll_frame) elif (code_type == "product"): self.__select_tab_from_barcode("products") self.products.process_barcode(barcode, frame=self.content_scroll_frame) else: self.parts.process_barcode(barcode) elif (Config.scanning_mode == 1): # orders mode if (code_type == "order"): self.__select_tab_from_barcode("orders") self.orders.process_barcode(barcode, frame=self.content_scroll_frame) elif (code_type == "product"): self.__select_tab_from_barcode("orders") self.orders.process_product_barcode(barcode, frame=self.content_scroll_frame) else: self.uicommon.message_box(self.root, "Error", "Unknown Barcode") elif (Config.scanning_mode == 2): # product mode if (code_type == "order"): self.uicommon.message_box(self.root, "Error", "Not a product barcode") elif (code_type == "product"): self.__select_tab_from_barcode("products") self.products.process_barcode(barcode, frame=self.content_scroll_frame) else: self.uicommon.message_box(self.root, "Error", "Unknown Barcode") elif (Config.scanning_mode == 3): # parts mode if (code_type == "order"): self.uicommon.message_box(self.root, "Error", "Not a parts barcode") elif (code_type == "product"): self.uicommon.message_box(self.root, "Error", "Not a parts barcode") else: self.__select_tab_from_barcode("parts") self.parts.process_barcode(barcode, frame=self.content_scroll_frame) else: # orders mode self.uicommon.message_box(self.root, "Error", "Unknown System Mode") def __titlebar_update_event(self): # # Update the UI elements in the title bar # # update titlebar clock self.clock_label.config(text=datetime.now().strftime('%d/%m/%Y %H:%M:%S')) # get the wifi status wifi_strength = int(self.hardware.get_wifi_strength()) # update the wifi icon if the value has changed beyond the current range if (wifi_strength == 0) and (self.wifi_status != 0): self.wifi_status = 0 self.wifi_image = ImageTk.PhotoImage(Image.open(self.system_path + "wifi0.bmp")) self.wifi_icon.config(image = self.wifi_image) elif (wifi_strength > 0) and (wifi_strength < 17) and (self.wifi_status != 1): self.wifi_status = 1 self.wifi_image = ImageTk.PhotoImage(Image.open(self.system_path + "wifi1.bmp")) self.wifi_icon.config(image = self.wifi_image) elif (wifi_strength >= 17) and (wifi_strength < 35) and (self.wifi_status != 2): self.wifi_status = 2 self.wifi_image = ImageTk.PhotoImage(Image.open(self.system_path + "wifi2.bmp")) self.wifi_icon.config(image = self.wifi_image) elif (wifi_strength >= 35) and (wifi_strength < 52) and (self.wifi_status != 3): self.wifi_status = 3 self.wifi_image = ImageTk.PhotoImage(Image.open(self.system_path + "wifi3.bmp")) self.wifi_icon.config(image = self.wifi_image) elif (wifi_strength >= 52) and (self.wifi_status != 4): self.wifi_status = 4 self.wifi_image = ImageTk.PhotoImage(Image.open(self.system_path + "wifi4.bmp")) self.wifi_icon.config(image = self.wifi_image) # get the power status current_power_level = self.hardware.get_battery_level() s = str(current_power_level) + "%" self.power_label.config(text=s) int_current_power_level = int(int(current_power_level) / 10) if self.battery_status != int_current_power_level: self.battery_status = int_current_power_level self.battery_image = ImageTk.PhotoImage(Image.open(self.system_path + "battery" + str(self.battery_status) + ".bmp")) self.power_icon.config(image = self.battery_image) # reset the timer to trigger in 1 second self.root.after(1000, self.__titlebar_update_event) #region touch scroll functions def __scroll_start(self, event): # # Start the scroll event # self.is_scrolling = True self.cursor_start_position = self.root.winfo_pointery() self.frame_start_position = self.content_scroll_frame.winfo_y() self.click_start_time = datetime.now() threading.Timer(0.01, self.__scroll_event).start() return def __scroll_end(self, event): # # End the scroll event # self.is_scrolling = False def __scroll_event(self): # # Update the scroll frame position based on the touch location # if (self.is_scrolling): ypos = (self.root.winfo_pointery() - self.cursor_start_position) + self.frame_start_position max = 0 - self.content_scroll_frame.winfo_height() + self.content_frame.winfo_height() if (ypos < 0) and (ypos > max): self.content_scroll_frame.place(y = ypos) if (ypos > 0): self.content_scroll_frame.place(y = 0) threading.Timer(0.03, self.__scroll_event).start() #endregion #region tab bar events def __select_tab_from_barcode(self, section): # # Updates the tab bar from the barcode scan function # if (section == "orders") and (self.current_tab != "orders"): self.__orders_tab_clicked(from_barcode = True) elif (section == "products") and (self.current_tab != "products"): self.__products_tab_clicked(from_barcode = True) elif (section == "parts") and (self.current_tab != "parts"): self.__parts_tab_clicked(from_barcode = True) def __orders_tab_clicked(self, from_barcode = False): # # Orders tab click event # self.current_tab = "orders" # update the images in the tab bar to show the selected tab self.ordersicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-orders-selected.bmp")) self.orders_button.config(image = self.ordersicon) self.productsicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-products.bmp")) self.products_button.config(image = self.productsicon) self.partsicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-parts.bmp")) self.parts_button.config(image = self.partsicon) # clear any content from the content_scroll_frame and get a list of the current orders self.uicommon.clear_frame(self.content_scroll_frame) if (not from_barcode): self.orders.orders_list(self.content_scroll_frame) return() def __products_tab_clicked(self, from_barcode = False): # # Products tab click events # self.current_tab = "products" # update the images in the tab bar to show the selected tab self.ordersicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-orders.bmp")) self.orders_button.config(image = self.ordersicon) self.productsicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-products-selected.bmp")) self.products_button.config(image = self.productsicon) self.partsicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-parts.bmp")) self.parts_button.config(image = self.partsicon) # clear any content from the content_scroll_frame and get a list of the products self.uicommon.clear_frame(self.content_scroll_frame) if (not from_barcode): self.products.products_list(self.content_scroll_frame) return() def __parts_tab_clicked(self, from_barcode = False): # # Parts tab click event # self.current_tab = "parts" # update the images in the tab bar to show the selected tab self.ordersicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-orders.bmp")) self.orders_button.config(image = self.ordersicon) self.productsicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-products.bmp")) self.products_button.config(image = self.productsicon) self.partsicon = ImageTk.PhotoImage(Image.open(self.system_path + "tabbar-parts-selected.bmp")) self.parts_button.config(image = self.partsicon) # clear any content from the content_scroll_frame and get a list of the parts self.uicommon.clear_frame(self.content_scroll_frame) if (not from_barcode): self.parts.parts_list(self.content_scroll_frame) return() def __power_tab_clicked(self): # # Power tab click events: show the overlay for shutdown, restart, exit... # # create overlay frame self.power_dialog = tk.Frame(self.root, width=320, height=480, background="grey") self.power_dialog.place(x=0, y=0, width=320, height=480) # title power_title = tk.Label(self.power_dialog, text="Options", font="DejaVuSans 36 normal", background="grey", foreground="white") power_title.pack(fill=tk.X, expand=1) # shutdown button power_shutdown_button = tk.Button(self.power_dialog, text="Shutdown", height=2, font="DejaVuSans 32 normal", command=self.hardware.shutdown) power_shutdown_button.pack(fill=tk.X) # restart button power_restart_button = tk.Button(self.power_dialog, text="Restart", height=2,font="DejaVuSans 32 normal", command=self.hardware.restart) power_restart_button.pack(fill=tk.X) # exit application button power_exit_button = tk.Button(self.power_dialog, text="Exit Application", height=2,font="DejaVuSans 32 normal", command=exit) power_exit_button.pack(fill=tk.X) # cancel button power_cancel_button = tk.Button(self.power_dialog, text="Cancel", height=2,font="DejaVuSans 32 normal", command=self.close_power_dialog) power_cancel_button.pack(fill=tk.BOTH) return() def close_power_dialog(self): self.power_dialog.place_forget() self.power_dialog.destroy() #endregion