Руководство программиста в Photon (1037671), страница 53
Текст из файла (страница 53)
«Отображаемое окно» определяет прямоугольную область на экране, где будет отображаться содержимое слоя.
Прокрутка и масштабирование, если поддерживаются слоем, могут осуществляться изменением этих типов «окон». Для перемещения по изображению на поверхности, связанной со слоем необходимо менять координаты «окна-источника». Для масштабирования – менять размеры «окон».
Вам необходимо установить цель действия этих преобразований используя PdSetTargetDevice().
API слоев
Программный интерфейс слоев состоит из:
PtGetLayerCaps() получить информацию о возможностях слоя
PgCreateLayerSurface() создать внеэкранную поверхность, отображаемую слоем
PgSetLayerSurface() отобразить внеэкранную поверхность на слое
PgSetLayerArg() настроить параметры слоя
PgLockLayer() захватить слой для эксклюзивного использования приложением
PgUnlockLayer() снять захват со слоя
PgLayerCaps_t структура данных, описывающая возможности слоя
API слоев в настоящий момент несовместимо с API оверлеев (PgCreateVideoChannel(), PgConfigScalerChannel(), PgNextVideoFrame(), и так далее). Не запускайте одновременно два приложения использующие эти два программные интерфейса.
Учтите:
-
Photon не может рисовать во внеэкранных поверхностях, формат которых отличен от текущего видеорежима. Таким образом может оказаться невозможно использовать функции рисования Photon на внеэкранном онтексте, полученном при помощи PgCreateLayerSurface(). Вместо этого приложение должно использовать PdGetOffscreenContextPtr(), для получения указателя на видеопамять и записывать данные напрямую.
-
Если приложение изменит внеэкранную поверхность основного экрана при помощи PgSetLayerSurface(), Photon всеравно продолжит рисовать в старую внеэкранную поверхность. Приложению необходимо сохранить указатель на старую поверхность и восстановить её как только оно перестанет использовать слой. Как это сделать показано ниже в примере.
Использование слоев
Чтобы использовать возможности слоев вы обычно должны сделать следующее:
-
Используйте PgGetLayerCaps() с постоянно увеличивающимся индексом слоя для определения возможностей оборудования (если вы еще их не знаете). Если PgGetLayerCaps() дает ошибку для любых значений – драйвер не поддерживает слои.
-
Если вы хотите предотвратить использование слоя другими приложениями – используйте PgLockLayer().
-
Создайте поверхности для отображения на слое и внеэкранные контексты – для отображения данных на поверхность при помощи PgCreateLayerSurface().
-
Вызовите PgSetLayerArg() с аргументом Pg_LAYER_ARG_LIST_BEGIN.
-
Вызовите PgSetLayerArg() для установки параметров слоя.
-
Вызовите PgSetLayerSurface() для отображения внеэкранного контекста поверхности на слое.
-
Вызовите PgSetLayerArg() для установки параметров слоя. Вы можете использовать Pg_LAYER_ARG_ACTIVE в качестве аргумента для отображения содержимого слоя на экране.
-
Вызовите PgSetLayerArg() с аргументом Pg_LAYER_ARG_LIST_END.
-
Если формат слоя RGB или PAL8 установите один из контекстов поверхности слоя текущим а затем используйте Pg* - функции для рисования во внеэкранный контекст.
-
Если формат слоя YUV, или подобный – вы чаще всего будете записывать данные непосредственно в буфер (например для воспроизведения видеопотока).
-
Если вы захватили слой для эксклюзивного использования вам необходимо снять блокировку при помощи PgUnlockLayer() прежде, чем ваше приложение выйдет.
Программа, приведенная ниже показывает использование программного интерфейса слоев.
Пример
#include <errno.h>
#include <stdio.h>
#include <Ph.h>
int
FindFormatIndex(int layer, unsigned int format)
{
PgLayerCaps_t caps;
int format_idx = 0;
while (PgGetLayerCaps(layer, format_idx, &caps) != -1) {
if (caps.format == format)
return format_idx;
format_idx++;
}
return -1;
}
int
main(int argc, char **argv)
{
/*
* For best results, these values should match your video mode.
*/
#define LAYER_FORMAT Pg_LAYER_FORMAT_ARGB8888
#define SURFACE_WIDTH 1024
#define SURFACE_HEIGHT 768
struct _Ph_ctrl *ph;
PgLayerCaps_t caps;
PdOffscreenContext_t *surf;
PdOffscreenContext_t *scr = NULL;
PhDrawContext_t *olddc;
PhRid_t driver_rid = -1;
int layer_idx = -1;
int format_idx = -1;
int active = 1;
int i;
/*
* Arguments:
* -d <driver region>
* -l <layer index>
*/
while ((i = getopt(argc, argv, "d:l:")) != -1) {
switch(i) {
case 'd': /* driver region */
driver_rid = atol(optarg);
break;
case 'l': /* layer index */
layer_idx = atoi(optarg);
break;
default:
break;
}
}
if (layer_idx == -1) {
printf("Specify layer index.\n");
exit(-1);
}
if (driver_rid == -1) {
printf("Specify graphics driver region.\n");
exit(-1);
}
ph = PhAttach(NULL, NULL);
if (ph == NULL) {
perror("PhAttach");
exit(-1);
}
if (-1 == PdSetTargetDevice(PhDCGetCurrent(), driver_rid)) {
perror("PdSetTargetDevice");
exit(-1);
}
/* Check if the layer supports the required format */
format_idx = FindFormatIndex(layer_idx, LAYER_FORMAT);
if (format_idx == -1) {
printf("Layer does not support format\n");
exit(-1);
}
/* Get the layer capabilities */
PgGetLayerCaps(layer_idx, format_idx, &caps);
if (caps.caps & Pg_LAYER_CAP_MAIN_DISPLAY) {
/* Save a reference to the current display surface */
scr = PdCreateOffscreenContext(0, 0, 0, Pg_OSC_MAIN_DISPLAY);
}
/* Allocate a surface for the layer */
surf = PgCreateLayerSurface(layer_idx, 0, format_idx,
SURFACE_WIDTH, SURFACE_HEIGHT, Pg_OSC_MEM_PAGE_ALIGN);
if (surf == NULL)
exit(-1);
/* Draw some stuff on the surface */
olddc = PhDCSetCurrent(surf);
PgSetFillColor(Pg_BLACK);
PgDrawIRect(0, 0, SURFACE_WIDTH-1, SURFACE_HEIGHT-1, Pg_DRAW_FILL);
PgSetFillColor(Pg_YELLOW);
PgDrawIRect(0, 0, 100, 100, Pg_DRAW_FILL);
PgSetFillColor(PgRGB(255,180, 0));
PgDrawIRect(70, 80, 600, 500, Pg_DRAW_FILL);
PhDCSetCurrent(olddc);
/* Lock the layer */
if (-1 == PgLockLayer(layer_idx))
exit(-1);
/* Start configuring arguments */
PgSetLayerArg(layer_idx, Pg_LAYER_ARG_LIST_BEGIN, 0, 0);
/* Select the layer format */
PgSetLayerArg(layer_idx, Pg_LAYER_ARG_FORMAT_INDEX,
&format_idx, sizeof(int));
/* This changes the current display surface */
PgSetLayerSurface(layer_idx, 0, surf);
PgSetLayerArg(layer_idx, Pg_LAYER_ARG_ACTIVE,
&active, sizeof(int));
/* Configure other arguments ... */
/* End configuration */
PgSetLayerArg(layer_idx, Pg_LAYER_ARG_LIST_END, 0, 0);
/* Application continues ... */
sleep(3);
/* Finished using layer; Restore the current display surface */
if (caps.caps & Pg_LAYER_CAP_MAIN_DISPLAY) {
PgSetLayerArg(layer_idx, Pg_LAYER_ARG_LIST_BEGIN, 0, 0);
PgSetLayerSurface(layer_idx, 0, scr);
PgSetLayerArg(layer_idx, Pg_LAYER_ARG_LIST_END, 0, 0);
}
PgUnlockLayer(layer_idx);
if (scr) PhDCRelease(scr);
PhDCRelease(surf);
PhDetach(ph);
exit(0);
}
Глава 19. Шрифты
Хотя библиотеки Photon'а и предлагают ряд функций по работе с шрифтами (см. главу "Pf – сервер шрифта" в "Справочнике библиотечных функций Photon'а"), большинство из них являются подпрограммами низкого уровня и, вероятно, Вам не понадобится их использовать. Эта глава описывает основы использования шрифтов.
Эта глава включает:
-
Метрики символа
-
Имена шрифтов
-
Написание текста в прямоугольной области
-
Пропорциональный текст, приводящий к ошибкам восстановления повреждений.
Метрики символа
Давайте начнём с некоторых определений:
Рис. 19-1. Метрики символа
Advance | Продвижение. Величина, на которую продвигается по оси x перо после прорисовки литеры. Это может быть не полная ширина литеры (особенно для курсивного шрифта) для обеспечения кернинга (т.е. создания выносного элемента литеры). |
Ascender | Верхний элемент литеры. Высота от базовой линии до вершины литеры. |
Bearing x or left bearing | Выноска по х или левая выноска. Размер литеры слева оттуда, где символ считается начинающимся. |
Descender | Подстрочный элемент литеры. Высота от низа литеры до базовой линии. |
Extent | Протяжённость литеры. Ширина литеры. Зависит от шрифта, она может включать определённое чистое пространство. |
Origin | Начало. Нижний левый угол литеры. |
X Max | Ширина символа, не включая выноски по х. |
Для экономии времени и памяти, кернинг не поддерживается.
Имена шрифтов
Шрифт идентифицируется по своему имени, которое может иметь одну из следующих форм:
Имя лигатуры (foundry name) | Имя, задаваемое именем лигатуры для идентификации семейства шрифтов, такие как Helvetica, Comic Sans MS или Prima Sans BT. Обратите внимание на использование заглавных букв. Имя лигатуры не включает информацию о стиле (напр., жирный, наклонный) или размере. Это имя является универсальным для всего операционного окружения (напр., X, Photon). |
Имя основы | Уникальный идентификатор, включающий сокращение от имени лигатуры, а также стиль (напр., b, i) и размер. Например, helv12 является именем основы 12-пунктного шрифта Helvetica, а helv12b – имя основы 12-пунктного жирного шрифта Helvetica. |
Чтобы задать шрифт в API Photon'а, обычно используется имя основы. Вы должны рассматривать имена основы как постоянные идентификаторы, а не как модифицируемые строки.
Вы можете жёстко прописать все ссылки на шрифты в приложении Photon'а. Но Ваше приложение может быть более гибким, если Вы используете лигатурное имя, чтобы иметь возможность выбора наилучшего совпадения из всех доступных шрифтов. При таком подходе нет проблемы, если какой-то конкретный шрифт со временем окажется переименован, удалён или перемещён. Например, в следующем вызове функции PtAlert() используется жёстко прописанное имя основы helv14, задающее 14-точечный шрифт Helvetica:
answer = PtAlert(base_wgt, NULL, "File Not Saved", NULL,
"File has not been saved.\nSave it?",
"helv14", 3, btns, NULL, 1, 3, Pt_MODAL );
Доступные имена основы Вы можете получить из имён файлов в ${PHOTON_PATH}/font – просто удалите имеющееся расширение файла (напр., .phf).
Иной способ заключается в том, что если у Вас есть директория $HOME/.ph, просмотреть директорию $HOME/.ph/font/. МикроGUI Photon'а создаёт этот локальный файл только при необходимости, как скажем, когда Вы запускаете утилиту fontadmin (см. "Справочник утилит QNX 6") для создания Вашей собственной персональной конфигурации. Пока локальный файл не создан, микроGUI использует глобальный файл.
Запрос доступных шрифтов
В приведенном выше примере используется сокращённое наименование жёстко прописанного имени основы (helv14). И, как любое приближение, оно допускает компромиссы. Прежде всего имена основы являются объектами для изменений. Что более важно, все версии Photon'овского микроGUI, вплоть до версии 1.13 включительно, позволяют использовать для имени основы не более 16 символов. Этого не всегда достаточно, чтобы дать каждому шрифту уникальную основу. Текущая версия микроGUI Photon'а допускает до 80 символов.
Чтобы обойти эту проблему, Вы можете использовать функцию PfQueryFonts(), чтобы определить, какие шрифты доступны, и обеспечить информацию, требующуюся для построения имени основы. Эта функция запрашивает сервер шрифтов Photon'а и защищает Вас от будущих изменений. Давайте начнём с параметров функции PfQueryFonts() – а затем рассмотрим образец программного кода, в котором из данных, возвращаемых функцией, извлекается имя основы. Сама функция выглядит подобным образом: