diff --git a/usr/share/blackbox/ui/AppFrameGUI.py b/usr/share/blackbox/ui/AppFrameGUI.py new file mode 100644 index 0000000..ada506f --- /dev/null +++ b/usr/share/blackbox/ui/AppFrameGUI.py @@ -0,0 +1,523 @@ +# ================================================================= +# = Author: Cameron Percival = +# ================================================================= +from socket import TIPC_ADDR_NAME +from urllib.parse import scheme_chars +import Functions as fn + + +class AppFrameGUI: + def build_ui_frame(self, Gtk, vbox_stack, category, packages_list): + try: + # Lets set some variables that we know we will need later + # hboxes and items to make the page look sensible + cat_name = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + seperator = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + lbl1 = Gtk.Label(xalign=0) + lbl1.set_text(category) + lbl1.set_name("title") + hseparator = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) + seperator.pack_start(hseparator, True, True, 0) + cat_name.pack_start(lbl1, False, False, 0) + + # Stack for the different subcategories - I like crossfade as a transition, but you choose + stack = Gtk.Stack() + stack.set_transition_type(Gtk.StackTransitionType.SLIDE_UP_DOWN) + stack.set_transition_duration(350) + stack.set_hhomogeneous(False) + stack.set_vhomogeneous(False) + + # Stack needs a stack switcher to allow the user to make different choices + stack_switcher = Gtk.StackSwitcher() + stack_switcher.set_orientation(Gtk.Orientation.HORIZONTAL) + stack_switcher.set_stack(stack) + stack_switcher.set_homogeneous(True) + + # We will need a vbox later for storing the stack and stack switcher together at the end + vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) + + # create scroller for when/if these items go "off the page" + scrolled_switch = Gtk.ScrolledWindow() + scrolled_switch.add(stack_switcher) + + # These lists will ensure that we can keep track of the individual windows and their names + # stack of vboxes + vbox_stacks = [] + # name of each vbox - derived from the sub category name + vbox_stacknames = [] + sep_text = " " + subcats = {} + # index for the grid + index = 0 + + """ + Store a list of unique sub-categories + e.g. + + category --> applications + sub category --> Accessories + sub category --> Conky + + """ + + sub_catlabels = [] + + # store unique subcategory names into a dictionary + + for package in packages_list: + subcats[package.subcategory] = package + + # we now iterate across the dictionary keys + # each Stack has an associated subcategory + + for subcat in subcats.keys(): + vbox_stacks.append( + Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) + ) + # for the sub-cat page title + sub_catlabels.append(Gtk.Label(xalign=0)) + + vbox_stacknames.append(subcat) + # iterate across a list of packages + + for package in packages_list: + if package.subcategory == subcat: + page = vbox_stacks.pop() + + if len(sub_catlabels) > 0: + lbl_title = sub_catlabels.pop() + lbl_desc = Gtk.Label(xalign=0) + lbl_desc.set_markup( + "Description: " + + package.subcategory_description + + "" + ) + lbl_title.set_markup("" + package.subcategory + "") + + lbl_padding_page1 = Gtk.Label(xalign=0) + lbl_padding_page1.set_text("") + + page.pack_start(lbl_title, False, False, 0) + page.pack_start(lbl_desc, False, False, 0) + page.pack_start(lbl_padding_page1, False, False, 0) + + grid = Gtk.Grid() + + grid.insert_row(index) + + lbl_sep1 = Gtk.Label(xalign=0, yalign=0) + lbl_sep1.set_text(sep_text) + grid.attach(lbl_sep1, 0, index, 1, 1) + lbl_package = Gtk.Label(xalign=0, yalign=0) # was in for loop + + lbl_package.set_markup("%s" % package.name) + + ###### switch widget starts ###### + + # construct new switch + switch = Gtk.Switch() + switch.set_valign(Gtk.Align.CENTER) + + """ + Changed to use signal state-set for switch widget. + set_state(boolean) allows the switch state to be enabled/disabled. + When a pkg install/uninstall fails, the switch widget is enabled/disabled inside a thread. + + Changing the switch using set_active(bool), and using the signal notify::active + caused a never-ending loop which would call app_toggle. + + """ + switch.set_state(fn.query_pkg(package.name)) + switch.connect( + "state-set", + self.app_toggle, + package, + ) + + # add switch widget to grid + + # attach_next_to(child, sibling, side, width, height) + + grid.attach_next_to( + switch, lbl_sep1, Gtk.PositionType.LEFT, 1, 1 + ) + + # add space seperator next to switch + + lbl_sep_switch = Gtk.Label(xalign=0, yalign=0) + lbl_sep_switch.set_text(sep_text) + + grid.attach_next_to( + lbl_sep_switch, switch, Gtk.PositionType.LEFT, 1, 1 + ) + + ###### switch widget ends ###### + + ###### pkg name label widget starts ###### + + lbl_sep_package1 = Gtk.Label(xalign=0, yalign=0) + lbl_sep_package1.set_text(sep_text) + + # add space seperator next to switch for extra padding + + grid.attach_next_to( + lbl_sep_package1, switch, Gtk.PositionType.RIGHT, 1, 1 + ) + + lbl_sep_package2 = Gtk.Label(xalign=0, yalign=0) + lbl_sep_package2.set_text(sep_text) + + # add pkg name label widget to grid + + grid.attach_next_to( + lbl_package, lbl_sep_package1, Gtk.PositionType.RIGHT, 1, 1 + ) + + ###### pkg name label widget ends + + ###### pkg desc label widget starts ###### + + lbl_sep_package_desc = Gtk.Label(xalign=0, yalign=0) + lbl_sep_package_desc.set_text(sep_text) + + # add space seperator next to pkg name for extra padding + + grid.attach_next_to( + lbl_sep_package_desc, + lbl_package, + Gtk.PositionType.RIGHT, + 1, + 1, + ) + + lbl_package_desc = Gtk.Label(xalign=0, yalign=0) + lbl_package_desc.set_text(package.description) + + # add pkg desc label widget to grid + + grid.attach_next_to( + lbl_package_desc, + lbl_sep_package_desc, + Gtk.PositionType.RIGHT, + 1, + 1, + ) + + ###### pkg desc label widget ends + + ##### add pkg version label widget starts ##### + + if self.display_versions is True: + lbl_package_version = Gtk.Label(xalign=0, yalign=0) + lbl_package_version.set_text(package.version) + lbl_package_version.set_name("lbl_package_version") + + lbl_sep_package_version = Gtk.Label(xalign=0, yalign=0) + lbl_sep_package_version.set_text(sep_text) + + grid.attach_next_to( + lbl_sep_package_version, + lbl_package_desc, + Gtk.PositionType.RIGHT, + 1, + 1, + ) + + grid.attach_next_to( + lbl_package_version, + lbl_sep_package_version, + Gtk.PositionType.RIGHT, + 1, + 1, + ) + + ##### pkg version ends ##### + + # make the page scrollable + grid_sc = Gtk.ScrolledWindow() + + # hide the horizontal scrollbar showing on each grid row if the window width is resized + grid_sc.set_policy( + Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC + ) + grid_sc.add(grid) + + grid_sc.set_propagate_natural_height(True) + # pack the grid to the page. + + page.pack_start(grid_sc, True, True, 0) + # save the page - put it back (now populated) + + """ + UI note. + To remove the extra padding around the switch buttons + Comment out the references to grid_sc + Then just have page.pack_start(grid,True, True, 0) + """ + vbox_stacks.append(page) + + # reset the things that we need to. + # packages.clear() + grid = Gtk.Grid() + + index += 1 + + # Now we pack the stack + item_num = 0 + + for item in vbox_stacks: + stack.add_titled( + item, + "stack" + str(item_num), + vbox_stacknames[item_num], + ) + item_num += 1 + + # Place the stack switcher and the stack together into a vbox + vbox.pack_start(scrolled_switch, False, False, 0) + + scrolled_window = Gtk.ScrolledWindow() + scrolled_window.set_propagate_natural_height(True) + scrolled_window.add(stack) + vbox.pack_start(scrolled_window, True, True, 0) + + # Stuff the vbox with the title and seperator to create the page + vbox_stack.pack_start(cat_name, False, False, 0) + vbox_stack.pack_start(seperator, False, False, 0) + vbox_stack.pack_start(vbox, False, False, 0) + + except Exception as e: + fn.logger.error("Exception in App_Frame_GUI.GUI(): %s" % e) + + +########## PREVIOUS GUI CODE START ########## +""" +def GUI(self, Gtk, vboxStack1, category, package_file): + try: + # Lets set some variables that we know we will need later + # hboxes and items to make the page look sensible + cat_name = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + seperator = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + lbl1 = Gtk.Label(xalign=0) + lbl1.set_text(category) + lbl1.set_name("title") + hseparator = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) + seperator.pack_start(hseparator, True, True, 0) + cat_name.pack_start(lbl1, False, False, 0) + + # Stack for the different subcategories - I like crossfade as a transition, but you choose + stack = Gtk.Stack() + stack.set_transition_type(Gtk.StackTransitionType.SLIDE_UP_DOWN) + stack.set_transition_duration(350) + stack.set_hhomogeneous(False) + stack.set_vhomogeneous(False) + + # Stack needs a stack switcher to allow the user to make different choices + stack_switcher = Gtk.StackSwitcher() + stack_switcher.set_orientation(Gtk.Orientation.HORIZONTAL) + stack_switcher.set_stack(stack) + stack_switcher.set_homogeneous(True) + + # We will need a vbox later for storing the stack and stack switcher together at the end + vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) + + # create scroller for when/if these items go "off the page" + scrolledSwitch = Gtk.ScrolledWindow() + scrolledSwitch.add(stack_switcher) + + # These lists will ensure that we can keep track of the individual windows and their names + # stack of vboxes + vboxStacks = [] + # name of each vbox - derived from the sub category name + vboxStackNames = [] + + # page variables - reset these when making multiple subcategories: + # List of packages for any given subcategory + packages = [] + # labels: + name = "" + description = "" + # Lets start by reading in the package list and saving it as a file + with open(package_file, "r") as f: + content = f.readlines() + # f.close() + + # Add a line to the end of content to force the page to be packed. + content.append( + "pack now" + ) # Really, this can be any string, as long as it doesn't match the if statement below. + # Now lets read the file, and use some logic to drive what goes where + # Optomised for runspeed: the line most commonly activated appears first. + for line in content: + # this line will handle code in the yaml that we simply don't need or care about + # MAINTENANCE; if the structure of the .yaml file ever changes, this WILL likely need to be updated + if line.startswith(" packages:"): + continue + elif line.startswith(" - "): + # add the package to the packages list + package = line.strip(" - ") + packages.append(package) + # TODO: Add list and function to obtain package description from pacman and store it (maybe? Maybe the yaml file has what we need?) + elif line.startswith(" description: "): + # Set the label text for the description line + description = ( + line.strip(" description: ").strip().strip('"').strip("\n") + ) + else: + # We will only hit here for category changes, or to pack the page, or if the yaml is changed. + # Yaml changes are handled in the first if statement. + # Pack page; + + if len(packages) > 0: + # Pack the page + # Packing list: + # vbox to pack into - pop it off the + page = vboxStacks.pop() + # grid it + grid = Gtk.Grid() + # Subcat + lblName = Gtk.Label(xalign=0) + lblName.set_markup("" + name + "") + page.pack_start(lblName, False, False, 0) + # description + lblDesc = Gtk.Label(xalign=0) + lblDesc.set_markup("Description: " + description + "") + page.pack_start(lblDesc, False, False, 0) + # packages + sep_text = " " + for i in range(len(packages)): + grid.insert_row(i) + # hbox_pkg = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0) + lblSep1 = Gtk.Label(xalign=0, yalign=0) + lblSep1.set_text(sep_text) + grid.attach(lblSep1, 0, i, 1, 1) + lblPkg = Gtk.Label(xalign=0, yalign=0) # was in for loop + + lblPkg.set_markup("%s" % packages[i].strip()) # was in for loop + # hbox_pkg.pack_start(lblPkg, False, False, 100) + ###### switch widget starts ###### + + + # construct new switch + switch = Gtk.Switch() + + switch.set_active(Functions.query_pkg(packages[i])) + switch.connect( + "notify::active", + self.app_toggle, + packages[i], + Gtk, + vboxStack1, + Functions, + category, + ) + + # add switch widget to grid + + # attach_next_to(child, sibling, side, width, height) + + grid.attach_next_to( + switch, lblSep1, Gtk.PositionType.LEFT, 1, 1 + ) + + # add space seperator next to switch + + lblSepSwitch = Gtk.Label(xalign=0, yalign=0) + lblSepSwitch.set_text(sep_text) + + grid.attach_next_to( + lblSepSwitch, switch, Gtk.PositionType.LEFT, 1, 1 + ) + + ###### switch widget ends ###### + + + ###### pkg name label widget starts ###### + + lblSepPkg1 = Gtk.Label(xalign=0, yalign=0) + lblSepPkg1.set_text(sep_text) + + + # add space seperator next to switch for extra padding + + grid.attach_next_to( + lblSepPkg1, switch, Gtk.PositionType.RIGHT, 1, 1 + ) + + lblSepPkg2 = Gtk.Label(xalign=0, yalign=0) + lblSepPkg2.set_text(sep_text) + + # add pkg name label widget to grid + + grid.attach_next_to( + lblPkg, lblSepPkg1, Gtk.PositionType.RIGHT, 1, 1 + ) + + ###### pkg name label widget ends + + + ###### pkg desc label widget starts ###### + + lblSepPkgDesc = Gtk.Label(xalign=0, yalign=0) + lblSepPkgDesc.set_text(sep_text) + + # add space seperator next to pkg name for extra padding + + grid.attach_next_to( + lblSepPkgDesc, lblPkg, Gtk.PositionType.RIGHT, 1, 1 + ) + + lblPkgDesc = Gtk.Label(xalign=0, yalign=0) + lblPkgDesc.set_text(Functions.obtain_pkg_description(packages[i])) + + # add pkg desc label widget to grid + + grid.attach_next_to( + lblPkgDesc, lblSepPkgDesc, Gtk.PositionType.RIGHT, 1, 1 + ) + + + + + ###### pkg desc label widget ends + + # make the page scrollable + grid_sc = Gtk.ScrolledWindow() + grid_sc.add(grid) + + grid_sc.set_propagate_natural_height(True) + # pack the grid to the page. + page.pack_start(grid_sc, False, False, 0) + # save the page - put it back (now populated) + vboxStacks.append(page) + # reset the things that we need to. + packages.clear() + grid = Gtk.Grid() + # category change + if line.startswith("- name: "): + # Generate the vboxStack item and name for use later (and in packing) + name = line.strip("- name: ").strip().strip('"') + vboxStackNames.append(name) + vboxStacks.append( + Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) + ) + + # Now we pack the stack + item_num = 0 + for item in vboxStacks: + stack.add_titled(item, "stack" + str(item_num), vboxStackNames[item_num]) + item_num += 1 + + # Place the stack switcher and the stack together into a vbox + vbox.pack_start(scrolledSwitch, False, False, 0) + vbox.pack_start(stack, True, True, 0) + + # Stuff the vbox with the title and seperator to create the page + vboxStack1.pack_start(cat_name, False, False, 0) + vboxStack1.pack_start(seperator, False, False, 0) + vboxStack1.pack_start(vbox, False, False, 0) + + except Exception as e: + print("Exception in App_Frame_GUI.GUI(): %s" % e) +""" +########## PREVIOUS GUI CODE END ########## \ No newline at end of file