TSP: The Transport Sample Protocol



Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

gdisp_plot2D.c

Go to the documentation of this file.
00001 
00043 /*
00044  * System includes.
00045  */
00046 #include <stdio.h>
00047 #include <stdlib.h>
00048 #include <assert.h>
00049 #include <string.h>
00050 #include <errno.h>
00051 #include <math.h>
00052 
00053 
00054 /*
00055  * For key manipulation.
00056  */
00057 #include <gdk/gdkkeysyms.h>
00058 #include <gdk/gdkx.h>
00059 
00060 
00061 /*
00062  * GDISP+ includes.
00063  */
00064 #include "gdisp_kernel.h"
00065 #include "gdisp_prototypes.h"
00066 
00067 #include "gdisp_plot2D.h"
00068 
00069 #undef DEBUG_2D
00070 
00071 /*
00072  --------------------------------------------------------------------
00073                              TODO : Hard coded VALUES 
00074  --------------------------------------------------------------------
00075 */
00076 #define GDISP_2D_MARGIN_RATIO   0.1 /* We anticipate the next 10% of futur */
00077 #define GDISP_2D_MAX_TITLE     50   /* Nb char in title  */
00078 
00079 #define GDISP_2D_BACK_COLOR _BLACK_
00080 
00081 /*
00082  --------------------------------------------------------------------
00083                              STATIC ROUTINES
00084  --------------------------------------------------------------------
00085 */
00086 
00087 static void
00088 gdisp_manageSymbolNameWindow ( Kernel_T *kernel,
00089                                Plot2D_T *plot,
00090                                GList    *symbolList);
00091 
00092 /*
00093  * Verbosity management.
00094  */
00095 static int gdispVerbosity = 1;
00096 
00097 #if defined(DEBUG_2D)   
00098 #  define GDISP_TRACE(level,txt) \
00099         if (level <= gdispVerbosity) fprintf(stderr,txt); 
00100 #else
00101 #  define GDISP_TRACE(level,txt) \
00102         /* nothing to be done */
00103 #endif
00104 
00105 #define EVENT_METHOD(widget,event) \
00106         GTK_WIDGET_CLASS(GTK_OBJECT(widget)->klass)->event
00107 
00108 /*
00109  * SAMPLE is in physical unit,
00110  * PLOT is in logical pixel, (0,0) is bottom left,
00111  * WIN is in pixel with "good" GTK direction, (0,0) is upper left.
00112  */
00113 
00114 #define X_WIN_TO_PLOT(plot,x) (x)
00115 #define Y_WIN_TO_PLOT(plot,y) ((plot)->p2dAreaHeight - (y))
00116 
00117 #define X_PLOT_TO_WIN(plot,x) (x)
00118 #define Y_PLOT_TO_WIN(plot,y) ((plot)->p2dAreaHeight - (y))
00119 
00120 #define X_SYMBOL_OFFSET  5
00121 #define Y_SYMBOL_OFFSET 15
00122 
00123 #define X_SAMPLE_TO_PLOT(plot,xx) \
00124         ( ((xx) - (plot)->p2dPtMin.x) * (plot)->p2dPtSlope.x)
00125 #define Y_SAMPLE_TO_PLOT(plot,yy) \
00126         ( ((yy) - (plot)->p2dPtMin.y) * (plot)->p2dPtSlope.y)
00127 
00128 #define X_SAMPLE_TO_WIN(plot,x) (X_PLOT_TO_WIN(plot,X_SAMPLE_TO_PLOT(plot,x)))
00129 #define Y_SAMPLE_TO_WIN(plot,y) (Y_PLOT_TO_WIN(plot,Y_SAMPLE_TO_PLOT(plot,y)))
00130 
00131 
00132 /*
00133  * Free memory of all sample point table.
00134  */
00135 static void
00136 gdisp_freeSampledPointTables( Kernel_T *kernel,
00137                               Plot2D_T *plot,
00138                               gboolean  freeAll)
00139 {
00140 
00141   guint    nbCurves  = 0;
00142   guint    sArrayCpt = 0;
00143   gpointer pdata     = (gpointer)NULL;
00144 
00145   nbCurves = plot->p2dSampleArray->len;
00146 
00147   for (sArrayCpt=0; sArrayCpt<nbCurves; sArrayCpt++) {
00148 
00149     pdata = g_ptr_array_remove_index_fast(plot->p2dSampleArray,
00150                                           0 /* always remove first one */);
00151 
00152     dparray_freeSampleArray((DoublePointArray_T*)pdata);
00153 
00154   }
00155 
00156   if (freeAll == TRUE) {
00157 
00158     g_ptr_array_free(plot->p2dSampleArray,FALSE);
00159     plot->p2dSampleArray = (GPtrArray*)NULL;
00160 
00161   }
00162 
00163 }
00164 
00165 
00166 /*
00167  * Loop over all elements of the list.
00168  * Each element is a TSP symbol the 'sReference' parameter of
00169  * which must be decremented.
00170  */
00171 static void
00172 gdisp_dereferenceSymbolList ( GList *symbolList )
00173 {
00174 
00175   GList    *symbolItem =    (GList*)NULL;
00176   Symbol_T *symbol     = (Symbol_T*)NULL;
00177 
00178   /*
00179    * Loop over all elements of the list.
00180    * Do not forget to decrement the 'sReference' of each symbol.
00181    */
00182   if (symbolList != (GList*)NULL) {
00183 
00184     symbolItem = g_list_first(symbolList);
00185 
00186     while (symbolItem != (GList*)NULL) {
00187 
00188       symbol = (Symbol_T*)symbolItem->data;
00189 
00190       symbol->sReference--;
00191 
00192       symbolItem = g_list_next(symbolItem);
00193 
00194     }
00195 
00196     g_list_free(symbolList);
00197 
00198   }
00199 
00200 }
00201 
00202 
00203 /*
00204  * Draw the symbol list.
00205  */
00206 static void
00207 gdisp_drawSymbolName ( Kernel_T *kernel,
00208                        Plot2D_T *plot,
00209                        gboolean  xAxis)
00210 {
00211 
00212   GList    *symbolItem   =    (GList*)NULL;
00213   Symbol_T *symbol       = (Symbol_T*)NULL;
00214   guint     xPosition    =               0;
00215   guint     yPosition    =               0;
00216   gint      lBearing     =               0;
00217   gint      rBearing     =               0;
00218   gint      width        =               0;
00219   gint      ascent       =               0;
00220   gint      descent      =               0;
00221   gint      windowX      =               0;
00222   gint      windowY      =               0;
00223   gint      windowWidth  =               0;
00224   gint      windowHeight =               0;
00225   gint      windowDepth  =               0;
00226 
00227 
00228   /*
00229    * Clear window content.
00230    */
00231   gdk_gc_set_foreground(plot->p2dGContext,
00232                         &kernel->colors[_GREY_]);
00233 
00234   gdk_window_get_geometry(xAxis == TRUE ?
00235                           plot->p2dXSymbolWindow : plot->p2dYSymbolWindow,
00236                           &windowX,
00237                           &windowY,
00238                           &windowWidth,
00239                           &windowHeight,
00240                           &windowDepth);
00241 
00242   gdk_draw_rectangle(xAxis == TRUE ?
00243                      plot->p2dXSymbolWindow : plot->p2dYSymbolWindow,
00244                      plot->p2dGContext,
00245                      TRUE, /* rectangle is filled */
00246                      0,
00247                      0,
00248                      windowWidth,
00249                      windowHeight);
00250 
00251   /*
00252    * TSP Symbol list attached to the X and Y axis.
00253    */
00254   if (xAxis == TRUE) {
00255 
00256     xPosition = X_SYMBOL_OFFSET;
00257     yPosition = Y_SYMBOL_OFFSET;
00258 
00259     symbol = (Symbol_T*)plot->p2dXSymbolList->data;
00260 
00261     gdk_gc_set_foreground(plot->p2dGContext,
00262                           &kernel->colors[_BLACK_]);
00263 
00264     gdk_draw_string(plot->p2dXSymbolWindow,
00265                     plot->p2dFont,
00266                     plot->p2dGContext,
00267                     xPosition,
00268                     yPosition,
00269                     symbol->sInfo.name);
00270 
00271     /*
00272      * White rectangle around window.
00273      */
00274     gdk_window_get_geometry(plot->p2dXSymbolWindow,
00275                             &windowX,
00276                             &windowY,
00277                             &windowWidth,
00278                             &windowHeight,
00279                             &windowDepth);
00280 
00281     gdk_gc_set_foreground(plot->p2dGContext,
00282                           &kernel->colors[_WHITE_]);
00283 
00284     gdk_draw_rectangle(plot->p2dXSymbolWindow,
00285                        plot->p2dGContext,
00286                        FALSE, /* rectangle is not filled */
00287                        0,
00288                        0,
00289                        windowWidth  - 1,
00290                        windowHeight - 1);
00291 
00292   }
00293   else /* Y axis */ {
00294 
00295     xPosition = X_SYMBOL_OFFSET;
00296     yPosition = Y_SYMBOL_OFFSET;
00297 
00298     gdk_gc_set_foreground(plot->p2dGContext,
00299                           &kernel->colors[_BLACK_]);
00300 
00301     symbolItem = g_list_first(plot->p2dYSymbolList);
00302     while (symbolItem != (GList*)NULL) {
00303 
00304       symbol = (Symbol_T*)symbolItem->data;
00305 
00306       gdk_draw_string(plot->p2dYSymbolWindow,
00307                       plot->p2dFont,
00308                       plot->p2dGContext,
00309                       xPosition,
00310                       yPosition,
00311                       symbol->sInfo.name);
00312 
00313       /*
00314        * Underline selected symbol.
00315        */
00316       if (symbolItem == plot->p2dSelectedSymbol) {
00317 
00318         gdk_string_extents(plot->p2dFont,
00319                            symbol->sInfo.name,
00320                            &lBearing,
00321                            &rBearing,
00322                            &width,
00323                            &ascent,
00324                            &descent);
00325 
00326         gdk_draw_line(plot->p2dYSymbolWindow,
00327                       plot->p2dGContext,
00328                       xPosition,                /* x1 */
00329                       yPosition + descent,      /* y1 */
00330                       xPosition + width,        /* x2 */
00331                       yPosition + descent);     /* y2 */
00332 
00333       }
00334 
00335       yPosition += Y_SYMBOL_OFFSET;
00336 
00337       symbolItem = g_list_next(symbolItem);
00338 
00339     }
00340 
00341     /*
00342      * White rectangle around window.
00343      */
00344     gdk_gc_set_foreground(plot->p2dGContext,
00345                           &kernel->colors[_WHITE_]);
00346 
00347     gdk_draw_rectangle(plot->p2dYSymbolWindow,
00348                        plot->p2dGContext,
00349                        FALSE, /* rectangle is not filled */
00350                        0,
00351                        0,
00352                        windowWidth  - 1,
00353                        windowHeight - 1);
00354 
00355   }
00356 
00357 }
00358 
00359 
00360 /*
00361  * Try to delete one or several symbols on Y axis.
00362  */
00363 static void
00364 gdisp_deleteSelectedSymbolName ( Kernel_T *kernel,
00365                                  Plot2D_T *plot,
00366                                  gint      xMouse,
00367                                  gint      yMouse,
00368                                  gboolean  isShifted)
00369 {
00370 
00371   DoublePointArray_T *pArray   = (DoublePointArray_T*)NULL;
00372   guint               position =                         0;
00373 
00374   /*
00375    * 'button3' removes the selected symbol from the list.
00376    * 'shift' + 'button3' removes all symbols.
00377    */
00378   if (isShifted == TRUE) {
00379 
00380     /*
00381      * Do not forget to decrement the reference of the Y symbol.
00382      */
00383     gdisp_dereferenceSymbolList(plot->p2dXSymbolList);
00384     gdisp_dereferenceSymbolList(plot->p2dYSymbolList);
00385     plot->p2dXSymbolList    = (GList*)NULL;
00386     plot->p2dYSymbolList    = (GList*)NULL;
00387     plot->p2dSelectedSymbol = (GList*)NULL;
00388 
00389     /*
00390      * Free data for sampled points.
00391      */
00392     gdisp_freeSampledPointTables(kernel,plot,FALSE /* freeAll */);
00393 
00394     /*
00395      * Reset bounding box.
00396      */
00397     plot->p2dPtMin.x = 0;
00398     plot->p2dPtMin.y = 0;
00399     plot->p2dPtMax.x = 0;
00400     plot->p2dPtMax.y = 0;
00401 
00402     /*
00403      * Destroy all Gdk windows.
00404      */
00405     if (plot->p2dXSymbolWindow != (GdkWindow*)NULL)
00406       gdk_window_destroy(plot->p2dXSymbolWindow);
00407     if (plot->p2dYSymbolWindow != (GdkWindow*)NULL)
00408       gdk_window_destroy(plot->p2dYSymbolWindow);
00409 
00410     plot->p2dXSymbolWindow = (GdkWindow*)NULL;
00411     plot->p2dYSymbolWindow = (GdkWindow*)NULL;
00412 
00413   }
00414   else {
00415 
00416     if (plot->p2dSelectedSymbol != (GList*)NULL) {
00417 
00418       position = g_list_position(plot->p2dYSymbolList,
00419                                  plot->p2dSelectedSymbol);
00420 
00421       plot->p2dYSymbolList = g_list_remove_link(plot->p2dYSymbolList,
00422                                                 plot->p2dSelectedSymbol);
00423 
00424       /*
00425        * Do not forget to decrement the reference of the Y symbol.
00426        */
00427       gdisp_dereferenceSymbolList(plot->p2dSelectedSymbol);
00428       plot->p2dSelectedSymbol = (GList*)NULL;
00429 
00430       /*
00431        * Free corresponding memory.
00432        */
00433       pArray = g_ptr_array_remove_index(plot->p2dSampleArray,
00434                                         position);
00435       dparray_freeSampleArray(pArray);
00436 
00437       /*
00438        * Update Y symbol name window.
00439        */
00440       if (g_list_length(plot->p2dYSymbolList) == 0) {
00441 
00442         if (plot->p2dYSymbolWindow != (GdkWindow*)NULL)
00443           gdk_window_destroy(plot->p2dYSymbolWindow);
00444         plot->p2dYSymbolWindow = (GdkWindow*)NULL;
00445 
00446       }
00447       else {
00448 
00449         gdisp_manageSymbolNameWindow(kernel,
00450                                      plot,
00451                                      plot->p2dYSymbolList);
00452 
00453       }
00454 
00455       /*
00456        * FIXME : Duf.
00457        * We have just removed one symbol.
00458        * How do we recompute the bounding box (min, max) so that the
00459        * remaining symbols use the whole graphic area ?
00460        */
00461 
00462     }
00463 
00464   }
00465 
00466 }
00467 
00468 
00469 /*
00470  * Draw selected symbol on Y axis.
00471  */
00472 static void
00473 gdisp_underlineSelectedSymbolName ( Kernel_T *kernel,
00474                                     Plot2D_T *plot,
00475                                     gint      xMouse,
00476                                     gint      yMouse)
00477 {
00478 
00479   GList    *symbolItem =    (GList*)NULL;
00480   Symbol_T *symbol     = (Symbol_T*)NULL;
00481   guint     xPosition  =               0;
00482   guint     yPosition  =               0;
00483   gint      lBearing   =               0;
00484   gint      rBearing   =               0;
00485   gint      width      =               0;
00486   gint      ascent     =               0;
00487   gint      descent    =               0;
00488 
00489 
00490   /*
00491    * Return if no symbol available.
00492    */
00493   if (plot->p2dYSymbolList == (GList*)NULL) {
00494 
00495     return;
00496 
00497   }
00498 
00499 
00500   /*
00501    * Try to get the symbol the mouse is over.
00502    */
00503   xPosition = X_SYMBOL_OFFSET;
00504   yPosition = Y_SYMBOL_OFFSET;
00505 
00506   symbolItem = g_list_first(plot->p2dYSymbolList);
00507   while (symbolItem != (GList*)NULL) {
00508 
00509     symbol = (Symbol_T*)symbolItem->data;
00510 
00511     /*
00512      * Compute surrounding rectangle dimensions.
00513      */
00514     gdk_string_extents(plot->p2dFont,
00515                        symbol->sInfo.name,
00516                        &lBearing,
00517                        &rBearing,
00518                        &width,
00519                        &ascent,
00520                        &descent);
00521 
00522     if (xPosition          < xMouse && xMouse < xPosition + width &&
00523         yPosition - ascent < yMouse && yMouse < yPosition + descent  ) {
00524 
00525       if (symbolItem != plot->p2dSelectedSymbol) {
00526 
00527         /*
00528          * This symbol becomes the new selected one, refresh graphic area.
00529          */
00530         plot->p2dSelectedSymbol = symbolItem;
00531 
00532         gdisp_drawSymbolName (kernel,
00533                               plot,
00534                               FALSE /* TRUE for xAxis, FALSE otherwise */);
00535 
00536       }
00537 
00538       /*
00539        * Stop here investigations, because selected symbol is found.
00540        */
00541       return;
00542 
00543     } /* Inside rectangle */
00544 
00545     yPosition += Y_SYMBOL_OFFSET;
00546 
00547     symbolItem = g_list_next(symbolItem);
00548 
00549   }
00550 
00551   /*
00552    * No symbol is selected, because the mouse is not inside any rectangle.
00553    * Refresh graphic area.
00554    */
00555   if (plot->p2dSelectedSymbol != (GList*)NULL) {
00556 
00557     plot->p2dSelectedSymbol = (GList*)NULL;
00558 
00559     gdisp_drawSymbolName (kernel,
00560                           plot,
00561                           FALSE /* TRUE for xAxis, FALSE otherwise */);
00562 
00563   }
00564 
00565 }
00566 
00567 
00568 /*
00569  * Manage symbol name window.
00570  */
00571 static GdkFilterReturn
00572 gdisp_symbolNameWindowEvent ( GdkXEvent *xevent,
00573                               GdkEvent  *event,
00574                               gpointer   data )
00575 {
00576 
00577   Kernel_T        *kernel       =   (Kernel_T*)data;
00578   Plot2D_T        *plot         =   (Plot2D_T*)NULL;
00579   GdkWindow       *nameWindow   =  (GdkWindow*)NULL;
00580   GdkFilterReturn  returnFilter = GDK_FILTER_REMOVE;
00581   XEvent          *xEvent       =     (XEvent*)NULL;
00582   GdkRectangle     exposeArea;
00583 
00584   GDISP_TRACE(3,"Symbol name window management.\n");
00585 
00586   /*
00587    * Manage all cases.
00588    */
00589   gdk_window_get_user_data(event->any.window,
00590                            (gpointer)&plot);
00591 
00592 
00593   /*
00594    * CAUTION !!!! CAUTION !!!! CAUTION !!!! CAUTION !!!! CAUTION !!!!
00595    *
00596    * Due to a strange way of processing events within Gdk, the second
00597    * parameter "event" (a GdkEvent pointer) must be used carefully.
00598    * The only field that is correct is the "window" field. All other
00599    * fields must not be used, because they are UNINITIALIZED !!!
00600    * All other information must be taken from the first argument "xevent"
00601    * that must be casted to a X11 native "XEvent" structure.
00602    */
00603   nameWindow = event->any.window; /* Symbol window */
00604   xEvent     = (XEvent*)xevent;
00605 
00606   switch (xEvent->type) {
00607 
00608   case Expose :
00609 
00610     GDISP_TRACE(3,"Expose on symbol name window.\n");
00611 
00612     exposeArea.x      = xEvent->xexpose.x;
00613     exposeArea.y      = xEvent->xexpose.y;
00614     exposeArea.width  = xEvent->xexpose.width;
00615     exposeArea.height = xEvent->xexpose.height;
00616 
00617     gdk_gc_set_clip_rectangle(plot->p2dGContext,
00618                               &exposeArea);
00619 
00620     gdisp_drawSymbolName(kernel,
00621                          plot,
00622                          nameWindow == plot->p2dXSymbolWindow ? TRUE : FALSE);
00623 
00624     gdk_gc_set_clip_rectangle(plot->p2dGContext,
00625                               (GdkRectangle*)NULL);
00626 
00627     break;
00628 
00629   case MotionNotify :
00630 
00631     GDISP_TRACE(3,"MotionNotify on symbol name window.\n");
00632 
00633     if (plot->p2dYSymbolWindow     == nameWindow &&
00634         plot->p2dSignalsAreBlocked == FALSE         ) {
00635 
00636       gdisp_underlineSelectedSymbolName(kernel,
00637                                         plot,
00638                                         xEvent->xmotion.x,
00639                                         xEvent->xmotion.y);
00640 
00641     }
00642 
00643     break;
00644 
00645   case ButtonPress :
00646 
00647     GDISP_TRACE(3,"ButtonPress on symbol name window.\n");
00648 
00649     if (plot->p2dYSymbolWindow     == nameWindow &&
00650         plot->p2dSignalsAreBlocked == FALSE         ) {
00651 
00652       if (xEvent->xbutton.button == Button3) {
00653 
00654         gdisp_deleteSelectedSymbolName(kernel,
00655                                        plot,
00656                                        xEvent->xbutton.x,
00657                                        xEvent->xbutton.y,
00658                                        (xEvent->xbutton.state & ShiftMask) ?
00659                                        TRUE : FALSE /* isShifted */);
00660 
00661       }
00662 
00663     }
00664 
00665     break;
00666 
00667   default :
00668     break;
00669 
00670   }
00671 
00672   return returnFilter;
00673 
00674 }
00675 
00676 
00677 /*
00678  * Create or resize the window associated to X and Y symbol names.
00679  */
00680 static void
00681 gdisp_manageSymbolNameWindow ( Kernel_T *kernel,
00682                                Plot2D_T *plot,
00683                                GList    *symbolList)
00684 {
00685 
00686   GdkWindow     **windowPointer  =  (GdkWindow**)NULL;
00687   GdkVisual      *visual         =   (GdkVisual*)NULL;
00688   GdkColormap    *colormap       = (GdkColormap*)NULL;
00689   GList          *symbolItem     =       (GList*)NULL;
00690   Symbol_T       *symbol         =    (Symbol_T*)NULL;
00691   gint            windowAttrMask =                  0;
00692   gint16          windowX        =                  0;
00693   gint16          windowY        =                  0;
00694   gint16          windowWidth    =                  0;
00695   gint16          windowHeight   =                  0;
00696   gint            lBearing       =                  0;
00697   gint            rBearing       =                  0;
00698   gint            width          =                  0;
00699   gint            ascent         =                  0;
00700   gint            descent        =                  0;
00701   GdkWindowAttr   windowAttr;
00702 
00703 
00704   GDISP_TRACE(3,"Creating or resizing symbol name window.\n");
00705 
00706 
00707   /*
00708    * Which axis ?
00709    */
00710   if (symbolList == plot->p2dYSymbolList) {
00711 
00712     if (g_list_length(symbolList) == 0)
00713       return;
00714 
00715     windowPointer = &plot->p2dYSymbolWindow;
00716 
00717     windowX       = X_SYMBOL_OFFSET * 3;
00718     windowY       = Y_SYMBOL_OFFSET;
00719 
00720     windowWidth   = 0; /* by default */
00721     windowHeight  = g_list_length(symbolList) * Y_SYMBOL_OFFSET;
00722     windowHeight += Y_SYMBOL_OFFSET / 2;
00723 
00724     symbolItem = g_list_first(symbolList);
00725     while (symbolItem != (GList*)NULL) {
00726 
00727       symbol = (Symbol_T*)symbolItem->data;
00728 
00729       gdk_string_extents(plot->p2dFont,
00730                          symbol->sInfo.name,
00731                          &lBearing,
00732                          &rBearing,
00733                          &width,
00734                          &ascent,
00735                          &descent);
00736 
00737       windowWidth = MAX(windowWidth,width);
00738 
00739       symbolItem = g_list_next(symbolItem);
00740 
00741     }
00742 
00743     windowWidth += 2 * X_SYMBOL_OFFSET;
00744 
00745   }
00746   else /* X */ {
00747 
00748     if (g_list_length(symbolList) == 0)
00749       return;
00750 
00751     windowPointer = &plot->p2dXSymbolWindow;
00752 
00753     windowX      = plot->p2dAreaWidth  - 3 * X_SYMBOL_OFFSET;
00754     windowY      = plot->p2dAreaHeight - 2 * Y_SYMBOL_OFFSET;
00755     windowWidth  = 0; /* by default */
00756     windowHeight = Y_SYMBOL_OFFSET + Y_SYMBOL_OFFSET / 2;
00757 
00758     symbolItem = g_list_first(symbolList);
00759     symbol = (Symbol_T*)symbolItem->data;
00760 
00761     gdk_string_extents(plot->p2dFont,
00762                        symbol->sInfo.name,
00763                        &lBearing,
00764                        &rBearing,
00765                        &width,
00766                        &ascent,
00767                        &descent);
00768 
00769     windowWidth  = width + 2 * X_SYMBOL_OFFSET;
00770     windowX     -= windowWidth;
00771 
00772   }
00773 
00774 
00775   /*
00776    * Get back information from parent window.
00777    */
00778   if (*windowPointer == (GdkWindow*)NULL) {
00779 
00780     visual   = gdk_window_get_visual  (plot->p2dArea->window);
00781     colormap = gdk_window_get_colormap(plot->p2dArea->window);
00782 
00783     memset(&windowAttr,0,sizeof(GdkWindowAttr));
00784 
00785     windowAttr.event_mask  = GDK_EXPOSURE_MASK       |
00786                              GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK;
00787     windowAttr.x           = windowX;
00788     windowAttr.y           = windowY;
00789     windowAttr.width       = windowWidth;
00790     windowAttr.height      = windowHeight;
00791     windowAttr.window_type = GDK_WINDOW_CHILD;
00792     windowAttr.wclass      = GDK_INPUT_OUTPUT;
00793     windowAttr.visual      = visual;
00794     windowAttr.colormap    = colormap;
00795     windowAttrMask         = GDK_WA_X        | GDK_WA_Y      |
00796                              GDK_WA_COLORMAP | GDK_WA_VISUAL;
00797 
00798     *windowPointer = gdk_window_new(plot->p2dArea->window,
00799                                     &windowAttr,
00800                                     windowAttrMask);
00801 
00802     assert(*windowPointer);
00803 
00804     gdk_window_set_user_data(*windowPointer,
00805                              (gpointer)plot);
00806 
00807     gdk_window_add_filter(*windowPointer,
00808                           gdisp_symbolNameWindowEvent,
00809                           (gpointer)kernel);
00810 
00811     gdk_window_show(*windowPointer);
00812 
00813   }
00814   else /* resize */ {
00815 
00816     gdk_window_move_resize(*windowPointer,
00817                            windowX,
00818                            windowY,
00819                            windowWidth,
00820                            windowHeight);
00821 
00822   }
00823 
00824 }
00825 
00826 
00827 /*
00828  * Copy back buffer into graphic area (front buffer).
00829  */
00830 static void
00831 gdisp_plot2DSwapBuffers (Kernel_T       *kernel,
00832                          Plot2D_T       *plot,
00833                          KindOfRedraw_T  drawType)
00834 {
00835 
00836   GDISP_TRACE(3,"Swaping front and back buffers\n");
00837 
00838   /*
00839    * Take care of draw type.
00840    */
00841   if (drawType == GD_2D_ADD_NEW_SAMPLES) {
00842 
00843     /*
00844      * Should only repaint the area of buffer
00845      * that has been updated => OverPowerfull. Thanks Duf.
00846      */
00847     gdk_draw_pixmap(plot->p2dArea->window,
00848                     plot->p2dGContext,
00849                     plot->p2dBackBuffer,
00850                     plot->p2dPtRedrawMin.x,
00851                     plot->p2dPtRedrawMin.y,
00852                     plot->p2dPtRedrawMin.x,
00853                     plot->p2dPtRedrawMin.y,
00854                     plot->p2dPtRedrawMax.x - plot->p2dPtRedrawMin.x + 1,
00855                     plot->p2dPtRedrawMax.y - plot->p2dPtRedrawMin.y + 1);
00856 
00857   }
00858   else {
00859 
00860     /*
00861      * Copy back buffer into front buffer.
00862      */
00863     gdk_draw_pixmap(plot->p2dArea->window,
00864                     plot->p2dGContext,
00865                     plot->p2dBackBuffer,
00866                     0,
00867                     0,
00868                     0,
00869                     0,
00870                     plot->p2dArea->allocation.width,
00871                     plot->p2dArea->allocation.height);
00872 
00873   }
00874 
00875 }
00876 
00877 
00878 /*
00879  * Redraw back buffer content. 2 parts :
00880  *
00881  * - gdisp_plot2DDrawBackBufferBackground : 
00882  *      Only for background earsing, titles and Axis.
00883  *      For X_SCROLL, use 'gdk_draw_pixmap' for translating 90% of bitmap.
00884  *
00885  * - gdisp_plot2DDrawBackBufferCurves
00886  *      Plot the lines 
00887  *
00888  */
00889 static void
00890 gdisp_plot2DDrawBackBufferBackground (Kernel_T       *kernel,
00891                                       Plot2D_T       *plot,
00892                                       KindOfRedraw_T  drawType)
00893 {
00894 
00895 #undef WANT_TITLES
00896 
00897 #if defined(WANT_TITLES)
00898   gint      lBearing   =               0;
00899   gint      rBearing   =               0;
00900   gint      width      =               0;
00901   gint      ascent     =               0;
00902   gint      descent    =               0;
00903   gchar     title   [GDISP_2D_MAX_TITLE];
00904   gchar     subTitle[GDISP_2D_MAX_TITLE];
00905 #endif
00906 
00907 
00908   /*
00909    * We never enter this routine with 'drawType' GD_2D_ADD_NEW_SAMPLES.
00910    */
00911 
00912   /*
00913    * Take care of the type of the drawing process.
00914    */
00915   if (drawType == GD_2D_FULL_REDRAW) {
00916 
00917     GDISP_TRACE(2,"Drawing into back buffer -> background : FULL_REDRAW\n");
00918 
00919     gdk_gc_set_foreground(plot->p2dGContext,
00920                           &kernel->colors[GDISP_2D_BACK_COLOR]);
00921 
00922     gdk_draw_rectangle(plot->p2dBackBuffer,
00923                        plot->p2dGContext,
00924                        TRUE, /* rectangle is filled */
00925                        0,
00926                        0,
00927                        plot->p2dArea->allocation.width,
00928                        plot->p2dArea->allocation.height);
00929 
00930   } /* GD_2D_FULL_REDRAW */
00931 
00932 
00933   /*
00934    * We need to scroll the X axis.
00935    */
00936   else if (drawType == GD_2D_SCROLL_X_AXIS) {
00937 
00938     GDISP_TRACE(2,"Drawing into back buffer -> background : SCROLL_X\n");
00939 
00940     /*
00941      * Scroll the 90% of the backbuffer to the left.
00942      */
00943     gdk_draw_pixmap(plot->p2dBackBuffer, /* destination */
00944                     plot->p2dGContext,
00945                     plot->p2dBackBuffer, /* source      */
00946                     (gint)ceil(plot->p2dArea->allocation.width *
00947                                                      GDISP_2D_MARGIN_RATIO),
00948                     0,
00949                     0,
00950                     0,
00951                     (gint)ceil(plot->p2dArea->allocation.width *
00952                                                (1 - GDISP_2D_MARGIN_RATIO)), 
00953                     plot->p2dArea->allocation.height);
00954 
00955     /*
00956      * Erase the 10% left on the right.
00957      */
00958     gdk_gc_set_foreground(plot->p2dGContext,
00959                           &kernel->colors[GDISP_2D_BACK_COLOR]);
00960 
00961     gdk_draw_rectangle(plot->p2dBackBuffer,
00962                        plot->p2dGContext,
00963                        TRUE, /* rectangle is filled */
00964                        (gint)floor(plot->p2dArea->allocation.width *
00965                                                 (1 - GDISP_2D_MARGIN_RATIO)), 
00966                        0,
00967                        (gint)ceil(plot->p2dArea->allocation.width *
00968                                                       GDISP_2D_MARGIN_RATIO), 
00969                        plot->p2dArea->allocation.height);
00970 
00971   }
00972   else /* GD_2D_ADD_NEW_SAMPLES */ {
00973 
00974     GDISP_TRACE(2,
00975                 "Drawing into back buffer -> background : ADD_NEW_SAMPLES\n");
00976 
00977     return;
00978 
00979   }
00980 
00981 
00982   /*
00983    * Title
00984    */
00985 #if defined(WANT_TITLES)
00986 
00987   gdk_gc_set_foreground(plot->p2dGContext,
00988                         &kernel->colors[_WHITE_]);
00989 
00990   snprintf(title,
00991            GDISP_2D_MAX_TITLE,
00992            "Y=Sin(t) : {%g,%g}", 
00993            plot->p2dPtLast.x,
00994            plot->p2dPtLast.y);
00995 
00996   gdk_string_extents(plot->p2dFont,
00997                      title,
00998                      &lBearing,
00999                      &rBearing,
01000                      &width,
01001                      &ascent,
01002                      &descent);
01003 
01004   gdk_draw_string(plot->p2dBackBuffer,
01005                   plot->p2dFont,
01006                   plot->p2dGContext,
01007                   (plot->p2dArea->allocation.width - width) / 2,
01008                   Y_SYMBOL_OFFSET,
01009                   title);
01010       
01011   snprintf(subTitle,
01012            GDISP_2D_MAX_TITLE,
01013            "Bornes X={%g<%g} Y={%g<%g}", 
01014            plot->p2dPtMin.x,
01015            plot->p2dPtMax.x, 
01016            plot->p2dPtMin.y,
01017            plot->p2dPtMax.y);
01018       
01019   gdk_string_extents(plot->p2dFont,
01020                      subTitle,
01021                      &lBearing,
01022                      &rBearing,
01023                      &width,
01024                      &ascent,
01025                      &descent);
01026 
01027   gdk_draw_string(plot->p2dBackBuffer,
01028                   plot->p2dFont,
01029                   plot->p2dGContext,
01030                   (plot->p2dArea->allocation.width - width) / 2,
01031                   Y_SYMBOL_OFFSET * 2,
01032                   subTitle);
01033 
01034 #endif
01035       
01036 
01037   /*
01038    * X & Y axis lines around the graphic area.
01039    */
01040   gdk_gc_set_foreground(plot->p2dGContext,
01041                         &kernel->colors[_GREY_]);
01042 
01043 
01044   /* Axis on X=0 */
01045   gdk_draw_line(plot->p2dBackBuffer,
01046                 plot->p2dGContext,
01047                 X_SAMPLE_TO_WIN(plot,0.0),                /* x1 */
01048                 Y_SAMPLE_TO_WIN(plot,plot->p2dPtMin.y),   /* y1 */
01049                 X_SAMPLE_TO_WIN(plot,0.0),                /* x2 */
01050                 Y_SAMPLE_TO_WIN(plot,plot->p2dPtMax.y) ); /* y2 */
01051       
01052   /* Axis on Y=0 */
01053   gdk_draw_line(plot->p2dBackBuffer,
01054                 plot->p2dGContext,
01055                 X_SAMPLE_TO_WIN(plot,plot->p2dPtMin.x),   /* x1 */
01056                 Y_SAMPLE_TO_WIN(plot,0.0),                /* y1 */
01057                 X_SAMPLE_TO_WIN(plot,plot->p2dPtMax.x),   /* x2 */
01058                 Y_SAMPLE_TO_WIN(plot,0.0) );              /* y2 */
01059 
01060 
01061   /*
01062    * Black lines around the graphic area.
01063    */
01064   gdk_gc_set_foreground(plot->p2dGContext,
01065                         &kernel->colors[_BLACK_]);
01066 
01067   gdk_draw_line(plot->p2dBackBuffer,
01068                 plot->p2dGContext,
01069                 0,                                   /* x1 */
01070                 0,                                   /* y1 */
01071                 plot->p2dArea->allocation.width - 1, /* x2 */
01072                 0);                                  /* y2 */
01073 
01074   gdk_draw_line(plot->p2dBackBuffer,
01075                 plot->p2dGContext,
01076                 plot->p2dArea->allocation.width  - 1,  /* x1 */
01077                 0,                                     /* y1 */
01078                 plot->p2dArea->allocation.width  - 1,  /* x2 */
01079                 plot->p2dArea->allocation.height - 1); /* y2 */
01080 
01081 
01082   /*
01083    * Axis
01084    * FIXME : This piece of code must be put elsewhere,
01085    * but NOT here while drawing into the back-buffer.
01086    */
01087   if (plot->p2dPtMin.x != plot->p2dPtMax.x) {
01088 
01089     gtk_ruler_set_range(GTK_RULER(plot->p2dHRuler),
01090                         plot->p2dPtMin.x,
01091                         plot->p2dPtMax.x,
01092                         plot->p2dPtMin.x,
01093                         GDISP_WIN_T_DURATION);
01094 
01095   }
01096 
01097   if (plot->p2dPtMin.y != plot->p2dPtMax.y) {
01098 
01099     gtk_ruler_set_range(GTK_RULER(plot->p2dVRuler),
01100                         -plot->p2dPtMax.y,
01101                         -plot->p2dPtMin.y,
01102                         0,
01103                         plot->p2dPtMax.y - plot->p2dPtMin.y);
01104 
01105   }
01106       
01107 }
01108 
01109 
01110 static void
01111 gdisp_plot2DDrawBackBufferCurves (Kernel_T       *kernel,
01112                                   Plot2D_T       *plot,
01113                                   KindOfRedraw_T  drawType)
01114 {
01115 
01116   guint               nbCurves   =                         0;
01117   guint               cptCurve   =                         0;
01118   guint               cptPoint   =                         0;
01119   DoublePointArray_T *pArray     = (DoublePointArray_T*)NULL;
01120   DoublePoint_T      *pSample    =      (DoublePoint_T*)NULL;
01121   guint               startIndex =                         0;
01122   guint               lastIndex  =                         0;
01123   guint               nbPoints   =                         0;
01124   ShortPoint_T        lastPixel;
01125   ShortPoint_T        currentPixel;
01126 
01127   GDISP_TRACE(3,"Drawing into back buffer -> curves\n");
01128 
01129   /*
01130    * Compute bounding box to be redrawn.
01131    * Inversion for Y minimum and maximum, cause (0,0) is (up,left).
01132    */
01133   plot->p2dPtRedrawMin.x = X_SAMPLE_TO_WIN(plot,plot->p2dPtMax.x);
01134   plot->p2dPtRedrawMax.x = X_SAMPLE_TO_WIN(plot,plot->p2dPtMin.x);
01135   plot->p2dPtRedrawMin.y = Y_SAMPLE_TO_WIN(plot,plot->p2dPtMin.y);
01136   plot->p2dPtRedrawMax.y = Y_SAMPLE_TO_WIN(plot,plot->p2dPtMax.y);
01137 
01138 
01139   /*
01140    * Plot the sample lines
01141    */
01142   nbCurves = plot->p2dSampleArray->len;
01143   for (cptCurve=0; cptCurve<nbCurves; cptCurve++) {
01144 
01145     pArray = plot->p2dSampleArray->pdata[cptCurve]; 
01146 
01147     if (drawType == GD_2D_FULL_REDRAW) {
01148 
01149       /*
01150        * Plot all for GDISP_2D_FULL_REDRAW & GDISP_2D_SCROLL_X_AXIS.
01151        */
01152       startIndex = dparray_getFirstIndex(pArray);
01153       nbPoints   = dparray_getNbSamples (pArray);
01154 
01155     }
01156     else {
01157 
01158       /*
01159        * GDISP_2D_ADD_NEW_SAMPLES => restart from where we stopped earlier.
01160        */
01161       startIndex = dparray_getMarkerIndex(pArray);
01162       nbPoints = dparray_getLeftSamplesFromPos(pArray,
01163                                                startIndex);
01164 
01165     }
01166     lastIndex = startIndex;
01167       
01168 
01169     /*
01170      * TODO: A color per draw ?
01171      */
01172     gdk_gc_set_foreground(plot->p2dGContext,
01173                           &kernel->colors[_YELLOW_ + cptCurve * 7]);
01174       
01175     for (cptPoint=startIndex; cptPoint<startIndex+nbPoints; cptPoint++) {
01176 
01177       lastIndex = cptPoint;
01178 
01179       pSample        = dparray_getSamplePtr(pArray,cptPoint);
01180       currentPixel.x = X_SAMPLE_TO_WIN(plot,pSample->x);
01181       currentPixel.y = Y_SAMPLE_TO_WIN(plot,pSample->y);
01182 
01183       /*
01184        * Store the area of backbuffer
01185        * that we'll need to redraw on front buffer.
01186        */
01187       if (currentPixel.x < plot->p2dPtRedrawMin.x) {
01188         plot->p2dPtRedrawMin.x = currentPixel.x;
01189       }
01190       if (currentPixel.y < plot->p2dPtRedrawMin.y) {
01191         plot->p2dPtRedrawMin.y = currentPixel.y;
01192       }
01193       if (currentPixel.x > plot->p2dPtRedrawMax.x) {
01194         plot->p2dPtRedrawMax.x = currentPixel.x;
01195       }
01196       if (currentPixel.y > plot->p2dPtRedrawMax.y) {
01197         plot->p2dPtRedrawMax.y = currentPixel.y;
01198       }
01199 
01200       if ((cptPoint > startIndex ) &&
01201           (lastPixel.x != currentPixel.x || lastPixel.y != currentPixel.y)) {
01202 
01203         gdk_draw_line(plot->p2dBackBuffer,
01204                       plot->p2dGContext,
01205                       lastPixel.x,
01206                       lastPixel.y,
01207                       currentPixel.x,
01208                       currentPixel.y);
01209 
01210       }
01211 
01212       lastPixel = currentPixel;
01213 
01214     } /* end of loop for drawing on curve */
01215 
01216     /*
01217      * Mark the last plotted position, for next drawBackBuffer optimisation.
01218      */
01219     if (nbPoints > 0) {
01220 
01221       /*
01222        * Must Redtart from the previous last point
01223        */
01224       dparray_setMarkerIndex(pArray,
01225                              lastIndex -1);
01226 
01227     }
01228 
01229   } /* end of loop on every curves */
01230 
01231 }
01232 
01233 
01234 /*
01235  * Redraw back buffer content.
01236  */
01237 static void
01238 gdisp_plot2DDrawBackBuffer (Kernel_T       *kernel,
01239                             Plot2D_T       *plot,
01240                             KindOfRedraw_T  drawType)
01241 {
01242 
01243   GDISP_TRACE(3,"Drawing into back buffer\n");
01244 
01245   /*
01246    * Do not redraw background when simply adding new samples.
01247    */
01248   if (drawType != GD_2D_ADD_NEW_SAMPLES) {
01249 
01250     plot->p2dPtSlope.x =
01251       plot->p2dAreaWidth  / (plot->p2dPtMax.x - plot->p2dPtMin.x);
01252     plot->p2dPtSlope.y =
01253       plot->p2dAreaHeight / (plot->p2dPtMax.y - plot->p2dPtMin.y);
01254 
01255     gdisp_plot2DDrawBackBufferBackground(kernel,
01256                                          plot,
01257                                          drawType);
01258   }
01259 
01260   /*
01261    * Always plot the new lines for every curve.
01262    */
01263   gdisp_plot2DDrawBackBufferCurves(kernel,
01264                                    plot,
01265                                    drawType);
01266 
01267 }
01268 
01269 
01270 /*
01271  * Treat 'expose' X event.
01272  * What shall I do when the graphic area has to be refreshed ?
01273  */
01274 static gboolean
01275 gdisp_plot2DExpose (GtkWidget       *area,
01276                     GdkEventExpose  *event,
01277                     gpointer         data)
01278 {
01279 
01280   Kernel_T *kernel = (Kernel_T*)data;
01281   Plot2D_T *plot   = (Plot2D_T*)NULL;
01282 
01283   GDISP_TRACE(3,"Expose event\n");
01284 
01285   /*
01286    * Graphic area has now to be repainted.
01287    */
01288   plot = (Plot2D_T*)gtk_object_get_data(GTK_OBJECT(area),
01289                                         "plotPointer");
01290 
01291   gdk_gc_set_clip_rectangle(plot->p2dGContext,
01292                             &event->area);
01293 
01294   gdisp_plot2DSwapBuffers(kernel,
01295                           plot,
01296                           GD_2D_FULL_REDRAW);
01297 
01298   gdk_gc_set_clip_rectangle(plot->p2dGContext,
01299                             (GdkRectangle*)NULL);
01300 
01301   return TRUE;
01302 
01303 }
01304 
01305 
01306 /*
01307  * Treat 'configure' X event.
01308  * What shall I do when the graphic area has to be re-configured ?
01309  */
01310 static gboolean
01311 gdisp_plot2DConfigure (GtkWidget         *area,
01312                        GdkEventConfigure *event,
01313                        gpointer           data)
01314 {
01315 
01316   Kernel_T *kernel = (Kernel_T*)data;
01317   Plot2D_T *plot   = (Plot2D_T*)NULL;
01318 
01319   GDISP_TRACE(1,"Configure event\n");
01320 
01321   /*
01322    * Get plot private data.
01323    */
01324   plot = (Plot2D_T*)gtk_object_get_data(GTK_OBJECT(area),
01325                                         "plotPointer");
01326 
01327 
01328   /*
01329    * Don't know why, but GTK generates a 'configure' event when
01330    * showing widgets before returning into the main X loop. Strange.
01331    */
01332   if (event->width == 1 && event->height == 1) {
01333 
01334     GDISP_TRACE(3,"Configure event returns suddendly.\n");
01335 
01336     return TRUE;
01337 
01338   }
01339 
01340 
01341   /*
01342    * Graphic area has now to be resized
01343    */
01344   plot->p2dAreaWidth  = event->width;
01345   plot->p2dAreaHeight = event->height;
01346 
01347 
01348   /*
01349    * Some difficulties to create the back buffer in the 'create' procedure,
01350    * because some window information are not yet available.
01351    * So create it here.
01352    */
01353   if (plot->p2dBackBuffer != (GdkPixmap*)NULL) {
01354 
01355     gdk_pixmap_unref(plot->p2dBackBuffer);
01356 
01357   }
01358 
01359 
01360   /*
01361    * Create a pixmap for double buffering.
01362    * Deduce depth from graphic area window.
01363    */
01364   GDISP_TRACE(3,"Creating back buffer.\n");
01365 
01366   plot->p2dBackBuffer = gdk_pixmap_new(plot->p2dArea->window,
01367                                        plot->p2dAreaWidth,
01368                                        plot->p2dAreaHeight,
01369                                        -1 /* same as window */);
01370 
01371   assert(plot->p2dBackBuffer);
01372 
01373 
01374   /*
01375    * The configure operation is done after a resize request.
01376    * So refresh back buffer.
01377    */
01378   gdisp_plot2DDrawBackBuffer(kernel,
01379                              plot,
01380                              GD_2D_FULL_REDRAW);
01381 
01382 
01383   /*
01384    * Take care of X symbol name window.
01385    * No need to move/resize Y symbol list.
01386    */
01387   gdisp_manageSymbolNameWindow(kernel,
01388                                plot,
01389                                plot->p2dXSymbolList);
01390 
01391   return TRUE;
01392 
01393 }
01394 
01395 
01396 /*
01397  * Treat 'enter-notify' X event.
01398  * What shall I do when the mouse enters the graphic area ?
01399  */
01400 static gboolean
01401 gdisp_plot2DEnterNotify (GtkWidget        *area,
01402                          GdkEventCrossing *event,
01403                          gpointer          data)
01404 {
01405 
01406   Plot2D_T *plot = (Plot2D_T*)NULL;
01407 
01408   GDISP_TRACE(2,"Enter Notify Event\n");
01409 
01410   /*
01411    * Graphic area has now the focus.
01412    */
01413   plot = (Plot2D_T*)gtk_object_get_data(GTK_OBJECT(area),
01414                                         "plotPointer");
01415 
01416   plot->p2dHasFocus = TRUE;
01417 
01418   return TRUE;
01419 
01420 }
01421 
01422 
01423 /*
01424  * Treat 'leave-notify' X event.
01425  * What shall I do when the mouse leaves the graphic area ?
01426  */
01427 static gboolean
01428 gdisp_plot2DLeaveNotify (GtkWidget        *area,
01429                          GdkEventCrossing *event,
01430                          gpointer          data)
01431 {
01432 
01433   Plot2D_T *plot = (Plot2D_T*)NULL;
01434 
01435   GDISP_TRACE(2,"Leave Notify Event.\n");
01436 
01437   /*
01438    * Graphic area has lost the focus.
01439    */
01440   plot = (Plot2D_T*)gtk_object_get_data(GTK_OBJECT(area),
01441                                         "plotPointer");
01442 
01443   plot->p2dHasFocus = FALSE;
01444 
01445   return TRUE;
01446 
01447 }
01448 
01449 
01450 /*
01451  * Treat 'button-press' X event.
01452  * What shall I do when the user press a button on the graphic area ?
01453  */
01454 static gboolean
01455 gdisp_plot2DButtonPress (GtkWidget      *area,
01456                          GdkEventButton *event,
01457                          gpointer        data)
01458 {
01459 
01460   Kernel_T *kernel = (Kernel_T*)data;
01461   Plot2D_T *plot   = (Plot2D_T*)NULL;
01462 
01463   GDISP_TRACE(3,"Button press event.\n");
01464 
01465   /*
01466    * Graphic area has lost the focus.
01467    */
01468   plot = (Plot2D_T*)gtk_object_get_data(GTK_OBJECT(area),
01469                                         "plotPointer");
01470 
01471   /*
01472    * Nothing to be done if button identity is not 3.
01473    */
01474   if (event->button != 3) {
01475 
01476     return TRUE;
01477 
01478   }
01479 
01480   /*
01481    * 'button3' removes the selected symbol from the list.
01482    * 'shift' + 'button3' removes all symbols.
01483    */
01484   if (event->state & GDK_SHIFT_MASK) {
01485 
01486   }
01487   else {
01488 
01489   }
01490 
01491   /*
01492    * Refresh graphic area.
01493    */
01494   gdisp_plot2DDrawBackBuffer(kernel,
01495                              plot,
01496                              GD_2D_FULL_REDRAW);
01497 
01498   gdisp_plot2DSwapBuffers   (kernel,
01499                              plot,
01500                              GD_2D_FULL_REDRAW);
01501 
01502   return TRUE;
01503 
01504 }
01505 
01506 
01507 /*
01508  * Treat 'motion-notify' X event.
01509  * What shall I do when the mouse moves over the graphic area ?
01510  */
01511 static gboolean
01512 gdisp_plot2DMotionNotify (GtkWidget      *area,
01513                           GdkEventMotion *event,
01514                           gpointer        data)
01515 {
01516 
01517   Kernel_T *kernel     = (Kernel_T*)data;
01518   Plot2D_T *plot       = (Plot2D_T*)NULL;
01519 
01520   guint     xPosition  =               0;
01521   guint     yPosition  =               0;
01522 
01523   GDISP_TRACE(3,"Motion notify event.\n");
01524 
01525 
01526   /*
01527    * Graphic area has lost the focus.
01528    */
01529   plot = (Plot2D_T*)gtk_object_get_data(GTK_OBJECT(area),
01530                                         "plotPointer");
01531 
01532 
01533   /*
01534    * Take care of hints from X Server.
01535    */
01536   if (event->is_hint) {
01537   
01538     gdk_window_get_pointer(event->window,
01539                            &xPosition,
01540                            &yPosition,
01541                            &event->state);
01542 
01543     event->x = (gdouble)xPosition;
01544     event->y = (gdouble)yPosition;
01545 
01546   }
01547 
01548   gdisp_plot2DDrawBackBuffer(kernel,
01549                              plot,
01550                              GD_2D_FULL_REDRAW);
01551 
01552   gdisp_plot2DSwapBuffers   (kernel,
01553                              plot,
01554                              GD_2D_FULL_REDRAW);
01555 
01556   return TRUE;
01557 
01558 }
01559 
01560 
01561 /*
01562  * Create a '2D plot' by providing an opaque structure to the
01563  * caller. This opaque structure will be given as an argument to all
01564  * plot function. These functions remain generic.
01565  */
01566 static void*
01567 gdisp_createPlot2D (Kernel_T *kernel)
01568 {
01569 
01570 #define FROZEN_RULER
01571 
01572   Plot2D_T *plot     = (Plot2D_T*)NULL;
01573   guint     signalID = 0;
01574 
01575   /*
01576    * Dynamic allocation.
01577    */
01578   plot = g_malloc0(sizeof(Plot2D_T));
01579   assert(plot);
01580 
01581   /*
01582    * Few initialisations.
01583    */
01584   plot->p2dHasFocus  = FALSE;
01585   plot->p2dIsWorking = FALSE;
01586   plot->p2dType      = GD_PLOT_2D;
01587   plot->p2dSubType   = GD_2D_F2T;
01588 
01589   /*
01590    * Create a table : dimension 2 x 2, homogeneous.
01591    * Insert a graphic area and two rulers in it.
01592    */
01593   plot->p2dTable = gtk_table_new(2,
01594                                  2,
01595                                  FALSE);
01596 
01597   plot->p2dArea = gtk_drawing_area_new();
01598 
01599   plot->p2dSignalsAreBlocked = FALSE;
01600   plot->p2dSignalIdentities  = g_array_new(FALSE /* zero terminated */,
01601                                            TRUE  /* clear           */,
01602                                            sizeof(guint));
01603 
01604   gtk_table_attach(GTK_TABLE(plot->p2dTable),
01605                    plot->p2dArea,
01606                    1,
01607                    2,
01608                    0,
01609                    1,
01610                    GTK_EXPAND | GTK_FILL,
01611                    GTK_EXPAND | GTK_FILL,
01612                    0,
01613                    0 );
01614 
01615 #if defined(GD_AREA_WANT_EXTRA_EVENTS)
01616 
01617   gtk_widget_set_events(plot->p2dArea,
01618                         GDK_POINTER_MOTION_MASK      |
01619                         GDK_POINTER_MOTION_HINT_MASK |
01620                         GDK_ENTER_NOTIFY_MASK        |
01621                         GDK_LEAVE_NOTIFY_MASK        |
01622                         GDK_BUTTON_PRESS_MASK          );
01623 
01624 #endif
01625 
01626   gtk_signal_connect(GTK_OBJECT(plot->p2dArea),
01627                      "expose_event",
01628                      (GtkSignalFunc)gdisp_plot2DExpose,
01629                      (gpointer)kernel);
01630 
01631   gtk_signal_connect (GTK_OBJECT(plot->p2dArea),
01632                       "configure_event",
01633                       (GtkSignalFunc)gdisp_plot2DConfigure,
01634                       (gpointer)kernel); 
01635 
01636   /*
01637    * Store few signals in order to block them afterwards.
01638    */
01639   signalID = gtk_signal_connect(GTK_OBJECT(plot->p2dArea),
01640                                 "enter_notify_event",
01641                                 (GtkSignalFunc)gdisp_plot2DEnterNotify,
01642                                 (gpointer)kernel);
01643   g_array_append_val(plot->p2dSignalIdentities,signalID);
01644 
01645   signalID = gtk_signal_connect(GTK_OBJECT(plot->p2dArea),
01646                                 "leave_notify_event",
01647                                 (GtkSignalFunc)gdisp_plot2DLeaveNotify,
01648                                 (gpointer)kernel);
01649   g_array_append_val(plot->p2dSignalIdentities,signalID);
01650 
01651   signalID = gtk_signal_connect(GTK_OBJECT(plot->p2dArea),
01652                                 "button_press_event",
01653                                 (GtkSignalFunc)gdisp_plot2DButtonPress,
01654                                 (gpointer)kernel);
01655   g_array_append_val(plot->p2dSignalIdentities,signalID);
01656 
01657   signalID = gtk_signal_connect(GTK_OBJECT(plot->p2dArea),
01658                                 "motion_notify_event",
01659                                 (GtkSignalFunc)gdisp_plot2DMotionNotify,
01660                                 (gpointer)kernel);
01661   g_array_append_val(plot->p2dSignalIdentities,signalID);
01662 
01663   gtk_object_set_data(GTK_OBJECT(plot->p2dArea),
01664                       "plotPointer",
01665                       (gpointer)plot);
01666 
01667   /*
01668    * The horizontal ruler goes on bottom.
01669    * As the mouse moves across the drawing area, a 'motion_notify_event'
01670    * is passed to the appropriate event handler for the ruler.
01671    */
01672   plot->p2dHRuler = gtk_hruler_new();
01673 
01674   gtk_ruler_set_metric(GTK_RULER(plot->p2dHRuler),
01675                        GTK_PIXELS);
01676 
01677   gtk_ruler_set_range(GTK_RULER(plot->p2dHRuler),
01678                       0,
01679                       10,
01680                       0,
01681                       10);
01682 
01683 #if !defined(FROZEN_RULER)
01684   gtk_signal_connect_object(GTK_OBJECT(plot->p2dArea),
01685                             "motion_notify_event",
01686                             (GtkSignalFunc)EVENT_METHOD(plot->p2dHRuler,
01687                                                         motion_notify_event),
01688                             GTK_OBJECT(plot->p2dHRuler));
01689 #endif
01690 
01691 #if defined(FROZEN_RULER)
01692   gtk_widget_set_sensitive(plot->p2dHRuler,
01693                            FALSE /* no sensitive */);
01694 #endif
01695 
01696   gtk_table_attach(GTK_TABLE(plot->p2dTable),
01697                    plot->p2dHRuler,
01698                    1,
01699                    2,
01700                    1,
01701                    2,
01702                    GTK_EXPAND | GTK_SHRINK | GTK_FILL,
01703                    GTK_FILL,
01704                    0,
01705                    0);
01706     
01707   /*
01708    * The vertical ruler goes on the left.
01709    * As the mouse moves across the drawing area, a 'motion_notify_event'
01710    * is passed to the appropriate event handler for the ruler.
01711    */
01712   plot->p2dVRuler = gtk_vruler_new();
01713 
01714   gtk_ruler_set_metric(GTK_RULER(plot->p2dVRuler),
01715                        GTK_PIXELS);
01716 
01717   gtk_ruler_set_range(GTK_RULER(plot->p2dVRuler),
01718                       -10,
01719                       0,
01720                       0,
01721                       10);
01722 
01723 #if !defined(FROZEN_RULER)
01724   gtk_signal_connect_object(GTK_OBJECT(plot->p2dArea),
01725                             "motion_notify_event",
01726                             (GtkSignalFunc)EVENT_METHOD(plot->p2dVRuler,
01727                                                         motion_notify_event),
01728                             GTK_OBJECT(plot->p2dVRuler));
01729 #endif
01730 
01731 #if defined(FROZEN_RULER)
01732   gtk_widget_set_sensitive(plot->p2dVRuler,
01733                            FALSE /* no sensitive */);
01734 #endif
01735 
01736   gtk_table_attach(GTK_TABLE(plot->p2dTable),
01737                    plot->p2dVRuler,
01738                    0,
01739                    1,
01740                    0,
01741                    1,
01742                    GTK_FILL,
01743                    GTK_EXPAND | GTK_SHRINK | GTK_FILL,
01744                    0,
01745                    0);
01746 
01747   /*
01748    * Create a graphic context specific to this plot.
01749    */
01750   plot->p2dGContext =
01751     gdk_gc_new(GTK_WIDGET(kernel->widgets.mainBoardWindow)->window);
01752   plot->p2dFont     = kernel->fonts[GD_FONT_SMALL][GD_FONT_FIXED];
01753 
01754 
01755   /*
01756    * Initialize sampled points.
01757    * Allocation is done when dropping symbols onto the plot.
01758    */
01759   plot->p2dSampleArray = g_ptr_array_new();
01760 
01761 
01762   /*
01763    * Return the opaque structure.
01764    */
01765   return (void*)plot;
01766 
01767 }
01768 
01769 
01770 /*
01771  * Destroy a '2D' plot opaque structure.
01772  */
01773 static void
01774 gdisp_destroyPlot2D(Kernel_T *kernel,
01775                     void     *data)
01776 {
01777 
01778   Plot2D_T *plot = (Plot2D_T*)data;
01779 
01780   /*
01781    * Free symbol list.
01782    */
01783   gdisp_dereferenceSymbolList(plot->p2dXSymbolList);
01784   gdisp_dereferenceSymbolList(plot->p2dYSymbolList);
01785 
01786   /*
01787    * Now destroy everything.
01788    */
01789   if (plot->p2dXSymbolWindow != (GdkWindow*)NULL)
01790     gdk_window_destroy(plot->p2dXSymbolWindow      );
01791   if (plot->p2dYSymbolWindow != (GdkWindow*)NULL)
01792     gdk_window_destroy(plot->p2dYSymbolWindow      );
01793   gdk_gc_destroy    (plot->p2dGContext             );
01794   gdk_pixmap_unref  (plot->p2dBackBuffer           );
01795   gtk_widget_destroy(plot->p2dArea                 );
01796   gtk_widget_destroy(plot->p2dHRuler               );
01797   gtk_widget_destroy(plot->p2dVRuler               );
01798   gtk_widget_destroy(plot->p2dTable                );
01799   g_array_free      (plot->p2dSignalIdentities,TRUE);
01800 
01801   /*
01802    * Free data for sampled points.
01803    */
01804   gdisp_freeSampledPointTables(kernel,plot,TRUE /* freeAll */);
01805 
01806   /*
01807    * Free opaque structure.
01808    */
01809   memset(plot,0,sizeof(Plot2D_T));
01810   g_free(plot);
01811 
01812 }
01813 
01814 
01815 /*
01816  * Record the parent widget.
01817  */
01818 static void
01819 gdisp_setPlot2DParent (Kernel_T  *kernel,
01820                        void      *data,
01821                        GtkWidget *parent)
01822 {
01823 
01824   Plot2D_T *plot = (Plot2D_T*)data;
01825 
01826   /*
01827    * Remember my parent.
01828    */
01829   plot->p2dParent = parent;
01830 
01831 }
01832 
01833 
01834 /*
01835  * Record initial dimensions provided by the calling process.
01836  */
01837 static void
01838 gdisp_setPlot2DInitialDimensions (Kernel_T *kernel,
01839                                   void     *data,
01840                                   guint     width,
01841                                   guint     height)
01842 {
01843 
01844   Plot2D_T *plot = (Plot2D_T*)data;
01845 
01846   /*
01847    * Remember my initial width and height.
01848    */
01849   plot->p2dAreaWidth  = width;
01850   plot->p2dAreaHeight = height;
01851 
01852 }
01853 
01854 
01855 /*
01856  * Give back to the calling process the top level widget
01857  * in order to be inserted in a possible container for further
01858  * dynamic X management.
01859  */
01860 static GtkWidget*
01861 gdisp_getPlot2DTopLevelWidget (Kernel_T  *kernel,
01862                                void      *data)
01863 {
01864 
01865   Plot2D_T *plot = (Plot2D_T*)data;
01866 
01867   GDISP_TRACE(3,"Getting back plot 2D top level widget.\n");
01868 
01869   return (GtkWidget*)plot->p2dTable;
01870 
01871 }
01872 
01873 
01874 /*
01875  * By now, the '2D plot' widgets are created, but not shown yet.
01876  * Show them here.
01877  */
01878 static void
01879 gdisp_showPlot2D (Kernel_T  *kernel,
01880                   void      *data)
01881 {
01882 
01883   Plot2D_T *plot = (Plot2D_T*)data;
01884 
01885   GDISP_TRACE(3,"Showing plot 2D.\n");
01886 
01887   /*
01888    * Now show everything.
01889    */
01890   gtk_widget_show(plot->p2dArea  );
01891   gtk_widget_show(plot->p2dHRuler);
01892   gtk_widget_show(plot->p2dVRuler);
01893   gtk_widget_show(plot->p2dTable );
01894 
01895   /*
01896    * These 'show' operations generate 'configure' events. Strange.
01897    */
01898 
01899 }
01900 
01901 
01902 /*
01903  * Return to calling process what king of plot we are.
01904  */
01905 static PlotType_T
01906 gdisp_getPlot2DType (Kernel_T *kernel,
01907                      void     *data)
01908 {
01909 
01910   Plot2D_T *plot = (Plot2D_T*)data;
01911 
01912   GDISP_TRACE(3,"Getting back plot type (2D).\n");
01913 
01914   /*
01915    * Must be GD_PLOT_2D. See 'create' routine.
01916    */
01917   return plot->p2dType;
01918 
01919 }
01920 
01921 
01922 /*
01923  * Record any incoming symbols.
01924  * The drop coordinate (0,0) is at the lower left corner of the graphic area.
01925  */
01926 static void
01927 gdisp_addSymbolsToPlot2D (Kernel_T *kernel,
01928                           void     *data,
01929                           GList    *symbolList,
01930                           guchar    zoneId)
01931 {
01932 
01933   Plot2D_T *plot       = (Plot2D_T*)data;
01934   GList    *symbolItem =    (GList*)NULL;
01935   Symbol_T *symbol     = (Symbol_T*)NULL;
01936   guint     maxSamples =               0;
01937 
01938   GDISP_TRACE(3,"Adding symbols to plot 2D.\n");
01939 
01940   /*
01941    * If drop coordinates are in the X zone, the symbol has to be
01942    * attached to the X axis.
01943    * CAUTION : we bet the X will be monotonic increasing 
01944    * try plot y=f(t). Realtime will warn us if not.
01945    */
01946   if (zoneId == 'X') {
01947 
01948     /*
01949      * We cannot change X symbol while plot is been working...
01950      * It is a choice. Technically, it is possible, but what for ?
01951      */
01952     if (plot->p2dIsWorking == FALSE) {
01953 
01954       plot->p2dSubType = GD_2D_F2T;
01955 
01956       /*
01957        * Do not forget to decrement the reference of the X symbol.
01958        */
01959       gdisp_dereferenceSymbolList(plot->p2dXSymbolList);
01960       plot->p2dXSymbolList = (GList*)NULL;
01961 
01962       /*
01963        * Only one symbol on X axis.
01964        * Take the first symbol of the incoming list. DO NOT LOOP.
01965        */
01966       symbolItem = g_list_first(symbolList);
01967       if (symbolItem != (GList*)NULL) {
01968 
01969         plot->p2dXSymbolList = g_list_append(plot->p2dXSymbolList,
01970                                              symbolItem->data);
01971 
01972         symbol = (Symbol_T*)symbolItem->data;
01973         symbol->sReference++;
01974 
01975       }
01976 
01977       gdisp_manageSymbolNameWindow(kernel,
01978                                    plot,
01979                                    plot->p2dXSymbolList);
01980 
01981     } /* p2dIsWorking == FALSE */
01982 
01983   }
01984   else if (zoneId == 'Y') {
01985 
01986     /*
01987      * Incoming symbols are to be attached to the Y axis.
01988      */
01989 
01990     /*
01991      * Loop over all incoming symbols and store only those that
01992      * are not already in the final list.
01993      */
01994     symbolItem = g_list_first(symbolList);
01995     while (symbolItem != (GList*)NULL) {
01996 
01997       if (g_list_find(plot->p2dYSymbolList,symbolItem->data) == (GList*)NULL) {
01998 
01999         plot->p2dYSymbolList = g_list_append(plot->p2dYSymbolList,
02000                                              symbolItem->data);
02001 
02002         /*
02003          * Do not forget to increment the reference of the Y symbol.
02004          */
02005         symbol = (Symbol_T*)symbolItem->data;
02006         symbol->sReference++;
02007 
02008 
02009         /*
02010          * Allocate memory for receiving sampled values of the symbol.
02011          */
02012         maxSamples = TSP_PROVIDER_FREQ * GDISP_WIN_T_DURATION;
02013         g_ptr_array_add(plot->p2dSampleArray,
02014                         (gpointer)dparray_newSampleArray(maxSamples));
02015 
02016       }
02017 
02018       symbolItem = g_list_next(symbolItem);
02019 
02020     }
02021 
02022     gdisp_manageSymbolNameWindow(kernel,
02023                                  plot,
02024                                  plot->p2dYSymbolList);
02025 
02026   }
02027 
02028 
02029   /*
02030    * Refresh graphic area only if back buffer exists.
02031    */
02032   if (plot->p2dBackBuffer != (GdkPixmap*)NULL) {
02033 
02034     gdisp_plot2DDrawBackBuffer(kernel,
02035                                plot,
02036                                GD_2D_FULL_REDRAW);
02037 
02038     gdisp_plot2DSwapBuffers   (kernel,
02039                                plot,
02040                                GD_2D_FULL_REDRAW);
02041 
02042   }
02043 
02044 }
02045 
02046 
02047 /*
02048  * Broadcast all symbols.
02049  */
02050 static GList*
02051 gdisp_getSymbolsFromPlot2D (Kernel_T *kernel,
02052                             void     *data,
02053                             gchar     axis)
02054 {
02055 
02056   Plot2D_T *plot = (Plot2D_T*)data;
02057 
02058   GDISP_TRACE(3,"Give back the list of symbols handled by the plot 2D.\n");
02059 
02060   switch (axis) {
02061 
02062   case 'X' :
02063     return plot->p2dXSymbolList;
02064     break;
02065 
02066   case 'Y' :
02067     return plot->p2dYSymbolList;
02068     break;
02069 
02070   default :
02071     return (GList*)NULL;
02072     break;
02073 
02074   }
02075 
02076 }
02077 
02078 
02079 /*
02080  * Real time Starting Step Action.
02081  */
02082 static gboolean
02083 gdisp_startStepOnPlot2D (Kernel_T *kernel,
02084                          void     *data)
02085 {
02086 
02087   Plot2D_T *plot     = (Plot2D_T*)data;
02088   guint     nbEvents = 0;
02089   guint     cptEvent = 0;
02090   guint     eventID  = 0;
02091 
02092   GDISP_TRACE(3,"Performing start-step on plot 2D.\n");
02093 
02094   /*
02095    * Performs actions before starting steps.
02096    *
02097    * BUT we must return TRUE to the calling procedure in order to allow
02098    * the general step management to proceed.
02099    *
02100    * Returning FALSE means that our plot is not enabled to perform its
02101    * step operations, because of this or that...
02102    */
02103 
02104   /*
02105    * Checkout X and Y symbol lists.
02106    * There must be at least one symbol affected to the Y axis.
02107    * The X symbol list must not be empty.
02108    */
02109   if (g_list_length(plot->p2dYSymbolList) == 0 ||
02110       g_list_length(plot->p2dXSymbolList) == 0    ) {
02111 
02112     plot->p2dIsWorking = FALSE;
02113 
02114     return FALSE;
02115 
02116   }
02117 
02118 
02119   /*
02120    * Before starting steps, block few X signals.
02121    * Those signals have been recorded into a table.
02122    * These signals are : CrossingEvents, ButtonPressEvents, MotionEvents.
02123    */
02124   if (plot->p2dSignalsAreBlocked == FALSE) {
02125 
02126     nbEvents = plot->p2dSignalIdentities->len;
02127     for (cptEvent=0; cptEvent<nbEvents; cptEvent++) {
02128 
02129       eventID = (guint)g_array_index(plot->p2dSignalIdentities,
02130                                      guint,
02131                                      cptEvent);
02132 
02133       gtk_signal_handler_block(GTK_OBJECT(plot->p2dArea),
02134                                eventID);
02135 
02136     }
02137 
02138     plot->p2dSignalsAreBlocked = TRUE;
02139 
02140   }
02141 
02142 
02143   /*
02144    * Tell the plot it has been started by the application kernel.
02145    */
02146   plot->p2dIsWorking = TRUE;
02147 
02148   return TRUE /* everything's ok */;
02149 
02150 }
02151 
02152 
02153 /*
02154  * Real time Step Action.
02155  */
02156 static void
02157 gdisp_stepOnPlot2D (Kernel_T *kernel,
02158                     void     *data)
02159 {
02160 
02161   Plot2D_T           *plot           = (Plot2D_T*)data;
02162 
02163   guint               nbCurves       = 0;
02164   guint               cptCurve       = 0;
02165   guint               cptPoint       = 0;
02166   guint               startIndex     = 0;
02167   guint               nbPoints       = 0;
02168   KindOfRedraw_T      drawType       = GD_2D_ADD_NEW_SAMPLES;
02169   DoublePointArray_T *pArray         = (DoublePointArray_T*)NULL;
02170   DoublePoint_T      *pSample        =      (DoublePoint_T*)NULL;
02171   DoublePoint_T      *pLastPoint     = (DoublePoint_T*)NULL;
02172   guint               totalNbSamples = 0;
02173 
02174   /*
02175    * Guess we got new TSP values at each refresh cycles.
02176    */
02177   nbCurves = plot->p2dSampleArray->len;
02178   for (cptCurve=0; cptCurve<nbCurves; cptCurve++) {
02179 
02180     pArray         = plot->p2dSampleArray->pdata[cptCurve]; 
02181 
02182     totalNbSamples = dparray_getNbSamples         (pArray);
02183     startIndex     = dparray_getMarkerIndex       (pArray);
02184     nbPoints       = dparray_getLeftSamplesFromPos(pArray,
02185                                                    startIndex);
02186 
02187     /*
02188      * Try to know whether F2T becomes F2X...
02189      */
02190     pLastPoint = dparray_getSamplePtr(pArray,startIndex-1);
02191 
02192     for (cptPoint=startIndex; cptPoint<startIndex+nbPoints; cptPoint++) {
02193 
02194       pSample = dparray_getSamplePtr(pArray,cptPoint);
02195 
02196       /*
02197        * Check if plot2D is still monotonic increasing on X.
02198        */
02199       if (plot->p2dSubType == GD_2D_F2T && totalNbSamples > 0) {
02200 
02201         if (pSample->x < pLastPoint->x) {
02202 
02203           /*
02204            * FIXME : What to do if X increase like a exponentiel ?
02205            */
02206           plot->p2dSubType = GD_2D_F2X;
02207           drawType         = GD_2D_FULL_REDRAW;
02208           GDISP_TRACE(1,"gdisp_stepOnPlot2D : changing type to F2X\n");
02209 
02210         }
02211 
02212       }
02213 
02214       /*
02215        * I Could do this check later, but might be speeder on the fly.
02216        */
02217       if (pSample->y < plot->p2dPtMin.y) {
02218 
02219         plot->p2dPtMin.y = pSample->y * (1 + GDISP_2D_MARGIN_RATIO);
02220         drawType         = GD_2D_FULL_REDRAW;
02221 
02222       }
02223       if (pSample->y > plot->p2dPtMax.y) {
02224 
02225         plot->p2dPtMax.y = pSample->y * (1 + GDISP_2D_MARGIN_RATIO);
02226         drawType         = GD_2D_FULL_REDRAW;
02227 
02228       }
02229 
02230       switch (plot->p2dSubType) {
02231 
02232       case GD_2D_F2T :
02233         if (pSample->x > plot->p2dPtMax.x) {
02234 
02235           plot->p2dPtMax.x = pSample->x +
02236                              GDISP_WIN_T_DURATION * GDISP_2D_MARGIN_RATIO; 
02237           drawType         = GD_2D_FULL_REDRAW;
02238 
02239         }
02240         if (plot->p2dPtMax.x - plot->p2dPtMin.x > GDISP_WIN_T_DURATION) {
02241 
02242           plot->p2dPtMin.x = plot->p2dPtMax.x - GDISP_WIN_T_DURATION;
02243           drawType         = GD_2D_SCROLL_X_AXIS;
02244 
02245         }
02246         break;
02247  
02248       case GD_2D_F2X :
02249         if (pSample->x < plot->p2dPtMin.x) {
02250 
02251           plot->p2dPtMin.x = pSample->x * (1 + GDISP_2D_MARGIN_RATIO);
02252           drawType         = GD_2D_FULL_REDRAW;
02253 
02254         }
02255         if (pSample->x > plot->p2dPtMax.x) {
02256 
02257           plot->p2dPtMax.x = pSample->x * (1 + GDISP_2D_MARGIN_RATIO);
02258           drawType         = GD_2D_FULL_REDRAW;
02259 
02260         }
02261         break;
02262 
02263       default : 
02264         break;
02265 
02266       }
02267 
02268       plot->p2dPtLast = *pSample;
02269       *pLastPoint     = *pSample;
02270 
02271     } /* end loop upon new points */
02272           
02273   } /* end loop upon curves */
02274   
02275 
02276   /*
02277    * Put here what must be done at each step.
02278    */
02279   gdisp_plot2DDrawBackBuffer(kernel,
02280                              plot,
02281                              drawType);
02282 
02283   gdisp_plot2DSwapBuffers   (kernel,
02284                              plot,
02285                              drawType);
02286 
02287 }
02288 
02289 
02290 /*
02291  * Real time Starting Step Action.
02292  */
02293 static void
02294 gdisp_stopStepOnPlot2D (Kernel_T *kernel,
02295                         void     *data)
02296 {
02297 
02298   Plot2D_T *plot     = (Plot2D_T*)data;
02299   guint     nbEvents = 0;
02300   guint     cptEvent = 0;
02301   guint     eventID  = 0;
02302 
02303   GDISP_TRACE(3,"Performing stop-step on plot 2D.\n");
02304 
02305   /*
02306    * Performs actions after stopping steps.
02307    */
02308 
02309   /*
02310    * After stopping steps, unblock few X signals.
02311    * Those signals have been recorded into a table.
02312    * These signals are : CrossingEvents, ButtonPressEvents, MotionEvents.
02313    */
02314   if (plot->p2dSignalsAreBlocked == TRUE) {
02315 
02316     nbEvents = plot->p2dSignalIdentities->len;
02317     for (cptEvent=0; cptEvent<nbEvents; cptEvent++) {
02318 
02319       eventID = (guint)g_array_index(plot->p2dSignalIdentities,
02320                                      guint,
02321                                      cptEvent);
02322 
02323       gtk_signal_handler_unblock(GTK_OBJECT(plot->p2dArea),
02324                                  eventID);
02325 
02326     }
02327 
02328     plot->p2dSignalsAreBlocked = FALSE;
02329 
02330   }
02331 
02332   /*
02333    * Tell the plot it has been stopped by the application kernel.
02334    */
02335   plot->p2dIsWorking = FALSE;
02336 
02337 }
02338 
02339 
02340 /*
02341  * Get back to the calling procedure my period, expressed in milliseconds.
02342  * CAUTION : The period must be an exact multiple of 10.
02343  *           Should not be lower than 100.
02344  */
02345 static guint
02346 gdisp_getPlot2DPeriod (Kernel_T *kernel,
02347                        void     *data)
02348 {
02349 
02350   /*
02351    * My period is 100 milli-seconds.
02352    * FIXME : This value is hardcoded. It should be easily modifiable.
02353    * But how ?
02354    */
02355   return 100;
02356 
02357 }
02358 
02359 
02360 /*
02361  * Get back to the calling procedure my information.
02362  */
02363 static void
02364 gdisp_getPlot2DInformation (Kernel_T         *kernel,
02365                             PlotSystemInfo_T *information)
02366 {
02367 
02368 #include "pixmaps/gdisp_2dLogo.xpm"
02369 
02370   /*
02371    *   - Name,
02372    *   - Formula,
02373    *   - Descripton for tooltip purpose.
02374    */
02375   information->psName        = "2D Plot";
02376   information->psFormula     = "Y = F ( X or T )";
02377   information->psDescription = "A typical 2D plot that shows the evolution "
02378     "of several symbols (Y axis) relatively to a single one (X axis).";
02379   information->psLogo        = gdisp_2dLogo;
02380 
02381 }
02382 
02383 
02384 /*
02385  * This procedure is called whenever all symbols have been time-tagged
02386  * by the corresponding provider sampling thread.
02387  * The last value of all symbols can now be retreived by the graphic plot.
02388  *
02389  * CAUTION : This procedure is called in another thread, compared to all
02390  * other procedures of the graphic plot that are called by GTK main thread.
02391  */
02392 static void
02393 gdisp_treatPlot2DSymbolValues (Kernel_T *kernel,
02394                                void     *data)
02395 {
02396 
02397   Plot2D_T       *plot       = (Plot2D_T*)data;
02398 
02399   Symbol_T       *symbol     = (Symbol_T*)NULL;
02400   GList          *symbolItem = (GList*)NULL;
02401   guint           cptCurve   = 0;
02402   guint           nbCurves   = 0;
02403   DoublePoint_T   aPoint;
02404 
02405 
02406   /*
02407    * Get X (or T) last value.
02408    */
02409   symbol   = (Symbol_T*)plot->p2dXSymbolList->data;
02410   aPoint.x = symbol->sLastValue;
02411 
02412 
02413   /*
02414    * Get Y last values.
02415    */
02416   symbolItem = g_list_first(plot->p2dYSymbolList);
02417   nbCurves   = plot->p2dSampleArray->len;
02418 
02419   for (cptCurve=0; cptCurve<nbCurves; cptCurve++) {
02420 
02421     symbol   = (Symbol_T*)symbolItem->data;
02422     aPoint.y = symbol->sLastValue;
02423 
02424     dparray_addSample((DoublePointArray_T*)
02425                       plot->p2dSampleArray->pdata[cptCurve],
02426                       &aPoint);
02427 
02428     symbolItem = g_list_next(symbolItem);
02429 
02430   }
02431 
02432 }
02433 
02434 
02435 /*
02436  * Get back the zones that have been defined on that plot.
02437  */
02438 static GArray*
02439 gdisp_getPlot2DDropZones (Kernel_T *kernel)
02440 {
02441 
02442 #include "pixmaps/gdisp_xLogo.xpm"
02443 #include "pixmaps/gdisp_yLogo.xpm"
02444 
02445   static GArray    *p2dDropZones = (GArray*)NULL;
02446 
02447   PlotSystemZone_T  zone;
02448 
02449 
02450   /*
02451    * Allocate and define drop zones.
02452    */
02453   if (p2dDropZones == (GArray*)NULL) {
02454 
02455     p2dDropZones = g_array_new(FALSE, /* zero_terminated */
02456                                TRUE,  /* clear           */
02457                                sizeof(PlotSystemZone_T));
02458 
02459     /* X zone definition */
02460     zone.pszId          = 'X';
02461     zone.pszX[0] = 0.0;  zone.pszX[1] = 1.0;  zone.pszX[2] = 1.0;
02462     zone.pszY[0] = 0.0;  zone.pszY[1] = 0.0;  zone.pszY[2] = 1.0;
02463     zone.pszPointNb     = 3;
02464     zone.pszAcceptDrops = TRUE;
02465     zone.pszComment     = "X";
02466     zone.pszIcon        = gdisp_xLogo;
02467     g_array_append_val(p2dDropZones,zone);
02468 
02469     /* Y zone definition */
02470     zone.pszId          = 'Y';
02471     zone.pszX[0] = 0.0;  zone.pszX[1] = 1.0;  zone.pszX[2] = 0.0;
02472     zone.pszY[0] = 0.0;  zone.pszY[1] = 1.0;  zone.pszY[2] = 1.0;
02473     zone.pszPointNb     = 3;
02474     zone.pszAcceptDrops = TRUE;
02475     zone.pszComment     = "Y";
02476     zone.pszIcon        = gdisp_yLogo;
02477     g_array_append_val(p2dDropZones,zone);
02478 
02479     /* adjust mempry */
02480     p2dDropZones = g_array_set_size(p2dDropZones,
02481                                     2 /* two zones */ );
02482 
02483   }
02484 
02485   /*
02486    * X and Y zones on 2D plots.
02487    */
02488   return p2dDropZones;
02489 
02490 }
02491 
02492 
02493 /*
02494  --------------------------------------------------------------------
02495                              PUBLIC ROUTINES
02496  --------------------------------------------------------------------
02497 */
02498 
02499 
02500 void
02501 gdisp_initPlot2DSystem (Kernel_T     *kernel,
02502                         PlotSystem_T *plotSystem)
02503 {
02504 
02505   gchar *trace = (gchar*)NULL;
02506 
02507   /*
02508    * We must here provide all 'Plot2D' private functions
02509    * that remain 'static' here, but accessible from everywhere
02510    * via the kernel.
02511    */
02512   plotSystem->psCreate            = gdisp_createPlot2D;
02513   plotSystem->psDestroy           = gdisp_destroyPlot2D;
02514   plotSystem->psSetParent         = gdisp_setPlot2DParent;
02515   plotSystem->psGetTopLevelWidget = gdisp_getPlot2DTopLevelWidget;
02516   plotSystem->psShow              = gdisp_showPlot2D;
02517   plotSystem->psGetType           = gdisp_getPlot2DType;
02518   plotSystem->psAddSymbols        = gdisp_addSymbolsToPlot2D;
02519   plotSystem->psGetSymbols        = gdisp_getSymbolsFromPlot2D;
02520   plotSystem->psSetDimensions     = gdisp_setPlot2DInitialDimensions;
02521   plotSystem->psStartStep         = gdisp_startStepOnPlot2D;
02522   plotSystem->psStep              = gdisp_stepOnPlot2D;
02523   plotSystem->psStopStep          = gdisp_stopStepOnPlot2D;
02524   plotSystem->psGetInformation    = gdisp_getPlot2DInformation;
02525   plotSystem->psTreatSymbolValues = gdisp_treatPlot2DSymbolValues;
02526   plotSystem->psGetPeriod         = gdisp_getPlot2DPeriod;
02527   plotSystem->psGetDropZones      = gdisp_getPlot2DDropZones;
02528 
02529   /*
02530    * Manage debug traces.
02531    */
02532   trace = getenv("GDISP_STRACE");
02533   gdispVerbosity = (trace != (gchar*)NULL) ? atoi(trace) : 1;
02534 
02535 }
Framework Home Page.

Beware !! TSP wave is coming...