}
GetSystemPalette();
return 0;
}
Помимо выбора исходного видеорежима функция SelectInitialDisplayMode() используется для подготовки двух массивов: в первом хранятся сведения о палитровых (palettemode), а во втором — о беспалитровых (nonpalettemode) видеорежимах. Мы воспользуемся этими массивами позднее, при отображении диалогового окна. Когда пользователь выбирает файл с палитровым изображением, в список включаются только палитровые режимы; для беспалитровых режимов дело обстоит аналогично. Обратите внимание — в подготовленные массивы (коллекции структур DisplayModeDescription) включены строки, отображаемые в диалоговом окне.
Функция SelectInitialDisplayMode() также используется для вызова функции GetSystemPalette(), создающей палитру DirectDraw на базе системной палитры. Функция GetSystemPalette() выглядит так:
void BmpViewWin::GetSystemPalette() {
PALETTEENTRY pe[256];
HDC dc = ::GetDC(0);
if (GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE) {
GetSystemPaletteEntries(dc, 0, 256, pe);
ddraw2->CreatePalette(DDPCAPS_8BIT, pe, &syspal, 0);
}
::ReleaseDC(0, dc);
}
С помощью функции Win32 GetSystemPaletteEntries() мы получаем содержимое текущей палитры Windows и создаем по ее образцу палитру DirectDraw функцией CreatePalette() интерфейса DirectDraw. Указатель на созданную палитру syspal позднее будет применяться для восстановления системной палитры; это обеспечивает правильное отображение диалоговых окон Windows в 8-битных видеорежимах.
Следующий шаг инициализации приложения, заслуживающий нашего внимания, — функция OnCreate(). В функции OnCreate (), переопределенной классом BmpViewWin(), происходит создание и отображение диалогового окна:
int BmpViewWin::OnCreate(LPCREATESTRUCT lpCreateStruct) {
if (DirectDrawWin::OnCreate(lpCreateStruct) == -1) return -1;
ShowDialog();
return 0;
}
Функция ShowDialog() вызывается при запуске приложения и при выборе нового файла. ShowDialog() подготавливает DirectDraw к отображению диалогового окна, выводит окно, получает информацию о выбранном BMP-файле и выбранном видеорежиме и отображает содержимое файла. Функция ShowDialog() приведена в листинге 5.7.
Листинг 5.7. Функция ShowDialog()
void BmpViewWin::ShowDialog() {
CRect displayrect=GetDisplayRect();
if (displayrect.Width()<640) ddraw2->SetDisplayMode(640, 480, 8, 0, 0);
if (GetDisplayDepth()==8) {
ClearSurface(backsurf, 0);
primsurf->SetPalette(syspal);
} else {
BltSurface(backsurf, bmpsurf, x, y);
}
ddraw2->FlipToGDISurface();
ShowCursor(TRUE);
if (bmpdialog==0) {
bmpdialog=new BmpDialog();
bmpdialog->SetArrays(&palettemode, &nonpalettemode);
}
if (bmpdialog->DoModal()==IDCANCEL) {
PostMessage(WM_CLOSE);
return;
}
fullfilename=bmpdialog->fullfilename;
filename=bmpdialog->filename;
pathname=bmpdialog->pathname;
int index=bmpdialog->GetIndex();
DWORD w,h,d;
if (bmpdialog->FilePalettized()) {
w=palettemode[index].w;
h=palettemode[index].h;
d=palettemode[index].d;
} else {
w=nonpalettemode[index].w;
h=nonpalettemode[index].h;
d=nonpalettemode[index].d;
}
if (GetDisplayDepth()==8) primsurf->SetPalette(palette);
ActivateDisplayMode(GetDisplayModeIndex(w, h, d));
LoadBmp();
ShowCursor(FALSE);
}
Функция ShowDialog() прежде всего проверяет, что текущий видеорежим имеет разрешение не менее 640×480. Из обсуждения функции SelectInitialDisplayMode() нам известно, что при инициализации приложения это условие заведомо выполняется, однако функция ShowDialog() также вызывается при каждом отображении BMP-файла. Если в данный момент установлен режим низкого разрешения, то перед тем, как продолжать, мы переходим в режим 640×480×8. Это обусловлено тем, что режимы низкого разрешения часто являются режимами Mode X, а GDI в таких режимах не может правильно отображать диалоговые окна.
Далее мы готовимся к отображению диалогового окна. Для палитровых режимов мы очищаем вторичный буфер и устанавливаем сохраненную ранее системную палитру, не пытаясь выводить диалоговое окно вместе с текущим изображением. Для беспалитровых режимов текущее изображение копируется на вторичный буфер и выводится за диалоговым окном.
Диалоговое окно и изображение
Чтобы организовать совместный вывод текущего изображения и диалогового окна в палитровом видеорежиме, вам придется сократить 256 элементов палитры изображения до 236, добавить новые цвета в середину палитры (системные цвета занимают по 10 элементов в начале и в конце палитры) и пересчитать пиксели изображения в соответствии с внесенными изменениями. Обычно это ведет к снижению качества изображения, но присутствие диалогового окна все равно отвлекает внимание пользователя. Чтобы восстановить прежнее изображение, необходимо сохранить предыдущие варианты изображения и палитры.
Вызов функции FlipToGDISurface() гарантирует, что вывод GDI будет присутствовать на экране. Кроме того, мы включаем курсор мыши (отключенный при запуске приложения классом DirectDrawWin), чтобы для работы с диалоговым окном можно было пользоваться мышью.
Далее мы создаем экземпляр класса BmpDialog, если он не был создан ранее. Класс-оболочка BmpDialog создается ClassWizard, он предназначен для отображения диалогового окна и работы с ним. Класс содержит код для работы с управляющими элементами окна и реакции на действия пользователя. Код класса BmpDialog здесь не рассматривается, так как он не имеет никакого отношения к DirectDraw.
Обратите внимание: при создании диалогового окна мы вызываем функцию SetArrays() и передаем ей массивы palettemode и nonpalettemode в качестве аргументов. Эта функция передает диалоговому окну информацию о