]> git.donarmstrong.com Git - lilypond.git/blob - notationcanvas.py
* ikebana.py (NotationApplication.create_window): add zoom.
[lilypond.git] / notationcanvas.py
1 import gtk
2 import gnomecanvas
3 import music
4 import math
5
6 class Notation_toolbar (gtk.VBox):
7         def __init__ (self, notation, check_refresh_callback):
8                 gtk.VBox.__init__ (self)
9                 self.button_dict = {}
10                 self.key_dict = {}
11                 self.notation = notation
12                 self.rows = {}
13                 self.add_buttons ()
14                 self.check_refresh_callback = check_refresh_callback
15                 
16         def get_row (self, row):
17                 if not self.rows.has_key (row):
18                         r = gtk.HBox()
19                         self.pack_start (r, expand = False)
20                         r.show ()
21                         self.rows[row] = r
22                         return r
23                 
24                 return self.rows[row]
25                 
26         def click_callback (self, widget):
27                 if not self.button_dict.has_key (widget):
28                         print 'no such widget?'
29                         return False
30
31                 cb = self.button_dict[widget]
32                 cb()
33                 self.check_refresh_callback()
34                 return True
35
36         def keypress_callback (self, widget, event):
37                 key =  event.keyval
38                 name = gtk.gdk.keyval_name (key)
39
40                 if event.get_state () & gtk.gdk.SHIFT_MASK:
41                         name = 'Shift+' + name 
42                 if event.get_state () & gtk.gdk.CONTROL_MASK:
43                         name = 'Ctrl+' + name
44                 if not self.key_dict.has_key (name):
45                         print 'no such key?', name
46                         return False
47
48                 button = self.key_dict[name]
49                 button.do_activate (button)
50                 return True
51         
52         def add_button (self, text, key, callback, row_id):
53                 b = gtk.Button (text)
54                 row = self.get_row (row_id)
55                 row.pack_start (b, expand=True)
56                 
57                 b.connect ('clicked', self.click_callback)
58                 b.set_focus_on_click (False)
59                 self.key_dict[key] = b
60                 self.button_dict[b] = callback
61                 b.show ()
62
63         def add_buttons (self):
64                 for (key_name, text, func, row) in \
65                         [('p', 'LilyPond',
66                           lambda: self.notation.print_score(), 0),
67                          ('q', 'quit',
68                           lambda: gtk.main_quit(), 0),
69                          ('Left', '<-',
70                           lambda: self.notation.cursor_move (-1), 0),
71                          ('Right', '->',
72                           lambda: self.notation.cursor_move (1), 0),
73                          ('space', 'new',
74                           lambda: self.notation.add_note (), 0),
75                          ('BackSpace', 'backspace',
76                           lambda: self.notation.backspace (), 0),
77                          ('Shift+Up', '#',
78                           lambda: self.notation.change_alteration (2), 1),
79                          ('Shift+Down', 'b',
80                           lambda: self.notation.change_alteration (-2), 1),
81                          ('Up', 'up',
82                           lambda: self.notation.change_step (1), 1),
83                          ('Down', 'down',
84                           lambda: self.notation.change_step (-1), 1),
85                          ('apostrophe', 'oct up',
86                           lambda: self.notation.change_octave (1), 1),
87                          ('comma', 'oct down',
88                           lambda: self.notation.change_octave (-1), 1),
89                          ('period', '.',
90                           lambda: self.notation.change_dots (), 1),
91                          ('slash', 'shorter',
92                           lambda: self.notation.change_duration_log (1), 1),
93                          ('Shift+asterisk', 'longer',
94                           lambda: self.notation.change_duration_log (-1), 1),
95                          ('r', 'rest',
96                           lambda: self.notation.ensure_rest (), 1),
97                          ('Shift+C', '+C',
98                           lambda: self.notation.add_step (0), 2),
99                          ('Shift+D', '+D',
100                           lambda: self.notation.add_step (1), 2),
101                          ('Shift+E', '+E',
102                           lambda: self.notation.add_step (2), 2),
103                          ('Shift+F', '+F',
104                           lambda: self.notation.add_step (3), 2),
105                          ('Shift+G', '+G',
106                           lambda: self.notation.add_step (4), 2),
107                          ('Shift+A', '+A',
108                           lambda: self.notation.add_step (5), 2),
109                          ('Shift+B', '+B',
110                           lambda: self.notation.add_step (6), 2),
111                          ('c', 'C',
112                           lambda: self.notation.set_step (0), 3),
113                          ('d', 'D',
114                           lambda: self.notation.set_step (1), 3),
115                          ('e', 'E',
116                           lambda: self.notation.set_step (2), 3),
117                          ('f', 'F',
118                           lambda: self.notation.set_step (3), 3),
119                          ('g', 'G',
120                           lambda: self.notation.set_step (4), 3),
121                          ('a', 'A',
122                           lambda: self.notation.set_step (5), 3),
123                          ('b', 'B',
124                           lambda: self.notation.set_step (6), 3)]:
125                         
126                         self.add_button (text, key_name, func, row)
127
128
129 class Notation_canvas (gnomecanvas.Canvas):
130         """The canvas for drawing notation symbols."""
131         
132         def __init__ (self, canvas_controller):
133                 gnomecanvas.Canvas.__init__ (self,
134                                              #aa=True
135                                              )
136                 (w,h) = (400,200)
137                 self.set_size_request (w, h) 
138                 self.set_scroll_region (0, 0, w, h)
139                 root = self.root ()
140                 root.affine_relative ((1,0,0,-1,0, 5))
141                 self.pixel_scale = 10
142                 self.set_pixels_per_unit (self.pixel_scale)
143                 i = root.add (gnomecanvas.CanvasRect,
144                               y1 = 5,
145                               x2 = w, y2 = -h + 5,
146                               fill_color = 'white', outline_color = 'white')
147                 i.notation_item = None
148                 self.notation_canvas_controller = canvas_controller
149                 self.create_cursor ()
150                 
151         def create_cursor (self):
152                 type = gnomecanvas.CanvasRect
153                 w = self.root ().add (type,
154                                       fill_color = 'lightblue',
155                                       outline_color = 'lightblue')
156                 w.notation_item = None
157                 
158                 self.cursor_widget = w
159                 
160         def set_cursor (self, notation_item):
161                 if not notation_item.bbox:
162                         print 'no bbox'
163                         return
164
165                 (x1, y1, x2, y2) = notation_item.bbox
166                 self.cursor_widget.set (x1 = x1,
167                                         x2 = x2,
168                                         y1 = y1,
169                                         y2 = y2)
170                 
171                 
172         def item_set_active_state (self, item, active):
173                 color = 'black'
174                 if active:
175                         color = 'red'
176                         
177                 item.set (fill_color = color)
178                 
179         def click_event (self, widget, event = None):
180                 if event <> None and event.type == gtk.gdk.BUTTON_PRESS:
181                         if event.button == 1 and widget.notation_item.name in ('Rest', 'NoteHead'):
182                                 
183                                 notat = self.notation_canvas_controller.notation
184                                 notat.set_cursor (widget.notation_item.music_expression)
185                                 self.notation_canvas_controller.check_update()
186                                 
187                                 return True
188                 return False
189         
190         def register_notation_canvas_item (self, citem):
191                 if citem.notation_item and citem.notation_item.music_expression:
192                         citem.connect ("event", self.click_event)
193
194         def set_cursor_to_music (self, music_expression):
195                 c_items = [it for it in self.root().item_list if
196                            (it.notation_item
197                             and it.notation_item.music_expression
198                                 == music_expression)]
199
200                 c_items = filter (lambda it: it.notation_item.name in ('NoteHead', 'Rest'),
201                                   c_items) 
202                 if c_items:
203                         self.set_cursor (c_items[0].notation_item)
204
205         def zoom (self, delta):
206                 fact = pow (1.25, delta)
207                 self.pixel_scale *= fact
208                 self.set_pixels_per_unit (self.pixel_scale)
209                 
210 class Notation_canvas_controller:
211         """The connection between canvas and the abstract notation graphics."""
212
213         def __init__ (self, notation):
214                 self.canvas = Notation_canvas (self)
215                 self.notation = notation
216                 
217         def update_cursor (self):
218                 self.canvas.set_cursor_to_music (self.notation.music_cursor)
219
220         def update_canvas (self):
221                 self.notation.paint_on_canvas (self.canvas)
222
223         def check_update (self):
224                 self.notation.check_update ()
225                 if self.notation.touched:
226                         self.update_canvas ()
227                 elif self.notation.cursor_touched:
228                         self.update_cursor ()
229
230