Дизайн формы
Дизайн формы определяет то, каким образом форма будет отображаться в интерактивном представлении.
Как и в любом GUI, дизайн формы представляет собой иерархию, узлами которой являются компоненты. Компонентами, в свою очередь, могут быть:
- контейнеры - компоненты, которые содержат в себе другие компоненты.
- базовые компоненты - графические представления элементов, описанных в структуре формы и интерактивном представлении формы.
Каждый компонент должен иметь свое уникальное имя в рамках формы.
Контейнеры
Все потомки любого контейнера образуют упорядоченный список. Для каждого контейнера на форме необходимо определить, каким образом должны располагаться его потомки. Для этого контейнеру можно задать опции horizontal, tabbed, lines.
По умолчанию, любой создаваемый контейнер является вертикальным.
Контейнеру можно задать заголовок — постоянный текст или текущее значение свойства, и тогда он зависит от данных и меняется вместе с ними. Заголовок главного контейнера формы (в дизайне по умолчанию — BOX) — это и есть заголовок формы в интерактивном представлении: он показывается как заголовок её окна или закладки. По умолчанию это заголовок, заданный при объявлении формы; на заголовок элемента формы в навигаторе он не влияет.
Если в какой-то момент времени выполнения у контейнера потомки отсутствуют или являются невидимыми, то он автоматически скрывается. В свою очередь, если какой-то компонент не является потомком ни одного контейнера, то он также не будет показан на форме.
Контейнер с заголовком по умолчанию сворачиваемый: переключатель рядом с заголовком его сворачивает, а дизайн может задать, что изначально он свернут. Рабочий параметр disableCollapsibleContainers (по умолчанию false) убирает это поведение по умолчанию, оставляя сворачиваемыми только те контейнеры, для которых это указано в дизайне явно. Две его половины действуют в разное время: переключатель пропадает сразу после изменения параметра, а заданное в дизайне начальное свернутое состояние перестает учитываться только для дизайна, построенного после этого, то есть после перезапуска сервера.
Базовые компоненты
При задании дизайна формы разработчик может использовать следующие базовые компоненты, которые создаются автоматически на основе структуры формы:
Группы объектов / деревья:
- Таблица / Дерево (
GRID) - компонент, состоящий из рядов и колонок, в котором рядам соответствуют наборы объектов соответствующей группы объектов, а колонкам - свойства и действия. - Системный тулбар (
TOOLBARSYSTEM) - панель, состоящая из кнопок, при помощи которых пользователь может проводить различные системные действия над рядами в таблице. Автоматически прячется, если таблица становится невидимой. - Пользовательский фильтр (
FILTERS) - компонент, при помощи которого пользователь может создавать и применять собственные фильтры к таблице. - Расчеты (
CALCULATIONS) - компонент, который отображает результаты агрегирующих расчетов по колонкам таблицы (например, суммы по колонкам).
Группы фильтров
- Группа фильтров (
FILTERGROUP) - компонент, при помощи которого пользователь может активировать необходимые ему фильтры в группах фильтров формы.
Свойства / Действия
- Панель свойства (
PROPERTY) - компонент, которые отображает заголовок и текущее значение свойства. Заголовок может быть как слева от ячейки значения, так и сверху. Не показывается, если свойство отображается в таблицу.
Отображение ячейки значения
В веб-клиенте ячейка значения свойства обычно представляет собой обычный блок, который превращается в редактор, когда пользователь начинает изменение. Свойство строкового типа, показанное в панели, вместо этого может сразу рисоваться настоящим полем ввода - это решает рабочий параметр useInputTagForTextBasedInPanel (по умолчанию 1): 0 рисует его полем ввода в любой теме, 1 - только в bootstrap-теме, 2 - никогда. При этом свойство должно быть изменяемым, а его класс - иметь подходящий тип ввода; HTML, форматированный текст и ссылки так не рисуются никогда, а BOOLEAN, наоборот, рисуется всегда, независимо от этого параметра.
Поверх ячейки значения клиент рисует тулбар ячейки: индикатор загрузки свойства и кнопки действий, вынесенных в ячейку для быстрого доступа. Убирают его три параметра: noToolbarForInputTagInPanel (по умолчанию false) - для свойства в панели, нарисованного полем ввода, noToolbarForBoolean (true, то есть включен из коробки) - для любого BOOLEAN, и в панели, и в таблице, и noToolbarForSelectDropdownInPanel (false) - для свойства, значение которого выбирается из выпадающего списка: оно тогда рисуется штатным элементом выбора. Вопреки названию, последний не ограничен панелью, а поскольку у такого свойства кнопок быстрого доступа и так нет, на практике он убирает индикатор загрузки над ним. Опция toolbar в дизайне формы сильнее всех трех.
Размеры и расположение компонент
Разработчик может управлять, каким образом платформа будет распределять доступные размеры контейнеров между своими внутренними компонентами, а также как эти компоненты будут располагаться друг относительно друга.
Прежде всего, для каждого компонента можно задать базовый размер, который этот компонент получит в любом случае не зависимо от алгоритма расположения его контейнера.
Для определения окончательного размера компонент и их расположения внутри контейнера, используется следующий алгоритм:
Для каждого контейнера одно из направлений считается динамическим, другое - статическим. Динамическое направление определяется из названия контейнера, так, к примеру для вертикального контейнера динамическим направлением будет вертикальное, для горизонтального сплиттера - горизонтальное. Для колоночного, прокручиваемого контейнера, а также панели закладок, динамическим направлением считается вертикальное. Далее, в зависимости от направления:
-
Динамическое - все компоненты располагаются друг за другом, в порядке их добавления в контейнер. При этом, для каждого компонента можно задать коэффициент расширения (
flex). В этом случае оставшееся в контейнере пространство (то есть за вычетом базовых размеров всех внутренних компонент) делится между всеми компонентами пропорционально их коэффициентам расширения. -
Статическое - для каждого компонента задается выравнивание (
alignment) - В начале (START), По центру (CENTER), В конце (END), и Растянуть (STRETCH). В первых трех случаях компонент в качестве окончательного размера получает свой базовый размер, и располагается в соответствии с указанным типом выравнивания (то есть в начале, по центру или в конце). Если же в качестве типа выравнивания используется Растянуть, окончательным размером компонента будет размер верхнего контейнера (но не меньше базового размера), а располагаться он будет ровно по центру.
К примеру, в случае вертикального верхнего контейнера, если для компонента задано выравнивание В начале, то он будет располагаться в контейнере максимально слева, а если Растянуть - то компонент займет все пространство от левой до правой границы.
Данный алгоритм расположения компонент является частным случаем CSS Flexible Box Layout (а в веб-клиенте при помощи него и реализуется). Так, к примеру, коэффициенту расширения соответствует свойство CSS flex-grow, а базовому размеру - flex-basis.
Колоночный контейнер свое статическое (горизонтальное) направление разбивает на N одинаковых частей (где N - количество колонок), после чего каждая из частей располагает свои компоненты, как если бы эта часть была отдельным вертикальным контейнером.
Для базовых компонент можно задать специальную опцию автоматического определения размера (autoSize), в этом случае базовый размер будет автоматически изменяться таким образом, чтобы вместить ровно все содержимое этого базового компонента (к примеру для таблицы - все ее записи плюс заголовок). Для свойства эта опция относится к ячейке значения: ее высота, а в панели и ширина, если они не заданы явно в пикселях, следуют за содержимым, а не определяются классом значения; ширина колонки таблицы и при этой опции определяется классом значения.
Расположение свойств в таблице (а точнее колонок, которые отображают их значения) происходит аналогично, как если бы таблица была горизонтальным контейнером, а колонки таблицы - внутренними компонентами этого контейнера.
Так как в текущей реализации для расположения колонок внутри таблицы в веб-клиенте используется механизм CSS Table Layout Fixed (а его возможности существенно ограничены), для свойств, отображающихся в таблице, коэффициент расширения может быть равен либо 0, либо базовому размеру.
Расположение заголовка и ячейки значения внутри панели свойства происходит аналогично, как если бы панель была контейнером (горизонтальным - если заголовок слева, вертикальным - если сверху), в котором у ячейки значения коэффициент расширения равен 1, у заголовка равен 0, а выравнивания обоих равны STRETCH.
Размеры ячеек значений свойств
При отображении свойств можно явно задавать как размеры всего контейнера (вместе с заголовком, если свойство находится в панели), так и размеры непосредственно ячейки значения. Для этого к названию размера необходимо добавить префикс value - например valueWidth). Также, стоит отметить, что именно эти размеры (то есть ячейки значения, а не всего контейнера) используются при определении ширин колонок, если свойство отображается в таблице.
Для ячеек значений свойств также существует возможность задать базовую ширину не в пикселях, а при помощи некоторого значения-образца (widthValue). В этом случае платформа сама с учетом используемых шрифта / маски / локали пользователя вычисляет и устанавливает ширину в пикселях, таким образом, чтобы пользователю было видно в точности заданное значение-образец (ни больше, ни меньше). Предполагается, что значение-образец должно быть либо строкой, либо его класс должен совпадать с классом значения свойства.
Кроме того, ширину ячейки значения можно задавать в символах (charWidth), что эквивалентно тому, как если бы значение-образец было строкой и состояло из заданного количества нулей.
В последних двух случаях (то есть при задании ширины в виде значения-образца или в символах), если класс значения свойства при вводе подразумевает наличие справа кнопки (например, таким классом является DATE), то к ширине ячейки значения свойства дополнительно добавляется ширина этой кнопки (21 пиксель).
Размеры и расположение по умолчанию
По умолчанию, коэффициент расширения и выравнивание для компонент определяются следующим образом:
| Компонент | Коэффициент расширения | Выравнивание |
|---|---|---|
| Таблица / Дерево | 1 | STRETCH |
| Компонент внутри прокручиваемых контейнеров, сплиттеров и панели закладок | 1 | STRETCH |
| Панель свойства внутри горизонтального контейнера или свойство в таблице. При этом значения свойства являются объектами встроенных классов динамической длины (то есть строки и числа) | Ширина ячейки значения | START |
| Панель свойства внутри вертикального контейнера. При этом значения свойства являются объектами встроенных классов динамической длины (то есть строки и числа) | 0 | STRETCH |
| Все остальные | 0 | START |
0 из последней строки - не совсем 0 для колонки таблицы. Пока включен рабочий параметр defaultFlexInGrid (по умолчанию true), колонка, значения которой имеют фиксированный размер - BOOLEAN, дата, цвет, файл, объект пользовательского класса, действие, - получает вместо него крошечный коэффициент растяжения 0.001, чтобы забирать свою долю свободной ширины только после колонок динамической длины. При выключенном параметре у такой колонки остается 0: она никогда не растет сверх базового размера, и ширина, до которой ее растянул пользователь, тоже не запоминается, так как сохраненная ширина применяется только к колонке с ненулевым коэффициентом растяжения.
Базовый размер контейнера (за исключением панели закладок) по умолчанию равен сумме базовых размеров всех его потомков для динамического направления, и максимуму - для статического направления. Базовая высота панели закладок равна сумме базовой высоты ее текущей вкладки и высоты панели заголовков вкладок, базовая ширина при этом совпадает с базовой шириной текущей вкладки.
Базовая ширина таблиц / деревьев по умолчанию равна 130 пикселям, высота - 70. Базовый размер панели свойства определяется аналогично, как если бы панель была контейнером (горизонтальным - если заголовок слева, вертикальным - если сверху), состоящим из заголовка и ячейки значения. Базовый размер остальных базовых компонент (а также заголовка в панели свойства) определяется таким образом, чтобы вместить весь содержащийся в них текст.
Размеры ячеек значений свойств
Для определения ширины ячейки значения свойства по умолчанию используются следующие формулы:
| Класс значения свойства | В чем определяется ширина | Ширина / Значение |
|---|---|---|
| Строки | В символах | IF length <= 12 result = length ELSE IF length = INFINITE result = 15 ELSE result = 12 + (length - 12) ^ 0.7 |
| Числа | В символах | IF length <= 6 result = length ELSE IF this = DOUBLE result = 10 ELSE result = MIN(6 + (length - 6) ^ 0.7, 10)Где length = integerPart + precision |
COLOR | В пикселях | 40 |
| Файлы и ссылки на файлы | В пикселях | 18 |
BOOLEAN | В пикселях | 30 |
DATE | Значение-образец | 1991_11_21 |
DATETIME | Значение-образец | 1991_11_21_10:55:55 |
TIME | Значение-образец | 10:55:55 |
| Пользовательские классы | В символах | 13 |
Высота ячейки значения свойства по умолчанию равна высоте используемого шрифта, за исключением свойств, значения которых принадлежат классам TEXT, RICHTEXT и HTMLTEXT (в этом случае высота равна четырехкратной высоте шрифта, а ширина - как у строки неограниченной длины). В панели эта высота - базовый размер ячейки, который не меняется с содержимым: текст длиннее четырех строк прокручивается внутри поля ввода или редактора форматированного текста, а содержимое ячейки, показываемой как есть, - HTML, текст только для чтения - по умолчанию обрезается.
Размер окна
Если форма открывается в режиме окна, у нее нет верхнего контейнера, соответственно для этого окна необходимо определить его первоначальный размер. Этот размер определяется аналогично базовому размеру по умолчанию, с той лишь разницей, что для таблиц / деревьев, размер по умолчанию определяется не как константа (по умолчанию - 130, 70), а таким образом чтобы вместить все ее содержимое (по аналогии с механизмом автоматического определения размера), но не меньше чем 130 по ширине и 140 по высоте.
Размер вычисляется по содержимому, имеющемуся в момент открытия окна, и после этого не меняется (изменить окно может только пользователь). В веб-клиенте содержимое контейнера, отрисовываемого компонентом React, рисует сам компонент — уже после того, как размер окна вычислен, — поэтому такой контейнер без заданного базового размера учитывается как пустой, а его содержимое затем не помещается в окно и вытесняет за его край расположенные ниже компоненты, включая системные кнопки. Заданный базовый размер компонента при вычислении размера окна учитывается как минимальный, поэтому такому контейнеру задают базовый размер; содержимое, не поместившееся в него, по умолчанию прокручивается внутри контейнера.
Измерение и фиксация размера при открытии — режим главного контейнера формы по умолчанию. Если в дизайне формы главному контейнеру явно задать базовый размер -1 — по обоим направлениям или только по высоте, — в этом направлении окно не измеряется и не фиксируется, а следует за содержимым, в том числе отрисованным позже. При этом окно центрируется только при открытии, по содержимому, которое было в тот момент, его высота не ограничивается высотой экрана — окно выше экрана прокручивается целиком, — а таблицы на такой форме не подстраивают высоту под свои строки, оставаясь базовой высоты с собственной прокруткой.
Дизайн по умолчанию
Для каждый формы может быть создан автоматический дизайн на основе структуры формы. Разработчик может как модифицировать автоматический, так и создать свой собственный дизайн с нуля.
Автоматический дизайн формируется следующим образом:
BOX- содержит все компоненты данной формы. Вертикальный контейнер. Коэффициент расширения -1, выравнивание -STRETCH.PANEL- содержит компоненты свойств, которые отображаются в представленииPANELи для которых группа отображения не определена (у свойства нет параметров). Внутренняя структура и расположение аналогичны соответствующему контейнеру для группы объектов.GROUP...
OBJECTS- содержит все компоненты, которые создаются для групп объектов / деревьев данной формы. Вертикальный контейнер. Коэффициент расширения -1, выравнивание -STRETCH.BOX(<группа объектов / дерево>)- содержит все компоненты данной группы объектов. Вертикальный контейнер. Коэффициент расширения -1, выравнивание -STRETCH.FILTERBOX(<группа объектов / дерево>)- содержит пользовательский фильтр группы объектов вместе с его элементами управления. Горизонтальный контейнер.FILTERS(<группа объектов / дерево>)- базовый компонент Пользовательский фильтр. Выравнивание -STRETCH.FILTERCONTROLS(<группа объектов / дерево>)- базовый компонент элементов управления пользовательского фильтра. Выравнивание -CENTER.
GRID(<группа объектов / дерево>)- базовый компонент Таблица.TOOLBARBOX(<группа объектов / дерево>)- содержит все составные части тулбара (отвечающие за расположение внутри тулбара). Горизонтальный контейнер. Выравнивание -STRETCHTOOLBARLEFT(<группа объектов / дерево>)- левая часть тулбара. Горизонтальный контейнер. Выравнивание -CENTER.TOOLBARSYSTEM(<группа объектов / дерево>)- базовый компонент Системный тулбар. Выравнивание -CENTER.POPUP(<группа объектов / дерево>)- свернутый всплывающий контейнер (отображается как меню "⋮"), в который помещаются перенесенные в него компоненты.
TOOLBARRIGHT(<группа объектов / дерево>)- правая часть тулбара. Горизонтальный контейнер. Коэффициент расширения -1, выравнивание -CENTER.CALCULATIONS(<группа объектов / дерево>)- базовый компонент Расчеты по таблице. Коэффициент расширения -1.FILTERGROUPS(<группа фильтров>)- содержит все компоненты, которые создаются для групп фильтров соответствующей группы объектов. Горизонтальный контейнер. Выравнивание -CENTER.FILTERGROUP- базовый компонент Группа фильтров. Выравнивание -CENTER.
TOOLBAR(<группа объектов / дерево>)- содержит компоненты свойств, которые отображаются в представленииTOOLBARи группа отображения которых равна заданной. Горизонтальный контейнер. Выравнивание -CENTER.PROPERTY(<свойство>)- базовый компонент Панель свойства.
PANEL(<группа объектов / дерево>)- содержит компоненты свойств, которые отображаются в представленииPANEL. Вертикальный контейнер. Выравнивание -STRETCH. Если некоторые свойства принадлежат группам, для которых необходимо создание отдельных контейнеров, то для них создается соответствующая иерархия контейнеров и в нее помещаются компоненты этих свойств:GROUP(<группа свойств>,<группа объектов / дерево>)- содержит компоненты свойств, которые принадлежат заданным группе объектов и группе свойств (или не принадлежат никакой группе свойств, в этом случае группа свойств не указывается, напримерGROUP(,a)). Вертикальный контейнер с тремя линиями: потомки раскладываются по трём колонкам, а если их не больше трёх — одной горизонтальной линией.PROPERTY(<свойство>)- базовый компонент Панель свойства.
TOOLBARBOX- содержит компоненты свойств, которые отображаются в представленииTOOLBARи для которых группа отображения не определена (например у свойства нет параметров). Внутренняя структура и расположение аналогичны соответствующему контейнеру для группы объектов (за исключениемFILTERGROUPS, который не имеет смысла, когда группа объектов не определена, и соответственно в этом контейнере отсутствуют). Этот контейнер добавляется в конецBOX, а компоненты, которые дизайн формы добавляет вBOXв порядке объявления, располагаются над ним.TOOLBARLEFT, TOOLBARRIGHT, TOOLBAR...
Этот дизайн по умолчанию меняют два рабочих параметра. Оба читаются в момент его построения, поэтому изменение любого из них вступает в силу только после перезапуска сервера.
verticalColumnsFiltersContainer (по умолчанию true) раскладывает условия внутри FILTERS в три колонки, как это делает контейнер GROUP, с той разницей, что при одном-двух условиях он сохраняет три колонки, а не сворачивается в одну строку. При выключенном параметре FILTERS - обычный горизонтальный контейнер, и все условия идут в один ряд.
toolbarTopLeft (по умолчанию false) помещает TOOLBARBOX над пользовательским фильтром и таблицей, а не под ними, и меняет местами две половины внутри него: первым идет TOOLBARRIGHT с расчетами, группами фильтров и свойствами тулбара, а TOOLBARLEFT с системным тулбаром и меню POPUP уходит вправо, причем каждая половина забирает свободную ширину и выравнивает своих потомков тоже наоборот. В тулбаре самой формы меняется и порядок системных кнопок: Обновить уходит в конец, ОК и Закрыть - в начало. Для дерева действует только перенос по вертикали - половины там своего порядка не меняют.
Пример дизайна по умолчанию
FORM myForm 'myForm'
OBJECTS myObject = myClass
PROPERTIES(myObject) myProperty1, myProperty2 PANEL
FILTERGROUP myFilter
FILTER 'myFilter' myProperty1(myObject)
;
Иерархия контейнеров и компонентов в дизайне по умолчанию будет выглядеть следующим образом :

