Update main app with theming and UI improvements
- App metadata defines at top of main.cpp - Dynamic themed app icon (accent color replaces red) - Icon refreshes on theme change - Disabled unimplemented menu actions - Image preview with theme support - Updated CLI help text with feature list - Splash screen integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
42373120b0
commit
5f43466057
@ -6,6 +6,7 @@
|
||||
#include <QScrollBar>
|
||||
#include <QWheelEvent>
|
||||
#include <QEvent>
|
||||
#include <QHeaderView>
|
||||
#include "statusbarmanager.h"
|
||||
|
||||
ImagePreviewWidget::ImagePreviewWidget(QWidget *parent)
|
||||
@ -13,8 +14,10 @@ ImagePreviewWidget::ImagePreviewWidget(QWidget *parent)
|
||||
, mImageLabel(new QLabel(this))
|
||||
, mInfoLabel(new QLabel(this))
|
||||
, mScrollArea(new QScrollArea(this))
|
||||
, mMetadataTree(new QTreeWidget(this))
|
||||
, mDragging(false)
|
||||
, mZoomFactor(1.0)
|
||||
, mBitsPerPixel(0)
|
||||
{
|
||||
mImageLabel->setAlignment(Qt::AlignCenter);
|
||||
mImageLabel->setBackgroundRole(QPalette::Base);
|
||||
@ -31,11 +34,23 @@ ImagePreviewWidget::ImagePreviewWidget(QWidget *parent)
|
||||
mInfoLabel->setAlignment(Qt::AlignCenter);
|
||||
mInfoLabel->setStyleSheet("QLabel { background-color: #333; color: #fff; padding: 4px; }");
|
||||
|
||||
// Setup metadata tree
|
||||
mMetadataTree->setHeaderLabels({"Property", "Value"});
|
||||
mMetadataTree->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
||||
mMetadataTree->header()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||
mMetadataTree->setAlternatingRowColors(true);
|
||||
|
||||
// Create splitter for image and metadata
|
||||
auto *splitter = new QSplitter(Qt::Horizontal, this);
|
||||
splitter->addWidget(mScrollArea);
|
||||
splitter->addWidget(mMetadataTree);
|
||||
splitter->setSizes({500, 200});
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(mInfoLabel);
|
||||
layout->addWidget(mScrollArea, 1);
|
||||
layout->addWidget(splitter, 1);
|
||||
setLayout(layout);
|
||||
|
||||
// Enable mouse tracking for drag-to-pan
|
||||
@ -50,6 +65,53 @@ void ImagePreviewWidget::setFilename(const QString &filename)
|
||||
mFilename = filename;
|
||||
}
|
||||
|
||||
void ImagePreviewWidget::setMetadata(const QVariantMap &metadata)
|
||||
{
|
||||
// Add parsed metadata fields to tree
|
||||
for (auto it = metadata.begin(); it != metadata.end(); ++it) {
|
||||
if (it.key().startsWith("_")) continue; // Skip internal fields
|
||||
|
||||
auto *item = new QTreeWidgetItem(mMetadataTree);
|
||||
item->setText(0, it.key());
|
||||
|
||||
QVariant val = it.value();
|
||||
if (val.typeId() == QMetaType::QByteArray) {
|
||||
QByteArray ba = val.toByteArray();
|
||||
item->setText(1, QString("<%1 bytes>").arg(ba.size()));
|
||||
} else {
|
||||
item->setText(1, val.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImagePreviewWidget::updateMetadataDisplay()
|
||||
{
|
||||
mMetadataTree->clear();
|
||||
|
||||
// Add image info
|
||||
auto *dimItem = new QTreeWidgetItem(mMetadataTree);
|
||||
dimItem->setText(0, "Dimensions");
|
||||
dimItem->setText(1, QString("%1 x %2").arg(mImageSize.width()).arg(mImageSize.height()));
|
||||
|
||||
if (!mDetectedFormat.isEmpty()) {
|
||||
auto *formatItem = new QTreeWidgetItem(mMetadataTree);
|
||||
formatItem->setText(0, "Format");
|
||||
formatItem->setText(1, mDetectedFormat);
|
||||
}
|
||||
|
||||
if (mBitsPerPixel > 0) {
|
||||
auto *bppItem = new QTreeWidgetItem(mMetadataTree);
|
||||
bppItem->setText(0, "Bit Depth");
|
||||
bppItem->setText(1, QString("%1-bit").arg(mBitsPerPixel));
|
||||
}
|
||||
|
||||
if (!mCompression.isEmpty()) {
|
||||
auto *compItem = new QTreeWidgetItem(mMetadataTree);
|
||||
compItem->setText(0, "Compression");
|
||||
compItem->setText(1, mCompression);
|
||||
}
|
||||
}
|
||||
|
||||
QSize ImagePreviewWidget::imageSize() const
|
||||
{
|
||||
return mImageSize;
|
||||
@ -166,19 +228,28 @@ void ImagePreviewWidget::updateZoom()
|
||||
|
||||
bool ImagePreviewWidget::loadFromData(const QByteArray &data, const QString &format)
|
||||
{
|
||||
// Reset format info
|
||||
mDetectedFormat.clear();
|
||||
mBitsPerPixel = 0;
|
||||
mCompression.clear();
|
||||
|
||||
// Check for Xbox texture formats (XBTX2D, TX2D, etc.)
|
||||
if (data.size() >= 8) {
|
||||
QString magic = QString::fromLatin1(data.left(8));
|
||||
if (magic.startsWith("XBTX2D") || magic.startsWith("TX2D") || magic.startsWith("TX1D") || magic.startsWith("TX3D")) {
|
||||
mDetectedFormat = "Xbox 360 Texture";
|
||||
mCompression = "DXT";
|
||||
// Try to decode Xbox 360 texture
|
||||
QImage image = loadXBTX2D(data);
|
||||
if (!image.isNull()) {
|
||||
mImageSize = image.size();
|
||||
mBitsPerPixel = image.depth();
|
||||
mOriginalPixmap = QPixmap::fromImage(image);
|
||||
mZoomFactor = 1.0;
|
||||
mImageLabel->setPixmap(mOriginalPixmap);
|
||||
mImageLabel->adjustSize();
|
||||
mInfoLabel->setText(QString("%1 - %2x%3 (Xbox 360)").arg(mFilename).arg(image.width()).arg(image.height()));
|
||||
updateMetadataDisplay();
|
||||
return true;
|
||||
}
|
||||
// Fallback to info display if decode fails
|
||||
@ -186,15 +257,19 @@ bool ImagePreviewWidget::loadFromData(const QByteArray &data, const QString &for
|
||||
.arg(magic.left(6).trimmed())
|
||||
.arg(data.size()));
|
||||
mInfoLabel->setText(QString("%1 - Xbox 360 Texture (%2 bytes)").arg(mFilename).arg(data.size()));
|
||||
updateMetadataDisplay();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for DDS format (starts with "DDS ")
|
||||
if (data.size() >= 4 && data.left(4) == "DDS ") {
|
||||
mDetectedFormat = "DDS";
|
||||
mCompression = "DXT";
|
||||
mImageLabel->setText(QString("DDS Texture Format\n\nSize: %1 bytes\n\nDDS preview not yet implemented.")
|
||||
.arg(data.size()));
|
||||
mInfoLabel->setText(QString("%1 - DDS Texture (%2 bytes)").arg(mFilename).arg(data.size()));
|
||||
updateMetadataDisplay();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -203,6 +278,7 @@ bool ImagePreviewWidget::loadFromData(const QByteArray &data, const QString &for
|
||||
// Try standard Qt loading first
|
||||
if (!format.isEmpty()) {
|
||||
image.loadFromData(data, format.toUtf8().constData());
|
||||
mDetectedFormat = format.toUpper();
|
||||
}
|
||||
|
||||
if (image.isNull()) {
|
||||
@ -213,6 +289,7 @@ bool ImagePreviewWidget::loadFromData(const QByteArray &data, const QString &for
|
||||
if (image.isNull() && (format.toLower() == "tga" ||
|
||||
(data.size() > 18 && mFilename.toLower().endsWith(".tga")))) {
|
||||
image = loadTGA(data);
|
||||
mDetectedFormat = "TGA";
|
||||
}
|
||||
|
||||
if (image.isNull()) {
|
||||
@ -229,10 +306,12 @@ bool ImagePreviewWidget::loadFromData(const QByteArray &data, const QString &for
|
||||
}
|
||||
|
||||
mImageSize = image.size();
|
||||
mBitsPerPixel = image.depth();
|
||||
mOriginalPixmap = QPixmap::fromImage(image);
|
||||
mZoomFactor = 1.0;
|
||||
mImageLabel->setPixmap(mOriginalPixmap);
|
||||
mImageLabel->adjustSize();
|
||||
updateMetadataDisplay();
|
||||
|
||||
QString info = QString("%1 - %2x%3 - %4 bytes")
|
||||
.arg(mFilename)
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
#include <QPixmap>
|
||||
#include <QImage>
|
||||
#include <QMouseEvent>
|
||||
#include <QTreeWidget>
|
||||
#include <QSplitter>
|
||||
|
||||
class ImagePreviewWidget : public QWidget
|
||||
{
|
||||
@ -26,6 +28,9 @@ public:
|
||||
// Set the filename for display
|
||||
void setFilename(const QString &filename);
|
||||
|
||||
// Set metadata to display in the properties panel
|
||||
void setMetadata(const QVariantMap &metadata);
|
||||
|
||||
// Get current image size
|
||||
QSize imageSize() const;
|
||||
|
||||
@ -41,6 +46,7 @@ private:
|
||||
QLabel *mImageLabel;
|
||||
QLabel *mInfoLabel;
|
||||
QScrollArea *mScrollArea;
|
||||
QTreeWidget *mMetadataTree;
|
||||
QString mFilename;
|
||||
QSize mImageSize;
|
||||
|
||||
@ -52,12 +58,18 @@ private:
|
||||
double mZoomFactor;
|
||||
QPixmap mOriginalPixmap;
|
||||
void updateZoom();
|
||||
void updateMetadataDisplay();
|
||||
|
||||
// Try to load TGA manually if Qt can't handle it
|
||||
QImage loadTGA(const QByteArray &data);
|
||||
|
||||
// Load Xbox 360 XBTX2D texture format
|
||||
QImage loadXBTX2D(const QByteArray &data);
|
||||
|
||||
// Detected image info
|
||||
QString mDetectedFormat;
|
||||
int mBitsPerPixel;
|
||||
QString mCompression;
|
||||
};
|
||||
|
||||
#endif // IMAGEPREVIEWWIDGET_H
|
||||
|
||||
165
app/main.cpp
165
app/main.cpp
@ -1,5 +1,13 @@
|
||||
#include "mainwindow.h"
|
||||
#include "splashscreen.h"
|
||||
#include "typeregistry.h"
|
||||
#include "settings.h"
|
||||
|
||||
// Application metadata
|
||||
#define APP_NAME "XPlor"
|
||||
#define APP_VERSION "1.0.8"
|
||||
#define APP_ORG_NAME "RedLine Solutions LLC."
|
||||
#define APP_ORG_DOMAIN "redline.llc"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
@ -12,6 +20,9 @@
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QTextStream>
|
||||
#include <QThread>
|
||||
#include <QImage>
|
||||
#include <QIcon>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
@ -102,6 +113,55 @@ static QJsonValue variantToJson(const QVariant& v) {
|
||||
return v.toString();
|
||||
}
|
||||
|
||||
// Generate themed app icon by replacing red with accent color
|
||||
static QIcon generateThemedIcon(const QColor &accentColor) {
|
||||
// Try loading from Qt resource first (XPlor.png)
|
||||
QImage image(":/images/images/XPlor.png");
|
||||
|
||||
if (image.isNull()) {
|
||||
// Fallback: try app.ico in app directory
|
||||
QString iconPath = QCoreApplication::applicationDirPath() + "/app.ico";
|
||||
image = QImage(iconPath);
|
||||
}
|
||||
|
||||
if (image.isNull()) {
|
||||
return QIcon();
|
||||
}
|
||||
|
||||
// Convert to ARGB32 for pixel manipulation
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
// Replace red-ish pixels with the accent color
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
QRgb *line = reinterpret_cast<QRgb*>(image.scanLine(y));
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QColor pixel(line[x]);
|
||||
int r = pixel.red();
|
||||
int g = pixel.green();
|
||||
int b = pixel.blue();
|
||||
int a = pixel.alpha();
|
||||
|
||||
// Detect red-ish pixels (high red, low green/blue)
|
||||
// The icon uses #ad0c0c (173, 12, 12) as the red color
|
||||
if (r > 100 && g < 80 && b < 80 && a > 0) {
|
||||
// Calculate how "red" this pixel is (0-1 scale)
|
||||
float intensity = static_cast<float>(r) / 255.0f;
|
||||
|
||||
// Apply the accent color with the same intensity
|
||||
QColor newColor = accentColor;
|
||||
newColor.setRed(static_cast<int>(accentColor.red() * intensity));
|
||||
newColor.setGreen(static_cast<int>(accentColor.green() * intensity));
|
||||
newColor.setBlue(static_cast<int>(accentColor.blue() * intensity));
|
||||
newColor.setAlpha(a);
|
||||
|
||||
line[x] = newColor.rgba();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QIcon(QPixmap::fromImage(image));
|
||||
}
|
||||
|
||||
// CLI output - writes to both console and log file for reliability
|
||||
static QFile* g_logFile = nullptr;
|
||||
|
||||
@ -238,30 +298,41 @@ int main(int argc, char *argv[])
|
||||
attachWindowsConsole();
|
||||
#endif
|
||||
QCoreApplication app(argc, argv);
|
||||
app.setApplicationName("XPlor");
|
||||
app.setApplicationVersion("1.0");
|
||||
app.setOrganizationDomain(APP_ORG_DOMAIN);
|
||||
app.setOrganizationName(APP_ORG_NAME);
|
||||
app.setApplicationName(APP_NAME);
|
||||
app.setApplicationVersion(APP_VERSION);
|
||||
|
||||
// Initialize log file for CLI output
|
||||
initCliLog();
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("XPlor - Call of Duty FastFile Explorer");
|
||||
parser.setApplicationDescription(
|
||||
"XPlor - Binary File Format Explorer\n\n"
|
||||
"Parse and explore binary file formats using XScript definitions.\n"
|
||||
"Supports Call of Duty FastFiles, Asura archives, and custom formats.\n\n"
|
||||
"Features:\n"
|
||||
" - XScript DSL for defining binary structures\n"
|
||||
" - Hex viewer with highlighting\n"
|
||||
" - Audio/image preview for embedded assets\n"
|
||||
" - Theme support with customizable colors"
|
||||
);
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
|
||||
QCommandLineOption cliOption(QStringList() << "cli" << "parse" << "p", "Run in CLI mode (no GUI)");
|
||||
parser.addOption(cliOption);
|
||||
|
||||
QCommandLineOption jsonOption(QStringList() << "json" << "j", "Output results as JSON");
|
||||
QCommandLineOption jsonOption(QStringList() << "json" << "j", "Output parsed data as JSON");
|
||||
parser.addOption(jsonOption);
|
||||
|
||||
QCommandLineOption gameOption(QStringList() << "game" << "g", "Game identifier", "game", "COD4");
|
||||
QCommandLineOption gameOption(QStringList() << "game" << "g", "Game identifier (e.g., COD4, COD5, MW2)", "game", "COD4");
|
||||
parser.addOption(gameOption);
|
||||
|
||||
QCommandLineOption platformOption(QStringList() << "platform" << "t", "Platform (PC, Xbox360, PS3)", "platform", "PC");
|
||||
QCommandLineOption platformOption(QStringList() << "platform" << "t", "Target platform (PC, Xbox360, PS3)", "platform", "PC");
|
||||
parser.addOption(platformOption);
|
||||
|
||||
parser.addPositionalArgument("file", "FastFile to parse");
|
||||
parser.addPositionalArgument("file", "Binary file to parse (e.g., FastFile, archive)");
|
||||
parser.process(app);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
@ -284,7 +355,85 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
QApplication a(argc, argv);
|
||||
a.setOrganizationDomain(APP_ORG_DOMAIN);
|
||||
a.setOrganizationName(APP_ORG_NAME);
|
||||
a.setApplicationName(APP_NAME);
|
||||
a.setApplicationVersion(APP_VERSION);
|
||||
|
||||
// Set themed window icon
|
||||
Theme currentTheme = Settings::instance().theme();
|
||||
QIcon themedIcon = generateThemedIcon(QColor(currentTheme.accentColor));
|
||||
if (!themedIcon.isNull()) {
|
||||
a.setWindowIcon(themedIcon);
|
||||
}
|
||||
|
||||
// Show splash screen
|
||||
SplashScreen splash;
|
||||
splash.setWaitForInteraction(false); // Normal behavior - close when finished
|
||||
splash.show();
|
||||
a.processEvents();
|
||||
|
||||
splash.setStatus("Initializing...");
|
||||
splash.setProgress(0, 100);
|
||||
a.processEvents();
|
||||
|
||||
// Load definitions with progress updates
|
||||
splash.setStatus("Loading definitions...");
|
||||
splash.setProgress(10, 100);
|
||||
a.processEvents();
|
||||
|
||||
const QString definitionsDir = QCoreApplication::applicationDirPath() + "/definitions/";
|
||||
|
||||
// First pass: count files
|
||||
QStringList defFiles;
|
||||
QDirIterator countIt(definitionsDir, {"*.xscript"}, QDir::Files, QDirIterator::Subdirectories);
|
||||
while (countIt.hasNext()) {
|
||||
defFiles.append(countIt.next());
|
||||
}
|
||||
|
||||
// Second pass: load definitions
|
||||
TypeRegistry registry;
|
||||
QVector<DefinitionLoadResult> defResults;
|
||||
int loaded = 0;
|
||||
int total = defFiles.size();
|
||||
|
||||
for (const QString& path : defFiles) {
|
||||
QString fileName = QFileInfo(path).fileName();
|
||||
splash.setStatus(QString("Loading: %1").arg(fileName));
|
||||
splash.setProgress(10 + (loaded * 70 / qMax(1, total)), 100);
|
||||
a.processEvents();
|
||||
|
||||
QFile f(path);
|
||||
if (!f.open(QIODevice::ReadOnly)) {
|
||||
defResults.append({path, fileName, false, "Failed to open file"});
|
||||
} else {
|
||||
try {
|
||||
registry.ingestScript(QString::fromUtf8(f.readAll()), path);
|
||||
defResults.append({path, fileName, true, QString()});
|
||||
} catch (const std::exception& e) {
|
||||
defResults.append({path, fileName, false, QString::fromUtf8(e.what())});
|
||||
}
|
||||
}
|
||||
loaded++;
|
||||
}
|
||||
|
||||
splash.setStatus("Creating main window...");
|
||||
splash.setProgress(85, 100);
|
||||
a.processEvents();
|
||||
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
// Pass loaded definitions to MainWindow
|
||||
w.setTypeRegistry(std::move(registry), defResults);
|
||||
|
||||
splash.setStatus("Ready");
|
||||
splash.setProgress(100, 100);
|
||||
a.processEvents();
|
||||
|
||||
QThread::msleep(200);
|
||||
|
||||
// finish() will show the main window and keep splash on top if waitForInteraction is enabled
|
||||
splash.finish(&w);
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -2,8 +2,17 @@
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QFrame>
|
||||
|
||||
#include "typeregistry.h"
|
||||
#include "settings.h"
|
||||
|
||||
struct DefinitionLoadResult {
|
||||
QString filePath;
|
||||
QString fileName;
|
||||
bool success;
|
||||
QString errorMessage;
|
||||
};
|
||||
|
||||
class XTreeWidget;
|
||||
class XTreeWidgetItem;
|
||||
@ -24,20 +33,27 @@ public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
void LoadDefinitions();
|
||||
void LoadDefinitions(); // For reparse
|
||||
void setTypeRegistry(TypeRegistry&& registry, const QVector<DefinitionLoadResult>& results);
|
||||
void LoadTreeCategories();
|
||||
void Reset();
|
||||
|
||||
const QVector<DefinitionLoadResult>& definitionResults() const { return mDefinitionResults; }
|
||||
const TypeRegistry& typeRegistry() const { return mTypeRegistry; }
|
||||
|
||||
QString pluralizeType(const QString &typeName);
|
||||
XTreeWidgetItem *ensureTypeCategoryRoot(const QString &typeName);
|
||||
XTreeWidgetItem *ensureSubcategory(XTreeWidgetItem *instanceNode, const QString &childTypeName);
|
||||
void routeNestedObjects(XTreeWidgetItem *ownerInstanceNode, const QVariantMap &vars);
|
||||
XTreeWidgetItem *addInstanceNode(XTreeWidgetItem *parent, const QString &displayName, const QString &typeName, const QVariantMap &vars);
|
||||
void organizeChildrenByExtension(XTreeWidgetItem *parent);
|
||||
void updateTreeNodeCounts(XTreeWidgetItem *node);
|
||||
static QString instanceDisplayFor(const QVariantMap &obj, const QString &fallbackType, const QString &fallbackKey = {}, std::optional<int> index = std::nullopt);
|
||||
private slots:
|
||||
void HandleLogEntry(const QString &entry);
|
||||
void HandleStatusUpdate(const QString &message, int timeout);
|
||||
void HandleProgressUpdate(const QString &message, int progress, int max);
|
||||
void applyTheme(const Theme &theme);
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
@ -50,10 +66,12 @@ private:
|
||||
XTreeWidget *mTreeWidget;
|
||||
QPlainTextEdit *mLogWidget;
|
||||
QProgressBar *mProgressBar;
|
||||
QFrame *mRibbon;
|
||||
|
||||
QHash<QString, XTreeWidgetItem*> mTypeCategoryRoots;
|
||||
TypeRegistry mTypeRegistry;
|
||||
QStringList mOpenedFilePaths; // Track opened files for reparsing
|
||||
QVector<DefinitionLoadResult> mDefinitionResults;
|
||||
|
||||
// Actions - File menu
|
||||
QAction *actionNew;
|
||||
@ -76,6 +94,7 @@ private:
|
||||
|
||||
// Actions - Tools menu
|
||||
QAction *actionRunTests;
|
||||
QAction *actionViewDefinitions;
|
||||
|
||||
// Actions - Help menu
|
||||
QAction *actionAbout;
|
||||
|
||||
@ -54,25 +54,21 @@
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<!-- Actions added in mainwindow.cpp -->
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuEdit">
|
||||
<property name="title">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
<!-- Actions added in mainwindow.cpp -->
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<!-- Actions added in mainwindow.cpp -->
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
<!-- Actions added in mainwindow.cpp -->
|
||||
</widget>
|
||||
<addaction name="MenuDef"/>
|
||||
<addaction name="menuEdit"/>
|
||||
@ -91,10 +87,7 @@
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
<!-- All actions are now created in mainwindow.cpp -->
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../data/data.qrc"/>
|
||||
</resources>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user