Moved Ui::TimePart to separated file.
This commit is contained in:
parent
2256b4b8ea
commit
c026c1125e
4 changed files with 170 additions and 142 deletions
|
|
@ -176,6 +176,8 @@ PRIVATE
|
||||||
ui/widgets/input_fields.h
|
ui/widgets/input_fields.h
|
||||||
ui/widgets/labels.cpp
|
ui/widgets/labels.cpp
|
||||||
ui/widgets/labels.h
|
ui/widgets/labels.h
|
||||||
|
ui/widgets/fields/time_part_input.cpp
|
||||||
|
ui/widgets/fields/time_part_input.h
|
||||||
ui/widgets/menu/menu.cpp
|
ui/widgets/menu/menu.cpp
|
||||||
ui/widgets/menu/menu.h
|
ui/widgets/menu/menu.h
|
||||||
ui/widgets/menu/menu_action.cpp
|
ui/widgets/menu/menu_action.cpp
|
||||||
|
|
|
||||||
123
ui/widgets/fields/time_part_input.cpp
Normal file
123
ui/widgets/fields/time_part_input.cpp
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
// This file is part of Desktop App Toolkit,
|
||||||
|
// a set of libraries for developing nice desktop applications.
|
||||||
|
//
|
||||||
|
// For license and copyright information please follow this link:
|
||||||
|
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||||
|
//
|
||||||
|
#include "ui/widgets/fields/time_part_input.h"
|
||||||
|
|
||||||
|
#include "ui/ui_utility.h" // WheelDirection
|
||||||
|
|
||||||
|
#include <QtCore/QRegularExpression>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
std::optional<int> TimePart::number() {
|
||||||
|
const auto text = getLastText();
|
||||||
|
auto view = QStringView(text);
|
||||||
|
while (view.size() > 1 && view.at(0) == '0') {
|
||||||
|
view = base::StringViewMid(view, 1);
|
||||||
|
}
|
||||||
|
return QRegularExpression("^\\d+$").match(view).hasMatch()
|
||||||
|
? std::make_optional(view.toInt())
|
||||||
|
: std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimePart::setMaxValue(int value) {
|
||||||
|
_maxValue = value;
|
||||||
|
_maxDigits = 0;
|
||||||
|
while (value > 0) {
|
||||||
|
++_maxDigits;
|
||||||
|
value /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimePart::setWheelStep(int value) {
|
||||||
|
_wheelStep = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> TimePart::erasePrevious() const {
|
||||||
|
return _erasePrevious.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<QChar> TimePart::putNext() const {
|
||||||
|
return _putNext.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimePart::keyPressEvent(QKeyEvent *e) {
|
||||||
|
const auto isBackspace = (e->key() == Qt::Key_Backspace);
|
||||||
|
const auto isBeginning = (cursorPosition() == 0);
|
||||||
|
if (isBackspace && isBeginning && !hasSelectedText()) {
|
||||||
|
_erasePrevious.fire({});
|
||||||
|
} else {
|
||||||
|
MaskedInputField::keyPressEvent(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimePart::wheelEvent(QWheelEvent *e) {
|
||||||
|
const auto direction = WheelDirection(e);
|
||||||
|
const auto now = number();
|
||||||
|
if (!now.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto time = *now + (direction * _wheelStep);
|
||||||
|
const auto max = _maxValue + 1;
|
||||||
|
if (time < 0) {
|
||||||
|
time += max;
|
||||||
|
} else if (time >= max) {
|
||||||
|
time -= max;
|
||||||
|
}
|
||||||
|
setText(QString::number(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimePart::correctValue(
|
||||||
|
const QString &was,
|
||||||
|
int wasCursor,
|
||||||
|
QString &now,
|
||||||
|
int &nowCursor) {
|
||||||
|
auto newText = QString();
|
||||||
|
auto newCursor = -1;
|
||||||
|
const auto oldCursor = nowCursor;
|
||||||
|
const auto oldLength = now.size();
|
||||||
|
auto accumulated = 0;
|
||||||
|
auto limit = 0;
|
||||||
|
for (; limit != oldLength; ++limit) {
|
||||||
|
if (now[limit].isDigit()) {
|
||||||
|
accumulated *= 10;
|
||||||
|
accumulated += (now[limit].unicode() - '0');
|
||||||
|
if (accumulated > _maxValue || limit == _maxDigits) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto i = 0; i != limit;) {
|
||||||
|
if (now[i].isDigit()) {
|
||||||
|
newText += now[i];
|
||||||
|
}
|
||||||
|
if (++i == oldCursor) {
|
||||||
|
newCursor = newText.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newCursor < 0) {
|
||||||
|
newCursor = newText.size();
|
||||||
|
}
|
||||||
|
if (newText != now) {
|
||||||
|
now = newText;
|
||||||
|
setText(now);
|
||||||
|
startPlaceholderAnimation();
|
||||||
|
}
|
||||||
|
if (newCursor != nowCursor) {
|
||||||
|
nowCursor = newCursor;
|
||||||
|
setCursorPosition(nowCursor);
|
||||||
|
}
|
||||||
|
if (accumulated > _maxValue
|
||||||
|
|| (limit == _maxDigits && oldLength > _maxDigits)) {
|
||||||
|
if (oldCursor > limit) {
|
||||||
|
_putNext.fire('0' + (accumulated % 10));
|
||||||
|
} else {
|
||||||
|
_putNext.fire(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
||||||
44
ui/widgets/fields/time_part_input.h
Normal file
44
ui/widgets/fields/time_part_input.h
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
// This file is part of Desktop App Toolkit,
|
||||||
|
// a set of libraries for developing nice desktop applications.
|
||||||
|
//
|
||||||
|
// For license and copyright information please follow this link:
|
||||||
|
// https://github.com/desktop-app/legal/blob/master/LEGAL
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/widgets/input_fields.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class TimePart : public MaskedInputField {
|
||||||
|
public:
|
||||||
|
using MaskedInputField::MaskedInputField;
|
||||||
|
|
||||||
|
void setMaxValue(int value);
|
||||||
|
void setWheelStep(int value);
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<> erasePrevious() const;
|
||||||
|
[[nodiscard]] rpl::producer<QChar> putNext() const;
|
||||||
|
|
||||||
|
[[nodiscard]] std::optional<int> number();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
void wheelEvent(QWheelEvent *e) override;
|
||||||
|
|
||||||
|
void correctValue(
|
||||||
|
const QString &was,
|
||||||
|
int wasCursor,
|
||||||
|
QString &now,
|
||||||
|
int &nowCursor) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _maxValue = 0;
|
||||||
|
int _maxDigits = 0;
|
||||||
|
int _wheelStep = 0;
|
||||||
|
rpl::event_stream<> _erasePrevious;
|
||||||
|
rpl::event_stream<QChar> _putNext;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
||||||
|
|
@ -6,9 +6,7 @@
|
||||||
//
|
//
|
||||||
#include "ui/widgets/time_input.h"
|
#include "ui/widgets/time_input.h"
|
||||||
|
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/fields/time_part_input.h"
|
||||||
#include "ui/ui_utility.h"
|
|
||||||
#include "base/qt/qt_common_adapters.h"
|
|
||||||
|
|
||||||
#include <QtCore/QRegularExpression>
|
#include <QtCore/QRegularExpression>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
|
@ -48,145 +46,6 @@ QString GetMinute(const QString &value) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class TimePart final : public MaskedInputField {
|
|
||||||
public:
|
|
||||||
using MaskedInputField::MaskedInputField;
|
|
||||||
|
|
||||||
void setMaxValue(int value);
|
|
||||||
void setWheelStep(int value);
|
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> erasePrevious() const;
|
|
||||||
[[nodiscard]] rpl::producer<QChar> putNext() const;
|
|
||||||
|
|
||||||
[[nodiscard]] std::optional<int> number();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void keyPressEvent(QKeyEvent *e) override;
|
|
||||||
void wheelEvent(QWheelEvent *e) override;
|
|
||||||
|
|
||||||
void correctValue(
|
|
||||||
const QString &was,
|
|
||||||
int wasCursor,
|
|
||||||
QString &now,
|
|
||||||
int &nowCursor) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int _maxValue = 0;
|
|
||||||
int _maxDigits = 0;
|
|
||||||
int _wheelStep = 0;
|
|
||||||
rpl::event_stream<> _erasePrevious;
|
|
||||||
rpl::event_stream<QChar> _putNext;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
std::optional<int> TimePart::number() {
|
|
||||||
const auto text = getLastText();
|
|
||||||
auto view = QStringView(text);
|
|
||||||
while (view.size() > 1 && view.at(0) == '0') {
|
|
||||||
view = base::StringViewMid(view, 1);
|
|
||||||
}
|
|
||||||
return QRegularExpression("^\\d+$").match(view).hasMatch()
|
|
||||||
? std::make_optional(view.toInt())
|
|
||||||
: std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimePart::setMaxValue(int value) {
|
|
||||||
_maxValue = value;
|
|
||||||
_maxDigits = 0;
|
|
||||||
while (value > 0) {
|
|
||||||
++_maxDigits;
|
|
||||||
value /= 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimePart::setWheelStep(int value) {
|
|
||||||
_wheelStep = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
rpl::producer<> TimePart::erasePrevious() const {
|
|
||||||
return _erasePrevious.events();
|
|
||||||
}
|
|
||||||
|
|
||||||
rpl::producer<QChar> TimePart::putNext() const {
|
|
||||||
return _putNext.events();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimePart::keyPressEvent(QKeyEvent *e) {
|
|
||||||
const auto isBackspace = (e->key() == Qt::Key_Backspace);
|
|
||||||
const auto isBeginning = (cursorPosition() == 0);
|
|
||||||
if (isBackspace && isBeginning && !hasSelectedText()) {
|
|
||||||
_erasePrevious.fire({});
|
|
||||||
} else {
|
|
||||||
MaskedInputField::keyPressEvent(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimePart::wheelEvent(QWheelEvent *e) {
|
|
||||||
const auto direction = WheelDirection(e);
|
|
||||||
const auto now = number();
|
|
||||||
if (!now.has_value()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto time = *now + (direction * _wheelStep);
|
|
||||||
const auto max = _maxValue + 1;
|
|
||||||
if (time < 0) {
|
|
||||||
time += max;
|
|
||||||
} else if (time >= max) {
|
|
||||||
time -= max;
|
|
||||||
}
|
|
||||||
setText(QString::number(time));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TimePart::correctValue(
|
|
||||||
const QString &was,
|
|
||||||
int wasCursor,
|
|
||||||
QString &now,
|
|
||||||
int &nowCursor) {
|
|
||||||
auto newText = QString();
|
|
||||||
auto newCursor = -1;
|
|
||||||
const auto oldCursor = nowCursor;
|
|
||||||
const auto oldLength = now.size();
|
|
||||||
auto accumulated = 0;
|
|
||||||
auto limit = 0;
|
|
||||||
for (; limit != oldLength; ++limit) {
|
|
||||||
if (now[limit].isDigit()) {
|
|
||||||
accumulated *= 10;
|
|
||||||
accumulated += (now[limit].unicode() - '0');
|
|
||||||
if (accumulated > _maxValue || limit == _maxDigits) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto i = 0; i != limit;) {
|
|
||||||
if (now[i].isDigit()) {
|
|
||||||
newText += now[i];
|
|
||||||
}
|
|
||||||
if (++i == oldCursor) {
|
|
||||||
newCursor = newText.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (newCursor < 0) {
|
|
||||||
newCursor = newText.size();
|
|
||||||
}
|
|
||||||
if (newText != now) {
|
|
||||||
now = newText;
|
|
||||||
setText(now);
|
|
||||||
startPlaceholderAnimation();
|
|
||||||
}
|
|
||||||
if (newCursor != nowCursor) {
|
|
||||||
nowCursor = newCursor;
|
|
||||||
setCursorPosition(nowCursor);
|
|
||||||
}
|
|
||||||
if (accumulated > _maxValue
|
|
||||||
|| (limit == _maxDigits && oldLength > _maxDigits)) {
|
|
||||||
if (oldCursor > limit) {
|
|
||||||
_putNext.fire('0' + (accumulated % 10));
|
|
||||||
} else {
|
|
||||||
_putNext.fire(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeInput::TimeInput(
|
TimeInput::TimeInput(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
const QString &value,
|
const QString &value,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue