Commit db1e85f4 authored by Taylor Hanayik's avatar Taylor Hanayik
Browse files

starting to switch to buildGUI from json or dict

parent d0948650
"""
core functions for setting up and controlling GUIs
"""
import os
import sys
import json
import wx
import fsleyes_props as props
import fsl.gui.exceptions as fslerrs
import fsl.gui.views as fslviews
keyToWidgetMap = {
'column' : fslviews.Column,
'row' : fslviews.Row,
'filePicker' : wx.TextCtrl,
'checkBox' : wx.CheckBox,
}
allowedWidgets = (keyToWidgetMap.keys())
allowedContainerWidgets = (
'column', 'row',
)
allowedConfigKeys = (
'appName', 'windowSize', 'width', 'height',
)
allowedKeys = (
*allowedConfigKeys,
*allowedWidgets,
)
def checkSpec(buildSpec):
"""
make sure the build spec contains only expected fields
"""
def dictCheck(d):
for k, v in d.items():
if k not in allowedKeys:
raise fslerrs.NotAValidKey("{} is not an allowed buildSpec key".format(k))
if type(v) is dict:
dictCheck(v)
dictCheck(buildSpec)
def widgetFromKey(key):
"""
return an appropriate widget for a given key
"""
if key in keyToWidgetMap:
return keyToWidgetMap[key]
else:
raise fslerrs.NotAValidKey("{} is not an allowed buildSpec key".format(key))
def _layout_from(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
def layout(buildSpec, parent):
"""
layout all allowed widgets in a buildSpec
"""
for k, v in buildSpec.items():
if k in allowedWidgets:
print("adding widget: ", k)
_ = widgetFromKey(k)
if type(v) is dict:
w = _(parent, **v)
else:
w = _(parent)
parent.GetSizer().Add(w, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
_layout_from(w)
if k in allowedContainerWidgets:
if type(v) is list:
for widget in v:
layout(widget, w)
return parent
def buildGUI(buildSpec):
"""
build a GUI from a build spec dictionary (or JSON)
"""
checkSpec(buildSpec)
app = wx.App()
mainWin = wx.Frame(None)
mainWin.SetTitle(buildSpec['appName'])
mainWin.SetSize((buildSpec['windowSize']['width'], buildSpec['windowSize']['height']))
mainSizer = wx.BoxSizer(wx.VERTICAL)
mainWin.SetSizer(mainSizer)
mainWin = layout(buildSpec, mainWin)
mainWin.Centre()
mainWin.Show()
return mainWin
"""
custom exceptions to be used in fslgui
"""
class NotAValidKey(Exception):
pass
......@@ -9,6 +9,9 @@ import random
import wx
from fsl.data import image
import fsleyes_props as props
#from fsleyes_props.build import buildGUI
props.initGUI()
import fsl.gui.views as fslviews
import fsl.gui.tools as fsltools
......@@ -210,4 +213,64 @@ class FlirtGui(BaseGui):
else:
self.view.input.set_label("Input image*")
self.view.input_lowres.Hide()
self._layout_from(self.view.input_lowres)
\ No newline at end of file
self._layout_from(self.view.input_lowres)
class PnmGui(BaseGui):
"""
The PnmGui is the controller for the PnmView that
can interact with the Pnm model
"""
labels = {
'physioFile' : 'Physio file',
'imgVolume' : 'Image data (4D)',
'sliceOrder' : 'Volume slice order',
'sliceDir' : 'Slice direction',
'idxCardiac' : 'Cardiac Column #',
'idxResp' : 'Resp Column #',
'idxTrig' : 'Trig Column #'
}
def __init__(self, parent, title="PNM", data=None):
super().__init__()
if data is None:
self.data = fsltools.Pnm(slice_order='up')
self.view = self._make_view(parent)
def _make_view(self, parent):
"""
make a view made up of wx widgets
"""
view = wx.Panel(parent)
sizer = wx.BoxSizer(wx.VERTICAL)
inputFiles = props.buildGUI(view, self.data,
view=props.VGroup(
children=(
props.Widget('physioFile'),
props.Widget('imgVolume'),
),
border=False),
labels=self.labels)
sizer.Add(inputFiles, proportion=0, flag= wx.ALL | wx.EXPAND, border=5)
physioIds = props.buildGUI(view, self.data,
view=props.HGroup(
children=(
props.Widget('idxCardiac'),
props.Widget('idxResp'),
props.Widget('idxTrig'),
),
border=False,),
labels=self.labels)
sizer.Add(physioIds, proportion=0, flag= wx.ALL | wx.EXPAND, border=5)
#TODO add next PNM sections. Make it similar to existing PNM gui
# set the sizer last
view.SetSizer(sizer)
return view
#!/usr/bin/env python
import sys
#from fsl.gui.guis import PnmGui
import argparse
import wx
import fsl.gui.core as guiCore
import fsl.gui.views as fslviews
def main():
# get an app instance
app = wx.App()
gui = guiCore.buildGUI(fslviews.PnmView)
"""
frame = wx.Frame(None, size=(800, 600), title="PNM")
sizer = wx.BoxSizer(wx.VERTICAL)
pnm_gui = PnmGui(frame, "PNM")
sizer.Add(pnm_gui.view, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
frame.SetSizer(sizer)
frame.Centre()
frame.Show()
"""
app.MainLoop()
if __name__ == "__main__":
sys.exit(main())
......@@ -8,9 +8,11 @@ tools are models that store data and allow FSL tools to be called from other pyt
# Author: Taylor Hanayik <hanayik@gmail.com>
import os
import subprocess
from collections import OrderedDict
from fsl.utils import idle
from fsl.utils import idle
import fsleyes_props as props
class Bet(object):
......@@ -318,3 +320,38 @@ class Flirt(object):
search_zmax=90
):
pass
class Pnm(props.HasProperties):
"""
Pnm is the data model for PnmGui
"""
physioFile = props.FilePath(required=True, exists=True)
imgVolume = props.FilePath(required=True, exists=True)
sliceOrderChoices = OrderedDict((
('up', 'Up'),
('down', 'Down'),
('iup', 'Interleaved Up'),
('idown', 'Interleaved Down'),
('file', 'User Specified File')
))
scannerSliceDirChoices = OrderedDict((
('x', 'X'),
('y', 'Y'),
('z', 'Z')
))
sliceOrder = props.Choice(choices=list(sliceOrderChoices.keys()))
sliceDir = props.Choice(choices=list(scannerSliceDirChoices.keys()))
idxCardiac = props.Int(minval=0, slider=False)
idxResp = props.Int(minval=0, slider=False)
idxTrig = props.Int(minval=0, slider=False)
def __init__(
self,
**kwargs
):
super().__init__(**kwargs)
#!/usr/bin/env python
#
# bet_view.py
#
# Author: Taylor Hanayik <hanayik@gmail.com>
"""
views are the graphical layouts of windows.
User interaction is controlled by guis.py.
Data is stored and updated using tools.py
Author: Taylor Hanayik, hanayik@gmail.com
"""
import wx
import wx.lib.scrolledpanel as scrolled
......@@ -201,7 +210,7 @@ class BetView(wx.Panel):
self.SetSizer(sizer)
class PnmView(wx.Panel):
class NotUsedPnmView(wx.Panel):
"""
PnmView defines the graphical layout of widgets for the PNM gui
"""
......@@ -209,6 +218,15 @@ class PnmView(wx.Panel):
super().__init__(parent)
sizer = wx.BoxSizer(wx.VERTICAL)
# init title panel
self.title_panel = fslwidgets.Title(self, title=title)
# add title panel
sizer.Add(self.title_panel, proportion=0, flag=wx.ALIGN_CENTER | wx.ALL, border=5)
#
# lastly set the sizer with all widgets added
self.SetSizer(sizer)
class FlirtView(wx.Panel):
"""
......@@ -240,7 +258,7 @@ class FlirtView(wx.Panel):
self.input_lowres = fslwidgets.Input(self).set_label("Low res image*")
sizer.Add(self.input_lowres, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
self.input_lowres.Hide()
# high res input panel
self.input = fslwidgets.Input(self).set_label("Input image*")
sizer.Add(self.input, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
......@@ -259,12 +277,53 @@ class FlirtView(wx.Panel):
# lastly set the sizer with all widgets added
self.SetSizer(sizer)
PnmView={
'appName': 'PNM',
'windowSize':
{
'width': 800,
'height' : 600
},
'column' :
[
{'filePicker' : {'value' : 'Physio file'}},
{'filePicker' :{'value' : 'Image volume (4D)'}},
{'row' :
[
{'checkBox' : {'label' : 'one'}},
{'checkBox' :{'label' : 'two'}},
]
},
],
'row' :
[
{'checkBox' : {'label' : 'three'}},
{'checkBox' :{'label' : 'four'}},
]
}
class Column(wx.Panel):
"""
a wx.Panel with a vertical sizer
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.SetSizer(wx.BoxSizer(wx.VERTICAL))
class Row(wx.Panel):
"""
a wx.Panel with a horizontal sizer
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.SetSizer(wx.BoxSizer(wx.HORIZONTAL))
class FslView():
"""
FslView is the main FSL start window. not to be
confused with the deprecated image viewer fslview (RIP)
"""
......@@ -28,7 +28,8 @@ setup(
entry_points={
'console_scripts' : [
'bet_gui = fsl.gui.scripts.bet_gui:main',
'flirt_gui = fsl.gui.scripts.flirt_gui:main'
'flirt_gui = fsl.gui.scripts.flirt_gui:main',
'pnm_gui = fsl.gui.scripts.pnm_gui:main'
]
},
package_data={
......
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