[Tux4kids-commits] r1160 - tuxmath/trunk/src

Bolesław Kulbabiński bolekk-guest at alioth.debian.org
Wed Jul 8 15:06:19 UTC 2009


Author: bolekk-guest
Date: 2009-07-08 15:06:19 +0000 (Wed, 08 Jul 2009)
New Revision: 1160

Modified:
   tuxmath/trunk/src/menu.c
Log:
added search for best menu font size

Modified: tuxmath/trunk/src/menu.c
===================================================================
--- tuxmath/trunk/src/menu.c	2009-07-08 13:29:50 UTC (rev 1159)
+++ tuxmath/trunk/src/menu.c	2009-07-08 15:06:19 UTC (rev 1160)
@@ -54,44 +54,51 @@
 /*TODO: move these constants into a config file (maybe together with
   titlescreen paths and rects ? ) */
 const float menu_pos[4] = {0.4, 0.25, 0.55, 0.7};
-const float stop_pos[4] = {0.95, 0.0, 0.05, 0.05};
+const float stop_pos[4] = {0.94, 0.0, 0.06, 0.06};
 const float prev_pos[4] = {0.9, 0.95, 0.05, 0.05};
 const float next_pos[4] = {0.95, 0.95, 0.05, 0.05};
 const char* stop_path = "status/stop.png";
 const char* prev_path = "status/left.png";
 const char* next_path = "status/right.png";
 const float button_gap = 0.2, text_h_gap = 0.4, text_w_gap = 0.5;
+const int min_font_size = 8, default_font_size = 20, max_font_size = 40;
 
+/* font size used in current resolution */
+int curr_font_size;
+
 /* menu title rect */
 SDL_Rect title_rect;
 
-
-
 /* buffer size used when reading attributes or names */
 const int buf_size = 128;
 
 
 
 /* local functions */
-MenuNode* create_empty_node();
-char* get_attribute_name(const char* token);
-char* get_attribute_value(const char* token);
-void read_attributes(FILE* xml_file, MenuNode* node);
-MenuNode* load_menu_from_file(FILE* xml_file, MenuNode* parent);
-void free_menu(MenuNode* menu);
+MenuNode*       create_empty_node();
+char*           get_attribute_name(const char* token);
+char*           get_attribute_value(const char* token);
+void            read_attributes(FILE* xml_file, MenuNode* node);
+MenuNode*       load_menu_from_file(FILE* xml_file, MenuNode* parent);
+void            free_menu(MenuNode* menu);
+MenuNode*       create_one_level_menu(int items, char** item_names, char* title, char* trailer);
 
-int handle_activity(int act);
-int run_academy(void);
+int             handle_activity(int act);
+int             run_academy(void);
 
-int run_menu(MenuNode* menu, bool return_choice);
-void prerender_menu(MenuNode* menu);
-void prerender_all();
-SDL_Surface** render_buttons(MenuNode* menu, bool selected);
-MenuNode* create_one_level_menu(int items, char** item_names, char* title, char* trailer);
+int             run_menu(MenuNode* menu, bool return_choice);
+SDL_Surface**   render_buttons(MenuNode* menu, bool selected);
+void            prerender_menu(MenuNode* menu);
+void            set_rect(SDL_Rect* rect, const float* pos);
+char*           find_longest_text(MenuNode* menu, int* length);
+void            set_font_size();
+void            prerender_all();
 
 
+
 /*
   functions responsible for parsing menu files
+  and creating menu trees
 */
 
 /* creates new MenuNode struct with all fields set to NULL (or 0) */
@@ -229,7 +236,34 @@
   }
 }
 
