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.