¸®´ª½º ±âŸ ÀÚ·á

HomePage Backward Forward Post Reply List
Delete Modify
  Á¦¸ñ   gtk °­Á #12 1998/07/10 (17:35)
À̸§ ±èÈ¿¿ø
¹øÈ£ 96
Á¶È¸ 308
º»¹®
***
*** 19-4.3. Dial WidgetÀÇ ±â¿ø
***
 Áö»óÀÇ ¸ðµç µ¿¹°µéÀÌ ÁøÈëÅÁ¿¡¼­ óÀ½À¸·Î ±â¾î³ª¿Â ¾ç¼­·ùÀÇ º¯Á¾µéÀÎ °Íó·³,
Gtk widgetµéµµ ¸ÕÀú ¸¸µé¾îÁø widgetÀÇ º¯Çü¿¡¼­ Ãâ¹ßÇÏ´Â °æÇâÀÌ ÀÖ´Ù.  ±×·¡¼­,
ÀÌ Àý(section)ÀÌ "Creating a Widget from Scratch"¶ó´Â Á¦¸ñÀ¸·Î µÇ¾î ÀÖÀ½¿¡µµ,
Dial widgetÀº ½ÇÁ¦·Î Range widgetÀÇ Äڵ忡¼­ Ãâ¹ßÇÑ´Ù.  ÀÌ´Â ¿ª½Ã Range
widget¿¡¼­ ÆÄ»ýµÈ Scale widgetµé°ú ¶È°°Àº ÀÎÅÍÆäÀ̽º¸¦, ¿ì¸®ÀÇ Dial widgetÀÌ
°¡Áú ¼ö ÀÖ´Ù¸é ¸ÚÁú °ÍÀ̶ó´Â »ý°¢¿¡¼­´Ù.  ¶ÇÇÑ ¸¸¾à ¿©·¯ºÐÀÌ ¾îÇà Á¦ÀÛÀÚÀÇ
°üÁ¡¿¡¼­ scale widgetµéÀÇ ÀÛ¿ë¿¡ ´ëÇØ Àͼ÷ÇÏÁö ¾Ê´Ù¸é, ¸ÕÀú ±×µé¿¡ ´ëÇØ ¾Ë¾Æ
º¸´Â °Íµµ ÁÁÀº »ý°¢ÀÏ °ÍÀÌ´Ù.

***
*** 19-4.4. ±âÃÊ
***
 ¿ì¸® widgetÀÇ »ó´ç ºÎºÐÀº Tictactoe widget°ú ²Ï À¯»çÇÏ°Ô º¸ÀÏ °ÍÀÌ´Ù.  ¸ÕÀú
Çì´õ ÆÄÀÏÀ» º¸ÀÚ.

 /* GTK - The GIMP Toolkit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
  * License along with this library; if not, write to the Free
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */

 #ifndef __GTK_DIAL_H__
 #define __GTK_DIAL_H__

 #include <gdk/gdk.h>
 #include <gtk/gtkadjustment.h>
 #include <gtk/gtkwidget.h>

 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */

 #define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
 #define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
 #define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())

 typedef struct _GtkDial        GtkDial;
 typedef struct _GtkDialClass   GtkDialClass;

 struct _GtkDial
 {
   GtkWidget widget;

   /* policy¸¦ ¾÷µ¥ÀÌÆ®ÇÑ´Ù(GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]). */
   guint policy : 2;

   /* ÇöÀç ´­·¯Áø ¹öÆ°, ´­¸®Áö ¾Ê¾Ò´Ù¸é 0. */
   guint8 button;

   /* ´ÙÀÌ¾ó ±¸¼º¿ä¼ÒµéÀÇ Ä¡¼ö. */
   gint radius;
   gint pointer_width;

   /* ¾÷µ¥ÀÌÆ® ŸÀ̸ÓÀÇ ID, ¾÷µ¥ÀÌÆ®°¡ ¾øÀ¸¸é 0. */
   guint32 timer;

   /* ÇöÀçÀÇ °¢µµ. */
   gfloat angle;

   /* Adjustment°¡ ÀúÀåÇÑ ÀÌÀü °ªµé·Î, ¿ì¸®°¡ ¾î¶² º¯È­¸¦ ¾Ë¾Æ³¾ ¼ö ÀÖ´Ù. */
   gfloat old_value;
   gfloat old_lower;
   gfloat old_upper;

   /* ´ÙÀ̾óÀÇ µ¥ÀÌÅ͸¦ ÀúÀåÇÏ´Â adjustment object´Ù. */
   GtkAdjustment *adjustment;
 };

 struct _GtkDialClass
 {
   GtkWidgetClass parent_class;
 };

 GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
 guint          gtk_dial_get_type               (void);
 GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
 void           gtk_dial_set_update_policy      (GtkDial      *dial,
                                                 GtkUpdateType  policy);

 void           gtk_dial_set_adjustment         (GtkDial      *dial,
                                                 GtkAdjustment *adjustment);
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

 #endif /* __GTK_DIAL_H__ */

 ÀÌ°ÍÀÌ ÀÌ widgetÀÇ ÀüºÎ°¡ ¾Æ´Ï°í µ¥ÀÌÅÍ ±¸Á¶Ã¼¿¡ ÇʵåµéÀÌ ´õ ÀÖÁö¸¸, ´Ù¸¥
