Logo Search packages:      
Sourcecode: ktechlab version File versions

picitem.cpp

/***************************************************************************
 *   Copyright (C) 2003-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 "canvasitemparts.h"
#include "flowcodedocument.h"
#include "microinfo.h"
#include "microsettings.h"
#include "microsettingsdlg.h"
#include "micropackage.h"
#include "picitem.h"
#include "eventinfo.h"

#include <kdebug.h>
#include <kiconloader.h>
#include <klocale.h>
#include <qpainter.h>

static const int InnerWidth = 88;
static const int SidePadding = 24;
static const int TopPadding = 36;
static const int BottomPadding = 42;
static const int PinWidth = 12;
static const int PinSeparation = 16 - PinWidth;
static const int PinLength = 8;
static const int ArcWidth = 22;
static const int PinDirArrow = 3;


//BEGIN class PinItem
PinItem::PinItem( FlowCodeDocument* _view, QPoint position, bool _onLeft, PinSettings * pinSettings )
      : QCanvasRectangle(0)
{
      m_pinSettings = pinSettings;
      view = _view;
      onLeft = _onLeft;
      
      connect( m_pinSettings, SIGNAL(settingsChanged()), this, SLOT(updateDrawing()) );
      
      if ( QFontInfo(m_font).pixelSize() > 11 ) // It has to be > 11, not > 12, as (I think) pixelSize() rounds off the actual size
            m_font.setPixelSize(12);
      
      setCanvas( view->canvas() );
      
      move ( position.x(), position.y() );
      initItem();
      setZ( (ICNDocument::Z::RaisedItem + ICNDocument::Z::ResizeHandle)/2 + 1 ); // Hackish, but whatever
}


void PinItem::updateDrawing()
{
      update();
}


void PinItem::initItem()
{
      setSize( PinLength, PinWidth );
      setSelected(false);
      setPen( Qt::black );
      calcTextRect();
      show();
}


void PinItem::drawShape( QPainter& p )
{
      if (!m_pinSettings)
            return;
      
      if ( m_pinSettings->state() == PinSettings::ps_on )
      {
            if ( m_pinSettings->type() == PinSettings::pt_output )
                  setBrush( QColor( 255, 127, 127 ) );
            else
                  setBrush( QColor( 255, 191, 191 ) );
      }
      else
            setBrush( Qt::white );
      
      p.drawRect(rect());
      
      p.setFont(m_font);
      p.setBrush( Qt::NoBrush );
      QRect r = m_textRect;
      if ( onLeft )
            p.drawText( r, Qt::AlignLeft, m_pinSettings->id() );
      else
            p.drawText( r, Qt::AlignRight, m_pinSettings->id() );
      QRect br = p.boundingRect( r, Qt::AlignLeft, m_pinSettings->id() );
      
      int left;
      int right;
      if ( onLeft )
      {
            right = (int)x();
            left = right - 8;
      }
      else
      {
            left = (int)x() + PinLength;
            right = left + 8;
      }
      
      int midY = (int)y() + PinWidth/2;
      QPointArray pa(3);
      int midLeft = left + (8-PinDirArrow)/2;
      int midRight = left + (8+PinDirArrow)/2;
      
      if ( onLeft )
      {
            midLeft--;
            midRight--;
      }
      else
      {
            midLeft++;
            midRight++;
      }
      
      p.setBrush( Qt::black );
      
      // Right facing arrow
      if ( (m_pinSettings->type() == PinSettings::pt_input && onLeft) ||
                   (m_pinSettings->type() == PinSettings::pt_output && !onLeft) )
      {
            pa[0] = QPoint::QPoint( midRight, midY );
            pa[1] = QPoint::QPoint( midLeft, midY - PinDirArrow );
            pa[2] = QPoint::QPoint( midLeft, midY + PinDirArrow );
            p.drawPolygon(pa);
            p.drawLine ( left, midY, right, midY );
      }
      else // Left facing arrow
      {
            pa[0] = QPoint::QPoint( midLeft, midY );
            pa[1] = QPoint::QPoint( midRight, midY - PinDirArrow );
            pa[2] = QPoint::QPoint( midRight, midY + PinDirArrow );
            p.drawPolygon(pa);
            p.drawLine ( left, midY, right, midY );
      }
}


QRect PinItem::boundingRect () const
{
      QRect r = m_textRect;
      if ( onLeft )
            r.setLeft( (int)x() - 10 );
      else
            r.setRight( (int)x() + PinLength + 10 );
      
      return r;
}


QString PinItem::id()
{
      return m_pinSettings->id();
}


void PinItem::switchState()
{
      if ( m_pinSettings->state() == PinSettings::ps_on )
            m_pinSettings->setState(PinSettings::ps_off);
      else
            m_pinSettings->setState(PinSettings::ps_on);
      
      update();
}


00180 void PinItem::dragged( int dx )
{
      if ( (onLeft && dx > 0) ||
           (!onLeft && dx < 0) )
      {
            m_pinSettings->setType(PinSettings::pt_input);
      }
      else
            m_pinSettings->setType(PinSettings::pt_output);
      
      update();
}


void PinItem::moveBy ( double dx, double dy )
{
      QCanvasRectangle::moveBy( dx, dy );
      calcTextRect();
}


void PinItem::calcTextRect()
{
      m_textRect = rect();
      m_textRect.moveTop( m_textRect.top()-2 );
      QRect br;
      
      QWidget tmpWidget;
      QPainter p(&tmpWidget);

      p.setFont(m_font);

      if (!m_pinSettings)
      {
            kdDebug() << "PinItem::textRect: No pinSettings!"<<endl;
            return;
      }     
      if ( onLeft )
      {
            m_textRect.setLeft( (int)x() + PinLength + 2 );
            m_textRect.setRight( (int)x() + InnerWidth/2 );
            br = p.boundingRect( m_textRect, Qt::AlignLeft, m_pinSettings->id() );
      }
      else
      {
            m_textRect.setLeft( m_textRect.right() - InnerWidth/2 );
            m_textRect.setRight( (int)x() - 2 );
            br = p.boundingRect( m_textRect, Qt::AlignRight, m_pinSettings->id() );
      }
}
//END class PinItem



//BEGIN class PicItem
PicItem::PicItem( ICNDocument *icnDocument, bool newItem, const char *id, MicroSettings *_microSettings )
      : CNItem( icnDocument, newItem, id ? id : "picitem" )
{
      m_name = "PIC";
      m_type = typeString();
      p_icnDocument = icnDocument;
      icnDocument->registerItem(this);
      
      microSettings = _microSettings;
      const int numPins = microSettings->microInfo()->package()->pinCount( PicPin::type_bidir | PicPin::type_input | PicPin::type_open );
      const int numSide = (numPins/2) + (numPins%2);
      
      m_bExpanded = true;
      m_innerHeight = (numSide+2)*PinWidth + (numSide-1)*PinSeparation;
      updateVisibility();
      
      addButton( "settings", QRect( SidePadding-8, m_innerHeight+TopPadding+(BottomPadding-24)/2-1, InnerWidth+16, 24 ), i18n("Advanced...") );
      addButton( "expandBtn", QRect( (TopPadding-22)/2, (TopPadding-22)/2, 22, 22 ), KGlobal::iconLoader()->loadIcon( "down", KIcon::Small ), true );
      button("expandBtn")->setState(true);
      
      move( 12, 12 );
      
      QStringList pinIDs = microSettings->microInfo()->package()->pinIDs( PicPin::type_bidir | PicPin::type_input | PicPin::type_open );
      QStringList::iterator it = pinIDs.begin();
      
      for ( int i=0; i < numSide; ++i, ++it )
      {
            QPoint position( int(this->x()) + SidePadding - PinLength+1, int(y()) + TopPadding + (i+1)*PinWidth + i*PinSeparation );
            const QString id = *it;
            PinSettings *settings = microSettings->pinWithID(id);
            m_pinItemList.append( new PinItem( dynamic_cast<FlowCodeDocument*>(icnDocument), position, true, settings ) );
      }
      
      for ( int i=0; i < numPins/2; ++i, ++it )
      {
            QPoint position( int(this->x()) + SidePadding + InnerWidth-1, int(y()) + TopPadding + m_innerHeight - ( (i+2)*PinWidth + i*PinSeparation ) );
            const QString id = *it;
            PinSettings *settings = microSettings->pinWithID(id);
            m_pinItemList.append( new PinItem( dynamic_cast<FlowCodeDocument*>(icnDocument), position, false, settings ) );
      }

      setSelected(false);
      setPen( Qt::black );
      updateZ(-1);
      update();
      show();
}


PicItem::~PicItem()
{
      const PinItemList::iterator end = m_pinItemList.end();
      for ( PinItemList::iterator it = m_pinItemList.begin(); it != end; ++it )
            delete *it;
      
      m_pinItemList.clear();
}


00294 void PicItem::updateZ( int baseZ )
{
      (void)baseZ;
      setZ( (ICNDocument::Z::RaisedItem + ICNDocument::Z::ResizeHandle)/2 ); // Hackish, but whatever
      button("settings")->setZ( z()+1 );
      button("expandBtn")->setZ( z()+1 );
}


void PicItem::drawShape( QPainter & p )
{
      int _x = int(x());
      int _y = int(y());
      
      p.setBrush( QColor( 0xef, 0xff, 0xef ) );
      p.setFont( font() );
      
      p.drawRoundRect( _x, _y, width(), height(), 2000/width(), 2000/height() );
      
      p.drawText( _x+TopPadding-2, _y, width()-TopPadding+2, TopPadding, Qt::AlignVCenter, i18n("PIC Settings") );
      
      if ( !m_bExpanded )
            return;
      
      // Draw rectangle to cut off pins
      p.setBrush( QColor( 239, 255, 255 ) );
      QRect r( _x+SidePadding, _y+TopPadding, InnerWidth, m_innerHeight );
      p.drawRect(r);
      
      // Draw dimple thingy at end of pic
      p.drawArc( r.x()+(r.width()-ArcWidth)/2, r.y()+1-ArcWidth/2, ArcWidth, ArcWidth, 180*16, 180*16 );
      
      // Draw vertical text centered in PIC
      p.translate( r.width()/2 + r.x(), r.height()/2 + r.y() );
      p.rotate(90);
      QRect textRect( r.width()/-2, r.height()/-2, r.width(), r.height() );
      p.drawText( textRect, Qt::AlignCenter, microSettings->microInfo()->id() );
      
      p.rotate(-90);
      p.translate( r.width()/-2 - r.x(), r.height()/-2 - r.y() );
}


void PicItem::buttonStateChanged( const QString &id, bool state )
{
      if ( id == "expandBtn" )
      {
            m_bExpanded = state;
            updateVisibility();
      }
      
      else if ( id == "settings" )
      {
            if (!state)
                  return;
            
            // Redraw button
            button("settings")->setState(false);
            update();
      
            MicroSettingsDlg *dlg = new MicroSettingsDlg( microSettings, 0L, "microSettingsDlg" );
            connect( dlg, SIGNAL(okClicked()), this, SLOT(slotMicroSettingsDlgAccepted()) );
            connect( dlg, SIGNAL(applyClicked()), this, SLOT(slotMicroSettingsDlgAccepted()) );
            dlg->show();
            // At this point the PIC is selected but this does not appear to the
            // user so we must deselect it when done.
            p_icnDocument->unselectAll(); 
      }
}


void PicItem::updateVisibility()
{
      if (m_bExpanded)
            setSize( 0, 0, InnerWidth+(2*SidePadding), m_innerHeight+TopPadding+BottomPadding, true );
            
      else
            setSize( 0, 0, InnerWidth+(2*SidePadding), TopPadding, true );
      
      const PinItemList::iterator end = m_pinItemList.end();
      for ( PinItemList::iterator it = m_pinItemList.begin(); it != end; ++it )
            (*it)->setVisible(m_bExpanded);
      
      if ( Button * btn = button("settings") )
            btn->setVisible(m_bExpanded);
}


void PicItem::slotMicroSettingsDlgAccepted()
{
      const PinItemList::iterator end = m_pinItemList.end();
      for ( PinItemList::iterator it = m_pinItemList.begin(); it != end; ++it )
            canvas()->setChanged( (*it)->boundingRect() );
      
      p_icnDocument->requestStateSave();
}

bool PicItem::mousePressEvent( const EventInfo &info )
{
      QMouseEvent *e = info.mousePressEvent( 0, 0 );
      const PinItemList::iterator end = m_pinItemList.end();
      for ( PinItemList::iterator it = m_pinItemList.begin(); it != end; ++it )
            if ( e->isAccepted() && (*it)->boundingRect().contains( info.pos ) ) {
                  //reset mouse-gesture state
                  m_pressed = true;
                  m_pos = info.pos;
                  m_dragged = false;
                  m_dx = 0;
                  delete e;
                  return true;
            }

      m_pressed = false;
      delete e;
      return CNItem::mousePressEvent( info );
}

bool PicItem::mouseReleaseEvent( const EventInfo &info )
{
      QMouseEvent *e = info.mouseReleaseEvent( 0, 0 );
      if ( !m_pressed ) {
            delete e;
            return CNItem::mouseReleaseEvent( info );
      }

      const PinItemList::iterator end = m_pinItemList.end();
      for ( PinItemList::iterator it = m_pinItemList.begin(); it != end; ++it )
            if ( !e->isAccepted() ) {
                  continue;
            } else if ( (*it)->boundingRect().contains(m_pos) && (*it)->boundingRect().contains( info.pos ) ) {
                  if ( m_dragged ) {
                        (*it)->dragged( m_dx );
                  } else {
                        (*it)->switchState();
                  }
                  m_pressed = false;
                  m_dragged = false;
                  m_pos = QPoint();
                  m_dx = 0;
                  delete e;
                  return true;
            }
      delete e;
      return CNItem::mouseReleaseEvent( info );
}

bool PicItem::mouseMoveEvent( const EventInfo &info )
{
      QMouseEvent *e = info.mouseMoveEvent( 0, 0 );
      const PinItemList::iterator end = m_pinItemList.end();
      for ( PinItemList::iterator it = m_pinItemList.begin(); it != end; ++it )
            if ( e->isAccepted() && (*it)->boundingRect().contains( info.pos ) ) {
                  QPoint vec = info.pos - m_pos;
                  if ( m_pressed && vec.manhattanLength() > 4 ) {
                        m_dragged = true;
                        m_dx = vec.x();
                  }
                  delete e;
                  return true;
            }
      delete e;
      return CNItem::mouseMoveEvent( info );
}

//END class PicItem

#include "picitem.moc"

Generated by  Doxygen 1.6.0   Back to index