#ifdef INTERFACE CLASS(XonoticPlayList) EXTENDS(XonoticListBox) METHOD(XonoticPlayList, configureXonoticPlayList, void(entity)) ATTRIB(XonoticPlayList, rowsPerItem, float, 1) METHOD(XonoticPlayList, resizeNotify, void(entity, vector, vector, vector, vector)) METHOD(XonoticPlayList, draw, void(entity)) METHOD(XonoticPlayList, drawListBoxItem, void(entity, float, vector, float)) METHOD(XonoticPlayList, stopSound, void(entity)) METHOD(XonoticPlayList, startSound, void(entity, float)) METHOD(XonoticPlayList, pauseSound, void(entity)) METHOD(XonoticPlayList, clickListBoxItem, void(entity, float, vector)) METHOD(XonoticPlayList, keyDown, float(entity, float, float, float)) METHOD(XonoticPlayList, mouseDrag, float(entity, vector)) METHOD(XonoticPlayList, addToPlayList, void(entity, string)) METHOD(XonoticPlayList, removeSelectedFromPlayList, void(entity)) ATTRIB(XonoticPlayList, playingTrack, string, string_null) ATTRIB(XonoticPlayList, realFontSize, vector, '0 0 0') ATTRIB(XonoticPlayList, columnNameOrigin, float, 0) ATTRIB(XonoticPlayList, columnNameSize, float, 0) ATTRIB(XonoticPlayList, columnNumberOrigin, float, 0) ATTRIB(XonoticPlayList, columnNumberSize, float, 0) ATTRIB(XonoticPlayList, realUpperMargin, float, 0) ATTRIB(XonoticPlayList, origin, vector, '0 0 0') ATTRIB(XonoticPlayList, itemAbsSize, vector, '0 0 0') ATTRIB(XonoticPlayList, lastClickedSound, float, -1) ATTRIB(XonoticPlayList, lastClickedTime, float, 0) ENDCLASS(XonoticPlayList) entity makeXonoticPlayList(); void PlayList_Remove(entity btn, entity me); void PlayList_Remove_All(entity btn, entity me); void StopSound_Click(entity btn, entity me); void StartSound_Click(entity btn, entity me); void PauseSound_Click(entity btn, entity me); void PrevSound_Click(entity btn, entity me); void NextSound_Click(entity btn, entity me); #endif #ifdef IMPLEMENTATION entity makeXonoticPlayList() { entity me; me = spawnXonoticPlayList(); me.configureXonoticPlayList(me); return me; } void XonoticPlayList_configureXonoticPlayList(entity me) { me.nItems = tokenize_console(cvar_string("music_playlist_list0")); me.configureXonoticListBox(me); } void XonoticPlayList_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize) { me.itemAbsSize = '0 0 0'; SUPER(XonoticPlayList).resizeNotify(me, relOrigin, relSize, absOrigin, absSize); me.realFontSize_y = me.fontSize / (me.itemAbsSize_y = (absSize_y * me.itemHeight)); me.realFontSize_x = me.fontSize / (me.itemAbsSize_x = (absSize_x * (1 - me.controlWidth))); me.realUpperMargin = 0.5 * (1 - me.realFontSize_y); me.columnNumberOrigin = 0; me.columnNumberSize = 3 * me.realFontSize_x; me.columnNameOrigin = me.columnNumberSize + me.realFontSize_x; me.columnNameSize = 1 - me.columnNameOrigin - me.realFontSize_x; } void XonoticPlayList_addToPlayList(entity me, string track) { me.nItems = tokenize_console(cvar_string("music_playlist_list0")); if(me.nItems == 0) { cvar_set("music_playlist_list0", track); return; } float i; for(i = 0; i < me.nItems; ++i) { if(argv(i) == track) return; // track is already in playlist } cvar_set("music_playlist_list0", strcat(cvar_string("music_playlist_list0"), " ", track)); } void XonoticPlayList_removeSelectedFromPlayList(entity me) { float i, cpt = FALSE; string s = ""; me.nItems = tokenize_console(cvar_string("music_playlist_list0")); if(me.nItems == 0) return; for(i = 0; i < me.nItems; ++i) { if(i == me.selectedItem) { if(i == me.nItems - 1) me.setSelected(me, me.selectedItem - 1); if(cvar("music_playlist_index") == 0 || cvar("music_playlist_index") == 999) { if(cvar("music_playlist_current0") == i) cpt = TRUE; // current playing track (we can't start next track here because startSound calls tokenize_console) else if(cvar("music_playlist_current0") > i) cvar_set("music_playlist_current0", ftos(cvar("music_playlist_current0") - 1)); } continue; } s = strcat(s, " ", argv(i)); } // we must stop the current playing track if it has been removed // otherwise pause/play button will resume from another track if(s == "") { cvar_set("music_playlist_list0", ""); if(cpt) me.stopSound(me); } else { cvar_set("music_playlist_list0", substring(s, 1, strlen(s))); // remove initial space if(cpt) me.startSound(me, 0); } } void PlayList_Remove(entity btn, entity me) { me.removeSelectedFromPlayList(me); } void PlayList_Remove_All(entity btn, entity me) { cvar_set("music_playlist_list0", ""); me.stopSound(me); me.selectedItem = 0; } float XonoticPlayList_mouseDrag(entity me, vector pos) { float f, i; i = me.selectedItem; f = SUPER(XonoticPlayList).mouseDrag(me, pos); if(me.pressed != 1) // don't change priority if the person is just scrolling { if(me.selectedItem != i) { cvar_set("music_playlist_list0", swapInPriorityList(cvar_string("music_playlist_list0"), me.selectedItem, i)); float c = cvar("music_playlist_current0"); if(c == i) cvar_set("music_playlist_current0", ftos(me.selectedItem)); else if(c == me.selectedItem) cvar_set("music_playlist_current0", ftos(i)); } } return f; } void XonoticPlayList_draw(entity me) { me.nItems = tokenize_console(cvar_string("music_playlist_list0")); SUPER(XonoticPlayList).draw(me); } void XonoticPlayList_drawListBoxItem(entity me, float i, vector absSize, float isSelected) { string s; if(isSelected) draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED); if(argv(i) == me.playingTrack) { float f = cvar("music_playlist_sampleposition0"); if(f == 0 || (((time * 2) & 1) && f > 0)) draw_Text(me.realUpperMargin * eY + (me.columnNumberOrigin + me.columnNumberSize) * eX, chr(0xE000 + 141), me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0); } s = ftos(i+1); draw_CenterText(me.realUpperMargin * eY + (me.columnNumberOrigin + 0.5 * me.columnNumberSize) * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0); s = draw_TextShortenToWidth(argv(i), me.columnNameSize, 0, me.realFontSize); draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 0); } void XonoticPlayList_stopSound(entity me) { // STOP: list 0 is disabled by setting the index to -1 // we set sampleposition0 to -1 to indicate that music is stopped if(cvar("music_playlist_index") == 0 || cvar("music_playlist_index") == 999) { cvar_set("music_playlist_index", "-1"); localcmd("\nwait; music_playlist_sampleposition0 -1\n"); localcmd("\ndefer 3 \"cd play $menu_cdtrack\"\n"); } } void StopSound_Click(entity btn, entity me) { me.stopSound(me); } void XonoticPlayList_startSound(entity me, float offset) { float f; me.nItems = tokenize_console(cvar_string("music_playlist_list0")); if(offset) { if(cvar("music_playlist_index") == -1) return; f = bound(0, cvar("music_playlist_current0") + offset, me.nItems - 1); if(f == cvar("music_playlist_current0")) return; } else f = me.selectedItem; if(me.playingTrack) strunzone(me.playingTrack); me.playingTrack = strzone(argv(f)); // START: list 0 is disabled by setting the index to 999 // we set current0 to the selected track and sampleposition0 to 0 to forget value saved by the engine // then we switch back to list 0 cvar_set("music_playlist_index", "999"); cvar_set("music_playlist_current0", ftos(f)); localcmd("\nwait; music_playlist_sampleposition0 0; wait; music_playlist_index 0\n"); } void StartSound_Click(entity btn, entity me) { me.startSound(me, 0); } void PrevSound_Click(entity btn, entity me) { me.startSound(me, -1); } void NextSound_Click(entity btn, entity me) { me.startSound(me, +1); } void XonoticPlayList_pauseSound(entity me) { // PAUSE: list 0 is disabled by setting the index to 999 // (we know the track is paused because the engine sets sampleposition0 to remember current position) // RESUME: list 0 is enabled by setting the index to 0 // (we reset sampleposition0 to 0 to mark the track as in playing back state) if(cvar("music_playlist_index") == 0) localcmd("\nmusic_playlist_index 999\n"); else if(cvar("music_playlist_index") == 999) localcmd("\nmusic_playlist_index 0; wait; music_playlist_sampleposition0 0\n"); } void PauseSound_Click(entity btn, entity me) { me.pauseSound(me); } void XonoticPlayList_clickListBoxItem(entity me, float i, vector where) { if(i == me.lastClickedSound) if(time < me.lastClickedTime + 0.3) { // DOUBLE CLICK! me.setSelected(me, i); me.startSound(me, 0); } me.lastClickedSound = i; me.lastClickedTime = time; } float XonoticPlayList_keyDown(entity me, float scan, float ascii, float shift) { if(scan == K_ENTER || scan == K_KP_ENTER) { me.startSound(me, 0); return 1; } else if(scan == K_SPACE) { me.pauseSound(me); return 1; } else if(scan == K_DEL || scan == K_KP_DEL || scan == K_BACKSPACE || scan == K_MOUSE3) { me.removeSelectedFromPlayList(me); return 1; } else return SUPER(XonoticPlayList).keyDown(me, scan, ascii, shift); } #endif