°Íµé ¶ÇÇÑ ¿©±â º¸ÀÎ °Í°ú ºñ½ÁÇÏ´Ù.

 ÀÌÁ¦ Çì´õÆÄÀÏÀ» Æ÷ÇÔ(include)ÇÏ°í, ¸î °³ÀÇ »ó¼ö(constant)¸¦ ¼±¾ðÇÏ°í,
widget¿¡ ´ëÇÑ Á¤º¸¸¦ Á¦°øÇÏ°í ±×°ÍÀ» ÃʱâÈ­ÇØ ÁÖ´Â ÇÔ¼öµéÀÌ ÀÖ´Ù.

 #include <math.h>
 #include <stdio.h>
 #include <gtk/gtkmain.h>
 #include <gtk/gtksignal.h>

 #include "gtkdial.h"

 #define SCROLL_DELAY_LENGTH  300
 #define DIAL_DEFAULT_SIZE 100

 /* ¾Õ ºÎºÐÀÇ ¼±¾ðµé */

 [ °ø°£À» ¾Æ³¢±â À§ÇØ »ý·«µÊ. ]

 /* ·ÎÄà µ¥ÀÌÅÍ */

 static GtkWidgetClass *parent_class = NULL;

 guint
 gtk_dial_get_type ()
 {
   static guint dial_type = 0;

   if (!dial_type)
     {
       GtkTypeInfo dial_info =
       {
         "GtkDial",
         sizeof (GtkDial),
         sizeof (GtkDialClass),
         (GtkClassInitFunc) gtk_dial_class_init,
         (GtkObjectInitFunc) gtk_dial_init,
         (GtkArgFunc) NULL,
       };

       dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
     }

   return dial_type;
 }

 static void
 gtk_dial_class_init (GtkDialClass *class)
 {
   GtkObjectClass *object_class;
   GtkWidgetClass *widget_class;

   object_class = (GtkObjectClass*) class;
   widget_class = (GtkWidgetClass*) class;

   parent_class = gtk_type_class (gtk_widget_get_type ());

   object_class->destroy = gtk_dial_destroy;

   widget_class->realize = gtk_dial_realize;
   widget_class->expose_event = gtk_dial_expose;
   widget_class->size_request = gtk_dial_size_request;
   widget_class->size_allocate = gtk_dial_size_allocate;
   widget_class->button_press_event = gtk_dial_button_press;
   widget_class->button_release_event = gtk_dial_button_release;
   widget_class->motion_notify_event = gtk_dial_motion_notify;
 }

 static void
 gtk_dial_init (GtkDial *dial)
 {
   dial->button = 0;
   dial->policy = GTK_UPDATE_CONTINUOUS;
   dial->timer = 0;
   dial->radius = 0;
   dial->pointer_width = 0;
   dial->angle = 0.0;
   dial->old_value = 0.0;
   dial->old_lower = 0.0;
   dial->old_upper = 0.0;
   dial->adjustment = NULL;
 }

 GtkWidget*
 gtk_dial_new (GtkAdjustment *adjustment)
 {
   GtkDial *dial;

   dial = gtk_type_new (gtk_dial_get_type ());

   if (!adjustment)
     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);

   gtk_dial_set_adjustment (dial, adjustment);

   return GTK_WIDGET (dial);
 }

 static void
 gtk_dial_destroy (GtkObject *object)
 {
   GtkDial *dial;

   g_return_if_fail (object != NULL);
   g_return_if_fail (GTK_IS_DIAL (object));

   dial = GTK_DIAL (object);

   if (dial->adjustment)
     gtk_object_unref (GTK_OBJECT (dial->adjustment));

   if (GTK_OBJECT_CLASS (parent_class)->destroy)
     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
 }

 ÀÌ°Ç ÇÕ¼º widgetÀÌ ¾Æ´Ï¹Ç·Î ¿©±â¼­ÀÇ init()ÇÔ¼ö´Â Tictactoe widget¿¡
