Neste tutorial iremos aprender a como utlilizar o mouse em nossos programas. A captura do movimento e cliques do mouse é feita através dos eventos, aprendidos na lição anterior. Neste exemplos iremos criar duas áreas coloridas, onde uma reagirá com o movimento do mouse, e a outra ao clique do mouse. Vamos ao código:
// Os arquivos de cabeçalho #include <allegro5/allegro.h> #include <allegro5/allegro_native_dialog.h> // Atributos da tela #define LARGURA_TELA 640 #define ALTURA_TELA 480 void error_msg(char *text){ al_show_native_message_box(NULL,"ERRO", "Ocorreu o seguinte erro e o programa sera finalizado:", text,NULL,ALLEGRO_MESSAGEBOX_ERROR); } int main(void){ ALLEGRO_DISPLAY *janela = NULL; ALLEGRO_EVENT_QUEUE *fila_eventos = NULL; ALLEGRO_BITMAP *botao_sair = NULL, *area_central = 0; // Flag que condicionará nosso looping int sair = 0; if (!al_init()){ error_msg("Falha ao inicializar a Allegro"); return -1; } janela = al_create_display(LARGURA_TELA, ALTURA_TELA); if (!janela){ error_msg("Falha ao criar janela"); return -1; } // Configura o título da janela al_set_window_title(janela, "Rotinas de Mouse"); // Torna apto o uso de mouse na aplicação if (!al_install_mouse()){ error_msg("Falha ao inicializar o mouse"); al_destroy_display(janela); return -1; } // Atribui o cursor padrão do sistema para ser usado if (!al_set_system_mouse_cursor(janela, ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT)){ error_msg("Falha ao atribuir ponteiro do mouse"); al_destroy_display(janela); return -1; } // Alocamos o retângulo central da tela area_central = al_create_bitmap(LARGURA_TELA / 2, ALTURA_TELA / 2); if (!area_central){ error_msg("Falha ao criar bitmap"); al_destroy_display(janela); return -1; } // Alocamos o botão para fechar a aplicação botao_sair = al_create_bitmap(100, 50); if (!botao_sair){ error_msg("Falha ao criar botão de saída"); al_destroy_bitmap(area_central); al_destroy_display(janela); return -1; } fila_eventos = al_create_event_queue(); if (!fila_eventos){ error_msg("Falha ao inicializar o fila de eventos"); al_destroy_display(janela); return -1; } // Dizemos que vamos tratar os eventos vindos do mouse al_register_event_source(fila_eventos, al_get_mouse_event_source()); // Flag indicando se o mouse está sobre o retângulo central int na_area_central = 0; while (!sair){ // Verificamos se há eventos na fila while (!al_is_event_queue_empty(fila_eventos)){ ALLEGRO_EVENT evento; al_wait_for_event(fila_eventos, &evento); // Se o evento foi de movimentação do mouse if (evento.type == ALLEGRO_EVENT_MOUSE_AXES){ // Verificamos se ele está sobre a região do retângulo central if (evento.mouse.x >= LARGURA_TELA / 2 - al_get_bitmap_width(area_central) / 2 && evento.mouse.x <= LARGURA_TELA / 2 + al_get_bitmap_width(area_central) / 2 && evento.mouse.y >= ALTURA_TELA / 2 - al_get_bitmap_height(area_central) / 2 && evento.mouse.y <= ALTURA_TELA / 2 + al_get_bitmap_height(area_central) / 2){ na_area_central = 1; } else{ na_area_central = 0; } } // Ou se o evento foi um clique do mouse else if (evento.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP){ if (evento.mouse.x >= LARGURA_TELA - al_get_bitmap_width(botao_sair) - 10 && evento.mouse.x <= LARGURA_TELA - 10 && evento.mouse.y <= ALTURA_TELA - 10 && evento.mouse.y >= ALTURA_TELA - al_get_bitmap_height(botao_sair) - 10){ sair = 1; } } } // Limpamos a tela al_clear_to_color(al_map_rgb(0, 0, 0)); // Colorimos o bitmap correspondente ao retângulo central, // com a cor condicionada ao conteúdo da flag na_area_central al_set_target_bitmap(area_central); if (!na_area_central){ al_clear_to_color(al_map_rgb(255, 255, 255)); } else{ al_clear_to_color(al_map_rgb(0, 255, 0)); } // Colorimos o bitmap do botão de sair al_set_target_bitmap(botao_sair); al_clear_to_color(al_map_rgb(255, 0, 0)); // Desenhamos os retângulos na tela al_set_target_bitmap(al_get_backbuffer(janela)); al_draw_bitmap(area_central, LARGURA_TELA / 2 - al_get_bitmap_width(area_central) / 2, ALTURA_TELA / 2 - al_get_bitmap_height(area_central) / 2, 0); al_draw_bitmap(botao_sair, LARGURA_TELA - al_get_bitmap_width(botao_sair) - 10, ALTURA_TELA - al_get_bitmap_height(botao_sair) - 10, 0); // Atualiza a tela al_flip_display(); } // Desaloca os recursos utilizados na aplicação al_destroy_bitmap(botao_sair); al_destroy_bitmap(area_central); al_destroy_display(janela); al_destroy_event_queue(fila_eventos); return 0; }
No início do programa declaramos algumas variáveis, e iniciamos a biblioteca e addons. Tudo isso já foi visto anteriormente. Vamos direto ao que temos de novo.
Na linha 34 chamamos a função al_set_window_title(), que muda o texto da janela. Ela recebe o display, e a string contendo o texto.
Na linha 37 chamamos a função al_install_mouse(), permite o uso dos eventos relativos à captura de cliques e movimentos do mouse.
Na linha 44 chamamos a função al_install_mouse(), que que serve para definir o tipo de cursor do mouse que será usado em uma determinada janela. Ela recebe como parâmetro o display, e uma flag indicando o tipo de cursor. No exemplo, usamos ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT, que é o cursor padrão. Consulte a referência para conhecer os outros tipos de cursores disponíveis.
Na linha 51 e linha 59 usamos a função al_create_bitmap(), que cria uma área gráfica, chamada bitmap, nas posições X e Y informadas por parâmetro. Já havíamos trabalhado com a função al_load_bitmap(), que carrega uma imagem em um bitmap. A diferença é que al_create_bitmap() cria a área sem atribuir nada a ela, somente com as dimensões especificadas.
Note que nas linhas seguintes criamos a fila de eventos (explicada anteriormente) e inicamos a mesma. Na linha 75 porém, usamos como segundo parâmetro de al_register_event_source() (função que faz com que a fila de eventos guarde os eventos de uma determinada fonte de eventos) o retorno da função al_get_mouse_event_source(). Isto faz com que todos eventos relacionados ao mouse sejam registrados na fila de eventos. Diferente desta, lembre-se que na lição anterior havíamos registrado os eventos da janela na fila.
Os seguintes passos serão executados, até que a flag sair==0:
Na linha 78 criamos a flag na_area_central que começa em 0, e irá receber 1 quando o mouse estiver sobre o bitmap do centro da janela.
Na linha 81 usamos a função al_is_event_queue_empty que verifica se a fila de eventos passada por parâmetro está vazia. Como nossa while está condicionado à esta função, este trecho de código só deixará de ser executado quando todos os eventos tiverem sido tratados.
Neste exemplo, usamos a função al_wait_for_event() na linha 83, que difere da função al_wait_for_event_until() já utilizada porque ela não recebe o timeout como último parâmetro. Isto quer dizer que o programa fica esperando até que o evento aconteça.
Na linha 86 testamos se o tipo do evento disparado é ALLEGRO_EVENT_MOUSE_AXES, que representa o movimento do mouse.
O if das linhas 88 à 91 testa se o ponteiro do mouse está entre as dimensões do bitmap maior, nas coordenadas X e Y. a função al_get_bitmap_width() serve para pegar a largura do bitmap e al_get_bitmap_height() a altura. Os campos mouse.x e mouse.y da variável ALLEGRO_EVENT acessam as posições X e Y do ponteiro do mouse, relativos à janela.
Na linha 99 testamos se o tipo do evento disparado é ALLEGRO_EVENT_MOUSE_BUTTON_UP, que representa o botão do mouse sendo soltado. Caso seja do desejo testar qual botão foi pressionado, usamos o campo mouse.button que possuirá os valores 1, 2 ou 3 para os botões esquerdo, direito e central, respectivamente. O if testa testa se o usuário ao clicar na janela, o cursor está dentro do espaço do bitmap menor. E em caso afirmativo seta a flag sair=1.
Após sair da repetição que verifica os eventos, na linha 113 chamamos a função al_set_target_bitmap() que muda o bitmap ativo para o bitmap area_central. Lembrando que as funções que fazem alterações em bitmaps (mudança de cor, desenho, etc) levam consideração sempre o bitmap ativo (por padrão o último display criado). Como já colorimos a janela com a cor preta na linha 109 e agora queremos colorir o bitmap area_central, devemos mudar o bitmap ativo. Por isso chamamos a função al_set_target_bitmap(). Em seguida colorimos ele na cor branca (R:255 G:255 B:255) ou na cor verde (R:0 G:255 B:0), dependendo do valor da flag na_area_central (que depende da posição do cursor do mouse, conforme vimos acima, na linha 92). Em seguida o mesmo é feito com o outro bitmap, o botao_sair.
Na linha 126 queremos devolver o bitmap ativo para a janela, pois chegou o momento de escrever a area_central e botao_sair nela. Então chamamos a função al_set_target_bitmap(), mas ao invés de usar a janela como parâmetro, chamamos a função al_get_backbuffer(). E o porque disso será explicado.
Existem duas áreas de desenho da tela: O front buffer, e o back buffer. Quando criamos o display, automaticamente ele se torna o display ativo (isso já sabemos), e todas rotinas de desenho são feitas no back buffer desse display. O que está no front buffer é o que é mostrado na tela. Pontanto, ao usar a função al_flip_display(), o conteúdo do front e back buffer se inverte, fazendo com que mostremos o que antes estava no back buffer, por isso chamamos essa função de "função que atualiza a tela".
Com isso, percebemos que o bitmat ativo (aquele que desenhamos em cima) nunca deve ser o front buffer do display. Por conta disso, que quando mudamos o bitmap ativo de volta para a janela, precisamos mudar para o back buffer da janela, daí entra a função al_get_backbuffer().
Daí em diante no código é simples, desenhamos os dois bitmaps em posições diferentes da janela (no back buffer dela), e atualizamos a tela (trocando o front com o back buffer).