4 ** Copyright (C) 1994,95,96 Bernardo Innocenti
6 ** Parts of the code have been inspired by ScrollerWindow 0.3 demo
7 ** Copyright © 1994 Christoph Feck, TowerSystems.
9 ** Pattern editor handling functions.
12 ** Diagram of object interconnections:
15 ** ScrollButtonClass objects
16 ** +----------+ +---------+ +----------+ +----------+
17 ** | UpButton | | DnButton| | SxButton | | DxButton |
18 ** +----------+ +---------+ +----------+ +----------+
19 ** | GA_ID = | GA_ID = | GA_ID = | GA_ID =
20 ** | PATTA_Up | PATTA_Down | PATTA_Left | PATTA_Right
23 ** | | +------------------+ |
24 ** | | | +----------------------------+
25 ** | | | | propgclass object icclass object
26 ** | | | | +----------------+ +-----------------+
27 ** | | | | +--| HSlider |<--------------------| EditorToHSlider |
28 ** | | | | | +----------------+ PATTA_LeftTrack = +-----------------+
29 ** | | | | | PGA_Top = PGA_Top ^
30 ** | | | | | PATTA_TopLine PATTA_DisplayTracks = |
31 ** | | | | | PGA_Visible |
32 ** | | | | | +-----------------------------+
34 ** +---------------+ ************
35 ** | PattEditGad |----------->* Model *----------------> IDCMP_IDCMPUPDATE
36 ** +---------------+ ************ PATTA_CursLine to PatternWin
37 ** ^ | PATTA_CursTrack
38 ** | propgclass object |
39 ** | PGA_Top = PATTA_TopLine V icclass object
40 ** +----------------+ +-----------------+
41 ** | VSlider |<------| EditorToVSlider | PATTA_TopLine = PGA_Top
42 ** +----------------+ +-----------------+ PATTA_DisplayLines = PGA_Visible
46 #include <intuition/intuition.h>
47 #include <intuition/icclass.h>
48 #include <intuition/gadgetclass.h>
49 #include <intuition/imageclass.h>
50 #include <graphics/gfxbase.h>
51 #include <libraries/gadtools.h>
52 #include <libraries/iffparse.h>
53 #include <libraries/patteditclass.h>
55 #include <proto/exec.h>
56 #include <proto/intuition.h>
57 #include <proto/graphics.h>
58 #include <proto/layers.h>
59 #include <proto/utility.h>
60 #include <proto/dos.h>
61 #include <proto/iffparse.h>
62 #include <proto/diskfont.h>
63 #include <proto/xmodule.h>
65 #include "XModulePriv.h"
67 #include "CustomClasses.h"
84 /* Local function prototypes */
86 static struct Gadget *CreatePattEdit (void);
87 static struct Gadget *LayoutPatternWin (struct WinUserData *wud);
89 static void PatternPostOpen (struct WinUserData *wud);
90 static void PatternWindowCleanup(struct WinUserData *wud);
92 static void RenderPatternWindow (struct WinUserData *wud);
93 static void HandlePatternIDCMP (struct WinUserData *wud);
94 static void PatternLoad (STRPTR name, ULONG num, ULONG count);
95 static LONG PatternSave (STRPTR name, struct Pattern *patt);
97 static void PatternMiOpen (void);
98 static void PatternMiSave (void);
99 static void PatternMiSaveAs (void);
100 static void PatternMiSize (void);
101 static void PatternMiMark (struct WinUserData *wud);
102 static void PatternMiCut (struct WinUserData *wud);
103 static void PatternMiCopy (struct WinUserData *wud);
104 static void PatternMiPaste (struct WinUserData *wud);
105 static void PatternMiErase (struct WinUserData *wud);
106 static void PatternMiUndo (struct WinUserData *wud);
107 static void PatternMiRedo (struct WinUserData *wud);
108 static void PatternMiSettings (void);
114 static struct Library *PattEditBase = NULL;
115 static struct TextFont *EditorFont = NULL;
116 static Object *Model = NULL,
117 *EditorToVSlider = NULL,
118 *EditorToHSlider = NULL;
120 static UBYTE WindowTitle[128];
121 static UBYTE TitleInfo[16];
125 XDEF struct PattSwitches PattSwitches =
127 0, 1, /* AdvanceTracks, AdvanceLines */
128 32, 8192, /* MaxUndoLevels, MaxUndoMem */
130 SCROLLERPLACE_RIGHT, /* VScrollerPlace */
131 SCROLLERPLACE_BOTTOM, /* HScrollerPlace */
132 0, 0, /* ClipboardUnit, Pad0 */
133 10, 0, /* TrackChars, Backdrop */
134 0, 1, 2, 2 /* BGPen, TextPen, LinesPen, TinyLinesPen */
138 static LONG MapVSlider2Editor[] =
140 PGA_Top, PEA_TopLine,
144 static LONG MapHSlider2Editor[] =
146 PGA_Top, PEA_LeftTrack,
150 static LONG MapEditorToVSlider[] =
152 PEA_TopLine, PGA_Top,
153 PEA_DisplayLines, PGA_Visible,
157 static LONG MapEditorToHSlider[] =
159 PEA_LeftTrack, PGA_Top,
160 PEA_DisplayTracks, PGA_Visible,
164 static LONG MapUp2Editor[] =
170 static LONG MapDn2Editor[] =
176 static LONG MapSx2Editor[] =
182 static LONG MapDx2Editor[] =
190 static struct NewMenu PatternNewMenu[] = {
191 NM_TITLE, (STRPTR)MSG_PATTERNS_MEN, NULL, 0, NULL, NULL,
192 NM_ITEM, (STRPTR)MSG_OPEN_MEN, (STRPTR)"O", 0, 0L, (APTR)PatternMiOpen,
193 NM_ITEM, (STRPTR)MSG_SAVE_MEN, (STRPTR)"S", 0, 0L, (APTR)PatternMiSave,
194 NM_ITEM, (STRPTR)MSG_SAVE_AS_MEN, (STRPTR)"A", 0, 0L, (APTR)PatternMiSaveAs,
195 NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
196 NM_ITEM, (STRPTR)MSG_SIZE_MEN, NULL, 0, 0L, (APTR)PatternMiSize,
197 NM_TITLE, (STRPTR)MSG_EDIT_MEN, NULL, 0, NULL, NULL,
198 NM_ITEM, (STRPTR)MSG_MARK_MEN, (STRPTR)"B", 0, 0L, (APTR)PatternMiMark,
199 NM_ITEM, (STRPTR)MSG_CUT_MEN, (STRPTR)"X", 0, 0L, (APTR)PatternMiCut,
200 NM_ITEM, (STRPTR)MSG_COPY_MEN, (STRPTR)"C", 0, 0L, (APTR)PatternMiCopy,
201 NM_ITEM, (STRPTR)MSG_PASTE_MEN, (STRPTR)"V", 0, 0L, (APTR)PatternMiPaste,
202 NM_ITEM, (STRPTR)MSG_ERASE_MEN, (STRPTR)"E", 0, 0L, (APTR)PatternMiErase,
203 NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
204 NM_ITEM, (STRPTR)MSG_UNDO_MEN, (STRPTR)"U", 0, 0L, (APTR)PatternMiUndo,
205 NM_ITEM, (STRPTR)MSG_REDO_MEN, (STRPTR)"R", 0, 0L, (APTR)PatternMiRedo,
206 NM_TITLE, (STRPTR)MSG_SETTINGS_MEN, NULL, 0, NULL, NULL,
207 NM_ITEM, (STRPTR)MSG_EDITOR_SETTINGS_MEN, (STRPTR)"P", 0, 0L, (APTR)PatternMiSettings,
208 NM_END, NULL, NULL, 0, 0L, NULL };
212 XDEF LONG PatternWinTags[] =
214 TAG_IGNORE, TRUE, /* WA_SizeB(Left|Right) */
216 WA_BackFill, LAYERS_NOBACKFILL,
217 #endif /* OS30_ONLY */
218 XMWIN_NewMenu, (LONG)PatternNewMenu,
219 XMWIN_LayoutFunc, (LONG)LayoutPatternWin,
220 XMWIN_GCount, Pattern_CNT,
221 XMWIN_Title, MSG_PATTERN_TITLE,
222 XMWIN_WindowFlags, WFLG_CLOSEGADGET | WFLG_ACTIVATE|
223 WFLG_SIZEGADGET | WFLG_SIMPLE_REFRESH | WFLG_NOCAREREFRESH,
224 XMWIN_IDCMPFlags, IDCMP_MENUPICK|IDCMP_CLOSEWINDOW|IDCMP_ACTIVEWINDOW|IDCMP_INACTIVEWINDOW|IDCMP_NEWSIZE|IDCMP_IDCMPUPDATE|IDCMP_INTUITICKS,
225 XMWIN_IDCMPFunc, (LONG)HandlePatternIDCMP,
226 XMWIN_PostOpenFunc, (LONG)PatternPostOpen,
227 XMWIN_LayoutCleanup,(LONG)PatternWindowCleanup,
228 XMWIN_HelpNode, (LONG)"Pattern",
234 static struct Gadget *CreatePattEdit (void)
236 /* We do not initialize PEA_Pattern right now because
237 * it is done later by UpdatePattern().
239 return ((struct Gadget *)NewObject (NULL, PATTEDITCLASS,
241 GA_Left, ((PattSwitches.VScrollerPlace == SCROLLERPLACE_LEFT) ? SizeWidth : OffX),
243 GA_RelWidth, - SizeWidth - ((PattSwitches.VScrollerPlace == SCROLLERPLACE_LEFT) ? Scr->WBorRight : OffX),
244 GA_RelHeight, - OffY - (((PattSwitches.HScrollerPlace == SCROLLERPLACE_BOTTOM) ||
245 (PattSwitches.VScrollerPlace != SCROLLERPLACE_RIGHT)) ? SizeHeight : Scr->WBorBottom),
246 PEA_TextFont, EditorFont ? EditorFont : TopazFont,
247 PEA_AdvanceCurs, (PattSwitches.AdvanceTracks << 16) | PattSwitches.AdvanceLines,
248 PEA_MaxUndoLevels, PattSwitches.MaxUndoLevels,
249 PEA_MaxUndoMem, PattSwitches.MaxUndoMem,
250 PEA_Flags, PattSwitches.Flags,
251 PEA_TrackChars, PattSwitches.TrackChars,
252 PEA_BGPen, PattSwitches.BGPen,
253 PEA_TextPen, PattSwitches.TextPen,
254 PEA_LinesPen, PattSwitches.LinesPen,
255 PEA_TinyLinesPen, PattSwitches.TinyLinesPen,
261 static struct Gadget *LayoutPatternWin (struct WinUserData *wud)
263 struct Gadget *pattedit;
266 if (!(PattEditBase = MyOpenLibrary (PATTEDITNAME, PATTEDITVERS)))
270 ULONG numcols = 1 << Scr->RastPort.BitMap->Depth; /**/
272 if (PattSwitches.TextPen >= numcols)
273 PattSwitches.TextPen = 1;
275 if (PattSwitches.LinesPen >= numcols)
276 PattSwitches.LinesPen = 2;
278 if (PattSwitches.TinyLinesPen >= numcols)
279 PattSwitches.TinyLinesPen = 2;
282 if (!(EditorFont = OpenFont (&EditorAttr)))
284 EditorFont = OpenDiskFont (&EditorAttr);
288 CantOpenLib (EditorAttr.ta_Name, 0);
289 EditorFont = OpenFont (&TopazAttr);
293 PatternWinTags[0] = (PattSwitches.VScrollerPlace == SCROLLERPLACE_RIGHT) ?
294 WA_SizeBRight : WA_SizeBBottom;
296 if (PattSwitches.Backdrop)
298 wud->Flags = WFLG_BORDERLESS | WFLG_BACKDROP | WFLG_SMART_REFRESH | WFLG_NOCAREREFRESH;
299 wud->WindowSize.Left = wud->WindowSize.Top = 0;
300 wud->WindowSize.Width = Scr->Width;
301 wud->WindowSize.Height = Scr->Height;
305 wud->WindowSize.Width = max (wud->WindowSize.Width,
306 EditorFont->tf_XSize * (MINTRACKCHARS + 4));
307 wud->WindowSize.Height = max (wud->WindowSize.Height,
308 EditorFont->tf_YSize * 2);
311 if (!(pattedit = wud->Gadgets[GD_PattEdit] = CreatePattEdit()))
314 if (PattSwitches.VScrollerPlace)
316 if (!(wud->Gadgets[GD_UpButton] = CreateUpButton (GD_UpButton, pattedit, MapUp2Editor, PattSwitches.VScrollerPlace)))
318 if (!(wud->Gadgets[GD_DnButton] = CreateDnButton (GD_DnButton, pattedit, MapDn2Editor, PattSwitches.VScrollerPlace)))
320 if (!(wud->Gadgets[GD_VSlider] = CreateVSlider (GD_VSlider, pattedit, MapVSlider2Editor,
321 wud->Gadgets[GD_UpButton]->Height + wud->Gadgets[GD_DnButton]->Height,
322 PattSwitches.VScrollerPlace)))
326 if (PattSwitches.HScrollerPlace)
328 if (!(wud->Gadgets[GD_SxButton] = CreateSxButton (GD_SxButton, pattedit, MapSx2Editor)))
330 if (!(wud->Gadgets[GD_DxButton] = CreateDxButton (GD_DxButton, pattedit, MapDx2Editor)))
332 if (!(wud->Gadgets[GD_HSlider] = CreateHSlider (GD_HSlider, pattedit, MapHSlider2Editor,
333 wud->Gadgets[GD_DxButton]->Width + wud->Gadgets[GD_SxButton]->Width)))
338 /* Link gadgets together */
340 if (PattSwitches.VScrollerPlace)
342 wud->Gadgets[GD_PattEdit]->NextGadget = wud->Gadgets[GD_UpButton];
343 wud->Gadgets[GD_UpButton]->NextGadget = wud->Gadgets[GD_DnButton];
344 wud->Gadgets[GD_DnButton]->NextGadget = wud->Gadgets[GD_VSlider];
345 if (PattSwitches.HScrollerPlace)
346 wud->Gadgets[GD_VSlider]->NextGadget = wud->Gadgets[GD_SxButton];
348 if (PattSwitches.HScrollerPlace)
350 if (!PattSwitches.VScrollerPlace)
351 wud->Gadgets[GD_PattEdit]->NextGadget = wud->Gadgets[GD_SxButton];
353 wud->Gadgets[GD_SxButton]->NextGadget = wud->Gadgets[GD_DxButton];
354 wud->Gadgets[GD_DxButton]->NextGadget = wud->Gadgets[GD_HSlider];
358 if (PattSwitches.VScrollerPlace || PattSwitches.HScrollerPlace)
360 /* Create the Model */
361 if (Model = NewObject (NULL, MODELCLASS,
362 ICA_TARGET, ICTARGET_IDCMP,
365 /* Connect Editor to Model */
366 SetAttrs (wud->Gadgets[GD_PattEdit],
370 if (PattSwitches.VScrollerPlace)
372 if (EditorToVSlider = NewObject (NULL, ICCLASS,
373 ICA_TARGET, wud->Gadgets[GD_VSlider],
374 ICA_MAP, MapEditorToVSlider,
376 /* Connect Model to VSlider */
377 if (!DoMethod (Model, OM_ADDMEMBER, EditorToVSlider))
378 DisposeObject (EditorToVSlider); EditorToVSlider = NULL;
381 if (PattSwitches.HScrollerPlace)
383 if (EditorToHSlider = NewObject (NULL, ICCLASS,
384 ICA_TARGET, wud->Gadgets[GD_HSlider],
385 ICA_MAP, MapEditorToHSlider,
387 /* Connect Model to HSlider */
388 if (!DoMethod (Model, OM_ADDMEMBER, EditorToHSlider))
389 DisposeObject (EditorToHSlider); EditorToHSlider = NULL;
394 /* Connect Editor to application */
395 SetAttrs (wud->Gadgets[GD_PattEdit],
396 ICA_TARGET, ICTARGET_IDCMP,
399 return wud->Gadgets[GD_PattEdit];
401 /* NOTE: The model will also dispose its members... */
403 DisposeObject (Model); Model = NULL;
404 EditorToVSlider = NULL; EditorToHSlider = NULL;
414 static ULONG __asm BFHookFunc (void)
416 /* No-op backfilling hook. Since we are going to redraw the whole window
417 * anyway, we can disable backfilling. This avoids ugly flashing while
418 * resizing or revealing the window.
420 * This function hasn't the __saveds attribute because it makes no
421 * references to external data.
424 return 1; /* Do nothing */
427 static struct Hook BFHook =
432 #endif /* !OS30_ONLY */
436 static void PatternPostOpen (struct WinUserData *wud)
438 /* Limit window flashing by providing a no-op hook for window
442 InstallLayerHook (wud->Win->WLayer, (LayersBase->lib_Version >= 39) ?
443 ((struct Hook *)LAYERS_NOBACKFILL) : &BFHook);
444 #endif /* !OS30_ONLY */
448 /* Allow window resizing. Minimum size is chosen so that at least
449 * two lines are visible.
451 WindowLimits (wud->Win,
452 wud->Win->BorderLeft + wud->Win->BorderRight + EditorFont->tf_XSize * (10 + 4),
453 wud->Win->BorderTop + wud->Win->BorderBottom + EditorFont->tf_YSize * 2,
459 static void PatternWindowCleanup (struct WinUserData *wud)
461 /* NOTE: The model will also dispose its members. */
462 DisposeObject (Model); Model = NULL;
463 EditorToVSlider = NULL;
464 EditorToHSlider = NULL;
468 DisposeObject (wud->Gadgets[GD_VSlider]);
469 wud->Gadgets[GD_VSlider] = NULL;
470 DisposeObject (wud->Gadgets[GD_HSlider]);
471 wud->Gadgets[GD_HSlider] = NULL;
473 if (wud->Gadgets[GD_UpButton])
475 DisposeObject (wud->Gadgets[GD_UpButton]->GadgetRender);
476 DisposeObject (wud->Gadgets[GD_UpButton]);
477 wud->Gadgets[GD_UpButton] = NULL;
480 if (wud->Gadgets[GD_DnButton])
482 DisposeObject (wud->Gadgets[GD_DnButton]->GadgetRender);
483 DisposeObject (wud->Gadgets[GD_DnButton]);
484 wud->Gadgets[GD_DnButton] = NULL;
487 if (wud->Gadgets[GD_SxButton])
489 DisposeObject (wud->Gadgets[GD_SxButton]->GadgetRender);
490 DisposeObject (wud->Gadgets[GD_SxButton]);
491 wud->Gadgets[GD_SxButton] = NULL;
494 if (wud->Gadgets[GD_DxButton])
496 DisposeObject (wud->Gadgets[GD_DxButton]->GadgetRender);
497 DisposeObject (wud->Gadgets[GD_DxButton]);
498 wud->Gadgets[GD_DxButton] = NULL;
501 DisposeObject (wud->Gadgets[GD_PattEdit]);
502 wud->Gadgets[GD_PattEdit] = NULL;
507 CloseFont (EditorFont);
513 CloseLibrary (PattEditBase);
520 static void HandlePatternIDCMP (struct WinUserData *wud)
522 switch (IntuiMsg.Class)
524 case IDCMP_IDCMPUPDATE:
526 struct TagItem *ti, *tstate = IntuiMsg.IAddress;
527 ULONG line = ((UWORD)~0), track = ((UWORD)~0);
529 while (ti = NextTagItem (&tstate))
541 /* TODO: Increment changes counter of song */
548 if (track != ((UWORD)~0))
550 SPrintf (TitleInfo, " %lu, %lu", track, line);
551 RenderPatternWindow (wud);
557 case IDCMP_ACTIVEWINDOW:
558 case IDCMP_INACTIVEWINDOW:
560 RenderPatternWindow (wud);
563 case IDCMP_INTUITICKS:
564 if (!(wud->Gadgets[GD_PattEdit]->Flags & GFLG_SELECTED))
565 ActivateGadget (wud->Gadgets[GD_PattEdit], wud->Win, NULL);
575 static void RenderPatternWindow (struct WinUserData *wud)
577 /* Prints <TitleInfo> on the right hand of the window title bar */
581 struct TextFont *oldfont;
583 tlen = strlen (TitleInfo); /* Couldn't get it from SPrintf()!! */
585 rp = wud->Win->RPort;
587 SetFont (rp, DrawInfo->dri_Font);
589 twidth = TextLength (rp, TitleInfo, tlen);
591 if (wud->Win->Flags & WFLG_WINDOWACTIVE)
594 if (GfxBase->LibNode.lib_Version >= 39)
595 #endif /* !OS30_ONLY */
596 SetABPenDrMd (rp, DrawInfo->dri_Pens[FILLTEXTPEN],
597 DrawInfo->dri_Pens[FILLPEN], JAM2);
601 SetAPen (rp, DrawInfo->dri_Pens[FILLTEXTPEN]);
602 SetBPen (rp, DrawInfo->dri_Pens[FILLPEN]);
605 #endif /* !OS30_ONLY */
610 if (GfxBase->LibNode.lib_Version >= 39)
611 #endif /* !OS30_ONLY */
612 SetABPenDrMd (rp, DrawInfo->dri_Pens[TEXTPEN],
613 DrawInfo->dri_Pens[BACKGROUNDPEN], JAM2);
617 SetAPen (rp, DrawInfo->dri_Pens[TEXTPEN]);
618 SetBPen (rp, DrawInfo->dri_Pens[BACKGROUNDPEN]);
621 #endif /* !OS30_ONLY */
624 Move (rp, wud->Win->Width - twidth - 60, rp->TxBaseline + 1);
625 Text (rp, TitleInfo, tlen);
627 SetFont (rp, oldfont);
632 GLOBALCALL void UpdatePattern (void)
634 struct WinUserData *wud = WDescr[WID_PATTERN].Wud;
639 struct Pattern *patt;
642 if (si = xmLockActiveSong (SM_SHARED))
644 patt = si->Patt[si->CurrentPatt];
645 currentinst = si->CurrentInst;
647 SPrintf (WindowTitle, "%s/%03ld: %s (%ld/%ld)",
650 patt->Name ? patt->Name : (UBYTE *)"", patt->Tracks, patt->Lines);
652 ReleaseSemaphore (&si->Lock);
658 strcpy (WindowTitle, "Pattern Editor");
661 SetWindowTitles (wud->Win, WindowTitle, NULL);
663 SetGadgetAttrs (wud->Gadgets[GD_PattEdit], wud->Win, NULL,
665 PEA_CurrentInst, currentinst,
668 SetGadgetAttrs (wud->Gadgets[GD_VSlider], wud->Win, NULL,
669 PGA_Total, patt ? patt->Lines : 0,
672 SetGadgetAttrs (wud->Gadgets[GD_HSlider], wud->Win, NULL,
673 PGA_Total, patt ? patt->Tracks : 0,
682 GLOBALCALL void UpdateEditorInst (void)
684 struct WinUserData *wud = WDescr[WID_PATTERN].Wud;
690 if (si = xmLockActiveSong (SM_SHARED))
692 SetGadgetAttrs (wud->Gadgets[GD_PattEdit], wud->Win, NULL,
693 PEA_CurrentInst, si->CurrentInst,
695 ReleaseSemaphore (&si->Lock);
703 static void PatternLoad (STRPTR name, ULONG num, ULONG count)
705 /* Load a pattern from an IFF PATT file. This function is called only
706 * by the file requester handler.
710 struct IFFHandle *iff;
713 if (si = xmLockActiveSong (SM_SHARED))
717 if (iff = AllocIFF())
720 if (iff->iff_Stream = (ULONG) Open (name, MODE_OLDFILE))
722 if (!(err = OpenIFF (iff, IFFF_READ)))
724 LoadPattern (si, si->CurrentPatt + num, iff);
728 Close (iff->iff_Stream);
734 else err = ERROR_NO_FREE_STORE;
736 ReleaseSemaphore (&si->Lock);
738 UpdatePatternList(); // This will also update the Pattern Editor.
748 static LONG PatternSave (STRPTR name, struct Pattern *patt)
750 /* Store a pattern to an IFF PATT file. */
752 struct IFFHandle *iff;
756 if (iff = AllocIFF())
761 iff->iff_Stream = (ULONG) Open (name, MODE_NEWFILE);
766 iff->iff_Stream = (ULONG) OpenClipboard (PattSwitches.ClipboardUnit);
772 if (!(err = OpenIFF (iff, IFFF_WRITE)))
774 SavePattern (iff, patt);
779 Close (iff->iff_Stream);
781 CloseClipboard ((struct ClipboardHandle *)iff->iff_Stream);
787 else err = ERROR_NO_FREE_STORE;
798 static void PatternMiOpen (void)
800 StartFileRequest (FREQ_LOADPATT, PatternLoad);
805 static void PatternMiSave (void)
808 struct Pattern *patt;
811 if (si = xmLockActiveSong (SM_SHARED))
814 patt = si->Patt[si->CurrentPatt];
815 LastErr = PatternSave (patt->Name, patt);
817 ReleaseSemaphore (&si->Lock);
823 static void PatternMiSaveAs (void)
826 struct Pattern *patt;
827 UBYTE name[PATHNAME_MAX];
829 if (si = xmLockActiveSong (SM_SHARED))
833 patt = si->Patt[si->CurrentPatt];
835 strncpy (name, patt->Name, PATHNAME_MAX-1);
836 name[PATHNAME_MAX-1] = '\0';
838 if (FileRequest (FREQ_SAVEINST, name))
839 LastErr = PatternSave (name, patt);
842 ReleaseSemaphore (&si->Lock);
848 static void PatternMiSize (void)
850 NewWindow (WID_PATTSIZE);
855 static void PatternMiMark (struct WinUserData *wud)
857 SetGadgetAttrs (wud->Gadgets[GD_PattEdit], wud->Win, NULL,
864 static void PatternMiCut (struct WinUserData *wud)
867 struct Pattern *patt, *cpatt;
868 struct Rectangle markregion;
871 if (si = xmLockActiveSong (SM_SHARED))
873 patt = si->Patt[si->CurrentPatt];
875 if (GetAttr (PEA_MarkRegion, wud->Gadgets[GD_PattEdit], (ULONG *)&markregion))
877 if ((markregion.MaxX == 0) && (markregion.MaxY == 0))
878 return; /* Not in mark mode */
880 if (cpatt = xmAddPattern (si, -1,
881 PATTA_Tracks, markregion.MaxX - markregion.MinX + 1,
882 PATTA_Lines, 0, /* Do not allocate anything */
883 PATTA_Name, patt->Name,
886 cpatt->Lines = markregion.MaxY - markregion.MinY + 1;
888 for (i = 0; i < cpatt->Tracks; i++)
889 cpatt->Notes[i] = patt->Notes[i + markregion.MinX] + markregion.MinY;
891 /* Snap marked region to Clipboard */
892 PatternSave (NULL, cpatt);
894 /* And then clear it */
895 for (i = 0; i < cpatt->Tracks; i++)
896 memset (cpatt->Notes[i], 0, sizeof (struct Note) * cpatt->Lines);
898 /* Free dummy pattern */
900 for (i = 0; i < cpatt->Tracks; i++)
901 cpatt->Notes[i] = NULL;
902 xmRemPattern (si, -1, (ULONG)cpatt);
904 SetGadgetAttrs (wud->Gadgets[GD_PattEdit], wud->Win, NULL,
905 PEA_Pattern, patt, /* Refresh display */
906 PEA_MarkRegion, NULL, /* Stop marking */
911 ReleaseSemaphore (&si->Lock);
917 static void PatternMiCopy (struct WinUserData *wud)
920 struct Pattern *patt, *cpatt;
921 struct Rectangle markregion;
924 if (si = xmLockActiveSong (SM_SHARED))
926 patt = si->Patt[si->CurrentPatt];
928 if (GetAttr (PEA_MarkRegion, wud->Gadgets[GD_PattEdit], (ULONG *)&markregion))
930 if ((markregion.MaxX == 0) && (markregion.MaxY == 0))
931 return; /* Not in mark mode */
933 if (cpatt = xmAddPattern (si, -1,
934 PATTA_Tracks, markregion.MaxX - markregion.MinX + 1,
935 PATTA_Lines, 0, /* Do not allocate anything */
936 PATTA_Name, patt->Name,
939 cpatt->Lines = markregion.MaxY - markregion.MinY + 1;
941 for (i = 0; i < cpatt->Tracks; i++)
942 cpatt->Notes[i] = patt->Notes[i + markregion.MinX] + markregion.MinY;
944 PatternSave (NULL, cpatt);
946 /* Free dummy pattern */
948 for (i = 0; i < cpatt->Tracks; i++)
949 cpatt->Notes[i] = NULL;
950 xmRemPattern (si, -1, (ULONG)cpatt);
952 SetGadgetAttrs (wud->Gadgets[GD_PattEdit], wud->Win, NULL,
953 PEA_MarkRegion, NULL, /* Stop marking */
958 ReleaseSemaphore (&si->Lock);
964 static void PatternMiPaste (struct WinUserData *wud)
967 struct IFFHandle *iff;
968 struct Pattern *patt, *cpatt;
972 if (si = xmLockActiveSong (SM_EXCLUSIVE))
974 patt = si->Patt[si->CurrentPatt];
977 /* Get pattern in Clip */
979 if (iff = AllocIFF())
982 if (iff->iff_Stream = (ULONG) OpenClipboard (PattSwitches.ClipboardUnit))
984 if (!OpenIFF (iff, IFFF_READ))
986 if (cpatt = LoadPattern (si, -1, iff))
988 if (GetAttr (PEA_CursTrack, wud->Gadgets[GD_PattEdit], &track) &&
989 GetAttr (PEA_CursLine, wud->Gadgets[GD_PattEdit], &line))
991 /* Paste it into the pattern */
993 for (i = 0; i < min (cpatt->Tracks, patt->Tracks - track); i++)
994 CopyMem (cpatt->Notes[i], patt->Notes[i + track] + line,
995 sizeof (struct Note) * min (patt->Lines - line, cpatt->Lines));
997 SetGadgetAttrs (wud->Gadgets[GD_PattEdit], wud->Win, NULL,
998 PEA_Pattern, patt, /* Refresh display */
999 PEA_CursTrack, min (track + cpatt->Tracks, patt->Tracks) - 1,
1000 PEA_CursLine, min (line + cpatt->Lines, patt->Lines) - 1,
1004 xmRemPattern (si, -1, (ULONG)cpatt);
1009 CloseClipboard ((struct ClipboardHandle *)iff->iff_Stream);
1015 ReleaseSemaphore (&si->Lock);
1021 static void PatternMiErase (struct WinUserData *wud)
1023 struct SongInfo *si;
1024 struct Pattern *patt;
1025 struct Rectangle markregion;
1028 if (si = xmLockActiveSong (SM_EXCLUSIVE))
1030 patt = si->Patt[si->CurrentPatt];
1032 if (GetAttr (PEA_MarkRegion, wud->Gadgets[GD_PattEdit], (ULONG *)&markregion))
1034 if ((markregion.MaxX == 0) && (markregion.MaxY == 0))
1035 return; /* Not in mark mode */
1037 /* Clear marked region */
1038 for (i = markregion.MinX; i <= markregion.MaxX; i++)
1039 memset (patt->Notes[i] + markregion.MinY, 0, sizeof (struct Note) *
1040 (markregion.MaxY - markregion.MinY + 1));
1042 SetGadgetAttrs (wud->Gadgets[GD_PattEdit], wud->Win, NULL,
1043 PEA_Pattern, patt, /* Refresh display */
1044 PEA_MarkRegion, NULL, /* Stop marking */
1048 ReleaseSemaphore (&si->Lock);
1054 static void PatternMiUndo (struct WinUserData *wud)
1056 SetGadgetAttrs (wud->Gadgets[GD_PattEdit], wud->Win, NULL,
1063 static void PatternMiRedo (struct WinUserData *wud)
1065 SetGadgetAttrs (wud->Gadgets[GD_PattEdit], wud->Win, NULL,
1072 static void PatternMiSettings (void)
1074 NewWindow (WID_PATTPREFS);