#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include #pragma GCC diagnostic pop #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace Wt; using namespace Wt::cpp17; #define SET_BS5THEME 1 // Always apply theme before creating widgets! class CThemedApplication : public WApplication { public: CThemedApplication(const WEnvironment& rcEnv) : WApplication{rcEnv} { #if SET_BS5THEME setTheme(make_shared()); #endif } }; class CFixedTableModel : public WAbstractTableModel { public: CFixedTableModel(const int rowCount, const int colCount) : _rowCount{rowCount} , _colCount{colCount} { } any headerData(const int section, const Orientation orientation, const ItemDataRole role) const { if (orientation != Orientation::Horizontal) throw invalid_argument("orientation"); switch (role.value()) { default: return {}; case ItemDataRole::Display: return format("C{}", section); } } any data(const WModelIndex& index, const ItemDataRole role) const override { if (!index.isValid()) return {}; switch (role.value()) { default: return {}; case ItemDataRole::Display: return format("{}, {}", index.row(), index.column()); } } int columnCount(const WModelIndex& index) const override { return index.isValid() ? 0 : _colCount; } int rowCount (const WModelIndex& index) const override { return index.isValid() ? 0 : _rowCount; } const int _rowCount; const int _colCount; }; template constexpr inline std::unique_ptr create(std::function&& fInitialize, TArgs&&... args) { std::unique_ptr Ptr{std::make_unique(std::forward(args)...)}; fInitialize(*Ptr); return Ptr; } class CApplication final : public CThemedApplication { public: CApplication(const WEnvironment& rcEnv); static void setAccessKey(WInteractWidget& widget, const char mnemonic) { widget.setAttributeValue("accesskey", string(1, tolower(mnemonic))); } static void suppressBrowserContextMenu(WWidget& rWidget) { rWidget.setAttributeValue("oncontextmenu", "event.cancelBubble = true; event.returnValue = false; return false;"); } private: WServer& _Server; //!< The associated WServer instance, needed for async operations. WContainerWidget& _cntRoot{*root()}; WBoxLayout& _lytRoot{*_cntRoot.setLayout(make_unique())}; WPushButton& _btnPopup{*_lytRoot.addWidget(create([this](auto& btnPopup) { btnPopup.clicked().connect([this] { log("trace") << "_btnPopup.clicked"; _dlgPopup.show(); }); btnPopup.setTextFormat(TextFormat::UnsafeXHTML); setAccessKey(btnPopup, 'P'); }, "Popup"))}; WTabWidget& _tbwMain{*_lytRoot.addWidget(make_unique(), /*stretch*/ 100)}; WMenuItem& _tabA{*_tbwMain.addTab(make_unique(), "A", ContentLoading::Eager)}; WTableView& _tvA{dynamic_cast(*_tbwMain.widget(_tbwMain.count() - 1))}; WMenuItem& _tabB{*_tbwMain.addTab(make_unique(), "B", ContentLoading::Eager)}; WTableView& _tvB{dynamic_cast(*_tbwMain.widget(_tbwMain.count() - 1))}; shared_ptr _mdlAPtr{make_shared(100, 50)}; WDialog _dlgPopup{}; }; CApplication::CApplication(const WEnvironment& rcEnv) : CThemedApplication{rcEnv} , _Server{*environment().server()} { setTitle("bug repro " WT_VERSION_STR); suppressBrowserContextMenu(_cntRoot); suppressBrowserContextMenu(_dlgPopup); _dlgPopup.setClosable(true); _dlgPopup.setWindowTitle("Popup"); _dlgPopup.keyWentDown().connect([this](const WKeyEvent& e) { switch (e.key()) { default: return; case Key::Enter: case Key::Escape: _dlgPopup.reject(); } }); WHBoxLayout& lytPopup{*_dlgPopup.contents()->setLayout(make_unique())}; lytPopup.addWidget(create([this] (WTableView& tv) { tv.setModel(_mdlAPtr); tv.setMaximumSize(WLength{2000, LengthUnit::Pixel}, WLength{900, LengthUnit::Pixel}); }), 0, AlignmentFlag::Top); const auto fTryAddKeyHandlers = [](WDialog& dlg, TWidget* const cpWidget) { if (cpWidget == nullptr) { return false; } TWidget& rWidget{*cpWidget}; rWidget.keyWentDown().connect([&dlg] (const WKeyEvent& rcKeyEvent) { dlg.keyWentDown().emit(rcKeyEvent); }); rWidget.keyWentUp ().connect([&dlg] (const WKeyEvent& rcKeyEvent) { if (rcKeyEvent.key() == Key::Escape) { dlg.escapePressed().emit(); } else { dlg.keyWentUp ().emit(rcKeyEvent); } }); rWidget.keyPressed ().connect([&dlg, cpWidget](const WKeyEvent& rcKeyEvent) { switch (rcKeyEvent.key()) { default: break; case Key::Escape: dlg.escapePressed().emit(); break; case Key::Enter: { if (dynamic_cast(cpWidget) != nullptr) { // Let the WPushButton widget trigger the action } #if 0 else if (WRadioButton* const cpRadioButton{dynamic_cast(cpWidget)}; cpRadioButton != nullptr) { setChecked(*cpRadioButton); } #endif else { dlg.enterPressed().emit(); } } break; } // switch (rcKeyEvent.key()) }); return true; }; const auto fAddKeyHandlers = [&fTryAddKeyHandlers, this](WWidget* const cpWidget) { fTryAddKeyHandlers(_dlgPopup, dynamic_cast(cpWidget)) || fTryAddKeyHandlers(_dlgPopup, dynamic_cast(cpWidget)); }; lytPopup.iterateWidgets(fAddKeyHandlers); _dlgPopup.show(); // final action after creating the UI enableUpdates(); } int main(int argc, char* argv[]) { return WRun(argc, argv, [](const WEnvironment& rcEnv) { try { return make_unique(rcEnv); } catch (const std::exception& rcException) { cerr << "exception " << typeid(remove_cvref::type).name() << ": " << rcException.what() << endl; #if DEBUG exit(-1); #endif throw; } }); }