Skip to content

Commit 78439e6

Browse files
committed
Working on UI updates
1 parent f2cee15 commit 78439e6

File tree

10 files changed

+194
-59
lines changed

10 files changed

+194
-59
lines changed

src/JulGame.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ module JulGame
2222
FONT_CACHE::Dict = Dict{String, Any}()
2323
AUDIO_CACHE::Dict = Dict{String, Any}()
2424

25+
BUILT_IN_ASSETS::Dict = Dict{String, Any}()
26+
BUILT_IN_ASSETS["Font"] = read(joinpath(@__DIR__, "engine", "Assets", "Fonts", "FiraCode-Regular.ttf"))
27+
2528
Coroutines::Vector = []
2629

2730
ProjectModule = ""

src/engine/Component/Sprite.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ module SpriteModule
216216
if !isfile(joinpath(BasePath, "assets", "images", imagePath))
217217
@error("Image file does not exist: $(imagePath)")
218218
this.image = load_fallback_image()
219-
this.imagePath = "fallback.png"
219+
setfield!(this, :imagePath, "fallback.png")
220220
this.pixelsPerUnit = 0
221221
if this.image == C_NULL
222222
@error("Fallback image also failed to load! $(unsafe_string(SDL2.SDL_GetError()))")
@@ -235,7 +235,7 @@ module SpriteModule
235235

236236
# Load from byte array
237237
this.image = load_fallback_image()
238-
this.imagePath = "fallback.png"
238+
setfield!(this, :imagePath, "fallback.png")
239239
this.pixelsPerUnit = 0
240240
if this.image == C_NULL
241241
@error("Fallback image also failed to load! $(unsafe_string(SDL2.SDL_GetError()))")

src/engine/SceneManagement/SceneReader.jl

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ module SceneReaderModule
146146

147147
function deserialize_ui_elements(jsonUIElements)
148148
res = []
149-
149+
default_Vector2 = Vector2(0,0)
150150
for uiElement in jsonUIElements
151151
try
152152
newUIElement = nothing
@@ -158,26 +158,22 @@ module SceneReaderModule
158158
end
159159

160160
newUIElement = TextBox(
161-
uiElement.name,
162-
uiElement.fontPath,
163-
Int(get(uiElement, "fontSize", 20)), # Use fontSize from JSON or default
164-
Vector2(uiElement.position.x, uiElement.position.y),
165-
get(uiElement, "text", " "),
166-
get(uiElement, "isCenteredX", false),
167-
get(uiElement, "isCenteredY", false);
168-
# Keyword arguments:
169-
anchorOffset = !haskey(uiElement, "anchorOffset") ? Vector2(0,0) : Vector2(uiElement.anchorOffset.x, uiElement.anchorOffset.y),
161+
get(uiElement, "text", " ");
170162
id = string(get(uiElement, "id", JulGame.generate_uuid())),
163+
name = get(uiElement, "name", "TextBox"),
164+
anchor = get(uiElement, "anchor", :center),
165+
anchorOffset = Vector2(get(uiElement, "anchorOffset", default_Vector2).x, get(uiElement, "anchorOffset", default_Vector2).y),
171166
isWorldEntity = get(uiElement, "isWorldEntity", false),
172167
layer = Int(get(uiElement, "layer", 0)),
168+
position = Vector2(get(uiElement, "position", default_Vector2).x, get(uiElement, "position", default_Vector2).y),
169+
isActive = get(uiElement, "isActive", true),
170+
persistentBetweenScenes = get(uiElement, "persistentBetweenScenes", false),
173171
color = color_tuple,
172+
fontPath = get(uiElement, "fontPath", "Default"),
173+
fontSize = Int(get(uiElement, "fontSize", 20)), # Use fontSize from JSON or default
174174
maxLineWidth = Int(get(uiElement, "maxLineWidth", 0)),
175175
wrapWords = get(uiElement, "wrapWords", true)
176-
# Note: isActive is handled after creation as it might affect centering
177176
)
178-
# Set isActive after potential centering logic inside TextBox initialization
179-
newUIElement.isActive = get(uiElement, "isActive", true)
180-
181177
else
182178
# For text offset, check if it should be centered (if not specified or all zeros)
183179
textOffset = Vector2(uiElement.textOffset.x, uiElement.textOffset.y)

src/engine/UI/ImmediateUI.jl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,9 @@ module ImmediateUIModule
368368
color::NTuple{4, Int}=(255, 255, 255, 255),
369369
borderWidth::Int=0, fillMode::Bool=true;
370370
isWorldEntity::Bool=false, borderColor::NTuple{4, Int}=(0, 0, 0, 255),
371-
borderRadius::Int=0, isActive::Bool=true, layer::Int=0, lifetime::Int=DEFAULT_LIFETIME)
371+
borderRadius::Int=0, isActive::Bool=true, layer::Int=0, lifetime::Int=DEFAULT_LIFETIME,
372+
clickEvent::Function=() -> nothing,
373+
hoverEnterEvent::Function=() -> nothing, hoverExitEvent::Function=() -> nothing)
372374

373375
# Convert colors to Int32 tuples
374376
color = (color[1],
@@ -457,6 +459,12 @@ module ImmediateUIModule
457459
if !(rect in MAIN.scene.uiElements)
458460
push!(MAIN.scene.uiElements, rect)
459461
end
462+
463+
if !isempty(rect.clickEvents)
464+
rect.clickEvents[1] = clickEvent
465+
else
466+
UI.add_click_event(rect, clickEvent)
467+
end
460468

461469
return rect
462470
else

src/engine/UI/Rectangle.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module RectangleModule
1919
borderColor::NTuple{4, Int}
2020
isHovered::Bool
2121
clickEvents::Vector{Function}
22+
hoverEvents::Vector{Function}
2223
layer::Int
2324
function Rectangle(name::String, position::Math.Vector2, size::Math.Vector2, color::NTuple{4, Int}=(255, 255, 255, 255),
2425
fillMode::Bool=true; id::String=JulGame.generate_uuid(), isWorldEntity::Bool=false,
@@ -40,6 +41,7 @@ module RectangleModule
4041
this.borderColor = borderColor
4142
this.isHovered = false
4243
this.clickEvents = []
44+
this.hoverEvents = []
4345
this.layer = layer
4446

4547
return this
@@ -422,6 +424,10 @@ module RectangleModule
422424
push!(this.clickEvents, event)
423425
end
424426

427+
#= function UI.add_hover_event(this::Rectangle, event)
428+
push!(this.hoverEvents, event)
429+
end =#
430+
425431
function UI.handle_event(this::Rectangle, evt, x, y)
426432
if evt.type == evt.type == SDL2.SDL_MOUSEBUTTONDOWN
427433
elseif evt.type == SDL2.SDL_MOUSEBUTTONUP

src/engine/UI/TextBox.jl

Lines changed: 83 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,79 @@ module TextBoxModule
33
using ..UI.JulGame.Math
44
import ..UI
55
export TextBox
6-
mutable struct TextBox
7-
anchorOffset::Vector2
8-
#anchor::JulGame.Enum
9-
clickEvents
10-
font
6+
mutable struct TextBox <: UI.UIElement
7+
font::Union{Ptr{SDL2.TTF_Font}, Ptr{Nothing}}
118
fontPath::String
129
fontSize::Int
13-
id::String
14-
isActive::Bool
15-
isCenteredX::Bool
16-
isCenteredY::Bool
17-
isHovered::Bool
18-
isWorldEntity::Bool
19-
layer::Int
20-
name::String
21-
persistentBetweenScenes::Bool
22-
position::Vector2
23-
renderText
24-
size::Vector2
25-
text::String
26-
textTexture
2710
isConstructed::Bool
28-
color::NTuple{4, Int}
11+
isWorldEntity::Bool
2912
maxLineWidth::Int
13+
renderText::Union{Ptr{SDL2.SDL_Surface}, Ptr{Nothing}}
14+
text::String
15+
textTexture::Union{Ptr{SDL2.SDL_Texture}, Ptr{Nothing}}
3016
wrapWords::Bool
3117

32-
function TextBox(name::String, fontPath::String, fontSize::Int, position::Math.Vector2, text::String, isCenteredX::Bool = false, isCenteredY::Bool = false; anchorOffset::Math.Vector2 = Math.Vector2(0,0), id::String=JulGame.generate_uuid(), isWorldEntity::Bool=false, layer::Int=0, color::NTuple{4, Int}=(255, 255, 255, 255), maxLineWidth::Int=0, wrapWords::Bool=true) # TODO: replace bool with enum { left, center, right, etc }
33-
this = new()
18+
function TextBox(text::String;
19+
id::String=JulGame.generate_uuid(),
20+
name::String = "TextBox",
21+
anchor::Symbol = :center,
22+
anchorOffset::Math.Vector2 = Math.Vector2(0,0),
23+
isWorldEntity::Bool=false,
24+
layer::Int=0,
25+
position::Math.Vector2 = Math.Vector2(0,0),
26+
clickEvents::Vector{Function} = Function[],
27+
hoverEnterEvents::Vector{Function} = Function[],
28+
hoverExitEvents::Vector{Function} = Function[],
29+
isActive::Bool=true,
30+
persistentBetweenScenes::Bool=false,
31+
color::NTuple{4, Int}=(255, 255, 255, 255),
32+
fontPath::String = "FiraCode-Regular.ttf",
33+
fontSize::Int = 16,
34+
maxLineWidth::Int=0,
35+
wrapWords::Bool=true)
3436

37+
this = new()
38+
3539
this.isConstructed = false
36-
this.clickEvents = []
40+
this.anchor = JulGame.Enum{Any}(
41+
:center,
42+
:top,
43+
:bottom,
44+
:left,
45+
:right,
46+
:topLeft,
47+
:topRight,
48+
:bottomLeft,
49+
:bottomRight,
50+
)
51+
52+
this.anchor.current_state = anchor
53+
this.anchorOffset = anchorOffset
54+
55+
this.clickEvents = clickEvents
56+
this.hoverEnterEvents = hoverEnterEvents
57+
this.hoverExitEvents = hoverExitEvents
58+
3759
this.fontPath = fontPath
3860
this.fontSize = fontSize # Store the base font size
3961
this.id = id
40-
this.anchorOffset = anchorOffset
41-
this.isCenteredX = isCenteredX
42-
this.isCenteredY = isCenteredY
4362
this.layer = layer
4463
this.name = name
4564
this.position = position
4665
setfield!(this, :text, text)
47-
this.isHovered = false
4866
this.isWorldEntity = isWorldEntity
49-
this.textTexture = C_NULL
50-
this.persistentBetweenScenes = false
51-
this.isActive = true
52-
this.renderText = C_NULL
67+
this.persistentBetweenScenes = persistentBetweenScenes
68+
this.isActive = isActive
5369
this.color = color
5470
this.maxLineWidth = maxLineWidth
5571
this.wrapWords = wrapWords
5672

73+
this.textTexture = C_NULL
74+
this.renderText = C_NULL
75+
5776
if strip(fontPath) == ""
5877
@debug "fontPath is empty, using default font"
59-
fontPath = joinpath("FiraCode-Regular.ttf")
78+
fontPath = "Default"
6079
end
6180

6281
# Load the font with the true font size (scaled for current window size)
@@ -126,7 +145,8 @@ module TextBoxModule
126145
@debug string("loading font from $(basePath)\\$(fontPath)")
127146

128147
# Calculate the true font size based on window resolution
129-
trueFontSize = get_true_font_size(this.fontSize)
148+
#trueFontSize = get_true_font_size(this.fontSize)
149+
trueFontSize = this.fontSize
130150

131151
this.font = load_font_sdl(basePath, fontPath, trueFontSize)
132152
if this.font == C_NULL
@@ -187,8 +207,14 @@ module TextBoxModule
187207
end
188208

189209
function load_font_sdl(basePath::String, fontPath::String, fontSize::Int)
190-
if haskey(JulGame.FONT_CACHE, get_comma_separated_path(fontPath))
191-
raw_data = JulGame.FONT_CACHE[get_comma_separated_path(fontPath)]
210+
if haskey(JulGame.FONT_CACHE, get_comma_separated_path(fontPath)) || fontPath == "Default"
211+
if fontPath == "Default"
212+
raw_data = JulGame.BUILT_IN_ASSETS["Font"]
213+
@debug "loading default font"
214+
else
215+
raw_data = JulGame.FONT_CACHE[get_comma_separated_path(fontPath)]
216+
@debug "loading font from cache"
217+
end
192218
rw = SDL2.SDL_RWFromConstMem(pointer(raw_data), length(raw_data))
193219
if rw != C_NULL
194220
@debug("loading font from cache")
@@ -334,11 +360,26 @@ module TextBoxModule
334360
return
335361
end
336362

337-
if this.isCenteredX
338-
this.position = Math.Vector2(max(MAIN.scene.camera.size.x/2 - this.size.x/2, 0) + this.anchorOffset.x, this.position.y)
339-
end
340-
if this.isCenteredY
341-
this.position = Math.Vector2(this.position.x, max(MAIN.scene.camera.size.y/2 - this.size.y/2, 0) + this.anchorOffset.y)
363+
if this.anchor.current_state == :center
364+
this.position = Math.Vector2(max(MAIN.scene.camera.size.x/2 - this.size.x/2, 0) + this.anchorOffset.x, max(MAIN.scene.camera.size.y/2 - this.size.y/2, 0) + this.anchorOffset.y)
365+
elseif this.anchor.current_state == :top
366+
this.position = Math.Vector2(max(MAIN.scene.camera.size.x/2 - this.size.x/2, 0) + this.anchorOffset.x, this.anchorOffset.y)
367+
elseif this.anchor.current_state == :bottom
368+
this.position = Math.Vector2(max(MAIN.scene.camera.size.x/2 - this.size.x/2, 0) + this.anchorOffset.x, MAIN.scene.camera.size.y - this.size.y + this.anchorOffset.y)
369+
elseif this.anchor.current_state == :left
370+
this.position = Math.Vector2(this.anchorOffset.x, max(MAIN.scene.camera.size.y/2 - this.size.y/2, 0) + this.anchorOffset.y)
371+
elseif this.anchor.current_state == :right
372+
this.position = Math.Vector2(MAIN.scene.camera.size.x - this.size.x + this.anchorOffset.x, max(MAIN.scene.camera.size.y/2 - this.size.y/2, 0) + this.anchorOffset.y)
373+
elseif this.anchor.current_state == :topLeft
374+
this.position = Math.Vector2(this.anchorOffset.x, this.anchorOffset.y)
375+
elseif this.anchor.current_state == :topRight
376+
this.position = Math.Vector2(MAIN.scene.camera.size.x - this.size.x + this.anchorOffset.x, this.anchorOffset.y)
377+
elseif this.anchor.current_state == :bottomLeft
378+
this.position = Math.Vector2(this.anchorOffset.x, MAIN.scene.camera.size.y - this.size.y + this.anchorOffset.y)
379+
elseif this.anchor.current_state == :bottomRight
380+
this.position = Math.Vector2(MAIN.scene.camera.size.x - this.size.x + this.anchorOffset.x, MAIN.scene.camera.size.y - this.size.y + this.anchorOffset.y)
381+
else
382+
@error "Invalid anchor state: $(this.anchor.current_state)"
342383
end
343384
end
344385

@@ -398,7 +439,7 @@ module TextBoxModule
398439
SDL2.SDL_DestroyTexture(this.textTexture)
399440
this.textTexture = C_NULL
400441
end
401-
442+
#=
402443
function Base.setproperty!(this::TextBox, s::Symbol, x)
403444
try
404445
setfield!(this, s, x)
@@ -415,7 +456,7 @@ module TextBoxModule
415456
error(e)
416457
Base.show_backtrace(stderr, catch_backtrace())
417458
end
418-
end
459+
end =#
419460

420461
# Add methods to set and get the maximum line width
421462
function set_max_line_width(this::TextBox, maxWidth::Int)

src/engine/UI/UI.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
update_button_text,
1919
update_font_size
2020

21+
include("UIElement.jl")
2122
include("ScreenButton.jl")
2223
include("TextBox.jl")
2324
#include("Draggable.jl")

0 commit comments

Comments
 (0)