diff --git a/LICENSE b/LICENSE index b917f865b788f82c5a821c63ba3d9a11dcf3cfb3..d9e2e43b582ad60a868d009bd3b48d755c7677a0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -fslpy library, 2014, The University of Oxford (the "Software") +FSLeyes, (c) 2016, The University of Oxford (the "Software") The Software remains the property of the University of Oxford ("the University"). diff --git a/fsl/data/strings.py b/fsl/data/strings.py index 0f5aee7135d6c3beeb1fc1b071c9fdccb25445a7..11a892c760ae26c5dc069340a3041f877a607f39 100644 --- a/fsl/data/strings.py +++ b/fsl/data/strings.py @@ -19,14 +19,17 @@ into the following categories: :data:`labels` Labels for miscellaneous things. :data:`properties` Display names for ``props.HasProperties`` properties. :data:`choices` Display names for ``props.HasProperties`` choice - properties. + properties. :data:`anatomy` Anatomical and orientation labels. :data:`nifti` Labels for NIFTI header fields. :data:`feat` FEAT specific names and labels. + :data:`about` Strings used in the *FSLeyes* about dialog. ================== ===================================================== """ +import textwrap + from fsl.utils.typedict import TypeDict import fsl.data.constants as constants @@ -257,6 +260,7 @@ actions = TypeDict({ 'SavePerspectiveAction' : 'Save current perspective', 'ClearPerspectiveAction' : 'Clear all perspectives', 'DiagnosticReportAction' : 'Diagnostic report', + 'AboutAction' : 'About FSLeyes', 'FSLEyesFrame.closeViewPanel' : 'Close', @@ -900,3 +904,42 @@ tensor = { 'l2' : 'Second eigenvalue image', 'l3' : 'Third eigenvalue image', } + + +about = { + 'title' : 'About FSLeyes', + 'author' : 'Paul McCarthy', + 'email' : 'paulmc@fmrib.ox.ac.uk', + 'company' : u'\u00A9 FMRIB Centre, Oxford, UK', + 'version' : 'FSLeyes version: {}', + 'glVersion' : 'OpenGL version: {}', + 'glRenderer' : 'OpenGL renderer: {}', + 'software' : textwrap.dedent( + """ + FSLeyes was developed at the FMRIB Centre, Nuffield Department of Clinical Neurosciences, Oxford University, United Kingdom. + + FSLeyes is a Python application which leverages the following open-source software libraries: + + - jinja2 [{}] (http://jinja.pocoo.org) + - matplotlib [{}] (http://www.matplotlib.org) + - nibabel [{}] (http://nipy.org/nibabel) + - numpy [{}] (http://www.numpy.org) + - pillow [{}] (http://python-pillow.org/) + - props [{}] (https://git.fmrib.ox.ac.uk/paulmc/props) + - pyopengl [{}] (http://pyopengl.sourceforge.net) + - pyparsing [{}] (http://pyparsing.wikispaces.com/) + - scipy [{}] (http://www.scipy.org) + - wxPython [{}] (http://www.wxpython.org) + + Some of the icons used in FSLeyes are derived from the Freeline icon set, by Enes Dal, available at https://www.iconfinder.com/Enesdal, and released under the Creative Commons (Attribution 3.0 Unported) license. + """).strip(), + + # This is a list of all the libraries listed + # in the software string above - the AboutDialog + # dynamically looks up the version number for + # each of them, and inserts them into the above + # string. + 'libs' : ['jinja2', 'matplotlib', 'nibabel', 'numpy', + 'PIL', 'props', 'OpenGL', 'pyparsing', + 'scipy', 'wx'], +} diff --git a/fsl/fsleyes/about.py b/fsl/fsleyes/about.py new file mode 100644 index 0000000000000000000000000000000000000000..49a31bd675d0f9d11f41b359a6ce61009f033c05 --- /dev/null +++ b/fsl/fsleyes/about.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python +# +# about.py - The AboutDialog class. +# +# Author: Paul McCarthy <pauldmccarthy@gmail.com> +# +"""This module provides the :class:`.AboutDialog` class, a dialog which +displays information about *FSLeyes*. +""" + + +import os.path as op + +import wx +import OpenGL.GL as gl + +import fsl.fsleyes.widgets.imagepanel as imagepanel +import fsl.data.strings as strings +import fsl.version as version + + +class AboutDialog(wx.Dialog): + """The ``AboutDialog`` is a dialog which displays information about + *FSLeyes*. + """ + + def __init__(self, parent): + """Create an ``AboutDialog``. + + :arg parent: ``wx`` parent object. + """ + wx.Dialog.__init__(self, parent, title=strings.about['title']) + + # Load the splash screen + splashfile = op.join(op.dirname(__file__), + 'icons', 'splash', 'splash.png') + splashbmp = wx.Bitmap(splashfile, wx.BITMAP_TYPE_PNG) + splashimg = splashbmp.ConvertToImage() + + # Create all the widgets + splashPanel = imagepanel.ImagePanel(self, splashimg) + authorLabel = wx.StaticText(self) + emailLabel = wx.StaticText(self) + companyLabel = wx.StaticText(self) + versionLabel = wx.StaticText(self) + glVersionLabel = wx.StaticText(self) + glRendererLabel = wx.StaticText(self) + softwareField = wx.TextCtrl( self, + size=(-1, 200), + style=(wx.TE_LEFT | + wx.TE_RICH | + wx.TE_MULTILINE | + wx.TE_READONLY | + wx.TE_AUTO_URL)) + closeButton = wx.Button( self, id=wx.ID_CANCEL) + + # Set foreground/background colours + objs = [self, + authorLabel, + emailLabel, + companyLabel, + versionLabel, + glVersionLabel, + glRendererLabel, + softwareField] + + for obj in objs: + obj.SetBackgroundColour('#000000') + obj.SetForegroundColour('#ffffff') + + softwareField.SetDefaultStyle(wx.TextAttr('#ffffff', wx.NullColour)) + + # Create / retrieve all the content + verStr = version.__version__ + glVerStr = gl.glGetString(gl.GL_VERSION) + glRenStr = gl.glGetString(gl.GL_RENDERER) + swlibs = strings.about['libs'] + + swVersions = [] + for lib in swlibs: + + try: + mod = __import__(lib) + if lib == 'PIL': + swVer = str(mod.PILLOW_VERSION) + else: + swVer = str(mod.__version__) + except: + swVer = '' + + swVersions.append(swVer) + + verStr = strings.about['version'] .format(verStr) + glVerStr = strings.about['glVersion'] .format(glVerStr) + glRenStr = strings.about['glRenderer'].format(glRenStr) + swStr = strings.about['software'] .format(*swVersions) + + # Tack the license file contents onto + # the end of the software description. + licenseFile = op.join(op.dirname(__file__), + '..', '..', 'LICENSE') + try: + with open(licenseFile, 'rt') as f: + licenseStr = f.read() + except: + licenseStr = '' + + swStr = swStr + '\n\n' + licenseStr + swStr = swStr.strip() + + # Set the widget content + authorLabel .SetLabel(strings.about['author']) + emailLabel .SetLabel(strings.about['email']) + companyLabel .SetLabel(strings.about['company']) + versionLabel .SetLabel(verStr) + glVersionLabel .SetLabel(glVerStr) + glRendererLabel.SetLabel(glRenStr) + softwareField .SetValue(swStr) + closeButton .SetLabel('Close') + + # Arrange the widgets + mainSizer = wx.BoxSizer(wx.VERTICAL) + row1Sizer = wx.BoxSizer(wx.HORIZONTAL) + row2Sizer = wx.BoxSizer(wx.HORIZONTAL) + row3Sizer = wx.BoxSizer(wx.HORIZONTAL) + row4Sizer = wx.BoxSizer(wx.HORIZONTAL) + + row1Sizer.Add(versionLabel, flag=wx.EXPAND) + row1Sizer.Add((1, 1), flag=wx.EXPAND, proportion=1) + row1Sizer.Add(authorLabel, flag=wx.EXPAND) + + row2Sizer.Add(companyLabel, flag=wx.EXPAND) + row2Sizer.Add((1, 1), flag=wx.EXPAND, proportion=1) + row2Sizer.Add(emailLabel, flag=wx.EXPAND) + + row3Sizer.Add(glVersionLabel, flag=wx.EXPAND) + row3Sizer.Add((1, 1), flag=wx.EXPAND, proportion=1) + + row4Sizer.Add(glRendererLabel, flag=wx.EXPAND) + row4Sizer.Add((1, 1), flag=wx.EXPAND, proportion=1) + + rowargs = {'border' : 3, + 'flag' : wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM} + + mainSizer.Add(splashPanel) + mainSizer.Add(row1Sizer, **rowargs) + mainSizer.Add(row2Sizer, **rowargs) + mainSizer.Add(row3Sizer, **rowargs) + mainSizer.Add(row4Sizer, **rowargs) + mainSizer.Add(softwareField, flag=wx.EXPAND, proportion=1) + mainSizer.Add(closeButton, flag=wx.EXPAND) + + self.SetSizer(mainSizer) + self.Layout() + self.Fit() diff --git a/fsl/fsleyes/actions/__init__.py b/fsl/fsleyes/actions/__init__.py index 3fb2b45823f4b6d97c0175776b857a22b20ed4ab..8d128acd88e40c084d5dcdf687ee13fe4b4c2e4e 100644 --- a/fsl/fsleyes/actions/__init__.py +++ b/fsl/fsleyes/actions/__init__.py @@ -108,6 +108,7 @@ Finally, some 'global' actions are also provided in this package: ~fsl.fsleyes.actions.clearperspective ~fsl.fsleyes.actions.togglecontrolpanel ~fsl.fsleyes.actions.diagnosticreport + ~fsl.fsleyes.actions.about """ @@ -135,6 +136,7 @@ import loadperspective import clearperspective import togglecontrolpanel import diagnosticreport +import about Action = action .Action @@ -153,6 +155,7 @@ LoadPerspectiveAction = loadperspective .LoadPerspectiveAction ClearPerspectiveAction = clearperspective .ClearPerspectiveAction ToggleControlPanelAction = togglecontrolpanel.ToggleControlPanelAction DiagnosticReportAction = diagnosticreport .DiagnosticReportAction +AboutAction = about .AboutAction log = logging.getLogger(__name__) diff --git a/fsl/fsleyes/actions/about.py b/fsl/fsleyes/actions/about.py new file mode 100644 index 0000000000000000000000000000000000000000..651e241ca32e421bbeb494a8fda9a2f14000a085 --- /dev/null +++ b/fsl/fsleyes/actions/about.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# +# about.py - The AboutAction class. +# +# Author: Paul McCarthy <pauldmccarthy@gmail.com> +# +"""This module provides the :class:`.AboutAction` class, an action which +displays an about dialog for *FSLeyes*. +""" + + +import action +import fsl.fsleyes.about as aboutdlg + + +class AboutAction(action.Action): + """The ``AboutAction`` class is an action which displays an + :class:`.AboutDialog`, containing information about *FSLeyes*. + """ + + def __init__(self, overlayList, displayCtx, frame): + """Create an ``AboutAction``. + + :arg overlayList: The :class:`.OverlayList`. + :arg displayCtx: The master :class:`.DisplayContext`. + :arg frame: The :class:`.FSLEyesFrame`. + """ + + action.Action.__init__(self, self.__showDialog) + + self.__frame = frame + self.__overlayList = overlayList + self.__displayCtx = displayCtx + + + def __showDialog(self): + """Creates and shows an :class:`.AboutDialog`. """ + + dlg = aboutdlg.AboutDialog(self.__frame) + dlg.Show() + dlg.CentreOnParent() diff --git a/fsl/fsleyes/icons/splash/splash.png b/fsl/fsleyes/icons/splash/splash.png index bfff2a38c58ca2203c5d8d06c932a00507fc4f88..9b01fb2e575a4be3ea8fc9ca9bed9e35d9c3f71a 100644 Binary files a/fsl/fsleyes/icons/splash/splash.png and b/fsl/fsleyes/icons/splash/splash.png differ diff --git a/fsl/fsleyes/icons/splash/splash.xcf b/fsl/fsleyes/icons/splash/splash.xcf index b323b7edcb393cce8ad87cccad0add073865b253..14d491e4bb34878bd2ac2baa1dfd3f3dae27350e 100644 Binary files a/fsl/fsleyes/icons/splash/splash.xcf and b/fsl/fsleyes/icons/splash/splash.xcf differ diff --git a/fsl/tools/fsleyes.py b/fsl/tools/fsleyes.py index cadb92488b5fd675f7f0b0fe5b36076206224316..edc8fd4a35707d410dfd48b9aab8f4852670e040 100644 --- a/fsl/tools/fsleyes.py +++ b/fsl/tools/fsleyes.py @@ -266,6 +266,15 @@ def diagnosticReport(frame, ctx): import fsl.fsleyes.actions as actions actions.DiagnosticReportAction(overlayList, displayCtx, frame)() + +def about(frame, ctx): + """Set as a ``FSL_ACTION`` (see the :mod:`.tools` documentation). + Creates and calls an :class:`.AboutAction`. + """ + overlayList, displayCtx, _ = ctx + import fsl.fsleyes.actions as actions + actions.AboutAction(overlayList, displayCtx, frame)() + ############################################# # See the fsl.tools package documentation for @@ -277,4 +286,5 @@ FSL_TOOLNAME = 'FSLeyes' FSL_INTERFACE = interface FSL_CONTEXT = context FSL_PARSEARGS = parseArgs -FSL_ACTIONS = [(strings.actions['DiagnosticReportAction'], diagnosticReport)] +FSL_ACTIONS = [(strings.actions['AboutAction'], about), + (strings.actions['DiagnosticReportAction'], diagnosticReport)]