Documentation/Maemo 5 Developer Guide/Porting Software/Scaling Fixed Size Windows

(categorise)
(use <source> and <code>, tidy)
 
(One intermediate revision not shown)
Line 1: Line 1:
-
= Scaling Fixed-size Windows =
 
-
 
When porting existing applications to Maemo, it is sometimes necessary to scale a fixed-size interface to the target screen size. For example, many games written for a specific gaming platform assume the screen size of that platform. Scaling the interface allows you to port the application without completely rewriting it.
When porting existing applications to Maemo, it is sometimes necessary to scale a fixed-size interface to the target screen size. For example, many games written for a specific gaming platform assume the screen size of that platform. Scaling the interface allows you to port the application without completely rewriting it.
-
You can scale a window with <tt>[http://maemo.org/api_refs/5.0/5.0-final/hildon/hildon-HildonAnimationActor.html HildonAnimationActor]</tt>. <tt>HildonAnimationActor</tt> creates an overlay window that can be positioned anywhere on the screen and scaled to any size. The following code demonstrates how to embed a fixed-size <tt>GtkWidget</tt>, main into a <tt>HildonAnimationActor</tt>.
+
You can scale a window with [http://maemo.org/api_refs/5.0/5.0-final/hildon/hildon-HildonAnimationActor.html HildonAnimationActor]. <code>HildonAnimationActor</code> creates an overlay window that can be positioned anywhere on the screen and scaled to any size. The following code demonstrates how to embed a fixed-size <code>GtkWidget</code>, <code>main</code>, into a <code>HildonAnimationActor</code>.
-
In this code snippet, window is a top-level <tt>[http://maemo.org/api_refs/5.0/5.0-final/hildon/HildonWindow.html HildonWindow]</tt>. It assumes that the original size of <tt>main</tt> is 320⨉240, and that you want to scale the window to 800⨉424.
+
In this code snippet, window is a top-level <tt>[http://maemo.org/api_refs/5.0/5.0-final/hildon/HildonWindow.html HildonWindow]</tt>. It assumes that the original size of <code>main</code> is 320&times;240, and that you want to scale the window to 800&times;424.
-
<pre>actor = HILDON_ANIMATION_ACTOR (hildon_animation_actor_new());
+
<source lang="c">
 +
actor = HILDON_ANIMATION_ACTOR (hildon_animation_actor_new());
gtk_container_add (GTK_CONTAINER (actor), main);
gtk_container_add (GTK_CONTAINER (actor), main);
gtk_window_resize (GTK_WINDOW (actor), 320, 240);
gtk_window_resize (GTK_WINDOW (actor), 320, 240);
Line 13: Line 12:
hildon_animation_actor_set_parent (actor, window);
hildon_animation_actor_set_parent (actor, window);
hildon_animation_actor_set_scale (actor, 2.5, 1.77);
hildon_animation_actor_set_scale (actor, 2.5, 1.77);
-
gtk_widget_show_all (GTK_WIDGET (actor));</pre>
+
gtk_widget_show_all (GTK_WIDGET (actor));
 +
</source>
-
This will scale <tt>main</tt> and display it over <tt>window</tt>. <tt>HildonAnimationActor</tt>, however, does not accept any input events, so all keyboard and mouse events will pass directly through to <tt>window</tt>. To make the application respond to user input, you must capture the relevant events on window and pass them to main. For events which have associated screen coordinates, such as mouse clicks, you must transform the coordinates based on the scaling factor.
+
This will scale <code>main</code> and display it over <code>window</code>. <code>HildonAnimationActor</code>, however, does not accept any input events, so all keyboard and mouse events will pass directly through to <code>window</code>. To make the application respond to user input, you must capture the relevant events on window and pass them to main. For events which have associated screen coordinates, such as mouse clicks, you must transform the coordinates based on the scaling factor.
The following code demonstrates how to capture button press and release events from a pointing device. On Maemo-based devices, this corresponds to the press and release of a tap on the screen.
The following code demonstrates how to capture button press and release events from a pointing device. On Maemo-based devices, this corresponds to the press and release of a tap on the screen.
-
<pre>static void
+
<source lang="c">
 +
static void
window_button_proxy (GtkWidget *widget,
window_button_proxy (GtkWidget *widget,
    GdkEventButton *event,
    GdkEventButton *event,
Line 33: Line 34:
                   G_CALLBACK (window_button_proxy), main);
                   G_CALLBACK (window_button_proxy), main);
g_signal_connect (window, "button-release-event",
g_signal_connect (window, "button-release-event",
-
                   G_CALLBACK (window_button_proxy), main);</pre>
+
                   G_CALLBACK (window_button_proxy), main);
 +
</source>
In this example, we've scaled the original application by different scale factors on the horizontal and vertical axes. To maintain the aspect ratio, you may need to use less than the entire available screen space. In this case, you will need to do more sophisticated coordinate transformations in your event-handling code.
In this example, we've scaled the original application by different scale factors on the horizontal and vertical axes. To maintain the aspect ratio, you may need to use less than the entire available screen space. In this case, you will need to do more sophisticated coordinate transformations in your event-handling code.
-
Finally, the following code implements a simple that draws circles for button presses and releases. It scales this widget with HildonAnimationActor and redirects button press and release events to the widget
+
Finally, the following code implements a simple that draws circles for button presses and releases. It scales this widget with <code>HildonAnimationActor</code> and redirects button press and release events to the widget
-
<pre>/*
+
<source lang="c">
 +
/*
window-scaler.c
window-scaler.c
gcc -Wall -o window-scaler window-scaler.c \
gcc -Wall -o window-scaler window-scaler.c \
Line 155: Line 158:
   gtk_main ();
   gtk_main ();
   return 0;
   return 0;
-
}</pre>
+
}
 +
</source>
[[Category:Development]]
[[Category:Development]]
[[Category:Documentation]]
[[Category:Documentation]]
[[Category:Fremantle]]
[[Category:Fremantle]]

Latest revision as of 20:49, 11 August 2010

When porting existing applications to Maemo, it is sometimes necessary to scale a fixed-size interface to the target screen size. For example, many games written for a specific gaming platform assume the screen size of that platform. Scaling the interface allows you to port the application without completely rewriting it.

You can scale a window with HildonAnimationActor. HildonAnimationActor creates an overlay window that can be positioned anywhere on the screen and scaled to any size. The following code demonstrates how to embed a fixed-size GtkWidget, main, into a HildonAnimationActor.

In this code snippet, window is a top-level HildonWindow. It assumes that the original size of main is 320×240, and that you want to scale the window to 800×424.

actor = HILDON_ANIMATION_ACTOR (hildon_animation_actor_new());
gtk_container_add (GTK_CONTAINER (actor), main);
gtk_window_resize (GTK_WINDOW (actor), 320, 240);
hildon_animation_actor_set_position (actor, 0, 56);
hildon_animation_actor_set_parent (actor, window);
hildon_animation_actor_set_scale (actor, 2.5, 1.77);
gtk_widget_show_all (GTK_WIDGET (actor));

This will scale main and display it over window. HildonAnimationActor, however, does not accept any input events, so all keyboard and mouse events will pass directly through to window. To make the application respond to user input, you must capture the relevant events on window and pass them to main. For events which have associated screen coordinates, such as mouse clicks, you must transform the coordinates based on the scaling factor.

The following code demonstrates how to capture button press and release events from a pointing device. On Maemo-based devices, this corresponds to the press and release of a tap on the screen.

static void
window_button_proxy (GtkWidget *widget,
		     GdkEventButton *event,
		     GtkWidget *proxy)
{
  GdkEventButton *newev = (GdkEventButton *) gdk_event_copy ((GdkEvent *) event);
  newev->window = proxy->window;
  newev->x = (gint) (newev->x / 2.5);
  newev->y = (gint) (newev->y / 1.77);
  gdk_event_put ((GdkEvent *) newev);
}
g_signal_connect (window, "button-press-event",
                  G_CALLBACK (window_button_proxy), main);
g_signal_connect (window, "button-release-event",
                  G_CALLBACK (window_button_proxy), main);

In this example, we've scaled the original application by different scale factors on the horizontal and vertical axes. To maintain the aspect ratio, you may need to use less than the entire available screen space. In this case, you will need to do more sophisticated coordinate transformations in your event-handling code.

Finally, the following code implements a simple that draws circles for button presses and releases. It scales this widget with HildonAnimationActor and redirects button press and release events to the widget

/*
window-scaler.c
gcc -Wall -o window-scaler window-scaler.c \
  `pkg-config --cflags --libs gtk+-2.0 hildon-1 cairo`
*/
 
#include <cairo.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <math.h>
#include <stdlib.h>
#include <hildon/hildon.h>
 
static gint X_SIZE = 320;
static gint Y_SIZE = 240;
 
static gint X_POS = 0;
static gint Y_POS = 56;
 
/* Using 800x424 as fullscreen */
static gdouble X_SCALE = 2.5;  /* width / X_SIZE */
static gdouble Y_SCALE = 1.77; /* height / Y_SIZE */
 
 
/** Simple drawing widget **/
 
static void
drawing_button_event (GtkWidget *drawing,
		      GdkEventButton *event,
		      cairo_t *context)
{
  cairo_new_path (context);
  cairo_move_to (context, event->x + 5, event->y);
  cairo_arc (context, event->x, event->y, 5, 0, 2 * M_PI);
  if (event->type == GDK_BUTTON_PRESS)
    cairo_set_source_rgb (context, 1.0, 0.0, 0.0);
  else
    cairo_set_source_rgb (context, 0.0, 0.0, 1.0);
  cairo_fill (context);
}
 
static void
drawing_realize (GtkWidget *drawing,
		 gpointer user_data)
{
  cairo_t *context;
  context = gdk_cairo_create (GDK_DRAWABLE (drawing->window));
  gtk_widget_add_events (drawing,
			 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
  g_signal_connect (drawing, "button-press-event",
		    G_CALLBACK (drawing_button_event), context);
  g_signal_connect (drawing, "button-release-event",
		    G_CALLBACK (drawing_button_event), context);
}
 
static GtkWidget *
get_drawing_widget (void)
{
  GtkWidget *drawing = gtk_drawing_area_new ();
  g_signal_connect (drawing, "realize",
		    G_CALLBACK (drawing_realize), NULL);
  return drawing;
}
 
/** Test application **/
 
static void
window_button_proxy (GtkWidget *widget,
		     GdkEventButton *event,
		     GtkWidget *proxy)
{
  GdkEventButton *newev = (GdkEventButton *) gdk_event_copy ((GdkEvent *) event);
  newev->window = proxy->window;
  newev->x = (gint) (newev->x / X_SCALE);
  newev->y = (gint) (newev->y / Y_SCALE);
  gdk_event_put ((GdkEvent *) newev);
}
 
int
main (int argc,
      char *argv[])
{
  HildonAnimationActor *actor;
  GtkWidget *window, *drawing;
  GdkColor pink = { .red = 0xffff, .green = 0x9999, .blue = 0x9999 };
 
  gtk_init (&argc, &argv);
 
  window = hildon_stackable_window_new ();
  gtk_widget_modify_bg (GTK_WIDGET (window), GTK_STATE_NORMAL, &pink);
  g_signal_connect (G_OBJECT (window), "delete_event",
		    G_CALLBACK (gtk_main_quit), NULL);
  gtk_widget_add_events (window,
			 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
 
  actor = HILDON_ANIMATION_ACTOR (hildon_animation_actor_new());
  gtk_widget_add_events (GTK_WIDGET (actor),
			 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
  gtk_window_resize (GTK_WINDOW (actor), X_SIZE, Y_SIZE);
  hildon_animation_actor_set_position (actor, X_POS, Y_POS);
  hildon_animation_actor_set_parent (actor, GTK_WINDOW (window));
  hildon_animation_actor_set_scale (actor, X_SCALE, Y_SCALE);
 
  drawing = get_drawing_widget ();
  gtk_container_add (GTK_CONTAINER (actor), drawing);
 
  g_signal_connect (window, "button-press-event",
		    G_CALLBACK (window_button_proxy), drawing);
  g_signal_connect (window, "button-release-event",
		    G_CALLBACK (window_button_proxy), drawing);
 
  gtk_widget_show_all (GTK_WIDGET (actor));
  gtk_widget_show_all (GTK_WIDGET (window));
 
  gtk_main ();
  return 0;
}