´ëÇؼ­º¸´Ù ´õ ÀûÀº ÀÛ¾÷À» ÇàÇÑ´Ù.  ±×¸®°í ÀÎÀÚ¸¦ °¡Áö°Ô µÇ¾úÀ¸¹Ç·Î new()
ÇÔ¼ö´Â ´õ ¸¹Àº ÀÛ¾÷À» ÇÑ´Ù.  ¶ÇÇÑ, ¿ì¸®°¡ Adjustment object¸¦ ÇâÇÑ Æ÷ÀÎÅ͸¦
ÀúÀåÇÒ ¶§¸¶´Ù ±×°ÍÀÇ reference count¸¦ Áõ°¡½ÃÅ´À» ±â¾ïÇ϶ó. (ÀÌ°ÍÀ» ´õÀÌ»ó
ÀÌ¿ëÇÏÁö ¾ÊÀ» ¶§´Â ¹Ý´ë·Î °¨¼Ò½ÃŲ´Ù.)  ±×·¡¼­ GTK´Â ±×°ÍÀÌ ¾ÈÀüÇÏ°Ô Æı«µÉ
¼ö ÀÖµµ·Ï Æ®·¢À» À¯ÁöÇÒ ¼ö ÀÖ´Ù.

 WidgetÀÇ ¿É¼ÇÀ» ´Ù·ê ¼ö ÀÖ´Â ¸î °³ÀÇ ÇÔ¼öµµ ÀÖ´Ù.

 GtkAdjustment*
 gtk_dial_get_adjustment (GtkDial *dial)
 {
   g_return_val_if_fail (dial != NULL, NULL);
   g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);

   return dial->adjustment;
 }

 void
 gtk_dial_set_update_policy (GtkDial      *dial,
                              GtkUpdateType  policy)
 {
   g_return_if_fail (dial != NULL);
   g_return_if_fail (GTK_IS_DIAL (dial));

   dial->policy = policy;
 }

 void
 gtk_dial_set_adjustment (GtkDial      *dial,
                           GtkAdjustment *adjustment)
 {
   g_return_if_fail (dial != NULL);
   g_return_if_fail (GTK_IS_DIAL (dial));

   if (dial->adjustment)
     {
       gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
       gtk_object_unref (GTK_OBJECT (dial->adjustment));
     }

   dial->adjustment = adjustment;
   gtk_object_ref (GTK_OBJECT (dial->adjustment));

   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
                       (GtkSignalFunc) gtk_dial_adjustment_changed,
                       (gpointer) dial);
   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
                       (GtkSignalFunc) gtk_dial_adjustment_value_changed,
                       (gpointer) dial);

   dial->old_value = adjustment->value;
   dial->old_lower = adjustment->lower;
   dial->old_upper = adjustment->upper;

   gtk_dial_update (dial);
 }

***
*** 19-4.5. gtk_dial_realize()
***
 ÀÌÁ¦ »õ·Î¿î ŸÀÔÀÇ ÇÔ¼öµéÀ» ¸¸³ªº¸ÀÚ.  ¸ÕÀú, XÀ©µµ¸¦ ¸¸µå´Â ÀÛ¾÷À» ÇØÁÖ´Â
ÇÔ¼ö´Ù.  ÇÔ¼ö gdk_window_new()·Î ÇÑ ¸¶½ºÅ©°¡ ³Ñ°ÜÁø °ÍÀ» ÁÖ¸ñÇ϶ó.  ÀÌ°ÍÀº
GdkWindowAttr ±¸Á¶Ã¼ÀÇ ¾î´À Çʵ尡 ½ÇÁ¦·Î µ¥ÀÌÅ͸¦ °¡Áú °ÍÀÎÁö ¼³Á¤ÇØ ÁÖ´Â
°ÍÀÌ´Ù.  ³ª¸ÓÁö ÇʵåµéÀº µðÆúÆ® °ªÀ¸·Î ä¿öÁö°Ô µÈ´Ù.  ¶ÇÇÑ ´«¿©°Ü ºÁµÑ ¸¸ÇÑ
°ÍÀº widgetÀÇ À̺¥Æ® ¸¶½ºÅ©°¡ ¼³Á¤µÇ´Â ¹æ¹ýÀÌ´Ù.  ¿ì¸®´Â gtk_widget_get_
events()·Î½á ÀÌ widget¿¡ ´ëÇØ »ç¿ëÀÚ°¡ ¼³Á¤ÇØ ³õÀº À̺¥Æ® ¸¶½ºÅ©¸¦ º¹±¸ÇØ
ÁÙ ¼ö ÀÖ´Ù(gtk_widget_set_events()·Î, ±×¸®°í ¿ì¸®°¡ ¿øÇÏ´Â À̺¥Æ®¸¦ ´õÇØ
ÁØ´Ù).

 À©µµ¸¦ ¸¸µé¾ú´Ù¸é, ¿ì¸®´Â ±×°ÍÀÇ ½ºÅ¸ÀÏ°ú ¹è°æÀ» ¼¼ÆÃÇÏ°í, ±×¸®°í ±×
