´ÙÀ½ ÀÌÀü Â÷·Ê

20. ÀڽŸ¸ÀÇ widget ¸¸µé±â

20.1 °³¿ä

ºñ·Ï GTK ¹èÆ÷ÆÇ¿¡ Æ÷ÇԵǾî ÀÖ´Â ¼ö¸¹Àº widgetµéÀÌ ´ëºÎºÐÀÇ ±âº»ÀûÀÎ ¿ä±¸»çÇ×À» ÃæÁ·½ÃÄÑ ÁÖÁö¸¸, ¾ðÁ¨°¡ ½º½º·Î »õ·Î¿î widgetÀ» ¸¸µé¾î¾ß ÇÒ ¶§°¡ ¿Ã °ÍÀÌ´Ù. GTK°¡ widgetÀÇ »ó¼ÓÀ» ±¤¹üÀ§ÇÏ°Ô ÀÌ¿ëÇÏ°í ¶Ç ÀÌ ¸¸µé¾îÁ® ÀÖ´Â widgetµéÀÌ ¿©·¯ºÐÀÇ ¿ä±¸¿¡ ±ÙÁ¢ÇÑ °ÍµéÀ̱⠶§¹®¿¡, À¯¿ëÇÏ°í »õ·Î¿î widgetÀ» ¸¸µå´Â °Íµµ ´ÜÁö ¸î ÁÙÀÇ ÄÚµå·Î½á °¡´ÉÇÒ ¼öµµ ÀÖ´Ù. ±×·¯³ª »õ·Î¿î widgetÀ» ¸¸µå´Â ÀÛ¾÷À» ½ÃÀÛÇϱâ Àü¿¡, ¸ÕÀú ´©±º°¡ ±×°ÍÀ» ÀÌ¹Ì ¸¸µé¾î ³õÁö ¾Ê¾Ò´ÂÁö üũÇÏÀÚ. ÀÌ·¸°Ô Çؼ­ ³ë·ÂÀÇ Áߺ¹À» ¸·°í ¶Ç GTK widgetÀÇ °¹¼ö¸¦ ÃÖ¼ÒÇÑÀ¸·Î À¯ÁöÇÒ ¼ö ÀÖ´Ù. ÀÌ°ÍÀº ¼­·Î ´Ù¸¥ ¾îÇÃµé »çÀÌ¿¡¼­ ÄÚµå¿Í ÀÎÅÍÆäÀ̽º ¸ðµÎÀÇ ÅëÀϼºÀ» À¯ÁöÇÏ´Â °ÍÀÌ´Ù. ÀÌ·¸°Ô ÇÏ´Â ÇÑ°¡Áö ¹æ¹ýÀ¸·Î, ¸¸¾à ¿©·¯ºÐÀÌ ÀڽŸ¸ÀÇ widgetÀ» ¿Ï¼ºÇÏ°Ô µÇ¸é, ±×°ÍÀ» ´Ù¸¥ »ç¶÷µé ¸ðµÎ ÀÌ¿ëÇÒ ¼ö ÀÖ°Ô ¼¼°è¿¡ ³Î¸® ¾Ë¸®ÀÚ. ÀÌ·¸°Ô ÇÒ ¼ö ÀÖ´Â °¡Àå ÁÁÀº Àå¼Ò´Â ¾Æ¸¶ gtk-listÀÏ °ÍÀÌ´Ù.

¿¹Á¦µéÀÇ ¿ÏÀüÇÑ ¼Ò½º ÄÚµå´Â ´ç½ÅÀÌ ÀÌ ¹®¼­¸¦ ±¸ÇÑ °÷À̳ª ¶Ç´Â ´ÙÀ½ Àå¼Ò¿¡¼­ ±¸ÇÒ ¼ö ÀÖ´Ù.

http://www.msc.cornell.edu/~otaylor/gtk-gimp/tutorial

20.2 WidgetÀÇ ±¸Á¶

»õ·Î¿î widgetÀ» ¸¸µå´Â µ¥ À־, GTK objectµéÀÌ ¾î¶»°Ô µ¿ÀÛÇÏ´ÂÁö ÀÌÇØ ÇÏ´Â °ÍÀÌ Áß¿äÇÒ °ÍÀÌ´Ù. À̹ø ¼½¼ÇÀº ´ÜÁö ª¸·ÇÑ °³¿ä¸¸À» ¼Ò°³ÇÏ°íÀÚ ÇÑ´Ù. ÀÚ¼¼ÇÑ °ÍÀº Âü°í ¹®¼­¸¦ º¸¶ó.

GTK widgetµéÀº °´Ã¼ÁöÇâÀû ¹æ¹ýÀ» ÁöÇâÇÑ´Ù. ±×·¯³ª, ±×µéÀº Ç¥ÁØ C·Î ¾²¿©Áø´Ù. ÀÌ°ÍÀº ÇöÀç ¼öÁØÀÇ C++ ÄÄÆÄÀÏ·¯¸¦ ¾²´Â °Íº¸´Ù À̽ļº°ú ¾ÈÁ¤¼ºÀ» Å©°Ô Çâ»ó½ÃŲ´Ù. ÇÏÁö¸¸ ÀÌ°ÍÀº widget ÀÛ¼ºÀÚ°¡ ¸î¸î ¼¼ºÎÀûÀÎ °÷¿¡ ÁÖÀǸ¦ ±â¿ï¿©¾ß¸¸ ÇÏ´Â °ÍÀ» ÀǹÌÇÑ´Ù. ÇÑ Å¬·¡½ºÀÇ widgetµé(¿¹¸¦ µéÀÚ¸é ¸ðµç Button widgetµé)ÀÇ instanceµé ¸ðµÎ¿¡ °øÅëÀûÀÎ Á¤º¸´Â class structure¿¡ ÀúÀåµÇ¾î ÀÖ´Ù. ÀÌ classÀÇ ½Ã±×³ÎµéÀº ÇÔ¼ö¿¡ ´ëÇÑ Æ÷ÀÎÅÍ, Áï callback ÇÔ¼ö·Î ó¸® µÇ°í, C++¿¡¼­ÀÇ virtual ÇÔ¼öó·³ ÇϳªÀÇ º¹»çº»¸¸ÀÌ Á¸ÀçÇØ ÁØ´Ù. »ó¼ÓÀ» Áö¿øÇϱâ À§Çؼ­, class structureÀÇ Ã¹¹ø° Çʵå´Â parent class structureÀÇ copy°¡ µÇ¾î¾ß ÇÑ´Ù. GtkButtonÀ̶ó´Â class structureÀÇ ¼±¾ðÀº ÀÌ·¸°Ô µÈ´Ù.

struct _GtkButtonClass
{
        GtkContainerClass parent_class;

        void (* pressed)  (GtkButton *button);
        void (* released) (GtkButton *button);
        void (* clicked)  (GtkButton *button);
        void (* enter)    (GtkButton *button);
        void (* leave)    (GtkButton *button);
};

¹öÆ°ÀÌ ÇϳªÀÇ ÄÁÅ×À̳ʷΠ´Ù·ç¾îÁø´Ù¸é(¿¹¸¦µé¾î, resizeµÇ¾úÀ» ¶§), ±×°ÍÀÇ class structure´Â GtkContainerClass·Î ij½ºÆ®µÉ ¼ö ÀÖ°í, ¶Ç ½Ã±×³ÎµéÀ» ´Ù·ç±â À§ÇØ °ü·ÃµÈ ÇʵåµéÀÌ ¾²ÀÌ°Ô µÈ´Ù.

ÇϳªÀÇ instance basis¸¦ ±â¹ÝÀ¸·Î ÇÑ °¢°¢ÀÇ widgetµéÀ» À§ÇÑ ±¸Á¶Ã¼µµ ÀÖ´Ù. ÀÌ ±¸Á¶Ã¼´Â ¾î¶² widgetÀÇ °¢°¢ÀÇ instance¸¦ À§ÇÑ ¼­·Î ´Ù¸¥ Á¤º¸¸¦ °¡Áö°í ÀÖ´Ù. ¿ì¸®´Â ÀÌ ±¸Á¶Ã¼¸¦ object structure¶ó°í ºÎ¸¦ °ÍÀÌ´Ù. ¹öÆ° Ŭ·¡½º¸¦ ¿¹·Î µç´Ù¸é ÀÌ·¸°Ô µÈ´Ù.

struct _GtkButton
{
        GtkContainer container;

        GtkWidget *child;

        guint in_button : 1;
        guint button_down : 1;
};

Class structure¿¡¼­¿Í ¸¶Âù°¡Áö·Î ù¹ø° Çʵå´Â parent classÀÇ object structureÀÓÀ» ÁÖÀÇÇ϶ó. ±×·¡¼­ ÀÌ ±¸Á¶Ã¼´Â ÇÊ¿äÇÒ °æ¿ì parent classÀÇ object·Î ij½ºÆ®µÉ ¼öµµ ÀÖ´Â °ÍÀÌ´Ù.

20.3 Composite(ÇÕ¼º,È¥¼º) widget ¸¸µé±â

¼Ò°³

¿ì¸®°¡ ¸¸µé°íÀÚ ÇÏ´Â ¾î¶² widgetÀº ´ÜÁö ´Ù¸¥ GTK widgetµéÀÇ ÁýÇÕüÀÏ »ÓÀÏ ¼öµµ ÀÖ´Ù. ÀÌ·± widgetÀº ²À »õ·Î¿î °ÍÀ¸·Î ¸¸µé¾îÁ®¾ß ÇÒ °ÍÀº ¾Æ´ÏÁö¸¸, Àç»ç¿ë¼ºÀ» À§ÇØ »ç¿ëÀÚ ÀÎÅÍÆäÀ̽ºÀûÀÎ ¿ä¼ÒµéÀ» ÆÐŰ¡ÇÏ´Â µ¥ ÀÖ¾î Æí¸®ÇÑ ¹æ½ÄÀ» Á¦°øÇÑ´Ù. Ç¥ÁØ GTK ¹èÆ÷ÆÇ¿¡ ÀÖ´Â FileSelection°ú ColorSelection widgetÀÌ ¿¹°¡ µÉ °ÍÀÌ´Ù.

¿ì¸®°¡ ¿©±â¼­ ¸¸µé·Á´Â ¿¹Á¦´Â Tictactoe widgetÀ¸·Î, Åä±Û¹öÆ°ÀÇ 3x3 ¹è¿­ ¿¡¼­ ¾î´À ÇÑ Çà ¶Ç´Â ¿­ ¶Ç´Â ´ë°¢¼ººÐ ¸ðµÎ°¡ ´­·¯Áö°Ô µÇ¸é ½Ã±×³ÎÀ» ³»º¸³½ ´Ù.

Parent class¸¦ °í¸£±â

ÀüÇüÀûÀ¸·Î composite widgetÀÇ parent class´Â ±× composite widgetÀÇ ¸ðµç ¸â¹öµéÀ» °¡Áö°í ÀÖ´Â ÄÁÅ×ÀÌ³Ê Å¬·¡½ºÀÌ´Ù. ¿¹¸¦µé¾î, FileSelection widgetÀÇ parent class´Â Dialog Ŭ·¡½ºÀÌ´Ù. ¿ì¸® ¹öÆ°µéÀº table ¾È¿¡ ´Ã¾î¼­ ÀÖÀ» °Í À̹ǷÎ, parent class·Î GtkTable Ŭ·¡½º°¡ µÇ´Â °ÍÀÌ ÀÚ¿¬½º·´´Ù. ºÒÇàÈ÷µµ, ÀÌ°ÍÀº µ¿ÀÛÇÏÁö ¾Ê´Â´Ù. ÇÑ widgetÀ» ¸¸µå´Â °ÍÀº µÎ ÇÔ¼ö¿¡ ÀÇÇÑ °ÍÀ¸·Î ³ª´¶´Ù. WIDGETNAME_new() ÇÔ¼ö¸¦ »ç¿ëÀÚ°¡ ºÎ¸£°í, ±×¸®°í WIDGETNAME_init()ÇÔ¼ö´Â _new()ÇÔ¼öÀÇ ÀÎÀÚ·Î ÁÖ¾îÁø widgetµé¿¡ ´ëÇÑ ±âº»ÀûÀÎ ÃʱâÈ­ ÀÛ¾÷À» ÇÑ´Ù. Descendent widgetµéÀº ´ÜÁö ±×µéÀÇ parent widgetÀÇ _init()ÇÔ¼ö¸¸ ºÎ¸£°Ô µÈ´Ù. ±×·¯³ª ÀÌ ÀÛ¾÷ ºÐÇÒÀº Å×ÀÌºí¿¡ ´ëÇؼ­´Â Àß µ¿ÀÛÇÏÁö ¾Ê´Â´Ù. Å×À̺íÀÇ °æ¿ì¿¡´Â ¸¸µé¾îÁú ¶§ Çà°ú ¿­ÀÇ °¹¼ö¸¦ ¾Ë Çʿ伺ÀÌ Àֱ⠶§¹®ÀÌ´Ù. ±×·¸Áö ¾ÊÀ¸¸é ¿ì¸®´Â ÀÌ Tictactoe widget¿¡ ÀÖ´Â gtk_table_new()ÀÇ ´ëºÎºÐÀÇ ±â´ÉµéÀ» Áߺ¹Çؼ­ ÀÌ¿ëÇÏ°Ô µÉ °ÍÀÌ´Ù. ±×·¯¹Ç·Î, ¿ì¸®´Â ´ë½Å ±×°ÍÀ» GtkVBox ·ÎºÎÅÍ À̲ø¾î³»¾î, ¿ì¸®ÀÇ Å×À̺íÀ» VBox ³»ºÎ·Î ºÙ¿©ÁÙ °ÍÀÌ´Ù.

Çì´õ ÆÄÀÏ

°¢°¢ÀÇ widget class´Â public ÇÔ¼ö¿Í ±¸Á¶Ã¼ ¹× °´Ã¼ÀÇ ¼±¾ðµéÀÌ ÀÖ´Â Çì´õ ÆÄÀÏÀ» °¡Áö°í ÀÖ´Ù. ¿©±â¼­ °£´ÜÈ÷ »ìÆ캸ÀÚ. Áߺ¹ Á¤ÀǸ¦ ÇÇÇϱâ À§Çؼ­, ¿ì¸®´Â Çì´õÆÄÀÏ Àüü¸¦ ÀÌ·¸°Ô µÑ·¯½Ñ´Ù.

#ifndef __TICTACTOE_H__
#define __TICTACTOE_H__
.
.
.
#endif /* __TICTACTOE_H__ */

±×¸®°í C++ ÇÁ·Î±×·¥À» °í·ÁÇؼ­ À̰͵µ Ãß°¡ÇÑ´Ù.

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

