OpenPLC-Ladder-Editor/ldmicro-rel2.2/ldmicro/maincontrols.cpp

750 lines
29 KiB
C++

//-----------------------------------------------------------------------------
// 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/>.
//------
//
// Common controls in the main window. The main window consists of the drawing
// area, where the ladder diagram is displayed, plus various controls for
// scrolling, I/O list, menus.
// Jonathan Westhues, Nov 2004
//-----------------------------------------------------------------------------
#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <stdio.h>
#include <stdlib.h>
#include "ldmicro.h"
// scrollbars for the ladder logic area
static HWND HorizScrollBar;
static HWND VertScrollBar;
int ScrollWidth;
int ScrollHeight;
BOOL NeedHoriz;
// status bar at the bottom of the screen, to display settings
static HWND StatusBar;
// have to get back to the menus to gray/ungray, check/uncheck things
static HMENU FileMenu;
static HMENU EditMenu;
static HMENU InstructionMenu;
static HMENU ProcessorMenu;
static HMENU SimulateMenu;
static HMENU TopMenu;
// listview used to maintain the list of I/O pins with symbolic names, plus
// the internal relay too
HWND IoList;
static int IoListSelectionPoint;
static BOOL IoListOutOfSync;
int IoListHeight;
int IoListTop;
// whether the simulation is running in real time
static BOOL RealTimeSimulationRunning;
//-----------------------------------------------------------------------------
// Create the standard Windows controls used in the main window: a Listview
// for the I/O list, and a status bar for settings.
//-----------------------------------------------------------------------------
void MakeMainWindowControls(void)
{
LVCOLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
#define LV_ADD_COLUMN(hWnd, i, w, s) do { \
lvc.iSubItem = i; \
lvc.pszText = s; \
lvc.iOrder = 0; \
lvc.cx = w; \
ListView_InsertColumn(hWnd, i, &lvc); \
} while(0)
IoList = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "", WS_CHILD |
LVS_REPORT | LVS_NOSORTHEADER | LVS_SHOWSELALWAYS | WS_TABSTOP |
LVS_SINGLESEL | WS_CLIPSIBLINGS,
12, 25, 300, 300, MainWindow, NULL, Instance, NULL);
ListView_SetExtendedListViewStyle(IoList, LVS_EX_FULLROWSELECT);
int typeWidth = 85;
int pinWidth = 100;
int portWidth = 90;
LV_ADD_COLUMN(IoList, LV_IO_NAME, 250, _("Name"));
LV_ADD_COLUMN(IoList, LV_IO_TYPE, typeWidth, _("Type"));
LV_ADD_COLUMN(IoList, LV_IO_STATE, 100, _("State"));
//LV_ADD_COLUMN(IoList, LV_IO_PIN, pinWidth, _("Pin on Processor"));
//LV_ADD_COLUMN(IoList, LV_IO_PORT, portWidth, _("MCU Port"));
HorizScrollBar = CreateWindowEx(0, WC_SCROLLBAR, "", WS_CHILD |
SBS_HORZ | SBS_BOTTOMALIGN | WS_VISIBLE | WS_CLIPSIBLINGS,
100, 100, 100, 100, MainWindow, NULL, Instance, NULL);
VertScrollBar = CreateWindowEx(0, WC_SCROLLBAR, "", WS_CHILD |
SBS_VERT | SBS_LEFTALIGN | WS_VISIBLE | WS_CLIPSIBLINGS,
200, 100, 100, 100, MainWindow, NULL, Instance, NULL);
RECT scroll;
GetWindowRect(HorizScrollBar, &scroll);
ScrollHeight = scroll.bottom - scroll.top;
GetWindowRect(VertScrollBar, &scroll);
ScrollWidth = scroll.right - scroll.left;
StatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
"LDmicro started", MainWindow, 0);
int edges[] = { 250, 370, -1 };
SendMessage(StatusBar, SB_SETPARTS, 3, (LPARAM)edges);
ShowWindow(IoList, SW_SHOW);
}
//-----------------------------------------------------------------------------
// Set up the title bar text for the main window; indicate whether we are in
// simulation or editing mode, and indicate the filename.
//-----------------------------------------------------------------------------
void UpdateMainWindowTitleBar(void)
{
char line[MAX_PATH+100];
if(InSimulationMode) {
if(RealTimeSimulationRunning) {
strcpy(line, _("OpenPLC Ladder - Simulation (Running)"));
} else {
strcpy(line, _("OpenPLC Ladder - Simulation (Stopped)"));
}
} else {
strcpy(line, _("OpenPLC Ladder - Program Editor"));
}
if(strlen(CurrentSaveFile) > 0) {
sprintf(line+strlen(line), " - %s", CurrentSaveFile);
} else {
strcat(line, _(" - (not yet saved)"));
}
SetWindowText(MainWindow, line);
}
//-----------------------------------------------------------------------------
// Set the enabled state of the logic menu items to reflect where we are on
// the schematic (e.g. can't insert two coils in series).
//-----------------------------------------------------------------------------
void SetMenusEnabled(BOOL canNegate, BOOL canNormal, BOOL canResetOnly,
BOOL canSetOnly, BOOL canDelete, BOOL canInsertEnd, BOOL canInsertOther,
BOOL canPushDown, BOOL canPushUp, BOOL canInsertComment)
{
EnableMenuItem(EditMenu, MNU_PUSH_RUNG_UP,
canPushUp ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(EditMenu, MNU_PUSH_RUNG_DOWN,
canPushDown ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(EditMenu, MNU_DELETE_RUNG,
(Prog.numRungs > 1) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(InstructionMenu, MNU_NEGATE,
canNegate ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(InstructionMenu, MNU_MAKE_NORMAL,
canNormal ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(InstructionMenu, MNU_MAKE_RESET_ONLY,
canResetOnly ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(InstructionMenu, MNU_MAKE_SET_ONLY,
canSetOnly ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(InstructionMenu, MNU_INSERT_COMMENT,
canInsertComment ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(EditMenu, MNU_DELETE_ELEMENT,
canDelete ? MF_ENABLED : MF_GRAYED);
int t;
t = canInsertEnd ? MF_ENABLED : MF_GRAYED;
EnableMenuItem(InstructionMenu, MNU_INSERT_COIL, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_RES, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_MOV, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_ADD, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_SUB, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_MUL, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_DIV, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_CTC, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_PERSIST, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_READ_ADC, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_SET_PWM, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_MASTER_RLY, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_SHIFT_REG, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_LUT, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_PWL, t);
t = canInsertOther ? MF_ENABLED : MF_GRAYED;
EnableMenuItem(InstructionMenu, MNU_INSERT_TON, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_TOF, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_OSR, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_OSF, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_RTO, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_CONTACTS, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_CTU, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_CTD, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_EQU, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_NEQ, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_GRT, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_GEQ, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_LES, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_LEQ, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_SHORT, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_OPEN, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_UART_SEND, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_UART_RECV, t);
EnableMenuItem(InstructionMenu, MNU_INSERT_FMTD_STR, t);
}
//-----------------------------------------------------------------------------
// Set the enabled state of the undo/redo menus.
//-----------------------------------------------------------------------------
void SetUndoEnabled(BOOL undoEnabled, BOOL redoEnabled)
{
EnableMenuItem(EditMenu, MNU_UNDO, undoEnabled ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(EditMenu, MNU_REDO, redoEnabled ? MF_ENABLED : MF_GRAYED);
}
//-----------------------------------------------------------------------------
// Create the top-level menu bar for the main window. Mostly static, but we
// create the "select processor" menu from the list in mcutable.h dynamically.
//-----------------------------------------------------------------------------
HMENU MakeMainWindowMenus(void)
{
HMENU compile, help; //settings, compile, help;
int i;
FileMenu = CreatePopupMenu();
AppendMenu(FileMenu, MF_STRING, MNU_NEW, _("&New\tCtrl+N"));
AppendMenu(FileMenu, MF_STRING, MNU_OPEN, _("&Open...\tCtrl+O"));
AppendMenu(FileMenu, MF_STRING, MNU_SAVE, _("&Save\tCtrl+S"));
AppendMenu(FileMenu, MF_STRING, MNU_SAVE_AS,_("Save &As..."));
AppendMenu(FileMenu, MF_SEPARATOR,0, "");
AppendMenu(FileMenu, MF_STRING, MNU_EXPORT,
_("&Export As Text...\tCtrl+E"));
AppendMenu(FileMenu, MF_SEPARATOR,0, "");
AppendMenu(FileMenu, MF_STRING, MNU_EXIT, _("E&xit"));
EditMenu = CreatePopupMenu();
AppendMenu(EditMenu, MF_STRING, MNU_UNDO, _("&Undo\tCtrl+Z"));
AppendMenu(EditMenu, MF_STRING, MNU_REDO, _("&Redo\tCtrl+Y"));
AppendMenu(EditMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(EditMenu, MF_STRING, MNU_INSERT_RUNG_BEFORE,
_("Insert Rung &Before\tShift+6"));
AppendMenu(EditMenu, MF_STRING, MNU_INSERT_RUNG_AFTER,
_("Insert Rung &After\tShift+V"));
AppendMenu(EditMenu, MF_STRING, MNU_PUSH_RUNG_UP,
_("Move Selected Rung &Up\tShift+Up"));
AppendMenu(EditMenu, MF_STRING, MNU_PUSH_RUNG_DOWN,
_("Move Selected Rung &Down\tShift+Down"));
AppendMenu(EditMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(EditMenu, MF_STRING, MNU_DELETE_ELEMENT,
_("&Delete Selected Element\tDel"));
AppendMenu(EditMenu, MF_STRING, MNU_DELETE_RUNG,
_("D&elete Rung\tShift+Del"));
InstructionMenu = CreatePopupMenu();
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_COMMENT,
_("Insert Co&mment\t;"));
AppendMenu(InstructionMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_CONTACTS,
_("Insert &Contacts\tC"));
AppendMenu(InstructionMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_OSR,
_("Insert OSR (One Shot Rising)\t&/"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_OSF,
_("Insert OSF (One Shot Falling)\t&\\"));
AppendMenu(InstructionMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_TON,
_("Insert T&ON (Delayed Turn On)\tO"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_TOF,
_("Insert TO&F (Delayed Turn Off)\tF"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_RTO,
_("Insert R&TO (Retentive Delayed Turn On)\tT"));
AppendMenu(InstructionMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_CTU,
_("Insert CT&U (Count Up)\tU"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_CTD,
_("Insert CT&D (Count Down)\tI"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_CTC,
_("Insert CT&C (Count Circular)\tJ"));
AppendMenu(InstructionMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_EQU,
_("Insert EQU (Compare for Equals)\t="));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_NEQ,
_("Insert NEQ (Compare for Not Equals)"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_GRT,
_("Insert GRT (Compare for Greater Than)\t>"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_GEQ,
_("Insert GEQ (Compare for Greater Than or Equal)\t."));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_LES,
_("Insert LES (Compare for Less Than)\t<"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_LEQ,
_("Insert LEQ (Compare for Less Than or Equal)\t,"));
AppendMenu(InstructionMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_OPEN,
_("Insert Open-Circuit"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_SHORT,
_("Insert Short-Circuit"));
//AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_MASTER_RLY,
// _("Insert Master Control Relay"));
AppendMenu(InstructionMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_COIL,
_("Insert Coi&l\tL"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_RES,
_("Insert R&ES (Counter/RTO Reset)\tE"));
AppendMenu(InstructionMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_MOV,
_("Insert MOV (Move)\tM"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_ADD,
_("Insert ADD (16-bit Integer Add)\t+"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_SUB,
_("Insert SUB (16-bit Integer Subtract)\t-"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_MUL,
_("Insert MUL (16-bit Integer Multiply)\t*"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_DIV,
_("Insert DIV (16-bit Integer Divide)\tD"));
/*AppendMenu(InstructionMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_SHIFT_REG,
_("Insert Shift Register"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_LUT,
_("Insert Look-Up Table"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_PWL,
_("Insert Piecewise Linear"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_FMTD_STR,
_("Insert Formatted String Over UART"));
AppendMenu(InstructionMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_UART_SEND,
_("Insert &UART Send"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_UART_RECV,
_("Insert &UART Receive"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_SET_PWM,
_("Insert Set PWM Output"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_READ_ADC,
_("Insert A/D Converter Read\tP"));
AppendMenu(InstructionMenu, MF_STRING, MNU_INSERT_PERSIST,
_("Insert Make Persistent"));
*/
AppendMenu(InstructionMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(InstructionMenu, MF_STRING, MNU_MAKE_NORMAL,
_("Make Norm&al\tA"));
AppendMenu(InstructionMenu, MF_STRING, MNU_NEGATE,
_("Make &Negated\tN"));
AppendMenu(InstructionMenu, MF_STRING, MNU_MAKE_SET_ONLY,
_("Make &Set-Only\tS"));
AppendMenu(InstructionMenu, MF_STRING, MNU_MAKE_RESET_ONLY,
_("Make &Reset-Only\tR"));
/*
settings = CreatePopupMenu();
AppendMenu(settings, MF_STRING, MNU_MCU_SETTINGS, _("&MCU Parameters..."));
ProcessorMenu = CreatePopupMenu();
for(i = 0; i < NUM_SUPPORTED_MCUS; i++) {
AppendMenu(ProcessorMenu, MF_STRING, MNU_PROCESSOR_0+i,
SupportedMcus[i].mcuName);
}
AppendMenu(ProcessorMenu, MF_STRING, MNU_PROCESSOR_0+i,
_("(no microcontroller)"));
AppendMenu(settings, MF_STRING | MF_POPUP, (UINT_PTR)ProcessorMenu,
_("&Microcontroller"));
*/
SimulateMenu = CreatePopupMenu();
AppendMenu(SimulateMenu, MF_STRING, MNU_SIMULATION_MODE,
_("Si&mulation Mode\tCtrl+M"));
AppendMenu(SimulateMenu, MF_STRING | MF_GRAYED, MNU_START_SIMULATION,
_("Start &Real-Time Simulation\tCtrl+R"));
AppendMenu(SimulateMenu, MF_STRING | MF_GRAYED, MNU_STOP_SIMULATION,
_("&Halt Simulation\tCtrl+H"));
AppendMenu(SimulateMenu, MF_STRING | MF_GRAYED, MNU_SINGLE_CYCLE,
_("Single &Cycle\tSpace"));
compile = CreatePopupMenu();
AppendMenu(compile, MF_STRING, MNU_COMPILE, _("&Compile\tF5"));
AppendMenu(compile, MF_STRING, MNU_COMPILE_AS, _("Compile &As..."));
help = CreatePopupMenu();
AppendMenu(help, MF_STRING, MNU_MANUAL, _("&Manual...\tF1"));
AppendMenu(help, MF_STRING, MNU_ABOUT, _("&About..."));
TopMenu = CreateMenu();
AppendMenu(TopMenu, MF_STRING | MF_POPUP, (UINT_PTR)FileMenu, _("&File"));
AppendMenu(TopMenu, MF_STRING | MF_POPUP, (UINT_PTR)EditMenu, _("&Edit"));
/*
AppendMenu(TopMenu, MF_STRING | MF_POPUP, (UINT_PTR)settings,
_("&Settings"));
*/
AppendMenu(TopMenu, MF_STRING | MF_POPUP, (UINT_PTR)InstructionMenu,
_("&Instruction"));
AppendMenu(TopMenu, MF_STRING | MF_POPUP, (UINT_PTR)SimulateMenu,
_("Si&mulate"));
AppendMenu(TopMenu, MF_STRING | MF_POPUP, (UINT_PTR)compile,
_("&Compile"));
AppendMenu(TopMenu, MF_STRING | MF_POPUP, (UINT_PTR)help, _("&Help"));
return TopMenu;
}
//-----------------------------------------------------------------------------
// Adjust the size and visibility of the scrollbars as necessary, either due
// to a change in the size of the program or a change in the size of the
// window.
//-----------------------------------------------------------------------------
void RefreshScrollbars(void)
{
SCROLLINFO vert, horiz;
SetUpScrollbars(&NeedHoriz, &horiz, &vert);
SetScrollInfo(HorizScrollBar, SB_CTL, &horiz, TRUE);
SetScrollInfo(VertScrollBar, SB_CTL, &vert, TRUE);
RECT main;
GetClientRect(MainWindow, &main);
if(NeedHoriz) {
MoveWindow(HorizScrollBar, 0, IoListTop - ScrollHeight - 2,
main.right - ScrollWidth - 2, ScrollHeight, TRUE);
ShowWindow(HorizScrollBar, SW_SHOW);
EnableWindow(HorizScrollBar, TRUE);
} else {
ShowWindow(HorizScrollBar, SW_HIDE);
}
MoveWindow(VertScrollBar, main.right - ScrollWidth - 2, 1, ScrollWidth,
NeedHoriz ? (IoListTop - ScrollHeight - 4) : (IoListTop - 3), TRUE);
MoveWindow(VertScrollBar, main.right - ScrollWidth - 2, 1, ScrollWidth,
NeedHoriz ? (IoListTop - ScrollHeight - 4) : (IoListTop - 3), TRUE);
InvalidateRect(MainWindow, NULL, FALSE);
}
//-----------------------------------------------------------------------------
// Respond to a WM_VSCROLL sent to the main window, presumably by the one and
// only vertical scrollbar that it has as a child.
//-----------------------------------------------------------------------------
void VscrollProc(WPARAM wParam)
{
int prevY = ScrollYOffset;
switch(LOWORD(wParam)) {
case SB_LINEUP:
case SB_PAGEUP:
if(ScrollYOffset > 0) {
ScrollYOffset--;
}
break;
case SB_LINEDOWN:
case SB_PAGEDOWN:
if(ScrollYOffset < ScrollYOffsetMax) {
ScrollYOffset++;
}
break;
case SB_TOP:
ScrollYOffset = 0;
break;
case SB_BOTTOM:
ScrollYOffset = ScrollYOffsetMax;
break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION:
ScrollYOffset = HIWORD(wParam);
break;
}
if(prevY != ScrollYOffset) {
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = ScrollYOffset;
SetScrollInfo(VertScrollBar, SB_CTL, &si, TRUE);
InvalidateRect(MainWindow, NULL, FALSE);
}
}
//-----------------------------------------------------------------------------
// Respond to a WM_HSCROLL sent to the main window, presumably by the one and
// only horizontal scrollbar that it has as a child.
//-----------------------------------------------------------------------------
void HscrollProc(WPARAM wParam)
{
int prevX = ScrollXOffset;
switch(LOWORD(wParam)) {
case SB_LINEUP:
ScrollXOffset -= FONT_WIDTH;
break;
case SB_PAGEUP:
ScrollXOffset -= POS_WIDTH*FONT_WIDTH;
break;
case SB_LINEDOWN:
ScrollXOffset += FONT_WIDTH;
break;
case SB_PAGEDOWN:
ScrollXOffset += POS_WIDTH*FONT_WIDTH;
break;
case SB_TOP:
ScrollXOffset = 0;
break;
case SB_BOTTOM:
ScrollXOffset = ScrollXOffsetMax;
break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION:
ScrollXOffset = HIWORD(wParam);
break;
}
if(ScrollXOffset > ScrollXOffsetMax) ScrollXOffset = ScrollXOffsetMax;
if(ScrollXOffset < 0) ScrollXOffset = 0;
if(prevX != ScrollXOffset) {
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = ScrollXOffset;
SetScrollInfo(HorizScrollBar, SB_CTL, &si, TRUE);
InvalidateRect(MainWindow, NULL, FALSE);
}
}
//-----------------------------------------------------------------------------
// Cause the status bar and the list view to be in sync with the actual data
// structures describing the settings and the I/O configuration. Listview
// does callbacks to get the strings it displays, so it just needs to know
// how many elements to populate.
//-----------------------------------------------------------------------------
void RefreshControlsToSettings(void)
{
int i;
if(!IoListOutOfSync) {
IoListSelectionPoint = -1;
for(i = 0; i < Prog.io.count; i++) {
if(ListView_GetItemState(IoList, i, LVIS_SELECTED)) {
IoListSelectionPoint = i;
break;
}
}
}
ListView_DeleteAllItems(IoList);
for(i = 0; i < Prog.io.count; i++) {
LVITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
lvi.state = lvi.stateMask = 0;
lvi.iItem = i;
lvi.iSubItem = 0;
lvi.pszText = LPSTR_TEXTCALLBACK;
lvi.lParam = i;
if(ListView_InsertItem(IoList, &lvi) < 0) oops();
}
if(IoListSelectionPoint >= 0) {
for(i = 0; i < Prog.io.count; i++) {
ListView_SetItemState(IoList, i, 0, LVIS_SELECTED);
}
ListView_SetItemState(IoList, IoListSelectionPoint, LVIS_SELECTED,
LVIS_SELECTED);
ListView_EnsureVisible(IoList, IoListSelectionPoint, FALSE);
}
IoListOutOfSync = FALSE;
if(Prog.mcu) {
SendMessage(StatusBar, SB_SETTEXT, 0, (LPARAM)Prog.mcu->mcuName);
} else {
SendMessage(StatusBar, SB_SETTEXT, 0, (LPARAM)_("no MCU selected"));
}
char buf[256];
sprintf(buf, _("cycle time %.2f ms"), (double)Prog.cycleTime/1000.0);
SendMessage(StatusBar, SB_SETTEXT, 1, (LPARAM)buf);
if(Prog.mcu && (Prog.mcu->whichIsa == ISA_ANSIC ||
Prog.mcu->whichIsa == ISA_INTERPRETED))
{
strcpy(buf, "");
} else {
sprintf(buf, _("processor clock %.4f MHz"),
(double)Prog.mcuClock/1000000.0);
}
SendMessage(StatusBar, SB_SETTEXT, 2, (LPARAM)buf);
for(i = 0; i < NUM_SUPPORTED_MCUS; i++) {
if(&SupportedMcus[i] == Prog.mcu) {
CheckMenuItem(ProcessorMenu, MNU_PROCESSOR_0+i, MF_CHECKED);
} else {
CheckMenuItem(ProcessorMenu, MNU_PROCESSOR_0+i, MF_UNCHECKED);
}
}
// `(no microcontroller)' setting
if(!Prog.mcu) {
CheckMenuItem(ProcessorMenu, MNU_PROCESSOR_0+i, MF_CHECKED);
} else {
CheckMenuItem(ProcessorMenu, MNU_PROCESSOR_0+i, MF_UNCHECKED);
}
}
//-----------------------------------------------------------------------------
// Regenerate the I/O list, keeping the selection in the same place if
// possible.
//-----------------------------------------------------------------------------
void GenerateIoListDontLoseSelection(void)
{
int i;
IoListSelectionPoint = -1;
for(i = 0; i < Prog.io.count; i++) {
if(ListView_GetItemState(IoList, i, LVIS_SELECTED)) {
IoListSelectionPoint = i;
break;
}
}
IoListSelectionPoint = GenerateIoList(IoListSelectionPoint);
// can't just update the listview index; if I/O has been added then the
// new selection point might be out of range till we refill it
IoListOutOfSync = TRUE;
RefreshControlsToSettings();
}
//-----------------------------------------------------------------------------
// Called when the main window has been resized. Adjust the size of the
// status bar and the listview to reflect the new window size.
//-----------------------------------------------------------------------------
void MainWindowResized(void)
{
RECT main;
GetClientRect(MainWindow, &main);
RECT status;
GetWindowRect(StatusBar, &status);
int statusHeight = status.bottom - status.top;
MoveWindow(StatusBar, 0, main.bottom - statusHeight, main.right,
statusHeight, TRUE);
// Make sure that the I/O list can't disappear entirely.
if(IoListHeight < 30) {
IoListHeight = 30;
}
IoListTop = main.bottom - IoListHeight - statusHeight;
// Make sure that we can't drag the top of the I/O list above the
// bottom of the menu bar, because it then becomes inaccessible.
if(IoListTop < 5) {
IoListHeight = main.bottom - statusHeight - 5;
IoListTop = main.bottom - IoListHeight - statusHeight;
}
MoveWindow(IoList, 0, IoListTop, main.right, IoListHeight, TRUE);
RefreshScrollbars();
InvalidateRect(MainWindow, NULL, FALSE);
}
//-----------------------------------------------------------------------------
// Toggle whether we are in simulation mode. A lot of options are only
// available in one mode or the other.
//-----------------------------------------------------------------------------
void ToggleSimulationMode(void)
{
InSimulationMode = !InSimulationMode;
if(InSimulationMode) {
EnableMenuItem(SimulateMenu, MNU_START_SIMULATION, MF_ENABLED);
EnableMenuItem(SimulateMenu, MNU_SINGLE_CYCLE, MF_ENABLED);
EnableMenuItem(FileMenu, MNU_OPEN, MF_GRAYED);
EnableMenuItem(FileMenu, MNU_SAVE, MF_GRAYED);
EnableMenuItem(FileMenu, MNU_SAVE_AS, MF_GRAYED);
EnableMenuItem(FileMenu, MNU_NEW, MF_GRAYED);
EnableMenuItem(FileMenu, MNU_EXPORT, MF_GRAYED);
EnableMenuItem(TopMenu, 1, MF_GRAYED | MF_BYPOSITION);
EnableMenuItem(TopMenu, 2, MF_GRAYED | MF_BYPOSITION);
//EnableMenuItem(TopMenu, 3, MF_GRAYED | MF_BYPOSITION);
EnableMenuItem(TopMenu, 4, MF_GRAYED | MF_BYPOSITION);
CheckMenuItem(SimulateMenu, MNU_SIMULATION_MODE, MF_CHECKED);
ClearSimulationData();
// Recheck InSimulationMode, because there could have been a compile
// error, which would have kicked us out of simulation mode.
if(UartFunctionUsed() && InSimulationMode) {
ShowUartSimulationWindow();
}
} else {
RealTimeSimulationRunning = FALSE;
KillTimer(MainWindow, TIMER_SIMULATE);
EnableMenuItem(SimulateMenu, MNU_START_SIMULATION, MF_GRAYED);
EnableMenuItem(SimulateMenu, MNU_STOP_SIMULATION, MF_GRAYED);
EnableMenuItem(SimulateMenu, MNU_SINGLE_CYCLE, MF_GRAYED);
EnableMenuItem(FileMenu, MNU_OPEN, MF_ENABLED);
EnableMenuItem(FileMenu, MNU_SAVE, MF_ENABLED);
EnableMenuItem(FileMenu, MNU_SAVE_AS, MF_ENABLED);
EnableMenuItem(FileMenu, MNU_NEW, MF_ENABLED);
EnableMenuItem(FileMenu, MNU_EXPORT, MF_ENABLED);
EnableMenuItem(TopMenu, 1, MF_ENABLED | MF_BYPOSITION);
EnableMenuItem(TopMenu, 2, MF_ENABLED | MF_BYPOSITION);
//EnableMenuItem(TopMenu, 3, MF_ENABLED | MF_BYPOSITION);
EnableMenuItem(TopMenu, 4, MF_ENABLED | MF_BYPOSITION);
CheckMenuItem(SimulateMenu, MNU_SIMULATION_MODE, MF_UNCHECKED);
if(UartFunctionUsed()) {
DestroyUartSimulationWindow();
}
}
UpdateMainWindowTitleBar();
DrawMenuBar(MainWindow);
InvalidateRect(MainWindow, NULL, FALSE);
ListView_RedrawItems(IoList, 0, Prog.io.count - 1);
}
//-----------------------------------------------------------------------------
// Start real-time simulation. Have to update the controls grayed status
// to reflect this.
//-----------------------------------------------------------------------------
void StartSimulation(void)
{
RealTimeSimulationRunning = TRUE;
EnableMenuItem(SimulateMenu, MNU_START_SIMULATION, MF_GRAYED);
EnableMenuItem(SimulateMenu, MNU_STOP_SIMULATION, MF_ENABLED);
StartSimulationTimer();
UpdateMainWindowTitleBar();
}
//-----------------------------------------------------------------------------
// Stop real-time simulation. Have to update the controls grayed status
// to reflect this.
//-----------------------------------------------------------------------------
void StopSimulation(void)
{
RealTimeSimulationRunning = FALSE;
EnableMenuItem(SimulateMenu, MNU_START_SIMULATION, MF_ENABLED);
EnableMenuItem(SimulateMenu, MNU_STOP_SIMULATION, MF_GRAYED);
KillTimer(MainWindow, TIMER_SIMULATE);
UpdateMainWindowTitleBar();
}