mirror of
https://github.com/dolphin-emu/fifoplayer.git
synced 2026-01-31 01:05:16 +01:00
437 lines
16 KiB
C++
437 lines
16 KiB
C++
#include <QLabel>
|
|
#include <QSpinBox>
|
|
#include <QModelIndex>
|
|
#include <QItemSelectionModel>
|
|
#include "command_info.h"
|
|
|
|
#include "client.h" // just for DffModel::UserRoles...
|
|
#include <QDebug>
|
|
|
|
#include "../source/OpcodeDecoding.h"
|
|
#include "../source/BPMemory.h"
|
|
|
|
LinkedSpinBox::LinkedSpinBox(const BitFieldWrapper& bitfield) : QSpinBox(), bitfield(bitfield)
|
|
{
|
|
setMinimum(0);
|
|
setMaximum(bitfield.MaxVal());
|
|
setValue(bitfield);
|
|
|
|
connect(this, SIGNAL(valueChanged(int)), this, SLOT(OnValueChanged(int)));
|
|
}
|
|
|
|
void LinkedSpinBox::OnValueChanged(int value)
|
|
{
|
|
bitfield = value;
|
|
emit ValueChanged(bitfield.RawValue());
|
|
}
|
|
|
|
LinkedCheckBox::LinkedCheckBox(const QString& str, const BitFieldWrapper& bitfield) : QCheckBox(str), bitfield(bitfield)
|
|
{
|
|
// assert(bitfield.NumBits() == 1);//TODO: Enable!
|
|
|
|
setCheckState((bitfield != 0) ? Qt::Checked : Qt::Unchecked);
|
|
|
|
connect(this, SIGNAL(stateChanged(int)), this, SLOT(OnStateChanged(int)));
|
|
}
|
|
|
|
void LinkedCheckBox::OnStateChanged(int state)
|
|
{
|
|
bitfield = (state == Qt::Checked) ? 1 : 0;
|
|
emit HexChanged(bitfield.RawValue());
|
|
}
|
|
|
|
LinkedLineEdit::LinkedLineEdit(const BitFieldWrapper& bitfield) : QLineEdit(), bitfield(bitfield)
|
|
{
|
|
setText(QString("%1").arg(bitfield, (bitfield.NumBits()+7)/8, 16, QLatin1Char('0')));
|
|
|
|
connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(OnTextChanged(const QString&)));
|
|
}
|
|
|
|
void LinkedLineEdit::OnTextChanged(const QString& str)
|
|
{
|
|
bool ok = false;
|
|
uint ret = str.toUInt(&ok, 16);
|
|
if (ok == ret) {
|
|
bitfield = ret;
|
|
emit HexChanged(bitfield.RawValue());
|
|
}
|
|
else {
|
|
qDebug() << "Failed to convert " << str << "to UInt!";
|
|
}
|
|
}
|
|
|
|
LinkedComboBox::LinkedComboBox(const BitFieldWrapper& bitfield, const QStringList& elements) : QComboBox(), bitfield(bitfield)
|
|
{
|
|
// assert(elements.size() == bitfield.MaxVal()); TODO!
|
|
|
|
addItems(elements);
|
|
|
|
setCurrentIndex(bitfield);
|
|
|
|
connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(OnCurrentIndexChanged(int)));
|
|
}
|
|
|
|
void LinkedComboBox::OnCurrentIndexChanged(int index)
|
|
{
|
|
bitfield = index;
|
|
emit HexChanged(bitfield.RawValue());
|
|
}
|
|
|
|
|
|
template<u32 bitfield_position, u32 bitfield_size>
|
|
LayoutStream& LayoutStream::AddSpinBox(BitField<bitfield_position, bitfield_size>& bitfield)
|
|
{
|
|
LinkedSpinBox* widget = new LinkedSpinBox(BitFieldWrapper(bitfield));
|
|
|
|
connect(widget, SIGNAL(ValueChanged(u32)), this, SLOT(OnFifoDataChanged()));
|
|
|
|
cur_hlayout->addWidget(widget);
|
|
return *this;
|
|
}
|
|
|
|
template<u32 BFPos, u32 BFSize>
|
|
LayoutStream& LayoutStream::AddCheckBox(BitField<BFPos, BFSize>& bitfield, const QString& str)
|
|
{
|
|
LinkedCheckBox* widget = new LinkedCheckBox(str, BitFieldWrapper(bitfield));
|
|
|
|
connect(widget, SIGNAL(HexChanged(u32)), this, SLOT(OnFifoDataChanged()));
|
|
|
|
cur_hlayout->addWidget(widget);
|
|
return *this;
|
|
}
|
|
|
|
template<u32 BFPos, u32 BFSize>
|
|
LayoutStream& LayoutStream::AddLineEdit(BitField<BFPos, BFSize>& bitfield)
|
|
{
|
|
LinkedLineEdit* widget = new LinkedLineEdit(BitFieldWrapper(bitfield));
|
|
|
|
connect(widget, SIGNAL(HexChanged(u32)), this, SLOT(OnFifoDataChanged()));
|
|
|
|
cur_hlayout->addWidget(widget);
|
|
return *this;
|
|
}
|
|
|
|
template<u32 BFPos, u32 BFSize>
|
|
LayoutStream& LayoutStream::AddComboBox(BitField<BFPos, BFSize>& bitfield, const QStringList& elements)
|
|
{
|
|
LinkedComboBox* widget = new LinkedComboBox(BitFieldWrapper(bitfield), elements);
|
|
|
|
connect(widget, SIGNAL(HexChanged(u32)), this, SLOT(OnFifoDataChanged()));
|
|
|
|
cur_hlayout->addWidget(widget);
|
|
return *this;
|
|
}
|
|
|
|
LayoutStream& LayoutStream::AddLabel(const QString& str)
|
|
{
|
|
cur_hlayout->addWidget(new QLabel(str));
|
|
return *this;
|
|
}
|
|
|
|
LayoutStream& LayoutStream::endl()
|
|
{
|
|
cur_hlayout = new QHBoxLayout;
|
|
addLayout(cur_hlayout);
|
|
return *this;
|
|
}
|
|
|
|
void LayoutStream::ActiveItemChanged(const QModelIndex& index)
|
|
{
|
|
Clear();
|
|
|
|
const QAbstractItemModel* sender = ((QItemSelectionModel*)QObject::sender())->model();
|
|
if (sender->data(index, DffModel::UserRole_Type) != DffModel::IDX_COMMAND)
|
|
return;
|
|
|
|
current_index = index;
|
|
dff_model = (QAbstractItemModel*)sender; // TODO: not const-correct...
|
|
|
|
u32 cmd_start = sender->data(index, DffModel::UserRole_CmdStart).toUInt();
|
|
cur_fifo_data.clear();
|
|
cur_fifo_data.append(sender->data(index, DffModel::UserRole_FifoData).toByteArray()); // TODO: Only retrieve this on dataChanged()...
|
|
u8* fifo_data = (u8*)cur_fifo_data.data();
|
|
|
|
if (fifo_data[cmd_start] == GX_LOAD_BP_REG)
|
|
{
|
|
u32& cmddata = (*(u32*)&fifo_data[cmd_start+1]);
|
|
edit_offset = cmd_start+1;
|
|
edit_size = sizeof(u32);
|
|
|
|
#define GET(type, name) type& name = *(type*)&cmddata
|
|
|
|
if (fifo_data[cmd_start+1] == BPMEM_GENMODE) // 0x00
|
|
{
|
|
GET(GenMode, mode);
|
|
|
|
AddLabel(tr("Gen mode")).endl();
|
|
AddLabel(tr("numtexgens: ")).AddSpinBox(mode.numtexgens).endl();
|
|
AddLabel(tr("numcolchans: ")).AddSpinBox(mode.numcolchans).endl();
|
|
AddCheckBox(mode.ms_en, tr("Enable multisampling")).endl();
|
|
AddLabel(tr("numtexstages: ")).AddSpinBox(mode.numtexstages).endl();
|
|
AddLabel(tr("Culling: ")).AddComboBox(mode.cullmode, {tr("Disabled"), tr("Cull front facing"), tr("Cull back facing"), tr("Cull everything") }).endl();
|
|
AddLabel(tr("numindstages: ")).AddSpinBox(mode.numindstages).endl();
|
|
AddCheckBox(mode.zfreeze, tr("Enable zfreeze")).endl();
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_SCISSORTL) // 0x20
|
|
{
|
|
GET(X12Y12, coord);
|
|
AddLabel(tr("Scissor rectangle")).endl();
|
|
AddLabel(tr("Left coordinate:")).AddSpinBox(coord.x).endl();
|
|
AddLabel(tr("Top coordinate:")).AddSpinBox(coord.y).endl();
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_SCISSORBR) // 0x21
|
|
{
|
|
GET(X12Y12, coord);
|
|
AddLabel(tr("Scissor rectangle")).endl();
|
|
AddLabel(tr("Right coordinate:")).AddSpinBox(coord.x).endl();
|
|
AddLabel(tr("Bottom coordinate:")).AddSpinBox(coord.y).endl();
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_ZMODE) // 0x40
|
|
{
|
|
ZMode& zmode = *(ZMode*)&cmddata;
|
|
|
|
AddLabel(tr("BPMEM_ZMODE")).endl();
|
|
AddCheckBox(zmode.testenable, tr("Enable depth testing")).endl();
|
|
AddLabel(tr("Depth test function: ")).AddComboBox(zmode.func, {tr("Never"), tr("Less"), tr("Equal"),
|
|
tr("Less or equal"), tr("Greater"), tr("Not equal"),
|
|
tr("Greater or equal"), tr("Always")}).endl();
|
|
AddCheckBox(zmode.updateenable, tr("Enable depth writing")).endl();
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_BLENDMODE) // 0x41
|
|
{
|
|
BlendMode& mode = *(BlendMode*)&cmddata;
|
|
|
|
QStringList dstfactors = {
|
|
tr("Zero"), tr("One"), tr("SRCCOL"), tr("1-SRCCOL"),
|
|
tr("SRCALP"), tr("1-SRCALP"), tr("DSTALP"), tr("1-DSTALP")
|
|
};
|
|
QStringList srcfactors = {
|
|
tr("Zero"), tr("One"), tr("DSTCOL"), tr("1-DSTCOL"),
|
|
tr("SRCALP"), tr("1-SRCALP"), tr("DSTALP"), tr("1-DSTALP")
|
|
};
|
|
QStringList logicmodes = {
|
|
"0", "s & d", "s & ~d", "s",
|
|
"~s & d", "d", "s ^ d", "s | d",
|
|
"~(s | d)", "~(s ^ d)", "~d", "s | ~d",
|
|
"~s", "~s | d", "~(s & d)", "1"
|
|
};
|
|
|
|
AddLabel(tr("BPMEM_BLENDMODE")).endl();
|
|
AddCheckBox(mode.blendenable, tr("Enable blending")).endl();
|
|
AddComboBox(mode.dstfactor, dstfactors).endl();
|
|
AddComboBox(mode.srcfactor, srcfactors).endl();
|
|
AddCheckBox(mode.subtract, tr("Subtract")).endl();
|
|
AddCheckBox(mode.logicopenable, tr("Enable logical operations")).endl();
|
|
AddLabel(tr("Logic operation: ")).AddComboBox(mode.logicmode, logicmodes).endl();
|
|
AddCheckBox(mode.colorupdate, tr("Enable color writing")).endl();
|
|
AddCheckBox(mode.alphaupdate, tr("Enable alpha writing")).endl();
|
|
AddCheckBox(mode.dither, tr("Enable dithering")).endl();
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_ZCOMPARE) // 0x43
|
|
{
|
|
GET(PE_CONTROL, ctrl);
|
|
|
|
AddLabel(tr("Pixel Engine control")).endl();
|
|
AddLabel(tr("EFB pixel format: ")).AddComboBox(ctrl.pixel_format, {"RGB8 Z24", "RGBA6 Z24", "RGB565 Z16", "Z24", "Y8", "U8", "V8", "YUV420"}).endl();
|
|
AddLabel(tr("EFB depth format: ")).AddComboBox(ctrl.zformat, {tr("Linear"), tr("Near"), tr("Mid"), tr("Far"), tr("Inverse near"), tr("Inverse mid"), tr("Inverse far")}).endl();
|
|
AddCheckBox(ctrl.early_ztest, tr("Early depth test")).endl();
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_TRIGGER_EFB_COPY) // 0x52
|
|
{
|
|
UPE_Copy& copy = *(UPE_Copy*)&cmddata;
|
|
|
|
AddLabel(tr("BPMEM_TRIGGER_EFB_COPY")).endl();
|
|
AddLabel(tr("Clamping: ")).AddCheckBox(copy.clamp0, tr("Top")).AddCheckBox(copy.clamp1, tr("Bottom")).endl();
|
|
AddLabel(tr("Convert from RGB to YUV: ")).AddCheckBox(copy.yuv).endl();
|
|
AddLabel(tr("Target pixel format: ")).AddComboBox(copy.target_pixel_format,
|
|
{"Z4/I4/R4", "Z8/I8/R8", "IA4/RA4", "Z16/IA8/RA8",
|
|
"RGB565", "RGB5A3", "Z24X8/RGBA8", "A8",
|
|
"Z8/I8/R8", "Z8M/G8", "Z8L/B8"", Z16Rev/RG8",
|
|
"Z16L/GB8", "", "", "" }).endl();
|
|
AddLabel(tr("Gamma correction: ")).AddComboBox(copy.gamma, {"1.0","1.7","2.2","Inv." }).endl();
|
|
AddLabel(tr("Downscale: ")).AddCheckBox(copy.half_scale).endl();
|
|
AddLabel(tr("Vertical scaling: ")).AddCheckBox(copy.scale_invert).endl();
|
|
AddLabel(tr("Clear: ")).AddCheckBox(copy.clear).endl();
|
|
AddLabel(tr("Copy to XFB: ")).AddCheckBox(copy.frame_to_field).endl();
|
|
AddLabel(tr("Copy as intensity: ")).AddCheckBox(copy.intensity_fmt).endl();
|
|
AddLabel(tr("Automatic color conversion: ")).AddCheckBox(copy.auto_conv).endl();
|
|
}
|
|
else if (fifo_data[cmd_start+1] >= BPMEM_TEV_COLOR_ENV &&
|
|
fifo_data[cmd_start+1] <= BPMEM_TEV_ALPHA_ENV + 2*15) // 0xC0 - 0xDF
|
|
{
|
|
int stage = (fifo_data[cmd_start+1] - BPMEM_TEV_COLOR_ENV) / 2;
|
|
|
|
QStringList bias_values = { tr("0"), tr("+0.5"), tr("-0.5"), tr("Use compare function") };
|
|
QStringList shift_values = { "1.0", "2.0", "4.0", "0.5" };
|
|
QStringList outputs = { "PREV", "REG0", "REG1", "REG2"};
|
|
QStringList operations = { tr("Add"), tr("Subtract")};
|
|
QStringList compare_functions = {"Greater", "Equal"};
|
|
|
|
if ((fifo_data[cmd_start+1] & 1) == 0)
|
|
{
|
|
GET(TevStageCombiner::ColorCombiner, comb);
|
|
|
|
QStringList inputs = {
|
|
tr("PREV color"), tr("PREV alpha"), tr("REG0 color"), tr("REG0 alpha"),
|
|
tr("REG1 color"), tr("REG1 alpha"), tr("REG2 color"), tr("REG2 alpha"),
|
|
tr("Texture color"), tr("Texture alpha"), tr("Rasterized color"), tr("Rasterized alpha"),
|
|
tr("1"), tr("0.5"), tr("Konst color"), tr("0")
|
|
};
|
|
|
|
AddLabel(tr("Color combiner for Tev stage %1").arg(stage)).endl();
|
|
AddLabel(tr("Input A: ")).AddComboBox(comb.a, inputs).endl();
|
|
AddLabel(tr("Input B: ")).AddComboBox(comb.b, inputs).endl();
|
|
AddLabel(tr("Input C: ")).AddComboBox(comb.c, inputs).endl();
|
|
AddLabel(tr("Input D: ")).AddComboBox(comb.d, inputs).endl();
|
|
|
|
AddLabel(tr("Bias: ")).AddComboBox(comb.bias, bias_values).endl();
|
|
AddLabel(tr("Operation: ")).AddComboBox(comb.op, operations).endl();
|
|
AddCheckBox(comb.clamp, tr("Clamp")).endl();
|
|
AddLabel(tr("Scale: ")).AddComboBox(comb.shift, shift_values).endl();
|
|
|
|
AddLabel(tr("Destination: ")).AddComboBox(comb.dest, outputs).endl();
|
|
|
|
// TODO: Changing these does not update the upper ones!!
|
|
AddLabel(tr("Compare operation: ")).AddComboBox(comb.op, compare_functions).endl();
|
|
AddLabel(tr("Compared components: ")).AddComboBox(comb.shift, {"R", "GR", "BGR", "RGB per-channel"}).endl();
|
|
}
|
|
else
|
|
{
|
|
GET(TevStageCombiner::AlphaCombiner, comb);
|
|
|
|
QStringList inputs = {
|
|
tr("PREV"), tr("REG0"), tr("REG1"), tr("REG2"),
|
|
tr("Texture"), tr("Rasterizer"), tr("Konst"), tr("0")
|
|
};
|
|
|
|
AddLabel(tr("Alpha combiner for Tev stage %1").arg(stage)).endl();
|
|
AddLabel(tr("Input A: ")).AddComboBox(comb.a, inputs).endl();
|
|
AddLabel(tr("Input B: ")).AddComboBox(comb.b, inputs).endl();
|
|
AddLabel(tr("Input C: ")).AddComboBox(comb.c, inputs).endl();
|
|
AddLabel(tr("Input D: ")).AddComboBox(comb.d, inputs).endl();
|
|
|
|
AddLabel(tr("Bias: ")).AddComboBox(comb.bias, bias_values).endl();
|
|
AddLabel(tr("Operation: ")).AddComboBox(comb.op, operations).endl();
|
|
AddCheckBox(comb.clamp, tr("Clamp")).endl();
|
|
AddLabel(tr("Scale: ")).AddComboBox(comb.shift, shift_values).endl();
|
|
|
|
AddLabel(tr("Destination: ")).AddComboBox(comb.dest, outputs).endl();
|
|
|
|
// TODO: Changing these does not update the upper ones!!
|
|
AddLabel(tr("Compare operation: ")).AddComboBox(comb.op, compare_functions).endl();
|
|
AddLabel(tr("Compared components: ")).AddComboBox(comb.shift, {"R", "GR", "BGR", "A"}).endl();
|
|
|
|
AddLabel(tr("Rasterized input swap: ")).AddSpinBox(comb.rswap).endl();
|
|
AddLabel(tr("Texture input swap: ")).AddSpinBox(comb.tswap).endl();
|
|
}
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_FOGRANGE) // 0xE8
|
|
{
|
|
GET(FogRangeParams::RangeBase, range);
|
|
|
|
AddLabel(tr("Fog range adjustment")).endl();
|
|
AddCheckBox(range.Enabled, tr("Enable")).endl();
|
|
AddLabel(tr("Center: ")).AddSpinBox(range.Center).endl();
|
|
}
|
|
else if (fifo_data[cmd_start+1] >= BPMEM_FOGRANGE + 1 &&
|
|
fifo_data[cmd_start+1] <= BPMEM_FOGRANGE + 5) // 0xE9 - 0xED
|
|
{
|
|
GET(FogRangeKElement, range);
|
|
|
|
AddLabel(tr("Fog range adjustment factor group %1").arg(fifo_data[cmd_start+1]-BPMEM_FOGRANGE)).endl();
|
|
AddLabel(tr("Factor HI: ")).AddSpinBox(range.HI).endl();
|
|
AddLabel(tr("Factor LO: ")).AddSpinBox(range.LO).endl();
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_FOGPARAM0) // 0xEE
|
|
{
|
|
GET(FogParam0, fog);
|
|
|
|
AddLabel(tr("Fog parameter A")).endl();
|
|
AddLabel(tr("Mantissa: ")).AddSpinBox(fog.mantissa).endl();
|
|
AddLabel(tr("Exponent: ")).AddSpinBox(fog.exponent).endl();
|
|
AddLabel(tr("Sign: ")).AddComboBox(fog.sign, {tr("Positive"), tr("Negative")}).endl();
|
|
|
|
// TODO: _additionally_ add an input field for directly entering the floating point value!
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_FOGBMAGNITUDE) // 0xEF
|
|
{
|
|
AddLabel(tr("Fog parameter B")).endl();
|
|
// TODO!
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_FOGBEXPONENT) // 0xF0
|
|
{
|
|
AddLabel(tr("Fog parameter B")).endl();
|
|
// TODO!
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_FOGPARAM3) // 0xF1
|
|
{
|
|
GET(FogParam3, fog);
|
|
|
|
AddLabel(tr("Fog configuration and fog parameter C")).endl();
|
|
AddLabel(tr("Mantissa: ")).AddSpinBox(fog.c_mant).endl();
|
|
AddLabel(tr("Exponent: ")).AddSpinBox(fog.c_exp).endl();
|
|
AddLabel(tr("Sign: ")).AddComboBox(fog.c_sign, {tr("Positive"), tr("Negative")}).endl();
|
|
AddLabel(tr("Projection mode: ")).AddComboBox(fog.c_sign, {tr("Perspective"), tr("Orthographic")}).endl();
|
|
AddLabel(tr("Fog mode: ")).AddComboBox(fog.c_sign, {tr("Disabled"), tr("Unknown"), tr("Linear"), tr("Unknown"),
|
|
tr("Exponential"), tr("Exponential squared"), tr("Inverse exponential"),
|
|
tr("Inverse exponential squared")}).endl();
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_FOGCOLOR) // 0xF2
|
|
{
|
|
GET(FogParams::FogColor, color);
|
|
|
|
AddLabel(tr("Fog color")).endl();
|
|
AddLabel(tr("Red:")).AddSpinBox(color.r).endl();
|
|
AddLabel(tr("Green:")).AddSpinBox(color.g).endl();
|
|
AddLabel(tr("Blue:")).AddSpinBox(color.b).endl();
|
|
}
|
|
else if (fifo_data[cmd_start+1] == BPMEM_ALPHACOMPARE) // 0xF3
|
|
{
|
|
GET(AlphaTest, test);
|
|
|
|
QStringList comp_funcs = {
|
|
tr("Never"), tr("Less"), tr("Equal"), tr("Less or equal"),
|
|
tr("Greater"), tr("Not equal"), tr("Greater or equal"), tr("Always"),
|
|
};
|
|
|
|
QStringList alpha_ops = {
|
|
tr("and"), tr("or"), tr("xor"), tr("equal"),
|
|
};
|
|
|
|
AddLabel(tr("Alpha test")).endl();
|
|
AddLabel(tr("First reference value: ")).AddSpinBox(test.ref0).endl();
|
|
AddLabel(tr("First comparison function: ")).AddComboBox(test.comp0, comp_funcs).endl();
|
|
AddLabel(tr("Second reference value: ")).AddSpinBox(test.ref1).endl();
|
|
AddLabel(tr("Second comparison function: ")).AddComboBox(test.comp1, comp_funcs).endl();
|
|
AddLabel(tr("Combining function: ")).AddComboBox(test.logic, alpha_ops).endl();
|
|
}
|
|
}
|
|
}
|
|
|
|
void LayoutStream::OnFifoDataChanged()
|
|
{
|
|
// printf("data changed: %08x\n", data);
|
|
int cmd_start = dff_model->data(current_index, DffModel::UserRole_CmdStart).toInt();
|
|
QByteArray data = cur_fifo_data.mid(cmd_start, edit_size+(edit_offset-cmd_start));
|
|
dff_model->setData(current_index, QVariant(data), DffModel::UserRole_FifoDataForCommand);
|
|
}
|
|
|
|
void LayoutStream::ClearLayout(QLayout *layout)
|
|
{
|
|
QLayoutItem *item;
|
|
while((item = layout->takeAt(0))) {
|
|
// Making sure not to delete things multiple times
|
|
QLayout* layout = item->layout();
|
|
QWidget* widget = item->widget();
|
|
if (layout) {
|
|
ClearLayout(layout);
|
|
delete layout;
|
|
}
|
|
if (widget && (QLayoutItem*)widget != (QLayoutItem*)layout)
|
|
delete widget;
|
|
|
|
if (item != (QLayoutItem*)widget && item != (QLayoutItem*)layout)
|
|
delete item;
|
|
}
|
|
}
|