ÇÔ¼ö¿Í ±¸Á¶Ã¼µé¿¡ ´ëÇØ, ¿ì¸®´Â Çì´õÆÄÀÏ ³»¿¡¼­ ¼¼°¡Áö Ç¥ÁØÀûÀÎ ¸ÅÅ©·Î¸¦ ¼±¾ðÇÑ´Ù. Áï TICTACTOE(obj), TICTACTOE_CLASS(klass), IS_TICTACTOE(obj)ÀÌ´Ù. À̵éÀº ¾î¶² ÇÑ Æ÷ÀÎÅ͸¦ object ȤÀº class structure¿¡ ´ëÇÑ Æ÷ÀÎÅͷΠij½ºÆ® ÇÏ°í, ¾î¶² object°¡ Tictactoe widgetÀÎÁö¸¦ üũÇÏ´Â ¿ªÇÒÀ» ÇÑ´Ù.

ÀÌ°ÍÀÌ ÃÖÁ¾ÀûÀÎ Çì´õÆÄÀÏÀÌ´Ù.

/* tictactoe.h */

#ifndef __TICTACTOE_H__
#define __TICTACTOE_H__

#include <gdk/gdk.h>
#include <gtk/gtkvbox.h>

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

#define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
#define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
#define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())

typedef struct _Tictactoe       Tictactoe;
typedef struct _TictactoeClass  TictactoeClass;

struct _Tictactoe
{
        GtkVBox vbox;

        GtkWidget *buttons[3][3];
};

struct _TictactoeClass
{
        GtkVBoxClass parent_class;

        void (* tictactoe) (Tictactoe *ttt);
};

guint          tictactoe_get_type        (void);
GtkWidget*     tictactoe_new             (void);
void           tictactoe_clear           (Tictactoe *ttt);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __TICTACTOE_H__ */

_get_type() ÇÔ¼ö

ÀÌÁ¦ ¿ì¸®ÀÇ widgetÀ» °è¼Ó ´Ùµë¾î º¸ÀÚ. ¸ðµç widgetµé¿¡ ´ëÇÑ ÇÙ½É(core) ÇÔ¼ö´Â WIDGETNAME_get_type()ÀÌ´Ù. ÀÌ ÇÔ¼ö´Â óÀ½ È£ÃâµÇ¾úÀ» ¶§, GTK¿¡°Ô widget class¿¡ ´ëÇØ ¾Ë·ÁÁØ´Ù. ±×¸®°í widget class¸¦ ¸íÈ®È÷ ½Äº°ÇÏ´Â ID¸¦ ÃëÇÑ´Ù. °è¼Ó È£ÃâÇÏ¸é ¹Ù·Î ±× ID¸¦ ¸®ÅÏÇÑ´Ù.

guint
tictactoe_get_type ()
{
  static guint ttt_type = 0;

  if (!ttt_type)
    {
      GtkTypeInfo ttt_info =
      {
        "Tictactoe",
        sizeof (Tictactoe),
        sizeof (TictactoeClass),
        (GtkClassInitFunc) tictactoe_class_init,
        (GtkObjectInitFunc) tictactoe_init,
        (GtkArgSetFunc) NULL,
        (GtkArgGetFunc) NULL
      };

      ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
    }

  return ttt_type;
}

±¸Á¶Ã¼ GtkTypeInfo´Â ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾú´Ù.

struct _GtkTypeInfo
{
  gchar *type_name;
  guint object_size;
  guint class_size;
  GtkClassInitFunc class_init_func;
  GtkObjectInitFunc object_init_func;
  GtkArgSetFunc arg_set_func;
  GtkArgGetFunc arg_get_func;
};

ÀÌ ±¸Á¶Ã¼ÀÇ °¢ Çʵå´Â ¿ª½Ã º¸ÀÌ´Â ±×´ë·Î´Ù. ¿ì¸®´Â ¿©±â¼­ arg_set_func¿Í arg_get_func ÇÊµå ¸¦ ¹«½ÃÇÒ °ÍÀÌ´Ù. ÀÌ°ÍÀº ÀÎÅÍÇÁ¸®ÅÍ ¾ð¾î¿¡¼­ ºñ·ÔµÇ¾î widget ¿É¼ÇµéÀ» Æí¸®ÇÏ°Ô ¼¼ÆÃÇÒ ¼ö ÀÖµµ·Ï ÇÏ´Â Áß¿äÇÑ ¿ªÇÒÀ» ÇÒ ¼ö ÀÖÁö¸¸, ¾ÆÁ÷Àº ´ë°³ °®Ãß¾îÁöÁö ¾Ê¾Ò´Ù. ÀÏ´Ü GTK°¡ ÀÌ ±¸Á¶Ã¼ÀÇ Á¦´ë·Î µÈ º¹»çº»À» °¡Áö°Ô µÇ¸é, ±×°ÍÀº Ưº°ÇÑ widget typeÀÇ object¸¦ ¸¸µå´Â ¹æ¹ýÀ» ¾Ë°Ô µÈ´Ù.

_class_init() ÇÔ¼ö

WIDGETNAME_class_init() ÇÔ¼ö´Â widgetÀÇ class structure¿¡ ÀÖ´Â ÇʵåµéÀ» ÃʱâÈ­ÇÏ°í, ±× Ŭ·¡½º¿¡ ´ëÇÑ ½Ã±×³Îµéµµ ¼Â¾÷ÇØ ÁØ´Ù. ¿ì¸®ÀÇ Tictactoe widget¿¡ ´ëÇؼ­ ÀÌ°ÍÀº ÀÌ·¸°Ô º¸¿©Áø´Ù.


enum {
  TICTACTOE_SIGNAL,
  LAST_SIGNAL
};

static gint tictactoe_signals[LAST_SIGNAL] = { 0 };

static void
tictactoe_class_init (TictactoeClass *class)
{
  GtkObjectClass *object_class;

  object_class = (GtkObjectClass*) class;
  
  tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
                                         GTK_RUN_FIRST,
                                         object_class->type,
                                         GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
                                         gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);


  gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);

  class->tictactoe = NULL;
}

¿ì¸® widgetÀÌ °¡Áø À¯ÀÏÇÑ ½Ã±×³ÎÀº ``tictactoe'' ½Ã±×³Î·Î, ÀÌ°ÍÀº ÇÑ Çà, ¿­, ȤÀº ´ë°¢ ¼ººÐÀÌ ¿ÏÀüÈ÷ ä¿öÁö¸é ¿ä±¸µÈ´Ù. ¸ðµç ÇÕ¼º widgetµéÀÌ ½Ã±×³Î À» ÇÊ¿ä·Î ÇÏ´Â °ÍÀº ¾Æ´Ï¸ç, µû¶ó¼­ ¿©·¯ºÐÀÌ ÀÌ ºÎºÐÀ» óÀ½ Àаí ÀÖ´Â »óÅ ¶ó¸é ´ÙÀ½ ¼½¼Ç(section)À¸·Î ³Ñ¾î°¡µµ ÁÁ´Ù. ÀÌ ºÎºÐÀº ´Ù¼Ò º¹ÀâÇÒ °ÍÀ̱⠶§¹®ÀÌ´Ù.

ÀÌ ÇÔ¼ö¸¦ º¸ÀÚ.

gint   gtk_signal_new (gchar               *name,
                                         GtkSignalRunType     run_type,
                                         gint                 object_type,
                                         gint                 function_offset,
                                         GtkSignalMarshaller  marshaller,
                                         GtkArgType           return_val,
                                         gint                 nparams,
                                         ...);

»õ·Î¿î ½Ã±×³ÎÀ» ¸¸µç´Ù. ¿©±â¿¡ ¾²ÀÎ ÀÎÀÚµéÀ» »ìÆ캸ÀÚ.

ŸÀÔÀ» ¼³Á¤Çϱâ À§ÇØ, GtkTypeÀ̶ó´Â enumerationÀÌ ¾²ÀδÙ.

typedef enum
{
  GTK_TYPE_INVALID,
  GTK_TYPE_NONE,
  GTK_TYPE_CHAR,
  GTK_TYPE_BOOL,
  GTK_TYPE_INT,
  GTK_TYPE_UINT,
  GTK_TYPE_LONG,
  GTK_TYPE_ULONG,
  GTK_TYPE_FLOAT,
  GTK_TYPE_DOUBLE,
  GTK_TYPE_STRING,
  GTK_TYPE_ENUM,
  GTK_TYPE_FLAGS,
  GTK_TYPE_BOXED,
  GTK_TYPE_FOREIGN,
  GTK_TYPE_CALLBACK,
  GTK_TYPE_ARGS,

  GTK_TYPE_POINTER,

  /* it'd be great if the next two could be removed eventually */
  GTK_TYPE_SIGNAL,
  GTK_TYPE_C_CALLBACK,

  GTK_TYPE_OBJECT

} GtkFundamentalType;

gtk_signal_new()´Â ½Ã±×³Î¿¡ ´ëÇØ °íÀ¯ÇÑ Á¤¼ö ½Äº°ÀÚ¸¦ ¸®ÅÏÇÑ´Ù. ¿ì¸®´Â À̵éÀ» tictactoe_signals ¹è¿­¿¡ ÀúÀåÇÏ°í, enumeration·Î ÀÌ¿ëÇؼ­ À妽º¸¦ ÁØ´Ù. (°ü½ÀÀûÀ¸·Î enumerationÀÇ ¿ø¼ÒµéÀº ´ë¹®ÀÚ·Î ½Ã±×³ÎÀÇ À̸§À» ³ªÅ¸³» Áö¸¸, ¿©±â¼­ TICTACTOE() ¸ÅÅ©·Î¿Í Ãæµ¹ÇÒ ¼ö Àֱ⠶§¹®¿¡, ¿ì¸®´Â À̵éÀ» TICTACTOE_SIGNALÀ̶ó°í ºÎ¸¥´Ù.)