+/* create a simple one-level menu without sprites.
+   all given strings are copied */
+MenuNode* create_one_level_menu(int items, char** item_names, char* title, char* trailer)
+{
+  MenuNode* menu = create_empty_node();
+  int i;
 
+  if(title)
+    menu->title = strdup(title);
+  menu->submenu_size = items + (trailer ? 1 : 0);
+  menu->submenu = (MenuNode**) malloc(menu->submenu_size * sizeof(MenuNode*));
+  for(i = 0; i < items; i++)
+  {
+    menu->submenu[i] = create_empty_node();
+    menu->submenu[i]->title = strdup(item_names[i]);
+    menu->submenu[i]->activity = i;
+  }
+
+  if(trailer)
+  {
+    menu->submenu[items] = create_empty_node();
+    menu->submenu[items]->title = strdup(trailer);
+    menu->submenu[items]->activity = items;
+  }
+
+  return menu;
+}
+
 /*
   handlers for specific game activities
 */
@@ -306,7 +340,6 @@
 {
   SDL_Surface** menu_item_unselected = NULL;
   SDL_Surface** menu_item_selected = NULL;
-  //SDL_Surface* title = NULL;
   SDL_Event event;
   MenuNode* menu = root;
   MenuNode* tmp_node;
@@ -355,9 +388,9 @@
 
     SDL_WM_GrabInput(SDL_GRAB_OFF);
 
-    /******** Main loop:                                *********/
     while (SDL_PollEvent(&event));  // clear pending events
 
+    /******** Main loop: *********/
     stop = false;
     DEBUGMSG(debug_menu, "run_menu(): entering menu loop\n");
     while (!stop)
@@ -378,13 +411,11 @@
 
           case SDL_MOUSEMOTION:
           {
-            loc = -1;  // By default, don't be in any entry
-
+            loc = -1;
             for (i = 0; i < items; i++)
             {
               if (inRect(menu->submenu[menu->first_entry + i]->button_rect, event.motion.x, event.motion.y))
               {
-                // Play sound if loc is being changed:
                 if (Opts_GetGlobalOpt(MENU_SOUND) && old_loc != i)
                   playsound(SND_TOCK);
                 loc = i;
@@ -393,49 +424,43 @@
             }
 
             /* "Left" button - make click if button active: */
-            if (inRect(prev_rect, event.motion.x, event.motion.y))
+            if(inRect(prev_rect, event.motion.x, event.motion.y)
+               && menu->first_entry > 0 && Opts_GetGlobalOpt(MENU_SOUND))
             {
-              if (menu->first_entry > 0)
+              if(click_flag)
               {
-                if (Opts_GetGlobalOpt(MENU_SOUND) && click_flag)
-                {
-                  playsound(SND_TOCK);
-                  click_flag = 0;
-                }
+                playsound(SND_TOCK);
+                click_flag = 0;
               }
-              break;  /* from case switch */
             }
 
-            /* "Right" button - go to next page: */
-            else if (inRect(next_rect, event.motion.x, event.motion.y ))
+            /* "Right" button - make click if button active: */
+            else if(inRect(next_rect, event.motion.x, event.motion.y)
+               && menu->first_entry + items < menu->submenu_size
+               && Opts_GetGlobalOpt(MENU_SOUND))
             {
-              if (menu->first_entry + items < menu->submenu_size)
+              if(click_flag)
               {
-                if (Opts_GetGlobalOpt(MENU_SOUND) && click_flag)
-                {
-                  playsound(SND_TOCK);
-                  click_flag = 0;
-                }
+                playsound(SND_TOCK);
+                click_flag = 0;
               }
-              break;  /* from case switch */
             }
 
             /* "stop" button */
-            else if (inRect(stop_rect, event.motion.x, event.motion.y ))
+            else if (inRect(stop_rect, event.motion.x, event.motion.y )
+               && Opts_GetGlobalOpt(MENU_SOUND))
             {
-              if (Opts_GetGlobalOpt(MENU_SOUND) && click_flag)
+              if(click_flag)
               {
                 playsound(SND_TOCK);
                 click_flag = 0;
               }
-              break;
             }
 
             else  // Mouse outside of arrow rects - re-enable click sound:
-            {
               click_flag = 1;
-              break;  /* from case switch */
-            }
+
+            break;
           }
 
           case SDL_MOUSEBUTTONDOWN:
@@ -455,27 +480,21 @@
             }
 
             /* "Left" button */
-            if (inRect(prev_rect, event.motion.x, event.motion.y))
+            if (inRect(prev_rect, event.motion.x, event.motion.y)
+               && menu->first_entry > 0)
             {
-              if (menu->first_entry > 0)
-              {
-                if (Opts_GetGlobalOpt(MENU_SOUND))
-                  playsound(SND_POP);
-                action = PAGEUP;
-              }
-              break;  /* from case switch */
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+                playsound(SND_POP);
+              action = PAGEUP;
             }
 
             /* "Right" button - go to next page: */
-            else if (inRect(next_rect, event.motion.x, event.motion.y ))
+            else if (inRect(next_rect, event.motion.x, event.motion.y )
+               && menu->first_entry + items < menu->submenu_size)
             {
-              if (menu->first_entry + items < menu->submenu_size)
-              {
-                if (Opts_GetGlobalOpt(MENU_SOUND))
-                  playsound(SND_POP);
-                action = PAGEDOWN;
-              }
-              break;  /* from case switch */
+              if (Opts_GetGlobalOpt(MENU_SOUND))
+                playsound(SND_POP);
+              action = PAGEDOWN;
             }
 
             /* "Stop" button - go to main menu: */
@@ -484,11 +503,11 @@
               if (Opts_GetGlobalOpt(MENU_SOUND))
                 playsound(SND_TOCK);
               action = STOP_ESC;
-              break;
             }
+
+            break;
           } /* End of case SDL_MOUSEDOWN */
 
-
           case SDL_KEYDOWN:
           {
             /* Proceed according to particular key pressed: */
@@ -820,7 +839,7 @@
 
     /* text */
     tmp_surf = BlackOutline(_(menu->submenu[menu->first_entry + i]->title),
-                            menu->submenu[menu->first_entry + i]->font_size, selected ? &yellow : &white);
+                            curr_font_size, selected ? &yellow : &white);
     SDL_BlitSurface(tmp_surf, NULL, menu_items[i], &menu->submenu[menu->first_entry + i]->text_rect);
     SDL_FreeSurface(tmp_surf);
   }
@@ -853,7 +872,7 @@
   for(i = 0; i < menu->submenu_size; i++)
   {
     temp_surf = NULL;
-    temp_surf = SimpleText(_(menu->submenu[i]->title), DEFAULT_MENU_FONT_SIZE, &black);
+    temp_surf = SimpleText(_(menu->submenu[i]->title), curr_font_size, &black);
     if(temp_surf)
     {
       max_text_h = max(max_text_h, temp_surf->h);
@@ -885,8 +904,6 @@
     curr_node->text_rect.h = max_text_h;
     curr_node->text_rect.w = max_text_w;
 
-    curr_node->font_size = DEFAULT_MENU_FONT_SIZE;
-
     if(curr_node->icon)
       FreeSprite(curr_node->icon);
 
@@ -911,6 +928,75 @@
   rect->h = pos[3] * screen->h;
 }
 
+char* find_longest_text(MenuNode* menu, int* length)
+{
+  SDL_Surface* text = NULL;
+  char *ret = NULL, *temp = NULL;
+  int i;
+
+  if(menu->submenu_size == 0)
+  {
+    text = SimpleText(_(menu->title), curr_font_size, &black);
+    if(text->w > *length)
+    {
+      *length = text->w;
+      ret = menu->title;
+    }
+    SDL_FreeSurface(text);
+  }
+  else
+  {
+    for(i = 0; i < menu->submenu_size; i++)
+    {
+      temp = find_longest_text(menu->submenu[i], length);
+      if(temp)
+        ret = temp;
+    }
+  }
+  return ret;
+}
+
+/* find the longest text in all existing menus and binary search
+   for the best font size */
+void set_font_size()
+{
+  char* longest = NULL;
+  char* temp;
+  SDL_Surface* surf;
+  int length = 0, i, min_f, max_f, mid_f;
+
+  curr_font_size = default_font_size;
+
+  for(i = 0; i < N_OF_MENUS; i++)
+  {
+    if(menus[i])
+    {
+      temp = find_longest_text(menus[i], &length);
+      if(temp)
+        longest = temp;
+    }
+  }
+
+  if(!longest)
+    return;
+
+  min_f = min_font_size;
+  max_f = max_font_size;
+
+  while(min_f < max_f)
+  {
+    mid_f = (min_f + max_f) / 2;
+    surf = SimpleText(_(longest), mid_f, &black);
+    if(surf->w + (1.0 + 2.0 * text_w_gap) * (1.0 + 2.0 * text_h_gap) * surf->h < menu_rect.w)
+      min_f = mid_f + 1;
+    else
+      max_f = mid_f;
+    SDL_FreeSurface(surf);
+  }
+
+  curr_font_size = min_f;
+}
+
 /* prerender arrows, stop button and all non-NULL menus from menus[] array
    this function should be invoked after every resolution change */
 void prerender_all()
@@ -923,18 +1009,23 @@
   if(stop_button)
     SDL_FreeSurface(stop_button);
   stop_button = LoadImageOfBoundingBox(stop_path, IMG_ALPHA, stop_rect.w, stop_rect.h);
+  /* move button to the right */
   stop_rect.x = screen->w - stop_button->w;
 
   set_rect(&prev_rect, prev_pos);
   if(prev_arrow)
     SDL_FreeSurface(prev_arrow);
   prev_arrow = LoadImageOfBoundingBox(prev_path, IMG_ALPHA, prev_rect.w, prev_rect.h);
+  /* move button to the right */
+  prev_rect.x += prev_rect.w - prev_arrow->w;
 
   set_rect(&next_rect, next_pos);
   if(next_arrow)
     SDL_FreeSurface(next_arrow);
   next_arrow = LoadImageOfBoundingBox(next_path, IMG_ALPHA, next_rect.w, next_rect.h);
 
+  set_font_size();
+
   for(i = 0; i < N_OF_MENUS; i++)
     if(menus[i])
       prerender_menu(menus[i]);
@@ -976,34 +1067,8 @@
   prerender_all();
 }
 
-/* create a simple one-level menu without sprites.
-   all given strings are copied */
-MenuNode* create_one_level_menu(int items, char** item_names, char* title, char* trailer)
-{
-  MenuNode* menu = create_empty_node();
-  int i;
 
-  if(title)
-    menu->title = strdup(title);
-  menu->submenu_size = items + (trailer ? 1 : 0);
-  menu->submenu = (MenuNode**) malloc(menu->submenu_size * sizeof(MenuNode*));
-  for(i = 0; i < items; i++)
-  {
-    menu->submenu[i] = create_empty_node();
-    menu->submenu[i]->title = strdup(item_names[i]);
-    menu->submenu[i]->activity = i;
-  }
 
-  if(trailer)
-  {
-    menu->submenu[items] = create_empty_node();
-    menu->submenu[items]->title = strdup(trailer);
-    menu->submenu[items]->activity = items;
-  }
-
-  return menu;
-}
-
 /* create login menu tree, run it and set the user home directory
    -1 indicates that the user wants to quit without logging in,
     0 indicates that a choice has been made. */
@@ -1046,6 +1111,7 @@
 
   while (n_users) {
     // Get the user choice
+    set_font_size();
     prerender_menu(menus[MENU_LOGIN]);
     chosen_login = run_menu(menus[MENU_LOGIN], true);
     // Determine whether there were any modifier (CTRL) keys pressed
@@ -1137,6 +1203,7 @@
     tmp_node->submenu[i]->activity = i;
   }
   menus[MENU_LESSONS] = tmp_node;
+  set_font_size();
   prerender_menu(menus[MENU_LESSONS]);
 
   run_menu(menus[MENU_MAIN], false);




More information about the Tux4kids-commits mailing list