File indexing completed on 2024-04-21 05:43:37

0001 /***************************************************************************
0002  *   Copyright (C) 2003-2005 by David Saxton                               *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #ifndef FLOWPART_H
0012 #define FLOWPART_H
0013 
0014 #include "cnitem.h"
0015 
0016 class ICNDocument;
0017 class Node;
0018 class FlowCode;
0019 class FlowCodeDocument;
0020 class FlowPart;
0021 class FPNode;
0022 class QPixmap;
0023 class QSize;
0024 
0025 typedef QList<FlowPart *> FlowPartList;
0026 
0027 /**
0028 All flow parts (eg 'CallSub', 'Read from Port' ,etc) should inherit from this class.
0029 It provides basic functionality for creating commonly used nodes, as well as a virtual function
0030 that you should reinherit for generating the assembly code.
0031 @short Base class for all FlowParts
0032 @author David Saxton
0033 */
0034 class FlowPart : public CNItem
0035 {
0036     Q_OBJECT
0037 public:
0038     enum FlowSymbol {
0039         ps_process,  // Process - Plain rectangular box
0040         ps_call,     // Call - Rectangular box with double vertical lines at either end
0041         ps_io,       // I/O - Slanter rectangular box
0042         ps_round,    // Start/End - Rounded rectangular box
0043         ps_decision, // Decision - Diamond shape
0044         ps_other     // Custom shape, which is ignored by FlowPart
0045     };
0046     FlowPart(ICNDocument *icnDocument, bool newItem, const QString &id);
0047     ~FlowPart() override;
0048 
0049     virtual void generateMicrobe(FlowCode * /*code*/) = 0;
0050     /**
0051      * Set a preset "orientation" of this item - 0 through 7
0052      */
0053     void setOrientation(uint orientation);
0054     uint orientation() const
0055     {
0056         return m_orientation;
0057     }
0058     /**
0059      * The allowed orientations, as bit positions of 0 through 7
0060      */
0061     uint allowedOrientations() const;
0062     ItemData itemData() const override;
0063     void restoreFromItemData(const ItemData &itemData) override;
0064     /**
0065      * Sets the caption displayed in the flowpart, resizes the item as necessary
0066      */
0067     virtual void setCaption(const QString &caption);
0068     /**
0069      * Traces the FlowCode document route from the nodes with the given internal
0070      * ids, and returns the FlowPart to which:
0071      * @li all the routes from the given nodes are eventually connected to downwards
0072      * @li their exists one (possibly internally branched) route for each node to that part
0073      * @param ids The list of internal ids of the nodes for the paths to begin from - if empty,
0074      *            all nodes internal nodes are used
0075      * @param previousParts A list of parts in the calling tree. This avoids infinite recursion.
0076      * @returns The first FlowPart satisfying these conditions, or nullptr if no such part exists
0077      */
0078     FlowPart *endPart(QStringList ids, FlowPartList *previousParts = nullptr);
0079     /**
0080      * Handles the addition of a if-else statement to the given FlowCode. This will
0081      * order the code as necessary, adding the branches in the appropriate places
0082      * @param code The FlowCode where the if-else will be added
0083      * @param case1Statement The statement (e.g. "PORTA.0 is high") used for the first case
0084      * @param case2Statement The logically opposite statement (e.g. "PORTA.0 is low") (note
0085                              that only one of the two statements will be used.
0086      * @param case1 The internal node id for case1
0087      * @param case2 The internal node id for case2
0088      */
0089     void handleIfElse(FlowCode *code, const QString &case1Statement, const QString &case2Statement, const QString &case1, const QString &case2);
0090     /**
0091      * Returns a pointer to the FlowPart that is connected to the node with the
0092      * given internal id, or nullptr if no such node / no connected part
0093      */
0094     FlowPart *outputPart(const QString &internalNodeId);
0095     /**
0096      * Returns the FlowParts connected to the given node
0097      * @see outputPart
0098      */
0099     FlowPartList inputParts(const QString &id);
0100     /**
0101      * Returns a list of parts that are connected to *all* input parts
0102      */
0103     FlowPartList inputParts();
0104     /**
0105      * Returns a list of parts that are connected to *all* output parts. Note that if
0106      * the same FlowPart is connected to more than one output, that flowpart will appear
0107      * in the FlowPartList the number of times it is connected.
0108      */
0109     FlowPartList outputParts();
0110     /**
0111      * Draw the picture of the flowpart in the given orientation onto the pixmap
0112      */
0113     void orientationPixmap(uint orientation, QPixmap &pm) const;
0114     Variant *createProperty(const QString &id, Variant::Type::Value type) override;
0115 
0116 public slots:
0117     /**
0118      * Called when variable name data for MicroSettings changes, and so our
0119      * data needs updating
0120      */
0121     void updateVarNames();
0122     /**
0123      * Called when a variable name has changed (from an entry box)
0124      */
0125     void varNameChanged(QVariant newValue, QVariant oldValue);
0126     /**
0127      * Called when some of the FlowPart-specific variables (e.g. Pin or
0128      * SevenSegment) requiring updating, such as when the PIC type changes
0129      * or the list of Pin Maps changes.
0130      */
0131     void slotUpdateFlowPartVariables();
0132 
0133 protected:
0134     void updateAttachedPositioning() override;
0135     /**
0136      * Removes the node ids that shouldn't be used for finding the end part
0137      */
0138     virtual void filterEndPartIDs(QStringList *ids)
0139     {
0140         Q_UNUSED(ids);
0141     }
0142     /**
0143      * Normally just passes the paint request onto CNItem::drawShape,
0144      * although in the case of some FlowSymbols (e.g. decision), it will handle
0145      * the drawing itself
0146      */
0147     void drawShape(QPainter &p) override;
0148 
0149     /**
0150      * Returns the goto instruction that will goto the FlowPart that is connected
0151      * to the node with the given internal id.
0152      * For example, gotoCode("stdOutput") might return "goto delay__13"
0153      */
0154     QString gotoCode(const QString &internalNodeId);
0155     /**
0156      * Creates a FPNode with an internal id of "stdinput".
0157      * The node is positioned half-way along the top of the FlowPart,
0158      * as determined by width(), height(), x() and y()
0159      */
0160     void createStdInput();
0161     /**
0162      * Creates a FPNode with an internal id of "stdoutput".
0163      * The node is positioned half-way along the bottom of the FlowPart,
0164      * as determined by width(), height(), x() and y()
0165      */
0166     void createStdOutput();
0167     /**
0168      * Creates a FPNode with an internal id of "altoutput".
0169      * The node is positioned half-way along the right of the FlowPart,
0170      * as determined by width(), height(), x() and y()
0171      */
0172     void createAltOutput();
0173     /**
0174      * Initialises a symbol, by calling setItemPoints with the shape
0175      */
0176     void initSymbol(FlowPart::FlowSymbol symbol, int width = 48);
0177 
0178     void initProcessSymbol()
0179     {
0180         initSymbol(FlowPart::ps_process);
0181     }
0182     void initCallSymbol()
0183     {
0184         initSymbol(FlowPart::ps_call);
0185     }
0186     void initIOSymbol()
0187     {
0188         initSymbol(FlowPart::ps_io);
0189     }
0190     void initRoundedRectSymbol()
0191     {
0192         initSymbol(FlowPart::ps_round);
0193     }
0194     void initDecisionSymbol()
0195     {
0196         initSymbol(FlowPart::ps_decision);
0197     }
0198 
0199     QString m_caption;
0200     uint m_orientation;
0201     FPNode *m_stdInput;
0202     FPNode *m_stdOutput;
0203     FPNode *m_altOutput;
0204     QPointer<FlowCodeDocument> m_pFlowCodeDocument;
0205 
0206     void postResize() override;
0207     void updateNodePositions();
0208 
0209 private:
0210     FlowSymbol m_flowSymbol;
0211 };
0212 typedef QList<FlowPart *> FlowPartList;
0213 
0214 #endif