Added "mod", "rem", "round", "round-up", "round-down", and "round-to-zero" SizeFunc functions

This commit is contained in:
Alexei Anoshenko 2024-06-26 18:45:47 +03:00
parent d1d8c2af37
commit 00d6e2379d
4 changed files with 172 additions and 20 deletions

View File

@ -1,3 +1,7 @@
# v0.17.0
* Added "mod", "rem", "round", "round-up", "round-down", and "round-to-zero" SizeFunc functions
* Added ModSize, RemSize, RoundSize, RoundUpSize, RoundDownSize, and RoundToZeroSize functions
# v0.16.0
* Can use ListAdapter as "content" property value of ListLayout
* The IsListItemEnabled method of the ListAdapter interface has been made optional

View File

@ -161,6 +161,12 @@ SizeUnit объявлена как
| "sub(<arg1>, <arg2>)" | SubSize(arg0, arg1 any) | находит разность значений аргументов |
| "mul(<arg1>, <arg2>)" | MulSize(arg0, arg1 any) | находит результат умножения значений аргументов |
| "div(<arg1>, <arg2>)" | DivSize(arg0, arg1 any) | находит результат деления значений аргументов |
| "rem(<arg1>, <arg2>)" | ModSize(arg0, arg1 any) | находит остаток деления значений аргументов, результат имеет тотже знак что и делимое |
| "mod(<arg1>, <arg2>)" | ModSize(arg0, arg1 any) | находит остаток деления значений аргументов, результат имеет тотже знак что и делитель |
| "round(<arg1>, <arg2>)" | RoundSize(arg0, arg1 any) | округляет первый аргумент до ближайшего целого числа кратного второму аргументу |
| "round-up(<arg1>, <arg2>)" | RoundUpSize(arg0, arg1 any) | округляет первый аргумент до ближайшего большего целого числа, кратного второму аргументу |
| "round-down(<arg1>, <arg2>)" | RoundDownSize(arg0, arg1 any) | округляет первый аргумент до ближайшего меньшего целого числа кратного второму аргументу |
| "round-to-zero(<arg1>, <arg2>)" | RoundToZeroSize(arg0, arg1 any) | округляет первый аргумент до ближайшего целого числа кратного второму аргументу, которое ближе к нулю по сравнению с первым аргументом |
| "clamp(<min>, <val>, <max>)" | ClampSize(min, val, max any) | ограничивает значение заданным диапазоном |
Дополнительные пояснения к функции "clamp(<min>, <val>, <max>)": результат вычисляется следующим образом:
@ -169,6 +175,17 @@ SizeUnit объявлена как
* if val < min then min;
* if max < val then max;
Аргументы всех функций могут иметь следующий тип:
* SizeUnit;
* SizeFunc;
* string являющееся SizeUnit константой или текстовым представлением SizeUnit или SizeFunc.
Кроме этого второй аргумент функций mul, div, mod, rem и всех round может быть числом
(float32, float32, int, int8...int64, uint, uint8...unit64).
Также второй аргумент функций div, mod, rem и всех round не может быть нулевым значением.
### Color
Тип Color описывает 32-битный цвет в формате ARGB:

View File

