Merge pull request #5 from CMDR-Kiel42/plot_from_EDMC

Plot from edmc
This commit is contained in:
CMDR-Kiel42 2019-07-17 20:51:40 +02:00 committed by GitHub
commit 40ad5e6a69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 382 additions and 36 deletions

145
AutoCompleter.py Executable file
View File

@ -0,0 +1,145 @@
#!/usr/bin/env python2
from Tkinter import *
import threading
import Queue
from time import sleep
import json
import os
import requests
from PlaceHolder import PlaceHolder
class AutoCompleter(Entry, PlaceHolder):
def __init__(self, parent, placeholder, **kw):
Entry.__init__(self, parent, **kw)
self.var = self["textvariable"] = StringVar()
self.var.trace('w', self.changed)
self.parent = parent
self.lb = Listbox(self.parent, **kw)
self.lb_up = False
self.has_selected = False
self.queue = Queue.Queue()
PlaceHolder.__init__(self, placeholder)
self.bind("<Any-Key>", self.keypressed)
self.bind('<Control-KeyRelease-a>', self.select_all)
self.lb.bind("<Double-Button-1>", self.selection)
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']:
if self.lb_up:
self.selection()
elif key == 'Escape' and self.lb_up:
self.hide_list()
def select_all(self, event):
event.widget.event_generate('<<SelectAll>>')
def changed(self, name, index, mode):
if self.var.get().__len__() < 3 and self.lb_up or self.has_selected:
self.hide_list()
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.hide_list()
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)
else:
self.query_systems()
def show_results(self, results):
if results:
self.lb.delete(0, END)
for w in results:
self.lb.insert(END,w)
self.show_list(len(results))
else:
if self.lb_up:
self.hide_list()
def show_list(self, height):
self.lb["height"] = height
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()
if inp != self.placeholder and 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)
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, "Test")
widget.grid(row=0)
root.mainloop()

View File

@ -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

31
PlaceHolder.py Normal file
View File

@ -0,0 +1,31 @@
from config import config
from Tkinter import END
class PlaceHolder():
def __init__(self, placeholder, **kw):
self.placeholder = placeholder
self.placeholder_color = "grey"
self.default_fg_color = config.get('dark_text')
self.bind("<FocusIn>", self.foc_in)
self.bind("<FocusOut>", self.foc_out)
self.put_placeholder()
def put_placeholder(self):
self['fg'] = self.placeholder_color
if self.get() != self.placeholder:
self.delete(0, END)
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')
self['fg'] = self.default_fg_color
def foc_out(self, *args):
if not self.get():
self.put_placeholder()

9
PlaceHolderEntry.py Normal file
View File

@ -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)

View File

@ -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.

204
load.py
View File

@ -1,21 +1,22 @@
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
import requests
from AutoCompleter import AutoCompleter
from PlaceHolderEntry import PlaceHolderEntry
if sys.platform.startswith('linux'):
import subprocess
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 = []
@ -81,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()
@ -108,8 +109,49 @@ 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()
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
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:
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()
show_route_gui(True)
def copy_waypoint(self=None):
if sys.platform == "win32":
@ -128,7 +170,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,13 +190,94 @@ def new_route(self=None):
copy_waypoint()
update_gui()
def clear_route(self=None):
clear = confirmDialog.askyesno("SpanshRouter","Are you sure you want to clear the current route?")
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()
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:
enable_plot_gui(False)
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)["result"]["system_jumps"]
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]
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:
sys.stderr.write("Failed to query route from Spansh: code " + str(results.status_code) + results.text)
except:
pass
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:
@ -166,7 +289,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,8 +305,11 @@ def update_route(direction=1):
update_gui()
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:
@ -192,30 +317,60 @@ 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.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))
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 +381,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()

View File

@ -1 +1 @@
1.2.1
2.0.0