Skip to content

Commit

Permalink
#6131: Convert PatchInspector to a dockable control
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Oct 21, 2022
1 parent 79013b6 commit b1254d7
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 126 deletions.
1 change: 1 addition & 0 deletions include/ui/iusercontrol.h
Expand Up @@ -46,6 +46,7 @@ struct UserControl
constexpr static const char* OrthoView = "OrthoView";
constexpr static const char* TextureBrowser = "TextureBrowser";
constexpr static const char* SurfaceInspector = "SurfaceInspector";
constexpr static const char* PatchInspector = "PatchInspector";
constexpr static const char* LayerControlPanel = "LayerControlPanel";
constexpr static const char* TextureTool = "TextureTool";
};
Expand Down
5 changes: 4 additions & 1 deletion radiant/ui/UserInterfaceModule.cpp
Expand Up @@ -75,6 +75,7 @@

#include "console/ConsoleControl.h"
#include "layers/LayerControl.h"
#include "patch/PatchInspectorControl.h"
#include "surfaceinspector/SurfaceInspectorControl.h"
#include "textool/TextureToolControl.h"

Expand Down Expand Up @@ -253,13 +254,15 @@ void UserInterfaceModule::initialiseModule(const IApplicationContext& ctx)
registerControl(std::make_shared<SurfaceInspectorControl>());
registerControl(std::make_shared<LayerControl>());
registerControl(std::make_shared<TextureToolControl>());
registerControl(std::make_shared<PatchInspectorControl>());

GlobalMainFrame().signal_MainFrameConstructed().connect([&]()
{
// Set default locations of some controls
GlobalMainFrame().addControl(UserControl::SurfaceInspector, { IMainFrame::Location::FloatingWindow, false });
GlobalMainFrame().addControl(UserControl::LayerControlPanel, { IMainFrame::Location::FloatingWindow, false });
GlobalMainFrame().addControl(UserControl::TextureTool, { IMainFrame::Location::FloatingWindow, false });
GlobalMainFrame().addControl(UserControl::PatchInspector, { IMainFrame::Location::FloatingWindow, false });
});
}

Expand Down Expand Up @@ -423,8 +426,8 @@ void UserInterfaceModule::registerUICommands()
GlobalCommandSystem().addCommand("ToggleLightInspector", LightInspector::toggleInspector);
GlobalCommandSystem().addStatement("SurfaceInspector", fmt::format("ToggleControl {0}", UserControl::SurfaceInspector), false);
GlobalCommandSystem().addStatement("ToggleLayerControlDialog", fmt::format("ToggleControl {0}", UserControl::LayerControlPanel), false);
GlobalCommandSystem().addStatement("PatchInspector", fmt::format("ToggleControl {0}", UserControl::PatchInspector), false);

GlobalCommandSystem().addCommand("PatchInspector", PatchInspector::toggle);
GlobalCommandSystem().addCommand("MergeControlDialog", MergeControlDialog::ShowDialog);
GlobalCommandSystem().addCommand("OverlayDialog", OverlayDialog::toggle);
GlobalCommandSystem().addCommand("TransformDialog", TransformDialog::toggle);
Expand Down
118 changes: 28 additions & 90 deletions radiant/ui/patch/PatchInspector.cpp
@@ -1,7 +1,6 @@
#include "PatchInspector.h"

#include "i18n.h"
#include "itextstream.h"
#include "ui/imainframe.h"
#include "iundo.h"

Expand All @@ -11,10 +10,10 @@
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/spinctrl.h>
#include "wxutil/Bitmap.h"

#include "registry/Widgets.h"
#include "selectionlib.h"
#include "wxutil/Bitmap.h"
#include "wxutil/ControlButton.h"
#include "util/ScopedBoolLock.h"

Expand All @@ -25,20 +24,18 @@ namespace ui

namespace
{
const char* const WINDOW_TITLE = N_("Patch Inspector");
const char* const LABEL_STEP = N_("Step:");
constexpr const char* const LABEL_STEP = N_("Step:");

const std::string RKEY_ROOT = "user/ui/patch/patchInspector/";
const std::string RKEY_WINDOW_STATE = RKEY_ROOT + "window";
const std::string RKEY_X_STEP = RKEY_ROOT + "xCoordStep";
const std::string RKEY_Y_STEP = RKEY_ROOT + "yCoordStep";
const std::string RKEY_Z_STEP = RKEY_ROOT + "zCoordStep";
const std::string RKEY_S_STEP = RKEY_ROOT + "sCoordStep";
const std::string RKEY_T_STEP = RKEY_ROOT + "tCoordStep";
}

