diff --git a/planet/System.ocg/LanguageDE.txt b/planet/System.ocg/LanguageDE.txt index c30d4acaf..5c06df87a 100644 --- a/planet/System.ocg/LanguageDE.txt +++ b/planet/System.ocg/LanguageDE.txt @@ -85,6 +85,8 @@ IDS_CNS_SCENARIOSAVED=Szenario gespeichert. IDS_CNS_SCENARIOSETTINGS=Szenarieneinstellungen IDS_CNS_SCRIPT=Script IDS_CNS_SCRIPTCREATEDOBJECTS=Das Script dieses Szenarios hat beim Start der Runde Objekte erschaffen. +IDS_CNS_SELECTNEARBYOBJECTS=Objekt auswählen +IDS_CNS_SELECTCONTENTS=%s Inhalt... IDS_CNS_TITLE=Titel IDS_CNS_TRUE=Ja IDS_CNS_TYPE=Typ: %s (%s) diff --git a/planet/System.ocg/LanguageUS.txt b/planet/System.ocg/LanguageUS.txt index 6f8443f29..5dab66d6a 100644 --- a/planet/System.ocg/LanguageUS.txt +++ b/planet/System.ocg/LanguageUS.txt @@ -85,6 +85,8 @@ IDS_CNS_SCENARIOSAVED=Scenario saved. IDS_CNS_SCENARIOSETTINGS=Scenario settings IDS_CNS_SCRIPT=Script IDS_CNS_SCRIPTCREATEDOBJECTS=This scenario's script has created objects on initialization. +IDS_CNS_SELECTNEARBYOBJECTS=Select object +IDS_CNS_SELECTCONTENTS=%s contents... IDS_CNS_TITLE=Title IDS_CNS_TRUE=Yes IDS_CNS_TYPE=Type: %s (%s) diff --git a/src/editor/C4ConsoleQtMainWindow.ui b/src/editor/C4ConsoleQtMainWindow.ui index b343c29b8..c0254542e 100644 --- a/src/editor/C4ConsoleQtMainWindow.ui +++ b/src/editor/C4ConsoleQtMainWindow.ui @@ -975,6 +975,33 @@ MAP_STATICFLAT_TIP + + + IDS_MNU_DELETE + + + IDS_MNU_DELETE + + + Del + + + + + IDS_MNU_DUPLICATE + + + IDS_MNU_DUPLICATE + + + + + IDS_MNU_CONTENTS + + + IDS_MNU_CONTENTS + + @@ -1540,6 +1567,54 @@ + + actionDeleteObject + triggered(bool) + MainWindow + SelectionDelete() + + + -1 + -1 + + + 477 + 312 + + + + + actionDuplicateObject + triggered() + MainWindow + SelectionDuplicate() + + + -1 + -1 + + + 477 + 312 + + + + + actionEjectContents + triggered() + MainWindow + SelectionEjectContents() + + + -1 + -1 + + + 477 + 312 + + + PlayPressed(bool) @@ -1576,5 +1651,8 @@ AddArrayElement() RemoveArrayElement() StaticFlatLandscapePressed(bool) + SelectionDelete() + SelectionDuplicate() + SelectionEjectContents() diff --git a/src/editor/C4ConsoleQtState.cpp b/src/editor/C4ConsoleQtState.cpp index b4829a840..be4bac66c 100644 --- a/src/editor/C4ConsoleQtState.cpp +++ b/src/editor/C4ConsoleQtState.cpp @@ -420,6 +420,21 @@ void C4ConsoleQtMainWindow::WelcomeLinkActivated(const QString &link) } } +void C4ConsoleQtMainWindow::SelectionDelete() +{ + ::Console.EditCursor.Delete(); +} + +void C4ConsoleQtMainWindow::SelectionDuplicate() +{ + ::Console.EditCursor.Duplicate(); +} + +void C4ConsoleQtMainWindow::SelectionEjectContents() +{ + ::Console.EditCursor.GrabContents(); +} + /* Common C4ConsoleGUI interface */ diff --git a/src/editor/C4ConsoleQtState.h b/src/editor/C4ConsoleQtState.h index e1fca9b10..05f6f6faa 100644 --- a/src/editor/C4ConsoleQtState.h +++ b/src/editor/C4ConsoleQtState.h @@ -141,6 +141,10 @@ public slots: void BackgroundMaterialChanged(const QString &new_selection); // Links on welcome page void WelcomeLinkActivated(const QString &link); + // Object context menu + void SelectionDelete(); + void SelectionDuplicate(); + void SelectionEjectContents(); }; diff --git a/src/editor/C4ConsoleQtViewport.cpp b/src/editor/C4ConsoleQtViewport.cpp index 90d1553dd..4f805ac9a 100644 --- a/src/editor/C4ConsoleQtViewport.cpp +++ b/src/editor/C4ConsoleQtViewport.cpp @@ -23,10 +23,12 @@ #include "editor/C4Console.h" #include "editor/C4ConsoleQtShapes.h" #include "game/C4Viewport.h" +#include "object/C4Object.h" #include "editor/C4ViewportWindow.h" #include "editor/C4Console.h" #include "gui/C4MouseControl.h" #include "landscape/C4Landscape.h" +#include "object/C4GameObjects.h" /* Console viewports */ @@ -36,9 +38,12 @@ C4ConsoleQtViewportView::C4ConsoleQtViewportView(class C4ConsoleQtViewportScroll setAttribute(Qt::WA_ShowWithoutActivating, true); setFocusPolicy(Qt::WheelFocus); setMouseTracking(true); + setContextMenuPolicy(Qt::CustomContextMenu); // Register for viewport C4ViewportWindow *window = dock->cvp; window->glwidget = this; + // Enable context menu + connect(this, &QWidget::customContextMenuRequested, this, &C4ConsoleQtViewportView::ShowContextMenu); } bool C4ConsoleQtViewportView::IsPlayViewport() const @@ -61,6 +66,82 @@ qreal C4ConsoleQtViewportView::GetDevicePixelRatio() return screen->devicePixelRatio(); } +void C4ConsoleQtViewportView::AddSelectObjectContextEntry(C4Object *obj, QMenu *menu) +{ + // Add select object item for object and for all contents + if (!obj || !obj->Status) return; + int32_t object_number = obj->Number; + QAction *select_object_action = new QAction(QString("%1 #%2 (%3/%4)").arg(obj->GetName()).arg(object_number).arg(obj->GetX()).arg(obj->GetY()), menu); + connect(select_object_action, &QAction::triggered, menu, [object_number]() { + bool add = !!(QGuiApplication::keyboardModifiers() & Qt::ShiftModifier); + C4Object *obj = ::Objects.SafeObjectPointer(object_number); + if (obj) ::Console.EditCursor.DoContextObjsel(obj, !add); + }); + menu->addAction(select_object_action); + if (obj->Contents.ObjectCount()) + { + QMenu *submenu = menu->addMenu(FormatString(LoadResStr("IDS_CNS_SELECTCONTENTS"), obj->GetName()).getData()); + for (C4Object *cobj : obj->Contents) + { + AddSelectObjectContextEntry(cobj, submenu); + } + } +} + +void C4ConsoleQtViewportView::ShowContextMenu(const QPoint &pos) +{ + // Coordinates are in viewport (not adjusted by parent scroll window) + if (!IsPlayViewport()) + { + // Show context menu in editor viewport + QMenu *menu = new QMenu(this); + // Show current object(s) as unselectable item + auto &ui = dock->main_window->GetConsoleState()->ui; + menu->addSection(ui.selectionInfoLabel->text()); + // Object actions. Always shown but grayed out if no object is selected. + bool has_object = false; + int32_t contents_count = 0; + for (const C4Value &sel : ::Console.EditCursor.GetSelection()) + { + C4Object *obj = sel.getObj(); + if (obj) + { + has_object = true; + contents_count += obj->Contents.ObjectCount(); + } + } + for (QAction *act : { ui.actionDeleteObject, ui.actionDuplicateObject, ui.actionEjectContents }) + { + act->setEnabled(has_object); + menu->addAction(act); + } + if (!contents_count) + { + ui.actionEjectContents->setEnabled(false); + } + ui.actionEjectContents->setText(QString("%1 (%2)").arg(LoadResStr("IDS_MNU_CONTENTS")).arg((int)contents_count)); + // Object selection section for overlapping objects + auto pr = GetDevicePixelRatio(); + int32_t x = cvp->WindowToGameX(pr * pos.x()), + y = cvp->WindowToGameY(pr * pos.y()); + auto pFOl = new C4FindObjectAtPoint(x, y); // freed by ~C4FindObjectAnd + auto pFOc = new C4FindObjectContainer(nullptr); // freed by ~C4FindObjectAnd + C4FindObject *pFO_conds[] = { pFOl , pFOc }; + C4FindObjectAnd pFO(2, pFO_conds, false); + std::unique_ptr atcursor(pFO.FindMany(::Objects, ::Objects.Sectors)); // needs freeing (single object ptr) + int itemcount = atcursor->GetSize(); + if (itemcount) + { + menu->addSection(LoadResStr("IDS_CNS_SELECTNEARBYOBJECTS")); + for (int32_t i = 0; i < itemcount; ++i) + { + AddSelectObjectContextEntry(atcursor->GetItem(i).getObj(), menu); + } + } + menu->popup(mapToGlobal(pos)); + } +} + // Get Shift state as Win32 wParam uint32_t GetShiftWParam() { diff --git a/src/editor/C4ConsoleQtViewport.h b/src/editor/C4ConsoleQtViewport.h index 5c3209cca..1ff3a2c29 100644 --- a/src/editor/C4ConsoleQtViewport.h +++ b/src/editor/C4ConsoleQtViewport.h @@ -34,6 +34,8 @@ class C4ConsoleQtViewportView : public QOpenGLWidget private: bool IsPlayViewport() const; qreal GetDevicePixelRatio(); + void ShowContextMenu(const QPoint &pos); + void AddSelectObjectContextEntry(C4Object *obj, QMenu *menu); protected: void focusInEvent(QFocusEvent * event) override; diff --git a/src/editor/C4EditCursor.cpp b/src/editor/C4EditCursor.cpp index 91e99a6ee..722117804 100644 --- a/src/editor/C4EditCursor.cpp +++ b/src/editor/C4EditCursor.cpp @@ -615,11 +615,12 @@ bool SetMenuItemText(HMENU hMenu, WORD id, const char *szText) bool C4EditCursor::RightButtonUp(DWORD dwKeyState) { Target=NULL; - +#ifndef WITH_QT_EDITOR DoContextMenu(dwKeyState); - +#endif // Update UpdateStatusBar(); + return true; } diff --git a/src/editor/C4EditCursor.h b/src/editor/C4EditCursor.h index a7af39c23..369ae0101 100644 --- a/src/editor/C4EditCursor.h +++ b/src/editor/C4EditCursor.h @@ -130,8 +130,8 @@ protected: void ToolFailure(); void PutContents(); void UpdateDropTarget(DWORD dwKeyState); - void AppendMenuItem(int num, const StdStrBuf & label); bool DoContextMenu(DWORD dwKeyState); + void AppendMenuItem(int num, const StdStrBuf & label); void ApplyToolFill(); void ApplyToolRect(); void ApplyToolLine(); @@ -142,10 +142,13 @@ protected: void FrameSelection(); void MoveSelection(C4Real iXOff, C4Real iYOff); void EMMoveObject(enum C4ControlEMObjectAction eAction, C4Real tx, C4Real ty, C4Object *pTargetObj, const C4EditCursorSelection *pObjs = NULL, const char *szScript = NULL); - void DoContextObjsel(C4Object *, bool clear); void DoContextObjCommand(C4Object *, const char *cmd); void ObjselectDelItems(); +public: + void DoContextObjsel(C4Object *, bool clear); + +protected: #ifdef USE_GTK static void OnDelete(GtkWidget* widget, gpointer data); static void OnDuplicate(GtkWidget* widget, gpointer data);