Commit 57dda55d authored by Taylor Hanayik's avatar Taylor Hanayik
Browse files

update fsleyes embed and cleanup

parent ff34e0c6
......@@ -176,7 +176,7 @@ def makeWidget(parent, propObj, key, tag, value):
"""
if key in allowedWidgets:
wid = widgetFromKey(key)
# print('making widget: ', key)
print('making widget: ', key)
if isinstance(value, dict):
w = wid(parent, propObj, **value)
else:
......@@ -210,6 +210,10 @@ def layout(parent, buildSpec, propObj):
return parent
def onClose(event):
wx.GetApp().ExitMainLoop()
def buildGUI(buildSpec, propObj):
"""
build a GUI from a build spec dictionary (or JSON)
......@@ -226,6 +230,7 @@ def buildGUI(buildSpec, propObj):
mainWin.Centre()
mainWin.Show()
mainWin.Bind(wx.EVT_CLOSE, onClose)
return mainWin
......@@ -233,3 +238,4 @@ def buildGUI(buildSpec, propObj):
......@@ -14,6 +14,7 @@ import fsleyes.profiles as profiles
import fsleyes.profiles.profilemap as profilemap
import fsleyes.colourmaps as colourmaps
import fsleyes_props as props
from fsleyes.main import embed
from fsl.utils.platform import platform as fslplatform
from fsl.utils import idle
......@@ -139,342 +140,68 @@ def choice(parent, propobj, **kwargs):
def _embed(parent=None, make_fsleyesframe=True, **kwargs):
"""Initialise FSLeyes and create a :class:`.FSLeyesFrame`, when
running within another application.
# def _embed(parent=None, make_fsleyesframe=True, **kwargs):
# """Initialise FSLeyes and create a :class:`.FSLeyesFrame`, when
# running within another application.
.. note:: If a ``wx.App`` does not exist, one is created.
# .. note:: If a ``wx.App`` does not exist, one is created.
:arg parent: ``wx`` parent object
:arg make_fsleyesframe: bool, default is True to make a new :class:`.FSLeyesFrame`
:returns: A tuple containing:
- The :class:`.OverlayList`
- The master :class:`.DisplayContext`
- The :class:`.FSLeyesFrame` or None if make_fsleyesframe=False
# :arg parent: ``wx`` parent object
# :arg make_fsleyesframe: bool, default is True to make a new :class:`.FSLeyesFrame`
# :returns: A tuple containing:
# - The :class:`.OverlayList`
# - The master :class:`.DisplayContext`
# - The :class:`.FSLeyesFrame` or None if make_fsleyesframe=False
All other arguments are passed to :meth:`.FSLeyesFrame.__init__`.
"""
import fsleyes_props as props
import fsleyes.gl as fslgl
import fsleyes.frame as fslframe
import fsleyes.overlay as fsloverlay
import fsleyes.displaycontext as fsldc
app = wx.GetApp()
ownapp = app is None
if ownapp:
app = FSLeyesApp()
fsleyes.initialise()
colourmaps.init()
props.initGUI()
called = [False]
ret = [None]
def until():
return called[0]
def ready():
frame = None
fslgl.bootstrap()
overlayList = fsloverlay.OverlayList()
displayCtx = fsldc.DisplayContext(overlayList)
if make_fsleyesframe:
frame = fslframe.FSLeyesFrame(
parent, overlayList, displayCtx, **kwargs)
if ownapp:
app.SetOverlayListAndDisplayContext(overlayList, displayCtx)
# Keep a ref to prevent the app from being GC'd
if make_fsleyesframe:
frame._embed_app = app
called[0] = True
ret[0] = (overlayList, displayCtx, frame)
fslgl.getGLContext(parent=parent, ready=ready)
idle.block(10, until=until)
if ret[0] is None:
raise RuntimeError('Failed to start FSLeyes')
return ret[0]
def layout_from_deprecated(widget):
"""
redo layout of all widgets up the parent tree from this widget.
Stop when we get to a frame. This was taken from a wx wiki post
"""
while widget.GetParent():
widget = widget.GetParent()
widget.Layout()
if widget.IsTopLevel():
break
class FileDropTextCtrl(wx.FileDropTarget):
"""
Drop target specifically for wx.TextCtrl widgets.
It's specific because it expects window to have a SetValue method
"""
def __init__(self, window):
wx.FileDropTarget.__init__(self)
self.window = window
def OnDropFiles(self, x, y, filenames):
# only use the first file if multiple are dropped at once
self.window.SetValue(filenames[0])
return True
class Input(wx.Panel):
def __init__(self, parent, label="", show_remove=False):
wx.Panel.__init__(self, parent)
self.file_path = ""
#sizer = wx.StaticBoxSizer(wx.HORIZONTAL, self, "Input image*")
self.box = wx.StaticBox(self, label=label)
sizer = wx.StaticBoxSizer(self.box)
self.remove_button = wx.Button(self.box, label="Remove")
self.button = wx.Button(self.box, label="Choose")
if not show_remove:
self.remove_button.Hide()
self.file_ctrl = wx.TextCtrl(self.box, value="")
drop_target = FileDropTextCtrl(self.file_ctrl)
self.file_ctrl.SetDropTarget(drop_target)
sizer.Add(self.remove_button, proportion=0, flag=wx.ALL, border=5)
sizer.Add(self.file_ctrl, 1, wx.EXPAND | wx.ALL, 5)
sizer.Add(self.button, 0, wx.ALL, 5)
self.SetSizer(sizer)
self.button.Bind(wx.EVT_BUTTON, self._on_choose)
self.remove_button.Bind(wx.EVT_BUTTON, self._on_remove)
def set_label(self, text):
self.box.SetLabel(text)
layout_from(self.box)
return self
def set_text(self, text):
self.file_ctrl.SetValue(text)
return self
def get_path(self):
return self.file_ctrl.GetValue()
def _on_choose(self, event):
with wx.FileDialog(self, "Choose input file", style=wx.FD_OPEN) as fd:
if fd.ShowModal() == wx.ID_CANCEL:
return
self.file_path = os.path.abspath(fd.GetPath())
self.set_text(self.file_path)
def _on_remove(self, event):
self.Hide()
self.GetGrandParent().Layout()
self.Destroy()
class SecondaryImageInput(wx.Panel):
def __init__(self, parent, label=""):
wx.Panel.__init__(self, parent)
self.image_list = []
#sizer = wx.StaticBoxSizer(wx.HORIZONTAL, self, "Input image*")
self.box = wx.StaticBox(self, label=label)
sizer = wx.StaticBoxSizer(self.box, orient=wx.VERTICAL)
text_and_btn_panel = wx.Panel(self)
text_and_btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
st = wx.StaticText(text_and_btn_panel, label="Apply transform to secondary images")
st.SetToolTip("Secondary images MUST be in the same space as the first input image (or the low res image)")
add_btn = wx.Button(text_and_btn_panel, label="Add image")
text_and_btn_sizer.Add(st, proportion=0, flag=wx.ALL, border=5)
text_and_btn_sizer.Add(add_btn, proportion=0, flag=wx.ALL, border=5)
text_and_btn_panel.SetSizer(text_and_btn_sizer)
sizer.Add(text_and_btn_panel, proportion=0, flag=wx.ALL, border=5)
self.SetSizer(sizer)
# All other arguments are passed to :meth:`.FSLeyesFrame.__init__`.
# """
add_btn.Bind(wx.EVT_BUTTON, self._on_add)
def _on_add(self, event):
self.image_list.clear()
#TODO add input panels to a list to get input files from
new_input = Input(self, show_remove=True)
self.image_list.append(new_input)
self.GetSizer().Add(new_input, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
self.GetParent().Layout()
class ReferencePicker(wx.Panel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.file_path = ""
#sizer = wx.StaticBoxSizer(wx.HORIZONTAL, self, "Input image*")
self.box = wx.StaticBox(self, label="Reference image")
sizer = wx.StaticBoxSizer(self.box, orient=wx.VERTICAL)
input_panel = wx.Panel(self.box)
input_panel_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.choose_button = wx.Button(input_panel, label="Choose")
self.file_ctrl = wx.TextCtrl(input_panel, value="")
input_panel_sizer.Add(self.file_ctrl, 1, wx.EXPAND | wx.ALL, 5)
input_panel_sizer.Add(self.choose_button, 0, wx.ALL, 5)
input_panel.SetSizer(input_panel_sizer)
button_panel = wx.Panel(self.box)
button_panel_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.btn_1mm_brain = wx.Button(button_panel, label="standard_1mm_brain")
self.btn_2mm_brain = wx.Button(button_panel, label="standard_2mm_brain")
button_panel_sizer.Add(self.btn_1mm_brain, proportion=0, flag=wx.ALL, border=5)
button_panel_sizer.Add(self.btn_2mm_brain, proportion=0, flag=wx.ALL, border=5)
button_panel.SetSizer(button_panel_sizer)
sizer.Add(input_panel, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
sizer.Add(button_panel, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
self.SetSizer(sizer)
# import fsleyes_props as props
# import fsleyes.gl as fslgl
# import fsleyes.frame as fslframe
# import fsleyes.overlay as fsloverlay
# import fsleyes.displaycontext as fsldc
self.choose_button.Bind(wx.EVT_LEFT_UP, self._on_choose)
self.btn_1mm_brain.Bind(wx.EVT_LEFT_UP, self._on_1mm_brain)
self.btn_2mm_brain.Bind(wx.EVT_LEFT_UP, self._on_2mm_brain)
def set_label(self, text):
self.box.SetLabel(text)
layout_from(self.box)
return self
def set_text(self, text):
self.file_ctrl.SetValue(text)
return self
def get_path(self):
return self.file_ctrl.GetValue()
def _on_choose(self, event):
with wx.FileDialog(self, "Choose input file", style=wx.FD_OPEN) as fd:
if fd.ShowModal() == wx.ID_CANCEL:
return
self.file_path = os.path.abspath(fd.GetPath())
self.set_text(self.file_path)
def _on_1mm_brain(self, event):
self.file_path = os.path.join(
fslplatform.fsldir,
"data",
"standard",
"MNI152_T1_1mm_brain.nii.gz"
)
self.set_text(self.file_path)
def _on_2mm_brain(self, event):
self.file_path = os.path.join(
fslplatform.fsldir,
"data",
"standard",
"MNI152_T1_2mm_brain.nii.gz"
)
self.set_text(self.file_path)
class Output(wx.Panel):
def __init__(self, parent, label=""):
wx.Panel.__init__(self, parent)
self.file_path = ""
self.box = wx.StaticBox(self, label=label)
sizer = wx.StaticBoxSizer(self.box)
self.button = wx.Button(self.box, label="Set path")
self.file_ctrl = wx.TextCtrl(self.box, value="")
sizer.Add(self.file_ctrl, 1, wx.EXPAND | wx.ALL, 5)
sizer.Add(self.button, 0, wx.ALL, 5)
self.SetSizer(sizer)
# app = wx.GetApp()
# ownapp = app is None
# if ownapp:
# app = FSLeyesApp()
self.button.Bind(wx.EVT_LEFT_UP, self._on_choose)
# fsleyes.initialise()
# colourmaps.init()
# props.initGUI()
def set_label(self, text):
self.box.SetLabel(text)
layout_from(self.box)
return self
# called = [False]
# ret = [None]
def set_text(self, text):
self.file_ctrl.SetValue(text)
# def until():
# return called[0]
def get_path(self):
return self.file_ctrl.GetValue()
# def ready():
# frame = None
# fslgl.bootstrap()
def _on_choose(self, event):
with wx.DirDialog(None, message="Choose output directory", defaultPath=os.getcwd()) as dd:
if dd.ShowModal() == wx.ID_CANCEL:
return
self.file_path = os.path.abspath(dd.GetPath())
self.set_text(self.file_path)
# overlayList = fsloverlay.OverlayList()
# displayCtx = fsldc.DisplayContext(overlayList)
# if make_fsleyesframe:
# frame = fslframe.FSLeyesFrame(
# parent, overlayList, displayCtx, **kwargs)
# if ownapp:
# app.SetOverlayListAndDisplayContext(overlayList, displayCtx)
# # Keep a ref to prevent the app from being GC'd
# if make_fsleyesframe:
# frame._embed_app = app
class Title(wx.Panel):
def __init__(self, parent, title="", **kwargs):
super().__init__(parent, **kwargs)
self.SetMinSize((-1, 32))
self.SetMaxSize((-1, 32))
sizer = wx.BoxSizer(wx.VERTICAL)
self.title_text = wx.StaticText(parent=self, label=title)
self.title_text.SetFont(
wx.Font(
wx.FontInfo(16).Bold()
)
)
sizer.Add(
self.title_text,
1,
wx.ALIGN_CENTER | wx.ALL,
0)
self.SetSizer(sizer)
def set_text(self, new_text):
self.title_text.SetLabel(new_text)
self.Layout()
return self
# called[0] = True
# ret[0] = (overlayList, displayCtx, frame)
# fslgl.getGLContext(parent=parent, ready=ready)
# idle.block(10, until=until)
class ToolActionPanel(wx.Panel):
"""
A CardControlsPanel contains the action buttons related to the card.
"""
def __init__(self, parent):
super().__init__(parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL)
self.SetMinSize(wx.Size(-1, 38))
sizer = wx.BoxSizer(wx.HORIZONTAL)
#self.SetBackgroundColour(wx.Colour(255, 255, 255))
self.code_icon = wx.BitmapButton(
self,
wx.ID_ANY,
wx.Bitmap(
fslicons.icon_code, wx.BITMAP_TYPE_PNG
),
wx.DefaultPosition,
wx.DefaultSize,
)
sizer.Add(self.code_icon, 0, wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT, 4)
self.pause_icon = wx.BitmapButton(
self,
wx.ID_ANY,
wx.Bitmap(
fslicons.icon_pause, wx.BITMAP_TYPE_PNG
),
wx.DefaultPosition,
wx.DefaultSize,
)
sizer.Add(self.pause_icon, 0, wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT, 4)
self.play_icon = wx.BitmapButton(
self,
wx.ID_ANY,
wx.Bitmap(
fslicons.icon_play, wx.BITMAP_TYPE_PNG
),
wx.DefaultPosition,
wx.DefaultSize,
)
sizer.Add(self.play_icon, 0, wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT, 4)
self.SetSizer(sizer)
self.Layout()
# if ret[0] is None:
# raise RuntimeError('Failed to start FSLeyes')
# return ret[0]
......@@ -508,68 +235,10 @@ class ViewProfile(profiles.Profile):
profilemap.profiles[orthopanel.OrthoPanel].insert(0, 'minview')
profilemap.profileHandlers[orthopanel.OrthoPanel, 'minview'] = ViewProfile
# def nomenu(*a):
# pass
# FSLeyesFrame._FSLeyesFrame__makeMenuBar = nomenu
class OrthoView(wx.CollapsiblePane):
def __init__(self, parent, **kwargs):
super().__init__(parent, **kwargs)
pane = self.GetPane()
self.overlayList, masterDisplayCtx, _ = _embed(None, make_fsleyesframe=False)
self.displayCtx = fsldc.DisplayContext(self.overlayList, parent=masterDisplayCtx)
sizer = wx.BoxSizer(wx.VERTICAL)
self.op = orthopanel.OrthoPanel(
pane,
self.overlayList,
self.displayCtx,
None)
self.op.SetMinSize((-1, 300))
self.op.Show()
self.btn_fsleyes = wx.Button(pane, label="Open in FSLeyes")
sizer.Add(self.btn_fsleyes, proportion=0, flag=wx.ALL, border=5)
sizer.Add(self.op, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
pane.SetSizer(sizer)
# bind events
self.btn_fsleyes.Bind(wx.EVT_BUTTON, self.launch_fsleyes)
def _run_fsleyes(self):
imgs = [img.dataSource for img in self.overlayList]
# print([img.dataSource for img in self.overlayList])
cmd = [
os.path.join(fslplatform.fsldir, 'bin', 'fsleyes'),
" ".join(imgs)
]
subprocess.run(
" ".join(cmd),
shell=True,
check=True
)
def launch_fsleyes(self, event):
thread_id = idle.run(self._run_fsleyes)
def reset(self):
self.overlayList.clear()
def add_image(self, new_img):
img = fslimage.Image(new_img)
self.overlayList.append(img)
def add_mask(self, new_img):
img = fslimage.Image(new_img)
self.overlayList.append(img, cmap='red', alpha=30)
class FsleyesImage(wx.Panel):
def __init__(self, parent, propobj, **kwargs):
super().__init__(parent, **kwargs)
self.overlayList, masterDisplayCtx, _ = _embed(None, make_fsleyesframe=False)
self.overlayList, masterDisplayCtx, _ = embed(None, mkFrame=False)
self.displayCtx = fsldc.DisplayContext(self.overlayList, parent=masterDisplayCtx)
sizer = wx.BoxSizer(wx.VERTICAL)
......@@ -617,56 +286,3 @@ class FsleyesImage(wx.Panel):
def add_mask(self, new_img):
img = fslimage.Image(new_img)
self.overlayList.append(img, cmap='red', alpha=30)
# def fsleyesImage(parent, propobj, **kwargs):
# overlayList, masterDisplayCtx, _ = _embed(None, make_fsleyesframe=False)
# displayCtx = fsldc.DisplayContext(overlayList, parent=masterDisplayCtx)
# panel = wx.Panel(parent)
# sizer = wx.BoxSizer(wx.VERTICAL)
# op = orthopanel.OrthoPanel(
# panel,
# overlayList,
# displayCtx,
# None)
# op.SetMinSize((-1, 300))
# op.Show()
# btn_fsleyes = wx.Button(panel, label="Open in FSLeyes")
# sizer.Add(btn_fsleyes, proportion=0, flag=wx.ALL, border=5)
# sizer.Add(op, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
# panel.SetSizer(sizer)
# def _run_fsleyes():
# imgs = [img.dataSource for img in overlayList]
# cmd = [
# os.path.join(fslplatform.fsldir, 'bin', 'fsleyes'),
# " ".join(imgs)
# ]
# subprocess.run(
# " ".join(cmd),
# shell=True,
# check=True
# )
# def _launch_fsleyes(event):
# thread_id = idle.run(_run_fsleyes)
# def _reset():
# overlayList.clear()
# def _add_image(new_img, valid, context, name):
# img = fslimage.Image(new_img)
# overlayList.append(img)
# def _add_mask(new_img):
# img = fslimage.Image(new_img)
# overlayList.append(img, cmap='red', alpha=30)
# # bind events
# btn_fsleyes.Bind(wx.EVT_BUTTON, _launch_fsleyes)
# return panel
\ No newline at end of file
......@@ -10,7 +10,7 @@ pyparsing==2.*
scipy>=0.18
wxPython>=3.0.2.0
fslpy>=3.0.0
fsleyes>=0.32.3
fsleyes>=0.33.0
fsleyes-props>=1.6.7
fsleyes-widgets>=0.8.4
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment