Re-added the message log, now draws into the viewport

Thu, 04 Jul 2013 03:05:39 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Thu, 04 Jul 2013 03:05:39 +0300
changeset 322
5e701c3c3d8e
parent 321
48e429bfd58c
child 323
4200e1c89e97

Re-added the message log, now draws into the viewport

changelog.txt file | annotate | diff | comparison | revisions
src/common.h file | annotate | diff | comparison | revisions
src/file.cpp file | annotate | diff | comparison | revisions
src/gldraw.cpp file | annotate | diff | comparison | revisions
src/gldraw.h file | annotate | diff | comparison | revisions
src/gui.cpp file | annotate | diff | comparison | revisions
src/gui.h file | annotate | diff | comparison | revisions
src/gui_actions.cpp file | annotate | diff | comparison | revisions
src/main.cpp file | annotate | diff | comparison | revisions
src/msglog.cpp file | annotate | diff | comparison | revisions
src/msglog.h file | annotate | diff | comparison | revisions
src/types.cpp file | annotate | diff | comparison | revisions
src/types.h file | annotate | diff | comparison | revisions
--- a/changelog.txt	Wed Jul 03 00:43:27 2013 +0300
+++ b/changelog.txt	Thu Jul 04 03:05:39 2013 +0300
@@ -9,6 +9,8 @@
 	it's not cached (prims.cfg in configuration directory) or on user demand. Primitives can be categorised
 	with the use of a regex-based configuration file, with a valid default which should cater to most users.
 - Added an export to file action, moved it + insert from to File menu
+- Added the message log - instead of being a separate text widget as originally planned, messages are
+	drawn into the viewport. Messages expire after 5 seconds.
 - Parts are now zoomed to fit properly, making the initial view of the part clearer.
 - Replace coords: allow replacing all coords regardless of original value, plus relative moving (offset)
 - Objects can now be edited by double-clicking on them.
--- a/src/common.h	Wed Jul 03 00:43:27 2013 +0300
+++ b/src/common.h	Thu Jul 04 03:05:39 2013 +0300
@@ -248,11 +248,15 @@
 	LOG_Dev,
 };
 
-// logf - universal access to the message log. Defined here so that I don't have
-// to include gui.h here and recompile everything every time that file changes.
-// logf is defined in main.cpp
-void logf (const char* fmtstr, ...) FORMAT_PRINTF (1, 2);
-void logf (LogType type, const char* fmtstr, ...) FORMAT_PRINTF (2, 3);
+// log() - universal access to the message log. Defined here so that I don't have
+// to include msglog.h here and recompile everything every time that file changes.
+void DoLog( std::initializer_list<StringFormatArg> args );
+#ifndef IN_IDE_PARSER
+# define log(...) DoLog({ __VA_ARGS__ });
+#else
+void log( const char* fmtstr, ... );
+#endif
+
 // -----------------------------------------------------------------------------
 // Vertex at (0, 0, 0)
 extern const vertex g_origin;
--- a/src/file.cpp	Wed Jul 03 00:43:27 2013 +0300
+++ b/src/file.cpp	Thu Jul 04 03:05:39 2013 +0300
@@ -223,12 +223,10 @@
 		// Check for parse errors and warn about tthem
 		if( obj->getType () == LDObject::Gibberish )
 		{
-/*
-			logf( LOG_Warning, "Couldn't parse line #%lu: %s\n",
-				m_progress + 1, qchars (static_cast<LDGibberish*> (obj)->reason ));
+			log( "Couldn't parse line #%lu: %s\n",
+				m_progress + 1, static_cast<LDGibberish*> (obj)->reason );
 			
-			logf (LOG_Warning, "- Line was: %s\n", qchars (line));
-*/
+			log( "- Line was: %s\n", line );
 			
 			if( m_warningsPointer )
 				( *m_warningsPointer )++;
--- a/src/gldraw.cpp	Wed Jul 03 00:43:27 2013 +0300
+++ b/src/gldraw.cpp	Thu Jul 04 03:05:39 2013 +0300
@@ -35,6 +35,7 @@
 #include "history.h"
 #include "dialogs.h"
 #include "addObjectDialog.h"
+#include "msglog.h"
 
 static const struct staticCameraMeta {
 	const char glrotate[3];
@@ -102,6 +103,7 @@
 	setFile (null);
 	setDrawOnly (false);
 	resetAngles ();
+	setMessageLog( null );
 	
 	m_toolTipTimer = new QTimer (this);
 	m_toolTipTimer->setSingleShot (true);
@@ -604,7 +606,7 @@
 			str label;
 			label = fmt( fmtstr, tr( g_CameraNames[camera ()] ));
 			paint.setPen (m_darkbg ? Qt::white : Qt::black);
-			paint.drawText (QPoint (margin, margin + metrics.ascent ()), label);
+			paint.drawText( QPoint( margin, height() - ( margin + metrics.descent() )), label );
 		}
 		
 		// Tool tips
@@ -644,6 +646,24 @@
 		}
 	}
 	
