Windows: refactored GUI

This commit is contained in:
zvon 2020-02-25 16:11:25 +01:00
parent 7b3e95c231
commit 7186635f1c
16 changed files with 1603 additions and 17 deletions

View File

@ -48,19 +48,14 @@ tv_rename: functions.o filesystem.o network.o tv_rename.o progress.o main.o
filesystem.o: unix/filesystem.cpp filesystem.o: unix/filesystem.cpp
$(CXX) $(CFLAGS) -c unix/filesystem.cpp -o filesystem.o $(CXX) $(CFLAGS) -c unix/filesystem.cpp -o filesystem.o
functions.o: functions.cpp functions.o: functions.cpp
$(CXX) $(CFLAGS) -c functions.cpp $(CXX) $(CFLAGS) -c functions.cpp
network.o: unix/network.cpp network.o: unix/network.cpp
$(CXX) $(CFLAGS) -c unix/network.cpp $(CXX) $(CFLAGS) -c unix/network.cpp
tv_rename.o: tv_rename.cpp tv_rename.o: tv_rename.cpp
$(CXX) $(CFLAGS) -c tv_rename.cpp $(CXX) $(CFLAGS) -c tv_rename.cpp
progress.o: progress.cpp progress.o: progress.cpp
$(CXX) $(CFLAGS) -c progress.cpp $(CXX) $(CFLAGS) -c progress.cpp
main.o: main.cpp main.o: main.cpp
$(CXX) $(CFLAGS) -c main.cpp $(CXX) $(CFLAGS) -c main.cpp
@ -76,13 +71,10 @@ tv_rename_gui: gui.o mainwindow.o seasonwindow.o databasewindow.o\
filesystem_u_gui.o: unix/filesystem.cpp filesystem_u_gui.o: unix/filesystem.cpp
$(CXX) $(CFLAGS) -c unix/filesystem.cpp -o filesystem_u_gui.o -DGUI $(CXX) $(CFLAGS) -c unix/filesystem.cpp -o filesystem_u_gui.o -DGUI
functions_gui.o: functions.cpp functions_gui.o: functions.cpp
$(CXX) $(CFLAGS) -c functions.cpp -o functions_gui.o -DGUI $(CXX) $(CFLAGS) -c functions.cpp -o functions_gui.o -DGUI
tv_rename_gui.o: tv_rename.cpp tv_rename_gui.o: tv_rename.cpp
$(CXX) $(CFLAGS) -c tv_rename.cpp -o tv_rename_gui.o -DGUI $(CXX) $(CFLAGS) -c tv_rename.cpp -o tv_rename_gui.o -DGUI
gui.o: gui.cpp gui.o: gui.cpp
$(CXX) $(CFLAGS) -o $@ -c $^ $(GTKFLAGS) -DGUI $(CXX) $(CFLAGS) -o $@ -c $^ $(GTKFLAGS) -DGUI
mainwindow.o: mainwindow.cpp mainwindow.o: mainwindow.cpp
@ -113,12 +105,12 @@ tv_rename.exe: tv_rename.cpp functions.cpp windows/filesystem.cpp\
.PHONY: windows_gui .PHONY: windows_gui
windows_gui: tv_rename_gui.exe windows_gui: tv_rename_gui.exe
tv_rename_gui.exe: tv_rename_gui.res tv_rename_gui.cpp tv_rename.cpp\ tv_rename_gui.exe: windows/gui.cpp windows/mainwindow.cpp\
windows/filesystem.cpp functions.cpp windows/network.cpp windows/gui_functions.cpp tv_rename.cpp\
$(CXX) -MD -EHsc -Fe"tv_rename_gui" tv_rename_gui.cpp tv_rename.cpp\ windows/filesystem.cpp functions.cpp windows/network.cpp\
windows/filesystem.cpp functions.cpp windows/network.cpp -D_WIN32\ progress.cpp sqlite3.c windows/patternwindow.cpp\
-DUNICODE -DGUI -link wininet.lib shlwapi.lib ole32.lib shell32.lib\ windows/progresswindow.cpp windows/seasonwindow.cpp\
gdi32.lib user32.lib tv_rename_gui.res windows/databasewindow.cpp windows/searchwindow.cpp
$(CXX) -MD -EHsc -Fe"tv_rename_gui" $^ -DGUI -D_WIN32 -DUNICODE\
tv_rename_gui.res: tv_rename_gui.rc -link wininet.lib shlwapi.lib ole32.lib\
rc tv_rename_gui.rc shell32.lib user32.lib gdi32.lib comctl32.lib

285
windows/databasewindow.cpp Normal file
View File

@ -0,0 +1,285 @@
#include "databasewindow.hpp"
#include "../filesystem.hpp"
#include "../functions.hpp"
#include "gui_functions.hpp"
#include "progresswindow.hpp"
#include "searchwindow.hpp"
#include <commctrl.h>
#include <thread>
#define ID_LISTVIEW 0x0001
#define ID_OK_BUTTON 0x0002
#define ID_CANCEL_BUTTON 0x0003
#define ID_SAVE_BUTTON 0x0004
#define ID_LANG_COMBO 0x0005
#define SHOW_COLUMN 0
#define PATH_COLUMN 1
#define LANG_COLUMN 2
#define DVD_COLUMN 3
#define ID_COLUMN 4
#define LANG_ID_COLUMN 5
#define TVID_COLUMN 6
#define database_width( width ) width - 25
#define database_height( height ) height - 90
#define cancel_x( width ) width - 100
#define cancel_y( height ) height - 73
#define ok_x( width ) width - 185
#define ok_y( height ) height - 73
#define save_x( width ) 5
#define save_y( height ) height - 73
DatabaseWindow *DatabaseWindow::dw = nullptr;
void toggleDVD( LPNMITEMACTIVATE temp, HWND list_hwnd ) {
auto dvd = getItemText( list_hwnd, temp->iItem, temp->iSubItem ) != L"No";
if ( dvd ) {
setListViewItemText( list_hwnd, temp->iItem, temp->iSubItem, L"No" );
} else {
setListViewItemText( list_hwnd, temp->iItem, temp->iSubItem, L"Yes" );
}
}
DatabaseWindow::DatabaseWindow(
HINSTANCE hInstance,
std::vector< std::pair< std::wstring, std::wstring > > &languages,
HWND parent_window )
: parent( parent_window ), hInst( hInstance ), langs( languages ) {
// need to set this here for WM_NOTIFY to work
dw = this;
window = CreateWindowW( L"DatabaseWindow", L"Progress",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT,
CW_USEDEFAULT, window_width, window_height, parent,
NULL, hInstance, NULL );
ShowWindow( window, SW_SHOW );
auto hFont = ( HFONT )GetStockObject( DEFAULT_GUI_FONT );
EnableWindow( parent, false );
INITCOMMONCONTROLSEX icex; // Structure for control initialization.
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx( &icex );
list_hwnd = createListView( 5, 5, database_width( window_width ),
database_height( window_height ), ID_LISTVIEW,
window, hFont );
addColumnToListView( list_hwnd, L"Show", 90, SHOW_COLUMN );
addColumnToListView( list_hwnd, L"Path", 180, PATH_COLUMN );
addColumnToListView( list_hwnd, L"Language", 70, LANG_COLUMN );
addColumnToListView( list_hwnd, L"DVD", 40, DVD_COLUMN );
// create hidden columns
addColumnToListView( list_hwnd, L"ID", 0, ID_COLUMN );
addColumnToListView( list_hwnd, L"LangID", 0, LANG_ID_COLUMN );
addColumnToListView( list_hwnd, L"TVID", 0, TVID_COLUMN );
int row{ 0 };
for ( auto &x : dbGetShows() ) {
if ( x[L"SHOW"] == L"pattern" )
continue;
addItemToListView( list_hwnd, row, SHOW_COLUMN, x[L"SHOW"].c_str() );
addItemToListView( list_hwnd, row, PATH_COLUMN, x[L"PATH"].c_str() );
addItemToListView( list_hwnd, row, DVD_COLUMN,
x[L"DVD"] == L"1" ? L"Yes" : L"No" );
addItemToListView( list_hwnd, row, ID_COLUMN, x[L"ID"].c_str() );
addItemToListView( list_hwnd, row, TVID_COLUMN, x[L"TVID"].c_str() );
// lang_id[0] will be index of the language
wchar_t lang_id[2];
lang_id[1] = '\0';
for ( wchar_t i = 0; i < ( wchar_t )languages.size(); i++ ) {
if ( x[L"LANGUAGE"] == languages[i].first ) {
addItemToListView( list_hwnd, row, LANG_COLUMN,
languages[i].second.c_str() );
lang_id[0] = i;
addItemToListView( list_hwnd, row, LANG_ID_COLUMN, lang_id );
}
}
row++;
}
cancel_button = createButton( L"Cancel", cancel_x( window_width ),
cancel_y( window_height ), 80, 25,
ID_CANCEL_BUTTON, window, hFont );
ok_button =
createButton( L"OK", ok_x( window_width ), ok_y( window_height ), 80,
25, ID_OK_BUTTON, window, hFont );
save_button =
createButton( L"Save", save_x( window_width ), save_y( window_height ),
80, 25, ID_SAVE_BUTTON, window, hFont );
lang_combo = createCombo( 0, 0, 120, 110, ID_LANG_COMBO, window, hFont );
ShowWindow( lang_combo, SW_HIDE );
for ( auto &x : languages ) {
addItemToCombo( lang_combo, x.second.c_str() );
}
UpdateWindow( window );
}
LRESULT CALLBACK DatabaseWindow::messageHandler( HWND hwnd, UINT umsg,
WPARAM wParam,
LPARAM lParam ) {
switch ( umsg ) {
case WM_CREATE:
centerWindow( hwnd );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
case ID_OK_BUTTON:
dw->save();
SendMessage( hwnd, WM_CLOSE, 0, 0 );
break;
case ID_CANCEL_BUTTON:
SendMessage( hwnd, WM_CLOSE, 0, 0 );
break;
case ID_SAVE_BUTTON:
dw->save();
break;
case ID_LANG_COMBO:
switch ( HIWORD( wParam ) ) {
case CBN_KILLFOCUS:
ShowWindow( dw->lang_combo, SW_HIDE );
break;
case CBN_SELCHANGE: {
wchar_t lang_id[2];
lang_id[1] = '\0';
lang_id[0] = getComboCurSel( dw->lang_combo );
setListViewItemText( dw->list_hwnd, dw->cur_row, LANG_COLUMN,
dw->langs[lang_id[0]].second.c_str() );
setListViewItemText( dw->list_hwnd, dw->cur_row, LANG_ID_COLUMN,
lang_id );
} break;
}
break;
}
break;
case WM_SIZE: {
auto width = LOWORD( lParam );
auto height = HIWORD( lParam );
SetWindowPos( dw->list_hwnd, HWND_TOP, 5, 5, database_width( width ),
database_height( height ), 0 );
SetWindowPos( dw->cancel_button, HWND_TOP, cancel_x( width ),
cancel_y( height ), 80, 25, 0 );
SetWindowPos( dw->ok_button, HWND_TOP, ok_x( width ), ok_y( height ),
80, 25, 0 );
SetWindowPos( dw->save_button, HWND_TOP, save_x( width ),
save_y( height ), 80, 25, 0 );
UpdateWindow( dw->window );
} break;
case WM_NOTIFY:
dw->listNotify( lParam );
break;
}
return DefWindowProcW( hwnd, umsg, wParam, lParam );
}
void DatabaseWindow::mainLoop() {
MSG msg;
while ( GetMessage( &msg, NULL, 0, 0 ) ) {
if ( !IsDialogMessage( window, &msg ) ) {
TranslateMessage( &msg );
dw = this;
DispatchMessage( &msg );
}
}
}
void DatabaseWindow::changed( int index ) {
auto path = getItemText( list_hwnd, index, PATH_COLUMN );
if ( !FSLib::isDirectory( path ) ) {
MessageBox( window,
( L"Directory '" + path + L"' doesn't exist" ).c_str(),
L"Error", MB_OK | MB_ICONERROR );
return;
}
changed_rows.push_back( index );
}
void DatabaseWindow::save() {
if ( changed_rows.size() == 0 )
return;
std::unordered_set< size_t > row_indexes;
for ( auto &row : changed_rows ) {
auto index = std::stoi( getItemText( list_hwnd, row, ID_COLUMN ) );
auto show = getItemText( list_hwnd, row, SHOW_COLUMN );
auto path = getItemText( list_hwnd, row, PATH_COLUMN );
auto lang =
langs[getItemText( list_hwnd, row, LANG_ID_COLUMN )[0]].first;
auto show_id = getItemText( list_hwnd, row, TVID_COLUMN );
bool dvd = getItemText( list_hwnd, row, DVD_COLUMN ) == L"Yes";
changeDB( index, path, lang, show_id, dvd );
row_indexes.insert( index );
}
ProgressWindow pw( hInst, window );
std::thread t =
std::thread( refreshSelectDB, row_indexes, false, pw.getWindow() );
t.detach();
pw.mainLoop();
changed_rows.clear();
}
void DatabaseWindow::listNotify( LPARAM lParam ) {
NMHDR &nmh = *( NMHDR * )lParam;
if ( nmh.hwndFrom != dw->list_hwnd )
return;
switch ( nmh.code ) {
case NM_DBLCLK: {
LPNMITEMACTIVATE temp = ( LPNMITEMACTIVATE )lParam;
if ( temp->iItem == -1 )
break;
switch ( temp->iSubItem ) {
case SHOW_COLUMN: {
auto lang_id =
getItemText( list_hwnd, temp->iItem, LANG_ID_COLUMN );
auto show = getItemText( list_hwnd, temp->iItem, SHOW_COLUMN );
SearchWindow sw( hInst, langs, lang_id[0], show.c_str(), window );
sw.mainLoop();
// test if user clicke OK
if ( sw.accepted() ) {
setListViewItemText( list_hwnd, temp->iItem, SHOW_COLUMN,
sw.getShow().c_str() );
setListViewItemText( list_hwnd, temp->iItem, TVID_COLUMN,
sw.getShowID().c_str() );
setListViewItemText( list_hwnd, temp->iItem, LANG_COLUMN,
langs[sw.getLangID()].second.c_str() );
wchar_t langid[2];
langid[1] = '\0';
langid[0] = sw.getLangID();
setListViewItemText( list_hwnd, temp->iItem, LANG_ID_COLUMN,
langid );
}
} break;
case PATH_COLUMN: {
auto dir = getDir();
if ( !dir.empty() )
addItemToListView( list_hwnd, temp->iItem, temp->iSubItem,
dir.c_str() );
} break;
case LANG_COLUMN: {
RECT item_rect;
cur_row = temp->iItem;
ListView_GetSubItemRect( list_hwnd, temp->iItem, temp->iSubItem,
LVIR_BOUNDS, &item_rect );
SetWindowPos( lang_combo, HWND_TOP, item_rect.left, item_rect.top,
item_rect.right - item_rect.left, window_height,
NULL );
ShowWindow( lang_combo, SW_SHOW );
SetFocus( lang_combo );
auto id = getItemText( list_hwnd, temp->iItem, LANG_ID_COLUMN );
SendMessage( lang_combo, CB_SETCURSEL, id[0], NULL );
} break;
case DVD_COLUMN:
toggleDVD( temp, list_hwnd );
break;
}
changed( temp->iItem );
} break;
}
}

