학습목표 : primitive graphic, timer, log
아날로그 시계를 타이머를 이용해 구현해보도록 하자.
아날로그 시계를 그리는데에 있어서, 구현 방법은 크게 2가지가 있을 수 있다.
여기서는 2개의 접근법을 다 사용하는 것을 보여주겠지만, Tizen 에서는 두번째 방법이 일반적으로 더 선호된다.
그 이유를 설명하자면,
1번 방법은, 프로그래밍 API를 써서, 그래픽적인 요소를 그리는 것으로, Tizen 철학에서는, 그래픽 요소는 그래픽 디자이너가 그리고, 프로그래머는 해당 요소를 활용해 프로그래밍하도록 하고 있는 것에 반한다고 볼 수 있다.
Tizen은 Animation 을 Native API로서 직접 제공하고 있는데, 이를 통해 시계의 분침과 시침을 rotation하는 것이 가능하다. 이와 같이, Tizen은 현대적인 프로그래밍 방식을 Native API로 제공하고 있기 때문에, 2번 방법이 선호된다.
Tizen은 다양한 수준의 API를 제공함으로서 프로그래머가 최적화가 필요하다 생각되는 부분에 있어서 저수준으로 구현할 수 있도록 API를 제공하는 장점이 있다. 하지만, 초심자가 보기에는, 같은 일할 수 있는 여러개의 API를 보고, 헤깔려하거나, 어떤 API를 써야할지 혼동이 올 수 도 있겠다.
1번 방법을 도식화 하면 아래 와 같다.
2번 방법을 도식화 하면 아래와 같다.
Tizen은 타 플렛폼과 달리 Animation을 API를 지원하는데 이를 통해 Main Thread의 부담을 줄여 response time을 줄이며, Animation 제어에 대한 저수준 구현을 피하고 고수준으로 구현하여, 빠르고 쉽게 구현할 수 있다.
Animation 효과는 이동, 또는 변환이 가능하겠고,
과 같은 Animator map을 설정하여, 효과를 줄 수 있다.
앞서 작성했던 hellow world에 코드를 추가해보자
소스 최상단 include 밑에
#include <math.h>
Evas_Object *line = NULL;
int box_x = 20, box_y = 240;
와 같이 math.h를 include하고 필요한 전역변수를 정의하고
create_base_gui 함수의 hellow world 레이블 밑에다가 다음과 같은 코드를 넣어 사각형을 그려보자
// draw a rectangle
Evas_Object *clock_box = evas_object_rectangle_add(evas_object_evas_get(ad->conform));
evas_object_color_set(clock_box, 0, 0, 255, 255);
evas_object_move(clock_box, box_x, box_y);
evas_object_resize(clock_box, 100, 100);
evas_object_show(clock_box);
와 같이 추가하게 되면 사각형이 나오게된다.
기존의 다른 플렛폼의 API와 비교해보면 rectangle의 x,y, width, height를 한번에 받아 그리는 API에 비교하여 API 호출 횟수가 많다는 것을 알 수 있다.
Tizen은 그래픽 객체들이 즉시 버퍼에 그려지기는 타 플렛폼의 방식과 비교해 사뭇 다르다.
Tizen의 경우에는 그래픽 객체를 메모리에 생성하고, 이 것을 필요할 때마다 좌표를 재설정하고,랜더링 하게 되는 방식이다.
이런 방식의 장점은, 한번 메모리에 생성한 객체를 재활용 할 수 있다는 장점이 있다.(아래에서시계 바늘의 선 그리는 것을 보면 더 확실히 알 수 있다.)
Tizen에는 원을 그리는 API가 없다. 이 또한 Tizen에서는 원, 화살표, 상자 등의 것들을 이미지로 읽어와 화면에 중첩하거나 애니메이션을 넣는 프로그래밍 방식을 지향하기 때문이다.
하지만 도형이 필요하다면 polygon으로 필요한 도형을 거의다 그려낼 수 있다.
아래와 같이 원을 그려보자.
// draw a circle
int angle = 0;
Evas_Object *ployg = NULL;
for(angle = 0; angle < 360; angle += 1)
{
int radius = 50;
double radian_angle = (angle)*(3.141592/180);
double x = (radius * cos(radian_angle));
double y = (radius * sin(radian_angle));
if(ployg == NULL)
ployg = evas_object_polygon_add(evas_object_evas_get(ad->conform));
else
evas_object_polygon_point_add(ployg, x + 50 + box_x, y + 50 + box_y);
}
evas_object_color_set(ployg, 0, 255, 0, 255);
evas_object_show(ployg);
이렇게 하게 되면 바로 아래 캡쳐된 그림에서의 파란 네모상자와, 녹색의 원이 그려지게 된다.
시계의 초바늘은 1초마다 그려져야하므로, 1초마다 불려지는 timer를 생성하여
그 안에서 그려보도록 하자
// create a timer
ecore_timer_add(1, timer_cb, ad);
와 같은 코드를 원 그리는 코드 밑에 넣어보자.
여기서 1은 1초마다 불러달라는 파라미터이고, timer_cb은 타이머가 expired되었을 때 호출해야할 callback function이고, ad는 user data pointer로 원하는 것을 넘길 수 있다.
timer_cb 함수가 추가로 필요하기 때문에
소스코드 상단 #include 와 자료구조 밑에
Eina_Bool timer_cb(void *data)
{
appdata_s *ad = data;
int radius = 50;
static int angle = 0;
double radian_angle = (angle)*(3.141592/180);
double x = (radius * cos(radian_angle));
double y = (radius * sin(radian_angle));
if(line == NULL)
{
line = evas_object_line_add(evas_object_evas_get(ad->conform));
evas_object_color_set(line, 255, 0, 0, 255);
}
evas_object_line_xy_set(line, x + 50 + box_x, y + 50 + box_y, 50 + box_x, 50 + box_y);
evas_object_show(line);
angle += 10;
if(angle >= 360)
angle = 0;
return ECORE_CALLBACK_RENEW;
}
를 추가하도록 한다.
이 함수에는 1개의 line을 메모리에 생성하고, 1초마다 좌표만 업데이트 하여 랜더링하도록 한 것이다.
기기 연결 및 로그 보는 방법 로그를 넣기 위해선
LOGI("I am the Info log");
LOGW("I am the Warning log");
LOGE("I am the Error log");
LOGF("I am the Fatal log");
과 같은 코드를 넣으면 되며, 사용법은 printf와 같다.
Log Tag은 프로젝트를 만들 때, 헤더에 자동으로 프로젝트 이름과 동일하게 선언된다.
이 것을 바꾸고 싶다면
#undef LOG_TAG
#define LOG_TAG "MyNewLogTag"
와 같이 하여 log tag을 바꾸도록 하자.
보통 프로그램을 작성시 소스코드가 여러 파일이 될 수 있고 모듈이 여러개가 될 수 있는데, 이 때에 모듈별로 log tag을 다르게 선언하여 사용하면 디버깅시에 log tag으로 filtering하여 볼 때 매우 유용하다.