Advertisement
Uno-Dan

Untitled

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