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);