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/ldmicro.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/ldmicro.cpp')
-rw-r--r-- | ldmicro/ldmicro.cpp | 1177 |
1 files changed, 1177 insertions, 0 deletions
diff --git a/ldmicro/ldmicro.cpp b/ldmicro/ldmicro.cpp new file mode 100644 index 0000000..9997b5a --- /dev/null +++ b/ldmicro/ldmicro.cpp @@ -0,0 +1,1177 @@ +//----------------------------------------------------------------------------- +// 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/>. +//------ +// +// A ladder logic compiler for 8 bit micros: user draws a ladder diagram, +// with an appropriately constrained `schematic editor,' and then we can +// simulated it under Windows or generate PIC/AVR code that performs the +// requested operations. This files contains the program entry point, plus +// most of the UI logic relating to the main window. +// Jonathan Westhues, Oct 2004 +//----------------------------------------------------------------------------- +#include <windows.h> +#include <commctrl.h> +#include <commdlg.h> +#include <stdio.h> +#include <stdlib.h> + +#include "ldmicro.h" +#include "freeze.h" +#include "mcutable.h" +#include "advanceddialog.h" + + +HINSTANCE Instance; +HWND MainWindow; +HDC Hdc; + +// parameters used to capture the mouse when implementing our totally non- +// general splitter control +static HHOOK MouseHookHandle; +static int MouseY; + +// For the open/save dialog boxes +#define LDMICRO_PATTERN "LDmicro Ladder Logic Programs (*.ld)\0*.ld\0" \ + "All files\0*\0\0" +char CurrentSaveFile[MAX_PATH]; +static BOOL ProgramChangedNotSaved = FALSE; + +#define HEX_PATTERN "Intel Hex Files (*.hex)\0*.hex\0All files\0*\0\0" +#define C_PATTERN "C Source Files (*.c)\0*.c\0All Files\0*\0\0" +#define INTERPRETED_PATTERN \ + "Interpretable Byte Code Files (*.int)\0*.int\0All Files\0*\0\0" +char CurrentCompileFile[MAX_PATH]; + +#define TXT_PATTERN "Text Files (*.txt)\0*.txt\0All files\0*\0\0" + +// Everything relating to the PLC's program, I/O configuration, processor +// choice, and so on--basically everything that would be saved in the +// project file. +PlcProgram Prog; + +//----------------------------------------------------------------------------- +// Get a filename with a common dialog box and then save the program to that +// file and then set our default filename to that. +//----------------------------------------------------------------------------- +static BOOL SaveAsDialog(void) +{ + OPENFILENAME ofn; + + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hInstance = Instance; + ofn.lpstrFilter = LDMICRO_PATTERN; + ofn.lpstrDefExt = "ld"; + ofn.lpstrFile = CurrentSaveFile; + ofn.nMaxFile = sizeof(CurrentSaveFile); + ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; + + if(!GetSaveFileName(&ofn)) + return FALSE; + + if(!SaveProjectToFile(CurrentSaveFile)) { + Error(_("Couldn't write to '%s'."), CurrentSaveFile); + return FALSE; + } else { + ProgramChangedNotSaved = FALSE; + return TRUE; + } +} + +//----------------------------------------------------------------------------- +// Get a filename with a common dialog box and then export the program as +// an ASCII art drawing. +//----------------------------------------------------------------------------- +static void ExportDialog(void) +{ + char exportFile[MAX_PATH]; + OPENFILENAME ofn; + + exportFile[0] = '\0'; + + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hInstance = Instance; + ofn.lpstrFilter = TXT_PATTERN; + ofn.lpstrFile = exportFile; + ofn.lpstrTitle = _("Export As Text"); + ofn.nMaxFile = sizeof(exportFile); + ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; + + if(!GetSaveFileName(&ofn)) + return; + + ExportDrawingAsText(exportFile); +} + +//----------------------------------------------------------------------------- +// If we already have a filename, save the program to that. Otherwise same +// as Save As. Returns TRUE if it worked, else returns FALSE. +//----------------------------------------------------------------------------- +static BOOL SaveProgram(void) +{ + if(strlen(CurrentSaveFile)) { + if(!SaveProjectToFile(CurrentSaveFile)) { + Error(_("Couldn't write to '%s'."), CurrentSaveFile); + return FALSE; + } else { + ProgramChangedNotSaved = FALSE; + return TRUE; + } + } else { + return SaveAsDialog(); + } +} + +//----------------------------------------------------------------------------- +// Compile the program to a hex file for the target micro. Get the output +// file name if necessary, then call the micro-specific compile routines. +//----------------------------------------------------------------------------- +static void CompileProgram(BOOL compileAs) +{ + if(compileAs || strlen(CurrentCompileFile)==0) { + OPENFILENAME ofn; + + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hInstance = Instance; + ofn.lpstrTitle = _("Compile To"); + if(Prog.mcu && Prog.mcu->whichIsa == ISA_ANSIC) { + ofn.lpstrFilter = C_PATTERN; + ofn.lpstrDefExt = "c"; + } else if(Prog.mcu && Prog.mcu->whichIsa == ISA_INTERPRETED) { + ofn.lpstrFilter = INTERPRETED_PATTERN; + ofn.lpstrDefExt = "int"; + } else { + ofn.lpstrFilter = HEX_PATTERN; + ofn.lpstrDefExt = "hex"; + } + ofn.lpstrFile = CurrentCompileFile; + ofn.nMaxFile = sizeof(CurrentCompileFile); + ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; + + if(!GetSaveFileName(&ofn)) + return; + + // hex output filename is stored in the .ld file + ProgramChangedNotSaved = TRUE; + } + + if(!GenerateIntermediateCode()) return; + + if(Prog.mcu == NULL) { + Error(_("Must choose a target microcontroller before compiling.")); + return; + } + + if(UartFunctionUsed() && Prog.mcu->uartNeeds.rxPin == 0) { + Error(_("UART function used but not supported for this micro.")); + return; + } + + if(PwmFunctionUsed() && Prog.mcu->pwmNeedsPin == 0) { + Error(_("PWM function used but not supported for this micro.")); + return; + } + + switch(Prog.mcu->whichIsa) { + case ISA_AVR: CompileAvr(CurrentCompileFile); break; + case ISA_PIC16: CompilePic16(CurrentCompileFile); break; + case ISA_ANSIC: CompileAnsiC(CurrentCompileFile); break; + case ISA_INTERPRETED: CompileInterpreted(CurrentCompileFile); break; + case ISA_ARDUINO: CompileArduino(CurrentCompileFile); break; + + default: oops(); + } +// IntDumpListing("t.pl"); +} + +//----------------------------------------------------------------------------- +// If the program has been modified then give the user the option to save it +// or to cancel the operation they are performing. Return TRUE if they want +// to cancel. +//----------------------------------------------------------------------------- +BOOL CheckSaveUserCancels(void) +{ + if(!ProgramChangedNotSaved) { + // no problem + return FALSE; + } + + int r = MessageBox(MainWindow, + _("The program has changed since it was last saved.\r\n\r\n" + "Do you want to save the changes?"), "LDmicro", + MB_YESNOCANCEL | MB_ICONWARNING); + switch(r) { + case IDYES: + if(SaveProgram()) + return FALSE; + else + return TRUE; + + case IDNO: + return FALSE; + + case IDCANCEL: + return TRUE; + + default: + oops(); + } +} + +//----------------------------------------------------------------------------- +// Load a new program from a file. If it succeeds then set our default filename +// to that, else we end up with an empty file then. +//----------------------------------------------------------------------------- +static void OpenDialog(void) +{ + OPENFILENAME ofn; + + char tempSaveFile[MAX_PATH] = ""; + + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hInstance = Instance; + ofn.lpstrFilter = LDMICRO_PATTERN; + ofn.lpstrDefExt = "ld"; + ofn.lpstrFile = tempSaveFile; + ofn.nMaxFile = sizeof(tempSaveFile); + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + + if(!GetOpenFileName(&ofn)) + return; + + if(!LoadProjectFromFile(tempSaveFile)) { + Error(_("Couldn't open '%s'."), tempSaveFile); + CurrentSaveFile[0] = '\0'; + } else { + ProgramChangedNotSaved = FALSE; + strcpy(CurrentSaveFile, tempSaveFile); + UndoFlush(); + } + + GenerateIoListDontLoseSelection(); + RefreshScrollbars(); + UpdateMainWindowTitleBar(); +} + +//----------------------------------------------------------------------------- +// Housekeeping required when the program changes: mark the program as +// changed so that we ask if user wants to save before exiting, and update +// the I/O list. +//----------------------------------------------------------------------------- +void ProgramChanged(void) +{ + ProgramChangedNotSaved = TRUE; + GenerateIoListDontLoseSelection(); + RefreshScrollbars(); + if(AdvancedWindowOpen) + { + FlushPinNames(); + PopulateNamingList(); + } +} +#define CHANGING_PROGRAM(x) { \ + UndoRemember(); \ + x; \ + ProgramChanged(); \ + } + +//----------------------------------------------------------------------------- +// Hook that we install when the user starts dragging the `splitter,' in case +// they drag it out of the narrow area of the drawn splitter bar. Resize +// the listview in response to mouse move, and unhook ourselves when they +// release the mouse button. +//----------------------------------------------------------------------------- +static LRESULT CALLBACK MouseHook(int code, WPARAM wParam, LPARAM lParam) +{ + switch(code) { + case HC_ACTION: { + MSLLHOOKSTRUCT *mhs = (MSLLHOOKSTRUCT *)lParam; + + switch(wParam) { + case WM_MOUSEMOVE: { + int dy = MouseY - mhs->pt.y; + + IoListHeight += dy; + if(IoListHeight < 50) IoListHeight = 50; + MouseY = mhs->pt.y; + MainWindowResized(); + + break; + } + + case WM_LBUTTONUP: + UnhookWindowsHookEx(MouseHookHandle); + break; + } + break; + } + } + return CallNextHookEx(MouseHookHandle, code, wParam, lParam); +} + +//----------------------------------------------------------------------------- +// Handle a selection from the menu bar of the main window. +//----------------------------------------------------------------------------- +static void ProcessMenu(int code) +{ + if(code >= MNU_PROCESSOR_0 && code < MNU_PROCESSOR_0+NUM_SUPPORTED_MCUS) { + strcpy(CurrentCompileFile, ""); + Prog.mcu = &SupportedMcus[code - MNU_PROCESSOR_0]; + RefreshControlsToSettings(); + return; + } + if(code == MNU_PROCESSOR_0+NUM_SUPPORTED_MCUS) { + Prog.mcu = NULL; + strcpy(CurrentCompileFile, ""); + RefreshControlsToSettings(); + return; + } + + switch(code) { + case MNU_NEW: + if(CheckSaveUserCancels()) break; + NewProgram(); + strcpy(CurrentSaveFile, ""); + strcpy(CurrentCompileFile, ""); + GenerateIoListDontLoseSelection(); + RefreshScrollbars(); + UpdateMainWindowTitleBar(); + break; + + case MNU_OPEN: + if(CheckSaveUserCancels()) break; + OpenDialog(); + break; + + case MNU_SAVE: + SaveProgram(); + UpdateMainWindowTitleBar(); + break; + + case MNU_SAVE_AS: + SaveAsDialog(); + UpdateMainWindowTitleBar(); + break; + + case MNU_EXPORT: + ExportDialog(); + break; + + case MNU_EXIT: + if(CheckSaveUserCancels()) break; + PostQuitMessage(0); + break; + + case MNU_INSERT_COMMENT: + CHANGING_PROGRAM(AddComment(_("--add comment here--"))); + break; + + case MNU_INSERT_CONTACTS: + CHANGING_PROGRAM(AddContact()); + break; + + case MNU_INSERT_COIL: + CHANGING_PROGRAM(AddCoil()); + break; + + case MNU_INSERT_TON: + CHANGING_PROGRAM(AddTimer(ELEM_TON)); + break; + + case MNU_INSERT_TOF: + CHANGING_PROGRAM(AddTimer(ELEM_TOF)); + break; + + case MNU_INSERT_RTO: + CHANGING_PROGRAM(AddTimer(ELEM_RTO)); + break; + + case MNU_INSERT_CTU: + CHANGING_PROGRAM(AddCounter(ELEM_CTU)); + break; + + case MNU_INSERT_CTD: + CHANGING_PROGRAM(AddCounter(ELEM_CTD)); + break; + + case MNU_INSERT_CTC: + CHANGING_PROGRAM(AddCounter(ELEM_CTC)); + break; + + case MNU_INSERT_RES: + CHANGING_PROGRAM(AddReset()); + break; + + case MNU_INSERT_OPEN: + CHANGING_PROGRAM(AddEmpty(ELEM_OPEN)); + break; + + case MNU_INSERT_SHORT: + CHANGING_PROGRAM(AddEmpty(ELEM_SHORT)); + break; + + case MNU_INSERT_MASTER_RLY: + CHANGING_PROGRAM(AddMasterRelay()); + break; + + case MNU_INSERT_SHIFT_REG: + CHANGING_PROGRAM(AddShiftRegister()); + break; + + case MNU_INSERT_LUT: + CHANGING_PROGRAM(AddLookUpTable()); + break; + + case MNU_INSERT_PWL: + CHANGING_PROGRAM(AddPiecewiseLinear()); + break; + + case MNU_INSERT_FMTD_STR: + CHANGING_PROGRAM(AddFormattedString()); + break; + + case MNU_INSERT_OSR: + CHANGING_PROGRAM(AddEmpty(ELEM_ONE_SHOT_RISING)); + break; + + case MNU_INSERT_OSF: + CHANGING_PROGRAM(AddEmpty(ELEM_ONE_SHOT_FALLING)); + break; + + case MNU_INSERT_MOV: + CHANGING_PROGRAM(AddMove()); + break; + + case MNU_INSERT_SET_PWM: + CHANGING_PROGRAM(AddSetPwm()); + break; + + case MNU_INSERT_READ_ADC: + CHANGING_PROGRAM(AddReadAdc()); + break; + + case MNU_INSERT_UART_SEND: + CHANGING_PROGRAM(AddUart(ELEM_UART_SEND)); + break; + + case MNU_INSERT_UART_RECV: + CHANGING_PROGRAM(AddUart(ELEM_UART_RECV)); + break; + + case MNU_INSERT_PERSIST: + CHANGING_PROGRAM(AddPersist()); + break; + + { + int elem; + case MNU_INSERT_ADD: elem = ELEM_ADD; goto math; + case MNU_INSERT_SUB: elem = ELEM_SUB; goto math; + case MNU_INSERT_MUL: elem = ELEM_MUL; goto math; + case MNU_INSERT_DIV: elem = ELEM_DIV; goto math; +math: + CHANGING_PROGRAM(AddMath(elem)); + break; + } + + { + int elem; + case MNU_INSERT_EQU: elem = ELEM_EQU; goto cmp; + case MNU_INSERT_NEQ: elem = ELEM_NEQ; goto cmp; + case MNU_INSERT_GRT: elem = ELEM_GRT; goto cmp; + case MNU_INSERT_GEQ: elem = ELEM_GEQ; goto cmp; + case MNU_INSERT_LES: elem = ELEM_LES; goto cmp; + case MNU_INSERT_LEQ: elem = ELEM_LEQ; goto cmp; +cmp: + CHANGING_PROGRAM(AddCmp(elem)); + break; + } + + case MNU_MAKE_NORMAL: + CHANGING_PROGRAM(MakeNormalSelected()); + break; + + case MNU_NEGATE: + CHANGING_PROGRAM(NegateSelected()); + break; + + case MNU_MAKE_SET_ONLY: + CHANGING_PROGRAM(MakeSetOnlySelected()); + break; + + case MNU_MAKE_RESET_ONLY: + CHANGING_PROGRAM(MakeResetOnlySelected()); + break; + + case MNU_UNDO: + UndoUndo(); + break; + + case MNU_REDO: + UndoRedo(); + break; + + case MNU_INSERT_RUNG_BEFORE: + CHANGING_PROGRAM(InsertRung(FALSE)); + break; + + case MNU_INSERT_RUNG_AFTER: + CHANGING_PROGRAM(InsertRung(TRUE)); + break; + + case MNU_DELETE_RUNG: + CHANGING_PROGRAM(DeleteSelectedRung()); + break; + + case MNU_PUSH_RUNG_UP: + CHANGING_PROGRAM(PushRungUp()); + break; + + case MNU_PUSH_RUNG_DOWN: + CHANGING_PROGRAM(PushRungDown()); + break; + + case MNU_DELETE_ELEMENT: + CHANGING_PROGRAM(DeleteSelectedFromProgram()); + break; + + case MNU_MCU_SETTINGS: + CHANGING_PROGRAM(ShowConfDialog()); + break; + + case MNU_SIMULATION_MODE: + ToggleSimulationMode(); + ToggleAdvancedSimulationMode(); + break; + + case MNU_START_SIMULATION: + StartSimulation(); + StartAdvSimulation(); + break; + + case MNU_STOP_SIMULATION: + StopSimulation(); + StopAdvSimulation(); + break; + + case MNU_SINGLE_CYCLE: + SimulateOneCycle(TRUE); + break; + + case MNU_COMPILE: + CompileProgram(FALSE); + break; + + case MNU_COMPILE_AS: + CompileProgram(TRUE); + break; + + case MNU_MANUAL: + ShowHelpDialog(FALSE); + break; + + case MNU_ABOUT: + ShowHelpDialog(TRUE); + break; + + case MNU_ADV_SIMULATION: + ShowAdvancedDialog(); + } +} + +//----------------------------------------------------------------------------- +// WndProc for MainWindow. +//----------------------------------------------------------------------------- +LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_ERASEBKGND: + break; + + case WM_SETFOCUS: + InvalidateRect(MainWindow, NULL, FALSE); + break; + + case WM_PAINT: { + PAINTSTRUCT ps; + Hdc = BeginPaint(hwnd, &ps); + + // This draws the schematic. + PaintWindow(); + + RECT r; + // Fill around the scroll bars + if(NeedHoriz) { + r.top = IoListTop - ScrollHeight - 2; + r.bottom = IoListTop - 2; + FillRect(Hdc, &r, (HBRUSH)GetStockObject(LTGRAY_BRUSH)); + } + GetClientRect(MainWindow, &r); + r.left = r.right - ScrollWidth - 2; + FillRect(Hdc, &r, (HBRUSH)GetStockObject(LTGRAY_BRUSH)); + + // Draw the splitter thing to grab to resize the I/O listview. + GetClientRect(MainWindow, &r); + r.top = IoListTop - 2; + r.bottom = IoListTop; + FillRect(Hdc, &r, (HBRUSH)GetStockObject(LTGRAY_BRUSH)); + r.top = IoListTop - 2; + r.bottom = IoListTop - 1; + FillRect(Hdc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH)); + r.top = IoListTop; + r.bottom = IoListTop + 1; + FillRect(Hdc, &r, (HBRUSH)GetStockObject(DKGRAY_BRUSH)); + + EndPaint(hwnd, &ps); + return 1; + } + + case WM_KEYDOWN: { + if(wParam == 'M') { + if(GetAsyncKeyState(VK_CONTROL) & 0x8000) { + ToggleSimulationMode(); + ToggleAdvancedSimulationMode(); + break; + } + } else if(wParam == VK_TAB) { + SetFocus(IoList); + BlinkCursor(0, 0, 0, 0); + break; + } else if(wParam == VK_F1) { + ShowHelpDialog(FALSE); + break; + } + + if(wParam == 'A') { + if(GetAsyncKeyState(VK_CONTROL) & 0x8000) { + ShowAdvancedDialog(); + break; + } + } + + if(InSimulationMode) { + switch(wParam) { + case ' ': + SimulateOneCycle(TRUE); + break; + + case 'R': + if(GetAsyncKeyState(VK_CONTROL) & 0x8000) + StartSimulation(); + StartAdvSimulation(); + break; + + case 'H': + if(GetAsyncKeyState(VK_CONTROL) & 0x8000) + StopSimulation(); + StopAdvSimulation(); + break; + + case VK_DOWN: + if(ScrollYOffset < ScrollYOffsetMax) + ScrollYOffset++; + RefreshScrollbars(); + InvalidateRect(MainWindow, NULL, FALSE); + break; + + case VK_UP: + if(ScrollYOffset > 0) + ScrollYOffset--; + RefreshScrollbars(); + InvalidateRect(MainWindow, NULL, FALSE); + break; + + case VK_LEFT: + ScrollXOffset -= FONT_WIDTH; + if(ScrollXOffset < 0) ScrollXOffset = 0; + RefreshScrollbars(); + InvalidateRect(MainWindow, NULL, FALSE); + break; + + case VK_RIGHT: + ScrollXOffset += FONT_WIDTH; + if(ScrollXOffset >= ScrollXOffsetMax) + ScrollXOffset = ScrollXOffsetMax; + RefreshScrollbars(); + InvalidateRect(MainWindow, NULL, FALSE); + break; + + case VK_RETURN: + case VK_ESCAPE: + ToggleSimulationMode(); + break; + } + break; + } + + switch(wParam) { + case VK_F5: + CompileProgram(FALSE); + break; + + case VK_UP: + if(GetAsyncKeyState(VK_SHIFT) & 0x8000) { + CHANGING_PROGRAM(PushRungUp()); + } else { + MoveCursorKeyboard(wParam); + } + break; + + case VK_DOWN: + if(GetAsyncKeyState(VK_SHIFT) & 0x8000) { + CHANGING_PROGRAM(PushRungDown()); + } else { + MoveCursorKeyboard(wParam); + } + break; + + case VK_RIGHT: + case VK_LEFT: + MoveCursorKeyboard(wParam); + break; + + case VK_RETURN: + CHANGING_PROGRAM(EditSelectedElement()); + break; + + case VK_DELETE: + if(GetAsyncKeyState(VK_SHIFT) & 0x8000) { + CHANGING_PROGRAM(DeleteSelectedRung()); + } else { + CHANGING_PROGRAM(DeleteSelectedFromProgram()); + } + break; + + case VK_OEM_1: + CHANGING_PROGRAM(AddComment(_("--add comment here--"))); + break; + + case 'C': + CHANGING_PROGRAM(AddContact()); + break; + + // TODO: rather country-specific here + case VK_OEM_2: + CHANGING_PROGRAM(AddEmpty(ELEM_ONE_SHOT_RISING)); + break; + + case VK_OEM_5: + CHANGING_PROGRAM(AddEmpty(ELEM_ONE_SHOT_FALLING)); + break; + + case 'L': + CHANGING_PROGRAM(AddCoil()); + break; + + case 'R': + CHANGING_PROGRAM(MakeResetOnlySelected()); + break; + + case 'E': + if(GetAsyncKeyState(VK_CONTROL) & 0x8000) { + ExportDialog(); + } else { + CHANGING_PROGRAM(AddReset()); + } + break; + + case 'S': + if(GetAsyncKeyState(VK_CONTROL) & 0x8000) { + SaveProgram(); + UpdateMainWindowTitleBar(); + } else { + CHANGING_PROGRAM(MakeSetOnlySelected()); + } + break; + + case 'N': + if(GetAsyncKeyState(VK_CONTROL) & 0x8000) { + if(CheckSaveUserCancels()) break; + if(!ProgramChangedNotSaved) { + int r = MessageBox(MainWindow, + _("Start new program?"), + "LDmicro", MB_YESNO | MB_DEFBUTTON2 | + MB_ICONQUESTION); + if(r == IDNO) break; + } + NewProgram(); + strcpy(CurrentSaveFile, ""); + strcpy(CurrentCompileFile, ""); + GenerateIoListDontLoseSelection(); + RefreshScrollbars(); + UpdateMainWindowTitleBar(); + } else { + CHANGING_PROGRAM(NegateSelected()); + } + break; + + case 'A': + CHANGING_PROGRAM(MakeNormalSelected()); + break; + + case 'T': + CHANGING_PROGRAM(AddTimer(ELEM_RTO)); + break; + + case 'O': + if(GetAsyncKeyState(VK_CONTROL) & 0x8000) { + if(CheckSaveUserCancels()) break; + OpenDialog(); + } else { + CHANGING_PROGRAM(AddTimer(ELEM_TON)); + } + break; + + case 'F': + CHANGING_PROGRAM(AddTimer(ELEM_TOF)); + break; + + case 'U': + CHANGING_PROGRAM(AddCounter(ELEM_CTU)); + break; + + case 'I': + CHANGING_PROGRAM(AddCounter(ELEM_CTD)); + break; + + case 'J': + CHANGING_PROGRAM(AddCounter(ELEM_CTC)); + break; + + case 'M': + CHANGING_PROGRAM(AddMove()); + break; + + case 'P': + CHANGING_PROGRAM(AddReadAdc()); + break; + + case VK_OEM_PLUS: + if(GetAsyncKeyState(VK_SHIFT) & 0x8000) { + CHANGING_PROGRAM(AddMath(ELEM_ADD)); + } else { + CHANGING_PROGRAM(AddCmp(ELEM_EQU)); + } + break; + + case VK_OEM_MINUS: + if(GetAsyncKeyState(VK_SHIFT) & 0x8000) { + } else { + CHANGING_PROGRAM(AddMath(ELEM_SUB)); + } + break; + + case '8': + if(GetAsyncKeyState(VK_SHIFT) & 0x8000) { + CHANGING_PROGRAM(AddMath(ELEM_MUL)); + } + break; + + case 'D': + CHANGING_PROGRAM(AddMath(ELEM_DIV)); + break; + + case VK_OEM_PERIOD: + if(GetAsyncKeyState(VK_SHIFT) & 0x8000) { + CHANGING_PROGRAM(AddCmp(ELEM_GRT)); + } else { + CHANGING_PROGRAM(AddCmp(ELEM_GEQ)); + } + break; + + case VK_OEM_COMMA: + if(GetAsyncKeyState(VK_SHIFT) & 0x8000) { + CHANGING_PROGRAM(AddCmp(ELEM_LES)); + } else { + CHANGING_PROGRAM(AddCmp(ELEM_LEQ)); + } + break; + + case 'V': + if(GetAsyncKeyState(VK_SHIFT) & 0x8000) { + CHANGING_PROGRAM(InsertRung(TRUE)); + } + break; + + case '6': + if(GetAsyncKeyState(VK_SHIFT) & 0x8000) { + CHANGING_PROGRAM(InsertRung(FALSE)); + } + break; + + case 'Z': + if(GetAsyncKeyState(VK_CONTROL) & 0x8000) { + UndoUndo(); + } + break; + + case 'Y': + if(GetAsyncKeyState(VK_CONTROL) & 0x8000) { + UndoRedo(); + } + break; + + default: + break; + } + if(wParam != VK_SHIFT && wParam != VK_CONTROL) { + InvalidateRect(MainWindow, NULL, FALSE); + } + break; + } + + case WM_LBUTTONDBLCLK: { + int x = LOWORD(lParam); + int y = HIWORD(lParam); + if(InSimulationMode) { + EditElementMouseDoubleclick(x, y); + } else { + CHANGING_PROGRAM(EditElementMouseDoubleclick(x, y)); + } + InvalidateRect(MainWindow, NULL, FALSE); + break; + } + + case WM_LBUTTONDOWN: { + int x = LOWORD(lParam); + int y = HIWORD(lParam); + if((y > (IoListTop - 9)) && (y < (IoListTop + 3))) { + POINT pt; + pt.x = x; pt.y = y; + ClientToScreen(MainWindow, &pt); + MouseY = pt.y; + MouseHookHandle = SetWindowsHookEx(WH_MOUSE_LL, + (HOOKPROC)MouseHook, Instance, 0); + } + if(!InSimulationMode) MoveCursorMouseClick(x, y); + + SetFocus(MainWindow); + InvalidateRect(MainWindow, NULL, FALSE); + break; + } + case WM_MOUSEMOVE: { + int x = LOWORD(lParam); + int y = HIWORD(lParam); + + if((y > (IoListTop - 9)) && (y < (IoListTop + 3))) { + SetCursor(LoadCursor(NULL, IDC_SIZENS)); + } else { + SetCursor(LoadCursor(NULL, IDC_ARROW)); + } + + break; + } + case WM_MOUSEWHEEL: { + if((GET_WHEEL_DELTA_WPARAM(wParam)) > 0) { + VscrollProc(SB_LINEUP); + } else { + VscrollProc(SB_LINEDOWN); + } + break; + } + + case WM_SIZE: + MainWindowResized(); + break; + + case WM_NOTIFY: { + NMHDR *h = (NMHDR *)lParam; + if(h->hwndFrom == IoList) { + IoListProc(h); + } + return 0; + } + case WM_VSCROLL: + VscrollProc(wParam); + break; + + case WM_HSCROLL: + HscrollProc(wParam); + break; + + case WM_COMMAND: + ProcessMenu(LOWORD(wParam)); + InvalidateRect(MainWindow, NULL, FALSE); + break; + + case WM_CLOSE: + case WM_DESTROY: + if(CheckSaveUserCancels()) break; + + PostQuitMessage(0); + return 1; + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + + return 1; +} + +//----------------------------------------------------------------------------- +// Create our window class; nothing exciting. +//----------------------------------------------------------------------------- +static BOOL MakeWindowClass() +{ + WNDCLASSEX wc; + memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof(wc); + + wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC | + CS_DBLCLKS; + wc.lpfnWndProc = (WNDPROC)MainWndProc; + wc.hInstance = Instance; + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wc.lpszClassName = "LDmicro"; + wc.lpszMenuName = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hIcon = (HICON)LoadImage(Instance, MAKEINTRESOURCE(4000), + IMAGE_ICON, 32, 32, 0); + wc.hIconSm = (HICON)LoadImage(Instance, MAKEINTRESOURCE(4000), + IMAGE_ICON, 16, 16, 0); + + return RegisterClassEx(&wc); +} + +//----------------------------------------------------------------------------- +// Entry point into the program. +//----------------------------------------------------------------------------- +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, INT nCmdShow) +{ + Instance = hInstance; + + MainHeap = HeapCreate(0, 1024*64, 0); + + MakeWindowClass(); + MakeDialogBoxClass(); + MakeAdvancedDialogClass(); + MakeAdvancedWorkspaceClass(); + MakeComponentListClass(); + MakeSmplDialogClass(); + MakeNamingListClass(); + HMENU top = MakeMainWindowMenus(); + + MainWindow = CreateWindowEx(0, "LDmicro", "", + WS_OVERLAPPED | WS_THICKFRAME | WS_CLIPCHILDREN | WS_MAXIMIZEBOX | + WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX, + 10, 10, 800, 600, NULL, top, Instance, NULL); + ThawWindowPos(MainWindow); + IoListHeight = 100; + ThawDWORD(IoListHeight); + + InitCommonControls(); + InitForDrawing(); + + MakeMainWindowControls(); + MainWindowResized(); + NewProgram(); + strcpy(CurrentSaveFile, ""); + + // Check if we're running in non-interactive mode; in that case we should + // load the file, compile, and exit. + while(isspace(*lpCmdLine)) { + lpCmdLine++; + } + if(memcmp(lpCmdLine, "/c", 2)==0) { + RunningInBatchMode = TRUE; + + char *err = + "Bad command line arguments: run 'ldmicro /c src.ld dest.hex'"; + + char *source = lpCmdLine + 2; + while(isspace(*source)) { + source++; + } + if(*source == '\0') { Error(err); exit(-1); } + char *dest = source; + while(!isspace(*dest) && *dest) { + dest++; + } + if(*dest == '\0') { Error(err); exit(-1); } + *dest = '\0'; dest++; + while(isspace(*dest)) { + dest++; + } + if(*dest == '\0') { Error(err); exit(-1); } + if(!LoadProjectFromFile(source)) { + Error("Couldn't open '%s', running non-interactively.", source); + exit(-1); + } + strcpy(CurrentCompileFile, dest); + GenerateIoList(-1); + CompileProgram(FALSE); + exit(0); + } + + // We are running interactively, or we would already have exited. We + // can therefore show the window now, and otherwise set up the GUI. + + ShowWindow(MainWindow, SW_SHOW); + SetTimer(MainWindow, TIMER_BLINK_CURSOR, 800, BlinkCursor); + + if(strlen(lpCmdLine) > 0) { + char line[MAX_PATH]; + if(*lpCmdLine == '"') { + strcpy(line, lpCmdLine+1); + } else { + strcpy(line, lpCmdLine); + } + if(strchr(line, '"')) *strchr(line, '"') = '\0'; + + char *s; + GetFullPathName(line, sizeof(CurrentSaveFile), CurrentSaveFile, &s); + if(!LoadProjectFromFile(CurrentSaveFile)) { + NewProgram(); + Error(_("Couldn't open '%s'."), CurrentSaveFile); + CurrentSaveFile[0] = '\0'; + } + UndoFlush(); + } + + GenerateIoListDontLoseSelection(); + RefreshScrollbars(); + UpdateMainWindowTitleBar(); + + MSG msg; + DWORD ret; + while(ret = GetMessage(&msg, NULL, 0, 0)) { + if(msg.hwnd == IoList && msg.message == WM_KEYDOWN) { + if(msg.wParam == VK_TAB) { + SetFocus(MainWindow); + continue; + } + } + if(msg.message == WM_KEYDOWN && msg.wParam != VK_UP && + msg.wParam != VK_DOWN && msg.wParam != VK_RETURN && msg.wParam + != VK_SHIFT) + { + if(msg.hwnd == IoList) { + msg.hwnd = MainWindow; + SetFocus(MainWindow); + } + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } + FreezeWindowPos(MainWindow); + FreezeDWORD(IoListHeight); + + return 0; +} |