PatchInspector::PatchInspector() :
TransientWindow(_(WINDOW_TITLE), GlobalMainFrame().getWxTopLevelWindow(), true),
PatchInspector::PatchInspector(wxWindow* parent) :
wxPanel(parent),
_rowCombo(nullptr),
_colCombo(nullptr),
_selectionInfo(GlobalSelectionSystem().getSelectionInfo()),
Expand All @@ -47,50 +44,22 @@ PatchInspector::PatchInspector() :
_updateActive(false),
_updateNeeded(false)
{
Bind(wxEVT_IDLE, &PatchInspector::onIdle, this);

// Create all the widgets and pack them into the window
populateWindow();

InitialiseWindowPosition(410, 480, RKEY_WINDOW_STATE);
}
_undoHandler.disconnect();
_redoHandler.disconnect();

std::shared_ptr<PatchInspector>& PatchInspector::InstancePtr()
{
static std::shared_ptr<PatchInspector> _instancePtr;
return _instancePtr;
}
// Register self to the SelSystem to get notified upon selection changes.
GlobalSelectionSystem().addObserver(this);

void PatchInspector::onMainFrameShuttingDown()
{
rMessage() << "PatchInspector shutting down." << std::endl;
_undoHandler = GlobalMapModule().signal_postUndo().connect(
sigc::mem_fun(this, &PatchInspector::queueUpdate));
_redoHandler = GlobalMapModule().signal_postRedo().connect(
sigc::mem_fun(this, &PatchInspector::queueUpdate));

if (IsShownOnScreen())
{
Hide();
}

// Destroy the window
SendDestroyEvent();
InstancePtr().reset();
}

PatchInspector& PatchInspector::Instance()
{
auto& instancePtr = InstancePtr();

if (!instancePtr)
{
// Not yet instantiated, do it now
instancePtr.reset(new PatchInspector);

// Pre-destruction cleanup
GlobalMainFrame().signal_MainFrameShuttingDown().connect(
sigc::mem_fun(*instancePtr, &PatchInspector::onMainFrameShuttingDown)
);
}

return *instancePtr;
// Check for selection changes
rescanSelection();
}

void PatchInspector::populateWindow()
Expand All @@ -106,8 +75,8 @@ void PatchInspector::populateWindow()
_colCombo = findNamedObject<wxChoice>(this, "PatchInspectorControlColumn");

// Create the controls table
wxPanel* coordPanel = findNamedObject<wxPanel>(this, "PatchInspectorCoordPanel");
wxFlexGridSizer* table = new wxFlexGridSizer(5, 5, 6, 16);
auto coordPanel = findNamedObject<wxPanel>(this, "PatchInspectorCoordPanel");
auto table = new wxFlexGridSizer(5, 5, 6, 16);
table->AddGrowableCol(1);

coordPanel->GetSizer()->Add(table, 1, wxEXPAND);
Expand All @@ -126,24 +95,22 @@ void PatchInspector::populateWindow()
registry::bindWidget(_coords["t"].stepEntry, RKEY_T_STEP);

// Connect all the arrow buttons
for (CoordMap::iterator i = _coords.begin(); i != _coords.end(); ++i)
for (const auto& [_, row] : _coords)
{
CoordRow& row = i->second;

// Pass a CoordRow ref to the callback, that's all it will need to update
row.smaller->Bind(wxEVT_BUTTON, std::bind(&PatchInspector::onClickSmaller, this, row));
row.larger->Bind(wxEVT_BUTTON, std::bind(&PatchInspector::onClickLarger, this, row));
}

// Tesselation checkbox
findNamedObject<wxCheckBox>(this, "PatchInspectorFixedSubdivisions")->Connect(
wxEVT_CHECKBOX, wxCommandEventHandler(PatchInspector::onFixedTessChange), NULL, this);
findNamedObject<wxCheckBox>(this, "PatchInspectorFixedSubdivisions")->Bind(
wxEVT_CHECKBOX, &PatchInspector::onFixedTessChange, this);

// Tesselation values
findNamedObject<wxSpinCtrl>(this, "PatchInspectorSubdivisionsX")->Connect(
wxEVT_SPINCTRL, wxSpinEventHandler(PatchInspector::onTessChange), NULL, this);
findNamedObject<wxSpinCtrl>(this, "PatchInspectorSubdivisionsY")->Connect(
wxEVT_SPINCTRL, wxSpinEventHandler(PatchInspector::onTessChange), NULL, this);
findNamedObject<wxSpinCtrl>(this, "PatchInspectorSubdivisionsX")->Bind(
wxEVT_SPINCTRL, &PatchInspector::onTessChange, this);
findNamedObject<wxSpinCtrl>(this, "PatchInspectorSubdivisionsY")->Bind(
wxEVT_SPINCTRL, &PatchInspector::onTessChange, this);
}

PatchInspector::CoordRow PatchInspector::createCoordRow(
Expand Down Expand Up @@ -191,8 +158,8 @@ PatchInspector::CoordRow PatchInspector::createCoordRow(

void PatchInspector::queueUpdate()
{
// Request an idle callback to perform the update when GTK is idle
_updateNeeded = true;
requestIdleCallback();
}

void PatchInspector::update()
Expand Down Expand Up @@ -246,13 +213,10 @@ void PatchInspector::loadControlVertex()
}
}

// Pre-hide callback
void PatchInspector::_preHide()
PatchInspector::~PatchInspector()
{
TransientWindow::_preHide();

// Clear the patch, we don't need to observe it while hidden
setPatch(IPatchNodePtr());
setPatch({});

// A hidden PatchInspector doesn't need to listen for events
_undoHandler.disconnect();
Expand All @@ -261,26 +225,6 @@ void PatchInspector::_preHide()
GlobalSelectionSystem().removeObserver(this);
}

// Pre-show callback
void PatchInspector::_preShow()
{
TransientWindow::_preShow();

_undoHandler.disconnect();
_redoHandler.disconnect();

// Register self to the SelSystem to get notified upon selection changes.
GlobalSelectionSystem().addObserver(this);

_undoHandler = GlobalMapModule().signal_postUndo().connect(
sigc::mem_fun(this, &PatchInspector::queueUpdate));
_redoHandler = GlobalMapModule().signal_postRedo().connect(
sigc::mem_fun(this, &PatchInspector::queueUpdate));

// Check for selection changes before showing the dialog again
rescanSelection();
}

void PatchInspector::selectionChanged(const scene::INodePtr& node, bool isComponent)
{
if (!isComponent)
Expand Down Expand Up @@ -541,12 +485,6 @@ void PatchInspector::onClickSmaller(CoordRow& row)
row.value->SetValue(string::to_string(value - step));
}

// static command target
void PatchInspector::toggle(const cmd::ArgumentList& args)
{
Instance().ToggleVisibility();
}

void PatchInspector::onPatchControlPointsChanged()
{
queueUpdate();
Expand All @@ -562,12 +500,12 @@ void PatchInspector::onPatchDestruction()
rescanSelection();
}

void PatchInspector::onIdle(wxIdleEvent& ev)
void PatchInspector::onIdle()
{
if (_updateNeeded)
{
update();
}
}

} // namespace ui
} // namespace
49 changes: 14 additions & 35 deletions radiant/ui/patch/PatchInspector.h
@@ -1,33 +1,31 @@
#pragma once

#include <map>
#include "icommandsystem.h"
#include "iselection.h"
#include "iradiant.h"
#include "ipatch.h"

#include <sigc++/connection.h>
#include <sigc++/trackable.h>

#include "wxutil/window/TransientWindow.h"
#include <wx/panel.h>
#include "wxutil/event/SingleIdleCallback.h"
#include "wxutil/XmlResourceBasedWidget.h"

namespace wxutil { class ControlButton; }
class wxChoice;
class wxPanel;
class wxTextCtrl;
class wxSizer;

namespace ui
{

class PatchInspector :
public wxutil::TransientWindow,
public wxPanel,
public selection::SelectionSystem::Observer,
public IPatch::Observer,
private wxutil::XmlResourceBasedWidget,
public sigc::trackable
public sigc::trackable,
public wxutil::SingleIdleCallback
{
private:
wxChoice* _rowCombo;
Expand Down Expand Up @@ -94,7 +92,6 @@ class PatchInspector :

// Gets called if the spin buttons with the coordinates get changed
void onCoordChange(wxCommandEvent& ev);
void onStepChanged();

void onClickSmaller(CoordRow& row);
void onClickLarger(CoordRow& row);
Expand All @@ -104,36 +101,25 @@ class PatchInspector :
void onTessChange(wxSpinEvent& ev);

public:
PatchInspector();

/** greebo: Contains the static instance of this dialog.
* Constructs the instance and calls toggle() when invoked.
*/
static PatchInspector& Instance();

// The command target
static void toggle(const cmd::ArgumentList& args);
PatchInspector(wxWindow* parent);
~PatchInspector() override;

/** greebo: SelectionSystem::Observer implementation. Gets called by
* the SelectionSystem upon selection change to allow updating of the
* patch property widgets.
*/
void selectionChanged(const scene::INodePtr& node, bool isComponent);
void selectionChanged(const scene::INodePtr& node, bool isComponent) override;

// Request a deferred update of the UI elements (is performed when GTK is idle)
void queueUpdate();

/**
* greebo: Safely disconnects this dialog from all systems
* (SelectionSystem, EventManager, ...)
* Also saves the window state to the registry.
*/
void onMainFrameShuttingDown();

// Patch::Observer
void onPatchControlPointsChanged();
void onPatchTextureChanged();
void onPatchDestruction();
void onPatchControlPointsChanged() override;
void onPatchTextureChanged() override;
void onPatchDestruction() override;

protected:
void onIdle() override;

private:
void setPatch(const IPatchNodePtr& patch);
Expand All @@ -146,13 +132,6 @@ class PatchInspector :

// Populates the combo boxes
void repopulateVertexChooser();

// This is where the static shared_ptr of the singleton instance is held.
static std::shared_ptr<PatchInspector>& InstancePtr();

// Called by wxWidgets when the system is idle
void onIdle(wxIdleEvent& ev);

}; // class PatchInspector
};

} // namespace ui

0 comments on commit b1254d7

Please sign in to comment.