from collections import OrderedDict import csv from sys import platform from functools import partial import time if __debug__: from traceback import print_exc import tkinter as tk from tkinter import ttk import myNotebook as nb import companion from companion import ship_map from l10n import Locale from monitor import monitor import prefs if platform=='win32': import ctypes from ctypes.wintypes import * try: CalculatePopupWindowPosition = ctypes.windll.user32.CalculatePopupWindowPosition CalculatePopupWindowPosition.argtypes = [ctypes.POINTER(POINT), ctypes.POINTER(SIZE), UINT, ctypes.POINTER(RECT), ctypes.POINTER(RECT)] GetParent = ctypes.windll.user32.GetParent GetParent.argtypes = [HWND] GetWindowRect = ctypes.windll.user32.GetWindowRect GetWindowRect.argtypes = [HWND, ctypes.POINTER(RECT)] except: # Not supported under Wine 4.0 CalculatePopupWindowPosition = None def status(data): # StatsResults assumes these three things are first res = [ [_('Cmdr'), data['commander']['name']], [_('Balance'), str(data['commander'].get('credits', 0))], # Cmdr stats [_('Loan'), str(data['commander'].get('debt', 0))], # Cmdr stats ] RANKS = [ # in output order (_('Combat') , 'combat'), # Ranking (_('Trade') , 'trade'), # Ranking (_('Explorer') , 'explore'), # Ranking (_('CQC') , 'cqc'), # Ranking (_('Federation') , 'federation'), # Ranking (_('Empire') , 'empire'), # Ranking (_('Powerplay') , 'power'), # Ranking # ??? , 'crime'), # Ranking # ??? , 'service'), # Ranking ] RANK_NAMES = { # http://elite-dangerous.wikia.com/wiki/Pilots_Federation#Ranks 'combat' : [_('Harmless'), # Combat rank _('Mostly Harmless'), # Combat rank _('Novice'), # Combat rank _('Competent'), # Combat rank _('Expert'), # Combat rank _('Master'), # Combat rank _('Dangerous'), # Combat rank _('Deadly'), # Combat rank _('Elite')], # Top rank 'trade' : [_('Penniless'), # Trade rank _('Mostly Penniless'), # Trade rank _('Peddler'), # Trade rank _('Dealer'), # Trade rank _('Merchant'), # Trade rank _('Broker'), # Trade rank _('Entrepreneur'), # Trade rank _('Tycoon'), # Trade rank _('Elite')], # Top rank 'explore' : [_('Aimless'), # Explorer rank _('Mostly Aimless'), # Explorer rank _('Scout'), # Explorer rank _('Surveyor'), # Explorer rank _('Trailblazer'), # Explorer rank _('Pathfinder'), # Explorer rank _('Ranger'), # Explorer rank _('Pioneer'), # Explorer rank _('Elite')], # Top rank 'cqc' : [_('Helpless'), # CQC rank _('Mostly Helpless'), # CQC rank _('Amateur'), # CQC rank _('Semi Professional'), # CQC rank _('Professional'), # CQC rank _('Champion'), # CQC rank _('Hero'), # CQC rank _('Gladiator'), # CQC rank _('Elite')], # Top rank # http://elite-dangerous.wikia.com/wiki/Federation#Ranks 'federation' : [_('None'), # No rank _('Recruit'), # Federation rank _('Cadet'), # Federation rank _('Midshipman'), # Federation rank _('Petty Officer'), # Federation rank _('Chief Petty Officer'), # Federation rank _('Warrant Officer'), # Federation rank _('Ensign'), # Federation rank _('Lieutenant'), # Federation rank _('Lieutenant Commander'), # Federation rank _('Post Commander'), # Federation rank _('Post Captain'), # Federation rank _('Rear Admiral'), # Federation rank _('Vice Admiral'), # Federation rank _('Admiral')], # Federation rank # http://elite-dangerous.wikia.com/wiki/Empire#Ranks 'empire' : [_('None'), # No rank _('Outsider'), # Empire rank _('Serf'), # Empire rank _('Master'), # Empire rank _('Squire'), # Empire rank _('Knight'), # Empire rank _('Lord'), # Empire rank _('Baron'), # Empire rank _('Viscount'), # Empire rank _('Count'), # Empire rank _('Earl'), # Empire rank _('Marquis'), # Empire rank _('Duke'), # Empire rank _('Prince'), # Empire rank _('King')], # Empire rank # http://elite-dangerous.wikia.com/wiki/Ratings 'power' : [_('None'), # No rank _('Rating 1'), # Power rank _('Rating 2'), # Power rank _('Rating 3'), # Power rank _('Rating 4'), # Power rank _('Rating 5')], # Power rank } ranks = data['commander'].get('rank', {}) for title, thing in RANKS: rank = ranks.get(thing) names = RANK_NAMES[thing] if isinstance(rank, int): res.append([title, rank < len(names) and names[rank] or ('Rank %d' % rank)]) else: res.append([title, _('None')]) # No rank return res def export_status(data, filename): h = csv.writer(open(filename, 'w')) h.writerow(['Category', 'Value']) for thing in status(data): h.writerow([x for x in thing]) # Returns id,name,shipName,system,station,value def ships(data): ships = companion.listify(data.get('ships')) current = data['commander'].get('currentShipId') if isinstance(current, int) and current < len(ships) and ships[current]: ships.insert(0, ships.pop(current)) # Put current ship first if not data['commander'].get('docked'): # Set current system, not last docked return ([ (str(ships[0]['id']), ship_map.get(ships[0]['name'].lower(), ships[0]['name']), ships[0].get('shipName', ''), data['lastSystem']['name'], '', str(ships[0]['value']['total'])) ] + [ (str(ship['id']), ship_map.get(ship['name'].lower(), ship['name']), ship.get('shipName', ''), ship['starsystem']['name'], ship['station']['name'], str(ship['value']['total'])) for ship in ships[1:] if ship]) return [ (str(ship['id']), ship_map.get(ship['name'].lower(), ship['name']), ship.get('shipName', ''), ship['starsystem']['name'], ship['station']['name'], str(ship['value']['total'])) for ship in ships if ship] def export_ships(data, filename): h = csv.writer(open(filename, 'w')) h.writerow(['Id', 'Ship', 'Name', 'System', 'Station', 'Value']) for thing in ships(data): h.writerow([x for x in thing]) class StatsDialog(): def __init__(self, app): self.parent = app.w self.status = app.status self.showstats() def showstats(self): if not monitor.cmdr: return self.status['text'] = _('Fetching data...') self.parent.update_idletasks() try: data = companion.session.profile() except companion.ServerError as e: self.status['text'] = str(e) return except Exception as e: if __debug__: print_exc() self.status['text'] = str(e) return if not data.get('commander') or not data['commander'].get('name','').strip(): self.status['text'] = _("Who are you?!") # Shouldn't happen elif not data.get('lastSystem') or not data['lastSystem'].get('name','').strip() or not data.get('lastStarport') or not data['lastStarport'].get('name','').strip(): self.status['text'] = _("Where are you?!") # Shouldn't happen elif not data.get('ship') or not data['ship'].get('modules') or not data['ship'].get('name','').strip(): self.status['text'] = _("What are you flying?!") # Shouldn't happen else: self.status['text'] = '' StatsResults(self.parent, data) class StatsResults(tk.Toplevel): def __init__(self, parent, data): tk.Toplevel.__init__(self, parent) self.parent = parent stats = status(data) self.title(' '.join(stats[0])) # assumes first thing is player name if parent.winfo_viewable(): self.transient(parent) # position over parent if platform!='darwin' or parent.winfo_rooty()>0: # http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7 self.geometry("+%d+%d" % (parent.winfo_rootx(), parent.winfo_rooty())) # remove decoration self.resizable(tk.FALSE, tk.FALSE) if platform=='win32': self.attributes('-toolwindow', tk.TRUE) elif platform=='darwin': # http://wiki.tcl.tk/13428 parent.call('tk::unsupported::MacWindowStyle', 'style', self, 'utility') frame = ttk.Frame(self) frame.grid(sticky=tk.NSEW) notebook = nb.Notebook(frame) page = self.addpage(notebook) for thing in stats[1:3]: self.addpagerow(page, [thing[0], self.credits(int(thing[1]))]) # assumes things two and three are money for thing in stats[3:]: self.addpagerow(page, thing) ttk.Frame(page).grid(pady=5) # bottom spacer notebook.add(page, text=_('Status')) # Status dialog title page = self.addpage(notebook, [ _('Ship'), # Status dialog subtitle '', _('System'), # Main window _('Station'), # Status dialog subtitle _('Value'), # Status dialog subtitle - CR value of ship ]) shiplist = ships(data) for thing in shiplist: self.addpagerow(page, list(thing[1:-1]) + [self.credits(int(thing[-1]))]) # skip id, last item is money ttk.Frame(page).grid(pady=5) # bottom spacer notebook.add(page, text=_('Ships')) # Status dialog title if platform!='darwin': buttonframe = ttk.Frame(frame) buttonframe.grid(padx=10, pady=(0,10), sticky=tk.NSEW) buttonframe.columnconfigure(0, weight=1) ttk.Label(buttonframe).grid(row=0, column=0) # spacer ttk.Button(buttonframe, text='OK', command=self.destroy).grid(row=0, column=1, sticky=tk.E) # wait for window to appear on screen before calling grab_set self.wait_visibility() self.grab_set() # Ensure fully on-screen if platform == 'win32' and CalculatePopupWindowPosition: position = RECT() GetWindowRect(GetParent(self.winfo_id()), position) if CalculatePopupWindowPosition(POINT(parent.winfo_rootx(), parent.winfo_rooty()), SIZE(position.right - position.left, position.bottom - position.top), 0x10000, None, position): self.geometry("+%d+%d" % (position.left, position.top)) def addpage(self, parent, header=[], align=None): page = nb.Frame(parent) page.grid(pady=10, sticky=tk.NSEW) page.columnconfigure(0, weight=1) if header: self.addpageheader(page, header, align=align) return page def addpageheader(self, parent, header, align=None): self.addpagerow(parent, header, align=align) ttk.Separator(parent, orient=tk.HORIZONTAL).grid(columnspan=len(header), padx=10, pady=2, sticky=tk.EW) def addpagespacer(self, parent): self.addpagerow(parent, ['']) def addpagerow(self, parent, content, align=None): for i in range(len(content)): label = nb.Label(parent, text=content[i]) if i == 0: label.grid(padx=10, sticky=tk.W) row = parent.grid_size()[1]-1 elif align is None and i == len(content) - 1: # Assumes last column right justified if unspecified label.grid(row=row, column=i, padx=10, sticky=tk.E) else: label.grid(row=row, column=i, padx=10, sticky=align or tk.W) def credits(self, value): return Locale.stringFromNumber(value, 0) + ' Cr'