diff options
Diffstat (limited to 'src/flowparts')
49 files changed, 4318 insertions, 0 deletions
diff --git a/src/flowparts/Makefile.am b/src/flowparts/Makefile.am new file mode 100644 index 0000000..44e89fa --- /dev/null +++ b/src/flowparts/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/electronics \ + -I$(top_srcdir)/src/electronics/components -I$(top_srcdir)/src/gui -I$(top_srcdir)/src/languages \ + -I$(top_srcdir)/src/micro $(all_includes) +METASOURCES = AUTO +noinst_LTLIBRARIES = libflowparts.la +noinst_HEADERS = callsub.h delay.h end.h forloop.h readport.h setpin.h start.h \ + testpin.h unary.h varassignment.h varcomparison.h writeport.h repeat.h while.h \ + sub.h inputbutton.h flowpart.h pinmapping.h +libflowparts_la_SOURCES = callsub.cpp delay.cpp end.cpp forloop.cpp \ + readport.cpp setpin.cpp start.cpp testpin.cpp unary.cpp varassignment.cpp \ + varcomparison.cpp writeport.cpp repeat.cpp while.cpp sub.cpp count.cpp embed.cpp \ + interrupt.cpp keypad.cpp pulse.cpp sevenseg.cpp inputbutton.cpp flowpart.cpp \ + pinmapping.cpp + +libflowparts_la_PCH = AUTO diff --git a/src/flowparts/callsub.cpp b/src/flowparts/callsub.cpp new file mode 100644 index 0000000..8487ed0 --- /dev/null +++ b/src/flowparts/callsub.cpp @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "callsub.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* CallSub::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new CallSub( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* CallSub::libraryItem() +{ + return new LibraryItem( + QString("flow/callsub"), + i18n("Sub Call"), + i18n("Common"), + "subcall.png", + LibraryItem::lit_flowpart, + CallSub::construct ); +} + +CallSub::CallSub( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "callsub" ) +{ + m_name = i18n("Sub Call"); + m_desc = i18n("Call a subroutine. When the subroutine returns, the code will continue execution from this point."); + initCallSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "sub", Variant::Type::Combo ); + property("sub")->setCaption( i18n("Subroutine") ); + property("sub")->setValue("MySub"); +} + +CallSub::~CallSub() +{ +} + +void CallSub::dataChanged() +{ + setCaption( i18n("Call %1").arg(dataString("sub")) ); +} + +void CallSub::generateMicrobe( FlowCode *code ) +{ + code->addCode( "call " + dataString("sub") ); + code->addCodeBranch( outputPart("stdoutput" ) ); +} + diff --git a/src/flowparts/callsub.h b/src/flowparts/callsub.h new file mode 100644 index 0000000..5cba4f2 --- /dev/null +++ b/src/flowparts/callsub.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef CALLSUB_H +#define CALLSUB_H + +#include "flowpart.h" + +/** +@short FlowPart that calls a subroutine +@author David Saxton +*/ +class CallSub : public FlowPart +{ +public: + CallSub( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~CallSub(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +private: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/count.cpp b/src/flowparts/count.cpp new file mode 100644 index 0000000..dc0281f --- /dev/null +++ b/src/flowparts/count.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "count.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* Count::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Count( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Count::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/count"), + i18n("Count"), + i18n("Functions"), + "ppcount.png", + LibraryItem::lit_flowpart, + Count::construct ); +} + +Count::Count( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "count" ) +{ + m_name = i18n("Count"); + m_desc = i18n("Count the number of pulses during a fixed interval. To avoid ambiguity, this increments the counter on either a rising or falling edge, as opposed to a high or a low."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-trigger", Variant::Type::Select ); + property("0-trigger")->setAllowed( QStringList::split(',',"rising,falling") ); + property("0-triger")->setValue("rising"); + property("0-trigger")->setCaption( i18n("Trigger") ); + + createProperty( "1-length", Variant::Type::Double ); + property("1-length")->setUnit("sec"); + property("1-length")->setValue(10.0); + property("1-length")->setCaption("Interval"); +} + +Count::~Count() +{ +} + +void Count::dataChanged() +{ + double count = dataDouble("1-length"); + setCaption( i18n("Count %1 for %2 sec").arg(dataString("0-trigger")).arg(QString::number( count / getMultiplier(count), 'g', 3 ) + getNumberMag(count)) ); +} + +void Count::generateMicrobe( FlowCode *code ) +{ + const double count_ms = dataDouble("1-length")*1e3; + code->addCode( "count "+dataString("0-trigger")+" for "+QString::number(count_ms)+"ms" ); + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/count.h b/src/flowparts/count.h new file mode 100644 index 0000000..516889d --- /dev/null +++ b/src/flowparts/count.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef COUNT_H +#define COUNT_H + +#include "flowpart.h" + +/** +@short FlowPart that provides a delay +@author David Saxton +*/ +class Count : public FlowPart +{ +public: + Count( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Count(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/delay.cpp b/src/flowparts/delay.cpp new file mode 100644 index 0000000..fa37770 --- /dev/null +++ b/src/flowparts/delay.cpp @@ -0,0 +1,136 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "delay.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* Delay::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Delay( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Delay::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/delay"), + i18n("Delay"), + i18n("Functions"), + "delay.png", + LibraryItem::lit_flowpart, + Delay::construct ); +} + +Delay::Delay( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "delay" ) +{ + m_name = i18n("Delay"); + m_desc = i18n("Delay the program execution for a fixed period of time."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "delay_length", Variant::Type::Double ); + property("delay_length")->setCaption( i18n("Pause Length") ); + property("delay_length")->setUnit("sec"); + property("delay_length")->setValue(1.0); +} + +Delay::~Delay() +{ +} + +void Delay::dataChanged() +{ + double delay = dataDouble("delay_length"); + setCaption( i18n("Delay for %1 sec").arg(QString::number( delay / getMultiplier(delay), 'g', 3 )+getNumberMag(delay)) ); +} + +void Delay::generateMicrobe( FlowCode *code ) +{ + const double delayLength_ms = dataDouble("delay_length")*1e3; + code->addCode( "delay "+QString::number(delayLength_ms) ); + code->addCodeBranch( outputPart("stdoutput") ); + +// code->addVariable("COUNT_REPEAT"); + +#if 0 + // Code for pauses less than 769uS + if ( pauseLength < 769 ) + { + code->addCodeBlock( id(), "movlw " + QString::number(pauseLength/3) + "\n" + "movwf COUNT_REPEAT\n" + "call count_3uS\n" + + gotoCode("stdoutput") ); + + code->addCodeBlock( "count_3uS", "decfsz COUNT_REPEAT,1\n" + "goto count_3uS\n" + "return" ); + } + else if ( pauseLength < 196609 ) + { + code->addVariable("COUNT_LOOP_1"); + + code->addCodeBlock( id(), "movlw " + QString::number(pauseLength/(3*256)) + "\n" + "movwf COUNT_REPEAT\n" + "call count_768uS\n" + + gotoCode("stdoutput") ); + + code->addCodeBlock( "count_768uS", "decfsz COUNT_LOOP_1,1\n" + "goto count_768uS\n" + "decfsz COUNT_REPEAT,1\n" + "goto count_768uS\n" + "return" ); + } + else if ( pauseLength < 50331649 ) + { + code->addVariable("COUNT_LOOP_1"); + code->addVariable("COUNT_LOOP_2"); + + code->addCodeBlock( id(), "movlw " + QString::number(pauseLength/(3*256*256)) + "\n" + "movwf COUNT_REPEAT\n" + "call count_200mS\n" + + gotoCode("stdoutput") ); + + code->addCodeBlock( "count_200mS", "decfsz COUNT_LOOP_1,1\n" + "goto count_200mS\n" + "decfsz COUNT_LOOP_2,1\n" + "goto count_200mS\n" + "decfsz COUNT_REPEAT,1\n" + "goto count_200mS\n" + "return" ); + } + else/* if ( pauseLength < 12884901889 )*/ + { + code->addVariable("COUNT_LOOP_1"); + code->addVariable("COUNT_LOOP_2"); + code->addVariable("COUNT_LOOP_3"); + + code->addCodeBlock( id(), "movlw " + QString::number(pauseLength/(3*256*256*256)) + "\n" + "movwf COUNT_REPEAT\n" + "call count_50S\n" + + gotoCode("stdoutput") ); + + code->addCodeBlock( "count_50S", "decfsz COUNT_LOOP_1,1\n" + "goto count_50S\n" + "decfsz COUNT_LOOP_2,1\n" + "goto count_50S\n" + "decfsz COUNT_LOOP_3,1\n" + "goto count_50S\n" + "decfsz COUNT_REPEAT,1\n" + "goto count_50S\n" + "return" ); + } +#endif +} + diff --git a/src/flowparts/delay.h b/src/flowparts/delay.h new file mode 100644 index 0000000..fbe6326 --- /dev/null +++ b/src/flowparts/delay.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef DELAY_H +#define DELAY_H + +#include "flowpart.h" + +/** +@short FlowPart that provides a delay +@author David Saxton +*/ +class Delay : public FlowPart +{ +public: + Delay( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Delay(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/embed.cpp b/src/flowparts/embed.cpp new file mode 100644 index 0000000..ca04c65 --- /dev/null +++ b/src/flowparts/embed.cpp @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "embed.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* Embed::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Embed( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Embed::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/embed"), + i18n("Embed"), + i18n("Common"), + "embed.png", + LibraryItem::lit_flowpart, + Embed::construct + ); +} + +Embed::Embed( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "embed" ) +{ + m_name = i18n("Embed"); + m_desc = i18n("Doubleclick on the item to edit the embedded code."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "type", Variant::Type::Select ); + property("type")->setAllowed( QStringList::split( ',', "Microbe,Assembly" ) ); + property("type")->setValue("Microbe"); + property("type")->setCaption( i18n("Type") ); // TODO: replace this with i18n( "the type", "Type" ); + + createProperty( "code", Variant::Type::Multiline ); + property("code")->setCaption( i18n("Code") ); + property("code")->setValue( i18n("// Embedded code:") ); +} + +Embed::~Embed() +{ +} + + +void Embed::dataChanged() +{ + const QString sample = dataString("code").left(10).replace("\n"," "); + setCaption( i18n("%1: %2...").arg(dataString("type")).arg(sample) ); +} + + +bool Embed::typeIsMicrobe() const +{ + return dataString("type") == "Microbe"; +} + + +void Embed::generateMicrobe( FlowCode *code ) +{ + if ( typeIsMicrobe() ) + code->addCode( dataString("code") ); + + else + { + // Is assembly code, we need to microbe as such + code->addCode("asm\n{"); + code->addCode( dataString("code") ); + code->addCode("}"); + } + + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/embed.h b/src/flowparts/embed.h new file mode 100644 index 0000000..d891c39 --- /dev/null +++ b/src/flowparts/embed.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef EMBED_H +#define EMBED_H + +#include "flowpart.h" + +/** +@short FlowPart that provides a delay +@author David Saxton +*/ +class Embed : public FlowPart +{ +public: + Embed( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Embed(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + bool typeIsMicrobe() const; + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/end.cpp b/src/flowparts/end.cpp new file mode 100644 index 0000000..37d7e91 --- /dev/null +++ b/src/flowparts/end.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "end.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* End::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new End( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* End::libraryItem() +{ + return new LibraryItem( + QString("flow/end"), + i18n("End"), + i18n("Common"), + "end.png", + LibraryItem::lit_flowpart, + End::construct ); +} + +End::End( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "END" ) +{ + m_name = i18n("End"); + m_desc = i18n("End the program execution, putting the IC into sleep. Unlike Start, however, this FlowPart is not necessary for proper program execution"); + initRoundedRectSymbol(); + createStdInput(); + setCaption( i18n("End") ); +} + +End::~End() +{ +} + +void End::generateMicrobe( FlowCode */*code*/ ) +{ +} + diff --git a/src/flowparts/end.h b/src/flowparts/end.h new file mode 100644 index 0000000..a2c2a1e --- /dev/null +++ b/src/flowparts/end.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef END_H +#define END_H + +#include "flowpart.h" + +/** +@short FlowPart that tells the program where to end +@author David Saxton +*/ +class End : public FlowPart +{ +public: + End( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~End(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); +}; + +#endif diff --git a/src/flowparts/flowpart.cpp b/src/flowparts/flowpart.cpp new file mode 100644 index 0000000..e12213c --- /dev/null +++ b/src/flowparts/flowpart.cpp @@ -0,0 +1,977 @@ +/*************************************************************************** + * 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 "connector.h" +#include "flowcodedocument.h" +#include "flowcode.h" +#include "flowpart.h" +#include "fpnode.h" +#include "itemdocument.h" +#include "itemdocumentdata.h" +#include "microsettings.h" +#include "micropackage.h" +#include "picinfo.h" +#include "pinmapping.h" +#include "variant.h" + +#include <kdebug.h> + +#include <qbitarray.h> +#include <qbitmap.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qregexp.h> + +#include <assert.h> +#include <algorithm> +#include <cmath> + +// The following arrays of numbers represent the positions of nodes in different configurations, +// with the numbers as NodeInfo::Position. + +Node::node_dir diamondNodePositioning[8][3] = { + {Node::dir_up, Node::dir_down, Node::dir_right}, + {Node::dir_up, Node::dir_down, Node::dir_left}, + {Node::dir_up, Node::dir_right,Node::dir_down}, + {Node::dir_up, Node::dir_right,Node::dir_left}, + {Node::dir_left,Node::dir_right,Node::dir_down}, + {Node::dir_left,Node::dir_right,Node::dir_up}, + {Node::dir_left,Node::dir_down, Node::dir_right}, + {Node::dir_left,Node::dir_down, Node::dir_up} }; + +Node::node_dir inOutNodePositioning[8][2] = { + {Node::dir_up,Node::dir_down}, + {Node::dir_up,Node::dir_right}, + {Node::dir_up,Node::dir_left}, + {Node::dir_right,Node::dir_right}, // (invalid) + {Node::dir_left,Node::dir_right}, + {Node::dir_left,Node::dir_down}, + {Node::dir_left,Node::dir_up}, + {Node::dir_right,Node::dir_right} }; // (invalid) + +Node::node_dir inNodePositioning[4] = {Node::dir_up,Node::dir_right,Node::dir_down,Node::dir_left}; + +Node::node_dir outNodePositioning[4] = {Node::dir_down,Node::dir_left,Node::dir_up,Node::dir_right}; + +FlowPart::FlowPart( ICNDocument *icnDocument, bool newItem, const QString &id ) + : CNItem( icnDocument, newItem, id ) +{ + icnDocument->registerItem(this); + m_pFlowCodeDocument = dynamic_cast<FlowCodeDocument*>(icnDocument); + assert( m_pFlowCodeDocument ); + + m_flowSymbol = FlowPart::ps_other; + m_orientation = 0; + m_stdInput = 0l; + m_stdOutput = 0l; + m_altOutput = 0l; + + connect( m_pFlowCodeDocument, SIGNAL(picTypeChanged()), this, SLOT(slotUpdateFlowPartVariables()) ); + connect( m_pFlowCodeDocument, SIGNAL(pinMappingsChanged()), this, SLOT(slotUpdateFlowPartVariables()) ); +} + + +FlowPart::~FlowPart() +{ + // We have to check view, as if the item is deleted before the CNItem constructor + // is called, then there will be no view + if (m_pFlowCodeDocument) + { + const VariantDataMap::iterator end = m_variantData.end(); + for ( VariantDataMap::iterator it = m_variantData.begin(); it != end; ++it ) + { + Variant *v = it.data(); + if (v) + m_pFlowCodeDocument->varNameChanged( "", v->value().toString() ); + } + } +} + + +void FlowPart::setCaption( const QString &caption ) +{ + if ( m_flowSymbol == FlowPart::ps_other ) + { + m_caption = caption; + return; + } + + QWidget *w = new QWidget(); + QPainter p(w); + p.setFont( font() ); + const int text_width = p.boundingRect( boundingRect(), (Qt::SingleLine | Qt::AlignHCenter | Qt::AlignVCenter), caption ).width(); + p.end(); + delete w; + int width = std::max( ((int)(text_width/16))*16, 48 ); + + switch(m_flowSymbol) + { + case FlowPart::ps_call: + { + width += 48; + break; + } + case FlowPart::ps_io: + case FlowPart::ps_round: + { + width += 32; + break; + } + case FlowPart::ps_decision: + { + width += 64; + break; + } + case FlowPart::ps_process: + default: + { + width += 32; + break; + } + } + + bool hasSideConnectors = m_flowSymbol == FlowPart::ps_decision; + if ( hasSideConnectors && (width != this->width()) ) + p_icnDocument->requestRerouteInvalidatedConnectors(); + + initSymbol( m_flowSymbol, width ); + m_caption = caption; +} +void FlowPart::postResize() +{ + updateNodePositions(); + CNItem::postResize(); +} + +void FlowPart::createStdInput() +{ + m_stdInput = (FPNode*)createNode( 0, 0, Node::dir_up, "stdinput", Node::fp_in ); + updateNodePositions(); +} +void FlowPart::createStdOutput() +{ + m_stdOutput = (FPNode*)createNode( 0, 0, Node::dir_down, "stdoutput", Node::fp_out ); + updateNodePositions(); +} +void FlowPart::createAltOutput() +{ + m_altOutput = (FPNode*)createNode( 0, 0, Node::dir_right, "altoutput", Node::fp_out ); + updateNodePositions(); +} + +void FlowPart::initSymbol( FlowPart::FlowSymbol symbol, int width ) +{ + m_flowSymbol = symbol; + + switch(symbol) + { + case FlowPart::ps_other: + { + return; + } + case FlowPart::ps_call: + case FlowPart::ps_process: + { + setItemPoints( QRect( -width/2, -16, width, 24 ) ); + break; + } + + case FlowPart::ps_io: + { + // define parallelogram shape + QPointArray pa(4); + pa[0] = QPoint( -(width-10)/2, -16 ); + pa[1] = QPoint( width/2, -16 ); + pa[2] = QPoint( (width-10)/2, 8 ); + pa[3] = QPoint( -width/2, 8 ); + setItemPoints(pa); + break; + } + + case FlowPart::ps_round: + { + // define rounded rectangles as two semicricles with RP_NUM/2 points with gap inbetween + // These points are not used for drawing; merely for passing to qcanvaspolygonitem for collision detection + // If there is a better way for a rounder rectangle + collision detection, please let me know... + + int halfHeight = 12; + + // Draw semicircle + double x; + const int RP_NUM = 48; + QPointArray pa(RP_NUM); + int point = 0; + for ( double y = -1.0; y <= 1.0; y+= 4.0/(RP_NUM-2) ) + { + x = sqrt(1-y*y)*halfHeight; + pa[point] = QPoint( (int)(width+x)-halfHeight, (int)(halfHeight*y) ); + pa[RP_NUM-1-point] = QPoint ( (int)(halfHeight-x), (int)(halfHeight*y) ); + point++; + } + + pa.translate( -width/2, 4 ); + setItemPoints(pa); + break; + } + + case FlowPart::ps_decision: + { + // define rhombus + QPointArray pa(6); + pa[0] = QPoint( 0, -24 ); + pa[1] = QPoint( width/2, -6 ); + pa[2] = QPoint( width/2, 6 ); + pa[3] = QPoint( 0, 24 ); + pa[4] = QPoint( -width/2, 6 ); + pa[5] = QPoint( -width/2, -6 ); + setItemPoints(pa); + break; + } + default: kdError() << k_funcinfo << "Unknown flowSymbol: "<<symbol<<endl; + } +} + +void FlowPart::drawShape( QPainter &p ) +{ + initPainter(p); + + const double _x = int( x() + offsetX() ); + const double _y = int( y() + offsetY() ); + const double w = width(); + double h = height(); + + switch (m_flowSymbol) + { + case FlowPart::ps_other: + { + CNItem::drawShape(p); + break; + } + + case FlowPart::ps_io: + { + h--; + double roundSize = 8; + double slantIndent = 5; + + const double pi = 3.1415926536; + const double DPR = 180./pi; +// CNItem::drawShape(p); + double inner = std::atan(h/slantIndent); + double outer = pi-inner; + + int inner16 = int(16*inner*DPR); + int outer16 = int(16*outer*DPR); + + p.save(); + p.setPen( Qt::NoPen ); + p.drawPolygon( areaPoints() ); + p.restore(); + + p.drawLine( int(_x+slantIndent+roundSize/2), int(_y), int(_x+w-roundSize/2), int(_y) ); + p.drawLine( int(_x-slantIndent+w-roundSize/2), int(_y+h), int(_x+roundSize/2), int(_y+h) ); + p.drawLine( int(_x+w+(std::sin(outer)-1)*(roundSize/2)), int(_y+(1-std::cos(outer))*(roundSize/2)), + int(_x+w-slantIndent+(std::sin(inner)-1)*(roundSize/2)), int(_y+h+(std::cos(inner)-1)*(roundSize/2)) ); + p.drawLine( int(_x+(1-std::sin(outer))*(roundSize/2)), int(_y+h+(std::cos(outer)-1)*(roundSize/2)), + int(_x+slantIndent+(1-std::sin(inner))*(roundSize/2)), int(_y+(1-std::cos(inner))*(roundSize/2)) ); + + p.drawArc( int(_x+slantIndent), int(_y), int(roundSize), int(roundSize), 90*16, inner16 ); + p.drawArc( int(_x+w-roundSize), int(_y), int(roundSize), int(roundSize), 270*16+inner16, outer16 ); + p.drawArc( int(_x-slantIndent+w-roundSize), int(_y+h-roundSize), int(roundSize), int(roundSize), 270*16, inner16 ); + p.drawArc( int(_x), int(_y+h-roundSize), int(roundSize), int(roundSize), 90*16+inner16, outer16) ; + break; + } + + case FlowPart::ps_decision: + { + // TODO Make the shape nice and pretty with rounded corners + CNItem::drawShape(p); + break; + } + + case FlowPart::ps_call: + { + p.drawRoundRect( int(_x), int(_y), int(w), int(h+1), int(1000./w), int(1000./h) ); + p.drawLine( int(_x+8), int(_y), int(_x+8), int(_y+h) ); + p.drawLine( int(_x+w-8), int(_y), int(_x+w-8), int(_y+h) ); + break; + } + case FlowPart::ps_process: + { + p.drawRoundRect( int(_x), int(_y), int(w), int(h+1), int(1000./w), int(1000./h) ); + break; + } + + case FlowPart::ps_round: + { + p.drawRoundRect( int(_x), int(_y), int(w), int(h+1), 30, 100 ); + break; + } + } + + p.setPen( Qt::black ); + p.setFont( font() ); + p.drawText( boundingRect(), (Qt::WordBreak | Qt::AlignHCenter | Qt::AlignVCenter), m_caption ); +} + +QString FlowPart::gotoCode( const QString& internalNodeId ) +{ + FlowPart *end = outputPart(internalNodeId); + if (!end) return ""; + return "goto "+end->id(); +} + +FlowPart* FlowPart::outputPart( const QString& internalNodeId ) +{ + Node *node = p_icnDocument->nodeWithID( nodeId(internalNodeId) ); + + FPNode *fpnode = dynamic_cast<FPNode*>(node); + if ( !fpnode || fpnode->type() == Node::fp_in ) + return 0l; + + return fpnode->outputFlowPart(); +} + +FlowPartList FlowPart::inputParts( const QString& id ) +{ + Node *node = p_icnDocument->nodeWithID(id); + + if ( FPNode *fpNode = dynamic_cast<FPNode*>(node) ) + return fpNode->inputFlowParts(); + + return FlowPartList(); +} + +FlowPartList FlowPart::inputParts() +{ + FlowPartList list; + + const NodeMap::iterator nEnd = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != nEnd; ++it ) + { + Node *node = p_icnDocument->nodeWithID( it.data().id ); + FlowPartList newList; + + if ( FPNode *fpNode = dynamic_cast<FPNode*>(node) ) + newList = fpNode->inputFlowParts(); + + const FlowPartList::iterator nlEnd = newList.end(); + for ( FlowPartList::iterator it = newList.begin(); it != nlEnd; ++it ) + { + if (*it) list.append(*it); + } + } + + return list; +} + +FlowPartList FlowPart::outputParts() +{ + FlowPartList list; + + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + FlowPart *part = outputPart( it.key() ); + if (part) list.append(part); + } + + return list; +} + + +FlowPart* FlowPart::endPart( QStringList ids, FlowPartList *previousParts ) +{ + if ( ids.empty() ) + { + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + ids.append( it.key() ); + } + filterEndPartIDs( &ids ); + } + + const bool createdList = (!previousParts); + if (createdList) { + previousParts = new FlowPartList; + } else if ( previousParts->contains(this) ) { + return 0l; + } + previousParts->append(this); + + if ( ids.empty() ) { + return 0l; + } + if ( ids.size() == 1 ) { + return outputPart( *(ids.begin()) ); + } + + typedef QValueList<FlowPartList> ValidPartsList; + ValidPartsList validPartsList; + + const QStringList::iterator idsEnd = ids.end(); + for ( QStringList::iterator it = ids.begin(); it != idsEnd; ++it ) + { + int prevLevel = level(); + FlowPartList validParts; + FlowPart *part = outputPart(*it); + while (part) + { + if ( !validParts.contains(part) ) + { + validParts.append(part); +// if ( part->level() >= level() ) { + const int _l = part->level(); + part = part->endPart( QStringList(), previousParts ); + prevLevel = _l; +// } else { +// part = 0l; +// } + } + else { + part = 0l; + } + } + if ( !validParts.empty() ) { + validPartsList.append(validParts); + } + } + + if (createdList) + { + delete previousParts; + previousParts = 0l; + } + + if ( validPartsList.empty() ) return 0l; + + FlowPartList firstList = *(validPartsList.begin()); + const FlowPartList::iterator flEnd = firstList.end(); + const ValidPartsList::iterator vplEnd = validPartsList.end(); + for ( FlowPartList::iterator it = firstList.begin(); it != flEnd; ++it ) + { + bool ok = true; + for ( ValidPartsList::iterator vplit = validPartsList.begin(); vplit != vplEnd; ++vplit ) + { + if ( !(*vplit).contains(*it) ) ok = false; + } + if (ok) return *it; + } + + return 0l; +} + + +void FlowPart::handleIfElse( FlowCode *code, const QString &case1Statement, const QString &case2Statement, + const QString &case1, const QString &case2 ) +{ + if (!code) return; + + FlowPart *stop = 0l; + FlowPart *part1 = outputPart(case1); + FlowPart *part2 = outputPart(case2); + + if ( part1 && part2 ) stop = endPart( QStringList::split( ',', case1+","+case2 ) ); + + if ( (!part1 && !part2) || (part1 == stop && part2 == stop) ) return; + + code->addStopPart(stop); + + if ( part1 && part1 != stop && code->isValidBranch(part1) ) + { + // Use the case1 statement + code->addCode( "if "+case1Statement+" then "+"\n{" ); + code->addCodeBranch(part1); + code->addCode("}"); + + if ( part2 && part2 != stop && code->isValidBranch(part2) ) + { + code->addCode( "else\n{" ); + code->addCodeBranch(part2); + code->addCode("}"); + } + } + else if ( code->isValidBranch(part2) ) + { + // Use the case2 statement + code->addCode( "if "+case2Statement+" then "+"\n{" ); + code->addCodeBranch(part2); + code->addCode("}"); + } + + code->removeStopPart(stop); + code->addCodeBranch(stop); +} + + +Variant * FlowPart::createProperty( const QString & id, Variant::Type::Value type ) +{ + if ( type != Variant::Type::Port + && type != Variant::Type::Pin + && type != Variant::Type::VarName + && type != Variant::Type::SevenSegment + && type != Variant::Type::KeyPad ) + return CNItem::createProperty( id, type ); + + Variant * v = createProperty( id, Variant::Type::String ); + v->setType(type); + + if ( type == Variant::Type::VarName ) + { + if ( MicroSettings * settings = m_pFlowCodeDocument->microSettings() ) + v->setAllowed( settings->variableNames() ); + connect( property(id), SIGNAL(valueChanged(QVariant, QVariant )), this, SLOT(varNameChanged(QVariant, QVariant )) ); + } + else + slotUpdateFlowPartVariables(); + + return v; +} + + +void FlowPart::slotUpdateFlowPartVariables() +{ + if (!m_pFlowCodeDocument) + return; + + MicroSettings *s = m_pFlowCodeDocument->microSettings(); + if (!s) + return; + + const PinMappingMap pinMappings = s->pinMappings(); + QStringList sevenSegMaps; + QStringList keyPadMaps; + PinMappingMap::const_iterator pEnd = pinMappings.end(); + for ( PinMappingMap::const_iterator it = pinMappings.begin(); it != pEnd; ++it ) + { + switch ( it.data().type() ) + { + case PinMapping::SevenSegment: + sevenSegMaps << it.key(); + break; + + case PinMapping::Keypad_4x3: + case PinMapping::Keypad_4x4: + keyPadMaps << it.key(); + break; + + case PinMapping::Invalid: + break; + } + } + + QStringList ports = s->microInfo()->package()->portNames(); + ports.sort(); + + QStringList pins = s->microInfo()->package()->pinIDs(PicPin::type_bidir | PicPin::type_input | PicPin::type_open); + pins.sort(); + + const VariantDataMap::iterator vEnd = m_variantData.end(); + for ( VariantDataMap::iterator it = m_variantData.begin(); it != vEnd; ++it ) + { + Variant * v = it.data(); + if ( !v ) + continue; + + if ( v->type() == Variant::Type::Port ) + v->setAllowed( ports ); + + else if ( v->type() == Variant::Type::Pin ) + v->setAllowed( pins ); + + else if ( v->type() == Variant::Type::SevenSegment ) + { + v->setAllowed( sevenSegMaps ); + if ( !sevenSegMaps.isEmpty() && !sevenSegMaps.contains( v->value().toString() ) ) + v->setValue( sevenSegMaps.first() ); + } + + else if ( v->type() == Variant::Type::KeyPad ) + { + v->setAllowed( keyPadMaps ); + if ( !keyPadMaps.isEmpty() && !keyPadMaps.contains( v->value().toString() ) ) + v->setValue( keyPadMaps.first() ); + } + } +} + + +void FlowPart::updateVarNames() +{ + if (!m_pFlowCodeDocument) + return; + + MicroSettings *s = m_pFlowCodeDocument->microSettings(); + if (!s) + return; + + const QStringList names = s->variableNames(); + const VariantDataMap::iterator end = m_variantData.end(); + for ( VariantDataMap::iterator it = m_variantData.begin(); it != end; ++it ) + { + Variant *v = it.data(); + if ( v && v->type() == Variant::Type::VarName ) + v->setAllowed(names); + } +} + + +void FlowPart::varNameChanged( QVariant newValue, QVariant oldValue ) +{ + if (!m_pFlowCodeDocument) + return; + m_pFlowCodeDocument->varNameChanged( newValue.asString(), oldValue.asString() ); +} + + +inline int nodeDirToPos( Node::node_dir dir ) +{ + switch (dir) + { + case Node::dir_right: + return 0; + case Node::dir_up: + return 1; + case Node::dir_left: + return 2; + case Node::dir_down: + return 3; + } + return 0; +} + + +void FlowPart::updateAttachedPositioning( ) +{ + if (b_deleted) + return; + + //BEGIN Rearrange text if appropriate + const QRect textPos[4] = { + QRect( offsetX()+width(), 6, 40, 16 ), + QRect( 0, offsetY()-16, 40, 16 ), + QRect( offsetX()-40, 6, 40, 16 ), + QRect( 0, offsetY()+height(), 40, 16 ) }; + + NodeInfo * stdOutputInfo = m_stdOutput ? &m_nodeMap["stdoutput"] : 0; + NodeInfo * altOutputInfo = m_altOutput ? &m_nodeMap["altoutput"] : 0l; + + Text *outputTrueText = m_textMap.contains("output_true") ? m_textMap["output_true"] : 0l; + Text *outputFalseText = m_textMap.contains("output_false") ? m_textMap["output_false"] : 0l; + + if ( stdOutputInfo && outputTrueText ) + outputTrueText->setOriginalRect( textPos[ nodeDirToPos( (Node::node_dir)stdOutputInfo->orientation ) ] ); + + if ( altOutputInfo && outputFalseText ) + outputFalseText->setOriginalRect( textPos[ nodeDirToPos( (Node::node_dir)altOutputInfo->orientation ) ] ); + + const TextMap::iterator textMapEnd = m_textMap.end(); + for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) + { + QRect pos = it.data()->recommendedRect(); + it.data()->move( pos.x() + x(), pos.y() + y() ); + it.data()->setGuiPartSize( pos.width(), pos.height() ); + } + //END Rearrange text if appropriate + + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + if ( !it.data().node ) + { + kdError() << k_funcinfo << "Node in nodemap is null" << endl; + continue; + } + + double nx = it.data().x; + double ny = it.data().y; + +#define round_8(x) (((x) > 0) ? int(((x)+4)/8)*8 : int(((x)-4)/8)*8) + nx = round_8(nx); + ny = round_8(ny); +#undef round_8 + + it.data().node->move( int(nx+x()), int(ny+y()) ); + it.data().node->setOrientation( (Node::node_dir)it.data().orientation ); + } +} + + +ItemData FlowPart::itemData( ) const +{ + ItemData itemData = CNItem::itemData(); + itemData.orientation = m_orientation; + return itemData; +} + + +void FlowPart::restoreFromItemData( const ItemData & itemData ) +{ + CNItem::restoreFromItemData(itemData); + if ( itemData.orientation >= 0 ) + setOrientation( uint(itemData.orientation) ); +} + + +void FlowPart::updateNodePositions() +{ + if ( m_orientation > 7 ) + { + kdWarning() << k_funcinfo << "Invalid orientation: "<<m_orientation<<endl; + return; + } + + NodeInfo * stdInputInfo = m_stdInput ? &m_nodeMap["stdinput"] : 0l; + NodeInfo * stdOutputInfo = m_stdOutput ? &m_nodeMap["stdoutput"] : 0; + NodeInfo * altOutputInfo = m_altOutput ? &m_nodeMap["altoutput"] : 0l; + + if ( m_stdInput && m_stdOutput && m_altOutput ) + { + stdInputInfo->orientation = diamondNodePositioning[m_orientation][0]; + stdOutputInfo->orientation = diamondNodePositioning[m_orientation][1]; + altOutputInfo->orientation = diamondNodePositioning[m_orientation][2]; + } + else if ( m_stdInput && m_stdOutput ) + { + stdInputInfo->orientation = inOutNodePositioning[m_orientation][0]; + stdOutputInfo->orientation = inOutNodePositioning[m_orientation][1]; + } + else if ( m_orientation < 4 ) + { + if (stdInputInfo) + stdInputInfo->orientation = inNodePositioning[m_orientation]; + else if (stdOutputInfo) + stdOutputInfo->orientation = outNodePositioning[m_orientation]; + } + else + { + kdWarning() << k_funcinfo << "Invalid orientation: "<<m_orientation<<endl; + return; + } + + const NodeMap::iterator end = m_nodeMap.end(); + for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) + { + if ( !it.data().node ) + kdError() << k_funcinfo << "Node in nodemap is null" << endl; + + else + { + switch ( it.data().orientation ) + { + case Node::dir_right: + it.data().x = offsetX()+width()+8; + it.data().y = 0; + break; + case Node::dir_up: + it.data().x = 0; + it.data().y = offsetY()-8; + break; + case Node::dir_left: + it.data().x = offsetX()-8; + it.data().y = 0; + break; + case Node::dir_down: + it.data().x = 0; + it.data().y = offsetY()+height()+8;; + break; + } + } + } + + updateAttachedPositioning(); +} + + +void FlowPart::setOrientation( uint orientation ) +{ + if ( orientation == m_orientation ) + return; + + m_orientation = orientation; + updateNodePositions(); + p_icnDocument->requestRerouteInvalidatedConnectors(); +} + + +uint FlowPart::allowedOrientations( ) const +{ + // The bit positions shown here represent whether or not that orientation is allowed, the orientation being + // what is displayed in the i'th position (0 to 3 on top, 4 to 7 on bottom) of orientation widget + + if ( m_stdInput && m_stdOutput && m_altOutput ) + return 255; + + if ( m_stdInput && m_stdOutput ) + return 119; + + if ( m_stdInput || m_stdOutput ) + return 15; + + return 0; +} + +void FlowPart::orientationPixmap( uint orientation, QPixmap & pm ) const +{ + const QSize size = pm.size(); + + if ( ! ( allowedOrientations() & ( 1 << orientation ) ) ) + { + kdWarning() << k_funcinfo << "Requesting invalid orientation of " << orientation << endl; + return; + } + + QBitmap mask( 50, 50 ); + QPainter maskPainter(&mask); + mask.fill( Qt::color0 ); + maskPainter.setBrush(Qt::color1); + maskPainter.setPen(Qt::color1); + + QPainter p(&pm); + p.setBrush(m_brushCol); + p.setPen( Qt::black ); + + // In order: right corner, top corner, left corner, bottom corner + + QPoint c[4] = { + QPoint( int(0.7*size.width()), int(0.5*size.height()) ), + QPoint( int(0.5*size.width()), int(0.4*size.height()) ), + QPoint( int(0.3*size.width()), int(0.5*size.height()) ), + QPoint( int(0.5*size.width()), int(0.6*size.height()) ) }; + + QPoint d[4]; + d[0] = c[0] + QPoint( 7, 0 ); + d[1] = c[1] + QPoint( 0, -7 ); + d[2] = c[2] + QPoint( -7, 0 ); + d[3] = c[3] + QPoint( 0, 7 ); + + if ( m_stdInput && m_stdOutput && m_altOutput ) + { + //BEGIN Draw diamond outline + QPointArray diamond(4); + for ( uint i=0; i<4; ++i ) + diamond[i] = c[i]; + + p.drawPolygon(diamond); + maskPainter.drawPolygon(diamond); + //END Draw diamond outline + + + //BEGIN Draw input + int pos0 = nodeDirToPos( diamondNodePositioning[orientation][0] ); + p.drawLine( c[pos0], d[pos0] ); + maskPainter.drawLine( c[pos0], d[pos0] ); + //END Draw input + + + //BEGIN Draw "true" output as a tick + QPointArray tick(4); + tick[0] = QPoint( -3, 0 ); + tick[1] = QPoint( 0, 2 ); + tick[2] = QPoint( 0, 2 ); + tick[3] = QPoint( 4, -2 ); + + int pos1 = nodeDirToPos( diamondNodePositioning[orientation][1] ); + tick.translate( d[pos1].x(), d[pos1].y() ); + p.drawLineSegments(tick); + maskPainter.drawLineSegments(tick); + //END Draw "true" output as a tick + + + //BEGIN Draw "false" output as a cross + QPointArray cross(4); + cross[0] = QPoint( -2, -2 ); + cross[1] = QPoint( 2, 2 ); + cross[2] = QPoint( -2, 2 ); + cross[3] = QPoint( 2, -2 ); + + int pos2 = nodeDirToPos( diamondNodePositioning[orientation][2] ); + cross.translate( d[pos2].x(), d[pos2].y() ); + p.drawLineSegments(cross); + maskPainter.drawLineSegments(cross); + //END Draw "false" output as a cross + } + + else if ( m_stdInput || m_stdOutput ) + { + p.drawRoundRect( int(0.3*size.width()), int(0.4*size.height()), int(0.4*size.width()), int(0.2*size.height()) ); + maskPainter.drawRoundRect( int(0.3*size.width()), int(0.4*size.height()), int(0.4*size.width()), int(0.2*size.height()) ); + + int hal = 5; // half arrow length + int haw = 3; // half arrow width + + QPoint arrows[4][6] = { + { QPoint( hal, 0 ), QPoint( 0, -haw ), + QPoint( hal, 0 ), QPoint( -hal, 0 ), + QPoint( hal, 0 ), QPoint( 0, haw ) }, + + { QPoint( 0, -hal ), QPoint( -haw, 0 ), + QPoint( 0, -hal ), QPoint( 0, hal ), + QPoint( 0, -hal ), QPoint( haw, 0 ) }, + + { QPoint( -hal, 0 ), QPoint( 0, -haw ), + QPoint( -hal, 0 ), QPoint( hal, 0 ), + QPoint( -hal, 0 ), QPoint( 0, haw ) }, + + { QPoint( 0, hal ), QPoint( -haw, 0 ), + QPoint( 0, hal ), QPoint( 0, -hal ), + QPoint( 0, hal ), QPoint( haw, 0 ) } }; + + int inPos = -1; + int outPos = -1; + + if ( m_stdInput && m_stdOutput ) + { + inPos = nodeDirToPos( inOutNodePositioning[orientation][0] ); + outPos = nodeDirToPos( inOutNodePositioning[orientation][1] ); + } + else if ( m_stdInput ) + { + inPos = nodeDirToPos( inNodePositioning[orientation] ); + } + else if ( m_stdOutput ) + { + outPos = nodeDirToPos( outNodePositioning[orientation] ); + } + + if ( inPos != -1 ) + { + QPointArray inArrow(6); + for ( int i=0; i<6; ++i ) + { + inArrow[i] = arrows[(inPos+2)%4][i]; + } + inArrow.translate( d[inPos].x(), d[inPos].y() ); + p.drawPolygon(inArrow); + maskPainter.drawPolygon(inArrow); + } + + if ( outPos != -1 ) + { + QPointArray outArrow(6); + for ( int i=0; i<6; ++i ) + { + outArrow[i] = arrows[outPos][i]; + } + outArrow.translate( d[outPos].x(), d[outPos].y() ); + p.drawPolygon(outArrow); + maskPainter.drawPolygon(outArrow); + } + } + + pm.setMask(mask); +} + + +#include "flowpart.moc" + + diff --git a/src/flowparts/flowpart.h b/src/flowparts/flowpart.h new file mode 100644 index 0000000..d689ebf --- /dev/null +++ b/src/flowparts/flowpart.h @@ -0,0 +1,197 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FLOWPART_H +#define FLOWPART_H + +#include "cnitem.h" + +class ICNDocument; +class Node; +class FlowCode; +class FlowCodeDocument; +class FlowPart; +class FPNode; +class QPixmap; +class QSize; + +typedef QValueList<FlowPart*> FlowPartList; + +/** +All flow parts (eg 'CallSub', 'Read from Port' ,etc) should inherit from this class. +It provides basic functionality for creating commonly used nodes, as well as a virtual function +that you should reinherit for generating the assembly code. +@short Base class for all FlowParts +@author David Saxton +*/ +class FlowPart : public CNItem +{ +Q_OBJECT +public: + enum FlowSymbol + { + ps_process, // Process - Plain rectangular box + ps_call, // Call - Rectangular box with double vertical lines at either end + ps_io, // I/O - Slanter rectangular box + ps_round, // Start/End - Rounded rectangular box + ps_decision, // Decision - Diamond shape + ps_other // Custom shape, which is ignored by FlowPart + }; + FlowPart( ICNDocument *icnDocument, bool newItem, const QString &id ); + virtual ~FlowPart(); + + virtual void generateMicrobe( FlowCode */*code*/ ) = 0; + /** + * Set a preset "orientation" of this item - 0 through 7 + */ + void setOrientation( uint orientation ); + uint orientation() const { return m_orientation; } + /** + * The allowed orientations, as bit positions of 0 through 7 + */ + uint allowedOrientations() const; + virtual ItemData itemData() const; + virtual void restoreFromItemData( const ItemData &itemData ); + /** + * Sets the caption displayed in the flowpart, resizes the item as necessary + */ + virtual void setCaption( const QString &caption ); + /** + * Traces the FlowCode document route from the nodes with the given internal + * ids, and returns the FlowPart to which: + * @li all the routes from the given nodes are eventually connected to downwards + * @li their exists one (possibly internally branched) route for each node to that part + * @param ids The list of internal ids of the nodes for the paths to begin from - if empty, + * all nodes internal nodes are used + * @param previousParts A list of parts in the calling tree. This avoids infinite recursion. + * @returns The first FlowPart satisfying these conditions, or NULL if no such part exists + */ + FlowPart* endPart( QStringList ids, FlowPartList *previousParts = 0l ); + /** + * Handles the addition of a if-else statement to the given FlowCode. This will + * order the code as necessary, adding the branches in the appropriate places + * @param code The FlowCode where the if-else will be added + * @param case1Statement The statement (e.g. "PORTA.0 is high") used for the first case + * @param case2Statement The logically opposite statement (e.g. "PORTA.0 is low") (note + that only one of the two statements will be used. + * @param case1 The internal node id for case1 + * @param case2 The internal node id for case2 + */ + void handleIfElse( FlowCode *code, const QString &case1Statement, const QString &case2Statement, + const QString &case1, const QString &case2 ); + /** + * Returns a pointer to the FlowPart that is connected to the node with the + * given internal id, or NULL if no such node / no connected part + */ + FlowPart* outputPart( const QString& internalNodeId ); + /** + * Returns the FlowParts connected to the given node + * @see outputPart + */ + FlowPartList inputParts( const QString& id ); + /** + * Returns a list of parts that are connected to *all* input parts + */ + FlowPartList inputParts(); + /** + * Returns a list of parts that are connected to *all* output parts. Note that if + * the same FlowPart is connected to more than one output, that flowpart will appear + * in the FlowPartList the number of times it is connected. + */ + FlowPartList outputParts(); + /** + * Draw the picture of the flowpart in the given orientation onto the pixmap + */ + void orientationPixmap( uint orientation, QPixmap & pm ) const; + virtual Variant * createProperty( const QString & id, Variant::Type::Value type ); + +public slots: + /** + * Called when variable name data for MicroSettings changes, and so our + * data needs updating + */ + void updateVarNames(); + /** + * Called when a variable name has changed (from an entry box) + */ + void varNameChanged( QVariant newValue, QVariant oldValue ); + /** + * Called when some of the FlowPart-specific variables (e.g. Pin or + * SevenSegment) requiring updating, such as when the PIC type changes + * or the list of Pin Maps changes. + */ + void slotUpdateFlowPartVariables(); + +protected: + virtual void updateAttachedPositioning(); + /** + * Removes the node ids that shouldn't be used for finding the end part + */ + virtual void filterEndPartIDs( QStringList *ids ) { Q_UNUSED(ids); } + /** + * Normally just passes the paint request onto CNItem::drawShape, + * although in the case of some FlowSymbols (e.g. decision), it will handle + * the drawing itself + */ + virtual void drawShape( QPainter &p ); + /** + * Returns the goto instruction that will goto the FlowPart that is connected + * to the node with the given internal id. + * For example, gotoCode("stdOutput") might return "goto delay__13" + */ + QString gotoCode( const QString& internalNodeId ); + /** + * Creates a FPNode with an internal id of "stdinput". + * The node is positioned half-way along the top of the FlowPart, + * as determined by width(), height(), x() and y() + */ + void createStdInput(); + /** + * Creates a FPNode with an internal id of "stdoutput". + * The node is positioned half-way along the bottom of the FlowPart, + * as determined by width(), height(), x() and y() + */ + void createStdOutput(); + /** + * Creates a FPNode with an internal id of "altoutput". + * The node is positioned half-way along the right of the FlowPart, + * as determined by width(), height(), x() and y() + */ + void createAltOutput(); + /** + * Initialises a symbol, by calling setItemPoints with the shape + */ + void initSymbol( FlowPart::FlowSymbol symbol, int width = 48 ); + + void initProcessSymbol() { initSymbol( FlowPart::ps_process ); } + void initCallSymbol() { initSymbol( FlowPart::ps_call ); } + void initIOSymbol() { initSymbol( FlowPart::ps_io ); } + void initRoundedRectSymbol() { initSymbol( FlowPart::ps_round ); } + void initDecisionSymbol() { initSymbol( FlowPart::ps_decision ); } + + QString m_caption; + uint m_orientation; + FPNode *m_stdInput; + FPNode *m_stdOutput; + FPNode *m_altOutput; + QGuardedPtr<FlowCodeDocument> m_pFlowCodeDocument; + + virtual void postResize(); + void updateNodePositions(); + +private: + FlowSymbol m_flowSymbol; +}; +typedef QValueList<FlowPart*> FlowPartList; + +#endif + + + diff --git a/src/flowparts/forloop.cpp b/src/flowparts/forloop.cpp new file mode 100644 index 0000000..d2fe88b --- /dev/null +++ b/src/flowparts/forloop.cpp @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "forloop.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* ForLoop::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ForLoop( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ForLoop::libraryItem() +{ + return new LibraryItem( + QString("flow/forloop"), + i18n("For"), + i18n("Loops"), + "for.png", + LibraryItem::lit_flowpart, + ForLoop::construct ); +} + +ForLoop::ForLoop( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowContainer( icnDocument, newItem, (id) ? id : "forloop" ) +{ + m_name = i18n("For Loop"); + m_desc = i18n("The code contained in the foor loop is repeatedly executed. By default, the variable used will be incremented every time. This can be changed by entering a value other than 1 into Step.<br><br>The for loop will exit when the value contained in the variable is equal to the end value."); + + createTopContainerNode(); + createBotContainerNode(); + + createProperty( "0-var", Variant::Type::Combo ); + property("0-var")->setToolbarCaption("for"); + property("0-var")->setEditorCaption( i18n("Variable") ); + property("0-var")->setValue("x"); + + createProperty( "1-initial", Variant::Type::Combo ); + property("1-initial")->setToolbarCaption("="); + property("1-initial")->setEditorCaption( i18n("Initial Value") ); + property("1-initial")->setValue("1"); + + createProperty( "2-end", Variant::Type::Combo ); + property("2-end")->setToolbarCaption("to"); + property("2-end")->setEditorCaption( i18n("End Value") ); + property("2-end")->setValue("10"); + + createProperty( "3-step", Variant::Type::Combo ); + property("3-step")->setToolbarCaption("step"); + property("3-step")->setEditorCaption( i18n("Step") ); + property("3-step")->setValue("1"); + property("3-step")->setAdvanced(true); +} + +ForLoop::~ForLoop() +{ +} + +void ForLoop::dataChanged() +{ + if( dataString("3-step").toInt() == 1 ) + setCaption( "for " + dataString("0-var") + " = " + dataString("1-initial") + " to " + dataString("2-end") ); + else setCaption( "for " + dataString("0-var") + " = " + dataString("1-initial") + " to " + dataString("2-end") + " step " + dataString("3-step")); +} + +void ForLoop::generateMicrobe( FlowCode *code ) +{ + if( dataString("3-step").toInt() == 1 ) code->addCode( "for " + dataString("0-var") + " = " + dataString("1-initial") + " to " + dataString("2-end") + "\n{" ); + else code->addCode( "for " + dataString("0-var") + " = " + dataString("1-initial") + " to " + dataString("2-end") + " step " + dataString("3-step") +"\n{" ); + code->addCodeBranch( outputPart("int_in") ); + code->addCode("}"); + code->addCodeBranch( outputPart("ext_out") ); +} + diff --git a/src/flowparts/forloop.h b/src/flowparts/forloop.h new file mode 100644 index 0000000..c6b61b0 --- /dev/null +++ b/src/flowparts/forloop.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef FORLOOP_H +#define FORLOOP_H + +#include "flowcontainer.h" + +/** +@author David Saxton +*/ +class ForLoop : public FlowContainer +{ +public: + ForLoop( ICNDocument *icnDocument, bool newItem, const char *id ); + ~ForLoop(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/inputbutton.cpp b/src/flowparts/inputbutton.cpp new file mode 100644 index 0000000..a0564d4 --- /dev/null +++ b/src/flowparts/inputbutton.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "inputbutton.h" +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* InputButton::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new InputButton( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* InputButton::libraryItem() +{ + return new LibraryItem( + "flow/inputbutton", + i18n("InputButton"), + i18n("Functions"), + "ppinputbutton.png", + LibraryItem::lit_flowpart, + InputButton::construct + ); +} + + +InputButton::InputButton( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "inputbutton" ) +{ + m_name = i18n("InputButton"); + m_desc = i18n("Pauses program execution until a inputbutton has been pressed or released (i.e. on rising or falling input), after performing debouncing."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-trigger", Variant::Type::Select ); + property("0-trigger")->setCaption( i18n("Trigger") ); + property("0-trigger")->setAllowed( QStringList::split(',',"rising,falling") ); + property("0-trigger")->setValue("rising"); + + createProperty( "1-pin", Variant::Type::Pin ); + property("1-pin")->setCaption( i18n("Pin") ); + property("1-pin")->setValue("RA0"); +} + +InputButton::~InputButton() +{ +} + + +void InputButton::dataChanged() +{ + setCaption( i18n("Continue on %1 %2").arg(dataString("0-trigger")).arg(dataString("1-pin")) ); +} + + +void InputButton::generateMicrobe( FlowCode *code ) +{ + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/inputbutton.h b/src/flowparts/inputbutton.h new file mode 100644 index 0000000..7467b42 --- /dev/null +++ b/src/flowparts/inputbutton.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef INPUTBUTTON_H +#define INPUTBUTTON_H + +#include "flowpart.h" + +/** +@short InputButton - does debouncing of input +@author David Saxton +*/ +class InputButton : public FlowPart +{ +public: + InputButton( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~InputButton(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/interrupt.cpp b/src/flowparts/interrupt.cpp new file mode 100644 index 0000000..5e8c42f --- /dev/null +++ b/src/flowparts/interrupt.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "interrupt.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* Interrupt::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Interrupt( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Interrupt::libraryItem() +{ + return new LibraryItem( + "flow/interrupt", + i18n("Interrupt"), + i18n("Common"), + "interrupt.png", + LibraryItem::lit_flowpart, + Interrupt::construct ); +} + +Interrupt::Interrupt( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowContainer( icnDocument, newItem, id ? id : "interrupt" ) +{ + m_name = i18n("Interrupt"); + m_desc = i18n("Defines the starting point of a interrupt handler."); + + QStringList interruptTypes; + interruptTypes.append("changed"); + interruptTypes.append("external"); + interruptTypes.append("timer"); + interruptTypes.append("trigger"); + + createProperty( "interrupt", Variant::Type::Select ); + property("interrupt")->setAllowed(interruptTypes); + property("interrupt")->setCaption( i18n("Interrupt") ); + property("interrupt")->setValue("trigger"); +} + +Interrupt::~Interrupt() +{ +} + +void Interrupt::dataChanged() +{ + setCaption( i18n("Interrupt %1").arg(dataString("interrupt")) ); +} + +void Interrupt::generateMicrobe( FlowCode *code ) +{ + code->addCode( "\ninterrupt "+dataString("interrupt")+"\n{" ); + code->addCodeBranch( outputPart("int_in") ); + code->addCode("}"); +} + + diff --git a/src/flowparts/interrupt.h b/src/flowparts/interrupt.h new file mode 100644 index 0000000..807cc30 --- /dev/null +++ b/src/flowparts/interrupt.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef INTERRUPT_H +#define INTERRUPT_H + +#include "flowcontainer.h" + +/** +@short FlowPart that defines the start of a interrupt +@author David Saxton +*/ +class Interrupt : public FlowContainer +{ +public: + Interrupt( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Interrupt(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/keypad.cpp b/src/flowparts/keypad.cpp new file mode 100644 index 0000000..f0d7136 --- /dev/null +++ b/src/flowparts/keypad.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "keypad.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* Keypad::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Keypad( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Keypad::libraryItem() +{ + return new LibraryItem( + "flow/keypad", + i18n("Keypad"), + i18n("Functions"), + "keypad.png", + LibraryItem::lit_flowpart, + Keypad::construct + ); +} + +Keypad::Keypad( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, id ? id : "keypad" ) +{ + m_name = i18n("Keypad"); + m_desc = i18n("Gets a key from a keypad connected to the PIC."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "variable", Variant::Type::VarName ); + property("variable")->setValue("x"); + property("variable")->setCaption( i18n("Variable") ); + + Variant * v = createProperty( "keypad", Variant::Type::KeyPad ); + v->setCaption( i18n("Pin map") ); +} + +Keypad::~Keypad() +{ +} + +void Keypad::dataChanged() +{ + setCaption( i18n("Read %1 to %2").arg( dataString( "keypad" ) ).arg( dataString( "variable" ) ) ); +} + +void Keypad::generateMicrobe( FlowCode *code ) +{ + code->addCode( QString("%1 = %2").arg( dataString("variable") ).arg( dataString("keypad") ) ); + code->addCodeBranch( outputPart("stdoutput") ); +} + + diff --git a/src/flowparts/keypad.h b/src/flowparts/keypad.h new file mode 100644 index 0000000..e2ddba8 --- /dev/null +++ b/src/flowparts/keypad.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef KEYPAD_H +#define KEYPAD_H + +#include "flowpart.h" + +/** +@short FlowPart that provides a keypad +@author David Saxton +*/ +class Keypad : public FlowPart +{ +public: + Keypad( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Keypad(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/pinmapping.cpp b/src/flowparts/pinmapping.cpp new file mode 100644 index 0000000..3b85b46 --- /dev/null +++ b/src/flowparts/pinmapping.cpp @@ -0,0 +1,398 @@ +/*************************************************************************** + * 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 "cnitemgroup.h" +#include "eckeypad.h" +#include "ecsevensegment.h" +#include "libraryitem.h" +#include "microinfo.h" +#include "micropackage.h" +#include "node.h" +#include "pinmapping.h" +#include "viewcontainer.h" + +#include <kdebug.h> +#include <klocale.h> +#include <kstdaccel.h> + +#include <qaccel.h> +#include <qapplication.h> +#include <qframe.h> +#include <qlayout.h> + + +//BEGIN class PinMapping +PinMapping::PinMapping( Type type ) +{ + m_type = type; +} + + +PinMapping::PinMapping() +{ + m_type = Invalid; +} + + +PinMapping::~PinMapping() +{ +} +//END class PinMapping + + + +//BEGIN class PinMapEditor +PinMapEditor::PinMapEditor( PinMapping * pinMapping, MicroInfo * picInfo, QWidget * parent, const char * name ) + : KDialogBase( parent, name, true, i18n("Pin Map Editor"), Ok|Apply|Cancel, KDialogBase::Ok, true ) +{ + m_pPinMapping = pinMapping; + + m_pPinMapDocument = new PinMapDocument(); + + QAccel * accel = new QAccel( this ); + accel->connectItem( accel->insertItem( Key_Delete ), + m_pPinMapDocument, + SLOT(deleteSelection()) ); + + accel->connectItem( accel->insertItem( KStdAccel::selectAll().keyCodeQt() ), + m_pPinMapDocument, + SLOT(selectAll()) ); + + accel->connectItem( accel->insertItem( KStdAccel::undo().keyCodeQt() ), + m_pPinMapDocument, + SLOT(undo()) ); + + accel->connectItem( accel->insertItem( KStdAccel::redo().keyCodeQt() ), + m_pPinMapDocument, + SLOT(redo()) ); + + + QFrame * f = new QFrame(this); + f->setMinimumWidth( 480 ); + f->setMinimumHeight( 480 ); + + f->setFrameShape( QFrame::Box ); + f->setFrameShadow( QFrame::Plain ); + QVBoxLayout * fLayout = new QVBoxLayout( f, 1, 0, "fLayout" ); + + ViewContainer * vc = new ViewContainer( 0, 0, f ); + fLayout->addWidget( vc ); + + m_pPinMapView = static_cast<PinMapView*>(m_pPinMapDocument->createView( vc, 0 )); + + qApp->processEvents(); + + m_pPinMapDocument->init( *m_pPinMapping, picInfo ); + + enableButtonSeparator( false ); + setMainWidget(f); +} + + +void PinMapEditor::slotApply() +{ + savePinMapping(); + KDialogBase::slotApply(); +} + + +void PinMapEditor::slotOk() +{ + savePinMapping(); + KDialogBase::slotOk(); +} + + +void PinMapEditor::savePinMapping() +{ + *m_pPinMapping = m_pPinMapDocument->pinMapping(); +} +//END class PinMapEditor + + + +//BEGIN class PinMapDocument +PinMapDocument::PinMapDocument() + : ICNDocument( 0, 0, 0 ) +{ + m_pPicComponent = 0l; + m_pKeypad = 0l; + m_pSevenSegment = 0l; + m_type = dt_pinMapEditor; + + m_cmManager->addManipulatorInfo( CMSelect::manipulatorInfo() ); +} + + +PinMapDocument::~PinMapDocument() +{ +} + + +void PinMapDocument::init( const PinMapping & pinMapping, MicroInfo * microInfo ) +{ + m_pinMappingType = pinMapping.type(); + + m_pPicComponent = static_cast<PIC_IC*>( addItem( "PIC_IC", QPoint( 336, 224 ), true ) ); + m_pPicComponent->initPackage( microInfo ); + + const QStringList pins = pinMapping.pins(); + const QStringList::const_iterator end = pins.end(); + + int keypadCols = -1; // -1 means no keypad + + switch ( m_pinMappingType ) + { + case PinMapping::SevenSegment: + { + m_pSevenSegment = static_cast<ECSevenSegment*>( addItem( "ec/seven_segment", QPoint( 144, 232 ), true ) ); + + char ssPin = 'a'; + for ( QStringList::const_iterator it = pins.begin(); it != end; ++it ) + { + createConnector( m_pSevenSegment->childNode( QChar(ssPin) ), m_pPicComponent->childNode(*it) ); + ssPin++; + } + + break; + } + + case PinMapping::Keypad_4x3: + m_pKeypad = static_cast<ECKeyPad*>( addItem( "ec/keypad", QPoint( 144, 232 ), true ) ); + m_pKeypad->property("numCols")->setValue(3); + keypadCols = 3; + break; + + case PinMapping::Keypad_4x4: + m_pKeypad = static_cast<ECKeyPad*>( addItem( "ec/keypad", QPoint( 144, 232 ), true ) ); + m_pKeypad->property("numCols")->setValue(4); + keypadCols = 4; + break; + + case PinMapping::Invalid: + kdDebug() << k_funcinfo << "m_pinMappingType == Invalid" << endl; + break; + } + + if ( keypadCols != -1 ) + { + QStringList::const_iterator it = pins.begin(); + for ( unsigned row = 0; (row < 4) && (it != end); ++row, ++it ) + createConnector( m_pKeypad->childNode( QString("row_%1").arg( row ) ), m_pPicComponent->childNode( *it ) ); + + for ( unsigned col = 0; (col < keypadCols) && (it != end); ++col, ++it ) + createConnector( m_pKeypad->childNode( QString("col_%1").arg( col ) ), m_pPicComponent->childNode( *it ) ); + } + + clearHistory(); // Don't allow undoing of initial creation of stuff +} + + +bool PinMapDocument::isValidItem( Item * item ) +{ + return isValidItem( item->type() ); +} + + +bool PinMapDocument::isValidItem( const QString & id ) +{ + if ( !m_pPicComponent && id == "PIC_IC" ) + return true; + + switch ( m_pinMappingType ) + { + case PinMapping::SevenSegment: + return ( !m_pSevenSegment && id == "ec/seven_segment" ); + + case PinMapping::Keypad_4x3: + return ( !m_pKeypad && id == "ec/keypad" ); + + case PinMapping::Keypad_4x4: + return ( !m_pKeypad && id == "ec/keypad" ); + + case PinMapping::Invalid: + return false; + } + + return false; +} + + +void PinMapDocument::deleteSelection() +{ + m_selectList->removeQCanvasItem( m_pPicComponent ); + m_selectList->removeQCanvasItem( m_pSevenSegment ); + m_selectList->removeQCanvasItem( m_pKeypad ); + + ICNDocument::deleteSelection(); +} + + +PinMapping PinMapDocument::pinMapping() const +{ + const NodeMap picNodeMap = m_pPicComponent->nodeMap(); + const NodeMap::const_iterator picNodeMapEnd = picNodeMap.end(); + + QStringList picPinIDs; + QStringList attachedIDs; + Component * attached = 0l; + + switch ( m_pinMappingType ) + { + case PinMapping::SevenSegment: + for ( unsigned i = 0; i < 7; ++i ) + attachedIDs << QChar('a'+i); + attached = m_pSevenSegment; + break; + + case PinMapping::Keypad_4x3: + for ( unsigned i = 0; i < 4; ++i ) + attachedIDs << QString("row_%1").arg(i); + for ( unsigned i = 0; i < 3; ++i ) + attachedIDs << QString("col_%1").arg(i); + attached = m_pKeypad; + break; + + case PinMapping::Keypad_4x4: + for ( unsigned i = 0; i < 4; ++i ) + attachedIDs << QString("row_%1").arg(i); + for ( unsigned i = 0; i < 4; ++i ) + attachedIDs << QString("col_%1").arg(i); + attached = m_pKeypad; + break; + + case PinMapping::Invalid: + break; + } + + if ( !attached ) + return PinMapping(); + + QStringList::iterator end = attachedIDs.end(); + for ( QStringList::iterator attachedIt = attachedIDs.begin(); attachedIt != end; ++ attachedIt ) + { + Node * node = attached->childNode( *attachedIt ); + QString pinID; + + for ( NodeMap::const_iterator it = picNodeMap.begin(); it != picNodeMapEnd; ++it ) + { + if ( it.data().node->isConnected( node ) ) + { + pinID = it.key(); + break; + } + } + + picPinIDs << pinID; + } + + PinMapping pinMapping( m_pinMappingType ); + pinMapping.setPins( picPinIDs ); + + return pinMapping; +} +//END class PinMapDocument + + + +//BEGIN class PinMapView +PinMapView::PinMapView( PinMapDocument * pinMapDocument, ViewContainer * viewContainer, uint viewAreaId, const char * name ) + : ICNView( pinMapDocument, viewContainer, viewAreaId, name ) +{ +} + + +PinMapView::~PinMapView() +{ +} +//END class PinMapView + + + +//BEGIN class PIC_IC +Item* PIC_IC::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new PIC_IC( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* PIC_IC::libraryItem() +{ + return new LibraryItem( "PIC_IC", 0, 0, LibraryItem::lit_other, PIC_IC::construct ); +} + + +PIC_IC::PIC_IC( ICNDocument * icnDocument, bool newItem, const char * id ) + : Component( icnDocument, newItem, id ? id : "PIC_IC" ) +{ +} + + +PIC_IC::~PIC_IC() +{ +} + + +void PIC_IC::initPackage( MicroInfo * microInfo ) +{ + // The code in this function is a stripped down version of that in PICComponent::initPackage + + if (!microInfo) + return; + + MicroPackage * microPackage = microInfo->package(); + if (!microPackage) + return; + + //BEGIN Get pin IDs + QStringList allPinIDs = microPackage->pinIDs(); + QStringList ioPinIDs = microPackage->pinIDs( PicPin::type_bidir | PicPin::type_input | PicPin::type_open ); + + // Now, we make the unwanted pin ids blank, so a pin is not created for them + const QStringList::iterator allPinIDsEnd = allPinIDs.end(); + for ( QStringList::iterator it = allPinIDs.begin(); it != allPinIDsEnd; ++it ) + { + if ( !ioPinIDs.contains(*it) ) + *it = ""; + } + //END Get pin IDs + + + //BEGIN Remove old stuff + // Remove old text + TextMap textMapCopy = m_textMap; + const TextMap::iterator textMapEnd = textMapCopy.end(); + for ( TextMap::iterator it = textMapCopy.begin(); it != textMapEnd; ++it ) + removeDisplayText(it.key()); + + // Remove old nodes + NodeMap nodeMapCopy = m_nodeMap; + const NodeMap::iterator nodeMapEnd = nodeMapCopy.end(); + for ( NodeMap::iterator it = nodeMapCopy.begin(); it != nodeMapEnd; ++it ) + { + if ( !ioPinIDs.contains(it.key()) ) + removeNode( it.key() ); + } + //END Remove old stuff + + + + //BEGIN Create new stuff + initDIPSymbol( allPinIDs, 80 ); + initDIP(allPinIDs); + //END Create new stuff + + + addDisplayText( "picid", QRect(offsetX(), offsetY()-16, width(), 16), microInfo->id() ); +} +//END class PIC_IC + +#include "pinmapping.moc" diff --git a/src/flowparts/pinmapping.h b/src/flowparts/pinmapping.h new file mode 100644 index 0000000..6131e45 --- /dev/null +++ b/src/flowparts/pinmapping.h @@ -0,0 +1,142 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef PINMAPPING_H +#define PINMAPPING_H + +#include "component.h" +#include "icndocument.h" +#include "icnview.h" + +#include <kdialogbase.h> + +class ECKeyPad; +class ECSevenSegment; +class MicroInfo; +class PIC_IC; +class PinMapDocument; +class PinMapView; + + +/** +Stores a pin mapping Pic <--> [component] where component is set by the Type +(e.g. Keypad or Seven Segment). Used for FlowCode. +@author David Saxton +*/ +class PinMapping +{ + public: + enum Type + { + SevenSegment, + Keypad_4x3, + Keypad_4x4, + Invalid + }; + + /** + * Creates an invalid PinMapping, required by Qt templates. + */ + PinMapping(); + /** + * Creates a PinMapping with the given type. + */ + PinMapping( Type type ); + ~PinMapping(); + + Type type() const { return m_type; } + + QStringList pins() const { return m_pins; } + void setPins( const QStringList & pins ) { m_pins = pins; } + + protected: + QStringList m_pins; + Type m_type; +}; +typedef QMap< QString, PinMapping > PinMappingMap; + + + +/** +Dialog for editing a Pin Mapping +@author David Saxton +*/ +class PinMapEditor : public KDialogBase +{ + Q_OBJECT + public: + PinMapEditor( PinMapping * PinMapping, MicroInfo * Info, QWidget * parent, const char * name ); + + protected: + virtual void slotApply(); + virtual void slotOk(); + void savePinMapping(); + + PinMapping * m_pPinMapping; + PinMapDocument * m_pPinMapDocument; + PinMapView * m_pPinMapView; +}; + + + +/** +For use with FlowParts that require a pin map (e.g. Keypad and Seven Segment). +@author David Saxton +*/ +class PinMapDocument : public ICNDocument +{ + Q_OBJECT + public: + PinMapDocument(); + ~PinMapDocument(); + + void init( const PinMapping & PinMapping, MicroInfo * microInfo ); + + virtual bool isValidItem( Item * item ); + virtual bool isValidItem( const QString &itemId ); + + PinMapping pinMapping() const; + + virtual void deleteSelection(); + + protected: + PinMapping::Type m_pinMappingType; + ECKeyPad * m_pKeypad; + ECSevenSegment * m_pSevenSegment; + PIC_IC * m_pPicComponent; +}; + + +/** +@author David Saxton +*/ +class PinMapView : public ICNView +{ + Q_OBJECT + public: + PinMapView( PinMapDocument * pinMapDocument, ViewContainer * viewContainer, uint viewAreaId, const char * name = 0l ); + ~PinMapView(); +}; + + +class PIC_IC : public Component +{ + public: + PIC_IC( ICNDocument * icnDocument, bool newItem, const char *id = 0L ); + virtual ~PIC_IC(); + + virtual bool canFlip() const { return true; } + static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem * libraryItem(); + + void initPackage( MicroInfo * info ); +}; + +#endif diff --git a/src/flowparts/pulse.cpp b/src/flowparts/pulse.cpp new file mode 100644 index 0000000..2037d2f --- /dev/null +++ b/src/flowparts/pulse.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "libraryitem.h" +#include "flowcode.h" +#include "pulse.h" + +#include <klocale.h> + +Item* Pulse::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Pulse( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Pulse::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/pulse"), + i18n("Pulse"), + i18n("Functions"), + "pppulse.png", + LibraryItem::lit_flowpart, + Pulse::construct + ); +} + +Pulse::Pulse( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "pulse" ) +{ + m_name = i18n("Pulse"); + m_desc = i18n("Pulse a pin high/low for a given duration."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-duration", Variant::Type::Double ); + property("0-duration")->setCaption( i18n("Duration") ); + property("0-duration")->setUnit("sec"); + property("0-duration")->setValue(2.0); + + createProperty( "1-high", Variant::Type::Double ); + property("1-high")->setCaption( i18n("High Time") ); + property("1-high")->setUnit("sec"); + property("1-high")->setValue(0.5); + + createProperty( "2-low", Variant::Type::Double ); + property("2-low")->setCaption( i18n("High Time") ); + property("2-low")->setUnit("sec"); + property("2-low")->setValue(0.5); + + createProperty( "3-pin", Variant::Type::Pin ); + property("3-pin")->setCaption( i18n("Pin") ); + property("3-pin")->setValue("RA0"); +} + +Pulse::~Pulse() +{ +} + + +void Pulse::dataChanged() +{ + double pulse = dataDouble("0-duration"); + setCaption( i18n("Pulse %1 for %2 sec").arg(dataString("3-pin")).arg(QString::number( pulse / getMultiplier(pulse), 'f', 1 ) + getNumberMag(pulse)) ); +} + +void Pulse::generateMicrobe( FlowCode *code ) +{ + const double duration_ms = dataDouble("0-duration")*1e3; + const double high_ms = dataDouble("1-high")*1e3; + const double low_ms = dataDouble("2-low")*1e3; + const QString pin = dataString("3-pin"); + + // TODO Do we want to change the format for pulsing? + code->addCode( "pulse "+pin+" "+QString::number(duration_ms)+" "+QString::number(high_ms)+" "+QString::number(low_ms) ); + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/pulse.h b/src/flowparts/pulse.h new file mode 100644 index 0000000..db40aee --- /dev/null +++ b/src/flowparts/pulse.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef PULSE_H +#define PULSE_H + +#include "flowpart.h" + +/** +@short FlowPart that provides a pulse +@author David Saxton +*/ +class Pulse : public FlowPart +{ +public: + Pulse( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Pulse(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/readport.cpp b/src/flowparts/readport.cpp new file mode 100644 index 0000000..d87fe85 --- /dev/null +++ b/src/flowparts/readport.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "readport.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* ReadPort::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new ReadPort( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* ReadPort::libraryItem() +{ + return new LibraryItem( + QString("flow/readport"), + i18n("Read from Port"), + i18n("I\\/O"), + "portread.png", + LibraryItem::lit_flowpart, + ReadPort::construct ); +} + +ReadPort::ReadPort( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "readport" ) +{ + m_name = i18n("Read from Port"); + m_desc = i18n("Assign the value of a port to a variable."); + initIOSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-port", Variant::Type::Port ); + property("0-port")->setToolbarCaption( i18n("Read") ); + property("0-port")->setEditorCaption( i18n("Port") ); + property("0-port")->setValue("PORTA"); + + createProperty( "1-var", Variant::Type::VarName ); + property("1-var")->setToolbarCaption( "to" ); + property("1-var")->setEditorCaption( i18n("Variable") ); + property("1-var")->setValue("x"); +} + + +ReadPort::~ReadPort() +{ +} + +void ReadPort::dataChanged() +{ + setCaption( i18n("Read %1 to %2").arg(dataString("0-port")).arg(dataString("1-var")) ); +} + +void ReadPort::generateMicrobe( FlowCode *code ) +{ + code->addCode( dataString("1-var")+" = "+dataString("0-port") ); + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/readport.h b/src/flowparts/readport.h new file mode 100644 index 0000000..a150f64 --- /dev/null +++ b/src/flowparts/readport.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef READPORT_H +#define READPORT_H + +#include "flowpart.h" + +/** +@short FlowPart that reads from a port +@author David Saxton +*/ +class ReadPort : public FlowPart +{ +public: + ReadPort( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~ReadPort(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/repeat.cpp b/src/flowparts/repeat.cpp new file mode 100644 index 0000000..562bb03 --- /dev/null +++ b/src/flowparts/repeat.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "repeat.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* Repeat::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Repeat( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Repeat::libraryItem() +{ + return new LibraryItem( + QString("flow/repeat"), + i18n("Repeat"), + i18n("Loops"), + "repeat.png", + LibraryItem::lit_flowpart, + Repeat::construct ); +} + +Repeat::Repeat( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowContainer( icnDocument, newItem, (id) ? id : "repeatloop" ) +{ + m_name = i18n("Repeat"); + m_desc = i18n("Repeatedly execute code, until the given condition is false. The condition is checked after the code has been executed.<br><br>This is different from \"While\", which checks for the condition to be true before the code is executed."); + createTopContainerNode(); + createBotContainerNode(); + + createProperty( "0var1", Variant::Type::Combo ); + property("0var1")->setToolbarCaption( "repeat until" ); + property("0var1")->setEditorCaption( i18n("Variable") ); + property("0var1")->setValue("x"); + + createProperty( "1op", Variant::Type::Select ); + property("1op")->setToolbarCaption(" "); + property("1op")->setEditorCaption( i18n("Operation") ); + property("1op")->setAllowed( QStringList::split( ',', "==,<,>,<=,>=,!=" ) ); + property("1op")->setValue("=="); + + createProperty( "2var2", Variant::Type::Combo ); + property("2var2")->setToolbarCaption(" "); + property("2var2")->setEditorCaption( i18n("Value") ); + property("2var2")->setValue("0"); +} + +Repeat::~Repeat() +{ +} + +void Repeat::dataChanged() +{ + setCaption( i18n("repeat until %1 %2 %3").arg(dataString("0var1")).arg(dataString("1op")).arg(dataString("2var2")) ); +} + +void Repeat::generateMicrobe( FlowCode *code ) +{ + code->addCode("repeat\n{\n"); + code->addCodeBranch( outputPart("int_in") ); + code->addCode("}\n"); + code->addCode("until "+dataString("0var1")+" "+dataString("1op")+" " + dataString("2var2") ); + code->addCodeBranch( outputPart("ext_out") ); +} + + + + + diff --git a/src/flowparts/repeat.h b/src/flowparts/repeat.h new file mode 100644 index 0000000..c363275 --- /dev/null +++ b/src/flowparts/repeat.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef REPEAT_H +#define REPEAT_H + +#include "flowcontainer.h" + +/** +@author David Saxton +*/ +class Repeat : public FlowContainer +{ +public: + Repeat( ICNDocument *icnDocument, bool newItem, const char *id ); + ~Repeat(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/setpin.cpp b/src/flowparts/setpin.cpp new file mode 100644 index 0000000..b92ac8d --- /dev/null +++ b/src/flowparts/setpin.cpp @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "setpin.h" + +#include "libraryitem.h" +#include "flowcode.h" +#include "picinfo.h" +#include "flowcodedocument.h" +#include "microsettings.h" + +#include <klocale.h> + +Item* SetPin::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new SetPin( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* SetPin::libraryItem() +{ + return new LibraryItem( + QString("flow/setpin"), + i18n("Set Pin State"), + i18n("I\\/O"), + "pinwrite.png", + LibraryItem::lit_flowpart, + SetPin::construct ); +} + +SetPin::SetPin( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "setpin" ) +{ + m_name = i18n("Set Pin State"); + m_desc = i18n("Set a pin on a port high or low. The pin needs to be set as an output pin."); + initIOSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "state", Variant::Type::Select ); + property("state")->setCaption( i18n("State") ); + property("state")->setAllowed( QStringList::split( ',', "high,low" ) ); + property("state")->setValue("high"); + + createProperty( "pin", Variant::Type::Pin ); + property("pin")->setCaption( i18n("Pin") ); + property("pin")->setValue("RA0"); +} + +SetPin::~SetPin() +{ +} + +void SetPin::dataChanged() +{ + setCaption( i18n("Set %1 %2").arg(dataString("pin")).arg(dataString("state")) ); +} + +void SetPin::generateMicrobe( FlowCode *code ) +{ + const QString pin = dataString("pin"); + const QString port = "PORT" + QString((QChar)pin[1]); + const QString bit = (QChar)pin[2]; + code->addCode( port+"."+bit+" = "+dataString("state") ); + code->addCodeBranch( outputPart("stdoutput") ); + +#if 0 + const QString pin = dataString("pin"); + const bool isHigh = (dataString("state") == "High"); + const QString port = "PORT" + QString((QChar)pin[1]); + const QString bit = (QChar)pin[2]; + + QString newCode; + if (isHigh) + { + newCode += "bsf " + port + "," + bit + " ; Set bit high\n"; + } + else + { + newCode += "bcf " + port + "," + bit + " ; Set bit low\n"; + } + + code->addCodeBlock( id(), newCode ); +#endif +} diff --git a/src/flowparts/setpin.h b/src/flowparts/setpin.h new file mode 100644 index 0000000..0e662bc --- /dev/null +++ b/src/flowparts/setpin.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef SETPIN_H +#define SETPIN_H + +#include "flowpart.h" + +/** +@short FlowPart that writes a high/low to a pin +@author David Saxton +*/ +class SetPin : public FlowPart +{ +public: + SetPin( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~SetPin(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); + +private: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/sevenseg.cpp b/src/flowparts/sevenseg.cpp new file mode 100644 index 0000000..c376f00 --- /dev/null +++ b/src/flowparts/sevenseg.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "sevenseg.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* SevenSeg::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new SevenSeg( (ICNDocument*)itemDocument, newItem, id ); +} + + +LibraryItem* SevenSeg::libraryItem() +{ + return new LibraryItem( + "flow/sevenseg", + i18n("Seven Segment"), + "Functions", + "seven_segment.png", + LibraryItem::lit_flowpart, + SevenSeg::construct + ); +} + + +SevenSeg::SevenSeg( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, id ? id : "sevenseg" ) +{ + m_name = i18n("SevenSeg"); + m_desc = i18n("Output to a Seven Segment display."); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "expression", Variant::Type::Combo ); + property("expression")->setValue("x"); + property("expression")->setCaption( i18n("Variable") ); + + createProperty( "sevenseg", Variant::Type::SevenSegment ); + property("sevenseg")->setCaption( i18n("Pin map") ); +} + + +SevenSeg::~SevenSeg() +{ +} + + +void SevenSeg::dataChanged() +{ + setCaption( i18n("Display %1 on %2").arg( dataString("expression") ).arg( dataString("sevenseg") ) ); +} + + +void SevenSeg::generateMicrobe( FlowCode *code ) +{ + code->addCode( QString("%1 = %2").arg( dataString("sevenseg") ).arg( dataString("expression") ) ); + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/sevenseg.h b/src/flowparts/sevenseg.h new file mode 100644 index 0000000..47b2979 --- /dev/null +++ b/src/flowparts/sevenseg.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef SEVENSEG_H +#define SEVENSEG_H + +#include "flowpart.h" + +/** +@short Allows a configurable output to a seven segment display +@author David Saxton +*/ +class SevenSeg : public FlowPart +{ +public: + SevenSeg( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~SevenSeg(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/start.cpp b/src/flowparts/start.cpp new file mode 100644 index 0000000..6fd8af0 --- /dev/null +++ b/src/flowparts/start.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "start.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* Start::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Start( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Start::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/start"), + i18n("Start"), + i18n("Common"), + "start.png", + LibraryItem::lit_flowpart, + Start::construct ); +} + +Start::Start( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "START" ) +{ + m_name = i18n("Start"); + m_desc = i18n("Determines the initial program execution point."); + initRoundedRectSymbol(); + createStdOutput(); + setCaption( i18n("Start") ); +} + +Start::~Start() +{ +} + +void Start::generateMicrobe( FlowCode *code ) +{ + code->addCodeBranch( outputPart("stdoutput") ); +} + diff --git a/src/flowparts/start.h b/src/flowparts/start.h new file mode 100644 index 0000000..8585b4a --- /dev/null +++ b/src/flowparts/start.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef START_H +#define START_H + +#include "flowpart.h" + +/** +@short FlowPart that tells the program where to start +@author David Saxton +*/ +class Start : public FlowPart +{ +public: + Start( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Start(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode * ); +}; + +#endif diff --git a/src/flowparts/sub.cpp b/src/flowparts/sub.cpp new file mode 100644 index 0000000..222b167 --- /dev/null +++ b/src/flowparts/sub.cpp @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "sub.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* Sub::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Sub( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Sub::libraryItem() +{ + return new LibraryItem( + QString("flow/sub"), + i18n("Subroutine"), + i18n("Common"), + "sub.png", + LibraryItem::lit_flowpart, + Sub::construct ); +} + +Sub::Sub( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowContainer( icnDocument, newItem, (id) ? id : "sub" ) +{ + m_name = i18n("Sub"); + m_desc = i18n("Defines the starting point of a subroutine. Call this subroutine using \"Call Sub\""); + + createProperty( "sub", Variant::Type::Combo ); + property("sub")->setCaption( i18n("Subroutine") ); + property("sub")->setValue("MySub"); +} + +Sub::~Sub() +{ +} + +void Sub::dataChanged() +{ + setCaption( "Sub " + dataString("sub") ); +} + +void Sub::generateMicrobe( FlowCode *code ) +{ + code->addCode( "\nsub "+dataString("sub")+"\n{" ); + code->addCodeBranch( outputPart("int_in") ); + code->addCode("}"); +} + + +// #include "sub.moc" diff --git a/src/flowparts/sub.h b/src/flowparts/sub.h new file mode 100644 index 0000000..aca2005 --- /dev/null +++ b/src/flowparts/sub.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef SUB_H +#define SUB_H + +#include "flowcontainer.h" + +/** +@short FlowPart that defines the start of a subroutine +@author David Saxton +*/ +class Sub : public FlowContainer +{ +public: + Sub( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Sub(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/testpin.cpp b/src/flowparts/testpin.cpp new file mode 100644 index 0000000..85fdb37 --- /dev/null +++ b/src/flowparts/testpin.cpp @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "testpin.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* TestPin::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new TestPin( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* TestPin::libraryItem() +{ + return new LibraryItem( + QString("flow/testpin"), + i18n("Test Pin State"), + i18n("I\\/O"), + "pinread.png", + LibraryItem::lit_flowpart, + TestPin::construct ); +} + +TestPin::TestPin( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "testpin" ) +{ + m_name = i18n("Test Pin State"); + m_desc = i18n("Conditional branch point, depending on the high/low state of a pin."); + initDecisionSymbol(); + createStdInput(); + createStdOutput(); + createAltOutput(); + + createProperty( "pin", Variant::Type::Pin ); + property("pin")->setCaption( i18n("Pin") ); + property("pin")->setValue("RA0"); + + addDisplayText( "output_false", QRect( offsetX()+width(), 2, 40, 20 ), "Low" ); + addDisplayText( "output_true", QRect( 0, offsetY()+height(), 50, 20 ), "High" ); +} + + +TestPin::~TestPin() +{ +} + + +void TestPin::dataChanged() +{ + setCaption( "Test " + dataString("pin") ); +} + + +void TestPin::generateMicrobe( FlowCode *code ) +{ + const QString pin = dataString("pin"); + const QString port = "PORT" + QString((QChar)pin[1]); + const QString bit = (QChar)pin[2]; + + handleIfElse( code, port+"."+bit+" is high", port+"."+bit+" is low", "stdoutput", "altoutput" ); + +#if 0 + QString newCode; + + newCode += "btfss "+port+","+bit+" ; Check if pin is clear\n"; + newCode += gotoCode("altoutput") + " ; Pin is low\n"; + newCode += gotoCode("stdoutput") + " ; Pin is high, continue on from this point\n"; + + code->addCodeBlock( id(), newCode ); +#endif +} + + diff --git a/src/flowparts/testpin.h b/src/flowparts/testpin.h new file mode 100644 index 0000000..72a1411 --- /dev/null +++ b/src/flowparts/testpin.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef TESTPIN_H +#define TESTPIN_H + +#include "flowpart.h" + +/** +@short FlowPart that tests a pin to see if it's high +@author David Saxton +*/ +class TestPin : public FlowPart +{ +public: + TestPin( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~TestPin(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/unary.cpp b/src/flowparts/unary.cpp new file mode 100644 index 0000000..fe0b549 --- /dev/null +++ b/src/flowparts/unary.cpp @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "unary.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* Unary::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new Unary( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* Unary::libraryItem() +{ + return new LibraryItem( + QString("flow/unary"), + i18n("Unary"), + i18n("Variables"), + "unary.png", + LibraryItem::lit_flowpart, + Unary::construct ); +} + +Unary::Unary( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "unary" ) +{ + m_name = i18n("Unary"); + m_desc = i18n("A unary operation involves only one variable. Suppo operations are:<br><ul><li><b>Rotate Left</b> rotates the binary bits of the variable left (discarding the end bits).</li><li><b>Rotate Right</b> rotates the binary bits right (discarding the start bits).</li><li><b>Increment</b> increases the value of the variable by 1. A value of 255 wraps around to 0.</li><li><b>Decrement</b> decreases the value of a variable by 1. A value of 0 wraps around to 255.</li></ul>"); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-var", Variant::Type::VarName ); + property("0-var")->setValue("x"); + property("0-var")->setCaption( i18n("Variable") ); + + createProperty( "1-op", Variant::Type::Select ); + property("1-op")->setCaption( i18n("Operation") ); + property("1-op")->setAllowed( QStringList::split( ',', "Rotate Left,Rotate Right,Increment,Decrement" ) ); + property("1-op")->setValue("Rotate Left"); +} + +Unary::~Unary() +{ +} + +void Unary::dataChanged() +{ + setCaption( dataString("0-var") + " " + dataString("1-op") ); +} + +void Unary::generateMicrobe( FlowCode *code ) +{ + const QString var = dataString("0-var"); + const QString op = dataString("1-op"); + + if ( op == "Rotate Left" ) code->addCode( "rotateleft "+var ); + else if ( op == "Rotate Right" ) code->addCode( "rotateright "+var ); + else if ( op == "Increment" ) code->addCode( "increment "+var ); + else if ( op == "Decrement" ) code->addCode( "decrement "+var ); + else; // Hmm... + code->addCodeBranch( outputPart("stdoutput") ); + +#if 0 + QString rot = dataString("1-rot"); + + if ( FlowCode::isLiteral(var) ) return; + + QString newCode; + + code->addVariable(var); + if ( rot == "Left" ) newCode += "rlf " + var + ",1 ; Unary " + var + " left through Carry, place result back in " + var + "\n"; + else newCode += "rrf " + var + ",1 ; Unary " + var + " right through Carry, place result back in " + var + "\n"; + + newCode += gotoCode("stdoutput"); + code->addCodeBlock( id(), newCode ); +#endif +} + + diff --git a/src/flowparts/unary.h b/src/flowparts/unary.h new file mode 100644 index 0000000..ec830d6 --- /dev/null +++ b/src/flowparts/unary.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef ROTATE_H +#define ROTATE_H + +#include "flowpart.h" + +/** +@short FlowPart that rotates a variable +@author David Saxton +*/ +class Unary : public FlowPart +{ +public: + Unary( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~Unary(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/varassignment.cpp b/src/flowparts/varassignment.cpp new file mode 100644 index 0000000..44b76fd --- /dev/null +++ b/src/flowparts/varassignment.cpp @@ -0,0 +1,100 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "varassignment.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* VarAssignment::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new VarAssignment( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* VarAssignment::libraryItem() +{ + return new LibraryItem( + QString::QString("flow/varassignment"), + i18n("Assignment"), + i18n("Variables"), + "assignment.png", + LibraryItem::lit_flowpart, + VarAssignment::construct ); +} + +VarAssignment::VarAssignment( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "varassignment" ) +{ + m_name = i18n("Variable Assignment"); + m_desc = i18n("Assigns the evaluation of an expression to a variable. The expression can take many forms. For example:<ul><li><b>x = 2</b></li><li><b>x = y + 3</b></li><li><b>x = y + z</b></li><li><b>x = 2 * y</b></ul>"); + initProcessSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-var1", Variant::Type::VarName ); + property("0-var1")->setCaption( i18n("Variable") ); + property("0-var1")->setValue("x"); + + createProperty( "2-var2", Variant::Type::Combo ); + property("2-var2")->setToolbarCaption(" = "); + property("2-var2")->setEditorCaption( i18n("Value") ); + property("2-var2")->setValue("0"); + +} + +VarAssignment::~VarAssignment() +{ +} + +void VarAssignment::dataChanged() +{ + setCaption( dataString("0-var1") + " " + "=" /*dataString("1-op")*/ + " " + dataString("2-var2") ); +} + +void VarAssignment::generateMicrobe( FlowCode *code ) +{ + code->addCode( dataString("0-var1")+" "+"="/*dataString("1-op")*/+" "+dataString("2-var2") ); + code->addCodeBranch( outputPart("stdoutput") ); + +#if 0 + QString var1 = dataString("0-var1"); + QString var2 = dataString("2-var2"); + QString op = dataString("1-op"); + + if ( FlowCode::isLiteral(var1) ) return; + code->addVariable(var1); + + QString newCode; + + if ( !FlowCode::isLiteral(var1) ) + { + if ( FlowCode::isLiteral(var2) ) newCode += "movlw " + var2 + " ; Assign " + var2 + " to w register\n"; + } + + if ( !FlowCode::isLiteral(var2) ) + { + code->addVariable(var2); + newCode += "movf " + var2 + ",0 ; Move " + var2 + " to w register\n"; + } + + if ( op == "=" ) newCode += "movwf " + var1 + " ; Move contents of w register to " + var1 + "\n"; + else if ( op == "+=" ) newCode += "addwf " + var1 + ",1 ; Add contents of w register to " + var1 + " and place result back in " + var1 + "\n"; + else if ( op == "-=" ) newCode += "subwf " + var1 + ",1 ; Subtract contents of w register from " + var1 + " and place result back in " + var1 + "\n"; + else if ( op == "&=" ) newCode += "andwf " + var1 + ",1 ; Binary AND contents of w register with " + var1 + " and place result back in " + var1 + "\n"; + else if ( op == "or=" ) newCode += "iorwf " + var1 + ",1 ; Binary inclusive OR contents of w register with " + var1 + " and place result back in " + var1 + "\n"; + else if ( op == "xor=" ) newCode += "xorwf " + var1 + ",1 ; Binary exclusive OR contents of w register with " + var1 + " and place result back in " + var1 + "\n"; + + newCode += gotoCode("stdoutput"); + + code->addCodeBlock( id(), newCode ); +#endif +} diff --git a/src/flowparts/varassignment.h b/src/flowparts/varassignment.h new file mode 100644 index 0000000..25cb78c --- /dev/null +++ b/src/flowparts/varassignment.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef VARASSIGNMENT_H +#define VARASSIGNMENT_H + +#include "flowpart.h" + +/** +@short FlowPart that assigns a value to a variable +@author David Saxton +*/ +class VarAssignment : public FlowPart +{ +public: + VarAssignment( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~VarAssignment(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/varcomparison.cpp b/src/flowparts/varcomparison.cpp new file mode 100644 index 0000000..e01ebf2 --- /dev/null +++ b/src/flowparts/varcomparison.cpp @@ -0,0 +1,170 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "varcomparison.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* VarComparison::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new VarComparison( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* VarComparison::libraryItem() +{ + return new LibraryItem( + QString("flow/varcomparison"), + i18n("Comparison"), + i18n("Variables"), + "branch.png", + LibraryItem::lit_flowpart, + VarComparison::construct ); +} + +VarComparison::VarComparison( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "varcomparison" ) +{ + m_name = i18n("Variable Comparison"); + m_desc = i18n("Conditional branch point, depending on the comparison of two values. The supported comparisons are:<ul><li><b>x == y</b> - Equality: true if x has the same value as y.</li><li><b>x < y</b> - Less than: true if x is smaller than y.</li><li><b>x > y</b> - Greater than: true if x is bigger than y.</li><li><b>x <= y</b> - Less than or equal: true if x is less than or equal to y.</li><li><b>x >= y</b> - Greater than or equal: true if x is greater than or equal to y.</li><li><b>x != y</b> - Does not equal: true if x does not have the same value as y.</li></ul>"); + initDecisionSymbol(); + createStdInput(); + createStdOutput(); + createAltOutput(); + + createProperty( "0var1", Variant::Type::Combo ); + property("0var1")->setCaption( i18n("Variable") ); + property("0var1")->setValue("x"); + + createProperty( "1op", Variant::Type::Select ); + property("1op")->setAllowed( QStringList::split( ',', "==,<,>,<=,>=,!=" ) ); + property("1op")->setValue("=="); + property("1op")->setToolbarCaption(" "); + property("1op")->setEditorCaption( i18n("Operation") ); + + createProperty( "2var2", Variant::Type::Combo ); + property("2var2")->setToolbarCaption(" "); + property("2var2")->setEditorCaption( i18n("Value") ); + property("2var2")->setValue("0"); + + addDisplayText( "output_false", QRect( offsetX()+width(), 2, 40, 20 ), "No" ); + addDisplayText( "output_true", QRect( 0, offsetY()+height(), 50, 20 ), "Yes" ); +} + +VarComparison::~VarComparison() +{ +} + +void VarComparison::dataChanged() +{ + setCaption( dataString("0var1") + " " + dataString("1op") + " " + dataString("2var2") + " ?" ); +} + +QString VarComparison::oppOp( const QString &op ) +{ + if ( op == "==" ) return "!="; + if ( op == "!=" ) return "=="; + else if ( op == "<" ) return ">="; + else if ( op == ">=" ) return "<"; + else if ( op == ">" ) return "<="; + else if ( op == "<=" ) return ">"; + else return "__UNKNOWN_OP__"; +} + +void VarComparison::generateMicrobe( FlowCode *code ) +{ + QString var1 = dataString("0var1"); + QString var2 = dataString("2var2"); + QString test = dataString("1op"); + + handleIfElse( code, var1+" "+test+" "+var2, var1+" "+oppOp(test)+" "+var2, "stdoutput", "altoutput" ); + +#if 0 + code->addCode( "if "+var1+" "+test+" "+var2+"\n{\n" ); + code->addCodeBranch( outputPart("stdoutput") ); + code->addCode("}"); + if ( outputPart("altoutput") ) + { + code->addCode("else\n{"); + code->addCodeBranch( outputPart("altoutput") ); + code->addCode("}"); + } +#endif + +#if 0 + QString newCode; + + if ( FlowCode::isLiteral(var2) ) newCode += "movlw " + var2 + " ; Move literal to register w\n"; + else + { + code->addVariable(var2); + newCode += "movf " + var2 + ",0 ; Move " + var2 + " to register w\n"; + } + + if ( FlowCode::isLiteral(var1) ) newCode += "sublw " + var1 + " ; Subtract register w from " + var1 + ", placing result in w\n"; + else + { + code->addVariable(var1); + newCode += "subwf " + var1 + ",0 ; Subtract register w from " + var1 + ", placing result in w\n"; + } + + + if ( test == "==" ) + { + // check: works + newCode += "btfss STATUS,2 ; Check if zero flag is set\n"; + newCode += gotoCode("altoutput") + " ; Result from calculation was non-zero; hence comparison is false\n"; + newCode += gotoCode("stdoutput") + " ; Ouput was zero; hence comparison is true, so continue from this point\n"; + } + else if ( test == "!=" ) + { + // check: works + newCode += "btfsc STATUS,2 ; Check if zero flag is clear\n"; + newCode += gotoCode("altoutput") + " ; Result from calculation was zero; hence comparison is false\n"; + newCode += gotoCode("stdoutput") + " ; Output was non-zero; hence comparison is true, so continue from this point\n"; + } + else if ( test == ">=" ) + { + // check: works + newCode += "btfss STATUS,0 ; Check if carry flag is set\n"; + newCode += gotoCode("altoutput") + " ; Result from calculation is negative; hence comparison is false\n"; + newCode += gotoCode("stdoutput") + " ; Result from calculation is positive or zero; so continue from this point\n"; + } + else if ( test == ">" ) + { + // check: works + newCode += "btfss STATUS,0 ; Check if carry flag is set\n"; + newCode += gotoCode("altoutput") + " ; Result is negative; hence comparison is false\n"; + newCode += "btfsc STATUS,2 ; Check if zero flag is set\n"; + newCode += gotoCode("altoutput") + " ; Result is zero; hence comparison is false\n"; + newCode += gotoCode("stdoutput") + " ; Comparison is true, so continue from this point\n"; + } + else if ( test == "<" ) + { + // check: works + newCode += "btfsc STATUS,0 ; Check if carry flag is set\n"; + newCode += gotoCode("altoutput"); + newCode += gotoCode("stdoutput"); + } + else if ( test == "<=" ) + { + // check: works + newCode += "btfsc STATUS,2 ; Check if result is zero\n"; + newCode += gotoCode("stdoutput") + " ; Result is zero; hence comparison is true\n"; + newCode += "btfsc STATUS,0 ; Check if carry flag is set\n"; + newCode += gotoCode("altoutput") + " ; Result is positive (not zero, has already tested for this); hence comparison is false\n"; + newCode += gotoCode("stdoutput") + " ; Result is negative, hence comparison is true\n"; + } + + code->addCodeBlock( id(), newCode ); +#endif +} diff --git a/src/flowparts/varcomparison.h b/src/flowparts/varcomparison.h new file mode 100644 index 0000000..b1220c8 --- /dev/null +++ b/src/flowparts/varcomparison.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef VARCOMPARISON_H +#define VARCOMPARISON_H + +#include "flowpart.h" + +/** +@short FlowPart that compares two values +@author David Saxton +*/ +class VarComparison : public FlowPart +{ +public: + VarComparison( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~VarComparison(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); + /** + * Use this to find the logically opposite comparison (e.g. "==" returns "!=", + * ">=" returns "<", etc). Supoorted ops: != == <= >= < > + */ + QString oppOp( const QString &op ); +}; + +#endif diff --git a/src/flowparts/while.cpp b/src/flowparts/while.cpp new file mode 100644 index 0000000..b0461df --- /dev/null +++ b/src/flowparts/while.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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 "while.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* While::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new While( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* While::libraryItem() +{ + return new LibraryItem( + QString("flow/while"), + i18n("While"), + i18n("Loops"), + "while.png", + LibraryItem::lit_flowpart, + While::construct ); +} + +While::While( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowContainer( icnDocument, newItem, (id) ? id : "whileloop" ) +{ + m_name = i18n("While"); + m_desc = i18n("Repeatedly execute code, until the given condition is false. The condition is checked before the code has been executed.<br><br>This is different from \"Repeat\", which checks for the condition to be true after the code is executed."); + createTopContainerNode(); + createBotContainerNode(); + + createProperty( "0var1", Variant::Type::Combo ); + property("0var1")->setToolbarCaption( "while" ); + property("0var1")->setEditorCaption( i18n("Variable") ); + property("0var1")->setValue("x"); + + createProperty( "1op", Variant::Type::Select ); + property("1op")->setToolbarCaption(" "); + property("1op")->setEditorCaption( i18n("Operation") ); + property("1op")->setAllowed( QStringList::split( ',', "==,<,>,<=,>=,!=" ) ); + property("1op")->setValue("=="); + + createProperty( "2var2", Variant::Type::Combo ); + property("2var2")->setToolbarCaption(" "); + property("2var2")->setEditorCaption( i18n("Value") ); + property("2var2")->setValue("0"); +} + +While::~While() +{ +} + +void While::dataChanged() +{ + setCaption( i18n("while %1 %2 %3").arg(dataString("0var1")).arg(dataString("1op")).arg(dataString("2var2")) ); +} + +void While::generateMicrobe( FlowCode *code ) +{ + code->addCode("while "+dataString("0var1")+" "+dataString("1op")+" " + dataString("2var2")+"\n{" ); + code->addCodeBranch( outputPart("int_in") ); + code->addCode("}"); + code->addCodeBranch( outputPart("ext_out") ); +} + + + + + diff --git a/src/flowparts/while.h b/src/flowparts/while.h new file mode 100644 index 0000000..51f851a --- /dev/null +++ b/src/flowparts/while.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2003-2004 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. * + ***************************************************************************/ + +#ifndef WHILE_H +#define WHILE_H + +#include "flowcontainer.h" + +/** +@author David Saxton +*/ +class While : public FlowContainer +{ +public: + While( ICNDocument *icnDocument, bool newItem, const char *id ); + ~While(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +protected: + void dataChanged(); +}; + +#endif diff --git a/src/flowparts/writeport.cpp b/src/flowparts/writeport.cpp new file mode 100644 index 0000000..dede6f1 --- /dev/null +++ b/src/flowparts/writeport.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (C) 2003 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 "writeport.h" + +#include "libraryitem.h" +#include "flowcode.h" + +#include <klocale.h> + +Item* WritePort::construct( ItemDocument *itemDocument, bool newItem, const char *id ) +{ + return new WritePort( (ICNDocument*)itemDocument, newItem, id ); +} + +LibraryItem* WritePort::libraryItem() +{ + return new LibraryItem( + QString("flow/writeport"), + i18n("Write to Port"), + i18n("I\\/O"), + "portwrite.png", + LibraryItem::lit_flowpart, + WritePort::construct ); +} + +WritePort::WritePort( ICNDocument *icnDocument, bool newItem, const char *id ) + : FlowPart( icnDocument, newItem, (id) ? id : "writeport" ) +{ + m_name = i18n("Write to Port"); + m_desc = i18n("Sets the port's pins state to high/low from the given value. Only pins that have been configured as output pins will take on the value assigned to them."); + initIOSymbol(); + createStdInput(); + createStdOutput(); + + createProperty( "0-var", Variant::Type::Combo ); + property("0-var")->setToolbarCaption( i18n("Write") ); + property("0-var")->setEditorCaption( i18n("Variable") ); + property("0-var")->setValue("x"); + + createProperty( "1-port", Variant::Type::Port ); + property("1-port")->setToolbarCaption( "to" ); + property("1-port")->setEditorCaption( i18n("Port") ); + property("1-port")->setValue("PORTA"); +} + + +WritePort::~WritePort() +{ +} + + +void WritePort::dataChanged() +{ + setCaption( i18n("Write %1 to %2").arg(dataString("0-var")).arg(dataString("1-port")) ); +} + + +void WritePort::generateMicrobe( FlowCode *code ) +{ + code->addCode( dataString("1-port")+" = "+dataString("0-var") ); + code->addCodeBranch( outputPart("stdoutput") ); + +#if 0 + QString var = dataString("var"); + QString port = dataString("port"); + + // WTF? I don't want to do this! +// QString newCode = "bsf STATUS,5 ; Move to bank 1\n"; + QString newCode; + + if ( FlowCode::isLiteral(var) ) newCode += "movlw " + var + " ; Move " + var + " to working register w\n"; + else + { + code->addVariable(var); + newCode += "movf " + var + ",0 ; Move " + var + " to working register w\n"; + } + + newCode += "movwf " + port + " ; Move register w to port\n"; + + // Same for below as for above +// newCode += "bcf STATUS,5 ; Come back to bank 0\n"; + + newCode += gotoCode("stdoutput") + "\n"; + + code->addCodeBlock( id(), newCode ); +#endif +} diff --git a/src/flowparts/writeport.h b/src/flowparts/writeport.h new file mode 100644 index 0000000..335db3b --- /dev/null +++ b/src/flowparts/writeport.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2003 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. * + ***************************************************************************/ + +#ifndef WRITEPORT_H +#define WRITEPORT_H + +#include "flowpart.h" + +/** +@short FlowPart that writes to a port +@author David Saxton +*/ +class WritePort : public FlowPart +{ +public: + WritePort( ICNDocument *icnDocument, bool newItem, const char *id = 0L ); + ~WritePort(); + + static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id ); + static LibraryItem *libraryItem(); + + virtual void generateMicrobe( FlowCode *code ); + +private: + void dataChanged(); +}; + +#endif |