C dla każdego (cz. 4.)
Otwieranie ekranów
Umiecie już otwierać okna na ekranie Workbencha (a
właściwie na standardowym ekranie publicznym).
Dziś nauczymy Was otwierać okna na cudzych
ekranach oraz... samemu otwierać ekrany.
Właściwie to wypadałoby zacząć od tego, czym się
różni okno od ekranu, bo, jak zauważyliśmy,
autorzy wielu artykułów w polskiej prasie
komputerowej po prostu mylą te dwa pojęcia.
Czym jest okno, tłumaczyć chyba nie trzeba. "Takie
coś" mające zwykle ramkę i kupę gadżetów.
Wystarczy zresztą uruchomić któryś z przykładów z
poprzedniej części, aby je zobaczyć.
Ekrany są zaś jednostką nadrzędną w stosunku do
okien -- okno otwiera się na konkretnym ekranie i
nie można go za pomocą myszy przesunąć na inny.
Ekrany obsługuje się tylko dwoma gadżetami:
przesuwa w górę/w dół (służy do tego po prostu
listwa tytułowa) oraz do przodu/do tyłu. Wszystkie
inne gadżety, jakie można zobaczyć, znajdują się w
oknach. Ekranów, w przeciwieństwie do okien, nie
można zwykle przesuwać na boki -- wyjątkiem są te
o szerokości innej niż szerokość aktualnego trybu
wyświetlania. Każdy ekran ma własne, niezależne od
innych, atrybuty, takie jak liczba kolorów i ich
numery (bo trzeba wiedzieć, że kolory są
numerowane), a także szerokość, wysokość i tryb
wyświetlania (tj. częstotliwość odchylania
pionowego/poziomego, przeplot itp.). Okna otwarte
na danym ekranie dziedziczą jego atrybuty, tzn.
mają takie same kolory jak ekran, są wyświetlane w
takiej samej rozdzielczości itp.
No, chyba wystarczy tego sadzenia banałów. Ci,
którzy jeszcze mają wątpliwości, czym się jedno od
drugiego różni, niech sobie poczytają instrukcję
do Amigi. Tam jest to nieźle opisane i pokazane na
obrazkach.
Zacznijmy może od otwierania naszych okien na
cudzych ekranach. Przede wszystkim, nie na każdym
ekranie można okno otworzyć -- do tego celu służą
ekrany publiczne (ang. public screens). Domyślnym
ekranem publicznym jest ekran Workbencha. Jeśli
chcemy otworzyć okno na innym ekranie publicznym,
to musimy znać nazwę tego ekranu. Jest ona zwykle
wyświetlana na listwie tytułowej okna bądź w
"About". Przykłady: "CygnusEdScreen1", "DOPUS.1",
"GOLDED.1", "SC_CPR.1". Pisownia małych i dużych
liter JEST WAŻNA! Najpierw warto sprawdzić, czy
ekran publiczny o danej nazwie istnieje. Służy do
tego funkcja:
struct Screen *LockPubScreen( UBYTE *name );
Jej parametrem jest wskaźnik na nazwę ekranu,
zwraca zaś ona wskaźnik na strukturę "Screen",
opisującą otwarty ekran. Jeżeli ekran o podanej
nazwie nie istnieje, to funkcja zwraca NULL.
Jeżeli jako nazwę podamy NULL, to funkcja zwraca
adres domyślnego ekranu publicznego. Po użyciu tej
funkcji nie da się danego ekranu zamknąć.
Jeżeli adres ekranu nie jest nam już potrzebny,
należy użyć funkcji:
void UnlockPubScreen( UBYTE *name, struct Screen
*screen );
Jako pierwszy parametr podaje się zwykle NULL, a
jako drugi wartość zwróconą przez LockPubScreen().
Wywołanie tej funkcji umożliwia póˇniej zamkniecie
danego ekranu przez program, który ekranem
zarządza.
Skoro znamy już adres ekranu, na którym chcemy
otworzyć okno, to należy teraz poinformować o tym
funkcję OpenWindowTagList(), która otworzy nam
okno na tym właśnie ekranie. Służy do tego tag:
WA_PubScreen -- jego parametrem jest po prostu
adres ekranu (struktury "Screen").
Czas więc na mały przykładzik, utrwalający zdobytą
właśnie wiedzę:
listing nr 6
Sądzimy, że nie wymaga on dłuższego komentarza:
jeżeli poda się przy uruchamianiu parametr w linii
argumentowej, to program uzna ten parametr za
nazwę ekranu publicznego i spróbuje otworzyć na
nim okno. Bardziej eleganckie metody podawania
parametrów omówimy w którejś z kolejnych części.
Ponieważ nie podaliśmy przy otwieraniu okna tagów
"WA_Left" oraz "WA_Width", to system otworzy okno
maksymalnej wielkości, a więc o szerokości ekranu.
Tagi "WA_Top" oraz "WA_Height" podaliśmy po to,
aby okno nie zasłaniało górnej listwy ekranu.
Szerokość górnej listwy jest zapisana w strukturze
"Screen" -- wynosi ona BarHeight+1. Nie można w to
miejsce wstawić jakiejś stałej wartości, gdyż
szerokość listwy zależy od użytej czcionki
ekranowej.
Istnieją inne niż tag "WA_PubScreen" metody
podawania, na którym ekranie ma być otwarte okno:
WA_PubScreenName -- parametrem jest wskaźnik na
NAZWĘ ekranu publicznego, na którym chcemy
otworzyć okno.
WA_PubScreenFallBack -- użyty w połączeniu z
powyższym powoduje, że jeżeli ekran o danej nazwie
nie jest dostępny, to okno zostanie otwarte na
standardowym ekranie publicznym.
WA_CustomScreen -- używany, gdy ekran, na którym
chcemy otworzyć okno, nie jest ekranem publicznym
(w praktyce oznacza to, że jesteśmy właścicielami
tego ekranu -- sami go otworzyliśmy). Parametrem
tego tagu jest adres ekranu, tak samo jak w tagu
"WA_PubScreen".
No, teraz wypadałoby samemu otworzyć ekran. Służy
do tego funkcja:
struct Screen *OpenScreenTagList( struct NewScreen
*newScreen, struct TagItem *tagList );
struct Screen *OpenScreenTags( struct NewScreen
*newScreen, unsigned long tag1Type, ... );
Znaczenie parametrów jest analogiczne do omówionej
w poprzedniej części funkcji OpenWindowTagList()
(tak samo, istnieje też stara funkcja OpenScreen()
-- bez tagów). Analogiczna jest również zwracana
przez funkcję wartość -- jest nią wskaźnik na
strukturę "Screen" (tę samą, co w
"LockPubScreen()"), bądˇ 0, gdy ekran nie może być
otwarty (bo np. nie wystarczyło pamięci).
Tagów dla funkcji OpenScreenTagList() jest cała
masa, najważniejsze to:
SA_Depth -- "głębokość" ekranu, tzn. liczba
bitplanów. Gdyby ktoś nie wiedział: liczbę kolorów
oblicza się jako 2 do potęgi "liczba bitplanów".
Standardowa wartość (tj. taka, jaka zostanie
ustawiona, jeżeli ten tag w ogóle nie będzie
podany) to 1 (2 kolory).
SA_Title -- tytuł ekranu, wyświetlany na listwie
tytułowej (NIE jest to równoznaczne z nazwą ekranu
publicznego).
SA_Type -- typ ekranu -- PUBLICSCREEN, gdy ekran
ma być publiczny, CUSTOMSCREEN, gdy ma być
prywatny.
SA_PubName -- nazwa ekranu publicznego (tag
używany wtedy, gdy chcemy, aby ekran był
publiczny).
SA_DisplayID -- rozdzielczość, w jakiej ma być
wyświetlany ekran. Jako parametr podajemy stałe
zdefiniowane w pliku "graphics/modeid.h" lub
"graphics/displayinfo.h" (w zależności od
posiadanej wersji inkludów). Na przykład, aby
otrzymać ekran o częstotliwości odchylania PAL (50
Hz), w wysokiej rozdzielczości i z przeplotem,
jako parametr podajemy: PAL_MONITOR_ID |
HIRESLACE_KEY.
SA_Pens -- ten wymaga dłuższego komentarza. Jak
wiadomo, ekrany mogą mieć różną liczbę kolorów,
różne mogą też być poszczególne barwy. Barwy,
zapisane jako składowe R (red -- czerwona), G
(green -- zielona) i B (blue -- niebieska), są
przyporządkowane numerom od 0 do
"iloŁć_kolorów-1". Zarówno system, jak i inne
programy, chciałby wiedzieć, którym z kolorów ma
być narysowana górna listwa ekranu, którym mają
być rysowane lewe i górne krawędzie gadżetów, a
którym prawe i dolne (aby otrzymać efekt
trójwymiarowości), którym kolorem powinny być
rysowane normalne teksty, a którym teksty o
szczególnym znaczeniu itp. To wszystko ustala
właśnie tag "SA_Pens". Jego parametrem jest adres
do tablicy UWORDów, zawierającej informacje o
numerach kolorów, przeznaczonych dla
poszczególnych zadań. Tablica ta powinna być
zakończona numerem ~0, czyli 0xFFFF. W pliku
"intuition/screens.h" znajdują się stałe,
informujące, w których elementach tablicy powinny
być numery kolorów dla odpowiednich celów, np.
SHADOWPEN ustala, jakim kolorem mają być rysowane
"ciemne krawędzie" trójwymiarowych obiektów. Stała
ta ma wartość 4, co oznacza, że numer koloru
służącego do tego celu ma być odnotowany w
czwartym elemencie tablicy (czyli w piątym z
kolei, bo pierwszy element tablicy ma w "C" indeks
0). W systemie 2.04 jest 9 takich "penów" (jak to
przetłumaczyć?!), w 3.0 doszły jeszcze 3,
ustalające dokładnie kolory na górnej listwie
ekranu. Nie ma potrzeby podawać całej tablicy
"penów". Można podać np. tylko 3 pierwsze (a więc
DETAILPEN, BLOCKPEN i TEXTPEN -- patrz
"intuition/screens.h"), a zaraz po nich ~0, co
spowoduje, że pozostałe zostaną ustawione na
standardowe wartości.
I tu nasz mały apel. Jeżeli nie musicie, nie
ustalajcie własnych, niestandardowych wartości.
Najlepiej już jako pierwszy element podać ~0, co
spowoduje, że wszystkie "peny" zostaną ustawione
na standardowe wartości. Ma to tę zaletę, że Wasze
programy nie będą odstawały swym wyglądem od
reszty systemu. Jeżeli standardowe systemowe
wartości ulegną zmianie (tak jak to miało miejsce
w wypadku kolorów górnej listwy ekranu pomiędzy OS
2.04 i OS 3.0), to przy takim rozwiązaniu Wasz
program dostosuje się do tego -- użytkownicy będą
Wam wdzięczni. Jeżeli zależy Wam na innych
wartościach, to powinniście mimo wszystko dać
użytkownikowi możliwość ich zmiany (taką opcję ma
np. edytor GoldEd, a także sam AmigaOS od wersji
3.0 -- program Palette), bo użytkownik może chcieć
inaczej, i ma do tego prawo! Jednym słowem, nic na
siłę!
Otwarty za pomocą OpenScreenTagList() z użyciem
powyższych tagów ekran będzie miał standardowe
rozmiary oraz pozycję. I tu ponawiamy nasz apel.
Nie zmieniajcie tego bez ważnego powodu!
Standardowe wartości ustawia sam użytkownik, za
pomocą systemowego programu Overscan, i jest
naprawdę denerwujące, gdy program otwiera ekran
640 x 256, mimo że w Overscan jest ustawione 724 x
283... Jeżeli jednak musicie mieć inny rozmiar, to
używa się do tego tagów "SA_Width" oraz
"SA_Height", których znaczenie jest chyba
oczywiste (szerokość, wysokość). Istnieją też tagi
"SA_Left" i "SA_Top", ustalające początkową
pozycję ekranu w stosunku do lewego górnego rogu,
ustalonego przez użytkownika w programie Overscan
(standardowo 0, 0). To samo dotyczy właściwie
również rozdzielczości oraz liczby kolorów: o tym
wszystkim powinien móc decydować użytkownik.
Najbardziej eleganckim rozwiązaniem jest użycie
ScreenMode-requestera, w którym użytkownik może
sobie podstawowe atrybuty dowolnie ustalić.
Zostanie to pokazane w którejś z kolejnych części.
Ekran ma po otwarciu ustawienie kolorów takie
samo, jak ekran Workbencha.
"Świeżo otwarty" ekran publiczny nie jest w
gruncie rzeczy publiczny, tzn. jest otwierany w
trybie prywatnym. Jest to dość sensowne, bo
program otwierający ekran publiczny może chcieć
najpierw dokonać jakichś inicjalizacji -- nasz
prymitywny przykład, rzecz jasna, nic takiego nie
będzie robił. Gdy program chce zezwolić innym na
otwieranie na swym ekranie publicznym okien, musi
zmienić status tego ekranu, wywołując funkcję:
UWORD PubScreenStatus( struct Screen *screen,
unsigned long statusFlags );
Pierwszym parametrem jest, oczywiście, ekran,
drugim -- status, jaki ma otrzymać ekran. Na razie
istnieje tylko jedna flaga statusu: PSNF_PRIVATE.
Podaje się ją, gdy chce się ekran uczynić na
powrót prywatnym. Jeżeli chce się, tak jak my,
uczynić ekran publicznym, to podaje się 0. Funkcja
zwraca poprzedni status ekranu. W wypadku, gdy
chcemy za pomocą tej funkcji uczynić ekran
publiczny na powrót prywatnym, funkcja może
zwrócić 0, aby zasygnalizować niepowodzenie
(spowodowane np. tym, że na ekranie są otwarte
okna innych programów).
Gdy chcemy zamknąć nasz ekran, należy użyć
funkcji:
BOOL CloseScreen( struct Screen *screen );
Parametrem jest ekran, który ma zostać zamknięty.
Funkcja zwraca 0, jeżeli nie udało się zamknąć
ekranu. Dzieje się to wtedy, gdy na ekranie są
otwarte jakieś okna (albo użyty został
LockPubScreen() bez dopełniającego go
UnlockPubScreen()). Wykorzystamy tę własność w
naszym przykładzie.
W przykładzie użyjemy jeszcze jednej funkcji
systemu operacyjnego:
LONG ModeNotAvailable( unsigned long modeID );
UWAGA! Funkcja ta znajduje się w bibliotece
"graphics.library", a NIE w Intuition, należy więc
tę bibliotekę najpierw otworzyć. Funkcja służy do
sprawdzania, czy podany jej jako parametr
identyfikator trybu wyświetlania (liczba, którą
podaje się jako parametr tagu "SA_DisplayID") jest
poprawnym, dostępnym na danym komputerze trybem.
Zwraca ona 0, jeżeli tryb może być użyty; w
przeciwnym wypadku zwraca jedną z wartości
zdefiniowanych w pliku "graphics/displayinfo.h"
(np. DI_AVAIL_NOCHIPS oznacza, że nie masz
odpowiednich kości graficznych, niezbędnych do
wyświetlenia danego trybu, może to spotkać na
przykład posiadaczy Amig 3000 z OS 3.x, chcących
otworzyć ekran w trybie HAM8).
Tyle teorii w tym odcinku. W następnym zamieszczę
przykłady.