package rui import ( "strings" ) // CheckboxChangedEvent is the constant for "checkbox-event" property tag. // // Used by `Checkbox`. // Event occurs when the checkbox becomes checked/unchecked. // // General listener format: // `func(checkbox rui.Checkbox, checked bool)`. // // where: // checkbox - Interface of a checkbox which generated this event, // checked - Checkbox state. // // Allowed listener formats: // `func(checkbox rui.Checkbox)`, // `func(checked bool)`, // `func()`. const CheckboxChangedEvent PropertyName = "checkbox-event" // Checkbox represent a Checkbox view type Checkbox interface { ViewsContainer } type checkboxData struct { viewsContainerData } // NewCheckbox create new Checkbox object and return it func NewCheckbox(session Session, params Params) Checkbox { view := new(checkboxData) view.init(session) setInitParams(view, params) return view } func newCheckbox(session Session) View { return new(checkboxData) } func (button *checkboxData) init(session Session) { button.viewsContainerData.init(session) button.tag = "Checkbox" button.systemClass = "ruiGridLayout ruiCheckbox" button.set = button.setFunc button.remove = button.removeFunc button.changed = button.propertyChanged button.setRaw(ClickEvent, []func(View, MouseEvent){checkboxClickListener}) button.setRaw(KeyDownEvent, []func(View, KeyEvent){checkboxKeyListener}) } func (button *checkboxData) Focusable() bool { return true } func (button *checkboxData) propertyChanged(tag PropertyName) { switch tag { case Checked: session := button.Session() checked := IsCheckboxChecked(button) if listeners := GetCheckboxChangedListeners(button); len(listeners) > 0 { for _, listener := range listeners { listener(button, checked) } } buffer := allocStringBuilder() defer freeStringBuilder(buffer) checkboxHtml(button, buffer, checked) session.updateInnerHTML(button.htmlID()+"checkbox", buffer.String()) case CheckboxHorizontalAlign, CheckboxVerticalAlign: htmlID := button.htmlID() session := button.Session() updateCSSStyle(htmlID, session) updateInnerHTML(htmlID, session) case VerticalAlign: button.Session().updateCSSProperty(button.htmlID()+"content", "align-items", checkboxVerticalAlignCSS(button)) case HorizontalAlign: button.Session().updateCSSProperty(button.htmlID()+"content", "justify-items", checkboxHorizontalAlignCSS(button)) case AccentColor: updateInnerHTML(button.htmlID(), button.Session()) default: button.viewsContainerData.propertyChanged(tag) } } func (button *checkboxData) setFunc(tag PropertyName, value any) []PropertyName { switch tag { case ClickEvent: if listeners, ok := valueToOneArgEventListeners[View, MouseEvent](value); ok && listeners != nil { listeners = append(listeners, checkboxClickListener) button.setRaw(tag, listeners) return []PropertyName{tag} } return nil case KeyDownEvent: if listeners, ok := valueToOneArgEventListeners[View, KeyEvent](value); ok && listeners != nil { listeners = append(listeners, checkboxKeyListener) button.setRaw(tag, listeners) return []PropertyName{tag} } return nil case CheckboxChangedEvent: return setOneArgEventListener[Checkbox, bool](button, tag, value) case Checked: return setBoolProperty(button, Checked, value) case CellVerticalAlign, CellHorizontalAlign, CellWidth, CellHeight: ErrorLogF(`"%s" property is not compatible with the BoundsProperty`, string(tag)) return nil } return button.viewsContainerData.setFunc(tag, value) } func (button *checkboxData) removeFunc(tag PropertyName) []PropertyName { switch tag { case ClickEvent: button.setRaw(ClickEvent, []func(View, MouseEvent){checkboxClickListener}) return []PropertyName{ClickEvent} case KeyDownEvent: button.setRaw(KeyDownEvent, []func(View, KeyEvent){checkboxKeyListener}) return []PropertyName{ClickEvent} } return button.viewsContainerData.removeFunc(tag) } /* func (button *checkboxData) changedCheckboxState(state bool) { for _, listener := range GetCheckboxChangedListeners(button) { listener(button, state) } buffer := allocStringBuilder() defer freeStringBuilder(buffer) button.htmlCheckbox(buffer, state) button.Session().updateInnerHTML(button.htmlID()+"checkbox", buffer.String()) } */ func checkboxClickListener(view View, _ MouseEvent) { view.Set(Checked, !IsCheckboxChecked(view)) BlurView(view) } func checkboxKeyListener(view View, event KeyEvent) { switch event.Code { case "Enter", "Space": view.Set(Checked, !IsCheckboxChecked(view)) } } func (button *checkboxData) cssStyle(self View, builder cssBuilder) { session := button.Session() vAlign := GetCheckboxVerticalAlign(button) hAlign := GetCheckboxHorizontalAlign(button) switch hAlign { case CenterAlign: if vAlign == BottomAlign { builder.add("grid-template-rows", "1fr auto") } else { builder.add("grid-template-rows", "auto 1fr") } case RightAlign: builder.add("grid-template-columns", "1fr auto") default: builder.add("grid-template-columns", "auto 1fr") } if gap, ok := sizeConstant(session, "ruiCheckboxGap"); ok && gap.Type != Auto && gap.Value > 0 { builder.add("gap", gap.cssString("0", session)) } builder.add("align-items", "stretch") builder.add("justify-items", "stretch") button.viewsContainerData.cssStyle(self, builder) } func checkboxHtml(button View, buffer *strings.Builder, checked bool) (int, int) { //func (button *checkboxData) htmlCheckbox(buffer *strings.Builder, checked bool) (int, int) { vAlign := GetCheckboxVerticalAlign(button) hAlign := GetCheckboxHorizontalAlign(button) buffer.WriteString(`
`) accentColor := Color(0) if color := GetAccentColor(button, ""); color != 0 { accentColor = color } if checked { buffer.WriteString(button.Session().checkboxOnImage(accentColor)) } else { buffer.WriteString(button.Session().checkboxOffImage(accentColor)) } buffer.WriteString(`
`) return vAlign, hAlign } func (button *checkboxData) htmlSubviews(self View, buffer *strings.Builder) { vCheckboxAlign, hCheckboxAlign := checkboxHtml(button, buffer, IsCheckboxChecked(button)) buffer.WriteString(`
`) button.viewsContainerData.htmlSubviews(self, buffer) buffer.WriteString(`
`) } func checkboxHorizontalAlignCSS(view View) string { align := GetHorizontalAlign(view) values := enumProperties[CellHorizontalAlign].cssValues if align >= 0 && align < len(values) { return values[align] } return values[0] } func checkboxVerticalAlignCSS(view View) string { align := GetVerticalAlign(view) values := enumProperties[CellVerticalAlign].cssValues if align >= 0 && align < len(values) { return values[align] } return values[0] } // IsCheckboxChecked returns true if the Checkbox is checked, false otherwise. // If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. func IsCheckboxChecked(view View, subviewID ...string) bool { return boolStyledProperty(view, subviewID, Checked, false) } // GetCheckboxVerticalAlign return the vertical align of a Checkbox subview: TopAlign (0), BottomAlign (1), CenterAlign (2) // If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned func GetCheckboxVerticalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, CheckboxVerticalAlign, LeftAlign, false) } // GetCheckboxHorizontalAlign return the vertical align of a Checkbox subview: LeftAlign (0), RightAlign (1), CenterAlign (2) // If the second argument (subviewID) is not specified or it is "" then a left position of the first argument (view) is returned func GetCheckboxHorizontalAlign(view View, subviewID ...string) int { return enumStyledProperty(view, subviewID, CheckboxHorizontalAlign, TopAlign, false) } // GetCheckboxChangedListeners returns the CheckboxChangedListener list of an Checkbox subview. // If there are no listeners then the empty list is returned // If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned. func GetCheckboxChangedListeners(view View, subviewID ...string) []func(Checkbox, bool) { return getOneArgEventListeners[Checkbox, bool](view, subviewID, CheckboxChangedEvent) }