[jokosher-devel] [PATCH] UI improvements



Here are three patches that together make the following improvements to the user interface:
Patches are included as attachments, and affect Event.py, EventViewer.py, and Instrument.py

Daniel
Index: /home/daniel/workspace/Jokosher/Jokosher/EventViewer.py
===================================================================
--- /home/daniel/workspace/Jokosher/Jokosher/EventViewer.py	(revision 1494)
+++ /home/daniel/workspace/Jokosher/Jokosher/EventViewer.py	(working copy)
@@ -104,6 +104,7 @@
 		# Selections--marking part of the waveform. Don't confuse this with
 		# self.event.isSelected, which means the whole waveform is selected.
 		self.isSelecting = False		# True if a selection is currently being set
+		self.isDraggingSelection = False# True if a selection is currently being dragged
 		self.isDraggingFade = False		# True if the user is dragging a fade marker
 		self.lane = lane				# The parent lane for this object
 		self.currentScale = 0			# Tracks if the project viewScale has changed
@@ -108,9 +109,9 @@
 		self.lane = lane				# The parent lane for this object
 		self.currentScale = 0			# Tracks if the project viewScale has changed
 		self.redrawWaveform = False		# Force redraw the cached waveform on next expose event
-		self.drawerAlignToLeft = True		#boolean; if the drawer should be at the left of current selection
+		self.drawerAlignToLeft = True	#boolean; if the drawer should be at the left of current selection
 									#otherwise it will be put on the right
-		self.fadeMarkers = [100,100]		#the values of the right and left fade markers on the selection
+		self.fadeMarkers = [100,100]	#the values of the right and left fade markers on the selection
 
 		# Set accessibility helpers
 		self.SetAccessibleName()
@@ -540,6 +541,7 @@
 				
 				
 			self.highlightCursor = None
+		
 		elif self.isSelecting:
 			x2 = max(0,min(self.allocation.width,mouse.x))
 			self.event.selection[1] = self.SecFromPixX(x2)
@@ -556,6 +558,26 @@
 			#move the drawer to its proper position
 			self.UpdateDrawerPosition(selection_direction == "rtol")
 			
+		elif self.isDraggingSelection:
+			#temp variable to keep track of length moved
+			selectionDuration = self.PixXFromSec(self.event.selection[1] - self.event.selection[0])
+			x1 = max(selectionDuration,min(self.allocation.width,mouse.x))#(mouse.x - mousedelta1)
+			x0 = x1 - selectionDuration#(mouse.x - mousedelta0)
+			self.event.selection[1] = self.SecFromPixX(x1)
+			self.event.selection[0] = self.SecFromPixX(x0)
+			self.UpdateFadeMarkers()
+						
+			selection_direction = "ltor"
+			selection = self.event.selection
+			if selection[0] > selection[1]:
+				selection_direction = "rtol"
+				self.fadeMarkers.reverse()
+			
+			#set the drawer align position
+			self.drawerAlignToLeft = (selection_direction == "rtol")
+			#move the drawer to its proper position
+			self.UpdateDrawerPosition(selection_direction == "rtol")
+			
 		else:
 			self.highlightCursor = mouse.x
 		
@@ -570,8 +592,11 @@
 		Possible click combinations to capture:
 			{L|R}MB: deselect all Events, remove any existing selection in
 					this Event then select this Event and begin moving the Event.
-			LMB+shift: remove any existing selection in this Event and begin
-					selecting part of this Event.
+			MMB: remove any existing selection in this Event and begin selecting
+					part of this Event.
+			MMB+shift: continue selecting in addition to an already selected part
+					of this Event.
+			{L|R}MB+shift: select everything from last selected Event to this Event
 			{L|R}MB+ctrl: select this Event without deselecting other Events.
 			RMB: display a context menu.
 			LMB double-click: split this Event here.
@@ -592,13 +617,38 @@
 		
 		# {L|R}MB: deselect all events, select this event, begin moving the event
 		# {L|R}MB+ctrl: select this event without deselecting other events
-		if 'GDK_CONTROL_MASK' not in mouse.state.value_names:
+		# {L|R}MB+shift: select all events from this one to last selected
+		if ('GDK_CONTROL_MASK' not in mouse.state.value_names) & ('GDK_SHIFT_MASK' not in mouse.state.value_names):
 			self.project.ClearEventSelections()
 			self.project.SelectInstrument(None)
-		self.event.SetSelected(True)
-		
+			self.event.SetSelected(True)
+		elif 'GDK_SHIFT_MASK' not in mouse.state.value_names:
+			#deselect previously selected events
+			if self.event.isSelected == True:
+				self.event.SetSelected(False)
+			else:
+				self.event.SetSelected(True)
+		elif 'GDK_SHIFT_MASK' in mouse.state.value_names:
+			#CTRL+SHIFT: add everything from last selected to self to selection
+			#SHIFT: everything from last selected to self becomes the selection 
+			if self.event.instrument.orderSelected == []:
+				startSel = self.event.instrument.events.index(self.event) #If no event selected, select clicked
+			else:
+				startSel = self.event.instrument.orderSelected[-1] #Begin shift-selection at last part of orderSelected
+			endSel = self.event.instrument.events.index(self.event) #End shift-selection at event clicked
+			if 'GDK_CONTROL_MASK' not in mouse.state.value_names:
+				self.project.ClearEventSelections()
+				self.project.SelectInstrument(None)
+			#select everything from startSel to endSel
+			if endSel >= startSel:
+				for i in range (startSel, endSel+1):
+					self.event.instrument.events[i].SetSelected(True)
+			else:
+				for i in range (startSel, endSel-1, -1):
+					self.event.instrument.events[i].SetSelected(True)
+	
 		#Don't allow editing while playing back.
-		#It must be here to avoid afecting the selection behavior
+		#It must be here to avoid affecting the selection behavior
 		if self.mainview.isPlaying or self.mainview.isPaused:
 			return True
 		
@@ -605,6 +655,32 @@
 		# RMB: context menu
 		if mouse.button == 3:
 			self.ContextMenu(mouse)
+		
+		# MMB: selecting part of this event	
+		elif mouse.button == 2:
+			if 'GDK_SHIFT_MASK' not in mouse.state.value_names:
+				# Remove any existing selection in this event, if 
+				#   MMB is pressed without shift.
+				self.event.selection[0] = self.SecFromPixX(mouse.x)
+				self.event.selection[1] = self.SecFromPixX(mouse.x)
+				self.isSelecting = True
+				self.fadeMarkers = [100,100] 
+			else: #if shift is on
+				#If cursor is on or before selection, drag the leftmost portion of selection 
+				if (self.SecFromPixX(mouse.x) <= self.event.selection[0]) & (self.SecFromPixX(mouse.x) <= self.event.selection[1]):
+					self.event.selection[0] = self.event.selection[1]
+					self.isSelecting = True
+				#If cursor is amid selection, move the whole selection
+				elif self.event.selection[0] < self.SecFromPixX(mouse.x) < self.event.selection[1]:
+					
+					self.isDraggingSelection = True
+				#If cursor is on or after selection, drag the rightmost portion of selection
+				else:
+					self.isSelecting = True
+			
+			if not self.selmessageID: 
+				self.selmessageID = self.mainview.SetStatusBar(_("<b>Click</b> the buttons below the selection to do something to that portion of audio."))
+			
 		elif mouse.button == 1:
 			# check to see if the user clicked on the cancel button
 			if self.cancelButtonArea.x <= mouse.x <= self.cancelButtonArea.width+self.cancelButtonArea.x \
@@ -613,46 +689,37 @@
 				self.OnDelete()
 				return True
 			
-			if 'GDK_SHIFT_MASK' in mouse.state.value_names:
-				# LMB+shift: remove any existing selection in this event, begin 
-				#   selecting part of this event
-				self.isSelecting = True
-				self.event.selection[0] = self.SecFromPixX(mouse.x)
-				self.fadeMarkers = [100,100]
-				if not self.selmessageID: 
-					self.selmessageID = self.mainview.SetStatusBar(_("<b>Click</b> the buttons below the selection to do something to that portion of audio."))
-			else:
-				if self.fadeMarkersContext and self.fadeMarkersContext.in_fill(mouse.x, mouse.y):
-					# LMB over a fadeMarker: drag that marker
-					self.isDraggingFade = True
-					if mouse.x > self.PixXFromSec(self.event.selection[1]) - self._PIXX_FADEMARKER_WIDTH - 1:
-						self.fadeBeingDragged = 1
-						return True
-					else:
-						self.fadeBeingDragged = 0
-						return True
-				if mouse.type == gtk.gdk._2BUTTON_PRESS:
-					# LMB double-click: split here
-					self.mouseAnchor[0] = mouse.x
-					if self.event.isLoading == False:
-						self.OnSplit(None, mouse.x)
+			if self.fadeMarkersContext and self.fadeMarkersContext.in_fill(mouse.x, mouse.y):
+				# LMB over a fadeMarker: drag that marker
+				self.isDraggingFade = True
+				if mouse.x > self.PixXFromSec(self.event.selection[1]) - self._PIXX_FADEMARKER_WIDTH - 1:
+					self.fadeBeingDragged = 1
+					return True
+				else:
+					self.fadeBeingDragged = 0
 					return True
+			if mouse.type == gtk.gdk._2BUTTON_PRESS:
+				# LMB double-click: split here
+				self.mouseAnchor[0] = mouse.x
+				if self.event.isLoading == False:
+					self.OnSplit(None, mouse.x)
+				return True
 				
-				# remove any existing selection in this event
-				self.event.selection = [0,0]
-				if self.drawer.parent == self.lane.fixed:
-					self.lane.fixed.remove(self.drawer)
-					if self.volmessageID:   #clesr status bar if not already clear
-						self.mainview.ClearStatusBar(self.volmessageID)
-						self.volmessageID = None
-					if self.selmessageID:   #clesr status bar if not already clear
-						self.mainview.ClearStatusBar(self.selmessageID)
-						self.selmessageID = None	
-				self.isDragging = True
+			# remove any existing selection in this event
+			self.event.selection = [0,0]
+			if self.drawer.parent == self.lane.fixed:
+				self.lane.fixed.remove(self.drawer)
+				if self.volmessageID:   #clesr status bar if not already clear
+					self.mainview.ClearStatusBar(self.volmessageID)
+					self.volmessageID = None
+				if self.selmessageID:   #clesr status bar if not already clear
+					self.mainview.ClearStatusBar(self.selmessageID)
+					self.selmessageID = None	
+			self.isDragging = True
 				
-				self.eventStart = self.event.start
-				ptr = gtk.gdk.display_get_default().get_pointer()
-				self.mouseAnchor = [ptr[1], ptr[2]]
+			self.eventStart = self.event.start
+			ptr = gtk.gdk.display_get_default().get_pointer()
+			self.mouseAnchor = [ptr[1], ptr[2]]
 	
 		return True
 
@@ -957,6 +1024,14 @@
 			elif self.isSelecting:
 				self.isSelecting = False
 				self.ShowDrawer()
+		elif mouse.button == 2:
+		#For MMB selections
+			if self.isSelecting:
+				self.isSelecting = False
+				self.ShowDrawer()
+			elif self.isDraggingSelection:
+				self.isDraggingSelection = False
+				self.ShowDrawer()
 
 	#_____________________________________________________________________
 
Index: /home/daniel/workspace/Jokosher/Jokosher/Instrument.py
===================================================================
--- /home/daniel/workspace/Jokosher/Jokosher/Instrument.py	(revision 1494)
+++ /home/daniel/workspace/Jokosher/Jokosher/Instrument.py	(working copy)
@@ -110,6 +110,7 @@
 		self.isSolo = False			# True if the instrument is solo'd (only instrument active)
 		self.isVisible = True			# True if the instrument should be displayed in the mixer views
 		self.isSelected = False		# True if the instrument is currently selected
+		self.orderSelected = []		# The order in which events were selected (Used for shift-selection of events)
 		
 		self.level = 0.0				# Current audio level in range 0..1
 		self.volume = 1.0			# Gain of the current instrument in range 0..1
Index: /home/daniel/workspace/Jokosher/Jokosher/Event.py
===================================================================
--- /home/daniel/workspace/Jokosher/Jokosher/Event.py	(revision 1494)
+++ /home/daniel/workspace/Jokosher/Jokosher/Event.py	(working copy)
@@ -840,10 +840,14 @@
 		# No need to emit a signal when there is no change in selection state
 		if self.isSelected is not sel:
 			self.isSelected = sel
+			if sel == True:
+				self.instrument.orderSelected.append(self.instrument.events.index(self))
+			else:
+				self.instrument.orderSelected.remove(self.instrument.events.index(self))
 			self.emit("selected")
 	
 	#_____________________________________________________________________
-	
+
 	def MayPlace(self, xpos):
 		"""
 		Checks if this event could be placed at xpos without 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]