Beispiel #1
0
/* Test al_ustr_length. */
static void t27(void)
{
   ALLEGRO_USTR *us = al_ustr_new("aþ€\xf4\x8f\xbf\xbf");

   CHECK(0 == al_ustr_length(al_ustr_empty_string()));
   CHECK(4 == al_ustr_length(us));

   al_ustr_free(us);
}
Beispiel #2
0
bool InputField::Input(ALLEGRO_EVENT &ev, float &scalex, float &scaley)
{
    int unichar = 0;

    detectingbutton->Input(ev, scalex, scaley);

    if(detectingbutton->is_button_clicked() == true && detectingbutton->is_mouse_in_it() == false &&
       ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN && ev.mouse.button == 1)
    {
        detectingbutton->unclick();
    }
    else if(detectingbutton->is_button_clicked() == true)
    {
        if(ev.type == ALLEGRO_EVENT_KEY_CHAR && (ev.keyboard.keycode == ALLEGRO_KEY_BACKSPACE || ev.keyboard.keycode == ALLEGRO_KEY_ENTER))
        {
            switch(ev.keyboard.keycode)
            {
                case ALLEGRO_KEY_BACKSPACE :
                    if(al_ustr_length(al_text) > 0)
                    {
                        al_ustr_remove_chr(al_text, al_ustr_length(al_text)-1);
                    }
                    break;
                case ALLEGRO_KEY_ENTER :
                    detectingbutton->unclick();
                    break;
            }
        }
        else if(ev.type == ALLEGRO_EVENT_KEY_CHAR)
        {
            if(lenght_limit == true && (int)text.size() >= max_lenght)
            {
                return true;
            }
            unichar = ev.keyboard.unichar;

            if(unichar >= 32)
            {
                al_ustr_append_chr(al_text, unichar);
            }
        }
    }

    text = al_cstr_dup(al_text);
    text_width = al_get_text_width(font, text.c_str()) + 7;


    return true;
}
Beispiel #3
0
/* Function: al_create_path_for_directory
 */
ALLEGRO_PATH *al_create_path_for_directory(const char *str)
{
   ALLEGRO_PATH *path = al_create_path(str);
   if (al_ustr_length(path->filename)) {
      ALLEGRO_USTR *last = path->filename;
      path->filename = al_ustr_new("");
      al_append_path_component(path, al_cstr(last));
      al_ustr_free(last);
   }
   return path;
}
Beispiel #4
0
void wz_def_draw_editbox(struct WZ_THEME* theme, float x, float y, float w, float h, int cursor_pos, ALLEGRO_USTR* text, int style)
{
	WZ_DEF_THEME* thm = (WZ_DEF_THEME*)theme;
	int len = wz_get_text_pos(thm->font, text, w - 4);
	int cx,cy,cw,ch;
	int len2 = al_ustr_length(text);
	int offset;
	ALLEGRO_USTR_INFO info;
	ALLEGRO_USTR* token;
	ALLEGRO_COLOR border_col;
	ALLEGRO_COLOR text_col;
	len = len + 1 > len2 ? len2 : len + 1;
	
	offset = al_ustr_offset(text, len);
	
	token = al_ref_ustr(&info, text, 0, offset);
	
	border_col = thm->color1;
	text_col = thm->color2;
	
	if (style & WZ_STYLE_FOCUSED)
	{
		border_col = wz_scale_color(thm->color1, 1.5);
	}
	if (style & WZ_STYLE_DISABLED)
	{
		border_col = wz_scale_color(thm->color1, 0.5);
		text_col = wz_scale_color(thm->color2, 0.5);
	}
	
	wz_draw_3d_rectangle(x, y, x + w, y + h, 1, border_col, true);
	
	al_get_clipping_rectangle(&cx, &cy, &cw, &ch);
	al_set_clipping_rectangle(x + 2, y + 2, w - 4, h - 4);
	wz_draw_single_text(x + 2, y + 2, w - 4, h - 4, WZ_ALIGN_LEFT, WZ_ALIGN_CENTRE, text_col, thm->font, token);
	al_set_clipping_rectangle(cx, cy, cw, ch);
	
	if (style & WZ_STYLE_FOCUSED)
	{
		if (((int)(al_get_time() / 0.5f)) % 2 == 0)
		{
			float len;
			float halfheight;
			offset = al_ustr_offset(text, cursor_pos);
			token = al_ref_ustr(&info, text, 0, offset);
			len = al_get_ustr_width(thm->font, token);
			halfheight = al_get_font_line_height(thm->font) / 2.0f;
			al_draw_line(x + 2 + len, y + 2 + h / 2 - halfheight, x + 2 + len, y + 2 + h / 2 + halfheight, text_col, 1);
		}
	}
}
Beispiel #5
0
/* Function: al_ustr_offset
 */
