Drobne programowanie

Kaczuś zaprasza do opowieści o algorytmach, językach programowania i strukturach danych

Na stronie stosowane są pliki cookies. Więcej na podstronie.
odsłon: 517

Moje boje z MUI

Ostatnimi czasy, moja aktywność na stronie została troszkę ograniczona. W zasadzie powinien pokazać sie teraz inny artykuł, ale pewien splot wydarzeń spowodował, że odkopałem mój stary projekt i zacząłem go zmieniać tak, aby nadawał się w przyszłości do upublicznienia. Żeby programu używało sie wygodniej, toteż postanowiłem skończyc go używając dobrodziejstwa biblioteki MUI. Tworząc go dowiedziałem się kilku istotnych rzeczy, które mogą przydać się również innym. Wiedzę zawdzięczam sobie, oraz bywalcom kanału #castor-csv (miedzy innymi Jacy, Krashanowi, Kierowi i Rzookolowi).

Przedstawione uwagi dotyczą MUI w wersji 4 i systemu MorphOS, jednak większość z nich również przyda się przy programowaniu z użyciem starszych wersji MUI i systemu AmigaOS).

Program wymagał stworzenia własnej klasy MUI. Klasa jest odpowiedzialna za wyświetlanie pewnych dokumentów. Tak więc dziedziczy po MUIC_Area. Ponieważ nie chciałem zajmować się całą otoczką związaną ze skrolowaniem itp, toteż wymyśliłem prosty patent, że umieszczę sobie klasę jako element MUIC_Scrollgroup.

MUIM_AskMinMax

Pamiętając o podstawach, że rysujemy po prostu w funkcji MUIM_Draw, renderujemy sobie spokojnie całość wyświetlanego dokumentu i tyle. Jedyne o czym musimy pamiętać, to, że w określonych sytuacjach musimy poinformować o zmianie wielkości, czyli wymusić wywołanie funkcji MUIM_AskMinMax. W funkcji tej ustawiamy sobie MaxWidth oraz MaxHeight na wielkość MUI_MAXMAX, natomiast DefWidth i DefHeight na wielkość aktualną dokumentu. Wymuszenie wywołania metody MUIM_AskMinMax uzyskujemy:
DoMethod(object1, MUIM_Group_InitChange);
//kod przygotowujący
DoMethod(object1, MUIM_Group_ExitChange2);
object1 to wskaźnik na obiekt rodzica, czyli MUIC_Scrollgroup.

