Blog (76)
Komentarze (5.3k)
Recenzje (0)

Libgreattao: dynamiczne zmiany interfejsu w locie

@nintyfanLibgreattao: dynamiczne zmiany interfejsu w locie08.11.2015 16:22

W tym wpisie opiszę zmiany, jakie zaszły w standardowym trybie pracy libgreattao. Chodzi o priorytety i switches. Priorytety pozwalają na określenie uszczegółowienia sposobu przetwarzania pewnej ścieżki. Switches pozwalają na zmianę interfejsu w zależności od wewnętrznych stanów lub interakcji z użytkownikiem.

Dla zademonstrowania tego, co zaszło, posłużę się przykładami.

Przykład pierwszy na priorytety - wydzielamy przycisk cancel

W tym celu przerobimy okno /desktop/dialogs/question_dialog dla wzornictwa podstawowego, nazwanego mWidgets.

Tak wygląda kod wspomnianej klasy, dostarczany wraz z biblioteką.


<root>

<label dir-for="label" path="/message" />
<label dir-for="description" path="/message" />

<hbox>
<template path="/actions/*">
<button label="ok" dir-for="event,label,shortcut">
<attr-connect name="label" function="last-dir" />
</button>
</template>
</hbox>

</root>

Przerobimy go na taki:


<root>

<label dir-for="label" path="/message" />
<label dir-for="description" path="/message" />

<hbox>
<template path="/actions/*" priority="0">
<button label="ok" dir-for="event,label,shortcut">
<attr-connect name="label" function="last-dir" />
</button>
</template>
</hbox>
<hbox>
<template path="/actions/cancel" priority="1">
<button label="Cancel" dir-for="event,label,shortcut" />
</template>
<template path="/actions/exit" priority="1">
<button label="Exit" dir-for="event,label,shortcut" />
</template>
<template path="/actions/ok" priority="1">
<button label="Exit" dir-for="event,label,shortcut" />
</template>
</hobx>

</root>

W ten sposób przyciski exit, cancel i ok będą wydzielone i wyświetlane poniżej. Priorytety poza tym dają możliwość spersonalizowania elementów, jak np. ustawienia własnej etykiety czy ikony.

Pierwszy przykład wykorzystanie przełączników na podstawie programu testowego

Przełączniki zostały wykorzystane w dwóch trzech testowych. Pierwszy typ przełączników, to przełączniki pozwalające na zmienienie widoku ze względu na wartość zmiennej. Zaprezentowana niżej klasa okna zawiera szablony do akcji, lecz przełączanie widoku jest realizowane całkowicie przez libgreattao. Użytkownik tylko naciska przycisk.Jedyne, co musi zrobić aplikacja, to zainicjować libgreattao, utworzyć okno, a następnie uruchomić domyślną pętlę komunikatów. Przykładu kodu programu nie przedstawię.


<root>
<variable name="zero" action="change" value="0" />
<variable name="one" action="change" value="1" />
<variable name="state" action="change" value="0" />
<variable name="true"  action="change" value="TRUE" />
<variable name="false" action="change" value="FALSE" />
<variable name="is_first_if_processed" action="change" value="FALSE" />
<button label="toggle">
<handler>
     <if type="equal" variable1="state" variable2="zero">
       <variable name="state" action="change" value="1" />       
       <variable name="is_first_if_processed" action="change" value="TRUE" />
      </if>
      <if type="equal" variable1="is_first_if_processed" variable2="false">
         <if type="equal" variable1="state" variable2="one">
            <variable name="state" action="change" value="0" />
          </if>
       </if>
      <variable name="is_first_if_processed" action="change" value="FALSE" />
</handler>
</button>
<switch variable="state">
<if type="equal" variable1=".switch_value" variable2="zero">
    <label label="0" />
</if>
<if type="equal" variable1=".switch_value" variable2="one">
   <label label="1" />
</if>
</switch>
</root>

Pierwszymi dziećmi elementu root są zmienne. Ponieważ każda wartość musi być przechowywana w pamięci, to postanowiłem, że do porównania dwóch wartości potrzebne są dwie zmienne. Najpierw definiujemy zmienne dla stanu okna. Następnie domyślny widok(zmienna state). Następne zmienne są nam potrzebne do pewnej sztuczki, ponieważ nie obsługujemy słowa kluczowego else. Sztuczka była omawiana w jednym z poprzednich wpisów. Co ten kod powoduje? Zawartość elementu handler, w naszym przykładzie, określa zachowanie domyślnego zdarzenia przycisku, którego element jest dzieckiem. Ustawiamy w nim zmienną state. Zmiana tej zmiennej spowoduje usunięcie zawartości wygenerowanej dla naszego okna przez switch, a następnie wygenerowanie nowej zawartości, przetwarzając ten switch, Switch dla swoich potomków określa zmienną .switch_value, która zawiera wartość zmiennej state. W ten sposób generujemy nową etykietę za każdym razem, gdy ktoś naciśnie przycisk.

Drugi przykład wykorzystania przełączników na podstawie programu testowego

W tym wypadku obsłużymy również szablony. Po prostu użytkownik wybiera menu view, a następnie tryb widoku. Jedyne, co musi zrobić aplikacja, to zainicjować libgreattao, utworzyć okno, stworzyć elementy, a następnie uruchomić domyślną pętlę komunikatów. Przykładu kodu programu nie przedstawię.


<root>
<variable name="zero" action="change" value="0" />
<variable name="one" action="change" value="1" />
<variable name="state" action="change" value="0" />
<menu>
<submenu label="View">
<item label="Normal">
<handler>
<variable action="change" name="state" value="0" />
</handler>
</item>
<item label="Compact">
<handler>
<variable action="change" name="state" value="1" />
</handler>
</item>
</submenu>
</menu>
<switch variable="state">
<label label="First test" />
<if type="equal" variable1=".switch_value" variable2="zero">
    <label label="One" />
    <template path="/actions/*">
      <button dir-for="label,event">
        <attr-connect name="label" function="last-dir" />
      </button>
    </template>
</if>
<if type="equal" variable1=".switch_value" variable2="one">
   <label label="Two" />
   <template path="/actions/*">
      <button dir-for="label,event" />
    </template>
    <template path="/actions/cancel" priority="1">
       <label label="You cannot cancel this action in this view" />
       <label>
          <attr-connect name="label" function="last-dir"/>
       </label>
    </template>
</if>
</switch>
<template path="/actions/*">
<label label="a" />
<switch variable="state">
<if type="equal" variable1=".switch_value" variable2="zero">
    <button dir-for="label,event" />
</if>
<if type="equal" variable1=".switch_value" variable2="one">
    <label label="test" dir-for="label" />
</if>
</switch>
</template>
</root>

W tym wypadku wykorzystujemy i przełączniki, jak również priorytety. Jeżeli użytkownik wybierze drugi widok(compact), to wtedy na górze okna nie zostanie wyświetlony przycisk cancel, a jedynie napis. Pozostałe przyciski zostaną obsłużone normalnie.

Kolejny przykład zastosowania przełączników - dostosowujące się samo okno z zapytaniem

Teraz inny rodzaj przełączników - przełączniki bazujące na ilości dopasowań ścieżek do wzoru. Zaczniemy od kodu:


<root>

<variable action="change" name="two" value="2" />
<variable action="change" name="one" value="1" />
<variable action="change" name="zero" value="0" />

<label dir-for="label" path="/message" />
<label dir-for="description" path="/message" />
<switch name="/actions/*" function="path-matched">
<label label="Hello, world!" />
<if type="greater" variable1=".switch_value" variable2="one">
   <hbox>
     <template path="/actions/*">
       <button dir-for="label,event">
          <attr-connect name="label" function="last-dir" />
       </button>
     </template>
   </hbox>
</if>
<if type="smaller" variable1=".switch_value" variable2="two">
   <vbox>
     <template path="/actions/*">
       <label label="Option:" />
       <button dir-for="label,event">
          <attr-connect name="label" function="last-dir" />
       </button>
     </template>
   </vbox>
   </if>
</switch>
</root>

Jak to działa? Taki przełącznik ma inne atrybuty niż dla poprzedniego typu. Musi być ustawiony atrybut function na path-matched, a dodatkowo atrybut name musi być ustawiony na wzór do porównywania. Gdy zmieni się liczba elementów pasujących do wzoru, to wtedy nastąpi usunięcie wszystkich elementów wygenerowanych podczas przetwarzania switches, a następnie ponowne przetworzenie switches - bardzo prosty mechanizm! W tym wypadku napisałem prostą aplikację, która tworzy i usuwa przycisk exit. Oto jej kod źródłowy:

[code=C] #include <libgreattao/tao.h> #include <stdlib.h>

char show_option= 0;

static void exit_from_app(void *mess1, void *mess2) { exit(0); }

static void toggle(void *mesh1, void *window) { show_option ^= 1; if (show_option) { tao_add_handler(window, "/actions/exit", exit_from_app, NULL); } else {

tao_delete_handlers(window, "/actions/exit"); } }

int main(int argc, char **argv) { void *window; tao_initialize("Libgreattao test for morphing window 1", "", &argc, argv); tao_set_alternative_design("tests-design/"); window = tao_new_window("/switches/question_dialog"); tao_add_handler(window, "/:abort", exit_from_app, NULL);

tao_add_handler(window, "/actions/toggle", toggle, window); tao_handle_events();

} [/code]

Jak widać, po naciśnięciu przycisku toggle tworzony bądź usuwany jest przycisk exit, a interfejs dokonuje automatycznych przekształceń, raz wyświetlając etykietę Opcje, a innym razem nie.

Co dalej?

