Open-source News

Discover the power of the Linux SpaceFM file manager

opensource.com - Mon, 12/19/2022 - 16:00
Discover the power of the Linux SpaceFM file manager sethkenlon Mon, 12/19/2022 - 03:00

SpaceFM is a tabbed file manager for Linux using the GTK toolkit, so it fits right in on desktops like GNOME, Mate, Cinnamon, and others. SpaceFM also features a built-in device manager system, so it's particularly good for window managers, like Fluxbox or fvwm, which typically don't include a graphical device manager. If you're happy with the file managers on Linux, but you want to try one that's a little bit different in design, SpaceFM is worth a look.

Install SpaceFM

On Linux, you're likely to find SpaceFM in your distribution's software repository. On Fedora, Mageia, OpenMandriva, and similar:

$ sudo dnf install spacefm

On Debian and Debian-based systems:

$ sudo apt install spacefmPanels

I don't know why SpaceFM is called SpaceFM, but it could be because it makes a concerted effort to let you use every bit of space in its window for something useful. By default, SpaceFM is actually pretty simple, standard-issue file manager. It has a single panel listing your files, a toolbar, and a menu bar.

Image by:

(Seth Kenlon, CC BY-SA 4.0)

All the "usual" rules apply.

  • Double-click to open a directory or to open a file in its default application.

  • Right-click for a contextual menu providing lots of standard options (copy, paste, rename, view properties, create a new folder, and so on).

The way SpaceFM sets itself apart, though, is its panel system. SpaceFM displays one panel by default. That's the big file window listing your files. But it can have up to four panel views, plus a few bonus panels for some specific tasks.

More Linux resources Linux commands cheat sheet Advanced Linux commands cheat sheet Free online course: RHEL technical overview Linux networking cheat sheet SELinux cheat sheet Linux common commands cheat sheet What are Linux containers? Our latest Linux articles Opening a new panel

Instead of seeing one directory in your file manager, you can see two. To bring up another directory in its own pane, press Ctrl+2 or go to the View menu and select Panel 2. Alternatively, click the second green dot icon from the left in the menu panel.

With two panels, you can move files from one directory to another without opening a new file manager window, or you can browse two directories to compare their contents.

But why settle for two panels? Maybe you'd rather see three directories at once. To bring up a third directory in a dedicated pane, press Ctrl+3 or go to the View menu and select Panel 3. Alternatively, click the third green dot icon from the left in the menu panel. This panel appears at the bottom of the SpaceFM window.

With three panels open, you can move files between several directories, or sort files from a common "dumping ground" (like your Desktop or Downloads folder) into specific directories.

Of course, once you've tried three panels you'll probably find yourself itching for a fourth. To open a fourth directory in its own pane, press Ctrl+4 or go to the View menu and select Panel 4. Alternatively, click the fourth green dot icon from the left in the menu panel. This one opens next to Panel 3, splitting your SpaceFM window into even quarters.

Image by:

(Seth Kenlon, CC BY-SA 4.0)

What about a fifth panel? Well, actually SpaceFM stops at four panels. If you really do want a fifth panel, you have to open a new SpaceFM window. However, there are still more panels, used for information other than file listings, to explore.

Special panels

The View menu reveals that in addition to file panels, there are additionally task-specific panels you can choose to display. This includes:

  • Task manager: Lists ongoing file manager processes. This isn't a general-purpose task manager, so to set nice values or detect a zombie apocalypse of undead PIDs, htop or top is still your utility of choice.

  • Bookmarks: Links to common folders, such as Desktop, Documents, Downloads, and any location you want to keep handy.

  • Devices: USB thumb drives and remote file systems.

  • File tree: A view of your file system in order of directory inheritance.

These panels open on the left side of SpaceFM, but they do stack. You can have bookmarks, devices, tasks, and a file tree open at once, although it helps to have a very tall SpaceFM window.

Make space for SpaceFM

SpaceFM is a configurable multi-tasking file manager. It maximizes the information you can build into a single window, and it lets you decide what's important, and when. This article has focused on the panels of SpaceFM because those are, at least in my view, the most unique aspect of the application. However, there's a lot more to SpaceFM, including plugins, preferences, a design mode, keyboard shortcuts, and customization. This isn't a small application, even though it is a lightweight one. Spend some time with SpaceFM, because you never know what you'll discover.

If you're happy with the file managers on Linux, but you want to try one that's a little bit different in design, SpaceFM is worth a look.

Image by:

Opensource.com

Linux What to read next This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License. Register or Login to post a comment.

Most Commonly Asked Questions in Linux Interviews

Tecmint - Mon, 12/19/2022 - 15:14
The post Most Commonly Asked Questions in Linux Interviews first appeared on Tecmint: Linux Howtos, Tutorials & Guides .

If you have already achieved your Linux certification and are looking forward to securing a Linux job, it pays a great deal to prepare for an interview that tests your knowledge of the ins

The post Most Commonly Asked Questions in Linux Interviews first appeared on Tecmint: Linux Howtos, Tutorials & Guides.

XFS Aims To Get Online File-System Repair Support Merged Next Year

Phoronix - Mon, 12/19/2022 - 13:00
For years XFS has been working toward online repair capabilities for the file-system and it looks like in 2023 that work may finally come to fruition...

GNU Linux-libre's Freed-ora Effort To "Free Fedora" Has Been Sunset

Phoronix - Mon, 12/19/2022 - 04:10
Freed-ora had been a seldom talked about effort from the Free Software Foundation Latin America maintainers of GNU Linux-libre to ensure a fully free software kernel was installed on interested Fedora Linux systems and that no non-free packages were installed on the system. But now that effort has come to an end...

Microsoft Begins Providing DirectX Shader Compiler Linux Binaries

Phoronix - Sun, 12/18/2022 - 21:33
In early 2017 Microsoft open-sourced their DirectX shader compiler and shortly thereafter it's been possible to build it on Linux while finally as of this week Microsoft has begun providing official Linux binaries of their shader compiler...

SquashFS Gains Support For IDMAPPED Mounts With Linux 6.2

Phoronix - Sun, 12/18/2022 - 20:09
Introduced nearly two years ago with Linux 5.12 was IDMAPPED mounts for many innovative use-cases from containers to systemd-homed. With the Linux 6.2 kernel, SquashFS is the latest file-system adding support for IDMAPPED mounts...

NVIDIA-VAAPI-Driver 0.0.8 Introduces New Direct Backend

Phoronix - Sun, 12/18/2022 - 19:53
Introduced at the start of the year was an experimental open-source project implementing the VA-API interface over NVIDIA's NVDEC video decoding API. In turn this VA-API support for running atop NVIDIA's proprietary Linux graphics driver allows for GPU video acceleration within Firefox and other software only targeting the Video Acceleration API. Now in closing out the year is a new NVIDIA-VAAPI-Driver release...

Landlock Security Module Adds File Truncation Support With Linux 6.2

Phoronix - Sun, 12/18/2022 - 19:16
Merged back in Linux 5.13 last year was Landlock for allowing unprivileged application sandboxing. Landlock allows restricting ambient rights for a set of processes and is implemented as a stackable Linux security module (LSM) for establishing safe security sandboxes. With Linux 6.2 file truncation support is added for Landlock...

Linux 6.2 Introduces Several More Touchscreen Drivers

Phoronix - Sun, 12/18/2022 - 18:41
In addition to the HID driver updates for the Linux 6.2 kernel that were merged this week, the input subsystem updates also landed this week and were headlined by having several new touchscreen drivers...

Use my Groovy color wheel calculator

opensource.com - Sun, 12/18/2022 - 16:00
Use my Groovy color wheel calculator clhermansen Sun, 12/18/2022 - 03:00

Every so often, I find myself needing to calculate complementary colors. For example, I might be making a line graph in a web app or bar graphs for a report. When this happens, I want to use complementary colors to have the maximum "visual difference" between the lines or bars.

Online calculators can be useful in calculating two or maybe three complementary colors, but sometimes I need a lot more–for instance, maybe 10 or 15.

Many online resources explain how to do this and offer formulas, but I think it's high time for a Groovy color calculator. So please follow along. First, you might need to install Java and Groovy.

Install Java and Groovy

Groovy is based on Java and requires a Java installation as well. Both a recent/decent version of Java and Groovy might be in your Linux distribution's repositories. Or you can install Groovy by following the instructions on the above link.

A nice alternative for Linux users is SDKMan, which can get multiple versions of Java, Groovy, and many other related tools. For this article, I'm using SDK's releases of:

  • Java: version 11.0.12-open of OpenJDK 11
  • Groovy: version 3.0.8
Using a color wheel

Before you start coding, look at a real color wheel. If you open GIMP (the GNU Image Manipulation Program) and look on the upper left-hand part of the screen, you'll see the controls to set the foreground and background colors, circled in red on the image below:

Image by:

(Chris Hermansen, CC BY-SA 4.0)

If you click on the upper left square (the foreground color), a window will open that looks like this:

Image by:

(Chris Hermansen, CC BY-SA 4.0)

More on Java What is enterprise Java programming? An open source alternative to Oracle JDK Java cheat sheet Red Hat build of OpenJDK Free online course: Developing cloud-native applications with microservices Fresh Java articles

If it doesn't quite look like that, click on the fourth from the left button on the top left row, which looks like a circle with a triangle inscribed in it.

The ring around the triangle represents a nearly continuous range of colors. In the image above, starting from the triangle pointer (the black line that interrupts the circle on the left), the colors shade from blue into cyan into green, yellow, orange, red, magenta, violet, and back to blue. This is the color wheel. If you pick two colors opposite each other on that wheel, you will have two complementary colors. If you choose 17 colors evenly spaced around that wheel, you'll have 17 colors that are as distinct as possible.

Make sure you have selected the HSV button in the top right of the window, then look at the sliders marked H, S, and V, respectively. These are hue, saturation, and value. When choosing contrasting colors, the hue is the interesting parameter.

Its value runs from zero to 360 degrees; in the image above, it's 192.9 degrees.

You can use this color wheel to calculate the complementary color to another manually–just add 180 to your color's value, giving you 372.9. Next, subtract 360, leaving 17.9 degrees. Type that 17.9 into the H box, replacing the 192.9, and poof, you have its complementary color:

Image by:

(Chris Hermansen, CC BY-SA 4.0)

If you inspect the text box labeled HTML notation you'll see that the color you started with was #0080a3, and its complement is #a33100. Look at the fields marked Current and Old to see the two colors complementing each other.

There is a most excellent and detailed article on Wikipedia explaining HSL (hue, saturation, and lightness) and HSV (hue, saturation, and value) color models and how to convert between them and the RGB standard most of us know.

I'll automate this in Groovy. Because you might want to use this in various ways, create a Color class that provides constructors to create an instance of Color and then several methods to query the color of the instance in HSV and RGB.

Here's the Color class, with an explanation following:

     1  /**
     2   *  This class based on the color transformation calculations
     3   *  in https://en.wikipedia.org/wiki/HSL_and_HSV
     4   *
     5   *  Once an instance of Color is created, it can be transformed
     6   *  between RGB triplets and HSV triplets and converted to and
     7   *  from hex codes.
     8   */
       
     9  public class Color {
       
    10      /**
    11       * May as well keep the color as both RGB and HSL triplets
    12       * Keep each component as double to avoid as many rounding
    13       * errors as possible.
    14       */
       
    15      private final Map rgb // keys 'r','g','b'; values 0-1,0-1,0-1 double
    16      private final Map hsv // keys 'h','s','v'; values 0-360,0-1,0-1 double
       
    17      /**
    18       * If constructor provided a single int, treat it as a 24-bit RGB representation
    19       * Throw exception if not a reasonable unsigned 24 bit value
    20       */
       
    21      public Color(int color) {
    22          if (color < 0 || color > 0xffffff) {
    23              throw new IllegalArgumentException('color value must be between 0x000000 and 0xffffff')
    24          } else {
    25              this.rgb = [r: ((color & 0xff0000) >> 16) / 255d, g: ((color & 0x00ff00) >> 8) / 255d, b: (color & 0x0000ff) / 255d]
    26              this.hsv = rgb2hsv(this.rgb)
    27          }
    28      }
       
    29      /**
    30       * If constructor provided a Map, treat it as:
    31       * - RGB if map keys are 'r','g','b'
    32       *   - Integer and in range 0-255 ⇒ scale
    33       *   - Double and in range 0-1 ⇒ use as is
    34       * - HSV if map keys are 'h','s','v'
    35       *   - Integer and in range 0-360,0-100,0-100 ⇒ scale
    36       *   - Double and in range 0-360,0-1,0-1 ⇒ use as is
    37       * Throw exception if not according to above
    38       */
       
    39      public Color(Map triplet) {
    40          def keySet = triplet.keySet()
    41          def types = triplet.values().collect { it.class }
    42          if (keySet == ['r','g','b'] as Set) {
    43              def minV = triplet.min { it.value }.value
    44              def maxV = triplet.max { it.value }.value
    45              if (types == [Integer,Integer,Integer] && 0 <= minV && maxV <= 255) {
    46                  this.rgb = [r: triplet.r / 255d, g: triplet.g / 255d, b: triplet.b / 255d]
    47                  this.hsv = rgb2hsv(this.rgb)
    48              } else if (types == [Double,Double,Double] && 0d <= minV && maxV <= 1d) {
    49                  this.rgb = triplet
    50                  this.hsv = rgb2hsv(this.rgb)
    51              } else {
    52                  throw new IllegalArgumentException('rgb triplet must have integer values between (0,0,0) and (255,255,255) or double values between (0,0,0) and (1,1,1)')
    53              }
    54          } else if (keySet == ['h','s','v'] as Set) {
    55              if (types == [Integer,Integer,Integer] && 0 <= triplet.h && triplet.h <= 360
    56              && 0 <= triplet.s && triplet.s <= 100 && 0 <= triplet.v && triplet.v <= 100) {
    57                  this.hsv = [h: triplet.h as Double, s: triplet.s / 100d, v: triplet.v / 100d]
    58                  this.rgb = hsv2rgb(this.hsv)
    59              } else if (types == [Double,Double,Double] && 0d <= triplet.h && triplet.h <= 360d
    60              && 0d <= triplet.s && triplet.s <= 1d && 0d <= triplet.v && triplet.v <= 1d) {
    61                  this.hsv = triplet
    62                  this.rgb = hsv2rgb(this.hsv)
    63              } else {
    64                  throw new IllegalArgumentException('hsv triplet must have integer values between (0,0,0) and (360,100,100) or double values between (0,0,0) and (360,1,1)')
    65              }
    66          } else {
    67              throw new IllegalArgumentException('triplet must be a map with keys r,g,b or h,s,v')
    68          }
    69      }
       
    70      /**
    71       * Get the color representation as a 24 bit integer which can be
    72       * rendered in hex in the familiar HTML form.
    73       */
       
    74      public int getHex() {
    75          (Math.round(this.rgb.r * 255d) << 16) +
    76          (Math.round(this.rgb.g * 255d) << 8) +
    77          Math.round(this.rgb.b * 255d)
    78      }
       
    79      /**
    80       * Get the color representation as a map with keys r,g,b
    81       * and the corresponding double values in the range 0-1
    82       */
       
    83      public Map getRgb() {
    84          this.rgb
    85      }
       
    86      /**
    87       * Get the color representation as a map with keys r,g,b
    88       * and the corresponding int values in the range 0-255
    89       */
       
    90      public Map getRgbI() {
    91          this.rgb.collectEntries {k, v -> [(k): Math.round(v*255d)]}
    92      }
       
    93      /**
    94       * Get the color representation as a map with keys h,s,v
    95       * and the corresponding double values in the ranges 0-360,0-1,0-1
    96       */
       
    97      public Map getHsv() {
    98          this.hsv
    99      }
       
   100      /**
   101       * Get the color representation as a map with keys h,s,v
   102       * and the corresponding int values in the ranges 0-360,0-100,0-100
   103       */
       
   104      public Map getHsvI() {
   105          [h: Math.round(this.hsv.h), s: Math.round(this.hsv.s*100d), v: Math.round(this.hsv.v*100d)]
   106      }
       
   107      /**
   108       * Internal routine to convert an RGB triple to an HSV triple
   109       * Follows the Wikipedia section https://en.wikipedia.org/wiki/HSL_and_HSV#Hue_and_chroma
   110       * (almost) - note that the algorithm given there does not adjust H for G < B
   111       */
       
   112      private static def rgb2hsv(Map rgbTriplet) {
   113          def max = rgbTriplet.max { it.value }
   114          def min = rgbTriplet.min { it.value }
   115          double c = max.value - min.value
   116          if (c) {
   117              double h
   118              switch (max.key) {
   119              case 'r': h = ((60d * (rgbTriplet.g - rgbTriplet.b) / c) + 360d) % 360d; break
   120              case 'g': h = ((60d * (rgbTriplet.b - rgbTriplet.r) / c) + 120d) % 360d; break
   121              case 'b': h = ((60d * (rgbTriplet.r - rgbTriplet.g) / c) + 240d) % 360d; break
   122              }
   123              double v = max.value // hexcone model
   124              double s = max.value ? c / max.value : 0d
   125              [h: h, s: s, v: v]
   126          } else {
   127              [h: 0d, s: 0d, v: 0d]
   128          }
   129      }
       
   130      /**
   131       * Internal routine to convert an HSV triple to an RGB triple
   132       * Follows the Wikipedia section https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
   133       */
       
   134      private static def hsv2rgb(Map hsvTriplet) {
   135          double c = hsvTriplet.v * hsvTriplet.s
   136          double hp = hsvTriplet.h / 60d
   137          double x = c * (1d - Math.abs(hp % 2d - 1d))
   138          double m = hsvTriplet.v - c
   139          if (hp < 1d)      [r: c  + m, g: x  + m, b: 0d + m]
   140          else if (hp < 2d) [r: x  + m, g: c  + m, b: 0d + m]
   141          else if (hp < 3d) [r: 0d + m, g: c  + m, b: x  + m]
   142          else if (hp < 4d) [r: 0d + m, g: x  + m, b: c  + m]
   143          else if (hp < 5d) [r: x  + m, g: 0d + m, b: c  + m]
   144          else if (hp < 6d) [r: c  + m, g: 0d + m, b: x  + m]
   145      }
       
   146  }

The Color class definition, which begins on line 9 and ends on line 146, looks a lot like a Java class definition (at first glance, anyway) that would do the same thing. But this is Groovy, so you have no imports up at the beginning, just comments. Plus, the details illustrate some more Groovyness.

Line 15 creates the private final variable rgb that contains the color value supplied to the class constructor. You'll keep this value as Map with keys r, g, and b to access the RGB values. Keep the values as double values between 0 and 1 so that 0 would indicate a hexadecimal value of #00 or an integer value of 0 and 1 would mean a hexadecimal value of #ff or an integer value of 255. Use double to avoid accumulating rounding errors when converting inside the class.

Similarly, line 16 creates the private final variable hsv that contains the same color value but in HSV format–also a Map, but with keys h, s, and v to access the HSV values, which will be kept as double values between 0 and 360 (hue) and 0 and 1 (saturation and value).

Lines 21-28 define a Color constructor to be called when passing in an int argument. For example, you might use this as:

def blue = new Color(0x0000ff)
  • On lines 22-23, check to make sure the argument passed to the constructor is in the allowable range for a 24-bit integer RGB constructor, and throw an exception if not.
  • On line 25, initialize the rgb private variable as the desired RGB Map, using bit shifts and dividing each by a double value 255 to scale the numbers between 0 and 1.
  • On line 26, convert the RGB triplet to HSV and assign it to the hsv private variable.

Lines 39-69 define another Color constructor to be called when passing in either an RGB or HSV triple as a Map. You might use this as:

def green = new Color([r: 0, g: 255, b: 0])

or

def cyan = new Color([h: 180, s: 100, v: 100])

Or similarly with double values scaled between 0 and 1 instead of integers between 0 and 255 in the RGB case and between 0 and 360, 0 and 1, and 0 and 1 for hue, saturation, and value, respectively.

This constructor looks complicated, and in a way, it is. It checks the keySet() of the map argument to decide whether it denotes an RGB or HSV tuple. It checks the class of the values passed in to determine whether the values are to be interpreted as integers or double values and, therefore, whether they are scaled into 0-1 (or 0-360 for hue).

Arguments that can't be sorted out using this checking are deemed incorrect, and an exception is thrown.

Worth noting is the handy streamlining provided by Groovy:

def types = triplet.values().collect { it.class }

This uses the values() method on the map to get the values as a List and then the collect() method on that List to get the class of each value so that they can later be checked against [Integer,Integer,Integer] or [Double,Double,Double] to ensure that arguments meet expectations.

Here is another useful streamlining provided by Groovy:

def minV = triplet.min { it.value }.value

The min() method is defined on Map; it iterates over the Map and returns the MapEntry—a (key, value) pair—having the minimum value encountered. The .value on the end selects the value field from that MapEntry, which gives something to check against later to determine whether the values need to be normalized.

Both rely on the Groovy Closure, similar to a Java lambda–a kind of anonymous procedure defined where it is called. For example, collect() takes a single Closure argument and passes it to each MapEntry encountered, known as the parameter within the closure body. Also, the various implementations of the Groovy Collection interface, including here Map, define the collect() and min() methods that iterate over the elements of the Collection and call the Closure argument. Finally, the syntax of Groovy supports compact and low-ceremony invocations of these various features.

Lines 70-106 define five "getters" that return the color used to create the instance in one of five formats:

  1. getHex() returns an int corresponding to a 24-bit HTML RGB color.
  2. getRgb() returns a Map with keys r, g, b and corresponding double values in the range 0-1.
  3. getRgbI() returns a Map with keys r, g, b and corresponding int values in the range 0-255.
  4. getHsv() returns a Map with keys h, s, v and corresponding double values in the range 0-360, 0-1 and 0-1, respectively.
  5. getHsvI() returns a Map with keys h, s, v and corresponding int values in the range 0-360, 0-100 and 0-100, respectively.

Lines 112-129 define a static private (internal) method rgb2hsv() that converts an RGB triplet to an HSV triplet. This follows the algorithm described in the Wikipedia article section on Hue and chroma, except that the algorithm there yields negative hue values when the green value is less than the blue value, so the version is modified slightly. This code isn't particularly Groovy other than using the max() and min() Map methods and returning a Map instance declaratively without a return statement.

This method is used by the two getter methods to return the Color instance value in the correct form. Since it doesn't refer to any instance fields, it is static.

Similarly, lines 134-145 define another private (internal) method hsv2rgb(), that converts an HSV triplet to an RGB triplet, following the algorithm described in the Wikipedia article section on HSV to RGB conversion. The constructor uses this method to convert HSV triple arguments into RGB triples. Since it doesn't refer to any instance fields, it is static.

That's it. Here's an example of how to use this class:

     1  def favBlue = new Color(0x0080a3)
       
     2  def favBlueRgb = favBlue.rgb
     3  def favBlueHsv = favBlue.hsv
       
     4  println "favBlue hex = ${sprintf('0x%06x',favBlue.hex)}"
     5  println "favBlue rgbt = ${favBlue.rgb}"
     6  println "favBlue hsvt = ${favBlue.hsv}"
       
     7  int spokeCount = 8
     8  double dd = 360d / spokeCount
     9  double d = favBlue.hsv.h
    10  for (int spoke = 0; spoke < spokeCount; spoke++) {
    11      def color = new Color(h: d, s: favBlue.hsv.s, v: favBlue.hsv.v)
    12      println "spoke $spoke $d° hsv ${color.hsv}"
    13      println "    hex ${sprintf('0x%06x',color.hex)} hsvI ${color.hsvI} rgbI ${color.rgbI}"
    14      d = (d + dd) % 360d
    15  }

