본문 바로가기

IT/Tizen

[EFL/Tizen 타이젠] edc - Part의 기본 필드(ignore_flags)

edc의 part에 들어가는 필드 중에 ignore_flags가 있습니다.

무언가를 무시하기 위한 목적으로 만들어진 필드일텐데요,

이름만 봐서는 역할이 분명하게 다가오지 않네요.


이럴 때는 구글링으로 궁금증을 해소하거나,

EFL 소스를 뒤져보거나,

시간과 노력을 들여 순수한 삽질로 기능을 유추해야 합니다.

아니면, EFL 커미터에게 헬프를 외치면 됩니다.



안녕하세요, Tizen 개발자 윤진입니다.


우선, EFL 공식 사이트에서 설명을 찾아보겠습니다.

"Specifies whether events with the given flags should be ignored,

i.e., will not have the signals emitted to the parts."


플래그에 대한 이야기가 나옵니다.

플래그를 설정하면 이벤트가 무시될 수 있다고 하네요.

하지만, 단순히 ignore_flags에 넣는 값에 따라 이벤트를 무시한다면,

이전 포스팅에서 다룬 mouse_events와 다를 바가 없겠지요.


ignore_flags는 mouse_events처럼 무조건적으로 이벤트를 통제하는 것이 아닙니다.

경우에 따라 이벤트를 막거나 혹은 받을 수 있습니다.

그렇다면 그 '경우에 따라'는 어디에서 기인하는 것일까요?


파트 자신이 스스로 각각의 경우를 만들어낼 수 있을까요?

아닙니다. ignore_flags를 적어놓고 있는 파트 자신은 스스로 각각의 경우를 발생하지 못합니다.

대신 위의 파트와 관련이 있는 다른 파트들이 각각의 경우를 만들어냅니다.


어째서 이러한 구조가 필요한 것일까요?

스크롤이 가능한 영역을 생각해보지요.

스크롤이 가능한 영역에 다수의 객체가 삽입되었습니다.

스크롤을 하기 위해 press를 한 후 스크롤을 좌우로 움직입니다.

그리고 release를 하면 스크롤 내에 있던 객체는 이벤트를 받아야할까요?


분명 사용자는 스크롤을 목적으로 press - move - release를 했는데,

사용자의 의도와는 다르게 스크롤 내에 삽입된 객체가 release에 대한 이벤트를 처리할 수 있습니다.

사실 삽입객체는 이벤트를 ignore해야하는데 말이지요.


바로 여기에 ignore_flags 필드가 필요한 겁니다.

삽입객체에 "ignore_flags: ON_HOLD;"를 지정하면,

누군가가 ON_HOLD라고 외치는 순간 자신에게 오는 모든 이벤트는 무시하게 됩니다.

스크롤 와중에 삽입객체들은 이벤트를 받으면 안되지요.


이 사실을 파악하기 이해 먼저 evas 소스를 뒤져보았습니다.

Repository : git://review.tizen.org/framework/uifw/evas

Branch : tizen_2.4


/**
 * @brief Enumeration for events.
 */
typedef enum _Evas_Event_Flags
{
   EVAS_EVENT_FLAG_NONE = 0, /**< No fancy flags set */
   EVAS_EVENT_FLAG_ON_HOLD = (1 << 0), /**< The event is being delivered but should be put "on hold" until the on hold flag is unset \n
   The event should be used for informational purposes and maybe for some indications visually, but should not actually perform anything. */
   EVAS_EVENT_FLAG_ON_SCROLL = (1 << 1) /**< The event occurs while scrolling \n
   For example, DOWN event occurs during scrolling; the event should be used for informational purposes and maybe for some indications visually, but should not actually perform anything. */
} Evas_Event_Flags; /**< Flags for Events */


Evas 단에서 이미 ON_HOLD에 대한 enum을 정의하고 있습니다.

EVAS_EVENT_FLAG_ON_HOLD가 설정된 객체(Evas_Object 혹은 group 혹은 part)는,

