def on_b1_press_dt(self, event): item = self.device_tree.identify('item', event.x, event.y) if item: self.add_button.config(state="active") for widget in self.fr.winfo_children(): widget.destroy() dt_type = self.device_tree.item(item, "text") self.v = StringVar() self.v.set(dt_type) # initialize b = Radiobutton(self.fr, text=dt_type, variable=self.v, value=dt_type) b.pack(anchor="w") macros = self.device_tree.item(item, "values")[0] if not macros == "None": l = macros.split(" ") for mstr in l: b = Radiobutton(self.fr, text=mstr, variable=self.v, value=mstr) b.pack(anchor="w") b.select()
def _create_ui(self): '''Create the UI for this panel.''' self._ship_var = IntVar() self.ship_buttons = {} for i, ship in enumerate(Ship.SHORT_NAMES): b = Radiobutton(self, text=Ship.NAMES[ship].title(), value=i, variable=self._ship_var, indicatoron=False) b.pack(anchor=W, pady=10) b.grid(sticky=N + S + E + W) # and a sort-of experimental feature... b.ship_state = self.UNPLACED # save it self.ship_buttons[ship] = b
class Task(Frame): def __init__(self, master=None, work=WORK_TM, rest=REST_TM, server=HOST, port=PORT, mode='fascist'): """create the task widget and get things started""" self.lid_state = "open" self.lid_time = time.time() self.interrupt_count = 0 self.then = 0.0 self.old_work = 0.0 self.state = "working" self.cancel_rest = 0 self.log = logging.getLogger(__name__) Frame.__init__(*(self, master)) self.mode = StringVar() self.mode.set(mode) # "fascist" or "friendly" # create main interactor window self.workmeter = Meter(self, background="grey50") self.workmeter.pack() self.work_frame = Frame(self) self.work_frame.pack() self.work_label = Label(self.work_frame, text="Work time:") self.work_label.pack(side=LEFT) self.work_scl = Scale(self.work_frame, orient=HORIZONTAL, from_=1, to=max(45, work), command=self.reset_duration) self.work_scl.set(work) self.work_scl.pack(side=LEFT) self.rest_frame = Frame(self) self.rest_frame.pack() self.rest_label = Label(self.rest_frame, text="Rest time:") self.rest_label.pack(side=LEFT) self.rest_scl = Scale(self.rest_frame, orient=HORIZONTAL, from_=1, to=max(15, rest), command=self.reset_duration) self.rest_scl.set(rest) self.rest_scl.pack(side=LEFT) self.radio_frame = Frame(self) self.radio_frame.pack() self.dictator = Radiobutton(self.radio_frame, text="Fascist", variable=self.mode, value="fascist") self.friend = Radiobutton(self.radio_frame, text="Friendly", variable=self.mode, value="friendly") self.dictator.pack(side=LEFT) self.friend.pack(side=LEFT) self.button_frame = Frame(self) self.button_frame.pack() self.restb = Button(self.button_frame, text="Rest", command=self.rest) self.restb.pack(side=LEFT) self.stopb = Button(self.button_frame, text="Quit", command=self.quit) self.stopb.pack(side=LEFT) self.helpb = Button(self.button_frame, text="Help", command=self.help) self.helpb.pack(side=LEFT) # create the cover window self.cover = Toplevel(background="black") self.cover.withdraw() # user can't resize it self.cover.resizable(0, 0) # when displayed, it should cover all displays (w, h) = (self.winfo_vrootwidth(), self.winfo_vrootheight()) if self.log.getEffectiveLevel() <= logging.DEBUG: # but we reduce it while debugging w, h = (w / 5, h / 5) self.cover.geometry("%dx%d+0+0" % (w, h)) # and it's undecorated self.cover.overrideredirect(1) # cover contains a frame with rest message and meter f = Frame(self.cover, background="black") self.restnote = Label(f, background="black", foreground="white") self.restmeter = Meter(f, background="grey50", height=10, width=200) self.restnote.pack(pady=2) self.restmeter.pack(fill="x", expand=1, pady=2) self.cancel_button = Button(f, text="Cancel Rest", command=self.cancel) f.pack() # initialize interrupt information self.linux_interrupts = 0 # used by the default activity checker self.mouse = None self.setup_server(server, port) # self.last_int is the last time the server was alerted to activity # self.now is the server's notion of the current time # idle time is therefore max(0, self.now-self.last_int) (self.last_int, _w_time, _r_time, self.now) = self.server.get() self.idle = max(0, self.now - self.last_int) self.bgcolor = self["background"] # start the ball rolling self.after(CHK_INT, self.tick) self.work() def setup_server(self, server, port): if server is None: self.server = collector.Collector() self.log.debug("using private Collector()") return self.server = xmlrpc_client.ServerProxy("http://%s:%d" % (server, port)) try: self.server.get() self.log.debug("found existing server") except socket.error: if server in ["", "localhost", "127.0.0.1"]: cmd = "watch-server.py" args = ["-p", "%d" % port] pid = os.spawnvp(os.P_NOWAIT, cmd, args) # wait briefly for server to start time.sleep(0.2) self.server = xmlrpc_client.ServerProxy("http://%s:%d" % (server, port), allow_none=True) # try connecting for _i in range(10): try: self.server.get() atexit.register(os.kill, pid, signal.SIGHUP) self.log.debug("spawned server") return except socket.error: time.sleep(0.1) # nothing else worked, so fall back to an embedded collector self.server = collector.Collector() self.log.debug("using private Collector()") def reset_duration(self, _dummy=None): """reset work/rest interval lengths to current scale values""" wtime = self.work_scl.get() self.workmeter.set_range(self.workmeter.min_val, self.workmeter.min_val + wtime * 60) self.restmeter.set_range( self.restmeter.min_val, self.restmeter.min_val + self.rest_scl.get() * 60) # only time the user can fiddle the work/rest meters is during # the work phase, so the only scale change that matters for extending # or contracting the end of the interval is the work scale try: delta = wtime - self.old_work except AttributeError: delta = 0 self.log.debug(__("then: {} delta: {}m", hhmm(self.then), delta)) self.then = self.then + delta * 60 self.old_work = wtime self.server.put(self.work_scl.get(), self.rest_scl.get()) def work(self): """start the work period""" self.reset_warning() self.restmeter.reset() self.state = "working" self.then = self.now + self.work_scl.get() * 60 self.log.debug(__("work: then: {}", hhmm(self.then))) self.workmeter.set_range(self.now, self.then) self.workmeter.reset() self.cover.withdraw() def warn_work_end(self): """alert user that work period is almost up""" self.set_background("yellow") def reset_warning(self): """back to plain old grey bg""" self.set_background(self.bgcolor) def set_background(self, color): for w in (self, self.work_scl, self.rest_scl, self.dictator, self.friend, self.button_frame, self.stopb, self.restb, self.helpb, self.work_frame, self.rest_frame, self.radio_frame, self.work_label, self.rest_label): w["background"] = color def rest(self): """overlay the screen with a window, preventing typing""" self.cancel_rest = 0 self.workmeter.reset() self.state = "resting" # the user may not have been typing or mousing right up to the # work/rest threshold - give credit for whatever rest time has # already been accumulated resttime = self.rest_scl.get() * 60 - (self.now - self.last_int) if resttime < 0: self.work() return mins, secs = divmod(resttime, 60) self.then = self.now + resttime self.cover.deiconify() self.cover.tkraise() resttext = ("Rest for %dm%02ds please..." % (mins, secs)) self.restnote.configure(text=resttext) self.restmeter.set_range(self.now, self.then) self.restmeter.reset() if self.mode.get() == "friendly": self.cancel_button.pack(pady=2) else: self.cancel_button.pack_forget() self.log.debug( __("rest: state: {} now: {} then: {} active? {}", self.state, hhmm(self.now), hhmm(self.then), self.check_activity())) def help(self): Dialog(self.master, title="Help", content=usageText()) ### ---- define activity checkers here ---- ### # keyed by sys.platform or "default" to return a method that checks # for mouse/keyboard activity _dispatch = {} def check_activity(self): """check mouse/keyboard activity info where possible, call platform-dependent routine to get mouse and keyboard info, otherwise, just return mouse info in all cases, the value returned should evaluate to False if no activity was detected. """ active = False if self.lid_state == "open": dflt = self._dispatch["default"] checker = self._dispatch.get(sys.platform, dflt) active = checker(self) if active: self.server.tick() return active def check_mouse(self): """default checker, just compares current w/ saved mouse pos""" mouse = self.winfo_pointerxy() try: return mouse != self.mouse finally: self.mouse = mouse _dispatch["default"] = check_mouse def get_linux_interrupts(self): count = 0 # Can't seem to find mouse interrupts, so for now, just watch # keyboard and mix add get_mouseinfo() output as a substitute for # mouse interrupts. last_count = self.interrupt_count for line in open("/proc/interrupts"): fields = line.split() if fields[0] == "1:": count = sum(int(fields[n]) for n in range(1, 8)) self.interrupt_count = count break return self.check_mouse() or self.interrupt_count > last_count _dispatch["linux"] = get_linux_interrupts def check_lid_state(self): if os.path.exists(LID_STATE): for line in open(LID_STATE): fields = line.strip().split() if fields[0] == "state:": return self.maybe_change_lid_state(fields[1]) else: self.lid_state = "open" return 0 def maybe_change_lid_state(self, state): """Take necessary action when lid state changes. Return True if lid state changed. """ idle = 0 if state != self.lid_state: self.log.info(__("lid state changed: {}", state)) lid_time = time.time() if state == "open": idle = lid_time - self.lid_time self.log.info(__("idle for {}s", idle)) self.lid_state = state self.lid_time = lid_time return idle def tick(self): """perform periodic checks for activity or state switch""" try: self._tick() finally: self.after(CHK_INT, self.tick) def _tick(self): (self.last_int, work_time, rest_time, self.now) = self.server.get() # check for mouse or keyboard activity idle_time = self.check_lid_state() if idle_time > rest_time * 60: self.log.info( __("The lid is up! Back to work: {}", hhmm(idle_time))) self.work() return active = self.check_activity() idle = max(0, self.now - self.last_int) # check to see if the work/rest scales got adjusted by another # watch instance if (self.work_scl.get() != work_time or self.rest_scl.get() != rest_time): self.work_scl.set(work_time) self.rest_scl.set(rest_time) self.log.debug( __("work: state: {} now: {} then: {} active? {}", self.state, hhmm(self.now), hhmm(self.then), active)) if self.state == "resting": # user explicitly cancelled the rest or the idle period # exceeded the desired rest time if self.cancel_rest or idle > rest_time * 60: self.work() return # make sure the rest window is as far up the window stack as # possible self.cover.tkraise() if idle <= self.idle: # user moved something - extend rest by a second self.then += 1 self.restmeter.set_range(self.restmeter.min_val, self.then) self.restmeter.set(self.now) self.idle = idle # update message to reflect rest time remaining timeleft = int(round(self.then - self.now)) minleft, secleft = divmod(timeleft, 60) resttext = ("Rest for %dm%02ds please..." % (minleft, secleft)) self.restnote.configure(text=resttext) else: # if it's been at least the length of the rest interval # since last interrupt, reset the work interval if idle >= rest_time * 60: self.work() return self.idle = idle if self.now > self.then: # work period expired self.rest() return if self.now + 60 > self.then: # work period nearly expired - warn user self.warn_work_end() else: self.reset_warning() self.restmeter.set(self.now) self.workmeter.set(self.now) def cancel(self): self.cancel_rest = 1