mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-04-14 00:07:14 +03:00
Add support for internal plugins
Settings tab shows current plugins.
This commit is contained in:
parent
72efbadc59
commit
084128e797
@ -135,8 +135,8 @@ class AppWindow:
|
||||
self.system.grid(row=3, column=1, sticky=tk.EW)
|
||||
self.station.grid(row=4, column=1, sticky=tk.EW)
|
||||
|
||||
for plugname in plug.PLUGINS:
|
||||
appitem = plug.get_plugin_app(plugname, frame)
|
||||
for plugin in plug.PLUGINS:
|
||||
appitem = plugin.get_app(frame)
|
||||
if appitem:
|
||||
if isinstance(appitem, tuple) and len(appitem)==2:
|
||||
row = frame.grid_size()[1]
|
||||
@ -489,7 +489,7 @@ class AppWindow:
|
||||
self.edit_menu.entryconfigure(0, state=tk.NORMAL) # Copy
|
||||
|
||||
# stuff we can do when not docked
|
||||
plug.notify_newdata(data)
|
||||
self.status['text'] = plug.notify_newdata(data) or ''
|
||||
if config.getint('output') & config.OUT_SHIP:
|
||||
loadout.export(data)
|
||||
|
||||
@ -733,7 +733,9 @@ class AppWindow:
|
||||
return # Startup or in CQC
|
||||
|
||||
# Plugins
|
||||
plug.notify_journal_entry(monitor.cmdr, monitor.system, monitor.station, entry, monitor.state)
|
||||
err = plug.notify_journal_entry(monitor.cmdr, monitor.system, monitor.station, entry, monitor.state)
|
||||
if err:
|
||||
self.status['text'] = err
|
||||
|
||||
if entry['event'] in ['StartUp', 'LoadGame'] and monitor.started:
|
||||
# Can start interaction monitoring
|
||||
@ -814,7 +816,9 @@ class AppWindow:
|
||||
return
|
||||
|
||||
# Currently we don't do anything with these events
|
||||
plug.notify_interaction(monitor.cmdr, entry)
|
||||
err = plug.notify_interaction(monitor.cmdr, entry)
|
||||
if err:
|
||||
self.status['text'] = err
|
||||
|
||||
def edsmpoll(self):
|
||||
result = self.edsm.result
|
||||
|
@ -123,6 +123,8 @@ class Config:
|
||||
if not isdir(self.plugin_dir):
|
||||
mkdir(self.plugin_dir)
|
||||
|
||||
self.internal_plugin_dir = getattr(sys, 'frozen', False) and normpath(join(dirname(sys.executable), pardir, 'Resources')) or join(dirname(__file__), 'plugins')
|
||||
|
||||
self.default_journal_dir = join(NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, True)[0], 'Frontier Developments', 'Elite Dangerous')
|
||||
|
||||
self.default_interaction_dir = join(self.default_journal_dir, 'CommanderHistory')
|
||||
@ -183,6 +185,8 @@ class Config:
|
||||
if not isdir(self.plugin_dir):
|
||||
mkdir(self.plugin_dir)
|
||||
|
||||
self.internal_plugin_dir = getattr(sys, 'frozen', False) and dirname(sys.executable) or join(dirname(__file__), 'plugins')
|
||||
|
||||
# expanduser in Python 2 on Windows doesn't handle non-ASCII - http://bugs.python.org/issue13207
|
||||
self.home = KnownFolderPath(FOLDERID_Profile) or u'\\'
|
||||
|
||||
@ -282,6 +286,8 @@ class Config:
|
||||
if not isdir(self.plugin_dir):
|
||||
mkdir(self.plugin_dir)
|
||||
|
||||
self.internal_plugin_dir = join(dirname(__file__), 'plugins')
|
||||
|
||||
self.default_journal_dir = None
|
||||
|
||||
self.default_interaction_dir = None
|
||||
|
7
l10n.py
7
l10n.py
@ -6,7 +6,7 @@
|
||||
import codecs
|
||||
from collections import OrderedDict
|
||||
import os
|
||||
from os.path import dirname, isfile, join, normpath
|
||||
from os.path import basename, dirname, isfile, join, normpath
|
||||
import re
|
||||
import sys
|
||||
from sys import platform
|
||||
@ -166,14 +166,15 @@ if __name__ == "__main__":
|
||||
import re
|
||||
regexp = re.compile(r'''_\([ur]?(['"])(((?<!\\)\\\1|.)+?)\1\)[^#]*(#.+)?''') # match a single line python literal
|
||||
seen = {}
|
||||
for f in sorted([x for x in os.listdir('.') if x.endswith('.py')]):
|
||||
for f in sorted([x for x in os.listdir('.') if x.endswith('.py')] +
|
||||
[join('plugins', x) for x in os.listdir('plugins') if x.endswith('.py')]):
|
||||
with codecs.open(f, 'r', 'utf-8') as h:
|
||||
lineno = 0
|
||||
for line in h:
|
||||
lineno += 1
|
||||
match = regexp.search(line)
|
||||
if match and not seen.get(match.group(2)): # only record first commented instance of a string
|
||||
seen[match.group(2)] = (match.group(4) and (match.group(4)[1:].strip()) + '. ' or '') + '[%s]' % f
|
||||
seen[match.group(2)] = (match.group(4) and (match.group(4)[1:].strip()) + '. ' or '') + '[%s]' % basename(f)
|
||||
if seen:
|
||||
template = codecs.open('L10n/en.template', 'w', 'utf-8')
|
||||
template.write('/* Language name */\n"%s" = "%s";\n\n' % (LANGUAGE_ID, 'English'))
|
||||
|
252
plug.py
252
plug.py
@ -1,150 +1,151 @@
|
||||
"""
|
||||
Plugin hooks for EDMC - Ian Norton
|
||||
Plugin hooks for EDMC - Ian Norton, Jonathan Harris
|
||||
"""
|
||||
import os
|
||||
import imp
|
||||
import sys
|
||||
import operator
|
||||
import threading # We don't use it, but plugins might
|
||||
from traceback import print_exc
|
||||
|
||||
if __debug__:
|
||||
from traceback import print_exc
|
||||
from config import config, appname
|
||||
|
||||
from config import config
|
||||
|
||||
"""
|
||||
Dictionary of loaded plugin modules.
|
||||
"""
|
||||
PLUGINS = dict()
|
||||
# List of loaded Plugins
|
||||
PLUGINS = []
|
||||
|
||||
|
||||
def find_plugins():
|
||||
"""
|
||||
Look for plugin entry points.
|
||||
:return:
|
||||
"""
|
||||
found = dict()
|
||||
disabled = list()
|
||||
plug_folders = os.listdir(config.plugin_dir)
|
||||
for name in plug_folders:
|
||||
if name.endswith(".disabled"):
|
||||
name, discard = name.rsplit(".", 1)
|
||||
disabled.append(name)
|
||||
continue
|
||||
loadfile = os.path.join(config.plugin_dir, name, "load.py")
|
||||
if os.path.isfile(loadfile):
|
||||
found[name] = loadfile
|
||||
return found, disabled
|
||||
class Plugin(object):
|
||||
|
||||
def __init__(self, name, loadfile):
|
||||
"""
|
||||
Load a single plugin
|
||||
:param name: module name
|
||||
:param loadfile: the main .py file
|
||||
:raises Exception: Typically ImportError or OSError
|
||||
"""
|
||||
|
||||
self.name = name # Display name.
|
||||
self.folder = name # basename of plugin folder. None for internal plugins.
|
||||
self.module = None # None for disabled plugins.
|
||||
|
||||
if loadfile:
|
||||
sys.stdout.write('loading plugin %s\n' % name)
|
||||
with open(loadfile, 'rb') as plugfile:
|
||||
module = imp.load_module(name, plugfile, loadfile.encode(sys.getfilesystemencoding()),
|
||||
('.py', 'r', imp.PY_SOURCE))
|
||||
newname = module.plugin_start()
|
||||
self.name = newname and unicode(newname) or name
|
||||
self.module = module
|
||||
else:
|
||||
sys.stdout.write('plugin %s disabled\n' % name)
|
||||
|
||||
def _get_func(self, funcname):
|
||||
"""
|
||||
Get a function from a plugin, else return None if it isn't implemented.
|
||||
:param funcname:
|
||||
:return:
|
||||
"""
|
||||
return getattr(self.module, funcname, None)
|
||||
|
||||
def get_app(self, parent):
|
||||
"""
|
||||
If the plugin provides mainwindow content create and return it.
|
||||
:param parent: the parent frame for this entry.
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
plugin_app = self._get_func('plugin_app')
|
||||
return plugin_app and plugin_app(parent)
|
||||
except:
|
||||
print_exc()
|
||||
return None
|
||||
|
||||
def get_prefs(self, parent):
|
||||
"""
|
||||
If the plugin provides a prefs frame, create and return it.
|
||||
:param parent: the parent frame for this preference tab.
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
plugin_prefs = self._get_func('plugin_prefs')
|
||||
return plugin_prefs and plugin_prefs(parent)
|
||||
except:
|
||||
print_exc()
|
||||
return None
|
||||
|
||||
|
||||
def load_plugins():
|
||||
"""
|
||||
Load all found plugins
|
||||
Find and load all plugins
|
||||
:return:
|
||||
"""
|
||||
found, disabled = find_plugins()
|
||||
imp.acquire_lock()
|
||||
for plugname in disabled:
|
||||
sys.stdout.write("plugin {} disabled\n".format(plugname))
|
||||
|
||||
for plugname, loadfile in found.iteritems():
|
||||
try:
|
||||
sys.stdout.write("loading plugin {}\n".format(plugname))
|
||||
|
||||
# Add plugin's folder to Python's load path in case plugin has dependencies.
|
||||
sys.path.append(os.path.dirname(loadfile))
|
||||
|
||||
with open(loadfile, "rb") as plugfile:
|
||||
plugmod = imp.load_module(plugname, plugfile, loadfile.encode(sys.getfilesystemencoding()),
|
||||
(".py", "r", imp.PY_SOURCE))
|
||||
if hasattr(plugmod, "plugin_start"):
|
||||
newname = plugmod.plugin_start()
|
||||
PLUGINS[newname and unicode(newname) or plugname] = plugmod
|
||||
|
||||
except Exception as plugerr:
|
||||
if __debug__:
|
||||
internal = []
|
||||
for name in os.listdir(config.internal_plugin_dir):
|
||||
if name.endswith('.py') and not name[0] in ['.', '_'] and not name.startswith(appname):
|
||||
try:
|
||||
plugin = Plugin(name[:-3], os.path.join(config.internal_plugin_dir, name))
|
||||
plugin.folder = None # Suppress listing in Plugins prefs tab
|
||||
internal.append(plugin)
|
||||
except:
|
||||
print_exc()
|
||||
else:
|
||||
sys.stderr.write('%s: %s\n' % (plugname, plugerr)) # appears in %TMP%/EDMarketConnector.log in packaged Windows app
|
||||
PLUGINS.extend(sorted(internal, key = lambda p: operator.attrgetter('name')(p).lower()))
|
||||
|
||||
found = []
|
||||
for name in os.listdir(config.plugin_dir):
|
||||
if name[0] == '.':
|
||||
pass
|
||||
elif name.endswith('.disabled'):
|
||||
name, discard = name.rsplit('.', 1)
|
||||
found.append(Plugin(name, None))
|
||||
else:
|
||||
try:
|
||||
found.append(Plugin(name, os.path.join(config.plugin_dir, name, 'load.py')))
|
||||
except:
|
||||
print_exc()
|
||||
PLUGINS.extend(sorted(found, key = lambda p: operator.attrgetter('name')(p).lower()))
|
||||
|
||||
imp.release_lock()
|
||||
|
||||
|
||||
def _get_plugin_func(plugname, funcname):
|
||||
"""
|
||||
Get a function from a plugin, else return None if it isn't implemented.
|
||||
:param plugname:
|
||||
:param funcname:
|
||||
:return:
|
||||
"""
|
||||
return getattr(PLUGINS[plugname], funcname, None)
|
||||
|
||||
|
||||
def get_plugin_app(plugname, parent):
|
||||
"""
|
||||
If the plugin provides mainwindow content create and return it.
|
||||
:param plugname: name of the plugin
|
||||
:param parent: the parent frame for this entry.
|
||||
:return:
|
||||
"""
|
||||
plugin_app = _get_plugin_func(plugname, "plugin_app")
|
||||
if plugin_app:
|
||||
return plugin_app(parent)
|
||||
return None
|
||||
|
||||
|
||||
def get_plugin_prefs(plugname, parent):
|
||||
"""
|
||||
If the plugin provides a prefs frame, create and return it.
|
||||
:param plugname: name of the plugin
|
||||
:param parent: the parent frame for this preference tab.
|
||||
:return:
|
||||
"""
|
||||
plugin_prefs = _get_plugin_func(plugname, "plugin_prefs")
|
||||
if plugin_prefs:
|
||||
return plugin_prefs(parent)
|
||||
return None
|
||||
|
||||
|
||||
def notify_prefs_changed():
|
||||
"""
|
||||
Notify each plugin that the settings dialog has been closed.
|
||||
:return:
|
||||
"""
|
||||
for plugname in PLUGINS:
|
||||
prefs_changed = _get_plugin_func(plugname, "prefs_changed")
|
||||
for plugin in PLUGINS:
|
||||
prefs_changed = plugin._get_func('prefs_changed')
|
||||
if prefs_changed:
|
||||
try:
|
||||
prefs_changed()
|
||||
except Exception as plugerr:
|
||||
if __debug__:
|
||||
print_exc()
|
||||
else:
|
||||
sys.stderr.write('%s: %s\n' % (plugname, plugerr))
|
||||
except:
|
||||
print_exc()
|
||||
|
||||
|
||||
def notify_journal_entry(cmdr, system, station, entry, state):
|
||||
def notify_journal_entry(cmdr, system, station, entry, cmdr_state):
|
||||
"""
|
||||
Send a journal entry to each plugin.
|
||||
:param cmdr: The Cmdr name, or None if not yet known
|
||||
:param system: The current system, or None if not yet known
|
||||
:param station: The current station, or None if not docked or not yet known
|
||||
:param entry: The journal entry as a dictionary
|
||||
:param state: A dictionary containing info about the Cmdr, current ship and cargo
|
||||
:return:
|
||||
:param cmdr_state: A dictionary containing info about the Cmdr, current ship and cargo
|
||||
:return: Error message from the first plugin that returns one (if any)
|
||||
"""
|
||||
for plugname in PLUGINS:
|
||||
journal_entry = _get_plugin_func(plugname, "journal_entry")
|
||||
error = None
|
||||
for plugin in PLUGINS:
|
||||
journal_entry = plugin._get_func('journal_entry')
|
||||
if journal_entry:
|
||||
try:
|
||||
# Pass a copy of the journal entry in case the callee modifies it
|
||||
if journal_entry.func_code.co_argcount == 4:
|
||||
journal_entry(cmdr, system, station, dict(entry))
|
||||
error = error or journal_entry(cmdr, system, station, dict(entry))
|
||||
else:
|
||||
journal_entry(cmdr, system, station, dict(entry), dict(state))
|
||||
except Exception as plugerr:
|
||||
if __debug__:
|
||||
print_exc()
|
||||
else:
|
||||
sys.stderr.write('%s: %s\n' % (plugname, plugerr))
|
||||
error = error or journal_entry(cmdr, system, station, dict(entry), dict(cmdr_state))
|
||||
except:
|
||||
print_exc()
|
||||
return error
|
||||
|
||||
|
||||
def notify_interaction(cmdr, entry):
|
||||
@ -152,19 +153,18 @@ def notify_interaction(cmdr, entry):
|
||||
Send an interaction entry to each plugin.
|
||||
:param cmdr: The piloting Cmdr name
|
||||
:param entry: The interaction entry as a dictionary
|
||||
:return:
|
||||
:return: Error message from the first plugin that returns one (if any)
|
||||
"""
|
||||
for plugname in PLUGINS:
|
||||
interaction = _get_plugin_func(plugname, "interaction")
|
||||
error = None
|
||||
for plugin in PLUGINS:
|
||||
interaction = plugin._get_func('interaction')
|
||||
if interaction:
|
||||
try:
|
||||
# Pass a copy of the interaction entry in case the callee modifies it
|
||||
interaction(cmdr, dict(entry))
|
||||
except Exception as plugerr:
|
||||
if __debug__:
|
||||
print_exc()
|
||||
else:
|
||||
sys.stderr.write('%s: %s\n' % (plugname, plugerr))
|
||||
error = error or interaction(cmdr, dict(entry))
|
||||
except:
|
||||
print_exc()
|
||||
return error
|
||||
|
||||
|
||||
def notify_system_changed(timestamp, system, coordinates):
|
||||
@ -176,34 +176,30 @@ def notify_system_changed(timestamp, system, coordinates):
|
||||
deprecated:: 2.2
|
||||
Use :func:`journal_entry` with the 'FSDJump' event.
|
||||
"""
|
||||
for plugname in PLUGINS:
|
||||
system_changed = _get_plugin_func(plugname, "system_changed")
|
||||
for plugin in PLUGINS:
|
||||
system_changed = plugin._get_func('system_changed')
|
||||
if system_changed:
|
||||
try:
|
||||
if system_changed.func_code.co_argcount == 2:
|
||||
system_changed(timestamp, system)
|
||||
else:
|
||||
system_changed(timestamp, system, coordinates)
|
||||
except Exception as plugerr:
|
||||
if __debug__:
|
||||
print_exc()
|
||||
else:
|
||||
sys.stderr.write('%s: %s\n' % (plugname, plugerr))
|
||||
except:
|
||||
print_exc()
|
||||
|
||||
|
||||
def notify_newdata(data):
|
||||
"""
|
||||
Send the latest EDMC data from the FD servers to each plugin
|
||||
:param data:
|
||||
:return:
|
||||
:return: Error message from the first plugin that returns one (if any)
|
||||
"""
|
||||
for plugname in PLUGINS:
|
||||
cmdr_data = _get_plugin_func(plugname, "cmdr_data")
|
||||
error = None
|
||||
for plugin in PLUGINS:
|
||||
cmdr_data = plugin._get_func('cmdr_data')
|
||||
if cmdr_data:
|
||||
try:
|
||||
cmdr_data(data)
|
||||
except Exception as plugerr:
|
||||
if __debug__:
|
||||
print_exc()
|
||||
else:
|
||||
sys.stderr.write('%s: %s\n' % (plugname, plugerr))
|
||||
error = error or cmdr_data(data)
|
||||
except:
|
||||
print_exc()
|
||||
return error
|
||||
|
@ -1,78 +0,0 @@
|
||||
"""
|
||||
A Skeleton EDMC Plugin
|
||||
"""
|
||||
import sys
|
||||
import ttk
|
||||
import Tkinter as tk
|
||||
|
||||
from config import applongname, appversion
|
||||
import myNotebook as nb
|
||||
|
||||
|
||||
def plugin_start():
|
||||
"""
|
||||
Start this plugin
|
||||
:return: Plugin name
|
||||
"""
|
||||
sys.stderr.write("example plugin started\n") # appears in %TMP%/EDMarketConnector.log in packaged Windows app
|
||||
return 'About'
|
||||
|
||||
|
||||
def plugin_prefs(parent):
|
||||
"""
|
||||
Return a TK Frame for adding to the EDMC settings dialog.
|
||||
"""
|
||||
frame = nb.Frame(parent)
|
||||
|
||||
nb.Label(frame, text="{NAME} {VER}".format(NAME=applongname, VER=appversion)).grid(sticky=tk.W)
|
||||
nb.Label(frame).grid() # spacer
|
||||
nb.Label(frame, text="Fly Safe!").grid(sticky=tk.W)
|
||||
nb.Label(frame).grid() # spacer
|
||||
|
||||
if cmdr_data.last is not None:
|
||||
datalen = len(str(cmdr_data.last))
|
||||
nb.Label(frame, text="FD sent {} chars".format(datalen)).grid(sticky=tk.W)
|
||||
|
||||
return frame
|
||||
|
||||
|
||||
def plugin_app(parent):
|
||||
"""
|
||||
Return a TK Widget for the EDMC main window.
|
||||
:param parent:
|
||||
:return:
|
||||
"""
|
||||
plugin_app.status = tk.Label(parent, text="---")
|
||||
return plugin_app.status
|
||||
|
||||
|
||||
def journal_entry(cmdr, system, station, entry, state):
|
||||
"""
|
||||
E:D client made a journal entry
|
||||
:param cmdr: The Cmdr name, or None if not yet known
|
||||
:param system: The current system, or None if not yet known
|
||||
:param station: The current station, or None if not docked or not yet known
|
||||
:param entry: The journal entry as a dictionary
|
||||
:param state: A dictionary containing info about the Cmdr, current ship and cargo
|
||||
:return:
|
||||
"""
|
||||
if entry['event'] == 'FSDJump':
|
||||
# We arrived at a new system!
|
||||
if 'StarPos' in entry:
|
||||
sys.stderr.write("Arrived at {} ({},{},{})\n".format(entry['StarSystem'], *tuple(entry['StarPos'])))
|
||||
else:
|
||||
sys.stderr.write("Arrived at {}\n".format(entry['StarSystem']))
|
||||
|
||||
|
||||
def cmdr_data(data):
|
||||
"""
|
||||
Obtained new data from Frontier about our commander, location and ships
|
||||
:param data:
|
||||
:return:
|
||||
"""
|
||||
cmdr_data.last = data
|
||||
plugin_app.status['text'] = "Got new data ({} chars)".format(len(str(data)))
|
||||
sys.stderr.write("Got new data ({} chars)\n".format(len(str(data))))
|
||||
|
||||
cmdr_data.last = None
|
||||
|
28
prefs.py
28
prefs.py
@ -211,10 +211,10 @@ class PreferencesDialog(tk.Toplevel):
|
||||
notebook.add(edsmframe, text='EDSM') # Not translated
|
||||
|
||||
# build plugin prefs tabs
|
||||
for plugname in plug.PLUGINS:
|
||||
plugframe = plug.get_plugin_prefs(plugname, notebook)
|
||||
for plugin in plug.PLUGINS:
|
||||
plugframe = plugin.get_prefs(notebook)
|
||||
if plugframe:
|
||||
notebook.add(plugframe, text=plugname)
|
||||
notebook.add(plugframe, text=plugin.name)
|
||||
|
||||
configframe = nb.Frame(notebook)
|
||||
configframe.columnconfigure(1, weight=1)
|
||||
@ -326,11 +326,8 @@ class PreferencesDialog(tk.Toplevel):
|
||||
plugdir = tk.StringVar()
|
||||
plugdir.set(config.plugin_dir)
|
||||
|
||||
plugnames, disabled_plugins = plug.find_plugins()
|
||||
|
||||
nb.Label(plugsframe, text=_('Plugins folder')+':').grid(padx=PADX, sticky=tk.W) # Section heading in settings
|
||||
plugdirentry = nb.Entry(plugsframe,
|
||||
justify=tk.LEFT)
|
||||
plugdirentry = nb.Entry(plugsframe, justify=tk.LEFT)
|
||||
self.displaypath(plugdir, plugdirentry)
|
||||
plugdirentry.grid(row=10, padx=PADX, sticky=tk.EW)
|
||||
|
||||
@ -340,16 +337,23 @@ class PreferencesDialog(tk.Toplevel):
|
||||
nb.Label(plugsframe, text=_("Tip: You can disable a plugin by{CR}adding '{EXT}' to it's folder name").format(EXT='.disabled')).grid( # Help text in settings
|
||||
columnspan=2, padx=PADX, pady=10, sticky=tk.NSEW)
|
||||
|
||||
if len(plugnames):
|
||||
enabled_plugins = [x for x in plug.PLUGINS if x.folder and x.module]
|
||||
if len(enabled_plugins):
|
||||
ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW)
|
||||
nb.Label(plugsframe, text=_('Enabled Plugins')+':').grid(padx=PADX, sticky=tk.W) # List of plugins in settings
|
||||
for plugname in plugnames:
|
||||
nb.Label(plugsframe, text=plugname).grid(columnspan=2, padx=PADX*2, sticky=tk.W)
|
||||
for plugin in enabled_plugins:
|
||||
if plugin.name == plugin.folder:
|
||||
label = nb.Label(plugsframe, text=plugin.name)
|
||||
else:
|
||||
label = nb.Label(plugsframe, text='%s (%s)' % (plugin.folder, plugin.name))
|
||||
label.grid(columnspan=2, padx=PADX*2, sticky=tk.W)
|
||||
|
||||
disabled_plugins = [x for x in plug.PLUGINS if x.folder and not x.module]
|
||||
if len(disabled_plugins):
|
||||
ttk.Separator(plugsframe, orient=tk.HORIZONTAL).grid(columnspan=3, padx=PADX, pady=PADY * 8, sticky=tk.EW)
|
||||
nb.Label(plugsframe, text=_('Disabled Plugins')+':').grid(padx=PADX, sticky=tk.W) # List of plugins in settings
|
||||
for plugname in disabled_plugins:
|
||||
nb.Label(plugsframe, text=plugname).grid(columnspan=2, padx=PADX*2, sticky=tk.W)
|
||||
for plugin in disabled_plugins:
|
||||
nb.Label(plugsframe, text=plugin.name).grid(columnspan=2, padx=PADX*2, sticky=tk.W)
|
||||
|
||||
notebook.add(plugsframe, text=_('Plugins')) # Tab heading in settings
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user