def temp_setup(self): """ Description ------------- - Temporary function to setup some Qt GUI functionality for proof-of-concept testing. """ monitor = QApplication.desktop().geometry() # TODO: Remove these buttons once you're done testing and showing proof-of-concept up_button = QPushButton("UP", self) down_button = QPushButton("DOWN", self) left_button = QPushButton("LEFT", self) right_button = QPushButton("RIGHT", self) up_button.move(self.board_width, monitor.height() / 3 - up_button.height()) down_button.move(self.board_width, monitor.height() / 3 - (up_button.height() * 2)) left_button.move(self.board_width, monitor.height() / 3 - (up_button.height() * 3)) right_button.move(self.board_width, monitor.height() / 3 - (up_button.height() * 4)) self.connect(up_button, SIGNAL("clicked()"), partial(self.get_direction, "UP")) self.connect(down_button, SIGNAL("clicked()"), partial(self.get_direction, "DOWN")) self.connect(left_button, SIGNAL("clicked()"), partial(self.get_direction, "LEFT")) self.connect(right_button, SIGNAL("clicked()"), partial(self.get_direction, "RIGHT")) get_dice_amount_button = QPushButton("Move Player", self) get_dice_amount_button.move(self.board_width, monitor.height() / 3) get_dice_amount_button.clicked.connect(self.get_dice_amount) get_dice_amount_button.show() reset_player_button = QPushButton("Reset", self) reset_player_button.move( get_dice_amount_button.x() + get_dice_amount_button.width(), get_dice_amount_button.y() + get_dice_amount_button.height()) reset_player_button.clicked.connect(self.reset_player) reset_player_button.show() self.dice_text_field = QTextEdit("<Enter Dice Amount>", self) self.dice_text_field.move(self.board_width + 100, monitor.height() / 3) self.dice_text_field.show() roll_dice_button = QPushButton("Roll & Move", self) roll_dice_button.move(self.board_width, monitor.height() / 3 - (up_button.height() * 5)) roll_dice_button.clicked.connect(self.roll_dice) roll_dice_button.show() self.initialize_player_tokens() self.initialize_dice() self.layout().addChildWidget(self.player_widget) self.layout().addChildWidget(self.dice_widget)
class FieldNameListEditor(QWidget): """A widget to edit foreign keys' field name lists.""" data_committed = Signal(name="data_committed") def __init__(self, parent, option, index): """Initialize class.""" super().__init__(parent) layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.model = MinimalTableModel(self) self.model.flags = self.model_flags self.view = QTableView(self) self.view.setModel(self.model) self.view.verticalHeader().hide() self.view.horizontalHeader().hide() self.view.setShowGrid(False) check_box_delegate = CheckBoxDelegate(self) self.view.setItemDelegateForColumn(0, check_box_delegate) check_box_delegate.data_committed.connect( self._handle_check_box_data_committed) self.button = QPushButton("Ok", self) self.button.setFlat(True) self.view.verticalHeader().setDefaultSectionSize(option.rect.height()) self.button.setFixedHeight(option.rect.height()) layout.addWidget(self.view) layout.addWidget(self.button) self.button.clicked.connect(self._handle_ok_button_clicked) self.setWindowFlags(Qt.FramelessWindowHint | Qt.Popup) x_offset = parent.parent().columnViewportPosition(index.column()) y_offset = parent.parent().rowViewportPosition(index.row()) self.position = parent.mapToGlobal(QPoint(0, 0)) + QPoint( x_offset, y_offset) def model_flags(self, index): """Return index flags.""" if not index.isValid(): return Qt.NoItemFlags if index.column() != 0: return ~Qt.ItemIsEditable return Qt.ItemIsEditable @Slot("QModelIndex", name="_handle_check_box_data_committed") def _handle_check_box_data_committed(self, index): """Called when checkbox delegate wants to edit data. Toggle the index's value.""" data = index.data(Qt.EditRole) self.model.setData(index, not data) @Slot("bool", name="_handle_ok_button_clicked") def _handle_ok_button_clicked(self, checked=False): """Called when user pressed Ok.""" self.data_committed.emit() def set_data(self, field_names, current_field_names): """Set values to show in the 'menu'. Reset model using those values and update geometry.""" data = [[name in current_field_names, name] for name in field_names] self.model.reset_model(data) self.view.resizeColumnsToContents() width = self.view.horizontalHeader().length() + qApp.style( ).pixelMetric(QStyle.PM_ScrollBarExtent) self.setFixedWidth(width + 2) height = self.view.verticalHeader().length() + self.button.height() parent_height = self.parent().height() self.setFixedHeight(min(height, parent_height / 2) + 2) self.move(self.position) def data(self): return ",".join( [name for checked, name in self.model._main_data if checked])
class LoadingBar(QWidget): def __init__(self, parent, fn, *args): super(LoadingBar, self).__init__(parent) self.fn = fn self.args = args self.worker = Worker(fn, *args) self.worker.signals.result.connect( main_window.MainWindow.get_instance().calc_done) main_window.MainWindow.get_instance().threadpool.start(self.worker) # overlay # make the window frameless self.loading_icon = QSvgRenderer('resources/images/loading_icon.svg') self.qp = QPainter() self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground) self.fillColor = QColor(30, 30, 30, 120) self.penColor = QColor("#333333") self.close_btn = QPushButton(self) self.close_btn.setText("Abbrechen") font = QFont() font.setPixelSize(18) font.setBold(True) self.close_btn.setFont(font) self.close_btn.setStyleSheet("QPushButton {" "background-color: #EAEAEA;" "border: None;" "padding-top: 12px;" "padding-bottom: 12px;" "padding-left: 20px;" "padding-right: 20px;" "}" "QPushButton:hover {" "background-color: #DFDFDF;" "}") #self.close_btn.setFixedSize(30, 30) self.close_btn.clicked.connect(self._onclose) self.signals = LoadingBarSignals() def resizeEvent(self, event=None): button_x = (self.width() - self.close_btn.width()) / 2 button_y = (self.height() - self.close_btn.height()) / 2 + 60 self.close_btn.move(button_x, button_y) def paintEvent(self, event): # This method is, in practice, drawing the contents of # your window. # get current window size s = self.size() self.qp.begin(self) self.qp.setRenderHint(QPainter.Antialiasing, True) self.qp.setPen(self.penColor) self.qp.setBrush(self.fillColor) self.qp.drawRect(0, 0, s.width(), s.height()) icon_size = 180 self.loading_icon.render( self.qp, QRect((self.width() - icon_size) / 2, (self.height() - icon_size) / 2 - 60, icon_size, icon_size)) self.qp.end() def _onclose(self): self.signals.close.emit()
class AutoFilterWidget(QWidget): """A widget to show the auto filter 'menu'.""" def __init__(self, parent): """Initialize class.""" super().__init__(parent) layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.model = MinimalTableModel(self) self.model.flags = self.model_flags self.view = QTableView(self) self.view.setModel(self.model) self.view.verticalHeader().hide() self.view.horizontalHeader().hide() self.view.setShowGrid(False) check_box_delegate = CheckBoxDelegate(self) self.view.setItemDelegateForColumn(0, check_box_delegate) check_box_delegate.data_committed.connect( self._handle_check_box_data_committed) self.button = QPushButton("Ok", self) self.button.setFlat(True) layout.addWidget(self.view) layout.addWidget(self.button) self.button.clicked.connect(self.hide) self.hide() self.setWindowFlags(Qt.FramelessWindowHint | Qt.Popup) def model_flags(self, index): """Return index flags.""" if not index.isValid(): return Qt.NoItemFlags if index.column() == 1: return ~Qt.ItemIsEditable return Qt.ItemIsEditable @Slot("QModelIndex", name="_handle_check_box_data_committed") def _handle_check_box_data_committed(self, index): """Called when checkbox delegate wants to edit data. Toggle the index's value.""" data = index.data(Qt.EditRole) model_data = self.model._main_data row_count = self.model.rowCount() if index.row() == 0: # Ok row value = data in (None, False) for row in range(row_count): model_data[row][0] = value self.model.dataChanged.emit(self.model.index(0, 0), self.model.index(row_count - 1, 0)) else: # Data row self.model.setData(index, not data) self.set_ok_index_data() def set_ok_index_data(self): """Set data for ok index based on data from all other indexes.""" ok_index = self.model.index(0, 0) true_count = 0 for row_data in self.model._main_data[1:]: if row_data[0] == True: true_count += 1 if true_count == len(self.model._main_data) - 1: self.model.setData(ok_index, True) elif true_count == 0: self.model.setData(ok_index, False) else: self.model.setData(ok_index, None) def set_values(self, values): """Set values to show in the 'menu'. Reset model using those values and update geometry.""" self.model.reset_model([[None, "All"]] + values) self.set_ok_index_data() self.view.horizontalHeader().hideSection( 2) # Column 2 holds internal data (cls_id_set) self.view.resizeColumnsToContents() width = self.view.horizontalHeader().length() + qApp.style( ).pixelMetric(QStyle.PM_ScrollBarExtent) self.setFixedWidth(width + 2) height = self.view.verticalHeader().length() + self.button.height() parent_height = self.parent().height() self.setFixedHeight(min(height, parent_height / 2) + 2) def set_section_height(self, height): """Set vertical header default section size as well as button height.""" self.view.verticalHeader().setDefaultSectionSize(height) self.button.setFixedHeight(height)
class MapWidget(QQuickWidget): def __init__(self, data, model): super(MapWidget, self).__init__(resizeMode=QQuickWidget.SizeRootObjectToView) self.data = data self.model = model self.attribute_button = QPushButton(self) self.attribute_button.setStyleSheet("color: black") self.menu = QMenu("Pick an attribute", self) # Create Menu Options self.humidity_attribute = QAction("humidity") self.pressure_attribute = QAction("pressure") self.temperature_attribute = QAction("temperature") self.wind_speed_attribute = QAction("wind_speed") # due to frequent access of dates based on index, we store this data separately self.uniqueDates = self.data["datetime"].apply( lambda x: x.split(' ')[0]).unique().tolist() self.aggregation = 1 self.rootContext().setContextProperty("markermodel", model) self.rootContext().setContextProperty("MapWidget", self) qml_path = os.path.join(os.path.dirname(__file__), "map.qml") self.setSource(QUrl.fromLocalFile(qml_path)) positions = self.get_positions(self.data) names = self.get_names(self.data) # get first date of dataset in yy-mm-dd self.currentDate = self.uniqueDates[0] # Set Labels self.date_label = QLabel( "selected date: " + str(self.currentDate).replace("-", "."), self) self.date_label.setStyleSheet("color: black") # Set Previous and Next Buttons self.previous_button = QPushButton("Previous", self) self.next_button = QPushButton("Next", self) self.previous_button.clicked.connect( partial(self.on_button_clicked, "previous")) self.next_button.clicked.connect( partial(self.on_button_clicked, "next")) values = self.get_values(self.data, "humidity") colors = self.get_colors(self.data, "humidity") for i in range(0, len(names)): geo_coordinates = QGeoCoordinate(positions[i][0], positions[i][1]) name = names[i] value = values[i] color = colors[i] model.append_marker({ "position": geo_coordinates, "color": color, "name": name, "value": value, "date": self.currentDate }) self.create_interface() return def add_attribute_to_menu(self, attribute_action, attribute): attribute_action.triggered.connect(lambda: self.clicked(attribute)) self.menu.addAction(attribute_action) def create_date_picker(self, index): tmp_time = self.uniqueDates[index] time_QFormat = tmp_time.split("-") # date is parsed and converted to int to comply with required format of QDate date_picker = QDateTimeEdit( QDate(int(time_QFormat[0]), int(time_QFormat[1]), int(time_QFormat[2])), self) date_picker.setDisplayFormat("yyyy.MM.dd") date_picker.setCalendarPopup(True) date_picker.setCalendarWidget(QCalendarWidget()) date_picker.resize(date_picker.width() + 20, date_picker.height()) return date_picker def set_date_pickers(self, slider): # Set Date Picker for Start of self.slider date_picker_start = self.create_date_picker(0) date_picker_start.setToolTip( "Select the BEGINNING of the time period from which the data is displayed" ) date_picker_start.move( slider.property("x") - date_picker_start.width() - 30, slider.property("y")) # Set Date Picker for End of self.slider date_picker_end = self.create_date_picker(-1) date_picker_end.setToolTip( "Select the END of the time period from which the data is displayed" ) date_picker_end.move( slider.property("x") + slider.property("width") + 30, slider.property("y")) # Set Date Pickers Boundaries Based on First and Last Date in Given Data date_picker_start.setMinimumDate(date_picker_start.date()) date_picker_end.setMinimumDate(date_picker_start.date()) date_picker_start.setMaximumDate(date_picker_end.date()) date_picker_end.setMaximumDate(date_picker_end.date()) return date_picker_start, date_picker_end def create_interface(self): self.attribute_button.move(50, 0) # Create a Menu Option for Each Attribute self.add_attribute_to_menu(self.humidity_attribute, "humidity") self.add_attribute_to_menu(self.pressure_attribute, "pressure") self.add_attribute_to_menu(self.temperature_attribute, "temperature") self.add_attribute_to_menu(self.wind_speed_attribute, "wind_speed") self.attribute_button.setMenu(self.menu) self.attribute_button.resize(self.menu.width() + 50, self.attribute_button.height()) # Get self.slider from QML File self.slider = self.rootObject().findChild(QObject, "slider") # Set Date Pickers self.date_picker_start, self.date_picker_end = self.set_date_pickers( self.slider) self.date_picker_start.dateChanged.connect(lambda: self.change_date( self.slider, self.self.date_picker_start, self.date_picker_end)) self.date_picker_end.dateChanged.connect(lambda: self.change_date( self.slider, self.self.date_picker_start, self.date_picker_end)) # Label Holding the Current Date Selected by User self.date_label.move( self.slider.property("x") + (self.slider.width() / 2) - 100, self.slider.property("y") + 30) self.date_label.adjustSize() # Set Buttons Position self.previous_button.setStyleSheet("color: black") self.previous_button.move(self.slider.property("x"), self.slider.property("y") + 50) self.previous_button.adjustSize() self.next_button.setStyleSheet("color: black") self.next_button.move( self.slider.property("x") + self.slider.width() - 70, self.slider.property("y") + 50) self.next_button.adjustSize() jump_label = QLabel("self.slider jump (in days): ", self) jump_label.setStyleSheet("color: black") jump_label.move(self.date_label.x(), self.date_label.y() + 40) jump_label.adjustSize() self.jump_value = QLineEdit(self) self.jump_value.move(jump_label.x() + jump_label.width(), jump_label.y() - 5) self.jump_value.resize(35, self.jump_value.height()) self.jump_value.editingFinished.connect( lambda: self.slider.setProperty("stepSize", self.jump_value.text() )) agg_label = QLabel(self) agg_label.setStyleSheet("color: black") agg_label.move(self.date_label.x(), self.jump_value.y() + 40) agg_label.setText("mean (in days): ") agg_label.adjustSize() agg_value = QLineEdit(self) agg_value.move(self.jump_value.x(), agg_label.y() - 5) agg_value.resize(35, agg_value.height()) agg_value.editingFinished.connect( lambda: self.set_agg(agg_value.text())) # Initialize Visualization self.humidity_attribute.trigger() self.change_date(self.slider, self.date_picker_start, self.date_picker_end) def on_button_clicked(self, action): jump_value = int(self.jump_value.text()) slider_value = int(self.slider.property("value")) current_date = pandas.to_datetime(self.currentDate) start_date = self.date_picker_start.date().toPython() end_date = self.date_picker_end.date().toPython() if action == "next": if current_date + datetime.timedelta(days=jump_value) <= end_date: self.slider.setProperty("value", slider_value + jump_value) self.update_date(int(self.slider.property("value"))) elif action == "previous": if current_date - datetime.timedelta( days=jump_value) >= start_date: self.slider.setProperty("value", slider_value - jump_value) self.update_date(int(self.slider.property("value"))) @Slot(int) def update_date(self, value): self.currentDate = self.uniqueDates[value - 1] self.date_label.setText("selected date: " + str(self.currentDate).replace("-", ".")) self.clicked(self.attribute_button.text()) # TODO: visualise time series data, not just int created by aggregation # TODO: create setting of visualised time period for user # calculates the difference (in days) between start date and end date and rescales the self.slider def set_agg(self, value): self.aggregation = int(value) self.clicked(self.attribute_button.text()) def change_date(self, slider, date_picker_start, date_picker_end): dif = self.uniqueDates\ .index(date_picker_end.date().toString("yyyy-MM-dd")) - self.uniqueDates.index(date_picker_start.date().toString("yyyy-MM-dd")) slider.setProperty("to", dif + 1) # when button is clicked, changes values in all model items to a different attribute def clicked(self, attribute): self.attribute_button.setText(attribute) values = self.get_values(self.data, attribute) colors = self.get_colors(self.data, attribute) for i in range(0, len(values)): self.model.setData(i, values[i], colors[i], MarkerModel.ValueRole) @staticmethod def get_positions(data): tmp = data.drop_duplicates('city').sort_values(by=['city']) positions = [[x, y] for x, y in zip(tmp['latitude'], tmp['longitude'])] return positions @staticmethod def get_names(data): tmp = data.drop_duplicates('city').sort_values(by=['city']) names = tmp['city'].values.tolist() return names # creates an ordered list of aggregated values of a specified attribute def get_values(self, data, attribute): data['datetime'] = pandas.to_datetime(data['datetime']) start_date = pandas.to_datetime(self.currentDate) end_date = start_date + datetime.timedelta(days=self.aggregation) tmp = data[data['datetime'] >= start_date] tmp = tmp[tmp['datetime'] <= end_date] values = tmp.groupby('city').apply( lambda x: x[attribute].mean()).values.round(2).tolist() return values @staticmethod def get_colors(data, attribute): tmp = data.groupby('city').agg({attribute: 'mean'}) max_value = round(tmp[attribute].max()) min_value = round(tmp[attribute].min()) diff = max_value - min_value step = round(1 / 6 * diff) if attribute == 'pressure': attribute_values = { 0: [255, 255, 255], 1: [204, 229, 255], 2: [102, 178, 255], 3: [0, 128, 255], 4: [0, 0, 255], 5: [0, 0, 102], 6: [0, 0, 51] } elif attribute == 'temperature': attribute_values = { 0: [0, 102, 204], 1: [102, 178, 255], 2: [204, 229, 255], 3: [255, 204, 204], 4: [255, 102, 102], 5: [204, 0, 0], 6: [102, 0, 0] } # TODO: create more suited colors for humidity and wind speed elif attribute == 'humidity': attribute_values = { 0: [0, 102, 204], 1: [102, 178, 255], 2: [204, 229, 255], 3: [255, 204, 204], 4: [255, 102, 102], 5: [204, 0, 0], 6: [102, 0, 0] } elif attribute == 'wind_speed': attribute_values = { 0: [0, 102, 204], 1: [102, 178, 255], 2: [204, 229, 255], 3: [255, 204, 204], 4: [255, 102, 102], 5: [204, 0, 0], 6: [102, 0, 0] } values = numpy.array([ min_value, min_value + 1 * step, min_value + 2 * step, min_value + 3 * step, min_value + 4 * step, min_value + 5 * step, max_value ]) tmp['distances'] = tmp[attribute].apply(lambda x: abs(x - values)) tmp['index'] = tmp['distances'].apply(lambda x: numpy.argmin(x)) tmp['color'] = tmp['index'].apply(lambda x: attribute_values.get(x)) colors = tmp['color'].tolist() colors_list = [] for color_tmp in colors: color = QColor(color_tmp[0], color_tmp[1], color_tmp[2], 255) colors_list.append(color) # returns QJSValue return colors_list def createAction(self, attribute): action = QAction(attribute) action.triggered.connect(self.clicked(attribute)) self.menu.addAction(action) return action
class Window(QWidget): def __init__(self, app, parent=None): print("Window init") super().__init__(parent) # self.win_event_filter = WinEventFilter("window") # self.installNativeEventFilter(self.win_event_filter) self.app = app self.window_size = QtCore.QSize(400, 250) self.window_size_offset = QtCore.QSize(0, 150) self.window_position = QtCore.QPoint(0, 0) self.window_position_offset = QtCore.QPoint(0, 0) # self.setWindowFlags( # QtCore.Qt.Window | # QtCore.Qt.CustomizeWindowHint | # QtCore.Qt.WindowTitleHint | # QtCore.Qt.WindowCloseButtonHint | # QtCore.Qt.WindowStaysOnTopHint # ) self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint) self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint) self.setWindowFlags( QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.Tool) # hlayout = QHBoxLayout() # hlayout.setMargin(0) # hlayout.setContentsMargins(0, 0, 0, 0) # hlayout.setSpacing(0) # buttonslayout = QVBoxLayout() self.labels = [] self.menuButton = QPushButton(u"\U00002261") self.menuLabel = QLabel("Menu") myFontBold = self.menuLabel.font() myFontBold.setBold(True) # buttons myFont = self.menuButton.font() myFont2 = self.menuButton.font() if (myFont.pointSize() > 0): myFont.setPointSizeF(1.25 * myFont.pointSizeF()) myFont2.setPointSizeF(1.4 * myFont.pointSizeF()) else: myFont.setPixelSize(1.25 * myFont.pixelSize()) myFont2.setPixelSize(1.4 * myFont.pixelSize()) self.menuLabel.setFont(myFontBold) width = self.menuButton.fontMetrics().boundingRect("OO").width() + 7 height = width # okButton.height() self.menuButton.setFont(myFont2) self.menuButton.setMaximumWidth(width) self.menuButton.setMinimumWidth(width) self.menuButton.setFlat(True) self.menuButton.clicked.connect(self.menuPressed) mainButton = QPushButton(u"\U0000239A") mainLabel = QLabel("Main") width = mainButton.fontMetrics().boundingRect("OO").width() + 7 height = width # okButton.height() mainButton.setFont(myFont2) mainButton.setMaximumWidth(width) mainButton.setMinimumWidth(width) mainButton.clicked.connect(self.main) mainButton.setFlat(True) setupButton = QPushButton(u"\U0001F527") setupLabel = QLabel("Setup") setupButton.setFont(myFont) setupButton.setFlat(True) setupButton.setMaximumWidth(width) setupButton.setMinimumWidth(width) setupButton.clicked.connect(self.setup) identifyButton = QPushButton(u"\U00002755") identifyLabel = QLabel("Identify") identifyButton.setFont(myFont) identifyButton.setFlat(True) identifyButton.setMaximumWidth(width) identifyButton.setMinimumWidth(width) identifyButton.clicked.connect(self.identify) self.refreshButton = QPushButton(u"\U000021BB") self.refreshLabel = QLabel("Detect") self.refreshButton.setFont(myFont) self.refreshButton.setFlat(True) self.refreshButton.setMaximumWidth(width) self.refreshButton.setMinimumWidth(width) self.refreshButton.clicked.connect(self.refreshPressed) aboutButton = QPushButton(u"\U00002754") aboutLabel = QLabel("About") aboutButton.setFont(myFont) aboutButton.setFlat(True) aboutButton.setMaximumWidth(width) aboutButton.setMinimumWidth(width) aboutButton.clicked.connect(self.about) # closeButton = QPushButton(u"\U00002573") closeButton = QPushButton(u"\U000026CC") closeLabel = QLabel("Close") closeButton.setFont(myFont) closeButton.setFlat(True) closeButton.setMaximumWidth(width) closeButton.setMinimumWidth(width) closeButton.clicked.connect(self.close_) buttongrid = QGridLayout() buttongrid.addWidget(self.menuButton, 0, 0) buttongrid.addWidget(mainButton, 1, 0) buttongrid.addWidget(setupButton, 2, 0) buttongrid.addWidget(self.refreshButton, 3, 0) buttongrid.addWidget(identifyButton, 4, 0) buttongrid.addWidget(aboutButton, 6, 0) buttongrid.addWidget(closeButton, 7, 0) buttongrid.addWidget(self.menuLabel, 0, 1) buttongrid.addWidget(mainLabel, 1, 1) buttongrid.addWidget(setupLabel, 2, 1) buttongrid.addWidget(self.refreshLabel, 3, 1) buttongrid.addWidget(identifyLabel, 4, 1) buttongrid.addWidget(aboutLabel, 6, 1) buttongrid.addWidget(closeLabel, 7, 1) self.labels.append(self.menuLabel) self.labels.append(mainLabel) self.labels.append(setupLabel) self.labels.append(self.refreshLabel) self.labels.append(identifyLabel) self.labels.append(aboutLabel) self.labels.append(closeLabel) self.menuLabel .mousePressEvent = self.menuLabelPressed mainLabel .mousePressEvent = self.mainLabel setupLabel.mousePressEvent = self.setupLabel self.refreshLabel.mousePressEvent = self.refreshLabelPressed identifyLabel.mousePressEvent = self.identifyLabel aboutLabel.mousePressEvent = self.aboutLabel closeLabel.mousePressEvent = self.closeLabel buttongrid.setRowStretch(0, 0) buttongrid.setRowStretch(1, 0) buttongrid.setRowStretch(2, 0) buttongrid.setRowStretch(3, 0) buttongrid.setRowStretch(4, 0) buttongrid.setRowStretch(5, 1) buttongrid.setRowStretch(6, 0) buttongrid.setRowStretch(7, 0) self.labels_set_visible(False) self.layout = QHBoxLayout() # buttonslayout.addWidget(mainButton) # buttonslayout.addWidget(setupButton) # buttonslayout.addStretch(1) # buttonslayout.addWidget(aboutButton) # hlayout.addLayout(buttonslayout) # hlayout.addLayout(buttongrid) # grid.addLayout(hlayout, 1, 1) buttongrid.setSpacing(0) self.layout.addLayout(buttongrid) self.body_layout = QVBoxLayout() self.body_layout.setContentsMargins(0, 0, 0, 1) self.body_layout.setSpacing(0) self.title_layout = QHBoxLayout() self.title_layout.setContentsMargins(0, 0, 0, 0) self.title_layout.setSpacing(0) self.titleLabel = QLabel("Monitor Control") self.titleLabel.setWordWrap(True) self.titleLabel.setSizeIncrement(10, 10) myFont = self.titleLabel.font() myFont.setBold(True) self.titleLabel.setFont(myFont) width = self.titleLabel.fontMetrics().boundingRect("OO").width() + 7 height = width # okButton.height() self.titleLabel.mousePressEvent = self.mainLabel self.backButton = QPushButton(u"\U00002190", self) myFont = self.backButton.font() myFont.setBold(True) self.backButton.setFont(myFont) self.backButton.setMaximumWidth(width) self.backButton.setMinimumWidth(width) self.backButton.setFlat(True) self.backButton.clicked.connect(self.main) self.titleLabel.setMinimumHeight(self.backButton.height()) self.title_layout.addWidget(self.backButton, 0, QtCore.Qt.AlignVCenter) self.title_layout.addSpacing(20) self.title_layout.addWidget(self.titleLabel, 1, QtCore.Qt.AlignVCenter) # self.backButton.setAlignment(Qt.AlignTop) self.title_layout.setAlignment(QtCore.Qt.AlignTop) self.body_layout.addLayout(self.title_layout) self.main_frame = QtWidgets.QFrame(self) self.main_layout = QVBoxLayout() self.feature_brightness = FeatureWidget( self.main_frame, "Brightness", self.app.brightness) self.feature_contrast = FeatureWidget( self.main_frame, "Contrast", self.app.contrast) self.main_layout.addWidget(self.feature_brightness) self.main_layout.addWidget(self.feature_contrast) self.main_layout.addStretch(1) self.main_frame.setLayout(self.main_layout) self.main_frame.hide() self.body_layout.addWidget(self.main_frame, 1) self.setup_frame = QtWidgets.QFrame(self) leftButton = QPushButton("<", self.setup_frame) width = leftButton.fontMetrics().boundingRect("<").width() + 7 leftButton.setFlat(True) leftButton.setMaximumWidth(width) leftButton.setMinimumWidth(width) leftButton.setSizePolicy(QtWidgets.QSizePolicy( QSizePolicy.Fixed, QSizePolicy.Expanding)) self.setup_layout = QHBoxLayout() self.setup_layout.addWidget(leftButton) self.feature_setup_widget = FeatureSetupWidget( self.app, self.setup_frame) # hlayout.addWidget(self.feature_setup_widget, 1) self.feature_setup_widget.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding) rightButton = QPushButton(">", self.setup_frame) rightButton.setFlat(True) rightButton.setMaximumWidth(width) rightButton.setMinimumWidth(width) rightButton.setSizePolicy(QtWidgets.QSizePolicy( QSizePolicy.Fixed, QSizePolicy.Expanding)) self.setup_layout.addWidget(self.feature_setup_widget, 1) self.setup_layout.addWidget(rightButton) self.setup_layout.setContentsMargins(0, 0, 0, 0) self.setup_layout.setSpacing(0) leftButton.clicked.connect(self.feature_setup_widget.previous) rightButton.clicked.connect(self.feature_setup_widget.next) self.setup_frame.setLayout(self.setup_layout) # self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(10) self.body_layout.addWidget(self.setup_frame, 1) self.layout.addLayout(self.body_layout, 1) self.about_frame = QtWidgets.QFrame(self) self.about_layout = QVBoxLayout() self.aboutLabel1 = QLabel("About", self.about_frame) self.aboutLabel1.setWordWrap(True) myFont = self.aboutLabel1.font() myFont.setBold(True) self.aboutLabel1.setFont(myFont) about = "©️ ™️ Juno\n\nMonitor Control synchronizes your monitor hardware properties like brightness and contrast.\nThese properties can be changed by the software sliders, or monitor buttons. These changes are monitored and read, and subsequently set to the other monitors using a calibration. This will ensure an input change has the same result on all monitors.\n" self.aboutLabel2 = QLabel("{}".format(about), self.about_frame) self.aboutLabel2.setAlignment( QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) self.aboutLabel2.setWordWrap(True) self.about_layout.addWidget(self.aboutLabel1) self.about_layout.addWidget(self.aboutLabel2, 1) self.about_frame.setLayout(self.about_layout) self.about_frame.hide() self.body_layout.addWidget(self.about_frame, 1) # self.layout.setSizeConstraint(QtGui.QLayout.setFixedSize) self.setLayout(self.layout) self.setWindowIcon(QtGui.QIcon('artifacts/icon.png')) # set the title self.setWindowTitle("Monitors Control") self.main() self.setFixedSize(400, 250) def labels_set_visible(self, visible): for label in self.labels: if (self.refreshLabel == label) and visible: self.refreshLabel.setVisible(self.refreshButton.isVisible()) else: label.setVisible(visible) def refresh_visible(self, visible): if (visible): self.refreshButton.setVisible(visible) self.refreshLabel.setVisible(self.menuLabel.isVisible()) else: self.refreshLabel.setVisible(visible) self.refreshButton.setVisible(visible) def focusOutEvent(self, event): print('Lost focus') def menuLabelPressed(self, event): self.menuPressed() def menuPressed(self): print("Menu") self.labels_set_visible(not self.labels[0].isVisible()) def aboutLabel(self, event): self.about() def about(self): print("About") self.setupUpdate() self.setMinimumSize(200, 130) # self.feature_setup_widget.hide() self.setup_frame.hide() self.main_frame.hide() self.refresh_visible(False) self.backButton.show() self.about_frame.show() self.move(self.window_position) self.setFixedSize(self.window_size) def closeLabel(self, event): self.close_() def close_(self): print("Close {}".format(len(self.app.identifyWindows))) self.setupUpdate() if (len(self.app.identifyWindows) == 0): self.hide() def setupLabel(self, event): self.setup() def setup(self): print("Setup") self.move(self.window_position + self.window_position_offset) self.setFixedSize(self.window_size + self.window_size_offset) self.app.monitors._calibrations.loadYaml() self.feature_setup_widget.init() self.backButton.show() self.main_frame.hide() self.about_frame.hide() self.refresh_visible(True) self.setup_frame.show() self.setMinimumSize(200, 130) def setupUpdate(self): if (self.setup_frame.isVisible()): self.app.monitors._calibrations.saveYaml() def mainLabel(self, event): self.main() def main(self): print("Main") self.setMinimumSize(200, 130) self.setupUpdate() self.refresh_visible(False) self.backButton.hide() # self.feature_setup_widget.hide() self.setup_frame.hide() self.about_frame.hide() self.main_frame.hide() self.move(self.window_position) self.setFixedSize(self.window_size) self.main_frame.show() def identifyLabel(self, event): self.identify() def identify(self): print("Identify") self.app.identify() def refreshLabelPressed(self, event): self.refreshPressed() def refreshPressed(self): QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) print("detect") self.feature_setup_widget.clear() self.app.detect() self.setup() self.feature_setup_widget.set_infos(self.app.monitors) self.feature_setup_widget.init() self.app.list_monitors() QApplication.restoreOverrideCursor() def position_show(self): print("position_show") self.app.position_next_to_tray() self.main() self.show() # self.requestActivate() # QtCore.Qt.ActiveWindowFocusReason self.activateWindow() self.setFocus(QtCore.Qt.PopupFocusReason) def contrast(self, value): # from gui self.app.contrast(value) def brightness(self, value): # from gui self.app.brightness(value) def set_contrast(self, value): # to gui self.feature_contrast.set_value(value) self.feature_setup_widget.set_contrast(value) def set_brightness(self, value): # to gui self.feature_brightness.set_value(value) self.feature_setup_widget.set_brightness(value) def show(self): # to gui value = self.app.monitors.get_contrast() if (value is not None): self.set_contrast(value) value = self.app.monitors.get_brightness() if (value is not None): self.set_brightness(value) self.feature_setup_widget.set_infos(self.app.monitors) super().show()