diff --git a/qwerty.py b/qwerty.py
index 3cbba9e..d0a99b0 100755
--- a/qwerty.py
+++ b/qwerty.py
@@ -4,6 +4,7 @@
import sys
import os
import re
+import time
from Xlib import X,display,Xatom
import Xlib.protocol.event
@@ -21,6 +22,9 @@ SHIFT = 1
CONTROL = 2
ALT = 4
+OK = True
+CANCEL = False
+
PADDING = 4
ICON_TOP_MARGIN = 35
LABEL_LEFT, LABEL_TOP = 15,25
@@ -221,16 +225,33 @@ class SectionButton(SuperButton):
cr.set_font_size(16)
cr.show_text(self.label)
-
class Section(object):
def __init__(self,title):
self.title = title
self.keys = []
+ self.keydict = {}
class Key(object):
def __init__(self,key):
self.key = key
self.mods = []
+
+ def __repr__(self):
+ return "<Key %s: %s>" % (self.key, self.title)
+
+def dict_from_keylist(keys):
+ return dict([((k.key,tuple(k.mods)), k) for k in keys])
+
+def parse_mods(s):
+ r = []
+ ms = s.upper().split()
+ if 'SHIFT' in ms:
+ r.append(SHIFT)
+ if ('CONTROL' in ms) or ('CTRL' in ms):
+ r.append(CONTROL)
+ if 'ALT' in ms:
+ r.append(ALT)
+ return r
def parse_config():
global sections
@@ -246,17 +267,6 @@ def parse_config():
if line.startswith(key):
return line[len(key):].strip()
- def parse_mods(s):
- r = []
- ms = s.upper().split()
- if 'SHIFT' in ms:
- r.append(SHIFT)
- if ('CONTROL' in ms) or ('CTRL' in ms):
- r.append(CONTROL)
- if 'ALT' in ms:
- r.append(ALT)
- return r
-
context = GLOBAL
for line in open(config_file):
line = line.strip()
@@ -344,6 +354,18 @@ def parse_config():
raise SyntaxError, "Unexpected 'Command' key in config"
continue
sections = dict([(s.order, s) for s in ts])
+ for s in sections.values():
+ s.keydict = dict_from_keylist(s.keys)
+
+def mods_str(ms):
+ r = ''
+ if SHIFT in ms:
+ r += 'Shift '
+ if CONTROL in ms:
+ r += 'Control '
+ if ALT in ms:
+ r += 'Alt'
+ return r
def save_config():
def write(key,value):
@@ -352,16 +374,6 @@ def save_config():
def writeln():
cf.write('\n')
- def mods_str(ms):
- r = ''
- if SHIFT in ms:
- r += 'Shift '
- if CONTROL in ms:
- r += 'Control '
- if ALT in ms:
- r += 'Alt'
- return r
-
global sections
global defsection
global speckeys
@@ -375,7 +387,7 @@ def save_config():
write('Order', S.order)
writeln()
- for K in S.keys:
+ for K in S.keydict.values():
write('Key', K.key)
if K.mods:
write('Mods', mods_str(K.mods))
@@ -395,6 +407,104 @@ def save_config():
cf.close()
+class LabeledEntry(gtk.HBox):
+ def __init__(self,label):
+ gtk.HBox.__init__(self)
+ self.set_spacing(5)
+ lbl = gtk.Label(label+": ")
+ self.entry = gtk.Entry()
+ self.pack_start(lbl, False)
+ self.pack_start(self.entry, True)
+
+ def get_text(self):
+ return self.entry.get_text()
+
+ def set_text(self,text):
+ self.entry.set_text(text)
+
+class KeyEditDialog(object):
+ def __init__(self):
+ self.return_code = CANCEL
+ self.exit = False
+ self.callback = None
+
+ self.window = gtk.Window()
+ self.window.set_title('Edit key')
+ self.window.connect('destroy', self.on_cancel)
+ self.window.set_border_width(5)
+
+ self.ed_key = LabeledEntry('Key')
+ self.ed_mods = LabeledEntry('Mods')
+ self.ed_title = LabeledEntry('Title')
+ self.ed_desc = LabeledEntry('Description')
+ self.ed_icon = LabeledEntry('Icon')
+ self.ed_class = LabeledEntry('Class')
+ self.ed_command = LabeledEntry('Command')
+
+ vb = gtk.VBox()
+ vb.set_spacing(3)
+ for box in [self.ed_key, self.ed_mods, self.ed_title, self.ed_desc, self.ed_icon, self.ed_class, self.ed_command]:
+ vb.pack_start(box, False)
+ ok = gtk.Button(stock=gtk.STOCK_OK)
+ ok.connect('clicked', self.on_ok)
+ cancel = gtk.Button(stock=gtk.STOCK_CANCEL)
+ cancel.connect('clicked', self.on_cancel)
+ okbox = gtk.HBox()
+ okbox.set_spacing(5)
+ okbox.pack_end(cancel, False)
+ okbox.pack_end(ok, False)
+ main = gtk.VBox()
+ main.pack_start(vb, True)
+ main.pack_start(okbox, False)
+ self.window.add(main)
+ self.window.set_size_request(400,300)
+
+ def show(self,G):
+ self.window.show_all()
+ self.G = G
+
+ def hide(self):
+ self.exit = True
+ self.window.hide()
+ K = self.get_key()
+ if not K:
+ return
+ self.G.S.keydict[K.key,tuple(K.mods)] = K
+ self.G.show_section()
+
+ def set_key(self,K):
+ self.ed_key.set_text(K.key)
+ self.ed_mods.set_text(mods_str(K.mods))
+ self.ed_title.set_text(K.title)
+ if hasattr(K,'desc'):
+ self.ed_desc.set_text(K.desc)
+ self.ed_icon.set_text(K.icon)
+ if hasattr(K,'cls'):
+ self.ed_class.set_text(K.cls)
+ self.ed_command.set_text(K.command)
+
+ def get_key(self):
+ K = Key(self.ed_key.get_text())
+ K.mods = parse_mods(self.ed_mods.get_text())
+ K.title = self.ed_title.get_text()
+ if not K.title:
+ return None
+ d = self.ed_desc.get_text()
+ if d:
+ K.desc = d
+ K.icon = self.ed_icon.get_text()
+ d = self.ed_class.get_text()
+ if d:
+ K.cls = d
+ K.command = self.ed_command.get_text()
+ return K
+
+ def on_ok(self,widget):
+ self.return_code = OK
+ self.hide()
+
+ def on_cancel(self,widget):
+ self.hide()
class GUI(object):
def __init__(self):
@@ -491,7 +601,6 @@ class GUI(object):
for cls in self.convert_class(clss):
self.by_class[cls] = w
-
def fill_taskbar(self):
def rm(widget):
self.taskbar.remove(widget)
@@ -567,7 +676,6 @@ class GUI(object):
return self.key_in(kv,names)
def key_released(self,widget,event):
-
if self.key_in_mods(event.keyval):
mods = self.translate_mods(event)
@@ -614,9 +722,15 @@ class GUI(object):
elif k in ALPHABET.lower():
self.do_button(k, mods)
+ def Key_by_key(self,key,mods=[]):
+ ks = self.S.keydict
+ try:
+ return ks[key, tuple(mods)]
+ except KeyError:
+ return None
+
def key_exec(self,key,mods):
- ks = dict([((k.key,tuple(k.mods)), k) for k in self.S.keys])
- cmd = ks[key,tuple(mods)].command
+ cmd = self.Key_by_key(key,mods).command
os.system(cmd + " &")
def do_button(self,key, mods):
@@ -650,7 +764,20 @@ class GUI(object):
else:
os.system(key.command + ' &')
+ def edit_key(self,K,key=''):
+ ed = KeyEditDialog()
+ if K:
+ ed.set_key(K)
+ else:
+ ed.ed_key.set_text(key)
+ ed.show(self)
+
def on_button(self,widget,event=None,mods=[]):
+ if event and event.button == 3:
+ K = self.Key_by_key(widget.key, mods)
+ self.edit_key(K, widget.key)
+ return
+
if widget.running:
self.activate_window(widget.cls)
else:
@@ -666,9 +793,14 @@ class GUI(object):
for b in self.buttons.values():
b.queue_draw()
- def show_section(self,k,mods):
+ def show_section(self,k=None,mods=None):
global sections
global defsection
+
+ if not k:
+ k = (self.S.order+1) % 10
+ if not mods:
+ mods = []
self.collect_windows()
@@ -688,7 +820,7 @@ class GUI(object):
btn = self.buttons[b]
btn.clear()
- for K in self.S.keys:
+ for K in self.S.keydict.values():
if K.mods != mods:
continue
k = K.key