123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592 |
- #########################################################
- # #
- # THIS SOFTWARE IS (C) J.Y.Amihud and contributors 2022 #
- # AND IT'S UNDER THE GNU AGPLv3 or any later version. #
- # #
- #########################################################
- # I will try to do something crazy stupid. I will try to
- # Make an entire graphical editor using GTK in one python
- # script. Which will not be very wise. But I will give it
- # a shot.
- # A lot of the decisions will be made because of this fact
- # so be aware of that.
- #########################################################
- # #
- # IMPORTING VARIOUS MODULES #
- # #
- #########################################################
- import os
- import time
- import json
- import threading
- import gi
- gi.require_version('Gtk', '3.0')
- from gi.repository import Gtk
- from gi.repository import GLib
- #########################################################
- # #
- # CONFIGURING THE WINDOW #
- # #
- #########################################################
- win = Gtk.Window()
- win.set_size_request(600, 600)
- win.connect("destroy", Gtk.main_quit)
- scrl = Gtk.ScrolledWindow()
- win.add(scrl)
- box = Gtk.VBox()
- scrl.add(box)
- #########################################################
- # #
- # LOADING PRESETS #
- # #
- #########################################################
- # I want to load all kinds of presets for the auto-fill
- # For this we will nee to read all of the files. And it
- # will be done before we have a GUI running. So the out
- # put of this should be done in terminal it self.
- def pbar(now, total):
- # Simple terminal progress bar
- ################------------------------------
- # That's roughly 30% with such a graph.
-
- w, h = os.get_terminal_size()
- n = "#"
- t = "-"
- ns = int(w/total*now)
- string = "\r"+(n*ns)+(t*(w-ns))
- print(string, end="")
- # We assume that it's in a correct folder
- print(" ----- LOADING AUTO-FILL DATA ------ ")
- win.full = {}
- all_apps = list(os.listdir(os.getcwd()+"/apps"))
- for n, i in enumerate(all_apps):
- pbar(n, len(all_apps))
- if i.endswith(".json"):
- # we found a file on an app:
- try:
- with open("apps/"+i) as f:
- this_file = json.load(f)
- for key in this_file:
- if key not in win.full:
- win.full[key] = this_file[key]
- elif type(this_file[key]) == list:
- for item in this_file[key]:
- if item not in win.full[key]:
- win.full[key].append(item)
- elif type(this_file[key]) == dict:
- for thekey in this_file[key]:
- win.full[key][thekey] = ""
-
-
- except Exception as e:
- pass
-
- print(" ----- DONE LOADING AUTO-FILL DATA ------ ")
- #########################################################
- # #
- # LIST EDITOR ( TAG EDITOR ) #
- # #
- #########################################################
- # This piece of code I wrote for FastLBRY GTK, but it will
- # be very handy here. I did a few modifications to remove
- # the dependancy on the icon system in FastLBRY GTK
- def tags_editor(win, data, return_edit_functions=False, auto_fill=[]):
- def update(new_data):
- old = data.copy()
- for t in old:
- data.remove(t)
- for t in new_data:
- data.append(t)
- for i in tagsbox.get_children():
- i.destroy()
- for tag in data:
- add_tag(tag)
-
-
- tagscont = Gtk.HBox()
-
-
- tagscrl = Gtk.ScrolledWindow()
- tagscrl.set_size_request(40,40)
- tagscont.pack_start(tagscrl, True, True, 0)
- tagsbox = Gtk.HBox()
- tagscrl.add_with_viewport(tagsbox)
- def add_tag(tag):
- if not tag:
- return
-
- if tag not in data:
- data.append(tag)
- tagb = Gtk.HBox()
- tagb.pack_start(Gtk.Label(" "+tag+" "), False, False, 0)
- def kill(w):
- tagb.destroy()
- data.remove(tag)
- tagk = Gtk.Button("-")
- tagk.connect("clicked", kill)
- tagk.set_relief(Gtk.ReliefStyle.NONE)
- tagb.pack_start(tagk, False, False, 0)
- tagb.pack_start(Gtk.VSeparator(), False, False, 5)
- tagsbox.pack_start(tagb, False, False, 0)
- tagsbox.show_all()
- # Scroll to the last
- def later():
- time.sleep(0.1)
- def now():
- a = tagscrl.get_hadjustment()
- a.set_value(a.get_upper())
- GLib.idle_add(now)
- load_thread = threading.Thread(target=later)
- load_thread.start()
- # The threading is needed, since we want to wait
- # while GTK will update the UI and only then move
- # the adjustent. Becuase else, it will move to the
- # last previous, not to the last last.
-
- addt = Gtk.Button("+")
- addt.set_relief(Gtk.ReliefStyle.NONE)
- tagscont.pack_end(addt, False, False, 0)
- def on_entry(w):
- add_tag(tagentry.get_text())
- tagentry.set_text("")
- tagentry = Gtk.Entry()
- if auto_fill:
-
- liststore = Gtk.ListStore(str)
- completion = Gtk.EntryCompletion()
- completion.set_model(liststore)
- completion.set_text_column(0)
- for i in auto_fill:
- liststore.append((i,))
- tagentry.set_completion(completion)
- completion.set_minimum_key_length(0)
- completion.complete()
-
- tagentry.connect("activate", on_entry)
- addt.connect("clicked", on_entry)
- tagscont.pack_end(tagentry, False, False, False)
-
-
- for tag in data:
- add_tag(tag)
- if not return_edit_functions:
- return tagscont
- else:
- return tagscont, update
- #########################################################
- # #
- # TOOL BAR #
- # #
- #########################################################
- # Tool bar will not going to have icons and things like
- # this. It's not about being pretty. It's about giving
- # the contributor a handy tool to contribute.
- pannel = Gtk.HeaderBar()
- pannel.set_show_close_button(True)
- win.set_titlebar(pannel)
- # We are going to make a little trick on our self ( I do
- # that everywhere ). I gonna put important variables into
- # the GTK Window.
- win.data_is = {
- "names":[],
- "comment":"",
- "links":{},
- "licenses":[],
- "platforms":[],
- "interface":[],
- "languages":[],
- "networks_read":[],
- "networks_write":[],
- "formats_read":[],
- "formats_write":[],
- "generic_name":[],
- "issues":[],
-
- }
- ##################### NEW BUTTON #######################
- def type_min(i):
- if type(win.data_is[i]) == list:
- return []
- elif type(win.data_is[i]) == dict:
- return {}
- elif type(win.data_is[i]) == str:
- return ""
- def on_new(w):
-
- for i in win.data_is:
-
- try:
- updaters[i](type_min(i))
- except Exception as e:
- win.data_is[i] = type_min(i)
- new_button = Gtk.Button("New")
- new_button.set_relief(Gtk.ReliefStyle.NONE)
- new_button.connect("clicked", on_new)
- pannel.pack_start(new_button)
- ##################### OPEN BUTTON #######################
- def on_open(w):
- dialog = Gtk.FileChooserDialog("Choose a file",
- None,
- Gtk.FileChooserAction.OPEN,
- (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
- Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
- dialog.set_current_folder(os.getcwd()+"/apps")
- filter_sup = Gtk.FileFilter()
- filter_sup.set_name("Json Files")
- filter_sup.add_pattern("*.json")
- dialog.add_filter(filter_sup)
-
- response = dialog.run()
- if response == Gtk.ResponseType.OK:
- # LOADING THE FILE
-
- with open(dialog.get_filename()) as f:
- loaded_file = json.load(f)
-
-
- for i in win.data_is:
- if i in loaded_file and type(win.data_is[i]) == type(loaded_file[i]):
-
- try:
- updaters[i](loaded_file.get(i, type_min(i)))
- except Exception as e:
- win.data_is[i] = loaded_file.get(i, type_min(i))
- else:
- try:
- updaters[i](loaded_file.get(i, type_min(i)))
- except:
- win.data_is[i] = loaded_file.get(i, type_min(i))
-
-
-
-
- dialog.destroy()
- open_button = Gtk.Button("Open")
- open_button.set_relief(Gtk.ReliefStyle.NONE)
- open_button.connect("clicked", on_open)
- pannel.pack_start(open_button)
- ##################### SAVE BUTTON #######################
- # save_button = Gtk.Button("Save")
- # pannel.pack_start(save_button)
- #################### SAVE AS BUTTON #####################
- def on_save_as(w):
- tb = detext.get_buffer()
- win.data_is["comment"] = tb.get_text(tb.get_start_iter(), tb.get_end_iter(), True)
-
- dialog = Gtk.FileChooserDialog("Choose a file",
- None,
- Gtk.FileChooserAction.SAVE,
- (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
- Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
- dialog.set_current_folder(os.getcwd()+"/apps")
- filter_sup = Gtk.FileFilter()
- filter_sup.set_name("Json Files")
- filter_sup.add_pattern("*.json")
- dialog.add_filter(filter_sup)
-
- response = dialog.run()
- if response == Gtk.ResponseType.OK:
- savename = dialog.get_filename()
- if not savename.endswith(".json"):
- savename = savename+".json"
- with open(savename, 'w') as f:
- json.dump(win.data_is, f, indent=4, sort_keys=True)
-
- dialog.destroy()
-
- save_as_button = Gtk.Button("Save As")
- save_as_button.connect("clicked", on_save_as)
- save_as_button.set_relief(Gtk.ReliefStyle.NONE)
- pannel.pack_start(save_as_button)
- #########################################################
- # #
- # EDITOR IT SELF #
- # #
- #########################################################
- updaters = {} # Very important to make tags editor work
- #################### NAMES / COMMENT ####################
- collapsable = Gtk.Expander(label=" Names / Comment: ")
- box.pack_start(collapsable, 0,0,5)
- term_box = Gtk.VBox()
- collapsable.add(term_box)
- # The list of names
- term_box.pack_start(Gtk.Label("List of Names"),0,0,5)
- names_editor, updaters["names"] = tags_editor(win, win.data_is["names"], True)
- term_box.pack_start(names_editor,0,0,5)
- # The list of names
- term_box.pack_start(Gtk.Label("Generic Names ( Features )"),0,0,5)
- generic_editor, updaters["generic_name"] = tags_editor(win, win.data_is["generic_name"], True, win.full.get("generic_name",[]))
- term_box.pack_start(generic_editor,0,0,5)
- term_box.pack_start(Gtk.Label("Comment (HTML)"),0,0,5)
- def comment_updater(new):
- detext.get_buffer().set_text(new)
- win.data_is["comment"] = new
- updaters["comment"] = comment_updater
- descrl = Gtk.ScrolledWindow()
- descrl.set_size_request(100,100)
- detext = Gtk.TextView()
- detext.set_wrap_mode(Gtk.WrapMode.WORD)
- detext.get_buffer().set_text(win.data_is["comment"])
- descrl.add(detext)
- term_box.pack_start(descrl,0,0,5)
- #################### LINKS ####################
- collapsable = Gtk.Expander(label=" Links: ")
- box.pack_start(collapsable, 0,0,5)
- term_box = Gtk.VBox()
- collapsable.add(term_box)
- # Links are a bit more complicated. It will require a
- # special editor.
- def add_item_to_view(category, link):
- itembox = Gtk.HBox()
- itembox.pack_start(Gtk.Label(" "+category+": "), 0,0,0)
- itembox.pack_start(Gtk.VSeparator(), 0,0,0)
- itembox.pack_start(Gtk.Label(" "+link+" "), 0,0,0)
- def on_destroy(w, itembox, category):
- itembox.destroy()
- del win.data_is["links"][category]
-
- destroy = Gtk.Button("-")
- destroy.set_relief(Gtk.ReliefStyle.NONE)
- destroy.connect("clicked", on_destroy, itembox, category)
- itembox.pack_end(destroy, 0,0,0)
-
- linksbox.pack_end(itembox, 0,0,0)
- linksbox.show_all()
-
- def add_item(w):
- key = categoryInput.get_text()
- value = linkInput.get_text()
- if key not in win.data_is["links"]:
- add_item_to_view(key, value)
- win.data_is["links"][key] = value
- categoryInput.set_text("")
- linkInput.set_text("")
- categoryInput.grab_focus()
- def links_updater(new):
- for i in linksbox.get_children():
- i.destroy()
- win.data_is["links"] = {}
-
- for i in new:
- add_item_to_view(i, new[i])
- win.data_is["links"][i] = new[i]
- updaters["links"] = links_updater
-
- inputbox = Gtk.HBox()
- term_box.pack_start(inputbox, 1, 0, 5)
- inputbox.pack_start(Gtk.Label("Category:"), 0,0,1)
- categoryInput = Gtk.Entry()
- inputbox.pack_start(categoryInput, 0,0,1)
- liststore = Gtk.ListStore(str)
- completion = Gtk.EntryCompletion()
- completion.set_model(liststore)
- completion.set_text_column(0)
- for i in list(win.full["links"].keys()):
- liststore.append((i,))
- categoryInput.set_completion(completion)
- completion.set_minimum_key_length(0)
- completion.complete()
- inputbox.pack_start(Gtk.Label("Link:"), 0,0,1)
- linkInput = Gtk.Entry()
- linkInput.connect("activate", add_item)
- inputbox.pack_start(linkInput, 1,1,1)
- addInput = Gtk.Button("+")
- addInput.connect("clicked", add_item)
- addInput.set_relief(Gtk.ReliefStyle.NONE)
- inputbox.pack_end(addInput, 0,0,1)
- linksbox = Gtk.VBox()
- term_box.pack_start(Gtk.HSeparator(), 1, 0, 5)
- term_box.pack_start(linksbox, 1, 0, 5)
- #################### LICENSES ####################
- collapsable = Gtk.Expander(label=" Licenses: ")
- box.pack_start(collapsable, 0,0,5)
- term_box = Gtk.VBox()
- collapsable.add(term_box)
- # The list of licenses
- #term_box.pack_start(Gtk.Label("Licenses:"),0,0,5)
- licenses_editor, updaters["licenses"] = tags_editor(win, win.data_is["licenses"], True, win.full.get("licenses",[]))
- term_box.pack_start(licenses_editor,0,0,5)
- #################### NERDY INFO ##################
- collapsable = Gtk.Expander(label=" Technical Info: ")
- box.pack_start(collapsable, 0,0,5)
- term_box = Gtk.VBox()
- collapsable.add(term_box)
- # The list of Platforms
- term_box.pack_start(Gtk.Label("Platforms:"),0,0,5)
- platforms_editor, updaters["platforms"] = tags_editor(win, win.data_is["platforms"], True, win.full.get("platforms",[]))
- term_box.pack_start(platforms_editor,0,0,5)
- # The list of Interfaces
- term_box.pack_start(Gtk.Label("Interfaces:"),0,0,5)
- interface_editor, updaters["interface"] = tags_editor(win, win.data_is["interface"], True, win.full.get("interface",[]))
- term_box.pack_start(interface_editor,0,0,5)
- # The list of Languages
- term_box.pack_start(Gtk.Label("Languages:"),0,0,5)
- languages_editor, updaters["languages"] = tags_editor(win, win.data_is["languages"], True, win.full.get("languages",[]))
- term_box.pack_start(languages_editor,0,0,5)
- #################### FORMATS / NETWORKS #################
- collapsable = Gtk.Expander(label=" Formats / Networks: ")
- box.pack_start(collapsable, 0,0,5)
- term_box = Gtk.VBox()
- collapsable.add(term_box)
- # The list of Networs read
- term_box.pack_start(Gtk.Label("Networks it can access ( read ):"),0,0,5)
- networks_read_editor, updaters["networks_read"] = tags_editor(win, win.data_is["networks_read"], True, win.full.get("networks_read",[]))
- term_box.pack_start(networks_read_editor,0,0,5)
- # The list of Networs write
- term_box.pack_start(Gtk.Label("Networks it can post to ( write ):"),0,0,5)
- networks_write_editor, updaters["networks_write"] = tags_editor(win, win.data_is["networks_write"], True, win.full.get("networks_write",[]))
- term_box.pack_start(networks_write_editor,0,0,5)
- # The list of Opens files
- term_box.pack_start(Gtk.Label("File formats it reads:"),0,0,5)
- formats_read_editor, updaters["formats_read"] = tags_editor(win, win.data_is["formats_read"], True, win.full.get("formats_read",[]))
- term_box.pack_start(formats_read_editor,0,0,5)
- # The list of saves files
- term_box.pack_start(Gtk.Label("File formats it saves to:"),0,0,5)
- formats_write_editor, updaters["formats_write"] = tags_editor(win, win.data_is["formats_write"], True, win.full.get("formats_write",[]))
- term_box.pack_start(formats_write_editor,0,0,5)
- #################### ANTI-FEATURES #################
- collapsable = Gtk.Expander(label=" Anti-Features ( Malware ): ")
- box.pack_start(collapsable, 0,0,5)
- term_box = Gtk.VBox()
- collapsable.add(term_box)
- # The list of saves files
- issues_editor, updaters["issues"] = tags_editor(win, win.data_is["issues"], True, win.full.get("issues",[]))
- term_box.pack_start(issues_editor,0,0,5)
- #########################################################
- # #
- # STARTING EVERYTHING #
- # #
- #########################################################
- win.show_all()
- Gtk.main()
|