int al_ustr_offset(const ALLEGRO_USTR *us, int index)
{
   int pos = 0;

   if (index < 0)
      index += al_ustr_length(us);

   while (index-- > 0) {
      if (!al_ustr_next(us, &pos))
         return pos;
   }

   return pos;
}
Beispiel #6
0
void wz_snap_editbox(WZ_EDITBOX* box)
{
	WZ_WIDGET* wgt = (WZ_WIDGET*)box;
	ALLEGRO_FONT* font = wgt->theme->get_font(wgt->theme, 0);
	int len = al_ustr_length(box->text);
	int size = al_ustr_size(box->text);
	
	int scroll_offset = al_ustr_offset(box->text, box->scroll_pos);
	int cursor_offset;
	ALLEGRO_USTR_INFO info;
	ALLEGRO_USTR* text = al_ref_ustr(&info, box->text, scroll_offset, size);
	
	int max_rel_cursor_pos = wz_get_text_pos(font, text, wgt->w);
	
	if (box->cursor_pos < box->scroll_pos)
	{
		box->scroll_pos = box->cursor_pos;
	}
	if (box->cursor_pos > box->scroll_pos + max_rel_cursor_pos)
	{
		box->scroll_pos = box->cursor_pos - max_rel_cursor_pos;
	}
	
	if (box->cursor_pos > 0 && box->cursor_pos - box->scroll_pos < 1)
	{
		box->scroll_pos--;
	}
	
	if (box->cursor_pos > len)
	{
		box->cursor_pos = len;
	}
	if (box->cursor_pos < 0)
	{
		box->cursor_pos = 0;
	}
	
	scroll_offset = al_ustr_offset(box->text, box->scroll_pos);
	cursor_offset = al_ustr_offset(box->text, box->cursor_pos);
	
	text = al_ref_ustr(&info, box->text, scroll_offset, cursor_offset);
	if (al_get_ustr_width(font, text) > wgt->w)
	{
		box->scroll_pos++;
	}
}
Beispiel #7
0
/*
Function: wz_get_text_pos

Parameters:

text - the text you want to search
x - the length you want to match

Returns:

The character position such that the text length of the string up to that character
is as close as possible to the passed length.
*/
int wz_get_text_pos(ALLEGRO_FONT* font, ALLEGRO_USTR* text, float x)
{
	int ii = 0;
	int len = al_ustr_length(text);
	float width = al_get_ustr_width(font, text);

	if(x > width)
	{
		return len + 1;
	}

	if(x < 0)
	{
		return 0;
	}
	else
	{
		float old_diff = x;
		float diff;
		ALLEGRO_USTR_INFO info;

		for(ii = 0; ii <= len; ii++)
		{
			int offset = al_ustr_offset(text, ii);
			const ALLEGRO_USTR* str = al_ref_ustr(&info, text, 0, offset);
			diff = fabs(x - al_get_ustr_width(font, str));

			if(diff > old_diff)
			{
				return ii - 1;
			}

			old_diff = diff;
		}
	}

	return ii - 1;
}
Beispiel #8
0
/* Test UTF-16 conversion. */
static void t50(void)
{
   ALLEGRO_USTR *us;
   char utf8[] = "⅛-note: 𝅘𝅥𝅮, domino: 🁡";
   uint16_t *utf16;
   size_t s;
   uint16_t little[8];
   /* Only native byte order supported right now, so have to specify
    * elements as uint16_t and not as char.
    */
   uint16_t utf16_ref[] = {
      0x215b, 0x002d, 0x006e, 0x006f, 0x0074,
      0x0065, 0x003a, 0x0020, 0xd834, 0xdd60,
      0x002c, 0x0020, 0x0064, 0x006f, 0x006d,
      0x0069, 0x006e, 0x006f, 0x003a, 0x0020,
      0xd83c, 0xdc61, 0x0000};
   uint16_t truncated[] = {
      0x215b, 0x002d, 0x006e, 0x006f, 0x0074,
      0x0065, 0x003a, 0x0000};

   us = al_ustr_new_from_utf16(utf16_ref);
   CHECK(20 == al_ustr_length(us));
   CHECK(0 == strcmp(utf8, al_cstr(us)));
   al_ustr_free(us);

   us = al_ustr_new(utf8);
   s = al_ustr_size_utf16(us);
   CHECK(46 == s);
   utf16 = malloc(s);
   al_ustr_encode_utf16(us, utf16, s);
   CHECK(0 == memcmp(utf16, utf16_ref, s));
   free(utf16);
   
   s = al_ustr_encode_utf16(us, little, sizeof little);
   CHECK(16 == s);
   CHECK(0 == memcmp(truncated, little, s));
   al_ustr_free(us);
}
Beispiel #9
0
/* Print some text with a shadow. */
static void print(int x, int y, bool vertical, char const *format, ...)
{
   va_list list;
   char message[1024];
   ALLEGRO_COLOR color;
   int h;
   int j;

   va_start(list, format);
   vsnprintf(message, sizeof message, format, list);
   va_end(list);

   al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
   h = al_get_font_line_height(ex.myfont);

   for (j = 0; j < 2; j++) {
      if (j == 0)
         color = al_map_rgb(0, 0, 0);
      else
         color = al_map_rgb(255, 255, 255);

      if (vertical) {
         int i;
         ALLEGRO_USTR_INFO ui;
         const ALLEGRO_USTR *us = al_ref_cstr(&ui, message);
         for (i = 0; i < (int)al_ustr_length(us); i++) {
            ALLEGRO_USTR_INFO letter;
            al_draw_ustr(ex.myfont, color, x + 1 - j, y + 1 - j + h * i, 0,
               al_ref_ustr(&letter, us, al_ustr_offset(us, i),
               al_ustr_offset(us, i + 1)));
         }
      }
      else {
         al_draw_text(ex.myfont, color, x + 1 - j, y + 1 - j, 0, message);
      }
   }
}
Beispiel #10
0
/*
Title: Edit Box

Section: Internal

Function: wz_editbox_proc

See also:
<wz_widget_proc>
*/
int wz_editbox_proc(WZ_WIDGET* wgt, ALLEGRO_EVENT* event)
{
	int ret = 1;
	WZ_EDITBOX* box = (WZ_EDITBOX*)wgt;
	switch (event->type)
	{
		case WZ_DRAW:
		{
			if (wgt->flags & WZ_STATE_HIDDEN)
			{
				ret = 0;
			}
			else
			{
				int size = al_ustr_size(box->text);
				int scroll_offset = al_ustr_offset(box->text, box->scroll_pos);
				ALLEGRO_USTR_INFO info;
				ALLEGRO_USTR* text = al_ref_ustr(&info, box->text, scroll_offset, size);
				
				int pos = box->cursor_pos - box->scroll_pos;
			
				int flags = 0;
				if(wgt->flags & WZ_STATE_DISABLED)
					flags = WZ_STYLE_DISABLED;
				else if(wgt->flags & WZ_STATE_HAS_FOCUS)
					flags = WZ_STYLE_FOCUSED;
			
				wgt->theme->draw_editbox(wgt->theme, wgt->local_x, wgt->local_y, wgt->w, wgt->h, pos, text, flags);
			}
			break;
		}
		case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
		{
			if (wgt->flags & WZ_STATE_DISABLED)
			{
				ret = 0;
			}
			else if (event->mouse.button == 1 && wz_widget_rect_test(wgt, event->mouse.x, event->mouse.y))
			{
				int len = al_ustr_length(box->text);
				ALLEGRO_USTR_INFO info;
				ALLEGRO_USTR* text = al_ref_ustr(&info, box->text, box->scroll_pos, len - 1);
			
				ALLEGRO_FONT* font = wgt->theme->get_font(wgt->theme, 0);
				wz_ask_parent_for_focus(wgt);
				box->cursor_pos = wz_get_text_pos(font, text, event->mouse.x - wgt->x) + box->scroll_pos;
			}
			else
				ret = 0;
			break;
		}
#if (ALLEGRO_SUB_VERSION > 0)
		case ALLEGRO_EVENT_TOUCH_BEGIN:
		{
			if (wgt->flags & WZ_STATE_DISABLED)
			{
				ret = 0;
			}
			else if (wz_widget_rect_test(wgt, event->touch.x, event->touch.y))
			{
				int len = al_ustr_length(box->text);
				ALLEGRO_USTR_INFO info;
				ALLEGRO_USTR* text = al_ref_ustr(&info, box->text, box->scroll_pos, len - 1);

				ALLEGRO_FONT* font = wgt->theme->get_font(wgt->theme, 0);
				wz_ask_parent_for_focus(wgt);
				box->cursor_pos = wz_get_text_pos(font, text, event->touch.x - wgt->x) + box->scroll_pos;
			}
			else
				ret = 0;
			break;
		}
#endif
		case WZ_HANDLE_SHORTCUT:
		{
			wz_ask_parent_for_focus(wgt);
			break;
		}
		case WZ_DESTROY:
		{
			if(box->own)
				al_ustr_free(box->text);
			ret = 0;
			break;
		}
		case ALLEGRO_EVENT_KEY_CHAR:
		{
			int len;
			if(wgt->flags & WZ_STATE_DISABLED || !(wgt->flags & WZ_STATE_HAS_FOCUS))
			{
				ret = 0;
				break;
			}
			else if(event->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL || event->keyboard.modifiers & ALLEGRO_KEYMOD_ALT)
			{
				ret = 0;
			}
			
			len = al_ustr_length(box->text);
			
			if((int)(event->keyboard.unichar) > 31 && (int)(event->keyboard.unichar) != 127)
			{
				al_ustr_insert_chr(box->text, al_ustr_offset(box->text, box->cursor_pos), event->keyboard.unichar);
				box->cursor_pos++;
			}
			else
			{
				switch (event->keyboard.keycode)
				{
					case ALLEGRO_KEY_BACKSPACE:
					{
						if (len > 0 && box->cursor_pos > 0)
						{
							al_ustr_remove_chr(box->text, al_ustr_offset(box->text, box->cursor_pos - 1));
							box->cursor_pos--;
						}
						break;
					}
					case ALLEGRO_KEY_DELETE:
					{
						if (len > 0 && box->cursor_pos < len)
						{
							al_ustr_remove_chr(box->text, al_ustr_offset(box->text, box->cursor_pos));
						}
						break;
					}
					case ALLEGRO_KEY_LEFT:
					{
						if (box->cursor_pos > 0)
						{
							box->cursor_pos--;
						}
						else
							ret = 0;
						break;
					}
					case ALLEGRO_KEY_RIGHT:
					{
						if (box->cursor_pos < len)
						{
							box->cursor_pos++;
						}
						else
							ret = 0;
						break;
					}
					case ALLEGRO_KEY_HOME:
					{
						box->cursor_pos = 0;
						break;
					}
					case ALLEGRO_KEY_END:
					{
						len = al_ustr_length(box->text);
						box->cursor_pos = len;
						break;
					}
					case ALLEGRO_KEY_ENTER:
					{
						wz_trigger(wgt);
						break;
					}
					default:
						ret = 0;
				}
			}
			
			wz_snap_editbox(box);
			
			break;
		}
		case WZ_SET_CURSOR_POS:
		{
			box->cursor_pos = event->user.data3;
			wz_snap_editbox(box);
		}
		case WZ_SET_TEXT:
		{
			if(box->own)
			{
				al_ustr_assign(box->text, (ALLEGRO_USTR*)event->user.data3);
			}
			else
				box->text = (ALLEGRO_USTR*)event->user.data3;
			wz_snap_editbox(box);
			break;
		}
		case WZ_TRIGGER:
		{
			ALLEGRO_EVENT ev;
			wz_craft_event(&ev, WZ_TEXT_CHANGED, wgt, 0);
			al_emit_user_event(wgt->source,	&ev, 0);
			break;
		}
		case ALLEGRO_EVENT_MOUSE_AXES:
		{
			if (wgt->flags & WZ_STATE_DISABLED)
			{
				ret = 0;
			}
			if (wz_widget_rect_test(wgt, event->mouse.x, event->mouse.y))
			{
				wz_ask_parent_for_focus(wgt);
			}
			return wz_widget_proc(wgt, event);
			break;
		}
		default:
			ret = 0;
	}
	if (ret == 0)
		ret = wz_widget_proc(wgt, event);
	return ret;
}
Beispiel #11
0
static void render(void)
{
    ALLEGRO_COLOR white = al_map_rgba_f(1, 1, 1, 1);
    ALLEGRO_COLOR black = al_map_rgba_f(0, 0, 0, 1);
    ALLEGRO_COLOR red = al_map_rgba_f(1, 0, 0, 1);
    ALLEGRO_COLOR green = al_map_rgba_f(0, 0.5, 0, 1);
    ALLEGRO_COLOR blue = al_map_rgba_f(0.1, 0.2, 1, 1);
    ALLEGRO_COLOR purple = al_map_rgba_f(0.3, 0.1, 0.2, 1);
    int x, y, w, h, as, de, xpos, ypos;
    unsigned int index;
    int target_w, target_h;
    ALLEGRO_USTR_INFO info, sub_info;
    const ALLEGRO_USTR *u;
    ALLEGRO_USTR *tulip = al_ustr_new("Tulip");
    ALLEGRO_USTR *dimension_text = al_ustr_new("Tulip");
    ALLEGRO_USTR *vertical_text  = al_ustr_new("Rose.");

    al_clear_to_color(white);

    al_hold_bitmap_drawing(true);

    al_draw_textf(ex.f1, black, 50,  20, 0, "Tulip (kerning)");
    al_draw_textf(ex.f2, black, 50,  80, 0, "Tulip (no kerning)");

    x = 50;
    y = 140;
    for (index = 0; index < al_ustr_length(dimension_text); index ++) {
       int cp  = ustr_at(dimension_text, index);
       int bbx, bby, bbw, bbh;
       al_get_glyph_dimensions(ex.f2, cp, &bbx, &bby, &bbw, &bbh);
       al_draw_rectangle(x + bbx + 0.5, y + bby + 0.5, x + bbx + bbw - 0.5, y + bby + bbh - 0.5, blue, 1);
       al_draw_rectangle(x + 0.5, y + 0.5, x + bbx + bbw - 0.5, y + bby + bbh - 0.5, green, 1);
       al_draw_glyph(ex.f2, purple, x, y, cp);
       x += al_get_glyph_advance(ex.f2, cp, ALLEGRO_NO_KERNING);
    }
    al_draw_line(50.5, y+0.5, x+0.5, y+0.5, red, 1);
    al_draw_textf(ex.f2, black, x + 10, y, 0, "(dimensions)");

    al_draw_textf(ex.f3, black, 50, 200, 0, "This font has a size of 12 pixels, "
        "the one above has 48 pixels.");

    al_hold_bitmap_drawing(false);
    al_hold_bitmap_drawing(true);

    al_draw_textf(ex.f3, red, 50, 220, 0, "The color can simply be changed.🐊← fallback glyph");

    al_hold_bitmap_drawing(false);
    al_hold_bitmap_drawing(true);

    al_draw_textf(ex.f3, green, 50, 240, 0, "Some unicode symbols:");
    al_draw_textf(ex.f3, green, 50, 260, 0, "%s", get_string("symbols1"));
    al_draw_textf(ex.f3, green, 50, 280, 0, "%s", get_string("symbols2"));
    al_draw_textf(ex.f3, green, 50, 300, 0, "%s", get_string("symbols3"));

   #define OFF(x) al_ustr_offset(u, x)
   #define SUB(x, y) al_ref_ustr(&sub_info, u, OFF(x), OFF(y))
    u = al_ref_cstr(&info, get_string("substr1"));
    al_draw_ustr(ex.f3, green, 50, 320, 0, SUB(0, 6));
    u = al_ref_cstr(&info, get_string("substr2"));
    al_draw_ustr(ex.f3, green, 50, 340, 0, SUB(7, 11));
    u = al_ref_cstr(&info, get_string("substr3"));
    al_draw_ustr(ex.f3, green, 50, 360, 0, SUB(4, 11));
    u = al_ref_cstr(&info, get_string("substr4"));
    al_draw_ustr(ex.f3, green, 50, 380, 0, SUB(0, 11));

    al_draw_textf(ex.f5, black, 50, 395, 0, "forced monochrome");

    /* Glyph rendering tests. */
    al_draw_textf(ex.f3, red, 50, 410, 0, "Glyph adv Tu: %d, draw: ",
                        al_get_glyph_advance(ex.f3, 'T', 'u'));
    x = 50;
    y = 425;
    for (index = 0; index < al_ustr_length(tulip); index ++) {
       int cp  = ustr_at(tulip, index);
       /* Use al_get_glyph_advance for the stride, with no kerning. */
       al_draw_glyph(ex.f3, red, x, y, cp);
       x += al_get_glyph_advance(ex.f3, cp, ALLEGRO_NO_KERNING);
    }

    x = 50;
    y = 440;
    /* First draw a red string using al_draw_text, that should be hidden
     * completely by the same text drawing in green per glyph
     * using al_draw_glyph and al_get_glyph_advance below. */
    al_draw_ustr(ex.f3, red, x, y, 0, tulip);
    for (index = 0; index < al_ustr_length(tulip); index ++) {
      int cp  = ustr_at(tulip, index);
      int ncp = (index < (al_ustr_length(tulip) - 1)) ?
         ustr_at(tulip, index + 1) : ALLEGRO_NO_KERNING;
      /* Use al_get_glyph_advance for the stride and apply kerning. */
      al_draw_glyph(ex.f3, green, x, y, cp);
      x += al_get_glyph_advance(ex.f3, cp, ncp);
    }

    x = 50;
    y = 466;
    al_draw_ustr(ex.f3, red, x, y, 0, tulip);
    for (index = 0; index < al_ustr_length(tulip); index ++) {
      int cp  = ustr_at(tulip, index);
      int bbx, bby, bbw, bbh;
      al_get_glyph_dimensions(ex.f3, cp, &bbx, &bby, &bbw, &bbh);
      al_draw_glyph(ex.f3, blue, x, y, cp);
      x += bbx + bbw;
    }


    x = 10;
    y = 30;
    for (index = 0; index < al_ustr_length(vertical_text); index ++) {
      int bbx, bby, bbw, bbh;
      int cp  = ustr_at(vertical_text, index);
      /* Use al_get_glyph_dimensions for the height to apply. */
      al_get_glyph_dimensions(ex.f3, cp, &bbx, &bby, &bbw, &bbh);
      al_draw_glyph(ex.f3, green, x, y, cp);
      y += bby;
      y += bbh;
    }


    x = 30;
    y = 30;
    for (index = 0; index < al_ustr_length(vertical_text); index ++) {
      int bbx, bby, bbw, bbh;
      int cp  = ustr_at(vertical_text, index);
      /* Use al_get_glyph_dimensions for the height to apply, here bby is
       * omited for the wrong result. */
      al_get_glyph_dimensions(ex.f3, cp, &bbx, &bby, &bbw, &bbh);
      al_draw_glyph(ex.f3, red, x, y, cp);
      y += bbh;
    }


    al_hold_bitmap_drawing(false);

    target_w = al_get_bitmap_width(al_get_target_bitmap());
    target_h = al_get_bitmap_height(al_get_target_bitmap());

    xpos = target_w - 10;
    ypos = target_h - 10;
    al_get_text_dimensions(ex.f4, "Allegro", &x, &y, &w, &h);
    as = al_get_font_ascent(ex.f4);
    de = al_get_font_descent(ex.f4);
    xpos -= w;
    ypos -= h;
    x += xpos;
    y += ypos;

    al_draw_rectangle(x, y, x + w - 0.5, y + h - 0.5, black, 0);
    al_draw_line(x+0.5, y + as + 0.5, x + w - 0.5, y + as + 0.5, black, 0);
    al_draw_line(x + 0.5, y + as + de + 0.5, x + w - 0.5, y + as + de + 0.5, black, 0);

    al_hold_bitmap_drawing(true);
    al_draw_textf(ex.f4, blue, xpos, ypos, 0, "Allegro");
    al_hold_bitmap_drawing(false);

    al_hold_bitmap_drawing(true);

    al_draw_textf(ex.f3, black, target_w, 0, ALLEGRO_ALIGN_RIGHT,
       "%.1f FPS", ex.fps);

    al_draw_textf(ex.f3, black, 0, 0, 0, "%s: %d unicode ranges", font_file,
       ex.ranges_count);

    al_hold_bitmap_drawing(false);
}