From b4565c530add8622bfe09a8d0d98f9dae1a6c805 Mon Sep 17 00:00:00 2001
From: Jens Nolte <jens@nightmarestudio.de>
Date: Sat, 1 Feb 2020 04:27:18 +0100
Subject: [PATCH] Unify color types

---
 src/QBar/BlockOutput.hs   | 35 ++-------------
 src/QBar/Cli.hs           |  6 +--
 src/QBar/ControlSocket.hs |  4 +-
 src/QBar/Filter.hs        | 88 --------------------------------------
 src/QBar/Server.hs        | 19 +++------
 src/QBar/Themes.hs        | 89 +++++++++++++++++++++++++++++++++------
 6 files changed, 88 insertions(+), 153 deletions(-)
 delete mode 100644 src/QBar/Filter.hs

diff --git a/src/QBar/BlockOutput.hs b/src/QBar/BlockOutput.hs
index 1b20587..5869ae4 100644
--- a/src/QBar/BlockOutput.hs
+++ b/src/QBar/BlockOutput.hs
@@ -11,7 +11,6 @@ import Data.Int (Int64)
 import qualified Data.Text.Lazy as T
 
 
-
 data BlockOutput = BlockOutput
   { _fullText :: BlockText
   , _shortText :: Maybe BlockText
@@ -38,9 +37,11 @@ data BlockTextSegment = BlockTextSegment {
     importance :: Importance,
     text :: T.Text
   }
-  | PangoTextSegment T.Text
+  | PangoTextSegment PangoText
   deriving (Eq, Show)
 
+type PangoText = T.Text
+
 type Importance = Float
 
 $(deriveJSON defaultOptions ''BlockOutput)
@@ -171,32 +172,4 @@ pangoText :: T.Text -> BlockText
 pangoText pango = BlockText [PangoTextSegment pango]
 
 surroundWith :: (T.Text -> BlockText) -> T.Text -> T.Text -> BlockText -> BlockText
-surroundWith format left right middle = format left <> middle <> format right
-
-data Color = ColorRGB Float Float Float | ColorRGBA Float Float Float Float
-colorToHex :: Color -> T.Text
-colorToHex = colorToHex'
-  where
-    colorToHex' :: Color -> T.Text
-    colorToHex' (ColorRGB r g b) = "#" <> (toDualHex . floor) (r * 255) <> (toDualHex . floor) (g * 255)  <> (toDualHex . floor) (b * 255)
-    colorToHex' (ColorRGBA r g b a) = "#" <> (toDualHex . floor) (r * 255) <> (toDualHex . floor) (g * 255)  <> (toDualHex . floor) (b * 255) <> (toDualHex . floor) (a * 255)
-    toHex :: Int -> T.Text
-    toHex 0 = "0"
-    toHex 1 = "1"
-    toHex 2 = "2"
-    toHex 3 = "3"
-    toHex 4 = "4"
-    toHex 5 = "5"
-    toHex 6 = "6"
-    toHex 7 = "7"
-    toHex 8 = "8"
-    toHex 9 = "9"
-    toHex 10 = "A"
-    toHex 11 = "B"
-    toHex 12 = "C"
-    toHex 13 = "D"
-    toHex 14 = "E"
-    toHex 15 = "F"
-    toHex x = toHex $ mod x 16
-    toDualHex :: Int -> T.Text
-    toDualHex x = toHex (div x 16) <> toHex x
+surroundWith format left right middle = format left <> middle <> format right
\ No newline at end of file
diff --git a/src/QBar/Cli.hs b/src/QBar/Cli.hs
index 512e0e5..75fdfed 100644
--- a/src/QBar/Cli.hs
+++ b/src/QBar/Cli.hs
@@ -5,13 +5,13 @@ module QBar.Cli where
 import qualified Data.Text as T
 import Options.Applicative
 
-data BarCommand = BarServer | NoFilter | RainbowFilter
+data BarCommand = BarServer | DefaultTheme | RainbowTheme
 
 barCommandParser :: Parser BarCommand
 barCommandParser = hsubparser
   ( command "server" (info (pure BarServer) (progDesc "Start a new qbar server. Should be called by swaybar, i3bar or or another i3bar-protocol compatible host process.")) <>
-    command "default" (info (pure NoFilter) (progDesc "Send a message to a running qbar server.")) <>
-    command "rainbow" (info (pure RainbowFilter) (progDesc "Send a message to a running qbar server."))
+    command "default" (info (pure DefaultTheme) (progDesc "Send a message to a running qbar server.")) <>
+    command "rainbow" (info (pure RainbowTheme) (progDesc "Send a message to a running qbar server."))
   )
 
 data MainOptions = MainOptions {
diff --git a/src/QBar/ControlSocket.hs b/src/QBar/ControlSocket.hs
index 195a8f1..6dde25c 100644
--- a/src/QBar/ControlSocket.hs
+++ b/src/QBar/ControlSocket.hs
@@ -5,8 +5,6 @@ module QBar.ControlSocket where
 
 import QBar.Cli (MainOptions(..))
 import QBar.Core
--- TODO: remove dependency?
-import QBar.Filter
 import QBar.BlockOutput
 
 import Control.Exception (handle)
@@ -35,7 +33,7 @@ import System.Environment (getEnv)
 
 type CommandChan = TChan Command
 
-data Command = SetFilter Filter
+data Command = SetTheme T.Text
   | Block
   deriving Show
 
diff --git a/src/QBar/Filter.hs b/src/QBar/Filter.hs
deleted file mode 100644
index 125d9af..0000000
--- a/src/QBar/Filter.hs
+++ /dev/null
@@ -1,88 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-
-module QBar.Filter where
-
-import QBar.BlockOutput
-
-import Control.Monad.State.Lazy (State, evalState, get, put)
-import Data.Aeson.TH
-import Data.Colour.RGBSpace.HSV (hsv)
-import qualified Data.Text.Lazy as T
-import Control.Lens hiding (index)
-
-import Numeric (showHex)
-import Data.Colour.RGBSpace
-
-
-data Filter = StaticFilter StaticFilter
-  | AnimatedFilter AnimatedFilter
-  deriving Show
-
-data StaticFilter = None
-  deriving Show
-
-data AnimatedFilter = Rainbow
-  deriving Show
-
-$(deriveJSON defaultOptions ''Filter)
-$(deriveJSON defaultOptions ''StaticFilter)
-$(deriveJSON defaultOptions ''AnimatedFilter)
-
-isAnimatedFilter :: Filter -> Bool
-isAnimatedFilter (AnimatedFilter _) = True
-isAnimatedFilter _ = False
-
-applyFilter :: Filter -> Double -> [BlockOutput] -> [BlockOutput]
-applyFilter (StaticFilter None) = static id
-applyFilter (AnimatedFilter Rainbow) = rainbow
-
-static :: a -> Double -> a
-static fn _ = fn
-
-
-coloredText :: T.Text -> T.Text -> T.Text
-coloredText color text = "<span color='" <> color <> "'>" <> text <> "</span>"
-
-
-pangoColor :: RGB Double -> T.Text
-pangoColor (RGB r g b) =
-  let r' = hexColorComponent r
-      g' = hexColorComponent g
-      b' = hexColorComponent b
-  in "#" <> r' <> g' <> b'
-  where
-    hexColorComponent :: Double -> T.Text
-    hexColorComponent val = paddedHexComponent $ T.pack $ showHex (max 0 $ min 255 (truncate (val * 255) :: Int)) ""
-    paddedHexComponent hex =
-      let len = 2 - T.length hex
-          padding = if len == 1 then "0" else ""
-      in padding <> hex
-
-
-rainbow :: Double -> [BlockOutput] -> [BlockOutput]
-rainbow time blocks = reverse $ evalState (mapM rainbowBlock $ reverse blocks) 0
-  where
-    rainbowBlock :: BlockOutput -> State Integer BlockOutput
-    rainbowBlock block = do
-      let text = removePango $ block^.fullText
-      let chars = T.unpack . T.reverse $ text
-      coloredChars <- mapM rainbowChar chars
-      let rainbowText = T.concat . reverse $ coloredChars
-      return $ fullText .~ pangoText rainbowText $ block
-    rainbowChar :: Char -> State Integer T.Text
-    rainbowChar char = do
-      color <- nextRainbowColor
-      return $ coloredText color $ T.singleton char
-    nextRainbowColor :: State Integer T.Text
-    -- nextRainbowColor = state $ \index -> (rainbowColor (fromInteger index), index + 1)
-    nextRainbowColor = do
-      index <- get
-      put $ index + 1
-      return $ rainbowColor (fromInteger index + time * 10)
-
-
-rainbowColor :: Double -> T.Text
-rainbowColor position =
-  let hue' = position * 3
-      color = hsv hue' 0.8 1.0
-  in pangoColor color
diff --git a/src/QBar/Server.hs b/src/QBar/Server.hs
index e17590a..86a19ef 100644
--- a/src/QBar/Server.hs
+++ b/src/QBar/Server.hs
@@ -6,20 +6,17 @@ import QBar.BlockOutput
 import QBar.Core
 import QBar.Cli
 import QBar.ControlSocket
-import QBar.Filter
 import QBar.Host
 import QBar.Themes
 
 import Control.Monad (forever, when, unless, forM_)
-import Control.Monad.STM (atomically)
 import Control.Concurrent.Async
-import Control.Concurrent.STM.TChan (newTChanIO, readTChan)
+import Control.Concurrent.STM.TChan (newTChanIO)
 import Data.Aeson (encode, decode, ToJSON, toJSON, object, (.=))
 import Data.ByteString.Lazy (hPut)
 import qualified Data.ByteString.Char8 as BSSC8
 import qualified Data.ByteString.Lazy as BS
 import qualified Data.ByteString.Lazy.Char8 as C8
-import Data.IORef
 import Data.Maybe (fromMaybe)
 import qualified Data.Text.Lazy as T
 import Pipes
@@ -105,10 +102,6 @@ runBarServer defaultBarConfig options = runBarHost barServer (swayBarInput optio
   where
     barServer :: Consumer [BlockOutput] BarIO ()
     barServer = do
-      -- Create IORef to contain the active filter
-      let initialBlockFilter = StaticFilter None
-      activeFilter <- liftIO $ newIORef initialBlockFilter
-
       -- Load blocks
       lift $ do
         when (indicator options) $ addBlock renderIndicator
@@ -123,10 +116,8 @@ runBarServer defaultBarConfig options = runBarHost barServer (swayBarInput optio
 
       -- Update bar on control socket messages
       socketUpdateAsync <- liftIO $ async $ forever $ do
-        command <- atomically $ readTChan commandChan
-        case command of
-          SetFilter blockFilter -> atomicWriteIORef activeFilter blockFilter
-          Block -> error "TODO"
+        -- command <- atomically $ readTChan commandChan
+        void $ error "TODO"
         updateBar' bar
       liftIO $ link socketUpdateAsync
 
@@ -140,5 +131,5 @@ runQBar :: BarIO () -> MainOptions -> IO ()
 runQBar barConfiguration options@MainOptions{barCommand} = runCommand barCommand
   where
     runCommand BarServer = runBarServer barConfiguration options
-    runCommand NoFilter = sendIpc options $ SetFilter $ StaticFilter None
-    runCommand RainbowFilter = sendIpc options $ SetFilter $ AnimatedFilter Rainbow
+    runCommand DefaultTheme = sendIpc options $ SetTheme "default"
+    runCommand RainbowTheme = sendIpc options $ SetTheme "rainbow"
diff --git a/src/QBar/Themes.hs b/src/QBar/Themes.hs
index 63531f9..7e48b69 100644
--- a/src/QBar/Themes.hs
+++ b/src/QBar/Themes.hs
@@ -2,9 +2,16 @@ module QBar.Themes where
 
 import QBar.BlockOutput
 
+import Control.Lens ((^.), (.~))
+import Control.Monad.State.Lazy (State, evalState, get, put)
+import Data.Colour.RGBSpace
+import Data.Colour.RGBSpace.HSV (hsv)
 import qualified Data.Text.Lazy as T
+import Numeric (showHex)
 
-import Control.Lens
+
+
+data Color = ColorRGB (RGB Double) | ColorRGBA (RGB Double) Double
 
 
 type Theme = [BlockOutput] -> [(T.Text, Maybe T.Text)]
@@ -29,15 +36,12 @@ mkTheme theming' = map themeBlock
     themeBlockText :: SimplifiedTheme -> BlockText -> T.Text
     themeBlockText theming (BlockText b) = foldr ((<>) . themeSegment theming) "" b
     themeSegment :: SimplifiedTheme -> BlockTextSegment -> T.Text
-    themeSegment theming BlockTextSegment {active, importance, text} = (applyTheme $ theming active importance) text
+    themeSegment theming BlockTextSegment {active, importance, text} = (coloredText' $ theming active importance) text
     themeSegment _ (PangoTextSegment text) = text
-    applyTheme :: (Color, Maybe Color) -> T.Text -> T.Text
-    applyTheme (fc, Just bc) s = "<span color='" <> colorToHex fc <> "' background='" <> colorToHex bc <> "'>" <> s <> "</span>"
-    applyTheme (fc, Nothing) s = "<span color='" <> colorToHex fc <> "'>" <> s <> "</span>"
 
 
 invalidColor :: Color
-invalidColor = ColorRGBA (0x96 / 255) (0x98 / 255) (0x96 / 255) (0x77 / 255)
+invalidColor = ColorRGBA (RGB (0x96 / 255) (0x98 / 255) (0x96 / 255)) (0x77 / 255)
 
 
 invalidSimplifiedTheme :: SimplifiedTheme
@@ -53,11 +57,68 @@ defaultTheme = mkTheme defaultTheme'
   where
     defaultTheme' :: SimplifiedTheme
     defaultTheme' active importance
-      | isCritical importance, active = (ColorRGB 0 0 0, Just $ ColorRGB 1 0 0)
-      | isCritical importance         = (ColorRGB 0.8 0.15 0.15, Nothing)
-      | isError importance, active    = (ColorRGB 1 0.3 0, Nothing)
-      | isError importance            = (ColorRGB 0.7 0.35 0.2, Nothing)
-      | isWarning importance,active   = (ColorRGB 1 0.9 0, Nothing)
-      | isWarning importance          = (ColorRGB 0.6 0.6 0, Nothing)
-      | otherwise, active             = (ColorRGB 1 1 1, Nothing)
-      | otherwise                     = (ColorRGB (0x96 / 255) (0x98 / 255) (0x96 / 255), Nothing)
+      | isCritical importance, active = (ColorRGB (RGB 0 0 0), Just $ ColorRGB (RGB 1 0 0))
+      | isCritical importance         = (ColorRGB (RGB 0.8 0.15 0.15), Nothing)
+      | isError importance, active    = (ColorRGB (RGB 1 0.3 0), Nothing)
+      | isError importance            = (ColorRGB (RGB 0.7 0.35 0.2), Nothing)
+      | isWarning importance,active   = (ColorRGB (RGB 1 0.9 0), Nothing)
+      | isWarning importance          = (ColorRGB (RGB 0.6 0.6 0), Nothing)
+      | otherwise, active             = (ColorRGB (RGB 1 1 1), Nothing)
+      | otherwise                     = (ColorRGB (RGB (0x96 / 255) (0x98 / 255) (0x96 / 255)), Nothing)
+
+
+rainbowTheme :: Double -> [BlockOutput] -> [BlockOutput]
+rainbowTheme time blocks = reverse $ evalState (mapM rainbowBlock $ reverse blocks) 0
+  where
+    rainbowBlock :: BlockOutput -> State Integer BlockOutput
+    rainbowBlock block = do
+      let text = removePango $ block ^. fullText
+      let chars = T.unpack . T.reverse $ text
+      coloredChars <- mapM rainbowChar chars
+      let rainbowText = T.concat . reverse $ coloredChars
+      return $ fullText .~ pangoText rainbowText $ block
+    rainbowChar :: Char -> State Integer T.Text
+    rainbowChar char = do
+      color <- nextRainbowColor
+      return $ coloredText color $ T.singleton char
+    nextRainbowColor :: State Integer Color
+    -- nextRainbowColor = state $ \index -> (rainbowColor (fromInteger index), index + 1)
+    nextRainbowColor = do
+      index <- get
+      put $ index + 1
+      return $ rainbowColor (fromInteger index + time * 10)
+    rainbowColor :: Double -> Color
+    rainbowColor position =
+      let hue' = position * 3
+          color = hsv hue' 0.8 1.0
+      in ColorRGB color
+
+
+coloredText :: Color -> T.Text -> PangoText
+coloredText color text = "<span color='" <> pangoColor color <> "'>" <> text <> "</span>"
+
+coloredText' :: (Color, Maybe Color) -> T.Text -> PangoText
+coloredText' (foreground, Nothing) text = "<span color='" <> pangoColor foreground <> "'>" <> text <> "</span>"
+coloredText' (foreground, Just background) text = "<span color='" <> pangoColor foreground <> "' background='" <> pangoColor background <> "'>" <> text <> "</span>"
+
+
+pangoColor :: Color -> T.Text
+pangoColor = pangoColor'
+  where
+    pangoColor' :: Color -> T.Text
+    pangoColor' (ColorRGB rgb) = pangoRGB rgb
+    pangoColor' (ColorRGBA rgb a) = pangoRGB rgb <> hexColorComponent a
+
+    pangoRGB :: RGB Double -> T.Text
+    pangoRGB (RGB r g b) =
+      let r' = hexColorComponent r
+          g' = hexColorComponent g
+          b' = hexColorComponent b
+      in "#" <> r' <> g' <> b'
+    hexColorComponent :: Double -> T.Text
+    hexColorComponent val = paddedHexComponent $ T.pack $ showHex (max 0 $ min 255 (truncate (val * 255) :: Int)) ""
+    paddedHexComponent :: T.Text -> T.Text
+    paddedHexComponent hex =
+      let len = 2 - T.length hex
+          padding = if len == 1 then "0" else ""
+      in padding <> hex
-- 
GitLab