// src/engine/ui/Checkbox.js
import BaseUIElement from './BaseUIElement.js'
/**
* @class Checkbox
* @extends BaseUIElement
* @description An interactive UI element that represents a boolean state (checked/unchecked).
*/
class Checkbox extends BaseUIElement {
/**
* Creates an instance of Checkbox.
* @param {object} options - Configuration options for the checkbox.
* @param {number} [options.x=0] - The x-coordinate of the checkbox (top-left of the box).
* @param {number} [options.y=0] - The y-coordinate of the checkbox (top-left of the box).
* @param {string} [options.label=''] - Text label to display next to the checkbox.
* @param {boolean} [options.isChecked=false] - Initial checked state.
* @param {number} [options.boxSize=16] - The size (width and height) of the checkbox square.
* @param {number} [options.labelOffset=5] - Space between the checkbox and the label text.
* @param {string} [options.font='16px sans-serif'] - Font for the label.
* @param {string} [options.textColor='white'] - Color for the label text.
* @param {string} [options.boxColor='white'] - Color of the checkbox border/box.
* @param {string} [options.checkColor='dodgerblue'] - Color of the checkmark or fill when checked.
* @param {string} [options.hoverBoxColor=null] - Optional: Color of the box when hovered (if you implement hover visual state).
* @param {string} [options.disabledColor='gray'] - Color for box and text when disabled.
* @param {string} [options.disabledCheckColor='darkgray'] - Color for the checkmark when disabled and checked.
* @param {function} [options.onClick] - Callback function when the checkbox is clicked (state toggled).
* @param {boolean} [options.visible=true] - Whether the checkbox is visible.
* @param {boolean} [options.enabled=true] - Whether the checkbox is enabled.
* @param {string} [options.id] - Optional ID.
* @param {number} [options.width] - Optional: Explicit width for the entire clickable area (box + label).
* @param {number} [options.height] - Optional: Explicit height for the entire clickable area.
*/
constructor(options = {}) {
const boxSize = options.boxSize || 16
const labelOffset = options.labelOffset || 5
let estimatedWidth = boxSize
if (options.label) {
// A more accurate width estimation would require measuring text with canvas context.
// For simplicity, this is a rough estimate.
// Consider setting explicit width if precise hit area for label text is needed.
estimatedWidth += labelOffset + options.label.length * (boxSize * 0.6) // Rough estimate
}
super({
...options,
width: options.width !== undefined ? options.width : estimatedWidth,
height: options.height !== undefined ? options.height : boxSize,
})
this.label = options.label || ''
this.isChecked = !!options.isChecked // Ensure boolean
this.boxSize = boxSize
this.labelOffset = labelOffset
this.font = options.font || '16px sans-serif'
this.textColor = options.textColor || 'white'
this.boxColor = options.boxColor || 'white'
this.checkColor = options.checkColor || 'dodgerblue'
this.hoverBoxColor = options.hoverBoxColor || null
this.disabledColor = options.disabledColor || 'gray'
this.disabledCheckColor = options.disabledCheckColor || 'darkgray'
this.isHovered = false // For visual feedback on hover, if desired
}
/**
* Toggles the checked state of the checkbox.
* Also triggers the onClick callback.
*/
toggle() {
if (!this.enabled || !this.visible) return
this.isChecked = !this.isChecked
this._triggerClick() // Call the inherited click handler from BaseUIElement
}
/**
* Sets the checked state of the checkbox.
* @param {boolean} checked - The new checked state.
* @param {boolean} [triggerCallback=false] - Whether to trigger the onClick callback.
*/
setChecked(checked, triggerCallback = false) {
if (!this.enabled || !this.visible) return
const newState = !!checked
if (this.isChecked !== newState) {
this.isChecked = newState
if (triggerCallback) {
this._triggerClick()
}
}
}
/**
* Updates the checkbox's state based on mouse input.
* @param {number} deltaTime - The time elapsed since the last frame.
* @param {import('../core/IroncladEngine.js').default} engine - The engine instance.
* @param {{x: number, y: number}} mousePos - Current canvas-relative mouse position.
*/
update(deltaTime, engine, mousePos) {
super.update(deltaTime, engine, mousePos) // Call base update
if (!this.visible || !this.enabled) {
this.isHovered = false
return
}
// The clickable area is defined by this.x, this.y, this.width, this.height from BaseUIElement
this.isHovered = this.containsPoint(mousePos.x, mousePos.y)
const inputManager = engine.inputManager
if (
this.isHovered &&
inputManager.isMouseButtonJustPressed(inputManager.constructor.MOUSE_BUTTON_LEFT)
) {
this.toggle()
}
}
/**
* Specific drawing logic for the Checkbox.
* Called by BaseUIElement.render after visibility and context checks.
* @param {CanvasRenderingContext2D} context - The rendering context.
* @param {import('../core/IroncladEngine.js').default} engine - The engine instance.
* @protected
*/
_drawSelf(context, engine) {
// Determine colors based on enabled state
const currentBoxColor = !this.enabled
? this.disabledColor
: this.isHovered && this.hoverBoxColor
? this.hoverBoxColor
: this.boxColor
const currentTextColor = !this.enabled ? this.disabledColor : this.textColor
const currentCheckColor = !this.enabled ? this.disabledCheckColor : this.checkColor
// Draw the checkbox square
context.strokeStyle = currentBoxColor
context.lineWidth = 2
context.strokeRect(this.x, this.y, this.boxSize, this.boxSize)
// Draw the checkmark if checked
if (this.isChecked) {
context.fillStyle = currentCheckColor
// Simple filled square as checkmark
const padding = Math.max(2, this.boxSize / 5) // Ensure padding is reasonable
context.fillRect(
this.x + padding,
this.y + padding,
this.boxSize - padding * 2,
this.boxSize - padding * 2,
)
}
// Draw the label text
if (this.label) {
context.font = this.font
context.fillStyle = currentTextColor
context.textAlign = 'left'
context.textBaseline = 'middle' // Align text vertically with the middle of the box
context.fillText(
this.label,
this.x + this.boxSize + this.labelOffset,
this.y + this.boxSize / 2,
)
}
}
}
export default Checkbox