Toggle main window hide on tray icon click
- converted openBictoinAction to toggleHideAction - put GUIUtil functions into a namespace instead of a class - put window-related functions together in optionsdialog Reasoning: - toggle is more typical behaviour - it's more functional - better UX The typical issue with toggling visibility is that when a window is obscured by other windows but in the 'shown' state, hiding it isn't what you want. I've added an 'isObscured' function to GUIUtil that checks several pixels in the window to see if they are visible on the desktop so that an obscured but shown window can be raised. Conflicts: src/qt/guiutil.cpp src/qt/guiutil.h
This commit is contained in:
parent
962e2fcdb6
commit
86d5634941
5 changed files with 90 additions and 44 deletions
|
@ -23,6 +23,7 @@
|
||||||
#include "guiconstants.h"
|
#include "guiconstants.h"
|
||||||
#include "askpassphrasedialog.h"
|
#include "askpassphrasedialog.h"
|
||||||
#include "notificator.h"
|
#include "notificator.h"
|
||||||
|
#include "guiutil.h"
|
||||||
|
|
||||||
#ifdef Q_WS_MAC
|
#ifdef Q_WS_MAC
|
||||||
#include "macdockiconhandler.h"
|
#include "macdockiconhandler.h"
|
||||||
|
@ -239,8 +240,8 @@ void BitcoinGUI::createActions()
|
||||||
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
|
optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this);
|
||||||
optionsAction->setToolTip(tr("Modify configuration options for bitcoin"));
|
optionsAction->setToolTip(tr("Modify configuration options for bitcoin"));
|
||||||
optionsAction->setMenuRole(QAction::PreferencesRole);
|
optionsAction->setMenuRole(QAction::PreferencesRole);
|
||||||
openBitcoinAction = new QAction(QIcon(":/icons/bitcoin"), tr("Open &Bitcoin"), this);
|
toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("Show/Hide &Bitcoin"), this);
|
||||||
openBitcoinAction->setToolTip(tr("Show the Bitcoin window"));
|
toggleHideAction->setToolTip(tr("Show or Hide the Bitcoin window"));
|
||||||
exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
|
exportAction = new QAction(QIcon(":/icons/export"), tr("&Export..."), this);
|
||||||
exportAction->setToolTip(tr("Export the data in the current tab to a file"));
|
exportAction->setToolTip(tr("Export the data in the current tab to a file"));
|
||||||
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this);
|
encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet"), this);
|
||||||
|
@ -255,7 +256,7 @@ void BitcoinGUI::createActions()
|
||||||
connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
|
connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
|
||||||
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
|
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
|
||||||
connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
|
connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
|
||||||
connect(openBitcoinAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized()));
|
connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden()));
|
||||||
connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
|
connect(encryptWalletAction, SIGNAL(triggered(bool)), this, SLOT(encryptWallet(bool)));
|
||||||
connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet()));
|
connect(backupWalletAction, SIGNAL(triggered()), this, SLOT(backupWallet()));
|
||||||
connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
|
connect(changePassphraseAction, SIGNAL(triggered()), this, SLOT(changePassphrase()));
|
||||||
|
@ -392,7 +393,7 @@ void BitcoinGUI::createTrayIcon()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Configuration of the tray icon (or dock icon) icon menu
|
// Configuration of the tray icon (or dock icon) icon menu
|
||||||
trayIconMenu->addAction(openBitcoinAction);
|
trayIconMenu->addAction(toggleHideAction);
|
||||||
trayIconMenu->addSeparator();
|
trayIconMenu->addSeparator();
|
||||||
trayIconMenu->addAction(messageAction);
|
trayIconMenu->addAction(messageAction);
|
||||||
#ifndef FIRST_CLASS_MESSAGING
|
#ifndef FIRST_CLASS_MESSAGING
|
||||||
|
@ -416,11 +417,33 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
|
||||||
if(reason == QSystemTrayIcon::Trigger)
|
if(reason == QSystemTrayIcon::Trigger)
|
||||||
{
|
{
|
||||||
// Click on system tray icon triggers "open bitcoin"
|
// Click on system tray icon triggers "open bitcoin"
|
||||||
openBitcoinAction->trigger();
|
toggleHideAction->trigger();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void BitcoinGUI::toggleHidden()
|
||||||
|
{
|
||||||
|
// activateWindow() (sometimes) helps with keyboard focus on Windows
|
||||||
|
if(isHidden())
|
||||||
|
{
|
||||||
|
show();
|
||||||
|
activateWindow();
|
||||||
|
}
|
||||||
|
else if(isMinimized())
|
||||||
|
{
|
||||||
|
showNormal();
|
||||||
|
activateWindow();
|
||||||
|
}
|
||||||
|
else if(GUIUtil::isObscured(this))
|
||||||
|
{
|
||||||
|
raise();
|
||||||
|
activateWindow();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
void BitcoinGUI::optionsClicked()
|
void BitcoinGUI::optionsClicked()
|
||||||
{
|
{
|
||||||
if(!clientModel || !clientModel->getOptionsModel())
|
if(!clientModel || !clientModel->getOptionsModel())
|
||||||
|
|
|
@ -81,7 +81,7 @@ private:
|
||||||
QAction *aboutAction;
|
QAction *aboutAction;
|
||||||
QAction *receiveCoinsAction;
|
QAction *receiveCoinsAction;
|
||||||
QAction *optionsAction;
|
QAction *optionsAction;
|
||||||
QAction *openBitcoinAction;
|
QAction *toggleHideAction;
|
||||||
QAction *exportAction;
|
QAction *exportAction;
|
||||||
QAction *encryptWalletAction;
|
QAction *encryptWalletAction;
|
||||||
QAction *backupWalletAction;
|
QAction *backupWalletAction;
|
||||||
|
@ -166,6 +166,8 @@ private slots:
|
||||||
|
|
||||||
/** Show window if hidden, unminimize when minimized */
|
/** Show window if hidden, unminimize when minimized */
|
||||||
void showNormalIfMinimized();
|
void showNormalIfMinimized();
|
||||||
|
/** Hide window if visible, show if hidden */
|
||||||
|
void toggleHidden();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,31 +19,33 @@
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
QString GUIUtil::dateTimeStr(qint64 nTime)
|
namespace GUIUtil {
|
||||||
{
|
|
||||||
return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString GUIUtil::dateTimeStr(const QDateTime &date)
|
QString dateTimeStr(const QDateTime &date)
|
||||||
{
|
{
|
||||||
return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
|
return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm");
|
||||||
}
|
}
|
||||||
|
|
||||||
QFont GUIUtil::bitcoinAddressFont()
|
QString dateTimeStr(qint64 nTime)
|
||||||
|
{
|
||||||
|
return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
QFont bitcoinAddressFont()
|
||||||
{
|
{
|
||||||
QFont font("Monospace");
|
QFont font("Monospace");
|
||||||
font.setStyleHint(QFont::TypeWriter);
|
font.setStyleHint(QFont::TypeWriter);
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIUtil::setupAddressWidget(QLineEdit *widget, QWidget *parent)
|
void setupAddressWidget(QLineEdit *widget, QWidget *parent)
|
||||||
{
|
{
|
||||||
widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength);
|
widget->setMaxLength(BitcoinAddressValidator::MaxAddressLength);
|
||||||
widget->setValidator(new BitcoinAddressValidator(parent));
|
widget->setValidator(new BitcoinAddressValidator(parent));
|
||||||
widget->setFont(bitcoinAddressFont());
|
widget->setFont(bitcoinAddressFont());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIUtil::setupAmountWidget(QLineEdit *widget, QWidget *parent)
|
void setupAmountWidget(QLineEdit *widget, QWidget *parent)
|
||||||
{
|
{
|
||||||
QDoubleValidator *amountValidator = new QDoubleValidator(parent);
|
QDoubleValidator *amountValidator = new QDoubleValidator(parent);
|
||||||
amountValidator->setDecimals(8);
|
amountValidator->setDecimals(8);
|
||||||
|
@ -52,7 +54,7 @@ void GUIUtil::setupAmountWidget(QLineEdit *widget, QWidget *parent)
|
||||||
widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GUIUtil::parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
|
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
|
||||||
{
|
{
|
||||||
if(uri.scheme() != QString("bitcoin"))
|
if(uri.scheme() != QString("bitcoin"))
|
||||||
return false;
|
return false;
|
||||||
|
@ -97,7 +99,7 @@ bool GUIUtil::parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GUIUtil::parseBitcoinURI(QString uri, SendCoinsRecipient *out)
|
bool parseBitcoinURI(QString uri, SendCoinsRecipient *out)
|
||||||
{
|
{
|
||||||
// Convert bitcoin:// to bitcoin:
|
// Convert bitcoin:// to bitcoin:
|
||||||
//
|
//
|
||||||
|
@ -111,7 +113,7 @@ bool GUIUtil::parseBitcoinURI(QString uri, SendCoinsRecipient *out)
|
||||||
return parseBitcoinURI(uriInstance, out);
|
return parseBitcoinURI(uriInstance, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GUIUtil::HtmlEscape(const QString& str, bool fMultiLine)
|
QString HtmlEscape(const QString& str, bool fMultiLine)
|
||||||
{
|
{
|
||||||
QString escaped = Qt::escape(str);
|
QString escaped = Qt::escape(str);
|
||||||
if(fMultiLine)
|
if(fMultiLine)
|
||||||
|
@ -121,12 +123,12 @@ QString GUIUtil::HtmlEscape(const QString& str, bool fMultiLine)
|
||||||
return escaped;
|
return escaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GUIUtil::HtmlEscape(const std::string& str, bool fMultiLine)
|
QString HtmlEscape(const std::string& str, bool fMultiLine)
|
||||||
{
|
{
|
||||||
return HtmlEscape(QString::fromStdString(str), fMultiLine);
|
return HtmlEscape(QString::fromStdString(str), fMultiLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIUtil::copyEntryData(QAbstractItemView *view, int column, int role)
|
void copyEntryData(QAbstractItemView *view, int column, int role)
|
||||||
{
|
{
|
||||||
if(!view || !view->selectionModel())
|
if(!view || !view->selectionModel())
|
||||||
return;
|
return;
|
||||||
|
@ -139,7 +141,7 @@ void GUIUtil::copyEntryData(QAbstractItemView *view, int column, int role)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GUIUtil::getSaveFileName(QWidget *parent, const QString &caption,
|
QString getSaveFileName(QWidget *parent, const QString &caption,
|
||||||
const QString &dir,
|
const QString &dir,
|
||||||
const QString &filter,
|
const QString &filter,
|
||||||
QString *selectedSuffixOut)
|
QString *selectedSuffixOut)
|
||||||
|
@ -185,7 +187,7 @@ QString GUIUtil::getSaveFileName(QWidget *parent, const QString &caption,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::ConnectionType GUIUtil::blockingGUIThreadConnection()
|
Qt::ConnectionType blockingGUIThreadConnection()
|
||||||
{
|
{
|
||||||
if(QThread::currentThread() != QCoreApplication::instance()->thread())
|
if(QThread::currentThread() != QCoreApplication::instance()->thread())
|
||||||
{
|
{
|
||||||
|
@ -196,3 +198,23 @@ Qt::ConnectionType GUIUtil::blockingGUIThreadConnection()
|
||||||
return Qt::DirectConnection;
|
return Qt::DirectConnection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool checkPoint(const QPoint &p, const QWidget *w)
|
||||||
|
{
|
||||||
|
QWidget *atW = qApp->widgetAt(w->mapToGlobal(p));
|
||||||
|
if(!atW) return false;
|
||||||
|
return atW->topLevelWidget() == w;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isObscured(QWidget *w)
|
||||||
|
{
|
||||||
|
|
||||||
|
return !(checkPoint(QPoint(0, 0), w)
|
||||||
|
&& checkPoint(QPoint(w->width() - 1, 0), w)
|
||||||
|
&& checkPoint(QPoint(0, w->height() - 1), w)
|
||||||
|
&& checkPoint(QPoint(w->width() - 1, w->height() - 1), w)
|
||||||
|
&& checkPoint(QPoint(w->width()/2, w->height()/2), w));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace GUIUtil
|
||||||
|
|
||||||
|
|
|
@ -13,30 +13,29 @@ class QAbstractItemView;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
class SendCoinsRecipient;
|
class SendCoinsRecipient;
|
||||||
|
|
||||||
/** Static utility functions used by the Bitcoin Qt UI.
|
/** Utility functions used by the Bitcoin Qt UI.
|
||||||
*/
|
*/
|
||||||
class GUIUtil
|
namespace GUIUtil
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
// Create human-readable string from date
|
// Create human-readable string from date
|
||||||
static QString dateTimeStr(qint64 nTime);
|
QString dateTimeStr(const QDateTime &datetime);
|
||||||
static QString dateTimeStr(const QDateTime &datetime);
|
QString dateTimeStr(qint64 nTime);
|
||||||
|
|
||||||
// Render bitcoin addresses in monospace font
|
// Render bitcoin addresses in monospace font
|
||||||
static QFont bitcoinAddressFont();
|
QFont bitcoinAddressFont();
|
||||||
|
|
||||||
// Set up widgets for address and amounts
|
// Set up widgets for address and amounts
|
||||||
static void setupAddressWidget(QLineEdit *widget, QWidget *parent);
|
void setupAddressWidget(QLineEdit *widget, QWidget *parent);
|
||||||
static void setupAmountWidget(QLineEdit *widget, QWidget *parent);
|
void setupAmountWidget(QLineEdit *widget, QWidget *parent);
|
||||||
|
|
||||||
// Parse "bitcoin:" URI into recipient object, return true on succesful parsing
|
// Parse "bitcoin:" URI into recipient object, return true on succesful parsing
|
||||||
// See Bitcoin URI definition discussion here: https://bitcointalk.org/index.php?topic=33490.0
|
// See Bitcoin URI definition discussion here: https://bitcointalk.org/index.php?topic=33490.0
|
||||||
static bool parseBitcoinURI(const QUrl &, SendCoinsRecipient *out);
|
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out);
|
||||||
static bool parseBitcoinURI(QString uri, SendCoinsRecipient *out);
|
bool parseBitcoinURI(QString uri, SendCoinsRecipient *out);
|
||||||
|
|
||||||
// HTML escaping for rich text controls
|
// HTML escaping for rich text controls
|
||||||
static QString HtmlEscape(const QString& str, bool fMultiLine=false);
|
QString HtmlEscape(const QString& str, bool fMultiLine=false);
|
||||||
static QString HtmlEscape(const std::string& str, bool fMultiLine=false);
|
QString HtmlEscape(const std::string& str, bool fMultiLine=false);
|
||||||
|
|
||||||
/** Copy a field of the currently selected entry of a view to the clipboard. Does nothing if nothing
|
/** Copy a field of the currently selected entry of a view to the clipboard. Does nothing if nothing
|
||||||
is selected.
|
is selected.
|
||||||
|
@ -44,7 +43,7 @@ public:
|
||||||
@param[in] role Data role to extract from the model
|
@param[in] role Data role to extract from the model
|
||||||
@see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
|
@see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
|
||||||
*/
|
*/
|
||||||
static void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole);
|
void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole);
|
||||||
|
|
||||||
/** Get save file name, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
|
/** Get save file name, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
|
||||||
when no suffix is provided by the user.
|
when no suffix is provided by the user.
|
||||||
|
@ -56,18 +55,20 @@ public:
|
||||||
@param[out] selectedSuffixOut Pointer to return the suffix (file type) that was selected (or 0).
|
@param[out] selectedSuffixOut Pointer to return the suffix (file type) that was selected (or 0).
|
||||||
Can be useful when choosing the save file format based on suffix.
|
Can be useful when choosing the save file format based on suffix.
|
||||||
*/
|
*/
|
||||||
static QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(),
|
QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(),
|
||||||
const QString &dir=QString(), const QString &filter=QString(),
|
const QString &dir=QString(), const QString &filter=QString(),
|
||||||
QString *selectedSuffixOut=0);
|
QString *selectedSuffixOut=0);
|
||||||
|
|
||||||
|
|
||||||
/** Get connection type to call object slot in GUI thread with invokeMethod. The call will be blocking.
|
/** Get connection type to call object slot in GUI thread with invokeMethod. The call will be blocking.
|
||||||
|
|
||||||
@returns If called from the GUI thread, return a Qt::DirectConnection.
|
@returns If called from the GUI thread, return a Qt::DirectConnection.
|
||||||
If called from another thread, return a Qt::BlockingQueuedConnection.
|
If called from another thread, return a Qt::BlockingQueuedConnection.
|
||||||
*/
|
*/
|
||||||
static Qt::ConnectionType blockingGUIThreadConnection();
|
Qt::ConnectionType blockingGUIThreadConnection();
|
||||||
|
|
||||||
};
|
// Determine whether a widget is hidden behind other windows
|
||||||
|
bool isObscured(QWidget *w);
|
||||||
|
|
||||||
|
} // namespace GUIUtil
|
||||||
|
|
||||||
#endif // GUIUTIL_H
|
#endif // GUIUTIL_H
|
||||||
|
|
|
@ -175,18 +175,16 @@ MainOptionsPage::MainOptionsPage(QWidget *parent):
|
||||||
minimize_to_tray = new QCheckBox(tr("&Minimize to the tray instead of the taskbar"));
|
minimize_to_tray = new QCheckBox(tr("&Minimize to the tray instead of the taskbar"));
|
||||||
minimize_to_tray->setToolTip(tr("Show only a tray icon after minimizing the window"));
|
minimize_to_tray->setToolTip(tr("Show only a tray icon after minimizing the window"));
|
||||||
layout->addWidget(minimize_to_tray);
|
layout->addWidget(minimize_to_tray);
|
||||||
|
|
||||||
|
minimize_on_close = new QCheckBox(tr("M&inimize on close"));
|
||||||
|
minimize_on_close->setToolTip(tr("Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu."));
|
||||||
|
layout->addWidget(minimize_on_close);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
map_port_upnp = new QCheckBox(tr("Map port using &UPnP"));
|
map_port_upnp = new QCheckBox(tr("Map port using &UPnP"));
|
||||||
map_port_upnp->setToolTip(tr("Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled."));
|
map_port_upnp->setToolTip(tr("Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled."));
|
||||||
layout->addWidget(map_port_upnp);
|
layout->addWidget(map_port_upnp);
|
||||||
|
|
||||||
#ifndef Q_WS_MAC
|
|
||||||
minimize_on_close = new QCheckBox(tr("M&inimize on close"));
|
|
||||||
minimize_on_close->setToolTip(tr("Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu."));
|
|
||||||
layout->addWidget(minimize_on_close);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
connect_socks4 = new QCheckBox(tr("&Connect through SOCKS4 proxy:"));
|
connect_socks4 = new QCheckBox(tr("&Connect through SOCKS4 proxy:"));
|
||||||
connect_socks4->setToolTip(tr("Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor)"));
|
connect_socks4->setToolTip(tr("Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor)"));
|
||||||
layout->addWidget(connect_socks4);
|
layout->addWidget(connect_socks4);
|
||||||
|
|
Loading…
Reference in a new issue