📄 draw_outputdev.cpp
字号:
//-----------------------------------------------------------------------------
// 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/>.
//------
//
// The two `output devices' for the drawing code: either the export as text
// stuff to write to a file, or all the routines concerned with drawing to
// the screen.
// Jonathan Westhues, Dec 2004
//-----------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "ldmicro.h"
void (*DrawChars)(int, int, char *);
// After an undo all the memory addresses change but make an effort to put
// the cursor roughly where it should be.
int SelectedGxAfterNextPaint = -1;
int SelectedGyAfterNextPaint = -1;
// After pushing a rung up or down the position of that rung in the table
// changes, but the cursor should stay where it was.
BOOL ScrollSelectedIntoViewAfterNextPaint;
// Buffer that we write to when exporting (drawing) diagram to a text file.
// Dynamically allocated so that we're at least slightly efficient.
static char **ExportBuffer;
// The fonts that we will use to draw the ladder diagram: fixed width, one
// normal-weight, one bold.
HFONT FixedWidthFont;
HFONT FixedWidthFontBold;
// Different colour brushes for right and left buses in simulation, but same
// colour for both in edit mode; also for the backgrounds in simulation and
// edit modes.
static HBRUSH BusRightBus;
static HBRUSH BusLeftBrush;
static HBRUSH BusBrush;
static HBRUSH BgBrush;
static HBRUSH SimBgBrush;
// Parameters that determine our offset if we are scrolled
int ScrollXOffset;
int ScrollYOffset;
int ScrollXOffsetMax;
int ScrollYOffsetMax;
// Is the cursor currently drawn? We XOR it so this gets toggled.
static BOOL CursorDrawn;
// Colours with which to do syntax highlighting, configurable
SyntaxHighlightingColours HighlightColours;
#define X_RIGHT_PADDING 30
//-----------------------------------------------------------------------------
// Blink the cursor on the schematic; called by a Windows timer. We XOR
// draw it so just draw the same rectangle every time to show/erase the
// cursor. Cursor may be in one of four places in the selected leaf (top,
// bottom, left, right) but we don't care; just go from the coordinates
// computed when we drew the schematic in the paint procedure.
//-----------------------------------------------------------------------------
void CALLBACK BlinkCursor(HWND hwnd, UINT msg, UINT_PTR id, DWORD time)
{
if(GetFocus() != MainWindow && !CursorDrawn) return;
if(Cursor.left == 0) return;
PlcCursor c;
memcpy(&c, &Cursor, sizeof(c));
c.top -= ScrollYOffset*POS_HEIGHT*FONT_HEIGHT;
c.left -= ScrollXOffset;
if(c.top >= IoListTop) return;
if(c.top + c.height >= IoListTop) {
c.height = IoListTop - c.top - 3;
}
Hdc = GetDC(MainWindow);
SelectObject(Hdc, GetStockObject(WHITE_BRUSH));
PatBlt(Hdc, c.left, c.top, c.width, c.height, PATINVERT);
CursorDrawn = !CursorDrawn;
ReleaseDC(MainWindow, Hdc);
}
//-----------------------------------------------------------------------------
// Output a string to the screen at a particular location, in character-
// sized units.
//-----------------------------------------------------------------------------
static void DrawCharsToScreen(int cx, int cy, char *str)
{
cy -= ScrollYOffset*POS_HEIGHT;
if(cy < -2) return;
if(cy*FONT_HEIGHT + Y_PADDING > IoListTop) return;
COLORREF prev;
BOOL firstTime = TRUE;
BOOL inNumber = FALSE;
BOOL inComment = FALSE;
int inBrace = 0;
for(; *str; str++, cx++) {
int x = cx*FONT_WIDTH + X_PADDING;
int y = cy*FONT_HEIGHT + Y_PADDING;
BOOL hiOk = !(InSimulationMode || ThisHighlighted);
if(strchr("{}[]", *str) && hiOk && !inComment) {
if(*str == '{' || *str == '[') inBrace++;
if(inBrace == 1) {
prev = GetTextColor(Hdc);
SetTextColor(Hdc, HighlightColours.punct);
TextOut(Hdc, x, y, str, 1);
SetTextColor(Hdc, prev);
} else {
TextOut(Hdc, x, y, str, 1);
}
if(*str == ']' || *str == '}') inBrace--;
} else if((
(isdigit(*str) && (firstTime || isspace(str[-1])
|| str[-1] == ':' || str[-1] == '[')) ||
(*str == '-' && isdigit(str[1]))) && hiOk && !inComment)
{
prev = GetTextColor(Hdc);
SetTextColor(Hdc, HighlightColours.lit);
TextOut(Hdc, x, y, str, 1);
SetTextColor(Hdc, prev);
inNumber = TRUE;
} else if(*str == '\x01') {
cx--;
if(hiOk) {
prev = GetTextColor(Hdc);
SetTextColor(Hdc, HighlightColours.op);
}
} else if(*str == '\x02') {
cx--;
if(hiOk) {
SetTextColor(Hdc, prev);
inComment = FALSE;
}
} else if(*str == '\x03') {
cx--;
if(hiOk) {
prev = GetTextColor(Hdc);
SetTextColor(Hdc, HighlightColours.comment);
inComment = TRUE;
}
} else if(inNumber) {
if(isdigit(*str) || *str == '.') {
prev = GetTextColor(Hdc);
SetTextColor(Hdc, HighlightColours.lit);
TextOut(Hdc, x, y, str, 1);
SetTextColor(Hdc, prev);
} else {
TextOut(Hdc, x, y, str, 1);
inNumber = FALSE;
}
} else {
TextOut(Hdc, x, y, str, 1);
}
firstTime = FALSE;
}
}
//-----------------------------------------------------------------------------
// Total number of columns that we can display in the given amount of
// window area. Need to leave some slop on the right for the scrollbar, of
// course.
//-----------------------------------------------------------------------------
int ScreenColsAvailable(void)
{
RECT r;
GetClientRect(MainWindow, &r);
return (r.right - (X_PADDING + X_RIGHT_PADDING)) / (POS_WIDTH*FONT_WIDTH);
}
//-----------------------------------------------------------------------------
// Total number of columns that we can display in the given amount of
// window area. Need to leave some slop on the right for the scrollbar, of
// course, and extra slop at the bottom for the horiz scrollbar if it is
// shown.
//-----------------------------------------------------------------------------
int ScreenRowsAvailable(void)
{
int adj;
if(ScrollXOffsetMax == 0) {
adj = 0;
} else {
adj = 18;
}
return (IoListTop - Y_PADDING - adj) / (POS_HEIGHT*FONT_HEIGHT);
}
//-----------------------------------------------------------------------------
// Paint the ladder logic program to the screen. Also figure out where the
// cursor should go and fill in coordinates for BlinkCursor. Not allowed to
// draw deeper than IoListTop, as we would run in to the I/O listbox.
//-----------------------------------------------------------------------------
void PaintWindow(void)
{
static HBITMAP BackBitmap;
static HDC BackDc;
static int BitmapWidth;
ok();
RECT r;
GetClientRect(MainWindow, &r);
int bw = r.right;
int bh = IoListTop;
HDC paintDc;
if(!BackDc) {
HWND desktop = GetDesktopWindow();
RECT dk;
GetClientRect(desktop, &dk);
BitmapWidth = max(2000, dk.right + 300);
BackBitmap = CreateCompatibleBitmap(Hdc, BitmapWidth, dk.bottom + 300);
BackDc = CreateCompatibleDC(Hdc);
SelectObject(BackDc, BackBitmap);
}
paintDc = Hdc;
Hdc = BackDc;
RECT fi;
fi.left = 0; fi.top = 0;
fi.right = BitmapWidth; fi.bottom = bh;
FillRect(Hdc, &fi, InSimulationMode ? SimBgBrush : BgBrush);
// now figure out how we should draw the ladder logic
ColsAvailable = ProgCountWidestRow();
if(ColsAvailable < ScreenColsAvailable()) {
ColsAvailable = ScreenColsAvailable();
}
memset(DisplayMatrix, 0, sizeof(DisplayMatrix));
SelectionActive = FALSE;
memset(&Cursor, 0, sizeof(Cursor));
DrawChars = DrawCharsToScreen;
int i;
int cy = 0;
int rowsAvailable = ScreenRowsAvailable();
for(i = 0; i < Prog.numRungs; i++) {
int thisHeight = POS_HEIGHT*CountHeightOfElement(ELEM_SERIES_SUBCKT,
Prog.rungs[i]);
// For speed, there is no need to draw everything all the time, but
// we still must draw a bit above and below so that the DisplayMatrix
// is filled in enough to make it possible to reselect using the
// cursor keys.
if(((cy + thisHeight) >= (ScrollYOffset - 8)*POS_HEIGHT) &&
(cy < (ScrollYOffset + rowsAvailable + 8)*POS_HEIGHT))
{
SetBkColor(Hdc, InSimulationMode ? HighlightColours.simBg :
HighlightColours.bg);
SetTextColor(Hdc, InSimulationMode ? HighlightColours.simRungNum :
HighlightColours.rungNum);
SelectObject(Hdc, FixedWidthFont);
int rung = i + 1;
int y = Y_PADDING + FONT_HEIGHT*cy;
int yp = y + FONT_HEIGHT*(POS_HEIGHT/2) -
POS_HEIGHT*FONT_HEIGHT*ScrollYOffset;
if(rung < 10) {
char r[1] = { rung + '0' };
TextOut(Hdc, 8 + FONT_WIDTH, yp, r, 1);
} else {
char r[2] = { (rung / 10) + '0', (rung % 10) + '0' };
TextOut(Hdc, 8, yp, r, 2);
}
int cx = 0;
DrawElement(ELEM_SERIES_SUBCKT, Prog.rungs[i], &cx, &cy,
Prog.rungPowered[i]);
}
cy += thisHeight;
cy += POS_HEIGHT;
}
cy -= 2;
DrawEndRung(0, cy);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -