Skip to content

Commit

Permalink
Merge pull request #1653 from Scille/gui-add-qr-code
Browse files Browse the repository at this point in the history
[GUI] Added QR code on device invitation
  • Loading branch information
Max-7 authored Jun 25, 2021
2 parents 2d2dfe2 + d8f7d9c commit b8372af
Show file tree
Hide file tree
Showing 13 changed files with 397 additions and 28 deletions.
1 change: 1 addition & 0 deletions newsfragments/1652.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add QR code on device invitation
12 changes: 11 additions & 1 deletion parsec/core/gui/custom_dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,16 @@
class GreyedDialog(QDialog, Ui_GreyedDialog):
closing = pyqtSignal()

def __init__(self, center_widget, title, parent, hide_close=False, width=None):
def __init__(
self, center_widget, title, parent, hide_close=False, width=None, close_on_click=False
):
super().__init__(None)
self.setupUi(self)
self.setModal(True)
self.setObjectName("GreyedDialog")
self.setWindowModality(Qt.ApplicationModal)
self.button_close.apply_style()
self.close_on_click = close_on_click
if sys.platform == "win32":
# SplashScreen on Windows freezes the Window
self.setWindowFlags(Qt.FramelessWindowHint)
Expand Down Expand Up @@ -97,6 +100,13 @@ def paintEvent(self, event):
p = QPainter(self)
self.style().drawPrimitive(QStyle.PE_Widget, opt, p, self)

def mousePressEvent(self, event):
super().mousePressEvent(event)
if not self.close_on_click:
return
if event.button() == Qt.LeftButton:
self.accept()

def on_finished(self):
if (
self.result() == QDialog.Rejected
Expand Down
67 changes: 67 additions & 0 deletions parsec/core/gui/custom_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import math

from enum import Enum

from PyQt5.QtCore import Qt, pyqtSignal, QSize
from PyQt5.QtGui import QIcon, QPainter, QColor, QPen, QCursor, QPixmap, QFont, QFontMetrics
from PyQt5.QtWidgets import (
Expand Down Expand Up @@ -258,6 +260,71 @@ def mousePressEvent(self, event):
self.clicked.emit(self.text())


class OverlayLabel(ClickableLabel):
OPEN_FULLSCREEN_ICON = None
CLOSE_FULLSCREEN_ICON = None

class ClickMode(Enum):
OpenFullScreen = 1
CloseFullScreen = 2

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._pix = None
self.click_mode = OverlayLabel.ClickMode.OpenFullScreen
self.show_icon = True
if not OverlayLabel.OPEN_FULLSCREEN_ICON:
OverlayLabel.OPEN_FULLSCREEN_ICON = Pixmap(":/icons/images/material/fullscreen.svg")
OverlayLabel.OPEN_FULLSCREEN_ICON.replace_color(QColor(0, 0, 0), QColor(164, 164, 164))
if not OverlayLabel.CLOSE_FULLSCREEN_ICON:
OverlayLabel.CLOSE_FULLSCREEN_ICON = Pixmap(
":/icons/images/material/fullscreen_exit.svg"
)
OverlayLabel.CLOSE_FULLSCREEN_ICON.replace_color(QColor(0, 0, 0), QColor(164, 164, 164))

def set_mode(self, click_mode, show_icon):
self.click_mode = click_mode
self.show_icon = show_icon

def enterEvent(self, event):
self._draw_overlay()

def leaveEvent(self, event):
self._draw_overlay()

def setPixmap(self, pix):
self._pix = pix.copy()
self._draw_overlay()

def _draw_overlay(self):
if not self._pix:
return

if not self.underMouse():
super().setPixmap(self._pix)
return

icon = None

if self.click_mode == OverlayLabel.ClickMode.OpenFullScreen and self.show_icon:
icon = OverlayLabel.OPEN_FULLSCREEN_ICON
icon = icon.scaled(self._pix.width() - 10, self._pix.height() - 10, Qt.KeepAspectRatio)
elif self.click_mode == OverlayLabel.ClickMode.CloseFullScreen and self.show_icon:
icon = OverlayLabel.CLOSE_FULLSCREEN_ICON
icon = icon.scaled(
int(self._pix.width() / 5), int(self._pix.height() / 5), Qt.KeepAspectRatio
)

p = self._pix.copy()
painter = QPainter(p)
if icon:
pos_x = int(p.width() / 2) - int(icon.width() / 2)
pos_y = int(p.height() / 2) - int(icon.height() / 2)
painter.drawPixmap(pos_x, pos_y, icon)
painter.end()
super().setPixmap(p)


class IconLabel(QLabel):
def apply_style(self):
color = self.property("color")
Expand Down
38 changes: 36 additions & 2 deletions parsec/core/gui/forms/greet_device_instructions_widget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>259</height>
<width>312</width>
<height>250</height>
</rect>
</property>
<property name="windowTitle">
Expand Down Expand Up @@ -51,6 +51,32 @@
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="SmallQRCodeWidget" name="qrcode_widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
Expand Down Expand Up @@ -137,6 +163,14 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SmallQRCodeWidget</class>
<extends>QWidget</extends>
<header>parsec.core.gui.qrcode_widget</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
114 changes: 114 additions & 0 deletions parsec/core/gui/forms/qrcode_widget.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QRCodeWidget</class>
<widget class="QWidget" name="QRCodeWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>216</width>
<height>177</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="OverlayLabel" name="label_qrcode">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_text">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>TEXT_CLICK_TO_ENLARGE</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>OverlayLabel</class>
<extends>QLabel</extends>
<header>parsec.core.gui.custom_widgets</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
4 changes: 4 additions & 0 deletions parsec/core/gui/greet_device_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from parsec.core.gui.trio_thread import JobResultError, ThreadSafeQtSignal, QtToTrioJob
from parsec.core.gui.custom_dialogs import show_error, GreyedDialog, show_info
from parsec.core.gui.lang import translate as _
from parsec.core.gui.qrcode_widget import generate_qr_code
from parsec.core.gui import desktop
from parsec.core.gui.ui.greet_device_widget import Ui_GreetDeviceWidget
from parsec.core.gui.ui.greet_device_code_exchange_widget import Ui_GreetDeviceCodeExchangeWidget
Expand Down Expand Up @@ -139,6 +140,9 @@ def __init__(self, jobs_ctx, greeter, invite_addr, core):
self.invite_addr = invite_addr
self.core = core

pix = generate_qr_code(invite_addr.to_url())
self.qrcode_widget.set_image(pix)

self.wait_peer_job = None
self.wait_peer_success.connect(self._on_wait_peer_success)
self.wait_peer_error.connect(self._on_wait_peer_error)
Expand Down
3 changes: 2 additions & 1 deletion parsec/core/gui/parsec-gui.pro
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ FORMS += forms/main_window.ui \
forms/password_choice_widget.ui \
forms/temporary_workspace_widget.ui \
forms/key_widget.ui \
forms/keys_widget.ui
forms/keys_widget.ui \
forms/qrcode_widget.ui

RESOURCES += rc/resources.qrc \
forms/rc/resources.qrc
Loading

0 comments on commit b8372af

Please sign in to comment.