diff --git a/.idea/pyforms.iml b/.idea/pyforms.iml
deleted file mode 100644
index 5554030..0000000
--- a/.idea/pyforms.iml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 53a74ef..1655be8 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@

If you find this project useful, please, do not forget to  it.
-
+
@@ -15,7 +15,7 @@ Pyforms is a Python 2.7.x and 3.x cross-enviroment framework to develop GUI appl
### It offers:
* A Python layer of Desktop forms, based on PyQt, OpenGL and other libraries.
* A Python layer that allow applications to run on Desktop GUI, Web and terminal without requiring code modifications.
-* A group of rules and methodologies that help the developer maintaining his code short, clean, reusable and readable.
+* A group of rules and methodologies that help the developer maintain short, clean, reusable and readable code.

@@ -35,6 +35,7 @@ Example of an application running in the Desktop, Web and Terminal enviroments:
## Examples of applications developed in Pyforms
* [Python Video Annotator](https://github.com/UmSenhorQualquer/pythonVideoAnnotator)
* [3D tracking analyser](https://github.com/UmSenhorQualquer/3D-tracking-analyser)
+* [PyBpod](http://pybpod.readthedocs.io)
## Documentation
@@ -82,7 +83,7 @@ class ComputerVisionAlgorithm(BaseWidget):
#Define the event that will be called when the run button is processed
self._runbutton.value = self.__runEvent
#Define the event called before showing the image in the player
- self._player.processFrame = self.__processFrame
+ self._player.process_frame_event = self.__process_frame
#Define the organization of the Form Controls
self._formset = [
@@ -99,7 +100,7 @@ class ComputerVisionAlgorithm(BaseWidget):
"""
self._player.value = self._videofile.value
- def __processFrame(self, frame):
+ def __process_frame(self, frame):
"""
Do some processing to the frame and return the result frame
"""
diff --git a/build_settings/win/build.bat b/build_settings/win/build.bat
deleted file mode 100644
index 13a4b27..0000000
--- a/build_settings/win/build.bat
+++ /dev/null
@@ -1,31 +0,0 @@
-@echo off
-
-setlocal enableextensions enabledelayedexpansion
-
-rem set /A PYTHON_VERSION=2
-
-IF /I "%PYTHON_VERSION%" EQU "2" (
- set "WINPYDIR=C:\Users\swp\Python\WinPython-32bit-2.7.10.3\python-2.7.10"
- set "WINPYVER=2.7.10.3"
-) ELSE (
- set "WINPYDIR=C:\WinPython\WinPython-64bit-3.5.3.0Qt5\python-3.5.3.amd64"
- set "WINPYVER=3.5.3.0Qt5"
-)
-
-set "HOME=%WINPYDIR%\..\settings"
-set "WINPYARCH=WIN32"
-
-set "PATH=%WINPYDIR%\Lib\site-packages\PyQt4;%WINPYDIR%\;%WINPYDIR%\DLLs;%WINPYDIR%\Scripts;%WINPYDIR%\..\tools;"
-
-rem keep nbextensions in Winpython directory, rather then %APPDATA% default
-set "JUPYTER_DATA_DIR=%WINPYDIR%\..\settings"
-
-set PROJECTNAME="pyforms"
-
-python --version
-
-pip uninstall -y %PROJECTNAME%
-pip install .
-pip show %PROJECTNAME%
-
-python setup.py sdist --formats=zip
\ No newline at end of file
diff --git a/docs/api-documentation/basewidget.md b/docs/api-documentation/basewidget.md
index 40918b1..a7ccf34 100644
--- a/docs/api-documentation/basewidget.md
+++ b/docs/api-documentation/basewidget.md
@@ -37,9 +37,9 @@ class SimpleExample(BaseWidget):
### \_\_init\_\_(title='Untitled', parent_win=None, win_flag=None)
-**title** - Title of the window.
-**parent_win** - Parent widget. If the win_flag is None and the parent parameters is set, then the flag_win will be QtCore.Qt.Dialog.
-**win_flag** - Window type flag. Type of Qt.WindowType.
+**title** - Title of the window.
+**parent_win** - Parent widget. If the win_flag is None and the parent parameters is set, then the flag_win will be QtCore.Qt.Dialog.
+**win_flag** - Window type flag. Type of Qt.WindowType.
## **Functions**
***************************
diff --git a/docs/api-documentation/controls.md b/docs/api-documentation/controls.md
index 477fc12..e9b296c 100644
--- a/docs/api-documentation/controls.md
+++ b/docs/api-documentation/controls.md
@@ -613,6 +613,13 @@ Returns a list of graphs objects.
The control may be used to select a file.
+### **Constructer**
+***************************
+
+#### \_\_init\_\_(label='', default='', helptext='', use_save_dialog=False)
+
+**use_save_dialog** - By default the control will select a file to be opened. If this flab is True The control will open a file to be created or updated.
+
### **Functions**
***************************
@@ -754,7 +761,7 @@ Returns the a specific cell from the QTableWidget.
#### data_changed_event(row, col, item)
-Called when any of list the content is updated.
+Called when any of content of the list is updated.
#### item_selection_changed_event()
@@ -775,6 +782,10 @@ Called on item item double click.
### **Properties**
***************************
+#### autoscroll
+
+Returns and sets the autoscroll flag. If True the ControlList will position the scroll automatically to a position where the new new added item will be visible.
+
#### horizontal_headers
Get and set the horizontal headers in the table list.
@@ -820,6 +831,42 @@ Returns and sets the readonly flag for the control.
+## ControlMatplotlib
+***************************
+
+
+
+
+
+### **Functions**
+***************************
+
+#### draw()
+
+Draw the graph.
+
+### **Properties**
+***************************
+
+#### value
+
+Sets and gets a function called to draw the graph. This functions receives a matplotlib figure as parameter.
+
+
+Usage:
+```python
+
+def on_draw(figure:
+ x = range(len(self.value))
+
+ axes = figure.add_subplot(111, projection='3d')
+ axes.clear();
+ pts = axes.scatter(x, x, x, c=x)
+ figure.colorbar(pts)
+
+
+obj.value = on_draw
+```
@@ -1210,6 +1257,11 @@ Append text to the bottom.
Returns and sets the readonly flag for the control.
+#### autoscroll
+
+Returns and sets the autoscroll flag. If True the ControlTextArea will scroll always the text to the bottom everytime a new text is added.
+
+
## ControlToolBox
***************************
diff --git a/docs/api-documentation/settings.md b/docs/api-documentation/settings.md
index d61cf7c..4424bd7 100644
--- a/docs/api-documentation/settings.md
+++ b/docs/api-documentation/settings.md
@@ -1,6 +1,6 @@
# Settings
-Pyforms is using the pysettings library to manage it settings.
+Pyforms is using the pyforms.utils.settings_manager library to manage it settings.
Here it is described some of the settings of the library.
diff --git a/docs/getting-started/multiple-windows.md b/docs/getting-started/multiple-windows.md
index 7212031..12c124a 100644
--- a/docs/getting-started/multiple-windows.md
+++ b/docs/getting-started/multiple-windows.md
@@ -67,8 +67,8 @@ This window should inherit from the BaseWidget and Person classes.
```python
import pyforms
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
from Person import Person
class PersonWindow(Person, BaseWidget):
@@ -111,7 +111,7 @@ This window should inherit from the BaseWidget and People classes.
```python
import pyforms
from pyforms import BaseWidget
-from pyforms.Controls import ControlList
+from pyforms.controls import ControlList
from People import People
from PersonWindow import PersonWindow
from AddMenuFuntionality import AddMenuFuntionality
@@ -179,7 +179,7 @@ The application will look like:
Instead of opening a new window everytime we want to add a new Person, we will change the Application to open the PersonWindow inside the PeopleWindow. For this we will use the ControlEmptyWidget.
```python
-from pyforms.Controls import ControlEmptyWidget
+from pyforms.controls import ControlEmptyWidget
...
def __init__(self):
@@ -205,7 +205,7 @@ from pyforms.Controls import ControlEmptyWidget
A DockWidget works like the EmptyWidget but can be detached or moved around the sides of the main Window.
```python
-from pyforms.Controls import ControlDockWidget
+from pyforms.controls import ControlDockWidget
...
def __init__(self):
diff --git a/docs/getting-started/run-terminal.md b/docs/getting-started/run-terminal.md
index 1d89a8a..38d7fd3 100644
--- a/docs/getting-started/run-terminal.md
+++ b/docs/getting-started/run-terminal.md
@@ -7,8 +7,8 @@ The next code produces this Window:
```python
import pyforms
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
from Person import Person
class PersonWindow(Person, BaseWidget):
diff --git a/docs/getting-started/the-basic.md b/docs/getting-started/the-basic.md
index a6a9013..fb0b632 100644
--- a/docs/getting-started/the-basic.md
+++ b/docs/getting-started/the-basic.md
@@ -16,8 +16,8 @@ Import the pyforms library, the BaseWidget and the Controls classes that you wil
```python
import pyforms
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
```
### Create your application class.
@@ -70,8 +70,8 @@ The final code should look like:
```python
import pyforms
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
class SimpleExample1(BaseWidget):
diff --git a/docs/index.md b/docs/index.md
index 62b5a5f..b5f5f46 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -14,9 +14,9 @@ Pyforms is a Python 2.7.x and 3.x cross-enviroment framework to develop GUI appl
### It offers
* A Python layer of Desktop forms, based on PyQt, OpenGL and other libraries.
* A Python layer that allow applications to run on Desktop GUI, Web and terminal without requiring code modifications.
-* A group of rules and methodologies that help the developer maintaining his code short, clean, reusable and readable.
+* A group of rules and methodologies that help the developer maintain short, clean, reusable and readable code.
-
+
Example of an application running in the Desktop, Web and Terminal enviroments:
@@ -28,35 +28,4 @@ Example of an application running in the Desktop, Web and Terminal enviroments:
Run in the terminal:
```bash
pip install pyforms
-```
-
-### Requirements
-
-* [setuptools] (https://pypi.python.org/pypi/setuptools)
-* [Python 2.7](https://www.python.org/download/releases/2.7/)
-* [pysettings](https://github.com/UmSenhorQualquer/pysettings.git)
-* [PyQt4](http://www.riverbankcomputing.co.uk/software/pyqt/download)
-* [PyOpenGL](http://pyopengl.sourceforge.net/) [Optional - Only used by some Controls]
-* [VisVis](https://code.google.com/p/visvis/) [Optional - Only used by some Controls]
-* [Numpy](http://www.numpy.org/) [Optional - Only used by some Controls]
-* [Python opencv](http://opencv.org/) [Optional - Only used by some Controls]
-
-
-### Ubuntu 14
-
-* setuptools: ```sudo apt-get install python-setuptools```
-* pysettings: ```sudo pip install git+https://github.com/UmSenhorQualquer/pysettings.git```
-* Opengl: ```sudo apt-get install python-opengl```
-* OpenCV: ```sudo apt-get install python-opencv```
-* PyQt4: ```sudo apt-get install pyqt4-dev-tools python-qt4```
-* PyQt4 OpenGL Widget [Optional]: ```sudo apt-get install python-qt4-gl```
-* Pyforms: ```sudo pip install pyforms```
-* VisVis: ```sudo pip install visvis```
-
-### Mac OSx
-
-* Install python and its tools using [Homebrew] (http://brew.sh)
-* [Scientific Python on Mac OS X 10.9+ with homebrew | Jörn's Blog](https://joernhees.de/blog/2014/02/25/scientific-python-on-mac-os-x-10-9-with-homebrew/)
-* [Installing scientific Python on Mac OS X | Lowin Data Company](http://www.lowindata.com/2013/installing-scientific-python-on-mac-os-x/)
-* run ```sudo python setup.py install```
-
+```
\ No newline at end of file
diff --git a/pyforms/Controls.py b/pyforms/Controls.py
deleted file mode 100644
index 9c33ed1..0000000
--- a/pyforms/Controls.py
+++ /dev/null
@@ -1,108 +0,0 @@
-from pyforms import conf
-import logging, traceback
-
-logger = logging.getLogger(__file__)
-
-if conf.PYFORMS_MODE in ['GUI', 'GUI-OPENCSP']:
-
- from pyforms.gui.Controls.ControlBase import ControlBase
- from pyforms.gui.Controls.ControlText import ControlText
- from pyforms.gui.Controls.ControlBoundingSlider import ControlBoundingSlider
- from pyforms.gui.Controls.ControlButton import ControlButton
- from pyforms.gui.Controls.ControlCheckBoxList import ControlCheckBoxList
- from pyforms.gui.Controls.ControlCheckBox import ControlCheckBox
- from pyforms.gui.Controls.ControlCombo import ControlCombo
- from pyforms.gui.Controls.ControlDir import ControlDir
- from pyforms.gui.Controls.ControlDockWidget import ControlDockWidget
- from pyforms.gui.Controls.ControlEmptyWidget import ControlEmptyWidget
- from pyforms.gui.Controls.ControlFile import ControlFile
- from pyforms.gui.Controls.ControlFilesTree import ControlFilesTree
- from pyforms.gui.Controls.ControlLabel import ControlLabel
- from pyforms.gui.Controls.ControlList import ControlList
- from pyforms.gui.Controls.ControlMdiArea import ControlMdiArea
- from pyforms.gui.Controls.ControlNumber import ControlNumber
-
- if conf.PYFORMS_MATPLOTLIB_ENABLED:
- try:
- from pyforms.gui.Controls.ControlMatplotlib import ControlMatplotlib
- except:
- logger.warning("Matplot lib not installed or not working properly")
- logger.warning(traceback.format_exc())
-
- if conf.PYFORMS_WEB_ENABLED:
- try:
- from pyforms.gui.Controls.ControlWeb import ControlWeb
- except:
- logger.warning("QtWebKit lib not installed or not working properly")
- logger.warning(traceback.format_exc())
-
- if conf.PYFORMS_GL_ENABLED:
- try:
- from pyforms.gui.Controls.ControlOpenGL import ControlOpenGL
- from pyforms.gui.Controls.ControlImage import ControlImage
- from pyforms.gui.Controls.ControlPlayer.ControlPlayer import ControlPlayer
- except:
- logger.warning("GL widgets or Opencv not installed")
- logger.warning(traceback.format_exc())
-
- from pyforms.gui.Controls.ControlProgress import ControlProgress
- from pyforms.gui.Controls.ControlSlider import ControlSlider
- from pyforms.gui.Controls.ControlTextArea import ControlTextArea
- from pyforms.gui.Controls.ControlToolBox import ControlToolBox
- from pyforms.gui.Controls.ControlTree import ControlTree
- from pyforms.gui.Controls.ControlTreeView import ControlTreeView
-
- if conf.PYFORMS_VISVIS_ENABLED:
- try:
- from pyforms.gui.Controls.ControlVisVis import ControlVisVis
- from pyforms.gui.Controls.ControlVisVisVolume import ControlVisVisVolume
- except:
- logger.warning("VisVis not installed")
- #logger.warning(traceback.format_exc())
-
- from pyforms.gui.Controls.ControlEventTimeline.ControlEventTimeline import ControlEventTimeline
- from pyforms.gui.Controls.ControlEventsGraph.ControlEventsGraph import ControlEventsGraph
-
- try:
- from pyforms.gui.Controls.ControlCodeEditor import ControlCodeEditor
- except:
- logger.debug("QScintilla2 not installed")
- logger.debug(traceback.format_exc())
-
-
-elif conf.PYFORMS_MODE in ['TERMINAL']:
-
- from pyforms.terminal.Controls.ControlBase import ControlBase
- from pyforms.terminal.Controls.ControlText import ControlText
- from pyforms.terminal.Controls.ControlButton import ControlButton
- from pyforms.terminal.Controls.ControlCheckBox import ControlCheckBox
- from pyforms.terminal.Controls.ControlCombo import ControlCombo
- from pyforms.terminal.Controls.ControlFile import ControlFile
- from pyforms.terminal.Controls.ControlDir import ControlDir
- from pyforms.terminal.Controls.ControlImage import ControlImage
- from pyforms.terminal.Controls.ControlSlider import ControlSlider
- from pyforms.terminal.Controls.ControlPlayer import ControlPlayer
- from pyforms.terminal.Controls.ControlNumber import ControlNumber
- from pyforms.terminal.Controls.ControlProgress import ControlProgress
-
-elif conf.PYFORMS_MODE in ['WEB']:
-
- from pyforms_web.web.Controls.ControlBase import ControlBase
- from pyforms_web.web.Controls.ControlText import ControlText
- from pyforms_web.web.Controls.ControlBoundingSlider import ControlBoundingSlider
- from pyforms_web.web.Controls.ControlDate import ControlDate
- from pyforms_web.web.Controls.ControlButton import ControlButton
- from pyforms_web.web.Controls.ControlCheckBox import ControlCheckBox
- from pyforms_web.web.Controls.ControlCombo import ControlCombo
- from pyforms_web.web.Controls.ControlDir import ControlDir
- from pyforms_web.web.Controls.ControlFile import ControlFile
- from pyforms_web.web.Controls.ControlImage import ControlImage
- from pyforms_web.web.Controls.ControlSlider import ControlSlider
- from pyforms_web.web.Controls.ControlPlayer import ControlPlayer
- from pyforms_web.web.Controls.ControlProgress import ControlProgress
- from pyforms_web.web.Controls.ControlVisVis import ControlVisVis
- from pyforms_web.web.Controls.ControlList import ControlList
- from pyforms_web.web.Controls.ControlLabel import ControlLabel
- from pyforms_web.web.Controls.ControlTimeout import ControlTimeout
- from pyforms_web.web.Controls.ControlEmptyWidget import ControlEmptyWidget
- from pyforms_web.web.Controls.ControlWorkflow import ControlWorkflow
diff --git a/pyforms/__init__.py b/pyforms/__init__.py
index 0c4aa63..ca64213 100644
--- a/pyforms/__init__.py
+++ b/pyforms/__init__.py
@@ -1,40 +1,38 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-import logging
-import loggingbootstrap
-from pysettings import conf
-conf += 'pyforms.settings'
+from pyforms.utils.settings_manager import conf
-__author__ = "Ricardo Ribeiro"
-__credits__ = ["Ricardo Ribeiro"]
-__license__ = "MIT"
-__version__ = '2.0.5'
-__maintainer__ = ["Ricardo Ribeiro", "Carlos Mão de Ferro"]
-__email__ = ["ricardojvr@gmail.com", "cajomferro@gmail.com"]
-__status__ = "Production"
+conf += 'pyforms.settings'
-logger = logging.getLogger(__name__)
+__author__ = "Ricardo Ribeiro"
+__credits__ = ["Ricardo Ribeiro"]
+__license__ = "MIT"
+__version__ = '3.0.1'
+__maintainer__ = ["Ricardo Ribeiro", "Carlos Mão de Ferro"]
+__email__ = ["ricardojvr@gmail.com", "cajomferro@gmail.com"]
+__status__ = "Production"
if conf.PYFORMS_MODE in ['GUI', 'GUI-OPENCSP']:
- from pyforms.gui import Controls
- from pyforms.gui.BaseWidget import BaseWidget
-
- if conf.PYFORMS_MODE in ['GUI-OPENCSP']:
- from pyforms.gui.appmanager import start_app
- else:
- from pyforms.gui.standaloneManager import start_app
+ from pyforms.gui import controls
+ from pyforms.gui.basewidget import BaseWidget
+ from pyforms.gui.appmanager import start_app
+ from pyforms.gui.basewidget import vsplitter, hsplitter
elif conf.PYFORMS_MODE in ['TERMINAL']:
- from pyforms.terminal import Controls
- from pyforms.terminal.BaseWidget import BaseWidget
+ from pyforms.terminal import controls
+ from pyforms.terminal.basewidget import BaseWidget
from pyforms.terminal.appmanager import start_app
elif conf.PYFORMS_MODE in ['WEB']:
- from pyforms_web.web import Controls
- from pyforms_web.web.BaseWidget import BaseWidget
+ from pyforms_web.web import controls
+ from pyforms_web.web.basewidget import BaseWidget, no_columns, segment
from pyforms_web.web.appmanager import start_app
+
+ from pyforms_web.web.django_pyforms.model_admin import ModelAdmin
+ from pyforms_web.web.django_pyforms.model_admin import ViewFormAdmin
+ from pyforms_web.web.django_pyforms.model_admin import EditFormAdmin
diff --git a/pyforms/controls.py b/pyforms/controls.py
new file mode 100644
index 0000000..b2d355a
--- /dev/null
+++ b/pyforms/controls.py
@@ -0,0 +1,109 @@
+from pyforms import conf
+
+if conf.PYFORMS_MODE=='GUI':
+ import logging, traceback; logger=logging.getLogger(__file__)
+
+ from pyforms.gui.controls.ControlBase import ControlBase
+ from pyforms.gui.controls.ControlText import ControlText
+ from pyforms.gui.controls.ControlBoundingSlider import ControlBoundingSlider
+ from pyforms.gui.controls.ControlButton import ControlButton
+ from pyforms.gui.controls.ControlToolButton import ControlToolButton
+ from pyforms.gui.controls.ControlCheckBoxList import ControlCheckBoxList
+ from pyforms.gui.controls.ControlCheckBox import ControlCheckBox
+ from pyforms.gui.controls.ControlCombo import ControlCombo
+ from pyforms.gui.controls.ControlDir import ControlDir
+ from pyforms.gui.controls.ControlDockWidget import ControlDockWidget
+ from pyforms.gui.controls.ControlEmptyWidget import ControlEmptyWidget
+ from pyforms.gui.controls.ControlFile import ControlFile
+ from pyforms.gui.controls.ControlFilesTree import ControlFilesTree
+ from pyforms.gui.controls.ControlLabel import ControlLabel
+ from pyforms.gui.controls.ControlList import ControlList
+ from pyforms.gui.controls.ControlMdiArea import ControlMdiArea
+ from pyforms.gui.controls.ControlNumber import ControlNumber
+ from pyforms.gui.controls.ControlProgress import ControlProgress
+ from pyforms.gui.controls.ControlSlider import ControlSlider
+ from pyforms.gui.controls.ControlTextArea import ControlTextArea
+ from pyforms.gui.controls.ControlToolBox import ControlToolBox
+ from pyforms.gui.controls.ControlTableView import ControlTableView
+ from pyforms.gui.controls.ControlTree import ControlTree
+ from pyforms.gui.controls.ControlTreeView import ControlTreeView
+ from pyforms.gui.controls.control_event_timeline.ControlEventTimeline import ControlEventTimeline
+ from pyforms.gui.controls.control_events_graph.ControlEventsGraph import ControlEventsGraph
+
+ if conf.PYFORMS_MATPLOTLIB_ENABLED:
+ try:
+ from pyforms.gui.controls.ControlMatplotlib import ControlMatplotlib
+ except Exception as e:
+ logger.warning("Matplot lib not installed or not working properly")
+ logger.error(e, exc_info=True)
+
+ if conf.PYFORMS_WEB_ENABLED:
+ try:
+ from pyforms.gui.controls.ControlWeb import ControlWeb
+ except Exception as e:
+ logger.warning("QtWebKit lib not installed or not working properly")
+ logger.error(e, exc_info=True)
+
+ if conf.PYFORMS_GL_ENABLED:
+ try:
+ from pyforms.gui.controls.ControlOpenGL import ControlOpenGL
+ from pyforms.gui.controls.ControlImage import ControlImage
+ from pyforms.gui.controls.control_player.ControlPlayer import ControlPlayer
+ except Exception as e:
+ logger.warning("GL widgets or Opencv is not installed")
+ logger.error(e, exc_info=True)
+
+ if conf.PYFORMS_VISVIS_ENABLED:
+ try:
+ from pyforms.gui.controls.ControlVisVis import ControlVisVis
+ from pyforms.gui.controls.ControlVisVisVolume import ControlVisVisVolume
+ except Exception as e:
+ logger.warning("VisVis not installed")
+ logger.error(e, exc_info=True)
+
+ if conf.PYFORMS_QSCINTILLA_ENABLED:
+ try:
+ from pyforms.gui.controls.ControlCodeEditor import ControlCodeEditor
+ except Exception as e:
+ logger.warning("QScintilla2 not installed")
+ logger.error(e, exc_info=True)
+
+
+elif conf.PYFORMS_MODE=='TERMINAL':
+
+ from pyforms.terminal.controls.ControlBase import ControlBase
+ from pyforms.terminal.controls.ControlBoundingSlider import ControlBoundingSlider
+ from pyforms.terminal.controls.ControlText import ControlText
+ from pyforms.terminal.controls.ControlButton import ControlButton
+ from pyforms.terminal.controls.ControlCheckBox import ControlCheckBox
+ from pyforms.terminal.controls.ControlCombo import ControlCombo
+ from pyforms.terminal.controls.ControlFile import ControlFile
+ from pyforms.terminal.controls.ControlDir import ControlDir
+ from pyforms.terminal.controls.ControlImage import ControlImage
+ from pyforms.terminal.controls.ControlSlider import ControlSlider
+ from pyforms.terminal.controls.ControlPlayer import ControlPlayer
+ from pyforms.terminal.controls.ControlNumber import ControlNumber
+ from pyforms.terminal.controls.ControlProgress import ControlProgress
+
+elif conf.PYFORMS_MODE=='WEB':
+
+ from pyforms_web.web.controls.ControlBase import ControlBase
+ from pyforms_web.web.controls.ControlText import ControlText
+ from pyforms_web.web.controls.ControlBoundingSlider import ControlBoundingSlider
+ from pyforms_web.web.controls.ControlDate import ControlDate
+ from pyforms_web.web.controls.ControlButton import ControlButton
+ from pyforms_web.web.controls.ControlCheckBox import ControlCheckBox
+ from pyforms_web.web.controls.ControlCombo import ControlCombo
+ from pyforms_web.web.controls.ControlDir import ControlDir
+ from pyforms_web.web.controls.ControlFile import ControlFile
+ from pyforms_web.web.controls.ControlImage import ControlImage
+ from pyforms_web.web.controls.ControlSlider import ControlSlider
+ from pyforms_web.web.controls.ControlPlayer import ControlPlayer
+ from pyforms_web.web.controls.ControlProgress import ControlProgress
+ from pyforms_web.web.controls.ControlVisVis import ControlVisVis
+ from pyforms_web.web.controls.ControlList import ControlList
+ from pyforms_web.web.controls.ControlLabel import ControlLabel
+ from pyforms_web.web.controls.ControlTimeout import ControlTimeout
+ from pyforms_web.web.controls.ControlEmptyWidget import ControlEmptyWidget
+ from pyforms_web.web.controls.ControlWorkflow import ControlWorkflow
+ from pyforms_web.web.controls.ControlPieChart import ControlPieChart
diff --git a/pyforms/dialogs.py b/pyforms/dialogs.py
index 84239d7..1d7c5f3 100644
--- a/pyforms/dialogs.py
+++ b/pyforms/dialogs.py
@@ -1,4 +1,8 @@
from pyforms import conf
-if conf.PYFORMS_MODE in ['GUI','GUI-OPENCSP']:
- from pyforms.gui.dialogs.csv_parser import CsvParserDialog
\ No newline at end of file
+if conf.PYFORMS_MODE=='GUI':
+ from pyforms.gui.dialogs.csv_parser import CsvParserDialog
+
+
+elif conf.PYFORMS_MODE in ['TERMINAL']:
+ class CsvParserDialog(object): pass
\ No newline at end of file
diff --git a/pyforms/gui/.DS_Store b/pyforms/gui/.DS_Store
new file mode 100644
index 0000000..e4da2b0
Binary files /dev/null and b/pyforms/gui/.DS_Store differ
diff --git a/pyforms/gui/BaseWidget.py b/pyforms/gui/BaseWidget.py
deleted file mode 100644
index 49678a1..0000000
--- a/pyforms/gui/BaseWidget.py
+++ /dev/null
@@ -1,492 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-
-import os
-import json
-import subprocess
-import time, sys
-from datetime import datetime, timedelta
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QFrame
- from PyQt5.QtWidgets import QVBoxLayout
- from PyQt5.QtWidgets import QTabWidget
- from PyQt5.QtWidgets import QSplitter
- from PyQt5.QtWidgets import QHBoxLayout
- from PyQt5.QtWidgets import QSpacerItem
- from PyQt5.QtWidgets import QSizePolicy
- from PyQt5.QtWidgets import QLabel
- from PyQt5.QtGui import QFont
- from PyQt5.QtWidgets import QFileDialog
- from PyQt5.QtWidgets import QApplication
- from PyQt5 import QtCore
-
-else:
- from PyQt4.QtGui import QFrame
- from PyQt4.QtGui import QVBoxLayout
- from PyQt4.QtGui import QTabWidget
- from PyQt4.QtGui import QSplitter
- from PyQt4.QtGui import QHBoxLayout
- from PyQt4.QtGui import QSpacerItem
- from PyQt4.QtGui import QSizePolicy
- from PyQt4.QtGui import QLabel
- from PyQt4.QtGui import QFont
- from PyQt4.QtGui import QFileDialog
- from PyQt4.QtGui import QApplication
- from PyQt4 import QtCore
-
-from pyforms.gui.Controls.ControlBase import ControlBase
-from pyforms.gui.Controls.ControlProgress import ControlProgress
-
-
-class BaseWidget(QFrame):
- """
- The class implements the most basic widget or window.
- """
-
- def __init__(self, title='Untitled', parent_win=None, win_flag=None):
- if parent_win is not None and win_flag is None: win_flag = QtCore.Qt.Dialog
-
- QFrame.__init__(self) if parent_win is None else QFrame.__init__(self, parent_win, win_flag)
-
- # self.setObjectName(self.__class__.__name__)
-
-
- layout = QVBoxLayout()
- self.setLayout(layout)
-
- if conf.PYFORMS_USE_QT5:
- layout.setContentsMargins(0,0,0,0)
- else:
- layout.setMargin(0)
-
- self.title = title
- self.has_progress = False
-
- self._mainmenu = []
- self._splitters = []
- self._tabs = []
- self._formset = None
- self._formLoaded = False
- self.uid = id(self)
-
- self.setAccessibleName('BaseWidget')
-
- ##########################################################################
- ############ FUNCTIONS ##################################################
- ##########################################################################
-
-
- def init_form(self):
- """
- Generate the module Form
- """
- if not self._formLoaded:
-
- if self.has_progress:
- self._progress = ControlProgress("Progress", 0, 100)
- self._progress.hide()
- if self._formset != None:
- self._formset += ['_progress']
-
- if self._formset is not None:
- control = self.generate_panel(self._formset)
- self.layout().addWidget(control)
- else:
- allparams = self.controls
- for key, param in allparams.items():
- param.parent = self
- param.name = key
- self.layout().addWidget(param.form)
- self._formLoaded = True
-
- def set_margin(self, margin):
- if conf.PYFORMS_USE_QT5:
- self.layout().setContentsMargins(margin,margin,margin,margin)
- else:
- self.layout().setMargin(margin)
-
-
- def generate_tabs(self, formsetdict):
- """
- Generate QTabWidget for the module form
- @param formset: Tab form configuration
- @type formset: dict
- """
- tabs = QTabWidget(self)
- for key, item in sorted(formsetdict.items()):
- ctrl = self.generate_panel(item)
- tabs.addTab(ctrl, key[key.find(':') + 1:])
- return tabs
-
- def generate_panel(self, formset):
- """
- Generate a panel for the module form with all the controls
- formset format example: [('_video', '_arenas', '_run'), {"Player":['_threshold', "_player", "=", "_results", "_query"], "Background image":[(' ', '_selectBackground', '_paintBackground'), '_image']}, "_progress"]
- tuple: will display the controls in the same horizontal line
- list: will display the controls in the same vertical line
- dict: will display the controls in a tab widget
- '||': will plit the controls in a horizontal line
- '=': will plit the controls in a vertical line
- @param formset: Form configuration
- @type formset: list
- """
- control = None
- if '=' in formset:
- control = QSplitter(QtCore.Qt.Vertical)
- tmp = list(formset)
- index = tmp.index('=')
- firstPanel = self.generate_panel(formset[0:index])
- secondPanel = self.generate_panel(formset[index + 1:])
- control.addWidget(firstPanel)
- control.addWidget(secondPanel)
- self._splitters.append(control)
- return control
- elif '||' in formset:
- control = QSplitter(QtCore.Qt.Horizontal)
- tmp = list(formset)
- rindex = lindex = index = tmp.index('||')
- rindex -= 1
- rindex += 2
- if isinstance(formset[lindex - 1], int):
- lindex = lindex - 1
- if len(formset) > rindex and isinstance(formset[index + 1], int):
- rindex += 1
- firstPanel = self.generate_panel(formset[0:lindex])
- secondPanel = self.generate_panel(formset[rindex:])
- if isinstance(formset[index - 1], int):
- firstPanel.setMaximumWidth(formset[index - 1])
- if isinstance(formset[index + 1], int):
- secondPanel.setMaximumWidth(formset[index + 1])
- control.addWidget(firstPanel)
- control.addWidget(secondPanel)
- self._splitters.append(control)
- return control
- control = QFrame(self)
- layout = None
- if type(formset) is tuple:
- layout = QHBoxLayout()
- for row in formset:
- if isinstance(row, (list, tuple)):
- panel = self.generate_panel(row)
- layout.addWidget(panel)
- elif row == " ":
- spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
- layout.addItem(spacer)
- elif type(row) is dict:
- c = self.generate_tabs(row)
- layout.addWidget(c)
- self._tabs.append(c)
- else:
- param = self.controls.get(row, None)
- if param is None:
- label = QLabel()
- label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
- # layout.addWidget( label )
-
- if row.startswith('info:'):
- label.setText(row[5:])
- font = QFont()
- font.setPointSize(10)
- label.setFont(font)
- label.setAccessibleName('info')
- elif row.startswith('h1:'):
- label.setText(row[3:])
- font = QFont()
- font.setPointSize(17)
- font.setBold(True)
- label.setFont(font)
- label.setAccessibleName('h1')
- elif row.startswith('h2:'):
- label.setText(row[3:])
- font = QFont()
- font.setPointSize(16)
- font.setBold(True)
- label.setFont(font)
- label.setAccessibleName('h2')
- elif row.startswith('h3:'):
- label.setText(row[3:])
- font = QFont()
- font.setPointSize(15)
- font.setBold(True)
- label.setFont(font)
- label.setAccessibleName('h3')
- elif row.startswith('h4:'):
- label.setText(row[3:])
- font = QFont()
- font.setPointSize(14)
- font.setBold(True)
- label.setFont(font)
- label.setAccessibleName('h4')
- elif row.startswith('h5:'):
- label.setText(row[3:])
- font = QFont()
- font.setPointSize(12)
- font.setBold(True)
- label.setFont(font)
- label.setAccessibleName('h5')
- else:
- label.setText(row)
- font = QFont()
- font.setPointSize(10)
- label.setFont(font)
- label.setAccessibleName('msg')
- label.setToolTip(label.text())
- layout.addWidget(label)
- else:
- param.parent = self
- param.name = row
- layout.addWidget(param.form)
- elif type(formset) is list:
- layout = QVBoxLayout()
- for row in formset:
- if isinstance(row, (list, tuple)):
- panel = self.generate_panel(row)
- layout.addWidget(panel)
- elif row == " ":
- spacer = QSpacerItem(
- 20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
- layout.addItem(spacer)
- elif type(row) is dict:
- c = self.generate_tabs(row)
- layout.addWidget(c)
- self._tabs.append(c)
- else:
- param = self.controls.get(row, None)
- if param is None:
- label = QLabel()
- label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
- label.resize(30, 30)
- # layout.addWidget( label )
-
- if row.startswith('info:'):
- label.setText(row[5:])
- font = QFont()
- font.setPointSize(10)
- label.setFont(font)
- label.setAccessibleName('info')
- elif row.startswith('h1:'):
- label.setText(row[3:])
- font = QFont()
- font.setPointSize(17)
- font.setBold(True)
- label.setFont(font)
- label.setAccessibleName('h1')
- elif row.startswith('h2:'):
- label.setText(row[3:])
- font = QFont()
- font.setPointSize(16)
- font.setBold(True)
- label.setFont(font)
- label.setAccessibleName('h2')
- elif row.startswith('h3:'):
- label.setText(row[3:])
- font = QFont()
- font.setPointSize(15)
- font.setBold(True)
- label.setFont(font)
- label.setAccessibleName('h3')
- elif row.startswith('h4:'):
- label.setText(row[3:])
- font = QFont()
- font.setPointSize(14)
- font.setBold(True)
- label.setFont(font)
- label.setAccessibleName('h4')
- elif row.startswith('h5:'):
- label.setText(row[3:])
- font = QFont()
- font.setPointSize(12)
- font.setBold(True)
- label.setFont(font)
- label.setAccessibleName('h5')
- else:
- label.setText(row)
- font = QFont()
- font.setPointSize(10)
- label.setFont(font)
- label.setAccessibleName('msg')
-
- label.setToolTip(label.text())
-
- layout.addWidget(label)
- else:
- param.parent = self
- param.name = row
- layout.addWidget(param.form)
-
- if conf.PYFORMS_USE_QT5:
- layout.setContentsMargins(0,0,0,0)
- else:
- layout.setMargin(0)
-
- control.setLayout(layout)
- return control
-
- def show(self):
- """
- It shows the
- """
- self.init_form()
- super(BaseWidget, self).show()
-
- def save_form(self, data={}, path=None):
- allparams = self.controls
-
- if hasattr(self, 'load_order'):
- for name in self.load_order:
- param = allparams[name]
- data[name] = {}
- param.save_form(data[name])
- else:
- for name, param in allparams.items():
- data[name] = {}
- param.save_form(data[name])
- return data
-
- def load_form(self, data, path=None):
- allparams = self.controls
-
- if hasattr(self, 'load_order'):
- for name in self.load_order:
- param = allparams[name]
- if name in data:
- param.load_form(data[name])
- else:
- for name, param in allparams.items():
- if name in data:
- param.load_form(data[name])
- # self.init_form()
-
- def save_window(self):
- allparams = self.controls
- data = {}
- self.save_form(data)
-
- filename = QFileDialog.getSaveFileName(self, 'Select file')
- with open(filename, 'w') as output_file: json.dump(data, output_file)
-
- def load_form_filename(self, filename):
- with open(filename, 'r') as pkl_file:
- project_data = json.load(pkl_file)
- data = dict(project_data)
- self.load_form(data)
-
- def load_window(self):
- filename = QFileDialog.getOpenFileNames(self, 'Select file')
- self.load_form_filename(str(filename[0]))
-
- ##########################################################################
- ############ EVENTS ######################################################
- ##########################################################################
-
- def before_close_event(self):
- """
- Do something before closing widget
- Note that the window will be closed anyway
- """
- pass
-
- ##########################################################################
- ############ Properties ##################################################
- ##########################################################################
-
- @property
- def form_has_loaded(self):
- return self._formLoaded
-
- @property
- def controls(self):
- """
- Return all the form controls from the the module
- """
- result = {}
- for name, var in vars(self).items():
- try:
- if isinstance(var, ControlBase):
- result[name] = var
- except:
- pass
- return result
-
- @property
- def form(self):
- return self
-
- @property
- def title(self):
- return self.windowTitle()
-
- @title.setter
- def title(self, value):
- self.setWindowTitle(value)
-
- @property
- def mainmenu(self):
- return self._mainmenu
-
- @mainmenu.setter
- def mainmenu(self, value):
- self._mainmenu = value
-
- @property
- def formset(self):
- return self._formset
-
- @formset.setter
- def formset(self, value):
- self._formset = value
-
- @property
- def uid(self):
- return self._uid
-
- @uid.setter
- def uid(self, value):
- self._uid = value
-
- @property
- def max_progress(self):
- return self._progress.max
-
- @max_progress.setter
- def max_progress(self, value):
- self._progress.max = value
-
- @property
- def min_progress(self):
- return self._progress.min
-
- @min_progress.setter
- def min_progress(self, value):
- self._progress.min = value
-
- @property
- def progress(self):
- return self._progress.value
-
- @progress.setter
- def progress(self, value):
- self._progress.value = value
- QApplication.processEvents()
-
- if value == self.max_progress: self._progress.hide()
- if value == self.min_progress: self._progress.show()
-
- @property
- def visible(self):
- return self.isVisible()
-
- @visible.setter
- def visible(self, value):
- self.show() if value else self.hide()
-
- ##########################################################################
- ############ PRIVATE FUNCTIONS ###########################################
- ##########################################################################
- def closeEvent(self, event):
- self.before_close_event()
- super(BaseWidget, self).closeEvent(event)
diff --git a/pyforms/gui/Controls/ControlBase.py b/pyforms/gui/Controls/ControlBase.py
deleted file mode 100755
index 413da38..0000000
--- a/pyforms/gui/Controls/ControlBase.py
+++ /dev/null
@@ -1,243 +0,0 @@
-# !/usr/bin/python
-# -*- coding: utf-8 -*-
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QMenu
- from PyQt5.QtWidgets import QAction
- from PyQt5.QtGui import QIcon
- from PyQt5.QtGui import QKeySequence
- from PyQt5 import QtCore
- from PyQt5 import uic
-else:
- from PyQt4.QtGui import Qmenu
- from PyQt4.QtGui import QAction
- from PyQt4.QtGui import QIcon
- from PyQt4.QtGui import QKeySequence
- from PyQt4 import QtCore
- from PyQt4 import uic
-
-
-
-class ControlBase(object):
- """
- This class represents the most basic control that can exist
- A Control is a Widget or a group of widgets that can be reused from application to application
-
- @undocumented: __repr__
- """
-
- def __init__(self, label='', default=None, helptext=None):
- self._help = helptext
- self._value = default
- self._form = None # Qt widget
- self._parent = None # Parent window
- self._label = label # Label
- self._popup_menu = None
-
- self.init_form()
-
-
- def init_form(self):
- """
- Load Control and initiate the events
- """
- if self.help: self.form.setToolTip(self.help)
-
-
- def __repr__(self): return str(self._value)
-
- ##########################################################################
- ############ Funcions ####################################################
- ##########################################################################
-
- def load_form(self, data, path=None):
- """
- Load a value from the dict variable
- @param data: dictionary with the value of the Control
- """
- if 'value' in data:
- self.value = data['value']
-
- def save_form(self, data, path=None):
- """
- Save a value to dict variable
- @param data: dictionary with to where the value of the Control will be added
- """
- if self.value:
- data['value'] = self.value
- return data
-
- def show(self):
- """
- Show the control
- """
- if self.form is None:
- return
- self.form.show()
-
- def hide(self):
- """
- Hide the control
- """
- if self.form is None:
- return
- self.form.hide()
-
-
- def __create_popup_menu(self):
- if not self._popup_menu:
- self.form.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
- self.form.customContextMenuRequested.connect(self._open_popup_menu)
- self._popup_menu = QMenu(self.parent)
- self._popup_menu.aboutToShow.connect( self.about_to_show_contextmenu_event)
-
- def add_popup_submenu(self, label, submenu=None):
- self.__create_popup_menu()
- menu = submenu if submenu else self._popup_menu
- submenu = QMenu(label, menu)
- menu.addMenu(submenu)
- return submenu
-
- def add_popup_menu_option(self, label, function_action=None, key=None, icon=None, submenu=None):
- """
- Add an option to the Control popup menu
- @param label: label of the option.
- @param function_action: function called when the option is selected.
- @param key: shortcut key
- @param icon: icon
- """
- self.__create_popup_menu()
-
- menu = submenu if submenu else self._popup_menu
-
- if label == "-":
- return menu.addSeparator()
- else:
- action = QAction(label, self.form)
- if icon is not None:
- action.setIconVisibleInMenu(True)
- action.setIcon(icon if isinstance(icon, QIcon) else QIcon(icon) )
- if key != None:
- action.setShortcut(QKeySequence(key))
- if function_action:
- action.triggered.connect(function_action)
- menu.addAction(action)
- return action
-
-
- ##########################################################################
- ############ Events ######################################################
- ##########################################################################
-
- def changed_event(self):
- """
- Function called when ever the Control value is changed
- """
- return True
-
- def about_to_show_contextmenu_event(self):
- """
- Function called before open the Control popup menu
- """
- pass
-
- def _open_popup_menu(self, position):
- if self._popup_menu:
- self._popup_menu.exec_(self.form.mapToGlobal(position))
-
- ##########################################################################
- ############ Properties ##################################################
- ##########################################################################
-
- ##########################################################################
- # Set the Control enabled or disabled
-
- @property
- def enabled(self):
- return self.form.isEnabled()
-
- @enabled.setter
- def enabled(self, value):
- """@type value: boolean"""
- self.form.setEnabled(value)
-
- ##########################################################################
- # Return or update the value of the Control
-
- @property
- def value(self):
- return self._value
-
- @value.setter
- def value(self, value):
- """
- This property return and set what the control should manage or store.
- @type value: string
- """
- oldvalue = self._value
- self._value = value
- if oldvalue != value:
- self.changed_event()
-
- @property
- def visible(self): return self.form.isVisible()
-
- @visible.setter
- def visible(self, value):
- self.show() if value else self.hide()
-
- @property
- def name(self): return self.form.objectName()
-
- @name.setter
- def name(self, value):
- """
- This property return and set the name of the control
- @type value: string
- """
- self.form.setObjectName(value)
-
- ##########################################################################
- # Return or update the label of the Control
-
- @property
- def label(self):
- return self._label
-
- @label.setter
- def label(self, value):
- """
- Label of the control, if applies
- @type value: string
- """
- self._label = value
-
- ##########################################################################
- # Return the QT widget
-
- @property
- def form(self):
- """
- Returns the Widget of the control.
- This property will be deprecated in a future version.
- """
- return self._form
-
- ##########################################################################
- # Parent window
-
- @property
- def parent(self): return self._parent
-
- @parent.setter
- def parent(self, value):
- """
- Returns or set the parent basewidget where the Control is
- @type value: BaseWidget
- """
- self._parent = value
-
- @property
- def help(self): return self._help if self._help else ''
diff --git a/pyforms/gui/Controls/ControlBoundingSlider.py b/pyforms/gui/Controls/ControlBoundingSlider.py
deleted file mode 100755
index fdd6749..0000000
--- a/pyforms/gui/Controls/ControlBoundingSlider.py
+++ /dev/null
@@ -1,412 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QWidget
- from PyQt5.QtWidgets import QVBoxLayout
- from PyQt5.QtWidgets import QHBoxLayout
- from PyQt5.QtWidgets import QSpinBox
- from PyQt5.QtGui import QPainter
- from PyQt5.QtGui import QFont
- from PyQt5.QtGui import QColor
- from PyQt5.QtGui import QCursor
- from PyQt5 import QtCore
-
-else:
- from PyQt4.QtGui import QWidget
- from PyQt4.QtGui import QVBoxLayout
- from PyQt4.QtGui import QHBoxLayout
- from PyQt4.QtGui import QPainter
- from PyQt4.QtGui import QFont
- from PyQt4.QtGui import QColor
- from PyQt4.QtGui import QCursor
- from PyQt4.QtGui import QSpinBox
- from PyQt4 import QtCore
-
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-
-class GaugeWidgetVertical(QWidget):
- def __init__(self, *args, **kwargs):
- QWidget.__init__(self, *args, **kwargs)
-
- self.setMouseTracking(True)
- self.setMinimumHeight(30)
- self.setMinimumWidth(30)
- self.setMaximumWidth(50)
-
- self._lower = 0
- self._higher = 100
- self._minVal = 0
- self._maxVal = 75
- self._lastMouseY = None
- self._moving = False
- self._resizingBottom = False
- self._resizingTop = False
- self._scale = 1.0
- self._use_float = False
-
- def changed_event(self):
- pass
-
- def paintEvent(self, e):
- # call the base implementation to paint normal interface
- super(GaugeWidgetVertical, self).paintEvent(e)
- draw = QPainter()
- draw.begin(self)
-
- window_with = self.width() - 1
- diff = (self._higher - self._lower) * self.scale
- try:
- self._step = float(self.height()) / float(diff)
- except ZeroDivisionError:
- self._step = 0
- y_start = self.height() - (self._minVal - self._lower) * self._step * self.scale
- y_end = self.height() - (self._maxVal - self._lower) * self._step * self.scale
-
- draw.setOpacity(1.0)
- draw.setBrush(QtCore.Qt.NoBrush)
- draw.setPen(QColor(200, 200, 255))
-
- for i in range(self.height() / 5, (self.height() - self.height() / 5) + 1, self.height() / 5):
- draw.drawLine(0, i, window_with, i)
-
- draw.setBrush(QColor(33, 133, 208))
- draw.setPen(QColor(33, 133, 208))
- draw.setOpacity(0.7)
- draw.drawRect(0, y_start, window_with, y_end - y_start)
-
- draw.setFont(QFont('Decorative', 8))
- draw.setPen(QColor(30, 30, 30))
- draw.drawText(3, self.height() - 3, str(self._lower) if self._use_float else str(int(round(self._lower))))
- draw.drawText(3, 10, str(self._higher) if self._use_float else str(int(round(self._higher))))
-
- draw.drawText(3, y_start + 11, str(self._minVal) if self._use_float else str(int(round(self._minVal))))
- draw.drawText(3, y_end - 4, str(self._maxVal) if self._use_float else str(int(round(self._maxVal))))
-
- draw.end()
-
- def mousePressEvent(self, event):
- self._moving = False
- self._resizingBottom = False
- self._resizingTop = False
-
- y_start = self.height() - (self._minVal - self._lower) * self._step * self.scale
- y_end = self.height() - (self._maxVal - self._lower) * self._step * self.scale
-
- if event.buttons() == QtCore.Qt.LeftButton:
- if y_start > event.y() > y_end:
- self._moving = True
- elif event.y() < y_end:
- self._resizingTop = True
- elif y_start < event.y():
- self._resizingBottom = True
-
- def mouseReleaseEvent(self, event):
- self._moving = False
- self._resizingBottom = False
- self._resizingTop = False
-
- def mouseMoveEvent(self, event):
- super(GaugeWidgetVertical, self).mouseMoveEvent(event)
-
- y_start = self.height() - (self._minVal - self._lower) * self._step * self.scale
- y_end = self.height() - (self._maxVal - self._lower) * self._step * self.scale
-
- if y_start < event.y() or event.y() < y_end:
- self.setCursor(QCursor(QtCore.Qt.SizeVerCursor))
- else:
- self.setCursor(QCursor(QtCore.Qt.ArrowCursor))
-
- if event.buttons() == QtCore.Qt.LeftButton:
- if self._lastMouseY != None:
- diff = self._lastMouseY - event.y()
- if diff != 0:
- if self._moving:
- new_min = self._minVal * self.scale + diff * 1 / self._step
- new_max = self._maxVal * self.scale + diff * 1 / self._step
- if new_min < new_max:
- self._minVal = new_min / self.scale
- self._maxVal = new_max / self.scale
- elif self._resizingTop:
- new_max = self._maxVal * self.scale + diff * 1 / self._step
- if self._minVal < (new_max / self.scale): self._maxVal = new_max / self.scale
- elif self._resizingBottom:
- new_min = self._minVal * self.scale + diff * 1 / self._step
- if (new_min / self.scale) < self._maxVal: self._minVal = new_min / self.scale
-
- self.repaint()
-
- self.changed_event()
-
- self._lastMouseY = event.y()
-
- def mouseReleaseEvent(self, event):
- self._lastMouseY = None
-
- @property
- def scale(self):
- return self._scale
-
- @scale.setter
- def scale(self, value):
- self._scale = value
-
-
-class GaugeWidgetHorizontal(GaugeWidgetVertical):
- def __init__(self, *args, **kwargs):
- super(GaugeWidgetHorizontal, self).__init__(*args, **kwargs)
-
- self.setMaximumWidth(1000000)
- self.setMinimumHeight(20)
- self.setMaximumHeight(20)
-
- def paintEvent(self, e):
- # call the base implementation to paint normal interface
- QWidget.paintEvent(self, e);
- draw = QPainter();
- draw.begin(self)
-
- h = self.height() - 1
- diff = (self._higher - self._lower) * self.scale
-
- try:
- self._step = float(self.width()) / float(diff)
- except ZeroDivisionError:
- self._step = 0
- x_start = (self._minVal - self._lower) * self._step * self.scale
- x_end = (self._maxVal - self._lower) * self._step * self.scale
-
- draw.setOpacity(1.0)
- draw.setBrush(QtCore.Qt.NoBrush)
- draw.setPen(QColor(200, 200, 255))
-
- for i in range( int(self.width()/5), int(self.width()-self.width()/5) + 1, int(self.width()/5) ):
- draw.drawLine(i, 0, i, h)
-
- draw.setBrush(QColor(238, 238, 238))
- draw.setPen(QColor(238, 238, 238))
- draw.drawRoundedRect(0, 2, self.width(), h - 4, 3, 3)
-
- draw.setBrush(QColor(33, 133, 208))
- draw.setPen(QColor(33, 133, 208))
- draw.drawRoundedRect(int(round(x_start)), 2, int(round(x_end - x_start)), h - 4, 3, 3)
- # draw.setOpacity(1.0)
- draw.setFont(QFont('Decorative', 8))
- draw.setPen(QColor(80, 80, 80))
-
- str(self._maxVal) if self._use_float else str(int(round(self._maxVal)))
-
- boundtext = draw.boundingRect(QtCore.QRectF(),
- str(self._higher) if self._use_float else str(int(round(self._higher))))
- draw.drawText(self.width() - boundtext.width(), 14,
- str(self._higher) if self._use_float else str(int(round(self._higher))))
- draw.drawText(0, 14, str(self._lower) if self._use_float else str(int(round(self._lower))))
-
- draw.setPen(QColor(255, 255, 255))
- boundtext = draw.boundingRect(QtCore.QRectF(),
- str(self._minVal) if self._use_float else str(int(round(self._minVal))))
- draw.drawText(x_start + 2, 14, str(self._minVal) if self._use_float else str(int(round(self._minVal))))
- boundtext = draw.boundingRect(QtCore.QRectF(),
- str(self._maxVal) if self._use_float else str(int(round(self._maxVal))))
- draw.drawText(x_end - boundtext.width(), 14,
- str(self._maxVal) if self._use_float else str(int(round(self._maxVal))))
-
- draw.end()
-
- def mousePressEvent(self, event):
- self._moving = False
- self._resizingLeft = False
- self._resizingRight = False
-
- x_start = (self._minVal - self._lower) * self._step * self.scale
- x_end = (self._maxVal - self._lower) * self._step * self.scale
-
- if event.buttons() == QtCore.Qt.LeftButton:
- if x_start < event.x() < x_end:
- self._moving = True
- elif event.x() > x_end:
- self._resizingLeft = True
- elif x_start > event.x():
- self._resizingRight = True
-
- def mouseMoveEvent(self, event):
- super(GaugeWidgetVertical, self).mouseMoveEvent(event)
-
- x_start = (self._minVal - self._lower) * self._step * self.scale
- x_end = (self._maxVal - self._lower) * self._step * self.scale
-
- # set the cursors
- if x_start >= event.x() or event.x() >= x_end:
- self.setCursor(QCursor(QtCore.Qt.SizeHorCursor))
- else:
- self.setCursor(QCursor(QtCore.Qt.ArrowCursor))
-
- if event.buttons() == QtCore.Qt.LeftButton:
- if self._lastMouseY != None:
- diff = self._lastMouseY - event.x()
- if diff != 0:
- if self._moving:
- new_min = self._minVal * self.scale - diff * 1 / self._step
- new_max = self._maxVal * self.scale - diff * 1 / self._step
- if new_min < new_max:
- self._minVal = new_min / self.scale
- self._maxVal = new_max / self.scale
- elif self._resizingLeft:
- new_max = self._maxVal * self.scale - diff * 1 / self._step
- if self._minVal < (new_max / self.scale): self._maxVal = new_max / self.scale
- elif self._resizingRight:
- new_min = self._minVal * self.scale - diff * 1 / self._step
- if (new_min / self.scale) < self._maxVal: self._minVal = new_min / self.scale
-
- self.repaint()
- self.changed_event()
-
- self._lastMouseY = event.x()
-
-
-class ControlBoundingSlider(ControlBase):
- def __init__(self, label="", default=[20, 40], min=0, max=100, horizontal=False, helptext=None,
- show_spinboxes=True):
- self._horizontal = horizontal
- self._show_spinboxes = show_spinboxes
- ControlBase.__init__(self, label, default, helptext=helptext)
-
- self.min = min
- self.max = max
- self.value = default
- self.__update()
-
- def init_form(self):
- self._boundingbox = GaugeWidgetHorizontal() if self._horizontal else GaugeWidgetVertical()
- self._boundingbox.changed_event = self.__update
-
- if self._show_spinboxes:
- self._form = hwidget = QWidget()
- if self._horizontal:
- hlayout = QHBoxLayout()
- else:
- hlayout = QVBoxLayout()
-
-
- if conf.PYFORMS_USE_QT5:
- hlayout.setContentsMargins(0,0,0,0)
- else:
- hlayout.setMargin(0)
-
-
- hwidget.setLayout(hlayout)
- self._min_spinbox = QSpinBox()
- self._min_spinbox.valueChanged.connect(self.__min_spinbox_changed)
- self._min_spinbox.setMaximumWidth(95)
-
- self._max_spinbox = QSpinBox()
- self._max_spinbox.valueChanged.connect(self.__max_spinbox_changed)
- self._max_spinbox.setMaximumWidth(95)
-
- if self._horizontal:
- hlayout.addWidget(self._min_spinbox)
- else:
- hlayout.addWidget(self._max_spinbox)
- hlayout.addWidget(self._boundingbox)
- if self._horizontal:
- hlayout.addWidget(self._max_spinbox)
- else:
- hlayout.addWidget(self._min_spinbox)
-
- else:
- self._form = self._boundingbox
-
- super(ControlBoundingSlider, self).init_form()
-
- def __max_spinbox_changed(self, value):
- if value < self._boundingbox._minVal: return
- if hasattr(self, '_is_updating_spinboxes'): return
- self.scale = self.__find_scale_factor(value)
- self._boundingbox._maxVal = value
- self._boundingbox.repaint()
- self.changed_event()
-
- def __min_spinbox_changed(self, value):
- if value > self._boundingbox._maxVal: return
- if hasattr(self, '_is_updating_spinboxes'): return
- self.scale = self.__find_scale_factor(value)
- self._boundingbox._minVal = value
- self._boundingbox.repaint()
- self.changed_event()
-
- def __update(self):
- l, h = self._boundingbox._minVal, self._boundingbox._maxVal
- self._is_updating_spinboxes = True
- self._min_spinbox.setValue(l)
- self._max_spinbox.setValue(h)
- del self._is_updating_spinboxes
- self.changed_event()
-
- def changed_event(self):
- pass
-
- def __find_scale_factor(self, value):
- scale = 1.0
- new_value = value
- while abs(new_value) < 0.0:
- scale *= 10.0
- new_value = value * scale
- return scale
-
- ##########################################################################
- ############ Properties ##################################################
- ##########################################################################
-
- @property
- def value(self):
- return self._boundingbox._minVal, self._boundingbox._maxVal
-
- @value.setter
- def value(self, value):
- ControlBase.value.fset(self, value)
- self.scale = self.__find_scale_factor(value[0])
- self._boundingbox._minVal, self._boundingbox._maxVal = value[0], value[1]
- if hasattr(self, '_min_spinbox'): self._min_spinbox.setValue(value[0])
- if hasattr(self, '_max_spinbox'): self._max_spinbox.setValue(value[1])
- self._boundingbox.repaint()
-
- @property
- def min(self):
- return self._boundingbox._lower
-
- @min.setter
- def min(self, value):
- self._boundingbox._lower = value
- self._boundingbox.repaint()
- if hasattr(self, '_min_spinbox'): self._min_spinbox.setMinimum(value)
- if hasattr(self, '_max_spinbox'): self._max_spinbox.setMinimum(value)
-
- @property
- def max(self):
- return self._boundingbox._higher
-
- @max.setter
- def max(self, value):
- self._boundingbox._higher = value
- self._boundingbox.repaint()
- if hasattr(self, '_min_spinbox'): self._min_spinbox.setMaximum(value)
- if hasattr(self, '_max_spinbox'): self._max_spinbox.setMaximum(value)
-
- @property
- def scale(self):
- return self._boundingbox.scale
-
- @scale.setter
- def scale(self, value):
- self._boundingbox.scale = value
-
- @property
- def convert_2_int(self):
- return not self._boundingbox._use_float
-
- @convert_2_int.setter
- def convert_2_int(self, value):
- self._boundingbox._use_float = not value
diff --git a/pyforms/gui/Controls/ControlCheckBoxList.py b/pyforms/gui/Controls/ControlCheckBoxList.py
deleted file mode 100755
index 127b833..0000000
--- a/pyforms/gui/Controls/ControlCheckBoxList.py
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-from pysettings import conf
-
-import pyforms.utils.tools as tools
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QListWidgetItem
- from PyQt5 import uic
- from PyQt5 import QtCore
-
-else:
- from PyQt4.QtGui import QListWidgetItem
- from PyQt4 import uic
- from PyQt4 import QtCore
-
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-
-class ControlCheckBoxList(ControlBase):
- def init_form(self):
- control_path = tools.getFileInSameDirectory(__file__, "tree.ui")
- self._form = uic.loadUi(control_path)
-
- self._form.label.setText(self._label)
-
- self._form.listWidget.itemChanged.connect(self.item_changed)
-
- self._form.listWidget.itemSelectionChanged.connect(self.__itemSelectionChanged)
-
- if self.help: self.form.setToolTip(self.help)
-
- def item_changed(self, item):
- self.changed_event()
-
- def __add__(self, val):
- if isinstance(val, (tuple, list)):
- item = QListWidgetItem(str(val[0]))
- item.value = val[0]
- if val[1]:
- item.setCheckState(QtCore.Qt.Checked)
- else:
- item.setCheckState(QtCore.Qt.Unchecked)
- else:
- item = QListWidgetItem(str(val))
- item.value = val
-
- self._form.listWidget.addItem(item)
- return self
-
- def __sub__(self, other):
- if isinstance(other, int):
- if other < 0:
- indexToRemove = self._form.listWidget.currentRow()
- else:
- indexToRemove = other
- self._form.listWidget.takeItem(indexToRemove)
- else:
- for row in range(self.count):
- item = self._form.listWidget.item(row)
- if item != None and hasattr(item, 'value') and item.value == other:
- self._form.listWidget.takeItem(row)
- return self
-
- def clear(self):
- self._form.listWidget.clear()
-
- def refresh(self):
- for row in range(self.count):
- item = self._form.listWidget.item(row)
- if hasattr(item, 'value'): item.setText(str(item.value))
-
- ############################################################################
- ############ Events ########################################################
- ############################################################################
-
- def __itemSelectionChanged(self):
- self.selection_changed_event()
-
- def selection_changed_event(self):
- pass
-
- ############################################################################
- ############ Properties ####################################################
- ############################################################################
-
- @property
- def count(self):
- return self._form.listWidget.count()
-
- @property
- def checked_indexes(self):
- results = []
- for row in range(self.count):
- item = self._form.listWidget.item(row)
- if item != None and item.checkState() == QtCore.Qt.Checked: results.append(row)
- return results
-
- @property
- def value(self):
- results = []
- for row in range(self.count):
- item = self._form.listWidget.item(row)
- if item != None and item.checkState() == QtCore.Qt.Checked:
- results.append(item.value if hasattr(item, 'value') else str(item.text()))
- return results
-
- @value.setter
- def value(self, value):
- self.clear()
- for row in value: self += row
-
- @property
- def selected_row_index(self):
- return self.form.listWidget.currentRow()
-
- @property
- def items(self):
- results = []
- for row in range(self.count):
- item = self._form.listWidget.item(row)
- results.append(
- [item.value if hasattr(item, 'value') else str(item.text()), item.checkState() == QtCore.Qt.Checked])
- return results
diff --git a/pyforms/gui/Controls/ControlEventTimeline/ControlEventTimeline.py b/pyforms/gui/Controls/ControlEventTimeline/ControlEventTimeline.py
deleted file mode 100755
index 16174d4..0000000
--- a/pyforms/gui/Controls/ControlEventTimeline/ControlEventTimeline.py
+++ /dev/null
@@ -1,502 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-import csv
-import os
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QWidget, QScrollArea, QColorDialog, QFileDialog, QMessageBox, QPushButton, QLabel, \
- QSlider, QHBoxLayout, QVBoxLayout
- from PyQt5 import QtCore
-
-else:
- from PyQt4.QtGui import QWidget, QScrollArea, QColorDialog, QFileDialog, QMessageBox, QPushButton, QLabel, QSlider, \
- QHBoxLayout, QVBoxLayout
- from PyQt4 import QtCore
-
-from pyforms.gui.Controls.ControlEventTimeline.TimelineChart import TimelineChart
-from pyforms.gui.Controls.ControlBase import ControlBase
-from pyforms.gui.Controls.ControlEventTimeline.TimelineWidget import TimelineWidget
-from pyforms.gui.Controls.ControlEventTimeline.TimelinePopupWindow import TimelinePopupWindow
-from pyforms.gui.Controls.ControlEventTimeline.import_window import ImportWindow
-
-from pyforms.gui.Controls.ControlEventTimeline.graphs_graph2event import Graph2Event
-from pyforms.gui.Controls.ControlEventTimeline.graphs_properties import GraphsProperties
-from pyforms.gui.Controls.ControlEventTimeline.graphs_eventsgenerator import GraphsEventsGenerator
-
-
-
-class ControlEventTimeline(ControlBase, QWidget):
- """
- Timeline events editor
- """
-
- def __init__(self, label="", default=0, max=100):
- QWidget.__init__(self)
- ControlBase.__init__(self, label, default)
- self._max = 100
- self._graphs_prop_win = GraphsProperties(self._time, self)
- self._graphsgenerator_win = GraphsEventsGenerator(self._time)
- self._graph2event_win = Graph2Event(self._time)
-
- # Popup menus that only show when clicking on a TIMELINEDELTA object
- self._deltaLockAction = self.add_popup_menu_option("Lock", self.__lockSelected, key='L')
- self._deltaColorAction = self.add_popup_menu_option("Pick a color", self.__pickColor)
- self._deltaRemoveAction = self.add_popup_menu_option("Remove", self.__removeSelected, key='Delete')
- self._deltaActions = [self._deltaLockAction, self._deltaColorAction, self._deltaRemoveAction]
- for action in self._deltaActions:
- action.setVisible(False)
-
- self.add_popup_menu_option("-")
-
- self.add_popup_menu_option("Graphs", self.show_graphs_properties, icon=conf.PYFORMS_ICON_EVENTTIMELINE_GRAPH)
- self.add_popup_menu_option("Apply a function to the graphs", self.__generate_graphs_events,
- icon=conf.PYFORMS_ICON_EVENTTIMELINE_GRAPH)
- self.add_popup_menu_option("Convert graph to events", self.__graph2event_event,
- icon=conf.PYFORMS_ICON_EVENTTIMELINE_GRAPH)
-
- self.add_popup_menu_option("-")
-
- # General righ click popup menus
- self.add_popup_menu_option("Rows", self.__setLinePropertiesEvent,
- icon=conf.PYFORMS_ICON_EVENTTIMELINE_REMOVE)
- self.add_popup_menu_option("-")
-
-
-
- self.add_popup_menu_option("-")
-
- self.add_popup_menu_option("Auto adjust rows", self.__auto_adjust_tracks_evt,
- icon=conf.PYFORMS_ICON_EVENTTIMELINE_REFRESH)
- self.add_popup_menu_option("Add a row", self.__add_track_2_bottom_evt,
- icon=conf.PYFORMS_ICON_EVENTTIMELINE_ADD)
-
- self.add_popup_menu_option("-")
-
- clean_menu = self.add_popup_submenu('Clean')
-
- self.add_popup_menu_option('The current row', function_action=self.__cleanLine, submenu=clean_menu)
- self.add_popup_menu_option('-')
- self.add_popup_menu_option('All graphs', function_action=self.__cleanCharts, submenu=clean_menu)
- self.add_popup_menu_option('-')
- self.add_popup_menu_option('Everything', function_action=self.clean, submenu=clean_menu)
-
- def init_form(self):
- # Get the current path of the file
- rootPath = os.path.dirname(__file__)
-
- vlayout = QVBoxLayout()
- hlayout = QHBoxLayout()
-
- if conf.PYFORMS_USE_QT5:
- hlayout.setContentsMargins(0,0,0,0)
- vlayout.setContentsMargins(0,0,0,0)
- else:
- hlayout.setMargin(0)
- vlayout.setMargin(0)
-
- self.setLayout(vlayout)
-
- # Add scroll area
- scrollarea = QScrollArea()
- scrollarea.setMinimumHeight(140)
- scrollarea.setWidgetResizable(True)
- scrollarea.keyPressEvent = self.__scrollAreaKeyPressEvent
- scrollarea.keyReleaseEvent = self.__scrollAreaKeyReleaseEvent
- vlayout.addWidget(scrollarea)
- # vlayout.setContentsMargins(5, 5, 5, 5)
-
- # The timeline widget
- widget = TimelineWidget(self)
- widget._scroll = scrollarea
- # widget.setMinimumHeight(1000)
- scrollarea.setWidget(widget)
-
- # TODO Options buttons
- # btn_1 = QtGui.QPushButton("?")
- # btn_2 = QtGui.QPushButton("?")
- # vlayout_options = QtGui.QVBoxLayout()
- # vlayout_options.addWidget(btn_1)
- # vlayout_options.addWidget(btn_2)
- # hlayout.addLayout(vlayout_options)
- # hlayout.addWidget(btn_1)
- # hlayout.addWidget(btn_2)
-
- # Timeline zoom slider
- slider = QSlider(QtCore.Qt.Horizontal)
- slider.setFocusPolicy(QtCore.Qt.NoFocus)
- slider.setMinimum(1)
- slider.setMaximum(100)
- slider.setValue(10)
- slider.setPageStep(1)
- slider.setTickPosition(QSlider.NoTicks) # TicksBothSides
- slider.valueChanged.connect(self.__scaleSliderChange)
-
- slider_label_zoom_in = QLabel()
- slider_label_zoom_out = QLabel()
- slider_label_zoom_in.setPixmap(conf.PYFORMS_PIXMAP_EVENTTIMELINE_ZOOM_IN)
- slider_label_zoom_out.setPixmap(conf.PYFORMS_PIXMAP_EVENTTIMELINE_ZOOM_OUT)
-
- self._zoomLabel = QLabel("100%")
- hlayout.addWidget(self._zoomLabel)
- hlayout.addWidget(slider_label_zoom_out)
- hlayout.addWidget(slider)
- hlayout.addWidget(slider_label_zoom_in)
- # hlayout.setContentsMargins(5, 0, 5, 5)
- # Import/Export Buttons
- btn_import = QPushButton("Import")
-
- btn_import.setIcon(conf.PYFORMS_ICON_EVENTTIMELINE_IMPORT)
- btn_import.clicked.connect(self.__import)
- btn_export = QPushButton("Export")
-
- btn_export.setIcon(conf.PYFORMS_ICON_EVENTTIMELINE_EXPORT)
- btn_export.clicked.connect(self.__export)
- # importexport_vlayout = QtGui.QVBoxLayout()
- # importexport_vlayout.adimdWidget(btn_import)
- # importexport_vlayout.addWidget(btn_export)
- # hlayout.addLayout(importexport_vlayout)
- hlayout.addWidget(btn_import)
- hlayout.addWidget(btn_export)
-
- vlayout.addLayout(hlayout)
-
- self._time = widget
- self._scrollArea = scrollarea
-
- ##########################################################################
- #### HELPERS/PUBLIC FUNCTIONS ############################################
- ##########################################################################
-
- def __add__(self, other):
- if isinstance(other, TimelineChart):
- self._graphs_prop_win += other
- self._graphsgenerator_win += other
- self._graph2event_win += other
- return self
-
- def __sub__(self, other):
- if isinstance(other, int):
- self._graphs_prop_win -= other
- self._graphsgenerator_win -= other
- self._graph2event_win -= other
- return self
-
- def rename_graph(self, graph_index, newname):
- self._graphs_prop_win.rename_graph(graph_index, newname)
- self._graphsgenerator_win.rename_graph(graph_index, newname)
- self._graph2event_win.rename_graph(graph_index, newname)
-
- def add_period(self, value, row=0, color=None):
- """
-
- :param value:
- :param row:
- :param color:
- :return:
- """
- self._time.addPeriod(value, track, color)
- self._time.repaint()
-
- def add_graph(self, name, data):
- """
-
- :param name:
- :param data:
- :return:
- """
- self._time.add_chart(name, data)
-
- def import_graph(self, filename, frame_col=0, val_col=1):
- """
-
- :param filename:
- :param frame_col:
- :param val_col:
- :return:
- """
- self.__import()
- self._import_window.import_chart(filename, frame_col, val_col)
-
- def import_graph_file(self, filename, separator=';', ignore_rows=0):
- """
-
- :param filename:
- :param separator:
- :param ignore_rows:
- :return:
- """
- csvfile = open(filename, 'U')
- spamreader = csv.reader(csvfile, delimiter=separator)
- for i in range(ignore_rows): next(spamreader, None)
- chart = self._time.importchart_csv(spamreader)
- chart.name = os.path.basename(filename).replace('.csv', '').replace('.CSV', '')
- csvfile.close()
-
- def show_graphs_properties(self):
- """
-
- """
- self._graphs_prop_win.show()
- self._time.repaint()
-
- def import_csv(self, csvfile):
- """
-
- :param csvfile:
- """
- # If there are annotation in the timeline, show a warning
- if len(self._time._tracks) > 0: # dict returns True if not empty
- message = ["You are about to import new data. ",
- "If you proceed, current annotations will be erased. ",
- "Make sure to export current annotations first to save.",
- "\n",
- "Are you sure you want to proceed?"]
- reply = QMessageBox.question(self,
- "Warning!",
- "".join(message),
- QMessageBox.Yes | QMessageBox.No,
- QMessageBox.No)
-
- if reply != QMessageBox.Yes:
- return
-
- self._time.import_csv(csvfile)
-
- def export_csv_file(self, filename):
- with open(filename, 'w') as csvfile:
- spamwriter = csv.writer(csvfile, dialect='excel')
- self._time.export_csv(spamwriter)
-
- def import_csv_file(self, filename):
- with open(filename, 'r') as csvfile:
- spamreader = csv.reader(csvfile, dialect='excel')
- self._time.import_csv(spamreader)
-
- ##########################################################################
- #### EVENTS ##############################################################
- ##########################################################################
-
- def mouse_moveover_timeline_event(self, event):
- self._graphs_prop_win.mouse_moveover_timeline_event(event)
-
-
- @property
- def pointer_changed_event(self):
- return self._time._pointer.moveEvent
-
- @pointer_changed_event.setter
- def pointer_changed_event(self, value):
- self._time._pointer.moveEvent = value
-
- def __auto_adjust_tracks_evt(self):
- for i in range(len(self._time.tracks) - 1, -1, -1):
- track = self._time.tracks[i]
- if len(track) == 0:
- self._time.remove_track(track)
- else:
- break
-
- def __add_track_2_bottom_evt(self):
- self._time.addTrack()
-
- def __remove_track_from_bottom_evt(self):
- if len(self._time.tracks) > 0:
- track = self._time.tracks[-1]
- if len(track) == 0:
- self._time.remove_track(track)
-
- def __generate_graphs_events(self):
- self._graphsgenerator_win.show()
-
- def __graph2event_event(self):
- self._graph2event_win.show()
-
- ##########################################################################
- #### PROPERTIES ##########################################################
- ##########################################################################
-
- @property
- def value(self):
- return self._time.position
-
- @value.setter
- def value(self, value):
- ControlBase.value.fset(self, value)
- self._time.position = value
-
- @property
- def max(self):
- return self._time.minimumWidth()
-
- @max.setter
- def max(self, value):
- self._max = value
- self._time.setMinimumWidth(value)
- self.repaint()
-
- @property
- def form(self):
- return self
-
- @property
- def rows(self):
- return self._time.tracks
-
- @property
- def graphs(self): return self._time.graphs
-
- ##########################################################################
- #### PRIVATE FUNCTIONS ###################################################
- ##########################################################################
-
- def about_to_show_contextmenu_event(self):
- for action in self._deltaActions:
- action.setVisible(
- True) if self._time._selected is not None else action.setVisible(False)
-
-
-
- def __setLinePropertiesEvent(self):
- """
- This controls makes possible the edition of a track in the
- timeline, based on the position of the mouse.
-
- Updates:
- - Track label
- - Track default color
- """
- current_track = self._time.current_mouseover_track
- parent = self._time
-
- # Tracks info dict and index
- i = current_track
-
- # Save current default color to override with selected track color
- timeline_default_color = parent.color
- try:
- parent.color = self._time._tracks[current_track].color
- except Exception as e:
- error_message = ("You tried to edit an empty track.",
- "\n",
- "Initialize it by creating an event first.")
- QMessageBox.warning(
- parent, "Attention!", "".join(error_message))
- return e
-
- # Create dialog
- dialog = TimelinePopupWindow(parent, i)
- dialog.setModal(True) # to disable main application window
-
- # If dialog is accepted, update dict info
- if dialog._ui.exec_() == dialog.Accepted:
- # Update label
- if dialog.behavior is not None:
- self._time._tracks[i].title = dialog.behavior
-
- # Update color
- if self._time._tracks[i].color != dialog.color:
- for delta in self._time._tracks[i].periods:
- delta.color = dialog.color
- self._time._tracks[i].color = dialog.color
- self._time.repaint()
- else:
- pass
-
- # Restore timeline default color
- parent.color = timeline_default_color
-
- def __lockSelected(self):
- self._time.lockSelected()
-
- def __removeSelected(self):
- self._time.removeSelected()
-
- def __import(self):
- """Import annotations from a file."""
- if not hasattr(self, '_import_window'): self._import_window = ImportWindow(self)
- self._import_window.show()
-
- def __export(self):
- """Export annotations to a file."""
-
- filename, ffilter = QFileDialog.getSaveFileName(parent=self,
- caption="Export annotations file",
- directory="untitled.csv",
- filter="CSV Files (*.csv);;CSV Matrix Files (*.csv)",
- options=QFileDialog.DontUseNativeDialog)
-
- filename = str(filename)
- ffilter = str(ffilter)
- if filename != "":
- with open(filename, 'w') as csvfile:
- spamwriter = csv.writer(csvfile, dialect='excel')
- if ffilter == 'CSV Files (*.csv)':
- self._time.export_csv(spamwriter)
- elif ffilter == 'CSV Matrix Files (*.csv)':
- self._time.export_2_csv_matrix(spamwriter)
-
- def __export_2_csv_matrix(self):
- QMessageBox.warning(
- self, "Important!", 'Please note that this file cannot be imported after.')
-
- filename = QFileDialog.getSaveFileName(parent=self,
- caption="Export matrix file",
- directory="untitled.csv",
- filter="CSV Files (*.csv)",
- options=QFileDialog.DontUseNativeDialog)
- if filename != "":
- with open(filename, 'w') as csvfile:
- spamwriter = csv.writer(csvfile, dialect='excel')
- self._time.export_2_csv_matrix(spamwriter)
-
- def __cleanLine(self):
- reply = QMessageBox.question(self, 'Confirm',
- "Are you sure you want to clean all the events on this track?",
- QMessageBox.Yes |
- QMessageBox.No, QMessageBox.No)
- if reply == QMessageBox.Yes:
- self._time.cleanLine(self._time.current_mouseover_track)
-
- def __cleanCharts(self):
- reply = QMessageBox.question(self, 'Confirm',
- "Are you sure you want to clean all the charts?", QMessageBox.Yes |
- QMessageBox.No, QMessageBox.No)
- if reply == QMessageBox.Yes:
- self._time.cleanCharts()
-
- def clean(self):
- reply = QMessageBox.question(self, 'Confirm',
- "Are you sure you want to clean everything?", QMessageBox.Yes |
- QMessageBox.No, QMessageBox.No)
- if reply == QMessageBox.Yes:
- self._time.clean()
-
- def __pickColor(self):
- self._time.color = QColorDialog.getColor(self._time.color)
- if self._time._selected != None:
- self._time._selected.color = self._time.color
- self._time.repaint()
-
- def __scaleSliderChange(self, value):
- scale = 0.1 * value
- self._time.setMinimumWidth(scale * self._max)
- self._time.scale = scale
- self._zoomLabel.setText(str(value * 10).zfill(3) + "%")
-
- def __scrollAreaKeyReleaseEvent(self, event):
- modifiers = int(event.modifiers())
- self._time.keyReleaseEvent(event)
- if modifiers is not QtCore.Qt.ControlModifier and \
- modifiers is not int(QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier) and \
- modifiers is not QtCore.Qt.ShiftModifier:
- QScrollArea.keyReleaseEvent(self._scrollArea, event)
-
- def __scrollAreaKeyPressEvent(self, event):
- modifiers = int(event.modifiers())
- if modifiers is not QtCore.Qt.ControlModifier and \
- modifiers is not int(QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier) and \
- modifiers is not QtCore.Qt.ShiftModifier:
- QScrollArea.keyPressEvent(self._scrollArea, event)
diff --git a/pyforms/gui/Controls/ControlEventTimeline/graphs_eventsgenerator.py b/pyforms/gui/Controls/ControlEventTimeline/graphs_eventsgenerator.py
deleted file mode 100644
index 9a55b45..0000000
--- a/pyforms/gui/Controls/ControlEventTimeline/graphs_eventsgenerator.py
+++ /dev/null
@@ -1,128 +0,0 @@
-import csv, sys
-from pyforms import BaseWidget
-from pyforms.Controls import ControlProgress
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlList
-from pyforms.Controls import ControlNumber
-from pyforms.Controls import ControlSlider
-from pyforms.Controls import ControlTextArea
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlNumber
-from pyforms.Controls import ControlLabel
-
-import time
-import datetime
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QMessageBox
-else:
- from PyQt4.QtGui import QMessageBox
-
-
-
-class GraphsEventsGenerator(BaseWidget):
-
- def __init__(self, timeline=None):
- super(GraphsEventsGenerator, self).__init__('Apply a function to the graph values', parent_win=timeline)
- self.setContentsMargins(10, 10, 10, 10)
- self._timeline = timeline
-
-
- # Definition of the forms fields
- self._graphs_list = ControlList('Graphs list (try double click)')
- self._equation = ControlTextArea('Equation')
- self._graphname = ControlText('Graph name')
- self._genevts_btn = ControlButton('Generate graph')
-
-
- self._formset = [
- (
- ['_graphs_list'],
- '||',
- [
- '_graphname',
- '_equation',
- '_genevts_btn',
- ]
- ),
- ]
-
- self._graphs_list.cell_double_clicked_event = self.__cell_double_clicked_evt
- self._graphs_list.readonly = True
- self._graphs_list.select_entire_row = True
- self._genevts_btn.value = self.__generage_events_evt
-
-
-
- def __add__(self, other):
- self._graphs_list += [other.name]
- return self
-
- def __sub__(self, other):
- self._graphs_list -= other
- return self
-
- def rename_graph(self, graph_index, newname):
- self._graphs_list.set_value(graph_index, 0, newname)
-
- @property
- def graphs(self):
- return self._timeline._charts
-
- def show(self):
- super(GraphsEventsGenerator, self).show()
-
- if len(self._graphname.value.strip())==0:
- self._graphname.value = "generated-graph-{0}".format( len(self._timeline.graphs))
-
-
-
- def __cell_double_clicked_evt(self, row, column):
- if len(self._equation.value.strip())==0:
- self._equation.value += '[{0}]'.format( self._graphs_list.value[row][column] )
- else:
- self._equation.value += ' and [{0}]'.format( self._graphs_list.value[row][column] )
-
-
- def __generage_events_evt(self):
- if len(self._graphname.value.strip())==0:
- QMessageBox.warning(
- self, "Attention!", 'The graph name cannot be empty')
- return
-
- if len(self._equation.value.strip())==0:
- QMessageBox.warning(
- self, "Attention!", 'The equation cannot be empty')
- return
-
- max_frame = 0
- equation = self._equation.value
- for i, values in enumerate(self._graphs_list.value):
- graphname = '[{0}]'.format(values[0])
-
- if graphname in equation: max_frame = max(max_frame, len(self.graphs[i]))
-
- equation = equation.replace(graphname, 'graphs[{0}][i]'.format(i) )
-
- graphs = self.graphs
- data = []
- try:
- for i in range(max_frame):
- data.append( (i, eval(equation)) )
- self._timeline.add_chart(self._graphname.value, data)
-
- self._graphname.value = "generated-graph-{0}".format( len(self._timeline.graphs))
- except Exception as e:
- QMessageBox.warning( self, "Error!", str(e) )
-
-
-##################################################################################################################
-##################################################################################################################
-##################################################################################################################
-
-# Execute the application
-if __name__ == "__main__":
- import pyforms
- pyforms.start_app(GraphsEventsGenerator, geometry=(0, 0, 600, 400))
diff --git a/pyforms/gui/Controls/ControlEventTimeline/import_window.py b/pyforms/gui/Controls/ControlEventTimeline/import_window.py
deleted file mode 100644
index b76c53b..0000000
--- a/pyforms/gui/Controls/ControlEventTimeline/import_window.py
+++ /dev/null
@@ -1,163 +0,0 @@
-import csv
-from pyforms import BaseWidget
-from pyforms.Controls import ControlProgress
-from pyforms.Controls import ControlCombo
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlEmptyWidget
-from pyforms.Controls import ControlFile
-from pyforms.Controls import ControlNumber
-
-
-import time
-import datetime
-
-
-class BonsaiImportFileDlg(BaseWidget):
-
- def __init__(self, timeline=None):
- super(BonsaiImportFileDlg, self).__init__('Import file')
-
- self._file = ControlFile('File to import')
- self._fps = ControlNumber('Video FPS', 30)
-
- self._formset = [('_fps', '_file')]
-
- #self._file.value = '/home/ricardo/Desktop/rat1e2.csv'
-
-
-class ImportWindow(BaseWidget):
-
- def __init__(self, timeline=None):
- super(ImportWindow, self).__init__('Import file', parent_win=timeline)
- self.setContentsMargins(10, 10, 10, 10)
- self._timeline = timeline
-
- # Definition of the forms fields
- self._filetype = ControlCombo('Please select the type of file you would like to import:')
- self._importButton = ControlButton('Import')
- self._panel = ControlEmptyWidget('Panel')
- self._file = ControlFile('File to import')
-
- self._panel.value = self._file
- self._filetype.add_item('Events file', 0)
- self._filetype.add_item('Graph file', 1)
- self._filetype.add_item('Bonsai events file', 2)
-
- self._formset = [
- ('_filetype', ' '),
- '_panel',
- (' ', '_importButton'), ' ']
-
- self._filetype.changed_event = self.__fileTypeChanged
- self._importButton.value = self.__importData
-
- from pyforms.gui.dialogs.csv_parser import CsvParserDialog
- self._graphCsvParserDlg = CsvParserDialog()
- self._graphCsvParserDlg.xField.label = "Value column"
- self._graphCsvParserDlg.yField.hide()
- self._graphCsvParserDlg.zField.hide()
- self._graphCsvParserDlg.loadButton.hide()
-
- self._bonsaiImportDlg = BonsaiImportFileDlg()
-
- def __fileTypeChanged(self):
- if self._filetype.value == 0:
- self._panel.value = self._file
-
- elif self._filetype.value == 1:
- self._panel.value = self._graphCsvParserDlg
-
- elif self._filetype.value == 2:
- self._panel.value = self._bonsaiImportDlg
-
- def __importData(self):
- if self._filetype.value == 0:
- separator = ','
- with open(self._file.value, 'rU') as csvfile:
- line = csvfile.readline()
- if ";" in line:
- separator = ';'
- with open(self._file.value, 'rU') as csvfile:
- csvfile = csv.reader(csvfile, delimiter=separator)
- self._timeline._time.import_csv(csvfile)
-
- elif self._filetype.value == 1:
- self._timeline._time.importchart_csv(self._graphCsvParserDlg)
- self._timeline.show_graphs_properties()
-
- elif self._filetype.value == 2:
- with open(self._bonsaiImportDlg._file.value, 'rU') as csvfile:
- values = []
- pointEventValues = []
- csvfile = csv.reader(csvfile, delimiter=' ')
- for row in csvfile: # strip Start/End word from all events names which are not PointEven
- try:
- timestr = row[1].rstrip('0')
- cvttime = datetime.datetime.strptime(timestr, "%H:%M:%S.%f")
- except:
- timestr = row[1]
- cvttime = datetime.datetime.strptime(timestr, "%H:%M:%S")
-
- seconds = (cvttime - datetime.datetime(1900, 1, 1)).total_seconds()
- frame = int(round(self._bonsaiImportDlg._fps.value * seconds))
-
- if row[2] == "PointEvent":
- eventtype = row[0]
- pointEventValues.append([eventtype, frame, row[2]])
- else:
- if row[0].startswith('Start'):
- eventtype = row[0][len('Start'):] # strip Start word from the beginning
- else:
- eventtype = row[0][len('End'):] # strip End word from the beginning
- values.append([eventtype, frame, row[2]])
-
- values = sorted(values, key=lambda x: (x[0].capitalize(), x[1]))
- pointEventValues = sorted(pointEventValues, key=lambda x: (x[0].capitalize(), x[1]))
- ntracks = len(set([x[0] for x in values])) + 1
-
- # collapse
- events = []
- eventsTypes = {} # Events names
- currentTrack = 0
- for index in range(0, len(pointEventValues)):
- pointEventValue = pointEventValues[index]
- eventsTypes[pointEventValue[0]] = currentTrack
- self._timeline.addPeriod([pointEventValue[1], pointEventValue[1] + 50, pointEventValue[0]], track=currentTrack)
-
- currentTrack = 1
-
- for index in range(0, len(values), 2):
- row0 = values[index]
- row1 = values[index + 1]
-
- if row0[0] not in eventsTypes:
- eventsTypes[row0[0]] = currentTrack
- track = currentTrack
- currentTrack += 1
- else:
- track = eventsTypes[row0[0]]
-
- self._timeline.addPeriod([row0[1], row1[1], row0[0]], track=track)
-
- self._timeline.repaint()
- self._timeline._time.repaint()
- self.close() # pylint: disable=no-member
-
-
- def import_chart(self, filename, frame_col=0, val_col=1):
- self._filetype.value = 1
- self._graphCsvParserDlg.filename = filename
- self._graphCsvParserDlg.frameColumn = frame_col
- self._graphCsvParserDlg.xColumn = val_col
-
-
-
-
-##################################################################################################################
-##################################################################################################################
-##################################################################################################################
-
-# Execute the application
-if __name__ == "__main__":
- import pyforms
- pyforms.start_app(ImportWindow, geometry=(0, 0, 600, 400))
diff --git a/pyforms/gui/Controls/ControlList.py b/pyforms/gui/Controls/ControlList.py
deleted file mode 100755
index c6c59bd..0000000
--- a/pyforms/gui/Controls/ControlList.py
+++ /dev/null
@@ -1,385 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-""" pyforms.gui.Controls.ControlList
-
-"""
-import logging
-import os
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QWidget
- from PyQt5.QtWidgets import QTableWidgetItem
- from PyQt5.QtWidgets import QAbstractItemView
- from PyQt5.QtGui import QIcon
- from PyQt5 import uic
- from PyQt5 import QtCore
- from PyQt5.QtCore import Qt
-
-else:
- from PyQt4.QtGui import QWidget
- from PyQt4.QtGui import QTableWidgetItem
- from PyQt4.QtGui import QAbstractItemView
- from PyQt4.QtGui import QIcon
- from PyQt4 import uic
- from PyQt4 import QtCore
- from PyQt4.QtCore import Qt
-
-from pyforms.gui.BaseWidget import BaseWidget
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-logger = logging.getLogger(__name__)
-
-
-class ControlList(ControlBase, QWidget):
- """ This class represents a wrapper to the table widget
- It allows to implement a list view
- """
-
- CELL_VALUE_BEFORE_CHANGE = None # store value when cell is double clicked
-
- def __init__(self, label="", default="", add_function=None,
- remove_function=None):
- QWidget.__init__(self)
-
- self._plusFunction = add_function
- self._minusFunction = remove_function
- ControlBase.__init__(self, label, default)
-
- ##########################################################################
- ############ FUNCTIONS ###################################################
- ##########################################################################
-
- def init_form(self):
- plusFunction = self._plusFunction
- minusFunction = self._minusFunction
-
- # Get the current path of the file
- rootPath = os.path.dirname(__file__)
- # Load the UI for the self instance
- uic.loadUi(os.path.join(rootPath, "list.ui"), self)
-
- self.label = self._label
-
- self.tableWidget.currentCellChanged.connect(
- self.tableWidgetCellChanged)
- self.tableWidget.currentItemChanged.connect(
- self.tableWidgetItemChanged)
- self.tableWidget.itemSelectionChanged.connect(
- self.tableWidgetItemSelectionChanged)
- self.tableWidget.cellDoubleClicked.connect(self.tableWidgetCellDoubleClicked)
- self.tableWidget.model().dataChanged.connect(self._dataChangedEvent)
-
- if plusFunction is None and minusFunction is None:
- self.bottomBar.hide()
- elif plusFunction is None:
- self.plusButton.hide()
- self.minusButton.pressed.connect(minusFunction)
- elif minusFunction is None:
- self.minusButton.hide()
- self.plusButton.pressed.connect(plusFunction)
- else:
- self.plusButton.pressed.connect(plusFunction)
- self.minusButton.pressed.connect(minusFunction)
-
- def __repr__(self):
- return "ControlList " + str(self._value)
-
- def clear(self, headers=False):
-
- for row in range(self.rows_count):
- columns = []
- for column in range(self.columns_count):
- v = self.get_value(column, row)
- if isinstance(v, BaseWidget):
- v.destroy()
-
- if headers:
- self.tableWidget.clear()
- self.tableWidget.setColumnCount(3)
- self.tableWidget.setRowCount(0)
- else:
- self.tableWidget.clearContents()
- self.tableWidget.setRowCount(0)
-
- def save_form(self, data, path=None):
- if self.value:
- rows = []
- for row in range(self.rows_count):
- columns = []
- for column in range(self.columns_count):
- v = self.get_value(column, row)
- if isinstance(v, BaseWidget):
- columns.append(v.save({}))
- else:
- columns.append(str(v))
- rows.append(columns)
- data['value'] = rows
- return data
-
- def load_form(self, data, path=None):
- if self.value:
- rows = data['value']
- for row in range(len(rows)):
- for column in range(len(rows[row])):
- v = self.get_value(column, row)
- if isinstance(v, BaseWidget):
- v.load(rows[row][column])
- else:
- self.set_value(column, row, rows[row][column])
- elif 'value' in data.keys():
- self.value = data['value']
-
- def __add__(self, other):
-
- row = self.tableWidget.rowCount()
-
- self.tableWidget.insertRow(row)
- if self.tableWidget.currentColumn() < len(other):
- self.tableWidget.setColumnCount(len(other))
-
- for column, e in enumerate(other): self.set_value(column, row, e)
-
- self.tableWidget.resizeColumnsToContents()
- return self
-
- def __sub__(self, other):
-
- if isinstance(other, int):
- if other < 0:
- indexToRemove = self.tableWidget.currentRow()
- else:
- indexToRemove = other
-
- self.tableWidget.removeRow(indexToRemove)
- return self
-
- def set_value(self, column, row, value):
- if isinstance(value, QWidget):
- self.tableWidget.setCellWidget(row, column, value)
- value.show()
- self.tableWidget.setRowHeight(row, value.height())
- else:
- args = [value] if not hasattr(value, 'icon') else [QIcon(value.icon), value]
- item = QTableWidgetItem()
- item.setData(Qt.EditRole, *args)
- self.tableWidget.setItem(row, column, item)
-
- def get_value(self, column, row):
- try:
- return str(self.tableWidget.item(row, column).text())
- except AttributeError as err:
- return self.tableWidget.cellWidget(row, column)
- except AttributeError as err:
- return ''
-
- def resize_rows_contents(self):
- self.tableWidget.resizeRowsToContents()
-
- def get_currentrow_value(self):
- currentRow = self.tableWidget.currentRow()
- if not currentRow < 0:
- return self.value[currentRow]
- else:
- return []
-
- def get_cell(self, column, row):
- return self.tableWidget.item(row, column)
-
- def set_sorting_enabled(self, value):
- """
- Enable or disable columns sorting
-
- :param bool value: True to enable sorting, False otherwise
- """
- self.tableWidget.setSortingEnabled(value)
-
- ##########################################################################
- ############ EVENTS ######################################################
- ##########################################################################
-
- def data_changed_event(self, row, col, item):
- pass
-
- def item_selection_changed_event(self):
- pass
-
- def current_cell_changed_event(self, next_row, next_col, previous_row, previous_col):
- pass
-
- def current_item_changed_event(self, current, previous):
- pass
-
- def cell_double_clicked_event(self, row, column):
- pass
-
- ##########################################################################
- ############ PROPERTIES ##################################################
- ##########################################################################
-
-
- @property
- def horizontal_headers(self):
- return self._horizontalHeaders
-
- @horizontal_headers.setter
- def horizontal_headers(self, horizontal_headers):
- """Set horizontal headers in the table list."""
-
- self._horizontalHeaders = horizontal_headers
-
- self.tableWidget.setColumnCount(len(horizontal_headers))
- self.tableWidget.horizontalHeader().setVisible(True)
-
- for idx, header in enumerate(horizontal_headers):
- item = QTableWidgetItem()
- item.setText(header)
- self.tableWidget.setHorizontalHeaderItem(idx, item)
-
- @property
- def word_wrap(self):
- return self.tableWidget.wordWrap()
-
- @word_wrap.setter
- def word_wrap(self, value):
- self.tableWidget.setWordWrap(value)
-
- @property
- def readonly(self):
- return self.tableWidget.editTriggers()
-
- @readonly.setter
- def readonly(self, value):
- if value:
- self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
- else:
- self.tableWidget.setEditTriggers(QAbstractItemView.AllEditTriggers)
-
- @property
- def select_entire_row(self):
- return self.tableWidget.selectionBehavior()
-
- @select_entire_row.setter
- def select_entire_row(self, value):
- if value:
- self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
- else:
- self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectItems)
-
- @property
- def rows_count(self):
- return self.tableWidget.rowCount()
-
- @property
- def columns_count(self):
- return self.tableWidget.columnCount()
-
- def __len__(self):
- return self.rows_count
-
- @property
- def value(self):
- if hasattr(self, 'tableWidget'):
- results = []
- for row in range(self.tableWidget.rowCount()):
- r = []
- for col in range(self.tableWidget.columnCount()):
- try:
- r.append(self.get_value(col, row))
- except Exception as err:
- logger.debug(str(err))
- r.append("")
- results.append(r)
- return results
- return self._value
-
- @value.setter
- def value(self, value):
- self.clear()
- for row in value: self += row
-
- # TODO: implement += on self.value? I want to add a list of tuples to
- # self.value
-
- @property
- def selected_rows_indexes(self):
- result = []
- for index in self.tableWidget.selectedIndexes():
- result.append(index.row())
- return list(set(result))
-
- @property
- def selected_row_index(self):
- indexes = self.selected_rows_indexes
- if len(indexes) > 0:
- return indexes[0]
- else:
- return None
-
- @property
- def label(self):
- return self.labelWidget.getText()
-
- @label.setter
- def label(self, value):
- if value != '':
- self.labelWidget.setText(value)
- else:
- self.labelWidget.hide()
-
- @property
- def form(self):
- return self
-
- @property
- def icon_size(self):
- return self.tableWidget.iconSize()
-
- @icon_size.setter
- def icon_size(self, value):
- if isinstance(value, (tuple, list)):
- self.tableWidget.setIconSize(QtCore.QSize(*value))
- else:
- self.tableWidget.setIconSize(QtCore.QSize(value, value))
-
- ##########################################################################
- ############ PRIVATE FUNCTIONS ###########################################
- ##########################################################################
-
- def _dataChangedEvent(self, item):
- self.data_changed_event(item.row(), item.column(), self.tableWidget.model().data(item))
- self.changed_event()
-
- def tableWidgetCellChanged(self, nextRow, nextCol, previousRow,
- previousCol):
- self.current_cell_changed_event(nextRow, nextCol, previousRow, previousCol)
- self.changed_event()
-
- def tableWidgetItemChanged(self, current, previous):
- self.current_item_changed_event(current, previous)
- self.changed_event()
-
- def tableWidgetItemSelectionChanged(self):
- self.item_selection_changed_event()
-
- def tableWidgetCellDoubleClicked(self, row, column):
- """
- (From PyQt) This signal is emitted whenever a cell in the table is double clicked.
- The row and column specified is the cell that was double clicked.
-
- Besides firing this signal, we save the current value, in case the user needs to know the old value.
- :param row:
- :param column:
- :return:
- """
- self.CELL_VALUE_BEFORE_CHANGE = self.get_value(column, row)
- logger.debug("Cell double clicked. Stored value: %s", self.CELL_VALUE_BEFORE_CHANGE)
- self.cell_double_clicked_event(row, column)
-
- def empty_signal(self, *args, **kwargs):
- """
- Use this function if you want to disconnect a signal temporarily
- """
- pass
diff --git a/pyforms/gui/Controls/ControlOpenGL.py b/pyforms/gui/Controls/ControlOpenGL.py
deleted file mode 100644
index c12b840..0000000
--- a/pyforms/gui/Controls/ControlOpenGL.py
+++ /dev/null
@@ -1,255 +0,0 @@
-# !/usr/bin/python
-# -*- coding: utf-8 -*-
-
-import logging
-
-from pysettings import conf
-
-logger = logging.getLogger(__name__)
-
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QSizePolicy
-
- try:
- from OpenGL.GL import *
- from OpenGL.GLU import *
- from PyQt5.QtOpenGL import QGLWidget
- except:
- logger.debug("No OpenGL library available")
-
-else:
- from PyQt4.QtGui import QSizePolicy
-
- try:
- from OpenGL.GL import *
- from OpenGL.GLU import *
- from PyQt4.QtOpenGL import QGLWidget
- except:
- logger.debug("No OpenGL library available")
-
-
-class OpenglGLWidget(QGLWidget):
- def __init__(self, parent=None):
- QGLWidget.__init__(self, parent)
-
- self._zoom = 1.0
- self._scene = None
- self._rotation = [0, 0, 0]
-
- self._mouseLeftDown = False
- self._mouseRightDown = False
-
- self._mouseGLPosition = [0, 0, 0]
- self._lastMouseGLPosition = [0, 0, 0]
-
- self._mousePosition = [0, 0] # Current mouse position
- self._lastMousePosition = [0, 0] # Last mouse position
-
- self._mouseStartDragPoint = None
- self._clear_color = None
-
- self.setMinimumHeight(100)
- self.setMinimumWidth(100)
- self.setMouseTracking(True)
- self.setAcceptDrops(True)
-
- self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding);
-
- def initializeGL(self):
- glClearDepth(1.0)
- if self._clear_color: glClearColor(*self._clear_color)
- glEnable(GL_BLEND)
- glBlendFunc(GL_SRC_ALPHA, GL_ONE)
-
- glEnable(GL_POINT_SMOOTH);
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_POLYGON_SMOOTH);
- glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
- glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
- glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
-
- def resizeGL(self, width, height):
- """
-
- :param width:
- :param height:
- :return:
- """
- glViewport(0, 0, width, height)
- glMatrixMode(GL_PROJECTION)
- glLoadIdentity()
- gluPerspective(65.0, float(width) / float(height), 0.01, 800.0)
-
- def paintGL(self):
- """
-
- """
- if self._clear_color:
- glBlendFunc(GL_ONE_MINUS_CONSTANT_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
- glClearColor(*self._clear_color)
- else:
- glBlendFunc(GL_SRC_ALPHA, GL_ONE)
- glClearColor(0, 0, 0, 1)
-
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
- glMatrixMode(GL_MODELVIEW)
- glLoadIdentity()
-
- glEnable(GL_BLEND)
-
- glScalef(1, -1, -1)
-
- glTranslatef(0, 0, self._zoom)
- glRotatef(self._rotation[0], 1, 0, 0)
- glRotatef(self._rotation[1], 0, 1, 0)
- glRotatef(self._rotation[2], 0, 0, 1)
-
- if self._scene != None: self._scene.DrawGLScene()
-
- if self.mouseDown:
- # Get mouse position
- modelview, projection = glGetDoublev(GL_MODELVIEW_MATRIX), glGetDoublev(GL_PROJECTION_MATRIX)
- viewport = glGetIntegerv(GL_VIEWPORT)
- winX, winY = float(self._mousePosition[0]), float(viewport[3] - self._mousePosition[1])
- winZ = glReadPixels(winX, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)
- self._mouseGLPosition = gluUnProject(winX, winY, winZ[0][0], modelview, projection, viewport)
-
- glDisable(GL_BLEND)
-
- def __updateMouse(self, event, pressed=None):
- self._mousePosition[0] = event.x()
- self._mousePosition[1] = event.y()
-
- if pressed != None:
- if event.button() == 2: self._mouseRightDown = pressed
- if event.button() == 1: self._mouseLeftDown = pressed
-
- def wheelEvent(self, event):
- """
-
- :param event:
- """
- if event.delta() < 0:
- self._zoom += 1
- else:
- self._zoom -= 1
-
- self.repaint()
-
- def mouseReleaseEvent(self, event):
- """
-
- :param event:
- """
- self.__updateMouse(event)
-
- if self._mouseRightDown:
- self._lastMouseGLPosition = self._mouseGLPosition
- self._mouseRightDown = False
-
- if self._mouseLeftDown:
- self.onEndDrag(self._mouseStartDragPoint, self._mouseGLPosition)
- self._mouseLeftDown = False
-
- def mousePressEvent(self, event):
- """
-
- :param event:
- """
- QGLWidget.mousePressEvent(self, event)
- self.__updateMouse(event, pressed=True)
- self.repaint()
-
- if self._mouseLeftDown: self._mouseStartDragPoint = self._mouseGLPosition
- if self._mouseRightDown: self._lastMouseGLPosition = self._mouseGLPosition
-
- self.onPress(event.button(), self._mousePosition, self._mouseGLPosition)
-
- def mouseMoveEvent(self, event):
- """
-
- :param event:
- """
- QGLWidget.mouseMoveEvent(self, event)
- self.__updateMouse(event)
- self.repaint()
-
- self.onMove((self._mouseGLPosition[0], self._mouseGLPosition[1]))
-
- if self.mouseDown:
- if self._mouseLeftDown:
- # p = self._mouseGLPosition[0] - self._x, self._mouseGLPosition[1] + self._y
- # p = self._mouseGLPosition[0], self._mouseGLPosition[1]
- self.onDrag(self._lastMousePosition, self._mousePosition)
-
- self._lastMousePosition = list(self._mousePosition)
-
- def onMove(self, point):
- pass
-
- def onPress(self, button, point, glpoint=None):
- pass
-
- def onDrag(self, startPoint, endPoint, startGLPoint=None, endGLPoint=None):
- """
-
- :param startPoint:
- :param endPoint:
- :param startGLPoint:
- :param endGLPoint:
- """
- movX, movY = endPoint[0] - startPoint[0], endPoint[1] - startPoint[1]
- self._rotation[2] -= float(movX) * 0.15
- self._rotation[0] += float(movY) * 0.15
-
- def onEndDrag(self, startPoint, endPoint, startGLPoint=None, endGLPoint=None):
- pass
-
- ##############################################################################
- ###### Properties ############################################################
- ##############################################################################
-
- @property
- def scene(self):
- return self._scene
-
- @scene.setter
- def scene(self, value):
- self._scene = value
-
- @property
- def mouseDown(self):
- return self._mouseLeftDown or self._mouseRightDown
-
- def resetZoomAndRotation(self):
- self._zoom, self._rotation = 0.0, [0, 0, 0]
-
-
-class ControlOpenGL(ControlBase):
- def init_form(self): self._form = OpenglGLWidget()
-
- def repaint(self): self._form.repaint()
-
- def reset_zoom_and_rotation(self): self._form.resetZoomAndRotation()
-
- @property
- def value(self): return self._form.scene
-
- @value.setter
- def value(self, value): self._form.scene = value; self._form.repaint()
-
- @property
- def clear_color(self): self._form._clear_color
-
- @clear_color.setter
- def clear_color(self, value):
- self._form._clear_color = value;
- self._form.repaint()
-
- @property
- def width(self): return self._form.width()
-
- @property
- def height(self): return self._form.height()
diff --git a/pyforms/gui/Controls/ControlPlayer/VideoGLWidget.py b/pyforms/gui/Controls/ControlPlayer/VideoGLWidget.py
deleted file mode 100644
index 9804e51..0000000
--- a/pyforms/gui/Controls/ControlPlayer/VideoGLWidget.py
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-""" pyforms.gui.Controls.ControlPlayer.VideoGLWidget
-
-"""
-
-from pyforms.gui.Controls.ControlPlayer.AbstractGLWidget import AbstractGLWidget
-
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtOpenGL import QGLWidget
-else:
- from PyQt4.QtOpenGL import QGLWidget
-
-class VideoGLWidget(AbstractGLWidget, QGLWidget): pass
\ No newline at end of file
diff --git a/pyforms/gui/Controls/ControlTextArea.py b/pyforms/gui/Controls/ControlTextArea.py
deleted file mode 100755
index 0af7adc..0000000
--- a/pyforms/gui/Controls/ControlTextArea.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-import pyforms.utils.tools as tools
-from pysettings import conf
-if conf.PYFORMS_USE_QT5:
- from PyQt5 import uic
-else:
- from PyQt4 import uic
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-__author__ = "Ricardo Ribeiro"
-__credits__ = ["Ricardo Ribeiro"]
-__license__ = "MIT"
-__version__ = "0.0"
-__maintainer__ = "Ricardo Ribeiro"
-__email__ = "ricardojvr@gmail.com"
-__status__ = "Development"
-
-
-class ControlTextArea(ControlBase):
-
- def init_form(self):
- control_path = tools.getFileInSameDirectory(__file__, "textArea.ui")
- self._form = uic.loadUi(control_path)
- self._form.label.setText(self._label)
- if self._value:
- self._form.plainTextEdit.setPlainText(str(self._value))
-
- if not self._label or len(self._label)==0:
- self.form.label.hide()
-
- super(ControlTextArea, self).init_form()
- self.form.plainTextEdit.textChanged.connect(self.finishEditing)
-
- def __add__(self, other):
- self._form.plainTextEdit.appendPlainText(str(other))
- return self
-
- def finishEditing(self):
- """Function called when the lineEdit widget is edited"""
- self.changed_event()
-
-
- @property
- def value(self):
- return self._form.plainTextEdit.toPlainText()
-
- @value.setter
- def value(self, value):
- self._form.plainTextEdit.setPlainText(str(value))
-
- @property
- def readonly(self):
- return self._form.plainTextEdit.isReadOnly()
-
- @readonly.setter
- def readonly(self, value):
- self._form.plainTextEdit.setReadOnly(value)
diff --git a/pyforms/gui/Controls/ControlTreeView.py b/pyforms/gui/Controls/ControlTreeView.py
deleted file mode 100644
index 1ac261c..0000000
--- a/pyforms/gui/Controls/ControlTreeView.py
+++ /dev/null
@@ -1,133 +0,0 @@
-# !/usr/bin/python
-# -*- coding: utf-8 -*-
-
-from pysettings import conf
-
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QTreeView, QAbstractItemView
- from PyQt5.QtGui import QStandardItem, QStandardItemModel
-
-else:
- from PyQt4.QtGui import QTreeView, QAbstractItemView, QStandardItem, QStandardItemModel
-
-
-class ControlTreeView(ControlBase, QTreeView):
- def __init__(self, title='untitled'):
- QTreeView.__init__(self)
- ControlBase.__init__(self, title)
-
- def init_form(self):
- self.setSelectionBehavior(QAbstractItemView.SelectRows)
- self.header().hide()
- self.setUniformRowHeights(True)
- self.setDragDropMode(QAbstractItemView.InternalMove)
- self.setDragEnabled(True)
- self.setAcceptDrops(True)
-
- self.setModel(QStandardItemModel())
- self.model().itemChanged.connect(self.__item_changed_event)
-
- self.selectionChanged = self.selectionChanged
-
- # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- # populate data
- """
- for i in range(3):
- parent1 = QtGui.QStandardItem('Family {}. Some long status text for sp'.format(i))
- for j in range(3):
- child1 = QtGui.QStandardItem('Child {}'.format(i*3+j))
- parent1.appendRow(child1)
- model().appendRow(parent1)
- # span container columns
- view.setFirstColumnSpanned(i, view.rootIndex(), True)
- """
-
- def __item_changed_event(self, item):
- self.item_changed_event(item)
-
- def item_changed_event(self, item):
- pass
-
- def item_selection_changed_event(self):
- pass
-
- def selectionChanged(self, selected, deselected):
- super(QTreeView, self.form).selectionChanged(selected, deselected)
- self.item_selection_changed_event()
-
- @property
- def mouseSelectedRowsIndexes(self):
- result = []
- for index in self.form.selectedIndexes():
- result.append(index.row())
- return list(set(result))
-
- @property
- def selected_row_index(self):
- indexes = self.mouseSelectedRowsIndexes
- if len(indexes) > 0:
- return indexes[0]
- else:
- return None
-
- @property
- def selectedItem(self):
- for index in self.form.selectedIndexes():
- item = index.model().itemFromIndex(index)
- return item
- else:
- return None
-
- @property
- def cells(self):
- results = []
- for row in range(self._model().rowCount()):
- r = []
- for col in range(self._model().columnCount()):
- r.append(self._model().item(row, col))
- if len(r) > 0: results.append(r)
- # print r, '---'
-
- return results
-
- def __add__(self, other):
- if isinstance(other, TreeItem):
- self._model().invisibleRootItem().appendRow(other)
-
- elif isinstance(other, list):
- for x in other:
- item = QStandardItem(x)
- self._model().appendRow(item)
- else:
- item = QStandardItem(other)
- self._model().appendRow(item)
-
- self.form.setFirstColumnSpanned(self._model().rowCount() - 1, self.form.rootIndex(), True)
- return self
-
- def __sub__(self, other):
- if isinstance(other, int):
- if other < 0:
- indexToRemove = self.selected_row_index
- else:
- indexToRemove = other
- self.model().removeRow(indexToRemove)
- return self
-
- @property
- def value(self):
- return self.form.model().invisibleRootItem()
- return self.recursivelyReadRoot(root)
-
- @value.setter
- def value(self, value):
- for row in value: self += row
-
- def getAllSceneObjects(self):
- return self._model().getChildrens()
-
- @property
- def form(self):
- return self
diff --git a/pyforms/gui/Controls/ControlWeb.py b/pyforms/gui/Controls/ControlWeb.py
deleted file mode 100644
index afe3247..0000000
--- a/pyforms/gui/Controls/ControlWeb.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-__author__ = "Ricardo Ribeiro"
-__credits__ = ["Ricardo Ribeiro"]
-__license__ = "MIT"
-__version__ = "0.0"
-__maintainer__ = "Ricardo Ribeiro"
-__email__ = "ricardojvr@gmail.com"
-__status__ = "Development"
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWebEngineWidgets import QWebEngineView as QWebView
- from PyQt5.QtCore import QUrl
-else:
- from PyQt4.QtCore import QUrl
- from PyQt4.QtWebKit import QWebView
-
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-
-class ControlWeb(ControlBase, QWebView):
- def __init__(self, label=""):
- QWebView.__init__(self)
- ControlBase.__init__(self, label)
-
- ############################################################################
- ############ Properties ####################################################
- ############################################################################
-
- @property
- def value(self): return ControlBase.value.fget(self)
-
- @value.setter
- def value(self, value):
- ControlBase.value.fset(self, value)
- QWebView.load(self, QUrl(value))
-
- @property
- def form(self):
- return self
diff --git a/pyforms/gui/Controls/comboInput.ui b/pyforms/gui/Controls/comboInput.ui
deleted file mode 100755
index 7c06100..0000000
--- a/pyforms/gui/Controls/comboInput.ui
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 169
- 38
-
-
-
-
- 0
- 38
-
-
-
-
- 16777215
- 38
-
-
-
- Form
-
-
-
- 0
-
- -
-
-
- TextLabel
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
-
-
-
diff --git a/pyforms/gui/Controls/dbquery.ui b/pyforms/gui/Controls/dbquery.ui
deleted file mode 100755
index 67f380f..0000000
--- a/pyforms/gui/Controls/dbquery.ui
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 471
- 168
-
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
-
- 16777215
- 16777215
-
-
-
- Form
-
-
-
- 0
-
-
- 0
-
- -
-
-
- QAbstractItemView::SelectRows
-
-
-
-
-
-
-
-
diff --git a/pyforms/gui/Controls/list.ui b/pyforms/gui/Controls/list.ui
deleted file mode 100755
index 3e2ffdf..0000000
--- a/pyforms/gui/Controls/list.ui
+++ /dev/null
@@ -1,131 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 471
- 168
-
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
-
- 16777215
- 16777215
-
-
-
- Form
-
-
-
- 0
-
-
- 0
-
- -
-
-
- TextLabel
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- false
-
-
- Qt::NoPen
-
-
- false
-
-
- 100
-
-
- false
-
-
- true
-
-
- false
-
-
- false
-
-
- false
-
-
-
- -
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 16
- 16
-
-
-
- -
-
-
-
- -
-
-
-
- 16
- 16
-
-
-
- +
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pyforms/gui/Controls/list_with_headers.ui b/pyforms/gui/Controls/list_with_headers.ui
deleted file mode 100644
index 42ad4fd..0000000
--- a/pyforms/gui/Controls/list_with_headers.ui
+++ /dev/null
@@ -1,147 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 471
- 168
-
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
-
- 16777215
- 16777215
-
-
-
- Form
-
-
-
- 0
-
-
- 0
-
- -
-
-
- TextLabel
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- false
-
-
- Qt::NoPen
-
-
- true
-
-
- 100
-
-
- false
-
-
- true
-
-
- false
-
-
- false
-
-
- false
-
-
-
- column1
-
-
-
-
- column2
-
-
-
-
- -
-
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- 16
- 16
-
-
-
- +
-
-
-
- -
-
-
-
- 16
- 16
-
-
-
- -
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pyforms/gui/Controls/table.ui b/pyforms/gui/Controls/table.ui
deleted file mode 100644
index debb4f1..0000000
--- a/pyforms/gui/Controls/table.ui
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 471
- 168
-
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
-
- 16777215
- 16777215
-
-
-
- Form
-
-
-
- 0
-
-
- 0
-
- -
-
-
- TextLabel
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- false
-
-
-
- -
-
-
-
- 0
-
-
- 0
-
-
-
-
-
-
- 16
- 16
-
-
-
- +
-
-
-
- -
-
-
-
- 16
- 16
-
-
-
- -
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pyforms/gui/appmanager.py b/pyforms/gui/appmanager.py
index 768ca5a..4ad5c7c 100644
--- a/pyforms/gui/appmanager.py
+++ b/pyforms/gui/appmanager.py
@@ -1,68 +1,210 @@
-import sys, glob, os
-import logging
-import traceback
-from PyQt4 import uic
-from PyQt4 import QtGui, QtCore
-import pyforms.utils.tools as tools
-
-class Container(object):
- def __init__(self, ClassObject):
-
- self.logger = logging.getLogger('pyforms')
-
- self._algorithm = ClassObject()
- self._algorithm.init_form()
- form_path = os.path.join(tools.get_object_class_path( Container ), 'mainWindow.ui')
- self._form = uic.loadUi( form_path )
- self._form.verticalLayout.addWidget( self._algorithm )
- self._form.verticalLayout.setMargin(10)
- self._form.verticalLayout.setSpacing(0)
-
- if conf.PYFORMS_USE_QT5:
- self._form.verticalLayout.setContentsMargins(10,10,10,10)
- else:
- self._form.verticalLayout.setMargin(10)
-
- self._form.actionExit.triggered.connect( self.actionExit_triggered )
- self._form.show()
- self._form.setWindowTitle( self._algorithm.title )
- self._form.actionStop.setEnabled(False)
- self._form.actionStop.triggered.connect( self.actionStop_triggered )
-
- try:
- getattr(self._algorithm, 'execute')
- self._form.actionRun.triggered.connect( self.actionRun_triggered )
- except:
- self._form.menuAlgorithm.setEnabled(False)
- self._form.actionRun.setEnabled(False)
- self._form.menuAlgorithm.setVisible(False)
- self._form.actionRun.setVisible(False)
-
-
- def actionExit_triggered(self): exit()
- def actionRun_triggered(self):
- self._algorithm.stop = False
- self._form.actionRun.setEnabled(False)
- self._form.actionStop.setEnabled(True)
- try:
- self._algorithm.execute()
- except Exception as err:
- self.logger.warning("Error", exc_info=True)
- self.actionStop_triggered()
-
- def actionStop_triggered(self):
- self._algorithm.stop = True
- self._form.actionRun.setEnabled(True)
- self._form.actionStop.setEnabled(False)
-
-
-
-def start_app(ClassObject):
- from pysettings import conf
-
- app = QtGui.QApplication(sys.argv)
-
- conf += 'pyforms.gui.settings'
-
- container = Container(ClassObject)
- app.exec_()
\ No newline at end of file
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+from pyforms.gui.controls.ControlDockWidget import ControlDockWidget
+from AnyQt.QtWidgets import QMainWindow, QDockWidget, QAction, QApplication, QToolBar
+from AnyQt import QtCore, _api
+from AnyQt.QtGui import QIcon
+
+from pyforms.utils.settings_manager import conf
+import sys, os, platform, logging
+
+logger = logging.getLogger(__name__)
+
+class StandAloneContainer(QMainWindow):
+ def __init__(self, ClassObject):
+ super(QMainWindow, self).__init__()
+
+ w = ClassObject()
+ w.app_main_window = self
+ self._widget = w
+
+ if len(w.mainmenu) > 0:
+ w._mainmenu = self.__initMainMenu(w.mainmenu)
+
+ w.init_form()
+
+ if _api.USED_API == _api.QT_API_PYQT5:
+ self.layout().setContentsMargins(conf.PYFORMS_MAINWINDOW_MARGIN,conf.PYFORMS_MAINWINDOW_MARGIN,conf.PYFORMS_MAINWINDOW_MARGIN,conf.PYFORMS_MAINWINDOW_MARGIN)
+ elif _api.USED_API == _api.QT_API_PYQT4:
+ self.layout().setMargin(conf.PYFORMS_MAINWINDOW_MARGIN)
+
+ self.setCentralWidget(w)
+ self.setWindowTitle(w.title)
+
+ docks = {}
+ for name, item in w.controls.items():
+ if isinstance(item, ControlDockWidget):
+ if item.side not in docks:
+ docks[item.side] = []
+ docks[item.side].append((name, item))
+
+ #Construct the toolbar
+ if len(w.toolbar)>0:
+ tb = QToolBar(self)
+ self.addToolBar(tb)
+ for item in w.toolbar:
+ if isinstance(item, str) and item in ['|','-']:
+ tb.addSeparator()
+ else:
+ tb.addWidget(item.form)
+
+
+ for key, widgets in docks.items():
+ side = QtCore.Qt.RightDockWidgetArea
+ if key == 'left':
+ side = QtCore.Qt.LeftDockWidgetArea
+ elif key == 'right':
+ side = QtCore.Qt.RightDockWidgetArea
+ elif key == 'top':
+ side = QtCore.Qt.TopDockWidgetArea
+ elif key == 'bottom':
+ side = QtCore.Qt.BottomDockWidgetArea
+ else:
+ side = QtCore.Qt.LeftDockWidgetArea
+
+ if isinstance(widgets, list):
+ widgets = sorted(widgets, key=lambda x: x[1].order)
+
+ for name, widget in widgets:
+ dock = QDockWidget(self)
+ dock.setFeatures(
+ QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable)
+ dock.setObjectName(name)
+
+ if _api.USED_API == _api.QT_API_PYQT5:
+ dock.setContentsMargins(0,0,0,0)
+ widget.form.layout().setContentsMargins(widget.margin,widget.margin,widget.margin,widget.margin)
+ elif _api.USED_API == _api.QT_API_PYQT4:
+ dock.setMargin(0)
+ widget.form.layout().setMargin(widget.margin)
+
+ # print dock.objectName(),1
+ dock.setWidget(widget.form)
+ dock.setWindowTitle(widget.label)
+ widget.dock = dock
+ if not widget._show: dock.hide()
+
+ self.addDockWidget(side, dock)
+ else:
+ dock = QDockWidget(self)
+ dock.setFeatures(
+ QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable)
+ # dock.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
+
+ if _api.USED_API == _api.QT_API_PYQT5:
+ widget.form.layout().setContentsMargins(widget.margin,widget.margin,widget.margin,widget.margin)
+ elif _api.USED_API == _api.QT_API_PYQT5:
+ widget.form.layout().setMargin(widget.margin)
+
+ # print dock.objectName(), 2
+ dock.setObjectName(name)
+ dock.setWidget(widget.form)
+ self.addDockWidget(side, dock)
+ dock.setWindowTitle(widget.label)
+ widget.dock = dock
+ if not widget._show: dock.hide()
+
+ if conf.PYFORMS_STYLESHEET:
+ stylesheet_files = [conf.PYFORMS_STYLESHEET]
+
+ p = platform.system()
+ if p == 'Windows' and conf.PYFORMS_STYLESHEET_WINDOWS:
+ stylesheet_files.append(conf.PYFORMS_STYLESHEET_WINDOWS)
+ elif p == 'Darwin' and conf.PYFORMS_STYLESHEET_DARWIN:
+ stylesheet_files.append(conf.PYFORMS_STYLESHEET_DARWIN)
+ elif p == 'Linux' and conf.PYFORMS_STYLESHEET_LINUX:
+ stylesheet_files.append(conf.PYFORMS_STYLESHEET_LINUX)
+
+ logger.debug('Import stylesheets: {0}'.format(stylesheet_files))
+ self.loadStyleSheetFile(stylesheet_files)
+
+
+ def closeEvent(self, event):
+ self._widget.closeEvent(event)
+
+ def __initMainMenu(self, options, keys={}):
+ menubar = self.menuBar()
+ for menuIndex, m in enumerate(options):
+ for key, menus in m.items():
+ menu = menubar.addMenu(key)
+ for subMenuIndex, m1 in enumerate(menus):
+ if isinstance(m1, str) and m1 == "-":
+ menu.addSeparator()
+ else:
+ for text, func in m1.items():
+ if text != 'icon':
+ action = QAction(text, self)
+ if 'icon' in m1.keys():
+ action.setIconVisibleInMenu(True)
+ action.setIcon(QIcon(m1['icon']))
+ if func:
+ action.triggered.connect(func)
+ menu.addAction(action)
+ options[menuIndex][key][subMenuIndex][text] = action
+ break
+ return options
+
+ def loadStyleSheetFile(self, files):
+ content = ''
+ for filename in files:
+ infile = open(filename, 'r')
+ content += infile.read() + '\n'
+ infile.close()
+
+ self.setStyleSheet(content)
+
+
+def execute_test_file(myapp):
+ import argparse
+ parser = argparse.ArgumentParser()
+ parser.add_argument("test_file", help="File with the tests script")
+ args = parser.parse_args()
+
+ with open(args.test_file) as f:
+ global_vars = globals()
+ local_vars = locals()
+ code = compile(f.read(), args.test_file, 'exec')
+ exec(code, global_vars, local_vars)
+
+
+def start_app(ClassObject, geometry=None, stylesheet=None):
+ from pyforms.utils.settings_manager import conf
+
+ app = QApplication(sys.argv)
+
+ conf += 'pyforms.gui.settings'
+
+ mainwindow = StandAloneContainer(ClassObject)
+
+ myapp = mainwindow.centralWidget()
+
+ if geometry is not None:
+ mainwindow.show()
+ mainwindow.setGeometry(*geometry)
+ else:
+ mainwindow.showMaximized()
+
+ if conf.PYFORMS_QUALITY_TESTS_PATH is not None:
+ import argparse
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--test", help="File with the tests script")
+ args = parser.parse_args()
+
+ if args.test:
+ TEST_PATH = os.path.join(conf.PYFORMS_QUALITY_TESTS_PATH, args.test)
+ TEST_FILE_PATH = os.path.join(TEST_PATH, args.test + '.py')
+ DATA_PATH = os.path.join(TEST_PATH, 'data', sys.platform)
+ INPUT_DATA_PATH = os.path.join(DATA_PATH, 'input-data')
+ OUTPUT_DATA_PATH = os.path.join(DATA_PATH, 'output-data')
+ EXPECTED_DATA_PATH = os.path.join(DATA_PATH, 'expected-data')
+
+ with open(TEST_FILE_PATH) as f:
+ global_vars = {} # globals()
+ local_vars = locals()
+ code = compile(f.read(), TEST_FILE_PATH, 'exec')
+
+ exec(code, global_vars, local_vars)
+
+ if stylesheet: app.setStyleSheet(stylesheet)
+ app.exec_()
+ return myapp
diff --git a/pyforms/gui/basewidget.py b/pyforms/gui/basewidget.py
new file mode 100644
index 0000000..c098193
--- /dev/null
+++ b/pyforms/gui/basewidget.py
@@ -0,0 +1,602 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import json, AnyQt
+
+from pyforms.utils.settings_manager import conf
+
+from AnyQt.QtWidgets import QFrame
+from AnyQt.QtWidgets import QVBoxLayout
+from AnyQt.QtWidgets import QTabWidget
+from AnyQt.QtWidgets import QSplitter
+from AnyQt.QtWidgets import QHBoxLayout
+from AnyQt.QtWidgets import QSpacerItem
+from AnyQt.QtWidgets import QSizePolicy
+from AnyQt.QtWidgets import QLabel
+from AnyQt.QtGui import QFont
+from AnyQt.QtWidgets import QFileDialog
+from AnyQt.QtWidgets import QApplication
+from AnyQt import QtCore, _api
+
+from pyforms.gui.controls.ControlBase import ControlBase
+
+from AnyQt.QtWidgets import QMessageBox, QInputDialog
+
+class vsplitter(object):
+ def __init__(self, *args, **kwargs):
+ self.items = args
+ self.left_width = kwargs.get('left_width', 1)
+ self.right_width = kwargs.get('right_width', 1)
+ def __getitem__(self,index): return self.items[index]
+ def __setitem__(self,index,value): self.items[index] = value
+ def __len__(self): return len(self.items)
+ def __iter__(self):
+ self._index = -1; return self
+ def __next__(self):
+ self._index += 1
+ if self._index>=len(self.items): raise StopIteration
+ return self.items[self._index]
+
+class hsplitter(object):
+ def __init__(self, *args, **kwargs): self.items = args
+ def __getitem__(self,index): return self.items[index]
+ def __setitem__(self,index,value): self.items[index] = value
+ def __len__(self): return len(self.items)
+ def __iter__(self):
+ self._index = -1; return self
+ def __next__(self):
+ self._index += 1
+ if self._index>=len(self.items): raise StopIteration
+ return self.items[self._index]
+
+
+class BaseWidget(QFrame):
+ """
+ The class implements the most basic widget or window.
+ """
+
+ def __init__(self, *args, **kwargs):
+ title = kwargs.get('title', args[0] if len(args)>0 else '')
+
+ parent_win = kwargs.get('parent_win', kwargs.get('parent_widget', None))
+ win_flag = kwargs.get('win_flag', None)
+
+ self._parent_widget = parent_win
+
+ if parent_win is not None and win_flag is None: win_flag = QtCore.Qt.Dialog
+
+ QFrame.__init__(self) if parent_win is None else QFrame.__init__(self, parent_win, win_flag)
+
+ layout = QVBoxLayout()
+ self.setLayout(layout)
+
+ if _api.USED_API == _api.QT_API_PYQT5:
+ layout.setContentsMargins(0,0,0,0)
+ elif _api.USED_API == _api.QT_API_PYQT4:
+ layout.setMargin(0)
+
+ self.title = title
+
+ self.title = title
+ self.has_progress = False
+
+ self.toolbar = []
+ self._mainmenu = []
+ self._splitters = []
+ self._tabs = []
+ self._formset = None
+ self._formLoaded = False
+ self.uid = id(self)
+
+ self.setAccessibleName('BaseWidget')
+
+ ##########################################################################
+ ############ FUNCTIONS ##################################################
+ ##########################################################################
+
+ def init_form(self):
+ """
+ Generate the module Form
+ """
+ if not self._formLoaded:
+
+ if self._formset is not None:
+ control = self.generate_panel(self._formset)
+ self.layout().addWidget(control)
+ else:
+ allparams = self.controls
+ for key, param in allparams.items():
+ param.parent = self
+ param.name = key
+ self.layout().addWidget(param.form)
+ self._formLoaded = True
+
+ def set_margin(self, margin):
+ if _api.USED_API == _api.QT_API_PYQT5:
+ self.layout().setContentsMargins(margin,margin,margin,margin)
+ elif _api.USED_API == _api.QT_API_PYQT4:
+ self.layout().setMargin(margin)
+
+
+ def generate_tabs(self, formsetdict):
+ """
+ Generate QTabWidget for the module form
+ @param formset: Tab form configuration
+ @type formset: dict
+ """
+ tabs = QTabWidget(self)
+ for key, item in sorted(formsetdict.items()):
+ ctrl = self.generate_panel(item)
+ tabs.addTab(ctrl, key[key.find(':') + 1:])
+ return tabs
+
+ def generate_panel(self, formset):
+ """
+ Generate a panel for the module form with all the controls
+ formset format example: [('_video', '_arenas', '_run'), {"Player":['_threshold', "_player", "=", "_results", "_query"], "Background image":[(' ', '_selectBackground', '_paintBackground'), '_image']}, "_progress"]
+ tuple: will display the controls in the same horizontal line
+ list: will display the controls in the same vertical line
+ dict: will display the controls in a tab widget
+ '||': will plit the controls in a horizontal line
+ '=': will plit the controls in a vertical line
+ @param formset: Form configuration
+ @type formset: list
+ """
+ control = None
+ if '=' in formset or isinstance( formset, hsplitter ):
+ control = QSplitter(QtCore.Qt.Vertical)
+ index = list(formset).index('=')
+ first_panel = self.generate_panel(formset[0:index])
+ second_panel = self.generate_panel(formset[index+1:])
+ control.addWidget(first_panel)
+ control.addWidget(second_panel)
+ self._splitters.append(control)
+ return control
+ elif '||' in formset or isinstance( formset, vsplitter ):
+ control = QSplitter(QtCore.Qt.Horizontal)
+ index = list(formset).index('||')
+ first_panel = self.generate_panel(formset[0:index])
+ second_panel = self.generate_panel(formset[index+1:])
+ control.addWidget(first_panel)
+ control.addWidget(second_panel)
+
+ if isinstance( formset, vsplitter ):
+ sizes = [formset.left_width, formset.right_width]
+ control.setSizes(sizes)
+ self._splitters.append(control)
+ return control
+ control = QFrame(self)
+ layout = None
+ if type(formset) is tuple:
+ layout = QHBoxLayout()
+ for row in formset:
+ if isinstance(row, (list, tuple, vsplitter, hsplitter) ):
+ panel = self.generate_panel(row)
+ layout.addWidget(panel)
+ elif row == " ":
+ spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+ layout.addItem(spacer)
+ elif type(row) is dict:
+ c = self.generate_tabs(row)
+ layout.addWidget(c)
+ self._tabs.append(c)
+ else:
+ param = self.controls.get(row, None)
+ if param is None:
+ label = QLabel()
+ label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
+ # layout.addWidget( label )
+
+ if row.startswith('info:'):
+ label.setText(row[5:])
+ font = QFont()
+ font.setPointSize(10)
+ label.setFont(font)
+ label.setAccessibleName('info')
+ elif row.startswith('h1:'):
+ label.setText(row[3:])
+ font = QFont()
+ font.setPointSize(17)
+ font.setBold(True)
+ label.setFont(font)
+ label.setAccessibleName('h1')
+ elif row.startswith('h2:'):
+ label.setText(row[3:])
+ font = QFont()
+ font.setPointSize(16)
+ font.setBold(True)
+ label.setFont(font)
+ label.setAccessibleName('h2')
+ elif row.startswith('h3:'):
+ label.setText(row[3:])
+ font = QFont()
+ font.setPointSize(15)
+ font.setBold(True)
+ label.setFont(font)
+ label.setAccessibleName('h3')
+ elif row.startswith('h4:'):
+ label.setText(row[3:])
+ font = QFont()
+ font.setPointSize(14)
+ font.setBold(True)
+ label.setFont(font)
+ label.setAccessibleName('h4')
+ elif row.startswith('h5:'):
+ label.setText(row[3:])
+ font = QFont()
+ font.setPointSize(12)
+ font.setBold(True)
+ label.setFont(font)
+ label.setAccessibleName('h5')
+ else:
+ label.setText(row)
+ font = QFont()
+ font.setPointSize(10)
+ label.setFont(font)
+ label.setAccessibleName('msg')
+ label.setToolTip(label.text())
+ layout.addWidget(label)
+ else:
+ param.parent = self
+ param.name = row
+ layout.addWidget(param.form)
+ elif type(formset) is list:
+ layout = QVBoxLayout()
+ for row in formset:
+ if isinstance(row, (list, tuple, vsplitter, hsplitter) ):
+ panel = self.generate_panel(row)
+ layout.addWidget(panel)
+ elif row == " ":
+ spacer = QSpacerItem(
+ 20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
+ layout.addItem(spacer)
+ elif type(row) is dict:
+ c = self.generate_tabs(row)
+ layout.addWidget(c)
+ self._tabs.append(c)
+ else:
+ param = self.controls.get(row, None)
+ if param is None:
+ label = QLabel()
+ label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
+ label.resize(30, 30)
+ # layout.addWidget( label )
+
+ if row.startswith('info:'):
+ label.setText(row[5:])
+ font = QFont()
+ font.setPointSize(10)
+ label.setFont(font)
+ label.setAccessibleName('info')
+ elif row.startswith('h1:'):
+ label.setText(row[3:])
+ font = QFont()
+ font.setPointSize(17)
+ font.setBold(True)
+ label.setFont(font)
+ label.setAccessibleName('h1')
+ elif row.startswith('h2:'):
+ label.setText(row[3:])
+ font = QFont()
+ font.setPointSize(16)
+ font.setBold(True)
+ label.setFont(font)
+ label.setAccessibleName('h2')
+ elif row.startswith('h3:'):
+ label.setText(row[3:])
+ font = QFont()
+ font.setPointSize(15)
+ font.setBold(True)
+ label.setFont(font)
+ label.setAccessibleName('h3')
+ elif row.startswith('h4:'):
+ label.setText(row[3:])
+ font = QFont()
+ font.setPointSize(14)
+ font.setBold(True)
+ label.setFont(font)
+ label.setAccessibleName('h4')
+ elif row.startswith('h5:'):
+ label.setText(row[3:])
+ font = QFont()
+ font.setPointSize(12)
+ font.setBold(True)
+ label.setFont(font)
+ label.setAccessibleName('h5')
+ else:
+ label.setText(row)
+ font = QFont()
+ font.setPointSize(10)
+ label.setFont(font)
+ label.setAccessibleName('msg')
+
+ label.setToolTip(label.text())
+
+ layout.addWidget(label)
+ else:
+ param.parent = self
+ param.name = row
+ layout.addWidget(param.form)
+
+ if _api.USED_API == _api.QT_API_PYQT5:
+ layout.setContentsMargins(0,0,0,0)
+ elif _api.USED_API == _api.QT_API_PYQT4:
+ layout.setMargin(0)
+
+ control.setLayout(layout)
+ return control
+
+ def show(self):
+ self.init_form()
+ super(BaseWidget, self).show()
+
+ def save_form(self, data={}, path=None):
+ allparams = self.controls
+
+ if hasattr(self, 'load_order'):
+ for name in self.load_order:
+ param = allparams[name]
+ data[name] = {}
+ param.save_form(data[name])
+ else:
+ for name, param in allparams.items():
+ data[name] = {}
+ param.save_form(data[name])
+ return data
+
+ def load_form(self, data, path=None):
+ allparams = self.controls
+
+ if hasattr(self, 'load_order'):
+ for name in self.load_order:
+ param = allparams[name]
+ if name in data:
+ param.load_form(data[name])
+ else:
+ for name, param in allparams.items():
+ if name in data:
+ param.load_form(data[name])
+ # self.init_form()
+
+ def save_window(self):
+ allparams = self.controls
+ data = {}
+ self.save_form(data)
+
+ filename, _ = QFileDialog.getSaveFileName(self, 'Select file')
+ with open(filename, 'w') as output_file: json.dump(data, output_file)
+
+ def load_form_filename(self, filename):
+ with open(filename, 'r') as pkl_file:
+ project_data = json.load(pkl_file)
+ data = dict(project_data)
+ self.load_form(data)
+
+ def load_window(self):
+ filename, _ = QFileDialog.getOpenFileNames(self, 'Select file')
+ self.load_form_filename(str(filename[0]))
+
+ def close(self):
+ super(BaseWidget, self).close()
+
+
+ def input_text(self, msg, title='', default=None):
+ text, ok = QInputDialog.getText(self, title, msg, text=default)
+ if ok:
+ return str(text)
+ else:
+ return None
+
+ def input_double(self, msg, title='', default=0, min=-2147483647, max=2147483647, decimals=1):
+ text, ok = QInputDialog.getDouble(self, title, msg, value=default, min=min, max=max, decimals=decimals)
+ if ok:
+ return float(text)
+ else:
+ return None
+
+ def input_int(self, msg, title='', default=0, min=-2147483647, max=2147483647):
+ text, ok = QInputDialog.getInt(self, title, msg, value=default, min=min, max=max)
+ if ok:
+ return int(text)
+ else:
+ return None
+
+
+ def question(self, msg, title=None, buttons=['no', 'yes']):
+ btns = None
+ for btn in buttons:
+ if btn.lower()=='cancel':
+ b = QMessageBox.Cancel
+ elif btn.lower()=='no':
+ b = QMessageBox.No
+ elif btn.lower()=='yes':
+ b = QMessageBox.Yes
+
+ if btns is None:
+ btns=b
+ else: btns |= b
+
+ m = QMessageBox(QMessageBox.Question, title, msg, btns)
+ reply = m.exec()
+
+ if reply==QMessageBox.Cancel: return 'cancel'
+ elif reply==QMessageBox.No: return 'no'
+ elif reply==QMessageBox.Yes: return 'yes'
+
+ return None
+
+ def message(self, msg, title=None, msg_type=None):
+ if msg_type=='success':
+ m = QMessageBox(QMessageBox.NoIcon, title, msg)
+ elif msg_type=='info':
+ m = QMessageBox(QMessageBox.Information, title, msg)
+ elif msg_type=='warning':
+ m = QMessageBox(QMessageBox.Warning, title, msg)
+ elif msg_type=='error':
+ m = QMessageBox(QMessageBox.Critical, title, msg)
+ elif msg_type=='about':
+ m = QMessageBox(QMessageBox.Question, title, msg)
+ elif msg_type=='aboutQt':
+ m = QMessageBox(QMessageBox.Question, title, msg)
+ else:
+ m = QMessageBox(QMessageBox.NoIcon, title, msg)
+
+ m.exec()
+
+ def success(self, msg, title=None): self.message(msg, title, msg_type='success')
+ def info(self, msg, title=None): self.message(msg, title, msg_type='info')
+ def warning(self, msg, title=None): self.message(msg, title, msg_type='warning');
+ def alert(self, msg, title=None): self.message(msg, title, msg_type='error')
+ def critical(self, msg, title=None): self.message(msg, title, msg_type='error')
+ def about(self, msg, title=None): self.message(msg, title, msg_type='about')
+ def aboutQt(self, msg, title=None): self.message(msg, title, msg_type='aboutQt')
+
+ def message_popup(self, msg, title='', buttons=None, handler=None, msg_type='success'):
+ pass
+ def success_popup(self, msg, title='', buttons=None, handler=None):
+ return self.message_popup(msg, title, buttons, handler, msg_type='success')
+ def info_popup(self, msg, title='', buttons=None, handler=None):
+ return self.message_popup(msg, title, buttons, handler, msg_type='info')
+ def warning_popup(self, msg, title='', buttons=None, handler=None):
+ return self.message_popup(msg, title, buttons, handler, msg_type='warning')
+ def alert_popup(self, msg, title='', buttons=None, handler=None):
+ return self.message_popup(msg, title, buttons, handler, msg_type='alert')
+
+
+
+
+ ##########################################################################
+ ############ GUI functions ###############################################
+ ##########################################################################
+
+ def set_margin(self, margin):
+ if AnyQt.USED_API=='pyqt5':
+ self.layout().setContentsMargins(margin,margin,margin,margin)
+ else:
+ self.layout().setMargin(margin)
+
+ ##########################################################################
+ ############ EVENTS ######################################################
+ ##########################################################################
+
+ def before_close_event(self):
+ """
+ Do something before closing widget
+ Note that the window will be closed anyway
+ """
+ pass
+
+ ##########################################################################
+ ############ Properties ##################################################
+ ##########################################################################
+
+ @property
+ def controls(self):
+ """
+ Return all the form controls from the the module
+ """
+ result = {}
+ for name, var in vars(self).items():
+ try:
+ if isinstance(var, ControlBase):
+ result[name] = var
+ except:
+ pass
+ return result
+
+ ############################################################################
+ ############ GUI Properties ################################################
+ ############################################################################
+
+
+ @property
+ def form_has_loaded(self):
+ return self._formLoaded
+
+
+ @property
+ def form(self):
+ return self
+
+ @property
+ def visible(self):
+ return self.isVisible()
+
+ @property
+ def mainmenu(self):
+ return self._mainmenu
+ @mainmenu.setter
+ def mainmenu(self, value):
+ self._mainmenu = value
+
+
+ @property
+ def controls(self):
+ """
+ Return all the form controls from the the module
+ """
+ result = {}
+ for name, var in vars(self).items():
+ try:
+ if isinstance(var, ControlBase):
+ result[name] = var
+ except:
+ pass
+ return result
+
+ ############################################################################
+ ############ GUI Properties ################################################
+ ############################################################################
+
+
+ @property
+ def form_has_loaded(self):
+ return self._formLoaded
+
+ @property
+ def parent_widget(self):
+ return self._parent_widget
+
+ @property
+ def form(self):
+ return self
+
+ @property
+ def title(self):
+ return self.windowTitle()
+
+ @title.setter
+ def title(self, value):
+ self.setWindowTitle(value)
+
+
+ @property
+ def formset(self):
+ return self._formset
+
+ @formset.setter
+ def formset(self, value):
+ self._formset = value
+
+ @property
+ def uid(self):
+ return self._uid
+
+ @uid.setter
+ def uid(self, value):
+ self._uid = value
+
+
+ @property
+ def visible(self):
+ return self.isVisible()
+
+
+
+ ##########################################################################
+ ############ PRIVATE FUNCTIONS ###########################################
+ ##########################################################################
+
+ def closeEvent(self, event):
+ self.before_close_event()
+ super(BaseWidget, self).closeEvent(event)
diff --git a/pyforms/gui/controls/ControlBase.py b/pyforms/gui/controls/ControlBase.py
new file mode 100644
index 0000000..edc3053
--- /dev/null
+++ b/pyforms/gui/controls/ControlBase.py
@@ -0,0 +1,280 @@
+# !/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from pyforms.utils.settings_manager import conf
+
+from AnyQt import QtCore, uic
+from AnyQt.QtWidgets import QMenu, QAction
+from AnyQt.QtGui import QIcon, QKeySequence
+
+class ControlBase(object):
+ """
+ This class represents the most basic control that can exist
+ A Control is a Widget or a group of widgets that can be reused from application to application
+
+ @undocumented: __repr__
+ """
+
+ def __init__(self, *args, **kwargs):
+ self._form = None # Qt widget
+ self._parent = None # Parent window
+ self._popup_menu = None
+
+ self._help = kwargs.get('helptext', None)
+ self._value = kwargs.get('default', None)
+ self._label = kwargs.get('label', args[0] if len(args)>0 else '')
+ """
+ self._visible = kwargs.get('visible', True)
+ self._error = kwargs.get('error', False)
+ self._css = kwargs.get('css', None)
+ self._enabled = kwargs.get('enabled', True)
+ self._readonly = kwargs.get('readonly', False)
+ self._label_visible = kwargs.get('label_visible', True)
+ """
+
+ self.init_form()
+
+ self.changed_event = kwargs.get('changed_event', self.changed_event)
+ self.enabled = kwargs.get('enabled', True)
+ self.readonly = kwargs.get('readonly', False)
+ if not kwargs.get('visible', True): self.hide()
+
+
+ def __repr__(self): return str(self._value)
+
+ ##########################################################################
+ ############ Funcions ####################################################
+ ##########################################################################
+
+ def init_form(self):
+ """
+ Load Control and initiate the events
+ """
+ if self.help: self.form.setToolTip(self.help)
+
+
+
+ def load_form(self, data, path=None):
+ """
+ Load a value from the dict variable
+ @param data: dictionary with the value of the Control
+ """
+ if 'value' in data:
+ self.value = data['value']
+
+ def save_form(self, data, path=None):
+ """
+ Save a value to dict variable
+ @param data: dictionary with to where the value of the Control will be added
+ """
+ data['value'] = self.value
+ return data
+
+ def show(self):
+ """
+ Show the control
+ """
+ if self.form is None:
+ return
+ elif self.form==self:
+ super(ControlBase,self).show()
+ else:
+ self.form.show()
+
+ def hide(self):
+ """
+ Hide the control
+ """
+ if self.form is None:
+ return
+ elif self.form==self:
+ super(ControlBase,self).hide()
+ else:
+ self.form.hide()
+
+
+ def __create_popup_menu(self):
+ if not self._popup_menu:
+ self.form.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
+ self.form.customContextMenuRequested.connect(self._open_popup_menu)
+ self._popup_menu = QMenu(self.parent)
+ self._popup_menu.aboutToShow.connect( self.about_to_show_contextmenu_event)
+
+ def add_popup_submenu(self, label, submenu=None):
+ self.__create_popup_menu()
+ menu = submenu if submenu else self._popup_menu
+ submenu = QMenu(label, menu)
+ menu.addMenu(submenu)
+ return submenu
+
+ def add_popup_menu_option(self, label, function_action=None, key=None, icon=None, submenu=None):
+ """
+ Add an option to the Control popup menu
+ @param label: label of the option.
+ @param function_action: function called when the option is selected.
+ @param key: shortcut key
+ @param icon: icon
+ """
+ self.__create_popup_menu()
+
+ menu = submenu if submenu else self._popup_menu
+
+ if label == "-":
+ return menu.addSeparator()
+ else:
+ action = QAction(label, self.form)
+ if icon is not None:
+ action.setIconVisibleInMenu(True)
+ action.setIcon(icon if isinstance(icon, QIcon) else QIcon(icon) )
+ if key != None:
+ action.setShortcut(QKeySequence(key))
+ if function_action:
+ action.triggered.connect(function_action)
+ menu.addAction(action)
+ return action
+
+
+ ##########################################################################
+ ############ Events ######################################################
+ ##########################################################################
+
+ def changed_event(self):
+ """
+ Function called when ever the Control value is changed
+ """
+ return True
+
+ def about_to_show_contextmenu_event(self):
+ """
+ Function called before open the Control popup menu
+ """
+ pass
+
+ def _open_popup_menu(self, position):
+ if self._popup_menu:
+ self._popup_menu.exec_(self.form.mapToGlobal(position))
+
+ ##########################################################################
+ ############ Properties ##################################################
+ ##########################################################################
+
+ ##########################################################################
+ # Set the Control enabled or disabled
+
+ @property
+ def enabled(self):
+ return self.form.isEnabled()
+
+ @enabled.setter
+ def enabled(self, value):
+ """@type value: boolean"""
+ self.form.setEnabled(value)
+
+ ##########################################################################
+ # Return or update the value of the Control
+
+ @property
+ def value(self):
+ return self._value
+
+ @value.setter
+ def value(self, value):
+ """
+ This property return and set what the control should manage or store.
+ @type value: string
+ """
+ oldvalue = self._value
+ self._value = value
+ if oldvalue != value:
+ self.changed_event()
+
+
+ @property
+ def name(self): return self.form.objectName()
+
+ @name.setter
+ def name(self, value):
+ """
+ This property return and set the name of the control
+ @type value: string
+ """
+ self.form.setObjectName(value)
+
+ ##########################################################################
+ # Return or update the label of the Control
+
+ @property
+ def label(self):
+ return self._label
+
+ @label.setter
+ def label(self, value):
+ """
+ Label of the control, if applies
+ @type value: string
+ """
+ self._label = value
+
+ ##########################################################################
+ # Parent window
+
+ @property
+ def parent(self): return self._parent
+
+ @parent.setter
+ def parent(self, value):
+ """
+ Returns or set the parent basewidget where the Control is
+ @type value: BaseWidget
+ """
+ self._parent = value
+
+ @property
+ def visible(self): return self.form.isVisible()
+
+ @property
+ def help(self): return self._help if self._help else ''
+
+ @property
+ def error(self): return None
+
+ @error.setter
+ def error(self, value):
+ pass
+
+ @property
+ def label_visible(self): return None
+
+ @label_visible.setter
+ def label_visible(self, value):
+ pass
+
+ @property
+ def readonly(self): return None
+
+ @readonly.setter
+ def readonly(self, value):
+ pass
+
+ @property
+ def css(self): return None
+
+ @css.setter
+ def css(self, value):
+ pass
+
+
+ ##########################################################################
+ ############ Properties just for the GUI version #########################
+ ##########################################################################
+
+ ##########################################################################
+ # Return the QT widget
+
+ @property
+ def form(self):
+ """
+ Returns the Widget of the control.
+ This property will be deprecated in a future version.
+ """
+ return self._form
diff --git a/pyforms/gui/controls/ControlBoundingSlider.py b/pyforms/gui/controls/ControlBoundingSlider.py
new file mode 100644
index 0000000..fc051a7
--- /dev/null
+++ b/pyforms/gui/controls/ControlBoundingSlider.py
@@ -0,0 +1,423 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from pyforms.utils.settings_manager import conf
+
+from AnyQt import QtCore, _api
+from AnyQt.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QSpinBox
+from AnyQt.QtGui import QFont, QColor, QCursor, QPainter
+
+from pyforms.gui.controls.ControlBase import ControlBase
+
+
+class GaugeWidgetVertical(QWidget):
+ def __init__(self, *args, **kwargs):
+ QWidget.__init__(self, *args, **kwargs)
+
+ self.setMouseTracking(True)
+ self.setMinimumHeight(30)
+ self.setMinimumWidth(30)
+ self.setMaximumWidth(50)
+
+ self._step = 0
+ self._lower = 0
+ self._higher = 100
+ self._minVal = 0
+ self._maxVal = 75
+ self._lastMouseY = None
+ self._moving = False
+ self._resizingBottom = False
+ self._resizingTop = False
+ self._scale = 1.0
+ self._use_float = False
+
+ def changed_event(self):
+ pass
+
+ def paintEvent(self, e):
+ # call the base implementation to paint normal interface
+ super(GaugeWidgetVertical, self).paintEvent(e)
+ draw = QPainter()
+ draw.begin(self)
+
+ window_with = self.width() - 1
+ diff = (self._higher - self._lower) * self.scale
+ try:
+ self._step = float(self.height()) / float(diff)
+ except ZeroDivisionError:
+ self._step = 0
+ y_start = self.height() - (self._minVal - self._lower) * self._step * self.scale
+ y_end = self.height() - (self._maxVal - self._lower) * self._step * self.scale
+
+ draw.setOpacity(1.0)
+ draw.setBrush(QtCore.Qt.NoBrush)
+ draw.setPen(QColor(200, 200, 255))
+
+ b = int(self.height() / 5)
+ e = int(self.height() - (self.height() / 5) + 1)
+ s = int(self.height() / 5)
+
+ for i in range( b, e, s ):
+ draw.drawLine(0, i, window_with, i)
+
+ draw.setBrush(QColor(33, 133, 208))
+ draw.setPen(QColor(33, 133, 208))
+ draw.setOpacity(0.7)
+ draw.drawRect(0, y_start, window_with, y_end - y_start)
+
+ draw.setFont(QFont('Decorative', 8))
+ draw.setPen(QColor(30, 30, 30))
+ draw.drawText(3, self.height() - 3, str(self._lower) if self._use_float else str(int(round(self._lower))))
+ draw.drawText(3, 10, str(self._higher) if self._use_float else str(int(round(self._higher))))
+
+ draw.drawText(3, y_start + 11, str(self._minVal) if self._use_float else str(int(round(self._minVal))))
+ draw.drawText(3, y_end - 4, str(self._maxVal) if self._use_float else str(int(round(self._maxVal))))
+
+ draw.end()
+
+ def mousePressEvent(self, event):
+ self._moving = False
+ self._resizingBottom = False
+ self._resizingTop = False
+
+ y_start = self.height() - (self._minVal - self._lower) * self._step * self.scale
+ y_end = self.height() - (self._maxVal - self._lower) * self._step * self.scale
+
+ if event.buttons() == QtCore.Qt.LeftButton:
+ if y_start > event.y() > y_end:
+ self._moving = True
+ elif event.y() < y_end:
+ self._resizingTop = True
+ elif y_start < event.y():
+ self._resizingBottom = True
+
+ def mouseReleaseEvent(self, event):
+ self._moving = False
+ self._resizingBottom = False
+ self._resizingTop = False
+
+ def mouseMoveEvent(self, event):
+ super(GaugeWidgetVertical, self).mouseMoveEvent(event)
+
+ y_start = self.height() - (self._minVal - self._lower) * self._step * self.scale
+ y_end = self.height() - (self._maxVal - self._lower) * self._step * self.scale
+
+ if y_start < event.y() or event.y() < y_end:
+ self.setCursor(QCursor(QtCore.Qt.SizeVerCursor))
+ else:
+ self.setCursor(QCursor(QtCore.Qt.ArrowCursor))
+
+ if event.buttons() == QtCore.Qt.LeftButton:
+ if self._lastMouseY != None:
+ diff = self._lastMouseY - event.y()
+ if diff != 0:
+ if self._moving:
+ new_min = self._minVal * self.scale + diff * 1 / self._step
+ new_max = self._maxVal * self.scale + diff * 1 / self._step
+ if new_min < new_max:
+ self._minVal = new_min / self.scale
+ self._maxVal = new_max / self.scale
+ elif self._resizingTop:
+ new_max = self._maxVal * self.scale + diff * 1 / self._step
+ if self._minVal < (new_max / self.scale): self._maxVal = new_max / self.scale
+ elif self._resizingBottom:
+ new_min = self._minVal * self.scale + diff * 1 / self._step
+ if (new_min / self.scale) < self._maxVal: self._minVal = new_min / self.scale
+
+ self.repaint()
+
+ self.changed_event()
+
+ self._lastMouseY = event.y()
+
+ def mouseReleaseEvent(self, event):
+ self._lastMouseY = None
+
+ @property
+ def scale(self):
+ return self._scale
+
+ @scale.setter
+ def scale(self, value):
+ self._scale = value
+
+
+class GaugeWidgetHorizontal(GaugeWidgetVertical):
+ def __init__(self, *args, **kwargs):
+ super(GaugeWidgetHorizontal, self).__init__(*args, **kwargs)
+
+ self.setMaximumWidth(1000000)
+ self.setMinimumHeight(20)
+ self.setMaximumHeight(20)
+
+ def paintEvent(self, e):
+ # call the base implementation to paint normal interface
+ QWidget.paintEvent(self, e);
+ draw = QPainter();
+ draw.begin(self)
+
+ h = self.height() - 1
+ diff = (self._higher - self._lower) * self.scale
+
+ try:
+ self._step = float(self.width()) / float(diff)
+ except ZeroDivisionError:
+ self._step = 0
+ x_start = (self._minVal - self._lower) * self._step * self.scale
+ x_end = (self._maxVal - self._lower) * self._step * self.scale
+
+ draw.setOpacity(1.0)
+ draw.setBrush(QtCore.Qt.NoBrush)
+ draw.setPen(QColor(200, 200, 255))
+
+ for i in range( int(self.width()/5), int(self.width()-self.width()/5) + 1, int(self.width()/5) ):
+ draw.drawLine(i, 0, i, h)
+
+ draw.setBrush(QColor(238, 238, 238))
+ draw.setPen(QColor(238, 238, 238))
+ draw.drawRoundedRect(0, 2, self.width(), h - 4, 3, 3)
+
+ draw.setBrush(QColor(33, 133, 208))
+ draw.setPen(QColor(33, 133, 208))
+ draw.drawRoundedRect(int(round(x_start)), 2, int(round(x_end - x_start)), h - 4, 3, 3)
+ # draw.setOpacity(1.0)
+ draw.setFont(QFont('Decorative', 8))
+ draw.setPen(QColor(80, 80, 80))
+
+ str(self._maxVal) if self._use_float else str(int(round(self._maxVal)))
+
+ boundtext = draw.boundingRect(QtCore.QRectF(),
+ str(self._higher) if self._use_float else str(int(round(self._higher))))
+ draw.drawText(self.width() - boundtext.width(), 14,
+ str(self._higher) if self._use_float else str(int(round(self._higher))))
+ draw.drawText(0, 14, str(self._lower) if self._use_float else str(int(round(self._lower))))
+
+ draw.setPen(QColor(255, 255, 255))
+ boundtext = draw.boundingRect(QtCore.QRectF(),
+ str(self._minVal) if self._use_float else str(int(round(self._minVal))))
+ draw.drawText(x_start + 2, 14, str(self._minVal) if self._use_float else str(int(round(self._minVal))))
+ boundtext = draw.boundingRect(QtCore.QRectF(),
+ str(self._maxVal) if self._use_float else str(int(round(self._maxVal))))
+ draw.drawText(x_end - boundtext.width(), 14,
+ str(self._maxVal) if self._use_float else str(int(round(self._maxVal))))
+
+ draw.end()
+
+ def mousePressEvent(self, event):
+ self._moving = False
+ self._resizingLeft = False
+ self._resizingRight = False
+
+ x_start = (self._minVal - self._lower) * self._step * self.scale
+ x_end = (self._maxVal - self._lower) * self._step * self.scale
+
+ if event.buttons() == QtCore.Qt.LeftButton:
+ if x_start < event.x() < x_end:
+ self._moving = True
+ elif event.x() > x_end:
+ self._resizingLeft = True
+ elif x_start > event.x():
+ self._resizingRight = True
+
+ def mouseMoveEvent(self, event):
+ super(GaugeWidgetVertical, self).mouseMoveEvent(event)
+
+ x_start = (self._minVal - self._lower) * self._step * self.scale
+ x_end = (self._maxVal - self._lower) * self._step * self.scale
+
+ # set the cursors
+ if x_start >= event.x() or event.x() >= x_end:
+ self.setCursor(QCursor(QtCore.Qt.SizeHorCursor))
+ else:
+ self.setCursor(QCursor(QtCore.Qt.ArrowCursor))
+
+ if event.buttons() == QtCore.Qt.LeftButton:
+ if self._lastMouseY != None:
+ diff = self._lastMouseY - event.x()
+ if diff != 0:
+ if self._moving:
+ new_min = self._minVal * self.scale - diff * 1 / self._step
+ new_max = self._maxVal * self.scale - diff * 1 / self._step
+ if new_min < new_max:
+ self._minVal = new_min / self.scale
+ self._maxVal = new_max / self.scale
+ elif self._resizingLeft:
+ new_max = self._maxVal * self.scale - diff * 1 / self._step
+ if self._minVal < (new_max / self.scale): self._maxVal = new_max / self.scale
+ elif self._resizingRight:
+ new_min = self._minVal * self.scale - diff * 1 / self._step
+ if (new_min / self.scale) < self._maxVal: self._minVal = new_min / self.scale
+
+ self.repaint()
+ self.changed_event()
+
+ self._lastMouseY = event.x()
+
+
+class ControlBoundingSlider(ControlBase):
+ def __init__(self, *args, **kwargs):
+ self._horizontal = kwargs.get('horizontal', True)
+ self._show_spinboxes = kwargs.get('show_spinboxes', True)
+ ControlBase.__init__(self, *args, **kwargs)
+
+ self.min = kwargs.get('min', kwargs.get('minimum', 0))
+ self.max = kwargs.get('max', kwargs.get('maximum', 100))
+ self.value = kwargs.get('default', [10,20])
+ self.__update()
+
+ def init_form(self):
+ self._boundingbox = GaugeWidgetHorizontal() if self._horizontal else GaugeWidgetVertical()
+ self._boundingbox.changed_event = self.__update
+
+ if self._show_spinboxes:
+ self._form = hwidget = QWidget()
+ if self._horizontal:
+ hlayout = QHBoxLayout()
+ else:
+ hlayout = QVBoxLayout()
+
+
+ if _api.USED_API == _api.QT_API_PYQT5:
+ hlayout.setContentsMargins(0,0,0,0)
+ elif _api.USED_API == _api.QT_API_PYQT4:
+ hlayout.setMargin(0)
+
+
+ hwidget.setLayout(hlayout)
+ self._min_spinbox = QSpinBox()
+ self._min_spinbox.valueChanged.connect(self.__min_spinbox_changed)
+ self._min_spinbox.setMaximumWidth(95)
+
+ self._max_spinbox = QSpinBox()
+ self._max_spinbox.valueChanged.connect(self.__max_spinbox_changed)
+ self._max_spinbox.setMaximumWidth(95)
+
+ if self._horizontal:
+ hlayout.addWidget(self._min_spinbox)
+ else:
+ hlayout.addWidget(self._max_spinbox)
+ hlayout.addWidget(self._boundingbox)
+ if self._horizontal:
+ hlayout.addWidget(self._max_spinbox)
+ else:
+ hlayout.addWidget(self._min_spinbox)
+
+ else:
+ self._form = self._boundingbox
+
+ super(ControlBoundingSlider, self).init_form()
+
+ def __max_spinbox_changed(self, value):
+ if value < self._boundingbox._minVal: return
+ if hasattr(self, '_is_updating_spinboxes'): return
+ self.scale = self.__find_scale_factor(value)
+ self._boundingbox._maxVal = value
+ self._boundingbox.repaint()
+ self.changed_event()
+
+ def __min_spinbox_changed(self, value):
+ if value > self._boundingbox._maxVal: return
+ if hasattr(self, '_is_updating_spinboxes'): return
+ self.scale = self.__find_scale_factor(value)
+ self._boundingbox._minVal = value
+ self._boundingbox.repaint()
+ self.changed_event()
+
+ def __update(self):
+ l, h = self._boundingbox._minVal, self._boundingbox._maxVal
+ self._is_updating_spinboxes = True
+ self._min_spinbox.setValue(l)
+ self._max_spinbox.setValue(h)
+ del self._is_updating_spinboxes
+ self.changed_event()
+
+ def changed_event(self):
+ pass
+
+ def __find_scale_factor(self, value):
+ scale = 1.0
+ new_value = value
+ while abs(new_value) < 0.0:
+ scale *= 10.0
+ new_value = value * scale
+ return scale
+
+ def load_form(self, data, path=None):
+ """
+ Load a value from the dict variable
+ @param data: dictionary with the value of the Control
+ """
+
+ self.convert_2_int = data.get('convert-int', self.convert_2_int)
+ self.scale = data.get('scale', self.scale)
+ self.max = data.get('max', self.max)
+ self.min = data.get('min', self.min)
+ self.value = data.get('value', self.value)
+
+
+ def save_form(self, data, path=None):
+ """
+ Save a value to dict variable
+ @param data: dictionary with to where the value of the Control will be added
+ """
+ data['value'] = self.value
+ data['max'] = self.max
+ data['min'] = self.min
+ data['scale'] = self.scale
+ data['convert-int'] = self.convert_2_int
+ return data
+
+ ##########################################################################
+ ############ Properties ##################################################
+ ##########################################################################
+
+ @property
+ def value(self):
+ return self._boundingbox._minVal, self._boundingbox._maxVal
+
+ @value.setter
+ def value(self, value):
+ self.scale = self.__find_scale_factor(value[0])
+ self._boundingbox._minVal, self._boundingbox._maxVal = value[0], value[1]
+ if hasattr(self, '_min_spinbox'): self._min_spinbox.setValue(value[0])
+ if hasattr(self, '_max_spinbox'): self._max_spinbox.setValue(value[1])
+ ControlBase.value.fset(self, value)
+ self._boundingbox.repaint()
+
+ @property
+ def min(self):
+ return self._boundingbox._lower
+
+ @min.setter
+ def min(self, value):
+ self._boundingbox._lower = value
+ self._boundingbox.repaint()
+ if hasattr(self, '_min_spinbox'): self._min_spinbox.setMinimum(value)
+ if hasattr(self, '_max_spinbox'): self._max_spinbox.setMinimum(value)
+
+ @property
+ def max(self):
+ return self._boundingbox._higher
+
+ @max.setter
+ def max(self, value):
+ self._boundingbox._higher = value
+ self._boundingbox.repaint()
+ if hasattr(self, '_min_spinbox'): self._min_spinbox.setMaximum(value)
+ if hasattr(self, '_max_spinbox'): self._max_spinbox.setMaximum(value)
+
+ @property
+ def scale(self):
+ return self._boundingbox.scale
+
+ @scale.setter
+ def scale(self, value):
+ self._boundingbox.scale = value
+
+ @property
+ def convert_2_int(self):
+ return not self._boundingbox._use_float
+
+ @convert_2_int.setter
+ def convert_2_int(self, value):
+ self._boundingbox._use_float = not value
diff --git a/pyforms/gui/Controls/ControlButton.py b/pyforms/gui/controls/ControlButton.py
old mode 100755
new mode 100644
similarity index 71%
rename from pyforms/gui/Controls/ControlButton.py
rename to pyforms/gui/controls/ControlButton.py
index 29aa486..a16ec7b
--- a/pyforms/gui/Controls/ControlButton.py
+++ b/pyforms/gui/controls/ControlButton.py
@@ -3,26 +3,25 @@
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QPushButton
- from PyQt5.QtWidgets import QSizePolicy
- from PyQt5.QtGui import QIcon
- from PyQt5 import uic
-else:
- from PyQt4.QtGui import QPushButton
- from PyQt4.QtGui import QSizePolicy
- from PyQt4.QtGui import QIcon
- from PyQt4 import uic
+from AnyQt import uic
+from AnyQt.QtWidgets import QPushButton, QSizePolicy
+from AnyQt.QtGui import QIcon
-from pyforms.gui.Controls.ControlBase import ControlBase
+from pyforms.gui.controls.ControlBase import ControlBase
class ControlButton(ControlBase):
- def __init__(self, label='', default=None, checkable=False, helptext=None):
- self._checkable = checkable
- super(ControlButton, self).__init__(label=label, default=default, helptext=helptext)
+ def __init__(self, *args, **kwargs):
+ self._checkable = kwargs.get('checkable', False)
+ super(ControlButton, self).__init__(*args, **kwargs)
+
+ default = kwargs.get('default', None)
+ if default: self.value = default
+
+ icon = kwargs.get('icon', None)
+ if icon: self.icon = icon
def init_form(self):
self._form = QPushButton()
diff --git a/pyforms/gui/Controls/ControlCheckBox.py b/pyforms/gui/controls/ControlCheckBox.py
old mode 100755
new mode 100644
similarity index 78%
rename from pyforms/gui/Controls/ControlCheckBox.py
rename to pyforms/gui/controls/ControlCheckBox.py
index 8568b16..df62a48
--- a/pyforms/gui/Controls/ControlCheckBox.py
+++ b/pyforms/gui/controls/ControlCheckBox.py
@@ -1,19 +1,13 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
-import pyforms.utils.tools as tools
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5 import uic
- from PyQt5 import QtCore
+from AnyQt import uic, QtCore
-else:
- from PyQt4 import uic
- from PyQt4 import QtCore
-from pyforms.gui.Controls.ControlBase import ControlBase
+import pyforms.utils.tools as tools
+from pyforms.gui.controls.ControlBase import ControlBase
class ControlCheckBox(ControlBase):
@@ -35,7 +29,7 @@ def __checkedToggle(self):
def load_form(self, data, path=None):
if 'value' in data:
- self._form.checkBox.setChecked(data['value'] == 'True')
+ self._form.checkBox.setChecked(data['value'] == 'True' or data['value'] == True)
def save_form(self, data, path=None):
data['value'] = str(self._form.checkBox.isChecked())
diff --git a/pyforms/gui/controls/ControlCheckBoxList.py b/pyforms/gui/controls/ControlCheckBoxList.py
new file mode 100644
index 0000000..8cfa367
--- /dev/null
+++ b/pyforms/gui/controls/ControlCheckBoxList.py
@@ -0,0 +1,146 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from pyforms.utils.settings_manager import conf
+
+import pyforms.utils.tools as tools
+
+from AnyQt import uic, QtCore
+from AnyQt.QtWidgets import QListWidgetItem
+
+from pyforms.gui.controls.ControlBase import ControlBase
+
+
+class ControlCheckBoxList(ControlBase):
+
+ def init_form(self):
+ control_path = tools.getFileInSameDirectory(__file__, "tree.ui")
+ self._form = uic.loadUi(control_path)
+
+ self._form.label.setText(self._label)
+
+ self._form.listWidget.itemChanged.connect(self.item_changed)
+
+ self._form.listWidget.itemSelectionChanged.connect(self.__itemSelectionChanged)
+
+ if self.help: self.form.setToolTip(self.help)
+
+
+
+
+ def save_form(self, data={}, path=None):
+ results = []
+
+ for row in range(self.count):
+ item = self._form.listWidget.item(row)
+ if item != None and item.checkState() == QtCore.Qt.Checked:
+ results.append(item.text())
+ data['selected'] = results
+
+ return data
+
+ def load_form(self, data, path=None):
+ results = data['selected']
+
+ for row in range(self.count):
+ item = self._form.listWidget.item(row)
+ if item != None and item.text() in results:
+ item.setCheckState(QtCore.Qt.Checked)
+ else:
+ item.setCheckState(QtCore.Qt.Unchecked)
+
+
+
+ def item_changed(self, item):
+ self.changed_event()
+
+ def __add__(self, val):
+ if isinstance(val, (tuple, list)):
+ item = QListWidgetItem(str(val[0]))
+ item.value = val[0]
+ if val[1]:
+ item.setCheckState(QtCore.Qt.Checked)
+ else:
+ item.setCheckState(QtCore.Qt.Unchecked)
+ else:
+ item = QListWidgetItem(str(val))
+ item.value = val
+
+ self._form.listWidget.addItem(item)
+ return self
+
+ def __sub__(self, other):
+ if isinstance(other, int):
+ if other < 0:
+ indexToRemove = self._form.listWidget.currentRow()
+ else:
+ indexToRemove = other
+ self._form.listWidget.takeItem(indexToRemove)
+ else:
+ for row in range(self.count):
+ item = self._form.listWidget.item(row)
+ if item != None and hasattr(item, 'value') and item.value == other:
+ self._form.listWidget.takeItem(row)
+ return self
+
+ def clear(self):
+ self._form.listWidget.clear()
+
+ def refresh(self):
+ for row in range(self.count):
+ item = self._form.listWidget.item(row)
+ if hasattr(item, 'value'): item.setText(str(item.value))
+
+ ############################################################################
+ ############ Events ########################################################
+ ############################################################################
+
+ def __itemSelectionChanged(self):
+ self.selection_changed_event()
+
+ def selection_changed_event(self):
+ pass
+
+ ############################################################################
+ ############ Properties ####################################################
+ ############################################################################
+
+ @property
+ def count(self):
+ return self._form.listWidget.count()
+
+ @property
+ def checked_indexes(self):
+ results = []
+ for row in range(self.count):
+ item = self._form.listWidget.item(row)
+ if item != None and item.checkState() == QtCore.Qt.Checked: results.append(row)
+ return results
+
+ @property
+ def value(self):
+ results = []
+ for row in range(self.count):
+ item = self._form.listWidget.item(row)
+ if item != None and item.checkState() == QtCore.Qt.Checked:
+ results.append(item.value if hasattr(item, 'value') else str(item.text()))
+ return results
+
+ @value.setter
+ def value(self, value):
+ self.clear()
+ for row in value: self += row
+ self.changed_event()
+
+ @property
+ def selected_row_index(self):
+ return self.form.listWidget.currentRow()
+
+ @property
+ def items(self):
+ results = []
+ for row in range(self.count):
+ item = self._form.listWidget.item(row)
+ results.append(
+ [item.value if hasattr(item, 'value') else str(item.text()), item.checkState() == QtCore.Qt.Checked])
+ return results
diff --git a/pyforms/gui/Controls/ControlCodeEditor.py b/pyforms/gui/controls/ControlCodeEditor.py
old mode 100755
new mode 100644
similarity index 76%
rename from pyforms/gui/Controls/ControlCodeEditor.py
rename to pyforms/gui/controls/ControlCodeEditor.py
index 1a2c2a1..2b2c883
--- a/pyforms/gui/Controls/ControlCodeEditor.py
+++ b/pyforms/gui/controls/ControlCodeEditor.py
@@ -3,22 +3,21 @@
import logging
-from pysettings import conf
+from AnyQt import _api
+from pyforms.utils.settings_manager import conf
-from pyforms.gui.Controls.ControlBase import ControlBase
+from pyforms.gui.controls.ControlBase import ControlBase
import pyforms.utils.tools as tools
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QApplication
- from PyQt5.QtGui import QFontMetrics, QColor, QIcon, QFont
- from PyQt5.Qsci import QsciScintilla, QsciLexerPython
- from PyQt5 import uic
- from PyQt5 import QtCore
-else:
- from PyQt4.QtGui import QApplication, QFontMetrics, QColor, QIcon, QFont
- from PyQt4.Qsci import QsciScintilla, QsciLexerPython
- from PyQt4 import uic
- from PyQt4 import QtCore
+from AnyQt import QtCore, uic
+from AnyQt.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QSpinBox
+from AnyQt.QtGui import QFontMetrics, QColor, QIcon, QFont
+
+if _api.USED_API == _api.QT_API_PYQT5:
+ from PyQt5.Qsci import QsciScintilla, QsciLexerPython, QsciAPIs
+elif _api.USED_API == _api.QT_API_PYQT4:
+ from PyQt4.Qsci import QsciScintilla, QsciLexerPython, QsciAPIs
+
logger = logging.getLogger(__name__)
@@ -30,18 +29,19 @@ class ControlCodeEditor(ControlBase):
ARROW_MARKER_NUM = 8
- def __init__(self, label='', default='', helptext='', read_only=True):
+ def __init__(self, *args, **kwargs):
"""
:param label:
:param default:
:param helptext:
"""
- self._read_only = read_only
-
- super(ControlCodeEditor, self).__init__(label, default, helptext)
-
+ self._read_only = kwargs.get('readonly', False)
self._changed_func = None
+ super(ControlCodeEditor, self).__init__(*args, **kwargs)
+
+ self.discart_event = kwargs.get('discart_event', self.discart_event)
+
def init_form(self):
"""
@@ -51,14 +51,19 @@ def init_form(self):
control_path = tools.getFileInSameDirectory(__file__, "code_editor.ui")
self._form = uic.loadUi(control_path)
- self._code_editor = self._form.code_editor
+ self._code_editor = self._form.code_editor
self._save_button = self._form.save_button
+ self._discart_button = self._form.discart_button
+
self._save_button.clicked[bool].connect(self.on_save_changes)
+ self._discart_button.clicked[bool].connect(self.on_discart_changes)
- if not self._read_only:
+
+ if self._read_only:
self._code_editor.setReadOnly(True)
self._save_button.setVisible(False)
+ self._discart_button.setVisible(False)
self.form.font_size.addItem('9')
self.form.font_size.addItem('10')
@@ -75,6 +80,7 @@ def init_form(self):
self.form.font_size.currentIndexChanged.connect(self.__font_size_index_changed)
self.form.save_button.setIcon(QIcon(conf.PYFORMS_ICON_CODEEDITOR_SAVE))
+ self.form.discart_button.setIcon(QIcon(conf.PYFORMS_ICON_CODEEDITOR_DISCART))
self.lexer = QsciLexerPython
@@ -141,6 +147,18 @@ def _load_code_editor_settings(self):
# Don't want to see the horizontal scrollbar at all
# Use raw message to Scintilla here (all messages are documented here: http://www.scintilla.org/ScintillaDoc.html)
self._code_editor.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)
+
+ self._lexer_obj = lexer
+ self.qsci_api = QsciAPIs(self._lexer_obj)
+ ## Add autocompletion strings
+ self.qsci_api.add("aLongString")
+ self.qsci_api.add("aLongerString")
+ self.qsci_api.add("aDifferentString")
+ self.qsci_api.add("sOmethingElse")
+ ## Compile the api for use in the lexer
+ self.qsci_api.prepare()
+ self._code_editor.setAutoCompletionThreshold(1)
+ self._code_editor.setAutoCompletionSource(QsciScintilla.AcsAll)
# not too small
# self._code_editor.setMinimumSize(600, 450)
@@ -168,15 +186,30 @@ def on_modification_changed(self):
"""
On modification change, re-enable save button
"""
- if self._changed_func: self._save_button.setEnabled(True)
+ if self._changed_func:
+ self._save_button.setEnabled(True)
+ self._discart_button.setEnabled(True)
def on_save_changes(self):
"""
On button save clicked, save changes made on the code editor to file
"""
- if self.changed_event() and self._changed_func:
+ if self.changed_event():
self._code_editor.setModified(False)
self._save_button.setEnabled(False)
+ self._discart_button.setEnabled(False)
+
+ def on_discart_changes(self):
+
+ if self.discart_event():
+ self._code_editor.setModified(False)
+ self._save_button.setEnabled(False)
+ self._discart_button.setEnabled(False)
+
+ def discart_event(self):
+
+ return True
+
def _key_pressed(self, event):
"""
@@ -223,11 +256,11 @@ def value(self):
@value.setter
def value(self, value):
- ControlBase.value.fset(self, value)
- if len(value) > 0:
+ if value is not None:
self._code_editor.setText(str(value))
self._code_editor.setModified(False)
self._save_button.setEnabled(False)
+ self._discart_button.setEnabled(False)
@property
def changed_event(self):
diff --git a/pyforms/gui/Controls/ControlCombo.py b/pyforms/gui/controls/ControlCombo.py
old mode 100755
new mode 100644
similarity index 64%
rename from pyforms/gui/Controls/ControlCombo.py
rename to pyforms/gui/controls/ControlCombo.py
index df9860a..254edd0
--- a/pyforms/gui/Controls/ControlCombo.py
+++ b/pyforms/gui/controls/ControlCombo.py
@@ -4,51 +4,71 @@
import pyforms.utils.tools as tools
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
-if conf.PYFORMS_USE_QT5:
- from PyQt5 import uic
-else:
- from PyQt4 import uic
+from AnyQt.QtWidgets import QLabel, QWidget, QComboBox, QHBoxLayout, QSizePolicy
-from pyforms.gui.Controls.ControlBase import ControlBase
+from pyforms.gui.controls.ControlBase import ControlBase
-class ControlCombo(ControlBase):
+class ControlCombo(ControlBase, QWidget):
"""This class represents a wrapper to the combo box"""
+ def __init__(self, *args, **kwargs):
+ QWidget.__init__(self)
+ ControlBase.__init__(self, *args, **kwargs)
+
##########################################################################
############ Functions ###################################################
##########################################################################
def init_form(self):
- control_path = tools.getFileInSameDirectory(__file__, "comboInput.ui")
- self._form = uic.loadUi(control_path)
-
- self._form.comboLabel.setAccessibleName('ControlCombo-label')
- self._form.comboBox.currentIndexChanged.connect(self._currentIndexChanged)
- self._form.comboBox.activated.connect(self._activated)
- self._form.comboBox.highlighted.connect(self._highlighted)
- self._form.comboBox.editTextChanged.connect(self._editTextChanged)
+ self._layout = QHBoxLayout()
+ self._combo = QComboBox(self.form)
+
+ if self._label is not None:
+ self._combolabel = QLabel(self.form)
+ self._layout.addWidget( self._combolabel )
+ self._combolabel.setAccessibleName('ControlCombo-label')
+ self.label = self._label
+ else:
+ self._combolabel = None
+
+ self._layout.addWidget( self._combo )
+ self.form.setLayout( self._layout )
+
+
+ self._combo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
+ self._layout.setContentsMargins(0,0,0,0)
+ self.form.setContentsMargins(0,0,0,0)
+ self.form.setMinimumHeight(38)
+ self.form.setMaximumHeight(38)
+ self.form.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
+
+ self._combo.currentIndexChanged.connect(self._currentIndexChanged)
+ self._combo.activated.connect(self._activated)
+ self._combo.highlighted.connect(self._highlighted)
+ self._combo.editTextChanged.connect(self._editTextChanged)
+
self._items = {}
self._addingItem = False
- self.label = self._label
+
def clear(self):
self._items = {}
self._value = None
- self._form.comboBox.clear()
+ self._combo.clear()
def add_item(self, label, value=None):
self._addingItem = True
if value is not None:
if not (value in self._items.values()):
- self._form.comboBox.addItem(label)
+ self._combo.addItem(label)
else:
if not (label in self._items.keys()):
- self._form.comboBox.addItem(label)
+ self._combo.addItem(label)
firstValue = False
if self._items == {}:
@@ -77,10 +97,23 @@ def get_item_index_by_name(self, item_name):
:param item_name: item name in combo box
:type item_name: string
"""
- return self._form.comboBox.findText(item_name)
+ return self._combo.findText(item_name)
def count(self):
- return self._form.comboBox.count()
+ return self._combo.count()
+
+ def show(self):
+ """
+ Show the control
+ """
+ QWidget.show(self)
+
+ def hide(self):
+ """
+ Hide the control
+ """
+ QWidget.hide(self)
+
##########################################################################
############ Events ######################################################
@@ -110,13 +143,21 @@ def edittext_changed_event(self, text):
############ PROPERTIES ##################################################
##########################################################################
+ @property
+ def form(self):
+ return self
+
@property
def current_index(self):
- return self._form.comboBox.currentIndex()
+ return self._combo.currentIndex()
@current_index.setter
def current_index(self, value):
- self._form.comboBox.setCurrentIndex(value)
+ self._combo.setCurrentIndex(value)
+
+ @property
+ def values(self):
+ return self._items.values()
@property
def items(self):
@@ -130,15 +171,15 @@ def value(self):
def value(self, value):
for key, val in self.items:
if value == val:
- index = self._form.comboBox.findText(key)
- self._form.comboBox.setCurrentIndex(index)
+ index = self._combo.findText(key)
+ self._combo.setCurrentIndex(index)
if self._value != value:
self.changed_event()
self._value = val
@property
def text(self):
- return str(self._form.comboBox.currentText())
+ return str(self._combo.currentText())
@text.setter
def text(self, value):
@@ -149,7 +190,10 @@ def text(self, value):
@property
def label(self):
- return self._form.comboLabel.text()
+ if self._combolabel:
+ return self._combolabel.text()
+ else:
+ return None
@label.setter
def label(self, value):
@@ -157,7 +201,9 @@ def label(self, value):
Label of the control, if applies
@type value: string
"""
- self._form.comboLabel.setText(value)
+ if self._combolabel:
+ self._combolabel.setText(value)
+
##########################################################################
############ Private functions ###########################################
@@ -165,7 +211,7 @@ def label(self, value):
def _activated(self, index):
if not self._addingItem:
- item = self._form.comboBox.currentText()
+ item = self._combo.currentText()
if len(item) >= 1:
ControlBase.value.fset(self, self._items[str(item)])
self.activated_event(index)
@@ -182,7 +228,7 @@ def _editTextChanged(self, text):
def _currentIndexChanged(self, index):
if not self._addingItem:
- item = self._form.comboBox.currentText()
+ item = self._combo.currentText()
if len(item) >= 1:
ControlBase.value.fset(self, self._items[str(item)])
self.current_index_changed_event(index)
diff --git a/pyforms/gui/Controls/ControlDir.py b/pyforms/gui/controls/ControlDir.py
old mode 100755
new mode 100644
similarity index 72%
rename from pyforms/gui/Controls/ControlDir.py
rename to pyforms/gui/controls/ControlDir.py
index a4df416..8091a12
--- a/pyforms/gui/Controls/ControlDir.py
+++ b/pyforms/gui/controls/ControlDir.py
@@ -1,26 +1,24 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
-from pyforms.gui.Controls.ControlText import ControlText
+from pyforms.gui.controls.ControlText import ControlText
import pyforms.utils.tools as tools
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QFileDialog
- from PyQt5 import uic
-else:
- from PyQt4.QtGui import QFileDialog
- from PyQt4 import uic
+from AnyQt import uic
+from AnyQt.QtWidgets import QFileDialog
class ControlDir(ControlText):
+
def init_form(self):
control_path = tools.getFileInSameDirectory(__file__, "fileInput.ui")
self._form = uic.loadUi(control_path)
self._form.label.setText(self._label)
+ self._form.lineEdit.setText(self._value)
def click(self):
value = str(QFileDialog.getExistingDirectory(self._form, 'Choose a directory', self.value))
diff --git a/pyforms/gui/Controls/ControlDockWidget.py b/pyforms/gui/controls/ControlDockWidget.py
similarity index 74%
rename from pyforms/gui/Controls/ControlDockWidget.py
rename to pyforms/gui/controls/ControlDockWidget.py
index fd7fb35..35c2b48 100644
--- a/pyforms/gui/Controls/ControlDockWidget.py
+++ b/pyforms/gui/controls/ControlDockWidget.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-from pyforms.gui.Controls.ControlEmptyWidget import ControlEmptyWidget
+from pyforms.gui.controls.ControlEmptyWidget import ControlEmptyWidget
class ControlDockWidget(ControlEmptyWidget):
@@ -11,11 +11,13 @@ class ControlDockWidget(ControlEmptyWidget):
SIDE_BOTTOM = 'bottom'
SIDE_DETACHED = 'detached'
- def __init__(self, label='', default=None, side='left', order=0, margin=0):
- ControlEmptyWidget.__init__(self, label)
- self.side = side
- self.order = order
- self.margin = margin
+ def __init__(self, *args, **kwargs):
+ ControlEmptyWidget.__init__(self, *args, **kwargs)
+ self.side = kwargs.get('side', 'left')
+ self.order = kwargs.get('order',0)
+ self.margin = kwargs.get('margin', 0)
+
+ default = kwargs.get('default', None)
if default is not None: self.value = default
self._show = True
diff --git a/pyforms/gui/Controls/ControlEmptyWidget.py b/pyforms/gui/controls/ControlEmptyWidget.py
old mode 100755
new mode 100644
similarity index 72%
rename from pyforms/gui/Controls/ControlEmptyWidget.py
rename to pyforms/gui/controls/ControlEmptyWidget.py
index a144a5a..7fb92c1
--- a/pyforms/gui/Controls/ControlEmptyWidget.py
+++ b/pyforms/gui/controls/ControlEmptyWidget.py
@@ -1,34 +1,29 @@
#!/usr/bifn/python
# -*- coding: utf-8 -*-
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QWidget
- from PyQt5.QtWidgets import QVBoxLayout
-else:
- from PyQt4.QtGui import QWidget
- from PyQt4.QtGui import QVBoxLayout
-
-from pyforms.gui.Controls.ControlBase import ControlBase
-from pyforms.gui.BaseWidget import BaseWidget
+from AnyQt import _api
+from AnyQt.QtWidgets import QWidget, QVBoxLayout
+from pyforms.gui.controls.ControlBase import ControlBase
+from pyforms.gui.basewidget import BaseWidget
class ControlEmptyWidget(ControlBase, QWidget):
- def __init__(self, label='', default=None):
+ def __init__(self, *args, **kwargs):
QWidget.__init__(self)
layout = QVBoxLayout()
- if conf.PYFORMS_USE_QT5:
+ if _api.USED_API == _api.QT_API_PYQT5:
layout.setContentsMargins(0,0,0,0)
- else:
+ elif _api.USED_API == _api.QT_API_PYQT4:
layout.setMargin(0)
self.form.setLayout(layout)
- ControlBase.__init__(self, label)
- self.value = default
+ ControlBase.__init__(self, *args, **kwargs)
+ self.value = kwargs.get('default', None)
def init_form(self):
pass
@@ -55,9 +50,16 @@ def value(self, value):
if isinstance(value, list):
for w in value:
self.form.layout().addWidget(w.form)
+ if not hasattr(w, 'about_to_be_shown'):
+ w.about_to_be_shown = True
+ w.show()
+ del w.about_to_be_shown
else:
self.form.layout().addWidget(value.form)
-
+ if not hasattr(value, 'about_to_be_shown'):
+ value.about_to_be_shown = True
+ value.show()
+ del value.about_to_be_shown
# The init_form should be called only for the BaseWidget
if isinstance(value, BaseWidget) and not value._formLoaded:
diff --git a/pyforms/gui/Controls/ControlFile.py b/pyforms/gui/controls/ControlFile.py
old mode 100755
new mode 100644
similarity index 53%
rename from pyforms/gui/Controls/ControlFile.py
rename to pyforms/gui/controls/ControlFile.py
index 31039d2..f892f81
--- a/pyforms/gui/Controls/ControlFile.py
+++ b/pyforms/gui/controls/ControlFile.py
@@ -1,22 +1,23 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
-
-from pyforms.gui.Controls.ControlText import ControlText
+from pyforms.utils.settings_manager import conf
+from pyforms.gui.controls.ControlText import ControlText
import pyforms.utils.tools as tools
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QFileDialog
- from PyQt5 import uic
-else:
- from PyQt4.QtGui import QFileDialog
- from PyQt4 import uic
+from AnyQt import uic, _api
+from AnyQt.QtWidgets import QFileDialog
class ControlFile(ControlText):
+
+ def __init__(self, *args, **kwargs):
+
+ super(ControlFile, self).__init__(*args, **kwargs)
+ self.use_save_dialog = kwargs.get('use_save_dialog', False)
+
def init_form(self):
control_path = tools.getFileInSameDirectory(__file__, "fileInput.ui")
self._form = uic.loadUi(control_path)
@@ -30,11 +31,16 @@ def finishEditing(self):
self.changed_event()
def click(self):
- value = QFileDialog.getOpenFileName(self.parent, self._label, self.value)
+
+ if self.use_save_dialog:
+ value, _ = QFileDialog.getSaveFileName(self.parent, self._label, self.value)
+ else:
+ value = QFileDialog.getOpenFileName(self.parent, self._label, self.value)
+
- if conf.PYFORMS_USE_QT5:
+ if _api.USED_API == _api.QT_API_PYQT5:
value = value[0]
- else:
+ elif _api.USED_API == _api.QT_API_PYQT4:
value = str(value)
if value and len(value)>0: self.value = value
diff --git a/pyforms/gui/Controls/ControlFilesTree.py b/pyforms/gui/controls/ControlFilesTree.py
old mode 100755
new mode 100644
similarity index 59%
rename from pyforms/gui/Controls/ControlFilesTree.py
rename to pyforms/gui/controls/ControlFilesTree.py
index 3f5f899..1e6fa3e
--- a/pyforms/gui/Controls/ControlFilesTree.py
+++ b/pyforms/gui/controls/ControlFilesTree.py
@@ -2,20 +2,12 @@
# -*- coding: utf-8 -*-
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QTreeView
- from PyQt5.QtWidgets import QFileSystemModel
- from PyQt5 import QtCore
-
-else:
- from PyQt4.QtGui import QTreeView
- from PyQt4.QtGui import QFileSystemModel
- from PyQt4 import QtCore
+from pyforms.gui.controls.ControlBase import ControlBase
+from AnyQt import QtCore
+from AnyQt.QtWidgets import QTreeView, QFileSystemModel
class ControlFilesTree(ControlBase):
def init_form(self):
diff --git a/pyforms/gui/Controls/ControlImage.py b/pyforms/gui/controls/ControlImage.py
old mode 100755
new mode 100644
similarity index 69%
rename from pyforms/gui/Controls/ControlImage.py
rename to pyforms/gui/controls/ControlImage.py
index a7a93da..f669b4b
--- a/pyforms/gui/Controls/ControlImage.py
+++ b/pyforms/gui/controls/ControlImage.py
@@ -3,11 +3,11 @@
import logging
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
logger = logging.getLogger(__name__)
-from pyforms.gui.Controls.ControlBase import ControlBase
+from pyforms.gui.controls.ControlBase import ControlBase
from pyforms.utils import tools
try:
@@ -15,34 +15,33 @@
except:
logger.debug("OpenCV not available")
-if conf.PYFORMS_USE_QT5:
- from PyQt5 import uic
+import OpenGL.GL as GL
+import OpenGL.GLU as GLU
+
+from AnyQt import QtCore, QtOpenGL, uic
+from AnyQt.QtWidgets import QWidget
+from AnyQt import _api
+
+if _api.USED_API == _api.QT_API_PYQT5:
try:
- import OpenGL.GL as GL
- import OpenGL.GLU as GLU
- from PyQt5.QtOpenGL import QGLWidget
+ from AnyQt.QtOpenGL import QGLWidget
except:
logger.debug("No OpenGL library available")
import platform
-
if platform.system() == 'Darwin':
- from pyforms.gui.Controls.ControlPlayer.VideoQt5GLWidget import VideoQt5GLWidget as VideoGLWidget
+ from pyforms.gui.controls.control_player.VideoQt5GLWidget import VideoQt5GLWidget as VideoGLWidget
else:
- from pyforms.gui.Controls.ControlPlayer.VideoGLWidget import VideoGLWidget
-
-else:
- from PyQt4 import uic
+ from pyforms.gui.controls.control_player.VideoGLWidget import VideoGLWidget
+elif _api.USED_API == _api.QT_API_PYQT4:
try:
- import OpenGL.GL as GL
- import OpenGL.GLU as GLU
from PyQt4.QtOpenGL import QGLWidget
except:
logger.debug("No OpenGL library available")
- from pyforms.gui.Controls.ControlPlayer.VideoGLWidget import VideoGLWidget
+ from pyforms.gui.controls.control_player.VideoGLWidget import VideoGLWidget
import numpy as np
diff --git a/pyforms/gui/Controls/ControlLabel.py b/pyforms/gui/controls/ControlLabel.py
old mode 100755
new mode 100644
similarity index 75%
rename from pyforms/gui/Controls/ControlLabel.py
rename to pyforms/gui/controls/ControlLabel.py
index 3d30273..669877b
--- a/pyforms/gui/Controls/ControlLabel.py
+++ b/pyforms/gui/controls/ControlLabel.py
@@ -1,17 +1,14 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-""" pyforms.gui.Controls.ControlLabel"""
+""" pyforms.gui.controls.ControlLabel"""
import pyforms.utils.tools as tools
-from pysettings import conf
-if conf.PYFORMS_USE_QT5:
- from PyQt5 import uic
-else:
- from PyQt4 import uic
+from pyforms.utils.settings_manager import conf
+from AnyQt import uic
-from pyforms.gui.Controls.ControlBase import ControlBase
+from pyforms.gui.controls.ControlBase import ControlBase
__author__ = "Carlos Mão de Ferro"
__copyright__ = ""
@@ -25,9 +22,6 @@
class ControlLabel(ControlBase):
- def __init__(self, label=''):
- super(ControlLabel, self).__init__(label=label, default=label)
-
def init_form(self):
control_path = tools.getFileInSameDirectory(__file__, "label.ui")
self._form = uic.loadUi(control_path)
diff --git a/pyforms/gui/controls/ControlList.py b/pyforms/gui/controls/ControlList.py
new file mode 100644
index 0000000..0968a42
--- /dev/null
+++ b/pyforms/gui/controls/ControlList.py
@@ -0,0 +1,408 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+""" pyforms.gui.controls.ControlList
+
+"""
+import logging
+import os
+
+from pyforms.utils.settings_manager import conf
+
+from AnyQt import QtCore, uic
+from AnyQt.QtWidgets import QTableWidgetItem, QWidget, QAbstractItemView
+from AnyQt.QtGui import QIcon
+
+from pyforms.gui.basewidget import BaseWidget
+from pyforms.gui.controls.ControlBase import ControlBase
+
+logger = logging.getLogger(__name__)
+
+
+class ControlList(ControlBase, QWidget):
+ """ This class represents a wrapper to the table widget
+ It allows to implement a list view
+ """
+
+ CELL_VALUE_BEFORE_CHANGE = None # store value when cell is double clicked
+
+ def __init__(self, *args, **kwargs):
+ QWidget.__init__(self)
+
+ self._plusFunction = kwargs.get('add_function', None)
+ self._minusFunction = kwargs.get('remove_function', None)
+ ControlBase.__init__(self, *args, **kwargs)
+
+ self.autoscroll = kwargs.get('autoscroll', True)
+ self.resizecolumns = kwargs.get('resizecolumns', True)
+ self.select_entire_row = kwargs.get('select_entire_row', False)
+ self.horizontal_headers = kwargs.get('horizontal_headers', None)
+
+ ##########################################################################
+ ############ FUNCTIONS ###################################################
+ ##########################################################################
+
+ def init_form(self):
+ plusFunction = self._plusFunction
+ minusFunction = self._minusFunction
+
+ # Get the current path of the file
+ rootPath = os.path.dirname(__file__)
+ # Load the UI for the self instance
+ uic.loadUi(os.path.join(rootPath, "list.ui"), self)
+
+ self.label = self._label
+
+ self.tableWidget.currentCellChanged.connect(self.tableWidgetCellChanged)
+ self.tableWidget.currentItemChanged.connect(self.tableWidgetItemChanged)
+ self.tableWidget.itemSelectionChanged.connect(self.tableWidgetItemSelectionChanged)
+ self.tableWidget.cellDoubleClicked.connect(self.tableWidgetCellDoubleClicked)
+ self.tableWidget.model().dataChanged.connect(self._dataChangedEvent)
+
+
+ self.tableWidget.horizontalHeader().setVisible(False)
+
+ if plusFunction is None and minusFunction is None:
+ self.plusButton.hide()
+ self.minusButton.hide()
+ elif plusFunction is None:
+ self.plusButton.hide()
+ self.minusButton.pressed.connect(minusFunction)
+ elif minusFunction is None:
+ self.minusButton.hide()
+ self.plusButton.pressed.connect(plusFunction)
+ else:
+ self.plusButton.pressed.connect(plusFunction)
+ self.minusButton.pressed.connect(minusFunction)
+
+
+
+ def __repr__(self):
+ return "ControlList " + str(self._value)
+
+ def clear(self, headers=False):
+
+ for row in range(self.rows_count):
+ columns = []
+ for column in range(self.columns_count):
+ v = self.get_value(column, row)
+ if isinstance(v, BaseWidget):
+ v.destroy()
+
+ if headers:
+ self.tableWidget.clear()
+ self.tableWidget.setColumnCount(3)
+ self.tableWidget.setRowCount(0)
+ else:
+ self.tableWidget.clearContents()
+ self.tableWidget.setRowCount(0)
+
+ def save_form(self, data, path=None):
+ if self.value:
+ rows = []
+ for row in range(self.rows_count):
+ columns = []
+ for column in range(self.columns_count):
+ v = self.get_value(column, row)
+ if isinstance(v, BaseWidget):
+ columns.append(v.save_form({}, path))
+ else:
+ columns.append(str(v))
+ rows.append(columns)
+ data['value'] = rows
+ return data
+
+ def load_form(self, data, path=None):
+ if self.value:
+ rows = data['value']
+ for row in range(len(rows)):
+ for column in range(len(rows[row])):
+ v = self.get_value(column, row)
+ if isinstance(v, BaseWidget):
+ v.load_form(rows[row][column], path)
+ else:
+ self.set_value(column, row, rows[row][column])
+ elif 'value' in data.keys():
+ self.value = data['value']
+
+ def __add__(self, other):
+ row_index = self.tableWidget.rowCount()
+
+ self.tableWidget.insertRow(row_index)
+
+ #increase the number of columns if necessary ####
+ if self.tableWidget.currentColumn() < len(other):
+ self.tableWidget.setColumnCount(len(other))
+ #################################################
+
+ for column, e in enumerate(other): self.set_value(column, row_index, e)
+
+ #Auto resize the columns if the flag is activated ################
+ if self.resizecolumns:
+ self.tableWidget.resizeColumnsToContents()
+ ##################################################################
+
+ # auto scroll the list to the new inserted item ##################
+ if self.autoscroll:
+ self.tableWidget.scrollToItem( self.get_cell(0,row_index) )
+ ##################################################################
+ return self
+
+ def __sub__(self, other):
+
+ if isinstance(other, int):
+ if other < 0:
+ indexToRemove = self.tableWidget.currentRow()
+ else:
+ indexToRemove = other
+
+ self.tableWidget.removeRow(indexToRemove)
+ return self
+
+ def set_value(self, column, row, value):
+ if isinstance(value, QWidget):
+ self.tableWidget.setCellWidget(row, column, value)
+ value.show()
+ self.tableWidget.setRowHeight(row, value.height())
+ elif isinstance(value, ControlBase):
+ self.tableWidget.setCellWidget(row, column, value.form)
+ value.show()
+ self.tableWidget.setRowHeight(row, value.form.height())
+ else:
+ args = [value] if not hasattr(value, 'icon') else [QIcon(value.icon), value]
+ item = QTableWidgetItem()
+ item.setData(QtCore.Qt.EditRole, *args)
+ self.tableWidget.setItem(row, column, item)
+
+ def get_value(self, column, row):
+ try:
+ return str(self.tableWidget.item(row, column).text())
+ except AttributeError as err:
+ return self.tableWidget.cellWidget(row, column)
+ except AttributeError as err:
+ return ''
+
+ def resize_rows_contents(self):
+ self.tableWidget.resizeRowsToContents()
+
+ def get_currentrow_value(self):
+ currentRow = self.tableWidget.currentRow()
+ if not currentRow < 0:
+ return self.value[currentRow]
+ else:
+ return []
+
+ def get_cell(self, column, row):
+ return self.tableWidget.item(row, column)
+
+ def set_sorting_enabled(self, value):
+ """
+ Enable or disable columns sorting
+
+ :param bool value: True to enable sorting, False otherwise
+ """
+ self.tableWidget.setSortingEnabled(value)
+
+ ##########################################################################
+ ############ EVENTS ######################################################
+ ##########################################################################
+
+ def data_changed_event(self, row, col, item):
+ pass
+
+ def item_selection_changed_event(self):
+ pass
+
+ def current_cell_changed_event(self, next_row, next_col, previous_row, previous_col):
+ pass
+
+ def current_item_changed_event(self, current, previous):
+ pass
+
+ def cell_double_clicked_event(self, row, column):
+ pass
+
+ ##########################################################################
+ ############ PROPERTIES ##################################################
+ ##########################################################################
+
+
+ @property
+ def horizontal_headers(self):
+ return self._horizontalHeaders
+
+ @horizontal_headers.setter
+ def horizontal_headers(self, horizontal_headers):
+ """Set horizontal headers in the table list."""
+ if horizontal_headers is None:
+ self._horizontalHeaders = horizontal_headers
+ self.tableWidget.horizontalHeader().setVisible(False)
+ return
+
+
+ self._horizontalHeaders = horizontal_headers
+
+ self.tableWidget.setColumnCount(len(horizontal_headers))
+ self.tableWidget.horizontalHeader().setVisible(True)
+
+ for idx, header in enumerate(horizontal_headers):
+ item = QTableWidgetItem()
+ item.setText(header)
+ self.tableWidget.setHorizontalHeaderItem(idx, item)
+
+ @property
+ def word_wrap(self):
+ return self.tableWidget.wordWrap()
+
+ @word_wrap.setter
+ def word_wrap(self, value):
+ self.tableWidget.setWordWrap(value)
+
+ @property
+ def readonly(self):
+ return self.tableWidget.editTriggers()
+
+ @readonly.setter
+ def readonly(self, value):
+ if value:
+ self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
+ else:
+ self.tableWidget.setEditTriggers(QAbstractItemView.AllEditTriggers)
+
+ @property
+ def select_entire_row(self):
+ return self.tableWidget.selectionBehavior()
+
+ @select_entire_row.setter
+ def select_entire_row(self, value):
+ if value:
+ self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
+ else:
+ self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectItems)
+
+ @property
+ def rows_count(self):
+ return self.tableWidget.rowCount()
+
+ @property
+ def columns_count(self):
+ return self.tableWidget.columnCount()
+
+ def __len__(self):
+ return self.rows_count
+
+ @property
+ def value(self):
+ if hasattr(self, 'tableWidget'):
+ results = []
+ for row in range(self.tableWidget.rowCount()):
+ r = []
+ for col in range(self.tableWidget.columnCount()):
+ try:
+ r.append(self.get_value(col, row))
+ except Exception as err:
+ logger.debug(str(err))
+ r.append("")
+ results.append(r)
+ return results
+ return self._value
+
+ @value.setter
+ def value(self, value):
+ self.clear()
+ for row in value: self += row
+
+ # TODO: implement += on self.value? I want to add a list of tuples to
+ # self.value
+
+ @property
+ def selected_rows_indexes(self):
+ result = []
+ for index in self.tableWidget.selectedIndexes():
+ result.append(index.row())
+ return list(set(result))
+
+ @property
+ def selected_row_index(self):
+ indexes = self.selected_rows_indexes
+ if len(indexes) > 0:
+ return indexes[0]
+ else:
+ return None
+
+ @property
+ def label(self):
+ return self.labelWidget.getText()
+
+ @label.setter
+ def label(self, value):
+ if value.strip() != '':
+ self.labelWidget.setText(value)
+ else:
+ self.labelWidget.hide()
+
+ @property
+ def form(self):
+ return self
+
+ @property
+ def icon_size(self):
+ return self.tableWidget.iconSize()
+
+ @icon_size.setter
+ def icon_size(self, value):
+ if isinstance(value, (tuple, list)):
+ self.tableWidget.setIconSize(QtCore.QSize(*value))
+ else:
+ self.tableWidget.setIconSize(QtCore.QSize(value, value))
+
+ @property
+ def autoscroll(self): return self._autoscroll
+ @autoscroll.setter
+ def autoscroll(self, value): self._autoscroll = value
+
+ @property
+ def resizecolumns(self): return self._resizecolumns
+ @resizecolumns.setter
+ def resizecolumns(self, value): self._resizecolumns = value
+
+
+ ##########################################################################
+ ############ PRIVATE FUNCTIONS ###########################################
+ ##########################################################################
+
+ def _dataChangedEvent(self, item):
+ self.data_changed_event(item.row(), item.column(), self.tableWidget.model().data(item))
+ self.changed_event()
+
+ def tableWidgetCellChanged(self, nextRow, nextCol, previousRow,
+ previousCol):
+ self.current_cell_changed_event(nextRow, nextCol, previousRow, previousCol)
+ self.changed_event()
+
+ def tableWidgetItemChanged(self, current, previous):
+ self.current_item_changed_event(current, previous)
+ self.changed_event()
+
+ def tableWidgetItemSelectionChanged(self):
+ self.item_selection_changed_event()
+
+ def tableWidgetCellDoubleClicked(self, row, column):
+ """
+ (From PyQt) This signal is emitted whenever a cell in the table is double clicked.
+ The row and column specified is the cell that was double clicked.
+
+ Besides firing this signal, we save the current value, in case the user needs to know the old value.
+ :param row:
+ :param column:
+ :return:
+ """
+ self.CELL_VALUE_BEFORE_CHANGE = self.get_value(column, row)
+ logger.debug("Cell double clicked. Stored value: %s", self.CELL_VALUE_BEFORE_CHANGE)
+ self.cell_double_clicked_event(row, column)
+
+ def empty_signal(self, *args, **kwargs):
+ """
+ Use this function if you want to disconnect a signal temporarily
+ """
+ pass
diff --git a/pyforms/gui/Controls/ControlMatplotlib.py b/pyforms/gui/controls/ControlMatplotlib.py
similarity index 82%
rename from pyforms/gui/Controls/ControlMatplotlib.py
rename to pyforms/gui/controls/ControlMatplotlib.py
index f83d8d5..13a7ed2 100644
--- a/pyforms/gui/Controls/ControlMatplotlib.py
+++ b/pyforms/gui/controls/ControlMatplotlib.py
@@ -10,21 +10,19 @@
__status__ = "Development"
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QWidget, QVBoxLayout
-else:
- from PyQt4.QtGui import QWidget, QVBoxLayout
+from AnyQt.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout
+from pyforms.gui.controls.ControlBase import ControlBase
-from pyforms.gui.Controls.ControlBase import ControlBase
+from AnyQt import _api
-if conf.PYFORMS_USE_QT5:
+if _api.USED_API == _api.QT_API_PYQT5:
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
-else:
+elif _api.USED_API == _api.QT_API_PYQT4:
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
@@ -35,9 +33,9 @@
class ControlMatplotlib(ControlBase, QWidget):
- def __init__(self, label = ""):
+ def __init__(self, *args, **kwargs):
QWidget.__init__(self)
- ControlBase.__init__(self, label)
+ ControlBase.__init__(self, *args, **kwargs)
def init_form(self):
@@ -83,11 +81,6 @@ def on_draw(self, figure):
############ Properties ####################################################
############################################################################
- @property
- def axes(self): return self._axes
- @axes.setter
- def axes(self, value): self._axes = value
-
@property
def fig(self): return self._fig
@fig.setter
diff --git a/pyforms/gui/Controls/ControlMdiArea.py b/pyforms/gui/controls/ControlMdiArea.py
similarity index 90%
rename from pyforms/gui/Controls/ControlMdiArea.py
rename to pyforms/gui/controls/ControlMdiArea.py
index 6011c5e..ba45418 100644
--- a/pyforms/gui/Controls/ControlMdiArea.py
+++ b/pyforms/gui/controls/ControlMdiArea.py
@@ -3,17 +3,11 @@
import logging
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QMdiArea
- from PyQt5.QtWidgets import QMdiSubWindow
+from AnyQt.QtWidgets import QMdiArea, QMdiSubWindow
-else:
- from PyQt4.QtGui import QMdiArea
- from PyQt4.QtGui import QMdiSubWindow
-
-from pyforms.gui.Controls.ControlBase import ControlBase
+from pyforms.gui.controls.ControlBase import ControlBase
logger = logging.getLogger(__name__)
@@ -24,10 +18,11 @@ class ControlMdiArea(ControlBase, QMdiArea):
an area in which MDI windows are displayed.
"""
- def __init__(self, label=""):
+ def __init__(self, *args, **kwargs):
QMdiArea.__init__(self)
- ControlBase.__init__(self, label)
+ ControlBase.__init__(self, *args, **kwargs)
self._showCloseButton = True
+ self._openWindows = []
self.logger = logging.getLogger(__name__)
diff --git a/pyforms/gui/Controls/ControlNumber.py b/pyforms/gui/controls/ControlNumber.py
similarity index 79%
rename from pyforms/gui/Controls/ControlNumber.py
rename to pyforms/gui/controls/ControlNumber.py
index 3d9e6f2..5f29b31 100644
--- a/pyforms/gui/Controls/ControlNumber.py
+++ b/pyforms/gui/controls/ControlNumber.py
@@ -2,24 +2,22 @@
# -*- coding: utf-8 -*-
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
import pyforms.utils.tools as tools
-if conf.PYFORMS_USE_QT5:
- from PyQt5 import uic
+from AnyQt import uic
-else:
- from PyQt4 import uic
-
-from pyforms.gui.Controls.ControlBase import ControlBase
+from pyforms.gui.controls.ControlBase import ControlBase
class ControlNumber(ControlBase):
- def __init__(self, label="", default=0, minimum=0, maximum=100):
- self._min = minimum
- self._max = maximum
- ControlBase.__init__(self, label, default)
+ def __init__(self, *args, **kwargs):
+ self._min = kwargs.get('minimum', 0)
+ self._max = kwargs.get('maximum', 100)
+ if 'default' not in kwargs: kwargs['default'] = 0
+ ControlBase.__init__(self, *args, **kwargs)
+ self.decimals = kwargs.get('decimals', 0)
def init_form(self):
control_path = tools.getFileInSameDirectory(__file__, "number.ui")
@@ -30,7 +28,7 @@ def init_form(self):
self.value = self._value
self.form.label.setAccessibleName('ControlNumber-label')
self.form.spinBox.valueChanged.connect(self.update_event)
- self.form.spinBox.setDecimals(0)
+
def update_event(self, value):
self._updateSlider = False
@@ -53,7 +51,7 @@ def value(self):
return self._value
@value.setter
- def value(self, value):
+ def value(self, value):
self.form.spinBox.setValue(value)
ControlBase.value.fset(self, value)
diff --git a/pyforms/gui/controls/ControlOpenGL.py b/pyforms/gui/controls/ControlOpenGL.py
new file mode 100644
index 0000000..dcb6bd4
--- /dev/null
+++ b/pyforms/gui/controls/ControlOpenGL.py
@@ -0,0 +1,276 @@
+# !/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import logging
+
+from pyforms.utils.settings_manager import conf
+
+logger = logging.getLogger(__name__)
+
+from pyforms.gui.controls.ControlBase import ControlBase
+
+from AnyQt.QtWidgets import QSizePolicy
+
+from AnyQt import _api
+
+from OpenGL.GL import *
+from OpenGL.GLU import *
+
+from AnyQt import _api
+if _api.USED_API == _api.QT_API_PYQT5:
+ try:
+ from AnyQt.QtOpenGL import QGLWidget
+ except:
+ logger.debug("No OpenGL library available")
+
+ import platform
+ if platform.system() == 'Darwin':
+ from pyforms.gui.controls.control_player.VideoQt5GLWidget import VideoQt5GLWidget as VideoGLWidget
+ else:
+ from pyforms.gui.controls.control_player.VideoGLWidget import VideoGLWidget
+
+elif _api.USED_API == _api.QT_API_PYQT4:
+ try:
+ from PyQt4.QtOpenGL import QGLWidget
+ except:
+ logger.debug("No OpenGL library available")
+
+ from pyforms.gui.controls.control_player.VideoGLWidget import VideoGLWidget
+
+
+class OpenglGLWidget(QGLWidget):
+ def __init__(self, parent=None):
+ QGLWidget.__init__(self, parent)
+
+ self._zoom = 1.0
+ self._scene = None
+ self._rotation = [0, 0, 0]
+
+ self._mouseLeftDown = False
+ self._mouseRightDown = False
+
+ self._mouseGLPosition = [0, 0, 0]
+ self._lastMouseGLPosition = [0, 0, 0]
+
+ self._mousePosition = [0, 0] # Current mouse position
+ self._lastMousePosition = [0, 0] # Last mouse position
+
+ self._mouseStartDragPoint = None
+ self._clear_color = None
+
+ self.setMinimumHeight(100)
+ self.setMinimumWidth(100)
+ self.setMouseTracking(True)
+ self.setAcceptDrops(True)
+
+ self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding);
+
+ def initializeGL(self):
+ glClearDepth(1.0)
+ if self._clear_color: glClearColor(*self._clear_color)
+ glEnable(GL_BLEND)
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE)
+
+ glEnable(GL_POINT_SMOOTH);
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_POLYGON_SMOOTH);
+ glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
+ glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+ glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
+
+ def resizeGL(self, width, height):
+ """
+
+ :param width:
+ :param height:
+ :return:
+ """
+
+ glViewport(0, 0, width, height)
+ glMatrixMode(GL_PROJECTION)
+ glLoadIdentity()
+
+ if height!=0:
+ ratio = float(width) / float(height)
+ else:
+ ratio = 1
+ gluPerspective(65.0, ratio, 0.01, 800.0)
+
+ def paintGL(self):
+ """
+
+ """
+ if self._clear_color:
+ glBlendFunc(GL_ONE_MINUS_CONSTANT_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
+ glClearColor(*self._clear_color)
+ else:
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE)
+ glClearColor(0, 0, 0, 1)
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+ glMatrixMode(GL_MODELVIEW)
+ glLoadIdentity()
+
+ glEnable(GL_BLEND)
+
+ glScalef(1, -1, -1)
+
+ glTranslatef(0, 0, self._zoom)
+ glRotatef(self._rotation[0], 1, 0, 0)
+ glRotatef(self._rotation[1], 0, 1, 0)
+ glRotatef(self._rotation[2], 0, 0, 1)
+
+ if self._scene != None: self._scene.DrawGLScene()
+
+ if self.mouseDown:
+ # Get mouse position
+ modelview, projection = glGetDoublev(GL_MODELVIEW_MATRIX), glGetDoublev(GL_PROJECTION_MATRIX)
+ viewport = glGetIntegerv(GL_VIEWPORT)
+ winX, winY = float(self._mousePosition[0]), float(viewport[3] - self._mousePosition[1])
+ winZ = glReadPixels(winX, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)
+ self._mouseGLPosition = gluUnProject(winX, winY, winZ[0][0], modelview, projection, viewport)
+
+ glDisable(GL_BLEND)
+
+ def __updateMouse(self, event, pressed=None):
+ self._mousePosition[0] = event.x()
+ self._mousePosition[1] = event.y()
+
+ if pressed != None:
+ if event.button() == 2: self._mouseRightDown = pressed
+ if event.button() == 1: self._mouseLeftDown = pressed
+
+ def wheelEvent(self, event):
+ """
+
+ :param event:
+ """
+ if _api.USED_API == _api.QT_API_PYQT5:
+ p = event.angleDelta()
+ delta = p.y()
+ elif _api.USED_API == _api.QT_API_PYQT4:
+ delta = event.delta()
+
+
+ if delta < 0:
+ self._zoom += 1
+ else:
+ self._zoom -= 1
+
+ self.repaint()
+
+ def mouseReleaseEvent(self, event):
+ """
+
+ :param event:
+ """
+ self.__updateMouse(event)
+
+ if self._mouseRightDown:
+ self._lastMouseGLPosition = self._mouseGLPosition
+ self._mouseRightDown = False
+
+ if self._mouseLeftDown:
+ self.onEndDrag(self._mouseStartDragPoint, self._mouseGLPosition)
+ self._mouseLeftDown = False
+
+ def mousePressEvent(self, event):
+ """
+
+ :param event:
+ """
+ QGLWidget.mousePressEvent(self, event)
+ self.__updateMouse(event, pressed=True)
+ self.repaint()
+
+ if self._mouseLeftDown: self._mouseStartDragPoint = self._mouseGLPosition
+ if self._mouseRightDown: self._lastMouseGLPosition = self._mouseGLPosition
+
+ self.onPress(event.button(), self._mousePosition, self._mouseGLPosition)
+
+ def mouseMoveEvent(self, event):
+ """
+
+ :param event:
+ """
+ QGLWidget.mouseMoveEvent(self, event)
+ self.__updateMouse(event)
+ self.repaint()
+
+ self.onMove((self._mouseGLPosition[0], self._mouseGLPosition[1]))
+
+ if self.mouseDown:
+ if self._mouseLeftDown:
+ # p = self._mouseGLPosition[0] - self._x, self._mouseGLPosition[1] + self._y
+ # p = self._mouseGLPosition[0], self._mouseGLPosition[1]
+ self.onDrag(self._lastMousePosition, self._mousePosition)
+
+ self._lastMousePosition = list(self._mousePosition)
+
+ def onMove(self, point):
+ pass
+
+ def onPress(self, button, point, glpoint=None):
+ pass
+
+ def onDrag(self, startPoint, endPoint, startGLPoint=None, endGLPoint=None):
+ """
+
+ :param startPoint:
+ :param endPoint:
+ :param startGLPoint:
+ :param endGLPoint:
+ """
+ movX, movY = endPoint[0] - startPoint[0], endPoint[1] - startPoint[1]
+ self._rotation[2] -= float(movX) * 0.15
+ self._rotation[0] += float(movY) * 0.15
+
+ def onEndDrag(self, startPoint, endPoint, startGLPoint=None, endGLPoint=None):
+ pass
+
+ ##############################################################################
+ ###### Properties ############################################################
+ ##############################################################################
+
+ @property
+ def scene(self):
+ return self._scene
+
+ @scene.setter
+ def scene(self, value):
+ self._scene = value
+
+ @property
+ def mouseDown(self):
+ return self._mouseLeftDown or self._mouseRightDown
+
+ def resetZoomAndRotation(self):
+ self._zoom, self._rotation = 0.0, [0, 0, 0]
+
+
+class ControlOpenGL(ControlBase):
+ def init_form(self): self._form = OpenglGLWidget()
+
+ def repaint(self): self._form.repaint()
+
+ def reset_zoom_and_rotation(self): self._form.resetZoomAndRotation()
+
+ @property
+ def value(self): return self._form.scene
+
+ @value.setter
+ def value(self, value): self._form.scene = value; self._form.repaint()
+
+ @property
+ def clear_color(self): self._form._clear_color
+
+ @clear_color.setter
+ def clear_color(self, value):
+ self._form._clear_color = value;
+ self._form.repaint()
+
+ @property
+ def width(self): return self._form.width()
+
+ @property
+ def height(self): return self._form.height()
diff --git a/pyforms/gui/Controls/ControlProgress.py b/pyforms/gui/controls/ControlProgress.py
old mode 100755
new mode 100644
similarity index 77%
rename from pyforms/gui/Controls/ControlProgress.py
rename to pyforms/gui/controls/ControlProgress.py
index a3d2a9a..d4dc776
--- a/pyforms/gui/Controls/ControlProgress.py
+++ b/pyforms/gui/controls/ControlProgress.py
@@ -2,27 +2,20 @@
# -*- coding: utf-8 -*-
import os
-
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5 import uic
- from PyQt5.QtWidgets import QApplication
-
-else:
- from PyQt4 import uic
- from PyQt4.QtGui import QApplication
-
+from pyforms.gui.controls.ControlBase import ControlBase
+from AnyQt import uic
+from AnyQt.QtWidgets import QApplication
class ControlProgress(ControlBase):
- def __init__(self, label="%p%", default=0, min=0, max=100):
+
+ def __init__(self, *args, **kwargs):
self._updateSlider = True
- self._min = min
- self._max = max
+ self._min = kwargs.get('minimum', 0)
+ self._max = kwargs.get('maximum', 100)
+ if 'default' not in kwargs: kwargs['default'] = 0
+ ControlBase.__init__(self, *args, **kwargs)
- ControlBase.__init__(self, label, default)
+
def init_form(self):
module_path = os.path.abspath(os.path.dirname(__file__))
diff --git a/pyforms/gui/Controls/ControlSlider.py b/pyforms/gui/controls/ControlSlider.py
old mode 100755
new mode 100644
similarity index 78%
rename from pyforms/gui/Controls/ControlSlider.py
rename to pyforms/gui/controls/ControlSlider.py
index 43c8ae7..4d0b3d1
--- a/pyforms/gui/Controls/ControlSlider.py
+++ b/pyforms/gui/controls/ControlSlider.py
@@ -1,29 +1,26 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
-
import pyforms.utils.tools as tools
-if conf.PYFORMS_USE_QT5:
- from PyQt5 import uic
-
-else:
- from PyQt4 import uic
-
-from pyforms.gui.Controls.ControlBase import ControlBase
+from AnyQt import uic
+from pyforms.gui.controls.ControlBase import ControlBase
class ControlSlider(ControlBase):
- def __init__(self, label="", default=0, min=0, max=100):
- self._updateSlider = True
- self._min = min
- self._max = max
- ControlBase.__init__(self, label, default)
- self._form.value.setText(str(default))
+ def __init__(self, *args, **kwargs):
+ self._updateSlider = True
+ self._min = kwargs.get('minimum', 0)
+ self._max = kwargs.get('maximum', 100)
+ if 'default' not in kwargs: kwargs['default'] = 0
+ ControlBase.__init__(self, *args, **kwargs)
+
+ self._form.value.setText(str(kwargs['default']))
self._form.horizontalSlider.valueChanged.connect(self.valueChanged)
+
+
def init_form(self):
control_path = tools.getFileInSameDirectory(__file__, "sliderInput.ui")
self._form = uic.loadUi(control_path)
@@ -43,7 +40,7 @@ def load_form(self, data, path=None):
if 'value' in data: self.value = int(data['value'])
def save_form(self, data, path=None):
- if self.value: data['value'] = self.value
+ data['value'] = self.value
@property
def value(self):
diff --git a/pyforms/gui/controls/ControlTableView.py b/pyforms/gui/controls/ControlTableView.py
new file mode 100644
index 0000000..0946a0f
--- /dev/null
+++ b/pyforms/gui/controls/ControlTableView.py
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+""" pyforms.gui.controls.ControlList
+
+"""
+import logging
+import os
+
+from pyforms.utils.settings_manager import conf
+
+from AnyQt import QtCore, uic
+from AnyQt.QtWidgets import QTableView, QAbstractItemView
+from AnyQt.QtGui import QIcon
+
+from pyforms.gui.basewidget import BaseWidget
+from pyforms.gui.controls.ControlBase import ControlBase
+
+logger = logging.getLogger(__name__)
+
+
+class ControlTableView(ControlBase, QTableView):
+ """ This class represents a wrapper to the table widget
+ It allows to implement a list view
+ """
+
+ CELL_VALUE_BEFORE_CHANGE = None # store value when cell is double clicked
+
+ def __init__(self, *args, **kwargs):
+ QTableView.__init__(self)
+ ControlBase.__init__(self, *args, **kwargs)
+
+ if kwargs.get('select_entire_row', False):
+ self.setSelectionBehavior(QAbstractItemView.SelectRows)
+
+
+ ##########################################################################
+ ############ EVENTS ######################################################
+ ##########################################################################
+
+
+ ##########################################################################
+ ############ PROPERTIES ##################################################
+ ##########################################################################
+
+
+
+ @property
+ def value(self):
+ return self.model()
+
+ @value.setter
+ def value(self, value):
+ self.setModel(value)
+
+
+
+
+ @property
+ def form(self):
+ return self
+
+
+ ##########################################################################
+ ############ PRIVATE FUNCTIONS ###########################################
+ ##########################################################################
diff --git a/pyforms/gui/Controls/ControlText.py b/pyforms/gui/controls/ControlText.py
old mode 100755
new mode 100644
similarity index 87%
rename from pyforms/gui/Controls/ControlText.py
rename to pyforms/gui/controls/ControlText.py
index 45b4516..610c2b5
--- a/pyforms/gui/Controls/ControlText.py
+++ b/pyforms/gui/controls/ControlText.py
@@ -10,18 +10,10 @@
@status: Development
@lastEditedBy: Carlos Mão de Ferro (carlos.maodeferro@neuro.fchampalimaud.org)
'''
-
-from pyforms.gui.Controls.ControlBase import ControlBase
import pyforms.utils.tools as tools
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QLineEdit
- from PyQt5 import uic
-else:
- from PyQt4.QtGui import QLineEdit
- from PyQt4 import uic
+from pyforms.gui.controls.ControlBase import ControlBase
+from AnyQt.QtWidgets import QLineEdit
+from AnyQt import uic
class ControlText(ControlBase):
diff --git a/pyforms/gui/controls/ControlTextArea.py b/pyforms/gui/controls/ControlTextArea.py
new file mode 100644
index 0000000..cc1cd46
--- /dev/null
+++ b/pyforms/gui/controls/ControlTextArea.py
@@ -0,0 +1,71 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+__author__ = "Ricardo Ribeiro"
+__credits__ = ["Ricardo Ribeiro"]
+__license__ = "MIT"
+__version__ = "0.0"
+__maintainer__ = "Ricardo Ribeiro"
+__email__ = "ricardojvr@gmail.com"
+__status__ = "Development"
+
+import pyforms.utils.tools as tools
+from AnyQt import uic, QtGui
+from pyforms.gui.controls.ControlBase import ControlBase
+
+class ControlTextArea(ControlBase):
+
+ def __init__(self, *args, **kwargs):
+ ControlBase.__init__(self, *args, **kwargs)
+ self.autoscroll = kwargs.get('autoscroll', False)
+
+
+
+ def init_form(self):
+ control_path = tools.getFileInSameDirectory(__file__, "textArea.ui")
+ self._form = uic.loadUi(control_path)
+ self._form.label.setText(self._label)
+ if self._value:
+ self._form.plainTextEdit.setPlainText(str(self._value))
+
+ if not self._label or len(self._label)==0:
+ self.form.label.hide()
+
+ super(ControlTextArea, self).init_form()
+ self.form.plainTextEdit.textChanged.connect(self.finishEditing)
+
+ def __add__(self, other):
+ self._form.plainTextEdit.appendPlainText(str(other))
+
+ # if activated the text field is autoscrolled to the bottom
+ if self.autoscroll:
+ self._form.plainTextEdit.moveCursor(QtGui.QTextCursor.End)
+
+ return self
+
+ def finishEditing(self):
+ """Function called when the lineEdit widget is edited"""
+ self.changed_event()
+
+
+ @property
+ def value(self):
+ return self._form.plainTextEdit.toPlainText()
+
+ @value.setter
+ def value(self, value):
+ self._form.plainTextEdit.setPlainText(str(value))
+
+ @property
+ def readonly(self):
+ return self._form.plainTextEdit.isReadOnly()
+
+ @readonly.setter
+ def readonly(self, value):
+ self._form.plainTextEdit.setReadOnly(value)
+
+
+ @property
+ def autoscroll(self): return self._autoscroll
+ @autoscroll.setter
+ def autoscroll(self, value): self._autoscroll = value
diff --git a/pyforms/gui/Controls/ControlToolBox.py b/pyforms/gui/controls/ControlToolBox.py
similarity index 72%
rename from pyforms/gui/Controls/ControlToolBox.py
rename to pyforms/gui/controls/ControlToolBox.py
index 87ecbfb..4562d9d 100644
--- a/pyforms/gui/Controls/ControlToolBox.py
+++ b/pyforms/gui/controls/ControlToolBox.py
@@ -1,21 +1,15 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QToolBox
- from PyQt5.QtWidgets import QFrame
- from PyQt5.QtWidgets import QVBoxLayout
- from PyQt5.QtWidgets import QHBoxLayout
+from AnyQt import _api
+from AnyQt.QtWidgets import QToolBox
+from AnyQt.QtWidgets import QFrame
+from AnyQt.QtWidgets import QVBoxLayout
+from AnyQt.QtWidgets import QHBoxLayout
-else:
- from PyQt4.QtGui import QToolBox
- from PyQt4.QtGui import QFrame
- from PyQt4.QtGui import QVBoxLayout
- from PyQt4.QtGui import QHBoxLayout
-
-from pyforms.gui.Controls.ControlBase import ControlBase
+from pyforms.gui.controls.ControlBase import ControlBase
class ControlToolBox(ControlBase):
@@ -39,9 +33,9 @@ def value(self, value):
widget = QFrame(self.form);
layout = QVBoxLayout();
- if conf.PYFORMS_USE_QT5:
+ if _api.USED_API == _api.QT_API_PYQT5:
layout.setContentsMargins(0,0,0,0)
- else:
+ elif _api.USED_API == _api.QT_API_PYQT4:
layout.setMargin(0)
widget.setLayout(layout)
@@ -51,9 +45,9 @@ def value(self, value):
hwidget = QFrame(self.form);
hlayout = QHBoxLayout();
- if conf.PYFORMS_USE_QT5:
+ if _api.USED_API == _api.QT_API_PYQT5:
hlayout.setContentsMargins(0,0,0,0)
- else:
+ elif _api.USED_API == _api.QT_API_PYQT4:
hlayout.setMargin(0)
hwidget.setLayout(hlayout)
diff --git a/pyforms/gui/controls/ControlToolButton.py b/pyforms/gui/controls/ControlToolButton.py
new file mode 100644
index 0000000..0fd102c
--- /dev/null
+++ b/pyforms/gui/controls/ControlToolButton.py
@@ -0,0 +1,96 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+
+
+from pyforms.utils.settings_manager import conf
+
+from AnyQt.QtCore import Qt
+from AnyQt import uic
+from AnyQt.QtWidgets import QToolButton, QSizePolicy
+from AnyQt.QtGui import QIcon
+
+from pyforms.gui.controls.ControlBase import ControlBase
+
+
+class ControlToolButton(ControlBase):
+ def __init__(self, *args, **kwargs):
+ self._checkable = kwargs.get('checkable', False)
+ self._maxheight = kwargs.get('maxheight', None)
+ self._maxwidth = kwargs.get('maxwidth', None)
+ super(ControlToolButton, self).__init__(*args, **kwargs)
+
+ default = kwargs.get('default', None)
+ if default: self.value = default
+
+ icon = kwargs.get('icon', None)
+ if icon: self.icon = icon
+
+
+
+ def init_form(self):
+ self._form = QToolButton()
+ if self._maxwidth: self._form.setMaximumWidth(self._maxwidth)
+ if self._maxheight: self._form.setMaximumHeight(self._maxheight)
+ self._form.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
+ self._form.setCheckable(self._checkable)
+ self.label = self._label
+ self._form.setToolTip(self.help)
+
+ def click(self):
+ self._form.click()
+
+ def load_form(self, data, path=None):
+ pass
+
+ def save_form(self, data, path=None):
+ pass
+
+ ##########################################################################
+
+ @property
+ def label(self):
+ return ControlBase.label.fget(self)
+
+ @label.setter
+ def label(self, value):
+ ControlBase.label.fset(self, value)
+ if value is None:
+ self._form.setToolButtonStyle(Qt.ToolButtonIconOnly)
+ else:
+ self._form.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
+ self._form.setText(self._label)
+
+ @property
+ def icon(self):
+ return self._form.icon()
+
+ @icon.setter
+ def icon(self, value):
+ if isinstance(value, (str, bytes)):
+ self._form.setIcon(QIcon(value))
+ else:
+ self._form.setIcon(value)
+
+ ##########################################################################
+
+ @property
+ def value(self):
+ return None
+
+ @value.setter
+ def value(self, value):
+ try:
+ self._form.clicked.disconnect() # ignore previous signals if any
+ except TypeError as err:
+ # http://stackoverflow.com/questions/21586643/pyqt-widget-connect-and-disconnect
+ pass
+ self._form.clicked[bool].connect(value)
+
+ @property
+ def checked(self):
+ return self._form.isChecked()
+
+ @checked.setter
+ def checked(self, value):
+ self._form.setChecked(value)
diff --git a/pyforms/gui/Controls/ControlTree.py b/pyforms/gui/controls/ControlTree.py
similarity index 94%
rename from pyforms/gui/Controls/ControlTree.py
rename to pyforms/gui/controls/ControlTree.py
index e5c00a2..07ce514 100644
--- a/pyforms/gui/Controls/ControlTree.py
+++ b/pyforms/gui/controls/ControlTree.py
@@ -1,26 +1,17 @@
# !/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
-
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QTreeView, QAbstractItemView, QAction
- from PyQt5.QtGui import QIcon, QKeySequence
- from PyQt5 import QtCore
-
-else:
- from PyQt4.QtGui import QTreeWidget, QTreeWidgetItem, QTreeView, QAbstractItemView, QAction, QKeySequence, QIcon
- from PyQt4 import QtCore
-
+from pyforms.gui.controls.ControlBase import ControlBase
+from AnyQt.QtWidgets import QTreeWidget, QTreeWidgetItem, QTreeView, QAbstractItemView, QAction
+from AnyQt.QtGui import QIcon, QKeySequence
+from AnyQt import QtCore
class ControlTree(ControlBase, QTreeWidget):
"""This class represents a wrapper to the QTreeWidget"""
- def __init__(self, label='', default=''):
+ def __init__(self, *args, **kwargs):
QTreeWidget.__init__(self)
- ControlBase.__init__(self, label, default)
+ ControlBase.__init__(self, *args, **kwargs)
def init_form(self):
self.setSelectionBehavior(QAbstractItemView.SelectRows)
diff --git a/pyforms/gui/controls/ControlTreeView.py b/pyforms/gui/controls/ControlTreeView.py
new file mode 100644
index 0000000..aec05bb
--- /dev/null
+++ b/pyforms/gui/controls/ControlTreeView.py
@@ -0,0 +1,83 @@
+# !/usr/bin/python
+# -*- coding: utf-8 -*-
+from pyforms.gui.controls.ControlBase import ControlBase
+
+from AnyQt.QtWidgets import QTreeView, QAbstractItemView
+from AnyQt.QtGui import QStandardItem, QStandardItemModel
+
+
+class ControlTreeView(ControlBase, QTreeView):
+
+ default_width = None
+
+ def __init__(self, *args, **kwargs):
+ QTreeView.__init__(self)
+ ControlBase.__init__(self, *args, **kwargs)
+
+ self.item_selection_changed_event = kwargs.get('item_selection_changed_event', self.item_selection_changed_event)
+ self.item_double_clicked_event = kwargs.get('item_double_clicked_event', self.item_double_clicked_event)
+
+ def init_form(self):
+ #self.header().hide()
+ self.setSelectionBehavior(QAbstractItemView.SelectRows)
+ self.setUniformRowHeights(True)
+ #self.setDragDropMode(QAbstractItemView.InternalMove)
+ #self.setDragEnabled(True)
+ #self.setAcceptDrops(True)
+
+ self.value = QStandardItemModel() if self._value is None else self._value
+
+ #self.selectionChanged = self.__selectionChanged
+ self.mouseDoubleClickEvent = self.__itemDoubleClicked
+
+ self.selectionModel().selectionChanged.connect(self.__selectionChanged)
+
+ def item_selection_changed_event(self, selected, deselected):
+ pass
+
+ def item_double_clicked_event(self, evt):
+ pass
+
+ ###################################################
+ ## OTHER FUNCTIONS ################################
+ ###################################################
+
+ def __itemDoubleClicked(self, evt):
+ self.item_double_clicked_event(evt)
+
+ def __selectionChanged(self, selected, deselected):
+ #def selectionChanged(self, selected, deselected):
+ self.item_selection_changed_event(selected, deselected)
+ #super(QTreeView, self.form).selectionChanged(selected, deselected)
+
+ ###################################################
+ ## PROPERTIES #####################################
+ ###################################################
+
+ @property
+ def selected_row_index(self):
+ for index in self.selectedIndexes():
+ return index.row()
+ return None
+
+ @property
+ def selected_item(self):
+ for index in self.selectedIndexes():
+ res = []
+ while index.isValid():
+ print( index.data() )
+ res.append( index.data() )
+ index = index.parent()
+ return list(reversed(res))
+ return None
+
+ @property
+ def value(self):
+ return self.model()
+
+ @value.setter
+ def value(self, value): self.setModel(value)
+
+
+ @property
+ def form(self): return self
diff --git a/pyforms/gui/Controls/ControlVisVis.py b/pyforms/gui/controls/ControlVisVis.py
old mode 100755
new mode 100644
similarity index 80%
rename from pyforms/gui/Controls/ControlVisVis.py
rename to pyforms/gui/controls/ControlVisVis.py
index a0d9577..5efad6b
--- a/pyforms/gui/Controls/ControlVisVis.py
+++ b/pyforms/gui/controls/ControlVisVis.py
@@ -9,41 +9,33 @@
__email__ = "ricardojvr@gmail.com"
__status__ = "Development"
+import visvis as vv, numpy as np
-import pyforms.utils.tools as tools
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-from visvis import Point, Pointset
-import visvis as vv
-import numpy as np
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QWidget, QVBoxLayout, QSizePolicy
-else:
- from PyQt4.QtGui import QWidget, QVBoxLayout, QSizePolicy
+from visvis import Point, Pointset
+from pyforms.gui.controls.ControlBase import ControlBase
+from AnyQt import _api
+from AnyQt.QtWidgets import QWidget, QVBoxLayout, QSizePolicy
class ControlVisVis(ControlBase):
def init_form(self):
- self._form = QtGui.QWidget()
- layout = QtGui.QVBoxLayout()
+ self._form = QWidget()
+ layout = QVBoxLayout()
- if conf.PYFORMS_USE_QT5:
+ if _api.USED_API == _api.QT_API_PYQT5:
layout.setContentsMargins(0,0,0,0)
else:
layout.setMargin(0)
self._form.setLayout( layout )
- self._app = vv.use('pyqt4')
+ self._app = vv.use('pyqt5')
self._app.Create()
Figure = self._app.GetFigureClass()
self._fig = Figure(self._form)
- policy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
+ policy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
widget = self._fig._widget
widget.setSizePolicy(policy)
diff --git a/pyforms/gui/Controls/ControlVisVisVolume.py b/pyforms/gui/controls/ControlVisVisVolume.py
old mode 100755
new mode 100644
similarity index 80%
rename from pyforms/gui/Controls/ControlVisVisVolume.py
rename to pyforms/gui/controls/ControlVisVisVolume.py
index d7709ee..723fc35
--- a/pyforms/gui/Controls/ControlVisVisVolume.py
+++ b/pyforms/gui/controls/ControlVisVisVolume.py
@@ -9,33 +9,24 @@
__email__ = "ricardojvr@gmail.com"
__status__ = "Development"
-import pyforms.utils.tools as tools
-from pyforms.gui.Controls.ControlBase import ControlBase
-
-from visvis import Point, Pointset
-import visvis as vv
-import numpy as np
-
-from pysettings import conf
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QWidget, QVBoxLayout, QSizePolicy
-else:
- from PyQt4.QtGui import QWidget, QVBoxLayout, QSizePolicy
-
+import visvis as vv, numpy as np
+from pyforms.gui.controls.ControlBase import ControlBase
+from visvis import Point, Pointset
+from AnyQt import _api
+from AnyQt.QtWidgets import QWidget, QVBoxLayout, QSizePolicy
class ControlVisVisVolume(ControlBase):
def init_form(self):
self._form = QWidget()
layout = QVBoxLayout()
- layout.setMargin(0)
-
- if conf.PYFORMS_USE_QT5:
+
+ if _api.USED_API == _api.QT_API_PYQT5:
layout.setContentsMargins(0,0,0,0)
- else:
+ elif _api.USED_API == _api.QT_API_PYQT4:
layout.setMargin(0)
self._form.setLayout(layout)
- self._app = vv.use('pyqt4')
+ self._app = vv.use('pyqt5')
self._app.Create()
self._first = True
diff --git a/pyforms/gui/controls/ControlWeb.py b/pyforms/gui/controls/ControlWeb.py
new file mode 100644
index 0000000..a8415a3
--- /dev/null
+++ b/pyforms/gui/controls/ControlWeb.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+__author__ = "Ricardo Ribeiro"
+__credits__ = ["Ricardo Ribeiro"]
+__license__ = "MIT"
+__version__ = "0.0"
+__maintainer__ = "Ricardo Ribeiro"
+__email__ = "ricardojvr@gmail.com"
+__status__ = "Development"
+
+from AnyQt.QtWebEngineWidgets import QWebEngineView as QWebView
+from AnyQt.QtCore import QUrl
+from pyforms.gui.controls.ControlBase import ControlBase
+
+
+class ControlWeb(ControlBase, QWebView):
+ def __init__(self, *args, **kwargs):
+ QWebView.__init__(self)
+ if 'load_finnished_event' in kwargs:
+ self.load_finnished_event=kwargs['load_finnished_event']
+ self.loadFinished.connect(self.__load_finnished_evt)
+ ControlBase.__init__(self, *args, **kwargs)
+
+
+ def init_form(self):
+ """
+ Load Control and initiate the events
+ """
+ ControlBase.init_form(self)
+ if self._value: QWebView.load(self, QUrl(self._value))
+ if self.help: self.form.setToolTip(self.help)
+ ############################################################################
+ ############ Properties ####################################################
+ ############################################################################
+
+ def __load_finnished_evt(self, ok):
+ self.load_finnished_event(ok)
+
+ def load_finnished_event(self,ok):
+ pass
+
+ @property
+ def value(self): return ControlBase.value.fget(self)
+
+ @value.setter
+ def value(self, value):
+ ControlBase.value.fset(self, value)
+ QWebView.load(self, QUrl(value))
+
+ @property
+ def form(self):
+ return self
diff --git a/pyforms/gui/Controls/__init__.py b/pyforms/gui/controls/__init__.py
old mode 100755
new mode 100644
similarity index 100%
rename from pyforms/gui/Controls/__init__.py
rename to pyforms/gui/controls/__init__.py
diff --git a/pyforms/gui/Controls/button.ui b/pyforms/gui/controls/button.ui
old mode 100755
new mode 100644
similarity index 100%
rename from pyforms/gui/Controls/button.ui
rename to pyforms/gui/controls/button.ui
diff --git a/pyforms/gui/Controls/checkbox.ui b/pyforms/gui/controls/checkbox.ui
old mode 100755
new mode 100644
similarity index 100%
rename from pyforms/gui/Controls/checkbox.ui
rename to pyforms/gui/controls/checkbox.ui
diff --git a/pyforms/gui/Controls/code_editor.ui b/pyforms/gui/controls/code_editor.ui
similarity index 55%
rename from pyforms/gui/Controls/code_editor.ui
rename to pyforms/gui/controls/code_editor.ui
index 95f18bd..bf51fd5 100644
--- a/pyforms/gui/Controls/code_editor.ui
+++ b/pyforms/gui/controls/code_editor.ui
@@ -14,11 +14,23 @@
Form
-
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
0
-
+
+ 2
+
-
@@ -50,19 +62,57 @@
-
-
-
- false
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Maximum
-
-
- 0
- 0
-
+
+
+ 40
+ 10
+
+
+
+
+ -
+
+
+ false
Save
+
+ QToolButton::InstantPopup
+
+
+ Qt::ToolButtonTextBesideIcon
+
+
+ true
+
+
+
+ -
+
+
+ false
+
+
+ Discart
+
+
+ QToolButton::InstantPopup
+
+
+ Qt::ToolButtonTextBesideIcon
+
+
+ true
+
diff --git a/pyforms/gui/controls/control_event_timeline/ControlEventTimeline.py b/pyforms/gui/controls/control_event_timeline/ControlEventTimeline.py
new file mode 100644
index 0000000..b1e7f41
--- /dev/null
+++ b/pyforms/gui/controls/control_event_timeline/ControlEventTimeline.py
@@ -0,0 +1,499 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import csv
+import os
+
+from pyforms.utils.settings_manager import conf
+
+
+from AnyQt.QtWidgets import QWidget, QScrollArea, QColorDialog, QFileDialog, QMessageBox, QPushButton, QLabel, QSlider, QHBoxLayout, QVBoxLayout
+from AnyQt import QtCore, _api
+
+from pyforms.gui.controls.control_event_timeline.TimelineChart import TimelineChart
+from pyforms.gui.controls.ControlBase import ControlBase
+from pyforms.gui.controls.control_event_timeline.TimelineWidget import TimelineWidget
+from pyforms.gui.controls.control_event_timeline.TimelinePopupWindow import TimelinePopupWindow
+from pyforms.gui.controls.control_event_timeline.import_window import ImportWindow
+
+from pyforms.gui.controls.control_event_timeline.graphs_graph2event import Graph2Event
+from pyforms.gui.controls.control_event_timeline.graphs_properties import GraphsProperties
+from pyforms.gui.controls.control_event_timeline.graphs_eventsgenerator import GraphsEventsGenerator
+
+
+
+class ControlEventTimeline(ControlBase, QWidget):
+ """
+ Timeline events editor
+ """
+
+ def __init__(self, label="", default=0, max=100):
+ QWidget.__init__(self)
+ ControlBase.__init__(self, label, default)
+ self._max = 100
+ self._graphs_prop_win = GraphsProperties(self._time, self)
+ self._graphsgenerator_win = GraphsEventsGenerator(self._time)
+ self._graph2event_win = Graph2Event(self._time)
+
+ # Popup menus that only show when clicking on a TIMELINEDELTA object
+ self._deltaLockAction = self.add_popup_menu_option("Lock", self.__lockSelected, key='L')
+ self._deltaColorAction = self.add_popup_menu_option("Pick a color", self.__pickColor)
+ self._deltaRemoveAction = self.add_popup_menu_option("Remove", self.__removeSelected, key='Delete')
+ self._deltaActions = [self._deltaLockAction, self._deltaColorAction, self._deltaRemoveAction]
+ for action in self._deltaActions:
+ action.setVisible(False)
+
+ self.add_popup_menu_option("-")
+
+ self.add_popup_menu_option("Graphs", self.show_graphs_properties, icon=conf.PYFORMS_ICON_EVENTTIMELINE_GRAPH)
+ self.add_popup_menu_option("Apply a function to the graphs", self.__generate_graphs_events,
+ icon=conf.PYFORMS_ICON_EVENTTIMELINE_GRAPH)
+ self.add_popup_menu_option("Convert graph to events", self.__graph2event_event,
+ icon=conf.PYFORMS_ICON_EVENTTIMELINE_GRAPH)
+
+ self.add_popup_menu_option("-")
+
+ # General righ click popup menus
+ self.add_popup_menu_option("Rows", self.__setLinePropertiesEvent,
+ icon=conf.PYFORMS_ICON_EVENTTIMELINE_REMOVE)
+ self.add_popup_menu_option("-")
+
+
+
+ self.add_popup_menu_option("-")
+
+ self.add_popup_menu_option("Auto adjust rows", self.__auto_adjust_tracks_evt,
+ icon=conf.PYFORMS_ICON_EVENTTIMELINE_REFRESH)
+ self.add_popup_menu_option("Add a row", self.__add_track_2_bottom_evt,
+ icon=conf.PYFORMS_ICON_EVENTTIMELINE_ADD)
+
+ self.add_popup_menu_option("-")
+
+ clean_menu = self.add_popup_submenu('Clean')
+
+ self.add_popup_menu_option('The current row', function_action=self.__cleanLine, submenu=clean_menu)
+ self.add_popup_menu_option('-')
+ self.add_popup_menu_option('All graphs', function_action=self.__cleanCharts, submenu=clean_menu)
+ self.add_popup_menu_option('-')
+ self.add_popup_menu_option('Everything', function_action=self.clean, submenu=clean_menu)
+
+ def init_form(self):
+ # Get the current path of the file
+ rootPath = os.path.dirname(__file__)
+
+ vlayout = QVBoxLayout()
+ hlayout = QHBoxLayout()
+
+ if _api.USED_API == _api.QT_API_PYQT5:
+ hlayout.setContentsMargins(0,0,0,0)
+ vlayout.setContentsMargins(0,0,0,0)
+ elif _api.USED_API == _api.QT_API_PYQT4:
+ hlayout.setMargin(0)
+ vlayout.setMargin(0)
+
+
+
+
+ self.setLayout(vlayout)
+
+ # Add scroll area
+ scrollarea = QScrollArea()
+ scrollarea.setMinimumHeight(140)
+ scrollarea.setWidgetResizable(True)
+ scrollarea.keyPressEvent = self.__scrollAreaKeyPressEvent
+ scrollarea.keyReleaseEvent = self.__scrollAreaKeyReleaseEvent
+ vlayout.addWidget(scrollarea)
+ # vlayout.setContentsMargins(5, 5, 5, 5)
+
+ # The timeline widget
+ widget = TimelineWidget(self)
+ widget._scroll = scrollarea
+ # widget.setMinimumHeight(1000)
+ scrollarea.setWidget(widget)
+
+ # TODO Options buttons
+ # btn_1 = QtGui.QPushButton("?")
+ # btn_2 = QtGui.QPushButton("?")
+ # vlayout_options = QtGui.QVBoxLayout()
+ # vlayout_options.addWidget(btn_1)
+ # vlayout_options.addWidget(btn_2)
+ # hlayout.addLayout(vlayout_options)
+ # hlayout.addWidget(btn_1)
+ # hlayout.addWidget(btn_2)
+
+ # Timeline zoom slider
+ slider = QSlider(QtCore.Qt.Horizontal)
+ slider.setFocusPolicy(QtCore.Qt.NoFocus)
+ slider.setMinimum(1)
+ slider.setMaximum(100)
+ slider.setValue(10)
+ slider.setPageStep(1)
+ slider.setTickPosition(QSlider.NoTicks) # TicksBothSides
+ slider.valueChanged.connect(self.__scaleSliderChange)
+
+ slider_label_zoom_in = QLabel()
+ slider_label_zoom_out = QLabel()
+ slider_label_zoom_in.setPixmap(conf.PYFORMS_PIXMAP_EVENTTIMELINE_ZOOM_IN)
+ slider_label_zoom_out.setPixmap(conf.PYFORMS_PIXMAP_EVENTTIMELINE_ZOOM_OUT)
+
+ self._zoomLabel = QLabel("100%")
+ hlayout.addWidget(self._zoomLabel)
+ hlayout.addWidget(slider_label_zoom_out)
+ hlayout.addWidget(slider)
+ hlayout.addWidget(slider_label_zoom_in)
+ # hlayout.setContentsMargins(5, 0, 5, 5)
+ # Import/Export Buttons
+ btn_import = QPushButton("Import")
+
+ btn_import.setIcon(conf.PYFORMS_ICON_EVENTTIMELINE_IMPORT)
+ btn_import.clicked.connect(self.__import)
+ btn_export = QPushButton("Export")
+
+ btn_export.setIcon(conf.PYFORMS_ICON_EVENTTIMELINE_EXPORT)
+ btn_export.clicked.connect(self.__export)
+ # importexport_vlayout = QtGui.QVBoxLayout()
+ # importexport_vlayout.adimdWidget(btn_import)
+ # importexport_vlayout.addWidget(btn_export)
+ # hlayout.addLayout(importexport_vlayout)
+ hlayout.addWidget(btn_import)
+ hlayout.addWidget(btn_export)
+
+ vlayout.addLayout(hlayout)
+
+ self._time = widget
+ self._scrollArea = scrollarea
+
+ ##########################################################################
+ #### HELPERS/PUBLIC FUNCTIONS ############################################
+ ##########################################################################
+
+ def __add__(self, other):
+ if isinstance(other, TimelineChart):
+ self._graphs_prop_win += other
+ self._graphsgenerator_win += other
+ self._graph2event_win += other
+ return self
+
+ def __sub__(self, other):
+ if isinstance(other, int):
+ self._graphs_prop_win -= other
+ self._graphsgenerator_win -= other
+ self._graph2event_win -= other
+ return self
+
+ def rename_graph(self, graph_index, newname):
+ self._graphs_prop_win.rename_graph(graph_index, newname)
+ self._graphsgenerator_win.rename_graph(graph_index, newname)
+ self._graph2event_win.rename_graph(graph_index, newname)
+
+ def add_period(self, value, row=0, color=None):
+ """
+
+ :param value:
+ :param row:
+ :param color:
+ :return:
+ """
+ self._time.add_period(value, row, color)
+ self._time.repaint()
+
+ def add_graph(self, name, data):
+ """
+
+ :param name:
+ :param data:
+ :return:
+ """
+ self._time.add_chart(name, data)
+
+ def import_graph(self, filename, frame_col=0, val_col=1):
+ """
+
+ :param filename:
+ :param frame_col:
+ :param val_col:
+ :return:
+ """
+ self.__import()
+ self._import_window.import_chart(filename, frame_col, val_col)
+
+ def import_graph_file(self, filename, separator=';', ignore_rows=0):
+ """
+
+ :param filename:
+ :param separator:
+ :param ignore_rows:
+ :return:
+ """
+ csvfile = open(filename, 'U')
+ spamreader = csv.reader(csvfile, delimiter=separator)
+ for i in range(ignore_rows): next(spamreader, None)
+ chart = self._time.importchart_csv(spamreader)
+ chart.name = os.path.basename(filename).replace('.csv', '').replace('.CSV', '')
+ csvfile.close()
+
+ def show_graphs_properties(self):
+ """
+
+ """
+ self._graphs_prop_win.show()
+ self._time.repaint()
+
+ def import_csv(self, csvfile):
+ """
+
+ :param csvfile:
+ """
+ # If there are annotation in the timeline, show a warning
+ if len(self._time._tracks) > 0: # dict returns True if not empty
+ message = ["You are about to import new data. ",
+ "If you proceed, current annotations will be erased. ",
+ "Make sure to export current annotations first to save.",
+ "\n",
+ "Are you sure you want to proceed?"]
+ reply = QMessageBox.question(self,
+ "Warning!",
+ "".join(message),
+ QMessageBox.Yes | QMessageBox.No,
+ QMessageBox.No)
+
+ if reply != QMessageBox.Yes:
+ return
+
+ self._time.import_csv(csvfile)
+
+ def export_csv_file(self, filename):
+ with open(filename, 'w') as csvfile:
+ spamwriter = csv.writer(csvfile, dialect='excel')
+ self._time.export_csv(spamwriter)
+
+ def import_csv_file(self, filename):
+ with open(filename, 'r') as csvfile:
+ spamreader = csv.reader(csvfile, dialect='excel')
+ self._time.import_csv(spamreader)
+
+ ##########################################################################
+ #### EVENTS ##############################################################
+ ##########################################################################
+
+ def mouse_moveover_timeline_event(self, event):
+ self._graphs_prop_win.mouse_moveover_timeline_event(event)
+
+
+ @property
+ def pointer_changed_event(self):
+ return self._time._pointer.moveEvent
+
+ @pointer_changed_event.setter
+ def pointer_changed_event(self, value):
+ self._time._pointer.moveEvent = value
+
+ def __auto_adjust_tracks_evt(self):
+ for i in range(len(self._time.tracks) - 1, -1, -1):
+ track = self._time.tracks[i]
+ if len(track) == 0:
+ self._time.remove_track(track)
+ else:
+ break
+
+ def __add_track_2_bottom_evt(self):
+ self._time.add_track()
+
+ def __remove_track_from_bottom_evt(self):
+ if len(self._time.tracks) > 0:
+ track = self._time.tracks[-1]
+ if len(track) == 0:
+ self._time.remove_track(track)
+
+ def __generate_graphs_events(self):
+ self._graphsgenerator_win.show()
+
+ def __graph2event_event(self):
+ self._graph2event_win.show()
+
+ ##########################################################################
+ #### PROPERTIES ##########################################################
+ ##########################################################################
+
+ @property
+ def value(self):
+ return self._time.position
+
+ @value.setter
+ def value(self, value):
+ ControlBase.value.fset(self, value)
+ self._time.position = value
+
+ @property
+ def max(self):
+ return self._time.minimumWidth()
+
+ @max.setter
+ def max(self, value):
+ self._max = value
+ self._time.setMinimumWidth(value)
+ self.repaint()
+
+ @property
+ def form(self):
+ return self
+
+ @property
+ def rows(self):
+ return self._time.tracks
+
+ @property
+ def graphs(self): return self._time.graphs
+
+ ##########################################################################
+ #### PRIVATE FUNCTIONS ###################################################
+ ##########################################################################
+
+ def about_to_show_contextmenu_event(self):
+ for action in self._deltaActions:
+ action.setVisible(
+ True) if self._time._selected is not None else action.setVisible(False)
+
+
+
+ def __setLinePropertiesEvent(self):
+ """
+ This controls makes possible the edition of a track in the
+ timeline, based on the position of the mouse.
+
+ Updates:
+ - Track label
+ - Track default color
+ """
+ current_track = self._time.current_mouseover_track
+ parent = self._time
+
+ # Tracks info dict and index
+ i = current_track
+
+ # Save current default color to override with selected track color
+ timeline_default_color = parent.color
+ try:
+ parent.color = self._time._tracks[current_track].color
+ except Exception as e:
+ error_message = ("You tried to edit an empty track.",
+ "\n",
+ "Initialize it by creating an event first.")
+ QMessageBox.warning(
+ parent, "Attention!", "".join(error_message))
+ return e
+
+ # Create dialog
+ dialog = TimelinePopupWindow(parent, i)
+ dialog.setModal(True) # to disable main application window
+
+ # If dialog is accepted, update dict info
+ if dialog._ui.exec_() == dialog.Accepted:
+ # Update label
+ if dialog.behavior is not None:
+ self._time._tracks[i].title = dialog.behavior
+
+ # Update color
+ if self._time._tracks[i].color != dialog.color:
+ for delta in self._time._tracks[i].periods:
+ delta.color = dialog.color
+ self._time._tracks[i].color = dialog.color
+ self._time.repaint()
+ else:
+ pass
+
+ # Restore timeline default color
+ parent.color = timeline_default_color
+
+ def __lockSelected(self):
+ self._time.lockSelected()
+
+ def __removeSelected(self):
+ self._time.removeSelected()
+
+ def __import(self):
+ """Import annotations from a file."""
+ if not hasattr(self, '_import_window'): self._import_window = ImportWindow(self)
+ self._import_window.show()
+
+ def __export(self):
+ """Export annotations to a file."""
+
+ filename, ffilter = QFileDialog.getSaveFileName(parent=self,
+ caption="Export annotations file",
+ directory="untitled.csv",
+ filter="CSV Files (*.csv);;CSV Matrix Files (*.csv)",
+ options=QFileDialog.DontUseNativeDialog)
+
+ filename = str(filename)
+ ffilter = str(ffilter)
+ if filename != "":
+ with open(filename, 'w') as csvfile:
+ spamwriter = csv.writer(csvfile, dialect='excel')
+ if ffilter == 'CSV Files (*.csv)':
+ self._time.export_csv(spamwriter)
+ elif ffilter == 'CSV Matrix Files (*.csv)':
+ self._time.export_2_csv_matrix(spamwriter)
+
+ def __export_2_csv_matrix(self):
+ QMessageBox.warning(
+ self, "Important!", 'Please note that this file cannot be imported after.')
+
+ filename, _ = QFileDialog.getSaveFileName(parent=self,
+ caption="Export matrix file",
+ directory="untitled.csv",
+ filter="CSV Files (*.csv)",
+ options=QFileDialog.DontUseNativeDialog)
+ if filename != "":
+ with open(filename, 'w') as csvfile:
+ spamwriter = csv.writer(csvfile, dialect='excel')
+ self._time.export_2_csv_matrix(spamwriter)
+
+ def __cleanLine(self):
+ reply = QMessageBox.question(self, 'Confirm',
+ "Are you sure you want to clean all the events on this track?",
+ QMessageBox.Yes |
+ QMessageBox.No, QMessageBox.No)
+ if reply == QMessageBox.Yes:
+ self._time.cleanLine(self._time.current_mouseover_track)
+
+ def __cleanCharts(self):
+ reply = QMessageBox.question(self, 'Confirm',
+ "Are you sure you want to clean all the charts?", QMessageBox.Yes |
+ QMessageBox.No, QMessageBox.No)
+ if reply == QMessageBox.Yes:
+ self._time.cleanCharts()
+
+ def clean(self):
+ reply = QMessageBox.question(self, 'Confirm',
+ "Are you sure you want to clean everything?", QMessageBox.Yes |
+ QMessageBox.No, QMessageBox.No)
+ if reply == QMessageBox.Yes:
+ self._time.clean()
+
+ def __pickColor(self):
+ self._time.color = QColorDialog.getColor(self._time.color)
+ if self._time._selected != None:
+ self._time._selected.color = self._time.color
+ self._time.repaint()
+
+ def __scaleSliderChange(self, value):
+ scale = 0.1 * value
+ self._time.setMinimumWidth(scale * self._max)
+ self._time.scale = scale
+ self._zoomLabel.setText(str(value * 10).zfill(3) + "%")
+
+ def __scrollAreaKeyReleaseEvent(self, event):
+ modifiers = int(event.modifiers())
+ self._time.keyReleaseEvent(event)
+ if modifiers is not QtCore.Qt.ControlModifier and \
+ modifiers is not int(QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier) and \
+ modifiers is not QtCore.Qt.ShiftModifier:
+ QScrollArea.keyReleaseEvent(self._scrollArea, event)
+
+ def __scrollAreaKeyPressEvent(self, event):
+ modifiers = int(event.modifiers())
+ if modifiers is not QtCore.Qt.ControlModifier and \
+ modifiers is not int(QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier) and \
+ modifiers is not QtCore.Qt.ShiftModifier:
+ QScrollArea.keyPressEvent(self._scrollArea, event)
diff --git a/pyforms/gui/Controls/ControlEventTimeline/TimelineChart.py b/pyforms/gui/controls/control_event_timeline/TimelineChart.py
similarity index 89%
rename from pyforms/gui/Controls/ControlEventTimeline/TimelineChart.py
rename to pyforms/gui/controls/control_event_timeline/TimelineChart.py
index 319cb19..a5cf8cf 100644
--- a/pyforms/gui/Controls/ControlEventTimeline/TimelineChart.py
+++ b/pyforms/gui/controls/control_event_timeline/TimelineChart.py
@@ -1,13 +1,6 @@
# !/usr/bin/python
# -*- coding: utf-8 -*-
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtGui import QColor
-
-else:
- from PyQt4.QtGui import QColor
+from AnyQt.QtGui import QColor
class TimelineChart(object):
@@ -124,21 +117,21 @@ def draw(self, painter, left, right, top, bottom):
painter.setPen(self._color)
painter.setOpacity(0.7)
- fov_height = (bottom - top) * self._zoom
- start = self._widget.x2frame(left)
- end = self._widget.x2frame(right)
- end = len(self) if end > len(self) else end
- diff_max_min = (self._graph_max - self._graph_min)
+ fov_height = (bottom - top) * self.zoom #calculate the height visible
+ start = self._widget.x2frame(left) #calculate the start frame to draw
+ end = self._widget.x2frame(right) #calculate the end frame to draw
+ end = len(self) if end > len(self) else end #check if the end frame his higher than the available data
+ diff_max_min = (self._graph_max - self._graph_min) #calculate the difference bettween the lower and higher value
top = (-self._graph_min if self._graph_min > 0 else abs(self._graph_min)) * self._zoom
if diff_max_min <= 0: diff_max_min = 1
- last_coordenate = None
+ last_coordenate = None
last_real_x_coord = None
for i, y in enumerate(self._data[start:end]):
- if y:
+ if y is not None:
x = i + start
if y == None: continue
y = self._top + ((top + y) * fov_height) // diff_max_min
diff --git a/pyforms/gui/Controls/ControlEventTimeline/TimelineDelta.py b/pyforms/gui/controls/control_event_timeline/TimelineDelta.py
old mode 100755
new mode 100644
similarity index 91%
rename from pyforms/gui/Controls/ControlEventTimeline/TimelineDelta.py
rename to pyforms/gui/controls/control_event_timeline/TimelineDelta.py
index 1ac8f5d..202f2f0
--- a/pyforms/gui/Controls/ControlEventTimeline/TimelineDelta.py
+++ b/pyforms/gui/controls/control_event_timeline/TimelineDelta.py
@@ -1,19 +1,13 @@
# !/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
+from AnyQt.QtWidgets import QInputDialog
+from AnyQt.QtGui import QColor
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QInputDialog
- from PyQt5.QtGui import QColor
-
-else:
- from PyQt4.QtGui import QColor, QInputDialog
-
-from pyforms.gui.Controls.ControlEventTimeline.Track import Track
+from pyforms.gui.controls.control_event_timeline.Track import Track
from pyforms import BaseWidget
-from pyforms.Controls import ControlText, ControlNumber, ControlButton
+from pyforms.controls import ControlText, ControlNumber, ControlButton
class DeltaEditWindow(BaseWidget):
@@ -21,14 +15,11 @@ class DeltaEditWindow(BaseWidget):
def __init__(self, parent_win, label, begin, end):
BaseWidget.__init__(self, 'Edit frame', parent_win=parent_win)
- if conf.PYFORMS_USE_QT5:
- self.layout().setContentsMargins(5,5,5,5)
- else:
- self.layout().setMargin(5)
+ self.set_margin(5)
- self._label = ControlText('Label', label)
- self._begin = ControlNumber('Begin', begin, 0, 100000000000000)
- self._end = ControlNumber('End', end, 0, 100000000000000)
+ self._label = ControlText('Label', default=label)
+ self._begin = ControlNumber('Begin', default=begin, minimum=0, maximum=100000000000000)
+ self._end = ControlNumber('End', default=end, minimum=0, maximum=100000000000000)
self._applybtn = ControlButton('Apply')
@@ -42,12 +33,16 @@ def __init__(self, parent_win, label, begin, end):
self._end.changed_event = self.__end_changed_event
def __begin_changed_event(self):
- if self._begin.value>=self._end.value:
+ if not hasattr(self, '_updating') and self._begin.value>=self._end.value:
+ self._updating = True
self._begin.value = self._end.value-1
+ del self._updating
def __end_changed_event(self):
- if self._end.value<=self._begin.value:
+ if not hasattr(self, '_updating') and self._end.value<=self._begin.value:
+ self._updating = True
self._end.value = self._begin.value+1
+ del self._updating
@property
@@ -109,7 +104,7 @@ def checkNumberOfTracks(self):
"""
if self.track >= (self._parent.numberoftracks - 1):
for i in range(self._parent.numberoftracks - 1, self.track + 1):
- self._parent.addTrack()
+ self._parent.add_track()
def collide(self, x, y):
"""
@@ -325,7 +320,7 @@ def track(self, value):
# Verify if the new track exists. In case not create it
self._top = Track.whichTop(value)
- if self.track >= len(self._parent._tracks): self._parent.addTrack()
+ if self.track >= len(self._parent._tracks): self._parent.add_track()
# if do not exists in the track add it
if self not in self._parent._tracks[self.track].periods: self._parent._tracks[self.track].periods.append(self)
diff --git a/pyforms/gui/Controls/ControlEventTimeline/TimelinePointer.py b/pyforms/gui/controls/control_event_timeline/TimelinePointer.py
old mode 100755
new mode 100644
similarity index 92%
rename from pyforms/gui/Controls/ControlEventTimeline/TimelinePointer.py
rename to pyforms/gui/controls/control_event_timeline/TimelinePointer.py
index 22d7c9d..ab9f6c4
--- a/pyforms/gui/Controls/ControlEventTimeline/TimelinePointer.py
+++ b/pyforms/gui/controls/control_event_timeline/TimelinePointer.py
@@ -1,15 +1,8 @@
# !/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtGui import QColor
- from PyQt5 import QtCore
-
-else:
- from PyQt4.QtGui import QColor
- from PyQt4 import QtCore
+from AnyQt.QtGui import QColor
+from AnyQt import QtCore
class TimelinePointer(object):
diff --git a/pyforms/gui/Controls/ControlEventTimeline/TimelinePopupWindow.py b/pyforms/gui/controls/control_event_timeline/TimelinePopupWindow.py
similarity index 93%
rename from pyforms/gui/Controls/ControlEventTimeline/TimelinePopupWindow.py
rename to pyforms/gui/controls/control_event_timeline/TimelinePopupWindow.py
index 863d453..42d8587 100644
--- a/pyforms/gui/Controls/ControlEventTimeline/TimelinePopupWindow.py
+++ b/pyforms/gui/controls/control_event_timeline/TimelinePopupWindow.py
@@ -1,17 +1,13 @@
# !/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QDialog, QInputDialog, QColorDialog
- from PyQt5.QtGui import QColor, QPixmap, QFont, QPainter
- from PyQt5 import uic
- from PyQt5 import QtCore
-else:
- from PyQt4.QtGui import QDialog, QInputDialog, QColor, QPixmap, QColorDialog, QPainter, QFont
- from PyQt4 import uic
- from PyQt4 import QtCore
+from pyforms.utils.settings_manager import conf
+
+from AnyQt.QtWidgets import QDialog, QInputDialog, QColorDialog
+from AnyQt.QtGui import QColor, QPixmap, QFont, QPainter
+from AnyQt import uic
+from AnyQt import QtCore
+
import pyforms.utils.tools as tools
diff --git a/pyforms/gui/Controls/ControlEventTimeline/TimelinePopupWindow.ui b/pyforms/gui/controls/control_event_timeline/TimelinePopupWindow.ui
similarity index 100%
rename from pyforms/gui/Controls/ControlEventTimeline/TimelinePopupWindow.ui
rename to pyforms/gui/controls/control_event_timeline/TimelinePopupWindow.ui
diff --git a/pyforms/gui/Controls/ControlEventTimeline/TimelineWidget.py b/pyforms/gui/controls/control_event_timeline/TimelineWidget.py
old mode 100755
new mode 100644
similarity index 94%
rename from pyforms/gui/Controls/ControlEventTimeline/TimelineWidget.py
rename to pyforms/gui/controls/control_event_timeline/TimelineWidget.py
index 5e98ad0..157d61a
--- a/pyforms/gui/Controls/ControlEventTimeline/TimelineWidget.py
+++ b/pyforms/gui/controls/control_event_timeline/TimelineWidget.py
@@ -1,21 +1,15 @@
# !/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QWidget, QMessageBox
- from PyQt5.QtGui import QColor, QPainter, QFont, QCursor
- from PyQt5 import QtCore
+from AnyQt.QtWidgets import QWidget, QMessageBox
+from AnyQt.QtGui import QColor, QPainter, QFont, QCursor
+from AnyQt import QtCore
-else:
- from PyQt4.QtGui import QWidget, QColor, QMessageBox, QPainter, QFont, QCursor
- from PyQt4 import QtCore
-
-from pyforms.gui.Controls.ControlEventTimeline.Track import Track
-from pyforms.gui.Controls.ControlEventTimeline.TimelinePointer import TimelinePointer
-from pyforms.gui.Controls.ControlEventTimeline.TimelineDelta import TimelineDelta
-from pyforms.gui.Controls.ControlEventTimeline.TimelineChart import TimelineChart
+from pyforms.gui.controls.control_event_timeline.Track import Track
+from pyforms.gui.controls.control_event_timeline.TimelinePointer import TimelinePointer
+from pyforms.gui.controls.control_event_timeline.TimelineDelta import TimelineDelta
+from pyforms.gui.controls.control_event_timeline.TimelineChart import TimelineChart
class TimelineWidget(QWidget):
@@ -194,10 +188,10 @@ def import_csv(self, csvfileobject):
for row in csvfileobject:
if len(row) == 0: continue
if row[0] == "T":
- track = self.addTrack()
+ track = self.add_track()
track.properties = row
elif row[0] == "P":
- period = self.addPeriod([0, 1, '-'])
+ period = self.add_period([0, 1, '-'])
period.properties = row
def export_csv(self, csvfileobject):
@@ -275,16 +269,16 @@ def cleanLine(self, track_index=None):
QMessageBox.about(self, "Error", "You must select a timebar first")
return
- def addTrack(self):
+ def add_track(self):
t = Track(parent=self)
self._tracks.append(t)
self.setMinimumHeight(Track.whichTop(len(self._tracks)))
return t
- def addPeriod(self, value, track=0, color=None):
+ def add_period(self, value, row=0, color=None):
"""Adds an annotated interval."""
begin, end, title = value
- period = TimelineDelta(begin, end, title=title, parent=self, top=Track.whichTop(track))
+ period = TimelineDelta(begin, end, title=title, parent=self, top=Track.whichTop(row))
self._tracks[period.track].periods.append(period)
return period
@@ -429,7 +423,7 @@ def keyReleaseEvent(self, event):
comment = ""
if end > start:
- self.addPeriod((start, end, comment), self._selected_track)
+ self.add_period((start, end, comment), self._selected_track)
self.repaint()
self._creating_event = False
else:
@@ -568,7 +562,7 @@ def numberoftracks(self, value):
# self._n_tracks = value
if value < len(self._tracks):
for i in range(value, self._tracks + 1):
- self.addTrack()
+ self.add_track()
y = value * 34 + 20
if y + 40 > self.height():
self.setMinimumHeight(y + 40)
diff --git a/pyforms/gui/Controls/ControlEventTimeline/Track.py b/pyforms/gui/controls/control_event_timeline/Track.py
similarity index 92%
rename from pyforms/gui/Controls/ControlEventTimeline/Track.py
rename to pyforms/gui/controls/control_event_timeline/Track.py
index 16b188e..c44e187 100644
--- a/pyforms/gui/Controls/ControlEventTimeline/Track.py
+++ b/pyforms/gui/controls/control_event_timeline/Track.py
@@ -1,16 +1,8 @@
# !/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtGui import QColor
- from PyQt5 import QtCore
-
-else:
- from PyQt4.QtGui import QColor
- from PyQt4 import QtCore
-
+from AnyQt.QtGui import QColor
+from AnyQt import QtCore
class Track(object):
"""
diff --git a/pyforms/gui/Controls/ControlEventTimeline/__init__.py b/pyforms/gui/controls/control_event_timeline/__init__.py
similarity index 89%
rename from pyforms/gui/Controls/ControlEventTimeline/__init__.py
rename to pyforms/gui/controls/control_event_timeline/__init__.py
index 5a0c3bb..956e9c5 100644
--- a/pyforms/gui/Controls/ControlEventTimeline/__init__.py
+++ b/pyforms/gui/controls/control_event_timeline/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-""" pyforms.gui.Controls.ControlEventTimeline.__init__
+""" pyforms.gui.controls.ControlEventTimeline.__init__
"""
diff --git a/pyforms/gui/controls/control_event_timeline/graphs_eventsgenerator.py b/pyforms/gui/controls/control_event_timeline/graphs_eventsgenerator.py
new file mode 100644
index 0000000..5aac17e
--- /dev/null
+++ b/pyforms/gui/controls/control_event_timeline/graphs_eventsgenerator.py
@@ -0,0 +1,131 @@
+import csv, sys
+from pyforms import BaseWidget
+from pyforms.controls import ControlProgress
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlList
+from pyforms.controls import ControlNumber
+from pyforms.controls import ControlSlider
+from pyforms.controls import ControlTextArea
+from pyforms.controls import ControlText
+from pyforms.controls import ControlNumber
+from pyforms.controls import ControlLabel
+import traceback
+import time
+import datetime
+
+from pyforms.utils.settings_manager import conf
+from AnyQt.QtWidgets import QMessageBox
+
+
+
+class GraphsEventsGenerator(BaseWidget):
+
+ def __init__(self, timeline=None):
+ super(GraphsEventsGenerator, self).__init__('Apply a function to the graph values', parent_win=timeline)
+ self.setContentsMargins(10, 10, 10, 10)
+ self._timeline = timeline
+
+
+ # Definition of the forms fields
+ self._graphs_list = ControlList('Graphs list (try double click)', readonly=False, select_entire_row=True)
+ self._equation = ControlTextArea('Equation')
+ self._graphname = ControlText('Graph name')
+ self._genevts_btn = ControlButton('Generate graph')
+
+
+ self._formset = [
+ (
+ ['_graphs_list'],
+ '||',
+ [
+ '_graphname',
+ '_equation',
+ '_genevts_btn',
+ ]
+ ),
+ ]
+
+ self._graphs_list.cell_double_clicked_event = self.__cell_double_clicked_evt
+ self._graphs_list.readonly = True
+ self._graphs_list.select_entire_row = True
+ self._genevts_btn.value = self.__generage_events_evt
+
+
+
+ def __add__(self, other):
+ self._graphs_list += [other.name]
+ return self
+
+ def __sub__(self, other):
+ self._graphs_list -= other
+ return self
+
+ def rename_graph(self, graph_index, newname):
+ self._graphs_list.set_value(graph_index, 0, newname)
+
+ @property
+ def graphs(self):
+ return self._timeline._charts
+
+ def show(self):
+ super(GraphsEventsGenerator, self).show()
+
+ if len(self._graphname.value.strip())==0:
+ self._graphname.value = "generated-graph-{0}".format( len(self._timeline.graphs))
+
+
+
+ def __cell_double_clicked_evt(self, row, column):
+ if len(self._equation.value.strip())==0:
+ self._equation.value += '[{0}]'.format( self._graphs_list.value[row][column] )
+ else:
+ self._equation.value += ' and [{0}]'.format( self._graphs_list.value[row][column] )
+
+
+ def __generage_events_evt(self):
+ if len(self._graphname.value.strip())==0:
+ QMessageBox.warning(
+ self, "Attention!", 'The graph name cannot be empty')
+ return
+
+ if len(self._equation.value.strip())==0:
+ QMessageBox.warning(
+ self, "Attention!", 'The equation cannot be empty')
+ return
+
+ max_frame = 0
+ equation = self._equation.value
+ for i, values in enumerate(self._graphs_list.value):
+ graphname = '[{0}]'.format(values[0])
+
+ if graphname in equation: max_frame = max(max_frame, len(self.graphs[i]))
+
+ equation = equation.replace(graphname, 'graphs[{0}][i]'.format(i) )
+
+ graphs = self.graphs
+ data = []
+ try:
+ for i in range(max_frame):
+
+ try:
+ value = eval(equation)
+ except:
+ value = None
+
+ data.append( (i, value) )
+ self._timeline.add_chart(self._graphname.value, data)
+
+ self._graphname.value = "generated-graph-{0}".format( len(self._timeline.graphs))
+ except Exception as e:
+ traceback.print_exc()
+ QMessageBox.warning( self, "Error!", str(e) )
+
+
+##################################################################################################################
+##################################################################################################################
+##################################################################################################################
+
+# Execute the application
+if __name__ == "__main__":
+ import pyforms
+ pyforms.start_app(GraphsEventsGenerator, geometry=(0, 0, 600, 400))
diff --git a/pyforms/gui/Controls/ControlEventTimeline/graphs_graph2event.py b/pyforms/gui/controls/control_event_timeline/graphs_graph2event.py
similarity index 84%
rename from pyforms/gui/Controls/ControlEventTimeline/graphs_graph2event.py
rename to pyforms/gui/controls/control_event_timeline/graphs_graph2event.py
index afc2793..d5f219b 100644
--- a/pyforms/gui/Controls/ControlEventTimeline/graphs_graph2event.py
+++ b/pyforms/gui/controls/control_event_timeline/graphs_graph2event.py
@@ -1,26 +1,14 @@
-import csv, sys
-from pyforms import BaseWidget
-from pyforms.Controls import ControlProgress
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlList
-from pyforms.Controls import ControlNumber
-from pyforms.Controls import ControlSlider
-from pyforms.Controls import ControlTextArea
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlNumber
-from pyforms.Controls import ControlLabel
-
-import time
-import datetime
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QMessageBox
-else:
- from PyQt4.QtGui import QMessageBox
-
-
+from pyforms import BaseWidget
+from pyforms.controls import ControlProgress
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlList
+from pyforms.controls import ControlNumber
+from pyforms.controls import ControlSlider
+from pyforms.controls import ControlTextArea
+from pyforms.controls import ControlText
+from pyforms.controls import ControlNumber
+from pyforms.controls import ControlLabel
+from AnyQt.QtWidgets import QMessageBox
class Graph2Event(BaseWidget):
diff --git a/pyforms/gui/Controls/ControlEventTimeline/graphs_properties.py b/pyforms/gui/controls/control_event_timeline/graphs_properties.py
similarity index 81%
rename from pyforms/gui/Controls/ControlEventTimeline/graphs_properties.py
rename to pyforms/gui/controls/control_event_timeline/graphs_properties.py
index 0fe89e8..ba8de0a 100644
--- a/pyforms/gui/Controls/ControlEventTimeline/graphs_properties.py
+++ b/pyforms/gui/controls/control_event_timeline/graphs_properties.py
@@ -1,12 +1,16 @@
import csv, time, datetime, decimal, logging, sys, numpy as np
from pyforms import BaseWidget
-from pyforms.Controls import ControlProgress
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlList
-from pyforms.Controls import ControlNumber
-from pyforms.Controls import ControlSlider
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlLabel
+from pyforms.controls import ControlProgress
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlList
+from pyforms.controls import ControlNumber
+from pyforms.controls import ControlSlider
+from pyforms.controls import ControlText
+from pyforms.controls import ControlLabel
+from pyforms.utils.settings_manager import conf
+
+if conf.PYFORMS_MODE=='GUI':
+ from AnyQt.QtWidgets import QColorDialog
logger = logging.getLogger(__name__)
@@ -24,12 +28,13 @@ def __init__(self, timelineWidget=None, parent_win=None):
# Definition of the forms fields
self._graphs_list = ControlList('Graphs list')
self._name = ControlText('Name')
- self._min_value = ControlNumber('Min', 0, -sys.float_info.max, sys.float_info.max)
- self._max_value = ControlNumber('Max', 0, -sys.float_info.max, sys.float_info.max)
- self._values_zoom = ControlSlider('Amplitude', 100, 60, 400)
- self._values_top = ControlNumber('Bottom', 0, -1000, 1000)
+ self._min_value = ControlNumber('Min', default=0, minimum=-sys.float_info.max, maximum=sys.float_info.max)
+ self._max_value = ControlNumber('Max', default=0, minimum=-sys.float_info.max, maximum=sys.float_info.max)
+ self._values_zoom = ControlSlider('Amplitude', default=100, minimum=60, maximum=400)
+ self._values_top = ControlNumber('Bottom', default=0, minimum=-1000, maximum=1000)
self._remove_graph_btn = ControlButton('Remove graph')
self._value = ControlLabel()
+ self._pickcolor = ControlButton('Pick color', default=self.__pickcolor_evt)
self._graphs_list.readonly = True
@@ -41,7 +46,7 @@ def __init__(self, timelineWidget=None, parent_win=None):
' ',
'_name',
('_min_value', '_max_value', ' '),
- ('_values_top', ' '),
+ ('_values_top', '_pickcolor'),
'_values_zoom',
'info:Choose one graph and move the mouse over \nthe timeline to visualize the coordenates.',
'_value'
@@ -66,6 +71,7 @@ def __init__(self, timelineWidget=None, parent_win=None):
self._values_zoom.enabled = False
self._values_top.enabled = False
self._remove_graph_btn.enabled = False
+ self._pickcolor.enabled = False
self._remove_graph_btn.value = self.__remove_chart
@@ -97,6 +103,13 @@ def show(self):
super(GraphsProperties, self).show()
self._loaded = False
+ def __pickcolor_evt(self):
+ color = QColorDialog.getColor(
+ self._current_selected_graph._color,
+ self, 'Pick a color for the graph')
+ self._current_selected_graph._color = color
+ self._timeline.repaint()
+
def __remove_chart(self):
index = self._graphs_list.selected_row_index
@@ -110,6 +123,7 @@ def __remove_chart(self):
self._values_zoom.enabled = False
self._values_top.enabled = False
self._remove_graph_btn.enabled = False
+ self._pickcolor.enabled = False
self._timeline.repaint()
self._mainwindow -= index
@@ -143,6 +157,7 @@ def __graphs_list_selection_changed(self):
self._values_zoom.enabled = True
self._values_top.enabled = True
self._remove_graph_btn.enabled = True
+ self._pickcolor.enabled = True
self._current_selected_graph = graph
del self._updating_properties
diff --git a/pyforms/gui/controls/control_event_timeline/import_window.py b/pyforms/gui/controls/control_event_timeline/import_window.py
new file mode 100644
index 0000000..accc474
--- /dev/null
+++ b/pyforms/gui/controls/control_event_timeline/import_window.py
@@ -0,0 +1,275 @@
+import csv
+from pyforms import BaseWidget
+from pyforms.controls import ControlProgress
+from pyforms.controls import ControlCombo
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlEmptyWidget
+from pyforms.controls import ControlFile
+from pyforms.controls import ControlNumber
+
+
+import time
+import datetime
+import dateutil.parser
+
+import logging
+
+logger=logging.getLogger(__file__)
+
+class BonsaiImportFileDlg(BaseWidget):
+
+ def __init__(self, timeline=None):
+ super(BonsaiImportFileDlg, self).__init__('Import file')
+
+ self._file = ControlFile('File to import')
+ self._fps = ControlNumber('Video FPS', default=30)
+ self._startframe = ControlNumber('Initial frame', visible=False, maximum=100000)
+
+
+ self._formset = [('_startframe','_fps', '_file')]
+
+ #self._file.value = '/home/ricardo/Desktop/rat1e2.csv'
+
+
+class ImportWindow(BaseWidget):
+
+ def __init__(self, timeline=None):
+ super(ImportWindow, self).__init__('Import file', parent_win=timeline)
+ self.setContentsMargins(10, 10, 10, 10)
+ self._timeline = timeline
+
+ # Definition of the forms fields
+ self._filetype = ControlCombo('Please select the type of file you would like to import:')
+ self._importButton = ControlButton('Import')
+ self._panel = ControlEmptyWidget('Panel')
+ self._file = ControlFile('File to import')
+
+ self._panel.value = self._file
+ self._filetype.add_item('Events file', 0)
+ self._filetype.add_item('Graph file', 1)
+ self._filetype.add_item('Bonsai events file', 2)
+ self._filetype.add_item('Bonsai events file (old format)', 3)
+
+ self._formset = [
+ ('_filetype', ' '),
+ '_panel',
+ (' ', '_importButton'),
+ ' '
+ ]
+
+ self._filetype.changed_event = self.__fileTypeChanged
+ self._importButton.value = self.__importData
+
+ from pyforms.gui.dialogs.csv_parser import CsvParserDialog
+ self._graphCsvParserDlg = CsvParserDialog()
+ self._graphCsvParserDlg.xField.label = "Value column"
+ self._graphCsvParserDlg.yField.hide()
+ self._graphCsvParserDlg.zField.hide()
+ self._graphCsvParserDlg.loadButton.hide()
+
+ self._bonsai_import_dlg = BonsaiImportFileDlg()
+
+ def __fileTypeChanged(self):
+ if self._filetype.value == 0:
+ self._panel.value = self._file
+
+ elif self._filetype.value == 1:
+ self._panel.value = self._graphCsvParserDlg
+
+ elif self._filetype.value == 2:
+ self._panel.value = self._bonsai_import_dlg
+ self._bonsai_import_dlg._startframe.hide()
+
+ elif self._filetype.value == 3:
+ self._panel.value = self._bonsai_import_dlg
+ self._bonsai_import_dlg._startframe.show()
+
+
+
+
+
+
+
+
+
+
+
+
+
+ def __importData(self):
+ if self._filetype.value == 0:
+ separator = ','
+ with open(self._file.value, 'rU') as csvfile:
+ line = csvfile.readline()
+ if ";" in line:
+ separator = ';'
+ with open(self._file.value, 'rU') as csvfile:
+ csvfile = csv.reader(csvfile, delimiter=separator)
+ self._timeline._time.import_csv(csvfile)
+
+ elif self._filetype.value == 1:
+ self._timeline._time.importchart_csv(self._graphCsvParserDlg)
+ self._timeline.show_graphs_properties()
+
+ elif self._filetype.value == 2:
+ self.__import_bonsai_events()
+ elif self._filetype.value == 3:
+ self.__import_bonsai_events_oldformat()
+
+ self._timeline.repaint()
+ self._timeline._time.repaint()
+ self.close() # pylint: disable=no-member
+
+
+ def import_chart(self, filename, frame_col=0, val_col=1):
+ self._filetype.value = 1
+ self._graphCsvParserDlg.filename = filename
+ self._graphCsvParserDlg.frameColumn = frame_col
+ self._graphCsvParserDlg.xColumn = val_col
+
+
+
+ def __import_bonsai_events(self):
+
+ with open(self._bonsai_import_dlg._file.value, 'rU') as csvfile:
+ values = []
+ pointEventValues = []
+ csvfile = csv.reader(csvfile, delimiter=' ')
+ for row in csvfile: # strip Start/End word from all events names which are not PointEven
+
+ try:
+ timestr = row[1].rstrip('0')
+ cvttime = datetime.datetime.strptime(timestr, "%H:%M:%S.%f")
+ except:
+ timestr = row[1]
+ try:
+ print(timestr)
+ cvttime = datetime.datetime.strptime(timestr, "%H:%M:%S")
+ except:
+ timestr = timestr.replace('T', ' ')
+ print(timestr)
+ cvttime = dateutil.parser.parse(timestr)
+
+ seconds = (cvttime - datetime.datetime(1900, 1, 1)).total_seconds()
+ frame = int(round(self._bonsai_import_dlg._fps.value * seconds))
+
+ if row[2] == "PointEvent":
+ eventtype = row[0]
+ pointEventValues.append([eventtype, frame, row[2]])
+ else:
+ if row[0].startswith('Start'):
+ eventtype = row[0][len('Start'):] # strip Start word from the beginning
+ else:
+ eventtype = row[0][len('End'):] # strip End word from the beginning
+ values.append([eventtype, frame, row[2]])
+
+ values = sorted(values, key=lambda x: (x[0].capitalize(), x[1]))
+ pointEventValues = sorted(pointEventValues, key=lambda x: (x[0].capitalize(), x[1]))
+ ntracks = len(set([x[0] for x in values])) + 1
+
+ # collapse
+ events = []
+ eventsTypes = {} # Events names
+ currentTrack = 0
+ for index in range(0, len(pointEventValues)):
+ pointEventValue = pointEventValues[index]
+ eventsTypes[pointEventValue[0]] = currentTrack
+ self._timeline.add_period([pointEventValue[1], pointEventValue[1] + 50, pointEventValue[0]], row=currentTrack)
+
+ currentTrack = 1
+
+ for index in range(0, len(values), 2):
+ row0 = values[index]
+ row1 = values[index + 1]
+
+ if row0[0] not in eventsTypes:
+ eventsTypes[row0[0]] = currentTrack
+ track = currentTrack
+ currentTrack += 1
+ else:
+ track = eventsTypes[row0[0]]
+
+ self._timeline.add_period([row0[1], row1[1], row0[0]], row=track)
+
+
+
+
+ def __import_bonsai_events_oldformat(self):
+
+ try:
+ with open(self._bonsai_import_dlg._file.value, 'rU') as csvfile:
+ windows_events = []
+ points_events = []
+ first_date = None
+
+ initial_frame = int(self._bonsai_import_dlg._startframe.value)
+
+ open_windows = {}
+ for row in csvfile:
+ row = row[:-1] #remove the newline character
+
+ if row.endswith('WindowClosing'):
+ split = row.rfind(' ')
+ #eventtype = row[-split:]
+ eventtype = 'end'
+ timestr = row[split-33:split]
+ eventname = row[3:split-33].strip()
+ elif row.endswith('PointEvent'):
+ split = row.rfind(' ')
+ eventtype = row[split+1:]
+ timestr = row[split-33:split]
+ eventname = row[:split-33]
+ else:
+ eventtype = 'start'
+ timestr = row[-33:]
+ eventname = row[5:-33].strip()
+
+ cvttime = dateutil.parser.parse(timestr.replace('T', ' '))
+ cvttime = cvttime.replace(tzinfo=None)
+ if first_date is None: first_date = cvttime
+
+ seconds = (cvttime - first_date).total_seconds()
+ frame = int(round(self._bonsai_import_dlg._fps.value * seconds)) + initial_frame
+
+ if eventtype=='PointEvent':
+ points_events.append([eventtype, frame, eventname])
+ else:
+ if eventtype=='start':
+ open_windows[eventname] = frame
+ elif eventtype=='end':
+ begin_frame = open_windows[eventname]
+ del open_windows[eventname]
+ windows_events.append( [eventtype, (begin_frame, frame) , eventname] )
+
+
+ windows_events = sorted(windows_events, key=lambda x: (x[0].capitalize(), x[2], x[1]))
+ points_events = sorted(points_events, key=lambda x: (x[0].capitalize(), x[1]))
+ ntracks = len(set([x[0][1] for x in windows_events])) + 1
+
+ # collapse
+ events = []
+ events_types = {} # Events names
+ current_track = 0
+ for index in range(0, len(points_events)):
+ eventtype, frame, eventname = points_events[index]
+ events_types[eventname] = current_track
+ self._timeline.add_period([frame, frame+2, eventname], row=current_track)
+
+ current_track = 1
+
+ for event in windows_events:
+ eventtype, (frame_begin, frame_end), eventname = event
+
+ if eventname not in events_types:
+ events_types[eventname] = current_track
+ track = current_track
+ current_track += 1
+ else:
+ track = events_types[eventname]
+
+ self._timeline.add_period([frame_begin, frame_end, eventname], row=track)
+
+
+ except Exception as e:
+ self.warning("An error occurred when trying to import the file. Please check the logs.")
+ logger.error(e, exc_info=True)
\ No newline at end of file
diff --git a/pyforms/gui/Controls/ControlEventsGraph/ControlEventsGraph.py b/pyforms/gui/controls/control_events_graph/ControlEventsGraph.py
old mode 100755
new mode 100644
similarity index 88%
rename from pyforms/gui/Controls/ControlEventsGraph/ControlEventsGraph.py
rename to pyforms/gui/controls/control_events_graph/ControlEventsGraph.py
index 072503a..04938ca
--- a/pyforms/gui/Controls/ControlEventsGraph/ControlEventsGraph.py
+++ b/pyforms/gui/controls/control_events_graph/ControlEventsGraph.py
@@ -2,20 +2,10 @@
# -*- coding: utf-8 -*-
import csv
-
-from pysettings import conf
-
-from pyforms.gui.Controls.ControlBase import ControlBase
-from pyforms.gui.Controls.ControlEventsGraph.EventsWidget import EventsWidget
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QWidget, QVBoxLayout, QScrollArea, QScrollBar, QFileDialog
- from PyQt5 import QtCore
-
-else:
- from PyQt4.QtGui import QWidget, QVBoxLayout, QScrollArea, QScrollBar, QFileDialog
- from PyQt4 import QtCore
-
+from pyforms.gui.controls.ControlBase import ControlBase
+from pyforms.gui.controls.control_events_graph.EventsWidget import EventsWidget
+from AnyQt.QtWidgets import QWidget, QVBoxLayout, QScrollArea, QScrollBar, QFileDialog
+from AnyQt import QtCore, _api
class ControlEventsGraph(ControlBase, QWidget):
"""
@@ -38,9 +28,9 @@ def __init__(self, label="", default=0, min=0, max=100, **kwargs):
def init_form(self):
vlayout = QVBoxLayout()
- if conf.PYFORMS_USE_QT5:
+ if _api.USED_API == _api.QT_API_PYQT5:
vlayout.setContentsMargins(0,0,0,0)
- else:
+ elif _api.USED_API == _api.QT_API_PYQT4:
vlayout.setMargin(0)
self.setLayout(vlayout)
@@ -95,7 +85,7 @@ def get_export_filename(self): return "untitled.csv"
def __export(self):
"""Export annotations to a file."""
- filename = QFileDialog.getSaveFileName(parent=self,
+ filename, _ = QFileDialog.getSaveFileName(parent=self,
caption="Export annotations file",
directory=self.get_export_filename(),
filter="CSV Files (*.csv)",
diff --git a/pyforms/gui/Controls/ControlEventsGraph/Event.py b/pyforms/gui/controls/control_events_graph/Event.py
similarity index 92%
rename from pyforms/gui/Controls/ControlEventsGraph/Event.py
rename to pyforms/gui/controls/control_events_graph/Event.py
index a8c577a..38af3c0 100644
--- a/pyforms/gui/Controls/ControlEventsGraph/Event.py
+++ b/pyforms/gui/controls/control_events_graph/Event.py
@@ -1,15 +1,8 @@
# !/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtGui import QColor
-
-else:
- from PyQt4.QtGui import QColor
-
-from pyforms.gui.Controls.ControlEventsGraph.Track import Track
+from AnyQt.QtGui import QColor
+from pyforms.gui.controls.control_events_graph.Track import Track
class Event(object):
diff --git a/pyforms/gui/Controls/ControlEventsGraph/EventsWidget.py b/pyforms/gui/controls/control_events_graph/EventsWidget.py
old mode 100755
new mode 100644
similarity index 94%
rename from pyforms/gui/Controls/ControlEventsGraph/EventsWidget.py
rename to pyforms/gui/controls/control_events_graph/EventsWidget.py
index f5d82f4..77a012f
--- a/pyforms/gui/Controls/ControlEventsGraph/EventsWidget.py
+++ b/pyforms/gui/controls/control_events_graph/EventsWidget.py
@@ -2,21 +2,14 @@
# -*- coding: utf-8 -*-
import sys
+from pyforms.utils.settings_manager import conf
+from AnyQt.QtWidgets import QWidget
+from AnyQt.QtGui import QColor, QPainter, QFont
+from AnyQt import QtCore
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QWidget
- from PyQt5.QtGui import QColor, QPainter, QFont
- from PyQt5 import QtCore
-
-else:
- from PyQt4.QtGui import QWidget, QColor, QPainter, QFont
- from PyQt4 import QtCore
-
-from pyforms.gui.Controls.ControlEventsGraph.Track import Track
-from pyforms.gui.Controls.ControlEventsGraph.Pointer import Pointer
-from pyforms.gui.Controls.ControlEventsGraph.Event import Event
+from pyforms.gui.controls.control_events_graph.Track import Track
+from pyforms.gui.controls.control_events_graph.Pointer import Pointer
+from pyforms.gui.controls.control_events_graph.Event import Event
class EventsWidget(QWidget):
@@ -53,7 +46,7 @@ def __init__(self, scroll):
#### HELPERS/FUNCTIONS ###################################################
##########################################################################
- def clean(self):
+ def clear(self):
"""
Clean all events
"""
diff --git a/pyforms/gui/Controls/ControlEventsGraph/Pointer.py b/pyforms/gui/controls/control_events_graph/Pointer.py
similarity index 91%
rename from pyforms/gui/Controls/ControlEventsGraph/Pointer.py
rename to pyforms/gui/controls/control_events_graph/Pointer.py
index 771713c..548357f 100644
--- a/pyforms/gui/Controls/ControlEventsGraph/Pointer.py
+++ b/pyforms/gui/controls/control_events_graph/Pointer.py
@@ -1,16 +1,8 @@
# !/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtGui import QColor
- from PyQt5 import QtCore
-
-else:
- from PyQt4.QtGui import QColor
- from PyQt4 import QtCore
-
+from AnyQt.QtGui import QColor
+from AnyQt import QtCore
class Pointer(object):
"""
diff --git a/pyforms/gui/Controls/ControlEventsGraph/Track.py b/pyforms/gui/controls/control_events_graph/Track.py
similarity index 94%
rename from pyforms/gui/Controls/ControlEventsGraph/Track.py
rename to pyforms/gui/controls/control_events_graph/Track.py
index 028266a..2435321 100644
--- a/pyforms/gui/Controls/ControlEventsGraph/Track.py
+++ b/pyforms/gui/controls/control_events_graph/Track.py
@@ -1,16 +1,8 @@
# !/usr/bin/python
# -*- coding: utf-8 -*-
-from pysettings import conf
-
import bisect
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtGui import QColor
-
-else:
- from PyQt4.QtGui import QColor
-
+from AnyQt.QtGui import QColor
class Track(object):
"""
diff --git a/pyforms/gui/Controls/ControlEventsGraph/__init__.py b/pyforms/gui/controls/control_events_graph/__init__.py
similarity index 88%
rename from pyforms/gui/Controls/ControlEventsGraph/__init__.py
rename to pyforms/gui/controls/control_events_graph/__init__.py
index 161f236..b6df673 100644
--- a/pyforms/gui/Controls/ControlEventsGraph/__init__.py
+++ b/pyforms/gui/controls/control_events_graph/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-""" pyforms.gui.Controls.ControlEventTimeline.__init__
+""" pyforms.gui.controls.ControlEventTimeline.__init__
"""
diff --git a/pyforms/gui/Controls/ControlPlayer/AbstractGLWidget.py b/pyforms/gui/controls/control_player/AbstractGLWidget.py
similarity index 93%
rename from pyforms/gui/Controls/ControlPlayer/AbstractGLWidget.py
rename to pyforms/gui/controls/control_player/AbstractGLWidget.py
index 493509b..3d391b5 100644
--- a/pyforms/gui/Controls/ControlPlayer/AbstractGLWidget.py
+++ b/pyforms/gui/controls/control_player/AbstractGLWidget.py
@@ -1,38 +1,25 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-""" pyforms.gui.Controls.ControlPlayer.VideoGLWidget
+""" pyforms.gui.controls.ControlPlayer.VideoGLWidget
"""
+import logging, cv2
-from pysettings import conf
-import logging, math, pyforms.utils.tools as tools, time
+from pyforms.utils.settings_manager import conf
+from AnyQt import QtGui, QtCore, _api
+from AnyQt.QtWidgets import QApplication
-if conf.PYFORMS_USE_QT5:
- from PyQt5 import QtGui
- from PyQt5 import QtCore
- from PyQt5.QtWidgets import QApplication
-else:
- from PyQt4 import QtGui
- from PyQt4 import QtCore
- from PyQt4.QtGui import QApplication
-
-import OpenGL.GL as GL
+import OpenGL.GL as GL
import OpenGL.GLU as GLU
-from pysettings import conf
-try:
- import cv2
-except:
- print("Warning: was not possible to import cv2 in ControlPlayer")
-
-__author__ = "Ricardo Ribeiro"
-__credits__ = ["Ricardo Ribeiro"]
-__license__ = "MIT"
-__version__ = "0.0"
-__maintainer__ = "Ricardo Ribeiro"
-__email__ = "ricardojvr@gmail.com"
-__status__ = "Development"
+__author__ = "Ricardo Ribeiro"
+__credits__ = ["Ricardo Ribeiro"]
+__license__ = "MIT"
+__version__ = "0.0"
+__maintainer__ = "Ricardo Ribeiro"
+__email__ = "ricardojvr@gmail.com"
+__status__ = "Development"
class MouseEvent:
@@ -40,6 +27,7 @@ def __init__(self, event):
self.x = event.x()
self.y = event.y()
self.button = event.button()
+ self.event = event
class AbstractGLWidget(object):
@@ -350,10 +338,10 @@ def wheelEvent(self, event):
self._mouseX = event.x()
self._mouseY = event.y()
- if conf.PYFORMS_USE_QT5:
+ if _api.USED_API == _api.QT_API_PYQT5:
p = event.angleDelta()
delta = p.y()
- else:
+ elif _api.USED_API == _api.QT_API_PYQT4:
delta = event.delta()
zoom_factor = delta / float(1500)
@@ -455,39 +443,39 @@ def keyReleaseEvent(self, event):
if event.key() == QtCore.Qt.Key_M: self._move_img = False
if event.key() == QtCore.Qt.Key_1:
- self._control.speed = 1
+ self._control.next_frame_step = 1
self.show_tmp_msg('Speed: 1x')
if event.key() == QtCore.Qt.Key_2:
- self._control.speed = 2
+ self._control.next_frame_step = 2
self.show_tmp_msg('Speed: 2x')
if event.key() == QtCore.Qt.Key_3:
- self._control.speed = 3
+ self._control.next_frame_step = 3
self.show_tmp_msg('Speed: 3x')
if event.key() == QtCore.Qt.Key_4:
- self._control.speed = 4
+ self._control.next_frame_step = 4
self.show_tmp_msg('Speed: 4x')
if event.key() == QtCore.Qt.Key_5:
- self._control.speed = 5
+ self._control.next_frame_step = 5
self.show_tmp_msg('Speed: 5x')
if event.key() == QtCore.Qt.Key_6:
- self._control.speed = 6
+ self._control.next_frame_step = 6
self.show_tmp_msg('Speed: 6x')
if event.key() == QtCore.Qt.Key_7:
- self._control.speed = 7
+ self._control.next_frame_step = 7
self.show_tmp_msg('Speed: 7x')
if event.key() == QtCore.Qt.Key_8:
- self._control.speed = 8
+ self._control.next_frame_step = 8
self.show_tmp_msg('Speed: 8x')
if event.key() == QtCore.Qt.Key_9:
- self._control.speed = 9
+ self._control.next_frame_step = 9
self.show_tmp_msg('Speed: 9x')
diff --git a/pyforms/gui/Controls/ControlPlayer/ControlPlayer.py b/pyforms/gui/controls/control_player/ControlPlayer.py
similarity index 90%
rename from pyforms/gui/Controls/ControlPlayer/ControlPlayer.py
rename to pyforms/gui/controls/control_player/ControlPlayer.py
index 466d76f..8f2492a 100755
--- a/pyforms/gui/Controls/ControlPlayer/ControlPlayer.py
+++ b/pyforms/gui/controls/control_player/ControlPlayer.py
@@ -1,56 +1,37 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-""" pyforms.gui.Controls.ControlPlayer.ControlPlayer
+""" pyforms.gui.controls.ControlPlayer.ControlPlayer
"""
+__author__ = "Ricardo Ribeiro"
+__credits__ = ["Ricardo Ribeiro"]
+__license__ = "MIT"
+__version__ = "0.0"
+__maintainer__ = "Ricardo Ribeiro"
+__email__ = "ricardojvr@gmail.com"
+__status__ = "Development"
-import math
-import os
-import logging
+import logging, platform, os, math, cv2
-from pysettings import conf
-if conf.PYFORMS_USE_QT5:
- from PyQt5 import uic
- from PyQt5 import QtCore
- from PyQt5.QtWidgets import QFrame
- from PyQt5.QtWidgets import QApplication
+from pyforms.utils.settings_manager import conf
+from AnyQt import uic, _api
+from AnyQt import QtCore
+from AnyQt.QtWidgets import QFrame
+from AnyQt.QtWidgets import QApplication
+from pyforms.gui.controls.ControlBase import ControlBase
+if _api.USED_API == _api.QT_API_PYQT5:
import platform
-
if platform.system() == 'Darwin':
- from pyforms.gui.Controls.ControlPlayer.VideoQt5GLWidget import VideoQt5GLWidget as VideoGLWidget
+ from pyforms.gui.controls.control_player.VideoQt5GLWidget import VideoQt5GLWidget as VideoGLWidget
else:
- from pyforms.gui.Controls.ControlPlayer.VideoGLWidget import VideoGLWidget
-
-else:
- from PyQt4.QtGui import QFrame
- from PyQt4 import uic
- from PyQt4 import QtCore
- from PyQt4.QtGui import QApplication
- from pyforms.gui.Controls.ControlPlayer.VideoGLWidget import VideoGLWidget
-
-from pyforms.gui.Controls.ControlBase import ControlBase
-import pyforms.utils.tools as tools
-from pysettings import conf
-
-try:
- import cv2
-except:
- print("Warning: was not possible to import cv2 in ControlPlayer")
-
-
+ from pyforms.gui.controls.control_player.VideoGLWidget import VideoGLWidget
+elif _api.USED_API == _api.QT_API_PYQT4:
+ from pyforms.gui.controls.control_player.VideoGLWidget import VideoGLWidget
-__author__ = "Ricardo Ribeiro"
-__credits__ = ["Ricardo Ribeiro"]
-__license__ = "MIT"
-__version__ = "0.0"
-__maintainer__ = "Ricardo Ribeiro"
-__email__ = "ricardojvr@gmail.com"
-__status__ = "Development"
-
class ControlPlayer(ControlBase, QFrame):
@@ -78,8 +59,6 @@ def init_form(self):
self.videoPlay.setIcon(conf.PYFORMS_ICON_VIDEOPLAYER_PAUSE_PLAY)
-
-
self._videoWidget = VideoGLWidget()
self._videoWidget._control = self
self.videoLayout.addWidget(self._videoWidget)
@@ -227,6 +206,7 @@ def value(self): return ControlBase.value.fget(self)
@value.setter
def value(self, value):
+ self.form.setUpdatesEnabled(False)
if value is None:
self.stop()
self.videoControl.setEnabled(False)
@@ -254,6 +234,7 @@ def value(self, value):
self.videoControl.setEnabled(True)
self.refresh()
+ self.form.setUpdatesEnabled(True)
##########################################################################
@@ -273,6 +254,8 @@ def __rotateZ(self):
def update_frame(self):
+ self.form.setUpdatesEnabled(False)
+
if not self.visible: self.stop()
if self.value is None:
@@ -298,6 +281,9 @@ def update_frame(self):
if self._updateVideoFrame:
self.videoFrames.setValue(currentFrame)
+ self.form.setUpdatesEnabled(True)
+
+
def videoPlay_clicked(self):
"""Slot for Play/Pause functionality."""
diff --git a/pyforms/gui/controls/control_player/VideoGLWidget.py b/pyforms/gui/controls/control_player/VideoGLWidget.py
new file mode 100644
index 0000000..1cae8fa
--- /dev/null
+++ b/pyforms/gui/controls/control_player/VideoGLWidget.py
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+""" pyforms.gui.controls.ControlPlayer.VideoGLWidget
+
+"""
+
+from pyforms.gui.controls.control_player.AbstractGLWidget import AbstractGLWidget
+from AnyQt.QtOpenGL import QGLWidget
+
+class VideoGLWidget(AbstractGLWidget, QGLWidget): pass
\ No newline at end of file
diff --git a/pyforms/gui/Controls/ControlPlayer/VideoQt5GLWidget.py b/pyforms/gui/controls/control_player/VideoQt5GLWidget.py
similarity index 86%
rename from pyforms/gui/Controls/ControlPlayer/VideoQt5GLWidget.py
rename to pyforms/gui/controls/control_player/VideoQt5GLWidget.py
index 5485d3f..0d16072 100644
--- a/pyforms/gui/Controls/ControlPlayer/VideoQt5GLWidget.py
+++ b/pyforms/gui/controls/control_player/VideoQt5GLWidget.py
@@ -1,9 +1,9 @@
-from pyforms.gui.Controls.ControlPlayer.AbstractGLWidget import AbstractGLWidget
+from pyforms.gui.controls.control_player.AbstractGLWidget import AbstractGLWidget
import math
-from PyQt5 import QtGui
-from PyQt5.QtWidgets import QOpenGLWidget
-from PyQt5 import QtCore
+from AnyQt import QtGui
+from AnyQt.QtWidgets import QOpenGLWidget
+from AnyQt import QtCore
class VideoQt5GLWidget(AbstractGLWidget, QOpenGLWidget):
diff --git a/pyforms/gui/Controls/ControlPlayer/__init__.py b/pyforms/gui/controls/control_player/__init__.py
similarity index 100%
rename from pyforms/gui/Controls/ControlPlayer/__init__.py
rename to pyforms/gui/controls/control_player/__init__.py
diff --git a/pyforms/gui/Controls/ControlPlayer/video.ui b/pyforms/gui/controls/control_player/video.ui
old mode 100755
new mode 100644
similarity index 100%
rename from pyforms/gui/Controls/ControlPlayer/video.ui
rename to pyforms/gui/controls/control_player/video.ui
diff --git a/pyforms/gui/Controls/fileInput.ui b/pyforms/gui/controls/fileInput.ui
old mode 100755
new mode 100644
similarity index 100%
rename from pyforms/gui/Controls/fileInput.ui
rename to pyforms/gui/controls/fileInput.ui
diff --git a/pyforms/gui/Controls/image.ui b/pyforms/gui/controls/image.ui
old mode 100755
new mode 100644
similarity index 100%
rename from pyforms/gui/Controls/image.ui
rename to pyforms/gui/controls/image.ui
diff --git a/pyforms/gui/Controls/label.ui b/pyforms/gui/controls/label.ui
similarity index 100%
rename from pyforms/gui/Controls/label.ui
rename to pyforms/gui/controls/label.ui
diff --git a/pyforms/gui/controls/list.ui b/pyforms/gui/controls/list.ui
new file mode 100644
index 0000000..760ab06
--- /dev/null
+++ b/pyforms/gui/controls/list.ui
@@ -0,0 +1,219 @@
+
+
+ ControlList
+
+
+
+ 0
+ 0
+ 471
+ 168
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Form
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 28
+
+
+
+
+ 16777215
+ 28
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 28
+
+
+
+ TextLabel
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ 0
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 28
+ 28
+
+
+
+
+ 18
+ 75
+ true
+
+
+
+ +
+
+
+
+ 28
+ 28
+
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 28
+ 28
+
+
+
+
+ 18
+ 75
+ true
+
+
+
+ -
+
+
+
+ 28
+ 28
+
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+ false
+
+
+ Qt::NoPen
+
+
+ false
+
+
+ 100
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ false
+
+
+ false
+
+
+
+
+
+
+
+
diff --git a/pyforms/gui/Controls/number.ui b/pyforms/gui/controls/number.ui
similarity index 100%
rename from pyforms/gui/Controls/number.ui
rename to pyforms/gui/controls/number.ui
diff --git a/pyforms/gui/Controls/progressInput.ui b/pyforms/gui/controls/progressInput.ui
old mode 100755
new mode 100644
similarity index 100%
rename from pyforms/gui/Controls/progressInput.ui
rename to pyforms/gui/controls/progressInput.ui
diff --git a/pyforms/gui/Controls/sliderInput.ui b/pyforms/gui/controls/sliderInput.ui
old mode 100755
new mode 100644
similarity index 100%
rename from pyforms/gui/Controls/sliderInput.ui
rename to pyforms/gui/controls/sliderInput.ui
diff --git a/pyforms/gui/controls/table-view.ui b/pyforms/gui/controls/table-view.ui
new file mode 100644
index 0000000..3d765ad
--- /dev/null
+++ b/pyforms/gui/controls/table-view.ui
@@ -0,0 +1,198 @@
+
+
+ ControlList
+
+
+
+ 0
+ 0
+ 471
+ 168
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Form
+
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 28
+
+
+
+
+ 16777215
+ 28
+
+
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 28
+
+
+
+ TextLabel
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ 0
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 28
+ 28
+
+
+
+
+ 18
+ 75
+ true
+
+
+
+ +
+
+
+
+ 28
+ 28
+
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 28
+ 28
+
+
+
+
+ 18
+ 75
+ true
+
+
+
+ -
+
+
+
+ 28
+ 28
+
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+ false
+
+
+ Qt::NoPen
+
+
+ 0
+
+
+ 100
+
+
+ false
+
+
+ true
+
+
+ 0
+
+
+ false
+
+
+
+
+
+
+
+
diff --git a/pyforms/gui/Controls/textArea.ui b/pyforms/gui/controls/textArea.ui
old mode 100755
new mode 100644
similarity index 100%
rename from pyforms/gui/Controls/textArea.ui
rename to pyforms/gui/controls/textArea.ui
diff --git a/pyforms/gui/Controls/textInput.ui b/pyforms/gui/controls/textInput.ui
old mode 100755
new mode 100644
similarity index 100%
rename from pyforms/gui/Controls/textInput.ui
rename to pyforms/gui/controls/textInput.ui
diff --git a/pyforms/gui/Controls/tree.ui b/pyforms/gui/controls/tree.ui
old mode 100755
new mode 100644
similarity index 100%
rename from pyforms/gui/Controls/tree.ui
rename to pyforms/gui/controls/tree.ui
diff --git a/pyforms/gui/Controls/uipics/add.png b/pyforms/gui/controls/uipics/add.png
similarity index 100%
rename from pyforms/gui/Controls/uipics/add.png
rename to pyforms/gui/controls/uipics/add.png
diff --git a/pyforms/gui/Controls/uipics/film.png b/pyforms/gui/controls/uipics/film.png
similarity index 100%
rename from pyforms/gui/Controls/uipics/film.png
rename to pyforms/gui/controls/uipics/film.png
diff --git a/pyforms/gui/Controls/uipics/film_edit.png b/pyforms/gui/controls/uipics/film_edit.png
similarity index 100%
rename from pyforms/gui/Controls/uipics/film_edit.png
rename to pyforms/gui/controls/uipics/film_edit.png
diff --git a/pyforms/gui/Controls/uipics/graph.png b/pyforms/gui/controls/uipics/graph.png
similarity index 100%
rename from pyforms/gui/Controls/uipics/graph.png
rename to pyforms/gui/controls/uipics/graph.png
diff --git a/pyforms/gui/Controls/uipics/page_white_get.png b/pyforms/gui/controls/uipics/page_white_get.png
similarity index 100%
rename from pyforms/gui/Controls/uipics/page_white_get.png
rename to pyforms/gui/controls/uipics/page_white_get.png
diff --git a/pyforms/gui/Controls/uipics/page_white_put.png b/pyforms/gui/controls/uipics/page_white_put.png
similarity index 100%
rename from pyforms/gui/Controls/uipics/page_white_put.png
rename to pyforms/gui/controls/uipics/page_white_put.png
diff --git a/pyforms/gui/Controls/uipics/refresh.png b/pyforms/gui/controls/uipics/refresh.png
similarity index 100%
rename from pyforms/gui/Controls/uipics/refresh.png
rename to pyforms/gui/controls/uipics/refresh.png
diff --git a/pyforms/gui/Controls/uipics/remove.png b/pyforms/gui/controls/uipics/remove.png
similarity index 100%
rename from pyforms/gui/Controls/uipics/remove.png
rename to pyforms/gui/controls/uipics/remove.png
diff --git a/pyforms/gui/Controls/uipics/timeline.png b/pyforms/gui/controls/uipics/timeline.png
similarity index 100%
rename from pyforms/gui/Controls/uipics/timeline.png
rename to pyforms/gui/controls/uipics/timeline.png
diff --git a/pyforms/gui/Controls/uipics/zoom_in.png b/pyforms/gui/controls/uipics/zoom_in.png
similarity index 100%
rename from pyforms/gui/Controls/uipics/zoom_in.png
rename to pyforms/gui/controls/uipics/zoom_in.png
diff --git a/pyforms/gui/Controls/uipics/zoom_out.png b/pyforms/gui/controls/uipics/zoom_out.png
similarity index 100%
rename from pyforms/gui/Controls/uipics/zoom_out.png
rename to pyforms/gui/controls/uipics/zoom_out.png
diff --git a/pyforms/gui/dialogs/csv_parser.py b/pyforms/gui/dialogs/csv_parser.py
index 65be78e..cb219c0 100644
--- a/pyforms/gui/dialogs/csv_parser.py
+++ b/pyforms/gui/dialogs/csv_parser.py
@@ -1,10 +1,10 @@
import csv
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlFile
-from pyforms.Controls import ControlList
-from pyforms.Controls import ControlNumber
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlFile
+from pyforms.controls import ControlList
+from pyforms.controls import ControlNumber
class CsvParserDialog(BaseWidget):
@@ -15,12 +15,12 @@ def __init__(self, parent=None):
# Definition of the forms fields
self._filename = ControlFile('CSV File')
- self._separator = ControlText('Separator', ';')
- self._startingrow = ControlNumber('Starting row', 0)
- self._frameCol = ControlNumber('Frame column', 0, 0, 100)
- self._xCol = ControlNumber('X column', 1, 0, 100)
- self._yCol = ControlNumber('Y column', 2, 0, 100)
- self._zCol = ControlNumber('Z column', 3, 0, 100)
+ self._separator = ControlText('Separator', default=';')
+ self._startingrow = ControlNumber('Starting row', default=0)
+ self._frameCol = ControlNumber('Frame column', default=0, minumum=0, maximum=100)
+ self._xCol = ControlNumber('X column', default=1, minumum=0, maximum=100)
+ self._yCol = ControlNumber('Y column', default=2, minumum=0, maximum=100)
+ self._zCol = ControlNumber('Z column', default=3, minumum=0, maximum=100)
self._filePreview = ControlList('Preview')
self._loadButton = ControlButton('Load')
@@ -40,10 +40,10 @@ def filename(self, value):
self.__refreshPreview()
@property
- def loadFileEvent(self): return self._loadButton.value
+ def load_file_event(self): return self._loadButton.value
- @loadFileEvent.setter
- def loadFileEvent(self, value): self._loadButton.value = value
+ @load_file_event.setter
+ def load_file_event(self, value): self._loadButton.value = value
@property
def separator(self): return self._separator.value
@@ -107,7 +107,7 @@ def __next__(self): return self.next()
def next(self):
if self._spamreader != None:
- row = self._spamreader.next()
+ row = next(self._spamreader)
return [row[int(col)] for col in self._cols]
else:
raise StopIteration()
diff --git a/pyforms/gui/dialogs/generic_csv_parser.py b/pyforms/gui/dialogs/generic_csv_parser.py
index e2364f6..4aeabce 100644
--- a/pyforms/gui/dialogs/generic_csv_parser.py
+++ b/pyforms/gui/dialogs/generic_csv_parser.py
@@ -1,90 +1,137 @@
import csv
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlFile
-from pyforms.Controls import ControlList
-from pyforms.Controls import ControlNumber
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlFile
+from pyforms.controls import ControlList
+from pyforms.controls import ControlNumber
class GenericCsvParserDialog(BaseWidget):
+ def __init__(self, columns, parent=None):
+ super(GenericCsvParserDialog, self).__init__('CSV Choose the columns', parent_win=parent)
+
+ self._filename = None
+ self._columns = columns
+ self._columns_indexes = []
+ self._rownum = 0
+
+ # Definition of the forms fields
+ self._filename = ControlFile('CSV File')
+ self._separator = ControlCombo('Separator', default='auto')
+ self._startingrow = ControlNumber('Starting row', default=0)
+
+ for index, column in enumerate(columns):
+ setattr(self, '_col_{0}'.format(index), ControlNumber(column, default=index, minimum=-1, maximum=1000))
+
+ self._filePreview = ControlList('Preview')
+ self._loadButton = ControlButton('Load')
+
+ form_row = ['_separator'] + ['_col_{0}'.format(index) for index, column in enumerate(columns)] + ['_loadButton']
+
+ self._formset = [
+ ('_filename', '_startingrow'),
+ tuple(form_row),
+ '_filePreview'
+ ]
+ self._separator.changed_event = self.__refreshPreview
+ self._filename.changed_event = self.__refreshPreview
+ self._startingrow.changed_event = self.__refreshPreview
+ self._loadButton.value = self.load
+
+ self._load_event = None
+
+ self._separator.add_item('auto', 'auto')
+ self._separator.add_item(';', ';')
+ self._separator.add_item(',', ',')
+ self._separator.add_item('TAB', '\t')
+ self._separator.add_item('Excel', csv.excel)
+ self._separator.add_item('Excel TAB', csv.excel_tab)
+
+ @property
+ def load_file_event(self):
+ return self._load_event
+
+ @load_file_event.setter
+ def load_file_event(self, value):
+ self._load_event = value
+
+ def __iter__(self):
+
+ if self._filename.value != None and self._filename.value != '':
+ csvfile = open(self._filename.value, 'U')
+ if self.delimiter in ['auto', csv.excel, csv.excel_tab]:
+ try:
+ dialect = csv.Sniffer().sniff(csvfile.read(1024))
+ csvfile.seek(0)
+ self._spamreader = csv.reader(csvfile, dialect)
+ except:
+ self._spamreader = None
+ return self
+ else:
+ self._spamreader = csv.reader(csvfile, delimiter=self.delimiter)
+ for i in range(int(self._startingrow.value)): next(self._spamreader, None) # skip the headers
+ else:
+ self._spamreader = None
+
+ return self
+
+ # For compatibility with python 3
+ def __next__(self):
+ return self.next()
+
+ def next(self):
+ if self._spamreader != None:
+ row = next(self._spamreader)
+ res = []
+ for col in self._columns_indexes:
+ if col == -1:
+ res.append(self._rownum)
+ else:
+ if row[col].lower() == 'nan':
+ res.append('None')
+ else:
+ res.append(row[col])
+
+ self._rownum +=1
+
+ return res
+ else:
+ raise StopIteration()
+
+ def __refreshPreview(self):
+ if self._filename.value != None and self._filename.value != '':
+ with open(self._filename.value, 'U') as csvfile:
+ if self.delimiter in ['auto', csv.excel, csv.excel_tab]:
+ try:
+ dialect = csv.Sniffer().sniff(csvfile.read(1024))
+ csvfile.seek(0)
+ spamreader = csv.reader(csvfile, dialect)
+ except:
+ self.message('Error when reading the file.')
+ return
+ else:
+ spamreader = csv.reader(csvfile, delimiter=self.delimiter)
+
+ for i in range(int(self._startingrow.value)): next(spamreader, None) # skip the headers
+ self._filePreview.value = []
+ self._filePreview.horizontalHeaders = map(str, range(1000))
+ for i, row in enumerate(spamreader):
+ self._filePreview += row
+ if i >= 10:
+ break
+
+ @property
+ def delimiter(self):
+ return self._separator.value
+
+ def load(self):
+ self.__refreshPreview()
+ self._columns_indexes = []
+ for index, column in enumerate(self._columns):
+ self._columns_indexes.append(int(getattr(self, '_col_{0}'.format(index)).value))
+ if self._load_event is not None: self._load_event()
- def __init__(self, columns, parent=None):
- super(GenericCsvParserDialog, self).__init__('CSV Choose the columns', parent_win = parent)
-
- self._filename = None
- self._columns = columns
- self._columns_indexes = []
-
- # Definition of the forms fields
- self._filename = ControlFile('CSV File')
- self._separator = ControlText('Separator', ';')
- self._startingrow = ControlNumber('Starting row', 0)
-
- for index, column in enumerate(columns):
- setattr(self, '_col_{0}'.format(index), ControlNumber(column, index, -1, 1000) )
-
- self._filePreview = ControlList('Preview')
- self._loadButton = ControlButton('Load')
-
- form_row = ['_separator'] + ['_col_{0}'.format(index) for index, column in enumerate(columns)] + ['_loadButton']
-
- self._formset = [
- ('_filename','_startingrow'),
- tuple(form_row),
- '_filePreview'
- ]
- self._separator.changed_event = self.__refreshPreview
- self._filename.changed_event = self.__refreshPreview
- self._startingrow.changed_event = self.__refreshPreview
- self._loadButton.value = self.load
-
- self._load_event = None
-
- @property
- def load_file_event(self): return self._load_event
- @load_file_event.setter
- def load_file_event(self, value): self._load_event = value
-
-
- def __iter__(self):
- if self._filename.value != None and self._filename.value != '':
- csvfile = open(self._filename.value, 'U')
- self._spamreader = csv.reader(csvfile, delimiter=self._separator.value)
- for i in range(int(self._startingrow.value)): next(self._spamreader, None) # skip the headers
- else:
- self._spamreader = None
- return self
-
- # For compatibility with python 3
- def __next__(self): return self.next()
-
- def next(self):
- if self._spamreader != None:
- row = next(self._spamreader)
- return [row[col] for col in self._columns_indexes]
- else:
- raise StopIteration()
-
- def __refreshPreview(self):
- if self._filename.value != None and self._filename.value != '':
- with open(self._filename.value, 'U') as csvfile:
- spamreader = csv.reader(csvfile, delimiter=self._separator.value)
- for i in range(int(self._startingrow.value)): next(spamreader, None) # skip the headers
- self._filePreview.value = []
- self._filePreview.horizontalHeaders = map(str, range(1000))
- for i, row in enumerate(spamreader):
- self._filePreview += row
- if i >= 10:
- break
-
- def load(self):
- self.__refreshPreview()
- self._columns_indexes = []
- for index, column in enumerate(self._columns):
- self._columns_indexes.append( int(getattr(self, '_col_{0}'.format(index) ).value) )
- if self._load_event is not None: self._load_event()
-
##################################################################################################################
##################################################################################################################
@@ -92,5 +139,6 @@ def load(self):
# Execute the application
if __name__ == "__main__":
- import pyforms
- pyforms.start_app(GenericCsvParserDialog, geometry=(0, 0, 600, 400))
+ import pyforms
+
+ pyforms.start_app(GenericCsvParserDialog, geometry=(0, 0, 600, 400))
\ No newline at end of file
diff --git a/pyforms/gui/mainWindow.ui b/pyforms/gui/mainWindow.ui
deleted file mode 100755
index cae4f72..0000000
--- a/pyforms/gui/mainWindow.ui
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
- MainWindow
-
-
-
- 0
- 0
- 767
- 597
-
-
-
- MainWindow
-
-
-
-
- 0
-
-
- 0
-
- -
-
-
- 0
-
-
-
-
-
-
-
-
- Quit
-
-
-
-
- Run
-
-
-
-
- Stop
-
-
-
-
-
-
diff --git a/pyforms/gui/settings.py b/pyforms/gui/settings.py
index 89ab5e8..d833613 100644
--- a/pyforms/gui/settings.py
+++ b/pyforms/gui/settings.py
@@ -2,20 +2,12 @@
# -*- coding: utf-8 -*-
import os
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QStyle, qApp
- from PyQt5.QtGui import QIcon, QPixmap
-
-else:
- from PyQt4.QtGui import QStyle, qApp, QIcon, QPixmap
+from AnyQt.QtGui import QIcon, QPixmap
+from AnyQt.QtWidgets import QStyle, qApp
def path(filename):
- """
-
+ """
:param filename:
:return:
"""
@@ -29,6 +21,7 @@ def path(filename):
state=QIcon.On)
PYFORMS_ICON_CODEEDITOR_SAVE = QIcon(qApp.style().standardPixmap(QStyle.SP_DialogSaveButton))
+PYFORMS_ICON_CODEEDITOR_DISCART = QIcon(qApp.style().standardPixmap(QStyle.SP_DialogDiscardButton))
PYFORMS_PIXMAP_EVENTTIMELINE_ZOOM_IN = QPixmap(path(os.path.join("Controls", "uipics", "zoom_in.png")))
PYFORMS_PIXMAP_EVENTTIMELINE_ZOOM_OUT = QPixmap(path(os.path.join("Controls", "uipics", "zoom_in.png")))
diff --git a/pyforms/gui/standaloneManager.py b/pyforms/gui/standaloneManager.py
deleted file mode 100644
index 4e6ba0a..0000000
--- a/pyforms/gui/standaloneManager.py
+++ /dev/null
@@ -1,218 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-
-import sys
-import os, types
-import inspect, platform
-import logging
-
-from pysettings import conf
-
-from pysettings import conf
-
-if conf.PYFORMS_USE_QT5:
- from PyQt5.QtWidgets import QMainWindow
- from PyQt5.QtWidgets import QDockWidget
- from PyQt5.QtWidgets import QAction
- from PyQt5.QtWidgets import QApplication
- from PyQt5 import QtCore
- from PyQt5.QtGui import QIcon
-else:
- from PyQt4.QtGui import QMainWindow
- from PyQt4.QtGui import QDockWidget
- from PyQt4.QtGui import QAction
- from PyQt4.QtGui import QIcon
- from PyQt4.QtGui import QApplication
- from PyQt4 import QtCore
-
-from pyforms.gui.Controls.ControlDockWidget import ControlDockWidget
-
-logger = logging.getLogger(__name__)
-
-
-class StandAloneContainer(QMainWindow):
- def __init__(self, ClassObject):
- super(QMainWindow, self).__init__()
-
- w = ClassObject()
- w.app_main_window = self
- self._widget = w
-
- if len(w.mainmenu) > 0:
- w._mainmenu = self.__initMainMenu(w.mainmenu)
-
- w.init_form()
-
- if conf.PYFORMS_USE_QT5:
- self.layout().setContentsMargins(conf.PYFORMS_MAINWINDOW_MARGIN,conf.PYFORMS_MAINWINDOW_MARGIN,conf.PYFORMS_MAINWINDOW_MARGIN,conf.PYFORMS_MAINWINDOW_MARGIN)
- else:
- self.layout().setMargin(conf.PYFORMS_MAINWINDOW_MARGIN)
-
- self.setCentralWidget(w)
- self.setWindowTitle(w.title)
-
- docks = {}
- for name, item in w.controls.items():
- if isinstance(item, ControlDockWidget):
- if item.side not in docks:
- docks[item.side] = []
- docks[item.side].append((name, item))
-
- for key, widgets in docks.items():
- side = QtCore.Qt.RightDockWidgetArea
- if key == 'left':
- side = QtCore.Qt.LeftDockWidgetArea
- elif key == 'right':
- side = QtCore.Qt.RightDockWidgetArea
- elif key == 'top':
- side = QtCore.Qt.TopDockWidgetArea
- elif key == 'bottom':
- side = QtCore.Qt.BottomDockWidgetArea
- else:
- side = QtCore.Qt.LeftDockWidgetArea
-
- if isinstance(widgets, list):
- widgets = sorted(widgets, key=lambda x: x[1].order)
-
- for name, widget in widgets:
- dock = QDockWidget(self)
- dock.setFeatures(
- QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable)
- dock.setObjectName(name)
-
- if conf.PYFORMS_USE_QT5:
- dock.setContentsMargins(0,0,0,0)
- widget.form.layout().setContentsMargins(widget.margin,widget.margin,widget.margin,widget.margin)
- else:
- dock.setMargin(0)
- widget.form.layout().setMargin(widget.margin)
-
- # print dock.objectName(),1
- dock.setWidget(widget.form)
- dock.setWindowTitle(widget.label)
- widget.dock = dock
- if not widget._show: dock.hide()
-
- self.addDockWidget(side, dock)
- else:
- dock = QDockWidget(self)
- dock.setFeatures(
- QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable)
- # dock.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
-
- if conf.PYFORMS_USE_QT5:
- widget.form.layout().setContentsMargins(widget.margin,widget.margin,widget.margin,widget.margin)
- else:
- widget.form.layout().setMargin(widget.margin)
-
- # print dock.objectName(), 2
- dock.setObjectName(name)
- dock.setWidget(widget.form)
- self.addDockWidget(side, dock)
- dock.setWindowTitle(widget.label)
- widget.dock = dock
- if not widget._show: dock.hide()
-
- if conf.PYFORMS_STYLESHEET:
- stylesheet_files = [conf.PYFORMS_STYLESHEET]
-
- p = platform.system()
- if p == 'Windows' and conf.PYFORMS_STYLESHEET_WINDOWS:
- stylesheet_files.append(conf.PYFORMS_STYLESHEET_WINDOWS)
- elif p == 'Darwin' and conf.PYFORMS_STYLESHEET_DARWIN:
- stylesheet_files.append(conf.PYFORMS_STYLESHEET_DARWIN)
- elif p == 'Linux' and conf.PYFORMS_STYLESHEET_LINUX:
- stylesheet_files.append(conf.PYFORMS_STYLESHEET_LINUX)
-
- logger.debug('Import stylesheets: {0}'.format(stylesheet_files))
- self.loadStyleSheetFile(stylesheet_files)
-
- def closeEvent(self, event):
- self._widget.closeEvent(event)
-
- def __initMainMenu(self, options, keys={}):
- menubar = self.menuBar()
- for menuIndex, m in enumerate(options):
- for key, menus in m.items():
- menu = menubar.addMenu(key)
- for subMenuIndex, m1 in enumerate(menus):
- if isinstance(m1, str) and m1 == "-":
- menu.addSeparator()
- else:
- for text, func in m1.items():
- if text != 'icon':
- action = QAction(text, self)
- if 'icon' in m1.keys():
- action.setIconVisibleInMenu(True)
- action.setIcon(QIcon(m1['icon']))
- if func:
- action.triggered.connect(func)
- menu.addAction(action)
- options[menuIndex][key][subMenuIndex][text] = action
- break
- return options
-
- def loadStyleSheetFile(self, files):
- content = ''
- for filename in files:
- infile = open(filename, 'r')
- content += infile.read() + '\n'
- infile.close()
-
- self.setStyleSheet(content)
-
-
-def execute_test_file(myapp):
- import argparse
- parser = argparse.ArgumentParser()
- parser.add_argument("test_file", help="File with the tests script")
- args = parser.parse_args()
-
- with open(args.test_file) as f:
- global_vars = globals()
- local_vars = locals()
- code = compile(f.read(), args.test_file, 'exec')
- exec(code, global_vars, local_vars)
-
-
-def start_app(ClassObject, geometry=None):
- from pysettings import conf
-
- app = QApplication(sys.argv)
-
- conf += 'pyforms.gui.settings'
-
- mainwindow = StandAloneContainer(ClassObject)
-
- myapp = mainwindow.centralWidget()
-
- if geometry is not None:
- mainwindow.show()
- mainwindow.setGeometry(*geometry)
- else:
- mainwindow.showMaximized()
-
- if conf.PYFORMS_QUALITY_TESTS_PATH is not None:
- import argparse
- parser = argparse.ArgumentParser()
- parser.add_argument("--test", help="File with the tests script")
- args = parser.parse_args()
-
- if args.test:
- TEST_PATH = os.path.join(conf.PYFORMS_QUALITY_TESTS_PATH, args.test)
- TEST_FILE_PATH = os.path.join(TEST_PATH, args.test + '.py')
- DATA_PATH = os.path.join(TEST_PATH, 'data', sys.platform)
- INPUT_DATA_PATH = os.path.join(DATA_PATH, 'input-data')
- OUTPUT_DATA_PATH = os.path.join(DATA_PATH, 'output-data')
- EXPECTED_DATA_PATH = os.path.join(DATA_PATH, 'expected-data')
-
- with open(TEST_FILE_PATH) as f:
- global_vars = {} # globals()
- local_vars = locals()
- code = compile(f.read(), TEST_FILE_PATH, 'exec')
-
- exec(code, global_vars, local_vars)
-
- app.exec_()
- return myapp
diff --git a/pyforms/settings.py b/pyforms/settings.py
index 0441907..f350bca 100644
--- a/pyforms/settings.py
+++ b/pyforms/settings.py
@@ -2,12 +2,16 @@
# -*- coding: utf-8 -*-
-import logging, os
+import logging, os, sys
+
+if 'terminal_mode' in sys.argv:
+ PYFORMS_MODE = 'TERMINAL'
+else:
+ PYFORMS_MODE = os.environ.get('PYFORMS_MODE', 'GUI')
-PYFORMS_MODE = os.environ.get('PYFORMS_MODE', 'GUI')
PYFORMS_LOG_FILENAME = 'pyforms.log'
-PYFORMS_LOG_HANDLER_FILE_LEVEL = logging.DEBUG
+PYFORMS_LOG_HANDLER_FILE_LEVEL = logging.INFO
PYFORMS_LOG_HANDLER_CONSOLE_LEVEL = logging.INFO
PYFORMS_CONTROL_CODE_EDITOR_DEFAULT_FONT_SIZE = '12'
@@ -28,9 +32,8 @@
# See pyforms.utils.plugins_finder.find_class()
PYFORMS_SILENT_PLUGINS_FINDER = True
-PYFORMS_USE_QT5 = True
-
-PYFORMS_MATPLOTLIB_ENABLED = True
-PYFORMS_WEB_ENABLED = True
-PYFORMS_GL_ENABLED = True
-PYFORMS_VISVIS_ENABLED = True
+PYFORMS_QSCINTILLA_ENABLED = True
+PYFORMS_MATPLOTLIB_ENABLED = True
+PYFORMS_WEB_ENABLED = True
+PYFORMS_GL_ENABLED = True
+PYFORMS_VISVIS_ENABLED = True
diff --git a/pyforms/terminal/BaseWidget.py b/pyforms/terminal/BaseWidget.py
deleted file mode 100755
index 97fc159..0000000
--- a/pyforms/terminal/BaseWidget.py
+++ /dev/null
@@ -1,185 +0,0 @@
-from pyforms.Controls import ControlFile, ControlSlider, ControlText, ControlCombo, ControlCheckBox, ControlBase, ControlDir, ControlNumber
-from datetime import datetime, timedelta
-import argparse, uuid, os, shutil, time, sys, subprocess
-
-try:
- import requests
-except:
- print("No requests lib")
-
-
-class BaseWidget(object):
-
- def __init__(self, title):
- self._parser = argparse.ArgumentParser()
- with open('pid.txt', 'w') as f:
- f.write( str(os.getpid()) )
-
- self._controlsPrefix = ''
- self._title = title
- self.stop = False
-
- ############################################################################
- ############ Module functions #############################################
- ############################################################################
-
- def init_form(self, parse=True):
- result = {}
- for fieldname, var in self.controls.items():
- name = var._name
- if isinstance(var, (
- ControlFile,ControlSlider,ControlText,
- ControlCombo,ControlCheckBox, ControlDir, ControlNumber
- )
- ):
- self._parser.add_argument("--%s" % name, help=var.label)
-
- if parse:
-
- self._parser.add_argument(
- "--exec{0}".format(self._controlsPrefix),
- default='',
- help='Function from the application that should be executed. Use | to separate a list of functions.')
- self._args = self._parser.parse_args()
-
- self.__parse_terminal_parameters()
- self.__execute_events()
-
-
- def __parse_terminal_parameters(self):
- for fieldname, var in self.controls.items():
- name = var._name
- if self._args.__dict__.get(name, None):
-
- if isinstance(var, ControlFile):
- value = self._args.__dict__[name]
- if value!=None and (value.startswith('http://') or value.startswith('https://')):
- local_filename = value.split('/')[-1]
- outputFileName = os.path.join('input', local_filename)
- self.__downloadFile(value, outputFileName)
- var.value = outputFileName
- else:
- var.value = value
-
- if isinstance(var, ControlDir):
- value = self._args.__dict__[name]
- var.value = value
- elif isinstance(var, (ControlText, ControlCombo)):
- var.value = self._args.__dict__[name]
- elif isinstance(var, ControlCheckBox):
- var.value = self._args.__dict__[name]=='True'
- elif isinstance(var, (ControlSlider, ControlNumber) ):
- var.value = int(self._args.__dict__[name])
-
-
-
- def __execute_events(self):
- for function in self._args.__dict__.get("exec{0}".format(self._controlsPrefix), []).split('|'):
- if len(function)>0:
- getattr(self, function)()
-
- res = {}
- for controlName, control in self.controls.items():
- res[controlName] = {'value': control.value }
- with open('out-parameters.txt', 'w') as outfile:
- outfile.write( str(res) )
-
-
- def __downloadFile(self, url, outFilepath):
- chunksize = 512*1024
- r = requests.get(url, stream=True)
- with open(outFilepath, 'w') as f:
- for chunk in r.iter_content(chunk_size=chunksize):
- if chunk: f.write(chunk); f.flush();
-
-
-
- def execute(self): pass
-
-
- def start_progress(self, total = 100):
- self._total_processing_count = total
- self._processing_initial_time = time.time()
- self._processing_count = 1
-
- def update_progress(self):
- div = int(self._total_processing_count/400)
- if div==0: div = 1
- if (self._processing_count % div )==0:
- self._processing_last_time = time.time()
- total_passed_time = self._processing_last_time - self._processing_initial_time
- remaining_time = ( (self._total_processing_count * total_passed_time) / self._processing_count ) - total_passed_time
- if remaining_time<0: remaining_time = 0
- time_remaining = datetime(1,1,1) + timedelta(seconds=remaining_time )
- time_elapsed = datetime(1,1,1) + timedelta(seconds=(total_passed_time) )
-
- values = (
- time_elapsed.day-1, time_elapsed.hour, time_elapsed.minute, time_elapsed.second,
- time_remaining.day-1, time_remaining.hour, time_remaining.minute, time_remaining.second,
- (float(self._processing_count)/float(self._total_processing_count))*100.0, self._processing_count, self._total_processing_count,
- )
-
- print("Elapsed: %d:%d:%d:%d; Remaining: %d:%d:%d:%d; Processed %0.2f %% (%d/%d); | \r" % values)
- sys.stdout.flush()
-
- self._processing_count += 1
-
- def end_progress(self):
- self._processing_count = self._total_processing_count
- self.update_progress()
-
-
-
- def __savePID(self, pid):
- try:
- with open('pending_PID.txt', 'w') as f:
- f.write(str(pid))
- f.write('\n')
- except (IOError) as e:
- raise e
-
- def __savePID(self, pid):
- try:
- with open('pending_PID.txt', 'w') as f:
- f.write(str(pid))
- f.write('\n')
- except (IOError) as e:
- raise e
-
-
- def executeCommand(self, cmd, cwd=None, env=None):
- if cwd!=None:
- currentdirectory = os.getcwd()
- os.chdir(cwd)
-
- print(" ".join(cmd))
- proc = subprocess.Popen(cmd)
-
- if cwd!=None: os.chdir(currentdirectory)
- self.__savePID(proc.pid)
- proc.wait()
- #(output, error) = proc.communicate()
- #if error: print 'error: ', error
- #print 'output: ', output
- return ''#output
-
- def exec_terminal_cmd(self, args, **kwargs):
- print('TERMINAL <<',' '.join(args) )
- sys.stdout.flush()
- proc = subprocess.Popen(args, **kwargs)
- self.__savePID(proc.pid)
- proc.wait()
- sys.stdout.flush()
-
-
- @property
- def controls(self):
- """
- Return all the form controls from the the module
- """
- result = {}
- for name, var in vars(self).items():
- if isinstance(var, ControlBase):
- var._name = self._controlsPrefix+"-"+name if len(self._controlsPrefix)>0 else name
- result[name] = var
- return result
\ No newline at end of file
diff --git a/pyforms/terminal/Controls/ControlButton.py b/pyforms/terminal/Controls/ControlButton.py
deleted file mode 100755
index 6e9835d..0000000
--- a/pyforms/terminal/Controls/ControlButton.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from pyforms.terminal.Controls.ControlBase import ControlBase
-
-class ControlButton(ControlBase):
-
- @property
- def value(self): return None
-
- @value.setter
- def value(self, value): self._value = value
-
diff --git a/pyforms/terminal/Controls/ControlDir.py b/pyforms/terminal/Controls/ControlDir.py
deleted file mode 100644
index 2b1f64e..0000000
--- a/pyforms/terminal/Controls/ControlDir.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from pyforms.terminal.Controls.ControlBase import ControlBase
-
-class ControlDir(ControlBase):
-
- pass
\ No newline at end of file
diff --git a/pyforms/terminal/Controls/ControlFile.py b/pyforms/terminal/Controls/ControlFile.py
deleted file mode 100755
index 4f8aa63..0000000
--- a/pyforms/terminal/Controls/ControlFile.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from pyforms.terminal.Controls.ControlBase import ControlBase
-
-class ControlFile(ControlBase):
-
- pass
\ No newline at end of file
diff --git a/pyforms/terminal/Controls/ControlPlayer.py b/pyforms/terminal/Controls/ControlPlayer.py
deleted file mode 100755
index b47a294..0000000
--- a/pyforms/terminal/Controls/ControlPlayer.py
+++ /dev/null
@@ -1,116 +0,0 @@
-from pyforms.terminal.Controls.ControlBase import ControlBase
-import numpy
-
-
-import numpy as np
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
-
-try:
- import cv2
-except:
- print( "cv2 not present. ControlPlayer not working")
-
-
-try:
- from PIL import Image
-except:
- print( "PIL not present. ControlPlayer not working")
-
-
-try:
- import base64
-except:
- print( "base64 not present. ControlPlayer not working")
-
-
-
-
-class ControlPlayer(ControlBase):
- _currentFrame = None
- _min = 0
- _max = 0
- _filename = ''
- _position = 0
-
- def process_frame_event(self, frame): pass
-
- def play(): pass
-
- def stop(): pass
-
- def refresh(): pass
-
- def update_frame(): pass
-
- def double_click_event(event, x, y): pass
-
- def click_event(event, x, y): pass
-
- def drag_event(start_point, end_point): pass
-
- def end_drag_event(start_point, end_point): pass
-
- def key_release_event(event): pass
-
- def process_frame_event(frame): pass
-
- def save_Form(self, data): pass
-
- def load_form(self, data): pass
-
- @property
- def value(self):
- result = {'min': self._min, 'max': self._max, 'position': self.video_index, 'frame': '', 'filename': self._filename }
- capture = self._value
-
- _, image = capture.read()
- if isinstance(image, numpy.ndarray):
- image = self.processFrame(image)
-
- if isinstance(image, list) or isinstance(image, tuple):
- image = groupImage(image, True)
-
-
- if len(image.shape)>2: image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
- image = Image.fromarray(image)
- buff = StringIO.StringIO()
- image.save(buff, format="PNG")
- content = buff.getvalue()
- buff.close()
- result['frame'] = base64.b64encode(content)
-
- return result
-
- @value.setter
- def value(self, value):
- if isinstance( value, (str, unicode) ):
- ControlBase.value.fset(self, cv2.VideoCapture( value ) )
- self._filename = value
- if isinstance( value, dict ):
- ControlBase.value.fset(self, cv2.VideoCapture( value['filename'] ) )
- if 'position' in value.keys(): self.video_index = int(value['position'])
- self._filename = value['filename']
- self._max = int(self._value.get(7))
-
-
-
- @property
- def video_index(self): return self._position
-
- @video_index.setter
- def video_index(self, value): self._position = value
-
-
-
-
- @property
- def image(self): return self._currentFrame
-
- @image.setter
- def image(self, value): pass
-
-
diff --git a/pyforms/terminal/Controls/ControlProgress.py b/pyforms/terminal/Controls/ControlProgress.py
deleted file mode 100755
index 16c90fc..0000000
--- a/pyforms/terminal/Controls/ControlProgress.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from pyforms.terminal.Controls.ControlBase import ControlBase
-
-class ControlProgress(ControlBase):
-
- _min = 0
- _max = 100
-
- def __init__(self, label = "%p%", defaultValue = 0, min = 0, max = 100, helptext=None):
- self._updateSlider = True
- self._min = min
- self._max = max
- ControlBase.__init__(self, label, defaultValue)
-
-
- @property
- def value(self): return self._value
-
- @value.setter
- def value(self, value): self._value = value
-
- @property
- def min(self): return
-
- @min.setter
- def min(self, value): pass
-
- @property
- def max(self): return
-
- @max.setter
- def max(self, value): pass
\ No newline at end of file
diff --git a/pyforms/terminal/Controls/ControlSlider.py b/pyforms/terminal/Controls/ControlSlider.py
deleted file mode 100755
index 4df2c46..0000000
--- a/pyforms/terminal/Controls/ControlSlider.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from pyforms.terminal.Controls.ControlBase import ControlBase
-
-class ControlSlider(ControlBase):
-
- _min = 0
- _max = 100
-
- def __init__(self, label = "", helptext=None, defaultValue = 0, min = 0, max = 100):
- self._updateSlider = True
- self._min = min
- self._max = max
-
- ControlBase.__init__(self, label, defaultValue)
-
-
- @property
- def min(self): return self._min
-
- @min.setter
- def min(self, value): self._min = value
-
- @property
- def max(self): return self._max
-
- @max.setter
- def max(self, value): self._max = value
\ No newline at end of file
diff --git a/pyforms/terminal/Controls/ControlText.py b/pyforms/terminal/Controls/ControlText.py
deleted file mode 100755
index 1e851cf..0000000
--- a/pyforms/terminal/Controls/ControlText.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from pyforms.terminal.Controls.ControlBase import ControlBase
-
-class ControlText(ControlBase):pass
-
-
\ No newline at end of file
diff --git a/pyforms/terminal/appmanager.py b/pyforms/terminal/appmanager.py
old mode 100755
new mode 100644
index 153b00d..7cd5b4c
--- a/pyforms/terminal/appmanager.py
+++ b/pyforms/terminal/appmanager.py
@@ -1,5 +1,5 @@
from pyforms import BaseWidget
-def start_app(ClassObject):
- app = ClassObject()
- app.init_form()
+def start_app(AppClass, **kwargs):
+ app = AppClass(**kwargs.get('app_args', {}))
+ app.init_form()
diff --git a/pyforms/terminal/basewidget.py b/pyforms/terminal/basewidget.py
new file mode 100644
index 0000000..4cdfd9b
--- /dev/null
+++ b/pyforms/terminal/basewidget.py
@@ -0,0 +1,220 @@
+from pyforms.controls import ControlFile, ControlSlider, ControlText, ControlCombo, ControlCheckBox, ControlBase, ControlDir, ControlNumber, ControlBoundingSlider
+from datetime import datetime, timedelta
+import argparse, uuid, os, shutil, time, sys, subprocess
+import simplejson as json
+
+import logging, traceback; logger=logging.getLogger(__file__)
+
+try:
+ import requests
+except:
+ logger.warning("No requests lib")
+ logger.error(e, exc_info=True)
+
+
+class BaseWidget(object):
+
+ def __init__(self, *args, **kwargs):
+ self._parser = argparse.ArgumentParser()
+ self._controlsPrefix = ''
+ self._title = kwargs.get('title', args[0] if len(args)>0 else '')
+ self.stop = False
+
+ self._conf = kwargs.get('load', None)
+
+ ############################################################################
+ ############ Module functions #############################################
+ ############################################################################
+
+ def set_margin(self, margin):pass
+
+ def init_form(self, parse=True):
+ result = {}
+ for fieldname, var in self.controls.items():
+ name = var._name
+ if isinstance(var, (
+ ControlFile, ControlSlider, ControlText,
+ ControlCombo,ControlCheckBox, ControlDir, ControlNumber, ControlBoundingSlider
+ )
+ ):
+ self._parser.add_argument("--%s" % name, help=var.label)
+
+ if parse:
+ self._parser.add_argument('terminal_mode', type=str, default='terminal_mode', help='Flag to run pyforms in terminal mode')
+ self._parser.add_argument(
+ "--exec{0}".format(self._controlsPrefix),
+ default='',
+ help='Function from the application that should be executed. Use | to separate a list of functions.')
+ self._parser.add_argument(
+ "--load{0}".format(self._controlsPrefix),
+ default=None,
+ help='Load a json file containing the pyforms form configuration.')
+ self._args = self._parser.parse_args()
+
+ self.__parse_terminal_parameters()
+ self.__execute_events()
+
+ def load_form(self, data, path=None):
+ allparams = self.controls
+
+ if hasattr(self, 'load_order'):
+ for name in self.load_order:
+ param = allparams[name]
+ if name in data:
+ param.load_form(data[name])
+ else:
+ for name, param in allparams.items():
+ if name in data:
+ param.load_form(data[name])
+
+
+ def __parse_terminal_parameters(self):
+ for fieldname, var in self.controls.items():
+ name = var._name
+ if self._args.__dict__.get(name, None):
+
+ if isinstance(var, ControlFile):
+ value = self._args.__dict__[name]
+ if value!=None and (value.startswith('http://') or value.startswith('https://')):
+ local_filename = value.split('/')[-1]
+ outputFileName = os.path.join('input', local_filename)
+ self.__downloadFile(value, outputFileName)
+ var.value = outputFileName
+ else:
+ var.value = value
+
+ if isinstance(var, ControlDir):
+ value = self._args.__dict__[name]
+ var.value = value
+ elif isinstance(var, (ControlText, ControlCombo)):
+ var.value = self._args.__dict__[name]
+ elif isinstance(var, ControlCheckBox):
+ var.value = self._args.__dict__[name]=='True'
+ elif isinstance(var, (ControlSlider, ControlNumber) ):
+ var.value = int(self._args.__dict__[name])
+ elif isinstance(var, ControlBoundingSlider):
+ var.value = eval(self._args.__dict__[name])
+
+ if self._args.load:
+ print('\n--------- LOADING CONFIG ------------------')
+ with open(self._args.load) as infile:
+ data = json.load(infile)
+ self.load_form(data, os.path.dirname(self._args.load))
+ print('--------- END LOADING CONFIG --------------\n')
+ elif self._conf is not None:
+ print('\n--------- LOADING DEFAULT CONFIG ------------------')
+ self.load_form(self._conf, '.')
+ print('--------- END LOADING DEFAULT CONFIG --------------\n')
+
+
+
+ def __execute_events(self):
+ for function in self._args.__dict__.get("exec{0}".format(self._controlsPrefix), []).split('|'):
+ if len(function)>0:
+ getattr(self, function)()
+
+ res = {}
+ for controlName, control in self.controls.items():
+ res[controlName] = {'value': control.value }
+ with open('out-parameters.txt', 'w') as outfile:
+ outfile.write( str(res) )
+
+
+ def __downloadFile(self, url, outFilepath):
+ chunksize = 512*1024
+ r = requests.get(url, stream=True)
+ with open(outFilepath, 'w') as f:
+ for chunk in r.iter_content(chunk_size=chunksize):
+ if chunk: f.write(chunk); f.flush();
+
+
+
+ def execute(self): pass
+
+
+ def start_progress(self, total = 100):
+ self._total_processing_count = total
+ self._processing_initial_time = time.time()
+ self._processing_count = 1
+
+ def update_progress(self):
+ div = int(self._total_processing_count/400)
+ if div==0: div = 1
+ if (self._processing_count % div )==0:
+ self._processing_last_time = time.time()
+ total_passed_time = self._processing_last_time - self._processing_initial_time
+ remaining_time = ( (self._total_processing_count * total_passed_time) / self._processing_count ) - total_passed_time
+ if remaining_time<0: remaining_time = 0
+ time_remaining = datetime(1,1,1) + timedelta(seconds=remaining_time )
+ time_elapsed = datetime(1,1,1) + timedelta(seconds=(total_passed_time) )
+
+ values = (
+ time_elapsed.day-1, time_elapsed.hour, time_elapsed.minute, time_elapsed.second,
+ time_remaining.day-1, time_remaining.hour, time_remaining.minute, time_remaining.second,
+ (float(self._processing_count)/float(self._total_processing_count))*100.0, self._processing_count, self._total_processing_count,
+ )
+
+ print("Elapsed: %d:%d:%d:%d; Remaining: %d:%d:%d:%d; Processed %0.2f %% (%d/%d); | \r" % values)
+ sys.stdout.flush()
+
+ self._processing_count += 1
+
+ def end_progress(self):
+ self._processing_count = self._total_processing_count
+ self.update_progress()
+
+
+
+ def __savePID(self, pid):
+ try:
+ with open('pending_PID.txt', 'w') as f:
+ f.write(str(pid))
+ f.write('\n')
+ except (IOError) as e:
+ raise e
+
+ def __savePID(self, pid):
+ try:
+ with open('pending_PID.txt', 'w') as f:
+ f.write(str(pid))
+ f.write('\n')
+ except (IOError) as e:
+ raise e
+
+
+ def executeCommand(self, cmd, cwd=None, env=None):
+ if cwd!=None:
+ currentdirectory = os.getcwd()
+ os.chdir(cwd)
+
+ print(" ".join(cmd))
+ proc = subprocess.Popen(cmd)
+
+ if cwd!=None: os.chdir(currentdirectory)
+ self.__savePID(proc.pid)
+ proc.wait()
+ #(output, error) = proc.communicate()
+ #if error: print 'error: ', error
+ #print 'output: ', output
+ return ''#output
+
+ def exec_terminal_cmd(self, args, **kwargs):
+ print('TERMINAL <<',' '.join(args) )
+ sys.stdout.flush()
+ proc = subprocess.Popen(args, **kwargs)
+ self.__savePID(proc.pid)
+ proc.wait()
+ sys.stdout.flush()
+
+
+ @property
+ def controls(self):
+ """
+ Return all the form controls from the the module
+ """
+ result = {}
+ for name, var in vars(self).items():
+ if isinstance(var, ControlBase):
+ var._name = self._controlsPrefix+"-"+name if len(self._controlsPrefix)>0 else name
+ result[name] = var
+ return result
\ No newline at end of file
diff --git a/pyforms/terminal/Controls/ControlBase.py b/pyforms/terminal/controls/ControlBase.py
old mode 100755
new mode 100644
similarity index 67%
rename from pyforms/terminal/Controls/ControlBase.py
rename to pyforms/terminal/controls/ControlBase.py
index bb53838..033b160
--- a/pyforms/terminal/Controls/ControlBase.py
+++ b/pyforms/terminal/controls/ControlBase.py
@@ -7,21 +7,24 @@ class ControlBase(object):
_label = None
_controlHTML = ""
- def __init__(self, label = "", defaultValue = "", helptext=None):
+ def __init__(self, *args, **kwargs):
self._id = uuid.uuid4()
- self._value = defaultValue
+ self._value = kwargs.get('default', None)
self._parent = 1
- self._label = label
+ self._label = kwargs.get('label', args[0] if len(args)>0 else '')
def init_form(self): pass
def load_form(self, data, path=None):
- if 'value' in data: self.value = data['value']
+ oldvalue = self.value
+ self.value = data.get('value', None)
+ if oldvalue!=self.value: self.changed_event()
- def save_form(self, data, path=None):
- if self.value: data['value'] = self.value
-
- def value_updated(self, value): pass
+ def changed_event(self):
+ """
+ Function called when ever the Control value is changed
+ """
+ return True
def show(self):pass
@@ -55,7 +58,7 @@ def value(self): return self._value
def value(self, value):
oldvalue = self._value
self._value = value
- if oldvalue!=value: self.value_updated(value)
+ if oldvalue!=value: self.changed_event()
############################################################################
@@ -80,27 +83,4 @@ def parent(self, value): self._parent = value
- @property
- def maxWidth(self): return -1
-
- @maxWidth.setter
- def maxWidth(self, value): pass
-
- @property
- def minWidth(self): return -1
-
- @minWidth.setter
- def minWidth(self, value): pass
-
-
- @property
- def maxHeight(self): return -1
-
- @maxHeight.setter
- def maxHeight(self, value): pass
-
- @property
- def minHeight(self): return -1
-
- @minHeight.setter
- def minHeight(self, value): pass
+
\ No newline at end of file
diff --git a/pyforms/terminal/controls/ControlBoundingSlider.py b/pyforms/terminal/controls/ControlBoundingSlider.py
new file mode 100644
index 0000000..f424808
--- /dev/null
+++ b/pyforms/terminal/controls/ControlBoundingSlider.py
@@ -0,0 +1,5 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlBoundingSlider(ControlBase):
+
+ pass
\ No newline at end of file
diff --git a/pyforms/terminal/controls/ControlButton.py b/pyforms/terminal/controls/ControlButton.py
new file mode 100644
index 0000000..01d0130
--- /dev/null
+++ b/pyforms/terminal/controls/ControlButton.py
@@ -0,0 +1,17 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlButton(ControlBase):
+
+ def __init__(self, *args, **kwargs):
+ super(ControlButton, self).__init__(*args, **kwargs)
+ self.checked = False
+
+ @property
+ def value(self): return None
+
+ @value.setter
+ def value(self, value): self._value = value
+
+
+
+
\ No newline at end of file
diff --git a/pyforms/terminal/Controls/ControlCheckBox.py b/pyforms/terminal/controls/ControlCheckBox.py
similarity index 76%
rename from pyforms/terminal/Controls/ControlCheckBox.py
rename to pyforms/terminal/controls/ControlCheckBox.py
index 2c7540d..1e8ada4 100644
--- a/pyforms/terminal/Controls/ControlCheckBox.py
+++ b/pyforms/terminal/controls/ControlCheckBox.py
@@ -1,5 +1,5 @@
-from pyforms.terminal.Controls.ControlBase import ControlBase
+from pyforms.terminal.controls.ControlBase import ControlBase
class ControlCheckBox(ControlBase):
diff --git a/pyforms/terminal/controls/ControlCheckBoxList.py b/pyforms/terminal/controls/ControlCheckBoxList.py
new file mode 100644
index 0000000..e26fd80
--- /dev/null
+++ b/pyforms/terminal/controls/ControlCheckBoxList.py
@@ -0,0 +1,55 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlCheckBoxList(ControlBase):
+
+ def __init__(self, *args, **kwargs):
+ if 'default' not in kwargs: kwargs['default'] = []
+ super(ControlCheckBoxList, self).__init__(*args, **kwargs)
+
+ def clear(self):
+ self._value = []
+
+ def __add__(self, val):
+ self._value.append(val)
+ return self
+
+ def __sub__(self, other):
+ self._value.remove(other)
+ return self
+
+ def load_form(self, data, path=None):
+ results = data['selected']
+ for row in range(self.count):
+ item = self._value[row][0]
+ if item != None and str(item) in results:
+ self._value[row] = [item, True]
+ else:
+ self._value[row] = [item, False]
+ self.changed_event()
+
+ @property
+ def count(self):
+ return len(self._value)
+
+ @property
+ def selected_row_index(self):
+ return -1
+
+ @property
+ def value(self):
+ results = []
+ for item, checked in self._value:
+ if checked:
+ results.append(item)
+ return results
+
+ @value.setter
+ def value(self, value):
+ self.clear()
+ for row in value: self += row
+ self.changed_event()
+
+ @property
+ def items(self):
+ for item, checked in self._value:
+ yield (item, checked)
\ No newline at end of file
diff --git a/pyforms/terminal/Controls/ControlCombo.py b/pyforms/terminal/controls/ControlCombo.py
old mode 100755
new mode 100644
similarity index 68%
rename from pyforms/terminal/Controls/ControlCombo.py
rename to pyforms/terminal/controls/ControlCombo.py
index b3cb855..7317b80
--- a/pyforms/terminal/Controls/ControlCombo.py
+++ b/pyforms/terminal/controls/ControlCombo.py
@@ -1,24 +1,22 @@
-from pyforms.terminal.Controls.ControlBase import ControlBase
+from pyforms.terminal.controls.ControlBase import ControlBase
class ControlCombo(ControlBase):
+ def __init__(self, *args, **kwargs):
+ super(ControlCombo, self).__init__(*args, **kwargs)
+ self._items = None
def add_item(self, label, value = None):
if self._items==None: self._items={}
- self._addingItem = True
- #if not (label in self._items.keys()):
- # self._form.comboBox.addItem( label )
-
- firstValue = False
- if self._items=={}: firstValue = True
+
+ first_value = (len(self._items)==0)
if value==None:
self._items[label] = label
else:
self._items[label] = value
- self._addingItem = False
-
- if firstValue: self.value = self._items[label]
+
+ if first_value: self.value = self._items[label]
def clear(self):
@@ -39,7 +37,8 @@ def value(self): return self._value
def value(self, value):
for key, val in self._items.items():
if value == val:
- if self._value!=value: self.value_updated(value)
+ if self._value!=value:
+ self.changed_event()
self._value = val
@property
diff --git a/pyforms/terminal/controls/ControlDir.py b/pyforms/terminal/controls/ControlDir.py
new file mode 100644
index 0000000..7828cb9
--- /dev/null
+++ b/pyforms/terminal/controls/ControlDir.py
@@ -0,0 +1,5 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlDir(ControlBase):
+
+ pass
\ No newline at end of file
diff --git a/pyforms/terminal/controls/ControlEmptyWidget.py b/pyforms/terminal/controls/ControlEmptyWidget.py
new file mode 100644
index 0000000..294d493
--- /dev/null
+++ b/pyforms/terminal/controls/ControlEmptyWidget.py
@@ -0,0 +1,8 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlEmptyWidget(ControlBase):
+
+
+ def load_form(self, data, path=None):
+ if 'value' in data and self.value is not None and self.value != '':
+ self.value.load_form(data['value'], path)
\ No newline at end of file
diff --git a/pyforms/terminal/controls/ControlFile.py b/pyforms/terminal/controls/ControlFile.py
new file mode 100644
index 0000000..0da983e
--- /dev/null
+++ b/pyforms/terminal/controls/ControlFile.py
@@ -0,0 +1,5 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlFile(ControlBase):
+
+ pass
\ No newline at end of file
diff --git a/pyforms/terminal/Controls/ControlImage.py b/pyforms/terminal/controls/ControlImage.py
old mode 100755
new mode 100644
similarity index 71%
rename from pyforms/terminal/Controls/ControlImage.py
rename to pyforms/terminal/controls/ControlImage.py
index a189775..db4914f
--- a/pyforms/terminal/Controls/ControlImage.py
+++ b/pyforms/terminal/controls/ControlImage.py
@@ -1,4 +1,4 @@
-from pyforms.terminal.Controls.ControlBase import ControlBase
+from pyforms.terminal.controls.ControlBase import ControlBase
class ControlImage(ControlBase):
diff --git a/pyforms/terminal/controls/ControlLabel.py b/pyforms/terminal/controls/ControlLabel.py
new file mode 100644
index 0000000..61431a8
--- /dev/null
+++ b/pyforms/terminal/controls/ControlLabel.py
@@ -0,0 +1,5 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlLabel(ControlBase):pass
+
+
\ No newline at end of file
diff --git a/pyforms/terminal/controls/ControlList.py b/pyforms/terminal/controls/ControlList.py
new file mode 100644
index 0000000..fd7443e
--- /dev/null
+++ b/pyforms/terminal/controls/ControlList.py
@@ -0,0 +1,208 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+""" pyforms.gui.Controls.ControlList
+
+"""
+import logging
+from pyforms.terminal.BaseWidget import BaseWidget
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+
+logger = logging.getLogger(__name__)
+
+
+class ControlList(ControlBase):
+ """ This class represents a wrapper to the table widget
+ It allows to implement a list view
+ """
+ def __init__(self, *args, **kwargs):
+ if 'default' not in kwargs: kwargs['default'] = []
+ super(ControlList, self).__init__(*args, **kwargs)
+
+
+ def clear(self, headers=False):
+ pass
+
+ def save_form(self, data, path=None):
+ if self.value:
+ rows = []
+ for row in range(self.rows_count):
+ columns = []
+ for column in range(self.columns_count):
+ v = self.get_value(column, row)
+ if isinstance(v, BaseWidget):
+ columns.append(v.save({}))
+ else:
+ columns.append(str(v))
+ rows.append(columns)
+ data['value'] = rows
+ return data
+
+ def load_form(self, data, path=None):
+ rows = data.get('value')
+
+ if self.value is not None and rows is not None:
+ for row_index in range(len(self.value)):
+ for column_index in range(len(self.value[row_index])):
+ v = self.get_value(column_index, row_index)
+
+ if isinstance(v, BaseWidget):
+ v.load_form(rows[row_index][column_index], path)
+ else:
+ self.value[row_index] = list(self.value[row_index])
+ self.value[row_index][column_index] = rows[row_index][column_index]
+ elif rows is not None:
+ self.value = rows
+
+ def __add__(self, other):
+ self._value.append(val)
+ return self
+ """
+ row_index = self.tableWidget.rowCount()
+
+ self.tableWidget.insertRow(row_index)
+
+ #increase the number of columns if necessary ####
+ if self.tableWidget.currentColumn() < len(other):
+ self.tableWidget.setColumnCount(len(other))
+ #################################################
+
+ for column, e in enumerate(other): self.set_value(column, row_index, e)
+
+ self.tableWidget.resizeColumnsToContents()
+
+ # auto scroll the list to the new inserted item ##################
+ if self.autoscroll:
+ self.tableWidget.scrollToItem( self.get_cell(0,row_index) )
+ ##################################################################
+ return self
+ """
+
+ def __sub__(self, other):
+ self._value.remove(other)
+ return self
+ """
+ if isinstance(other, int):
+ if other < 0:
+ indexToRemove = self.tableWidget.currentRow()
+ else:
+ indexToRemove = other
+
+ self.tableWidget.removeRow(indexToRemove)
+ return self
+ """
+
+ def set_value(self, column, row, value):
+ self.value[row][column] = value
+
+ def get_value(self, column, row):
+ return self.value[row][column]
+
+ def resize_rows_contents(self):
+ pass
+
+ def get_currentrow_value(self):
+ return None
+
+ def get_cell(self, column, row):
+ return None
+
+ def set_sorting_enabled(self, value):
+ pass
+
+ ##########################################################################
+ ############ EVENTS ######################################################
+ ##########################################################################
+
+ def data_changed_event(self, row, col, item):
+ pass
+
+ def item_selection_changed_event(self):
+ pass
+
+ def current_cell_changed_event(self, next_row, next_col, previous_row, previous_col):
+ pass
+
+ def current_item_changed_event(self, current, previous):
+ pass
+
+ def cell_double_clicked_event(self, row, column):
+ pass
+
+ ##########################################################################
+ ############ PROPERTIES ##################################################
+ ##########################################################################
+
+
+ @property
+ def horizontal_headers(self):
+ return self._horizontalHeaders
+
+ @horizontal_headers.setter
+ def horizontal_headers(self, horizontal_headers):
+ """Set horizontal headers in the table list."""
+
+ self._horizontalHeaders = horizontal_headers
+
+
+ @property
+ def word_wrap(self):
+ return True
+
+ @word_wrap.setter
+ def word_wrap(self, value):
+ pass
+
+ @property
+ def readonly(self):
+ return False
+
+ @readonly.setter
+ def readonly(self, value):
+ pass
+
+ @property
+ def select_entire_row(self):
+ pass
+
+ @select_entire_row.setter
+ def select_entire_row(self, value):
+ pass
+
+ @property
+ def rows_count(self):
+ return 0
+
+ @property
+ def columns_count(self):
+ return 0
+
+ def __len__(self):
+ return 0
+
+
+ # TODO: implement += on self.value? I want to add a list of tuples to
+ # self.value
+
+ @property
+ def selected_rows_indexes(self):
+ return None
+
+ @property
+ def selected_row_index(self):
+ pass
+
+ @property
+ def icon_size(self):
+ return 0
+
+ @icon_size.setter
+ def icon_size(self, value):
+ pass
+
+ @property
+ def autoscroll(self): return False
+ @autoscroll.setter
+ def autoscroll(self, value): pass
+
diff --git a/pyforms/terminal/Controls/ControlNumber.py b/pyforms/terminal/controls/ControlNumber.py
similarity index 86%
rename from pyforms/terminal/Controls/ControlNumber.py
rename to pyforms/terminal/controls/ControlNumber.py
index 8ea43b9..58c34ba 100644
--- a/pyforms/terminal/Controls/ControlNumber.py
+++ b/pyforms/terminal/controls/ControlNumber.py
@@ -1,4 +1,4 @@
-from pyforms.terminal.Controls.ControlBase import ControlBase
+from pyforms.terminal.controls.ControlBase import ControlBase
class ControlNumber(ControlBase):
diff --git a/pyforms/terminal/controls/ControlPlayer.py b/pyforms/terminal/controls/ControlPlayer.py
new file mode 100644
index 0000000..183eccd
--- /dev/null
+++ b/pyforms/terminal/controls/ControlPlayer.py
@@ -0,0 +1,146 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+from pyforms.utils.tools import groupImage
+import numpy, types
+
+
+import numpy as np
+try:
+ from StringIO import StringIO as BufferClass
+except ImportError:
+ from io import BytesIO as BufferClass
+
+
+try:
+ import cv2
+except:
+ print( "cv2 not present. ControlPlayer not working")
+
+
+try:
+ from PIL import Image
+except:
+ print( "PIL not present. ControlPlayer not working")
+
+
+try:
+ import base64
+except:
+ print( "base64 not present. ControlPlayer not working")
+
+
+
+
+class ControlPlayer(ControlBase):
+ _currentFrame = None
+ _min = 0
+ _max = 0
+ _filename = ''
+ _position = 0
+
+ def process_frame_event(self, frame): pass
+
+ def play(self): pass
+
+ def stop(self): pass
+
+ def refresh(self): pass
+
+ def update_frame(self): pass
+
+ def double_click_event(self, event, x, y): pass
+
+ def click_event(self, event, x, y): pass
+
+ def drag_event(self, start_point, end_point): pass
+
+ def end_drag_event(self, start_point, end_point): pass
+
+ def key_release_event(self, event): pass
+
+ def process_frame_event(self, frame): pass
+
+ def save_Form(self, data): pass
+
+ def load_form(self, data): pass
+
+ @property
+ def value(self):
+ result = {'min': self._min, 'max': self._max, 'position': self.video_index, 'frame': '', 'filename': self._filename }
+ capture = self._value
+
+ _, image = capture.read()
+ if isinstance(image, numpy.ndarray):
+ image = self.process_frame_event(image)
+
+ if isinstance(image, list) or isinstance(image, tuple):
+ image = groupImage(image, True)
+
+
+ if len(image.shape)>2: image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
+ image = Image.fromarray(image)
+ buff = BufferClass()
+ image.save(buff, format="PNG")
+ content = buff.getvalue()
+ buff.close()
+ result['frame'] = base64.b64encode(content)
+
+ return result
+
+ @value.setter
+ def value(self, value):
+ if value:
+ if isinstance( value, str ):
+ ControlBase.value.fset(self, cv2.VideoCapture( value ) )
+ self._filename = value
+ if isinstance( value, dict ):
+ ControlBase.value.fset(self, cv2.VideoCapture( value['filename'] ) )
+ if 'position' in value.keys(): self.video_index = int(value['position'])
+ self._filename = value['filename']
+
+ if isinstance(value,types.BuiltinFunctionType):
+ ControlBase.value.fset(self, value )
+
+ self._max = int(self._value.get(7))
+ else:
+ self._filename = None
+ self._value = None
+
+
+
+ @property
+ def video_index(self): return self._position
+
+ @video_index.setter
+ def video_index(self, value): self._position = value
+
+
+
+
+ @property
+ def image(self): return self._currentFrame
+
+ @image.setter
+ def image(self, value): pass
+
+
+
+
+
+ @property
+ def frame_width(self): return self._value.get(3)
+
+ @property
+ def frame_height(self): return self._value.get(4)
+
+ @property
+ def max(self): return int(self._value.get(7))
+
+ @property
+ def frame(self): return self._currentFrame
+
+ @property
+ def fps(self):
+ """
+ Return the video frames per second
+ """
+ return self._value.get(5)
diff --git a/pyforms/terminal/controls/ControlProgress.py b/pyforms/terminal/controls/ControlProgress.py
new file mode 100644
index 0000000..ca5094b
--- /dev/null
+++ b/pyforms/terminal/controls/ControlProgress.py
@@ -0,0 +1,37 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+from sys import stdout
+
+class ControlProgress(ControlBase):
+
+ _min = 0
+ _max = 100
+
+ def __init__(self, *args, **kwargs):
+ self._updateSlider = True
+ self._min = kwargs.get('min', kwargs.get('minimum', 0))
+ self._max = kwargs.get('max', kwargs.get('maximum', 100))
+ ControlBase.__init__(self, *args, **kwargs)
+
+
+ @property
+ def value(self): return self._value
+
+ @value.setter
+ def value(self, value):
+ #diff = self._max-self._min
+
+ if (value % 100 == 0):
+ stdout.write( '\rprogress {0}/{1}'.format(value-self._min, self._max) )
+ self._value = value
+
+ @property
+ def min(self): return self._min
+
+ @min.setter
+ def min(self, value): self._min = value
+
+ @property
+ def max(self): return self._max
+
+ @max.setter
+ def max(self, value): self._max = value
\ No newline at end of file
diff --git a/pyforms/terminal/controls/ControlSlider.py b/pyforms/terminal/controls/ControlSlider.py
new file mode 100644
index 0000000..ca5de38
--- /dev/null
+++ b/pyforms/terminal/controls/ControlSlider.py
@@ -0,0 +1,23 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlSlider(ControlBase):
+
+
+ def __init__(self, *args, **kwargs):
+ self._min = kwargs.get('minimum', 0)
+ self._max = kwargs.get('maximum', 100)
+ if 'default' not in kwargs: kwargs['default'] = 0
+ ControlBase.__init__(self, *args, **kwargs)
+
+
+ @property
+ def min(self): return self._min
+
+ @min.setter
+ def min(self, value): self._min = value
+
+ @property
+ def max(self): return self._max
+
+ @max.setter
+ def max(self, value): self._max = value
\ No newline at end of file
diff --git a/pyforms/terminal/controls/ControlText.py b/pyforms/terminal/controls/ControlText.py
new file mode 100644
index 0000000..c3b76cb
--- /dev/null
+++ b/pyforms/terminal/controls/ControlText.py
@@ -0,0 +1,5 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlText(ControlBase):pass
+
+
\ No newline at end of file
diff --git a/pyforms/terminal/controls/ControlTextArea.py b/pyforms/terminal/controls/ControlTextArea.py
new file mode 100644
index 0000000..e1d5d3f
--- /dev/null
+++ b/pyforms/terminal/controls/ControlTextArea.py
@@ -0,0 +1,5 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlTextArea(ControlBase):pass
+
+
\ No newline at end of file
diff --git a/pyforms/terminal/controls/ControlToolBox.py b/pyforms/terminal/controls/ControlToolBox.py
new file mode 100644
index 0000000..412d2a6
--- /dev/null
+++ b/pyforms/terminal/controls/ControlToolBox.py
@@ -0,0 +1,5 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlToolBox(ControlBase):pass
+
+
\ No newline at end of file
diff --git a/pyforms/terminal/controls/ControlTree.py b/pyforms/terminal/controls/ControlTree.py
new file mode 100644
index 0000000..a3d50d4
--- /dev/null
+++ b/pyforms/terminal/controls/ControlTree.py
@@ -0,0 +1,5 @@
+from pyforms.terminal.controls.ControlBase import ControlBase
+
+class ControlTree(ControlBase):pass
+
+
\ No newline at end of file
diff --git a/pyforms/terminal/Controls/__init__.py b/pyforms/terminal/controls/__init__.py
similarity index 100%
rename from pyforms/terminal/Controls/__init__.py
rename to pyforms/terminal/controls/__init__.py
diff --git a/pyforms/utils/__init__.py b/pyforms/utils/__init__.py
old mode 100755
new mode 100644
diff --git a/pyforms/utils/make_lambda.py b/pyforms/utils/make_lambda.py
new file mode 100644
index 0000000..fab247b
--- /dev/null
+++ b/pyforms/utils/make_lambda.py
@@ -0,0 +1,5 @@
+
+
+def make_lambda_func(func, **kwargs):
+ """ Auxiliar function for passing parameters to functions """
+ return lambda: func(**kwargs)
\ No newline at end of file
diff --git a/pyforms/utils/plugins_finder.py b/pyforms/utils/plugins_finder.py
index 8b0a9ed..67d7605 100644
--- a/pyforms/utils/plugins_finder.py
+++ b/pyforms/utils/plugins_finder.py
@@ -3,7 +3,7 @@
import re
import logging
-from pysettings import conf
+from pyforms.utils.settings_manager import conf
logger = logging.getLogger(__name__)
@@ -40,19 +40,21 @@ def find_class(self, class_full_name):
class_name = values[-1]
module_name = ('.' + '.'.join(values[:-1])) if len(values) > 1 else ''
module = __import__(plugin + module_name, fromlist=[''])
- class_def = getattr(module, class_name)
- res.append(class_def)
+ try:
+ class_def = getattr(module, class_name)
+ res.append(class_def)
+ except AttributeError:
+ if not conf.PYFORMS_SILENT_PLUGINS_FINDER:
+ logger.error('Error importing model {0} {1} {2}'.format(str(plugin), str(package_name), str(class_name)), exc_info=True)
+
except ImportError:
if not conf.PYFORMS_SILENT_PLUGINS_FINDER:
- logger.error(
- 'Error importing model {0} {1} {2}'.format(str(plugin), str(package_name), str(class_name)),
- exc_info=True)
- pass
+ logger.error('Error importing model {0} {1} {2}'.format(str(plugin), str(package_name), str(class_name)), exc_info=True)
+
except:
- if not conf.PYFORMS_SILENT_PLUGINS_FINDER:
- logger.error(
- 'Error importing model {0} {1} {2}'.format(str(plugin), str(package_name), str(class_name)),
- exc_info=True)
+ logger.error(
+ 'Error importing model {0} {1} {2}'.format(str(plugin), str(package_name), str(class_name)),
+ exc_info=True)
pass
return res
diff --git a/pyforms/utils/settings_manager.py b/pyforms/utils/settings_manager.py
new file mode 100644
index 0000000..3ede4d2
--- /dev/null
+++ b/pyforms/utils/settings_manager.py
@@ -0,0 +1,42 @@
+
+import logging; logger = logging.getLogger(__name__)
+
+class SettingsManager(object):
+
+ def __init__(self):
+ self._modules = []
+ self._loaded_modules = {}
+
+ def __load_module(self, module_name):
+ if module_name in self._loaded_modules.keys(): return self._loaded_modules[module_name]
+
+ modules = module_name.split('.')
+ moduleclass = __import__( '.'.join(modules[:-1]) , fromlist=[modules[-1]] )
+
+ module = getattr(moduleclass, modules[-1])
+ self._loaded_modules[module_name] = module
+
+ return module
+
+ def __add__(self, other):
+ if isinstance(other, str): other = self.__load_module(other)
+
+ modules = object.__getattribute__(self, '_modules')
+ if other not in modules:
+ logger.info('added settings: {0}'.format(other.__name__))
+ modules.append(other)
+ self._modules = sorted(modules, key=lambda x: (x.SETTINGS_PRIORITY if hasattr(x, 'SETTINGS_PRIORITY') else 999999999) )
+ return self
+
+ def __sub__(self, other):
+ self._modules.remove(other)
+ return self
+
+ def __getattribute__(self, name):
+ for module in object.__getattribute__(self, '_modules'):
+ if hasattr(module, name): return getattr(module, name)
+
+ return object.__getattribute__(self, name)
+
+
+conf = SettingsManager()
\ No newline at end of file
diff --git a/pyforms/utils/timeit.py b/pyforms/utils/timeit.py
index 6e780b1..2ea1eac 100755
--- a/pyforms/utils/timeit.py
+++ b/pyforms/utils/timeit.py
@@ -12,14 +12,14 @@
import time
-from datetime import datetime, timedelta
+from datetime import datetime as datetime_dt, timedelta
def timeit(method):
def timed(*args, **kw):
ts = time.time()
result = method(*args, **kw)
te = time.time()
- time_elapsed = datetime(1,1,1) + timedelta(seconds=(te-ts) )
+ time_elapsed = datetime_dt(1,1,1) + timedelta(seconds=(te-ts) )
print("%s: %d:%d:%d:%d;%d" % (method.__name__, time_elapsed.day-1, time_elapsed.hour, time_elapsed.minute, time_elapsed.second, time_elapsed.microsecond))
return result
return timed
\ No newline at end of file
diff --git a/setup.py b/setup.py
index b4bb60b..d2ddd72 100644
--- a/setup.py
+++ b/setup.py
@@ -6,35 +6,32 @@
version = ''
with open('pyforms/__init__.py', 'r') as fd: version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
- fd.read(), re.MULTILINE).group(1)
+ fd.read(), re.MULTILINE).group(1)
if not version: raise RuntimeError('Cannot find version information')
setup(
name='PyForms',
version=version,
- description="""Pyforms is a Python 2.7 and 3.4 framework to develop GUI application,
- which promotes modular software design and code reusability with minimal effort.""",
+ description="""Pyforms is a Python 2.7 and 3.4 framework to develop GUI applications based on pyqt""",
author='Ricardo Ribeiro',
author_email='ricardojvr@gmail.com',
license='MIT',
url='https://github.com/UmSenhorQualquer/pyforms',
-
- packages=[
- 'pyforms',
- 'pyforms.utils',
- 'pyforms.terminal',
- 'pyforms.terminal.Controls',
- 'pyforms.gui',
- 'pyforms.gui.dialogs',
- 'pyforms.gui.Controls',
- 'pyforms.gui.Controls.ControlEventTimeline',
- 'pyforms.gui.Controls.ControlEventsGraph',
- 'pyforms.gui.Controls.ControlPlayer'],
-
+ install_requires=[
+ 'anyqt',
+ 'pyqt5',
+ 'pyopengl',
+ 'QScintilla',
+ 'visvis',
+ 'matplotlib',
+ 'python-dateutil',
+ 'numpy'
+ ],
+ packages=find_packages(),
package_data={'pyforms': [
- 'gui/Controls/uipics/*.png',
- 'gui/mainWindow.ui', 'gui/Controls/*.ui', 'gui/Controls/ControlPlayer/*.ui',
- 'gui/Controls/ControlEventTimeline/*.ui']
+ 'gui/controls/uipics/*.png',
+ 'gui/mainWindow.ui', 'gui/controls/*.ui', 'gui/controls/control_player/*.ui',
+ 'gui/controls/control_event_timeline/*.ui']
},
)
diff --git a/tutorials/1.SimpleExamples/ComputerVisionAlgorithmExample/Example.py b/tutorials/1.SimpleExamples/ComputerVisionAlgorithmExample/Example.py
index 2e5ae24..ba5265e 100644
--- a/tutorials/1.SimpleExamples/ComputerVisionAlgorithmExample/Example.py
+++ b/tutorials/1.SimpleExamples/ComputerVisionAlgorithmExample/Example.py
@@ -20,8 +20,8 @@ def __init__(self):
#Definition of the forms fields
self._videofile = ControlFile('Video')
self._outputfile = ControlText('Results output file')
- self._threshold = ControlSlider('Threshold', 114, 0,255)
- self._blobsize = ControlSlider('Minimum blob size', 100, 100,2000)
+ self._threshold = ControlSlider('Threshold', default=114, 0,255)
+ self._blobsize = ControlSlider('Minimum blob size', default=100, 100,2000)
self._player = ControlPlayer('Player')
self._runbutton = ControlButton('Run')
@@ -30,7 +30,7 @@ def __init__(self):
#Define the event that will be called when the run button is processed
self._runbutton.value = self.__runEvent
#Define the event called before showing the image in the player
- self._player.processFrame = self.__processFrame
+ self._player.process_frame_event = self.__process_frame
#Define the organization of the Form Controls
self.formset = [
@@ -47,7 +47,7 @@ def __videoFileSelectionEvent(self):
"""
self._player.value = self._videofile.value
- def __processFrame(self, frame):
+ def __process_frame(self, frame):
"""
Do some processing to the frame and return the result frame
"""
diff --git a/tutorials/1.SimpleExamples/ComputerVisionAlgorithmExample/__init__.py b/tutorials/1.SimpleExamples/ComputerVisionAlgorithmExample/__init__.py
index 0ca0ca9..31685a5 100644
--- a/tutorials/1.SimpleExamples/ComputerVisionAlgorithmExample/__init__.py
+++ b/tutorials/1.SimpleExamples/ComputerVisionAlgorithmExample/__init__.py
@@ -11,10 +11,10 @@
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlSlider
-from pyforms.Controls import ControlFile
-from pyforms.Controls import ControlPlayer
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlSlider
+from pyforms.controls import ControlFile
+from pyforms.controls import ControlPlayer
import pyforms
\ No newline at end of file
diff --git a/tutorials/1.SimpleExamples/SimpleExample1/__init__.py b/tutorials/1.SimpleExamples/SimpleExample1/__init__.py
index a543081..540aab2 100644
--- a/tutorials/1.SimpleExamples/SimpleExample1/__init__.py
+++ b/tutorials/1.SimpleExamples/SimpleExample1/__init__.py
@@ -11,7 +11,7 @@
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlMatplotlib
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlMatplotlib
import pyforms
\ No newline at end of file
diff --git a/tutorials/1.SimpleExamples/SimpleExample2/__init__.py b/tutorials/1.SimpleExamples/SimpleExample2/__init__.py
index b36dd67..6725787 100644
--- a/tutorials/1.SimpleExamples/SimpleExample2/__init__.py
+++ b/tutorials/1.SimpleExamples/SimpleExample2/__init__.py
@@ -10,7 +10,7 @@
__status__ = "Development"
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
import pyforms
\ No newline at end of file
diff --git a/tutorials/1.SimpleExamples/SimpleExample3/__init__.py b/tutorials/1.SimpleExamples/SimpleExample3/__init__.py
index 60246a6..274f2e3 100644
--- a/tutorials/1.SimpleExamples/SimpleExample3/__init__.py
+++ b/tutorials/1.SimpleExamples/SimpleExample3/__init__.py
@@ -1,6 +1,6 @@
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
import pyforms
\ No newline at end of file
diff --git a/tutorials/1.SimpleExamples/SimpleExample4/__init__.py b/tutorials/1.SimpleExamples/SimpleExample4/__init__.py
index 60246a6..274f2e3 100644
--- a/tutorials/1.SimpleExamples/SimpleExample4/__init__.py
+++ b/tutorials/1.SimpleExamples/SimpleExample4/__init__.py
@@ -1,6 +1,6 @@
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
import pyforms
\ No newline at end of file
diff --git a/tutorials/1.SimpleExamples/SimpleExample5/__init__.py b/tutorials/1.SimpleExamples/SimpleExample5/__init__.py
index 60246a6..274f2e3 100644
--- a/tutorials/1.SimpleExamples/SimpleExample5/__init__.py
+++ b/tutorials/1.SimpleExamples/SimpleExample5/__init__.py
@@ -1,6 +1,6 @@
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
import pyforms
\ No newline at end of file
diff --git a/tutorials/1.SimpleExamples/SimpleExample6/__init__.py b/tutorials/1.SimpleExamples/SimpleExample6/__init__.py
index c093436..486a386 100644
--- a/tutorials/1.SimpleExamples/SimpleExample6/__init__.py
+++ b/tutorials/1.SimpleExamples/SimpleExample6/__init__.py
@@ -1,6 +1,6 @@
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
import pyforms
\ No newline at end of file
diff --git a/tutorials/2.ControlsExamples/__init__.py b/tutorials/2.ControlsExamples/__init__.py
index 32d5a79..7717b87 100644
--- a/tutorials/2.ControlsExamples/__init__.py
+++ b/tutorials/2.ControlsExamples/__init__.py
@@ -10,25 +10,25 @@
__status__ = "Development"
from pyforms import BaseWidget
-from pyforms.Controls import ControlBoundingSlider
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlCheckBox
-from pyforms.Controls import ControlCheckBoxList
-from pyforms.Controls import ControlCombo
-from pyforms.Controls import ControlDir
-from pyforms.Controls import ControlDockWidget
-from pyforms.Controls import ControlEmptyWidget
-from pyforms.Controls import ControlFile
-from pyforms.Controls import ControlFilesTree
-from pyforms.Controls import ControlImage
-from pyforms.Controls import ControlList
-from pyforms.Controls import ControlPlayer
-from pyforms.Controls import ControlProgress
-from pyforms.Controls import ControlSlider
-from pyforms.Controls import ControlVisVis
-from pyforms.Controls import ControlVisVisVolume
-from pyforms.Controls import ControlEventTimeline
-from pyforms.Controls import ControlCodeEditor
+from pyforms.controls import ControlBoundingSlider
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlCheckBox
+from pyforms.controls import ControlCheckBoxList
+from pyforms.controls import ControlCombo
+from pyforms.controls import ControlDir
+from pyforms.controls import ControlDockWidget
+from pyforms.controls import ControlEmptyWidget
+from pyforms.controls import ControlFile
+from pyforms.controls import ControlFilesTree
+from pyforms.controls import ControlImage
+from pyforms.controls import ControlList
+from pyforms.controls import ControlPlayer
+from pyforms.controls import ControlProgress
+from pyforms.controls import ControlSlider
+from pyforms.controls import ControlVisVis
+from pyforms.controls import ControlVisVisVolume
+from pyforms.controls import ControlEventTimeline
+from pyforms.controls import ControlCodeEditor
import pyforms
\ No newline at end of file
diff --git a/tutorials/3.CodeOrganization/AddMenuFuntionality.py b/tutorials/3.CodeOrganization/AddMenuFuntionality.py
index d83b09e..9a6c595 100644
--- a/tutorials/3.CodeOrganization/AddMenuFuntionality.py
+++ b/tutorials/3.CodeOrganization/AddMenuFuntionality.py
@@ -23,7 +23,7 @@ def __init__(self):
def __savePeople(self):
- filename = QtGui.QFileDialog.getSaveFileName(parent=self,
+ filename, _ = QtGui.QFileDialog.getSaveFileName(parent=self,
caption="Save file",
directory=".",
filter="*.dat")
@@ -31,7 +31,7 @@ def __savePeople(self):
if filename!=None and filename!='': self.save(filename)
def __loadPeople(self):
- filename = QtGui.QFileDialog.getOpenFileName(parent=self,
+ filename, _ = QtGui.QFileDialog.getOpenFileName(parent=self,
caption="Import file",
directory=".",
filter="*.dat")
diff --git a/tutorials/3.CodeOrganization/PeopleWindow.py b/tutorials/3.CodeOrganization/PeopleWindow.py
index 1854124..913d10f 100644
--- a/tutorials/3.CodeOrganization/PeopleWindow.py
+++ b/tutorials/3.CodeOrganization/PeopleWindow.py
@@ -3,7 +3,7 @@
from PersonWindow import PersonWindow
from AddMenuFuntionality import AddMenuFuntionality
-from pyforms.Controls import ControlDockWidget
+from pyforms.controls import ControlDockWidget
class PeopleWindow(AddMenuFuntionality, People, BaseWidget):
diff --git a/tutorials/3.CodeOrganization/PersonWindow.py b/tutorials/3.CodeOrganization/PersonWindow.py
index 4b98edc..8301246 100644
--- a/tutorials/3.CodeOrganization/PersonWindow.py
+++ b/tutorials/3.CodeOrganization/PersonWindow.py
@@ -1,11 +1,11 @@
-from pysettings import conf;
+from pyforms.utils.settings_manager import conf;
import settings
conf+=settings
import pyforms
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
from Person import Person
diff --git a/tutorials/3.CodeOrganization/__init__.py b/tutorials/3.CodeOrganization/__init__.py
index 5ff2a7b..e712839 100644
--- a/tutorials/3.CodeOrganization/__init__.py
+++ b/tutorials/3.CodeOrganization/__init__.py
@@ -11,9 +11,9 @@
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlList
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlList
import pyforms
diff --git a/tutorials/4.MdiApplication/Core/BaseWindow.py b/tutorials/4.MdiApplication/Core/BaseWindow.py
index 78425ed..eb2cdac 100644
--- a/tutorials/4.MdiApplication/Core/BaseWindow.py
+++ b/tutorials/4.MdiApplication/Core/BaseWindow.py
@@ -1,10 +1,10 @@
import pyforms
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlDockWidget
-from pyforms.Controls import ControlMdiArea
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlDockWidget
+from pyforms.controls import ControlMdiArea
from Core.SimpleExample1 import SimpleExample1
from Core.Controllers.ProjectTree import ProjectTree
diff --git a/tutorials/4.MdiApplication/Core/Controllers/ProjectTree.py b/tutorials/4.MdiApplication/Core/Controllers/ProjectTree.py
index c0a7a56..1b1aa28 100644
--- a/tutorials/4.MdiApplication/Core/Controllers/ProjectTree.py
+++ b/tutorials/4.MdiApplication/Core/Controllers/ProjectTree.py
@@ -3,9 +3,9 @@
from PyQt4 import QtGui, QtCore
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
-from pyforms.Controls import ControlTree
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
+from pyforms.controls import ControlTree
class ProjectTree(BaseWidget):
diff --git a/tutorials/4.MdiApplication/Core/SimpleExample1.py b/tutorials/4.MdiApplication/Core/SimpleExample1.py
index f162d2e..4bc0078 100644
--- a/tutorials/4.MdiApplication/Core/SimpleExample1.py
+++ b/tutorials/4.MdiApplication/Core/SimpleExample1.py
@@ -12,8 +12,8 @@
from pyforms import BaseWidget
-from pyforms.Controls import ControlText
-from pyforms.Controls import ControlButton
+from pyforms.controls import ControlText
+from pyforms.controls import ControlButton
diff --git a/tutorials/Controls4Docs/__init__.py b/tutorials/Controls4Docs/__init__.py
index a0df076..fa42181 100644
--- a/tutorials/Controls4Docs/__init__.py
+++ b/tutorials/Controls4Docs/__init__.py
@@ -11,5 +11,5 @@
from pyforms import BaseWidget
-from pyforms.Controls import *
+from pyforms.controls import *
import pyforms
\ No newline at end of file