summaryrefslogtreecommitdiffstats
path: root/src/flowparts
diff options
context:
space:
mode:
Diffstat (limited to 'src/flowparts')
-rw-r--r--src/flowparts/Makefile.am15
-rw-r--r--src/flowparts/callsub.cpp62
-rw-r--r--src/flowparts/callsub.h35
-rw-r--r--src/flowparts/count.cpp70
-rw-r--r--src/flowparts/count.h35
-rw-r--r--src/flowparts/delay.cpp136
-rw-r--r--src/flowparts/delay.h35
-rw-r--r--src/flowparts/embed.cpp87
-rw-r--r--src/flowparts/embed.h36
-rw-r--r--src/flowparts/end.cpp51
-rw-r--r--src/flowparts/end.h32
-rw-r--r--src/flowparts/flowpart.cpp977
-rw-r--r--src/flowparts/flowpart.h197
-rw-r--r--src/flowparts/forloop.cpp84
-rw-r--r--src/flowparts/forloop.h34
-rw-r--r--src/flowparts/inputbutton.cpp70
-rw-r--r--src/flowparts/inputbutton.h35
-rw-r--r--src/flowparts/interrupt.cpp68
-rw-r--r--src/flowparts/interrupt.h35
-rw-r--r--src/flowparts/keypad.cpp67
-rw-r--r--src/flowparts/keypad.h35
-rw-r--r--src/flowparts/pinmapping.cpp398
-rw-r--r--src/flowparts/pinmapping.h142
-rw-r--r--src/flowparts/pulse.cpp85
-rw-r--r--src/flowparts/pulse.h35
-rw-r--r--src/flowparts/readport.cpp69
-rw-r--r--src/flowparts/readport.h35
-rw-r--r--src/flowparts/repeat.cpp80
-rw-r--r--src/flowparts/repeat.h34
-rw-r--r--src/flowparts/setpin.cpp91
-rw-r--r--src/flowparts/setpin.h35
-rw-r--r--src/flowparts/sevenseg.cpp71
-rw-r--r--src/flowparts/sevenseg.h35
-rw-r--r--src/flowparts/start.cpp52
-rw-r--r--src/flowparts/start.h32
-rw-r--r--src/flowparts/sub.cpp62
-rw-r--r--src/flowparts/sub.h35
-rw-r--r--src/flowparts/testpin.cpp83
-rw-r--r--src/flowparts/testpin.h35
-rw-r--r--src/flowparts/unary.cpp90
-rw-r--r--src/flowparts/unary.h35
-rw-r--r--src/flowparts/varassignment.cpp100
-rw-r--r--src/flowparts/varassignment.h35
-rw-r--r--src/flowparts/varcomparison.cpp170
-rw-r--r--src/flowparts/varcomparison.h40
-rw-r--r--src/flowparts/while.cpp79
-rw-r--r--src/flowparts/while.h34
-rw-r--r--src/flowparts/writeport.cpp95
-rw-r--r--src/flowparts/writeport.h35
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 &lt; y</b> - Less than: true if x is smaller than y.</li><li><b>x &gt; y</b> - Greater than: true if x is bigger than y.</li><li><b>x &lt;= y</b> - Less than or equal: true if x is less than or equal to y.</li><li><b>x &gt;= 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