diff --git a/CherryTomato/__init__.py b/CherryTomato/__init__.py
index 5210c24..d1cb619 100644
--- a/CherryTomato/__init__.py
+++ b/CherryTomato/__init__.py
@@ -4,6 +4,6 @@
MEDIA_DIR = os.path.join(BASE_DIR, 'media')
APP_ICON = os.path.join(MEDIA_DIR, 'icon.png')
-VERSION = '0.3.0'
-ORGANIZATION_NAME = 'CherryTomato'
+VERSION = '0.4.0'
+ORGANIZATION_NAME = 'yakimka'
APPLICATION_NAME = 'CherryTomato'
diff --git a/CherryTomato/about_window.py b/CherryTomato/about_window.py
index 15b08b6..2b16915 100644
--- a/CherryTomato/about_window.py
+++ b/CherryTomato/about_window.py
@@ -1,3 +1,4 @@
+from PyQt5 import Qt
from PyQt5 import QtWidgets
from PyQt5.QtGui import QIcon
@@ -15,3 +16,9 @@ def __init__(self):
self.labelTitle.setText(title)
self.setWindowIcon(QIcon(APP_ICON))
+
+ def keyPressEvent(self, event):
+ if event.key() == Qt.Qt.Key_Escape:
+ self.close()
+ else:
+ super().keyPressEvent(event)
diff --git a/CherryTomato/main.py b/CherryTomato/main.py
index 4b79ead..5755c38 100755
--- a/CherryTomato/main.py
+++ b/CherryTomato/main.py
@@ -8,7 +8,7 @@
from CherryTomato import ORGANIZATION_NAME, APPLICATION_NAME
from CherryTomato.main_window import CherryTomatoMainWindow
-QCoreApplication.setApplicationName(ORGANIZATION_NAME)
+QCoreApplication.setOrganizationName(ORGANIZATION_NAME)
QCoreApplication.setApplicationName(APPLICATION_NAME)
app = Qt.QApplication(sys.argv)
diff --git a/CherryTomato/main_ui.py b/CherryTomato/main_ui.py
index 60a75b3..f80f9e1 100644
--- a/CherryTomato/main_ui.py
+++ b/CherryTomato/main_ui.py
@@ -55,6 +55,9 @@ def setupUi(self, MainWindow):
self.actionAbout.setObjectName("actionAbout")
self.actionSettings = QtWidgets.QAction(MainWindow)
self.actionSettings.setObjectName("actionSettings")
+ self.actionReset = QtWidgets.QAction(MainWindow)
+ self.actionReset.setObjectName("actionReset")
+ self.menuFile.addAction(self.actionReset)
self.menuFile.addAction(self.actionSettings)
self.menuFile.addAction(self.actionAbout)
self.menuBar.addAction(self.menuFile.menuAction())
@@ -68,4 +71,5 @@ def retranslateUi(self, MainWindow):
self.menuFile.setTitle(_translate("MainWindow", "File"))
self.actionAbout.setText(_translate("MainWindow", "About"))
self.actionSettings.setText(_translate("MainWindow", "Settings"))
+ self.actionReset.setText(_translate("MainWindow", "Reset"))
from CherryTomato.widget import QRoundProgressBar, QRoundPushbutton
diff --git a/CherryTomato/main_ui.ui b/CherryTomato/main_ui.ui
index b677000..1f12e17 100644
--- a/CherryTomato/main_ui.ui
+++ b/CherryTomato/main_ui.ui
@@ -99,6 +99,7 @@ border-radius: 20px;
File
+
@@ -114,6 +115,11 @@ border-radius: 20px;
Settings
+
+
+ Reset
+
+
diff --git a/CherryTomato/main_window.py b/CherryTomato/main_window.py
index 1134aec..cc1f028 100644
--- a/CherryTomato/main_window.py
+++ b/CherryTomato/main_window.py
@@ -1,7 +1,7 @@
import os
from PyQt5 import Qt, QtCore
-from PyQt5.QtGui import QBrush, QColor, QPalette, QIcon
+from PyQt5.QtGui import QBrush, QColor, QPalette, QIcon, QKeySequence
from PyQt5.QtMultimedia import QSound
from CherryTomato import about_window, APP_ICON, MEDIA_DIR, settings_window
@@ -35,6 +35,9 @@ def __init__(self, parent=None):
self.actionSettings.triggered.connect(self.showSettingsWindow)
self.settingsWindow.closing.connect(self.update)
+ self.actionReset.setShortcut(QKeySequence('Ctrl+R'))
+ self.actionReset.triggered.connect(self.tomatoTimer.reset)
+
def update(self):
self.tomatoTimer.updateState()
@@ -80,10 +83,10 @@ def closeEvent(self, e):
@Qt.pyqtSlot()
def display(self):
- TOMATO_SIGN = '˙'
+ TOMATO_SIGN = '🍅'
minutes, seconds = int(self.tomatoTimer.seconds // 60), int(self.tomatoTimer.seconds % 60)
- display = f'\n{minutes:02d}:{seconds:02d}\n{TOMATO_SIGN * self.tomatoTimer.tomatoes}'
- self.progress.setFormat(display)
+ self.progress.setFormat(f'{minutes:02d}:{seconds:02d}')
+ self.progress.setSecondFormat(f'{TOMATO_SIGN}x{self.tomatoTimer.tomatoes}')
self.progress.setValue(self.tomatoTimer.progress)
self.changeButtonState()
@@ -94,7 +97,7 @@ def display(self):
@Qt.pyqtSlot()
def do_start(self):
- # trigger through proxy
+ # TODO trigger through proxy
if not self.tomatoTimer.running:
self.tomatoTimer.start()
else:
@@ -137,12 +140,6 @@ def setGreen(self):
green = (60, 187, 111)
self.setColor(lightGreen, green)
- def keyPressEvent(self, event):
- if event.key() == Qt.Qt.Key_Escape:
- self.close()
- else:
- super().keyPressEvent(event)
-
@Qt.pyqtSlot()
def setFocusOnWindowAndPlayNotification(self):
if self.settings.interrupt:
diff --git a/CherryTomato/settings_window.py b/CherryTomato/settings_window.py
index d98859f..2e7ff90 100644
--- a/CherryTomato/settings_window.py
+++ b/CherryTomato/settings_window.py
@@ -1,4 +1,4 @@
-from PyQt5 import QtWidgets
+from PyQt5 import QtWidgets, Qt
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtGui import QIcon
@@ -32,6 +32,12 @@ def __init__(self):
self.autoStopBreak.setChecked(self.settings.autoStopBreak)
self.switchToTomatoOnAbort.setChecked(self.settings.switchToTomatoOnAbort)
+ def keyPressEvent(self, event):
+ if event.key() == Qt.Qt.Key_Escape:
+ self.close()
+ else:
+ super().keyPressEvent(event)
+
def closeEvent(self, e):
e.accept()
self.updateSettings()
diff --git a/CherryTomato/tomato_timer.py b/CherryTomato/tomato_timer.py
index f4f168b..69dca4d 100644
--- a/CherryTomato/tomato_timer.py
+++ b/CherryTomato/tomato_timer.py
@@ -3,8 +3,6 @@
from CherryTomato.settings import CherryTomatoSettings
-settings = CherryTomatoSettings()
-
class TomatoTimer(QObject):
TICK_TIME = 64 # ms
@@ -15,7 +13,7 @@ class TomatoTimer(QObject):
def __init__(self):
super().__init__()
- self.settings = settings
+ self.settings = CherryTomatoSettings()
self.tomatoes = 0
self.state = None
@@ -47,7 +45,7 @@ def abort(self):
if not self.isTomato() and self.settings.switchToTomatoOnAbort:
self.changeState()
else:
- self.reset()
+ self.resetTime()
self.notifyAboutAnyChange()
def createTimer(self):
@@ -100,10 +98,10 @@ def _isTimeForLongBreak(self):
def updateState(self):
if not self.running:
- self.reset()
+ self.resetTime()
self.notifyAboutAnyChange()
- def reset(self):
+ def resetTime(self):
self.seconds = self.state.time
def notifyAboutAnyChange(self):
@@ -111,3 +109,11 @@ def notifyAboutAnyChange(self):
def notifyTimerIsOver(self):
self.finished.emit()
+
+ def reset(self):
+ self.stop()
+ self.tomatoes = 0
+ self.state = None
+ del self._states
+ self.changeState()
+ self.notifyAboutAnyChange()
diff --git a/CherryTomato/widget.py b/CherryTomato/widget.py
index f4dfb21..814a480 100644
--- a/CherryTomato/widget.py
+++ b/CherryTomato/widget.py
@@ -1,10 +1,12 @@
import os
from PyQt5 import QtCore
+from PyQt5.QtCore import QRectF, Qt
+from PyQt5.QtGui import QPainter, QFont, QFontMetricsF, QPaintEvent, QImage
from PyQt5.QtWidgets import QPushButton
+from qroundprogressbar import QRoundProgressBar as QRoundProgressBar_
from CherryTomato import MEDIA_DIR
-from qroundprogressbar import QRoundProgressBar as QRoundProgressBar_
class QRoundPushbutton(QPushButton):
@@ -39,11 +41,76 @@ def applyStyleSheet(self):
class QRoundProgressBar(QRoundProgressBar_):
def __init__(self, parent=None):
super().__init__(parent)
+ self.m_second_format = ''
+
self.setFormat('')
self.setValue(0)
self.setBarStyle(QRoundProgressBar.BarStyle.LINE)
- self.setOutlinePenWidth(6)
- self.setDataPenWidth(6)
+ self.setOutlinePenWidth(4)
+ self.setDataPenWidth(4)
def resizeEvent(self, e):
self.setMaximumWidth(self.height())
+
+ def setSecondFormat(self, val: str):
+ if val != self.m_second_format:
+ self.m_second_format = val
+ self.valueFormatChanged()
+
+ def paintEvent(self, event: QPaintEvent):
+ outerRadius = min(self.width(), self.height())
+ baseRect = QRectF(1, 1, outerRadius - 2, outerRadius - 2)
+ buffer = QImage(outerRadius, outerRadius, QImage.Format_ARGB32_Premultiplied)
+ p = QPainter(buffer)
+ p.setRenderHint(QPainter.Antialiasing)
+ self.rebuildDataBrushIfNeeded()
+ self.drawBackground(p, buffer.rect())
+ self.drawBase(p, baseRect)
+ if self.m_value > 0:
+ delta = (self.m_max - self.m_min) / (self.m_value - self.m_min)
+ else:
+ delta = 0
+ self.drawValue(p, baseRect, self.m_value, delta)
+ firstInnerRect, secondInnerRect, innerRadius = self.calculateInnerRect(outerRadius)
+ self.drawInnerBackground(p, firstInnerRect)
+ self.drawInnerBackground(p, secondInnerRect)
+ self.drawTwoTexts(p, firstInnerRect, secondInnerRect, innerRadius, self.m_value)
+ p.end()
+ painter = QPainter(self)
+ painter.fillRect(baseRect, self.palette().window())
+ painter.drawImage(0, 0, buffer)
+
+ def calculateInnerRect(self, outerRadius: float):
+ innerRect, innerRadius = super().calculateInnerRect(outerRadius)
+
+ left, top, width, height = innerRect.getRect()
+
+ firstHeight = height * 0.7
+ firstInnerRect = QRectF(left, top, width, firstHeight)
+ secondInnerRect = QRectF(left, top + firstHeight, width, height - firstHeight)
+ return firstInnerRect, secondInnerRect, innerRadius
+
+ def drawTwoTexts(self,
+ p: QPainter,
+ firstRect: QRectF,
+ secondRect: QRectF,
+ innerRadius: float,
+ value: float):
+ if not self.m_format:
+ return
+ f = QFont(self.font())
+ f.setPixelSize(10)
+ fm = QFontMetricsF(f)
+ maxWidth = fm.width(self.valueToText(self.m_max))
+ delta = innerRadius / maxWidth
+ timeFontSize = f.pixelSize() * delta * 0.75
+ f.setPixelSize(int(timeFontSize))
+ p.setFont(f)
+ timeTextRect = QRectF(firstRect)
+ tomatoesTextRect = QRectF(secondRect)
+ p.setPen(self.palette().text().color())
+ p.drawText(timeTextRect, Qt.AlignCenter | Qt.AlignBottom, self.valueToText(value))
+ tomatoesFontSize = timeFontSize * 0.3
+ f.setPixelSize(int(tomatoesFontSize))
+ p.setFont(f)
+ p.drawText(tomatoesTextRect, Qt.AlignHCenter, self.m_second_format)
diff --git a/README.md b/README.md
index 7cdc99f..b639c7e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# CherryTomato
-
+
## Features
diff --git a/assets/Screenshot_20191211_004536.png b/assets/Screenshot_20191211_004536.png
deleted file mode 100644
index 7d91e7b..0000000
Binary files a/assets/Screenshot_20191211_004536.png and /dev/null differ
diff --git a/assets/screenshot.png b/assets/screenshot.png
new file mode 100644
index 0000000..237bb40
Binary files /dev/null and b/assets/screenshot.png differ
diff --git a/setup.py b/setup.py
index 2296d4b..e1ee4fb 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
setup(name='CherryTomato',
author='yakimka',
- version='0.1.0',
+ version='0.4.0',
packages=['CherryTomato'],
install_requires=['PyQt5', 'qroundprogressbar'],
url='https://github.com/yakimka/CherryTomato',
diff --git a/tests/test_tomato_timer.py b/tests/test_tomato_timer.py
index 04f94de..1d77b70 100644
--- a/tests/test_tomato_timer.py
+++ b/tests/test_tomato_timer.py
@@ -64,7 +64,7 @@ def test_stop(mock_qt_timer, tomato):
@pytest.fixture
def mock_change_reset(mocker):
- return mocker.patch('CherryTomato.tomato_timer.TomatoTimer.reset')
+ return mocker.patch('CherryTomato.tomato_timer.TomatoTimer.resetTime')
@pytest.fixture
@@ -76,7 +76,7 @@ def test_abort(mock_for_abort, tomato):
tomato.abort()
tomato.stop.assert_called_once()
- tomato.reset.assert_called_once()
+ tomato.resetTime.assert_called_once()
assert tomato.isTomato()
@@ -136,9 +136,9 @@ def test_change_state_to_long_break(tomato, tomatoes, const_value, expected):
assert tomato.seconds == expected.time
-def test_reset(tomato):
+def test_reset_time(tomato):
tomato.seconds = 1
- tomato.reset()
+ tomato.resetTime()
assert tomato.seconds == 100