# HG changeset patch # User Santeri Piippo # Date 1372896339 -10800 # Node ID 5e701c3c3d8efd544a9d184d32e4ddb3abe44010 # Parent 48e429bfd58c4aa261ee50111463c8525e39ddbc Re-added the message log, now draws into the viewport diff -r 48e429bfd58c -r 5e701c3c3d8e changelog.txt --- 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. diff -r 48e429bfd58c -r 5e701c3c3d8e src/common.h --- 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 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; diff -r 48e429bfd58c -r 5e701c3c3d8e src/file.cpp --- 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 (obj)->reason )); + log( "Couldn't parse line #%lu: %s\n", + m_progress + 1, static_cast (obj)->reason ); - logf (LOG_Warning, "- Line was: %s\n", qchars (line)); -*/ + log( "- Line was: %s\n", line ); if( m_warningsPointer ) ( *m_warningsPointer )++; diff -r 48e429bfd58c -r 5e701c3c3d8e src/gldraw.cpp --- 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; } diff -r 48e429bfd58c -r 5e701c3c3d8e src/gldraw.h --- 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) diff -r 48e429bfd58c -r 5e701c3c3d8e src/gui.cpp --- 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) diff -r 48e429bfd58c -r 5e701c3c3d8e src/gui.h --- 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 m_colorMeta; vector m_colorButtons; vector m_recentFiles; + MessageManager* m_msglog; void createMenuActions (); void createMenus (); diff -r 48e429bfd58c -r 5e701c3c3d8e src/gui_actions.cpp --- 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; diff -r 48e429bfd58c -r 5e701c3c3d8e src/main.cpp --- 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; diff -r 48e429bfd58c -r 5e701c3c3d8e src/msglog.cpp --- /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 . + */ + +#include "msglog.h" +#include "gldraw.h" +#include "gui.h" +#include +#include + +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 args ) +{ + g_win->addMessage( DoFormat( args )); +} \ No newline at end of file diff -r 48e429bfd58c -r 5e701c3c3d8e src/msglog.h --- /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 . + */ + +#ifndef MSGLOG_H +#define MSGLOG_H + +#include +#include +#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::it it; + typedef vector::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 m_lines; + QTimer* m_ticker; + +private slots: + void tick(); +}; + +#endif // MSGLOG_H \ No newline at end of file diff -r 48e429bfd58c -r 5e701c3c3d8e src/types.cpp --- 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 diff -r 48e429bfd58c -r 5e701c3c3d8e src/types.h --- 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 StringFormatArg (const vector& v) { m_val = "{ ";