Skip to content
Snippets Groups Projects
Commit 8de1ae64 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

Moved slicecanvas and imageview (now called orthopanel) to a new package, fslview.

parent a67c1bc7
No related branches found
No related tags found
No related merge requests found
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
# Author: Paul McCarthy <pauldmccarthy@gmail.com> # Author: Paul McCarthy <pauldmccarthy@gmail.com>
# #
import collections
import os.path as op import os.path as op
import numpy as np import numpy as np
...@@ -145,6 +147,9 @@ class ImageList(object): ...@@ -145,6 +147,9 @@ class ImageList(object):
if images is None: images = [] if images is None: images = []
if not isinstance(images, collections.Iterable):
raise TypeError('images must be a sequence of images')
self._images = images self._images = images
self._listeners = [] self._listeners = []
......
#!/usr/bin/env python #!/usr/bin/env python
# #
# imgshow.py - A wx/OpenGL widget for displaying and interacting with a # orthopanel.py - A wx/OpenGL widget for displaying and interacting with a
# collection of 3D images. Displays three canvases, each of which shows # collection of 3D images. Displays three canvases, each of which shows the
# same image(s) on a different orthogonal plane.
# #
# Author: Paul McCarthy <pauldmccarthy@gmail.com> # Author: Paul McCarthy <pauldmccarthy@gmail.com>
# #
import sys import sys
if False: if True:
import logging import logging
logging.basicConfig( logging.basicConfig(
format='%(levelname)8s '\ format='%(levelname)8s '\
...@@ -22,184 +22,25 @@ if False: ...@@ -22,184 +22,25 @@ if False:
import wx import wx
import wx.lib.newevent as wxevent import wx.lib.newevent as wxevent
import fsl.props as props import fsl.props as props
import fsl.data.fslimage as fslimage import fsl.data.fslimage as fslimage
import fsl.utils.slicecanvas as slicecanvas import fsl.fslview.slicecanvas as slicecanvas
# The OrthoPanel emits a LocationEvent whenever the 'cursor' location
# changes. It contains three attributes, x, y, and z, corresponding to
# the current cursort location in the image space.
LocationEvent, EVT_LOCATION_EVENT = wxevent.NewEvent() LocationEvent, EVT_LOCATION_EVENT = wxevent.NewEvent()
class EditableListBox(wx.Panel): class OrthoPanel(wx.Panel):
"""
wx.gizmos.EditableListBox is rubbish.
"""
ListSelectEvent, EVT_ELB_SELECT_EVENT = wxevent.NewEvent()
ListAddEvent, EVT_ELB_ADD_EVENT = wxevent.NewEvent()
ListRemoveEvent, EVT_ELB_REMOVE_EVENT = wxevent.NewEvent()
ListMoveEvent, EVT_ELB_MOVE_EVENT = wxevent.NewEvent()
def __init__(
self,
parent,
choices,
clientData):
wx.Panel.__init__(self, parent)
self.listBox = wx.ListBox(
self, style=wx.LB_SINGLE | wx.LB_NEEDED_SB)
for choice,data in zip(choices, clientData):
self.listBox.Append(choice, data)
self.listBox.Bind(wx.EVT_LISTBOX, self.itemSelected)
self.buttonPanel = wx.Panel(self)
self.upButton = wx.Button(self.buttonPanel, label=u'\u25B2')
self.downButton = wx.Button(self.buttonPanel, label=u'\u25BC')
self.addButton = wx.Button(self.buttonPanel, label='+')
self.removeButton = wx.Button(self.buttonPanel, label='-')
self.upButton .Bind(wx.EVT_BUTTON, self.moveItemUp)
self.downButton .Bind(wx.EVT_BUTTON, self.moveItemDown)
self.addButton .Bind(wx.EVT_BUTTON, self.addItem)
self.removeButton.Bind(wx.EVT_BUTTON, self.removeItem)
self.buttonPanelSizer = wx.BoxSizer(wx.VERTICAL)
self.buttonPanel.SetSizer(self.buttonPanelSizer)
self.buttonPanelSizer.Add(self.upButton)
self.buttonPanelSizer.Add(self.downButton)
self.buttonPanelSizer.Add(self.addButton)
self.buttonPanelSizer.Add(self.removeButton)
self.sizer = wx.BoxSizer(wx.HORIZONTAL)
self.SetSizer(self.sizer)
self.sizer.Add(self.buttonPanel, flag=wx.EXPAND)
self.sizer.Add(self.listBox, flag=wx.EXPAND, proportion=1)
self.Layout()
def itemSelected(self, ev):
idx = ev.GetSelection()
choice = self.listBox.GetString(idx)
data = self.listBox.GetClientData(idx)
print 'selected {}'.format(idx)
ev = EditableListBox.ListSelectEvent(
idx=idx, choice=choice, data=data)
wx.PostEvent(self, ev)
def moveItem(self, oldIdx, newIdx):
# nothing is selected
if oldIdx == wx.NOT_FOUND: return
choice = self.listBox.GetString(oldIdx)
data = self.listBox.GetClientData(oldIdx)
choices = self.listBox.GetItems()
if oldIdx < 0 or oldIdx >= len(choices): return
if newIdx < 0 or newIdx >= len(choices): return
self.listBox.Delete(oldIdx)
self.listBox.Insert(choice, newIdx, data)
self.listBox.SetSelection(newIdx)
ev = EditableListBox.ListMoveEvent(
oldIdx=oldIdx,
newIdx=newIdx,
choice=choice,
data=data)
wx.PostEvent(self, ev)
def moveItemDown(self, ev):
oldIdx = self.listBox.GetSelection()
newIdx = oldIdx+1
self.moveItem(oldIdx, newIdx)
def moveItemUp(self, ev):
oldIdx = self.listBox.GetSelection()
newIdx = oldIdx-1
self.moveItem(oldIdx, newIdx)
def addItem(self, ev):
pass
def removeItem(self, ev):
pass
class DisplayControl(wx.Panel):
def __init__(self, parent, imageList):
wx.Panel.__init__(self, parent)
self.imageList = imageList
imageNames = [img.name for img in imageList]
self.listBox = EditableListBox(
self, imageNames, imageList)
self.listBox.Bind(
EditableListBox.EVT_ELB_SELECT_EVENT, self.imageSelected)
self.listBox.Bind(
EditableListBox.EVT_ELB_MOVE_EVENT, self.imageMoved)
self.editPanels = []
for image in imageList:
displayProps = props.buildGUI(self, image.display)
self.editPanels.append(displayProps)
self.sizer = wx.BoxSizer(wx.HORIZONTAL)
self.SetSizer(self.sizer)
self.sizer.Add(self.listBox, flag=wx.EXPAND, proportion=1)
for i,editPanel in enumerate(self.editPanels):
self.sizer.Add(editPanel, flag=wx.EXPAND, proportion=2)
editPanel.Show(i == 0)
self.Layout()
def imageMoved(self, ev):
oldIdx = ev.oldIdx
newIdx = ev.newIdx
image = self.imageList.pop(oldIdx)
self.imageList.insert(newIdx, image)
self.Refresh()
def imageSelected(self, ev):
"""
"""
print 'imageSelected'
for i,editPanel in enumerate(self.editPanels):
editPanel.Show(i == ev.idx)
self.Layout()
class ImageView(wx.Panel):
def __init__(self, parent, imageList, *args, **kwargs): def __init__(self, parent, imageList, *args, **kwargs):
""" """
Creates three SliceCanvas objects, each displaying a Creates three SliceCanvas objects, each displaying the images
different axis of the given image list. in the given image list along a different axis.
""" """
# if an fslimage.Image is passed in, we turn
# a blind eye, and make it a list of length 1
if isinstance(imageList, fslimage.Image): if isinstance(imageList, fslimage.Image):
imageList = fslimage.ImageList(imageList) imageList = fslimage.ImageList(imageList)
...@@ -214,32 +55,19 @@ class ImageView(wx.Panel): ...@@ -214,32 +55,19 @@ class ImageView(wx.Panel):
self.shape = imageList[0].data.shape self.shape = imageList[0].data.shape
self.canvasPanel = wx.Panel(self) self.xcanvas = slicecanvas.SliceCanvas(self, imageList, zax=0)
self.ycanvas = slicecanvas.SliceCanvas(self, imageList, zax=1,
context=self.xcanvas.context)
self.zcanvas = slicecanvas.SliceCanvas(self, imageList, zax=2,
context=self.xcanvas.context)
self.xcanvas = slicecanvas.SliceCanvas( self.sizer = wx.BoxSizer(wx.HORIZONTAL)
self.canvasPanel, imageList, zax=0) self.SetSizer(self.sizer)
self.ycanvas = slicecanvas.SliceCanvas(
self.canvasPanel, imageList, zax=1, context=self.xcanvas.context)
self.zcanvas = slicecanvas.SliceCanvas(
self.canvasPanel, imageList, zax=2, context=self.xcanvas.context)
self.controlPanel = DisplayControl(self, imageList)
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
self.canvasSizer = wx.BoxSizer(wx.HORIZONTAL)
self.SetSizer(self.mainSizer)
self.mainSizer.Add(self.canvasPanel, flag=wx.EXPAND, proportion=1)
self.mainSizer.Add(self.controlPanel, flag=wx.EXPAND)
self.canvasPanel.SetSizer(self.canvasSizer)
self.canvasSizer.Add(self.xcanvas, flag=wx.EXPAND, proportion=1) self.sizer.Add(self.xcanvas, flag=wx.EXPAND, proportion=1)
self.canvasSizer.Add(self.ycanvas, flag=wx.EXPAND, proportion=1) self.sizer.Add(self.ycanvas, flag=wx.EXPAND, proportion=1)
self.canvasSizer.Add(self.zcanvas, flag=wx.EXPAND, proportion=1) self.sizer.Add(self.zcanvas, flag=wx.EXPAND, proportion=1)
self.canvasPanel.Layout()
self.Layout() self.Layout()
self.xcanvas.Bind(wx.EVT_LEFT_DOWN, self._setCanvasPosition) self.xcanvas.Bind(wx.EVT_LEFT_DOWN, self._setCanvasPosition)
...@@ -287,7 +115,9 @@ class ImageView(wx.Panel): ...@@ -287,7 +115,9 @@ class ImageView(wx.Panel):
""" """
Called on mouse movement and left clicks. The currently Called on mouse movement and left clicks. The currently
displayed slices and cursor positions on each of the displayed slices and cursor positions on each of the
canvases follow mouse clicks and drags. canvases follow mouse clicks and drags, and an
EVT_LOCATION_EVENT is emitted when the cursor position
changes.
""" """
if not ev.LeftIsDown(): return if not ev.LeftIsDown(): return
...@@ -336,33 +166,36 @@ class ImageView(wx.Panel): ...@@ -336,33 +166,36 @@ class ImageView(wx.Panel):
wx.PostEvent(self, evt) wx.PostEvent(self, evt)
class ImageFrame(wx.Frame): class OrthoFrame(wx.Frame):
""" """
Convenience class for displaying a collection of images in a standalone Convenience class for displaying an OrthoPanel in a standalone window.
window.
""" """
def __init__(self, parent, imageList, title=None): def __init__(self, parent, imageList, title=None):
wx.Frame.__init__(self, parent, title=title) wx.Frame.__init__(self, parent, title=title)
self.panel = OrthoPanel(self, imageList)
self.panel = ImageView(self, imageList)
self.Layout() self.Layout()
if __name__ == '__main__': def main():
"""
Test program, displays the image specified on the command line.
"""
if len(sys.argv) < 2: if len(sys.argv) != 2:
print 'usage: imageview.py filename [filename]' print 'usage: orthopanel.py filename'
sys.exit(1) sys.exit(1)
app = wx.App() app = wx.App()
images = map(fslimage.Image, sys.argv[1:]) image = fslimage.Image(sys.argv[1])
imageList = fslimage.ImageList(images) imageList = fslimage.ImageList([image])
frame = ImageFrame( frame = OrthoFrame(None, imageList, title=sys.argv[1])
None,
imageList,
title=sys.argv[1])
frame.Show() frame.Show()
app.MainLoop() app.MainLoop()
if __name__ == '__main__':
main()
File moved
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment