libGUI – это библиотека GUI компонентов для операционной системы KolibriOS.
GUI компонент сосотоит из двух элементов – структуры Control, содержащей информацию о GUI компоненте, и обработчика контрола. Тоесть функции, которая рисует GUI компонент и определяет его поведение в зависимости от состояний: мыши, клавиатуры и сообщений получаемых от программы.
Control представляет из себя структуру с общим заголовком в 44 байта. Дальше идут поля специфичные для данного типа GUI компонента. Какие это будут поля - определяет программист, пишущий обработчик GUI компонента. Также в контроле могут храниться переменные, которые могут содержать какие-то данные необходимые для работы обработчика компонента.
Общий заголовок контрола состоит из следующих полей:
struc CONTROL
{
.ctrl_proc rd 1
.ctrl_fd rd 1
.ctrl_bk rd 1
.child_fd rd 1
.child_bk rd 1
.parend rd 1
.ctrl_x rd 1
.ctrl_y rd 1
.ctrl_sizex rd 1
.ctrl_sizey rd 1
.ctrl_ID rd 1
}
ctrl_proc – это поле содержит адрес обработчика для GUI компонента. Поля: ctrl_fd , ctrl_bk, child_fd, child_bk, необходимы для организации контролов в двусвязные списки. Контролы могут организовываться в виде дерева из списков, примерно так же как это происходит с каталогами. Эти поля используются только библиотекой libGUI поэтому их нельзя использовать(в них нельзя писать).
parend – это поле содержит указатель на контрол, который является родителем для данного контрола. Если провести аналогию с каталогами, то parend – это корневой каталог. А все дочерние элементы parend-а – это подкаталоги в корневом каталоге. parend указывает на область памяти размером в 44 байта(размер структуры control). При инициализации программы эту область памяти необходимо обнулить(можно просто создать массив, заполненный нулями), чтобы невозникло ошибок в работе библиотеки.
ctrl_x – это x координата контрола, отсчитываемая от верхнего левого угла клиентской области окна. Для пермещения контрола внутри онка нужно менять содержимое координаты x именно в этом поле.
ctrl_y – это y координата контрола, отсчитываемая от верхнего левого угла клиентской области окна. Для пермещения контрола внутри окна нужно менять содержимое координаты y именно в этом поле.
ctrl_sizex - размер GUI компонента по оси x.
ctrl_sizey - размер GUI компонента по оси y.
ctrl_ID - идентификатор контрола. Этот параметр задается библиотекой и его нельзя изменять(нельзя писать в это поле).
Для создания GUI компонента в libGUI используются функции , имеющие название craete_название_контрола. Итак, что представляют из себя эти функции создания контрола.
В libGUI принят стандарт, согласно которому, все параметры функциям работы с котролами передаются через стек. Функции, создающей контрол, передаются два параметра(в порядке их занесения в стек): указатель на parend-а, указатель на структуру с данными для данного GUI компонента . Что это будут за данные – решает программист, пишущий данный компонент. Но эти данные обязательно должны содержать информации о координатах и размере контрола.
После того, как через стек переданы указатели на необходимые данные, необходимо создать контрол. Для этого в libGUI есть функция craete_control . Для ускорения работы библиотеки, параметры для этой функции передаются через регистры. Регистр eax содержит количество байт которые нужно зарезервировать под структуру control . Рассчёт производиться по формуле: 44 + количество байт для данных GUI компонента. В регистре ebx передаётся указатель на родителя. После вызова craete_control в регистре eax передаётся указатель на структуру control с заполненными системными(для библиотеки) полями. Теперь нужно занести информацию в контрол. По соответствующим смещениям, описанным выше, необходимо записать: указатель на адрес обработчика данного GUI компонента, координаты компонента, размер компонента. А также необходимо скопировать данные, специфичные для данного компонента, по адресу указатель_на_контрол+44. То есть все необходимые для работы данные будут храниться за системными(за заголовком control). После завершения этих действий, функция создания компонента должна передать через стек указатель на созданный контрол с заполненными полями.
Для передачи информации контролам, в библиотеке используется система сообщений. Сообщение представляет из себя указатель на область памяти размером 16 байт.
Первые 4 байта резервируются под тип сообщения. Всего возможно 5 типов сообщений: сообщение на полную перерисовку(код 1), сообщение от клавиатуры(код 2), специализированное сообщение(код 3), сообщение от мыши(код 6), сообщение на удаление контрола(код -1).
Специализированное сообщение необходимо в тех случаях, когда нужно перерисовать отдельный контрол в какой-то момент времени(например полоса прогресса в ProgressBar-е).Или для других ситуаций(например для отключения контрола).
Следующие 4 байта в сообщении зависят от типа сообщения. Если было сообщение 1, то следующие байты для работы не требуются. Если было сообщение 2, то последующие 4 байта – это код нажатой клавиши(scan код или ascii код). В сообщении 3 последующие байты тоже не нужны. Для сообщения 6 последующие значения – это координаты x и y мыши, а также состояния кнопок мыши, полученные от функции 37 под функции 2.
Сообщения контролы получают от программы. Для передачи сообщений из программы к контролам, в библиотеке имеется функция send_message. В качестве параметров ей передаётся указатель на родителя для контролов и указатель на сообщение. Эта функция рассылает сообщения контролам, являющимся дочерними для данного родителя(рассылка сообщения представляет собой вызов обработчика контрола с передачей ему сообщения через стек). В свою очередь, если дочерние контролы являются родителями для каких-то других контролов, то обработчики дочерних контролов, рассылают сообщения своим дочерним контролам.
Сообщения от клавиатуры, доступны не всем контролам, а только активным. Контрол считается активным, если указатель мыши находиться над ним и , если по нему был сделан щелчок мыши. Таким образом, если вы набираете текст в одном из EditBox-ов, то сообщения от клавиатуры будет получать именно этот GUI компонент, а не какой-то другой.
Для удаления контрола в libGUI есть функция destroy_control. Эта функция удаляет контрол из списка дочерних контролов того родителя(parend-а) к которому принадлежит и высвобождает память из под контрола. В качестве параметра этой функции передаётся указатель на контрол(тот самый указатель, который возвращает функция craete_название_контрола). При удалении контрола , обработчику контрола посылается сообщение с кодом -1. Если у контрола есть дочерние контролы, то обработчик контрола рассылает им сообщение с кодом -1 . Если же у контрола нет дочерних контролов, то происходит просто возвращение из обработчика контрола.
Button – это кнопка. Для создания этого компонента используется функция craete_button. Рассмотрим, какие параметры необходимо передавать этой функции для создания кнопки. Структура с данными для кнопки имеет вид:
struc BUTTON { .type db 1 .flag db 1 .x dw 1 .y dw 1 .width dw 1 .height dw 1 .image dd 1 .imageX dw 1 .imageY dw 1 .imageSizeX dw 1 .imageSizeY dw 1 .transparentColor dd 1 .text dd 1 .textX dw 1 .textY dw 1 .textcolor dd 1 .color1 dd 1 .color2 dd 1 .mouseX dw 1 .mouseY dw 1 }
Поле type определяет тип кнопки и задаёт некоторые параметры инициализации.
Установка старшего бита (7-го ) разрешает полную перерисовку кнопки.Устанавливайте этот бит в 1 при инициализации кнопки.
Установка четвёртого бита определяет внешний вид кнопки. Если бит установлен в 1 , то будет нарисована объёмная кнопка с градиентными заливками. Иначе будет нарисована плоская кнопка.
При установке нулевого бита рисуется кнопка с текстом. Текст автоматически центрируется на кнопке. Для рисования кнопки с текстом необходимо занести в поле text указатель на строку с текстом(строка обязательно должна заканчиваться нулём). А в поле textcolor – цвет текста.
Установка первого бита задаёт кнопку с картинкой. Картинка автоматически центрируется на кнопке. Для рисования картинки на кнопке необходимо занести в поле image указатель на картинку. Также необходимо задать размер картинки в полях imageSizeX и imageSizeY. И ещё один дополнительный параметер - цвет прозрачности для картики transparentColor.
Второй бит ответственен за одновременный вывод картинки и текста на кнопку. В этом случае нужно задавать координаты текста и координаты картинки на кнопке. Координаты задаются от левого верхнего угла кнопки. textX и textY задают координаты текста, а imageX и imageY координаты картинки.
Третий бит отключает рисование кнопки, но кнопка всёравно существует и реагирует на наведение и нажатие машью.Если установить этот бит совместно с битами: 0, или 1, или 2, то всёравно будут рисоваться текст, картинка, или то и другое вместе. Это полезное свойство можно использовать для создания других компонентов.
Поле color1 задаёт цвета компонента(на основе него генерируются другие цвета). Этот цвет лучше всего брать из стандартной таблицы цветов, которая загружается 48 системной функцией KolibriOS. А потом нужно взять третий цвет из этой таблицы(смещение 8).
В полях x и y задаются координаты кнопки. В поле width ширина кнопки(размер по оси x ), в поле height высота кнопки(размер по y ).
Остальные поля структуры используются для хранения данных контрола во время работы.
Данные о состоянии кнопки записываются в поле flag контрола. Необходимо помнить, что данные во всех контролах начинаются после заголовка контрола, длиной 44 байта. То есть для кнопки поле flag будет иметь смещение 45 относительно начала контрола.Если в этом поле установлен 0-й бит, значит курсор мыши находиться над кнопкой. Если установлен 0-й и 1-й биты, значит курсор находиться над кнопкой и кнопка нажата. Используя эту информацию в программе, можно сделать, чтобы была реакция на нажатие или отпускание кнопки.
Scroler – это полоса прокрутки. Этот компонент создаётся функцией craete_scroller. В качестве параметра ему необходимо передавать следующую структуру:
struc SCROLLER
{ .type rb 1 .x rw 1 .y rw 1 .length rw 1 .color1 rd 1 .size rd 1 .pos rd 1
.mouseX rw 1
.mouseY rw 1
.buttons_flags rw 1
.ChildButtton1 rd 1
.ChildButtton2 rd 1
}
Поля: x, y, color1 имеют тот-же смысл, что и в GUI компоненте Button(см. выше).
Поле type задаёт тип скроллера. Биты 7 и 4 выполняют ту же самую роль, что и для кнопок. Биты 6 и 5 нужно обязательно устанавливать в 1 при инициализации скроллера. При установке 0-го бита рисуется вертикальный скролер, а если установлен 1-ый бит, то горизонтальный.
Поле length задаёт длину скролера в пикселах. По краям скролера находятся кнопки. Каждая из них имеет размер 16x16 пикселов. Минимально возможный размер ползунка – 4 пиксела. Поэтому минимальный размер скроллера 36 пикселей.
Поле size задаёт размер ползунка скролера. Эта величина вещественная и меняется от 0 до 1. Нулю соответствует минимальный размер ползунка(4 пиксела), а 1 – максимальный(от одной кнопки до другой).
Поле pos задаёт позицию ползунка на scroller-е. Эта величина тоже вещественная и меняется от 0 до 1. Если записать в это поле значение, то ползунок установиться в соответствующую позицию. А если двигать ползунок мышью, то содержимое этого поля будет меняться в зависимости от положения ползунка.
В поле buttons_flags храняться состояния кнопок мыши. Первой кнопкой мыши считается та, которая ближе всего к точке с координатами (x,y) (к точке, в которой рисуется скролер). Если установлен нулевой бит в этом поле, то значит нажата первая кнопка, а если 4-ый бит , то вторая.
Поля: ChildButton1, ChildButton2 хранят адреса контролов дочерних кнопок скролера. Эти поля используются обработчиком скролера и их нельзя изменять.
Для работы со скролером, необходимо читать/писать из/в поля size или pos. Адреса(смещения) соответствующих полей контрола равны : 44 + смещение в поле структуры.
Компонент Bookmark необходим в тех случаях, когда нужно работать с большим количеством разнообразных контролов. Для создания закладки в библиотеке используется функция craete_bookmark. Так как закладок может быть много и они могут встречаться в разных конфигурациях, то структура с данными для закладки, имеет переменную длину. Но первые несколько полей закладки – стандартны. Разберём сначала эти поля.
struc BOOKMARK { .type rb 1 .flag rb 1 .x rd 1 .y rd 1 .sizex rd 1 .sizey rd 1 .color_1 rd 1 .reserved rd 1 .color2 rd 1 ......................... }
Для того, чтобы инициализировать закладку в поле type необходимо установить 7-ой бит. Больше никаких битов в этом поле устанавливать не нужно.
Смысл полей: x, y, sizex, sizey, понятен интуитивно.
Поле color_1 задаёт цвет закладки. А поле color2 цвет текста на закладке.
Дальше в закладке начинаются поля переменной длины. Каждое поле по 4 байта. Первым идёт поле, содержащее общее число строк закладок. Под строкой понимается ряд из закладок. Дальше идёт поле содержащее общее количество закладок в первой строке, потом поле содержащее количество закладок во второй строке, и так до поля с информацией о самой последней строке. Рассмотрим пример. Пусть у нас есть закладка с тремя строками. В первой строке 3 закладки, во второй 2, а в третьей 1. Тогда столбец(поля структуры) из 4-х байтовых чисел будет выглядеть так:
3 |
3 |
2 |
1 |
Дальше идёт последовательно друг за другом информация о каждой закладке. Закладки перечисляются с лева на право, сверху в низ. То есть первой закладкой будут закладка верхнего ряда, находящаяся у левого края, а последней закладка нижнего ряда находящаяся у правого края.
Информация о каждой закладке имеет переменную длину(зависит от числа контролов на закладке) и в общем виде выглядит так:
указатель на текст для n-ой закладки количество контролов на n-ой закладке тип 1-го контрола на n-ой закладке указатель на структуру с данными для 1-го контрола на n-ой закладке ....................................................................................................... ....................................................................................................... тип последнего контрола на n-ой закладке указатель на структуру с данными для последнего контрола на n-ой закладке
Тип контрола определяется его порядковым номером в библиотеке libGUI. Для кнопки этот номер 1, для скроллера - 2 и т.д.
После того, как вы передали функции craete_Bookmark структуру с данными, эта функция создаёт контролы для закладок. Эти контролы являются дочерними для закладки. Указатели на контролы заносятся в поля , где раньше были указатели на данные для дочерних контролов. То есть теперь в поле :
указатель на структуру с данными для k-го контрола на n-ой закладке
будет указатель на созданный контрол с соответствующим типом . И для того, чтобы писать/читать данные из дочерних контролов нужно получить указатель на этот контрол. Для этого необходимо взять указатель на контрол закладки, прибавить 44 + смещение соответствующего поля в структуре с данными(для лучшего понимания смотрите примеры, прилагающиеся к библиотеке). После того, как указатель на дочерний контрол получен, извлечение информации из него нужно производить соответственно типу этого контрола.
image – это компонент для работы с изображениями. Для создания контрола этого типа в libGUI используется функция craete_image. Структура с данными для этой функции имеет вид:
struc IMAGE { .type rb 1 .flag rb 1 .color rd 1 .x rd 1 .y rd 1 .sizex rd 1 .sizey rd 1 .pointer rd 1 }
По умолчанию в поле type ничего устанавливать не нужно. Но, если вы хотите, чтобы этот контрол реагировал на специализированные сообщения, то необходимо установить 0-ой бит . После получения специализированного сообщения контрол перерисовывается и сбрасывает 0 бит. То есть каждый раз перед посылкой специализированного сообщения нужно устанавливать 0-ой бит. Этот бит служит ловушкой для специализированных сообщений.
Поля x и y задают координаты картинки. sizex, sizey размер картинки.
pointer – указатель на область памяти, где находиться картика в формате RRGGBB(3 байта на пиксель). Остальные поля зарезервированы для работы обработчика данного контрола.
Если вы хотите , чтобы компонент реагировал на специализированные сообщения, то устанавливайте 0-ой бит по адресу(относительно начала контрола) 44 + смещение поля type.
text – это компонент для работы с текстом. Для создания этого компонента используется функция craete_text. Структура с данными для этой функции имеет вид:
struc TEXT { .type rb 1 .flag rb 1 .color rd 1 .x rd 1 .y rd 1 .length rd 1 .pointer rd 1 }
По умолчанию в поле type никаких битов устанавливать не нужно. Но если вы хотите, чтобы контрол реагировал на специализированные сообщения, то нужно устанавливать 2-ой бит, каждый раз перед посылкой специализированного сообщения. Установка этого бита включает ловушку для специализированных сообщений. После приёма специализированного сообщения 2-ой бит сбрасывается. Также в этом контроле имеется возможность отключать от рисовку текста. Для этого нужно установит 0-й бит. Эта возможность может пригодиться, если вы используете переменное число дочерних контролов в таких контролах, как Bookmark где нельзя динамически менять число дочерних контролов(все дочерние контролы создаются один раз – при инициализации компонента).
В поле pointer заноситься указатель на текст, а в поле length длина текста(в символах).
Если вы хотите , чтобы компонент реагировал на специализированные сообщения, то устанавливайте 2-ой бит по адресу(относительно начала контрола) 44 + смещение поля type. А если хотите, чтобы контрол не отрисовывался, то устанавливайте 0-й бит по этому же адресу.
Компонент Number – это компонент для вывода чисел(как целых, так и вещественных). Этот компонент создаётся при помощи функции craete_number. Структура с данными для этого контрола имеет вид:
struc NUMBER { .type rb 1 .flag rb 1 .color rd 1 .x rd 1 .y rd 1 .number rd 1 .parameters rd 1 }
Рассмотрим поле type. Установка 0-го бита в этом поле запрещает рисование контрола. 1- й бит ответственен за тип числа. Если этот бит не установлен, то будет выводиться целое число, а если установлен, то число с «плавающей» запятой. Установка 2-го бита включает ловушку для специализированных сообщений. После приёма специализированного сообщения 2-ой бит сбрасывается.
Поля x и y задают координаты компонента. color – определяет цвет числа. В поле number записывается число, которое требуется выводить(целое или вещественное).
Поле parameters определяет формат выводимого числа. Если выводиться целое число, то старшие 16 бит этого числа задают количество знаков для вывода числа. Если выводиться число с плавающей запятой, то старшие 16 бит задают число знаков целой части вещественного числа, а младшие 16 бит число знаков после запятой. Помните, что максимальный размер вещественного числа ограничен 32 битами.
Если вы хотите , чтобы компонент реагировал на специализированные сообщения, то устанавливайте 2-ой бит по адресу(относительно начала контрола) 44 + смещение поля type. А если хотите, чтобы контрол не отрисовывался, то устанавливайте 0-й бит по этому же адресу.
CheckBox – это компонент для выбора опций. Он позволяет включать или выключать действие какой-то опции. Этот компонент создаётся функцией craete_check_box. В качестве параметра этой функции передаётся следующая структура:
struc CHECKBOX { .ch_flags rw 1 .ch_left rw 1 .ch_top rw 1 .ch_text_margin rd 1 .ch_size rd 1 .ch_size_2 rw 1 .ch_size_3 rw 1 .ch_color rd 1 .ch_border_color rd 1 .ch_text_color rd 1 .ch_text_pt rd 1 .ch_text_length rw 1 .mouseX rd 1 .mouseY rd 1 }
Рассмотрим поле ch_flags. Если в этом поле 0, то рисуется неактивный CheckBox. А если установить 1-й бит, то активный.
ch_left – координата компонента по оси x.
ch_top – координата компонента размер по оси y.
ch_size – размер компонента (он квадратный).
ch_color – цвет внутренней части компонента.
сh_border_color – цвет рамки компонента.
ch_text_color – цвет текста.
ch_text_ptr – указатель на текст для CheckBox-а.
ch_text_length – длина текста(в символах).
Для получения данных о состоянии CheckBox - а, необходимо прочитать его состояние из поля flags. и по состоянию описанных выше битов, проверять состояние компонента. В котроле это поле находиться по смещению(относительно начала контрола) 44 + смещение поля flags в структуре.
Описание GUI компонента EditBox.
EditBox – это компонент для вввода: тектса, чисел. Этот компонент создаётся функцией craete_edit_box. В качестве параметра этой функции передаётся следующая структура:
struc EDITBOX
{ .ed_width rd 1 .ed_left rd 1 .ed_top rd 1 .ed_color rd 1 .ed_focus_border_color rd 1 .ed_blur_border_color rd 1 .ed_text_color rd 1 .ed_max rd 1 .ed_text rd 1 .ed_flags rw 1 .ed_size rd 1 .ed_pos rd 1 .ed_offset rd 1 .cl_curs_x rd 1 .cl_curs_y rd 1 .ed_shift_pos rd 1 .ed_shift_pos_old rd 1 .ed_height r rd 1 .mouseX rd 1 .mouseY rd 1
}
Рассмотрим поле ........
.............
Работа с GUI компонентом EditBox.
Для получения данных введённых в EditBox-е необходимо .......
.............