ORE Studio 0.0.4
Loading...
Searching...
No Matches
WidgetUtils.hpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * Copyright (C) 2026 Marco Craveiro <marco.craveiro@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 3 of the License, or (at your option) any later
8 * version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 * details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20#ifndef ORES_QT_WIDGET_UTILS_HPP
21#define ORES_QT_WIDGET_UTILS_HPP
22
23#include <QApplication>
24#include <QComboBox>
25#include <QListView>
26#include <QPointer>
27#include <QScreen>
28#include <QShowEvent>
29#include <QSize>
30#include <QTimer>
31#include <QWidget>
32#include "ores.qt/export.hpp"
33
34namespace ores::qt {
35
47class BoundedListView : public QListView {
48public:
49 static constexpr int max_popup_height = 250;
50
51 explicit BoundedListView(QComboBox* combo)
52 : QListView(combo), combo_(combo) {}
53
54 QSize sizeHint() const override {
55 const auto s = QListView::sizeHint();
56 return { s.width(), std::min(s.height(), max_popup_height) };
57 }
58
59protected:
60 void showEvent(QShowEvent* event) override {
61 QListView::showEvent(event);
62 // Post so this runs after QComboBox::showPopup() finishes sizing and
63 // positioning. We then correct both if needed.
64 QTimer::singleShot(0, this, [this]() {
65 QWidget* popup = parentWidget();
66 if (!popup || !combo_ || popup->height() <= max_popup_height)
67 return;
68
69 // Determine where the combo box is on screen.
70 const QPoint comboPos = combo_->mapToGlobal(QPoint(0, 0));
71 const QRect comboRect(comboPos, combo_->size());
72
73 // Get the available screen geometry.
74 const QScreen* screen = QApplication::screenAt(comboPos);
75 const QRect screenRect = screen
76 ? screen->availableGeometry()
77 : QRect(0, 0, 9999, 9999);
78
79 // Resize first, then reposition: prefer opening below the combo,
80 // fall back to above if there is not enough room.
81 popup->resize(popup->width(), max_popup_height);
82 int y = comboRect.bottom() + 1;
83 if (y + max_popup_height > screenRect.bottom())
84 y = comboRect.top() - max_popup_height;
85 popup->move(popup->x(), y);
86 });
87 }
88
89private:
90 QPointer<QComboBox> combo_;
91};
92
97
107 static void setupComboBoxes(QWidget* parent) {
108 for (auto* combo : parent->findChildren<QComboBox*>()) {
109 combo->setMaxVisibleItems(10);
110 combo->setView(new BoundedListView(combo));
111 }
112 }
113};
114
115}
116
117#endif
Qt-based graphical user interface for ORE Studio.
Definition AccountController.hpp:32
A QListView that caps the combo box popup height and repositions it.
Definition WidgetUtils.hpp:47
Utility functions for common widget configuration.
Definition WidgetUtils.hpp:96
static void setupComboBoxes(QWidget *parent)
Apply standard configuration to all combo boxes in a widget.
Definition WidgetUtils.hpp:107