diff --git a/README.md b/README.md index 0b93b8d..33fe4f5 100644 --- a/README.md +++ b/README.md @@ -170,14 +170,29 @@ Did the terminal window expand to cover the area previously occupied by Safari? ![stackline setup 01](assets/stackline-setup-01@2x.png) The default stack indicator style is a "pill" as seen ↑ -To toggle icons: + +* To toggle icons: ```sh - echo ":toggle_icons:1" | hs -m stackline-config +# Turn on icons + echo ":show_icons:1" | hs -m stackline-config +# Turn off icons + echo ":show_icons:0" | hs -m stackline-config ``` ![stackline setup 02](assets/stackline-icon-indicators.png) +* To toggle colors: + +```sh +# Turn on colors + echo ":indicator_colors:1" | hs -m stackline-config +# Turn off colors + echo ":indicator_colors:0" | hs -m stackline-config +``` + +![stackline setup 03](assets/stackline-color-indicators.png) + Image (and feature!) courtesy of [@alin23](https://github.com/alin23). ## Help us get to v1.0.0! diff --git a/assets/stackline-color-indicators.png b/assets/stackline-color-indicators.png new file mode 100644 index 0000000..daef7d8 Binary files /dev/null and b/assets/stackline-color-indicators.png differ diff --git a/assets/stackline-demo.gif b/assets/stackline-demo.gif index 4aced14..498b01e 100644 Binary files a/assets/stackline-demo.gif and b/assets/stackline-demo.gif differ diff --git a/assets/stackline-github-banner.png b/assets/stackline-github-banner.png index c8b0dad..ad08fa7 100644 Binary files a/assets/stackline-github-banner.png and b/assets/stackline-github-banner.png differ diff --git a/assets/stackline-github-banner@2x.png b/assets/stackline-github-banner@2x.png index 2b81924..1ee4b4b 100644 Binary files a/assets/stackline-github-banner@2x.png and b/assets/stackline-github-banner@2x.png differ diff --git a/assets/stackline-icon-indicators.png b/assets/stackline-icon-indicators.png index 51efc3d..05c9fdc 100644 Binary files a/assets/stackline-icon-indicators.png and b/assets/stackline-icon-indicators.png differ diff --git a/assets/stackline-logo.png b/assets/stackline-logo.png index bfe1089..4a66475 100644 Binary files a/assets/stackline-logo.png and b/assets/stackline-logo.png differ diff --git a/assets/stackline-logo@2x.png b/assets/stackline-logo@2x.png index d23c59d..198ebeb 100644 Binary files a/assets/stackline-logo@2x.png and b/assets/stackline-logo@2x.png differ diff --git a/assets/stackline-setup-01@2x.png b/assets/stackline-setup-01@2x.png index e7415aa..1236223 100644 Binary files a/assets/stackline-setup-01@2x.png and b/assets/stackline-setup-01@2x.png differ diff --git a/stackline/core.lua b/stackline/core.lua index 8afe86f..a42ba2b 100644 --- a/stackline/core.lua +++ b/stackline/core.lua @@ -2,19 +2,11 @@ require("hs.ipc") local Stack = require 'stackline.stackline.stack' local tut = require 'stackline.utils.table-utils' +local utils = require 'stackline.utils.utils' print(hs.settings.bundleID) -function getOrSet(key, val) - local existingVal = hs.settings.get(key) - if existingVal == nil then - hs.settings.set(key, val) - return val - end - return existingVal -end - -local showIcons = getOrSet("showIcons", false) +local showIcons = utils.settingsGetOrSet("show_icons", false) wsi = Stack:newStackManager(showIcons) local shouldRestack = tut.Set{ @@ -24,7 +16,8 @@ local shouldRestack = tut.Set{ "window_destroyed", "window_resized", "window_moved", - "toggle_icons", + "show_icons", + "indicator_colors", } local shouldClean = tut.Set{ @@ -34,6 +27,17 @@ local shouldClean = tut.Set{ "window_minimized", } +function resetLuminanceCache(paths, flagTables) + print("Changed wallpaper, resetting luminanceCache") + utils.luminanceCache = {} + wsi.cleanup() + wsi = Stack:newStackManager(hs.settings.get("show_icons")) +end + +local wallpaperDB = os.getenv("HOME") .. "/Library/Application Support/Dock/" +print("Watching", wallpaperDB) +wallpaperWatcher = hs.pathwatcher.new(wallpaperDB, resetLuminanceCache):start() + function configHandler(_, msgID, msg) if msgID == 900 then return "version:2.0a" @@ -41,14 +45,11 @@ function configHandler(_, msgID, msg) if msgID == 500 then key, value = msg:match(".+:([%a_-]+):([%a%d_-]+)") - if key == "toggle_icons" then - showIcons = not showIcons - hs.settings.set("showIcons", showIcons) - end + hs.settings.set(key, utils.boolean(string.lower(value))) if shouldRestack[key] then wsi.cleanup() - wsi = Stack:newStackManager(showIcons) + wsi = Stack:newStackManager(hs.settings.get("show_icons")) end wsi.update(shouldClean[key]) end diff --git a/stackline/window.lua b/stackline/window.lua index ac72dd8..1bb2680 100644 --- a/stackline/window.lua +++ b/stackline/window.lua @@ -85,9 +85,17 @@ end -- }}} function Window:process(showIcons, currTabIdx) -- {{{ -- Config + local indicatorColors = _.settingsGetOrSet("indicator_colors", false) + self.showIcons = showIcons - local unfocused_color = {white = 0.9, alpha = 0.30} - local focused_color = {white = 0.9, alpha = 0.99} + local unfocused_color_light = {white = 0.9, alpha = 0.40} + local focused_color_light = indicatorColors and + {hue = 0.1, saturation = 1.0, brightness = 0.9, alpha = 0.95} or + {white = 0.9, alpha = 0.99} + local unfocused_color_dark = {white = 0.1, alpha = 0.40} + local focused_color_dark = indicatorColors and + {hue = 0.99, saturation = 0.8, brightness = 0.8, alpha = 0.95} or + {white = 0.1, alpha = 0.99} local padding = 4 local iconPadding = 4 local aspectRatio = 5 @@ -96,6 +104,7 @@ function Window:process(showIcons, currTabIdx) -- {{{ local width = self.showIcons and size or (size / aspectRatio) local shit = self.frame.x - (width + padding) + self.canvas_frame = { x = shit, y = self.frame.y + 2, @@ -105,7 +114,7 @@ function Window:process(showIcons, currTabIdx) -- {{{ self.indicator_rect = { x = 0, - y = ((currTabIdx - 1) * size * 1.1), + y = _.round((currTabIdx - 1) * size * 1.1), w = width, h = size, } @@ -117,8 +126,11 @@ function Window:process(showIcons, currTabIdx) -- {{{ h = self.indicator_rect.h - (iconPadding * 2), } + light_bg = _.hasLightBG(self.canvas_frame, self.indicator_rect) self.color_opts = { - bg = self.focused and focused_color or unfocused_color, + bg = self.focused and + (light_bg and focused_color_dark or focused_color_light) or + (light_bg and unfocused_color_dark or unfocused_color_light), canvasAlpha = self.focused and 1 or 0.2, imageAlpha = self.focused and 1 or 0.4, } diff --git a/utils/utils.lua b/utils/utils.lua index e4d0491..cf19714 100644 --- a/utils/utils.lua +++ b/utils/utils.lua @@ -1,9 +1,78 @@ +local tut = require 'stackline.utils.table-utils' +local LIGHT_BG_BRIGHTNESS_THRESHOLD = 0.5 + +local trueValues = tut.Set{ + "1", + "t", + "y", + "true", + "yes", + "on", +} + utils = {} utils.map = hs.fnutils.map utils.concat = hs.fnutils.concat utils.each = hs.fnutils.each + +utils.luminanceCache = {} + +utils.luminance = function(color) + color = hs.drawing.color.asHSB(color) + return (2 - color.saturation) * color.brightness / 2 +end + +utils.pixelBrightness = function(image, pixel) + color = image:colorAt(pixel) + return color and utils.luminance(color) or 0.5 +end + +utils.hasLightBG = function(canvasFrame, indicatorFrame) + screen = hs.screen.mainScreen() + + frame = screen:absoluteToLocal(hs.geometry(canvasFrame)) + frame = hs.geometry(indicatorFrame.x + frame.x, indicatorFrame.y + frame.y, indicatorFrame.w, indicatorFrame.h) + + if utils.luminanceCache[frame.string] ~= nil then + return utils.luminanceCache[frame.string] + end + + image = screen:snapshot(frame) + + topleft = frame.topleft + brightness = 0.0 + for dx=0,frame.w do + for dy=0,frame.h do + brightness = brightness + utils.pixelBrightness(image, hs.geometry.point(dx, dy)) + end + end + + brightness = brightness / (frame.w * frame.h) + print(brightness, frame) + utils.luminanceCache[frame.string] = brightness > LIGHT_BG_BRIGHTNESS_THRESHOLD + return utils.luminanceCache[frame.string] +end + +utils.round = function(x) + return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5) +end + +utils.boolean = function(val) + return trueValues[val] +end + +utils.settingsGetOrSet = function(key, val) + local existingVal = hs.settings.get(key) + if existingVal == nil then + hs.settings.set(key, val) + return val + end + return existingVal +end + + utils.filter = function(t, f) local out = {} for k, v in pairs(t) do @@ -272,7 +341,7 @@ function utils.p(...) -- p('# to be cleaned: ', table.length(self.tabStacks)) -- -> "# to be cleaned: 2" -- Example 2: - -- p('keys be cleaned: ', table.keys(self.tabStacks)) + -- p('keys be cleaned: ', table.keys(self.tabStacks)) -- -> "keys be cleaned: { "6207671375", "63771631066207041183" }" result = {}