타 객체에서 설정한 EVAS_EVENT_FLAG_ON_HOLD에 의해 이벤트를 받지 못합니다.


elementary 소스를 뒤져보면,

대부분의 위젯들이 event를 처리하는 콜백에서 해당 객체가 ON_HOLD 처리가 되어 있는지 확인하고,

ON_HOLD가 set되어 있으면 event 콜백 진입 직후에 return 해버립니다.


Repository : git://review.tizen.org/framework/uifw/elementary

Branch : tizen_2.4

./elm_video.c:31:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_flip.c:1541:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
./elm_flip.c:1572:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
./elm_flip.c:1634:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
./elm_scroller.c:127:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elc_popup.c:2148:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_flipselector.c:440:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_slideshow.c:34:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elc_multibuttonentry.c:80:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_gengrid.c:852:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
./elm_gengrid.c:2312:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_diskselector.c:913:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_web.c:180:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_entry.c:3208:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
./elm_button.c:297:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_interface_scrollable.c:2143:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
./elm_map.c:4378:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_panel.c:818:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elc_ctxpopup.c:1198:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_genlist.c:2682:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_genlist.c:3547:   //if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
./elm_radio.c:164:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./els_scroller.c:1863:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
./els_scroller.c:1931:   //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
./els_scroller.c:2193:   //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
./els_scroller.c:2512:   //   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return ;
./elm_list.c:426:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_colorselector.c:1760:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_slider.c:381:   if (mev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_slider.c:391:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elc_naviframe.c:1332:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
./elc_naviframe.c:1773:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_check.c:155:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elc_player.c:51:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_toolbar.c:756:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
./elm_photocam.c:944:   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;


스크롤러 등에 삽입되어 이벤트를 유연하게 처리하고자 한다면,

위의 위젯들처럼 ON_HOLD가 설정된 event에는 return 처리를 해야겠지요.


그렇다면, 최초 발생한 이벤트는 어떻게 되는 것일까요?

ON_HOLD된 파트들은 건너뛰고,

계속 부모 객체를 찾아갑니다.

ON_HOLD가 설정되지 않은 부모 객체까지 타고 올라가서 이벤트를 처리하게 합니다.

그와 관련된 부분은 아래 propagate 함수에서 엿보실 수 있습니다.


Repository : git://review.tizen.org/framework/uifw/elementary

Branch : tizen_2.4

src/lib/elm_widget.c

EAPI Eina_Bool
elm_widget_event_propagate(Evas_Object *obj,
                           Evas_Callback_Type type,
                           void *event_info,
                           Evas_Event_Flags *event_flags)
{
   API_ENTRY return EINA_FALSE; //TODO reduce.

   if (!_elm_widget_is(obj)) return EINA_FALSE;
   Evas_Object *parent = obj;
   Elm_Event_Cb_Data *ecd;
   Eina_List *l, *l_prev;

   while (parent &&
          (!(event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD))))
     {   
        sd = evas_object_smart_data_get(parent);
        if ((!sd) || (!_elm_widget_is(obj)))
          return EINA_FALSE;  //Not Elm Widget
        if (!sd->api) return EINA_FALSE;

        if (sd->api->event(parent, obj, type, event_info))
          return EINA_TRUE;

        EINA_LIST_FOREACH_SAFE(sd->event_cb, l, l_prev, ecd)
          {https://docs.enlightenment.org/auto/edje/edcref.html
             if (ecd->func((void *)ecd->data, parent, obj, type, event_info) ||
                 (event_flags && ((*event_flags) & EVAS_EVENT_FLAG_ON_HOLD)))
               return EINA_TRUE;
          }
        parent = sd->parent_obj;
     }   

   return EINA_FALSE;
}


이상입니다.

다음 포스팅에서도 part의 기본필드를 알아보도록 하겠습니다.


그럼 좋은 하루 보내세요~

끝_


* References

https://docs.enlightenment.org/auto/edje/edcref.html