summaryrefslogtreecommitdiffstats
path: root/src/itemview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/itemview.cpp')
-rw-r--r--src/itemview.cpp581
1 files changed, 581 insertions, 0 deletions
diff --git a/src/itemview.cpp b/src/itemview.cpp
new file mode 100644
index 0000000..452d33c
--- /dev/null
+++ b/src/itemview.cpp
@@ -0,0 +1,581 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include "canvasmanipulator.h"
+#include "cnitem.h"
+#include "connector.h"
+#include "docmanager.h"
+#include "drawpart.h"
+#include "ecnode.h"
+#include "itemdocument.h"
+#include "itemview.h"
+#include "ktechlab.h"
+#include "core/ktlconfig.h"
+
+#include <kaccel.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kurldrag.h>
+
+#include <cmath>
+#include <qcursor.h>
+#include <qtimer.h>
+#include <qwmatrix.h>
+
+
+//BEGIN class ItemView
+ItemView::ItemView( ItemDocument * itemDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name )
+ : View( itemDocument, viewContainer, viewAreaId, name )
+{
+ KActionCollection * ac = actionCollection();
+
+ KStdAction::selectAll( itemDocument, SLOT(selectAll()), ac );
+ KStdAction::zoomIn( this, SLOT(zoomIn()), ac );
+ KStdAction::zoomOut( this, SLOT(zoomOut()), ac );
+ KStdAction::actualSize( this, SLOT(actualSize()), ac )->setEnabled(false);
+
+
+ KAccel *pAccel = new KAccel(this);
+ pAccel->insert( "Cancel", i18n("Cancel"), i18n("Cancel the current operation"), Qt::Key_Escape, itemDocument, SLOT(cancelCurrentOperation()) );
+ pAccel->readSettings();
+
+ new KAction( i18n("Delete"), "editdelete", Qt::Key_Delete, itemDocument, SLOT(deleteSelection()), ac, "edit_delete" );
+ new KAction( i18n("Export as Image..."), 0, 0, itemDocument, SLOT(exportToImage()), ac, "file_export_image");
+
+ //BEGIN Item Alignment actions
+ new KAction( i18n("Align Horizontally"), 0, 0, itemDocument, SLOT(alignHorizontally()), ac, "align_horizontally" );
+ new KAction( i18n("Align Vertically"), 0, 0, itemDocument, SLOT(alignVertically()), ac, "align_vertically" );
+ new KAction( i18n("Distribute Horizontally"), 0, 0, itemDocument, SLOT(distributeHorizontally()), ac, "distribute_horizontally" );
+ new KAction( i18n("Distribute Vertically"), 0, 0, itemDocument, SLOT(distributeVertically()), ac, "distribute_vertically" );
+ //END Item Alignment actions
+
+
+ //BEGIN Draw actions
+ KToolBarPopupAction * pa = new KToolBarPopupAction( i18n("Draw"), "paintbrush", 0, 0, 0, ac, "edit_draw" );
+ pa->setDelayed(false);
+
+ KPopupMenu * m = pa->popupMenu();
+ m->insertTitle( i18n("Draw") );
+
+ m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_text", KIcon::Small ), i18n("Text"), DrawPart::da_text );
+ m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_line", KIcon::Small ), i18n("Line"), DrawPart::da_line );
+ m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_arrow", KIcon::Small ), i18n("Arrow"), DrawPart::da_arrow );
+ m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_ellipse", KIcon::Small ), i18n("Ellipse"), DrawPart::da_ellipse );
+ m->insertItem( KGlobal::iconLoader()->loadIcon( "tool_rectangle", KIcon::Small ), i18n("Rectangle"), DrawPart::da_rectangle );
+ connect( m, SIGNAL(activated(int)), itemDocument, SLOT(slotSetDrawAction(int)) );
+ //END Draw actions
+
+
+ //BEGIN Item Control actions
+ new KAction( i18n("Raise Selection"), "1uparrow", Qt::Key_PageUp, itemDocument, SLOT(raiseZ()), ac, "edit_raise" );
+ new KAction( i18n("Lower Selection"), "1downarrow", Qt::Key_PageDown, itemDocument, SLOT(lowerZ()), ac, "edit_lower" );
+ //END Item Control actions
+
+
+ KAction * na = new KAction( "", 0, 0, 0, 0, ac, "null_action" );
+ na->setEnabled(false);
+
+ setXMLFile( "ktechlabitemviewui.rc" );
+
+ m_pUpdateStatusTmr = new QTimer(this);
+ connect( m_pUpdateStatusTmr, SIGNAL(timeout()), this, SLOT(updateStatus()) );
+ connect( this, SIGNAL(viewUnfocused()), this, SLOT(stopUpdatingStatus()) );
+
+ p_itemDocument = itemDocument;
+ m_zoomLevel = 1.;
+ m_CVBEditor = new CVBEditor( p_itemDocument->canvas(), this, "cvbEditor" );
+ m_CVBEditor->setLineWidth(1);
+
+ m_layout->insertWidget( 0, m_CVBEditor );
+
+ setAcceptDrops(true);
+}
+
+
+ItemView::~ItemView()
+{
+}
+
+
+bool ItemView::canZoomIn() const
+{
+ return true;
+}
+bool ItemView::canZoomOut() const
+{
+ return int(std::floor((100*m_zoomLevel)+0.5)) > 25;
+}
+
+
+void ItemView::zoomIn()
+{
+ int currentZoomPercent = int(std::floor((100*m_zoomLevel)+0.5));
+ int newZoom = currentZoomPercent;
+
+ if ( currentZoomPercent < 100 )
+ newZoom += 25;
+ else if ( currentZoomPercent < 200 )
+ newZoom += 50;
+ else
+ newZoom += 100;
+
+ m_zoomLevel = newZoom/100.;
+
+ QWMatrix m( m_zoomLevel, 0.0, 0.0, m_zoomLevel, 1.0, 1.0 );
+ m_CVBEditor->setWorldMatrix(m);
+
+ p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems );
+ updateZoomActions();
+}
+
+
+void ItemView::zoomOut()
+{
+ int currentZoomPercent = int(std::floor((100*m_zoomLevel)+0.5));
+ int newZoom = currentZoomPercent;
+
+ if ( currentZoomPercent <= 25 )
+ return;
+ if ( currentZoomPercent <= 100 )
+ newZoom -= 25;
+ else if ( currentZoomPercent <= 200 )
+ newZoom -= 50;
+ else
+ newZoom -= 100;
+
+ m_zoomLevel = newZoom/100.;
+
+ QWMatrix m( m_zoomLevel, 0.0, 0.0, m_zoomLevel, 1.0, 1.0 );
+ m_CVBEditor->setWorldMatrix(m);
+
+ p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems );
+ updateZoomActions();
+}
+
+
+void ItemView::actualSize()
+{
+ m_zoomLevel = 1.0;
+ QWMatrix m( m_zoomLevel, 0.0, 0.0, m_zoomLevel, 1.0, 1.0 );
+ m_CVBEditor->setWorldMatrix(m);
+
+ p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems );
+ updateZoomActions();
+}
+
+
+void ItemView::updateZoomActions()
+{
+ action("view_zoom_in")->setEnabled( canZoomIn() );
+ action("view_zoom_out")->setEnabled( canZoomOut() );
+ action("view_actual_size")->setEnabled( m_zoomLevel != 1.0 );
+}
+
+
+void ItemView::dropEvent( QDropEvent *event )
+{
+ KURL::List urls;
+ if ( KURLDrag::decode( event, urls ) )
+ {
+ // Then it is URLs that we can decode :)
+ const KURL::List::iterator end = urls.end();
+ for ( KURL::List::iterator it = urls.begin(); it != end; ++it )
+ {
+ DocManager::self()->openURL(*it);
+ }
+ return;
+ }
+
+ if ( !QString(event->format()).startsWith("ktechlab/") )
+ return;
+
+ QString text;
+ QDataStream stream( event->encodedData(event->format()), IO_ReadOnly );
+ stream >> text;
+
+ QPoint position = event->pos();
+ position.setX( int((position.x() + m_CVBEditor->contentsX())/m_zoomLevel) );
+ position.setY( int((position.y() + m_CVBEditor->contentsY())/m_zoomLevel) );
+
+ // Get a new component item
+ p_itemDocument->addItem( text, position, true );
+
+ setFocus();
+}
+
+
+void ItemView::scrollToMouse( const QPoint &pos )
+{
+ QPoint position = pos * m_zoomLevel;
+
+ int left = m_CVBEditor->contentsX();
+ int top = m_CVBEditor->contentsY();
+ int right = left + m_CVBEditor->visibleWidth();
+ int bottom = top + m_CVBEditor->visibleHeight();
+
+ if( position.x() < left ) m_CVBEditor->scrollBy( position.x() - left, 0 );
+ else if( position.x() > right ) m_CVBEditor->scrollBy( position.x() - right, 0 );
+
+ if( position.y() < top ) m_CVBEditor->scrollBy( 0, position.y() - top );
+ else if( position.y() > bottom ) m_CVBEditor->scrollBy( 0, position.y() - bottom);
+}
+
+
+void ItemView::contentsMousePressEvent( QMouseEvent *e )
+{
+ if (!e)
+ return;
+
+ e->accept();
+
+ // For some reason, when we are initially unfocused, we only receive the
+ // release event if the user drags the mouse - not very often. So see if we
+ // were initially unfocused, and if so, do unclick as well.
+ bool wasFocused = isFocused();
+ setFocused();
+
+ if ( !p_itemDocument )
+ return;
+
+ p_itemDocument->canvas()->setMessage( QString::null );
+ p_itemDocument->m_cmManager->mousePressEvent( EventInfo( this, e ) );
+
+ if ( !wasFocused )
+ p_itemDocument->m_cmManager->mouseReleaseEvent( EventInfo( this, e ) );
+}
+
+
+void ItemView::contentsMouseDoubleClickEvent( QMouseEvent *e )
+{
+ if (!e)
+ return;
+
+ e->accept();
+
+ //HACK: Pass this of as a single press event if widget underneath
+ QCanvasItem * atTop = p_itemDocument->itemAtTop( e->pos()/zoomLevel() );
+ if ( atTop && atTop->rtti() == ItemDocument::RTTI::Widget )
+ contentsMousePressEvent(e);
+ else
+ p_itemDocument->m_cmManager->mouseDoubleClickEvent( EventInfo( this, e ) );
+}
+
+
+void ItemView::contentsMouseMoveEvent( QMouseEvent *e )
+{
+ if ( !e || !p_itemDocument )
+ return;
+
+ e->accept();
+
+ p_itemDocument->m_cmManager->mouseMoveEvent( EventInfo( this, e ) );
+ if ( !m_pUpdateStatusTmr->isActive() )
+ startUpdatingStatus();
+}
+
+
+void ItemView::contentsMouseReleaseEvent( QMouseEvent *e )
+{
+ if (!e)
+ return;
+
+ e->accept();
+
+ p_itemDocument->m_cmManager->mouseReleaseEvent( EventInfo( this, e ) );
+}
+
+
+void ItemView::contentsWheelEvent( QWheelEvent *e )
+{
+ if (!e)
+ return;
+
+ e->accept();
+
+ p_itemDocument->m_cmManager->wheelEvent( EventInfo( this, e ) );
+}
+
+
+void ItemView::dragEnterEvent( QDragEnterEvent *event )
+{
+ startUpdatingStatus();
+
+ KURL::List urls;
+ if ( KURLDrag::decode( event, urls ) )
+ {
+ event->accept(true);
+ // Then it is URLs that we can decode later :)
+ return;
+ }
+}
+
+
+void ItemView::enterEvent( QEvent * e )
+{
+ Q_UNUSED(e);
+ startUpdatingStatus();
+}
+
+
+void ItemView::leaveEvent( QEvent * e )
+{
+ Q_UNUSED(e);
+ stopUpdatingStatus();
+
+ // Cleanup
+ setCursor(Qt::ArrowCursor);
+
+ if (p_ktechlab)
+ p_ktechlab->slotChangeStatusbar(QString::null);
+
+ if ( p_itemDocument )
+ p_itemDocument->m_canvasTip->setVisible(false);
+}
+
+
+void ItemView::slotUpdateConfiguration()
+{
+// m_CVBEditor->setEraseColor( KTLConfig::bgColor() );
+ m_CVBEditor->setEraseColor( Qt::white );
+
+ if ( m_pUpdateStatusTmr->isActive() )
+ startUpdatingStatus();
+}
+
+
+void ItemView::startUpdatingStatus()
+{
+ m_pUpdateStatusTmr->stop();
+ m_pUpdateStatusTmr->start( int(1000./KTLConfig::refreshRate()) );
+}
+
+
+void ItemView::stopUpdatingStatus()
+{
+ m_pUpdateStatusTmr->stop();
+}
+
+
+void ItemView::updateStatus()
+{
+ QPoint pos = (m_CVBEditor->mapFromGlobal( QCursor::pos() ) + QPoint( m_CVBEditor->contentsX(), m_CVBEditor->contentsY() )) / zoomLevel();
+
+ ItemDocument * itemDocument = static_cast<ItemDocument*>(document());
+ if ( !itemDocument )
+ return;
+
+ CMManager * cmManager = itemDocument->m_cmManager;
+ CanvasTip * canvasTip = itemDocument->m_canvasTip;
+
+ bool displayTip = false;
+ QCursor cursor = Qt::ArrowCursor;
+ QString statusbar;
+
+ if ( cmManager->cmState() & CMManager::cms_repeated_add )
+ {
+ cursor = Qt::CrossCursor;
+ statusbar = i18n("Left click to add. Right click to resume normal editing");
+ }
+ else if ( cmManager->cmState() & CMManager::cms_draw )
+ {
+ cursor = Qt::CrossCursor;
+ statusbar = i18n("Click and hold to start drawing.");
+ }
+ else if ( cmManager->currentManipulator())
+ {
+ switch ( cmManager->currentManipulator()->type() )
+ {
+ case CanvasManipulator::RepeatedItemAdd:
+ cursor = Qt::CrossCursor;
+ statusbar = i18n("Left click to add. Right click to resume normal editing");
+ break;
+ case CanvasManipulator::ManualConnector:
+ statusbar = i18n("Right click to cancel the connector");
+ // no break
+ case CanvasManipulator::AutoConnector:
+ cursor = Qt::CrossCursor;
+ break;
+ case CanvasManipulator::ItemMove:
+ case CanvasManipulator::MechItemMove:
+ cursor = Qt::SizeAllCursor;
+ break;
+ case CanvasManipulator::Draw:
+ cursor = Qt::CrossCursor;
+ break;
+ default:
+ break;
+ }
+
+ }
+ else if ( QCanvasItem *qcanvasItem = itemDocument->itemAtTop(pos) )
+ {
+ switch( qcanvasItem->rtti() )
+ {
+ case ItemDocument::RTTI::Connector:
+ {
+ cursor = Qt::CrossCursor;
+ if ( itemDocument->type() != Document::dt_circuit )
+ break;
+
+ canvasTip->displayVI( static_cast<Connector*>(qcanvasItem), pos );
+ displayTip = true;
+ break;
+ }
+ case ItemDocument::RTTI::Node:
+ {
+ cursor = Qt::CrossCursor;
+ ECNode * ecnode = dynamic_cast<ECNode*>(qcanvasItem);
+ if ( !ecnode )
+ break;
+
+ canvasTip->displayVI( ecnode, pos );
+ displayTip = true;
+ break;
+ }
+ case ItemDocument::RTTI::CNItem:
+ {
+ statusbar = (static_cast<CNItem*>(qcanvasItem))->name();
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ setCursor(cursor);
+
+ if (p_ktechlab)
+ p_ktechlab->slotChangeStatusbar(statusbar);
+
+ canvasTip->setVisible(displayTip);
+}
+
+//END class ItemView
+
+
+
+//BEGIN class CVBEditor
+CVBEditor::CVBEditor( QCanvas *canvas, ItemView *itemView, const char *name )
+ : QCanvasView( canvas, itemView, name, WNoAutoErase | WStaticContents )
+{
+ b_ignoreEvents = false;
+ b_passEventsToView = true;
+ p_itemView = itemView;
+ viewport()->setMouseTracking(true);
+ setAcceptDrops(true);
+ setFrameShape(NoFrame);
+// setEraseColor( KTLConfig::bgColor() );
+ setEraseColor( Qt::white );
+ setPaletteBackgroundColor( Qt::white );
+ viewport()->setEraseColor( Qt::white );
+ viewport()->setPaletteBackgroundColor( Qt::white );
+}
+
+
+void CVBEditor::contentsMousePressEvent( QMouseEvent* e )
+{
+ if (b_passEventsToView)
+ p_itemView->contentsMousePressEvent(e);
+ else
+ QCanvasView::contentsMousePressEvent(e);
+}
+
+
+void CVBEditor::contentsMouseReleaseEvent( QMouseEvent* e )
+{
+ if (b_passEventsToView)
+ p_itemView->contentsMouseReleaseEvent(e);
+ else
+ QCanvasView::contentsMouseReleaseEvent(e);
+}
+
+
+void CVBEditor::contentsMouseDoubleClickEvent( QMouseEvent* e )
+{
+ if (b_passEventsToView)
+ p_itemView->contentsMouseDoubleClickEvent(e);
+ else
+ QCanvasView::contentsMouseDoubleClickEvent(e);
+}
+
+
+void CVBEditor::contentsMouseMoveEvent( QMouseEvent* e )
+{
+ if (b_passEventsToView)
+ p_itemView->contentsMouseMoveEvent(e);
+ else
+ QCanvasView::contentsMouseMoveEvent(e);
+}
+
+
+void CVBEditor::dragEnterEvent( QDragEnterEvent* e )
+{
+ if (b_passEventsToView)
+ p_itemView->dragEnterEvent(e);
+ else
+ QCanvasView::dragEnterEvent(e);
+}
+
+
+void CVBEditor::dropEvent( QDropEvent* e )
+{
+ if (b_passEventsToView)
+ p_itemView->dropEvent(e);
+ else
+ QCanvasView::dropEvent(e);
+}
+
+
+void CVBEditor::enterEvent( QEvent * e )
+{
+ if (b_passEventsToView)
+ p_itemView->enterEvent(e);
+ else
+ QCanvasView::enterEvent(e);
+}
+
+
+void CVBEditor::leaveEvent( QEvent* e )
+{
+ if (b_passEventsToView)
+ p_itemView->leaveEvent(e);
+ else
+ QCanvasView::leaveEvent(e);
+}
+
+
+void CVBEditor::contentsWheelEvent( QWheelEvent *e )
+{
+ if (b_ignoreEvents)
+ {
+ e->ignore();
+ return;
+ }
+
+ if (b_passEventsToView)
+ p_itemView->contentsWheelEvent(e);
+ else
+ {
+ b_ignoreEvents = true;
+ QCanvasView::wheelEvent(e);
+ b_ignoreEvents = false;
+ }
+}
+
+void CVBEditor::viewportResizeEvent( QResizeEvent * e )
+{
+ QCanvasView::viewportResizeEvent(e);
+ p_itemView->p_itemDocument->requestEvent( ItemDocument::ItemDocumentEvent::ResizeCanvasToItems );
+}
+//END class CVBEditor
+
+#include "itemview.moc"