summaryrefslogtreecommitdiffstats
path: root/src/Pager/Sixelerator.hs
blob: c518484e7469def0a4d587e6d74a4090ad921695 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
module Pager.Sixelerator where

import Data.ByteString (ByteString)
import Data.Maybe (catMaybes)
import Pager.Types
import Sixel (PaletteColor)
import State (State(..))
import qualified Sixel


data WindowFeature
    = WindowBackground
    | WindowBorder
    | FocusBackground
    | FocusBorder
    | UrgentBackground
    | UrgentBorder


renderWorkspacePreview :: Geometry -> State -> Workspace -> ByteString
renderWorkspacePreview previewGeometry State{screenHeight,screenWidth} Workspace{..} =
    Sixel.render previewGeometry rgbColors canvas
  where
    workspaceHeight = fromIntegral $ geometry_height previewGeometry :: Int
    workspaceWidth = fromIntegral $ geometry_width previewGeometry :: Int

    scaleX = fromIntegral workspaceWidth / fromIntegral screenWidth :: Double
    scaleY = fromIntegral workspaceHeight / fromIntegral screenHeight :: Double

    -- XXX color indexes must start at 0 and be continuous (to compute sixeldata)
    workspaceBackgroundColor = 0
    windowBackgroundColor = 1
    windowBorderColor = 2
    focusBackgroundColor = 3
    focusBorderColor = 4
    urgentBackgroundColor = 5
    urgentBorderColor = 6

    rgbColors =
      [ (0,0,0)       -- workspace background
      , (29,113,29)   -- window background color
      , (0,255,0)     -- window border color
      , (113,29,113)  -- focus background color
      , (255,0,255)   -- focus border color
      , (113,29,29)   -- urgent background color
      , (255,0,0)     -- urgent border color
      ]

    canvas = rasterize f (fromIntegral workspaceWidth) (fromIntegral workspaceHeight)
              <> blankLine
      where
        f x y = case catMaybes (map (getWindowFeatureAt x y) workspace_windows) of
                  UrgentBackground:_ -> urgentBackgroundColor
                  UrgentBorder:_ -> urgentBorderColor
                  FocusBackground:_ -> focusBackgroundColor
                  FocusBorder:_ -> focusBorderColor
                  WindowBackground:_ -> windowBackgroundColor
                  WindowBorder:_ -> windowBorderColor
                  _ -> workspaceBackgroundColor

        -- XXX blank line is used in conjunction with ex_offsetY to "clean up" when moving up
        -- remove this together with ex_offsetY.
        blankLine = replicate workspaceWidth 0

    getWindowFeatureAt x y Window{..} =
        if isBorder then
          if window_urgent then
            Just UrgentBorder
          else if window_focused then
            Just FocusBorder
          else
            Just WindowBorder
        else if isBackground then
          if window_urgent then
            Just UrgentBackground
          else if window_focused then
            Just FocusBackground
          else
            Just WindowBackground
        else
          Nothing
      where
        w_x = round (scaleX * fromIntegral (geometry_x window_geometry))
        w_y = round (scaleY * fromIntegral (geometry_y window_geometry))
        w_width = round (scaleX * fromIntegral (geometry_width window_geometry))
        w_height = round (scaleY * fromIntegral (geometry_height window_geometry))
        isBackground =
          (w_x <= x && x < w_x + w_width) &&
          (w_y <= y && y < w_y + w_height)
        isBorder =
          (w_x <= x && x < w_x + w_width) &&
          (w_y <= y && y < w_y + w_height) &&
          (x == w_x || x == w_x + w_width - 1 || y == w_y || y == w_y + w_height - 1)


rasterize :: (Int -> Int -> PaletteColor) -> Int -> Int -> [PaletteColor]
rasterize f width height =
    map f' ([0..width * height - 1] :: [Int])
  where
    f' index = f x y
      where
        x = fromIntegral $ index `mod` width
        y = floor $ fromIntegral index / (fromIntegral width :: Double)