#!/usr/bin/env bash # Copyright (C) Daniel Napora 2021 # Dependencies: jgmenu, xdotool, colorpicker, xdg-utils, xclip # TODO check for other color-tools like gpick,gcolor2 and add launchers to menu # TODO export to .gpl (GIMP,Inkscape) VERSION="0.1.7" TEMP_DIR=/tmp/colormenu ME=${0##*/} CNF_DIR="$HOME/.config/mbxcolors" CNF_FILE="$CNF_DIR/mbxcolors.cfg" RECENT="$CNF_DIR/recent.clr" USED="$CNF_DIR/.used" LASTPAL="$CNF_DIR/.palette" [ ! -d "$CNF_DIR" ] && mkdir -p "$CNF_DIR" && cp -r /usr/share/mbxcolors/* "$CNF_DIR"/ if [ ! -f $CNF_FILE ]; then cat < ${CNF_FILE} # Paste mode: hex,rgb or rgba format=hex #Action when color is clicked: paste (imadietely) or copy (to clipboard) action=paste #What thing to expose on top of main menu: recently picked colors, last used colors or last used palette expose=html #Show HTML colors? yes|no htmlcolors=no #Show built in palettes? (slow) builtin_palettes=no #Position on screen: topleft, top, topright, left, center, right, bottomleft, bottom, bottomright position=left EOF fi source <(grep = $CNF_FILE) if [ ! -f $RECENT ]; then cat < ${RECENT} #FFFFFF White #C0C0C0 Silver #808080 Gray #000000 Black EOF fi fgcolor() { r=$(printf "%d" 0x${1:1:2}) g=$(printf "%d" 0x${1:3:2}) b=$(printf "%d" 0x${1:5:2}) [ "$((r*299+g*587+b*114))" -gt 149000 ] && echo "#111111" || echo "#EEEEEE" } hex2rgb() { r=$(printf "%d" 0x${1:1:2}) g=$(printf "%d" 0x${1:3:2}) b=$(printf "%d" 0x${1:5:2}) echo "rgb($r, $g, $b)" } hex2rgba() { r=$(printf "%d" 0x${1:1:2}) g=$(printf "%d" 0x${1:3:2}) b=$(printf "%d" 0x${1:5:2}) echo "rgba($r, $g, $b, 1.0)" } pickcolor() { #color=$(colorpicker --short --one-shot --preview) #color=$(xcolor --preview-size "${preview-size:-255}" --scale "${scale:-8}") size=${xcolor_preview_size:-255} scale=${xcolor_scale:-8} command="xcolor --preview-size ${size} --scale ${scale}" color="$(${command})" if [ -n "${color}" ]; then echo "$color " > "$RECENT".tmp # add on top deduplicate awk '!x[$0]++' "$RECENT" >> "$RECENT".tmp awk '!x[$0]++' "$RECENT".tmp > "$RECENT" [ -n "$1" ] && file="$1" echo "$color " >> "$file" setvar expose=picked fi $ME } pycolor() { read -r -d '' script <<-"----EOF" import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QColorDialog class App(QMainWindow): def __init__(self): super().__init__() color = QColorDialog.getColor() if color.isValid(): print(color.name()) self.deleteLater() if __name__ == "__main__": app = QApplication(sys.argv) win = App() ----EOF python -c "$script" } addcolor() { color=$(gcolor3) if [ -n "${color}" ]; then echo "$color " > "$RECENT".tmp # add on top deduplicate awk '!x[$0]++' "$RECENT" >> "$RECENT".tmp awk '!x[$0]++' "$RECENT".tmp > "$RECENT" [ -n "$1" ] && file="$1" echo "$color " >> "$file" setvar expose=picked fi $ME } getcolorcode() { if [ $action = "paste" ];then case "$format" in rgb) clr=$(hex2rgb $1);xdotool type --delay 0 "$clr";; rgba) clr=$(hex2rgba $1);xdotool type --delay 0 "$clr";; *) xdotool type --delay 0 "$1";; esac else case "$format" in rgb) clr=$(hex2rgb $1);echo $clr | tr -d "\n" | xclip -sel c;; rgba) clr=$(hex2rgba $1);echo $clr | tr -d "\n" | xclip -sel c;; *) clr="$1";echo "$1" | tr -d "\n" | xclip -sel c;; esac mkdir -p $TEMP_DIR FNAME="$TEMP_DIR/$clr.png" convert -size 100x100 xc:"$1" "$FNAME" notify-send ColorMenu "$clr" --icon="$FNAME" --expire-time=10000 fi echo "$1" > "$USED".tmp # add on top and deduplicate awk '!x[$0]++' "$USED" >> "$USED".tmp awk '!x[$0]++' "$USED".tmp > "$USED" [[ $2 ]] && echo "$2" > "$LASTPAL" } recent2palette () { DATE=$(date +"%Y%m%d-%H%M%S") mkdir -p "$CNF_DIR/palettes/my" grep ^# $RECENT |tac > "$CNF_DIR/palettes/my/My_palette_$DATE.clr" } newpalette() { DATE=$(date +"%Y%m%d-%H%M%S") mkdir -p "$CNF_DIR/palettes/my" touch "$CNF_DIR/palettes/my/My_palette_$DATE.clr" } palettes() { [ -n "$1" ] && pdir="$CNF_DIR/palettes/my/" || pdir="$CNF_DIR/palettes/" for file in "$pdir"*.clr;do filename=${file##*/} palette=${filename%.*} pal=${palette//_/ } tagname=${palette// /_} out+=("${pal^},^checkout($tagname)") out2+=("^tag($tagname)") out2+=("^sep(${pal^})") while read -r color name; do #name=$(printf "%22s %s\n" "$name") #fg=$(fgcolor $color) #out2+=(" $color$name ,$ME getcolorcode '$color' '$file',,,#${palette}") out2+=("$color ,$ME getcolorcode '$color' '$file',,,#${palette}") done < "$file" if [[ -n "$1" ]] ; then out2+=("^sep()") out2+=("Add color... from screen,$ME pickcolor '$file'") if hash pyuic5 2>/dev/null; then out2+=("^sep()") out2+=("Add color from selector...,$ME addcolor") fi out2+=("^sep()") out2+=("Edit palette file,xdg-open '$file'") out2+=("^sep(Danger zone...)") out2+=("Delete palette: ${palette^},^checkout($tagname-del)") out3+=("^tag($tagname-del)") out3+=("^sep(Are you sure?)") out3+=("Yes,rm '$file';$ME") fi done #if [[ $# = 0 ]] ; then if [[ -n "$1" ]] ; then out1+=("^sep()") out1+=("Add new palette...,$ME newpalette;$ME") out1+=("Open palette directory,xdg-open $CNF_DIR/palettes/my/") fi } htmlcolors() { out+=("HTML colors,^checkout(html)") out2+=("^tag(html)") out2+=("^sep(HTML colors)") for i in white yellow orange pink red brown green cyan blue purple gray;do out2+=(" ${i^} ...,^checkout($i)") out3+=("^tag($i)") out3+=("^sep(${i^} colors)") while read -r color name; do name=$(printf "%22s %s\n" "$name") fg=$(fgcolor $color) out3+=(" $color$name,$ME getcolorcode '$color',,,#$i") done < "$CNF_DIR/$i.clr" done } if [ $htmlcolors = "yes" ] && [ $expose != "html" ]; then htmlroot="^sep() HTML colors,^checkout(html) " htmlsub="^tag(html) . ${CNF_DIR}/htmlsub.csv" htmlclrs=". ${CNF_DIR}/htmlclrs.csv" else htmlroot="" htmlsub="" htmlclrs="" fi position() { case "$position" in ipc) POSITION_MODE="ipc";; pointer) POSITION_MODE="pointer";; topleft) POSITION_MODE="fixed" MENU_VALIGN="top" MENU_HALIGN="left";; top) POSITIOM_MODE="fixed" MENU_VALIGN="top" MENU_HALIGN="center";; topright) POSITION_MODE="fixed" MENU_VALIGN="top" MENU_HALIGN="right";; left) POSITION_MODE="fixed" MENU_VALIGN="center" MENU_HALIGN="left";; right) POSITION_MODE="fixed" MENU_VALIGN="center" MENU_HALIGN="right";; bottomleft) POSITION_MODE="fixed" MENU_VALIGN="bottom" MENU_HALIGN="left";; bottom) POSITION_MODE="fixed" MENU_VALIGN="bottom" MENU_HALIGN="center";; bottomright) POSITION_MODE="fixed" MENU_VALIGN="bottom" MENU_HALIGN="right";; center|*) POSITION_MODE="center";; esac } mkconfigfile() { if [[ -f /usr/share/mbxtools/configure.inc ]];then . /usr/share/mbxtools/configure.inc elif [[ -f /usr/share/mb-jgtools/pipemenu-standalone.cfg ]];then . /usr/share/mb-jgtools/pipemenu-standalone.cfg . $HOME/.config/mabox/mabox.conf else MENU_ITEMS=$(mktemp) CONFIG_FILE=$(mktemp) cat < ${CONFIG_FILE} position_mode = ${POSITION_MODE:-center} menu_halign = ${MENU_HALIGN:-center} menu_valign = ${MENU_VALIGN:-center} csv_cmd = apps stay_alive = 0 hide_back_items = ${HIDE_BACK_ITEMS:-0} terminal_exec = terminator terminal_args = -e tabs = ${TABS:-220} menu_border = ${jgtools_border:-0} # MENU MARGIN menu_margin_x = ${menu_margin_x:-0} menu_margin_y = ${panels_topmargin:-0} sub_spacing = ${submenu_spacing:-2} menu_width = $JGWIDTH menu_height_min = ${MENU_HEIGHT_MIN:-0} menu_height_max = ${MENU_HEIGHT_MAX:-0} menu_padding_top = ${MENU_PADDING_TOP:-70} menu_padding_right = ${jgtools_padding:-0} menu_padding_bottom = ${jgtools_padding:-0} menu_padding_left = ${jgtools_padding:-0} menu_radius = ${MENU_RADIUS:-0} #item_height = ${jgmenu_item_height:-30} #item_halign = ${ITEM_HALIGN:-left} #item_padding_x = 4 #item_margin_x = ${item_margin_x:-0} item_margin_y = ${item_margin_y:-0} #item_radius = ${item_radius:-2} #item_border = ${item_border:-0} columns = ${COLUMNS:-1} menu_gradient_pos = ${menu_gradient_pos:- none} #color_menu_bg = ${color_menu_bg:-#222222 80} #color_menu_bg_to = ${color_menu_bg_to:- #000000 100} #color_menu_border = ${color_menu_border:-#2f9b85 100} #color_norm_bg = ${color_norm_bg:-#000000 0} #color_norm_fg = ${color_norm_fg:-#CCCCCC 100} #color_sel_bg = ${color_sel_bg:-#169f6f 60} #color_sel_fg = ${color_sel_fg:-#f8f8f8 100} #color_sel_border = ${color_sel_border:-#504e65 100} #color_sep_fg = ${color_sep_fg:-#4D4D4D 100} #color_sep_bg = ${color_sep_bg:-#262626 100} #color_title_fg = ${color_title_fg:-#4D4D4D 100} #color_title_border = ${color_title_border:-#169f6f 100} #color_title_bg = ${color_title_bg:-#262626 100} #color_scroll_ind = ${COLOR_SCROLL_IND:-#504e65 100} sep_markup = weight="bold" sep_height = ${sep_height:-5} #font = ${jgmenu_font:-Noto Sans Medium 9} icon_size = ${jgmenu_icon_size:-16} icon_theme = ${jgmenu_icon_theme:-Numix-Square} EOF fi } main () { # Mabox Linux if [[ -f /usr/share/mb-jgtools/pipemenu-standalone.cfg ]];then . /usr/share/mb-jgtools/pipemenu-standalone.cfg . $HOME/.config/mabox/mabox.conf fi [ "$1" = "ipc" ] && position="ipc" MENU_PADDING_TOP=${jgtools_padding:-0} JGWIDTH="220" ITEM_HALIGN="center" jgmenu_icon_size=0 menu_margin_x=${submenu_spacing:-0} [ $(pidof picom) ] && MENU_RADIUS=$jgtools_radius #jgmenu_font="Noto Sans Medium 10" position mkconfigfile trap "rm -f ${CONFIG_FILE} ${MENU_ITEMS}" EXIT out+=("^sep(mbxcolors [$action $format])") #out+=("^sep( mbx colors [$action $format])") out+=("Pick color from screen...,$ME pickcolor") if hash pyuic5 2>/dev/null; then out+=("^sep()") out+=("Add color from selector...,$ME addcolor") fi # exposed thing case "$expose" in used) out+=("^sep(Recently used colors:)") while read -r color name;do name=$(printf "%22s %s\n" "$name") fg=$(fgcolor $color) out+=(" $color$name,$ME getcolorcode '$color'") done < <(grep ^# $USED) out+=("^sep()") out+=("Clear recently used colors,echo > $USED;$ME") ;; html) htmlroot=". ${CNF_DIR}/htmlsub.csv" htmlsub=". ${CNF_DIR}/htmlclrs.csv" htmlclrs="" ;; palette) pal=$(cat "$CNF_DIR/.palette") filename=${pal##*/} palette=${filename%.*} out+=("^sep(Last used palette ${palette^})") while read -r color name;do #name=$(printf "%22s %s\n" "$name") #fg=$(fgcolor $color) #out+=(" $color$name,$ME getcolorcode '$color'") out+=("$color ,$ME getcolorcode '$color'") done < "${pal}" ;; picked|*) out+=("^sep(Recently picked colors:)") # for clear/delete out2+=("^tag(pickeddel)") out2+=("^sep(Clear All)") out2+=("Clear all,echo > $RECENT;$ME") out2+=("^sep(Just remove one color...)") while read -r color name;do # name=$(printf "%22s %s\n" "$name") # fg=$(fgcolor $color) # out+=(" $color$name,$ME getcolorcode '$color'") out+=("$color ,$ME getcolorcode '$color'") out2+=("$color ,sed -i '/${color:1:6}/d' $RECENT;$ME") #echo "$color ,sed '/${color:1:6}/d' $RECENT;$ME" done < <(grep ^# $RECENT) out+=("^sep()") out+=("New palette from recently picked,$ME recent2palette;$ME") #out+=("Clear recently picked,echo > $RECENT;$ME") out+=("Clear recently picked,^checkout(pickeddel)") ;; esac #if [[ "$CNF_DIR"/palettes/my/*.clr ]]; then if [ "$(find "$CNF_DIR"/palettes/my/*.clr -maxdepth 1 -type f -iname \*.clr)" ]; then out+=("^sep(My palletes)") palettes my fi if [[ $builtin_palettes == "yes" ]];then out+=("^sep(Built-in palettes)") palettes fi out1+=("^sep(Settings)") out1+=("Preferences,^pipe($ME preferences)") cat << EOF > ${MENU_ITEMS} $(printf '%s\n' "${out[@]}") ${htmlroot} $(printf '%s\n' "${out1[@]}") ${htmlsub} $(printf '%s\n' "${out2[@]}") ${htmlclrs} $(printf '%s\n' "${out3[@]}") EOF jgmenu --config-file=${CONFIG_FILE} --csv-file=${MENU_ITEMS} 2>/dev/null #printf '%s\n' "${out3[@]}" exit 0 } preferences() { out2+=("^sep(Settings)") out2+=("$(printf "%-20s %20s" "Color click action:" "[$action]"),^checkout(action)") out2+=("$(printf "%-20s %20s" "Format:" "[$format]"),^checkout(format)") out2+=("^sep()") out2+=("$(printf "%-20s %20s" "Expose on top:" "[$expose]"),^checkout(expose)") out2+=("$(printf "%-20s %20s" "HTML colors:" "[$htmlcolors]"),^checkout(showhtml)") out2+=("$(printf "%-20s %20s" "Built-in palettes:" "[$builtin_palettes]"),^checkout(builtinpalettes)") out2+=("^sep()") out2+=("$(printf "%-20s %20s" "Position:" "[$position]"),^checkout(position)") out2+=("^sep()") out2+=("Reset to defaults,rm $CNF_FILE;$ME") out2+=("^sep()") out2+=("Edit config file,xdg-open $CNF_FILE") out2+=("Open config directory,xdg-open $CNF_DIR") out2+=("^tag(format)") out2+=("^sep(Output format)") out2+=("hex #579C8E,$ME setvar format=hex;$ME") out2+=("rgb rgb(87, 156, 142),$ME setvar format=rgb;$ME") out2+=("rgba rgba(87, 156, 142, 1.0),$ME setvar format=rgba;$ME") out2+=("^tag(action)") out2+=("^sep(Color action)") out2+=("paste (paste color immediately),$ME setvar action=paste;$ME") out2+=("copy (copy color to clipboard),$ME setvar action=copy;$ME") out2+=("^tag(expose)") out2+=("^sep(Show on top of rootmenu)") out2+=("picked recently picked colors,$ME setvar expose=picked;$ME") out2+=("used recently used colors,$ME setvar expose=used;$ME") out2+=("palette recently used palette,$ME setvar expose=palette;$ME") out2+=("html HTML Colors,$ME setvar expose=html;$ME") out2+=("^tag(showhtml)") out2+=("^sep(Show HTML colors?)") out2+=("yes,$ME setvar htmlcolors=yes;$ME") out2+=("no,$ME setvar htmlcolors=no;$ME") out2+=("^tag(builtinpalettes)") out2+=("^sep(Show Built-in palettes?)") out2+=("yes,$ME setvar builtin_palettes=yes;$ME") out2+=("no,$ME setvar builtin_palettes=no;$ME") out2+=("^tag(position)") out2+=("^sep(Position on screen)") out2+=("center,$ME setvar position=center;$ME") out2+=("topleft,$ME setvar position=topleft;$ME") out2+=("top,$ME setvar position=top;$ME") out2+=("topright,$ME setvar position=topright;$ME") out2+=("left,$ME setvar position=left;$ME") out2+=("right,$ME setvar position=right;$ME") out2+=("bottomleft,$ME setvar position=bottomleft;$ME") out2+=("bottom,$ME setvar position=bottom;$ME") out2+=("bottomright,$ME setvar position=bottomright;$ME") printf '%s\n' "${out2[@]}" } setvar() { search=$(echo $1|cut -d= -f1) FILE=${CNF_FILE} if grep -Rq $search $FILE then #found sed -i s/^"$search".*$/"$1"/ $FILE else #not found echo $1 >> $FILE fi } case "$1" in -h|--help|help) usage;; --pickcolor|pickcolor) pickcolor "$2";; --addcolor|addcolor) addcolor "$2" ;; -g|--getcolorcode|getcolorcode) getcolorcode "$2" "$3";; -p|preferences) preferences;; -s|setvar) setvar "$2";; ipc) main "$1";; recent2palette) recent2palette ;; newpalette) newpalette;; *) main;; esac exit 0