widgetÀ» ÇâÇÑ Æ÷ÀÎÅ͸¦ GdkWindowÀÇ user data Çʵ忡 ³õ´Â´Ù.  ÀÌ ¸¶Áö¸·
´Ü°è´Â GTK°¡ ÀûÀýÇÑ widgetÀ¸·Î ÀÌ À©µµ¿¡ ´ëÇÑ À̺¥Æ®¸¦ ÀüÆÄÇÒ ¼ö ÀÖµµ·Ï
ÇÑ´Ù.

      static void
      gtk_dial_realize (GtkWidget *widget)
      {
        GtkDial *dial;
        GdkWindowAttr attributes;
        gint attributes_mask;

        g_return_if_fail (widget != NULL);
        g_return_if_fail (GTK_IS_DIAL (widget));

        GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
        dial = GTK_DIAL (widget);

        attributes.x = widget->allocation.x;
        attributes.y = widget->allocation.y;
        attributes.width = widget->allocation.width;
        attributes.height = widget->allocation.height;
        attributes.wclass = GDK_INPUT_OUTPUT;
        attributes.window_type = GDK_WINDOW_CHILD;
        attributes.event_mask = gtk_widget_get_events (widget) |
          GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
          GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
          GDK_POINTER_MOTION_HINT_MASK;
        attributes.visual = gtk_widget_get_visual (widget);
        attributes.colormap = gtk_widget_get_colormap (widget);

        attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
        widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);

        widget->style = gtk_style_attach (widget->style, widget->window);

        gdk_window_set_user_data (widget->window, widget);

        gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
      }

***
*** 19.4.6. Å©±â °áÁ¤
***
 ¾î¶² widgetÀ» Æ÷ÇÔÇÑ À©µµ°¡ óÀ½ º¸¿©Áö°Ô µÇ±â¿¡ ¾Õ¼­, ±×¸®°í À©µµÀÇ
layoutÀÌ º¯ÇßÀ» ¶§µµ ¾ðÁ¦³ª, GTK´Â ±×°ÍÀÇ ±â´ëµÈ Å©±â´ë·Î °¢ child widgetÀ»
¿ä±¸ÇÑ´Ù.  ÀÌ ¿äûÀº ÇÔ¼ö gtk_dial_size_request()¿¡ ÀÇÇØ ´Ù·ç¾îÁø´Ù.  ¿ì¸®
widgetÀº ÄÁÅ×ÀÌ³Ê widgetÀÌ ¾Æ´Ï°í ¶Ç Å©±â¿¡ ´ëÇØ ¾î¶² Á¦ÇÑ Á¶°Çµµ ¾øÀ¸¹Ç·Î,
¿ì¸®´Â ´ÜÁö ÇÕ´çÇÑ µðÆúÆ® °ªÀ» ¸®ÅÏÇØ ÁØ´Ù.

      static void
      gtk_dial_size_request (GtkWidget      *widget,
                             GtkRequisition *requisition)
      {
        requisition->width = DIAL_DEFAULT_SIZE;
        requisition->height = DIAL_DEFAULT_SIZE;
      }

 ¸ðµç widgetµéÀÌ ÀÌ»óÀûÀÎ Å©±â·Î ¿äûµÈ ÈÄ, À©µµÀÇ layoutÀÌ °è»êµÇ°í °¢
child widgetÀº ±×°ÍÀÇ ½ÇÁ¦ Å©±â·Î ÅëÁö¹Þ´Â´Ù.  º¸Åë ÀÌ°ÍÀº ÃÖ¼ÒÇÑ ¿äûµÈ
Å©±â¸¸Å­ µÈ´Ù.  ÇÏÁö¸¸ »ç¿ëÀÚ°¡ À©µµ¸¦ resizeÇÏ´Â °æ¿ìó·³, °£È¤ ¿äûµÈ
Å©±âº¸´Ù ÀÛ¾ÆÁú ¶§µµ ÀÖ´Ù.  Å©±âÀÇ ÅëÁö(notification)´Â ÇÔ¼ö gtk_dial_size_
allocate()·Î ´Ù·é´Ù.  ¾ÕÀ¸·ÎÀÇ ÀÌ¿ëÀ» À§ÇØ ÀϺΠ±¸¼º ¿ä¼Ò Á¶°¢µéÀÇ Å©±â¸¦
°è»êÇÒ »Ó ¾Æ´Ï¶ó, À̵é ÇÔ¼öµéÀº »õ·Î¿î À§Ä¡¿Í Å©±â·Î widgetÀÇ XÀ©µµ¸¦ ¿Å°Ü
ÁÖ´Â ¿ªÇÒÀ» ÇÑ´Ù´Â °ÍÀ» ±â¾ïÇÏÀÚ.

      static void
      gtk_dial_size_allocate (GtkWidget     *widget,
                              GtkAllocation *allocation)
      {
        GtkDial *dial;

        g_return_if_fail (widget != NULL);
        g_return_if_fail (GTK_IS_DIAL (widget));
        g_return_if_fail (allocation != NULL);

        widget->allocation = *allocation;
        if (GTK_WIDGET_REALIZED (widget))
          {
            dial = GTK_DIAL (widget);

            gdk_window_move_resize (widget->window,
                                    allocation->x, allocation->y,
                                    allocation->width, allocation->height);

            dial->radius = MAX(allocation->width,allocation->height) * 0.45;
            dial->pointer_width = dial->radius / 5;
          }
      }