Priorytety, jak i przełączniki, można wykorzystać do różnych celów. W przyszłości połączę widoki /desktop/dialogs/question_dialog wzornictwa domyślnego i modern w taki sposób, że po wyborze wzornictwa modern przyciski będą wyświetlane, jak we wzornictwie domyślnym, jeśli będzie ich mało, a w przypadku dużej liczby przycisków, będą wyświetlane, jak w wzornictwie modern, dodatkowo będą stosowane priorytety w przypadku dużej liczby przycisków, by exit, itd. były wyświetlane poza listą rozwijaną.

Planuję również zaimplementować widok ikon i wykorzystać priorytety i przełączniki w /app/file_manager, by umożliwić użytkownikowi przełączanie widoku listy/ikon bez konieczności stosowania zmian w aplikacji.

To już wszystko!

Edycja 11.11.2015: Poniżej zaznaczam film demonstrujący, jak to działa [youtube=https://www.youtube.com/watch?v=q3LRHIg2B2w&feature=youtu.be]

Szanowna Użytkowniczko! Szanowny Użytkowniku!
×
Aby dalej móc dostarczać coraz lepsze materiały redakcyjne i udostępniać coraz lepsze usługi, potrzebujemy zgody na dopasowanie treści marketingowych do Twojego zachowania. Twoje dane są u nas bezpieczne, a zgodę możesz wycofać w każdej chwili na podstronie polityka prywatności.

Kliknij "PRZECHODZĘ DO SERWISU" lub na symbol "X" w górnym rogu tej planszy, jeżeli zgadzasz się na przetwarzanie przez Wirtualną Polskę i naszych Zaufanych Partnerów Twoich danych osobowych, zbieranych w ramach korzystania przez Ciebie z usług, portali i serwisów internetowych Wirtualnej Polski (w tym danych zapisywanych w plikach cookies) w celach marketingowych realizowanych na zlecenie naszych Zaufanych Partnerów. Jeśli nie zgadzasz się na przetwarzanie Twoich danych osobowych skorzystaj z ustawień w polityce prywatności. Zgoda jest dobrowolna i możesz ją w dowolnym momencie wycofać zmieniając ustawienia w polityce prywatności (w której znajdziesz odpowiedzi na wszystkie pytania związane z przetwarzaniem Twoich danych osobowych).

Od 25 maja 2018 roku obowiązuje Rozporządzenie Parlamentu Europejskiego i Rady (UE) 2016/679 (określane jako "RODO"). W związku z tym chcielibyśmy poinformować o przetwarzaniu Twoich danych oraz zasadach, na jakich odbywa się to po dniu 25 maja 2018 roku.

Kto będzie administratorem Twoich danych?

Administratorami Twoich danych będzie Wirtualna Polska Media Spółka Akcyjna z siedzibą w Warszawie, oraz pozostałe spółki z grupy Wirtualna Polska, jak również nasi Zaufani Partnerzy, z którymi stale współpracujemy. Szczegółowe informacje dotyczące administratorów znajdują się w polityce prywatności.

O jakich danych mówimy?

Chodzi o dane osobowe, które są zbierane w ramach korzystania przez Ciebie z naszych usług, portali i serwisów internetowych udostępnianych przez Wirtualną Polskę, w tym zapisywanych w plikach cookies, które są instalowane na naszych stronach przez Wirtualną Polskę oraz naszych Zaufanych Partnerów.

Dlaczego chcemy przetwarzać Twoje dane?

Przetwarzamy je dostarczać coraz lepsze materiały redakcyjne, dopasować ich tematykę do Twoich zainteresowań, tworzyć portale i serwisy internetowe, z których będziesz korzystać z przyjemnością, zapewniać większe bezpieczeństwo usług, udoskonalać nasze usługi i maksymalnie dopasować je do Twoich zainteresowań, pokazywać reklamy dopasowane do Twoich potrzeb. Szczegółowe informacje dotyczące celów przetwarzania Twoich danych znajdują się w polityce prywatności.

Komu możemy przekazać dane?

Twoje dane możemy przekazywać podmiotom przetwarzającym je na nasze zlecenie oraz podmiotom uprawnionym do uzyskania danych na podstawie obowiązującego prawa – oczywiście tylko, gdy wystąpią z żądaniem w oparciu o stosowną podstawę prawną.

Jakie masz prawa w stosunku do Twoich danych?

Masz prawo żądania dostępu, sprostowania, usunięcia lub ograniczenia przetwarzania danych. Możesz wycofać zgodę na przetwarzanie, zgłosić sprzeciw oraz skorzystać z innych praw wymienionych szczegółowo w polityce prywatności.

Jakie są podstawy prawne przetwarzania Twoich danych?

Podstawą prawną przetwarzania Twoich danych w celu świadczenia usług jest niezbędność do wykonania umów o ich świadczenie (tymi umowami są zazwyczaj regulaminy). Podstawą prawną przetwarzania danych w celu pomiarów statystycznych i marketingu własnego administratorów jest tzw. uzasadniony interes administratora. Przetwarzanie Twoich danych w celach marketingowych realizowanych przez Wirtualną Polskę na zlecenie Zaufanych Partnerów i bezpośrednio przez Zaufanych Partnerów będzie odbywać się na podstawie Twojej dobrowolnej zgody.