Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions code/missioneditor/sexp_tree_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -952,9 +952,8 @@ SCP_string SexpTreeModel::match_closest_operator(const SCP_string& str, int node
opf = query_operator_argument_type(op, arg_num);

// find the best operator
int best = sexp_match_closest_operator(str, opf);
int best = sexp_match_closest_operator(str, opf, 10);
if (best < 0) {
Warning(LOCATION, "Unable to find an operator match for string '%s' and argument type %d", str.c_str(), opf);
return str;
}
return Operators[best].text;
Expand Down
9 changes: 6 additions & 3 deletions code/parse/sexp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35315,12 +35315,15 @@ bool sexp_query_type_match(int opf, int opr)
* Finds the operator that is the best textual match for the input string, given the required OPF type. For equal matches,
* the alphabetically earliest operator is returned.
*
* min defaults to SCP_string::npos, when specified to another value, this function will not always return a match
*
* Note: Returns the operator index, not the operator value.
*/
int sexp_match_closest_operator(const SCP_string &str, int opf)
int sexp_match_closest_operator(const SCP_string &str, int opf, size_t min)
{
// Cyborg - This bool setup helps with readability
bool return_any = (min == SCP_string::npos);
int best = -1;
size_t min = SCP_string::npos;

for (int op_index : Sorted_operator_indexes)
{
Expand All @@ -35330,7 +35333,7 @@ int sexp_match_closest_operator(const SCP_string &str, int opf)
if (sexp_query_type_match(opf, opr))
{
size_t cost = stringcost(op_text, str, Max_operator_length, stringcost_tolower_equal);
if (best < 0 || cost < min)
if (cost < min || (return_any && best == -1) )
{
min = cost;
best = op_index;
Expand Down
2 changes: 1 addition & 1 deletion code/parse/sexp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1494,7 +1494,7 @@ extern std::pair<int, sexp_src> query_referenced_in_sexp(sexp_ref_type type, con
extern void stuff_sexp_text_string(SCP_string &dest, int node, int mode);
extern int build_sexp_string(SCP_string &accumulator, int cur_node, int level, int mode);
extern bool sexp_query_type_match(int opf, int opr);
extern int sexp_match_closest_operator(const SCP_string &str, int opf);
extern int sexp_match_closest_operator(const SCP_string &str, int opf, size_t min = SCP_string::npos);
extern bool sexp_recoverable_error(int num);
extern const char *sexp_error_message(int num);
extern int count_free_sexp_nodes();
Expand Down
34 changes: 26 additions & 8 deletions qtfred/src/ui/widgets/sexp_tree_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ sexp_tree_view::sexp_tree_view(QWidget* parent) : QTreeWidget(parent), _actions(
installShortcut(QKeySequence::Delete,
[](const SexpContextMenuState& s) { return s.can_delete; },
[this]() { deleteActionHandler(); });

// This keyboard shortcut does not need as much state checking because the helper
// handles security checks and what to call, and any node should work here.
auto* shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_S), this);
shortcut->setContext(Qt::WidgetShortcut);
connect(shortcut, &QShortcut::activated, this, &sexp_tree_view::editActionHandlerHelper);
}


Expand Down Expand Up @@ -1143,8 +1149,9 @@ std::unique_ptr<QMenu> sexp_tree_view::buildContextMenu(QTreeWidgetItem* h) {
popup_menu->addSeparator();

auto replace_op_menu = popup_menu->addMenu(tr("Replace Operator"));

auto replace_data_menu = popup_menu->addMenu(tr("Replace Data"));

auto replace_number_act =
replace_data_menu->addAction(tr("Number"), this, [this]() { replaceNumberDataHandler(); });
replace_number_act->setEnabled(false);
Expand All @@ -1153,6 +1160,7 @@ std::unique_ptr<QMenu> sexp_tree_view::buildContextMenu(QTreeWidgetItem* h) {
replace_string_act->setEnabled(false);
replace_data_menu->addSeparator();

popup_menu->addAction(tr("Search for Replacement"), QKeySequence(Qt::CTRL | Qt::Key_S), this, [this]() { editActionHandlerHelper(); });
popup_menu->addSection("Variables");

auto modify_variable_act = popup_menu->addAction(tr("Add/Modify Variable"), this, [this]() {
Expand Down Expand Up @@ -1608,11 +1616,18 @@ void sexp_tree_view::startOperatorQuickSearch(QTreeWidgetItem* item, const QStri
void sexp_tree_view::filterOperatorPopup(const QString& text)
{
_opList->clear();
SCP_set<QString> found_list;

if (text.isEmpty()) {
_opList->addItems(_opAll);
} else {
for (const auto& s : _opAll) {
if (s.contains(text, Qt::CaseInsensitive))
if (s.startsWith(text, Qt::CaseInsensitive))
_opList->addItem(s);
}

for (const auto& s : _opAll) {
if (s.contains(text, Qt::CaseInsensitive) && _opList->findItems(s, Qt::MatchExactly).isEmpty())
_opList->addItem(s);
}
}
Expand Down Expand Up @@ -1987,13 +2002,16 @@ void sexp_tree_view::handleDoubleClick() {

// Helper function for making sure that search and edit are initiated consistently
void sexp_tree_view::editActionHandlerHelper(){
item_index = get_node(currentItem());

if (_model.compute_context_menu_state().can_edit_text) {
editDataActionHandler();
} else {
openNodeEditor(currentItem());
auto item = currentItem();

// Just to be extra safe, early exit when an item is not selected
if (_currently_editing || _opPopupActive || item == nullptr || !_interface) {
return;
}

item_index = get_node(item);
// No longer gated to just certain types.
openNodeEditor(currentItem());
}

// Public entry point for deleting the currently selected item. Simply delegates to deleteActionHandler().
Expand Down
Loading