import gtk import pygtk import random class BrickBrowser(gtk.DrawingArea): def __init__(self, wid, hei, platform, mp): self.main = mp self.platform = platform self.width, self.height = wid, hei self.init_data() self.init_graphics() gtk.DrawingArea.__init__(self) self.set_size_request(self.width, self.height) self.connect("expose_event", self.expose_event) self.connect("configure_event", self.configure_event) self.connect("leave_notify_event", self.leave_notify_event) self.connect("motion_notify_event", self.motion_notify_event) self.connect("button_press_event", self.button_press_event) self.connect("button_release_event", self.button_release_event) self.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.LEAVE_NOTIFY_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK) def init_data(self): self.flag = 0 # 0 off 1 on self.fix_button = 0 self.brick_highlight = -1 self.drag_brick = -1 self.select_brick = -1 self.drag_state = 0 self.list = [] self.listf = [] self.list_p = 0 self.page_cnt = [0 for i in range(1000)] self.all_brick_list = [] self.active_brick_list = [] self.button_highlight = -1 self.btns = ["Back","Stop","Prev","Next","Refresh","Load"] self.bx1 = [0 for i in range(self.main.score.tesize)] self.bx2 = [0 for i in range(self.main.score.tesize)] self.by = [0 for i in range(self.main.score.tesize)] self.no_update = False self.update_pending = 0 self.ready = 0 self.loadmode = False #self.create_all_list() #self.lucky_pick() #self.load_temp_list() def init_graphics(self): self.cx = (int)(0.09 * self.width) self.cy = 10 self.btn_h = 42 self.gridw = self.main.bricksarea.gridw self.gridh = self.main.bricksarea.gridh self.ngrid_v = self.main.bricksarea.ngrid_v self.ngrid_h = self.main.bricksarea.ngrid_h self.ahei = self.main.bricksarea.chei * 4 self.thei = self.ahei + 4*3 + 2*2 self.height = self.cy * 2 + self.thei def configure_event(self, widget, event): x, y, width, height = widget.get_allocation() self.pixmap = gtk.gdk.Pixmap(widget.window, width, height) return True def leave_notify_event(self, widget, event): return def button_press_event(self, widget, event): self.fix_button = self.fix_button + 1 if self.fix_button != 1: return if event.button == 1: t = self.is_on_brick(event.x, event.y) # print "Back 0 %d" % t if t != -1: if self.drag_state == 1 and self.loadmode: if self.drag_brick == t: self.drag_state = 2 else: self.draw_1_score(self.drag_brick, t) self.drag_brick = t self.filename_label.set_text(self.main.score.temp_bricks[t].filename) self.author_label.set_text(self.main.score.temp_bricks[t].author) if self.main.score.temp_bricks[t].filename.endswith("mps"): name = "Composition" elif self.main.score.temp_bricks[t].brick_type == 2: name = "Rhythm Brick" else: name = "Melody Brick" self.type_label.set_text(name) self.scale_label.set_text(self.main.score.scale_list[self.main.score.temp_bricks[t].scale_mode]) self.title_label.set_text(self.main.score.temp_bricks[t].title) self.desc_label.set_text(self.main.score.temp_bricks[t].description) self.note_label.set_text(self.main.score.temp_bricks[t].note) else: self.drag_brick = t self.drag_state = 1 else: t = self.is_on_button(event.x, event.y) if t != 1 and t != 5 and self.drag_state == 1: self.drag_state = 0 self.draw_1_score(self.drag_brick, -1) # print "Back 1 %d" % t if t == 0: # back self.main.browser_layout.remove(self.main.bricksarea) if self.platform != "sugar-xo": self.main.window.remove(self.main.browser_layout) self.main.layout.put(self.main.bricksarea, 0, self.main.toolbararea_height + self.main.canvas_height) if self.platform == "sugar-xo": self.main.window.set_canvas(self.main.layout) else: self.main.window.add(self.main.layout) self.main.window.show_all() self.fix_button = 0 self.flag = 0 elif t == 1: # stop self.main.score.stop_music(self.main.csound) elif t == 2: # prev if self.list_p > 0: self.list_p = self.list_p - 1 self.load_temp_list_1page() self.draw_scores() elif t == 3: # next if self.page_cnt[self.list_p] < len(self.list): self.list_p = self.list_p + 1 # self.list_p = self.list_p + self.main.score.tesize self.load_temp_list_1page() self.draw_scores() elif t == 4: # refresh self.update_all_list() elif t == 5: # load if self.drag_state == 1: self.main.browser_layout.remove(self.main.bricksarea) if self.platform != "sugar-xo": self.main.window.remove(self.main.browser_layout) self.main.layout.put(self.main.bricksarea, 0, self.main.toolbararea_height + self.main.canvas_height) if self.platform == "sugar-xo": self.main.window.set_canvas(self.main.layout) else: self.main.window.add(self.main.layout) self.main.window.show_all() self.fix_button = 0 self.flag = 0 self.drag_state = 0 self.main.canvas.canvas_load_score(self.main.score.temp_bricks[self.drag_brick].filename) return def button_release_event(self, widget, event): self.fix_button = 0 if self.drag_state == 2 and self.loadmode: t = self.is_on_brick(event.x, event.y) if self.drag_brick == t: self.main.score.temp_bricks[t].play_music() self.drag_state = 1 else: self.draw_1_score(self.drag_brick, t) self.brick_highlight = t self.drag_state = 0 elif self.drag_state == 1: t = self.is_on_brick(event.x, event.y) if not self.loadmode: if self.drag_brick == t: self.main.score.temp_bricks[t].play_music() else: self.draw_1_score(self.drag_brick, t) self.brick_highlight = t self.drag_state = 0 # drag to if not self.loadmode: bricka = self.main.bricksarea score = self.main.score t = bricka.is_on_brickarea(event.x, event.y - self.main.canvas_height) if t: grp = -1 brick = score.temp_bricks[self.drag_brick] if brick.author == self.main.username: if brick.brick_type == 0: grp = 1 elif brick.brick_type == 2: grp = 2 else: if brick.brick_type == 0: grp = 4 elif brick.brick_type == 2: grp = 5 if grp != -1 and bricka.add_brick(grp, brick): if grp !=bricka.active_group: bricka.change_active_group(grp) else: bricka.bricks_cnt = bricka.bricks_cnt + 1 bricka.draw_scores() self.active_brick_list.append(brick.filename) self.draw_1_score(-1, self.drag_brick) def motion_notify_event(self, widget, event): if event.is_hint: x, y, state = event.window.get_pointer() else: x, y = event.x, event.y state = event.state t = self.is_on_brick(event.x, event.y) if self.drag_state == 0 and t != self.brick_highlight and (self.brick_highlight != -1 or t != -1): if t == -1: self.filename_label.set_text("") self.author_label.set_text("") self.type_label.set_text("") self.scale_label.set_text("") self.title_label.set_text("") self.desc_label.set_text("") self.note_label.set_text("") else: self.filename_label.set_text(self.main.score.temp_bricks[t].filename) self.author_label.set_text(self.main.score.temp_bricks[t].author) if self.main.score.temp_bricks[t].filename.endswith("mps"): name = "Composition" elif self.main.score.temp_bricks[t].brick_type == 2: name = "Rhythm Brick" else: name = "Melody Brick" self.type_label.set_text(name) self.scale_label.set_text(self.main.score.scale_list[self.main.score.temp_bricks[t].scale_mode]) self.title_label.set_text(self.main.score.temp_bricks[t].title) self.desc_label.set_text(self.main.score.temp_bricks[t].description) self.note_label.set_text(self.main.score.temp_bricks[t].note) self.draw_1_score(self.brick_highlight, t) self.brick_highlight = t t = self.is_on_button(event.x, event.y) if self.drag_state == 0 and t != self.button_highlight: self.button_highlight = t self.draw_buttons() def expose_event(self, widget, event): print "expose_event" self.widget = widget self.ready = 1 cr = self.pixmap.cairo_create() # set a clip region for the expose event x , y, width, height = event.area cr.rectangle(x, y, width, height) cr.clip() self.draw(cr) # draw_drawable? if self.update_pending == 1: if self.main.type_box.get_active_text() == "Compositions": self.draw_buttons() self.draw_scores() self.update_pending = 0 widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL], self.pixmap, x, y, x, y, width, height) return False def draw_curvy_rectangle(self, cr, x0, y0, x1, y1, r, highlight): if highlight == 0: cr.set_source_rgb(0.80,0.80,0.80) else: cr.set_source_rgb(0.92,0.92,0.92) cr.move_to(x0, y0 + r) cr.curve_to(x0, y0, x0, y0, x0+r, y0) cr.line_to(x1-r, y0) cr.curve_to(x1, y0, x1, y0, x1, y0+r) cr.line_to(x1, y1-r) cr.curve_to(x1, y1, x1, y1, x1-r, y1) cr.line_to(x0+r, y1) cr.curve_to(x0, y1, x0, y1, x0, y1-r) cr.close_path() cr.fill_preserve() cr.set_line_width(1) cr.set_source_rgb(0.98, 0.98, 0.98) cr.stroke() def is_on_brick(self, x, y): if y < self.cy - 2 or y > self.cy + self.ahei + 12: return -1 if x < self.cx or x > self.width-20: return -1 bricka = self.main.bricksarea for i in range(self.main.score.temp_bricks_cnt): if self.list_p == 0 and i >= self.page_cnt[self.list_p]: return -1 elif self.list_p > 0 and i >= (self.page_cnt[self.list_p] - self.page_cnt[self.list_p - 1]): return -1 # print "%d %d %d %d %d" % (x, y, self.bx1[i], self.bx2[i], self.by[i]) if y >= self.by[i] and y < (self.by[i] + bricka.chei) and x >= self.bx1[i] and x < self.bx2[i]: return i return -1 def draw_1_score(self, t1, t2): cr = self.pixmap.cairo_create() widget = self.widget bricka = self.main.bricksarea ty = bricka.cy if t1 != -1: bricka.cy = self.by[t1] bricka.draw_mini_score(cr, self.bx1[t1]-self.cx, self.main.score.temp_bricks[t1], self.listf[t1+self.list_p]) if t2 != -1: bricka.cy = self.by[t2] bricka.draw_mini_score(cr, self.bx1[t2]-self.cx, self.main.score.temp_bricks[t2], 1) bricka.cy = ty widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL], self.pixmap, self.cx, 0, self.cx, 0, self.width, self.height) def is_on_button(self, x, y): if x < 12 or x >= self.cx - 12: return -1 for i in range(len(self.btns)): if i == len(self.btns)-1 and self.main.type_box.get_active_text() != "Compositions": continue; if y >= self.cy + i*self.btn_h and y < self.cy + i*self.btn_h + self.btn_h - 8: return i return -1 def draw_scores(self): cr = self.pixmap.cairo_create() widget = self.widget score = self.main.score bricka = self.main.bricksarea self.draw_curvy_rectangle(cr, self.cx-2, self.cy-5, self.width-20+2, self.cy + self.ahei+16, 8, 0) x = 5 row = 0 ty = bricka.cy bricka.cy = self.cy + 2 if self.list_p == 0: self.page_cnt[self.list_p] = score.temp_bricks_cnt else: self.page_cnt[self.list_p] = self.page_cnt[self.list_p-1] + score.temp_bricks_cnt for i in range(score.temp_bricks_cnt): brick = score.temp_bricks[i] if x + brick.width * self.gridw > self.width-20-self.cx: row = row + 1 bricka.cy = bricka.cy + bricka.chei + 4 x = 5 if row >= 4: if self.list_p == 0: self.page_cnt[self.list_p] = i + 1 else: self.page_cnt[self.list_p] = i + 1 + self.page_cnt[self.list_p - 1] break if self.list_p == 0: bricka.draw_mini_score(cr, x, brick, self.listf[i]) else: bricka.draw_mini_score(cr, x, brick, self.listf[i+self.page_cnt[self.list_p-1]]) self.bx1[i] = self.cx + x self.bx2[i] = self.cx + x + brick.width * self.gridw self.by[i] = bricka.cy x = x + brick.width * self.gridw + bricka.bdiv + 2 bricka.cy = ty widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL], self.pixmap, self.cx, 0, self.cx, 0, self.width, self.height) def draw(self, cr): cr.set_source_rgb(0.84, 0.84, 1) cr.rectangle(0, 0, self.width, self.height) cr.fill() self.draw_buttons() self.draw_scores() def draw_buttons(self): cr = self.pixmap.cairo_create() cr.set_source_rgb(0.84, 0.84, 1) cr.rectangle(0, 0, self.cx, self.height) cr.fill() widget = self.widget cr.set_font_size(18) for i in range(len(self.btns)): if i == len(self.btns)-1 and self.main.type_box.get_active_text() != "Compositions": continue; (x0, y0) = (12, self.cy + i * self.btn_h) (x1, y1) = (self.cx-12, self.cy + i * self.btn_h + self.btn_h - 8) self.draw_curvy_rectangle(cr, x0, y0, x1, y1, 4, (self.button_highlight == i)) xb, yb, wid, hei = cr.text_extents(self.btns[i])[:4] cr.set_source_rgb(0.4, 0.4, 0.4) cr.move_to( (x0+x1)/2 - wid/2 - xb, (y0+y1)/2 - hei/2 - yb) cr.show_text(self.btns[i]) widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL], self.pixmap, 0, 0, 0, 0, self.cx-3, self.height) def get_file_info(self, filename): try: n = filename.split("_") l = len(n) if filename.endswith("mps"): type = -1 else: type = (int)(n[l-3]) scale = (int)(n[l-2]) if l == 4: author = n[0] else: author = "" for i in range(l-3): author = author + n[i] if i != l-4: author = author + "_" except: return ["invalid_filename", 0, 0] else: return [author, type, scale] def update_author_list(self): score = self.main.score size1 = len(score.local_brick_list) size2 = len(score.srv_brick_list) self.main.model1.append([self.main.username]) for i in range(size1): [author, type, scale] = self.get_file_info(score.local_brick_list[i]) if author == "invalid_filename": continue; flag = 0 for j in range(len(self.main.model1)): if self.main.model1[j][0] == author: flag = 1 break if flag == 0: self.main.model1.append([author]) for i in range(size2): [author, type, scale] = self.get_file_info(score.srv_brick_list[i]) if author == "invalid_filename": continue; flag = 0 for j in range(len(self.main.model1)): if self.main.model1[j][0] == author: flag = 1 break if flag == 0: self.main.model1.append([author]) def combo_changed(self, widget, entry = None): self.load_temp_list() self.brick_highlight = -1 self.drag_brick = -1 self.drag_state = 0 self.loadmode = (self.main.type_box.get_active_text() == "Compositions") # if not self.loadmode: # self.drag_state = 0 if self.ready == 0: self.update_pending = 1 return self.draw_buttons() self.draw_scores() def filter(self, filename): [author, type, scale] = self.get_file_info(filename) if author == "invalid_filename": return False af = self.main.author_box.get_active_text() if af != "All Authors": if author != af: return False at = self.main.type_box.get_active_text() if at == "Compositions" and type != -1: return False elif at == "All Bricks" and type == -1: return False elif at == "Melody Bricks" and type != 0: return False elif at == "Rhythm Bricks" and type != 2: return False a = self.main.scale_box.get_active() if a == 0: return True elif a-1 != scale: return False return True def writeline_cb(self, line): self.stream.writelines(line + "\n") def makesure_file_on_local(self, filename): try: file = open("myscore/" + filename) except IOError: if self.main.ftp_status == 1: try: self.stream = open("myscore/" + filename, 'w') msg = self.main.ftp.retrlines("RETR " + filename, self.writeline_cb) print "ftp::RETR " + filename + "...." + msg self.stream.close() except IOError: return False else: return True else: return True def update_all_list(self): score = self.main.score try: score.srv_brick_list = self.main.ftp.nlst("*.mp*") except: score.srv_brick_list = [] self.main.ftp_status = 0 score.create_local_brick_list() size1 = len(score.local_brick_list) size2 = len(score.srv_brick_list) for i in range(size1): try: self.all_brick_list.index(score.local_brick_list[i]) except ValueError: self.all_brick_list.append(score.local_brick_list[i]) for i in range(size2): try: self.all_brick_list.index(score.srv_brick_list[i]) except ValueError: self.all_brick_list.append(score.srv_brick_list[i]) self.combo_changed(self.widget) def create_all_list(self): if not self.main.update_author: self.update_author_list() self.main.update_author = True score = self.main.score self.active_brick_list = [] for i in range(score.work_bricks_cnt): self.active_brick_list.append(score.work_bricks[i].filename) for i in range(score.mymelody_bricks_cnt): self.active_brick_list.append(score.mymelody_bricks[i].filename) for i in range(score.myrhythm_bricks_cnt): self.active_brick_list.append(score.myrhythm_bricks[i].filename) for i in range(score.cmelody_bricks_cnt): self.active_brick_list.append(score.cmelody_bricks[i].filename) for i in range(score.crhythm_bricks_cnt): self.active_brick_list.append(score.crhythm_bricks[i].filename) self.all_brick_list = [] size1 = len(score.local_brick_list) size2 = len(score.srv_brick_list) print str(size1) + " files on local, " + str(size2) + " files on server" self.list = [] for i in range(size1): self.all_brick_list.append(score.local_brick_list[i]) for i in range(size2): flag = 0 for j in range(len(self.all_brick_list)): if self.all_brick_list[j] == score.srv_brick_list[i]: flag = 1 break if flag == 0: self.all_brick_list.append(score.srv_brick_list[i]) t = len(self.all_brick_list) for i in range(t * 10): a = random.randint(0, t-1) b = random.randint(0, t-1) f = self.all_brick_list[a] self.all_brick_list[a] = self.all_brick_list[b] self.all_brick_list[b] = f def change_status(self, name, new_state): try: id = self.list.index(name) except ValueError: return else: self.listf[id] = new_state def create_list(self): size = len(self.all_brick_list) self.list = [] self.listf = [] for i in range(size): if self.filter(self.all_brick_list[i]): self.list.append(self.all_brick_list[i]) try: id = self.active_brick_list.index(self.all_brick_list[i]) except ValueError: self.listf.append(0) # not in list else: self.listf.append(1) # in active list def lucky_pick(self): # automatically generate collected brick list score = self.main.score size = len(self.all_brick_list) cnt = 0 while score.cmelody_bricks_cnt < 5: cnt = cnt + 1 if cnt > 200: break a = random.randint(0, size-1) name = self.all_brick_list[a] [author, type, scale] = self.get_file_info(name) if author == "invalid_filename" or author == self.main.username or type != 0: continue try: id = self.active_brick_list.index(name) except ValueError: self.makesure_file_on_local(name) self.active_brick_list.append(name) score.cmelody_bricks[score.cmelody_bricks_cnt].read_score(name, score) score.cmelody_bricks_cnt = score.cmelody_bricks_cnt + 1 cnt = 0 while score.crhythm_bricks_cnt < 5: cnt = cnt + 1 if cnt > 200: break a = random.randint(0, size-1) name = self.all_brick_list[a] [author, type, scale] = self.get_file_info(name) if author == "invalid_filename" or author == self.main.username or type != 2: continue try: id = self.active_brick_list.index(name) except ValueError: self.makesure_file_on_local(name) self.active_brick_list.append(name) score.crhythm_bricks[score.crhythm_bricks_cnt].read_score(name, score) score.crhythm_bricks_cnt = score.crhythm_bricks_cnt + 1 def load_temp_list_1page(self): size = len(self.list) score = self.main.score score.temp_bricks_cnt = 0 if self.list_p == 0: t = size t2 = 0 else: t = size - self.page_cnt[self.list_p-1] t2 = self.page_cnt[self.list_p-1] for i in range(t): self.makesure_file_on_local(self.list[t2+i]) score.temp_bricks[i].read_score(self.list[t2+i], score) score.temp_bricks_cnt = score.temp_bricks_cnt + 1 if i == score.tesize - 1: break def load_temp_list(self): self.create_list() self.list_p = 0 self.load_temp_list_1page()