Implement semi-native macOS title buttons for the viewer.
BIN
Telegram/Resources/icons/mediaview/title_button_close_mac.png
Normal file
After Width: | Height: | Size: 260 B |
BIN
Telegram/Resources/icons/mediaview/title_button_close_mac@2x.png
Normal file
After Width: | Height: | Size: 368 B |
BIN
Telegram/Resources/icons/mediaview/title_button_close_mac@3x.png
Normal file
After Width: | Height: | Size: 490 B |
BIN
Telegram/Resources/icons/mediaview/title_button_mac.png
Normal file
After Width: | Height: | Size: 292 B |
BIN
Telegram/Resources/icons/mediaview/title_button_mac@2x.png
Normal file
After Width: | Height: | Size: 485 B |
BIN
Telegram/Resources/icons/mediaview/title_button_mac@3x.png
Normal file
After Width: | Height: | Size: 703 B |
BIN
Telegram/Resources/icons/mediaview/title_button_maximize_mac.png
Normal file
After Width: | Height: | Size: 244 B |
After Width: | Height: | Size: 324 B |
After Width: | Height: | Size: 448 B |
BIN
Telegram/Resources/icons/mediaview/title_button_minimize_mac.png
Normal file
After Width: | Height: | Size: 210 B |
After Width: | Height: | Size: 265 B |
After Width: | Height: | Size: 319 B |
BIN
Telegram/Resources/icons/mediaview/title_button_shadow_mac.png
Normal file
After Width: | Height: | Size: 371 B |
After Width: | Height: | Size: 636 B |
After Width: | Height: | Size: 915 B |
BIN
Telegram/Resources/icons/mediaview/title_button_shrink_mac.png
Normal file
After Width: | Height: | Size: 259 B |
After Width: | Height: | Size: 319 B |
After Width: | Height: | Size: 434 B |
|
@ -321,6 +321,19 @@ mediaviewTitle: WindowTitle(defaultWindowTitle) {
|
||||||
closeIconActive: mediaviewTitleClose;
|
closeIconActive: mediaviewTitleClose;
|
||||||
closeIconActiveOver: mediaviewTitleClose;
|
closeIconActiveOver: mediaviewTitleClose;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mediaviewTitleButtonMac: icon{
|
||||||
|
{ "mediaview/title_button_shadow_mac", windowShadowFg },
|
||||||
|
{ "mediaview/title_button_mac", mediaviewControlFg },
|
||||||
|
};
|
||||||
|
mediaviewTitleMinimizeMac: icon {{ "mediaview/title_button_minimize_mac", mediaviewBg }};
|
||||||
|
mediaviewTitleMaximizeMac: icon {{ "mediaview/title_button_maximize_mac", mediaviewBg }};
|
||||||
|
mediaviewTitleRestoreMac: icon {{ "mediaview/title_button_shrink_mac", mediaviewBg }};
|
||||||
|
mediaviewTitleCloseMac: icon {{ "mediaview/title_button_close_mac", mediaviewBg }};
|
||||||
|
mediaviewTitleCloseMacPadding: margins(8px, 4px, 0px, 4px);
|
||||||
|
mediaviewTitleMinimizeMacPadding: margins(0px, 4px, 0px, 4px);
|
||||||
|
mediaviewTitleMaximizeMacPadding: margins(0px, 4px, 8px, 4px);
|
||||||
|
|
||||||
mediaviewShadowTop: icon{{ "mediaview/shadow_top", windowShadowFg }};
|
mediaviewShadowTop: icon{{ "mediaview/shadow_top", windowShadowFg }};
|
||||||
mediaviewShadowBottom: icon{{ "mediaview/shadow_bottom", windowShadowFg }};
|
mediaviewShadowBottom: icon{{ "mediaview/shadow_bottom", windowShadowFg }};
|
||||||
|
|
||||||
|
|
|
@ -3080,6 +3080,7 @@ void OverlayWidget::displayFinished() {
|
||||||
//Ui::Platform::UpdateOverlayed(_window);
|
//Ui::Platform::UpdateOverlayed(_window);
|
||||||
showAndActivate();
|
showAndActivate();
|
||||||
} else if (isMinimized()) {
|
} else if (isMinimized()) {
|
||||||
|
_helper->beforeShow(_fullscreen);
|
||||||
showAndActivate();
|
showAndActivate();
|
||||||
} else {
|
} else {
|
||||||
activate();
|
activate();
|
||||||
|
|
|
@ -9,6 +9,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "platform/platform_overlay_widget.h"
|
#include "platform/platform_overlay_widget.h"
|
||||||
|
|
||||||
|
template <typename Object>
|
||||||
|
class object_ptr;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class AbstractButton;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Ui::Platform {
|
||||||
|
enum class TitleControl;
|
||||||
|
} // namespace Ui::Platform
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
class MacOverlayWidgetHelper final : public OverlayWidgetHelper {
|
class MacOverlayWidgetHelper final : public OverlayWidgetHelper {
|
||||||
|
@ -22,15 +33,22 @@ public:
|
||||||
void afterShow(bool fullscreen) override;
|
void afterShow(bool fullscreen) override;
|
||||||
void notifyFileDialogShown(bool shown) override;
|
void notifyFileDialogShown(bool shown) override;
|
||||||
void minimize(not_null<Ui::RpWindow*> window) override;
|
void minimize(not_null<Ui::RpWindow*> window) override;
|
||||||
|
void clearState() override;
|
||||||
|
void setControlsOpacity(float64 opacity) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using Control = Ui::Platform::TitleControl;
|
||||||
struct Data;
|
struct Data;
|
||||||
|
|
||||||
void activate(int button); // NSWindowButton
|
void activate(Control control);
|
||||||
void resolveNative();
|
void resolveNative();
|
||||||
void updateStyles(bool fullscreen);
|
void updateStyles(bool fullscreen);
|
||||||
void refreshButtons(bool fullscreen);
|
void refreshButtons(bool fullscreen);
|
||||||
|
|
||||||
|
object_ptr<Ui::AbstractButton> create(
|
||||||
|
not_null<QWidget*> parent,
|
||||||
|
Control control);
|
||||||
|
|
||||||
std::unique_ptr<Data> _data;
|
std::unique_ptr<Data> _data;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,85 +7,34 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "platform/mac/overlay_widget_mac.h"
|
#include "platform/mac/overlay_widget_mac.h"
|
||||||
|
|
||||||
|
#include "base/object_ptr.h"
|
||||||
|
#include "ui/platform/ui_platform_window_title.h"
|
||||||
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/rp_window.h"
|
#include "ui/widgets/rp_window.h"
|
||||||
|
#include "styles/style_media_view.h"
|
||||||
|
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
#include <Cocoa/Cocoa.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
@interface ButtonHandler : NSObject {
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype) initWithCallback:(Fn<void(NSWindowButton)>)callback;
|
|
||||||
- (void) close:(id) sender;
|
|
||||||
- (void) miniaturize:(id) sender;
|
|
||||||
- (void) zoom:(id) sender;
|
|
||||||
|
|
||||||
@end // @interface ButtonHandler
|
|
||||||
|
|
||||||
@implementation ButtonHandler {
|
|
||||||
Fn<void(NSWindowButton)> _callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype) initWithCallback:(Fn<void(NSWindowButton)>)callback {
|
|
||||||
_callback = std::move(callback);
|
|
||||||
return [super init];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) close:(id) sender {
|
|
||||||
_callback(NSWindowCloseButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) miniaturize:(id) sender {
|
|
||||||
_callback(NSWindowMiniaturizeButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) zoom:(id) sender {
|
|
||||||
_callback(NSWindowZoomButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end // @implementation ButtonHandler
|
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
[[nodiscard]] base::flat_map<int, NSRect> ButtonGeometries() {
|
using namespace Media::View;
|
||||||
auto result = base::flat_map<int, NSRect>();
|
|
||||||
auto normal = QWidget();
|
|
||||||
normal.hide();
|
|
||||||
normal.createWinId();
|
|
||||||
const auto view = reinterpret_cast<NSView*>(normal.winId());
|
|
||||||
const auto window = [view window];
|
|
||||||
const auto process = [&](NSWindowButton type) {
|
|
||||||
if (const auto button = [window standardWindowButton:type]) {
|
|
||||||
result.emplace(int(type), [button frame]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
process(NSWindowCloseButton);
|
|
||||||
process(NSWindowMiniaturizeButton);
|
|
||||||
process(NSWindowZoomButton);
|
|
||||||
|
|
||||||
const auto full = [window frame];
|
|
||||||
const auto inner = [window contentRectForFrameRect:full].size.height;
|
|
||||||
const auto height = std::max(full.size.height - inner, 0.);
|
|
||||||
|
|
||||||
result[int(NSWindowToolbarButton)] = { CGPoint(), CGSize{ full.size.width, height }};
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
struct MacOverlayWidgetHelper::Data {
|
struct MacOverlayWidgetHelper::Data {
|
||||||
const not_null<Ui::RpWindow*> window;
|
const not_null<Ui::RpWindow*> window;
|
||||||
const Fn<void(bool)> maximize;
|
const Fn<void(bool)> maximize;
|
||||||
const base::flat_map<int, NSRect> buttons;
|
object_ptr<Ui::AbstractButton> buttonClose = { nullptr };
|
||||||
ButtonHandler *handler = nil;
|
object_ptr<Ui::AbstractButton> buttonMinimize = { nullptr };
|
||||||
|
object_ptr<Ui::AbstractButton> buttonMaximize = { nullptr };
|
||||||
|
rpl::event_stream<> activations;
|
||||||
|
rpl::variable<float64> masterOpacity = 1.;
|
||||||
|
rpl::variable<bool> maximized = false;
|
||||||
|
rpl::event_stream<> clearStateRequests;
|
||||||
|
bool anyOver = false;
|
||||||
NSWindow * __weak native = nil;
|
NSWindow * __weak native = nil;
|
||||||
NSButton * __weak closeNative = nil;
|
|
||||||
NSButton * __weak miniaturizeNative = nil;
|
|
||||||
NSButton * __weak zoomNative = nil;
|
|
||||||
NSButton * __weak close = nil;
|
|
||||||
NSButton * __weak miniaturize = nil;
|
|
||||||
NSButton * __weak zoom = nil;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MacOverlayWidgetHelper::MacOverlayWidgetHelper(
|
MacOverlayWidgetHelper::MacOverlayWidgetHelper(
|
||||||
|
@ -94,24 +43,20 @@ MacOverlayWidgetHelper::MacOverlayWidgetHelper(
|
||||||
: _data(std::make_unique<Data>(Data{
|
: _data(std::make_unique<Data>(Data{
|
||||||
.window = window,
|
.window = window,
|
||||||
.maximize = std::move(maximize),
|
.maximize = std::move(maximize),
|
||||||
.buttons = ButtonGeometries(),
|
|
||||||
.handler = [[ButtonHandler alloc] initWithCallback:[=](NSWindowButton button) {
|
|
||||||
activate(int(button));
|
|
||||||
}]
|
|
||||||
})) {
|
})) {
|
||||||
|
_data->buttonClose = create(window, Control::Close);
|
||||||
|
_data->buttonMinimize = create(window, Control::Minimize);
|
||||||
|
_data->buttonMaximize = create(window, Control::Maximize);
|
||||||
}
|
}
|
||||||
|
|
||||||
MacOverlayWidgetHelper::~MacOverlayWidgetHelper() {
|
MacOverlayWidgetHelper::~MacOverlayWidgetHelper() = default;
|
||||||
[_data->handler release];
|
|
||||||
_data->handler = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacOverlayWidgetHelper::activate(int button) {
|
void MacOverlayWidgetHelper::activate(Control control) {
|
||||||
const auto fullscreen = (_data->window->windowHandle()->flags() & Qt::FramelessWindowHint);
|
const auto fullscreen = (_data->window->windowHandle()->flags() & Qt::FramelessWindowHint);
|
||||||
switch (NSWindowButton(button)) {
|
switch (control) {
|
||||||
case NSWindowCloseButton: _data->window->close(); return;
|
case Control::Close: _data->window->close(); return;
|
||||||
case NSWindowMiniaturizeButton: [_data->native miniaturize:_data->handler]; return;
|
case Control::Minimize: [_data->native miniaturize:_data->native]; return;
|
||||||
case NSWindowZoomButton: _data->maximize(!fullscreen); return;
|
case Control::Maximize: _data->maximize(!fullscreen); return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +64,7 @@ void MacOverlayWidgetHelper::beforeShow(bool fullscreen) {
|
||||||
_data->window->setAttribute(Qt::WA_MacAlwaysShowToolWindow, !fullscreen);
|
_data->window->setAttribute(Qt::WA_MacAlwaysShowToolWindow, !fullscreen);
|
||||||
_data->window->windowHandle()->setFlag(Qt::FramelessWindowHint, fullscreen);
|
_data->window->windowHandle()->setFlag(Qt::FramelessWindowHint, fullscreen);
|
||||||
updateStyles(fullscreen);
|
updateStyles(fullscreen);
|
||||||
|
clearState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacOverlayWidgetHelper::afterShow(bool fullscreen) {
|
void MacOverlayWidgetHelper::afterShow(bool fullscreen) {
|
||||||
|
@ -133,6 +79,8 @@ void MacOverlayWidgetHelper::resolveNative() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacOverlayWidgetHelper::updateStyles(bool fullscreen) {
|
void MacOverlayWidgetHelper::updateStyles(bool fullscreen) {
|
||||||
|
_data->maximized = fullscreen;
|
||||||
|
|
||||||
resolveNative();
|
resolveNative();
|
||||||
if (!_data->native) {
|
if (!_data->native) {
|
||||||
return;
|
return;
|
||||||
|
@ -153,85 +101,23 @@ void MacOverlayWidgetHelper::refreshButtons(bool fullscreen) {
|
||||||
Expects(_data->native != nullptr);
|
Expects(_data->native != nullptr);
|
||||||
|
|
||||||
const auto window = _data->native;
|
const auto window = _data->native;
|
||||||
auto next = CGPoint();
|
const auto process = [&](NSWindowButton type) {
|
||||||
const auto added = [&](NSRect frame) {
|
if (const auto button = [window standardWindowButton:type]) {
|
||||||
const auto left = frame.origin.x + frame.size.width * 1.5;
|
[button setHidden:YES];
|
||||||
const auto top = frame.origin.y;
|
|
||||||
if (next.x < left) {
|
|
||||||
next.x = left;
|
|
||||||
}
|
}
|
||||||
next.y = top;
|
|
||||||
};
|
};
|
||||||
for (const auto &[type, frame] : _data->buttons) {
|
process(NSWindowCloseButton);
|
||||||
added(frame);
|
process(NSWindowMiniaturizeButton);
|
||||||
}
|
process(NSWindowZoomButton);
|
||||||
const auto skip = fullscreen
|
_data->buttonClose->moveToLeft(0, 0);
|
||||||
? _data->buttons.find(int(NSWindowToolbarButton))->second.size.height
|
_data->buttonClose->raise();
|
||||||
: 0.;
|
_data->buttonClose->show();
|
||||||
const auto process = [&](auto native, auto custom, NSWindowButton type, auto action) {
|
_data->buttonMinimize->moveToLeft(_data->buttonClose->width(), 0);
|
||||||
auto retained = (NSButton*)nil;
|
_data->buttonMinimize->raise();
|
||||||
while (const auto button = [window standardWindowButton:type]) {
|
_data->buttonMinimize->show();
|
||||||
if ([button superview] != [window contentView]) {
|
_data->buttonMaximize->moveToLeft(_data->buttonClose->width() + _data->buttonMinimize->width(), 0);
|
||||||
*native = button;
|
_data->buttonMaximize->raise();
|
||||||
[button setHidden:YES];
|
_data->buttonMaximize->show();
|
||||||
break;
|
|
||||||
} else if (button == *custom) {
|
|
||||||
retained = [button retain];
|
|
||||||
}
|
|
||||||
[button removeFromSuperview];
|
|
||||||
}
|
|
||||||
const auto i = _data->buttons.find(int(type));
|
|
||||||
const auto frame = [&](NSButton *button) {
|
|
||||||
if (i != end(_data->buttons)) {
|
|
||||||
auto origin = i->second.origin;
|
|
||||||
origin.y += skip;
|
|
||||||
return NSRect{ origin, i->second.size };
|
|
||||||
}
|
|
||||||
const auto size = [button frame].size;
|
|
||||||
auto result = NSRect{ next, size };
|
|
||||||
added(result);
|
|
||||||
result.origin.y += skip;
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
if (!retained) {
|
|
||||||
if (*custom) {
|
|
||||||
retained = *custom;
|
|
||||||
[retained retain];
|
|
||||||
[retained removeFromSuperview];
|
|
||||||
} else {
|
|
||||||
const auto style = NSWindowStyleMaskTitled
|
|
||||||
| NSWindowStyleMaskClosable
|
|
||||||
| NSWindowStyleMaskMiniaturizable
|
|
||||||
| NSWindowStyleMaskResizable;
|
|
||||||
*custom
|
|
||||||
= retained
|
|
||||||
= [NSWindow standardWindowButton:type forStyleMask:style];
|
|
||||||
[retained setTarget:_data->handler];
|
|
||||||
[retained setAction:action];
|
|
||||||
[retained retain];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[[window contentView] addSubview:retained];
|
|
||||||
[retained setFrame:frame(retained)];
|
|
||||||
[retained setEnabled:YES];
|
|
||||||
[retained setHidden:NO];
|
|
||||||
[retained release];
|
|
||||||
};
|
|
||||||
process(
|
|
||||||
&_data->closeNative,
|
|
||||||
&_data->close,
|
|
||||||
NSWindowCloseButton,
|
|
||||||
@selector(close:));
|
|
||||||
process(
|
|
||||||
&_data->miniaturizeNative,
|
|
||||||
&_data->miniaturize,
|
|
||||||
NSWindowMiniaturizeButton,
|
|
||||||
@selector(miniaturize:));
|
|
||||||
process(
|
|
||||||
&_data->zoomNative,
|
|
||||||
&_data->zoom,
|
|
||||||
NSWindowZoomButton,
|
|
||||||
@selector(zoom:));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacOverlayWidgetHelper::notifyFileDialogShown(bool shown) {
|
void MacOverlayWidgetHelper::notifyFileDialogShown(bool shown) {
|
||||||
|
@ -250,10 +136,142 @@ void MacOverlayWidgetHelper::notifyFileDialogShown(bool shown) {
|
||||||
void MacOverlayWidgetHelper::minimize(not_null<Ui::RpWindow*> window) {
|
void MacOverlayWidgetHelper::minimize(not_null<Ui::RpWindow*> window) {
|
||||||
resolveNative();
|
resolveNative();
|
||||||
if (_data->native) {
|
if (_data->native) {
|
||||||
[_data->native miniaturize:_data->handler];
|
[_data->native miniaturize:_data->native];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacOverlayWidgetHelper::clearState() {
|
||||||
|
_data->clearStateRequests.fire({});
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacOverlayWidgetHelper::setControlsOpacity(float64 opacity) {
|
||||||
|
_data->masterOpacity = opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ptr<Ui::AbstractButton> MacOverlayWidgetHelper::create(
|
||||||
|
not_null<QWidget*> parent,
|
||||||
|
Control control) {
|
||||||
|
auto result = object_ptr<Ui::AbstractButton>(parent);
|
||||||
|
const auto raw = result.data();
|
||||||
|
|
||||||
|
raw->setClickedCallback([=] { activate(control); });
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
Ui::Animations::Simple animation;
|
||||||
|
float64 progress = -1.;
|
||||||
|
QImage frame;
|
||||||
|
bool maximized = false;
|
||||||
|
bool anyOver = false;
|
||||||
|
bool over = false;
|
||||||
|
};
|
||||||
|
const auto state = raw->lifetime().make_state<State>();
|
||||||
|
|
||||||
|
rpl::merge(
|
||||||
|
_data->masterOpacity.changes() | rpl::to_empty,
|
||||||
|
_data->maximized.changes() | rpl::to_empty
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
raw->update();
|
||||||
|
}, raw->lifetime());
|
||||||
|
|
||||||
|
_data->clearStateRequests.events(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
raw->clearState();
|
||||||
|
raw->update();
|
||||||
|
state->over = raw->isOver();
|
||||||
|
_data->anyOver = false;
|
||||||
|
state->animation.stop();
|
||||||
|
}, raw->lifetime());
|
||||||
|
|
||||||
|
struct Info {
|
||||||
|
const style::icon *icon = nullptr;
|
||||||
|
style::margins padding;
|
||||||
|
};
|
||||||
|
const auto info = [&]() -> Info {
|
||||||
|
switch (control) {
|
||||||
|
case Control::Minimize:
|
||||||
|
return { &st::mediaviewTitleMinimizeMac, st::mediaviewTitleMinimizeMacPadding };
|
||||||
|
case Control::Maximize:
|
||||||
|
return { &st::mediaviewTitleMaximizeMac, st::mediaviewTitleMaximizeMacPadding };
|
||||||
|
case Control::Close:
|
||||||
|
return { &st::mediaviewTitleCloseMac, st::mediaviewTitleCloseMacPadding };
|
||||||
|
}
|
||||||
|
Unexpected("Value in DefaultOverlayWidgetHelper::Buttons::create.");
|
||||||
|
}();
|
||||||
|
const auto icon = info.icon;
|
||||||
|
|
||||||
|
raw->resize(QRect(QPoint(), icon->size()).marginsAdded(info.padding).size());
|
||||||
|
state->frame = QImage(
|
||||||
|
icon->size() * style::DevicePixelRatio(),
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
state->frame.setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
|
|
||||||
|
const auto updateOver = [=] {
|
||||||
|
const auto over = raw->isOver();
|
||||||
|
if (state->over == over) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state->over = over;
|
||||||
|
const auto anyOver = over
|
||||||
|
|| _data->buttonClose->isOver()
|
||||||
|
|| _data->buttonMinimize->isOver()
|
||||||
|
|| _data->buttonMaximize->isOver();
|
||||||
|
if (_data->anyOver != anyOver) {
|
||||||
|
_data->anyOver = anyOver;
|
||||||
|
_data->buttonClose->update();
|
||||||
|
_data->buttonMinimize->update();
|
||||||
|
_data->buttonMaximize->update();
|
||||||
|
}
|
||||||
|
state->animation.start(
|
||||||
|
[=] { raw->update(); },
|
||||||
|
state->over ? 0. : 1.,
|
||||||
|
state->over ? 1. : 0.,
|
||||||
|
st::mediaviewFadeDuration);
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto prepareFrame = [=] {
|
||||||
|
const auto progress = state->animation.value(state->over ? 1. : 0.);
|
||||||
|
const auto maximized = _data->maximized.current();
|
||||||
|
const auto anyOver = _data->anyOver;
|
||||||
|
if (state->progress == progress
|
||||||
|
&& state->maximized == maximized
|
||||||
|
&& state->anyOver == anyOver) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state->progress = progress;
|
||||||
|
state->maximized = maximized;
|
||||||
|
state->anyOver = anyOver;
|
||||||
|
auto current = icon;
|
||||||
|
if (control == Control::Maximize) {
|
||||||
|
current = maximized ? &st::mediaviewTitleRestoreMac : icon;
|
||||||
|
}
|
||||||
|
state->frame.fill(Qt::transparent);
|
||||||
|
|
||||||
|
auto q = QPainter(&state->frame);
|
||||||
|
const auto normal = maximized
|
||||||
|
? kMaximizedIconOpacity
|
||||||
|
: kNormalIconOpacity;
|
||||||
|
q.setOpacity(progress + (1 - progress) * normal);
|
||||||
|
st::mediaviewTitleButtonMac.paint(q, 0, 0, raw->width());
|
||||||
|
if (anyOver) {
|
||||||
|
q.setOpacity(1.);
|
||||||
|
current->paint(q, 0, 0, raw->width());
|
||||||
|
}
|
||||||
|
q.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
raw->paintRequest(
|
||||||
|
) | rpl::start_with_next([=, padding = info.padding] {
|
||||||
|
updateOver();
|
||||||
|
prepareFrame();
|
||||||
|
|
||||||
|
auto p = QPainter(raw);
|
||||||
|
p.setOpacity(_data->masterOpacity.current());
|
||||||
|
p.drawImage(padding.left(), padding.top(), state->frame);
|
||||||
|
}, raw->lifetime());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<OverlayWidgetHelper> CreateOverlayWidgetHelper(
|
std::unique_ptr<OverlayWidgetHelper> CreateOverlayWidgetHelper(
|
||||||
not_null<Ui::RpWindow*> window,
|
not_null<Ui::RpWindow*> window,
|
||||||
Fn<void(bool)> maximize) {
|
Fn<void(bool)> maximize) {
|
||||||
|
|
|
@ -404,7 +404,7 @@ if customRunCommand:
|
||||||
stage('patches', """
|
stage('patches', """
|
||||||
git clone https://github.com/desktop-app/patches.git
|
git clone https://github.com/desktop-app/patches.git
|
||||||
cd patches
|
cd patches
|
||||||
git checkout e8574ccccc
|
git checkout 53214c8a8a
|
||||||
""")
|
""")
|
||||||
|
|
||||||
stage('msys64', """
|
stage('msys64', """
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 85b73e98eccec7e77d7910f92bf747c7db3f1c4c
|
Subproject commit 0b87868b1d708020155571d4e0c90095e58d6572
|