Skip to content

Conversation

@emyfops
Copy link
Collaborator

@emyfops emyfops commented Jan 11, 2025

Related: #79 #78

This pull request is the result of 7 months of hard work

A new maintainable click gui api was implemented
A new setting layout builder was added to create custom gui elements such as buttons, sliders, etc.

The opengl common buffer was reworked to reduce overhead

The texture uploading process was simplified for the end user by providing a new TextureOwner object that keeps track of all the textures created in a given scope
The functions to upload textures are as follow:

  • fun Any.upload() = ...
  • fun Any.uploadGif() = ...
  • fun Any.uploadField() = ...

A new AnimatedTexture class was added for gif rendering
The texture base class was extended to correctly handle other pixel formats such as BGRA, RG, RED and provide mappings to mojang's native image formats
The pixel buffer was reworked according to the buffer api

Both fonts, text and emojis, were reworked according to the texture api
A new SDF texture (also known as alpha-tested magnification) was implemented in order to display clearer characters at any scale or transformation

There are many breaking changes that need to be corrected before merging
This pull request is NOT ready to be merged

Summary by CodeRabbit

  • New Features

    • Added animated texture support for GIFs with a new HUD module.
    • Introduced a Map Downloader that saves in‑game maps as PNG images.
  • UI Enhancements

    • Revamped Click GUI with updated layout, new settings (title bar height, module size, round radius, etc.) and improved visual customization.
    • Enhanced font and emoji rendering using new shader techniques for smoother, sharper text.
  • Improvements

    • Streamlined module list and HUD rendering for a cleaner display.
    • Improved interactive animations and slider precision.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
common/src/main/kotlin/com/lambda/graphics/buffer/VertexPipeline.kt (1)

188-190: 🛠️ Refactor suggestion

** Implement proper OpenGL resource cleanup in finalize().**

This empty method is currently unutilized. Please remove it if it’s unnecessary or perform resource cleanup (e.g., deleting VAO/VBO/EBO) to avoid GPU memory leaks. Also, relying on finalization for cleanup is discouraged in Kotlin; an explicit close() method or AutoCloseable implementation is typically more reliable.

🧰 Tools
🪛 detekt (1.23.7)

[warning] 188-190: This empty block of code can be removed.

(detekt.empty-blocks.EmptyFunctionBlock)

🧹 Nitpick comments (27)
common/src/main/resources/assets/lambda/shaders/fragment/signed_distance_field.frag (3)

1-10: Check constant naming: SPHREAD vs SPREAD

The constant name SPHREAD on line 9 appears to be a typo of "SPREAD" which would be more appropriate for a blur radius constant.

-#define SPHREAD 4
+#define SPREAD 4

27-28: Add protection against division by zero

While unlikely due to the nature of the exp function, it's still good practice to add protection against division by zero.

-    color = colors / blurWeight;
+    color = colors / max(blurWeight, vec4(0.0001));

1-29: Add documentation about the shader purpose and parameters

This shader implements a specific blur technique for signed distance fields, but lacks documentation explaining its purpose and how the parameters affect the output.

Consider adding comments to explain:

  1. The purpose of the shader (SDF blurring/smoothing)
  2. How u_TexelSize should be calculated
  3. How the weight calculation works and what it achieves
  4. The expected input texture format (presumably a distance field)
common/src/main/kotlin/com/lambda/gui/component/window/AnimatedWindowChild.kt (2)

45-58: Ensure animation logic is tested thoroughly.

The code uses exponential animations (animation.exp) and dynamically adjusts the animation speed based on the index and lastIndex. Consider adding unit or integration tests to validate that:

  1. The showAnimation correctly transitions between 0.0 and 1.0.
  2. The computed speed values yield the intended user experience for sequential animations.

75-81: Consider consolidating initialization blocks.

Having two separate init blocks controlling aspects of the title bar text updates can introduce complexity. You might merge them into a single initialization flow or comment explicitly on each block’s purpose, making it clearer for future maintainers.

common/src/main/kotlin/com/lambda/graphics/buffer/vertex/ElementBuffer.kt (1)

26-29: Document usage parameter.

Including a brief comment clarifying the intended usage for usage: Int = GL_DYNAMIC_DRAW would help maintainers understand why dynamic draw is used here (versus static or stream). Doing so also clarifies the performance trade-offs of changing this parameter in the future.

common/src/main/kotlin/com/lambda/gui/component/core/UIBuilder.kt (1)

33-42: Robust layout insertion method with proper error handling.

The insertLayout function provides a clean way to insert layouts with appropriate error checking. The check for base layout ownership prevents invalid insertions.

Consider adding KDoc to explain the function's purpose and parameters, especially the meaning of the next parameter, to improve code readability.

