Qt Editor: Add groups to enum

qteditor
Sven Eberhardt 2016-06-15 00:15:08 -04:00
parent 6b958fe88e
commit ad863836b3
4 changed files with 164 additions and 6 deletions

View File

@ -241,10 +241,11 @@ C4PropertyDelegateLabelAndButtonWidget::C4PropertyDelegateLabelAndButtonWidget(Q
palette.setColor(label->foregroundRole(), palette.color(QPalette::HighlightedText));
palette.setColor(label->backgroundRole(), palette.color(QPalette::Highlight));
label->setPalette(palette);
setPalette(palette);
layout->addWidget(label);
button = new QPushButton(QString(LoadResStr("IDS_CNS_MORE")), this);
layout->addWidget(button);
// Make sure to draw over view in background
setPalette(palette);
setAutoFillBackground(true);
}
@ -421,6 +422,75 @@ QColor C4PropertyDelegateColor::GetDisplayBackgroundColor(const C4Value &val, cl
return static_cast<uint32_t>(val.getInt()) & 0xffffff;
}
C4DeepQComboBox::C4DeepQComboBox(QWidget *parent)
: QComboBox(parent), descending(false), item_clicked(false)
{
QTreeView *view = new QTreeView(this);
view->setFrameShape(QFrame::NoFrame);
view->setSelectionBehavior(QTreeView::SelectRows);
view->setAllColumnsShowFocus(true);
view->header()->hide();
setView(view);
view->viewport()->installEventFilter(this);
}
void C4DeepQComboBox::showPopup()
{
// New selection: Reset to root of model
setRootModelIndex(QModelIndex());
QComboBox::showPopup();
view()->setMinimumWidth(200); // prevent element list from becoming too small in nested dialogues
}
void C4DeepQComboBox::hidePopup()
{
QModelIndex current = view()->currentIndex();
setRootModelIndex(current.parent());
setCurrentIndex(current.row());
QVariant selected_data = model()->data(current, Qt::UserRole + 1);
if (item_clicked && selected_data.type() != QVariant::Int)
{
if (descending)
{
QTreeView *tview = static_cast<QTreeView *>(view());
bool expand = !tview->isExpanded(current);
tview->setExpanded(current, expand);
// Put all child elements into view if possible
if (expand)
{
int32_t child_row_count = model()->rowCount(current);
tview->scrollTo(model()->index(child_row_count - 1, 0, current), QAbstractItemView::EnsureVisible);
tview->scrollTo(current, QAbstractItemView::EnsureVisible);
}
}
}
else
{
// Otherwise, finish selection
QComboBox::hidePopup();
}
descending = item_clicked = false;
}
void C4DeepQComboBox::setCurrentModelIndex(QModelIndex new_index)
{
setRootModelIndex(new_index.parent());
setCurrentIndex(new_index.row());
}
// event filter for view: Catch mouse clicks to descend into children
bool C4DeepQComboBox::eventFilter(QObject *obj, QEvent *event)
{
if (obj == view()->viewport() && event->type() == QEvent::MouseButtonPress)
{
QPoint pos = static_cast<QMouseEvent *>(event)->pos();
QModelIndex pressed_index = view()->indexAt(pos);
item_clicked = pressed_index.isValid();
descending = view()->visualRect(pressed_index).contains(pos);
}
return false;
}
C4PropertyDelegateEnum::C4PropertyDelegateEnum(const C4PropertyDelegateFactory *factory, C4PropList *props, const C4ValueArray *poptions)
: C4PropertyDelegate(factory, props)
{
@ -443,6 +513,7 @@ C4PropertyDelegateEnum::C4PropertyDelegateEnum(const C4PropertyDelegateFactory *
Option option;
option.name = props->GetPropertyStr(P_Name);
if (!option.name.Get()) option.name = ::Strings.RegString("???");
option.group = props->GetPropertyStr(P_Group);
option.value_key = props->GetPropertyStr(P_ValueKey);
if (!option.value_key) option.value_key = default_value_key;
props->GetProperty(P_Value, &option.value);
@ -463,6 +534,44 @@ C4PropertyDelegateEnum::C4PropertyDelegateEnum(const C4PropertyDelegateFactory *
}
}
QStandardItemModel *C4PropertyDelegateEnum::CreateOptionModel() const
{
// Create a QStandardItemModel tree from all options and their groups
std::unique_ptr<QStandardItemModel> model(new QStandardItemModel());
model->setColumnCount(1);
int idx = 0;
for (const Option &opt : options)
{
QStandardItem *parent = model->invisibleRootItem();
if (opt.group)
{
QStringList group_names = QString(opt.group->GetCStr()).split(QString("/"));
for (const QString &group_name : group_names)
{
int row_index = -1;
for (int check_row_index = 0; check_row_index < parent->rowCount(); ++check_row_index)
if (parent->child(check_row_index, 0)->text() == group_name)
{
row_index = check_row_index;
parent = parent->child(check_row_index, 0);
break;
}
if (row_index < 0)
{
QStandardItem *new_group = new QStandardItem(group_name);
parent->appendRow(new_group);
parent = new_group;
}
}
}
QStandardItem *new_item = new QStandardItem(QString(opt.name->GetCStr()));
new_item->setData(QVariant(idx), Qt::UserRole + 1);
parent->appendRow(new_item);
++idx;
}
return model.release();
}
void C4PropertyDelegateEnum::ReserveOptions(int32_t num)
{
options.reserve(num);
@ -583,6 +692,23 @@ void C4PropertyDelegateEnum::UpdateEditorParameter(C4PropertyDelegateEnum::Edito
}
}
QModelIndex C4PropertyDelegateEnum::GetModelIndexByID(QStandardItemModel *model, QStandardItem *parent_item, int32_t id, const QModelIndex &parent) const
{
// Resolve data stored in model to model index in tree
for (int row = 0; row < parent_item->rowCount(); ++row)
{
QStandardItem *child = parent_item->child(row, 0);
QVariant v = child->data(Qt::UserRole + 1);
if (v.type() == QVariant::Int && v.toInt() == id) return model->index(row, 0, parent);
if (child->rowCount())
{
QModelIndex child_match = GetModelIndexByID(model, child, id, model->index(row, 0, parent));
if (child_match.isValid()) return child_match;
}
}
return QModelIndex();
}
void C4PropertyDelegateEnum::SetEditorData(QWidget *aeditor, const C4Value &val, const C4PropertyPath &property_path) const
{
Editor *editor = static_cast<Editor*>(aeditor);
@ -591,7 +717,8 @@ void C4PropertyDelegateEnum::SetEditorData(QWidget *aeditor, const C4Value &val,
editor->updating = true;
// Update option selection
int32_t index = std::max<int32_t>(GetOptionByValue(val), 0);
editor->option_box->setCurrentIndex(index);
QStandardItemModel *model = static_cast<QStandardItemModel *>(editor->option_box->model());
editor->option_box->setCurrentModelIndex(GetModelIndexByID(model, model->invisibleRootItem(), index, QModelIndex()));
// Update parameter
UpdateEditorParameter(editor, false);
editor->updating = false;
@ -599,10 +726,13 @@ void C4PropertyDelegateEnum::SetEditorData(QWidget *aeditor, const C4Value &val,
void C4PropertyDelegateEnum::SetModelData(QObject *aeditor, const C4PropertyPath &property_path) const
{
LogF("SetModelData %s", property_path.GetPath());
// Fetch value from editor
Editor *editor = static_cast<Editor*>(aeditor);
int32_t idx = editor->option_box->currentIndex();
QStandardItemModel *model = static_cast<QStandardItemModel *>(editor->option_box->model());
QModelIndex selected_model_index = model->index(editor->option_box->currentIndex(), 0, editor->option_box->rootModelIndex());
QVariant vidx = model->data(selected_model_index, Qt::UserRole + 1);
if (vidx.type() != QVariant::Int) return;
int32_t idx = vidx.toInt();
if (idx < 0 || idx >= options.size()) return;
const Option &option = options[idx];
// Store directly in value or in a proplist field?
@ -638,13 +768,14 @@ QWidget *C4PropertyDelegateEnum::CreateEditor(const C4PropertyDelegateFactory *p
editor->layout->setMargin(0);
editor->layout->setSpacing(0);
editor->updating = true;
editor->option_box = new QComboBox(editor);
editor->option_box = new C4DeepQComboBox(editor);
editor->layout->addWidget(editor->option_box);
for (auto &option : options) editor->option_box->addItem(option.name->GetCStr());
void (QComboBox::*currentIndexChanged)(int) = &QComboBox::currentIndexChanged;
connect(editor->option_box, currentIndexChanged, editor, [editor, this](int newval) {
if (!editor->updating) this->UpdateOptionIndex(editor, newval); });
editor->updating = false;
editor->option_box->setModel(CreateOptionModel());
return editor;
}

View File

@ -174,6 +174,27 @@ public:
QColor GetDisplayBackgroundColor(const C4Value &val, class C4Object *obj) const override;
};
// A combo box that can select from a model with nested elements
// On click, descend into child elements
class C4DeepQComboBox : public QComboBox
{
Q_OBJECT
bool descending, item_clicked;
public:
C4DeepQComboBox(QWidget *parent);
void showPopup() override;
void hidePopup() override;
void setCurrentModelIndex(QModelIndex new_index);
protected:
// event filter for view: Catch mouse clicks to descend into children
bool eventFilter(QObject *obj, QEvent *event) override;
};
// Widget holder class
class C4PropertyDelegateEnumEditor : public QWidget
{
@ -182,7 +203,7 @@ class C4PropertyDelegateEnumEditor : public QWidget
public:
C4Value last_val;
C4PropertyPath last_get_path;
QComboBox *option_box;
C4DeepQComboBox *option_box;
QHBoxLayout *layout;
QWidget *parameter_widget;
bool updating, option_changed;
@ -202,6 +223,7 @@ public:
{
public:
C4RefCntPointer<C4String> name; // Display name in Editor enum dropdown box
C4RefCntPointer<C4String> group; // Grouping in enum dropdown box; nested groups separated by '/'
C4RefCntPointer<C4String> option_key;
C4RefCntPointer<C4String> value_key;
C4V_Type type; // Assume this option is set when value is of given type
@ -218,11 +240,13 @@ public:
Option() : type(C4V_Any), adelegate(NULL), storage_type(StorageNone) {}
};
private:
std::vector<Option> options;
protected:
void ReserveOptions(int32_t num);
QStandardItemModel *CreateOptionModel() const;
public:
C4PropertyDelegateEnum(const class C4PropertyDelegateFactory *factory, C4PropList *props, const C4ValueArray *poptions=NULL);
@ -236,6 +260,7 @@ public:
const class C4PropertyDelegateShape *GetShapeDelegate(const C4Value &val) const override; // Forward to parameter of selected option
private:
QModelIndex GetModelIndexByID(QStandardItemModel *model, QStandardItem *parent_item, int32_t id, const QModelIndex &parent) const;
int32_t GetOptionByValue(const C4Value &val) const;
void UpdateEditorParameter(C4PropertyDelegateEnum::Editor *editor, bool by_selection) const;
void EnsureOptionDelegateResolved(const Option &option) const;

View File

@ -269,6 +269,7 @@ C4StringTable::C4StringTable()
P[P_Display] = "Display";
P[P_DefaultValue] = "DefaultValue";
P[P_DefinitionPriority] = "DefinitionPriority";
P[P_Group] = "Group";
P[DFA_WALK] = "WALK";
P[DFA_FLIGHT] = "FLIGHT";
P[DFA_KNEEL] = "KNEEL";

View File

@ -493,6 +493,7 @@ enum C4PropertyName
P_Display,
P_DefaultValue,
P_DefinitionPriority,
P_Group,
// Default Action Procedures
DFA_WALK,
DFA_FLIGHT,