This repository has been archived on 2025-11-10. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ClickPlay/main.cpp
T
2021-06-03 20:28:00 +02:00

550 lines
16 KiB
C++

//INCLUDES
#include "framework.h"
#include "resource.h"
#include <ShlObj.h>
#include <string>
#include <vector>
#include <algorithm>
#include <cwctype>
#include <cstdlib>
#include <time.h>
//IMPORTS
using std::wstring;
using std::vector;
//CONTROL IDS
#define IDC_DIRLABEL 201
#define IDC_BROWSEBTN 202
#define IDC_LIST 203
#define IDC_SEARCH 204
#define IDC_SEARCHBTN 205
#define IDC_NPLABEL 206
#define IDC_PLAYBTN 207
#define IDC_STOPBTN 208
//STATIC DEFINES
#define EXT_LENGTH 2
#define STATE_CHANGE 333
//STRING TABLE
#define PROGRAM_NAME L"ClickPlay"
#define NOT_PLAYING_LABEL L"Nic nie jest odtwarzane"
#define PLAY_LABEL L"Odtwarzaj"
#define PAUSE_LABEL L"Pauza"
#define NO_DIR_LOADED_LABEL L"Nie wybrano folderu"
//GLOBAL VARS
HFONT hFont = CreateFont(18, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Segoe UI"));
HINSTANCE globalInstance;
MSG msg;
wstring ext[EXT_LENGTH] = { L"mp3", L"wav" };
//PATH VARS
vector<WIN32_FIND_DATA> files;
wstring path;
int selected = -1;
//STATE VARS
/*
* -1 - not ready
* 0 - ready
* 1 - playback active
* 2 - playback paused
*/
int currentState = -1;
BOOL isAutoPlayEnabled = TRUE;
BOOL isLoopEnabled = FALSE;
BOOL isQueued = FALSE;
//CONTROLS
HWND mainWindow;
HWND dirLabel;
HWND browseButton;
HWND filesListCtrl;
HWND searchBox;
HWND searchBtn;
HWND playButton;
HWND stopButton;
HWND npLabel;
HMENU menuBar;
//HOOKS
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
bool alphabeticSort(WIN32_FIND_DATA a, WIN32_FIND_DATA b);
//ENTRY POINT
int WINAPI WinMain(HINSTANCE currentInst, HINSTANCE previousInst, LPSTR lpCmdLine, int nCmdShow) {
globalInstance = currentInst;
//CREATE & REGISTER WINDOW CLASS
WNDCLASSEX windowClass = { 0 };
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.lpfnWndProc = WndProc;
windowClass.hInstance = currentInst;
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
windowClass.lpszClassName = PROGRAM_NAME;
windowClass.hIcon = (HICON)LoadImage(currentInst, L"ClickPlay.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_SHARED);
windowClass.hIconSm = (HICON)LoadImage(currentInst, L"small.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_SHARED);
if (!RegisterClassEx(&windowClass)) {
return 1;
}
//LOAD KEYBOARD SHORTCUT TABLE
HACCEL shortcuts = LoadAccelerators(currentInst, MAKEINTRESOURCE(IDC_CLICKPLAY));
//LOAD MENU BAR
menuBar = LoadMenu(currentInst, (LPCWSTR)IDC_MENU);
//CREATE MAIN WINDOW
mainWindow = CreateWindowEx(WS_EX_CLIENTEDGE, windowClass.lpszClassName, PROGRAM_NAME, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 400, 620, NULL, menuBar, currentInst, NULL);
SendMessage(mainWindow, WM_SETFONT, (WPARAM)hFont, TRUE);
SendMessage(mainWindow, STATE_CHANGE, -1, NULL);
ShowWindow(mainWindow, nCmdShow);
UpdateWindow(mainWindow);
//INITIALIZE MESSAGE LOOP
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, shortcuts, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
//CREATE CONTROLS
void CreateControls(HWND window) {
dirLabel = CreateWindowEx(0, L"STATIC", NO_DIR_LOADED_LABEL, WS_CHILD | WS_VISIBLE, 10, 10, 250, 40, window, (HMENU)IDC_DIRLABEL, globalInstance, NULL);
SendMessage(dirLabel, WM_SETFONT, (WPARAM)hFont, TRUE);
browseButton = CreateWindowEx(0, L"BUTTON", L"Przegl¹daj", WS_CHILD | WS_VISIBLE, 275, 10, 100, 30, window, (HMENU)IDC_BROWSEBTN, globalInstance, NULL);
SendMessage(browseButton, WM_SETFONT, (WPARAM)hFont, TRUE);
filesListCtrl = CreateWindowEx(0, L"LISTBOX", NULL, LBS_NOTIFY | LBS_DISABLENOSCROLL | WS_CHILD | WS_VISIBLE | WS_VSCROLL, 0, 50, 380, 425, window, (HMENU)IDC_LIST, globalInstance, NULL);
SendMessage(filesListCtrl, WM_SETFONT, (WPARAM)hFont, TRUE);
searchBox = CreateWindowEx(0, L"EDIT", L"", WS_CHILD | WS_VISIBLE, 0, 460, 300, 25, window, (HMENU)IDC_SEARCH, globalInstance, NULL);
SendMessage(searchBox, EM_SETCUEBANNER, FALSE, (LPARAM)L"Szukaj");
SendMessage(searchBox, WM_SETFONT, (WPARAM)hFont, TRUE);
searchBtn = CreateWindowEx(0, L"BUTTON", L"Szukaj", WS_CHILD | WS_VISIBLE, 300, 460, 80, 25, window, (HMENU)IDC_SEARCHBTN, globalInstance, NULL);
SendMessage(searchBtn, WM_SETFONT, (WPARAM)hFont, TRUE);
npLabel = CreateWindowEx(0, L"STATIC", NOT_PLAYING_LABEL, SS_CENTER | WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, -5, 485, 400, 25, window, (HMENU)IDC_NPLABEL, globalInstance, NULL);
SendMessage(npLabel, WM_SETFONT, (WPARAM)hFont, TRUE);
playButton = CreateWindowEx(0, L"BUTTON", PLAY_LABEL, WS_CHILD | WS_VISIBLE, 75, 515, 100, 30, window, (HMENU)IDC_PLAYBTN, globalInstance, NULL);
SendMessage(playButton, WM_SETFONT, (WPARAM)hFont, TRUE);
stopButton = CreateWindowEx(0, L"BUTTON", L"Zatrzymaj", WS_CHILD | WS_VISIBLE, 195, 515, 100, 30, window, (HMENU)IDC_STOPBTN, globalInstance, NULL);
SendMessage(stopButton, WM_SETFONT, (WPARAM)hFont, TRUE);
}
//GET SELECTED INDEX
int GetIndex() {
LRESULT listItemsCount = SendMessage(filesListCtrl, LB_GETCOUNT, NULL, NULL);
for (int i = 0; i < listItemsCount; i++) {
if (SendMessage(filesListCtrl, LB_GETSEL, (WPARAM)i, NULL) > 0) {
return i;
}
}
return -1;
}
//REMOVE SELECTION
void UnloadSelection() {
mciSendString(L"close mp3", NULL, 0, mainWindow);
selected = -1;
}
//LOAD SELECTION
/*
* ERROR CODES
* -1 - invalid index
* -2 - file not found
* -3 - path not loaded
*/
int LoadSelection(int index) {
UnloadSelection();
if (index != -1) {
if (!path.empty()) {
wstring fullPath = path + L"\\" + wstring(files[index].cFileName);
WIN32_FIND_DATA fileData;
HANDLE fileExist = FindFirstFile(fullPath.c_str(), &fileData);
if (fileExist == INVALID_HANDLE_VALUE) {
MessageBox(mainWindow, L"Wskazany plik nie zosta³ odnaleziony. Upewnij siê, ¿e nie zosta³ przeniesiony lub naciœnij klawisz F5, aby pozbyæ siê niedzia³aj¹cych pozycji.", L"Nie znaleziono pliku", MB_ICONERROR);
return -2;
}
else {
wstring fullCommandS = L"open \"" + fullPath + L"\" type mpegvideo alias mp3";
LPCWSTR fullCommand = fullCommandS.c_str();
mciSendString(fullCommand, NULL, 0, mainWindow);
selected = index;
return 0;
}
}
else {
MessageBox(mainWindow, L"Naruszenie dostêpu do stanu programu. Proces zostanie zakoñczony.", L"B³¹d krytyczny", MB_ICONERROR);
ExitProcess(0);
return -3;
}
}
else {
return -1;
}
}
//FILL THE LIST BOX
void GenerateList(vector<WIN32_FIND_DATA> list) {
SendMessage(filesListCtrl, LB_RESETCONTENT, NULL, NULL);
for (int i = 0; i < list.size(); i++) {
wstring fileName = list[i].cFileName;
int dotPos = fileName.find_last_of('.');
fileName.erase(dotPos, 4);
SendMessage(filesListCtrl, LB_ADDSTRING, NULL, (LPARAM)fileName.c_str());
}
}
//UNLOAD DIRECTORY
void UnloadDir() {
SendMessage(filesListCtrl, LB_RESETCONTENT, NULL, NULL);
path.clear();
files.clear();
if (selected != -1) {
UnloadSelection();
}
}
//LOAD DIRECTORY
/*
* ERROR CODES
* -1 - empty string
* -2 - invalid directory
* -3 - empty directory
*/
int LoadDir(wstring dir) {
UnloadDir();
if (!dir.empty()) {
DWORD dirA = GetFileAttributes(dir.c_str());
if (dirA & FILE_ATTRIBUTE_DIRECTORY) {
for (int i = 0; i < EXT_LENGTH; i++) {
wstring findPathS = dir + L"\\*." + ext[i];
LPCWSTR findPath = findPathS.c_str();
WIN32_FIND_DATA dirData;
HANDLE finder = FindFirstFile(findPath, &dirData);
if (finder != INVALID_HANDLE_VALUE) {
do {
files.push_back(dirData);
} while (FindNextFile(finder, &dirData));
}
}
if (files.empty()) {
MessageBox(mainWindow, L"Wygl¹da na to, ¿e w tym katalogu nie ma ¿adnych plików, które mog¹ zostaæ otwarte przez program. Wybierz inny folder i spróbuj ponownie.", L"Brak plików", MB_ICONEXCLAMATION);
files.clear();
return -3;
}
std::sort(files.begin(), files.end(), alphabeticSort);
GenerateList(files);
path = dir;
return 0;
}
else {
MessageBox(mainWindow, L"Program nie mo¿e uzyskaæ dostêpu do wskazanego katalogu.", L"Nieprawid³owy katalog", MB_ICONERROR);
return -2;
}
}
else {
MessageBox(mainWindow, L"Nie za³adowano folderu. U¿yj przycisku PRZEGL¥DAJ, aby za³adaowaæ katalog.", L"Brak katalogu", MB_ICONERROR);
return -1;
}
}
//INITALIZE FOLDER PICKER
BOOL FolderBrowseDialog(HWND window) {
BROWSEINFO dialog = { 0 };
dialog.hwndOwner = window;
dialog.ulFlags = BIF_NEWDIALOGSTYLE;
dialog.lpszTitle = L"Wybierz folder, który ma zostaæ otwarty przez program";
LPITEMIDLIST pid = SHBrowseForFolder(&dialog);
TCHAR currentPath[MAX_PATH];
if (pid != 0) {
SHGetPathFromIDList(pid, currentPath);
if (LoadDir((wstring)currentPath) == 0) {
SetCurrentDirectory(path.c_str());
SetWindowText(dirLabel, path.c_str());
return TRUE;
}
else {
return FALSE;
}
}
else {
return FALSE;
}
}
//SEARCH DIRECTORY
void SearchDir(wstring phrase) {
//PERFORM CHECKING
if (path.empty()) {
return;
}
//RELOAD DIR
LoadDir(path);
//PREPARE
if (phrase.empty()) {
return;
}
vector<WIN32_FIND_DATA> results;
//GET FILES
for (int i = 0; i < files.size(); i++) {
if (wstring(files[i].cFileName).find(phrase) != wstring::npos) {
results.push_back(files[i]);
}
}
std::sort(results.begin(), results.end(), alphabeticSort);
files = results;
//ADD FILTERED CONTENT
GenerateList(files);
}
//GET SEARCH PHRASE FROM searchBox
wstring GetSearchPhrase() {
__int64 searchLength = SendMessage(searchBox, WM_GETTEXTLENGTH, 0, NULL);
TCHAR* searchPhrase = new TCHAR[static_cast<__int64>(searchLength) << 1];
SendMessage(searchBox, WM_GETTEXT, static_cast<__int64>(searchLength) << 1, (LPARAM)searchPhrase);
searchPhrase[searchLength] = _T('\0');
return wstring(searchPhrase);
}
//MESSAGE LOOP
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
int windowId, windowEvent;
switch (msg) {
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CREATE:
CreateControls(hwnd);
break;
case WM_COMMAND:
windowId = LOWORD(wParam);
windowEvent = HIWORD(wParam);
switch (windowId) {
case ID_PLIK_OPENDIR:
case IDC_BROWSEBTN:
if (FolderBrowseDialog(mainWindow) == TRUE) {
SendMessage(mainWindow, STATE_CHANGE, 0, NULL);
}
break;
case IDC_LIST:
if (windowEvent == LBN_SELCHANGE) {
if (currentState == 1 || currentState == 2) { currentState = 1; isQueued = TRUE; }
if (LoadSelection(GetIndex()) == 0) {
if (isAutoPlayEnabled == TRUE) {
SendMessage(mainWindow, STATE_CHANGE, 1, NULL);
}
}
}
break;
case IDC_SEARCHBTN:
SearchDir(GetSearchPhrase());
break;
case IDC_PLAYBTN:
switch (currentState) {
case 0:
if (LoadSelection(GetIndex()) == 0) {
SendMessage(mainWindow, STATE_CHANGE, 1, NULL);
}
else {
MessageBox(mainWindow, L"Podczas odtwarzania wyst¹pi³ b³¹d", L"B³¹d odtwarzacza", MB_ICONERROR);
}
break;
case 1:
SendMessage(mainWindow, STATE_CHANGE, 2, NULL);
break;
case 2:
SendMessage(mainWindow, STATE_CHANGE, 1, NULL);
break;
}
break;
case IDC_STOPBTN:
isQueued = FALSE;
SendMessage(mainWindow, MM_MCINOTIFY, 0, 0);
break;
case IDM_EXIT:
SendMessage(mainWindow, WM_CLOSE, NULL, NULL);
break;
case IDM_ABOUT:
DialogBox(globalInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), mainWindow, About);
break;
case ID_REFRESH:
LoadDir(path);
if (SendMessage(searchBox, WM_GETTEXTLENGTH, 0, 0) > 0) {
SearchDir(GetSearchPhrase());
}
break;
case ID_OPCJE_ONCLICK:
if (isAutoPlayEnabled) {
CheckMenuItem(menuBar, ID_OPCJE_ONCLICK, MF_UNCHECKED);
isAutoPlayEnabled = FALSE;
}
else {
CheckMenuItem(menuBar, ID_OPCJE_ONCLICK, MF_CHECKED);
isAutoPlayEnabled = TRUE;
}
break;
case ID_OPCJE_LOOP:
if (isLoopEnabled) {
CheckMenuItem(menuBar, ID_OPCJE_LOOP, MF_UNCHECKED);
isLoopEnabled = FALSE;
}
else {
CheckMenuItem(menuBar, ID_OPCJE_LOOP, MF_CHECKED);
isLoopEnabled = TRUE;
}
UnloadSelection();
SendMessage(mainWindow, STATE_CHANGE, 0, 0);
break;
case ID_PLIK_CLOSEDIR:
SendMessage(mainWindow, STATE_CHANGE, -1, NULL);
break;
case ID_AKCJE_SRCLEAR:
SendMessage(searchBox, WM_SETTEXT, (WPARAM)L"", 0);
LoadDir(path);
break;
case ID_AKCJE_RANDOM:
if (currentState == 1) {
isQueued = TRUE;
}
//GET SEED
srand(time(NULL));
//LOAD AND PLAY
LoadSelection(rand() % files.size());
SendMessage(mainWindow, STATE_CHANGE, 1, 0);
break;
}
break;
case MM_MCINOTIFY:
if (!isQueued) {
UnloadSelection();
SendMessage(mainWindow, STATE_CHANGE, 0, NULL);
}
else {
isQueued = FALSE;
}
break;
case STATE_CHANGE:
switch ((int)wParam) {
case -1:
UnloadSelection();
UnloadDir();
EnableWindow(filesListCtrl, FALSE);
EnableWindow(playButton, FALSE);
EnableWindow(stopButton, FALSE);
EnableWindow(searchBtn, FALSE);
EnableMenuItem(menuBar, ID_REFRESH, MF_DISABLED);
EnableMenuItem(menuBar, ID_PLIK_CLOSEDIR, MF_DISABLED);
EnableMenuItem(menuBar, ID_AKCJE_RANDOM, MF_DISABLED);
EnableMenuItem(menuBar, ID_AKCJE_SRCLEAR, MF_DISABLED);
SetWindowText(dirLabel, NO_DIR_LOADED_LABEL);
SetWindowText(npLabel, L"");
SetWindowText(playButton, PLAY_LABEL);
break;
case 0:
if (!path.empty()) {
EnableWindow(filesListCtrl, TRUE);
EnableWindow(playButton, TRUE);
EnableWindow(stopButton, TRUE);
EnableWindow(searchBtn, TRUE);
EnableMenuItem(menuBar, ID_REFRESH, MF_ENABLED);
EnableMenuItem(menuBar, ID_PLIK_CLOSEDIR, MF_ENABLED);
EnableMenuItem(menuBar, ID_AKCJE_RANDOM, MF_ENABLED);
EnableMenuItem(menuBar, ID_AKCJE_SRCLEAR, MF_ENABLED);
SetWindowText(npLabel, NOT_PLAYING_LABEL);
SetWindowText(playButton, PLAY_LABEL);
break;
}
else {
SendMessage(mainWindow, STATE_CHANGE, -1, 0);
break;
}
case 1:
if (!path.empty() && selected != -1) {
if (currentState == 2) {
mciSendString(L"resume mp3", NULL, 0, mainWindow);
}
else {
if (isLoopEnabled) {
mciSendString(L"play mp3 repeat", NULL, 0, mainWindow);
}
else {
mciSendString(L"play mp3 notify", NULL, 0, mainWindow);
}
}
EnableWindow(filesListCtrl, TRUE);
EnableWindow(playButton, TRUE);
EnableWindow(stopButton, TRUE);
EnableWindow(searchBtn, TRUE);
EnableMenuItem(menuBar, ID_REFRESH, MF_DISABLED);
EnableMenuItem(menuBar, ID_PLIK_CLOSEDIR, MF_ENABLED);
EnableMenuItem(menuBar, ID_AKCJE_RANDOM, MF_ENABLED);
EnableMenuItem(menuBar, ID_AKCJE_SRCLEAR, MF_ENABLED);
SetWindowText(npLabel, files[selected].cFileName);
SetWindowText(playButton, PAUSE_LABEL);
break;
}
else {
SendMessage(mainWindow, STATE_CHANGE, 0, NULL);
break;
}
case 2:
mciSendString(L"pause mp3", NULL, 0, mainWindow);
wstring pauseStringWS = wstring(files[selected].cFileName) + L" [PAUZA]";
LPCWSTR pauseString = pauseStringWS.c_str();
EnableWindow(filesListCtrl, TRUE);
EnableWindow(playButton, TRUE);
EnableWindow(stopButton, TRUE);
EnableWindow(searchBtn, TRUE);
EnableMenuItem(menuBar, ID_REFRESH, MF_DISABLED);
EnableMenuItem(menuBar, ID_PLIK_CLOSEDIR, MF_ENABLED);
EnableMenuItem(menuBar, ID_AKCJE_RANDOM, MF_ENABLED);
EnableMenuItem(menuBar, ID_AKCJE_SRCLEAR, MF_ENABLED);
SetWindowText(npLabel, pauseString);
SetWindowText(playButton, L"Wznów");
break;
}
currentState = (int)wParam;
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return NULL;
}
//ABOUT DIALOG LOOP
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
UNREFERENCED_PARAMETER(lParam);
switch (message) {
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
//SORTING FUNCTION
bool alphabeticSort(WIN32_FIND_DATA a, WIN32_FIND_DATA b) {
return std::tolower(wstring(a.cFileName).at(0)) < std::tolower(wstring(b.cFileName).at(0));
}