OriginX, OriginY, and OriginZ properties renamed to TransformOriginX, TransformOriginY, and TransformOriginZ. GetOrigin function renamed to GetTransformOrigin

This commit is contained in:
Alexei Anoshenko 2024-11-18 16:20:25 +02:00
parent e2775d52f2
commit 0f2e7e55ea
45 changed files with 910 additions and 930 deletions

View File

@ -1,4 +1,7 @@
# v0.18.0
* OriginX, OriginY, and OriginZ properties renamed to TransformOriginX, TransformOriginY, and TransformOriginZ
* GetOrigin function renamed to GetTransformOrigin
* Added LineJoin type. Type of constants MiterJoin, RoundJoin, and BevelJoin changed to LineJoin. Type of Canvas.SetLineJoin function argument changed to LineJoin.
* Added LineCap type. Type of constants ButtCap, RoundCap, and SquareCap changed to LineCap. Type of Canvas.SetLineCap function argument changed to LineCap.

View File

@ -157,7 +157,7 @@ const (
/*
func setTransitionListener(properties Properties, tag PropertyName, value any) bool {
if listeners, ok := valueToEventListeners[View, string](value); ok {
if listeners, ok := valueToOneArgEventListeners[View, string](value); ok {
if len(listeners) == 0 {
properties.setRaw(tag, nil)
} else {
@ -206,7 +206,7 @@ func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject)
}
}
for _, listener := range getEventListeners[View, PropertyName](view, nil, tag) {
for _, listener := range getOneArgEventListeners[View, PropertyName](view, nil, tag) {
listener(view, property)
}
}
@ -214,7 +214,7 @@ func (view *viewData) handleTransitionEvents(tag PropertyName, data DataObject)
/*
func setAnimationListener(properties Properties, tag PropertyName, value any) bool {
if listeners, ok := valueToEventListeners[View, string](value); ok {
if listeners, ok := valueToOneArgEventListeners[View, string](value); ok {
if len(listeners) == 0 {
properties.setRaw(tag, nil)
} else {
@ -252,7 +252,7 @@ func animationEventsHtml(view View, buffer *strings.Builder) {
*/
func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) {
if listeners := getEventListeners[View, string](view, nil, tag); len(listeners) > 0 {
if listeners := getOneArgEventListeners[View, string](view, nil, tag); len(listeners) > 0 {
id := ""
if name, ok := data.PropertyValue("name"); ok {
for _, animation := range GetAnimation(view) {
@ -271,54 +271,54 @@ func (view *viewData) handleAnimationEvents(tag PropertyName, data DataObject) {
// 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 GetTransitionRunListeners(view View, subviewID ...string) []func(View, string) {
return getEventListeners[View, string](view, subviewID, TransitionRunEvent)
return getOneArgEventListeners[View, string](view, subviewID, TransitionRunEvent)
}
// GetTransitionStartListeners returns the "transition-start-event" listener list.
// 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 GetTransitionStartListeners(view View, subviewID ...string) []func(View, string) {
return getEventListeners[View, string](view, subviewID, TransitionStartEvent)
return getOneArgEventListeners[View, string](view, subviewID, TransitionStartEvent)
}
// GetTransitionEndListeners returns the "transition-end-event" listener list.
// 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 GetTransitionEndListeners(view View, subviewID ...string) []func(View, string) {
return getEventListeners[View, string](view, subviewID, TransitionEndEvent)
return getOneArgEventListeners[View, string](view, subviewID, TransitionEndEvent)
}
// GetTransitionCancelListeners returns the "transition-cancel-event" listener list.
// 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 GetTransitionCancelListeners(view View, subviewID ...string) []func(View, string) {
return getEventListeners[View, string](view, subviewID, TransitionCancelEvent)
return getOneArgEventListeners[View, string](view, subviewID, TransitionCancelEvent)
}
// GetAnimationStartListeners returns the "animation-start-event" listener list.
// 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 GetAnimationStartListeners(view View, subviewID ...string) []func(View, string) {
return getEventListeners[View, string](view, subviewID, AnimationStartEvent)
return getOneArgEventListeners[View, string](view, subviewID, AnimationStartEvent)
}
// GetAnimationEndListeners returns the "animation-end-event" listener list.
// 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 GetAnimationEndListeners(view View, subviewID ...string) []func(View, string) {
return getEventListeners[View, string](view, subviewID, AnimationEndEvent)
return getOneArgEventListeners[View, string](view, subviewID, AnimationEndEvent)
}
// GetAnimationCancelListeners returns the "animation-cancel-event" listener list.
// 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 GetAnimationCancelListeners(view View, subviewID ...string) []func(View, string) {
return getEventListeners[View, string](view, subviewID, AnimationCancelEvent)
return getOneArgEventListeners[View, string](view, subviewID, AnimationCancelEvent)
}
// GetAnimationIterationListeners returns the "animation-iteration-event" listener list.
// 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 GetAnimationIterationListeners(view View, subviewID ...string) []func(View, string) {
return getEventListeners[View, string](view, subviewID, AnimationIterationEvent)
return getOneArgEventListeners[View, string](view, subviewID, AnimationIterationEvent)
}

View File

