diff --git a/js/actionCreators.js b/js/actionCreators.js index 9d4d190f..fa94a67e 100644 --- a/js/actionCreators.js +++ b/js/actionCreators.js @@ -145,7 +145,8 @@ export function setSkinFromFile(skinFile) { type: SET_SKIN_DATA, skinImages: skinData.images, skinColors: skinData.colors, - skinPlaylistStyle: skinData.playlistStyle + skinPlaylistStyle: skinData.playlistStyle, + skinCursors: skinData.cursors }); }; } diff --git a/js/components/Skin.js b/js/components/Skin.js index ae3a87f4..19421cb4 100644 --- a/js/components/Skin.js +++ b/js/components/Skin.js @@ -242,6 +242,10 @@ const imageSelectors = { ] }; +const cursorSelectors = { + PSIZE: ["#playlist-resize-target"] +}; + Object.keys(FONT_LOOKUP).forEach(character => { const key = imageConstFromChar(character); const code = character.charCodeAt(0); @@ -265,6 +269,17 @@ const Skin = props => { }); } }); + Object.keys(cursorSelectors).map(cursorName => { + const imageUrl = props.skinCursors[cursorName]; + if (imageUrl) { + cursorSelectors[cursorName].forEach(selector => { + cssRules.push( + `#winamp2-js ${selector} {cursor: url(${imageUrl}), auto}` + ); + }); + } + }); + if (numExIsUsed(props.skinImages)) { // This alternate number file requires that the minus sign be // formatted differently. @@ -275,6 +290,7 @@ const Skin = props => { return ; }; -export default connect(state => ({ skinImages: state.display.skinImages }))( - Skin -); +export default connect(state => ({ + skinImages: state.display.skinImages, + skinCursors: state.display.skinCursors +}))(Skin); diff --git a/js/reducers.js b/js/reducers.js index e95ace59..63a2aea3 100644 --- a/js/reducers.js +++ b/js/reducers.js @@ -122,6 +122,7 @@ const defaultDisplayState = { working: false, skinImages: {}, skinColors: null, + skinCursors: null, skinPlaylistStyle: {}, visualizerStyle: 2, playlistScrollPosition: 0, @@ -150,12 +151,14 @@ const display = (state = defaultDisplayState, action) => { case CLOSE_WINAMP: return { ...state, closed: true }; case SET_SKIN_DATA: + console.log(action); return { ...state, loading: false, skinImages: action.skinImages, skinColors: action.skinColors, - skinPlaylistStyle: action.skinPlaylistStyle + skinPlaylistStyle: action.skinPlaylistStyle, + skinCursors: action.skinCursors }; case TOGGLE_VISUALIZER_STYLE: return { ...state, visualizerStyle: (state.visualizerStyle + 1) % 3 }; diff --git a/js/skinParser.js b/js/skinParser.js index ef3f7826..f45f8375 100644 --- a/js/skinParser.js +++ b/js/skinParser.js @@ -2,6 +2,39 @@ import SKIN_SPRITES from "./skinSprites"; import JSZip from "../node_modules/jszip/dist/jszip"; // Hack import { parseViscolors, parseIni } from "./utils"; +const shallowMerge = objs => + objs.reduce((prev, img) => Object.assign(prev, img), {}); + +const CURSORS = [ + "CLOSE", + "EQCLOSE", + "EQNORMAL", + "EQSLID", + "EQTITLE", + "MAINMENU", + "MIN", + "NORMAL", + "PCLOSE", + "PNORMAL", + "POSBAR", + "PSIZE", + "PTBAR", + "PVSCROLL", + "PWINBUT", + "PWSNORM", + "PWSSIZE", + "SONGNAME", + "TITLEBAR", + "VOLBAL", + "VOLBAR", + "WINBUT", + "WSCLOSE", + "WSMIN", + "WSNORMAL", + "WSPOSBAR", + "WSWINBUT" +]; + const genImgFromBlob = blob => new Promise(resolve => { const img = new Image(); @@ -51,6 +84,11 @@ async function genSpriteUrisFromFilename(zip, fileName) { return spriteUris; } +async function getCursorFromFilename(zip, fileName) { + const base64 = await genFileFromZip(zip, fileName, "CUR", "base64"); + return `data:image/x-win-bitmap;base64,${base64}`; +} + const defaultVisColors = [ "rgb(0,0,0)", "rgb(24,33,41)", @@ -97,7 +135,15 @@ async function skinParser(zipFile) { ); // Merge all the objects into a single object. Tests assert that sprite keys are unique. - const images = imageObjs.reduce((prev, img) => Object.assign(prev, img), {}); + const images = shallowMerge(imageObjs); + + const cursorObjs = await Promise.all( + CURSORS.map(async cursorName => ({ + [cursorName]: await getCursorFromFilename(zip, cursorName) + })) + ); + + const cursors = shallowMerge(cursorObjs); const viscolorContent = await genFileFromZip(zip, "VISCOLOR", "txt", "text"); const colors = viscolorContent @@ -109,7 +155,7 @@ async function skinParser(zipFile) { ? parseIni(pleditContent) : defaultPlaylistStyle; - return { colors, playlistStyle, images }; + return { colors, playlistStyle, images, cursors }; } export default skinParser;