forked from mbk-lab/rui_orig
Added the background conic gradient
This commit is contained in:
parent
371079e27b
commit
86271a3c6e
67
README-ru.md
67
README-ru.md
|
@ -990,16 +990,16 @@ RadiusProperty, а не структура BoxRadius. Получить стру
|
|||
Может принимать или значение типа AngleUnit (угол наклона линии относительно вертикали)
|
||||
или одно из следующих значений типа Int:
|
||||
|
||||
| Значение | Константа | Имя | Описание |
|
||||
|:--------:|-----------------------|-------------------|------------------------------------------------|
|
||||
| 0 | ToTopGradient | "to-top" | Линия идет снизу вверх (значение по умолчанию) |
|
||||
| 1 | ToRightTopGradient | "to-right-top" | Из левого нижнего угла в правый верхний |
|
||||
| 2 | ToRightGradient | "to-right" | Слева направо |
|
||||
| 3 | ToRightBottomGradient | "to-right-bottom" | Из левого верхнего угла в правый нижний |
|
||||
| 4 | ToBottomGradient | "to-bottom" | Сверху вних |
|
||||
| 5 | ToLeftBottomGradient | "to-left-bottom" | Из правого верхнего угла в левый нижний |
|
||||
| 6 | ToLeftGradient | "to-left" | Справа налево |
|
||||
| 7 | ToLeftTopGradient | "to-left-top" | Из правого нижнего угла в левый верхний |
|
||||
| Значение | Константа | Имя | Описание |
|
||||
|:--------:|-----------------------|-------------------|-----------------------------------------|
|
||||
| 0 | ToTopGradient | "to-top" | Линия идет снизу вверх |
|
||||
| 1 | ToRightTopGradient | "to-right-top" | Из левого нижнего угла в правый верхний |
|
||||
| 2 | ToRightGradient | "to-right" | Слева направо |
|
||||
| 3 | ToRightBottomGradient | "to-right-bottom" | Из левого верхнего угла в правый нижний |
|
||||
| 4 | ToBottomGradient | "to-bottom" | Сверху вниз (значение по умолчанию) |
|
||||
| 5 | ToLeftBottomGradient | "to-left-bottom" | Из правого верхнего угла в левый нижний |
|
||||
| 6 | ToLeftGradient | "to-left" | Справа налево |
|
||||
| 7 | ToLeftTopGradient | "to-left-top" | Из правого нижнего угла в левый верхний |
|
||||
|
||||
* Gradient ("gradient") - массив ключевых точек градиента (обязательный параметр). Каждая точка
|
||||
описывается структурой BackgroundGradientPoint, которая имеет два поля: Pos типа SizeUnit и Color.
|
||||
|
@ -1010,12 +1010,12 @@ Pos определяет положение точки относительно
|
|||
Элементами этого массива могут быть BackgroundGradientPoint, Color, текстовое представление BackgroundGradientPoint
|
||||
или Color и имя константы
|
||||
|
||||
* Repeat ("repeat") - булево значение, определяющее будет ли повторяться градиент после последней
|
||||
* Repeating ("repeating") - булево значение, определяющее будет ли повторяться градиент после последней
|
||||
ключевой точки. Необязательный параметр. Значение по умолчанию - false (не повторять)
|
||||
|
||||
Текстовое представление линейного градиента имеет следующий вид:
|
||||
|
||||
linear-gradient { gradient = <значение> [, direction = <значение>] [, repeat = <значение>] }
|
||||
linear-gradient { gradient = <значение> [, direction = <значение>] [, repeating = <значение>] }
|
||||
|
||||
#### Радиальный градиент
|
||||
|
||||
|
@ -1028,7 +1028,7 @@ Pos определяет положение точки относительно
|
|||
* Gradient ("gradient") - массив ключевых точек градиента (обязательный параметр). Идентичен одноименному
|
||||
параметру линейного градиента.
|
||||
|
||||
* Repeat ("repeat") - булево значение, определяющее будет ли повторяться градиент после последней
|
||||
* Repeating ("repeating") - булево значение, определяющее будет ли повторяться градиент после последней
|
||||
ключевой точки. Необязательный параметр. Значение по умолчанию - false (не повторять)
|
||||
|
||||
* RadialGradientShape ("radial-gradient-shape") или Shape ("shape") - определяет форму градиента.
|
||||
|
@ -1051,7 +1051,7 @@ Pos определяет положение точки относительно
|
|||
| FarthestSideGradient | 2 | "farthest-side" | Схоже с ClosestSideGradient, кроме того что, размер формы определяется самой дальней стороной от своего центра (или вертикальных и горизонтальных сторон) |
|
||||
| FarthestCornerGradient | 3 | "farthest-corner" | Конечная форма градиента определяется таким образом, чтобы он точно соответствовал самому дальнему углу прямоугольника от его центра |
|
||||
|
||||
Необязательный параметр. Значение по умолчанию ClosestSideGradient
|
||||
Необязательный параметр. Значение по умолчанию FarthestCornerGradient
|
||||
|
||||
* CenterX ("center-x"), CenterY ("center-y") - задает центр градиента относительно левого верхнего
|
||||
угла View. Принимает значение типа SizeUnit. Необязательный параметр.
|
||||
|
@ -1059,9 +1059,46 @@ Pos определяет положение точки относительно
|
|||
|
||||
Текстовое представление линейного градиента имеет следующий вид:
|
||||
|
||||
radial-gradient { gradient = <значение> [, repeat = <значение>] [, shape = <значение>]
|
||||
radial-gradient { gradient = <значение> [, repeating = <значение>] [, shape = <значение>]
|
||||
[, radius = <значение>][, center-x = <значение>][, center-y = <значение>]}
|
||||
|
||||
#### Конический градиент
|
||||
|
||||
Конический градиент создается с помощью функции
|
||||
|
||||
func NewBackgroundConicGradient(params Params) BackgroundElement
|
||||
|
||||
Радиальный градиент имеет следующие параметры:
|
||||
|
||||
* Gradient ("gradient") - массив ключевых углов градиента (обязательный параметр). Каждая ключевой угол
|
||||
описывается структурой BackgroundGradientAngle:
|
||||
|
||||
type BackgroundGradientAngle struct {
|
||||
Color interface{}
|
||||
Angle interface{}
|
||||
}
|
||||
|
||||
где Color задает цвет ключевого угла и может принимать значение типа Color или string (цветовая константа
|
||||
или текстовое описание цвета);
|
||||
Angle задает угол относительно начального угла задаваемого параметром From и может принимать значение типа
|
||||
AngleUnit или string (угловая константа или текстовое описание угла).
|
||||
|
||||
Поле Color является обязательным и не может быть nil. Поле Angle опционально, если оно равно nil, то угол
|
||||
задается как середина между соседними углами. Для первго элемента угол по умолчанию равен 0°, для последнего - 360°.
|
||||
|
||||
* Repeating ("repeating") - булево значение, определяющее будет ли повторяться градиент после последнего
|
||||
ключевого угла. Необязательный параметр. Значение по умолчанию - false (не повторять)
|
||||
|
||||
* CenterX ("center-x"), CenterY ("center-y") - задает центр градиента относительно левого верхнего
|
||||
угла View. Принимает значение типа SizeUnit. Необязательный параметр.
|
||||
Значение по умолчанию "50%", т.е. центр градиента совпадает с центром View.
|
||||
|
||||
Текстовое представление конического градиента имеет следующий вид:
|
||||
|
||||
conic-gradient { gradient = <значение> [, repeating = <значение>] [, from = <значение>]
|
||||
[, center-x = <значение>][, center-y = <значение>]}
|
||||
|
||||
|
||||
#### Изображение
|
||||
|
||||
Изображение имеет следующие параметры:
|
||||
|
|
49
README.md
49
README.md
|
@ -972,11 +972,11 @@ Optional parameter. The default direction is from bottom to top. It can be eithe
|
|||
|
||||
| Value | Constant | Name | Description |
|
||||
|:-----:|-----------------------|-------------------|-----------------------------------------------|
|
||||
| 0 | ToTopGradient | "to-top" | Line goes from bottom to top (default) |
|
||||
| 0 | ToTopGradient | "to-top" | Line goes from bottom to top |
|
||||
| 1 | ToRightTopGradient | "to-right-top" | From bottom left to top right |
|
||||
| 2 | ToRightGradient | "to-right" | From left to right |
|
||||
| 3 | ToRightBottomGradient | "to-right-bottom" | From top left to bottom right |
|
||||
| 4 | ToBottomGradient | "to-bottom" | From top to bottom |
|
||||
| 4 | ToBottomGradient | "to-bottom" | From top to bottom (default) |
|
||||
| 5 | ToLeftBottomGradient | "to-left-bottom" | From the upper right corner to the lower left |
|
||||
| 6 | ToLeftGradient | "to-left" | From right to left |
|
||||
| 7 | ToLeftTopGradient | "to-left-top" | From the bottom right corner to the top left |
|
||||
|
@ -988,7 +988,7 @@ You can also pass a Color array as the gradient value. In this case, the points
|
|||
You can also use an array of []interface{} as an array of cue points.
|
||||
The elements of this array can be BackgroundGradientPoint, Color, BackgroundGradientPoint or Color text representation, and the name of the constant
|
||||
|
||||
* Repeat ("repeat") - a boolean value that determines whether the gradient will repeat after the last key point.
|
||||
* Repeating ("repeating") - a boolean value that determines whether the gradient will repeat after the last key point.
|
||||
Optional parameter. The default is false (do not repeat)
|
||||
|
||||
The linear gradient text representation is as follows:
|
||||
|
@ -1005,7 +1005,7 @@ The radial gradient has the following parameters:
|
|||
|
||||
* Gradient ("gradient") - array of gradient key points (required parameter). Identical to the linear gradient parameter of the same name.
|
||||
|
||||
* Repeat ("repeat") - a boolean value that determines whether the gradient will repeat after the last key point.
|
||||
* Repeating ("repeating") - a boolean value that determines whether the gradient will repeat after the last key point.
|
||||
Optional parameter. The default is false (do not repeat)
|
||||
|
||||
* RadialGradientShape ("radial-gradient-shape") or Shape ("shape") - defines the shape of the gradient.
|
||||
|
@ -1028,7 +1028,7 @@ Can be either SizeUnit or one of the following int values:
|
|||
| 2 | FarthestSideGradient | "farthest-side" | Similar to ClosestSideGradient, except that the size of the shape is determined by the farthest side from its center (or vertical and horizontal sides) |
|
||||
| 3 | FarthestCornerGradient | "farthest-corner" | The final shape of the gradient is defined so that it exactly matches the farthest corner of the rectangle from its center |
|
||||
|
||||
Optional parameter. The default is ClosestSideGradient
|
||||
Optional parameter. The default is FarthestCornerGradient
|
||||
|
||||
* CenterX ("center-x"), CenterY ("center-y") - sets the center of the gradient relative to the upper left corner of the View. Takes in a SizeUnit value. Optional parameter.
|
||||
The default value is "50%", i.e. the center of the gradient is the center of the View.
|
||||
|
@ -1038,6 +1038,45 @@ The linear gradient text representation is as follows:
|
|||
radial-gradient { gradient = <Value> [, repeat = <Value>] [, shape = <Value>]
|
||||
[, radius = <Value>][, center-x = <Value>][, center-y = <Value>]}
|
||||
|
||||
#### Conic gradient
|
||||
|
||||
The conic gradient is created using the function
|
||||
|
||||
func NewBackgroundConicGradient(params Params) BackgroundElement
|
||||
|
||||
The radial gradient has the following options:
|
||||
|
||||
* Gradient ("gradient") - array of gradient key angles (required parameter).
|
||||
Each key angle is described by a BackgroundGradientAngle structure:
|
||||
|
||||
type BackgroundGradientAngle struct {
|
||||
Color interface{}
|
||||
Angle interface{}
|
||||
}
|
||||
|
||||
where Color specifies the color of the key corner and can take a value of Color type or
|
||||
string (color constant or textual description of the color);
|
||||
Angle sets the angle relative to the initial angle specified by the From parameter
|
||||
and can take a value of the AngleUnit type or string (an angle constant or a textual description of the angle).
|
||||
|
||||
The Color field is required and cannot be nil.
|
||||
|
||||
The Angle field is optional. If it is nil, then the angle is set as the midpoint between adjacent corners.
|
||||
For the first element, the default angle is 0°, for the last element it is 360°.
|
||||
|
||||
* Repeating ("repeating") is a boolean value that determines whether the gradient will repeat after the last key corner.
|
||||
Optional parameter. Default value is false (don't repeat)
|
||||
|
||||
* CenterX ("center-x"), CenterY ("center-y") - sets the center of the gradient relative to the upper left corner of the View.
|
||||
Takes a value of SizeUnit type. Optional parameter.
|
||||
The default value is "50%", i.e. the center of the gradient is the same as the center of the View.
|
||||
|
||||
The textual representation of a conic gradient looks like this:
|
||||
|
||||
conic-gradient { gradient = <Value> [, repeating = <Value>] [, from = <Value>]
|
||||
[, center-x = <Value>][, center-y = <Value>]}
|
||||
|
||||
|
||||
#### Image
|
||||
|
||||
The image has the following parameters:
|
||||
|
|
500
background.go
500
background.go
|
@ -56,47 +56,6 @@ const (
|
|||
// ContentBoxClip is value of the BackgroundClip property:
|
||||
// The background is painted within (clipped to) the content box.
|
||||
ContentBoxClip = 2
|
||||
|
||||
// ToTopGradient is value of the Direction property of a linear gradient. The value is equivalent to the 0deg angle
|
||||
ToTopGradient = 0
|
||||
// ToRightTopGradient is value of the Direction property of a linear gradient.
|
||||
ToRightTopGradient = 1
|
||||
// ToRightGradient is value of the Direction property of a linear gradient. The value is equivalent to the 90deg angle
|
||||
ToRightGradient = 2
|
||||
// ToRightBottomGradient is value of the Direction property of a linear gradient.
|
||||
ToRightBottomGradient = 3
|
||||
// ToBottomGradient is value of the Direction property of a linear gradient. The value is equivalent to the 180deg angle
|
||||
ToBottomGradient = 4
|
||||
// ToLeftBottomGradient is value of the Direction property of a linear gradient.
|
||||
ToLeftBottomGradient = 5
|
||||
// ToLeftGradient is value of the Direction property of a linear gradient. The value is equivalent to the 270deg angle
|
||||
ToLeftGradient = 6
|
||||
// ToLeftTopGradient is value of the Direction property of a linear gradient.
|
||||
ToLeftTopGradient = 7
|
||||
|
||||
// EllipseGradient is value of the Shape property of a radial gradient background:
|
||||
// the shape is an axis-aligned ellipse
|
||||
EllipseGradient = 0
|
||||
// CircleGradient is value of the Shape property of a radial gradient background:
|
||||
// the gradient's shape is a circle with constant radius
|
||||
CircleGradient = 1
|
||||
|
||||
// ClosestSideGradient is value of the Radius property of a radial gradient background:
|
||||
// The gradient's ending shape meets the side of the box closest to its center (for circles)
|
||||
// or meets both the vertical and horizontal sides closest to the center (for ellipses).
|
||||
ClosestSideGradient = 0
|
||||
// ClosestCornerGradient is value of the Radius property of a radial gradient background:
|
||||
// The gradient's ending shape is sized so that it exactly meets the closest corner
|
||||
// of the box from its center.
|
||||
ClosestCornerGradient = 1
|
||||
// FarthestSideGradient is value of the Radius property of a radial gradient background:
|
||||
// Similar to closest-side, except the ending shape is sized to meet the side of the box
|
||||
// farthest from its center (or vertical and horizontal sides).
|
||||
FarthestSideGradient = 2
|
||||
// FarthestCornerGradient is value of the Radius property of a radial gradient background:
|
||||
// The default value, the gradient's ending shape is sized so that it exactly meets
|
||||
// the farthest corner of the box from its center.
|
||||
FarthestCornerGradient = 3
|
||||
)
|
||||
|
||||
// BackgroundElement describes the background element.
|
||||
|
@ -104,6 +63,7 @@ type BackgroundElement interface {
|
|||
Properties
|
||||
cssStyle(session Session) string
|
||||
Tag() string
|
||||
Clone() BackgroundElement
|
||||
}
|
||||
|
||||
type backgroundElement struct {
|
||||
|
@ -114,26 +74,6 @@ type backgroundImage struct {
|
|||
backgroundElement
|
||||
}
|
||||
|
||||
// BackgroundGradientPoint define point on gradient straight line
|
||||
type BackgroundGradientPoint struct {
|
||||
// Pos - the distance from the start of the gradient straight line
|
||||
Pos SizeUnit
|
||||
// Color - the color of the point
|
||||
Color Color
|
||||
}
|
||||
|
||||
type backgroundGradient struct {
|
||||
backgroundElement
|
||||
}
|
||||
|
||||
type backgroundLinearGradient struct {
|
||||
backgroundGradient
|
||||
}
|
||||
|
||||
type backgroundRadialGradient struct {
|
||||
backgroundGradient
|
||||
}
|
||||
|
||||
// NewBackgroundImage creates the new background image
|
||||
func createBackground(obj DataObject) BackgroundElement {
|
||||
var result BackgroundElement = nil
|
||||
|
@ -154,6 +94,11 @@ func createBackground(obj DataObject) BackgroundElement {
|
|||
gradient.properties = map[string]interface{}{}
|
||||
result = gradient
|
||||
|
||||
case "conic-gradient":
|
||||
gradient := new(backgroundConicGradient)
|
||||
gradient.properties = map[string]interface{}{}
|
||||
result = gradient
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
@ -180,30 +125,18 @@ func NewBackgroundImage(params Params) BackgroundElement {
|
|||
return result
|
||||
}
|
||||
|
||||
// NewBackgroundLinearGradient creates the new background linear gradient
|
||||
func NewBackgroundLinearGradient(params Params) BackgroundElement {
|
||||
result := new(backgroundLinearGradient)
|
||||
result.properties = map[string]interface{}{}
|
||||
for tag, value := range params {
|
||||
result.Set(tag, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// NewBackgroundRadialGradient creates the new background radial gradient
|
||||
func NewBackgroundRadialGradient(params Params) BackgroundElement {
|
||||
result := new(backgroundRadialGradient)
|
||||
result.properties = map[string]interface{}{}
|
||||
for tag, value := range params {
|
||||
result.Set(tag, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (image *backgroundImage) Tag() string {
|
||||
return "image"
|
||||
}
|
||||
|
||||
func (image *backgroundImage) Clone() BackgroundElement {
|
||||
result := NewBackgroundImage(nil)
|
||||
for tag, value := range image.properties {
|
||||
result.setRaw(tag, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (image *backgroundImage) normalizeTag(tag string) string {
|
||||
tag = strings.ToLower(tag)
|
||||
switch tag {
|
||||
|
@ -306,408 +239,3 @@ func (image *backgroundImage) cssStyle(session Session) string {
|
|||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (gradient *backgroundGradient) Set(tag string, value interface{}) bool {
|
||||
|
||||
switch tag = strings.ToLower(tag); tag {
|
||||
case Repeat:
|
||||
return gradient.setBoolProperty(tag, value)
|
||||
|
||||
case Gradient:
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if value != "" {
|
||||
elements := strings.Split(value, `,`)
|
||||
if count := len(elements); count > 1 {
|
||||
points := make([]interface{}, count)
|
||||
for i, element := range elements {
|
||||
if strings.Contains(element, "@") {
|
||||
points[i] = element
|
||||
} else {
|
||||
var point BackgroundGradientPoint
|
||||
if point.setValue(element) {
|
||||
points[i] = point
|
||||
} else {
|
||||
ErrorLogF("Invalid gradient element #%d: %s", i, element)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
gradient.properties[Gradient] = points
|
||||
return true
|
||||
}
|
||||
|
||||
text := strings.Trim(value, " \n\r\t")
|
||||
if text[0] == '@' {
|
||||
gradient.properties[Gradient] = text
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
case []BackgroundGradientPoint:
|
||||
if len(value) >= 2 {
|
||||
gradient.properties[Gradient] = value
|
||||
return true
|
||||
}
|
||||
|
||||
case []Color:
|
||||
count := len(value)
|
||||
if count >= 2 {
|
||||
points := make([]BackgroundGradientPoint, count)
|
||||
for i, color := range value {
|
||||
points[i].Color = color
|
||||
points[i].Pos = AutoSize()
|
||||
}
|
||||
gradient.properties[Gradient] = points
|
||||
return true
|
||||
}
|
||||
|
||||
case []GradientPoint:
|
||||
count := len(value)
|
||||
if count >= 2 {
|
||||
points := make([]BackgroundGradientPoint, count)
|
||||
for i, point := range value {
|
||||
points[i].Color = point.Color
|
||||
points[i].Pos = Percent(point.Offset * 100)
|
||||
}
|
||||
gradient.properties[Gradient] = points
|
||||
return true
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
if count := len(value); count > 1 {
|
||||
points := make([]interface{}, count)
|
||||
for i, element := range value {
|
||||
switch element := element.(type) {
|
||||
case string:
|
||||
if strings.Contains(element, "@") {
|
||||
points[i] = element
|
||||
} else {
|
||||
var point BackgroundGradientPoint
|
||||
if !point.setValue(element) {
|
||||
ErrorLogF("Invalid gradient element #%d: %s", i, element)
|
||||
return false
|
||||
}
|
||||
points[i] = point
|
||||
}
|
||||
|
||||
case BackgroundGradientPoint:
|
||||
points[i] = element
|
||||
|
||||
case GradientPoint:
|
||||
points[i] = BackgroundGradientPoint{Color: element.Color, Pos: Percent(element.Offset * 100)}
|
||||
|
||||
case Color:
|
||||
points[i] = BackgroundGradientPoint{Color: element, Pos: AutoSize()}
|
||||
|
||||
default:
|
||||
ErrorLogF("Invalid gradient element #%d: %v", i, element)
|
||||
return false
|
||||
}
|
||||
}
|
||||
gradient.properties[Gradient] = points
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
ErrorLogF("Invalid gradient %v", value)
|
||||
return false
|
||||
}
|
||||
|
||||
return gradient.backgroundElement.Set(tag, value)
|
||||
}
|
||||
|
||||
func (point *BackgroundGradientPoint) setValue(value string) bool {
|
||||
var ok bool
|
||||
|
||||
switch elements := strings.Split(value, `:`); len(elements) {
|
||||
case 2:
|
||||
if point.Color, ok = StringToColor(elements[0]); !ok {
|
||||
return false
|
||||
}
|
||||
if point.Pos, ok = StringToSizeUnit(elements[1]); !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
case 1:
|
||||
if point.Color, ok = StringToColor(elements[0]); !ok {
|
||||
return false
|
||||
}
|
||||
point.Pos = AutoSize()
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (gradient *backgroundGradient) writeGradient(session Session, buffer *strings.Builder) bool {
|
||||
|
||||
value, ok := gradient.properties[Gradient]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
points := []BackgroundGradientPoint{}
|
||||
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(value); ok && text != "" {
|
||||
elements := strings.Split(text, `,`)
|
||||
points := make([]BackgroundGradientPoint, len(elements))
|
||||
for i, element := range elements {
|
||||
if !points[i].setValue(element) {
|
||||
ErrorLogF(`Invalid gradient point #%d: "%s"`, i, element)
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ErrorLog(`Invalid gradient: ` + value)
|
||||
return false
|
||||
}
|
||||
|
||||
case []BackgroundGradientPoint:
|
||||
points = value
|
||||
|
||||
case []interface{}:
|
||||
points = make([]BackgroundGradientPoint, len(value))
|
||||
for i, element := range value {
|
||||
switch element := element.(type) {
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(element); ok && text != "" {
|
||||
if !points[i].setValue(text) {
|
||||
ErrorLogF(`Invalid gradient point #%d: "%s"`, i, text)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
ErrorLogF(`Invalid gradient point #%d: "%s"`, i, text)
|
||||
return false
|
||||
}
|
||||
|
||||
case BackgroundGradientPoint:
|
||||
points[i] = element
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(points) > 0 {
|
||||
for i, point := range points {
|
||||
if i > 0 {
|
||||
buffer.WriteString(`, `)
|
||||
}
|
||||
|
||||
buffer.WriteString(point.Color.cssString())
|
||||
if point.Pos.Type != Auto {
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(point.Pos.cssString(""))
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (gradient *backgroundLinearGradient) Tag() string {
|
||||
return "linear-gradient"
|
||||
}
|
||||
|
||||
func (gradient *backgroundLinearGradient) Set(tag string, value interface{}) bool {
|
||||
if tag == Direction {
|
||||
switch value := value.(type) {
|
||||
case AngleUnit:
|
||||
gradient.properties[Direction] = value
|
||||
return true
|
||||
|
||||
case string:
|
||||
var angle AngleUnit
|
||||
if ok, _ := angle.setValue(value); ok {
|
||||
gradient.properties[Direction] = angle
|
||||
return true
|
||||
}
|
||||
}
|
||||
return gradient.setEnumProperty(tag, value, enumProperties[Direction].values)
|
||||
}
|
||||
|
||||
return gradient.backgroundGradient.Set(tag, value)
|
||||
}
|
||||
|
||||
func (gradient *backgroundLinearGradient) cssStyle(session Session) string {
|
||||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
if repeating, _ := boolProperty(gradient, Repeating, session); repeating {
|
||||
buffer.WriteString(`repeating-linear-gradient(`)
|
||||
} else {
|
||||
buffer.WriteString(`linear-gradient(`)
|
||||
}
|
||||
|
||||
if value, ok := gradient.properties[Direction]; ok {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(value); ok {
|
||||
direction := enumProperties[Direction]
|
||||
if n, ok := enumStringToInt(text, direction.values, false); ok {
|
||||
buffer.WriteString(direction.cssValues[n])
|
||||
buffer.WriteString(", ")
|
||||
} else {
|
||||
if angle, ok := StringToAngleUnit(text); ok {
|
||||
buffer.WriteString(angle.cssString())
|
||||
buffer.WriteString(", ")
|
||||
} else {
|
||||
ErrorLog(`Invalid linear gradient direction: ` + text)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ErrorLog(`Invalid linear gradient direction: ` + value)
|
||||
}
|
||||
|
||||
case int:
|
||||
values := enumProperties[Direction].cssValues
|
||||
if value >= 0 && value < len(values) {
|
||||
buffer.WriteString(values[value])
|
||||
buffer.WriteString(", ")
|
||||
} else {
|
||||
ErrorLogF(`Invalid linear gradient direction: %d`, value)
|
||||
}
|
||||
|
||||
case AngleUnit:
|
||||
buffer.WriteString(value.cssString())
|
||||
buffer.WriteString(", ")
|
||||
}
|
||||
}
|
||||
|
||||
if !gradient.writeGradient(session, buffer) {
|
||||
return ""
|
||||
}
|
||||
|
||||
buffer.WriteString(") ")
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) Tag() string {
|
||||
return "radial-gradient"
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) normalizeTag(tag string) string {
|
||||
tag = strings.ToLower(tag)
|
||||
switch tag {
|
||||
case Radius:
|
||||
tag = RadialGradientRadius
|
||||
|
||||
case Shape:
|
||||
tag = RadialGradientShape
|
||||
|
||||
case "x-center":
|
||||
tag = CenterX
|
||||
|
||||
case "y-center":
|
||||
tag = CenterY
|
||||
}
|
||||
|
||||
return tag
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) Set(tag string, value interface{}) bool {
|
||||
tag = gradient.normalizeTag(tag)
|
||||
switch tag {
|
||||
case RadialGradientRadius:
|
||||
switch value := value.(type) {
|
||||
case string, SizeUnit:
|
||||
return gradient.propertyList.Set(RadialGradientRadius, value)
|
||||
|
||||
case int:
|
||||
n := value
|
||||
if n >= 0 && n < len(enumProperties[RadialGradientRadius].values) {
|
||||
return gradient.propertyList.Set(RadialGradientRadius, value)
|
||||
}
|
||||
}
|
||||
ErrorLogF(`Invalid value of "%s" property: %v`, tag, value)
|
||||
|
||||
case RadialGradientShape:
|
||||
return gradient.propertyList.Set(RadialGradientShape, value)
|
||||
|
||||
case CenterX, CenterY:
|
||||
return gradient.propertyList.Set(tag, value)
|
||||
}
|
||||
|
||||
return gradient.backgroundGradient.Set(tag, value)
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) Get(tag string) interface{} {
|
||||
return gradient.backgroundGradient.Get(gradient.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
|
||||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
if repeating, _ := boolProperty(gradient, Repeating, session); repeating {
|
||||
buffer.WriteString(`repeating-radial-gradient(`)
|
||||
} else {
|
||||
buffer.WriteString(`radial-gradient(`)
|
||||
}
|
||||
|
||||
if shape, ok := enumProperty(gradient, RadialGradientShape, session, EllipseGradient); ok && shape == CircleGradient {
|
||||
buffer.WriteString(`circle `)
|
||||
} else {
|
||||
buffer.WriteString(`ellipse `)
|
||||
}
|
||||
|
||||
if value, ok := gradient.properties[RadialGradientRadius]; ok {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(value); ok {
|
||||
values := enumProperties[RadialGradientRadius]
|
||||
if n, ok := enumStringToInt(text, values.values, false); ok {
|
||||
buffer.WriteString(values.cssValues[n])
|
||||
buffer.WriteString(" ")
|
||||
} else {
|
||||
if r, ok := StringToSizeUnit(text); ok && r.Type != Auto {
|
||||
buffer.WriteString(r.cssString(""))
|
||||
buffer.WriteString(" ")
|
||||
} else {
|
||||
ErrorLog(`Invalid linear gradient radius: ` + text)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ErrorLog(`Invalid linear gradient radius: ` + value)
|
||||
}
|
||||
|
||||
case int:
|
||||
values := enumProperties[RadialGradientRadius].cssValues
|
||||
if value >= 0 && value < len(values) {
|
||||
buffer.WriteString(values[value])
|
||||
buffer.WriteString(" ")
|
||||
} else {
|
||||
ErrorLogF(`Invalid linear gradient radius: %d`, value)
|
||||
}
|
||||
|
||||
case SizeUnit:
|
||||
if value.Type != Auto {
|
||||
buffer.WriteString(value.cssString(""))
|
||||
buffer.WriteString(" ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x, _ := sizeProperty(gradient, CenterX, session)
|
||||
y, _ := sizeProperty(gradient, CenterX, session)
|
||||
if x.Type != Auto || y.Type != Auto {
|
||||
buffer.WriteString("at ")
|
||||
buffer.WriteString(x.cssString("50%"))
|
||||
buffer.WriteString(" ")
|
||||
buffer.WriteString(y.cssString("50%"))
|
||||
}
|
||||
|
||||
buffer.WriteString(", ")
|
||||
if !gradient.writeGradient(session, buffer) {
|
||||
return ""
|
||||
}
|
||||
|
||||
buffer.WriteString(") ")
|
||||
|
||||
return buffer.String()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,416 @@
|
|||
package rui
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type backgroundConicGradient struct {
|
||||
backgroundElement
|
||||
}
|
||||
|
||||
// BackgroundGradientAngle defined an element of the conic gradient
|
||||
type BackgroundGradientAngle struct {
|
||||
// Color - the color of the key angle. Must not be nil.
|
||||
// Can take a value of Color type or string (color constant or textual description of the color)
|
||||
Color interface{}
|
||||
// Angle - the key angle. Optional (may be nil).
|
||||
// Can take a value of AngleUnit type or string (angle constant or textual description of the angle)
|
||||
Angle interface{}
|
||||
}
|
||||
|
||||
// NewBackgroundConicGradient creates the new background conic gradient
|
||||
func NewBackgroundConicGradient(params Params) BackgroundElement {
|
||||
result := new(backgroundConicGradient)
|
||||
result.properties = map[string]interface{}{}
|
||||
for tag, value := range params {
|
||||
result.Set(tag, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (point *BackgroundGradientAngle) String() string {
|
||||
result := "black"
|
||||
if point.Color != nil {
|
||||
switch color := point.Color.(type) {
|
||||
case string:
|
||||
result = color
|
||||
|
||||
case Color:
|
||||
result = color.String()
|
||||
}
|
||||
}
|
||||
|
||||
if point.Angle != nil {
|
||||
switch value := point.Angle.(type) {
|
||||
case string:
|
||||
result += " " + value
|
||||
|
||||
case AngleUnit:
|
||||
result += " " + value.String()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (point *BackgroundGradientAngle) color(session Session) (Color, bool) {
|
||||
if point.Color != nil {
|
||||
switch color := point.Color.(type) {
|
||||
case string:
|
||||
if color != "" {
|
||||
if color[0] == '@' {
|
||||
if clr, ok := session.Color(color[1:]); ok {
|
||||
return clr, true
|
||||
}
|
||||
} else {
|
||||
if clr, ok := StringToColor(color); ok {
|
||||
return clr, true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case Color:
|
||||
return color, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (point *BackgroundGradientAngle) isValid(session Session) bool {
|
||||
_, ok := point.color(session)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (point *BackgroundGradientAngle) cssString(session Session, buffer *strings.Builder) {
|
||||
if color, ok := point.color(session); ok {
|
||||
buffer.WriteString(color.cssString())
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
if point.Angle != nil {
|
||||
switch value := point.Angle.(type) {
|
||||
case string:
|
||||
if value != "" {
|
||||
if value[0] == '@' {
|
||||
if val, ok := session.Constant(value[1:]); ok {
|
||||
value = val
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if angle, ok := StringToAngleUnit(value); ok {
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(angle.cssString())
|
||||
}
|
||||
}
|
||||
|
||||
case AngleUnit:
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(value.cssString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) Tag() string {
|
||||
return "conic-gradient"
|
||||
}
|
||||
|
||||
func (image *backgroundConicGradient) Clone() BackgroundElement {
|
||||
result := NewBackgroundConicGradient(nil)
|
||||
for tag, value := range image.properties {
|
||||
result.setRaw(tag, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) normalizeTag(tag string) string {
|
||||
tag = strings.ToLower(tag)
|
||||
switch tag {
|
||||
case "x-center":
|
||||
tag = CenterX
|
||||
|
||||
case "y-center":
|
||||
tag = CenterY
|
||||
}
|
||||
|
||||
return tag
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) Set(tag string, value interface{}) bool {
|
||||
tag = gradient.normalizeTag(tag)
|
||||
switch tag {
|
||||
case CenterX, CenterY, Repeating, From:
|
||||
return gradient.propertyList.Set(tag, value)
|
||||
|
||||
case Gradient:
|
||||
return gradient.setGradient(value)
|
||||
}
|
||||
|
||||
ErrorLogF(`"%s" property is not supported by BackgroundConicGradient`, tag)
|
||||
return false
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) stringToAngle(text string) (interface{}, bool) {
|
||||
if text == "" {
|
||||
return nil, false
|
||||
} else if text[0] == '@' {
|
||||
return text, true
|
||||
}
|
||||
return StringToAngleUnit(text)
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) stringToGradientPoint(text string) (BackgroundGradientAngle, bool) {
|
||||
var result BackgroundGradientAngle
|
||||
colorText := ""
|
||||
pointText := ""
|
||||
|
||||
if index := strings.Index(text, " "); index > 0 {
|
||||
colorText = text[:index]
|
||||
pointText = strings.Trim(text[index+1:], " ")
|
||||
} else {
|
||||
colorText = text
|
||||
}
|
||||
|
||||
if colorText == "" {
|
||||
return result, false
|
||||
}
|
||||
|
||||
if colorText[0] == '@' {
|
||||
result.Color = colorText
|
||||
} else if color, ok := StringToColor(colorText); ok {
|
||||
result.Color = color
|
||||
} else {
|
||||
return result, false
|
||||
}
|
||||
|
||||
if pointText != "" {
|
||||
if angle, ok := gradient.stringToAngle(pointText); ok {
|
||||
result.Angle = angle
|
||||
} else {
|
||||
return result, false
|
||||
}
|
||||
}
|
||||
|
||||
return result, true
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) parseGradientText(value string) []BackgroundGradientAngle {
|
||||
elements := strings.Split(value, ",")
|
||||
count := len(elements)
|
||||
if count < 2 {
|
||||
ErrorLog("The gradient must contain at least 2 points")
|
||||
return nil
|
||||
}
|
||||
|
||||
vector := make([]BackgroundGradientAngle, count)
|
||||
for i, element := range elements {
|
||||
var ok bool
|
||||
if vector[i], ok = gradient.stringToGradientPoint(strings.Trim(element, " ")); !ok {
|
||||
ErrorLogF(`Ivalid %d element of the conic gradient: "%s"`, i, element)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return vector
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) setGradient(value interface{}) bool {
|
||||
if value == nil {
|
||||
delete(gradient.properties, Gradient)
|
||||
return true
|
||||
}
|
||||
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if value == "" {
|
||||
delete(gradient.properties, Gradient)
|
||||
return true
|
||||
}
|
||||
|
||||
if strings.Contains(value, ",") || strings.Contains(value, " ") {
|
||||
if vector := gradient.parseGradientText(value); vector != nil {
|
||||
gradient.properties[Gradient] = vector
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} else if value[0] == '@' {
|
||||
gradient.properties[Gradient] = value
|
||||
return true
|
||||
}
|
||||
|
||||
ErrorLogF(`Ivalid conic gradient: "%s"`, value)
|
||||
return false
|
||||
|
||||
case []interface{}:
|
||||
count := len(value)
|
||||
if count < 2 {
|
||||
ErrorLog("The gradient must contain at least 2 points")
|
||||
return false
|
||||
}
|
||||
vector := make([]BackgroundGradientAngle, len(value))
|
||||
for i, point := range value {
|
||||
if point == nil {
|
||||
ErrorLogF("Ivalid %d element of the conic gradient: nil", i)
|
||||
return false
|
||||
}
|
||||
|
||||
switch element := point.(type) {
|
||||
case string:
|
||||
if data, ok := gradient.stringToGradientPoint(element); ok {
|
||||
vector[i] = data
|
||||
} else {
|
||||
ErrorLogF("Ivalid %d element of the conic gradient: %s", i, element)
|
||||
return false
|
||||
}
|
||||
|
||||
case Color:
|
||||
vector[i].Color = element
|
||||
|
||||
case BackgroundGradientAngle:
|
||||
if element.Color == nil {
|
||||
ErrorLogF("Ivalid %d element of the conic gradient: Color is nil", i)
|
||||
return false
|
||||
}
|
||||
switch color := element.Color.(type) {
|
||||
case string:
|
||||
if color == "" {
|
||||
ErrorLogF("Ivalid %d element of the conic gradient: empty Color text", i)
|
||||
return false
|
||||
}
|
||||
if color[0] != '@' {
|
||||
if clr, ok := StringToColor(color); ok {
|
||||
element.Color = clr
|
||||
} else {
|
||||
ErrorLogF("Ivalid %d element of the conic gradient: invalid Color text", i)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
case Color:
|
||||
// do nothing
|
||||
|
||||
default:
|
||||
ErrorLogF("Ivalid %d element of the conic gradient: unsupported Color type", i)
|
||||
return false
|
||||
}
|
||||
|
||||
if element.Angle != nil {
|
||||
switch point := element.Angle.(type) {
|
||||
case string:
|
||||
if angle, ok := gradient.stringToAngle(point); ok {
|
||||
element.Angle = angle
|
||||
} else {
|
||||
ErrorLogF("Ivalid %d element of the conic gradient: invalid Point text", i)
|
||||
return false
|
||||
}
|
||||
|
||||
case AngleUnit:
|
||||
// do nothing
|
||||
|
||||
default:
|
||||
ErrorLogF("Ivalid %d element of the conic gradient: unsupported Point type", i)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
vector[i] = element
|
||||
}
|
||||
}
|
||||
gradient.properties[Gradient] = vector
|
||||
return true
|
||||
|
||||
case []BackgroundGradientAngle:
|
||||
count := len(value)
|
||||
if count < 2 {
|
||||
ErrorLog("The gradient must contain at least 2 points")
|
||||
return false
|
||||
}
|
||||
|
||||
for i, point := range value {
|
||||
if point.Color == nil {
|
||||
ErrorLogF("Ivalid %d element of the conic gradient: Color is nil", i)
|
||||
return false
|
||||
}
|
||||
}
|
||||
gradient.properties[Gradient] = value
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) Get(tag string) interface{} {
|
||||
return gradient.backgroundElement.Get(gradient.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (gradient *backgroundConicGradient) cssStyle(session Session) string {
|
||||
|
||||
points := []BackgroundGradientAngle{}
|
||||
if value, ok := gradient.properties[Gradient]; ok {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(value); ok && text != "" {
|
||||
if points = gradient.parseGradientText(text); points == nil {
|
||||
return ""
|
||||
}
|
||||
} else {
|
||||
ErrorLog(`Invalid conic gradient: ` + value)
|
||||
return ""
|
||||
}
|
||||
|
||||
case []BackgroundGradientAngle:
|
||||
points = value
|
||||
}
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
|
||||
if len(points) < 2 {
|
||||
ErrorLog("The gradient must contain at least 2 points")
|
||||
return ""
|
||||
}
|
||||
|
||||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
if repeating, _ := boolProperty(gradient, Repeating, session); repeating {
|
||||
buffer.WriteString(`repeating-conic-gradient(`)
|
||||
} else {
|
||||
buffer.WriteString(`conic-gradient(`)
|
||||
}
|
||||
|
||||
comma := false
|
||||
if angle, ok := angleProperty(gradient, From, session); ok {
|
||||
buffer.WriteString("from ")
|
||||
buffer.WriteString(angle.cssString())
|
||||
comma = true
|
||||
}
|
||||
|
||||
x, _ := sizeProperty(gradient, CenterX, session)
|
||||
y, _ := sizeProperty(gradient, CenterX, session)
|
||||
if x.Type != Auto || y.Type != Auto {
|
||||
if comma {
|
||||
buffer.WriteRune(' ')
|
||||
}
|
||||
buffer.WriteString("at ")
|
||||
buffer.WriteString(x.cssString("50%"))
|
||||
buffer.WriteString(" ")
|
||||
buffer.WriteString(y.cssString("50%"))
|
||||
comma = true
|
||||
}
|
||||
|
||||
for _, point := range points {
|
||||
if point.isValid(session) {
|
||||
if comma {
|
||||
buffer.WriteString(`, `)
|
||||
}
|
||||
point.cssString(session, buffer)
|
||||
comma = true
|
||||
}
|
||||
}
|
||||
|
||||
buffer.WriteString(") ")
|
||||
|
||||
return buffer.String()
|
||||
}
|
|
@ -0,0 +1,508 @@
|
|||
package rui
|
||||
|
||||
import "strings"
|
||||
|
||||
const (
|
||||
|
||||
// ToTopGradient is value of the Direction property of a linear gradient. The value is equivalent to the 0deg angle
|
||||
ToTopGradient = 0
|
||||
// ToRightTopGradient is value of the Direction property of a linear gradient.
|
||||
ToRightTopGradient = 1
|
||||
// ToRightGradient is value of the Direction property of a linear gradient. The value is equivalent to the 90deg angle
|
||||
ToRightGradient = 2
|
||||
// ToRightBottomGradient is value of the Direction property of a linear gradient.
|
||||
ToRightBottomGradient = 3
|
||||
// ToBottomGradient is value of the Direction property of a linear gradient. The value is equivalent to the 180deg angle
|
||||
ToBottomGradient = 4
|
||||
// ToLeftBottomGradient is value of the Direction property of a linear gradient.
|
||||
ToLeftBottomGradient = 5
|
||||
// ToLeftGradient is value of the Direction property of a linear gradient. The value is equivalent to the 270deg angle
|
||||
ToLeftGradient = 6
|
||||
// ToLeftTopGradient is value of the Direction property of a linear gradient.
|
||||
ToLeftTopGradient = 7
|
||||
|
||||
// EllipseGradient is value of the Shape property of a radial gradient background:
|
||||
// the shape is an axis-aligned ellipse
|
||||
EllipseGradient = 0
|
||||
// CircleGradient is value of the Shape property of a radial gradient background:
|
||||
// the gradient's shape is a circle with constant radius
|
||||
CircleGradient = 1
|
||||
|
||||
// ClosestSideGradient is value of the Radius property of a radial gradient background:
|
||||
// The gradient's ending shape meets the side of the box closest to its center (for circles)
|
||||
// or meets both the vertical and horizontal sides closest to the center (for ellipses).
|
||||
ClosestSideGradient = 0
|
||||
// ClosestCornerGradient is value of the Radius property of a radial gradient background:
|
||||
// The gradient's ending shape is sized so that it exactly meets the closest corner
|
||||
// of the box from its center.
|
||||
ClosestCornerGradient = 1
|
||||
// FarthestSideGradient is value of the Radius property of a radial gradient background:
|
||||
// Similar to closest-side, except the ending shape is sized to meet the side of the box
|
||||
// farthest from its center (or vertical and horizontal sides).
|
||||
FarthestSideGradient = 2
|
||||
// FarthestCornerGradient is value of the Radius property of a radial gradient background:
|
||||
// The default value, the gradient's ending shape is sized so that it exactly meets
|
||||
// the farthest corner of the box from its center.
|
||||
FarthestCornerGradient = 3
|
||||
)
|
||||
|
||||
// BackgroundGradientPoint define point on gradient straight line
|
||||
type BackgroundGradientPoint struct {
|
||||
// Pos - the distance from the start of the gradient straight line
|
||||
Pos SizeUnit
|
||||
// Color - the color of the point
|
||||
Color Color
|
||||
}
|
||||
|
||||
type backgroundGradient struct {
|
||||
backgroundElement
|
||||
}
|
||||
|
||||
type backgroundLinearGradient struct {
|
||||
backgroundGradient
|
||||
}
|
||||
|
||||
type backgroundRadialGradient struct {
|
||||
backgroundGradient
|
||||
}
|
||||
|
||||
// NewBackgroundLinearGradient creates the new background linear gradient
|
||||
func NewBackgroundLinearGradient(params Params) BackgroundElement {
|
||||
result := new(backgroundLinearGradient)
|
||||
result.properties = map[string]interface{}{}
|
||||
for tag, value := range params {
|
||||
result.Set(tag, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// NewBackgroundRadialGradient creates the new background radial gradient
|
||||
func NewBackgroundRadialGradient(params Params) BackgroundElement {
|
||||
result := new(backgroundRadialGradient)
|
||||
result.properties = map[string]interface{}{}
|
||||
for tag, value := range params {
|
||||
result.Set(tag, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gradient *backgroundGradient) Set(tag string, value interface{}) bool {
|
||||
|
||||
switch tag = strings.ToLower(tag); tag {
|
||||
case Repeating:
|
||||
return gradient.setBoolProperty(tag, value)
|
||||
|
||||
case Gradient:
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if value != "" {
|
||||
elements := strings.Split(value, `,`)
|
||||
if count := len(elements); count > 1 {
|
||||
points := make([]interface{}, count)
|
||||
for i, element := range elements {
|
||||
if strings.Contains(element, "@") {
|
||||
points[i] = element
|
||||
} else {
|
||||
var point BackgroundGradientPoint
|
||||
if point.setValue(element) {
|
||||
points[i] = point
|
||||
} else {
|
||||
ErrorLogF("Invalid gradient element #%d: %s", i, element)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
gradient.properties[Gradient] = points
|
||||
return true
|
||||
}
|
||||
|
||||
text := strings.Trim(value, " \n\r\t")
|
||||
if text[0] == '@' {
|
||||
gradient.properties[Gradient] = text
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
case []BackgroundGradientPoint:
|
||||
if len(value) >= 2 {
|
||||
gradient.properties[Gradient] = value
|
||||
return true
|
||||
}
|
||||
|
||||
case []Color:
|
||||
count := len(value)
|
||||
if count >= 2 {
|
||||
points := make([]BackgroundGradientPoint, count)
|
||||
for i, color := range value {
|
||||
points[i].Color = color
|
||||
points[i].Pos = AutoSize()
|
||||
}
|
||||
gradient.properties[Gradient] = points
|
||||
return true
|
||||
}
|
||||
|
||||
case []GradientPoint:
|
||||
count := len(value)
|
||||
if count >= 2 {
|
||||
points := make([]BackgroundGradientPoint, count)
|
||||
for i, point := range value {
|
||||
points[i].Color = point.Color
|
||||
points[i].Pos = Percent(point.Offset * 100)
|
||||
}
|
||||
gradient.properties[Gradient] = points
|
||||
return true
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
if count := len(value); count > 1 {
|
||||
points := make([]interface{}, count)
|
||||
for i, element := range value {
|
||||
switch element := element.(type) {
|
||||
case string:
|
||||
if strings.Contains(element, "@") {
|
||||
points[i] = element
|
||||
} else {
|
||||
var point BackgroundGradientPoint
|
||||
if !point.setValue(element) {
|
||||
ErrorLogF("Invalid gradient element #%d: %s", i, element)
|
||||
return false
|
||||
}
|
||||
points[i] = point
|
||||
}
|
||||
|
||||
case BackgroundGradientPoint:
|
||||
points[i] = element
|
||||
|
||||
case GradientPoint:
|
||||
points[i] = BackgroundGradientPoint{Color: element.Color, Pos: Percent(element.Offset * 100)}
|
||||
|
||||
case Color:
|
||||
points[i] = BackgroundGradientPoint{Color: element, Pos: AutoSize()}
|
||||
|
||||
default:
|
||||
ErrorLogF("Invalid gradient element #%d: %v", i, element)
|
||||
return false
|
||||
}
|
||||
}
|
||||
gradient.properties[Gradient] = points
|
||||
return true
|
||||
}
|
||||
|
||||
default:
|
||||
ErrorLogF("Invalid gradient %v", value)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return gradient.backgroundElement.Set(tag, value)
|
||||
}
|
||||
|
||||
func (point *BackgroundGradientPoint) setValue(value string) bool {
|
||||
var ok bool
|
||||
|
||||
switch elements := strings.Split(value, `:`); len(elements) {
|
||||
case 2:
|
||||
if point.Color, ok = StringToColor(elements[0]); !ok {
|
||||
return false
|
||||
}
|
||||
if point.Pos, ok = StringToSizeUnit(elements[1]); !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
case 1:
|
||||
if point.Color, ok = StringToColor(elements[0]); !ok {
|
||||
return false
|
||||
}
|
||||
point.Pos = AutoSize()
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (gradient *backgroundGradient) writeGradient(session Session, buffer *strings.Builder) bool {
|
||||
|
||||
value, ok := gradient.properties[Gradient]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
points := []BackgroundGradientPoint{}
|
||||
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(value); ok && text != "" {
|
||||
elements := strings.Split(text, `,`)
|
||||
points := make([]BackgroundGradientPoint, len(elements))
|
||||
for i, element := range elements {
|
||||
if !points[i].setValue(element) {
|
||||
ErrorLogF(`Invalid gradient point #%d: "%s"`, i, element)
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ErrorLog(`Invalid gradient: ` + value)
|
||||
return false
|
||||
}
|
||||
|
||||
case []BackgroundGradientPoint:
|
||||
points = value
|
||||
|
||||
case []interface{}:
|
||||
points = make([]BackgroundGradientPoint, len(value))
|
||||
for i, element := range value {
|
||||
switch element := element.(type) {
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(element); ok && text != "" {
|
||||
if !points[i].setValue(text) {
|
||||
ErrorLogF(`Invalid gradient point #%d: "%s"`, i, text)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
ErrorLogF(`Invalid gradient point #%d: "%s"`, i, text)
|
||||
return false
|
||||
}
|
||||
|
||||
case BackgroundGradientPoint:
|
||||
points[i] = element
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(points) > 0 {
|
||||
for i, point := range points {
|
||||
if i > 0 {
|
||||
buffer.WriteString(`, `)
|
||||
}
|
||||
|
||||
buffer.WriteString(point.Color.cssString())
|
||||
if point.Pos.Type != Auto {
|
||||
buffer.WriteRune(' ')
|
||||
buffer.WriteString(point.Pos.cssString(""))
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (gradient *backgroundLinearGradient) Tag() string {
|
||||
return "linear-gradient"
|
||||
}
|
||||
|
||||
func (image *backgroundLinearGradient) Clone() BackgroundElement {
|
||||
result := NewBackgroundLinearGradient(nil)
|
||||
for tag, value := range image.properties {
|
||||
result.setRaw(tag, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gradient *backgroundLinearGradient) Set(tag string, value interface{}) bool {
|
||||
if strings.ToLower(tag) == Direction {
|
||||
switch value := value.(type) {
|
||||
case AngleUnit:
|
||||
gradient.properties[Direction] = value
|
||||
return true
|
||||
|
||||
case string:
|
||||
var angle AngleUnit
|
||||
if ok, _ := angle.setValue(value); ok {
|
||||
gradient.properties[Direction] = angle
|
||||
return true
|
||||
}
|
||||
}
|
||||
return gradient.setEnumProperty(tag, value, enumProperties[Direction].values)
|
||||
}
|
||||
|
||||
return gradient.backgroundGradient.Set(tag, value)
|
||||
}
|
||||
|
||||
func (gradient *backgroundLinearGradient) cssStyle(session Session) string {
|
||||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
if repeating, _ := boolProperty(gradient, Repeating, session); repeating {
|
||||
buffer.WriteString(`repeating-linear-gradient(`)
|
||||
} else {
|
||||
buffer.WriteString(`linear-gradient(`)
|
||||
}
|
||||
|
||||
if value, ok := gradient.properties[Direction]; ok {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(value); ok {
|
||||
direction := enumProperties[Direction]
|
||||
if n, ok := enumStringToInt(text, direction.values, false); ok {
|
||||
buffer.WriteString(direction.cssValues[n])
|
||||
buffer.WriteString(", ")
|
||||
} else {
|
||||
if angle, ok := StringToAngleUnit(text); ok {
|
||||
buffer.WriteString(angle.cssString())
|
||||
buffer.WriteString(", ")
|
||||
} else {
|
||||
ErrorLog(`Invalid linear gradient direction: ` + text)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ErrorLog(`Invalid linear gradient direction: ` + value)
|
||||
}
|
||||
|
||||
case int:
|
||||
values := enumProperties[Direction].cssValues
|
||||
if value >= 0 && value < len(values) {
|
||||
buffer.WriteString(values[value])
|
||||
buffer.WriteString(", ")
|
||||
} else {
|
||||
ErrorLogF(`Invalid linear gradient direction: %d`, value)
|
||||
}
|
||||
|
||||
case AngleUnit:
|
||||
buffer.WriteString(value.cssString())
|
||||
buffer.WriteString(", ")
|
||||
}
|
||||
}
|
||||
|
||||
if !gradient.writeGradient(session, buffer) {
|
||||
return ""
|
||||
}
|
||||
|
||||
buffer.WriteString(") ")
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) Tag() string {
|
||||
return "radial-gradient"
|
||||
}
|
||||
|
||||
func (image *backgroundRadialGradient) Clone() BackgroundElement {
|
||||
result := NewBackgroundRadialGradient(nil)
|
||||
for tag, value := range image.properties {
|
||||
result.setRaw(tag, value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) normalizeTag(tag string) string {
|
||||
tag = strings.ToLower(tag)
|
||||
switch tag {
|
||||
case Radius:
|
||||
tag = RadialGradientRadius
|
||||
|
||||
case Shape:
|
||||
tag = RadialGradientShape
|
||||
|
||||
case "x-center":
|
||||
tag = CenterX
|
||||
|
||||
case "y-center":
|
||||
tag = CenterY
|
||||
}
|
||||
|
||||
return tag
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) Set(tag string, value interface{}) bool {
|
||||
tag = gradient.normalizeTag(tag)
|
||||
switch tag {
|
||||
case RadialGradientRadius:
|
||||
switch value := value.(type) {
|
||||
case string, SizeUnit:
|
||||
return gradient.propertyList.Set(RadialGradientRadius, value)
|
||||
|
||||
case int:
|
||||
n := value
|
||||
if n >= 0 && n < len(enumProperties[RadialGradientRadius].values) {
|
||||
return gradient.propertyList.Set(RadialGradientRadius, value)
|
||||
}
|
||||
}
|
||||
ErrorLogF(`Invalid value of "%s" property: %v`, tag, value)
|
||||
|
||||
case RadialGradientShape:
|
||||
return gradient.propertyList.Set(RadialGradientShape, value)
|
||||
|
||||
case CenterX, CenterY:
|
||||
return gradient.propertyList.Set(tag, value)
|
||||
}
|
||||
|
||||
return gradient.backgroundGradient.Set(tag, value)
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) Get(tag string) interface{} {
|
||||
return gradient.backgroundGradient.Get(gradient.normalizeTag(tag))
|
||||
}
|
||||
|
||||
func (gradient *backgroundRadialGradient) cssStyle(session Session) string {
|
||||
buffer := allocStringBuilder()
|
||||
defer freeStringBuilder(buffer)
|
||||
|
||||
if repeating, _ := boolProperty(gradient, Repeating, session); repeating {
|
||||
buffer.WriteString(`repeating-radial-gradient(`)
|
||||
} else {
|
||||
buffer.WriteString(`radial-gradient(`)
|
||||
}
|
||||
|
||||
if shape, ok := enumProperty(gradient, RadialGradientShape, session, EllipseGradient); ok && shape == CircleGradient {
|
||||
buffer.WriteString(`circle `)
|
||||
} else {
|
||||
buffer.WriteString(`ellipse `)
|
||||
}
|
||||
|
||||
if value, ok := gradient.properties[RadialGradientRadius]; ok {
|
||||
switch value := value.(type) {
|
||||
case string:
|
||||
if text, ok := session.resolveConstants(value); ok {
|
||||
values := enumProperties[RadialGradientRadius]
|
||||
if n, ok := enumStringToInt(text, values.values, false); ok {
|
||||
buffer.WriteString(values.cssValues[n])
|
||||
buffer.WriteString(" ")
|
||||
} else {
|
||||
if r, ok := StringToSizeUnit(text); ok && r.Type != Auto {
|
||||
buffer.WriteString(r.cssString(""))
|
||||
buffer.WriteString(" ")
|
||||
} else {
|
||||
ErrorLog(`Invalid radial gradient radius: ` + text)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ErrorLog(`Invalid radial gradient radius: ` + value)
|
||||
}
|
||||
|
||||
case int:
|
||||
values := enumProperties[RadialGradientRadius].cssValues
|
||||
if value >= 0 && value < len(values) {
|
||||
buffer.WriteString(values[value])
|
||||
buffer.WriteString(" ")
|
||||
} else {
|
||||
ErrorLogF(`Invalid radial gradient radius: %d`, value)
|
||||
}
|
||||
|
||||
case SizeUnit:
|
||||
if value.Type != Auto {
|
||||
buffer.WriteString(value.cssString(""))
|
||||
buffer.WriteString(" ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x, _ := sizeProperty(gradient, CenterX, session)
|
||||
y, _ := sizeProperty(gradient, CenterX, session)
|
||||
if x.Type != Auto || y.Type != Auto {
|
||||
buffer.WriteString("at ")
|
||||
buffer.WriteString(x.cssString("50%"))
|
||||
buffer.WriteString(" ")
|
||||
buffer.WriteString(y.cssString("50%"))
|
||||
}
|
||||
|
||||
buffer.WriteString(", ")
|
||||
if !gradient.writeGradient(session, buffer) {
|
||||
return ""
|
||||
}
|
||||
|
||||
buffer.WriteString(") ")
|
||||
|
||||
return buffer.String()
|
||||
}
|
|
@ -359,6 +359,8 @@ const (
|
|||
Direction = "direction"
|
||||
// Repeating is the constant for the "repeating" property tag.
|
||||
Repeating = "repeating"
|
||||
// Repeating is the constant for the "repeating" property tag.
|
||||
From = "from"
|
||||
// RadialGradientRadius is the constant for the "radial-gradient-radius" property tag.
|
||||
RadialGradientRadius = "radial-gradient-radius"
|
||||
// RadialGradientShape is the constant for the "radial-gradient-shape" property tag.
|
||||
|
|
|
@ -33,6 +33,7 @@ var angleProperties = []string{
|
|||
Rotate,
|
||||
SkewX,
|
||||
SkewY,
|
||||
From,
|
||||
}
|
||||
|
||||
var boolProperties = []string{
|
||||
|
@ -58,6 +59,7 @@ var boolProperties = []string{
|
|||
AnimationPaused,
|
||||
Multiple,
|
||||
TabCloseButton,
|
||||
Repeating,
|
||||
}
|
||||
|
||||
var intProperties = []string{
|
||||
|
|
Loading…
Reference in New Issue