#!/usr/bin/python # -*- coding: koi8-r -*- import gtk import gobject import pango from math import sqrt, atan, degrees white = gtk.gdk.Color(red = 65535, green = 65535, blue = 65535) black = gtk.gdk.Color(red = 0, green = 0, blue = 0) red = gtk.gdk.Color(red = 65535, green = 0, blue = 0) green = gtk.gdk.Color(red = 0, green = 65535, blue = 0) blue = gtk.gdk.Color(red = 0, green = 0, blue = 65535) yellow = gtk.gdk.Color(red = 65535, green = 65535, blue = 0) #Borrowed from gtk. Original comment: # Solve the tridiagonal equation system that determines the second # derivatives for the interpolation points. (Based on Numerical # Recipes 2nd Edition.) def spline_solve(xarr, yarr): res = [0.0] * len(xarr) tmparr = [0.0] * len(xarr) for i in xrange(1, len(xarr) - 1): d1 = xarr[i + 1] - xarr[i - 1] sig = (xarr[i] - xarr[i - 1]) / d1 p = sig * res[i - 1] + 2.0 res[i] = (sig - 1.0) / p d2 = (xarr[i + 1] - xarr[i]) d3 = (xarr[i] - xarr[i - 1]) tmparr[i] = (yarr[i + 1] - yarr[i]) / d2 - (yarr[i] - yarr[i - 1]) / d3 tmparr[i] = (6.0 * tmparr[i] / d1 - sig * tmparr[i - 1]) / p res[len(xarr) - 1] = 0.0 for k in xrange(len(xarr) - 2, -1, -1): res[k] = res[k] * res[k + 1] + tmparr[k] return res def spline_eval(xarr, yarr, carr, x): k_lo = 0 k_hi = len(xarr) - 1 while k_hi - k_lo > 1: k = (k_hi + k_lo) / 2 if xarr[k] > x: k_hi = k else: k_lo = k h = float(xarr[k_hi] - xarr[k_lo]) if h <= 0.0: print 'FOO' return 0 a = (xarr[k_hi] - x) / h b = (x - xarr[k_lo]) / h return a * yarr[k_lo] + b * yarr[k_hi] + \ ((a * a * a - a) * carr[k_lo] + (b * b * b - b) * carr[k_hi]) * (h * h) / 6.0 class MapDisplay: def __init__(self, lines, stations, vectors, selcb, spbhack): self.gc = None self.scb = selcb self.menu_cb = None self.menu_items = None self.toggle_trans_cb = None self.Lines = lines self.Stations = stations self.Vectors = vectors self.spbhack = spbhack self.pixbuf = None #count picture area minx = min(map(lambda st: min(st['x'] - st['diameter'] / 2 - 5, st['namerect'][0] - 5), self.Stations.values())) miny = min(map(lambda st: min(st['y'] - st['diameter'] / 2 - 5, st['namerect'][1] - 5), self.Stations.values())) maxx = max(map(lambda st: max(st['x'] + st['diameter'] / 2 + 5, st['namerect'][0] + st['namerect'][2] + 20), self.Stations.values())) maxy = max(map(lambda st: max(st['y'] + st['diameter'] / 2 + 5, st['namerect'][1] + st['namerect'][3] + 20), self.Stations.values())) self.da = gtk.DrawingArea() self.da.set_size_request(maxx + 1, maxy + 1) self.da.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.KEY_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK) self.da.connect("expose_event", self.expose) self.da.connect("button_press_event", self.bp) self.da.connect("button_release_event", self.bp) self.da.connect("motion_notify_event", self.bp) self.da.connect('configure_event', self.__configure_cb) self.button_pressed = None self.button_pressed_coords = [0, 0] self.button_press_treshold = 5 self.daw = self.da.get_allocation().width self.dah = self.da.get_allocation().height self.pw = maxx + 1 self.ph = maxy + 1 self.dx = 0 self.dy = 0 self.stfrom = None self.stto = None self.pathlist = None self.drawpath = False if self.Vectors.has_key('lineswidth'): self.pathwidth = self.Vectors['lineswidth'] - 5 else: self.pathwidth = self.Stations[0]['diameter'] / 4 if self.pathwidth == 0: self.pathwidth = 1 self.timeout = gobject.timeout_add(400, self.redraw, False) self.step = 0 self.STATE_OFF = 0 self.STATE_FROM = 1 self.STATE_TO = 2 def _create_colors_towhite(self, coldesc): c = map(lambda a: int(a, 16) * 256, (coldesc[0:2], coldesc[2:4], coldesc[4:6])) cl = map(lambda a: a + (65535 - a) / 2, c) return gtk.gdk.Color(c[0], c[1], c[2]), gtk.gdk.Color(cl[0] , cl[1], cl[2]) def __draw_dash_rect(self, step, c1, c2, x, y, w, h): cs = c1 ce = c2 if step == 0: cs = c2 ce = c1 self.gc.set_rgb_fg_color(cs) self.gc.set_line_attributes(2, gtk.gdk.LINE_SOLID, 0, 0) self.da.window.draw_rectangle(self.gc, False, x, y, w, h) self.gc.set_rgb_fg_color(ce) self.gc.set_line_attributes(2, gtk.gdk.LINE_ON_OFF_DASH, 0, 0) self.da.window.draw_rectangle(self.gc, False, x, y, w, h) def __draw_dash_arc(self, step, c1, c2, x, y, d): cs = c1 ce = c2 if step == 0: cs = c2 ce = c1 self.gc.set_rgb_fg_color(cs) self.gc.set_line_attributes(2, gtk.gdk.LINE_SOLID, 0, 0) self.da.window.draw_arc(self.gc, False, x, y, d, d, 0, 64 * 360) self.gc.set_rgb_fg_color(ce) self.gc.set_line_attributes(2, gtk.gdk.LINE_ON_OFF_DASH, 0, 0) self.da.window.draw_arc(self.gc, False, x, y, d, d, 0, 64 * 360) def draw_station(self, num, state): if num == None: return sx, sy, sd = self.Stations[num]['x'], self.Stations[num]['y'], self.Stations[num]['diameter'] ov = self.is_st_overlap([num] + self.Stations[num]['transfers']) if ov[0]: sx, sy, sd = ov[1], ov[2], ov[3] snx, sny, snw, snh = self.Stations[num]['namerectact'] snx -= 2 sny -= 2 snw += 4 snh += 4 if state == self.STATE_OFF: self.draw_pic(sx - sd / 2 - 1, sy - sd / 2 - 1, sd + 2, sd + 2) self.draw_pic(snx - 1, sny - 1, snw + 2, snh + 2) else: c = blue if state == self.STATE_FROM: c = red self.__draw_dash_rect(self.step, c, white, snx + self.dx, sny + self.dy, snw, snh) self.__draw_dash_arc(self.step, c, white, self.dx + sx - sd / 2, self.dy + sy - sd / 2, sd) def draw_path(self, path, state): points = list() gpoints = list() fr = path[0] for p in path[1:]: points.append(self._make_segments(fr, p)) fr = p for seg in points: if seg: for next in seg: gpoints.append((next[0], next[1])) if state: points = map(lambda a: (a[0] + self.dx, a[1] + self.dy), gpoints) self.gc.set_line_attributes(self.pathwidth + 2, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_ROUND) self.gc.set_rgb_fg_color(black) self.da.window.draw_lines(self.gc, points) self.gc.set_line_attributes(self.pathwidth, gtk.gdk.LINE_ON_OFF_DASH, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_ROUND) self.gc.set_rgb_fg_color(white) self.da.window.draw_lines(self.gc, points) else: minx = max(min(map(lambda a: a[0], gpoints)) - self.pathwidth - 2, 0) miny = max(min(map(lambda a: a[1], gpoints)) - self.pathwidth - 2, 0) maxx = min(max(map(lambda a: a[0], gpoints)) + self.pathwidth + 2, self.pw - 1) maxy = min(max(map(lambda a: a[1], gpoints)) + self.pathwidth + 2, self.ph - 1) self.draw_pic(minx, miny, maxx - minx, maxy - miny) def _make_segments(self, fr, to): xf, yf = self.Stations[fr]['x'], self.Stations[fr]['y'] xt, yt = self.Stations[to]['x'], self.Stations[to]['y'] if self.Stations[fr]['add'].has_key(to): if len(self.Stations[fr]['add'][to]['coords']) > 1: len1 = abs(xf - self.Stations[fr]['add'][to]['coords'][0][0]) + \ abs(yf - self.Stations[fr]['add'][to]['coords'][0][1]) len2 = abs(xf - self.Stations[fr]['add'][to]['coords'][1][0]) + \ abs(yf - self.Stations[fr]['add'][to]['coords'][1][1]) if len1 > len2: self.Stations[fr]['add'][to]['coords'].reverse() point = [(xf, yf)] + self.Stations[fr]['add'][to]['coords'] + [(xt, yt)] else: point = [(xf, yf), (xt, yt)] return point def draw_text_rotated(self, x, y, layout, drawable): (l, b, w, h), logicalRect = layout.get_pixel_extents() dw = layout.get_width() / pango.SCALE if dw > w: w = dw if x + w > drawable.get_size()[0]: dx = w else: dx = 0 gc = self.gc # save the background imageBack = drawable.get_image(x - dx, y, w, h) imageVert = drawable.get_image(x, y, h, w) # transform the vertical image, write it onto the renderer, # and draw the layout onto it imageFlip = gtk.gdk.Image(type = gtk.gdk.IMAGE_NORMAL, visual = drawable.get_visual(), width = w, height = h) if imageFlip is None or imageBack is None or imageVert is None: return imageFlip.set_colormap(drawable.get_colormap()) for i in range(w): for j in range(h): imageFlip.put_pixel(i, j, imageVert.get_pixel(j, w - i - 1)) drawable.draw_image(gc, imageFlip, 0, 0, x - dx, y, w, h) drawable.draw_layout(gc, x - dx, y - b, layout) # now get that image and flip it vertical imageIn = drawable.get_image(x - dx, y, w, h) imageOut = gtk.gdk.Image(type = gtk.gdk.IMAGE_NORMAL, visual = drawable.get_visual(), width = h, height = w) imageOut.set_colormap(drawable.get_colormap()) for i in range(w): for j in range(h): imageOut.put_pixel(j, i, imageIn.get_pixel(w - i - 1, j)) # draw the old background and the flipped text drawable.draw_image(gc, imageBack, 0, 0, x - dx, y, w, h) drawable.draw_image(gc, imageOut, 0, 0, x, y, h, w) def draw_st_arc(self, snum, xc, yc, d, num, pos): s = self.Stations[snum] c, cl = self._create_colors_towhite(self.Lines[s['line']]['color']) a2 = 360 * 64 / num a1 = 90 * 64 + a2 * pos if a1 >= 360 * 64: a1 -= 360 * 64 x = xc - d / 2 y = yc - d / 2 self.gc.set_rgb_fg_color(cl) self.pixbuf.draw_arc(self.gc, True, x, y, d, d, a1, a2) d = d - 2 x = xc - d / 2 y = yc - d / 2 self.gc.set_rgb_fg_color(c) self.pixbuf.draw_arc(self.gc, True, x, y, d, d, a1, a2) return a1, a2 def draw_st_circle(self, snum): s = self.Stations[snum] c, cl = self._create_colors_towhite(self.Lines[s['line']]['color']) d = s['diameter'] self.gc.set_rgb_fg_color(cl) self.pixbuf.draw_arc(self.gc, True, s['x'] - d / 2 - 1, s['y'] - d / 2 - 1, d + 2, d + 2, 0, 64 * 360) self.gc.set_rgb_fg_color(c) self.pixbuf.draw_arc(self.gc, True, s['x'] - d / 2, s['y'] - d / 2, d, d, 0, 64 * 360) if s['uc']: nd = d - 8 if nd <= 0: nd = d / 2 self.gc.set_rgb_fg_color(white) self.pixbuf.draw_arc(self.gc, True, s['x'] - nd / 2, s['y'] - nd / 2, nd, nd, 0, 64 * 360) def is_st_overlap(self, slist): extrad = -2 if self.spbhack: extrad = 4 overlap = False s = self.Stations[slist[0]] d = s['diameter'] minx = s['x'] - d / 2 miny = s['y'] - d / 2 maxx = minx + d maxy = miny + d for n in xrange(len(slist)): s = self.Stations[slist[n]] d = s['diameter'] minx = min(minx, s['x'] - d / 2) miny = min(miny, s['y'] - d / 2) maxx = max(maxx, s['x'] - d / 2 + d) maxy = max(maxy, s['y'] - d / 2 + d) if not overlap: r = gtk.gdk.Rectangle(s['x'] - d / 2, s['y'] - d / 2, d + extrad, d + extrad) for nd in slist[n + 1:]: sd = self.Stations[nd] dd = sd['diameter'] rd = gtk.gdk.Rectangle(sd['x'] - dd / 2, sd['y'] - dd / 2, dd + extrad, dd + extrad) rr = r.intersect(rd) if rr.width > 0 and rr.height > 0: overlap = True break d = max(maxx - minx, maxy - miny) x = minx + (maxx - minx) / 2 y = miny + (maxy - miny) / 2 return overlap, x, y, d def create_pixbuf(self): self.pixbuf = gtk.gdk.Pixmap(self.da.window, self.pw, self.ph, -1) self.pango_context = self.da.create_pango_context() self.pango_layout = pango.Layout(self.pango_context) self.gc.set_rgb_fg_color(white) self.pixbuf.draw_rectangle(self.gc, True, 0, 0, self.pw, self.ph) for i in self.Vectors['instructions']: if i[0] == 'set_rgb_fg_color': c, cl = self._create_colors_towhite(i[1]) self.gc.set_rgb_fg_color(c) elif i[0] == 'spline': self.gc.set_line_attributes(i[1], gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_ROUND) self.pixbuf.draw_lines(self.gc, i[2]) elif i[0] == 'text': self.pango_layout.set_font_description(pango.FontDescription(i[1]['font'] + " " + str(i[1]['size'] / 1.3))) self.pango_layout.set_text(i[1]['text']) self.pixbuf.draw_layout(self.gc, i[1]['x'], i[1]['y'], self.pango_layout) self.pango_layout.set_wrap(pango.WRAP_WORD) self.pango_layout.set_spacing(-1 * pango.SCALE) #FIXME: make font family configurable? fn = 'Sans' rffw = dict() for k in xrange(5): s = self.Stations[self.Stations.keys()[k]] w = s['namerect'][2] - 3 self.pango_layout.set_width(w * pango.SCALE) if s['namerect'][0] > s['x']: self.pango_layout.set_alignment(pango.ALIGN_LEFT) else: self.pango_layout.set_alignment(pango.ALIGN_RIGHT) self.pango_layout.set_text(s['name']) mindiff = 65535 ffw = 8 #FIXME: if 5 first stations have vertical labels this will fail for fw in xrange(3, 20): self.pango_layout.set_font_description(pango.FontDescription(fn + ' ' + str(fw))) (l1, b1, w1, h1), logicalRect = self.pango_layout.get_pixel_extents() diff = abs(logicalRect[2] - w) if diff < mindiff: mindiff = diff ffw = fw if rffw.has_key(ffw): rffw[ffw] += 1 else: rffw[ffw] = 1 ffw = rffw.keys()[0] ffn = rffw[ffw] for k in rffw.keys()[1:]: if rffw[k] > ffn: ffw = k ffn = rffw[k] self.pango_layout.set_font_description(pango.FontDescription(fn + ' ' + str(ffw))) #draw lines for l in self.Lines.values(): c, cl = self._create_colors_towhite(l['color']) points = dict() for s in l['stations']: for n in self.Stations[s]['neighbours']: if not points.has_key((s, n)) and not points.has_key((n, s)): uc = False if self.Stations[s]['uc'] or self.Stations[n]['uc']: uc = True points[(s, n)] = [self._make_segments(s, n), uc] for seg in points.values(): if seg[0]: self.gc.set_rgb_fg_color(c) if seg[1]: self.gc.set_line_attributes(self.pathwidth + 4, gtk.gdk.LINE_ON_OFF_DASH, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_ROUND) else: self.gc.set_line_attributes(self.pathwidth + 6, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_ROUND) self.pixbuf.draw_lines(self.gc, seg[0]) #draw transfers for par in [[black, 4, 0], [white, 2, 4]]: drawn = dict() #avoid drawing same things many times for st in self.Stations.values(): if len(st['transfers']) and not drawn.has_key(st['number']): self.gc.set_line_attributes(st['diameter'] - par[2] - 3, gtk.gdk.LINE_SOLID, 0, 0) trlist = [st['number']] + st['transfers'] ov = self.is_st_overlap(trlist) if ov[0]: self.gc.set_rgb_fg_color(par[0]) d = ov[3] + par[1] * 2 x = ov[1] - d / 2 y = ov[2] - d / 2 self.pixbuf.draw_arc(self.gc, True, x, y, d, d, 0, 64 * 360) else: for n in xrange(len(trlist)): ts = trlist[n] s = self.Stations[ts] d = s['diameter'] self.gc.set_rgb_fg_color(par[0]) self.pixbuf.draw_arc(self.gc, True, s['x'] - d / 2 - par[1], s['y'] - d / 2 - par[1], d + par[1] * 2, d + par[1] * 2, 0, 64 * 360) for dst in trlist[n + 1:]: ds = self.Stations[dst] self.pixbuf.draw_line(self.gc, s['x'], s['y'], ds['x'], ds['y']) drawn[ts] = 1 #draw circles drawn = dict() #avoid drawing same things many times for st in self.Stations.keys(): if not len(self.Stations[st]['transfers']): self.draw_st_circle(st) elif not drawn.has_key(st): trlist = [st] + self.Stations[st]['transfers'] trlist.sort(lambda a, b: cmp(self.Stations[a]['x'], self.Stations[b]['x'])) ov = self.is_st_overlap(trlist) for n in range(len(trlist)): if ov[0]: a1, a2 = self.draw_st_arc(trlist[n], ov[1], ov[2], ov[3], len(trlist), n) self.Stations[trlist[n]]['trrect'] = (ov[1], ov[2], ov[3], a1, a2) else: self.draw_st_circle(trlist[n]) drawn[trlist[n]] = 1 #draw station names for l in self.Lines.values(): c, cl = self._create_colors_towhite(l['color']) for st in l['stations']: s = self.Stations[st] if s['namerect'][2] < s['namerect'][3]: #vertical label self.pango_layout.set_width(s['namerect'][3] * pango.SCALE) if s['namerect'][1] < s['y']: self.pango_layout.set_alignment(pango.ALIGN_LEFT) else: self.pango_layout.set_alignment(pango.ALIGN_RIGHT) self.pango_layout.set_text(s['name']) (l, b, w, h), logicalRect = self.pango_layout.get_pixel_extents() if s['namerect'][3] > logicalRect[2]: if s['namerect'][1] >= s['y']: dx = 0 else: dx = logicalRect[0] + s['namerect'][3] - logicalRect[2] else: dx = logicalRect[0] s['namerectact'] = [s['namerect'][0] + logicalRect[1], s['namerect'][1] + dx, logicalRect[3], logicalRect[2]] self.gc.set_rgb_fg_color(white) self.draw_text_rotated(s['namerect'][0] - 1, s['namerect'][1] + 1, self.pango_layout,self.pixbuf) self.draw_text_rotated(s['namerect'][0] + 2, s['namerect'][1] - 2, self.pango_layout,self.pixbuf) self.gc.set_rgb_fg_color(black) self.draw_text_rotated(s['namerect'][0] + 1, s['namerect'][1] - 1, self.pango_layout,self.pixbuf) self.gc.set_rgb_fg_color(c) self.draw_text_rotated(s['namerect'][0], s['namerect'][1], self.pango_layout,self.pixbuf) else: self.pango_layout.set_width(s['namerect'][2] * pango.SCALE) if s['namerect'][0] > s['x']: self.pango_layout.set_alignment(pango.ALIGN_LEFT) else: self.pango_layout.set_alignment(pango.ALIGN_RIGHT) self.pango_layout.set_text(s['name']) (l, b, w, h), logicalRect = self.pango_layout.get_pixel_extents() s['namerectact'] = [logicalRect[0] + s['namerect'][0], logicalRect[1] + s['namerect'][1], logicalRect[2], logicalRect[3]] self.gc.set_rgb_fg_color(white) self.pixbuf.draw_layout(self.gc, s['namerect'][0] - 1, s['namerect'][1] - 1, self.pango_layout) self.pixbuf.draw_layout(self.gc, s['namerect'][0] + 2, s['namerect'][1] + 2, self.pango_layout) self.gc.set_rgb_fg_color(black) self.pixbuf.draw_layout(self.gc, s['namerect'][0] + 1, s['namerect'][1] + 1, self.pango_layout) self.gc.set_rgb_fg_color(c) self.pixbuf.draw_layout(self.gc, s['namerect'][0], s['namerect'][1], self.pango_layout) def redraw(self, full): if not self.da.window: return False if not self.gc: return True if not self.pixbuf: self.create_pixbuf() if full and self.pathlist and len(self.pathlist): self.draw_path(self.pathlist, self.drawpath) self.step = 1 - self.step self.draw_station(self.stfrom, self.STATE_FROM) self.draw_station(self.stto, self.STATE_TO) return True def set_path_list(self, pathlist): if self.pathlist and len(self.pathlist): self.drawpath = False self.redraw(True) self.pathlist = pathlist self.drawpath = True self.redraw(True) def set_start_station(self, st): self.draw_station(self.stfrom, self.STATE_OFF) self.stfrom = st self.redraw(True) def set_stop_station(self, st): self.draw_station(self.stto, self.STATE_OFF) self.stto = st self.redraw(True) def set_selection_cb(self, cb): self.scb = cb def set_menu(self, callback, items): self.menu_cb = callback self.menu_items = items def menu_item_act(self, widget, data): if self.menu_cb: self.menu_cb(data) def set_dtcb(self, cb): self.toggle_trans_cb = cb def toggle_transfer(self, widget, fr, to): if self.toggle_trans_cb: self.toggle_trans_cb('set', sfrom = fr, sto = to) def menu(self, st): def st_line(fr): return self.Stations[fr]['name'] + " " + self.Lines[self.Stations[fr]['line']]['name'] if self.button_pressed: self.button_pressed = None menu = gtk.Menu() dtdict = dict() if self.toggle_trans_cb: dtdict = self.toggle_trans_cb('get') if st and len(self.Stations[st]['transfers']): for t in self.Stations[st]['transfers']: if dtdict.has_key((st, t)): msg = _("Enable") else: msg = _("Disable") i = gtk.MenuItem(msg + _(' transfer from "') + st_line(st) + _('" to "') + st_line(t) + '"') i.connect('activate', self.toggle_transfer, st, t) menu.append(i) if len(dtdict.keys()): if st and len(self.Stations[st]['transfers']): i = gtk.SeparatorMenuItem() menu.append(i) i = gtk.MenuItem(_('Enable disabled transfers')) dtmenu = gtk.Menu() if len(dtdict.keys()) > 2: di = gtk.MenuItem(_("All")) di.connect('activate', self.toggle_transfer, None, None) dtmenu.append(di) added = dict() for dt in dtdict.keys(): if not added.has_key((dt[0], dt[1])): di = gtk.MenuItem(_('From "') + st_line(dt[0]) + _('" to "') + st_line(dt[1]) + '"') di.connect('activate', self.toggle_transfer, dt[0], dt[1]) dtmenu.append(di) added[(dt[0], dt[1])] = 1 added[(dt[1], dt[0])] = 1 i.set_submenu(dtmenu) menu.append(i) if len(dtdict.keys()) or (st and len(self.Stations[st]['transfers'])): i = gtk.SeparatorMenuItem() menu.append(i) for item in self.menu_items: if type(item[0]) == str: i = gtk.MenuItem(item[0]) i.connect('activate', self.menu_item_act, item[1]) menu.append(i) else: i = gtk.MenuItem(item[0][0]) submenu = gtk.Menu() for foo in item[0][1]: si = gtk.MenuItem(foo[0]) si.connect('activate', self.menu_item_act, item[1] + ' ' + str(foo[1])) submenu.append(si) i.set_submenu(submenu) menu.append(i) menu.show_all() menu.popup(None, None, None, 3, 0) return False def find_st_at_pos(self, x, y): #first - search in transfers for st in filter(lambda a: a.has_key('trrect'), self.Stations.values()): d = sqrt((x - st['trrect'][0]) ** 2 + (y - st['trrect'][1]) ** 2) if d <= st['trrect'][2] / 2: if x == st['trrect'][0]: a = 90 else: a = degrees(atan((y - st['trrect'][1]) / (x - st['trrect'][0]))) if a < 0: a = -a elif a != 0 or x < st['trrect'][0]: a = 180 - a if y > st['trrect'][1]: a += 180 a *= 64 a1 = st['trrect'][3] a2 = a1 + st['trrect'][4] if ((a >= a1 and a <= a2) or (a2 > 360 * 64 and a < a2 - 360 * 64)): return st['number'] for st in self.Stations.values(): sx, sy, sd = st['x'], st['y'], st['diameter'] / 2 + 2 snx, sny, snw, snh = st['namerectact'] if (x > sx - sd and x < sx + sd and y > sy - sd and y < sy + sd) or\ (x > snx and x < snx + snw and y > sny and y < sny + snh): return st['number'] return None def bp(self, widget, event): if (event.type == gtk.gdk.BUTTON_RELEASE and event.button != self.button_pressed) or \ (event.type == gtk.gdk.BUTTON_PRESS and self.button_pressed != None): self.button_pressed = None return if event.type == gtk.gdk.BUTTON_PRESS: self.button_pressed = event.button self.button_pressed_coords = [event.x_root, event.y_root] if event.button == 3: gobject.timeout_add(200, self.menu, self.find_st_at_pos(event.get_coords()[0] - self.dx, event.get_coords()[1] - self.dy)) return if self.button_pressed_coords[0] > event.x_root + self.button_press_treshold or \ self.button_pressed_coords[0] < event.x_root - self.button_press_treshold or \ self.button_pressed_coords[1] > event.y_root + self.button_press_treshold or \ self.button_pressed_coords[1] < event.y_root - self.button_press_treshold: self.button_pressed = None return if event.type == gtk.gdk.MOTION_NOTIFY or (event.button != 1 and event.button != 3): return self.button_pressed = None start = False if event.button == 1: start = True n = self.find_st_at_pos(event.get_coords()[0] - self.dx, event.get_coords()[1] - self.dy) if n != None and n != self.stto and n != self.stfrom and self.scb: self.scb(n, start) def __update_vars(self): self.daw = self.da.get_allocation().width self.dah = self.da.get_allocation().height self.dx = (self.daw - self.pw) / 2 self.dy = (self.dah - self.ph) / 2 def __configure_cb(self, foo, bar): self.__update_vars() def expose(self, widget, event): if not self.gc: self.gc = gtk.gdk.GC(self.da.window) self.gc.set_fill(gtk.gdk.SOLID) x, y, w, h = event.area.x, event.area.y, event.area.width, event.area.height #clip event region if x < self.dx: w -= self.dx - x x = self.dx if y < self.dy: h -= self.dy - y y = self.dy if x + w > self.dx + self.pw: w = self.pw + self.dx - x if y + h > self.dy + self.ph: h = self.ph + self.dy - y if w > 0 and h > 0: if not self.pixbuf: self.create_pixbuf() self.da.window.draw_drawable(self.gc, self.pixbuf, x - self.dx, y - self.dy, x, y, w, h) self.redraw(True) def draw_pic(self, x, y, w, h): self.da.window.draw_drawable(self.gc, self.pixbuf, x, y, self.dx + x, self.dy + y, w, h)