Move UI independent parts of mapWidget into main module
[wifihood] / wifiscanner / wifiview.py
1
2 import gtk
3 import gobject
4 try :
5     import hildon
6 except :
7     hildon = False
8
9 import urllib2
10 import math
11
12 import os
13
14 import wifimap.config
15
16 import wifimap.view
17
18 class mapWidget ( wifimap.view.AbstractmapWidget , gtk.Image ) :
19
20   def __init__ ( self , config ) :
21     wifimap.view.AbstractmapWidget.__init__( self , config )
22
23     gtk.Image.__init__(self)
24
25     p = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, self.win_x, self.win_y)
26     self.set_from_pixbuf(p)
27
28     self.composeMap()
29
30   def composeMap( self ) :
31     center_x , center_y = self.win_x / 2 , self.win_y / 2
32
33     # To get the central pixel in the window center, we must shift to the tile origin
34     center_x -= self.refpix_x
35     center_y -= self.refpix_y
36
37     # Ranges should be long enough as to fill the screen
38     # Maybe they should be decided based on self.win_x, self.win_y
39     for i in range(-3,4) :
40       for j in range(-3,4) :
41         file = self.tilename( i , j , self.conf.zoom )
42         if file is None :
43           pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, self.tile_size, self.tile_size )
44           pixbuf.fill( 0x00000000 )
45         else :
46           try :
47             pixbuf = gtk.gdk.pixbuf_new_from_file( file )
48           except gobject.GError , ex :
49             print "Corrupted file %s" % ( file )
50             os.unlink( file )
51             #file = self.tilename( self.reftile_x + i , self.reftile_y + j , self.conf.zoom )
52             file = self.tilename( i , j , self.conf.zoom )
53             try :
54               pixbuf = gtk.gdk.pixbuf_new_from_file( file )
55             except :
56               print "Total failure for tile for %s,%s" % ( self.reftile_x + i , self.reftile_y + j )
57               pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, self.tile_size, self.tile_size )
58
59         dest_x = self.tile_size * i + center_x
60         dest_y = self.tile_size * j + center_y
61
62         init_x = 0
63         size_x = self.tile_size
64         if dest_x < 0 :
65            init_x = abs(dest_x)
66            size_x = self.tile_size + dest_x
67            dest_x = 0
68         if dest_x + self.tile_size > self.win_x :
69            size_x = self.win_x - dest_x
70
71         init_y = 0
72         size_y = self.tile_size
73         if dest_y < 0 :
74            init_y = abs(dest_y)
75            size_y = self.tile_size + dest_y
76            dest_y = 0
77         if dest_y + self.tile_size > self.win_y :
78            size_y = self.win_y - dest_y
79
80         if ( size_x > 0 and size_y > 0 ) and ( init_x < self.tile_size and init_y < self.tile_size ) :
81             pixbuf.copy_area( init_x, init_y, size_x, size_y, self.get_pixbuf(), dest_x , dest_y )
82         del(pixbuf)
83
84     pixmap,mask = self.get_pixbuf().render_pixmap_and_mask()
85     red = pixmap.new_gc()
86     red.foreground = pixmap.get_colormap().alloc_color("red")
87     green = pixmap.new_gc()
88     green.foreground = pixmap.get_colormap().alloc_color("green")
89     blue = pixmap.new_gc()
90     blue.foreground = pixmap.get_colormap().alloc_color("blue")
91
92     filename = "data/wiscan_gui.info.old"
93     fd = open( filename )
94     for line in fd.readlines() :
95         values = line.split()
96         if values[1] == "FIX" :
97             dest_x , dest_y = self.gps2pix( ( float(values[5]) , float(values[6]) ) , ( center_x , center_y ) )
98             pixmap.draw_rectangle(blue, True , dest_x , dest_y , 3 , 3 )
99     fd.close()
100
101     db = wifimap.db.database( os.path.join( self.conf.homedir , self.conf.dbname ) )
102     db.open()
103     for ap in db.db.execute( "SELECT * FROM ap" ) :
104         if ap[3] > 1 :
105             dest_x , dest_y = self.gps2pix( ( ap[4]/ap[3] , ap[5]/ap[3] ) , ( center_x , center_y ) )
106             pixmap.draw_rectangle(red, True , dest_x , dest_y , 3 , 3 )
107     db.close()
108
109     self.get_pixbuf().get_from_drawable( pixmap , pixmap.get_colormap() , 0, 0 , 0 , 0 , self.win_x, self.win_y )
110
111
112 if hildon :
113
114     class ZoomDialog ( hildon.TouchSelector ) :
115
116         def __init__ ( self , widget ) :
117             hildon.TouchSelector.__init__( self )
118
119             zooms = gtk.ListStore(str)
120
121             active = index = 0
122             for zoom in range(8,19) :
123                 iter = zooms.append()
124                 zooms.set( iter , 0 , "%2d" % zoom )
125                 if zoom == widget.conf.zoom :
126                     active = index
127                 index += 1
128
129             column = self.append_text_column( zooms , True )
130             #renderer = gtk.CellRendererText()
131             #column = self.append_column( zooms , renderer )
132             #column.set_property('text-column', 0)
133
134             # NOTE : with text=True, we must use 1 instead of 0
135             self.set_active( 0 , active )
136
137 else :
138
139     class ZoomDialog ( gtk.Dialog ) :
140
141         def __init__ ( self , widget ) :
142             gtk.Dialog.__init__( self , "Select zoom level",
143                                  None,
144                                  gtk.DIALOG_MODAL,
145                                  ( gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,
146                                    gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT
147                                    )
148                                  )
149
150             zooms = gtk.ListStore(int)
151             combo = gtk.ComboBox( zooms )
152
153             for zoom in range(8,19) :
154                 iter = zooms.append()
155                 zooms.set( iter , 0 , zoom )
156                 if zoom == widget.conf.zoom :
157                     combo.set_active_iter( iter )
158
159             cell = gtk.CellRendererText()
160             combo.pack_start(cell, True)
161             combo.add_attribute(cell, 'text', 0)
162
163             self.vbox.pack_start(combo , True, True, 0)
164
165             self.connect_object( "response", self.response , combo , widget )
166
167         def response ( self , combo , response  , widget ) :
168             if response == gtk.RESPONSE_ACCEPT :
169                 item = combo.get_active_iter()
170                 model = combo.get_model()
171                 widget.SetZoom( model.get(item,0)[0] )
172             self.destroy()
173
174
175 class AbstractMapWindow:
176
177     def destroy(self, widget, data=None):
178         gtk.main_quit()
179
180     def press_event ( self, widget, event, *args ) :
181       # FIXME : Set only if far enough from borders
182       border_x = 40
183       border_y = 30
184       print "press  ",event.get_coords(),event.get_root_coords()
185       if event.x > border_x and event.y > border_y and event.x < ( self.size_x - border_x ) and event.y < ( self.size_y - border_y ) :
186         self.click_x = event.x
187         self.click_y = event.y
188
189     def release_event ( self, widget, event, *args ) :
190       min_shift = 50
191       print "unpress",event.get_coords(),event.get_root_coords()
192       if self.click_x is not None and self.click_y is not None :
193         delta_x = int( event.x - self.click_x )
194         delta_y = int( event.y - self.click_y )
195         shift = math.sqrt( delta_x * delta_x + delta_y * delta_y )
196         if shift > min_shift :
197           self.map.Shift(delta_x, delta_y)
198         #  if delta_x > 100 :
199         #    self.map.Left()
200         #  elif delta_x < -100 :
201         #    self.map.Right()
202         #  elif delta_y > 100 :
203         #    self.map.Up()
204         #  elif delta_y < -100 :
205         #    self.map.Down()
206       self.click_x , self.click_y = None , None
207
208     def screen_event ( self, widget, event, *args ) :
209       print "REDIOS",event
210       print "      ",widget
211       print "      ",args
212
213
214     def on_button_press ( self, widget, event, *args ) :
215       print "HOLA",event
216
217     def on_key_press ( self, widget, event, *args ) :
218       if event.keyval == gtk.keysyms.Up :
219           self.map.Up()
220       elif event.keyval == gtk.keysyms.Down :
221           self.map.Down()
222       elif event.keyval == gtk.keysyms.Right :
223           self.map.Right()
224       elif event.keyval == gtk.keysyms.Left :
225           self.map.Left()
226       else :
227           print "UNKNOWN",event.keyval
228
229     def __init__(self):
230
231         self.connect("destroy", self.destroy)
232
233         self.set_border_width(10)
234
235         self.connect("key-press-event", self.on_key_press)
236
237         vbox = gtk.VBox(False, 0)
238         self.add( vbox )
239
240         # To get explicit GDK_BUTTON_PRESS instead of paired GDK_LEAVE_NOTIFY & GDK_ENTER_NOTIFY
241 #        self.add_events(gtk.gdk.BUTTON_MOTION_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_MASK)
242         self.set_events( gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK )
243         #
244 #        self.connect('motion_notify_event', self.screen_event)
245         self.connect('button_press_event', self.press_event)
246         self.connect('button_release_event', self.release_event)
247         #
248         self.config = wifimap.config.Configuration()
249         self.map = mapWidget( self.config )
250         vbox.pack_end( self.map , True , True , 5)
251
252         self.create_menu( vbox )
253
254         # and the window
255         self.show_all()
256
257         self.size_x , self.size_y = 800 , 480
258         self.click_x , self.click_y = None , None
259
260     def zoomdialog ( self , widget ) :
261         dialog = ZoomDialog( widget )
262         dialog.show_all()
263
264     def main(self):
265         gtk.main()
266
267 if hildon :
268
269     class MapWindow ( AbstractMapWindow , hildon.Window ) :
270
271         def __init__(self):
272             hildon.Window.__init__( self )
273             AbstractMapWindow.__init__(self)
274
275         def create_menu ( self , vbox ) :
276
277             self.menubar = menubar = hildon.AppMenu()
278
279             #zoomlevel = hildon.Button(gtk.HILDON_SIZE_AUTO,
280             #                          hildon.BUTTON_ARRANGEMENT_VERTICAL,
281             #                          "Zoom level", None)
282             #zoomlevel.connect_object( "clicked", self.zoomstack, self.map )
283             selector = ZoomDialog( self.map )
284             zoomlevel = hildon.PickerButton(gtk.HILDON_SIZE_AUTO,
285                                           hildon.BUTTON_ARRANGEMENT_VERTICAL)
286             zoomlevel.set_title( "Zoom" )
287             zoomlevel.set_selector( selector )
288             zoomlevel.connect_object( "value-changed", self.map.ZoomChange , selector )
289             menubar.append( zoomlevel )
290
291             menubar.show_all()
292             self.set_app_menu( menubar )
293
294 else :
295
296     class MapWindow ( AbstractMapWindow , gtk.Window ) :
297
298         def __init__(self):
299             gtk.Window.__init__( self , gtk.WINDOW_TOPLEVEL )
300             AbstractMapWindow.__init__(self)
301             self.resize( self.size_x , self.size_y)
302
303         def create_menu ( self , vbox ) :
304
305             menubar = gtk.MenuBar()
306
307             zoomlevel = gtk.MenuItem( label="Zoom level" )
308             zoomlevel.connect_object( "activate", self.zoomdialog, self.map )
309             menubar.append( zoomlevel )
310
311             vbox.pack_start(menubar,True,True,5)
312