***
*** 19-4.7. gtk_dial_expose()
***
 ¾Õ¿¡¼­ ¾ð±ÞÇßµíÀÌ, ÀÌ widgetÀÇ ¸ðµç ±×¸®±â ÀÛ¾÷Àº expose À̺¥Æ®¿¡ ´ëÇÑ
Çڵ鷯¿¡¼­ ÇàÇØÁø´Ù.  ¿©±â¼­ ÁÖ¸ñÇÒ °ÍÀº ÇÑ °¡Áö »ÓÀÌ´Ù.  WidgetÀÇ ½ºÅ¸ÀÏ¿¡
ÀúÀåµÈ »ö±òµé¿¡ µû¶ó 3Â÷¿øÀ¸·Î ±×¸²ÀÚ Áø Æ÷ÀÎÅ͸¦ ±×¸®±â À§ÇØ, gtk_draw_
polygonÀ» ÀÌ¿ëÇÑ´Ù´Â °ÍÀÌ´Ù.

 static gint
 gtk_dial_expose (GtkWidget      *widget,
                  GdkEventExpose *event)
 {
   GtkDial *dial;
   GdkPoint points[3];
   gdouble s,c;
   gdouble theta;
   gint xc, yc;
   gint tick_length;
   gint i;

   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);

   if (event->count > 0)
     return FALSE;

   dial = GTK_DIAL (widget);

   gdk_window_clear_area (widget->window,
                          0, 0,
                          widget->allocation.width,
                          widget->allocation.height);

   xc = widget->allocation.width/2;
   yc = widget->allocation.height/2;

   /* ½Ã°è ´«±ÝÀ» ±×¸°´Ù. */

   for (i=0; i<25; i++)
     {
       theta = (i*M_PI/18. - M_PI/6.);
       s = sin(theta);
       c = cos(theta);

       tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;

       gdk_draw_line (widget->window,
                      widget->style->fg_gc[widget->state],
                      xc + c*(dial->radius - tick_length),
                      yc - s*(dial->radius - tick_length),
                      xc + c*dial->radius,
                      yc - s*dial->radius);
     }

   /* Æ÷ÀÎÅ͸¦ ±×¸°´Ù. */

   s = sin(dial->angle);
   c = cos(dial->angle);

   points[0].x = xc + s*dial->pointer_width/2;
   points[0].y = yc + c*dial->pointer_width/2;
   points[1].x = xc + c*dial->radius;
   points[1].y = yc - s*dial->radius;
   points[2].x = xc - s*dial->pointer_width/2;
   points[2].y = yc - c*dial->pointer_width/2;

   gtk_draw_polygon (widget->style,
                     widget->window,
                     GTK_STATE_NORMAL,
                     GTK_SHADOW_OUT,
                     points, 3,
                     TRUE);
   return FALSE;
 }

***
*** 19-4.8. À̺¥Æ® ´Ù·ç±â
***
 WidgetÀÇ Äڵ忡¼­ ³ª¸ÓÁö ÄÚµå´Â ´Ù¾çÇÑ ÇüÅÂÀÇ À̺¥Æ®¸¦ ´Ù·é´Ù.  ¶ÇÇÑ ÀÌ°ÍÀº
¼ö¸¹Àº GTK ¾îÇÃµé »çÀÌ¿¡¼­ ±×´ÙÁö Å« Â÷ÀÌ°¡ ³ªÁö ¾Ê´Â´Ù.  À̺¥Æ®´Â Å©°Ô
µÎ°¡Áö ÇüÅ·Π³ª´­ ¼ö ÀÖ´Ù.  ¸ÕÀú »ç¿ëÀÚ°¡ widget À§¿¡¼­ ¸¶¿ì½º¸¦ Ŭ¸¯Çϰųª
Æ÷ÀÎÅ͸¦ À̵¿½ÃÅ°·Á°í µå·¡±×¸¦ ÇÒ ¼ö ÀÖ´Ù.  ±×¸®°í ¿ÜºÎÀûÀÎ »óȲ¿¡ ÀÇÇØ,
Adjustment objectÀÇ °ªÀÌ º¯ÇØ ¹ö¸± °æ¿ì°¡ ÀÖ´Ù.

 »ç¿ëÀÚ°¡ widget À§¿¡¼­ Ŭ¸¯À» Çϸé, ¿ì¸®´Â Ŭ¸¯ÀÌ ÀûÀýÈ÷ Æ÷ÀÎÅÍ ±Ùó¿¡¼­
ÀÌ·ç¾îÁ³´ÂÁö üũÇÏ°í, ¸¸¾à ±×·¸´Ù¸é widget ±¸Á¶Ã¼ÀÇ ¹öÆ° Çʵ忡 ±× ´­·ÁÁø
¹öÆ°À» ÀúÀåÇÏ°í, ±×¸®°í gtk_grab_add() È£Ãâ·Î½á ¸ðµç ¸¶¿ì½º À̺¥Æ®¸¦ Àâ¾Æ
æ´Ù.  µÚµû¸£´Â ¸¶¿ì½ºÀÇ µ¿ÀÛÀº Á¦¾î°ªµéÀÌ ´Ù½Ã °è»êµÇ¾îÁö°Ô ÇÑ´Ù(gtk_dial_
update_mouseÇÔ¼ö·Î½á).  ¼¼ÆÃµÈ policy¿¡ µû¶ó, "value_changed" À̺¥Æ®´Â ´Ù¸£°Ô
¹ß»ýÇÑ´Ù.  Áï GTK_UPDATE_CONTINUOUSÀÏ °æ¿ì¿£ ¿¬¼ÓÀûÀ¸·Î °è¼Ó ¹ß»ýÇÏ°í, GTK_
UPDATE_DELAYEDÀÏ °æ¿ì¿£ ÇÔ¼ö gtk_timeout_add()·Î ´õÇØÁö´Â ŸÀ̸Ӹ¸Å­ Áö¿¬µÇ¸ç
¹ß»ýÇϸç, GTK_UPDATE_DISCONTINUOUSÀÏ °æ¿ì¿£ ¹öÆ°ÀÌ releaseµÇ´Â ¼ø°£¿¡¸¸ ¹ß»ý
ÇÑ´Ù.

 static gint
 gtk_dial_button_press (GtkWidget      *widget,
                        GdkEventButton *event)
 {
   GtkDial *dial;
   gint dx, dy;
   double s, c;
   double d_parallel;
   double d_perpendicular;

   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);

   dial = GTK_DIAL (widget);

   /* ¹öÆ°ÀÇ ´­¸²ÀÌ Æ÷ÀÎÅÍ ¿µ¿ª ³»ºÎ¿¡¼­ ÀÌ·ç¾îÁ³³ª üũÇÑ´Ù.
    * ÀÌ°ÍÀº Æ÷ÀÎÅÍÀÇ À§Ä¡¿Í ¸¶¿ì½º°¡ ´­·¯Áø À§Ä¡ÀÇ ¼öÁ÷ ¹× ¼öÆò °Å¸®¸¦
    * °è»êÇÔÀ¸·Î½á ÀÌ·ç¾îÁø´Ù. */

   dx = event->x - widget->allocation.width / 2;
   dy = widget->allocation.height / 2 - event->y;

   s = sin(dial->angle);
   c = cos(dial->angle);

   d_parallel = s*dy + c*dx;
   d_perpendicular = fabs(s*dx - c*dy);

   if (!dial->button &&
       (d_perpendicular < dial->pointer_width/2) &&
       (d_parallel > - dial->pointer_width))
     {
       gtk_grab_add (widget);

       dial->button = event->button;

       gtk_dial_update_mouse (dial, event->x, event->y);
     }

   return FALSE;
 }

 static gint
 gtk_dial_button_release (GtkWidget      *widget,
                           GdkEventButton *event)
 {
   GtkDial *dial;

   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);

   dial = GTK_DIAL (widget);

   if (dial->button == event->button)
     {
       gtk_grab_remove (widget);

       dial->button = 0;

       if (dial->policy == GTK_UPDATE_DELAYED)
         gtk_timeout_remove (dial->timer);

       if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
           (dial->old_value != dial->adjustment->value))
         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
     }

   return FALSE;
 }

 static gint
 gtk_dial_motion_notify (GtkWidget      *widget,
                          GdkEventMotion *event)
 {
   GtkDial *dial;
   GdkModifierType mods;
   gint x, y, mask;

   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);

   dial = GTK_DIAL (widget);

   if (dial->button != 0)
     {
       x = event->x;
       y = event->y;

       if (event->is_hint || (event->window != widget->window))
         gdk_window_get_pointer (widget->window, &x, &y, &mods);

       switch (dial->button)
         {
         case 1:
           mask = GDK_BUTTON1_MASK;
           break;
         case 2:
           mask = GDK_BUTTON2_MASK;
           break;
         case 3:
           mask = GDK_BUTTON3_MASK;
           break;
         default:
           mask = 0;
           break;
         }

       if (mods & mask)
         gtk_dial_update_mouse (dial, x,y);
     }

   return FALSE;
 }

 static gint
 gtk_dial_timer (GtkDial *dial)
 {
   g_return_val_if_fail (dial != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);

   if (dial->policy == GTK_UPDATE_DELAYED)
     gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");

   return FALSE;
 }

 static void
 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
 {
   gint xc, yc;
   gfloat old_value;

   g_return_if_fail (dial != NULL);
   g_return_if_fail (GTK_IS_DIAL (dial));

   xc = GTK_WIDGET(dial)->allocation.width / 2;
   yc = GTK_WIDGET(dial)->allocation.height / 2;

   old_value = dial->adjustment->value;
   dial->angle = atan2(yc-y, x-xc);

   if (dial->angle < -M_PI/2.)
     dial->angle += 2*M_PI;

   if (dial->angle < -M_PI/6)
     dial->angle = -M_PI/6;

   if (dial->angle > 7.*M_PI/6.)
     dial->angle = 7.*M_PI/6.;

   dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
     (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);

   if (dial->adjustment->value != old_value)
     {
       if (dial->policy == GTK_UPDATE_CONTINUOUS)
         {
           gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
         }
       else
         {
           gtk_widget_draw (GTK_WIDGET(dial), NULL);

           if (dial->policy == GTK_UPDATE_DELAYED)
             {
               if (dial->timer)
                 gtk_timeout_remove (dial->timer);

               dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
                                              (GtkFunction) gtk_dial_timer,
                                              (gpointer) dial);
             }
         }
     }
 }

 ±×¸®°í ¿ÜºÎ ¿äÀο¡ ÀÇÇÑ AdjustmentÀÇ º¯È­µéÀº 'changed'¿Í 'value_changed'
½Ã±×³ÎÀ» ÅëÇØ ¿ì¸® widget¿¡ Àü´ÞµÇ´Â °ÍÀÌ´Ù.  ÀÌ·± ÇÔ¼öµéÀ» À§ÇÑ Çڵ鷯µéÀº
gtk_dial_update()¸¦ È£ÃâÇؼ­, ÀÎÀÚµéÀ» È®ÀÎÇÏ°í, »õ·Î¿î Æ÷ÀÎÅÍ °¢µµ¸¦ °è»ê
ÇÏ°í, ±×¸®°í widgetÀ» ´Ù½Ã ±×·ÁÁØ´Ù(gtk_widget_draw()¸¦ È£ÃâÇؼ­).

 static void
 gtk_dial_update (GtkDial *dial)
 {
   gfloat new_value;

   g_return_if_fail (dial != NULL);
   g_return_if_fail (GTK_IS_DIAL (dial));

   new_value = dial->adjustment->value;

   if (new_value < dial->adjustment->lower)
     new_value = dial->adjustment->lower;

   if (new_value > dial->adjustment->upper)
     new_value = dial->adjustment->upper;

   if (new_value != dial->adjustment->value)
     {
       dial->adjustment->value = new_value;
       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
     }

   dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
     (dial->adjustment->upper - dial->adjustment->lower);

   gtk_widget_draw (GTK_WIDGET(dial), NULL);
 }

 static void
 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
                               gpointer       data)
 {
   GtkDial *dial;

   g_return_if_fail (adjustment != NULL);
   g_return_if_fail (data != NULL);

   dial = GTK_DIAL (data);

   if ((dial->old_value != adjustment->value) ||
       (dial->old_lower != adjustment->lower) ||
       (dial->old_upper != adjustment->upper))
     {
       gtk_dial_update (dial);

       dial->old_value = adjustment->value;
       dial->old_lower = adjustment->lower;
       dial->old_upper = adjustment->upper;
     }
 }

 static void
 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
                                     gpointer       data)
 {
   GtkDial *dial;

   g_return_if_fail (adjustment != NULL);
   g_return_if_fail (data != NULL);

   dial = GTK_DIAL (data);

   if (dial->old_value != adjustment->value)
     {
       gtk_dial_update (dial);

       dial->old_value = adjustment->value;
     }
 }

***
*** 19-4.9. °¡´ÉÇÑ ±â´ÉÇâ»óµé
***
 ¿ì¸®°¡ ºÃµíÀÌ Dial widgetÀº ¾à 670ÁÙÀÇ Äڵ带 °¡Áö°í ÀÖ´Ù.  Æ¯È÷ ÀÌ ÄÚµå
±æÀÌÀÇ ´ëºÎºÐÀÌ Çì´õ¿Í º¸ÀÏ·¯ÆÇ(boiler plate)À̱⠶§¹®¿¡, ¿ì¸®´Â ÀÌ ±ä ÄÚµå
¿¡¼­ ²Ï ¸¹Àº °ÍÀ» ¹è¿ï ¼ö ÀÖ¾ú´Ù.  ±×·¯³ª ÀÌ widget¿¡ ´ëÇØ °¡´ÉÇÑ ¸î °¡Áö
±â´É°³¼±ÀÌ ÀÖ´Ù.

 o ÀÌ widgetÀ» ½ÇÁ¦·Î ±¸ÇöÇØ º¸¸é, Æ÷ÀÎÅÍ°¡ µå·¡±×µÇ¸é¼­ ¾à°£ÀÇ ¹ø½°Å¸²ÀÌ
  ÀÖÀ½À» ¹ß°ßÇÒ ¼ö ÀÖÀ» °ÍÀÌ´Ù.  ÀÌ°ÍÀº Æ÷ÀÎÅÍ°¡ À̵¿ÇÒ ¶§¸¶´Ù redrawµÇ±â
  ÀÌÀü¿¡ widget Àüü°¡ Áö¿öÁö±â ¶§¹®ÀÌ´Ù.  ÀÌ ¹®Á¦¸¦ ÇØ°áÇÏ´Â °¡Àå ÁÁÀº
  ¹æ¹ýÀº º¸ÀÌÁö ¾Ê´Â(offscreen) ÇȽº¸Ê¿¡ ±×·ÁÁÖ°í, ±×¸®°í´Â ÃÖÁ¾ °á°ú¹°À»
  ½ºÅ©¸° À§·Î ´Ü¹ø¿¡ º¹»çÇØ ÁÖ´Â °ÍÀÌ´Ù.  
  (ÁøÇื´ë(progress bar) widgetÀÌ ÀÌ·± ½ÄÀ¸·Î º¸¿©Á³¾ú´Ù.)
 o »ç¿ëÀÚ´Â °ªÀ» º¯È­½ÃÅ°±â À§Çؼ­ up ¹× down È­»ìǥŰ(arrow key)¸¦ ÀÌ¿ëÇÒ
  ¼ö ÀÖ¾î¾ß ÇÒ °ÍÀÌ´Ù.

 o ¿ì¸® widgetÀÌ Å©°Å³ª ÀÛÀº ÆøÀ¸·Î °ªÀ» Áõ°¨½Ãų ¼ö ÀÖ´Â ¹öÆ°À» °¡Áø´Ù¸é
  ±¦ÂúÀº ±â´ÉÀÌ µÉ °ÍÀÌ´Ù.  À̸¦ À§ÇØ ³»ÀåµÈ ¹öÆ° widgetÀ» ÀÌ¿ëÇÏ´Â °Íµµ
  °¡´ÉÇÏ°ÚÁö¸¸, ¿ì¸®´Â ¶ÇÇÑ ÀÌ ¹öÆ°µéÀÌ °è¼Ó ´­·¯Áø »óÅ¿¡¼­ auto-repeat
  µÇµµ·Ï ÇÏ°í½Í´Ù, ½ºÅ©·Ñ¹Ù¿¡ ÀÖ´Â È­»ìÇ¥µéó·³.  ÀÌ·± ½ÄÀÇ µ¿ÀÛµéÀ» °®Ãß°Ô
  ÇØÁÖ´Â ´ëºÎºÐÀÇ ÄÚµå´Â GtkRange widget¿¡¼­ ãÀ» ¼ö ÀÖ´Ù.

 o ´ÙÀ̾ó(Dial) widgetÀº ¾Õ¿¡¼­ ¾ð±ÞµÈ ¹öÆ°µéÀÇ ¹Ù´Ú¿¡ À§Ä¡ÇÑ ÇϳªÀÇ child
  widgetÀ» °¡Áø, ÄÁÅ×ÀÌ³Ê widgetÀ¸·Î ¸¸µé¾îÁú ¼ö ÀÖ´Ù.  ±×·¯¸é »ç¿ëÀÚ´Â
  ´ÙÀ̾óÀÇ ÇöÀç°ªÀ» º¸À̱â À§ÇØ ¿øÇÏ´Â ¶óº§À̳ª ¿£Æ®¸® widgetÀ» ´õÇØÁÙ ¼ö
  ÀÖ´Ù.

***
*** 19-5. ´õ ¹è¿öº¸±â
***
 WidgetÀ» ¸¸µé±â À§ÇÑ ¼ö¸¹Àº Ç׸ñµé Áß ±ØÈ÷ ÀϺθ¸ÀÌ À§¿¡¼­ ¼Ò°³µÇ¾ú´Ù.
ÀÚ½ÅÀÇ widgetÀ» ¸¸µé·Á´Â ÀÌ¿¡°Ô, °¡Àå ÁÁÀº ¼Ò½º´Â GTK ±× ÀÚüÀÏ °ÍÀÌ´Ù.
¿©·¯ºÐÀÌ ¸¸µé·Á´Â widget¿¡ ´ëÇØ ½º½º·Î ¸î°¡Áö Áú¹®À» Çغ¸ÀÚ.  ÀÌ°ÍÀº
Container widgetÀΰ¡?  ÀÌ°ÍÀº °ü·ÃµÈ À©µµ¸¦ °¡Áö°í Àִ°¡?  ÀÌ°ÍÀº À̹Ì
Á¸ÀçÇÏ´Â widgetÀÇ º¯ÇüÀΰ¡?  ±×¸®°í´Â À¯»çÇÑ widgetÀ» ã°í, º¯È­¸¦ ÁÖ±â
½ÃÀÛÇÏ´Â °ÍÀÌ´Ù.  Çà¿îÀ» ºó´Ù!


HomePage Backward Forward Post Reply List
1998 by swindler