Viewer: inspector width from its content, fold it away on a narrow window
The inspector's width bounds were 75-100 average character widths, which on macOS (8 px) came to 600 px for content that needs 397. They are now measured: at least the panel's minimum size hint plus the scroll bar, at most a third more. CollapsibleSection reports its folded content's width in minimumSizeHint, so the panel keeps its width when a section opens. On a font change the measurement waits a turn, until the children have the new font. When shrinking the window would leave the image narrower than the inspector, the inspector folds away, with the magnifier if it shares the inspector's column; they come back once the image would still be at least as wide as the inspector (plus 40 px of hysteresis). Only a shrink folds, a dock shown by anyone else is no longer the window's to restore, and folded docks are saved as open. Measured on a 1920 px screen: folds at 1140 px, returns at 1260 px; at 960 px the image gets 620 px instead of ~145. Dark theme: disabled text is set explicitly (#858AAE, ~4.8:1 on the panels) instead of the derived colour, which was nearly the panel colour and made greyed-out fields look empty. The splash text is black in either theme: its message is rich text, which takes the palette's text colour rather than showMessage's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9f369567f1
commit
22d4e94bd8
6 files changed
+74
-11
No files matched your search
@@ -17,6 +17,9 @@
|
||||
#include <QScreen>
|
||||
#include <QApplication>
|
||||
#include <QScrollArea>
|
||||
#include <QScrollBar>
|
||||
#include <QResizeEvent>
|
||||
#include <utility>
|
||||
#include <QSettings>
|
||||
#include <QCloseEvent>
|
||||
#include <QRandomGenerator>
|
||||
@@ -163,6 +166,10 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString
|
||||
splitDockWidget(inspectorDock, magnifierDock, Qt::Vertical);
|
||||
resizeDocks({inspectorDock, magnifierDock}, {600, 400}, Qt::Vertical);
|
||||
menuBar->AddDockEntry(magnifierDock, "Magnifier");
|
||||
// Shown by anyone - the Window menu, a layout, a reset - it is no longer the window's to restore.
|
||||
for (auto *dock: {inspectorDock, magnifierDock})
|
||||
connect(dock, &QDockWidget::visibilityChanged, this,
|
||||
[this, dock](bool visible) { if (visible) autoHiddenDocks.removeAll(dock); });
|
||||
|
||||
magnifierWindow = new JFJochHelperWindow(this);
|
||||
magnifierWindow->setWindowTitle("Magnifier");
|
||||
@@ -719,26 +726,59 @@ void JFJochViewerWindow::ResetAllSettings() {
|
||||
menuBar->ResetFontZoom();
|
||||
}
|
||||
|
||||
// The inspector's width bounds are a character count, not a pixel count, so the value column keeps
|
||||
// up with the text - the View menu's font zoom or the desktop's scaling. At the default font this
|
||||
// is the 450/600 px it has always been. The count comes from the application font rather than the
|
||||
// scroll area's: on a font change the window is told before its children are.
|
||||
// The inspector's width bounds are measured from its content: at least what its widest section needs
|
||||
// (folded ones included, see CollapsibleSection) plus the scroll bar, so nothing is cut off, and a third
|
||||
// more at most - wider only adds empty space next to the text, and takes it from the image. Measured
|
||||
// rather than counted in characters, as they once were, because a character count that suits one
|
||||
// platform's font is far too wide on another's (600 px for 400 px of content on macOS).
|
||||
void JFJochViewerWindow::UpdateInspectorWidth() {
|
||||
const int char_width = QFontMetrics(QApplication::font()).averageCharWidth();
|
||||
inspectorScroll->setMinimumWidth(75 * char_width);
|
||||
inspectorScroll->setMaximumWidth(100 * char_width);
|
||||
const int need = inspectorScroll->widget()->minimumSizeHint().width()
|
||||
+ inspectorScroll->verticalScrollBar()->sizeHint().width();
|
||||
inspectorScroll->setMinimumWidth(need);
|
||||
inspectorScroll->setMaximumWidth(need * 4 / 3);
|
||||
}
|
||||
|
||||
void JFJochViewerWindow::changeEvent(QEvent *event) {
|
||||
QMainWindow::changeEvent(event);
|
||||
// The menu bar sets the application font while the window is still being built, so the inspector
|
||||
// is not there yet on the first one.
|
||||
// is not there yet on the first one. The window hears of a font change before its children do,
|
||||
// so the content is measured once they have all taken the new font.
|
||||
if (event->type() == QEvent::FontChange && inspectorScroll)
|
||||
UpdateInspectorWidth();
|
||||
QTimer::singleShot(0, this, &JFJochViewerWindow::UpdateInspectorWidth);
|
||||
}
|
||||
|
||||
// The image comes first. When shrinking the window would leave it narrower than the inspector next
|
||||
// to it, the inspector folds away, with the magnifier if it shares the inspector's column. They come
|
||||
// back once the image would still be at least as wide as the inspector with it restored (plus a
|
||||
// margin, so a window resized around the threshold does not flicker). Only a shrink folds: a panel
|
||||
// the user reopens on a narrow window stays open, and one the user closed is never brought back.
|
||||
void JFJochViewerWindow::resizeEvent(QResizeEvent *event) {
|
||||
QMainWindow::resizeEvent(event);
|
||||
if (!inspectorDock || !magnifierDock)
|
||||
return;
|
||||
const int image_width = centralWidget()->width();
|
||||
const bool shrinking = event->oldSize().width() < 0 || event->size().width() < event->oldSize().width();
|
||||
if (shrinking && inspectorDock->isVisible() && image_width < inspectorDock->width()) {
|
||||
autoHiddenWidth = inspectorDock->width();
|
||||
QList<QDockWidget *> docks = {inspectorDock};
|
||||
if (magnifierDock->isVisible() && dockWidgetArea(magnifierDock) == dockWidgetArea(inspectorDock))
|
||||
docks.append(magnifierDock);
|
||||
for (auto *dock: docks) {
|
||||
dock->hide();
|
||||
if (!autoHiddenDocks.contains(dock))
|
||||
autoHiddenDocks.append(dock);
|
||||
}
|
||||
} else if (!autoHiddenDocks.isEmpty() && image_width - autoHiddenWidth >= autoHiddenWidth + 40) {
|
||||
for (auto *dock: std::exchange(autoHiddenDocks, {}))
|
||||
dock->show();
|
||||
}
|
||||
}
|
||||
|
||||
void JFJochViewerWindow::closeEvent(QCloseEvent *event) {
|
||||
// Persist the dock/toolbar arrangement and window geometry so the next launch resumes it.
|
||||
// Persist the dock/toolbar arrangement and window geometry so the next launch resumes it. Docks
|
||||
// folded away only for a narrow window are saved as open: the next start may have the room.
|
||||
for (auto *dock: std::exchange(autoHiddenDocks, {}))
|
||||
dock->show();
|
||||
QSettings settings("PSI", "jfjoch_viewer");
|
||||
settings.setValue("geometry", saveGeometry());
|
||||
settings.setValue("windowState", saveState(kLayoutVersion));
|
||||
|
||||
@@ -68,6 +68,12 @@ private:
|
||||
void ResetAllSettings();
|
||||
void UpdateInspectorWidth();
|
||||
|
||||
// A narrow window folds the inspector away (with the magnifier, when it is docked in the same
|
||||
// column) so the image keeps its room, and brings it back once the window is wide enough again.
|
||||
QList<QDockWidget *> autoHiddenDocks; // hidden by the window, not by the user
|
||||
int autoHiddenWidth = 0; // the inspector column's width when it was folded away
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
// Both ways of opening a dataset from outside the file manager - the File menu and D-Bus -
|
||||
// come through here, so the browser follows the same way for either.
|
||||
void FollowInFileBrowser(const QString &filename);
|
||||
|
||||
@@ -66,6 +66,10 @@ namespace {
|
||||
pal.setColor(QPalette::Link, QColor(0x8A, 0xB4, 0xF8));
|
||||
pal.setColor(QPalette::PlaceholderText, QColor(0x80, 0x84, 0xA8));
|
||||
SetTextColor(pal, DARK_TEXT);
|
||||
// The derived disabled text is nearly the panel colour, so a greyed-out field looked empty.
|
||||
// A muted lavender still reads (about 4.8:1 on the panels, against 13:1 for normal text).
|
||||
for (auto role: {QPalette::WindowText, QPalette::Text, QPalette::ButtonText})
|
||||
pal.setColor(QPalette::Disabled, role, QColor(0x85, 0x8A, 0xAE));
|
||||
return pal;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,8 +127,11 @@ int main(int argc, char *argv[]) {
|
||||
QSplashScreen *splash = new QSplashScreen(splash_pixmap);
|
||||
splash->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::SplashScreen);
|
||||
QString version(QString::fromStdString(jfjoch_version()));
|
||||
// The splash is white in either theme, so its text is black in either theme too. The message is
|
||||
// rich text, and rich text takes its colour from the palette, not from showMessage's colour.
|
||||
splash->showMessage(
|
||||
"<b>Jungfrujoch image viewer</b><br/> Version " + version + "<br/>Paul Scherrer Institut",
|
||||
"<span style=\"color: black;\"><b>Jungfrujoch image viewer</b><br/> Version " + version
|
||||
+ "<br/>Paul Scherrer Institut</span>",
|
||||
Qt::AlignBottom | Qt::AlignHCenter,
|
||||
Qt::black
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "CollapsibleSection.h"
|
||||
#include "../ViewerTheme.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
@@ -45,3 +46,10 @@ void CollapsibleSection::setContentLayout(QLayout *layout) {
|
||||
void CollapsibleSection::setExpanded(bool on) {
|
||||
header_->setChecked(on);
|
||||
}
|
||||
|
||||
QSize CollapsibleSection::minimumSizeHint() const {
|
||||
// A hidden widget does not count towards its parent's layout, so the folded content is measured here.
|
||||
QSize s = QWidget::minimumSizeHint();
|
||||
s.setWidth(std::max(s.width(), content_->minimumSizeHint().width()));
|
||||
return s;
|
||||
}
|
||||
@@ -17,6 +17,8 @@ public:
|
||||
explicit CollapsibleSection(const QString &title, QWidget *parent = nullptr);
|
||||
void setContentLayout(QLayout *layout);
|
||||
void setExpanded(bool on);
|
||||
// As wide as the content needs even while folded, so a panel keeps its width when a section opens.
|
||||
QSize minimumSizeHint() const override;
|
||||
|
||||
private:
|
||||
QToolButton *header_;
|
||||
|
||||
Reference in new issue
Block a user