Initial commit.
[amiga/xmodule.git] / SongInfoWin.c
1 /*
2 **      SongInfoWin.c
3 **
4 **      Copyright (C) 1993,94,95,96 Bernardo Innocenti
5 **
6 **      Handle Song Information panel.
7 */
8
9 #include <exec/nodes.h>
10 #include <intuition/intuition.h>
11 #include <intuition/gadgetclass.h>
12 #include <libraries/gadtools.h>
13
14 #include <proto/exec.h>
15 #include <proto/intuition.h>
16 #include <proto/gadtools.h>
17 #include <proto/xmodule.h>
18
19 #include "XModulePriv.h"
20 #include "Gui.h"
21
22
23 /* Gadgets IDs */
24
25 enum
26 {
27         GD_SongInfoGroup0,
28                 GD_SongInfoGroup1,
29                         GD_SongList,
30                         GD_SongInfoGroup2,
31                                 GD_NewSong,
32                                 GD_OpenSong,
33                                 GD_SaveSong,
34                                 GD_DelSong,
35                 GD_SongInfoGroup3,
36                         GD_SongName,
37                         GD_AuthorName,
38                 GD_SongInfoGroup4,
39                         GD_SongInfoGroup5,
40                                 GD_Tempo,
41                                 GD_Speed,
42                                 GD_Restart,
43                         GD_SongInfoGroup6,
44                                 GD_SongLength,
45                                 GD_Patterns,
46                                 GD_Tracks,
47                 GD_SongInfoGroup7,
48                         GD_TotalSize,
49                         GD_InstSize,
50
51         SongInfo_CNT
52 };
53
54
55
56
57 /* Local function Prototypes */
58
59 static void SongInfoPostOpen    (void);
60
61 static void SongListClicked             (struct WinUserData *wud);
62 static void SongNameClicked             (struct WinUserData *wud);
63 static void AuthorNameClicked   (struct WinUserData *wud);
64 static void TempoClicked                (struct WinUserData *wud);
65 static void SpeedClicked                (struct WinUserData *wud);
66 static void RestartClicked              (struct WinUserData *wud);
67 static void NewSongClicked              (struct WinUserData *wud);
68 static void OpenSongClicked             (struct WinUserData *wud);
69 static void DelSongClicked              (struct WinUserData *wud);
70 static void SaveSongClicked             (struct WinUserData *wud);
71
72 static void SongInfoMiMergeSongs        (void);
73 static void SongInfoMiJoinSongs         (void);
74 static void SongInfoMiClearSong         (void);
75
76
77
78 static struct NewMenu SongInfoNewMenu[] =
79 {
80         NM_TITLE, (STRPTR)MSG_SONG_MEN, NULL, 0, NULL, NULL,
81         NM_ITEM, (STRPTR)MSG_MERGE_SONGS_MEN, "M", 0, 0L, (APTR)SongInfoMiMergeSongs,
82         NM_ITEM, (STRPTR)MSG_JOIN_SONGS_MEN, "J", 0, 0L, (APTR)SongInfoMiJoinSongs,
83         NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
84         NM_ITEM, (STRPTR)MSG_CLEAR_MEN, "K", 0, 0L, (APTR)SongInfoMiClearSong,
85         NM_END, NULL, NULL, 0, 0L, NULL
86 };
87
88
89
90 static ULONG SongInfoArgs[] =
91 {
92         HGROUP_KIND, 0,
93                 LISTVIEW_KIND,  (ULONG)SongListClicked,         0,      NULL, TAG_DONE,
94                 VGROUP_KIND, 0,
95                         BUTTON_KIND,    (ULONG)NewSongClicked,  MSG_UNDERSCORE_NEW_GAD, TAG_DONE,
96                         BUTTON_KIND,    (ULONG)OpenSongClicked, MSG_OPEN_GAD,                   TAG_DONE,
97                         BUTTON_KIND,    (ULONG)SaveSongClicked, MSG_SAVE_GAD,                   TAG_DONE,
98                         BUTTON_KIND,    (ULONG)DelSongClicked,  MSG_DEL_GAD,                    TAG_DONE,
99                         ENDGROUP_KIND,
100                 ENDGROUP_KIND,
101         VGROUP_KIND,    BBFT_RIDGE,
102                 STRING_KIND,    (ULONG)SongNameClicked,         MSG_SONG_NAME_GAD,              31,     TAG_DONE,
103                 STRING_KIND,    (ULONG)AuthorNameClicked,       MSG_AUTHOR_NAME_GAD,    63,     TAG_DONE,
104                 ENDGROUP_KIND,
105         HGROUP_KIND,    BBFT_RIDGE,
106                 VGROUP_KIND, 0,
107                         INTEGER_KIND,   (ULONG)TempoClicked,    MSG_DEF_TEMPO_GAD,      3,      TAG_DONE,
108                         INTEGER_KIND,   (ULONG)SpeedClicked,    MSG_DEF_SPEED_GAD,      3,      TAG_DONE,
109                         INTEGER_KIND,   (ULONG)RestartClicked,  MSG_RESTART_GAD,        3,      TAG_DONE,
110                         ENDGROUP_KIND,
111                 VGROUP_KIND, 0,
112                         NUMBER_KIND, MSG_LENGHT_GAD,            3, TAG_DONE,
113                         NUMBER_KIND, MSG_NUM_PATTS_GAD,         3, TAG_DONE,
114                         NUMBER_KIND, MSG_NUM_TRACKS_GAD,        3, TAG_DONE,
115                         ENDGROUP_KIND,
116                 ENDGROUP_KIND,
117         VGROUP_KIND, BBFT_RIDGE,
118                 NUMBER_KIND, MSG_TOT_MOD_SIZE_GAD,      7, TAG_DONE,
119                 NUMBER_KIND, MSG_TOT_INST_SIZE_GAD,     7, TAG_DONE,
120                 ENDGROUP_KIND,
121         ENDGROUP_KIND
122 };
123
124
125
126 XDEF LONG SongInfoWinTags[] =
127 {
128         XMWIN_NewMenu,          (LONG)SongInfoNewMenu,
129         XMWIN_LayoutArgs,       (LONG)SongInfoArgs,
130         XMWIN_GCount,           SongInfo_CNT,
131         XMWIN_Title,            MSG_SONGINFO_TITLE,
132         XMWIN_WindowFlags,      WFLG_CLOSEGADGET,
133         XMWIN_IDCMPFlags,       NUMBERIDCMP | STRINGIDCMP | LISTVIEWIDCMP | INTEGERIDCMP | BUTTONIDCMP | IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW | IDCMP_MENUPICK,
134         XMWIN_PostOpenFunc,     (LONG)SongInfoPostOpen,
135         XMWIN_DropIconFunc,     (LONG)ToolBoxDropIcon,
136         XMWIN_HelpNode,         (LONG)"SongInfo",
137         TAG_DONE
138 };
139
140
141
142 static void SongInfoPostOpen (void)
143 {
144         UpdateSongInfoList();
145         UpdateSongInfo();
146 }
147
148
149
150 /**********************/
151 /* SongInfo Functions */
152 /**********************/
153
154
155 GLOBALCALL void DetatchSongInfoList (void)
156
157 /* Detatches the SongInfo list from the listview gadget.
158  * Call UpdateSongInfoList() to re-attach it when you are done modifying it.
159  */
160 {
161         struct WinUserData *wud = WDescr[WID_SONGINFO].Wud;
162
163         if (wud && wud->Win)
164                 GT_SetGadgetAttrs (wud->Gadgets[GD_SongList], wud->Win, NULL,
165                         GTLV_Labels, ~0,
166                         TAG_DONE);
167 }
168
169
170
171 GLOBALCALL void UpdateSongInfoList (void)
172
173 /* Updates the SongInfo listview gadget */
174 {
175         struct WinUserData *wud = WDescr[WID_SONGINFO].Wud;
176
177         if (wud && wud->Win)
178         {
179 #ifdef OS30_ONLY
180                 ObtainSemaphoreShared (&XModuleBase->xm_BaseLock);
181 #else
182                 /* Workaround for Pre-V39 ObtainSemaphoreShared() bug (see autodoc) */
183
184                 /* Try to get the shared semaphore */
185                 if (!AttemptSemaphoreShared (&XModuleBase->xm_BaseLock))
186                         /* Check if we can get the exclusive version */
187                         if (!AttemptSemaphore (&XModuleBase->xm_BaseLock))
188                                 /* Oh well, wait for the shared lock */
189                                 ObtainSemaphoreShared (&XModuleBase->xm_BaseLock);
190 #endif /* OS30_ONLY */
191
192                 if (XModuleBase->xm_CurrentSong)
193                 {
194                         struct SongInfo *tmp = (struct SongInfo *)XModuleBase->xm_Songs.mlh_Head;
195                         ULONG songnum = 0;
196
197                         /* Find current song number */
198
199                         while (tmp != XModuleBase->xm_CurrentSong)
200                         {
201                                 tmp = (struct SongInfo *)tmp->Link.ln_Succ;
202                                 songnum++;
203                         }
204
205                         GT_SetGadgetAttrs (wud->Gadgets[GD_SongList], wud->Win, NULL,
206                                 GTLV_Labels,            &XModuleBase->xm_Songs,
207                                 GTLV_Selected,          songnum,
208                                 GTLV_MakeVisible,       songnum,
209                                 TAG_DONE);
210                 }
211
212                 ReleaseSemaphore (&XModuleBase->xm_BaseLock);
213         }
214 }
215
216
217
218 GLOBALCALL void UpdateSongInfo (void)
219
220 /* Update information on the current song */
221 {
222         struct WinUserData *wud = WDescr[WID_SONGINFO].Wud;
223         struct SongInfo *si;
224         DB(ULONG millisecs);
225
226         if (wud && wud->Win)
227                 if (si = xmLockActiveSong (SM_SHARED))
228                 {
229                         SetGadgets (wud,
230                                 GD_SongName,    si->Title,
231                                 GD_AuthorName,  si->Author,
232                                 GD_Tempo,               si->GlobalTempo,
233                                 GD_Speed,               si->GlobalSpeed,
234                                 GD_SongLength,  si->Length,
235                                 GD_Patterns,    si->NumPatterns,
236                                 GD_Tracks,              si->MaxTracks,
237                                 GD_Restart,             si->RestartPos,
238                                 GD_TotalSize,   CalcSongSize (si),
239                                 GD_InstSize,    CalcInstSize (si),
240                                 -1);
241
242                         /* TODO */
243                         DB(millisecs = CalcSongTime (si));
244                         DB(xmDisplayMessage (XMDMF_DEBUG, "Song Time: %02ld:%02ld", millisecs / 60000, (millisecs / 1000) % 60));
245
246                         ReleaseSemaphore (&si->Lock);
247                 }
248
249         UpdateInstrList();
250         UpdatePatternList();
251 }
252
253
254
255 /********************/
256 /* SongInfo Gadgets */
257 /********************/
258
259
260 static void SongListClicked (struct WinUserData *wud)
261 {
262         WORD i;
263         struct SongInfo *tmp;
264
265         ObtainSemaphoreShared (&XModuleBase->xm_BaseLock);
266
267         tmp = (struct SongInfo *)XModuleBase->xm_Songs.mlh_Head;
268
269         for (i = IntuiMsg.Code; (i > 0) && tmp ; i--)
270                 tmp = (struct SongInfo *)tmp->Link.ln_Succ;
271
272         if (tmp) ObtainSemaphoreShared (&tmp->Lock);
273         ReleaseSemaphore (&XModuleBase->xm_BaseLock);
274         if (tmp)
275         {
276                 xmActivateSong (tmp);
277                 ReleaseSemaphore (&tmp->Lock);
278         }
279 }
280
281
282
283 static void SongNameClicked (struct WinUserData *wud)
284 {
285         struct SongInfo *si;
286
287         if (si = xmLockActiveSong(SM_EXCLUSIVE))
288         {
289                 DetatchSongInfoList();
290
291                 SetAttrs (si,
292                         SNGA_Title,     GetString (wud->Gadgets[GD_SongName]),
293                         TAG_DONE);
294
295                 ReleaseSemaphore (&si->Lock);
296
297                 UpdateSongInfoList();
298         }
299 }
300
301
302
303 static void AuthorNameClicked (struct WinUserData *wud)
304 {
305         struct SongInfo *si;
306
307         if (si = xmLockActiveSong(SM_EXCLUSIVE))
308         {
309                 SetAttrs (si,
310                         SNGA_Author,    GetString (wud->Gadgets[GD_AuthorName]),
311                         TAG_DONE);
312
313                 ReleaseSemaphore (&si->Lock);
314         }
315 }
316
317
318
319 static void TempoClicked (struct WinUserData *wud)
320 {
321         struct SongInfo *si;
322
323         if (si = xmLockActiveSong(SM_EXCLUSIVE))
324         {
325                 SetAttrs (si,
326                         SNGA_GlobalTempo,       GetNumber (wud->Gadgets[GD_Tempo]),
327                         TAG_END);
328                 GT_SetGadgetAttrs (wud->Gadgets[GD_Tempo], wud->Win, NULL,
329                         GTIN_Number, si->GlobalTempo,
330                         TAG_DONE);
331
332                 ReleaseSemaphore (&si->Lock);
333         }
334 }
335
336
337
338 static void RestartClicked (struct WinUserData *wud)
339 {
340         struct SongInfo *si;
341
342         if (si = xmLockActiveSong(SM_EXCLUSIVE))
343         {
344                 SetAttrs (si,
345                         SNGA_RestartPos, GetNumber (wud->Gadgets[GD_Restart]),
346                         TAG_END);
347                 GT_SetGadgetAttrs (wud->Gadgets[GD_Restart], wud->Win, NULL,
348                         GTIN_Number, si->RestartPos,
349                         TAG_DONE);
350
351                 ReleaseSemaphore (&si->Lock);
352         }
353 }
354
355
356
357 static void SpeedClicked (struct WinUserData *wud)
358 {
359         struct SongInfo *si;
360
361         if (si = xmLockActiveSong(SM_EXCLUSIVE))
362         {
363                 SetAttrs (si,
364                         SNGA_GlobalSpeed, GetNumber (wud->Gadgets[GD_Speed]),
365                         TAG_END);
366                 GT_SetGadgetAttrs (wud->Gadgets[GD_Speed], wud->Win, NULL,
367                         GTIN_Number, si->GlobalSpeed,
368                         TAG_DONE);
369
370                 ReleaseSemaphore (&si->Lock);
371         }
372 }
373
374
375
376 static void NewSongClicked (struct WinUserData *wud)
377 {
378         struct SongInfo *si;
379
380         if (si = xmCreateSong (
381                 SNGA_ReadyToUse,        TRUE,
382                 XMSNG_AddToList,        -1,
383                 XMSNG_Active,           TRUE,
384                 TAG_DONE))
385                 ReleaseSemaphore (&si->Lock);   /* This is for XMSNG_AddToList */
386         else
387                 DisplayBeep (NULL);
388 }
389
390
391
392 static void OpenSongClicked (struct WinUserData *wud)
393 {
394         StartFileRequest (FREQ_LOADMOD, ToolBoxOpenModule);
395 }
396
397
398
399 static void DelSongClicked (struct WinUserData *wud)
400 {
401         if (ShowRequestArgs (MSG_DISCARD_CURRENT_SONG, MSG_YES_OR_NO, NULL))
402         {
403                 struct SongInfo *si;
404
405                 if (si = xmLockActiveSong (SM_EXCLUSIVE))
406                         xmDeleteSong (si);
407
408                 if (!XModuleBase->xm_CurrentSong)
409                         NewSongClicked(wud);
410         }
411 }
412
413
414 static void SaveSongClicked (struct WinUserData *wud)
415 {
416         struct SongInfo *si;
417
418         LockWindows();
419
420         if (si = xmLockActiveSong (SM_EXCLUSIVE))
421         {
422                 LastErr = xmSaveModuleA (si, si->Path, NULL, NULL);
423                 ReleaseSemaphore (&si->Lock);
424         }
425
426         UnlockWindows();
427 }
428
429
430
431 /******************/
432 /* SongInfo Menus */
433 /******************/
434
435 static void SongInfoMiMergeSongs (void)
436 {
437         struct SongInfo *si1, *si2, *si3;
438
439         LockWindows();
440
441         ObtainSemaphoreShared (&XModuleBase->xm_BaseLock);
442
443         if (si1 = XModuleBase->xm_CurrentSong)
444         {
445                 si2 = (struct SongInfo *)si1->Link.ln_Succ;
446
447                 if (si2->Link.ln_Succ)
448                 {
449                         /* Risking a deadlock??  Hmmm... No!
450                          * Shared locks do not prevent other tasks from
451                          * locking these two songs.
452                          */
453                         ObtainSemaphoreShared (&si1->Lock);
454                         ObtainSemaphoreShared (&si2->Lock);
455                         ReleaseSemaphore (&XModuleBase->xm_BaseLock);
456
457                         si3 = MergeSongs (si1, si2);
458
459                         ReleaseSemaphore (&si1->Lock);
460                         ReleaseSemaphore (&si2->Lock);
461
462                         if (si3) xmAddSongA (si3, si2, NULL);
463                 }
464                 else
465                 {
466                         ReleaseSemaphore (&XModuleBase->xm_BaseLock);
467                         xmDisplayMessageA (XMDMF_ERROR | XMDMF_USECATALOG,
468                                 (APTR)MSG_MERGE_REQUIRES_TWO_SONGS, NULL);
469                 }
470         }
471         else
472         {
473                 ReleaseSemaphore (&XModuleBase->xm_BaseLock);
474                 DisplayBeep (Scr);
475         }
476
477         ReleaseSemaphore (&XModuleBase->xm_BaseLock);
478         UnlockWindows();
479 }
480
481
482
483 static void SongInfoMiJoinSongs (void)
484 {
485         struct SongInfo *si1, *si2, *si3;
486
487         LockWindows();
488
489         ObtainSemaphoreShared (&XModuleBase->xm_BaseLock);
490
491         if (si1 = XModuleBase->xm_CurrentSong)
492         {
493                 si2 = (struct SongInfo *)si1->Link.ln_Succ;
494
495                 if (si2->Link.ln_Succ)
496                 {
497                         /* Risking a deadlock??  Hmmm... No!
498                          * Shared locks do not prevent other tasks from
499                          * locking these two songs.
500                          */
501                         ObtainSemaphoreShared (&si1->Lock);
502                         ObtainSemaphoreShared (&si2->Lock);
503                         ReleaseSemaphore (&XModuleBase->xm_BaseLock);
504
505                         si3 = JoinSongs (si1, si2);
506
507                         ReleaseSemaphore (&si1->Lock);
508                         ReleaseSemaphore (&si2->Lock);
509
510                         xmAddSongA (si3, si2, NULL);
511                 }
512                 else
513                 {
514                         ReleaseSemaphore (&XModuleBase->xm_BaseLock);
515                         xmDisplayMessageA (XMDMF_ERROR | XMDMF_USECATALOG,
516                                 (APTR)MSG_JOIN_REQUIRES_TWO_SONGS, NULL);
517                 }
518         }
519         else
520         {
521                 ReleaseSemaphore (&XModuleBase->xm_BaseLock);
522                 DisplayBeep (Scr);
523         }
524
525         UnlockWindows();
526 }
527
528
529
530 static void SongInfoMiClearSong (void)
531 {
532         NewWindow (WID_CLEAR);
533 }