+	// Message log
+	if( msglog() )
+	{
+		MessageManager* m = msglog();
+		int y = 0;
+		const int margin = 2;
+		QColor col = Qt::black;
+		paint.setPen( QPen() );
+		
+		for( const MessageManager::Line& line : *m )
+		{
+			col.setAlphaF( line.alpha );
+			paint.setPen( QPen( col ));
+			paint.drawText( QPoint( margin, y + margin + metrics.ascent() ), line.text );
+			y += metrics.height();
+		}
+	}
+	
 	// If we're range-picking, draw a rectangle encompassing the selection area.
 	if (m_rangepick && !m_picking && m_totalmove >= 10) {
 		const short x0 = m_rangeStart.x (),
@@ -1180,6 +1200,7 @@
 	case Select:
 		unsetCursor ();
 		setContextMenuPolicy (Qt::DefaultContextMenu);
+		log( "Changed to Select mode." );
 		break;
 	
 	case Draw:
@@ -1199,6 +1220,7 @@
 		g_win->sel ().clear ();
 		g_win->updateSelection ();
 		m_drawedVerts.clear ();
+		log( "Changed to Draw mode." );
 		break;
 	}
 	
--- a/src/gldraw.h	Wed Jul 03 00:43:27 2013 +0300
+++ b/src/gldraw.h	Thu Jul 04 03:05:39 2013 +0300
@@ -23,6 +23,7 @@
 #include "common.h"
 #include "ldtypes.h"
 
+class MessageManager;
 class QDialogButtonBox;
 class RadioBox;
 class QDoubleSpinBox;
@@ -55,8 +56,9 @@
 class GLRenderer : public QGLWidget {
 	Q_OBJECT
 	
-	PROPERTY (bool, drawOnly, setDrawOnly)
-	PROPERTY (double, zoom, setZoom)
+	PROPERTY( bool, drawOnly, setDrawOnly )
+	PROPERTY( double, zoom, setZoom )
+	PROPERTY( MessageManager*, msglog, setMessageLog )
 	READ_PROPERTY (bool, picking, setPicking)
 	DECLARE_PROPERTY (LDOpenFile*, file, setFile)
 	DECLARE_PROPERTY (EditMode, editMode, setEditMode)
--- a/src/gui.cpp	Wed Jul 03 00:43:27 2013 +0300
+++ b/src/gui.cpp	Thu Jul 04 03:05:39 2013 +0300
@@ -45,6 +45,7 @@
 #include "history.h"
 #include "widgets.h"
 #include "addObjectDialog.h"
+#include "msglog.h"
 #include "config.h"
 
 actionmeta g_actionMeta[MAX_ACTIONS];
@@ -79,6 +80,10 @@
 	connect (m_objList, SIGNAL (itemSelectionChanged ()), this, SLOT (slot_selectionChanged ()));
 	connect (m_objList, SIGNAL (itemDoubleClicked (QListWidgetItem*)), this, SLOT (slot_editObject (QListWidgetItem*)));
 	
+	m_msglog = new MessageManager;
+	m_msglog->setRenderer( R() );
+	m_renderer->setMessageLog( m_msglog );
+	
 	m_splitter = new QSplitter;
 	m_splitter->addWidget (m_renderer);
 	m_splitter->addWidget (m_objList);
@@ -562,7 +567,7 @@
 	}
 	
 	if (!meta) {
-		logf (LOG_Warning, "unknown signal sender %p!\n", qAct);
+		log ("Warning: unknown signal sender %p!\n", qAct);
 		return;
 	}
 	
@@ -1043,6 +1048,8 @@
 		
 		if( f == g_curfile )
 			g_win->updateTitle ();
+		
+		log( "Saved to %1.", path );
 	}
 	else
 	{
@@ -1066,6 +1073,11 @@
 	}
 }
 
+void ForgeWindow::addMessage( str msg )
+{
+	m_msglog->addLine( msg );
+}
+
 // ============================================================================
 void ObjectList::contextMenuEvent (QContextMenuEvent* ev) {
 	g_win->spawnContextMenu (ev->globalPos ());
@@ -1095,19 +1107,6 @@
 }
 
 // =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-// Print to message log
-// TODO: I don't think that the message log being a widget in the window
-// is a very good idea... maybe this should log into the renderer? Or into
-// another dialog that can be popped up?
-void ForgeWindow::logVA (LogType type, const char* fmtstr, va_list va) {
-	(void) type;
-	(void) fmtstr;
-	(void) va;
-}
-
-// =============================================================================
 QAction* findAction (str name) {
 	for (actionmeta& meta : g_actionMeta) {
 		if (meta.qAct == null)
--- a/src/gui.h	Wed Jul 03 00:43:27 2013 +0300
+++ b/src/gui.h	Thu Jul 04 03:05:39 2013 +0300
@@ -25,6 +25,7 @@
 #include "config.h"
 #include "ldtypes.h"
 
+class MessageManager;
 class ForgeWindow;
 class color;
 class QSplitter;
@@ -130,6 +131,7 @@
 	}
 	void setStatusBarText (str text);
 	void addActionMeta (actionmeta& meta);
+	void addMessage( str msg );
 	
 public slots:
 	void primitiveLoaderStart (ulong max);
@@ -138,17 +140,12 @@
 	
 protected:
 	void closeEvent (QCloseEvent* ev);
-	void logVA (LogType eType, const char* fmtstr, va_list va);
-	
-	friend void logf (const char* fmtstr, ...);
-	friend void logf (LogType type, const char* fmtstr, ...);
 	
 private:
 	GLRenderer* m_renderer;
 	ObjectList* m_objList;
 	QMenu* m_recentFilesMenu;
 	QSplitter* m_splitter;
-	str m_msglogHTML;
 	QToolBar* m_colorToolBar;
 	QProgressBar* m_primLoaderBar;
 	QWidget* m_primLoaderWidget;
@@ -157,6 +154,7 @@
 	vector<quickColor> m_colorMeta;
 	vector<QToolButton*> m_colorButtons;
 	vector<QAction*> m_recentFiles;
+	MessageManager* m_msglog;
 	
 	void createMenuActions ();
 	void createMenus ();
--- a/src/gui_actions.cpp	Wed Jul 03 00:43:27 2013 +0300
+++ b/src/gui_actions.cpp	Thu Jul 04 03:05:39 2013 +0300
@@ -440,7 +440,6 @@
 	g_win->R ()->clearOverlay ();
 }
 
-// =========================================================================================================================================
 MAKE_ACTION (modeSelect, "Select Mode", "mode-select", "Select objects from the camera view.", CTRL (1)) {
 	g_win->R ()->setEditMode (Select);
 }
@@ -449,7 +448,6 @@
 	g_win->R ()->setEditMode (Draw);
 }
 
-// =========================================================================================================================================
 MAKE_ACTION (setDrawDepth, "Set Depth Value", "depth-value", "Set the depth coordinate of the current camera.", (0)) {
 	if (g_win->R ()->camera () == GL::Free)
 		return;
--- a/src/main.cpp	Wed Jul 03 00:43:27 2013 +0300
+++ b/src/main.cpp	Thu Jul 04 03:05:39 2013 +0300
@@ -85,23 +85,6 @@
 	return app.exec ();
 }
 
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void logf (const char* fmtstr, ...) {
-	va_list va;
-	va_start (va, fmtstr);
-	g_win->logVA (LOG_Normal, fmtstr, va);
-	va_end (va);
-}
-
-void logf (LogType type, const char* fmtstr, ...) {
-	va_list va;
-	va_start (va, fmtstr);
-	g_win->logVA (type, fmtstr, va);
-	va_end (va);
-}
-
 void doDevf (const char* func, const char* fmtstr, ...) {
 	va_list va;
 	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/msglog.cpp	Thu Jul 04 03:05:39 2013 +0300
@@ -0,0 +1,116 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013 Santeri Piippo
+ *  
+ *  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 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "msglog.h"
+#include "gldraw.h"
+#include "gui.h"
+#include <QTimer>
+#include <QDate>
+
+static const unsigned int g_maxMessages = 5;
+static const int g_expiry = 5;
+static const int g_fadeTime = 500; // msecs
+
+MessageManager::MessageManager( QObject* parent ) : QObject( parent )
+{
+	m_ticker = new QTimer;
+	m_ticker->start( 100 );
+	connect( m_ticker, SIGNAL( timeout() ), this, SLOT( tick() ));
+}
+
+MessageManager::Line::Line( str text ) : text( text ), alpha( 1.0f )
+{
+	// Init expiry
+	expiry = QDateTime::currentDateTime().addSecs( g_expiry );
+}
+
+// =============================================================================
+// Check this line's expiry and update alpha accordingly. Returns true if the
+// line is still around, false if it expired.
+bool MessageManager::Line::update( bool& changed )
+{
+	changed = false;
+	
+	QDateTime now = QDateTime::currentDateTime();
+	if( now >= expiry )
+	{
+		changed = true;
+		return false;
+	}
+	
+	int msec = now.msecsTo( expiry );
+	if( msec <= g_fadeTime )
+	{
+		alpha = ( (float) msec ) / g_fadeTime;
+		changed = true;
+	}
+	
+	return true;
+}
+
+void MessageManager::addLine( str line )
+{
+	// If there's too many entries, pop the excess out
+	while( m_lines.size() >= g_maxMessages )
+		m_lines.erase( 0 );
+	
+	m_lines << Line( line );
+	
+	// Force a tick, we added a new message and it should
+	// show up immediately.
+	tick();
+}
+
+MessageManager& MessageManager::operator<<( str line )
+{
+	addLine( line );
+	return *this;
+}
+
+void MessageManager::tick()
+{
+	bool changed = false;
+	
+	for( uint i = 0; i < m_lines.size(); ++i )
+	{
+		bool lineChanged;
+		
+		if( !m_lines[i].update( lineChanged ))
+			m_lines.erase( i-- );
+		
+		changed |= lineChanged;
+	}
+	
+	if( changed )
+		renderer()->update();
+}
+
+MessageManager::c_it MessageManager::begin() const
+{
+	return m_lines.begin();
+}
+
+MessageManager::c_it MessageManager::end() const
+{
+	return m_lines.end();
+}
+
+void DoLog( std::initializer_list<StringFormatArg> args )
+{
+	g_win->addMessage( DoFormat( args ));
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/msglog.h	Thu Jul 04 03:05:39 2013 +0300
@@ -0,0 +1,64 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013 Santeri Piippo
+ *  
+ *  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 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MSGLOG_H
+#define MSGLOG_H
+
+#include <QObject>
+#include <QDate>
+#include "common.h"
+#include "types.h"
+
+class GLRenderer;
+class QTimer;
+class MessageManager : public QObject
+{
+	Q_OBJECT
+	PROPERTY( GLRenderer*, renderer, setRenderer )
+	
+public:
+	class Line
+	{
+	public:
+		Line( str text );
+		bool update( bool& changed );
+		
+		str text;
+		float alpha;
+		QDateTime expiry;
+	};
+	
+	typedef vector<Line>::it it;
+	typedef vector<Line>::c_it c_it;
+	
+	explicit MessageManager( QObject* parent = 0 );
+	void addLine( str line );
+	c_it begin() const;
+	c_it end() const;
+	
+	MessageManager& operator<<( str line );
+	
+private:
+	vector<Line> m_lines;
+	QTimer* m_ticker;
+	
+private slots:
+	void tick();
+};
+
+#endif // MSGLOG_H
\ No newline at end of file
--- a/src/types.cpp	Wed Jul 03 00:43:27 2013 +0300
+++ b/src/types.cpp	Thu Jul 04 03:05:39 2013 +0300
@@ -275,6 +275,11 @@
 	m_val.number (v.value);
 }
 
+StringFormatArg::StringFormatArg( const void* v )
+{
+	m_val.sprintf( "%p", v );
+}
+
 // =============================================================================
 File::File () {
 	// Make a null file
--- a/src/types.h	Wed Jul 03 00:43:27 2013 +0300
+++ b/src/types.h	Thu Jul 04 03:05:39 2013 +0300
@@ -376,6 +376,7 @@
 	StringFormatArg (const strconfig& v);
 	StringFormatArg (const intconfig& v);
 	StringFormatArg (const floatconfig& v);
+	StringFormatArg (const void* v);
 	
 	template<class T> StringFormatArg (const vector<T>& v) {
 		m_val = "{ ";

mercurial