Полный исходный текст на языке C++ для библиотеки (DLL) с моделями блоков, иллюстрирующих прямой вызов функции одного блока. Библиотека содержит две модели:
- PlusMinus – модель блока, увеличивающего и уменьшающего свой выход по щелчкам мыши и нажатию клавиш (см. §2.12.1, теперь к блоку можно подключать поле ввода для точного задания значения);
- SimpleJoystick – модель блока, изображающего двухкоординатную рукоятку, которую пользователь может перемещать мышью (см. §2.12.2, теперь у блоку можно подключать поля ввода для точного задания координат рукоятки).
Изменения относительно предыдущих версий этих моделей выделены цветом.
// Прямой вызов функции блока #include <windows.h> #include <RdsDef.h> // Подготовка описаний сервисных функций #define RDS_SERV_FUNC_BODY GetInterfaceFunctions #include <RdsFunc.h> //========== Главная функция DLL ========== int WINAPI DllMain(HINSTANCE /*hinst*/, unsigned long reason, void* /*lpReserved*/) { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL { // Получение доступа к функциям RDS if(!GetInterfaceFunctions()) RDS_SERV_ERROR_MSGW // Сообщение: старая версия RDS } return 1; } //========= Конец главной функции =========// Глобальная переменная для уникального идентификатора функции // "Common.ControlValueChanged" int ControlValueChangedId=0;// Функция обратного вызова для "Common.ControlValueChanged" BOOL RDSCALL ControlValChanged_Callback( RDS_PPOINTDESCRIPTION /*src*/, RDS_PPOINTDESCRIPTION dest, LPVOID /*data*/) { // Вызов функции "Common.ControlValueChanged" у блока на другом // конце связи rdsCallBlockFunction(dest->Block,ControlValueChangedId,NULL); // Возвращаем TRUE – не останавливаем перебор блоков return TRUE; } //=========================================// Функция уведомления соседей об изменении значения void ControlValueChangedCall(BOOL *pCancelCall) { // В параметре pCancelCall передается указатель на флаг // блокировки вызова функции if(*pCancelCall) // Вызов заблокирован return; // Принудительно передаем данные выходов блока, модель которого // сейчас выполняется, по связям rdsActivateOutputConnections(NULL,TRUE); // Взводим флаг блокировки перед вызовом функций *pCancelCall=TRUE; // Перебираем все простые блоки, соединенные с выходами текущего // (для каждого будет вызвана ControlValChanged_Callback) rdsEnumConnectedBlocks(NULL, RDS_BEN_OUTPUTS | RDS_BEN_TRACELINKS, ControlValChanged_Callback, NULL); // Сбрасываем флаг блокировки после вызова функций *pCancelCall=FALSE; } //=========================================//==================================================================== // Уменьшающий/увеличивающий выход блок //==================================================================== //====== Класс личной области данных ====== class TPlusMinusData { public: int KeyPlus; // Клавиша увеличения DWORD ShiftsPlus; // и ее флаги int KeyMinus; // Клавиша уменьшения DWORD ShiftsMinus; // и ее флаги int Setup(void); // Функция настройки клавиш void SaveBin(void); // Сохранение параметров int LoadBin(void); // Загрузка параметров // Конструктор класса TPlusMinusData(void) { KeyPlus=ShiftsPlus=KeyMinus=ShiftsMinus=0;NoCall=FALSE; // Исходно флаг блокировки сброшен if(ControlValueChangedId==0) // Регистрация функции ControlValueChangedId= rdsRegisterFunction("Common.ControlValueChanged");}; }; //========================================= // Функция задания клавиш // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" int TPlusMinusData::Setup(void) { RDS_HOBJECT window; // Идентификатор вспомогательного объекта BOOL ok; // Пользователь нажал "OK" // Создание окна window=rdsFORMCreate(FALSE,-1,-1,"Плюс/минус"); // Добавление полей ввода rdsFORMAddEdit(window,0,1,RDS_FORMCTRL_HOTKEY, "Клавиша увеличения:",80); rdsFORMAddEdit(window,0,2,RDS_FORMCTRL_HOTKEY, "Клавиша уменьшения:",80); // Занесение исходных значений кодов клавиш в поля ввода rdsSetObjectInt(window,1,RDS_FORMVAL_VALUE,KeyPlus); rdsSetObjectInt(window,1,RDS_FORMVAL_HKSHIFTS,ShiftsPlus); rdsSetObjectInt(window,2,RDS_FORMVAL_VALUE,KeyMinus); rdsSetObjectInt(window,2,RDS_FORMVAL_HKSHIFTS,ShiftsMinus); // Открытие окна ok=rdsFORMShowModalEx(window,NULL); if(ok) { // Нажата кнопка OK - запись кодов клавиш в класс KeyPlus=rdsGetObjectInt(window,1,RDS_FORMVAL_VALUE); ShiftsPlus=rdsGetObjectInt(window,1,RDS_FORMVAL_HKSHIFTS); KeyMinus=rdsGetObjectInt(window,2,RDS_FORMVAL_VALUE); ShiftsMinus=rdsGetObjectInt(window,2,RDS_FORMVAL_HKSHIFTS); } // Уничтожение окна rdsDeleteObject(window); // Возвращаемое значение return ok?RDS_BFR_MODIFIED:RDS_BFR_DONE; } //========================================= // Сохранение параметров void TPlusMinusData::SaveBin(void) { BYTE tag; // Переменная для байта тега tag=1; // Тег 1 - клавиша увеличения rdsWriteBlockData(&tag,sizeof(tag)); rdsWriteBlockData(&KeyPlus,sizeof(KeyPlus)); rdsWriteBlockData(&ShiftsPlus,sizeof(ShiftsPlus)); tag=2; // Тег 2 - клавиша уменьшения rdsWriteBlockData(&tag,sizeof(tag)); rdsWriteBlockData(&KeyMinus,sizeof(KeyMinus)); rdsWriteBlockData(&ShiftsMinus,sizeof(ShiftsMinus)); tag=0; // Тег 0 - конец данных rdsWriteBlockData(&tag,sizeof(tag)); } //========================================= // Загрузка параметров int TPlusMinusData::LoadBin(void) { BYTE tag; for(;;) // Цикл до тех пор, пока данные не кончатся { // Читаем байт тега if(!rdsReadBlockData(&tag,sizeof(tag))) break; // Тег не считан - данные кончились // Анализируем считанный тег switch(tag) { case 0: // Конец данных блока return RDS_BFR_DONE; // Загрузка успешно завершена case 1: // Данные клавиши увеличения rdsReadBlockData(&KeyPlus,sizeof(KeyPlus)); rdsReadBlockData(&ShiftsPlus,sizeof(ShiftsPlus)); break; case 2: // Данные клавиши уменьшения rdsReadBlockData(&KeyMinus,sizeof(KeyMinus)); rdsReadBlockData(&ShiftsMinus,sizeof(ShiftsMinus)); break; default: // Неопознанный тег return RDS_BFR_ERROR; // Сообщаем RDS об ошибке } } // Данные кончились до тега 0 - сообщаем об ошибке return RDS_BFR_ERROR; } //========================================= // Увеличение/уменьшение значения по щелчку и клавишам extern "C" __declspec(dllexport) int RDSCALL PlusMinus(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { // Макроопределения для статических переменных #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define v (*((RDSINT32 *)(pStart+2*RDS_VSZ_S))) #define input (*((RDSINT32 *)(pStart+2*RDS_VSZ_S+RDS_VSZ_I))) // Вспомогательная — указатель на структуру события мыши RDS_PMOUSEDATA mouse; // Вспомогательная — указатель на структуру события клавиатуры RDS_PKEYDATA key; // Указатель на личную область данных блока,приведенный к // правильному типу TPlusMinusData *data=(TPlusMinusData*)(BlockData->BlockData); switch(CallMode) { // Проверка типа статических переменных case RDS_BFM_VARCHECK: return strcmp((char*)ExtParam,"{SSII}")? RDS_BFR_BADVARSMSG:RDS_BFR_DONE; // Реакция на нажатие кнопки мыши case RDS_BFM_MOUSEDOWN: // Приведение ExtParam к нужному типу mouse=(RDS_PMOUSEDATA)ExtParam; if(mouse->Button==RDS_MLEFTBUTTON) { // Нажата левая кнопка // Проверяем, есть ли у блока картинка (получаем описание блока) RDS_BLOCKDESCRIPTION descr; descr.servSize=sizeof(descr); rdsGetBlockDescription(BlockData->Block,&descr); if(descr.Flags & RDS_BDF_HASPICTURE) { // Картинка есть – определяем идентификатор // элемента под курсором int id=rdsGetMouseObjectId(mouse); v+=id; } else if(mouse->y<mouse->Top+mouse->Height/2) v++; // В верхней половине блока - увеличиваем else v--; // В нижней половине блока — уменьшаем // Взводим сигнал готовности Ready=1;// Принудительно передаем в соседние блоки ControlValueChangedCall(&(data->NoCall));} break; case RDS_BFM_INIT: // Инициализация BlockData->BlockData=new TPlusMinusData(); break; case RDS_BFM_CLEANUP:// Очистка данных delete data; break; case RDS_BFM_SETUP: // Настройка параметров return data->Setup(); case RDS_BFM_SAVEBIN:// Сохранение параметров data->SaveBin(); break; case RDS_BFM_LOADBIN:// Загрузка параметров return data->LoadBin(); // Реакция на нажатие клавиши case RDS_BFM_KEYDOWN: // Приведение ExtParam к нужному типу key=(RDS_PKEYDATA)ExtParam; // Сравнение нажатой клавиши с клавишами уменьшения // и увеличения if(key->KeyCode==data->KeyPlus && key->Shift==data->ShiftsPlus) { v++; Ready=1; } else if(key->KeyCode==data->KeyMinus && key->Shift==data->ShiftsMinus) { v--; Ready=1; }// Принудительно передаем в соседние блоки if(Ready) ControlValueChangedCall(&(data->NoCall));break;// Такт расчета case RDS_BFM_MODEL: if(v==input) // Новое значение равно старому { Ready=0; // Не передаем по связям break; } v=input; // Передаем значение входа на выход // Принудительно передаем в соседние блоки ControlValueChangedCall(&(data->NoCall)); break;// Реакция на вызов функции блока case RDS_BFM_FUNCTIONCALL: if(((RDS_PFUNCTIONCALLDATA)ExtParam)->Function== ControlValueChangedId) { // Вызвана"Common.ControlValueChanged" if(data->NoCall) // Взведен флаг блокировки break; if(v==input) // Новое значение равно старому - break; // передавать не нужно v=input; // Передаем значение входа на выход Ready=1; // Взводим сигнал готовности // Принудительно передаем в соседние блоки ControlValueChangedCall(&(data->NoCall)); } break;} return RDS_BFR_DONE; // Отмена макроопределений #undef input #undef v #undef Ready #undef Start #undef pStart } //========================================= //============================================================================ // Двухкоординатная рукоятка //============================================================================ //====== Класс личной области данных ====== class TSimpleJoystick { private: // Центр круга (рукоятки) до начала перетаскивания int OldHandleX,OldHandleY; // Координаты курсора на момент начала перетаскивания int OldMouseX,OldMouseY; // Флаги фиксации одной из координат BOOL LockX,LockY; // Идентификаторы добавленных пунктов меню RDS_MENUITEM MenuLockX,MenuLockY; public: // Настроечные параметры блока COLORREF BorderColor; // Цвет рамки блока COLORREF FieldColor; // Цвет прямоугольника COLORREF HandleColor; // Цвет круга в покое COLORREF MovingHandleColor; // Цвет круга при таскании COLORREF GrayedColor; // Цвет недоступной области int HandleSize; // Диаметр круга // Реакция на нажатие кнопки мыши int MouseDown(RDS_PMOUSEDATA mouse,double x,double y,DWORD *pFlags); // Реакция на перемещение курсора мыши void MouseMove(RDS_PMOUSEDATA mouse,double *px,double *py); // Рисование изображения блока void Draw(RDS_PDRAWDATA draw,double x,double y,BOOL moving); // Реакция на выбор добавленного пункта меню void MenuFunction(RDS_PMENUFUNCDATA MenuData); // Реакция на изменение размеров блока void Resizing(RDS_PRESIZEDATA ResData);// Ограничение входных значений void LimitInputValues(double *px_in,double *py_in,double x,double y);// Конструктор класса TSimpleJoystick(void) { BorderColor=0; // Черная рамка FieldColor=0xffffff; // Белое поле HandleColor=0xff0000; // Синий круг MovingHandleColor=0xff; // Красный при таскании HandleSize=20; // Диаметр круга GrayedColor=0x7f7f7f; // Серый LockX=LockY=FALSE; // Фиксация выключена // Создание пунктов меню // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" MenuLockX=rdsRegisterContextMenuItem("Фиксировать X",1,0); MenuLockY=rdsRegisterContextMenuItem("Фиксировать Y",2,0);NoCall=FALSE; // Исходно флаг блокировки сброшен if(ControlValueChangedId==0) // Регистрация функции ControlValueChangedId= rdsRegisterFunction("Common.ControlValueChanged");}; // Деструктор класса ~TSimpleJoystick() { // Уничтожение пунктов меню rdsUnregisterMenuItem(MenuLockX); rdsUnregisterMenuItem(MenuLockY); }; }; //========================================= // Рисование изображения блока void TSimpleJoystick::Draw(RDS_PDRAWDATA draw, double x,double y,BOOL moving) { int hx,hy,cx,cy; RECT r; int hR=HandleSize*draw->DoubleZoom/2; // Радиус круга-рукоятки // Если размер блока - нулевой, рисовать негде if(draw->Height==0 || draw->Width==0) return; // Рисование поля блока rdsXGSetPenStyle(0,PS_SOLID,1,BorderColor,R2_COPYPEN); rdsXGSetBrushStyle(0,RDS_GFS_SOLID,FieldColor); rdsXGRectangle(draw->Left,draw->Top, draw->Left+draw->Width,draw->Top+draw->Height); // Вычисление центра прямоугольника блока cx=draw->Left+draw->Width/2; cy=draw->Top+draw->Height/2; // Вычисление координат центра круга-рукоятки hx=cx+x*draw->Width/2; hy=cy-y*draw->Height/2; // Установка области отсечения r.left=draw->Left+1; r.top=draw->Top+1; r.right=draw->Left+draw->Width-1; r.bottom=draw->Top+draw->Height-1; rdsXGSetClipRect(&r); // Рисование ограничений if(LockX||LockY) // Фиксируется одна из координат { // Установка серого цвета заливки rdsXGSetBrushStyle(0,RDS_GFS_SOLID,GrayedColor); if(LockX) // Фиксируется X { rdsXGFillRect(r.left,r.top,hx-hR,r.bottom); // Слева rdsXGFillRect(hx+hR,r.top,r.right,r.bottom);// Справа } else // Фиксируется Y { rdsXGFillRect(r.left,r.top,r.right,hy-hR); // Сверху rdsXGFillRect(r.left,hy+hR,r.right,r.bottom);// Снизу } } // Линии перекрестия rdsXGMoveTo(cx,draw->Top); rdsXGLineTo(cx,draw->Top+draw->Height); rdsXGMoveTo(draw->Left,cy); rdsXGLineTo(draw->Left+draw->Width,cy); // Рисование круга (цвет зависит от параметра moving) rdsXGSetPenStyle(RDS_GFSTYLE,PS_NULL,0,0,0); rdsXGSetBrushStyle(0,RDS_GFS_SOLID, moving?MovingHandleColor:HandleColor); rdsXGEllipse(hx-hR,hy-hR,hx+hR+1,hy+hR+1); // Отмена отсечения rdsXGSetClipRect(NULL); } //========================================= // Реакция на нажатие кнопки мыши int TSimpleJoystick::MouseDown(RDS_PMOUSEDATA mouse, double x,double y,DWORD *pFlags) { int hx,hy,cx,cy, hR=HandleSize*mouse->DoubleZoom/2; // Радиус круга // Если размер - нулевой, реакция не имеет смысла if(mouse->Height==0 || mouse->Width==0) return RDS_BFR_DONE; // Если нажата не левая кнопка, перетаскивать не надо // Разрешаем в этом случае вызов контекстного меню блока if(mouse->Button!=RDS_MLEFTBUTTON) return RDS_BFR_SHOWMENU; // Координаты цента блока cx=mouse->Left+mouse->Width/2; cy=mouse->Top+mouse->Height/2; // Координаты центра круга-рукоятки hx=cx+x*mouse->Width/2; hy=cy-y*mouse->Height/2; // Проверка попадания курсора в круг if(abs(mouse->x-hx)<=hR && abs(mouse->y-hy)<=hR) { // Курсор попал в круг // Запоминаем координаты центр круга на момент // начала перетаскивания OldHandleX=hx; OldHandleY=hy; // Координаты курсора на начало перетаскивания OldMouseX=mouse->x; OldMouseY=mouse->y; // Взводим флаг захвата мыши *pFlags|=RDS_MOUSECAPTURE; } // Курсор не попал в рукоятку - захватывать мышь // и подготавливать перетаскивание не нужно return RDS_BFR_DONE; } //========================================= // Реакция на перемещение курсора мыши void TSimpleJoystick::MouseMove(RDS_PMOUSEDATA mouse, double *px,double *py) { int hx,hy,cx,cy; // Если размер - нулевой, реакция не имеет смысла if(mouse->Height==0 || mouse->Width==0) { *px=*py=0.0; return; } // Новые координаты центра рукоятки hx=OldHandleX+(mouse->x-OldMouseX); hy=OldHandleY+(mouse->y-OldMouseY); // Координаты центра блока cx=mouse->Left+mouse->Width/2; cy=mouse->Top+mouse->Height/2; // По новым координатам центра рукоятки вычисляем соответствующие // им вещественные значения выходов, ограничивая их // диапазоном [-1...1] if(!LockX) { *px=2.0*(hx-cx)/mouse->Width; if(*px>1.0) *px=1.0; else if(*px<-1.0) *px=-1.0; } if(!LockY) { *py=-2.0*(hy-cy)/mouse->Height; if(*py>1.0) *py=1.0; else if(*py<-1.0) *py=-1.0; } } //========================================= // Функция реакции на выбор одного из пунктов меню void TSimpleJoystick::MenuFunction(RDS_PMENUFUNCDATA MenuData) { switch(MenuData->Function) { case 1: // Выбран пункт "Фиксировать X" LockX=!LockX; // Переключаем флаг фиксации X LockY=FALSE; // Отключаем фиксацию Y break; case 2: // Выбран пункт "Фиксировать Y" LockY=!LockY; // Переключаем флаг фиксации Y LockX=FALSE; // Отключаем фиксацию X break; } // Установка галочек у пунктов меню в зависимости от // флагов фиксации координат rdsSetMenuItemOptions(MenuLockX,LockX?RDS_MENU_CHECKED:0); rdsSetMenuItemOptions(MenuLockY,LockY?RDS_MENU_CHECKED:0); } //========================================= // Реакция на изменение размеров блока void TSimpleJoystick::Resizing(RDS_PRESIZEDATA ResData) { if(ResData->HorzResize && (!ResData->VertResize)) // Перетаскивается левый или правый маркер ResData->newHeight=ResData->newWidth; else if((!ResData->HorzResize) && ResData->VertResize) // Перетаскивается верхний или нижний маркер ResData->newWidth=ResData->newHeight; else // Перетаскивается угловой маркер или размер задан точно { // Вычисляем среднее арифметическое int avg=(ResData->newWidth+ResData->newHeight)/2; // Присваиваем его ширине и высоте ResData->newWidth=ResData->newHeight=avg; } } //========================================= // Ограничение значений входов блока void TSimpleJoystick::LimitInputValues(double *px_in,double *py_in, double x,double y) { // px_in, py_in - указатели на входы блока // x, y - текущие значения выходов if(LockX) // Координата x зафиксирована *px_in=x; // Присваиваем входу x_in зафиксированное значение else // Ограничиваем x_in диапазоном [-1...1] { if(*px_in<-1.0) *px_in=-1.0; else if(*px_in>1.0) *px_in=1.0; } if(LockY) // Координата y зафиксирована *py_in=y; // Присваиваем входу y_in зафиксированное значение else // Ограничиваем y_in диапазоном [-1...1] { if(*py_in<-1.0) *py_in=-1.0; else if(*py_in>1.0) *py_in=1.0; } } //========================================= // Функция модели блока extern "C" __declspec(dllexport) int E SimpleJoystick(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { // Макроопределения для статических переменных #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define x (*((double *)(pStart+2*RDS_VSZ_S))) #define y (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D))) #define x_in (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D))) #define y_in (*((double *)(pStart+2*RDS_VSZ_S+3*RDS_VSZ_D))) #define x_in_ok (*((char *)(pStart+2*RDS_VSZ_S+4*RDS_VSZ_D))) #define y_in_ok (*((char *)(pStart+3*RDS_VSZ_S+4*RDS_VSZ_D))) // Вспомогательная переменная - указатель на личную область, // приведенный к правильному типу TSimpleJoystick *data=(TSimpleJoystick*)(BlockData->BlockData); switch(CallMode) { // Инициализация case RDS_BFM_INIT: BlockData->BlockData=new TSimpleJoystick(); break; // Очистка case RDS_BFM_CLEANUP: delete data; break; // Проверка допустимости типов переменных case RDS_BFM_VARCHECK: return strcmp((char*)ExtParam,"{SSDDDDSS}")? RDS_BFR_BADVARSMSG:RDS_BFR_DONE; // Нажатие кнопки мыши case RDS_BFM_MOUSEDOWN: return data->MouseDown((RDS_PMOUSEDATA)ExtParam,x,y, &(BlockData->Flags)); // Отпускание кнопки мыши case RDS_BFM_MOUSEUP: // Снятие захвата мыши RDS_SETFLAG(BlockData->Flags,RDS_MOUSECAPTURE,FALSE); break; // Перемещение курсора мыши case RDS_BFM_MOUSEMOVE: // Проверка: включен ли захват мыши if(BlockData->Flags & RDS_MOUSECAPTURE) // Включен { // Запоминаем старые значения double oldX=x,oldY=y; // Вызываем функцию реакции data->MouseMove((RDS_PMOUSEDATA)ExtParam,&x,&y); Ready=1; // Взводим сигнал готовности // Если значения изменились, передаем соседям if(oldX!=x || oldY!=y) ControlValueChangedCall(&(data->NoCall)); } break; // Рисование case RDS_BFM_DRAW: data->Draw((RDS_PDRAWDATA)ExtParam,x,y, BlockData->Flags & RDS_MOUSECAPTURE); break; // Выбор пользователем добавленного пункта меню case RDS_BFM_MENUFUNCTION: data->MenuFunction((RDS_PMENUFUNCDATA)ExtParam); break; // Изменение размеров блока case RDS_BFM_RESIZE: case RDS_BFM_RESIZING: data->Resizing((RDS_PRESIZEDATA)ExtParam); break;// Один такт расчета case RDS_BFM_MODEL: if(x_in_ok==0 && y_in_ok==0) { // Связанные сигналы не взведены Ready=0; // Сбрасываем сигнал готовности break; } if(x==x_in && y==y_in) { // На входах те же значения, что и на выходах Ready=x_in_ok=y_in_ok=0; // Сбрасываем все сигналы break; } // Ограничиваем входные значения data->LimitInputValues(&x_in,&y_in,x,y); // В зависимости от того, какой связанный сигнал взведен, // копируем соответствующие входы в выходы if(x_in_ok) x=x_in; if(y_in_ok) y=y_in; x_in_ok=y_in_ok=0; // Сбрасываем связанные сигналы // Передаем данные соединенным блокам ControlValueChangedCall(&(data->NoCall)); break;// Реакция на вызов функции case RDS_BFM_FUNCTIONCALL: if(((RDS_PFUNCTIONCALLDATA)ExtParam)->Function== ControlValueChangedId) { // Вызвана "Common.ControlValueChanged" if(data->NoCall) // Вызов заблокирован break; // Ограничиваем входные значения data->LimitInputValues(&x_in,&y_in,x,y); // Если связанные сигналы не взведены - не реагируем if(x_in_ok==0 && y_in_ok==0) break; // Если значения входов те же, что и у выходов - // не реагируем if(x_in==x && y_in==y) break; // Копируем входы в выходы согласно связанным сигналам if(x_in_ok) x=x_in; if(y_in_ok) y=y_in; x_in_ok=y_in_ok=0; // Сбрасываем связанные сигналы Ready=1; // Взводим сигнал готовности // Передаем данные соединенным блокам ControlValueChangedCall(&(data->NoCall)); } break;} return RDS_BFR_DONE; // Отмена макроопределений #undef y_in_ok #undef x_in_ok #undef y_in #undef x_in #undef y #undef x #undef Ready #undef Start #undef pStart } //=========================================