mirror of
https://github.com/norohind/EDMC_SpanshRouter.git
synced 2025-04-19 18:47:36 +03:00
commit
40ad5e6a69
145
AutoCompleter.py
Executable file
145
AutoCompleter.py
Executable 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()
|
@ -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
31
PlaceHolder.py
Normal 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
9
PlaceHolderEntry.py
Normal 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)
|
22
README.md
22
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.
|
||||
|
204
load.py
204
load.py
@ -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()
|
||||
|
||||
|
@ -1 +1 @@
|
||||
1.2.1
|
||||
2.0.0
|
Loading…
x
Reference in New Issue
Block a user