source: subversion/applications/routing/pyroute/overlay.py @ 5698

Last change on this file since 5698 was 5698, checked in by ojw, 12 years ago

Some more stuff going into a base class (so e.g.
self.modulesdata?.getOption('x') is now just self.get('x')

File size: 15.9 KB
Line 
1import cairo
2import os
3from base import pyrouteModule
4
5class menuIcons:
6    def __init__(self):
7        self.images = {}
8        self.cantLoad = []
9    def load(self,name):
10        filename = "icons/bitmap/%s.png" % name
11        if(not os.path.exists(filename)):
12            return(0)
13        self.images[name] = cairo.ImageSurface.create_from_png(filename)
14        if(self.images[name]):
15            return(1)
16        return(0)
17    def draw(self,cr,name,x,y,w,h):
18        if not name in self.images.keys():
19            if(name in self.cantLoad):
20                return
21            if(not self.load(name)):
22                self.cantLoad.append(name)
23                return
24        imagesize = 120.0
25        cr.save()
26        cr.translate(x,y)
27        cr.scale(w / imagesize, h / imagesize)
28        cr.set_source_surface(self.images[name],0,0)
29        cr.paint()
30        cr.restore()
31
32class overlayArea:
33    def __init__(self,cr,x,y,dx,dy,modules,iconSet):
34        self.cr = cr
35        self.x1 = x;
36        self.y1 = y;
37        self.x2 = x + dx;
38        self.y2 = y + dy;
39        self.w = dx
40        self.h = dy
41        self.cx = x + 0.5 * dx
42        self.cy = y + 0.5 * dy
43        self.event = None
44        self.modules = modules
45        self.iconSet = iconSet
46    def fill(self,r,g,b,outline=0):
47        self.cr.set_source_rgb(r,g,b)
48        self.cr.rectangle(self.x1,self.y1,self.w,self.h)
49        if(outline):
50            self.cr.stroke()
51        else:
52            self.cr.fill()
53    def mainMenuButton(self):
54        self.cr.set_line_width(2)
55        self.cr.set_dash((2,2,2), 0);
56        self.cr.set_source_rgba(0.4,0,0)
57        self.cr.arc(self.cx,self.cy, 0.5*self.w, 0, 2*3.14)
58        self.cr.stroke()
59        self.setEvent("menu:main")
60    def drawTextSomewhere(self,text,px1,py1,px2,py2):
61        innerBox = self.copyself(px1,py1,px2,py2)
62        innerBox.drawText(text)
63    def drawText(self,text):
64        self.cr.select_font_face('Verdana', cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
65        test_fontsize = 60
66        self.cr.set_font_size(test_fontsize)
67        xbearing, ybearing, textwidth, textheight, xadvance, yadvance = self.cr.text_extents(text)
68        # Resize the font to fit
69        ratiox = textwidth / self.w
70        ratioy = textheight / self.h
71        ratio = max(ratiox,ratioy)
72       
73        self.cr.set_font_size(test_fontsize / ratio)
74        textwidth = textwidth / ratio
75        textheight = textheight / ratio
76
77        marginx = 0.5 * (self.w - textwidth)
78        marginy = 0.5 * (self.h - textheight)
79        # Text
80        self.cr.move_to(self.x1 + marginx, self.y2 - marginy)
81        self.cr.set_source_rgba(0, 0, 0, 0.5)
82        self.cr.show_text(text)
83       
84    def button(self,text=None,event=None,icon=None):
85        # Rectangle
86        if(not icon):
87          if(text):
88            self.iconSet.draw(self.cr,"generic",self.x1,self.y1,self.w,self.h)
89          else:
90            self.iconSet.draw(self.cr,"blank",self.x1,self.y1,self.w,self.h)
91        if(icon):
92            self.iconSet.draw(self.cr,icon,self.x1,self.y1,self.w,self.h)
93        if(text):
94            self.drawTextSomewhere(text,0.2,0.6,0.8,0.8)
95        if(event):
96            self.setEvent(event)
97    def setEvent(self,text):
98        self.event = text
99    def xc(self,p):
100        return(self.x1 + p * self.w)
101    def yc(self,p):
102        return(self.y1 + p * self.h)
103    def copyself(self,px1,py1,px2,py2):
104        x1 = self.xc(px1)
105        y1 = self.yc(py1)
106        return(overlayArea( \
107            self.cr,
108            x1,
109            y1,
110            self.xc(px2) - x1,
111            self.yc(py2) - y1,
112            self.modules,
113            self.iconSet))
114    def xsplit(self,p):
115        a = self.copyself(0,0,p,1)
116        b = self.copyself(p,0,1,1)
117        return(a,b)
118    def ysplit(self,p):
119        a = self.copyself(0,0,1,p)
120        b = self.copyself(0,p,1,1)
121        return(a,b)
122    def xsplitn(self,px1,py1,px2,py2,n):
123        dpx = (px2 - px1) / n
124        cells = []
125        for i in range(0,n-1):
126            px = px1 + i * dpx
127            cells.append(self.copyself(px,py1,px + dpx,py2))
128        return(cells)
129    def ysplitn(self,px1,py1,px2,py2,n):
130        dpy = (py2 - py1) / n
131        cells = []
132        for i in range(0,n):
133            py = py1 + i * dpy
134            cells.append(self.copyself(px1,py,px2,py+dpy))
135        return(cells)
136           
137    def contains(self,x,y):
138        if(x > self.x1 and x < self.x2 and y > self.y1 and y < self.y2):
139            return(1)
140    def handleClick(self,x,y):
141        if(self.event):
142            self.modules['data'].handleEvent(self.event)
143            return(1)
144        return(0)
145   
146class guiOverlay(pyrouteModule):
147    def __init__(self, modules):
148        pyrouteModule.__init__(self, modules)
149        self.modules = modules
150        self.icons = menuIcons()
151
152    def fullscreen(self):
153        """Asks if the menu is fullscreen -- if it is, then the
154        map doesn't need to be drawn underneath"""
155        return(self.get('menu'))
156   
157    def handleClick(self,x,y):
158        """return 1 if click was handled"""
159        for cell in self.clickable:
160            if(cell.contains(x,y)):
161                if(cell.handleClick(x,y)):
162                    return(1)
163        if(self.fullscreen()):
164            return(1)
165        return(0)
166    def draw(self, cr, rect):
167        self.cr = cr
168        self.rect = overlayArea(cr,rect.x,rect.y,rect.width,rect.height,self.modules,self.icons)
169        nx = 3
170        ny = 4
171        self.clickable = []
172        self.cells = {}
173        dx = rect.width / nx
174        dy = rect.height / ny
175        for i in range(0,nx):
176            x1 = rect.x + i * dx
177            self.cells[i] = {}
178            for j in range(0,ny):
179                y1 = rect.y + j * dy
180                self.cells[i][j] = overlayArea(cr,x1,y1,dx,dy,self.modules, self.icons)
181                self.clickable.append(self.cells[i][j])
182        currentMenu = self.get('menu')
183        if(currentMenu):
184            self.drawMenu(currentMenu)
185        else:
186            self.cells[0][0].mainMenuButton()
187            self.cr.set_line_width(2)
188            self.cr.set_dash((2,2,2), 0);
189            self.cr.set_source_rgba(0.4,0,0)
190            y = 100
191            self.cr.move_to(0,y)
192            self.cr.line_to(rect.width,y)
193            self.cr.stroke()
194                   
195    def drawMenu(self, menu):
196        menuName = 'menu_%s' % menu
197        try:
198            function = getattr(self, menuName)
199        except AttributeError:
200            print "Error: %s not defined" % menuName
201            self.set('menu',None)
202            return
203        function()
204    def backButton(self,i,j):
205        self.cells[i][j].button("","menu:","up")
206       
207    def menu_main(self):
208        self.backButton(0,0)
209        self.cells[1][0].button("Mark",None,"map_pin")
210        self.cells[2][0].button("Draw",None,"sketch")
211       
212        self.cells[0][1].button("View","menu:view","viewMenu")
213        self.cells[1][1].button("GPS","menu:gps","gps")
214        self.cells[2][1].button("Download","menu:download","download")
215
216        self.cells[0][2].button()
217        self.cells[1][2].button()
218        self.cells[2][2].button()
219       
220        self.cells[0][3].button("Centre","option:toggle:centred","centre")
221        self.cells[1][3].button("Options","menu:options","options")
222        self.cells[2][3].button("Mode", "menu:mode","transport")
223
224    def menu_mode(self):
225        self.backButton(0,0)
226        self.cells[1][0].button("Cycle","mode:cycle","bike")
227        self.cells[2][0].button("Walk","mode:foot","hike")
228       
229        self.cells[0][1].button("MTB","mode:cycle","mtb")
230        self.cells[1][1].button("Car","mode:car","car")
231        self.cells[2][1].button("Hike","mode:foot","hike")
232
233        self.cells[0][2].button("Fast cycle","mode:cycle","fastbike")
234
235        self.cells[0][3].button("HGV","mode:hgv","hgv")
236    def menu_feeds(self):
237      self.menu_list("rss")
238    def menu_geonames(self):
239      self.menu_list("geonames")
240     
241    def menu_list(self, module):
242        self.backButton(0,0)
243        n = 9
244        offset = 0
245        selectedFeed = int(self.modules['data'].getOption('selectedFeed',0))
246        titlebar = self.rect.copyself(1.0/3.0,0,1,0.25)
247        line1, line2 = titlebar.ysplit(0.5)
248        back = line1.copyself(0,0,0.25,1)
249        next = line1.copyself(0.75,0,1,1)
250        back.button("","option:add:selectedFeed:-1","back")
251        next.button("","option:add:selectedFeed:1","next")
252        self.clickable.append(back)
253        self.clickable.append(next)
254
255        line1.copyself(0.25,0,0.75,1).drawText("Feed %d of %d" % (selectedFeed + 1, len(self.modules['plugins'][module].groups)))
256
257        try:
258            group = self.modules['plugins'][module].groups[selectedFeed]
259        except KeyError:
260            return
261        except IndexError:
262            return
263       
264        line2.drawText(group.name)
265       
266        listrect = self.rect.ysplitn(0, 0.25, 0.8, 1, n)
267        ownpos = self.modules['position'].get()
268        for i in range(0,n):
269            textarea, button = listrect[i].xsplit(0.8)
270            if(i > 0):
271                self.cr.set_line_width(0.5)
272                self.cr.set_dash((2,2,2), 0);
273                self.cr.set_source_rgb(0,0,0)
274                self.cr.move_to(textarea.x1,textarea.y1)
275                self.cr.line_to(textarea.x2,textarea.y1)
276                self.cr.stroke()
277            try:
278                item = group.items[i + offset]
279                textarea.drawTextSomewhere(item.formatText(), 0.1,0.1,0.9,0.5)
280                textarea.drawTextSomewhere(item.formatPos(ownpos), 0.1,0.6,0.9,0.9)
281                button.button("", "route:%1.5f:%1.5f" % (item.lat, item.lon), "goto")
282                self.clickable.append(button)
283            except IndexError:
284                pass
285
286    def menu_search_eat(self):
287        self.backButton(0,0)
288        self.cells[1][0].button("Pub food", "search:amenity=pub;food=yes", None)
289        self.cells[2][0].button("Restaurant", "search:amenity=restaurant", None)
290       
291        self.cells[0][1].button("Cafe", "search:amenity=cafe",None)
292        self.cells[1][1].button("Fast food","search:amenity=fast_food",None)
293        self.cells[2][1].button("Takeaway",None,None)
294   
295    def menu_search_sleep(self):
296        self.backButton(0,0)
297        self.cells[1][0].button("Hotel", "search:tourism=hotel",None)
298        self.cells[2][0].button("Hostel", "search:tourism=hostel",None)
299       
300    def menu_search_repair(self):
301        self.backButton(0,0)
302        self.cells[1][0].button("Bike shop","search:amenity=bike_shop",None)
303        self.cells[2][0].button("Garage","search:amenity=garage",None)
304       
305    def menu_search_buy(self):
306        self.backButton(0,0)
307        self.cells[1][0].button("Supermarket","search:amenity=supermarket",None)
308        self.cells[2][0].button("Mall",None,None)
309       
310        self.cells[0][1].button("High street",None,None)
311        self.cells[1][1].button("Dep't Store",None,None)
312        self.cells[2][1].button("Outdoor","search:shop=outdoor",None)
313       
314        self.cells[0][2].button("DIY","search:tourism=diy",None)
315        self.cells[1][2].button("",None,None)
316        self.cells[2][2].button("",None,None)
317   
318    def menu_search_help(self):
319        self.backButton(0,0)
320        self.cells[1][0].button("Police Stn", "search:amenity=police", None)
321        self.cells[2][0].button("Fire Stn", "search:amenity=fire", None)
322       
323        self.cells[0][1].button("Hospital", "search:amenity=hospital",None)
324        self.cells[1][1].button("Ranger", "search:amenity=ranger_station", None)
325        self.cells[2][1].button("Pharmacy", "search:amenity=pharmacy", None)
326       
327    def menu_search_park(self):
328        self.backButton(0,0)
329        self.cells[1][0].button("Car park", "search:amenity=parking", None)
330        self.cells[2][0].button("Free car park","search:amenity=parking;cost=free",None)
331       
332        self.cells[0][1].button("Bike park", "search:amenity=cycle_parking", None)
333        self.cells[1][1].button("Lay-by", "search:amenity=layby", None)
334       
335    def menu_search_hire(self):
336        self.backButton(0,0)
337        self.cells[1][0].button("Car hire", "search:amenity=car_hire", None)
338        self.cells[2][0].button("Bike hire", "search:amenity=bike_hire",None)
339       
340        self.cells[0][1].button("Ski hire","search:amenity=ski_hire",None)
341
342    def menu_search(self):
343        self.backButton(0,0)
344        self.cells[1][0].button("Eat","menu:search_eat",None)
345        self.cells[2][0].button("Sleep","menu:search_sleep",None)
346
347        self.cells[0][1].button("Fuel","menu:search_fuel",None)
348        self.cells[1][1].button("Repair","menu:search_repair",None)
349        self.cells[2][1].button("Buy","menu:search_buy",None)
350
351        self.cells[0][2].button("Help","menu:search_help",None)
352        self.cells[1][2].button("Park","menu:search_park",None)
353        self.cells[2][2].button("Hire","menu:search_hire",None)
354       
355        self.cells[0][3].button("",None,None)
356
357    def menu_view(self):
358        self.backButton(0,0)
359        self.cells[1][0].button("People",None,"people")
360        self.cells[2][0].button("Wiki","menu:geonames","wiki")
361
362        self.cells[0][1].button("Business","menu:search","business")
363        self.cells[1][1].button("RSS","menu:feeds","rss")
364        self.cells[2][1].button("Bookmarks",None,"bookmark")
365
366        self.cells[0][2].button("Routes",None,"route")
367        self.cells[1][2].button("Waypoints",None,"waypoints")
368        self.cells[2][2].button("Drawings",None,"sketch")
369       
370        self.cells[0][3].button("Events",None,"events")
371   
372    def menu_download(self):
373        self.backButton(0,0)
374        self.cells[1][0].button("",None,None)
375        self.cells[2][0].button("",None,None)
376
377        self.cells[0][1].button("",None,None)
378        self.cells[1][1].button("",None,None)
379        self.cells[2][1].button("Route data","download:osm:0.2","download")
380
381        self.cells[0][2].button("",None,None)
382        self.cells[1][2].button("",None,None)
383        self.cells[2][2].button("",None,None)
384       
385        self.cells[0][3].button("",None,None)
386        self.cells[1][3].button("",None,None)
387        self.cells[2][3].button("",None,None)
388
389    def menu_click(self):
390        self.backButton(0,0)
391       
392        latlonRect = self.rect.copyself(0.33,0,1,0.25)
393        latRect = latlonRect.copyself(0,0,1,0.5)
394        lonRect = latlonRect.copyself(0,0.5,1,1)
395       
396        lat,lon = self.get('clicked')
397       
398        NS = lat > 0 and 'N' or 'S'
399        EW = lon > 0 and 'E' or 'W'
400       
401        latRect.drawTextSomewhere('%1.4f %s' % (abs(lat), NS), 0.05, 0.05, 0.7, 0.95)
402        lonRect.drawTextSomewhere('%1.4f %s' % (abs(lon), EW), 0.3, 0.05, 0.95, 0.95)
403        #def drawTextSomewhere(self,text,px1,py1,px2,py2):
404        #innerBox = self.copyself(px1,py1,px2,py2)
405        #innerBox.drawText(text)
406   
407        #self.cells[1][0].button("(lat)",None,None)
408        #self.cells[2][0].button("(lon)",None,None)
409
410        self.cells[0][1].button("set pos","ownpos:clicked","set_pos")
411        self.cells[1][1].button("route to","route:clicked","route_to")
412        self.cells[2][1].button("direct to","direct:clicked","direct_to")
413
414        self.cells[0][2].button("waypoint", "waypoint:clicked", "bookmark")
415        self.cells[1][2].button("extend route", "extend:route:clicked", "extend_route")
416        self.cells[2][2].button("extend direct", "extend:direct:clicked", "extend_direct")
417
418        self.cells[0][3].button("",None,None)
419        self.cells[1][3].button("",None,None)
420        self.cells[2][3].button("",None,None)
421
422    def menu_options(self):
423        view,scroll = self.rect.xsplit(0.8)
424        view.fill(1,0,0)
425        scroll.fill(0,1,0)
426        self.backButton(0,0)
427
428
429if __name__ == "__main__":
430    a = guiOverlay(None,None)
431    print dir(a)
Note: See TracBrowser for help on using the repository browser.