4 ** Copyright (C) 1995,96,97,98 Bernardo Innocenti
6 ** Pattern Editor gadget class
9 #include <exec/memory.h>
10 #include <exec/ports.h>
11 #include <utility/tagitem.h>
12 #include <utility/hooks.h>
13 #include <devices/inputevent.h>
14 #include <libraries/SongClass.h>
15 #include <libraries/PattEditClass.h>
16 #include <libraries/xmodule.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>
28 #include <proto/exec.h>
29 #include <proto/intuition.h>
30 #include <proto/graphics.h>
31 #include <proto/utility.h>
32 #include <proto/keymap.h>
35 #include "CompilerSpecific.h"
37 #include "ListMacros.h"
40 #define WANTED_LIBVER 39
42 #define WANTED_LIBVER 37
46 /* Some handy definitions missing in <devices/inputevent.h> */
47 #define IEQUALIFIER_SHIFT (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)
48 #define IEQUALIFIER_ALT (IEQUALIFIER_LALT | IEQUALIFIER_RALT)
49 #define IEQUALIFIER_COMMAND (IEQUALIFIER_LCOMMAND | IEQUALIFIER_RCOMMAND)
53 /* Scrolling control */
54 #define SCROLLED_VERT 1
55 #define SCROLLED_HORIZ 2
59 /* Private class instance data */
64 struct TextFont *EditorFont;
66 /* These are the actual Gadget position and size,
67 * regardless of any GREL_#? flag.
71 /* These are the actual editing area position and size. */
77 /* Pens used to draw various pattern editor elements */
83 ULONG Flags; /* See definitions in <PattEditClass.h> */
85 /* Routine used to convert a note into its ASCII representation
86 * This routine is passed the pointer to the note and a buffer
87 * with <TrackChars> characters to fill in.
89 ASMCALL void (*Note2ASCIIFunc)(REG(a1, UBYTE *s), REG(a2, struct Note *note));
91 UWORD TrackWidth; /* Width of a track in pixels */
92 UWORD TrackChars; /* Width of a track in chars */
95 /* How many tracks and lines we can fit in the gadget bounds */
102 /* Current cursor position */
109 UWORD CursState; /* IDS_NORMAL, IDS_DISABLED or IDS_BUSY */
110 UWORD CursLinePos; /* Cursor line position (0 = not drawn) */
111 struct Rectangle CursRect; /* Cursor Position to erase it quickly. */
113 /* Cursor advancement */
117 /* Range marking info */
118 UWORD RangeStartTrack;
119 UWORD RangeStartLine;
123 /* Backup cursor position for mouse right button undo operation */
128 /* This variable holds a counter for the optimized scroller update.
129 * When the pattern is scrolling, updates are only sent after
130 * a specific amount of scrolling operations have occurred.
134 /* The following two are for track resizing. ResizeXStart
135 * is the horizontal mouse position when the resize operation
136 * was started. ResizeChars is the last number of chars set.
141 struct Rectangle RangeRect; /* Backup of range rect to erase it quickly. */
143 /* Undo/Redo support */
149 struct MinList UndoList;
150 struct MinList RedoList;
152 /* For testing double/triple click */
153 ULONG DoubleClickSeconds;
154 ULONG DoubleClickMicros;
155 ULONG TripleClickSeconds;
156 ULONG TripleClickMicros;
158 /* Experimental: timer.device stuff */
159 // struct timerequest TimerIO;
160 // struct MsgPort TimerPort;
161 // struct Interrupt TimerInt;
165 /* This structure holds an entry for the Undo/Redo buffer. */
177 /* Function prototypes */
179 static ULONG HOOKCALL PattEditDispatcher (
181 REG(a2, struct ExtGadget *g),
183 static void GetGadgetBox (struct GadgetInfo *ginfo, struct ExtGadget *g, struct IBox *rect);
184 static BOOL CalcDisplaySize (struct PattEditData *ped, struct ExtGadget *g, struct GadgetInfo *gpi);
185 static void SaveUndo (struct PattEditData *ped);
186 static BOOL UndoChange (struct PattEditData *ped);
187 static BOOL RedoChange (struct PattEditData *ped);
188 static void FreeUndoBuffers (struct PattEditData *ped, BOOL freeall);
189 static BOOL MoveCursor (struct PattEditData *ped, WORD x, WORD y);
190 static void EraseCursor (struct RastPort *rp, struct PattEditData *ped);
191 static UWORD DrawCursor (struct RastPort *rp, struct PattEditData *ped, struct ExtGadget *g);
192 static void DrawRange (struct RastPort *rp, struct PattEditData *ped);
193 static void ClearRange (struct RastPort *rp, struct PattEditData *ped);
194 static void RedrawAll (struct RastPort *rp, struct PattEditData *ped, struct ExtGadget *g);
195 static void RedrawPattern (struct RastPort *rp, struct PattEditData *ped, struct ExtGadget *g);
196 static void DrawTrackSeparators (struct RastPort *rp, struct PattEditData *ped, UWORD width);
197 static void DrawTrackNumbers(struct RastPort *rp, struct PattEditData *ped);
198 static void DrawPatternLines(struct RastPort *rp, struct PattEditData *ped, UWORD min, UWORD max);
199 static void DrawNote (struct RastPort *rp, struct PattEditData *ped);
200 void ASMCALL Note2ASCII (REG(a1, UBYTE *s), REG(a2, struct Note *note));
201 void ASMCALL Note2ASCIIBlank0 (REG(a1, UBYTE *s), REG(a2, struct Note *note));
202 static UWORD ScrollPattern (struct RastPort *rp, struct PattEditData *ped, struct ExtGadget *g,
203 UWORD lefttrack, UWORD topline);
204 static void NotifyCursor (struct PattEditData *ped, struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags);
205 static void NotifyVSlider (struct PattEditData *ped, struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags);
206 static void NotifyHSlider (struct PattEditData *ped, struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags);
207 static void NotifySliders (struct PattEditData *ped, struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags);
209 //static void ASMCALL TimerIntServer (register REG(a1, struct ExtGadget *g));
211 HOOKCALL struct ClassLibrary *_UserLibInit (REG(a6, struct ClassLibrary *mybase));
212 HOOKCALL struct ClassLibrary *_UserLibCleanup (REG(a6, struct ClassLibrary *mybase));
213 HOOKCALL Class *_GetEngine (REG(a6, struct ClassLibrary *mybase));
219 const UBYTE LibName[] = LIBNAME;
220 const UBYTE LibVer[] = { '$', 'V', 'E', 'R', ':', ' ' };
221 const UBYTE LibId[] = LIBNAME " 2.1 (8.4.97) " BUILDMODE " © 1995,96,97 by Bernardo Innocenti\n";
228 static const ULONG TextNotes[MAXNOTES] =
231 'C-0 ', 'C#0 ', 'D-0 ', 'D#0 ', 'E-0 ', 'F-0 ',
232 'F#0 ', 'G-0 ', 'G#0 ', 'A-0 ', 'A#0 ', 'B-0 ',
234 'C-1 ', 'C#1 ', 'D-1 ', 'D#1 ', 'E-1 ', 'F-1 ',
235 'F#1 ', 'G-1 ', 'G#1 ', 'A-1 ', 'A#1 ', 'B-1 ',
237 'C-2 ', 'C#2 ', 'D-2 ', 'D#2 ', 'E-2 ', 'F-2 ',
238 'F#2 ', 'G-2 ', 'G#2 ', 'A-2 ', 'A#2 ', 'B-2 ',
240 'C-3 ', 'C#3 ', 'D-3 ', 'D#3 ', 'E-3 ', 'F-3 ',
241 'F#3 ', 'G-3 ', 'G#3 ', 'A-3 ', 'A#3 ', 'B-3 ',
243 'C-4 ', 'C#4 ', 'D-4 ', 'D#4 ', 'E-4 ', 'F-4 ',
244 'F#4 ', 'G-4 ', 'G#4 ', 'A-4 ', 'A#4 ', 'B-4 ',
246 'C-5 ', 'C#5 ', 'D-5 ', 'D#5 ', 'E-5 ', 'F-5 ',
247 'F#5 ', 'G-5 ', 'G#5 ', 'A-5 ', 'A#5 ', 'B-5 '
249 #endif /* PORTABLE */
252 /* Keyboard rawkeys -> notes conversion table */
254 static const UBYTE KeyNotes0[10] = { 0, 26, 28, 0, 31, 33, 35, 0, 38, 40}; /* (1..0) */
255 static const UBYTE KeyNotes1[10] = {25, 27, 29, 30, 32, 34, 36, 37, 39, 41}; /* (Q..]) */
256 static const UBYTE KeyNotes2[10] = { 0, 14, 16, 0, 19, 21, 23, 0, 26, 28}; /* (A..') */
257 static const UBYTE KeyNotes3[10] = {13, 15, 17, 18, 20, 22, 24, 25, 27, 29}; /* (Z../) */
259 static const UBYTE HexValues[20] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', 'G', 'H', 'I', 'J'};
260 static const UBYTE HexValuesNo0[20] = {' ','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', 'G', 'H', 'I', 'J'};
264 /* Cursor patterns - Used in EraseCursor() and DrawCursor() */
266 static UWORD GhostPattern[] = { 0xAAAA, 0x5555 };
267 static UWORD MarkPattern[] = { 0xFFFF, 0x0000 };
275 struct ExecBase *SysBase = NULL;
276 struct IntuitionBase *IntuitionBase = NULL;
277 struct GfxBase *GfxBase = NULL;
278 struct UtilityBase *UtilityBase = NULL;
279 struct Library *KeymapBase = NULL;
282 static ULONG HOOKCALL PattEditDispatcher (
284 REG(a2, struct ExtGadget *g),
287 /* PattEdit class dispatcher entrypoint. Handle BOOPSI messages.
291 struct PattEditData *ped;
296 switch (msg->MethodID)
300 ped = INST_DATA (cl, g);
304 result = GMR_NOREUSE;
308 g->Flags |= GFLG_SELECTED;
310 /* Render active cursor */
311 if (rp = ObtainGIRPort (((struct gpInput *)msg)->gpi_GInfo))
313 DrawCursor (rp, ped, g);
317 /* Do not process InputEvent when the gadget has been
318 * activated by ActivateGadget().
320 if (!((struct gpInput *)msg)->gpi_IEvent)
322 result = GMR_MEACTIVE;
326 /* Note: The input event that triggered the gadget
327 * activation (usually a mouse click) should be passed
328 * to the GM_HANDLEINPUT method, so we fall down to it.
333 struct InputEvent *ie = ((struct gpInput *)msg)->gpi_IEvent;
334 UWORD topline, lefttrack;
335 WORD MouseX, MouseY; /* Mouse coordinates relative to editing area bounds */
338 scroll_pattern = FALSE;
341 result = GMR_MEACTIVE;
342 ped = INST_DATA (cl, g);
344 /* MouseX and MouseY represent the mouse position inside the
345 * editing area of the gadget.
347 MouseX = ((struct gpInput *)msg)->gpi_Mouse.X + ped->GBounds.Left - ped->TBounds.Left;
348 MouseY = ((struct gpInput *)msg)->gpi_Mouse.Y + ped->GBounds.Top - ped->TBounds.Top;
350 switch (ie->ie_Class)
354 /* Timer events are used to keep scrolling
355 * when the mouse is outside the bounds of the
356 * gadget. When a timer event is recevied and
357 * the mouse button is pressed, we scroll the
360 if (ped->Flags & PEF_DRAGGING)
361 moved = MoveCursor (ped, MouseX, MouseY);
365 case IECLASS_RAWMOUSE:
367 BOOL double_click = FALSE, triple_click;
369 (MouseX < 0) || (MouseX >= ped->TBounds.Width) ||
370 (MouseY < 0) || (MouseY >= ped->TBounds.Height);
376 /* Abort cursor dragging operation and restore
377 * old cursor position.
379 if (ped->Flags & PEF_DRAGGING)
381 ped->Line = ped->BackupLine;
382 ped->Track = ped->BackupTrack;
383 ped->Column = ped->BackupColumn;
385 ped->Flags &= ~(PEF_DRAGGING | PEF_SCROLLING);
387 else if (ped->Flags & PEF_RESIZETRACKS)
389 if (rp = ObtainGIRPort (((struct gpInput *)msg)->gpi_GInfo))
391 SetDrMd (rp, COMPLEMENT);
392 DrawTrackSeparators (rp, ped, ped->ResizeChars * ped->FontXSize);
395 ped->Flags &= ~PEF_RESIZETRACKS;
397 else result = GMR_REUSE;
402 /* Send final update to sliders */
403 if (ped->Flags & PEF_SCROLLING)
404 scrolled = SCROLLED_VERT | SCROLLED_HORIZ;
406 if (ped->Flags & PEF_RESIZETRACKS)
408 ped->TrackChars = ped->ResizeChars;
409 ped->TrackWidth = ped->TrackChars * ped->FontXSize;
410 CalcDisplaySize(ped, g, ((struct gpInput *)msg)->gpi_GInfo);
411 if (rp = ObtainGIRPort (((struct gpInput *)msg)->gpi_GInfo))
413 //SetDrMd (rp, COMPLEMENT);
414 //DrawTrackSeparators (rp, ped, ped->ResizeChars * ped->FontXSize);
416 DoMethod ((Object *)g, GM_RENDER, ((struct gpInput *)msg)->gpi_GInfo, rp,
423 /* Stop scrolling, dragging, resizing tracks and
424 * adjustisting the scroll box.
426 ped->Flags &= ~(PEF_DRAGGING | PEF_SCROLLING |
427 PEF_RESIZETRACKS | PEF_ADJUSTSCROLLBOX);
433 /* Check if mouse click is still over the gadget */
437 /* Click outside editing area box:
438 * Check if click is really outside gadget box.
439 * If it is, deactivate the gadget and reuse the event.
440 * Notify application if it is interested in
441 * hearing IDCMP_GADGETUP codes.
443 MouseX = ((struct gpInput *)msg)->gpi_Mouse.X;
444 MouseY = ((struct gpInput *)msg)->gpi_Mouse.Y;
446 if ((MouseX < 0) || (MouseX >= ped->GBounds.Width) ||
447 (MouseY < 0) || (MouseY >= ped->GBounds.Height))
448 result = GMR_REUSE | GMR_VERIFY;
453 if (MouseX % ped->TrackWidth >= ped->TrackWidth - 2)
455 /* Start track resizing mode */
456 ped->Flags |= PEF_RESIZETRACKS;
457 ped->ResizeXStart = MouseX;
458 ped->ResizeChars = 0;
462 /* Backup cursor position for undo feature */
463 ped->BackupLine = ped->Line;
464 ped->BackupTrack = ped->Track;
465 ped->BackupColumn = ped->Column;
467 /* Start cursor drag mode */
468 ped->Flags |= PEF_DRAGGING;
472 /* Check for double click */
474 if (DoubleClick (ped->DoubleClickSeconds, ped->DoubleClickMicros,
475 ie->ie_TimeStamp.tv_secs, ie->ie_TimeStamp.tv_micro))
479 if (DoubleClick (ped->TripleClickSeconds, ped->TripleClickMicros,
480 ped->DoubleClickSeconds, ped->DoubleClickMicros))
483 triple_click = FALSE;
485 ped->TripleClickSeconds = ped->DoubleClickSeconds;
486 ped->TripleClickMicros = ped->DoubleClickMicros;
489 ped->DoubleClickSeconds = ie->ie_TimeStamp.tv_secs;
490 ped->DoubleClickMicros = ie->ie_TimeStamp.tv_micro;
492 /* NOTE: I'm falling through here! */
496 if ((ped->Flags & PEF_DRAGGING))
498 if (outside) ped->Flags |= PEF_SCROLLING;
501 if (ped->Flags & PEF_SCROLLING)
503 /* Last update to sync sliders */
504 scrolled = SCROLLED_VERT | SCROLLED_HORIZ;
505 ped->Flags &= ~PEF_SCROLLING;
507 moved = MoveCursor (ped, MouseX, MouseY);
510 /* if ((outside) && (ped->Flags & PEF_DRAGGING) && !(ped->Flags & PEF_SCROLLING))
512 ped->Flags |= PEF_SCROLLING;
514 ped->TimerIO.tr_node.io_Command = TR_ADDREQUEST;
515 ped->TimerIO.tr_time.tv_micro = 100000;
516 BeginIO ((struct IORequest *)&ped->TimerIO);
519 else if (ped->Flags & PEF_RESIZETRACKS)
521 UWORD chars = ped->TrackChars +
522 (((MouseX - ped->ResizeXStart) / ped->FontXSize)
523 / ((ped->ResizeXStart / ped->TrackWidth) + 1));
525 if (chars < MINTRACKCHARS) chars = MINTRACKCHARS;
526 if (chars > MAXTRACKCHARS) chars = MAXTRACKCHARS;
528 if (chars != ped->ResizeChars)
530 if (rp = ObtainGIRPort (((struct gpInput *)msg)->gpi_GInfo))
532 SetDrMd (rp, COMPLEMENT);
534 /* Erase old lines */
535 DrawTrackSeparators (rp, ped, ped->ResizeChars * ped->FontXSize);
538 DrawTrackSeparators (rp, ped, chars * ped->FontXSize);
539 ped->ResizeChars = chars;
546 if (!moved && double_click)
548 if (ped->Flags & PEF_MARKING)
550 if (triple_click && !(ped->Flags & PEF_MARKFULLTRACKS)
551 && (ped->RangeStartLine == ped->RangeEndLine))
553 /* Start full track marking mode */
554 ped->Flags |= PEF_MARKFULLTRACKS;
555 ped->RangeStartLine = 0;
556 ped->RangeEndLine = ped->Patt->Lines - 1;
560 /* Stop marking mode */
561 ped->Flags &= ~(PEF_MARKING | PEF_MARKFULLTRACKS);
565 /* Start normal marking mode */
567 ped->Flags |= PEF_MARKING;
568 ped->RangeStartLine = ped->Line;
569 ped->RangeStartTrack = ped->Track;
573 if (!(ped->Flags & PEF_MARKING))
575 if (rp = ObtainGIRPort (((struct gpInput *)msg)->gpi_GInfo))
577 ClearRange (rp, ped);
586 } /* End switch (ie->ie_Code) */
593 if (ie->ie_Code & IECODE_UP_PREFIX)
595 /* Send final update to slider */
597 if ((ie->ie_Code == (IECODE_UP_PREFIX | CURSORUP))
598 || (ie->ie_Code == (IECODE_UP_PREFIX | CURSORDOWN)))
599 scrolled = SCROLLED_VERT;
601 else if ((ie->ie_Code == (IECODE_UP_PREFIX | CURSORLEFT))
602 || (ie->ie_Code == (IECODE_UP_PREFIX | CURSORRIGHT)))
603 scrolled = SCROLLED_HORIZ;
605 else if ((ie->ie_Qualifier & IEQUALIFIER_COMMAND) && (ie->ie_Code != 0x67))
607 else switch (ie->ie_Code)
613 if (ie->ie_Qualifier & IEQUALIFIER_SHIFT)
615 if (ped->Line > ped->TopLine)
616 ped->Line = ped->TopLine;
618 if (ped->Line >= ped->DisplayLines - 1)
619 ped->Line -= ped->DisplayLines - 1;
622 else if (ie->ie_Qualifier & IEQUALIFIER_ALT)
624 else if (ie->ie_Qualifier & IEQUALIFIER_CONTROL)
626 if (ped->TopLine + ped->DisplayLines < ped->Patt->Lines)
628 topline = ped->TopLine + 1;
629 lefttrack = ped->LeftTrack;
630 scroll_pattern = TRUE;
631 if (ped->Line < topline)
635 else ped->Line--; /* Cursor key without qualifiers */
639 else if (ped->Flags & PEF_VWRAP)
641 ped->Line = ped->Patt->Lines - 1;
650 if (ped->Line < ped->Patt->Lines - 1)
652 if (ie->ie_Qualifier & IEQUALIFIER_SHIFT)
654 if (ped->Line < ped->TopLine + ped->DisplayLines - 1)
655 ped->Line = ped->TopLine + ped->DisplayLines - 1;
658 ped->Line += ped->DisplayLines - 1;
659 if (ped->Line > ped->Patt->Lines - 1)
660 ped->Line = ped->Patt->Lines - 1;
663 else if (ie->ie_Qualifier & IEQUALIFIER_ALT)
664 ped->Line = ped->Patt->Lines - 1;
665 else if (ie->ie_Qualifier & IEQUALIFIER_CONTROL)
667 if (ped->TopLine > 1)
669 topline = ped->TopLine - 1;
670 lefttrack = ped->LeftTrack;
671 scroll_pattern = TRUE;
672 if (ped->Line >= (topline + ped->DisplayLines))
676 else ped->Line++; /* Cursor key without qualifiers */
680 else if (ped->Flags & PEF_VWRAP)
691 if (ie->ie_Qualifier & IEQUALIFIER_SHIFT)
698 else if (ped->Column)
704 else if (ie->ie_Qualifier & IEQUALIFIER_ALT)
711 else if (ped->Column)
727 ped->Column = COL_COUNT-1;
732 if (!moved && (ped->Flags & PEF_HWRAP))
734 ped->Track = ped->Patt->Tracks - 1;
735 ped->Column = COL_COUNT-1;
744 if (ie->ie_Qualifier & IEQUALIFIER_SHIFT)
746 if (ped->Track < ped->Patt->Tracks - 1)
751 else if (ped->Column != COL_COUNT-1)
753 ped->Column = COL_COUNT-1;
757 else if (ie->ie_Qualifier & IEQUALIFIER_ALT)
759 if (ped->Track != ped->Patt->Tracks - 1)
761 ped->Track = ped->Patt->Tracks - 1;
764 else if (ped->Column != COL_COUNT-1)
766 ped->Column = COL_COUNT-1;
772 if (ped->Column < COL_COUNT-1)
777 else if (ped->Track < ped->Patt->Tracks - 1)
785 if (!moved && (ped->Flags & PEF_HWRAP))
796 case 0x5F: /* HELP */
803 if (ie->ie_Qualifier & IEQUALIFIER_ALT)
804 /* Deactivate gadget on ALT+TAB to allow
805 * window cycling in the application.
810 if (ie->ie_Qualifier & IEQUALIFIER_SHIFT)
815 ped->Track = ped->Patt->Tracks - 1;
819 if (ped->Track < ped->Patt->Tracks - 1)
825 ped->Column = COL_NOTE;
832 case 0x0D: /* RETURN */
833 ped->Column = COL_NOTE;
834 if (ped->Line < ped->Patt->Lines - 1)
836 else if (ped->Flags & PEF_VWRAP)
844 struct Note *note = &ped->Patt->Notes[ped->Track][ped->Line];
849 if (ie->ie_Qualifier & IEQUALIFIER_SHIFT)
850 memset (note, 0, sizeof (struct Note));
851 else switch (ped->Column)
867 note->EffNum = EFF_NULL;
871 note->EffVal &= 0x0F;
875 note->EffVal &= 0xF0;
883 struct Note *note = &ped->Patt->Notes[ped->Track][ped->Line];
884 UBYTE tmp = 0, keycode = 1;
886 /* Convert to hex number */
888 if (ped->Column != COL_NOTE)
890 if (MapRawKey (ie, &keycode, 1, NULL) == -1)
894 if (keycode >= '0' && keycode <= '9')
896 else if (keycode >= 'a' && keycode <= ((ped->Column == COL_EFF) ? 'j' : 'f'))
897 tmp = keycode - ('a' - 10);
903 if (keycode) switch (ped->Column)
909 if (ie->ie_Code >= 0x1 && ie->ie_Code <= 0x0A)
910 tmp = KeyNotes0[ie->ie_Code - 0x1];
911 else if (ie->ie_Code >= 0x10 && ie->ie_Code <= 0x19)
912 tmp = KeyNotes1[ie->ie_Code - 0x10];
913 else if (ie->ie_Code >= 0x20 && ie->ie_Code <= 0x29)
914 tmp = KeyNotes2[ie->ie_Code - 0x20];
915 else if (ie->ie_Code >= 0x31 && ie->ie_Code <= 0x39)
916 tmp = KeyNotes3[ie->ie_Code - 0x31];
923 note->Inst = ped->CurrentInst;
930 note->Inst = (note->Inst & 0xF0) | tmp;
934 if (tmp < MAXINSTRUMENTS>>4)
938 note->Inst = (note->Inst & 0x0F) | (tmp<<4);
951 note->EffVal = (note->EffVal & 0xF0) | tmp;
957 note->EffVal = (note->EffVal & 0x0F) | (tmp<<4);
963 } /* End switch (ie->ie_Code) */
970 } /* End switch (ie->ie_Class) */
972 if (moved || change_note || scroll_pattern)
974 if (rp = ObtainGIRPort (((struct gpInput *)msg)->gpi_GInfo))
977 scrolled |= ScrollPattern (rp, ped, g, lefttrack, topline);
981 EraseCursor (rp, ped);
986 ped->Track += ped->AdvanceTracks;
987 ped->Line += ped->AdvanceLines;
989 if (ped->Flags & PEF_HWRAP)
990 ped->Track = ped->Track % ped->Patt->Tracks;
995 else if (ped->Track > ped->Patt->Tracks - 1)
996 ped->Track = ped->Patt->Tracks - 1;
999 if (ped->Flags & PEF_VWRAP)
1000 ped->Line = ped->Line % ped->Patt->Lines;
1005 else if (ped->Line > ped->Patt->Lines - 1)
1006 ped->Line = ped->Patt->Lines - 1;
1010 scrolled |= DrawCursor (rp, ped, g);
1011 ReleaseGIRPort (rp);
1014 /* Broadcast notification to our target object. */
1015 NotifyCursor (ped, g, ((struct gpInput *)msg)->gpi_GInfo, (ie->ie_Code & IECODE_UP_PREFIX) ? 0 : OPUF_INTERIM);
1018 if (scrolled & SCROLLED_VERT)
1019 NotifyVSlider (ped, g, ((struct gpInput *)msg)->gpi_GInfo, (ie->ie_Code & IECODE_UP_PREFIX) ? 0 : OPUF_INTERIM);
1021 if (scrolled & SCROLLED_HORIZ)
1022 NotifyHSlider (ped, g, ((struct gpInput *)msg)->gpi_GInfo, (ie->ie_Code & IECODE_UP_PREFIX) ? 0 : OPUF_INTERIM);
1030 ped = INST_DATA (cl, g);
1032 /* We do not support GREDRAW_TOGGLE */
1034 switch (((struct gpRender *)msg)->gpr_Redraw)
1036 case GREDRAW_REDRAW:
1038 /* Recalculate the display size only on V37.
1039 * As of V39, Intuition supports GM_LAYOUT, which
1040 * allows a more optimized way to handle dynamic resizing.
1042 if (IntuitionBase->LibNode.lib_Version < 39)
1043 if (CalcDisplaySize (ped, g, ((struct gpRender *)msg)->gpr_GInfo))
1044 NotifySliders (ped, g, ((struct gpRender *)msg)->gpr_GInfo, 0);
1045 #endif /* OS30_ONLY */
1047 RedrawAll (((struct gpRender *)msg)->gpr_RPort, ped, g);
1050 case GREDRAW_UPDATE:
1051 /* Just redraw the notes, not the lines, etc. */
1052 RedrawPattern (((struct gpRender *)msg)->gpr_RPort, ped, g);
1061 /* As we are rectangular shaped, we are always hit */
1062 result = GMR_GADGETHIT;
1066 result = GMR_HELPHIT;
1071 ped = INST_DATA (cl, g);
1073 g->Flags &= ~GFLG_SELECTED;
1076 /* Render disabled cursor */
1077 if (rp = ObtainGIRPort (((struct gpGoInactive *)msg)->gpgi_GInfo))
1079 DrawCursor (rp, ped, g);
1080 ReleaseGIRPort (rp);
1087 ped = INST_DATA (cl, g);
1089 if (CalcDisplaySize (ped, g, ((struct gpLayout *)msg)->gpl_GInfo))
1090 NotifySliders (ped, g, ((struct gpLayout *)msg)->gpl_GInfo, 0);
1098 struct TagItem *tstate = ((struct opSet *)msg)->ops_AttrList;
1099 BOOL redraw_all = FALSE,
1100 redraw_pattern = FALSE,
1101 move_cursor = FALSE,
1102 scroll_pattern = FALSE,
1103 change_note = FALSE,
1104 do_super_method = FALSE;
1105 WORD lefttrack, topline;
1106 WORD line, track, column;
1108 ped = INST_DATA (cl, g);
1110 lefttrack = ped->LeftTrack;
1111 topline = ped->TopLine;
1114 column = ped->Column;
1117 while (ti = NextTagItem(&tstate))
1122 track = ti->ti_Data;
1125 case PEA_CursColumn:
1126 column = ti->ti_Data;
1134 if (lefttrack != ti->ti_Data)
1136 lefttrack = ti->ti_Data;
1137 track = lefttrack + (ped->DisplayTracks / 2);
1138 scroll_pattern = TRUE;
1143 if (topline != ti->ti_Data)
1145 topline = ti->ti_Data;
1146 line = topline + (ped->DisplayLines / 2);
1147 scroll_pattern = TRUE;
1153 track = lefttrack - 1;
1157 if (ped->Patt && (lefttrack + ped->DisplayTracks < ped->Patt->Tracks))
1158 track = lefttrack + ped->DisplayTracks;
1167 if (ped->Patt && (topline + ped->DisplayLines < ped->Patt->Lines))
1168 line = topline + ped->DisplayLines;
1174 else if (ped->Flags & PEF_VWRAP)
1175 track = ped->Patt->Tracks - 1;
1180 if (ped->Patt && (track < ped->Patt->Tracks - 1))
1182 else if (ped->Flags & PEF_HWRAP)
1190 else if (ped->Flags & PEF_VWRAP)
1191 line = ped->Patt->Lines - 1;
1196 if (ped->Patt && line < ped->Patt->Lines - 1)
1198 else if (ped->Flags & PEF_VWRAP)
1203 case PEA_UndoChange:
1204 if (((LONG)ti->ti_Data) < 0)
1205 change_note |= RedoChange (ped);
1207 change_note |= UndoChange (ped);
1214 ped->Changes = ti->ti_Data;
1217 case PEA_MarkRegion:
1219 struct Rectangle *region = (struct Rectangle *)ti->ti_Data;
1221 if (!region) /* End mark mode */
1223 ped->Flags &= ~(PEF_MARKING | PEF_MARKFULLTRACKS);
1225 else if (region == (struct Rectangle *)-1) /* Toggle mark mode */
1227 if (ped->Flags & PEF_MARKFULLTRACKS)
1228 ped->Flags &= ~(PEF_MARKING | PEF_MARKFULLTRACKS);
1229 else if (ped->Flags & PEF_MARKING)
1231 if (ped->RangeStartLine == ped->RangeEndLine)
1233 ped->Flags |= PEF_MARKFULLTRACKS;
1234 ped->RangeStartLine = 0;
1235 ped->RangeEndLine = ped->Patt->Lines - 1;
1238 ped->Flags &= ~PEF_MARKING;
1242 ped->Flags |= PEF_MARKING;
1243 ped->RangeStartTrack = track;
1244 ped->RangeStartLine = line;
1247 else /* Start mark mode */
1249 memcpy (&ped->RangeStartTrack, region, sizeof (struct Rectangle));
1250 track = ped->Track = region->MaxX;
1251 line = ped->Line = region->MaxY;
1252 ped->Flags |= PEF_MARKING;
1255 if (rp = ObtainGIRPort (((struct opSet *)msg)->ops_GInfo))
1257 if (!(ped->Flags & PEF_MARKING))
1258 ClearRange (rp, ped);
1260 DrawCursor (rp, ped, g);
1262 ReleaseGIRPort (rp);
1270 ULONG oldflags = ped->Flags;
1271 ped->Flags = (ped->Flags & 0xFFFF0000) | ti->ti_Data;
1273 if ((oldflags & (PEF_HEXMODE | PEF_BLANKZERO | PEF_INVERSETEXT | PEF_DOTINYLINES)) !=
1274 (ped->Flags & (PEF_HEXMODE | PEF_BLANKZERO | PEF_INVERSETEXT | PEF_DOTINYLINES)))
1276 /* Select Note2ASCII func */
1277 if (ped->Flags & PEF_BLANKZERO)
1278 ped->Note2ASCIIFunc = Note2ASCIIBlank0;
1280 ped->Note2ASCIIFunc = Note2ASCII;
1282 if (!(ped->Flags & PEF_DOCURSORRULER))
1283 ped->CursLinePos = 0;
1285 /* Cause complete radraw */
1289 if ((oldflags & PEF_DOCURSORRULER) !=
1290 (ped->Flags & PEF_DOCURSORRULER))
1297 ped->Patt = (struct Pattern *) ti->ti_Data;
1298 redraw_pattern = TRUE;
1299 FreeUndoBuffers (ped, TRUE);
1301 if (ped->Patt == NULL)
1303 static LONG tags[] = { GA_Disabled, TRUE, TAG_DONE };
1305 lefttrack = topline = ped->DisplayTracks = ped->DisplayLines = 0;
1308 DoMethod ((Object *)g, OM_UPDATE, tags, ((struct opUpdate *)msg)->opu_GInfo, 0);
1312 /* Recalculate pattern dimensions */
1313 if (CalcDisplaySize (ped, g, ((struct opSet *)msg)->ops_GInfo))
1315 NotifySliders (ped, g, ((struct opSet *)msg)->ops_GInfo, 0);
1319 /* Force cursor inside pattern */
1321 if (line >= ped->Patt->Lines)
1323 line = ped->Patt->Lines - 1;
1327 if (track >= ped->Patt->Tracks)
1329 track = ped->Patt->Tracks - 1;
1333 if (lefttrack + ped->DisplayTracks > ped->Patt->Tracks)
1335 lefttrack = ped->Patt->Tracks - ped->DisplayTracks;
1336 scroll_pattern = TRUE;
1339 if (topline + ped->DisplayLines > ped->Patt->Lines)
1341 topline = ped->Patt->Lines - ped->DisplayLines;
1342 scroll_pattern = TRUE;
1345 if (g->Flags & GFLG_DISABLED)
1347 static ULONG tags[] = { GA_Disabled, FALSE, TAG_DONE };
1348 DoMethod ((Object *)g, OM_UPDATE, tags, ((struct opUpdate *)msg)->opu_GInfo, 0);
1353 case PEA_CurrentInst:
1354 ped->CurrentInst = ti->ti_Data;
1357 case PEA_MaxUndoLevels:
1358 ped->MaxUndoLevels = ti->ti_Data;
1359 FreeUndoBuffers (ped, FALSE);
1362 case PEA_MaxUndoMem:
1363 ped->MaxUndoMem = ti->ti_Data;
1365 /* Unlimited undo memory */
1366 if (ped->MaxUndoMem == 0) ped->MaxUndoMem = ~0;
1368 FreeUndoBuffers (ped, FALSE);
1372 case PEA_AdvanceCurs:
1373 ped->AdvanceLines = ti->ti_Data & 0xFFFF;
1374 ped->AdvanceTracks = ti->ti_Data >> 16;
1378 ped->Flags = (ped->Flags & (PEF_HWRAP | PEF_VWRAP)) | (ti->ti_Data & (PEF_HWRAP | PEF_VWRAP));
1382 if (ped->BGPen != ti->ti_Data)
1384 ped->BGPen = ti->ti_Data;
1390 if (ped->TextPen != ti->ti_Data)
1392 ped->TextPen = ti->ti_Data;
1398 if (ped->LinesPen != ti->ti_Data)
1400 ped->LinesPen = ti->ti_Data;
1405 case PEA_TinyLinesPen:
1406 if (ped->TinyLinesPen != ti->ti_Data)
1408 ped->TinyLinesPen = ti->ti_Data;
1414 /* This little optimization avoids forwarding the
1415 * OM_SET method to our superclass then there are
1418 do_super_method = TRUE;
1422 } /* End while (NextTagItem()) */
1426 move_cursor = ((line != ped->Line) ||
1427 (track != ped->Track) ||
1428 (column != ped->Column));
1430 if (do_super_method)
1431 result = DoSuperMethodA (cl, (Object *)g, msg);
1435 if (redraw_all || redraw_pattern || scroll_pattern || move_cursor || change_note)
1439 if (rp = ObtainGIRPort (((struct opSet *)msg)->ops_GInfo))
1441 if (redraw_all || redraw_pattern)
1443 ped->LeftTrack = lefttrack;
1444 ped->TopLine = topline;
1447 ped->Column = column;
1449 DoMethod ((Object *)g, GM_RENDER, ((struct opSet *)msg)->ops_GInfo, rp,
1450 (redraw_all ? GREDRAW_REDRAW : GREDRAW_UPDATE));
1451 scrolled = SCROLLED_VERT | SCROLLED_HORIZ;
1453 else if (scroll_pattern)
1457 scrolled = ScrollPattern (rp, ped, g, lefttrack, topline);
1459 else if (move_cursor || change_note)
1463 ped->Column = column;
1467 EraseCursor (rp, ped);
1471 scrolled |= DrawCursor (rp, ped, g);
1474 ReleaseGIRPort (rp);
1477 /* TODO: avoid sending back updates to the sliders */
1479 if (scrolled & SCROLLED_VERT)
1480 NotifyVSlider (ped, g, ((struct opSet *)msg)->ops_GInfo, msg->MethodID == OM_UPDATE ? (((struct opUpdate *)msg)->opu_Flags) : 0);
1481 if (scrolled & SCROLLED_HORIZ)
1482 NotifyHSlider (ped, g, ((struct opSet *)msg)->ops_GInfo, msg->MethodID == OM_UPDATE ? (((struct opUpdate *)msg)->opu_Flags) : 0);
1484 if (scrolled || move_cursor)
1485 NotifyCursor (ped, g, ((struct opSet *)msg)->ops_GInfo, msg->MethodID == OM_UPDATE ? (((struct opUpdate *)msg)->opu_Flags) : 0);
1494 ped = INST_DATA (cl, g);
1497 switch (((struct opGet *) msg)->opg_AttrID)
1500 *(((struct opGet *) msg)->opg_Storage) = (ULONG) ped->Track;
1503 case PEA_CursColumn:
1504 *(((struct opGet *) msg)->opg_Storage) = (ULONG) ped->Column;
1508 *(((struct opGet *) msg)->opg_Storage) = (ULONG) ped->Line;
1512 *(((struct opGet *) msg)->opg_Storage) = (ULONG) ped->LeftTrack;
1516 *(((struct opGet *) msg)->opg_Storage) = (ULONG) ped->TopLine;
1520 *(((struct opGet *) msg)->opg_Storage) = (ULONG) ped->Changes;
1523 case PEA_MarkRegion:
1525 struct Rectangle *region = (struct Rectangle *) (((struct opGet *) msg)->opg_Storage);
1527 region->MinX = min (ped->RangeStartTrack, ped->RangeEndTrack);
1528 region->MaxX = max (ped->RangeStartTrack, ped->RangeEndTrack);
1529 region->MinY = min (ped->RangeStartLine, ped->RangeEndLine);
1530 region->MaxY = max (ped->RangeStartLine, ped->RangeEndLine);
1535 *(((struct opGet *) msg)->opg_Storage) = (ULONG) ped->Flags;
1538 case PEA_DisplayTracks:
1539 *(((struct opGet *) msg)->opg_Storage) = (ULONG) ped->DisplayTracks;
1542 case PEA_DisplayLines:
1543 *(((struct opGet *) msg)->opg_Storage) = (ULONG) ped->DisplayLines;
1547 *(((struct opGet *) msg)->opg_Storage) = (ULONG) ped->Patt;
1551 result = DoSuperMethodA (cl, (Object *)g, msg);
1560 if (result = DoSuperMethodA (cl, (Object *)g, msg))
1564 g = (struct ExtGadget *) result;
1566 ped = INST_DATA (cl, g); /* Get pointer to instance data */
1567 memset (ped, 0, sizeof (struct PattEditData));
1569 /* We are going to use ScrollRaster() in this gadget... */
1571 if (g->Flags & GFLG_EXTENDED)
1572 g->MoreFlags |= GMORE_SCROLLRASTER;
1574 g->Flags |= GFLG_TABCYCLE | GFLG_RELSPECIAL;
1576 /* Initialize our lists */
1577 NEWLIST ((struct List *)&ped->UndoList);
1578 NEWLIST ((struct List *)&ped->RedoList);
1581 /* Open the timer.device */
1583 NEWLIST (&ped->TimerPort.mp_MsgList);
1584 ped->TimerPort.mp_Flags = PA_SOFTINT;
1585 ped->TimerPort.mp_SoftInt = &ped->TimerInt;
1586 ped->TimerInt.is_Node.ln_Type = NT_INTERRUPT;
1587 ped->TimerInt.is_Data = g;
1588 ped->TimerInt.is_Code = (void (*)())TimerIntServer;
1589 ped->TimerIO.tr_node.io_Message.mn_ReplyPort = &ped->TimerPort;
1591 if (OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *)&ped->TimerIO, 0))
1593 CoerceMethod (cl, g, OM_DISPOSE);
1599 /* Initialize attributes */
1601 ped->Patt = (struct Pattern *) GetTagData (PEA_Pattern, NULL, ((struct opSet *)msg)->ops_AttrList);
1602 ped->CurrentInst = GetTagData (PEA_CurrentInst, NULL, ((struct opSet *)msg)->ops_AttrList);
1603 ped->EditorFont = (struct TextFont *) GetTagData (PEA_TextFont, (ULONG)GfxBase->DefaultFont, ((struct opSet *)msg)->ops_AttrList);
1604 ped->BGPen = GetTagData (PEA_BGPen, 0, ((struct opSet *)msg)->ops_AttrList);
1605 ped->TextPen = GetTagData (PEA_TextPen, 1, ((struct opSet *)msg)->ops_AttrList);
1606 ped->LinesPen = GetTagData (PEA_LinesPen, 2, ((struct opSet *)msg)->ops_AttrList);
1607 ped->TinyLinesPen = GetTagData (PEA_TinyLinesPen, 2, ((struct opSet *)msg)->ops_AttrList);
1608 ped->MaxUndoLevels = GetTagData (PEA_MaxUndoLevels, 32, ((struct opSet *)msg)->ops_AttrList);
1609 ped->MaxUndoMem = GetTagData (PEA_MaxUndoMem, 8192, ((struct opSet *)msg)->ops_AttrList);
1610 ped->Flags = GetTagData (PEA_Flags, 0, ((struct opSet *)msg)->ops_AttrList);
1611 ped->Flags |= GetTagData (PEA_CursWrap, ped->Flags, ((struct opSet *)msg)->ops_AttrList) & (PEF_HWRAP | PEF_VWRAP);
1613 tmp = GetTagData (PEA_AdvanceCurs, 1, ((struct opSet *)msg)->ops_AttrList);
1614 ped->AdvanceTracks = tmp << 16;
1615 ped->AdvanceLines = tmp & 0xFFFF;
1617 ped->Line = GetTagData (PEA_CursLine, 0, ((struct opSet *)msg)->ops_AttrList);
1618 ped->Track = GetTagData (PEA_CursTrack, 0, ((struct opSet *)msg)->ops_AttrList);
1619 ped->Column = GetTagData (PEA_CursColumn, 0, ((struct opSet *)msg)->ops_AttrList);
1621 ped->FontXSize = ped->EditorFont->tf_XSize;
1622 ped->FontYSize = ped->EditorFont->tf_YSize;
1623 ped->TrackChars = 10;
1624 ped->TrackWidth = ped->FontXSize * ped->TrackChars;
1626 /* Select Note2ASCII func */
1627 if (ped->Flags & PEF_BLANKZERO)
1628 ped->Note2ASCIIFunc = Note2ASCIIBlank0;
1630 ped->Note2ASCIIFunc = Note2ASCII;
1632 /* Unlimited undo memory */
1633 if (ped->MaxUndoMem == 0) ped->MaxUndoMem = ~0;
1635 if (ped->Patt == NULL)
1637 static LONG tags[] = { GA_Disabled, TRUE, TAG_DONE };
1638 DoMethod ((Object *)g, OM_UPDATE, tags, NULL, 0);
1646 ped = INST_DATA (cl, g);
1648 FreeUndoBuffers (ped, TRUE);
1649 // CloseDevice ((struct IORequest *)&ped->TimerIO);
1651 /* NOTE: I'm falling through here! */
1657 /* Unsupported method: let our superclass's
1658 * dispatcher take a look at it.
1660 result = DoSuperMethodA (cl, (Object *)g, msg);
1669 static void SaveUndo (struct PattEditData *ped)
1671 struct UndoNode *undo;
1675 /* Is undo feature disabled ? */
1676 if (!ped->MaxUndoLevels) return;
1678 /* Empty redo list */
1679 while (undo = (struct UndoNode *) REMHEAD((struct List *)&ped->RedoList))
1680 FreeMem (undo, sizeof (struct UndoNode));
1682 FreeUndoBuffers (ped, FALSE);
1684 while (ped->UndoCount >= ped->MaxUndoLevels || ped->UndoMem >= ped->MaxUndoMem)
1685 if (undo = (struct UndoNode *) REMTAIL ((struct List *)&ped->UndoList))
1687 FreeMem (undo, sizeof (struct UndoNode));
1689 ped->UndoMem -= sizeof (struct UndoNode);
1692 /* Allocate a new undo buffer and save current note */
1693 if (undo = AllocMem (sizeof (struct UndoNode), MEMF_ANY))
1695 undo->Track = ped->Track;
1696 undo->Line = ped->Line;
1698 memcpy (&undo->OldNote, &ped->Patt->Notes[ped->Track][ped->Line],
1699 sizeof (struct Note));
1701 ADDHEAD ((struct List *)&ped->UndoList, (struct Node *)undo);
1703 ped->UndoMem += sizeof (struct UndoNode);
1709 static BOOL UndoChange (struct PattEditData *ped)
1711 struct UndoNode *undo;
1713 struct Note tmp_note;
1715 if (undo = (struct UndoNode *) REMHEAD ((struct List *) &ped->UndoList))
1718 ped->UndoMem -= sizeof (struct UndoNode);
1721 ped->Track = undo->Track;
1722 ped->Line = undo->Line;
1724 note = &ped->Patt->Notes[ped->Track][ped->Line];
1726 /* Swap undo buffer with note */
1727 memcpy (&tmp_note, &undo->OldNote, sizeof (struct Note));
1728 memcpy (&undo->OldNote, note, sizeof (struct Note));
1729 memcpy (note, &tmp_note, sizeof (struct Note));
1732 /* Move this node to the redo buffer */
1733 ADDHEAD ((struct List *)&ped->RedoList, (struct Node *)undo);
1743 static BOOL RedoChange (struct PattEditData *ped)
1745 struct UndoNode *undo;
1747 struct Note tmp_note;
1749 if (undo = (struct UndoNode *) REMHEAD ((struct List *) &ped->RedoList))
1751 ped->Track = undo->Track;
1752 ped->Line = undo->Line;
1754 note = &ped->Patt->Notes[ped->Track][ped->Line];
1756 /* Swap undo buffer and note */
1757 memcpy (&tmp_note, &undo->OldNote, sizeof (struct Note));
1758 memcpy (&undo->OldNote, note, sizeof (struct Note));
1759 memcpy (note, &tmp_note, sizeof (struct Note));
1761 /* Move this node to the undo buffer */
1762 ADDHEAD ((struct List *)&ped->UndoList, (struct Node *)undo);
1766 ped->UndoMem += sizeof (struct UndoNode);
1776 static void FreeUndoBuffers (struct PattEditData *ped, BOOL freeall)
1778 /* If <freeall> is TRUE, this routine will free all the undo buffers.
1779 * Otherwhise, it will check for undo overflow and free enough nodes
1780 * to keep the undo buffers inside the memory size and nodes count
1784 struct UndoNode *undo;
1788 while (ped->UndoCount >= ped->MaxUndoLevels || ped->UndoMem >= ped->MaxUndoMem)
1789 if (undo = (struct UndoNode *) RemTail ((struct List *)&ped->UndoList))
1791 FreeMem (undo, sizeof (struct UndoNode));
1793 ped->UndoMem -= sizeof (struct UndoNode);
1799 /* Free everything */
1801 while (undo = (struct UndoNode *) REMHEAD ((struct List *)&ped->UndoList))
1802 FreeMem (undo, sizeof (struct UndoNode));
1804 while (undo = (struct UndoNode *) REMHEAD ((struct List *)&ped->RedoList))
1805 FreeMem (undo, sizeof (struct UndoNode));
1807 ped->UndoCount = 0; ped->UndoMem = 0;
1812 static void NotifyCursor (struct PattEditData *ped, struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags)
1814 static LONG tags[] =
1823 /* Always send notification if the gadget has the GACT_IMMEDIATE
1824 * flag set. If it isn't, the editor will report its cursor
1825 * position only on last cursor update.
1827 if ((g->Activation & GACT_IMMEDIATE) || !(flags & OPUF_INTERIM))
1829 tags[1] = ped->Line;
1830 tags[3] = ped->Track;
1831 tags[5] = ped->Column;
1832 tags[7] = g->GadgetID;
1834 DoMethod ((Object *)g, OM_NOTIFY, tags, gi, flags);
1840 static void NotifyVSlider (struct PattEditData *ped, struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags)
1842 static LONG tags[] =
1845 // PEA_DisplayLines, 0,
1851 /* Optimized slider update; only broadcast updates if one of
1852 * these conditions is satisfied:
1854 * - Final update (keyup or selectup),
1855 * - SliderCounter reached,
1856 * - Reached top/bottom of the pattern.
1858 * In addition, notifications are not sent when the we receive OM_UPDATE messages
1861 if ((!(flags & OPUF_INTERIM)) || (ped->SliderCounter == 0) || (ped->TopLine == 0)
1862 || (ped->TopLine + ped->DisplayLines >= ped->Patt->Lines))
1864 ped->SliderCounter = 4;
1866 tags[1] = ped->TopLine;
1867 // tags[3] = ped->DisplayLines;
1868 tags[3] = g->GadgetID;
1870 DoMethod ((Object *)g, OM_NOTIFY, tags, gi, flags);
1873 ped->SliderCounter--;
1878 static void NotifyHSlider (struct PattEditData *ped, struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags)
1880 static LONG tags[] =
1883 // PEA_DisplayTracks, 0,
1889 /* Optimized slider update; only send updates if one of
1890 * these conditions is satisfied:
1892 * - Final update (keyup or selectup),
1893 * - SliderCounter reached,
1894 * - Reached left/right of pattern.
1896 if ((!(flags & OPUF_INTERIM)) || (ped->SliderCounter == 0) || (ped->LeftTrack == 0)
1897 || (ped->LeftTrack + ped->DisplayTracks >= ped->Patt->Tracks))
1899 ped->SliderCounter = 3;
1901 tags[1] = ped->LeftTrack;
1902 // tags[3] = ped->DisplayTracks;
1903 tags[3] = g->GadgetID;
1905 DoMethod ((Object *)g, OM_NOTIFY, tags, gi, flags);
1908 ped->SliderCounter--;
1913 static void NotifySliders (struct PattEditData *ped, struct ExtGadget *g, struct GadgetInfo *gi, ULONG flags)
1915 static LONG tags[] =
1918 PEA_DisplayTracks, 0,
1920 PEA_DisplayLines, 0,
1925 tags[1] = ped->LeftTrack;
1926 tags[3] = ped->DisplayTracks;
1927 tags[5] = ped->TopLine;
1928 tags[7] = ped->DisplayLines;
1929 tags[9] = g->GadgetID;
1931 DoMethod ((Object *)g, OM_NOTIFY, tags, gi, flags);
1938 static void GetGadgetBox (struct GadgetInfo *ginfo, struct ExtGadget *g, struct IBox *rect)
1940 /* This function gets the actual IBox where a gadget exists
1941 * in a window. The special cases it handles are all the REL#?
1942 * (relative positioning flags).
1944 * The function takes a struct GadgetInfo pointer, a struct Gadget
1945 * pointer, and a struct IBox pointer. It uses the window and
1946 * gadget to fill in the IBox.
1949 rect->Left = g->LeftEdge;
1950 if (g->Flags & GFLG_RELRIGHT) rect->Left += ginfo->gi_Domain.Width - 1;
1952 rect->Top = g->TopEdge;
1953 if (g->Flags & GFLG_RELBOTTOM) rect->Top += ginfo->gi_Domain.Height - 1;
1955 rect->Width = g->Width;
1956 if (g->Flags & GFLG_RELWIDTH) rect->Width += ginfo->gi_Domain.Width;
1958 rect->Height = g->Height;
1959 if (g->Flags & GFLG_RELHEIGHT) rect->Height += ginfo->gi_Domain.Height;
1964 static BOOL CalcDisplaySize (struct PattEditData *ped, struct ExtGadget *g, struct GadgetInfo *ginfo)
1966 /* Calculate maximum number of tracks and lines that will fit in the gadget
1967 * size. Returns TRUE if something has changed.
1969 * GBounds are the bounds of the whole gadget and
1970 * TBounds are the bounds of the portion where the cursor lives.
1972 * +--Window--------------------+
1974 * | +--GBounds----------------+|
1975 * | | +--TBounds-----------+||
1976 * | |001|C#2 1 000|B#2 2 C20 |||
1977 * | |002|--- 0 000|A-2 2 C30 |||
1978 * | |003|--- 0 000|C-2 2 C10 |||
1979 * | |004|--- 0 000|C#2 3 000 |||
1980 * | | +--------------------+||
1981 * | +-------------------------+|
1982 * +----------------------------+
1985 UWORD old_displaytracks = ped->DisplayTracks,
1986 old_displaylines = ped->DisplayLines,
1987 numcol_width = ped->FontXSize * 4;
1989 GetGadgetBox (ginfo, g, &ped->GBounds);
1991 /* Setup DisplayTracks and DisplayLines */
1995 ped->DisplayTracks = min ((ped->GBounds.Width - numcol_width) / ped->TrackWidth, ped->Patt->Tracks);
1996 ped->DisplayLines = min (ped->GBounds.Height / ped->FontYSize, ped->Patt->Lines);
1998 if (ped->TopLine + ped->DisplayLines > ped->Patt->Lines)
1999 ped->TopLine = max (0, ped->Patt->Lines - ped->DisplayLines);
2001 if (ped->LeftTrack + ped->DisplayTracks > ped->Patt->Tracks)
2002 ped->LeftTrack = max (0, ped->Patt->Tracks - ped->DisplayTracks);
2006 /* Setup Text Bounds */
2008 ped->TBounds.Top = ped->GBounds.Top;
2009 ped->TBounds.Left = ped->GBounds.Left + numcol_width;
2010 ped->TBounds.Width = ped->DisplayTracks * ped->TrackWidth;
2011 ped->TBounds.Height = ped->DisplayLines * ped->FontYSize;
2013 return ((BOOL)((old_displaytracks != ped->DisplayTracks) || (old_displaylines != ped->DisplayLines)));
2018 static BOOL MoveCursor (struct PattEditData *ped, WORD x, WORD y)
2020 /* Moves the cursor to a given xy position. Checks whether the cursor has
2021 * really moved and returns FALSE if there is no need to update its imagery.
2025 BOOL moved = FALSE, maxtrack = FALSE;
2028 /* X Position (Track) */
2031 tmp = ped->LeftTrack - 1;
2033 tmp = (x / ped->TrackWidth) + ped->LeftTrack;
2035 if (tmp < 0) tmp = 0;
2037 if (tmp >= ped->Patt->Tracks)
2039 tmp = ped->Patt->Tracks - 1;
2043 if (ped->Track != tmp)
2050 /* X Position (Column) */
2053 tmp = ped->TrackChars - 1;
2055 tmp = (x / ped->FontXSize) % ped->TrackChars;
2058 if (tmp < 3) tmp = COL_NOTE;
2059 else if (tmp == 3) tmp = COL_INSTH;
2060 else if (tmp == 4) tmp = COL_INSTL;
2061 else if (tmp < 7) tmp = COL_EFF;
2062 else if (tmp == 7) tmp = COL_VALH;
2063 else tmp = COL_VALL;
2066 if (ped->Column != tmp)
2075 tmp = (y / ped->FontYSize) + ped->TopLine;
2077 if (tmp < 0) tmp = 0;
2079 if (tmp >= ped->Patt->Lines)
2080 tmp = ped->Patt->Lines - 1;
2082 if (ped->Line != tmp)
2093 static void EraseCursor (struct RastPort *rp, struct PattEditData *ped)
2095 SetDrMd (rp,COMPLEMENT);
2097 switch (ped->CursState)
2100 SetAfPt (rp, GhostPattern, 1);
2101 RectFill (rp, ped->CursRect.MinX, ped->CursRect.MinY,
2102 ped->CursRect.MaxX, ped->CursRect.MaxY);
2103 SetAfPt (rp, NULL, 0); /* Reset Area Pattern */
2107 SetAfPt (rp, MarkPattern, 1);
2108 RectFill (rp, ped->CursRect.MinX, ped->CursRect.MinY,
2109 ped->CursRect.MaxX, ped->CursRect.MaxY);
2110 SetAfPt (rp, NULL, 0); /* Reset Area Pattern */
2114 RectFill (rp, ped->CursRect.MinX, ped->CursRect.MinY,
2115 ped->CursRect.MaxX, ped->CursRect.MaxY);
2117 if (ped->CursLinePos)
2119 /* Erase cursor line */
2121 /* Question: Is RectFill faster than Move()+Draw()? Hmmm... */
2122 RectFill (rp, ped->GBounds.Left, ped->CursRect.MaxY,
2123 ped->TBounds.Left + ped->TBounds.Width - 1, ped->CursRect.MaxY);
2124 // Move (rp, ped->GBounds.Left, ped->CursRect.MaxY);
2125 // Draw (rp, ped->TBounds.Left + ped->TBounds.Width - 1, ped->CursRect.MaxY);
2126 ped->CursLinePos = 0;
2132 /* When the cursor is not rendered, its state
2133 * will be IDS_NORMAL, so we won't erase it at all.
2138 ped->CursState = IDS_NORMAL;
2143 static UWORD DrawCursor (struct RastPort *rp, struct PattEditData *ped, struct ExtGadget *g)
2145 /* Draw the cursor image on the editor. If the cursor goes outside
2146 * of the scrolling region, the view is scrolled to make
2150 * 0 - no scrolling occurred,
2151 * SCROLLED_VERT - vertical scroll occurred,
2152 * SCROLLED_HORIZ - horizontal scroll occurred,
2153 * SCROLLED_VERT|SCROLLED_HORIZ - scrolled in both directions.
2157 /* Cursor offsets for each track column */
2158 static UWORD ColumnOff[COL_COUNT] = { 0, 3, 4, 6, 7, 8 };
2160 struct Rectangle NewCurs;
2164 /* Do not attemt to draw a cursor if the editor is so small that
2165 * it can't display anything,
2167 if (!ped->DisplayTracks || !ped->DisplayLines)
2170 /* Check whether cursor is outside the display bounds and
2171 * scroll pattern to make it visible if required.
2174 if (ped->Line < ped->TopLine)
2175 return ScrollPattern (rp, ped, g, ped->LeftTrack, ped->Line);
2176 else if (ped->Line >= ped->TopLine + ped->DisplayLines)
2177 return ScrollPattern (rp, ped, g, ped->LeftTrack, ped->Line - ped->DisplayLines + 1);
2178 if (ped->Track < ped->LeftTrack)
2179 return ScrollPattern (rp, ped, g, ped->Track, ped->TopLine);
2180 else if (ped->Track >= ped->LeftTrack + ped->DisplayTracks)
2181 return ScrollPattern (rp, ped, g, ped->Track - ped->DisplayTracks + 1, ped->TopLine);
2185 /* Calculate new cursor rectangle */
2187 NewCurs.MinX = ped->TBounds.Left +
2188 (((ped->Track - ped->LeftTrack) * ped->TrackChars) + ColumnOff[ped->Column]) * ped->FontXSize;
2189 NewCurs.MinY = ped->TBounds.Top + (ped->Line - ped->TopLine) * ped->FontYSize;
2190 NewCurs.MaxX = NewCurs.MinX + ped->FontXSize - 1;
2191 NewCurs.MaxY = NewCurs.MinY + ped->FontYSize - 1;
2194 /* Note field is three characters wide */
2195 if (ped->Column == COL_NOTE)
2196 NewCurs.MaxX += ped->FontXSize * 2;
2199 /* Set AreaPattern to show current cursor state */
2201 if (!(g->Flags & GFLG_SELECTED))
2203 NewState = IDS_DISABLED;
2205 /* Set this pattern to draw an inactive cursor */
2206 SetAfPt (rp, GhostPattern, 1);
2208 else if (ped->Flags & PEF_MARKING)
2210 NewState = IDS_BUSY;
2212 /* Set this pattern to draw marking cursor */
2213 SetAfPt (rp, MarkPattern, 1);
2215 else NewState = IDS_SELECTED;
2217 SetDrMd (rp, COMPLEMENT);
2219 RectFill (rp, NewCurs.MinX, NewCurs.MinY,
2220 NewCurs.MaxX, NewCurs.MaxY);
2221 SetAfPt (rp, NULL, 0); /* Reset AreaFill Pattern */
2223 if ((ped->Flags & PEF_DOCURSORRULER) && (NewState == IDS_SELECTED))
2225 if (ped->CursLinePos != NewCurs.MaxY)
2227 /* Draw horizontal line */
2229 /* Question: Is RectFill faster than Move()+Draw()? Hmmm... */
2230 RectFill (rp, ped->GBounds.Left, NewCurs.MaxY,
2231 ped->TBounds.Left + ped->TBounds.Width - 1, NewCurs.MaxY);
2232 // Move (rp, ped->GBounds.Left, NewCurs.MaxY);
2233 // Draw (rp, ped->TBounds.Left + ped->TBounds.Width - 1, NewCurs.MaxY);
2235 /* Cause EraseCursor() to leave the old line alone */
2236 else ped->CursLinePos = 0;
2240 /* Erase old cursor */
2241 EraseCursor (rp, ped);
2243 if (ped->Flags & PEF_MARKING)
2244 /* Update the range */
2245 DrawRange (rp, ped);
2248 /* Store new position and state */
2249 ped->CursRect = NewCurs;
2250 ped->CursState = NewState;
2252 if ((ped->Flags & PEF_DOCURSORRULER) && (NewState == IDS_SELECTED))
2253 ped->CursLinePos = NewCurs.MaxY;
2260 static void DrawRange (struct RastPort *rp, struct PattEditData *ped)
2262 UWORD tmin, tmax, lmin, lmax;
2263 struct Rectangle newrange;
2265 ped->RangeEndTrack = ped->Track;
2267 if (!(ped->Flags & PEF_MARKFULLTRACKS))
2268 ped->RangeEndLine = ped->Line;
2270 if (ped->RangeStartTrack < ped->RangeEndTrack)
2272 tmin = ped->RangeStartTrack;
2273 tmax = ped->RangeEndTrack;
2277 tmin = ped->RangeEndTrack;
2278 tmax = ped->RangeStartTrack;
2281 if (ped->RangeStartLine < ped->RangeEndLine)
2283 lmin = ped->RangeStartLine;
2284 lmax = ped->RangeEndLine;
2288 lmin = ped->RangeEndLine;
2289 lmax = ped->RangeStartLine;
2292 /* Limit to visible portion of range rectangle */
2294 if (tmin < ped->LeftTrack)
2295 tmin = ped->LeftTrack;
2296 if (tmin >= ped->LeftTrack + ped->DisplayTracks)
2297 tmin = ped->LeftTrack + ped->DisplayTracks - 1;
2299 if (tmax < ped->LeftTrack)
2300 tmax = ped->LeftTrack;
2301 if (tmax >= ped->LeftTrack + ped->DisplayTracks)
2302 tmax = ped->LeftTrack + ped->DisplayTracks - 1;
2304 if (lmin < ped->TopLine)
2305 lmin = ped->TopLine;
2306 if (lmin >= ped->TopLine + ped->DisplayLines)
2307 lmin = ped->TopLine + ped->DisplayLines - 1;
2309 if (lmax < ped->TopLine)
2310 lmax = ped->TopLine;
2311 if (lmax >= ped->TopLine + ped->DisplayLines)
2312 lmax = ped->TopLine + ped->DisplayLines - 1;
2315 newrange.MinX = ped->TBounds.Left + (tmin - ped->LeftTrack) * ped->TrackWidth;
2316 newrange.MinY = ped->TBounds.Top + (lmin - ped->TopLine) * ped->FontYSize;
2317 newrange.MaxX = ped->TBounds.Left + ((tmax - ped->LeftTrack + 1) * ped->TrackWidth) - 1;
2318 newrange.MaxY = ped->TBounds.Top + ((lmax - ped->TopLine + 1) * ped->FontYSize) - 1;
2321 SetWriteMask (rp, ped->TextPen | ped->BGPen);
2323 SafeSetWriteMask (rp, ped->TextPen | ped->BGPen);
2324 #endif /* OS30_ONLY */
2326 SetDrMd (rp, COMPLEMENT);
2329 if (ped->RangeRect.MaxX == 0)
2331 RectFill (rp, newrange.MinX,
2338 /* Incremental range box update. We only draw changes relative to last
2339 * ranged box. As the range box is drawn complementing bitplane 1,
2340 * complementing it again will erase it, so we do not care if the box
2341 * has grown or shrinked; we just complemnt delta boxes.
2348 * |###| <-+-- unchanged
2351 * ^---------- changed
2353 if (newrange.MinX != ped->RangeRect.MinX)
2354 RectFill (rp, min (ped->RangeRect.MinX, newrange.MinX),
2356 max (ped->RangeRect.MinX, newrange.MinX) - 1,
2366 if (newrange.MaxX != ped->RangeRect.MaxX)
2367 RectFill (rp, min (ped->RangeRect.MaxX, newrange.MaxX) + 1,
2369 max (ped->RangeRect.MaxX, newrange.MaxX),
2379 if (newrange.MinY != ped->RangeRect.MinY)
2380 RectFill (rp, ped->RangeRect.MinX,
2381 min (ped->RangeRect.MinY, newrange.MinY),
2382 ped->RangeRect.MaxX,
2383 max (ped->RangeRect.MinY, newrange.MinY) - 1);
2392 if (newrange.MaxY != ped->RangeRect.MaxY)
2393 RectFill (rp, ped->RangeRect.MinX,
2394 min (ped->RangeRect.MaxY, newrange.MaxY) + 1,
2395 ped->RangeRect.MaxX,
2396 max (ped->RangeRect.MaxY, newrange.MaxY));
2399 /* Copy new values */
2400 ped->RangeRect = newrange;
2403 SetWriteMask (rp, ~0);
2405 SafeSetWriteMask (rp, (UBYTE)~0);
2406 #endif /* OS30_ONLY */
2411 static void ClearRange (struct RastPort *rp, struct PattEditData *ped)
2414 SetWriteMask (rp, ped->TextPen | ped->BGPen);
2416 SafeSetWriteMask (rp, ped->TextPen | ped->BGPen);
2417 #endif /* OS30_ONLY */
2418 SetDrMd (rp, COMPLEMENT);
2420 RectFill (rp, ped->RangeRect.MinX, ped->RangeRect.MinY,
2421 ped->RangeRect.MaxX, ped->RangeRect.MaxY);
2423 memset (&ped->RangeRect, 0, sizeof (ped->RangeRect));
2426 SetWriteMask (rp, ~0);
2428 SafeSetWriteMask (rp, (UBYTE)~0);
2429 #endif /* OS30_ONLY */
2434 static void RedrawAll (struct RastPort *rp, struct PattEditData *ped, struct ExtGadget *g)
2441 /* Erase the whole gadget imagery */
2443 SetAPen (rp, ped->BGPen);
2448 /* Clear everything */
2450 RectFill (rp, ped->GBounds.Left, ped->GBounds.Top,
2451 ped->GBounds.Left + ped->GBounds.Width - 1, ped->GBounds.Top + ped->GBounds.Height - 1);
2455 if (rp->BitMap->Depth > 1)
2457 /* Do not clear the bitplanes used by the text because they will
2458 * be completely redrawn later.
2461 SetWriteMask (rp, ~ped->TextPen);
2463 SafeSetWriteMask (rp, (UBYTE)~ped->TextPen);
2464 #endif /* OS30_ONLY */
2474 RectFill (rp, ped->GBounds.Left, ped->GBounds.Top,
2475 ped->TBounds.Left + ped->TBounds.Width - 1, ped->TBounds.Top + ped->TBounds.Height - 1);
2477 /* Restore the Mask */
2479 SetWriteMask (rp, ~0);
2481 SafeSetWriteMask (rp, (UBYTE)~0);
2482 #endif /* OS30_ONLY */
2485 /* Now clear the area at the right and bottom side of
2486 * the editing field.
2496 if (ped->TBounds.Left + ped->TBounds.Width < ped->GBounds.Left + ped->GBounds.Width)
2497 RectFill (rp, ped->TBounds.Left + ped->TBounds.Width, ped->GBounds.Top,
2498 ped->GBounds.Left + ped->GBounds.Width - 1, ped->TBounds.Top + ped->TBounds.Height - 1);
2507 if (ped->TBounds.Top + ped->TBounds.Height < ped->GBounds.Top + ped->GBounds.Height)
2508 RectFill (rp, ped->GBounds.Left, ped->TBounds.Top + ped->TBounds.Height,
2509 ped->GBounds.Left + ped->GBounds.Width - 1, ped->GBounds.Top + ped->GBounds.Height - 1);
2512 /* Cursor shouldn't be deleted again since everything has been cleared */
2513 ped->CursState = IDS_NORMAL;
2514 ped->CursLinePos = 0;
2516 if (!(ped->Patt)) return;
2518 /* Draw track separator lines */
2519 SetAPen (rp, ped->LinesPen);
2520 DrawTrackSeparators (rp, ped, ped->TrackWidth);
2522 /* Draw tiny vertical separator lines */
2523 if (ped->Flags & PEF_DOTINYLINES)
2525 SetAPen (rp, ped->TinyLinesPen);
2526 SetDrPt (rp, 0xCCCC);
2527 HOffset = ped->TBounds.Left - 1;
2529 for (i = 0; i < ped->DisplayTracks; i++, HOffset += ped->TrackWidth)
2531 Move (rp, tmp = HOffset + ped->FontXSize * 3, ped->GBounds.Top);
2532 Draw (rp, tmp, ped->GBounds.Top + ped->GBounds.Height - 1);
2533 Move (rp, tmp = HOffset + ped->FontXSize * 5, ped->GBounds.Top);
2534 Draw (rp, tmp, ped->GBounds.Top + ped->GBounds.Height - 1);
2535 Move (rp, tmp = HOffset + ped->FontXSize * 7, ped->GBounds.Top);
2536 Draw (rp, tmp, ped->GBounds.Top + ped->GBounds.Height - 1);
2539 SetDrPt (rp, 0xFFFF);
2542 RedrawPattern (rp, ped, g);
2544 DrawTrackNumbers (rp, ped);
2549 static void DrawTrackSeparators (struct RastPort *rp, struct PattEditData *ped, UWORD width)
2551 UWORD i, HOffset = ped->TBounds.Left - 1;
2553 for (i = 0; i <= ped->DisplayTracks; i++, HOffset += width)
2555 /* Never draw outside gadget bounds */
2556 if (HOffset >= ped->GBounds.Left + ped->GBounds.Width + 1) break;
2557 RectFill (rp, HOffset - 1, ped->GBounds.Top, HOffset, ped->GBounds.Top + ped->GBounds.Height - 1);
2563 static void DrawTrackNumbers (struct RastPort *rp, struct PattEditData *ped)
2565 struct TextFont *oldfont = rp->Font;
2566 UWORD HOffset = ped->TBounds.Left + ped->FontXSize * 5;
2572 if (GfxBase->LibNode.lib_Version < 39)
2574 rp->Mask = ped->LinesPen;
2575 SetAPen (rp, ped->LinesPen);
2576 SetBPen (rp, ped->BGPen);
2577 SetDrMd (rp, JAM2); /* JAM1 or JAM2... Which one is faster? */
2581 #endif /* !OS30_ONLY */
2582 SetWrMsk (rp, ped->LinesPen);
2583 SetABPenDrMd (rp, ped->LinesPen, ped->BGPen, JAM2);
2586 #endif /* !OS30_ONLY */
2588 SetFont (rp, ped->EditorFont);
2590 for (i = 0; i < ped->DisplayTracks; i++, HOffset += ped->TrackWidth)
2592 Move (rp, HOffset, ped->GBounds.Top + ped->EditorFont->tf_Baseline);
2593 ch = HexValuesNo0[((i+ped->LeftTrack)>>4) & 0xF];
2595 Move (rp, HOffset, ped->GBounds.Top + ped->FontXSize + ped->EditorFont->tf_Baseline);
2596 ch = HexValues[(i+ped->LeftTrack) & 0xF];
2600 SetFont (rp, oldfont);
2605 static void RedrawPattern (struct RastPort *rp, struct PattEditData *ped, struct ExtGadget *g)
2607 EraseCursor (rp, ped);
2609 /* Redraw all lines */
2610 if (ped->DisplayLines)
2611 DrawPatternLines (rp, ped, 0, ped->DisplayLines - 1);
2613 if (ped->Flags & PEF_MARKING)
2614 /* Clear the range rectangle bounds so the next call
2615 * to DrawCursor() will redraw all the range box.
2617 memset (&ped->RangeRect, 0, sizeof (ped->RangeRect));
2619 DrawCursor (rp, ped, g);
2624 static void DrawPatternLines (struct RastPort *rp, struct PattEditData *ped, UWORD min, UWORD max)
2626 /* Draws Pattern display lines. Only lines from <min> to <max> are drawn.
2627 * To redraw all the display, pass min = 0 and max = ped->DisplayLines - 1.
2630 struct Pattern *patt;
2631 struct TextFont *oldfont = rp->Font;
2634 UWORD VOffset = ped->TBounds.Top + ped->EditorFont->tf_Baseline
2635 + min * ped->FontYSize;
2637 /* Note well: I've put 32 and not MAXTRACKS here because 255 tracks would
2638 * have used too much stack. :-(
2640 ALIGNED UBYTE line[MAXTRACKCHARS * 32 + 4];
2643 if (!(patt = ped->Patt)) return;
2645 SetFont (rp, ped->EditorFont);
2648 if (GfxBase->LibNode.lib_Version >= 39)
2650 #endif /* !OS30_ONLY */
2651 SetWriteMask (rp, ped->TextPen | ped->BGPen);
2652 SetABPenDrMd (rp, ped->TextPen, ped->BGPen, JAM2);
2657 rp->Mask = ped->TextPen | ped->BGPen;
2658 SetAPen (rp, ped->TextPen);
2659 SetBPen (rp, ped->BGPen);
2660 SetDrMd (rp, JAM2); /* JAM1 or JAM2... Which one is faster? */
2662 #endif /* !OS30_ONLY */
2665 for (i = min; i <= max; i++)
2669 /* Write Line Numbers column */
2671 if (ped->Flags & PEF_HEXMODE)
2673 *l++ = HexValues[((i+ped->TopLine)>>8) & 0xF];
2674 *l++ = HexValues[((i+ped->TopLine)>>4) & 0xF];
2675 *l++ = HexValues[((i+ped->TopLine) & 0xF)];
2679 *l++ = HexValues[((i+ped->TopLine) / 100) % 10];
2680 *l++ = HexValues[((i+ped->TopLine) / 10) % 10];
2681 *l++ = HexValues[((i+ped->TopLine) % 10)];
2686 for (j = 0; j < ped->DisplayTracks; j++, l += ped->TrackChars)
2687 ped->Note2ASCIIFunc (l, &patt->Notes[j+ped->LeftTrack][i+ped->TopLine]);
2689 Move (rp, ped->GBounds.Left, VOffset);
2690 Text (rp, line, ped->DisplayTracks * ped->TrackChars + 4);
2691 VOffset += ped->FontYSize;
2695 SetWriteMask (rp, ~0);
2697 SafeSetWriteMask (rp, (UBYTE)~0);
2698 #endif /* OS30_ONLY */
2699 SetFont (rp, oldfont);
2704 static void DrawNote (struct RastPort *rp, struct PattEditData *ped)
2706 /* Draws the note under the cursor. DrawNote() won't draw if the cursor
2707 * is outside of the editing area. Range marking mode is also taken into
2708 * account and the colors of the note will be reversed when the note must
2712 struct Pattern *patt;
2713 struct TextFont *oldfont = rp->Font;
2715 UBYTE buf[MAXTRACKCHARS];
2718 if (!(patt = ped->Patt)) return;
2720 /* Is the cursor outside the editing area? */
2722 if ((ped->Line < ped->TopLine) || (ped->Line >= ped->TopLine + ped->DisplayLines) ||
2723 (ped->Track < ped->LeftTrack) || (ped->Track >= ped->LeftTrack + ped->DisplayTracks))
2726 SetFont (rp, ped->EditorFont);
2729 if (GfxBase->LibNode.lib_Version >= 39)
2731 #endif /* OS30_ONLY */
2732 SetWriteMask (rp, ped->TextPen | ped->BGPen);
2733 if (ped->Flags & PEF_MARKING)
2734 SetABPenDrMd (rp, ped->BGPen, ped->TextPen, JAM2);
2736 SetABPenDrMd (rp, ped->TextPen, ped->BGPen, JAM2);
2741 rp->Mask = ped->TextPen | ped->BGPen;
2742 if (ped->Flags & PEF_MARKING)
2744 SetAPen (rp, ped->BGPen);
2745 SetBPen (rp, ped->TextPen);
2749 SetAPen (rp, ped->TextPen);
2750 SetBPen (rp, ped->BGPen);
2754 #endif /* OS30_ONLY */
2757 ped->Note2ASCIIFunc (buf, &patt->Notes[ped->Track][ped->Line]);
2759 Move (rp, ped->TBounds.Left + ((ped->Track - ped->LeftTrack) * ped->TrackWidth),
2760 ped->TBounds.Top + ped->EditorFont->tf_Baseline + (ped->Line - ped->TopLine) * ped->FontYSize);
2761 Text (rp, buf, ped->TrackChars);
2764 SetWriteMask (rp, (UBYTE)~0);
2766 SafeSetWriteMask (rp, (UBYTE)~0);
2767 #endif /* OS30_ONLY */
2769 SetFont (rp, oldfont);
2776 void ASMCALL Note2ASCIIBlank0 (REG(a1, UBYTE *s), REG(a2, struct Note *note))
2778 /* Fill buffer <s> with the ASCII representation of a
2779 * Note structure. <s> will be able to hold at
2780 * least <ped->TrackChars> characters.
2783 *((ULONG *)s) = TextNotes[note->Note];
2787 s[3] = HexValuesNo0[note->Inst>>4];
2788 s[4] = HexValues[note->Inst & 0x0F];
2798 if (note->EffNum || note->EffVal)
2800 s[6] = HexValues[note->EffNum];
2801 s[7] = HexValues[note->EffVal>>4];
2802 s[8] = HexValues[note->EffVal & 0xF];
2806 *((ULONG *)(s+6)) = ' . ';
2811 void ASMCALL Note2ASCII (REG(a1, UBYTE *s), REG(a2, struct Note *note))
2813 /* Fill buffer <s> with the ASCII representation of a
2814 * Note structure. <s> will be able to hold at
2815 * least <ped->TrackChars> characters.
2818 *((ULONG *)s) = note->Note ? TextNotes[note->Note] : '--- ';
2820 s[3] = HexValuesNo0[note->Inst>>4];
2821 s[4] = HexValues[note->Inst & 0x0F];
2825 s[6] = HexValues[note->EffNum];
2826 s[7] = HexValues[note->EffVal>>4];
2827 s[8] = HexValues[note->EffVal & 0xF];
2831 #endif /* PORTABLE */
2835 static UWORD ScrollPattern (struct RastPort *rp, struct PattEditData *ped, struct ExtGadget *g, UWORD lefttrack, UWORD topline)
2837 * Scroll the display to the new position <lefttrack>, <topline>.
2840 * 0 - no scrolling occurred,
2841 * SCROLLED_VERT - vertical scroll occurred,
2842 * SCROLLED_HORIZ - horizontal scroll occurred,
2843 * SCROLLED_VERT | SCROLLED_HORIZ - scrolled in both directions.
2846 if (ped->LeftTrack != lefttrack)
2848 UWORD retval = SCROLLED_HORIZ | ped->TopLine != topline;
2850 ped->LeftTrack = lefttrack;
2851 ped->TopLine = topline;
2853 EraseCursor (rp, ped);
2854 DrawTrackNumbers (rp, ped);
2855 RedrawPattern (rp, ped, g);
2861 UWORD scroll_lines = abs(ped->TopLine - topline);
2863 /* Redraw everything if more than an half of the screen
2864 * has scrolled. When in mark mode, the scroll limit is set
2865 * to two thirds of the display, because redrawing the mark
2866 * region takes up a lot of time.
2868 //if (scroll_lines > ((ped->Flags & PEF_MARKING) ? ((ped->DisplayLines * 3) >> 1) : (ped->DisplayLines >> 1)))
2869 if (scroll_lines > (ped->DisplayLines * 3) >> 1)
2871 ped->LeftTrack = lefttrack;
2872 ped->TopLine = topline;
2874 EraseCursor (rp, ped);
2875 RedrawPattern (rp, ped, g);
2876 return SCROLLED_VERT;
2880 WORD scroll_dy = (topline - ped->TopLine) * ped->FontYSize;
2882 EraseCursor (rp, ped);
2884 /* Scroll range rectangle */
2886 ped->RangeRect.MinY -= scroll_dy;
2887 ped->RangeRect.MaxY -= scroll_dy;
2889 if (ped->RangeRect.MinY < ped->TBounds.Top)
2890 ped->RangeRect.MinY = ped->TBounds.Top;
2891 if (ped->RangeRect.MaxY >= ped->TBounds.Top + ped->TBounds.Height)
2892 ped->RangeRect.MaxY = ped->TBounds.Top + ped->TBounds.Height - 1;
2894 /* We use ClipBlit() to scroll the pattern because it doesn't clear
2895 * the scrolled region like ScrollRaster() would do. Unfortunately,
2896 * ClipBlit() does not scroll along the damage regions, so we also
2897 * call ScrollRaster() with the mask set to 0, which will scroll the
2898 * layer damage regions without actually modifying the display.
2902 SetWriteMask (rp, ped->TextPen | ped->BGPen);
2904 SafeSetWriteMask (rp, ped->TextPen | ped->BGPen);
2905 #endif /* OS30_ONLY */
2909 ClipBlit (rp, ped->GBounds.Left, ped->TBounds.Top + scroll_dy,
2910 rp, ped->GBounds.Left, ped->TBounds.Top,
2911 ped->TBounds.Width + (ped->TBounds.Left - ped->GBounds.Left), ped->TBounds.Height - scroll_dy,
2915 ClipBlit (rp, ped->GBounds.Left, ped->TBounds.Top,
2916 rp, ped->GBounds.Left, ped->TBounds.Top - scroll_dy,
2917 ped->TBounds.Width + (ped->TBounds.Left - ped->GBounds.Left), ped->TBounds.Height + scroll_dy,
2921 /* This will scroll the layer damage regions without actually
2922 * scrolling the display.
2924 if (rp->Layer->Flags & LAYERSIMPLE)
2927 SetWriteMask (rp, 0);
2929 SafeSetWriteMask (rp, 0);
2930 #endif /* OS30_ONLY */
2932 ScrollRaster (rp, 0, scroll_dy,
2933 ped->GBounds.Left, ped->TBounds.Top,
2934 ped->TBounds.Left + ped->TBounds.Width - 1,
2935 ped->TBounds.Top + ped->TBounds.Height - 1);
2938 ped->LeftTrack = lefttrack;
2939 ped->TopLine = topline;
2943 DrawPatternLines (rp, ped, ped->DisplayLines - scroll_lines, ped->DisplayLines-1);
2946 DrawPatternLines (rp, ped, 0, scroll_lines - 1);
2950 SetWriteMask (rp, ~0);
2952 SafeSetWriteMask (rp, (UBYTE)~0);
2953 #endif /* OS30_ONLY */
2955 DrawCursor (rp, ped, g);
2957 return SCROLLED_VERT;
2967 INTCALL static void TimerIntServer (REG(a1) struct ExtGadget *g)
2969 struct PattEditData *ped = INST_DATA (OCLASS(g), g); /*!*/
2971 /* Remove TimerIO for further usage */
2972 GetMsg (&ped->TimerPort);
2974 if ((ped->Flags & PEF_SCROLLING) && ped->TopLine)
2976 SetGadgetAttrs (g, ped->MyWindow, NULL,
2980 /* Send another request for next scroll */
2981 ped->TimerIO.tr_node.io_Command = TR_ADDREQUEST;
2982 ped->TimerIO.tr_time.tv_micro = 500000;
2983 BeginIO ((struct IORequest *)&ped->TimerIO);
2991 * Class library support functions
2994 HOOKCALL struct ClassLibrary * _UserLibInit (REG(a6, struct ClassLibrary *mybase))
2996 SysBase = *((struct ExecBase **)4); /* Initialize SysBase */
2998 IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", WANTED_LIBVER);
2999 GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library", WANTED_LIBVER);
3000 UtilityBase = (struct UtilityBase *) OpenLibrary ("utility.library", WANTED_LIBVER);
3001 KeymapBase = OpenLibrary ("keymap.library", 36); /* Kick V37 has keymap V36! */
3003 if (!(IntuitionBase && GfxBase && UtilityBase && KeymapBase))
3005 _UserLibCleanup (mybase);
3009 if (mybase->cl_Class = MakeClass (PATTEDITCLASS, GADGETCLASS, NULL, sizeof (struct PattEditData), 0))
3011 mybase->cl_Class->cl_Dispatcher.h_Entry = (ULONG (*)()) PattEditDispatcher;
3012 AddClass (mybase->cl_Class);
3016 _UserLibCleanup (mybase);
3025 HOOKCALL struct ClassLibrary * _UserLibCleanup (REG(a6, struct ClassLibrary *mybase))
3027 if (mybase->cl_Class)
3028 if (!FreeClass (mybase->cl_Class))
3031 /* The tests against NULL are needed here because CloseLibrary()
3032 * in V34 crashes when passed a NULL pointer, and this
3033 * function might get called when someone tries to load this
3034 * library on an 1.3 system.
3036 if (KeymapBase) CloseLibrary ((struct Library *)KeymapBase);
3037 if (UtilityBase) CloseLibrary ((struct Library *)UtilityBase);
3038 if (GfxBase) CloseLibrary ((struct Library *)GfxBase);
3039 if (IntuitionBase) CloseLibrary ((struct Library *)IntuitionBase);
3046 HOOKCALL Class * _GetEngine (REG(a6, struct ClassLibrary *mybase))
3048 return (mybase->cl_Class);