rui_orig/checkbox.go

345 lines
10 KiB
Go
Raw Normal View History

2021-09-07 17:36:50 +03:00
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()`.
2024-11-13 12:56:39 +03:00
const CheckboxChangedEvent PropertyName = "checkbox-event"
2021-09-07 17:36:50 +03:00
// Checkbox represent a Checkbox view
2021-09-07 17:36:50 +03:00
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)
2021-09-07 17:36:50 +03:00
setInitParams(view, params)
return view
}
func newCheckbox(session Session) View {
2024-11-13 12:56:39 +03:00
return new(checkboxData)
2021-09-07 17:36:50 +03:00
}
func (button *checkboxData) init(session Session) {
button.viewsContainerData.init(session)
2021-09-07 17:36:50 +03:00
button.tag = "Checkbox"
button.systemClass = "ruiGridLayout ruiCheckbox"
2024-11-13 12:56:39 +03:00
button.set = button.setFunc
button.remove = button.removeFunc
button.changed = checkboxPropertyChanged
2021-09-07 17:36:50 +03:00
2024-11-13 12:56:39 +03:00
button.setRaw(ClickEvent, checkboxClickListener)
button.setRaw(KeyDownEvent, checkboxKeyListener)
2022-05-22 12:54:02 +03:00
}
2021-09-07 17:36:50 +03:00
func (button *checkboxData) Focusable() bool {
return true
}
2024-11-13 12:56:39 +03:00
func checkboxPropertyChanged(view View, tag PropertyName) {
switch tag {
2021-09-07 17:36:50 +03:00
case Checked:
2024-11-13 12:56:39 +03:00
session := view.Session()
checked := IsCheckboxChecked(view)
if listeners := GetCheckboxChangedListeners(view); len(listeners) > 0 {
if checkbox, ok := view.(Checkbox); ok {
for _, listener := range listeners {
listener(checkbox, checked)
}
2021-09-07 17:36:50 +03:00
}
}
2024-11-13 12:56:39 +03:00
buffer := allocStringBuilder()
defer freeStringBuilder(buffer)
checkboxHtml(view, buffer, checked)
session.updateInnerHTML(view.htmlID()+"checkbox", buffer.String())
2021-09-07 17:36:50 +03:00
case CheckboxHorizontalAlign, CheckboxVerticalAlign:
2024-11-13 12:56:39 +03:00
htmlID := view.htmlID()
session := view.Session()
updateCSSStyle(htmlID, session)
updateInnerHTML(htmlID, session)
2021-09-07 17:36:50 +03:00
case VerticalAlign:
2024-11-13 12:56:39 +03:00
view.Session().updateCSSProperty(view.htmlID()+"content", "align-items", checkboxVerticalAlignCSS(view))
2021-09-07 17:36:50 +03:00
case HorizontalAlign:
2024-11-13 12:56:39 +03:00
view.Session().updateCSSProperty(view.htmlID()+"content", "justify-items", checkboxHorizontalAlignCSS(view))
case AccentColor:
2024-11-13 12:56:39 +03:00
updateInnerHTML(view.htmlID(), view.Session())
default:
2024-11-13 12:56:39 +03:00
viewsContainerPropertyChanged(view, tag)
2021-09-07 17:36:50 +03:00
}
}
2024-11-13 12:56:39 +03:00
func (button *checkboxData) setFunc(view View, tag PropertyName, value any) []PropertyName {
switch tag {
case ClickEvent:
2024-11-13 12:56:39 +03:00
if button.viewsContainerData.setFunc(view, ClickEvent, value) != nil {
if value := view.getRaw(ClickEvent); value != nil {
if listeners, ok := value.([]func(View, MouseEvent)); ok {
listeners = append(listeners, checkboxClickListener)
view.setRaw(ClickEvent, listeners)
return []PropertyName{ClickEvent}
}
}
return button.viewsContainerData.setFunc(view, ClickEvent, checkboxClickListener)
}
2024-11-13 12:56:39 +03:00
return nil
case KeyDownEvent:
2024-11-13 12:56:39 +03:00
if button.viewsContainerData.setFunc(view, KeyDownEvent, value) != nil {
if value := view.getRaw(KeyDownEvent); value != nil {
if listeners, ok := value.([]func(View, KeyEvent)); ok {
listeners = append(listeners, checkboxKeyListener)
view.setRaw(KeyDownEvent, listeners)
return []PropertyName{KeyDownEvent}
}
}
return button.viewsContainerData.setFunc(view, KeyDownEvent, checkboxKeyListener)
}
2024-11-13 12:56:39 +03:00
return nil
2021-09-07 17:36:50 +03:00
case CheckboxChangedEvent:
2024-11-13 12:56:39 +03:00
return setViewEventListener[Checkbox, bool](view, tag, value)
2021-09-07 17:36:50 +03:00
case Checked:
2024-11-13 12:56:39 +03:00
return setBoolProperty(view, Checked, value)
2021-09-07 17:36:50 +03:00
2024-11-13 12:56:39 +03:00
case CellVerticalAlign, CellHorizontalAlign, CellWidth, CellHeight:
ErrorLogF(`"%s" property is not compatible with the BoundsProperty`, string(tag))
return nil
}
2021-09-07 17:36:50 +03:00
2024-11-13 12:56:39 +03:00
return button.viewsContainerData.setFunc(view, tag, value)
}
2021-09-07 17:36:50 +03:00
2024-11-13 12:56:39 +03:00
func (button *checkboxData) removeFunc(view View, tag PropertyName) []PropertyName {
switch tag {
case ClickEvent:
button.setRaw(ClickEvent, checkboxClickListener)
return []PropertyName{ClickEvent}
2021-09-07 17:36:50 +03:00
2024-11-13 12:56:39 +03:00
case KeyDownEvent:
button.setRaw(KeyDownEvent, checkboxKeyListener)
return []PropertyName{ClickEvent}
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
return button.viewsContainerData.removeFunc(view, tag)
2021-09-07 17:36:50 +03:00
}
func (button *checkboxData) checked() bool {
checked, _ := boolProperty(button, Checked, button.Session())
return checked
}
2024-11-13 12:56:39 +03:00
/*
2021-09-07 17:36:50 +03:00
func (button *checkboxData) changedCheckboxState(state bool) {
2024-11-13 12:56:39 +03:00
for _, listener := range GetCheckboxChangedListeners(button) {
2021-09-07 17:36:50 +03:00
listener(button, state)
}
buffer := allocStringBuilder()
defer freeStringBuilder(buffer)
button.htmlCheckbox(buffer, state)
2022-10-30 17:22:33 +03:00
button.Session().updateInnerHTML(button.htmlID()+"checkbox", buffer.String())
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
*/
2021-09-07 17:36:50 +03:00
2024-11-13 12:56:39 +03:00
func checkboxClickListener(view View, _ MouseEvent) {
view.Set(Checked, !IsCheckboxChecked(view))
BlurView(view)
2021-09-07 17:36:50 +03:00
}
func checkboxKeyListener(view View, event KeyEvent) {
switch event.Code {
case "Enter", "Space":
view.Set(Checked, !IsCheckboxChecked(view))
2021-09-07 17:36:50 +03:00
}
}
func (button *checkboxData) cssStyle(self View, builder cssBuilder) {
session := button.Session()
vAlign := GetCheckboxVerticalAlign(button)
hAlign := GetCheckboxHorizontalAlign(button)
2021-09-07 17:36:50 +03:00
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))
2021-09-07 17:36:50 +03:00
}
builder.add("align-items", "stretch")
builder.add("justify-items", "stretch")
button.viewsContainerData.cssStyle(self, builder)
}
2024-11-13 12:56:39 +03:00
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)
2021-09-07 17:36:50 +03:00
buffer.WriteString(`<div id="`)
buffer.WriteString(button.htmlID())
buffer.WriteString(`checkbox" style="display: grid;`)
if hAlign == CenterAlign {
buffer.WriteString(" justify-items: center; grid-column-start: 1; grid-column-end: 2;")
if vAlign == BottomAlign {
buffer.WriteString(" grid-row-start: 2; grid-row-end: 3;")
} else {
buffer.WriteString(" grid-row-start: 1; grid-row-end: 2;")
}
} else {
if hAlign == RightAlign {
buffer.WriteString(" grid-column-start: 2; grid-column-end: 3;")
} else {
buffer.WriteString(" grid-column-start: 1; grid-column-end: 2;")
}
buffer.WriteString(" grid-row-start: 1; grid-row-end: 2;")
switch vAlign {
case BottomAlign:
buffer.WriteString(" align-items: end;")
case CenterAlign:
buffer.WriteString(" align-items: center;")
default:
buffer.WriteString(" align-items: start;")
}
}
buffer.WriteString(`">`)
accentColor := Color(0)
if color := GetAccentColor(button, ""); color != 0 {
accentColor = color
}
2021-09-07 17:36:50 +03:00
if checked {
buffer.WriteString(button.Session().checkboxOnImage(accentColor))
2021-09-07 17:36:50 +03:00
} else {
buffer.WriteString(button.Session().checkboxOffImage(accentColor))
2021-09-07 17:36:50 +03:00
}
buffer.WriteString(`</div>`)
return vAlign, hAlign
}
func (button *checkboxData) htmlSubviews(self View, buffer *strings.Builder) {
2024-11-13 12:56:39 +03:00
vCheckboxAlign, hCheckboxAlign := checkboxHtml(button, buffer, IsCheckboxChecked(button))
2021-09-07 17:36:50 +03:00
buffer.WriteString(`<div id="`)
buffer.WriteString(button.htmlID())
buffer.WriteString(`content" style="display: grid;`)
if hCheckboxAlign == LeftAlign {
buffer.WriteString(" grid-column-start: 2; grid-column-end: 3;")
} else {
buffer.WriteString(" grid-column-start: 1; grid-column-end: 2;")
}
if hCheckboxAlign == CenterAlign && vCheckboxAlign != BottomAlign {
buffer.WriteString(" grid-row-start: 2; grid-row-end: 3;")
} else {
buffer.WriteString(" grid-row-start: 1; grid-row-end: 2;")
}
buffer.WriteString(" align-items: ")
2024-11-13 12:56:39 +03:00
buffer.WriteString(checkboxVerticalAlignCSS(button))
2021-09-07 17:36:50 +03:00
buffer.WriteRune(';')
buffer.WriteString(" justify-items: ")
2024-11-13 12:56:39 +03:00
buffer.WriteString(checkboxHorizontalAlignCSS(button))
2021-09-07 17:36:50 +03:00
buffer.WriteRune(';')
buffer.WriteString(`">`)
button.viewsContainerData.htmlSubviews(self, buffer)
buffer.WriteString(`</div>`)
}
2024-11-13 12:56:39 +03:00
func checkboxHorizontalAlignCSS(view View) string {
align := GetHorizontalAlign(view)
2021-09-07 17:36:50 +03:00
values := enumProperties[CellHorizontalAlign].cssValues
if align >= 0 && align < len(values) {
return values[align]
}
return values[0]
}
2024-11-13 12:56:39 +03:00
func checkboxVerticalAlignCSS(view View) string {
align := GetVerticalAlign(view)
2021-09-07 17:36:50 +03:00
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)
2021-09-07 17:36:50 +03:00
}
2022-07-28 12:41:50 +03:00
// 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 {
2022-08-16 11:40:42 +03:00
return enumStyledProperty(view, subviewID, CheckboxVerticalAlign, LeftAlign, false)
2022-07-28 12:41:50 +03:00
}
// 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 {
2022-08-16 11:40:42 +03:00
return enumStyledProperty(view, subviewID, CheckboxHorizontalAlign, TopAlign, false)
2022-07-28 12:41:50 +03:00
}
// 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 getEventListeners[Checkbox, bool](view, subviewID, CheckboxChangedEvent)
}