View File

@ -0,0 +1,40 @@
#include <string>
#include <vector>
#include <windows.h>
class DatabaseWindow {
public:
DatabaseWindow(
HINSTANCE hInstance,
std::vector< std::pair< std::wstring, std::wstring > > &languages,
HWND parent_window );
void mainLoop();
static LRESULT CALLBACK messageHandler( HWND hwnd, UINT umsg, WPARAM wParam,
LPARAM lParam );
~DatabaseWindow() {
EnableWindow( parent, true );
SetFocus( parent );
}
private:
void listNotify( LPARAM lParam );
void changed( int indes );
void save();
HWND window;
HWND lang_combo;
HWND list_hwnd;
HWND cancel_button;
HWND ok_button;
HWND save_button;
HWND parent;
HINSTANCE hInst;
int cur_row;
const int window_width{ 350 };
const int window_height{ 370 };
std::vector< int > changed_rows;
const std::vector< std::pair< std::wstring, std::wstring > > &langs;
static DatabaseWindow *dw;
};

9
windows/gui.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "mainwindow.hpp"
#include "gui_functions.hpp"
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR szCmdLine, int nCmdShow ) {
registerWindowClasses( hInstance );
MainWindow mw( hInstance, nCmdShow );
mw.mainLoop();
return 0;
}

196
windows/gui_functions.cpp Normal file
View File

@ -0,0 +1,196 @@
#define UNICODE
#include "gui_functions.hpp"
#include "databasewindow.hpp"
#include "mainwindow.hpp"
#include "patternwindow.hpp"
#include "progresswindow.hpp"
#include "searchwindow.hpp"
#include "seasonwindow.hpp"
#include <shlobj.h>
void registerWindowClasses( HINSTANCE hInstance ) {
WNDCLASSW wc{};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpszClassName = L"MainWindow";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush( COLOR_3DFACE );
wc.lpfnWndProc = MainWindow::messageHandler;
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
RegisterClassW( &wc );
wc.lpszClassName = L"PatternWindow";
wc.lpfnWndProc = PatternWindow::messageHandler;
RegisterClassW( &wc );
wc.lpszClassName = L"ProgressWindow";
wc.lpfnWndProc = ProgressWindow::messageHandler;
RegisterClassW( &wc );
wc.lpszClassName = L"SeasonWindow";
wc.lpfnWndProc = SeasonWindow::messageHandler;
RegisterClassW( &wc );
wc.lpszClassName = L"DatabaseWindow";
wc.lpfnWndProc = DatabaseWindow::messageHandler;
RegisterClassW( &wc );
wc.lpszClassName = L"SearchWindow";
wc.lpfnWndProc = SearchWindow::messageHandler;
RegisterClassW( &wc );
}
void centerWindow( HWND hwnd ) {
RECT rc = {};
GetWindowRect( hwnd, &rc );
int win_w = rc.right - rc.left;
int win_h = rc.bottom - rc.top;
int screen_w = GetSystemMetrics( SM_CXSCREEN );
int screen_h = GetSystemMetrics( SM_CYSCREEN );
SetWindowPos( hwnd, HWND_TOP, ( screen_w - win_w ) / 2,
( screen_h - win_h ) / 2, 0, 0, SWP_NOSIZE );
}
HWND createWindow( const wchar_t *type, const wchar_t *text, int x, int y,
int width, int height, long long id, HWND parent,
HFONT hFont, long long dwStyle, long long exStyle ) {
HWND child_hwnd =
CreateWindowExW( exStyle, type, text, dwStyle, x, y, width, height,
parent, ( HMENU )id, NULL, NULL );
SendMessage( child_hwnd, WM_SETFONT, ( WPARAM )hFont, true );
return child_hwnd;
}
HWND createLabel( const wchar_t *text, int x, int y, int width, int height,
long long id, HWND parent, HFONT hFont ) {
return createWindow( L"Static", text, x, y, width, height, id, parent,
hFont, WS_VISIBLE | WS_CHILD | SS_LEFT | WS_TABSTOP,
0 );
}
HWND createEditBox( int x, int y, int width, int height, long long id,
HWND parent, HFONT hFont ) {
return createWindow( L"Edit", NULL, x, y, width, height, id, parent, hFont,
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP |
ES_AUTOHSCROLL,
WS_EX_CLIENTEDGE );
}
HWND createCombo( int x, int y, int width, int height, long long id,
HWND parent, HFONT hFont ) {
return createWindow(
L"Combobox", NULL, x, y, width, height, id, parent, hFont,
WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP, 0 );
}
HWND createButton( const wchar_t *text, int x, int y, int width, int height,
long long id, HWND parent, HFONT hFont ) {
return createWindow(
L"Button", text, x, y, width, height, id, parent, hFont,
WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | WS_TABSTOP, 0 );
}
HWND createCheckbox( const wchar_t *text, int x, int y, int width, int height,
long long id, HWND parent, HFONT hFont ) {
return createWindow(
L"Button", text, x, y, width, height, id, parent, hFont,
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX | WS_TABSTOP, 0 );
}
HWND createProgressbar( int x, int y, int width, int height, long long id,
HWND parent, HFONT hFont ) {
return createWindow( PROGRESS_CLASSW, NULL, x, y, width, height, id, parent,
hFont, WS_CHILD | WS_VISIBLE | PBS_SMOOTH, 0 );
}
HWND createListView( int x, int y, int width, int height, long long id,
HWND parent, HFONT hFont ) {
auto hwnd = createWindow(
WC_LISTVIEWW, NULL, x, y, width, height, id, parent, hFont,
WS_CHILD | LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_VISIBLE, 0 );
SendMessage( hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT );
return hwnd;
}
LVCOLUMNW addColumnToListView( HWND list_view, const wchar_t *text, int width,
int pos ) {
// not thread-safe, but I don't care
static wchar_t pszText[MAX_PATH];
static LVCOLUMNW col{};
wcscpy( pszText, text );
col.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH;
col.fmt = LVCFMT_LEFT;
col.cx = width;
col.pszText = pszText;
SendMessage( list_view, LVM_INSERTCOLUMN, pos, ( LPARAM )&col );
return col;
}
void addItemToCombo( HWND combo, const wchar_t *text ) {
SendMessage( combo, CB_ADDSTRING, 0, ( LPARAM )text );
}
void addItemToListView( HWND list_view, int row, int column,
const wchar_t *text ) {
// not thread-safe, but I don't care
static wchar_t pszText[MAX_PATH];
static LVITEMW item{};
wcscpy( pszText, text );
item.mask = LVIF_TEXT;
item.iItem = row;
item.iSubItem = column;
item.pszText = pszText;
item.cchTextMax = MAX_PATH;
if ( column == 0 )
SendMessage( list_view, LVM_INSERTITEM, 0, ( LPARAM )&item );
else
SendMessage( list_view, LVM_SETITEMTEXT, item.iItem, ( LPARAM )&item );
}
void setListViewItemText( HWND list_view, int row, int column,
const wchar_t *text ) {
static wchar_t pszText[MAX_PATH];
static LVITEMW item{};
wcscpy( pszText, text );
item.mask = LVIF_TEXT;
item.iItem = row;
item.iSubItem = column;
item.pszText = pszText;
item.cchTextMax = MAX_PATH;
SendMessage( list_view, LVM_SETITEMTEXT, row, ( LPARAM )&item );
}
std::wstring getDir() {
wchar_t path[MAX_PATH];
BROWSEINFO bi{};
bi.lpszTitle = L"Choose a folder";
LPITEMIDLIST pidl = SHBrowseForFolder( &bi );
if ( pidl != 0 ) {
SHGetPathFromIDList( pidl, path );
IMalloc *imalloc = 0;
if ( SUCCEEDED( SHGetMalloc( &imalloc ) ) ) {
imalloc->Free( pidl );
imalloc->Release();
}
} else {
path[0] = '\0';
}
return path;
}
std::wstring getItemText( HWND hwnd, int row, int column ) {
wchar_t text[MAX_PATH];
ListView_GetItemText( hwnd, row, column, text, MAX_PATH );
return text;
}
int getComboCurSel( HWND hwnd ) {
return SendMessage( hwnd, CB_GETCURSEL, 0, 0 );
}

