From 5fc1fd42b8eaec2fe38cd4aa3f7853ead6b27cc0 Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Tue, 16 Jul 2019 17:10:10 +0200 Subject: [PATCH 01/18] Added AutoCompleter class --- AutoCompleter.py | 125 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100755 AutoCompleter.py diff --git a/AutoCompleter.py b/AutoCompleter.py new file mode 100755 index 0000000..54b5de5 --- /dev/null +++ b/AutoCompleter.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python2 + +from Tkinter import * +import threading +import Queue +from time import sleep +import json +import os +import requests + +class AutoCompleter(Entry): + def __init__(self, *args, **kwargs): + Entry.__init__(self, *args, **kwargs) + self.lb_up = False + self.has_selected = False + self.queue = Queue.Queue() + + self.var = self["textvariable"] + if self.var == '': + self.var = self["textvariable"] = StringVar() + + self.var.trace('w', self.changed) + self.bind("", self.keypressed) + + self.update_me() + + def keypressed(self, event): + key=event.keysym + if key == 'Down': + self.down() + elif key == 'Up': + self.up() + elif key in ['Return', 'Right']: + self.selection() + + def changed(self, name, index, mode): + if self.var.get().__len__() < 3 and self.lb_up or self.has_selected: + self.lb.destroy() + self.lb_up = False + self.has_selected = False + else: + t = threading.Thread(target=self.query_systems) + t.start() + + def selection(self, event=None): + if self.lb_up: + self.has_selected = True + self.var.set(self.lb.get(ACTIVE)) + self.lb.destroy() + self.lb_up = False + self.icursor(END) + + def up(self): + if self.lb_up: + if self.lb.curselection() == (): + index = '0' + else: + index = self.lb.curselection()[0] + if index != '0': + self.lb.selection_clear(first=index) + index = str(int(index)-1) + self.lb.selection_set(first=index) + self.lb.activate(index) + + def down(self): + if self.lb_up: + if self.lb.curselection() == (): + index = '0' + else: + index = self.lb.curselection()[0] + if int(index+1) != END: + self.lb.selection_clear(first=index) + index = str(int(index+1)) + + self.lb.selection_set(first=index) + self.lb.activate(index) + + def show_results(self, results): + if results: + if not self.lb_up: + self.lb = Listbox() + self.lb.place(x=self.winfo_x(), y=self.winfo_y()+self.winfo_height()) + self.lb_up = True + + self.lb.delete(0, END) + for w in results: + self.lb.insert(END,w) + else: + if self.lb_up: + self.lb.destroy() + self.lb_up = False + + def query_systems(self): + url = "https://spansh.co.uk/api/systems?" + results = requests.get(url, + params={'q': self.var.get()}, + headers={'User-Agent': "EDMC_SpanshRouter 1.0"}) + + lista = json.loads(results.content) + if lista: + self.write(lista) + + def write(self, lista): + self.queue.put(lista) + + def clear(self): + self.queue.put(None) + + def update_me(self): + try: + while 1: + lista = self.queue.get_nowait() + self.show_results(lista) + + self.update_idletasks() + except Queue.Empty: + pass + self.after(100, self.update_me) + +if __name__ == '__main__': + root = Tk() + + widget = AutoCompleter(root) + widget.grid(row=0) + root.mainloop() \ No newline at end of file From 9284e5f4459838ee6f87a55f948a4546f8ad9d88 Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Tue, 16 Jul 2019 17:31:38 +0200 Subject: [PATCH 02/18] add escape key to close autocopletion list --- AutoCompleter.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/AutoCompleter.py b/AutoCompleter.py index 54b5de5..eca5618 100755 --- a/AutoCompleter.py +++ b/AutoCompleter.py @@ -9,8 +9,9 @@ import os import requests class AutoCompleter(Entry): - def __init__(self, *args, **kwargs): - Entry.__init__(self, *args, **kwargs) + def __init__(self, parent, **kwargs): + self.parent = parent + Entry.__init__(self, parent, **kwargs) self.lb_up = False self.has_selected = False self.queue = Queue.Queue() @@ -31,7 +32,11 @@ class AutoCompleter(Entry): elif key == 'Up': self.up() elif key in ['Return', 'Right']: - self.selection() + if self.lb_up: + self.selection() + elif key == 'Escape' and self.lb_up: + self.lb.destroy() + self.lb_up = False def changed(self, name, index, mode): if self.var.get().__len__() < 3 and self.lb_up or self.has_selected: @@ -74,11 +79,13 @@ class AutoCompleter(Entry): self.lb.selection_set(first=index) self.lb.activate(index) + else: + self.query_systems() def show_results(self, results): if results: if not self.lb_up: - self.lb = Listbox() + self.lb = Listbox(self.parent) self.lb.place(x=self.winfo_x(), y=self.winfo_y()+self.winfo_height()) self.lb_up = True @@ -91,14 +98,16 @@ class AutoCompleter(Entry): self.lb_up = False def query_systems(self): - url = "https://spansh.co.uk/api/systems?" - results = requests.get(url, - params={'q': self.var.get()}, - headers={'User-Agent': "EDMC_SpanshRouter 1.0"}) + inp = self.var.get() + if inp.__len__() >= 3: + url = "https://spansh.co.uk/api/systems?" + results = requests.get(url, + params={'q': inp}, + headers={'User-Agent': "EDMC_SpanshRouter 1.0"}) - lista = json.loads(results.content) - if lista: - self.write(lista) + lista = json.loads(results.content) + if lista: + self.write(lista) def write(self, lista): self.queue.put(lista) From e91d9a8ada1567f6b2ecd24b2599285f56169a36 Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Tue, 16 Jul 2019 19:04:03 +0200 Subject: [PATCH 03/18] Adaptive height and length --- AutoCompleter.py | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/AutoCompleter.py b/AutoCompleter.py index eca5618..a8a2a43 100755 --- a/AutoCompleter.py +++ b/AutoCompleter.py @@ -12,6 +12,7 @@ class AutoCompleter(Entry): def __init__(self, parent, **kwargs): self.parent = parent Entry.__init__(self, parent, **kwargs) + self.lb = Listbox(self.parent) self.lb_up = False self.has_selected = False self.queue = Queue.Queue() @@ -35,13 +36,11 @@ class AutoCompleter(Entry): if self.lb_up: self.selection() elif key == 'Escape' and self.lb_up: - self.lb.destroy() - self.lb_up = False + self.hide_list() def changed(self, name, index, mode): if self.var.get().__len__() < 3 and self.lb_up or self.has_selected: - self.lb.destroy() - self.lb_up = False + self.hide_list self.has_selected = False else: t = threading.Thread(target=self.query_systems) @@ -51,8 +50,7 @@ class AutoCompleter(Entry): if self.lb_up: self.has_selected = True self.var.set(self.lb.get(ACTIVE)) - self.lb.destroy() - self.lb_up = False + self.hide_list() self.icursor(END) def up(self): @@ -83,19 +81,30 @@ class AutoCompleter(Entry): self.query_systems() def show_results(self, results): - if results: - if not self.lb_up: - self.lb = Listbox(self.parent) - self.lb.place(x=self.winfo_x(), y=self.winfo_y()+self.winfo_height()) - self.lb_up = True - + if results: self.lb.delete(0, END) for w in results: self.lb.insert(END,w) + + sortedwords = sorted(results, key=len) + longestlen = len(sortedwords[-1]) + self.show_list(longestlen, len(results)) else: if self.lb_up: - self.lb.destroy() - self.lb_up = False + self.hide_list() + + def show_list(self, width, height): + self["width"] = width + self.lb["height"] = height + print(self.lb.size()) + if not self.lb_up: + self.lb.grid(row=self.grid_info()["row"]+1, columnspan=2) + self.lb_up = True + + def hide_list(self): + if self.lb_up: + self.lb.grid_remove() + self.lb_up = False def query_systems(self): inp = self.var.get() From c015c3628fc21ff1019344a157146e95b292b549 Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 00:03:51 +0200 Subject: [PATCH 04/18] Add placholder --- AutoCompleter.py | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/AutoCompleter.py b/AutoCompleter.py index a8a2a43..a5071ca 100755 --- a/AutoCompleter.py +++ b/AutoCompleter.py @@ -9,23 +9,33 @@ import os import requests class AutoCompleter(Entry): - def __init__(self, parent, **kwargs): + def __init__(self, parent, placeholder, **kw): + Entry.__init__(self, parent, **kw) self.parent = parent - Entry.__init__(self, parent, **kwargs) + self.placeholder = placeholder + self.placeholder_color = "grey" + self.default_fg_color = self['fg'] + + self.bind("", self.foc_in) + self.bind("", self.foc_out) + self.lb = Listbox(self.parent) self.lb_up = False self.has_selected = False self.queue = Queue.Queue() - self.var = self["textvariable"] - if self.var == '': - self.var = self["textvariable"] = StringVar() + self.var = self["textvariable"] = StringVar() self.var.trace('w', self.changed) + self.put_placeholder() self.bind("", self.keypressed) - + self.update_me() + def put_placeholder(self): + self['fg'] = self.placeholder_color + self.insert(0, self.placeholder) + def keypressed(self, event): key=event.keysym if key == 'Down': @@ -38,6 +48,15 @@ class AutoCompleter(Entry): elif key == 'Escape' and self.lb_up: self.hide_list() + def foc_in(self, *args): + if self['fg'] == self.placeholder_color or self.get() == self.placeholder: + self.delete('0', 'end') + self['fg'] = self.default_fg_color + + def foc_out(self, *args): + if not self.get(): + self.put_placeholder() + def changed(self, name, index, mode): if self.var.get().__len__() < 3 and self.lb_up or self.has_selected: self.hide_list @@ -108,7 +127,7 @@ class AutoCompleter(Entry): def query_systems(self): inp = self.var.get() - if inp.__len__() >= 3: + if inp != self.placeholder and inp.__len__() >= 3: url = "https://spansh.co.uk/api/systems?" results = requests.get(url, params={'q': inp}, @@ -138,6 +157,6 @@ class AutoCompleter(Entry): if __name__ == '__main__': root = Tk() - widget = AutoCompleter(root) + widget = AutoCompleter(root, "Test") widget.grid(row=0) root.mainloop() \ No newline at end of file From a671bdcb66324c0559690cc2bed84cb7de30774d Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 01:00:44 +0200 Subject: [PATCH 05/18] Add PlaceHolder class to use on an Entry widget --- AutoCompleter.py | 29 ++++++----------------------- PlaceHolder.py | 25 +++++++++++++++++++++++++ PlaceHolderEntry.py | 9 +++++++++ 3 files changed, 40 insertions(+), 23 deletions(-) create mode 100644 PlaceHolder.py create mode 100644 PlaceHolderEntry.py diff --git a/AutoCompleter.py b/AutoCompleter.py index a5071ca..3ba536e 100755 --- a/AutoCompleter.py +++ b/AutoCompleter.py @@ -7,35 +7,27 @@ from time import sleep import json import os import requests +from PlaceHolder import PlaceHolder -class AutoCompleter(Entry): +class AutoCompleter(Entry, PlaceHolder): def __init__(self, parent, placeholder, **kw): Entry.__init__(self, parent, **kw) - self.parent = parent - self.placeholder = placeholder - self.placeholder_color = "grey" - self.default_fg_color = self['fg'] + self.var = self["textvariable"] = StringVar() + self.var.trace('w', self.changed) - self.bind("", self.foc_in) - self.bind("", self.foc_out) + self.parent = parent self.lb = Listbox(self.parent) self.lb_up = False self.has_selected = False self.queue = Queue.Queue() - self.var = self["textvariable"] = StringVar() + PlaceHolder.__init__(self, placeholder) - self.var.trace('w', self.changed) - self.put_placeholder() self.bind("", self.keypressed) self.update_me() - def put_placeholder(self): - self['fg'] = self.placeholder_color - self.insert(0, self.placeholder) - def keypressed(self, event): key=event.keysym if key == 'Down': @@ -48,15 +40,6 @@ class AutoCompleter(Entry): elif key == 'Escape' and self.lb_up: self.hide_list() - def foc_in(self, *args): - if self['fg'] == self.placeholder_color or self.get() == self.placeholder: - self.delete('0', 'end') - self['fg'] = self.default_fg_color - - def foc_out(self, *args): - if not self.get(): - self.put_placeholder() - def changed(self, name, index, mode): if self.var.get().__len__() < 3 and self.lb_up or self.has_selected: self.hide_list diff --git a/PlaceHolder.py b/PlaceHolder.py new file mode 100644 index 0000000..c58b92e --- /dev/null +++ b/PlaceHolder.py @@ -0,0 +1,25 @@ +from config import config + +class PlaceHolder(): + def __init__(self, placeholder, **kw): + self.placeholder = placeholder + self.placeholder_color = "grey" + self.default_fg_color = config.get('dark_text') + + self.bind("", self.foc_in) + self.bind("", self.foc_out) + + self.put_placeholder() + + def put_placeholder(self): + self['fg'] = self.placeholder_color + self.insert(0, self.placeholder) + + def foc_in(self, *args): + if self['fg'] == self.placeholder_color or self.get() == self.placeholder: + self.delete('0', 'end') + self['fg'] = self.default_fg_color + + def foc_out(self, *args): + if not self.get(): + self.put_placeholder() diff --git a/PlaceHolderEntry.py b/PlaceHolderEntry.py new file mode 100644 index 0000000..fb58798 --- /dev/null +++ b/PlaceHolderEntry.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python2 + +from Tkinter import * +from PlaceHolder import PlaceHolder + +class PlaceHolderEntry(Entry, PlaceHolder): + def __init__(self, parent, placeholder, **kw): + Entry.__init__(self, parent, **kw) + PlaceHolder.__init__(self, placeholder) \ No newline at end of file From 93ae3f2290f484c635766496bae3dabedfff8a60 Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 12:12:32 +0200 Subject: [PATCH 06/18] Add placeholder color workaround --- PlaceHolder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/PlaceHolder.py b/PlaceHolder.py index c58b92e..6318e91 100644 --- a/PlaceHolder.py +++ b/PlaceHolder.py @@ -15,6 +15,9 @@ class PlaceHolder(): self['fg'] = self.placeholder_color self.insert(0, self.placeholder) + def force_placeholder_color(self): + self['fg'] = self.placeholder_color + def foc_in(self, *args): if self['fg'] == self.placeholder_color or self.get() == self.placeholder: self.delete('0', 'end') From 9a6082c0e2d2f5d78cdfbbd1982541bebfe670ea Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 12:13:13 +0200 Subject: [PATCH 07/18] Removed adaptive width as it was epileptic --- AutoCompleter.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/AutoCompleter.py b/AutoCompleter.py index 3ba536e..2c294c0 100755 --- a/AutoCompleter.py +++ b/AutoCompleter.py @@ -17,7 +17,7 @@ class AutoCompleter(Entry, PlaceHolder): self.parent = parent - self.lb = Listbox(self.parent) + self.lb = Listbox(self.parent, **kw) self.lb_up = False self.has_selected = False self.queue = Queue.Queue() @@ -42,7 +42,7 @@ class AutoCompleter(Entry, PlaceHolder): def changed(self, name, index, mode): if self.var.get().__len__() < 3 and self.lb_up or self.has_selected: - self.hide_list + self.hide_list() self.has_selected = False else: t = threading.Thread(target=self.query_systems) @@ -88,15 +88,12 @@ class AutoCompleter(Entry, PlaceHolder): for w in results: self.lb.insert(END,w) - sortedwords = sorted(results, key=len) - longestlen = len(sortedwords[-1]) - self.show_list(longestlen, len(results)) + self.show_list(len(results)) else: if self.lb_up: self.hide_list() - def show_list(self, width, height): - self["width"] = width + def show_list(self, height): self.lb["height"] = height print(self.lb.size()) if not self.lb_up: From 7df4070944f060c752e4c4b7dccadbcfae78ceba Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 12:23:30 +0200 Subject: [PATCH 08/18] Delete previous text when putting a placeholder --- PlaceHolder.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/PlaceHolder.py b/PlaceHolder.py index 6318e91..41c7061 100644 --- a/PlaceHolder.py +++ b/PlaceHolder.py @@ -1,4 +1,5 @@ from config import config +from Tkinter import END class PlaceHolder(): def __init__(self, placeholder, **kw): @@ -13,7 +14,9 @@ class PlaceHolder(): def put_placeholder(self): self['fg'] = self.placeholder_color - self.insert(0, self.placeholder) + if self.get() != self.placeholder: + self.delete(0, END) + self.insert(0, self.placeholder) def force_placeholder_color(self): self['fg'] = self.placeholder_color From 4bd6d1511eca52e1312032f50cb2ae2aeb743057 Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 12:27:18 +0200 Subject: [PATCH 09/18] Added GUI for plotting --- load.py | 94 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 18 deletions(-) diff --git a/load.py b/load.py index a55696b..6b602c3 100644 --- a/load.py +++ b/load.py @@ -1,14 +1,14 @@ import Tkinter as tk import tkFileDialog as filedialog import tkMessageBox as confirmDialog -from ttkHyperlinkLabel import HyperlinkLabel import sys import csv import os -from monitor import monitor import urllib import json import webbrowser +from AutoCompleter import AutoCompleter +from PlaceHolderEntry import PlaceHolderEntry if sys.platform.startswith('linux'): import subprocess @@ -109,7 +109,34 @@ def update_gui(): this.clear_route_btn.grid() +def show_plot_gui(show=True): + if show: + this.plot_gui_btn.grid_remove() + this.csv_route_btn.grid_remove() + this.source_ac.grid() + this.dest_ac.grid() + this.range_entry.grid() + this.efficiency_slider.grid() + this.plot_route_btn.grid() + this.cancel_plot.grid() + # Workaround because EDMC keeps switching the placeholder to bright white + this.source_ac.force_placeholder_color() + this.dest_ac.force_placeholder_color() + this.range_entry.force_placeholder_color() + + else: + this.source_ac.put_placeholder() + this.dest_ac.put_placeholder() + this.source_ac.grid_remove() + this.dest_ac.grid_remove() + this.range_entry.grid_remove() + this.efficiency_slider.grid_remove() + this.plot_gui_btn.grid_remove() + this.plot_route_btn.grid_remove() + this.cancel_plot.grid_remove() + this.plot_gui_btn.grid() + this.csv_route_btn.grid() def copy_waypoint(self=None): if sys.platform == "win32": @@ -128,7 +155,7 @@ def goto_prev_waypoint(self=None): if this.offset > 0: update_route(-1) -def new_route(self=None): +def plot_csv(self=None): filename = filedialog.askopenfilename(filetypes = (("csv files", "*.csv"),)) # show an "Open" dialog box and return the path to the selected file if filename.__len__() > 0: @@ -148,6 +175,9 @@ def new_route(self=None): copy_waypoint() update_gui() +def plot_route(self=None): + show_plot_gui(False) + def clear_route(self=None): clear = confirmDialog.askyesno("SpanshRouter","Are you sure you want to clear the current route?") @@ -166,7 +196,6 @@ def clear_route(self=None): update_gui() - def update_route(direction=1): if direction > 0: this.jumps_left -= int(this.route[this.offset][1]) @@ -183,7 +212,6 @@ def update_route(direction=1): update_gui() copy_waypoint(this.parent) - def journal_entry(cmdr, is_beta, system, station, entry, state): if (entry['event'] == 'FSDJump' or entry['event'] == 'Location') and entry["StarSystem"] == this.next_stop: update_route() @@ -192,30 +220,59 @@ def journal_entry(cmdr, is_beta, system, station, entry, state): elif entry['event'] == 'FSSDiscoveryScan' and entry['SystemName'] == this.next_stop: update_route() - def goto_update_page(self=None): webbrowser.open('https://github.com/CMDR-Kiel42/EDMC_SpanshRouter/releases') - def plugin_app(parent): this.parent = parent - this.frame = tk.Frame(parent) - + parentwidth = parent.winfo_width() + this.frame = tk.Frame(parent, borderwidth=2) + this.frame.grid(sticky=tk.NSEW) + + # Route info this.waypoint_prev_btn = tk.Button(this.frame, text="^", command=goto_prev_waypoint) this.waypoint_btn = tk.Button(this.frame, text=this.next_wp_label + this.next_stop, command=copy_waypoint) this.waypoint_next_btn = tk.Button(this.frame, text="v", command=goto_next_waypoint) + this.jumpcounttxt_lbl = tk.Label(this.frame, text=this.jumpcountlbl_txt + str(this.jumps_left)) - this.upload_route_btn = tk.Button(this.frame, text="Upload new route", command=new_route) + # Plotting GUI + this.source_ac = AutoCompleter(this.frame, "Source System", width=30) + this.dest_ac = AutoCompleter(this.frame, "Destination System", width=30) + this.range_entry = PlaceHolderEntry(this.frame, "Range (LY)", width=10) + this.efficiency_slider = tk.Scale(this.frame, from_=1, to=100, orient=tk.HORIZONTAL, label="Efficiency (%)") + this.plot_gui_btn = tk.Button(this.frame, text="Plot route", command=show_plot_gui) + this.plot_route_btn = tk.Button(this.frame, text="Calculate", command=plot_route) + this.cancel_plot = tk.Button(this.frame, text="Cancel", command=lambda: show_plot_gui(False)) + + this.csv_route_btn = tk.Button(this.frame, text="Import CSV", command=plot_csv) this.clear_route_btn = tk.Button(this.frame, text="Clear route", command=clear_route) - this.waypoint_prev_btn.grid(row=0, columnspan=2) - this.waypoint_btn.grid(row=1, columnspan=2) - this.waypoint_next_btn.grid(row=2, columnspan=2) - this.upload_route_btn.grid(row=3, pady=10, padx=0) - this.clear_route_btn.grid(row=3,column=1) + row = 0 + this.waypoint_prev_btn.grid(row=row, columnspan=2) + row += 1 + this.waypoint_btn.grid(row=row, columnspan=2) + row += 1 + this.waypoint_next_btn.grid(row=row, columnspan=2) + row += 1 + this.source_ac.grid(row=row,columnspan=2, pady=(10,0)) # The AutoCompleter takes two rows to show the list when needed, so we skip one + row += 2 + this.dest_ac.grid(row=row,columnspan=2, pady=(10,0)) + row += 2 + this.range_entry.grid(row=row, pady=10, sticky=tk.W) + row += 1 + this.efficiency_slider.grid(row=row, pady=10, columnspan=2, sticky=tk.EW) + row += 1 + this.csv_route_btn.grid(row=row, pady=10, padx=0) + this.plot_route_btn.grid(row=row, pady=10, padx=0) + this.plot_gui_btn.grid(row=row, column=1, pady=10, padx=5, sticky=tk.W) + this.cancel_plot.grid(row=row, column=1, pady=10, padx=5, sticky=tk.E) + row += 1 + this.clear_route_btn.grid(row=row,column=1) + row += 1 + this.jumpcounttxt_lbl.grid(row=row, pady=5, sticky=tk.W) + row += 1 - this.jumpcounttxt_lbl = tk.Label(this.frame, text=this.jumpcountlbl_txt + str(this.jumps_left)) - this.jumpcounttxt_lbl.grid(row=4, pady=5, sticky=tk.W) + show_plot_gui(False) if not this.route.__len__() > 0: this.waypoint_prev_btn.grid_remove() @@ -226,7 +283,8 @@ def plugin_app(parent): if this.update_available: this.update_btn = tk.Button(this.frame, text="SpanshRouter update available for download!", command=goto_update_page) - this.update_btn.grid(row=5, pady=5, columnspan=2) + this.update_btn.grid(row=row, pady=5, columnspan=2) + row += 1 update_gui() From de7deb87bcba3bf543170516df4d3bbe19db9dbb Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 12:43:03 +0200 Subject: [PATCH 10/18] Removed useless print statement --- AutoCompleter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/AutoCompleter.py b/AutoCompleter.py index 2c294c0..898cbcc 100755 --- a/AutoCompleter.py +++ b/AutoCompleter.py @@ -95,7 +95,6 @@ class AutoCompleter(Entry, PlaceHolder): def show_list(self, height): self.lb["height"] = height - print(self.lb.size()) if not self.lb_up: self.lb.grid(row=self.grid_info()["row"]+1, columnspan=2) self.lb_up = True From 54fbdf502ead5f2606ad9566b5ce97b6e89b5f0a Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 13:06:45 +0200 Subject: [PATCH 11/18] Bind double click on Systems list --- AutoCompleter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/AutoCompleter.py b/AutoCompleter.py index 898cbcc..f2ee70d 100755 --- a/AutoCompleter.py +++ b/AutoCompleter.py @@ -25,6 +25,7 @@ class AutoCompleter(Entry, PlaceHolder): PlaceHolder.__init__(self, placeholder) self.bind("", self.keypressed) + self.lb.bind("", self.selection) self.update_me() From 565f47a4ae1534bc5393ebce7a11452675ed3670 Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 13:12:59 +0200 Subject: [PATCH 12/18] Support Ctrl+A --- AutoCompleter.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AutoCompleter.py b/AutoCompleter.py index f2ee70d..cb8ee24 100755 --- a/AutoCompleter.py +++ b/AutoCompleter.py @@ -25,6 +25,7 @@ class AutoCompleter(Entry, PlaceHolder): PlaceHolder.__init__(self, placeholder) self.bind("", self.keypressed) + self.bind('', self.select_all) self.lb.bind("", self.selection) self.update_me() @@ -40,6 +41,9 @@ class AutoCompleter(Entry, PlaceHolder): self.selection() elif key == 'Escape' and self.lb_up: self.hide_list() + + def select_all(self, event): + event.widget.event_generate('<>') def changed(self, name, index, mode): if self.var.get().__len__() < 3 and self.lb_up or self.has_selected: From 0ce5ddb729c6dea66b1e6b7869f9c1e81a564e1e Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 13:49:04 +0200 Subject: [PATCH 13/18] Query route from Spansh --- load.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/load.py b/load.py index 6b602c3..b6779f1 100644 --- a/load.py +++ b/load.py @@ -7,6 +7,7 @@ import os import urllib import json import webbrowser +import requests from AutoCompleter import AutoCompleter from PlaceHolderEntry import PlaceHolderEntry @@ -176,7 +177,58 @@ def plot_csv(self=None): update_gui() def plot_route(self=None): - show_plot_gui(False) + try: + source = this.source_ac.get() + dest = this.dest_ac.get() + efficiency = this.efficiency_slider.get() + + if ( source and source != this.source_ac.placeholder and + dest and dest != this.dest_ac.placeholder ): + range_ly = float(this.range_entry.get()) + + job_url="https://spansh.co.uk/api/route?" + + results = requests.post(job_url, params={ + "efficiency": efficiency, + "range": range_ly, + "from": source, + "to": dest + }, headers={'User-Agent': "EDMC_SpanshRouter 1.0"}) + + if results.status_code == 202: + this.source_ac.config(state=tk.DISABLED) + this.source_ac.update_idletasks() + this.dest_ac.config(state=tk.DISABLED) + this.dest_ac.update_idletasks() + this.efficiency_slider.config(state=tk.DISABLED) + this.efficiency_slider.update_idletasks() + this.range_entry.config(state=tk.DISABLED) + this.range_entry.update_idletasks() + this.plot_route_btn.config(state=tk.DISABLED, text="Computing...") + this.plot_route_btn.update_idletasks() + this.cancel_plot.config(state=tk.DISABLED) + this.cancel_plot.update_idletasks() + + while(True): + response = json.loads(results.content) + job = response["job"] + + results_url = "https://spansh.co.uk/api/results/" + job + route_response = requests.get(results_url) + if route_response.status_code != 202: + break + + if route_response.status_code == 200: + route = json.loads(route_response.content) + print(route) + show_plot_gui(False) + else: + sys.stderr.write("Failed to query plotted route from Spansh: code " + str(route_response.status_code) + route_response.text) + else: + sys.stderr.write("Failed to query route from Spansh: code " + str(results.status_code) + results.text) + + except: + pass def clear_route(self=None): clear = confirmDialog.askyesno("SpanshRouter","Are you sure you want to clear the current route?") @@ -240,6 +292,7 @@ def plugin_app(parent): this.dest_ac = AutoCompleter(this.frame, "Destination System", width=30) this.range_entry = PlaceHolderEntry(this.frame, "Range (LY)", width=10) this.efficiency_slider = tk.Scale(this.frame, from_=1, to=100, orient=tk.HORIZONTAL, label="Efficiency (%)") + this.efficiency_slider.set(60) this.plot_gui_btn = tk.Button(this.frame, text="Plot route", command=show_plot_gui) this.plot_route_btn = tk.Button(this.frame, text="Calculate", command=plot_route) this.cancel_plot = tk.Button(this.frame, text="Cancel", command=lambda: show_plot_gui(False)) From a1fb3e3e5802d2ec3701e82e10db334058909c35 Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 14:23:26 +0200 Subject: [PATCH 14/18] Actually plot route from Spansh --- load.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/load.py b/load.py index b6779f1..5fe6eb9 100644 --- a/load.py +++ b/load.py @@ -219,9 +219,18 @@ def plot_route(self=None): break if route_response.status_code == 200: - route = json.loads(route_response.content) - print(route) + route = json.loads(route_response.content)["result"]["system_jumps"] + + this.jumps_left = 0 + for waypoint in route: + this.route.append([waypoint["system"], str(waypoint["jumps"])]) + this.jumps_left += waypoint["jumps"] + show_plot_gui(False) + this.offset = 0 + this.next_stop = this.route[0][0] + copy_waypoint() + update_gui() else: sys.stderr.write("Failed to query plotted route from Spansh: code " + str(route_response.status_code) + route_response.text) else: From 15f1f2bd84660f8832c46b59823f9d6d3837540e Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 15:24:10 +0200 Subject: [PATCH 15/18] Update GUI --- load.py | 69 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/load.py b/load.py index 5fe6eb9..d1ca480 100644 --- a/load.py +++ b/load.py @@ -82,8 +82,8 @@ def plugin_stop(): print("No route to delete") -def update_gui(): - if not this.route.__len__() > 0: +def show_route_gui(show): + if not show or not this.route.__len__() > 0: this.waypoint_prev_btn.grid_remove() this.waypoint_btn.grid_remove() this.waypoint_next_btn.grid_remove() @@ -109,9 +109,18 @@ def update_gui(): this.waypoint_next_btn.config(state=tk.NORMAL) this.clear_route_btn.grid() - + +def update_gui(): + show_route_gui(True) + def show_plot_gui(show=True): if show: + this.waypoint_prev_btn.grid_remove() + this.waypoint_btn.grid_remove() + this.waypoint_next_btn.grid_remove() + this.jumpcounttxt_lbl.grid_remove() + this.clear_route_btn.grid_remove() + this.plot_gui_btn.grid_remove() this.csv_route_btn.grid_remove() this.source_ac.grid() @@ -125,6 +134,7 @@ def show_plot_gui(show=True): this.source_ac.force_placeholder_color() this.dest_ac.force_placeholder_color() this.range_entry.force_placeholder_color() + show_route_gui(False) else: this.source_ac.put_placeholder() @@ -138,6 +148,7 @@ def show_plot_gui(show=True): this.cancel_plot.grid_remove() this.plot_gui_btn.grid() this.csv_route_btn.grid() + show_route_gui(True) def copy_waypoint(self=None): if sys.platform == "win32": @@ -176,6 +187,34 @@ def plot_csv(self=None): copy_waypoint() update_gui() +def enable_plot_gui(enable): + if enable: + this.source_ac.config(state=tk.NORMAL) + this.source_ac.update_idletasks() + this.dest_ac.config(state=tk.NORMAL) + this.dest_ac.update_idletasks() + this.efficiency_slider.config(state=tk.NORMAL) + this.efficiency_slider.update_idletasks() + this.range_entry.config(state=tk.NORMAL) + this.range_entry.update_idletasks() + this.plot_route_btn.config(state=tk.NORMAL, text="Calculate") + this.plot_route_btn.update_idletasks() + this.cancel_plot.config(state=tk.NORMAL) + this.cancel_plot.update_idletasks() + else: + this.source_ac.config(state=tk.DISABLED) + this.source_ac.update_idletasks() + this.dest_ac.config(state=tk.DISABLED) + this.dest_ac.update_idletasks() + this.efficiency_slider.config(state=tk.DISABLED) + this.efficiency_slider.update_idletasks() + this.range_entry.config(state=tk.DISABLED) + this.range_entry.update_idletasks() + this.plot_route_btn.config(state=tk.DISABLED, text="Computing...") + this.plot_route_btn.update_idletasks() + this.cancel_plot.config(state=tk.DISABLED) + this.cancel_plot.update_idletasks() + def plot_route(self=None): try: source = this.source_ac.get() @@ -196,18 +235,7 @@ def plot_route(self=None): }, headers={'User-Agent': "EDMC_SpanshRouter 1.0"}) if results.status_code == 202: - this.source_ac.config(state=tk.DISABLED) - this.source_ac.update_idletasks() - this.dest_ac.config(state=tk.DISABLED) - this.dest_ac.update_idletasks() - this.efficiency_slider.config(state=tk.DISABLED) - this.efficiency_slider.update_idletasks() - this.range_entry.config(state=tk.DISABLED) - this.range_entry.update_idletasks() - this.plot_route_btn.config(state=tk.DISABLED, text="Computing...") - this.plot_route_btn.update_idletasks() - this.cancel_plot.config(state=tk.DISABLED) - this.cancel_plot.update_idletasks() + enable_plot_gui(False) while(True): response = json.loads(results.content) @@ -220,12 +248,11 @@ def plot_route(self=None): if route_response.status_code == 200: route = json.loads(route_response.content)["result"]["system_jumps"] - - this.jumps_left = 0 + clear_route(show_dialog=False) for waypoint in route: this.route.append([waypoint["system"], str(waypoint["jumps"])]) this.jumps_left += waypoint["jumps"] - + enable_plot_gui(True) show_plot_gui(False) this.offset = 0 this.next_stop = this.route[0][0] @@ -239,13 +266,15 @@ def plot_route(self=None): except: pass -def clear_route(self=None): - clear = confirmDialog.askyesno("SpanshRouter","Are you sure you want to clear the current route?") +def clear_route(self=None, show_dialog=True): + print("Show dialog =" + str(show_dialog)) + clear = confirmDialog.askyesno("SpanshRouter","Are you sure you want to clear the current route?") if show_dialog else True if clear: this.offset = 0 this.route = [] this.next_waypoint = "" + this.jumps_left = 0 try: os.remove(this.save_route_path) except: From 38b27c25792651a68cfeaa4b7df3a417a42d6235 Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 20:31:10 +0200 Subject: [PATCH 16/18] Prefill the source system --- AutoCompleter.py | 1 - load.py | 13 ++++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/AutoCompleter.py b/AutoCompleter.py index cb8ee24..0351f75 100755 --- a/AutoCompleter.py +++ b/AutoCompleter.py @@ -132,7 +132,6 @@ class AutoCompleter(Entry, PlaceHolder): while 1: lista = self.queue.get_nowait() self.show_results(lista) - self.update_idletasks() except Queue.Empty: pass diff --git a/load.py b/load.py index d1ca480..3f05e85 100644 --- a/load.py +++ b/load.py @@ -131,9 +131,12 @@ def show_plot_gui(show=True): this.cancel_plot.grid() # Workaround because EDMC keeps switching the placeholder to bright white - this.source_ac.force_placeholder_color() - this.dest_ac.force_placeholder_color() - this.range_entry.force_placeholder_color() + if this.source_ac.get() == this.source_ac.placeholder: + this.source_ac.force_placeholder_color() + if this.dest_ac.get() == this.dest_ac.placeholder: + this.dest_ac.force_placeholder_color() + if this.range_entry.get() == this.range_entry.placeholder: + this.range_entry.force_placeholder_color() show_route_gui(False) else: @@ -303,6 +306,10 @@ def update_route(direction=1): copy_waypoint(this.parent) def journal_entry(cmdr, is_beta, system, station, entry, state): + if entry["StarSystem"]: + this.source_ac.delete(0, tk.END) + this.source_ac.insert(0, entry["StarSystem"]) + this.source_ac["fg"] = this.source_ac.default_fg_color if (entry['event'] == 'FSDJump' or entry['event'] == 'Location') and entry["StarSystem"] == this.next_stop: update_route() elif entry['event'] in ['SupercruiseEntry', 'SupercruiseExit'] and entry['StarSystem'] == this.next_stop: From 0ca039b22e4ad3cd62b638a78b0a23accd3f0ae2 Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 20:41:40 +0200 Subject: [PATCH 17/18] update ReadMe --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 2f0d23a..fb1cf26 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,22 @@ # EDMC_SpanshRouter -This plugin's purpose is to automatically copy to your clipboard the next waypoint on a route you planned using [Spansh](https://www.spansh.co.uk/plotter). +This plugin's purpose is to automatically copy to your clipboard the next waypoint on a route you planned using [Spansh](https://www.spansh.co.uk/plotter). ## Install - Download the latest release [here](https://github.com/CMDR-Kiel42/EDMC_SpanshRouter/releases) and unzip it. - Open your EDMC plugins folder - in EDMC settings, select "Plugins" tab, click the "Open" button. - Create a folder inside the plugins folder called **SpanshRouter** -- Open the **SpanshRouter** folder and put **load.py** inside. +- Open the **SpanshRouter** folder and put all the files you extracted inside. - Restart EDMC - ## How to use -- Once you've plotted your route on [Spansh](https://www.spansh.co.uk/plotter), download the CSV file that it generates -- On EDMC, click the **Upload new route** button and choose your file -- The next waypoint is now copied into your clipboard! Simply paste it into your Galaxy Map, and *voilĂ *! +You can either plot your route directly from EDMC, or you can import a CSV file from [Spansh](https://www.spansh.co.uk/plotter) -Once you reach your next waypoint, the plugin will automatically update your clipboard, so you just need to go to your Galaxy Map and paste it everytime you reach a waypoint. +Once your route is plotted, and every time you reach a waypoint, the next one is automatically copied to your clipboard. + +You just need to go to your Galaxy Map and paste it everytime you reach a waypoint. If for some reason, your clipboard should be empty or containing other stuff that you copied yourself, just click on the **Next waypoint** button, and the waypoint will be copied again to your clipboard. @@ -25,10 +24,11 @@ If you close EDMC, the plugin will save your progress. The next time you run EDM Fly dangerous! o7 - ## Known Issues + At the moment, plotting a route while the game is running, and which begins from the system you're currently in, doesn't update your "next waypoint". If you're in that situation, a couple of solutions are available: -* Performing a FSS Discovery Scan -* Go in our out of Supercruise -* Logging back in and out while EDMC is already running. +- Using the **down** button below the **Next waypoint** +- Performing a FSS Discovery Scan +- Go in our out of Supercruise +- Logging back in and out while EDMC is already running. From dd7deef9fcdf44668487cf2234d6ec5f3bfd5b9f Mon Sep 17 00:00:00 2001 From: CMDR-Kiel42 Date: Wed, 17 Jul 2019 20:46:59 +0200 Subject: [PATCH 18/18] Update plugin version and changelog --- CHANGELOG.md | 5 +++++ load.py | 2 +- version.json | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d7e74f..2e61208 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. +## 2.0.0 + +- You can now plot your route directly from EDMC +- A few bugs were fixed + ## 1.2.1 - Added update button which opens the releases page diff --git a/load.py b/load.py index 3f05e85..a013963 100644 --- a/load.py +++ b/load.py @@ -16,7 +16,7 @@ if sys.platform.startswith('linux'): this = sys.modules[__name__] -this.plugin_version = "1.2.1" +this.plugin_version = "2.0.0" this.update_available = False this.next_stop = "No route planned" this.route = [] diff --git a/version.json b/version.json index cb174d5..359a5b9 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -1.2.1 \ No newline at end of file +2.0.0 \ No newline at end of file