Mercurial > hg > mood-conductor
comparison visualclient2/midiclient.py @ 37:2db17c224664
added visclient2
author | gyorgyf |
---|---|
date | Fri, 24 Apr 2015 07:09:32 +1000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
36:caea7ec0c162 | 37:2db17c224664 |
---|---|
1 #!/usr/bin/env python | |
2 # encoding: utf-8 | |
3 """ | |
4 visclient.py | |
5 | |
6 Created by George Fazekas on 2012-06-17. | |
7 Copyright (c) 2012 . All rights reserved. | |
8 """ | |
9 | |
10 import sys,os,math,time,copy | |
11 import pygame as pg | |
12 from pygame.locals import * | |
13 import httplib as ht | |
14 from pygame import midi | |
15 | |
16 import gradients | |
17 from gradients import genericFxyGradient | |
18 | |
19 from threading import Thread | |
20 from random import random | |
21 import numpy as np | |
22 | |
23 import colorsys as cs | |
24 | |
25 NOTE_OFF_CH0 = [[[0xb0,0x7b,0],0]] | |
26 | |
27 # 1 HONKY TONK 0x1 / 0x4 (5) | |
28 # 2 SITAR 0x9 / 0x0 (1) | |
29 # 3 Melancholia | |
30 # 4 Rock GITAR 0x3 / 0x2C (45) | |
31 | |
32 IMAP = {1 : (0x1,0x4), 2: (0x9,0x0), 3:(0x8,0xb), 4:(0x3,0x2c) } | |
33 | |
34 | |
35 # from pytagcloud import create_tag_image, make_tags | |
36 # from pytagcloud.lang.counter import get_tag_counts | |
37 | |
38 # YOUR_TEXT = "A tag cloud is a visual representation for text data, typically\ | |
39 # used to depict keyword metadata on websites, or to visualize free form text." | |
40 # | |
41 # tags = make_tags(get_tag_counts(YOUR_TEXT), maxsize=120) | |
42 # | |
43 # create_tag_image(tags, 'cloud_large.png', size=(900, 600), fontname='Lobster') | |
44 | |
45 scol = (0,255,0,255) | |
46 ecol = (0,0,0,255) | |
47 | |
48 # X,Y=1140,900 | |
49 # X,Y = 600,400 | |
50 X,Y = 800,600 | |
51 | |
52 # Fullscreen resolution: | |
53 # XF,YF = 1280,900 | |
54 # XF,YF = 1440,900 | |
55 XF,YF = 1344,900 | |
56 # display calibrated | |
57 | |
58 # detect display resolution | |
59 import subprocess | |
60 screenres = subprocess.Popen('xrandr | grep "\*" | cut -d" " -f4',shell=True, stdout=subprocess.PIPE).communicate()[0] | |
61 screenres = map(lambda x: int(x.strip()), screenres.split('x')) | |
62 XF,YF = screenres | |
63 print "Screen resolution: ",XF,YF | |
64 | |
65 NBLOBS = 18 | |
66 BLOBSIZE = 25 | |
67 G=110 | |
68 FADE = 15 | |
69 DIST = 0.15 # blob equivalence tolerance | |
70 FRAMERATE = 60 | |
71 | |
72 # Connection: | |
73 # IP = "127.0.0.1:8030" | |
74 # IP = "192.168.2.158:8030" | |
75 IP = "138.37.95.215" | |
76 HTTP_TIMEOUT = 3 | |
77 SERVER_UPDATE_INTERVAL = 0.8 | |
78 | |
79 | |
80 class Indicator(object): | |
81 | |
82 off_color = pg.Color(110,0,0) | |
83 on_color = pg.Color(0,120,0) | |
84 | |
85 def __init__(self,bg,pos): | |
86 self.visible = True | |
87 self.ison = True | |
88 self.x,self.y = pos | |
89 self.xs = int(self.x * X) | |
90 self.ys = int(Y - (self.y * Y)) | |
91 self.c = self.off_color | |
92 self.size = 6 | |
93 self.bg = bg | |
94 | |
95 def reinit(self,bg): | |
96 self.bg = bg | |
97 self.xs = int(self.x * X) | |
98 self.ys = int(Y - (self.y * Y)) | |
99 | |
100 def draw(self): | |
101 if self.visible : | |
102 pg.draw.circle(self.bg, self.c, (self.xs,self.ys),self.size,0) | |
103 | |
104 def toggle(self): | |
105 if self.ison == True : | |
106 self.off() | |
107 else : | |
108 self.on() | |
109 return self | |
110 | |
111 def on(self): | |
112 self.c = self.on_color | |
113 self.ison = True | |
114 return self | |
115 | |
116 def off(self): | |
117 self.c = self.off_color | |
118 self.ison = False | |
119 return self | |
120 | |
121 | |
122 class Blob(object): | |
123 | |
124 def __init__(self,bg,x,y,color=(255,255,255),mood=None,fade=FADE): | |
125 # print x,y | |
126 self.x = x | |
127 self.y = y | |
128 self.quadrant = self.get_quadrant_number(x,y) | |
129 self.xs = x * X | |
130 self.ys = Y - (y * Y) | |
131 self.bg = bg | |
132 self.size = BLOBSIZE | |
133 self.time = time.time() | |
134 self.alpha = 255 | |
135 self.c = color | |
136 self.count = 1 | |
137 self.visible = True | |
138 self.FADE = fade | |
139 if mood and mood.color : | |
140 self.c = mood.color | |
141 | |
142 def get_quadrant_number(self,x,y): | |
143 if x > 0.5 and y > 0.5 : | |
144 return 1 | |
145 if x > 0.5 and y < 0.5 : | |
146 return 2 | |
147 if x < 0.5 and y < 0.5 : | |
148 return 3 | |
149 if x < 0.5 and y > 0.5 : | |
150 return 4 | |
151 | |
152 | |
153 def __cmp__(self,other): | |
154 d = math.sqrt( math.pow((self.x-other.x),2) + math.pow((self.y-other.y),2) ) | |
155 if d < DIST : | |
156 return 0 | |
157 else : | |
158 return -1 | |
159 | |
160 def draw(self): | |
161 if not self.visible : return | |
162 d=int(self.size) | |
163 self.bg.blit(gradients.radial(self.size, (self.c[0],self.c[1],self.c[2],self.alpha), (0,0,0,self.alpha)), (self.xs-d,self.ys-d)) | |
164 self.alpha = 255 - int(self.age()*self.FADE) | |
165 if self.alpha < 5 : | |
166 self.alpha = 1 | |
167 self.visible = False | |
168 | |
169 def age(self): | |
170 return time.time() - self.time | |
171 | |
172 def increment(self,count): | |
173 self.time = time.time() | |
174 self.count = count | |
175 # self.size = int(BLOBSIZE * int(self.count/1.5)) | |
176 self.to = int(BLOBSIZE * int(self.count/1.5)) | |
177 self.start_animate() | |
178 | |
179 def get_distance(self,x,y): | |
180 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) ) | |
181 | |
182 def fade(self,fade): | |
183 if not fade : self.alpha = 255 | |
184 self.FADE = fade | |
185 | |
186 def reset_time(self): | |
187 self.time = time.time() | |
188 | |
189 def start_animate(self): | |
190 self.thread = Thread(target = self.animate) | |
191 self.thread.daemon = True | |
192 self.thread.start() | |
193 | |
194 def animate(self): | |
195 '''Animate the way bubbles are grown.''' | |
196 while self.size < self.to : | |
197 self.size += 1 | |
198 time_inc = 20.0 / (pow(1.2, self.to-self.size) * 200.0) | |
199 time.sleep(0.02+time_inc) | |
200 | |
201 | |
202 | |
203 | |
204 class Mood(): | |
205 def __init__(self,word,x,y): | |
206 self.word = word | |
207 self.x = float(x) | |
208 self.y = float(y) | |
209 self.color = [] | |
210 | |
211 def get_distance(self,x,y): | |
212 return math.sqrt( math.pow((self.x-x),2) + math.pow((self.y-y),2) ) | |
213 | |
214 | |
215 | |
216 class VisualClient(object): | |
217 '''Main visualisation client.''' | |
218 | |
219 def __init__(self): | |
220 # self.conn = ht.HTTPConnection("192.168.2.184:8030") | |
221 # self.conn = ht.HTTPConnection("138.37.95.215") | |
222 self.s_age = 10 | |
223 self.s_dist = DIST | |
224 self.s_ninp = 18 | |
225 | |
226 pg.init() | |
227 | |
228 # fontObj = pg.font.Font("freesansbold.ttf",18) | |
229 white = ( 255, 255, 255) | |
230 black = ( 0,0,0) | |
231 | |
232 self.fpsClock = pg.time.Clock() | |
233 self.screen = pg.display.set_mode((X, Y)) | |
234 pg.display.set_caption('Mood Conductor') | |
235 self.bg = pg.Surface(self.screen.get_size()) | |
236 self.bg = self.bg.convert() | |
237 self.bg.fill((0,0,0)) | |
238 pg.display.set_gamma(100.0) | |
239 | |
240 | |
241 self.scol = (0,255,0,255) | |
242 self.ecol = (0,0,0,255) | |
243 coordstxt = "test" | |
244 | |
245 self.blobs = [] | |
246 self.moods = [] | |
247 self.read_mood_data() | |
248 | |
249 self.FADE = FADE | |
250 | |
251 self.indicators = { | |
252 "conn":Indicator(self.bg,(0.98,0.02)), | |
253 "update":Indicator(self.bg,(0.96,0.02)), | |
254 "data":Indicator(self.bg,(0.94,0.02)), | |
255 "receive":Indicator(self.bg,(0.92,0.02))} | |
256 | |
257 self.thread = None | |
258 self.running = False | |
259 self.fullscreen = False | |
260 self.init_reconnect = False | |
261 | |
262 pg.midi.init() | |
263 | |
264 print pg.midi.get_device_info(4) | |
265 self.midi_out = pg.midi.Output(4,0) | |
266 self.midi_out.set_instrument(6) | |
267 | |
268 # self.midi_out.note_on(23,128,1) | |
269 # self.midi_out.write([[[0xc0,0,0],20000],[[0x90,60,100],20500]]) | |
270 | |
271 self.active_quadrant = 1 | |
272 self.prev_quadrant = 1 | |
273 | |
274 pass | |
275 | |
276 | |
277 def read_mood_data(self): | |
278 '''Read the mood position and color information form csv file.''' | |
279 with open('moods.csv') as mf: | |
280 data = mf.readlines()[1:] | |
281 for line in data : | |
282 l = line.split(',') | |
283 mood = Mood(l[0],l[1],l[2]) | |
284 self.moods.append(mood) | |
285 with open('colors.txt') as ff: | |
286 data = ff.readlines()[1:] | |
287 data = map(lambda x: x.split(','),data) | |
288 for mood in self.moods : | |
289 d = cd = sys.float_info.max | |
290 for colors in data : | |
291 d = mood.get_distance(float(colors[0]),float(colors[1])) | |
292 if d < cd : | |
293 cd = d | |
294 # mood.color = tuple(map(lambda x: int(pow(math.atan((float(x)/7.0)),12.5)),(colors[2],colors[3],colors[4]))) | |
295 mood.color = self.set_color(tuple(map(lambda x: int(x),(colors[2],colors[3],colors[4])))) | |
296 return True | |
297 | |
298 def set_color(self,color): | |
299 '''Move to HLS colour space and manipulate saturation there.''' | |
300 # TODO: ideally, we need a non-linear compressor of the lightness and saturation values | |
301 r,g,b = map(lambda x: (1.0*x/255.0), color) | |
302 h,l,s = cs.rgb_to_hls(r,g,b) | |
303 s = 1.0 #1.0 - (1.0 / pow(50.0,s)) | |
304 l = 1.0 - (1.0 / pow(20.0,l)) #0.6 | |
305 r,g,b = map(lambda x: int(x*255), cs.hls_to_rgb(h,l,s)) | |
306 return r,g,b | |
307 | |
308 def start_update_thread(self): | |
309 '''Start the thread that reads data from the server.''' | |
310 self.running = True | |
311 self.thread = Thread(target = self.update_thread) | |
312 self.thread.daemon = True | |
313 self.thread.start() | |
314 | |
315 def stop_update_thread(self): | |
316 '''Stop the thread and allow some time fot the connections to close.''' | |
317 self.running = False | |
318 try : | |
319 self.thread.join(2) | |
320 except : | |
321 print "No update thread to join." | |
322 | |
323 def update_thread(self): | |
324 '''The server update thread''' | |
325 while self.running : | |
326 try : | |
327 self.update() | |
328 # self.indicators["update"].visible = True | |
329 except Exception, e: | |
330 if str(e).strip() : print "Exception: ", str(e), type(e), len(str(e).strip()) | |
331 self.indicators["conn"].off() | |
332 # self.indicators["update"].visible = False | |
333 time.sleep(SERVER_UPDATE_INTERVAL) | |
334 | |
335 | |
336 def update(self): | |
337 '''Update the blob list from the server. This should be in a thread.''' | |
338 | |
339 # indicate connection health by toggling an indictor | |
340 self.indicators["update"].toggle() | |
341 | |
342 # delete invisibles | |
343 for blob in self.blobs : | |
344 if not blob.visible : | |
345 self.blobs.remove(blob) | |
346 | |
347 # get new coordinates from the server | |
348 self.conn.putrequest("GET","/moodconductor/result", skip_host=True) | |
349 self.conn.putheader("Host", "www.isophonics.net") | |
350 self.conn.endheaders() | |
351 res = self.conn.getresponse() | |
352 data = res.read() | |
353 data = eval(data) | |
354 if not data : | |
355 self.conn.close() | |
356 self.indicators["data"].toggle() | |
357 return False | |
358 for d in data : | |
359 # coordstxt = "x:%s y:%s c:%s" %d | |
360 x,y,count = d | |
361 self.add_blob(x,y,count) | |
362 self.indicators["receive"].toggle() | |
363 self.conn.close() | |
364 self.blobs = self.blobs[:NBLOBS] | |
365 self.compute_quadrant_weighting() | |
366 self.self_change_instrument() | |
367 return True | |
368 | |
369 def compute_quadrant_weighting(self): | |
370 quadrant_dict = {1:[],2:[],3:[],4:[]} | |
371 # sort blobs into quadrants | |
372 for blob in self.blobs : | |
373 quadrant_dict[blob.quadrant].append(blob) | |
374 # get weight for each | |
375 quadrant_weights = [] | |
376 for q,blob_list in quadrant_dict.iteritems() : | |
377 quadrant_weights.append(sum(map(lambda x: x.alpha * x.size,blob_list))) | |
378 self.active_quadrant = np.argmax(quadrant_weights) + 1 | |
379 print self.active_quadrant | |
380 return self.active_quadrant | |
381 | |
382 def self_change_instrument(self): | |
383 if self.active_quadrant != self.prev_quadrant : | |
384 self.prev_quadrant = self.active_quadrant | |
385 args = IMAP[self.active_quadrant] | |
386 self.send_midi_patch_change_GR20(*args) | |
387 print args | |
388 | |
389 def add_blob(self,x,y,count=1): | |
390 '''Insert a blob to the list of blobs''' | |
391 # find mood correxponding to x,y | |
392 cmood = None | |
393 d = cd = sys.float_info.max | |
394 for mood in self.moods : | |
395 d = mood.get_distance(x,y) | |
396 if d < cd : | |
397 cd = d | |
398 cmood = mood | |
399 # create new blob or increase click count on existing one | |
400 new = Blob(self.bg,x,y,mood=cmood,fade=self.FADE) | |
401 if not new in self.blobs : | |
402 self.blobs.insert(0,new) | |
403 # self.send_midi() | |
404 elif count > self.blobs[self.blobs.index(new)].count: | |
405 self.blobs[self.blobs.index(new)].increment(count) | |
406 pass | |
407 | |
408 def send_midi(self): | |
409 # self.midi_out.write([[[0xc0,0,0],20000],[[0x90,60,100],20500]]) | |
410 self.midi_out.write([[[0x90,60,100],0],[[0x90,60,100],500]]) | |
411 | |
412 def send_midi_patch_change_GR20(self,bank,instrument): | |
413 '''PIANO = BANK 1, Patch 5.. bank starts from 1, patch starts from 0 so I have to substract one...''' | |
414 self.midi_out.write([[[0xB0,0x0,bank],0],[[0xC0,instrument],100]]) | |
415 # Control change (B) followed by patch change (C): | |
416 # midi_out.write([[[0xB0,0x0,0x9],0],[[0xC0,0x0],100]]) | |
417 # midi_out.write([[[0xB0,0x0,int(bank)],0],[[0xC0,int(instrument)-1],100]]) | |
418 # 1 HONKY TONK 0x1 / 0x4 (5) | |
419 # 2 SITAR 0x9 / 0x0 (1) | |
420 # 3 Melancholia | |
421 # 4 Rock GITAR 0x3 / 0x2C (45) | |
422 | |
423 | |
424 def draw(self): | |
425 self.bg.fill((0,0,0)) | |
426 # self.bg.blit(gradients.radial(19, self.scol, self.ecol), (rect_x,rect_y)) | |
427 l = copy.copy(self.blobs) | |
428 l.reverse() | |
429 for blob in l : | |
430 blob.draw() | |
431 | |
432 # axis | |
433 pg.draw.line(self.bg, (G,G,G), (int(X/2.0),0),(int(X/2.0),Y), 1) | |
434 pg.draw.line(self.bg, (G,G,G), (0,int(Y/2.0)),(X,int(Y/2.0)), 1) | |
435 | |
436 # indicators | |
437 for i in self.indicators.itervalues() : | |
438 i.draw() | |
439 | |
440 def read_keys(self): | |
441 '''Read keys''' | |
442 for event in pg.event.get() : | |
443 # Quit (event) | |
444 if event.type == QUIT: | |
445 self.midi_out.write(NOTE_OFF_CH0) | |
446 self.quit() | |
447 elif event.type == KEYDOWN : | |
448 # Post Quit: Esc, q | |
449 if event.key == K_ESCAPE or event.key == K_q : | |
450 pg.event.post(pg.event.Event(QUIT)) | |
451 # Reset: Space | |
452 elif event.key == K_SPACE : | |
453 self.blobs = [] | |
454 # Random : r | |
455 elif event.key == K_r : | |
456 self.add_blob(random(),random(),count=5) | |
457 # Connection : c | |
458 elif event.key == K_c : | |
459 self.init_reconnect = True | |
460 self.indicators["conn"].off() | |
461 # Fullscreen: f | |
462 elif event.key == K_f : | |
463 # pg.display.toggle_fullscreen() | |
464 self.toggle_screen_mode() | |
465 # Toggle fade: s | |
466 elif event.key == K_s : | |
467 if self.FADE : | |
468 print "fade off" | |
469 self.indicators["conn"].off() | |
470 self.FADE = 0 | |
471 for blob in self.blobs : | |
472 blob.fade(0) | |
473 else: | |
474 print "fade on" | |
475 self.indicators["conn"].on() | |
476 self.FADE = 15 | |
477 for blob in self.blobs : | |
478 blob.fade(15) | |
479 blob.reset_time() | |
480 # inc age | |
481 elif event.key == K_1 : | |
482 self.s_age += 1 | |
483 self.update_server_config(self.s_age,self.s_dist,self.s_ninp) | |
484 # dec age | |
485 elif event.key == K_2 : | |
486 self.s_age -= 1 | |
487 self.update_server_config(self.s_age,self.s_dist,self.s_ninp) | |
488 # inc dist | |
489 elif event.key == K_3 : | |
490 self.s_dist += 0.025 | |
491 self.update_server_config(self.s_age,self.s_dist,self.s_ninp) | |
492 # dec dist | |
493 elif event.key == K_4 : | |
494 self.s_dist -= 0.025 | |
495 if self.s_dist < 0.025 : self.s_dist = 0.025 | |
496 self.update_server_config(self.s_age,self.s_dist,self.s_ninp) | |
497 # inc ninp | |
498 elif event.key == K_5 : | |
499 self.s_ninp += 1 | |
500 self.update_server_config(self.s_age,self.s_dist,self.s_ninp) | |
501 # dec ninp | |
502 elif event.key == K_6 : | |
503 self.s_ninp -= 1 | |
504 if self.s_ninp < 2 : self.s_ninp = 2 | |
505 self.update_server_config(self.s_age,self.s_dist,self.s_ninp) | |
506 | |
507 pass | |
508 pass | |
509 | |
510 def toggle_screen_mode(self): | |
511 '''Go back and forth between full screen mode.''' | |
512 if self.fullscreen == False: | |
513 globals()['_X'] = globals()['X'] | |
514 globals()['_Y'] = globals()['Y'] | |
515 globals()['X'] = XF | |
516 globals()['Y'] = YF | |
517 self.screen = pg.display.set_mode((X, Y)) | |
518 # self.screen = pg.display.set_mode((0,0),pg.FULLSCREEN) | |
519 self.fullscreen = True | |
520 self.bg = pg.Surface(self.screen.get_size()) | |
521 self.bg = self.bg.convert() | |
522 self.bg.fill((0,0,0)) | |
523 for i in self.indicators.itervalues() : | |
524 i.reinit(self.bg) | |
525 i.draw() | |
526 else : | |
527 globals()['X'] = globals()['_X'] | |
528 globals()['Y'] = globals()['_Y'] | |
529 self.screen = pg.display.set_mode((X, Y)) | |
530 self.fullscreen = False | |
531 self.bg = pg.Surface(self.screen.get_size()) | |
532 self.bg = self.bg.convert() | |
533 self.bg.fill((0,0,0)) | |
534 for i in self.indicators.itervalues() : | |
535 i.reinit(self.bg) | |
536 i.draw() | |
537 pg.display.toggle_fullscreen() | |
538 | |
539 | |
540 | |
541 def run(self): | |
542 | |
543 # setup connection | |
544 self.connect() | |
545 | |
546 # main loop | |
547 while True : | |
548 # pg.draw.circle(screen, pg.Color(255,0,0), (300,50),20,0) | |
549 # screen.blit(gradients.radial(99, scol, ecol), (401, 1)) | |
550 | |
551 self.read_keys() | |
552 | |
553 # Draw | |
554 self.draw() | |
555 | |
556 # update display | |
557 self.screen.blit(self.bg, (0, 0)) | |
558 pg.display.flip() | |
559 self.fpsClock.tick(FRAMERATE) | |
560 | |
561 if self.init_reconnect: | |
562 self.reconnect() | |
563 | |
564 return True | |
565 | |
566 def configure_server(self): | |
567 '''Send the server some configuration data.''' | |
568 # age = 10.0 | |
569 # dist = DIST | |
570 # ninp = 18 | |
571 self.update_server_config(self.s_age,self.s_dist,self.s_ninp) | |
572 | |
573 | |
574 def update_server_config(self,age,dist,ninp,retry = 3): | |
575 '''Send the server some configuration data.''' | |
576 try : | |
577 self.conn.putrequest("GET","/moodconductor/config?age=%(age)s&dist=%(dist)s&ninp=%(ninp)s" %locals(), skip_host=True) | |
578 self.conn.putheader("Host", "www.isophonics.net") | |
579 self.conn.endheaders() | |
580 res = self.conn.getresponse() | |
581 if not res.status == 200 : | |
582 print "Server response:", res.status, res.reason | |
583 self.indicators["conn"].off() | |
584 time.sleep(0.5) | |
585 self.conn.putrequest("GET","/moodconductor/getconf", skip_host=True) | |
586 self.conn.putheader("Host", "www.isophonics.net") | |
587 self.conn.endheaders() | |
588 res = self.conn.getresponse() | |
589 if not res.status == 200 : | |
590 print "Server response:", res.status, res.reason | |
591 self.indicators["conn"].off() | |
592 print "Server configuration:", res.read() | |
593 except: | |
594 time.sleep(2) | |
595 retry -= 1 | |
596 self.update_server_config(age,dist,ninp,retry) | |
597 | |
598 | |
599 def connect(self,retry = 5): | |
600 '''Connect to the server and test connection.''' | |
601 if not retry : | |
602 print "Server unreachable" | |
603 pg.quit() | |
604 raise SystemExit | |
605 if retry < 5 : | |
606 time.sleep(3) | |
607 try : | |
608 self.conn = ht.HTTPConnection(IP,timeout=HTTP_TIMEOUT) | |
609 # self.start_update_thread() | |
610 self.indicators["conn"].on() | |
611 except : | |
612 self.indicators["conn"].off() | |
613 self.connect(retry = retry-1) | |
614 | |
615 try: | |
616 self.conn.putrequest("GET","/moodconductor/index.html", skip_host=True) | |
617 self.conn.putheader("Host", "www.isophonics.net") | |
618 self.conn.endheaders() | |
619 res = self.conn.getresponse() | |
620 if res.status == 200 : | |
621 self.indicators["conn"].on() | |
622 else : | |
623 print "Server response:", res.status, res.reason | |
624 self.indicators["conn"].off() | |
625 if not hasattr(self,"noretry") and raw_input("Go offline? ") in ['y',''] : | |
626 return False | |
627 else : | |
628 self.noretry = None | |
629 self.connect(retry = retry-1) | |
630 except : | |
631 print "Exception while testing connection." | |
632 self.indicators["conn"].off() | |
633 # comment out in offline mode | |
634 if not hasattr(self,"noretry") and raw_input("Go offline? ") in ['y',''] : | |
635 return False | |
636 else : | |
637 self.noretry = None | |
638 self.connect(retry = retry-1) | |
639 self.configure_server() | |
640 self.start_update_thread() | |
641 return True | |
642 | |
643 | |
644 | |
645 def reconnect(self): | |
646 '''Called when c is pressed.''' | |
647 self.init_reconnect = False | |
648 # self.indicators["conn"].off().draw() | |
649 # self.screen.blit(self.bg, (0, 0)) | |
650 # pg.display.flip() | |
651 | |
652 self.stop_update_thread() | |
653 time.sleep(1) | |
654 try : | |
655 self.conn.close() | |
656 except : | |
657 self.indicators["conn"].off() | |
658 try : | |
659 self.conn = ht.HTTPConnection(IP,timeout=HTTP_TIMEOUT) | |
660 self.conn.connect() | |
661 self.indicators["conn"].on() | |
662 print "Reconnected." | |
663 except : | |
664 self.indicators["conn"].off() | |
665 print "Error while reconnecting." | |
666 self.start_update_thread() | |
667 | |
668 | |
669 def quit(self): | |
670 print "Quitting.." | |
671 self.indicators["conn"].off() | |
672 self.stop_update_thread() | |
673 self.conn.close() | |
674 pg.quit() | |
675 sys.exit() | |
676 | |
677 | |
678 | |
679 | |
680 | |
681 def main(): | |
682 | |
683 v = VisualClient() | |
684 v.run() | |
685 | |
686 | |
687 if __name__ == '__main__': | |
688 pass | |
689 main() | |
690 |