summaryrefslogtreecommitdiff
path: root/utils/themeeditor/gui
diff options
context:
space:
mode:
authorRobert Bieber <robby@bieberphoto.com>2010-06-17 05:37:01 +0000
committerRobert Bieber <robby@bieberphoto.com>2010-06-17 05:37:01 +0000
commitca564287ee3f48945d45c7d92be7a83452f53745 (patch)
treed6e502bb604f925240a742b3bac2c813a98c447b /utils/themeeditor/gui
parentba07b2055c7eb8f2add96f55cb52b40b9ccb3d63 (diff)
downloadrockbox-ca564287ee3f48945d45c7d92be7a83452f53745.zip
rockbox-ca564287ee3f48945d45c7d92be7a83452f53745.tar.gz
rockbox-ca564287ee3f48945d45c7d92be7a83452f53745.tar.bz2
rockbox-ca564287ee3f48945d45c7d92be7a83452f53745.tar.xz
Theme Editor: Moved source files into subdirectories
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26876 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils/themeeditor/gui')
-rw-r--r--utils/themeeditor/gui/codeeditor.cpp149
-rw-r--r--utils/themeeditor/gui/codeeditor.h106
-rw-r--r--utils/themeeditor/gui/configdocument.cpp267
-rw-r--r--utils/themeeditor/gui/configdocument.h86
-rw-r--r--utils/themeeditor/gui/configdocument.ui79
-rw-r--r--utils/themeeditor/gui/editorwindow.cpp468
-rw-r--r--utils/themeeditor/gui/editorwindow.h93
-rw-r--r--utils/themeeditor/gui/editorwindow.ui324
-rw-r--r--utils/themeeditor/gui/preferencesdialog.cpp206
-rw-r--r--utils/themeeditor/gui/preferencesdialog.h72
-rw-r--r--utils/themeeditor/gui/preferencesdialog.ui306
-rw-r--r--utils/themeeditor/gui/skindocument.cpp311
-rw-r--r--utils/themeeditor/gui/skindocument.h96
-rw-r--r--utils/themeeditor/gui/skinhighlighter.cpp172
-rw-r--r--utils/themeeditor/gui/skinhighlighter.h59
-rw-r--r--utils/themeeditor/gui/skinviewer.cpp67
-rw-r--r--utils/themeeditor/gui/skinviewer.h51
-rw-r--r--utils/themeeditor/gui/skinviewer.ui42
-rw-r--r--utils/themeeditor/gui/tabcontent.h35
19 files changed, 2989 insertions, 0 deletions
diff --git a/utils/themeeditor/gui/codeeditor.cpp b/utils/themeeditor/gui/codeeditor.cpp
new file mode 100644
index 0000000..49f4410
--- /dev/null
+++ b/utils/themeeditor/gui/codeeditor.cpp
@@ -0,0 +1,149 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * This file has been copied from Nokia's Qt Examples, with minor modifications
+ * made available under the LGPL version 2.1, as the original file was licensed
+ *
+ ****************************************************************************
+ ****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include <QtGui>
+
+#include "codeeditor.h"
+
+//![constructor]
+
+CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent)
+{
+ lineNumberArea = new LineNumberArea(this);
+
+ connect(this, SIGNAL(blockCountChanged(int)),
+ this, SLOT(updateLineNumberAreaWidth(int)));
+ connect(this, SIGNAL(updateRequest(QRect,int)),
+ this, SLOT(updateLineNumberArea(QRect,int)));
+
+ updateLineNumberAreaWidth(0);
+}
+
+//![constructor]
+
+//![extraAreaWidth]
+
+int CodeEditor::lineNumberAreaWidth()
+{
+ int digits = 1;
+ int max = qMax(1, blockCount());
+ while (max >= 10) {
+ max /= 10;
+ ++digits;
+ }
+
+ int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits;
+
+ return space;
+}
+
+//![extraAreaWidth]
+
+//![slotUpdateExtraAreaWidth]
+
+void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
+{
+ setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
+}
+
+//![slotUpdateExtraAreaWidth]
+
+//![slotUpdateRequest]
+
+void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
+{
+ if (dy)
+ lineNumberArea->scroll(0, dy);
+ else
+ lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
+
+ if (rect.contains(viewport()->rect()))
+ updateLineNumberAreaWidth(0);
+}
+
+//![slotUpdateRequest]
+
+//![resizeEvent]
+
+void CodeEditor::resizeEvent(QResizeEvent *e)
+{
+ QPlainTextEdit::resizeEvent(e);
+
+ QRect cr = contentsRect();
+ lineNumberArea->setGeometry(QRect(cr.left(), cr.top(),
+ lineNumberAreaWidth(), cr.height()));
+}
+
+//![resizeEvent]
+
+//![extraAreaPaintEvent_0]
+
+void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
+{
+ QPainter painter(lineNumberArea);
+ painter.fillRect(event->rect(), Qt::lightGray);
+
+//![extraAreaPaintEvent_0]
+
+//![extraAreaPaintEvent_1]
+ QTextBlock block = firstVisibleBlock();
+ int blockNumber = block.blockNumber();
+ int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
+ int bottom = top + (int) blockBoundingRect(block).height();
+//![extraAreaPaintEvent_1]
+
+//![extraAreaPaintEvent_2]
+ while (block.isValid() && top <= event->rect().bottom()) {
+ if (block.isVisible() && bottom >= event->rect().top()) {
+ QString number = QString::number(blockNumber + 1);
+ /* Drawing an error circle if necessary */
+ if(errors.contains(blockNumber + 1))
+ {
+ painter.fillRect(QRect(0, top, lineNumberArea->width(),
+ fontMetrics().height()), errorColor);
+ }
+ painter.setPen(Qt::black);
+ painter.drawText(0, top, lineNumberArea->width(),
+ fontMetrics().height(), Qt::AlignRight, number);
+ }
+
+ block = block.next();
+ top = bottom;
+ bottom = top + (int) blockBoundingRect(block).height();
+ ++blockNumber;
+ }
+}
+//![extraAreaPaintEvent_2]
+
diff --git a/utils/themeeditor/gui/codeeditor.h b/utils/themeeditor/gui/codeeditor.h
new file mode 100644
index 0000000..1771e31
--- /dev/null
+++ b/utils/themeeditor/gui/codeeditor.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * This file has been copied from Nokia's Qt Examples, with minor modifications
+ * made available under the LGPL version 2.1, as the original file was licensed
+ *
+ ****************************************************************************
+ ****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CODEEDITOR_H
+#define CODEEDITOR_H
+
+#include <QPlainTextEdit>
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+class QPaintEvent;
+class QResizeEvent;
+class QSize;
+class QWidget;
+QT_END_NAMESPACE
+
+class LineNumberArea;
+
+//![codeeditordefinition]
+
+class CodeEditor : public QPlainTextEdit
+{
+ Q_OBJECT
+
+public:
+ CodeEditor(QWidget *parent = 0);
+
+ void lineNumberAreaPaintEvent(QPaintEvent *event);
+ int lineNumberAreaWidth();
+ void addError(int line){ errors.append(line); }
+ void clearErrors(){ errors.clear(); }
+ void setErrorColor(QColor color){ errorColor = color; }
+ bool isError(int line){ return errors.contains(line); }
+ bool hasErrors(){ return !errors.isEmpty(); }
+
+protected:
+ void resizeEvent(QResizeEvent *event);
+
+private slots:
+ void updateLineNumberAreaWidth(int newBlockCount);
+ void updateLineNumberArea(const QRect &, int);
+
+private:
+ QWidget *lineNumberArea;
+ QList<int> errors;
+ QColor errorColor;
+};
+
+//![codeeditordefinition]
+//![extraarea]
+
+class LineNumberArea : public QWidget
+{
+public:
+ LineNumberArea(CodeEditor *editor) : QWidget(editor) {
+ codeEditor = editor;
+ }
+
+ QSize sizeHint() const {
+ return QSize(codeEditor->lineNumberAreaWidth(), 0);
+ }
+
+protected:
+ void paintEvent(QPaintEvent *event) {
+ codeEditor->lineNumberAreaPaintEvent(event);
+ }
+
+private:
+ CodeEditor *codeEditor;
+};
+
+//![extraarea]
+
+#endif
diff --git a/utils/themeeditor/gui/configdocument.cpp b/utils/themeeditor/gui/configdocument.cpp
new file mode 100644
index 0000000..a897d3b
--- /dev/null
+++ b/utils/themeeditor/gui/configdocument.cpp
@@ -0,0 +1,267 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "projectmodel.h"
+#include "configdocument.h"
+#include "ui_configdocument.h"
+
+#include <QMessageBox>
+#include <QFile>
+#include <QSettings>
+#include <QFileDialog>
+
+ConfigDocument::ConfigDocument(QMap<QString, QString>& settings, QString file,
+ QWidget *parent)
+ : TabContent(parent),
+ ui(new Ui::ConfigDocument),
+ filePath(file)
+{
+ ui->setupUi(this);
+
+ /* Populating the known keys list */
+ QFile fin(":/resources/configkeys");
+ fin.open(QFile::ReadOnly);
+
+ QStringList* container = &primaryKeys;
+ while(!fin.atEnd())
+ {
+ QString current = QString(fin.readLine());
+ if(current == "-\n")
+ container = &secondaryKeys;
+ else if(current != "\n")
+ container->append(current.trimmed());
+ }
+
+ QMap<QString, QString>::iterator i;
+ for(i = settings.begin(); i != settings.end(); i++)
+ if(i.key() != "themebase")
+ addRow(i.key(), i.value());
+
+ saved = toPlainText();
+
+ QObject::connect(ui->addKeyButton, SIGNAL(pressed()),
+ this, SLOT(addClicked()));
+}
+
+ConfigDocument::~ConfigDocument()
+{
+ delete ui;
+}
+
+void ConfigDocument::changeEvent(QEvent *e)
+{
+ QWidget::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+QString ConfigDocument::title() const
+{
+ QStringList decompose = filePath.split("/");
+ return decompose.last();
+}
+
+void ConfigDocument::save()
+{
+ QFile fout(filePath);
+
+ if(!fout.exists())
+ {
+ saveAs();
+ return;
+ }
+
+ fout.open(QFile::WriteOnly);
+ fout.write(toPlainText().toAscii());
+ fout.close();
+
+ saved = toPlainText();
+ emit titleChanged(title());
+
+}
+
+void ConfigDocument::saveAs()
+{
+ /* Determining the directory to open */
+ QString directory = filePath;
+
+ QSettings settings;
+ settings.beginGroup("ProjectModel");
+ if(directory == "")
+ directory = settings.value("defaultDirectory", "").toString();
+
+ filePath = QFileDialog::getSaveFileName(this, tr("Save Document"),
+ directory,
+ ProjectModel::fileFilter());
+ directory = filePath;
+ if(filePath == "")
+ return;
+
+ directory.chop(filePath.length() - filePath.lastIndexOf('/') - 1);
+ settings.setValue("defaultDirectory", directory);
+ settings.endGroup();
+
+ QFile fout(filePath);
+ fout.open(QFile::WriteOnly);
+ fout.write(toPlainText().toAscii());
+ fout.close();
+
+ saved = toPlainText();
+ emit titleChanged(title());
+ emit configFileChanged(file());
+
+}
+
+bool ConfigDocument::requestClose()
+{
+ if(toPlainText() != saved)
+ {
+ /* Spawning the "Are you sure?" dialog */
+ QMessageBox confirm(this);
+ confirm.setWindowTitle(tr("Confirm Close"));
+ confirm.setText(title() + tr(" has been modified."));
+ confirm.setInformativeText(tr("Do you want to save your changes?"));
+ confirm.setStandardButtons(QMessageBox::Save | QMessageBox::Discard
+ | QMessageBox::Cancel);
+ confirm.setDefaultButton(QMessageBox::Save);
+ int confirmation = confirm.exec();
+
+ switch(confirmation)
+ {
+ case QMessageBox::Save:
+ save();
+ /* After calling save, make sure the user actually went through */
+ if(toPlainText() != saved)
+ return false;
+ else
+ return true;
+
+ case QMessageBox::Discard:
+ return true;
+
+ case QMessageBox::Cancel:
+ return false;
+ }
+ }
+ return true;
+}
+
+QString ConfigDocument::toPlainText() const
+{
+ QString buffer = "";
+
+ for(int i = 0; i < keys.count(); i++)
+ {
+ buffer += keys[i]->currentText();
+ buffer += ":";
+ buffer += values[i]->text();
+ buffer += "\n";
+ }
+
+ return buffer;
+}
+
+void ConfigDocument::addRow(QString key, QString value)
+{
+ QHBoxLayout* layout = new QHBoxLayout();
+ QComboBox* keyEdit = new QComboBox(this);
+ QLineEdit* valueEdit = new QLineEdit(value, this);
+ QPushButton* delButton = new QPushButton(tr("-"), this);
+ QLabel* label = new QLabel(":");
+
+ /* Loading the combo box options */
+ keyEdit->setInsertPolicy(QComboBox::InsertAlphabetically);
+ keyEdit->setEditable(true);
+ keyEdit->addItems(primaryKeys);
+ keyEdit->insertSeparator(keyEdit->count());
+ keyEdit->addItems(secondaryKeys);
+ if(keyEdit->findText(key) != -1)
+ keyEdit->setCurrentIndex(keyEdit->findText(key));
+ else
+ keyEdit->setEditText(key);
+
+ layout->addWidget(keyEdit);
+ layout->addWidget(label);
+ layout->addWidget(valueEdit);
+ layout->addWidget(delButton);
+
+ delButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
+ delButton->setMaximumWidth(35);
+
+ QObject::connect(delButton, SIGNAL(clicked()),
+ this, SLOT(deleteClicked()));
+ QObject::connect(keyEdit, SIGNAL(currentIndexChanged(QString)),
+ this, SLOT(textChanged()));
+ QObject::connect(keyEdit, SIGNAL(textChanged(QString)),
+ this, SLOT(textChanged()));
+ QObject::connect(valueEdit, SIGNAL(textChanged(QString)),
+ this, SLOT(textChanged()));
+
+ ui->configBoxes->addLayout(layout);
+
+ containers.append(layout);
+ keys.append(keyEdit);
+ values.append(valueEdit);
+ deleteButtons.append(delButton);
+ labels.append(label);
+
+}
+
+void ConfigDocument::deleteClicked()
+{
+ QPushButton* button = dynamic_cast<QPushButton*>(sender());
+ int row = deleteButtons.indexOf(button);
+
+ deleteButtons[row]->deleteLater();
+ keys[row]->deleteLater();
+ values[row]->deleteLater();
+ containers[row]->deleteLater();
+ labels[row]->deleteLater();
+
+ deleteButtons.removeAt(row);
+ keys.removeAt(row);
+ values.removeAt(row);
+ containers.removeAt(row);
+ labels.removeAt(row);
+
+ if(saved != toPlainText())
+ emit titleChanged(title() + "*");
+ else
+ emit titleChanged(title());
+}
+
+void ConfigDocument::addClicked()
+{
+ addRow(tr("Key"), tr("Value"));
+}
+
+void ConfigDocument::textChanged()
+{
+ if(toPlainText() != saved)
+ emit titleChanged(title() + "*");
+ else
+ emit titleChanged(title());
+}
diff --git a/utils/themeeditor/gui/configdocument.h b/utils/themeeditor/gui/configdocument.h
new file mode 100644
index 0000000..8493c7a
--- /dev/null
+++ b/utils/themeeditor/gui/configdocument.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIGDOCUMENT_H
+#define CONFIGDOCUMENT_H
+
+#include <QHBoxLayout>
+#include <QLineEdit>
+#include <QComboBox>
+#include <QPushButton>
+#include <QWidget>
+#include <QLabel>
+#include <QMap>
+
+#include "tabcontent.h"
+
+namespace Ui {
+ class ConfigDocument;
+}
+
+class ConfigDocument : public TabContent {
+ Q_OBJECT
+public:
+ ConfigDocument(QMap<QString, QString>& settings, QString file,
+ QWidget *parent = 0);
+ virtual ~ConfigDocument();
+
+ TabType type() const{ return TabContent::Config; }
+ QString file() const{ return filePath; }
+ QString title() const;
+
+ QString toPlainText() const;
+
+ void save();
+ void saveAs();
+
+ bool requestClose();
+
+protected:
+ void changeEvent(QEvent *e);
+
+signals:
+ void configFileChanged(QString);
+
+private slots:
+ void deleteClicked();
+ void addClicked();
+ void textChanged();
+
+
+private:
+ Ui::ConfigDocument *ui;
+ QList<QHBoxLayout*> containers;
+ QList<QComboBox*> keys;
+ QList<QLineEdit*> values;
+ QList<QPushButton*> deleteButtons;
+ QList<QLabel*> labels;
+
+ QStringList primaryKeys;
+ QStringList secondaryKeys;
+
+ QString filePath;
+ QString saved;
+
+ void addRow(QString key, QString value);
+};
+
+#endif // CONFIGDOCUMENT_H
diff --git a/utils/themeeditor/gui/configdocument.ui b/utils/themeeditor/gui/configdocument.ui
new file mode 100644
index 0000000..e2f9e7f
--- /dev/null
+++ b/utils/themeeditor/gui/configdocument.ui
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigDocument</class>
+ <widget class="QWidget" name="ConfigDocument">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>422</width>
+ <height>299</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>402</width>
+ <height>244</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QVBoxLayout" name="configBoxes"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="addKeyButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>35</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>+</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/utils/themeeditor/gui/editorwindow.cpp b/utils/themeeditor/gui/editorwindow.cpp
new file mode 100644
index 0000000..675520d
--- /dev/null
+++ b/utils/themeeditor/gui/editorwindow.cpp
@@ -0,0 +1,468 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "editorwindow.h"
+#include "projectmodel.h"
+#include "ui_editorwindow.h"
+
+#include <QDesktopWidget>
+#include <QFileSystemModel>
+#include <QSettings>
+#include <QFileDialog>
+#include <QGraphicsScene>
+
+EditorWindow::EditorWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::EditorWindow)
+{
+ ui->setupUi(this);
+ prefs = new PreferencesDialog(this);
+ project = 0;
+ loadSettings();
+ setupUI();
+ setupMenus();
+}
+
+void EditorWindow::loadTabFromSkinFile(QString fileName)
+{
+ /* Checking to see if the file is already open */
+ for(int i = 0; i < ui->editorTabs->count(); i++)
+ {
+ TabContent* current = dynamic_cast<TabContent*>
+ (ui->editorTabs->widget(i));
+ if(current->file() == fileName)
+ {
+ ui->editorTabs->setCurrentIndex(i);
+ return;
+ }
+ }
+
+ /* Adding a new document*/
+ SkinDocument* doc = new SkinDocument(parseStatus, fileName);
+ addTab(doc);
+ ui->editorTabs->setCurrentWidget(doc);
+
+}
+
+void EditorWindow::loadConfigTab(ConfigDocument* doc)
+{
+ for(int i = 0; i < ui->editorTabs->count(); i++)
+ {
+ TabContent* current = dynamic_cast<TabContent*>
+ (ui->editorTabs->widget(i));
+ if(current->file() == doc->file())
+ {
+ ui->editorTabs->setCurrentIndex(i);
+ doc->deleteLater();
+ return;
+ }
+ }
+
+ addTab(doc);
+ ui->editorTabs->setCurrentWidget(doc);
+
+ QObject::connect(doc, SIGNAL(titleChanged(QString)),
+ this, SLOT(tabTitleChanged(QString)));
+}
+
+void EditorWindow::loadSettings()
+{
+
+ QSettings settings;
+
+ /* Main Window location */
+ settings.beginGroup("EditorWindow");
+ QSize size = settings.value("size").toSize();
+ QPoint pos = settings.value("position").toPoint();
+ QByteArray state = settings.value("state").toByteArray();
+ settings.endGroup();
+
+ if(!(size.isNull() || pos.isNull() || state.isNull()))
+ {
+ resize(size);
+ move(pos);
+ restoreState(state);
+ }
+
+}
+
+void EditorWindow::saveSettings()
+{
+
+ QSettings settings;
+
+ /* Saving window and panel positions */
+ settings.beginGroup("EditorWindow");
+ settings.setValue("position", pos());
+ settings.setValue("size", size());
+ settings.setValue("state", saveState());
+ settings.endGroup();
+}
+
+void EditorWindow::setupUI()
+{
+ /* Connecting the tab bar signals */
+ QObject::connect(ui->editorTabs, SIGNAL(currentChanged(int)),
+ this, SLOT(shiftTab(int)));
+ QObject::connect(ui->editorTabs, SIGNAL(tabCloseRequested(int)),
+ this, SLOT(closeTab(int)));
+
+ /* Connecting the code gen button */
+ QObject::connect(ui->fromTree, SIGNAL(pressed()),
+ this, SLOT(updateCurrent()));
+
+ /* Connecting the preferences dialog */
+ QObject::connect(ui->actionPreferences, SIGNAL(triggered()),
+ prefs, SLOT(exec()));
+
+ /* Setting up the parse status label */
+ parseStatus = new QLabel(this);
+ ui->statusbar->addPermanentWidget(parseStatus);
+
+ /* Setting the selection for parse tree highlighting initially NULL */
+ parseTreeSelection = 0;
+
+ /* Adding the skin viewer */
+ viewer = new SkinViewer(this);
+ ui->skinPreviewLayout->addWidget(viewer);
+
+ //TODO: Remove this test code
+ QGraphicsScene* test = new QGraphicsScene();
+ test->addRect(0,0,50,50);
+
+ viewer->setScene(test);
+}
+
+void EditorWindow::setupMenus()
+{
+ /* Connecting panel show actions */
+ QObject::connect(ui->actionFile_Panel, SIGNAL(triggered()),
+ this, SLOT(showPanel()));
+ QObject::connect(ui->actionDisplay_Panel, SIGNAL(triggered()),
+ this, SLOT(showPanel()));
+ QObject::connect(ui->actionPreview_Panel, SIGNAL(triggered()),
+ this, SLOT(showPanel()));
+
+ /* Connecting the document management actions */
+ QObject::connect(ui->actionNew_Document, SIGNAL(triggered()),
+ this, SLOT(newTab()));
+ QObject::connect(ui->actionToolbarNew, SIGNAL(triggered()),
+ this, SLOT(newTab()));
+
+ QObject::connect(ui->actionClose_Document, SIGNAL(triggered()),
+ this, SLOT(closeCurrent()));
+
+ QObject::connect(ui->actionSave_Document, SIGNAL(triggered()),
+ this, SLOT(saveCurrent()));
+ QObject::connect(ui->actionSave_Document_As, SIGNAL(triggered()),
+ this, SLOT(saveCurrentAs()));
+ QObject::connect(ui->actionToolbarSave, SIGNAL(triggered()),
+ this, SLOT(saveCurrent()));
+
+ QObject::connect(ui->actionOpen_Document, SIGNAL(triggered()),
+ this, SLOT(openFile()));
+ QObject::connect(ui->actionToolbarOpen, SIGNAL(triggered()),
+ this, SLOT(openFile()));
+
+ QObject::connect(ui->actionOpen_Project, SIGNAL(triggered()),
+ this, SLOT(openProject()));
+}
+
+void EditorWindow::addTab(TabContent *doc)
+{
+ ui->editorTabs->addTab(doc, doc->title());
+
+ /* Connecting to title change events */
+ QObject::connect(doc, SIGNAL(titleChanged(QString)),
+ this, SLOT(tabTitleChanged(QString)));
+ QObject::connect(doc, SIGNAL(lineChanged(int)),
+ this, SLOT(lineChanged(int)));
+
+ /* Connecting to settings change events */
+ if(doc->type() == TabContent::Skin)
+ dynamic_cast<SkinDocument*>(doc)->connectPrefs(prefs);
+}
+
+
+void EditorWindow::newTab()
+{
+ SkinDocument* doc = new SkinDocument(parseStatus);
+ addTab(doc);
+ ui->editorTabs->setCurrentWidget(doc);
+}
+
+void EditorWindow::shiftTab(int index)
+{
+ TabContent* widget = dynamic_cast<TabContent*>
+ (ui->editorTabs->currentWidget());
+ if(index < 0)
+ {
+ ui->parseTree->setModel(0);
+ ui->actionSave_Document->setEnabled(false);
+ ui->actionSave_Document_As->setEnabled(false);
+ ui->actionClose_Document->setEnabled(false);
+ ui->actionToolbarSave->setEnabled(false);
+ ui->fromTree->setEnabled(false);
+ }
+ else if(widget->type() == TabContent::Config)
+ {
+ ui->actionSave_Document->setEnabled(true);
+ ui->actionSave_Document_As->setEnabled(true);
+ ui->actionClose_Document->setEnabled(true);
+ ui->actionToolbarSave->setEnabled(true);
+ }
+ else
+ {
+ /* Syncing the tree view and the status bar */
+ SkinDocument* doc = dynamic_cast<SkinDocument*>(widget);
+ ui->parseTree->setModel(doc->getModel());
+ parseStatus->setText(doc->getStatus());
+
+ ui->actionSave_Document->setEnabled(true);
+ ui->actionSave_Document_As->setEnabled(true);
+ ui->actionClose_Document->setEnabled(true);
+ ui->actionToolbarSave->setEnabled(true);
+ ui->fromTree->setEnabled(true);
+
+ sizeColumns();
+
+ }
+}
+
+bool EditorWindow::closeTab(int index)
+{
+ TabContent* widget = dynamic_cast<TabContent*>
+ (ui->editorTabs->widget(index));
+ if(widget->requestClose())
+ {
+ ui->editorTabs->removeTab(index);
+ widget->deleteLater();
+ return true;
+ }
+
+ return false;
+}
+
+void EditorWindow::closeCurrent()
+{
+ closeTab(ui->editorTabs->currentIndex());
+}
+
+void EditorWindow::saveCurrent()
+{
+ if(ui->editorTabs->currentIndex() >= 0)
+ dynamic_cast<TabContent*>(ui->editorTabs->currentWidget())->save();
+}
+
+void EditorWindow::saveCurrentAs()
+{
+ if(ui->editorTabs->currentIndex() >= 0)
+ dynamic_cast<TabContent*>(ui->editorTabs->currentWidget())->saveAs();
+}
+
+void EditorWindow::openFile()
+{
+ QStringList fileNames;
+ QSettings settings;
+
+ settings.beginGroup("SkinDocument");
+ QString directory = settings.value("defaultDirectory", "").toString();
+ fileNames = QFileDialog::getOpenFileNames(this, tr("Open Files"), directory,
+ SkinDocument::fileFilter());
+
+ for(int i = 0; i < fileNames.count(); i++)
+ {
+ if(!QFile::exists(fileNames[i]))
+ continue;
+
+ QString current = fileNames[i];
+
+ loadTabFromSkinFile(current);
+
+ /* And setting the new default directory */
+ current.chop(current.length() - current.lastIndexOf('/') - 1);
+ settings.setValue("defaultDirectory", current);
+
+ }
+
+ settings.endGroup();
+}
+
+void EditorWindow::openProject()
+{
+ QString fileName;
+ QSettings settings;
+
+ settings.beginGroup("ProjectModel");
+ QString directory = settings.value("defaultDirectory", "").toString();
+ fileName = QFileDialog::getOpenFileName(this, tr("Open Project"), directory,
+ ProjectModel::fileFilter());
+
+ if(QFile::exists(fileName))
+ {
+
+ if(project)
+ delete project;
+
+ project = new ProjectModel(fileName, this);
+ ui->projectTree->setModel(project);
+
+ QObject::connect(ui->projectTree, SIGNAL(activated(QModelIndex)),
+ project, SLOT(activated(QModelIndex)));
+
+ fileName.chop(fileName.length() - fileName.lastIndexOf('/') - 1);
+ settings.setValue("defaultDirectory", fileName);
+
+ }
+
+ settings.endGroup();
+
+}
+
+void EditorWindow::configFileChanged(QString configFile)
+{
+
+ QSettings settings;
+
+ settings.beginGroup("ProjectModel");
+
+ if(QFile::exists(configFile))
+ {
+
+ if(project)
+ delete project;
+
+ project = new ProjectModel(configFile, this);
+ ui->projectTree->setModel(project);
+
+ QObject::connect(ui->projectTree, SIGNAL(activated(QModelIndex)),
+ project, SLOT(activated(QModelIndex)));
+
+ configFile.chop(configFile.length() - configFile.lastIndexOf('/') - 1);
+ settings.setValue("defaultDirectory", configFile);
+
+ }
+
+ settings.endGroup();
+
+}
+
+void EditorWindow::tabTitleChanged(QString title)
+{
+ TabContent* sender = dynamic_cast<TabContent*>(QObject::sender());
+ ui->editorTabs->setTabText(ui->editorTabs->indexOf(sender), title);
+}
+
+void EditorWindow::showPanel()
+{
+ if(sender() == ui->actionFile_Panel)
+ ui->projectDock->setVisible(true);
+ if(sender() == ui->actionPreview_Panel)
+ ui->skinPreviewDock->setVisible(true);
+ if(sender() == ui->actionDisplay_Panel)
+ ui->parseTreeDock->setVisible(true);
+}
+
+void EditorWindow::closeEvent(QCloseEvent* event)
+{
+
+ saveSettings();
+
+ /* Closing all the tabs */
+ for(int i = 0; i < ui->editorTabs->count(); i++)
+ {
+ if(!dynamic_cast<TabContent*>
+ (ui->editorTabs->widget(i))->requestClose())
+ {
+ event->ignore();
+ return;
+ }
+ }
+
+ event->accept();
+}
+
+void EditorWindow::updateCurrent()
+{
+ if(ui->editorTabs->currentIndex() < 0)
+ return;
+
+ dynamic_cast<SkinDocument*>
+ (ui->editorTabs->currentWidget())->genCode();
+}
+
+void EditorWindow::lineChanged(int line)
+{
+ ui->parseTree->collapseAll();
+ if(parseTreeSelection)
+ parseTreeSelection->deleteLater();
+ ParseTreeModel* model = dynamic_cast<ParseTreeModel*>
+ (ui->parseTree->model());
+ parseTreeSelection = new QItemSelectionModel(model);
+ expandLine(model, QModelIndex(), line);
+ sizeColumns();
+ ui->parseTree->setSelectionModel(parseTreeSelection);
+
+}
+
+void EditorWindow::expandLine(ParseTreeModel* model, QModelIndex parent,
+ int line)
+{
+ for(int i = 0; i < model->rowCount(parent); i++)
+ {
+ QModelIndex dataType = model->index(i, ParseTreeModel::typeColumn,
+ parent);
+ QModelIndex dataVal = model->index(i, ParseTreeModel::valueColumn,
+ parent);
+ QModelIndex data = model->index(i, ParseTreeModel::lineColumn, parent);
+ QModelIndex recurse = model->index(i, 0, parent);
+
+ expandLine(model, recurse, line);
+
+ if(model->data(data, Qt::DisplayRole) == line)
+ {
+ ui->parseTree->expand(parent);
+ ui->parseTree->expand(data);
+ ui->parseTree->scrollTo(parent, QAbstractItemView::PositionAtTop);
+
+ parseTreeSelection->select(data, QItemSelectionModel::Select);
+ parseTreeSelection->select(dataType, QItemSelectionModel::Select);
+ parseTreeSelection->select(dataVal, QItemSelectionModel::Select);
+ }
+
+ }
+}
+
+void EditorWindow::sizeColumns()
+{
+ /* Setting the column widths */
+ ui->parseTree->resizeColumnToContents(ParseTreeModel::lineColumn);
+ ui->parseTree->resizeColumnToContents(ParseTreeModel::typeColumn);
+ ui->parseTree->resizeColumnToContents(ParseTreeModel::valueColumn);
+}
+
+EditorWindow::~EditorWindow()
+{
+ delete ui;
+ delete prefs;
+ if(project)
+ delete project;
+}
diff --git a/utils/themeeditor/gui/editorwindow.h b/utils/themeeditor/gui/editorwindow.h
new file mode 100644
index 0000000..6f73735
--- /dev/null
+++ b/utils/themeeditor/gui/editorwindow.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef EDITORWINDOW_H
+#define EDITORWINDOW_H
+
+#include <QMainWindow>
+#include <QLabel>
+#include <QItemSelectionModel>
+
+#include "parsetreemodel.h"
+#include "skinhighlighter.h"
+#include "skindocument.h"
+#include "configdocument.h"
+#include "preferencesdialog.h"
+#include "skinviewer.h"
+
+class ProjectModel;
+class TabContent;
+
+namespace Ui
+{
+ class EditorWindow;
+}
+
+class EditorWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ EditorWindow(QWidget *parent = 0);
+ ~EditorWindow();
+
+ /* A public function so external widgets can load files */
+ void loadTabFromSkinFile(QString fileName);
+ void loadConfigTab(ConfigDocument* doc);
+
+protected:
+ virtual void closeEvent(QCloseEvent* event);
+
+public slots:
+ void configFileChanged(QString configFile);
+
+private slots:
+ void showPanel();
+ void newTab();
+ void shiftTab(int index);
+ bool closeTab(int index);
+ void closeCurrent();
+ void saveCurrent();
+ void saveCurrentAs();
+ void openFile();
+ void openProject();
+ void tabTitleChanged(QString title);
+ void updateCurrent(); /* Generates code in the current tab */
+ void lineChanged(int line); /* Used for auto-expand */
+
+private:
+ /* Setup functions */
+ void loadSettings();
+ void saveSettings();
+ void setupUI();
+ void setupMenus();
+ void addTab(TabContent* doc);
+ void expandLine(ParseTreeModel* model, QModelIndex parent, int line);
+ void sizeColumns();
+
+ Ui::EditorWindow *ui;
+ PreferencesDialog* prefs;
+ QLabel* parseStatus;
+ ProjectModel* project;
+ QItemSelectionModel* parseTreeSelection;
+ SkinViewer* viewer;
+};
+
+#endif // EDITORWINDOW_H
diff --git a/utils/themeeditor/gui/editorwindow.ui b/utils/themeeditor/gui/editorwindow.ui
new file mode 100644
index 0000000..10e2c52
--- /dev/null
+++ b/utils/themeeditor/gui/editorwindow.ui
@@ -0,0 +1,324 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>EditorWindow</class>
+ <widget class="QMainWindow" name="EditorWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>628</width>
+ <height>433</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Rockbox Theme Editor</string>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/resources/resources/windowicon.png</normaloff>:/resources/resources/windowicon.png</iconset>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="editorTabs">
+ <property name="currentIndex">
+ <number>-1</number>
+ </property>
+ <property name="tabsClosable">
+ <bool>true</bool>
+ </property>
+ <property name="movable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>628</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menuFile">
+ <property name="title">
+ <string>&amp;File</string>
+ </property>
+ <addaction name="actionNew_Document"/>
+ <addaction name="actionOpen_Document"/>
+ <addaction name="actionOpen_Project"/>
+ <addaction name="separator"/>
+ <addaction name="actionClose_Document"/>
+ <addaction name="separator"/>
+ <addaction name="actionSave_Document"/>
+ <addaction name="actionSave_Document_As"/>
+ <addaction name="separator"/>
+ <addaction name="actionPreferences"/>
+ <addaction name="separator"/>
+ <addaction name="actionQuit"/>
+ </widget>
+ <widget class="QMenu" name="menuView">
+ <property name="title">
+ <string>&amp;View</string>
+ </property>
+ <addaction name="actionPreview_Panel"/>
+ <addaction name="actionDisplay_Panel"/>
+ <addaction name="actionFile_Panel"/>
+ </widget>
+ <addaction name="menuFile"/>
+ <addaction name="menuView"/>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ <widget class="QDockWidget" name="skinPreviewDock">
+ <property name="windowTitle">
+ <string>Skin Preview</string>
+ </property>
+ <attribute name="dockWidgetArea">
+ <number>2</number>
+ </attribute>
+ <widget class="QWidget" name="skinPreviewContents">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QVBoxLayout" name="skinPreviewLayout"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <widget class="QToolBar" name="toolBar">
+ <property name="windowTitle">
+ <string>toolBar</string>
+ </property>
+ <attribute name="toolBarArea">
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionToolbarNew"/>
+ <addaction name="actionToolbarOpen"/>
+ <addaction name="actionToolbarSave"/>
+ </widget>
+ <widget class="QDockWidget" name="projectDock">
+ <property name="windowTitle">
+ <string>Project</string>
+ </property>
+ <attribute name="dockWidgetArea">
+ <number>1</number>
+ </attribute>
+ <widget class="QWidget" name="dockWidgetContents_2">
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QListView" name="projectTree"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <widget class="QDockWidget" name="parseTreeDock">
+ <property name="windowTitle">
+ <string>Parse Tree</string>
+ </property>
+ <attribute name="dockWidgetArea">
+ <number>2</number>
+ </attribute>
+ <widget class="QWidget" name="dockWidgetContents_3">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QTreeView" name="parseTree">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::MultiSelection</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="fromTree">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Update Code</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <action name="actionQuit">
+ <property name="text">
+ <string>&amp;Quit</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+Q</string>
+ </property>
+ </action>
+ <action name="actionDisplay_Panel">
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Parse &amp;Tree Panel</string>
+ </property>
+ </action>
+ <action name="actionPreferences">
+ <property name="text">
+ <string>&amp;Preferences</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+P</string>
+ </property>
+ </action>
+ <action name="actionFile_Panel">
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>P&amp;roject Panel</string>
+ </property>
+ </action>
+ <action name="actionPreview_Panel">
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Preview Panel</string>
+ </property>
+ </action>
+ <action name="actionNew_Document">
+ <property name="text">
+ <string>&amp;New Document</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+N</string>
+ </property>
+ </action>
+ <action name="actionOpen_Document">
+ <property name="text">
+ <string>&amp;Open Document</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+O</string>
+ </property>
+ </action>
+ <action name="actionSave_Document">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Save Document</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+S</string>
+ </property>
+ </action>
+ <action name="actionClose_Document">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Close Document</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+W</string>
+ </property>
+ </action>
+ <action name="actionSave_Document_As">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Save Document &amp;As</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+Shift+S</string>
+ </property>
+ </action>
+ <action name="actionToolbarNew">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/resources/resources/document-new.png</normaloff>:/resources/resources/document-new.png</iconset>
+ </property>
+ <property name="text">
+ <string>ToolbarNew</string>
+ </property>
+ <property name="toolTip">
+ <string>New</string>
+ </property>
+ </action>
+ <action name="actionToolbarOpen">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/resources/resources/document-open.png</normaloff>:/resources/resources/document-open.png</iconset>
+ </property>
+ <property name="text">
+ <string>ToolbarOpen</string>
+ </property>
+ <property name="toolTip">
+ <string>Open</string>
+ </property>
+ </action>
+ <action name="actionToolbarSave">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/resources/resources/document-save.png</normaloff>:/resources/resources/document-save.png</iconset>
+ </property>
+ <property name="text">
+ <string>ToolbarSave</string>
+ </property>
+ <property name="toolTip">
+ <string>Save</string>
+ </property>
+ </action>
+ <action name="actionOpen_Project">
+ <property name="text">
+ <string>Open P&amp;roject</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+Shift+O</string>
+ </property>
+ </action>
+ </widget>
+ <tabstops>
+ <tabstop>projectTree</tabstop>
+ <tabstop>parseTree</tabstop>
+ <tabstop>fromTree</tabstop>
+ <tabstop>editorTabs</tabstop>
+ </tabstops>
+ <resources>
+ <include location="resources.qrc"/>
+ </resources>
+ <connections>
+ <connection>
+ <sender>actionQuit</sender>
+ <signal>activated()</signal>
+ <receiver>EditorWindow</receiver>
+ <slot>close()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>-1</x>
+ <y>-1</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>299</x>
+ <y>199</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/utils/themeeditor/gui/preferencesdialog.cpp b/utils/themeeditor/gui/preferencesdialog.cpp
new file mode 100644
index 0000000..8cd9665
--- /dev/null
+++ b/utils/themeeditor/gui/preferencesdialog.cpp
@@ -0,0 +1,206 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "preferencesdialog.h"
+#include "ui_preferencesdialog.h"
+
+#include <QSettings>
+#include <QColorDialog>
+
+PreferencesDialog::PreferencesDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::PreferencesDialog)
+{
+ ui->setupUi(this);
+ setupUI();
+ loadSettings();
+}
+
+PreferencesDialog::~PreferencesDialog()
+{
+ delete ui;
+}
+
+void PreferencesDialog::loadSettings()
+{
+ loadColors();
+ loadFont();
+}
+
+void PreferencesDialog::loadColors()
+{
+
+ QSettings settings;
+
+ /* The list of buttons from the SkinHighlighter group */
+
+ settings.beginGroup("SkinHighlighter");
+
+ commentColor = settings.value("commentColor",
+ QColor(0, 180, 0)).value<QColor>();
+ setButtonColor(ui->commentButton, commentColor);
+
+ escapedColor = settings.value("escapedColor",
+ QColor(120,120,120)).value<QColor>();
+ setButtonColor(ui->escapedButton, escapedColor);
+
+ conditionalColor = settings.value("conditionalColor",
+ QColor(0, 0, 180)).value<QColor>();
+ setButtonColor(ui->conditionalButton, conditionalColor);
+
+ tagColor = settings.value("tagColor",
+ QColor(180, 0, 0)).value<QColor>();
+ setButtonColor(ui->tagButton, tagColor);
+
+ settings.endGroup();
+
+ /* Buttons from the editor group */
+ settings.beginGroup("SkinDocument");
+
+ fgColor = settings.value("fgColor", Qt::black).value<QColor>();
+ setButtonColor(ui->fgButton, fgColor);
+
+ bgColor = settings.value("bgColor", Qt::white).value<QColor>();
+ setButtonColor(ui->bgButton, bgColor);
+
+ errorColor = settings.value("errorColor", Qt::red).value<QColor>();
+ setButtonColor(ui->errorButton, errorColor);
+
+ settings.endGroup();
+}
+
+void PreferencesDialog::loadFont()
+{
+ QSettings settings;
+ settings.beginGroup("SkinDocument");
+
+ QFont def("Monospace");
+ def.setStyleHint(QFont::TypeWriter);
+
+ QVariant family = settings.value("fontFamily", def);
+ int size = settings.value("fontSize", 12).toInt();
+
+ settings.endGroup();
+
+ ui->fontSelect->setCurrentFont(family.value<QFont>());
+ ui->fontSize->setValue(size);
+
+}
+
+void PreferencesDialog::saveSettings()
+{
+ saveColors();
+ saveFont();
+}
+
+void PreferencesDialog::saveColors()
+{
+ QSettings settings;
+
+ /* Saving the editor colors */
+ settings.beginGroup("SkinDocument");
+
+ settings.setValue("fgColor", fgColor);
+ settings.setValue("bgColor", bgColor);
+ settings.setValue("errorColor", errorColor);
+
+ settings.endGroup();
+
+ /* Saving the highlighting colors */
+ settings.beginGroup("SkinHighlighter");
+
+ settings.setValue("tagColor", tagColor);
+ settings.setValue("commentColor", commentColor);
+ settings.setValue("conditionalColor", conditionalColor);
+ settings.setValue("escapedColor", escapedColor);
+
+ settings.endGroup();
+}
+
+void PreferencesDialog::saveFont()
+{
+ QSettings settings;
+ settings.beginGroup("SkinDocument");
+
+ settings.setValue("fontFamily", ui->fontSelect->currentFont());
+ settings.setValue("fontSize", ui->fontSize->value());
+
+ settings.endGroup();
+}
+
+void PreferencesDialog::setupUI()
+{
+ /* Connecting color buttons */
+ QList<QPushButton*> buttons;
+ buttons.append(ui->bgButton);
+ buttons.append(ui->fgButton);
+ buttons.append(ui->commentButton);
+ buttons.append(ui->tagButton);
+ buttons.append(ui->conditionalButton);
+ buttons.append(ui->escapedButton);
+ buttons.append(ui->errorButton);
+
+ for(int i = 0; i < buttons.count(); i++)
+ QObject::connect(buttons[i], SIGNAL(pressed()),
+ this, SLOT(colorClicked()));
+}
+
+void PreferencesDialog::colorClicked()
+{
+ QColor* toEdit = 0, newColor;
+
+ if(QObject::sender() == ui->bgButton)
+ toEdit = &bgColor;
+ else if(QObject::sender() == ui->fgButton)
+ toEdit = &fgColor;
+ else if(QObject::sender() == ui->commentButton)
+ toEdit = &commentColor;
+ else if(QObject::sender() == ui->tagButton)
+ toEdit = &tagColor;
+ else if(QObject::sender() == ui->conditionalButton)
+ toEdit = &conditionalColor;
+ else if(QObject::sender() == ui->escapedButton)
+ toEdit = &escapedColor;
+ else if(QObject::sender() == ui->errorButton)
+ toEdit = &errorColor;
+
+ if(!toEdit)
+ return;
+
+ newColor = QColorDialog::getColor(*toEdit, this);
+ if (newColor.isValid())
+ {
+ *toEdit = newColor;
+ setButtonColor(dynamic_cast<QPushButton*>(QObject::sender()), *toEdit);
+ }
+}
+
+void PreferencesDialog::accept()
+{
+ saveSettings();
+ QDialog::accept();
+}
+
+void PreferencesDialog::reject()
+{
+ loadSettings();
+ QDialog::reject();
+}
diff --git a/utils/themeeditor/gui/preferencesdialog.h b/utils/themeeditor/gui/preferencesdialog.h
new file mode 100644
index 0000000..e28a830
--- /dev/null
+++ b/utils/themeeditor/gui/preferencesdialog.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef PREFERENCESDIALOG_H
+#define PREFERENCESDIALOG_H
+
+#include <QDialog>
+#include <QPushButton>
+
+namespace Ui {
+ class PreferencesDialog;
+}
+
+class PreferencesDialog : public QDialog {
+ Q_OBJECT
+public:
+ PreferencesDialog(QWidget *parent = 0);
+ ~PreferencesDialog();
+
+ static void setButtonColor(QPushButton* button, QColor color)
+ {
+ QString style = "* { background:" + color.name() + "}";
+ button->setStyleSheet(style);
+ }
+
+public slots:
+ void accept();
+ void reject();
+
+private slots:
+ void colorClicked();
+
+private:
+ Ui::PreferencesDialog *ui;
+
+ void loadSettings();
+ void loadColors();
+ void loadFont();
+ void saveSettings();
+ void saveColors();
+ void saveFont();
+
+ void setupUI();
+
+ QColor fgColor;
+ QColor bgColor;
+ QColor errorColor;
+ QColor commentColor;
+ QColor escapedColor;
+ QColor tagColor;
+ QColor conditionalColor;
+};
+
+#endif // PREFERENCESDIALOG_H
diff --git a/utils/themeeditor/gui/preferencesdialog.ui b/utils/themeeditor/gui/preferencesdialog.ui
new file mode 100644
index 0000000..1da7811
--- /dev/null
+++ b/utils/themeeditor/gui/preferencesdialog.ui
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PreferencesDialog</class>
+ <widget class="QDialog" name="PreferencesDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>370</width>
+ <height>370</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Preferences</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="prefsGroups">
+ <property name="tabPosition">
+ <enum>QTabWidget::North</enum>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab_2">
+ <attribute name="title">
+ <string>Editor</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <item>
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Font</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFontComboBox" name="fontSelect"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <item>
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>Size</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="fontSize">
+ <property name="value">
+ <number>12</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Foreground Colour</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy">
+ <cstring>fgButton</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="fgButton">
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Click To Change</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Background Colour</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy">
+ <cstring>bgButton</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="bgButton">
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Click To Change</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_9">
+ <item>
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Error Colour</string>
+ </property>
+ <property name="buddy">
+ <cstring>errorButton</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="errorButton">
+ <property name="text">
+ <string>Click To Change</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="prefsGroupsPage1">
+ <attribute name="title">
+ <string>Highlighting</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Comment</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy">
+ <cstring>commentButton</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="commentButton">
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Click To Change</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Escaped Character</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy">
+ <cstring>escapedButton</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="escapedButton">
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Click To Change</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Conditional</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy">
+ <cstring>conditionalButton</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="conditionalButton">
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Click To Change</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Tag</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="buddy">
+ <cstring>tagButton</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="tagButton">
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Click To Change</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>PreferencesDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>257</x>
+ <y>360</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>PreferencesDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>325</x>
+ <y>360</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/utils/themeeditor/gui/skindocument.cpp b/utils/themeeditor/gui/skindocument.cpp
new file mode 100644
index 0000000..82c7106
--- /dev/null
+++ b/utils/themeeditor/gui/skindocument.cpp
@@ -0,0 +1,311 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your optiyouon) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "skindocument.h"
+
+#include <QFile>
+#include <QSettings>
+#include <QColor>
+#include <QMessageBox>
+#include <QFileDialog>
+
+#include <iostream>
+
+SkinDocument::SkinDocument(QLabel* statusLabel, QWidget *parent) :
+ TabContent(parent), statusLabel(statusLabel)
+{
+ setupUI();
+
+ titleText = "Untitled";
+ fileName = "";
+ saved = "";
+ parseStatus = tr("Empty document");
+ blockUpdate = false;
+}
+
+SkinDocument::SkinDocument(QLabel* statusLabel, QString file, QWidget *parent):
+ TabContent(parent), fileName(file), statusLabel(statusLabel)
+{
+ setupUI();
+ blockUpdate = false;
+
+ /* Loading the file */
+ if(QFile::exists(fileName))
+ {
+ QFile fin(fileName);
+ fin.open(QFile::ReadOnly);
+ editor->document()->setPlainText(QString(fin.readAll()));
+ saved = editor->document()->toPlainText();
+ editor->setTextCursor(QTextCursor(editor->document()->begin()));
+ fin.close();
+ }
+
+ /* Setting the title */
+ QStringList decomposed = fileName.split('/');
+ titleText = decomposed.last();
+}
+
+SkinDocument::~SkinDocument()
+{
+ delete highlighter;
+ delete model;
+}
+
+void SkinDocument::connectPrefs(PreferencesDialog* prefs)
+{
+ QObject::connect(prefs, SIGNAL(accepted()),
+ this, SLOT(settingsChanged()));
+ QObject::connect(prefs, SIGNAL(accepted()),
+ highlighter, SLOT(loadSettings()));
+}
+
+bool SkinDocument::requestClose()
+{
+ /* Storing the response in blockUpdate will also block updates to the
+ status bar if the tab is being closed */
+ if(editor->document()->toPlainText() != saved)
+ {
+ /* Spawning the "Are you sure?" dialog */
+ QMessageBox confirm(this);
+ confirm.setWindowTitle(tr("Confirm Close"));
+ confirm.setText(titleText + tr(" has been modified."));
+ confirm.setInformativeText(tr("Do you want to save your changes?"));
+ confirm.setStandardButtons(QMessageBox::Save | QMessageBox::Discard
+ | QMessageBox::Cancel);
+ confirm.setDefaultButton(QMessageBox::Save);
+ int confirmation = confirm.exec();
+
+ switch(confirmation)
+ {
+ case QMessageBox::Save:
+ save();
+ /* After calling save, make sure the user actually went through */
+ if(editor->document()->toPlainText() != saved)
+ blockUpdate = false;
+ else
+ blockUpdate = true;
+ break;
+
+ case QMessageBox::Discard:
+ blockUpdate = true;
+ break;
+
+ case QMessageBox::Cancel:
+ blockUpdate = false;
+ break;
+ }
+ }
+ else
+ blockUpdate = true;
+
+ return blockUpdate;
+}
+
+void SkinDocument::setupUI()
+{
+ /* Setting up the text edit */
+ layout = new QHBoxLayout;
+ editor = new CodeEditor(this);
+ editor->setLineWrapMode(QPlainTextEdit::NoWrap);
+ layout->addWidget(editor);
+
+ setLayout(layout);
+
+ /* Attaching the syntax highlighter */
+ highlighter = new SkinHighlighter(editor->document());
+
+ /* Setting up the model */
+ model = new ParseTreeModel("");
+
+ /* Connecting the editor's signal */
+ QObject::connect(editor, SIGNAL(textChanged()),
+ this, SLOT(codeChanged()));
+ QObject::connect(editor, SIGNAL(cursorPositionChanged()),
+ this, SLOT(cursorChanged()));
+
+ settingsChanged();
+}
+
+void SkinDocument::settingsChanged()
+{
+ /* Setting the editor colors */
+ QSettings settings;
+ settings.beginGroup("SkinDocument");
+
+ QColor fg = settings.value("fgColor", Qt::black).value<QColor>();
+ QColor bg = settings.value("bgColor", Qt::white).value<QColor>();
+ QPalette palette;
+ palette.setColor(QPalette::All, QPalette::Base, bg);
+ palette.setColor(QPalette::All, QPalette::Text, fg);
+ editor->setPalette(palette);
+
+ QColor highlight = settings.value("errorColor", Qt::red).value<QColor>();
+ editor->setErrorColor(highlight);
+
+ /* Setting the font */
+ QFont def("Monospace");
+ def.setStyleHint(QFont::TypeWriter);
+ QFont family = settings.value("fontFamily", def).value<QFont>();
+ family.setPointSize(settings.value("fontSize", 12).toInt());
+ editor->setFont(family);
+
+ editor->repaint();
+
+ settings.endGroup();
+
+}
+
+void SkinDocument::cursorChanged()
+{
+ if(editor->isError(editor->textCursor().blockNumber() + 1))
+ {
+ QTextCursor line = editor->textCursor();
+ line.movePosition(QTextCursor::StartOfLine);
+ line.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
+ skin_parse(line.selectedText().toAscii());
+ if(skin_error_line() > 0)
+ parseStatus = tr("Error on line ") +
+ QString::number(line.blockNumber() + 1) + tr(": ") +
+ skin_error_message();
+ statusLabel->setText(parseStatus);
+ }
+ else if(editor->hasErrors())
+ {
+ parseStatus = tr("Errors in document");
+ statusLabel->setText(parseStatus);
+ }
+ else
+ {
+ emit lineChanged(editor->textCursor().blockNumber() + 1);
+ }
+
+}
+
+void SkinDocument::codeChanged()
+{
+ if(blockUpdate)
+ return;
+
+ if(editor->document()->isEmpty())
+ {
+ parseStatus = tr("Empty document");
+ statusLabel->setText(parseStatus);
+ return;
+ }
+
+ editor->clearErrors();
+ parseStatus = model->changeTree(editor->document()->
+ toPlainText().toAscii());
+ if(skin_error_line() > 0)
+ parseStatus = tr("Errors in document");
+ statusLabel->setText(parseStatus);
+
+ /* Highlighting if an error was found */
+ if(skin_error_line() > 0)
+ {
+ editor->addError(skin_error_line());
+
+ /* Now we're going to attempt parsing again at each line, until we find
+ one that won't error out*/
+ QTextDocument doc(editor->document()->toPlainText());
+ int base = 0;
+ while(skin_error_line() > 0 && !doc.isEmpty())
+ {
+ QTextCursor rest(&doc);
+
+ for(int i = 0; i < skin_error_line(); i++)
+ rest.movePosition(QTextCursor::NextBlock,
+ QTextCursor::KeepAnchor);
+ if(skin_error_line() == doc.blockCount())
+ rest.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
+
+ rest.removeSelectedText();
+ base += skin_error_line();
+
+ skin_parse(doc.toPlainText().toAscii());
+
+ if(skin_error_line() > 0)
+ editor->addError(base + skin_error_line());
+
+ }
+ }
+
+ if(editor->document()->toPlainText() != saved)
+ emit titleChanged(titleText + QChar('*'));
+ else
+ emit titleChanged(titleText);
+
+ cursorChanged();
+
+}
+
+void SkinDocument::save()
+{
+ QFile fout(fileName);
+
+ if(!fout.exists())
+ {
+ saveAs();
+ return;
+ }
+
+ fout.open(QFile::WriteOnly);
+ fout.write(editor->document()->toPlainText().toAscii());
+ fout.close();
+
+ saved = editor->document()->toPlainText();
+ QStringList decompose = fileName.split('/');
+ titleText = decompose.last();
+ emit titleChanged(titleText);
+
+}
+
+void SkinDocument::saveAs()
+{
+ /* Determining the directory to open */
+ QString directory = fileName;
+
+ QSettings settings;
+ settings.beginGroup("SkinDocument");
+ if(directory == "")
+ directory = settings.value("defaultDirectory", "").toString();
+
+ fileName = QFileDialog::getSaveFileName(this, tr("Save Document"),
+ directory, fileFilter());
+ directory = fileName;
+ if(fileName == "")
+ return;
+
+ directory.chop(fileName.length() - fileName.lastIndexOf('/') - 1);
+ settings.setValue("defaultDirectory", directory);
+ settings.endGroup();
+
+ QFile fout(fileName);
+ fout.open(QFile::WriteOnly);
+ fout.write(editor->document()->toPlainText().toAscii());
+ fout.close();
+
+ saved = editor->document()->toPlainText();
+ QStringList decompose = fileName.split('/');
+ titleText = decompose[decompose.count() - 1];
+ emit titleChanged(titleText);
+
+}
diff --git a/utils/themeeditor/gui/skindocument.h b/utils/themeeditor/gui/skindocument.h
new file mode 100644
index 0000000..c6449ca
--- /dev/null
+++ b/utils/themeeditor/gui/skindocument.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef SKINDOCUMENT_H
+#define SKINDOCUMENT_H
+
+#include <QWidget>
+#include <QLabel>
+#include <QHBoxLayout>
+
+#include "skinhighlighter.h"
+#include "parsetreemodel.h"
+#include "preferencesdialog.h"
+#include "codeeditor.h"
+#include "tabcontent.h"
+
+class SkinDocument : public TabContent
+{
+Q_OBJECT
+public:
+ static QString fileFilter()
+ {
+ return tr("WPS Files (*.wps *.rwps);;"
+ "SBS Files (*.sbs *.rsbs);;"
+ "FMS Files (*.fms *.rfms);;"
+ "All Skin Files (*.wps *.rwps *.sbs "
+ "*.rsbs *.fms *.rfms);;"
+ "All Files (*.*)");
+ }
+
+ SkinDocument(QLabel* statusLabel, QWidget *parent = 0);
+ SkinDocument(QLabel* statusLabel, QString file, QWidget* parent = 0);
+ virtual ~SkinDocument();
+
+ void connectPrefs(PreferencesDialog* prefs);
+
+ ParseTreeModel* getModel(){ return model; }
+ QString file() const{ return fileName; }
+ QString title() const{ return titleText; }
+ QString getStatus(){ return parseStatus; }
+ void genCode(){ editor->document()->setPlainText(model->genCode()); }
+
+ void save();
+ void saveAs();
+
+ bool requestClose();
+
+ TabType type() const{ return Skin; }
+
+signals:
+
+public slots:
+ void settingsChanged();
+ void cursorChanged();
+
+private slots:
+ void codeChanged();
+
+private:
+ void setupUI();
+
+ QString titleText;
+ QString fileName;
+ QString saved;
+ QString parseStatus;
+
+ QLayout* layout;
+ CodeEditor* editor;
+
+ SkinHighlighter* highlighter;
+ ParseTreeModel* model;
+
+ QLabel* statusLabel;
+
+ bool blockUpdate;
+};
+
+#endif // SKINDOCUMENT_H
diff --git a/utils/themeeditor/gui/skinhighlighter.cpp b/utils/themeeditor/gui/skinhighlighter.cpp
new file mode 100644
index 0000000..25a479f
--- /dev/null
+++ b/utils/themeeditor/gui/skinhighlighter.cpp
@@ -0,0 +1,172 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "skinhighlighter.h"
+
+#include <QSettings>
+
+SkinHighlighter::SkinHighlighter(QTextDocument* doc)
+ :QSyntaxHighlighter(doc)
+{
+ loadSettings();
+}
+
+SkinHighlighter::~SkinHighlighter()
+{
+
+}
+
+void SkinHighlighter::highlightBlock(const QString& text)
+{
+ for(int i = 0; i < text.length(); i++)
+ {
+ QChar c = text[i];
+
+ /* Checking for delimiters */
+ if(c == ARGLISTOPENSYM
+ || c == ARGLISTCLOSESYM
+ || c == ARGLISTSEPERATESYM)
+ setFormat(i, 1, tag);
+
+ if(c == ENUMLISTOPENSYM
+ || c == ENUMLISTCLOSESYM
+ || c == ENUMLISTSEPERATESYM)
+ setFormat(i, 1, conditional);
+
+ /* Checking for comments */
+ if(c == COMMENTSYM)
+ {
+ setFormat(i, text.length() - i, comment);
+ return;
+ }
+
+ if(c == TAGSYM)
+ {
+ if(text.length() - i < 2)
+ return;
+
+ if(find_escape_character(text[i + 1].toAscii()))
+ {
+ /* Checking for escaped characters */
+
+ setFormat(i, 2, escaped);
+ i++;
+ }
+ else if(text[i + 1] != CONDITIONSYM)
+ {
+ /* Checking for normal tags */
+
+ char lookup[3];
+ struct tag_info* found = 0;
+
+ /* First checking for a two-character tag name */
+ lookup[2] = '\0';
+
+ if(text.length() - i >= 3)
+ {
+ lookup[0] = text[i + 1].toAscii();
+ lookup[1] = text[i + 2].toAscii();
+
+ found = find_tag(lookup);
+ }
+
+ if(found)
+ {
+ setFormat(i, 3, tag);
+ i += 2;
+ }
+ else
+ {
+ lookup[1] = '\0';
+ lookup[0] = text[i + 1].toAscii();
+ found = find_tag(lookup);
+
+ if(found)
+ {
+ setFormat(i, 2, tag);
+ i++;
+ }
+ }
+
+ }
+ else if(text[i + 1] == CONDITIONSYM)
+ {
+ /* Checking for conditional tags */
+
+ if(text.length() - i < 3)
+ return;
+
+ char lookup[3];
+ struct tag_info* found = 0;
+
+ lookup[2] = '\0';
+
+ if(text.length() - i >= 4)
+ {
+ lookup[0] = text[i + 2].toAscii();
+ lookup[1] = text[i + 3].toAscii();
+
+ found = find_tag(lookup);
+ }
+
+ if(found)
+ {
+ setFormat(i, 4, conditional);
+ i += 3;
+ }
+ else
+ {
+ lookup[1] = '\0';
+ lookup[0] = text[i + 2].toAscii();
+
+ found = find_tag(lookup);
+
+ if(found)
+ {
+ setFormat(i, 3, conditional);
+ i += 2;
+ }
+ }
+
+ }
+ }
+ }
+}
+
+void SkinHighlighter::loadSettings()
+{
+ QSettings settings;
+
+ settings.beginGroup("SkinHighlighter");
+
+ /* Loading the highlighting colors */
+ tag = settings.value("tagColor", QColor(180,0,0)).value<QColor>();
+ conditional = settings.value("conditionalColor",
+ QColor(0, 0, 180)).value<QColor>();
+ escaped = settings.value("escapedColor",
+ QColor(120,120,120)).value<QColor>();
+ comment = settings.value("commentColor",
+ QColor(0, 180, 0)).value<QColor>();
+
+ settings.endGroup();
+
+ rehighlight();
+}
diff --git a/utils/themeeditor/gui/skinhighlighter.h b/utils/themeeditor/gui/skinhighlighter.h
new file mode 100644
index 0000000..4d5c68b
--- /dev/null
+++ b/utils/themeeditor/gui/skinhighlighter.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef SKINHIGHLIGHTER_H
+#define SKINHIGHLIGHTER_H
+
+#include <QSyntaxHighlighter>
+#include <QPlainTextEdit>
+
+#include "tag_table.h"
+#include "symbols.h"
+
+class SkinHighlighter : public QSyntaxHighlighter
+{
+Q_OBJECT
+public:
+ /*
+ * font - The font used for all text
+ * normal - The normal text color
+ * escaped - The color for escaped characters
+ * tag - The color for tags and their delimiters
+ * conditional - The color for conditionals and their delimiters
+ *
+ */
+ SkinHighlighter(QTextDocument* doc);
+ virtual ~SkinHighlighter();
+
+ void highlightBlock(const QString& text);
+
+public slots:
+ void loadSettings();
+
+private:
+ QColor escaped;
+ QColor tag;
+ QColor conditional;
+ QColor comment;
+
+};
+
+#endif // SKINHIGHLIGHTER_H
diff --git a/utils/themeeditor/gui/skinviewer.cpp b/utils/themeeditor/gui/skinviewer.cpp
new file mode 100644
index 0000000..152450e
--- /dev/null
+++ b/utils/themeeditor/gui/skinviewer.cpp
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "skinviewer.h"
+#include "ui_skinviewer.h"
+
+SkinViewer::SkinViewer(QWidget *parent) :
+ QWidget(parent),
+ ui(new Ui::SkinViewer)
+{
+ ui->setupUi(this);
+
+ QObject::connect(ui->zoomOutButton, SIGNAL(pressed()),
+ this, SLOT(zoomOut()));
+ QObject::connect(ui->zoomInButton, SIGNAL(pressed()),
+ this, SLOT(zoomIn()));
+}
+
+SkinViewer::~SkinViewer()
+{
+ delete ui;
+}
+
+void SkinViewer::changeEvent(QEvent *e)
+{
+ QWidget::changeEvent(e);
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ui->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void SkinViewer::setScene(QGraphicsScene *scene)
+{
+ ui->viewer->setScene(scene);
+}
+
+void SkinViewer::zoomIn()
+{
+ ui->viewer->scale(1.2, 1.2);
+}
+
+void SkinViewer::zoomOut()
+{
+ ui->viewer->scale(1/1.2, 1/1.2);
+}
diff --git a/utils/themeeditor/gui/skinviewer.h b/utils/themeeditor/gui/skinviewer.h
new file mode 100644
index 0000000..599a204
--- /dev/null
+++ b/utils/themeeditor/gui/skinviewer.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Robert Bieber
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef SKINVIEWER_H
+#define SKINVIEWER_H
+
+#include <QWidget>
+#include <QGraphicsScene>
+
+namespace Ui {
+ class SkinViewer;
+}
+
+class SkinViewer : public QWidget {
+ Q_OBJECT
+public:
+ SkinViewer(QWidget *parent = 0);
+ ~SkinViewer();
+
+ void setScene(QGraphicsScene* scene);
+
+public slots:
+ void zoomIn();
+ void zoomOut();
+
+protected:
+ void changeEvent(QEvent *e);
+
+private:
+ Ui::SkinViewer *ui;
+};
+
+#endif // SKINVIEWER_H
diff --git a/utils/themeeditor/gui/skinviewer.ui b/utils/themeeditor/gui/skinviewer.ui
new file mode 100644
index 0000000..ed260d0
--- /dev/null
+++ b/utils/themeeditor/gui/skinviewer.ui
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SkinViewer</class>
+ <widget class="QWidget" name="SkinViewer">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGraphicsView" name="viewer"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QToolButton" name="zoomInButton">
+ <property name="text">
+ <string>Zoom In</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="zoomOutButton">
+ <property name="text">
+ <string>Zoom Out</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/utils/themeeditor/gui/tabcontent.h b/utils/themeeditor/gui/tabcontent.h
new file mode 100644
index 0000000..1b153f7
--- /dev/null
+++ b/utils/themeeditor/gui/tabcontent.h
@@ -0,0 +1,35 @@
+#ifndef TABCONTENT_H
+#define TABCONTENT_H
+
+#include <QWidget>
+
+class TabContent : public QWidget
+{
+Q_OBJECT
+public:
+ enum TabType
+ {
+ Skin,
+ Config
+ };
+
+ TabContent(QWidget *parent = 0): QWidget(parent){ }
+
+ virtual TabType type() const = 0;
+ virtual QString title() const = 0;
+ virtual QString file() const = 0;
+
+ virtual void save() = 0;
+ virtual void saveAs() = 0;
+
+ virtual bool requestClose() = 0;
+
+signals:
+ void titleChanged(QString);
+ void lineChanged(int);
+
+public slots:
+
+};
+
+#endif // TABCONTENT_H