- re-committed bfc work (this makes 903ec1e46298 a suitable common ancestor for experimental branch features) experimental

Tue, 09 Sep 2014 01:17:36 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Tue, 09 Sep 2014 01:17:36 +0300
branch
experimental
changeset 891
00d76b281021
parent 890
903ec1e46298
child 895
f0d14f16ae87
child 906
d2b3c8ce8817

- re-committed bfc work (this makes 903ec1e46298 a suitable common ancestor for experimental branch features)

src/basics.h file | annotate | diff | comparison | revisions
src/glCompiler.cc file | annotate | diff | comparison | revisions
src/glShared.h file | annotate | diff | comparison | revisions
src/ldDocument.cc file | annotate | diff | comparison | revisions
src/ldDocument.h file | annotate | diff | comparison | revisions
src/ldObject.cc file | annotate | diff | comparison | revisions
src/ldObject.h file | annotate | diff | comparison | revisions
src/mainWindow.cc file | annotate | diff | comparison | revisions
src/partDownloader.cc file | annotate | diff | comparison | revisions
src/partDownloader.h file | annotate | diff | comparison | revisions
ui/config.ui file | annotate | diff | comparison | revisions
ui/ldforge.ui file | annotate | diff | comparison | revisions
--- a/src/basics.h	Tue Sep 09 01:16:24 2014 +0300
+++ b/src/basics.h	Tue Sep 09 01:17:36 2014 +0300
@@ -56,6 +56,21 @@
 	Z
 };
 
+enum class Winding
+{
+	CW,
+	CCW,
+	None
+};
+
+inline void invertWinding (Winding& winding)
+{
+	if (winding == Winding::CW)
+		winding = Winding::CCW;
+	elif (winding == Winding::CCW)
+		winding = Winding::CW;
+}
+
 //
 // Derivative of QVector3D: this class is used for the vertices.
 //
--- a/src/glCompiler.cc	Tue Sep 09 01:16:24 2014 +0300
+++ b/src/glCompiler.cc	Tue Sep 09 01:17:36 2014 +0300
@@ -49,10 +49,6 @@
 EXTERN_CFGENTRY (Bool, BlackEdges)
 EXTERN_CFGENTRY (String, BackgroundColor)
 
-static QList<int>		g_warnedColors;
-static const QColor		g_BFCFrontColor (64, 192, 80);
-static const QColor		g_BFCBackColor (208, 64, 64);
-
 // static QMap<LDObjectPtr, String> g_objectOrigins;
 
 // =============================================================================