½Ã±×³ÎÀ» ¸¸µé¾ú´Ù¸é, ÀÌÁ¦ GTK°¡ ÀÌ ½Ã±×³ÎµéÀ» Tictactoe Ŭ·¡½º¿¡ ¿¬°á½ÃÅ° µµ·Ï ÇØ¾ß ÇÑ´Ù. ÀÌ ÀÛ¾÷Àº gtk_object_class_add_signals()·Î ÇØÁØ´Ù. ±×¸®°í ¾Æ¹«·± µðÆúÆ® µ¿ÀÛÀÌ ¾ø´Ù´Â °É ³ªÅ¸³»±â À§ÇØ, ``tictactoe'' ½Ã±×³ÎÀ» À§ÇÑ µðÆúÆ® Çڵ鷯¸¦ °¡¸®Å°°í ÀÖ´Â Æ÷ÀÎÅ͸¦ NULL·Î ¼¼ÆÃÇÑ´Ù.

_init() ÇÔ¼ö

°¢ widget Ŭ·¡½º´Â ¶ÇÇÑ object structure¸¦ ÃʱâÈ­ÇØ ÁÙ ÇÔ¼ö¸¦ ÇÊ¿ä·Î ÇÑ´Ù. º¸Åë, ÀÌ ÇÔ¼ö´Â ±¸Á¶Ã¼ÀÇ ÇʵåµéÀ» µðÆúÆ® °ªÀ¸·Î ¼¼ÆÃÇÏ´Â ³ª¸§´ë·Î Á¦ÇÑµÈ ¿ªÇÒÀ» °¡Áö°í ÀÖ´Ù. ±×·¯³ª ÇÕ¼º widgetµéÀÇ °æ¿ì, ÀÌ ÇÔ¼öµéÀÌ ÀûÇÕÇÑ ¶Ç´Ù¸¥ widgetµéÀ» ¸¸µé¾î Áֱ⵵ ÇÑ´Ù.

static void
tictactoe_init (Tictactoe *ttt)
{
        GtkWidget *table;
        gint i,j;

        table = gtk_table_new (3, 3, TRUE);
        gtk_container_add (GTK_CONTAINER(ttt), table);
        gtk_widget_show (table);

        for (i=0;i<3; i++)
                for (j=0;j<3; j++)
                        {
                                ttt->buttons[i][j] = gtk_toggle_button_new ();
                                gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
                                                                                 i, i+1, j, j+1);
                                gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
                                                                        GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
                                gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
                                gtk_widget_show (ttt->buttons[i][j]);
                        }
}

±×¸®°í ³ª¸ÓÁöµé...

¸ðµç widgetµé(GtkBinó·³ ´Þ¸® ¼³¸íµÉ ¼ö ¾ø´Â base widgetµéÀº Á¦¿Ü)ÀÌ °¡Áö°í ÀÖ¾î¾ß ÇÒ ÇÔ¼ö°¡ Çϳª ´õ ÀÖ´Ù. ¹Ù·Î ±× ÇØ´çÇϴ ŸÀÔÀÇ object¸¦ ¸¸µé±â À§ÇÑ ÇÔ¼ö´Ù. ÀÌ°ÍÀº °ü·Ê»ó WIDGETNAME_new()°¡ µÈ´Ù. Tictactoe widget¿¡´Â ÇØ´çÇÏÁö ¾ÊÁö¸¸, ÀϺΠwidgetµéÀº ÀÌ ÇÔ¼öµéÀÌ ÀÎÀÚ¸¦ °¡Áö°í, ±×¸®°í ±× ÀÎÀÚ¸¦ Âü°íÇؼ­ ¾î¶² ¼Â¾÷À» ÇàÇϱ⵵ ÇÑ´Ù. ´Ù¸¥ µÎ ÇÔ¼ö´Â ¿ì¸®ÀÇ Tictactoe widget¿¡ ´ëÇÑ Æ¯º°ÇÑ °ÍµéÀÌ´Ù.

tictactoe_clear()´Â widget¿¡ ÀÖ´Â ¸ðµç ¹öÆ°À» up »óÅ·Π¸®¼ÂÇØ ÁØ´Ù. ¹öÆ° Åä±ÛÀ» À§ÇÑ ¿ì¸® ½Ã±×³Î Çڵ鷯°¡ ºÒÇÊ¿äÇÏ°Ô Á¶ÁصǴ °ÍÀ» ¸·¾ÆÁÖ±â À§ÇØ gtk_signal_handler_block_by_data()¸¦ ÀÌ¿ëÇÏ´Â °ÍÀ» ¸í½ÉÇÏÀÚ.

tictactoe_toggle()Àº »ç¿ëÀÚ°¡ ¾î¶² ¹öÆ°À» Ŭ¸¯ÇßÀ» ¶§ ¿äûµÇ´Â ½Ã±×³Î Çڵ鷯´Ù. ÀÌ°ÍÀº Åä±ÛµÈ ¹öÆ°À» Æ÷ÇÔÇØ ¾î¶² ¸Å·ÂÀûÀÎ ÄÞºñ(combination)°¡ ÀÌ·ç¾îÁö´ÂÁö üũÇÏ°í, ¸¸¾à ±×·¸´Ù¸é "tictactoe" ½Ã±×³ÎÀ» ¹ß»ý½ÃŲ´Ù.

  
GtkWidget*
tictactoe_new ()
{
  return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
}

void           
tictactoe_clear (Tictactoe *ttt)
{
  int i,j;

  for (i=0;i<3;i++)
    for (j=0;j<3;j++)
      {
        gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
        gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
                                     FALSE);
        gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
      }
}

static void
tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
{
  int i,k;

  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
                             { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
                             { 0, 1, 2 }, { 0, 1, 2 } };
  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
                             { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
                             { 0, 1, 2 }, { 2, 1, 0 } };

  int success, found;

  for (k=0; k<8; k++)
    {
      success = TRUE;
      found = FALSE;

      for (i=0;i<3;i++)
        {
          success = success && 
            GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
          found = found ||
            ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
        }
      
      if (success && found)
        {
          gtk_signal_emit (GTK_OBJECT (ttt), 
                           tictactoe_signals[TICTACTOE_SIGNAL]);
          break;
        }
    }
}

±×¸®°í ¿ì¸®ÀÇ Tictactoe widgetÀ» ÀÌ¿ëÇÑ ¿¹Á¦ ÇÁ·Î±×·¥Àº ÃÖÁ¾ÀûÀ¸·Î ÀÌ°ÍÀÌ´Ù.

#include <gtk/gtk.h>
#include "tictactoe.h"

/* ¾î¶² Çà, ¿­, ȤÀº ´ë°¢¼ººÐÀÌ ´Ù Â÷°Ô µÇ¸é ¿äûµÈ´Ù. */
void
win (GtkWidget *widget, gpointer data)
{
        g_print ("Yay!\n");
        tictactoe_clear (TICTACTOE (widget));
}

int
main (int argc, char *argv[])
{
        GtkWidget *window;
        GtkWidget *ttt;

        gtk_init (&argc, &argv);

        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

        gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");

        gtk_signal_connect (GTK_OBJECT (window), "destroy",
                                                GTK_SIGNAL_FUNC (gtk_exit), NULL);

        gtk_container_border_width (GTK_CONTAINER (window), 10);

        /* Tictactoe widgetÀ» Çϳª ¸¸µç´Ù. */
        ttt = tictactoe_new ();
        gtk_container_add (GTK_CONTAINER (window), ttt);
        gtk_widget_show (ttt);

        /* ±×¸®°í ÀÌ°ÍÀÇ "tictactoe" ½Ã±×³Î¿¡ °áÇÕ½ÃÄÑ µÐ´Ù. */
        gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
                                                GTK_SIGNAL_FUNC (win), NULL);

        gtk_widget_show (window);

        gtk_main ();

        return 0;
}

20.4 ¹«¿¡¼­(from scratch) widget ¸¸µé±â

¼Ò°³

À̹ø ¼½¼Ç¿¡¼­´Â widgetµéÀÌ ±× ÀڽŵéÀ» ¾î¶»°Ô ½ºÅ©¸°¿¡ º¸ÀÌ°Ô ÇÏ´ÂÁö, ±×¸®°í À̺¥Æ®¿Í »óÈ£ÀÛ¿ë ÇÏ´ÂÁö¸¦ ´õ °øºÎÇÒ °ÍÀÌ´Ù. ÀÌ¿¡ ´ëÇÑ ¿¹Á¦·Î ¿ì¸®´Â Æ÷ÀÎÅÍ°¡ ´Þ·ÁÀÖ´Â ¾Æ³¯·Î±× ´ÙÀ̾ó(analog dial) widgetÀ» ¸¸µé¾î¼­, »ç¿ëÀÚ°¡ ±×°É ²ø¾î¼­ °ªÀ» ¼¼ÆÃÇϵµ·Ï ÇÒ °ÍÀÌ´Ù.

½ºÅ©¸°¿¡ widgetÀ» º¸À̱â

½ºÅ©¸°¿¡ º¸¿©ÁÖ±â À§Çؼ­ ¸î°¡Áö ´Ü°è°¡ ÀÖ´Ù. WidgetÀÌ WIDGETNAME_new() ·Î½á ¸¸µé¾îÁö°í ³ª¼­, ¸î°³ÀÇ ÇÔ¼ö°¡ ´õ ÇÊ¿äÇÏ´Ù.

»ó´çÈ÷ À¯»çÇÑ ¸¶Áö¸·ÀÇ µÎ ÇÔ¼ö¿¡ ÁÖÀÇÇØ¾ß ÇÒ °ÍÀÌ´Ù. »ç½Ç ¸¹Àº ŸÀÔÀÇ widgetµéÀº µÎ °æ¿ìÀÇ Â÷ÀÌÁ¡À» ±×´ÙÁö ±¸º°ÇÏÁö ¾Ê´Â´Ù. Widget Ŭ·¡½ºÀÇ µðÆúÆ® draw() ÇÔ¼ö´Â ´ÜÁö ´Ù½Ã ±×·ÁÁø ¿µ¿ª¿¡ ´ëÇØ Á¾ÇÕÀûÀÎ expose À̺¥Æ®¸¦ ¹ß»ý½Ãų »ÓÀÌ´Ù. ±×·¯³ª ¾î¶² ŸÀÔÀÇ widgetÀº µÎ ÇÔ¼ö¸¦ ±¸º°ÇÔÀ¸·Î½á ÀÛ¾÷À» ÃÖ¼ÒÈ­Çϱ⵵ ÇÑ´Ù. ¿¹¸¦µé¾î ¿©·¯ °³ÀÇ XÀ©µµ¸¦ °¡Áø widgetÀº ¿µÇâÀ» ¹ÞÀº (affected) À©µµ¸¸À» ´Ù½Ã ±×·ÁÁÙ ¼ö Àִµ¥, ÀÌ°ÍÀº ´Ü¼øÈ÷ draw()À» È£ÃâÇÏ´Â °ÍÀ¸·Î´Â ºÒ°¡´ÉÇÑ ÀÏÀÌ´Ù.

