From: hanwen Date: Fri, 29 Jul 2005 11:35:52 +0000 (+0000) Subject: * ikebana.py (NotationApplication.tree_selection_changed): new X-Git-Tag: ikebana/2.7.1~3 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=9a6a7ab655730dc31ee5a3d99b140d9e2a9095bc;p=lilypond.git * ikebana.py (NotationApplication.tree_selection_changed): new function. * music.py (ClefEvent.__init__): add (NoteEvent.ly_expression): add (Music.has_children): new method. * musictree.py (MusicTreeView.selection_changed): add Tree view of music model. --- diff --git a/ChangeLog b/ChangeLog index 33fd62dd0e..e188fcc520 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,19 @@ +2005-07-29 Han-Wen Nienhuys + + * ikebana.py (NotationApplication.tree_selection_changed): new + function. + + * music.py (ClefEvent.__init__): add + (NoteEvent.ly_expression): add + (Music.has_children): new method. + + * musictree.py (MusicTreeView.selection_changed): add Tree view of + music model. + 2005-07-28 Han-Wen Nienhuys * server.ly: use Completion_heads_engraver + use version number. * music.py (Music.set_start): use Rationals for lengths. diff --git a/ikebana.py b/ikebana.py index ddd709d2e0..2d4ab757bb 100644 --- a/ikebana.py +++ b/ikebana.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import musictree import os import gtk import gnomecanvas @@ -14,16 +15,40 @@ def mainquit (*args): class NotationApplication: def __init__ (self): - self.music = music.Music_document () + self.document = music.Music_document () - nc = notation.Notation_controller (self.music) + nc = notation.Notation_controller (self.document) self.notation_controller = nc ncc = notationcanvas.Notation_canvas_controller (nc.notation) self.notation_canvas_controller = ncc self.window = self.create_window () + self.tree_window =self.create_tree_window () + + def tree_selection_changed (self, music_obj): + nc = self.notation_controller + nc.notation.set_cursor (music_obj) + self.notation_canvas_controller.check_update() + + def create_tree_window (self): + win = gtk.Window () + (w,h) = (500,300) + win.set_size_request (w, h) + + win.connect ('destroy', mainquit) + win.set_title ('Ikebana - music representation') + treeview = musictree.MusicTreeView (self.document.music) + win.add(treeview) + win.show() + treeview.selection_change_callback = self.tree_selection_changed + + notation = self.notation_canvas_controller.notation + notation.set_cursor_callback = treeview.cursor_changed + + return win + def create_window (self): win = gtk.Window () win.connect ('destroy', mainquit) diff --git a/music.py b/music.py index 14a767b80f..4db0b8e26a 100644 --- a/music.py +++ b/music.py @@ -61,14 +61,16 @@ class Pitch: def steps (self): return self.step + self.octave * 7 - def ly_expression (self): - + def ly_step_expression (self): str = 'cdefgab'[self.step] if self.alteration > 0: str += 'is'* (self.alteration/2) elif self.alteration < 0: str += 'es'* (-self.alteration/2) - + return str + + def ly_expression (self): + str = self.ly_step_expression () if self.octave >= 0: str += "'" * (self.octave + 1) elif self.octave < -1: @@ -94,6 +96,15 @@ class Music: def get_properties (self): return '' + def has_children (self): + return False + + def get_index (self): + if self.parent: + return self.parent.elements.index (self) + else: + return None + def lisp_expression (self): name = self.name() tag = '' @@ -128,7 +139,8 @@ class NestedMusic(Music): def __init__ (self): Music.__init__ (self) self.elements = [] - + def has_children (self): + return self.elements def set_tag (self, counter, dict): counter = Music.set_tag (self, counter, dict) for e in self.elements : @@ -285,6 +297,54 @@ class NoteEvent(RhythmicEvent): return '%s%s' % (self.pitch.ly_expression (), self.duration.ly_expression ()) + + +class KeySignatureEvent (Event): + def __init__ (self, tonic, scale): + Event.__init__ (self) + self.scale = scale + self.tonic = tonic + def name (self): + return 'KeySignatureEvent' + def ly_expression (self): + return '\\key %s \\major' % self.tonic.ly_step_expression () + + def lisp_expression (self): + pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)] + scale_str = ("'(%s)" % string.join (pairs)) + + return """ (make-music 'KeyChangeEvent + 'pitch-alist %s) """ % scale_str + +class ClefEvent (Event): + def __init__ (self, t): + Event.__init__ (self) + self.type = t + def name (self): + + return 'ClefEvent' + def ly_expression (self): + return '\\clef "%s"' % self.type + clef_dict = { + "G": ("clefs.G", -2, -6), + "C": ("clefs.C", 0, 0), + "F": ("clefs.F", 2, 6), + } + + def lisp_expression (self): + (glyph, pos, c0) = self.clef_dict [self.type] + clefsetting = """ + (make-music 'SequentialMusic + 'elements (list + (context-spec-music + (make-property-set 'clefGlyph "%s") 'Staff) + (context-spec-music + (make-property-set 'clefPosition %d) 'Staff) + (context-spec-music + (make-property-set 'middleCPosition %d) 'Staff))) +""" % (glyph, pos, c0) + return clefsetting + def test_expr (): m = SequentialMusic() l =2 @@ -302,7 +362,6 @@ def test_expr (): evc.insert_around (None, n, 0) m.insert_around (None, evc, 0) - evc = EventChord() n = NoteEvent() n.duration.duration_log = l @@ -310,15 +369,26 @@ def test_expr (): evc.insert_around (None, n, 0) m.insert_around (None, evc, 0) + evc = ClefEvent("G") + m.insert_around (None, evc, 0) + + evc = EventChord() + tonic = Pitch () + tonic.step = 2 + tonic.alteration = -2 + n = KeySignatureEvent(tonic, [0, 0, -2, 0, 0,-2,-2] ) + evc.insert_around (None, n, 0) + m.insert_around (None, evc, 0) + return m if __name__ == '__main__': expr = test_expr() expr.set_start (Rational (0)) - - start = 0.25 - stop = 0.5 + print expr.ly_expression() + start = Rational (0,4) + stop = Rational (4,2) def sub(x, start=start, stop=stop): ok = x.start >= start and x.start +x.length() <= stop return ok diff --git a/musictree.py b/musictree.py new file mode 100644 index 0000000000..29b7b095c5 --- /dev/null +++ b/musictree.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python +'''Tree View/Generic Tree Model + +This test is designed to demonstrate creating a new type of tree model +in python for use with the new tree widget in gtk 2.0.''' + +import gtk +import gobject + +# to create a new GtkTreeModel from python, you must derive from +# TreeModel. +class MusicTreeModel(gtk.GenericTreeModel): + '''This class represents the model of a tree. The iterators used + to represent positions are converted to python objects when passed + to the on_* methods. This means you can use any python object to + represent a node in the tree. The None object represents a NULL + iterator. + + In this tree, we use simple tuples to represent nodes, which also + happen to be the tree paths for those nodes. This model is a tree + of depth 3 with 5 nodes at each level of the tree. The values in + the tree are just the string representations of the nodes.''' + + def __init__(self, music): + '''constructor for the model. Make sure you call + PyTreeModel.__init__''' + gtk.GenericTreeModel.__init__(self) + self.music = music + + # the implementations for TreeModel methods are prefixed with on_ + def on_get_flags(self): + '''returns the GtkTreeModelFlags for this particular type of model''' + return 0 + + def on_get_n_columns(self): + '''returns the number of columns in the model''' + return 2 + + def on_get_column_type(self, index): + '''returns the type of a column in the model''' + return gobject.TYPE_STRING + + def on_get_path(self, node): + '''returns the tree path(a tuple of indices at the various + levels) for a particular node.''' + +# print 'on_get_path' + if node.parent: + return tuple (list (self.on_get_path (node.parent)) + + + [node.get_index ()]) + else: + return (0,) + + def on_get_iter(self, path): + '''returns the node corresponding to the given path. In our + case, the node is the path''' + +# print 'on_get_iter' , path + + ptr = self.music + for i in path[1:]: + ptr = ptr.elements[i] + + return ptr + + def on_get_value(self, node, column): + '''returns the value stored in a particular column for the node''' + + str = '' + if column == 0: + str = node.name() + elif column==1: + str = node.ly_expression() + + return str + + def on_iter_next(self, node): + '''returns the next node at this level of the tree''' +# print 'on_iter_next', node + if not node.parent: + return None + + neigh = node.parent.get_neighbor (node, 1) + if neigh <> node: + return neigh + else: + return None + + def on_iter_children(self, node): + '''returns the first child of this node''' +# print 'on_iter_children', node + if node.has_children (): + return node.elements[0] + else: + return None + + def on_iter_has_child(self, node): + '''returns true if this node has children''' + hc = node.has_children () + +# print node, 'has_child', hc + + return hc + + def on_iter_n_children(self, node): + '''returns the number of children of this node''' + assert node <> None + +# print 'on_iter_n_children', node + + return len (node.elements) + + def on_iter_nth_child(self, node, n): + '''returns the nth child of this node''' + if node == None: + return self.music + +# print 'on_iter_nth_child', node , n + + return node.elements[n] + + def on_iter_parent(self, node): + '''returns the parent of this node''' + +# print 'on_iter_parent', node + + return node.parent + +class MusicTreeView(gtk.ScrolledWindow): + def __init__(self, music): + gtk.ScrolledWindow.__init__(self) + self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + + model = MusicTreeModel (music) + self.model = model + tree_view = gtk.TreeView(model) + cell = gtk.CellRendererText() + + # the text in the column comes from column 0 + column = gtk.TreeViewColumn("Type", cell, text=0) + tree_view.append_column(column) + column = gtk.TreeViewColumn("Contents", cell, text=1) + tree_view.append_column(column) + self.tree_selection = tree_view.get_selection() + + self.add(tree_view) + self.show_all() + + self.tree_selection.connect ('changed', self.selection_changed) + self.selection_change_callback = None + + def selection_changed (self, a): + if self.selection_change_callback: + (model, iter) = a.get_selected() + path = model.get_path (iter) + obj = model.on_get_iter (path) + if obj.name() in ('RestEvent', 'NoteEvent'): + self.selection_change_callback(obj) + + def select_music (self, music): + path = self.model.on_get_path (music) + self.tree_selection.select_path (path) + + def cursor_changed (self, notation): + self.select_music (notation.music_cursor) + +def main(): + GenericTreeModelDemo() + gtk.main() + +if __name__ == '__main__': + main() + diff --git a/notation.py b/notation.py index 5fa77eb264..457dd14ee9 100644 --- a/notation.py +++ b/notation.py @@ -25,18 +25,6 @@ time_sig = (4, 4) measure_length = Rational (time_sig[0], time_sig[1]) measure_count = 4 -scale_str = ("'(%s)" % - string.join (['(%d . %d)' % (i , scale_alterations[i]) for i in range (0,7)], ' ')) - -"'((0 . 0) (1 . 0) (2 . -2) (3 . 0) (4 . 0) (5 . -2) (6 . -2))" -clefsetting = """ - (context-spec-music - (make-property-set 'clefGlyph "clefs.C") 'Staff) - (context-spec-music - (make-property-set 'clefPosition 0) 'Staff) - (context-spec-music - (make-property-set 'middleCPosition 0) 'Staff) -""" try: server = os.environ['IKEBANASERVER'] @@ -78,18 +66,9 @@ def set_measure_number (str, num): (make-property-set 'beatLength (ly:make-moment 1 %d)) 'Score) (context-spec-music (make-property-set 'currentBarNumber %d) 'Score) - (context-spec-music - (make-music 'EventChord - 'elements - (list - (make-music 'KeyChangeEvent - 'pitch-alist - %s) - )) - 'Staff) - + %s))""" % (time_sig[0], time_sig[1], time_sig[0], - time_sig[1], time_sig[1], num, scale_str, str) + time_sig[1], time_sig[1], num, str) def render_score (filename, ly): print ly @@ -162,6 +141,7 @@ class Notation_controller: def interpret_line (self, offset, cause, bbox, name, fields): notation_item = self.notation.add_item (offset, cause, bbox, fields) notation_item.name = name + def touch_document (self): self.document.touched = True @@ -196,7 +176,7 @@ class Notation_controller: new_stop = new_start + Rational (measure_count) * measure_length if new_start <> self.start_moment or new_stop <> self.stop_moment: - print "render interval", new_start, new_stop +# print "render interval", new_start, new_stop self.touch_document() self.start_moment = new_start @@ -234,6 +214,7 @@ class Notation: self.notation_controller = controller self.touched = True self.cursor_touched = True + self.cursor_callback = None toplevel = controller.document.music self.music_cursor = toplevel.find_first (lambda x: x.name()== "NoteEvent") @@ -269,11 +250,15 @@ class Notation: canvas.set_cursor_to_music (self.music_cursor) self.touched = False - + def set_cursor (self, music_expr): - self.music_cursor = music_expr - self.cursor_touched = True - self.ensure_cursor_visible () + if music_expr <> self.music_cursor: + self.music_cursor = music_expr + self.cursor_touched = True + self.ensure_cursor_visible () + proc = self.set_cursor_callback + if proc: + proc (self) def cursor_move (self, dir): mus = self.music_cursor @@ -481,6 +466,7 @@ class Notation: arp = music.ArpeggioEvent() par.insert_around (self.music_cursor, arp, -1) self.touch_document() + def print_score(self): doc = self.notation_controller.document ly = doc.music.ly_expression() diff --git a/notationcanvas.py b/notationcanvas.py index 0b769ebdcf..24a965376a 100644 --- a/notationcanvas.py +++ b/notationcanvas.py @@ -122,19 +122,19 @@ class Notation_toolbar (gtk.VBox): ('Shift+B', '+B', lambda: self.notation.add_step (6), 2), ('c', 'C', - lambda: self.notation.set_step (0), 3), + lambda: self.notation.set_step (0), 2), ('d', 'D', - lambda: self.notation.set_step (1), 3), + lambda: self.notation.set_step (1), 2), ('e', 'E', - lambda: self.notation.set_step (2), 3), + lambda: self.notation.set_step (2), 2), ('f', 'F', - lambda: self.notation.set_step (3), 3), + lambda: self.notation.set_step (3), 2), ('g', 'G', - lambda: self.notation.set_step (4), 3), + lambda: self.notation.set_step (4), 2), ('a', 'A', - lambda: self.notation.set_step (5), 3), + lambda: self.notation.set_step (5), 2), ('b', 'B', - lambda: self.notation.set_step (6), 3)]: + lambda: self.notation.set_step (6), 2)]: self.add_button (text, key_name, func, row) @@ -145,7 +145,7 @@ class Notation_canvas (gnomecanvas.Canvas): gnomecanvas.Canvas.__init__ (self, #aa=True ) - (w,h) = (400,200) + (w,h) = (400,150) self.set_size_request (w, h) self.set_scroll_region (0, 0, w, h) root = self.root ()