В этой статье Вы найдете описание частей элементов управления и как элементы управления управляют скрытием их невидимых частей, а так же скрытием невидимых частей дочерних элементов управления.
Посмотрите на картинку ниже. На ней видны GroupBox с Memo внутри. И хотя элементы управления могут иметь разные формы, все они могут быть вписаны в прямоугольник называемый прямоугольником элемента управления. У элементов управления могут быть разные эффекты. На картинке ниже есть эффект - тень. Прямоугольник в котором помещается элемент управления и его эффекты, называется прямоугольником рисования. Эффекты обычно представляют собой украшения, они не отвечают на события от пользователя такие как клики. Когда у элемента управления есть дочерние элементы управления, обычно, как показано ниже, дочерние элементы управления могут занимать не всю часть родительского. Эта часть называется клиентским прямоугольником. Все выравнивания происходят только внутри клиентского прямоугольника элемента управления. По умолчания у CControl, от которого наследуются все элементы управления, все прямоугольники одинаковы. При создании элемента управления Вам нужно указывать отличные прямоугольники для клиентской части и прямоугольника рисования. Это можно сделать переопределив методы getClientRect и getRenderRect класса CControl. Все координаты считаются относительно прямоугольника элемента управления. Например, если у Вашего элемента управления есть тень с радиусом размытия 5 пикселей и она смещена на 10 пикселей по осям X и Y, тогда Вам нужно переопределить метод getRenderRect и вернуть в нем return Rect{0, 0, getWidth() + 5 + 10, getHeight() + 5 + 10};
. Элементы управления используют такую же систему координат как и форма. Ось Y направлена вниз.
Под локальным обрезанием невидимых частей мы подразумеваем скрытие некоторых частей элементов управления, когда он рисует сам себя. Это может быть достигнуто разными способами. Есть два ниболее часто используемых элементами управления фреймверка. Первый используется в случае когда видимая зона предстваляет собой прямоугольник. В этом случае создается временная картинка(или текстура - ITexture) с необходимым размером и рисование происходит уже на ней. После этого отрисовывается уже сама эта временная картинка. Второй метод - это так называемое "обрезание блоком". Под блоком мы подразумеваем специальную фигуру. Эта фигура имеет координаты границ: левая, верхняя, правая и нижняя. Она так же имеет ширину границ и радиусы углов. Если граница не нужна, то предполагаем ее ширину равной нулю. То же самое для скругленных углов. Если угол не круглый, его радиус равен нулю. Большинство методов рисования рендера IRenderer поддерживают обрезание блоком. Эту функцию можно активировать методом ActivateBlock()
с указанием нужного блока. Например, можно рисовать только внутри или только на какой-то границе блока. Взгляните на следующую картинку. У панели есть один скругленный угол и она отрисовывается с примененным обрезанием блоком так что только часть, которая находится внутри блока(представляющего собой прямоугольник элемента управления за вычетом границ и пространства между ними и содержимым, а так же скругленного угла), рисуется(Вы можете видеть, что заголовок обрезан немного в районе правого нижнего угла).
Глобальное отсечение невидимых частей применяется к элементам управления в целом. Оно реализовано с помощью так называемых "масок". Используя IRenderer Вы можете рисовать не только на форме, но и на других картинках - текстурах. Вы можете создавать текстуры и устанавливать их в качестве цели рисования рендера с помощью метода ActivateTarget. Маска - это текстура применяющаяся ко всем методам рисования рендера пока активна. Только альфа-канал или канал прозрачности текстуры маски используется. Если его значение равно нулю, то ничего не рисуется, если больше нуля - тогда значение пикселя умножается на значение альфа канала маски. Маски кумулятивны. Можно добавлять несколько масок к рендеру. Это используется при рисовании дочерних элементов управления для скрытия тех их частей, которые находятся за границами родительских элементов управления. Посмотрите на картинку ниже. На ней видно дочерний элемент управления Button правильно обрезанный клиентской частью родительского элемента управления GroupBox. Это сделано с использованием масок. Когда Вам нужно такое же поведение для Вашего элемента управления, просто нарисуйте маску для клиентской части(с альфа = 255 для видимых частей и 0 для невидимых), активируйте маску используя IRenderer перед рисованием дочерних элементов управления, деактивируйте маску после отрисовки дочерних элементов управления. Вам нужно знать, что дочерние элементы управления рисуются автоматически, но только после отрисовки родительского элемента управления. Так что в уведомлении Вашего элемента управления NotifyOnPaint Вам нужно нарисовать элемент управления, потом нарисовать маску и далее активировать ее. И в уведомлении NotifyOnPaintEnd, которое происходит после отрисовки всех дочерних элементов управления, Вам нужно деактивировать маску. Все стандартные элементы управления имеют возможность включения и выключения маски. У них для этого есть свойство "UseMask". Рекомендуется отключать маску, если Вы уверены, что отсечение не требуется. Не забывайте, каждая операция рисования занимает какое-то время, постарайтесь избегать ненужных операций. По умолчанию маски всех стандартных элементов управления включены.