C dla każdego (cz. 1.)
Gadżety (2)
Dziś dokończymy rozpoczętą w poprzedniej części
listę stałych i przedstawimy pierwszą część
listingu. A więc do roboty.
Zostały nam do omówienia jeszcze trzy rodzaje
gadżetów oferowanych przez "gadtools.library:
- PALETTE_KIND - gadżet do wyboru jednego koloru z
palety. Podobnie jak w przypadku gadżetów-list,
rozmiar utworzonego gadżetu może być mniejszy od
żądanego, aby wszystkie prostokąty-kolory w
palecie miały ten sam rozmiar. Tagi:
GTPA_Depth - liczba bitplanów w palecie (a więc
pośrednio liczba kolorów). Standardowo 1, zwykle
podaje się tu "głębokość" ekranu, na którym gadżet
ma być używany.
GTPA_Color - początkowo zaznaczony kolor.
Standardowo 1.
GTPA_IndicatorWidth, GTPA_IndicatorHeight - tu
panuje drobne zamieszanie pomiędzy różnymi
wersjami systemu. Oryginalnie (OS 2.0) użycie
jednego z tych tagów powoduje, że odpowiednio: po
lewej bądź na górze gadżetu ukazuje się prostokąt
o podanej w tagu odpowiednio: szerokości lub
wysokości. W prostokącie tym wyświetlany jest
zaznaczony w danym momencie kolor. W OS 3.0
wprowadzono inny sposób oznaczania zaznaczonego w
danym momencie koloru - po prostu kolor ten jest
obrysowywany w palecie - nie ma żadnego osobnego
prostokąta, dane tych tagów są więc ignorowane, a
podanie któregoś z tagów powoduje tyle, że
zaznaczony w danym momencie kolor jest
obrysowywany. Patrz obrazek w poprzedniej części.
- SCROLLER_KIND - gadżet-suwak, używany zwykle do
skrolowania obiektów w liście, będący np. częścią
gadżetu-listy. Sam gadżet-suwak niczego nie
skroluje - służy on do wizualnej reprezentacji
tego, ile elementów lista zawiera (na podstawie
wielkości suwaka) i która część listy jest w danym
momencie wyświetlana (na podstawie położenia
suwaka). Tagi:
GTSC_Total - liczba obiektów zawartych w liście.
GTSC_Visible - liczba obiektów widoczna naraz na
ekranie - ten tag w połączeniu z powyższym służy
do wyliczenia rozmiaru suwaka.
GTSC_Top - element widoczny początkowo na szczycie
listy - ten tag służy do wyznaczenia początkowego
położenia suwaka.
PGA_Freedom - ustala, czy suwak ma działać w
poziomie (LORIEN_HORIZ - standardowo) czy w pionie
(LORIEN_VERT).
GTSC_Arrows - jeżeli tag ten zostanie użyty, to do
suwaka zostanie dołączony komplet dwóch
gadżetów-strzałek, powodujących zmianę położenia
suwaka. Dana tego tagu oznacza rozmiar strzałek, w
zależności od "PGA_Freedom" szerokość bądź
wysokość.
- SLIDER_KIND - to również gadżet-suwak, ale o
nieco innym zastosowaniu niż "SCROLLER_KIND".
Używa się go zwykle do graficznego przedstawienia
jakiejś wartości numerycznej, np. natężenia
dźwięku, składowych RGB koloru itp. Gadżet zajmuje
się również wyświetleniem obecnej wartości na
ekranie. Tagi:
GTSL_Min, GTSL_Max - ustalają
minimalną i maksymalną wartość liczby
reprezentowanej przez gadżet - na ich podstawie
wyznacza się wielkość suwaka. Standardowo 0, 15.
GTSL_Level - początkowa wartość liczby - na jej
podstawie wyznacza się początkowe położenie
suwaka. Standardowo 0.
PGA_Freedom - to samo co w SCROLLER_KIND.
GTSL_LevelFormat - parametrem jest napis
ustalający sposób wyświetlenia bieżącej wartości
liczby reprezentowanej przez gadżet na ekranie.
Napis podaje się niemal tak samo, jak dla
standardowej funkcji języka "C" printf(), jednak
zamiast "%d" należy używać "%ld" (tak samo, jak w
omówionej w części 3 funkcji EasyRequestArgs()).
Standardowo napis nie jest wyświetlany.
GTSL_MaxLevelLen - ustala, jaka jest maksymalna
długość napisu opisanego wcześniejszym tagiem -
powoduje po prostu przydzielenie bufora
odpowiedniej wielkości, nie ma wpływu na miejsce
wyświetlania napisu. Podanie tego tagu jest
konieczne, jeżeli używa się też GTSL_LevelFormat.
GTSL_LevelPlace - ustala, po której stronie
gadżetu ma być wypisywany opisany wcześniejszymi
tagami napis - PLACETEXT_LEFT (standardowo) itd.
Patrz opis pola "ng_Flags" struktury "NewGadget" w
poprzedniej części.
Uff, wreszcie koniec tych stałych...
Najwygodniej tworzy się gadżety "wrzucając"
omówioną w poprzedniej części funkcję
CreateGadgetA() w dużą pętlę. Niezbędne dla niej
parametry pobiera się z trzech tablic: tablicy
struktur "NewGadget", tablicy typów gadżetów i
tablicy tagów. W czwartej tablicy zapamiętuje się
adresy utworzonych przez funkcję gadżetów.
Rozwiązanie to jest zwykle krótsze od
konkurencyjnego, polegającego na wypełnianiu
pomocniczej struktury "NewGadget" różnymi danymi i
wywoływaniu funkcji CreateGadgetA() osobno dla
każdego gadżetu.
Nie rozumiecie? Wypełniamy
strukturę "NewGadget", wywołujemy funkcję, potem
zmieniamy parę pól struktury "NewGadget" (nazwę,
pozycję), wywołujemy znowu funkcję itd. Po prostu
praktyka wykazuje, że zdefiniowanie tablicy
struktur jest mniej "kosztowne" z punktu widzenia
długości uzyskanego programu niż "ręczne"
wypełnianie wszystkich pól, a poza tym w tej
drugiej metodzie łatwiej o pomyłkę... Nie bez
znaczenia jest też to, że metody z tablicami
używają programy do projektowania interfejsu
użytkownika (Designer, GadToolsBox itd.).
Gdy gadżety nie są nam już dłużej potrzebne,
należy użyć funkcji:
void FreeGadgets( struct Gadget *gad );
Jako parametr należy podać wartość zwróconą przez
funkcję CreateContext().
Kolejną sprawą jest kwestia skalowalnego
interfejsu. Czasy "tryumfalnego pochodu przez
świat" czcionki topaz/8 skończyły się wraz z
upowszechnieniem się trybów graficznych o wyższych
rozdzielczościach niż 640 x 256 dpi. Rozdzielczość
w okolicach 800 x 600 nikogo już dzisiaj nie
szokuje, a przy takiej rozdzielczości nikt
normalny nie używa czcionki o wysokości 8 punktów.
Jeżeli chcemy, aby nasz program nie został przez
posiadacza dobrego monitora skasowany w 10 sekund
po pierwszym uruchomieniu, to musimy stworzyć
interfejs dopasowujący się do czcionki ekranowej.
Niezbędne są nam więc informacje o parametrach
użytej na ekranie czcionki. Uzyskuje się je przy
użyciu funkcji biblioteki "graphics.library":
void AskFont( struct RastPort *rp, struct TextAttr
*textAttr );
Funkcja pobiera z RastPortu "rp" informacje o
używanej czcionce i zapisuje je w dostarczonej
jako drugi parametr strukturze "TextAttr".
Jeżeli nie używamy okna typu GIMMEZEROZERO (patrz
część 4.), to potrzebujemy też informacji o
wysokości górnej listwy oraz szerokości ramki z
lewej strony okna. W części 9. Darek pokazał Wam,
jak uzyskać te dane ze struktury "Window". Teraz
jednak musimy je znać wcześniej, przed otwarciem
okna - korzystamy więc z pól struktury "Screen".
Wysokość górnej listwy jest równa sumie wysokości
czcionki oraz pola "WBorTop" powiększonego o 1,
zaś szerokość lewej ramki jest zapisana w polu
"WBorLeft".
Zaleca się, aby interfejs projektować pod kątem
czcionki topaz/8 i rozdzielczości 640 x 200 dpi,
jako że są to minimalne atrybuty, które ma każda
Amiga.
Tak też robimy w naszym przykładzie - współrzędne
i rozmiary są podane dla czcionki o rozmiarze 8 x
8 i okna typu GIMMEZEROZERO. Każdą współrzędną
skalujemy za pomocą funkcji wyliczx() i wyliczy()
- funkcje te korzystają ze zmiennych "fontx" i
"fonty", które są niczym innym, jak szerokością i
wysokością czcionki. Użyte w tych funkcjach
wyrażenie "+4" służy zaokrąglaniu wyniku "do
najbliższej całkowitej" - bez niego część ułamkowa
wyniku byłaby pomijana (zaokrąglanie "w dół"). Dla
czcionek proporcjonalnych "fontx" jest siłą rzeczy
uśrednione i niektóre napisy mogą "wychodzić" poza
ramki.
Jeżeli to kogoś nie zadowala, to może
używać lepszych algorytmów - za pomocą poznanych w
części 8. funkcji sprawdzać rzeczywistą szerokość
napisów i odpowiednio przesuwać/skalować gadżety.
Jest to jednak w wypadku bardziej złożonych
układów gadżetów kawał roboty, dlatego my
zadowolimy się algorytmem prymitywniejszym
("Lepszy rydz niż nic").
Przed stworzeniem gadżetów sprawdzamy, czy
powiększone okno zmieści się na ekranie. Jeżeli
nie, to wymuszamy użycie standardowej czcionki
"topaz 8".
Na tym musimy już dziś zakończyć. Za miesiąc
omówimy dokładnie pokazaną dzisiaj część listingu
i przedstawimy kolejny jego fragment.