32
windows/gui_functions.hpp Normal file
View File

@ -0,0 +1,32 @@
#include <string>
#include <windows.h>
#include <commctrl.h>
void registerWindowClasses( HINSTANCE hInstance );
void centerWindow( HWND hwnd );
HWND createLabel( const wchar_t *text, int x, int y, int width, int height,
long long id, HWND parent, HFONT hFont );
HWND createEditBox( int x, int y, int width, int height, long long id,
HWND parent, HFONT hFont );
HWND createCombo( int x, int y, int width, int height, long long id,
HWND parent, HFONT hFont );
HWND createButton( const wchar_t *text, int x, int y, int width, int height,
long long id, HWND parent, HFONT hFont );
HWND createCheckbox( const wchar_t *text, int x, int y, int width, int height,
long long id, HWND parent, HFONT hFont );
HWND createProgressbar( int x, int y, int width, int height, long long id,
HWND parent, HFONT hFont );
HWND createListView( int x, int y, int width, int height, long long id,
HWND parent, HFONT hFont );
LVCOLUMNW addColumnToListView( HWND list_view, const wchar_t *text, int width,
int pos );
void addItemToCombo( HWND combo, const wchar_t *text );
void addItemToListView( HWND list_view, int row, int column,
const wchar_t *text );
void setListViewItemText( HWND list_view, int row, int column,
const wchar_t *text );
std::wstring getItemText( HWND hwnd, int row, int column );
int getComboCurSel( HWND hwnd );
std::wstring getDir();

431
windows/mainwindow.cpp Normal file
View File

