knightL

cw

Nov 27th, 2010
289
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.25 KB | None | 0 0
  1. ----/coursework.h/----
  2. #ifndef COURSEWORK_H
  3. #define COURSEWORK_H
  4.  
  5. #include <gtk/gtk.h>
  6.  
  7. #define TREEOFFSETX 10
  8. #define TREEOFFSETY 70
  9.  
  10. #define LINEOFFSETX 20
  11. #define LINEOFFSETY 300
  12. #define RISE 30
  13.  
  14. #define VCOUNT 10
  15. #define HCOUNT 20
  16.  
  17. #define CENTERTEXTOFFSETY 10
  18. #define SHADOWOFFSET -1
  19.  
  20. #define LEGENDOFFSETX 5
  21. #define LEGENDY 60
  22. #define LEGENDINNEROFFSETX 10
  23. #define LEGENDINNEROFFSETY 10
  24. #define LEGENDWIDTH 270
  25. #define LEGENDHEADERHEIGHT 20
  26. #define LEGENDHEADER "Легенда"
  27.  
  28. #define RAD 14
  29. #define GAP 5
  30.  
  31. #define N 20
  32. #define MOD 100
  33. #define STATECNT 6
  34.  
  35. #define MOVEDELAY 50
  36. #define SORTDELAY 500
  37.  
  38. #define WIDTH 800
  39. #define HEIGHT 360
  40.  
  41. typedef struct elpath elpath;
  42. typedef struct element element;
  43. typedef enum elstate elstate;
  44.  
  45.  
  46. struct elpath
  47. {
  48.     GList *linecurve,*treecurve;
  49.     int elnum;
  50. };
  51.  
  52. struct element
  53. {
  54.     GdkPoint linecoord,treecoord;
  55.     int value;
  56.     int state;
  57. };
  58. enum elstate
  59. {
  60.     normal=0,
  61.     inplace=1,
  62.     inheap=2,
  63.     active=3,
  64.     activeinplace=4,
  65.     activeinheap=5
  66. };
  67.  
  68. void init_gc();
  69. void init_sort();
  70. void init_legend();
  71. void draw_element(GtkWidget *w, element *e);
  72. void draw_text_in_center(gchar * text, GtkWidget *w, GdkDrawable *d, GdkGC *gc, gint xc, gint yc);
  73. void draw_text_in_center_y(gchar * text, GtkWidget *w, GdkDrawable *d, GdkGC *gc, gint x, gint yc);
  74. void draw_legend();
  75. void startmoving(elpath *p1,elpath *p2);
  76. void swap(int idx1,int idx2);
  77. void displayphasetxt();
  78. void genline(GdkPoint s, GdkPoint t,int cnt,GList ** l);
  79. GdkPoint getlinecoord(int n);
  80. GdkPoint gettreecoord(int n,int maxh);
  81. elpath makepath(gint idx,GdkPoint listb,GdkPoint liste, gint dy, gint listc1, gint listc2,gint listc3,GdkPoint treep1,GdkPoint treep2, gint treec);
  82. gboolean move(elpath* p);
  83. gboolean heapsort(gpointer data);
  84. gboolean expose_event(GtkWidget *w,GdkEvent *e, gpointer data);
  85. gboolean delete_event(GtkWidget *w,GdkEvent *e, gpointer data);
  86.  
  87. #endif
  88. ----/coursework.c/----
  89. #include <stdio.h>
  90. #include <stdlib.h>
  91. #include <time.h>
  92. #include <gtk/gtk.h>
  93. #include "coursework.h"
  94.  
  95. GtkWidget *window;
  96. GdkPixmap *legend;
  97. GdkGC *gcbg[STATECNT],*gcfg[STATECNT];
  98. element el[N];
  99. element *arr;
  100. char phasetxt[4][100]={"Построение кучи","Исключение наибольшего элемента","Восстановление кучи","Сортировка окончена"};
  101. gboolean legendshow[STATECNT]={TRUE,TRUE,TRUE,TRUE,TRUE,FALSE};
  102. int legendshowcnt;
  103. int legendheight;
  104. char legendtext[STATECNT][100]={"Обычный","На своём месте","В куче","Перемещается","Перемещается на своё место",""};
  105. int phase;
  106. int finished;
  107. int clrneed;
  108. int hi,hj;
  109. int legx,legy;
  110.  
  111. int main(int argc,char * argv[])
  112. {
  113.     int i;
  114.     int maxh;
  115.     gtk_init(&argc,&argv);
  116.     window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
  117.    
  118.     gtk_widget_set_size_request(window,WIDTH,HEIGHT);
  119.  
  120.    
  121.     srand(time(0));
  122.     for(maxh=0;(1<<maxh)<=N;maxh++);
  123.     for(i=0;i<N;i++)
  124.     {
  125.         el[i].linecoord=getlinecoord(i);
  126.         el[i].treecoord=gettreecoord(i,maxh);
  127.         el[i].value=rand()%MOD;
  128.         el[i].state=normal;
  129.     }
  130.     gtk_widget_show(window);
  131.     init_gc();
  132.     init_sort();
  133.     init_legend();
  134.     g_signal_connect(G_OBJECT(window),"delete-event",G_CALLBACK(delete_event),NULL);
  135.     g_signal_connect(G_OBJECT(window),"expose-event",G_CALLBACK(expose_event),NULL);
  136.     expose_event(window,NULL,NULL);
  137.     gtk_main();
  138.     return 0;
  139. }
  140.  
  141.  
  142. void init_gc()
  143. {
  144.     GdkColor c;
  145.     gcbg[normal]=gdk_gc_new(window->window);
  146.     gcfg[normal]=gdk_gc_new(window->window);
  147.     gcbg[active]=gdk_gc_new(window->window);
  148.     gcfg[active]=gdk_gc_new(window->window);
  149.     gcbg[inplace]=gdk_gc_new(window->window);
  150.     gcfg[inplace]=gdk_gc_new(window->window);
  151.     gcbg[activeinheap]=gcbg[active];
  152.     gcfg[activeinheap]=gcfg[active];
  153.     gcbg[inheap]=gdk_gc_new(window->window);
  154.     gcfg[inheap]=gdk_gc_new(window->window);
  155.     gcbg[activeinplace]=gdk_gc_new(window->window);
  156.     gcfg[activeinplace]=gdk_gc_new(window->window);
  157.    
  158.     c.red=255*257;
  159.     c.green=250*257;
  160.     c.blue=173*257;
  161.     gdk_gc_set_rgb_fg_color(gcbg[normal],&c);
  162.    
  163.     c.red=97*257;
  164.     c.green=78*257;
  165.     c.blue=0*257;
  166.     gdk_gc_set_rgb_fg_color(gcfg[normal],&c);
  167.    
  168.     c.red=255*257;
  169.     c.green=255*257;
  170.     c.blue=255*257;
  171.     gdk_gc_set_rgb_fg_color(gcbg[active],&c);  
  172.    
  173.     c.red=118*257;
  174.     c.green=0*257;
  175.     c.blue=0*257;  
  176.     gdk_gc_set_rgb_fg_color(gcfg[active],&c);
  177.        
  178.     c.red=205*257;
  179.     c.green=188*257;
  180.     c.blue=0*257;  
  181.     gdk_gc_set_rgb_fg_color(gcbg[inplace],&c);
  182.    
  183.     c.red=0*257;
  184.     c.green=0*257;
  185.     c.blue=0*257;  
  186.     gdk_gc_set_rgb_fg_color(gcfg[inplace],&c);
  187.    
  188.     c.red=246*255;
  189.     c.green=197*255;
  190.     c.blue=0*255;
  191.     gdk_gc_set_rgb_fg_color(gcbg[inheap],&c);
  192.    
  193.     c.red=97*257;
  194.     c.green=78*257;
  195.     c.blue=0*257;
  196.     gdk_gc_set_rgb_fg_color(gcfg[inheap],&c);
  197.  
  198.     c.red=255*257;
  199.     c.green=255*257;
  200.     c.blue=255*257;
  201.     gdk_gc_set_rgb_fg_color(gcbg[activeinplace],&c);   
  202.    
  203.     c.red=97*257;
  204.     c.green=78*257;
  205.     c.blue=0*257;
  206.     gdk_gc_set_rgb_fg_color(gcfg[activeinplace],&c);
  207. }
  208.  
  209. void init_sort()
  210. {
  211.     arr=el-1;
  212.     phase=0;
  213.     hi=1;
  214.     hj=1;
  215.     finished=2;
  216.     clrneed=1;
  217.     g_timeout_add(SORTDELAY,(GSourceFunc) heapsort,NULL);
  218. }
  219.  
  220. void init_legend()
  221. {
  222.     int i;
  223.     int curx,cury;
  224.     char s[10]="XX";
  225.     legx=-1;
  226.     legy=-1;
  227.     legendshowcnt=0;
  228.     for(i=0;i<STATECNT;i++)
  229.         if(legendshow[i]) legendshowcnt++;
  230.     legendheight=LEGENDINNEROFFSETY+2*RAD*legendshowcnt+GAP*(legendshowcnt-1)+LEGENDINNEROFFSETY+LEGENDHEADERHEIGHT;
  231.     legend=gdk_pixmap_new(window->window,LEGENDWIDTH+2,legendheight+2,-1);
  232.     gdk_draw_rectangle(legend,window->style->bg_gc[GTK_WIDGET_STATE(window)],TRUE,0,0,LEGENDWIDTH+2,legendheight+2);
  233.  
  234.     draw_text_in_center(LEGENDHEADER,window,legend,window->style->black_gc,LEGENDWIDTH/2,LEGENDHEADERHEIGHT/2);
  235.     gdk_draw_rectangle(legend,window->style->black_gc,FALSE,1,LEGENDHEADERHEIGHT+1,LEGENDWIDTH,legendheight-LEGENDHEADERHEIGHT);
  236.     gdk_draw_rectangle(legend,window->style->white_gc,FALSE,0,LEGENDHEADERHEIGHT,LEGENDWIDTH,legendheight-LEGENDHEADERHEIGHT);
  237.     curx=LEGENDINNEROFFSETX;
  238.     cury=LEGENDINNEROFFSETY+LEGENDHEADERHEIGHT;
  239.    
  240.     for(i=0;i<STATECNT;i++)
  241.     {
  242.         if(!legendshow[i]) continue;
  243.         gdk_draw_arc(legend,gcbg[i],TRUE,curx,cury,2*RAD,2*RAD,0,64*360);
  244.         gdk_draw_arc(legend,gcfg[i],FALSE,curx,cury,2*RAD,2*RAD,0,64*360);
  245.         draw_text_in_center(s,window,legend,gcfg[i],curx+RAD,cury+RAD);
  246.         draw_text_in_center_y(legendtext[i],window,legend,window->style->black_gc,curx+2*RAD+LEGENDINNEROFFSETX,cury+RAD);
  247.         cury+=2*RAD+GAP;
  248.     }
  249. }
  250.  
  251. gboolean expose_event(GtkWidget *w, GdkEvent *e, gpointer data)
  252. {
  253.     int i;
  254.     displayphasetxt();
  255.     draw_legend();
  256.     for(i=0;i<N;i++)
  257.     {
  258.         draw_element(w,&el[i]);
  259.     }
  260.     return TRUE;
  261. }
  262.  
  263. GdkPoint gettreecoord(int n,int maxh)
  264. {
  265.     GdkPoint res;
  266.     int h;
  267.     for(h=0;(1<<h)<=n+1;h++);
  268.     res.x=TREEOFFSETX+((1<<(maxh-h))-1)*(2*RAD+GAP)/2.0+( (1<<(maxh-h))*GAP+((1<<(maxh-h)))*2*RAD)*(n-(1<<(h-1))+1);
  269.     res.y=TREEOFFSETY+(h-1)*(2*RAD+GAP);
  270.     return res;
  271. }
  272.  
  273. GdkPoint getlinecoord(int n)
  274. {
  275.     GdkPoint res;
  276.     res.x=LINEOFFSETX+(2*RAD+GAP)*n;
  277.     res.y=LINEOFFSETY;
  278.     return res;
  279. }
  280.  
  281. void draw_element(GtkWidget *w, element *e)
  282. {
  283.     char s[10];
  284.     sprintf(s,"%.2d",e->value);
  285.     gdk_draw_arc(w->window,gcbg[e->state],TRUE,e->linecoord.x,e->linecoord.y,2*RAD,2*RAD,0,64*360);
  286.     gdk_draw_arc(w->window,gcfg[e->state],FALSE,e->linecoord.x,e->linecoord.y,2*RAD,2*RAD,0,64*360);
  287.     draw_text_in_center(s,w,w->window,gcfg[e->state],e->linecoord.x+RAD,e->linecoord.y+RAD);
  288.     gdk_draw_arc(w->window,gcbg[e->state],TRUE,e->treecoord.x,e->treecoord.y,2*RAD,2*RAD,0,64*360);
  289.     gdk_draw_arc(w->window,gcfg[e->state],FALSE,e->treecoord.x,e->treecoord.y,2*RAD,2*RAD,0,64*360);
  290.     draw_text_in_center(s,w,w->window,gcfg[e->state],e->treecoord.x+RAD,e->treecoord.y+RAD);
  291. }
  292.  
  293. void draw_text_in_center(gchar * text, GtkWidget *w, GdkDrawable *d, GdkGC *gc, gint xc, gint yc)
  294. {
  295.     PangoContext *context=gtk_widget_create_pango_context(w);
  296.     PangoLayout *layout= pango_layout_new(context);
  297.     gint width,height;
  298.     pango_layout_set_text(layout,text,-1);
  299.     pango_layout_get_pixel_size(layout,&width,&height);
  300.     gdk_draw_layout (d,gc,xc-width/2,yc-height/2,layout);
  301.     g_object_unref(context); g_object_unref(layout);
  302. }
  303.  
  304. void draw_text_in_center_y(gchar * text, GtkWidget *w, GdkDrawable *d, GdkGC *gc, gint x, gint yc)
  305. {
  306.     PangoContext *context=gtk_widget_create_pango_context(w);
  307.     PangoLayout *layout= pango_layout_new(context);
  308.     gint width,height;
  309.     pango_layout_set_text(layout,text,-1);
  310.     pango_layout_get_pixel_size(layout,&width,&height);
  311.     gdk_draw_layout (d,gc,x,yc-height/2,layout);
  312.     g_object_unref(context); g_object_unref(layout);
  313. }
  314.  
  315. void draw_legend()
  316. {
  317.     if(legx>0&&legy>0)
  318.         gdk_window_clear_area(window->window,legx,legy,legx+LEGENDWIDTH,legy+legendheight);
  319.     legx=window->allocation.width-LEGENDOFFSETX-LEGENDWIDTH;
  320.     legy=LEGENDY;
  321.     gdk_draw_drawable(window->window,window->style->fg_gc[GTK_WIDGET_STATE(window)],legend,0,0,legx,legy,-1,-1);
  322. }
  323.  
  324. void displayphasetxt()
  325. {
  326.     gdk_window_clear_area(window->window,0,0,window->allocation.width,2*CENTERTEXTOFFSETY+2);
  327.     draw_text_in_center(phasetxt[phase],window,window->window,window->style->white_gc,window->allocation.width/2+SHADOWOFFSET,CENTERTEXTOFFSETY+SHADOWOFFSET);
  328.     draw_text_in_center(phasetxt[phase],window,window->window,window->style->black_gc,window->allocation.width/2,CENTERTEXTOFFSETY);
  329. }
  330.  
  331. void startmoving(elpath *p1,elpath *p2)
  332. {
  333.     finished=0;
  334.     g_timeout_add(MOVEDELAY,(GSourceFunc) move,(gpointer) p1);
  335.     g_timeout_add(MOVEDELAY,(GSourceFunc) move,(gpointer) p2);
  336. }
  337.  
  338. gboolean move(elpath* p)
  339. {
  340.     int i;
  341.     GdkPoint lc,tc;
  342.     lc=el[p->elnum].linecoord;
  343.     tc=el[p->elnum].treecoord;
  344.     gdk_window_clear_area(window->window,el[p->elnum].linecoord.x,el[p->elnum].linecoord.y,2*RAD+1,2*RAD+1);
  345.     gdk_window_clear_area(window->window,el[p->elnum].treecoord.x,el[p->elnum].treecoord.y,2*RAD+1,2*RAD+1);
  346.     if(p->linecurve!=NULL)
  347.     {
  348.         el[p->elnum].linecoord=*((GdkPoint*) p->linecurve->data);
  349.         free(p->linecurve->data);
  350.         p->linecurve=g_list_remove(p->linecurve,p->linecurve->data);
  351.     }
  352.     if(p->treecurve!=NULL)
  353.     {
  354.         el[p->elnum].treecoord=*((GdkPoint*) p->treecurve->data);
  355.         free(p->treecurve->data);
  356.         p->treecurve=g_list_remove(p->treecurve,p->treecurve->data);
  357.     }
  358.     for(i=0;i<N;i++)
  359.     {
  360.         if(i==p->elnum) continue;
  361.         if((el[i].linecoord.x+2*RAD+1>=lc.x&&el[i].linecoord.x<=lc.x+2*RAD+1&&el[i].linecoord.y+2*RAD+1>=lc.y&&el[i].linecoord.y<=lc.y+2*RAD+1)||
  362.            (el[i].treecoord.x+2*RAD+1>=tc.x&&el[i].treecoord.x<=tc.x+2*RAD+1&&el[i].treecoord.y+2*RAD+1>=tc.y&&el[i].treecoord.y<=tc.y+2*RAD+1))
  363.         {
  364.             draw_element(window,&el[i]);
  365.         }
  366.     }
  367.     if(p->linecurve==NULL&&p->treecurve==NULL)
  368.     {
  369.         switch(el[p->elnum].state)
  370.         {
  371.             case activeinplace:
  372.                 el[p->elnum].state=inplace;
  373.                 break;
  374.             case activeinheap:
  375.                 el[p->elnum].state=inheap;
  376.                 break;
  377.             default:
  378.                 el[p->elnum].state=normal;
  379.         }
  380.     }
  381.     draw_element(window,&el[p->elnum]);
  382.     if(p->linecurve==NULL&&p->treecurve==NULL)
  383.     {
  384.         finished++;
  385.         free(p);
  386.         if(finished==2&&phase==1)
  387.             phase=2;
  388.         if(finished==2)
  389.             g_timeout_add(SORTDELAY,(GSourceFunc) heapsort,NULL);
  390.         return FALSE;
  391.     }
  392.     return TRUE;
  393. }
  394.  
  395. void swap(int idx1,int idx2)
  396. {
  397.     elpath *p1,*p2;
  398.     int i;
  399.     element t;
  400.     t=el[idx1];
  401.     el[idx1]=el[idx2];
  402.     el[idx2]=t;
  403.     p1=(elpath*) malloc(sizeof(elpath));
  404.     p2=(elpath*) malloc(sizeof(elpath));
  405.     *p1=makepath(idx1,el[idx1].linecoord,el[idx2].linecoord,-RISE,VCOUNT,HCOUNT,VCOUNT,el[idx1].treecoord,el[idx2].treecoord,2*VCOUNT+HCOUNT-2);
  406.     *p2=makepath(idx2,el[idx2].linecoord,el[idx1].linecoord,+RISE,VCOUNT,HCOUNT,VCOUNT,el[idx2].treecoord,el[idx1].treecoord,2*VCOUNT+HCOUNT-2);
  407.     switch(el[idx1].state)
  408.     {
  409.         case inplace:
  410.             el[idx1].state=activeinplace;
  411.             break;
  412.         case inheap:
  413.             el[idx1].state=activeinheap;
  414.             break;
  415.         default:
  416.             el[idx1].state=active;
  417.     }
  418.     switch(el[idx2].state)
  419.     {
  420.         case inplace:
  421.             el[idx2].state=activeinplace;
  422.             break;
  423.         case inheap:
  424.             el[idx2].state=activeinheap;
  425.             break;
  426.         default:
  427.             el[idx2].state=active;
  428.     }
  429.    
  430.     startmoving(p1,p2);
  431. }
  432.  
  433. void genline(GdkPoint s, GdkPoint t,int cnt,GList ** l)
  434. {
  435.     GdkPoint m,*c;
  436.     int i;
  437.     m=s;
  438.     for(i=1;i<cnt;i++)
  439.     {
  440.         c=(GdkPoint*) malloc(sizeof(GdkPoint));
  441.         *c=m;
  442.         *l=g_list_append(*l,c);
  443.         m.x=s.x+i*1.0*(t.x-s.x)/(cnt-1);
  444.         m.y=s.y+i*1.0*(t.y-s.y)/(cnt-1);
  445.     }
  446. }
  447.  
  448. elpath makepath(gint idx,GdkPoint listb,GdkPoint liste, gint dy, gint listc1, gint listc2,gint listc3,GdkPoint treep1,GdkPoint treep2, gint treec)
  449. {
  450.     GdkPoint s,t,*c;
  451.     elpath res;
  452.     double tx,ty;
  453.     GList *listl=NULL,*treel=NULL;
  454.     int i;
  455.     s=t=listb;
  456.     t.y+=dy;
  457.     genline(s,t,listc1,&listl);
  458.    
  459.     s=listb;
  460.     s.y+=dy;
  461.     t=liste;
  462.     t.y+=dy;
  463.     genline(s,t,listc2,&listl);
  464.    
  465.     s=liste;
  466.     s.y+=dy;
  467.     t=liste;
  468.     genline(s,t,listc3,&listl);
  469.    
  470.     c=(GdkPoint*) malloc(sizeof(GdkPoint));
  471.     *c=t;
  472.     listl=g_list_append(listl,c);
  473.    
  474.     genline(treep1,treep2,treec,&treel);
  475.    
  476.     c=(GdkPoint*) malloc(sizeof(GdkPoint));
  477.     *c=treep2;
  478.     treel=g_list_append(treel,c);
  479.    
  480.     res.linecurve=listl;
  481.     res.treecurve=treel;
  482.     res.elnum=idx;
  483.    
  484.     return res;
  485. }
  486.  
  487. gboolean heapsort(gpointer data)
  488. {
  489.     int s1,s2;
  490.     if(finished==2)
  491.     {
  492.         if(phase==0)
  493.         {
  494.             for(;hi<=N;hi++)
  495.             {
  496.                 el[hi-1].state=inheap;
  497.                 if(hi==1)
  498.                 {
  499.                     draw_element(window,&el[hi-1]);
  500.                     hi++;
  501.                     hj=hi;
  502.                     return TRUE;
  503.                 }
  504.                 for(;hj>1;hj>>=1)
  505.                 {
  506.                     if(arr[hj].value>arr[hj>>1].value)
  507.                     {
  508.                         swap(hj-1,(hj>>1)-1);
  509.                         hj>>=1;
  510.                         return FALSE;
  511.                     }
  512.                     else
  513.                     {
  514.                         draw_element(window,&el[hi-1]);
  515.                         hj>>=1;
  516.                         return TRUE;
  517.                     }              
  518.                 }
  519.                 hj=hi+1;
  520.             }
  521.             phase=1;
  522.             displayphasetxt();
  523.             hi=N;
  524.         }
  525.         if(clrneed)
  526.         {
  527.             for(hi=0;hi<N;hi++)
  528.                 el[hi].state=normal;
  529.             clrneed=0;
  530.         }
  531.         expose_event(window,NULL,NULL);
  532.         for(;hi>1;hi--)
  533.         {
  534.             displayphasetxt();
  535.             if(phase==1)
  536.             {
  537.                 if(hi==2) el[1].state=inplace;
  538.                 el[0].state=inplace;
  539.                 swap(0,hi-1);
  540.                 hj=1;
  541.                 return FALSE;
  542.             }
  543.             for(;;)
  544.             {
  545.                 s1=(hj<<1);
  546.                 s2=(hj<<1)+1;
  547.                 if(s1>=hi) s1=hj;
  548.                 if(s2>=hi) s2=hj;
  549.                 if(arr[s1].value>arr[hj].value||arr[s2].value>arr[hj].value)
  550.                 {
  551.                     if(arr[s1].value>arr[s2].value)
  552.                     {
  553.                         swap(hj-1,s1-1);
  554.                         hj=s1;
  555.                         return FALSE;
  556.                     }
  557.                     else
  558.                     {
  559.                         swap(hj-1,s2-1);
  560.                         hj=s2;
  561.                         return FALSE;
  562.                     }
  563.                 }
  564.                 else break;
  565.             }
  566.             phase=1;
  567.         }
  568.         phase=3;
  569.         displayphasetxt();
  570.         return FALSE;
  571.     }
  572.     return TRUE;
  573. }
  574.  
  575. gboolean delete_event(GtkWidget *w,GdkEvent *e, gpointer data)
  576. {
  577.     gtk_main_quit();
  578.     return TRUE;
  579. }
Add Comment
Please, Sign In to add comment