Advertisement
Guest User

Untitled

a guest
May 21st, 2018
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.83 KB | None | 0 0
  1. ########################################################################################################################
  2. #    File: menus.py
  3. # Purpose: Creates a menubar with submenus for Tkinter GUI
  4. #  Author: Dan Huckson, https://github.com/unodan
  5. #    Date: 2018-05-21
  6. ########################################################################################################################
  7. from tkinter import *
  8.  
  9.  
  10. def label_underline(label):
  11.     position = label.find('&')
  12.     if position >= 0:
  13.         label = label[:position] + label[position + 1:]
  14.  
  15.     return label, position
  16.  
  17.  
  18. class MenuItem:
  19.     def __init__(self, menu, item, **kwargs):
  20.         self.__parent = menu
  21.         self.__attributes = {}
  22.  
  23.         fg = self.__attributes['fg'] = kwargs.pop('fg', None)
  24.         bg = self.__attributes['bg'] = kwargs.pop('bg', None)
  25.         font = self.__attributes['font'] = kwargs.pop('font', None)
  26.         activeforeground = self.__attributes['activeforeground'] = kwargs.pop('activeforeground', None)
  27.         activebackground = self.__attributes['activebackground'] = kwargs.pop('activebackground', None)
  28.  
  29.         index = kwargs.pop('index', None)
  30.         image = self.__attributes['image'] = item[1]
  31.         accelerator = self.__attributes['accelerator'] = item[2]
  32.         command = self.__attributes['command'] = None if len(item) < 4 and not len(item) > 4 else item[3]
  33.         state = self.__attributes['state'] = 'normal' if len(item) < 5 else item[4]
  34.  
  35.         label, underline = label_underline(item[0])
  36.         self.__attributes['label'] = self.__index = label
  37.  
  38.         if label == '--sep--':
  39.             menu.add_separator()
  40.         else:
  41.             menu_command = menu.insert if isinstance(item[2], tuple) else menu.add_command
  42.             menu_command(
  43.                 index=index,
  44.                 state=state,
  45.                 command=command,
  46.                 font=font,
  47.                 label=label,
  48.                 image=image,
  49.                 compound='left',
  50.                 foreground=fg,
  51.                 background=bg,
  52.                 underline=underline,
  53.                 accelerator=accelerator,
  54.                 activeforeground=activeforeground,
  55.                 activebackground=activebackground,
  56.             )
  57.  
  58.     def cget(self, index):
  59.         return self.__attributes.get(index, None)
  60.  
  61.     def config(self, **kwargs):
  62.         fg = kwargs.pop('fg', None)
  63.         if fg:
  64.             self.__attributes['fg'] = fg
  65.  
  66.         bg = kwargs.pop('bg', None)
  67.         if bg:
  68.             self.__attributes['bg'] = bg
  69.  
  70.         font = kwargs.pop('font', None)
  71.         if font:
  72.             self.__attributes['font'] = font
  73.  
  74.         label = kwargs.pop('label', None)
  75.         if label:
  76.             self.__index = label
  77.             self.__attributes['label'] = label
  78.  
  79.         image = kwargs.pop('image', None)
  80.         if image:
  81.             self.__attributes['image'] = image
  82.  
  83.         state = kwargs.pop('state', None)
  84.         if state:
  85.             self.__attributes['state'] = state
  86.  
  87.         underline = kwargs.pop('underline', None)
  88.         if underline:
  89.             self.__attributes['underline'] = underline
  90.  
  91.         accelerator = kwargs.pop('accelerator', None)
  92.         if accelerator:
  93.             self.__attributes['accelerator'] = accelerator
  94.  
  95.         activeforeground = kwargs.pop('activeforeground', None)
  96.         if activeforeground:
  97.             self.__attributes['activeforeground'] = activeforeground
  98.  
  99.         activebackground = kwargs.pop('activebackground', None)
  100.         if activebackground:
  101.             self.__attributes['activebackground'] = activebackground
  102.  
  103.         self.__parent.entryconfig(
  104.             self.__index,
  105.             font=font,
  106.             label=label,
  107.             image=image,
  108.             state=state,
  109.             compound='left',
  110.             foreground=fg,
  111.             background=bg,
  112.             underline=underline,
  113.             accelerator=accelerator,
  114.             activeforeground=activeforeground,
  115.             activebackground=activebackground,
  116.         )
  117.  
  118.  
  119. class Menus(Menu):
  120.     def __init__(self, parent, *args, **kwargs):
  121.         super(Menus, self).__init__(parent, *args, **kwargs)
  122.  
  123.         self.__items = {}
  124.         self.__parent = parent
  125.         self.__index = kwargs.pop('index', None)
  126.  
  127.     def get(self, path):
  128.         path = path.replace('\\', '/')
  129.  
  130.         if '/' in path:
  131.             return self.item(self, path)
  132.  
  133.         return self.__items.get(path, None)
  134.  
  135.     def item(self, menu, path):
  136.         parts = path.split('/', 1)
  137.         member = menu.get(parts[0])
  138.  
  139.         if len(parts) > 1:
  140.             member = self.item(member, parts[1])
  141.  
  142.         return member
  143.  
  144.     def set(self, index, value):
  145.         if index in self.__items:
  146.             self.__items[index] = value
  147.  
  148.     def get_items(self):
  149.         return self.__items
  150.  
  151.     def add_items(self, item, **kwargs):
  152.  
  153.         label, underline = label_underline(item[0])
  154.  
  155.         if label in self.__items and label != '--sep--':
  156.             return
  157.  
  158.         bd = kwargs.pop('bd', self.cget('bd'))
  159.         fg = kwargs.pop('fg', self.cget('fg'))
  160.         bg = kwargs.pop('bg', self.cget('bg'))
  161.         font = kwargs.pop('font', self.cget('font'))
  162.         tearoff = kwargs.pop('tearoff', self.cget('tearoff'))
  163.         activeforeground = kwargs.pop('activeforeground', self.cget('activeforeground'))
  164.         activebackground = kwargs.pop('activebackground', self.cget('activebackground'))
  165.  
  166.         index = kwargs.pop('index', self.__index)
  167.  
  168.         menu_command = SubMenu if isinstance(item[2], tuple) else MenuItem
  169.         self.__items[label] = menu_command(
  170.             self,
  171.             item,
  172.             bd=bd,
  173.             fg=fg,
  174.             bg=bg,
  175.             font=font,
  176.             index=index,
  177.             tearoff=tearoff,
  178.             activeforeground=activeforeground,
  179.             activebackground=activebackground,
  180.         )
  181.  
  182.     def populate(self, menus):
  183.         if menus:
  184.             for item in menus:
  185.                 self.add_items(item)
  186.  
  187.  
  188. class SubMenu(Menus):
  189.     def __init__(self, parent, menu, *args, **kwargs):
  190.         index = kwargs.pop('index', None)
  191.         super().__init__(parent, *args, **kwargs)
  192.  
  193.         bd = kwargs.pop('bd', self.cget('bd'))
  194.         fg = kwargs.pop('fg', self.cget('fg'))
  195.         bg = kwargs.pop('bg', self.cget('bg'))
  196.         font = kwargs.pop('font', self.cget('font'))
  197.         tearoff = kwargs.pop('tearoff', self.cget('tearoff'))
  198.         activeforeground = kwargs.pop('activeforeground', self.cget('activeforeground'))
  199.         activebackground = kwargs.pop('activebackground', self.cget('activebackground'))
  200.  
  201.         image = menu[1]
  202.         items = None if len(menu) < 3 and not len(menu) > 3 else menu[2]
  203.         state = 'normal' if len(menu) < 4 else menu[3]
  204.  
  205.         self.__items = {}
  206.         label, underline = label_underline(menu[0])
  207.  
  208.         menu_command = parent.add_cascade if index is None else parent.insert_cascade
  209.         menu_command(index, label=label, image=image, compound='left', menu=self, state=state, underline=underline)
  210.  
  211.         item_names = []
  212.         for item in items:
  213.             if item[0] in item_names and item[0] != '--sep--':
  214.                 continue
  215.  
  216.             label = item[0]
  217.             position = label.find('&')
  218.             if position != -1:
  219.                 label = label[:position] + label[position + 1:]
  220.  
  221.             menu_command = SubMenu if isinstance(item[2], tuple) else MenuItem
  222.  
  223.             item_names.append(label)
  224.             self.__items[label] = menu_command(
  225.                 self,
  226.                 item,
  227.                 bd=bd,
  228.                 fg=fg,
  229.                 bg=bg,
  230.                 font=font,
  231.                 tearoff=tearoff,
  232.                 activeforeground=activeforeground,
  233.                 activebackground=activebackground,
  234.             )
  235.  
  236.     def get(self, path):
  237.         path = path.replace('\\', '/')
  238.  
  239.         if '/' in path:
  240.             return self.item(self, path)
  241.  
  242.         return self.__items.get(path, None)
  243.  
  244.  
  245. class MenuBar(Menus):
  246.     def __init__(self, parent, *args, **kwargs):
  247.         super().__init__(parent, *args, **kwargs)
  248.  
  249.         self.__items = {}
  250.  
  251.  
  252. class PopupMenu(Menus):
  253.     def __init__(self, parent, *args, **kwargs):
  254.         super().__init__(parent, *args, **kwargs)
  255.  
  256.         self.__items = {}
  257.         self.__leave = False
  258.         self.__delay_destroy = 1000
  259.         self.bind("<Enter>", self.on_enter)
  260.         self.bind("<Leave>", self.on_leave)
  261.         self.bind("<Escape>", self.on_escape)
  262.  
  263.     def on_enter(self, event):
  264.         self.__leave = False
  265.  
  266.     def on_leave(self, event):
  267.         self.__leave = True
  268.  
  269.         def leave():
  270.             if self.__leave:
  271.                 self.on_escape(event)
  272.  
  273.         self.after(self.__delay_destroy, leave)
  274.  
  275.     def on_escape(self, event):
  276.         self.unpost()
  277.         self.__leave = False
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement