From f36b05e7957d94109f790d21dd161cdf6f1009f7 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Mon, 12 Feb 2024 20:52:56 -0500 Subject: [PATCH] Starting to layout scaffolding for UI based on RAD Debugger/Ryan's UI Series --- code/api.odin | 11 ++- code/collision.odin | 5 +- code/entity_box2.odin | 7 +- code/input.odin | 4 +- code/space.odin | 162 +++++++++++++++++++++----------- code/text.odin | 2 +- code/tick_render.odin | 11 ++- code/tick_update.odin | 42 ++++----- code/ui.odin | 212 ++++++++++++++++++++++++++++++++++++++++++ scripts/build.ps1 | 7 +- 10 files changed, 367 insertions(+), 96 deletions(-) create mode 100644 code/ui.odin diff --git a/code/api.odin b/code/api.odin index 4663966..af2ced9 100644 --- a/code/api.odin +++ b/code/api.odin @@ -91,7 +91,11 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^ { path_rec_mono_semicasual_reg := strings.concatenate( { Path_Assets, "RecMonoSemicasual-Regular-1.084.ttf" }) cstr := strings.clone_to_cstring( path_rec_mono_semicasual_reg ) - font_rec_mono_semicasual_reg = rl.LoadFontEx( cstr, 24, nil, 0 ) + + font_data, read_succeded : = os.read_entire_file( path_rec_mono_semicasual_reg ) + verify( ! read_succeded, fmt.tprintf("Failed to read font file for: %v", path_rec_mono_semicasual_reg) ) + + font_rec_mono_semicasual_reg = rl.LoadFontEx( cstr, cast(i32) points_to_pixels(24.0), nil, 0 ) delete( cstr) rl.GuiSetFont( font_rec_mono_semicasual_reg ) // TODO(Ed) : Does this do anything? @@ -99,6 +103,7 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^ log( "Default font loaded" ) } + // Demo project setup { using project path = "./" @@ -122,10 +127,10 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^ frame_1.color = Color_BG_TextBox // Frame is getting interpreted as points (It doesn't have to be, I'm just doing it...) - box_set_size( & frame_1, { 400, 200 } ) + box_set_size( & frame_1, { 50, 25 } * CM_Per_Point ) frame_2.color = Color_BG_TextBox_Green - box_set_size( & frame_2, { 350, 500 } ) + box_set_size( & frame_2, { 30, 50 } * CM_Per_Point ) // frame_1.position = { 1000, 1000 } } } diff --git a/code/collision.odin b/code/collision.odin index 4409a2c..7afbaf6 100644 --- a/code/collision.odin +++ b/code/collision.odin @@ -29,11 +29,12 @@ box_is_within_view :: proc( box : ^ Box2 ) -> b32 } screen_bounds := view_get_bounds() - box_bounds := box_get_bounds( box ) + bounds := box_get_bounds( box ) within_bounds : b32 = false -// TODO(Ed) : Should be easy to finish given the other impl... + // within_x_bounds : b32 = pos.x >= bounds.top_left.x && pos.x <= bounds.bottom_right.x + // within_y_bounds : b32 = pos.y >= bounds.bottom_right.y && pos.y <= bounds.top_left.y return within_bounds } diff --git a/code/entity_box2.odin b/code/entity_box2.odin index 3a975d1..6770395 100644 --- a/code/entity_box2.odin +++ b/code/entity_box2.odin @@ -4,10 +4,15 @@ import "core:encoding/json" import rl "vendor:raylib" +// TODO(Ed) : I made this before doing Ryan's UI series. It was my initial attempt at a "frame" +// conceptually that I need as an Entity primitive for all my 2D primitives that I would lay out +// in either world (workspace) space or in screenspace (fixed ui space) + Box2 :: struct { position : Vec2, extent : Extents2, - color : Color + color : Color, + layer : i32, } box_size :: proc( box : ^ Box2 ) -> AreaSize { diff --git a/code/input.odin b/code/input.odin index 11fd456..72a0669 100644 --- a/code/input.odin +++ b/code/input.odin @@ -22,7 +22,7 @@ pressed :: proc { } MaxKeyboardKeys :: 256 -KeyboardKey :: enum { +KeyboardKey :: enum u32 { null = 0x00, enter = 0x01, @@ -249,7 +249,7 @@ KeyboardState :: struct #raw_union { } MaxMouseBtns :: 16 -MouseBtn :: enum { +MouseBtn :: enum u32 { Left = 0x0, Middle = 0x1, Right = 0x2, diff --git a/code/space.odin b/code/space.odin index 8dd6aec..f6314ee 100644 --- a/code/space.odin +++ b/code/space.odin @@ -6,130 +6,182 @@ import rl "vendor:raylib" // an object from world space to screen-space. // This prototype engine will have all its spacial unit base for distances in centimetres. -Inches_To_Centimetre :: cast(f32) 2.54 -Points_Per_Centimetre := cast(f32) 28.3465 -Centimetres_Per_Point :: cast(f32) 1.0 / 28.3465 // Precalculated reciprocal for multiplication -DPT_DPC :: cast(f32) 72.0 * Inches_To_Centimetre +Inches_To_CM :: cast(f32)2.54 +Points_Per_CM :: cast(f32)28.3465 +CM_Per_Point :: cast(f32)1.0 / 28.3465 // Precalculated reciprocal for multiplication +DPT_DPC :: cast(f32)72.0 * Inches_To_CM when ODIN_OS == OS_Type.Windows { - os_default_dpc :: 96 * Inches_To_Centimetre + os_default_dpc :: 96 * Inches_To_CM // 1 inch = 2.54 cm, 96 inch * 2.54 = 243.84 DPC } -// points_to_cm :: proc( points : f32 ) -> f32 { -// return points * +cm_to_pixels :: proc { + f32_cm_to_pixels, + vec2_cm_to_pixels, +} + +pixels_to_cm :: proc { + f32_pixels_to_cm, + vec2_pixels_to_cm, +} + +points_to_pixels :: proc { + f32_points_to_pixels, + vec2_points_to_pixels, +} + + +//region Unit Conversion Impl + +// cm_to_points :: proc ( cm : f32 ) -> f32 { + // } -cm_to_pixels :: proc( cm : f32 ) -> f32 { +// points_to_cm :: proc( points : f32 ) -> f32 { +// screen_dpc := get_state().app_window.dpc +// cm_per_pixel := 1.0 / screen_dpc +// pixels := points * DPT_DPC * cm_per_pixel +// return points * +// } + +f32_cm_to_pixels :: proc(cm: f32) -> f32 { screen_dpc := get_state().app_window.dpc return cm * screen_dpc } -vec2_cm_to_pixels :: proc( v : Vec2 ) -> Vec2 { +f32_pixels_to_cm :: proc(pixels: f32) -> f32 { screen_dpc := get_state().app_window.dpc - return v * screen_dpc + cm_per_pixel := 1.0 / screen_dpc + return pixels * cm_per_pixel } -points_to_pixels :: proc( points : f32 ) -> f32 { +f32_points_to_pixels :: proc(points: f32) -> f32 { screen_dpc := get_state().app_window.dpc cm_per_pixel := 1.0 / screen_dpc return points * DPT_DPC * cm_per_pixel } -pixels_to_points :: proc( pixels : f32 ) -> f32 { +f32_pixels_to_points :: proc(pixels: f32) -> f32 { screen_dpc := get_state().app_window.dpc cm_per_pixel := 1.0 / screen_dpc - return pixels * cm_per_pixel * Points_Per_Centimetre + return pixels * cm_per_pixel * Points_Per_CM } -vec2_points_to_pixels :: proc ( vpoints : Vec2 ) -> Vec2 { +vec2_cm_to_pixels :: proc(v: Vec2) -> Vec2 { + screen_dpc := get_state().app_window.dpc + return v * screen_dpc +} + +vec2_pixels_to_cm :: proc(v: Vec2) -> Vec2 { + screen_dpc := get_state().app_window.dpc + cm_per_pixel := 1.0 / screen_dpc + return v * cm_per_pixel +} + +vec2_points_to_pixels :: proc(vpoints: Vec2) -> Vec2 { screen_dpc := get_state().app_window.dpc cm_per_pixel := 1.0 / screen_dpc return vpoints * DPT_DPC * cm_per_pixel } + +// vec2_points_to_cm :: proc ( vpoints : Vec2 ) -> Vec2 { + +// } + +//endregion + Camera :: rl.Camera2D +// TODO(Ed) : I'm not sure making the size and extent types distinct has made things easier or more difficult in Odin.. +// The lack of operator overloads is going to make any sort of nice typesystem +// for doing lots of math or phyiscs more error prone or filled with proc wrappers AreaSize :: distinct Vec2 Bounds2 :: struct { - top_left, bottom_right : Vec2 + top_left, bottom_right: Vec2, } BoundsCorners2 :: struct { - top_left, top_right, bottom_left, bottom_right : Vec2 + top_left, top_right, bottom_left, bottom_right: Vec2, } -Extents2 :: distinct Vec2 +Extents2 :: distinct Vec2 Extents2i :: distinct Vec2i -bounds2_radius :: proc( bounds : Bounds2 ) -> f32 { - return max( bounds.bottom_right.x, bounds.top_left.y ) +WS_Pos :: struct { + tile_id : Vec2i, + rel : Vec2, } -extent_from_size :: proc ( size : AreaSize ) -> Extents2 { - return transmute(Extents2) size * 2.0 +bounds2_radius :: proc(bounds: Bounds2) -> f32 { + return max(bounds.bottom_right.x, bounds.top_left.y) +} + +extent_from_size :: proc(size: AreaSize) -> Extents2 { + return transmute(Extents2)size * 2.0 } screen_size :: proc "contextless" () -> AreaSize { extent := get_state().app_window.extent - return transmute(AreaSize) (extent * 2.0) + return transmute(AreaSize)(extent * 2.0) } screen_get_corners :: proc() -> BoundsCorners2 { - state := get_state(); using state + state := get_state();using state screen_extent := state.app_window.extent - top_left := Vec2 { -screen_extent.x, screen_extent.y } - top_right := Vec2 { screen_extent.x, screen_extent.y } - bottom_left := Vec2 { -screen_extent.x, -screen_extent.y } - bottom_right := Vec2 { screen_extent.x, -screen_extent.y } - return { top_left, top_right, bottom_left, bottom_right } + top_left := Vec2{-screen_extent.x, screen_extent.y} + top_right := Vec2{screen_extent.x, screen_extent.y} + bottom_left := Vec2{-screen_extent.x, -screen_extent.y} + bottom_right := Vec2{screen_extent.x, -screen_extent.y} + return {top_left, top_right, bottom_left, bottom_right} } view_get_bounds :: proc() -> Bounds2 { - state := get_state(); using state - cam := & project.workspace.cam + state := get_state();using state + cam := &project.workspace.cam screen_extent := state.app_window.extent - top_left := cam.target + Vec2 { -screen_extent.x, screen_extent.y } - bottom_right := cam.target + Vec2 { screen_extent.x, -screen_extent.y } - return { top_left, bottom_right } + top_left := cam.target + Vec2{-screen_extent.x, screen_extent.y} + bottom_right := cam.target + Vec2{screen_extent.x, -screen_extent.y} + return {top_left, bottom_right} } view_get_corners :: proc() -> BoundsCorners2 { - state := get_state(); using state - cam := & project.workspace.cam + state := get_state();using state + cam := &project.workspace.cam cam_zoom_ratio := 1.0 / cam.zoom - screen_extent := state.app_window.extent * cam_zoom_ratio - top_left := cam.target + Vec2 { -screen_extent.x, screen_extent.y } - top_right := cam.target + Vec2 { screen_extent.x, screen_extent.y } - bottom_left := cam.target + Vec2 { -screen_extent.x, -screen_extent.y } - bottom_right := cam.target + Vec2 { screen_extent.x, -screen_extent.y } - return { top_left, top_right, bottom_left, bottom_right } + screen_extent := state.app_window.extent * cam_zoom_ratio + top_left := cam.target + Vec2{-screen_extent.x, screen_extent.y} + top_right := cam.target + Vec2{screen_extent.x, screen_extent.y} + bottom_left := cam.target + Vec2{-screen_extent.x, -screen_extent.y} + bottom_right := cam.target + Vec2{screen_extent.x, -screen_extent.y} + return {top_left, top_right, bottom_left, bottom_right} } -screen_to_world :: proc( pos : Vec2 ) -> Vec2 { - state := get_state(); using state - cam := & project.workspace.cam - return cam.target + pos * (1 / cam.zoom) +screen_to_world :: proc(pos: Vec2) -> Vec2 { + state := get_state();using state + cam := &project.workspace.cam + return vec2_pixels_to_cm(cam.target + pos * (1 / cam.zoom)) } -screen_to_render :: proc( pos : Vec2 ) -> Vec2 { - screen_extent := transmute(Vec2) get_state().project.workspace.cam.offset - return pos + { screen_extent.x, -screen_extent.y } +screen_to_render :: proc(pos: Vec2) -> Vec2 { + screen_extent := transmute(Vec2)get_state().project.workspace.cam.offset + return pos + {screen_extent.x, -screen_extent.y} } -world_screen_extent :: proc () -> Extents2 { - state := get_state(); using state +world_screen_extent :: proc() -> Extents2 { + state := get_state();using state cam_zoom_ratio := 1.0 / project.workspace.cam.zoom return app_window.extent * cam_zoom_ratio } -world_to_screen_pos :: proc( position : Vec2 ) -> Vec2 { - return { position.x, position.y * -1 } +world_to_screen_pos :: proc(position: Vec2) -> Vec2 { + return {position.x, position.y * -1} } -world_to_screen_no_zoom :: proc( position : Vec2 ) -> Vec2 { - state := get_state(); using state +world_to_screen_no_zoom :: proc(position: Vec2) -> Vec2 { + state := get_state();using state cam_zoom_ratio := 1.0 / state.project.workspace.cam.zoom - return { position.x, position.y * -1 } * cam_zoom_ratio + return {position.x, position.y * -1} * cam_zoom_ratio } diff --git a/code/text.odin b/code/text.odin index 44aae72..88c509d 100644 --- a/code/text.odin +++ b/code/text.odin @@ -3,7 +3,7 @@ package sectr import "core:unicode/utf8" import rl "vendor:raylib" -debug_draw_text :: proc( content : string, pos : Vec2, size : f32 = 16.0, color : rl.Color = rl.WHITE, font : rl.Font = {} ) +debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : rl.Font = {} ) { state := get_state(); using state diff --git a/code/tick_render.odin b/code/tick_render.odin index e68cf80..a8b2767 100644 --- a/code/tick_render.odin +++ b/code/tick_render.odin @@ -19,11 +19,12 @@ render :: proc() rl.BeginDrawing() rl.ClearBackground( Color_BG ) render_mode_2d() + // Render Screenspace { fps_msg := fmt.tprint( "FPS:", rl.GetFPS() ) - fps_msg_width := measure_text_size( fps_msg, default_font, 16.0, 0.0 ).x + fps_msg_width := measure_text_size( fps_msg, default_font, points_to_pixels(24.0), 0.0 ).x fps_msg_pos := screen_get_corners().top_right - { fps_msg_width, 0 } - debug_draw_text( fps_msg, fps_msg_pos, color = rl.GREEN ) + debug_draw_text( fps_msg, fps_msg_pos, points_to_pixels(24.0), color = rl.GREEN ) debug_text :: proc( format : string, args : ..any ) { @@ -42,7 +43,7 @@ render :: proc() position.y += debug.draw_debug_text_y content := fmt.bprintf( draw_text_scratch[:], format, ..args ) - debug_draw_text( content, position ) + debug_draw_text( content, position, points_to_pixels(24.0) ) debug.draw_debug_text_y += 16 } @@ -88,8 +89,8 @@ render_mode_2d :: proc() { } for box in boxes { - screen_pos := world_to_screen_pos(box.position) - Vec2(box.extent) - size := transmute(Vec2) box.extent * 2.0 + screen_pos := world_to_screen_no_zoom(box.position) - vec2_cm_to_pixels( Vec2(box.extent) ) + size := vec2_cm_to_pixels( transmute(Vec2) box.extent * 2.0 ) rect : rl.Rectangle rect.x = screen_pos.x diff --git a/code/tick_update.odin b/code/tick_update.odin index 2862611..11b99a1 100644 --- a/code/tick_update.odin +++ b/code/tick_update.odin @@ -158,34 +158,28 @@ update :: proc( delta_time : f64 ) -> b32 } } - // Frame 1 bounds detection - { - if debug_actions.mouse_select { - cursor_pos := screen_to_world( input.mouse.pos ) - - box_bounds := box_get_bounds(& project.workspace.frame_1) - within_x_bounds : b32 = cursor_pos.x >= box_bounds.top_left.x && cursor_pos.x <= box_bounds.bottom_right.x - within_y_bounds : b32 = cursor_pos.y >= box_bounds.bottom_right.y && cursor_pos.y <= box_bounds.top_left.y - - if within_x_bounds && within_y_bounds { - debug.frame_1_on_top = true - } - } + boxes : [2]^Box2 + boxes = { & project.workspace.frame_1, & project.workspace.frame_2 } + if debug.frame_1_on_top { + boxes = { & project.workspace.frame_2, & project.workspace.frame_1 } + } + else { + boxes = { & project.workspace.frame_1, & project.workspace.frame_2 } } - // Frame 2 bounds detection + if debug_actions.mouse_select { - if debug_actions.mouse_select { + for box in boxes + { cursor_pos := screen_to_world( input.mouse.pos ) - box_extent := & project.workspace.frame_2.extent - - box_bounds := box_get_bounds(& project.workspace.frame_2) - - within_x_bounds : b32 = cursor_pos.x >= box_bounds.top_left.x && cursor_pos.x <= box_bounds.bottom_right.x - within_y_bounds : b32 = cursor_pos.y >= box_bounds.bottom_right.y && cursor_pos.y <= box_bounds.top_left.y - - if within_x_bounds && within_y_bounds { - debug.frame_1_on_top = false + if box_is_within( box, cursor_pos ) + { + if box == & project.workspace.frame_1 { + debug.frame_1_on_top = true + } + else { + debug.frame_1_on_top = false + } } } } diff --git a/code/ui.odin b/code/ui.odin new file mode 100644 index 0000000..3465841 --- /dev/null +++ b/code/ui.odin @@ -0,0 +1,212 @@ +package sectr + +// Based off Ryan Fleury's UI Series & Epic's RAD Debugger which directly implements a version of it. +// You will see Note(rjf) these are comments directly from the RAD Debugger codebase by Fleury. +// TODO(Ed) If I can, I would like this to be its own package, but the nature of packages in odin may make this difficult. + +// TODO(Ed) : This is in Raddbg base_types.h, consider moving outside of UI. +Axis2 :: enum { + Invalid = -1, + X, + Y, + Count, +} + +UI_SizeKind :: enum u32 { + Null, + Pixels, + Points, + TextContent, + PercentOfParent, + ChildrenSum, +} + +UI_Size :: struct { + kind : UI_SizeKind, + value : f32, + strictness : f32, +} + +UI_Size2 : struct { + kind : [Axis2.Count]UI_SizeKind, + value : Vec2, + strictness : Vec2, +} + +UI_Layout :: struct { + placeholder : int +} + +UI_Key :: struct { + opaque : [1]u64, +} + +UI_BoxFlag :: enum u64 { + // Note(rjf) : Interaction + Mouse_Clickable, + Keyboard_Clickable, + Click_To_Focus, + Scroll, + View_Scroll_X, + View_Scroll_Y, + View_Clamp_X, + View_Clamp_Y, + Focus_Active, + Focus_Active_Disabled, + Focus_Hot, + Focus_Hot_Disabled, + Default_Focus_Nav_X, + Default_Focus_Nav_Y, + Default_Focus_Edit, + Focus_Nav_Skip, + Disabled, + + // Note(rjf) : Layout + Floating_X, + Floating_Y, + Fixed_Width, + Fixed_Height, + Allow_Overflow_X, + Allow_Overflow_Y, + Skip_View_Off_X, + Skip_View_Off_Y, + + // Note(rjf) : Appearance / Animation + Draw_Drop_Shadow, + Draw_Background_Blur, + Draw_Background, + Draw_Border, + Draw_Side_Top, + Draw_Side_Bottom, + Draw_Side_Left, + Draw_Side_Right, + Draw_Text, + Draw_Text_Fastpath_Codepoint, + Draw_Hot_Effects, + Draw_Overlay, + Draw_Bucket, + Clip, + Animate_Pos_X, + Animate_Pos_Y, + Disable_Text_Trunc, + Disable_ID_String, + Disable_Focus_Viz, + Require_Focus_Background, + Has_Display_String, + Has_Fuzzy_Match_Ranges, + Round_Children_By_Parent, +} +UI_BoxFlags :: bit_set[UI_BoxFlag; u64] + +UI_BoxFlags_Null :: UI_BoxFlags {} +UI_BoxFlags_Clickable :: UI_BoxFlags { .Mouse_Clickable, .Keyboard_Clickable } + +UI_NullLabel :: "" + +// Note(Ed) : This is called UI_Widget in the substack series, its called box in raddbg +// This eventually gets renamed by part 4 of the series to UI_Box. +// However, its essentially a UI_Node or UI_BaselineEntity, etc. +// Think of godot's Control nodes I guess. +UI_Box :: struct { + // Note(rjf) : persistent links + hash : struct { + next, prev : ^ UI_Box, + }, + + // Note(rjf) : Per-build links & data + first, last, prev, next : ^ UI_Box, + num_children : i32, + + // Note(rjf) : Key + generation info + key : UI_Key, + last_frame_touched_index : u64, + + // Note(rjf) : Per-frame info provided by builders + flags : UI_BoxFlags, + semantic_size : [Axis2.Count]UI_Size, + + // Note(rjf) : Computed every frame + computed_rel_pos : Vec2, + computed_size : Vec2, + //rect : Rng2F32 + + // Note(rjf) : Persistent data + hot : f32, + active : f32, + + // bg_color : Color, + // txt_color : Color, +} + +UI_Signal :: struct { + box : UI_Box, + cursor_pos : Vec2, + drag_delta : Vec2, + scroll : Vec2, + left_clicked : b8, + right_clicked : b8, + double_clicked : b8, + keyboard_clicked : b8, + pressed : b8, + released : b8, + dragging : b8, + hovering : b8, + mouse_over : b8, + commit : b8, +} + +ui_key_null :: proc() -> UI_Key { + return {} +} + +ui_key_from_string :: proc( value : string ) -> UI_Key { + return {} +} + +ui_key_match :: proc( a, b : UI_Key ) -> b32 { + return false +} + +ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box) { + return nil +} + +ui_box_equip_display_string :: proc( box : ^ UI_Box, display_string : string ) { + +} + +ui_box_equip_child_layout_axis :: proc( box : ^ UI_Box, axis : Axis2 ) { + +} + +ui_push_parent :: proc( box : ^ UI_Box ) -> (^ UI_Box) { + return nil +} + +ui_pop_parent :: proc() -> (^ UI_Box) { + return nil +} + +ui_signal_from_box :: proc( box : ^ UI_Box ) -> UI_Signal { + return {} +} + +ui_button :: proc( label : string ) -> UI_Signal { + button_flags : UI_BoxFlags = + UI_BoxFlags_Clickable & { + .Draw_Border, + .Draw_Text, + .Draw_Background, + .Focus_Hot, + .Focus_Active, + } + box := ui_box_make( button_flags, label ) + signal := ui_signal_from_box( box ) + return signal +} + +ui_spacer :: proc ( label : string = UI_NullLabel ) -> UI_Signal { + box := ui_box_make( UI_BoxFlags_Null, label ) + signal := ui_signal_from_box( box ) + return signal +} diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 062498a..c14cb8f 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -70,11 +70,13 @@ push-location $path_root write-host "`nBuilding Sectr Prototype" + $module_host = join-path $path_code 'host' + $module_sectr = $path_code + function build-host { $executable = join-path $path_build ($project_name + '_host.exe') $pdb = join-path $path_build ($project_name + '_host.pdb') - $module_host = join-path $path_code 'host' $host_process_active = Get-Process | Where-Object {$_.Name -like 'sectr_host*'} if ( $host_process_active ) { @@ -82,7 +84,7 @@ push-location $path_root return } - $should_build = check-ModuleForChanges $module_host + $should_build = (check-ModuleForChanges $module_host) if ( -not( $should_build)) { write-host 'Skipping sectr_host build, module up to date' return @@ -106,7 +108,6 @@ push-location $path_root function build-sectr { - $module_sectr = $path_code $should_build = check-ModuleForChanges $module_sectr if ( -not( $should_build)) { write-host 'Skipping sectr build, module up to date'