From 05a5e683ffc873418efc3f6b22f01102558b3afc Mon Sep 17 00:00:00 2001 From: Chris Watson Date: Wed, 20 Nov 2024 05:17:53 -0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20gradient=20background?= =?UTF-8?q?=20support=20with=20multiple=20gradient=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit adds support for various gradient backgrounds including linear, radial, angular, diamond, spiral, square, and star patterns. Each gradient can be customized with stops, angle, center position and intensity. --- cmd/goshot/main.go | 85 ++++++++++++++++++++++++++++++++++++++ pkg/background/gradient.go | 5 ++- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/cmd/goshot/main.go b/cmd/goshot/main.go index f4b3824..c60097a 100644 --- a/cmd/goshot/main.go +++ b/cmd/goshot/main.go @@ -41,6 +41,14 @@ var ( windowTitle string windowCornerRadius float64 + // Gradient stuff + gradientType string + gradientStops []string + gradientAngle float64 + gradientCenterX float64 + gradientCenterY float64 + gradientIntensity float64 + // Padding and layout tabWidth int startLine int @@ -95,6 +103,14 @@ func init() { renderCmd.Flags().StringVar(&windowTitle, "window-title", "", "Show window title") renderCmd.Flags().Float64Var(&windowCornerRadius, "window-corner-radius", 10, "Corner radius of the window") + // Gradient flags + renderCmd.Flags().StringVar(&gradientType, "gradient-type", "linear", "Gradient type. Available types: linear, radial") + renderCmd.Flags().StringArrayVar(&gradientStops, "gradient-stop", []string{"#232323;0", "#383838;100"}, "Gradient stops. eg. '--gradient-stop '#ff0000;0' --gradient-stop '#00ff00;100'") + renderCmd.Flags().Float64Var(&gradientAngle, "gradient-angle", 90, "Gradient angle in degrees") + renderCmd.Flags().Float64Var(&gradientCenterX, "gradient-center-x", 0.5, "Center X of the gradient") + renderCmd.Flags().Float64Var(&gradientCenterY, "gradient-center-y", 0.5, "Center Y of the gradient") + renderCmd.Flags().Float64Var(&gradientIntensity, "gradient-intensity", 5, "Intensity modifier for special gradients") + // Padding and layout flags renderCmd.Flags().IntVar(&tabWidth, "tab-width", 4, "Tab width") renderCmd.Flags().IntVar(&startLine, "start-line", 1, "Line to start from") @@ -260,6 +276,40 @@ func renderImage(cmd *cobra.Command, args []string) { return } bg = background.NewImageBackground(backgroundImage).SetScaleMode(fit) + } else if gradientType != "" { + stops, err := parseGradientStops(gradientStops) + if err != nil { + fmt.Printf("invalid gradient stops: %v", err) + return + } + + var gradient background.GradientType + switch gradientType { + case "linear": + gradient = background.LinearGradient + case "radial": + gradient = background.RadialGradient + case "angular": + gradient = background.AngularGradient + case "diamond": + gradient = background.DiamondGradient + case "spiral": + gradient = background.SpiralGradient + case "square": + gradient = background.SquareGradient + case "star": + gradient = background.StarGradient + default: + fmt.Printf("invalid gradient type: %s", gradientType) + return + } + + bg = background.NewGradientBackground(gradient, stops...). + SetAngle(gradientAngle). + SetCenter(gradientCenterX, gradientCenterY). + SetIntensity(gradientIntensity). + SetCenter(gradientCenterX, gradientCenterY). + SetPaddingDetailed(padHoriz, padVert, padVert, padHoriz) } else { bg = background.NewColorBackground(). SetColor(bgColor). @@ -418,3 +468,38 @@ func parseFonts(input string) (string, float64) { return "", 14.0 } + +// parseGradientStops takes in a string slice of gradient stops and returns +// a slice of background.GradientStop. +func parseGradientStops(input []string) ([]background.GradientStop, error) { + var result []background.GradientStop + for _, part := range input { + parts := strings.Split(part, ";") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid gradient stop format: %s", part) + } + + hexColor := strings.TrimSpace(parts[0]) + positionStr := strings.TrimSpace(parts[1]) + + color, err := parseHexColor(hexColor) + if err != nil { + return nil, fmt.Errorf("invalid color in gradient stop: %s", err) + } + + position, err := strconv.ParseFloat(positionStr, 64) + if err != nil { + return nil, fmt.Errorf("invalid position in gradient stop: %s", err) + } + + if position < 0 || position > 100 { + return nil, fmt.Errorf("gradient stop position must be between 0 and 100: %f", position) + } + + result = append(result, background.GradientStop{ + Color: color, + Position: position / 100, // Convert percentage to decimal + }) + } + return result, nil +} diff --git a/pkg/background/gradient.go b/pkg/background/gradient.go index 2104f66..b725284 100644 --- a/pkg/background/gradient.go +++ b/pkg/background/gradient.go @@ -188,7 +188,10 @@ func (bg GradientBackground) Render(content image.Image) image.Image { // Calculate distance from center dx := float64(x) - centerX dy := float64(y) - centerY - pos = math.Sqrt(dx*dx+dy*dy) / (math.Sqrt(centerX*centerX + centerY*centerY)) + // Calculate maximum possible distance from center to any corner + maxDist := math.Sqrt(math.Max(centerX*centerX, math.Pow(float64(width)-centerX, 2)) + + math.Max(centerY*centerY, math.Pow(float64(height)-centerY, 2))) + pos = math.Sqrt(dx*dx+dy*dy) / maxDist case AngularGradient: // Calculate angle from center dx := float64(x) - centerX