@ -164,6 +164,12 @@ In addition to "min", there are the following functions
| "sub(<arg1>, <arg2>)" | SubSize(arg0, arg1 any) | calculates the subtraction of argument values |
| "mul(<arg1>, <arg2>)" | MulSize(arg0, arg1 any) | calculates the result of multiplying the argument values |
| "div(<arg1>, <arg2>)" | DivSize(arg0, arg1 any) | calculates the result of dividing the argument values |
| "rem(<arg1>, <arg2>)" | ModSize(arg0, arg1 any) | calculates the remainder of a division operation with the same sign as the dividend |
| "mod(<arg1>, <arg2>)" | ModSize(arg0, arg1 any) | calculates the remainder of a division operation with the same sign as the divisor |
| "round(<arg1>, <arg2>)" | RoundSize(arg0, arg1 any) | rounds the first argument to the nearest integer multiple of the second argument, which may be either above or below the value. |
| "round-up(<arg1>, <arg2>)" | RoundUpSize(arg0, arg1 any) | rounds the first argument up to the nearest integer multiple of the second argument (if the value is negative, it will become "more positive") |
| "round-down(<arg1>, <arg2>)" | RoundDownSize(arg0, arg1 any) | rounds the first argument down to the nearest integer multiple of the second argument (if the value is negative, it will become "more negative") |
| "round-to-zero(<arg1>, <arg2>)" | RoundToZeroSize(arg0, arg1 any) | rounds the first argument to the nearest integer multiple of the second argument closer to/towards zero (a positive number will decrease, while a negative value will become "less negative") |
| "clamp(<min>, <val>, <max>)" | ClampSize(min, val, max any) | limits value to specified range |
Additional explanations for the function "clamp(<min>, <val>, <max>)": the result is calculated as follows:
@ -172,6 +178,17 @@ Additional explanations for the function "clamp(<min>, <val>, <max>)": the resul
* if val < min then min;
* if max < val then max;
The arguments of all functions can be of the following type:
* SizeUnit;
* SizeFunc;
* string being a SizeUnit constant or a text representation of SizeUnit or SizeFunc.
In addition, the second argument of the functions mul, div, mod, rem, and all round can be a number
(float32, float32, int, int8...int64, uint, uint8...unit64).
Also, the second argument of the div, mod, rem, and all round functions cannot be a zero value.
### Color
The Color type describes a 32-bit ARGB color:

View File

@ -8,10 +8,12 @@ import (
// SizeFunc describes a function that calculates the SizeUnit size.
// Used as the value of the SizeUnit properties.
// "min", "max", "clamp", "sum", "sub", "mul", and "div" functions are available.
// "min", "max", "clamp", "sum", "sub", "mul", "div", mod,
// "round", "round-up", "round-down" and "round-to-zero" functions are available.
type SizeFunc interface {
fmt.Stringer
// Name() returns the function name: "min", "max", "clamp", "sum", "sub", "mul", or "div"
// Name() returns the function name: "min", "max", "clamp", "sum", "sub", "mul",
// "div", "mod", "rem", "round", "round-up", "round-down" or "round-to-zero"
Name() string
// Args() returns a list of function arguments
Args() []any
@ -28,7 +30,9 @@ type sizeFuncData struct {
func parseSizeFunc(text string) SizeFunc {
text = strings.Trim(text, " ")
for _, tag := range []string{"min", "max", "sum", "sub", "mul", "div", "clamp"} {
for _, tag := range []string{
"min", "max", "sum", "sub", "mul", "div", "mod", "rem", "clamp",
"round-up", "round-down", "round-to-zero", "round"} {
if strings.HasPrefix(text, tag) {
text = strings.Trim(strings.TrimPrefix(text, tag), " ")
last := len(text) - 1
@ -59,7 +63,7 @@ func parseSizeFunc(text string) SizeFunc {
args = append(args, text[start:])
switch tag {
case "sub", "mul", "div":
case "sub", "mul", "div", "mod", "rem", "round-up", "round-down", "round-to-zero", "round":
if len(args) != 2 {
ErrorLogF(`"%s" function needs 2 arguments`, tag)
return nil
@ -73,7 +77,9 @@ func parseSizeFunc(text string) SizeFunc {
data := new(sizeFuncData)
data.tag = tag
if data.parseArgs(args, tag == "mul" || tag == "div") {
if data.parseArgs(args, tag == "mul" || tag == "div" || tag == "mod" ||
tag == "rem" || tag == "round-up" || tag == "round-down" ||
tag == "round-to-zero" || tag == "round") {
return data
}
}
@ -92,19 +98,25 @@ func (data *sizeFuncData) parseArgs(args []any, allowNumber bool) bool {
numberArg := func(index int, value float64) bool {
if allowNumber {
if index == 1 {
if value == 0 && data.tag == "div" {
ErrorLog(`Division by 0 in div function`)
return false
if value == 0 {
if data.tag == "div" || data.tag == "mod" {
ErrorLogF(`Division by 0 in "%s" function`, data.tag)
return false
}
if data.tag == "round" || data.tag == "round-up" ||
data.tag == "round-down" || data.tag == "round-to-zero" {
ErrorLogF(`The rounding interval is 0 in "%s" function`, data.tag)
return false
}
}
data.args = append(data.args, value)
return true
} else {
ErrorLogF(`Only the second %s function argument can be a number`, data.tag)
return false
}
} else {
ErrorLogF(`The %s function argument can't be a number`, data.tag)
}
ErrorLogF(`The %s function argument can't be a number`, data.tag)
return false
}
@ -219,7 +231,7 @@ func (data *sizeFuncData) writeCSS(topFunc string, buffer *strings.Builder, sess
case "":
buffer.WriteString("calc(")
case "min", "max", "clamp":
case "min", "max", "clamp", "mod", "rem", "round", "round-up", "round-down", "round-to-zero":
bracket = false
default:
@ -228,10 +240,22 @@ func (data *sizeFuncData) writeCSS(topFunc string, buffer *strings.Builder, sess
}
switch data.tag {
case "min", "max", "clamp":
case "min", "max", "clamp", "mod", "rem":
buffer.WriteString(data.tag)
buffer.WriteRune('(')
case "round":
buffer.WriteString("round(nearest, ")
case "round-up":
buffer.WriteString("round(up, ")
case "round-down":
buffer.WriteString("round(down, ")
case "round-to-zero":
buffer.WriteString("round(to-zero, ")
case "sum":
mathFunc(" + ")
@ -287,7 +311,7 @@ func (data *sizeFuncData) writeCSS(topFunc string, buffer *strings.Builder, sess
}
// MaxSize creates a SizeUnit function that calculates the maximum argument.
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc
func MaxSize(arg0, arg1 any, args ...any) SizeFunc {
data := new(sizeFuncData)
data.tag = "max"
@ -298,7 +322,7 @@ func MaxSize(arg0, arg1 any, args ...any) SizeFunc {
}
// MinSize creates a SizeUnit function that calculates the minimum argument.
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
func MinSize(arg0, arg1 any, args ...any) SizeFunc {
data := new(sizeFuncData)
data.tag = "min"
@ -309,7 +333,7 @@ func MinSize(arg0, arg1 any, args ...any) SizeFunc {
}
// SumSize creates a SizeUnit function that calculates the sum of arguments.
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
func SumSize(arg0, arg1 any, args ...any) SizeFunc {
data := new(sizeFuncData)
data.tag = "sum"
@ -320,7 +344,7 @@ func SumSize(arg0, arg1 any, args ...any) SizeFunc {
}
// SumSize creates a SizeUnit function that calculates the result of subtracting the arguments (arg1 - arg2).
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
func SubSize(arg0, arg1 any) SizeFunc {
data := new(sizeFuncData)
data.tag = "sub"
@ -331,7 +355,7 @@ func SubSize(arg0, arg1 any) SizeFunc {
}
// MulSize creates a SizeUnit function that calculates the result of multiplying the arguments (arg1 * arg2).
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// The second argument can also be a number (float32, float32, int, int8...int64, uint, uint8...unit64)
// or a string which is a text representation of a number.
func MulSize(arg0, arg1 any) SizeFunc {
@ -344,7 +368,7 @@ func MulSize(arg0, arg1 any) SizeFunc {
}
// DivSize creates a SizeUnit function that calculates the result of dividing the arguments (arg1 / arg2).
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// The second argument can also be a number (float32, float32, int, int8...int64, uint, uint8...unit64)
// or a string which is a text representation of a number.
func DivSize(arg0, arg1 any) SizeFunc {
@ -356,13 +380,103 @@ func DivSize(arg0, arg1 any) SizeFunc {
return data
}
// RemSize creates a SizeUnit function that calculates the remainder of a division operation
// with the same sign as the dividend (arg1 % arg2).
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// The second argument can also be a number (float32, float32, int, int8...int64, uint, uint8...unit64)
// or a string which is a text representation of a number.
func RemSize(arg0, arg1 any) SizeFunc {
data := new(sizeFuncData)
data.tag = "rem"
if !data.parseArgs([]any{arg0, arg1}, true) {
return nil
}
return data
}
// ModSize creates a SizeUnit function that calculates the remainder of a division operation
// with the same sign as the divisor (arg1 % arg2).
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// The second argument can also be a number (float32, float32, int, int8...int64, uint, uint8...unit64)
// or a string which is a text representation of a number.
func ModSize(arg0, arg1 any) SizeFunc {
data := new(sizeFuncData)
data.tag = "mod"
if !data.parseArgs([]any{arg0, arg1}, true) {
return nil
}
return data
}
// RoundSize creates a SizeUnit function that calculates a rounded number.
// The function rounds valueToRound (first argument) to the nearest integer multiple
// of roundingInterval (second argument), which may be either above or below the value.
// If the valueToRound is half way between the rounding targets above and below (neither is "nearest"), it will be rounded up.
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// The second argument can also be a number (float32, float32, int, int8...int64, uint, uint8...unit64)
// or a string which is a text representation of a number.
func RoundSize(valueToRound, roundingInterval any) SizeFunc {
data := new(sizeFuncData)
data.tag = "round"
if !data.parseArgs([]any{valueToRound, roundingInterval}, true) {
return nil
}
return data
}
// RoundUpSize creates a SizeUnit function that calculates a rounded number.
// The function rounds valueToRound (first argument) up to the nearest integer multiple
// of roundingInterval (second argument) (if the value is negative, it will become "more positive").
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// The second argument can also be a number (float32, float32, int, int8...int64, uint, uint8...unit64)
// or a string which is a text representation of a number.
func RoundUpSize(valueToRound, roundingInterval any) SizeFunc {
data := new(sizeFuncData)
data.tag = "round-up"
if !data.parseArgs([]any{valueToRound, roundingInterval}, true) {
return nil
}
return data
}
// RoundDownSize creates a SizeUnit function that calculates a rounded number.
// The function rounds valueToRound (first argument) down to the nearest integer multiple
// of roundingInterval (second argument) (if the value is negative, it will become "more negative").
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// The second argument can also be a number (float32, float32, int, int8...int64, uint, uint8...unit64)
// or a string which is a text representation of a number.
func RoundDownSize(valueToRound, roundingInterval any) SizeFunc {
data := new(sizeFuncData)
data.tag = "round-down"
if !data.parseArgs([]any{valueToRound, roundingInterval}, true) {
return nil
}
return data
}
// RoundToZeroSize creates a SizeUnit function that calculates a rounded number.
// The function rounds valueToRound (first argument) to the nearest integer multiple
// of roundingInterval (second argument), which may be either above or below the value.
// If the valueToRound is half way between the rounding targets above and below.
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// The second argument can also be a number (float32, float32, int, int8...int64, uint, uint8...unit64)
// or a string which is a text representation of a number.
func RoundToZeroSize(valueToRound, roundingInterval any) SizeFunc {
data := new(sizeFuncData)
data.tag = "round-to-zero"
if !data.parseArgs([]any{valueToRound, roundingInterval}, true) {
return nil
}
return data
}
// ClampSize creates a SizeUnit function whose the result is calculated as follows:
//
// min ≤ value ≤ max -> value;
// value < min -> min;
// max < value -> max;
//
// Valid argument types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
// Valid arguments types are SizeUnit, SizeFunc and a string which is a text description of SizeUnit or SizeFunc.
func ClampSize(min, value, max any) SizeFunc {
data := new(sizeFuncData)
data.tag = "clamp"