ÄÁÅ×ÀÌ³Ê widgetµéÀº ¼­·ÎÀÇ Â÷ÀÌÁ¡¿¡ ´ëÇØ ÀÚ±â ÀÚ½ÅÀº »ó°üÇÏÁö ¾ÊÁö¸¸, ±×µéÀÇ child widgetµéÀº ¼­·Î¸¦ ºÐ¸íÈ÷ ±¸º°ÇØ¾ß ÇϹǷÎ, °£´ÜÈ÷ µðÆúÆ® draw() ÇÔ¼ö¸¦ °¡Áú ¼ö ¾ø´Ù. ÇÏÁö¸¸, µÎ ÇÔ¼ö »çÀÌ¿¡¼­ ±×¸®´Â Äڵ带 Áߺ¹ÇÏ´Â °ÍÀº ³¶ºñ´Ù. ÀÌ·± widgetµéÀº °ü½À»ó WIDGETNAME_paint() ¶ó°í ºÒ¸®´Â ÇÔ¼ö¸¦ °¡Áø´Ù. ÀÌ ÇÔ¼öµéÀº widgetÀ» ½ÇÁ¦·Î ±×¸®´Â ¿ªÇÒÀ» Çϸç, draw() ¹× expose() ÇÔ¼ö¿¡ ÀÇÇØ ºÒ¸®¾îÁö°Ô µÈ´Ù.

¿ì¸®ÀÇ ¿¹Á¦¿¡¼­´Â dial widgetÀÌ ÄÁÅ×À̳ʰ¡ ¾Æ´Ï¸ç ¿ÀÁ÷ ÇϳªÀÇ À©µµ¸¸ °¡Áö ±â ¶§¹®¿¡, ¿ì¸®´Â °£´ÜÇÏ°Ô ¹®Á¦¸¦ ÇØ°áÇÒ ¼ö ÀÖ´Ù. Áï µðÆúÆ® draw()¸¦ ÀÌ¿ë ÇÏ°í ¶Ç expose() ÇÔ¼ö¸¸À» °®Ãá´Ù.

Dial WidgetÀÇ ±â¿ø

Áö»óÀÇ ¸ðµç µ¿¹°µéÀÌ ÁøÈëÅÁ¿¡¼­ óÀ½À¸·Î ±â¾î³ª¿Â ¾ç¼­·ùÀÇ º¯Á¾µéÀÎ °Íó·³, Gtk widgetµéµµ ¸ÕÀú ¸¸µé¾îÁø widgetÀÇ º¯Çü¿¡¼­ Ãâ¹ßÇÏ´Â °æÇâÀÌ ÀÖ´Ù. ±×·¡¼­, ÀÌ Àý(section)ÀÌ "Creating a Widget from Scratch"¶ó´Â Á¦¸ñÀ¸·Î µÇ¾î ÀÖÀ½¿¡µµ, Dial widgetÀº ½ÇÁ¦·Î Range widgetÀÇ Äڵ忡¼­ Ãâ¹ßÇÑ´Ù. ÀÌ´Â ¿ª½Ã Range widget¿¡¼­ ÆÄ»ýµÈ Scale widgetµé°ú ¶È°°Àº ÀÎÅÍÆäÀ̽º¸¦, ¿ì¸®ÀÇ Dial widgetÀÌ °¡Áú ¼ö ÀÖ´Ù¸é ¸ÚÁú °ÍÀ̶ó´Â »ý°¢¿¡¼­´Ù. ¶ÇÇÑ ¸¸¾à ¿©·¯ºÐÀÌ ¾îÇà Á¦ÀÛÀÚÀÇ °üÁ¡¿¡¼­ scale widgetµéÀÇ ÀÛ¿ë¿¡ ´ëÇØ Àͼ÷ÇÏÁö ¾Ê´Ù¸é, ¸ÕÀú ±×µé¿¡ ´ëÇØ ¾Ë¾Æ º¸´Â °Íµµ ÁÁÀº »ý°¢ÀÏ °ÍÀÌ´Ù.

±âÃÊ

¿ì¸® 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);
}

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);
}

Å©±â °áÁ¤

¾î¶² 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;
                }
}

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;
}

À̺¥Æ® ´Ù·ç±â

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;
    }
}

°¡´ÉÇÑ ±â´ÉÇâ»óµé

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

20.5 ´õ ¹è¿öº¸±â

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


´ÙÀ½ ÀÌÀü Â÷·Ê