mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Support selecting messages range.
This commit is contained in:
parent
4414369fc8
commit
b7c95e9636
3 changed files with 314 additions and 39 deletions
|
@ -28,9 +28,9 @@ class CalendarBox::Context {
|
||||||
public:
|
public:
|
||||||
Context(QDate month, QDate highlighted);
|
Context(QDate month, QDate highlighted);
|
||||||
|
|
||||||
void setHasSelection(bool has);
|
void setAllowsSelection(bool allowsSelection);
|
||||||
[[nodiscard]] bool hasSelection() const {
|
[[nodiscard]] bool allowsSelection() const {
|
||||||
return _hasSelection;
|
return _allowsSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMinDate(QDate date);
|
void setMinDate(QDate date);
|
||||||
|
@ -66,20 +66,38 @@ public:
|
||||||
return (index >= _minDayIndex) && (index <= _maxDayIndex);
|
return (index >= _minDayIndex) && (index <= _maxDayIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] QDate month() const {
|
||||||
|
return _month.current();
|
||||||
|
}
|
||||||
[[nodiscard]] rpl::producer<QDate> monthValue() const {
|
[[nodiscard]] rpl::producer<QDate> monthValue() const {
|
||||||
return _month.value();
|
return _month.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
QDate dateFromIndex(int index) const;
|
[[nodiscard]] QDate dateFromIndex(int index) const;
|
||||||
QString labelFromIndex(int index) const;
|
[[nodiscard]] QString labelFromIndex(int index) const;
|
||||||
|
|
||||||
|
void toggleSelectionMode(bool enabled);
|
||||||
|
[[nodiscard]] bool selectionMode() const;
|
||||||
|
[[nodiscard]] rpl::producer<> selectionUpdates() const;
|
||||||
|
[[nodiscard]] std::optional<int> selectedMin() const;
|
||||||
|
[[nodiscard]] std::optional<int> selectedMax() const;
|
||||||
|
|
||||||
|
void startSelection(int index);
|
||||||
|
void updateSelection(int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Selection {
|
||||||
|
QDate min;
|
||||||
|
QDate max;
|
||||||
|
int minIndex = 0;
|
||||||
|
int maxIndex = 0;
|
||||||
|
};
|
||||||
void applyMonth(const QDate &month, bool forced = false);
|
void applyMonth(const QDate &month, bool forced = false);
|
||||||
|
|
||||||
static int DaysShiftForMonth(QDate month, QDate min);
|
static int DaysShiftForMonth(QDate month, QDate min);
|
||||||
static int RowsCountForMonth(QDate month, QDate min, QDate max);
|
static int RowsCountForMonth(QDate month, QDate min, QDate max);
|
||||||
|
|
||||||
bool _hasSelection = false;
|
bool _allowsSelection = false;
|
||||||
|
|
||||||
rpl::variable<QDate> _month;
|
rpl::variable<QDate> _month;
|
||||||
QDate _min, _max;
|
QDate _min, _max;
|
||||||
|
@ -94,6 +112,12 @@ private:
|
||||||
int _daysShift = 0;
|
int _daysShift = 0;
|
||||||
int _rowsCount = 0;
|
int _rowsCount = 0;
|
||||||
|
|
||||||
|
Selection _selection;
|
||||||
|
QDate _selectionStart;
|
||||||
|
int _selectionStartIndex = 0;
|
||||||
|
rpl::event_stream<> _selectionUpdates;
|
||||||
|
bool _selectionMode = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
CalendarBox::Context::Context(QDate month, QDate highlighted)
|
CalendarBox::Context::Context(QDate month, QDate highlighted)
|
||||||
|
@ -101,8 +125,8 @@ CalendarBox::Context::Context(QDate month, QDate highlighted)
|
||||||
showMonth(month);
|
showMonth(month);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalendarBox::Context::setHasSelection(bool has) {
|
void CalendarBox::Context::setAllowsSelection(bool allows) {
|
||||||
_hasSelection = has;
|
_allowsSelection = allows;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalendarBox::Context::setMinDate(QDate date) {
|
void CalendarBox::Context::setMinDate(QDate date) {
|
||||||
|
@ -128,17 +152,31 @@ bool CalendarBox::Context::showsMonthOf(QDate date) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalendarBox::Context::applyMonth(const QDate &month, bool forced) {
|
void CalendarBox::Context::applyMonth(const QDate &month, bool forced) {
|
||||||
|
const auto was = _month.current();
|
||||||
_daysCount = month.daysInMonth();
|
_daysCount = month.daysInMonth();
|
||||||
_daysShift = DaysShiftForMonth(month, _min);
|
_daysShift = DaysShiftForMonth(month, _min);
|
||||||
_rowsCount = RowsCountForMonth(month, _min, _max);
|
_rowsCount = RowsCountForMonth(month, _min, _max);
|
||||||
_highlightedIndex = month.daysTo(_highlighted);
|
_highlightedIndex = month.daysTo(_highlighted);
|
||||||
_minDayIndex = _min.isNull() ? INT_MIN : month.daysTo(_min);
|
_minDayIndex = _min.isNull() ? INT_MIN : month.daysTo(_min);
|
||||||
_maxDayIndex = _max.isNull() ? INT_MAX : month.daysTo(_max);
|
_maxDayIndex = _max.isNull() ? INT_MAX : month.daysTo(_max);
|
||||||
|
const auto shift = was.isNull() ? 0 : month.daysTo(was);
|
||||||
|
auto updated = false;
|
||||||
|
const auto update = [&](const QDate &date, int &index) {
|
||||||
|
if (shift && !date.isNull()) {
|
||||||
|
index += shift;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
update(_selection.min, _selection.minIndex);
|
||||||
|
update(_selection.max, _selection.maxIndex);
|
||||||
|
update(_selectionStart, _selectionStartIndex);
|
||||||
if (forced) {
|
if (forced) {
|
||||||
_month.force_assign(month);
|
_month.force_assign(month);
|
||||||
} else {
|
} else {
|
||||||
_month = month;
|
_month = month;
|
||||||
}
|
}
|
||||||
|
if (updated) {
|
||||||
|
_selectionUpdates.fire({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalendarBox::Context::skipMonth(int skip) {
|
void CalendarBox::Context::skipMonth(int skip) {
|
||||||
|
@ -235,6 +273,70 @@ QString CalendarBox::Context::labelFromIndex(int index) const {
|
||||||
return QString::number(day());
|
return QString::number(day());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CalendarBox::Context::toggleSelectionMode(bool enabled) {
|
||||||
|
if (_selectionMode == enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_selectionMode = enabled;
|
||||||
|
_selectionStart = {};
|
||||||
|
_selection = {};
|
||||||
|
_selectionUpdates.fire({});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CalendarBox::Context::selectionMode() const {
|
||||||
|
return _selectionMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> CalendarBox::Context::selectionUpdates() const {
|
||||||
|
return _selectionUpdates.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> CalendarBox::Context::selectedMin() const {
|
||||||
|
return _selection.min.isNull()
|
||||||
|
? std::optional<int>()
|
||||||
|
: _selection.minIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> CalendarBox::Context::selectedMax() const {
|
||||||
|
return _selection.max.isNull()
|
||||||
|
? std::optional<int>()
|
||||||
|
: _selection.maxIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CalendarBox::Context::startSelection(int index) {
|
||||||
|
Expects(_selectionMode);
|
||||||
|
|
||||||
|
if (!_selectionStart.isNull() && _selectionStartIndex == index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_selectionStartIndex = index;
|
||||||
|
_selectionStart = dateFromIndex(index);
|
||||||
|
updateSelection(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CalendarBox::Context::updateSelection(int index) {
|
||||||
|
Expects(_selectionMode);
|
||||||
|
Expects(!_selectionStart.isNull());
|
||||||
|
|
||||||
|
index = std::clamp(index, minDayIndex(), maxDayIndex());
|
||||||
|
const auto start = _selectionStartIndex;
|
||||||
|
const auto min = std::min(index, start);
|
||||||
|
const auto max = std::max(index, start);
|
||||||
|
if (!_selection.min.isNull()
|
||||||
|
&& _selection.minIndex == min
|
||||||
|
&& !_selection.max.isNull()
|
||||||
|
&& _selection.maxIndex == max) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_selection = Selection{
|
||||||
|
.min = dateFromIndex(min),
|
||||||
|
.max = dateFromIndex(max),
|
||||||
|
.minIndex = min,
|
||||||
|
.maxIndex = max,
|
||||||
|
};
|
||||||
|
_selectionUpdates.fire({});
|
||||||
|
}
|
||||||
|
|
||||||
class CalendarBox::Inner final : public RpWidget {
|
class CalendarBox::Inner final : public RpWidget {
|
||||||
public:
|
public:
|
||||||
Inner(
|
Inner(
|
||||||
|
@ -294,6 +396,11 @@ CalendarBox::Inner::Inner(
|
||||||
) | rpl::start_with_next([=](QDate month) {
|
) | rpl::start_with_next([=](QDate month) {
|
||||||
monthChanged(month);
|
monthChanged(month);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
context->selectionUpdates(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
update();
|
||||||
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalendarBox::Inner::monthChanged(QDate month) {
|
void CalendarBox::Inner::monthChanged(QDate month) {
|
||||||
|
@ -329,7 +436,13 @@ void CalendarBox::Inner::paintRows(Painter &p, QRect clip) {
|
||||||
p.setFont(st::calendarDaysFont);
|
p.setFont(st::calendarDaysFont);
|
||||||
auto y = rowsTop();
|
auto y = rowsTop();
|
||||||
auto index = -_context->daysShift();
|
auto index = -_context->daysShift();
|
||||||
auto highlightedIndex = _context->highlightedIndex();
|
const auto selectionMode = _context->selectionMode();
|
||||||
|
const auto impossible = index - 45;
|
||||||
|
const auto selectedMin = _context->selectedMin().value_or(impossible);
|
||||||
|
const auto selectedMax = _context->selectedMax().value_or(impossible);
|
||||||
|
const auto highlightedIndex = selectionMode
|
||||||
|
? impossible
|
||||||
|
: _context->highlightedIndex();
|
||||||
const auto daysCount = _context->daysCount();
|
const auto daysCount = _context->daysCount();
|
||||||
const auto rowsCount = _context->rowsCount();
|
const auto rowsCount = _context->rowsCount();
|
||||||
const auto rowHeight = _st.cellSize.height();
|
const auto rowHeight = _st.cellSize.height();
|
||||||
|
@ -339,31 +452,59 @@ void CalendarBox::Inner::paintRows(Painter &p, QRect clip) {
|
||||||
rowsCount);
|
rowsCount);
|
||||||
y += fromRow * rowHeight;
|
y += fromRow * rowHeight;
|
||||||
index += fromRow * kDaysInWeek;
|
index += fromRow * kDaysInWeek;
|
||||||
|
const auto innerSkipLeft = (_st.cellSize.width() - _st.cellInner) / 2;
|
||||||
|
const auto innerSkipTop = (_st.cellSize.height() - _st.cellInner) / 2;
|
||||||
for (auto row = fromRow; row != tillRow; ++row, y += rowHeight) {
|
for (auto row = fromRow; row != tillRow; ++row, y += rowHeight) {
|
||||||
auto x = rowsLeft();
|
auto x = rowsLeft();
|
||||||
|
const auto fromIndex = index;
|
||||||
|
const auto tillIndex = (index + kDaysInWeek);
|
||||||
|
const auto selectedFrom = std::max(fromIndex, selectedMin);
|
||||||
|
const auto selectedTill = std::min(tillIndex, selectedMax + 1);
|
||||||
|
const auto selectedInRow = (selectedTill - selectedFrom);
|
||||||
|
if (selectedInRow > 0) {
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(st::lightButtonBgOver);
|
||||||
|
p.drawRoundedRect(
|
||||||
|
(x
|
||||||
|
+ (selectedFrom - index) * _st.cellSize.width()
|
||||||
|
+ innerSkipLeft
|
||||||
|
- st::lineWidth),
|
||||||
|
y + innerSkipTop - st::lineWidth,
|
||||||
|
((selectedInRow - 1) * _st.cellSize.width()
|
||||||
|
+ 2 * st::lineWidth
|
||||||
|
+ _st.cellInner),
|
||||||
|
_st.cellInner + 2 * st::lineWidth,
|
||||||
|
(_st.cellInner / 2.) + st::lineWidth,
|
||||||
|
(_st.cellInner / 2.) + st::lineWidth);
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
}
|
||||||
for (auto col = 0; col != kDaysInWeek; ++col, ++index, x += _st.cellSize.width()) {
|
for (auto col = 0; col != kDaysInWeek; ++col, ++index, x += _st.cellSize.width()) {
|
||||||
auto rect = myrtlrect(x, y, _st.cellSize.width(), _st.cellSize.height());
|
const auto rect = myrtlrect(x, y, _st.cellSize.width(), _st.cellSize.height());
|
||||||
auto grayedOut = (index < 0 || index >= daysCount || !rect.intersects(clip));
|
const auto selected = (index >= selectedMin) && (index <= selectedMax);
|
||||||
auto highlighted = (index == highlightedIndex);
|
const auto grayedOut = !selected && (index < 0 || index >= daysCount);
|
||||||
auto enabled = _context->isEnabled(index);
|
const auto highlighted = (index == highlightedIndex);
|
||||||
auto innerLeft = x + (_st.cellSize.width() - _st.cellInner) / 2;
|
const auto enabled = _context->isEnabled(index);
|
||||||
auto innerTop = y + (_st.cellSize.height() - _st.cellInner) / 2;
|
const auto innerLeft = x + innerSkipLeft;
|
||||||
|
const auto innerTop = y + innerSkipTop;
|
||||||
if (highlighted) {
|
if (highlighted) {
|
||||||
PainterHighQualityEnabler hq(p);
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.setBrush(grayedOut ? st::windowBgOver : st::dialogsBgActive);
|
p.setBrush(grayedOut ? st::windowBgOver : st::dialogsBgActive);
|
||||||
p.drawEllipse(myrtlrect(innerLeft, innerTop, _st.cellInner, _st.cellInner));
|
p.drawEllipse(myrtlrect(innerLeft, innerTop, _st.cellInner, _st.cellInner));
|
||||||
p.setBrush(Qt::NoBrush);
|
p.setBrush(Qt::NoBrush);
|
||||||
}
|
}
|
||||||
auto it = _ripples.find(index);
|
const auto it = _ripples.find(index);
|
||||||
if (it != _ripples.cend()) {
|
if (it != _ripples.cend()) {
|
||||||
auto colorOverride = [highlighted, grayedOut] {
|
const auto colorOverride = [&] {
|
||||||
if (highlighted) {
|
if (selectionMode) {
|
||||||
|
return st::lightButtonBgOver;
|
||||||
|
} else if (highlighted) {
|
||||||
return grayedOut ? st::windowBgRipple : st::dialogsRippleBgActive;
|
return grayedOut ? st::windowBgRipple : st::dialogsRippleBgActive;
|
||||||
}
|
}
|
||||||
return st::windowBgOver;
|
return st::windowBgOver;
|
||||||
};
|
}()->c;
|
||||||
it->second->paint(p, innerLeft, innerTop, width(), &(colorOverride()->c));
|
it->second->paint(p, innerLeft, innerTop, width(), &colorOverride);
|
||||||
if (it->second->empty()) {
|
if (it->second->empty()) {
|
||||||
_ripples.erase(it);
|
_ripples.erase(it);
|
||||||
}
|
}
|
||||||
|
@ -400,6 +541,20 @@ void CalendarBox::Inner::mouseMoveEvent(QMouseEvent *e) {
|
||||||
} else {
|
} else {
|
||||||
setSelected(kEmptySelection);
|
setSelected(kEmptySelection);
|
||||||
}
|
}
|
||||||
|
if (_pressed != kEmptySelection && _context->selectionMode()) {
|
||||||
|
const auto row = (point.y() >= rowsTop())
|
||||||
|
? (point.y() - rowsTop()) / size.height()
|
||||||
|
: -1;
|
||||||
|
const auto col = (point.y() < rowsTop())
|
||||||
|
? 0
|
||||||
|
: (point.x() >= rowsLeft())
|
||||||
|
? std::min(
|
||||||
|
(point.x() - rowsLeft()) / size.width(),
|
||||||
|
kDaysInWeek - 1)
|
||||||
|
: 0;
|
||||||
|
const auto index = row * kDaysInWeek + col - _context->daysShift();
|
||||||
|
_context->updateSelection(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalendarBox::Inner::setSelected(int selected) {
|
void CalendarBox::Inner::setSelected(int selected) {
|
||||||
|
@ -440,13 +595,24 @@ void CalendarBox::Inner::mousePressEvent(QMouseEvent *e) {
|
||||||
}
|
}
|
||||||
auto ripplePosition = QPoint(cell.x() + (_st.cellSize.width() - _st.cellInner) / 2, cell.y() + (_st.cellSize.height() - _st.cellInner) / 2);
|
auto ripplePosition = QPoint(cell.x() + (_st.cellSize.width() - _st.cellInner) / 2, cell.y() + (_st.cellSize.height() - _st.cellInner) / 2);
|
||||||
it->second->add(e->pos() - ripplePosition);
|
it->second->add(e->pos() - ripplePosition);
|
||||||
|
|
||||||
|
if (_context->selectionMode()) {
|
||||||
|
if (_context->selectedMin().has_value()
|
||||||
|
&& (e->modifiers() & Qt::ShiftModifier)) {
|
||||||
|
_context->updateSelection(_selected);
|
||||||
|
} else {
|
||||||
|
_context->startSelection(_selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalendarBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
void CalendarBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
auto pressed = _pressed;
|
auto pressed = _pressed;
|
||||||
setPressed(kEmptySelection);
|
setPressed(kEmptySelection);
|
||||||
if (pressed != kEmptySelection && pressed == _selected) {
|
if (pressed != kEmptySelection
|
||||||
|
&& pressed == _selected
|
||||||
|
&& !_context->selectionMode()) {
|
||||||
crl::on_main(this, [=] {
|
crl::on_main(this, [=] {
|
||||||
const auto onstack = _dateChosenCallback;
|
const auto onstack = _dateChosenCallback;
|
||||||
onstack(_context->dateFromIndex(pressed));
|
onstack(_context->dateFromIndex(pressed));
|
||||||
|
@ -490,7 +656,8 @@ protected:
|
||||||
void paintEvent(QPaintEvent *e);
|
void paintEvent(QPaintEvent *e);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void monthChanged(QDate month);
|
void setTextFromMonth(QDate month);
|
||||||
|
void setText(QString text);
|
||||||
void paintDayNames(Painter &p, QRect clip);
|
void paintDayNames(Painter &p, QRect clip);
|
||||||
|
|
||||||
const style::CalendarSizes &_st;
|
const style::CalendarSizes &_st;
|
||||||
|
@ -513,13 +680,30 @@ CalendarBox::Title::Title(
|
||||||
_textLeft = _st.padding.left() + (_st.cellSize.width() - dayWidth) / 2;
|
_textLeft = _st.padding.left() + (_st.cellSize.width() - dayWidth) / 2;
|
||||||
|
|
||||||
_context->monthValue(
|
_context->monthValue(
|
||||||
) | rpl::start_with_next([=](QDate date) {
|
) | rpl::filter([=] {
|
||||||
monthChanged(date);
|
return !_context->selectionMode();
|
||||||
|
}) | rpl::start_with_next([=](QDate date) {
|
||||||
|
setTextFromMonth(date);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_context->selectionUpdates(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
if (!_context->selectionMode()) {
|
||||||
|
setTextFromMonth(_context->month());
|
||||||
|
} else if (!_context->selectedMin()) {
|
||||||
|
setText(tr::lng_calendar_select_days(tr::now));
|
||||||
|
} else {
|
||||||
|
setText(QString::number(1 + *_context->selectedMax() - *_context->selectedMin())); // #TODO calendar
|
||||||
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalendarBox::Title::monthChanged(QDate month) {
|
void CalendarBox::Title::setTextFromMonth(QDate month) {
|
||||||
_text = langMonthOfYearFull(month.month(), month.year());
|
setText(langMonthOfYearFull(month.month(), month.year()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CalendarBox::Title::setText(QString text) {
|
||||||
|
_text = std::move(text);
|
||||||
_textWidth = st::calendarTitleFont->width(_text);
|
_textWidth = st::calendarTitleFont->width(_text);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
@ -570,9 +754,10 @@ CalendarBox::CalendarBox(QWidget*, CalendarBoxArgs &&args)
|
||||||
, _next(this, st::calendarNext)
|
, _next(this, st::calendarNext)
|
||||||
, _callback(std::move(args.callback.value()))
|
, _callback(std::move(args.callback.value()))
|
||||||
, _finalize(std::move(args.finalize))
|
, _finalize(std::move(args.finalize))
|
||||||
, _jumpTimer([=] { jump(_jumpButton); }) {
|
, _jumpTimer([=] { jump(_jumpButton); })
|
||||||
|
, _selectionChanged(std::move(args.selectionChanged)) {
|
||||||
_title->setAttribute(Qt::WA_TransparentForMouseEvents);
|
_title->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
_context->setHasSelection(args.allowsSelection);
|
_context->setAllowsSelection(args.allowsSelection);
|
||||||
_context->setMinDate(args.minDate);
|
_context->setMinDate(args.minDate);
|
||||||
_context->setMaxDate(args.maxDate);
|
_context->setMaxDate(args.maxDate);
|
||||||
|
|
||||||
|
@ -612,6 +797,12 @@ CalendarBox::CalendarBox(QWidget*, CalendarBoxArgs &&args)
|
||||||
setupJumps(_next.data(), &_nextEnabled);
|
setupJumps(_next.data(), &_nextEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CalendarBox::~CalendarBox() = default;
|
||||||
|
|
||||||
|
void CalendarBox::toggleSelectionMode(bool enabled) {
|
||||||
|
_context->toggleSelectionMode(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
void CalendarBox::showJumpTooltip(not_null<IconButton*> button) {
|
void CalendarBox::showJumpTooltip(not_null<IconButton*> button) {
|
||||||
_tooltipButton = button;
|
_tooltipButton = button;
|
||||||
Ui::Tooltip::Show(kTooltipDelay, this);
|
Ui::Tooltip::Show(kTooltipDelay, this);
|
||||||
|
@ -644,21 +835,33 @@ void CalendarBox::prepare() {
|
||||||
|
|
||||||
_inner->setDateChosenCallback(std::move(_callback));
|
_inner->setDateChosenCallback(std::move(_callback));
|
||||||
|
|
||||||
addButton(tr::lng_close(), [=] { closeBox(); });
|
|
||||||
|
|
||||||
_context->monthValue(
|
_context->monthValue(
|
||||||
) | rpl::start_with_next([=](QDate month) {
|
) | rpl::start_with_next([=](QDate month) {
|
||||||
monthChanged(month);
|
monthChanged(month);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
setExactScroll();
|
setExactScroll();
|
||||||
|
|
||||||
|
_context->selectionUpdates(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_selectionMode = _context->selectionMode();
|
||||||
|
if (_selectionChanged) {
|
||||||
|
const auto count = !_selectionMode
|
||||||
|
? std::optional<int>()
|
||||||
|
: !_context->selectedMin()
|
||||||
|
? 0
|
||||||
|
: (1 + *_context->selectedMax() - *_context->selectedMin());
|
||||||
|
_selectionChanged(this, count);
|
||||||
|
}
|
||||||
|
if (!_selectionMode) {
|
||||||
|
clearButtons();
|
||||||
|
createButtons();
|
||||||
|
}
|
||||||
|
}, lifetime());
|
||||||
|
createButtons();
|
||||||
|
|
||||||
if (_finalize) {
|
if (_finalize) {
|
||||||
_finalize(this);
|
_finalize(this);
|
||||||
}
|
}
|
||||||
if (_context->hasSelection()) {
|
|
||||||
addLeftButton(tr::lng_calendar_select_days(), [=] {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CalendarBox::isPreviousEnabled() const {
|
bool CalendarBox::isPreviousEnabled() const {
|
||||||
|
@ -714,6 +917,21 @@ void CalendarBox::processScroll() {
|
||||||
_watchScroll = true;
|
_watchScroll = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CalendarBox::createButtons() {
|
||||||
|
if (!_context->allowsSelection()) {
|
||||||
|
addButton(tr::lng_close(), [=] { closeBox(); });
|
||||||
|
} else if (!_context->selectionMode()) {
|
||||||
|
addButton(tr::lng_close(), [=] { closeBox(); });
|
||||||
|
addLeftButton(tr::lng_calendar_select_days(), [=] {
|
||||||
|
_context->toggleSelectionMode(true);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
addButton(tr::lng_cancel(), [=] {
|
||||||
|
_context->toggleSelectionMode(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString CalendarBox::tooltipText() const {
|
QString CalendarBox::tooltipText() const {
|
||||||
if (_tooltipButton == _previous.data()) {
|
if (_tooltipButton == _previous.data()) {
|
||||||
return tr::lng_calendar_start_tip(tr::now);
|
return tr::lng_calendar_start_tip(tr::now);
|
||||||
|
@ -737,14 +955,14 @@ void CalendarBox::monthChanged(QDate month) {
|
||||||
_previousEnabled = isPreviousEnabled();
|
_previousEnabled = isPreviousEnabled();
|
||||||
_previous->setIconOverride(_previousEnabled ? nullptr : &st::calendarPreviousDisabled);
|
_previous->setIconOverride(_previousEnabled ? nullptr : &st::calendarPreviousDisabled);
|
||||||
_previous->setRippleColorOverride(_previousEnabled ? nullptr : &st::boxBg);
|
_previous->setRippleColorOverride(_previousEnabled ? nullptr : &st::boxBg);
|
||||||
_previous->setCursor(_previousEnabled ? style::cur_pointer : style::cur_default);
|
_previous->setPointerCursor(_previousEnabled);
|
||||||
if (!_previousEnabled) {
|
if (!_previousEnabled) {
|
||||||
_previous->clearState();
|
_previous->clearState();
|
||||||
}
|
}
|
||||||
_nextEnabled = isNextEnabled();
|
_nextEnabled = isNextEnabled();
|
||||||
_next->setIconOverride(_nextEnabled ? nullptr : &st::calendarNextDisabled);
|
_next->setIconOverride(_nextEnabled ? nullptr : &st::calendarNextDisabled);
|
||||||
_next->setRippleColorOverride(_nextEnabled ? nullptr : &st::boxBg);
|
_next->setRippleColorOverride(_nextEnabled ? nullptr : &st::boxBg);
|
||||||
_next->setCursor(_nextEnabled ? style::cur_pointer : style::cur_default);
|
_next->setPointerCursor(_nextEnabled);
|
||||||
if (!_nextEnabled) {
|
if (!_nextEnabled) {
|
||||||
_next->clearState();
|
_next->clearState();
|
||||||
}
|
}
|
||||||
|
@ -782,6 +1000,4 @@ void CalendarBox::keyPressEvent(QKeyEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CalendarBox::~CalendarBox() = default;
|
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -38,6 +38,9 @@ struct CalendarBoxArgs {
|
||||||
QDate minDate;
|
QDate minDate;
|
||||||
QDate maxDate;
|
QDate maxDate;
|
||||||
bool allowsSelection = false;
|
bool allowsSelection = false;
|
||||||
|
Fn<void(
|
||||||
|
not_null<Ui::CalendarBox*>,
|
||||||
|
std::optional<int>)> selectionChanged;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CalendarBox final : public BoxContent, private AbstractTooltipShower {
|
class CalendarBox final : public BoxContent, private AbstractTooltipShower {
|
||||||
|
@ -45,6 +48,8 @@ public:
|
||||||
CalendarBox(QWidget*, CalendarBoxArgs &&args);
|
CalendarBox(QWidget*, CalendarBoxArgs &&args);
|
||||||
~CalendarBox();
|
~CalendarBox();
|
||||||
|
|
||||||
|
void toggleSelectionMode(bool enabled);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
|
|
||||||
|
@ -61,6 +66,7 @@ private:
|
||||||
void goNextMonth();
|
void goNextMonth();
|
||||||
void setExactScroll();
|
void setExactScroll();
|
||||||
void processScroll();
|
void processScroll();
|
||||||
|
void createButtons();
|
||||||
|
|
||||||
void showJumpTooltip(not_null<IconButton*> button);
|
void showJumpTooltip(not_null<IconButton*> button);
|
||||||
void jumpAfterDelay(not_null<IconButton*> button);
|
void jumpAfterDelay(not_null<IconButton*> button);
|
||||||
|
@ -95,6 +101,11 @@ private:
|
||||||
QPointer<IconButton> _jumpButton;
|
QPointer<IconButton> _jumpButton;
|
||||||
base::Timer _jumpTimer;
|
base::Timer _jumpTimer;
|
||||||
|
|
||||||
|
bool _selectionMode = false;
|
||||||
|
Fn<void(
|
||||||
|
not_null<Ui::CalendarBox*>,
|
||||||
|
std::optional<int>)> _selectionChanged;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -1207,6 +1207,53 @@ void SessionController::showJumpToDate(Dialogs::Key chat, QDate requestedDate) {
|
||||||
: !currentPeerDate.isNull()
|
: !currentPeerDate.isNull()
|
||||||
? currentPeerDate
|
? currentPeerDate
|
||||||
: QDate::currentDate();
|
: QDate::currentDate();
|
||||||
|
struct ButtonState {
|
||||||
|
enum class Type {
|
||||||
|
None,
|
||||||
|
Disabled,
|
||||||
|
Active,
|
||||||
|
};
|
||||||
|
Type type = Type::None;
|
||||||
|
style::complex_color disabledFg = style::complex_color([] {
|
||||||
|
auto result = st::attentionBoxButton.textFg->c;
|
||||||
|
result.setAlpha(result.alpha() / 2);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
style::RoundButton disabled = st::attentionBoxButton;
|
||||||
|
};
|
||||||
|
const auto buttonState = std::make_shared<ButtonState>();
|
||||||
|
buttonState->disabled.textFg
|
||||||
|
= buttonState->disabled.textFgOver
|
||||||
|
= buttonState->disabledFg.color();
|
||||||
|
buttonState->disabled.ripple.color
|
||||||
|
= buttonState->disabled.textBgOver
|
||||||
|
= buttonState->disabled.textBg;
|
||||||
|
const auto selectionChanged = [=](
|
||||||
|
not_null<Ui::CalendarBox*> box,
|
||||||
|
std::optional<int> selected) {
|
||||||
|
if (!selected.has_value()) {
|
||||||
|
buttonState->type = ButtonState::Type::None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto type = (*selected > 0)
|
||||||
|
? ButtonState::Type::Active
|
||||||
|
: ButtonState::Type::Disabled;
|
||||||
|
if (buttonState->type == type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buttonState->type = type;
|
||||||
|
box->clearButtons();
|
||||||
|
box->addButton(tr::lng_cancel(), [=] {
|
||||||
|
box->toggleSelectionMode(false);
|
||||||
|
});
|
||||||
|
auto text = tr::lng_profile_clear_history();
|
||||||
|
const auto button = box->addLeftButton(std::move(text), [=] {
|
||||||
|
|
||||||
|
}, (*selected > 0) ? st::attentionBoxButton : buttonState->disabled);
|
||||||
|
if (!*selected) {
|
||||||
|
button->setPointerCursor(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
show(Box<Ui::CalendarBox>(Ui::CalendarBoxArgs{
|
show(Box<Ui::CalendarBox>(Ui::CalendarBoxArgs{
|
||||||
.month = highlighted,
|
.month = highlighted,
|
||||||
.highlighted = highlighted,
|
.highlighted = highlighted,
|
||||||
|
@ -1216,6 +1263,7 @@ void SessionController::showJumpToDate(Dialogs::Key chat, QDate requestedDate) {
|
||||||
.minDate = minPeerDate,
|
.minDate = minPeerDate,
|
||||||
.maxDate = maxPeerDate,
|
.maxDate = maxPeerDate,
|
||||||
.allowsSelection = history->peer->isUser(),
|
.allowsSelection = history->peer->isUser(),
|
||||||
|
.selectionChanged = selectionChanged,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue