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.