From 00d6e2379d0354735e42bab5f086db8f2c45b98a Mon Sep 17 00:00:00 2001 From: Alexei Anoshenko Date: Wed, 26 Jun 2024 18:45:47 +0300 Subject: [PATCH] Added "mod", "rem", "round", "round-up", "round-down", and "round-to-zero" SizeFunc functions --- CHANGELOG.md | 4 ++ README-ru.md | 17 ++++++ README.md | 17 ++++++ sizeFunc.go | 154 ++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 172 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcafcc0..536f15c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README-ru.md b/README-ru.md index 89eeb54..11a5653 100644 --- a/README-ru.md +++ b/README-ru.md @@ -161,6 +161,12 @@ SizeUnit объявлена как | "sub(, )" | SubSize(arg0, arg1 any) | находит разность значений аргументов | | "mul(, )" | MulSize(arg0, arg1 any) | находит результат умножения значений аргументов | | "div(, )" | DivSize(arg0, arg1 any) | находит результат деления значений аргументов | +| "rem(, )" | ModSize(arg0, arg1 any) | находит остаток деления значений аргументов, результат имеет тотже знак что и делимое | +| "mod(, )" | ModSize(arg0, arg1 any) | находит остаток деления значений аргументов, результат имеет тотже знак что и делитель | +| "round(, )" | RoundSize(arg0, arg1 any) | округляет первый аргумент до ближайшего целого числа кратного второму аргументу | +| "round-up(, )" | RoundUpSize(arg0, arg1 any) | округляет первый аргумент до ближайшего большего целого числа, кратного второму аргументу | +| "round-down(, )" | RoundDownSize(arg0, arg1 any) | округляет первый аргумент до ближайшего меньшего целого числа кратного второму аргументу | +| "round-to-zero(, )" | RoundToZeroSize(arg0, arg1 any) | округляет первый аргумент до ближайшего целого числа кратного второму аргументу, которое ближе к нулю по сравнению с первым аргументом | | "clamp(, , )" | ClampSize(min, val, max any) | ограничивает значение заданным диапазоном | Дополнительные пояснения к функции "clamp(, , )": результат вычисляется следующим образом: @@ -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: diff --git a/README.md b/README.md index ddb0fad..88f70b6 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,12 @@ In addition to "min", there are the following functions | "sub(, )" | SubSize(arg0, arg1 any) | calculates the subtraction of argument values | | "mul(, )" | MulSize(arg0, arg1 any) | calculates the result of multiplying the argument values | | "div(, )" | DivSize(arg0, arg1 any) | calculates the result of dividing the argument values | +| "rem(, )" | ModSize(arg0, arg1 any) | calculates the remainder of a division operation with the same sign as the dividend | +| "mod(, )" | ModSize(arg0, arg1 any) | calculates the remainder of a division operation with the same sign as the divisor | +| "round(, )" | 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(, )" | 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(, )" | 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(, )" | 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(, , )" | ClampSize(min, val, max any) | limits value to specified range | Additional explanations for the function "clamp(, , )": the result is calculated as follows: @@ -172,6 +178,17 @@ Additional explanations for the function "clamp(, , )": 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: diff --git a/sizeFunc.go b/sizeFunc.go index ff9bab5..8b80666 100644 --- a/sizeFunc.go +++ b/sizeFunc.go @@ -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"