├── CMakeLists.txt ├── Colormap.cpp ├── GUI.cpp ├── Graph.cpp ├── PPP ├── GUI.h ├── GUI_private.h ├── Graph.h ├── Image_private.h ├── Point.h ├── Simple_window.h ├── Window.h └── std_lib_facilities.h ├── Programming_Qt.sln ├── Programming_Qt.vcxproj ├── README.md ├── Simple_window.cpp ├── UserGuide.odt ├── UserGuide.pdf ├── Window.cpp └── main.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(Programming_Qt VERSION 0.1 LANGUAGES CXX) 4 | 5 | set(CMAKE_AUTOUIC ON) 6 | set(CMAKE_AUTOMOC ON) 7 | set(CMAKE_AUTORCC ON) 8 | 9 | set(CMAKE_CXX_STANDARD 20) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) 13 | find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) 14 | 15 | set(PROJECT_SOURCES 16 | main.cpp 17 | PPP/Window.h 18 | PPP/Graph.h 19 | PPP/GUI.h 20 | PPP/Simple_window.h 21 | PPP/Point.h 22 | PPP/std_lib_facilities.h 23 | Window.cpp 24 | Graph.cpp 25 | PPP/Image_private.h 26 | GUI.cpp 27 | PPP/GUI_private.h 28 | Simple_window.cpp 29 | Colormap.cpp 30 | ) 31 | 32 | if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) 33 | qt_add_executable(Programming_Qt 34 | MANUAL_FINALIZATION 35 | ${PROJECT_SOURCES} 36 | ) 37 | 38 | # Define target properties for Android with Qt 6 as: 39 | # set_property(TARGET Programming_Qt APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR 40 | # ${CMAKE_CURRENT_SOURCE_DIR}/android) 41 | # For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation 42 | else() 43 | if(ANDROID) 44 | add_library(Programming_Qt SHARED 45 | ${PROJECT_SOURCES} 46 | ) 47 | # Define properties for Android with Qt 5 after find_package() calls as: 48 | # set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") 49 | else() 50 | add_executable(Programming_Qt 51 | ${PROJECT_SOURCES} 52 | ) 53 | endif() 54 | endif() 55 | 56 | target_link_libraries(Programming_Qt PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) 57 | target_include_directories(Programming_Qt PRIVATE .) 58 | 59 | set_target_properties(Programming_Qt PROPERTIES 60 | MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com 61 | MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} 62 | MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} 63 | MACOSX_BUNDLE TRUE 64 | WIN32_EXECUTABLE TRUE 65 | ) 66 | 67 | if(MSVC) 68 | target_compile_options(Programming_Qt PRIVATE /EHsc /W4 /WX) 69 | else() 70 | target_compile_options(Programming_Qt PRIVATE -Wall -Wextra -Wpedantic -Werror) 71 | endif() 72 | 73 | if (EMSCRIPTEN) 74 | target_link_options(Programming_Qt PUBLIC -sASYNCIFY -Os) 75 | endif() 76 | 77 | install(TARGETS Programming_Qt 78 | BUNDLE DESTINATION . 79 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) 80 | 81 | if(QT_VERSION_MAJOR EQUAL 6) 82 | qt_finalize_executable(Programming_Qt) 83 | endif() 84 | -------------------------------------------------------------------------------- /Colormap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static QColor paletteColorMap[] = { 5 | {0, 0, 0}, 6 | {255, 0, 0}, 7 | {0, 255, 0}, 8 | {255, 255, 0}, 9 | {0, 0, 255}, 10 | {255, 0, 255}, 11 | {0, 255, 255}, 12 | {255, 255, 255}, 13 | {85, 85, 85}, 14 | {198, 113, 113}, 15 | {113, 198, 113}, 16 | {142, 142, 56}, 17 | {113, 113, 198}, 18 | {142, 56, 142}, 19 | {56, 142, 142}, 20 | {0, 0, 128}, 21 | {168, 168, 152}, 22 | {232, 232, 216}, 23 | {104, 104, 88}, 24 | {152, 168, 168}, 25 | {216, 232, 232}, 26 | {88, 104, 104}, 27 | {156, 156, 168}, 28 | {220, 220, 232}, 29 | {92, 92, 104}, 30 | {156, 168, 156}, 31 | {220, 232, 220}, 32 | {92, 104, 92}, 33 | {144, 144, 144}, 34 | {192, 192, 192}, 35 | {80, 80, 80}, 36 | {160, 160, 160}, 37 | {0, 0, 0}, 38 | {13, 13, 13}, 39 | {26, 26, 26}, 40 | {38, 38, 38}, 41 | {49, 49, 49}, 42 | {61, 61, 61}, 43 | {72, 72, 72}, 44 | {85, 85, 85}, 45 | {95, 95, 95}, 46 | {106, 106, 106}, 47 | {117, 117, 117}, 48 | {128, 128, 128}, 49 | {138, 138, 138}, 50 | {149, 149, 149}, 51 | {160, 160, 160}, 52 | {170, 170, 170}, 53 | {181, 181, 181}, 54 | {192, 192, 192}, 55 | {203, 203, 203}, 56 | {213, 213, 213}, 57 | {224, 224, 224}, 58 | {234, 234, 234}, 59 | {245, 245, 245}, 60 | {255, 255, 255}, 61 | {0, 0, 0}, 62 | {0, 36, 0}, 63 | {0, 72, 0}, 64 | {0, 109, 0}, 65 | {0, 145, 0}, 66 | {0, 182, 0}, 67 | {0, 218, 0}, 68 | {0, 255, 0}, 69 | {63, 0, 0}, 70 | {63, 36, 0}, 71 | {63, 72, 0}, 72 | {63, 109, 0}, 73 | {63, 145, 0}, 74 | {63, 182, 0}, 75 | {63, 218, 0}, 76 | {63, 255, 0}, 77 | {127, 0, 0}, 78 | {127, 36, 0}, 79 | {127, 72, 0}, 80 | {127, 109, 0}, 81 | {127, 145, 0}, 82 | {127, 182, 0}, 83 | {127, 218, 0}, 84 | {127, 255, 0}, 85 | {191, 0, 0}, 86 | {191, 36, 0}, 87 | {191, 72, 0}, 88 | {191, 109, 0}, 89 | {191, 145, 0}, 90 | {191, 182, 0}, 91 | {191, 218, 0}, 92 | {191, 255, 0}, 93 | {255, 0, 0}, 94 | {255, 36, 0}, 95 | {255, 72, 0}, 96 | {255, 109, 0}, 97 | {255, 145, 0}, 98 | {255, 182, 0}, 99 | {255, 218, 0}, 100 | {255, 255, 0}, 101 | {0, 0, 63}, 102 | {0, 36, 63}, 103 | {0, 72, 63}, 104 | {0, 109, 63}, 105 | {0, 145, 63}, 106 | {0, 182, 63}, 107 | {0, 218, 63}, 108 | {0, 255, 63}, 109 | {63, 0, 63}, 110 | {63, 36, 63}, 111 | {63, 72, 63}, 112 | {63, 109, 63}, 113 | {63, 145, 63}, 114 | {63, 182, 63}, 115 | {63, 218, 63}, 116 | {63, 255, 63}, 117 | {127, 0, 63}, 118 | {127, 36, 63}, 119 | {127, 72, 63}, 120 | {127, 109, 63}, 121 | {127, 145, 63}, 122 | {127, 182, 63}, 123 | {127, 218, 63}, 124 | {127, 255, 63}, 125 | {191, 0, 63}, 126 | {191, 36, 63}, 127 | {191, 72, 63}, 128 | {191, 109, 63}, 129 | {191, 145, 63}, 130 | {191, 182, 63}, 131 | {191, 218, 63}, 132 | {191, 255, 63}, 133 | {255, 0, 63}, 134 | {255, 36, 63}, 135 | {255, 72, 63}, 136 | {255, 109, 63}, 137 | {255, 145, 63}, 138 | {255, 182, 63}, 139 | {255, 218, 63}, 140 | {255, 255, 63}, 141 | {0, 0, 127}, 142 | {0, 36, 127}, 143 | {0, 72, 127}, 144 | {0, 109, 127}, 145 | {0, 145, 127}, 146 | {0, 182, 127}, 147 | {0, 218, 127}, 148 | {0, 255, 127}, 149 | {63, 0, 127}, 150 | {63, 36, 127}, 151 | {63, 72, 127}, 152 | {63, 109, 127}, 153 | {63, 145, 127}, 154 | {63, 182, 127}, 155 | {63, 218, 127}, 156 | {63, 255, 127}, 157 | {127, 0, 127}, 158 | {127, 36, 127}, 159 | {127, 72, 127}, 160 | {127, 109, 127}, 161 | {127, 145, 127}, 162 | {127, 182, 127}, 163 | {127, 218, 127}, 164 | {127, 255, 127}, 165 | {191, 0, 127}, 166 | {191, 36, 127}, 167 | {191, 72, 127}, 168 | {191, 109, 127}, 169 | {191, 145, 127}, 170 | {191, 182, 127}, 171 | {191, 218, 127}, 172 | {191, 255, 127}, 173 | {255, 0, 127}, 174 | {255, 36, 127}, 175 | {255, 72, 127}, 176 | {255, 109, 127}, 177 | {255, 145, 127}, 178 | {255, 182, 127}, 179 | {255, 218, 127}, 180 | {255, 255, 127}, 181 | {0, 0, 191}, 182 | {0, 36, 191}, 183 | {0, 72, 191}, 184 | {0, 109, 191}, 185 | {0, 145, 191}, 186 | {0, 182, 191}, 187 | {0, 218, 191}, 188 | {0, 255, 191}, 189 | {63, 0, 191}, 190 | {63, 36, 191}, 191 | {63, 72, 191}, 192 | {63, 109, 191}, 193 | {63, 145, 191}, 194 | {63, 182, 191}, 195 | {63, 218, 191}, 196 | {63, 255, 191}, 197 | {127, 0, 191}, 198 | {127, 36, 191}, 199 | {127, 72, 191}, 200 | {127, 109, 191}, 201 | {127, 145, 191}, 202 | {127, 182, 191}, 203 | {127, 218, 191}, 204 | {127, 255, 191}, 205 | {191, 0, 191}, 206 | {191, 36, 191}, 207 | {191, 72, 191}, 208 | {191, 109, 191}, 209 | {191, 145, 191}, 210 | {191, 182, 191}, 211 | {191, 218, 191}, 212 | {191, 255, 191}, 213 | {255, 0, 191}, 214 | {255, 36, 191}, 215 | {255, 72, 191}, 216 | {255, 109, 191}, 217 | {255, 145, 191}, 218 | {255, 182, 191}, 219 | {255, 218, 191}, 220 | {255, 255, 191}, 221 | {0, 0, 255}, 222 | {0, 36, 255}, 223 | {0, 72, 255}, 224 | {0, 109, 255}, 225 | {0, 145, 255}, 226 | {0, 182, 255}, 227 | {0, 218, 255}, 228 | {0, 255, 255}, 229 | {63, 0, 255}, 230 | {63, 36, 255}, 231 | {63, 72, 255}, 232 | {63, 109, 255}, 233 | {63, 145, 255}, 234 | {63, 182, 255}, 235 | {63, 218, 255}, 236 | {63, 255, 255}, 237 | {127, 0, 255}, 238 | {127, 36, 255}, 239 | {127, 72, 255}, 240 | {127, 109, 255}, 241 | {127, 145, 255}, 242 | {127, 182, 255}, 243 | {127, 218, 255}, 244 | {127, 255, 255}, 245 | {191, 0, 255}, 246 | {191, 36, 255}, 247 | {191, 72, 255}, 248 | {191, 109, 255}, 249 | {191, 145, 255}, 250 | {191, 182, 255}, 251 | {191, 218, 255}, 252 | {191, 255, 255}, 253 | {255, 0, 255}, 254 | {255, 36, 255}, 255 | {255, 72, 255}, 256 | {255, 109, 255}, 257 | {255, 145, 255}, 258 | {255, 182, 255}, 259 | {255, 218, 255}, 260 | {255, 255, 255} 261 | }; 262 | 263 | namespace Graph_lib { 264 | QColor mapPaletteColor(int rawColor) 265 | { 266 | return paletteColorMap[rawColor % 256]; 267 | } 268 | 269 | } 270 | -------------------------------------------------------------------------------- /GUI.cpp: -------------------------------------------------------------------------------- 1 | #include "PPP/GUI.h" 2 | #include "PPP/GUI_private.h" 3 | #include "PPP/Window.h" 4 | #include "PPP/std_lib_facilities.h" 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace Graph_lib; 16 | 17 | 18 | Widget::Widget(Point xy, int w, int h, const string& s, Callback cb) 19 | : loc(xy), width(w), height(h), label(s), do_it(cb), impl(std::make_unique()) 20 | {} 21 | 22 | Widget::~Widget() 23 | { 24 | 25 | } 26 | 27 | void Widget::move(int dx,int dy) 28 | { 29 | QRect geom = impl->widget->geometry(); 30 | geom.moveLeft(geom.left() + dx); 31 | geom.moveTop(geom.top() + dy); 32 | impl->widget->setGeometry(geom); 33 | loc.x += dx; 34 | loc.y += dy; 35 | } 36 | 37 | void Widget::hide() {impl->widget->setVisible(false);} 38 | void Widget::show() {impl->widget->setVisible(true);} 39 | 40 | Button::Button(Point xy, int w, int h, const string& label, Callback cb) 41 | : Widget(xy,w,h,label,cb) 42 | { 43 | WidgetPrivate& w_impl = get_impl(); 44 | QPushButton* button = new QPushButton(); 45 | w_impl.widget.reset(button); 46 | button->setText(QString::fromStdString(label)); 47 | QObject::connect(button, &QPushButton::clicked, [this]{ do_it(); }); 48 | } 49 | 50 | class InputDialog : public QInputDialog 51 | { 52 | public: 53 | InputDialog(QWidget* parent = nullptr) : QInputDialog(parent) {} 54 | void done(int result) override 55 | { 56 | if (result == QDialog::Rejected) { 57 | if (close_on_accept) { 58 | QInputDialog::done(result); 59 | } else { 60 | QInputDialog::rejected(); 61 | } 62 | } else if (result == QDialog::Accepted) { 63 | if (close_on_accept) { 64 | QInputDialog::done(result); 65 | } else { 66 | QInputDialog::accepted(); 67 | } 68 | } 69 | } 70 | void keyPressEvent(QKeyEvent *e) override { 71 | if ((options() | QInputDialog::NoButtons)) { 72 | if (e->key() == Qt::Key_Return) { 73 | done(QDialog::Accepted); 74 | } else if (e->key() == Qt::Key_Escape) { 75 | done(QDialog::Rejected); 76 | } 77 | } else { 78 | QInputDialog::keyPressEvent(e); 79 | } 80 | } 81 | void set_close_on_accept(bool val) {close_on_accept = val;} 82 | private: 83 | bool close_on_accept = false; 84 | }; 85 | 86 | In_box::In_box(Point xy, int w, int h, const string& s, Callback cb) 87 | :Widget(xy,w,h,s,0) 88 | { 89 | WidgetPrivate& w_impl = get_impl(); 90 | InputDialog* dialog = new InputDialog(); 91 | dialog->setVisible(false); 92 | w_impl.widget.reset(dialog); 93 | do_it = cb; 94 | } 95 | 96 | void setup_input(InputDialog* dialog, const std::string& label, 97 | bool close_on_accept, 98 | QInputDialog::InputMode inputMode, 99 | Callback& do_it, 100 | In_box::ResultData& result) 101 | { 102 | dialog->setWindowTitle(QString::fromStdString(label)); 103 | dialog->setLabelText(QString::fromStdString(label)); 104 | dialog->set_close_on_accept(close_on_accept); 105 | dialog->setInputMode(inputMode); 106 | dialog->setModal(false); 107 | QObject::connect(dialog, &QInputDialog::accepted, 108 | [dialog, &do_it, &result] { 109 | result.state = Graph_lib::In_box::accepted; 110 | if (dialog->inputMode() == QInputDialog::IntInput) { 111 | result.last_int = dialog->intValue(); 112 | dialog->setIntValue(0); 113 | } else if ((dialog->inputMode() == QInputDialog::TextInput)) { 114 | result.last_string = dialog->textValue().toStdString(); 115 | dialog->setTextValue(""); 116 | } 117 | if (do_it) { 118 | do_it(); 119 | } 120 | }); 121 | QObject::connect(dialog, &QInputDialog::rejected, 122 | [dialog, &do_it, &result] { 123 | result.state = Graph_lib::In_box::rejected; 124 | if (dialog->inputMode() == QInputDialog::TextInput) { 125 | dialog->setTextValue(""); 126 | } else if (dialog->inputMode() == QInputDialog::IntInput) { 127 | dialog->setIntValue(0); 128 | } 129 | if (do_it) { 130 | do_it(); 131 | } 132 | }); 133 | 134 | } 135 | 136 | void wait_for_input(InputDialog* dialog, In_box::State& state) 137 | { 138 | QEventLoop nested_loop; 139 | QTimer timer(&nested_loop); 140 | timer.setSingleShot(true); 141 | QObject::connect(&timer, &QTimer::timeout, 142 | [&] {nested_loop.quit();}); 143 | auto conn1 = QObject::connect(dialog, &QInputDialog::accepted, 144 | [&] { 145 | state = In_box::accepted; 146 | timer.start(0); 147 | }); 148 | auto conn2 = QObject::connect(dialog, &QInputDialog::rejected, 149 | [&] { 150 | state = In_box::rejected; 151 | timer.start(0); 152 | }); 153 | nested_loop.exec(); 154 | QObject::disconnect(conn1); 155 | QObject::disconnect(conn2); 156 | } 157 | 158 | void exec_input(InputDialog* dialog, In_box::State& state) 159 | { 160 | auto conn1 = QObject::connect(dialog, &QInputDialog::accepted, 161 | [&] { 162 | state = In_box::accepted; 163 | }); 164 | auto conn2 = QObject::connect(dialog, &QInputDialog::rejected, 165 | [&] { 166 | state = In_box::rejected; 167 | }); 168 | dialog->exec(); 169 | QObject::disconnect(conn1); 170 | QObject::disconnect(conn2); 171 | } 172 | 173 | int In_box::get_int() 174 | { 175 | InputDialog* dialog = static_cast(get_impl().widget.get()); 176 | if (waiting) { 177 | dialog->reject(); 178 | result.state = rejected; 179 | return 0; 180 | } 181 | result.state = idle; 182 | setup_input(dialog, label, true, QInputDialog::IntInput, 183 | do_it, result); 184 | waiting = true; 185 | exec_input(dialog, result.state); 186 | waiting = false; 187 | return dialog->intValue(); 188 | } 189 | 190 | int In_box::get_int_keep_open() 191 | { 192 | InputDialog* dialog = static_cast(get_impl().widget.get()); 193 | if (waiting) { 194 | dialog->reject(); 195 | result.state = rejected; 196 | return 0; 197 | } 198 | result.state = idle; 199 | setup_input(dialog, label, false, QInputDialog::IntInput, 200 | do_it, result); 201 | dialog->show(); 202 | waiting = true; 203 | wait_for_input(dialog, result.state); 204 | waiting = false; 205 | return dialog->intValue(); 206 | } 207 | 208 | string In_box::get_string() 209 | { 210 | InputDialog* dialog = static_cast(get_impl().widget.get()); 211 | if (waiting) { 212 | dialog->reject(); 213 | result.state = rejected; 214 | return ""; 215 | } 216 | result.state = idle; 217 | setup_input(dialog, label, true, QInputDialog::TextInput, 218 | do_it, result); 219 | waiting = true; 220 | exec_input(dialog, result.state); 221 | waiting = false; 222 | return dialog->textValue().toStdString(); 223 | } 224 | 225 | string In_box::get_string_keep_open() 226 | { 227 | InputDialog* dialog = static_cast(get_impl().widget.get()); 228 | if (waiting) { 229 | dialog->reject(); 230 | result.state = rejected; 231 | return ""; 232 | } 233 | result.state = idle; 234 | setup_input(dialog, label, false, QInputDialog::TextInput, 235 | do_it, result); 236 | dialog->show(); 237 | waiting = true; 238 | wait_for_input(dialog, result.state); 239 | waiting = false; 240 | return dialog->textValue().toStdString(); 241 | } 242 | 243 | void In_box::attach(Window& win) 244 | { 245 | InputDialog* dialog = static_cast(get_impl().widget.get()); 246 | dialog->hide(); 247 | QObject::connect(&win.get_impl(), &WindowPrivate::windowClosed, 248 | [=] {dialog->reject();}); 249 | } 250 | 251 | void In_box::dismiss() 252 | { 253 | InputDialog* dialog = static_cast(get_impl().widget.get()); 254 | dialog->reject(); 255 | result.state = rejected; 256 | } 257 | 258 | void In_box::hide() 259 | { 260 | InputDialog* dialog = static_cast(get_impl().widget.get()); 261 | dialog->hide(); 262 | } 263 | 264 | void In_box::show() 265 | { 266 | InputDialog* dialog = static_cast(get_impl().widget.get()); 267 | setup_input(dialog, label, false, QInputDialog::TextInput, 268 | do_it, result); 269 | dialog->show(); 270 | } 271 | 272 | void In_box::hide_buttons() 273 | { 274 | InputDialog* dialog = static_cast(get_impl().widget.get()); 275 | dialog->setOption(QInputDialog::NoButtons, true); 276 | } 277 | 278 | void In_box::show_buttons() 279 | { 280 | InputDialog* dialog = static_cast(get_impl().widget.get()); 281 | dialog->setOption(QInputDialog::NoButtons, false); 282 | } 283 | 284 | In_box::State In_box::last_result() 285 | { 286 | return result.state; 287 | } 288 | 289 | void In_box::clear_last_result() 290 | { 291 | result.state = idle; 292 | result.last_string = ""; 293 | result.last_int = 0; 294 | } 295 | 296 | std::string In_box::last_string_value() 297 | { 298 | return result.last_string; 299 | } 300 | 301 | int In_box::last_int_value() 302 | { 303 | return result.last_int; 304 | } 305 | 306 | Menu::Menu(Point xy, int w, int h, Kind kk, const string& label) 307 | : Widget(xy,w,h,label,0), k(kk), offset(0) 308 | { 309 | WidgetPrivate& w_impl = get_impl(); 310 | QWidget* widget = new QWidget(); 311 | w_impl.widget.reset(widget); 312 | if (k == Menu::horizontal) { 313 | QHBoxLayout* layout = new QHBoxLayout(); 314 | layout->setContentsMargins(0,0,0,0); 315 | layout->setSpacing(0); 316 | widget->setLayout(layout); 317 | } else { 318 | QVBoxLayout* layout = new QVBoxLayout(); 319 | layout->setContentsMargins(0,0,0,0); 320 | layout->setSpacing(0); 321 | widget->setLayout(layout); 322 | } 323 | 324 | } 325 | 326 | void Menu::layoutButtons(Button& b) 327 | { 328 | b.width = width; 329 | b.height = height; 330 | 331 | switch(k) { 332 | case horizontal: 333 | b.loc = Point{loc.x+offset,loc.y}; 334 | offset+= b.width; 335 | break; 336 | case vertical: 337 | b.loc = Point{loc.x,loc.y+offset}; 338 | offset+= b.height; 339 | break; 340 | } 341 | b.get_impl().widget->setMaximumHeight(height); 342 | b.get_impl().widget->setMaximumWidth(width); 343 | get_impl().widget->layout()->addWidget(b.get_impl().widget.get()); 344 | } 345 | 346 | void Menu::layoutMenu() 347 | { 348 | if (k == vertical) { 349 | get_impl().widget->setMinimumHeight(height * selection.size()); 350 | } else { 351 | get_impl().widget->setMinimumWidth(width * selection.size()); 352 | } 353 | } 354 | 355 | int Menu::attach(Button& b) 356 | { 357 | layoutButtons(b); 358 | selection.push_back(b); 359 | layoutMenu(); 360 | return int(selection.size()-1); 361 | } 362 | 363 | int Menu::attach(unique_ptr