diff options
author | Rr42 | 2018-05-25 10:13:59 +0530 |
---|---|---|
committer | Rr42 | 2018-05-25 10:13:59 +0530 |
commit | f7669a3fcc87d4f6040257c3dd8708c263331458 (patch) | |
tree | 9eb6b47b5911eb1f13776caaa341aab40cabe5e7 /ldmicro/draw_outputdev.cpp | |
parent | 8deab843fa6d616086955702c77751f631badc0d (diff) | |
download | LDMicroGtk-f7669a3fcc87d4f6040257c3dd8708c263331458.tar.gz LDMicroGtk-f7669a3fcc87d4f6040257c3dd8708c263331458.tar.bz2 LDMicroGtk-f7669a3fcc87d4f6040257c3dd8708c263331458.zip |
Added all LDmicro filles to be ported
Diffstat (limited to 'ldmicro/draw_outputdev.cpp')
-rw-r--r-- | ldmicro/draw_outputdev.cpp | 607 |
1 files changed, 607 insertions, 0 deletions
diff --git a/ldmicro/draw_outputdev.cpp b/ldmicro/draw_outputdev.cpp new file mode 100644 index 0000000..2173bb5 --- /dev/null +++ b/ldmicro/draw_outputdev.cpp @@ -0,0 +1,607 @@ +//----------------------------------------------------------------------------- +// 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); + + if(SelectedGxAfterNextPaint >= 0) { + MoveCursorNear(SelectedGxAfterNextPaint, SelectedGyAfterNextPaint); + InvalidateRect(MainWindow, NULL, FALSE); + SelectedGxAfterNextPaint = -1; + SelectedGyAfterNextPaint = -1; + } else if(ScrollSelectedIntoViewAfterNextPaint && Selected) { + SelectElement(-1, -1, Selected->selectedState); + ScrollSelectedIntoViewAfterNextPaint = FALSE; + InvalidateRect(MainWindow, NULL, FALSE); + } else { + if(!SelectionActive) { + if(Prog.numRungs > 0) { + if(MoveCursorTopLeft()) { + InvalidateRect(MainWindow, NULL, FALSE); + } + } + } + } + + // draw the `buses' at either side of the screen + r.left = X_PADDING - FONT_WIDTH; + r.top = 0; + r.right = r.left + 4; + r.bottom = IoListTop; + FillRect(Hdc, &r, InSimulationMode ? BusLeftBrush : BusBrush); + + r.left += POS_WIDTH*FONT_WIDTH*ColsAvailable + 2; + r.right += POS_WIDTH*FONT_WIDTH*ColsAvailable + 2; + FillRect(Hdc, &r, InSimulationMode ? BusRightBus : BusBrush); + + CursorDrawn = FALSE; + + BitBlt(paintDc, 0, 0, bw, bh, BackDc, ScrollXOffset, 0, SRCCOPY); + + if(InSimulationMode) { + KillTimer(MainWindow, TIMER_BLINK_CURSOR); + } else { + KillTimer(MainWindow, TIMER_BLINK_CURSOR); + BlinkCursor(NULL, 0, NULL, 0); + SetTimer(MainWindow, TIMER_BLINK_CURSOR, 800, BlinkCursor); + } + + Hdc = paintDc; + ok(); +} + +//----------------------------------------------------------------------------- +// Set up the syntax highlighting colours, according to the currently selected +// scheme. +//----------------------------------------------------------------------------- +static void SetSyntaxHighlightingColours(void) +{ + static const SyntaxHighlightingColours Schemes[] = { + { + RGB(0, 0, 0), // bg + RGB(255, 255, 225), // def + RGB(255, 110, 90), // selected + RGB(255, 150, 90), // op + RGB(255, 255, 100), // punct + RGB(255, 160, 160), // lit + RGB(120, 255, 130), // name + RGB(130, 130, 130), // rungNum + RGB(130, 130, 245), // comment + + RGB(255, 255, 255), // bus + + RGB(0, 0, 0), // simBg + RGB(130, 130, 130), // simRungNum + RGB(100, 130, 130), // simOff + RGB(255, 150, 150), // simOn + + RGB(255, 150, 150), // simBusLeft + RGB(150, 150, 255), // simBusRight + }, + }; + + memcpy(&HighlightColours, &Schemes[0], sizeof(Schemes[0])); +} + +//----------------------------------------------------------------------------- +// Set up the stuff we'll need to draw our schematic diagram. Fonts, brushes, +// pens, etc. +//----------------------------------------------------------------------------- +void InitForDrawing(void) +{ + SetSyntaxHighlightingColours(); + + FixedWidthFont = CreateFont( + FONT_HEIGHT, FONT_WIDTH, + 0, 0, + FW_REGULAR, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_DONTCARE, + "Lucida Console"); + + FixedWidthFontBold = CreateFont( + FONT_HEIGHT, FONT_WIDTH, + 0, 0, + FW_REGULAR, // the bold text renders funny under Vista + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_DONTCARE, + "Lucida Console"); + + LOGBRUSH lb; + lb.lbStyle = BS_SOLID; + lb.lbColor = HighlightColours.simBusRight; + BusRightBus = CreateBrushIndirect(&lb); + + lb.lbColor = HighlightColours.simBusLeft; + BusLeftBrush = CreateBrushIndirect(&lb); + + lb.lbColor = HighlightColours.bus; + BusBrush = CreateBrushIndirect(&lb); + + lb.lbColor = HighlightColours.bg; + BgBrush = CreateBrushIndirect(&lb); + + lb.lbColor = HighlightColours.simBg; + SimBgBrush = CreateBrushIndirect(&lb); +} + +//----------------------------------------------------------------------------- +// DrawChars function, for drawing to the export buffer instead of to the +// screen. +//----------------------------------------------------------------------------- +static void DrawCharsToExportBuffer(int cx, int cy, char *str) +{ + while(*str) { + if(*str >= 10) { + ExportBuffer[cy][cx] = *str; + cx++; + } + str++; + } +} + +//----------------------------------------------------------------------------- +// Export a text drawing of the ladder logic program to a file. +//----------------------------------------------------------------------------- +void ExportDrawingAsText(char *file) +{ + int maxWidth = ProgCountWidestRow(); + ColsAvailable = maxWidth; + + int totalHeight = 0; + int i; + for(i = 0; i < Prog.numRungs; i++) { + totalHeight += CountHeightOfElement(ELEM_SERIES_SUBCKT, Prog.rungs[i]); + totalHeight += 1; + } + totalHeight *= POS_HEIGHT; + totalHeight += 3; + + ExportBuffer = (char **)CheckMalloc(totalHeight * sizeof(char *)); + + int l = maxWidth*POS_WIDTH + 8; + for(i = 0; i < totalHeight; i++) { + ExportBuffer[i] = (char *)CheckMalloc(l); + memset(ExportBuffer[i], ' ', l-1); + ExportBuffer[i][4] = '|'; + ExportBuffer[i][3] = '|'; + ExportBuffer[i][l-3] = '|'; + ExportBuffer[i][l-2] = '|'; + ExportBuffer[i][l-1] = '\0'; + } + + DrawChars = DrawCharsToExportBuffer; + + int cy = 1; + for(i = 0; i < Prog.numRungs; i++) { + int cx = 5; + DrawElement(ELEM_SERIES_SUBCKT, Prog.rungs[i], &cx, &cy, + Prog.rungPowered[i]); + + if((i + 1) < 10) { + ExportBuffer[cy+1][1] = '0' + (i + 1); + } else { + ExportBuffer[cy+1][1] = '0' + ((i + 1) % 10); + ExportBuffer[cy+1][0] = '0' + ((i + 1) / 10); + } + + cy += POS_HEIGHT*CountHeightOfElement(ELEM_SERIES_SUBCKT, + Prog.rungs[i]); + cy += POS_HEIGHT; + } + cy -= 2; + DrawEndRung(5, cy); + + FILE *f = fopen(file, "w"); + if(!f) { + Error(_("Couldn't open '%s'\n"), f); + return; + } + + fprintf(f, "LDmicro export text\n"); + + if(Prog.mcu) { + fprintf(f, "for '%s', %.6f MHz crystal, %.1f ms cycle time\n\n", + Prog.mcu->mcuName, Prog.mcuClock/1e6, Prog.cycleTime/1e3); + } else { + fprintf(f, "no MCU assigned, %.6f MHz crystal, %.1f ms cycle time\n\n", + Prog.mcuClock/1e6, Prog.cycleTime/1e3); + } + + fprintf(f, "\nLADDER DIAGRAM:\n\n"); + + for(i = 0; i < totalHeight; i++) { + ExportBuffer[i][4] = '|'; + fprintf(f, "%s\n", ExportBuffer[i]); + CheckFree(ExportBuffer[i]); + } + CheckFree(ExportBuffer); + ExportBuffer = NULL; + + fprintf(f, _("\n\nI/O ASSIGNMENT:\n\n")); + + fprintf(f, _(" Name | Type | Pin\n")); + fprintf(f, " ----------------------------+--------------------+------\n"); + for(i = 0; i < Prog.io.count; i++) { + char b[1024]; + memset(b, '\0', sizeof(b)); + + PlcProgramSingleIo *io = &Prog.io.assignment[i]; + char *type = IoTypeToString(io->type); + char pin[MAX_NAME_LEN]; + + PinNumberForIo(pin, io); + + sprintf(b, " | | %s\n", + pin); + + memcpy(b+2, io->name, strlen(io->name)); + memcpy(b+31, type, strlen(type)); + fprintf(f, "%s", b); + } + + fclose(f); + + // we may have trashed the grid tables a bit; a repaint will fix that + InvalidateRect(MainWindow, NULL, FALSE); +} + +//----------------------------------------------------------------------------- +// Determine the settings of the vertical and (if needed) horizontal +// scrollbars used to scroll our view of the program. +//----------------------------------------------------------------------------- +void SetUpScrollbars(BOOL *horizShown, SCROLLINFO *horiz, SCROLLINFO *vert) +{ + int totalHeight = 0; + int i; + for(i = 0; i < Prog.numRungs; i++) { + totalHeight += CountHeightOfElement(ELEM_SERIES_SUBCKT, Prog.rungs[i]); + totalHeight++; + } + totalHeight += 1; // for the end rung + + int totalWidth = ProgCountWidestRow(); + + if(totalWidth <= ScreenColsAvailable()) { + *horizShown = FALSE; + ScrollXOffset = 0; + ScrollXOffsetMax = 0; + } else { + *horizShown = TRUE; + memset(horiz, 0, sizeof(*horiz)); + horiz->cbSize = sizeof(*horiz); + horiz->fMask = SIF_DISABLENOSCROLL | SIF_ALL; + horiz->nMin = 0; + horiz->nMax = X_PADDING + totalWidth*POS_WIDTH*FONT_WIDTH; + RECT r; + GetClientRect(MainWindow, &r); + horiz->nPage = r.right - X_PADDING; + horiz->nPos = ScrollXOffset; + + ScrollXOffsetMax = horiz->nMax - horiz->nPage + 1; + if(ScrollXOffset > ScrollXOffsetMax) ScrollXOffset = ScrollXOffsetMax; + if(ScrollXOffset < 0) ScrollXOffset = 0; + } + + vert->cbSize = sizeof(*vert); + vert->fMask = SIF_DISABLENOSCROLL | SIF_ALL; + vert->nMin = 0; + vert->nMax = totalHeight - 1; + vert->nPos = ScrollYOffset; + vert->nPage = ScreenRowsAvailable(); + + ScrollYOffsetMax = vert->nMax - vert->nPage + 1; + + if(ScrollYOffset > ScrollYOffsetMax) ScrollYOffset = ScrollYOffsetMax; + if(ScrollYOffset < 0) ScrollYOffset = 0; +} |