1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-06-01 16:11:18 +03:00

Split out ttk HyperlinkLabel widget into a separate file and generalise.

This commit is contained in:
Jonathan Harris 2015-10-13 16:50:05 +01:00
parent c4991d09ef
commit a74a928764
2 changed files with 98 additions and 48 deletions

View File

@ -8,12 +8,11 @@ from os.path import expanduser, isdir, join
import re
import requests
from time import time, localtime, strftime
import urllib
import webbrowser
import Tkinter as tk
import ttk
import tkFont
from ttkHyperlinkLabel import HyperlinkLabel
if __debug__:
from traceback import print_exc
@ -39,50 +38,6 @@ SERVER_RETRY = 5 # retry pause for Companion servers [s]
EDSM_POLL = 0.1
class HyperlinkLabel(ttk.Label):
def __init__(self, master=None, **kw):
self.urlfn = kw.pop('urlfn', None)
ttk.Label.__init__(self, master, **kw)
self.font_n = kw.get('font', ttk.Style().lookup('TLabel', 'font'))
self.font_u = tkFont.Font(self, self.font_n)
self.font_u.configure(underline = True)
self.menu = tk.Menu(None, tearoff=tk.FALSE)
self.menu.add_command(label=_('Copy'), command = self.copy) # As in Copy and Paste
self.bind('<Enter>', self._enter)
self.bind('<Leave>', self._leave)
self.bind('<Button-1>', self._click)
self.bind(platform == 'darwin' and '<Button-2>' or '<Button-3>', self._contextmenu)
# Make blue and clickable if setting non-empty text
def __setitem__(self, key, value):
if key=='text':
if self.urlfn and value:
self.configure({key: value}, foreground = 'blue', cursor = platform=='darwin' and 'pointinghand' or 'hand2')
else:
self.configure({key: value}, foreground = '', cursor = 'arrow')
else:
self.configure({key: value})
def _enter(self, event):
self.configure(font = self.font_u)
def _leave(self, event):
self.configure(font = self.font_n)
def _click(self, event):
if self.urlfn and self['text']:
webbrowser.open(self.urlfn(self['text']))
def _contextmenu(self, event):
if self['text'] and self['text'] != AppWindow.STATION_UNDOCKED:
self.menu.post(platform == 'darwin' and event.x_root + 1 or event.x_root, event.y_root)
def copy(self):
self.clipboard_clear()
self.clipboard_append(self['text'])
class AppWindow:
STATION_UNDOCKED = u'×' # "Station" name to display when not docked = U+00D7
@ -127,8 +82,8 @@ class AppWindow:
ttk.Label(frame, text=_('Station:')).grid(row=2, column=0, sticky=tk.W) # Main window
self.cmdr = ttk.Label(frame, width=-21)
self.system = HyperlinkLabel(frame, compound=tk.RIGHT, urlfn = self.system_url)
self.station = HyperlinkLabel(frame, urlfn = self.station_url)
self.system = HyperlinkLabel(frame, compound=tk.RIGHT, url = self.system_url, popup_copy = True)
self.station = HyperlinkLabel(frame, url = self.station_url, popup_copy = lambda x: x!=self.STATION_UNDOCKED)
self.button = ttk.Button(frame, text=_('Update'), command=self.getandsend, default=tk.ACTIVE, state=tk.DISABLED) # Update button in main window
self.status = ttk.Label(frame, width=-25)
self.w.bind('<Return>', self.getandsend)

95
ttkHyperlinkLabel.py Normal file
View File

@ -0,0 +1,95 @@
from sys import platform
import webbrowser
import Tkinter as tk
import ttk
import tkFont
# A clickable ttk Label
#
# In addition to standard ttk.Label arguments, takes the following arguments:
# url: The URL as a string that the user will be sent to on clicking on non-empty label text. If url is a function it will be called on click with the current label text and should return the URL as a string.
# underline: If True/False the text is always/never underlined. If None (the default) the text is underlined only on hover.
# popup_copy: Whether right-click on non-empty label text pops up a context menu with a 'Copy' option. Defaults to no context menu. If popup_copy is a function it will be called with the current label text and should a boolean.
#
class HyperlinkLabel(ttk.Label, object):
def __init__(self, master=None, **kw):
self.url = kw.pop('url')
self.popup_copy = kw.pop('popup_copy', False)
self.underline = kw.pop('underline', None) # override ttk.Label's underline
self.foreground = kw.get('foreground') or 'blue'
self.disabledforeground = kw.pop('disabledforeground', None) or 'SystemWindowText'
ttk.Label.__init__(self, master, **kw)
if self.url:
self.bind('<Button-1>', self._click)
if self.popup_copy:
self.menu = tk.Menu(None, tearoff=tk.FALSE)
self.menu.add_command(label=_('Copy'), command = self.copy) # As in Copy and Paste
self.bind(platform == 'darwin' and '<Button-2>' or '<Button-3>', self._contextmenu)
if self.underline is not False:
self.font_n = kw.get('font', ttk.Style().lookup('TLabel', 'font'))
self.font_u = tkFont.Font(self, self.font_n)
self.font_u.configure(underline = True)
if self.underline is True:
self.configure(font = self.font_u)
else:
self.bind('<Enter>', self._enter)
self.bind('<Leave>', self._leave)
self.configure(state = kw.get('state'), text = kw.get('text')) # set up initial appearance
# Change cursor and appearance depending on state and text
def configure(self, cnf=None, **kw):
if kw.get('state') == tk.DISABLED:
if 'foreground' not in kw:
kw['foreground'] = self.disabledforeground
if self.underline is not False and 'font' not in kw:
kw['font'] = self.font_n
if 'cursor' not in kw:
kw['cursor'] = 'arrow' # System default
elif 'state' in kw:
if 'foreground' not in kw:
kw['foreground'] = self.foreground
if self.underline is True and 'font' not in kw:
kw['font'] = self.font_u
# Hover cursor only if widget is enabled and text is non-empty
if ('text' in kw or 'state' in kw) and 'cursor' not in kw:
if self.url and (kw['text'] if 'text' in kw else self['text']) and (kw['state'] if 'state' in kw else str(self['state']))!=tk.DISABLED:
kw['cursor'] = platform=='darwin' and 'pointinghand' or 'hand2'
else:
kw['cursor'] = 'arrow' # System default
super(HyperlinkLabel, self).configure(cnf, **kw)
def __setitem__(self, key, value):
self.configure(None, **{key: value})
def _enter(self, event):
if str(self['state']) != tk.DISABLED:
self.configure(font = self.font_u)
def _leave(self, event):
self.configure(font = self.font_n)
def _click(self, event):
if self['text'] and str(self['state']) != tk.DISABLED:
url = self.url(self['text']) if callable(self.url) else self.url
if url:
webbrowser.open(url)
def _contextmenu(self, event):
if self['text'] and (self.popup_copy(self['text']) if callable(self.popup_copy) else self.popup_copy):
self.menu.post(platform == 'darwin' and event.x_root + 1 or event.x_root, event.y_root)
def copy(self):
self.clipboard_clear()
self.clipboard_append(self['text'])