@@ -135,7 +131,12 @@
 QColor GLCompiler::getColorForPolygon (LDPolygon& poly, LDObjectPtr topobj,
 									   EVBOComplement complement) const
 {
+	static const QColor bfcFrontColor (64, 192, 80);
+	static const QColor	bfcBackColor (208, 64, 64);
+	static const QColor	bfcDisabledColor (64, 64, 208);
+	static QList<int> warnedcolors;
 	QColor qcol;
+	print ("Winding of %1 is %2", poly.id, (int) poly.winding);
 
 	switch (complement)
 	{
@@ -144,11 +145,11 @@
 			return QColor();
 
 		case VBOCM_BFCFrontColors:
-			qcol = g_BFCFrontColor;
+			qcol = (poly.winding != Winding::None) ? bfcFrontColor : bfcDisabledColor;
 			break;
 
 		case VBOCM_BFCBackColors:
-			qcol = g_BFCBackColor;
+			qcol = (poly.winding != Winding::None) ? bfcBackColor : bfcDisabledColor;
 			break;
 
 		case VBOCM_PickColors:
@@ -184,16 +185,13 @@
 	{
 		// The color was unknown. Use main color to make the polygon at least
 		// not appear pitch-black.
-		if (poly.num != 2 and poly.num != 5)
-			qcol = GLRenderer::getMainColor();
-		else
-			qcol = Qt::black;
+		qcol = (poly.num != 2 and poly.num != 5) ? GLRenderer::getMainColor() : Qt::black;
 
 		// Warn about the unknown color, but only once.
-		if (not g_warnedColors.contains (poly.color))
+		if (not warnedcolors.contains (poly.color))
 		{
 			print ("Unknown color %1!\n", poly.color);
-			g_warnedColors << poly.color;
+			warnedcolors << poly.color;
 		}
 
 		return qcol;
@@ -285,16 +283,13 @@
 		if (it.key() == null)
 		{
 			it = m_objectInfo.erase (it);
-			continue;
 		}
-
-		if (it.key().toStrongRef()->document() == CurrentDocument()
+		elif (it.key().toStrongRef()->document() == CurrentDocument()
 			and not it.key().toStrongRef()->isHidden())
 		{
 			vbodata += it->data[vbonum];
+			++it;
 		}
-
-		++it;
 	}
 
 	glBindBuffer (GL_ARRAY_BUFFER, m_vbo[vbonum]);
@@ -392,7 +387,9 @@
 		QVector<GLfloat>& vbodata	= objinfo->data[vbonum];
 		const QColor color			= getColorForPolygon (poly, topobj, complement);
 
-		for (int vert = 0; vert < numverts; ++vert)
+		bool inverted = (poly.winding != Winding::CCW);
+
+		auto func = [&](int vert)
 		{
 			if (complement == VBOCM_Surfaces)
 			{
@@ -408,6 +405,17 @@
 						<< ((GLfloat) color.blue()) / 255.0f
 						<< ((GLfloat) color.alpha()) / 255.0f;
 			}
+		};
+
+		if (not inverted)
+		{
+			for (int vert = 0; vert < numverts; ++vert)
+				func (vert);
+		}
+		else
+		{
+			for (int vert = numverts - 1; vert >= 0; --vert)
+				func (vert);
 		}
 	}
 }
--- a/src/glShared.h	Tue Sep 09 01:16:24 2014 +0300
+++ b/src/glShared.h	Tue Sep 09 01:17:36 2014 +0300
@@ -32,6 +32,7 @@
 	Vertex		vertices[4];
 	int			id;
 	int			color;
+	Winding		winding;
 
 	inline int numVertices() const
 	{
--- a/src/ldDocument.cc	Tue Sep 09 01:16:24 2014 +0300
+++ b/src/ldDocument.cc	Tue Sep 09 01:17:36 2014 +0300
@@ -35,7 +35,6 @@
 
 CFGENTRY (String, LDrawPath, "")
 CFGENTRY (List, RecentFiles, {})
-CFGENTRY (Bool, TryDownloadMissingFiles, false)
 EXTERN_CFGENTRY (String, DownloadFilePath)
 EXTERN_CFGENTRY (Bool, UseLogoStuds)
 
@@ -209,6 +208,12 @@
 	}
 }
 
+LDObjectList const& LDDocument::objects()
+{
+	sweepBFC();
+	return m_objects;
+}
+
 // =============================================================================
 //
 QList<LDDocumentPtr> const& LDDocument::explicitDocuments()
@@ -757,22 +762,18 @@
 		unknowns << obj.staticCast<LDError>()->fileReferenced();
 	}
 
-	if (cfg::TryDownloadMissingFiles and not unknowns.isEmpty())
+	if (not unknowns.isEmpty())
 	{
 		PartDownloader dl;
-
-		if (dl.checkValidPath())
-		{
-			dl.setSource (PartDownloader::PartsTracker);
-			dl.setPrimaryFile (file);
+		dl.setSource (PartDownloader::PartsTracker);
+		dl.setPrimaryFile (file);
 
-			for (QString const& unknown : unknowns)
-				dl.downloadFromPartsTracker (unknown);
+		for (QString const& unknown : unknowns)
+			dl.downloadFromPartsTracker (unknown);
 
-			dl.exec();
-			dl.checkIfFinished();
-			file->reloadAllSubfiles();
-		}
+		dl.exec();
+		dl.checkIfFinished();
+		file->reloadAllSubfiles();
 	}
 }
 
