#!/usr/bin/python # -*- coding: koi8-r -*- import gtk import gobject class SimpleMessageBox: """ just as name says - an simple message box """ def __init__(self, name, wmclass, title, text, buttonlabel, parentwin): self._w = gtk.Window() if parentwin: self._w.set_transient_for(parentwin) self._w.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self._w.set_title(title) self._w.set_wmclass(name + wmclass, name) self._w.set_resizable(False) self._w.connect('key_press_event', self._keyhandler) self._w.connect('destroy', self._destroy_cb) vbox = gtk.VBox(False, 5) vbox.set_border_width(10) self._w.add(vbox) hbox = gtk.HBox(False, 0) hbox.set_border_width(10) vbox.pack_start(hbox, 1, 1, 0) label = gtk.Label('\n' + text + '\n') hbox.pack_start(label, 1, 1, 0) button = gtk.Button(stock=buttonlabel) button.connect('clicked', self._close) vbox.pack_start(button, 0, 0, 0) self._alive = 1 self._w.show_all() def _keyhandler(self, widget, event): if event.keyval == gtk.keysyms.Escape: self.close() def _close(self, widget): self.close() def _destroy_cb(self, widget): self._alive = 0 def shown(self): return self._alive def focus(self): self._w.present() def close(self): self._w.destroy() class Interface: def __init__(self, progname, stations, \ path_cb = None, station_cb = None, city_cb = None, dtime_cb = None, delta_cb = None, zoom_cb = None, \ xsize = 1024, ysize = 800, delta = 5, \ citylist = None, citynow = 0, compact = False, zoomlist = None, zoomnow = 0): maximize = False if compact: if not xsize: xsize = 640 maximize = True if not ysize: ysize = 480 maximize = True else: if not xsize: xsize = 1024 maximize = True if not ysize: ysize = 800 maximize = True self.path_cb = path_cb self.station_cb = station_cb self.city_cb = city_cb self.dtime_cb = dtime_cb self.delta_cb = delta_cb self.zoom_cb = zoom_cb self.stations = stations self.dont_set_path = False self.dont_set_from = False self.dont_set_to = False self.citylist = citylist self.dont_set_city = False self.da = None self.swin = None self.label_found_text = [_("Found paths"), ""] self.label_time_text = [_("Time of a day:"), ""] self.label_city_text = [_("Map:"), ""] self.menu_items = [(_("Help"), "help"), (_("Toggle compact mode"), "compact"), (_("Quit"), "quit")] self.compact_mode = not compact #hack =) self.zoomlist = zoomlist self.zoomnow = zoomnow if self.zoomlist and len(self.zoomlist): self.menu_items.insert(2, ([_("Zoom"), self.zoomlist], "zoom")) self.middle_pressed = False self.middle_button = None self.middle_x = 0 self.middle_y = 0 self.button_press_treshold = 5 self.move_started = False self.help_win = None self.helptext = _("Mouse bindings on Map display:\n\n" "Left mouse click - select source station\n" "Right mouse click - select destination station\n" "Right mouse click and hold - context menu\n" "Any mouse click and mouse move - scroll map around" ) self.progname = progname self.win = gtk.Window() self.win.set_title(progname) self.win.set_wmclass(progname + 'Main', progname) self.win.set_resizable(True) self.win.set_border_width(5) self.xsize = xsize self.ysize = ysize self.win.set_default_size(self.xsize, self.ysize) self.win.connect('configure_event', self.__configure_win_cb) self.tips = gtk.Tooltips() vbox = gtk.VBox(False, 5) self.win.add(vbox) hbox = gtk.HBox(False, 5) vbox.pack_start(hbox, False) self.st_hbox = hbox frame = gtk.Frame(_("Left mouse button")) hbox.pack_start(frame, True) thbox = gtk.HBox(False, 5) thbox.set_border_width(5) frame.add(thbox) label = gtk.Label(_("Source")) thbox.pack_start(label, False) self.cb_from = self.create_ebox(self.stations) self.cb_from.child.connect("changed", self.from_selected) thbox.pack_start(self.cb_from, True) frame = gtk.Frame(_("Right mouse button")) hbox.pack_start(frame, True) thbox = gtk.HBox(False, 5) thbox.set_border_width(5) frame.add(thbox) label = gtk.Label(_("Destination")) thbox.pack_start(label, False) self.cb_to = self.create_ebox(self.stations) self.cb_to.child.connect("changed", self.to_selected) thbox.pack_start(self.cb_to, True) frame = gtk.Frame() vbox.pack_start(frame, False) tvbox = gtk.VBox(False, 5) tvbox.set_border_width(5) frame.add(tvbox) thbox = gtk.HBox(False, 5) tvbox.pack_start(thbox, False) self.button_compact = gtk.Button("") self.button_compact.set_relief(gtk.RELIEF_NONE) thbox.pack_end(self.button_compact, False) self.button_help = gtk.Button("") image = gtk.Image() image.set_from_stock(gtk.STOCK_HELP, gtk.ICON_SIZE_BUTTON) self.button_help.set_image(image) self.button_help.connect("clicked", self.help_clicked) thbox.pack_end(self.button_help, False) self.tips.set_tip(self.button_help, _("Show help")) self.label_found = gtk.Label(self.label_found_text[0]) thbox.pack_start(self.label_found, False) self.cb_path = gtk.combo_box_new_text() thbox.pack_start(self.cb_path, True) self.cb_path.set_sensitive(False) self.cb_path.connect("changed", self.path_selected) self.cb_city = gtk.combo_box_new_text() thbox.pack_end(self.cb_city, False) self.citynow = 0 i = 0 for c in self.citylist: self.cb_city.append_text(c[0]) if c[1] == citynow: self.citynow = i i += 1 self.cb_city.set_active(self.citynow) self.label_city = gtk.Label(self.label_city_text[0]) thbox.pack_end(self.label_city, False) if len(self.citylist) < 2: self.cb_city.set_sensitive(False) self.cb_city.connect("changed", self.city_selected) self.cb_dtime = gtk.combo_box_new_text() thbox.pack_end(self.cb_dtime, False) for c in _('Day'), _('Night'): self.cb_dtime.append_text(c) self.cb_dtime.set_active(0) self.label_time = gtk.Label(self.label_time_text[0]) thbox.pack_end(self.label_time, False) self.cb_dtime.connect("changed", self.dtime_selected) thbox = gtk.HBox(False, 5) tvbox.pack_start(thbox, False) label = gtk.Label(_("Shortest way:")) thbox.pack_start(label, False) self.label_shortest = gtk.Label("") thbox.pack_start(self.label_shortest, False) if self.zoomlist and len(self.zoomlist): self.cb_zoom = gtk.combo_box_new_text() thbox.pack_end(self.cb_zoom, False) a = 0 for c in self.zoomlist: self.cb_zoom.append_text(c[0]) if c[1] == self.zoomnow: a = self.zoomlist.index(c) self.cb_zoom.set_active(a) self.label_zoom = gtk.Label(_('Zoom')) thbox.pack_end(self.label_zoom, False) self.cb_zoom.connect("changed", self.zoom_selected) adj = gtk.Adjustment(delta, 0, 99, 1, 10, 10) self.maxerror_cb = gtk.SpinButton(adj, 1, 0) self.maxerror_cb.set_numeric(True) thbox.pack_end(self.maxerror_cb, False) self.maxerror_cb.connect("value_changed", self.maxerror_selected) label = gtk.Label(_("Time delta:")) thbox.pack_end(label, False) self.sh_hbox = thbox self.big_vbox = vbox self.win.show_all() self.compact_clicked(None) self.button_compact.connect("clicked", self.compact_clicked) if maximize: self.win.maximize() def menu_callback(self, data): if data == "help": self.help_clicked(None) elif data == "compact": self.compact_clicked(None) elif data == "quit": self.quit_clicked(None) elif data.startswith("zoom"): self.cb_zoom.set_active(map(lambda a: a[1], self.zoomlist).index(float(data[5:]))) self.zoom_selected(None) def quit_clicked(self, widget): if self.quit_cb: self.quit_cb(None) def help_clicked(self, widget): if not self.help_win or not self.help_win.shown(): self.help_win = SimpleMessageBox(self.progname, 'Help', 'Help', self.helptext, gtk.STOCK_OK, self.win) else: x, y = self.win.get_position() w, h = self.win.get_size() dw, dh = self.help_win._w.get_size() self.help_win._w.move(x + (w - dw) / 2, y + (h - dh) / 2) self.help_win.focus() def compact_clicked(self, widget): self.compact_mode = not self.compact_mode if not self.compact_mode: self.st_hbox.show() self.sh_hbox.show() self.label_found.set_label(self.label_found_text[0]) self.label_time.set_label(self.label_time_text[0]) self.label_city.set_label(self.label_city_text[0]) self.tips.set_tip(self.button_compact, _("Switch to compact mode")) st = gtk.STOCK_GO_DOWN else: self.st_hbox.hide() self.sh_hbox.hide() self.label_found.set_label(self.label_found_text[1]) self.label_time.set_label(self.label_time_text[1]) self.label_city.set_label(self.label_city_text[1]) self.tips.set_tip(self.button_compact, _("Switch to normal mode")) st = gtk.STOCK_GO_UP image = gtk.Image() image.set_from_stock(st, gtk.ICON_SIZE_BUTTON) self.button_compact.set_image(image) def __configure_win_cb(self, widget, event): self.xsize, self.ysize = widget.get_size() def __pack_da(self, da, width, height): self.swin = gtk.ScrolledWindow() self.swin.set_shadow_type(gtk.SHADOW_NONE) self.swin.set_policy(gtk.POLICY_ALWAYS, gtk.POLICY_ALWAYS) self.swin.set_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_MASK) self.swin.connect("button_press_event", self.bp) self.swin.connect("button_release_event", self.bp) self.swin.connect("motion_notify_event", self.bp) self.big_vbox.pack_start(self.swin, True) if da: if type(da) == gtk.DrawingArea: self.swin.add_with_viewport(self.da) else: self.swin.add(self.da) def bp(self, widget, event): if event.type == gtk.gdk.BUTTON_PRESS: #and event.button == 2: self.middle_pressed = True self.move_started = False self.middle_button = event.button self.middle_x = event.x_root self.middle_y = event.y_root elif event.type == gtk.gdk.BUTTON_RELEASE and event.button == self.middle_button: self.middle_pressed = False elif event.type == gtk.gdk.MOTION_NOTIFY and self.middle_pressed: flags = gtk.gdk.device_get_core_pointer().get_state(self.win.get_root_window())[1] if (self.middle_button == 3 and not (flags & gtk.gdk.BUTTON3_MASK)) or \ (self.middle_button == 2 and not (flags & gtk.gdk.BUTTON2_MASK)) or \ (self.middle_button == 1 and not (flags & gtk.gdk.BUTTON1_MASK)): self.middle_pressed = False return if not self.move_started and \ abs(self.middle_x - event.x_root) < self.button_press_treshold and \ abs(self.middle_y - event.y_root) < self.button_press_treshold: return self.move_started = True def adjust(adj, d): if d != 0: av = adj.value + d if av < adj.lower: #round it av = adj.lower elif av > adj.upper - adj.page_size: av = adj.upper - adj.page_size adj.value = av adjust(widget.get_hadjustment(), self.middle_x - event.x_root) adjust(widget.get_vadjustment(), self.middle_y - event.y_root) self.middle_x = event.x_root self.middle_y = event.y_root def set_da(self, da, width, height): if self.swin: if self.da: self.swin.child.remove(self.da) self.swin.remove(self.swin.child) self.big_vbox.remove(self.swin) del self.swin del self.da self.da = da self.__pack_da(self.da, width, height) self.swin.show_all() def set_path_cb(self, cb): self.path_cb = cb def set_city_cb(self, cb): self.city_cb = cb def set_dtime_cb(self, cb): self.dtime_cb = cb def set_station_cb(self, cb): self.station_cb = cb def set_delta_cb(self, cb): self.delta_cb = cb def set_zoom_cb(self, cb): self.zoom_cb = cb def set_dtime(self, dtime): self.cb_dtime.set_active(dtime) def __num_station__(self, text): for s in self.stations: if s[0] == text: return s[1] return None def __text_station__(self, num): for s in self.stations: if s[1] == num: return s[0] return "" def maxerror_selected(self, widget): if self.delta_cb: self.delta_cb(int(widget.get_value())) def from_selected(self, foo): if not self.dont_set_from: num = self.__num_station__(self.cb_from.child.get_text()) if num != None: self.station_cb(num, True) self.cb_to.child.grab_focus() def to_selected(self, foo): if not self.dont_set_to: num = self.__num_station__(self.cb_to.child.get_text()) if num != None: self.station_cb(num, False) self.cb_from.child.grab_focus() def set_st_list(self, stations): self.stations = stations self.dont_set_from = True self.dont_set_to = True for cb in self.cb_from, self.cb_to: cb.child.set_text("") for p in xrange(len(cb.get_model()), 0, -1): cb.remove_text(p - 1) for s in stations: cb.append_text(s[0]) self.dont_set_from = False self.dont_set_to = False def set_from(self, station): self.dont_set_from = True self.cb_from.child.set_text(self.__text_station__(station)) self.dont_set_from = False def set_to(self, station): self.dont_set_to = True self.cb_to.child.set_text(self.__text_station__(station)) self.dont_set_to = False def set_path_list(self, plist): for p in xrange(len(self.cb_path.get_model()), 0, -1): self.cb_path.remove_text(p - 1) for p in plist: self.cb_path.append_text(p) if len(plist) > 0: self.label_shortest.set_text(plist[0]) self.dont_set_path = True self.cb_path.set_active(0) self.dont_set_path = False else: self.label_shortest.set_text("") if len(plist) > 1: self.cb_path.set_sensitive(True) else: self.cb_path.set_sensitive(False) def path_selected(self, foo): if self.path_cb and not self.dont_set_path: self.path_cb(self.cb_path.get_active()) def city_selected(self, foo): if self.city_cb and not self.dont_set_city: self.city_cb(self.citylist[self.cb_city.get_active()][1]) def set_win_title(self, title): self.win.set_title(title) def dtime_selected(self, foo): if self.dtime_cb: self.dtime_cb(self.cb_dtime.get_active()) def zoom_selected(self, foo): if self.zoom_cb: self.zoom_cb(self.zoomlist[self.cb_zoom.get_active()][1]) def create_ebox(self, names): ls = gtk.ListStore(gobject.TYPE_STRING) if names: map(lambda a: ls.append([a[0]]), names) ce = gtk.ComboBoxEntry(ls, 0) compl = gtk.EntryCompletion() compl.set_model(ls) compl.set_text_column(0) ce.child.set_completion(compl) return ce