As my starting value, I've chosen the lighter blue from the opensource.com header #0080a3, and I'm printing a set of seven more colors that give maximum separation from the original blue. I call each position going around the color wheel a spoke and compute its position in degrees in the variable d, which is incremented each time through the loop by the number of degrees dd between each spoke.

As long as Color.groovy and this test script are in the same directory, you can compile and run them as follows:

$ groovy test1Color.groovy
favBlue hex = 0x0080a3
favBlue rgbt = [r:0.0, g:0.5019607843137255, b:0.6392156862745098]
favBlue hsvt = [h:192.88343558282207, s:1.0, v:0.6392156862745098]
spoke 0 192.88343558282207° hsv [h:192.88343558282207, s:1.0, v:0.6392156862745098]
    hex 0x0080a3 hsvI [h:193, s:100, v:64] rgbI [r:0, g:128, b:163]
spoke 1 237.88343558282207° hsv [h:237.88343558282207, s:1.0, v:0.6392156862745098]
    hex 0x0006a3 hsvI [h:238, s:100, v:64] rgbI [r:0, g:6, b:163]
spoke 2 282.8834355828221° hsv [h:282.8834355828221, s:1.0, v:0.6392156862745098]
    hex 0x7500a3 hsvI [h:283, s:100, v:64] rgbI [r:117, g:0, b:163]
spoke 3 327.8834355828221° hsv [h:327.8834355828221, s:1.0, v:0.6392156862745098]
    hex 0xa30057 hsvI [h:328, s:100, v:64] rgbI [r:163, g:0, b:87]
spoke 4 12.883435582822074° hsv [h:12.883435582822074, s:1.0, v:0.6392156862745098]
    hex 0xa32300 hsvI [h:13, s:100, v:64] rgbI [r:163, g:35, b:0]
spoke 5 57.883435582822074° hsv [h:57.883435582822074, s:1.0, v:0.6392156862745098]
    hex 0xa39d00 hsvI [h:58, s:100, v:64] rgbI [r:163, g:157, b:0]
spoke 6 102.88343558282207° hsv [h:102.88343558282207, s:1.0, v:0.6392156862745098]
    hex 0x2fa300 hsvI [h:103, s:100, v:64] rgbI [r:47, g:163, b:0]
spoke 7 147.88343558282207° hsv [h:147.88343558282207, s:1.0, v:0.6392156862745098]
    hex 0x00a34c hsvI [h:148, s:100, v:64] rgbI [r:0, g:163, b:76]

You can see the degree position of the spokes reflected in the HSV triple. I've also printed the hex RGB value and the int version of the RGB and HSV triples.

I could have built this in Java. Had I done so, I probably would have created separate RgbTriple and HsvTriple helper classes because Java doesn't provide the declarative syntax for Map. That would have made finding the min and max values more verbose. So, as usual, the Java would have been more lengthy without improving readability. There would have been three constructors, though, which might be a more straightforward proposition.

I could have used 0-1 for the hue as I did for saturation and value, but somehow I like 0-360 better.

Finally, I could have added–and I may still do so one day–other conversions, such as HSL.

Wrap up

Color wheels are useful in many situations and building one in Groovy is a great exercise to learn both how the wheel works and the, well, grooviness of Groovy. Take your time; the code above is long. However, you can build your own practical color calculator and learn a lot along the way.

Groovy resources

The Apache Groovy language site provides a good tutorial-level overview of working with Collection, particularly Map classes. This documentation is quite concise and easy to follow, at least partly because the facility it is documenting has been designed to be itself concise and easy to use!

Color wheels are useful in many situations and building one in Groovy is a great exercise to learn both how the wheel works and the, well, grooviness of Groovy.

Image by:

Lisa Padilla. Modified by Opensource.com. CC BY-SA 4.0

Java Programming What to read next This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License. Register or Login to post a comment.

Pages