⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 draw.cpp

📁 plc软件的源代码 支持PIC ATMEGA单片机
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//-----------------------------------------------------------------------------
// Copyright 2007 Jonathan Westhues
//
// This file is part of LDmicro.
// 
// LDmicro 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 3 of the License, or
// (at your option) any later version.
// 
// LDmicro is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with LDmicro.  If not, see <http://www.gnu.org/licenses/>.
//------
//
// Routines for drawing the ladder diagram as a schematic on screen. This
// includes the stuff to figure out where we should draw each leaf (coil,
// contact, timer, ...) element on screen and how we should connect them up
// with wires.
// Jonathan Westhues, Oct 2004
//-----------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#include "ldmicro.h"

// Number of drawing columns (leaf element units) available. We want to
// know this so that we can right-justify the coils.
int ColsAvailable;

// Set when we draw the selected element in the program. If there is no
// element selected then we ought to put the cursor at the top left of
// the screen.
BOOL SelectionActive;

// Is the element currently being drawn highlighted because it is selected?
// If so we must not do further syntax highlighting.
BOOL ThisHighlighted;

#define TOO_LONG _("!!!too long!!!")

#define DM_BOUNDS(gx, gy) { \
        if((gx) >= DISPLAY_MATRIX_X_SIZE || (gx) < 0) oops(); \
        if((gy) >= DISPLAY_MATRIX_Y_SIZE || (gy) < 0) oops(); \
    }

//-----------------------------------------------------------------------------
// The display code is the only part of the program that knows how wide a
// rung will be when it's displayed; so this is the only convenient place to
// warn the user and undo their changes if they created something too wide.
// This is not very clean.
//-----------------------------------------------------------------------------
static BOOL CheckBoundsUndoIfFails(int gx, int gy)
{
    if(gx >= DISPLAY_MATRIX_X_SIZE || gx < 0 ||
       gy >= DISPLAY_MATRIX_Y_SIZE || gy < 0)
    {
        if(CanUndo()) {
            UndoUndo();
            Error(_("Too many elements in subcircuit!"));
            return TRUE;
        }
    }
    return FALSE;
}

//-----------------------------------------------------------------------------
// Determine the width, in leaf element units, of a particular subcircuit.
// The width of a leaf is 1, the width of a series circuit is the sum of
// of the widths of its members, and the width of a parallel circuit is
// the maximum of the widths of its members.
//-----------------------------------------------------------------------------
static int CountWidthOfElement(int which, void *elem, int soFar)
{
    switch(which) {
        case ELEM_PLACEHOLDER:
        case ELEM_OPEN:
        case ELEM_SHORT:
        case ELEM_CONTACTS:
        case ELEM_TON:
        case ELEM_TOF:
        case ELEM_RTO:
        case ELEM_CTU:
        case ELEM_CTD:
        case ELEM_ONE_SHOT_RISING:
        case ELEM_ONE_SHOT_FALLING:
        case ELEM_EQU:
        case ELEM_NEQ:
        case ELEM_GRT:
        case ELEM_GEQ:
        case ELEM_LES:
        case ELEM_LEQ:
        case ELEM_UART_RECV:
        case ELEM_UART_SEND:
            return 1;

        case ELEM_FORMATTED_STRING:
            return 2;

        case ELEM_COMMENT: {
            if(soFar != 0) oops();

            ElemLeaf *l = (ElemLeaf *)elem;
            char tbuf[MAX_COMMENT_LEN];

            strcpy(tbuf, l->d.comment.str);
            char *b = strchr(tbuf, '\n');

            int len;
            if(b) {
                *b = '\0';
                len = max(strlen(tbuf)-1, strlen(b+1));
            } else {
                len = strlen(tbuf);
            }
            // round up, and allow space for lead-in
            len = (len + 7 + (POS_WIDTH-1)) / POS_WIDTH;
            return max(ColsAvailable, len);
        }
        case ELEM_CTC:
        case ELEM_RES:
        case ELEM_COIL:
        case ELEM_MOVE:
        case ELEM_SHIFT_REGISTER:
        case ELEM_LOOK_UP_TABLE:
        case ELEM_PIECEWISE_LINEAR:
        case ELEM_MASTER_RELAY:
        case ELEM_READ_ADC:
        case ELEM_SET_PWM:
        case ELEM_PERSIST:
            if(ColsAvailable - soFar > 1) {
                return ColsAvailable - soFar;
            } else {
                return 1;
            }

        case ELEM_ADD:
        case ELEM_SUB:
        case ELEM_MUL:
        case ELEM_DIV:
            if(ColsAvailable - soFar > 2) {
                return ColsAvailable - soFar;
            } else {
                return 2;
            }

        case ELEM_SERIES_SUBCKT: {
            // total of the width of the members
            int total = 0;
            int i;
            ElemSubcktSeries *s = (ElemSubcktSeries *)elem;
            for(i = 0; i < s->count; i++) {
                total += CountWidthOfElement(s->contents[i].which,
                    s->contents[i].d.any, total+soFar);
            }
            return total;
        }

        case ELEM_PARALLEL_SUBCKT: {
            // greatest of the width of the members
            int max = 0;
            int i;
            ElemSubcktParallel *p = (ElemSubcktParallel *)elem;
            for(i = 0; i < p->count; i++) {
                int w = CountWidthOfElement(p->contents[i].which,
                    p->contents[i].d.any, soFar);
                if(w > max) {
                    max = w;
                }
            }
            return max;
        }

        default:
            oops();
    }
}

//-----------------------------------------------------------------------------
// Determine the height, in leaf element units, of a particular subcircuit.
// The height of a leaf is 1, the height of a parallel circuit is the sum of
// of the heights of its members, and the height of a series circuit is the
// maximum of the heights of its members. (This is the dual of the width
// case.)
//-----------------------------------------------------------------------------
int CountHeightOfElement(int which, void *elem)
{
    switch(which) {
        CASE_LEAF
            return 1;

        case ELEM_PARALLEL_SUBCKT: {
            // total of the height of the members
            int total = 0;
            int i;
            ElemSubcktParallel *s = (ElemSubcktParallel *)elem;
            for(i = 0; i < s->count; i++) {
                total += CountHeightOfElement(s->contents[i].which,
                    s->contents[i].d.any);
            }
            return total;
        }

        case ELEM_SERIES_SUBCKT: {
            // greatest of the height of the members
            int max = 0;
            int i;
            ElemSubcktSeries *s = (ElemSubcktSeries *)elem;
            for(i = 0; i < s->count; i++) {
                int w = CountHeightOfElement(s->contents[i].which,
                    s->contents[i].d.any);
                if(w > max) {
                    max = w;
                }
            }
            return max;
        }

        default:
            oops();
    }
}

//-----------------------------------------------------------------------------
// Determine the width, in leaf element units, of the widest row of the PLC
// program (i.e. loop over all the rungs and find the widest).
//-----------------------------------------------------------------------------
int ProgCountWidestRow(void)
{
    int i;
    int max = 0;
    int colsTemp = ColsAvailable;
    ColsAvailable = 0;
    for(i = 0; i < Prog.numRungs; i++) {
        int w = CountWidthOfElement(ELEM_SERIES_SUBCKT, Prog.rungs[i], 0);
        if(w > max) {
            max = w;
        }
    }
    ColsAvailable = colsTemp;
    return max;
}

//-----------------------------------------------------------------------------
// Draw a vertical wire one leaf element unit high up from (cx, cy), where cx
// and cy are in charcter units.
//-----------------------------------------------------------------------------
static void VerticalWire(int cx, int cy)
{
    int j;
    for(j = 1; j < POS_HEIGHT; j++) {
        DrawChars(cx, cy + (POS_HEIGHT/2 - j), "|");
    }
    DrawChars(cx, cy + (POS_HEIGHT/2), "+");
    DrawChars(cx, cy + (POS_HEIGHT/2 - POS_HEIGHT), "+");
}

//-----------------------------------------------------------------------------
// Convenience functions for making the text colors pretty, for DrawElement.
//-----------------------------------------------------------------------------
static void NormText(void)
{
    SetTextColor(Hdc, InSimulationMode ? HighlightColours.simOff :
        HighlightColours.def);
    SelectObject(Hdc, FixedWidthFont);
}
static void EmphText(void)
{
    SetTextColor(Hdc, InSimulationMode ? HighlightColours.simOn :
        HighlightColours.selected);
    SelectObject(Hdc, FixedWidthFontBold);
}
static void NameText(void)
{
    if(!InSimulationMode && !ThisHighlighted) {
        SetTextColor(Hdc, HighlightColours.name);
    }
}
static void BodyText(void)
{
    if(!InSimulationMode && !ThisHighlighted) {
        SetTextColor(Hdc, HighlightColours.def);
    }
}
static void PoweredText(BOOL powered)
{
    if(InSimulationMode) {
        if(powered)
            EmphText();
        else
            NormText();
    }
}

//-----------------------------------------------------------------------------
// Count the length of a string, in characters. Nonstandard because the
// string may contain special characters to indicate formatting (syntax
// highlighting).
//-----------------------------------------------------------------------------
static int FormattedStrlen(char *str)
{
    int l = 0;
    while(*str) {
        if(*str > 10) {
            l++;
        }
        str++;
    }
    return l;
}

//-----------------------------------------------------------------------------
// Draw a string, centred in the space of a single position, with spaces on
// the left and right. Draws on the upper line of the position.
//-----------------------------------------------------------------------------
static void CenterWithSpaces(int cx, int cy, char *str, BOOL powered,
    BOOL isName)
{
    int extra = POS_WIDTH - FormattedStrlen(str);
    PoweredText(powered);
    if(isName) NameText();
    DrawChars(cx + (extra/2), cy + (POS_HEIGHT/2) - 1, str);
    if(isName) BodyText();
}

//-----------------------------------------------------------------------------
// Like CenterWithWires, but for an arbitrary width position (e.g. for ADD
// and SUB, which are double-width).
//-----------------------------------------------------------------------------
static void CenterWithWiresWidth(int cx, int cy, char *str, BOOL before,
    BOOL after, int totalWidth)
{
    int extra = totalWidth - FormattedStrlen(str);

    PoweredText(after);
    DrawChars(cx + (extra/2), cy + (POS_HEIGHT/2), str);

    PoweredText(before);
    int i;
    for(i = 0; i < (extra/2); i++) {
        DrawChars(cx + i, cy + (POS_HEIGHT/2), "-");
    }
    PoweredText(after);
    for(i = FormattedStrlen(str)+(extra/2); i < totalWidth; i++) {
        DrawChars(cx + i, cy + (POS_HEIGHT/2), "-");
    }
}

//-----------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -