GZiCMK;x=_s*oyBR!9{nDWnP%
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
literal 0
HcmV?d00001
diff --git a/class_editor.py b/class_editor.py
deleted file mode 100644
index 1751ea3..0000000
--- a/class_editor.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from imgui_bundle import imgui, imgui_ctx
-from model import *
-
-class ClassEditor:
- def __init__(self):
- super().__init__()
- self.add_name = str()
- self.select = 0
-
- def __call__(self):
- classes = Class.select()
-
- with imgui_ctx.begin("Class Editor"):
- imgui.text("Add Class")
-
- _, self.add_name = imgui.input_text(" ", self.add_name)
-
- if imgui.button("Add"):
- if self.add_name:
- Class.create(name=self.add_name)
- self.add_name = str()
-
- imgui.separator()
-
- if not classes:
- imgui.text("No Dataset could be queried")
- return
-
- for n, c in enumerate(classes, start=1):
- display = f"{n}. {c.name}"
- opened, _ = imgui.selectable(display, self.select == n-1)
- if opened:
- self.select = n-1
-
- return classes[self.select]
diff --git a/database.py b/database.py
new file mode 100644
index 0000000..335c0a9
--- /dev/null
+++ b/database.py
@@ -0,0 +1,223 @@
+# Custom
+from model import *
+from appstate import *
+
+# External
+from imgui_bundle import (
+ imgui,
+ imgui_ctx,
+ immapp,
+ imgui_md,
+ im_file_dialog,
+ hello_imgui
+)
+
+# Built In
+from typing import List
+import shelve
+from pathlib import Path
+from datetime import datetime
+
+def file_info(path: Path) -> None:
+ stat = path.stat()
+ modified = datetime.fromtimestamp(stat.st_atime)
+ created = datetime.fromtimestamp(stat.st_ctime)
+ format = '%c'
+
+ data = {
+ "File": path.name,
+ "Size": f"{stat.st_size/100} KB",
+ "Modified": modified.strftime(format),
+ "Created": created.strftime(format)
+ }
+
+ if imgui.begin_table("File Info", 2):
+ imgui.table_setup_column(" ", 0)
+ imgui.table_setup_column(" ")
+
+ for k, v in data.items():
+ imgui.push_id(k)
+ imgui.table_next_row()
+ imgui.table_next_column()
+ imgui.text(k)
+ imgui.table_next_column()
+ imgui.text(v)
+ imgui.pop_id()
+ imgui.end_table()
+
+@immapp.static(inited=False, res=False)
+def select_file(app_state: AppState):
+ statics = select_file
+ if not statics.inited:
+ statics.res = None
+ statics.current = None
+ with shelve.open("state") as state:
+ statics.current = Path(state["DB"])
+ statics.inited = True
+
+ imgui_md.render("# Database Manager")
+ file_info(statics.current)
+
+ if imgui.button("Open File"):
+ im_file_dialog.FileDialog.instance().open("SelectDatabase", "Open Database", "Database File (*.json;*.db){.json,.db}")
+ if im_file_dialog.FileDialog.instance().is_done("SelectDatabase"):
+ if im_file_dialog.FileDialog.instance().has_result():
+ statics.res = im_file_dialog.FileDialog.instance().get_result()
+ LOG_INFO(f"Load File {statics.res}")
+ im_file_dialog.FileDialog.instance().close()
+
+ if statics.res:
+ filename = statics.res.filename()
+ info = Path(statics.res.path())
+
+ imgui.separator()
+ file_info(info)
+
+ file = None
+ if imgui.button("Load"):
+ if not db.is_closed():
+ db.close()
+
+ if statics.res.extension() == '.json':
+ file = filename.removesuffix('.json')
+ file = file + '.db'
+ db.init(file)
+ db.connect(reuse_if_open=True)
+ db.create_tables([Class, Student, Lecture, Submission])
+ load_from_json(str(info))
+ LOG_INFO(f"Successfully created {file}")
+
+ if statics.res.extension() == '.db':
+ file = str(statics.res.path())
+ db.init(file)
+ db.connect(reuse_if_open=True)
+ db.create_tables([Class, Student, Lecture, Submission])
+ LOG_INFO(f"Successfully loaded {filename}")
+
+ with shelve.open("state") as state:
+ state["DB"] = file
+ app_state.update()
+ statics.res = None
+
+@immapp.static(inited=False)
+def table(app_state: AppState) -> None:
+ statics = table
+ if not statics.inited:
+ statics.class_id = None
+ statics.lectures = None
+ statics.points = list()
+ statics.inited = True
+
+ if statics.class_id != app_state.current_class_id:
+ statics.class_id = app_state.current_class_id
+ statics.lectures = Lecture.select().where(Lecture.class_id == statics.class_id)
+ statics.data = dict()
+ for student in Student.select().where(Student.class_id == statics.class_id):
+ subs = Submission.select().where(Submission.student_id == student.id)
+ points = [sub.points for sub in subs]
+ statics.data[f"{student.prename} {student.surname}"] = points
+
+ if not statics.lectures:
+ imgui.text("No Lecture queried")
+ return
+
+ table_flags = (
+ imgui.TableFlags_.row_bg.value
+ | imgui.TableFlags_.borders.value
+ | imgui.TableFlags_.resizable.value
+ | imgui.TableFlags_.sizing_stretch_same.value
+ )
+
+ if imgui.begin_table("Overview", len(statics.lectures)+1, table_flags):
+ imgui.table_setup_column("Students")
+ for n, lecture in enumerate(statics.lectures, start=1):
+ imgui.table_setup_column(f"{n}. {lecture.title} ({lecture.points})")
+ imgui.table_setup_scroll_freeze(1, 1)
+ imgui.table_headers_row()
+
+ for k, v in statics.data.items():
+ imgui.push_id(k)
+ imgui.table_next_row()
+ imgui.table_next_column()
+ imgui.text(k)
+ for points in v:
+ imgui.table_next_column()
+ if points.is_integer():
+ points = int(points)
+ imgui.text(str(points))
+ imgui.pop_id()
+
+ imgui.end_table()
+
+@immapp.static(inited=False)
+def class_editor() -> None:
+ statics = class_editor
+ if not statics.inited:
+ statics.classes = None
+ statics.selected = 0
+ statics.inited = True
+
+ statics.classes = Class.select()
+
+ imgui_md.render("# Edit Classes")
+ _, statics.selected = imgui.combo("Classes", statics.selected, [c.name for c in statics.classes])
+ imgui.text(statics.classes[statics.selected].name)
+
+def database_editor(app_state: AppState) -> None:
+ class_editor()
+
+def database_docking_splits() -> List[hello_imgui.DockingSplit]:
+ split_main_command = hello_imgui.DockingSplit()
+ split_main_command.initial_dock = "MainDockSpace"
+ split_main_command.new_dock = "CommandSpace"
+ split_main_command.direction = imgui.Dir.down
+ split_main_command.ratio = 0.3
+
+ # Log Space
+ split_main_command2 = hello_imgui.DockingSplit()
+ split_main_command2.initial_dock = "CommandSpace"
+ split_main_command2.new_dock = "CommandSpace2"
+ split_main_command2.direction = imgui.Dir.right
+ split_main_command2.ratio = 0.3
+
+ split_main_misc = hello_imgui.DockingSplit()
+ split_main_misc.initial_dock = "MainDockSpace"
+ split_main_misc.new_dock = "MiscSpace"
+ split_main_misc.direction = imgui.Dir.left
+ split_main_misc.ratio = 0.2
+
+ splits = [split_main_misc, split_main_command, split_main_command2]
+ return splits
+
+def set_database_editor_layout(app_state: AppState) -> List[hello_imgui.DockableWindow]:
+
+ file_dialog = hello_imgui.DockableWindow()
+ file_dialog.label = "Database"
+ file_dialog.dock_space_name = "MiscSpace"
+ file_dialog.gui_function = lambda: select_file(app_state)
+
+ log = hello_imgui.DockableWindow()
+ log.label = "Logs"
+ log.dock_space_name = "CommandSpace2"
+ log.gui_function = hello_imgui.log_gui
+
+ table_view = hello_imgui.DockableWindow()
+ table_view.label = "Table"
+ table_view.dock_space_name = "MainDockSpace"
+ table_view.gui_function = lambda: table(app_state)
+
+ editor = hello_imgui.DockableWindow()
+ editor.label = "Editor"
+ editor.dock_space_name = "CommandSpace"
+ editor.gui_function = lambda: database_editor(app_state)
+
+ return [
+ file_dialog, log, table_view, editor
+ ]
+
+def database_editor_layout(app_state: AppState) -> hello_imgui.DockingParams:
+ docking_params = hello_imgui.DockingParams()
+ docking_params.layout_name = "Database Editor"
+ docking_params.docking_splits = database_docking_splits()
+ docking_params.dockable_windows = set_database_editor_layout(app_state)
+ return docking_params
diff --git a/datatypes.py b/datatypes.py
deleted file mode 100644
index 74eb1be..0000000
--- a/datatypes.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from PIL import ImageColor
-from enum import IntEnum
-
-# Global Color Pallet
-COLOR_BACKGROUND = tuple([e/255 for e in ImageColor.getcolor("#29132E","RGBA")])
-COLOR_1 = tuple([e/255 for e in ImageColor.getcolor("#321450","RGBA")])
-COLOR_2 = tuple([e/255 for e in ImageColor.getcolor("#860029","RGBA")])
-COLOR_3 = tuple([e/255 for e in ImageColor.getcolor("#DE004E","RGBA")])
-COLOR_TEXT = tuple([e/255 for e in ImageColor.getcolor("#F887FF","RGBA")])
-COLOR_TEXT_PASSED = tuple([e/255 for e in ImageColor.getcolor("#1AFE49","RGBA")])
-COLOR_TEXT_FAILED = tuple([e/255 for e in ImageColor.getcolor("#FF124F","RGBA")])
-
-class LayoutOptions(IntEnum):
- EDITOR = 1
- GRAPHER = 2
diff --git a/demo_docking.py b/demo_docking.py
deleted file mode 100644
index 1be190e..0000000
--- a/demo_docking.py
+++ /dev/null
@@ -1,926 +0,0 @@
-# A more complex app demo
-#
-# It demonstrates how to:
-# - set up a complex docking layouts (with several possible layouts):
-# - load additional fonts, possibly colored, and with emojis
-# - display a log window
-# - use the status bar
-# - use default menus (App and view menu), and how to customize them
-# - use a specific application state (instead of using static variables)
-# - save some additional user settings within imgui ini file
-# - use borderless windows, that are movable and resizable
-import json
-from enum import Enum
-import time
-
-from imgui_bundle import hello_imgui, icons_fontawesome_6, imgui, immapp, imgui_ctx, ImVec4, ImVec2
-from imgui_bundle.demos_python import demo_utils
-from typing import List, Any
-
-
-##########################################################################
-# Our Application State
-##########################################################################
-class MyAppSettings:
- motto: hello_imgui.InputTextData
- value: int = 10
-
- def __init__(self):
- self.motto = hello_imgui.InputTextData(
- "Hello, Dear ImGui\n"
- "Unleash your creativity!\n",
- True, # multiline
- (14.0, 3.0) # initial size (in em)
- )
-
-class RocketState(Enum):
- Init = 0
- Preparing = 1
- Launched = 2
-
-
-# Struct that holds the application's state
-class AppState:
- f: float
- counter: int
- rocket_progress: float
- my_app_settings: MyAppSettings
- rocket_state: RocketState
- rocket_launch_time: float
-
- title_font: imgui.ImFont
- color_font: imgui.ImFont
- emoji_font: imgui.ImFont
- large_icon_font: imgui.ImFont
-
- def __init__(self):
- self.f = 0
- self.counter = 0
- self.rocket_progress = 0.0
- self.rocket_launch_time = 0.0
- self.my_app_settings = MyAppSettings()
- self.rocket_state = RocketState.Init
-
-
-##########################################################################
-# Additional fonts handling
-##########################################################################
-def load_fonts(app_state: AppState): # This is called by runnerParams.callbacks.LoadAdditionalFonts
- # First, load the default font (the default font should be loaded first)
- # In this example, we instruct HelloImGui to use FontAwesome6 instead of FontAwesome4
- hello_imgui.get_runner_params().callbacks.default_icon_font = hello_imgui.DefaultIconFont.font_awesome6
- hello_imgui.imgui_default_settings.load_default_font_with_font_awesome_icons()
-
- # Load the title font
- # app_state.title_font = hello_imgui.load_font("fonts/DroidSans.ttf", 18.0)
- font_loading_params_title_icons = hello_imgui.FontLoadingParams()
- font_loading_params_title_icons.merge_font_awesome = True
- app_state.title_font = hello_imgui.load_font("fonts/Roboto/Roboto-BoldItalic.ttf", 18, font_loading_params_title_icons)
-
- # Load the emoji font
- font_loading_params_emoji = hello_imgui.FontLoadingParams()
- font_loading_params_emoji.use_full_glyph_range = True
- app_state.emoji_font = hello_imgui.load_font("fonts/NotoEmoji-Regular.ttf", 24., font_loading_params_emoji)
-
- # Load a large icon font
- font_loading_params_large_icon = hello_imgui.FontLoadingParams()
- font_loading_params_large_icon.use_full_glyph_range = True
- app_state.large_icon_font = hello_imgui.load_font("fonts/fontawesome-webfont.ttf", 24., font_loading_params_large_icon)
-
- # Load a colored font
- font_loading_params_color = hello_imgui.FontLoadingParams()
- font_loading_params_color.load_color = True
- app_state.color_font = hello_imgui.load_font("fonts/Playbox/Playbox-FREE.otf", 24., font_loading_params_color)
-
-
-
-##########################################################################
-# Save additional settings in the ini file
-##########################################################################
-# This demonstrates how to store additional info in the application settings
-# Use this sparingly!
-# This is provided as a convenience only, and it is not intended to store large quantities of text data.
-
-# Warning, the save/load function below are quite simplistic!
-def my_app_settings_to_string(settings: MyAppSettings) -> str:
- as_dict: dict[str, Any] = {}
- as_dict["motto"] = hello_imgui.input_text_data_to_dict(settings.motto)
- as_dict["value"] = settings.value
- return json.dumps(as_dict)
-
-
-def string_to_my_app_settings(s: str) -> MyAppSettings:
- r = MyAppSettings()
- try:
- as_dict = json.loads(s)
- r.motto = hello_imgui.input_text_data_from_dict(as_dict["motto"])
- r.value = as_dict["value"]
- except Exception as e:
- hello_imgui.log(hello_imgui.LogLevel.error, f"Error while loading user settings: {e}")
- return r
-
-
-def load_my_app_settings(app_state: AppState):
- """
- Note: load_my_app_settings() and save_my_app_settings() will be called in the callbacks `post_init` & `before_exit`
- runner_params.callbacks.post_init = lambda: load_user_settings(app_state)
- runner_params.callbacks.before_exit = lambda: save_user_settings(app_state)
- """
- app_state.my_app_settings = string_to_my_app_settings(
- hello_imgui.load_user_pref("MyAppSettings")
- )
-
-
-def save_my_app_settings(app_state: AppState):
- hello_imgui.save_user_pref(
- "MyAppSettings", my_app_settings_to_string(app_state.my_app_settings)
- )
-
-
-##########################################################################
-# Gui functions used in this demo
-##########################################################################
-@immapp.static(last_hide_time=1)
-def demo_hide_window(app_state: AppState):
- # Display a button that will hide the application window
- imgui.push_font(app_state.title_font)
- imgui.text("Hide app window")
- imgui.pop_font()
-
- if imgui.button("Hide"):
- demo_hide_window.last_hide_time = time.time()
- hello_imgui.get_runner_params().app_window_params.hidden = True
- if imgui.is_item_hovered():
- imgui.set_tooltip("By clicking this button, you can hide the window for 3 seconds.")
- if demo_hide_window.last_hide_time > 0.0:
- now = time.time()
- if now - demo_hide_window.last_hide_time > 3.0:
- demo_hide_window.last_hide_time = -1.0
- hello_imgui.get_runner_params().app_window_params.hidden = False
-
-
-# Display a button that will add another dockable window during execution
-def demo_show_additional_window(app_state: AppState):
- # In order to add a dockable window during execution, you should use
- # hello_imgui.add_dockable_window()
- # Note: you should not modify manually the content of runnerParams.docking_params.dockable_windows
- # (since HelloImGui is constantly looping on it)
-
- imgui.push_font(app_state.title_font)
- imgui.text("Dynamically add window")
- imgui.pop_font()
-
- window_name = "Additional Window"
- if imgui.button("Show additional window"):
- additional_window = hello_imgui.DockableWindow()
- additional_window.label = window_name
- additional_window.include_in_view_menu = False # this window is not shown in the view menu,
- additional_window.remember_is_visible = False # its visibility is not saved in the settings file,
- additional_window.dock_space_name = "MiscSpace" # when shown, it will appear in MiscSpace.
- additional_window.gui_function = lambda: imgui.text("This is the additional window")
- hello_imgui.add_dockable_window(
- additional_window,
- force_dockspace=False # means that the window will be docked to the last space it was docked to
- # i.e. dock_space_name is ignored if the user previously moved the window to another space
- )
- imgui.set_item_tooltip("By clicking this button, you can show an additional window")
-
- if imgui.button("Remove additional window"):
- hello_imgui.remove_dockable_window(window_name)
- imgui.set_item_tooltip("By clicking this button, you can remove the additional window")
-
-
-def demo_basic_widgets(app_state: AppState):
- imgui.push_font(app_state.title_font)
- imgui.text("Basic widgets demo")
- imgui.pop_font()
-
- imgui.begin_group()
- # Edit a float using a slider from 0.0 to 1.0
- changed, app_state.f = imgui.slider_float("float", app_state.f, 0.0, 1.0)
- if changed:
- hello_imgui.log(
- hello_imgui.LogLevel.warning, f"state.f was changed to {app_state.f}"
- )
-
- # Buttons return true when clicked (most widgets return true when edited/activated)
- if imgui.button("Button"):
- app_state.counter += 1
- hello_imgui.log(hello_imgui.LogLevel.info, "Button was pressed")
- imgui.same_line()
- imgui.text(f"counter = {app_state.counter}")
- imgui.end_group()
-
- if imgui.is_item_hovered():
- imgui.set_tooltip("These widgets will interact with the log window")
-
-
-def demo_user_settings(app_state: AppState):
- imgui.push_font(app_state.title_font)
- imgui.text("User settings")
- imgui.pop_font()
-
- imgui.begin_group()
-
- imgui.set_next_item_width(hello_imgui.em_size(7.0))
- _, app_state.my_app_settings.value = imgui.slider_int(
- "Value", app_state.my_app_settings.value, 0, 100
- )
-
- _ = hello_imgui.input_text_resizable("Motto", app_state.my_app_settings.motto)
- imgui.text("(this text widget is resizable)")
-
- imgui.end_group()
- if imgui.is_item_hovered():
- imgui.set_tooltip("The values below are stored in the application settings ini file and restored at startup")
-
-
-def demo_rocket(app_state: AppState):
- imgui.push_font(app_state.title_font)
- imgui.text("Rocket demo")
- imgui.pop_font()
-
- imgui.begin_group()
- if app_state.rocket_state == RocketState.Init:
- if imgui.button(f"{icons_fontawesome_6.ICON_FA_ROCKET} Launch rocket"):
- app_state.rocket_launch_time = time.time()
- app_state.rocket_state = RocketState.Preparing
- hello_imgui.log(hello_imgui.LogLevel.warning, "Rocket is being prepared")
- elif app_state.rocket_state == RocketState.Preparing:
- imgui.text("Please Wait")
- app_state.rocket_progress = (time.time() - app_state.rocket_launch_time) / 3.0
- if app_state.rocket_progress >= 1.0:
- app_state.rocket_state = RocketState.Launched
- hello_imgui.log(hello_imgui.LogLevel.warning, "Rocket was launched")
- elif app_state.rocket_state == RocketState.Launched:
- imgui.text(f"{icons_fontawesome_6.ICON_FA_ROCKET} Rocket launched")
- if imgui.button("Reset Rocket"):
- app_state.rocket_state = RocketState.Init
- app_state.rocket_progress = 0.0
- imgui.end_group()
- if imgui.is_item_hovered():
- imgui.set_tooltip("Look at the status bar after clicking")
-
-
-def demo_docking_flags(app_state: AppState):
- imgui.push_font(app_state.title_font)
- imgui.text("Main dock space node flags")
- imgui.pop_font()
- imgui.text_wrapped(
- """
-This will edit the ImGuiDockNodeFlags for "MainDockSpace".
-Most flags are inherited by children dock spaces.
- """
- )
-
- class DockFlagWithInfo:
- def __init__(self, flag, label, tip):
- self.flag = flag
- self.label = label
- self.tip = tip
-
- all_flags = [
- DockFlagWithInfo(
- imgui.DockNodeFlags_.no_docking_split,
- "NoSplit",
- "prevent Dock Nodes from being split",
- ),
- DockFlagWithInfo(
- imgui.DockNodeFlags_.no_resize,
- "NoResize",
- "prevent Dock Nodes from being resized",
- ),
- DockFlagWithInfo(
- imgui.DockNodeFlags_.auto_hide_tab_bar,
- "AutoHideTabBar",
- "show tab bar only if multiple windows\n"
- + 'You will need to restore the layout after changing (Menu "View/Restore Layout")',
- ),
- DockFlagWithInfo(
- imgui.DockNodeFlags_.no_docking_over_central_node,
- "NoDockingInCentralNode",
- "prevent docking in central node\n(only works with the main dock space)",
- ),
- # DockFlagWithInfo(imgui.DockNodeFlags_.passthru_central_node, "PassthruCentralNode", "advanced"),
- ]
-
- main_dock_space_node_flags = (
- hello_imgui.get_runner_params().docking_params.main_dock_space_node_flags
- )
- for flag_with_info in all_flags:
- _, main_dock_space_node_flags = imgui.checkbox_flags(
- flag_with_info.label, main_dock_space_node_flags, flag_with_info.flag
- )
- if imgui.is_item_hovered():
- imgui.set_tooltip("%s" % flag_with_info.tip)
-
- hello_imgui.get_runner_params().docking_params.main_dock_space_node_flags = (
- main_dock_space_node_flags
- )
-
-
-def gui_window_layout_customization(app_state: AppState):
- imgui.push_font(app_state.title_font)
- imgui.text("Switch between layouts")
- imgui.pop_font()
- imgui.text('with the menu "View/Layouts"')
- if imgui.is_item_hovered():
- imgui.set_tooltip(
- "Each layout remembers separately the modifications applied by the user, \n"
- + "and the selected layout is restored at startup"
- )
-
- imgui.separator()
-
- imgui.push_font(app_state.title_font)
- imgui.text("Change the theme")
- imgui.pop_font()
- imgui.text('with the menu "View/Theme"')
- if imgui.is_item_hovered():
- imgui.set_tooltip("The selected theme is remembered and restored at startup")
- imgui.separator()
-
- demo_docking_flags(app_state)
- imgui.separator()
-
-
-def gui_window_alternative_theme(app_state: AppState):
- # Since this window applies a theme, We need to call "imgui.begin" ourselves so
- # that we can apply the theme before opening the window.
- #
- # In order to obtain this, we applied the following option to the window
- # that displays this Gui:
- # alternative_theme_window.call_begin_end = False
-
- # emulate C/C++ static variable: we will store some static variables
- # as attributes of the function
- statics = gui_window_alternative_theme
-
- # Apply the theme before opening the window
- tweaked_theme = hello_imgui.ImGuiTweakedTheme()
- tweaked_theme.theme = hello_imgui.ImGuiTheme_.white_is_white
- tweaked_theme.tweaks.rounding = 0.0
- hello_imgui.push_tweaked_theme(tweaked_theme)
-
- # Open the window
- window_opened = imgui.begin("Alternative Theme")
- if window_opened:
- # Display some widgets
- imgui.push_font(app_state.title_font)
- imgui.text("Alternative Theme")
- imgui.pop_font()
- imgui.text("This window uses a different theme")
- imgui.set_item_tooltip("""
- tweaked_theme = hello_imgui.ImGuiTheme.ImGuiTweakedTheme()
- tweaked_theme.theme = hello_imgui.ImGuiTheme_.white_is_white.value
- tweaked_theme.tweaks.rounding = 0.0
- hello_imgui.apply_tweaked_theme(tweaked_theme)
- """
- )
-
- if imgui.collapsing_header("Basic Widgets", imgui.TreeNodeFlags_.default_open.value):
- if not hasattr(statics, "checked"):
- statics.checked = True
- _, statics.checked = imgui.checkbox("Checkbox", statics.checked)
-
- if imgui.button("Button"):
- hello_imgui.log(hello_imgui.LogLevel.info, "Button was pressed")
- imgui.set_item_tooltip("This is a button")
-
- if not hasattr(statics, "radio"):
- statics.radio = 0
- if imgui.radio_button("Radio 1", statics.radio == 0):
- statics.radio = 0
- imgui.same_line()
- if imgui.radio_button("Radio 2", statics.radio == 1):
- statics.radio = 1
- imgui.same_line()
- if imgui.radio_button("Radio 3", statics.radio == 2):
- statics.radio = 2
-
- # Haiku
- # Display a image of the haiku below with Japanese characters
- # with an informative tooltip
- haiku_image_height = hello_imgui.em_size(5.0)
- hello_imgui.image_from_asset("images/haiku.png", (0.0, haiku_image_height))
- imgui.set_item_tooltip("""
-Extract from Wikipedia
--------------------------------------------------------------------------------
-
-In early 1686, Bashō composed one of his best-remembered haiku:
-
- furu ike ya / kawazu tobikomu / mizu no oto
-
- an ancient pond / a frog jumps in / the splash of water
-
-This poem became instantly famous.
-
--------------------------------------------------------------------------------
-
-This haiku is here rendered as an image, mainly to preserve space,
-because adding a Japanese font to the project would enlarge its size.
-Handling Japanese font is of course possible within ImGui / Hello ImGui!
- """)
-
- # Display the haiku text as an InputTextMultiline
- if not hasattr(statics, "poem"):
- statics.poem = (
- " Old Pond\n"
- " Frog Leaps In\n"
- " Water's Sound\n"
- "\n"
- " Matsuo Bashō - 1686"
- )
-
- _, statics.poem = imgui.input_text_multiline("##Poem", statics.poem, hello_imgui.em_to_vec2(15.0, 5.5))
-
- # a popup with a modal window
- if imgui.button("Open Modal"):
- imgui.open_popup("MyModal")
- popup_opened, _ = imgui.begin_popup_modal("MyModal", None, imgui.WindowFlags_.always_auto_resize.value)
- if popup_opened:
- imgui.text("This is a modal window")
- if imgui.button("Close"):
- imgui.close_current_popup()
- imgui.end_popup()
-
- if not hasattr(statics, "text"):
- statics.text = "Hello, world!"
- _, statics.text = imgui.input_text("Input text", statics.text)
-
- if imgui.tree_node("Text Display"):
- imgui.text("Hello, world!")
- imgui.text_colored((1.0, 0.5, 0.5, 1.0), "Some text")
- imgui.text_disabled("Disabled text")
- imgui.text_wrapped("This is a long text that will be wrapped in the window")
- imgui.tree_pop()
-
- # Close the window
- imgui.end()
-
- # Restore the theme
- hello_imgui.pop_tweaked_theme()
-
-
-def demo_assets(app_state: AppState):
- imgui.push_font(app_state.title_font)
- imgui.text("Image From Assets")
- imgui.pop_font()
- hello_imgui.begin_group_column()
- imgui.dummy(hello_imgui.em_to_vec2(0.0, 0.45))
- imgui.text("Hello")
- hello_imgui.end_group_column()
- hello_imgui.image_from_asset("images/world.png", hello_imgui.em_to_vec2(2.5, 2.5))
-
-
-def demo_fonts(app_state: AppState):
- imgui.push_font(app_state.title_font)
- imgui.text("Fonts - " + icons_fontawesome_6.ICON_FA_ROCKET)
- imgui.pop_font()
-
- imgui.text_wrapped("Mix icons " + icons_fontawesome_6.ICON_FA_FACE_SMILE + " and text " + icons_fontawesome_6.ICON_FA_ROCKET)
- if imgui.is_item_hovered():
- imgui.set_tooltip("Example with Font Awesome Icons")
-
- imgui.text("Emojis")
-
- with imgui_ctx.begin_group():
- imgui.push_font(app_state.emoji_font)
- imgui.text("✌❤🌴🚀")
- imgui.pop_font()
-
- if imgui.is_item_hovered():
- imgui.set_tooltip("Example with NotoEmoji font")
-
- imgui.text("Colored Fonts")
- imgui.push_font(app_state.color_font)
- imgui.text("COLOR!")
- imgui.pop_font()
- if imgui.is_item_hovered():
- imgui.set_tooltip("Example with Playbox-FREE.otf font")
-
-
-def demo_themes(app_state: AppState):
- imgui.push_font(app_state.title_font)
- imgui.text("Themes")
- imgui.pop_font()
-
- tweaked_theme = hello_imgui.get_runner_params().imgui_window_params.tweaked_theme
-
- imgui.begin_group()
- button_size = hello_imgui.em_to_vec2(7.0, 0.0)
- if imgui.button("Cherry", button_size):
- tweaked_theme.theme = hello_imgui.ImGuiTheme_.cherry
- hello_imgui.apply_tweaked_theme(tweaked_theme)
- if imgui.button("DarculaDarker", button_size):
- tweaked_theme.theme = hello_imgui.ImGuiTheme_.darcula_darker
- hello_imgui.apply_tweaked_theme(tweaked_theme)
- imgui.end_group()
- if imgui.is_item_hovered():
- imgui.set_tooltip(
- "There are lots of other themes: look at the menu View/Theme\n"
- "The selected theme is remembered and restored at startup"
- )
-
-
-def gui_window_demo_features(app_state: AppState):
- demo_fonts(app_state)
- imgui.separator()
- demo_assets(app_state)
- imgui.separator()
- demo_basic_widgets(app_state)
- imgui.separator()
- demo_rocket(app_state)
- imgui.separator()
- demo_user_settings(app_state)
- imgui.separator()
- demo_hide_window(app_state)
- imgui.separator()
- demo_show_additional_window(app_state)
- imgui.separator()
- demo_themes(app_state)
- imgui.separator()
-
-
-def status_bar_gui(app_state: AppState):
- if app_state.rocket_state == RocketState.Preparing:
- imgui.text("Rocket completion: ")
- imgui.same_line()
- imgui.progress_bar(app_state.rocket_progress, hello_imgui.em_to_vec2(7.0, 1.0)) # type: ignore
-
-
-def show_menu_gui(runner_params: hello_imgui.RunnerParams):
- hello_imgui.show_app_menu(runner_params)
- hello_imgui.show_view_menu(runner_params)
- if imgui.begin_menu("My Menu"):
- clicked, _ = imgui.menu_item("Test me", "", False)
- if clicked:
- hello_imgui.log(hello_imgui.LogLevel.warning, "It works")
- imgui.end_menu()
-
-
-def show_app_menu_items():
- clicked, _ = imgui.menu_item("A Custom app menu item", "", False)
- if clicked:
- hello_imgui.log(hello_imgui.LogLevel.info, "Clicked on A Custom app menu item")
-
-
-def show_top_toolbar(app_state: AppState):
- imgui.push_font(app_state.large_icon_font)
- if imgui.button(icons_fontawesome_6.ICON_FA_POWER_OFF):
- hello_imgui.get_runner_params().app_shall_exit = True
-
- imgui.same_line(imgui.get_window_width() - hello_imgui.em_size(7.0))
- if imgui.button(icons_fontawesome_6.ICON_FA_HOUSE):
- hello_imgui.log(hello_imgui.LogLevel.info, "Clicked on Home in the top toolbar")
- imgui.same_line()
- if imgui.button(icons_fontawesome_6.ICON_FA_FLOPPY_DISK):
- hello_imgui.log(hello_imgui.LogLevel.info, "Clicked on Save in the top toolbar")
- imgui.same_line()
- if imgui.button(icons_fontawesome_6.ICON_FA_ADDRESS_BOOK):
- hello_imgui.log(hello_imgui.LogLevel.info, "Clicked on Address Book in the top toolbar")
-
- imgui.same_line(imgui.get_window_width() - hello_imgui.em_size(2.0))
- imgui.text(icons_fontawesome_6.ICON_FA_BATTERY_THREE_QUARTERS)
- imgui.pop_font()
-
-
-def show_right_toolbar(app_state: AppState):
- imgui.push_font(app_state.large_icon_font)
- if imgui.button(icons_fontawesome_6.ICON_FA_CIRCLE_ARROW_LEFT):
- hello_imgui.log(hello_imgui.LogLevel.info, "Clicked on Circle left in the right toolbar")
- if imgui.button(icons_fontawesome_6.ICON_FA_CIRCLE_ARROW_RIGHT):
- hello_imgui.log(hello_imgui.LogLevel.info, "Clicked on Circle right in the right toolbar")
- imgui.pop_font()
-
-
-##########################################################################
-# Docking Layouts and Docking windows
-##########################################################################
-
-#
-# 1. Define the Docking splits (two versions are available)
-#
-def create_default_docking_splits() -> List[hello_imgui.DockingSplit]:
- # Define the default docking splits,
- # i.e. the way the screen space is split in different target zones for the dockable windows
- # We want to split "MainDockSpace" (which is provided automatically) into three zones, like this:
- #
- # ___________________________________________
- # | | |
- # | Command| |
- # | Space | MainDockSpace |
- # |------- | |
- # | |--------------------------------|
- # | | CommandSpace2 |
- # -------------------------------------------
- # | MiscSpace |
- # -------------------------------------------
- #
-
- # Uncomment the next line if you want to always start with this layout.
- # Otherwise, modifications to the layout applied by the user layout will be remembered.
- # runner_params.docking_params.layout_condition = hello_imgui.DockingLayoutCondition.ApplicationStart
-
- # Then, add a space named "MiscSpace" whose height is 25% of the app height.
- # This will split the preexisting default dockspace "MainDockSpace" in two parts.
- split_main_misc = hello_imgui.DockingSplit()
- split_main_misc.initial_dock = "MainDockSpace"
- split_main_misc.new_dock = "MiscSpace"
- split_main_misc.direction = imgui.Dir.down
- split_main_misc.ratio = 0.25
-
- # Then, add a space to the left which occupies a column whose width is 25% of the app width
- split_main_command = hello_imgui.DockingSplit()
- split_main_command.initial_dock = "MainDockSpace"
- split_main_command.new_dock = "CommandSpace"
- split_main_command.direction = imgui.Dir.left
- split_main_command.ratio = 0.25
-
- # Then, add CommandSpace2 below MainDockSpace
- split_main_command2 = hello_imgui.DockingSplit()
- split_main_command2.initial_dock = "MainDockSpace"
- split_main_command2.new_dock = "CommandSpace2"
- split_main_command2.direction = imgui.Dir.down
- split_main_command2.ratio = 0.5
-
- splits = [split_main_misc, split_main_command, split_main_command2]
- return splits
-
-
-def create_alternative_docking_splits() -> List[hello_imgui.DockingSplit]:
- # Define alternative docking splits for the "Alternative Layout"
- # ___________________________________________
- # | | |
- # | Misc | |
- # | Space | MainDockSpace |
- # | | |
- # -------------------------------------------
- # | | |
- # | | Command |
- # | CommandSpace | Space2 |
- # -------------------------------------------
-
- split_main_command = hello_imgui.DockingSplit()
- split_main_command.initial_dock = "MainDockSpace"
- split_main_command.new_dock = "CommandSpace"
- split_main_command.direction = imgui.Dir.down
- split_main_command.ratio = 0.5
-
- split_main_command2 = hello_imgui.DockingSplit()
- split_main_command2.initial_dock = "CommandSpace"
- split_main_command2.new_dock = "CommandSpace2"
- split_main_command2.direction = imgui.Dir.right
- split_main_command2.ratio = 0.4
-
- split_main_misc = hello_imgui.DockingSplit()
- split_main_misc.initial_dock = "MainDockSpace"
- split_main_misc.new_dock = "MiscSpace"
- split_main_misc.direction = imgui.Dir.left
- split_main_misc.ratio = 0.5
-
- splits = [split_main_command, split_main_command2, split_main_misc]
- return splits
-
-
-#
-# 2. Define the Dockable windows
-#
-def create_dockable_windows(app_state: AppState) -> List[hello_imgui.DockableWindow]:
- # A features demo window named "FeaturesDemo" will be placed in "CommandSpace".
- # Its Gui is provided by "gui_window_demo_features"
- features_demo_window = hello_imgui.DockableWindow()
- features_demo_window.label = "Features Demo"
- features_demo_window.dock_space_name = "CommandSpace"
- features_demo_window.gui_function = lambda: gui_window_demo_features(app_state)
-
- # A layout customization window will be placed in "MainDockSpace".
- # Its Gui is provided by "gui_window_layout_customization"
- layout_customization_window = hello_imgui.DockableWindow()
- layout_customization_window.label = "Layout customization"
- layout_customization_window.dock_space_name = "MainDockSpace"
- layout_customization_window.gui_function = lambda: gui_window_layout_customization(app_state)
-
- # A Log window named "Logs" will be placed in "MiscSpace". It uses the HelloImGui logger gui
- logs_window = hello_imgui.DockableWindow()
- logs_window.label = "Logs"
- logs_window.dock_space_name = "MiscSpace"
- logs_window.gui_function = hello_imgui.log_gui
-
- # A Window named "Dear ImGui Demo" will be placed in "MainDockSpace"
- dear_imgui_demo_window = hello_imgui.DockableWindow()
- dear_imgui_demo_window.label = "Dear ImGui Demo"
- dear_imgui_demo_window.dock_space_name = "MainDockSpace"
- dear_imgui_demo_window.imgui_window_flags = imgui.WindowFlags_.menu_bar.value
- dear_imgui_demo_window.gui_function = imgui.show_demo_window # type: ignore
-
- # alternativeThemeWindow
- alternative_theme_window = hello_imgui.DockableWindow()
- # Since this window applies a theme, We need to call "imgui.begin" ourselves so
- # that we can apply the theme before opening the window.
- alternative_theme_window.call_begin_end = False
- alternative_theme_window.label = "Alternative Theme"
- alternative_theme_window.dock_space_name = "CommandSpace2"
- alternative_theme_window.gui_function = lambda: gui_window_alternative_theme(app_state)
-
- dockable_windows = [
- features_demo_window,
- layout_customization_window,
- logs_window,
- dear_imgui_demo_window,
- alternative_theme_window,
- ]
- return dockable_windows
-
-
-#
-# 3. Define the layouts:
-# A layout is stored inside DockingParams, and stores the splits + the dockable windows.
-# Here, we provide the default layout, and two alternative layouts.
-def create_default_layout(app_state: AppState) -> hello_imgui.DockingParams:
- docking_params = hello_imgui.DockingParams()
- # By default, the layout name is already "Default"
- # docking_params.layout_name = "Default"
- docking_params.docking_splits = create_default_docking_splits()
- docking_params.dockable_windows = create_dockable_windows(app_state)
- return docking_params
-
-
-def create_alternative_layouts(app_state: AppState) -> List[hello_imgui.DockingParams]:
- alternative_layout = hello_imgui.DockingParams()
- alternative_layout.layout_name = "Alternative Layout"
- alternative_layout.docking_splits = create_alternative_docking_splits()
- alternative_layout.dockable_windows = create_dockable_windows(app_state)
-
- tabs_layout = hello_imgui.DockingParams()
- tabs_layout.layout_name = "Tabs Layout"
- tabs_layout.dockable_windows = create_dockable_windows(app_state)
- # Force all windows to be presented in the MainDockSpace
- for window in tabs_layout.dockable_windows:
- window.dock_space_name = "MainDockSpace"
- # In "Tabs Layout", no split is created
- tabs_layout.docking_splits = []
-
- return [alternative_layout, tabs_layout]
-
-
-##########################################################################
-# Define the app initial theme
-##########################################################################
-def setup_my_theme():
- """Example of theme customization at App startup
- This function is called in the callback `setup_imgui_style` in order to apply a custom theme:
- runner_params.callbacks.setup_imgui_style = setup_my_theme()
- """
- # Apply default style
- hello_imgui.imgui_default_settings.setup_default_imgui_style()
- # Create a tweaked theme
- tweaked_theme = hello_imgui.ImGuiTweakedTheme()
- tweaked_theme.theme = hello_imgui.ImGuiTheme_.material_flat
- tweaked_theme.tweaks.rounding = 10.0
- # Apply the tweaked theme
- hello_imgui.apply_tweaked_theme(tweaked_theme) # Note: you can also push/pop the theme in order to apply it only to a specific part of the Gui: hello_imgui.push_tweaked_theme(tweaked_theme) / hello_imgui.pop_tweaked_theme()
- # Then apply further modifications to ImGui style
- imgui.get_style().item_spacing = ImVec2(6, 4) # Reduce spacing between items ((8, 4) by default)
- imgui.get_style().set_color_(imgui.Col_.text.value, (0.8, 0.8, 0.85, 1.0)) # Change text color
-
-
-##########################################################################
-# main(): here, we simply fill RunnerParams, then run the application
-##########################################################################
-def main():
- # By default, an assets folder is installed via pip inside site-packages/lg_imgui_bundle/assets
- # and provides two fonts (fonts/DroidSans.ttf and fonts/fontawesome-webfont.ttf)
- # If you need to add more assets, make a copy of this assets folder and add your own files,
- # and call set_assets_folder
- hello_imgui.set_assets_folder(demo_utils.demos_assets_folder())
-
- #
- # Part 1: Define the application state, fill the status and menu bars, and load additional font
- #
-
- # Our application state
- app_state = AppState()
-
- # Hello ImGui params (they hold the settings as well as the Gui callbacks)
- runner_params = hello_imgui.RunnerParams()
- runner_params.app_window_params.window_title = "Docking Demo"
- runner_params.imgui_window_params.menu_app_title = "Docking Demo"
- runner_params.app_window_params.window_geometry.size = (1000, 900)
- runner_params.app_window_params.restore_previous_geometry = True
- runner_params.app_window_params.borderless = True
- runner_params.app_window_params.borderless_movable = True
- runner_params.app_window_params.borderless_resizable = True
- runner_params.app_window_params.borderless_closable = True
-
- # Set LoadAdditionalFonts callback
- runner_params.callbacks.load_additional_fonts = lambda: load_fonts(app_state)
-
- #
- # Status bar
- #
- # We use the default status bar of Hello ImGui
- runner_params.imgui_window_params.show_status_bar = True
- # Add custom widgets in the status bar
- runner_params.callbacks.show_status = lambda: status_bar_gui(app_state)
- # uncomment next line in order to hide the FPS in the status bar
- # runner_params.im_gui_window_params.show_status_fps = False
-
- #
- # Menu bar
- #
- # Here, we fully customize the menu bar:
- # by setting `show_menu_bar` to True, and `show_menu_app` and `show_menu_view` to False,
- # HelloImGui will display an empty menu bar, which we can fill with our own menu items via the callback `show_menus`
- runner_params.imgui_window_params.show_menu_bar = True
- runner_params.imgui_window_params.show_menu_app = False
- runner_params.imgui_window_params.show_menu_view = False
- # Inside `show_menus`, we can call `hello_imgui.show_view_menu` and `hello_imgui.show_app_menu` if desired
- runner_params.callbacks.show_menus = lambda: show_menu_gui(runner_params)
- # Optional: add items to Hello ImGui default App menu
- runner_params.callbacks.show_app_menu_items = show_app_menu_items
-
- #
- # Top and bottom toolbars
- #
- # toolbar options
- edge_toolbar_options = hello_imgui.EdgeToolbarOptions()
- edge_toolbar_options.size_em = 2.5
- edge_toolbar_options.window_bg = ImVec4(0.8, 0.8, 0.8, 0.35)
- # top toolbar
- runner_params.callbacks.add_edge_toolbar(
- hello_imgui.EdgeToolbarType.top,
- lambda: show_top_toolbar(app_state),
- edge_toolbar_options,
- )
- # right toolbar
- edge_toolbar_options.window_bg.w = 0.4
- runner_params.callbacks.add_edge_toolbar(
- hello_imgui.EdgeToolbarType.right,
- lambda: show_right_toolbar(app_state),
- edge_toolbar_options,
- )
-
- #
- # Load user settings at callbacks `post_init` and save them at `before_exit`
- #
- runner_params.callbacks.post_init = lambda: load_my_app_settings(app_state)
- runner_params.callbacks.before_exit = lambda: save_my_app_settings(app_state)
-
- # Change style
- runner_params.callbacks.setup_imgui_style = setup_my_theme
-
- #
- # Part 2: Define the application layout and windows
- #
-
- # First, tell HelloImGui that we want full screen dock space (this will create "MainDockSpace")
- runner_params.imgui_window_params.default_imgui_window_type = (
- hello_imgui.DefaultImGuiWindowType.provide_full_screen_dock_space
- )
- # In this demo, we also demonstrate multiple viewports: you can drag windows outside
- # out the main window in order to put their content into new native windows
- runner_params.imgui_window_params.enable_viewports = True
- # Set the default layout (this contains the default DockingSplits and DockableWindows)
- runner_params.docking_params = create_default_layout(app_state)
- # Add alternative layouts
- runner_params.alternative_docking_layouts = create_alternative_layouts(app_state)
-
- #
- # Part 3: Where to save the app settings
- #
- # tag::app_settings[]
- # By default, HelloImGui will save the settings in the current folder.
- # This is convenient when developing, but not so much when deploying the app.
- # You can tell HelloImGui to save the settings in a specific folder: choose between
- # current_folder
- # app_user_config_folder
- # app_executable_folder
- # home_folder
- # temp_folder
- # documents_folder
- #
- # Note: app_user_config_folder is:
- # AppData under Windows (Example: C:\Users\[Username]\AppData\Roaming)
- # ~/.config under Linux
- # "~/Library/Application Support" under macOS or iOS
- runner_params.ini_folder_type = hello_imgui.IniFolderType.app_user_config_folder
-
- # runnerParams.ini_filename: this will be the name of the ini file in which the settings
- # will be stored.
- # In this example, the subdirectory Docking_Demo will be created under the folder defined
- # by runnerParams.ini_folder_type.
- #
- # Note: if ini_filename is left empty, the name of the ini file will be derived
- # from app_window_params.window_title
- runner_params.ini_filename = "Docking_Demo/Docking_demo.ini"
- # end::app_settings[]
-
- #
- # Part 4: Run the app
- #
- hello_imgui.run(runner_params)
-
-
-if __name__ == "__main__":
- main()
diff --git a/gui.py b/gui.py
index 0128e8e..1565dd5 100644
--- a/gui.py
+++ b/gui.py
@@ -1,47 +1,96 @@
-from imgui_bundle import imgui, immapp
-import glfw
-import OpenGL.GL as gl
-from datatypes import *
-from view import View
+# Custom
+from model import *
+from appstate import AppState
-class GUI(object):
- def __init__(self):
- super().__init__()
+# Layouts
+from analyzer import analyzer_layout
+from database import database_editor_layout
+
+# External
+from imgui_bundle import imgui, immapp, hello_imgui, ImVec2
+
+# Built In
+import shelve
+from typing import List
+
+def menu_bar(runner_params: hello_imgui.RunnerParams) -> None:
+ hello_imgui.show_app_menu(runner_params)
+ hello_imgui.show_view_menu(runner_params)
+ if imgui.begin_menu("File"):
+ clicked, _ = imgui.menu_item("Open", "", False)
+ if clicked:
+ pass
+ imgui.end_menu()
+
+def status_bar(app_state: AppState) -> None:
+ imgui.text("Student Analyzer by @DerGrumpf")
+
+def main() -> None:
+ app_state = AppState()
- # self.io = imgui.get_io()
+ # Load Database
+ with shelve.open("state") as state:
+ v = state.get("DB")
+ if v:
+ db.init(v)
+ db.connect()
+ db.create_tables([Class, Student, Lecture, Submission])
+ app_state.update()
- # Global GUI Setting
- '''win_w, win_h = glfw.get_window_size(self.window)
- fb_w, fb_h = glfw.get_framebuffer_size(self.window)
- font_scaling_factor = max(float(fb_w) / win_w, float(fb_h) / win_h)
- font_size_in_pixels = 30
- self.io.fonts.add_font_from_file_ttf("assets/MPLUSRounded1c-Regular.ttf", font_size_in_pixels * font_scaling_factor)
- self.io.font_global_scale /= font_scaling_factor'''
-
- self.view = View()
+ # Set Asset Folder
+ #hello_imgui.set_assets_folder()
- def header(self):
- imgui.set_next_window_size(io.display_size.x, io.display_size.y*0.03)
- imgui.set_next_window_position(0, io.display_size.y*0.02)
+ # Set Theme
- with imgui.begin("HEADER", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE | imgui.WINDOW_NO_TITLE_BAR):
- imgui.set_window_font_scale(1.3)
- text = "Student Analyzer"
- ww = imgui.get_window_size().x
- tw = imgui.calc_text_size(text).x
- imgui.set_cursor_pos_x((ww - tw) * 0.5)
- imgui.text("Student Analyzer")
-
- def __call__(self):
- self.view()
+ # Set Window Params
+ runner_params = hello_imgui.RunnerParams()
+ runner_params.app_window_params.window_title = "Analyzer"
+ runner_params.imgui_window_params.menu_app_title = "Analyzer"
+ runner_params.app_window_params.window_geometry.size = (1000, 900)
+ runner_params.app_window_params.restore_previous_geometry = True
+ runner_params.app_window_params.borderless = True
+ runner_params.app_window_params.borderless_movable = True
+ runner_params.app_window_params.borderless_resizable = True
+ runner_params.app_window_params.borderless_closable = True
+ # Load Fonts
+ #runner_params.callbacks.load_additional_fonts = lambda: f()
-
-if __name__ == "__main__":
- immapp.run(
- gui_function=GUI(),
- window_title="Student Analyzer",
- window_size_auto=True,
- with_implot=True,
- with_markdown=True
+ # Status Bar & Main Menu
+ runner_params.imgui_window_params.show_menu_bar = True
+ runner_params.imgui_window_params.show_menu_app = False
+ runner_params.imgui_window_params.show_menu_view = False
+ runner_params.imgui_window_params.show_status_bar = True
+ # Inside `show_menus`, we can call `hello_imgui.show_view_menu` and `hello_imgui.show_app_menu` if desired
+ runner_params.callbacks.show_menus = lambda: menu_bar(runner_params)
+ # Optional: add items to Hello ImGui default App menu
+ #runner_params.callbacks.show_app_menu_items = show_app_menu_items
+ runner_params.callbacks.show_status = lambda: status_bar(app_state)
+
+ # Application layout
+ runner_params.imgui_window_params.default_imgui_window_type = (
+ hello_imgui.DefaultImGuiWindowType.provide_full_screen_dock_space
)
+ runner_params.imgui_window_params.enable_viewports = True
+
+ runner_params.docking_params = analyzer_layout(app_state)
+ runner_params.alternative_docking_layouts = [
+ database_editor_layout(app_state)
+ ]
+
+ # Save App Settings
+ runner_params.ini_folder_type = hello_imgui.IniFolderType.app_user_config_folder
+ runner_params.ini_filename = "Analyzer/Analyzer.ini"
+
+ # Uncomment if layout will stay the same at start
+ runner_params.docking_params.layout_condition = hello_imgui.DockingLayoutCondition.application_start
+
+ # Run it
+ add_ons_params = immapp.AddOnsParams()
+ add_ons_params.with_markdown = True
+ add_ons_params.with_implot = True
+ add_ons_params.with_implot3d = True
+ immapp.run(runner_params, add_ons_params)
+
+if __name__ == "__main__":
+ main()
diff --git a/lecture_editor.py b/lecture_editor.py
deleted file mode 100644
index 235f082..0000000
--- a/lecture_editor.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from imgui_bundle import imgui
-from datatypes import *
-
-from model import *
-
-class LectureEditor:
- def __init__(self):
- super().__init__()
-
- self.select = 0
- self.add_lecture_text = str()
- self.add_lecture_points = 0
-
- def __call__(self, clas: Class):
- id = clas.id if clas else None
- lectures = Lecture.select().where(Lecture.class_id == id) if id else None
-
- with imgui.begin("Lecture Editor", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
- imgui.text("Add Lecture")
- _, self.add_lecture_text = imgui.input_text("Title", self.add_lecture_text)
- if self.add_lecture_points < 0:
- self.add_lecture_points = 0
- _, self.add_lecture_points = imgui.input_int("Points", self.add_lecture_points)
-
- if imgui.button("Add"):
- Lecture.create(
- title=self.add_lecture_text,
- points=self.add_lecture_points,
- class_id=id
- )
-
- imgui.separator()
-
- if not lectures:
- imgui.text("No Lectures could be queried")
- return
-
- for n, lecture in enumerate(lectures, start=1):
- display = f"{n}. {lecture.title}"
- opened, _ = imgui.selectable(display, self.select == n-1)
- if opened:
- self.select = n-1
-
- return lectures[self.select]
diff --git a/main_menu.py b/main_menu.py
deleted file mode 100644
index 94c8a96..0000000
--- a/main_menu.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from imgui_bundle import imgui, imgui_ctx
-
-from datatypes import *
-
-class MainMenu:
- def __init__(self):
- super().__init__()
-
- self.new = False
- self.new_text = str()
-
- def __call__(self):
- if self.new:
- self.create_new_file()
-
- with imgui_ctx.begin_main_menu_bar() as main_menu_bar:
- if main_menu_bar:
- with imgui_ctx.begin_menu("File", True) as file_menu:
- if file_menu.visible:
- new, _ = imgui.menu_item("New", " ", False, True)
- if new:
- self.new = True
- imgui.menu_item("Open", " ", False, True)
- imgui.menu_item("Save", " ", False, True)
- imgui.menu_item("Save as", " ", False, True)
- with imgui_ctx.begin_menu("View", True) as view_menu:
- if view_menu.visible:
- with imgui_ctx.begin_menu("Change Layout", True) as open_layout_menu:
- if open_layout_menu.visible:
- layout_options = list(LayoutOptions)
- for n, l in enumerate(layout_options):
- clicked = imgui.menu_item_simple(l.name.title())
- if clicked:
- return l
-
- def create_new_file(self):
- pass
diff --git a/model.py b/model.py
index 56aa96d..6036c92 100644
--- a/model.py
+++ b/model.py
@@ -123,10 +123,6 @@ def dump_to_json(fp: Path, indent=None) -> None:
with open(fp, "w") as file:
json.dump(d, file, indent=indent)
-db.init('test.db')
-db.connect()
-db.create_tables([Class, Student, Lecture, Submission])
-
def main():
import random
# Generate Test Data
@@ -166,4 +162,6 @@ def main():
if __name__ == "__main__":
# main()
+ db.init('wise_24_25.db')
+ db.connect()
dump_to_json(Path().cwd()/"TEST.json")
diff --git a/state b/state
new file mode 100644
index 0000000000000000000000000000000000000000..7135d886abbae2699c650eb6a672550df1e53fc6
GIT binary patch
literal 16384
zcmeIyu?>Pi6vpw>*jQoW0#4u=)Yuxr1{Rb?BM}l20uJB+mfARgtqZt=3z_Jhcf}R9
zCSv|1@D2)i{POO*pQEnm2=P8u(Y0;sMc1jm2=Oq5D*^~0fB*srAbbHE(156A&>fE*wP$N_SI93Th&EC(89SBslx7U94?_(IX&daC2o
zt9fozaKORcA9b0BtJjFaKy_~Oqp6nqwl4kCrF0fp-l2DmPL|oWKrhpa*<`}b}iMSNa9j1sw&=9GD>Ih+#k*TaeuWu
d_TB$xjQ|1&Ab lecture.points*0.3 else COLOR_TEXT_FAILED
- imgui.text_colored(display, *COLOR)
diff --git a/student_info.py b/student_info.py
deleted file mode 100644
index 325d695..0000000
--- a/student_info.py
+++ /dev/null
@@ -1,77 +0,0 @@
-from datatypes import *
-from imgui_bundle import imgui, imgui_ctx, imgui_md, implot, ImVec2
-import numpy as np
-
-from model import *
-
-class StudentInfo:
- def __init__(self):
- super().__init__()
- self.select_class = 0
- self.select_student = 0
-
- def student_graph(self, student_id: int) -> None:
- student = Student.get_by_id(student_id)
- clas = Class.get_by_id(student.class_id)
- lectures = Lecture.select().where(Lecture.class_id == clas.id)
- submissions = Submission.select().where(Submission.student_id == student.id)
-
- overall_points = np.sum([l.points for l in lectures])
- points = np.sum([sub.points for sub in submissions])
- if points.is_integer():
- points = int(points)
-
- subs_data = np.array([sub.points/l.points for sub, l in zip(submissions, lectures)])*100
- subs_labels = [str(l.title) for l in lectures]
-
- with imgui_ctx.begin_group():
- imgui_md.render(f"# {student.prename} {student.surname}")
- imgui_md.render(f"### {clas.name}")
-
- pb_content = f"{points}/{overall_points} {points/overall_points:.1%}"
- imgui.progress_bar(points/overall_points, overlay=pb_content)
-
- implot.push_colormap(implot.Colormap_.deep.value)
- if implot.begin_plot("Performance"):
- implot.setup_axes("Lectures", "Percentage")
- implot.setup_axes_limits(-1, len(subs_data), 0, 110)
- implot.setup_axis_ticks(implot.ImAxis_.x1.value, 0, len(subs_labels), len(subs_labels), subs_labels, False)
- implot.plot_bars("Submissions", subs_data)
- implot.end_plot()
-
- def student_list(self) -> int:
- classes = Class.select()
- content = [f"{n}. {c.name}" for n, c in enumerate(classes, start=1)]
- students = Student.select().where(Student.class_id == classes[self.select_class].id)
- lectures = Lecture.select().where(Lecture.class_id == classes[self.select_class].id)
-
- overall_points = np.sum([l.points for l in lectures])
- points = list()
- for student in students:
- submissions = Submission.select().where(Submission.student_id == student.id)
- cummultative = [sub.points for sub in submissions]
- passed = np.sum([p > overall_points*0.3 for p in cummultative])
- points.append((student, np.sum(cummultative)/overall_points, passed > 1))
-
- students = sorted(points, key=lambda x: x[1], reverse=True)
-
- with imgui_ctx.begin_group():
- _, self.select_class = imgui.combo("##class_list", self.select_class, content, len(content))
- for n, student in enumerate(students, start=1):
- s = student[0]
- display = f"{n}. {s.prename} {s.surname}"
- _, clicked = imgui.selectable(display, self.select_student == n-1)
- if clicked:
- self.select_student = n-1
-
- return students[self.select_student][0].id
-
- def __call__(self):
- with imgui_ctx.begin("Student Info"):
- w, h = imgui.get_window_size()
- with imgui_ctx.begin_child("Student Selector", ImVec2(w*0.25, h*0.9)):
- id = self.student_list()
- imgui.same_line()
- with imgui_ctx.begin_child("Student Graph", ImVec2(w*0.7, h*0.9)):
- self.student_graph(id)
-
diff --git a/student_list.py b/student_list.py
deleted file mode 100644
index 7ec48e3..0000000
--- a/student_list.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from model import *
-from imgui_bundle import imgui
-
-class StudentList:
- def __init__(self):
- super().__init__()
-
- self.select: int = 0
-
- def __call__(self, clas: Class):
- id = clas.id if clas else None
- students = Student.select().where(Student.class_id == id) if id else None
-
- with imgui.begin("Student Table", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
- if not students:
- imgui.text("No Dataset could be queried")
- return
-
- for n, student in enumerate(students, start=1):
- display = f"{n}. {student.prename} {student.surname}"
- opened, _ = imgui.selectable(display, self.select == n-1)
- if opened:
- self.select = n-1
-
- return students[self.select]
-
-
diff --git a/student_ranking.py b/student_ranking.py
deleted file mode 100644
index 6add0d0..0000000
--- a/student_ranking.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import numpy as np
-from imgui_bundle import imgui
-
-from model import *
-
-class StudentRanking:
- def __init__(self):
- super().__init__()
-
- def __call__(self):
- students = Student.select().where(Student.class_id == 1)
- lectures = Lecture.select().where(Lecture.class_id == 1)
-
- overall_points = sum([l.points for l in lectures])
-
- ranking = list()
- avg = list()
- for s in students:
- rank = sum([sub.points for sub in Submission.select().where(Submission.student_id == s.id)])/overall_points
- ranking.append((f"{s.prename} {s.surname}", rank))
- avg.append(rank)
- ranking = sorted(ranking, key=lambda x: x[1], reverse=True)
- avg = sum(avg)/len(avg)
-
- flag = True
-
- with imgui.begin("Student Ranking", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
- for n, rank in enumerate(ranking, start=1):
- if rank[1] < avg and flag:
- imgui.separator()
- flag = False
-
- imgui.text(f"{n}. {rank[0]} {rank[1]:.1%}")
-
- imgui.separator()
- imgui.text(f"Average: {avg:.1%}")
-
diff --git a/submission_editor.py b/submission_editor.py
deleted file mode 100644
index a231fe5..0000000
--- a/submission_editor.py
+++ /dev/null
@@ -1,66 +0,0 @@
-from imgui_bundle import imgui
-from model import *
-
-class SubmissionEditor:
- def __init__(self):
- super().__init__()
- self.current_lecture = 0
- self.current_student = 0
- self.points = 0
-
- def __call__(self, clas: Class):
- id = clas.id if clas else None
- lectures = Lecture.select().where(Lecture.class_id == id) if id else None
- students = Student.select().where(Student.class_id == id) if id else None
-
- with imgui.begin("Submission Editor", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
- imgui.text("Add Submission")
-
- if not lectures:
- imgui.text("No Lectures queried")
- return
-
- if not students:
- imgui.text("No Students queried")
- return
-
- _, self.current_lecture = imgui.combo("Lecture", self.current_lecture, [f"{l.title} ({l.points})" for l in lectures])
- _, self.current_student = imgui.combo("Student", self.current_student, [f"{s.prename} {s.surname}" for s in students])
-
- if self.points < 0:
- self.points = 0
-
- max = lectures[self.current_lecture].points
- if self.points > max:
- self.points = max
-
- _, self.points = imgui.input_float("Points", self.points, format='%.1f', step=0.5, step_fast=1.0)
-
- if imgui.button("Add"):
- if not Submission.select().where(
- Submission.student_id == students[self.current_student].id and
- Submission.lecture_id == lectures[self.current_lecture].id
- ):
- Submission.create(
- student_id=students[self.current_student].id,
- lecture_id=lectures[self.current_lecture].id,
- points=self.points
- )
-
- imgui.same_line()
-
- if imgui.button("Update"):
- submission = Submission.select().where(
- Submission.student_id == students[self.current_student].id and
- Submission.lecture_id == lectures[self.current_lecture].id
- ).get()
- submission.points = self.points
- submission.save()
-
- imgui.same_line()
-
- if imgui.button("Delete"):
- Submission.delete().where(
- Submission.student_id == students[self.current_student].id and
- Submission.lecture_id == lectures[self.current_lecture].id
- ).execute()
diff --git a/view.py b/view.py
deleted file mode 100644
index 9e3e55a..0000000
--- a/view.py
+++ /dev/null
@@ -1,65 +0,0 @@
-from imgui_bundle import imgui, ImVec2
-
-from datatypes import *
-
-from main_menu import MainMenu
-
-from database_editor import DatabaseEditor
-
-from student_info import StudentInfo
-
-def set_layout(size: tuple, pos: tuple) -> None:
- io = imgui.get_io()
- size = imgui.ImVec2(*size)
- pos = imgui.ImVec2(*pos)
- imgui.set_next_window_size(size)
- imgui.set_next_window_pos(pos)
-
-class GrapherLayout:
- def __init__(self):
- super().__init__()
-
- self.student_info = StudentInfo()
-
- def set_layout(self):
- pass
-
- def __call__(self):
- self.student_info()
-
-class EditorLayout:
- def __init__(self):
- super().__init__()
- self.database_editor = DatabaseEditor()
-
- def set_layout(self):
- pass
-
- def __call__(self):
- self.database_editor()
-
-class View:
- def __init__(self):
- super().__init__()
- self.current = LayoutOptions.GRAPHER
- self.main_menu = MainMenu()
- self.editor = EditorLayout()
- self.grapher = GrapherLayout()
-
- def switch_context(self, ctx: LayoutOptions) -> None:
- match ctx:
- case LayoutOptions.EDITOR:
- self.editor.set_layout()
- case LayoutOptions.GRAPHER:
- self.grapher.set_layout()
-
- def __call__(self):
- option = self.main_menu()
- if option:
- self.current = option
-
- if self.current == LayoutOptions.EDITOR:
- self.editor()
-
- if self.current == LayoutOptions.GRAPHER:
- self.grapher()