@@ -1147,6 +1148,7 @@
 }
 
 // =============================================================================
+// Adds an object at the end of the file.
 //
 int LDDocument::addObject (LDObjectPtr obj)
 {
@@ -1155,6 +1157,7 @@
 	addKnownVertices (obj);
 	obj->setDocument (self());
 	g_win->R()->compileObject (obj);
+	requireBFCSweep();
 	return getObjectCount() - 1;
 }
 
@@ -1167,6 +1170,8 @@
 		if (obj != null)
 			addObject (obj);
 	}
+
+	requireBFCSweep();
 }
 
 // =============================================================================
@@ -1177,8 +1182,8 @@
 	m_objects.insert (pos, obj);
 	obj->setDocument (self());
 	g_win->R()->compileObject (obj);
+	requireBFCSweep();
 	
-
 #ifdef DEBUG
 	if (not isImplicit())
 		dprint ("Inserted object #%1 (%2) at %3\n", obj->id(), obj->typeName(), pos);
@@ -1214,6 +1219,11 @@
 		m_objectVertices.remove (obj);
 	}
 
+	// We only need a sweep if we got rid of a BFC object, no processing is required if a polygon
+	// just got removed.
+	if (obj->type() == OBJ_BFC)
+		requireBFCSweep();
+
 	m_objects.removeAt (idx);
 	obj->setDocument (LDDocumentPtr());
 }
@@ -1257,11 +1267,12 @@
 
 // =============================================================================
 //
-LDObjectPtr LDDocument::getObject (int pos) const
+LDObjectPtr LDDocument::getObject (int pos)
 {
 	if (m_objects.size() <= pos)
 		return LDObjectPtr();
 
+	sweepBFC();
 	return m_objects[pos];
 }
 
@@ -1269,7 +1280,7 @@
 //
 int LDDocument::getObjectCount() const
 {
-	return objects().size();
+	return m_objects.size();
 }
 
 // =============================================================================
@@ -1507,8 +1518,9 @@
 
 // =============================================================================
 //
-const LDObjectList& LDDocument::getSelection() const
+const LDObjectList& LDDocument::getSelection()
 {
+	sweepBFC();
 	return m_sel;
 }
 
@@ -1522,6 +1534,7 @@
 	m_objects[b] = one;
 	m_objects[a] = other;
 	addToHistory (new SwapHistory (one->id(), other->id()));
+	requireBFCSweep();
 }
 
 // =============================================================================
@@ -1554,3 +1567,72 @@
 {
 	m_needVertexMerge = true;
 }
