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

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

Click menu, allows setting own position, as well as routing

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