@ -0,0 +1,431 @@
#include "mainwindow.hpp"
#include "../filesystem.hpp"
#include "../functions.hpp"
#include "../tv_rename.hpp"
#include "databasewindow.hpp"
#include "gui_functions.hpp"
#include "patternwindow.hpp"
#include "progresswindow.hpp"
#include "searchwindow.hpp"
#include "seasonwindow.hpp"
#include <fstream>
#include <thread>
#define API_KEY "42B66F5E-C6BF-423F-ADF9-CC97163472F6"
#define ID_SHOW_STATIC 0x0001
#define ID_LANGUAGE_STATIC 0x0002
#define ID_DIR_STATIC 0x0003
#define ID_PATTERN_STATIC 0x0004
#define ID_POSSIBLE_STATIC 0x0005
#define ID_SHOW_EDIT 0x1000
#define ID_LANGUAGE_COMBO 0x1001
#define ID_DIR_EDIT 0x1002
#define ID_DIR_BUTTON 0x1003
#define ID_PATTERN_EDIT 0x1004
#define ID_PATTERN_BUTTON 0x1005
#define ID_PROCESS_BUTTON 0x1006
#define ID_RENAME_CHECKBOX 0x1007
#define ID_SHOW_COMBO 0x1008
#define ID_RENAME_BUTTON 0x1009
#define ID_QUIT_BUTTON 0x100a
#define ID_DVD_CHECKBOX 0x100b
#define ID_DB_ADD_BUTTON 0x100c
#define MENU_FILE_EXIT 0x2000
#define MENU_DAT_UPDATE 0x2001
#define MENU_DAT_REFRESH 0x2002
#define MENU_DAT_CLEAN 0x2003
#define MENU_DAT_MANAGE 0x2004
#define MENU_DAT_PATTERN 0x2005
MainWindow *MainWindow::mw = nullptr;
MainWindow::MainWindow( HINSTANCE hInstance, int nCmdShow )
: hInst( hInstance ) {
window = CreateWindowW( L"MainWindow", L"TV Rename",
WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, window_width,
window_height, NULL, NULL, hInst, NULL );
ShowWindow( window, nCmdShow );
hFont = ( HFONT )GetStockObject( DEFAULT_GUI_FONT );
authenticate( API_KEY );
languages = getLangs();
createLabel( L"Show:", 5, 5, 30, 15, ID_SHOW_STATIC, window, hFont );
createLabel( L"Language:", 170, 5, 55, 15, ID_LANGUAGE_STATIC, window,
hFont );
createLabel( L"Directory:", 5, 45, 65, 15, ID_DIR_STATIC, window, hFont );
createLabel( L"Pattern:", 5, 85, 55, 15, ID_PATTERN_STATIC, window, hFont );
possible_label = createLabel( L"Possible shows:", 5, 190, 100, 15,
ID_POSSIBLE_STATIC, window, hFont );
show_input = createEditBox( 5, 20, 160, 25, ID_SHOW_EDIT, window, hFont );
language_input =
createCombo( 170, 20, 160, 250, ID_LANGUAGE_COMBO, window, hFont );
for ( auto &x : languages ) {
addItemToCombo( language_input, x.second.c_str() );
}
SendMessage( language_input, CB_SETCURSEL, langPos( L"en" ), NULL );
dir_input = createEditBox( 5, 60, 160, 25, ID_DIR_EDIT, window, hFont );
createButton( L"Choose directory", 170, 60, 120, 25, ID_DIR_BUTTON, window,
hFont );
pattern_input =
createEditBox( 5, 100, 160, 25, ID_PATTERN_EDIT, window, hFont );
createButton( L"Pattern help", 170, 100, 100, 25, ID_PATTERN_BUTTON, window,
hFont );
createButton( L"Process", 5, 140, 80, 25, ID_PROCESS_BUTTON, window,
hFont );
trust_input = createCheckbox( L"Don't ask for rename confirmation", 90, 146,
180, 12, ID_RENAME_CHECKBOX, window, hFont );
dvd_input = createCheckbox( L"Use DVD ordering", 5, 170, 180, 12,
ID_DVD_CHECKBOX, window, hFont );
possible_input = createCombo( 5, 205, 160, window_height - 220,
ID_SHOW_COMBO, window, hFont );
rename_button = createButton( L"Rename", 5, 230, 80, 25, ID_RENAME_BUTTON,
window, hFont );
db_add_button = createButton( L"Add to database", 90, 230, 100, 25,
ID_DB_ADD_BUTTON, window, hFont );
createButton( L"Quit", window_width - 100, window_height - 88, 80, 25,
ID_QUIT_BUTTON, window, hFont );
// MENUS
HMENU hMenuBar = CreateMenu();
HMENU hMenuFile = CreateMenu();
HMENU hMenuDatabase = CreateMenu();
AppendMenuW( hMenuFile, MF_STRING, MENU_FILE_EXIT, L"&Exit" );
AppendMenuW( hMenuDatabase, MF_STRING, MENU_DAT_UPDATE,
L"&Update database" );
AppendMenuW( hMenuDatabase, MF_STRING, MENU_DAT_REFRESH,
L"&Refresh database" );
AppendMenuW( hMenuDatabase, MF_STRING, MENU_DAT_CLEAN, L"&Clean database" );
AppendMenuW( hMenuDatabase, MF_STRING, MENU_DAT_MANAGE,
L"&Manage database" );
AppendMenuW( hMenuDatabase, MF_STRING, MENU_DAT_PATTERN,
L"Change &pattern" );
AppendMenuW( hMenuBar, MF_POPUP, ( UINT_PTR )hMenuFile, L"&File" );
AppendMenuW( hMenuBar, MF_POPUP, ( UINT_PTR )hMenuDatabase, L"&Database" );
SetMenu( window, hMenuBar );
INITCOMMONCONTROLSEX icex; // Structure for control initialization.
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx( &icex );
auto appdata = userHome() + L"\\tv_rename";
if ( !FSLib::isDirectory( appdata ) ) {
// create the directory so pattern can be stored when changed
CreateDirectory( appdata.c_str(), NULL );
} else {
readDefaultPattern( appdata );
}
SendMessage( pattern_input, WM_SETTEXT, NULL,
( LPARAM )default_pattern.c_str() );
ShowWindow( possible_label, SW_HIDE );
ShowWindow( possible_input, SW_HIDE );
ShowWindow( rename_button, SW_HIDE );
ShowWindow( db_add_button, SW_HIDE );
UpdateWindow( window );
}
LRESULT CALLBACK MainWindow::messageHandler( HWND hwnd, UINT umsg,
WPARAM wParam, LPARAM lParam ) {
switch ( umsg ) {
case WM_CREATE:
centerWindow( hwnd );
break;
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
case ID_QUIT_BUTTON:
case MENU_FILE_EXIT:
SendMessage( hwnd, WM_CLOSE, 0, 0 );
break;
case ID_PROCESS_BUTTON:
mw->process();
break;
case ID_DIR_BUTTON:
SendMessage( mw->dir_input, WM_SETTEXT, NULL,
( LPARAM )getDir().c_str() );
break;
case MENU_DAT_UPDATE:
dbUpdate();
break;
case MENU_DAT_REFRESH:
dbRefresh();
break;
case MENU_DAT_CLEAN:
dbClean();
break;
case MENU_DAT_MANAGE:
dbManage();
break;
case MENU_DAT_PATTERN:
dbPattern();
break;
case ID_PATTERN_BUTTON:
patternHelp();
break;
case ID_RENAME_BUTTON:
mw->rename();
break;
case ID_DB_ADD_BUTTON:
mw->dbAdd();
break;
}
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
}
return DefWindowProcW( hwnd, umsg, wParam, lParam );
}
void MainWindow::mainLoop() {
MSG msg;
while ( GetMessage( &msg, NULL, 0, 0 ) ) {
if ( !IsDialogMessage( window, &msg ) ) {
TranslateMessage( &msg );
mw = this;
DispatchMessage( &msg );
}
}
}
int MainWindow::langPos( const std::wstring &lang ) {
for ( unsigned long long i = 0; i < languages.size(); i++ ) {
if ( languages[i].first == lang )
return i;
}
return -1;
}
void MainWindow::readDefaultPattern( const std::wstring &base_dir ) {
std::wifstream file( base_dir + L"\\pattern" );
if ( file ) {
std::getline( file, default_pattern );
}
}
void MainWindow::process() {
wchar_t show[256];
SendMessage( show_input, WM_GETTEXT, ( WPARAM )255, ( LPARAM )show );
if ( wcslen( show ) == 0 ) {
MessageBox( window, L"Show field is empty", L"Error",
MB_OK | MB_ICONERROR );
return;
}
auto index = SendMessage( language_input, CB_GETCURSEL, NULL, NULL );
if ( index == CB_ERR ) {
MessageBox( window, L"No show selected", L"Error",
MB_OK | MB_ICONERROR );
return;
}
auto lang_code = languages[index].first;
possible_shows = searchShow( show, lang_code );
if ( possible_shows.size() == 0 ) {
MessageBox( window, L"No results found for given show name", L"Error",
MB_OK | MB_ICONERROR );
return;
}
SendMessage( possible_input, CB_RESETCONTENT, NULL, NULL );
for ( const auto &x : possible_shows ) {
SendMessage( possible_input, CB_ADDSTRING, NULL,
( LPARAM )x.first.c_str() );
}
SendMessage( possible_input, CB_SETCURSEL, 0, 0 );
ShowWindow( mw->possible_label, SW_SHOW );
ShowWindow( mw->possible_input, SW_SHOW );
ShowWindow( mw->rename_button, SW_SHOW );
ShowWindow( mw->db_add_button, SW_SHOW );
}
void MainWindow::rename() {
wchar_t path[MAX_PATH];
SendMessage( dir_input, WM_GETTEXT, ( WPARAM )MAX_PATH - 1,
( LPARAM )path );
if ( wcslen( path ) == 0 ) {
MessageBox( window, L"Directory field is empty", L"Error",
MB_OK | MB_ICONERROR );
return;
}
if ( !FSLib::isDirectory( path ) ) {
MessageBox( window, L"Directory doesn't exist", L"Error",
MB_OK | MB_ICONERROR );
return;
}
selected.clear();
files.clear();
std::vector< int > options{};
iterateFS( files, path );
for ( auto &x : files ) {
options.push_back( x.first );
}
SeasonWindow sw( hInst, options, selected, window );
sw.mainLoop();
auto index = SendMessage( possible_input, CB_GETCURSEL, NULL, NULL );
if ( index == CB_ERR ) {
MessageBox( window, L"No show selected", L"Error",
MB_OK | MB_ICONERROR );
return;
}
auto show = possible_shows[index].first;
auto show_id = possible_shows[index].second;
index = SendMessage( language_input, CB_GETCURSEL, NULL, NULL );
if ( index == CB_ERR ) {
MessageBox( window, L"No show selected", L"Error",
MB_OK | MB_ICONERROR );
return;
}
auto lang = languages[index].first;
bool dvd = SendMessage( dvd_input, BM_GETCHECK, NULL, NULL ) == BST_CHECKED;
bool trust =
SendMessage( trust_input, BM_GETCHECK, NULL, NULL ) == BST_CHECKED;
wchar_t input_pattern_wchar[MAX_PATH];
SendMessage( pattern_input, WM_GETTEXT, ( WPARAM )MAX_PATH,
( LPARAM )input_pattern_wchar );
if ( wcscmp( input_pattern_wchar, default_pattern.c_str() ) ) {
std::wofstream file( userHome() + L"\\tv_rename\\pattern" );
if ( file ) {
file << input_pattern_wchar;
}
}
std::wstring input_pattern = input_pattern_wchar;
for ( auto &season : selected ) {
auto renamed_files = getRenamedFiles(
show, season, show_id, lang,
( input_pattern.empty() ? default_pattern : input_pattern ), false,
files[season], dvd );
if ( renamed_files.empty() ) {
continue;
}
if ( trust ) {
renameFiles( renamed_files );
continue;
}
std::wstring message_text;
for ( auto &file : renamed_files ) {
message_text += std::get< 2 >( file ) + L" --> " +
std::get< 3 >( file ) + L"\n";
}
auto res = MessageBox( window, message_text.c_str(), L"Is this OK?",
MB_OKCANCEL );
if ( res == IDOK )
renameFiles( renamed_files );
}
}
void MainWindow::dbAdd() {
wchar_t path[MAX_PATH];
SendMessage( dir_input, WM_GETTEXT, ( WPARAM )MAX_PATH - 1,
( LPARAM )path );
if ( wcslen( path ) == 0 ) {
MessageBox( window, L"Directory field is empty", L"Error",
MB_OK | MB_ICONERROR );
return;
}
if ( !FSLib::isDirectory( path ) ) {
MessageBox( window, L"Directory doesn't exist", L"Error",
MB_OK | MB_ICONERROR );
return;
}
auto index = SendMessage( possible_input, CB_GETCURSEL, NULL, NULL );
if ( index == CB_ERR ) {
MessageBox( window, L"No show selected", L"Error",
MB_OK | MB_ICONERROR );
return;
}
auto show = possible_shows[index].first;
auto show_id = possible_shows[index].second;
index = SendMessage( language_input, CB_GETCURSEL, NULL, NULL );
if ( index == CB_ERR ) {
MessageBox( window, L"No language selected", L"Error",
MB_OK | MB_ICONERROR );
return;
}
auto lang = languages[index].first;
bool dvd = SendMessage( dvd_input, BM_GETCHECK, NULL, NULL ) == BST_CHECKED;
ProgressWindow pw( hInst, window );
std::thread t( addToDB, std::move( show ), path, std::move( lang ),
std::move( show_id ), getDBPattern(), false, dvd,
pw.getWindow() );
t.detach();
pw.mainLoop();
return;
}
void MainWindow::dbUpdate() {
ProgressWindow pw( mw->hInst, mw->window );
std::thread t( updateDB, false, pw.getWindow() );
t.detach();
pw.mainLoop();
}
void MainWindow::dbRefresh() {
ProgressWindow pw( mw->hInst, mw->window );
std::thread t( refreshDB, false, pw.getWindow() );
t.detach();
pw.mainLoop();
}
void MainWindow::dbClean() {
cleanDB();
}
void MainWindow::dbManage() {
DatabaseWindow dw( mw->hInst, mw->languages, mw->window );
dw.mainLoop();
}
void MainWindow::dbPattern() {
auto pattern = getDBPattern();
PatternWindow pw( mw->hInst, pattern.c_str(), mw->window );
pw.mainLoop();
if ( pw.accepted() )
changeDBPattern( pw.getPattern() );
return;
}
void MainWindow::patternHelp() {
MessageBoxW(
NULL,
L"%filename - original filename (without type extension)\n\n"
"%show - show name from thetvdb\n\n"
"%epname - episode name from thetvdb\n\n"
"%season - season number\n\n"
"%episode - episode number\n\n"
"Both season number and episode number can be padded with zeros, just "
"add width of padding"
" right after %, like this: %2season.\n\n"
"Default pattern is \"%filename - %epname\", you might want to change "
"this to"
" \"S%2seasonE%2episode - %epname\" or \"%show - S%2seasonE%2episode - "
"%epname\"",
L"Test", MB_OK );
return;
}

42
windows/mainwindow.hpp Normal file
View File

@ -0,0 +1,42 @@
#include <windows.h>
#include "../tv_rename.hpp"
class MainWindow {
public:
MainWindow( HINSTANCE hInstance, int nCmdShow );
void mainLoop();
static LRESULT CALLBACK messageHandler( HWND hwnd, UINT umsg, WPARAM wParam,
LPARAM lParam );
private:
int langPos( const std::wstring &lang );
void readDefaultPattern( const std::wstring &base_dir );
void process();
void rename();
void dbAdd();
static void dbUpdate();
static void dbRefresh();
static void dbClean();
static void dbManage();
static void dbPattern();
static void patternHelp();
HFONT hFont;
HWND window;
HINSTANCE hInst;
const int window_width{ 450 };
const int window_height{ 350 };
std::vector< std::pair< string, string > > languages;
std::vector< std::pair< string, string > > possible_shows;
std::wstring default_pattern{};
std::vector< int > selected;
std::map< int, std::map< int, string > > files;
HWND show_input, language_input, dir_input, pattern_input, trust_input,
dvd_input;
HWND possible_label, possible_input, rename_button, db_add_button;
static MainWindow *mw;
};

83
windows/patternwindow.cpp Normal file
View File

@ -0,0 +1,83 @@
#include "patternwindow.hpp"
#include "gui_functions.hpp"
#define ID_PATTERN_STATIC 0x0001
#define ID_PATTERN_EDIT 0x1000
#define ID_OK_BUTTON 0x1001
#define ID_CANCEL_BUTTON 0x1002
PatternWindow *PatternWindow::pw = nullptr;
PatternWindow::PatternWindow( HINSTANCE hInstance, const wchar_t *pattern,
HWND parent_window )
: parent( parent_window ) {
window = CreateWindowW( L"PatternWindow", L"Change database pattern",
WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, window_width,
window_height, parent, NULL, hInstance, NULL );
ShowWindow( window, SW_SHOW );
auto hFont = ( HFONT )GetStockObject( DEFAULT_GUI_FONT );
EnableWindow( parent, false );
createLabel( L"Pattern:", 5, 5, 30, 15, ID_PATTERN_STATIC, window, hFont );
pattern_input =
createEditBox( 5, 20, 190, 25, ID_PATTERN_EDIT, window, hFont );
createButton( L"Cancel", window_width - 100, window_height - 88, 80, 25,
ID_CANCEL_BUTTON, window, hFont );
createButton( L"OK", window_width - 185, window_height - 88, 80, 25,
ID_OK_BUTTON, window, hFont );
SendMessage( pattern_input, WM_SETTEXT, NULL, ( LPARAM )pattern );
UpdateWindow( window );
}
void PatternWindow::storePattern() {
SendMessage( pattern_input, WM_GETTEXT, ( WPARAM )2047, ( LPARAM )pattern );
}
const wchar_t *PatternWindow::getPattern() {
return pattern;
}
LRESULT CALLBACK PatternWindow::messageHandler( HWND hwnd, UINT umsg,
WPARAM wParam, LPARAM lParam ) {
switch ( umsg ) {
case WM_CREATE:
centerWindow( hwnd );
break;
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
case ID_OK_BUTTON:
pw->result = OK;
pw->storePattern();
SendMessage( hwnd, WM_CLOSE, 0, 0 );
break;
case ID_CANCEL_BUTTON:
pw->result = Cancel;
SendMessage( hwnd, WM_CLOSE, 0, 0 );
break;
}
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
}
return DefWindowProcW( hwnd, umsg, wParam, lParam );
}
void PatternWindow::mainLoop() {
MSG msg;
while ( GetMessage( &msg, NULL, 0, 0 ) ) {
if ( !IsDialogMessage( window, &msg ) ) {
TranslateMessage( &msg );
pw = this;
DispatchMessage( &msg );
}
}
}
bool PatternWindow::accepted() {
return result == OK;
}

34
windows/patternwindow.hpp Normal file
View File

@ -0,0 +1,34 @@
#include <string>
#include <windows.h>
class PatternWindow {
public:
PatternWindow( HINSTANCE hInstance, const wchar_t *pattern,
HWND parent_window );
void mainLoop();
static LRESULT CALLBACK messageHandler( HWND hwnd, UINT umsg, WPARAM wParam,
LPARAM lParam );
bool accepted();
const wchar_t *getPattern();
~PatternWindow() {
EnableWindow( parent, true );
SetFocus( parent );
}
private:
enum DialogResult { OK, Cancel };
void storePattern();
HWND window;
HWND pattern_input;
HWND parent;
enum DialogResult result;
wchar_t pattern[2048];
const int window_width{ 215 };
const int window_height{ 150 };
static PatternWindow *pw;
};

View File

@ -0,0 +1,69 @@
#include "progresswindow.hpp"
#include "../progress.hpp"
#include "gui_functions.hpp"
#include <commctrl.h>
#define ID_PROGRESS_STATIC 0x0001
#define ID_PROGRESS_BAR 0x1000
ProgressWindow *ProgressWindow::pw = nullptr;
ProgressWindow::ProgressWindow( HINSTANCE hInstance, HWND parent_window )
: parent( parent_window ) {
window = CreateWindowW( L"ProgressWindow", L"Progress",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT,
CW_USEDEFAULT, window_width, window_height, parent,
NULL, hInstance, NULL );
ShowWindow( window, SW_SHOW );
auto hFont = ( HFONT )GetStockObject( DEFAULT_GUI_FONT );
EnableWindow( parent, false );
progress_label = createLabel( L"Progress:", 5, 5, window_width - 25, 15,
ID_PROGRESS_STATIC, window, hFont );
progress_bar = createProgressbar( 5, 20, window_width - 25, 25,
ID_PROGRESS_BAR, window, hFont );
SendMessage( progress_bar, PBM_SETRANGE, 0, MAKELPARAM( 0, 100 ) );
SendMessage( progress_bar, PBM_SETPOS, 0, 0 );
UpdateWindow( window );
}
LRESULT CALLBACK ProgressWindow::messageHandler( HWND hwnd, UINT umsg,
WPARAM wParam,
LPARAM lParam ) {
switch ( umsg ) {
case WM_CREATE:
centerWindow( hwnd );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
case WM_APP:
switch ( wParam ) {
case PROGRESS_PERC:
SendMessage( pw->progress_bar, PBM_SETPOS, ( int )lParam, 0 );
break;
case PROGRESS_STRING:
SendMessage( pw->progress_label, WM_SETTEXT, NULL, lParam );
break;
}
}
return DefWindowProcW( hwnd, umsg, wParam, lParam );
}
void ProgressWindow::mainLoop() {
MSG msg;
while ( GetMessage( &msg, NULL, 0, 0 ) ) {
if ( !IsDialogMessage( window, &msg ) ) {
TranslateMessage( &msg );
pw = this;
DispatchMessage( &msg );
}
}
}
HWND ProgressWindow::getWindow() {
return window;
}

View File

@ -0,0 +1,27 @@
#include <string>
#include <windows.h>
class ProgressWindow {
public:
ProgressWindow( HINSTANCE hInstance, HWND parent_window );
void mainLoop();
static LRESULT CALLBACK messageHandler( HWND hwnd, UINT umsg, WPARAM wParam,
LPARAM lParam );
HWND getWindow();
~ProgressWindow() {
EnableWindow( parent, true );
SetFocus( parent );
}
private:
HWND window;
HWND progress_bar;
HWND progress_label;
HWND parent;
const int window_width{ 350 };
const int window_height{ 100 };
static ProgressWindow *pw;
};

158
windows/searchwindow.cpp Normal file
View File

@ -0,0 +1,158 @@
#include "searchwindow.hpp"
#include "../tv_rename.hpp"
#include "gui_functions.hpp"
#define ID_SHOW_STATIC 0x0001
#define ID_LANG_STATIC 0x0002
#define ID_RES_STATIC 0x0002
#define ID_SHOW_INPUT 0x1000
#define ID_LANG_INPUT 0x1001
#define ID_RES_INPUT 0x1002
#define ID_SEARCH_BUTTON 0x1003
#define ID_OK_BUTTON 0x1004
#define ID_CANCEL_BUTTON 0x1005
SearchWindow *SearchWindow::sw = nullptr;
SearchWindow::SearchWindow(
HINSTANCE hInstance,
const std::vector< std::pair< std::wstring, std::wstring > > &languages,
const int lang_pos, const wchar_t *show, HWND parent_window )
: parent( parent_window ), langs( languages ) {
window = CreateWindowW( L"SearchWindow", L"Show Search",
WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, window_width,
window_height, parent, NULL, hInstance, NULL );
ShowWindow( window, SW_SHOW );
auto hFont = ( HFONT )GetStockObject( DEFAULT_GUI_FONT );
EnableWindow( parent, false );
createLabel( L"Show:", 5, 5, 30, 15, ID_SHOW_STATIC, window, hFont );
createLabel( L"Language:", 170, 5, 55, 15, ID_LANG_STATIC, window, hFont );
possible_label = createLabel( L"Possible shows:", 5, 60, 100, 15,
ID_RES_STATIC, window, hFont );
show_input = createEditBox( 5, 20, 160, 25, ID_SHOW_INPUT, window, hFont );
SendMessage( show_input, WM_SETTEXT, NULL, ( LPARAM )show );
lang_input = createCombo( 170, 20, 160, 250, ID_LANG_INPUT, window, hFont );
for ( auto &x : languages ) {
addItemToCombo( lang_input, x.second.c_str() );
}
SendMessage( lang_input, CB_SETCURSEL, lang_pos, NULL );
createButton( L"Search", 340, 18, 80, 25, ID_SEARCH_BUTTON, window, hFont );
possible_input = createCombo( 5, 80, window_width - 125, 250, ID_RES_INPUT,
window, hFont );
createButton( L"OK", window_width - 200, 110, 80, 25, ID_OK_BUTTON, window,
hFont );
createButton( L"Cancel", window_width - 105, 110, 80, 25, ID_CANCEL_BUTTON,
window, hFont );
ShowWindow( possible_label, SW_HIDE );
ShowWindow( possible_input, SW_HIDE );
UpdateWindow( window );
}
LRESULT CALLBACK SearchWindow::messageHandler( HWND hwnd, UINT umsg,
WPARAM wParam, LPARAM lParam ) {
switch ( umsg ) {
case WM_CREATE:
centerWindow( hwnd );
break;
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
case ID_OK_BUTTON:
sw->ok();
SendMessage( hwnd, WM_CLOSE, 0, 0 );
break;
case ID_CANCEL_BUTTON:
sw->cancel();
SendMessage( hwnd, WM_CLOSE, 0, 0 );
break;
case ID_SEARCH_BUTTON:
sw->process();
break;
}
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
}
return DefWindowProcW( hwnd, umsg, wParam, lParam );
}
void SearchWindow::mainLoop() {
MSG msg;
while ( GetMessage( &msg, NULL, 0, 0 ) ) {
if ( !IsDialogMessage( window, &msg ) ) {
TranslateMessage( &msg );
sw = this;
DispatchMessage( &msg );
}
}
}
void SearchWindow::process() {
wchar_t show[256];
SendMessage( show_input, WM_GETTEXT, ( WPARAM )255, ( LPARAM )show );
if ( wcslen( show ) == 0 ) {
MessageBox( window, L"Show field is empty", L"Error",
MB_OK | MB_ICONERROR );
return;
}
auto index = SendMessage( lang_input, CB_GETCURSEL, NULL, NULL );
if ( index == CB_ERR ) {
MessageBox( window, L"No language selected", L"Error",
MB_OK | MB_ICONERROR );
return;
}
auto lang_code = langs[index].first;
possible_shows = searchShow( show, lang_code );
if ( possible_shows.size() == 0 ) {
MessageBox( window, L"No results found for given show name", L"Error",
MB_OK | MB_ICONERROR );
return;
}
SendMessage( possible_input, CB_RESETCONTENT, NULL, NULL );
for ( const auto &x : possible_shows ) {
SendMessage( possible_input, CB_ADDSTRING, NULL,
( LPARAM )x.first.c_str() );
}
SendMessage( possible_input, CB_SETCURSEL, 0, 0 );
ShowWindow( possible_label, SW_SHOW );
ShowWindow( possible_input, SW_SHOW );
}
void SearchWindow::ok() {
selected = SendMessage( possible_input, CB_GETCURSEL, NULL, NULL );
lang_id = SendMessage( lang_input, CB_GETCURSEL, NULL, NULL );
if ( selected == CB_ERR ) {
MessageBox( window, L"No show selected", L"Error",
MB_OK | MB_ICONERROR );
selected = -1;
}
}
void SearchWindow::cancel() {
selected = -1;
}
bool SearchWindow::accepted() {
return selected != -1;
}
std::wstring SearchWindow::getShow() {
return possible_shows[selected].first;
}
std::wstring SearchWindow::getShowID() {
return possible_shows[selected].second;
}
int SearchWindow::getLangID() {
return lang_id;
}

