mirror of https://github.com/PCSX2/pcsx2.git
Debugger: Allow having multiple dock widgets of the same type
This commit is contained in:
parent
ebaec570f7
commit
d92007bd62
|
@ -11,7 +11,7 @@
|
||||||
#include <QtGui/QClipboard>
|
#include <QtGui/QClipboard>
|
||||||
|
|
||||||
BreakpointWidget::BreakpointWidget(const DebuggerWidgetParameters& parameters)
|
BreakpointWidget::BreakpointWidget(const DebuggerWidgetParameters& parameters)
|
||||||
: DebuggerWidget(parameters)
|
: DebuggerWidget(parameters, DISALLOW_MULTIPLE_INSTANCES)
|
||||||
, m_model(new BreakpointModel(cpu()))
|
, m_model(new BreakpointModel(cpu()))
|
||||||
{
|
{
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
|
@ -11,6 +11,16 @@
|
||||||
#include "DebugTools/DebugInterface.h"
|
#include "DebugTools/DebugInterface.h"
|
||||||
|
|
||||||
#include "common/Assertions.h"
|
#include "common/Assertions.h"
|
||||||
|
#include "common/Console.h"
|
||||||
|
|
||||||
|
DebuggerWidget::DebuggerWidget(const DebuggerWidgetParameters& parameters, u32 flags)
|
||||||
|
: QWidget(parameters.parent)
|
||||||
|
, m_unique_name(parameters.unique_name)
|
||||||
|
, m_cpu(parameters.cpu)
|
||||||
|
, m_cpu_override(parameters.cpu_override)
|
||||||
|
, m_flags(flags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
DebugInterface& DebuggerWidget::cpu() const
|
DebugInterface& DebuggerWidget::cpu() const
|
||||||
{
|
{
|
||||||
|
@ -21,13 +31,49 @@ DebugInterface& DebuggerWidget::cpu() const
|
||||||
return *m_cpu;
|
return *m_cpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DebuggerWidget::displayName()
|
QString DebuggerWidget::uniqueName() const
|
||||||
{
|
{
|
||||||
auto description = DockTables::DEBUGGER_WIDGETS.find(metaObject()->className());
|
return m_unique_name;
|
||||||
if (description == DockTables::DEBUGGER_WIDGETS.end())
|
}
|
||||||
return QString();
|
|
||||||
|
|
||||||
return QCoreApplication::translate("DebuggerWidget", description->second.display_name);
|
QString DebuggerWidget::displayName() const
|
||||||
|
{
|
||||||
|
QString name = displayNameWithoutSuffix();
|
||||||
|
|
||||||
|
// If there are multiple debugger widgets of the same name, append a number
|
||||||
|
// to the display name.
|
||||||
|
if (m_display_name_suffix_number.has_value())
|
||||||
|
name = tr("%1 #%2").arg(name).arg(*m_display_name_suffix_number);
|
||||||
|
|
||||||
|
if (m_cpu_override)
|
||||||
|
name = tr("%1 (%2)").arg(name).arg(DebugInterface::cpuName(*m_cpu_override));
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DebuggerWidget::displayNameWithoutSuffix() const
|
||||||
|
{
|
||||||
|
return m_translated_display_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DebuggerWidget::customDisplayName() const
|
||||||
|
{
|
||||||
|
return m_custom_display_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerWidget::setCustomDisplayName(QString display_name)
|
||||||
|
{
|
||||||
|
m_custom_display_name = display_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DebuggerWidget::isPrimary() const
|
||||||
|
{
|
||||||
|
return m_is_primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerWidget::setPrimary(bool is_primary)
|
||||||
|
{
|
||||||
|
m_is_primary = is_primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebuggerWidget::setCpu(DebugInterface& new_cpu)
|
bool DebuggerWidget::setCpu(DebugInterface& new_cpu)
|
||||||
|
@ -72,10 +118,24 @@ bool DebuggerWidget::acceptsEventType(const char* event_type)
|
||||||
|
|
||||||
void DebuggerWidget::toJson(JsonValueWrapper& json)
|
void DebuggerWidget::toJson(JsonValueWrapper& json)
|
||||||
{
|
{
|
||||||
|
std::string custom_display_name_str = m_custom_display_name.toStdString();
|
||||||
|
rapidjson::Value custom_display_name;
|
||||||
|
custom_display_name.SetString(custom_display_name_str.c_str(), custom_display_name_str.size(), json.allocator());
|
||||||
|
json.value().AddMember("customDisplayName", custom_display_name, json.allocator());
|
||||||
|
|
||||||
|
json.value().AddMember("isPrimary", m_is_primary, json.allocator());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebuggerWidget::fromJson(JsonValueWrapper& json)
|
bool DebuggerWidget::fromJson(JsonValueWrapper& json)
|
||||||
{
|
{
|
||||||
|
auto custom_display_name = json.value().FindMember("customDisplayName");
|
||||||
|
if (custom_display_name != json.value().MemberEnd() && custom_display_name->value.IsString())
|
||||||
|
m_custom_display_name = QString(custom_display_name->value.GetString());
|
||||||
|
|
||||||
|
auto is_primary = json.value().FindMember("isPrimary");
|
||||||
|
if (is_primary != json.value().MemberEnd() && is_primary->value.IsBool())
|
||||||
|
m_is_primary = is_primary->value.GetBool();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +157,37 @@ void DebuggerWidget::switchToThisTab()
|
||||||
g_debugger_window->dockManager().switchToDebuggerWidget(this);
|
g_debugger_window->dockManager().switchToDebuggerWidget(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DebuggerWidget::supportsMultipleInstances()
|
||||||
|
{
|
||||||
|
return !(m_flags & DISALLOW_MULTIPLE_INSTANCES);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerWidget::retranslateDisplayName()
|
||||||
|
{
|
||||||
|
if (!m_custom_display_name.isEmpty())
|
||||||
|
{
|
||||||
|
m_translated_display_name = m_custom_display_name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto description = DockTables::DEBUGGER_WIDGETS.find(metaObject()->className());
|
||||||
|
if (description != DockTables::DEBUGGER_WIDGETS.end())
|
||||||
|
m_translated_display_name = QCoreApplication::translate("DebuggerWidget", description->second.display_name);
|
||||||
|
else
|
||||||
|
m_translated_display_name = QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> DebuggerWidget::displayNameSuffixNumber() const
|
||||||
|
{
|
||||||
|
return m_display_name_suffix_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebuggerWidget::setDisplayNameSuffixNumber(std::optional<int> suffix_number)
|
||||||
|
{
|
||||||
|
m_display_name_suffix_number = suffix_number;
|
||||||
|
}
|
||||||
|
|
||||||
void DebuggerWidget::goToInDisassembler(u32 address, bool switch_to_tab)
|
void DebuggerWidget::goToInDisassembler(u32 address, bool switch_to_tab)
|
||||||
{
|
{
|
||||||
DebuggerEvents::GoToAddress event;
|
DebuggerEvents::GoToAddress event;
|
||||||
|
@ -115,20 +206,17 @@ void DebuggerWidget::goToInMemoryView(u32 address, bool switch_to_tab)
|
||||||
DebuggerWidget::sendEvent(std::move(event));
|
DebuggerWidget::sendEvent(std::move(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
DebuggerWidget::DebuggerWidget(const DebuggerWidgetParameters& parameters)
|
|
||||||
: QWidget(parameters.parent)
|
|
||||||
, m_cpu(parameters.cpu)
|
|
||||||
, m_cpu_override(parameters.cpu_override)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerWidget::sendEventImplementation(const DebuggerEvents::Event& event)
|
void DebuggerWidget::sendEventImplementation(const DebuggerEvents::Event& event)
|
||||||
{
|
{
|
||||||
if (!g_debugger_window)
|
if (!g_debugger_window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (const auto& [unique_name, widget] : g_debugger_window->dockManager().debuggerWidgets())
|
for (const auto& [unique_name, widget] : g_debugger_window->dockManager().debuggerWidgets())
|
||||||
if (widget->handleEvent(event))
|
if (widget->isPrimary() && widget->handleEvent(event))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const auto& [unique_name, widget] : g_debugger_window->dockManager().debuggerWidgets())
|
||||||
|
if (!widget->isPrimary() && widget->handleEvent(event))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +245,13 @@ std::vector<QAction*> DebuggerWidget::createEventActionsImplementation(
|
||||||
if ((!skip_self || widget != this) && widget->acceptsEventType(event_type))
|
if ((!skip_self || widget != this) && widget->acceptsEventType(event_type))
|
||||||
receivers.emplace_back(widget);
|
receivers.emplace_back(widget);
|
||||||
|
|
||||||
|
std::sort(receivers.begin(), receivers.end(), [&](const DebuggerWidget* lhs, const DebuggerWidget* rhs) {
|
||||||
|
if (lhs->displayNameWithoutSuffix() == rhs->displayNameWithoutSuffix())
|
||||||
|
return lhs->displayNameSuffixNumber() < rhs->displayNameSuffixNumber();
|
||||||
|
|
||||||
|
return lhs->displayNameWithoutSuffix() < rhs->displayNameWithoutSuffix();
|
||||||
|
});
|
||||||
|
|
||||||
QMenu* submenu = nullptr;
|
QMenu* submenu = nullptr;
|
||||||
if (receivers.size() > max_top_level_actions)
|
if (receivers.size() > max_top_level_actions)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,7 @@ class JsonValueWrapper;
|
||||||
// Container for variables to be passed to the constructor of DebuggerWidget.
|
// Container for variables to be passed to the constructor of DebuggerWidget.
|
||||||
struct DebuggerWidgetParameters
|
struct DebuggerWidgetParameters
|
||||||
{
|
{
|
||||||
|
QString unique_name;
|
||||||
DebugInterface* cpu = nullptr;
|
DebugInterface* cpu = nullptr;
|
||||||
std::optional<BreakPointCpu> cpu_override;
|
std::optional<BreakPointCpu> cpu_override;
|
||||||
QWidget* parent = nullptr;
|
QWidget* parent = nullptr;
|
||||||
|
@ -26,8 +27,17 @@ class DebuggerWidget : public QWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
QString uniqueName() const;
|
||||||
|
|
||||||
// Get the translated name that should be displayed for this widget.
|
// Get the translated name that should be displayed for this widget.
|
||||||
QString displayName();
|
QString displayName() const;
|
||||||
|
QString displayNameWithoutSuffix() const;
|
||||||
|
|
||||||
|
QString customDisplayName() const;
|
||||||
|
void setCustomDisplayName(QString display_name);
|
||||||
|
|
||||||
|
bool isPrimary() const;
|
||||||
|
void setPrimary(bool is_primary);
|
||||||
|
|
||||||
// Get the effective debug interface associated with this particular widget
|
// Get the effective debug interface associated with this particular widget
|
||||||
// if it's set, otherwise return the one associated with the layout that
|
// if it's set, otherwise return the one associated with the layout that
|
||||||
|
@ -133,11 +143,25 @@ public:
|
||||||
|
|
||||||
void switchToThisTab();
|
void switchToThisTab();
|
||||||
|
|
||||||
|
bool supportsMultipleInstances();
|
||||||
|
|
||||||
|
void retranslateDisplayName();
|
||||||
|
|
||||||
|
std::optional<int> displayNameSuffixNumber() const;
|
||||||
|
void setDisplayNameSuffixNumber(std::optional<int> suffix_number);
|
||||||
|
|
||||||
static void goToInDisassembler(u32 address, bool switch_to_tab);
|
static void goToInDisassembler(u32 address, bool switch_to_tab);
|
||||||
static void goToInMemoryView(u32 address, bool switch_to_tab);
|
static void goToInMemoryView(u32 address, bool switch_to_tab);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DebuggerWidget(const DebuggerWidgetParameters& parameters);
|
enum Flags
|
||||||
|
{
|
||||||
|
NO_DEBUGGER_FLAGS = 0,
|
||||||
|
// Prevent the user from opening multiple dock widgets of this type.
|
||||||
|
DISALLOW_MULTIPLE_INSTANCES = 1 << 0
|
||||||
|
};
|
||||||
|
|
||||||
|
DebuggerWidget(const DebuggerWidgetParameters& parameters, u32 flags);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void sendEventImplementation(const DebuggerEvents::Event& event);
|
static void sendEventImplementation(const DebuggerEvents::Event& event);
|
||||||
|
@ -151,7 +175,22 @@ private:
|
||||||
const char* action_prefix,
|
const char* action_prefix,
|
||||||
std::function<const DebuggerEvents::Event*()> event_func);
|
std::function<const DebuggerEvents::Event*()> event_func);
|
||||||
|
|
||||||
|
QString m_unique_name;
|
||||||
|
|
||||||
|
// A user-defined name, or an empty string if no name was specified so that
|
||||||
|
// the default names can be retranslated on the fly.
|
||||||
|
QString m_custom_display_name;
|
||||||
|
|
||||||
|
QString m_translated_display_name;
|
||||||
|
std::optional<int> m_display_name_suffix_number;
|
||||||
|
|
||||||
|
// Primary debugger widgets will be chosen to handle events first. For
|
||||||
|
// example, clicking on an address to go to it in the primary memory view.
|
||||||
|
bool m_is_primary = false;
|
||||||
|
|
||||||
DebugInterface* m_cpu;
|
DebugInterface* m_cpu;
|
||||||
std::optional<BreakPointCpu> m_cpu_override;
|
std::optional<BreakPointCpu> m_cpu_override;
|
||||||
|
u32 m_flags;
|
||||||
|
|
||||||
std::multimap<std::string, std::function<bool(const DebuggerEvents::Event&)>> m_event_handlers;
|
std::multimap<std::string, std::function<bool(const DebuggerEvents::Event&)>> m_event_handlers;
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
using namespace QtUtils;
|
using namespace QtUtils;
|
||||||
|
|
||||||
DisassemblyWidget::DisassemblyWidget(const DebuggerWidgetParameters& parameters)
|
DisassemblyWidget::DisassemblyWidget(const DebuggerWidgetParameters& parameters)
|
||||||
: DebuggerWidget(parameters)
|
: DebuggerWidget(parameters, NO_DEBUGGER_FLAGS)
|
||||||
{
|
{
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
||||||
|
|
|
@ -47,14 +47,20 @@ DockLayout::DockLayout(
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < default_layout.widgets.size(); i++)
|
for (size_t i = 0; i < default_layout.widgets.size(); i++)
|
||||||
{
|
{
|
||||||
auto iterator = DockTables::DEBUGGER_WIDGETS.find(QString::fromStdString(default_layout.widgets[i].type));
|
auto iterator = DockTables::DEBUGGER_WIDGETS.find(default_layout.widgets[i].type);
|
||||||
pxAssertRel(iterator != DockTables::DEBUGGER_WIDGETS.end(), "Invalid default layout.");
|
pxAssertRel(iterator != DockTables::DEBUGGER_WIDGETS.end(), "Invalid default layout.");
|
||||||
const DockTables::DebuggerWidgetDescription& dock_description = iterator->second;
|
const DockTables::DebuggerWidgetDescription& dock_description = iterator->second;
|
||||||
|
|
||||||
DebuggerWidgetParameters parameters;
|
DebuggerWidgetParameters parameters;
|
||||||
|
parameters.unique_name = generateNewUniqueName(default_layout.widgets[i].type.c_str());
|
||||||
parameters.cpu = &DebugInterface::get(cpu);
|
parameters.cpu = &DebugInterface::get(cpu);
|
||||||
|
|
||||||
|
if (parameters.unique_name.isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
DebuggerWidget* widget = dock_description.create_widget(parameters);
|
DebuggerWidget* widget = dock_description.create_widget(parameters);
|
||||||
m_widgets.emplace(QString::fromStdString(default_layout.widgets[i].type), widget);
|
widget->setPrimary(true);
|
||||||
|
m_widgets.emplace(parameters.unique_name, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
save(index);
|
save(index);
|
||||||
|
@ -81,6 +87,7 @@ DockLayout::DockLayout(
|
||||||
: m_name(name)
|
: m_name(name)
|
||||||
, m_cpu(cpu)
|
, m_cpu(cpu)
|
||||||
, m_is_default(is_default)
|
, m_is_default(is_default)
|
||||||
|
, m_next_unique_name(layout_to_clone.m_next_unique_name)
|
||||||
, m_base_layout(layout_to_clone.m_base_layout)
|
, m_base_layout(layout_to_clone.m_base_layout)
|
||||||
, m_toolbars(layout_to_clone.m_toolbars)
|
, m_toolbars(layout_to_clone.m_toolbars)
|
||||||
, m_geometry(layout_to_clone.m_geometry)
|
, m_geometry(layout_to_clone.m_geometry)
|
||||||
|
@ -92,9 +99,13 @@ DockLayout::DockLayout(
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
DebuggerWidgetParameters parameters;
|
DebuggerWidgetParameters parameters;
|
||||||
|
parameters.unique_name = unique_name;
|
||||||
parameters.cpu = &DebugInterface::get(cpu);
|
parameters.cpu = &DebugInterface::get(cpu);
|
||||||
parameters.cpu_override = widget_to_clone->cpuOverride();
|
parameters.cpu_override = widget_to_clone->cpuOverride();
|
||||||
|
|
||||||
DebuggerWidget* new_widget = widget_description->second.create_widget(parameters);
|
DebuggerWidget* new_widget = widget_description->second.create_widget(parameters);
|
||||||
|
new_widget->setCustomDisplayName(widget_to_clone->customDisplayName());
|
||||||
|
new_widget->setPrimary(widget_to_clone->isPrimary());
|
||||||
m_widgets.emplace(unique_name, new_widget);
|
m_widgets.emplace(unique_name, new_widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,8 +166,8 @@ void DockLayout::setCpu(BreakPointCpu cpu)
|
||||||
|
|
||||||
void DockLayout::freeze()
|
void DockLayout::freeze()
|
||||||
{
|
{
|
||||||
pxAssert(!m_is_frozen);
|
pxAssert(m_is_active);
|
||||||
m_is_frozen = true;
|
m_is_active = false;
|
||||||
|
|
||||||
if (g_debugger_window)
|
if (g_debugger_window)
|
||||||
m_toolbars = g_debugger_window->saveState();
|
m_toolbars = g_debugger_window->saveState();
|
||||||
|
@ -178,8 +189,8 @@ void DockLayout::freeze()
|
||||||
|
|
||||||
void DockLayout::thaw()
|
void DockLayout::thaw()
|
||||||
{
|
{
|
||||||
pxAssert(m_is_frozen);
|
pxAssert(!m_is_active);
|
||||||
m_is_frozen = false;
|
m_is_active = true;
|
||||||
|
|
||||||
if (!g_debugger_window)
|
if (!g_debugger_window)
|
||||||
return;
|
return;
|
||||||
|
@ -204,26 +215,26 @@ void DockLayout::thaw()
|
||||||
{
|
{
|
||||||
// This is a newly created layout with no geometry information.
|
// This is a newly created layout with no geometry information.
|
||||||
setupDefaultLayout();
|
setupDefaultLayout();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// Restore the geometry of the dock widgets we just recreated.
|
|
||||||
KDDockWidgets::LayoutSaver saver(KDDockWidgets::RestoreOption_RelativeToMainWindow);
|
|
||||||
if (!saver.restoreLayout(m_geometry))
|
|
||||||
{
|
{
|
||||||
// We've failed to restore the geometry, so just tear down whatever dock
|
// Create all the dock widgets.
|
||||||
// widgets may exist and then setup the default layout.
|
KDDockWidgets::LayoutSaver saver(KDDockWidgets::RestoreOption_RelativeToMainWindow);
|
||||||
for (KDDockWidgets::Core::DockWidget* dock : KDDockWidgets::DockRegistry::self()->dockwidgets())
|
if (!saver.restoreLayout(m_geometry))
|
||||||
{
|
{
|
||||||
// Make sure the dock widget releases ownership of its content.
|
// We've failed to restore the geometry, so just tear down whatever
|
||||||
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(dock->view());
|
// dock widgets may exist and then setup the default layout.
|
||||||
view->setWidget(new QWidget());
|
for (KDDockWidgets::Core::DockWidget* dock : KDDockWidgets::DockRegistry::self()->dockwidgets())
|
||||||
|
{
|
||||||
|
// Make sure the dock widget releases ownership of its content.
|
||||||
|
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(dock->view());
|
||||||
|
view->setWidget(new QWidget());
|
||||||
|
|
||||||
delete dock;
|
delete dock;
|
||||||
|
}
|
||||||
|
|
||||||
|
setupDefaultLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
setupDefaultLayout();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that all the dock widgets have been restored correctly.
|
// Check that all the dock widgets have been restored correctly.
|
||||||
|
@ -242,16 +253,19 @@ void DockLayout::thaw()
|
||||||
for (const QString& unique_name : orphaned_debugger_widgets)
|
for (const QString& unique_name : orphaned_debugger_widgets)
|
||||||
{
|
{
|
||||||
auto widget_iterator = m_widgets.find(unique_name);
|
auto widget_iterator = m_widgets.find(unique_name);
|
||||||
|
pxAssert(widget_iterator != m_widgets.end());
|
||||||
|
|
||||||
|
setPrimaryDebuggerWidget(widget_iterator->second.get(), false);
|
||||||
delete widget_iterator->second.get();
|
delete widget_iterator->second.get();
|
||||||
m_widgets.erase(widget_iterator);
|
m_widgets.erase(widget_iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
retranslateDockWidgets();
|
updateDockWidgetTitles();
|
||||||
}
|
}
|
||||||
|
|
||||||
KDDockWidgets::Core::DockWidget* DockLayout::createDockWidget(const QString& name)
|
KDDockWidgets::Core::DockWidget* DockLayout::createDockWidget(const QString& name)
|
||||||
{
|
{
|
||||||
pxAssert(!m_is_frozen);
|
pxAssert(m_is_active);
|
||||||
pxAssert(KDDockWidgets::LayoutSaver::restoreInProgress());
|
pxAssert(KDDockWidgets::LayoutSaver::restoreInProgress());
|
||||||
|
|
||||||
auto widget_iterator = m_widgets.find(name);
|
auto widget_iterator = m_widgets.find(name);
|
||||||
|
@ -260,6 +274,7 @@ KDDockWidgets::Core::DockWidget* DockLayout::createDockWidget(const QString& nam
|
||||||
|
|
||||||
DebuggerWidget* widget = widget_iterator->second;
|
DebuggerWidget* widget = widget_iterator->second;
|
||||||
pxAssert(widget);
|
pxAssert(widget);
|
||||||
|
pxAssert(widget->uniqueName() == name);
|
||||||
|
|
||||||
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(
|
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(
|
||||||
KDDockWidgets::Config::self().viewFactory()->createDockWidget(name));
|
KDDockWidgets::Config::self().viewFactory()->createDockWidget(name));
|
||||||
|
@ -268,139 +283,132 @@ KDDockWidgets::Core::DockWidget* DockLayout::createDockWidget(const QString& nam
|
||||||
return view->asController<KDDockWidgets::Core::DockWidget>();
|
return view->asController<KDDockWidgets::Core::DockWidget>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockLayout::retranslateDockWidgets()
|
void DockLayout::updateDockWidgetTitles()
|
||||||
{
|
{
|
||||||
for (KDDockWidgets::Core::DockWidget* widget : KDDockWidgets::DockRegistry::self()->dockwidgets())
|
if (!m_is_active)
|
||||||
retranslateDockWidget(widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DockLayout::retranslateDockWidget(KDDockWidgets::Core::DockWidget* dock_widget)
|
|
||||||
{
|
|
||||||
pxAssert(!m_is_frozen);
|
|
||||||
|
|
||||||
auto widget_iterator = m_widgets.find(dock_widget->uniqueName());
|
|
||||||
if (widget_iterator == m_widgets.end())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DebuggerWidget* widget = widget_iterator->second.get();
|
// Translate default debugger widget names.
|
||||||
if (!widget)
|
for (auto& [unique_name, widget] : m_widgets)
|
||||||
return;
|
widget->retranslateDisplayName();
|
||||||
;
|
|
||||||
std::optional<BreakPointCpu> cpu_override = widget->cpuOverride();
|
|
||||||
|
|
||||||
if (cpu_override.has_value())
|
// Determine if any widgets have duplicate display names.
|
||||||
|
std::map<QString, std::vector<DebuggerWidget*>> display_name_to_widgets;
|
||||||
|
for (auto& [unique_name, widget] : m_widgets)
|
||||||
|
display_name_to_widgets[widget->displayNameWithoutSuffix()].emplace_back(widget.get());
|
||||||
|
|
||||||
|
for (auto& [display_name, widgets] : display_name_to_widgets)
|
||||||
{
|
{
|
||||||
const char* cpu_name = DebugInterface::cpuName(*cpu_override);
|
std::sort(widgets.begin(), widgets.end(),
|
||||||
dock_widget->setTitle(QString("%1 (%2)").arg(widget->displayName()).arg(cpu_name));
|
[&](const DebuggerWidget* lhs, const DebuggerWidget* rhs) {
|
||||||
|
return lhs->uniqueName() < rhs->uniqueName();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (size_t i = 0; i < widgets.size(); i++)
|
||||||
|
{
|
||||||
|
std::optional<int> suffix_number;
|
||||||
|
if (widgets.size() != 1)
|
||||||
|
suffix_number = static_cast<int>(i + 1);
|
||||||
|
|
||||||
|
widgets[i]->setDisplayNameSuffixNumber(suffix_number);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Propagate the new names from the debugger widgets to the dock widgets.
|
||||||
|
for (auto& [unique_name, widget] : m_widgets)
|
||||||
{
|
{
|
||||||
dock_widget->setTitle(std::move(widget->displayName()));
|
auto [controller, view] = DockUtils::dockWidgetFromName(widget->uniqueName());
|
||||||
|
if (!controller)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
controller->setTitle(widget->displayName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockLayout::dockWidgetClosed(KDDockWidgets::Core::DockWidget* dock_widget)
|
|
||||||
{
|
|
||||||
// The LayoutSaver class will close a bunch of dock widgets. We only want to
|
|
||||||
// delete the dock widgets when they're being closed by the user.
|
|
||||||
if (KDDockWidgets::LayoutSaver::restoreInProgress())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto debugger_widget_iterator = m_widgets.find(dock_widget->uniqueName());
|
|
||||||
if (debugger_widget_iterator == m_widgets.end())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_widgets.erase(debugger_widget_iterator);
|
|
||||||
dock_widget->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::map<QString, QPointer<DebuggerWidget>>& DockLayout::debuggerWidgets()
|
const std::map<QString, QPointer<DebuggerWidget>>& DockLayout::debuggerWidgets()
|
||||||
{
|
{
|
||||||
return m_widgets;
|
return m_widgets;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockLayout::hasDebuggerWidget(QString unique_name)
|
bool DockLayout::hasDebuggerWidget(const QString& unique_name)
|
||||||
{
|
{
|
||||||
return m_widgets.find(unique_name) != m_widgets.end();
|
return m_widgets.find(unique_name) != m_widgets.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockLayout::toggleDebuggerWidget(QString unique_name)
|
size_t DockLayout::countDebuggerWidgetsOfType(const char* type)
|
||||||
{
|
{
|
||||||
pxAssert(!m_is_frozen);
|
size_t count = 0;
|
||||||
|
for (const auto& [unique_name, widget] : m_widgets)
|
||||||
|
{
|
||||||
|
if (strcmp(widget->metaObject()->className(), type) == 0)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockLayout::createDebuggerWidget(const std::string& type)
|
||||||
|
{
|
||||||
|
pxAssert(m_is_active);
|
||||||
|
|
||||||
if (!g_debugger_window)
|
if (!g_debugger_window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto debugger_widget_iterator = m_widgets.find(unique_name);
|
auto description_iterator = DockTables::DEBUGGER_WIDGETS.find(type);
|
||||||
auto [controller, view] = DockUtils::dockWidgetFromName(unique_name);
|
pxAssert(description_iterator != DockTables::DEBUGGER_WIDGETS.end());
|
||||||
|
|
||||||
if (debugger_widget_iterator == m_widgets.end())
|
const DockTables::DebuggerWidgetDescription& description = description_iterator->second;
|
||||||
{
|
|
||||||
// Create the dock widget.
|
|
||||||
if (controller)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto description_iterator = DockTables::DEBUGGER_WIDGETS.find(unique_name);
|
DebuggerWidgetParameters parameters;
|
||||||
if (description_iterator == DockTables::DEBUGGER_WIDGETS.end())
|
parameters.unique_name = generateNewUniqueName(type.c_str());
|
||||||
return;
|
parameters.cpu = &DebugInterface::get(m_cpu);
|
||||||
|
|
||||||
const DockTables::DebuggerWidgetDescription& description = description_iterator->second;
|
if (parameters.unique_name.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
DebuggerWidgetParameters parameters;
|
DebuggerWidget* widget = description.create_widget(parameters);
|
||||||
parameters.cpu = &DebugInterface::get(m_cpu);
|
m_widgets.emplace(parameters.unique_name, widget);
|
||||||
DebuggerWidget* widget = description.create_widget(parameters);
|
|
||||||
m_widgets.emplace(unique_name, widget);
|
|
||||||
|
|
||||||
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(
|
setPrimaryDebuggerWidget(widget, countDebuggerWidgetsOfType(type.c_str()) == 0);
|
||||||
KDDockWidgets::Config::self().viewFactory()->createDockWidget(unique_name));
|
|
||||||
view->setWidget(widget);
|
|
||||||
|
|
||||||
KDDockWidgets::Core::DockWidget* controller = view->asController<KDDockWidgets::Core::DockWidget>();
|
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(
|
||||||
if (!controller)
|
KDDockWidgets::Config::self().viewFactory()->createDockWidget(widget->uniqueName()));
|
||||||
{
|
view->setWidget(widget);
|
||||||
delete view;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DockUtils::insertDockWidgetAtPreferredLocation(controller, description.preferred_location, g_debugger_window);
|
KDDockWidgets::Core::DockWidget* controller = view->asController<KDDockWidgets::Core::DockWidget>();
|
||||||
retranslateDockWidget(controller);
|
pxAssert(controller);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Delete the dock widget.
|
|
||||||
if (!controller)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_widgets.erase(debugger_widget_iterator);
|
DockUtils::insertDockWidgetAtPreferredLocation(controller, description.preferred_location, g_debugger_window);
|
||||||
delete controller;
|
updateDockWidgetTitles();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockLayout::recreateDebuggerWidget(QString unique_name)
|
void DockLayout::recreateDebuggerWidget(const QString& unique_name)
|
||||||
{
|
{
|
||||||
pxAssert(!m_is_frozen);
|
pxAssert(m_is_active);
|
||||||
|
|
||||||
auto [controller, view] = DockUtils::dockWidgetFromName(unique_name);
|
auto [controller, view] = DockUtils::dockWidgetFromName(unique_name);
|
||||||
if (!controller || !view)
|
pxAssert(controller);
|
||||||
return;
|
pxAssert(view);
|
||||||
|
|
||||||
auto debugger_widget_iterator = m_widgets.find(unique_name);
|
auto debugger_widget_iterator = m_widgets.find(unique_name);
|
||||||
if (debugger_widget_iterator == m_widgets.end())
|
pxAssert(debugger_widget_iterator != m_widgets.end());
|
||||||
return;
|
|
||||||
|
|
||||||
DebuggerWidget* old_debugger_widget = debugger_widget_iterator->second;
|
DebuggerWidget* old_debugger_widget = debugger_widget_iterator->second;
|
||||||
pxAssert(old_debugger_widget == view->widget());
|
pxAssert(old_debugger_widget == view->widget());
|
||||||
|
|
||||||
auto description_iterator = DockTables::DEBUGGER_WIDGETS.find(old_debugger_widget->metaObject()->className());
|
auto description_iterator = DockTables::DEBUGGER_WIDGETS.find(old_debugger_widget->metaObject()->className());
|
||||||
if (description_iterator == DockTables::DEBUGGER_WIDGETS.end())
|
pxAssert(description_iterator != DockTables::DEBUGGER_WIDGETS.end());
|
||||||
return;
|
|
||||||
|
|
||||||
const DockTables::DebuggerWidgetDescription& description = description_iterator->second;
|
const DockTables::DebuggerWidgetDescription& description = description_iterator->second;
|
||||||
|
|
||||||
DebuggerWidgetParameters parameters;
|
DebuggerWidgetParameters parameters;
|
||||||
|
parameters.unique_name = old_debugger_widget->uniqueName();
|
||||||
parameters.cpu = &DebugInterface::get(m_cpu);
|
parameters.cpu = &DebugInterface::get(m_cpu);
|
||||||
parameters.cpu_override = old_debugger_widget->cpuOverride();
|
parameters.cpu_override = old_debugger_widget->cpuOverride();
|
||||||
|
|
||||||
DebuggerWidget* new_debugger_widget = description.create_widget(parameters);
|
DebuggerWidget* new_debugger_widget = description.create_widget(parameters);
|
||||||
|
new_debugger_widget->setCustomDisplayName(old_debugger_widget->customDisplayName());
|
||||||
|
new_debugger_widget->setPrimary(old_debugger_widget->isPrimary());
|
||||||
debugger_widget_iterator->second = new_debugger_widget;
|
debugger_widget_iterator->second = new_debugger_widget;
|
||||||
|
|
||||||
view->setWidget(new_debugger_widget);
|
view->setWidget(new_debugger_widget);
|
||||||
|
@ -408,6 +416,77 @@ void DockLayout::recreateDebuggerWidget(QString unique_name)
|
||||||
delete old_debugger_widget;
|
delete old_debugger_widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DockLayout::destroyDebuggerWidget(const QString& unique_name)
|
||||||
|
{
|
||||||
|
pxAssert(m_is_active);
|
||||||
|
|
||||||
|
if (!g_debugger_window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto debugger_widget_iterator = m_widgets.find(unique_name);
|
||||||
|
if (debugger_widget_iterator == m_widgets.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
setPrimaryDebuggerWidget(debugger_widget_iterator->second.get(), false);
|
||||||
|
delete debugger_widget_iterator->second.get();
|
||||||
|
m_widgets.erase(debugger_widget_iterator);
|
||||||
|
|
||||||
|
auto [controller, view] = DockUtils::dockWidgetFromName(unique_name);
|
||||||
|
if (!controller)
|
||||||
|
return;
|
||||||
|
|
||||||
|
controller->deleteLater();
|
||||||
|
|
||||||
|
updateDockWidgetTitles();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockLayout::setPrimaryDebuggerWidget(DebuggerWidget* widget, bool is_primary)
|
||||||
|
{
|
||||||
|
bool present = false;
|
||||||
|
for (auto& [unique_name, test_widget] : m_widgets)
|
||||||
|
{
|
||||||
|
if (test_widget.get() == widget)
|
||||||
|
{
|
||||||
|
present = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!present)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (is_primary)
|
||||||
|
{
|
||||||
|
// Set the passed widget as the primary widget.
|
||||||
|
for (auto& [unique_name, test_widget] : m_widgets)
|
||||||
|
{
|
||||||
|
if (strcmp(test_widget->metaObject()->className(), widget->metaObject()->className()) == 0)
|
||||||
|
{
|
||||||
|
test_widget->setPrimary(test_widget.get() == widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (widget->isPrimary())
|
||||||
|
{
|
||||||
|
// Set an arbitrary widget as the primary widget.
|
||||||
|
bool next = true;
|
||||||
|
for (auto& [unique_name, test_widget] : m_widgets)
|
||||||
|
{
|
||||||
|
if (test_widget != widget &&
|
||||||
|
strcmp(test_widget->metaObject()->className(), widget->metaObject()->className()) == 0)
|
||||||
|
{
|
||||||
|
test_widget->setPrimary(next);
|
||||||
|
next = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we haven't set another widget as the primary one we can't make
|
||||||
|
// this one not the primary one.
|
||||||
|
if (!next)
|
||||||
|
widget->setPrimary(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DockLayout::deleteFile()
|
void DockLayout::deleteFile()
|
||||||
{
|
{
|
||||||
if (m_layout_file_path.empty())
|
if (m_layout_file_path.empty())
|
||||||
|
@ -416,12 +495,13 @@ void DockLayout::deleteFile()
|
||||||
if (!FileSystem::DeleteFilePath(m_layout_file_path.c_str()))
|
if (!FileSystem::DeleteFilePath(m_layout_file_path.c_str()))
|
||||||
Console.Error("Debugger: Failed to delete layout file '%s'.", m_layout_file_path.c_str());
|
Console.Error("Debugger: Failed to delete layout file '%s'.", m_layout_file_path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockLayout::save(DockLayout::Index layout_index)
|
bool DockLayout::save(DockLayout::Index layout_index)
|
||||||
{
|
{
|
||||||
if (!g_debugger_window)
|
if (!g_debugger_window)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!m_is_frozen)
|
if (m_is_active)
|
||||||
{
|
{
|
||||||
m_toolbars = g_debugger_window->saveState();
|
m_toolbars = g_debugger_window->saveState();
|
||||||
|
|
||||||
|
@ -451,6 +531,7 @@ bool DockLayout::save(DockLayout::Index layout_index)
|
||||||
json.AddMember("target", rapidjson::Value().SetString(cpu_name, strlen(cpu_name)), json.GetAllocator());
|
json.AddMember("target", rapidjson::Value().SetString(cpu_name, strlen(cpu_name)), json.GetAllocator());
|
||||||
json.AddMember("index", static_cast<int>(layout_index), json.GetAllocator());
|
json.AddMember("index", static_cast<int>(layout_index), json.GetAllocator());
|
||||||
json.AddMember("isDefault", m_is_default, json.GetAllocator());
|
json.AddMember("isDefault", m_is_default, json.GetAllocator());
|
||||||
|
json.AddMember("nextUniqueName", m_next_unique_name, json.GetAllocator());
|
||||||
|
|
||||||
if (!m_base_layout.empty())
|
if (!m_base_layout.empty())
|
||||||
{
|
{
|
||||||
|
@ -545,7 +626,7 @@ void DockLayout::load(
|
||||||
LoadResult& result,
|
LoadResult& result,
|
||||||
DockLayout::Index& index_last_session)
|
DockLayout::Index& index_last_session)
|
||||||
{
|
{
|
||||||
pxAssert(m_is_frozen);
|
pxAssert(!m_is_active);
|
||||||
|
|
||||||
result = SUCCESS;
|
result = SUCCESS;
|
||||||
|
|
||||||
|
@ -631,6 +712,10 @@ void DockLayout::load(
|
||||||
if (is_default != json.MemberEnd() && is_default->value.IsBool())
|
if (is_default != json.MemberEnd() && is_default->value.IsBool())
|
||||||
m_is_default = is_default->value.GetBool();
|
m_is_default = is_default->value.GetBool();
|
||||||
|
|
||||||
|
auto next_unique_name = json.FindMember("nextUniqueName");
|
||||||
|
if (next_unique_name != json.MemberBegin() && next_unique_name->value.IsInt())
|
||||||
|
m_next_unique_name = next_unique_name->value.GetInt();
|
||||||
|
|
||||||
auto base_layout = json.FindMember("baseLayout");
|
auto base_layout = json.FindMember("baseLayout");
|
||||||
if (base_layout != json.MemberEnd() && base_layout->value.IsString())
|
if (base_layout != json.MemberEnd() && base_layout->value.IsString())
|
||||||
m_base_layout = base_layout->value.GetString();
|
m_base_layout = base_layout->value.GetString();
|
||||||
|
@ -648,6 +733,10 @@ void DockLayout::load(
|
||||||
if (unique_name == object.MemberEnd() || !unique_name->value.IsString())
|
if (unique_name == object.MemberEnd() || !unique_name->value.IsString())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
auto widgets_iterator = m_widgets.find(unique_name->value.GetString());
|
||||||
|
if (widgets_iterator != m_widgets.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
auto type = object.FindMember("type");
|
auto type = object.FindMember("type");
|
||||||
if (type == object.MemberEnd() || !type->value.IsString())
|
if (type == object.MemberEnd() || !type->value.IsString())
|
||||||
continue;
|
continue;
|
||||||
|
@ -667,8 +756,10 @@ void DockLayout::load(
|
||||||
}
|
}
|
||||||
|
|
||||||
DebuggerWidgetParameters parameters;
|
DebuggerWidgetParameters parameters;
|
||||||
|
parameters.unique_name = unique_name->value.GetString();
|
||||||
parameters.cpu = &DebugInterface::get(m_cpu);
|
parameters.cpu = &DebugInterface::get(m_cpu);
|
||||||
parameters.cpu_override = cpu_override;
|
parameters.cpu_override = cpu_override;
|
||||||
|
|
||||||
DebuggerWidget* widget = description->second.create_widget(parameters);
|
DebuggerWidget* widget = description->second.create_widget(parameters);
|
||||||
|
|
||||||
JsonValueWrapper wrapper(object, json.GetAllocator());
|
JsonValueWrapper wrapper(object, json.GetAllocator());
|
||||||
|
@ -693,13 +784,44 @@ void DockLayout::load(
|
||||||
}
|
}
|
||||||
|
|
||||||
m_layout_file_path = path;
|
m_layout_file_path = path;
|
||||||
|
|
||||||
|
validatePrimaryDebuggerWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockLayout::validatePrimaryDebuggerWidgets()
|
||||||
|
{
|
||||||
|
std::map<std::string, std::vector<DebuggerWidget*>> type_to_widgets;
|
||||||
|
for (const auto& [unique_name, widget] : m_widgets)
|
||||||
|
type_to_widgets[widget->metaObject()->className()].emplace_back(widget.get());
|
||||||
|
|
||||||
|
for (auto& [type, widgets] : type_to_widgets)
|
||||||
|
{
|
||||||
|
u32 primary_widgets = 0;
|
||||||
|
|
||||||
|
// Make sure at most one widget is marked as primary.
|
||||||
|
for (DebuggerWidget* widget : widgets)
|
||||||
|
{
|
||||||
|
if (widget->isPrimary())
|
||||||
|
{
|
||||||
|
if (primary_widgets != 0)
|
||||||
|
widget->setPrimary(false);
|
||||||
|
|
||||||
|
primary_widgets++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If none of the widgets were marked as primary, just set the first one
|
||||||
|
// as the primary one.
|
||||||
|
if (primary_widgets == 0)
|
||||||
|
widgets[0]->setPrimary(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockLayout::setupDefaultLayout()
|
void DockLayout::setupDefaultLayout()
|
||||||
{
|
{
|
||||||
pxAssert(!m_is_frozen);
|
pxAssert(m_is_active);
|
||||||
|
|
||||||
if (m_base_layout.empty() || !g_debugger_window)
|
if (!g_debugger_window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const DockTables::DefaultDockLayout* base_layout = DockTables::defaultLayout(m_base_layout);
|
const DockTables::DefaultDockLayout* base_layout = DockTables::defaultLayout(m_base_layout);
|
||||||
|
@ -713,15 +835,16 @@ void DockLayout::setupDefaultLayout()
|
||||||
const DockTables::DefaultDockGroupDescription& group =
|
const DockTables::DefaultDockGroupDescription& group =
|
||||||
base_layout->groups[static_cast<u32>(dock_description.group)];
|
base_layout->groups[static_cast<u32>(dock_description.group)];
|
||||||
|
|
||||||
auto widget_iterator = m_widgets.find(QString::fromStdString(dock_description.type));
|
DebuggerWidget* widget = nullptr;
|
||||||
if (widget_iterator == m_widgets.end())
|
for (auto& [unique_name, test_widget] : m_widgets)
|
||||||
|
if (test_widget->metaObject()->className() == dock_description.type)
|
||||||
|
widget = test_widget;
|
||||||
|
|
||||||
|
if (!widget)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const QString& unique_name = widget_iterator->first;
|
|
||||||
DebuggerWidget* widget = widget_iterator->second;
|
|
||||||
|
|
||||||
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(
|
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(
|
||||||
KDDockWidgets::Config::self().viewFactory()->createDockWidget(unique_name));
|
KDDockWidgets::Config::self().viewFactory()->createDockWidget(widget->uniqueName()));
|
||||||
view->setWidget(widget);
|
view->setWidget(widget);
|
||||||
|
|
||||||
if (!groups[static_cast<u32>(dock_description.group)])
|
if (!groups[static_cast<u32>(dock_description.group)])
|
||||||
|
@ -742,6 +865,21 @@ void DockLayout::setupDefaultLayout()
|
||||||
|
|
||||||
for (KDDockWidgets::Core::Group* group : KDDockWidgets::DockRegistry::self()->groups())
|
for (KDDockWidgets::Core::Group* group : KDDockWidgets::DockRegistry::self()->groups())
|
||||||
group->setCurrentTabIndex(0);
|
group->setCurrentTabIndex(0);
|
||||||
|
}
|
||||||
retranslateDockWidgets();
|
|
||||||
|
QString DockLayout::generateNewUniqueName(const char* type)
|
||||||
|
{
|
||||||
|
QString name;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (m_next_unique_name == INT_MAX)
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
// Produce unique names that will lexicographically sort in the order
|
||||||
|
// they were allocated. This ensures the #1, #2, etc suffixes for dock
|
||||||
|
// widgets with conflicting names will be assigned in the correct order.
|
||||||
|
name = QStringLiteral("%1-%2").arg(m_next_unique_name, 16, 10, QLatin1Char('0')).arg(type);
|
||||||
|
m_next_unique_name++;
|
||||||
|
} while (hasDebuggerWidget(name));
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,14 +92,15 @@ public:
|
||||||
void thaw();
|
void thaw();
|
||||||
|
|
||||||
KDDockWidgets::Core::DockWidget* createDockWidget(const QString& name);
|
KDDockWidgets::Core::DockWidget* createDockWidget(const QString& name);
|
||||||
void retranslateDockWidgets();
|
void updateDockWidgetTitles();
|
||||||
void retranslateDockWidget(KDDockWidgets::Core::DockWidget* dock_widget);
|
|
||||||
void dockWidgetClosed(KDDockWidgets::Core::DockWidget* dock_widget);
|
|
||||||
|
|
||||||
const std::map<QString, QPointer<DebuggerWidget>>& debuggerWidgets();
|
const std::map<QString, QPointer<DebuggerWidget>>& debuggerWidgets();
|
||||||
bool hasDebuggerWidget(QString unique_name);
|
bool hasDebuggerWidget(const QString& unique_name);
|
||||||
void toggleDebuggerWidget(QString unique_name);
|
size_t countDebuggerWidgetsOfType(const char* type);
|
||||||
void recreateDebuggerWidget(QString unique_name);
|
void createDebuggerWidget(const std::string& type);
|
||||||
|
void recreateDebuggerWidget(const QString& unique_name);
|
||||||
|
void destroyDebuggerWidget(const QString& unique_name);
|
||||||
|
void setPrimaryDebuggerWidget(DebuggerWidget* widget, bool is_primary);
|
||||||
|
|
||||||
void deleteFile();
|
void deleteFile();
|
||||||
|
|
||||||
|
@ -111,8 +112,13 @@ private:
|
||||||
DockLayout::LoadResult& result,
|
DockLayout::LoadResult& result,
|
||||||
DockLayout::Index& index_last_session);
|
DockLayout::Index& index_last_session);
|
||||||
|
|
||||||
|
// Make sure there is only a single primary debugger widget of each type.
|
||||||
|
void validatePrimaryDebuggerWidgets();
|
||||||
|
|
||||||
void setupDefaultLayout();
|
void setupDefaultLayout();
|
||||||
|
|
||||||
|
QString generateNewUniqueName(const char* type);
|
||||||
|
|
||||||
// The name displayed in the user interface. Also used to determine the
|
// The name displayed in the user interface. Also used to determine the
|
||||||
// file name for the layout file.
|
// file name for the layout file.
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
@ -124,6 +130,9 @@ private:
|
||||||
// Is this one of the default layouts?
|
// Is this one of the default layouts?
|
||||||
bool m_is_default = false;
|
bool m_is_default = false;
|
||||||
|
|
||||||
|
// A counter used to generate new unique names for dock widgets.
|
||||||
|
int m_next_unique_name = 0;
|
||||||
|
|
||||||
// The name of the default layout which this layout was based on. This will
|
// The name of the default layout which this layout was based on. This will
|
||||||
// be used if the m_geometry variable above is empty.
|
// be used if the m_geometry variable above is empty.
|
||||||
std::string m_base_layout;
|
std::string m_base_layout;
|
||||||
|
@ -145,7 +154,7 @@ private:
|
||||||
// exists exists on disk, or empty if no such file exists.
|
// exists exists on disk, or empty if no such file exists.
|
||||||
std::string m_layout_file_path;
|
std::string m_layout_file_path;
|
||||||
|
|
||||||
// If this layout is the currently selected layout this will be false,
|
// If this layout is the currently selected layout this will be true,
|
||||||
// otherwise it will be true.
|
// otherwise it will be false.
|
||||||
bool m_is_frozen = true;
|
bool m_is_active = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -315,17 +315,119 @@ void DockManager::createWindowsMenu(QMenu* menu)
|
||||||
|
|
||||||
DockLayout& layout = m_layouts.at(m_current_layout);
|
DockLayout& layout = m_layouts.at(m_current_layout);
|
||||||
|
|
||||||
for (const auto& [type, desc] : DockTables::DEBUGGER_WIDGETS)
|
// Create a menu that allows for multiple dock widgets of the same type to
|
||||||
|
// be opened.
|
||||||
|
QMenu* add_another_menu = menu->addMenu(tr("Add Another..."));
|
||||||
|
|
||||||
|
std::vector<DebuggerWidget*> add_another_widgets;
|
||||||
|
std::set<std::string> add_another_types;
|
||||||
|
for (const auto& [unique_name, widget] : layout.debuggerWidgets())
|
||||||
|
{
|
||||||
|
std::string type = widget->metaObject()->className();
|
||||||
|
|
||||||
|
if (widget->supportsMultipleInstances() && !add_another_types.contains(type))
|
||||||
|
{
|
||||||
|
add_another_widgets.emplace_back(widget);
|
||||||
|
add_another_types.emplace(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(add_another_widgets.begin(), add_another_widgets.end(),
|
||||||
|
[](const DebuggerWidget* lhs, const DebuggerWidget* rhs) {
|
||||||
|
if (lhs->displayNameWithoutSuffix() == rhs->displayNameWithoutSuffix())
|
||||||
|
return lhs->displayNameSuffixNumber() < rhs->displayNameSuffixNumber();
|
||||||
|
|
||||||
|
return lhs->displayNameWithoutSuffix() < rhs->displayNameWithoutSuffix();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (DebuggerWidget* widget : add_another_widgets)
|
||||||
|
{
|
||||||
|
const char* type = widget->metaObject()->className();
|
||||||
|
|
||||||
|
const auto description_iterator = DockTables::DEBUGGER_WIDGETS.find(type);
|
||||||
|
pxAssert(description_iterator != DockTables::DEBUGGER_WIDGETS.end());
|
||||||
|
|
||||||
|
QAction* action = add_another_menu->addAction(description_iterator->second.display_name);
|
||||||
|
connect(action, &QAction::triggered, this, [this, type]() {
|
||||||
|
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_layouts.at(m_current_layout).createDebuggerWidget(type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (add_another_widgets.empty())
|
||||||
|
add_another_menu->setDisabled(true);
|
||||||
|
|
||||||
|
menu->addSeparator();
|
||||||
|
|
||||||
|
struct DebuggerWidgetToggle
|
||||||
|
{
|
||||||
|
QString display_name;
|
||||||
|
std::optional<int> suffix_number;
|
||||||
|
QAction* action;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<DebuggerWidgetToggle> toggles;
|
||||||
|
std::set<std::string> toggle_types;
|
||||||
|
|
||||||
|
// Create a menu item for each open debugger widget.
|
||||||
|
for (const auto& [unique_name, widget] : layout.debuggerWidgets())
|
||||||
{
|
{
|
||||||
QAction* action = new QAction(menu);
|
QAction* action = new QAction(menu);
|
||||||
action->setText(QCoreApplication::translate("DebuggerWidget", desc.display_name));
|
action->setText(widget->displayName());
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
action->setChecked(layout.hasDebuggerWidget(type));
|
action->setChecked(true);
|
||||||
connect(action, &QAction::triggered, this, [&layout, type]() {
|
connect(action, &QAction::triggered, this, [this, unique_name]() {
|
||||||
layout.toggleDebuggerWidget(type);
|
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_layouts.at(m_current_layout).destroyDebuggerWidget(unique_name);
|
||||||
});
|
});
|
||||||
menu->addAction(action);
|
|
||||||
|
DebuggerWidgetToggle& toggle = toggles.emplace_back();
|
||||||
|
toggle.display_name = widget->displayNameWithoutSuffix();
|
||||||
|
toggle.suffix_number = widget->displayNameSuffixNumber();
|
||||||
|
toggle.action = action;
|
||||||
|
|
||||||
|
toggle_types.emplace(widget->metaObject()->className());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create menu items to open debugger widgets without any open instances.
|
||||||
|
for (const auto& [type, desc] : DockTables::DEBUGGER_WIDGETS)
|
||||||
|
{
|
||||||
|
if (!toggle_types.contains(type))
|
||||||
|
{
|
||||||
|
QString display_name = QCoreApplication::translate("DebuggerWidget", desc.display_name);
|
||||||
|
|
||||||
|
QAction* action = new QAction(menu);
|
||||||
|
action->setText(display_name);
|
||||||
|
action->setCheckable(true);
|
||||||
|
action->setChecked(false);
|
||||||
|
connect(action, &QAction::triggered, this, [this, type]() {
|
||||||
|
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_layouts.at(m_current_layout).createDebuggerWidget(type);
|
||||||
|
});
|
||||||
|
|
||||||
|
DebuggerWidgetToggle& toggle = toggles.emplace_back();
|
||||||
|
toggle.display_name = display_name;
|
||||||
|
toggle.suffix_number = std::nullopt;
|
||||||
|
toggle.action = action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(toggles.begin(), toggles.end(),
|
||||||
|
[](const DebuggerWidgetToggle& lhs, const DebuggerWidgetToggle& rhs) {
|
||||||
|
if (lhs.display_name == rhs.display_name)
|
||||||
|
return lhs.suffix_number < rhs.suffix_number;
|
||||||
|
|
||||||
|
return lhs.display_name < rhs.display_name;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const DebuggerWidgetToggle& toggle : toggles)
|
||||||
|
menu->addAction(toggle.action);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget* DockManager::createLayoutSwitcher(QWidget* menu_bar)
|
QWidget* DockManager::createLayoutSwitcher(QWidget* menu_bar)
|
||||||
|
@ -564,20 +666,12 @@ bool DockManager::hasNameConflict(const std::string& name, DockLayout::Index lay
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockManager::retranslateDockWidget(KDDockWidgets::Core::DockWidget* dock_widget)
|
void DockManager::updateDockWidgetTitles()
|
||||||
{
|
{
|
||||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_layouts.at(m_current_layout).retranslateDockWidget(dock_widget);
|
m_layouts.at(m_current_layout).updateDockWidgetTitles();
|
||||||
}
|
|
||||||
|
|
||||||
void DockManager::dockWidgetClosed(KDDockWidgets::Core::DockWidget* dock_widget)
|
|
||||||
{
|
|
||||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_layouts.at(m_current_layout).dockWidgetClosed(dock_widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<QString, QPointer<DebuggerWidget>>& DockManager::debuggerWidgets()
|
const std::map<QString, QPointer<DebuggerWidget>>& DockManager::debuggerWidgets()
|
||||||
|
@ -589,7 +683,15 @@ const std::map<QString, QPointer<DebuggerWidget>>& DockManager::debuggerWidgets(
|
||||||
return m_layouts.at(m_current_layout).debuggerWidgets();
|
return m_layouts.at(m_current_layout).debuggerWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockManager::recreateDebuggerWidget(QString unique_name)
|
size_t DockManager::countDebuggerWidgetsOfType(const char* type)
|
||||||
|
{
|
||||||
|
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return m_layouts.at(m_current_layout).countDebuggerWidgetsOfType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockManager::recreateDebuggerWidget(const QString& unique_name)
|
||||||
{
|
{
|
||||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||||
return;
|
return;
|
||||||
|
@ -597,6 +699,22 @@ void DockManager::recreateDebuggerWidget(QString unique_name)
|
||||||
m_layouts.at(m_current_layout).recreateDebuggerWidget(unique_name);
|
m_layouts.at(m_current_layout).recreateDebuggerWidget(unique_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DockManager::destroyDebuggerWidget(const QString& unique_name)
|
||||||
|
{
|
||||||
|
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_layouts.at(m_current_layout).destroyDebuggerWidget(unique_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DockManager::setPrimaryDebuggerWidget(DebuggerWidget* widget, bool is_primary)
|
||||||
|
{
|
||||||
|
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_layouts.at(m_current_layout).setPrimaryDebuggerWidget(widget, is_primary);
|
||||||
|
}
|
||||||
|
|
||||||
void DockManager::switchToDebuggerWidget(DebuggerWidget* widget)
|
void DockManager::switchToDebuggerWidget(DebuggerWidget* widget)
|
||||||
{
|
{
|
||||||
if (m_current_layout == DockLayout::INVALID_INDEX)
|
if (m_current_layout == DockLayout::INVALID_INDEX)
|
||||||
|
@ -613,6 +731,7 @@ void DockManager::switchToDebuggerWidget(DebuggerWidget* widget)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool DockManager::isLayoutLocked()
|
bool DockManager::isLayoutLocked()
|
||||||
{
|
{
|
||||||
return m_layout_locked;
|
return m_layout_locked;
|
||||||
|
|
|
@ -71,11 +71,13 @@ public:
|
||||||
|
|
||||||
bool hasNameConflict(const std::string& name, DockLayout::Index layout_index);
|
bool hasNameConflict(const std::string& name, DockLayout::Index layout_index);
|
||||||
|
|
||||||
void retranslateDockWidget(KDDockWidgets::Core::DockWidget* dock_widget);
|
void updateDockWidgetTitles();
|
||||||
void dockWidgetClosed(KDDockWidgets::Core::DockWidget* dock_widget);
|
|
||||||
|
|
||||||
const std::map<QString, QPointer<DebuggerWidget>>& debuggerWidgets();
|
const std::map<QString, QPointer<DebuggerWidget>>& debuggerWidgets();
|
||||||
void recreateDebuggerWidget(QString unique_name);
|
size_t countDebuggerWidgetsOfType(const char* type);
|
||||||
|
void recreateDebuggerWidget(const QString& unique_name);
|
||||||
|
void destroyDebuggerWidget(const QString& unique_name);
|
||||||
|
void setPrimaryDebuggerWidget(DebuggerWidget* widget, bool is_primary);
|
||||||
void switchToDebuggerWidget(DebuggerWidget* widget);
|
void switchToDebuggerWidget(DebuggerWidget* widget);
|
||||||
|
|
||||||
bool isLayoutLocked();
|
bool isLayoutLocked();
|
||||||
|
|
|
@ -34,7 +34,7 @@ using namespace DockUtils;
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<QString, DockTables::DebuggerWidgetDescription> DockTables::DEBUGGER_WIDGETS = {
|
const std::map<std::string, DockTables::DebuggerWidgetDescription> DockTables::DEBUGGER_WIDGETS = {
|
||||||
DEBUGGER_WIDGET(BreakpointWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Breakpoints"), BOTTOM_MIDDLE),
|
DEBUGGER_WIDGET(BreakpointWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Breakpoints"), BOTTOM_MIDDLE),
|
||||||
DEBUGGER_WIDGET(DisassemblyWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Disassembly"), TOP_RIGHT),
|
DEBUGGER_WIDGET(DisassemblyWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Disassembly"), TOP_RIGHT),
|
||||||
DEBUGGER_WIDGET(FunctionTreeWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Functions"), TOP_LEFT),
|
DEBUGGER_WIDGET(FunctionTreeWidget, QT_TRANSLATE_NOOP("DebuggerWidget", "Functions"), TOP_LEFT),
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace DockTables
|
||||||
DockUtils::PreferredLocation preferred_location;
|
DockUtils::PreferredLocation preferred_location;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const std::map<QString, DebuggerWidgetDescription> DEBUGGER_WIDGETS;
|
extern const std::map<std::string, DebuggerWidgetDescription> DEBUGGER_WIDGETS;
|
||||||
|
|
||||||
enum class DefaultDockGroup
|
enum class DefaultDockGroup
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <kddockwidgets/qtwidgets/DockWidget.h>
|
#include <kddockwidgets/qtwidgets/DockWidget.h>
|
||||||
#include <kddockwidgets/qtwidgets/Group.h>
|
#include <kddockwidgets/qtwidgets/Group.h>
|
||||||
|
|
||||||
DockUtils::DockWidgetPair DockUtils::dockWidgetFromName(QString unique_name)
|
DockUtils::DockWidgetPair DockUtils::dockWidgetFromName(const QString& unique_name)
|
||||||
{
|
{
|
||||||
KDDockWidgets::Vector<QString> names{unique_name};
|
KDDockWidgets::Vector<QString> names{unique_name};
|
||||||
KDDockWidgets::Vector<KDDockWidgets::Core::DockWidget*> dock_widgets =
|
KDDockWidgets::Vector<KDDockWidgets::Core::DockWidget*> dock_widgets =
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace DockUtils
|
||||||
KDDockWidgets::QtWidgets::DockWidget* view = nullptr;
|
KDDockWidgets::QtWidgets::DockWidget* view = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
DockWidgetPair dockWidgetFromName(QString unique_name);
|
DockWidgetPair dockWidgetFromName(const QString& unique_name);
|
||||||
|
|
||||||
enum PreferredLocation
|
enum PreferredLocation
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,9 @@
|
||||||
#include <kddockwidgets/core/TabBar.h>
|
#include <kddockwidgets/core/TabBar.h>
|
||||||
#include <kddockwidgets/qtwidgets/views/DockWidget.h>
|
#include <kddockwidgets/qtwidgets/views/DockWidget.h>
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QtGui/QActionGroup>
|
||||||
|
#include <QtWidgets/QInputDialog>
|
||||||
|
#include <QtWidgets/QMenu>
|
||||||
|
|
||||||
KDDockWidgets::Core::View* DockViewFactory::createDockWidget(
|
KDDockWidgets::Core::View* DockViewFactory::createDockWidget(
|
||||||
const QString& unique_name,
|
const QString& unique_name,
|
||||||
|
@ -58,14 +60,13 @@ DockWidget::DockWidget(
|
||||||
|
|
||||||
void DockWidget::openStateChanged(bool open)
|
void DockWidget::openStateChanged(bool open)
|
||||||
{
|
{
|
||||||
auto view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(sender());
|
// The LayoutSaver class will close a bunch of dock widgets. We only want to
|
||||||
|
// delete the dock widgets when they're being closed by the user.
|
||||||
KDDockWidgets::Core::DockWidget* controller = view->asController<KDDockWidgets::Core::DockWidget>();
|
if (KDDockWidgets::LayoutSaver::restoreInProgress())
|
||||||
if (!controller)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!open && g_debugger_window)
|
if (!open && g_debugger_window)
|
||||||
g_debugger_window->dockManager().dockWidgetClosed(controller);
|
g_debugger_window->dockManager().destroyDebuggerWidget(uniqueName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
@ -115,104 +116,151 @@ DockTabBar::DockTabBar(KDDockWidgets::Core::TabBar* controller, QWidget* parent)
|
||||||
: KDDockWidgets::QtWidgets::TabBar(controller, parent)
|
: KDDockWidgets::QtWidgets::TabBar(controller, parent)
|
||||||
{
|
{
|
||||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(this, &DockTabBar::customContextMenuRequested, this, &DockTabBar::contextMenu);
|
connect(this, &DockTabBar::customContextMenuRequested, this, &DockTabBar::openContextMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockTabBar::contextMenu(QPoint pos)
|
void DockTabBar::openContextMenu(QPoint pos)
|
||||||
{
|
{
|
||||||
auto tab_bar = qobject_cast<KDDockWidgets::QtWidgets::TabBar*>(sender());
|
if (!g_debugger_window)
|
||||||
int tab_index = tab_bar->tabAt(pos);
|
|
||||||
|
|
||||||
// Filter out the placeholder widget displayed when there are no layouts.
|
|
||||||
if (!hasDebuggerWidget(tab_index))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QMenu* menu = new QMenu(tr("Dock Widget Menu"), tab_bar);
|
int tab_index = tabAt(pos);
|
||||||
|
|
||||||
|
// Filter out the placeholder widget displayed when there are no layouts.
|
||||||
|
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||||
|
if (!widget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t dock_widgets_of_type = g_debugger_window->dockManager().countDebuggerWidgetsOfType(
|
||||||
|
widget->metaObject()->className());
|
||||||
|
|
||||||
|
QMenu* menu = new QMenu(tr("Dock Widget Context Menu"), this);
|
||||||
|
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
QAction* rename_action = menu->addAction(tr("Rename"));
|
||||||
|
connect(rename_action, &QAction::triggered, this, [this, tab_index]() {
|
||||||
|
if (!g_debugger_window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||||
|
if (!widget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
QString new_name = QInputDialog::getText(
|
||||||
|
this, tr("Rename Window"), tr("New name:"), QLineEdit::Normal, widget->displayNameWithoutSuffix(), &ok);
|
||||||
|
if (!ok)
|
||||||
|
return;
|
||||||
|
|
||||||
|
widget->setCustomDisplayName(new_name);
|
||||||
|
g_debugger_window->dockManager().updateDockWidgetTitles();
|
||||||
|
});
|
||||||
|
|
||||||
|
QAction* reset_name_action = menu->addAction(tr("Reset Name"));
|
||||||
|
reset_name_action->setEnabled(!widget->customDisplayName().isEmpty());
|
||||||
|
connect(reset_name_action, &QAction::triggered, this, [this, tab_index] {
|
||||||
|
if (!g_debugger_window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||||
|
if (!widget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
widget->setCustomDisplayName(QString());
|
||||||
|
g_debugger_window->dockManager().updateDockWidgetTitles();
|
||||||
|
});
|
||||||
|
|
||||||
|
QAction* primary_action = menu->addAction(tr("Primary"));
|
||||||
|
primary_action->setCheckable(true);
|
||||||
|
primary_action->setChecked(widget->isPrimary());
|
||||||
|
primary_action->setEnabled(dock_widgets_of_type > 1);
|
||||||
|
connect(primary_action, &QAction::triggered, this, [this, tab_index](bool checked) {
|
||||||
|
if (!g_debugger_window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||||
|
if (!widget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_debugger_window->dockManager().setPrimaryDebuggerWidget(widget, checked);
|
||||||
|
});
|
||||||
|
|
||||||
QMenu* set_target_menu = menu->addMenu(tr("Set Target"));
|
QMenu* set_target_menu = menu->addMenu(tr("Set Target"));
|
||||||
|
QActionGroup* set_target_group = new QActionGroup(menu);
|
||||||
|
set_target_group->setExclusive(true);
|
||||||
|
|
||||||
for (BreakPointCpu cpu : DEBUG_CPUS)
|
for (BreakPointCpu cpu : DEBUG_CPUS)
|
||||||
{
|
{
|
||||||
const char* long_cpu_name = DebugInterface::longCpuName(cpu);
|
const char* long_cpu_name = DebugInterface::longCpuName(cpu);
|
||||||
const char* cpu_name = DebugInterface::cpuName(cpu);
|
const char* cpu_name = DebugInterface::cpuName(cpu);
|
||||||
QString text = QString("%1 (%2)").arg(long_cpu_name).arg(cpu_name);
|
QString text = QString("%1 (%2)").arg(long_cpu_name).arg(cpu_name);
|
||||||
QAction* action = new QAction(text, menu);
|
|
||||||
connect(action, &QAction::triggered, this, [tab_bar, tab_index, cpu]() {
|
|
||||||
KDDockWidgets::Core::TabBar* tab_bar_controller = tab_bar->asController<KDDockWidgets::Core::TabBar>();
|
|
||||||
if (!tab_bar_controller)
|
|
||||||
return;
|
|
||||||
|
|
||||||
KDDockWidgets::Core::DockWidget* dock_controller = tab_bar_controller->dockWidgetAt(tab_index);
|
QAction* cpu_action = set_target_menu->addAction(text);
|
||||||
if (!dock_controller)
|
cpu_action->setCheckable(true);
|
||||||
return;
|
cpu_action->setChecked(widget->cpuOverride().has_value() && *widget->cpuOverride() == cpu);
|
||||||
|
connect(cpu_action, &QAction::triggered, this, [this, tab_index, cpu]() {
|
||||||
KDDockWidgets::QtWidgets::DockWidget* dock_view =
|
setCpuOverrideForTab(tab_index, cpu);
|
||||||
static_cast<KDDockWidgets::QtWidgets::DockWidget*>(dock_controller->view());
|
|
||||||
|
|
||||||
DebuggerWidget* widget = qobject_cast<DebuggerWidget*>(dock_view->widget());
|
|
||||||
if (!widget)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!g_debugger_window)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!widget->setCpuOverride(cpu))
|
|
||||||
g_debugger_window->dockManager().recreateDebuggerWidget(dock_view->uniqueName());
|
|
||||||
|
|
||||||
g_debugger_window->dockManager().retranslateDockWidget(dock_controller);
|
|
||||||
});
|
});
|
||||||
set_target_menu->addAction(action);
|
set_target_group->addAction(cpu_action);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_target_menu->addSeparator();
|
set_target_menu->addSeparator();
|
||||||
|
|
||||||
QAction* inherit_action = new QAction(tr("Inherit From Layout"), menu);
|
QAction* inherit_action = set_target_menu->addAction(tr("Inherit From Layout"));
|
||||||
connect(inherit_action, &QAction::triggered, this, [tab_bar, tab_index]() {
|
inherit_action->setCheckable(true);
|
||||||
KDDockWidgets::Core::TabBar* tab_bar_controller = tab_bar->asController<KDDockWidgets::Core::TabBar>();
|
inherit_action->setChecked(!widget->cpuOverride().has_value());
|
||||||
if (!tab_bar_controller)
|
connect(inherit_action, &QAction::triggered, this, [this, tab_index]() {
|
||||||
return;
|
setCpuOverrideForTab(tab_index, std::nullopt);
|
||||||
|
});
|
||||||
KDDockWidgets::Core::DockWidget* dock_controller = tab_bar_controller->dockWidgetAt(tab_index);
|
set_target_group->addAction(inherit_action);
|
||||||
if (!dock_controller)
|
|
||||||
return;
|
|
||||||
|
|
||||||
KDDockWidgets::QtWidgets::DockWidget* dock_view =
|
|
||||||
static_cast<KDDockWidgets::QtWidgets::DockWidget*>(dock_controller->view());
|
|
||||||
|
|
||||||
DebuggerWidget* widget = qobject_cast<DebuggerWidget*>(dock_view->widget());
|
|
||||||
if (!widget)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
QAction* close_action = menu->addAction(tr("Close"));
|
||||||
|
connect(close_action, &QAction::triggered, this, [this, tab_index]() {
|
||||||
if (!g_debugger_window)
|
if (!g_debugger_window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!widget->setCpuOverride(std::nullopt))
|
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||||
g_debugger_window->dockManager().recreateDebuggerWidget(dock_view->uniqueName());
|
if (!widget)
|
||||||
|
return;
|
||||||
|
|
||||||
g_debugger_window->dockManager().retranslateDockWidget(dock_controller);
|
g_debugger_window->dockManager().destroyDebuggerWidget(widget->uniqueName());
|
||||||
});
|
});
|
||||||
set_target_menu->addAction(inherit_action);
|
|
||||||
|
|
||||||
menu->popup(tab_bar->mapToGlobal(pos));
|
menu->popup(mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockTabBar::hasDebuggerWidget(int tab_index)
|
void DockTabBar::setCpuOverrideForTab(int tab_index, std::optional<BreakPointCpu> cpu_override)
|
||||||
|
{
|
||||||
|
if (!g_debugger_window)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto [widget, controller, view] = widgetsFromTabIndex(tab_index);
|
||||||
|
if (!widget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!widget->setCpuOverride(cpu_override))
|
||||||
|
g_debugger_window->dockManager().recreateDebuggerWidget(view->uniqueName());
|
||||||
|
|
||||||
|
g_debugger_window->dockManager().updateDockWidgetTitles();
|
||||||
|
}
|
||||||
|
|
||||||
|
DockTabBar::WidgetsFromTabIndexResult DockTabBar::widgetsFromTabIndex(int tab_index)
|
||||||
{
|
{
|
||||||
KDDockWidgets::Core::TabBar* tab_bar_controller = asController<KDDockWidgets::Core::TabBar>();
|
KDDockWidgets::Core::TabBar* tab_bar_controller = asController<KDDockWidgets::Core::TabBar>();
|
||||||
if (!tab_bar_controller)
|
if (!tab_bar_controller)
|
||||||
return false;
|
return {};
|
||||||
|
|
||||||
KDDockWidgets::Core::DockWidget* dock_controller = tab_bar_controller->dockWidgetAt(tab_index);
|
KDDockWidgets::Core::DockWidget* dock_controller = tab_bar_controller->dockWidgetAt(tab_index);
|
||||||
if (!dock_controller)
|
if (!dock_controller)
|
||||||
return false;
|
return {};
|
||||||
|
|
||||||
auto dock_view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(dock_controller->view());
|
auto dock_view = static_cast<KDDockWidgets::QtWidgets::DockWidget*>(dock_controller->view());
|
||||||
|
|
||||||
DebuggerWidget* widget = qobject_cast<DebuggerWidget*>(dock_view->widget());
|
DebuggerWidget* widget = qobject_cast<DebuggerWidget*>(dock_view->widget());
|
||||||
if (!widget)
|
if (!widget)
|
||||||
return false;
|
return {};
|
||||||
|
|
||||||
return true;
|
return {widget, dock_controller, dock_view};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockTabBar::mouseDoubleClickEvent(QMouseEvent* ev)
|
void DockTabBar::mouseDoubleClickEvent(QMouseEvent* ev)
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
#include <kddockwidgets/qtwidgets/views/TitleBar.h>
|
#include <kddockwidgets/qtwidgets/views/TitleBar.h>
|
||||||
#include <kddockwidgets/qtwidgets/views/TabBar.h>
|
#include <kddockwidgets/qtwidgets/views/TabBar.h>
|
||||||
|
|
||||||
|
#include "DebugTools/DebugInterface.h"
|
||||||
|
|
||||||
|
class DebuggerWidget;
|
||||||
class DockManager;
|
class DockManager;
|
||||||
|
|
||||||
class DockViewFactory : public KDDockWidgets::QtWidgets::ViewFactory
|
class DockViewFactory : public KDDockWidgets::QtWidgets::ViewFactory
|
||||||
|
@ -82,8 +85,17 @@ public:
|
||||||
DockTabBar(KDDockWidgets::Core::TabBar* controller, QWidget* parent = nullptr);
|
DockTabBar(KDDockWidgets::Core::TabBar* controller, QWidget* parent = nullptr);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void contextMenu(QPoint pos);
|
void openContextMenu(QPoint pos);
|
||||||
bool hasDebuggerWidget(int tab_index);
|
|
||||||
|
struct WidgetsFromTabIndexResult
|
||||||
|
{
|
||||||
|
DebuggerWidget* debugger_widget = nullptr;
|
||||||
|
KDDockWidgets::Core::DockWidget* controller = nullptr;
|
||||||
|
KDDockWidgets::QtWidgets::DockWidget* view = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
void setCpuOverrideForTab(int tab_index, std::optional<BreakPointCpu> cpu_override);
|
||||||
|
WidgetsFromTabIndexResult widgetsFromTabIndex(int tab_index);
|
||||||
|
|
||||||
void mouseDoubleClickEvent(QMouseEvent* ev) override;
|
void mouseDoubleClickEvent(QMouseEvent* ev) override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,7 +24,7 @@ using SearchResult = MemorySearchWidget::SearchResult;
|
||||||
using namespace QtUtils;
|
using namespace QtUtils;
|
||||||
|
|
||||||
MemorySearchWidget::MemorySearchWidget(const DebuggerWidgetParameters& parameters)
|
MemorySearchWidget::MemorySearchWidget(const DebuggerWidgetParameters& parameters)
|
||||||
: DebuggerWidget(parameters)
|
: DebuggerWidget(parameters, NO_DEBUGGER_FLAGS)
|
||||||
{
|
{
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
this->repaint();
|
this->repaint();
|
||||||
|
|
|
@ -452,7 +452,7 @@ bool MemoryViewTable::KeyPress(int key, QChar keychar, DebugInterface& cpu)
|
||||||
MemoryViewWidget
|
MemoryViewWidget
|
||||||
*/
|
*/
|
||||||
MemoryViewWidget::MemoryViewWidget(const DebuggerWidgetParameters& parameters)
|
MemoryViewWidget::MemoryViewWidget(const DebuggerWidgetParameters& parameters)
|
||||||
: DebuggerWidget(parameters)
|
: DebuggerWidget(parameters, NO_DEBUGGER_FLAGS)
|
||||||
, m_table(this)
|
, m_table(this)
|
||||||
{
|
{
|
||||||
ui.setupUi(this);
|
ui.setupUi(this);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include <QtWidgets/QMenu>
|
#include <QtWidgets/QMenu>
|
||||||
|
|
||||||
SavedAddressesWidget::SavedAddressesWidget(const DebuggerWidgetParameters& parameters)
|
SavedAddressesWidget::SavedAddressesWidget(const DebuggerWidgetParameters& parameters)
|
||||||
: DebuggerWidget(parameters)
|
: DebuggerWidget(parameters, DISALLOW_MULTIPLE_INSTANCES)
|
||||||
, m_model(new SavedAddressesModel(cpu(), this))
|
, m_model(new SavedAddressesModel(cpu(), this))
|
||||||
{
|
{
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
using namespace QtUtils;
|
using namespace QtUtils;
|
||||||
|
|
||||||
RegisterWidget::RegisterWidget(const DebuggerWidgetParameters& parameters)
|
RegisterWidget::RegisterWidget(const DebuggerWidgetParameters& parameters)
|
||||||
: DebuggerWidget(parameters)
|
: DebuggerWidget(parameters, NO_DEBUGGER_FLAGS)
|
||||||
{
|
{
|
||||||
this->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
|
this->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <QtWidgets/QMenu>
|
#include <QtWidgets/QMenu>
|
||||||
|
|
||||||
StackWidget::StackWidget(const DebuggerWidgetParameters& parameters)
|
StackWidget::StackWidget(const DebuggerWidgetParameters& parameters)
|
||||||
: DebuggerWidget(parameters)
|
: DebuggerWidget(parameters, NO_DEBUGGER_FLAGS)
|
||||||
, m_model(new StackModel(cpu()))
|
, m_model(new StackModel(cpu()))
|
||||||
{
|
{
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
|
@ -18,7 +18,7 @@ SymbolTreeWidget::SymbolTreeWidget(
|
||||||
u32 flags,
|
u32 flags,
|
||||||
s32 symbol_address_alignment,
|
s32 symbol_address_alignment,
|
||||||
const DebuggerWidgetParameters& parameters)
|
const DebuggerWidgetParameters& parameters)
|
||||||
: DebuggerWidget(parameters)
|
: DebuggerWidget(parameters, NO_DEBUGGER_FLAGS)
|
||||||
, m_flags(flags)
|
, m_flags(flags)
|
||||||
, m_symbol_address_alignment(symbol_address_alignment)
|
, m_symbol_address_alignment(symbol_address_alignment)
|
||||||
, m_group_by_module(cpu().getCpuType() == BREAKPOINT_IOP)
|
, m_group_by_module(cpu().getCpuType() == BREAKPOINT_IOP)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <QtWidgets/QMenu>
|
#include <QtWidgets/QMenu>
|
||||||
|
|
||||||
ThreadWidget::ThreadWidget(const DebuggerWidgetParameters& parameters)
|
ThreadWidget::ThreadWidget(const DebuggerWidgetParameters& parameters)
|
||||||
: DebuggerWidget(parameters)
|
: DebuggerWidget(parameters, NO_DEBUGGER_FLAGS)
|
||||||
, m_model(new ThreadModel(cpu()))
|
, m_model(new ThreadModel(cpu()))
|
||||||
, m_proxy_model(new QSortFilterProxyModel())
|
, m_proxy_model(new QSortFilterProxyModel())
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,7 +33,7 @@ enum BreakPointCpu
|
||||||
BREAKPOINT_IOP_AND_EE = 0x03
|
BREAKPOINT_IOP_AND_EE = 0x03
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::vector<BreakPointCpu> DEBUG_CPUS = {
|
inline const std::array<BreakPointCpu, 2> DEBUG_CPUS = {
|
||||||
BREAKPOINT_EE,
|
BREAKPOINT_EE,
|
||||||
BREAKPOINT_IOP,
|
BREAKPOINT_IOP,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue