From 6e562fbb2599968f2d9080df765d8edfa3d3eb13 Mon Sep 17 00:00:00 2001 From: Isvvc Date: Thu, 17 Dec 2020 11:50:46 -0700 Subject: [PATCH 01/20] Create pipenv with PySimpleGUI example --- Armor Export/Pipfile | 12 ++++++++++++ Armor Export/Pipfile.lock | 29 +++++++++++++++++++++++++++++ Armor Export/src/Armor_Export.py | 23 +++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 Armor Export/Pipfile create mode 100644 Armor Export/Pipfile.lock create mode 100644 Armor Export/src/Armor_Export.py diff --git a/Armor Export/Pipfile b/Armor Export/Pipfile new file mode 100644 index 0000000..082d86b --- /dev/null +++ b/Armor Export/Pipfile @@ -0,0 +1,12 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +pysimplegui = "*" + +[dev-packages] + +[requires] +python_version = "3.8" diff --git a/Armor Export/Pipfile.lock b/Armor Export/Pipfile.lock new file mode 100644 index 0000000..0bcdd51 --- /dev/null +++ b/Armor Export/Pipfile.lock @@ -0,0 +1,29 @@ +{ + "_meta": { + "hash": { + "sha256": "4ff84e24091ab701f31d2314e77df8e5cbeb13c2c8f2c99fb19493a3fbc1400c" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.8" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "pysimplegui": { + "hashes": [ + "sha256:641431980a020159e4b1b4a425202560abf616b4de523d9b7476ff228b69b694", + "sha256:7132066ac7e365718e3025daa578cd3b229507164c6d80829405c9293adc6935" + ], + "index": "pypi", + "version": "==4.32.1" + } + }, + "develop": {} +} diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/src/Armor_Export.py new file mode 100644 index 0000000..d0f69b7 --- /dev/null +++ b/Armor Export/src/Armor_Export.py @@ -0,0 +1,23 @@ +import PySimpleGUI as sg + +# Define the window's contents +layout = [[sg.Text("What's your name?")], + [sg.Input(key='-INPUT-')], + [sg.Text(size=(40,1), key='-OUTPUT-')], + [sg.Button('OK'), sg.Button('Quit')]] + +# Create the window +window = sg.Window('Window Title', layout) + +# Display and interact with the Window using an Event Loop +while True: + event, values = window.read() + # See if user wants to quit or window was closed + if event == sg.WINDOW_CLOSED or event == 'Quit': + break + # Output a message to the window + window['-OUTPUT-'].update('Hello ' + values['-INPUT-'] + "! Thanks for trying PySimpleGUI") + +# Finish up by removing from the screen +window.close() + From b88c69ded906ebd12e46ebd4d2b678c72e6192b1 Mon Sep 17 00:00:00 2001 From: Isvvc Date: Thu, 17 Dec 2020 12:52:48 -0700 Subject: [PATCH 02/20] Add modified MyQR as dependency --- Armor Export/Pipfile | 1 + Armor Export/Pipfile.lock | 88 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/Armor Export/Pipfile b/Armor Export/Pipfile index 082d86b..c6055d7 100644 --- a/Armor Export/Pipfile +++ b/Armor Export/Pipfile @@ -5,6 +5,7 @@ name = "pypi" [packages] pysimplegui = "*" +myqr = {editable = true, git = "https://github.com/Isvvc/qrcode.git"} [dev-packages] diff --git a/Armor Export/Pipfile.lock b/Armor Export/Pipfile.lock index 0bcdd51..c8bc36e 100644 --- a/Armor Export/Pipfile.lock +++ b/Armor Export/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "4ff84e24091ab701f31d2314e77df8e5cbeb13c2c8f2c99fb19493a3fbc1400c" + "sha256": "61620181327f4e36a86687164b06888f555d859d10779741c8bbc3a71780a0ce" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,92 @@ ] }, "default": { + "imageio": { + "hashes": [ + "sha256:3604d751f03002e8e0e7650aa71d8d9148144a87daf17cb1f3228e80747f2e6b", + "sha256:52ddbaeca2dccf53ba2d6dec5676ca7bc3b2403ef8b37f7da78b7654bb3e10f0" + ], + "version": "==2.9.0" + }, + "myqr": { + "editable": true, + "git": "https://github.com/Isvvc/qrcode.git", + "ref": "79dc6ec85767edcc63d1d9f29f31c8f7bf731633" + }, + "numpy": { + "hashes": [ + "sha256:08308c38e44cc926bdfce99498b21eec1f848d24c302519e64203a8da99a97db", + "sha256:09c12096d843b90eafd01ea1b3307e78ddd47a55855ad402b157b6c4862197ce", + "sha256:13d166f77d6dc02c0a73c1101dd87fdf01339febec1030bd810dcd53fff3b0f1", + "sha256:141ec3a3300ab89c7f2b0775289954d193cc8edb621ea05f99db9cb181530512", + "sha256:16c1b388cc31a9baa06d91a19366fb99ddbe1c7b205293ed072211ee5bac1ed2", + "sha256:18bed2bcb39e3f758296584337966e68d2d5ba6aab7e038688ad53c8f889f757", + "sha256:1aeef46a13e51931c0b1cf8ae1168b4a55ecd282e6688fdb0a948cc5a1d5afb9", + "sha256:27d3f3b9e3406579a8af3a9f262f5339005dd25e0ecf3cf1559ff8a49ed5cbf2", + "sha256:2a2740aa9733d2e5b2dfb33639d98a64c3b0f24765fed86b0fd2aec07f6a0a08", + "sha256:4377e10b874e653fe96985c05feed2225c912e328c8a26541f7fc600fb9c637b", + "sha256:448ebb1b3bf64c0267d6b09a7cba26b5ae61b6d2dbabff7c91b660c7eccf2bdb", + "sha256:50e86c076611212ca62e5a59f518edafe0c0730f7d9195fec718da1a5c2bb1fc", + "sha256:5734bdc0342aba9dfc6f04920988140fb41234db42381cf7ccba64169f9fe7ac", + "sha256:64324f64f90a9e4ef732be0928be853eee378fd6a01be21a0a8469c4f2682c83", + "sha256:6ae6c680f3ebf1cf7ad1d7748868b39d9f900836df774c453c11c5440bc15b36", + "sha256:6d7593a705d662be5bfe24111af14763016765f43cb6923ed86223f965f52387", + "sha256:8cac8790a6b1ddf88640a9267ee67b1aee7a57dfa2d2dd33999d080bc8ee3a0f", + "sha256:8ece138c3a16db8c1ad38f52eb32be6086cc72f403150a79336eb2045723a1ad", + "sha256:9eeb7d1d04b117ac0d38719915ae169aa6b61fca227b0b7d198d43728f0c879c", + "sha256:a09f98011236a419ee3f49cedc9ef27d7a1651df07810ae430a6b06576e0b414", + "sha256:a5d897c14513590a85774180be713f692df6fa8ecf6483e561a6d47309566f37", + "sha256:ad6f2ff5b1989a4899bf89800a671d71b1612e5ff40866d1f4d8bcf48d4e5764", + "sha256:c42c4b73121caf0ed6cd795512c9c09c52a7287b04d105d112068c1736d7c753", + "sha256:cb1017eec5257e9ac6209ac172058c430e834d5d2bc21961dceeb79d111e5909", + "sha256:d6c7bb82883680e168b55b49c70af29b84b84abb161cbac2800e8fcb6f2109b6", + "sha256:e452dc66e08a4ce642a961f134814258a082832c78c90351b75c41ad16f79f63", + "sha256:e5b6ed0f0b42317050c88022349d994fe72bfe35f5908617512cd8c8ef9da2a9", + "sha256:e9b30d4bd69498fc0c3fe9db5f62fffbb06b8eb9321f92cc970f2969be5e3949", + "sha256:ec149b90019852266fec2341ce1db513b843e496d5a8e8cdb5ced1923a92faab", + "sha256:edb01671b3caae1ca00881686003d16c2209e07b7ef8b7639f1867852b948f7c", + "sha256:f0d3929fe88ee1c155129ecd82f981b8856c5d97bcb0d5f23e9b4242e79d1de3", + "sha256:f29454410db6ef8126c83bd3c968d143304633d45dc57b51252afbd79d700893", + "sha256:fe45becb4c2f72a0907c1d0246ea6449fe7a9e2293bb0e11c4e9a32bb0930a15", + "sha256:fedbd128668ead37f33917820b704784aff695e0019309ad446a6d0b065b57e4" + ], + "markers": "python_version >= '3.6'", + "version": "==1.19.4" + }, + "pillow": { + "hashes": [ + "sha256:006de60d7580d81f4a1a7e9f0173dc90a932e3905cc4d47ea909bc946302311a", + "sha256:0a2e8d03787ec7ad71dc18aec9367c946ef8ef50e1e78c71f743bc3a770f9fae", + "sha256:0eeeae397e5a79dc088d8297a4c2c6f901f8fb30db47795113a4a605d0f1e5ce", + "sha256:11c5c6e9b02c9dac08af04f093eb5a2f84857df70a7d4a6a6ad461aca803fb9e", + "sha256:2fb113757a369a6cdb189f8df3226e995acfed0a8919a72416626af1a0a71140", + "sha256:4b0ef2470c4979e345e4e0cc1bbac65fda11d0d7b789dbac035e4c6ce3f98adb", + "sha256:59e903ca800c8cfd1ebe482349ec7c35687b95e98cefae213e271c8c7fffa021", + "sha256:5abd653a23c35d980b332bc0431d39663b1709d64142e3652890df4c9b6970f6", + "sha256:5f9403af9c790cc18411ea398a6950ee2def2a830ad0cfe6dc9122e6d528b302", + "sha256:6b4a8fd632b4ebee28282a9fef4c341835a1aa8671e2770b6f89adc8e8c2703c", + "sha256:6c1aca8231625115104a06e4389fcd9ec88f0c9befbabd80dc206c35561be271", + "sha256:795e91a60f291e75de2e20e6bdd67770f793c8605b553cb6e4387ce0cb302e09", + "sha256:7ba0ba61252ab23052e642abdb17fd08fdcfdbbf3b74c969a30c58ac1ade7cd3", + "sha256:7c9401e68730d6c4245b8e361d3d13e1035cbc94db86b49dc7da8bec235d0015", + "sha256:81f812d8f5e8a09b246515fac141e9d10113229bc33ea073fec11403b016bcf3", + "sha256:895d54c0ddc78a478c80f9c438579ac15f3e27bf442c2a9aa74d41d0e4d12544", + "sha256:8de332053707c80963b589b22f8e0229f1be1f3ca862a932c1bcd48dafb18dd8", + "sha256:92c882b70a40c79de9f5294dc99390671e07fc0b0113d472cbea3fde15db1792", + "sha256:95edb1ed513e68bddc2aee3de66ceaf743590bf16c023fb9977adc4be15bd3f0", + "sha256:b63d4ff734263ae4ce6593798bcfee6dbfb00523c82753a3a03cbc05555a9cc3", + "sha256:bd7bf289e05470b1bc74889d1466d9ad4a56d201f24397557b6f65c24a6844b8", + "sha256:cc3ea6b23954da84dbee8025c616040d9aa5eaf34ea6895a0a762ee9d3e12e11", + "sha256:cc9ec588c6ef3a1325fa032ec14d97b7309db493782ea8c304666fb10c3bd9a7", + "sha256:d3d07c86d4efa1facdf32aa878bd508c0dc4f87c48125cc16b937baa4e5b5e11", + "sha256:d8a96747df78cda35980905bf26e72960cba6d355ace4780d4bdde3b217cdf1e", + "sha256:e38d58d9138ef972fceb7aeec4be02e3f01d383723965bfcef14d174c8ccd039", + "sha256:eb472586374dc66b31e36e14720747595c2b265ae962987261f044e5cce644b5", + "sha256:fbd922f702582cb0d71ef94442bfca57624352622d75e3be7a1e7e9360b07e72" + ], + "markers": "python_version >= '3.6'", + "version": "==8.0.1" + }, "pysimplegui": { "hashes": [ "sha256:641431980a020159e4b1b4a425202560abf616b4de523d9b7476ff228b69b694", From 5ed34de8110ac19c15ae957d61f48d4d7e2c7250 Mon Sep 17 00:00:00 2001 From: Isvvc Date: Thu, 17 Dec 2020 13:11:19 -0700 Subject: [PATCH 03/20] Add gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c77c861 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +qrcode.png From 345847a6b3c1d71766bd96f5879f5dc3cb2d75bf Mon Sep 17 00:00:00 2001 From: Isvvc Date: Thu, 17 Dec 2020 13:40:38 -0700 Subject: [PATCH 04/20] Create simple editable image link list --- Armor Export/src/Armor_Export.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/src/Armor_Export.py index d0f69b7..2a9c520 100644 --- a/Armor Export/src/Armor_Export.py +++ b/Armor Export/src/Armor_Export.py @@ -1,10 +1,14 @@ import PySimpleGUI as sg +images = {"https://upload.wikimedia.org/wikipedia/en/1/15/The_Elder_Scrolls_V_Skyrim_cover.png"} + # Define the window's contents -layout = [[sg.Text("What's your name?")], - [sg.Input(key='-INPUT-')], - [sg.Text(size=(40,1), key='-OUTPUT-')], - [sg.Button('OK'), sg.Button('Quit')]] +layout = [[sg.Text("Image URL")], + [sg.Input(key='-INPUT-'), sg.Button('Add')], + [sg.Text('Images')], + [sg.Listbox(list(images), size=(40,10), select_mode=sg.LISTBOX_SELECT_MODE_MULTIPLE, key='-LIST-')], + [sg.Button('Remove selected', key='Remove')], + [sg.Button('Quit')]] # Create the window window = sg.Window('Window Title', layout) @@ -12,11 +16,17 @@ # Display and interact with the Window using an Event Loop while True: event, values = window.read() + # See if user wants to quit or window was closed if event == sg.WINDOW_CLOSED or event == 'Quit': break - # Output a message to the window - window['-OUTPUT-'].update('Hello ' + values['-INPUT-'] + "! Thanks for trying PySimpleGUI") + + elif event == 'Add': + images.add(values['-INPUT-']) + elif event == 'Remove': + [images.remove(x) for x in values['-LIST-']] + + window['-LIST-'].update(list(images)) # Finish up by removing from the screen window.close() From 3a468e8a604d0d7509db4a0d513e932d9ab812ba Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Sun, 27 Dec 2020 13:01:56 -0700 Subject: [PATCH 05/20] Create function to lead image data from URL Improve the layout array format Change images set to list Support Windows HiDPI --- Armor Export/src/Armor_Export.py | 43 ++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/src/Armor_Export.py index 2a9c520..4dd6a6f 100644 --- a/Armor Export/src/Armor_Export.py +++ b/Armor Export/src/Armor_Export.py @@ -1,14 +1,35 @@ import PySimpleGUI as sg - -images = {"https://upload.wikimedia.org/wikipedia/en/1/15/The_Elder_Scrolls_V_Skyrim_cover.png"} +import requests +from PIL import Image, ImageTk +from io import BytesIO + +# Support HiDPI +import ctypes +import platform +if int(platform.release()) >= 8: + ctypes.windll.shcore.SetProcessDpiAwareness(True) + +def image_data(url: str) -> bytes: + data = BytesIO(requests.get(url).content) + + img = Image.open(data) + bio = BytesIO() + img.save(bio, format="PNG") + del img + return bio.getvalue() + +images = ["https://upload.wikimedia.org/wikipedia/en/1/15/The_Elder_Scrolls_V_Skyrim_cover.png"] # Define the window's contents -layout = [[sg.Text("Image URL")], - [sg.Input(key='-INPUT-'), sg.Button('Add')], - [sg.Text('Images')], - [sg.Listbox(list(images), size=(40,10), select_mode=sg.LISTBOX_SELECT_MODE_MULTIPLE, key='-LIST-')], - [sg.Button('Remove selected', key='Remove')], - [sg.Button('Quit')]] +layout = [ + [sg.Text("Image URL")], + [sg.Input(key='-INPUT-'), sg.Button('Add')], + [sg.Text('Images')], + [sg.Listbox(images, size=(40,10), select_mode=sg.LISTBOX_SELECT_MODE_MULTIPLE, key='-LIST-')], + [sg.Button('Remove selected', key='Remove')], + #[sg.Image(data=image_data(images[0]))], + [sg.Button('Quit')] +] # Create the window window = sg.Window('Window Title', layout) @@ -22,11 +43,13 @@ break elif event == 'Add': - images.add(values['-INPUT-']) + input = values['-INPUT-'] + if not input in images: + images.append(input) elif event == 'Remove': [images.remove(x) for x in values['-LIST-']] - window['-LIST-'].update(list(images)) + window['-LIST-'].update(images) # Finish up by removing from the screen window.close() From f15b71400f419d42b0360a5511462d6b9beaa09f Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Sun, 27 Dec 2020 13:09:48 -0700 Subject: [PATCH 06/20] Cache images by URL --- Armor Export/src/Armor_Export.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/src/Armor_Export.py index 4dd6a6f..dcf1eb7 100644 --- a/Armor Export/src/Armor_Export.py +++ b/Armor Export/src/Armor_Export.py @@ -9,16 +9,19 @@ if int(platform.release()) >= 8: ctypes.windll.shcore.SetProcessDpiAwareness(True) +images = ["https://upload.wikimedia.org/wikipedia/en/1/15/The_Elder_Scrolls_V_Skyrim_cover.png"] +image_cache = dict() + def image_data(url: str) -> bytes: + if url in image_cache: + return image_cache[url] data = BytesIO(requests.get(url).content) - img = Image.open(data) bio = BytesIO() img.save(bio, format="PNG") del img - return bio.getvalue() - -images = ["https://upload.wikimedia.org/wikipedia/en/1/15/The_Elder_Scrolls_V_Skyrim_cover.png"] + image_cache[url] = bio.getvalue() + return image_cache[url] # Define the window's contents layout = [ From 2a1f0096cc2476d1c0fb562949d198a53f5041a2 Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Sun, 27 Dec 2020 14:22:18 -0700 Subject: [PATCH 07/20] Allow images to be previewed --- Armor Export/src/Armor_Export.py | 44 ++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/src/Armor_Export.py index dcf1eb7..bdceeeb 100644 --- a/Armor Export/src/Armor_Export.py +++ b/Armor Export/src/Armor_Export.py @@ -17,31 +17,47 @@ def image_data(url: str) -> bytes: return image_cache[url] data = BytesIO(requests.get(url).content) img = Image.open(data) + + cur_width, cur_height = img.size + if cur_width > 400 or cur_height > 400: + scale = min(400/cur_height, 400/cur_width) + img = img.resize((int(cur_width*scale), int(cur_height*scale)), Image.ANTIALIAS) + bio = BytesIO() img.save(bio, format="PNG") del img image_cache[url] = bio.getvalue() return image_cache[url] -# Define the window's contents +images_col = [ + [sg.Text('Images')], + [sg.Listbox(images, size=(40,10), key='-LIST-')], + [ + sg.Button('Remove selected', key='Remove'), + sg.Button('Preview selected', key='Preview') + ] +] + +preview_col = [ + [sg.Image(data=image_data(images[0]), key='-PREVIEW-')] +] + layout = [ [sg.Text("Image URL")], - [sg.Input(key='-INPUT-'), sg.Button('Add')], - [sg.Text('Images')], - [sg.Listbox(images, size=(40,10), select_mode=sg.LISTBOX_SELECT_MODE_MULTIPLE, key='-LIST-')], - [sg.Button('Remove selected', key='Remove')], - #[sg.Image(data=image_data(images[0]))], + [ + sg.Input(key='-INPUT-'), + sg.Button('Add'), + sg.Button('Preview', key='PreviewInput') + ], + [sg.Column(images_col), sg.Column(preview_col)], [sg.Button('Quit')] ] -# Create the window -window = sg.Window('Window Title', layout) +window = sg.Window('Armor Export', layout) -# Display and interact with the Window using an Event Loop while True: event, values = window.read() - # See if user wants to quit or window was closed if event == sg.WINDOW_CLOSED or event == 'Quit': break @@ -51,9 +67,15 @@ def image_data(url: str) -> bytes: images.append(input) elif event == 'Remove': [images.remove(x) for x in values['-LIST-']] + elif event == 'Preview': + selection = values['-LIST-'] + if len(selection) > 0: + window['-PREVIEW-'].update(data=image_data(selection[0])) + elif event == 'PreviewInput': + input = values['-INPUT-'] + window['-PREVIEW-'].update(data=image_data(input)) window['-LIST-'].update(images) -# Finish up by removing from the screen window.close() From 9ee95dcf4dba1c8e3ccd52f90dfc2f6c614044ca Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Sun, 27 Dec 2020 15:59:45 -0700 Subject: [PATCH 08/20] Create image preview window --- Armor Export/src/Armor_Export.py | 42 +++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/src/Armor_Export.py index bdceeeb..4d18f45 100644 --- a/Armor Export/src/Armor_Export.py +++ b/Armor Export/src/Armor_Export.py @@ -24,17 +24,27 @@ def image_data(url: str) -> bytes: img = img.resize((int(cur_width*scale), int(cur_height*scale)), Image.ANTIALIAS) bio = BytesIO() - img.save(bio, format="PNG") + img.save(bio, format='PNG') del img image_cache[url] = bio.getvalue() return image_cache[url] +def make_images_window(images): + col = sg.Column([[ + sg.Checkbox('', key=f'Checkbox{index}'), + sg.Image(data=image_data(image), enable_events=True, key=f'Image{index}') + ] for index, image in enumerate(images)], size=(500,1000), scrollable=True) + images_layout = [[col]] + new_window = sg.Window('Images', images_layout, finalize=True) + return new_window + images_col = [ [sg.Text('Images')], [sg.Listbox(images, size=(40,10), key='-LIST-')], [ sg.Button('Remove selected', key='Remove'), - sg.Button('Preview selected', key='Preview') + sg.Button('Preview selected', key='Preview'), + sg.Button('Preview all', key='PreviewAll') ] ] @@ -53,29 +63,43 @@ def image_data(url: str) -> bytes: [sg.Button('Quit')] ] -window = sg.Window('Armor Export', layout) +window = sg.Window('Armor Export', layout, finalize=True) +images_window = None while True: - event, values = window.read() - - if event == sg.WINDOW_CLOSED or event == 'Quit': + active_window, event, values = sg.read_all_windows() + print(event) + if (event == sg.WINDOW_CLOSED and active_window == window) or event == 'Quit': break elif event == 'Add': input = values['-INPUT-'] if not input in images: images.append(input) + window['-LIST-'].update(images) + elif event == 'Remove': [images.remove(x) for x in values['-LIST-']] + window['-LIST-'].update(images) + elif event == 'Preview': selection = values['-LIST-'] if len(selection) > 0: window['-PREVIEW-'].update(data=image_data(selection[0])) + elif event == 'PreviewInput': input = values['-INPUT-'] window['-PREVIEW-'].update(data=image_data(input)) - - window['-LIST-'].update(images) + + elif event == 'PreviewAll': + images_window = make_images_window(images) + + elif event == sg.WINDOW_CLOSED and active_window == images_window: + images_window.close() + images_window = None + + elif "Image" in event: + index = event[5:] + images_window[f'Checkbox{index}'].update(not images_window[f'Checkbox{index}'].get()) window.close() - From ed2cc1600ad97bf63303f5808aa5f45acb34a523 Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 17:12:03 -0700 Subject: [PATCH 09/20] Fetch thumbnails of images from Nexusmods link Does not work for adult-only mods as you are required to be signed in to an account to view adult-only mod pages --- Armor Export/src/Armor_Export.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/src/Armor_Export.py index 4d18f45..823d151 100644 --- a/Armor Export/src/Armor_Export.py +++ b/Armor Export/src/Armor_Export.py @@ -1,5 +1,6 @@ import PySimpleGUI as sg import requests +import re from PIL import Image, ImageTk from io import BytesIO @@ -9,7 +10,7 @@ if int(platform.release()) >= 8: ctypes.windll.shcore.SetProcessDpiAwareness(True) -images = ["https://upload.wikimedia.org/wikipedia/en/1/15/The_Elder_Scrolls_V_Skyrim_cover.png"] +images = [] image_cache = dict() def image_data(url: str) -> bytes: @@ -49,13 +50,18 @@ def make_images_window(images): ] preview_col = [ - [sg.Image(data=image_data(images[0]), key='-PREVIEW-')] + [sg.Image(data=image_data("https://upload.wikimedia.org/wikipedia/en/1/15/The_Elder_Scrolls_V_Skyrim_cover.png"), key='-PREVIEW-')] ] layout = [ + [sg.Text("Nexusmods URL")], + [ + sg.Input(key='-NEXUS_INPUT-'), + sg.Button('Open') + ], [sg.Text("Image URL")], [ - sg.Input(key='-INPUT-'), + sg.Input(key='-URL_INPUT-'), sg.Button('Add'), sg.Button('Preview', key='PreviewInput') ], @@ -73,7 +79,7 @@ def make_images_window(images): break elif event == 'Add': - input = values['-INPUT-'] + input = values['-URL_INPUT-'] if not input in images: images.append(input) window['-LIST-'].update(images) @@ -88,15 +94,24 @@ def make_images_window(images): window['-PREVIEW-'].update(data=image_data(selection[0])) elif event == 'PreviewInput': - input = values['-INPUT-'] + input = values['-URL_INPUT-'] window['-PREVIEW-'].update(data=image_data(input)) elif event == 'PreviewAll': - images_window = make_images_window(images) + if images_window is None: + images_window = make_images_window(images) elif event == sg.WINDOW_CLOSED and active_window == images_window: images_window.close() images_window = None + + elif event == 'Open': + if images_window is None: + url = values['-NEXUS_INPUT-'] + html = requests.get(url).text + matches = re.findall('data-src="([^"]*)" data-sub-html="" data-exthumbimage="([^"]*)"', html) + thumbnails = [match[1] for match in matches[:5]] + images_window = make_images_window(thumbnails) elif "Image" in event: index = event[5:] From cebdcff8b67807635f3051520d93818c873d5c33 Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 18:30:06 -0700 Subject: [PATCH 10/20] Allow images to be added or removed from preview window Images from nexus can be added to the images list and images in the images list can be removed from --- Armor Export/src/Armor_Export.py | 48 ++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/src/Armor_Export.py index 823d151..0d4802c 100644 --- a/Armor Export/src/Armor_Export.py +++ b/Armor Export/src/Armor_Export.py @@ -13,6 +13,9 @@ images = [] image_cache = dict() +nexus_images = [] +nexus_images_loaded = 0 + def image_data(url: str) -> bytes: if url in image_cache: return image_cache[url] @@ -30,12 +33,27 @@ def image_data(url: str) -> bytes: image_cache[url] = bio.getvalue() return image_cache[url] -def make_images_window(images): +def make_images_window(current_images): + global nexus_images_loaded + image_links = [] + if current_images: + image_links = images + else: + image_links = [image[1] for image in nexus_images[:5]] + nexus_images_loaded = 5 + col = sg.Column([[ sg.Checkbox('', key=f'Checkbox{index}'), sg.Image(data=image_data(image), enable_events=True, key=f'Image{index}') - ] for index, image in enumerate(images)], size=(500,1000), scrollable=True) - images_layout = [[col]] + ] for index, image in enumerate(image_links)], size=(500,1000), scrollable=True) + + images_layout = [[ + col, + sg.Column([ + [sg.Button('Remove', key='RemoveCurrent') if current_images else sg.Button('Add', key='AddNexus')], + [sg.Button('Done')] + ], element_justification='center') + ]] new_window = sg.Window('Images', images_layout, finalize=True) return new_window @@ -83,6 +101,7 @@ def make_images_window(images): if not input in images: images.append(input) window['-LIST-'].update(images) + window['-URL_INPUT-'].update('') elif event == 'Remove': [images.remove(x) for x in values['-LIST-']] @@ -99,9 +118,9 @@ def make_images_window(images): elif event == 'PreviewAll': if images_window is None: - images_window = make_images_window(images) + images_window = make_images_window(current_images=True) - elif event == sg.WINDOW_CLOSED and active_window == images_window: + elif (event == sg.WINDOW_CLOSED and active_window == images_window) or event == 'Done': images_window.close() images_window = None @@ -109,12 +128,23 @@ def make_images_window(images): if images_window is None: url = values['-NEXUS_INPUT-'] html = requests.get(url).text - matches = re.findall('data-src="([^"]*)" data-sub-html="" data-exthumbimage="([^"]*)"', html) - thumbnails = [match[1] for match in matches[:5]] - images_window = make_images_window(thumbnails) + nexus_images = re.findall('data-src="([^"]*)" data-sub-html="" data-exthumbimage="([^"]*)"', html) + images_window = make_images_window(current_images=False) - elif "Image" in event: + elif 'Image' in event: index = event[5:] images_window[f'Checkbox{index}'].update(not images_window[f'Checkbox{index}'].get()) + + elif event == 'AddNexus': + [images.append(nexus_images[i][0]) for i in range(min(len(nexus_images), nexus_images_loaded)) if images_window[f'Checkbox{i}'].get() and not nexus_images[i][0] in images] + window['-LIST-'].update(images) + images_window.close() + images_window = None + + elif event == 'RemoveCurrent': + [images.pop(i) for i in reversed(range(len(images))) if images_window[f'Checkbox{i}'].get()] + window['-LIST-'].update(images) + images_window.close() + images_window = None window.close() From 0632966f7a3dfb6fd533760e921a74f29ffafea8 Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 18:37:46 -0700 Subject: [PATCH 11/20] Refresh preview window when removing images --- Armor Export/src/Armor_Export.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/src/Armor_Export.py index 0d4802c..9b138cc 100644 --- a/Armor Export/src/Armor_Export.py +++ b/Armor Export/src/Armor_Export.py @@ -132,6 +132,7 @@ def make_images_window(current_images): images_window = make_images_window(current_images=False) elif 'Image' in event: + # 'Image' has 5 characters, so remove the first 5 characters to get the index index = event[5:] images_window[f'Checkbox{index}'].update(not images_window[f'Checkbox{index}'].get()) @@ -145,6 +146,6 @@ def make_images_window(current_images): [images.pop(i) for i in reversed(range(len(images))) if images_window[f'Checkbox{i}'].get()] window['-LIST-'].update(images) images_window.close() - images_window = None + images_window = make_images_window(current_images=True) window.close() From fe124c6620cb912fe07dc37de81dd2eda9b33524 Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 19:09:39 -0700 Subject: [PATCH 12/20] Allow images to be saved to json file --- Armor Export/src/Armor_Export.py | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/src/Armor_Export.py index 9b138cc..a66c3ae 100644 --- a/Armor Export/src/Armor_Export.py +++ b/Armor Export/src/Armor_Export.py @@ -1,6 +1,7 @@ import PySimpleGUI as sg import requests import re +import json from PIL import Image, ImageTk from io import BytesIO @@ -10,6 +11,12 @@ if int(platform.release()) >= 8: ctypes.windll.shcore.SetProcessDpiAwareness(True) +# Load the json file +with open('ingredients.json', 'r') as json_file: + json_data = json_file.read() +ingredients = json.loads(json_data) +print(ingredients['modules'][0]['name']) + images = [] image_cache = dict() @@ -23,6 +30,8 @@ def image_data(url: str) -> bytes: img = Image.open(data) cur_width, cur_height = img.size + # TODO: only scale if the image is larger than this + # Nexusmods thumbnails are slightly below 400 pixels, so don't need to be resized. if cur_width > 400 or cur_height > 400: scale = min(400/cur_height, 400/cur_width) img = img.resize((int(cur_width*scale), int(cur_height*scale)), Image.ANTIALIAS) @@ -68,7 +77,7 @@ def make_images_window(current_images): ] preview_col = [ - [sg.Image(data=image_data("https://upload.wikimedia.org/wikipedia/en/1/15/The_Elder_Scrolls_V_Skyrim_cover.png"), key='-PREVIEW-')] + [sg.Image(key='-PREVIEW-')] ] layout = [ @@ -84,6 +93,11 @@ def make_images_window(current_images): sg.Button('Preview', key='PreviewInput') ], [sg.Column(images_col), sg.Column(preview_col)], + [ + sg.Button('Save images to module', key='SaveModule'), + sg.Button('Save images to mod', key='SaveMod'), + sg.Button('Save images to both', key='SaveBoth') + ], [sg.Button('Quit')] ] @@ -147,5 +161,21 @@ def make_images_window(current_images): window['-LIST-'].update(images) images_window.close() images_window = make_images_window(current_images=True) + + elif event == 'SaveModule': + ingredients['modules'][0]['images'] = images + with open('ingredients.json', 'w') as json_file: + json_file.write(json.dumps(ingredients)) + + elif event == 'SaveMod': + ingredients['mods'][0]['images'] = images + with open('ingredients.json', 'w') as json_file: + json_file.write(json.dumps(ingredients)) + + elif event == 'SaveBoth': + ingredients['modules'][0]['images'] = images + ingredients['mods'][0]['images'] = images + with open('ingredients.json', 'w') as json_file: + json_file.write(json.dumps(ingredients)) window.close() From 38e7eebc35171423d566ececadf21b349cda4493 Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 19:27:13 -0700 Subject: [PATCH 13/20] Allow QR codes to be generated --- Armor Export/src/Armor_Export.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/src/Armor_Export.py index a66c3ae..1f9fa05 100644 --- a/Armor Export/src/Armor_Export.py +++ b/Armor Export/src/Armor_Export.py @@ -4,6 +4,8 @@ import json from PIL import Image, ImageTk from io import BytesIO +# Must be the MyQR fork at https://github.com/Isvvc/qrcode/ +from MyQR import myqr # Support HiDPI import ctypes @@ -96,7 +98,8 @@ def make_images_window(current_images): [ sg.Button('Save images to module', key='SaveModule'), sg.Button('Save images to mod', key='SaveMod'), - sg.Button('Save images to both', key='SaveBoth') + sg.Button('Save images to both', key='SaveBoth'), + sg.Checkbox('Generate QR code', key='GenerateQR') ], [sg.Button('Quit')] ] @@ -104,6 +107,13 @@ def make_images_window(current_images): window = sg.Window('Armor Export', layout, finalize=True) images_window = None +def save_ingredients(): + global ingredients, window + with open('ingredients.json', 'w') as json_file: + json_file.write(json.dumps(ingredients)) + if window['GenerateQR'].get(): + myqr.run(json.dumps(ingredients), level = 'L') + while True: active_window, event, values = sg.read_all_windows() print(event) @@ -164,18 +174,15 @@ def make_images_window(current_images): elif event == 'SaveModule': ingredients['modules'][0]['images'] = images - with open('ingredients.json', 'w') as json_file: - json_file.write(json.dumps(ingredients)) + save_ingredients() elif event == 'SaveMod': ingredients['mods'][0]['images'] = images - with open('ingredients.json', 'w') as json_file: - json_file.write(json.dumps(ingredients)) + save_ingredients() elif event == 'SaveBoth': ingredients['modules'][0]['images'] = images ingredients['mods'][0]['images'] = images - with open('ingredients.json', 'w') as json_file: - json_file.write(json.dumps(ingredients)) + save_ingredients() window.close() From cf3eed643aae6fe59019cf7aa5a18238505d2b66 Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 19:46:40 -0700 Subject: [PATCH 14/20] Update xEdit script to run upadetd Python --- Armor Export/{src => }/Armor_Export.py | 6 +++--- Edit Scripts/Armor Stats and Requirements.pas | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) rename Armor Export/{src => }/Armor_Export.py (96%) diff --git a/Armor Export/src/Armor_Export.py b/Armor Export/Armor_Export.py similarity index 96% rename from Armor Export/src/Armor_Export.py rename to Armor Export/Armor_Export.py index 1f9fa05..c4847f5 100644 --- a/Armor Export/src/Armor_Export.py +++ b/Armor Export/Armor_Export.py @@ -14,7 +14,7 @@ ctypes.windll.shcore.SetProcessDpiAwareness(True) # Load the json file -with open('ingredients.json', 'r') as json_file: +with open('Armor Export\\ingredients.json', 'r') as json_file: json_data = json_file.read() ingredients = json.loads(json_data) print(ingredients['modules'][0]['name']) @@ -109,10 +109,10 @@ def make_images_window(current_images): def save_ingredients(): global ingredients, window - with open('ingredients.json', 'w') as json_file: + with open('Armor Export\\ingredients.json', 'w') as json_file: json_file.write(json.dumps(ingredients)) if window['GenerateQR'].get(): - myqr.run(json.dumps(ingredients), level = 'L') + myqr.run(json.dumps(ingredients), level = 'L', save_dir='Armor Export') while True: active_window, event, values = sg.read_all_windows() diff --git a/Edit Scripts/Armor Stats and Requirements.pas b/Edit Scripts/Armor Stats and Requirements.pas index e78183a..f6b09d0 100644 --- a/Edit Scripts/Armor Stats and Requirements.pas +++ b/Edit Scripts/Armor Stats and Requirements.pas @@ -313,7 +313,8 @@ function Finalize: integer; // Requires my modified myqr.exe compiled from https://github.com/Isvvc/qrcode // This should have already come with this script if you downloaded it from Releases. - ShellExecute(0, nil, '"Armor Export\myqr.exe"', '-l L -d "Armor Export" "Armor Export\Ingredients.json"', nil, 0); + //ShellExecute(0, nil, '"Armor Export\myqr.exe"', '-l L -d "Armor Export" "Armor Export\Ingredients.json"', nil, 0); + ShellExecute(0, nil, '"Armor Export\python-3.8.6.amd64\python.exe"', '"Armor Export\Armor_Export.py"', nil, 0); slIngredients.Free; slIngredientNames.Free; From 067c771ee4dfd00d519c20c2afa57901c196456a Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 19:53:15 -0700 Subject: [PATCH 15/20] Replace pipfile with requirements.txt Because an entire Python distribution is being bundled with releases, it's simpler and faster to just install packages directly rather than in a pipenv --- Armor Export/Pipfile | 13 ---- Armor Export/Pipfile.lock | 115 ---------------------------------- Armor Export/requirements.txt | 4 ++ 3 files changed, 4 insertions(+), 128 deletions(-) delete mode 100644 Armor Export/Pipfile delete mode 100644 Armor Export/Pipfile.lock create mode 100644 Armor Export/requirements.txt diff --git a/Armor Export/Pipfile b/Armor Export/Pipfile deleted file mode 100644 index c6055d7..0000000 --- a/Armor Export/Pipfile +++ /dev/null @@ -1,13 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -pysimplegui = "*" -myqr = {editable = true, git = "https://github.com/Isvvc/qrcode.git"} - -[dev-packages] - -[requires] -python_version = "3.8" diff --git a/Armor Export/Pipfile.lock b/Armor Export/Pipfile.lock deleted file mode 100644 index c8bc36e..0000000 --- a/Armor Export/Pipfile.lock +++ /dev/null @@ -1,115 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "61620181327f4e36a86687164b06888f555d859d10779741c8bbc3a71780a0ce" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.8" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "imageio": { - "hashes": [ - "sha256:3604d751f03002e8e0e7650aa71d8d9148144a87daf17cb1f3228e80747f2e6b", - "sha256:52ddbaeca2dccf53ba2d6dec5676ca7bc3b2403ef8b37f7da78b7654bb3e10f0" - ], - "version": "==2.9.0" - }, - "myqr": { - "editable": true, - "git": "https://github.com/Isvvc/qrcode.git", - "ref": "79dc6ec85767edcc63d1d9f29f31c8f7bf731633" - }, - "numpy": { - "hashes": [ - "sha256:08308c38e44cc926bdfce99498b21eec1f848d24c302519e64203a8da99a97db", - "sha256:09c12096d843b90eafd01ea1b3307e78ddd47a55855ad402b157b6c4862197ce", - "sha256:13d166f77d6dc02c0a73c1101dd87fdf01339febec1030bd810dcd53fff3b0f1", - "sha256:141ec3a3300ab89c7f2b0775289954d193cc8edb621ea05f99db9cb181530512", - "sha256:16c1b388cc31a9baa06d91a19366fb99ddbe1c7b205293ed072211ee5bac1ed2", - "sha256:18bed2bcb39e3f758296584337966e68d2d5ba6aab7e038688ad53c8f889f757", - "sha256:1aeef46a13e51931c0b1cf8ae1168b4a55ecd282e6688fdb0a948cc5a1d5afb9", - "sha256:27d3f3b9e3406579a8af3a9f262f5339005dd25e0ecf3cf1559ff8a49ed5cbf2", - "sha256:2a2740aa9733d2e5b2dfb33639d98a64c3b0f24765fed86b0fd2aec07f6a0a08", - "sha256:4377e10b874e653fe96985c05feed2225c912e328c8a26541f7fc600fb9c637b", - "sha256:448ebb1b3bf64c0267d6b09a7cba26b5ae61b6d2dbabff7c91b660c7eccf2bdb", - "sha256:50e86c076611212ca62e5a59f518edafe0c0730f7d9195fec718da1a5c2bb1fc", - "sha256:5734bdc0342aba9dfc6f04920988140fb41234db42381cf7ccba64169f9fe7ac", - "sha256:64324f64f90a9e4ef732be0928be853eee378fd6a01be21a0a8469c4f2682c83", - "sha256:6ae6c680f3ebf1cf7ad1d7748868b39d9f900836df774c453c11c5440bc15b36", - "sha256:6d7593a705d662be5bfe24111af14763016765f43cb6923ed86223f965f52387", - "sha256:8cac8790a6b1ddf88640a9267ee67b1aee7a57dfa2d2dd33999d080bc8ee3a0f", - "sha256:8ece138c3a16db8c1ad38f52eb32be6086cc72f403150a79336eb2045723a1ad", - "sha256:9eeb7d1d04b117ac0d38719915ae169aa6b61fca227b0b7d198d43728f0c879c", - "sha256:a09f98011236a419ee3f49cedc9ef27d7a1651df07810ae430a6b06576e0b414", - "sha256:a5d897c14513590a85774180be713f692df6fa8ecf6483e561a6d47309566f37", - "sha256:ad6f2ff5b1989a4899bf89800a671d71b1612e5ff40866d1f4d8bcf48d4e5764", - "sha256:c42c4b73121caf0ed6cd795512c9c09c52a7287b04d105d112068c1736d7c753", - "sha256:cb1017eec5257e9ac6209ac172058c430e834d5d2bc21961dceeb79d111e5909", - "sha256:d6c7bb82883680e168b55b49c70af29b84b84abb161cbac2800e8fcb6f2109b6", - "sha256:e452dc66e08a4ce642a961f134814258a082832c78c90351b75c41ad16f79f63", - "sha256:e5b6ed0f0b42317050c88022349d994fe72bfe35f5908617512cd8c8ef9da2a9", - "sha256:e9b30d4bd69498fc0c3fe9db5f62fffbb06b8eb9321f92cc970f2969be5e3949", - "sha256:ec149b90019852266fec2341ce1db513b843e496d5a8e8cdb5ced1923a92faab", - "sha256:edb01671b3caae1ca00881686003d16c2209e07b7ef8b7639f1867852b948f7c", - "sha256:f0d3929fe88ee1c155129ecd82f981b8856c5d97bcb0d5f23e9b4242e79d1de3", - "sha256:f29454410db6ef8126c83bd3c968d143304633d45dc57b51252afbd79d700893", - "sha256:fe45becb4c2f72a0907c1d0246ea6449fe7a9e2293bb0e11c4e9a32bb0930a15", - "sha256:fedbd128668ead37f33917820b704784aff695e0019309ad446a6d0b065b57e4" - ], - "markers": "python_version >= '3.6'", - "version": "==1.19.4" - }, - "pillow": { - "hashes": [ - "sha256:006de60d7580d81f4a1a7e9f0173dc90a932e3905cc4d47ea909bc946302311a", - "sha256:0a2e8d03787ec7ad71dc18aec9367c946ef8ef50e1e78c71f743bc3a770f9fae", - "sha256:0eeeae397e5a79dc088d8297a4c2c6f901f8fb30db47795113a4a605d0f1e5ce", - "sha256:11c5c6e9b02c9dac08af04f093eb5a2f84857df70a7d4a6a6ad461aca803fb9e", - "sha256:2fb113757a369a6cdb189f8df3226e995acfed0a8919a72416626af1a0a71140", - "sha256:4b0ef2470c4979e345e4e0cc1bbac65fda11d0d7b789dbac035e4c6ce3f98adb", - "sha256:59e903ca800c8cfd1ebe482349ec7c35687b95e98cefae213e271c8c7fffa021", - "sha256:5abd653a23c35d980b332bc0431d39663b1709d64142e3652890df4c9b6970f6", - "sha256:5f9403af9c790cc18411ea398a6950ee2def2a830ad0cfe6dc9122e6d528b302", - "sha256:6b4a8fd632b4ebee28282a9fef4c341835a1aa8671e2770b6f89adc8e8c2703c", - "sha256:6c1aca8231625115104a06e4389fcd9ec88f0c9befbabd80dc206c35561be271", - "sha256:795e91a60f291e75de2e20e6bdd67770f793c8605b553cb6e4387ce0cb302e09", - "sha256:7ba0ba61252ab23052e642abdb17fd08fdcfdbbf3b74c969a30c58ac1ade7cd3", - "sha256:7c9401e68730d6c4245b8e361d3d13e1035cbc94db86b49dc7da8bec235d0015", - "sha256:81f812d8f5e8a09b246515fac141e9d10113229bc33ea073fec11403b016bcf3", - "sha256:895d54c0ddc78a478c80f9c438579ac15f3e27bf442c2a9aa74d41d0e4d12544", - "sha256:8de332053707c80963b589b22f8e0229f1be1f3ca862a932c1bcd48dafb18dd8", - "sha256:92c882b70a40c79de9f5294dc99390671e07fc0b0113d472cbea3fde15db1792", - "sha256:95edb1ed513e68bddc2aee3de66ceaf743590bf16c023fb9977adc4be15bd3f0", - "sha256:b63d4ff734263ae4ce6593798bcfee6dbfb00523c82753a3a03cbc05555a9cc3", - "sha256:bd7bf289e05470b1bc74889d1466d9ad4a56d201f24397557b6f65c24a6844b8", - "sha256:cc3ea6b23954da84dbee8025c616040d9aa5eaf34ea6895a0a762ee9d3e12e11", - "sha256:cc9ec588c6ef3a1325fa032ec14d97b7309db493782ea8c304666fb10c3bd9a7", - "sha256:d3d07c86d4efa1facdf32aa878bd508c0dc4f87c48125cc16b937baa4e5b5e11", - "sha256:d8a96747df78cda35980905bf26e72960cba6d355ace4780d4bdde3b217cdf1e", - "sha256:e38d58d9138ef972fceb7aeec4be02e3f01d383723965bfcef14d174c8ccd039", - "sha256:eb472586374dc66b31e36e14720747595c2b265ae962987261f044e5cce644b5", - "sha256:fbd922f702582cb0d71ef94442bfca57624352622d75e3be7a1e7e9360b07e72" - ], - "markers": "python_version >= '3.6'", - "version": "==8.0.1" - }, - "pysimplegui": { - "hashes": [ - "sha256:641431980a020159e4b1b4a425202560abf616b4de523d9b7476ff228b69b694", - "sha256:7132066ac7e365718e3025daa578cd3b229507164c6d80829405c9293adc6935" - ], - "index": "pypi", - "version": "==4.32.1" - } - }, - "develop": {} -} diff --git a/Armor Export/requirements.txt b/Armor Export/requirements.txt new file mode 100644 index 0000000..783a7c8 --- /dev/null +++ b/Armor Export/requirements.txt @@ -0,0 +1,4 @@ +PySimpleGUI +requests +pillow +git+https://github.com/Isvvc/qrcode.git From b419bf7a1cf334455ff51a6c3ea09d228bfc80e0 Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 20:01:52 -0700 Subject: [PATCH 16/20] Rename python directory to Python38 --- Edit Scripts/Armor Stats and Requirements.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Edit Scripts/Armor Stats and Requirements.pas b/Edit Scripts/Armor Stats and Requirements.pas index f6b09d0..728b5be 100644 --- a/Edit Scripts/Armor Stats and Requirements.pas +++ b/Edit Scripts/Armor Stats and Requirements.pas @@ -314,7 +314,7 @@ function Finalize: integer; // Requires my modified myqr.exe compiled from https://github.com/Isvvc/qrcode // This should have already come with this script if you downloaded it from Releases. //ShellExecute(0, nil, '"Armor Export\myqr.exe"', '-l L -d "Armor Export" "Armor Export\Ingredients.json"', nil, 0); - ShellExecute(0, nil, '"Armor Export\python-3.8.6.amd64\python.exe"', '"Armor Export\Armor_Export.py"', nil, 0); + ShellExecute(0, nil, '"Armor Export\Python38\python.exe"', '"Armor Export\Armor_Export.py"', nil, 0); slIngredients.Free; slIngredientNames.Free; From f2eb3cc61196e7e02c1ac108af7b7ec27d063a27 Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 20:09:09 -0700 Subject: [PATCH 17/20] Enable generating QR codes by default --- Armor Export/Armor_Export.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Armor Export/Armor_Export.py b/Armor Export/Armor_Export.py index c4847f5..40f09d5 100644 --- a/Armor Export/Armor_Export.py +++ b/Armor Export/Armor_Export.py @@ -99,7 +99,7 @@ def make_images_window(current_images): sg.Button('Save images to module', key='SaveModule'), sg.Button('Save images to mod', key='SaveMod'), sg.Button('Save images to both', key='SaveBoth'), - sg.Checkbox('Generate QR code', key='GenerateQR') + sg.Checkbox('Generate QR code', default=True, key='GenerateQR') ], [sg.Button('Quit')] ] From bb18cfd10113bfc3645c5e38d6bab80f06204886 Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 20:16:12 -0700 Subject: [PATCH 18/20] Update running instructions --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 32d1f1c..11461b8 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ If it asks to replace `mteFunctions.pas`, it doesn't matter either way. 1. **Optional**: Enter a name for the mod if you want it shown in Character Tracker. + If you leave this empty, no mod entry will be created in the JSON. + This has no affect on the simple printout. -1. This will create an Ingredients.txt file in the `Armor Export` folder in your xEdit directory with the following information: +1. This will create an `Ingredients.txt` file in the `Armor Export` folder in your xEdit directory with the following information: + CSV list of crafting ingredients required + quantity, plugin name and FixedFormID, DisplayName + Combined armor rating @@ -36,8 +36,15 @@ If it asks to replace `mteFunctions.pas`, it doesn't matter either way. + Calculated level based on type and rating + JSON that can be imported into Character Tracker + A QR code that can be scanned into Character Tracker if `myqr.exe` is present. - + This can take some time to generate and may not complete until after the xEdit script has finished running. - + Generating the QR code may fail if the JSON output is too large. +1. A GUI will launch for adding images and generating QR codes. + + Manually add images with the **Image URL** text box + + Enter a Nexusmods mod page in the **Nexusmods URL** text box to select images from the mod page to load. + + Currently only the first 5 images will load. + + Adult-only mod pages will not load as they require a user to be signed in, and this does not currently support signing in to an account. + + When you have the images inputted that you'd like, click any of the **Save images to** buttons to save the images to the `Ingredients.json` file. + + Check **Generate QR code** to generate a QR code that can be scanned into Character Tracker. + + Note that this GUI is in early stages and can crash if text fields are left blank. + + Generating QR codes with no images, however, should work just fine. ## Build From 4848c3f3e766921b7a11ee80966cabb24d1503b5 Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 20:34:16 -0700 Subject: [PATCH 19/20] Update build and install instructions --- README.md | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 11461b8..b6d47da 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,10 @@ This script depends on `mteFunctions.pas` (included in release zips) 1. Download `xEdit-Armor-Export.zip` from the [Releases tab](https://github.com/Isvvc/xEdit-Armor-Export/releases). 1. Extract to your xEdit (TES5Edit, TES5VREdit, etc.) folder, merging any contents. -If it asks to replace `mteFunctions.pas`, it doesn't matter either way. - + Extracting `Armor Export\myqr.exe` is optional. - It is used for creating QR codes for Character Tracker. - You are welcome to remove it if you are not using the app. + + If it asks to replace `mteFunctions.pas`, it shouldn't matter either way. + + Extracting `Python38` and `Armor_Export.py` is optional. + These are used for creating QR codes for Character Tracker. + You are welcome to remove them if you are not using the app. ### Running @@ -52,13 +52,31 @@ If it asks to replace `mteFunctions.pas`, it doesn't matter either way. xEdit scripts are compiled at runtime, so no build is required for the Pascal script. -### MyQR +### Python -The `myqr.exe` included in Releases comes from [Isvvc/qrcode](https://github.com/Isvvc/qrcode/), -my slightly modified version of [sylnsfar/qrcode](https://github.com/sylnsfar/qrcode). +The Python UI is built using [PySimpleGUI](https://github.com/PySimpleGUI/PySimpleGUI). + +#### WinPython + +The image and QR code UI is built using Python. +To use a standalone Python distribution like the ones included in releases, you can download a Python 3.8dot release from [WinPython](https://winpython.github.io/). +Copy the Python folder (will look something like `python-3.8.6.amd64`) to `Armor Export` and rename it to `Python38`. + +To install dependencies, navigate to the xEdit directory in Command Prompt and run the following command: + + "Armor Export\Python\python.exe" -m pip install -r requirements.txt + +You should now be able to access the UI from the xEdit script or by running: + + "Armor Export\Python\python.exe" "Armor Export\Armor_Export.py" + +Note that you must run this from the xEdit directory, not the `Armor Export` directory, or the relative file paths will be wrong. + +#### MyQR + +[Isvvc/qrcode](https://github.com/Isvvc/qrcode/) is required to generate QR codes. +This is a slightly modified version of [sylnsfar/qrcode](https://github.com/sylnsfar/qrcode). The changes I made were simply adding `"` to the supported characters list so it could encode JSON and allowing it to read input from a file so long JSON could be passed in without having to try to pass it as an argument. -Once Python dependencies are installed (presumably using `pip`), it can be built using [PyInstaller](https://www.pyinstaller.org/) for Windows. - - pyinstaller -F myqr.py +Unlike previous releases, there is no `exe` file to generate. The included `python.exe` is run directly. From 181c8471bb01df65ec0cd5b36e168de5bc95ce8f Mon Sep 17 00:00:00 2001 From: Isaac Lyons Date: Mon, 28 Dec 2020 23:50:30 -0700 Subject: [PATCH 20/20] Add vc_redist to dependencies --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b6d47da..c88dfe0 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ It is still totally usable without it, though. ### Dependencies -This script depends on `mteFunctions.pas` (included in release zips) +[Microsoft Visual C++ Redistributable for Visual Studio](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads) ### Installation @@ -52,6 +52,8 @@ This script depends on `mteFunctions.pas` (included in release zips) xEdit scripts are compiled at runtime, so no build is required for the Pascal script. +This script depends on [`mteFunctions.pas`](https://github.com/matortheeternal/TES5EditScripts/blob/master/Edit%20Scripts/mteFunctions.pas) (included in releases). + ### Python The Python UI is built using [PySimpleGUI](https://github.com/PySimpleGUI/PySimpleGUI).