W tym odcinku kontynuuję rozważania na temat tworzenia typowych obiektów MUI stosowanych najczęściej w programach. Na dziś w porządku obrad mamy checkmarki, gadżety cykliczne, przyciski "radiowe" oraz przyciski z grafiką.
Checkmark jest gadżetem używanym z reguły do włączania (lub nie) jakiejś opcji w programie, stąd mnogość tych gadżetów w oknach konfiguracji różnych programów. Z reguły checkmark zawiera obrazek charakterystycznej "fajki", stąd zresztą wzięła się jego nazwa. W MUI (podobnie jak to było przy przyciskach) nie ma specjalnej klasy do tworzenia checkmarków, są one obiektami klasy MUIC_Image. Klasa ta służy do generowania między innymi przycisków graficznych (o tym niżej), posiada kilkanaście wbudowanych obrazków do typowych gadżetów (strzałki, przyciski pop-upów itp.), jednym z takich obrazków jest właśnie checkmark. Podstawowym więc zadaniem przy tworzeniu checkmarka jest użycie odpowiedniego obrazka.
MUIA_Image_Spec, MUII_Checkmark,
Oczywiście niezbędna jest ramka, w tym przypadku należy użyć ramki przycisków graficznych.
MUIA_Frame, MUIV_Frame_ImageButton,
Checkmark jest przyciskiem dwustanowym (po każdym kliknięciu zmienia stan na przeciwny, zatem jego "wciskalność" ustawiamy w następujący sposób:
MUIA_InputMode, MUIV_InputMode_Toggle,,
I ostatnia sprawa, szczególna dla checkmarka. Jego cechą charakterystyczną jest fakt, że przycisk nie wciska się (ramka nie zmienia się na "wciśniętą") przy użyciu. Oczywiście jest kwestią dyskusyjną, czy wciskający się nie wyglądałby lepiej, niemniej należy trzymać się standardów, dlatego w definicji pojawia się tag:
MUIA_ShowSelState, FALSE,
Tag ten blokuje właśnie odwracanie kolorów ramki po uaktywnieniu gadżetu. Jako należący do klasy Area może być zastosowany do każdego gadżetu, co czasem przydaje się do osiągania różnych efektów specjalnych. Na zakończenie warto checkmarka włączyć w łańcuch gadżetów obsługiwanych klawiszem TAB podając tag MUIA_CycleChain, TRUE, ewentualnie tagiem MUIA_ControlChar można przyporządkować checkmarkowi skrót z klawiatury. W tym przypadku w etykiecie gadżetu podkreślamy odpowiednią literę korzystając z atrybutu MUIA_HiChar. Jak każdy przycisk dwustanowy, także i checkmark reaguje na poczynania użytkownika zmianą wartości atrybutu MUIA_Selected, na ten więc atrybut należy ustawiać ewentualne notyfikacje, i przy jego pomocy odczytywać stan gadżetu. Przykładem użycia checkmarków jest program "odwracanka" z szóstej części kursu.
Gadżety te stosujemy, gdy chcemy dać użytkownikowi do wyboru jedną z kilku możliwości. Jeżeli możliwości jest niewiele (powiedzmy mniej niż 5) i nie zależy nam za bardzo na miejscu w oknie, warto przemyśleć użycie gadżetu "radio" o którym niżej. Dzięki temu, że użytkownik od razu widzi wszystkie opcje, jest mu łatwiej dokonać szybkiego wyboru. Ale na razie wróćmy do gadżetów cyklicznych. Tym razem mają one swoją oddzielną klasę - MUIC_Cycle. Podstawową sprawą dla takiego gadżetu jest tablica zawierająca wszystkie możliwości jakie można wybrać. Tablica składa się z wskaźników na łańcuchy znakowe (a więc z elementów typu STRPTR), ostatni z nich powinien być zerowy. Oto przykładowa definicja w C:
STRPTR pozycje[] = {"Amiga", "MacOS", "Linux", "Windows", "OS/2", "inny", NULL};
Adres tej tablicy stanowi parametr najważniejszego taga. Wydaje się, że tutaj MUI nie pozostawia zbyt wiele miejsca na fantazję programisty. Ale jak w każdym tekście MUI, tak i tutaj możemy użyć kodów formatujących. Standardowo formatowanie ogranicza się do wycentrowania tekstu. Nic nie stoi jednak na przeszkodzie, żeby wyjustować tekst do lewej ("33l"), do prawej ("33r"), używać wytłuszczenia, pogrubienia, czy kursywy ("33b", "33u", "33i"), zmieniać kolory ("33x", gdzie x to numer koloru ze struktury DrawInfo ekranu od 0 do 9), czy nawet wstawiać obrazki. W przykładzie 8a standardowe obrazki katalogu, dysku, dyskietki i przypisania (assign) są wstawione w tekst przez podanie łańcucha "33I[6:x]", gdzie x to numer obrazka, który można odnaleźć w pliku "mui.h". Tą samą metodą można wstawiać własne dzieła, szerzej omówię to przy przyciskach graficznych. A oto jak przypisujemy gadżetowi tablicę elementów:
MUIA_Cycle_Entries, (long)pozycje,
Ramka i tło są przydzielane obiektowi klasy Cycle automatycznie, nie jest tak w przypadku czcionki. Dyskusyjną sprawą jest, czy gadżety cykliczne powinny mieć czcionkę standardową, czy tą używaną do przycisków. Osobiście jestem zwolennikiem tej drugiej wersji, łatwo to zrozumieć, gdy zobaczy się jak wyglądają obok siebie przyciski tekstowe i gadżety cykliczne z różnymi czcionkami (np. w preferencjach MCP). Tak więc proponuję:
MUIA_Font, MUIV_Font_Button,
Po wybraniu dowolnej z pozycji, gadżet zmienia wartość swojego atrybutu MUIA_Cycle_Active, wartość ta jest numerem aktywnej pozycji liczonym od zera. Ustawiając ten atrybut przez SetAttrs() możemy zmieniać wybraną pozycję "od strony programu".
Obserwując znane programy korzystające z MUI dochodzi się do wniosku, że przyciski "radiowe" nie cieszą się wśród autorów popularnością. Nie wiem dlaczego, osobiście uważam je za bardzo ergonomiczne i wygodniejsze dla użytkownika, niż gadżet cykliczny. Pewnym wytłumaczeniem może być fakt, że przyciski zajmują zdecydowanie więcej miejsca. Jako, że funkcje spełniane przez oba gadżety są bardzo podobne (wybór jednej z wielu możliwości) ich tworzenie i obsługa również niewiele się różnią. Tak jak poprzednio tworzymy tablicę wszystkich przycisków zakończoną zerowym wskaźnikiem. Przekazujemy ją obiektowi w następujący sposób:
MUIA_Radio_Entries, (long)pozycje,
Przy wystroju zewnętrznym nie mamy wiele do roboty. Gadżet nie ma tła, nie posiada też ramki, aczkolwiek często dodaje się mu ramkę grupy z tytułem (jest to pokazane w przykładzie 8a). Czcionka, którą wypisane są etykiety poszczególnych przycisków, pozostaje standardowa. Wracając jeszcze do przykładu 8a - warto zauważyć, że ramką nie jest objęty sam gadżet, ale grupa składająca się z niego i otaczających go pustych obiektów Rectangle. Dzięki temu gadżet znacznie lepiej wygląda przy skalowaniu okna. Oczywiście jest to sprawa czysto estetyczna nie mająca wpływu na funkcjonowanie gadżetu. W przypadku użycia ramki warto też ustawić wewnątrz niej tło grupy, tak aby nasz gadżet radiowy nie wyróżniał się nieestetycznie spośród innych grup znajdujących się w oknie.
Przyciski z umieszczoną na nich grafiką z pewnością są miłym dla oka uatrakcyjnieniem interfejsu graficznego programu. Dotyczy to również innych elementów (np. logo programu). Ten rozdział odnosi się zarówno do przycisków, jak i grafiki wyłącznie ozdobnej, różnica sprowadza się jedynie do odpowiedniej ramki, tła i wartości atrybutu MUIA_InputMode.
W MUI istnieją dwie klasy przeznaczone do pokazywania grafiki: Image i Bitmap. Na początek omówię klasę Image jako prostszą w użyciu i mającą więcej możliwości (ale też i wady). Klasa Image jest w stanie pokazać sześć rodzajów grafiki. Opis grafiki jest przekazywany przez atrybut MUIA_ImageSpec, jego wartość jest tekstem zaczynającym się od cyfry i dwukropka, cyfra oznacza rodzaj grafiki. I tak:
0: Rysowany jest prostokąt jednym z wzorków zdefiniowanych przez MUI. Wzorki te można obejrzeć wybierając zakładkę "Pattern" w oknie wyboru tła w preferencjach MUI. Wzorki są zdefiniowane w ten sposób, że ustalone są numery kolorów w palecie, a nie wartości RGB, więc w zależności od ustawionej palety ekranu mogą wyglądać inaczej. Numery tych wzorków znajdują się w pliku "mui.h" (od MUII_BACKGROUND do MUII_FILLBACK2).
2: Tu możemy narysować prostokąt o zdefiniowanym kolorze RGB. Na przykład definicja "2:ffffffff,ffffffff,00000000" da nam jasnożółty prostokąt. Oczywiście kolor jest zawsze remapowany do palety ekranu, więc np. na 4-kolorowym ekranie otrzymamy kolor biały. Składowe zawsze należy podawać jako ośmiocyfrowe liczby szesnastkowe. Przykładem zastosowania wzorków i kolorów jest program "przyklad8b".
3: Pozwala narysować obiekt klasy BOOPSI wyprowadzonej z imageclass. Możliwość rzadko wykorzystywana i nienajprostsza w użyciu, powiązaniami między imageclass a MUI zajmę się w przyszłości.
4: Posłuży do wyświetlania tzw. "MUI brushes", są to obrazki w formacie ILBM narysowane w specjalnej 9-kolorowej palecie (rysunek "ImageDesign" w pakiecie MUI). Obrazki te mają dwie cechy. Po pierwsze nie są remapowane do aktualnej palety ekranu. A więc jeżeli kolor ramek okien zmienię sobie na zielony (jak to widać na wszystkich ilustracjach), to kolor niebieski w tych obrazkach również zmieni się na zielony. Druga cecha to fakt, że jeden z kolorów palety jest traktowany jako przeźroczysty, jest to niemożliwe do osiągnięcia w obrazkach z kolejnego typu 5. Oto jak kolejne kolory z palety brusha są interpretowane przez MUI (w nawiasach standardowe barwy z MagicWB): przeźroczysty, fill (niebieski), shadow (czarny), shine (biały), text (czarny), znowu fill (niebieski), halfshine (jasnoszary), background (szary), halfshadow (ciemnoszary), mark (różowy). Kolejna ciekawa właściwość - obrazek typu 4 może posiadać dwa stany. Jeżeli więc chcemy, żeby przy wciskaniu przycisku zmieniał się obrazek, należy na końcu nazwy pierwszego (w stanie nieaktywnym) obrazka dodać "0", na końcu drugiego "1". Wtedy MUI wczyta oba brushe i będzie je odpowiednio zamieniać przy uaktywnianiu gadżetu. Zmianę brusha można też wymusić "ręcznie" podając numer obrazka w atrybucie MUIA_Image_State. Przykład przycisku z dwoma stanami opartego o typ "4:" to program "przyklad8c".
5: Bardzo przyjemna możliwość wczytania dowolnego pliku graficznego za pośrednictwem systemowych datatypów. Obrazek (w przeciwieństwie do 4:) zostanie zawsze zremapowany do aktualnej palety ekranu. Poza tym nie da się uzyskać przezroczystości. Istnieje jeszcze jedno dodatkowe ograniczenie. Wymiar obrazka musi być określony w momencie tworzenia obiektu przez podanie tagów MUIA_FixWidth i MUIA_FixHeight. Mimo tego należy jednocześnie podać atrybuty MUIA_Image_FreeHoriz i MUIA_Image_FreeVert, co sugerowałoby z kolei, że obrazek będzie się skalował. Wygląda na to, że Stefan Stuntz nie zaimplementował odczytu rozmiarów obrazka z niego samego, a szkoda, bo wcale nie jest to trudne do zrobienia, jak to pokażę w jednej z następnych części. Jeżeli pominie się wyżej wspomniane tagi obrazek nie zostanie w ogóle pokazany. Uniemożliwia to użytkownikowi zmianę rozmiaru jeżeli chce np. zamienić firmowe obrazki własnymi. Sposobem na obejście tego i innych ograniczeń typu "5:" jest napisanie własnej klasy obsługującej obrazki, lub zastosowanie klasy Bitmap, której to klasie poświęcę jeden z następnych odcinków kursu. Przykład użycia typu "5:" to program "przyklad8d". Wyświetlany jest w nim obrazek w formacie PNG, program więc nie zadziała, jeżeli w systemie nie będzie zainstalowanego odpowiedniego datatypu. Dlatego na wszelki wypadek z programami najlepiej dostarczać użytkownikowi obrazki w formacie IFF ILBM, gdyż datatyp ILBM znajduje się na dyskietkach systemowych. Później użytkownik może sobie zmienić format, na taki, jaki mu odpowiada. Przy okazji w przykładzie pokazałem jak można zmienić odstępy między zawartością obiektu, a jego ramką przy pomocy atrybutów MUIA_InnerXxxx. W przypadku takim, jak w przykładzie wskazane jest wyzerować te odstępy ze względów estetycznych. Generalnie jednak nie należy nadużywać tych tagów, w ten sposób bowiem na siłę zmienia się ustawienia użytkownika.
6: Ostatni typ służy do pokazywania obrazków predefiniowanych w MUI, takich jak te pokazane w przykładzie 8a. Można tu również pokazywać tła wybrane przez użytkownika w preferencjach. Wykaz możliwych obrazków znajduje się w pliku "mui.h".
I na tych obrazkowych dywagacjach kończę dzisiejszy odcinek. A za miesiąc listy i listviewy. Jeżeli jednak chcecie w kursie czegoś innego, piszcie śmiało e-maile na podany niżej adres. Dodatek - tutaj.