Язык
Для управления дизайном формы предназначена инструкция DESIGN; в её статье приведены и полные таблицы свойств компонентов всех видов (контейнеров, компонентов свойств и действий на форме, тулбаров, таблиц), задаваемых этой инструкцией.
Примеры
DESIGN order { // настраиваем дизайн формы, начиная с дизайна по умолчанию
// отмечаем, что все изменения иерархии будут происходит для самого верхнего контейнера
// создаем новый контейнер самым первым перед системными кнопками, в который положим два контейнера -
// шапка и спецификации
NEW orderPane FIRST {
fill = 1; // указываем, что контейнер должен занимать все доступное ему место
MOVE BOX(o) { // переносим в новый контейнер все, что касается объекта o
PANEL(o) { // настроим как отображаются свойства в панели объекта o
horizontal = FALSE; // делаем, чтобы все потомки шли сверху вниз
NEW headerRow1 { // создаем контейнер - первый ряд
horizontal = TRUE;
MOVE PROPERTY(date(o)) { // переносим свойство даты заказа
// "перегружаем" заголовок свойства в дизайне формы (вместо стандартного)
caption = 'Дата редактируемого заказа';
// задаем подсказку для свойства дата заказа
tooltip = 'Введите сюда дату, когда был сделан заказ';
background = #FF0000; // делаем фон красным
}
MOVE PROPERTY(time(o)) { // переносим свойство времени заказа
foreground = #00FF00; // делаем цвет зеленым
}
MOVE PROPERTY(number(o)) { // переносим свойство номер заказа
// ставим, что пользователю желательно должно показываться 5 символов
charWidth = 5;
}
MOVE PROPERTY(series(o)); // переносим свойство серия заказа
}
NEW headerRow2 {
horizontal = FALSE; // потомки - сверху вниз
}
MOVE PROPERTY(note(o));
}
size = (400, 300); //указываем, что контейнер o.box должен иметь базовый размер 400x300 пикселей
}
// создаем контейнер, в котором будут хранится различные спецификации по заказу
NEW detailPane {
// помечаем, что этот контейнер должен быть панелью закладок, где закладками являются его потомки
tabbed = TRUE;
fill = 1; // отдаём панели закладок всё оставшееся по высоте место
alignment = STRETCH; // и растягиваем её на всю ширину контейнера
// добавляем контейнер с строками заказа как одну из закладок верхней панели
MOVE BOX(d) {
caption = 'Строки'; // задаем заголовок панели закладки
// делаем, чтобы колонка с номером строки никогда не могла иметь фокус
PROPERTY(index(d)) { focusable = FALSE; }
GRID(d) {
// делаем, чтобы по умолчанию фокус при открытии формы устанавливался на таблицу строк
defaultComponent = TRUE;
}
}
MOVE BOX(s) { // добавляем контейнер с итогами по sku как одну из закладок detailPane
caption = 'Подбор';
}
}
}
}
// разбиваем определение формы на две инструкции (вторую инструкцию можно перенести в другой модуль)
DESIGN order {
// убираем из иерархии контейнер с кнопками печати и экспорта в xls, тем самым делая их невидимыми
REMOVE TOOLBARLEFT;
}
На выходе получаем следующую форму:
