home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / C / OTL-MC7.DMS / in.adf / classsource.lha / ClassSource / BOOPSI / popupmenuclass / popupmenuclass.c
Encoding:
C/C++ Source or Header  |  1995-02-12  |  23.3 KB  |  853 lines

  1.  
  2. #include <classes/BOOPSI/popupmenuclass.h>
  3.  
  4. #include <exec/memory.h>
  5. #include <string.h>
  6.  
  7. #pragma -
  8. #include <pragma/utility_lib.h>
  9. #include <clib/alib_protos.h>
  10. #include <pragma/intuition_lib.h>
  11. #include <pragma/graphics_lib.h>
  12. #include <pragma/exec_lib.h>
  13. #include <pragma/layers_lib.h>
  14. #pragma +
  15.  
  16. static struct BitMap *AllocBitMap20(ULONG width, ULONG height, ULONG depth,
  17.             ULONG flags, struct BitMap *like);
  18. static VOID FreeBitMap20(struct BitMap *bitmap);
  19. static struct RastPort *CopyRastPort(struct RastPort *rastport);
  20. static VOID FreeRastPort(struct RastPort *rp);
  21.  
  22. struct InstanceData {
  23.     UWORD active;
  24.     STRPTR *labels;
  25.     struct TextAttr *tattr;
  26.     UWORD maxheight;
  27. // private:
  28.     struct TextFont *font;
  29.     UWORD labelCount;
  30.     UWORD left;      // die Grösse des Menüs
  31.     UWORD top;    // die Gadgetgröße wird nicht überschrieben, damit
  32.     UWORD width;  // die dort angegeben default Werte bestehen bleiben
  33.     UWORD height;
  34.     struct BitMap *save; // Sicherung des Bildschirmausschnitts
  35.     struct RastPort *rastport; // Kopie des Screenrastports zum Zeichnen
  36.     UWORD toplabel; // das oberste sichtbare Label im Menü
  37.     UWORD labelanz; // die Anzahl der sichtbaren Label
  38.     BOOL highlighted; // TRUE : ein Label ist invertiert
  39.     BOOL arrowup; // TRUE : Hochpfeil gezeichnet
  40.     BOOL arrowdown; // TRUE : Runterpfeil gezeichnet
  41.     UWORD lineHeight; // Höhe einer Menüzeile
  42.     BOOL manualActivated; // ohne Benutzeraktion aktiviert
  43. };
  44.  
  45. static struct TextAttr topaz8 = { "topaz.font",8,0,0 };
  46.  
  47. PopupMenuClass::PopupMenuClass()
  48.     : BoopsiClass(sizeof(struct InstanceData),(ULONG (*)()) &dispatcher,GADGETCLASS,NULL)
  49. {
  50. }
  51.  
  52. ULONG PopupMenuClass::dispatcher(Class *cl, Object *o, Msg msg)
  53. {
  54.     struct InstanceData *data;
  55.     ULONG retval = FALSE;
  56.     switch (msg->MethodID)
  57.     {
  58.         case OM_NEW:
  59.         {
  60.             Object *object;
  61.             if (object = (Object *) DoSuperMethodA(cl,o,msg))
  62.             {
  63.                 data = (struct InstanceData *) INST_DATA(cl,object);
  64.                 data->active = 0;
  65.                 data->labels = NULL;
  66.                 data->tattr = NULL;
  67.                 TagItemCursorC tic(((struct opSet *) msg)->ops_AttrList);
  68.                 while (!tic.isDone()) {
  69.                     /* register */ ULONG ticData = tic.itemData();
  70.                     switch (tic.itemTag())
  71.                     {
  72.                         case MA_Active:
  73.                             data->active = (UWORD) ticData;
  74.                             break;
  75.                         case MA_Labels:
  76.                             data->labels = (STRPTR *) ticData;
  77.                             break;
  78.                         case MA_Font:
  79.                             data->tattr = (struct TextAttr *) ticData;
  80.                             break;
  81.                         case MA_MaxHeight:
  82.                             data->maxheight = (UWORD) ticData;
  83.                             break;
  84.                         default:
  85.                             break;
  86.                     };
  87.                     tic.next();
  88.                 };
  89.                 if (data->tattr)
  90.                     data->font = OpenFont(data->tattr)
  91.                 else
  92.                     data->font = OpenFont(&topaz8);
  93.                 data->labelCount = countLabels(data->labels);
  94.                 cutActive(data);
  95.                 retval = (ULONG) object;
  96.             };
  97.             break;
  98.         };
  99.         case OM_DISPOSE:
  100.         {
  101.             data = (struct InstanceData *) INST_DATA(cl,o);
  102.             if (data->font)
  103.                 CloseFont(data->font);
  104.             retval = DoSuperMethodA(cl,o,msg);
  105.             break;
  106.         };
  107.         case OM_GET:
  108.         {
  109.             data = (struct InstanceData *) INST_DATA(cl,o);
  110.             switch (((struct opGet *) msg)->opg_AttrID)
  111.             {
  112.                 case GA_Left:
  113.                     *(((struct opGet *) msg)->opg_Storage) = ((struct Gadget *) o)->LeftEdge;
  114.                     retval = TRUE;
  115.                     break;
  116.                 case GA_Top:
  117.                     *(((struct opGet *) msg)->opg_Storage) = ((struct Gadget *) o)->TopEdge;
  118.                     retval = TRUE;
  119.                     break;
  120.                 case GA_Width:
  121.                     *(((struct opGet *) msg)->opg_Storage) = ((struct Gadget *) o)->Width;
  122.                     retval = TRUE;
  123.                     break;
  124.                 case GA_Height:
  125.                     *(((struct opGet *) msg)->opg_Storage) = ((struct Gadget *) o)->Height;
  126.                     retval = TRUE;
  127.                     break;
  128.                 case MA_Active:
  129.                     *(((struct opGet *) msg)->opg_Storage) = data->active;
  130.                     break;
  131.                 default:
  132.                     retval = DoSuperMethodA(cl,o,msg);
  133.                     break;
  134.             };
  135.             break;
  136.         };
  137.         case OM_SET:
  138.         {
  139.             data = (struct InstanceData *) INST_DATA(cl,o);
  140.             TagItemCursorC tic(((struct opSet *) msg)->ops_AttrList);
  141.             while (!tic.isDone()) {
  142.                 /* register */ ULONG ticData = tic.itemData();
  143.                 switch (tic.itemTag())
  144.                 {
  145.                     case MA_Active:
  146.                         data->active = (UWORD) ticData;
  147.                         break;
  148.                     case MA_Labels:
  149.                         data->labels = (STRPTR *) ticData;
  150.                         data->labelCount = countLabels(data->labels);
  151.                         break;
  152.                     case MA_MaxHeight:
  153.                         data->maxheight = (UWORD) ticData;
  154.                         break;
  155.                     case MA_Font:
  156.                         if (data->font)
  157.                         {
  158.                             CloseFont(data->font);
  159.                             data->font = NULL;
  160.                         };
  161.                         data->tattr = (struct TextAttr *) ticData;
  162.                         if (data->tattr)
  163.                             data->font = OpenFont(data->tattr);
  164.                         break;
  165.                     default:
  166.                         break;
  167.                 };
  168.                 tic.next();
  169.             };
  170.             cutActive(data);
  171.             retval = DoSuperMethodA(cl,o,msg);
  172.             break;
  173.         };
  174.         case GM_RENDER:
  175.         {
  176.             data = (struct InstanceData *) INST_DATA(cl,o);
  177.             retval = renderPopupMenu(cl,(struct Gadget *) o,
  178.                 (struct gpRender *) msg,data);
  179.             break;
  180.         };
  181.         case GM_HITTEST:
  182.         {
  183.             retval = GMR_GADGETHIT;
  184.             break;
  185.         };
  186.         case GM_GOACTIVE:
  187.         {
  188.             data = (struct InstanceData *) INST_DATA(cl,o);
  189.             if (((struct gpInput *) msg)->gpi_IEvent)
  190.             {
  191.                 ((struct Gadget *) msg)->Flags |= GFLG_SELECTED;
  192.                 renderPopupMenu(cl,(struct Gadget *) o,
  193.                     (struct gpRender *) msg,data);
  194.                 struct GadgetInfo *ginfo = ((struct gpInput *) msg)->gpi_GInfo;
  195.                 LockLayers(&ginfo->gi_Screen->LayerInfo);
  196.                 LockLayerInfo(&ginfo->gi_Screen->LayerInfo);
  197.                 InitPopupMenu(data, (struct Gadget *) o, ginfo);
  198.                 data->manualActivated = FALSE;
  199.                 retval = GMR_MEACTIVE;
  200.             }
  201.             else {
  202.                 ((struct Gadget *) msg)->Flags |= GFLG_SELECTED;
  203.                 struct GadgetInfo *ginfo = ((struct gpInput *) msg)->gpi_GInfo;
  204.                 LockLayers(&ginfo->gi_Screen->LayerInfo);
  205.                 LockLayerInfo(&ginfo->gi_Screen->LayerInfo);
  206.                 InitPopupMenu(data, (struct Gadget *) o, ginfo);
  207.                 data->manualActivated = TRUE;
  208.                 retval = GMR_MEACTIVE;
  209.             };
  210.             break;
  211.         };
  212.         case GM_GOINACTIVE:
  213.         {
  214.             data = (struct InstanceData *) INST_DATA(cl,o);
  215.             FinishPopupMenu(data,((struct gpGoInactive *) msg)->gpgi_GInfo);
  216.             UnlockLayerInfo(&((struct gpGoInactive *) msg)->
  217.                 gpgi_GInfo->gi_Screen->LayerInfo);
  218.             UnlockLayers(&((struct gpGoInactive *) msg)->
  219.                 gpgi_GInfo->gi_Screen->LayerInfo);
  220.             ((struct Gadget *) o)->Flags &= ~GFLG_SELECTED;
  221.             if (!data->manualActivated)
  222.             {
  223.                 renderPopupMenu(cl,(struct Gadget *) o,
  224.                     (struct gpRender *) msg,data);
  225.             };
  226.             break;
  227.         };
  228.         case GM_HANDLEINPUT:
  229.         {
  230.             data = (struct InstanceData *) INST_DATA(cl,o);
  231.             struct gpInput *gpi = (struct gpInput *) msg;
  232.             struct InputEvent *ie = gpi->gpi_IEvent;
  233.             WORD mouseX = gpi->gpi_Mouse.X + ((struct Gadget *) o)->LeftEdge;
  234.             if (gpi->gpi_GInfo->gi_Window)
  235.                 mouseX += gpi->gpi_GInfo->gi_Window->LeftEdge;
  236.             WORD mouseY = gpi->gpi_Mouse.Y + ((struct Gadget *) o)->TopEdge;
  237.             if (gpi->gpi_GInfo->gi_Window)
  238.                 mouseY += gpi->gpi_GInfo->gi_Window->TopEdge;
  239.             BOOL mouseOverGadget = (mouseX >= data->left) &&
  240.                 (mouseX < data->left + data->width) &&
  241.                 (mouseY >= data->top) && (mouseY < data->top + data->height);
  242.             if (mouseOverGadget)
  243.             {
  244.                 if (mouseY > data->top+2 && mouseY < data->top + data->height - 2)
  245.                 {
  246.                     UWORD viewline = (mouseY-(data->top+2)) / (data->font->tf_YSize + 2);
  247.                     if    (viewline < data->labelanz)
  248.                     {
  249.                         UWORD active = data->toplabel + viewline;
  250.                         if (active != data->active)
  251.                         {
  252.                             if (data->highlighted)
  253.                                 invertActive(data,gpi->gpi_GInfo);
  254.                             data->active = active;
  255.                             invertActive(data,gpi->gpi_GInfo);
  256.                         };
  257.                     };
  258.                     if (!data->highlighted)
  259.                         invertActive(data,gpi->gpi_GInfo);
  260.                 };
  261.             }
  262.             else {
  263.                 if (data->highlighted)
  264.                     invertActive(data,gpi->gpi_GInfo);
  265.             };
  266.             switch (ie->ie_Class)
  267.             {
  268.                 case IECLASS_RAWMOUSE:
  269.                 {
  270.                     switch (ie->ie_Code)
  271.                     {
  272.                         case SELECTUP:
  273.                             if (mouseOverGadget)
  274.                             {
  275.                                 retval = GMR_NOREUSE | GMR_VERIFY;
  276.                             }
  277.                             else {
  278.                                 retval = GMR_NOREUSE;
  279.                             };
  280.                             break;
  281.                         case MENUDOWN:
  282.                             retval = GMR_REUSE;
  283.                             break;
  284.                         default:
  285. #if 0
  286.                             if (mouseY < data->top + 2 && data->arrowup)
  287.                             {
  288.                                 if (data->highlighted)
  289.                                     invertActive(data,gpi->gpi_GInfo);
  290.                                 if (data->toplabel > 0)
  291.                                     data->toplabel--;
  292.                                 scrollDown(data,gpi->gpi_GInfo);
  293.                                 renderArrowUp(data,gpi->gpi_GInfo);
  294.                                 renderArrowDown(data,gpi->gpi_GInfo);
  295.                             }
  296.                             else if (mouseY > data->top + data->height - 2 && data->arrowdown)
  297.                             {
  298.                                 if (data->highlighted)
  299.                                     invertActive(data,gpi->gpi_GInfo);
  300.                                 if (data->toplabel + data->labelanz < data->labelCount)
  301.                                     data->toplabel++;
  302.                                 scrollUp(data,gpi->gpi_GInfo);
  303.                                 renderArrowUp(data,gpi->gpi_GInfo);
  304.                                 renderArrowDown(data,gpi->gpi_GInfo);
  305.                             };
  306. #endif
  307.                             retval = GMR_MEACTIVE;
  308.                             break;
  309.                     };
  310.                     break;
  311.                 };
  312.                 case IECLASS_TIMER:
  313.                 {
  314.                     if (mouseY < data->top + 2 && data->arrowup)
  315.                     {
  316.                         if (data->highlighted)
  317.                             invertActive(data,gpi->gpi_GInfo);
  318.                         if (data->toplabel > 0)
  319.                             data->toplabel--;
  320.                         scrollDown(data,gpi->gpi_GInfo);
  321.                         renderArrowUp(data,gpi->gpi_GInfo);
  322.                         renderArrowDown(data,gpi->gpi_GInfo);
  323.                     }
  324.                     else if (mouseY > data->top + data->height - 2 && data->arrowdown)
  325.                     {
  326.                         if (data->highlighted)
  327.                             invertActive(data,gpi->gpi_GInfo);
  328.                         if (data->toplabel + data->labelanz < data->labelCount)
  329.                             data->toplabel++;
  330.                         scrollUp(data,gpi->gpi_GInfo);
  331.                         renderArrowUp(data,gpi->gpi_GInfo);
  332.                         renderArrowDown(data,gpi->gpi_GInfo);
  333.                     };
  334.                     break;
  335.                 };
  336.                 default:
  337.                     retval = GMR_MEACTIVE;
  338.                     break;
  339.             };
  340.             break;
  341.         };
  342.         default:
  343.         {
  344.             retval = DoSuperMethodA(cl,o,msg);
  345.             break;
  346.         };
  347.     };
  348.     return retval;
  349. }
  350.  
  351. ULONG PopupMenuClass::renderPopupMenu(Class *cl, struct Gadget *g,
  352.     struct gpRender *msg, struct InstanceData *data)
  353. {
  354.     struct RastPort *rp;
  355.     struct GadgetInfo *ginfo;
  356.     if (msg->MethodID == OM_SET)
  357.         ginfo = ((struct opSet *) msg)->ops_GInfo
  358.     else
  359.         ginfo = msg->gpr_GInfo;
  360.     UWORD *pens = ginfo->gi_DrInfo->dri_Pens;
  361.     if (msg->MethodID == GM_RENDER)
  362.         rp = msg->gpr_RPort
  363.     else
  364.         rp = ObtainGIRPort(ginfo);
  365.     if (rp)
  366.     {
  367.         SetAPen(rp,pens[BACKGROUNDPEN]);
  368.         SetDrMd(rp,JAM1);
  369.         RectFill(rp,g->LeftEdge,g->TopEdge,g->LeftEdge+g->Width-1,
  370.             g->TopEdge+g->Height-1);
  371.         SetAPen(rp,pens[SHINEPEN]);
  372.         Move(rp,g->LeftEdge,g->TopEdge+g->Height-1);
  373.         Draw(rp,g->LeftEdge,g->TopEdge);
  374.         Draw(rp,g->LeftEdge+g->Width-1,g->TopEdge);
  375.         SetAPen(rp,pens[SHADOWPEN]);
  376.         Draw(rp,g->LeftEdge+g->Width-1,g->TopEdge+g->Height-1);
  377.         Draw(rp,g->LeftEdge,g->TopEdge+g->Height-1);
  378.         UWORD textwidth = g->Width - 4;
  379.         if (data->labels)
  380.         {
  381.             STRPTR label = data->labels[data->active];
  382.             if (label)
  383.             {
  384.                 TextExtent extent;
  385.                 SetFont(rp,data->font);
  386.                 ULONG c = TextFit(rp,label,strlen(label),&extent,NULL,1,
  387.                     textwidth,g->Height);
  388.                 if (c > 0)
  389.                 {
  390.                     SetAPen(rp,pens[TEXTPEN]);
  391.                     Move(rp,g->LeftEdge + 2 + extent.te_Extent.MinX +
  392.                         ((textwidth - extent.te_Extent.MinX - extent.te_Width) >> 1),
  393.                         g->TopEdge + ((g->Height - extent.te_Height) >> 1) -
  394.                             extent.te_Extent.MinY);
  395.                     Text(rp,label,c);
  396.                 };
  397.             };
  398.         };
  399.  
  400.         if (msg->MethodID != GM_RENDER)
  401.             ReleaseGIRPort(rp);
  402.         return TRUE;
  403.     };
  404.     return FALSE;
  405. }
  406.  
  407. UWORD PopupMenuClass::countLabels(STRPTR *labels)
  408. {
  409.     if (labels)
  410.     {
  411.         UWORD i = 0;
  412.         while (labels[i])
  413.             i++;
  414.         return i;
  415.     };
  416.     return 0;
  417. }
  418.  
  419. VOID PopupMenuClass::cutActive(struct InstanceData *data)
  420. {
  421.     if (data->active > data->labelCount)
  422.     {
  423.         data->active = 0;
  424.     }
  425. }
  426.  
  427. BOOL PopupMenuClass::InitPopupMenu(struct InstanceData *data, struct Gadget *g,
  428.             struct GadgetInfo *ginfo)
  429. {
  430.     UWORD lineHeight = data->font->tf_YSize + 2;
  431.     data->lineHeight = lineHeight;
  432.  
  433.     // Größe des Menüs bestimmen
  434.     ULONG height = data->labelCount * lineHeight + 4;
  435.     if (height > ginfo->gi_Screen->Height)
  436.         height = ginfo->gi_Screen->Height;
  437.     if (data->maxheight >= 2*lineHeight + 4 && height > data->maxheight)
  438.         height = data->maxheight;
  439.     UWORD width = g->Width;
  440.     if (width > ginfo->gi_Screen->Width)
  441.         width = ginfo->gi_Screen->Width;
  442.  
  443.     // Anzahl der Labels im Menü
  444.     data->labelanz = (height - 4) / lineHeight;
  445.     if (data->labelanz > data->labelCount)
  446.         data->labelanz = data->labelCount;
  447.  
  448.     // oberstes Label bestimmen
  449.     WORD toplabel = data->active - (data->labelanz >> 1);
  450.     if (toplabel < 0)
  451.         toplabel = 0;
  452.     if (toplabel + data->labelanz > data->labelCount)
  453.         toplabel = data->labelCount - data->labelanz;
  454.     data->toplabel = toplabel;
  455.  
  456.     // Position des Meüs bestimmen
  457.     WORD left = g->LeftEdge;
  458.     if (ginfo->gi_Window)
  459.         left += ginfo->gi_Window->LeftEdge;
  460.     if (left < 0)
  461.         left = 0
  462.     else if (left+width > ginfo->gi_Screen->Width)
  463.         left = ginfo->gi_Screen->Width - width;
  464.  
  465.     UWORD gadgettop = g->TopEdge;
  466.     if (ginfo->gi_Window)
  467.         gadgettop += ginfo->gi_Window->TopEdge;
  468.     WORD top = gadgettop - (data->active - data->toplabel) * lineHeight;
  469.     if (top < 0)
  470.         top = 0
  471.     else if (top+height > ginfo->gi_Screen->Height)
  472.         top = ginfo->gi_Screen->Height - height;
  473.     data->left = left;
  474.     data->top = top;
  475.     data->width = width;
  476.     data->height = height;
  477.  
  478.     // Menü darstellen
  479.     if (!(data->save = AllocBitMap20(width,height,
  480.         ginfo->gi_Screen->BitMap.Depth,0,&ginfo->gi_Screen->BitMap)))
  481.     {
  482.         return FALSE;
  483.     };
  484.     data->rastport = CopyRastPort(&ginfo->gi_Screen->RastPort);
  485.     BltBitMap(&ginfo->gi_Screen->BitMap,left,top,data->save,0,0,
  486.         width,height,0xc0,0xff,NULL);
  487.     data->highlighted = FALSE;
  488.     data->arrowup = FALSE;
  489.     data->arrowdown = FALSE;
  490.     renderPopupMenuFrame(data->rastport,left,top,width,height,
  491.         ginfo->gi_DrInfo->dri_Pens);
  492.     renderLabels(data,ginfo);
  493.     invertActive(data,ginfo);
  494.     renderArrowUp(data,ginfo);
  495.     renderArrowDown(data,ginfo);
  496.     return TRUE;
  497. }
  498.  
  499. VOID PopupMenuClass::FinishPopupMenu(struct InstanceData *data,
  500.     struct GadgetInfo *ginfo)
  501. {
  502.     if (data->save)
  503.     {
  504.         BltBitMap(data->save,0,0,&ginfo->gi_Screen->BitMap,data->left,data->top,
  505.             data->width,data->height,0xc0,0xff,NULL);
  506.         WaitBlit();
  507.         FreeBitMap20(data->save);
  508.     };
  509.     FreeRastPort(data->rastport);
  510. }
  511.  
  512. VOID PopupMenuClass::renderLabels(struct InstanceData *data,
  513.     struct GadgetInfo *ginfo)
  514. {
  515.     if (data->labels)
  516.     {
  517.         UWORD textwidth = data->width - 16;
  518.         UWORD top = data->top + 2;
  519.         UWORD left = data->left + 2;
  520.         int i;
  521.         for (i = data->toplabel; i < data->toplabel + data->labelanz; i++) {
  522.             STRPTR label = data->labels[i];
  523.             if (label)
  524.             {
  525.                 TextExtent extent;
  526.                 SetFont(data->rastport,data->font);
  527.                 ULONG c = TextFit(data->rastport,label,strlen(label),
  528.                     &extent,NULL,1,textwidth,data->lineHeight);
  529.                 if (c > 0)
  530.                 {
  531.                     SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[TEXTPEN]);
  532.                     SetBPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
  533.                     SetDrMd(data->rastport,JAM2);
  534.                     Move(data->rastport,left+extent.te_Extent.MinX +
  535.                         ((textwidth - extent.te_Extent.MinX - extent.te_Width) >> 1),
  536.                         top - extent.te_Extent.MinY);
  537.                     Text(data->rastport,label,c);
  538.                 };
  539.             }
  540.             else {
  541.                 return;
  542.             };
  543.             top += data->lineHeight;
  544.         };
  545.     };
  546. }
  547.  
  548. VOID PopupMenuClass::invertActive(struct InstanceData *data,
  549.     struct GadgetInfo *ginfo)
  550. {
  551.     if (data->active >= data->toplabel &&
  552.         data->active < data->toplabel+data->labelanz)
  553.     {
  554.         if (data->labels)
  555.         {
  556.             UWORD textwidth = data->width - 16;
  557.             UWORD top = data->top + 2 +
  558.                 (data->active - data->toplabel)*data->lineHeight;
  559.             UWORD left = data->left + 2;
  560.             STRPTR label = data->labels[data->active];
  561.             if (label)
  562.             {
  563.                 TextExtent extent;
  564.                 SetFont(data->rastport,data->font);
  565.                 ULONG c = TextFit(data->rastport,label,strlen(label),
  566.                     &extent,NULL,1,textwidth,data->lineHeight);
  567.                 if (c > 0)
  568.                 {
  569.                     UWORD textleft = left + extent.te_Extent.MinX +
  570.                         ((textwidth - extent.te_Extent.MinX - extent.te_Width) >> 1);
  571. #if 0
  572.                     SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[TEXTPEN]);
  573.                     SetBPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
  574.                     if (!data->highlighted)
  575.                     {
  576.                         SetDrMd(data->rastport,JAM2);
  577.                         RectFill(data->rastport,left,top,
  578.                             textleft - 1,top + data->lineHeight - 1);
  579.                         RectFill(data->rastport,textleft + extent.te_Width,top,
  580.                             left + textwidth - 1,top + data->lineHeight - 1);
  581.                         SetDrMd(data->rastport,JAM2|INVERSVID);
  582.                         Move(data->rastport,textleft,top - extent.te_Extent.MinY);
  583.                         Text(data->rastport,label,c);
  584.                     }
  585.                     else {
  586.                         SetDrMd(data->rastport,JAM2|INVERSVID);
  587.                         RectFill(data->rastport,left,top,
  588.                             textleft - 1,top + data->lineHeight - 1);
  589.                         RectFill(data->rastport,textleft + extent.te_Width,top,
  590.                             left + textwidth - 1,top + data->lineHeight - 1);
  591.                         SetDrMd(data->rastport,JAM2);
  592.                         Move(data->rastport,textleft,top - extent.te_Extent.MinY);
  593.                         Text(data->rastport,label,c);
  594.                     };
  595. #else
  596.                     if (!data->highlighted)
  597.                     {
  598.                         SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[TEXTPEN]);
  599.                         SetDrMd(data->rastport,JAM1);
  600.                         RectFill(data->rastport,left,top,
  601.                             left + textwidth - 1,top + data->lineHeight - 1);
  602.                         SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
  603.                         Move(data->rastport,textleft,top - extent.te_Extent.MinY);
  604.                         Text(data->rastport,label,c);
  605.                     }
  606.                     else {
  607.                         SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
  608.                         SetDrMd(data->rastport,JAM1);
  609.                         RectFill(data->rastport,left,top,
  610.                             left + textwidth - 1,top + data->lineHeight - 1);
  611.                         SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[TEXTPEN]);
  612.                         Move(data->rastport,textleft,top - extent.te_Extent.MinY);
  613.                         Text(data->rastport,label,c);
  614.                     };
  615. #endif
  616.                 }
  617.                 else {
  618.                     SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[TEXTPEN]);
  619.                     SetBPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
  620.                     if (!data->highlighted)
  621.                         SetDrMd(data->rastport,JAM2)
  622.                     else
  623.                         SetDrMd(data->rastport,JAM2|INVERSVID);
  624.                     RectFill(data->rastport,left,top,
  625.                         left + textwidth - 1,top + data->lineHeight - 1);
  626.                 };
  627.             };
  628.         };
  629.         data->highlighted = !data->highlighted;
  630.     };
  631. }
  632.  
  633. VOID PopupMenuClass::renderArrowUp(struct InstanceData *data,
  634.     struct GadgetInfo *ginfo)
  635. {
  636.     if (data->toplabel > 0)
  637.     {
  638.         if (!data->arrowup)
  639.         {
  640.             UWORD left = data->left + data->width - 12;
  641.             UWORD top = data->top + 2;
  642.             SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[SHADOWPEN]);
  643.             SetDrMd(data->rastport,JAM1);
  644.             WritePixel(data->rastport,left+4,top);
  645.             Move(data->rastport,left+3,top+1);
  646.             Draw(data->rastport,left+5,top+1);
  647.             Move(data->rastport,left+2,top+2);
  648.             Draw(data->rastport,left+6,top+2);
  649.             Move(data->rastport,left+1,top+3);
  650.             Draw(data->rastport,left+7,top+3);
  651.             Move(data->rastport,left+0,top+4);
  652.             Draw(data->rastport,left+8,top+4);
  653.             data->arrowup = TRUE;
  654.         };
  655.     }
  656.     else {
  657.         if (data->arrowup)
  658.         {
  659.             UWORD left = data->left + data->width - 12;
  660.             UWORD top = data->top + 2;
  661.             SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
  662.             SetDrMd(data->rastport,JAM1);
  663.             RectFill(data->rastport,left,top,left+9,top+5);
  664.             data->arrowup = FALSE;
  665.         };
  666.     };
  667. }
  668.  
  669. VOID PopupMenuClass::renderArrowDown(struct InstanceData *data,
  670.     struct GadgetInfo *ginfo)
  671. {
  672.     if (data->toplabel + data->labelanz < data->labelCount)
  673.     {
  674.         if (!data->arrowdown)
  675.         {
  676.             UWORD left = data->left + data->width - 12;
  677.             UWORD top = data->top + data->height - 7;
  678.             SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[SHADOWPEN]);
  679.             SetDrMd(data->rastport,JAM1);
  680.             WritePixel(data->rastport,left+4,top+4);
  681.             Move(data->rastport,left+3,top+3);
  682.             Draw(data->rastport,left+5,top+3);
  683.             Move(data->rastport,left+2,top+2);
  684.             Draw(data->rastport,left+6,top+2);
  685.             Move(data->rastport,left+1,top+1);
  686.             Draw(data->rastport,left+7,top+1);
  687.             Move(data->rastport,left+0,top);
  688.             Draw(data->rastport,left+8,top);
  689.             data->arrowdown = TRUE;
  690.         };
  691.     }
  692.     else {
  693.         if (data->arrowdown)
  694.         {
  695.             UWORD left = data->left + data->width - 12;
  696.             UWORD top = data->top + data->height - 7;
  697.             SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
  698.             SetDrMd(data->rastport,JAM1);
  699.             RectFill(data->rastport,left,top,left+9,top+5);
  700.             data->arrowdown = FALSE;
  701.         };
  702.     };
  703. }
  704.  
  705. VOID PopupMenuClass::scrollUp(struct InstanceData *data,
  706.         struct GadgetInfo *ginfo)
  707. {
  708.     SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
  709.     SetDrMd(data->rastport,JAM1);
  710.     ScrollRaster(data->rastport,0,data->lineHeight,data->left + 2,data->top + 2,
  711.         data->left + data->width - 13,
  712.         data->top + 1 + data->labelanz*data->lineHeight);
  713.     if (data->labels)
  714.     {
  715.         UWORD textwidth = data->width - 16;
  716.         UWORD top = data->top + 2 + (data->labelanz-1)*data->lineHeight;
  717.         UWORD left = data->left + 2;
  718.         STRPTR label = data->labels[data->toplabel+data->labelanz-1];
  719.         if (label)
  720.         {
  721.             TextExtent extent;
  722.             SetFont(data->rastport,data->font);
  723.             ULONG c = TextFit(data->rastport,label,strlen(label),
  724.                 &extent,NULL,1,textwidth,data->lineHeight);
  725.             if (c > 0)
  726.             {
  727.                 SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[TEXTPEN]);
  728.                 SetBPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
  729.                 SetDrMd(data->rastport,JAM2);
  730.                 Move(data->rastport,left+extent.te_Extent.MinX +
  731.                     ((textwidth - extent.te_Extent.MinX - extent.te_Width) >> 1),
  732.                     top - extent.te_Extent.MinY);
  733.                 Text(data->rastport,label,c);
  734.             };
  735.         };
  736.     };
  737. }
  738.  
  739. VOID PopupMenuClass::scrollDown(struct InstanceData *data,
  740.         struct GadgetInfo *ginfo)
  741. {
  742.     SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
  743.     SetDrMd(data->rastport,JAM1);
  744.     ScrollRaster(data->rastport,0,-data->lineHeight,data->left + 2,data->top + 2,
  745.         data->left + data->width - 13,
  746.         data->top + 1 + data->labelanz*data->lineHeight);
  747.     if (data->labels)
  748.     {
  749.         UWORD textwidth = data->width - 16;
  750.         UWORD top = data->top + 2;
  751.         UWORD left = data->left + 2;
  752.         STRPTR label = data->labels[data->toplabel];
  753.         if (label)
  754.         {
  755.             TextExtent extent;
  756.             SetFont(data->rastport,data->font);
  757.             ULONG c = TextFit(data->rastport,label,strlen(label),
  758.                 &extent,NULL,1,textwidth,data->lineHeight);
  759.             if (c > 0)
  760.             {
  761.                 SetAPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[TEXTPEN]);
  762.                 SetBPen(data->rastport,ginfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
  763.                 SetDrMd(data->rastport,JAM2);
  764.                 Move(data->rastport,left+extent.te_Extent.MinX +
  765.                     ((textwidth - extent.te_Extent.MinX - extent.te_Width) >> 1),
  766.                     top - extent.te_Extent.MinY);
  767.                 Text(data->rastport,label,c);
  768.             };
  769.         };
  770.     };
  771. }
  772.  
  773. VOID PopupMenuClass::renderPopupMenuFrame(struct RastPort *rp, UWORD left, UWORD top,
  774.             UWORD width, UWORD height, UWORD *pens)
  775. {
  776.     if (rp)
  777.     {
  778.         SetAPen(rp,pens[BACKGROUNDPEN]);
  779.         SetDrMd(rp,JAM1);
  780.         RectFill(rp,left,top,left+width-1,top+height-1);
  781.         SetAPen(rp,pens[SHINEPEN]);
  782.         Move(rp,left,top+height-1);
  783.         Draw(rp,left,top);
  784.         Draw(rp,left+width-1,top);
  785.         SetAPen(rp,pens[SHADOWPEN]);
  786.         Draw(rp,left+width-1,top+height-1);
  787.         Draw(rp,left,top+height-1);
  788.     };
  789. }
  790.  
  791. // *************************************************************
  792.  
  793. PopupMenuClass BPopupMenuC::pmc;
  794.  
  795. // *************************************************************
  796.  
  797. struct BitMap *AllocBitMap20(ULONG width, ULONG height, ULONG depth,
  798.                         ULONG flags, struct BitMap *like)
  799. {
  800.     struct BitMap *bm = (struct BitMap *) AllocMem(sizeof(struct BitMap),MEMF_CLEAR);
  801.     if (bm)
  802.     {
  803.         InitBitMap(bm,depth,width,height);
  804.         UWORD i;
  805.         BOOL failed = FALSE;
  806.         for (i = 0; i < depth; i++) {
  807.             if (!(bm->Planes[i] = AllocRaster(width,height)))
  808.                 failed = TRUE;
  809.         };
  810.         if (failed)
  811.         {
  812.             FreeBitMap20(bm);
  813.             bm = NULL;
  814.         };
  815.     };
  816.     return bm;
  817. }
  818.  
  819. VOID FreeBitMap20(struct BitMap *bm)
  820. {
  821.     if (bm)
  822.     {
  823.         UWORD depth = bm->Depth;
  824.         UWORD height = bm->Rows;
  825.         UWORD width = bm->BytesPerRow << 3;
  826.         int i;
  827.         for (i = 0; i < depth; i++) {
  828.             if (bm->Planes[i])
  829.                 FreeRaster(bm->Planes[i],width,height);
  830.         };
  831.         FreeMem(bm,sizeof(struct BitMap));
  832.     };
  833. }
  834.  
  835. struct RastPort *CopyRastPort(struct RastPort *rastport)
  836. {
  837.     struct RastPort *rp;
  838.     if (rp = (struct RastPort *) AllocMem(sizeof(struct RastPort),0))
  839.     {
  840.         memcpy(rp,rastport,sizeof(struct RastPort));
  841.     };
  842.     return rp;
  843. }
  844.  
  845. VOID FreeRastPort(struct RastPort *rp)
  846. {
  847.     if (rp)
  848.     {
  849.         FreeMem(rp,sizeof(struct RastPort));
  850.     };
  851. }
  852.  
  853.