44
windows/searchwindow.hpp Normal file
View File

@ -0,0 +1,44 @@
#include <string>
#include <vector>
#include <windows.h>
class SearchWindow {
public:
SearchWindow(
HINSTANCE hInstance,
const std::vector< std::pair< std::wstring, std::wstring > > &languages,
const int lang_pos, const wchar_t *show, HWND parent_window );
void mainLoop();
static LRESULT CALLBACK messageHandler( HWND hwnd, UINT umsg, WPARAM wParam,
LPARAM lParam );
bool accepted();
std::wstring getShow();
std::wstring getShowID();
int getLangID();
~SearchWindow() {
EnableWindow( parent, true );
SetFocus( parent );
}
private:
HWND window;
HWND show_input;
HWND lang_input;
HWND possible_label;
HWND possible_input;
HWND parent;
const int window_width{ 450 };
const int window_height{ 200 };
const std::vector< std::pair< std::wstring, std::wstring > > &langs;
std::vector< std::pair< std::wstring, std::wstring > > possible_shows;
int selected{ -1 };
int lang_id{ -1 };
void process();
void ok();
void cancel();
static SearchWindow *sw;
};

111
windows/seasonwindow.cpp Normal file
View File

@ -0,0 +1,111 @@
#include "seasonwindow.hpp"
#include "gui_functions.hpp"
#define ID_CHECKBOX 0x0001
#define ID_SEASONS_STATIC 0x0001
#define ID_ALL_BUTTON 0x1000
#define ID_NONE_BUTTON 0x1001
#define ID_CONFIRM_BUTTON 0x1002
SeasonWindow *SeasonWindow::sw = nullptr;
SeasonWindow::SeasonWindow( HINSTANCE hInstance,
const std::vector< int > &seasons,
std::vector< int > &return_vector,
HWND parent_window )
: parent( parent_window ), returned( return_vector ),
season_nums( seasons ) {
window = CreateWindowW( L"SeasonWindow", L"Select seasons",
WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, window_width,
window_height, parent, NULL, hInstance, NULL );
ShowWindow( window, SW_SHOW );
auto hFont = ( HFONT )GetStockObject( DEFAULT_GUI_FONT );
EnableWindow( parent, false );
size_t x{ 5 }, y{ 25 };
// create a check box for each season
HWND checkbox_hwnd;
for ( auto &s : season_nums ) {
checkbox_hwnd = createCheckbox( std::to_wstring( s ).c_str(), x, y, 55,
15, ID_CHECKBOX, window, hFont );
checkboxes.push_back( checkbox_hwnd );
if ( x == 185 ) {
x = 5;
y += 20;
} else {
x += 60;
}
}
createLabel( L"Select seasons:", 5, 5, 100, 15, ID_SEASONS_STATIC, window,
hFont );
createButton( L"Select all", 130, 175, 100, 25, ID_ALL_BUTTON, window,
hFont );
createButton( L"Unselect all", 5, 175, 110, 25, ID_NONE_BUTTON, window,
hFont );
createButton( L"Select", 165, 215, 80, 25, ID_CONFIRM_BUTTON, window,
hFont );
UpdateWindow( window );
}
void SeasonWindow::mainLoop() {
MSG msg;
while ( GetMessage( &msg, NULL, 0, 0 ) ) {
if ( !IsDialogMessage( window, &msg ) ) {
TranslateMessage( &msg );
sw = this;
DispatchMessage( &msg );
}
}
}
LRESULT CALLBACK SeasonWindow::messageHandler( HWND hwnd, UINT umsg,
WPARAM wParam, LPARAM lParam ) {
switch ( umsg ) {
case WM_CREATE:
centerWindow( hwnd );
break;
case WM_COMMAND:
switch ( LOWORD( wParam ) ) {
case ID_ALL_BUTTON:
sw->selectAll();
break;
case ID_NONE_BUTTON:
sw->selectNone();
break;
case ID_CONFIRM_BUTTON:
sw->storeResult();
SendMessage( hwnd, WM_CLOSE, 0, 0 );
break;
}
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
}
return DefWindowProcW( hwnd, umsg, wParam, lParam );
}
void SeasonWindow::selectAll() {
for ( auto &x : checkboxes ) {
SendMessage( x, BM_SETCHECK, BST_CHECKED, NULL );
}
}
void SeasonWindow::selectNone() {
for ( auto &x : checkboxes ) {
SendMessage( x, BM_SETCHECK, BST_UNCHECKED, NULL );
}
}
void SeasonWindow::storeResult() {
for ( unsigned long long i = 0; i < checkboxes.size(); i++ ) {
if ( SendMessage( checkboxes[i], BM_GETCHECK, 0, 0 ) == BST_CHECKED ) {
returned.push_back( season_nums[i] );
}
}
}

33
windows/seasonwindow.hpp Normal file
View File

@ -0,0 +1,33 @@
#include <string>
#include <vector>
#include <windows.h>
class SeasonWindow {
public:
SeasonWindow( HINSTANCE hInstance, const std::vector< int > &seasons,
std::vector< int > &return_vector, HWND parent_window );
void mainLoop();
static LRESULT CALLBACK messageHandler( HWND hwnd, UINT umsg, WPARAM wParam,
LPARAM lParam );
~SeasonWindow() {
EnableWindow( parent, true );
SetFocus( parent );
}
private:
void selectNone();
void selectAll();
void storeResult();
HWND window;
HWND parent;
const int window_width{ 250 };
const int window_height{ 250 };
std::vector< HWND > checkboxes;
std::vector< int > &returned;
const std::vector< int > &season_nums;
static SeasonWindow *sw;
};