Skip to content

Commit

Permalink
gui/moninj: flow layout
Browse files Browse the repository at this point in the history
sbourdeauducq committed Mar 17, 2016
1 parent 633bbc4 commit f739341
Showing 2 changed files with 146 additions and 4 deletions.
131 changes: 131 additions & 0 deletions artiq/gui/flowlayout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#############################################################################
##
## Copyright (C) 2013 Riverbank Computing Limited.
## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
## All rights reserved.
##
## This file is part of the examples of PyQt.
##
## $QT_BEGIN_LICENSE:BSD$
## You may use this file under the terms of the BSD license as follows:
##
## "Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions are
## met:
## * Redistributions of source code must retain the above copyright
## notice, this list of conditions and the following disclaimer.
## * Redistributions in binary form must reproduce the above copyright
## notice, this list of conditions and the following disclaimer in
## the documentation and/or other materials provided with the
## distribution.
## * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
## the names of its contributors may be used to endorse or promote
## products derived from this software without specific prior written
## permission.
##
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
## $QT_END_LICENSE$
##
#############################################################################


from PyQt5.QtCore import QPoint, QRect, QSize, Qt
from PyQt5.QtWidgets import (QApplication, QLayout, QPushButton, QSizePolicy,
QWidget)


class FlowLayout(QLayout):
def __init__(self, parent=None, margin=0, spacing=-1):
super(FlowLayout, self).__init__(parent)

if parent is not None:
self.setContentsMargins(margin, margin, margin, margin)

self.setSpacing(spacing)

self.itemList = []

def __del__(self):
item = self.takeAt(0)
while item:
item = self.takeAt(0)

def addItem(self, item):
self.itemList.append(item)

def count(self):
return len(self.itemList)

def itemAt(self, index):
if index >= 0 and index < len(self.itemList):
return self.itemList[index]

return None

def takeAt(self, index):
if index >= 0 and index < len(self.itemList):
return self.itemList.pop(index)

return None

def expandingDirections(self):
return Qt.Orientations(Qt.Orientation(0))

def hasHeightForWidth(self):
return True

def heightForWidth(self, width):
height = self.doLayout(QRect(0, 0, width, 0), True)
return height

def setGeometry(self, rect):
super(FlowLayout, self).setGeometry(rect)
self.doLayout(rect, False)

def sizeHint(self):
return self.minimumSize()

def minimumSize(self):
size = QSize()

for item in self.itemList:
size = size.expandedTo(item.minimumSize())

margin, _, _, _ = self.getContentsMargins()

size += QSize(2 * margin, 2 * margin)
return size

def doLayout(self, rect, testOnly):
x = rect.x()
y = rect.y()
lineHeight = 0

for item in self.itemList:
wid = item.widget()
spaceX = self.spacing() + wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Horizontal)
spaceY = self.spacing() + wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical)
nextX = x + item.sizeHint().width() + spaceX
if nextX - spaceX > rect.right() and lineHeight > 0:
x = rect.x()
y = y + lineHeight + spaceY
nextX = x + item.sizeHint().width() + spaceX
lineHeight = 0

if not testOnly:
item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))

x = nextX
lineHeight = max(lineHeight, item.sizeHint().height())

return y + lineHeight - rect.y()
19 changes: 15 additions & 4 deletions artiq/gui/moninj.py
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@

from artiq.tools import TaskObject
from artiq.protocols.sync_struct import Subscriber
from artiq.gui.flowlayout import FlowLayout


logger = logging.getLogger(__name__)
@@ -20,6 +21,8 @@
"in": 3
}

_widget_size = QtCore.QSize(350, 300)


class _TTLWidget(QtWidgets.QFrame):
def __init__(self, channel, send_to_device, force_out, title):
@@ -28,6 +31,7 @@ def __init__(self, channel, send_to_device, force_out, title):
self.force_out = force_out

QtWidgets.QFrame.__init__(self)
self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)

self.setFrameShape(QtWidgets.QFrame.Box)
self.setFrameShadow(QtWidgets.QFrame.Raised)
@@ -85,6 +89,9 @@ def __init__(self, channel, send_to_device, force_out, title):

self.set_value(0, False, False)

def sizeHint(self):
return _widget_size

def set_mode(self, mode):
data = struct.pack("bbb",
2, # MONINJ_REQ_TTLSET
@@ -124,6 +131,7 @@ def __init__(self, bus_channel, channel, sysclk, title):
self.sysclk = sysclk

QtWidgets.QFrame.__init__(self)
self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)

self.setFrameShape(QtWidgets.QFrame.Box)
self.setFrameShadow(QtWidgets.QFrame.Raised)
@@ -146,6 +154,9 @@ def __init__(self, bus_channel, channel, sysclk, title):

self.set_value(0)

def sizeHint(self):
return _widget_size

def set_value(self, ftw):
frequency = ftw*self.sysclk()/2**32
self._value.setText("<font size=\"6\">{:.7f} MHz</font>"
@@ -232,14 +243,14 @@ def layout_widgets(self, widgets):
scroll_area = QtWidgets.QScrollArea()
self.setWidget(scroll_area)

grid = QtWidgets.QGridLayout()
grid = FlowLayout()
grid_widget = QtWidgets.QWidget()
grid_widget.setLayout(grid)

for i, (_, w) in enumerate(sorted(widgets, key=itemgetter(0))):
grid.addWidget(w, i // 4, i % 4)
grid.setColumnStretch(i % 4, 1)
for _, w in sorted(widgets, key=itemgetter(0)):
grid.addWidget(w)

scroll_area.setWidgetResizable(True)
scroll_area.setWidget(grid_widget)


0 comments on commit f739341

Please sign in to comment.