From 29e22f05090827be14e2d9cfd29c73a5d0ec9239 Mon Sep 17 00:00:00 2001 From: amartin Date: Wed, 01 Aug 2007 11:26:00 +0000 Subject: Jam Desktop --- (limited to 'Jam') diff --git a/Jam/Block.py b/Jam/Block.py new file mode 100644 index 0000000..907ed3d --- /dev/null +++ b/Jam/Block.py @@ -0,0 +1,207 @@ + +import pygtk +pygtk.require( '2.0' ) +import gtk + +import Config + +import random + +class Block(): + + WIDTH = 100 + HEIGHT = 100 + + WIDTH_DIV2 = WIDTH//2 + HEIGHT_DIV2 = HEIGHT//2 + + def __init__( self, owner, graphics_context ): + self.owner = owner + self.gc = graphics_context + + self.type = Block + + self.parent = None + self.canChild = False + self.child = None + self.canParent = False + + self.dragging = False + + self.placed = False + self.x = -1 + self.y = -1 + + # TEMP + self.color = random.choice( [ "tempBlock1", "tempBlock2", "tempBlock3", "tempBlock4", "tempBlock5" ] ) + + def destroy( self ): + if self.child: + self.child.destroy() + self.child = None + + def getLoc( self ): + return ( self.x, self.y ) + + def setLoc( self, x, y ): + if x == self.x and y == self.y: return + + if self.placed: + self.invalidate_rect( not self.dragging ) + else: + self.placed = True + + self.x = x + self.y = y + self.endX = x + self.type.WIDTH + self.endY = y + self.type.HEIGHT + + self.invalidate_rect( not self.dragging ) + + if self.child: + self.child.setLoc( self.endX, y ) + + def testChild( self, loc ): + + if not self.canParent: + return False + + if self.child: + handled = self.child.testChild( loc ) + if handled: return handled + elif abs( self.endX - loc[0] ) < 10 and abs( self.y - loc[1] ) < 10: + return self + + return False + + def addChild( self, child ): + self.child = child + child._addParent( self ) + child.setLoc( self.endX, self.y ) + + def removeChild( self ): + self.child._removeParent() + self.child = None + + def _addParent( self, parent ): + self.parent = parent + + def _removeParent( self ): + self.parent = None + + def getRoot( self ): + if self.parent: return self.parent.getRoot() + return self + + def button_press( self, event ): + + if event.y < self.y or event.y > self.endY: + return False + + return self._button_pressB( event ) + + def _button_pressB( self, event ): + + if event.x < self.x: + return False + + if self.child: + handled = self.child._button_pressB( event ) + if handled: return handled + + if event.x > self.endX: + return False + + self.dragOffset = ( event.x - self.x, event.y - self.y ) + + self._doButtonPress( event ) + + return self + + def _doButtonPress( self, event ): + pass # override in subclasses + + def button_release( self, event ): + if self.dragging: + self.dragging = False + self.invalidateBranch() + + def motion_notify( self, event ): + + removeFromBlocks = not self.dragging and not self.parent + + if not self.dragging: + self.dragging = True + self.invalidate_rect() + + if self.parent: + self.parent.removeChild() + + self.setLoc( event.x - self.dragOffset[0], event.y - self.dragOffset[1] ) + + return removeFromBlocks + + def _beginDrag( self ): + self.dragging = True + self.dragOffset = ( self.type.WIDTH_DIV2, self.type.HEIGHT_DIV2 ) + + def invalidateBranch( self, base = True ): + self.invalidate_rect( base ) + if self.child: + self.child.invalidateBranch( base ) + + def invalidate_rect( self, base = True ): + self.owner.invalidate_rect( self.x, self.y, self.type.WIDTH, self.type.HEIGHT, base ) + + def draw( self, startX, startY, stopX, stopY, pixmap ): + if stopY < self.y or startY > self.endY: + return False + + self._drawB( startX, startY, stopX, stopY, pixmap ) + + def _drawB( self, startX, startY, stopX, stopY, pixmap ): + + if stopX < self.x: + return False + + if self.child: + self.child._drawB( startX, startY, stopX, stopX, pixmap ) + + if startX > self.endX: + return False + + self._doDraw( startX, startY, stopX, stopY, pixmap ) + + return True + + def _doDraw( self, startX, startY, stopX, stopY, pixmap ): + # TEMP + self.gc.foreground = self.owner.colors[self.color] + pixmap.draw_rectangle( self.gc, True, self.x, self.y, self.type.WIDTH, self.type.HEIGHT ) + pass # override in subclasses + + def drawHighlight( self, startX, startY, stopX, stopY, pixmap ): + # TEMP + self.gc.foreground = self.owner.colors["tempWhite"] + pixmap.draw_rectangle( self.gc, False, self.x, self.y, self.type.WIDTH-1, self.type.HEIGHT-1 ) + + +class Instrument(Block): + + WIDTH = Block.WIDTH + HEIGHT = Block.HEIGHT + + WIDTH_DIV2 = WIDTH//2 + HEIGHT_DIV2 = HEIGHT//2 + + def __init__( self, owner, graphics_context ): + Block.__init__( self, owner, graphics_context ) + + self.type = Instrument + + self.canParent = True + self.canChild = True + + def _doButtonPress( self, event ): # we were hit with a button press + pass + diff --git a/Jam/Desktop.py b/Jam/Desktop.py new file mode 100644 index 0000000..89c890b --- /dev/null +++ b/Jam/Desktop.py @@ -0,0 +1,244 @@ + +import pygtk +pygtk.require( '2.0' ) +import gtk + +import Config + +import Jam.Block as Block + +class Desktop( gtk.EventBox ): + + def __init__( self, owner ): + gtk.EventBox.__init__( self ) + + self.owner = owner + + self.drawingArea = gtk.DrawingArea() + self.add( self.drawingArea ) + + win = gtk.gdk.get_default_root_window() + self.gc = gtk.gdk.GC( win ) + colormap = self.drawingArea.get_colormap() + self.colors = { "bg": colormap.alloc_color( Config.BG_COLOR, True, True ), \ + "tempWhite": colormap.alloc_color( "#FFFFFF", True, True ), \ + "tempBlock1": colormap.alloc_color( "#227733", True, True ), \ + "tempBlock2": colormap.alloc_color( "#837399", True, True ), \ + "tempBlock3": colormap.alloc_color( "#111177", True, True ), \ + "tempBlock4": colormap.alloc_color( "#99AA22", True, True ), \ + "tempBlock5": colormap.alloc_color( "#449977", True, True ) } + + self.dirtyRectToAdd = gtk.gdk.Rectangle() # used by the invalidate_rect function + self.screenBuf = None + self.screenBufDirty = False + self.screenBufDirtyRect = gtk.gdk.Rectangle() + + self.blocks = [] # items on the desktop + + # TEMP + self.addBlock( Block.Instrument, [], ( 100, 100 ) ) + + self.add_events(gtk.gdk.POINTER_MOTION_MASK|gtk.gdk.POINTER_MOTION_HINT_MASK) + + self.connect( "size-allocate", self.size_allocate ) + self.connect( "button-press-event", self.button_press ) + self.connect( "button-release-event", self.button_release ) + self.connect( "motion-notify-event", self.motion_notify ) + self.drawingArea.connect( "expose-event", self.expose ) + + self.clickedBlock = None + self.possibleParent = None + self.dragging = False + self.possibleDelete = False + + def size_allocate( self, widget, allocation ): + if self.screenBuf == None or self.alloc.width != allocation.width or self.alloc.height != allocation.height: + win = gtk.gdk.get_default_root_window() + self.screenBuf = gtk.gdk.Pixmap( win, allocation.width, allocation.height ) + self.invalidate_rect( 0, 0, allocation.width, allocation.height ) + self.alloc = allocation + self.absoluteLoc = [0,0] + parent = self.get_parent() + while parent: + alloc = parent.get_allocation() + self.absoluteLoc[0] += alloc.x + self.absoluteLoc[1] += alloc.y + parent = parent.get_parent() + return False + + #========================================================== + # Blocks + + def addBlock( self, blockClass, blockData, loc = (-1,-1), drag = False ): + + block = blockClass( self, self.gc ) + + if loc[0] != -1: x = loc[0] + else: x = self.alloc.width//2 - blockClass.WIDTH_DIV2 + if loc[1] != -1: y = loc[1] + elif drag: y = self.alloc.height - blockClass.HEIGHT + else: y = self.alloc.height//2 - blockClass.HEIGHT_DIV2 + + if drag: + win = gtk.gdk.get_default_root_window() + display = win.get_display() + screen = display.get_default_screen() + display.warp_pointer( screen, self.absoluteLoc[0] + x + blockClass.WIDTH_DIV2, self.absoluteLoc[1] + y + blockClass.HEIGHT_DIV2 ) + self._beginDrag( block ) + block.setLoc( x, y ) + else: + self.blocks.append( block ) + block.setLoc( x, y ) + + + + #========================================================== + # Mouse + + def button_press( self, widget, event ): + + hit = False + for i in range(len(self.blocks)-1, -1, -1): + hit = self.blocks[i].button_press( event ) + if hit: + self.clickedBlock = hit + break + + def button_release( self, widget, event ): + + if self.possibleDelete: + self.possibleDelete = False + self.clickedBlock.destroy() + self.clickedBlock = None + self.possibleParent = None + self.dragging = False + + if self.dragging: + self.dragging = False + + if self.possibleParent: + self.possibleParent.invalidate_rect( False ) + self.possibleParent.addChild( self.clickedBlock ) + root = self.possibleParent.getRoot() + self.blocks.remove(root) + self.blocks.append(root) + self.possibleParent = None + else: + self.blocks.append( self.clickedBlock ) + + if self.clickedBlock: + self.clickedBlock.button_release( event ) + self.clickedBlock = None + + + def motion_notify( self, widget, event ): + + if not self.clickedBlock: + return + + if event.is_hint or widget != self: + x, y, state = self.window.get_pointer() + event.x = float(x) + event.y = float(y) + event.state = state + + self.dragging = True + + if self.clickedBlock.motion_notify( event ): # first drag of root block, remove from self.blocks + self.blocks.remove( self.clickedBlock ) + + if event.y < 0 or event.y > self.alloc.height: + self.possibleDelete = True + return + else: + self.possibleDelete = False + + if self.clickedBlock.canChild and len(self.blocks): + for i in range(len(self.blocks)-1, -1, -1): + handled = self.blocks[i].testChild( self.clickedBlock.getLoc() ) + if handled: + if self.possibleParent != handled: + if self.possibleParent: + self.possibleParent.invalidate_rect( False ) + self.possibleParent = handled + self.possibleParent.invalidate_rect( False ) + break + if not handled and self.possibleParent: + self.possibleParent.invalidate_rect( False ) + self.possibleParent = None + + def _beginDrag( self, block ): + block._beginDrag() + self.clickedBlock = block + self.dragging = True + + #========================================================== + # Drawing + + def draw( self ): + + startX = self.screenBufDirtyRect.x + startY = self.screenBufDirtyRect.y + stopX = startX + self.screenBufDirtyRect.width + stopY = startY + self.screenBufDirtyRect.height + + self.gc.set_clip_rectangle( self.screenBufDirtyRect ) + + # draw background + self.gc.foreground = self.colors["bg"] + self.screenBuf.draw_rectangle( self.gc, True, startX, startY, self.screenBufDirtyRect.width, self.screenBufDirtyRect.height ) + + # draw blocks + for block in self.blocks: + block.draw( startX, startY, stopX, stopY, self.screenBuf ) + + self.screenBufDirty = False + + def expose( self, DA, event ): + + if self.screenBufDirty: + self.draw() + + self.drawingAreaDirty = False + + startX = event.area.x + startY = event.area.y + stopX = event.area.x + event.area.width + stopY = event.area.y + event.area.height + + self.gc.set_clip_rectangle( event.area ) + + # draw base + DA.window.draw_drawable( self.gc, self.screenBuf, startX, startY, startX, startY, event.area.width, event.area.height ) + + if self.possibleDelete: + return + + # draw possible parent + if self.possibleParent: + self.possibleParent.drawHighlight( startX, startY, stopX, stopY, DA.window ) + + # draw dragged objects + if self.dragging: + self.clickedBlock.draw( startX, startY, stopX, stopY, DA.window ) + + def invalidate_rect( self, x, y, width, height, base = True ): + self.dirtyRectToAdd.x = x + self.dirtyRectToAdd.y = y + self.dirtyRectToAdd.width = width + self.dirtyRectToAdd.height = height + + #print "dirty %d %d %d %d %d %d" % (x, y, width, height, x+width, y+height) + if base: # the base image has been dirtied + if not self.screenBufDirty: + self.screenBufDirtyRect.x = x + self.screenBufDirtyRect.y = y + self.screenBufDirtyRect.width = width + self.screenBufDirtyRect.height = height + else: + self.screenBufDirtyRect = self.screenBufDirtyRect.union( self.dirtyRectToAdd ) + self.screenBufDirty = True + if self.drawingArea.window != None: + self.drawingArea.window.invalidate_rect( self.dirtyRectToAdd, True ) + self.drawingAreaDirty = True + diff --git a/Jam/Jam.py b/Jam/Jam.py deleted file mode 100644 index a143a29..0000000 --- a/Jam/Jam.py +++ /dev/null @@ -1,19 +0,0 @@ -from SubActivity import SubActivity - -class Jam(SubActivity): - - def __init__(self, activity, set_mode): - SubActivity.__init__(self, set_mode) - - self.activity = activity - - - def onActivate( self, arg ): - pass - - def onDeactivate( self ): - pass - - def onDestroy( self ): - pass - diff --git a/Jam/JamMain.py b/Jam/JamMain.py new file mode 100644 index 0000000..8c203a1 --- /dev/null +++ b/Jam/JamMain.py @@ -0,0 +1,78 @@ + +import pygtk +pygtk.require( '2.0' ) +import gtk + +from SubActivity import SubActivity + +from Jam.Desktop import Desktop +from Jam.Picker import Picker + +class JamMain(SubActivity): + + def __init__(self, activity, set_mode): + SubActivity.__init__(self, set_mode) + + self.activity = activity + + + #====================================================== + # GUI + + if True: # GUI + self.GUI = {} + self.GUI["mainVBox"] = gtk.VBox() + self.add( self.GUI["mainVBox"] ) + + #-- Desktop ------------------------------------------- + self.desktop = self.GUI["desktop"] = Desktop( self ) + self.GUI["mainVBox"].pack_start( self.GUI["desktop"] ) + + #-- Bank ---------------------------------------------- + self.GUI["bankVBox"] = gtk.VBox() + self.GUI["mainVBox"].pack_start( self.GUI["bankVBox"], False, False ) + if True: # Tabs + self.GUI["bankTabs"] = gtk.HBox() + self.GUI["bankTabs"].set_size_request( -1, 38 ) + self.GUI["bankVBox"].pack_start( self.GUI["bankTabs"], False, False ) + + self.GUI["bankInstrumentsTab"] = gtk.RadioButton( None, "Instruments" ) + self.GUI["bankTabs"].pack_start( self.GUI["bankInstrumentsTab"] ) + self.GUI["bankDrumsTab"] = gtk.RadioButton( self.GUI["bankInstrumentsTab"], "Drums" ) + self.GUI["bankTabs"].pack_start( self.GUI["bankDrumsTab"] ) + self.GUI["bankLoopsTab"] = gtk.RadioButton( self.GUI["bankInstrumentsTab"], "Loops" ) + self.GUI["bankTabs"].pack_start( self.GUI["bankLoopsTab"] ) + + if True: # Picker + self.GUI["bankPicker"] = gtk.HBox() + self.GUI["bankPicker"].set_size_request( -1, 149 ) + self.GUI["bankVBox"].pack_start( self.GUI["bankPicker"], False, False ) + + self.GUI["bankScrollLeft"] = gtk.Button( "<" ) + self.GUI["bankPicker"].pack_start( self.GUI["bankScrollLeft"], False, False ) + + self.GUI["bankScrolledWindow"] = gtk.ScrolledWindow() + self.GUI["bankScrolledWindow"].set_policy( gtk.POLICY_ALWAYS, gtk.POLICY_NEVER ) + self.GUI["bankPicker"].pack_start( self.GUI["bankScrolledWindow"] ) + + self.GUI["bankScrollRight"] = gtk.Button( ">" ) + self.GUI["bankPicker"].pack_start( self.GUI["bankScrollRight"], False, False ) + + self.GUI["pickerInstruments"] = Picker( self, Picker.INSTRUMENTS ) + self.GUI["pickerInstruments"].show_all() + + self.GUI["bankScrolledWindow"].add_with_viewport( self.GUI["pickerInstruments"] ) + + self.show_all() + + def onActivate( self, arg ): + pass + + def onDeactivate( self ): + pass + + def onDestroy( self ): + pass + + def getDesktop( self ): + return self.desktop diff --git a/Jam/Picker.py b/Jam/Picker.py new file mode 100644 index 0000000..5c1627b --- /dev/null +++ b/Jam/Picker.py @@ -0,0 +1,51 @@ + +import pygtk +pygtk.require( '2.0' ) +import gtk + +import Jam.Block as Block + +class Picker( gtk.HBox ): + + INSTRUMENTS = 0 + LOOPS = 1 + DRUMKITS = 2 + + def __init__( self, owner, type, filter = None ): + gtk.HBox.__init__( self ) + + self.owner = owner + + self.type = type + self.filter = filter + + self.desktop = owner.getDesktop() + + # temp + dummy = gtk.Button("dummy") + dummy.add_events(gtk.gdk.BUTTON_MOTION_MASK) + dummy.connect( "button-press-event", self.button_press ) + dummy.connect( "button-release-event", self.button_release ) + dummy.connect( "motion-notify-event", self.motion_notify ) + + self.pack_start( dummy, False, False ) + + def button_press( self, widget, event ): + alloc = widget.get_allocation() + if self.type == Picker.INSTRUMENTS: + blockClass = Block.Instrument + blockData = [] + loc = ( alloc.x + event.x - blockClass.WIDTH_DIV2, -1 ) + elif self.type == Picker.LOOPS: + pass + elif self.type == Picker.DRUMKITS: + pass + self.desktop.addBlock( blockClass, blockData, loc, True ) + + def button_release( self, widget, event ): + self.desktop.button_release( widget, event ) + + def motion_notify( self, widget, event ): + self.desktop.motion_notify( widget, event ) + + -- cgit v0.9.1