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

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

  // Программное добавление и удаление блоков и связей
  #include <windows.h>
  #include <stdio.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;
  }
  //========= Конец главной функции =========


  //=========================================
  // "Обрезание" отрезка по прямоугольнику
  // (вспомогательная функция)
  //=========================================
  void ClipLineByRect(
      int x1,int y1,   // Центр прямоугольника
      int w,int h,     // Размеры прямоугольника
      int x2,int y2,   // Конец отрезка
      int *px,int *py) // Координаты точки на границе
  { int xv,yg,xres,yres;
    double tv,tg,t;
    int status=0; // Наличие точек пересечения

    if(x2!=x1) // Отрезок не строго вертикален
      { if(x2>x1) // Отрезок уходит вправо
          xv=x1+w/2;
        else // Отрезок уходит влево
          xv=x1-w/2;
        // Параметр точки пересечения с вертикальной прямой
        tv=((double)(xv-x1))/((double)(x2-x1));
        status=1; // Есть точка пересечения с вертикалью
      }

    if(y2!=y1) // Отрезок не строго горизонтален
      { if(y2>y1) // Отрезок уходит вниз
          yg=y1+h/2;
        else // Отрезок уходит вверх
          yg=y1-h/2;
        // Параметр точки пересечения с горизонтальной прямой
        tg=((double)(yg-y1))/((double)(y2-y1));
        status+=10; // Есть пересечение с горизонталью
      }

    switch(status)
      { case 0:  // Ошибка: (x1,y1)==(x2,y2)
          *px=x1; *py=y1; return;
        case 1:  // Строго горизонтальный отрезок
          t=tv; break;
        case 10: // Строго вертикальный отрезок
          t=tg; break;
        default: // Диагональный отрезок
         t=(tv<tg)?tv:tg;
      }
    // Вычисление координат по параметру t
    *px=x1+t*(x2-x1);
    *py=y1+t*(y2-y1);
  }
  //=========================================

  //=========================================
  // Вывод сообщения об ошибке в файле
  // (вспомогательная функция)
  //=========================================
  // 
  // 
  // 
  void FileErrorMessage(int line,      // Номер строки или 0
                        char *file,    // Имя файла или NULL
                        char *message) // Описание ошибки
  { char *msg=NULL; // Здесь будет формироваться текст

    if(message) // Есть текст описания
      (&msg,message,FALSE); // Копируем в msg
    if(file) // Есть имя файла
      { // Добавляем к динамической строке msg
        (&msg,"\nФайл: ",FALSE);
        (&msg,file,FALSE);
      }
    if(line>0) // Есть номер строки
      { char buf[80]; // Преобразуем в текст и добавляем к msg
        sprintf(buf,"\nСтрока: %d",line);
        (&msg,buf,FALSE);
      }
    // Выводим сообщение пользователю
    (msg,"Ошибка",|);
    // Освобождаем динамическую строку msg
    (msg);
  }
  //=========================================


  //=========================================
  // Блок, добавляющий и удаляющий блоки и
  // связи в своей подсистеме
  //=========================================

  // Личная область данных блока
  class TLoadGraphData
  { public:
       List; // Объект-список добавленных блоков и связей

      // Функция добавления блоков по списку из файла
       LoadBlocks( thisblock,char *blockfile,
                      char *blocklist);
      // Функция добавления связей по списку из файла
      void LoadConnections( thisblock,char *connlist);
      // Функция удаления добавленного
      void DeleteByList(void);

      // Функция настройки (в нее передаются номера статических
      // переменных, в которых хранятся параметры блока)
      int Setup( Block,int BlockFileVar,
                int BlockLstVar,int ConnLstVar);

      // Конструктор класса
      TLoadGraphData(void){List=NULL;};
      // Деструктор класса
      ~TLoadGraphData(){(List);};
  };
  //=========================================

  // Функция настройки параметров блока
  // 
  // 
  // 
  int TLoadGraphData::Setup(
     Block, // Идентификатор блока
    int BlockFileVar,  // Номер переменной с файлом блока
    int BlockLstVar,   // Номер переменной со списком блоков
    int ConnLstVar)    // Номер переменной со списком связей
  {  window; // Идентификатор вспомогательного объекта
     ok;            // Пользователь нажал "OK"
    char *defval;

    // Создаем окно
    window=(FALSE,-1,-1,"Добавление блоков");

    //----- Файл с описанием блока -----
    // Значение по умолчанию переменной с номером BlockFileVar
    defval=(Block,BlockFileVar,NULL);
    // Поле ввода с возможностью выбора файла
    (window,0,1,,
        "Добавляемых блок:",300);
    // Фильтр имен файлов для поля
    (window,1,,
        "Файлы блоков (*.blk)|*.blk\nВсе файлы|*.*");
    // Значение поля ввода
    (window,1,,defval);
    // Динамическая строка defval больше не нужна
    (defval);

    // Список блоков
    defval=(Block,BlockLstVar,NULL);
    (window,0,2,,
        "Список блоков:",300);
    (window,2,,
        "Текстовые файлы (*.txt)|*.txt\nВсе файлы|*.*");
    (window,2,,defval);
    (defval);

    // Список связей
    defval=(Block,ConnLstVar,NULL);
    (window,0,3,,
        "Список связей:",300);
    (window,3,,
        "Текстовые файлы (*.txt)|*.txt\nВсе файлы|*.*");
    (window,3,,defval);
    (defval);

    // Открытие окна
    ok=(window,NULL);
    if(ok)
      { // Запись значений в переменных блока
        defval=(window,1,);
        (Block,BlockFileVar,defval);
        defval=(window,2,);
        (Block,BlockLstVar,defval);
        defval=(window,3,);
        (Block,ConnLstVar,defval);
      }
    // Уничтожение окна
    (window);
    return ok?1:0;
  }
  //=========================================

  // Создание блоков по списку
  // 
  // 
  // 
   TLoadGraphData::LoadBlocks(
     thisblock, // Идентификатор этого блока
    char *blockfile,       // Файл добавляемого блока
    char *blocklist)       // Файл списка блоков
  {  block=NULL;
     csv;
     descr;
     ok=TRUE;
     Modified=FALSE; // Флаг внесения изменений в схему
    int line=0; // Номер строки в списке блоков

    if(List) // Уже есть список объектов – очишаем его
      (List,);
    else // Списка нет – создаем новый (пустой)
      { List=(NULL,0,FALSE);
        // Включаем автоматическое обнуление удаленных блоков и связей
        (List,,0,1);
      }

    // Получаем описание нашего блока (нужны его родитель и имя)
    descr.servSize=sizeof(descr);
    (thisblock,&descr);

    // Создаем объект для разбора формата CSV
    csv=();

    // Открываем файл со списком блоков для чтения в csv
    (csv,,0,blocklist);

    // Проверяем, открылся ли файл
    if(!(csv,,0))
      { FileErrorMessage(0,blocklist,
            "Невозможно открыть список блоков");
        (csv);
        return FALSE;
      }

    // Читаем строки файла в цикле
    for(;;)
      { char *name;
        int x,y;
        // Читаем очередную строку из файла в строку объекта 0
        if(!(csv,,0,NULL))
          break; // Строки в файле кончились
        line++;
        name=(csv,0,0); // Имя блока (элемент 0)
        if(*name==0) // Имя блока пустое
          { FileErrorMessage(line,blocklist,"Пустое имя блока");
            ok=FALSE;
            break;
          }
        // Читаем из объекта координаты блока (элементы 1 и 2)
        x=atoi((csv,0,1));
        y=atoi((csv,0,2));
        // Если имя блока, который нужно добавить, совпадает с именем
        // нашего блока – переименовываем наш
        if(strcmp(name,descr.BlockName)==0)
          { // Имена совпали – подбираем новое для нашего
            char *newname=(
                              descr.Parent,descr.BlockName);
            // Переименовываем наш блок и получаем его новое описание
            (thisblock,newname,&descr);
            (newname); // Освобождаем строку имени
            Modified=TRUE;
          }

        if(block==NULL) // Добавляем самый первый блок (из файла)
          block=(blockfile,descr.Parent,x,y,NULL);
        else // Уже добавляли блок раньше – копируем добавленный
          block=(block,descr.Parent,x,y,NULL);
        if(block==NULL) // Ошибка при добавлении блока
          { FileErrorMessage(line,blocklist,
                "Не удалось добавить блок");
            ok=FALSE;
            break;
          }
        Modified=TRUE; // Схема изменилась
        // Заносим добавленный блок в список List
        (List,block,FALSE);
        // Даем добавленному блоку имя, считанное из списка
        if(!(block,name,NULL))
          { FileErrorMessage(line,blocklist,"Повтор имени блока");
            ok=FALSE;
            break;
          }
      } // for(;;)

    // Удаляем объект csv (файл закроется автоматически)
    (csv);
    if(Modified) // Добавлены блоки
      (TRUE);
    return ok;
  }
  //=========================================

  // Функция создания связей по списку
  // 
  // 
  // 
  void TLoadGraphData::LoadConnections(
     thisblock, // Идентификатор этого блока
    char *connlist)        // Файл списка связей
  {  csv;
     descr;
     ok=TRUE;
     Modified=FALSE;
     editor=NULL;
     dim1,dim2;
    int line=0; // Счетчик считанных строк

    // Заполнение поля размера служебных структур
    dim1.servSize=sizeof(dim1);
    dim2.servSize=sizeof(dim2);

    // Получаем описание нашего блока (нужен его родитель)
    descr.servSize=sizeof(descr);
    (thisblock,&descr);

    // Создаем объект для разбора формата CSV
    csv=();

    // Открываем файл со списком связей для чтения в csv
    (csv,,0,connlist);

    // Проверяем, открылся ли файл
    if(!(csv,,0))
      { FileErrorMessage(0,connlist,
            "Невозможно открыть список связей");
        (csv);
        return;
      }

    // Читаем строки файла в цикле
    for(;;)
      { char *name1,*name2,*var1,*var2;
         block1,block2;
        int xc1,xc2,yc1,yc2,pnum1,pnum2,x1,y1,x2,y2;
         conn;
        // Читаем очередную строку из файла в строку объекта 0
        if(!(csv,,0,NULL))
          break;
        line++;
        // Считываем из строки имена соединяемых блоков и переменных
        name1=(csv,0,0); // Имя блока 1
        var1=(csv,0,1);  // Имя переменной 1
        name2=(csv,0,2); // Имя блока 2
        var2=(csv,0,3);  // Имя переменной 2
        if(*name1==0 || *name2==0 || *var1==0 || *var2==0)
          { FileErrorMessage(line,connlist,
                "Мало данных в строке связи");
            break;
          }
        // Ищем в подсистеме блоки с указанными именами
        block1=(descr.Parent,name1,NULL);
        block2=(descr.Parent,name2,NULL);
        if(block1==NULL || block2==NULL) // Какого-то нет
          { FileErrorMessage(line,connlist,
                "Не найден один из блоков");
            break;
          }
        // Получаем координаты и размеры блоков
        (block1,&dim1,FALSE);
        (block2,&dim2,FALSE);
        // Вычисляем координаты центров блоков
        xc1=dim1.Left+dim1.Width/2;
        yc1=dim1.Top+dim1.Height/2;
        xc2=dim2.Left+dim2.Width/2;
        yc2=dim2.Top+dim2.Height/2;
        // "Обрезаем" прямую по границам первого блока
        (xc1,yc1,dim1.Width,dim1.Height,xc2,yc2,
            &x1,&y1);
        // "Обрезаем" прямую по границам второго блока
        (xc2,yc2,dim2.Width,dim2.Height,xc1,yc1,
            &x2,&y2);
        // Создаем или очищаем объект для редактирования связи
        if(editor==NULL) // Нужно создать
          editor=();
        else // Очищаем ранее созданный
          (editor,);
        // Добавляем в объект editor две точки
        pnum1=(editor,block1,var1,
                  x1-dim1.BlockX,y1-dim1.BlockY,FALSE);
        pnum2=(editor,block2,var2,
                  x2-dim2.BlockX,y2-dim2.BlockY,FALSE);
        // Добавляем соединяющую их линию
        (editor,pnum1,pnum2);
        // Создаем по данным объекта editor новую связь
        conn=(editor,descr.Parent,,NULL);
        if(conn!=NULL) // Создание связи удалось
          { Modified=TRUE;
            // Добавляем связь в список
            (List,conn,FALSE);
          }
        else // Ошибка при создании связи
          { FileErrorMessage(line,connlist,
                "Не удалось создать связь");
            break;
          }
      } // for(;;)

    // Удаляем объект csv (файл закроется автоматически)
    (csv);
    // Удаляем объект-редактор
    (editor);
    if(Modified) // Добавлены связи
      (TRUE);
  }
  //=========================================

  // Удаление добавленных блоков и связей
  void TLoadGraphData::DeleteByList(void)
  {  *conns;
     *blocks;
    int count;

    if(List==NULL) // Списка нет
      return;

    // Отключаем автоматическое обнуление удаляемых объектов
    (List,,0,0);

    // Получаем указатель на массив идентификаторов связей и его размер
    conns=(*)(List,,0,&count);
    // Удаляем все связи из этого массива
    for(int i=0;i<count;i++)
      (conns[i]);

    // Получаем указатель на массив идентификаторов блоков
    // и его размер
    blocks=(*)(List,,0,&count);
    // Удаляем все связи из этого массива
    for(int i=0;i<count;i++)
      (blocks[i]);

    // Удаляем объект-список и обнуляем List
    (List);
    List=NULL;
    // Взводим флаг измененности схемы
    (TRUE);
  }
  //=========================================

  // Модель блока
  extern "C" __declspec(dllexport)
    int  LoadGraph(int CallMode,
           BlockData,
           ExtParam)
  { // Приведение указателя на личную область данных 
    // к правильному типу
  TLoadGraphData *data=(TLoadGraphData*)(BlockData->BlockData);
  // 
  #define pStart ((char *)(BlockData->VarTreeData))
  #define Start (*((char *)(pStart)))
  #define Ready (*((char *)(pStart+RDS_VSZ_S)))
  #define BlockFile (*((char **)(pStart+2*RDS_VSZ_S)))
  #define BlockList (*((char **)(pStart+2*RDS_VSZ_S+RDS_VSZ_A)))
  #define ConnList (*((char **)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_A)))
    switch(CallMode)
      { // Инициализация модели
        case :
          BlockData->BlockData=new TLoadGraphData();
          break;

        // Очистка
        case :
          delete data;
          break;

        // Проверка типов переменных
        case :
          return strcmp((char*)ExtParam,"{SSAAA}")?
            :;

        // Настройка параметров блока
        case :
          return data->Setup(BlockData->Block,
                                2,  // BlockFile
                                3,  // BlockList
                                4); // ConnList

        // Вызов контекстного меню блока
        // 
        // 
        // 
        case :
          (
              "Добавить блоки и связи",0,1,0);
          (
              "Удалить добавленное",
              data->List==NULL?:0,2,0);
          break;

        // Выбор пункта в контекстном меню
        case :
          switch((()ExtParam)->Function)
            { case 1: // Добавить блоки и связи
                // Подготовка к серьезным изменениям
                (FALSE);
                if(data->LoadBlocks(BlockData->Block,
                                    BlockFile,BlockList))
                  data->LoadConnections(BlockData->Block,ConnList);
                // Серьезные изменения завершены
                (TRUE);
                break;
              case 2: // Удалить добавленное
                // Подготовка к серьезным изменениям
                (FALSE);
                data->DeleteByList();
                // Серьезные изменения завершены
                (TRUE);
                break;
            }
          break;
      }
    return ;
  // Отмена макроопределений
  #undef ConnList
  #undef BlockList
  #undef BlockFile
  #undef Ready
  #undef Start
  #undef pStart
  }
  //=========================================


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