This repository has been archived on 2020-10-28. You can view files and clone it, but cannot push or open issues or pull requests.
sike/main.py

187 lines
6.2 KiB
Python
Executable File

#!/usr/bin/env python
import gi
import math
import cairo
import subprocess as sp
import sys
import os
from os.path import expanduser
import toml
gi.require_version("Gtk","3.0")
gi.require_version("Gdk","3.0")
gi.require_version("GtkLayerShell","0.1")
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GtkLayerShell
Gtk.init()
def point_on_circle(r, point, angle):
x = point[0] + r * math.cos(angle)
y = point[1] + r * math.sin(angle)
return [x,y]
def gradient(x1,y1,x2,y2):
return y1-y2/x1-x2
class MenuWindow(Gtk.Window):
def __init__(self, options, colors,config):
super().__init__()
self.set_title("sike")
self.options = options
self.all_options = options
self.path = []
self.colors = colors
self.config = config
self.selected = None
self.set_resizable(False)
self.set_decorated(False)
self.mouse_x = 0
self.mouse_y = 0
self.connect("destroy",Gtk.main_quit)
self.area = Gtk.DrawingArea()
self.area.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK)
self.area.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
self.area.add_events(Gdk.EventMask.BUTTON_MOTION_MASK)
self.area.add_events(Gdk.EventMask.TOUCH_MASK)
self.area.connect("draw",self.draw_area)
self.area.connect("button_release_event",self.on_selection)
self.area.connect("motion_notify_event",self.on_move)
#self.area.connect("touch_event",self.on_touch)
self.add(self.area)
def scale(self,width,height):
self.width = width/3
self.height = height
self.set_default_size(width/3,height)
self.move(width-self.width,0)
def on_selection(self,widget,data):
if self.selected != None:
self.path.append(self.selected)
opt = self.options[self.selected]
if opt["type"] == "shell":
sp.Popen(opt["command"].split(" "))
self.destroy()
elif opt["type"] == "internal":
if opt["command"] == "exit":
self.destroy()
elif opt["type"] == "i3":
if type(i3) != None:
i3.command(f"[id={focused.window}] focus")
i3.command(opt["command"])
self.destroy()
elif opt["type"] == "submenu":
self.options = opt["options"]
self.selected = None
self.area.queue_draw()
else:
if self.path == []:
self.destroy()
else:
o = self.all_options
if len(self.path) == 1:
self.options = o
self.area.queue_draw()
else:
r = self.path[:-1].copy()
r.reverse()
for ind in r:
o = o[ind]
if type(o) == list:
self.options = o
else:
self.options = o["options"]
self.area.queue_draw()
del self.path[0]
def on_move(self,widget,data):
self.area.queue_draw()
self.mouse_x = data.x
self.mouse_y = data.y
mouse_angle = -(math.atan2(self.mouse_x-self.center[0],self.mouse_y-self.center[1]) + (math.pi/2)) # Get the angle from the center point of the menu to the mouse
current = 0
if self.mouse_x > self.width-(self.width/8):
self.selected = None
else:
for number, angle in enumerate(self.lines):
if mouse_angle < angle:
break
else:
current = number
self.selected = current
def draw_option(self, cr, i, option):
if self.selected != None:
if i == self.selected:
s = self.colors["selected"]
cr.set_source_rgb(s[0],s[1],s[2])
else:
s = self.colors["deselected"]
cr.set_source_rgb(s[0],s[1],s[2])
extents = cr.text_extents(option["label"])
cr.move_to(-self.width,0)
cr.show_text(option["label"])
cr.move_to(-self.width+extents.width,-extents.height/4)
cr.line_to(-self.width/8,0)
cr.stroke()
def draw_area(self, widget, cr):
self.lines = []
width = widget.get_allocated_width()
height = widget.get_allocated_height()
bg = self.colors["background"]
cr.set_source_rgb(bg[0],bg[1],bg[2])
cr.rectangle(0,0,width,height)
cr.fill() # Draw background
cr.translate(width,height/2) # All coordinates are relative to right center
cp = cr.get_current_point()
self.center = cr.user_to_device(cp[0],cp[1])
cr.select_font_face(self.config["font"],cairo.FontSlant.NORMAL,cairo.FontWeight.BOLD)
cr.set_line_width(4)
cr.set_font_size(20)
start_angle = (-math.pi/12)*(len(self.options)/2)
cr.rotate(start_angle)
angle = start_angle
cr.set_source_rgb(1,1,1)
for i, o in enumerate(self.options):
self.draw_option(cr, i, o)
cr.rotate(math.pi/12)
self.lines.append(angle)
angle += math.pi/12
config_home = os.getenv("XDG_CONFIG_HOME", expanduser("~/.config"))
config_file = toml.load(open(config_home + "/sike/config.toml"))
if config_file["config"]["use_i3"] == True:
from i3ipc import Connection
i3 = Connection()
focused = i3.get_tree().find_focused()
else:
i3 = None
win = MenuWindow(config_file["options"],config_file["colors"],config_file["config"])
screen = win.get_screen()
disp = screen.get_display()
monitor_count = disp.get_n_monitors()
if monitor_count == 1:
mon = disp.get_monitor(0)
else:
mon = disp.get_default_monitor()
g = mon.get_geometry()
win.scale(g.width,g.height)
GtkLayerShell.init_for_window(win)
GtkLayerShell.set_layer(win, GtkLayerShell.Layer.OVERLAY)
GtkLayerShell.set_anchor(win, GtkLayerShell.Edge.RIGHT, 1)
GtkLayerShell.set_anchor(win, GtkLayerShell.Edge.BOTTOM, 1)
GtkLayerShell.set_anchor(win, GtkLayerShell.Edge.TOP, 1)
win.show_all()
Gtk.main()