C dla każdego (cz. 5.)
Otwieranie ekranów (2)
Bez zbędnego wstępu przejdźmy do przykładu,
nawiązującego do poprzedniego odcinka. Chodzi o
listing 7.
Program demonstruje otwarcie ekranu
publicznego. Użytkownik może sam wybrać tryb, w
jakim ma być wyświetlany ekran, podając programowi
w linii argumentowej identyfikator trybu
wyświetlania, czyli odpowiednią liczbę,
zdefiniowaną w pliku "graphics/modeid.h". Liczbę
tę program otrzymuje w formie napisu (w argv[1])
-- konwersją na wartość liczbową zajmie się za nas
standardowa funkcja strtoul(), która przy użytych
przez nas parametrach akceptuje liczby podane w
trybie szesnastkowym (poprzedzone znakiem 0x bądź
0X), ósemkowym (poprzedzone zerem) bądź
dziesiętnym -- jej dokładny opis znajdziesz w
Zalecanej Literaturze ("Język ANSI C"). Jeżeli
użytkownik nie poda tego parametru, to ekran
zostanie otwarty w trybie hi-res, przy użyciu
standardowego monitora (a więc w wypadku
większości Amig w Polsce -- PAL).
listing 7.
Program sprawdza, czy podana wartość jest sensowna
(ModeNotAvailable()), otwiera ekran
(OpenScreenTagList()) i uaktywnia go
(PubScreenStatus()). Następnie czeka na
naciśnięcie [Return] i zamyka ekran.
Chcąc sprawdzić, czy program rzeczywiście działa
tak, jak powinien, uruchom go, a następnie uruchom
listing 6. z parametrem LISTING7 -- okno powinno
się otworzyć na naszym ekranie z listingu 7. Warto
też sprawdzić, czy działa otwieranie ekranu w
różnych rozdzielczościach. Uruchom listing 7, w
taki sposób:
Listing7 0x11000
Szybkie spojrzenie do "graphics/modeid.h" i już
wiesz, co to za tryb: NTSC_MONITOR_ID. Uruchamiamy
więc, a tu:
Podano nieznany identyfikator trybu wyświetlania!
Czyżby coś było nie tak? Nie, wszystko jest w
porządku! Po prostu nie można używać trybów,
których sterowniki nie są uruchomione. Uruchom
więc program "Storage/Monitors/NTSC" i... tym
razem działa, tzn. ekran wariuje (przynajmniej u
mnie -- mój monitor wyświetla tylko obraz w trybie
PAL).
A co się stanie, gdy się uruchomi dwa listingi 7
na raz -- np. z dwóch Shelli?
Nie mogę otworzyć ekranu!
Jest to związane z tym, że w systemie nie mogą
istnieć dwa ekrany publiczne o tej samej nazwie. Z
tego właśnie powodu większość aplikacji ma na
końcu nazwy ekranu publicznego cyfrę -- normalnie
jest to "1", ale gdy uruchomisz kolejne kopie tego
samego programu, to w nazwie będzie "2", "3" itd.
Możesz wprowadzić odpowiednie modyfikacje w
listingu 7., aby i on tak się zachowywał --
sugerujemy "wrzucić" OpenScreenTags() w pętlę i
stworzyć zmienną, zawierającą nazwę ekranu
publicznego, która powinna być po każdym nieudanym
OpenScreenTags() modyfikowana -- poprzez
zwiększanie się cyferki na jej końcu. Program
powinien jednak wiedzieć, dlaczego nie udało się
otworzyć ekranu. Może wcale nie dlatego, że jest
już inny o tej samej nazwie, ale dlatego, że
brakuje pamięci? Przewidzieli to twórcy systemu --
służy do tego tag:
SA_ErrorCode -- jego parametrem jest adres
zmiennej typu ULONG, do której zostanie zapisane,
dlaczego ekranu nie można było otworzyć, np. gdy
ekran publiczny o tej nazwie już istnieje,
zostanie tam odnotowana stała OSERR_PUBNOTUNIQUE,
gdy brakuje pamięci -- OSERR_NOMEM bądˇ
OSERR_NOCHIPMEM. Stałe są zdefiniowane w pliku
"intuition/screens.h".
Otwarty przez nas ekran będzie używał standardowej
czcionki systemowej, ustawionej przez użytkownika
w systemowym programie Font. Czcionka ta jest
zawsze nieproporcjonalna (fixed width), tzn.
szerokość wszystkich liter jest taka sama.
Istnieją dwa tagi kontrolujące to, jaka czcionka
ma zostać użyta na ekranie:
SA_SysFont -- ustala, która z ustawionych przez
użytkownika w Font czcionek ma być użyta: przy
parametrze 0 (wartość domyślna) użyta zostanie
czcionka systemowa, a przy 1 -- czcionka ekranu
Workbencha (która może być proporcjonalna).
SA_Font -- parametrem jest struktura "TextAttr",
którą omówimy za dwa miesiące -- specyfikuje ona
dokładnie nazwę i rozmiar czcionki, która ma
zostać użyta na ekranie. I znów powtórzę mój mały
apel (tak, wiem, że robić się nudny, ale będę to
powtarzał tak długo, aż wejdzie Wam to w krew!):
nie używajcie tego tagu bez ważnego powodu, a
jeżeli chcecie go użyć, to dajcie użytkownikowi
możliwość wybrania dowolnej czcionki. Szczególnie
denerwująca jest sytuacja, gdy posiadacz monitora
o rozdzielczości 800 x 600 pikseli musi wypatrywać
oczy, bo program używa maciupeńkiej czcionki topaz
8.
Powinniście jeszcze wiedzieć, w jaki sposób
zmienia się ustawienie kolorów ekranu (tylko
pamiętajcie o naszym apelu!). Robi się to za
pomocą następujących funkcji z biblioteki
"graphics.library":
void SetRGB4( struct ViewPort *vp, long index,
unsigned long red, unsigned long green, unsigned
long blue );
void SetRGB32( struct ViewPort *vp, unsigned long
n, unsigned long r, unsigned long g, unsigned long
b );
Pierwsza z nich jest starą funkcją, która
umożliwia ustawienie kolorów w wypadku palety 12
bitów (po 4 bity na każdą składową). Druga funkcja
pojawiła się razem z nowymi kośćmi graficznymi w
OS 3.0 i jest ona stworzona zdecydowanie na wyrost
-- obsługuje 96-bitową paletę (po 32 bity na każdą
składową). Rzecz jasna, obecne układy graficzne
nie mają takich możliwości, więc parametry są
"zaokrąglane". Znaczenie parametrów jest
następujące:
vp -- adres struktury "ViewPort", wchodzącej w
skład struktury "Screen" -- pole "ViewPort". W
strukturze tej są zapisane ustawienia kolorów,
tryb wyświetlania ekranu itp.
index, n -- numer koloru, który ma zostać
zmieniony
red, green, blue -- (w funkcji SetRGB4()) nowe
wartości poszczególnych składowych -- od 0 do 15
r, g, b -- (w funkcji SetRGB32()) nowe wartości
poszczególnych składowych -- od 0 (minimum
nasycenia) do 0xFFFFFFFF (maksimum nasycenia).
Przydatna jest możliwość otwarcia ekranu o takich
samych atrybutach, jak Workbench, jako że atrybuty
Workbencha użytkownik może łatwo dostosować do
własnego "widzimisię". Pomyśleli o tym twórcy
systemu:
SA_LikeWorkbench -- powoduje, że otwarty ekran
będzie kopią ekranu Workbencha -- będzie miał jego
rozmiar, liczbę kolorów, tryb wyświetlania,
czcionkę itp.
Niestety, twórcy systemu pomyśleli o tym nieco
zbyt późno -- tag ten jest dostępny dopiero od OS
3.0. W OS 2.04 trzeba go więc emulować. Aby zrobić
to dobrze, musicie poznać jeszcze trzy funkcje:
struct DrawInfo *GetScreenDrawInfo( struct Screen
*screen );
Funkcja zwraca adres struktury "DrawInfo",
należącej do ekranu "screen", bądź 0, gdy nie
można tego zrobić. Struktura "DrawInfo" jest
zdefiniowana w pliku "intuition/screens.h" -- nas
interesuje w niej pole "dri_Pens", będące
wskaźnikiem na tablicę "penów" oraz "dri_Depth",
zawierające informację o liczbie kolorów na
ekranie. Gdy struktura "DrawInfo" nie jest nam już
dłużej potrzebna, należy użyć funkcji:
void FreeScreenDrawInfo( struct Screen *screen,
struct DrawInfo *drawInfo );
Trzecia funkcja jest zawarta w "graphics.library":
LONG GetVPModeID( struct ViewPort *vp );
Zwraca ona tryb wyświetlania danego ViewPortu
(patrz wyżej -- opis SetRGB4()) bądź INVALID_ID,
gdy nie może tego zrobić.
SA_AutoScroll -- jeżeli parametrem jest TRUE i
szerokość/wysokość ekranu jest na tyle duża, że
niecały ekran możemy na raz zobaczyć, to po
przesunięciu myszy do krawędzi ekranu będzie on
przewijany (można to najlepiej zrozumieć,
eksperymentując w systemowym programie ScreenMode
z opcją AUTOSCROLL oraz szerokością i wysokością
ekranu).
Czas więc przetestować to wszystko - patrz listing
8. Gdy program wykryje obecność systemu 3.0 bądˇ
nowszego, to idzie na łatwiznę i po prostu używa
tagu "WA_LikeWorkbench". W wypadku systemu 2.x
pobiera informacje o "penach" i liczbie kolorów
(GetScreenDrawInfo()) oraz trybie wyświetlania
(GetVPModeID()), pozostałe zaś informacje bierze
po prostu ze struktury "Screen" ekranu Workbencha.
Gdy ekran ma włączony AutoScroll, to w polu
"Flags" struktury "Screen" jest ustawiona flaga
AUTOSCROLL.
Na dziś wystarczy. W następnej części trochę sobie porysujemy po okienkach.