Навигация:
<< >> Оглавление Указатель
Текст С++

Полный исходный текст на языке C++ для библиотеки (DLL) с моделями блоков, реагирующих на действия пользователя в режиме редактирования. Библиотека содержит три модели:

Изменения относительно предыдущих версий этих моделей выделены цветом.

  // Реакция на действия пользователя в режиме редактирования
  #include <windows.h>
  #include <math.h>
  #include <RdsDef.h>
  // Подготовка описаний сервисных функций
  
  #include <RdsFunc.h>

  //==========  ==========
  int WINAPI ( /*hinst*/,
                           unsigned long reason,
                           void* /*lpReserved*/)
  { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL
      { // Получение доступа к функциям RDS
        if(!GetInterfaceFunctions())
           // Сообщение: старая версия RDS
      }
    return 1;
  }
  //========= Конец главной функции =========

  //=========================================================================
  // Реакция на ручную вставку блока
  //=========================================================================

  // Класс личной области данных блока
  class TOpenSysWinData
  { public:
       MenuItem; // Идентификатор созданного пункта меню
      // Настроечные параметры
      char *Caption;         // Название пункта
      int Key;               // Клавиша (или 0,если ее нет)
       KeyShifts;       // Состояние Ctrl, Alt и Shift

      // Создание пункта меню с заданными параметрами или
      // изменение параметров уже созданного пункта
      void RegisterMenuItem(void);

      int Setup(void);    // Открыть окно настройки
      void SaveBin(void); // Сохранить параметры
      int LoadBin(void);  // Загрузить параметры

      // Конструктор класса
      TOpenSysWinData(void)
        { Caption=NULL;
          Key=0; KeyShifts=0;
          MenuItem=NULL;
        };
      // Деструктор класса
      ~TOpenSysWinData()
        { // Освободить память, занятую строкой Caption
          (Caption);
          // Удалить пункт меню
          (MenuItem);
        };
  };
  //=========================================

  // Создание или модификация пункта меню
  // 
  // 
  // 
  void TOpenSysWinData::RegisterMenuItem(void)
  { // Вспомогательная переменная для заголовка пункта меню:
    // если Caption==NULL, пункт получит заголовок "Открыть окно"
    const char *text=Caption?Caption:"Открыть окно";
    // Флаги пункта меню: если клавиша определена (Key!=0),
    // пункт будет иметь "горячую клавишу"
     options=Key?:0;

    if(MenuItem) // Пункт уже есть - изменяем
      (MenuItem,text,options,Key,KeyShifts,0,0);
    else // Пункта еще нет - создаем
      MenuItem=(text,options,Key,KeyShifts,0,0);
  }
  //=========================================

  // Запись параметров блока
  void TOpenSysWinData::SaveBin(void)
  {  tag; // Переменная для байта тега
    int len=Caption?strlen(Caption):0; // Длина строки Caption

    tag=1; // Тег 1 – название пункта меню
    (&tag,sizeof(tag));
    (&len,sizeof(len)); // Длина строки
    if(len) // При ненулевой длине – запись самой строки
      (Caption,len);

    tag=2; // Тег 2 – "горячая клавиша"
    (&tag,sizeof(tag));
    (&Key,sizeof(Key));
    (&KeyShifts,sizeof(KeyShifts));

    tag=0; // Тег 0 – конец данных
    (&tag,sizeof(tag));
  }
  //=========================================

  // Загрузка параметров блока
  int TOpenSysWinData::LoadBin(void)
  {  tag; // Переменная для байта тега
    int len;

    // Прежде всего, освобождаем память, которую занимало старое
    // название пункта меню – сейчас загрузится новое
    (Caption);
    Caption=NULL;

    for(;;)
      { if(!(&tag,sizeof(tag)))
          break; // Тег не считан – данные неожиданно кончились
        switch(tag)
          { case 0: // Конец данных
              RegisterMenuItem(); // Создаем или изменяем пункт меню
              return ;
            case 1: // Название пункта
              (&len,sizeof(len)); // Читаем длину
              if(len) // Длина ненулевая – читаем len байтов строки
                { // Отводим место с учетом нуля в конце строки
                  Caption=(char*)(len+1);
                  (Caption,len); // Читаем строку
                  Caption[len]=0; // Дописываем нулевой байт в конец
                }
              break;
            case 2: // Данные "горячей клавиши"
              (&Key,sizeof(Key));
              (&KeyShifts,sizeof(KeyShifts));
              break;
            default: // Тег не опознан – ошибка
              return RDS_BFR_ERROR;
          }
      }
    // Вышли из цикла из-за неожиданного конца данных блока - ошибка
    return RDS_BFR_ERROR;
  }
  //=========================================

  // Настройка параметров блока
  // 
  // 
  // 
  int TOpenSysWinData::Setup(void)
  {  window; // Идентификатор объекта-окна
     ok;            // Пользователь нажал "OK"
    // Создание окна
    window=(FALSE,-1,-1,"Открытие окна");
    // Поле ввода для строки названия
    (window,0,1,,
        "Текст пункта меню:",200);
    (window,1,,Caption);
    // Поле ввода для "горячей клавиши"
    (window,0,2,,
        "Клавиша:",150);
    (window,2,,Key);
    (window,2,,KeyShifts);
    // Открытие окна
    ok=(window,NULL);
    if(ok)
      { // Нажата кнопка OK – запись параметров в блок
        (Caption); // Уничтожение старой строки
        // Создание динамической копии введенной строки
        Caption=((window,1,
            ));
        // Чтение параметров клавиши
        Key=(window,2,);
        KeyShifts=(window,2,);
        // Создание пункта меню на основе изменившихся параметров
        RegisterMenuItem();
      }
    // Уничтожение окна
    (window);
    // Возвращаемое значение
    return ok?:;
  }
  //=========================================

  // Блок, открывающий окно родительской подсистемы
  extern "C" __declspec(dllexport)
    int  OpenSysWin(int CallMode,
                       BlockData,
                       ExtParam)
  { // Указатель на личную область данных блока,приведенный к
    // правильному типу
    TOpenSysWinData *data=(TOpenSysWinData*)(BlockData->BlockData);
    switch(CallMode)
      { case : // Инициализация
          BlockData->BlockData=data=new TOpenSysWinData();
          break;
        case : // Очистка
          delete data;
          break;
        case : // Настройка
          return data->Setup();
        case : // Сохранение параметров
          data->SaveBin();
          break;
        case : // Загрузка параметров
          return data->LoadBin();
        case :// Выбор пункта меню
          (BlockData->Parent);
          break;

case : // Добавление блока пользователем if( (()ExtParam)->Single ) { if(data->Setup()) // Параметры изменены (TRUE);// Взвести флаг изменений } break;
} return ; } //========================================= //========================================================================= // Реакция на удаление блока //========================================================================= //=========== Блок управления ============= // Структура личной области данных блока typedef struct { // Указатель на структуру подписки на скорость VLink; // Указатель на структуру подписки на направление ALink; } TestBlkMoveSetterData; //=========================================
// Функция обратного вызова для подсчета подписчиков // динамической переменной DynVarUsersCountEnum( /*block*/, /*link*/, ptr) { // Приводим ptr к типу "указатель на целое" int *pCount=(int*)ptr; (*pCount)++; // Увеличиваем счетчик return TRUE; } //=========================================
// Подсчет числа подписчиков на динамическую переменную int CountDynVarUsers( link) { int count=0; // Перебрать всех подписчиков переменной link (link,DynVarUsersCountEnum,&count); return count; } //=========================================
// Модель блока управления extern "C" __declspec(dllexport) int TestBlkMoveSetter(int CallMode, BlockData, ExtParam) { // #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define Speed (*((double *)(pStart+2*RDS_VSZ_S))) #define Angle (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D))) // Вспомогательная переменная – указатель на личную область // данных блока, приведенный к правильному типу TestBlkMoveSetterData *privdata; switch(CallMode) { // Инициализация блока case : // Отведение памяти под личную область данных privdata=(TestBlkMoveSetterData*) malloc(sizeof(TestBlkMoveSetterData)); BlockData->BlockData=privdata; // Создание переменной для передачи скорости privdata->VLink=( , // В родительской "BlkMove_Speed",// Имя переменной "D", // Тип double TRUE, // Запрет удаления NULL); // Без нач.значения // Создание переменной для передачи направления privdata->ALink=( , "BlkMove_Angle", "D", TRUE, NULL); break; // Очистка данных блока case : // Приведение указателя на личную область данных к // правильному типу privdata=(TestBlkMoveSetterData*)(BlockData->BlockData); // Удаление динамических переменных (privdata->VLink); (privdata->ALink); // Освобождение отведенной памяти free(privdata); break; // Проверка типа статических переменных case : if(strcmp((char*)ExtParam,"{SSDD}")==0) return ; return ; // Выполнение такта моделирования case : // Приведение указателя на личную область данных к // правильному типу privdata=(TestBlkMoveSetterData*)(BlockData->BlockData); // Проверка существования переменной направления if(privdata->ALink!=NULL && privdata->ALink->Data!=NULL) { // Переменная существует – привести к типу double* double *pa=(double*)privdata->ALink->Data; if(*pa!=Angle) // Значение направления изменилось { // Записать значение в динамическую переменную *pa=Angle; // Уведомить всех подписчиков об изменении (privdata->ALink); } } // Проверка существования переменной скорости if(privdata->VLink!=NULL && privdata->VLink->Data!=NULL) { // Переменная существует – привести к типу double* double *pv=(double*)privdata->VLink->Data; if(*pv!=Speed) { // Записать значение в динамическую переменную *pv=Speed; // Уведомить всех подписчиков об изменении (privdata->VLink); } } break;
// Удаление блока пользователем case : // Приведение указателя на личную область данных к // правильному типу privdata=(TestBlkMoveSetterData*)(BlockData->BlockData); // Если блок удаляется в составе подсистемы, // предупреждать не нужно if( (()ExtParam)->WithSys) break; // Считаем число подписчиков на переменные этого блока if(CountDynVarUsers(privdata->VLink)>1 || CountDynVarUsers(privdata->ALink)>1) // // // ("Внимание! Этот блок предоставляет " "данные другим блокам. Его удаление " "приведет к их отключению.", BlockData->BlockName, MB_OK | MB_ICONWARNING); break;
} return ; // Отмена макроопределений #undef Angle #undef Speed #undef Ready #undef Start #undef pStart } //========================================= //============ Подвижный блок ============= // Структура личной области данных блока typedef struct { // Указатель на структуру подписки на скорость VLink; // Указатель на структуру подписки на направление ALink; // Указатель на структуру подписки на время Time; // Дополнительные поля для хранения значений синуса // и косинуса направления движения блока double SinA; double CosA; } TestBlkMoveObjectData; // Модель перемещающегося блока extern "C" __declspec(dllexport) int TestBlkMoveObject(int CallMode, BlockData, 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 a (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D))) #define t0 (*((double *)(pStart+2*RDS_VSZ_S+3*RDS_VSZ_D))) // Вспомогательная переменная – указатель на личную область // данных блока, приведенный к правильному типу TestBlkMoveObjectData *privdata; // Вспомогательные переменные для скорости и времени double v,time; switch(CallMode) { // Инициализация блока case : // Отведение памяти под личную область данных privdata=(TestBlkMoveObjectData*) malloc(sizeof(TestBlkMoveObjectData)); BlockData->BlockData=privdata; // Подписка на переменную скорости privdata->VLink=( , // В родительской "BlkMove_Speed", // Имя переменной "D", // Тип double FALSE); // Без поиска // Подписка на переменную направления privdata->ALink=( , // В родительской "BlkMove_Angle", // Имя переменной "D", // Тип double FALSE); // Без поиска // Подписка на переменную времени privdata->Time=( , // В родительской "DynTime", // Имя переменной "D", // Тип double TRUE); // Поиск в иерархии break; // Очистка данных блока case : // Приведение указателя на личную область данных к правильному типу privdata=(TestBlkMoveObjectData*)(BlockData->BlockData); // Прекращение подписки на все динамические переменные (privdata->VLink); (privdata->ALink); (privdata->Time); // Освобождение отведенной памяти free(privdata); break; // Проверка типа статических переменных case : if(strcmp((char*)ExtParam,"{SSDDDD}")==0) return ; return ; // Реакция на изменение динамической переменной case : // Приведение указателя на личную область данных к правильному типу privdata=(TestBlkMoveObjectData*)(BlockData->BlockData); // Проверка – удалось ли подписаться на все переменные // (если хотя бы один указатель – NULL, значит, не удалось) if(privdata->VLink==NULL || // Скорость privdata->ALink==NULL || // Направление privdata->Time==NULL) // Время break; // Проверка – существуют ли все переменные // (если хотя бы один указатель – NULL, значит, не удалось) if(privdata->VLink->Data==NULL || // Скорость privdata->ALink->Data==NULL || // Направление privdata->Time->Data==NULL) // Время break; // Если изменилась переменная направления, нужно вычислить // и запомнить новые значения ыинуса и косинуса угла if(ExtParam==(void*)(privdata->ALink)) { // Изменилось направление – привести к типу double* double *pa=(double*)privdata->ALink->Data; // Значение угла в радианах a=(*pa)*M_PI/180.0; // Значения синуса и косинуса privdata->SinA=sin(a); privdata->CosA=cos(a); } // Записать во вспомогательные переменные v и time значения // скорости и времени v=*(double*)privdata->VLink->Data; time=*(double*)privdata->Time->Data; // Вычислить новое смещение изображения блока x+=v*(time-t0)*privdata->CosA; y-=v*(time-t0)*privdata->SinA; // Запомнить значение времени, для которого вычислены // новые координаты t0=time; break; } return ; // Отмена макроопределений #undef t0 #undef a #undef y #undef x #undef Ready #undef Start #undef pStart } //========================================= //============================================================================ // Реакция на изменение размеров блока (в двухкоординатной рукоятке) //============================================================================ //====== Класс личной области данных ====== class TSimpleJoystick { private: // Центр круга (рукоятки) до начала перетаскивания int OldHandleX,OldHandleY; // Координаты курсора на момент начала перетаскивания int OldMouseX,OldMouseY; // Флаги фиксации одной из координат LockX,LockY; // Идентификаторы добавленных пунктов меню MenuLockX,MenuLockY; public: // Настроечные параметры блока BorderColor; // Цвет рамки блока FieldColor; // Цвет прямоугольника HandleColor; // Цвет круга в покое MovingHandleColor; // Цвет круга при таскании GrayedColor; // Цвет недоступной области int HandleSize; // Диаметр круга // Реакция на нажатие кнопки мыши int MouseDown( mouse,double x,double y, *pFlags); // Реакция на перемещение курсора мыши void MouseMove( mouse,double *px,double *py); // Рисование изображения блока void Draw( draw,double x,double y, moving); // Реакция на выбор добавленного пункта меню void MenuFunction( MenuData);
// Реакция на изменение размеров блока void Resizing( ResData);
// Конструктор класса TSimpleJoystick(void) { BorderColor=0; // Черная рамка FieldColor=0xffffff; // Белое поле HandleColor=0xff0000; // Синий круг MovingHandleColor=0xff; // Красный при таскании HandleSize=20; // Диаметр круга GrayedColor=0x7f7f7f; // Серый LockX=LockY=FALSE; // Фиксация выключена // Создание пунктов меню // // // MenuLockX=("Фиксировать X",1,0); MenuLockY=("Фиксировать Y",2,0); }; // Деструктор класса ~TSimpleJoystick() { // Уничтожение пунктов меню (MenuLockX); (MenuLockY); }; }; //========================================= // Рисование изображения блока void TSimpleJoystick::Draw( draw, double x,double y,BOOL moving) { int hx,hy,cx,cy; r; int hR=HandleSize*draw->DoubleZoom/2; // Радиус круга-рукоятки // Если размер блока - нулевой, рисовать негде if(draw->Height==0 || draw->Width==0) return; // Рисование поля блока (0,,1,BorderColor,); (0,,FieldColor); (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; (&r); // Рисование ограничений if(LockX||LockY) // Фиксируется одна из координат { // Установка серого цвета заливки (0,,GrayedColor); if(LockX) // Фиксируется X { (r.left,r.top,hx-hR,r.bottom); // Слева (hx+hR,r.top,r.right,r.bottom); // Справа } else // Фиксируется Y { (r.left,r.top,r.right,hy-hR); // Сверху (r.left,hy+hR,r.right,r.bottom);// Снизу } } // Линии перекрестия (cx,draw->Top); (cx,draw->Top+draw->Height); (draw->Left,cy); (draw->Left+draw->Width,cy); // Рисование круга (цвет зависит от параметра moving) (,,0,0,0); (0,, moving?MovingHandleColor:HandleColor); (hx-hR,hy-hR,hx+hR+1,hy+hR+1); // Отмена отсечения (NULL); } //========================================= // Реакция на нажатие кнопки мыши int TSimpleJoystick::MouseDown( mouse, double x,double y, *pFlags) { int hx,hy,cx,cy, hR=HandleSize*mouse->DoubleZoom/2; // Радиус круга // Если размер - нулевой, реакция не имеет смысла if(mouse->Height==0 || mouse->Width==0) return ; // Если нажата не левая кнопка, перетаскивать не надо // Разрешаем в этом случае вызов контекстного меню блока if(mouse->Button!=) return ; // Координаты цента блока 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|=; } // Курсор не попал в рукоятку - захватывать мышь // и подготавливать перетаскивание не нужно return ; } //========================================= // Реакция на перемещение курсора мыши void TSimpleJoystick::MouseMove( 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( MenuData) { switch(MenuData->Function) { case 1: // Выбран пункт "Фиксировать X" LockX=!LockX; // Переключаем флаг фиксации X LockY=FALSE; // Отключаем фиксацию Y break; case 2: // Выбран пункт "Фиксировать Y" LockY=!LockY; // Переключаем флаг фиксации Y LockX=FALSE; // Отключаем фиксацию X break; } // Установка галочек у пунктов меню в зависимости от // флагов фиксации координат (MenuLockX,LockX?:0); (MenuLockY,LockY?:0); } //=========================================
// Реакция на изменение размеров блока void TSimpleJoystick::Resizing( 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; } } //=========================================
// Функция модели блока extern "C" __declspec(dllexport) int SimpleJoystick(int CallMode, BlockData, 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))) // Вспомогательная переменная - указатель на личную область, //приведенный к правильному типу TSimpleJoystick *data=(TSimpleJoystick*)(BlockData->BlockData); switch(CallMode) { // Инициализация case : BlockData->BlockData=new TSimpleJoystick(); break; // Очистка case : delete data; break; // Проверка допустимости типов переменных case : return strcmp((char*)ExtParam,"{SSDD}")? :; // Нажатие кнопки мыши case : return data->MouseDown(()ExtParam,x,y, &(BlockData->Flags)); // Отпускание кнопки мыши case : // Снятие захвата мыши (BlockData->Flags,,FALSE); break; // Перемещение курсора мыши case : // Проверка: включен ли захват мыши if(BlockData->Flags & ) // Включен { // Вызываем функцию реакции data->MouseMove(()ExtParam,&x,&y); Ready=1; // Взводим сигнал готовности } break; // Рисование case : data->Draw(()ExtParam,x,y, BlockData->Flags & ); break; // Выбор пользователем добавленного пункта меню case : data->MenuFunction(()ExtParam); break;
// Изменение размеров блока case : case : data->Resizing(()ExtParam); break;
} return ; // Отмена макроопределений #undef y #undef x #undef Ready #undef Start #undef pStart } //=========================================


<< >> Оглавление Указатель