From 7635df42b4b306e10adfe004f58000fddd5d96c7 Mon Sep 17 00:00:00 2001
From: DerGrumpf
Date: Sun, 5 Jan 2025 01:01:39 +0100
Subject: [PATCH] Added: Layout Switcher
---
class_editor.py | 36 +++++++
datatypes.py | 15 +++
gui.py | 89 +++++++++++++++
lecture_editor.py | 45 ++++++++
main.py | 250 -------------------------------------------
main_menu.py | 26 +++++
model.py | 61 +++++++++++
student_editor.py | 42 ++++++++
student_graph.py | 27 +++++
student_info.py | 60 +++++++++++
student_list.py | 28 +++++
submission_editor.py | 67 ++++++++++++
test.db | Bin 0 -> 36864 bytes
view.py | 86 +++++++++++++++
14 files changed, 582 insertions(+), 250 deletions(-)
create mode 100644 class_editor.py
create mode 100644 datatypes.py
create mode 100644 gui.py
create mode 100644 lecture_editor.py
create mode 100644 main_menu.py
create mode 100644 model.py
create mode 100644 student_editor.py
create mode 100644 student_graph.py
create mode 100644 student_info.py
create mode 100644 student_list.py
create mode 100644 submission_editor.py
create mode 100644 test.db
create mode 100644 view.py
diff --git a/class_editor.py b/class_editor.py
new file mode 100644
index 0000000..de1d775
--- /dev/null
+++ b/class_editor.py
@@ -0,0 +1,36 @@
+import imgui
+
+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.begin("Class Editor", False, imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
+ 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/datatypes.py b/datatypes.py
new file mode 100644
index 0000000..74eb1be
--- /dev/null
+++ b/datatypes.py
@@ -0,0 +1,15 @@
+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/gui.py b/gui.py
new file mode 100644
index 0000000..1afddce
--- /dev/null
+++ b/gui.py
@@ -0,0 +1,89 @@
+import imgui
+import glfw
+import OpenGL.GL as gl
+from imgui.integrations.glfw import GlfwRenderer
+from datatypes import *
+from view import View
+
+def impl_glfw_init(window_name="Grapher Tool", width=1280, height=720):
+ if not glfw.init():
+ print("Could not initialize OpenGL context")
+ exit(1)
+
+ # OS X supports only forward-compatible core profiles from 3.2
+ glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
+ glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
+ glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
+
+ glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, gl.GL_TRUE)
+
+ # Create a windowed mode window and its OpenGL context
+ window = glfw.create_window(int(width), int(height), window_name, None, None)
+ glfw.make_context_current(window)
+
+ if not window:
+ glfw.terminate()
+ print("Could not initialize Window")
+ exit(1)
+
+ return window
+
+class GUI(object):
+ def __init__(self):
+ super().__init__()
+
+ # Window States
+ self.window = impl_glfw_init()
+ gl.glClearColor(*COLOR_BACKGROUND)
+ imgui.create_context()
+ self.impl = GlfwRenderer(self.window)
+ self.io = imgui.get_io()
+
+ # 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()
+ self.loop()
+
+ 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)
+
+ 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 loop(self):
+ while not glfw.window_should_close(self.window):
+ glfw.poll_events()
+ self.impl.process_inputs()
+ imgui.new_frame()
+
+ self.view()
+
+ #imgui.show_test_window()
+
+ imgui.render()
+
+ gl.glClearColor(*COLOR_BACKGROUND)
+ gl.glClear(gl.GL_COLOR_BUFFER_BIT)
+
+ self.impl.render(imgui.get_draw_data())
+ glfw.swap_buffers(self.window)
+
+ self.impl.shutdown()
+ glfw.terminate()
+
+
+if __name__ == "__main__":
+
+ gui = GUI()
diff --git a/lecture_editor.py b/lecture_editor.py
new file mode 100644
index 0000000..b7a2682
--- /dev/null
+++ b/lecture_editor.py
@@ -0,0 +1,45 @@
+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.py b/main.py
index 45817de..818b799 100644
--- a/main.py
+++ b/main.py
@@ -1,24 +1,6 @@
import imgui
-import glfw
-import OpenGL.GL as gl
-from imgui.integrations.glfw import GlfwRenderer
-from PIL import ImageColor
-from dataclasses import dataclass
import numpy
-@dataclass
-class Lecture:
- name: str
- points: float
- max_points: int
-
-@dataclass
-class Student:
- name: str
- jupyter_id: str
- project: str
- lectures: list
-
phil = Student(
"Phil Keier", "772fb04b24caa68fd38a05ec2a22e62b", "Geomapping",
[Lecture("1. Tutorial 1", 28.5, 31), Lecture("2. Tutorial 2", 4.5, 15), Lecture("3. Extended Application", 18, 18)]
@@ -33,239 +15,7 @@ kathi = Student(
)
students = [phil, nova, kathi]
-# 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")])
-
-def impl_glfw_init(window_name="Grapher Tool", width=1280, height=720):
- if not glfw.init():
- print("Could not initialize OpenGL context")
- exit(1)
-
- # OS X supports only forward-compatible core profiles from 3.2
- glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
- glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
- glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
-
- glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, gl.GL_TRUE)
-
- # Create a windowed mode window and its OpenGL context
- window = glfw.create_window(int(width), int(height), window_name, None, None)
- glfw.make_context_current(window)
-
- if not window:
- glfw.terminate()
- print("Could not initialize Window")
- exit(1)
-
- return window
-
-
-class GUI(object):
- def __init__(self):
- super().__init__()
- self.backgroundColor = COLOR_BACKGROUND
- self.window = impl_glfw_init()
- gl.glClearColor(*self.backgroundColor)
- imgui.create_context()
- self.impl = GlfwRenderer(self.window)
-
- # App states
- self.select_student: int = 0
- self.select_lecture: int = 0
- self.lectures: list = list()
- self.add_lecture_text = str()
- self.add_lecture_points = 0
- self.edit_lecture_title = str()
- self.edit_lecture_points = 0
-
- # 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
- io = imgui.get_io()
- io.fonts.add_font_from_file_ttf("assets/MPLUSRounded1c-Regular.ttf", font_size_in_pixels * font_scaling_factor)
- io.font_global_scale /= font_scaling_factor
-
- self.loop()
-
- def student_info(self, student: Student):
-
- # Window Position and Sizing
- io = imgui.get_io()
- imgui.set_next_window_size(io.display_size.x*0.3, io.display_size.y*0.4)
- imgui.set_next_window_position(io.display_size.x*0.7, io.display_size.y*0.05)
-
- # Student accumulated Info
- overall_points = sum([lecture.points for lecture in student.lectures])
- if overall_points.is_integer():
- overall_points = int(overall_points)
- overall_max = sum([lecture.max_points for lecture in student.lectures])
-
- with imgui.begin("Student Info", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
- if not student:
- imgui.text("No Student selected")
- return
-
- s = f"{overall_points}/{overall_max} | {round(overall_points/overall_max*100, 1)}%"
- imgui.text_colored(student.name, *COLOR_TEXT)
- w, h = imgui.get_window_size()
- imgui.progress_bar(overall_points/overall_max, (w*0.5, h*0.1), s)
- imgui.text("Jupyter ID:")
- imgui.text_colored(student.jupyter_id.rjust(4+len(student.jupyter_id), " "), *COLOR_TEXT)
-
- imgui.separator()
- imgui.text("Project:")
- imgui.text_colored(student.project.rjust(4+len(student.project), " "), *COLOR_TEXT)
- imgui.text("Lectures:")
- for lecture in student.lectures:
- COLOR = COLOR_TEXT_PASSED if lecture.points >= lecture.max_points/3 else COLOR_TEXT_FAILED
- s = f"{lecture.name}: {lecture.points}/{lecture.max_points}"
- imgui.text_colored(s.rjust(4+len(s), " "), *COLOR)
-
- def table(self, students: list):
-
- # Window Position and Sizing
- io = imgui.get_io()
- imgui.set_next_window_size(io.display_size.x*0.15, io.display_size.y*0.95)
- imgui.set_next_window_position(0, io.display_size.y*0.05)
-
- 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 selected")
- return
-
- for n, student in enumerate(students):
- opened, _ = imgui.selectable(student.name, self.select_student == n)
- if opened:
- self.select_student = n
-
-
- def student_graph(self, student: Student):
-
- # Window Position and Sizing
- io = imgui.get_io()
- imgui.set_next_window_size(io.display_size.x*0.55, io.display_size.y*0.4)
- imgui.set_next_window_position(io.display_size.x*0.15, io.display_size.y*0.05)
-
- # Setup Data
- data = numpy.array([float(lecture.points) / float(lecture.max_points) * 100 for lecture in student.lectures], dtype=numpy.float32)
-
- with imgui.begin("Student Graph", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
- if not students:
- imgui.text("No Dataset selected")
- return
- imgui.plot_histogram(
- "##Data", data, overlay_text="Performance per Lecture (in %)",
- scale_min=0.0, scale_max=100,
- graph_size=imgui.get_content_region_available()
- )
-
- def header(self):
-
- # Window Position and Sizing
- io = imgui.get_io()
- 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)
-
- 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 editor(self):
-
- # Window Position and Sizing
- io = imgui.get_io()
- imgui.set_next_window_size(io.display_size.x*0.3, io.display_size.y*0.3)
- imgui.set_next_window_position(io.display_size.x*0.7, io.display_size.y*0.45)
- lecture = None
-
- with imgui.begin("Lecture Editor", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
- with imgui.begin_group():
- if not self.lectures:
- imgui.text("No Lecture Added")
- else:
- for n, lecture in enumerate(self.lectures):
- opened, _ = imgui.selectable(lecture.name, self.select_lecture == n, width=imgui.get_window_size().x*0.3)
- if opened:
- self.select_lecture = n
- lecture = self.lectures[self.select_lecture]
- self.edit_lecture_title = lecture.name
- self.edit_lecture_points = lecture.max_points
-
- imgui.same_line(spacing=int(imgui.get_window_size().x * 0.05))
-
- with imgui.begin_group():
- imgui.push_item_width(imgui.get_window_size().x * 0.2)
- imgui.text("Add Lecture")
- _, self.add_lecture_text = imgui.input_text(" ", self.add_lecture_text)
- _, self.add_lecture_points = imgui.input_int("", self.add_lecture_points)
-
- if self.add_lecture_points < 0:
- self.add_lecture_points = 0
-
- clicked = imgui.button("Confirm")
- if clicked:
- self.lectures.append(Lecture(self.add_lecture_text, 0, self.add_lecture_points))
- self.add_lecture_points = 0
- self.add_lecture_text = str()
- imgui.pop_item_width()
-
- if lecture:
- imgui.same_line(spacing=int(imgui.get_window_size().x * 0.05))
- with imgui.begin_group():
- _, self.edit_lecture_title = imgui.input_text(" ", self.edit_lecture_title)
- _, self.edit_lecture_points = imgui.input_int("", self.edit_lecture_points)
- if self.edit_lecture_points < 0:
- self.edit_lecture_points = 0
-
- def main_menu(self):
- with imgui.begin_main_menu_bar() as main_menu_bar:
- if main_menu_bar:
- with imgui.begin_menu("File", True) as file_menu:
- if file_menu.opened:
- imgui.menu_item("New", " ", False, True)
- imgui.menu_item("Open", " ", False, True)
- imgui.menu_item("Save", " ", False, True)
- imgui.menu_item("Save as", " ", False, True)
-
- def loop(self):
- while not glfw.window_should_close(self.window):
- glfw.poll_events()
- self.impl.process_inputs()
- imgui.new_frame()
-
- self.main_menu()
- self.header()
- self.table(students)
- self.student_info(students[self.select_student])
- self.student_graph(students[self.select_student])
- self.editor()
- #imgui.show_test_window()
-
- imgui.render()
-
- gl.glClearColor(*self.backgroundColor)
- gl.glClear(gl.GL_COLOR_BUFFER_BIT)
-
- self.impl.render(imgui.get_draw_data())
- glfw.swap_buffers(self.window)
-
- self.impl.shutdown()
- glfw.terminate()
-
if __name__ == "__main__":
-
gui = GUI()
diff --git a/main_menu.py b/main_menu.py
new file mode 100644
index 0000000..a9a4e19
--- /dev/null
+++ b/main_menu.py
@@ -0,0 +1,26 @@
+import imgui
+
+from datatypes import *
+
+class MainMenu:
+ def __init__(self):
+ super().__init__()
+
+ def __call__(self):
+ with imgui.begin_main_menu_bar() as main_menu_bar:
+ if main_menu_bar:
+ with imgui.begin_menu("File", True) as file_menu:
+ if file_menu.opened:
+ imgui.menu_item("New", " ", False, True)
+ imgui.menu_item("Open", " ", False, True)
+ imgui.menu_item("Save", " ", False, True)
+ imgui.menu_item("Save as", " ", False, True)
+ with imgui.begin_menu("View", True) as view_menu:
+ if view_menu.opened:
+ with imgui.begin_menu("Change Layout", True) as open_layout_menu:
+ if open_layout_menu.opened:
+ layout_options = list(LayoutOptions)
+ for n, l in enumerate(layout_options):
+ clicked, _ = imgui.menu_item(l.name.title(), None, False, True)
+ if clicked:
+ return l
diff --git a/model.py b/model.py
new file mode 100644
index 0000000..b843d4d
--- /dev/null
+++ b/model.py
@@ -0,0 +1,61 @@
+from peewee import *
+from datetime import datetime
+
+db = SqliteDatabase('test.db')
+
+class BaseModel(Model):
+ class Meta:
+ database = db
+
+class Class(BaseModel):
+ name = CharField()
+ created_at = DateTimeField(default=datetime.now)
+
+class Student(BaseModel):
+ prename = CharField()
+ surname = CharField()
+ sex = CharField()
+ class_id = ForeignKeyField(Class, backref='class')
+ created_at = DateTimeField(default=datetime.now)
+
+class Lecture(BaseModel):
+ title = CharField()
+ points = IntegerField()
+ class_id = ForeignKeyField(Class, backref='class')
+ created_at = DateTimeField(default=datetime.now)
+
+class Submission(BaseModel):
+ student_id = ForeignKeyField(Student, backref='student')
+ lecture_id = ForeignKeyField(Lecture, backref='lecture')
+ points = FloatField()
+ created_at = DateTimeField(default=datetime.now)
+
+db.connect()
+db.create_tables([Class, Student, Lecture, Submission])
+
+if __name__ == "__main__":
+ import random
+ # Generate Test Data
+ class1 = Class.create(name="WiSe 22/23")
+ class2 = Class.create(name="WiSe 23/24")
+ class3 = Class.create(name="WiSe 24/25")
+
+ phil = Student.create(prename="Phil", surname="Keier", sex="Male", class_id=class1.id)
+ calvin = Student.create(prename="Calvin", surname="Brandt", sex="Male", class_id=class2.id)
+ nova = Student.create(prename="Nova", surname="Eib", sex="Female", class_id=class1.id)
+ kathi = Student.create(prename="Katharina", surname="Walz", sex="Female", class_id=class3.id)
+ victoria = Student.create(prename="Victoria", surname="Möller", sex="Female", class_id=class3.id)
+
+ lec1 = Lecture.create(title="Tutorial 1", points=30, class_id=class1.id)
+ lec2 = Lecture.create(title="Tutorial 1", points=30, class_id=class3.id)
+ lec3 = Lecture.create(title="Tutorial 2", points=20, class_id=class1.id)
+ lec4 = Lecture.create(title="Tutorial 2", points=20, class_id=class2.id)
+ lec5 = Lecture.create(title="Extended Applications", points=44, class_id=class1.id)
+
+ sub1_phil = Submission.create(student_id=phil.id, lecture_id=lec1.id, points=random.randint(0, lec1.points))
+ sub2_phil = Submission.create(student_id=phil.id, lecture_id=lec3.id, points=random.randint(0, lec3.points))
+ sub3_phil = Submission.create(student_id=phil.id, lecture_id=lec5.id, points=random.randint(0, lec5.points))
+ sub1_nova = Submission.create(student_id=nova.id, lecture_id=lec1.id, points=random.randint(0, lec1.points))
+ sub2_nova = Submission.create(student_id=nova.id, lecture_id=lec3.id, points=random.randint(0, lec3.points))
+ sub1_kathi = Submission.create(student_id=kathi.id, lecture_id=lec3.id, points=random.randint(0, lec3.points))
+ sub1_vici = Submission.create(student_id=victoria.id, lecture_id=lec2.id, points=random.randint(0, lec2.points))
diff --git a/student_editor.py b/student_editor.py
new file mode 100644
index 0000000..48566cb
--- /dev/null
+++ b/student_editor.py
@@ -0,0 +1,42 @@
+import imgui
+
+from model import *
+
+class StudentEditor:
+ def __init__(self):
+ super().__init__()
+
+ self.prename = str()
+ self.surname = str()
+ self.sex = True
+ self.current = 0
+
+ def __call__(self):
+ with imgui.begin("Student Editor", False, imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
+ imgui.text("Add Student")
+
+ _, self.prename = imgui.input_text("First Name", self.prename)
+ _, self.surname = imgui.input_text("Last Name", self.surname)
+
+ with imgui.begin_group():
+ if imgui.radio_button("Male", self.sex):
+ self.sex = True
+
+ imgui.same_line()
+
+ if imgui.radio_button("Female", not self.sex):
+ self.sex = False
+
+ classes = Class.select()
+ if classes:
+ _, self.current = imgui.combo("Classes", self.current, [c.name for c in classes])
+
+ if imgui.button("Confirm") and classes:
+ Student.create(
+ prename=self.prename,
+ surname=self.surname,
+ sex='Male' if self.sex else 'Female',
+ class_id = classes[self.current]
+ )
+ self.prename = str()
+ self.surname = str()
diff --git a/student_graph.py b/student_graph.py
new file mode 100644
index 0000000..04b29d3
--- /dev/null
+++ b/student_graph.py
@@ -0,0 +1,27 @@
+import imgui
+import numpy as np
+import random
+
+from model import *
+
+class StudentGraph:
+ def __init__(self):
+ super().__init__()
+
+ def __call__(self):
+ # Setup Data
+ submissions = Submission.select().where(Submission.student_id == 1)
+ data = np.array([submission.points/Lecture.get_by_id(submission.lecture_id).points*100 for submission in submissions], dtype=np.float32)
+
+ with imgui.begin("Student Graph", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
+
+ w, h = imgui.get_content_region_available()
+
+ imgui.plot_histogram(
+ "##Data", data, overlay_text="Performance per Lecture (in %)",
+ scale_min=0.0, scale_max=100,
+ graph_size=(w, h*0.9)
+ )
+
+ imgui.button("Text")
+
diff --git a/student_info.py b/student_info.py
new file mode 100644
index 0000000..f64171f
--- /dev/null
+++ b/student_info.py
@@ -0,0 +1,60 @@
+import imgui
+from datatypes import *
+
+from model import *
+
+class StudentInfo:
+ def __init__(self):
+ super().__init__()
+
+ def __call__(self, student: Student):
+ submissions = Submission.select().where(Submission.student_id == student.id) if student else None
+
+ with imgui.begin("Student Info", False, imgui.WINDOW_NO_MOVE | imgui.WINDOW_NO_RESIZE | imgui.WINDOW_NO_COLLAPSE):
+ if not student:
+ imgui.text("No Student selected")
+ return
+
+ w, h = imgui.get_window_size()
+ imgui.text_colored(f"{student.prename} {student.surname}", *COLOR_TEXT)
+
+ content = Class.get_by_id(student.class_id).name
+ text_size = imgui.calc_text_size(content)
+ imgui.same_line(position=w-1.5*text_size.x)
+ imgui.text(content)
+
+ if submissions:
+ overall_points = sum([s.points for s in submissions])
+ if overall_points.is_integer():
+ overall_points = int(overall_points)
+ overall_max = sum([lectures.points for lectures in [Lecture.get_by_id(s.lecture_id) for s in submissions]])
+ percentile = overall_points / overall_max
+ imgui.progress_bar(percentile, (w*0.5, h*0.05), f"{overall_points}/{overall_max} {percentile:.1%}")
+
+ content = "Delete"
+ if submissions:
+ text_size = imgui.calc_text_size(content)
+ imgui.same_line(position=w-2*text_size.x)
+ if imgui.button(content):
+ # Delete all Submissions related to that Student
+ #for submission in submissions:
+ # submission.delete().execute()
+ # Delete Student
+ #student.delete().execute()
+ return
+
+ imgui.separator()
+
+ if not submissions:
+ imgui.text("No Submission for this Student")
+
+ for n, submission in enumerate(submissions, start=1):
+ lecture = Lecture.get_by_id(submission.lecture_id)
+
+ points = submission.points
+ if points.is_integer():
+ points = int(points)
+
+ display = f"{n}. {lecture.title} {points}/{lecture.points}"
+ COLOR = COLOR_TEXT_PASSED if points > lecture.points*0.3 else COLOR_TEXT_FAILED
+ imgui.text_colored(display, *COLOR)
diff --git a/student_list.py b/student_list.py
new file mode 100644
index 0000000..23b2942
--- /dev/null
+++ b/student_list.py
@@ -0,0 +1,28 @@
+import imgui
+
+from model import *
+
+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/submission_editor.py b/submission_editor.py
new file mode 100644
index 0000000..9a3c728
--- /dev/null
+++ b/submission_editor.py
@@ -0,0 +1,67 @@
+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/test.db b/test.db
new file mode 100644
index 0000000000000000000000000000000000000000..f80bd51879fd882ffbc475487fd80fa2707b8aa8
GIT binary patch
literal 36864
zcmeI*%}*m`90%~3PTOH{;n}#7hOn;FAx4_zrSsMoPYy7wNGWT<#Z63bpksEDp~ZF}
z=*570*+0OWS8tw8Jo^u5Oib3q=w;W#dQcB|*@Mqa-=<~2HPOSucLMFa{GPYZuO)eS
z%CP=+$?(KV-5wGW&7+q+J)
z>C|gmuD#>!H|#B^+B+#MR7_*T6qn13=DVWQyAX<IQrh=;W?bvV9!y&%$6-D+{6Yc8b$1FtH#DpKbYSoQMrIYcs7|rHNM%k@qaxL!suc46{69fnWXSjA
z3vx)_qPy52009U<00Izz00bZa0SG_<0+&D_mq;>sRxr#%&!(SQs*1+mp6l#b9{to(
zb2@4!t!K5IT$qk0nKa898~a|p;aIMyycCOy){458S8sBDv=EMt3@+s5Y;HO>P_=x6
zi;T_}3dQ10cA#qcMs#pilk>wgqY3huAy3I4PJ00Izz00bZa0SG_<
z0uX?}g%pT$0-H#1EE|jayPUtv#W+q7g7yE=rwsX)d`?`V(_L&3fB*y_009U<00Izz
z00bZafeR&&Pw>pk6XUFL$Jq(i>{q|}%609=lD%uWcJvB+PFC_+Jrf7%hEPdV}fz}p5w0Aj@|GJM7BZyEI^lA>;I2h>;ETo{r}O0N-+il
z0SG_<0uX=z1Rwwb2tWV=5V$-7!E%4F{?GN+|6|?tf1bn`@)P-*d`3PbCGr|Q#0CKf
zKmY;|fB*y_009U<00I!WU;>kTlK#&-)=0!sQOo3du8=FLlgU<4oEwS^(u?_AagyFS
zz^{qphNFYBIZc=7Z30+<1__Zd8eR9#O7!Lcg5Ra9kuj>G74)s+E#RTWVN8H{`x;pe)QM>{~~{q-{?I6exZlhAOHafKmY;|fB*y_009U<00Izr
zE(H8V{{-(p#*?Q$0N~#RAXxuz&Ho?z^ZzI0AvqzB$j{{W=VE~9Bm^J;0SG_<0uX=z
g1Rwwb2tWV={**r!O#iv|^xvQJ$AjMrgzo?MH`#febpQYW
literal 0
HcmV?d00001
diff --git a/view.py b/view.py
new file mode 100644
index 0000000..24ca2f2
--- /dev/null
+++ b/view.py
@@ -0,0 +1,86 @@
+import imgui
+
+from datatypes import *
+
+from main_menu import MainMenu
+
+from student_editor import StudentEditor
+from student_list import StudentList
+from student_info import StudentInfo
+from class_editor import ClassEditor
+from lecture_editor import LectureEditor
+from submission_editor import SubmissionEditor
+
+from student_graph import StudentGraph
+
+def set_layout(size: tuple, pos: tuple) -> None:
+ io = imgui.get_io()
+ imgui.set_next_window_size(
+ io.display_size.x*size[0],
+ io.display_size.y*size[1]
+ )
+ imgui.set_next_window_position(
+ io.display_size.x*pos[0],
+ io.display_size.y*pos[1]
+ )
+
+class GrapherLayout:
+ def __init__(self):
+ super().__init__()
+
+ self.student_graph = StudentGraph()
+
+ def __call__(self):
+ set_layout((0.7, 0.4), (0.1, 0.1))
+ self.student_graph()
+
+class EditorLayout:
+ def __init__(self):
+ super().__init__()
+ self.io = imgui.get_io()
+
+ self.student_editor = StudentEditor()
+ self.student_list = StudentList()
+ self.student_info = StudentInfo()
+ self.class_editor = ClassEditor()
+ self.lecture_editor = LectureEditor()
+ self.submission_editor = SubmissionEditor()
+
+ def __call__(self):
+ set_layout((0.3, 0.3), (0.7, 0.4))
+ clas = self.class_editor()
+
+ set_layout((0.5, 0.3), (0.2, 0.4))
+ self.student_editor()
+
+ set_layout((0.2, 0.98), (0, 0.02))
+ student = self.student_list(clas)
+
+ set_layout((0.3, 0.38), (0.7, 0.02))
+ self.student_info(student)
+
+ set_layout((0.5, 0.3), (0.2, 0.7))
+ self.lecture_editor(clas)
+
+ set_layout((0.5, 0.3), (0.2, 0.1))
+ self.submission_editor(clas)
+
+class View:
+ def __init__(self):
+ super().__init__()
+ self.io = imgui.get_io()
+ self.current = LayoutOptions.GRAPHER
+ self.main_menu = MainMenu()
+ self.editor = EditorLayout()
+ self.grapher = GrapherLayout()
+
+ 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()