Руководство программиста в Photon (953920), страница 53
Текст из файла (страница 53)
Чтобы обойти эту проблему, Вы можете использовать функцию PfQueryFonts(), чтобы определить, какие шрифты доступны, и обеспечить информацию, требующуюся для построения имени основы. Эта функция запрашивает сервер шрифтов Photon'а и защищает Вас от будущих изменений. Давайте начнём с параметров функции PfQueryFonts() – а затем рассмотрим образец программного кода, в котором из данных, возвращаемых функцией, извлекается имя основы. Сама функция выглядит подобным образом:
PfQueryFonts (long symbol,
unsigned flags,
FontDetails list[],
int n );
Её аргументами являются:
symbol | Ключ поиска для Photon'овского меенджера шрифтов. Функция ищет шрифты, которые включают этот символ, и отбрасывает те, которые его не имеют. Например, символ пробела в Unicode (0x0020) доступен почти во всех шрифтах. С другой стороны, задание символа "é" (в Unicode код символа 0х00С9) существенно сужает выбор шрифтов. И конечно, задание японского символа приведёт к отбору только японских шрифтов. Список символов см. в PkKeyDef.h или в ISO/EIC 10646-1. Чтобы включить все доступные шрифты, используйте константу PHFONT_ALL_SYMBOLS. |
flags | Предлагает другой способ сужения круга поиска. Возможными значениями этого параметра являются:
|
list[] | Массив, который Photon'овский менеджер шрифтов заполняет для Вас. Вы должны объявить структуру FontDetails, описанную ниже. |
n | Число элементов, доступных в списочном массиве. |
Если функция PfQueryFonts() завершилась успешно, она возвращает число доступных шрифтов, совпавших с заданным критерием отбора. В противном случае она возвращает -1.
Если n равно 0 и list равен NULL, функция PfQueryFonts() возвращает число совпавших шрифтов, но не пытается заполнять список. Вы можете использовать эту возможность для определения количества элементов при выделении памяти под список.
Структура FontDetails
После получения списка шрифтов Вы должны проверить в нём структуру FontDetails, чтобы найти нужный Вам шрифт и определить строку для использования её в качестве имени основы. Структура FontDetails определена в <photon/Pf.h> следующим образом:
typedef struct {
FontDescription desc;
FontName stem;
short losize;
short hisize;
unsigned short flags;
} FontDetails;
Для наших целей наиболее интересны элементы desc и stem, но давайте рассмотрим их все:
desc | Имя лигатуры или полное описательное имя шрифта, такое как "Helvetica" или "Charter". |
stem | Краткая форма. Она предоставляет часть имени основы, используемую вызовами API Photon'а. Например, "helv" и "char" соответствуют "Helvetica" и "Charter". |
losize | Минимальный возможный размер шрифта в пунктах, скажем 4. |
hisize | Наибольший возможный размер шрифта. Если и losize и hisize равны 0, то шрифт масштабируемый. |
flags | Возможные значения:
|
Генерирование имён шрифтов
Как описано выше, Photon'овский API требует для идентификации шрифта имя основы, но если Вы хотите быть гибким, можете использовать лигатурное имя шрифта.
Простейшим способом получения имени основы, задав лигатурное имя шрифта, желаемый размер в пунктах и стиль, является вызовом функции PfGenerateFontName(). Она создаёт в предоставляемом Вами буфере уникальное имя основы для шрифта. (Вы можете использовать этот подход, даже если Вы не используете функцию PfQueryFonts() для отыскания всех доступных шрифтов). Прототип этой функции следующий:
char * PfGenerateFontName(
char const * pkcDescription,
uint32_t kuiFlags,
uint32_t kuiSize,
char * pcBuff );
Если функция PfGenerateFontName() завершилась успешно, она возвращает указатель на буфер; в случае неудачи возвращается NULL.
Мы определили для Вас тип данных FontName для использования в буфере, переданном функции PfGenerateFontName(). Это массив размером MAX_FONT_TAG. Для успешного программирования шрифта не используйте буфер хранения идентификатора шрифта размером меньшим, чем FontName. Вот вызов функции PtAlert() – такой же, как показан выше, но на этот раз используется вызов PfGenerateFontName():
char Helvetica14[MAX_FONT_TAG];
if ( PfGenerateFontName("Helvetica", 0, 14, Helvetica14) = = NULL ) {
/* Не удалось найти шрифт! */
...
}
answer = PtAlert( base_wgt, NULL, "File Not Saved", NULL, "File has not been saved.\nSave it?",
Helvetica14, 3, btns, NULL, 1, 3, Pt_MODAL );
Теперь то, что мы рассматривали по кусочкам, просто чётко следует по пунктам, необходимым для сборки корректного имени основы для данного шрифта.
Имейте в виду следующие соображения:
-
Используйте буфер FontName для размещения в нём имени основы.
-
Поиск шрифта основан на имени лигатуры (т.е. члена desc его входа FontDetails), а не на имени основы stem.
Вы, вероятно, захотите выполнить эту работу в инициализирующей функции Вашего приложения, или, возможно, в установочной функции базового окна. Определите буфер FontName как глобальную переменную; Вы сможете затем использовать это имя в Вашем приложении по мере необходимости.
Вот простая функция инициализации приложения:
/*****************************
*** Глобальные переменные ***
*****************************/
FontName GcaCharter14Bold;
int fcnAppInit( int argc, char *argv[] ) {
/* Локальные переменные */
FontDetails tsFontList [nFONTLIST_SIZE];
short sCurrFont = 0;
char caBuff[20];
/* Получение описания доступных шрифтов */
if (PfQueryFonts (PHFONT_ALL_SYMBOLS, PHFONT_ALL_FONTS,
tsFontList, nFONTLIST_SIZE) = = -1) {
perror ("PfQueryFonts() неудача: ");
return (Pt_CONTINUE);
}
/* Поиск среди них шрифта, совпадающего с нашими спецификациями */
for (sCurrFont = 0; sCurrFont < nFONTLIST_SIZE; sCurrFont++) {
if ( !strcmp (tsFontList[sCurrFont].desc, "Charter")) break; /* мы нашли его */
}
/* Переполнение проверки */
if (sCurrFont == nFONTLIST_SIZE) {
/* проверка на частичное совпадение */
for (sCurrFont = 0; sCurrFont < nFONTLIST_SIZE; sCurrFont++) {
if ( !strncmp (tsFontList[sCurrFont].desc, "Charter", strlen ("Charter")))
break; /* найдено частичное совпадение */
}
if (sCurrFont == nFONTLIST_SIZE) {
printf ("шрифта Charter нет в %d проверенных шрифтах.\n", sCurrFont);
return (Pt_CONTINUE);
}
else printf ("Используется частичное совпадение -- 'Charter'.\n");
}
/* Имеет ли он жирный вариант? */
if (!(tsFontList[sCurrFont].flags & PHFONT_INFO_BOLD)) {
printf ("Charter не доступен как жирный.\n");
return (Pt_CONTINUE);
}
/* Доступен ли 14-пунктый? */
if ( !( (tsFontList[sCurrFont].losize = = tsFontList[sCurrFont].hisize = = 0)
/* пропорциональный шрифт – а он может быть изображён в 14 пунктов */
||
( (tsFontList[sCurrFont].losize <= 14 )
&&
(tsFontList[sCurrFont].hisize >= 14 ) ) ) )
/* 14-пунктный умещается между наименьшим и наибольшим доступными размерами */
{
printf ("шрифт Charter не доступен как 14-пунктый.\n");
return (Pt_CONTINUE);
}
/* Генерирование имени основы */
if (PfGenerateFontName( tsFontList[sCurrFont].desc,
PF_STYLE_BOLD, 14, GcaCharter14Bol) = = NULL) {
perror ("PfGenerateFontName() неудача: ");
return (Pt_CONTINUE);
}
/* Теперь Вы можете использовать GcaCharter14Bold как аргумент в PtAlert(), etc. */
/* предотвращает предупреждения (варнинги) об отсутствии ссылок */
argc = argc, argv = argv;
return( Pt_CONTINUE );
} // Функции fcnAppInit()
Чтобы вышеприведенный код работал, Вы должны объявить в глобальном хеадер-файле приложения нижеследующую информацию. Чтобы это сделать, используйте диалог PhAB'а "Startup Info/Modules" (доступный из меню "Application").
/*******************************************
*** определённые пользователем константы ***
*******************************************/
#define nFONTLIST_SIZE 100 /* просто случайно выбранный размер */
/*****************************
*** глобальные переменные ***
******************************/
extern FontName GcaCharter14Bold;
Вы можете избежать использования заданного размера списка, вызвав функцию PfQueryFonts() с параметром n, установленным в 0, и параметром list – в NULL. Если Вы так сделаете, функция PfQueryFonts() вернёт количество совпавших шрифтов, но не будет пытаться заполнить список. Вы можете использовать эту возможность для определения числа записей при выделении памяти.
Помните о том, что определить этот хеадер-файл надо перед тем, как Вы начнёте добавлять ответные реакции и установочные функции – в этом случае это будет автоматически включено как #define. Если Вы забудете сделать это, Вам придётся вернуться назад и добавить оператор ручками. Более полно см. раздел "Задание глобального хеадер-файла" в главе "Работа с приложениями".
И, наконец, вот пример ответной реакции, которая использует нашу строку с именем основы:
int fcnbase_btn_showdlg_ActivateCB( PtWidget_t *widget,
ApInfo_t *apinfo, PtCallbackInfo_t *cbinfo ) {
/* Эта ответная реакция используется для запуска диалогового окна
с целью поупражняться с глобальной переменной GcaCharter14Bold */
PtNotice (ABW_base, NULL, "Демонстрация шрифта ", NULL,
"Это написано 14-пунктовым жирным шрифтом Charter",
GcaCharter14Bold, "OK", NULL, 0);
/* предотвращает предупреждения (варнинги) об отсутствии ссылок */
widget = widget, apinfo = apinfo, cbinfo = cbinfo;
return( Pt_CONTINUE );
}
Написание текста в прямоугольной области
Написание текста в прямоугольнике заданного размера может оказаться непростым делом, если неизвестен размер строки. Рассмотрим прямоугольник фиксированных размеров, например, ячейку электронной таблицы. Как вы определите, сколько символов можно успешно отобразить в этой ячейке без отсечения? Вызовите функцию PfExtentTextToRect(). Передайте ей отсекающий прямоугольник, идентификатор шрифта, строку, максимальное число байтов в строке, и она сообщит Вам число символов и занимаемое ими пространство, которые уменьшаются внутри отсекающего прямоугольника. Это полезно для размещения многоточий (...) после обрезанной строки и недопущения частично обрезанных символов. В настоящее время эта функция поддерживает отсечение только по горизонтальной оси.
Вот пример:
/* PfExtentTextToRect */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Ap.h>
#include <Ph.h>
#include <Pt.h>
#include <errno.h>
PtWidget_t * pwndMain = NULL, * pbtn = NULL, * pobjRaw = NULL;