diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9c9bfd0 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +db: + python3 ./build_json.py > src/pkg.json + +run: db + godot --path src/ diff --git a/build_json.py b/build_json.py new file mode 100755 index 0000000..f53a355 --- /dev/null +++ b/build_json.py @@ -0,0 +1,41 @@ +#!/usr/local/bin/python3 + +import sqlite3 +import json +import re + +def main(): + database = r"/usr/local/share/sqlports" + + conn = sqlite3.connect(database) + data = [] + with conn: + cursor = conn.execute("SELECT FULLPKGNAME, COMMENT, DESCR_CONTENTS, WANTLIB, RUN_DEPENDS FROM PortsQ") + for row in cursor: + gui = False + tui = False + if row[3]: + m = re.search("(GL|SDL|gtk-3|X11|Qt5Gui)", row[3]) + if m: + gui = True + m = re.search("(curses)", row[3]) + if m: + tui = True + if row[4]: + m = re.search("x11/gtk\+3,-guic", row[4]) + if m: + gui = True + if not gui and row[2] and row[3] and row[1] and not tui: + m = re.search("(client)", row[3]+row[1]+row[2]) + if m: + tui = True + data.append({ + "pkgname": row[0], #"-".join(row[0].split("-")[:-1]), + "comment": row[1], + "descr": row[2], + "gui": gui, + "tui": tui + }) + print(json.dumps(data)) + +main() diff --git a/src/.import/.gdignore b/src/.import/.gdignore new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/.import/.gdignore @@ -0,0 +1 @@ + diff --git a/src/.import/button.png-234620e182281afdeb4aab4d2ed4f8a7.md5 b/src/.import/button.png-234620e182281afdeb4aab4d2ed4f8a7.md5 new file mode 100644 index 0000000..013b7b2 --- /dev/null +++ b/src/.import/button.png-234620e182281afdeb4aab4d2ed4f8a7.md5 @@ -0,0 +1,3 @@ +source_md5="1e219ff9157a025bff2dec28499918ac" +dest_md5="fe9d8d89b3fd9f03d6f3805d282bb391" + diff --git a/src/.import/button.png-234620e182281afdeb4aab4d2ed4f8a7.stex b/src/.import/button.png-234620e182281afdeb4aab4d2ed4f8a7.stex new file mode 100644 index 0000000..2dbcb95 Binary files /dev/null and b/src/.import/button.png-234620e182281afdeb4aab4d2ed4f8a7.stex differ diff --git a/src/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.md5 b/src/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.md5 new file mode 100644 index 0000000..5328bc7 --- /dev/null +++ b/src/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.md5 @@ -0,0 +1,3 @@ +source_md5="47313fa4c47a9963fddd764e1ec6e4a8" +dest_md5="26ea799ea0a3da9e753b3ebe822e0570" + diff --git a/src/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex b/src/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex new file mode 100644 index 0000000..71f6913 Binary files /dev/null and b/src/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex differ diff --git a/src/Node2D.gd b/src/Node2D.gd new file mode 100644 index 0000000..295f070 --- /dev/null +++ b/src/Node2D.gd @@ -0,0 +1,151 @@ +extends Node2D + +var data +var gui_program +var tui_program +var other +var packages = [] +var installed_packages = [] +var packages_to_delete = [] +var output = [] +var root_tree + +func get_installed_packages(): + var buffer = [] + installed_packages = [] +# warning-ignore:return_value_discarded + OS.execute("pkg_info", [], true, buffer, true) + for p in buffer[0].split("\n"): + installed_packages.append(p.split(" ")[0]) + +func _ready(): + get_installed_packages() + + var file = File.new() + file.open("pkg.json", File.READ) + var content_as_text = file.get_as_text() + data = parse_json(content_as_text) + $Panel/LineEdit.grab_focus() + +# click on APPLY CHANGES +func _on_Button_pressed(): + $Panel/Panel/RichTextLabel.text = "" + if packages.size() > 0: + $Panel/Panel/RichTextLabel.text = "You are going to install these packages:\n" + for l in packages: + $Panel/Panel/RichTextLabel.text += "- " + l + "\n" + if packages_to_delete.size() > 0: + $Panel/Panel/RichTextLabel.text += "You are going to remove these packages:\n" + for l in packages_to_delete: + $Panel/Panel/RichTextLabel.text += "- " + l + "\n" + $Panel/Panel/RichTextLabel.text += "\n\nClick on Accept to apply changes" + $Panel/Panel/Accept.visible = true + $Panel/Panel/Cancel.visible = true + $Panel/Panel.visible = true + +func _on_Tree_multi_selected(): + var item = $Panel/Tree.get_selected() + if item.get_parent() == root_tree: + return(0) + + var status = item.get_metadata(0) + if status == "for_install": # we don't want to install it + item.set_metadata(0, null) + item.clear_custom_bg_color(0) + packages.erase(item.get_text(0)) + elif not status: # we install it + packages.append(item.get_text(0)) + item.set_custom_bg_color(0, Color(0.5,1,0.5,1)) + item.set_metadata(0, "for_install") + elif status == "installed": # we delete it + packages_to_delete.append(item.get_text(0)) + item.set_custom_bg_color(0, Color(0.9,0.2,0.2,0.6)) + item.set_metadata(0, "to_delete") + elif status == "to_delete": # we keep it + packages_to_delete.erase(item.get_text(0)) + item.set_custom_bg_color(0, Color(0.7, 0.7,0.2,0.5)) + item.set_metadata(0, "installed") + + + +func _on_LineEdit_text_entered(text): + $Panel/Tree.clear() + root_tree = $Panel/Tree.create_item() + $Panel/Tree.set_hide_root(true) + gui_program = $Panel/Tree.create_item() + gui_program.set_text(0, "Graphical programs") + gui_program.collapsed = false + tui_program = $Panel/Tree.create_item($Panel/Tree) + tui_program.set_text(0, "Terminal/console programs") + tui_program.collapsed = false + other = $Panel/Tree.create_item($Panel/Tree) + other.set_text(0, "Other programs") + other.collapsed = false + + for d in data.size(): + var s = data[d] + var root + var found = false + + if text == "" or not text: + found = true + elif text.to_upper() in s["pkgname"].to_upper(): + found = true + elif s["comment"] and text.to_upper() in s["comment"].to_upper(): + found = true + elif $Panel/Search_Descr.pressed == true and s["descr"] and text.to_upper() in s["descr"].to_upper(): + found = true + + if found == false: + continue + + if str(s["gui"]) == "True": + root = $Panel/Tree.create_item(gui_program) + elif str(s["tui"]) == "True": + root = $Panel/Tree.create_item(tui_program) + else: + root = $Panel/Tree.create_item(other) + + root.set_text(0, s["pkgname"]) + if s["comment"]: + root.set_text(1, s["comment"]) + root.set_text(1, s["descr"]) + if s["pkgname"] in installed_packages: + root.set_metadata(0, "installed") + root.set_custom_bg_color(0, Color(0.7, 0.7,0.2,0.5)) + +func _on_Hide_pressed(): + $Panel/Panel.visible = false + $Panel/Panel/Hide.visible = false + $Panel/Panel/Accept.visible = false + packages = [] + packages_to_delete = [] + print("Regenerating display") + get_installed_packages() + _on_LineEdit_text_entered($Panel/LineEdit.text) + +func _on_Accept_pressed(): + $Panel/Panel/Accept.visible = false + $Panel/Panel/Hide.visible = true + $Panel/Panel/Cancel.visible = false + $Panel/Panel/RichTextLabel.text = "" + if packages_to_delete.size() > 0: + if $Panel/doas_nopass.pressed: + OS.execute("doas", ["pkg_delete", "-Ivx"] + packages_to_delete, true, output, true) + else: + OS.execute("xterm", ["-e", "doas", "pkg_delete", "-Ivx"] + packages_to_delete, true, output, true) + for l in output: + $Panel/Panel/RichTextLabel.text += l + if packages.size() > 0: + if $Panel/doas_nopass.pressed: + print(OS.execute("doas", ["pkg_add", "-Ivx"] + packages, true, output, true)) + else: + print(OS.execute("xterm", ["-e", "doas", "pkg_add", "-Ivx"] + packages, true, output, true)) + for l in output: + $Panel/Panel/RichTextLabel.text += l + if not $Panel/doas_nopass.pressed: + _on_Hide_pressed() + +func _on_Cancel_pressed(): + $Panel/Panel.visible = false + $Panel/Panel/Cancel.visible = false diff --git a/src/Node2D.tscn b/src/Node2D.tscn new file mode 100644 index 0000000..4b375f6 --- /dev/null +++ b/src/Node2D.tscn @@ -0,0 +1,101 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://Node2D.gd" type="Script" id=1] + +[sub_resource type="StyleBoxFlat" id=1] +bg_color = Color( 0, 0, 0, 1 ) + +[node name="Node2D" type="Node2D"] +script = ExtResource( 1 ) + +[node name="Panel" type="Panel" parent="."] +margin_right = 1022.0 +margin_bottom = 596.0 + +[node name="LineEdit" type="LineEdit" parent="Panel"] +margin_left = 400.0 +margin_top = 5.0 +margin_right = 600.0 +margin_bottom = 29.0 + +[node name="Tree" type="Tree" parent="Panel"] +margin_top = 30.0 +margin_right = 1022.0 +margin_bottom = 596.0 +mouse_default_cursor_shape = 2 +columns = 2 +allow_reselect = true +allow_rmb_select = true + +[node name="Button" type="Button" parent="Panel"] +margin_left = 5.0 +margin_top = 5.0 +margin_right = 69.0 +margin_bottom = 25.0 +text = "APPLY CHANGES" + +[node name="Panel" type="Panel" parent="Panel"] +visible = false +margin_left = 200.0 +margin_top = 150.0 +margin_right = 800.0 +margin_bottom = 550.0 +custom_styles/panel = SubResource( 1 ) + +[node name="RichTextLabel" type="RichTextLabel" parent="Panel/Panel"] +margin_left = 5.0 +margin_top = 5.0 +margin_right = 600.0 +margin_bottom = 300.0 +custom_colors/default_color = Color( 0, 1, 0.0156863, 1 ) +scroll_following = true + +[node name="Hide" type="Button" parent="Panel/Panel"] +visible = false +margin_left = 253.0 +margin_top = 375.0 +margin_right = 356.0 +margin_bottom = 395.0 +text = "Hide message" + +[node name="Accept" type="Button" parent="Panel/Panel"] +visible = false +anchor_left = 0.5 +anchor_top = 1.0 +anchor_right = 0.5 +anchor_bottom = 1.0 +margin_left = -28.0 +margin_top = -25.0 +margin_right = 28.0 +margin_bottom = -5.0 +text = "Accept" + +[node name="Cancel" type="Button" parent="Panel/Panel"] +visible = false +anchor_top = 1.0 +anchor_bottom = 1.0 +margin_left = 100.0 +margin_top = -25.0 +margin_right = 154.0 +margin_bottom = -5.0 +text = "Cancel" + +[node name="Search_Descr" type="CheckButton" parent="Panel"] +margin_left = 600.0 +margin_right = 782.0 +margin_bottom = 40.0 +text = "Search in DESCR" + +[node name="doas_nopass" type="CheckButton" parent="Panel"] +margin_left = 832.0 +margin_right = 1014.0 +margin_bottom = 40.0 +pressed = true +text = "doas_nopass" + +[connection signal="text_entered" from="Panel/LineEdit" to="." method="_on_LineEdit_text_entered"] +[connection signal="item_selected" from="Panel/Tree" to="." method="_on_Tree_multi_selected"] +[connection signal="pressed" from="Panel/Button" to="." method="_on_Button_pressed"] +[connection signal="pressed" from="Panel/Panel/Hide" to="." method="_on_Hide_pressed"] +[connection signal="pressed" from="Panel/Panel/Accept" to="." method="_on_Accept_pressed"] +[connection signal="pressed" from="Panel/Panel/Cancel" to="." method="_on_Cancel_pressed"] diff --git a/src/PackageLine.tscn b/src/PackageLine.tscn new file mode 100644 index 0000000..b171e8d --- /dev/null +++ b/src/PackageLine.tscn @@ -0,0 +1,3 @@ +[gd_scene format=2] + +[node name="Node2D" type="Node2D"] diff --git a/src/default_env.tres b/src/default_env.tres new file mode 100644 index 0000000..20207a4 --- /dev/null +++ b/src/default_env.tres @@ -0,0 +1,7 @@ +[gd_resource type="Environment" load_steps=2 format=2] + +[sub_resource type="ProceduralSky" id=1] + +[resource] +background_mode = 2 +background_sky = SubResource( 1 ) diff --git a/src/project.godot b/src/project.godot new file mode 100644 index 0000000..0d29246 --- /dev/null +++ b/src/project.godot @@ -0,0 +1,26 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=4 + +[application] + +config/name="AppManager" +run/main_scene="res://Node2D.tscn" +run/low_processor_mode=true + +[physics] + +common/enable_pause_aware_picking=true + +[rendering] + +quality/driver/driver_name="GLES2" +vram_compression/import_etc=true +vram_compression/import_etc2=false +environment/default_environment="res://default_env.tres"