u/Due_Engineer_7647

▲ 38 r/raylib+2 crossposts

Nevu UI has been updated to v0.7.5

Changelog: https://github.com/GolemBebrov/nevu-ui/releases/tag/v,

0.7.5

This update focuses on improving quality and shorten length of code! also improving performance

Please star my project, on github, i will really appreciate it!

Code of the program on the video:

import nevu_ui as nv #(0.7.5, tested on: python 3.14.2)
import pygame #(pygame-ce)
import sys
import pyray as rl
pygame.init()


GLOBAL_FONT = "tests/vk_font.ttf" # CHANGE IT!!! if you wnant to change font


def create_border(name):
    return nv.BorderConfig(name = name, font = nv.load_font(GLOBAL_FONT, 20))


class UI:
    def __init__(self, root, res):
        self.root = root
        self.generate_base_constants()
        self.create_menu_base(res)
        self.create_menu_left(res)
        self.create_menu_scr(res)
        self.create_menu_group(res)


    def generate_base_constants(self):
        self.widget_style = nv.default_style(border_radius=5, border_width=0, colortheme=nv.ColorThemeLibrary.dracula, font_name=GLOBAL_FONT)
             
        self.widget_style2 = self.widget_style(border_radius=15*2)
        
        self.widget_size_s = (100, 50)
        self.widget_size_m = (150, 50)
        self.widget_size_l = (200, 50)
        self.widget_size_x = (250, 75) 
        self.widget_size_xl = (300, 50)
        self.widget_size_xxl = (400, 50)
        
        self.widget_kwargs = {"size": self.widget_size_l, "style": self.widget_style, "single_instance": True}
        self.widget_kwargs2 = {"size": self.widget_size_m, "style": self.widget_style2, "single_instance": True}
    
    def _on_style_click(self, *args, **kwargs):
        colotheme = args[1]
        self.menu.apply_style_patch_to_layout(colortheme=colotheme) 
        self.menu_left.apply_style_patch_to_layout(colortheme=colotheme)
    
    def create_menu_base(self, res):
        nv.nevu_object_globals.modify(**self.widget_kwargs)
        with nv.widget_globals.modify_temp(size = self.widget_size_s, style = self.widget_style(font_size = 25), subtheme_role=nv.SubThemeRole.TERTIARY):
            self.x = nv.Label("X:NAN", self.widget_size_s, self.widget_style(font_size=25))
            self.y = nv.Label("Y:NAN", self.widget_size_s, self.widget_style(font_size=25))
        
        coords_lay = nv.StackColumn(
            content = [
                (nv.Align.CENTER, self.x),
                (nv.Align.CENTER, self.y)
            ])
        
        self.mode = nv.ElementSwitcher(elements = ["Tile","Script","Group"], on_content_change = self.root.on_change_mode)
        mode_layout = nv.StackColumn(
            content = [
                (nv.Align.CENTER, nv.Label("Mode:", self.widget_size_l, subtheme_role = nv.SubThemeRole.TERTIARY)),
                (nv.Align.CENTER, self.mode)
            ])
        
        with nv.widget_globals.modify_temp(subtheme_role = nv.SubThemeRole.PRIMARY, style = self.widget_style2, size=50, active_rect_factor=0.8): #type: ignore
            self.wall = nv.RectCheckBox(on_toggle = self.root.stub)
            is_wall_layout = nv.StackRow(
                content = [
                    (nv.Align.CENTER, nv.Label("Wall:", self.widget_size_l)),
                    (nv.Align.CENTER, self.wall)
                ]
            )


            self.passable =  nv.RectCheckBox(on_toggle = self.root.stub, toggled=True)
            is_passable_layout = nv.StackRow(
                content = [
                    (nv.Align.CENTER, nv.Label("Passable:", self.widget_size_l)),
                    (nv.Align.CENTER, self.passable)
                ]
            )


        tile_attrs_layout = nv.StackColumn(
            content = [
                (nv.Align.CENTER, is_wall_layout),
                (nv.Align.CENTER, is_passable_layout)
            ], borders = create_border(name = "Traits")
        )
        
        file_layout = nv.StackRow(
            content = [
                (nv.Align.CENTER, nv.Label("TBD...", subtheme_role = nv.SubThemeRole.TERTIARY))
            ], borders = create_border(name = "Files")
        )
        
        left_panel_layout = nv.StackColumn(
            content = [
                (nv.Align.CENTER, tile_attrs_layout),
                (nv.Align.CENTER, file_layout)
            ]
        ) 
        white_line = nv.Widget((300, 3), self.widget_style(border_radius=5, border_width=0), single_instance = False,)
        with nv.widget_globals.modify_temp(**self.widget_kwargs2):
            scene_layout = nv.StackColumn(
                content = [
                    (nv.Align.CENTER, nv.Button(self.root.stub,"Save")),
                    (nv.Align.CENTER, white_line),
                    (nv.Align.CENTER, nv.Button(self.root.stub,"Load")),
                    (nv.Align.CENTER, white_line),
                    (nv.Align.CENTER, nv.Button(self.root.stub,"New")),
                ], borders = create_border(name = "Scene")
            )


            self.obj_lbl = nv.Label("Object", style=self.widget_style(border_radius=(0,15,15,0)))
            self.obj_btn = nv.Button(self.root.stub, "+", size=(50,50), style=self.widget_style(border_radius=(15,0,0,15)))
            pl_object_stack = nv.StackRow(
                content = [
                    (nv.Align.CENTER, self.obj_btn), (nv.Align.CENTER, self.obj_lbl)
                ], spacing = 2
            )
            
            self.door_lbl = nv.Label("+ Door", style=self.widget_style(border_radius=(0,15,15,0)))
            self.door_btn = nv.Button(self.root.stub, "+", size=(50,50), style=self.widget_style(border_radius=(15,0,0,15)))
            pl_door_stack = nv.StackRow(
                content = [
                    (nv.Align.CENTER, self.door_btn), (nv.Align.CENTER, self.door_lbl)
                ], spacing = 2
            )
            
            objects_layout = nv.StackColumn(
                content=[(nv.Align.CENTER, pl_object_stack),
                        (nv.Align.CENTER, pl_door_stack),
                ], borders = create_border(name = "Objects")
            )
        
        self.stylechk = nv.ElementSwitcher(self.widget_size_m, [["Material", nv.ColorThemeLibrary.material3_green], ["MaterialAlt", nv.ColorThemeLibrary.material3_dark],
                                                                ["Cat Dark", nv.ColorThemeLibrary.catppuccin_mocha], ["Cat Light", nv.ColorThemeLibrary.catppuccin_latte],
                                                                ["Box Dark", nv.ColorThemeLibrary.gruvbox_dark], ["Box Light", nv.ColorThemeLibrary.gruvbox_light],
                                                                ["Guthib", nv.ColorThemeLibrary.github_dark], ["Pastel", nv.ColorThemeLibrary.pastel_rose_light],
                                                                [1,nv.ColorThemeLibrary.dracula]
                                                                ], self.widget_style2, on_content_change = self._on_style_click)
        self.stylechklbl = nv.Label("Style:", self.widget_size_s, self.widget_style, subtheme_role = nv.SubThemeRole.TERTIARY)
        
        style_layout = nv.StackColumn(
            content = [
                (nv.Align.CENTER, self.stylechklbl),
                (nv.Align.CENTER, self.stylechk)
            ]
        )
        
        self.layer = nv.ElementSwitcher(self.widget_size_s, ["0","1","2","3","4","5","6","7","8","9","10"], self.widget_style2, on_content_change = self.root.stub)
        self.layerlbl = nv.Label("layer:", self.widget_size_s, self.widget_style, subtheme_role = nv.SubThemeRole.TERTIARY)
        
        layer_layout = nv.StackColumn(
            content = [
                (nv.Align.CENTER, self.layerlbl),
                (nv.Align.CENTER, self.layer)
            ]
        )
        self.layer.disactivate()
        self.layer.hide()
        self.layerlbl.hide()
        layer_style_layout = nv.StackColumn(
            content = [
                (nv.Align.CENTER, style_layout),
                (nv.Align.CENTER, layer_layout)
            ]
        )
        
        main_layout = nv.Grid([nv.fill%100, nv.fill%100], x = 6, y = 1,
                            content = {
                                (1, 1): coords_lay,
                                (2, 1): left_panel_layout,
                                (3.3, 1): scene_layout,
                                (4.33, 1): objects_layout,
                                (5.3, 1): layer_style_layout,
                                (5, 1): nv.Widget([5,nv.fill%100], nv.default_style(border_width=0)),
                                (6, 1): mode_layout
                            }, borders = create_border(name = "REDATOR"))
                            
        self.menu = nv.Menu(window, [res[0], 300], layout=main_layout, style=self.widget_style(border_radius=0, border_width=0,))
        self.menu.set_coordinates(0, res[1]-300) #pls dont watch at this bad code aaaaaaaahh
        
    def create_menu_scr(self, res):
        self.menuscr = nv.Menu(window, [400,300])
        self.menuscr.set_coordinates(res[0]-400, res[1]-600)
        
        self.scriptE = nv.Input(self.widget_size_xl, self.widget_style2, "Not selected", whitelist = nv.InputType.ALL_LETTERS+nv.InputType.ALL_SYMBOLS, on_change_function=self.root.stub) 
        self.scriptL = nv.Input(self.widget_size_xl, self.widget_style2, "Not selected", whitelist = nv.InputType.ALL_LETTERS+nv.InputType.ALL_SYMBOLS, on_change_function=self.root.stub) 
        
        enter_layout = nv.StackColumn(spacing = 5,
                                content = [(nv.Align.CENTER, nv.Label("Enter:", [110,35], self.widget_style(border_radius=4, font_size=20))),
                                        (nv.Align.CENTER, self.scriptE)])
        exit_layout = nv.StackColumn(spacing = 5,
                                content = [(nv.Align.CENTER, nv.Label("Exit:", [110,35], self.widget_style(border_radius=4, font_size=20))),
                                        (nv.Align.CENTER, self.scriptL)])
        
        script_layout = nv.ScrollableColumn([400,300], spacing = 12,
                                content = [(nv.Align.CENTER, nv.Label("Script:", [nv.fill%60, 35], self.widget_style(font_size=20))),
                                        (nv.Align.CENTER, enter_layout),
                                        (nv.Align.CENTER, exit_layout)])
        
        self.menuscr.layout = script_layout
        
    def create_menu_group(self, res):
        self.menugroup = nv.Menu(window, [400,300], self.widget_style(colortheme=nv.ColorThemeLibrary.catppuccin_mocha))
        self.menugroup.set_coordinates(res[0]-400, res[1]-600)
        
        self.scr_name = nv.Input(self.widget_size_xxl, self.widget_style2(border_radius=0), "Not selected", whitelist = list(nv.InputType.ALL_LETTERS+nv.InputType.ALL_SYMBOLS), on_change_function=self.root.stub)
        self.groupE = nv.Input(self.widget_size_xl, self.widget_style2, "Entry", whitelist = list(nv.InputType.ALL_LETTERS+nv.InputType.ALL_SYMBOLS+" "+nv.InputType.NUMBERS), on_change_function=self.root.stub)
        self.groupL = nv.Input(self.widget_size_xl, self.widget_style2, "Exit", whitelist = list(nv.InputType.ALL_LETTERS+nv.InputType.ALL_SYMBOLS+" "+nv.InputType.NUMBERS), on_change_function=self.root.stub)
        self.groupC = nv.Input(self.widget_size_xl, self.widget_style2, "Inside", whitelist = list(nv.InputType.ALL_LETTERS+nv.InputType.ALL_SYMBOLS+" "+nv.InputType.NUMBERS), on_change_function=self.root.stub)


        name_lay = nv.StackColumn(
                            content = [(nv.Align.LEFT, nv.Label("Name(Important):", [200,35], self.widget_style(border_radius=(0,15,15,0), font_size=20))),
                                    (nv.Align.LEFT, self.scr_name)]
        )


        enter_lay = nv.StackColumn(spacing=5,
                            content = [(nv.Align.CENTER, nv.Label("Entry:", [110,35], self.widget_style(border_radius=4, font_size=20))),
                                    (nv.Align.CENTER, self.groupE)])


        exit_lay = nv.StackColumn(spacing=5,
                            content = [(nv.Align.CENTER, nv.Label("Exit:", [110,35], self.widget_style(border_radius=4, font_size=20))),
                                    (nv.Align.CENTER, self.groupL)])


        inside_lay = nv.StackColumn(spacing=5,
                            content = [(nv.Align.CENTER, nv.Label("Inside:", [110,35], self.widget_style(border_radius=4, font_size=20))),
                                    (nv.Align.CENTER, self.groupC)])



        script_group_panel = nv.ScrollableColumn([100%nv.fill, 100%nv.fill], spacing = 5, id = "scr",
            content=[
                (nv.Align.CENTER, nv.Label("Script Group:", self.widget_size_xl, self.widget_style(font_size=20))),
                (nv.Align.CENTER, name_lay),
                (nv.Align.CENTER, enter_lay),
                (nv.Align.CENTER, exit_lay),
                (nv.Align.CENTER, inside_lay)
            ])
        
        self.menugroup.layout = script_group_panel
        
    def create_menu_left(self, res):
        self.menu_left = nv.Menu(window, [300,1080-300], style=self.widget_style2(border_radius=0, border_width=0))
        lay2 = nv.ScrollableColumn([300,1080-300],)
        with nv.widget_globals.modify_temp(subtheme_role = nv.SubThemeRole.PRIMARY, style = self.widget_style2()):
            self.name = nv.Input((250,50),None,"Name","Name",whitelist=list(nv.InputType.ALL_SYMBOLS+nv.InputType.NUMBERS),on_change_function=self.root.stub, single_instance=True)
            self.desc = nv.Input((250,50),None,"Description",on_change_function=self.root.stub, single_instance=True)
        lay2.add_item(self.name,nv.Align.CENTER)
        lay2.add_item(self.desc,nv.Align.CENTER)
        
        self.graphity = nv.RectCheckBox(35,self.widget_style2, on_toggle =self.root.stub, active_rect_factor=0.85)
        self.graphity_slider = nv.Slider((200,30),self.widget_style2(font_size=10), current_value = 50, start = 50, end = 100,)
        
        lay3 = nv.StackColumn(
            content=[
                (nv.Align.CENTER, nv.Label("Graphity mode:",(200,50),self.widget_style2, subtheme_role = nv.SubThemeRole.TERTIARY)),
                (nv.Align.CENTER, nv.StackColumn(content=[(nv.Align.CENTER, self.graphity_slider),(nv.Align.CENTER, self.graphity)]))
            ])
            
        lay2.add_item(lay3,nv.Align.CENTER)
        self.menu_left.layout = lay2
        nv.Widget()
        
    def draw(self):
        
        self.menu.draw()
        self.menu_left.draw()
        if self.root.mode =="Script": self.menuscr.draw()
        if self.root.mode =="Group": self.menugroup.draw()


    def update(self):
        self.menu.update()
        self.menu_left.update()
        if self.root.mode =="Script": self.menuscr.update()
        if self.root.mode =="Group": self.menugroup.update()