+
+//
+// Sweeps through the file and adjusts the block windings of all objects.
+//
+void LDDocument::sweepBFC()
+{
+	if (not m_needBFCSweep)
+		return;
+
+	QTime t0 (QTime::currentTime());
+	Winding winding (Winding::None);
+	Winding preclip (winding);
+	LDBFCPtr bfc;
+	bool invertnext (false);
+
+	for (LDObjectPtr obj : m_objects)
+	{
+		if (obj->type() == OBJ_BFC)
+		{
+			switch (obj.staticCast<LDBFC>()->statement())
+			{
+			case BFCStatement::CCW:
+			case BFCStatement::CertifyCCW:
+				winding = Winding::CCW;
+				break;
+
+			case BFCStatement::CW:
+			case BFCStatement::CertifyCW:
+				winding = Winding::CW;
+
+			case BFCStatement::NoCertify:
+				winding = Winding::None;
+				break;
+
+			case BFCStatement::NoClip:
+				preclip = winding;
+				winding = Winding::None;
+				break;
+
+			case BFCStatement::InvertNext:
+				invertnext = true;
+				break;
+
+			case BFCStatement::Clip:
+				winding = preclip;
+				break;
+
+			default:
+				break;
+			}
+		}
+		else
+		{
+			Winding objwinding (winding);
+
+			if (invertnext)
+			{
+				invertWinding (objwinding);
+				invertnext = false;
+			}
+
+			print ("%1: BFC sweep: set winding of %2 to %3", getDisplayName(), obj->id(), int (objwinding));
+			obj->setBlockWinding (objwinding);
+		}
+	}
+
+	print ("%1: BFC sweep done in %2ms", getDisplayName(), t0.msecsTo (QTime::currentTime()));
+	m_needBFCSweep = false;
+}
--- a/src/ldDocument.h	Tue Sep 09 01:16:24 2014 +0300
+++ b/src/ldDocument.h	Tue Sep 09 01:17:36 2014 +0300
@@ -64,7 +64,6 @@
 {
 public:
 	PROPERTY (public,	QString,				name,			setName,			STOCK_WRITE)
-	PROPERTY (private,	LDObjectList,		objects, 		setObjects,			STOCK_WRITE)
 	PROPERTY (private,	LDObjectList,		cache, 			setCache,			STOCK_WRITE)
 	PROPERTY (private,	History*,			history,		setHistory,			STOCK_WRITE)
 	PROPERTY (public,	QString,				fullPath,		setFullPath,		STOCK_WRITE)
@@ -90,13 +89,13 @@
 	void clearSelection();
 	void forgetObject (LDObjectPtr obj); // Deletes the given object from the object chain.
 	QString getDisplayName();
-	const LDObjectList& getSelection() const;
+	const LDObjectList& getSelection();
 	bool hasUnsavedChanges() const; // Does this document have unsaved changes?
 	void initializeCachedData();
 	LDObjectList inlineContents (bool deep, bool renderinline);
 	void insertObj (int pos, LDObjectPtr obj);
 	int getObjectCount() const;
-	LDObjectPtr getObject (int pos) const;
+	LDObjectPtr getObject (int pos);
 	bool save (QString path = "", int64* sizeptr = null); // Saves this file to disk.
 	void swapObjects (LDObjectPtr one, LDObjectPtr other);
 	bool isSafeToClose(); // Perform safety checks. Do this before closing any files!
@@ -109,6 +108,8 @@
 	void redoVertices();
 	void needVertexMerge();
 	void reloadAllSubfiles();
+	void sweepBFC();
+	LDObjectList const& objects();
 
 	inline LDDocument& operator<< (LDObjectPtr obj)
 	{
@@ -146,6 +147,11 @@
 		setImplicit (true);
 	}
 
+	inline void requireBFCSweep()
+	{
+		m_needBFCSweep = true;
+	}
+
 	static LDDocumentPtr current();
 	static void setCurrent (LDDocumentPtr f);
 	static void closeInitialFile();
@@ -170,12 +176,16 @@
 	friend class GLRenderer;
 
 private:
+	LDObjectList			m_objects;
 	LDObjectList			m_sel;
 	LDGLData*				m_gldata;
 
 	// If set to true, next polygon inline of this document discards the
 	// stored polygon data and re-builds it.
 	bool					m_needsReCache;
+
+	// If set to true, next object reference request causes BFC sweep.
+	bool					m_needBFCSweep;
 };
 
 inline LDDocumentPtr CurrentDocument()
--- a/src/ldObject.cc	Tue Sep 09 01:16:24 2014 +0300
+++ b/src/ldObject.cc	Tue Sep 09 01:17:36 2014 +0300
@@ -419,6 +419,7 @@
 	data->id = id();
 	data->num = num;
 	data->color = color().index();
+	data->winding = blockWinding();
 
 	for (int i = 0; i < data->numVertices(); ++i)
 		data->vertices[i] = vertex (i);
@@ -430,14 +431,29 @@
 //
 QList<LDPolygon> LDSubfile::inlinePolygons()
 {
+	bool isInverted (false);
+	LDBFCPtr bfc (previous().dynamicCast<LDBFC>());
+
+	if ((bfc != null and bfc->statement() == BFCStatement::InvertNext)
+		or transform().getDeterminant() < 0)
+	{
+		isInverted = true;
+	}
+
+	print ("inlining polygons of subfile-ref %1: inverted: %2", fileInfo()->name(), isInverted ? "true" : "false");
+
 	QList<LDPolygon> data = fileInfo()->inlinePolygons();
 
 	for (LDPolygon& entry : data)
 	{
 		for (int i = 0; i < entry.numVertices(); ++i)
 			entry.vertices[i].transform (transform(), position());
+
+		if (isInverted)
+			invertWinding (entry.winding);
 	}
 
+	print ("Using winding: %1\n", (data[0].winding == Winding::CCW) ? "CCW" : (data[0].winding == Winding::CW) ? "CW" : "None");
 	return data;
 }
 
--- a/src/ldObject.h	Tue Sep 09 01:16:24 2014 +0300
+++ b/src/ldObject.h	Tue Sep 09 01:17:36 2014 +0300
@@ -101,6 +101,11 @@
 	PROPERTY (private,		QColor,				randomColor,	setRandomColor,	STOCK_WRITE)
 	PROPERTY (private,		LDObjectWeakPtr,	self,			setSelf,		STOCK_WRITE)
 
+	// What winding the object is supposed to be wound in, depending on the BFC statements
+	// This is CW if the part is CW-certified at this object, and vice versa. Can also be
+	// Winding::None for NOCERTIFY parts.
+	PROPERTY (public,		Winding,			blockWinding,	setBlockWinding,	STOCK_WRITE)
+
 public:
 	LDObject (LDObjectPtr* selfptr);
 
--- a/src/mainWindow.cc	Tue Sep 09 01:16:24 2014 +0300
+++ b/src/mainWindow.cc	Tue Sep 09 01:17:36 2014 +0300
@@ -215,16 +215,14 @@
 void MainWindow::updateColorToolbar()
 {
 	m_colorButtons.clear();
-	ui->toolBarColors->clear();
-	ui->toolBarColors->addAction (ui->actionUncolor);
-	ui->toolBarColors->addSeparator();
+	ui->colorToolbar->clear();
+	ui->colorToolbar->addAction (ui->actionUncolor);
+	ui->colorToolbar->addSeparator();
 
 	for (LDQuickColor& entry : m_quickColors)
 	{
 		if (entry.isSeparator())
-		{
-			ui->toolBarColors->addSeparator();
-		}
+			ui->colorToolbar->addSeparator();
 		else
 		{
 			QToolButton* colorButton = new QToolButton;
@@ -233,7 +231,7 @@
 			colorButton->setToolTip (entry.color().name());
 
 			connect (colorButton, SIGNAL (clicked()), this, SLOT (slot_quickColor()));
-			ui->toolBarColors->addWidget (colorButton);
+			ui->colorToolbar->addWidget (colorButton);
 			m_colorButtons << colorButton;
 
 			entry.setToolButton (colorButton);
--- a/src/partDownloader.cc	Tue Sep 09 01:16:24 2014 +0300
+++ b/src/partDownloader.cc	Tue Sep 09 01:17:36 2014 +0300
@@ -22,14 +22,13 @@
 #include <QDir>
 #include <QProgressBar>
 #include <QPushButton>
-#include <QFileDialog>
-#include <QMessageBox>
 #include "partDownloader.h"
 #include "ui_downloadfrom.h"
 #include "basics.h"
 #include "mainWindow.h"
 #include "ldDocument.h"
 #include "glRenderer.h"
+#include "configDialog.h"
 
 CFGENTRY (String, DownloadFilePath, "")
 CFGENTRY (Bool, GuessDownloadPaths, true)
@@ -41,12 +40,19 @@
 //
 void PartDownloader::staticBegin()
 {
-	PartDownloader dlg;
+	QString path = getDownloadPath();
+
+	if (path.isEmpty() or not QDir (path).exists())
+	{
+		Critical (PartDownloader::tr ("You need to specify a valid path for "
+			"downloaded files in the configuration to download paths."));
 
-	if (not dlg.checkValidPath())
+		(new ConfigDialog (ConfigDialog::DownloadTab, null))->exec();
 		return;
+	}
 
-	dlg.exec();
+	PartDownloader* dlg = new PartDownloader;
+	dlg->exec();
 }
 
 // =============================================================================
@@ -96,26 +102,6 @@
 
 // =============================================================================
 //
-bool PartDownloader::checkValidPath()
-{
-	QString path = getDownloadPath();
-
-	if (path.isEmpty() or not QDir (path).exists())
-	{
-		QMessageBox::information(this, "Notice", "Please input a path for files to download.");
-		path = QFileDialog::getExistingDirectory (this, "Path for downloaded files:");
-
-		if (path.isEmpty())
-			return false;
-
-		cfg::DownloadFilePath = path;
-	}
-
-	return true;
-}
-
-// =============================================================================
-//
 QString PartDownloader::getURL()
 {
 	const Source src = getSource();
--- a/src/partDownloader.h	Tue Sep 09 01:16:24 2014 +0300
+++ b/src/partDownloader.h	Tue Sep 09 01:17:36 2014 +0300
@@ -70,7 +70,6 @@
 	virtual			~PartDownloader();
 
 	void			addFile (LDDocumentPtr f);
-	bool			checkValidPath();
 	void			downloadFile (QString dest, QString url, bool primary);
 	void			downloadFromPartsTracker (QString file);
 	QPushButton*	getButton (Button i);
--- a/ui/config.ui	Tue Sep 09 01:16:24 2014 +0300
+++ b/ui/config.ui	Tue Sep 09 01:17:36 2014 +0300
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>648</width>
+    <width>644</width>
     <height>370</height>
    </rect>
   </property>
@@ -995,13 +995,6 @@
              </layout>
             </item>
             <item>
-             <widget class="QCheckBox" name="configTryDownloadMissingFiles">
-              <property name="text">
-               <string>Attempt to download missing parts from the PT</string>
-              </property>
-             </widget>
-            </item>
-            <item>
              <widget class="QCheckBox" name="configGuessDownloadPaths">
               <property name="whatsThis">
                <string>&lt;p&gt;When this is set, LDForge tries to adjust and correct part paths based on the input. A full path given to the download prompt should be of form &lt;tt&gt;&quot;&amp;lt;dir&amp;gt;/&amp;lt;file&amp;gt;.dat&quot;&lt;/tt&gt; - with this set, input can be automatically completed.&lt;/p&gt;
--- a/ui/ldforge.ui	Tue Sep 09 01:16:24 2014 +0300
+++ b/ui/ldforge.ui	Tue Sep 09 01:17:36 2014 +0300
@@ -47,8 +47,8 @@
           <rect>
            <x>0</x>
            <y>0</y>
-           <width>237</width>
-           <height>414</height>
+           <width>233</width>
+           <height>399</height>
           </rect>
          </property>
          <attribute name="label">
@@ -75,8 +75,8 @@
           <rect>
            <x>0</x>
            <y>0</y>
-           <width>237</width>
-           <height>414</height>
+           <width>256</width>
+           <height>121</height>
           </rect>
          </property>
          <attribute name="label">
@@ -157,8 +157,8 @@
           <rect>
            <x>0</x>
            <y>0</y>
-           <width>237</width>
-           <height>414</height>
+           <width>101</width>
+           <height>101</height>
           </rect>
          </property>
          <attribute name="label">
@@ -194,7 +194,7 @@
      <x>0</x>
      <y>0</y>
      <width>1010</width>
-     <height>26</height>
+     <height>27</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuFile">
@@ -286,11 +286,7 @@
     <addaction name="actionSelectByType"/>
     <addaction name="separator"/>
     <addaction name="actionModeSelect"/>
-    <addaction name="actionModeMagicWand"/>
     <addaction name="actionModeDraw"/>
-    <addaction name="actionModeRectangle"/>
-    <addaction name="actionModeCircle"/>
-    <addaction name="actionModeLinePath"/>
     <addaction name="separator"/>
     <addaction name="actionSetDrawDepth"/>
     <addaction name="separator"/>
@@ -404,9 +400,9 @@
    <addaction name="menuHelp"/>
   </widget>
   <widget class="QStatusBar" name="statusbar"/>
-  <widget class="QToolBar" name="toolBarFile">
+  <widget class="QToolBar" name="toolBar">
    <property name="windowTitle">
-    <string>File</string>
+    <string>toolBar</string>
    </property>
    <attribute name="toolBarArea">
     <enum>TopToolBarArea</enum>
@@ -420,9 +416,9 @@
    <addaction name="actionSave"/>
    <addaction name="actionSaveAs"/>
   </widget>
-  <widget class="QToolBar" name="toolBarNewObject">
+  <widget class="QToolBar" name="toolBar_2">
    <property name="windowTitle">
-    <string>New Object</string>
+    <string>toolBar_2</string>
    </property>
    <attribute name="toolBarArea">
     <enum>TopToolBarArea</enum>
@@ -439,9 +435,9 @@
    <addaction name="actionNewBFC"/>
    <addaction name="actionNewVertex"/>
   </widget>
-  <widget class="QToolBar" name="toolBarBasicTools">
+  <widget class="QToolBar" name="toolBar_3">
    <property name="windowTitle">
-    <string>Basic tools</string>
+    <string>toolBar_3</string>
    </property>
    <attribute name="toolBarArea">
     <enum>TopToolBarArea</enum>
@@ -456,9 +452,9 @@
    <addaction name="actionPaste"/>
    <addaction name="actionDelete"/>
   </widget>
-  <widget class="QToolBar" name="toolBarSelect">
+  <widget class="QToolBar" name="toolBar_4">
    <property name="windowTitle">
-    <string>Select</string>
+    <string>toolBar_4</string>
    </property>
    <attribute name="toolBarArea">
     <enum>TopToolBarArea</enum>
@@ -470,9 +466,9 @@
    <addaction name="actionSelectByColor"/>
    <addaction name="actionSelectByType"/>
   </widget>
-  <widget class="QToolBar" name="toolBarGrid">
+  <widget class="QToolBar" name="toolBar_5">
    <property name="windowTitle">
-    <string>Grid</string>
+    <string>toolBar_5</string>
    </property>
    <attribute name="toolBarArea">
     <enum>TopToolBarArea</enum>
@@ -484,9 +480,9 @@
    <addaction name="actionGridMedium"/>
    <addaction name="actionGridFine"/>
   </widget>
-  <widget class="QToolBar" name="toolBarDisplay">
+  <widget class="QToolBar" name="toolBar_6">
    <property name="windowTitle">
-    <string>Display options</string>
+    <string>toolBar_6</string>
    </property>
    <attribute name="toolBarArea">
     <enum>TopToolBarArea</enum>
@@ -500,9 +496,9 @@
    <addaction name="actionRandomColors"/>
    <addaction name="actionDrawAngles"/>
   </widget>
-  <widget class="QToolBar" name="toolBarEditTools">
+  <widget class="QToolBar" name="toolBar_7">
    <property name="windowTitle">
-    <string>Editing tools</string>
+    <string>toolBar_7</string>
    </property>
    <attribute name="toolBarArea">
     <enum>TopToolBarArea</enum>
@@ -524,9 +520,9 @@
    <addaction name="actionVisibilityToggle"/>
    <addaction name="actionVisibilityReveal"/>
   </widget>
-  <widget class="QToolBar" name="toolBarEditModes">
+  <widget class="QToolBar" name="toolBar_8">
    <property name="windowTitle">
-    <string>Editing modes</string>
+    <string>toolBar_8</string>
    </property>
    <attribute name="toolBarArea">
     <enum>LeftToolBarArea</enum>
@@ -535,15 +531,15 @@
     <bool>false</bool>
    </attribute>
    <addaction name="actionModeSelect"/>
-   <addaction name="actionModeMagicWand"/>
    <addaction name="actionModeDraw"/>
    <addaction name="actionModeRectangle"/>
    <addaction name="actionModeCircle"/>
+   <addaction name="actionModeMagicWand"/>
    <addaction name="actionModeLinePath"/>
   </widget>
-  <widget class="QToolBar" name="toolBarColors">
+  <widget class="QToolBar" name="colorToolbar">
    <property name="windowTitle">
-    <string>Colors</string>
+    <string>toolBar_9</string>
    </property>
    <attribute name="toolBarArea">
     <enum>RightToolBarArea</enum>
@@ -552,9 +548,9 @@
     <bool>false</bool>
    </attribute>
   </widget>
-  <widget class="QToolBar" name="toolBarExternalPrograms">
+  <widget class="QToolBar" name="toolBar_9">
    <property name="windowTitle">
-    <string>External Programs</string>
+    <string>toolBar_9</string>
    </property>
    <attribute name="toolBarArea">
     <enum>TopToolBarArea</enum>
@@ -990,7 +986,7 @@
     <string>Select Mode</string>
    </property>
    <property name="shortcut">
-    <string>S</string>
+    <string>Ctrl+1</string>
    </property>
   </action>
   <action name="actionModeDraw">
@@ -1005,7 +1001,7 @@
     <string>Draw Mode</string>
    </property>
    <property name="shortcut">
-    <string>D</string>
+    <string>Ctrl+2</string>
    </property>
   </action>
   <action name="actionSetDrawDepth">
@@ -1025,7 +1021,7 @@
     <string>Set the color on given objects.</string>
    </property>
    <property name="shortcut">
-    <string>Shift+C</string>
+    <string>C</string>
    </property>
   </action>
   <action name="actionAutocolor">
@@ -1204,9 +1200,6 @@
    <property name="statusTip">
     <string>Flip coordinates.</string>
    </property>
-   <property name="shortcut">
-    <string>Ctrl+Shift+F</string>
-   </property>
   </action>
   <action name="actionDemote">
    <property name="text">
@@ -1507,6 +1500,9 @@
    <property name="text">
     <string>Save All</string>
    </property>
+   <property name="shortcut">
+    <string>Ctrl+Shift+S</string>
+   </property>
   </action>
   <action name="actionClose">
    <property name="text">
@@ -1566,7 +1562,7 @@
     <string>Circle Mode</string>
    </property>
    <property name="shortcut">
-    <string>C</string>
+    <string>Ctrl+4</string>
    </property>
   </action>
   <action name="actionVisibilityHide">
@@ -1686,7 +1682,7 @@
     <string>Magic wand</string>
    </property>
    <property name="shortcut">
-    <string>W</string>
+    <string>Ctrl+5</string>
    </property>
   </action>
   <action name="actionModeRectangle">
@@ -1701,7 +1697,7 @@
     <string>Rectangle Mode</string>
    </property>
    <property name="shortcut">
-    <string>R</string>
+    <string>Ctrl+3</string>
    </property>
   </action>
   <action name="actionModeLinePath">
@@ -1716,7 +1712,7 @@
     <string>Line Path Mode</string>
    </property>
    <property name="shortcut">
-    <string>P</string>
+    <string>Ctrl+6</string>
    </property>
   </action>
  </widget>

mercurial