set.go

  1package lipgloss
  2
  3import "image/color"
  4
  5// Set a value on the underlying rules map.
  6func (s *Style) set(key propKey, value any) {
  7	// We don't allow negative integers on any of our other values, so just keep
  8	// them at zero or above. We could use uints instead, but the
  9	// conversions are a little tedious, so we're sticking with ints for
 10	// sake of usability.
 11	switch key { //nolint:exhaustive
 12	case foregroundKey:
 13		s.fgColor = colorOrNil(value)
 14	case backgroundKey:
 15		s.bgColor = colorOrNil(value)
 16	case widthKey:
 17		s.width = max(0, value.(int))
 18	case heightKey:
 19		s.height = max(0, value.(int))
 20	case alignHorizontalKey:
 21		s.alignHorizontal = value.(Position)
 22	case alignVerticalKey:
 23		s.alignVertical = value.(Position)
 24	case paddingTopKey:
 25		s.paddingTop = max(0, value.(int))
 26	case paddingRightKey:
 27		s.paddingRight = max(0, value.(int))
 28	case paddingBottomKey:
 29		s.paddingBottom = max(0, value.(int))
 30	case paddingLeftKey:
 31		s.paddingLeft = max(0, value.(int))
 32	case paddingCharKey:
 33		s.paddingChar = value.(rune)
 34	case marginTopKey:
 35		s.marginTop = max(0, value.(int))
 36	case marginRightKey:
 37		s.marginRight = max(0, value.(int))
 38	case marginBottomKey:
 39		s.marginBottom = max(0, value.(int))
 40	case marginLeftKey:
 41		s.marginLeft = max(0, value.(int))
 42	case marginBackgroundKey:
 43		s.marginBgColor = colorOrNil(value)
 44	case marginCharKey:
 45		s.marginChar = value.(rune)
 46	case borderStyleKey:
 47		s.borderStyle = value.(Border)
 48	case borderTopForegroundKey:
 49		s.borderTopFgColor = colorOrNil(value)
 50	case borderRightForegroundKey:
 51		s.borderRightFgColor = colorOrNil(value)
 52	case borderBottomForegroundKey:
 53		s.borderBottomFgColor = colorOrNil(value)
 54	case borderLeftForegroundKey:
 55		s.borderLeftFgColor = colorOrNil(value)
 56	case borderTopBackgroundKey:
 57		s.borderTopBgColor = colorOrNil(value)
 58	case borderRightBackgroundKey:
 59		s.borderRightBgColor = colorOrNil(value)
 60	case borderBottomBackgroundKey:
 61		s.borderBottomBgColor = colorOrNil(value)
 62	case borderLeftBackgroundKey:
 63		s.borderLeftBgColor = colorOrNil(value)
 64	case maxWidthKey:
 65		s.maxWidth = max(0, value.(int))
 66	case maxHeightKey:
 67		s.maxHeight = max(0, value.(int))
 68	case tabWidthKey:
 69		// TabWidth is the only property that may have a negative value (and
 70		// that negative value can be no less than -1).
 71		s.tabWidth = value.(int)
 72	case transformKey:
 73		s.transform = value.(func(string) string)
 74	default:
 75		if v, ok := value.(bool); ok { //nolint:nestif
 76			if v {
 77				s.attrs |= int(key)
 78			} else {
 79				s.attrs &^= int(key)
 80			}
 81		} else if attrs, ok := value.(int); ok {
 82			// bool attrs
 83			if attrs&int(key) != 0 {
 84				s.attrs |= int(key)
 85			} else {
 86				s.attrs &^= int(key)
 87			}
 88		}
 89	}
 90
 91	// Set the prop on
 92	s.props = s.props.set(key)
 93}
 94
 95// setFrom sets the property from another style.
 96func (s *Style) setFrom(key propKey, i Style) {
 97	switch key { //nolint:exhaustive
 98	case foregroundKey:
 99		s.set(foregroundKey, i.fgColor)
100	case backgroundKey:
101		s.set(backgroundKey, i.bgColor)
102	case widthKey:
103		s.set(widthKey, i.width)
104	case heightKey:
105		s.set(heightKey, i.height)
106	case alignHorizontalKey:
107		s.set(alignHorizontalKey, i.alignHorizontal)
108	case alignVerticalKey:
109		s.set(alignVerticalKey, i.alignVertical)
110	case paddingTopKey:
111		s.set(paddingTopKey, i.paddingTop)
112	case paddingRightKey:
113		s.set(paddingRightKey, i.paddingRight)
114	case paddingBottomKey:
115		s.set(paddingBottomKey, i.paddingBottom)
116	case paddingLeftKey:
117		s.set(paddingLeftKey, i.paddingLeft)
118	case paddingCharKey:
119		s.set(paddingCharKey, i.paddingChar)
120	case marginTopKey:
121		s.set(marginTopKey, i.marginTop)
122	case marginRightKey:
123		s.set(marginRightKey, i.marginRight)
124	case marginBottomKey:
125		s.set(marginBottomKey, i.marginBottom)
126	case marginLeftKey:
127		s.set(marginLeftKey, i.marginLeft)
128	case marginBackgroundKey:
129		s.set(marginBackgroundKey, i.marginBgColor)
130	case marginCharKey:
131		s.set(marginCharKey, i.marginChar)
132	case borderStyleKey:
133		s.set(borderStyleKey, i.borderStyle)
134	case borderTopForegroundKey:
135		s.set(borderTopForegroundKey, i.borderTopFgColor)
136	case borderRightForegroundKey:
137		s.set(borderRightForegroundKey, i.borderRightFgColor)
138	case borderBottomForegroundKey:
139		s.set(borderBottomForegroundKey, i.borderBottomFgColor)
140	case borderLeftForegroundKey:
141		s.set(borderLeftForegroundKey, i.borderLeftFgColor)
142	case borderTopBackgroundKey:
143		s.set(borderTopBackgroundKey, i.borderTopBgColor)
144	case borderRightBackgroundKey:
145		s.set(borderRightBackgroundKey, i.borderRightBgColor)
146	case borderBottomBackgroundKey:
147		s.set(borderBottomBackgroundKey, i.borderBottomBgColor)
148	case borderLeftBackgroundKey:
149		s.set(borderLeftBackgroundKey, i.borderLeftBgColor)
150	case maxWidthKey:
151		s.set(maxWidthKey, i.maxWidth)
152	case maxHeightKey:
153		s.set(maxHeightKey, i.maxHeight)
154	case tabWidthKey:
155		s.set(tabWidthKey, i.tabWidth)
156	case transformKey:
157		s.set(transformKey, i.transform)
158	default:
159		// Set attributes for set bool properties
160		s.set(key, i.attrs)
161	}
162}
163
164func colorOrNil(c any) color.Color {
165	if c, ok := c.(color.Color); ok {
166		return c
167	}
168	return nil
169}
170
171// Bold sets a bold formatting rule.
172func (s Style) Bold(v bool) Style {
173	s.set(boldKey, v)
174	return s
175}
176
177// Italic sets an italic formatting rule. In some terminal emulators this will
178// render with "reverse" coloring if not italic font variant is available.
179func (s Style) Italic(v bool) Style {
180	s.set(italicKey, v)
181	return s
182}
183
184// Underline sets an underline rule. By default, underlines will not be drawn on
185// whitespace like margins and padding. To change this behavior set
186// [Style.UnderlineSpaces].
187func (s Style) Underline(v bool) Style {
188	s.set(underlineKey, v)
189	return s
190}
191
192// Strikethrough sets a strikethrough rule. By default, strikes will not be
193// drawn on whitespace like margins and padding. To change this behavior set
194// StrikethroughSpaces.
195func (s Style) Strikethrough(v bool) Style {
196	s.set(strikethroughKey, v)
197	return s
198}
199
200// Reverse sets a rule for inverting foreground and background colors.
201func (s Style) Reverse(v bool) Style {
202	s.set(reverseKey, v)
203	return s
204}
205
206// Blink sets a rule for blinking foreground text.
207func (s Style) Blink(v bool) Style {
208	s.set(blinkKey, v)
209	return s
210}
211
212// Faint sets a rule for rendering the foreground color in a dimmer shade.
213func (s Style) Faint(v bool) Style {
214	s.set(faintKey, v)
215	return s
216}
217
218// Foreground sets a foreground color.
219//
220//	// Sets the foreground to blue
221//	s := lipgloss.NewStyle().Foreground(lipgloss.Color("#0000ff"))
222//
223//	// Removes the foreground color
224//	s.Foreground(lipgloss.NoColor)
225func (s Style) Foreground(c color.Color) Style {
226	s.set(foregroundKey, c)
227	return s
228}
229
230// Background sets a background color.
231func (s Style) Background(c color.Color) Style {
232	s.set(backgroundKey, c)
233	return s
234}
235
236// Width sets the width of the block before applying margins. This means your
237// styled content will exactly equal the size set here. Text will wrap based on
238// Padding and Borders set on the style.
239func (s Style) Width(i int) Style {
240	s.set(widthKey, i)
241	return s
242}
243
244// Height sets the height of the block before applying margins. If the height of
245// the text block is less than this value after applying padding (or not), the
246// block will be set to this height.
247func (s Style) Height(i int) Style {
248	s.set(heightKey, i)
249	return s
250}
251
252// Align is a shorthand method for setting horizontal and vertical alignment.
253//
254// With one argument, the position value is applied to the horizontal alignment.
255//
256// With two arguments, the value is applied to the horizontal and vertical
257// alignments, in that order.
258func (s Style) Align(p ...Position) Style {
259	if len(p) > 0 {
260		s.set(alignHorizontalKey, p[0])
261	}
262	if len(p) > 1 {
263		s.set(alignVerticalKey, p[1])
264	}
265	return s
266}
267
268// AlignHorizontal sets a horizontal text alignment rule.
269func (s Style) AlignHorizontal(p Position) Style {
270	s.set(alignHorizontalKey, p)
271	return s
272}
273
274// AlignVertical sets a vertical text alignment rule.
275func (s Style) AlignVertical(p Position) Style {
276	s.set(alignVerticalKey, p)
277	return s
278}
279
280// Padding is a shorthand method for setting padding on all sides at once.
281//
282// With one argument, the value is applied to all sides.
283//
284// With two arguments, the value is applied to the vertical and horizontal
285// sides, in that order.
286//
287// With three arguments, the value is applied to the top side, the horizontal
288// sides, and the bottom side, in that order.
289//
290// With four arguments, the value is applied clockwise starting from the top
291// side, followed by the right side, then the bottom, and finally the left.
292//
293// With more than four arguments no padding will be added.
294func (s Style) Padding(i ...int) Style {
295	top, right, bottom, left, ok := whichSidesInt(i...)
296	if !ok {
297		return s
298	}
299
300	s.set(paddingTopKey, top)
301	s.set(paddingRightKey, right)
302	s.set(paddingBottomKey, bottom)
303	s.set(paddingLeftKey, left)
304	return s
305}
306
307// PaddingLeft adds padding on the left.
308func (s Style) PaddingLeft(i int) Style {
309	s.set(paddingLeftKey, i)
310	return s
311}
312
313// PaddingRight adds padding on the right.
314func (s Style) PaddingRight(i int) Style {
315	s.set(paddingRightKey, i)
316	return s
317}
318
319// PaddingTop adds padding to the top of the block.
320func (s Style) PaddingTop(i int) Style {
321	s.set(paddingTopKey, i)
322	return s
323}
324
325// PaddingBottom adds padding to the bottom of the block.
326func (s Style) PaddingBottom(i int) Style {
327	s.set(paddingBottomKey, i)
328	return s
329}
330
331// PaddingChar sets the character used for padding. This is useful for
332// rendering blocks with a specific character, such as a space or a dot.
333// Example of using [NBSP] as padding to prevent line breaks:
334//
335//	```go
336//	s := lipgloss.NewStyle().PaddingChar(lipgloss.NBSP)
337//	```
338func (s Style) PaddingChar(r rune) Style {
339	s.set(paddingCharKey, r)
340	return s
341}
342
343// ColorWhitespace determines whether or not the background color should be
344// applied to the padding. This is true by default as it's more than likely the
345// desired and expected behavior, but it can be disabled for certain graphic
346// effects.
347//
348// Deprecated: Just use margins and padding.
349func (s Style) ColorWhitespace(v bool) Style {
350	s.set(colorWhitespaceKey, v)
351	return s
352}
353
354// Margin is a shorthand method for setting margins on all sides at once.
355//
356// With one argument, the value is applied to all sides.
357//
358// With two arguments, the value is applied to the vertical and horizontal
359// sides, in that order.
360//
361// With three arguments, the value is applied to the top side, the horizontal
362// sides, and the bottom side, in that order.
363//
364// With four arguments, the value is applied clockwise starting from the top
365// side, followed by the right side, then the bottom, and finally the left.
366//
367// With more than four arguments no margin will be added.
368func (s Style) Margin(i ...int) Style {
369	top, right, bottom, left, ok := whichSidesInt(i...)
370	if !ok {
371		return s
372	}
373
374	s.set(marginTopKey, top)
375	s.set(marginRightKey, right)
376	s.set(marginBottomKey, bottom)
377	s.set(marginLeftKey, left)
378	return s
379}
380
381// MarginLeft sets the value of the left margin.
382func (s Style) MarginLeft(i int) Style {
383	s.set(marginLeftKey, i)
384	return s
385}
386
387// MarginRight sets the value of the right margin.
388func (s Style) MarginRight(i int) Style {
389	s.set(marginRightKey, i)
390	return s
391}
392
393// MarginTop sets the value of the top margin.
394func (s Style) MarginTop(i int) Style {
395	s.set(marginTopKey, i)
396	return s
397}
398
399// MarginBottom sets the value of the bottom margin.
400func (s Style) MarginBottom(i int) Style {
401	s.set(marginBottomKey, i)
402	return s
403}
404
405// MarginBackground sets the background color of the margin. Note that this is
406// also set when inheriting from a style with a background color. In that case
407// the background color on that style will set the margin color on this style.
408func (s Style) MarginBackground(c color.Color) Style {
409	s.set(marginBackgroundKey, c)
410	return s
411}
412
413// MarginChar sets the character used for the margin. This is useful for
414// rendering blocks with a specific character, such as a space or a dot.
415func (s Style) MarginChar(r rune) Style {
416	s.set(marginCharKey, r)
417	return s
418}
419
420// Border is shorthand for setting the border style and which sides should
421// have a border at once. The variadic argument sides works as follows:
422//
423// With one value, the value is applied to all sides.
424//
425// With two values, the values are applied to the vertical and horizontal
426// sides, in that order.
427//
428// With three values, the values are applied to the top side, the horizontal
429// sides, and the bottom side, in that order.
430//
431// With four values, the values are applied clockwise starting from the top
432// side, followed by the right side, then the bottom, and finally the left.
433//
434// With more than four arguments the border will be applied to all sides.
435//
436// Examples:
437//
438//	// Applies borders to the top and bottom only
439//	lipgloss.NewStyle().Border(lipgloss.NormalBorder(), true, false)
440//
441//	// Applies rounded borders to the right and bottom only
442//	lipgloss.NewStyle().Border(lipgloss.RoundedBorder(), false, true, true, false)
443func (s Style) Border(b Border, sides ...bool) Style {
444	s.set(borderStyleKey, b)
445
446	top, right, bottom, left, ok := whichSidesBool(sides...)
447	if !ok {
448		top = true
449		right = true
450		bottom = true
451		left = true
452	}
453
454	s.set(borderTopKey, top)
455	s.set(borderRightKey, right)
456	s.set(borderBottomKey, bottom)
457	s.set(borderLeftKey, left)
458
459	return s
460}
461
462// BorderStyle defines the Border on a style. A Border contains a series of
463// definitions for the sides and corners of a border.
464//
465// Note that if border visibility has not been set for any sides when setting
466// the border style, the border will be enabled for all sides during rendering.
467//
468// You can define border characters as you'd like, though several default
469// styles are included: NormalBorder(), RoundedBorder(), BlockBorder(),
470// OuterHalfBlockBorder(), InnerHalfBlockBorder(), ThickBorder(),
471// and DoubleBorder().
472//
473// Example:
474//
475//	lipgloss.NewStyle().BorderStyle(lipgloss.ThickBorder())
476func (s Style) BorderStyle(b Border) Style {
477	s.set(borderStyleKey, b)
478	return s
479}
480
481// BorderTop determines whether or not to draw a top border.
482func (s Style) BorderTop(v bool) Style {
483	s.set(borderTopKey, v)
484	return s
485}
486
487// BorderRight determines whether or not to draw a right border.
488func (s Style) BorderRight(v bool) Style {
489	s.set(borderRightKey, v)
490	return s
491}
492
493// BorderBottom determines whether or not to draw a bottom border.
494func (s Style) BorderBottom(v bool) Style {
495	s.set(borderBottomKey, v)
496	return s
497}
498
499// BorderLeft determines whether or not to draw a left border.
500func (s Style) BorderLeft(v bool) Style {
501	s.set(borderLeftKey, v)
502	return s
503}
504
505// BorderForeground is a shorthand function for setting all of the
506// foreground colors of the borders at once. The arguments work as follows:
507//
508// With one argument, the argument is applied to all sides.
509//
510// With two arguments, the arguments are applied to the vertical and horizontal
511// sides, in that order.
512//
513// With three arguments, the arguments are applied to the top side, the
514// horizontal sides, and the bottom side, in that order.
515//
516// With four arguments, the arguments are applied clockwise starting from the
517// top side, followed by the right side, then the bottom, and finally the left.
518//
519// With more than four arguments nothing will be set.
520func (s Style) BorderForeground(c ...color.Color) Style {
521	if len(c) == 0 {
522		return s
523	}
524
525	top, right, bottom, left, ok := whichSidesColor(c...)
526	if !ok {
527		return s
528	}
529
530	s.set(borderTopForegroundKey, top)
531	s.set(borderRightForegroundKey, right)
532	s.set(borderBottomForegroundKey, bottom)
533	s.set(borderLeftForegroundKey, left)
534
535	return s
536}
537
538// BorderTopForeground set the foreground color for the top of the border.
539func (s Style) BorderTopForeground(c color.Color) Style {
540	s.set(borderTopForegroundKey, c)
541	return s
542}
543
544// BorderRightForeground sets the foreground color for the right side of the
545// border.
546func (s Style) BorderRightForeground(c color.Color) Style {
547	s.set(borderRightForegroundKey, c)
548	return s
549}
550
551// BorderBottomForeground sets the foreground color for the bottom of the
552// border.
553func (s Style) BorderBottomForeground(c color.Color) Style {
554	s.set(borderBottomForegroundKey, c)
555	return s
556}
557
558// BorderLeftForeground sets the foreground color for the left side of the
559// border.
560func (s Style) BorderLeftForeground(c color.Color) Style {
561	s.set(borderLeftForegroundKey, c)
562	return s
563}
564
565// BorderBackground is a shorthand function for setting all of the
566// background colors of the borders at once. The arguments work as follows:
567//
568// With one argument, the argument is applied to all sides.
569//
570// With two arguments, the arguments are applied to the vertical and horizontal
571// sides, in that order.
572//
573// With three arguments, the arguments are applied to the top side, the
574// horizontal sides, and the bottom side, in that order.
575//
576// With four arguments, the arguments are applied clockwise starting from the
577// top side, followed by the right side, then the bottom, and finally the left.
578//
579// With more than four arguments nothing will be set.
580func (s Style) BorderBackground(c ...color.Color) Style {
581	if len(c) == 0 {
582		return s
583	}
584
585	top, right, bottom, left, ok := whichSidesColor(c...)
586	if !ok {
587		return s
588	}
589
590	s.set(borderTopBackgroundKey, top)
591	s.set(borderRightBackgroundKey, right)
592	s.set(borderBottomBackgroundKey, bottom)
593	s.set(borderLeftBackgroundKey, left)
594
595	return s
596}
597
598// BorderTopBackground sets the background color of the top of the border.
599func (s Style) BorderTopBackground(c color.Color) Style {
600	s.set(borderTopBackgroundKey, c)
601	return s
602}
603
604// BorderRightBackground sets the background color of right side the border.
605func (s Style) BorderRightBackground(c color.Color) Style {
606	s.set(borderRightBackgroundKey, c)
607	return s
608}
609
610// BorderBottomBackground sets the background color of the bottom of the
611// border.
612func (s Style) BorderBottomBackground(c color.Color) Style {
613	s.set(borderBottomBackgroundKey, c)
614	return s
615}
616
617// BorderLeftBackground set the background color of the left side of the
618// border.
619func (s Style) BorderLeftBackground(c color.Color) Style {
620	s.set(borderLeftBackgroundKey, c)
621	return s
622}
623
624// Inline makes rendering output one line and disables the rendering of
625// margins, padding and borders. This is useful when you need a style to apply
626// only to font rendering and don't want it to change any physical dimensions.
627// It works well with Style.MaxWidth.
628//
629// Because this in intended to be used at the time of render, this method will
630// not mutate the style and instead return a copy.
631//
632// Example:
633//
634//	var userInput string = "..."
635//	var userStyle = text.Style{ /* ... */ }
636//	fmt.Println(userStyle.Inline(true).Render(userInput))
637func (s Style) Inline(v bool) Style {
638	o := s // copy
639	o.set(inlineKey, v)
640	return o
641}
642
643// MaxWidth applies a max width to a given style. This is useful in enforcing
644// a certain width at render time, particularly with arbitrary strings and
645// styles.
646//
647// Because this in intended to be used at the time of render, this method will
648// not mutate the style and instead return a copy.
649//
650// Example:
651//
652//	var userInput string = "..."
653//	var userStyle = text.Style{ /* ... */ }
654//	fmt.Println(userStyle.MaxWidth(16).Render(userInput))
655func (s Style) MaxWidth(n int) Style {
656	o := s // copy
657	o.set(maxWidthKey, n)
658	return o
659}
660
661// MaxHeight applies a max height to a given style. This is useful in enforcing
662// a certain height at render time, particularly with arbitrary strings and
663// styles.
664//
665// Because this in intended to be used at the time of render, this method will
666// not mutate the style and instead returns a copy.
667func (s Style) MaxHeight(n int) Style {
668	o := s // copy
669	o.set(maxHeightKey, n)
670	return o
671}
672
673// NoTabConversion can be passed to [Style.TabWidth] to disable the replacement
674// of tabs with spaces at render time.
675const NoTabConversion = -1
676
677// TabWidth sets the number of spaces that a tab (/t) should be rendered as.
678// When set to 0, tabs will be removed. To disable the replacement of tabs with
679// spaces entirely, set this to [NoTabConversion].
680//
681// By default, tabs will be replaced with 4 spaces.
682func (s Style) TabWidth(n int) Style {
683	if n <= -1 {
684		n = -1
685	}
686	s.set(tabWidthKey, n)
687	return s
688}
689
690// UnderlineSpaces determines whether to underline spaces between words. By
691// default, this is true. Spaces can also be underlined without underlining the
692// text itself.
693func (s Style) UnderlineSpaces(v bool) Style {
694	s.set(underlineSpacesKey, v)
695	return s
696}
697
698// StrikethroughSpaces determines whether to apply strikethroughs to spaces
699// between words. By default, this is true. Spaces can also be struck without
700// underlining the text itself.
701func (s Style) StrikethroughSpaces(v bool) Style {
702	s.set(strikethroughSpacesKey, v)
703	return s
704}
705
706// Transform applies a given function to a string at render time, allowing for
707// the string being rendered to be manipuated.
708//
709// Example:
710//
711//	s := NewStyle().Transform(strings.ToUpper)
712//	fmt.Println(s.Render("raow!") // "RAOW!"
713func (s Style) Transform(fn func(string) string) Style {
714	s.set(transformKey, fn)
715	return s
716}
717
718// whichSidesInt is a helper method for setting values on sides of a block based
719// on the number of arguments. It follows the CSS shorthand rules for blocks
720// like margin, padding. and borders. Here are how the rules work:
721//
722// 0 args:  do nothing
723// 1 arg:   all sides
724// 2 args:  top -> bottom
725// 3 args:  top -> horizontal -> bottom
726// 4 args:  top -> right -> bottom -> left
727// 5+ args: do nothing.
728func whichSidesInt(i ...int) (top, right, bottom, left int, ok bool) {
729	switch len(i) {
730	case 1:
731		top = i[0]
732		bottom = i[0]
733		left = i[0]
734		right = i[0]
735		ok = true
736	case 2: //nolint:mnd
737		top = i[0]
738		bottom = i[0]
739		left = i[1]
740		right = i[1]
741		ok = true
742	case 3: //nolint:mnd
743		top = i[0]
744		left = i[1]
745		right = i[1]
746		bottom = i[2]
747		ok = true
748	case 4: //nolint:mnd
749		top = i[0]
750		right = i[1]
751		bottom = i[2]
752		left = i[3]
753		ok = true
754	}
755	return top, right, bottom, left, ok
756}
757
758// whichSidesBool is like whichSidesInt, except it operates on a series of
759// boolean values. See the comment on whichSidesInt for details on how this
760// works.
761func whichSidesBool(i ...bool) (top, right, bottom, left bool, ok bool) {
762	switch len(i) {
763	case 1:
764		top = i[0]
765		bottom = i[0]
766		left = i[0]
767		right = i[0]
768		ok = true
769	case 2: //nolint:mnd
770		top = i[0]
771		bottom = i[0]
772		left = i[1]
773		right = i[1]
774		ok = true
775	case 3: //nolint:mnd
776		top = i[0]
777		left = i[1]
778		right = i[1]
779		bottom = i[2]
780		ok = true
781	case 4: //nolint:mnd
782		top = i[0]
783		right = i[1]
784		bottom = i[2]
785		left = i[3]
786		ok = true
787	}
788	return top, right, bottom, left, ok
789}
790
791// whichSidesColor is like whichSides, except it operates on a series of
792// boolean values. See the comment on whichSidesInt for details on how this
793// works.
794func whichSidesColor(i ...color.Color) (top, right, bottom, left color.Color, ok bool) {
795	switch len(i) {
796	case 1:
797		top = i[0]
798		bottom = i[0]
799		left = i[0]
800		right = i[0]
801		ok = true
802	case 2: //nolint:mnd
803		top = i[0]
804		bottom = i[0]
805		left = i[1]
806		right = i[1]
807		ok = true
808	case 3: //nolint:mnd
809		top = i[0]
810		left = i[1]
811		right = i[1]
812		bottom = i[2]
813		ok = true
814	case 4: //nolint:mnd
815		top = i[0]
816		right = i[1]
817		bottom = i[2]
818		left = i[3]
819		ok = true
820	}
821	return top, right, bottom, left, ok
822}