Files
leocad/common/lc_modellistdialog.cpp
T
Leonardo Zide 8b9f70f45b Fix HTML image transparency and extend dialog help
HTML export saved its transparency option without passing it to image
rendering. Select a transparent clear background when enabled and preserve
the configured background with fully opaque pixels when disabled. Keep the
existing background behavior for other step-image and Save Image callers.

Add tooltips, contextual overviews, and Help/F1 support to HTML Export,
Submodels, and all three Render modes. Link field labels to matching help
and explain export scope, file output, model management, and render controls.

Refresh catalog keys and locations while preserving existing translations
and review status. Leave the 56 new strings untranslated for the later
translation pass.

Validation: Qt 6.10 debug build; 16 actual PNG exports covering two steps,
solid/gradient backgrounds, transparency on/off, tiled rendering, background
colors, retained geometry, and unchanged Save Image behavior; dialog Help/F1,
Escape, label-buddy and visual layout checks; catalog coverage for 2,170
active source messages; git diff --check.
2026-10-22 16:15:47 -07:00

302 lines
8.9 KiB
C++

#include "lc_global.h"
#include "lc_qutils.h"
#include "lc_modellistdialog.h"
#include "ui_lc_modellistdialog.h"
#include "project.h"
#include "lc_profile.h"
#include "lc_model.h"
enum class lcModelListRole
{
ExistingModel = Qt::UserRole,
DuplicateModel
};
lcModelListDialog::lcModelListDialog(QWidget* Parent, const std::vector<std::unique_ptr<lcModel>>& Models)
: QDialog(Parent), ui(new Ui::lcModelListDialog)
{
mActiveModelItem = nullptr;
ui->setupUi(this);
lcSetupDialogHelp(this, ui->buttonBox);
connect(ui->NewModel, &QPushButton::clicked, this, &lcModelListDialog::NewModelClicked);
connect(ui->DeleteModel, &QPushButton::clicked, this, &lcModelListDialog::DeleteModelClicked);
connect(ui->RenameModel, &QPushButton::clicked, this, &lcModelListDialog::RenameModelClicked);
connect(ui->ExportModel, &QPushButton::clicked, this, &lcModelListDialog::ExportModelClicked);
connect(ui->DuplicateModel, &QPushButton::clicked, this, &lcModelListDialog::DuplicateModelClicked);
connect(ui->ModelList, &QListWidget::itemDoubleClicked, this, &lcModelListDialog::ModelListItemDoubleClicked);
connect(ui->ModelList, &QListWidget::itemSelectionChanged, this, &lcModelListDialog::ModelListItemSelectionChanged);
ui->ModelList->setDefaultDropAction(Qt::DropAction::MoveAction);
ui->ModelList->setDragDropMode(QAbstractItemView::DragDropMode::InternalMove);
lcModel* ActiveModel = lcGetActiveProject()->GetActiveModel();
int ActiveModelIndex = -1;
for (const std::unique_ptr<lcModel>& Model : Models)
{
QListWidgetItem* Item = new QListWidgetItem(Model->GetProperties().mFileName);
Item->setData(static_cast<int>(lcModelListRole::ExistingModel), QVariant::fromValue<uintptr_t>((uintptr_t)Model.get()));
ui->ModelList->addItem(Item);
if (Model.get() == ActiveModel)
ActiveModelIndex = ui->ModelList->count() - 1;
}
if (ActiveModelIndex != -1)
ui->ModelList->setCurrentRow(ActiveModelIndex);
QSettings Settings;
ui->SetActiveModel->setChecked(Settings.value("Settings/ModelListSetActive", true).toBool());
UpdateButtons();
}
lcModelListDialog::~lcModelListDialog()
{
delete ui;
}
int lcModelListDialog::GetActiveModelIndex() const
{
return ui->ModelList->row(mActiveModelItem);
}
std::vector<lcModelListDialogEntry> lcModelListDialog::GetResults() const
{
std::vector<lcModelListDialogEntry> Models;
Models.reserve(ui->ModelList->count());
for (int ItemIdx = 0; ItemIdx < ui->ModelList->count(); ItemIdx++)
{
QListWidgetItem* Item = ui->ModelList->item(ItemIdx);
lcModelListDialogEntry Entry;
Entry.Name = Item->text();
Entry.ExistingModel = reinterpret_cast<lcModel*>(Item->data(static_cast<int>(lcModelListRole::ExistingModel)).value<uintptr_t>());
Entry.DuplicateSource = reinterpret_cast<lcModel*>(Item->data(static_cast<int>(lcModelListRole::DuplicateModel)).value<uintptr_t>());
Models.emplace_back(Entry);
}
return Models;
}
void lcModelListDialog::UpdateButtons()
{
int ModelCount = ui->ModelList->count();
ui->DeleteModel->setEnabled(ModelCount > 1);
ui->SetActiveModel->setEnabled(ui->ModelList->currentItem() != nullptr);
}
void lcModelListDialog::accept()
{
if (ui->SetActiveModel->isChecked())
mActiveModelItem = ui->ModelList->currentItem();
QSettings Settings;
Settings.setValue("Settings/ModelListSetActive", ui->SetActiveModel->isChecked());
QDialog::accept();
}
void lcModelListDialog::NewModelClicked()
{
QStringList ModelNames;
for (int ItemIdx = 0; ItemIdx < ui->ModelList->count(); ItemIdx++)
ModelNames.append(ui->ModelList->item(ItemIdx)->text());
QString Name = lcGetActiveProject()->GetNewModelName(this, tr("New Submodel"), QString(), ModelNames);
if (Name.isEmpty())
return;
QListWidgetItem* Item = new QListWidgetItem(Name);
ui->ModelList->addItem(Item);
UpdateButtons();
}
void lcModelListDialog::DeleteModelClicked()
{
if (ui->ModelList->count() == 1)
{
QMessageBox::information(this, tr("Delete Submodel"), tr("The model cannot be empty."));
return;
}
const QList<QListWidgetItem*> SelectedItems = ui->ModelList->selectedItems();
if (SelectedItems.isEmpty())
{
QMessageBox::information(this, tr("Delete Submodel"), tr("No submodel selected."));
return;
}
QString Prompt;
if (SelectedItems.size() == 1)
Prompt = tr("Are you sure you want to delete the submodel '%1'?").arg(SelectedItems[0]->text());
else
Prompt = tr("Are you sure you want to delete %n submodels?", nullptr, static_cast<int>(SelectedItems.size()));
if (QMessageBox::question(this, tr("Delete Submodel"), Prompt, QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
return;
for (QListWidgetItem* SelectedItem : SelectedItems)
{
if (mActiveModelItem == SelectedItem)
mActiveModelItem = nullptr;
delete SelectedItem;
}
UpdateButtons();
}
void lcModelListDialog::RenameModelClicked()
{
const QList<QListWidgetItem*> SelectedItems = ui->ModelList->selectedItems();
if (SelectedItems.isEmpty())
{
QMessageBox::information(this, tr("Rename Submodel"), tr("No submodel selected."));
return;
}
for (QListWidgetItem* CurrentItem : SelectedItems)
{
QStringList ModelNames;
for (int ItemIdx = 0; ItemIdx < ui->ModelList->count(); ItemIdx++)
ModelNames.append(ui->ModelList->item(ItemIdx)->text());
QString Name = lcGetActiveProject()->GetNewModelName(this, tr("Rename Submodel"), CurrentItem->text(), ModelNames);
if (!Name.isEmpty())
CurrentItem->setText(Name);
}
}
void lcModelListDialog::ExportModelClicked()
{
const QList<QListWidgetItem*> SelectedItems = ui->ModelList->selectedItems();
if (SelectedItems.isEmpty())
{
QMessageBox::information(this, tr("Export Submodel"), tr("No submodel selected."));
return;
}
if (SelectedItems.size() == 1)
{
QListWidgetItem* CurrentItem = SelectedItems[0];
lcModel* Model = (lcModel*)CurrentItem->data(static_cast<int>(lcModelListRole::ExistingModel)).value<uintptr_t>();
if (!Model)
{
Model = (lcModel*)CurrentItem->data(static_cast<int>(lcModelListRole::DuplicateModel)).value<uintptr_t>();
if (!Model)
{
QMessageBox::information(this, tr("Export Submodel"), tr("Nothing to export."));
return;
}
}
QString SaveFileName = QFileInfo(QDir(lcGetProfileString(LC_PROFILE_PROJECTS_PATH)), CurrentItem->text()).absoluteFilePath();
SaveFileName = QFileDialog::getSaveFileName(this, tr("Export Model"), SaveFileName, tr("Supported Files (*.ldr *.dat);;All Files (*.*)"));
if (SaveFileName.isEmpty())
return;
lcResult<void> ExportResult = lcGetActiveProject()->ExportModel(SaveFileName, Model);
if (!ExportResult && !ExportResult.error().isEmpty())
QMessageBox::warning(this, tr("Export Submodel"), ExportResult.error());
lcSetProfileString(LC_PROFILE_PROJECTS_PATH, QFileInfo(SaveFileName).absolutePath());
}
else
{
QString Folder = QFileDialog::getExistingDirectory(this, tr("Select Export Folder"), lcGetProfileString(LC_PROFILE_PROJECTS_PATH));
for (QListWidgetItem* CurrentItem : SelectedItems)
{
lcModel* Model = (lcModel*)CurrentItem->data(static_cast<int>(lcModelListRole::ExistingModel)).value<uintptr_t>();
if (!Model)
Model = (lcModel*)CurrentItem->data(static_cast<int>(lcModelListRole::DuplicateModel)).value<uintptr_t>();
if (Model)
{
QString SaveFileName = QFileInfo(QDir(Folder), CurrentItem->text()).absoluteFilePath();
lcResult<void> ExportResult = lcGetActiveProject()->ExportModel(SaveFileName, Model);
if (!ExportResult && !ExportResult.error().isEmpty())
{
QMessageBox::warning(this, tr("Export Submodel"), ExportResult.error());
break;
}
}
}
lcSetProfileString(LC_PROFILE_PROJECTS_PATH, Folder);
}
}
void lcModelListDialog::DuplicateModelClicked()
{
const QList<QListWidgetItem*> SelectedItems = ui->ModelList->selectedItems();
if (SelectedItems.isEmpty())
{
QMessageBox::information(this, tr("Duplicate Submodel"), tr("No submodel selected."));
return;
}
for (QListWidgetItem* CurrentItem : SelectedItems)
{
QStringList ModelNames;
for (int ItemIdx = 0; ItemIdx < ui->ModelList->count(); ItemIdx++)
ModelNames.append(ui->ModelList->item(ItemIdx)->text());
QString Name = CurrentItem->text();
do
{
Name = tr("Copy of ") + Name;
} while (ModelNames.contains(Name, Qt::CaseInsensitive));
Name = lcGetActiveProject()->GetNewModelName(this, tr("Duplicate Submodel"), Name, ModelNames);
if (Name.isEmpty())
continue;
QListWidgetItem* Item = new QListWidgetItem(Name);
uintptr_t ExistingModel = CurrentItem->data(static_cast<int>(lcModelListRole::ExistingModel)).value<uintptr_t>();
if (!ExistingModel)
ExistingModel = CurrentItem->data(static_cast<int>(lcModelListRole::DuplicateModel)).value<uintptr_t>();
Item->setData(static_cast<int>(lcModelListRole::DuplicateModel), QVariant::fromValue<uintptr_t>(ExistingModel));
ui->ModelList->addItem(Item);
}
UpdateButtons();
}
void lcModelListDialog::ModelListItemDoubleClicked(QListWidgetItem* Item)
{
mActiveModelItem = Item;
accept();
}
void lcModelListDialog::ModelListItemSelectionChanged()
{
UpdateButtons();
}