diff --git a/ui/colors.palette b/ui/colors.palette index 7147e11..47d0f4d 100644 --- a/ui/colors.palette +++ b/ui/colors.palette @@ -555,6 +555,7 @@ callHangupRipple: #c04646; // phone call popup hangup button ripple effect callMuteRipple: #ffffff12; // phone call popup mute mic and camera ripple effect groupCallBg: #131417; // group call popup background +groupCallActiveFg: #4db8ff; // group call active controls text groupCallMembersBg: #1a1c1f; // group call members list background groupCallMembersFg: #ffffff; // group call member name text groupCallMembersRipple: #22252a; // group call member row ripple effect @@ -569,6 +570,8 @@ groupCallLive1: #0dcc39; // group call live button color1 groupCallLive2: #0bb6bd; // group call live button color2 groupCallMuted1: #0992ef; // group call muted button color1 groupCallMuted2: #16ccfb; // group call muted button color2 +groupCallBoxButtonBgOver: #1d2a39; // group call button in box with mouse over +groupCallBoxButtonBgRipple: #223143; // group call button in box ripple effect callBarBg: dialogsBgActive; // active phone call bar background callBarMuteRipple: dialogsRippleBgActive; // active phone call bar mute and hangup button ripple effect diff --git a/ui/layers/box_content.cpp b/ui/layers/box_content.cpp index 2a9ff65..cd6a406 100644 --- a/ui/layers/box_content.cpp +++ b/ui/layers/box_content.cpp @@ -29,7 +29,7 @@ QPointer BoxContent::addButton( return addButton( std::move(text), std::move(clickCallback), - st::defaultBoxButton); + getDelegate()->style().button); } QPointer BoxContent::addLeftButton( @@ -38,7 +38,7 @@ QPointer BoxContent::addLeftButton( return getDelegate()->addLeftButton( std::move(text), std::move(clickCallback), - st::defaultBoxButton); + getDelegate()->style().button); } void BoxContent::setInner(object_ptr inner) { @@ -245,8 +245,9 @@ void BoxContent::paintEvent(QPaintEvent *e) { Painter p(this); if (testAttribute(Qt::WA_OpaquePaintEvent)) { + const auto &color = getDelegate()->style().bg; for (const auto rect : e->region()) { - p.fillRect(rect, st::boxBg); + p.fillRect(rect, color); } } } diff --git a/ui/layers/box_content.h b/ui/layers/box_content.h index f293fe4..1c81444 100644 --- a/ui/layers/box_content.h +++ b/ui/layers/box_content.h @@ -45,6 +45,7 @@ class BoxContentDelegate { public: virtual void setLayerType(bool layerType) = 0; virtual void setStyle(const style::Box &st) = 0; + virtual const style::Box &style() = 0; virtual void setTitle(rpl::producer title) = 0; virtual void setAdditionalTitle(rpl::producer additional) = 0; virtual void setCloseByOutsideClick(bool close) = 0; diff --git a/ui/layers/box_layer_widget.cpp b/ui/layers/box_layer_widget.cpp index 6d38cb0..a7075ec 100644 --- a/ui/layers/box_layer_widget.cpp +++ b/ui/layers/box_layer_widget.cpp @@ -42,7 +42,7 @@ BoxLayerWidget::BoxLayerWidget( : LayerWidget(layer) , _layer(layer) , _content(std::move(content)) -, _roundRect(ImageRoundRadius::Small, st::boxBg) { +, _roundRect(ImageRoundRadius::Small, st().bg) { _content->setParent(this); _content->setDelegate(this); @@ -74,12 +74,21 @@ const style::Box &BoxLayerWidget::st() const { return _st ? *_st : _layerType - ? st::layerBox - : st::defaultBox; + ? (_layer->boxStyleOverrideLayer() + ? *_layer->boxStyleOverrideLayer() + : st::layerBox) + : (_layer->boxStyleOverride() + ? *_layer->boxStyleOverride() + : st::defaultBox); } void BoxLayerWidget::setStyle(const style::Box &st) { _st = &st; + _roundRect.setColor(st.bg); +} + +const style::Box &BoxLayerWidget::style() { + return st(); } int BoxLayerWidget::buttonsHeight() const { @@ -118,7 +127,7 @@ void BoxLayerWidget::paintEvent(QPaintEvent *e) { auto other = e->region().intersected(QRect(0, st::boxRadius, width(), height() - 2 * st::boxRadius)); if (!other.isEmpty()) { for (const auto rect : other) { - p.fillRect(rect, st::boxBg); + p.fillRect(rect, st().bg); } } if (!_additionalTitle.current().isEmpty() @@ -137,21 +146,29 @@ void BoxLayerWidget::paintEvent(QPaintEvent *e) { void BoxLayerWidget::paintAdditionalTitle(Painter &p) { p.setFont(st::boxTitleAdditionalFont); - p.setPen(st::boxTitleAdditionalFg); - p.drawTextLeft(_titleLeft + (_title ? _title->width() : 0) + st::boxTitleAdditionalSkip, _titleTop + st::boxTitleFont->ascent - st::boxTitleAdditionalFont->ascent, width(), _additionalTitle.current()); + p.setPen(st().titleAdditionalFg); + p.drawTextLeft( + _titleLeft + (_title ? _title->width() : 0) + st::boxTitleAdditionalSkip, + _titleTop + st::boxTitleFont->ascent - st::boxTitleAdditionalFont->ascent, + width(), + _additionalTitle.current()); } void BoxLayerWidget::parentResized() { auto newHeight = countRealHeight(); auto parentSize = parentWidget()->size(); - setGeometry((parentSize.width() - width()) / 2, (parentSize.height() - newHeight) / 2, width(), newHeight); + setGeometry( + (parentSize.width() - width()) / 2, + (parentSize.height() - newHeight) / 2, + width(), + newHeight); update(); } void BoxLayerWidget::setTitle(rpl::producer title) { const auto wasTitle = hasTitle(); if (title) { - _title.create(this, rpl::duplicate(title), st::boxTitle); + _title.create(this, rpl::duplicate(title), st().title); _title->show(); std::move( title @@ -323,9 +340,10 @@ void BoxLayerWidget::setDimensions(int newWidth, int maxHeight, bool forceCenter resize(newWidth, countRealHeight()); auto newGeometry = geometry(); auto parentHeight = parentWidget()->height(); - if (newGeometry.top() + newGeometry.height() + st::boxVerticalMargin > parentHeight + const auto bottomMargin = st().margin.bottom(); + if (newGeometry.top() + newGeometry.height() + bottomMargin > parentHeight || forceCenterPosition) { - const auto top1 = parentHeight - int(st::boxVerticalMargin) - newGeometry.height(); + const auto top1 = parentHeight - bottomMargin - newGeometry.height(); const auto top2 = (parentHeight - newGeometry.height()) / 2; const auto newTop = forceCenterPosition ? std::min(top1, top2) @@ -343,7 +361,10 @@ void BoxLayerWidget::setDimensions(int newWidth, int maxHeight, bool forceCenter } int BoxLayerWidget::countRealHeight() const { - return qMin(_fullHeight, parentWidget()->height() - 2 * st::boxVerticalMargin); + const auto &margin = st().margin; + return std::min( + _fullHeight, + parentWidget()->height() - margin.top() - margin.bottom()); } int BoxLayerWidget::countFullHeight() const { diff --git a/ui/layers/box_layer_widget.h b/ui/layers/box_layer_widget.h index 0313b66..9d195ce 100644 --- a/ui/layers/box_layer_widget.h +++ b/ui/layers/box_layer_widget.h @@ -45,6 +45,7 @@ public: void setLayerType(bool layerType) override; void setStyle(const style::Box &st) override; + const style::Box &style() override; void setTitle(rpl::producer title) override; void setAdditionalTitle(rpl::producer additional) override; void showBox( diff --git a/ui/layers/layer_manager.cpp b/ui/layers/layer_manager.cpp index 6ebbaa0..b5ca389 100644 --- a/ui/layers/layer_manager.cpp +++ b/ui/layers/layer_manager.cpp @@ -11,6 +11,16 @@ namespace Ui { LayerManager::LayerManager(not_null widget) : _widget(widget) { } +void LayerManager::setStyleOverrides( + const style::Box *boxSt, + const style::Box *layerSt) { + _boxSt = boxSt; + _layerSt = layerSt; + if (_layer) { + _layer->setStyleOverrides(_boxSt, _layerSt); + } +} + void LayerManager::setHideByBackgroundClick(bool hide) { _hideByBackgroundClick = hide; if (_layer) { @@ -55,6 +65,7 @@ void LayerManager::ensureLayerCreated() { } _layer.emplace(_widget); _layer->setHideByBackgroundClick(_hideByBackgroundClick); + _layer->setStyleOverrides(_boxSt, _layerSt); _layer->hideFinishEvents( ) | rpl::filter([=] { diff --git a/ui/layers/layer_manager.h b/ui/layers/layer_manager.h index 1f0d31e..4f53169 100644 --- a/ui/layers/layer_manager.h +++ b/ui/layers/layer_manager.h @@ -10,6 +10,10 @@ #include +namespace style { +struct Box; +} // namespace style + namespace Ui { class BoxContent; @@ -19,6 +23,10 @@ class LayerManager final { public: explicit LayerManager(not_null widget); + void setStyleOverrides( + const style::Box *boxSt, + const style::Box *layerSt); + void setHideByBackgroundClick(bool hide); void showBox( object_ptr box, @@ -34,6 +42,9 @@ private: const not_null _widget; base::unique_qptr _layer; + + const style::Box *_boxSt = nullptr; + const style::Box *_layerSt = nullptr; bool _hideByBackgroundClick = false; }; diff --git a/ui/layers/layer_widget.cpp b/ui/layers/layer_widget.cpp index b60cf69..c0ffe93 100644 --- a/ui/layers/layer_widget.cpp +++ b/ui/layers/layer_widget.cpp @@ -458,6 +458,13 @@ bool LayerStackWidget::layerShown() const { return _specialLayer || currentLayer() || _mainMenu; } +void LayerStackWidget::setStyleOverrides( + const style::Box *boxSt, + const style::Box *layerSt) { + _boxSt = boxSt; + _layerSt = layerSt; +} + void LayerStackWidget::setCacheImages() { auto bodyCache = QPixmap(), mainMenuCache = QPixmap(); auto specialLayerCache = QPixmap(); diff --git a/ui/layers/layer_widget.h b/ui/layers/layer_widget.h index 94344a0..f673678 100644 --- a/ui/layers/layer_widget.h +++ b/ui/layers/layer_widget.h @@ -16,6 +16,10 @@ class SectionMemento; struct SectionShow; } // namespace Window +namespace style { +struct Box; +} // namespace style + namespace Ui { class BoxContent; @@ -93,6 +97,16 @@ public: void finishAnimating(); rpl::producer<> hideFinishEvents() const; + void setStyleOverrides( + const style::Box *boxSt, + const style::Box *layerSt); + [[nodiscard]] const style::Box *boxStyleOverrideLayer() const { + return _layerSt; + } + [[nodiscard]] const style::Box *boxStyleOverride() const { + return _boxSt; + } + void showBox( object_ptr box, LayerOptions options, @@ -201,6 +215,9 @@ private: class BackgroundWidget; object_ptr _background; + + const style::Box *_boxSt = nullptr; + const style::Box *_layerSt = nullptr; bool _hideByBackgroundClick = true; rpl::event_stream<> _hideFinishStream; diff --git a/ui/layers/layers.style b/ui/layers/layers.style index ddb32ea..10046f9 100644 --- a/ui/layers/layers.style +++ b/ui/layers/layers.style @@ -24,6 +24,11 @@ ServiceCheck { Box { buttonPadding: margins; buttonHeight: pixels; + button: RoundButton; + margin: margins; + title: FlatLabel; + bg: color; + titleAdditionalFg: color; } boxDuration: 200; @@ -36,12 +41,6 @@ defaultBoxButton: RoundButton(defaultLightButton) { font: boxButtonFont; } -boxTextStyle: TextStyle(defaultTextStyle) { - font: font(boxFontSize); - linkFont: font(boxFontSize); - linkFontOver: font(boxFontSize underline); -} - boxLabelStyle: TextStyle(boxTextStyle) { lineHeight: 22px; } @@ -118,7 +117,6 @@ boxOptionListPadding: margins(0px, 0px, 0px, 0px); boxOptionListSkip: 20px; boxOptionInputSkip: 6px; -boxVerticalMargin: 10px; boxWidth: 320px; boxWideWidth: 364px; boxPadding: margins(22px, 30px, 22px, 8px); @@ -129,6 +127,11 @@ boxMediumSkip: 20px; defaultBox: Box { buttonPadding: margins(8px, 12px, 13px, 12px); buttonHeight: 36px; + button: defaultBoxButton; + margin: margins(0px, 10px, 0px, 10px); + bg: boxBg; + title: boxTitle; + titleAdditionalFg: boxTitleAdditionalFg; } layerBox: Box(defaultBox) { buttonPadding: margins(8px, 8px, 8px, 8px); diff --git a/ui/round_rect.cpp b/ui/round_rect.cpp index eb42a51..8d19b22 100644 --- a/ui/round_rect.cpp +++ b/ui/round_rect.cpp @@ -67,22 +67,25 @@ RoundRect::RoundRect( ImageRoundRadius radius, const style::color &color) : _color(color) -, _corners(Images::PrepareCorners(radius, color)) { +, _refresh([=] { _corners = Images::PrepareCorners(radius, _color); }) { + _refresh(); style::PaletteChanged( - ) | rpl::start_with_next([=] { - _corners = Images::PrepareCorners(radius, _color); - }, _lifetime); + ) | rpl::start_with_next(_refresh, _lifetime); } RoundRect::RoundRect( int radius, const style::color &color) : _color(color) -, _corners(Images::PrepareCorners(radius, color)) { +, _refresh([=] { _corners = Images::PrepareCorners(radius, _color); }) { + _refresh(); style::PaletteChanged( - ) | rpl::start_with_next([=] { - _corners = Images::PrepareCorners(radius, _color); - }, _lifetime); + ) | rpl::start_with_next(_refresh, _lifetime); +} + +void RoundRect::setColor(const style::color &color) { + _color = color; + _refresh(); } const style::color &RoundRect::color() const { diff --git a/ui/round_rect.h b/ui/round_rect.h index 920c3dd..e2c184b 100644 --- a/ui/round_rect.h +++ b/ui/round_rect.h @@ -27,6 +27,7 @@ public: RoundRect(int radius, const style::color &color); [[nodiscard]] const style::color &color() const; + void setColor(const style::color &color); void paint( QPainter &p, const QRect &rect, @@ -39,6 +40,7 @@ public: private: style::color _color; std::array _corners; + Fn _refresh; rpl::lifetime _lifetime; diff --git a/ui/widgets/widgets.style b/ui/widgets/widgets.style index 01d9cf4..8f84da0 100644 --- a/ui/widgets/widgets.style +++ b/ui/widgets/widgets.style @@ -495,6 +495,7 @@ SettingsButton { textBgOver: color; font: font; + rightLabel: FlatLabel; height: pixels; padding: margins; @@ -780,6 +781,7 @@ defaultToggle: Toggle { } defaultCheckbox: Checkbox { textFg: windowFg; + textFgActive: windowFg; width: -44px; margin: margins(8px, 8px, 8px, 8px); @@ -821,12 +823,76 @@ defaultMultiSelectItem: MultiSelectItem { minScale: 0.3; } -widgetSlideDuration: 200; -widgetFadeDuration: 200; +defaultMultiSelectSearchField: InputField(defaultInputField) { + textBg: transparent; + textMargins: margins(2px, 7px, 2px, 0px); + + placeholderFg: placeholderFg; + placeholderFgActive: placeholderFgActive; + placeholderFgError: placeholderFgActive; + placeholderMargins: margins(2px, 0px, 2px, 0px); + placeholderScale: 0.; + placeholderFont: normalFont; + + border: 0px; + borderActive: 0px; + + heightMin: 32px; + + font: normalFont; +} fieldSearchIcon: icon {{ "box_search", menuIconFg, point(9px, 8px) }}; boxFieldSearchIcon: icon {{ "box_search", menuIconFg, point(10px, 9px) }}; +defaultMultiSelectSearchCancel: CrossButton { + width: 44px; + height: 44px; + + cross: CrossAnimation { + size: 36px; + skip: 12px; + stroke: 2px; + minScale: 0.3; + } + crossFg: boxTitleCloseFg; + crossFgOver: boxTitleCloseFgOver; + crossPosition: point(4px, 4px); + + duration: 150; + loadingPeriod: 1000; + ripple: RippleAnimation(defaultRippleAnimation) { + color: windowBgOver; + } +} +defaultMultiSelect: MultiSelect { + bg: boxSearchBg; + padding: margins(8px, 6px, 8px, 6px); + maxHeight: 104px; + scroll: ScrollArea(defaultSolidScroll) { + deltat: 3px; + deltab: 3px; + round: 1px; + width: 8px; + deltax: 3px; + hiding: 1000; + } + + item: defaultMultiSelectItem; + itemSkip: 8px; + + field: defaultMultiSelectSearchField; + fieldMinWidth: 42px; + fieldIcon: boxFieldSearchIcon; + fieldIconSkip: 36px; + + fieldCancel: defaultMultiSelectSearchCancel; + fieldCancelSkip: 40px; +} + +widgetSlideDuration: 200; +widgetFadeDuration: 200; + SettingsSlider { height: pixels; barTop: pixels; @@ -1125,6 +1191,7 @@ PeerListItem { button: OutlineButton; checkbox: RoundImageCheckbox; + disabledCheckFg: color; statusFg: color; statusFgOver: color; statusFgActive: color; @@ -1132,6 +1199,8 @@ PeerListItem { PeerList { padding: margins; + bg: color; + about: FlatLabel; item: PeerListItem; } @@ -1163,13 +1232,31 @@ defaultPeerListItem: PeerListItem { photoSize: 46px; button: defaultPeerListButton; checkbox: defaultPeerListCheckbox; + disabledCheckFg: menuIconFg; statusFg: windowSubTextFg; statusFgOver: windowSubTextFgOver; statusFgActive: windowActiveTextFg; } +boxTextStyle: TextStyle(defaultTextStyle) { + font: font(boxFontSize); + linkFont: font(boxFontSize); + linkFontOver: font(boxFontSize underline); +} + +defaultPeerListAbout: FlatLabel(defaultFlatLabel) { + minWidth: 240px; + textFg: membersAboutLimitFg; + align: align(top); + style: TextStyle(boxTextStyle) { + lineHeight: 22px; + } +} + defaultPeerList: PeerList { padding: margins(0px, 0px, 0px, 0px); + bg: contactsBg; + about: defaultPeerListAbout; item: defaultPeerListItem; } @@ -1256,6 +1343,11 @@ defaultSettingsToggle: Toggle(defaultToggle) { defaultSettingsToggleOver: Toggle(defaultSettingsToggle) { untoggledFg: menuIconFgOver; } +defaultSettingsRightLabel: FlatLabel(defaultFlatLabel) { + textFg: windowActiveTextFg; + style: boxTextStyle; + maxHeight: 20px; +} defaultSettingsButton: SettingsButton { textFg: windowBoldFg; textFgOver: windowBoldFgOver; @@ -1263,6 +1355,7 @@ defaultSettingsButton: SettingsButton { textBgOver: windowBgOver; font: boxTextFont; + rightLabel: defaultSettingsRightLabel; height: 20px; padding: margins(22px, 10px, 22px, 8px);