summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/pure/colors.nim124
1 files changed, 104 insertions, 20 deletions
diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim
index b58166b05..159bc8023 100644
--- a/lib/pure/colors.nim
+++ b/lib/pure/colors.nim
@@ -13,10 +13,18 @@ import strutils
 from algorithm import binarySearch
 
 type
-  Color* = distinct int ## a color stored as RGB
+  Color* = distinct int ## A color stored as RGB, e.g. `0xff00cc`.
 
 proc `==` *(a, b: Color): bool {.borrow.}
-  ## compares two colors.
+  ## Compares two colors.
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = Color(0xff_00_ff)
+  ##     b = colFuchsia
+  ##     c = Color(0x00_ff_cc)
+  ##   assert a == b
+  ##   assert not a == c
 
 template extract(a: Color, r, g, b: untyped) =
   var r = a.int shr 16 and 0xff
@@ -40,24 +48,58 @@ proc satMinus(a, b: int): int {.inline.} =
   if result < 0: result = 0
 
 proc `+`*(a, b: Color): Color =
-  ## adds two colors: This uses saturated artithmetic, so that each color
+  ## Adds two colors.
+  ##
+  ## This uses saturated artithmetic, so that each color
   ## component cannot overflow (255 is used as a maximum).
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = Color(0xaa_00_ff)
+  ##     b = Color(0x11_cc_cc)
+  ##   assert a + b == Color(0xbb_cc_ff)
+  ##
   colorOp(satPlus)
 
 proc `-`*(a, b: Color): Color =
-  ## subtracts two colors: This uses saturated artithmetic, so that each color
-  ## component cannot overflow (255 is used as a maximum).
+  ## Subtracts two colors.
+  ##
+  ## This uses saturated artithmetic, so that each color
+  ## component cannot underflow (0 is used as a minimum).
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = Color(0xff_33_ff)
+  ##     b = Color(0x11_ff_cc)
+  ##   assert a - b == Color(0xee_00_33)
+  ##
   colorOp(satMinus)
 
 proc extractRGB*(a: Color): tuple[r, g, b: range[0..255]] =
-  ## extracts the red/green/blue components of the color `a`.
+  ## Extracts the red/green/blue components of the color `a`.
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = Color(0xff_00_ff)
+  ##     b = Color(0x00_ff_cc)
+  ##   echo extractRGB(a) # => (r: 255, g: 0, b: 255)
+  ##   echo extractRGB(b) # => (r: 0, g: 255, b: 204)
+  ##
   result.r = a.int shr 16 and 0xff
   result.g = a.int shr 8 and 0xff
   result.b = a.int and 0xff
 
 proc intensity*(a: Color, f: float): Color =
-  ## returns `a` with intensity `f`. `f` should be a float from 0.0 (completely
+  ## Returns `a` with intensity `f`. `f` should be a float from 0.0 (completely
   ## dark) to 1.0 (full color intensity).
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = Color(0xff_00_ff)
+  ##     b = Color(0x00_42_cc)
+  ##   assert a.intensity(0.5) == Color(0x80_00_80)
+  ##   assert b.intensity(0.5) == Color(0x00_21_66)
+  ##
   var r = toInt(toFloat(a.int shr 16 and 0xff) * f)
   var g = toInt(toFloat(a.int shr 8 and 0xff) * f)
   var b = toInt(toFloat(a.int and 0xff) * f)
@@ -67,10 +109,22 @@ proc intensity*(a: Color, f: float): Color =
   result = rawRGB(r, g, b)
 
 template mix*(a, b: Color, fn: untyped): untyped =
-  ## uses `fn` to mix the colors `a` and `b`. `fn` is invoked for each component
-  ## R, G, and B. This is a template because `fn` should be inlined and the
-  ## compiler cannot inline proc pointers yet. If `fn`'s result is not in the
-  ## range[0..255], it will be saturated to be so.
+  ## Uses `fn` to mix the colors `a` and `b`.
+  ##
+  ## `fn` is invoked for each component R, G, and B.
+  ## If `fn`'s result is not in the `range[0..255]`,
+  ## it will be saturated to be so.
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = Color(0x0a2814)
+  ##     b = Color(0x050a03)
+  ##
+  ##   proc myMix(x, y: int): int =
+  ##     2 * x - 3 * y
+  ##
+  ##   assert mix(a, b, myMix) == Color(0x05_32_1f)
+  ##
   template `><` (x: untyped): untyped =
     # keep it in the range 0..255
     block:
@@ -79,9 +133,10 @@ template mix*(a, b: Color, fn: untyped): untyped =
         y = if y < 0: 0 else: 255
       y
 
-  (bind extract)(a, ar, ag, ab)
-  (bind extract)(b, br, bg, bb)
-  (bind rawRGB)(><fn(ar, br), ><fn(ag, bg), ><fn(ab, bb))
+  var ar, ag, ab, br, bg, bb: int
+  extract(a, ar, ag, ab)
+  extract(b, br, bg, bb)
+  rawRGB(><fn(ar, br), ><fn(ag, bg), ><fn(ab, bb))
 
 
 const
@@ -369,15 +424,31 @@ const
     ("yellowgreen", colYellowGreen)]
 
 proc `$`*(c: Color): string =
-  ## converts a color into its textual representation. Example: ``#00FF00``.
+  ## Converts a color into its textual representation.
+  ##
+  ## .. code-block::
+  ##   assert $colFuchsia == "#FF00FF"
+  ##
   result = '#' & toHex(int(c), 6)
 
 proc colorNameCmp(x: tuple[name: string, col: Color], y: string): int =
   result = cmpIgnoreCase(x.name, y)
 
 proc parseColor*(name: string): Color =
-  ## parses `name` to a color value. If no valid color could be
-  ## parsed ``ValueError`` is raised. Case insensitive.
+  ## Parses `name` to a color value.
+  ##
+  ## If no valid color could be parsed ``ValueError`` is raised.
+  ## Case insensitive.
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = "silver"
+  ##     b = "#0179fc"
+  ##     c = "#zzmmtt"
+  ##   assert parseColor(a) == Color(0xc0_c0_c0)
+  ##   assert parseColor(b) == Color(0x01_79_fc)
+  ##   doAssertRaises(ValueError): discard parseColor(c)
+  ##
   if name[0] == '#':
     result = Color(parseHexInt(name))
   else:
@@ -386,8 +457,18 @@ proc parseColor*(name: string): Color =
     result = colorNames[idx][1]
 
 proc isColor*(name: string): bool =
-  ## returns true if `name` is a known color name or a hexadecimal color
+  ## Returns true if `name` is a known color name or a hexadecimal color
   ## prefixed with ``#``. Case insensitive.
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = "silver"
+  ##     b = "#0179fc"
+  ##     c = "#zzmmtt"
+  ##   assert a.isColor
+  ##   assert b.isColor
+  ##   assert not c.isColor
+  ##
   if name[0] == '#':
     for i in 1 .. name.len-1:
       if name[i] notin {'0'..'9', 'a'..'f', 'A'..'F'}: return false
@@ -396,6 +477,9 @@ proc isColor*(name: string): bool =
     result = binarySearch(colorNames, name, colorNameCmp) >= 0
 
 proc rgb*(r, g, b: range[0..255]): Color =
-  ## constructs a color from RGB values.
+  ## Constructs a color from RGB values.
+  ##
+  ## .. code-block::
+  ##   assert rgb(0, 255, 128) == Color(0x00_ff_80)
+  ##
   result = rawRGB(r, g, b)
-