Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Jam
diff options
context:
space:
mode:
authoramartin <olpc@xo-05-28-21.localdomain>2007-08-01 11:26:00 (GMT)
committer amartin <olpc@xo-05-28-21.localdomain>2007-08-01 11:26:00 (GMT)
commit29e22f05090827be14e2d9cfd29c73a5d0ec9239 (patch)
treeae55826ea3c9c0ee0d09a96a7bde00e865e0fa18 /Jam
parent65f1c3491a68fcf892987d8cba6485054694f4f7 (diff)
Jam Desktop
Diffstat (limited to 'Jam')
-rw-r--r--Jam/Block.py207
-rw-r--r--Jam/Desktop.py244
-rw-r--r--Jam/Jam.py19
-rw-r--r--Jam/JamMain.py78
-rw-r--r--Jam/Picker.py51
5 files changed, 580 insertions, 19 deletions
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 )
+
+