Added ability to change zoom in IV.

This commit is contained in:
23rd 2024-10-15 09:55:46 +03:00
parent d351a7d697
commit 7e14277ead
11 changed files with 247 additions and 10 deletions

View File

@ -12,6 +12,7 @@ body {
margin: 0;
background-color: var(--td-window-bg);
color: var(--td-window-fg);
zoom: var(--td-zoom-percentage);
}
html.custom_scroll ::-webkit-scrollbar {

View File

@ -222,7 +222,7 @@ QByteArray Settings::serialize() const {
+ Serialize::stringSize(_customFontFamily)
+ sizeof(qint32) * 3
+ Serialize::bytearraySize(_tonsiteStorageToken)
+ sizeof(qint32);
+ sizeof(qint32) * 2;
auto result = QByteArray();
result.reserve(size);
@ -377,7 +377,8 @@ QByteArray Settings::serialize() const {
<< qint32(_systemUnlockEnabled ? 1 : 0)
<< qint32(!_weatherInCelsius ? 0 : *_weatherInCelsius ? 1 : 2)
<< _tonsiteStorageToken
<< qint32(_includeMutedCounterFolders ? 1 : 0);
<< qint32(_includeMutedCounterFolders ? 1 : 0)
<< qint32(_ivZoom.current());
}
Ensures(result.size() == size);
@ -501,6 +502,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
qint32 systemUnlockEnabled = _systemUnlockEnabled ? 1 : 0;
qint32 weatherInCelsius = !_weatherInCelsius ? 0 : *_weatherInCelsius ? 1 : 2;
QByteArray tonsiteStorageToken = _tonsiteStorageToken;
qint32 ivZoom = _ivZoom.current();
stream >> themesAccentColors;
if (!stream.atEnd()) {
@ -810,6 +812,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) {
stream >> includeMutedCounterFolders;
}
if (!stream.atEnd()) {
stream >> ivZoom;
}
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()"));
@ -1021,6 +1026,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
? std::optional<bool>()
: (weatherInCelsius == 1);
_tonsiteStorageToken = tonsiteStorageToken;
_ivZoom = ivZoom;
}
QString Settings::getSoundPath(const QString &key) const {
@ -1408,6 +1414,7 @@ void Settings::resetOnLastLogout() {
_hiddenGroupCallTooltips = 0;
_storiesClickTooltipHidden = false;
_ttlVoiceClickTooltipHidden = false;
_ivZoom = 100;
_recentEmojiPreload.clear();
_recentEmoji.clear();
@ -1547,4 +1554,16 @@ bool Settings::rememberedDeleteMessageOnlyForYou() const {
return _rememberedDeleteMessageOnlyForYou;
}
int Settings::ivZoom() const {
return _ivZoom.current();
}
rpl::producer<int> Settings::ivZoomValue() const {
return _ivZoom.value();
}
void Settings::setIvZoom(int value) {
constexpr auto kMin = 30;
constexpr auto kMax = 200;
_ivZoom = std::clamp(value, kMin, kMax);
}
} // namespace Core

View File

@ -915,6 +915,10 @@ public:
_tonsiteStorageToken = value;
}
[[nodiscard]] int ivZoom() const;
[[nodiscard]] rpl::producer<int> ivZoomValue() const;
void setIvZoom(int value);
[[nodiscard]] static bool ThirdColumnByDefault();
[[nodiscard]] static float64 DefaultDialogsWidthRatio();
@ -1050,6 +1054,7 @@ private:
bool _systemUnlockEnabled = false;
std::optional<bool> _weatherInCelsius;
QByteArray _tonsiteStorageToken;
rpl::variable<int> _ivZoom = 100;
bool _tabbedReplacedWithInfo = false; // per-window
rpl::event_stream<bool> _tabbedReplacedWithInfoValue; // per-window

View File

@ -29,6 +29,38 @@ ivBack: IconButton(ivMenuToggle) {
iconOver: ivBackIcon;
rippleAreaPosition: point(12px, 6px);
}
ivZoomButtonsSize: 26px;
ivPlusMinusZoom: IconButton(ivMenuToggle) {
width: ivZoomButtonsSize;
height: ivZoomButtonsSize;
rippleAreaPosition: point(0px, 0px);
rippleAreaSize: ivZoomButtonsSize;
ripple: RippleAnimation(defaultRippleAnimation) {
color: windowBgOver;
}
}
ivResetZoomStyle: TextStyle(defaultTextStyle) {
font: font(12px);
}
ivResetZoom: RoundButton(defaultActiveButton) {
textFg: windowFg;
textFgOver: windowFgOver;
textBg: windowBg;
textBgOver: windowBgOver;
height: ivZoomButtonsSize;
padding: margins(0px, 0px, 0px, 0px);
style: ivResetZoomStyle;
ripple: defaultRippleAnimation;
}
ivResetZoomLabel: FlatLabel(defaultFlatLabel) {
textFg: windowFg;
style: ivResetZoomStyle;
}
ivResetZoomInnerPadding: 20px;
ivBackIconDisabled: icon {{ "box_button_back", menuIconFg }};
ivForwardIcon: icon {{ "box_button_back-flip_horizontal", menuIconColor }};
ivForward: IconButton(ivBack) {

View File

@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/platform/ui_platform_window_title.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/menu/menu_action.h"
#include "ui/widgets/rp_window.h"
#include "ui/widgets/popup_menu.h"
#include "ui/wrap/fade_wrap.h"
@ -50,7 +51,145 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Iv {
namespace {
[[nodiscard]] QByteArray ComputeStyles() {
constexpr auto kZoomStep = int(10);
constexpr auto kDefaultZoom = int(100);
class ItemZoom final : public Ui::Menu::Action {
public:
ItemZoom(
not_null<RpWidget*> parent,
const not_null<Delegate*> delegate,
const style::Menu &st)
: Ui::Menu::Action(
parent,
st,
Ui::CreateChild<QAction>(parent),
nullptr,
nullptr)
, _delegate(delegate)
, _st(st) {
init();
}
void init() {
enableMouseSelecting();
AbstractButton::setDisabled(true);
class SmallButton final : public Ui::IconButton {
public:
SmallButton(
not_null<Ui::RpWidget*> parent,
QChar c,
float64 skip,
const style::color &color)
: Ui::IconButton(parent, st::ivPlusMinusZoom)
, _color(color)
, _skip(style::ConvertFloatScale(skip))
, _c(c) {
}
void paintEvent(QPaintEvent *event) override {
auto p = Painter(this);
Ui::RippleButton::paintRipple(
p,
st::ivPlusMinusZoom.rippleAreaPosition);
p.setPen(_color);
p.setFont(st::normalFont);
p.drawText(
QRectF(rect()).translated(0, _skip),
_c,
style::al_center);
}
private:
const style::color _color;
const float64 _skip;
const QChar _c;
};
const auto reset = Ui::CreateChild<Ui::RoundButton>(
this,
rpl::single<QString>(QString()),
st::ivResetZoom);
const auto resetLabel = Ui::CreateChild<Ui::FlatLabel>(
reset,
tr::lng_background_reset_default(),
st::ivResetZoomLabel);
resetLabel->setAttribute(Qt::WA_TransparentForMouseEvents);
reset->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
reset->setClickedCallback([this] {
_delegate->ivSetZoom(kDefaultZoom);
});
reset->show();
const auto plus = Ui::CreateChild<SmallButton>(
this,
'+',
0,
_st.itemFg);
plus->setClickedCallback([this] {
_delegate->ivSetZoom(_delegate->ivZoom() + kZoomStep);
});
plus->show();
const auto minus = Ui::CreateChild<SmallButton>(
this,
QChar(0x2013),
-1,
_st.itemFg);
minus->setClickedCallback([this] {
_delegate->ivSetZoom(_delegate->ivZoom() - kZoomStep);
});
minus->show();
_delegate->ivZoomValue(
) | rpl::start_with_next([this](int value) {
_text.setText(_st.itemStyle, QString::number(value) + '%');
update();
}, lifetime());
rpl::combine(
sizeValue(),
reset->sizeValue()
) | rpl::start_with_next([=, this](const QSize &size, const QSize &) {
reset->setFullWidth(0
+ resetLabel->width()
+ st::ivResetZoomInnerPadding);
resetLabel->moveToLeft(
(reset->width() - resetLabel->width()) / 2,
(reset->height() - resetLabel->height()) / 2);
reset->moveToRight(
_st.itemPadding.right(),
(size.height() - reset->height()) / 2);
plus->moveToRight(
_st.itemPadding.right() + reset->width(),
(size.height() - plus->height()) / 2);
minus->moveToRight(
_st.itemPadding.right() + plus->width() + reset->width(),
(size.height() - minus->height()) / 2);
}, lifetime());
}
void paintEvent(QPaintEvent *event) override {
auto p = QPainter(this);
p.setPen(_st.itemFg);
_text.draw(p, {
.position = QPoint(
_st.itemIconPosition.x(),
(height() - _text.minHeight()) / 2),
.outerWidth = width(),
.availableWidth = width(),
});
}
private:
const not_null<Delegate*> _delegate;
const style::Menu &_st;
Ui::Text::String _text;
};
[[nodiscard]] QByteArray ComputeStyles(int zoom) {
static const auto map = base::flat_map<QByteArray, const style::color*>{
{ "shadow-fg", &st::shadowFg },
{ "scroll-bg", &st::scrollBg },
@ -85,7 +224,7 @@ namespace {
static const auto phrases = base::flat_map<QByteArray, tr::phrase<>>{
{ "iv-join-channel", tr::lng_iv_join_channel },
};
return Ui::ComputeStyles(map, phrases)
return Ui::ComputeStyles(map, phrases, zoom)
+ ';'
+ Ui::ComputeSemiTransparentOverStyle(
"light-button-bg-over",
@ -93,7 +232,7 @@ namespace {
st::windowBg);
}
[[nodiscard]] QByteArray WrapPage(const Prepared &page) {
[[nodiscard]] QByteArray WrapPage(const Prepared &page, int zoom) {
#ifdef Q_OS_MAC
const auto classAttribute = ""_q;
#else // Q_OS_MAC
@ -110,7 +249,7 @@ namespace {
<html)"_q
+ classAttribute
+ R"( style=")"
+ Ui::EscapeForAttribute(ComputeStyles())
+ Ui::EscapeForAttribute(ComputeStyles(zoom))
+ R"(">
<head>
<meta charset="utf-8">
@ -206,7 +345,8 @@ Controller::Controller(
Fn<ShareBoxResult(ShareBoxDescriptor)> showShareBox)
: _delegate(delegate)
, _updateStyles([=] {
const auto str = Ui::EscapeForScriptString(ComputeStyles());
const auto zoom = _delegate->ivZoom();
const auto str = Ui::EscapeForScriptString(ComputeStyles(zoom));
if (_webview) {
_webview->eval("IV.updateStyles('" + str + "');");
}
@ -484,6 +624,16 @@ void Controller::createWebview(const Webview::StorageId &storageId) {
if (event->key() == Qt::Key_Escape) {
escape();
}
if (event->modifiers() & Qt::ControlModifier) {
if (event->key() == Qt::Key_Plus
|| event->key() == Qt::Key_Equal) {
_delegate->ivSetZoom(_delegate->ivZoom() + kZoomStep);
} else if (event->key() == Qt::Key_Minus) {
_delegate->ivSetZoom(_delegate->ivZoom() - kZoomStep);
} else if (event->key() == Qt::Key_0) {
_delegate->ivSetZoom(kDefaultZoom);
}
}
}
}, window->lifetime());
@ -595,7 +745,8 @@ void Controller::createWebview(const Webview::StorageId &storageId) {
rpl::merge(
Lang::Updated(),
style::PaletteChanged()
style::PaletteChanged(),
_delegate->ivZoomValue() | rpl::to_empty
) | rpl::start_with_next([=] {
_updateStyles.call();
}, _webview->lifetime());
@ -611,7 +762,8 @@ void Controller::createWebview(const Webview::StorageId &storageId) {
return Webview::DataResult::Failed;
}
return finishWith(
WrapPage(_pages[index]), "text/html; charset=utf-8");
WrapPage(_pages[index], _delegate->ivZoom()),
"text/html; charset=utf-8");
} else if (id.starts_with("page") && id.ends_with(".json")) {
auto index = 0;
const auto result = std::from_chars(
@ -897,6 +1049,10 @@ void Controller::showMenu() {
showShareMenu();
}, &st::menuIconShare);
_menu->addSeparator();
_menu->addAction(
base::make_unique_q<ItemZoom>(_menu, _delegate, _menu->menu()->st()));
_menu->setForcedOrigin(Ui::PanelAnimation::Origin::TopRight);
_menu->popup(_window->body()->mapToGlobal(
QPoint(_window->body()->width(), 0) + st::ivMenuPosition));

View File

@ -18,6 +18,10 @@ public:
virtual void ivSetLastSourceWindow(not_null<QWidget*> window) = 0;
[[nodiscard]] virtual QRect ivGeometry() const = 0;
virtual void ivSaveGeometry(not_null<Ui::RpWindow*> window) = 0;
[[nodiscard]] virtual int ivZoom() const = 0;
[[nodiscard]] virtual rpl::producer<int> ivZoomValue() const = 0;
virtual void ivSetZoom(int value) = 0;
};
} // namespace Iv

View File

@ -117,4 +117,15 @@ void DelegateImpl::ivSaveGeometry(not_null<Ui::RpWindow*> window) {
}
}
int DelegateImpl::ivZoom() const {
return Core::App().settings().ivZoom();
}
rpl::producer<int> DelegateImpl::ivZoomValue() const {
return Core::App().settings().ivZoomValue();
}
void DelegateImpl::ivSetZoom(int value) {
Core::App().settings().setIvZoom(value);
Core::App().saveSettingsDelayed();
}
} // namespace Iv

View File

@ -19,6 +19,10 @@ public:
[[nodiscard]] QRect ivGeometry() const override;
void ivSaveGeometry(not_null<Ui::RpWindow*> window) override;
[[nodiscard]] int ivZoom() const;
[[nodiscard]] rpl::producer<int> ivZoomValue() const;
void ivSetZoom(int value);
private:
QPointer<QWidget> _lastSourceWindow;

View File

@ -379,7 +379,7 @@ void VenuesController::rowPaintIcon(
static const auto phrases = base::flat_map<QByteArray, tr::phrase<>>{
{ "maps-places-in-area", tr::lng_maps_places_in_area },
};
return Ui::ComputeStyles(map, phrases, Window::Theme::IsNightMode());
return Ui::ComputeStyles(map, phrases, 100, Window::Theme::IsNightMode());
}
[[nodiscard]] QByteArray ReadResource(const QString &name) {

View File

@ -31,6 +31,7 @@ namespace {
QByteArray ComputeStyles(
const base::flat_map<QByteArray, const style::color*> &colors,
const base::flat_map<QByteArray, tr::phrase<>> &phrases,
int zoom,
bool nightTheme) {
static const auto serialize = [](const style::color *color) {
return Serialize((*color)->c);
@ -66,6 +67,9 @@ QByteArray ComputeStyles(
result += "--td-"_q + name + ':' + serialize(color) + ';';
}
result += "--td-night:"_q + (nightTheme ? "1" : "0") + ';';
result += "--td-zoom-percentage:"_q
+ (QString::number(zoom).toUtf8() + '%')
+ ';';
return result;
}

View File

@ -19,6 +19,7 @@ namespace Ui {
[[nodiscard]] QByteArray ComputeStyles(
const base::flat_map<QByteArray, const style::color*> &colors,
const base::flat_map<QByteArray, tr::phrase<>> &phrases,
int zoom,
bool nightTheme = false);
[[nodiscard]] QByteArray ComputeSemiTransparentOverStyle(
const QByteArray &name,