Advertisement
Uno-Dan

Untitled

Jun 25th, 2018
149
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.67 KB | None | 0 0
  1. ########################################################################################################################
  2. #    File: menus.py
  3. #  Author: Dan Huckson, https://github.com/unodan
  4. #    Date: 2018-06-25
  5. ########################################################################################################################
  6. from os import path, getcwd
  7. from platform import system, release
  8. from tkinter import Menu, PhotoImage
  9. from tkinter.font import Font
  10.  
  11.  
  12. class MenuItem:
  13.     def __init__(self, parent, json, **kwargs):
  14.         self.parent = parent
  15.         self.has_children = False
  16.  
  17.         self.font = json.get('font')
  18.         self.label = json.get('label')
  19.         self.state = json.get('state')
  20.         self.value = json.get('value')
  21.         self.index = kwargs.get('index')
  22.         self.command = json.get('command')
  23.         self.onvalue = json.get('onvalue', True)
  24.         self.offvalue = json.get('offvalue', False)
  25.         self.variable = json.get('variable')
  26.         self.compound = json.get('compound', 'left')
  27.         self.underline = json.get('underline', 0)
  28.         self.foreground = json.get('foreground')
  29.         self.background = json.get('background')
  30.         self.accelerator = json.get('accelerator')
  31.         self.activeforeground = json.get('activeforeground')
  32.         self.activebackground = json.get('activebackground')
  33.  
  34.         if isinstance(self.font, dict):
  35.             self.font = Font(
  36.                 family=self.font.get('family'),
  37.                 size=self.font.get('size'),
  38.                 weight=self.font.get('weight', 'normal'),
  39.                 slant=self.font.get('slant', 'roman'),
  40.                 underline=self.font.get('underline', False),
  41.                 overstrike=self.font.get('overstrike', False)
  42.             )
  43.         self.image = PhotoImage(file=path.join(getcwd(), 'tkmenus', 'images', json.get('image', 'blank-21x16.png')))
  44.  
  45.         kwargs = {
  46.             'font': self.font,
  47.             'label': self.label,
  48.             'state': self.state,
  49.             'index': self.index,
  50.             'command': self.command,
  51.             'variable': self.variable,
  52.             'compound': self.compound,
  53.             'underline': self.underline,
  54.             'foreground': self.foreground,
  55.             'background': self.background,
  56.             'accelerator': self.accelerator,
  57.             'activeforeground': self.activeforeground,
  58.             'activebackground': self.activebackground,
  59.         }
  60.  
  61.         index = self.index
  62.         widget_type = json.get('type')
  63.         if widget_type == 'separator':
  64.             func = parent.insert_separator if index else parent.add_separator
  65.             func(index=index, background=self.background)
  66.         elif widget_type == 'checkbutton':
  67.             func = parent.insert_checkbutton if index else parent.add_checkbutton
  68.             func(**{**kwargs, **{'onvalue': self.onvalue, 'offvalue': self.offvalue}})
  69.         elif widget_type == 'radiobutton':
  70.             func = parent.insert_radiobutton if index else parent.add_radiobutton
  71.             func(**{**kwargs, **{'value': self.value}})
  72.         else:
  73.             func = parent.insert_command if index else parent.add_command
  74.             func(**{**kwargs, **{'image': self.image}})
  75.  
  76.     def cget(self, attribute):
  77.         return getattr(self, attribute, None)
  78.  
  79.     def config(self, **kwargs):
  80.         for attribute, value in kwargs.items():
  81.             setattr(self, attribute, value)
  82.  
  83.         index = self.index
  84.         if not self.parent.tearoff:
  85.             index -= 1
  86.  
  87.         self.parent.entryconfig(index, **kwargs)
  88.  
  89.  
  90. class Menus(Menu):
  91.     def __init__(self, parent, **kwargs):
  92.         self.items = {}
  93.         self.parent = parent
  94.         self.index = kwargs.pop('index', None)
  95.         super().__init__(parent, **kwargs)
  96.  
  97.     def menu(self, uri):
  98.         return self.get_child(uri)
  99.  
  100.     def populate(self, children):
  101.         for key, child in children.items():
  102.             self.add_child(key, child)
  103.  
  104.         return self
  105.  
  106.     def add_child(self, key, json, **kwargs):
  107.         font = json.get('font', kwargs.get('font', self.cget('font')))
  108.         if isinstance(font, dict):
  109.             font = Font(
  110.                 family=font.get('family'),
  111.                 size=font.get('size'),
  112.                 weight=font.get('weight', 'normal'),
  113.                 slant=font.get('slant', 'roman'),
  114.                 underline=font.get('underline', False),
  115.                 overstrike=font.get('overstrike', False)
  116.             )
  117.  
  118.         kwargs = {
  119.             'bd': json.get('bd', kwargs.get('bd', self.cget('bd'))),
  120.             'font': font,
  121.             'index': json.get('index', kwargs.get('index')),
  122.             'tearoff': json.get('tearoff', kwargs.get('tearoff', self.cget('tearoff'))),
  123.             'foreground': json.get('foreground', kwargs.get('foreground', self.cget('foreground'))),
  124.             'background': json.get('background', kwargs.get('background', self.cget('background'))),
  125.             'activeforeground': json.get(
  126.                 'activeforeground', kwargs.get('activeforeground', self.cget('activeforeground'))),
  127.             'activebackground': json.get(
  128.                 'activebackground', kwargs.get('activebackground', self.cget('activebackground'))),
  129.         }
  130.  
  131.         func = SubMenu if 'children' in json else MenuItem
  132.         self.items[key] = func(self, json, **kwargs)
  133.  
  134.     def get_child(self, uri):
  135.         uri = uri.replace('\\', '/')
  136.  
  137.         if '/' in uri:
  138.             def parse(parent, uri_part):
  139.                 parts = uri_part.split('/', 1)
  140.                 child = parent.get_child(parts[0])
  141.  
  142.                 if len(parts) > 1:
  143.                     child = parse(child, parts[1])
  144.                 return child
  145.  
  146.             return parse(self, uri)
  147.  
  148.         return self.items.get(uri, None)
  149.  
  150.     def get_children(self):
  151.         return self.items
  152.  
  153.     @property
  154.     def has_children(self):
  155.         return len(self.items)
  156.  
  157.     def config_children(self, **kwargs):
  158.         def process(children):
  159.             for index, child in children.items():
  160.                 if isinstance(child, MenuItem) and child.cget('widget_type') == 'separator':
  161.                     continue
  162.  
  163.                 child.config(**kwargs)
  164.  
  165.                 if child.has_children:
  166.                     process(child.get_children())
  167.  
  168.         process(self.get_children())
  169.  
  170.  
  171. class SubMenu(Menus):
  172.     def __init__(self, parent, json, **kwargs):
  173.         super().__init__(parent, **kwargs)
  174.  
  175.         self.__index = 0
  176.         self.bd = json.get('bd', kwargs.get('bd'))
  177.         self.font = json.get('font', kwargs.get('font'))
  178.         self.label = json.get('label', kwargs.get('label'))
  179.         self.image = json.get('image', kwargs.get('image'))
  180.         self.index = json.get('index', kwargs.get('index'))
  181.         self.state = json.get('state', kwargs.get('state'))
  182.         self.tearoff = json.get('tearoff', kwargs.get('tearoff'))
  183.         self.compound = json.get('compound', kwargs.get('compound', 'left'))
  184.         self.underline = json.get('underline', kwargs.get('underline'))
  185.         self.foreground = json.get('foreground', kwargs.get('foreground'))
  186.         self.background = json.get('background', kwargs.get('background'))
  187.         self.activeforeground = json.get('activeforeground', kwargs.get('activeforeground'))
  188.         self.activebackground = json.get('activebackground', kwargs.get('activebackground'))
  189.  
  190.         if not isinstance(parent, MenuBar):
  191.             self.image = PhotoImage(file=path.join(getcwd(), 'tkmenus', 'images', 'blank-21x16.png'))
  192.  
  193.         kwargs = {
  194.             'menu': self,
  195.             'label': self.label,
  196.             'image': self.image,
  197.             'compound': self.compound,
  198.             'underline': self.underline
  199.         }
  200.         if not self.index:
  201.             parent.add_cascade(**kwargs)
  202.         else:
  203.             parent.insert_cascade(self.index, **kwargs)
  204.  
  205.         kwargs = {
  206.             'font': self.font,
  207.             'state': self.state,
  208.             'foreground': self.foreground,
  209.             'background': self.background,
  210.             'activeforeground': self.activeforeground,
  211.             'activebackground': self.activebackground,
  212.         }
  213.         for key, child in json.get('children').items():
  214.             kwargs = {**kwargs, **{'index': self.next_index()}}
  215.  
  216.             if 'children' in child:
  217.                 self.items[key] = SubMenu(self, child, **{**kwargs, **{
  218.                     'bd': child.get('bd', None),
  219.                     'tearoff': child.get('tearoff', 0)
  220.                 }})
  221.             else:
  222.                 self.items[key] = MenuItem(self, child, **kwargs)
  223.  
  224.     def next_index(self):
  225.         self.__index += 1
  226.         return self.__index
  227.  
  228.  
  229. class MenuBar(Menus):
  230.     def __init__(self, parent, **kwargs):
  231.         super().__init__(parent, **kwargs)
  232.  
  233.         self.items = {}
  234.  
  235.         self.platform = system()
  236.         print(system(), release())
  237.  
  238.  
  239. class PopupMenu(Menus):
  240.     def __init__(self, parent, **kwargs):
  241.         super().__init__(parent, **kwargs)
  242.         tearoff = kwargs.get('tearoff', 0)
  243.  
  244.         self.items = {}
  245.         self.__leave = False
  246.         self.__delay_destroy = 1000
  247.         self.bind("<Enter>", self.on_enter)
  248.         self.bind("<Leave>", self.on_leave)
  249.         self.bind("<Escape>", self.on_escape)
  250.         self.config(tearoff=tearoff)
  251.  
  252.     def on_enter(self, event):
  253.         if event:
  254.             self.__leave = False
  255.  
  256.     def on_leave(self, event):
  257.         self.__leave = True
  258.  
  259.         def leave():
  260.             if self.__leave:
  261.                 self.on_escape(event)
  262.  
  263.         self.after(self.__delay_destroy, leave)
  264.  
  265.     def on_escape(self, event):
  266.         if event:
  267.             self.unpost()
  268.             self.__leave = False
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement