forked from clan/clan-core
Merge pull request 'gui add stack switcher, remove notebook tabs' (#602) from hsjobeki-main into main
This commit is contained in:
commit
354291440a
@ -6,19 +6,32 @@ from typing import Any
|
|||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
|
||||||
|
from clan_vm_manager.models import VMBase
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository import Gio, Gtk
|
from gi.repository import Gio, Gtk
|
||||||
|
|
||||||
from .constants import constants
|
from .constants import constants
|
||||||
from .ui.clan_select_list import ClanSelectPage
|
from .ui.clan_select_list import ClanEdit, ClanList
|
||||||
|
|
||||||
|
|
||||||
class ClanJoinPage(Gtk.Box):
|
class ClanJoinPage(Gtk.Box):
|
||||||
def __init__(self) -> None:
|
def __init__(self, stack: Gtk.Stack) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.page = Gtk.Box()
|
self.page = Gtk.Box(
|
||||||
|
orientation=Gtk.Orientation.VERTICAL, spacing=6, expand=True
|
||||||
|
)
|
||||||
self.set_border_width(10)
|
self.set_border_width(10)
|
||||||
self.add(Gtk.Label(label="Join"))
|
self.stack = stack
|
||||||
|
|
||||||
|
button = Gtk.Button(label="Back to list", margin_left=10)
|
||||||
|
button.connect("clicked", self.switch)
|
||||||
|
self.add(button)
|
||||||
|
|
||||||
|
self.add(Gtk.Label("Join cLan"))
|
||||||
|
|
||||||
|
def switch(self, widget: Gtk.Widget) -> None:
|
||||||
|
self.stack.set_visible_child_name("list")
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(Gtk.ApplicationWindow):
|
class MainWindow(Gtk.ApplicationWindow):
|
||||||
@ -35,25 +48,46 @@ class MainWindow(Gtk.ApplicationWindow):
|
|||||||
# Add a notebook layout
|
# Add a notebook layout
|
||||||
# https://python-gtk-3-tutorial.readthedocs.io/en/latest/layout.html#notebook
|
# https://python-gtk-3-tutorial.readthedocs.io/en/latest/layout.html#notebook
|
||||||
self.notebook = Gtk.Notebook()
|
self.notebook = Gtk.Notebook()
|
||||||
vbox.add(self.notebook)
|
self.stack = Gtk.Stack()
|
||||||
|
# self.stack_switcher = Gtk.StackSwitcher()
|
||||||
|
|
||||||
self.notebook.append_page(
|
# Add named stacks
|
||||||
ClanSelectPage(self.reload_clan_tab), Gtk.Label(label="Overview")
|
self.stack.add_titled(
|
||||||
|
ClanList(self.show_list, self.show_edit, self.set_selected), "list", "List"
|
||||||
)
|
)
|
||||||
self.notebook.append_page(ClanJoinPage(), Gtk.Label(label="Join"))
|
self.stack.add_titled(ClanJoinPage(self.show_list), "join", "Join")
|
||||||
|
self.stack.add_titled(ClanEdit(self.show_list, None), "edit", "Edit")
|
||||||
|
|
||||||
|
vbox.add(self.stack)
|
||||||
|
|
||||||
# Must be called AFTER all components were added
|
# Must be called AFTER all components were added
|
||||||
self.show_all()
|
self.show_all()
|
||||||
|
|
||||||
def reload_clan_tab(self) -> None:
|
def set_selected(self, sel: VMBase | None) -> None:
|
||||||
print("Remounting ClanSelectPage")
|
self.selected = sel
|
||||||
self.notebook.remove_page(0)
|
print(f"APP selected + {self.selected}")
|
||||||
self.notebook.insert_page(
|
|
||||||
ClanSelectPage(self.reload_clan_tab), Gtk.Label(label="Overview2"), 0
|
def show_list(self) -> None:
|
||||||
|
widget = self.stack.get_child_by_name("list")
|
||||||
|
print("Remounting ClanListView")
|
||||||
|
if widget:
|
||||||
|
widget.destroy()
|
||||||
|
|
||||||
|
self.stack.add_titled(
|
||||||
|
ClanList(self.show_list, self.show_edit, self.set_selected), "list", "List"
|
||||||
)
|
)
|
||||||
# must call show_all before set active tab
|
|
||||||
self.show_all()
|
self.show_all()
|
||||||
self.notebook.set_current_page(0)
|
self.stack.set_visible_child_name("list")
|
||||||
|
|
||||||
|
def show_edit(self) -> None:
|
||||||
|
print("Remounting ClanEdit")
|
||||||
|
widget = self.stack.get_child_by_name("edit")
|
||||||
|
if widget:
|
||||||
|
widget.destroy()
|
||||||
|
|
||||||
|
self.stack.add_titled(ClanEdit(self.show_list, self.selected), "edit", "Edit")
|
||||||
|
self.show_all()
|
||||||
|
self.stack.set_visible_child_name("edit")
|
||||||
|
|
||||||
def on_quit(self, *args: Any) -> None:
|
def on_quit(self, *args: Any) -> None:
|
||||||
Gio.Application.quit(self.get_application())
|
Gio.Application.quit(self.get_application())
|
||||||
|
@ -5,10 +5,93 @@ from gi.repository import GdkPixbuf, Gtk
|
|||||||
from ..models import VMBase, get_initial_vms
|
from ..models import VMBase, get_initial_vms
|
||||||
|
|
||||||
|
|
||||||
class ClanSelectPage(Gtk.Box):
|
class ClanEditForm(Gtk.ListBox):
|
||||||
def __init__(self, reload: Callable[[], None]) -> None:
|
def __init__(self, selected: VMBase | None) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, expand=True)
|
||||||
|
self.set_border_width(10)
|
||||||
|
self.selected = selected
|
||||||
|
self.set_selection_mode(0)
|
||||||
|
|
||||||
|
if self.selected:
|
||||||
|
row = Gtk.ListBoxRow()
|
||||||
|
row.add(Gtk.Label(f"\n {self.selected.name}"))
|
||||||
|
self.add(row)
|
||||||
|
|
||||||
|
# ---------- row 1 --------
|
||||||
|
row = Gtk.ListBoxRow()
|
||||||
|
row_layout = Gtk.Box(spacing=6, expand=True)
|
||||||
|
|
||||||
|
# Doc: pack_start/end takes alignment params Expand, Fill, Padding
|
||||||
|
row_layout.pack_start(Gtk.Label("Memory Size in MiB"), False, False, 5)
|
||||||
|
row_layout.pack_start(
|
||||||
|
Gtk.SpinButton.new_with_range(512, 4096, 256), True, True, 0
|
||||||
|
)
|
||||||
|
|
||||||
|
row.add(row_layout)
|
||||||
|
self.add(row)
|
||||||
|
|
||||||
|
# ----------- row 2 -------
|
||||||
|
|
||||||
|
row = Gtk.ListBoxRow()
|
||||||
|
row_layout = Gtk.Box(spacing=6, expand=True)
|
||||||
|
|
||||||
|
row_layout.pack_start(Gtk.Label("CPU Count"), False, False, 5)
|
||||||
|
row_layout.pack_end(Gtk.SpinButton.new_with_range(1, 5, 1), True, True, 0)
|
||||||
|
|
||||||
|
row.add(row_layout)
|
||||||
|
self.add(row)
|
||||||
|
|
||||||
|
def switch(self, widget: Gtk.Widget) -> None:
|
||||||
|
self.show_list()
|
||||||
|
|
||||||
|
|
||||||
|
class ClanEdit(Gtk.Box):
|
||||||
|
def __init__(self, show_list: Callable[[], None], selected: VMBase | None) -> None:
|
||||||
super().__init__(orientation=Gtk.Orientation.VERTICAL, expand=True)
|
super().__init__(orientation=Gtk.Orientation.VERTICAL, expand=True)
|
||||||
|
|
||||||
|
self.show_list = show_list
|
||||||
|
self.selected = selected
|
||||||
|
|
||||||
|
button_hooks = {
|
||||||
|
"on_save_clicked": self.on_save,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.toolbar = ClanEditToolbar(**button_hooks)
|
||||||
|
self.add(self.toolbar)
|
||||||
|
self.add(ClanEditForm(self.selected))
|
||||||
|
|
||||||
|
def on_save(self, widget: Gtk.Widget) -> None:
|
||||||
|
print("Save clicked saving values")
|
||||||
|
self.show_list()
|
||||||
|
|
||||||
|
|
||||||
|
class ClanList(Gtk.Box):
|
||||||
|
"""
|
||||||
|
The ClanList
|
||||||
|
Is the composition of
|
||||||
|
the ClanListToolbar
|
||||||
|
the clanListView
|
||||||
|
# ------------------------#
|
||||||
|
# - Tools <Join> < Edit> #
|
||||||
|
# ------------------------#
|
||||||
|
# - List Items
|
||||||
|
# - <...>
|
||||||
|
# ------------------------#
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
show_list: Callable[[], None],
|
||||||
|
show_edit: Callable[[], None],
|
||||||
|
set_selected: Callable[[VMBase | None], None],
|
||||||
|
) -> None:
|
||||||
|
super().__init__(orientation=Gtk.Orientation.VERTICAL, expand=True)
|
||||||
|
|
||||||
|
self.show_edit = show_edit
|
||||||
|
self.show_list = show_list
|
||||||
|
self.set_selected = set_selected
|
||||||
|
|
||||||
# TODO: We should use somekind of useState hook here.
|
# TODO: We should use somekind of useState hook here.
|
||||||
# that updates the list of VMs when the user changes something
|
# that updates the list of VMs when the user changes something
|
||||||
# @hsjobeki reply: @qubasa: This is how to update data in the list store
|
# @hsjobeki reply: @qubasa: This is how to update data in the list store
|
||||||
@ -17,59 +100,89 @@ class ClanSelectPage(Gtk.Box):
|
|||||||
# This class needs to take ownership of the data because it has access to the listStore only
|
# This class needs to take ownership of the data because it has access to the listStore only
|
||||||
self.selected_vm: VMBase | None = None
|
self.selected_vm: VMBase | None = None
|
||||||
|
|
||||||
self.list_hooks = {
|
|
||||||
"on_select_row": self.on_select_vm,
|
|
||||||
}
|
|
||||||
self.add(ClanSelectList(**self.list_hooks))
|
|
||||||
self.reload = reload
|
|
||||||
button_hooks = {
|
button_hooks = {
|
||||||
"on_start_clicked": self.on_start_clicked,
|
"on_start_clicked": self.on_start_clicked,
|
||||||
"on_stop_clicked": self.on_stop_clicked,
|
"on_stop_clicked": self.on_stop_clicked,
|
||||||
"on_backup_clicked": self.on_backup_clicked,
|
"on_edit_clicked": self.on_edit_clicked,
|
||||||
}
|
}
|
||||||
self.add(ClanSelectButtons(**button_hooks))
|
self.toolbar = ClanListToolbar(**button_hooks)
|
||||||
|
self.toolbar.set_is_selected(False)
|
||||||
|
self.add(self.toolbar)
|
||||||
|
|
||||||
|
self.list_hooks = {
|
||||||
|
"on_select_row": self.on_select_vm,
|
||||||
|
}
|
||||||
|
self.add(ClanListView(**self.list_hooks))
|
||||||
|
|
||||||
def on_start_clicked(self, widget: Gtk.Widget) -> None:
|
def on_start_clicked(self, widget: Gtk.Widget) -> None:
|
||||||
print("Start clicked")
|
print("Start clicked")
|
||||||
if self.selected_vm:
|
if self.selected_vm:
|
||||||
self.selected_vm.run()
|
self.selected_vm.run()
|
||||||
self.reload()
|
# Call this to reload
|
||||||
|
self.show_list()
|
||||||
|
|
||||||
def on_stop_clicked(self, widget: Gtk.Widget) -> None:
|
def on_stop_clicked(self, widget: Gtk.Widget) -> None:
|
||||||
print("Stop clicked")
|
print("Stop clicked")
|
||||||
|
|
||||||
def on_backup_clicked(self, widget: Gtk.Widget) -> None:
|
def on_edit_clicked(self, widget: Gtk.Widget) -> None:
|
||||||
print("Backup clicked")
|
print("Edit clicked")
|
||||||
|
self.show_edit()
|
||||||
|
|
||||||
def on_select_vm(self, vm: VMBase) -> None:
|
def on_select_vm(self, vm: VMBase) -> None:
|
||||||
print(f"on_select_vm: {vm}")
|
print(f"on_select_vm: {vm}")
|
||||||
|
if vm is None:
|
||||||
|
self.toolbar.set_is_selected(False)
|
||||||
|
else:
|
||||||
|
self.toolbar.set_is_selected(True)
|
||||||
|
|
||||||
|
self.set_selected(vm)
|
||||||
self.selected_vm = vm
|
self.selected_vm = vm
|
||||||
|
|
||||||
|
|
||||||
class ClanSelectButtons(Gtk.Box):
|
class ClanListToolbar(Gtk.Toolbar):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
on_start_clicked: Callable[[Gtk.Widget], None],
|
on_start_clicked: Callable[[Gtk.Widget], None],
|
||||||
on_stop_clicked: Callable[[Gtk.Widget], None],
|
on_stop_clicked: Callable[[Gtk.Widget], None],
|
||||||
on_backup_clicked: Callable[[Gtk.Widget], None],
|
on_edit_clicked: Callable[[Gtk.Widget], None],
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(
|
super().__init__(orientation=Gtk.Orientation.HORIZONTAL)
|
||||||
orientation=Gtk.Orientation.HORIZONTAL, margin_bottom=10, margin_top=10
|
|
||||||
)
|
|
||||||
|
|
||||||
button = Gtk.Button(label="Start", margin_left=10)
|
self.start_button = Gtk.ToolButton(label="Join")
|
||||||
button.connect("clicked", on_start_clicked)
|
self.start_button.connect("clicked", on_start_clicked)
|
||||||
self.add(button)
|
self.add(self.start_button)
|
||||||
button = Gtk.Button(label="Stop", margin_left=10)
|
|
||||||
button.connect("clicked", on_stop_clicked)
|
self.edit_button = Gtk.ToolButton(label="Edit")
|
||||||
self.add(button)
|
self.edit_button.connect("clicked", on_edit_clicked)
|
||||||
button = Gtk.Button(label="Edit", margin_left=10)
|
self.add(self.edit_button)
|
||||||
button.connect("clicked", on_backup_clicked)
|
|
||||||
self.add(button)
|
def set_is_selected(self, s: bool) -> None:
|
||||||
|
if s:
|
||||||
|
self.edit_button.set_sensitive(True)
|
||||||
|
self.start_button.set_sensitive(True)
|
||||||
|
else:
|
||||||
|
self.edit_button.set_sensitive(False)
|
||||||
|
self.start_button.set_sensitive(False)
|
||||||
|
|
||||||
|
|
||||||
class ClanSelectList(Gtk.Box):
|
class ClanEditToolbar(Gtk.Toolbar):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
on_save_clicked: Callable[[Gtk.Widget], None],
|
||||||
|
) -> None:
|
||||||
|
super().__init__(orientation=Gtk.Orientation.HORIZONTAL)
|
||||||
|
|
||||||
|
# Icons See: https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
|
||||||
|
# Could not find a suitable one
|
||||||
|
self.save_button = Gtk.ToolButton(label="Save")
|
||||||
|
self.save_button.connect("clicked", on_save_clicked)
|
||||||
|
|
||||||
|
self.add(self.save_button)
|
||||||
|
|
||||||
|
|
||||||
|
class ClanListView(Gtk.Box):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
|
Loading…
Reference in New Issue
Block a user