class App():
    def __init__(self,res):
        global window #Antipattern detected Ow<
        self.size = (res[0],res[1])
        window = nv.Window(self.size, resizable=True, backend=nv.Backend.Pygame) 
        self.window = window
        self.mode = "Tile"
        self.ui = UI(self,[res[0],res[1]])
        
        pygame.display.set_caption("Nevu UI Demo")


    def stub(self, *args, **kwargs):
        print("Action triggered:", args, kwargs)


    def on_change_mode(self, val, id):
        self.mode = val
        print(f"Mode changed to: {self.mode}")
        
        if self.mode != "Group":
            self.ui.layer.disactivate()
            self.ui.layer.hide()
            self.ui.layerlbl.hide()
        else:
            self.ui.layer.activate()
            self.ui.layer.show()
            self.ui.layerlbl.show()
            
    def update(self):
        self.window.update(pygame.event.get(), 999999999) #no limitz
        self.ui.update()
        
    def draw(self):
        self.window.display.fill((20, 20, 25, 255))
        self.ui.draw()
        #window.draw_overlay() #to draw layout borders!! uOu
        
    def run(self):
        font = pygame.Font(GLOBAL_FONT, 20)
        draw_fps = True
        while True:
            window.begin_frame()
            self.update()
            self.draw()
            if draw_fps:
                if nv.nevu_state.window.is_dtype.raylib:
                    rl.draw_fps(0,0)
                else:
                    self.window.display.blit(font.render(f"FPS: {str(nv.time.fps)}", True, (255, 255, 255)), (10,10))
            window.end_frame()
        
if __name__ == "__main__":
    app = App((1900, 1080))
    app.run()
u/Due_Engineer_7647 — 3 days ago