yacreader/custom_widgets/yacreader_macosx_toolbar.mm
Luis Ángel San Martín Rodríguez e026f25617 QMacToolBar is not available in Qt6
This commit adds new qt pure versions of the mac toolbar to be used in qt6.
2022-09-12 19:24:56 +02:00

504 lines
14 KiB
Plaintext

#include "yacreader_macosx_toolbar.h"
#include "QtWidgets/qmainwindow.h"
#include <QtGlobal>
#include <QtWidgets>
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include <QWidget>
#include <QMacNativeWidget>
#include <qmacfunctions.h>
#include <qpa/qplatformnativeinterface.h>
#include <QsLog.h>
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "shortcuts_manager.h"
//----------------------------
// A custom items separator for NSToolbar
@interface CustomSeparator : NSView
@end
@implementation CustomSeparator
- (void)drawRect:(NSRect)rect
{
[[NSColor colorWithDeviceRed:0.5 green:0.5 blue:0.5 alpha:1] setFill];
NSRectFill(rect);
[super drawRect:rect];
}
@end
//----------------------------
// Toolbar delegate, needed for allow disabled/enabled items
@interface MyToolbarDelegate : NSObject <NSToolbarDelegate> {
@public
YACReaderMacOSXToolbar *mytoolbar;
}
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdent willBeInsertedIntoToolbar:(BOOL)willBeInserted;
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar;
- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar;
//- (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar;
- (IBAction)itemClicked:(id)sender;
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem;
@end
@implementation MyToolbarDelegate
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
{
Q_UNUSED(toolbar);
NSMutableArray *array = [[NSMutableArray alloc] init];
QList<QMacToolBarItem *> items = mytoolbar->items();
foreach (const QMacToolBarItem *item, items) {
[array addObject:item->nativeToolBarItem().itemIdentifier];
}
return array;
}
- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
{
Q_UNUSED(toolbar);
NSMutableArray *array = [[NSMutableArray alloc] init];
QList<QMacToolBarItem *> items = mytoolbar->items();
foreach (const QMacToolBarItem *item, items) {
[array addObject:item->nativeToolBarItem().itemIdentifier];
}
return array;
}
/*
- (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar
{
Q_UNUSED(toolbar);
NSMutableArray *array = [[NSMutableArray alloc] init];
QList<QMacToolBarItem *> items = mytoolbar->items();
foreach (const QMacToolBarItem * item, items) {
[array addObject : item->nativeToolBarItem().itemIdentifier];
}
return array;
//NSMutableArray *array = toolbarPrivate->getItemIdentifiers(toolbarPrivate->items, true);
//[array addObjectsFromArray:toolbarPrivate->getItemIdentifiers(toolbarPrivate->allowedItems, true)];
//return array;
}*/
- (IBAction)itemClicked:(id)sender
{
if ([sender respondsToSelector:@selector(itemIdentifier)]) {
NSToolbarItem *item = reinterpret_cast<NSToolbarItem *>(sender);
QString identifier = QString::fromNSString([item itemIdentifier]);
QMacToolBarItem *toolButton = reinterpret_cast<QMacToolBarItem *>(identifier.toULongLong());
Q_EMIT toolButton->activated();
}
}
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)willBeInserted
{
Q_UNUSED(toolbar);
Q_UNUSED(willBeInserted);
QList<QMacToolBarItem *> items = mytoolbar->items();
foreach (const QMacToolBarItem *item, items) {
NSToolbarItem *toolbarItem = item->nativeToolBarItem();
if ([toolbarItem.itemIdentifier isEqual:itemIdentifier]) {
[toolbarItem setTarget:self];
[toolbarItem setAction:@selector(itemClicked:)];
return toolbarItem;
}
}
return nil;
}
- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
{
QString identifier = QString::fromNSString(theItem.itemIdentifier);
if (mytoolbar->actions.contains(identifier)) {
return mytoolbar->actions.value(identifier)->isEnabled();
} else
return NO;
}
@end
//----------------------------
// detect changes in native text field
// TODO implement validation and auto completion
@interface MyTextFieldDelegate : NSObject <NSTextFieldDelegate> {
@public
YACReaderMacOSXSearchLineEdit *mylineedit;
}
@end
@implementation MyTextFieldDelegate
- (void)controlTextDidChange:(NSNotification *)notification
{
NSTextField *textField = [notification object];
NSLog(@"%@", [textField stringValue]);
Q_EMIT mylineedit->filterChanged(QString::fromNSString([textField stringValue]));
}
@end
//----------------------------
YACReaderMacOSXToolbar::YACReaderMacOSXToolbar(QObject *parent)
: viewSelector(0)
{
// setup native toolbar
nativeToolBar = nativeToolbar();
[nativeToolBar setDisplayMode:NSToolbarDisplayModeIconOnly];
[nativeToolBar setAllowsUserCustomization:NO];
delegate = [[MyToolbarDelegate alloc] init];
((MyToolbarDelegate *)delegate)->mytoolbar = this;
[nativeToolBar setDelegate:(MyToolbarDelegate *)delegate];
#ifdef YACREADER_LIBRARY
NSWindow *nswindow = (NSWindow *)qApp->platformNativeInterface()->nativeResourceForWindow("nswindow", ((QMainWindow *)parent)->windowHandle());
if ([nswindow respondsToSelector:@selector(setTitleVisibility:)]) {
yosemite = true;
// TODO yosemite new constants are not found in compilation time
[nswindow setTitleVisibility:NSWindowTitleHidden];
// TODO NSFullSizeContentViewWindowMask produces an offset in the windows' content
// nswindow.styleMask |= 1 << 15; // NSFullSizeContentViewWindowMask;
[nativeToolBar setSizeMode:NSToolbarSizeModeSmall]; // TODO figure out how to load specific images in Yosemite
} else {
[nativeToolBar setSizeMode:NSToolbarSizeModeSmall];
yosemite = false;
}
#else
yosemite = false;
[nativeToolBar setAutosavesConfiguration:YES]; // TODO this doesn't work
[nativeToolBar setSizeMode:NSToolbarSizeModeSmall];
#endif
}
void YACReaderMacOSXToolbar::addAction(QAction *action)
{
QMacToolBarItem *toolBarItem = addItem(action->icon(), action->text());
if (action->data().toString() == TOGGLE_COMICS_VIEW_ACTION_YL)
viewSelector = toolBarItem;
connect(toolBarItem, &QMacToolBarItem::activated, action, [=] { emit action->triggered(); });
NSToolbarItem *nativeItem = toolBarItem->nativeToolBarItem();
actions.insert(QString::fromNSString(nativeItem.itemIdentifier), action);
MacToolBarItemWrapper *wrapper = new MacToolBarItemWrapper(action, toolBarItem);
// wrapper->actionToogled(true);
}
void YACReaderMacOSXToolbar::addDropDownItem(const QList<QAction *> &actions, const QAction *defaultAction)
{
// TODO
}
void YACReaderMacOSXToolbar::addSpace(int size)
{
QMacToolBarItem *toolBarItem = addItem(QIcon(), "");
NSToolbarItem *nativeItem = toolBarItem->nativeToolBarItem();
static const NSRect frameRect = { { 0.0, 0.0 }, { CGFloat(size), 16.0 } };
NSView *view = [[NSView alloc] initWithFrame:frameRect];
[nativeItem setView:view];
}
// reimplemented for convenience
void YACReaderMacOSXToolbar::addSeparator()
{
// QMacToolBar::addSeparator();
QMacToolBarItem *toolBarItem = addItem(QIcon(), "");
NSToolbarItem *nativeItem = toolBarItem->nativeToolBarItem();
static const NSRect frameRect = { { 0.0, 0.0 }, { 1, 16.0 } };
CustomSeparator *view = [[CustomSeparator alloc] initWithFrame:frameRect];
[nativeItem setView:view];
}
void YACReaderMacOSXToolbar::addStretch()
{
QMacToolBarItem *toolBarItem = addItem(QIcon(), "");
toolBarItem->setStandardItem(QMacToolBarItem::FlexibleSpace);
}
void YACReaderMacOSXToolbar::addWidget(QWidget *widget)
{
// TODO fix it
/* QMacNativeWidget *nativeWidget = new QMacNativeWidget();
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(widget);
nativeWidget->setLayout(layout);
NSView *nativeWidgetView = reinterpret_cast<NSView *>(nativeWidget->winId());
QMacToolBarItem *toolBarItem = addItem(QIcon(),"");
NSToolbarItem * nativeItem = toolBarItem->nativeToolBarItem();
[nativeItem setView:nativeWidgetView];*/
}
void YACReaderMacOSXToolbar::show()
{
[nativeToolBar setVisible:YES];
}
void YACReaderMacOSXToolbar::hide()
{
[nativeToolBar setVisible:NO];
}
YACReaderMacOSXSearchLineEdit *YACReaderMacOSXToolbar::addSearchEdit()
{
QMacToolBarItem *toolBarItem = addItem(QIcon(), "");
NSToolbarItem *nativeItem = toolBarItem->nativeToolBarItem();
YACReaderMacOSXSearchLineEdit *searchEdit = new YACReaderMacOSXSearchLineEdit();
if (yosemite)
[nativeItem setView:(NSTextField *)searchEdit->getNSTextField()];
else {
static const NSRect searchEditFrameRect = { { 0.0, 0.0 }, { 165, 26.0 } };
NSView *view = [[NSView alloc] initWithFrame:searchEditFrameRect];
[view addSubview:((NSTextField *)searchEdit->getNSTextField())];
[nativeItem setView:view];
}
return searchEdit;
}
// deprecated
QAction *YACReaderMacOSXToolbar::addFitToWidthSlider(QAction *attachToAction)
{
QMacToolBarItem *toolBarItem = addItem(QIcon(":/images/viewer_toolbar/toWidthSlider.png"), "fit to width slider");
NSToolbarItem *nativeItem = toolBarItem->nativeToolBarItem();
actions.insert(QString::fromNSString(nativeItem.itemIdentifier), attachToAction);
QAction *action = new QAction("", attachToAction->parent());
connect(toolBarItem, &QMacToolBarItem::activated, action, [=] { emit action->triggered(); });
return action;
}
void YACReaderMacOSXToolbar::updateViewSelectorIcon(const QIcon &icon)
{
if (viewSelector)
viewSelector->setIcon(icon);
}
void YACReaderMacOSXToolbar::attachToWindow(QMainWindow *window)
{
QMacToolBar::attachToWindow(window->windowHandle());
}
YACReaderMacOSXSearchLineEdit::YACReaderMacOSXSearchLineEdit()
: QObject()
{
NSRect searchEditFrameRect = { { 0.0, -3.0 }, { 165, 32.0 } };
// NSTextField * searchEdit = [[NSTextField alloc] initWithFrame:searchEditFrameRect];
NSTextField *searchEdit = [[NSSearchField alloc] initWithFrame:searchEditFrameRect];
//[searchEdit setBezelStyle:NSTextFieldRoundedBezel];
[[searchEdit cell] setPlaceholderString:@"type to search"];
MyTextFieldDelegate *delegate = [[MyTextFieldDelegate alloc] init];
delegate->mylineedit = this;
[searchEdit setDelegate:delegate];
nstextfield = searchEdit;
}
void YACReaderMacOSXSearchLineEdit::setFocus(Qt::FocusReason reason)
{
Q_UNUSED(reason)
[((NSTextField *)nstextfield) becomeFirstResponder];
}
void *YACReaderMacOSXSearchLineEdit::getNSTextField()
{
return nstextfield;
}
QString YACReaderMacOSXSearchLineEdit::text()
{
return QString::fromNSString([((NSTextField *)nstextfield) stringValue]);
}
void YACReaderMacOSXSearchLineEdit::clear()
{
[((NSTextField *)nstextfield) setStringValue:@""];
emit filterChanged("");
}
void YACReaderMacOSXSearchLineEdit::clearText()
{
// TODO be sure that this will not generate any event....
[((NSTextField *)nstextfield) setStringValue:@""];
}
void YACReaderMacOSXSearchLineEdit::setDisabled(bool disabled)
{
[((NSTextField *)nstextfield) setEnabled:!disabled];
}
void YACReaderMacOSXSearchLineEdit::setEnabled(bool enabled)
{
[((NSTextField *)nstextfield) setEnabled:enabled];
}
MacToolBarItemWrapper::MacToolBarItemWrapper(QAction *action, QMacToolBarItem *toolbaritem)
: action(action), toolbaritem(toolbaritem)
{
if (action->isCheckable()) {
connect(action, &QAction::toggled, this, &MacToolBarItemWrapper::actionToggled);
connect(toolbaritem, &QMacToolBarItem::activated, action, &QAction::toggle);
updateIcon(action->isChecked());
}
}
void MacToolBarItemWrapper::actionToggled(bool toogled)
{
updateIcon(toogled);
}
void MacToolBarItemWrapper::updateIcon(bool enabled)
{
if (enabled) {
QIcon icon = action->icon();
QPixmap tempPixmap = icon.pixmap(QSize(24, 24));
QPainter painter;
painter.begin(&tempPixmap);
painter.fillRect(QRect(3, 21, 18, 1), QColor("#3F3F3F"));
painter.fillRect(QRect(3, 22, 18, 1), QColor("#6E6E6E"));
painter.fillRect(QRect(3, 23, 18, 1), QColor("#EEEEEE"));
painter.end();
toolbaritem->setIcon(QIcon(tempPixmap));
} else
toolbaritem->setIcon(action->icon());
}
#else
#ifdef YACREADER_LIBRARY
YACReaderMacOSXToolbar::YACReaderMacOSXToolbar(QWidget *parent)
: YACReaderMainToolBar(parent)
{
backButton->setIconSize(QSize(24, 24));
forwardButton->setIconSize(QSize(24, 24));
settingsButton->setIconSize(QSize(24, 24));
serverButton->setIconSize(QSize(24, 24));
helpButton->setIconSize(QSize(24, 24));
toggleComicsViewButton->setIconSize(QSize(24, 24));
}
QSize YACReaderMacOSXToolbar::sizeHint() const
{
return QSize(400, 36);
}
void YACReaderMacOSXToolbar::addAction(QAction *action)
{
if (backButton->defaultAction() == nullptr) {
backButton->setDefaultAction(action);
return;
}
if (forwardButton->defaultAction() == nullptr) {
forwardButton->setDefaultAction(action);
return;
}
if (settingsButton->defaultAction() == nullptr) {
settingsButton->setDefaultAction(action);
return;
}
if (serverButton->defaultAction() == nullptr) {
serverButton->setDefaultAction(action);
return;
}
if (helpButton->defaultAction() == nullptr) {
helpButton->setDefaultAction(action);
return;
}
if (toggleComicsViewButton->defaultAction() == nullptr) {
toggleComicsViewButton->setDefaultAction(action);
return;
}
}
void YACReaderMacOSXToolbar::addSpace(int size)
{
}
void YACReaderMacOSXToolbar::addStretch()
{
}
YACReaderMacOSXSearchLineEdit *YACReaderMacOSXToolbar::addSearchEdit()
{
auto search = new YACReaderMacOSXSearchLineEdit();
setSearchWidget(search);
return search;
}
void YACReaderMacOSXToolbar::updateViewSelectorIcon(const QIcon &icon)
{
}
void YACReaderMacOSXToolbar::attachToWindow(QMainWindow *window)
{
auto toolbar = new QToolBar();
toolbar->addWidget(this);
toolbar->setMovable(false);
window->addToolBar(toolbar);
}
void YACReaderMacOSXToolbar::paintEvent(QPaintEvent *)
{
}
#else
YACReaderMacOSXToolbar::YACReaderMacOSXToolbar(QWidget *parent)
: QToolBar(parent)
{
setMovable(false);
setIconSize(QSize(24, 24));
}
void YACReaderMacOSXToolbar::attachToWindow(QMainWindow *window)
{
window->setUnifiedTitleAndToolBarOnMac(true);
window->addToolBar(this);
}
void YACReaderMacOSXToolbar::addStretch()
{
}
#endif
#endif