+/**
+ * Inserts this layout into the children of the specified owner layout.
+ * 
+ * @param owner The layout that will contain this layout
+ * @param base The reference layout in the owner's children list
+ * @param next If true, inserts after the base layout; if false, inserts before it
+ * @throws IllegalStateException If the base layout doesn't belong to the specified owner
+ * @return This layout (for chaining)
+ */
fun <T : Layout> T.insertLayout(
    owner: Layout,
    base: Layout,
    next: Boolean
) = apply {
common/src/main/kotlin/com/lambda/gui/impl/clickgui/ModuleWindow.kt (2)

44-55: Reduce repeated code paths
Both onWindowExpand and onWindowMinimize set isMinimized on the same module collection. Consider consolidating this functionality to avoid duplicated logic.

-        onWindowExpand {
-            modules.forEach {
-                it.isMinimized = true
-            }
-        }
-
-        onWindowMinimize {
-            modules.forEach {
-                it.isMinimized = true
-            }
-        }
+        val minimizeAll: () -> Unit = {
+            modules.forEach { it.isMinimized = true }
+        }
+        onWindowExpand(minimizeAll)
+        onWindowMinimize(minimizeAll)

57-69: Centralize window creation steps
The moduleWindow extension function is convenient, but if you plan to create windows with shared settings or common behavior, consider factoring out repeated initialization to ensure maintainability.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/SettingLayout.kt (1)

51-53: Question default minimization
By setting isMinimized = true, you're collapsing the layout at creation time. Confirm if this meets UX expectations. If not, you may need to invert or remove this behavior.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/settings/EnumSelector.kt (2)

28-28: Address the slider TODO
The comment suggests planning to morph this into a slider or completing the implementation. Let me know if you'd like a preliminary approach or a new issue to track the requirement.


44-45: Use friendlier labels
Currently, you’re displaying enumEntry.name verbatim. For improved UX, consider allowing a custom or localized display name if one is available.

common/src/main/kotlin/com/lambda/module/hud/TickShiftCharge.kt (2)

61-63: Avoid negative corner radii
If ClickGui.roundRadius is smaller than padding, subtracting them may yield a negative radius and cause wonky rendering.

Consider the following tweak:

-  roundRadius = ClickGui.roundRadius - padding,
+  roundRadius = max(0.0, ClickGui.roundRadius - padding),

68-76: Conditional outline rendering
Drawing the outline only when ClickGui.outline is true is a clean approach. Exposing a separate parameter for the shading might provide additional user customization.

common/src/main/kotlin/com/lambda/gui/component/window/WindowContent.kt (1)

68-117: Scroll and rubberband effect
Implementing a rubberband effect enhances UX. The factor 10.0 for dwheel is a magic number; consider making this scroll sensitivity configurable.

common/src/main/kotlin/com/lambda/gui/component/window/Window.kt (1)

40-50: Window class constructor
Offers a comprehensive set of adjustable parameters. Consider moving defaults (e.g., initialSize, title) to a config or constants for future flexibility.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/ModuleLayout.kt (4)

53-59: Consider replacing the manual hover timestamp with a timer or animation controller.

You already have a TODO comment suggesting this improvement. Relying on System.currentTimeMillis() can become cumbersome and harder to manage. A more elegant approach is to use a timer-based mechanism or unify it with your existing animation logic for consistent updates.

Would you like me to propose a simple timer-based approach for measuring hover duration?


60-117: Potential performance concern for repeated color calculations.

Each frame, multiple operations occur (lerping, alpha calculation, color blending). While this is functional, consider caching intermediate color states when they are unlikely to change frequently (e.g., whenever module.enabled changes) to reduce overhead and repeated color computations, especially on lower-spec systems.


155-168: Possible confusion when minimizing other modules on expand.

In onWindowExpand, all other ModuleLayout instances are minimized. This behavior might confuse users expecting multiple modules to be simultaneously expanded. Confirm user expectations before finalizing this. If intended, a comment explaining the rationale will help maintainers.


191-239: Clarify function usage in backgroundTint.

Although you’ve mentioned "Not for external usage," it’s declared as a public function in a companion object. If truly internal, consider reducing visibility or adding a note that it’s intended for internal composition only, to prevent unintended usage outside the module.

common/src/main/kotlin/com/lambda/gui/component/core/TextField.kt (1)

53-58: Optimize rendering alignment calculations.

Repeatedly calling lerp for horizontal and vertical alignment inside onRender is fine for smaller UIs, but can become costly with many text elements. If performance becomes an issue, consider caching or precalculating these positions until a property changes (e.g., size, alignment).

common/src/main/kotlin/com/lambda/gui/component/core/OutlineRect.kt (2)

35-50: Consider partial updates for outline rendering.

Right now, outlineRect is always called on each render pass, even if properties like roundRadius, glowRadius, or corner colors remain unchanged. If performance is crucial, caching the outline path or reusing buffers for repeated frames can be beneficial.


54-59: Add usage example for setColor.

setColor(color) is convenient, but consider adding code comments or examples on how to leverage it in the presence of gradient corners. This ensures future contributors understand its behavior and limitations with multi-colored corners.

common/src/main/kotlin/com/lambda/gui/component/layout/Layout.kt (3)

42-42: Consider addressing this TODO comment sooner rather than later.
This TODO suggests an intention to introduce a dedicated subclass or mechanism for alignment. Scheduling its implementation will help ensure complexity doesn’t accumulate and alignment logic remains maintainable.

Would you like me to open a new issue or propose a draft implementation to resolve this?


327-335: Clarify destroy contract or allow for safer repeated calls.
Currently, a second call to destroy() throws an exception. In many GUI frameworks, multiple destroy calls simply no-op. Decide if repeated calls should never happen (and thus throwing is appropriate) or if they can happen under valid scenarios. If valid, consider a safer approach.


423-466: Potential overhead from multiple child components.
The companion object factory methods (e.g., layout, animationTicker, cursorController) can facilitate many child creations. In high-complexity UIs, consider deferring child creation or employing lazy initialization for performance.

common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt (1)

31-31: Confirm the updated description aligns with user-facing documentation.
The description changed to “sexy again.” Verify that it matches your intended public-facing text and that it remains user-friendly.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a30839d and 57a351b.

📒 Files selected for processing (27)
  • common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt (2 hunks)
  • common/src/main/kotlin/com/lambda/graphics/buffer/VertexPipeline.kt (2 hunks)
  • common/src/main/kotlin/com/lambda/graphics/buffer/vertex/ElementBuffer.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/graphics/buffer/vertex/VertexBuffer.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/graphics/pipeline/ScissorAdapter.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontRenderer.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/FilledRectRenderer.kt (2 hunks)
  • common/src/main/kotlin/com/lambda/gui/GuiManager.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/core/FilledRect.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/core/OutlineRect.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/core/TextField.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/core/UIBuilder.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/layout/Layout.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/window/AnimatedWindowChild.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/window/TitleBar.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/window/Window.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/window/WindowContent.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/ModuleLayout.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/ModuleWindow.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/SettingLayout.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/settings/BooleanButton.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/settings/EnumSelector.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/module/hud/TickShiftCharge.kt (2 hunks)
  • common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt (3 hunks)
  • common/src/main/resources/assets/lambda/shaders/fragment/font/font.frag (1 hunks)
  • common/src/main/resources/assets/lambda/shaders/fragment/signed_distance_field.frag (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt
  • common/src/main/kotlin/com/lambda/gui/component/window/TitleBar.kt
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/settings/BooleanButton.kt
  • common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt
🧰 Additional context used
🧠 Learnings (1)
common/src/main/kotlin/com/lambda/gui/component/core/UIBuilder.kt (1)
Learnt from: Avanatiker
PR: Avanatiker/NeoLambda#98
File: common/src/main/kotlin/com/lambda/gui/component/core/UIBuilder.kt:20-27
Timestamp: 2025-02-21T23:22:59.595Z
Learning: The use of numbers in DSL annotation names (e.g. UIRenderPr0p3rty) is intentional as it affects the DSL color through the name's hash value. This is a design feature, not a naming convention violation.
🪛 detekt (1.23.7)
common/src/main/kotlin/com/lambda/graphics/buffer/VertexPipeline.kt

[warning] 188-190: This empty block of code can be removed.

(detekt.empty-blocks.EmptyFunctionBlock)

🔇 Additional comments (52)
common/src/main/resources/assets/lambda/shaders/fragment/signed_distance_field.frag (2)

15-25: Review performance impact of blur radius

The current implementation samples 81 texels (9x9 grid) for each output pixel. While this provides good quality for a signed distance field, it could impact performance on lower-end hardware.

Consider making the spread radius configurable via a uniform parameter rather than a hard-coded constant to allow runtime adjustment based on performance requirements.


20-21: Review weight calculation logic

The weight calculation exp(-color * color) is applied to a vec4 color, which might produce unexpected results as it performs the operation on each color channel independently. Typically, for distance field blurring, weights are based on a scalar distance or alpha value.

Consider if this is the intended behavior or if the weight should be calculated from a single component:

-            vec4 weight = exp(-color * color);
+            // Option 1: Use alpha channel if it represents the distance field
+            float distValue = color.a;
+            vec4 weight = exp(-distValue * distValue);
+            
+            // Option 2: Use color magnitude
+            // float distValue = length(color.rgb);
+            // vec4 weight = exp(-distValue * distValue);
common/src/main/kotlin/com/lambda/gui/GuiManager.kt (6)

1-16: License block check.
No issues found; the license header appears valid and complete.


18-28: Package and imports look appropriate.
No immediate concerns regarding naming, organization, or unused imports.


29-31: Consider thread safety for mutable data structures.
typeMap is a normal MutableMap that may pose concurrency risks if accessed by multiple threads. Consider using thread-safe alternatives (e.g., a ConcurrentHashMap) or proper synchronization if multi-threaded usage is expected.


32-34: Duplicate registrations remain unhandled.
A previous review comment suggested adding error handling or detection for duplicate type adapters. Reiterating the same suggestion here, as the current implementation silently overrides any existing adapter.


36-46: Initialization of adapters is straightforward.
All registered adapters are neatly organized, and the returned status message provides a useful log for debugging. No additional concerns.


48-57: Null checks for missing adapters.
layoutOf will return null if no matching type adapter is found. This approach is valid, but consider whether you might need logging or an assertion in cases where an adapter is unexpectedly missing.

common/src/main/kotlin/com/lambda/gui/component/window/AnimatedWindowChild.kt (1)

42-44: Check for potential null owner references.

Accessing owner?.owner as? Window or owner?.owner as? AnimatedWindowChild is safe with a cast, but might lead to unexpected null or type mismatches at runtime if owner?.owner does not match the assumed type. It might be wise to handle the case where the cast fails or the value is null more gracefully.

common/src/main/resources/assets/lambda/shaders/fragment/font/font.frag (1)

1-36: Clean and efficient SDF font shader implementation.

This new fragment shader effectively implements a signed distance field (SDF) approach for rendering both fonts and emojis. The implementation handles the two texture types (font and emoji) appropriately with good smoothing transitions via the smoothstep function.

A few suggestions to consider:

  • Consider adding comments explaining the SDF technique and expected texture formats
  • Document the expected range values for u_SDFMin and u_SDFMax to guide future developers
common/src/main/kotlin/com/lambda/graphics/pipeline/ScissorAdapter.kt (3)

18-19: Package relocated appropriately to pipeline namespace.

The package relocation from gl to pipeline better reflects the adapter role of this component in the rendering pipeline.


28-41: Good refactoring of scissor handling with proper stack management.

The scissor mechanism has been well-refactored with improved stack management. The changes simplify the API while maintaining correct nested scissor functionality.


43-58: Improved scissor calculation with proper scaling.

The scissor rectangle calculation now correctly uses RenderMain.scaleFactor for scaling and properly handles coordinate conversions. The use of coerceAtLeast(0.0) prevents negative dimensions which could cause rendering issues.

common/src/main/kotlin/com/lambda/graphics/buffer/vertex/VertexBuffer.kt (1)

27-32: Streamlined VertexBuffer class with improved inheritance.

The class now extends the abstract Buffer class instead of implementing IBuffer interface, which likely reduces code duplication and improves the overall buffer management system.

common/src/main/kotlin/com/lambda/gui/component/core/UIBuilder.kt (1)

24-31: Well-structured DSL marker annotations.

The DSL marker annotations are appropriately defined to ensure type-safe builders. The unconventional naming in UIRenderPr0p3rty with numbers is intentional as it affects the DSL color through the name's hash value, as noted in the retrieved learnings.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/ModuleWindow.kt (1)

38-41: Check multi-tag support
Current filtering uses defaultTags.firstOrNull() == tag, which may exclude modules having multiple tags. If there's a possibility of multiple applicable tags, consider broadening the filter logic.

Would you like me to search the codebase to confirm whether multiple active tags are expected?

common/src/main/kotlin/com/lambda/gui/impl/clickgui/SettingLayout.kt (1)

78-80: Monitor text shrinking
scale *= 0.92 can repeatedly shrink the text over time. Check whether this dynamic resizing is intentional, or switch to a static scale for consistent presentation.

common/src/main/kotlin/com/lambda/module/hud/TickShiftCharge.kt (3)

21-24: Use of new rendering imports is consistent
These imports provide direct access to the new rendering functions, simplifying calls to filledRect and outlineRect.


42-46: Progress animation logic looks correct
Ensuring the value is clamped in the range [0..1] avoids invalid progress values, aligning well with UI progress bar expectations.


53-55: Switched corner radius to ClickGui.roundRadius
Replacing any previous radius reference with ClickGui.roundRadius is coherent with the updated corner style.

common/src/main/kotlin/com/lambda/gui/component/window/WindowContent.kt (5)

1-16: License header check
The GPL license text is standard; no issues noted.


18-28: Imports look consistent
Imports for animation, layout, and math match the file’s usage.


29-66: Vertical layout with listify()
Using overrideY to stack children vertically is straightforward. Verify positioning logic if a child’s height changes at runtime to ensure no unwanted overlap.


119-127: Dynamic layout height
Combining child animations (showAnimation/staticShowAnimation) is sensible. Confirm child components always return valid animation values to avoid unexpected layout jumps.


129-136: Convenient windowContent builder
Provides a quick way to attach scrollable content to a window. No issues found.

common/src/main/kotlin/com/lambda/gui/component/window/Window.kt (7)

1-16: License header check
The GPL license text is standard; no issues found.


18-34: Imported references for UI building
All utility and GUI-related imports appear accurate and necessary.


85-88: Expand/minimize action lists
Deferring window-specific behavior to these callbacks is flexible. Ensure closures remain valid if the window is hidden or the layout reinitialized.


109-127: Minimize toggle & dimension tracking
Linking isMinimized to the actual window height ensures clarity. External references to width/height should respect these animated transitions.


128-158: Animated dimension properties
Using widthAnimation and heightAnimation for smooth transitions is well-structured. Remember to re-check if dynamic content changes are always reflected when autoResize is active.


239-246: Expose or configure resizing constraints
Hard-coded coerceIn(80.0, 1000.0) can be restrictive for some display setups.


292-311: Window builder pattern
Convenient creation of a Window with customizable content. No issues discovered.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/ModuleLayout.kt (1)

125-127: Validate layout constraints for dynamic size changes.

You override the X coordinate and width to fit within the owner layout. Ensure that the resulting size does not lead to overlapping or negative widths if the owner’s size becomes smaller than the specified padding. Adding boundary checks or a minimum width can prevent rendering anomalies.

common/src/main/kotlin/com/lambda/gui/component/core/TextField.kt (1)

32-44: Ensure text properties match various font renderers.

The computed textWidth and textHeight rely on FontRenderer, which may differ if custom or system fonts are used. Consider adding a fallback or a defensive check to ensure the returned dimensions are valid, particularly when switching to alternative font renderers or font sizes.

common/src/main/kotlin/com/lambda/gui/component/core/FilledRect.kt (5)

25-37: Well-structured property definitions.

The usage of @UIRenderPr0p3rty for both corner radii and color properties is consistent and avoids clutter. The defaults look sensible, and the code is clear.


40-57: Ensure consistent radius handling.

The onRender block correctly gathers all corner radii and color values to render a filled rectangle. This approach centralizes the rendering logic in the filledRect call. Just confirm that any outside changes to these properties invalidate the rendering cache if the framework caches layout results.


59-64: Radius assignment logic is readable and intuitive.

Both setRadius(Double) and setRadius(Double, Double, Double, Double) help set top and bottom corners in a straightforward manner. This ensures flexibility for the layout developer.

Also applies to: 66-76


78-83: Use of color gradient helpers is commendable.

Providing setColor, setColorH, and setColorV covers common gradient scenarios, making the API more versatile. Good job on ensuring corner color assignments remain consistent.

Also applies to: 85-97


99-125: Extension functions for layout integration are well-organized.

The approach of rect, rectBehind, and rectOver is readable, enabling developers to insert layer-based rectangles easily. This follows a clean builder pattern.

common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/FilledRectRenderer.kt (3)

30-31: Clarify alpha threshold logic.

Currently, MIN_ALPHA is set to 1. In AWT, color alpha ranges from 0 to 255. Checking if (alpha < 1) might effectively skip only fully transparent colors, but it could also skip semitransparent colors if fractional alpha values are interpreted differently. Consider clarifying or adjusting this threshold if partial transparency is intended.


81-93: Skip rendering only if fully transparent.

Skipping rendering when all corners have alpha below MIN_ALPHA is a reasonable optimization. Just ensure there's no scenario where partial transparency is erroneously dropped.


113-118: Efficient usage of 3D vectors for 2D quads.

Defining quad corners with vec3m(...).vec2(...) is consistent with typical buffers. Confirm that any Z-based transformations in the pipeline handle these coordinates correctly if layering or depth is introduced in the future.

common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontRenderer.kt (6)

36-40: Good separation of configuration getters.

Using dedicated properties (shadowShift, baselineOffset, gap) ensures customization remains centralized. This makes maintenance easier and avoids magic constants in the rendering code.

Also applies to: 41-47


58-76: Flexible text rendering method.

drawString properly sets up the shader, binds textures, and processes text. The injection of shadow logic and emoji parsing within processText is a neat separation of concerns, preserving clarity.


86-107: Dedicated glyph rendering function is helpful.

drawGlyph enables modular rendering, an advantage when dealing with custom glyph-based components or partial text rendering. This fosters code reuse and composability.


118-138: Well-structured buildGlyph implementation.

Using an extension on VertexPipeline for glyph construction keeps low-level buffer operations encapsulated. It's a clean approach that promotes maintainability.


156-162: Check for potential undercounting of width with newlines.

The logic increments width by char.width plus gaps. Ensure that multiple newlines do not create leftover vertical spacing that might need a separate measure. Currently, newlines reset posX but not the measuring logic, which might be acceptable for single-line usage.


185-213: Potential complexity in nested emoji parsing.

processTextSection recursively handles text blocks around emojis. While functional, consider carefully testing nested cases (e.g., multiple emojis in the same line, or edge cases with consecutive emojis) to ensure correct slicing and position increments.

Also applies to: 215-252

common/src/main/kotlin/com/lambda/gui/component/layout/Layout.kt (2)

49-53: Validate clamping logic when child size exceeds the parent.
When clampPosition is enabled, large children relative to the parent’s width or height can force positions to clamp to 0, potentially overlaying them awkwardly. Ensure that the clamping behavior gracefully handles situations where a child is larger than its parent.

Also applies to: 54-59


394-394: Avoid forcibly releasing mouse clicks on non-hovered layouts.
Line 394 sets the action to Mouse.Action.Release if the layout is not hovered. This might break scenarios where a click or drag event started on one layout and ended on another. Evaluate if there’s a more nuanced decision process.

common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt (2)

67-67: Avoid using owner!! to prevent potential runtime crashes.
Relying on !! can cause unexpected NullPointerException if the UI hierarchy changes. Consider a safe call (owner?.rect) and handle null gracefully, or ensure the owning context is always non-null.


80-83: Evaluate the self-toggle flow on enable.
Immediately toggling the module off after showing the screen can be surprising if a user expects to manually disable it. If auto-disabling is intended, clarify why. Otherwise, let the user close the GUI or hide it themselves.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57a351b and 195086d.

📒 Files selected for processing (1)
  • common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Build Lambda
🔇 Additional comments (3)
common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt (3)

29-29: Good work extracting the compression level to a constant.

Extracting the compression level value to a named constant improves code readability and maintainability.


28-73:

Details

❓ Verification inconclusive

Verify that removed functionality has been migrated to the new texture API.

According to the PR description, significant functionality has been removed from this file including:

  • The metricCache variable for font metrics caching
  • The upload method for BufferedImage
  • The setupLOD method for texture parameters
  • The getCharImage method for character image generation
  • The rescale extension function

Ensure that equivalent functionality exists in the new texture API mentioned in the PR objectives, particularly in the new TextureOwner class.


🏁 Script executed:

#!/bin/bash
# Look for the new TextureOwner class and its methods
rg -t kotlin "class TextureOwner" -A 20

# Check for new methods that might replace the old upload functionality
rg -t kotlin "fun upload" --glob "**/*Texture*.kt"

# Check for methods related to LOD setup in the new API
rg -t kotlin "setupLOD|texParameter" --glob "**/*Texture*.kt"

Length of output: 693


Action Required: Confirm Migration of All Texture Functionality

Based on our verification:

  • The new API in common/src/main/kotlin/com/lambda/graphics/texture/Texture.kt now includes:
    • The upload method (with both BufferedImage and ByteBuffer variants)
    • The setupLOD method (used within texture parameter setup)
  • However, we did not locate any evidence of the new TextureOwner class—nor did we find migrated equivalents for:
    • The metricCache variable for font metrics caching
    • The getCharImage method for character image generation
    • The rescale extension function

Please confirm that these missing functionalities have been intentionally removed or migrated elsewhere as per the PR objectives.


71-72:

Details

✅ Verification successful

Breaking change: Default parameter for format has been removed.

The second overload of readImage also had its default parameter removed. All calling code needs to be updated to explicitly specify the format.


🏁 Script executed:

#!/bin/bash
# Check if there are any calls to the second overload of readImage that might need updating
rg -A 3 "readImage\([^,]+\)" --type kotlin

Length of output: 175


Action Required: Ensure explicit format specification where applicable

I verified that, aside from the unrelated implementation in LambdaResource.readImage(), there are no remaining call sites that rely on the previously provided default parameter for format in the readImage overload. The breaking change in common/src/main/kotlin/com/lambda/graphics/texture/TextureUtils.kt (lines 71–72) appears isolated. Please confirm that any future invocations of the TextureUtils readImage methods explicitly pass a valid NativeImage.Format argument.

Comment on lines +55 to 56
format: NativeImage.Format,
): Long {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Breaking change: Default parameter for format has been removed.

The removal of the default parameter for format means that all callers of this method will now need to explicitly provide a format. Ensure all usages of this method throughout the codebase have been updated.


🏁 Script executed:

#!/bin/bash
# Look for calls to readImage that might be affected by the removed default parameter
rg -A 2 "readImage\(" --type kotlin

Length of output: 2145


Breaking Change: Mandatory Explicit Format Parameter

The default value for the format parameter has now been removed from the readImage method in TextureUtils.kt (lines 55-56). This change requires that every call site supplies an explicit NativeImage.Format value. Notably, the call in common/src/main/kotlin/com/lambda/graphics/texture/TextureOwner.kt (i.e. Texture(path.readImage(), levels = mipmaps)) still omits the format parameter and will need to be updated accordingly. Please review all usages of this method to ensure they are passing an explicit format.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (8)
common/src/main/kotlin/com/lambda/gui/GuiManager.kt (2)

38-52: Optional: Provide a mechanism for additional adapters.

The load() method hard-codes adaptations for BooleanSetting, EnumSetting, and FunctionSetting, but the PR objectives mention more advanced GUI configuration possibilities. You might consider adding custom adapters here or supporting runtime discovery to handle future UI element types seamlessly.


54-63: Optional: Handle unregistered references.

layoutOf returns null if no matching adapter is found in typeMap. Consider adding logging or a fallback to provide better insight when no adapter is found, especially in large-scale or production GUI systems.

common/src/main/kotlin/com/lambda/config/settings/FunctionSetting.kt (1)

1-16: Update the copyright year to match current year.

The copyright notice states the year as 2025, but the current year is 2024.

-/*
- * Copyright 2025 Lambda
+/*
+ * Copyright 2024 Lambda
common/src/main/kotlin/com/lambda/config/Configurable.kt (2)

424-429: Consider supporting generic return types in the function setting method.

While the FunctionSetting class supports functions that return any non-nullable type, this method is limited to functions that return Unit. Consider creating an overload that supports generic return types.

+/**
+ * Creates a [FunctionSetting] with the provided parameters and adds it to the [settings].
+ *
+ * @param name The unique identifier for the setting.
+ * @param defaultValue The function to be stored as the setting's value.
+ * @param description A brief explanation of the setting's purpose and behavior.
+ * @param visibility A lambda expression that determines the visibility status of the setting.
+ *
+ * @return The created [FunctionSetting].
+ */
 fun setting(
     name: String,
     defaultValue: () -> Unit,
     description: String = "",
     visibility: () -> Boolean = { true }
 ) = FunctionSetting(name, defaultValue, description, visibility).register()

+/**
+ * Creates a [FunctionSetting] with the provided parameters and adds it to the [settings].
+ *
+ * @param name The unique identifier for the setting.
+ * @param defaultValue The function to be stored as the setting's value.
+ * @param description A brief explanation of the setting's purpose and behavior.
+ * @param visibility A lambda expression that determines the visibility status of the setting.
+ *
+ * @return The created [FunctionSetting].
+ */
+inline fun <reified T : Any> setting(
+    name: String,
+    defaultValue: () -> T,
+    description: String = "",
+    noinline visibility: () -> Boolean = { true }
+) = FunctionSetting(name, defaultValue, description, visibility).register()

424-429: Add documentation comment for the new setting method.

The other setting methods have detailed documentation comments. Adding similar documentation to this new method would maintain consistency.

+/**
+ * Creates a [FunctionSetting] with the provided parameters and adds it to the [settings].
+ *
+ * @param name The unique identifier for the setting.
+ * @param defaultValue The function to be executed when the setting is triggered.
+ * @param description A brief explanation of the setting's purpose and behavior.
+ * @param visibility A lambda expression that determines the visibility status of the setting.
+ *
+ * @return The created [FunctionSetting].
+ */
 fun setting(
     name: String,
     defaultValue: () -> Unit,
     description: String = "",
     visibility: () -> Boolean = { true }
 ) = FunctionSetting(name, defaultValue, description, visibility).register()
common/src/main/kotlin/com/lambda/gui/impl/clickgui/settings/UnitButton.kt (3)

2-2: Copyright year should be updated

The copyright year is set to 2025, which is in the future. Consider updating it to the current year (2024) or the year when the code was actually written.

- * Copyright 2025 Lambda
+ * Copyright 2024 Lambda

31-33: Consider adding error handling

The click handler directly calls setting.value() without any error handling. If this function throws an exception, it might cause issues in the UI.

onMouseClick(Mouse.Button.Left, Mouse.Action.Click) {
-    setting.value()
+    try {
+        setting.value()
+    } catch (e: Exception) {
+        // Handle or log the exception
+        logger.error("Error executing setting function", e)
+    }
}

37-39: Enhance documentation for clarity

While the documentation comment is concise, it could benefit from more details about parameters, usage examples, or return values to help other developers understand how to use this component.

/**
 * Creates a [UnitButton] - visual representation of the [FunctionSetting]
+*
+* @param setting The function setting to be represented by this button
+* @return The created UnitButton instance that has been added to this layout
+*
+* Example usage:
+* ```
+* layout.unitSetting(myFunctionSetting)
+* ```
 */
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 195086d and 7591b93.

📒 Files selected for processing (7)
  • common/src/main/kotlin/com/lambda/config/AbstractSetting.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/config/Configurable.kt (2 hunks)
  • common/src/main/kotlin/com/lambda/config/settings/FunctionSetting.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/GuiManager.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/settings/UnitButton.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/module/Module.kt (3 hunks)
  • common/src/main/kotlin/com/lambda/module/modules/debug/SettingTest.kt (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • common/src/main/kotlin/com/lambda/module/Module.kt
🔇 Additional comments (9)
common/src/main/kotlin/com/lambda/config/AbstractSetting.kt (1)

129-131: Access to reset functionality is now public.

The reset() method visibility has been changed from private to public, allowing external classes to reset settings to their default values. This is a useful enhancement that enables more flexible management of settings throughout the application.

common/src/main/kotlin/com/lambda/gui/GuiManager.kt (1)

34-36: Consider handling duplicate adapter registrations ().

A past review mentioned adding safeguards to prevent duplicate registrations. Currently, typeAdapter overwrites existing mappings when the same type is registered again. This can lead to unexpected behavior, particularly if multiple modules attempt to register the same type.

common/src/main/kotlin/com/lambda/module/modules/debug/SettingTest.kt (2)

22-22: Added required import for Communication utility.

The import for Communication.info is correctly added to support the new unit setting that logs information when activated.


65-67: Good addition of action-based setting demonstrating the new GUI capabilities.

This new unitSetting demonstrates a different type of setting that executes an action (logging a message) rather than storing a value. This is a good test case that aligns with the new GUI API capabilities mentioned in the PR description.

The implementation correctly uses a lambda function with proper scoping (this@SettingTest) to ensure the action is executed in the correct context.

common/src/main/kotlin/com/lambda/config/settings/FunctionSetting.kt (1)

25-38: Well-designed implementation for function settings.

The FunctionSetting class provides a clean way to store function references as settings. The implementation correctly:

  • Uses generics to support functions returning any non-nullable type
  • Doesn't attempt to serialize the function (returning JsonNull)
  • Resets to default value when loading from JSON
common/src/main/kotlin/com/lambda/config/Configurable.kt (2)

26-26: Import for new FunctionSetting correctly added.

The import is properly added to support the new setting type.


33-33: Complex settings imports consolidated.

Changing to a wildcard import simplifies the import section.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/settings/UnitButton.kt (2)

26-34: Good implementation of the button component

The UnitButton class is well-structured and follows a clean object-oriented design. It properly extends SettingLayout with appropriate type parameters and implements the necessary functionality for executing an action when clicked.


37-42: Good use of extension function with builder pattern

The companion object effectively provides a clean, builder-style API for creating UnitButton instances. The use of @UIBuilder annotation and extension function on Layout improves readability and integration with the UI system.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (21)
common/src/main/kotlin/com/lambda/gui/impl/clickgui/core/AnimatedChild.kt (1)

34-134: Address the TODO and ensure UI stability.

Overall, the animations, visibility checks, and layout destruction are well-structured. However, note the “ToDo: replace with timer” comment on line 51. A dedicated timer or utility might provide more robust handling than manual time stamping. Also consider any edge cases involving:

  • Minimal or zero-sized windows
  • Rapidly toggling visibility or minimization states

Feel free to ask if you'd like a sample refactor for the timed hover logic.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/BooleanButton.kt (1)

1-16: The copyright year should be 2024 instead of 2025.

The copyright notice shows 2025, but according to the PR information, this should be 2024 since we're currently in March 2025.

-/*
- * Copyright 2025 Lambda
+/*
+ * Copyright 2024 Lambda
common/src/main/kotlin/com/lambda/gui/GuiManager.kt (1)

60-70: Consider adding null safety to the layout lookup.

The layoutOf function could benefit from more robust null safety when handling inheritance-based lookups.

 inline fun Layout.layoutOf(
     reference: Any,
     block: Layout.() -> Unit = {}
 ): Layout? =
-    (typeMap[reference::class] ?: typeMap.entries.firstOrNull {
-        reference::class.java.superclass == it.key.java
-    }?.value)?.invoke(this, reference)?.apply(block)
+    (typeMap[reference::class] 
+        ?: typeMap.entries.firstOrNull { entry ->
+            reference::class.java.superclass?.let { superclass ->
+                superclass == entry.key.java
+            } ?: false
+        }?.value)?.invoke(this, reference)?.apply(block)
common/src/main/kotlin/com/lambda/gui/impl/clickgui/ModuleWindow.kt (2)

32-33: Remove TODO comment about the tag system.

The code contains a TODO comment about the tag system, but since this PR represents "five months of development work," this comment should either be addressed or removed before merging.

 class ModuleWindow(
     owner: Layout,
-    val tag: ModuleTag, // todo: tag system
+    val tag: ModuleTag,
     initialPosition: Vec2d
 ) : Window(owner, tag.name, initialPosition, minimizing = Minimizing.Absolute, autoResize = AutoResize.ByConfig) {

44-52: Consider using state consistency instead of event-based minimization.

The code sets up handlers to minimize modules when the window expands or minimizes, but this approach could lead to state inconsistency if the window state changes through other means.

-    val minimize = {
-        modules.forEach {
-            it.isMinimized = true
-        }
-    }
-
-    onWindowExpand { minimize() }
-    onWindowMinimize { minimize() }
+    // Maintain state consistency through a property observer
+    var windowState: WindowState = WindowState.Normal
+        set(value) {
+            field = value
+            if (value == WindowState.Expanded || value == WindowState.Minimized) {
+                modules.forEach { it.isMinimized = true }
+            }
+        }
+
+    onWindowExpand { windowState = WindowState.Expanded }
+    onWindowMinimize { windowState = WindowState.Minimized }
common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/SettingSlider.kt (5)

1-16: The copyright year should be 2024 instead of 2025.

The copyright notice shows 2025, but according to the PR information, this should be 2024.

-/*
- * Copyright 2025 Lambda
+/*
+ * Copyright 2024 Lambda

34-36: Add space after the generic type parameter.

There should be a space after the generic type parameter in the class declaration.

-abstract class SettingSlider <V : Any, T: AbstractSetting<V>>(
+abstract class SettingSlider<V : Any, T : AbstractSetting<V>>(

37-39: Define animation property purpose in code comments.

The changeAnimation property lacks documentation explaining its purpose and usage within the slider.

+    /**
+     * Animation that controls the visual feedback when the setting value changes
+     */
     private var changeAnimation by animation.exp(0.0, 1.0, 0.5) { true }

64-82: Improve variable naming and consider extracting animation logic.

The variable lastValue could be named more descriptively, and the animation logic could be extracted to improve readability.

             textField {
-                var lastValue = ""
+                var previousTextValue = ""
+                
+                /**
+                 * Triggers the change animation if the text has changed
+                 */
+                fun updateChangeAnimationIfNeeded(newText: String) {
+                    if (previousTextValue != newText) {
+                        changeAnimation = 0.0
+                        previousTextValue = newText
+                    }
+                }

                 onUpdate {
-                    lastValue = text
                     text = settingDelegate.toString()
-                    if (lastValue != text) changeAnimation = 0.0
+                    updateChangeAnimationIfNeeded(text)

30-33: Unused imports in the SettingSlider class.

Several math imports (PI, pow, sin) are included but not used in the code.

 import com.lambda.gui.impl.clickgui.module.SettingLayout
 import com.lambda.module.modules.client.ClickGui
 import com.lambda.util.math.lerp
-import kotlin.math.PI
-import kotlin.math.pow
-import kotlin.math.sin
common/src/main/kotlin/com/lambda/gui/component/window/WindowContent.kt (2)

54-67: Consider handling out-of-order or dynamically inserted children.

listify() arranges children only on creation or reflow, but dynamic inserts/removals at runtime may disrupt ordering. Consider adding checks or triggers that call listify() again once new children are inserted or removed.


110-114: Make scrolling speed configurable.

Using a fixed multiplier (dwheel += delta * 10.0) might feel too fast or too slow for some users. Exposing a setting for scroll sensitivity could enhance usability.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/core/SliderLayout.kt (1)

38-39: Consider more robust approach to managing SettingSlider.
The code casts owner to SettingSlider<*,*>, but if that cast fails, the reference is null, which may lead to unexpected behavior if owner is not a SettingSlider. Consider requiring a SettingSlider in the constructor or provide a fallback strategy to handle non-SettingSlider owners.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/ModuleLayout.kt (3)

52-85: Extract complex animation logic for better maintainability.
This block combines multiple reversed animations for enabling, hovering, and opening. Consider refactoring into a separate helper method or class for clarity, testability, and troubleshooting.


139-151: Allow multiple modules to remain open if desired.
When one module expands, this logic closes all others unless ClickGui.multipleSettingWindows is true. Confirm that a single expanded module is the ideal UX or consider offering a user setting to open multiple modules concurrently.


174-176: Prefer a more descriptive method name or add explicit KDoc.
moduleLayout(module: Module) is terse. Consider a name like addModuleLayout for clarity, or add more KDoc to clarify its purpose and behavior for future maintainers.

common/src/main/kotlin/com/lambda/gui/component/core/OutlineRect.kt (2)

27-29: Clarify how roundRadius and glowRadius interact.
Both properties affect rendering differently, but the exact relationship is unclear. Documenting their intended ranges (e.g., 0 to ∞) or providing usage notes will help other developers configure them confidently.


54-73: Reduce duplication among color setting methods.
setColor, setColorH, and setColorV each assign corner colors. Consider consolidating shared logic in a helper method to adhere to DRY principles and reduce future maintenance overhead.

common/src/main/kotlin/com/lambda/gui/component/layout/Layout.kt (3)

42-43: Address the TODO for advanced alignment logic.
The inline // ToDo: impl alignmentLayout: Layout, ... could be a blocker if you plan to support more elaborate alignment use cases soon. Consider scheduling or implementing it sooner to avoid confusion.


49-62: Handle child size exceeding owner’s boundaries.
When the child’s width or height is larger than the owner’s, clamping the position to [0, ownerSize - childSize] can lead to unexpected layout overlaps or forced zero positioning. Consider providing a fallback (e.g., partial visibility or scroll support) to improve usability in such edge cases.


77-79: Prevent problematic negative sizes.
Negative or zero sizes may cause unexpected clipping, alignment, or scissoring behaviors. If not supported, consider adding a safeguard:

 @UIRenderPr0p3rty var width = 0.0
+  set(value) { field = value.coerceAtLeast(0.0) }
 @UIRenderPr0p3rty var height = 0.0
+  set(value) { field = value.coerceAtLeast(0.0) }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7591b93 and a63d0a1.

📒 Files selected for processing (21)
  • common/src/main/kotlin/com/lambda/config/settings/FunctionSetting.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/graphics/buffer/VertexPipeline.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/FilledRectRenderer.kt (2 hunks)
  • common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/OutlineRectRenderer.kt (4 hunks)
  • common/src/main/kotlin/com/lambda/gui/GuiManager.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/core/OutlineRect.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/layout/Layout.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/window/TitleBar.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/window/Window.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/component/window/WindowContent.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/ModuleWindow.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/core/AnimatedChild.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/core/SliderLayout.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/ModuleLayout.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/SettingLayout.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/BooleanButton.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/EnumSlider.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/NumberSlider.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/SettingSlider.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/settings/UnitButton.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • common/src/main/kotlin/com/lambda/graphics/buffer/VertexPipeline.kt
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/settings/UnitButton.kt
  • common/src/main/kotlin/com/lambda/config/settings/FunctionSetting.kt
  • common/src/main/kotlin/com/lambda/gui/component/window/TitleBar.kt
  • common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/FilledRectRenderer.kt
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Build Lambda
🔇 Additional comments (37)
common/src/main/kotlin/com/lambda/graphics/renderer/gui/rect/OutlineRectRenderer.kt (7)

37-39: Good architectural change to singleton pattern

Changing from a class to a singleton object makes sense for renderers that don't need instance-specific state. This follows the principle that stateless utility components should be singletons. The inheritance change to AbstractGUIRenderer also suggests a cleaner renderer hierarchy.


22-25: Appropriate import updates

The new imports reflect the restructured architecture with the new GUI rendering system. Using the shader companion's shader() function appears to be part of a more consistent shader management approach.


40-41: Better constant declaration with const val

Good improvement changing from mutable properties to const val. This makes the constants truly immutable and allows for compile-time optimization, which can improve performance.


43-49: Improved method naming from build to outlineRect

The rename from build to outlineRect is more descriptive and clearly indicates the method's purpose. This enhances code readability and follows better naming practices.


60-63: Enhanced rendering control flow

The change from pipeline.use to render(shade) improves the control flow with a more structured rendering approach. The early return inside the lambda is clean and prevents unnecessary work for very small glow radii.


73-85: Improved UV mapping in vertex generation

The addition of UV mapping calculations using the transform function provides better texture coordinate generation. The vertex creation is now more streamlined with the builder pattern approach.


104-108: Consistent use of constants

Good change replacing the variable reference with the VERTICES_COUNT constant directly, which makes the code more consistent and easier to maintain.

common/src/main/kotlin/com/lambda/module/modules/client/ClickGui.kt (4)

34-64: New settings look good.

These newly added settings (titleBarHeight, moduleHeight, etc.) provide helpful customization for the GUI layout and styling. They’re straightforward, and the range constraints look reasonable.


69-69: Avoid using the not-null assertion operator.

Relying on owner!! can lead to runtime crashes if owner is null. Consider using safe calls or adding null checks to ensure a more robust implementation.


74-78: Replace hard-coded spacing and add window bounds checks.

  1. The constants var x = 10.0 and the + 5 increments are hard-coded, which limits customization. Consider extracting them into configurable properties.
  2. There's no check to keep modules within screen bounds (e.g., reset X and increase Y upon overflow). This can result in off-screen windows.

88-91: Confirm the toggle logic.

Calling toggle() immediately after SCREEN.show() may disable the module right away, possibly preventing users from seeing or interacting with the GUI. Verify if this behavior is intentional.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/NumberSlider.kt (1)

28-58: Consider edge cases and add tests.

The logic for converting, interpolating, and rounding numeric settings works well. However, consider verifying behavior for:

  • Reversed or invalid ranges (e.g., min > max)
  • Zero or negative steps
  • Large numeric values that might lead to floating-point precision issues

Also, add a few unit tests confirming these corner cases, ensuring that the slider behaves predictably under all circumstances.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/EnumSlider.kt (1)

26-56: Double-check boundary conditions and test coverage.

Your approach for mapping the slider’s position to an enum’s ordinal is conceptually sound. However, consider verifying:

  • Behavior if the Enum has only one value or an unexpected ordinal range
  • Potential “skipping” of intermediate enum values if the user drags the slider quickly

Adding dedicated unit tests covering these boundary scenarios will help catch any off-by-one errors or unexpected user interactions.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/BooleanButton.kt (5)

35-39: LGTM! Clean implementation of the BooleanButton component.

The class structure clearly extends SettingLayout with proper generic type parameters for Boolean and BooleanSetting.


42-63: Well-structured checkbox implementation with proper animations.

The checkbox implementation makes good use of reactive updates with the onUpdate handler, sets appropriate cursor behavior, and handles animations smoothly.


65-82: Nicely implemented knob animations with smooth transitions.

The knob component provides fluid animations between states using lerp functions for both position and color, ensuring a polished user experience.


93-95: Simple and effective click handler.

The click handler toggles the setting value directly, which is appropriate for this component.


99-104: Clean extension function for declarative UI building.

The companion object provides a well-documented extension function that follows the builder pattern, making it easy to create boolean settings in layouts.

common/src/main/kotlin/com/lambda/gui/GuiManager.kt (2)

36-38: Add error handling for duplicate type adapter registration.

The typeAdapter function should check for duplicate registrations to prevent overwriting existing adapters without warning.

 private inline fun <reified T : Any> typeAdapter(noinline block: (Layout, T) -> Layout) {
+    if (typeMap.containsKey(T::class)) {
+        throw IllegalStateException("Type adapter for ${T::class.simpleName} is already registered")
+    }
     typeMap[T::class] = { owner, converted -> block(owner, converted as T) }
 }

40-58: LGTM! Clear implementation of type adapters for settings.

The load() method cleanly registers type adapters for different setting types. The implementation is straightforward and follows a consistent pattern.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/ModuleWindow.kt (2)

59-65: LGTM! Clean implementation of the module window builder.

The companion object extension function follows the builder pattern well, making it easy to create and configure module windows.


38-42:

Details

✅ Verification successful

Verify filter approach for modules.

The code filters modules based on the first tag only, which may not be the intended behavior if modules can have multiple relevant tags.


🏁 Script executed:

#!/bin/bash
# Check if modules can have multiple tags and whether filtering by first tag only is appropriate

# Look for module implementations with multiple tags
rg -A 3 "defaultTags\s*=\s*listOf\(" --glob "*.kt"

# Check other locations that may handle module tags
rg "firstOrNull\(\)\s*==\s*tag" --glob "*.kt"

Length of output: 228


Module Filtering Approach Verified – No Changes Needed

I analyzed the filtering logic using our search tool and confirmed that the only instance using tag filtering is in common/src/main/kotlin/com/lambda/gui/impl/clickgui/ModuleWindow.kt, where modules are filtered by the first default tag. There’s no evidence in the codebase of alternative filtering for multiple tags, so the current approach appears intentional.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/SettingLayout.kt (2)

80-83: Be cautious with continuously scaling down the text.

Within titleBar.textField.onUpdate { scale *= 0.92 }, each update frame repeatedly shrinks the text. This may cause it to become overly small or even disappear over time. Verify if this behavior is intentional or if you meant to apply a one-time scale factor.

Would you like me to generate a quick script to search for all references to titleBar.textField.onUpdate in the repo to confirm if there's a single-time or repeated scale pattern?


61-66: Confirm content destruction logic for non-expandable settings.

Calling content.destroy() when expandable == false permanently removes any child components that might be important for layout continuity or future expansions. Verify if this is the intended behavior or if you need a mere hide/disabling mechanism.

common/src/main/kotlin/com/lambda/gui/component/window/Window.kt (2)

236-241: Expose or configure size constraints.

Hard-coded size bounds (coerceIn(80.0, 1000.0)) can be limiting for different screen resolutions and user preferences. Consider making them dynamic or configurable via a setting.


80-84: Validate expand/minimize side effects.

When toggling isMinimized, the code iterates over a list of actions in expandActions or minimizeActions. Confirm that no concurrency or ordering concerns arise if these actions modify the same underlying GUI states.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/core/SliderLayout.kt (3)

75-79: Guard against zero or negative width in slider transform.
When computing dragProgress, transform(...) uses bg.width in the range calculation. If bg.width becomes zero, this may introduce unexpected division by zero scenarios. Consider either ensuring bg.width remains positive or adding a check before transformation.

Would you like me to search for references to bg.width in your codebase to verify whether it can be zero?


92-101: Confirm layering of progress and outline.
You're rendering both a progress rectangle and an outline referencing the same rect. Ensure this layering is intentional and the outline is always drawn on top. If it can be visually obscured, consider using rectOver(...) or adjusting render order.


35-139: Overall slider design looks solid.
Beyond the minor casting and edge-case concerns, the slider logic is well-organized, with clear property blocks for progress and animations. Good job!

common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/ModuleLayout.kt (2)

123-126: Confirm that left-click toggling matches user expectations.
Toggling a module via a single left-click might conflict with a typical drag-to-move pattern or double-click approach. Verify this is intentional and won't cause confusion for users.


36-218: Great modular approach overall.
The module’s layout, animation, and event handling are well-organized and extensible. With the smaller refinements suggested, this is shaping up nicely.

common/src/main/kotlin/com/lambda/gui/component/core/OutlineRect.kt (1)

75-101: Builder methods are straightforward and cohesive.
The outline, outlineBehind, and outlineOver functions cleanly integrate with the UIBuilder pattern. This consistency is excellent for reusability.

common/src/main/kotlin/com/lambda/gui/component/layout/Layout.kt (5)

1-16: License header looks consistent.
No immediate issues with the GPL header.


121-121: Revisit minimal rendering dimensions.
renderSelf is disabled if width or height is ≤ 1. This might hide elements intended to be 1-pixel thick (e.g., lines or separators). Double-check whether this threshold is too restrictive.


282-290: Confirm whether child layouts need manual cleanup.
Currently, destroy() only removes this layout from its owner’s children, leaving the removal (or potential recursion) of its own children unaddressed. Verify if child resources or references need explicit disposal.


304-383: Event propagation logic might skip rendering for children.
Returning early on certain events (e.g., Render) means children only get rendered if renderSelf is true for the parent. Ensure this matches your design for layered or hidden-yet-interactive components.


385-455: Utility methods are well-structured.
The builder pattern for creating layouts, animation tickers, and cursor controllers is clear and aligns well with a modular DSL-like approach.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/NumberSlider.kt (1)

34-48: Slider initialization logic looks robust.

The initialization block correctly:

  1. Sets up the slider's progress using a transformation function that maps the current setting value from min-max to 0.0-1.0 range
  2. Defines an onSlide event handler that updates the setting value with appropriate interpolation and step rounding

A minor suggestion would be to add validation for the initial setting value to ensure it falls within the defined range.

init {
+    // Ensure initial value is within bounds
+    if (settingDelegate.toDouble() < min || settingDelegate.toDouble() > max) {
+        settingDelegate = settingDelegate.typeConvert(settingDelegate.toDouble().coerceIn(min, max))
+    }
+
    slider.progress {
        transform(
            settingDelegate.toDouble(),
            min, max,
            0.0, 1.0
        )
    }
    // Rest of the code remains the same
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a63d0a1 and bb7ff6b.

📒 Files selected for processing (5)
  • common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt (2 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/NumberSlider.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/SettingSlider.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt (3 hunks)
  • common/src/main/kotlin/com/lambda/util/math/MathUtils.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • common/src/main/kotlin/com/lambda/graphics/animation/Animation.kt
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/SettingSlider.kt
  • common/src/main/kotlin/com/lambda/module/modules/client/GuiSettings.kt
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Build Lambda
🔇 Additional comments (5)
common/src/main/kotlin/com/lambda/util/math/MathUtils.kt (1)

42-52: Improved numerical precision with BigDecimal.

The rewrite of roundToStep using BigDecimal addresses potential floating-point precision issues in the previous implementation. This is a good enhancement, especially for financial calculations or UI components where precise decimal rounding is critical.

The implementation correctly:

  • Handles division by zero
  • Uses appropriate rounding mode (HALF_UP)
  • Preserves original scale of the step value
  • Properly converts back to the original number type
common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/NumberSlider.kt (4)

1-16: License header looks good.

The GNU GPL v3 license header is properly included with correct formatting and copyright information.


18-27: Appropriate imports and package declaration.

The package declaration and imports are well-organized. The code correctly imports required components including the necessary math utility functions for slider operation.


28-33: Well-defined class signature with proper generic constraints.

The class definition is well-structured with appropriate generic constraints. The NumberSlider class properly extends SettingSlider and requires that the generic type V is both a Number and Comparable<V>, which are suitable constraints for a numeric value that needs to be compared for range validation.

The properties min and max are correctly initialized from the setting's range by converting to Double for consistent handling.


50-58: Companion object provides a clean DSL builder approach.

The companion object follows best practices by:

  1. Using the @UIBuilder annotation for DSL support
  2. Providing clear documentation for the extension function
  3. Using a concise builder pattern with apply(children::add) to integrate with the layout system

This approach ensures a clean, fluent API for creating numeric sliders in layouts.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (6)
common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontRenderer.kt (6)

41-42: Consider caching repeated property lookups.
These getters fetch from RenderSettings each time, which could be micro-optimized if invoked frequently within tight loops.


44-46: Avoid magic numbers.
The constants 10.0, 2.0f, 16f, 0.5f, and 0.8f might be more readable as named constants or part of the settings themselves.


99-107: Potential duplication with drawString.
Consider extracting common rendering logic for glyph scaling and positioning into a shared helper to reduce code duplication.


173-173: Magic number 0.7 might need clarification.
Consider referencing a named constant or explaining its origin in a comment for maintainability.


185-257: Complex method structure.
Consider breaking processText into smaller helper functions to improve readability and maintainability.


265-265: Magic number 8.5 might need clarification.
Consider referencing a named constant or explaining its origin in a comment for maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb7ff6b and 645bc2b.

📒 Files selected for processing (4)
  • common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontRenderer.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/core/SliderLayout.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/SettingSlider.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/SettingSlider.kt
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Build Lambda
🔇 Additional comments (25)
common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt (3)

20-21: Adding font-related imports aligns with the new texture API.

The imports for LambdaEmoji and LambdaFont support the new font configurations added to the RenderSettings module, which is consistent with the PR's objectives to update fonts and text rendering.


34-35: Well-structured font configuration settings.

Adding dedicated settings for text and emoji fonts provides users with more customization options and supports the new font rendering system mentioned in the PR. These settings don't have page visibility conditions, making them always accessible regardless of the selected page.


42-43: SDF parameters properly configured for font rendering enhancement.

The new SDF (Signed Distance Field) min/max parameters will help control the sharpness and clarity of font rendering at different scales, which aligns with the PR's goal of "enhancing character clarity at any scale or transformation." The visibility condition ensures these settings only appear on the Font page.

Ensure that these default values (0.4 for min, 1.0 for max) have been tested across different font sizes and scaling scenarios to confirm optimal rendering quality.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/core/SliderLayout.kt (5)

1-16: License header
No issues found with the GPL license header. Everything looks consistent and properly configured.


82-92: Well-managed mouse event handling
The logic for setting the slider’s progress on mouse move and click events is straightforward and properly constrained to the left mouse button. This approach should be robust for typical slider interactions.


93-112: Smooth rendering of progress and outline
The code cleanly splits drawing of the filled area (rect {}) and outline (outline {}), applying animations and color alpha calculations. The operation width *= renderProgress is clear, though ensuring renderProgress stays within [0,1] is important to prevent abnormal visuals.


115-141: DSL methods provide a neat UI builder pattern
The companion object’s slider, sliderBehind, and sliderOver methods enable flexible composition with other layouts. This approach is consistent with Kotlin DSL best practices and promotes reusability.


64-81:

Details

❓ Verification inconclusive

Ensure bg.width is non-zero when transforming mouse coordinates
The dragProgress computation leverages bg.width in a transform from [0, bg.width] to [0, 1]. If bg.width is ever zero or negative for some reason, the transform might produce unexpected values (NaN or Infinity). Confirm or enforce a minimum width to avoid edge cases.


🏁 Script executed:

#!/bin/bash
# Description: Search for calls that set the slider width or affect `bg.width` to confirm it is always > 0.
ast-grep --pattern $'bg.width = $_' 

Length of output: 36


Action Required: Validate and Safeguard bg.width in SliderLayout

The current implementation calculates dragProgress by mapping mousePosition.x from the interval [0, bg.width] to [0, 1]. However, our initial search for explicit assignments or checks that guarantee a positive bg.width returned no results. This suggests that the rectangle’s width is implicitly inherited from its parent or default settings. To prevent potentially unexpected transform results (like NaN or Infinity) when bg.width is zero or negative, please verify manually that:

  • The rectangle defined in the rect { ... } block (which initializes bg) guarantees a positive width at all times.
  • If there exists a scenario where bg.width might be zero or negative, a safeguard (such as enforcing a minimum width or performing a conditional check) is in place.

Locations to review:

  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/core/SliderLayout.kt, specifically:
    • Lines 64-81 (initialization of bg and computation of dragProgress).

Please confirm the width’s validity and consider adding an explicit check if necessary.

common/src/main/kotlin/com/lambda/graphics/renderer/gui/font/FontRenderer.kt (17)

22-27: No immediate concerns with these import statements.


30-30: No additional comments.


36-39: Documentation is sufficiently clear.


40-40: Singleton usage makes sense here.


49-57: Documentation is well-structured.


60-65: Default parameter usage is consistent.
No issues found.


66-71: Shader uniform assignments look correct.


73-74: Callback approach is flexible.
No immediate issues spotted.


79-85: Clear documentation of drawGlyph.


86-91: Function signature is clear.
No issues found.


92-98: Shader uniform assignment is repeated here but appears valid.
No concurrency or correctness concerns identified.


109-117: Documentation is consistent with the method's purpose.


118-138: Quad rendering approach is straightforward.
The usage of grow(4) ensures sufficient buffer capacity. Implementation looks solid.


140-146: Documentation for getWidth is acceptable.


164-172: Documentation for getHeight is clear.


176-184: Process text documentation is thorough.


259-264: Clear doc for getScaleFactor.

Comment on lines +39 to +43
// Not a great solution
private val setting = owner as? SettingSlider<*, *>
private val showAnim get() = setting?.showAnimation ?: showAnimation
private val hoverAnim get() = setting?.hoverAnimation ?: hoverAnimation
private val pressedBut get() = setting?.pressedButton ?: pressedButton
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid over-reliance on casting to SettingSlider
Relying on owner as? SettingSlider<*, *> and storing it in setting may introduce subtle bugs if the layout isn't a SettingSlider. The comment “Not a great solution” underscores this. Consider using a design where the slider logic is decoupled from the exact type of the parent or use composition/dependency injection for better separation of concerns.

Comment on lines +267 to 279
/**
* Calculates the shadow color by adjusting the brightness of the input color.
*
* @param color The original color.
* @return The modified shadow color.
*/
fun getShadowColor(color: Color): Color = Color(
(color.red * RenderSettings.shadowBrightness).toInt(),
(color.green * RenderSettings.shadowBrightness).toInt(),
(color.blue * RenderSettings.shadowBrightness).toInt(),
color.alpha
)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Potential out-of-range color values.
If RenderSettings.shadowBrightness is outside the range [0.0, 1.0], (color.red * RenderSettings.shadowBrightness).toInt() can overflow the 0–255 bounds, potentially causing an exception. Consider clamping the values:

-fun getShadowColor(color: Color): Color = Color(
-    (color.red * RenderSettings.shadowBrightness).toInt(),
-    (color.green * RenderSettings.shadowBrightness).toInt(),
-    (color.blue * RenderSettings.shadowBrightness).toInt(),
-    color.alpha
-)
+fun getShadowColor(color: Color): Color {
+    val r = ((color.red * RenderSettings.shadowBrightness).coerceIn(0.0, 255.0)).toInt()
+    val g = ((color.green * RenderSettings.shadowBrightness).coerceIn(0.0, 255.0)).toInt()
+    val b = ((color.blue * RenderSettings.shadowBrightness).coerceIn(0.0, 255.0)).toInt()
+    return Color(r, g, b, color.alpha)
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Calculates the shadow color by adjusting the brightness of the input color.
*
* @param color The original color.
* @return The modified shadow color.
*/
fun getShadowColor(color: Color): Color = Color(
(color.red * RenderSettings.shadowBrightness).toInt(),
(color.green * RenderSettings.shadowBrightness).toInt(),
(color.blue * RenderSettings.shadowBrightness).toInt(),
color.alpha
)
}
/**
* Calculates the shadow color by adjusting the brightness of the input color.
*
* @param color The original color.
* @return The modified shadow color.
*/
fun getShadowColor(color: Color): Color {
val r = ((color.red * RenderSettings.shadowBrightness).coerceIn(0.0, 255.0)).toInt()
val g = ((color.green * RenderSettings.shadowBrightness).coerceIn(0.0, 255.0)).toInt()
val b = ((color.blue * RenderSettings.shadowBrightness).coerceIn(0.0, 255.0)).toInt()
return Color(r, g, b, color.alpha)
}
}

Comment on lines +148 to 162
fun getWidth(
text: String,
scale: Double = 1.0,
parseEmoji: Boolean = LambdaMoji.isEnabled,
): Double {
var width = 0.0
iterateText(text, scale, false) { char, _, _, _ -> width += char.width + gap }
return width * getScaleFactor(scale)
var gaps = -1

processText(text, scale = scale, parseEmoji = parseEmoji) { char, _, _, _, isShadow ->
if (isShadow) return@processText
width += char.width; gaps++
}

return (width + gaps.coerceAtLeast(0) * gap) * getScaleFactor(scale)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Potential inaccuracy for multi-line text measurement.
When encountering newline characters, the current logic resets posX but does not track the maximum width per line. The returned value may only reflect the final line’s width.

Consider tracking the maximum line width, for example:

 var width = 0.0
+var maxWidth = 0.0
 var gaps = -1

 processText(text, scale = scale, parseEmoji = parseEmoji) { char, _, _, _, isShadow ->
     if (isShadow) return@processText
     width += char.width
     gaps++
+    maxWidth = maxOf(maxWidth, width + gaps.coerceAtLeast(0) * gap)
 }

-return (width + gaps.coerceAtLeast(0) * gap) * getScaleFactor(scale)
+return maxWidth * getScaleFactor(scale)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fun getWidth(
text: String,
scale: Double = 1.0,
parseEmoji: Boolean = LambdaMoji.isEnabled,
): Double {
var width = 0.0
iterateText(text, scale, false) { char, _, _, _ -> width += char.width + gap }
return width * getScaleFactor(scale)
var gaps = -1
processText(text, scale = scale, parseEmoji = parseEmoji) { char, _, _, _, isShadow ->
if (isShadow) return@processText
width += char.width; gaps++
}
return (width + gaps.coerceAtLeast(0) * gap) * getScaleFactor(scale)
}
fun getWidth(
text: String,
scale: Double = 1.0,
parseEmoji: Boolean = LambdaMoji.isEnabled,
): Double {
var width = 0.0
var maxWidth = 0.0
var gaps = -1
processText(text, scale = scale, parseEmoji = parseEmoji) { char, _, _, _, isShadow ->
if (isShadow) return@processText
width += char.width
gaps++
maxWidth = maxOf(maxWidth, width + gaps.coerceAtLeast(0) * gap)
}
return maxWidth * getScaleFactor(scale)
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/SettingSlider.kt (1)

51-82: Consider handling direct user input through the text field

The current implementation only shows the setting value in the text field but doesn't appear to allow users to directly input values. If this is intentional, it's fine, but if direct text input is desired, you'll need to add handling for user input events.

Additionally, note that the animation will only trigger when the string representation changes. If two different setting values produce the same string output, the animation won't trigger.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 645bc2b and 803e630.

📒 Files selected for processing (4)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/EnumSlider.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/NumberSlider.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/SettingSlider.kt (1 hunks)
  • common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • common/src/main/kotlin/com/lambda/module/modules/client/RenderSettings.kt
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Build Lambda
🔇 Additional comments (9)
common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/NumberSlider.kt (3)

28-36: Well-structured generic class design

The NumberSlider class has appropriate generic constraints (where V : Number, V : Comparable<V>) and properly handles numeric range values by converting them to Double. This provides type safety while supporting all numeric types that can be used with settings.


37-51: Clean implementation of slider behavior

The slider implementation properly transforms the setting value to a 0.0-1.0 range for the slider progress and handles the inverse operation when the user interacts with the slider. The use of roundToStep ensures values align with the setting's defined step size.


53-60: Good use of companion object for DSL-style builder function

The companion object with the @UIBuilder annotation provides a clean, idiomatic way to create sliders within a layout. The extension function approach follows Kotlin best practices for DSL construction.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/EnumSlider.kt (3)

26-32: Good inheritance design for enum settings

The EnumSlider class properly extends the base SettingSlider class and is constrained to work with enum types, providing a specialized implementation for handling enumerated values.


33-49: Verify boundary behavior when slider is at maximum position

The calculation (it * entries.size).floorToInt() could potentially produce an index equal to entries.size when the slider is at exactly 1.0. While the coerceIn call correctly handles this case, consider using (it * (entries.size - 1)).roundToInt() for more intuitive mapping.

The current implementation works because of the bounds check, but the suggested approach might provide more consistent selection behavior across the slider's range.


51-58: Good use of companion object with UIBuilder annotation

Similar to the NumberSlider, this implementation provides a clean DSL-style builder function. The consistent pattern across different setting types makes the API intuitive to use.

common/src/main/kotlin/com/lambda/gui/impl/clickgui/module/settings/SettingSlider.kt (3)

31-39: Well-designed abstract base class for sliders

The SettingSlider abstract class provides a solid foundation for different types of sliders. The generic parameters are appropriately constrained, and the abstract settingValue property ensures that derived classes properly format their values as strings.


40-50: Good positioning logic for the slider component

The slider component is properly positioned relative to its parent layout, with clean update logic that keeps the slider in sync with the parent's dimensions.


36-36:

Details

❓ Verification inconclusive

Verify animation behavior with always-true condition

The animation setup uses by animation.exp(0.0, 1.0, 0.5) { true } with a lambda that always returns true. Confirm that this is the intended behavior, as it means the animation will always be considered active.


🏁 Script executed:

#!/bin/bash
# Search for other uses of this animation pattern to understand if this is a common pattern
rg "by animation\.exp\(.*\) \{ true \}" -A 2 -B 2

Length of output: 624


Ensure Intended Always-Active Animation Behavior

The usage of by animation.exp(0.0, 1.0, 0.5) { true } is unique to this file, which suggests it might be a deliberate design decision to have the animation always active. Please confirm whether an always-true condition is indeed intended for changeAnimation. If so, consider adding a clarifying comment to document that this behavior is by design.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
common/src/main/kotlin/com/lambda/module/Module.kt (1)

148-162: 🛠️ Refactor suggestion

Remove duplicated onEnable/onDisable blocks.

These repeated definitions for enabling/disabling the module produce the same effect multiple times. Consolidate them into a single pair of onEnable/onDisable calls:

--- a/common/src/main/kotlin/com/lambda/module/Module.kt
+++ b/common/src/main/kotlin/com/lambda/module/Module.kt
@@ -148,15 +148,6 @@
         onEnable {
             playSoundRandomly(LambdaSound.MODULE_ON.event)
         }
-
-        onDisable {
-            playSoundRandomly(LambdaSound.MODULE_OFF.event)
-        }
-    }
-
-    onEnable {
-        playSoundRandomly(LambdaSound.MODULE_ON.event)
-    }
-
-    onDisable {
-        playSoundRandomly(LambdaSound.MODULE_OFF.event)
-    }
🧹 Nitpick comments (1)
common/src/main/kotlin/com/lambda/module/hud/ModuleList.kt (1)

36-38: Combine filters for cleaner code.

Currently, modules are filtered twice based on it.isEnabled and it.isVisible.value. Combining these checks into a single filter can slightly improve readability:

-            val enabled = ModuleRegistry.modules
-                .filter { it.isEnabled }
-                .filter { it.isVisible.value }
+            val enabled = ModuleRegistry.modules
+                .filter { it.isEnabled && it.isVisible.value }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 803e630 and 87ecb9c.

📒 Files selected for processing (2)
  • common/src/main/kotlin/com/lambda/module/Module.kt (3 hunks)
  • common/src/main/kotlin/com/lambda/module/hud/ModuleList.kt (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Build Lambda
🔇 Additional comments (2)
common/src/main/kotlin/com/lambda/module/Module.kt (2)

120-120: Confirm logic for isVisible dependency.

isVisible depends on ModuleList.isEnabled. If ModuleList is disabled, isVisible will always be false. Verify that this is the intended behavior, especially if modules should remain visible regardless of ModuleList's status.


121-121: Reset property looks great.

The reset logic is straightforward. Proceed with caution if there's any data or side effects that should not be reverted automatically.

@Avanatiker Avanatiker merged commit 6c90f18 into master Mar 12, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants