Skip to content
Merged
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
2 changes: 1 addition & 1 deletion qtfred/src/mission/dialogs/MissionStatsDialogModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ int MissionStatsDialogModel::getJumpNodeCount()

int MissionStatsDialogModel::getMessageCount()
{
return Num_messages;
return Num_messages - Num_builtin_messages;
}

int MissionStatsDialogModel::getEventCount()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

#include "mission/object.h"

// Sub-texture type suffixes, mirroring the strcat_s calls in modelread.cpp.
// Used both when detecting sub-texture slots in initSubTypes and when parsing
// new_texture strings on dialog reload.
static const SCP_string SUBTEXTURE_SUFFIXES[] = { "misc", "shine", "glow", "normal", "height", "ao", "reflect" };

namespace fso {
namespace fred {
namespace dialogs {
Expand Down Expand Up @@ -76,24 +81,55 @@ namespace fso {
{
if (!stricmp(Ships[_editor->cur_ship].ship_name, Fred_texture_replacement.ship_name) && !(Fred_texture_replacement.from_table))
{
// old_texture is stored as the bare base name by this dialog (no type suffix).
// However, entries loaded from old mission files may have a type suffix
// (e.g. "fenris-body-misc"), so fall back to stripping if no direct match.
SCP_string pureName = Fred_texture_replacement.old_texture;
auto npos = pureName.find_last_of('-');
if (npos != SCP_string::npos) {
pureName = pureName.substr(0, pureName.find_last_of('-'));

// Find the matching default texture slot.
// Try direct match first; fall back to stripping the last '-' segment
// for old mission-file entries that stored old_texture with a type suffix.
size_t matchIdx = defaultTextures.size();
for (size_t i = 0; i < defaultTextures.size(); i++) {
if (lcase_equal(defaultTextures[i], pureName)) {
matchIdx = i;
break;
}
}
if (matchIdx == defaultTextures.size()) {
auto stripPos = pureName.find_last_of('-');
if (stripPos != SCP_string::npos) {
SCP_string stripped = pureName.substr(0, stripPos);
for (size_t i = 0; i < defaultTextures.size(); i++) {
if (lcase_equal(defaultTextures[i], stripped)) {
matchIdx = i;
break;
}
}
}
}

// look for corresponding old texture
for (size_t i = 0; i < defaultTextures.size(); i++)
if (matchIdx < defaultTextures.size())
{
// if match
if (lcase_equal(defaultTextures[i], pureName))
size_t i = matchIdx;
{
SCP_string newText = Fred_texture_replacement.new_texture;
npos = newText.find_last_of('-');
SCP_string type;
if (npos != SCP_string::npos) {
type = newText.substr(npos + 1);
newText = newText.substr(0, newText.find_last_of('-'));
{
auto npos = newText.find_last_of('-');
if (npos != SCP_string::npos) {
SCP_string possibleType = newText.substr(npos + 1);
// Only treat the suffix as a type if it's a known sub-texture type.
// Texture names themselves can contain hyphens (e.g. "fighter01-01a"),
// so we must not blindly strip the last segment.
for (const auto& kt : SUBTEXTURE_SUFFIXES) {
if (lcase_equal(possibleType, kt)) {
type = possibleType;
newText = newText.substr(0, npos);
break;
}
}
}
}
if (!type.empty()) {
if (type == "misc") {
Expand Down Expand Up @@ -142,8 +178,6 @@ namespace fso {
currentTextures[i]["main"] = newText;
}

// we found one, so no more to check
break;
}
}
}
Expand Down Expand Up @@ -206,30 +240,19 @@ namespace fso {
}
if (!type.empty()) {
if (type == "trans") {
}
else if (type == "misc") {
subTypesAvailable[MapNum]["misc"] = true;
}
else if (type == "shine") {
subTypesAvailable[MapNum]["shine"] = true;
}
else if (type == "glow") {
subTypesAvailable[MapNum]["glow"] = true;
}
else if (type == "normal") {
subTypesAvailable[MapNum]["normal"] = true;
}
else if (type == "height") {
subTypesAvailable[MapNum]["height"] = true;
}
else if (type == "ao") {
subTypesAvailable[MapNum]["ao"] = true;
}
else if (type == "reflect") {
subTypesAvailable[MapNum]["reflect"] = true;
}
else {
error_display(1, "Invalid Map type %s. Check your model's texture names or get a programmer", type.c_str());
// transparency map, not a replaceable subtype
} else {
bool known = false;
for (const auto& kt : SUBTEXTURE_SUFFIXES) {
if (lcase_equal(type, kt)) {
subTypesAvailable[MapNum][kt] = true;
known = true;
break;
}
}
if (!known) {
error_display(1, "Invalid Map type %s. Check your model's texture names or get a programmer", type.c_str());
}
}
}
}
Expand Down Expand Up @@ -564,7 +587,7 @@ namespace fso {
{
temp_bmp = bm_load_animation(fullName.c_str(), &temp_frames, &temp_fps, nullptr, nullptr, false, true);
}
return temp_bmp < 0;
return temp_bmp >= 0;
}
}

Expand Down
10 changes: 3 additions & 7 deletions qtfred/src/ui/FredView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,6 @@ FredView::FredView(QWidget* parent) : QMainWindow(parent), ui(new Ui::FredView()

initializeGroupActions();

auto propsAction = new QAction(tr("Props"), this);
connect(propsAction, &QAction::triggered, this, &FredView::on_actionProps_triggered);
ui->menuObjects->insertAction(ui->actionWaypoint_Paths, propsAction);

connect(ui->actionPreferences, &QAction::triggered, this, [this]() {
dialogs::PreferencesDialog preferencesDialog(this, _viewport);
preferencesDialog.exec();
Expand Down Expand Up @@ -1442,7 +1438,7 @@ void FredView::on_actionCampaign_triggered(bool) {
editorCampaign->setAttribute(Qt::WA_DeleteOnClose);
editorCampaign->show();
}
void FredView::on_actionObjects_triggered(bool) {
void FredView::on_actionObject_Orientation_triggered(bool) {
orientEditorTriggered();
}
void FredView::on_actionCommand_Briefing_triggered(bool) {
Expand Down Expand Up @@ -1587,7 +1583,7 @@ void FredView::orientEditorTriggered() {
dialog->exec();
}
void FredView::onUpdateEditorActions() {
ui->actionObjects->setEnabled(query_valid_object(fred->currentObject));
ui->actionObject_Orientation->setEnabled(query_valid_object(fred->currentObject));

const bool validObject = query_valid_object(fred->currentObject);
const bool hasMarked = fred->getNumMarked() > 0;
Expand All @@ -1600,7 +1596,7 @@ void FredView::onUpdateEditorActions() {
ui->actionDelete_Wing->setEnabled(fred->cur_wing >= 0);

// Objects editor — requires a selected object
ui->actionObjects->setEnabled(validObject);
ui->actionObject_Orientation->setEnabled(validObject);

// Level/Align — require something to be selected
ui->actionLevel_Object->setEnabled(validObject);
Expand Down
2 changes: 1 addition & 1 deletion qtfred/src/ui/FredView.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class FredView: public QMainWindow, public IDialogProvider {
void on_actionMission_Specs_triggered(bool);
void on_actionWaypoint_Paths_triggered(bool);
void on_actionJump_Nodes_triggered(bool);
void on_actionObjects_triggered(bool);
void on_actionObject_Orientation_triggered(bool);
void on_actionShips_triggered(bool);
void on_actionWings_triggered(bool);
void on_actionProps_triggered(bool);
Expand Down
5 changes: 5 additions & 0 deletions qtfred/src/ui/Theme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ QToolButton:checked:hover {
QToolButton::menu-indicator {
image: none;
}
QMenu::separator {
height: 1px;
background: #8f8f8f;
margin: 4px 8px;
}
)";

} // anonymous namespace
Expand Down
11 changes: 10 additions & 1 deletion qtfred/src/ui/dialogs/ReinforcementsEditorDialog.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "ReinforcementsEditorDialog.h"
#include "ui_ReinforcementsDialog.h"
#include "ui/Theme.h"
#include "mission/util.h"
#include <globalincs/linklist.h>
#include <ui/util/SignalBlockers.h>
Expand All @@ -16,6 +17,14 @@ ReinforcementsDialog::ReinforcementsDialog(FredView* parent, EditorViewport* vie
this->setFocus();
ui->setupUi(this);

fso::fred::bindStandardIcon(ui->moveSelectionUp, QStyle::SP_ArrowUp);
ui->moveSelectionUp->setText(QString());
ui->moveSelectionUp->setToolTip(tr("Move selected reinforcement up"));

fso::fred::bindStandardIcon(ui->moveSelectionDown, QStyle::SP_ArrowDown);
ui->moveSelectionDown->setText(QString());
ui->moveSelectionDown->setToolTip(tr("Move selected reinforcement down"));

updateUi();
}

Expand Down Expand Up @@ -262,4 +271,4 @@ void ReinforcementsDialog::on_poolMultiselectCheckbox_toggled(bool checked)
}
}

} // namespace fso::fred::dialogs
} // namespace fso::fred::dialogs
66 changes: 43 additions & 23 deletions qtfred/src/ui/dialogs/ShipEditor/ShipAltShipClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "ui_ShipAltShipClass.h"

#include <mission/util.h>
#include <ui/Theme.h>
#include <ui/util/SignalBlockers.h>

#include <QCloseEvent>
Expand Down Expand Up @@ -204,6 +205,15 @@ void ShipAltShipClass::initUI()
variable_pool->appendRow(item);
}
ui->variableCombo->setModel(variable_pool);

fso::fred::bindStandardIcon(ui->upButton, QStyle::SP_ArrowUp);
ui->upButton->setText(QString());
ui->upButton->setToolTip(tr("Move selected class up"));

fso::fred::bindStandardIcon(ui->downButton, QStyle::SP_ArrowDown);
ui->downButton->setText(QString());
ui->downButton->setToolTip(tr("Move selected class down"));

updateUI();
}

Expand All @@ -222,36 +232,46 @@ void ShipAltShipClass::updateUI()
if (ui->variableCombo->model()->rowCount() <= 1) {
dynamic_cast<InverseSortFilterProxyModel*>(ui->shipCombo->model())->setFilterFixedString("Set From Variable");
}
// Workaround: avoid model()->match() which returns a QModelIndexList that triggers a
// cross-heap free assert on Windows debug builds. Manually iterate instead.
{
QModelIndexList shipMatches =
ui->shipCombo->model()->match(ui->shipCombo->model()->index(0, 0), Qt::UserRole, ship_class);
if (!shipMatches.empty()) {
ui->shipCombo->setCurrentIndex(shipMatches.first().row());
} else {
if (ui->classList->model()->rowCount() != 0 && ship_class != -1) {
_viewport->dialogProvider->showButtonDialog(DialogType::Error,
"Error",
"Illegal ship class.\n Resetting to -1",
{DialogButton::Ok});
int shipRow = 0;
bool found = false;
auto* shipModel = ui->shipCombo->model();
for (int i = 0; i < shipModel->rowCount(); ++i) {
if (shipModel->data(shipModel->index(i, 0), Qt::UserRole).toInt() == ship_class) {
shipRow = i;
found = true;
break;
}
ui->shipCombo->setCurrentIndex(0);
}
if (!found && ui->classList->model()->rowCount() != 0 && ship_class != -1) {
_viewport->dialogProvider->showButtonDialog(DialogType::Error,
"Error",
"Illegal ship class.\n Resetting to -1",
{DialogButton::Ok});
}
ui->shipCombo->setCurrentIndex(shipRow);
}

{
QModelIndexList varMatches =
ui->variableCombo->model()->match(ui->variableCombo->model()->index(0, 0), Qt::UserRole, variable);
if (!varMatches.empty()) {
ui->variableCombo->setCurrentIndex(varMatches.first().row());
} else {
if (ui->classList->model()->rowCount() != 0) {
_viewport->dialogProvider->showButtonDialog(DialogType::Error,
"Error",
"Illegal variable index.\n Resetting to -1",
{DialogButton::Ok});
int varRow = 0;
bool found = false;
auto* varModel = ui->variableCombo->model();
for (int i = 0; i < varModel->rowCount(); ++i) {
if (varModel->data(varModel->index(i, 0), Qt::UserRole).toInt() == variable) {
varRow = i;
found = true;
break;
}
ui->variableCombo->setCurrentIndex(0);
}
if (!found && ui->classList->model()->rowCount() != 0) {
_viewport->dialogProvider->showButtonDialog(DialogType::Error,
"Error",
"Illegal variable index.\n Resetting to -1",
{DialogButton::Ok});
}
ui->variableCombo->setCurrentIndex(varRow);
}

if (ui->variableCombo->model()->rowCount() <= 1) {
Expand Down Expand Up @@ -323,4 +343,4 @@ bool InverseSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelI
bool accept = QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
return !accept;
}
} // namespace fso::fred::dialogs
} // namespace fso::fred::dialogs
27 changes: 12 additions & 15 deletions qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,21 +667,18 @@ void ShipEditorDialog::on_specialStatsButton_clicked()
}
void ShipEditorDialog::on_hideCuesButton_clicked()
{
if (ui->hideCuesButton->isChecked()) {
ui->arrivalGroupBox->setVisible(false);
ui->departureGroupBox->setVisible(false);
ui->HelpTitle->setVisible(false);
ui->helpText->setVisible(false);
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
resize(sizeHint());
} else {
ui->arrivalGroupBox->setVisible(true);
ui->departureGroupBox->setVisible(true);
ui->HelpTitle->setVisible(true);
ui->helpText->setVisible(true);
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
resize(sizeHint());
}
const auto showHelp = _viewport->Show_sexp_help_ship_editor;

_cues_hidden = !_cues_hidden;

ui->arrivalGroupBox->setVisible(!_cues_hidden);
ui->departureGroupBox->setVisible(!_cues_hidden);
ui->HelpTitle->setVisible(!_cues_hidden && showHelp);
ui->helpText->setVisible(!_cues_hidden && showHelp);
ui->hideCuesButton->setText(_cues_hidden ? "Show Cues" : "Hide Cues");

QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
resize(sizeHint());
}
void ShipEditorDialog::on_restrictArrivalPathsButton_clicked()
{
Expand Down
4 changes: 3 additions & 1 deletion qtfred/src/ui/dialogs/ShipEditor/ShipEditorDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,13 @@ class ShipEditorDialog : public QDialog, public SexpTreeEditorInterface {
void on_departureTree_helpChanged(const QString&);
void on_departureTree_miniHelpChanged(const QString&);
void on_noDepartureWarpCheckBox_toggled(bool);
private:
private: // NOLINT(readability-redundant-access-specifiers)
std::unique_ptr<Ui::ShipEditorDialog> ui;
std::unique_ptr<ShipEditorDialogModel> _model;
EditorViewport* _viewport;

bool _cues_hidden = false;

void update();

void updateUI(bool overwrite = false);
Expand Down
Loading
Loading