home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / cdrom / compactplayer / source / cdpanel.c < prev    next >
C/C++ Source or Header  |  1995-12-28  |  18KB  |  764 lines

  1. /****** cdpanel_gc/--datasheet-- ******************************************
  2.  
  3.    NAME
  4.        cdpanel.gadget -- CD front panel
  5.  
  6.    SUPERCLASS
  7.        gadgetclass
  8.  
  9.    DESCRIPTION
  10.  
  11.    METHODS
  12.        GM_DOMAIN
  13.        GM_RENDER
  14.        GM_HITTEST
  15.        GM_GOACTIVE
  16.        GM_GOINACTIVE
  17.        OM_SET
  18.        OM_UPDATE
  19.        OM_GET
  20.        OM_NEW
  21.        OM_DISPOSE
  22.  
  23.        All other methods are passed to the superclass.
  24.  
  25.    ATTRIBUTES
  26.  
  27.    NOTES
  28.  
  29.    SEE ALSO
  30.  
  31. ******************************************************************************
  32.  
  33. */
  34.  
  35. #include "sysheaders.h"
  36. #include "classdata.h"
  37. #include "cdpanel.h"
  38.  
  39. static ULONG new_method( Class *cl, Object *o, struct opSet *ops);
  40. static ULONG dispose_method( Class *cl, Object *o, Msg msg);
  41. static ULONG set_method( Class *cl, Object *o, struct opSet *ops);
  42. static ULONG get_method( Class *cl, Object *o, struct opGet *opg);
  43. static ULONG render_method( Class *cl, Object *o, struct gpRender *gpr);
  44. static ULONG domain_method( Class *cl, Object *o, struct gpDomain *gpd);
  45.  
  46. /* handy macro for handling tag data */
  47. #define SETTAGARG(tag, id, data)    { tag.ti_Tag = (ULONG)(id);\
  48.                       tag.ti_Data = (ULONG)(data); }
  49.  
  50. /* prototype for external function from 'gadgetbox.asm' */
  51. extern __stdargs void SetupGadgetIBox(
  52.                                      struct Gadget *gadget,
  53.                                      struct IBox *domain,
  54.                                      struct IBox *box);
  55.                                          
  56. /* prototype for LayoutClass */
  57. static ULONG __saveds __asm CDPanelDispatch(
  58.                                             register __a0 Class * class,
  59.                                             register __a2 Object * object,
  60.                                             register __a1 Msg message);
  61.  
  62. void Sprintf(char *, const char *, ...);
  63.  
  64. #ifdef __SASC
  65. #pragma msg 181 ign push
  66. static struct ClassLibrary *BevelBase;
  67. #pragma msg 181 pop
  68. #else
  69. static struct ClassLibrary *BevelBase;
  70. #endif
  71.  
  72. ULONG
  73. SendNotify(Object * o, struct GadgetInfo *gi, ULONG flags, Tag t,...)
  74. {
  75.     return DoMethod(o, OM_NOTIFY, &t, gi, flags);
  76. }
  77.  
  78. static ULONG __asm /* no __saveds necessary, this is called through the dispatcher anyway */
  79. tagset(
  80.           register __a0 Class * cl,
  81.           register __a2 Object * o,
  82.           register __a1 struct opSet *ops)
  83. {
  84.     struct CDPanelData *sd = INST_DATA(cl, o);
  85.     register ULONG tidata;
  86.     register BOOL ours;
  87.     BOOL refresh = FALSE;
  88.     struct TagItem *tag;
  89.     struct TagItem *tstate = ops->ops_AttrList;
  90.  
  91.     if (sd)
  92.     {
  93.         while (tag = NextTagItem(&tstate))
  94.         {
  95.             tidata = tag->ti_Data;
  96.             ours = TRUE;
  97.  
  98.             switch (tag->ti_Tag)
  99.             {
  100.                 case CDPANEL_Artist:
  101.                     sd->gad_Data[Artist] = tidata;
  102.                     sd->gad_Old[Artist] = ~0;
  103.                     break;
  104.                     
  105.                 case CDPANEL_Title:
  106.                     sd->gad_Data[Title] = tidata;
  107.                     sd->gad_Old[Title] = ~0;
  108.                     break;
  109.                     
  110.                 case CDPANEL_TrackTitles:
  111.                     sd->gad_TrackTitles = (STRPTR *)tidata;
  112.                     break;
  113.                     
  114.                 case CDPANEL_TotalTime:
  115.                     sd->gad_Data[TotalTime] = tidata;
  116.                     sd->gad_Old[TotalTime] = ~0;
  117.                     break;
  118.                     
  119.                 case CDPANEL_Time:
  120.                     sd->gad_Data[Time] = tidata;
  121.                     sd->gad_Old[Time] = ~0;
  122.                     break;
  123.                     
  124.                 case CDPANEL_Tracks:
  125.                     sd->gad_Data[Tracks] = tidata;
  126.                     sd->gad_Old[Tracks] = ~0;
  127.                     break;
  128.                     
  129.                 case CDPANEL_TrackTimes:
  130.                     sd->gad_TrackTimes = (ULONG *)tidata;
  131.                     break;
  132.                     
  133.                 case CDPANEL_Track:
  134.                     sd->gad_Old[Track] = sd->gad_Data[Track];
  135.                     sd->gad_Data[Track] = tidata;
  136.                     break;
  137.                     
  138.                 case CDPANEL_TrackTime:
  139.                     sd->gad_Data[TrackTime] = tidata;
  140.                     sd->gad_Old[TrackTime] = ~0;
  141.                     break;
  142.                     
  143.                 case CDPANEL_Status:
  144.                     if (tidata == CDP_EMPTY || tidata == CDP_EJECTED)
  145.                     {
  146.                         memset(sd->gad_Data, 0, sizeof(sd->gad_Data));
  147.                         memset(sd->gad_Graph, sd->gad_BgPen, 320);
  148.                     }
  149.                     else
  150.                     if (tidata == CDP_STOPPED && sd->gad_Data[Status] != tidata)
  151.                     {
  152.                         sd->gad_Data[Track] = 0;
  153.                         sd->gad_Data[TrackTime] = 0;
  154.                         sd->gad_Data[Time] = 0;
  155.                         memset(sd->gad_Graph, sd->gad_BgPen, 320);
  156.                     }
  157.                     sd->gad_Data[Status] = tidata;
  158.                 //    sd->gad_Old[Status] = ~0;
  159.                     break;
  160.                     
  161.                 case CDPANEL_BgPen:
  162.                     sd->gad_BgPen = (WORD)tidata;
  163.                     break;
  164.                     
  165.                 case CDPANEL_FgPen:
  166.                     sd->gad_FgPen = (WORD)tidata;
  167.                     break;
  168.                     
  169.                 case CDPANEL_NoBorder:
  170.                     sd->gad_NoBorder = (BOOL)tidata;
  171.                     SetAttrs( sd->gad_BevelFrame, BEVEL_Style, sd->gad_NoBorder ? BVS_NONE : BVS_BUTTON, TAG_END );
  172.                     break;
  173.                     
  174.                 case GA_TextAttr:
  175.                     if (sd->gad_Font)
  176.                         CloseFont(sd->gad_Font);
  177.                     sd->gad_Font = OpenFont((struct TextAttr *)tidata);
  178.                     break;
  179.                     
  180.                 default:
  181.                     ours = FALSE;
  182.                     break;
  183.             }
  184.             if (ours)
  185.                 refresh = TRUE;
  186.         }
  187.         
  188.         if (ops->ops_GInfo && refresh && AttemptLockLayerRom( ops->ops_GInfo->gi_Window->WLayer ) )
  189.         {
  190.             struct RastPort *rp;
  191.             
  192.             UnlockLayerRom( ops->ops_GInfo->gi_Window->WLayer );
  193.     
  194.             if (rp = ObtainGIRPort(ops->ops_GInfo))
  195.             {
  196.                 DoMethod(o, GM_RENDER, ops->ops_GInfo, rp, GREDRAW_UPDATE);
  197.                 ReleaseGIRPort(rp);
  198.                 refresh = FALSE;
  199.             }
  200.         }
  201.     }
  202.     return refresh;
  203. }
  204.  
  205. static void MyFreeBitMap( struct BitMap *bm )
  206. {
  207.     if (!bm)
  208.         return;
  209.  
  210.     if (GfxBase->LibNode.lib_Version >= 39)
  211.     {
  212.         FreeBitMap( bm );
  213.     }
  214.     else
  215.     {
  216.         if (bm->Planes[0])
  217.             FreeRaster( bm->Planes[0], bm->BytesPerRow<<3, bm->Rows * bm->Depth );
  218.         FreeMem( bm, sizeof(struct BitMap) );
  219.     }
  220. }
  221.  
  222. static struct BitMap *MyAllocBitMap( UWORD w, UWORD h, UBYTE d, ULONG f, struct BitMap *fr )
  223. {
  224.     if (GfxBase->LibNode.lib_Version >= 39)
  225.     {
  226.         return AllocBitMap( w, h, d, f, fr );
  227.     }
  228.     else
  229.     {
  230.         ULONG s = (((w+15)>>4)<<4);
  231.         UBYTE *r;
  232.         struct BitMap *bm = AllocMem( sizeof(struct BitMap), MEMF_PUBLIC );
  233.         if (!bm)
  234.             return NULL;
  235.         if (r = AllocRaster(s, h*d))
  236.         {
  237.             UBYTE p;
  238.             bm->BytesPerRow = s>>3;
  239.             bm->Rows = h;
  240.             bm->Depth = d;
  241.             bm->Flags = f;
  242.             if (!(f & BMF_INTERLEAVED))
  243.                 s *= h;
  244.             for (p = 0; p < d; p++)
  245.             {
  246.                 bm->Planes[p] = r;
  247.                 r += s;
  248.             }
  249.             return bm;
  250.         }
  251.         bm->Planes[0] = NULL;
  252.         MyFreeBitMap(bm);
  253.         return NULL;
  254.     }
  255. }
  256.  
  257. static ULONG
  258. new_method(
  259.               Class * cl,
  260.               Object * o,
  261.               struct opSet *ops)
  262. {
  263.     struct CDPanelData *sd;
  264.     Object *object;
  265.  
  266.     object = (Object *) DoSuperMethodA(cl, o, (Msg) ops);
  267.     if (object)
  268.     {
  269.         sd = INST_DATA(cl, object);
  270.  
  271.         if (sd->gad_Graph = AllocVec( 640, MEMF_CHIP ))
  272.         {
  273.             sd->gad_BgPen = 1;
  274.             sd->gad_FgPen = ~0;
  275.  
  276.             memset(sd->gad_Graph, sd->gad_BgPen, 320);
  277.  
  278.             tagset(cl, object, ops);
  279.         
  280.             if (!sd->gad_Font)
  281.                 sd->gad_Font = GfxBase->DefaultFont;
  282.  
  283.             if (sd->gad_BevelFrame = NewObject( BEVEL_GetClass(), NULL, BEVEL_Style, sd->gad_NoBorder ? BVS_NONE : BVS_BUTTON, TAG_END ))
  284.             {
  285.                 return ((ULONG)object);
  286.             }
  287.         }
  288.         CoerceMethod(cl, object, OM_DISPOSE);
  289.     }
  290.     return (0L);
  291. }
  292.  
  293. static ULONG
  294. dispose_method(
  295.                   Class * cl,
  296.                   Object * o,
  297.                   Msg message)
  298. {
  299.     struct CDPanelData *sd = INST_DATA(cl, o);
  300.  
  301.     if (sd->gad_Font != GfxBase->DefaultFont)
  302.         CloseFont( sd->gad_Font );
  303.         
  304.     DisposeObject(sd->gad_BevelFrame);
  305.     
  306.     if (sd->gad_Graph)
  307.         FreeVec(sd->gad_Graph);
  308.         
  309.     MyFreeBitMap(sd->gad_TempBitMap);
  310.  
  311.     return DoSuperMethodA(cl, o, message);
  312. }
  313.  
  314. static ULONG
  315. set_method(
  316.               Class * cl,
  317.               Object * o,
  318.               struct opSet *ops)
  319. {
  320.     register struct TagItem *tstate = ops->ops_AttrList;
  321.  
  322.     if (tstate)
  323.         tagset(cl, o, ops);
  324.  
  325.     DoSuperMethodA(cl, o, (Msg) ops);
  326.     return 0;
  327. }
  328.  
  329. static ULONG
  330. get_method(
  331.               Class * cl,
  332.               Object * o,
  333.               struct opGet *opg)
  334. {
  335.     ULONG retval = TRUE;
  336.     struct CDPanelData *sd = INST_DATA(cl, o);
  337.     
  338.     switch (opg->opg_AttrID)
  339.      {
  340.      case CDPANEL_Status:
  341.          *opg->opg_Storage = sd->gad_Data[Status];
  342.          break;
  343.      
  344.      case CDPANEL_Track:
  345.          *opg->opg_Storage = sd->gad_Data[Track];
  346.          break;
  347.          
  348.      default:
  349.          retval = DoSuperMethodA(cl, o, (Msg) opg);
  350.          break;
  351.      }
  352.     return (retval);
  353. }
  354.  
  355. static ULONG
  356. domain_method(
  357.                  Class * cl,
  358.                  Object * o,
  359.                  struct gpDomain *gpd)
  360. {
  361.     struct CDPanelData *sd = INST_DATA(cl, o);
  362.     ULONG t;
  363.     
  364.     /* GM_DOMAIN is a V42 method for asking a gadget how much space it
  365.      * needs/prefers.
  366.      * This is a fixed size gadget, so we'll always return the same thing.
  367.      */
  368.  
  369.     gpd->gpd_Domain.Left = gpd->gpd_Domain.Top = 0;
  370.     gpd->gpd_Domain.Width = 26 * (sd->gad_Font->tf_XSize) + 2*(2 + 1);
  371.     gpd->gpd_Domain.Height = 3 * (sd->gad_Font->tf_YSize + 1) + 8 + 2*(2 + 1);
  372.  
  373. //    if (!sd->gad_NoBorder)
  374. //    {
  375.         SetAttrs( sd->gad_BevelFrame, 
  376.                     IA_Width, gpd->gpd_Domain.Width, 
  377.                     IA_Height, gpd->gpd_Domain.Height,
  378.                     TAG_END );
  379.         
  380.         GetAttr( BEVEL_InnerWidth, sd->gad_BevelFrame, &t );
  381.         gpd->gpd_Domain.Width += gpd->gpd_Domain.Width - t;
  382.         GetAttr( BEVEL_InnerHeight, sd->gad_BevelFrame, &t );
  383.         gpd->gpd_Domain.Height += gpd->gpd_Domain.Height - t;
  384. //    }
  385.     
  386.     return (0);
  387. }
  388.  
  389. UBYTE IconPlaying[8] =    { 0x40, 0x70, 0x7c, 0x7f, 0x7c, 0x70, 0x40, 0x00 };
  390. UBYTE IconStopped[8] =    { 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00 };
  391. UBYTE IconEjected[8] =    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  392. UBYTE IconPaused[8]  =    { 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00 };
  393. UBYTE IconEmpty[8]   =    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  394. UBYTE IconSeeking[8] =    { 0x38, 0x38, 0x38, 0xfe, 0x7c, 0x38, 0x10, 0x00 };
  395.  
  396. static void
  397. DrawStatusIcon( struct RastPort *rp, UBYTE *icon, UWORD x, UWORD y )
  398. {
  399.     UWORD i,j;
  400.     
  401.     for (j = 0 ; j < 8 ; j++)
  402.     {
  403.         for (i = 0 ; i < 8 ; i++)
  404.         {
  405.             if (icon[j] & (1 << i))
  406.                 WritePixel( rp, x+7-i, y+j);
  407.         }
  408.     }
  409. }
  410.  
  411. static ULONG
  412. render_method(
  413.                  Class * cl,
  414.                  Object * o,
  415.                  struct gpRender *gpr)
  416. {
  417.     struct CDPanelData *sd = INST_DATA(cl, o);
  418.     struct RastPort rpfg = *gpr->gpr_RPort, rpbg = *gpr->gpr_RPort;
  419.     UBYTE line[6];
  420.     ULONG X, Y;
  421.     ULONG *data = sd->gad_Data, *old = sd->gad_Old;
  422.     ULONG baseline = sd->gad_Font->tf_Baseline;
  423.  
  424.     SetAPen( &rpbg, sd->gad_BgPen );
  425.     SetDrMd( &rpbg, JAM2 );
  426.     
  427.     if (gpr->gpr_Redraw == GREDRAW_REDRAW)
  428.     {
  429.         ULONG W, H;
  430. //        struct impDraw id;
  431.  
  432.         SetupGadgetIBox((struct Gadget *) o, &gpr->gpr_GInfo->gi_Domain, &sd->gad_Container);
  433.  
  434.         if (!sd->gad_NoBorder)
  435.         {
  436. #if 0
  437.             id.MethodID = IM_DRAWFRAME;
  438.             id.imp_RPort = &rpfg;
  439.             id.imp_Offset.X = sd->gad_Container.Left;
  440.             id.imp_Offset.Y = sd->gad_Container.Top;
  441.             id.imp_State = IDS_SELECTED;
  442.             id.imp_DrInfo = gpr->gpr_GInfo->gi_DrInfo;
  443.             id.imp_Dimensions.Width = sd->gad_Container.Width;
  444.             id.imp_Dimensions.Height = sd->gad_Container.Height;
  445.             DoMethodA( sd->gad_BevelFrame, (Msg)&id );
  446. #else
  447.             SetAttrs( sd->gad_BevelFrame, 
  448.                     IA_Left, 0, IA_Top, 0,
  449.                     IA_Width, sd->gad_Container.Width, IA_Height, sd->gad_Container.Height,
  450.                     TAG_END );
  451.             DrawImageState( &rpfg, (struct Image *)sd->gad_BevelFrame, sd->gad_Container.Left, sd->gad_Container.Top, IDS_SELECTED, gpr->gpr_GInfo->gi_DrInfo );
  452. #endif
  453.             
  454.             GetAttr( BEVEL_InnerLeft, sd->gad_BevelFrame, &X );
  455.             GetAttr( BEVEL_InnerTop, sd->gad_BevelFrame, &Y );
  456.             GetAttr( BEVEL_InnerWidth, sd->gad_BevelFrame, &W );
  457.             GetAttr( BEVEL_InnerHeight, sd->gad_BevelFrame, &H );
  458.         }
  459.         else
  460.         {
  461.             X = 0;
  462.             Y = 0;
  463.             W = sd->gad_Container.Width;
  464.             H = sd->gad_Container.Height;
  465.         }
  466.         
  467.         X += sd->gad_Container.Left + 1;
  468.         Y += sd->gad_Container.Top + 1;
  469.         W -= 2;
  470.         H -= 2;
  471.         RectFill( &rpbg, X, Y, X + W - 1, Y + H - 1 );
  472.  
  473.         sd->gad_GraphLen = W - 13;
  474.         
  475.         if (sd->gad_GraphLen > 320)
  476.             sd->gad_GraphLen = 320;
  477.         
  478.         MyFreeBitMap( sd->gad_TempBitMap );
  479.         sd->gad_TempBitMap = MyAllocBitMap( sd->gad_GraphLen, 1, 8, 0, NULL );
  480.  
  481.         memset(old, ~0, DATA_MAX * sizeof(ULONG));
  482.     }
  483.     else
  484.     {
  485. //        if (sd->gad_NoBorder)
  486. //        {
  487. //            X = Y = 0;
  488. //        }
  489. //        else
  490. //        {
  491.             GetAttr( BEVEL_InnerLeft, sd->gad_BevelFrame, &X );
  492.             GetAttr( BEVEL_InnerTop, sd->gad_BevelFrame, &Y );
  493. //        }
  494.         
  495.         X += sd->gad_Container.Left + 1;
  496.         Y += sd->gad_Container.Top + 1;
  497.     }
  498.     
  499.     SetAPen( &rpfg, sd->gad_FgPen );
  500.     SetBPen( &rpfg, sd->gad_BgPen );
  501.     SetDrMd( &rpfg, JAM2 );
  502.     SetFont( &rpfg, sd->gad_Font );
  503.     
  504.     X += 2;
  505.     Y += 2;
  506.     
  507.     if (data[Track] != old[Track] || data[Tracks] != old[Tracks])
  508.     {
  509.         /* track count */
  510.         Sprintf( line, "%02.2ld", data[Status] == CDP_STOPPED ? data[Tracks] : data[Track] );
  511.         Move( &rpfg, X, Y + baseline );
  512.         RectFill( &rpbg, X, Y, X + 2 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
  513.         Text( &rpfg, line, 2 /* constant length string */ );
  514.     }
  515.     
  516.     if (data[TrackTime] != old[TrackTime])
  517.     {
  518.         /* playing time on this track */
  519.         Sprintf( line, "%02.2ld:%02.2ld", data[TrackTime]/60, data[TrackTime]%60 );
  520.         Move( &rpfg, X + 3 * (sd->gad_Font->tf_XSize), Y + baseline );
  521.         RectFill( &rpbg, X + 3 * (sd->gad_Font->tf_XSize), Y, X + 8 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
  522.         Text( &rpfg, line, 5 /* constant length string */ );
  523.     }
  524.     
  525.     if (data[Time] != old[Time])
  526.     {
  527.         ULONG time = data[TrackTime];
  528.         
  529.         if (sd->gad_TrackTimes && data[Track])
  530.             time = sd->gad_TrackTimes[data[Track]] - data[Time];
  531.         
  532.         /* remaining time on this track */
  533.         Sprintf( line, "%02.2ld:%02.2ld", time/60, time%60 );
  534.         Move( &rpfg, X + 9 * (sd->gad_Font->tf_XSize), Y + baseline );
  535.         RectFill( &rpbg, X + 9 * (sd->gad_Font->tf_XSize), Y, X + 14 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
  536.         Text( &rpfg, line, 5 /* constant length string */ );
  537.  
  538.         /* playing time from the start of the CD */
  539.         Sprintf( line, "%02.2ld:%02.2ld", data[Time]/60, data[Time]%60 );
  540.         Move( &rpfg, X + 15 * (sd->gad_Font->tf_XSize), Y + baseline );
  541.         RectFill( &rpbg, X + 15 * (sd->gad_Font->tf_XSize), Y, X + 20 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
  542.         Text( &rpfg, line, 5 /* constant length string */ );
  543.     }
  544.     
  545.     if (data[TotalTime] != old[TotalTime])
  546.     {
  547.         /* total length of the CD */
  548.         Sprintf( line, "%02.2ld:%02.2ld", data[TotalTime]/60, data[TotalTime]%60 );
  549.         Move( &rpfg, X + 21 * (sd->gad_Font->tf_XSize), Y + baseline );
  550.         RectFill( &rpbg, X + 21 * (sd->gad_Font->tf_XSize), Y, X + 26 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
  551.         Text( &rpfg, line, 5 /* constant length string */ );
  552.     }
  553.     
  554.     Y += sd->gad_Font->tf_YSize + 1;
  555.     if (data[Artist] != old[Artist])
  556.     {
  557.         /* show artist name */
  558.         ULONG len;
  559.         if (!data[Artist])
  560.             data[Artist] = (ULONG)"CompactPlayer";
  561.         len = strlen((STRPTR)data[Artist]);
  562.         Move( &rpfg, X, Y + baseline );
  563.         RectFill( &rpbg, X, Y, X + 26 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
  564.         Text( &rpfg, (STRPTR)data[Artist], len > 26 ? 26 : len );
  565.     }
  566.     
  567.     /* title */
  568.     Y += sd->gad_Font->tf_YSize + 1;
  569.     if (sd->gad_TrackTitles && data[Track] && data[Track] != old[Track])
  570.     {
  571.         /* show track title */
  572.         ULONG len = strlen(sd->gad_TrackTitles[data[Track]-1]);
  573.         Move( &rpfg, X, Y + baseline );
  574.         RectFill( &rpbg, X, Y, X + 26 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
  575.         Text( &rpfg, sd->gad_TrackTitles[data[Track]-1], len > 26 ? 26 : len );
  576.     }
  577.     else
  578.     if (data[Title] != old[Title] || data[Track] != old[Track])
  579.     {    
  580.         /* show disc title */
  581.         ULONG len;
  582.         if (!data[Title])
  583.             data[Title] = (ULONG)"By Osma Ahvenlampi";
  584.         len = strlen((STRPTR)data[Title]);
  585.         Move( &rpfg, X, Y + baseline );
  586.         RectFill( &rpbg, X, Y, X + 26 * (sd->gad_Font->tf_XSize), Y + sd->gad_Font->tf_YSize );
  587.         Text( &rpfg, (STRPTR)data[Title], len > 26 ? 26 : len );
  588.     }
  589.  
  590.     /* track graph */
  591.     Y += sd->gad_Font->tf_YSize + 1;
  592.     
  593.     if (data[Tracks] != old[Tracks])
  594.     {
  595.         ULONG x = X + /*sd->gad_GraphLen*/ data[TotalTime] * sd->gad_GraphLen / (80*60);
  596.         /* draw the disc time line */
  597.         RectFill( &rpbg, X, Y, X + sd->gad_GraphLen, Y + 6 );
  598.         Move( &rpfg, X, Y + 3 );
  599.         Draw( &rpfg, X, Y + 6 );
  600.         Move( &rpfg, X, Y + 5 );
  601.         Draw( &rpfg, x, Y + 5 );
  602.         Move( &rpfg, x, Y + 3 );
  603.         Draw( &rpfg, x, Y + 6 );
  604.     
  605.         if (sd->gad_TrackTimes)
  606.         {
  607.             /* mark the track limits */
  608.             ULONG i = 0;
  609.             while (i < data[Tracks])
  610.             {    
  611.                 x = X + sd->gad_TrackTimes[i++] * sd->gad_GraphLen / (80*60) /*data[TotalTime]*/;
  612.                 Move( &rpfg, x, Y + 4 );
  613.                 Draw( &rpfg, x, Y + 6 );
  614.             }
  615.         }
  616.     }
  617.  
  618.     if (data[Status] != old[Status])
  619.     {
  620.         /* draw the icon */
  621.         ULONG x = X + sd->gad_GraphLen + 1;
  622.         UBYTE *i;
  623.         RectFill( &rpbg, x, Y, x + 7, Y + 7 );
  624.         
  625.         switch (data[Status])
  626.         {
  627.         case CDP_EMPTY:
  628.             i = IconEmpty;
  629.             break;
  630.         case CDP_PLAYING:
  631.             i = IconPlaying;
  632.             break;
  633.         case CDP_PAUSED:
  634.             i = IconPaused;
  635.             break;
  636.         case CDP_STOPPED:
  637.             i = IconStopped;
  638.             break;
  639.         case CDP_SEEKING:
  640.             i = IconSeeking;
  641.             break;
  642.         case CDP_EJECTED:
  643.             i = IconEjected;
  644.             break;
  645.         }
  646.         DrawStatusIcon( &rpfg, i, x, Y );
  647.     }
  648.     
  649.     if (data[Time] != old[Time] && sd->gad_TempBitMap)
  650.     {
  651.         /* draw the line at current track position */
  652.         ULONG x = data[Time] * sd->gad_GraphLen / (80*60)/*data[TotalTime]*/;
  653.         struct RastPort rp = rpfg;
  654.         
  655.         rp.Layer = NULL;
  656.         rp.BitMap = sd->gad_TempBitMap;
  657.  
  658.         if (data[Status] == CDP_PLAYING || data[Status] == CDP_SEEKING)
  659.         {
  660.             if (data[Track] != old[Track] || data[Time] < old[Time])
  661.                 memset(sd->gad_Graph + x, sd->gad_BgPen, sd->gad_TrackTimes[data[Track]] * sd->gad_GraphLen / (80*60) - x);
  662.  
  663.             sd->gad_Graph[x&0xfffe] = sd->gad_FgPen;
  664.         }
  665.         
  666.         memcpy(sd->gad_Graph + 320, sd->gad_Graph, 320);
  667.         WritePixelLine8(&rpfg, X, Y+2, sd->gad_GraphLen, sd->gad_Graph, &rp);
  668.         memcpy(sd->gad_Graph, sd->gad_Graph + 320, 320);
  669.     }
  670.     
  671.     memcpy(old, data, DATA_MAX * sizeof(ULONG));
  672.     
  673.     return (0);
  674. }
  675.  
  676. static ULONG __saveds __asm
  677. CDPanelDispatch(
  678.                         register __a0 Class * cl,
  679.                         register __a2 Object * o,
  680.                         register __a1 Msg message)
  681. {
  682.     ULONG retval;
  683.     
  684.     switch (message->MethodID)
  685.      {
  686.      case GM_DOMAIN:
  687.          retval = domain_method(cl, o, (struct gpDomain *) message);
  688.          break;
  689.  
  690.      case GM_RENDER:
  691.          retval = render_method(cl, o, (struct gpRender *) message);
  692.          break;
  693.  
  694.      case GM_HITTEST:
  695.          retval = 0;
  696.          break;
  697.  
  698.      case GM_HANDLEINPUT:
  699.      case GM_GOINACTIVE:
  700.      case GM_GOACTIVE:
  701.          retval = GMR_NOREUSE;
  702.          break;
  703.  
  704.      case OM_SET:
  705.      case OM_UPDATE:
  706.          retval = set_method(cl, o, (struct opSet *) message);
  707.          break;
  708.  
  709.      case OM_NEW:
  710.          retval = new_method(cl, o, (struct opSet *) message);
  711.          break;
  712.  
  713.      case OM_DISPOSE:
  714.          retval = dispose_method(cl, o, message);
  715.          break;
  716.  
  717.      case OM_GET:
  718.          retval = get_method(cl, o, (struct opGet *) message);
  719.          break;
  720.          
  721.      default:
  722.          retval = DoSuperMethodA(cl, o, message);
  723.          break;
  724.      }
  725.  
  726.     return (retval);
  727. }
  728.  
  729. /* function to create/initialize our CLASS */
  730. Class *
  731. CreateCDPanelClass(void)
  732. {
  733.     Class *cl;
  734.  
  735.     if (cl = MakeClass( NULL, "gadgetclass", NULL, sizeof(struct CDPanelData), 0))
  736.     {
  737.         cl->cl_Dispatcher.h_Entry = (unsigned long (*)())CDPanelDispatch;
  738.         cl->cl_Dispatcher.h_SubEntry = NULL;
  739.  
  740.         BevelBase = (struct ClassLibrary *) OpenLibrary("images/bevel.image", 0L);
  741.         if (BevelBase)
  742.         {
  743.             return (cl);
  744.         }
  745.         FreeClass( cl );
  746.     }
  747.     return (0);
  748. }
  749.  
  750. void
  751. DestroyCDPanelClass(struct Class * cl)
  752. {
  753.     if (BevelBase)
  754.     {
  755.         CloseLibrary((struct Library *)BevelBase);
  756.         BevelBase = NULL;
  757.     }
  758.     if (cl)
  759.     {
  760.         FreeClass((struct IClass *)cl);
  761.     }
  762. }
  763.  
  764.