@ -623,21 +623,10 @@ function listItemClickEvent(element, event) {
return
}
let selected = false;
if (element.classList) {
const focusStyle = getListFocusedItemStyle(element);
const blurStyle = getListSelectedItemStyle(element);
selected = (element.classList.contains(focusStyle) || element.classList.contains(blurStyle));
}
const list = element.parentNode.parentNode
if (list) {
if (!selected) {
selectListItem(list, element, true)
}
const message = "itemClick{session=" + sessionID + ",id=" + list.id + "}"
sendMessage(message);
const number = getListItemNumber(element.id)
sendMessage("itemClick{session=" + sessionID + ",id=" + list.id + ",number=" + number + "}");
}
}
@ -664,7 +653,7 @@ function getListSelectedItemStyle(element) {
return getStyleAttribute(element, "data-bluritemstyle", "ruiListItemSelected");
}
function selectListItem(element, item, needSendMessage) {
function selectListItem(element, item) {
const currentId = element.getAttribute("data-current");
let message;
const focusStyle = getListFocusedItemStyle(element);
@ -676,9 +665,7 @@ function selectListItem(element, item, needSendMessage) {
if (current.classList) {
current.classList.remove(focusStyle, blurStyle);
}
if (sendMessage) {
message = "itemUnselected{session=" + sessionID + ",id=" + element.id + "}";
}
message = "itemUnselected{session=" + sessionID + ",id=" + element.id + "}";
}
}
@ -693,42 +680,21 @@ function selectListItem(element, item, needSendMessage) {
}
}
element.setAttribute("data-current", item.id);
if (sendMessage) {
const number = getListItemNumber(item.id)
if (number != undefined) {
message = "itemSelected{session=" + sessionID + ",id=" + element.id + ",number=" + number + "}";
}
element.setAttribute("data-current", item.id);
const number = getListItemNumber(item.id)
if (number != undefined) {
message = "itemSelected{session=" + sessionID + ",id=" + element.id + ",number=" + number + "}";
}
if (item.scrollIntoViewIfNeeded) {
item.scrollIntoViewIfNeeded()
} else {
item.scrollIntoView({block: "nearest", inline: "nearest"});
}
/*
let left = item.offsetLeft - element.offsetLeft;
if (left < element.scrollLeft) {
element.scrollLeft = left;
}
let top = item.offsetTop - element.offsetTop;
if (top < element.scrollTop) {
element.scrollTop = top;
}
let right = left + item.offsetWidth;
if (right > element.scrollLeft + element.clientWidth) {
element.scrollLeft = right - element.clientWidth;
}
let bottom = top + item.offsetHeight
if (bottom > element.scrollTop + element.clientHeight) {
element.scrollTop = bottom - element.clientHeight;
}*/
}
if (needSendMessage && message != undefined) {
if (message != undefined) {
sendMessage(message);
}
scanElementsSize();
@ -857,7 +823,7 @@ function listViewKeyDownEvent(element, event) {
switch (key) {
case " ":
case "Enter":
const message = "itemClick{session=" + sessionID + ",id=" + element.id + "}";
const message = "itemClick{session=" + sessionID + ",id=" + element.id + ",number=" + getListItemNumber(currentId) + "}";
sendMessage(message);
break;
@ -897,7 +863,7 @@ function listViewKeyDownEvent(element, event) {
return;
}
if (item && item !== current) {
selectListItem(element, item, true);
selectListItem(element, item);
}
} else {
switch (key) {
@ -916,7 +882,7 @@ function listViewKeyDownEvent(element, event) {
if (item.getAttribute("data-disabled") == "1") {
continue;
}
selectListItem(element, item, true);
selectListItem(element, item);
return;
}
break;

View File

@ -37,8 +37,8 @@ func (canvasView *canvasViewData) init(session Session) {
canvasView.viewData.init(session)
canvasView.tag = "CanvasView"
canvasView.normalize = normalizeCanvasViewTag
canvasView.set = canvasViewSet
canvasView.remove = canvasViewRemove
canvasView.set = canvasView.setFunc
canvasView.remove = canvasView.removeFunc
}
@ -51,36 +51,32 @@ func normalizeCanvasViewTag(tag PropertyName) PropertyName {
return tag
}
func canvasViewRemove(view View, tag PropertyName) []PropertyName {
func (canvasView *canvasViewData) removeFunc(tag PropertyName) []PropertyName {
if tag == DrawFunction {
if view.getRaw(DrawFunction) != nil {
view.setRaw(DrawFunction, nil)
if canvasView, ok := view.(CanvasView); ok {
canvasView.Redraw()
}
if canvasView.getRaw(DrawFunction) != nil {
canvasView.setRaw(DrawFunction, nil)
canvasView.Redraw()
return []PropertyName{DrawFunction}
}
return []PropertyName{}
}
return viewRemove(view, tag)
return canvasView.viewData.removeFunc(tag)
}
func canvasViewSet(view View, tag PropertyName, value any) []PropertyName {
func (canvasView *canvasViewData) setFunc(tag PropertyName, value any) []PropertyName {
if tag == DrawFunction {
if fn, ok := value.(func(Canvas)); ok {
view.setRaw(DrawFunction, fn)
canvasView.setRaw(DrawFunction, fn)
} else {
notCompatibleType(tag, value)
return nil
}
if canvasView, ok := view.(CanvasView); ok {
canvasView.Redraw()
}
canvasView.Redraw()
return []PropertyName{DrawFunction}
}
return viewSet(view, tag, value)
return canvasView.viewData.setFunc(tag, value)
}
func (canvasView *canvasViewData) htmlTag() string {

View File

@ -49,117 +49,98 @@ func (button *checkboxData) init(session Session) {
button.systemClass = "ruiGridLayout ruiCheckbox"
button.set = button.setFunc
button.remove = button.removeFunc
button.changed = checkboxPropertyChanged
button.changed = button.propertyChanged
button.setRaw(ClickEvent, checkboxClickListener)
button.setRaw(KeyDownEvent, checkboxKeyListener)
button.setRaw(ClickEvent, []func(View, MouseEvent){checkboxClickListener})
button.setRaw(KeyDownEvent, []func(View, KeyEvent){checkboxKeyListener})
}
func (button *checkboxData) Focusable() bool {
return true
}
func checkboxPropertyChanged(view View, tag PropertyName) {
func (button *checkboxData) propertyChanged(tag PropertyName) {
switch tag {
case Checked:
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)
}
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(view, buffer, checked)
session.updateInnerHTML(view.htmlID()+"checkbox", buffer.String())
checkboxHtml(button, buffer, checked)
session.updateInnerHTML(button.htmlID()+"checkbox", buffer.String())
case CheckboxHorizontalAlign, CheckboxVerticalAlign:
htmlID := view.htmlID()
session := view.Session()
htmlID := button.htmlID()
session := button.Session()
updateCSSStyle(htmlID, session)
updateInnerHTML(htmlID, session)
case VerticalAlign:
view.Session().updateCSSProperty(view.htmlID()+"content", "align-items", checkboxVerticalAlignCSS(view))
button.Session().updateCSSProperty(button.htmlID()+"content", "align-items", checkboxVerticalAlignCSS(button))
case HorizontalAlign:
view.Session().updateCSSProperty(view.htmlID()+"content", "justify-items", checkboxHorizontalAlignCSS(view))
button.Session().updateCSSProperty(button.htmlID()+"content", "justify-items", checkboxHorizontalAlignCSS(button))
case AccentColor:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(button.htmlID(), button.Session())
default:
viewsContainerPropertyChanged(view, tag)
button.viewsContainerData.propertyChanged(tag)
}
}
func (button *checkboxData) setFunc(view View, tag PropertyName, value any) []PropertyName {
func (button *checkboxData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case ClickEvent:
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)
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 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)
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 setViewEventListener[Checkbox, bool](view, tag, value)
return setOneArgEventListener[Checkbox, bool](button, tag, value)
case Checked:
return setBoolProperty(view, Checked, value)
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(view, tag, value)
return button.viewsContainerData.setFunc(tag, value)
}
func (button *checkboxData) removeFunc(view View, tag PropertyName) []PropertyName {
func (button *checkboxData) removeFunc(tag PropertyName) []PropertyName {
switch tag {
case ClickEvent:
button.setRaw(ClickEvent, checkboxClickListener)
button.setRaw(ClickEvent, []func(View, MouseEvent){checkboxClickListener})
return []PropertyName{ClickEvent}
case KeyDownEvent:
button.setRaw(KeyDownEvent, checkboxKeyListener)
button.setRaw(KeyDownEvent, []func(View, KeyEvent){checkboxKeyListener})
return []PropertyName{ClickEvent}
}
return button.viewsContainerData.removeFunc(view, tag)
}
func (button *checkboxData) checked() bool {
checked, _ := boolProperty(button, Checked, button.Session())
return checked
return button.viewsContainerData.removeFunc(tag)
}
/*
@ -340,5 +321,5 @@ func GetCheckboxHorizontalAlign(view View, subviewID ...string) int {
// 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)
return getOneArgEventListeners[Checkbox, bool](view, subviewID, CheckboxChangedEvent)
}

View File

@ -66,8 +66,8 @@ func (picker *colorPickerData) init(session Session) {
picker.hasHtmlDisabled = true
picker.properties[Padding] = Px(0)
picker.normalize = normalizeColorPickerTag
picker.set = colorPickerSet
picker.changed = colorPickerPropertyChanged
picker.set = picker.setFunc
picker.changed = picker.propertyChanged
}
func normalizeColorPickerTag(tag PropertyName) PropertyName {
@ -80,44 +80,44 @@ func normalizeColorPickerTag(tag PropertyName) PropertyName {
return normalizeDataListTag(tag)
}
func colorPickerSet(view View, tag PropertyName, value any) []PropertyName {
func (picker *colorPickerData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case ColorChangedEvent:
return setEventWithOldListener[ColorPicker, Color](view, tag, value)
return setTwoArgEventListener[ColorPicker, Color](picker, tag, value)
case ColorPickerValue:
oldColor := GetColorPickerValue(view)
result := setColorProperty(view, ColorPickerValue, value)
oldColor := GetColorPickerValue(picker)
result := setColorProperty(picker, ColorPickerValue, value)
if result != nil {
view.setRaw("old-color", oldColor)
picker.setRaw("old-color", oldColor)
}
return result
case DataList:
return setDataList(view, value, "")
return setDataList(picker, value, "")
}
return viewSet(view, tag, value)
return picker.viewData.setFunc(tag, value)
}
func colorPickerPropertyChanged(view View, tag PropertyName) {
func (picker *colorPickerData) propertyChanged(tag PropertyName) {
switch tag {
case ColorPickerValue:
color := GetColorPickerValue(view)
view.Session().callFunc("setInputValue", view.htmlID(), color.rgbString())
color := GetColorPickerValue(picker)
picker.Session().callFunc("setInputValue", picker.htmlID(), color.rgbString())
if listeners := GetColorChangedListeners(view); len(listeners) > 0 {
if listeners := GetColorChangedListeners(picker); len(listeners) > 0 {
oldColor := Color(0)
if value := view.getRaw("old-color"); value != nil {
if value := picker.getRaw("old-color"); value != nil {
oldColor = value.(Color)
}
for _, listener := range listeners {
listener(view, color, oldColor)
listener(picker, color, oldColor)
}
}
default:
viewPropertyChanged(view, tag)
picker.viewData.propertyChanged(tag)
}
}
@ -196,5 +196,5 @@ func GetColorPickerValue(view View, subviewID ...string) Color {
// 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 GetColorChangedListeners(view View, subviewID ...string) []func(ColorPicker, Color, Color) {
return getEventWithOldListeners[ColorPicker, Color](view, subviewID, ColorChangedEvent)
return getTwoArgEventListeners[ColorPicker, Color](view, subviewID, ColorChangedEvent)
}

View File

@ -141,7 +141,7 @@ func (columnLayout *columnLayoutData) init(session Session) {
columnLayout.viewsContainerData.init(session)
columnLayout.tag = "ColumnLayout"
columnLayout.normalize = normalizeColumnLayoutTag
columnLayout.changed = columnLayoutPropertyChanged
columnLayout.changed = columnLayout.propertyChanged
//columnLayout.systemClass = "ruiColumnLayout"
}
@ -154,27 +154,27 @@ func normalizeColumnLayoutTag(tag PropertyName) PropertyName {
return tag
}
func columnLayoutPropertyChanged(view View, tag PropertyName) {
func (columnLayout *columnLayoutData) propertyChanged(tag PropertyName) {
switch tag {
case ColumnSeparator:
css := ""
session := view.Session()
if value := view.getRaw(ColumnSeparator); value != nil {
session := columnLayout.Session()
if value := columnLayout.getRaw(ColumnSeparator); value != nil {
separator := value.(ColumnSeparatorProperty)
css = separator.cssValue(view.Session())
css = separator.cssValue(session)
}
session.updateCSSProperty(view.htmlID(), "column-rule", css)
session.updateCSSProperty(columnLayout.htmlID(), "column-rule", css)
case ColumnCount:
session := view.Session()
if count, ok := intProperty(view, tag, session, 0); ok && count > 0 {
session.updateCSSProperty(view.htmlID(), string(ColumnCount), strconv.Itoa(count))
session := columnLayout.Session()
if count := GetColumnCount(columnLayout); count > 0 {
session.updateCSSProperty(columnLayout.htmlID(), string(ColumnCount), strconv.Itoa(count))
} else {
session.updateCSSProperty(view.htmlID(), string(ColumnCount), "auto")
session.updateCSSProperty(columnLayout.htmlID(), string(ColumnCount), "auto")
}
default:
viewsContainerPropertyChanged(view, tag)
columnLayout.viewsContainerData.propertyChanged(tag)
}
}

View File

@ -82,6 +82,7 @@ func NewColumnSeparator(params Params) ColumnSeparatorProperty {
func (separator *columnSeparatorProperty) init() {
separator.dataProperty.init()
separator.normalize = normalizeVolumnSeparatorTag
separator.set = columnSeparatorSet
separator.supportedProperties = []PropertyName{Style, Width, ColorTag}
}
@ -171,3 +172,10 @@ func (separator *columnSeparatorProperty) cssValue(session Session) string {
return buffer.String()
}
func columnSeparatorSet(properties Properties, tag PropertyName, value any) []PropertyName {
if tag == Style {
return setEnumProperty(properties, Style, value, enumProperties[BorderStyle].values)
}
return propertiesSet(properties, tag, value)
}

View File

@ -120,7 +120,7 @@ func normalizeDataListTag(tag PropertyName) PropertyName {
}
func setDataList(properties Properties, value any, dateTimeFormat string) []PropertyName {
if items, ok := anyToStringArray(value, timeFormat); ok {
if items, ok := anyToStringArray(value, dateTimeFormat); ok {
properties.setRaw(DataList, items)
return []PropertyName{DataList}
}

View File

@ -138,8 +138,8 @@ func (picker *datePickerData) init(session Session) {
picker.tag = "DatePicker"
picker.hasHtmlDisabled = true
picker.normalize = normalizeDatePickerTag
picker.set = datePickerSet
picker.changed = datePickerPropertyChanged
picker.set = picker.setFunc
picker.changed = picker.propertyChanged
}
func (picker *datePickerData) Focusable() bool {
@ -198,22 +198,22 @@ func stringToDate(value string) (time.Time, bool) {
return time.Now(), false
}
func datePickerSet(view View, tag PropertyName, value any) []PropertyName {
func (picker *datePickerData) setFunc(tag PropertyName, value any) []PropertyName {
setDateValue := func(tag PropertyName) []PropertyName {
switch value := value.(type) {
case time.Time:
view.setRaw(tag, value)
picker.setRaw(tag, value)
return []PropertyName{tag}
case string:
if isConstantName(value) {
view.setRaw(tag, value)
picker.setRaw(tag, value)
return []PropertyName{tag}
}
if date, ok := stringToDate(value); ok {
view.setRaw(tag, date)
picker.setRaw(tag, date)
return []PropertyName{tag}
}
}
@ -227,67 +227,67 @@ func datePickerSet(view View, tag PropertyName, value any) []PropertyName {
return setDateValue(tag)
case DatePickerStep:
return setIntProperty(view, DatePickerStep, value)
return setIntProperty(picker, DatePickerStep, value)
case DatePickerValue:
view.setRaw("old-date", GetDatePickerValue(view))
picker.setRaw("old-date", GetDatePickerValue(picker))
return setDateValue(tag)
case DateChangedEvent:
return setEventWithOldListener[DatePicker, time.Time](view, tag, value)
return setTwoArgEventListener[DatePicker, time.Time](picker, tag, value)
case DataList:
return setDataList(view, value, dateFormat)
return setDataList(picker, value, dateFormat)
}
return viewSet(view, tag, value)
return picker.viewData.setFunc(tag, value)
}
func datePickerPropertyChanged(view View, tag PropertyName) {
func (picker *datePickerData) propertyChanged(tag PropertyName) {
session := view.Session()
session := picker.Session()
switch tag {
case DatePickerMin:
if date, ok := GetDatePickerMin(view); ok {
session.updateProperty(view.htmlID(), "min", date.Format(dateFormat))
if date, ok := GetDatePickerMin(picker); ok {
session.updateProperty(picker.htmlID(), "min", date.Format(dateFormat))
} else {
session.removeProperty(view.htmlID(), "min")
session.removeProperty(picker.htmlID(), "min")
}
case DatePickerMax:
if date, ok := GetDatePickerMax(view); ok {
session.updateProperty(view.htmlID(), "max", date.Format(dateFormat))
if date, ok := GetDatePickerMax(picker); ok {
session.updateProperty(picker.htmlID(), "max", date.Format(dateFormat))
} else {
session.removeProperty(view.htmlID(), "max")
session.removeProperty(picker.htmlID(), "max")
}
case DatePickerStep:
if step := GetDatePickerStep(view); step > 0 {
session.updateProperty(view.htmlID(), "step", strconv.Itoa(step))
if step := GetDatePickerStep(picker); step > 0 {
session.updateProperty(picker.htmlID(), "step", strconv.Itoa(step))
} else {
session.removeProperty(view.htmlID(), "step")
session.removeProperty(picker.htmlID(), "step")
}
case DatePickerValue:
date := GetDatePickerValue(view)
session.callFunc("setInputValue", view.htmlID(), date.Format(dateFormat))
date := GetDatePickerValue(picker)
session.callFunc("setInputValue", picker.htmlID(), date.Format(dateFormat))
if listeners := GetDateChangedListeners(view); len(listeners) > 0 {
if listeners := GetDateChangedListeners(picker); len(listeners) > 0 {
oldDate := time.Now()
if value := view.getRaw("old-date"); value != nil {
if value := picker.getRaw("old-date"); value != nil {
if date, ok := value.(time.Time); ok {
oldDate = date
}
}
for _, listener := range listeners {
listener(view, date, oldDate)
listener(picker, date, oldDate)
}
}
default:
viewPropertyChanged(view, tag)
picker.viewData.propertyChanged(tag)
}
}
@ -447,5 +447,5 @@ func GetDatePickerValue(view View, subviewID ...string) time.Time {
// 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 GetDateChangedListeners(view View, subviewID ...string) []func(DatePicker, time.Time, time.Time) {
return getEventWithOldListeners[DatePicker, time.Time](view, subviewID, DateChangedEvent)
return getTwoArgEventListeners[DatePicker, time.Time](view, subviewID, DateChangedEvent)
}

View File

@ -54,7 +54,7 @@ func (detailsView *detailsViewData) init(session Session) {
detailsView.viewsContainerData.init(session)
detailsView.tag = "DetailsView"
detailsView.set = detailsView.setFunc
detailsView.changed = detailsViewPropertyChanged
detailsView.changed = detailsView.propertyChanged
//detailsView.systemClass = "ruiDetailsView"
}
@ -69,7 +69,7 @@ func (detailsView *detailsViewData) Views() []View {
return views
}
func (detailsView *detailsViewData) setFunc(self View, tag PropertyName, value any) []PropertyName {
func (detailsView *detailsViewData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Summary:
switch value := value.(type) {
@ -95,26 +95,26 @@ func (detailsView *detailsViewData) setFunc(self View, tag PropertyName, value a
return []PropertyName{tag}
}
return detailsView.viewsContainerData.setFunc(detailsView, tag, value)
return detailsView.viewsContainerData.setFunc(tag, value)
}
func detailsViewPropertyChanged(view View, tag PropertyName) {
func (detailsView *detailsViewData) propertyChanged(tag PropertyName) {
switch tag {
case Summary:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(detailsView.htmlID(), detailsView.Session())
case Expanded:
if IsDetailsExpanded(view) {
view.Session().updateProperty(view.htmlID(), "open", "")
if IsDetailsExpanded(detailsView) {
detailsView.Session().updateProperty(detailsView.htmlID(), "open", "")
} else {
view.Session().removeProperty(view.htmlID(), "open")
detailsView.Session().removeProperty(detailsView.htmlID(), "open")
}
case NotTranslate:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(detailsView.htmlID(), detailsView.Session())
default:
viewsContainerPropertyChanged(view, tag)
detailsView.viewsContainerData.propertyChanged(tag)
}
}
@ -155,8 +155,8 @@ func (detailsView *detailsViewData) handleCommand(self View, command PropertyNam
if command == "details-open" {
if n, ok := dataIntProperty(data, "open"); ok {
detailsView.properties[Expanded] = (n != 0)
if listener, ok := detailsView.changeListener[Current]; ok {
listener(detailsView, Current)
if listener, ok := detailsView.changeListener[Expanded]; ok {
listener(detailsView, Expanded)
}
}
return true

View File

@ -46,8 +46,8 @@ func (list *dropDownListData) init(session Session) {
list.tag = "DropDownList"
list.hasHtmlDisabled = true
list.normalize = normalizeDropDownListTag
list.set = dropDownListSet
list.changed = dropDownListPropertyChanged
list.set = list.setFunc
list.changed = list.propertyChanged
}
func (list *dropDownListData) Focusable() bool {
@ -62,59 +62,49 @@ func normalizeDropDownListTag(tag PropertyName) PropertyName {
return tag
}
func dropDownListSet(view View, tag PropertyName, value any) []PropertyName {
func (list *dropDownListData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Items:
if items, ok := anyToStringArray(value, ""); ok {
return setArrayPropertyValue(view, tag, items)
return setArrayPropertyValue(list, tag, items)
}
notCompatibleType(Items, value)
return nil
case DisabledItems, ItemSeparators:
if items, ok := parseIndicesArray(value); ok {
return setArrayPropertyValue(view, tag, items)
return setArrayPropertyValue(list, tag, items)
}
notCompatibleType(tag, value)
return nil
case DropDownEvent:
return setEventWithOldListener[DropDownList, int](view, tag, value)
return setTwoArgEventListener[DropDownList, int](list, tag, value)
case Current:
if view, ok := view.(View); ok {
view.setRaw("old-current", GetCurrent(view))
}
return setIntProperty(view, Current, value)
list.setRaw("old-current", GetCurrent(list))
return setIntProperty(list, Current, value)
}
return viewSet(view, tag, value)
return list.viewData.setFunc(tag, value)
}
func dropDownListPropertyChanged(view View, tag PropertyName) {
func (list *dropDownListData) propertyChanged(tag PropertyName) {
switch tag {
case Items, DisabledItems, ItemSeparators:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(list.htmlID(), list.Session())
case Current:
current := GetCurrent(view)
view.Session().callFunc("selectDropDownListItem", view.htmlID(), current)
current := GetCurrent(list)
list.Session().callFunc("selectDropDownListItem", list.htmlID(), current)
if list, ok := view.(DropDownList); ok {
oldCurrent := -1
if value := view.getRaw("old-current"); value != nil {
if n, ok := value.(int); ok {
oldCurrent = n
}
}
for _, listener := range GetDropDownListeners(view) {
listener(list, current, oldCurrent)
}
oldCurrent, _ := intProperty(list, "old-current", list.Session(), -1)
for _, listener := range GetDropDownListeners(list) {
listener(list, current, oldCurrent)
}
default:
viewPropertyChanged(view, tag)
list.viewData.propertyChanged(tag)
}
}
@ -253,6 +243,9 @@ func (list *dropDownListData) handleCommand(self View, command PropertyName, dat
for _, listener := range GetDropDownListeners(list) {
listener(list, number, old)
}
if listener, ok := list.changeListener[Current]; ok {
listener(list, Current)
}
}
} else {
ErrorLog(err.Error())
@ -268,7 +261,7 @@ func (list *dropDownListData) handleCommand(self View, command PropertyName, dat
// GetDropDownListeners returns the "drop-down-event" listener list. 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 GetDropDownListeners(view View, subviewID ...string) []func(DropDownList, int, int) {
return getEventWithOldListeners[DropDownList, int](view, subviewID, DropDownEvent)
return getTwoArgEventListeners[DropDownList, int](view, subviewID, DropDownEvent)
}
// GetDropDownItems return the DropDownList items list.

View File

@ -121,8 +121,8 @@ func (edit *editViewData) init(session Session) {
edit.hasHtmlDisabled = true
edit.tag = "EditView"
edit.normalize = normalizeEditViewTag
edit.set = editViewSet
edit.changed = editViewPropertyChanged
edit.set = edit.setFunc
edit.changed = edit.propertyChanged
}
func (edit *editViewData) Focusable() bool {
@ -148,18 +148,18 @@ func normalizeEditViewTag(tag PropertyName) PropertyName {
return normalizeDataListTag(tag)
}
func editViewSet(view View, tag PropertyName, value any) []PropertyName {
func (edit *editViewData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Text:
if text, ok := value.(string); ok {
old := ""
if val := view.getRaw(Text); val != nil {
if val := edit.getRaw(Text); val != nil {
if txt, ok := val.(string); ok {
old = txt
}
}
view.setRaw("old-text", old)
view.setRaw(tag, text)
edit.setRaw("old-text", old)
edit.setRaw(tag, text)
return []PropertyName{tag}
}
@ -168,85 +168,83 @@ func editViewSet(view View, tag PropertyName, value any) []PropertyName {
case Hint:
if text, ok := value.(string); ok {
return setStringPropertyValue(view, tag, strings.Trim(text, " \t\n"))
return setStringPropertyValue(edit, tag, strings.Trim(text, " \t\n"))
}
notCompatibleType(tag, value)
return nil
case DataList:
setDataList(view, value, "")
setDataList(edit, value, "")
case EditTextChangedEvent:
return setEventWithOldListener[EditView, string](view, tag, value)
return setTwoArgEventListener[EditView, string](edit, tag, value)
}
return viewSet(view, tag, value)
return edit.viewData.setFunc(tag, value)
}
func editViewPropertyChanged(view View, tag PropertyName) {
session := view.Session()
func (edit *editViewData) propertyChanged(tag PropertyName) {
session := edit.Session()
switch tag {
case Text:
text := GetText(view)
session.callFunc("setInputValue", view.htmlID(), text)
text := GetText(edit)
session.callFunc("setInputValue", edit.htmlID(), text)
if edit, ok := view.(EditView); ok {
old := ""
if val := view.getRaw("old-text"); val != nil {
if txt, ok := val.(string); ok {
old = txt
}
old := ""
if val := edit.getRaw("old-text"); val != nil {
if txt, ok := val.(string); ok {
old = txt
}
edit.textChanged(text, old)
}
edit.textChanged(text, old)
case Hint:
if text := GetHint(view); text != "" {
session.updateProperty(view.htmlID(), "placeholder", text)
if text := GetHint(edit); text != "" {
session.updateProperty(edit.htmlID(), "placeholder", text)
} else {
session.removeProperty(view.htmlID(), "placeholder")
session.removeProperty(edit.htmlID(), "placeholder")
}
case MaxLength:
if maxLength := GetMaxLength(view); maxLength > 0 {
session.updateProperty(view.htmlID(), "maxlength", strconv.Itoa(maxLength))
if maxLength := GetMaxLength(edit); maxLength > 0 {
session.updateProperty(edit.htmlID(), "maxlength", strconv.Itoa(maxLength))
} else {
session.removeProperty(view.htmlID(), "maxlength")
session.removeProperty(edit.htmlID(), "maxlength")
}
case ReadOnly:
if IsReadOnly(view) {
session.updateProperty(view.htmlID(), "readonly", "")
if IsReadOnly(edit) {
session.updateProperty(edit.htmlID(), "readonly", "")
} else {
session.removeProperty(view.htmlID(), "readonly")
session.removeProperty(edit.htmlID(), "readonly")
}
case Spellcheck:
session.updateProperty(view.htmlID(), "spellcheck", IsSpellcheck(view))
session.updateProperty(edit.htmlID(), "spellcheck", IsSpellcheck(edit))
case EditViewPattern:
if text := GetEditViewPattern(view); text != "" {
session.updateProperty(view.htmlID(), "pattern", text)
if text := GetEditViewPattern(edit); text != "" {
session.updateProperty(edit.htmlID(), "pattern", text)
} else {
session.removeProperty(view.htmlID(), "pattern")
session.removeProperty(edit.htmlID(), "pattern")
}
case EditViewType:
updateInnerHTML(view.parentHTMLID(), session)
updateInnerHTML(edit.parentHTMLID(), session)
case EditWrap:
if wrap := IsEditViewWrap(view); wrap {
session.updateProperty(view.htmlID(), "wrap", "soft")
if wrap := IsEditViewWrap(edit); wrap {
session.updateProperty(edit.htmlID(), "wrap", "soft")
} else {
session.updateProperty(view.htmlID(), "wrap", "off")
session.updateProperty(edit.htmlID(), "wrap", "off")
}
case DataList:
updateInnerHTML(view.htmlID(), session)
updateInnerHTML(edit.htmlID(), session)
default:
viewPropertyChanged(view, tag)
edit.viewData.propertyChanged(tag)
}
}
@ -467,7 +465,7 @@ func IsSpellcheck(view View, subviewID ...string) bool {
// 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 GetTextChangedListeners(view View, subviewID ...string) []func(EditView, string, string) {
return getEventWithOldListeners[EditView, string](view, subviewID, EditTextChangedEvent)
return getTwoArgEventListeners[EditView, string](view, subviewID, EditTextChangedEvent)
}
// GetEditViewType returns a value of the Type property of EditView.

View File

@ -35,7 +35,7 @@ var eventJsFunc = map[PropertyName]struct{ jsEvent, jsFunc string }{
AnimationCancelEvent: {jsEvent: "onanimationcancel", jsFunc: "animationCancelEvent"},
}
func valueToNoParamListeners[V any](value any) ([]func(V), bool) {
func valueToNoArgEventListeners[V any](value any) ([]func(V), bool) {
if value == nil {
return nil, true
}
@ -106,7 +106,7 @@ func valueToNoParamListeners[V any](value any) ([]func(V), bool) {
return nil, false
}
func valueToEventListeners[V View, E any](value any) ([]func(V, E), bool) {
func valueToOneArgEventListeners[V View, E any](value any) ([]func(V, E), bool) {
if value == nil {
return nil, true
}
@ -231,7 +231,7 @@ func valueToEventListeners[V View, E any](value any) ([]func(V, E), bool) {
return nil, false
}
func valueToEventWithOldListeners[V View, E any](value any) ([]func(V, E, E), bool) {
func valueToTwoArgEventListeners[V View, E any](value any) ([]func(V, E, E), bool) {
if value == nil {
return nil, true
}
@ -410,7 +410,7 @@ func valueToEventWithOldListeners[V View, E any](value any) ([]func(V, E, E), bo
return nil, false
}
func getNoParamEventListeners[V View](view View, subviewID []string, tag PropertyName) []func(V) {
func getNoArgEventListeners[V View](view View, subviewID []string, tag PropertyName) []func(V) {
if len(subviewID) > 0 && subviewID[0] != "" {
view = ViewByID(view, subviewID[0])
}
@ -424,7 +424,7 @@ func getNoParamEventListeners[V View](view View, subviewID []string, tag Propert
return []func(V){}
}
func getEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E) {
func getOneArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E) {
if len(subviewID) > 0 && subviewID[0] != "" {
view = ViewByID(view, subviewID[0])
}
@ -438,7 +438,7 @@ func getEventListeners[V View, E any](view View, subviewID []string, tag Propert
return []func(V, E){}
}
func getEventWithOldListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E, E) {
func getTwoArgEventListeners[V View, E any](view View, subviewID []string, tag PropertyName) []func(V, E, E) {
if len(subviewID) > 0 && subviewID[0] != "" {
view = ViewByID(view, subviewID[0])
}
@ -452,8 +452,8 @@ func getEventWithOldListeners[V View, E any](view View, subviewID []string, tag
return []func(V, E, E){}
}
func setNoParamEventListener[V View](properties Properties, tag PropertyName, value any) []PropertyName {
if listeners, ok := valueToNoParamListeners[V](value); ok {
func setNoArgEventListener[V View](properties Properties, tag PropertyName, value any) []PropertyName {
if listeners, ok := valueToNoArgEventListeners[V](value); ok {
if len(listeners) > 0 {
properties.setRaw(tag, listeners)
} else if properties.getRaw(tag) != nil {
@ -467,8 +467,8 @@ func setNoParamEventListener[V View](properties Properties, tag PropertyName, va
return nil
}
func setViewEventListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName {
if listeners, ok := valueToEventListeners[V, T](value); ok {
func setOneArgEventListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName {
if listeners, ok := valueToOneArgEventListeners[V, T](value); ok {
if len(listeners) > 0 {
properties.setRaw(tag, listeners)
} else if properties.getRaw(tag) != nil {
@ -482,8 +482,8 @@ func setViewEventListener[V View, T any](properties Properties, tag PropertyName
return nil
}
func setEventWithOldListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName {
listeners, ok := valueToEventWithOldListeners[V, T](value)
func setTwoArgEventListener[V View, T any](properties Properties, tag PropertyName, value any) []PropertyName {
listeners, ok := valueToTwoArgEventListeners[V, T](value)
if !ok {
notCompatibleType(tag, value)
return nil
@ -498,7 +498,7 @@ func setEventWithOldListener[V View, T any](properties Properties, tag PropertyN
}
func viewEventsHtml[T any](view View, events []PropertyName, buffer *strings.Builder) {
for _, tag := range []PropertyName{AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent} {
for _, tag := range events {
if value := view.getRaw(tag); value != nil {
if js, ok := eventJsFunc[tag]; ok {
if listeners, ok := value.([]func(View, T)); ok && len(listeners) > 0 {

View File

@ -123,8 +123,8 @@ func (picker *filePickerData) init(session Session) {
picker.hasHtmlDisabled = true
picker.files = []FileInfo{}
picker.loader = map[int]func(FileInfo, []byte){}
picker.set = filePickerSet
picker.changed = filePickerPropertyChanged
picker.set = picker.setFunc
picker.changed = picker.propertyChanged
}
@ -150,27 +150,16 @@ func (picker *filePickerData) LoadFile(file FileInfo, result func(FileInfo, []by
}
}
func filePickerSet(view View, tag PropertyName, value any) []PropertyName {
setAccept := func(value string) []PropertyName {
if value != "" {
view.setRaw(tag, value)
} else if view.getRaw(tag) != nil {
view.setRaw(tag, nil)
} else {
return []PropertyName{}
}
return []PropertyName{Accept}
}
func (picker *filePickerData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case FileSelectedEvent:
return setViewEventListener[FilePicker, []FileInfo](view, tag, value)
return setOneArgEventListener[FilePicker, []FileInfo](picker, tag, value)
case Accept:
switch value := value.(type) {
case string:
return setAccept(strings.Trim(value, " \t\n"))
return setStringPropertyValue(picker, Accept, strings.Trim(value, " \t\n"))
case []string:
buffer := allocStringBuilder()
@ -184,27 +173,27 @@ func filePickerSet(view View, tag PropertyName, value any) []PropertyName {
buffer.WriteString(val)
}
}
return setAccept(buffer.String())
return setStringPropertyValue(picker, Accept, buffer.String())
}
notCompatibleType(tag, value)
return nil
}
return viewSet(view, tag, value)
return picker.viewData.setFunc(tag, value)
}
func filePickerPropertyChanged(view View, tag PropertyName) {
func (picker *filePickerData) propertyChanged(tag PropertyName) {
switch tag {
case Accept:
session := view.Session()
if css := acceptPropertyCSS(view); css != "" {
session.updateProperty(view.htmlID(), "accept", css)
session := picker.Session()
if css := acceptPropertyCSS(picker); css != "" {
session.updateProperty(picker.htmlID(), "accept", css)
} else {
session.removeProperty(view.htmlID(), "accept")
session.removeProperty(picker.htmlID(), "accept")
}
default:
viewPropertyChanged(view, tag)
picker.viewData.propertyChanged(tag)
}
}
@ -381,5 +370,5 @@ func GetFilePickerAccept(view View, subviewID ...string) []string {
// 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 GetFileSelectedListeners(view View, subviewID ...string) []func(FilePicker, []FileInfo) {
return getEventListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent)
return getOneArgEventListeners[FilePicker, []FileInfo](view, subviewID, FileSelectedEvent)
}

View File

@ -51,11 +51,11 @@ func focusEventsHtml(view View, buffer *strings.Builder) {
// GetFocusListeners returns a FocusListener list. 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 GetFocusListeners(view View, subviewID ...string) []func(View) {
return getNoParamEventListeners[View](view, subviewID, FocusEvent)
return getNoArgEventListeners[View](view, subviewID, FocusEvent)
}
// GetLostFocusListeners returns a LostFocusListener list. 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 GetLostFocusListeners(view View, subviewID ...string) []func(View) {
return getNoParamEventListeners[View](view, subviewID, LostFocusEvent)
return getNoArgEventListeners[View](view, subviewID, LostFocusEvent)
}

View File

@ -137,10 +137,10 @@ func (gridLayout *gridLayoutData) init(session Session) {
gridLayout.systemClass = "ruiGridLayout"
gridLayout.adapter = nil
gridLayout.normalize = normalizeGridLayoutTag
gridLayout.getFunc = gridLayout.get
gridLayout.get = gridLayout.getFunc
gridLayout.set = gridLayout.setFunc
gridLayout.remove = gridLayout.removeFunc
gridLayout.changed = gridLayout.propertyChanged
}
func setGridCellSize(properties Properties, tag PropertyName, value any) []PropertyName {
@ -303,7 +303,7 @@ func normalizeGridLayoutTag(tag PropertyName) PropertyName {
return tag
}
func (gridLayout *gridLayoutData) get(self View, tag PropertyName) any {
func (gridLayout *gridLayoutData) getFunc(tag PropertyName) any {
switch tag {
case Gap:
rowGap := GetGridRowGap(gridLayout)
@ -319,10 +319,10 @@ func (gridLayout *gridLayoutData) get(self View, tag PropertyName) any {
}
}
return gridLayout.viewsContainerData.get(gridLayout, tag)
return gridLayout.viewsContainerData.getFunc(tag)
}
func (gridLayout *gridLayoutData) removeFunc(self View, tag PropertyName) []PropertyName {
func (gridLayout *gridLayoutData) removeFunc(tag PropertyName) []PropertyName {
switch tag {
case Gap:
result := []PropertyName{}
@ -343,13 +343,13 @@ func (gridLayout *gridLayoutData) removeFunc(self View, tag PropertyName) []Prop
return []PropertyName{}
}
return gridLayout.viewsContainerData.removeFunc(gridLayout, tag)
return gridLayout.viewsContainerData.removeFunc(tag)
}
func (gridLayout *gridLayoutData) setFunc(self View, tag PropertyName, value any) []PropertyName {
func (gridLayout *gridLayoutData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Gap:
result := gridLayout.setFunc(gridLayout, GridRowGap, value)
result := gridLayout.setFunc(GridRowGap, value)
if result != nil {
if gap := gridLayout.getRaw(GridRowGap); gap != nil {
gridLayout.setRaw(GridColumnGap, gap)
@ -370,21 +370,23 @@ func (gridLayout *gridLayoutData) setFunc(self View, tag PropertyName, value any
return []PropertyName{Content}
}
return gridLayout.viewsContainerData.setFunc(gridLayout, tag, value)
return gridLayout.viewsContainerData.setFunc(tag, value)
}
func gridLayoutPropertyChanged(view View, tag PropertyName) {
func (gridLayout *gridLayoutData) propertyChanged(tag PropertyName) {
switch tag {
case CellWidth:
view.Session().updateCSSProperty(view.htmlID(), `grid-template-columns`,
gridCellSizesCSS(view, CellWidth, view.Session()))
session := gridLayout.Session()
session.updateCSSProperty(gridLayout.htmlID(), `grid-template-columns`,
gridCellSizesCSS(gridLayout, CellWidth, session))
case CellHeight:
view.Session().updateCSSProperty(view.htmlID(), `grid-template-rows`,
gridCellSizesCSS(view, CellHeight, view.Session()))
session := gridLayout.Session()
session.updateCSSProperty(gridLayout.htmlID(), `grid-template-rows`,
gridCellSizesCSS(gridLayout, CellHeight, session))
default:
viewsContainerPropertyChanged(view, tag)
gridLayout.viewsContainerData.propertyChanged(tag)
}
}

View File

@ -97,8 +97,8 @@ func (imageView *imageViewData) init(session Session) {
imageView.tag = "ImageView"
imageView.systemClass = "ruiImageView"
imageView.normalize = normalizeImageViewTag
imageView.set = imageViewSet
imageView.changed = imageViewPropertyChanged
imageView.set = imageView.setFunc
imageView.changed = imageView.propertyChanged
}
func normalizeImageViewTag(tag PropertyName) PropertyName {
@ -122,30 +122,30 @@ func normalizeImageViewTag(tag PropertyName) PropertyName {
return tag
}
func imageViewSet(view View, tag PropertyName, value any) []PropertyName {
func (imageView *imageViewData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Source, SrcSet, AltText:
if text, ok := value.(string); ok {
return setStringPropertyValue(view, tag, text)
return setStringPropertyValue(imageView, tag, text)
}
notCompatibleType(tag, value)
return nil
case LoadedEvent, ErrorEvent:
return setNoParamEventListener[ImageView](view, tag, value)
return setNoArgEventListener[ImageView](imageView, tag, value)
}
return viewSet(view, tag, value)
return imageView.viewData.setFunc(tag, value)
}
func imageViewPropertyChanged(view View, tag PropertyName) {
session := view.Session()
htmlID := view.htmlID()
func (imageView *imageViewData) propertyChanged(tag PropertyName) {
session := imageView.Session()
htmlID := imageView.htmlID()
switch tag {
case Source:
src, srcset := imageViewSrc(view, GetImageViewSource(view))
src, srcset := imageViewSrc(imageView, GetImageViewSource(imageView))
session.updateProperty(htmlID, "src", src)
if srcset != "" {
session.updateProperty(htmlID, "srcset", srcset)
@ -154,7 +154,7 @@ func imageViewPropertyChanged(view View, tag PropertyName) {
}
case SrcSet:
_, srcset := imageViewSrc(view, GetImageViewSource(view))
_, srcset := imageViewSrc(imageView, GetImageViewSource(imageView))
if srcset != "" {
session.updateProperty(htmlID, "srcset", srcset)
} else {
@ -168,7 +168,7 @@ func imageViewPropertyChanged(view View, tag PropertyName) {
updateCSSStyle(htmlID, session)
default:
viewPropertyChanged(view, tag)
imageView.viewData.propertyChanged(tag)
}
}
@ -256,7 +256,7 @@ func (imageView *imageViewData) htmlProperties(self View, buffer *strings.Builde
buffer.WriteString(` onload="imageLoaded(this, event)"`)
if len(getNoParamEventListeners[ImageView](imageView, nil, ErrorEvent)) > 0 {
if len(getNoArgEventListeners[ImageView](imageView, nil, ErrorEvent)) > 0 {
buffer.WriteString(` onerror="imageError(this, event)"`)
}
}
@ -299,7 +299,7 @@ func (imageView *imageViewData) cssStyle(self View, builder cssBuilder) {
func (imageView *imageViewData) handleCommand(self View, command PropertyName, data DataObject) bool {
switch command {
case "imageViewError":
for _, listener := range getNoParamEventListeners[ImageView](imageView, nil, ErrorEvent) {
for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, ErrorEvent) {
listener(imageView)
}
@ -308,7 +308,7 @@ func (imageView *imageViewData) handleCommand(self View, command PropertyName, d
imageView.naturalHeight = dataFloatProperty(data, "natural-height")
imageView.currentSrc, _ = data.PropertyValue("current-src")
for _, listener := range getNoParamEventListeners[ImageView](imageView, nil, LoadedEvent) {
for _, listener := range getNoArgEventListeners[ImageView](imageView, nil, LoadedEvent) {
listener(imageView)
}

View File

@ -431,7 +431,7 @@ func (event *KeyEvent) init(data DataObject) {
/*
func setKeyListener(properties Properties, tag PropertyName, value any) bool {
if listeners, ok := valueToEventListeners[View, KeyEvent](value); ok {
if listeners, ok := valueToOneArgEventListeners[View, KeyEvent](value); ok {
if len(listeners) == 0 {
properties.setRaw(tag, nil)
} else {
@ -460,15 +460,15 @@ func (view *viewData) removeKeyListener(tag PropertyName) {
*/
func keyEventsHtml(view View, buffer *strings.Builder) {
if len(getEventListeners[View, KeyEvent](view, nil, KeyDownEvent)) > 0 {
if len(getOneArgEventListeners[View, KeyEvent](view, nil, KeyDownEvent)) > 0 {
buffer.WriteString(`onkeydown="keyDownEvent(this, event)" `)
} else if view.Focusable() {
if len(getEventListeners[View, MouseEvent](view, nil, ClickEvent)) > 0 {
if len(getOneArgEventListeners[View, MouseEvent](view, nil, ClickEvent)) > 0 {
buffer.WriteString(`onkeydown="keyDownEvent(this, event)" `)
}
}
if listeners := getEventListeners[View, KeyEvent](view, nil, KeyUpEvent); len(listeners) > 0 {
if listeners := getOneArgEventListeners[View, KeyEvent](view, nil, KeyUpEvent); len(listeners) > 0 {
buffer.WriteString(`onkeyup="keyUpEvent(this, event)" `)
}
}
@ -476,7 +476,7 @@ func keyEventsHtml(view View, buffer *strings.Builder) {
func handleKeyEvents(view View, tag PropertyName, data DataObject) {
var event KeyEvent
event.init(data)
listeners := getEventListeners[View, KeyEvent](view, nil, tag)
listeners := getOneArgEventListeners[View, KeyEvent](view, nil, tag)
if len(listeners) > 0 {
for _, listener := range listeners {
@ -486,7 +486,7 @@ func handleKeyEvents(view View, tag PropertyName, data DataObject) {
}
if tag == KeyDownEvent && view.Focusable() && (event.Key == " " || event.Key == "Enter") && !IsDisabled(view) {
if listeners := getEventListeners[View, MouseEvent](view, nil, ClickEvent); len(listeners) > 0 {
if listeners := getOneArgEventListeners[View, MouseEvent](view, nil, ClickEvent); len(listeners) > 0 {
clickEvent := MouseEvent{
TimeStamp: event.TimeStamp,
Button: PrimaryMouseButton,
@ -512,11 +512,11 @@ func handleKeyEvents(view View, tag PropertyName, data DataObject) {
// GetKeyDownListeners returns the "key-down-event" listener list. 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 GetKeyDownListeners(view View, subviewID ...string) []func(View, KeyEvent) {
return getEventListeners[View, KeyEvent](view, subviewID, KeyDownEvent)
return getOneArgEventListeners[View, KeyEvent](view, subviewID, KeyDownEvent)
}
// GetKeyUpListeners returns the "key-up-event" listener list. 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 GetKeyUpListeners(view View, subviewID ...string) []func(View, KeyEvent) {
return getEventListeners[View, KeyEvent](view, subviewID, KeyUpEvent)
return getOneArgEventListeners[View, KeyEvent](view, subviewID, KeyUpEvent)
}

View File

@ -64,10 +64,10 @@ func (listLayout *listLayoutData) init(session Session) {
listLayout.tag = "ListLayout"
listLayout.systemClass = "ruiListLayout"
listLayout.normalize = normalizeListLayoutTag
listLayout.getFunc = listLayout.get
listLayout.get = listLayout.getFunc
listLayout.set = listLayout.setFunc
listLayout.remove = listLayout.removeFunc
listLayout.changed = listLayoutPropertyChanged
listLayout.changed = listLayout.propertyChanged
}
@ -86,7 +86,7 @@ func normalizeListLayoutTag(tag PropertyName) PropertyName {
return tag
}
func (listLayout *listLayoutData) get(self View, tag PropertyName) any {
func (listLayout *listLayoutData) getFunc(tag PropertyName) any {
switch tag {
case Gap:
if rowGap := GetListRowGap(listLayout); rowGap.Equal(GetListColumnGap(listLayout)) {
@ -100,10 +100,10 @@ func (listLayout *listLayoutData) get(self View, tag PropertyName) any {
}
}
return listLayout.viewsContainerData.get(listLayout, tag)
return listLayout.viewsContainerData.getFunc(tag)
}
func (listLayout *listLayoutData) removeFunc(self View, tag PropertyName) []PropertyName {
func (listLayout *listLayoutData) removeFunc(tag PropertyName) []PropertyName {
switch tag {
case Gap:
result := []PropertyName{}
@ -116,18 +116,18 @@ func (listLayout *listLayoutData) removeFunc(self View, tag PropertyName) []Prop
return result
case Content:
listLayout.viewsContainerData.removeFunc(listLayout, Content)
listLayout.viewsContainerData.removeFunc(Content)
listLayout.adapter = nil
return []PropertyName{Content}
}
return listLayout.viewsContainerData.removeFunc(listLayout, tag)
return listLayout.viewsContainerData.removeFunc(tag)
}
func (listLayout *listLayoutData) setFunc(self View, tag PropertyName, value any) []PropertyName {
func (listLayout *listLayoutData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Gap:
result := listLayout.setFunc(listLayout, ListRowGap, value)
result := listLayout.setFunc(ListRowGap, value)
if result != nil {
if gap := listLayout.getRaw(ListRowGap); gap != nil {
listLayout.setRaw(ListColumnGap, gap)
@ -147,16 +147,16 @@ func (listLayout *listLayoutData) setFunc(self View, tag PropertyName, value any
}
return []PropertyName{Content}
}
return listLayout.viewsContainerData.setFunc(listLayout, tag, value)
return listLayout.viewsContainerData.setFunc(tag, value)
}
func listLayoutPropertyChanged(view View, tag PropertyName) {
func (listLayout *listLayoutData) propertyChanged(tag PropertyName) {
switch tag {
case Orientation, ListWrap, HorizontalAlign, VerticalAlign:
updateCSSStyle(view.htmlID(), view.Session())
updateCSSStyle(listLayout.htmlID(), listLayout.Session())
default:
viewsContainerPropertyChanged(view, tag)
listLayout.viewsContainerData.propertyChanged(tag)
}
}

View File

@ -148,11 +148,10 @@ func (listView *listViewData) init(session Session) {
listView.items = []View{}
listView.itemFrame = []Frame{}
listView.normalize = normalizeListViewTag
listView.getFunc = listView.get
listView.set = listViewSet
listView.changed = listViewPropertyChanged
listView.remove = listViewRemove
listView.get = listView.getFunc
listView.set = listView.setFunc
listView.remove = listView.removeFunc
listView.changed = listView.propertyChanged
}
func (listView *listViewData) Views() []View {
@ -183,36 +182,36 @@ func normalizeListViewTag(tag PropertyName) PropertyName {
return tag
}
func listViewRemove(view View, tag PropertyName) []PropertyName {
func (listView *listViewData) removeFunc(tag PropertyName) []PropertyName {
switch tag {
case Gap:
result := viewRemove(view, ListRowGap)
result := listView.removeFunc(ListRowGap)
if result != nil {
if result2 := viewRemove(view, ListColumnGap); result2 != nil {
if result2 := listView.removeFunc(ListColumnGap); result2 != nil {
result = append(result, result2...)
}
}
return result
}
return viewRemove(view, tag)
return listView.viewData.removeFunc(tag)
}
func listViewSet(view View, tag PropertyName, value any) []PropertyName {
func (listView *listViewData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Gap:
result := listViewSet(view, ListRowGap, value)
result := listView.setFunc(ListRowGap, value)
if result != nil {
if result2 := listViewSet(view, ListColumnGap, value); result2 != nil {
if result2 := listView.setFunc(ListColumnGap, value); result2 != nil {
result = append(result, result2...)
}
}
return result
case ListItemClickedEvent, ListItemSelectedEvent:
return setViewEventListener[ListView, int](view, tag, value)
return setOneArgEventListener[ListView, int](listView, tag, value)
case ListItemCheckedEvent:
return setViewEventListener[ListView, []int](view, tag, value)
return setOneArgEventListener[ListView, []int](listView, tag, value)
case Checked:
var checked []int
@ -243,69 +242,65 @@ func listViewSet(view View, tag PropertyName, value any) []PropertyName {
return nil
}
return setArrayPropertyValue(view, Checked, checked)
return setArrayPropertyValue(listView, Checked, checked)
case Items:
return listViewSetItems(view, value)
return listView.setItems(value)
case ListItemStyle, CurrentStyle, CurrentInactiveStyle:
if text, ok := value.(string); ok {
return setStringPropertyValue(view, tag, text)
return setStringPropertyValue(listView, tag, text)
}
notCompatibleType(tag, value)
return nil
case Current:
return setIntProperty(view, Current, value)
return setIntProperty(listView, Current, value)
}
return viewSet(view, tag, value)
return listView.viewData.setFunc(tag, value)
}
func listViewPropertyChanged(view View, tag PropertyName) {
func (listView *listViewData) propertyChanged(tag PropertyName) {
switch tag {
case Current:
updateInnerHTML(view.htmlID(), view.Session())
if listeners := getEventListeners[ListView, int](view, nil, ListItemSelectedEvent); len(listeners) > 0 {
if listView, ok := view.(ListView); ok {
current := GetCurrent(view)
for _, listener := range listeners {
listener(listView, current)
}
updateInnerHTML(listView.htmlID(), listView.Session())
if listeners := getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent); len(listeners) > 0 {
current := GetCurrent(listView)
for _, listener := range listeners {
listener(listView, current)
}
}
case Checked:
updateInnerHTML(view.htmlID(), view.Session())
if listeners := getEventListeners[ListView, []int](view, nil, ListItemCheckedEvent); len(listeners) > 0 {
if listView, ok := view.(ListView); ok {
checked := GetListViewCheckedItems(view)
for _, listener := range listeners {
listener(listView, checked)
}
updateInnerHTML(listView.htmlID(), listView.Session())
if listeners := getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent); len(listeners) > 0 {
checked := GetListViewCheckedItems(listView)
for _, listener := range listeners {
listener(listView, checked)
}
}
case Items, Orientation, ListWrap, ListRowGap, ListColumnGap, VerticalAlign, HorizontalAlign, Style, StyleDisabled, ItemWidth, ItemHeight,
ItemHorizontalAlign, ItemVerticalAlign, ItemCheckbox, CheckboxHorizontalAlign, CheckboxVerticalAlign, ListItemStyle, AccentColor:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(listView.htmlID(), listView.Session())
case CurrentStyle:
view.Session().updateProperty(view.htmlID(), "data-focusitemstyle", listViewCurrentStyle(view))
updateInnerHTML(view.htmlID(), view.Session())
listView.Session().updateProperty(listView.htmlID(), "data-focusitemstyle", listViewCurrentStyle(listView))
updateInnerHTML(listView.htmlID(), listView.Session())
case CurrentInactiveStyle:
view.Session().updateProperty(view.htmlID(), "data-bluritemstyle", listViewCurrentInactiveStyle(view))
updateInnerHTML(view.htmlID(), view.Session())
listView.Session().updateProperty(listView.htmlID(), "data-bluritemstyle", listViewCurrentInactiveStyle(listView))
updateInnerHTML(listView.htmlID(), listView.Session())
default:
viewPropertyChanged(view, tag)
listView.viewData.propertyChanged(tag)
}
}
func (listView *listViewData) get(self View, tag PropertyName) any {
func (listView *listViewData) getFunc(tag PropertyName) any {
switch tag {
case Gap:
if rowGap := GetListRowGap(listView); rowGap.Equal(GetListColumnGap(listView)) {
@ -313,16 +308,13 @@ func (listView *listViewData) get(self View, tag PropertyName) any {
}
return AutoSize()
}
return viewGet(self, tag)
return listView.viewData.getFunc(tag)
}
func listViewSetItems(properties Properties, value any) []PropertyName {
func (listView *listViewData) setItems(value any) []PropertyName {
var adapter ListAdapter = nil
var session Session = nil
if view, ok := properties.(View); ok {
session = view.Session()
}
session := listView.session
switch value := value.(type) {
case []string:
@ -400,7 +392,7 @@ func listViewSetItems(properties Properties, value any) []PropertyName {
return nil
}
properties.setRaw(Items, adapter)
listView.setRaw(Items, adapter)
return []PropertyName{Items}
}
@ -951,7 +943,9 @@ func (listView *listViewData) handleCommand(self View, command PropertyName, dat
}
case "itemClick":
listView.onItemClick()
if number, ok := dataIntProperty(data, `number`); ok {
listView.onItemClick(number)
}
default:
return listView.viewData.handleCommand(self, command, data)
@ -962,7 +956,7 @@ func (listView *listViewData) handleCommand(self View, command PropertyName, dat
func (listView *listViewData) handleCurrent(number int) {
listView.properties[Current] = number
for _, listener := range getEventListeners[ListView, int](listView, nil, ListItemSelectedEvent) {
for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemSelectedEvent) {
listener(listView, number)
}
if listener, ok := listView.changeListener[Current]; ok {
@ -970,33 +964,37 @@ func (listView *listViewData) handleCurrent(number int) {
}
}
func (listView *listViewData) onItemClick() {
checkbox := GetListViewCheckbox(listView)
if checkbox == NoneCheckbox {
func (listView *listViewData) onItemClick(number int) {
if IsDisabled(listView) {
return
}
if current := GetCurrent(listView); current >= 0 && !IsDisabled(listView) {
if current := GetCurrent(listView); current != number {
listView.Set(Current, number)
}
if checkbox := GetListViewCheckbox(listView); checkbox != NoneCheckbox {
checkedItem := GetListViewCheckedItems(listView)
switch checkbox {
case SingleCheckbox:
if len(checkedItem) == 0 {
checkedItem = []int{current}
listView.updateCheckboxItem(current, true)
} else if checkedItem[0] != current {
checkedItem = []int{number}
listView.updateCheckboxItem(number, true)
} else if checkedItem[0] != number {
listView.updateCheckboxItem(checkedItem[0], false)
checkedItem = []int{current}
listView.updateCheckboxItem(current, true)
checkedItem = []int{number}
listView.updateCheckboxItem(number, true)
} else {
checkedItem = []int{}
listView.updateCheckboxItem(current, false)
listView.updateCheckboxItem(number, false)
}
case MultipleCheckbox:
uncheck := false
for i, index := range checkedItem {
if index == current {
if index == number {
uncheck = true
listView.updateCheckboxItem(index, false)
count := len(checkedItem)
@ -1014,8 +1012,8 @@ func (listView *listViewData) onItemClick() {
}
if !uncheck {
listView.updateCheckboxItem(current, true)
checkedItem = append(checkedItem, current)
listView.updateCheckboxItem(number, true)
checkedItem = append(checkedItem, number)
}
}
@ -1024,10 +1022,15 @@ func (listView *listViewData) onItemClick() {
listener(listView, Checked)
}
for _, listener := range getEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent) {
for _, listener := range getOneArgEventListeners[ListView, []int](listView, nil, ListItemCheckedEvent) {
listener(listView, checkedItem)
}
}
for _, listener := range getOneArgEventListeners[ListView, int](listView, nil, ListItemClickedEvent) {
listener(listView, number)
}
}
func (listView *listViewData) onItemResize(self View, index string, x, y, width, height float64) {
@ -1057,21 +1060,21 @@ func GetHorizontalAlign(view View, subviewID ...string) int {
// 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 GetListItemClickedListeners(view View, subviewID ...string) []func(ListView, int) {
return getEventListeners[ListView, int](view, subviewID, ListItemClickedEvent)
return getOneArgEventListeners[ListView, int](view, subviewID, ListItemClickedEvent)
}
// GetListItemSelectedListeners returns a ListItemSelectedListener of the ListView.
// 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 GetListItemSelectedListeners(view View, subviewID ...string) []func(ListView, int) {
return getEventListeners[ListView, int](view, subviewID, ListItemSelectedEvent)
return getOneArgEventListeners[ListView, int](view, subviewID, ListItemSelectedEvent)
}
// GetListItemCheckedListeners returns a ListItemCheckedListener of the ListView.
// 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 GetListItemCheckedListeners(view View, subviewID ...string) []func(ListView, []int) {
return getEventListeners[ListView, []int](view, subviewID, ListItemCheckedEvent)
return getOneArgEventListeners[ListView, []int](view, subviewID, ListItemCheckedEvent)
}
// GetListItemWidth returns the width of a ListView item.

View File

@ -907,46 +907,39 @@ type MediaSource struct {
func (player *mediaPlayerData) init(session Session) {
player.viewData.init(session)
player.tag = "MediaPlayer"
player.set = mediaPlayerSet
player.changed = mediaPlayerPropertyChanged
player.set = player.setFunc
player.changed = player.propertyChanged
}
func (player *mediaPlayerData) Focusable() bool {
return true
}
func mediaPlayerSet(view View, tag PropertyName, value any) []PropertyName {
func (player *mediaPlayerData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent, LoadStartEvent,
EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent,
ProgressEvent, SeekedEvent, SeekingEvent, StalledEvent, SuspendEvent, WaitingEvent:
return setNoParamEventListener[MediaPlayer](view, tag, value)
return setNoArgEventListener[MediaPlayer](player, tag, value)
case DurationChangedEvent, RateChangedEvent, TimeUpdateEvent, VolumeChangedEvent:
return setViewEventListener[MediaPlayer, float64](view, tag, value)
return setOneArgEventListener[MediaPlayer, float64](player, tag, value)
case PlayerErrorEvent:
if listeners, ok := valueToPlayerErrorListeners(value); ok {
if len(listeners) > 0 {
view.setRaw(tag, listeners)
} else if view.getRaw(tag) != nil {
view.setRaw(tag, nil)
} else {
return []PropertyName{}
}
return []PropertyName{tag}
return setArrayPropertyValue(player, tag, listeners)
}
notCompatibleType(tag, value)
return nil
case Source:
return setMediaPlayerSource(view, value)
return setMediaPlayerSource(player, value)
}
return viewSet(view, tag, value)
return player.viewData.setFunc(tag, value)
}
func setMediaPlayerSource(properties Properties, value any) []PropertyName {
@ -1151,26 +1144,26 @@ func mediaPlayerEvents() map[PropertyName]string {
}
}
func mediaPlayerPropertyChanged(view View, tag PropertyName) {
session := view.Session()
func (player *mediaPlayerData) propertyChanged(tag PropertyName) {
session := player.Session()
switch tag {
case Controls, Loop:
value, _ := boolProperty(view, tag, session)
value, _ := boolProperty(player, tag, session)
if value {
session.updateProperty(view.htmlID(), string(tag), value)
session.updateProperty(player.htmlID(), string(tag), value)
} else {
session.removeProperty(view.htmlID(), string(tag))
session.removeProperty(player.htmlID(), string(tag))
}
case Muted:
value, _ := boolProperty(view, Muted, session)
session.callFunc("setMediaMuted", view.htmlID(), value)
value, _ := boolProperty(player, Muted, session)
session.callFunc("setMediaMuted", player.htmlID(), value)
case Preload:
value, _ := enumProperty(view, Preload, session, 0)
value, _ := enumProperty(player, Preload, session, 0)
values := enumProperties[Preload].values
session.updateProperty(view.htmlID(), string(Preload), values[value])
session.updateProperty(player.htmlID(), string(Preload), values[value])
case AbortEvent, CanPlayEvent, CanPlayThroughEvent, CompleteEvent, EmptiedEvent,
EndedEvent, LoadedDataEvent, LoadedMetadataEvent, PauseEvent, PlayEvent, PlayingEvent, ProgressEvent,
@ -1178,54 +1171,54 @@ func mediaPlayerPropertyChanged(view View, tag PropertyName) {
if cssTag, ok := mediaPlayerEvents()[tag]; ok {
fn := ""
if value := view.getRaw(tag); value != nil {
if value := player.getRaw(tag); value != nil {
if listeners, ok := value.([]func(MediaPlayer)); ok && len(listeners) > 0 {
fn = fmt.Sprintf(`viewEvent(this, "%s")`, string(tag))
}
}
session.updateProperty(view.htmlID(), cssTag, fn)
session.updateProperty(player.htmlID(), cssTag, fn)
}
case TimeUpdateEvent:
if value := view.getRaw(tag); value != nil {
session.updateProperty(view.htmlID(), "ontimeupdate", "viewTimeUpdatedEvent(this)")
if value := player.getRaw(tag); value != nil {
session.updateProperty(player.htmlID(), "ontimeupdate", "viewTimeUpdatedEvent(this)")
} else {
session.updateProperty(view.htmlID(), "ontimeupdate", "")
session.updateProperty(player.htmlID(), "ontimeupdate", "")
}
case VolumeChangedEvent:
if value := view.getRaw(tag); value != nil {
session.updateProperty(view.htmlID(), "onvolumechange", "viewVolumeChangedEvent(this)")
if value := player.getRaw(tag); value != nil {
session.updateProperty(player.htmlID(), "onvolumechange", "viewVolumeChangedEvent(this)")
} else {
session.updateProperty(view.htmlID(), "onvolumechange", "")
session.updateProperty(player.htmlID(), "onvolumechange", "")
}
case DurationChangedEvent:
if value := view.getRaw(tag); value != nil {
session.updateProperty(view.htmlID(), "ondurationchange", "viewDurationChangedEvent(this)")
if value := player.getRaw(tag); value != nil {
session.updateProperty(player.htmlID(), "ondurationchange", "viewDurationChangedEvent(this)")
} else {
session.updateProperty(view.htmlID(), "ondurationchange", "")
session.updateProperty(player.htmlID(), "ondurationchange", "")
}
case RateChangedEvent:
if value := view.getRaw(tag); value != nil {
session.updateProperty(view.htmlID(), "onratechange", "viewRateChangedEvent(this)")
if value := player.getRaw(tag); value != nil {
session.updateProperty(player.htmlID(), "onratechange", "viewRateChangedEvent(this)")
} else {
session.updateProperty(view.htmlID(), "onratechange", "")
session.updateProperty(player.htmlID(), "onratechange", "")
}
case PlayerErrorEvent:
if value := view.getRaw(tag); value != nil {
session.updateProperty(view.htmlID(), "onerror", "viewErrorEvent(this)")
if value := player.getRaw(tag); value != nil {
session.updateProperty(player.htmlID(), "onerror", "viewErrorEvent(this)")
} else {
session.updateProperty(view.htmlID(), "onerror", "")
session.updateProperty(player.htmlID(), "onerror", "")
}
case Source:
updateInnerHTML(view.htmlID(), session)
updateInnerHTML(player.htmlID(), session)
default:
viewPropertyChanged(view, tag)
player.viewData.propertyChanged(tag)
}
}

View File

@ -230,7 +230,7 @@ type MouseEvent struct {
/*
func setMouseListener(properties Properties, tag PropertyName, value any) bool {
if listeners, ok := valueToEventListeners[View, MouseEvent](value); ok {
if listeners, ok := valueToOneArgEventListeners[View, MouseEvent](value); ok {
if len(listeners) == 0 {
properties.setRaw(tag, nil)
} else {
@ -302,7 +302,7 @@ func (event *MouseEvent) init(data DataObject) {
}
func handleMouseEvents(view View, tag PropertyName, data DataObject) {
listeners := getEventListeners[View, MouseEvent](view, nil, tag)
listeners := getOneArgEventListeners[View, MouseEvent](view, nil, tag)
if len(listeners) > 0 {
var event MouseEvent
event.init(data)
@ -316,48 +316,48 @@ func handleMouseEvents(view View, tag PropertyName, data DataObject) {
// GetClickListeners returns the "click-event" listener list. 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 GetClickListeners(view View, subviewID ...string) []func(View, MouseEvent) {
return getEventListeners[View, MouseEvent](view, subviewID, ClickEvent)
return getOneArgEventListeners[View, MouseEvent](view, subviewID, ClickEvent)
}
// GetDoubleClickListeners returns the "double-click-event" listener list. 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 GetDoubleClickListeners(view View, subviewID ...string) []func(View, MouseEvent) {
return getEventListeners[View, MouseEvent](view, subviewID, DoubleClickEvent)
return getOneArgEventListeners[View, MouseEvent](view, subviewID, DoubleClickEvent)
}
// GetContextMenuListeners returns the "context-menu" listener list.
// 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 GetContextMenuListeners(view View, subviewID ...string) []func(View, MouseEvent) {
return getEventListeners[View, MouseEvent](view, subviewID, ContextMenuEvent)
return getOneArgEventListeners[View, MouseEvent](view, subviewID, ContextMenuEvent)
}
// GetMouseDownListeners returns the "mouse-down" listener list. 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 GetMouseDownListeners(view View, subviewID ...string) []func(View, MouseEvent) {
return getEventListeners[View, MouseEvent](view, subviewID, MouseDown)
return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseDown)
}
// GetMouseUpListeners returns the "mouse-up" listener list. 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 GetMouseUpListeners(view View, subviewID ...string) []func(View, MouseEvent) {
return getEventListeners[View, MouseEvent](view, subviewID, MouseUp)
return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseUp)
}
// GetMouseMoveListeners returns the "mouse-move" listener list. 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 GetMouseMoveListeners(view View, subviewID ...string) []func(View, MouseEvent) {
return getEventListeners[View, MouseEvent](view, subviewID, MouseMove)
return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseMove)
}
// GetMouseOverListeners returns the "mouse-over" listener list. 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 GetMouseOverListeners(view View, subviewID ...string) []func(View, MouseEvent) {
return getEventListeners[View, MouseEvent](view, subviewID, MouseOver)
return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseOver)
}
// GetMouseOutListeners returns the "mouse-out" listener list. 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 GetMouseOutListeners(view View, subviewID ...string) []func(View, MouseEvent) {
return getEventListeners[View, MouseEvent](view, subviewID, MouseOut)
return getOneArgEventListeners[View, MouseEvent](view, subviewID, MouseOut)
}

View File

@ -1,6 +1,7 @@
package rui
import (
"fmt"
"math"
"strconv"
"strings"
@ -79,6 +80,16 @@ const (
//
// Internal type is `float`, other types converted to it during assignment.
NumberPickerValue PropertyName = "number-picker-value"
// NumberPickerValue is the constant for "number-picker-value" property tag.
//
// Used by `NumberPicker`.
// Precision of displaying fractional part in editor. The default value is 0 (not used).
//
// Supported types: `int`, `int8`...`int64`, `uint`, `uint8`...`uint64`, `string`.
//
// Internal type is `float`, other types converted to it during assignment.
NumberPickerPrecision PropertyName = "number-picker-precision"
)
// Constants which describe values of the "number-picker-type" property of a [NumberPicker]
@ -116,8 +127,8 @@ func (picker *numberPickerData) init(session Session) {
picker.tag = "NumberPicker"
picker.hasHtmlDisabled = true
picker.normalize = normalizeNumberPickerTag
picker.set = numberPickerSet
picker.changed = numberPickerPropertyChanged
picker.set = picker.setFunc
picker.changed = picker.propertyChanged
}
func (picker *numberPickerData) Focusable() bool {
@ -127,73 +138,83 @@ func (picker *numberPickerData) Focusable() bool {
func normalizeNumberPickerTag(tag PropertyName) PropertyName {
tag = defaultNormalize(tag)
switch tag {
case Type, Min, Max, Step, Value:
case Type, Min, Max, Step, Value, "precision":
return "number-picker-" + tag
}
return normalizeDataListTag(tag)
}
func numberPickerSet(view View, tag PropertyName, value any) []PropertyName {
func (picker *numberPickerData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case NumberChangedEvent:
return setEventWithOldListener[NumberPicker, float64](view, tag, value)
return setTwoArgEventListener[NumberPicker, float64](picker, tag, value)
case NumberPickerValue:
view.setRaw("old-number", GetNumberPickerValue(view))
min, max := GetNumberPickerMinMax(view)
picker.setRaw("old-number", GetNumberPickerValue(picker))
min, max := GetNumberPickerMinMax(picker)
return setFloatProperty(view, NumberPickerValue, value, min, max)
return setFloatProperty(picker, NumberPickerValue, value, min, max)
case DataList:
return setDataList(view, value, "")
return setDataList(picker, value, "")
}
return viewSet(view, tag, value)
return picker.viewData.setFunc(tag, value)
}
func numberPickerPropertyChanged(view View, tag PropertyName) {
func (picker *numberPickerData) numberFormat() string {
if precission := GetNumberPickerPrecision(picker); precission > 0 {
return fmt.Sprintf("%%.%df", precission)
}
return "%g"
}
func (picker *numberPickerData) propertyChanged(tag PropertyName) {
switch tag {
case NumberPickerType:
if GetNumberPickerType(view) == NumberSlider {
view.Session().updateProperty(view.htmlID(), "type", "range")
if GetNumberPickerType(picker) == NumberSlider {
picker.Session().updateProperty(picker.htmlID(), "type", "range")
} else {
view.Session().updateProperty(view.htmlID(), "type", "number")
picker.Session().updateProperty(picker.htmlID(), "type", "number")
}
case NumberPickerMin:
min, _ := GetNumberPickerMinMax(view)
view.Session().updateProperty(view.htmlID(), "min", strconv.FormatFloat(min, 'f', -1, 32))
min, _ := GetNumberPickerMinMax(picker)
picker.Session().updateProperty(picker.htmlID(), "min", fmt.Sprintf(picker.numberFormat(), min))
case NumberPickerMax:
_, max := GetNumberPickerMinMax(view)
view.Session().updateProperty(view.htmlID(), "max", strconv.FormatFloat(max, 'f', -1, 32))
_, max := GetNumberPickerMinMax(picker)
picker.Session().updateProperty(picker.htmlID(), "max", fmt.Sprintf(picker.numberFormat(), max))
case NumberPickerStep:
if step := GetNumberPickerStep(view); step > 0 {
view.Session().updateProperty(view.htmlID(), "step", strconv.FormatFloat(step, 'f', -1, 32))
if step := GetNumberPickerStep(picker); step > 0 {
picker.Session().updateProperty(picker.htmlID(), "step", fmt.Sprintf(picker.numberFormat(), step))
} else {
view.Session().updateProperty(view.htmlID(), "step", "any")
picker.Session().updateProperty(picker.htmlID(), "step", "any")
}
case TimePickerValue:
value := GetNumberPickerValue(view)
view.Session().callFunc("setInputValue", view.htmlID(), value)
case NumberPickerValue:
value := GetNumberPickerValue(picker)
format := picker.numberFormat()
picker.Session().callFunc("setInputValue", picker.htmlID(), fmt.Sprintf(format, value))
if listeners := GetNumberChangedListeners(view); len(listeners) > 0 {
if listeners := GetNumberChangedListeners(picker); len(listeners) > 0 {
old := 0.0
if val := view.getRaw("old-number"); val != nil {
if val := picker.getRaw("old-number"); val != nil {
if n, ok := val.(float64); ok {
old = n
}
}
for _, listener := range listeners {
listener(view, value, old)
if old != value {
for _, listener := range listeners {
listener(picker, value, old)
}
}
}
default:
viewPropertyChanged(view, tag)
picker.viewData.propertyChanged(tag)
}
}
@ -217,30 +238,31 @@ func (picker *numberPickerData) htmlProperties(self View, buffer *strings.Builde
buffer.WriteString(` type="number"`)
}
format := picker.numberFormat()
min, max := GetNumberPickerMinMax(picker)
if min != math.Inf(-1) {
buffer.WriteString(` min="`)
buffer.WriteString(strconv.FormatFloat(min, 'f', -1, 64))
buffer.WriteString(fmt.Sprintf(format, min))
buffer.WriteByte('"')
}
if max != math.Inf(1) {
buffer.WriteString(` max="`)
buffer.WriteString(strconv.FormatFloat(max, 'f', -1, 64))
buffer.WriteString(fmt.Sprintf(format, max))
buffer.WriteByte('"')
}
step := GetNumberPickerStep(picker)
if step != 0 {
buffer.WriteString(` step="`)
buffer.WriteString(strconv.FormatFloat(step, 'f', -1, 64))
buffer.WriteString(fmt.Sprintf(format, step))
buffer.WriteByte('"')
} else {
buffer.WriteString(` step="any"`)
}
buffer.WriteString(` value="`)
buffer.WriteString(strconv.FormatFloat(GetNumberPickerValue(picker), 'f', -1, 64))
buffer.WriteString(fmt.Sprintf(format, GetNumberPickerValue(picker)))
buffer.WriteByte('"')
buffer.WriteString(` oninput="editViewInputEvent(this)"`)
@ -342,5 +364,11 @@ func GetNumberPickerValue(view View, subviewID ...string) float64 {
// 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 GetNumberChangedListeners(view View, subviewID ...string) []func(NumberPicker, float64, float64) {
return getEventWithOldListeners[NumberPicker, float64](view, subviewID, NumberChangedEvent)
return getTwoArgEventListeners[NumberPicker, float64](view, subviewID, NumberChangedEvent)
}
// GetNumberPickerPrecision returns the precision of displaying fractional part in editor of NumberPicker subview.
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetNumberPickerPrecision(view View, subviewID ...string) int {
return intStyledProperty(view, subviewID, NumberPickerPrecision, 0)
}

View File

@ -156,7 +156,7 @@ type PointerEvent struct {
/*
func setPointerListener(properties Properties, tag PropertyName, value any) bool {
if listeners, ok := valueToEventListeners[View, PointerEvent](value); ok {
if listeners, ok := valueToOneArgEventListeners[View, PointerEvent](value); ok {
if len(listeners) == 0 {
properties.setRaw(tag, nil)
} else {
@ -210,7 +210,7 @@ func (event *PointerEvent) init(data DataObject) {
}
func handlePointerEvents(view View, tag PropertyName, data DataObject) {
listeners := getEventListeners[View, PointerEvent](view, nil, tag)
listeners := getOneArgEventListeners[View, PointerEvent](view, nil, tag)
if len(listeners) == 0 {
return
}
@ -226,35 +226,35 @@ func handlePointerEvents(view View, tag PropertyName, data DataObject) {
// GetPointerDownListeners returns the "pointer-down" listener list. 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 GetPointerDownListeners(view View, subviewID ...string) []func(View, PointerEvent) {
return getEventListeners[View, PointerEvent](view, subviewID, PointerDown)
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerDown)
}
// GetPointerUpListeners returns the "pointer-up" listener list. 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 GetPointerUpListeners(view View, subviewID ...string) []func(View, PointerEvent) {
return getEventListeners[View, PointerEvent](view, subviewID, PointerUp)
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerUp)
}
// GetPointerMoveListeners returns the "pointer-move" listener list. 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 GetPointerMoveListeners(view View, subviewID ...string) []func(View, PointerEvent) {
return getEventListeners[View, PointerEvent](view, subviewID, PointerMove)
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerMove)
}
// GetPointerCancelListeners returns the "pointer-cancel" listener list. 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 GetPointerCancelListeners(view View, subviewID ...string) []func(View, PointerEvent) {
return getEventListeners[View, PointerEvent](view, subviewID, PointerCancel)
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerCancel)
}
// GetPointerOverListeners returns the "pointer-over" listener list. 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 GetPointerOverListeners(view View, subviewID ...string) []func(View, PointerEvent) {
return getEventListeners[View, PointerEvent](view, subviewID, PointerOver)
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerOver)
}
// GetPointerOutListeners returns the "pointer-out" listener list. 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 GetPointerOutListeners(view View, subviewID ...string) []func(View, PointerEvent) {
return getEventListeners[View, PointerEvent](view, subviewID, PointerOut)
return getOneArgEventListeners[View, PointerEvent](view, subviewID, PointerOut)
}

View File

@ -560,7 +560,7 @@ func (popup *popupData) init(view View, popupParams Params) {
}
case DismissEvent:
if listeners, ok := valueToNoParamListeners[Popup](value); ok {
if listeners, ok := valueToNoArgEventListeners[Popup](value); ok {
if listeners != nil {
popup.dismissListener = listeners
}

View File

@ -53,7 +53,7 @@ func (progress *progressBarData) init(session Session) {
progress.viewData.init(session)
progress.tag = "ProgressBar"
progress.normalize = normalizeProgressBarTag
progress.changed = progressBarPropertyChanged
progress.changed = progress.propertyChanged
}
func normalizeProgressBarTag(tag PropertyName) PropertyName {
@ -68,19 +68,19 @@ func normalizeProgressBarTag(tag PropertyName) PropertyName {
return tag
}
func progressBarPropertyChanged(view View, tag PropertyName) {
func (progress *progressBarData) propertyChanged(tag PropertyName) {
switch tag {
case ProgressBarMax:
view.Session().updateProperty(view.htmlID(), "max",
strconv.FormatFloat(GetProgressBarMax(view), 'f', -1, 32))
progress.Session().updateProperty(progress.htmlID(), "max",
strconv.FormatFloat(GetProgressBarMax(progress), 'f', -1, 32))
case ProgressBarValue:
view.Session().updateProperty(view.htmlID(), "value",
strconv.FormatFloat(GetProgressBarValue(view), 'f', -1, 32))
progress.Session().updateProperty(progress.htmlID(), "value",
strconv.FormatFloat(GetProgressBarValue(progress), 'f', -1, 32))
default:
viewPropertyChanged(view, tag)
progress.viewData.propertyChanged(tag)
}
}

View File

@ -19,6 +19,7 @@ var colorProperties = []PropertyName{
OutlineColor,
TextLineColor,
ColorPickerValue,
AccentColor,
}
func isPropertyInList(tag PropertyName, list []PropertyName) bool {
@ -74,6 +75,7 @@ var intProperties = []PropertyName{
Order,
TabIndex,
MaxLength,
NumberPickerPrecision,
}
var floatProperties = map[PropertyName]struct{ min, max float64 }{
@ -136,9 +138,9 @@ var sizeProperties = map[PropertyName]string{
Perspective: string(Perspective),
PerspectiveOriginX: string(PerspectiveOriginX),
PerspectiveOriginY: string(PerspectiveOriginY),
OriginX: string(OriginX),
OriginY: string(OriginY),
OriginZ: string(OriginZ),
TransformOriginX: string(TransformOriginX),
TransformOriginY: string(TransformOriginY),
TransformOriginZ: string(TransformOriginZ),
Radius: string(Radius),
RadiusX: string(RadiusX),
RadiusY: string(RadiusY),

View File

@ -80,8 +80,8 @@ func (resizable *resizableData) init(session Session) {
resizable.viewData.init(session)
resizable.tag = "Resizable"
resizable.systemClass = "ruiGridLayout"
resizable.set = resizableSet
resizable.changed = resizablePropertyChanged
resizable.set = resizable.setFunc
resizable.changed = resizable.propertyChanged
}
func (resizable *resizableData) Views() []View {
@ -100,25 +100,25 @@ func (resizable *resizableData) content() View {
return nil
}
func resizableSet(view View, tag PropertyName, value any) []PropertyName {
func (resizable *resizableData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Side:
return resizableSetSide(view, value)
return resizableSetSide(resizable, value)
case ResizeBorderWidth:
return setSizeProperty(view, tag, value)
return setSizeProperty(resizable, tag, value)
case Content:
var newContent View = nil
switch value := value.(type) {
case string:
newContent = NewTextView(view.Session(), Params{Text: value})
newContent = NewTextView(resizable.Session(), Params{Text: value})
case View:
newContent = value
case DataObject:
if newContent = CreateViewFromObject(view.Session(), value); newContent == nil {
if newContent = CreateViewFromObject(resizable.Session(), value); newContent == nil {
return nil
}
@ -127,7 +127,7 @@ func resizableSet(view View, tag PropertyName, value any) []PropertyName {
return nil
}
view.setRaw(Content, newContent)
resizable.setRaw(Content, newContent)
return []PropertyName{}
case CellWidth, CellHeight, GridRowGap, GridColumnGap, CellVerticalAlign, CellHorizontalAlign:
@ -135,28 +135,28 @@ func resizableSet(view View, tag PropertyName, value any) []PropertyName {
return nil
}
return viewSet(view, tag, value)
return resizable.viewData.setFunc(tag, value)
}
func resizablePropertyChanged(view View, tag PropertyName) {
func (resizable *resizableData) propertyChanged(tag PropertyName) {
switch tag {
case Side:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(resizable.htmlID(), resizable.Session())
fallthrough
case ResizeBorderWidth:
htmlID := view.htmlID()
session := view.Session()
column, row := resizableCellSizeCSS(view)
htmlID := resizable.htmlID()
session := resizable.Session()
column, row := resizableCellSizeCSS(resizable)
session.updateCSSProperty(htmlID, "grid-template-columns", column)
session.updateCSSProperty(htmlID, "grid-template-rows", row)
case Content:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(resizable.htmlID(), resizable.Session())
default:
viewPropertyChanged(view, tag)
resizable.viewData.propertyChanged(tag)
}
}

View File

@ -33,7 +33,7 @@ func (view *viewData) onItemResize(self View, index string, x, y, width, height
/*
func setFrameListener(properties Properties, tag PropertyName, value any) bool {
if listeners, ok := valueToEventListeners[View, Frame](value); ok {
if listeners, ok := valueToOneArgEventListeners[View, Frame](value); ok {
if len(listeners) == 0 {
properties.setRaw(tag, nil)
} else {
@ -85,5 +85,5 @@ func GetViewFrame(view View, subviewID ...string) Frame {
// GetResizeListeners returns the list of "resize-event" listeners. If there are no listeners then the empty list is returned
// If the second argument (subviewID) is not specified or it is "" then the listeners list of the first argument (view) is returned
func GetResizeListeners(view View, subviewID ...string) []func(View, Frame) {
return getEventListeners[View, Frame](view, subviewID, ResizeEvent)
return getOneArgEventListeners[View, Frame](view, subviewID, ResizeEvent)
}

View File

@ -54,7 +54,7 @@ func GetViewScroll(view View, subviewID ...string) Frame {
// GetScrollListeners returns the list of "scroll-event" listeners. If there are no listeners then the empty list is returned
// If the second argument (subviewID) is not specified or it is "" then the listeners list of the first argument (view) is returned
func GetScrollListeners(view View, subviewID ...string) []func(View, Frame) {
return getEventListeners[View, Frame](view, subviewID, ResizeEvent)
return getOneArgEventListeners[View, Frame](view, subviewID, ResizeEvent)
}
// ScrollTo scrolls the view's content to the given position.

View File

@ -81,9 +81,10 @@ func (layout *stackLayoutData) init(session Session) {
layout.tag = "StackLayout"
layout.systemClass = "ruiStackLayout"
layout.properties[TransitionEndEvent] = []func(View, string){layout.pushFinished, layout.popFinished}
layout.getFunc = layout.get
layout.get = layout.getFunc
layout.set = layout.setFunc
layout.remove = layout.removeFunc
layout.changed = layout.propertyChanged
}
func (layout *stackLayoutData) pushFinished(view View, tag string) {
@ -121,14 +122,14 @@ func (layout *stackLayoutData) popFinished(view View, tag string) {
}
}
func (layout *stackLayoutData) setFunc(view View, tag PropertyName, value any) []PropertyName {
func (layout *stackLayoutData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case TransitionEndEvent:
listeners, ok := valueToEventListeners[View, string](value)
listeners, ok := valueToOneArgEventListeners[View, string](value)
if ok && listeners != nil {
listeners = append(listeners, layout.pushFinished)
listeners = append(listeners, layout.popFinished)
view.setRaw(TransitionEndEvent, listeners)
layout.setRaw(TransitionEndEvent, listeners)
return []PropertyName{tag}
}
return nil
@ -170,42 +171,42 @@ func (layout *stackLayoutData) setFunc(view View, tag PropertyName, value any) [
layout.peek = newCurrent
return []PropertyName{tag}
}
return layout.viewsContainerData.setFunc(view, tag, value)
return layout.viewsContainerData.setFunc(tag, value)
}
func (layout *stackLayoutData) propertyChanged(view View, tag PropertyName) {
func (layout *stackLayoutData) propertyChanged(tag PropertyName) {
switch tag {
case Current:
if layout.prevPeek != layout.peek {
if layout.prevPeek < len(layout.views) {
layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(layout.prevPeek), "visibility", "hidden")
}
layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(layout.prevPeek), "visibility", "visible")
layout.Session().updateCSSProperty(layout.htmlID()+"page"+strconv.Itoa(layout.peek), "visibility", "visible")
layout.prevPeek = layout.peek
}
default:
viewsContainerPropertyChanged(view, tag)
layout.viewsContainerData.propertyChanged(tag)
}
}
func (layout *stackLayoutData) removeFunc(view View, tag PropertyName) []PropertyName {
func (layout *stackLayoutData) removeFunc(tag PropertyName) []PropertyName {
switch tag {
case TransitionEndEvent:
view.setRaw(TransitionEndEvent, []func(View, string){layout.pushFinished, layout.popFinished})
layout.setRaw(TransitionEndEvent, []func(View, string){layout.pushFinished, layout.popFinished})
return []PropertyName{tag}
case Current:
view.setRaw(Current, 0)
layout.setRaw(Current, 0)
return []PropertyName{tag}
}
return layout.viewsContainerData.removeFunc(view, tag)
return layout.viewsContainerData.removeFunc(tag)
}
func (layout *stackLayoutData) get(view View, tag PropertyName) any {
func (layout *stackLayoutData) getFunc(tag PropertyName) any {
if tag == Current {
return layout.peek
}
return layout.viewsContainerData.get(view, tag)
return layout.viewsContainerData.getFunc(tag)
}
func (layout *stackLayoutData) Peek() View {

View File

@ -34,8 +34,8 @@ func (imageView *svgImageViewData) init(session Session) {
imageView.tag = "SvgImageView"
imageView.systemClass = "ruiSvgImageView"
imageView.normalize = normalizeSvgImageViewTag
imageView.set = svgImageViewSet
imageView.changed = svgImageViewPropertyChanged
imageView.set = imageView.setFunc
imageView.changed = imageView.propertyChanged
}
@ -54,28 +54,28 @@ func normalizeSvgImageViewTag(tag PropertyName) PropertyName {
return tag
}
func svgImageViewSet(view View, tag PropertyName, value any) []PropertyName {
func (imageView *svgImageViewData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Content:
if text, ok := value.(string); ok {
view.setRaw(Content, text)
imageView.setRaw(Content, text)
return []PropertyName{tag}
}
notCompatibleType(Source, value)
return nil
default:
return viewSet(view, tag, value)
return imageView.viewData.setFunc(tag, value)
}
}
func svgImageViewPropertyChanged(view View, tag PropertyName) {
func (imageView *svgImageViewData) propertyChanged(tag PropertyName) {
switch tag {
case Content:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(imageView.htmlID(), imageView.Session())
default:
viewPropertyChanged(view, tag)
imageView.viewData.propertyChanged(tag)
}
}

View File

@ -593,8 +593,8 @@ func (table *tableViewData) init(session Session) {
table.current.Column = -1
*/
table.normalize = normalizeTableViewTag
table.set = tableViewSet
table.changed = tableViewPropertyChanged
table.set = table.setFunc
table.changed = table.propertyChanged
}
func normalizeTableViewTag(tag PropertyName) PropertyName {
@ -618,7 +618,7 @@ func (table *tableViewData) Focusable() bool {
return GetTableSelectionMode(table) != NoneSelection
}
func tableViewSet(view View, tag PropertyName, value any) []PropertyName {
func (table *tableViewData) setFunc(tag PropertyName, value any) []PropertyName {
setLineStyle := func() []PropertyName {
params := []Params{}
@ -637,9 +637,9 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName {
if len(params) > 0 {
style := new(simpleTableLineStyle)
style.params = params
view.setRaw(tag, style)
} else if view.getRaw(tag) != nil {
view.setRaw(tag, nil)
table.setRaw(tag, style)
} else if table.getRaw(tag) != nil {
table.setRaw(tag, nil)
} else {
return []PropertyName{}
}
@ -650,13 +650,13 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName {
case Content:
switch val := value.(type) {
case TableAdapter:
view.setRaw(Content, value)
table.setRaw(Content, value)
case [][]any:
view.setRaw(Content, NewSimpleTableAdapter(val))
table.setRaw(Content, NewSimpleTableAdapter(val))
case [][]string:
view.setRaw(Content, NewTextTableAdapter(val))
table.setRaw(Content, NewTextTableAdapter(val))
default:
notCompatibleType(tag, value)
@ -665,14 +665,14 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName {
return []PropertyName{tag}
case TableCellClickedEvent, TableCellSelectedEvent:
return setEventWithOldListener[TableView, int](view, tag, value)
return setTwoArgEventListener[TableView, int](table, tag, value)
case TableRowClickedEvent, TableRowSelectedEvent:
return setViewEventListener[TableView, int](view, tag, value)
return setOneArgEventListener[TableView, int](table, tag, value)
case CellStyle:
if style, ok := value.(TableCellStyle); ok {
view.setRaw(tag, style)
table.setRaw(tag, style)
return []PropertyName{tag}
}
notCompatibleType(tag, value)
@ -680,14 +680,14 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName {
case RowStyle:
if style, ok := value.(TableRowStyle); ok {
view.setRaw(tag, style)
table.setRaw(tag, style)
return []PropertyName{tag}
}
return setLineStyle()
case ColumnStyle:
if style, ok := value.(TableColumnStyle); ok {
view.setRaw(tag, style)
table.setRaw(tag, style)
return []PropertyName{tag}
}
return setLineStyle()
@ -696,9 +696,9 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName {
switch value := value.(type) {
case string:
if isConstantName(value) {
view.setRaw(tag, value)
table.setRaw(tag, value)
} else if n, err := strconv.Atoi(value); err == nil {
view.setRaw(tag, n)
table.setRaw(tag, n)
} else {
ErrorLog(err.Error())
notCompatibleType(tag, value)
@ -707,7 +707,7 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName {
default:
if n, ok := isInt(value); ok {
view.setRaw(tag, n)
table.setRaw(tag, n)
} else {
notCompatibleType(tag, value)
return nil
@ -718,13 +718,13 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName {
case HeadStyle, FootStyle:
switch value := value.(type) {
case string:
view.setRaw(tag, value)
table.setRaw(tag, value)
case Params:
if len(value) > 0 {
view.setRaw(tag, value)
} else if view.getRaw(tag) != nil {
view.setRaw(tag, nil)
table.setRaw(tag, value)
} else if table.getRaw(tag) != nil {
table.setRaw(tag, nil)
} else {
return []PropertyName{}
}
@ -736,15 +736,15 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName {
params[PropertyName(prop.Tag())] = prop.Text()
}
}
return tableViewSet(view, tag, params)
return table.setFunc(tag, params)
case DataNode:
switch value.Type() {
case ObjectNode:
return tableViewSet(view, tag, value.Object())
return table.setFunc(tag, value.Object())
case TextNode:
view.setRaw(tag, value.Text())
table.setRaw(tag, value.Text())
default:
notCompatibleType(tag, value)
@ -760,10 +760,10 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName {
case AllowSelection:
switch value.(type) {
case TableAllowCellSelection:
view.setRaw(tag, value)
table.setRaw(tag, value)
case TableAllowRowSelection:
view.setRaw(tag, value)
table.setRaw(tag, value)
default:
notCompatibleType(tag, value)
@ -819,17 +819,17 @@ func tableViewSet(view View, tag PropertyName, value any) []PropertyName {
return nil
}
}
view.setRaw(Current, current)
table.setRaw(Current, current)
return []PropertyName{tag}
}
return viewSet(view, tag, value)
return table.viewData.setFunc(tag, value)
}
func tableViewPropertyChanged(view View, tag PropertyName) {
func (table *tableViewData) propertyChanged(tag PropertyName) {
htmlID := view.htmlID()
session := view.Session()
htmlID := table.htmlID()
session := table.Session()
switch tag {
case Content, TableVerticalAlign, RowStyle, ColumnStyle, CellStyle, CellPadding,
@ -837,20 +837,20 @@ func tableViewPropertyChanged(view View, tag PropertyName) {
CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft,
TableCellClickedEvent, TableCellSelectedEvent, TableRowClickedEvent,
TableRowSelectedEvent, AllowSelection, AccentColor:
ReloadTableViewData(view)
ReloadTableViewData(table)
case Current:
switch GetTableSelectionMode(view) {
switch GetTableSelectionMode(table) {
case CellSelection:
current := tableViewCurrent(view)
current := tableViewCurrent(table)
session.callFunc("setTableCellCursorByID", htmlID, current.Row, current.Column)
case RowSelection:
session.callFunc("setTableRowCursorByID", htmlID, tableViewCurrent(view).Row)
session.callFunc("setTableRowCursorByID", htmlID, tableViewCurrent(table).Row)
}
case Gap:
gap, ok := sizeProperty(view, Gap, session)
gap, ok := sizeProperty(table, Gap, session)
if !ok || gap.Type == Auto || gap.Value <= 0 {
session.updateCSSProperty(htmlID, "border-spacing", "0")
session.updateCSSProperty(htmlID, "border-collapse", "collapse")
@ -860,43 +860,43 @@ func tableViewPropertyChanged(view View, tag PropertyName) {
}
case SelectionMode:
switch GetTableSelectionMode(view) {
switch GetTableSelectionMode(table) {
case CellSelection:
tabIndex, _ := intProperty(view, TabIndex, session, 0)
tabIndex, _ := intProperty(table, TabIndex, session, 0)
session.updateProperty(htmlID, "tabindex", tabIndex)
session.updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)")
session.updateProperty(htmlID, "onblur", "tableViewBlurEvent(this, event)")
session.updateProperty(htmlID, "data-selection", "cell")
session.updateProperty(htmlID, "data-focusitemstyle", tableViewCurrentStyle(view))
session.updateProperty(htmlID, "data-bluritemstyle", tableViewCurrentInactiveStyle(view))
session.updateProperty(htmlID, "data-focusitemstyle", tableViewCurrentStyle(table))
session.updateProperty(htmlID, "data-bluritemstyle", tableViewCurrentInactiveStyle(table))
current := tableViewCurrent(view)
current := tableViewCurrent(table)
if current.Row >= 0 && current.Column >= 0 {
session.updateProperty(htmlID, "data-current", tableViewCellID(view, current.Row, current.Column))
session.updateProperty(htmlID, "data-current", tableViewCellID(table, current.Row, current.Column))
} else {
session.removeProperty(htmlID, "data-current")
}
session.updateProperty(htmlID, "onkeydown", "tableViewCellKeyDownEvent(this, event)")
case RowSelection:
tabIndex, _ := intProperty(view, TabIndex, session, 0)
tabIndex, _ := intProperty(table, TabIndex, session, 0)
session.updateProperty(htmlID, "tabindex", tabIndex)
session.updateProperty(htmlID, "onfocus", "tableViewFocusEvent(this, event)")
session.updateProperty(htmlID, "onblur", "tableViewBlurEvent(this, event)")
session.updateProperty(htmlID, "data-selection", "row")
session.updateProperty(htmlID, "data-focusitemstyle", tableViewCurrentStyle(view))
session.updateProperty(htmlID, "data-bluritemstyle", tableViewCurrentInactiveStyle(view))
session.updateProperty(htmlID, "data-focusitemstyle", tableViewCurrentStyle(table))
session.updateProperty(htmlID, "data-bluritemstyle", tableViewCurrentInactiveStyle(table))
current := tableViewCurrent(view)
current := tableViewCurrent(table)
if current.Row >= 0 {
session.updateProperty(htmlID, "data-current", tableViewRowID(view, current.Row))
session.updateProperty(htmlID, "data-current", tableViewRowID(table, current.Row))
} else {
session.removeProperty(htmlID, "data-current")
}
session.updateProperty(htmlID, "onkeydown", "tableViewRowKeyDownEvent(this, event)")
default: // NoneSelection
if tabIndex, ok := intProperty(view, TabIndex, session, -1); !ok || tabIndex < 0 {
if tabIndex, ok := intProperty(table, TabIndex, session, -1); !ok || tabIndex < 0 {
session.removeProperty(htmlID, "tabindex")
}
@ -907,7 +907,7 @@ func tableViewPropertyChanged(view View, tag PropertyName) {
updateInnerHTML(htmlID, session)
default:
viewPropertyChanged(view, tag)
table.viewData.propertyChanged(tag)
}
}

View File

@ -152,28 +152,28 @@ func GetTableCurrent(view View, subviewID ...string) CellIndex {
// 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 GetTableCellClickedListeners(view View, subviewID ...string) []func(TableView, int, int) {
return getEventWithOldListeners[TableView, int](view, subviewID, TableCellClickedEvent)
return getTwoArgEventListeners[TableView, int](view, subviewID, TableCellClickedEvent)
}
// GetTableCellSelectedListeners returns listeners of event which occurs when a table cell becomes selected.
// 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 GetTableCellSelectedListeners(view View, subviewID ...string) []func(TableView, int, int) {
return getEventWithOldListeners[TableView, int](view, subviewID, TableCellSelectedEvent)
return getTwoArgEventListeners[TableView, int](view, subviewID, TableCellSelectedEvent)
}
// GetTableRowClickedListeners returns listeners of event which occurs when the user clicks on a table row.
// 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 GetTableRowClickedListeners(view View, subviewID ...string) []func(TableView, int) {
return getEventListeners[TableView, int](view, subviewID, TableRowClickedEvent)
return getOneArgEventListeners[TableView, int](view, subviewID, TableRowClickedEvent)
}
// GetTableRowSelectedListeners returns listeners of event which occurs when a table row becomes selected.
// 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 GetTableRowSelectedListeners(view View, subviewID ...string) []func(TableView, int) {
return getEventListeners[TableView, int](view, subviewID, TableRowSelectedEvent)
return getOneArgEventListeners[TableView, int](view, subviewID, TableRowSelectedEvent)
}
// ReloadTableViewData updates TableView

View File

@ -168,69 +168,69 @@ func tabsLayoutCurrent(view View, defaultValue int) int {
return result
}
func (tabsLayout *tabsLayoutData) setFunc(view View, tag PropertyName, value any) []PropertyName {
func (tabsLayout *tabsLayoutData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case CurrentTabChangedEvent:
return setEventWithOldListener[TabsLayout, int](view, tag, value)
return setTwoArgEventListener[TabsLayout, int](tabsLayout, tag, value)
case TabCloseEvent:
return setViewEventListener[TabsLayout, int](view, tag, value)
return setOneArgEventListener[TabsLayout, int](tabsLayout, tag, value)
case Current:
view.setRaw("old-current", tabsLayoutCurrent(view, -1))
tabsLayout.setRaw("old-current", tabsLayoutCurrent(tabsLayout, -1))
if current, ok := value.(int); ok && current < 0 {
view.setRaw(Current, nil)
tabsLayout.setRaw(Current, nil)
return []PropertyName{tag}
}
return setIntProperty(view, Current, value)
return setIntProperty(tabsLayout, Current, value)
case TabStyle, CurrentTabStyle, TabBarStyle:
if text, ok := value.(string); ok {
return setStringPropertyValue(view, tag, text)
return setStringPropertyValue(tabsLayout, tag, text)
}
notCompatibleType(tag, value)
return nil
}
return tabsLayout.viewsContainerData.setFunc(tabsLayout, tag, value)
return tabsLayout.viewsContainerData.setFunc(tag, value)
}
func (tabsLayout *tabsLayoutData) propertyChanged(view View, tag PropertyName) {
func (tabsLayout *tabsLayoutData) propertyChanged(tag PropertyName) {
switch tag {
case Current:
session := view.Session()
current := GetCurrent(view)
session.callFunc("activateTab", view.htmlID(), current)
session := tabsLayout.Session()
current := GetCurrent(tabsLayout)
session.callFunc("activateTab", tabsLayout.htmlID(), current)
if listeners := getEventWithOldListeners[TabsLayout, int](view, nil, CurrentTabChangedEvent); len(listeners) > 0 {
oldCurrent, _ := intProperty(view, "old-current", session, -1)
if listeners := getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent); len(listeners) > 0 {
oldCurrent, _ := intProperty(tabsLayout, "old-current", session, -1)
for _, listener := range listeners {
listener(tabsLayout, current, oldCurrent)
}
}
case Tabs:
htmlID := view.htmlID()
session := view.Session()
session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(view))
session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(view))
htmlID := tabsLayout.htmlID()
session := tabsLayout.Session()
session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(tabsLayout))
session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(tabsLayout))
updateCSSStyle(htmlID, session)
updateInnerHTML(htmlID, session)
case TabStyle, CurrentTabStyle, TabBarStyle:
htmlID := view.htmlID()
session := view.Session()
session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(view))
session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(view))
htmlID := tabsLayout.htmlID()
session := tabsLayout.Session()
session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(tabsLayout))
session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(tabsLayout))
updateInnerHTML(htmlID, session)
case TabCloseButton:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session())
default:
viewsContainerPropertyChanged(view, tag)
tabsLayout.viewsContainerData.propertyChanged(tag)
}
}
@ -499,7 +499,7 @@ func (tabsLayout *tabsLayoutData) ListItem(index int, session Session) View {
Column: 2,
Content: "✕",
ClickEvent: func() {
for _, listener := range getEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
listener(tabsLayout, index)
}
},
@ -565,7 +565,7 @@ func (tabsLayout *tabsLayoutData) Insert(view View, index int) {
if view != nil {
if current := GetCurrent(tabsLayout); current >= index {
tabsLayout.setRaw(Current, current+1)
defer tabsLayout.currentChanged()
defer tabsLayout.currentChanged(current+1, current)
}
tabsLayout.viewsContainerData.Insert(view, index)
view.SetChangeListener(Title, tabsLayout.updateTitle)
@ -574,7 +574,10 @@ func (tabsLayout *tabsLayoutData) Insert(view View, index int) {
}
}
func (tabsLayout *tabsLayoutData) currentChanged() {
func (tabsLayout *tabsLayoutData) currentChanged(newCurrent, oldCurrent int) {
for _, listener := range getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) {
listener(tabsLayout, newCurrent, oldCurrent)
}
if listener, ok := tabsLayout.changeListener[Current]; ok {
listener(tabsLayout, Current)
}
@ -600,7 +603,7 @@ func (tabsLayout *tabsLayoutData) RemoveView(index int) View {
if newCurrent != oldCurrent {
tabsLayout.setRaw(Current, newCurrent)
tabsLayout.currentChanged()
tabsLayout.currentChanged(newCurrent, oldCurrent)
}
}
return nil
@ -871,10 +874,8 @@ func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName,
current := GetCurrent(tabsLayout)
if current != number {
tabsLayout.setRaw(Current, number)
for _, listener := range getEventWithOldListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) {
listener(tabsLayout, number, current)
}
tabsLayout.currentChanged()
tabsLayout.currentChanged(number, current)
}
}
}
@ -883,7 +884,7 @@ func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName,
case "tabCloseClick":
if numberText, ok := data.PropertyValue("number"); ok {
if number, err := strconv.Atoi(numberText); err == nil {
for _, listener := range getEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
listener(tabsLayout, number)
}
}

View File

@ -30,63 +30,63 @@ func newTextView(session Session) View {
func (textView *textViewData) init(session Session) {
textView.viewData.init(session)
textView.tag = "TextView"
textView.set = textViewSet
textView.changed = textViewPropertyChanged
textView.set = textView.setFunc
textView.changed = textView.propertyChanged
}
func textViewPropertyChanged(view View, tag PropertyName) {
func (textView *textViewData) propertyChanged(tag PropertyName) {
switch tag {
case Text:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(textView.htmlID(), textView.Session())
case TextOverflow:
session := view.Session()
if n, ok := enumProperty(view, TextOverflow, session, 0); ok {
session := textView.Session()
if n, ok := enumProperty(textView, TextOverflow, session, 0); ok {
values := enumProperties[TextOverflow].cssValues
if n >= 0 && n < len(values) {
session.updateCSSProperty(view.htmlID(), string(TextOverflow), values[n])
session.updateCSSProperty(textView.htmlID(), string(TextOverflow), values[n])
return
}
}
session.updateCSSProperty(view.htmlID(), string(TextOverflow), "")
session.updateCSSProperty(textView.htmlID(), string(TextOverflow), "")
case NotTranslate:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(textView.htmlID(), textView.Session())
default:
viewPropertyChanged(view, tag)
textView.viewData.propertyChanged(tag)
}
}
func textViewSet(view View, tag PropertyName, value any) []PropertyName {
func (textView *textViewData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Text:
switch value := value.(type) {
case string:
view.setRaw(Text, value)
textView.setRaw(Text, value)
case fmt.Stringer:
view.setRaw(Text, value.String())
textView.setRaw(Text, value.String())
case float32:
view.setRaw(Text, fmt.Sprintf("%g", float64(value)))
textView.setRaw(Text, fmt.Sprintf("%g", float64(value)))
case float64:
view.setRaw(Text, fmt.Sprintf("%g", value))
textView.setRaw(Text, fmt.Sprintf("%g", value))
case []rune:
view.setRaw(Text, string(value))
textView.setRaw(Text, string(value))
case bool:
if value {
view.setRaw(Text, "true")
textView.setRaw(Text, "true")
} else {
view.setRaw(Text, "false")
textView.setRaw(Text, "false")
}
default:
if n, ok := isInt(value); ok {
view.setRaw(Text, fmt.Sprintf("%d", n))
textView.setRaw(Text, fmt.Sprintf("%d", n))
} else {
notCompatibleType(tag, value)
return nil
@ -95,7 +95,7 @@ func textViewSet(view View, tag PropertyName, value any) []PropertyName {
return []PropertyName{Text}
}
return viewSet(view, tag, value)
return textView.viewData.setFunc(tag, value)
}
func (textView *textViewData) htmlSubviews(self View, buffer *strings.Builder) {

View File

@ -120,8 +120,8 @@ func (picker *timePickerData) init(session Session) {
picker.tag = "TimePicker"
picker.hasHtmlDisabled = true
picker.normalize = normalizeTimePickerTag
picker.set = timePickerSet
picker.changed = timePickerPropertyChanged
picker.set = picker.setFunc
picker.changed = picker.propertyChanged
}
func (picker *timePickerData) Focusable() bool {
@ -167,22 +167,22 @@ func stringToTime(value string) (time.Time, bool) {
return result, true
}
func timePickerSet(view View, tag PropertyName, value any) []PropertyName {
func (picker *timePickerData) setFunc(tag PropertyName, value any) []PropertyName {
setTimeValue := func(tag PropertyName) []PropertyName {
switch value := value.(type) {
case time.Time:
view.setRaw(tag, value)
picker.setRaw(tag, value)
return []PropertyName{tag}
case string:
if isConstantName(value) {
view.setRaw(tag, value)
picker.setRaw(tag, value)
return []PropertyName{tag}
}
if time, ok := stringToTime(value); ok {
view.setRaw(tag, time)
picker.setRaw(tag, time)
return []PropertyName{tag}
}
}
@ -199,67 +199,67 @@ func timePickerSet(view View, tag PropertyName, value any) []PropertyName {
return setTimeValue(TimePickerMax)
case TimePickerStep:
return setIntProperty(view, TimePickerStep, value)
return setIntProperty(picker, TimePickerStep, value)
case TimePickerValue:
view.setRaw("old-time", GetTimePickerValue(view))
picker.setRaw("old-time", GetTimePickerValue(picker))
return setTimeValue(tag)
case TimeChangedEvent:
return setEventWithOldListener[TimePicker, time.Time](view, tag, value)
return setTwoArgEventListener[TimePicker, time.Time](picker, tag, value)
case DataList:
return setDataList(view, value, timeFormat)
return setDataList(picker, value, timeFormat)
}
return viewSet(view, tag, value)
return picker.viewData.setFunc(tag, value)
}
func timePickerPropertyChanged(view View, tag PropertyName) {
func (picker *timePickerData) propertyChanged(tag PropertyName) {
session := view.Session()
session := picker.Session()
switch tag {
case TimePickerMin:
if time, ok := GetTimePickerMin(view); ok {
session.updateProperty(view.htmlID(), "min", time.Format(timeFormat))
if time, ok := GetTimePickerMin(picker); ok {
session.updateProperty(picker.htmlID(), "min", time.Format(timeFormat))
} else {
session.removeProperty(view.htmlID(), "min")
session.removeProperty(picker.htmlID(), "min")
}
case TimePickerMax:
if time, ok := GetTimePickerMax(view); ok {
session.updateProperty(view.htmlID(), "max", time.Format(timeFormat))
if time, ok := GetTimePickerMax(picker); ok {
session.updateProperty(picker.htmlID(), "max", time.Format(timeFormat))
} else {
session.removeProperty(view.htmlID(), "max")
session.removeProperty(picker.htmlID(), "max")
}
case TimePickerStep:
if step := GetTimePickerStep(view); step > 0 {
session.updateProperty(view.htmlID(), "step", strconv.Itoa(step))
if step := GetTimePickerStep(picker); step > 0 {
session.updateProperty(picker.htmlID(), "step", strconv.Itoa(step))
} else {
session.removeProperty(view.htmlID(), "step")
session.removeProperty(picker.htmlID(), "step")
}
case TimePickerValue:
value := GetTimePickerValue(view)
session.callFunc("setInputValue", view.htmlID(), value.Format(timeFormat))
value := GetTimePickerValue(picker)
session.callFunc("setInputValue", picker.htmlID(), value.Format(timeFormat))
if listeners := GetTimeChangedListeners(view); len(listeners) > 0 {
if listeners := GetTimeChangedListeners(picker); len(listeners) > 0 {
oldTime := time.Now()
if val := view.getRaw("old-time"); val != nil {
if val := picker.getRaw("old-time"); val != nil {
if time, ok := val.(time.Time); ok {
oldTime = time
}
}
for _, listener := range listeners {
listener(view, value, oldTime)
listener(picker, value, oldTime)
}
}
default:
viewPropertyChanged(view, tag)
picker.viewData.propertyChanged(tag)
}
}
@ -420,5 +420,5 @@ func GetTimePickerValue(view View, subviewID ...string) time.Time {
// 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 GetTimeChangedListeners(view View, subviewID ...string) []func(TimePicker, time.Time, time.Time) {
return getEventWithOldListeners[TimePicker, time.Time](view, subviewID, TimeChangedEvent)
return getTwoArgEventListeners[TimePicker, time.Time](view, subviewID, TimeChangedEvent)
}

View File

@ -144,7 +144,7 @@ type TouchEvent struct {
/*
func setTouchListener(properties Properties, tag PropertyName, value any) bool {
if listeners, ok := valueToEventListeners[View, TouchEvent](value); ok {
if listeners, ok := valueToOneArgEventListeners[View, TouchEvent](value); ok {
if len(listeners) == 0 {
properties.setRaw(tag, nil)
} else {
@ -215,7 +215,7 @@ func (event *TouchEvent) init(data DataObject) {
}
func handleTouchEvents(view View, tag PropertyName, data DataObject) {
listeners := getEventListeners[View, TouchEvent](view, nil, tag)
listeners := getOneArgEventListeners[View, TouchEvent](view, nil, tag)
if len(listeners) == 0 {
return
}
@ -231,23 +231,23 @@ func handleTouchEvents(view View, tag PropertyName, data DataObject) {
// GetTouchStartListeners returns the "touch-start" listener list. 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 GetTouchStartListeners(view View, subviewID ...string) []func(View, TouchEvent) {
return getEventListeners[View, TouchEvent](view, subviewID, TouchStart)
return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchStart)
}
// GetTouchEndListeners returns the "touch-end" listener list. 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 GetTouchEndListeners(view View, subviewID ...string) []func(View, TouchEvent) {
return getEventListeners[View, TouchEvent](view, subviewID, TouchEnd)
return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchEnd)
}
// GetTouchMoveListeners returns the "touch-move" listener list. 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 GetTouchMoveListeners(view View, subviewID ...string) []func(View, TouchEvent) {
return getEventListeners[View, TouchEvent](view, subviewID, TouchMove)
return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchMove)
}
// GetTouchCancelListeners returns the "touch-cancel" listener list. 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 GetTouchCancelListeners(view View, subviewID ...string) []func(View, TouchEvent) {
return getEventListeners[View, TouchEvent](view, subviewID, TouchCancel)
return getOneArgEventListeners[View, TouchEvent](view, subviewID, TouchCancel)
}

View File

@ -61,22 +61,22 @@ func newVideoPlayer(session Session) View {
func (player *videoPlayerData) init(session Session) {
player.mediaPlayerData.init(session)
player.tag = "VideoPlayer"
player.changed = videoPlayerPropertyChanged
player.changed = player.propertyChanged
}
func (player *videoPlayerData) htmlTag() string {
return "video"
}
func videoPlayerPropertyChanged(view View, tag PropertyName) {
func (player *videoPlayerData) propertyChanged(tag PropertyName) {
session := view.Session()
session := player.Session()
updateSize := func(cssTag string) {
if size, ok := floatTextProperty(view, tag, session, 0); ok {
if size, ok := floatTextProperty(player, tag, session, 0); ok {
if size != "0" {
session.updateProperty(view.htmlID(), cssTag, size)
session.updateProperty(player.htmlID(), cssTag, size)
} else {
session.removeProperty(view.htmlID(), cssTag)
session.removeProperty(player.htmlID(), cssTag)
}
}
}
@ -89,14 +89,14 @@ func videoPlayerPropertyChanged(view View, tag PropertyName) {
updateSize("height")
case Poster:
if url, ok := stringProperty(view, Poster, session); ok {
session.updateProperty(view.htmlID(), string(Poster), url)
if url, ok := stringProperty(player, Poster, session); ok {
session.updateProperty(player.htmlID(), string(Poster), url)
} else {
session.removeProperty(view.htmlID(), string(Poster))
session.removeProperty(player.htmlID(), string(Poster))
}
default:
mediaPlayerPropertyChanged(view, tag)
player.mediaPlayerData.propertyChanged(tag)
}
}

296
view.go
View File

@ -110,10 +110,10 @@ type viewData struct {
created bool
hasFocus bool
hasHtmlDisabled bool
getFunc func(view View, tag PropertyName) any
set func(view View, tag PropertyName, value any) []PropertyName
remove func(view View, tag PropertyName) []PropertyName
changed func(view View, tag PropertyName)
get func(tag PropertyName) any
set func(tag PropertyName, value any) []PropertyName
remove func(tag PropertyName) []PropertyName
changed func(tag PropertyName)
}
func newView(session Session) View {
@ -145,10 +145,11 @@ func setInitParams(view View, params Params) {
func (view *viewData) init(session Session) {
view.viewStyle.init()
view.getFunc = viewGet
view.set = viewSet
view.get = view.getFunc
view.set = view.setFunc
view.remove = view.removeFunc
view.normalize = normalizeViewTag
view.changed = viewPropertyChanged
view.changed = view.propertyChanged
view.tag = "View"
view.session = session
view.changeListener = map[PropertyName]func(View, PropertyName){}
@ -213,35 +214,11 @@ func (view *viewData) Focusable() bool {
}
func (view *viewData) Remove(tag PropertyName) {
tag = view.normalize(tag)
var changedTags []PropertyName = nil
switch tag {
case ID:
if view.viewID != "" {
view.viewID = ""
changedTags = []PropertyName{ID}
}
case AnimationTag:
if val := view.getRaw(AnimationTag); val != nil {
if animations, ok := val.([]Animation); ok {
for _, animation := range animations {
animation.unused(view.session)
}
}
view.setRaw(AnimationTag, nil)
changedTags = []PropertyName{AnimationTag}
}
default:
changedTags = view.remove(view, tag)
}
changedTags := view.removeFunc(view.normalize(tag))
if view.created && len(changedTags) > 0 {
for _, tag := range changedTags {
view.changed(view, tag)
view.changed(tag)
}
for _, tag := range changedTags {
@ -252,6 +229,15 @@ func (view *viewData) Remove(tag PropertyName) {
}
}
func (view *viewData) Get(tag PropertyName) any {
switch tag {
case ID:
return view.ID()
}
return view.get(view.normalize(tag))
}
func (view *viewData) Set(tag PropertyName, value any) bool {
if value == nil {
view.Remove(tag)
@ -259,42 +245,11 @@ func (view *viewData) Set(tag PropertyName, value any) bool {
}
tag = view.normalize(tag)
var changedTags []PropertyName = nil
switch tag {
case ID:
text, ok := value.(string)
if !ok {
notCompatibleType(ID, value)
return false
}
view.viewID = text
changedTags = []PropertyName{ID}
case AnimationTag:
oldAnimations := []Animation{}
if val := view.getRaw(AnimationTag); val != nil {
if animation, ok := val.([]Animation); ok {
oldAnimations = animation
}
}
if !setAnimationProperty(view, tag, value) {
return false
}
for _, animation := range oldAnimations {
animation.unused(view.session)
}
changedTags = []PropertyName{AnimationTag}
default:
changedTags = viewSet(view, tag, value)
}
changedTags := view.set(tag, value)
if view.created && len(changedTags) > 0 {
for _, tag := range changedTags {
view.changed(view, tag)
view.changed(tag)
}
for _, tag := range changedTags {
@ -316,67 +271,78 @@ func normalizeViewTag(tag PropertyName) PropertyName {
return tag
}
/*
func (view *viewData) propertyChangedEvent(tag PropertyName) {
if listener, ok := view.changeListener[tag]; ok {
listener(view, tag)
func (view *viewData) getFunc(tag PropertyName) any {
if tag == ID {
if id := view.ID(); id != "" {
return id
} else {
return nil
}
}
return viewStyleGet(view, tag)
}
func (view *viewData) removeFunc(tag PropertyName) []PropertyName {
var changedTags []PropertyName = nil
switch tag {
case BorderLeft, BorderRight, BorderTop, BorderBottom,
BorderStyle, BorderLeftStyle, BorderRightStyle, BorderTopStyle, BorderBottomStyle,
BorderColor, BorderLeftColor, BorderRightColor, BorderTopColor, BorderBottomColor,
BorderWidth, BorderLeftWidth, BorderRightWidth, BorderTopWidth, BorderBottomWidth:
tag = Border
case ID:
if view.viewID != "" {
view.viewID = ""
changedTags = []PropertyName{ID}
} else {
changedTags = []PropertyName{}
}
case CellBorderStyle, CellBorderColor, CellBorderWidth,
CellBorderLeft, CellBorderLeftStyle, CellBorderLeftColor, CellBorderLeftWidth,
CellBorderRight, CellBorderRightStyle, CellBorderRightColor, CellBorderRightWidth,
CellBorderTop, CellBorderTopStyle, CellBorderTopColor, CellBorderTopWidth,
CellBorderBottom, CellBorderBottomStyle, CellBorderBottomColor, CellBorderBottomWidth:
tag = CellBorder
case AnimationTag:
if val := view.getRaw(AnimationTag); val != nil {
if animations, ok := val.([]Animation); ok {
for _, animation := range animations {
animation.unused(view.session)
}
}
case OutlineColor, OutlineStyle, OutlineWidth:
tag = Outline
case RadiusX, RadiusY, RadiusTopLeft, RadiusTopLeftX, RadiusTopLeftY,
RadiusTopRight, RadiusTopRightX, RadiusTopRightY,
RadiusBottomLeft, RadiusBottomLeftX, RadiusBottomLeftY,
RadiusBottomRight, RadiusBottomRightX, RadiusBottomRightY:
tag = Radius
case MarginTop, MarginRight, MarginBottom, MarginLeft,
"top-margin", "right-margin", "bottom-margin", "left-margin":
tag = Margin
case PaddingTop, PaddingRight, PaddingBottom, PaddingLeft,
"top-padding", "right-padding", "bottom-padding", "left-padding":
tag = Padding
case CellPaddingTop, CellPaddingRight, CellPaddingBottom, CellPaddingLeft:
tag = CellPadding
case ColumnSeparatorStyle, ColumnSeparatorWidth, ColumnSeparatorColor:
tag = ColumnSeparator
view.setRaw(AnimationTag, nil)
changedTags = []PropertyName{AnimationTag}
}
default:
return
changedTags = viewStyleRemove(view, tag)
}
if listener, ok := view.changeListener[tag]; ok {
listener(view, tag)
}
}
*/
func viewRemove(properties Properties, tag PropertyName) []PropertyName {
return viewStyleRemove(properties, tag)
return changedTags
}
func viewSet(view View, tag PropertyName, value any) []PropertyName {
func (view *viewData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case ID:
if text, ok := value.(string); ok {
view.viewID = text
view.setRaw(ID, text)
return []PropertyName{ID}
}
notCompatibleType(ID, value)
return nil
case AnimationTag:
oldAnimations := []Animation{}
if val := view.getRaw(AnimationTag); val != nil {
if animation, ok := val.([]Animation); ok {
oldAnimations = animation
}
}
if !setAnimationProperty(view, tag, value) {
return nil
}
for _, animation := range oldAnimations {
animation.unused(view.session)
}
return []PropertyName{AnimationTag}
case TabIndex, "tab-index":
return setIntProperty(view, TabIndex, value)
@ -393,29 +359,46 @@ func viewSet(view View, tag PropertyName, value any) []PropertyName {
return nil
case FocusEvent, LostFocusEvent:
return setNoParamEventListener[View](view, tag, value)
return setNoArgEventListener[View](view, tag, value)
case KeyDownEvent, KeyUpEvent:
return setViewEventListener[View, KeyEvent](view, tag, value)
return setOneArgEventListener[View, KeyEvent](view, tag, value)
case ClickEvent, DoubleClickEvent, MouseDown, MouseUp, MouseMove, MouseOut, MouseOver, ContextMenuEvent:
return setViewEventListener[View, MouseEvent](view, tag, value)
return setOneArgEventListener[View, MouseEvent](view, tag, value)
case PointerDown, PointerUp, PointerMove, PointerOut, PointerOver, PointerCancel:
return setViewEventListener[View, PointerEvent](view, tag, value)
return setOneArgEventListener[View, PointerEvent](view, tag, value)
case TouchStart, TouchEnd, TouchMove, TouchCancel:
return setViewEventListener[View, TouchEvent](view, tag, value)
return setOneArgEventListener[View, TouchEvent](view, tag, value)
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent,
AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
return setViewEventListener[View, string](view, tag, value)
//return setTransitionListener(view, tag, value), tag
//return setAnimationListener(view, tag, value), tag
case TransitionRunEvent, TransitionStartEvent, TransitionEndEvent, TransitionCancelEvent:
result := setOneArgEventListener[View, PropertyName](view, tag, value)
if result == nil {
result = setOneArgEventListener[View, string](view, tag, value)
if result != nil {
if listeners, ok := view.getRaw(tag).([]func(View, string)); ok {
newListeners := make([]func(View, PropertyName), len(listeners))
for i, listener := range listeners {
newListeners[i] = func(view View, name PropertyName) {
listener(view, string(name))
}
}
view.setRaw(tag, newListeners)
return result
}
view.setRaw(tag, nil)
return nil
}
}
return result
case AnimationStartEvent, AnimationEndEvent, AnimationIterationEvent, AnimationCancelEvent:
return setOneArgEventListener[View, string](view, tag, value)
case ResizeEvent, ScrollEvent:
return setViewEventListener[View, Frame](view, tag, value)
//return setFrameListener(view, tag, value), tag
return setOneArgEventListener[View, Frame](view, tag, value)
}
return viewStyleSet(view, tag, value)
@ -439,12 +422,7 @@ func (view *viewData) SetParams(params Params) bool {
return result
}
func viewPropertyChanged(view View, tag PropertyName) {
/*
if view.updateTransformProperty(tag) {
return
}
*/
func (view *viewData) propertyChanged(tag PropertyName) {
htmlID := view.htmlID()
session := view.Session()
@ -645,9 +623,11 @@ func viewPropertyChanged(view View, tag PropertyName) {
case Strikethrough, Overline, Underline:
session.updateCSSProperty(htmlID, "text-decoration", textDecorationCSS(view, session))
for _, tag2 := range []PropertyName{TextLineColor, TextLineStyle, TextLineThickness} {
viewPropertyChanged(view, tag2)
}
/*
for _, tag2 := range []PropertyName{TextLineColor, TextLineStyle, TextLineThickness} {
view.propertyChanged(tag2)
}
*/
case Transition:
session.updateCSSProperty(htmlID, "transition", transitionCSS(view, session))
@ -711,34 +691,19 @@ func viewPropertyChanged(view View, tag PropertyName) {
}
case PerspectiveOriginX, PerspectiveOriginY:
if getTransform3D(view, session) {
x, y := GetPerspectiveOrigin(view)
value := ""
if x.Type != Auto || y.Type != Auto {
value = x.cssString("50%", session) + " " + y.cssString("50%", session)
}
session.updateCSSProperty(htmlID, "perspective-origin", value)
}
x, y := GetPerspectiveOrigin(view)
session.updateCSSProperty(htmlID, "perspective-origin", transformOriginCSS(x, y, AutoSize(), view.Session()))
case BackfaceVisible:
if getTransform3D(view, session) {
if GetBackfaceVisible(view) {
session.updateCSSProperty(htmlID, string(BackfaceVisible), "visible")
} else {
session.updateCSSProperty(htmlID, string(BackfaceVisible), "hidden")
}
if GetBackfaceVisible(view) {
session.updateCSSProperty(htmlID, string(BackfaceVisible), "visible")
} else {
session.updateCSSProperty(htmlID, string(BackfaceVisible), "hidden")
}
case OriginX, OriginY, OriginZ:
x, y, z := getOrigin(view, session)
value := ""
if z.Type != Auto {
value = x.cssString("50%", session) + " " + y.cssString("50%", session) + " " + z.cssString("50%", session)
} else if x.Type != Auto || y.Type != Auto {
value = x.cssString("50%", session) + " " + y.cssString("50%", session)
}
session.updateCSSProperty(htmlID, "transform-origin", value)
case TransformOriginX, TransformOriginY, TransformOriginZ:
x, y, z := getTransformOrigin(view, session)
session.updateCSSProperty(htmlID, "transform-origin", transformOriginCSS(x, y, z, view.Session()))
case TransformTag, Perspective, SkewX, SkewY, TranslateX, TranslateY, TranslateZ,
ScaleX, ScaleY, ScaleZ, Rotate, RotateX, RotateY, RotateZ:
@ -803,17 +768,6 @@ func viewPropertyChanged(view View, tag PropertyName) {
}
}
func viewGet(view View, tag PropertyName) any {
if tag == ID {
if id := view.ID(); id != "" {
return id
} else {
return nil
}
}
return viewStyleGet(view, tag)
}
func (view *viewData) htmlTag() string {
if semantics := GetSemantics(view); semantics > DefaultSemantics {
values := enumProperties[Semantics].cssValues
@ -999,13 +953,13 @@ func (view *viewData) handleCommand(self View, command PropertyName, data DataOb
case FocusEvent:
view.hasFocus = true
for _, listener := range getNoParamEventListeners[View](view, nil, command) {
for _, listener := range getNoArgEventListeners[View](view, nil, command) {
listener(self)
}
case LostFocusEvent:
view.hasFocus = false
for _, listener := range getNoParamEventListeners[View](view, nil, command) {
for _, listener := range getNoArgEventListeners[View](view, nil, command) {
listener(self)
}

View File

@ -497,6 +497,16 @@ func normalizeViewStyleTag(tag PropertyName) PropertyName {
case "left-padding":
return PaddingLeft
case "origin-x":
return TransformOriginX
case "origin-y":
return TransformOriginY
case "origin-z":
return TransformOriginZ
}
return tag
}
@ -868,7 +878,8 @@ func writeViewStyle(name string, view Properties, buffer *strings.Builder, inden
}
finalTags := []PropertyName{
Perspective, PerspectiveOriginX, PerspectiveOriginY, BackfaceVisible, OriginX, OriginY, OriginZ,
PerspectiveOriginX, PerspectiveOriginY, BackfaceVisible,
TransformOriginX, TransformOriginY, TransformOriginZ,
TransformTag, Clip, Filter, BackdropFilter, Summary, Content, Transition}
for _, tag := range finalTags {
removeTag(tag)

View File

@ -79,7 +79,7 @@ const (
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
OriginX PropertyName = "origin-x"
TransformOriginX PropertyName = "transform-origin-x"
// OriginY is the constant for "origin-y" property tag.
//
@ -90,7 +90,7 @@ const (
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
OriginY PropertyName = "origin-y"
TransformOriginY PropertyName = "transform-origin-y"
// OriginZ is the constant for "origin-z" property tag.
//
@ -101,7 +101,7 @@ const (
//
// Internal type is `SizeUnit`, other types converted to it during assignment.
// See `SizeUnit` description for more details.
OriginZ PropertyName = "origin-z"
TransformOriginZ PropertyName = "transform-origin-z"
// TranslateX is the constant for "translate-x" property tag.
//
@ -527,29 +527,31 @@ func getTransformProperty(properties Properties) Transform {
func setTransformPropertyElement(properties Properties, tag PropertyName, value any) []PropertyName {
switch tag {
case Perspective, RotateX, RotateY, RotateZ, Rotate, SkewX, SkewY, ScaleX, ScaleY, ScaleZ, TranslateX, TranslateY, TranslateZ:
var result []PropertyName = nil
if transform := getTransformProperty(properties); transform != nil {
if result := transformSet(transform, tag, value); result != nil {
if result = transformSet(transform, tag, value); result != nil {
result = append(result, TransformTag)
}
} else {
transform := NewTransform(nil)
if result := transformSet(transform, tag, value); result != nil {
if result = transformSet(transform, tag, value); result != nil {
properties.setRaw(TransformTag, transform)
result = append(result, TransformTag)
}
}
default:
ErrorLogF(`"Transform" interface does not support the "%s" property`, tag)
return result
}
ErrorLogF(`"Transform" interface does not support the "%s" property`, tag)
return nil
}
/*
func getTransform3D(style Properties, session Session) bool {
perspective, ok := sizeProperty(style, Perspective, session)
return ok && perspective.Type != Auto && perspective.Value != 0
}
*/
func getPerspectiveOrigin(style Properties, session Session) (SizeUnit, SizeUnit) {
x, _ := sizeProperty(style, PerspectiveOriginX, session)
@ -557,10 +559,10 @@ func getPerspectiveOrigin(style Properties, session Session) (SizeUnit, SizeUnit
return x, y
}
func getOrigin(style Properties, session Session) (SizeUnit, SizeUnit, SizeUnit) {
x, _ := sizeProperty(style, OriginX, session)
y, _ := sizeProperty(style, OriginY, session)
z, _ := sizeProperty(style, OriginZ, session)
func getTransformOrigin(style Properties, session Session) (SizeUnit, SizeUnit, SizeUnit) {
x, _ := sizeProperty(style, TransformOriginX, session)
y, _ := sizeProperty(style, TransformOriginY, session)
z, _ := sizeProperty(style, TransformOriginZ, session)
return x, y, z
}
@ -674,8 +676,9 @@ func (transform *transformData) transformCSS(session Session) string {
func (style *viewStyle) writeViewTransformCSS(builder cssBuilder, session Session) {
x, y := getPerspectiveOrigin(style, session)
if x.Type != Auto || y.Type != Auto {
builder.addValues(`perspective-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session))
z := AutoSize()
if css := transformOriginCSS(x, y, z, session); css != "" {
builder.add(`perspective-origin`, css)
}
if backfaceVisible, ok := boolProperty(style, BackfaceVisible, session); ok {
@ -686,11 +689,9 @@ func (style *viewStyle) writeViewTransformCSS(builder cssBuilder, session Sessio
}
}
x, y, z := getOrigin(style, session)
if z.Type != Auto && z.Value != 0 {
builder.addValues(`transform-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session), z.cssString("0", session))
} else if x.Type != Auto || y.Type != Auto {
builder.addValues(`transform-origin`, ` `, x.cssString("50%", session), y.cssString("50%", session))
x, y, z = getTransformOrigin(style, session)
if css := transformOriginCSS(x, y, z, session); css != "" {
builder.add(`transform-origin`, css)
}
if transform := getTransformProperty(style); transform != nil {
@ -698,6 +699,56 @@ func (style *viewStyle) writeViewTransformCSS(builder cssBuilder, session Sessio
}
}
func transformOriginCSS(x, y, z SizeUnit, session Session) string {
if z.Type == Auto && x.Type == Auto && y.Type == Auto {
return ""
}
buffer := allocStringBuilder()
defer freeStringBuilder(buffer)
if x.Type == SizeInPercent {
switch x.Value {
case 0:
buffer.WriteString("left")
case 50:
buffer.WriteString("center")
case 100:
buffer.WriteString("right")
default:
buffer.WriteString(x.cssString("center", session))
}
} else {
buffer.WriteString(x.cssString("center", session))
}
buffer.WriteRune(' ')
if y.Type == SizeInPercent {
switch y.Value {
case 0:
buffer.WriteString("top")
case 50:
buffer.WriteString("center")
case 100:
buffer.WriteString("bottom")
default:
buffer.WriteString(y.cssString("center", session))
}
} else {
buffer.WriteString(y.cssString("center", session))
}
if z.Type != Auto && z.Value != 0 {
buffer.WriteRune(' ')
buffer.WriteString(z.cssString("0", session))
}
return buffer.String()
}
/*
func (view *viewData) updateTransformProperty(tag PropertyName) bool {
htmlID := view.htmlID()

View File

@ -613,17 +613,17 @@ func GetBackfaceVisible(view View, subviewID ...string) bool {
return boolStyledProperty(view, subviewID, BackfaceVisible, false)
}
// GetOrigin returns a x-, y-, and z-coordinate of the point around which a view transformation is applied.
// GetTransformOrigin returns a x-, y-, and z-coordinate of the point around which a view transformation is applied.
// The default value is (50%, 50%, 50%).
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit) {
func GetTransformOrigin(view View, subviewID ...string) (SizeUnit, SizeUnit, SizeUnit) {
if len(subviewID) > 0 && subviewID[0] != "" {
view = ViewByID(view, subviewID[0])
}
if view == nil {
return AutoSize(), AutoSize(), AutoSize()
}
return getOrigin(view, view.Session())
return getTransformOrigin(view, view.Session())
}
// GetTranslate returns a x-, y-, and z-axis translation value of a 2D/3D translation

View File

@ -38,10 +38,10 @@ func (container *viewsContainerData) init(session Session) {
container.viewData.init(session)
container.tag = "ViewsContainer"
container.views = []View{}
container.getFunc = container.get
container.get = container.getFunc
container.set = container.setFunc
container.remove = container.removeFunc
container.changed = viewsContainerPropertyChanged
container.changed = container.propertyChanged
}
func (container *viewsContainerData) setParentID(parentID string) {
@ -163,7 +163,7 @@ func viewFromTextValue(text string, session Session) View {
return NewTextView(session, Params{Text: text})
}
func (container *viewsContainerData) removeFunc(view View, tag PropertyName) []PropertyName {
func (container *viewsContainerData) removeFunc(tag PropertyName) []PropertyName {
switch tag {
case Content:
if len(container.views) > 0 {
@ -173,18 +173,18 @@ func (container *viewsContainerData) removeFunc(view View, tag PropertyName) []P
return []PropertyName{}
case Disabled:
if view.getRaw(Disabled) != nil {
view.setRaw(Disabled, nil)
if container.getRaw(Disabled) != nil {
container.setRaw(Disabled, nil)
for _, view := range container.views {
view.Remove(Disabled)
}
return []PropertyName{tag}
}
}
return viewRemove(view, tag)
return container.viewData.removeFunc(tag)
}
func (container *viewsContainerData) setFunc(self View, tag PropertyName, value any) []PropertyName {
func (container *viewsContainerData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Content:
if container.setContent(value) {
@ -194,7 +194,7 @@ func (container *viewsContainerData) setFunc(self View, tag PropertyName, value
case Disabled:
oldDisabled := IsDisabled(container)
result := viewSet(self, Disabled, value)
result := container.viewData.setFunc(Disabled, value)
if result != nil {
disabled := IsDisabled(container)
if oldDisabled != disabled {
@ -206,16 +206,16 @@ func (container *viewsContainerData) setFunc(self View, tag PropertyName, value
return result
}
return viewSet(self, tag, value)
return container.viewData.setFunc(tag, value)
}
func viewsContainerPropertyChanged(view View, tag PropertyName) {
func (container *viewsContainerData) propertyChanged(tag PropertyName) {
switch tag {
case Content:
updateInnerHTML(view.htmlID(), view.Session())
updateInnerHTML(container.htmlID(), container.Session())
default:
viewPropertyChanged(view, tag)
container.viewData.propertyChanged(tag)
}
}
@ -292,13 +292,13 @@ func (container *viewsContainerData) setContent(value any) bool {
return true
}
func (container *viewsContainerData) get(view View, tag PropertyName) any {
func (container *viewsContainerData) getFunc(tag PropertyName) any {
switch tag {
case Content:
return container.views
default:
return viewGet(view, tag)
return container.viewData.getFunc(tag)
}
}