mirror of https://github.com/anoshenko/rui.git
				
				
				
			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