Jeśli otrzymacie Państwo informację o braku identyfikatora MUIM_Group_ExitChange2 (jeszcze nie ma w oficjalnych include'ach), to możecie dodać:
#ifndef MUIM_Group_ExitChange2
#define MUIM_Group_ExitChange2              0x8042e541
#endif
No i już nam wszystko ładnie działa. Ja wymuszenie wykonuję po wczytaniu nowego dokumentu, lub po zmianie wielkości okna, gdyż dokument może mieć w parametrach dostosowanie się do wielkości okna.

MUI_MAXMAX

Napisałem, że wszystko ładnie działa? - no prawie wszystko. Otóż okazuje się, że dumne MUI_MAXMAX to tak na prawdę 10000 i jest to liczba ograniczająca wielkość elementu w MUIC_Scrollgroup.
W takim razie łatwe skrolowanie jednak nam odpada. Tworzymy sobie MUIC_Virtgroup złożone z obiektu naszej klasy, oraz 2 obiektów klasy MUIC_Scrollbar. Po stworzeniu ustawiamy notyfikacje na zmianę położenia suwaków, by wysyłały do obiektu naszej klasy odpowiedni komunikat i do dzieła!

MUIM_Setup

Aby działało to w miarę płynnie, renderujemy dokument na bitmapę pomocniczą. Tu pojawiają się kolejne schody. O ile system pozwoli nam zaalokować bitmapę w miarę dużą, to niektóre funcje zgłaszają problemy z rysowaniem po takiej bitmapie, jeśli jest ona większa niż pewien rozmiar. Jaki to rozmiar - dowiemy się używając funkcji GetDisplayInfoData, pobierając DTAG_DIMS. Dzięki temu zabiegowi w buforze otrzymamy informacje zapisane w postaci struktury DimensionInfo, gdzie pola MaxRasterWidth i MaxRasterHeight wyznaczą nam rozmiar bitmapy, która będzie przechowywała wyrenderowany fragment naszego dokumentu.
Stosując powyższe uwagi, wnętrze metody MUIM_Setup wygląda mniej więcej tak:
 
    struct ourclassData *d = INST_DATA(cl, obj);
    struct RastPort *RP = _rp(obj);
    struct Screen *scr = _screen(obj);
    struct DimensionInfo buf;
    ULONG mode_id;
    ULONG lsize;

    if (DoSuperMethodA (cl, obj, msg))
    {
     	
        mode_id = GetVPModeID(scr->ViewPort);
        lsize = GetDisplayInfoData(NULL, &buf, sizeof(struct DimensionInfo), DTAG_DIMS, mode_id);
        if(lsize > 0)
        {
           //jest ok
            kprintf("success: MaxDepth =%d; MinRasterWidth =%d; MinRasterHeight =%d; MaxRasterWidth =%d; MaxRasterHeight =%d\n",
				buf.MaxDepth, buf.MinRasterWidth, buf.MinRasterHeight, buf.MaxRasterWidth, buf.MaxRasterHeight);
        }
        else
        {
            //obsluzyc blad odczytu
            kprintf("failure\n");
        }

        d->bmWidth = buf.MaxRasterWidth;
        d->bmHeight = buf.MaxRasterHeight;
        d->privateBm = AllocBitMap(d->bmWidth, d->bmHeight, 32, BMF_MINPLANES, scr->RastPort.BitMap);
        InitRastPort(&d->privateRP);
        d->privateRP.BitMap = d->privateBm;
        //[...]
        return TRUE;
    }
    return FALSE;

MUIM_Draw

Jak już mamy bitmapę którą będziemy prezentowali w obiekcie naszej klasy, to warto zadbać o to, by wyświetlało się właściwie. Jeśli przyjdzie nam do głowy użyć funkcji przesuwającej fragment widoku, to niewskazane jest używanie funkcji ScrollRaster, tylko ScrollWindowRaster, bądź ScrollWindowRasterNoFill. Inaczej jeśli przysłonimy jakimś oknem nasze okno, to będą zostawały smugi podczas skrolowania.

Jeśli niezależnie od tego w jakim trybie jest rysowana zawartość obiektu naszej klasy (MADF_DRAWOBJECT czy MADF_DRAWUPDATE) nie chcemy by MUI zajmowało się czyszczeniem (w naszej sytuacji to nie jest potrzebne, a powoduje to mrugnięcie), musimy ustawic podczas tworzenia obiektu odpowiednią flagę, czyli MUIA_FillArea ustawić na wartość FALSE.

OM_NEW

Na zakończenie tego tekstu jeszcze jedna uwaga. Sam się złapałem kilka razy juz na tym, nie wiem, czy nie jest to nigdzie napisane, czy po prostu za mało uwypuklone: chodzi o metodę OM_NEW. Wiadomo, że w konstruktorze najpierw wywołujemy konstruktor obiektu nadrzędnego. W przypadku MUI będzie to wywołanie funkcji DoSuperMethodA. Jednak istotna jest inna część - jeśli chcemy w konstruktorze wykonywać jakiekolwiek operacje na obiekcie, należy wiedzieć, że w przypadku OM_NEW dopiero metoda DoSuperMethodA zwraca nam właściwy obiekt. Zatem konstruktor powinien wyglądac mniej więcej tak:
 
    obj = (Object *)DoSuperMethodA(cl, obj, msg);
    if (obj != NULL)
    {
        d = INST_DATA(cl, obj);
        [...]
    }
    return (IPTR)obj;
    
Na razie to wszystko. Jeśli znajdę jakiś problem, na który uznam, że warto zwrócić uwagę przy programowaniu z użyciem biblioteki MUI, to oczywiście postaram się o tym napisać.

Kaczuś

2014-10-26 17:25:44


MUI C morphos amigaos programowanie porady