Initial commit.
[amiga/xmodule.git] / Gadgets / SampEditClass.c
1 /*
2 **      SampEditClass.c
3 **
4 **      Copyright (C) 1995,96 Bernardo Innocenti
5 **
6 **      Sample editor class built on top of the "gadgetclass".
7 */
8
9 #include <string.h>
10
11 #include <exec/types.h>
12 #include <exec/memory.h>
13 #include <exec/nodes.h>
14 #include <exec/ports.h>
15 #include <utility/tagitem.h>
16 #include <utility/hooks.h>
17 #include <devices/inputevent.h>
18 #include <intuition/intuition.h>
19 #include <intuition/intuitionbase.h>
20 #include <intuition/classes.h>
21 #include <intuition/classusr.h>
22 #include <intuition/gadgetclass.h>
23 #include <intuition/imageclass.h>
24 #include <graphics/gfxbase.h>
25 #include <graphics/gfxmacros.h>
26 #include <graphics/text.h>
27 #include <libraries/songclass.h>
28 #include <libraries/sampeditclass.h>
29
30 #include <clib/exec_protos.h>
31 #include <clib/intuition_protos.h>
32 #include <clib/graphics_protos.h>
33 #include <clib/utility_protos.h>
34 #include <clib/alib_protos.h>
35
36 #include <pragmas/exec_sysbase_pragmas.h>
37 #include <pragmas/intuition_pragmas.h>
38 #include <pragmas/graphics_pragmas.h>
39 #include <pragmas/utility_pragmas.h>
40
41
42 /* Some handy definitions missing in <devices/inputevent.h> */
43 #define IEQUALIFIER_SHIFT       (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)
44 #define IEQUALIFIER_ALT         (IEQUALIFIER_LALT | IEQUALIFIER_RALT)
45 #define IEQUALIFIER_COMMAND     (IEQUALIFIER_LCOMMAND | IEQUALIFIER_RCOMMAND)
46
47 /* Scrolling control */
48 #define SCROLLED_VERT   1
49 #define SCROLLED_HORIZ  2
50
51
52
53 struct SampEditData
54 {
55         struct Instrument       *Instr;
56
57         /* These are the actual Gadget position and size,
58          * regardless of any GREL_#? flags.
59          */
60         struct IBox              GBounds;
61
62         ULONG                    Flags;                 /* See definitions in <SampEditClass.h>                 */
63
64         UWORD                    XStart;                /* X offset from the beginning of the sample    */
65         UWORD                    XVisible;              /* Number of visible samples                                    */
66
67         UWORD                    CursState;
68         UWORD                    CursX;                 /* Cursor position (which sample)                               */
69         UWORD                    CursScrPosX;   /* Screen cursor position to erase it quickly.  */
70
71         UWORD                    Pad0;
72
73         UWORD                    BackupCursX;   /* Cursor drag undo */
74         UWORD                    BackupXStart;
75
76         ULONG                    XRatio;                        /* X Zoom ratio, 16:16 bit fixed point number   */
77
78         /* Range marking info */
79         UWORD                    RangeStartX;
80         UWORD                    RangeStartY;
81         UWORD                    RangeEndX;
82         UWORD                    RangeEndY;
83
84         struct Rectangle RangeRect;             /* Backup of range rect to erase it quickly. */
85
86         /* Rendering routine for the sample. */
87         void                    (*RenderFunc)(struct Note *note, UBYTE *s);
88
89         /* Pens used to draw various gadget elements */
90         ULONG                    BackgroundPen;
91         ULONG                    LinePen;
92         ULONG                    FillPen;
93         ULONG                    GridPen;
94
95
96         /* For double click test */
97         ULONG                    DoubleClickSeconds;
98         ULONG                    DoubleClickMicros;
99 };
100
101
102
103
104 /* Function prototypes */
105
106 static ULONG __asm SampEditDispatcher (register __a0 Class *cl,
107                                                                 register __a2 struct ExtGadget *g,
108                                                                 register __a1 Msg msg);
109 static ULONG    SAMP_HandleInputMethod  (Class *cl, struct ExtGadget *g, struct gpInput *msg);
110 static void             SAMP_RenderMethod       (Class *cl, struct ExtGadget *g, struct gpRender *msg);
111 static ULONG    SAMP_SetMethod          (Class *cl, struct ExtGadget *g, struct opSet *msg);
112 static ULONG    SAMP_GetMethod          (Class *cl, struct ExtGadget *g, struct opGet *msg);
113 static ULONG    SAMP_NewMethod          (Class *cl, struct ExtGadget *g, struct opSet *msg);
114
115 static void             GetGadgetBox    (struct GadgetInfo *ginfo, struct ExtGadget *g, struct IBox *rect);
116 static BOOL             CalcDisplaySize (struct SampEditData *sed, struct ExtGadget *g, struct GadgetInfo *gpi);
117 static void             SaveUndo                (struct SampEditData *sed);
118 static BOOL             UndoChange              (struct SampEditData *sed);
119 static BOOL             RedoChange              (struct SampEditData *sed);
120 static void             FreeUndoBuffers (struct SampEditData *sed, BOOL freeall);
121 static BOOL             MoveCursor              (struct SampEditData *sed, WORD x /*, WORD y*/);
122 static void             EraseCursor             (struct RastPort *rp, struct SampEditData *sed);
123 static UWORD    DrawCursor              (struct RastPort *rp, struct SampEditData *sed, struct ExtGadget *g);
124 static void             DrawRange               (struct RastPort *rp, struct SampEditData *sed);
125 static void             ClearRange              (struct RastPort *rp, struct SampEditData *sed);
126 static void             RedrawAll               (struct RastPort *rp, struct SampEditData *sed, struct ExtGadget *g);
127 static void             RedrawSample    (struct RastPort *rp, struct SampEditData *sed, struct ExtGadget *g);
128 static void             DrawGrid                (struct RastPort *rp, struct SampEditData *sed, UWORD min, UWORD max);
129 static UWORD    ScrollDisplay   (struct RastPort *rp, struct SampEditData *sed, struct ExtGadget *g,
130                                                                 UWORD lefttrack, UWORD topline);
131 static void             NotifyCursor    (struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags);
132 static void             NotifyHSlider   (struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags);
133
134 //static void __asm TimerIntServer (register __a1 struct Gadget *g);
135
136 struct Library * __asm  _UserLibInit    (register __a6 struct Library *mybase);
137 struct Library * __asm  _UserLibCleanup (register __a6 struct Library *mybase);
138 struct IClass * __asm   _GetClass               (register __a6 struct Library *mybase);
139
140
141
142 /* Library data */
143
144 #ifdef _M68020
145 #define SAMPVERS "_020"
146 #else
147 #define SAMPVERS ""
148 #endif
149
150 const UBYTE LibName[] = "sampedit.gadget";
151 const UBYTE LibVer[] = { '$', 'V', 'E', 'R', ':', ' ' };
152 const UBYTE LibId[] = "sampedit.gadget" SAMPVERS " 1.1 (5.5.96) © 1995,96 by Bernardo Innocenti";
153
154
155
156
157 /*****************/
158 /* Library bases */
159 /*****************/
160
161 /* Get around a SAS/C bug which causes some annoying warnings
162  * with the library bases defined below.
163  */
164 #ifdef __SASC
165 #pragma msg 72 ignore push
166 #endif /* __SASC */
167
168 struct ExecBase                 *SysBase                = NULL;
169 struct IntuitionBase    *IntuitionBase  = NULL;
170 struct GfxBase                  *GfxBase                = NULL;
171 struct Library                  *UtilityBase    = NULL;
172
173 #ifdef __SASC
174 #pragma msg 72 pop
175 #endif /* __SASC */
176
177 static struct IClass    *SampEditClass  = NULL;
178
179
180 static ULONG __asm SampEditDispatcher (register __a0 Class *cl,
181                                                                                 register __a2 struct ExtGadget *g,
182                                                                                 register __a1 Msg msg)
183
184 /* SampEdit Class Dispatcher entrypoint.
185  * Handle BOOPSI messages.
186  */
187 {
188         switch (msg->MethodID)
189         {
190                 case GM_GOACTIVE:
191                         return SAMP_HandleInputMethod (cl, g, (struct gpInput *)msg);
192
193
194                 case GM_RENDER:
195                         SAMP_RenderMethod (cl, g, (struct gpRender *)msg);
196                         return 0;
197
198                 case GM_LAYOUT:
199                 {
200                         struct SampEditData *sed = INST_DATA (cl, g);
201
202                         if (CalcDisplaySize (sed, g, ((struct gpLayout *)msg)->gpl_GInfo))
203                                 NotifyHSlider (g, ((struct gpLayout *)msg)->gpl_GInfo, 0);
204
205                         return 0;
206                 }
207
208                 case OM_SET:
209                 case OM_UPDATE:
210                         return SAMP_SetMethod (cl, g, (struct opSet *)msg);
211
212                 case OM_GET:
213                         return SAMP_GetMethod (cl, g, (struct opGet *)msg);
214
215                 case OM_NEW:
216                         return (ULONG) SAMP_NewMethod (cl, g, (struct opSet *)msg);
217
218                 case OM_DISPOSE:
219                         /* NOTE: I'm falling through here! */
220
221                 default:
222
223                         /* Unsupported method: let our superclass's
224                          * dispatcher take a look at it.
225                          */
226                         return DoSuperMethodA (cl, (Object *)g, msg);
227         }
228 }
229
230
231
232 static ULONG SAMP_HandleInputMethod (Class *cl, struct ExtGadget *g, struct gpInput *msg)
233 {
234         struct SampEditData     *sed = INST_DATA (cl, g);
235         struct InputEvent       *ie = msg->gpi_IEvent;
236         WORD    MouseX, MouseY;         /* Mouse coordinates relative to editing area bounds */
237         BOOL    moved           = FALSE,
238                         scrolled        = FALSE;
239         ULONG   result = GMR_MEACTIVE;
240
241         if (msg->MethodID == GM_GOACTIVE)
242         {
243                 if (!sed->Instr)
244                         return GMR_NOREUSE;
245
246                 g->Flags |= GFLG_SELECTED;
247
248                 {
249                         struct RastPort *rp;
250
251                         /* Render active cursor */
252                         if (rp = ObtainGIRPort (((struct gpInput *)msg)->gpi_GInfo))
253                         {
254                                 DrawCursor (rp, sed, g);
255                                 ReleaseGIRPort (rp);
256                         }
257                 }
258
259                 /* Do not process InputEvent when the gadget has been
260                  * activated by ActivateGadget().
261                  */
262                 if (!((struct gpInput *)msg)->gpi_IEvent)
263                         return GMR_MEACTIVE;
264
265                 /* Note: The input event that triggered the gadget
266                  * activation (usually a mouse click) should be passed
267                  * to the GM_HANDLEINPUT method, so we fall down to it.
268                  */
269         }
270
271
272         MouseX = ((struct gpInput *)msg)->gpi_Mouse.X;
273         MouseY = ((struct gpInput *)msg)->gpi_Mouse.Y;
274
275         switch (ie->ie_Class)
276         {
277                 case IECLASS_TIMER:
278
279                         /* Timer events are used to keep scrolling
280                          * when the mouse is outside the bounds of the
281                          * gadget.  When a timer event is recevied and
282                          * the mouse button is still pressed, we scroll the
283                          * cursor.
284                          */
285                                 if (sed->Flags & SEF_DRAGGING)
286                                         moved = MoveCursor (sed, MouseX);
287
288                         break;
289
290                 case IECLASS_RAWMOUSE:
291                 {
292                         BOOL double_click = FALSE;
293                         BOOL outside = (MouseX < 0) || (MouseX >= sed->GBounds.Width);
294
295                         switch (ie->ie_Code)
296                         {
297                                 case MENUDOWN:
298
299                                         /* Abort cursor dragging operation and restore
300                                          * old cursor position.
301                                          */
302                                         if (sed->Flags & SEF_DRAGGING)
303                                         {
304                                                 sed->CursX              = sed->BackupCursX;
305                                                 sed->XStart             = sed->BackupXStart;
306                                                 moved = TRUE;
307                                                 sed->Flags &= ~(SEF_DRAGGING | SEF_SCROLLING);
308                                         }
309                                         else result = GMR_REUSE;
310
311                                         break;
312
313                                 case SELECTUP:
314                                         /* Send final update to sliders */
315                                         scrolled = SCROLLED_HORIZ | SCROLLED_VERT;
316                                         sed->Flags &= ~(SEF_DRAGGING | SEF_SCROLLING);
317                                         break;
318
319                                 case SELECTDOWN:
320
321                                         /* Check if mouse click is still over the gadget */
322
323                                         if (outside)
324                                         {
325                                                 /* Click outside editing area box:
326                                                  * Check if click is really outside gadget box.
327                                                  * If it is, deactivate the gadget and reuse the event.
328                                                  * Notify application if it is interested in
329                                                  * hearing IDCMP_GADGETUP codes.
330                                                  */
331
332                                                 if      ((MouseX < 0) || (MouseX >= sed->GBounds.Width) ||
333                                                         (MouseY < 0) || (MouseY >= sed->GBounds.Height))
334                                                         result = GMR_REUSE | GMR_VERIFY;
335                                                 break;
336                                         }
337                                         else
338                                         {
339                                                 /* Backup cursor position for undo feature */
340                                                 sed->BackupCursX        = sed->CursX;
341                                                 sed->BackupXStart       = sed->XStart;
342
343                                                 /* Start cursor drag mode */
344                                                 sed->Flags |= SEF_DRAGGING;
345                                         }
346
347                                         /* Check for double clicking */
348
349                                         if (DoubleClick (sed->DoubleClickSeconds, sed->DoubleClickMicros,
350                                                 ie->ie_TimeStamp.tv_secs, ie->ie_TimeStamp.tv_micro))
351                                                 double_click = TRUE;
352
353                                         sed->DoubleClickSeconds = ie->ie_TimeStamp.tv_secs;
354                                         sed->DoubleClickMicros  = ie->ie_TimeStamp.tv_micro;
355
356                                         /* NOTE: I'm falling through here! */
357
358                                 default:
359
360                                         if (sed->Flags & SEF_DRAGGING)
361                                         {
362                                                 if (outside)
363                                                         sed->Flags |= SEF_SCROLLING;
364                                                 else
365                                                         moved = MoveCursor (sed, MouseX);
366                                         }
367                                         else if (!moved && double_click)
368                                         {
369                                                 if (sed->Flags & SEF_MARKING)
370                                                         sed->Flags &= ~SEF_MARKING;
371                                                 else
372                                                 {
373                                                         sed->Flags |= SEF_MARKING;
374                                                         sed->RangeStartX = sed->CursX;
375                                                 }
376 /*
377                                                 if (rp = ObtainGIRPort (msg->gpi_GInfo))
378                                                 {
379                                                         if (!(sed->Flags & SEF_MARKING))
380                                                                 ClearRange (rp, sed);
381
382                                                         DrawCursor (rp, sed, g);
383
384                                                         ReleaseGIRPort (rp);
385                                                 }
386 */
387                                         }
388
389                                         break;
390                         }
391                         break;
392                 }
393
394                 default:
395                         return 0;
396
397         }       /* End switch (ie->ie_Class) */
398
399         if (moved)
400         {
401                 struct RastPort *rp;
402
403                 if (rp = ObtainGIRPort (msg->gpi_GInfo))
404                 {
405                         scrolled |= DrawCursor (rp, sed, g);
406                         ReleaseGIRPort (rp);
407                 }
408
409                 /* Broadcast notification to our target object. */
410                 NotifyCursor (g, msg->gpi_GInfo, (ie->ie_Code & IECODE_UP_PREFIX) ? 0 : OPUF_INTERIM);
411         }
412
413         if (scrolled)
414                 NotifyHSlider (g, msg->gpi_GInfo, (ie->ie_Code & IECODE_UP_PREFIX) ? 0 : OPUF_INTERIM);
415
416         return result;
417 }
418
419
420
421 static void SAMP_RenderMethod (Class *cl, struct ExtGadget *g, struct gpRender *msg)
422 {
423         struct SampEditData     *sed = INST_DATA (cl, g);
424
425         /* We do not support GREDRAW_UPDATE and GREDRAW_TOGGLE */
426
427         if (msg->gpr_Redraw == GREDRAW_REDRAW)
428         {
429                 /* Recalculate the display size only on V37.
430                  * As of V39, Intuition supports GM_LAYOUT, which
431                  * allows a more optimized way to handle dynamic resizing.
432                  */
433                 if (IntuitionBase->LibNode.lib_Version < 39)
434                 {
435                         if (CalcDisplaySize (sed, g, ((struct gpRender *)msg)->gpr_GInfo))
436                                 NotifyHSlider (g, msg->gpr_GInfo, 0);
437                 }
438
439                 RedrawAll (msg->gpr_RPort, sed, g);
440         }
441 }
442
443
444
445 static ULONG SAMP_SetMethod (Class *cl, struct ExtGadget *g, struct opSet *msg)
446 {
447         struct SampEditData *sed = INST_DATA (cl, g);
448         struct TagItem          *ti,
449                                                 *tstate = msg->ops_AttrList;
450         BOOL    zoom                    = FALSE,
451                         move_cursor             = FALSE,
452                         scroll                  = FALSE;
453
454
455         while (ti = NextTagItem(&tstate))
456         {
457                 switch (ti->ti_Tag)
458                 {
459                         case SEA_CursXPos:
460                                 if (sed->CursXPos != ti->ti_Data)
461                                 {
462                                         sed->CursXPos = ti->ti_Data;
463                                         move_cursor = TRUE;
464                                 }
465                                 break;
466
467                         case SEA_XStart:
468                                 if (sed->XStart != ti->ti_Data)
469                                 {
470                                         sed->XStart = ti->ti_Data;
471                                         scroll = TRUE;
472                                 }
473                                 break;
474
475                         case SEA_XRatio:
476                                 if (sed->XRatio != ti->ti_Data)
477                                 {
478                                         sed->XRatio = ti->ti_Data;
479                                         zoom = TRUE;
480                                         break;
481                                 }
482
483                         case SEA_ScrollLeft:
484                                 if (sed->XStart > 0)
485                                 {
486                                         sed->XStart--;
487                                         scroll = TRUE;
488                                 }
489                                 break;
490
491                         case SEA_ScrollRight:
492                                 if (sed->XStart + sed->XVisible < sed->Lenght)
493                                 {
494                                         sed->XStart++;
495                                         scroll = TRUE;
496                                 }
497                                 break;
498
499                         case SEA_MarkRegion:
500                         {
501                                 struct Rectangle *region = (struct Rectangle *)ti->ti_Data;
502
503                                 if (!region)                            /* End mark mode */
504
505                                         sed->Flags &= ~SEF_MARKING;
506
507                                 else if (region == (struct Rectangle *)-1)      /* Toggle mark mode */
508                                 {
509                                         sed->Flags ^= SEF_MARKING;
510                                         sed->RangeStartX        = sed->XStart;
511                                         // sed->RangeStartY     = sed->YStart;
512                                 }
513                                 else                                            /* Start mark mode */
514                                 {
515                                         memcpy (&sed->RangeStartX, region, sizeof (struct Rectangle));
516                                         sed->CursX      = region->MaxX;
517                                         sed->Flags |= PEF_MARKING;
518                                 }
519
520                                 if (rp = ObtainGIRPort (((struct opSet *)msg)->ops_GInfo))
521                                 {
522                                         if (!(sed->Flags & PEF_MARKING))
523                                                 ClearRange (rp, sed);
524
525                                         DrawCursor (rp, sed, g);
526
527                                         ReleaseGIRPort (rp);
528                                 }
529
530                                 break;
531                         }
532
533                         case SEA_Instrument:
534                                 sed->Instrument = (struct Instrument *) ti->ti_Data;
535                                 redraw = TRUE;
536                                 FreeUndoBuffers (sed, TRUE);
537
538                                 if (sed->Instrument == NULL)
539                                         sed->CursX = sed->VisibleX = 0;
540                                 else
541                                 {
542                                         /* Recalculate pattern dimensions */
543                                         if (CalcDisplaySize (sed, g, msg->ops_GInfo))
544                                                 NotifyHSlider (g, msg->ops_GInfo, 0);
545                                 }
546                                 break;
547
548                         case SEA_MaxUndoLevels:
549                                 sed->MaxUndoLevels = ti->ti_Data;
550                                 FreeUndoBuffers (sed, FALSE);
551                                 break;
552
553                         case SEA_MaxUndoMem:
554                                 sed->MaxUndoMem = ti->ti_Data;
555
556                                 /* Unlimited undo memory */
557                                 if (sed->MaxUndoMem == 0) sed->MaxUndoMem = ~0;
558
559                                 FreeUndoBuffers (sed, FALSE);
560
561                                 break;
562
563                         case SEA_BackgroundPen:
564                                 if (sed->BackgroundPen != ti->ti_Data)
565                                 {
566                                         sed->BackgroundPen = ti->ti_Data;
567                                         redraw_all = TRUE;
568                                 }
569                                 break;
570
571                         case SEA_LinePen:
572                                 if (sed->LinePen != ti->ti_Data)
573                                 {
574                                         sed->LinePen = ti->ti_Data;
575                                         redraw_all = TRUE;
576                                 }
577                                 break;
578
579                         case SEA_FillPen:
580                                 if (sed->FillPen != ti->ti_Data)
581                                 {
582                                         sed->FillPen = ti->ti_Data;
583                                         redraw_all = TRUE;
584                                 }
585                                 break;
586
587                         case SEA_GridPen:
588                                 if (sed->GridPen != ti->ti_Data)
589                                 {
590                                         sed->GridPen = ti->ti_Data;
591                                         redraw_all = TRUE;
592                                 }
593                                 break;
594
595                         default:
596                                 break;
597                 }
598
599         }       /* End while (NextTagItem()) */
600
601
602         result = DoSuperMethodA (cl, (Object *)g, msg);
603
604         if (redraw_all || scroll || move_cursor || zoom)
605         {
606                 WORD scrolled = 0;
607
608                 if (rp = ObtainGIRPort (msg->ops_GInfo))
609                 {
610                         if (redraw_all)
611                         {
612                                 DoMethod ((Object *)g, GM_RENDER, ((struct opSet *)msg)->ops_GInfo, rp, GREDRAW_REDRAW);
613                                 scrolled = 3;
614                         }
615                         else if (scroll)
616                                 scrolled = ScrollPattern (rp, sed, g, lefttrack, topline);
617
618                         if (move_cursor)
619                                 scrolled |= DrawCursor (rp, sed, g);
620
621                         ReleaseGIRPort (rp);
622                 }
623
624                 if (scrolled & 1)
625                         NotifyVSlider (g, ((struct opSet *)msg)->ops_GInfo, msg->MethodID == OM_UPDATE ? (((struct opUpdate *)msg)->opu_Flags) : 0);
626                 if (scrolled & 2)
627                         NotifyHSlider (g, ((struct opSet *)msg)->ops_GInfo, msg->MethodID == OM_UPDATE ? (((struct opUpdate *)msg)->opu_Flags) : 0);
628
629                 if (move_cursor || scrolled)
630                         NotifyCursor (g, ((struct opSet *)msg)->ops_GInfo, msg->MethodID == OM_UPDATE ? (((struct opUpdate *)msg)->opu_Flags) : 0);
631         }
632 }
633
634
635
636 static LONG SAMP_GetMethod (Class *cl, struct ExtGadget *g, struct opGet *msg)
637 {
638         struct SampEditData *sed = INST_DATA (cl, g);
639
640         switch (msg->opg_AttrID)
641         {
642                 case SEA_CursXPos:
643                         *msg->opg_Storage = (ULONG) sed->CursXPos;
644                         break;
645
646                 case SEA_CursYPos:
647                         *msg->opg_Storage = (ULONG) sed->CursYPos;
648                         break;
649
650                 case SEA_XStart:
651                         *msg->opg_Storage = (ULONG) sed->XStart;
652                         break;
653
654                 case SEA_YStart:
655                         *msg->opg_Storage = (ULONG) sed->YStart;
656                         break;
657
658                 case SEA_XRatio:
659                         *msg->opg_Storage = (ULONG) sed->XRatio;
660                         break;
661
662                 case SEA_YRatio:
663                         *msg->opg_Storage = (ULONG) sed->YRatio;
664                         break;
665
666                 case SEA_MarkRegion:
667                 {
668                         struct Rectangle *region = (struct Rectangle *) *msg->opg_Storage);
669
670                         region->MinX = min (sed->RangeStartX, sed->RangeEndX);
671                         region->MaxX = max (sed->RangeStartX, sed->RangeEndX);
672                         region->MinY = min (sed->RangeStartY, sed->RangeEndY);
673                         region->MaxY = max (sed->RangeStartY, sed->RangeEndY);
674                         break;
675                 }
676
677                 case SEA_Flags:
678                         *msg->opg_Storage = (ULONG) sed->Flags;
679                         break;
680
681                 case SEA_Instrument:
682                         *msg->opg_Storage = (ULONG) sed->Instrument;
683                         break;
684
685                 default:
686                         return DoSuperMethodA (cl, (Object *)g, msg);
687         }
688
689         return TRUE;
690 }
691
692
693
694 static ULONG SAMP_NewMethod (Class *cl, struct ExtGadget *g, struct opSet *msg)
695 {
696         struct SampEditData             *sed;
697         ULONG tmp;
698
699         if (!(g = DoSuperMethodA (cl, (Object *)g, msg)))
700                 return NULL;
701
702         sed = INST_DATA (cl, g);        /* Get pointer to instance data */
703
704         memset (sed, 0, sizeof (struct SampEditData));
705
706         /* We are going to use ScrollRaster() in this gadget... */
707
708         if (g->Flags & GFLG_EXTENDED)
709                 g->MoreFlags |= GMORE_SCROLLRASTER;
710
711         g->Flags |= GFLG_TABCYCLE | GFLG_RELSPECIAL;
712
713         /* Initialize our lists */
714         NEWLIST ((struct List *)&sed->UndoList);
715         NEWLIST ((struct List *)&sed->RedoList);
716
717
718         /* Initialize attributes */
719
720         sed->Instrument         = (struct Instrument *) GetTagData (SEA_Instrument, NULL, msg->ops_AttrList);
721         sed->BackgroundPen      = GetTagData (SEA_BackgroundPen,        0, msg->ops_AttrList);
722         sed->LinePen            = GetTagData (SEA_LinePen,                      2, msg->ops_AttrList);
723         sed->FillPen            = GetTagData (SEA_FillPen,                      1, msg->ops_AttrList);
724         sed->GridPen            = GetTagData (SEA_GridPen,                      3, msg->ops_AttrList);
725         sed->MaxUndoLevels      = GetTagData (SEA_MaxUndoLevels,        8, ((struct opSet *)msg)->ops_AttrList);
726         sed->MaxUndoMem         = GetTagData (SEA_MaxUndoMem,           32768, ((struct opSet *)msg)->ops_AttrList);
727         sed->Flags                      = GetTagData (SEA_Flags,                        0, ((struct opSet *)msg)->ops_AttrList);
728
729         /* Unlimited undo memory */
730         if (sed->MaxUndoMem == 0) sed->MaxUndoMem = ~0;
731
732         return (ULONG) g;
733 }
734
735
736
737 static void NotifyCursor (struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags)
738 {
739         /* Always sends notification if the gadget has the GACT_IMMEDIATE
740          * flag set.  If it isn't, the editor will report its cursor
741          * position only the last time it updates the cursor position.
742          */
743         if ((g->Activation & GACT_IMMEDIATE) || !(flags & OPUF_INTERIM))
744         {
745                 struct SampEditData *sed = INST_DATA (OCLASS(g), g);
746
747                 NotifyAttrChanges ((Object *)g, gi, flags,
748                         SEA_CursXPos,   sed->CursXPos,
749                         SEA_CursYPos,   sed->CursYPos,
750                         GA_ID,                  g->GadgetID,
751                         TAG_DONE);
752         }
753 }
754
755
756
757 static void NotifyHSlider (struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags)
758 {
759         struct SampEditData *sed = INST_DATA (OCLASS(g), g);
760
761         NotifyAttrChanges ((Object *)g, gi, flags,
762                 SEA_XStart,     sed->XStart;
763                 GA_ID,  g->GadgetID,
764                 TAG_DONE);
765 }
766
767
768
769 static void GetGadgetBox (struct GadgetInfo *ginfo, struct ExtGadget *g, struct IBox *rect)
770
771 /* This function gets the actual IBox where a gadget exists
772  * in a window.  The special cases it handles are all the REL#?
773  * (relative positioning flags).
774  *
775  * The function takes a struct GadgetInfo pointer, a struct Gadget
776  * pointer, and a struct IBox pointer.  It uses the window and
777  * gadget to fill in the IBox.
778  */
779 {
780         rect->Left = g->LeftEdge;
781         if (g->Flags & GFLG_RELRIGHT) rect->Left += ginfo->gi_Domain.Width - 1;
782
783         rect->Top = g->TopEdge;
784         if (g->Flags & GFLG_RELBOTTOM) rect->Top += ginfo->gi_Domain.Height - 1;
785
786         rect->Width = g->Width;
787         if (g->Flags & GFLG_RELWIDTH) rect->Width += ginfo->gi_Domain.Width;
788
789         rect->Height = g->Height;
790         if (g->Flags & GFLG_RELHEIGHT) rect->Height += ginfo->gi_Domain.Height;
791 }
792
793
794
795 XDEF HOOKCALL struct Library *_UserLibInit (REG(a6,struct Library *mybase))
796 {
797         SysBase = *((struct ExecBase **)4);
798
799         IntuitionBase   = (struct IntuitionBase *) OpenLibrary ("intuition.library", 37);
800         GfxBase                 = (struct GfxBase *) OpenLibrary ("graphics.library", 37);
801         UtilityBase             = OpenLibrary ("utility.library", 37);
802
803         if (!(IntuitionBase && GfxBase && UtilityBase && KeymapBase))
804         {
805                 _UserLibCleanup (mybase);
806                 return NULL;
807         }
808
809         if (SampEditClass = MakeClass (SAMPEDITCLASS, GADGETCLASS, NULL, sizeof (struct SampEditData), 0))
810         {
811                 SampEditClass->cl_Dispatcher.h_Entry = (ULONG (*)()) SampEditDispatcher;
812                 AddClass (SampEditClass);
813         }
814         else
815         {
816                 _UserLibCleanup (mybase);
817                 return NULL;
818         }
819
820         return mybase;
821 }
822
823
824
825 XDEF HOOKCALL struct Library *_UserLibCleanup (REG(a6,struct Library *mybase))
826 {
827         if (SampEditClass)
828                 if (!FreeClass (SampEditClass))
829                         return NULL;
830
831         /* Passing NULL to CloseLibrary() is safe */
832         CloseLibrary ((struct Library *)UtilityBase);
833         CloseLibrary ((struct Library *)GfxBase);
834         CloseLibrary ((struct Library *)IntuitionBase);
835
836         return mybase;
837 }
838
839
840
841 XDEF HOOKCALL struct IClass *_GetEngine (REG(a6,struct Library *mybase))
842 {
843         return (SampEditClass);
844 }