From 4196fc45d8090c3f81462442e85e3f0b948cb6ec Mon Sep 17 00:00:00 2001 From: Erik Faye-Lund Date: Fri, 15 Feb 2008 19:01:30 +0000 Subject: [PATCH] cleaning up the structure a bit --- client.cpp | 46 --- editor/synceditdata.h | 252 ++++++++++++ editor/synctracker2.cpp | 492 ++++++++++++++++++++++++ editor/trackview.cpp | 992 ++++++++++++++++++++++++++++++++++++++++++++++++ editor/trackview.h | 143 +++++++ example.cpp | 2 +- example_bass.cpp | 17 +- network.cpp | 74 ---- network.h | 29 -- stdafx.h | 1 + sync/device_client.cpp | 2 +- sync/network.cpp | 75 ++++ sync/network.h | 31 ++ synceditdata.h | 253 ------------ synctracker2.cpp | 490 ------------------------ synctracker2.vcproj | 22 +- trackview.cpp | 992 ------------------------------------------------ trackview.h | 143 ------- 18 files changed, 2010 insertions(+), 2046 deletions(-) delete mode 100644 client.cpp create mode 100644 editor/synceditdata.h create mode 100644 editor/synctracker2.cpp create mode 100644 editor/trackview.cpp create mode 100644 editor/trackview.h delete mode 100644 network.cpp delete mode 100644 network.h create mode 100644 sync/network.cpp create mode 100644 sync/network.h delete mode 100644 synceditdata.h delete mode 100644 synctracker2.cpp delete mode 100644 trackview.cpp delete mode 100644 trackview.h diff --git a/client.cpp b/client.cpp deleted file mode 100644 index 3e51bda..0000000 --- a/client.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include "network.h" -#include "syncdataclient.h" -#include "syncdevice.h" - -int main(int argc, char *argv[]) -{ - if (false == initNetwork()) - { - fputs("Failed to init WinSock", stderr); - exit(1); - } - - struct hostent * myhost = gethostbyname("localhost"); - printf("Found IP Address!\n"); - - struct sockaddr_in sain; - sain.sin_family = AF_INET; - sain.sin_port = htons(1338); - sain.sin_addr.s_addr= *( (unsigned long *)(myhost->h_addr_list[0]) ); - SOCKET serverSocket = serverConnect(&sain); - - if (INVALID_SOCKET == serverSocket) - { - puts("connection failed."); - exit(-1); - } - - SyncDataClient syncData(serverSocket); - SyncTrack &track = syncData.getTrack("test"); -// SyncTrack &track2 = syncData.getTrack("test2"); - - puts("recieving..."); - bool done = false; - while (!done) - { -// putchar('.'); - done = syncData.poll(); - } - closesocket(serverSocket); - - closeNetwork(); - - - return 0; -} diff --git a/editor/synceditdata.h b/editor/synceditdata.h new file mode 100644 index 0000000..c78c83c --- /dev/null +++ b/editor/synceditdata.h @@ -0,0 +1,252 @@ +#pragma once + +#include "../sync/network.h" +#include "../sync/data.h" +#include +#include + +class SyncEditData : public sync::Data +{ +public: + SyncEditData() : sync::Data(), clientPaused(true) {} + + void sendSetKeyCommand(int track, int row, const sync::Track::KeyFrame &key) + { + if (INVALID_SOCKET == clientSocket) return; + if (clientRemap.count(track) == 0) return; + track = int(clientRemap[track]); + + unsigned char cmd = SET_KEY; + send(clientSocket, (char*)&cmd, 1, 0); + send(clientSocket, (char*)&track, sizeof(int), 0); + send(clientSocket, (char*)&row, sizeof(int), 0); + send(clientSocket, (char*)&key.value, sizeof(float), 0); +// send(clientSocket, (char*)&key.lerp, 1, 0); + } + + void sendDeleteKeyCommand(int track, int row) + { + if (INVALID_SOCKET == clientSocket) return; + + unsigned char cmd = DELETE_KEY; + send(clientSocket, (char*)&cmd, 1, 0); + send(clientSocket, (char*)&track, sizeof(int), 0); + send(clientSocket, (char*)&row, sizeof(int), 0); + } + + void sendSetRowCommand(int row) + { + if (INVALID_SOCKET == clientSocket) return; + + unsigned char cmd = SET_ROW; + send(clientSocket, (char*)&cmd, 1, 0); + send(clientSocket, (char*)&row, sizeof(int), 0); + } + + void sendPauseCommand(bool pause) + { + unsigned char cmd = PAUSE; + send(clientSocket, (char*)&cmd, 1, 0); + unsigned char flag = pause; + send(clientSocket, (char*)&flag, 1, 0); + clientPaused = pause; + } + + + class Command + { + public: + virtual ~Command() {} + virtual void exec(SyncEditData *data) = 0; + virtual void undo(SyncEditData *data) = 0; + }; + + class InsertCommand : public Command + { + public: + InsertCommand(int track, int row, const sync::Track::KeyFrame &key) : track(track), row(row), key(key) {} + ~InsertCommand() {} + + virtual void exec(SyncEditData *data) + { + sync::Track &t = data->getTrack(this->track); + assert(!t.isKeyFrame(row)); + t.setKeyFrame(row, key); + + data->sendSetKeyCommand(track, row, key); // update clients + } + + virtual void undo(SyncEditData *data) + { + sync::Track &t = data->getTrack(this->track); + assert(t.isKeyFrame(row)); + t.deleteKeyFrame(row); + + data->sendDeleteKeyCommand(track, row); // update clients + } + + private: + int track, row; + sync::Track::KeyFrame key; + }; + + class DeleteCommand : public Command + { + public: + DeleteCommand(int track, int row) : track(track), row(row) {} + ~DeleteCommand() {} + + virtual void exec(SyncEditData *data) + { + sync::Track &t = data->getTrack(this->track); + assert(t.isKeyFrame(row)); + oldKey = *t.getKeyFrame(row); + t.deleteKeyFrame(row); + + data->sendDeleteKeyCommand(track, row); // update clients + } + + virtual void undo(SyncEditData *data) + { + sync::Track &t = data->getTrack(this->track); + assert(!t.isKeyFrame(row)); + t.setKeyFrame(row, oldKey); + + data->sendSetKeyCommand(track, row, oldKey); // update clients + } + + private: + int track, row; + sync::Track::KeyFrame oldKey; + }; + + + class EditCommand : public Command + { + public: + EditCommand(int track, int row, const sync::Track::KeyFrame &key) : track(track), row(row), key(key) {} + ~EditCommand() {} + + virtual void exec(SyncEditData *data) + { + sync::Track &t = data->getTrack(this->track); + + // store old key + assert(t.isKeyFrame(row)); + oldKey = *t.getKeyFrame(row); + + // update + t.setKeyFrame(row, key); + + data->sendSetKeyCommand(track, row, key); // update clients + } + + virtual void undo(SyncEditData *data) + { + sync::Track &t = data->getTrack(this->track); + + assert(t.isKeyFrame(row)); + t.setKeyFrame(row, oldKey); + + data->sendSetKeyCommand(track, row, oldKey); // update clients + } + + private: + int track, row; + sync::Track::KeyFrame oldKey, key; + }; + + class MultiCommand : public Command + { + public: + ~MultiCommand() + { + std::list::iterator it; + for (it = commands.begin(); it != commands.end(); ++it) + { + delete *it; + } + commands.clear(); + } + + void addCommand(Command *cmd) + { + commands.push_back(cmd); + } + + size_t getSize() const { return commands.size(); } + + virtual void exec(SyncEditData *data) + { + std::list::iterator it; + for (it = commands.begin(); it != commands.end(); ++it) (*it)->exec(data); + } + + virtual void undo(SyncEditData *data) + { + std::list::iterator it; + for (it = commands.begin(); it != commands.end(); ++it) (*it)->undo(data); + } + + private: + std::list commands; + }; + + void exec(Command *cmd) + { + undoStack.push(cmd); + cmd->exec(this); + clearRedoStack(); + } + + bool undo() + { + if (undoStack.size() == 0) return false; + + Command *cmd = undoStack.top(); + undoStack.pop(); + + redoStack.push(cmd); + cmd->undo(this); + return true; + } + + bool redo() + { + if (redoStack.size() == 0) return false; + + Command *cmd = redoStack.top(); + redoStack.pop(); + + undoStack.push(cmd); + cmd->exec(this); + return true; + } + + void clearRedoStack() + { + while (!redoStack.empty()) + { + Command *cmd = redoStack.top(); + redoStack.pop(); + delete cmd; + } + } + + Command *getSetKeyFrameCommand(int track, int row, const sync::Track::KeyFrame &key) + { + sync::Track &t = getTrack(track); + SyncEditData::Command *cmd; + if (t.isKeyFrame(row)) cmd = new EditCommand(track, row, key); + else cmd = new InsertCommand(track, row, key); + return cmd; + } + + SOCKET clientSocket; +// private: + std::map clientRemap; + bool clientPaused; + + std::stack undoStack; + std::stack redoStack; +}; diff --git a/editor/synctracker2.cpp b/editor/synctracker2.cpp new file mode 100644 index 0000000..e401817 --- /dev/null +++ b/editor/synctracker2.cpp @@ -0,0 +1,492 @@ +// synctracker2.cpp : Defines the entry point for the console application. +// + +#include "../stdafx.h" + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include "trackview.h" +#include +const TCHAR *mainWindowClassName = _T("MainWindow"); + +TrackView *trackView; +HWND trackViewWin; +HWND statusBarWin; + +#define WM_SETROWS (WM_USER+1) +#define WM_BIASSELECTION (WM_USER+2) + +#include "../sync/network.h" + +static LRESULT CALLBACK setRowsDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { +/* case WM_CHAR: + printf("char: %d %d\n", wParam, lParam); + break; */ + + case WM_INITDIALOG: + { + int *rows = (int*)lParam; + assert(NULL != rows); + + /* create row-string */ + TCHAR temp[256]; + _sntprintf_s(temp, 256, _T("%d"), *rows); + + /* set initial row count */ + SetDlgItemText(hDlg, IDC_SETROWS_EDIT, temp); + return TRUE; + } + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + /* get value */ + TCHAR temp[256]; + GetDlgItemText(hDlg, IDC_SETROWS_EDIT, temp, 256); + int result = _tstoi(temp); + + /* update editor */ + SendMessage(GetParent(hDlg), WM_SETROWS, 0, result); + + /* end dialog */ + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + else if(LOWORD(wParam)== IDCANCEL) + { + EndDialog( hDlg, LOWORD(wParam)); + return TRUE; + } + break; + + case WM_CLOSE: + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + + return FALSE; +} + +static LRESULT CALLBACK biasSelectionDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + { + int *intialBias = (int*)lParam; + assert(NULL != intialBias); + + /* create bias-string */ + TCHAR temp[256]; + _sntprintf_s(temp, 256, _T("%d"), *intialBias); + + /* set initial bias */ + SetDlgItemText(hDlg, IDC_SETROWS_EDIT, temp); + } + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) + { + /* get value */ + TCHAR temp[256]; + GetDlgItemText(hDlg, IDC_BIASSELECTION_EDIT, temp, 256); + int bias = _tstoi(temp); + + /* update editor */ + SendMessage(GetParent(hDlg), WM_BIASSELECTION, 0, LPARAM(bias)); + + /* end dialog */ + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + else if(LOWORD(wParam)== IDCANCEL) + { + EndDialog( hDlg, LOWORD(wParam)); + } + break; + + case WM_CLOSE: + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + + return FALSE; +} + +static LRESULT CALLBACK mainWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_CREATE: + { + HINSTANCE hInstance = GetModuleHandle(NULL); + trackViewWin = trackView->create(hInstance, hwnd); + InitCommonControls(); + statusBarWin = CreateWindowEx( + 0, // no extended styles + STATUSCLASSNAME, // status bar + (LPCTSTR)NULL, // no text + SBARS_SIZEGRIP | WS_VISIBLE | WS_CHILD, // styles + 0, 0, 0, 0, // x, y, cx, cy + hwnd, // parent window + NULL, // menu + hInstance, // instance + NULL // window data + ); + + int statwidths[] = { 100, -1 }; + SendMessage(statusBarWin, SB_SETPARTS, sizeof(statwidths) / sizeof(int), (LPARAM)statwidths); + SendMessage(statusBarWin, SB_SETTEXT, 0, (LPARAM)_T("Hi there :)")); + SendMessage(statusBarWin, SB_SETTEXT, 1, (LPARAM)_T("Hi there :)")); + } + break; + + case WM_SIZE: + { + int width = LOWORD(lParam); + int height = HIWORD(lParam); + + RECT statusBarRect; + GetClientRect(statusBarWin, &statusBarRect); + int statusBarHeight = statusBarRect.bottom - statusBarRect.top; + + MoveWindow(trackViewWin, 0, 0, width, height - statusBarHeight, TRUE); + MoveWindow(statusBarWin, 0, height - statusBarHeight, width, statusBarHeight, TRUE); + } + break; + + case WM_SETFOCUS: + SetFocus(trackViewWin); // needed to forward keyboard input + break; + + case WM_SETROWS: + printf("rows: %d\n", int(lParam)); + trackView->setRows(int(lParam)); + break; + + case WM_BIASSELECTION: + trackView->editBiasValue(float(lParam)); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case ID_FILE_SAVE: + case ID_FILE_SAVE_AS: + case ID_FILE_OPEN: + MessageBox(trackViewWin, "Not implemented", NULL, MB_OK | MB_ICONERROR); + break; + + case ID_FILE_EXIT: PostQuitMessage(0); break; + case ID_EDIT_UNDO: SendMessage(trackViewWin, WM_UNDO, 0, 0); break; + case ID_EDIT_REDO: SendMessage(trackViewWin, WM_REDO, 0, 0); break; + case ID_EDIT_COPY: SendMessage(trackViewWin, WM_COPY, 0, 0); break; + case ID_EDIT_CUT: SendMessage(trackViewWin, WM_CUT, 0, 0); break; + case ID_EDIT_PASTE: SendMessage(trackViewWin, WM_PASTE, 0, 0); break; + + case ID_EDIT_SETROWS: + { + HINSTANCE hInstance = GetModuleHandle(NULL); + int rows = trackView->getRows(); + INT_PTR result = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_SETROWS), hwnd, (DLGPROC)setRowsDialogProc, (LPARAM)&rows); + if (FAILED(result)) MessageBox(NULL, _T("unable to create dialog box"), NULL, MB_OK); + } + break; + + case ID_EDIT_BIAS: + { + HINSTANCE hInstance = GetModuleHandle(NULL); + int initialBias = 0; + INT_PTR result = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_BIASSELECTION), hwnd, (DLGPROC)biasSelectionDialogProc, (LPARAM)&initialBias); + if (FAILED(result)) MessageBox(NULL, _T("unable to create dialog box"), NULL, MB_OK); + } + break; + } + break; + + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; +} + +static ATOM registerMainWindowClass(HINSTANCE hInstance) +{ + WNDCLASSEX wc; + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = 0; + wc.lpfnWndProc = mainWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)0; + wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU); + wc.lpszClassName = mainWindowClassName; + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + return RegisterClassEx(&wc); +} + +int _tmain(int argc, _TCHAR* argv[]) +{ +#ifdef _DEBUG + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); +/* _CrtSetBreakAlloc(68); */ +#endif + + HINSTANCE hInstance = GetModuleHandle(NULL); + +#if 1 + if (false == initNetwork()) + { + fputs("Failed to init WinSock", stderr); + exit(1); + } + + SOCKET serverSocket = socket( AF_INET, SOCK_STREAM, 0 ); + + struct sockaddr_in sin; + memset( &sin, 0, sizeof sin ); + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons( 1338 ); + + puts("binding..."); + if (SOCKET_ERROR == bind( serverSocket, (struct sockaddr *)&sin, sizeof(sin))) + { + fputs("Coult not start server", stderr); + exit(1); + } + + puts("listening..."); + while ( listen( serverSocket, SOMAXCONN ) == SOCKET_ERROR ); + +/* ULONG nonBlock = 1; + if (ioctlsocket(serverSocket, FIONBIO, &nonBlock) == SOCKET_ERROR) + { + printf("ioctlsocket() failed\n"); + return 0; + } */ +#endif + + SyncEditData syncData; + syncData.clientSocket = INVALID_SOCKET; +#if 0 + + SyncTrack &camXTrack = syncData.getTrack(_T("cam.x")); + SyncTrack &camXTrack2 = syncData.getTrack(_T("cam.x")); + camXTrack.setKeyFrame(1, 2.0f); + camXTrack.setKeyFrame(4, 3.0f); + printf("%p %p\n", &camXTrack, &camXTrack2); + + SyncTrack &camYTrack = syncData.getTrack(_T("cam.y")); + SyncTrack &camZTrack = syncData.getTrack(_T("cam.z")); + +/* for (int i = 0; i < 16; ++i) + { + TCHAR temp[256]; + _sntprintf_s(temp, 256, _T("gen %02d"), i); + SyncTrack &temp2 = syncData.getTrack(temp); + } */ + + camXTrack.setKeyFrame(1, 2.0f); + camXTrack.setKeyFrame(4, 3.0f); + + camYTrack.setKeyFrame(0, 100.0f); + camYTrack.setKeyFrame(8, 999.0f); + + camYTrack.setKeyFrame(16, SyncTrack::KeyFrame(float(1E-5))); + + for (int i = 0; i < 5 * 2; ++i) + { + float time = float(i) / 2; + printf("%f %d - %f\n", time, camXTrack.isKeyFrame(i), camXTrack.getValue(time)); + } +#endif + + ATOM mainClass = registerMainWindowClass(hInstance); + ATOM trackViewClass = registerTrackViewWindowClass(hInstance); + if (!mainClass || !trackViewClass) + { + MessageBox(NULL, _T("Window Registration Failed!"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK); + return 0; + } + + trackView = new TrackView(); + trackView->setSyncData(&syncData); + + HWND hwnd = CreateWindowEx( + 0, + mainWindowClassName, + _T("SyncTracker 3000"), + WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, + CW_USEDEFAULT, CW_USEDEFAULT, // x, y + CW_USEDEFAULT, CW_USEDEFAULT, // width, height + NULL, NULL, hInstance, NULL + ); + printf("main window: %p\n", hwnd); + + if (NULL == hwnd) + { + MessageBox(NULL, _T("Window Creation Failed!"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK); + return 0; + } + + HACCEL accel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); + printf("accel: %p\n", accel); + + ShowWindow(hwnd, TRUE); + UpdateWindow(hwnd); + +#if 1 + + printf("server socket %x\n", serverSocket); + + bool done = false; + SOCKET clientSocket = INVALID_SOCKET; + MSG msg; + while (!done) + { +#if 1 + if (INVALID_SOCKET == clientSocket) + { + fd_set fds; + FD_ZERO(&fds); + FD_SET(serverSocket, &fds); + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + // look for new clients + if (select(0, &fds, NULL, NULL, &timeout) > 0) + { + puts("accepting..."); + clientSocket = clientConnect(serverSocket); + if (INVALID_SOCKET != clientSocket) + { + puts("connected."); + syncData.clientSocket = clientSocket; + syncData.clientRemap.clear(); + syncData.sendPauseCommand(true); + syncData.sendSetRowCommand(trackView->getEditRow()); + } + } + } + + if (INVALID_SOCKET != clientSocket) + { + // look for new commands + while (pollRead(clientSocket)) + { + unsigned char cmd = 0; + int ret = recv(clientSocket, (char*)&cmd, 1, 0); + if (1 > ret) + { + closesocket(clientSocket); + clientSocket = INVALID_SOCKET; + syncData.clientSocket = INVALID_SOCKET; + syncData.clientRemap.clear(); + InvalidateRect(trackViewWin, NULL, FALSE); + break; + } + else + { + switch (cmd) + { + case GET_TRACK: + { + size_t clientIndex = 0; + int ret = recv(clientSocket, (char*)&clientIndex, sizeof(int), 0); + printf("client index: %d\n", clientIndex); + + // get len + int str_len = 0; + ret = recv(clientSocket, (char*)&str_len, sizeof(int), 0); + + // int clientAddr = 0; + // int ret = recv(clientSocket, (char*)&clientAddr, sizeof(int), 0); + + // get string + std::string trackName; + trackName.resize(str_len); + recv(clientSocket, &trackName[0], str_len, 0); + + // find track + size_t serverIndex = syncData.getTrackIndex(trackName.c_str()); + printf("name: \"%s\"\n", trackName.c_str()); + + // setup remap + syncData.clientRemap[serverIndex] = clientIndex; + + const sync::Track &track = *syncData.actualTracks[serverIndex]; + + sync::Track::KeyFrameContainer::const_iterator it; + for (it = track.keyFrames.begin(); it != track.keyFrames.end(); ++it) + { + int row = int(it->first); + const sync::Track::KeyFrame &key = it->second; + syncData.sendSetKeyCommand(int(serverIndex), row, key); + } + + InvalidateRect(trackViewWin, NULL, FALSE); + } + break; + + case SET_ROW: + { + int newRow = 0; + int ret = recv(clientSocket, (char*)&newRow, sizeof(int), 0); + printf("new row: %d\n", newRow); + trackView->setEditRow(newRow); + } + break; + } + } + } + } +#endif + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (!TranslateAccelerator(hwnd, accel, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + if (WM_QUIT == msg.message) done = true; + } + } + Sleep(1); + } + + closesocket(clientSocket); + closesocket(serverSocket); + closeNetwork(); + +#else + // Step 3: The Message Loop + while(GetMessage(&msg, NULL, 0, 0) > 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +#endif + + delete trackView; + trackView = NULL; + + UnregisterClass(mainWindowClassName, hInstance); + return int(msg.wParam); +} \ No newline at end of file diff --git a/editor/trackview.cpp b/editor/trackview.cpp new file mode 100644 index 0000000..586758b --- /dev/null +++ b/editor/trackview.cpp @@ -0,0 +1,992 @@ +#include "../stdafx.h" + +#include "trackview.h" +#include + +static const TCHAR *trackViewWindowClassName = _T("TrackView"); + +static const int topMarginHeight = 20; +static const int leftMarginWidth = 60; + +static const int fontHeight = 16; +static const int fontWidth = 6; + +static const int trackWidth = fontWidth * 16; +static DWORD darken(DWORD col, float amt) +{ + return RGB(GetRValue(col) * amt, GetGValue(col) * amt, GetBValue(col) * amt); +} + +TrackView::TrackView() +{ + scrollPosX = 0; + scrollPosY = 0; + windowWidth = -1; + windowHeight = -1; + + editRow = 0; + editTrack = 0; + rows = 0x80; + + selectStartTrack = selectStopTrack = 0; + selectStartRow = selectStopRow = 0; + + this->hwnd = NULL; + + bgBaseBrush = GetSysColorBrush(COLOR_WINDOW); + bgDarkBrush = CreateSolidBrush(darken(GetSysColor(COLOR_WINDOW), 0.9f)); + + selectBaseBrush = GetSysColorBrush(COLOR_HIGHLIGHT); + selectDarkBrush = CreateSolidBrush(darken(GetSysColor(COLOR_HIGHLIGHT), 0.9f)); + + rowPen = CreatePen(PS_SOLID, 1, darken(GetSysColor(COLOR_WINDOW), 0.7f)); + rowSelectPen = CreatePen(PS_SOLID, 1, darken(GetSysColor(COLOR_HIGHLIGHT), 0.7f)); + + editBrush = CreateSolidBrush(RGB(255, 255, 0)); // yellow + + clipboardFormat = RegisterClipboardFormat(_T("syncdata")); + assert(0 != clipboardFormat); +} + +TrackView::~TrackView() +{ + DeleteObject(bgBaseBrush); + DeleteObject(bgDarkBrush); + DeleteObject(selectBaseBrush); + DeleteObject(selectDarkBrush); + DeleteObject(editBrush); + DeleteObject(rowPen); + DeleteObject(rowSelectPen); +} + +int TrackView::getScreenY(int row) +{ + return topMarginHeight + (row * fontHeight) - scrollPosY; +} + +int TrackView::getScreenX(int track) +{ + return leftMarginWidth + (track * trackWidth) - scrollPosX; +} + +LRESULT TrackView::onCreate() +{ + setupScrollBars(); + return FALSE; +} + +LRESULT TrackView::onPaint() +{ + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + + SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); +// SelectObject(hdc, GetStockObject(SYSTEM_FONT)); + paintTracks(hdc, ps.rcPaint); + + EndPaint(hwnd, &ps); + + return FALSE; +} + +void TrackView::paintTopMargin(HDC hdc, RECT rcTracks) +{ + RECT fillRect; + RECT topLeftMargin; + topLeftMargin.top = 0; + topLeftMargin.bottom = topMarginHeight; + topLeftMargin.left = 0; + topLeftMargin.right = leftMarginWidth; + fillRect = topLeftMargin; + DrawEdge(hdc, &fillRect, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_ADJUST | BF_BOTTOM); + FillRect(hdc, &fillRect, GetSysColorBrush(COLOR_3DFACE)); + + int firstTrack = min(max(scrollPosX / trackWidth, 0), getTrackCount() - 1); + int lastTrack = min(max(firstTrack + windowTracks + 1, 0), getTrackCount() - 1); + + sync::Data *syncData = getSyncData(); + if (NULL == syncData) return; + + SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + + sync::Data::TrackContainer::iterator trackIter = syncData->tracks.begin(); + for (int track = 0; track <= lastTrack; ++track, ++trackIter) + { + assert(trackIter != syncData->tracks.end()); + if (track < firstTrack) continue; + + RECT topMargin; + + topMargin.top = 0; + topMargin.bottom = topMarginHeight; + + topMargin.left = getScreenX(track); + topMargin.right = topMargin.left + trackWidth; + + if (!RectVisible(hdc, &topMargin)) continue; + + RECT fillRect = topMargin; + + HBRUSH bgBrush = GetSysColorBrush(COLOR_3DFACE); + if (track == editTrack) bgBrush = editBrush; + + DrawEdge(hdc, &fillRect, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_ADJUST | BF_LEFT | BF_RIGHT | BF_BOTTOM); + FillRect(hdc, &fillRect, bgBrush); + + const std::basic_string &trackName = trackIter->first; + + if (this->syncData->clientRemap.count(track) == 0) SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + else SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + TextOut(hdc, + fillRect.left, 0, + trackName.data(), int(trackName.length()) + ); + } + + RECT topRightMargin; + topRightMargin.top = 0; + topRightMargin.bottom = topMarginHeight; + topRightMargin.left = getScreenX(getTrackCount()); + topRightMargin.right = rcTracks.right; + fillRect = topRightMargin; + DrawEdge(hdc, &fillRect, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_ADJUST | BF_BOTTOM); + FillRect(hdc, &fillRect, GetSysColorBrush(COLOR_3DFACE)); + + // make sure that the top margin isn't overdrawn by the track-data + ExcludeClipRect(hdc, 0, 0, rcTracks.right, topMarginHeight); +} + +void TrackView::paintTracks(HDC hdc, RECT rcTracks) +{ + TCHAR temp[256]; + + int firstTrack = min(max(scrollPosX / trackWidth, 0), getTrackCount() - 1); + int lastTrack = min(max(firstTrack + windowTracks + 1, 0), getTrackCount() - 1); + + int firstRow = editRow - windowRows / 2 - 1; + int lastRow = editRow + windowRows / 2 + 1; + /* clamp first & last row */ + firstRow = min(max(firstRow, 0), rows - 1); + lastRow = min(max(lastRow, 0), rows - 1); + + SetBkMode(hdc, TRANSPARENT); + paintTopMargin(hdc, rcTracks); + + for (int row = firstRow; row <= lastRow; ++row) + { + RECT leftMargin; + leftMargin.left = 0; + leftMargin.right = leftMarginWidth; + leftMargin.top = getScreenY(row); + leftMargin.bottom = leftMargin.top + fontHeight; + + if (!RectVisible(hdc, &leftMargin)) continue; + + HBRUSH fillBrush; + if (row == editRow) fillBrush = editBrush; + else fillBrush = GetSysColorBrush(COLOR_3DFACE); + FillRect(hdc, &leftMargin, fillBrush); + + DrawEdge(hdc, &leftMargin, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_RIGHT | BF_BOTTOM | BF_TOP); + if ((row % 8) == 0) SetTextColor(hdc, RGB(0, 0, 0)); + else if ((row % 4) == 0) SetTextColor(hdc, RGB(64, 64, 64)); + else SetTextColor(hdc, RGB(128, 128, 128)); + +/* if ((row % 4) == 0) SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); + else SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); */ + + _sntprintf_s(temp, 256, _T("%0*Xh"), 5, row); + TextOut(hdc, + leftMargin.left, leftMargin.top, + temp, int(_tcslen(temp)) + ); + } + + SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + + sync::Data *syncData = getSyncData(); + if (NULL == syncData) return; + + int selectLeft = min(selectStartTrack, selectStopTrack); + int selectRight = max(selectStartTrack, selectStopTrack); + int selectTop = min(selectStartRow, selectStopRow); + int selectBottom = max(selectStartRow, selectStopRow); + + sync::Data::TrackContainer::iterator trackIter = syncData->tracks.begin(); + for (int track = 0; track <= lastTrack; ++track, ++trackIter) + { + assert(trackIter != syncData->tracks.end()); + if (track < firstTrack) continue; + + for (int row = firstRow; row <= lastRow; ++row) + { + RECT patternDataRect; + patternDataRect.left = getScreenX(track); + patternDataRect.right = patternDataRect.left + trackWidth; + patternDataRect.top = getScreenY(row); + patternDataRect.bottom = patternDataRect.top + fontHeight; + + if (!RectVisible(hdc, &patternDataRect)) continue; + + bool selected = (track >= selectLeft && track <= selectRight) && (row >= selectTop && row <= selectBottom); + + HBRUSH baseBrush = bgBaseBrush; + HBRUSH darkBrush = bgDarkBrush; + if (selected) + { + baseBrush = selectBaseBrush; + darkBrush = selectDarkBrush; + } + + HBRUSH bgBrush = baseBrush; + if (row % 8 == 0) bgBrush = darkBrush; + + RECT fillRect = patternDataRect; +// if (row == editRow && track == editTrack) DrawEdge(hdc, &fillRect, BDR_RAISEDINNER | BDR_SUNKENOUTER, BF_ADJUST | BF_TOP | BF_BOTTOM | BF_LEFT | BF_RIGHT); + FillRect( hdc, &fillRect, bgBrush); + if (row % 8 == 0) + { + MoveToEx(hdc, patternDataRect.left, patternDataRect.top, (LPPOINT) NULL); + if (selected) SelectObject(hdc, rowSelectPen); + else SelectObject(hdc, rowPen); + LineTo(hdc, patternDataRect.right, patternDataRect.top); + } + + bool drawEditString = false; + if (row == editRow && track == editTrack) + { + FrameRect(hdc, &fillRect, (HBRUSH)GetStockObject(BLACK_BRUSH)); +// DrawFocusRect(hdc, &fillRect); +// Rectangle(hdc, fillRect.left, fillRect.top, fillRect.right, fillRect.bottom); + if (editString.size() > 0) drawEditString = true; + } + +// InvertRect(hdc, &fillRect); + + const sync::Track &track = *syncData->actualTracks[trackIter->second]; + bool key = track.isKeyFrame(row); + + /* format the text */ + if (drawEditString) _sntprintf_s(temp, 256, editString.c_str()); + else if (!key) _sntprintf_s(temp, 256, _T(" ---")); + else + { + float val = track.getKeyFrame(row)->value; + _sntprintf_s(temp, 256, _T("% .2f"), val); + } + + COLORREF oldCol; + if (selected) oldCol = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + TextOut(hdc, + patternDataRect.left, patternDataRect.top, + temp, int(_tcslen(temp)) + ); + if (selected) SetTextColor(hdc, oldCol); + } + } + + /* right margin */ + { + RECT rightMargin; + rightMargin.top = getScreenY(0); + rightMargin.bottom = getScreenY(rows); + rightMargin.left = getScreenX(getTrackCount()); + rightMargin.right = rcTracks.right; + FillRect( hdc, &rightMargin, GetSysColorBrush(COLOR_APPWORKSPACE)); + } + + { + RECT bottomPadding; + bottomPadding.top = getScreenY(rows); + bottomPadding.bottom = rcTracks.bottom; + bottomPadding.left = rcTracks.left; + bottomPadding.right = rcTracks.right; + FillRect(hdc, &bottomPadding, GetSysColorBrush(COLOR_APPWORKSPACE)); + } + + { + RECT topPadding; + topPadding.top = max(rcTracks.top, topMarginHeight); + topPadding.bottom = getScreenY(0); + topPadding.left = rcTracks.left; + topPadding.right = rcTracks.right; + FillRect(hdc, &topPadding, GetSysColorBrush(COLOR_APPWORKSPACE)); + } +} + +struct CopyEntry +{ + int track, row; + sync::Track::KeyFrame keyFrame; +}; + + +void TrackView::editCopy() +{ + int selectLeft = min(selectStartTrack, selectStopTrack); + int selectRight = max(selectStartTrack, selectStopTrack); + int selectTop = min(selectStartRow, selectStopRow); + int selectBottom = max(selectStartRow, selectStopRow); + + if (FAILED(OpenClipboard(getWin()))) + { + MessageBox(NULL, _T("Failed to open clipboard"), NULL, MB_OK); + return; + } + + // gather data + int rows = selectBottom - selectTop + 1; + int columns = selectRight - selectLeft + 1; + size_t cells = columns * rows; + + std::vector copyEntries; + for (int track = selectLeft; track <= selectRight; ++track) + { + int localTrack = track - selectLeft; + const sync::Track &t = syncData->getTrack(track); + for (int row = selectTop; row <= selectBottom; ++row) + { + int localRow = row - selectTop; + if (t.isKeyFrame(row)) + { + const sync::Track::KeyFrame *keyFrame = t.getKeyFrame(row); + assert(NULL != keyFrame); + + CopyEntry ce; + ce.track = localTrack; + ce.row = localRow; + ce.keyFrame = *keyFrame; + + copyEntries.push_back(ce); + } + } + } + + int buffer_width = selectRight - selectLeft + 1; + int buffer_height = selectBottom - selectTop + 1; + size_t buffer_size = copyEntries.size(); + + HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE, sizeof(int) * 3 + sizeof(CopyEntry) * copyEntries.size()); + char *clipbuf = (char *)GlobalLock(hmem); + + // copy data + memcpy(clipbuf + 0, &buffer_width, sizeof(int)); + memcpy(clipbuf + sizeof(int), &buffer_height, sizeof(int)); + memcpy(clipbuf + 2 * sizeof(int), &buffer_size, sizeof(size_t)); + if (copyEntries.size() > 0 ) memcpy(clipbuf + 2 * sizeof(int) + sizeof(size_t), ©Entries[0], sizeof(CopyEntry) * copyEntries.size()); + + GlobalUnlock(hmem); + clipbuf = NULL; + + // update clipboard + EmptyClipboard(); + SetClipboardData(clipboardFormat, hmem); + CloseClipboard(); +} + +void TrackView::editCut() +{ + editCopy(); + editDelete(); +} + +void TrackView::editPaste() +{ +#if 1 + if (FAILED(OpenClipboard(getWin()))) + { + MessageBox(NULL, _T("Failed to open clipboard"), NULL, MB_OK); + return; + } + + if (IsClipboardFormatAvailable(clipboardFormat)) + { + HGLOBAL hmem = GetClipboardData(clipboardFormat); + char *clipbuf = (char *)GlobalLock(hmem); + + // copy data + int buffer_width, buffer_height, buffer_size; + memcpy(&buffer_width, clipbuf + 0, sizeof(int)); + memcpy(&buffer_height, clipbuf + sizeof(int), sizeof(int)); + memcpy(&buffer_size, clipbuf + 2 * sizeof(int), sizeof(size_t)); + + if (buffer_size > 0) + { + char *src = clipbuf + 2 * sizeof(int) + sizeof(size_t); + + SyncEditData::MultiCommand *multiCmd = new SyncEditData::MultiCommand(); + for (int i = 0; i < buffer_size; ++i) + { + struct CopyEntry ce; + memcpy(&ce, src, sizeof(CopyEntry)); + + SyncEditData::Command *cmd = syncData->getSetKeyFrameCommand(editTrack + ce.track, editRow + ce.row, ce.keyFrame); + multiCmd->addCommand(cmd); + src += sizeof(CopyEntry); + } + syncData->exec(multiCmd); + } + + GlobalUnlock(hmem); + clipbuf = NULL; + } + else MessageBeep(0); + + CloseClipboard(); +#endif +} + +void TrackView::setupScrollBars() +{ + SCROLLINFO si = { sizeof(si) }; + si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL; + si.nPos = editRow; + si.nPage = windowRows; + si.nMin = 0; + si.nMax = rows - 1 + windowRows - 1; + SetScrollInfo(hwnd, SB_VERT, &si, TRUE); + + si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL; + si.nPos = editTrack; + si.nPage = windowTracks; + si.nMin = 0; + si.nMax = getTrackCount() - 1 + windowTracks - 1; + SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); +} + +void TrackView::scrollWindow(int scrollX, int scrollY) +{ + RECT clip; + GetClientRect(hwnd, &clip); + + if (scrollX == 0) clip.top = topMarginHeight; // don't scroll the top margin + if (scrollY == 0) clip.left = leftMarginWidth; // don't scroll the left margin + + ScrollWindowEx( + hwnd, + scrollX, + scrollY, + NULL, + &clip, + NULL, + NULL, + SW_INVALIDATE + ); +} + +void TrackView::setScrollPos(int newScrollPosX, int newScrollPosY) +{ + // clamp newscrollPosX + newScrollPosX = max(newScrollPosX, 0); + + if (newScrollPosX != scrollPosX || newScrollPosY != scrollPosY) + { + int scrollX = scrollPosX - newScrollPosX; + int scrollY = scrollPosY - newScrollPosY; + + // update scrollPos + scrollPosX = newScrollPosX; + scrollPosY = newScrollPosY; + + scrollWindow(scrollX, scrollY); + } + setupScrollBars(); +} + +void TrackView::setEditRow(int newEditRow) +{ + int oldEditRow = editRow; + editRow = newEditRow; + + // clamp to document + editRow = min(max(editRow, 0), rows - 1); + + if (oldEditRow != editRow) + { + if (GetKeyState(VK_SHIFT) < 0) + { + selectStopRow = editRow; + invalidateRange(selectStartTrack, selectStopTrack, oldEditRow, editRow); + } + else + { + invalidateRange(selectStartTrack, selectStopTrack, selectStartRow, selectStopRow); + selectStartRow = selectStopRow = editRow; + selectStartTrack = selectStopTrack = editTrack; + } + getSyncData()->sendSetRowCommand(editRow); + } + + invalidateRow(oldEditRow); + invalidateRow(editRow); + + setScrollPos(scrollPosX, (editRow * fontHeight) - ((windowHeight - topMarginHeight) / 2) + fontHeight / 2); +} + +void TrackView::setEditTrack(int newEditTrack) +{ + int oldEditTrack = editTrack; + editTrack = newEditTrack; + + // clamp to document + editTrack = max(editTrack, 0); + editTrack = min(editTrack, getTrackCount() - 1); + + if (oldEditTrack != editTrack) + { + if (GetKeyState(VK_SHIFT) < 0) + { + selectStopTrack = editTrack; + invalidateRange(oldEditTrack, editTrack, selectStartRow, selectStopRow); + } + else + { + invalidateRange(selectStartTrack, selectStopTrack, selectStartRow, selectStopRow); + selectStartRow = selectStopRow = editRow; + selectStartTrack = selectStopTrack = editTrack; + } + } + + invalidateTrack(oldEditTrack); + invalidateTrack(editTrack); + + int firstTrack = scrollPosX / trackWidth; + int lastTrack = firstTrack + windowTracks; + + int newFirstTrack = firstTrack; + if (editTrack >= lastTrack) newFirstTrack = editTrack - (lastTrack - firstTrack - 1); + if (editTrack < firstTrack) newFirstTrack = editTrack; + setScrollPos(newFirstTrack * trackWidth, scrollPosY); +} + +static int getScrollPos(HWND hwnd, int bar) +{ + SCROLLINFO si = { sizeof(si), SIF_TRACKPOS }; + GetScrollInfo(hwnd, bar, &si); + return int(si.nTrackPos); +} + +void TrackView::setRows(int rows) +{ + this->rows = rows; + InvalidateRect(getWin(), NULL, FALSE); + setEditRow(min(editRow, rows - 1)); +} + + +LRESULT TrackView::onVScroll(UINT sbCode, int /*newPos*/) +{ + switch (sbCode) + { + case SB_TOP: + setEditRow(0); + break; + + case SB_LINEUP: + setEditRow(editRow - 1); + break; + + case SB_LINEDOWN: + setEditRow(editRow + 1); + break; + + case SB_PAGEUP: + setEditRow(editRow - windowRows / 2); + break; + + case SB_PAGEDOWN: + setEditRow(editRow + windowRows / 2); + break; + + case SB_THUMBPOSITION: + case SB_THUMBTRACK: + setEditRow(getScrollPos(hwnd, SB_VERT)); + break; + } + + return FALSE; +} + +LRESULT TrackView::onHScroll(UINT sbCode, int /*newPos*/) +{ + switch (sbCode) + { + case SB_LEFT: + setEditTrack(0); + break; + + case SB_RIGHT: + setEditTrack(getTrackCount() - 1); + break; + + case SB_LINELEFT: + setEditTrack(editTrack - 1); + break; + + case SB_LINERIGHT: + setEditTrack(editTrack + 1); + break; + + case SB_PAGELEFT: + setEditTrack(editTrack - windowTracks); + break; + + case SB_PAGEDOWN: + setEditTrack(editTrack + windowTracks); + break; + + case SB_THUMBPOSITION: + case SB_THUMBTRACK: + setEditTrack(getScrollPos(hwnd, SB_HORZ)); + break; + } + + return FALSE; +} + +void TrackView::editEnterValue() +{ + if (editString.size() > 0) + { + sync::Track &t = syncData->getTrack(editTrack); + + sync::Track::KeyFrame newKey; + if (t.isKeyFrame(editRow)) newKey = *t.getKeyFrame(editRow); // copy old key + newKey.value = float(_tstof(editString.c_str())); // modify value + + SyncEditData::Command *cmd = syncData->getSetKeyFrameCommand(editTrack, editRow, newKey); + syncData->exec(cmd); + + editString.clear(); + invalidatePos(editTrack, editRow); + } + else MessageBeep(0); +} + +void TrackView::editDelete() +{ + int selectLeft = min(selectStartTrack, selectStopTrack); + int selectRight = max(selectStartTrack, selectStopTrack); + int selectTop = min(selectStartRow, selectStopRow); + int selectBottom = max(selectStartRow, selectStopRow); + + SyncEditData::MultiCommand *multiCmd = new SyncEditData::MultiCommand(); + for (int track = selectLeft; track <= selectRight; ++track) + { + sync::Track &t = syncData->getTrack(track); + for (int row = selectTop; row <= selectBottom; ++row) + { + if (t.isKeyFrame(row)) + { + SyncEditData::Command *cmd = new SyncEditData::DeleteCommand(track, row); + multiCmd->addCommand(cmd); + } + } + } + + if (0 == multiCmd->getSize()) + { + MessageBeep(0); + delete multiCmd; + } + else + { + syncData->exec(multiCmd); + invalidateRange(selectLeft, selectRight, selectTop, selectBottom); + } +} + +void TrackView::editBiasValue(float amount) +{ + int selectLeft = min(selectStartTrack, selectStopTrack); + int selectRight = max(selectStartTrack, selectStopTrack); + int selectTop = min(selectStartRow, selectStopRow); + int selectBottom = max(selectStartRow, selectStopRow); + + SyncEditData::MultiCommand *multiCmd = new SyncEditData::MultiCommand(); + for (int track = selectLeft; track <= selectRight; ++track) + { + sync::Track &t = syncData->getTrack(track); + for (int row = selectTop; row <= selectBottom; ++row) + { + if (t.isKeyFrame(row)) + { + sync::Track::KeyFrame newKey = *t.getKeyFrame(row); // copy old key + newKey.value += amount; // modify value + + // add sub-command + SyncEditData::Command *cmd = syncData->getSetKeyFrameCommand(track, row, newKey); + multiCmd->addCommand(cmd); + } + } + } + + if (0 == multiCmd->getSize()) + { + MessageBeep(0); + delete multiCmd; + } + else + { + syncData->exec(multiCmd); + invalidateRange(selectLeft, selectRight, selectTop, selectBottom); + } +} + +LRESULT TrackView::onKeyDown(UINT keyCode, UINT /*flags*/) +{ + if (editString.empty() && getSyncData()->clientPaused) + { + switch (keyCode) + { + case VK_UP: + if (GetKeyState(VK_CONTROL) < 0) + { + float bias = 1.0f; + if (GetKeyState(VK_SHIFT) < 0) bias = 0.1f; + editBiasValue(bias); + } + else setEditRow(editRow - 1); + break; + + case VK_DOWN: + if (GetKeyState(VK_CONTROL) < 0) + { + float bias = 1.0f; + if (GetKeyState(VK_SHIFT) < 0) bias = 0.1f; + editBiasValue(-bias); + } + else setEditRow(editRow + 1); + break; + + case VK_LEFT: setEditTrack(editTrack - 1); break; + case VK_RIGHT: setEditTrack(editTrack + 1); break; + + case VK_PRIOR: + if (GetKeyState(VK_CONTROL) < 0) + { + float bias = 10.0f; + if (GetKeyState(VK_SHIFT) < 0) bias = 100.0f; + editBiasValue(bias); + } + else setEditRow(editRow - windowRows / 2); + break; + + case VK_NEXT: + if (GetKeyState(VK_CONTROL) < 0) + { + float bias = 10.0f; + if (GetKeyState(VK_SHIFT) < 0) bias = 100.0f; + editBiasValue(-bias); + } + else setEditRow(editRow + windowRows / 2); + break; + + default: + break; + } + } + + switch (keyCode) + { + case VK_RETURN: editEnterValue(); break; + case VK_DELETE: editDelete(); break; + + case VK_BACK: + if (!editString.empty()) + { + editString.resize(editString.size() - 1); + invalidatePos(editTrack, editRow); + } + else MessageBeep(0); + break; + + case VK_CANCEL: + case VK_ESCAPE: + if (!editString.empty()) + { + // return to old value (i.e don't clear) + editString.clear(); + invalidatePos(editTrack, editRow); + MessageBeep(0); + } + break; + case VK_SPACE: + getSyncData()->sendPauseCommand( !getSyncData()->clientPaused ); + break; + } + return FALSE; +} + +LRESULT TrackView::onChar(UINT keyCode, UINT flags) +{ + switch (char(keyCode)) + { + case '.': + // only one '.' allowed + if (std::string::npos != editString.find('.')) + { + MessageBeep(0); + break; + } + case '-': + if (editString.empty()) + { + editString.push_back(char(keyCode)); + invalidatePos(editTrack, editRow); + } + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + editString.push_back(char(keyCode)); + invalidatePos(editTrack, editRow); + break; + } + return FALSE; +} + +LRESULT TrackView::onSize(int width, int height) +{ + windowWidth = width; + windowHeight = height; + + windowRows = (height - topMarginHeight) / fontHeight; + windowTracks = (width - leftMarginWidth) / trackWidth; + + setEditRow(editRow); + setupScrollBars(); + return FALSE; +} + +LRESULT TrackView::windowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + assert(hwnd == this->hwnd); + + switch(msg) + { + case WM_CREATE: return onCreate(); + + case WM_CLOSE: + DestroyWindow(hwnd); + break; + + case WM_DESTROY: + PostQuitMessage(0); + break; + + case WM_SIZE: return onSize(LOWORD(lParam), HIWORD(lParam)); + case WM_VSCROLL: return onVScroll(LOWORD(wParam), getScrollPos(hwnd, SB_VERT)); + case WM_HSCROLL: return onHScroll(LOWORD(wParam), getScrollPos(hwnd, SB_HORZ)); + case WM_PAINT: return onPaint(); + case WM_KEYDOWN: return onKeyDown((UINT)wParam, (UINT)lParam); + case WM_CHAR: return onChar((UINT)wParam, (UINT)lParam); + + case WM_COPY: editCopy(); break; + case WM_CUT: editCut(); break; + case WM_PASTE: + editPaste(); + InvalidateRect(hwnd, NULL, FALSE); + break; + + case WM_UNDO: + if (!syncData->undo()) MessageBeep(0); + // unfortunately, we don't know how much to invalidate... so we'll just invalidate it all. + InvalidateRect(hwnd, NULL, FALSE); + break; + + case WM_REDO: + if (!syncData->redo()) MessageBeep(0); + // unfortunately, we don't know how much to invalidate... so we'll just invalidate it all. + InvalidateRect(hwnd, NULL, FALSE); + break; + + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return FALSE; +} + +static LRESULT CALLBACK trackViewWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + // Get the TrackView instance (if any) +#pragma warning(suppress:4312) /* remove a pointless warning */ + TrackView *trackView = (TrackView*)GetWindowLongPtr(hwnd, 0); + + switch(msg) + { + case WM_NCCREATE: + // Get TrackView from createstruct + trackView = (TrackView*)((CREATESTRUCT*)lParam)->lpCreateParams; + trackView->hwnd = hwnd; + + // Set the TrackView instance +#pragma warning(suppress:4244) /* remove a pointless warning */ + SetWindowLongPtr(hwnd, 0, (LONG_PTR)trackView); + + // call the proper window procedure + return trackView->windowProc(hwnd, msg, wParam, lParam); + break; + + case WM_NCDESTROY: + assert(NULL != trackView); + { + // call the window proc and store away the return code + LRESULT res = trackView->windowProc(hwnd, msg, wParam, lParam); + + // get rid of the TrackView instance + trackView = NULL; + SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL); + + // return the stored return code + return res; + } + break; + + default: + assert(NULL != trackView); + return trackView->windowProc(hwnd, msg, wParam, lParam); + } +} + +ATOM registerTrackViewWindowClass(HINSTANCE hInstance) +{ + WNDCLASSEX wc; + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = 0; + wc.lpfnWndProc = trackViewWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(TrackView*); + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor(NULL, IDC_IBEAM); + wc.hbrBackground = (HBRUSH)0; + wc.lpszMenuName = NULL; + wc.lpszClassName = trackViewWindowClassName; + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + return RegisterClassEx(&wc); +} + +HWND TrackView::create(HINSTANCE hInstance, HWND hwndParent) +{ + HWND hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + trackViewWindowClassName, _T(""), + WS_VSCROLL | WS_HSCROLL | WS_CHILD | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, // x, y + CW_USEDEFAULT, CW_USEDEFAULT, // width, height + hwndParent, NULL, hInstance, (void*)this + ); + return hwnd; +} + diff --git a/editor/trackview.h b/editor/trackview.h new file mode 100644 index 0000000..e43fbaf --- /dev/null +++ b/editor/trackview.h @@ -0,0 +1,143 @@ +#pragma once + +#include "synceditdata.h" + +#include +#include +#include + +// custom messages +#define WM_REDO (WM_USER + 1) + +class TrackView +{ +public: + TrackView(); + ~TrackView(); + + HWND create(HINSTANCE hInstance, HWND hwndParent); + HWND getWin(){ return hwnd; } + + void setSyncData(SyncEditData *syncData) { this->syncData = syncData; } + SyncEditData *getSyncData() { return syncData; } + + void setRows(int rows); + int getRows() const { return rows; } + void editBiasValue(float amount); + + void setEditRow(int newEditRow); + int getEditRow() { return editRow; } + +private: + // some nasty hackery to forward the window messages + friend static LRESULT CALLBACK trackViewWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + LRESULT windowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + // events + LRESULT onCreate(); + LRESULT onPaint(); + LRESULT onVScroll(UINT sbCode, int newPos); + LRESULT onHScroll(UINT sbCode, int newPos); + LRESULT onSize(int width, int height); + LRESULT onKeyDown(UINT keyCode, UINT flags); + LRESULT onChar(UINT keyCode, UINT flags); + + void editEnterValue(); + void editDelete(); + void editCopy(); + void editCut(); + void editPaste(); + + void paintTracks(HDC hdc, RECT rcTracks); + void paintTopMargin(HDC hdc, RECT rcTracks); + + void setupScrollBars(); + void setScrollPos(int newScrollPosX, int newScrollPosY); + void scrollWindow(int newScrollPosX, int newScrollPosY); + + void invalidateRange(int startTrack, int stopTrack, int startRow, int stopRow) + { + RECT rect; + rect.left = getScreenX(min(startTrack, stopTrack)); + rect.right = getScreenX(max(startTrack, stopTrack) + 1); + rect.top = getScreenY(min(startRow, stopRow)); + rect.bottom = getScreenY(max(startRow, stopRow) + 1); + InvalidateRect(hwnd, &rect, FALSE); + } + + void invalidatePos(int track, int row) + { + RECT rect; + rect.left = getScreenX(track); + rect.right = getScreenX(track + 1); + rect.top = getScreenY(row); + rect.bottom = getScreenY(row + 1); + InvalidateRect(hwnd, &rect, FALSE); + } + + void invalidateRow(int row) + { + RECT clientRect; + GetClientRect(hwnd, &clientRect); + + RECT rect; + rect.left = clientRect.left; + rect.right = clientRect.right; + rect.top = getScreenY(row); + rect.bottom = getScreenY(row + 1); + + InvalidateRect(hwnd, &rect, FALSE); + } + + void invalidateTrack(int track) + { + RECT clientRect; + GetClientRect(hwnd, &clientRect); + + RECT rect; + rect.left = getScreenX(track); + rect.right = getScreenX(track + 1); + rect.top = clientRect.top; + rect.bottom = clientRect.bottom; + + InvalidateRect(hwnd, &rect, FALSE); + } + + void setEditTrack(int newEditTrack); + + int getScreenY(int row); + int getScreenX(int track); + + int getTrackCount() + { + sync::Data *syncData = getSyncData(); + if (NULL == syncData) return 0; + return int(syncData->getTrackCount()); + }; + + int selectStartTrack, selectStopTrack; + int selectStartRow, selectStopRow; + + HBRUSH bgBaseBrush, bgDarkBrush; + HBRUSH selectBaseBrush, selectDarkBrush; + HPEN rowPen, rowSelectPen; + HBRUSH editBrush; + + /* cursor position */ + int editRow, editTrack; + + int scrollPosX, scrollPosY; + int windowWidth, windowHeight; + int windowRows, windowTracks; + + SyncEditData *syncData; + + std::basic_string editString; + + HWND hwnd; + + UINT clipboardFormat; + int rows; +}; + +ATOM registerTrackViewWindowClass(HINSTANCE hInstance); diff --git a/example.cpp b/example.cpp index 4cb2a66..10d9c1e 100644 --- a/example.cpp +++ b/example.cpp @@ -73,7 +73,7 @@ int main(int argc, char *argv[]) if (!syncDevice->update(row)) break; printf("%2.2f: %2.2f \n", row, track.getValue(row)); - Sleep(100); + Sleep(10); } return 0; diff --git a/example_bass.cpp b/example_bass.cpp index efb23c5..abe5406 100644 --- a/example_bass.cpp +++ b/example_bass.cpp @@ -1,11 +1,12 @@ #define WIN32_LEAN_AND_MEAN #include #include +#include #include #include #include #include "sync/device.h" - +#include "bass.h" class BassTimer : public sync::Timer { @@ -20,7 +21,7 @@ public: void play() { BASS_ChannelPlay(stream, false); } float getTime() { return BASS_ChannelBytes2Seconds(stream, BASS_ChannelGetPosition(stream)); } float getRow() { return getTime() * rowRate; } - void setRow(float pos) { BASS_ChannelSetPosition(stream, BASS_ChannelSeconds2Bytes(stream, row / rowRate)); } + void setRow(float row) { BASS_ChannelSetPosition(stream, BASS_ChannelSeconds2Bytes(stream, row / rowRate)); } bool isPlaying() { return (BASS_ChannelIsActive(stream) == BASS_ACTIVE_PLAYING); } private: HSTREAM stream; @@ -38,7 +39,7 @@ int main(int argc, char *argv[]) { // initialize directx IDirect3D9 *d3d = Direct3DCreate9(D3D_SDK_VERSION); - if (NULL == d3d) throw std::exception("update directx, fool."); + if (NULL == d3d) throw std::string("update directx, fool."); // create a window HWND hwnd = CreateWindowEx(0, "static", "BIG", WS_POPUP | WS_VISIBLE, 0, 0, width, height, 0, 0, GetModuleHandle(0), 0); @@ -47,20 +48,20 @@ int main(int argc, char *argv[]) IDirect3DDevice9 *device = NULL; static D3DPRESENT_PARAMETERS present_parameters = {width, height, D3DFMT_X8R8G8B8, 3, D3DMULTISAMPLE_NONE, 0, D3DSWAPEFFECT_DISCARD, 0, WINDOWED, 1, D3DFMT_D24S8, 0, WINDOWED ? 0 : D3DPRESENT_RATE_DEFAULT, 0}; if (D3D_OK != d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_parameters, &device)) - throw std::exception("could not create device. you computer SUCKS!"); + throw std::string("could not create device. you computer SUCKS!"); // init BASS int soundDevice = -1; - if (!BASS_Init(soundDevice, 44100, BASS_DEVICE_LATENCY, 0, 0)) throw FatalException("failed to init bass"); + if (!BASS_Init(soundDevice, 44100, BASS_DEVICE_LATENCY, 0, 0)) throw std::string("failed to init bass"); // load tune - stream = BASS_StreamCreateFile(false, "tune.mp3", 0, 0, BASS_MP3_SETPOS | ((0 == soundDevice) ? BASS_STREAM_DECODE : 0)); - if (NULL == stream) throw std::exception("failed to open tune"); + HSTREAM stream = BASS_StreamCreateFile(false, "tune.mp3", 0, 0, BASS_MP3_SETPOS | ((0 == soundDevice) ? BASS_STREAM_DECODE : 0)); + if (!stream) throw std::string("failed to open tune"); // setup timer and construct sync-device BassTimer timer(stream, 120.0f, 4); std::auto_ptr syncDevice = std::auto_ptr(sync::createDevice("sync", timer)); - if (NULL == syncDevice.get()) throw std::exception("something went wrong - failed to connect to host?"); + if (NULL == syncDevice.get()) throw std::string("something went wrong - failed to connect to host?"); // get tracks sync::Track &clearRTrack = syncDevice->getTrack("clear.r"); diff --git a/network.cpp b/network.cpp deleted file mode 100644 index 8fb7362..0000000 --- a/network.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "network.h" -#include - -bool initNetwork() -{ - WSADATA wsaData; - if (0 != WSAStartup(MAKEWORD( 2, 0 ), &wsaData)) return false; - if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0) return false; - return true; -} - -void closeNetwork() -{ - WSACleanup(); -} - -static const char *clientGreeting = "hello, synctracker!"; -static const char *serverGreeting = "hello, demo!"; - -SOCKET clientConnect(SOCKET serverSocket) -{ - SOCKET clientSocket = accept(serverSocket, NULL, NULL); - if (INVALID_SOCKET == clientSocket) return INVALID_SOCKET; - printf("%x\n", clientSocket); - - const char *expectedGreeting = clientGreeting; - char recievedGreeting[128]; - - recv(clientSocket, recievedGreeting, int(strlen(expectedGreeting)), 0); - - if (strncmp(expectedGreeting, recievedGreeting, strlen(expectedGreeting)) != 0) - { - closesocket(clientSocket); - return INVALID_SOCKET; - } - - const char *greeting = serverGreeting; - send(clientSocket, greeting, int(strlen(greeting)), 0); - - return clientSocket; -} - -SOCKET serverConnect(struct sockaddr_in *addr) -{ - SOCKET serverSocket = socket( AF_INET, SOCK_STREAM, 0 ); - connect( serverSocket,(struct sockaddr *)addr, sizeof(struct sockaddr_in)); - - const char *greeting = clientGreeting; - send(serverSocket, greeting, int(strlen(greeting)), 0); - - const char *expectedGreeting = serverGreeting; - char recievedGreeting[128]; - recv(serverSocket, recievedGreeting, int(sizeof(recievedGreeting)), 0); - if (strncmp(expectedGreeting, recievedGreeting, strlen(expectedGreeting)) != 0) - { - closesocket(serverSocket); - return INVALID_SOCKET; - } - - return serverSocket; -} - -bool pollRead(SOCKET socket) -{ - struct timeval timeout = { 0, 0 }; - fd_set fds; - - FD_ZERO(&fds); - FD_SET(socket, &fds); - - // look for new commands - return select(0, &fds, NULL, NULL, &timeout) > 0; -} - diff --git a/network.h b/network.h deleted file mode 100644 index 99dd3da..0000000 --- a/network.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef NETWORK_H -#define NETWORK_H - -#include - -bool initNetwork(); -void closeNetwork(); - -SOCKET clientConnect(SOCKET serverSocket); -SOCKET serverConnect(struct sockaddr_in *addr); - -bool pollRead(SOCKET socket); - -enum RemoteCommand { - // server -> client - SET_KEY = 0, - DELETE_KEY = 1, - - // client -> server - GET_TRACK = 2, - - // client -> server, server -> client - SET_ROW = 3, - - // server -> client - PAUSE = 4, -}; - -#endif /* NETWORK_H */ diff --git a/stdafx.h b/stdafx.h index 5037286..e18f3a9 100644 --- a/stdafx.h +++ b/stdafx.h @@ -5,6 +5,7 @@ #pragma once +#include #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include diff --git a/sync/device_client.cpp b/sync/device_client.cpp index 561dcb4..2846908 100644 --- a/sync/device_client.cpp +++ b/sync/device_client.cpp @@ -1,6 +1,6 @@ #include "device.h" #include "data.h" -#include "../network.h" +#include "network.h" using namespace sync; diff --git a/sync/network.cpp b/sync/network.cpp new file mode 100644 index 0000000..469034b --- /dev/null +++ b/sync/network.cpp @@ -0,0 +1,75 @@ +#include "../stdafx.h" +#include "network.h" +#include + +bool initNetwork() +{ + WSADATA wsaData; + if (0 != WSAStartup(MAKEWORD( 2, 0 ), &wsaData)) return false; + if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0) return false; + return true; +} + +void closeNetwork() +{ + WSACleanup(); +} + +static const char *clientGreeting = "hello, synctracker!"; +static const char *serverGreeting = "hello, demo!"; + +SOCKET clientConnect(SOCKET serverSocket) +{ + SOCKET clientSocket = accept(serverSocket, NULL, NULL); + if (INVALID_SOCKET == clientSocket) return INVALID_SOCKET; + printf("%x\n", clientSocket); + + const char *expectedGreeting = clientGreeting; + char recievedGreeting[128]; + + recv(clientSocket, recievedGreeting, int(strlen(expectedGreeting)), 0); + + if (strncmp(expectedGreeting, recievedGreeting, strlen(expectedGreeting)) != 0) + { + closesocket(clientSocket); + return INVALID_SOCKET; + } + + const char *greeting = serverGreeting; + send(clientSocket, greeting, int(strlen(greeting)), 0); + + return clientSocket; +} + +SOCKET serverConnect(struct sockaddr_in *addr) +{ + SOCKET serverSocket = socket( AF_INET, SOCK_STREAM, 0 ); + connect( serverSocket,(struct sockaddr *)addr, sizeof(struct sockaddr_in)); + + const char *greeting = clientGreeting; + send(serverSocket, greeting, int(strlen(greeting)), 0); + + const char *expectedGreeting = serverGreeting; + char recievedGreeting[128]; + recv(serverSocket, recievedGreeting, int(sizeof(recievedGreeting)), 0); + if (strncmp(expectedGreeting, recievedGreeting, strlen(expectedGreeting)) != 0) + { + closesocket(serverSocket); + return INVALID_SOCKET; + } + + return serverSocket; +} + +bool pollRead(SOCKET socket) +{ + struct timeval timeout = { 0, 0 }; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(socket, &fds); + + // look for new commands + return select(0, &fds, NULL, NULL, &timeout) > 0; +} + diff --git a/sync/network.h b/sync/network.h new file mode 100644 index 0000000..1f4e7a6 --- /dev/null +++ b/sync/network.h @@ -0,0 +1,31 @@ +#ifndef NETWORK_H +#define NETWORK_H + +#include +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#include + +bool initNetwork(); +void closeNetwork(); + +SOCKET clientConnect(SOCKET serverSocket); +SOCKET serverConnect(struct sockaddr_in *addr); + +bool pollRead(SOCKET socket); + +enum RemoteCommand { + // server -> client + SET_KEY = 0, + DELETE_KEY = 1, + + // client -> server + GET_TRACK = 2, + + // client -> server, server -> client + SET_ROW = 3, + + // server -> client + PAUSE = 4, +}; + +#endif /* NETWORK_H */ diff --git a/synceditdata.h b/synceditdata.h deleted file mode 100644 index d87774f..0000000 --- a/synceditdata.h +++ /dev/null @@ -1,253 +0,0 @@ -#pragma once - -#include "sync/data.h" -#include -#include - -#include "network.h" - -class SyncEditData : public sync::Data -{ -public: - SyncEditData() : sync::Data(), clientPaused(true) {} - - void sendSetKeyCommand(int track, int row, const sync::Track::KeyFrame &key) - { - if (INVALID_SOCKET == clientSocket) return; - if (clientRemap.count(track) == 0) return; - track = int(clientRemap[track]); - - unsigned char cmd = SET_KEY; - send(clientSocket, (char*)&cmd, 1, 0); - send(clientSocket, (char*)&track, sizeof(int), 0); - send(clientSocket, (char*)&row, sizeof(int), 0); - send(clientSocket, (char*)&key.value, sizeof(float), 0); -// send(clientSocket, (char*)&key.lerp, 1, 0); - } - - void sendDeleteKeyCommand(int track, int row) - { - if (INVALID_SOCKET == clientSocket) return; - - unsigned char cmd = DELETE_KEY; - send(clientSocket, (char*)&cmd, 1, 0); - send(clientSocket, (char*)&track, sizeof(int), 0); - send(clientSocket, (char*)&row, sizeof(int), 0); - } - - void sendSetRowCommand(int row) - { - if (INVALID_SOCKET == clientSocket) return; - - unsigned char cmd = SET_ROW; - send(clientSocket, (char*)&cmd, 1, 0); - send(clientSocket, (char*)&row, sizeof(int), 0); - } - - void sendPauseCommand(bool pause) - { - unsigned char cmd = PAUSE; - send(clientSocket, (char*)&cmd, 1, 0); - unsigned char flag = pause; - send(clientSocket, (char*)&flag, 1, 0); - clientPaused = pause; - } - - - class Command - { - public: - virtual ~Command() {} - virtual void exec(SyncEditData *data) = 0; - virtual void undo(SyncEditData *data) = 0; - }; - - class InsertCommand : public Command - { - public: - InsertCommand(int track, int row, const sync::Track::KeyFrame &key) : track(track), row(row), key(key) {} - ~InsertCommand() {} - - virtual void exec(SyncEditData *data) - { - sync::Track &t = data->getTrack(this->track); - assert(!t.isKeyFrame(row)); - t.setKeyFrame(row, key); - - data->sendSetKeyCommand(track, row, key); // update clients - } - - virtual void undo(SyncEditData *data) - { - sync::Track &t = data->getTrack(this->track); - assert(t.isKeyFrame(row)); - t.deleteKeyFrame(row); - - data->sendDeleteKeyCommand(track, row); // update clients - } - - private: - int track, row; - sync::Track::KeyFrame key; - }; - - class DeleteCommand : public Command - { - public: - DeleteCommand(int track, int row) : track(track), row(row) {} - ~DeleteCommand() {} - - virtual void exec(SyncEditData *data) - { - sync::Track &t = data->getTrack(this->track); - assert(t.isKeyFrame(row)); - oldKey = *t.getKeyFrame(row); - t.deleteKeyFrame(row); - - data->sendDeleteKeyCommand(track, row); // update clients - } - - virtual void undo(SyncEditData *data) - { - sync::Track &t = data->getTrack(this->track); - assert(!t.isKeyFrame(row)); - t.setKeyFrame(row, oldKey); - - data->sendSetKeyCommand(track, row, oldKey); // update clients - } - - private: - int track, row; - sync::Track::KeyFrame oldKey; - }; - - - class EditCommand : public Command - { - public: - EditCommand(int track, int row, const sync::Track::KeyFrame &key) : track(track), row(row), key(key) {} - ~EditCommand() {} - - virtual void exec(SyncEditData *data) - { - sync::Track &t = data->getTrack(this->track); - - // store old key - assert(t.isKeyFrame(row)); - oldKey = *t.getKeyFrame(row); - - // update - t.setKeyFrame(row, key); - - data->sendSetKeyCommand(track, row, key); // update clients - } - - virtual void undo(SyncEditData *data) - { - sync::Track &t = data->getTrack(this->track); - - assert(t.isKeyFrame(row)); - t.setKeyFrame(row, oldKey); - - data->sendSetKeyCommand(track, row, oldKey); // update clients - } - - private: - int track, row; - sync::Track::KeyFrame oldKey, key; - }; - - class MultiCommand : public Command - { - public: - ~MultiCommand() - { - std::list::iterator it; - for (it = commands.begin(); it != commands.end(); ++it) - { - delete *it; - } - commands.clear(); - } - - void addCommand(Command *cmd) - { - commands.push_back(cmd); - } - - size_t getSize() const { return commands.size(); } - - virtual void exec(SyncEditData *data) - { - std::list::iterator it; - for (it = commands.begin(); it != commands.end(); ++it) (*it)->exec(data); - } - - virtual void undo(SyncEditData *data) - { - std::list::iterator it; - for (it = commands.begin(); it != commands.end(); ++it) (*it)->undo(data); - } - - private: - std::list commands; - }; - - void exec(Command *cmd) - { - undoStack.push(cmd); - cmd->exec(this); - clearRedoStack(); - } - - bool undo() - { - if (undoStack.size() == 0) return false; - - Command *cmd = undoStack.top(); - undoStack.pop(); - - redoStack.push(cmd); - cmd->undo(this); - return true; - } - - bool redo() - { - if (redoStack.size() == 0) return false; - - Command *cmd = redoStack.top(); - redoStack.pop(); - - undoStack.push(cmd); - cmd->exec(this); - return true; - } - - void clearRedoStack() - { - while (!redoStack.empty()) - { - Command *cmd = redoStack.top(); - redoStack.pop(); - delete cmd; - } - } - - Command *getSetKeyFrameCommand(int track, int row, const sync::Track::KeyFrame &key) - { - sync::Track &t = getTrack(track); - SyncEditData::Command *cmd; - if (t.isKeyFrame(row)) cmd = new EditCommand(track, row, key); - else cmd = new InsertCommand(track, row, key); - return cmd; - } - - SOCKET clientSocket; -// private: - std::map clientRemap; - bool clientPaused; - - std::stack undoStack; - std::stack redoStack; -}; diff --git a/synctracker2.cpp b/synctracker2.cpp deleted file mode 100644 index f468dff..0000000 --- a/synctracker2.cpp +++ /dev/null @@ -1,490 +0,0 @@ -// synctracker2.cpp : Defines the entry point for the console application. -// - -#include "stdafx.h" -#include -#include - -#include "trackview.h" -#include -const TCHAR *mainWindowClassName = _T("MainWindow"); - -TrackView *trackView; -HWND trackViewWin; -HWND statusBarWin; - -#define WM_SETROWS (WM_USER+1) -#define WM_BIASSELECTION (WM_USER+2) - -#include "network.h" - -static LRESULT CALLBACK setRowsDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { -/* case WM_CHAR: - printf("char: %d %d\n", wParam, lParam); - break; */ - - case WM_INITDIALOG: - { - int *rows = (int*)lParam; - assert(NULL != rows); - - /* create row-string */ - TCHAR temp[256]; - _sntprintf_s(temp, 256, _T("%d"), *rows); - - /* set initial row count */ - SetDlgItemText(hDlg, IDC_SETROWS_EDIT, temp); - return TRUE; - } - break; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK) - { - /* get value */ - TCHAR temp[256]; - GetDlgItemText(hDlg, IDC_SETROWS_EDIT, temp, 256); - int result = _tstoi(temp); - - /* update editor */ - SendMessage(GetParent(hDlg), WM_SETROWS, 0, result); - - /* end dialog */ - EndDialog(hDlg, LOWORD(wParam)); - return TRUE; - } - else if(LOWORD(wParam)== IDCANCEL) - { - EndDialog( hDlg, LOWORD(wParam)); - return TRUE; - } - break; - - case WM_CLOSE: - EndDialog(hDlg, LOWORD(wParam)); - return TRUE; - } - - return FALSE; -} - -static LRESULT CALLBACK biasSelectionDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - case WM_INITDIALOG: - { - int *intialBias = (int*)lParam; - assert(NULL != intialBias); - - /* create bias-string */ - TCHAR temp[256]; - _sntprintf_s(temp, 256, _T("%d"), *intialBias); - - /* set initial bias */ - SetDlgItemText(hDlg, IDC_SETROWS_EDIT, temp); - } - break; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK) - { - /* get value */ - TCHAR temp[256]; - GetDlgItemText(hDlg, IDC_BIASSELECTION_EDIT, temp, 256); - int bias = _tstoi(temp); - - /* update editor */ - SendMessage(GetParent(hDlg), WM_BIASSELECTION, 0, LPARAM(bias)); - - /* end dialog */ - EndDialog(hDlg, LOWORD(wParam)); - return TRUE; - } - else if(LOWORD(wParam)== IDCANCEL) - { - EndDialog( hDlg, LOWORD(wParam)); - } - break; - - case WM_CLOSE: - EndDialog(hDlg, LOWORD(wParam)); - return TRUE; - } - - return FALSE; -} - -static LRESULT CALLBACK mainWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch(msg) - { - case WM_CREATE: - { - HINSTANCE hInstance = GetModuleHandle(NULL); - trackViewWin = trackView->create(hInstance, hwnd); - InitCommonControls(); - statusBarWin = CreateWindowEx( - 0, // no extended styles - STATUSCLASSNAME, // status bar - (LPCTSTR)NULL, // no text - SBARS_SIZEGRIP | WS_VISIBLE | WS_CHILD, // styles - 0, 0, 0, 0, // x, y, cx, cy - hwnd, // parent window - NULL, // menu - hInstance, // instance - NULL // window data - ); - - int statwidths[] = { 100, -1 }; - SendMessage(statusBarWin, SB_SETPARTS, sizeof(statwidths) / sizeof(int), (LPARAM)statwidths); - SendMessage(statusBarWin, SB_SETTEXT, 0, (LPARAM)_T("Hi there :)")); - SendMessage(statusBarWin, SB_SETTEXT, 1, (LPARAM)_T("Hi there :)")); - } - break; - - case WM_SIZE: - { - int width = LOWORD(lParam); - int height = HIWORD(lParam); - - RECT statusBarRect; - GetClientRect(statusBarWin, &statusBarRect); - int statusBarHeight = statusBarRect.bottom - statusBarRect.top; - - MoveWindow(trackViewWin, 0, 0, width, height - statusBarHeight, TRUE); - MoveWindow(statusBarWin, 0, height - statusBarHeight, width, statusBarHeight, TRUE); - } - break; - - case WM_SETFOCUS: - SetFocus(trackViewWin); // needed to forward keyboard input - break; - - case WM_SETROWS: - printf("rows: %d\n", int(lParam)); - trackView->setRows(int(lParam)); - break; - - case WM_BIASSELECTION: - trackView->editBiasValue(float(lParam)); - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case ID_FILE_SAVE: - case ID_FILE_SAVE_AS: - case ID_FILE_OPEN: - MessageBox(trackViewWin, "Not implemented", NULL, MB_OK | MB_ICONERROR); - break; - - case ID_FILE_EXIT: PostQuitMessage(0); break; - case ID_EDIT_UNDO: SendMessage(trackViewWin, WM_UNDO, 0, 0); break; - case ID_EDIT_REDO: SendMessage(trackViewWin, WM_REDO, 0, 0); break; - case ID_EDIT_COPY: SendMessage(trackViewWin, WM_COPY, 0, 0); break; - case ID_EDIT_CUT: SendMessage(trackViewWin, WM_CUT, 0, 0); break; - case ID_EDIT_PASTE: SendMessage(trackViewWin, WM_PASTE, 0, 0); break; - - case ID_EDIT_SETROWS: - { - HINSTANCE hInstance = GetModuleHandle(NULL); - int rows = trackView->getRows(); - INT_PTR result = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_SETROWS), hwnd, (DLGPROC)setRowsDialogProc, (LPARAM)&rows); - if (FAILED(result)) MessageBox(NULL, _T("unable to create dialog box"), NULL, MB_OK); - } - break; - - case ID_EDIT_BIAS: - { - HINSTANCE hInstance = GetModuleHandle(NULL); - int initialBias = 0; - INT_PTR result = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_BIASSELECTION), hwnd, (DLGPROC)biasSelectionDialogProc, (LPARAM)&initialBias); - if (FAILED(result)) MessageBox(NULL, _T("unable to create dialog box"), NULL, MB_OK); - } - break; - } - break; - - default: - return DefWindowProc(hwnd, msg, wParam, lParam); - } - return 0; -} - -static ATOM registerMainWindowClass(HINSTANCE hInstance) -{ - WNDCLASSEX wc; - - wc.cbSize = sizeof(WNDCLASSEX); - wc.style = 0; - wc.lpfnWndProc = mainWindowProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = hInstance; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)0; - wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU); - wc.lpszClassName = mainWindowClassName; - wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - - return RegisterClassEx(&wc); -} - -int _tmain(int argc, _TCHAR* argv[]) -{ -#ifdef _DEBUG - _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); - _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); -/* _CrtSetBreakAlloc(68); */ -#endif - - HINSTANCE hInstance = GetModuleHandle(NULL); - -#if 1 - if (false == initNetwork()) - { - fputs("Failed to init WinSock", stderr); - exit(1); - } - - SOCKET serverSocket = socket( AF_INET, SOCK_STREAM, 0 ); - - struct sockaddr_in sin; - memset( &sin, 0, sizeof sin ); - - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - sin.sin_port = htons( 1338 ); - - puts("binding..."); - if (SOCKET_ERROR == bind( serverSocket, (struct sockaddr *)&sin, sizeof(sin))) - { - fputs("Coult not start server", stderr); - exit(1); - } - - puts("listening..."); - while ( listen( serverSocket, SOMAXCONN ) == SOCKET_ERROR ); - -/* ULONG nonBlock = 1; - if (ioctlsocket(serverSocket, FIONBIO, &nonBlock) == SOCKET_ERROR) - { - printf("ioctlsocket() failed\n"); - return 0; - } */ -#endif - - SyncEditData syncData; - syncData.clientSocket = INVALID_SOCKET; -#if 0 - - SyncTrack &camXTrack = syncData.getTrack(_T("cam.x")); - SyncTrack &camXTrack2 = syncData.getTrack(_T("cam.x")); - camXTrack.setKeyFrame(1, 2.0f); - camXTrack.setKeyFrame(4, 3.0f); - printf("%p %p\n", &camXTrack, &camXTrack2); - - SyncTrack &camYTrack = syncData.getTrack(_T("cam.y")); - SyncTrack &camZTrack = syncData.getTrack(_T("cam.z")); - -/* for (int i = 0; i < 16; ++i) - { - TCHAR temp[256]; - _sntprintf_s(temp, 256, _T("gen %02d"), i); - SyncTrack &temp2 = syncData.getTrack(temp); - } */ - - camXTrack.setKeyFrame(1, 2.0f); - camXTrack.setKeyFrame(4, 3.0f); - - camYTrack.setKeyFrame(0, 100.0f); - camYTrack.setKeyFrame(8, 999.0f); - - camYTrack.setKeyFrame(16, SyncTrack::KeyFrame(float(1E-5))); - - for (int i = 0; i < 5 * 2; ++i) - { - float time = float(i) / 2; - printf("%f %d - %f\n", time, camXTrack.isKeyFrame(i), camXTrack.getValue(time)); - } -#endif - - ATOM mainClass = registerMainWindowClass(hInstance); - ATOM trackViewClass = registerTrackViewWindowClass(hInstance); - if (!mainClass || !trackViewClass) - { - MessageBox(NULL, _T("Window Registration Failed!"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK); - return 0; - } - - trackView = new TrackView(); - trackView->setSyncData(&syncData); - - HWND hwnd = CreateWindowEx( - 0, - mainWindowClassName, - _T("SyncTracker 3000"), - WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, - CW_USEDEFAULT, CW_USEDEFAULT, // x, y - CW_USEDEFAULT, CW_USEDEFAULT, // width, height - NULL, NULL, hInstance, NULL - ); - printf("main window: %p\n", hwnd); - - if (NULL == hwnd) - { - MessageBox(NULL, _T("Window Creation Failed!"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK); - return 0; - } - - HACCEL accel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); - printf("accel: %p\n", accel); - - ShowWindow(hwnd, TRUE); - UpdateWindow(hwnd); - -#if 1 - - printf("server socket %x\n", serverSocket); - - bool done = false; - SOCKET clientSocket = INVALID_SOCKET; - MSG msg; - while (!done) - { -#if 1 - if (INVALID_SOCKET == clientSocket) - { - fd_set fds; - FD_ZERO(&fds); - FD_SET(serverSocket, &fds); - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - // look for new clients - if (select(0, &fds, NULL, NULL, &timeout) > 0) - { - puts("accepting..."); - clientSocket = clientConnect(serverSocket); - if (INVALID_SOCKET != clientSocket) - { - puts("connected."); - syncData.clientSocket = clientSocket; - syncData.clientRemap.clear(); - syncData.sendPauseCommand(true); - syncData.sendSetRowCommand(trackView->getEditRow()); - } - } - } - - if (INVALID_SOCKET != clientSocket) - { - // look for new commands - while (pollRead(clientSocket)) - { - unsigned char cmd = 0; - int ret = recv(clientSocket, (char*)&cmd, 1, 0); - if (1 > ret) - { - closesocket(clientSocket); - clientSocket = INVALID_SOCKET; - syncData.clientSocket = INVALID_SOCKET; - syncData.clientRemap.clear(); - InvalidateRect(trackViewWin, NULL, FALSE); - break; - } - else - { - switch (cmd) - { - case GET_TRACK: - { - size_t clientIndex = 0; - int ret = recv(clientSocket, (char*)&clientIndex, sizeof(int), 0); - printf("client index: %d\n", clientIndex); - - // get len - int str_len = 0; - ret = recv(clientSocket, (char*)&str_len, sizeof(int), 0); - - // int clientAddr = 0; - // int ret = recv(clientSocket, (char*)&clientAddr, sizeof(int), 0); - - // get string - std::string trackName; - trackName.resize(str_len); - recv(clientSocket, &trackName[0], str_len, 0); - - // find track - size_t serverIndex = syncData.getTrackIndex(trackName.c_str()); - printf("name: \"%s\"\n", trackName.c_str()); - - // setup remap - syncData.clientRemap[serverIndex] = clientIndex; - - const sync::Track &track = *syncData.actualTracks[serverIndex]; - - sync::Track::KeyFrameContainer::const_iterator it; - for (it = track.keyFrames.begin(); it != track.keyFrames.end(); ++it) - { - int row = int(it->first); - const sync::Track::KeyFrame &key = it->second; - syncData.sendSetKeyCommand(int(serverIndex), row, key); - } - - InvalidateRect(trackViewWin, NULL, FALSE); - } - break; - - case SET_ROW: - { - int newRow = 0; - int ret = recv(clientSocket, (char*)&newRow, sizeof(int), 0); - printf("new row: %d\n", newRow); - trackView->setEditRow(newRow); - } - break; - } - } - } - } -#endif - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - if (!TranslateAccelerator(hwnd, accel, &msg)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - if (WM_QUIT == msg.message) done = true; - } - } - Sleep(1); - } - - closesocket(clientSocket); - closesocket(serverSocket); - closeNetwork(); - -#else - // Step 3: The Message Loop - while(GetMessage(&msg, NULL, 0, 0) > 0) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } -#endif - - delete trackView; - trackView = NULL; - - UnregisterClass(mainWindowClassName, hInstance); - return int(msg.wParam); -} \ No newline at end of file diff --git a/synctracker2.vcproj b/synctracker2.vcproj index 78a178a..c5c3ed0 100644 --- a/synctracker2.vcproj +++ b/synctracker2.vcproj @@ -184,7 +184,7 @@ > @@ -210,7 +210,15 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + + + - - diff --git a/trackview.cpp b/trackview.cpp deleted file mode 100644 index 393fc77..0000000 --- a/trackview.cpp +++ /dev/null @@ -1,992 +0,0 @@ -#include "stdafx.h" - -#include "trackview.h" -#include - -static const TCHAR *trackViewWindowClassName = _T("TrackView"); - -static const int topMarginHeight = 20; -static const int leftMarginWidth = 60; - -static const int fontHeight = 16; -static const int fontWidth = 6; - -static const int trackWidth = fontWidth * 16; -static DWORD darken(DWORD col, float amt) -{ - return RGB(GetRValue(col) * amt, GetGValue(col) * amt, GetBValue(col) * amt); -} - -TrackView::TrackView() -{ - scrollPosX = 0; - scrollPosY = 0; - windowWidth = -1; - windowHeight = -1; - - editRow = 0; - editTrack = 0; - rows = 0x80; - - selectStartTrack = selectStopTrack = 0; - selectStartRow = selectStopRow = 0; - - this->hwnd = NULL; - - bgBaseBrush = GetSysColorBrush(COLOR_WINDOW); - bgDarkBrush = CreateSolidBrush(darken(GetSysColor(COLOR_WINDOW), 0.9f)); - - selectBaseBrush = GetSysColorBrush(COLOR_HIGHLIGHT); - selectDarkBrush = CreateSolidBrush(darken(GetSysColor(COLOR_HIGHLIGHT), 0.9f)); - - rowPen = CreatePen(PS_SOLID, 1, darken(GetSysColor(COLOR_WINDOW), 0.7f)); - rowSelectPen = CreatePen(PS_SOLID, 1, darken(GetSysColor(COLOR_HIGHLIGHT), 0.7f)); - - editBrush = CreateSolidBrush(RGB(255, 255, 0)); // yellow - - clipboardFormat = RegisterClipboardFormat(_T("syncdata")); - assert(0 != clipboardFormat); -} - -TrackView::~TrackView() -{ - DeleteObject(bgBaseBrush); - DeleteObject(bgDarkBrush); - DeleteObject(selectBaseBrush); - DeleteObject(selectDarkBrush); - DeleteObject(editBrush); - DeleteObject(rowPen); - DeleteObject(rowSelectPen); -} - -int TrackView::getScreenY(int row) -{ - return topMarginHeight + (row * fontHeight) - scrollPosY; -} - -int TrackView::getScreenX(int track) -{ - return leftMarginWidth + (track * trackWidth) - scrollPosX; -} - -LRESULT TrackView::onCreate() -{ - setupScrollBars(); - return FALSE; -} - -LRESULT TrackView::onPaint() -{ - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - - SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); -// SelectObject(hdc, GetStockObject(SYSTEM_FONT)); - paintTracks(hdc, ps.rcPaint); - - EndPaint(hwnd, &ps); - - return FALSE; -} - -void TrackView::paintTopMargin(HDC hdc, RECT rcTracks) -{ - RECT fillRect; - RECT topLeftMargin; - topLeftMargin.top = 0; - topLeftMargin.bottom = topMarginHeight; - topLeftMargin.left = 0; - topLeftMargin.right = leftMarginWidth; - fillRect = topLeftMargin; - DrawEdge(hdc, &fillRect, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_ADJUST | BF_BOTTOM); - FillRect(hdc, &fillRect, GetSysColorBrush(COLOR_3DFACE)); - - int firstTrack = min(max(scrollPosX / trackWidth, 0), getTrackCount() - 1); - int lastTrack = min(max(firstTrack + windowTracks + 1, 0), getTrackCount() - 1); - - sync::Data *syncData = getSyncData(); - if (NULL == syncData) return; - - SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); - - sync::Data::TrackContainer::iterator trackIter = syncData->tracks.begin(); - for (int track = 0; track <= lastTrack; ++track, ++trackIter) - { - ASSERT(trackIter != syncData->tracks.end()); - if (track < firstTrack) continue; - - RECT topMargin; - - topMargin.top = 0; - topMargin.bottom = topMarginHeight; - - topMargin.left = getScreenX(track); - topMargin.right = topMargin.left + trackWidth; - - if (!RectVisible(hdc, &topMargin)) continue; - - RECT fillRect = topMargin; - - HBRUSH bgBrush = GetSysColorBrush(COLOR_3DFACE); - if (track == editTrack) bgBrush = editBrush; - - DrawEdge(hdc, &fillRect, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_ADJUST | BF_LEFT | BF_RIGHT | BF_BOTTOM); - FillRect(hdc, &fillRect, bgBrush); - - const std::basic_string &trackName = trackIter->first; - - if (this->syncData->clientRemap.count(track) == 0) SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); - else SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); - TextOut(hdc, - fillRect.left, 0, - trackName.data(), int(trackName.length()) - ); - } - - RECT topRightMargin; - topRightMargin.top = 0; - topRightMargin.bottom = topMarginHeight; - topRightMargin.left = getScreenX(getTrackCount()); - topRightMargin.right = rcTracks.right; - fillRect = topRightMargin; - DrawEdge(hdc, &fillRect, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_ADJUST | BF_BOTTOM); - FillRect(hdc, &fillRect, GetSysColorBrush(COLOR_3DFACE)); - - // make sure that the top margin isn't overdrawn by the track-data - ExcludeClipRect(hdc, 0, 0, rcTracks.right, topMarginHeight); -} - -void TrackView::paintTracks(HDC hdc, RECT rcTracks) -{ - TCHAR temp[256]; - - int firstTrack = min(max(scrollPosX / trackWidth, 0), getTrackCount() - 1); - int lastTrack = min(max(firstTrack + windowTracks + 1, 0), getTrackCount() - 1); - - int firstRow = editRow - windowRows / 2 - 1; - int lastRow = editRow + windowRows / 2 + 1; - /* clamp first & last row */ - firstRow = min(max(firstRow, 0), rows - 1); - lastRow = min(max(lastRow, 0), rows - 1); - - SetBkMode(hdc, TRANSPARENT); - paintTopMargin(hdc, rcTracks); - - for (int row = firstRow; row <= lastRow; ++row) - { - RECT leftMargin; - leftMargin.left = 0; - leftMargin.right = leftMarginWidth; - leftMargin.top = getScreenY(row); - leftMargin.bottom = leftMargin.top + fontHeight; - - if (!RectVisible(hdc, &leftMargin)) continue; - - HBRUSH fillBrush; - if (row == editRow) fillBrush = editBrush; - else fillBrush = GetSysColorBrush(COLOR_3DFACE); - FillRect(hdc, &leftMargin, fillBrush); - - DrawEdge(hdc, &leftMargin, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_RIGHT | BF_BOTTOM | BF_TOP); - if ((row % 8) == 0) SetTextColor(hdc, RGB(0, 0, 0)); - else if ((row % 4) == 0) SetTextColor(hdc, RGB(64, 64, 64)); - else SetTextColor(hdc, RGB(128, 128, 128)); - -/* if ((row % 4) == 0) SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); - else SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); */ - - _sntprintf_s(temp, 256, _T("%0*Xh"), 5, row); - TextOut(hdc, - leftMargin.left, leftMargin.top, - temp, int(_tcslen(temp)) - ); - } - - SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); - - sync::Data *syncData = getSyncData(); - if (NULL == syncData) return; - - int selectLeft = min(selectStartTrack, selectStopTrack); - int selectRight = max(selectStartTrack, selectStopTrack); - int selectTop = min(selectStartRow, selectStopRow); - int selectBottom = max(selectStartRow, selectStopRow); - - sync::Data::TrackContainer::iterator trackIter = syncData->tracks.begin(); - for (int track = 0; track <= lastTrack; ++track, ++trackIter) - { - ASSERT(trackIter != syncData->tracks.end()); - if (track < firstTrack) continue; - - for (int row = firstRow; row <= lastRow; ++row) - { - RECT patternDataRect; - patternDataRect.left = getScreenX(track); - patternDataRect.right = patternDataRect.left + trackWidth; - patternDataRect.top = getScreenY(row); - patternDataRect.bottom = patternDataRect.top + fontHeight; - - if (!RectVisible(hdc, &patternDataRect)) continue; - - bool selected = (track >= selectLeft && track <= selectRight) && (row >= selectTop && row <= selectBottom); - - HBRUSH baseBrush = bgBaseBrush; - HBRUSH darkBrush = bgDarkBrush; - if (selected) - { - baseBrush = selectBaseBrush; - darkBrush = selectDarkBrush; - } - - HBRUSH bgBrush = baseBrush; - if (row % 8 == 0) bgBrush = darkBrush; - - RECT fillRect = patternDataRect; -// if (row == editRow && track == editTrack) DrawEdge(hdc, &fillRect, BDR_RAISEDINNER | BDR_SUNKENOUTER, BF_ADJUST | BF_TOP | BF_BOTTOM | BF_LEFT | BF_RIGHT); - FillRect( hdc, &fillRect, bgBrush); - if (row % 8 == 0) - { - MoveToEx(hdc, patternDataRect.left, patternDataRect.top, (LPPOINT) NULL); - if (selected) SelectObject(hdc, rowSelectPen); - else SelectObject(hdc, rowPen); - LineTo(hdc, patternDataRect.right, patternDataRect.top); - } - - bool drawEditString = false; - if (row == editRow && track == editTrack) - { - FrameRect(hdc, &fillRect, (HBRUSH)GetStockObject(BLACK_BRUSH)); -// DrawFocusRect(hdc, &fillRect); -// Rectangle(hdc, fillRect.left, fillRect.top, fillRect.right, fillRect.bottom); - if (editString.size() > 0) drawEditString = true; - } - -// InvertRect(hdc, &fillRect); - - const sync::Track &track = *syncData->actualTracks[trackIter->second]; - bool key = track.isKeyFrame(row); - - /* format the text */ - if (drawEditString) _sntprintf_s(temp, 256, editString.c_str()); - else if (!key) _sntprintf_s(temp, 256, _T(" ---")); - else - { - float val = track.getKeyFrame(row)->value; - _sntprintf_s(temp, 256, _T("% .2f"), val); - } - - COLORREF oldCol; - if (selected) oldCol = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - TextOut(hdc, - patternDataRect.left, patternDataRect.top, - temp, int(_tcslen(temp)) - ); - if (selected) SetTextColor(hdc, oldCol); - } - } - - /* right margin */ - { - RECT rightMargin; - rightMargin.top = getScreenY(0); - rightMargin.bottom = getScreenY(rows); - rightMargin.left = getScreenX(getTrackCount()); - rightMargin.right = rcTracks.right; - FillRect( hdc, &rightMargin, GetSysColorBrush(COLOR_APPWORKSPACE)); - } - - { - RECT bottomPadding; - bottomPadding.top = getScreenY(rows); - bottomPadding.bottom = rcTracks.bottom; - bottomPadding.left = rcTracks.left; - bottomPadding.right = rcTracks.right; - FillRect(hdc, &bottomPadding, GetSysColorBrush(COLOR_APPWORKSPACE)); - } - - { - RECT topPadding; - topPadding.top = max(rcTracks.top, topMarginHeight); - topPadding.bottom = getScreenY(0); - topPadding.left = rcTracks.left; - topPadding.right = rcTracks.right; - FillRect(hdc, &topPadding, GetSysColorBrush(COLOR_APPWORKSPACE)); - } -} - -struct CopyEntry -{ - int track, row; - sync::Track::KeyFrame keyFrame; -}; - - -void TrackView::editCopy() -{ - int selectLeft = min(selectStartTrack, selectStopTrack); - int selectRight = max(selectStartTrack, selectStopTrack); - int selectTop = min(selectStartRow, selectStopRow); - int selectBottom = max(selectStartRow, selectStopRow); - - if (FAILED(OpenClipboard(getWin()))) - { - MessageBox(NULL, _T("Failed to open clipboard"), NULL, MB_OK); - return; - } - - // gather data - int rows = selectBottom - selectTop + 1; - int columns = selectRight - selectLeft + 1; - size_t cells = columns * rows; - - std::vector copyEntries; - for (int track = selectLeft; track <= selectRight; ++track) - { - int localTrack = track - selectLeft; - const sync::Track &t = syncData->getTrack(track); - for (int row = selectTop; row <= selectBottom; ++row) - { - int localRow = row - selectTop; - if (t.isKeyFrame(row)) - { - const sync::Track::KeyFrame *keyFrame = t.getKeyFrame(row); - assert(NULL != keyFrame); - - CopyEntry ce; - ce.track = localTrack; - ce.row = localRow; - ce.keyFrame = *keyFrame; - - copyEntries.push_back(ce); - } - } - } - - int buffer_width = selectRight - selectLeft + 1; - int buffer_height = selectBottom - selectTop + 1; - size_t buffer_size = copyEntries.size(); - - HGLOBAL hmem = GlobalAlloc(GMEM_MOVEABLE, sizeof(int) * 3 + sizeof(CopyEntry) * copyEntries.size()); - char *clipbuf = (char *)GlobalLock(hmem); - - // copy data - memcpy(clipbuf + 0, &buffer_width, sizeof(int)); - memcpy(clipbuf + sizeof(int), &buffer_height, sizeof(int)); - memcpy(clipbuf + 2 * sizeof(int), &buffer_size, sizeof(size_t)); - if (copyEntries.size() > 0 ) memcpy(clipbuf + 2 * sizeof(int) + sizeof(size_t), ©Entries[0], sizeof(CopyEntry) * copyEntries.size()); - - GlobalUnlock(hmem); - clipbuf = NULL; - - // update clipboard - EmptyClipboard(); - SetClipboardData(clipboardFormat, hmem); - CloseClipboard(); -} - -void TrackView::editCut() -{ - editCopy(); - editDelete(); -} - -void TrackView::editPaste() -{ -#if 1 - if (FAILED(OpenClipboard(getWin()))) - { - MessageBox(NULL, _T("Failed to open clipboard"), NULL, MB_OK); - return; - } - - if (IsClipboardFormatAvailable(clipboardFormat)) - { - HGLOBAL hmem = GetClipboardData(clipboardFormat); - char *clipbuf = (char *)GlobalLock(hmem); - - // copy data - int buffer_width, buffer_height, buffer_size; - memcpy(&buffer_width, clipbuf + 0, sizeof(int)); - memcpy(&buffer_height, clipbuf + sizeof(int), sizeof(int)); - memcpy(&buffer_size, clipbuf + 2 * sizeof(int), sizeof(size_t)); - - if (buffer_size > 0) - { - char *src = clipbuf + 2 * sizeof(int) + sizeof(size_t); - - SyncEditData::MultiCommand *multiCmd = new SyncEditData::MultiCommand(); - for (int i = 0; i < buffer_size; ++i) - { - struct CopyEntry ce; - memcpy(&ce, src, sizeof(CopyEntry)); - - SyncEditData::Command *cmd = syncData->getSetKeyFrameCommand(editTrack + ce.track, editRow + ce.row, ce.keyFrame); - multiCmd->addCommand(cmd); - src += sizeof(CopyEntry); - } - syncData->exec(multiCmd); - } - - GlobalUnlock(hmem); - clipbuf = NULL; - } - else MessageBeep(0); - - CloseClipboard(); -#endif -} - -void TrackView::setupScrollBars() -{ - SCROLLINFO si = { sizeof(si) }; - si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL; - si.nPos = editRow; - si.nPage = windowRows; - si.nMin = 0; - si.nMax = rows - 1 + windowRows - 1; - SetScrollInfo(hwnd, SB_VERT, &si, TRUE); - - si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL; - si.nPos = editTrack; - si.nPage = windowTracks; - si.nMin = 0; - si.nMax = getTrackCount() - 1 + windowTracks - 1; - SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); -} - -void TrackView::scrollWindow(int scrollX, int scrollY) -{ - RECT clip; - GetClientRect(hwnd, &clip); - - if (scrollX == 0) clip.top = topMarginHeight; // don't scroll the top margin - if (scrollY == 0) clip.left = leftMarginWidth; // don't scroll the left margin - - ScrollWindowEx( - hwnd, - scrollX, - scrollY, - NULL, - &clip, - NULL, - NULL, - SW_INVALIDATE - ); -} - -void TrackView::setScrollPos(int newScrollPosX, int newScrollPosY) -{ - // clamp newscrollPosX - newScrollPosX = max(newScrollPosX, 0); - - if (newScrollPosX != scrollPosX || newScrollPosY != scrollPosY) - { - int scrollX = scrollPosX - newScrollPosX; - int scrollY = scrollPosY - newScrollPosY; - - // update scrollPos - scrollPosX = newScrollPosX; - scrollPosY = newScrollPosY; - - scrollWindow(scrollX, scrollY); - } - setupScrollBars(); -} - -void TrackView::setEditRow(int newEditRow) -{ - int oldEditRow = editRow; - editRow = newEditRow; - - // clamp to document - editRow = min(max(editRow, 0), rows - 1); - - if (oldEditRow != editRow) - { - if (GetKeyState(VK_SHIFT) < 0) - { - selectStopRow = editRow; - invalidateRange(selectStartTrack, selectStopTrack, oldEditRow, editRow); - } - else - { - invalidateRange(selectStartTrack, selectStopTrack, selectStartRow, selectStopRow); - selectStartRow = selectStopRow = editRow; - selectStartTrack = selectStopTrack = editTrack; - } - getSyncData()->sendSetRowCommand(editRow); - } - - invalidateRow(oldEditRow); - invalidateRow(editRow); - - setScrollPos(scrollPosX, (editRow * fontHeight) - ((windowHeight - topMarginHeight) / 2) + fontHeight / 2); -} - -void TrackView::setEditTrack(int newEditTrack) -{ - int oldEditTrack = editTrack; - editTrack = newEditTrack; - - // clamp to document - editTrack = max(editTrack, 0); - editTrack = min(editTrack, getTrackCount() - 1); - - if (oldEditTrack != editTrack) - { - if (GetKeyState(VK_SHIFT) < 0) - { - selectStopTrack = editTrack; - invalidateRange(oldEditTrack, editTrack, selectStartRow, selectStopRow); - } - else - { - invalidateRange(selectStartTrack, selectStopTrack, selectStartRow, selectStopRow); - selectStartRow = selectStopRow = editRow; - selectStartTrack = selectStopTrack = editTrack; - } - } - - invalidateTrack(oldEditTrack); - invalidateTrack(editTrack); - - int firstTrack = scrollPosX / trackWidth; - int lastTrack = firstTrack + windowTracks; - - int newFirstTrack = firstTrack; - if (editTrack >= lastTrack) newFirstTrack = editTrack - (lastTrack - firstTrack - 1); - if (editTrack < firstTrack) newFirstTrack = editTrack; - setScrollPos(newFirstTrack * trackWidth, scrollPosY); -} - -static int getScrollPos(HWND hwnd, int bar) -{ - SCROLLINFO si = { sizeof(si), SIF_TRACKPOS }; - GetScrollInfo(hwnd, bar, &si); - return int(si.nTrackPos); -} - -void TrackView::setRows(int rows) -{ - this->rows = rows; - InvalidateRect(getWin(), NULL, FALSE); - setEditRow(min(editRow, rows - 1)); -} - - -LRESULT TrackView::onVScroll(UINT sbCode, int /*newPos*/) -{ - switch (sbCode) - { - case SB_TOP: - setEditRow(0); - break; - - case SB_LINEUP: - setEditRow(editRow - 1); - break; - - case SB_LINEDOWN: - setEditRow(editRow + 1); - break; - - case SB_PAGEUP: - setEditRow(editRow - windowRows / 2); - break; - - case SB_PAGEDOWN: - setEditRow(editRow + windowRows / 2); - break; - - case SB_THUMBPOSITION: - case SB_THUMBTRACK: - setEditRow(getScrollPos(hwnd, SB_VERT)); - break; - } - - return FALSE; -} - -LRESULT TrackView::onHScroll(UINT sbCode, int /*newPos*/) -{ - switch (sbCode) - { - case SB_LEFT: - setEditTrack(0); - break; - - case SB_RIGHT: - setEditTrack(getTrackCount() - 1); - break; - - case SB_LINELEFT: - setEditTrack(editTrack - 1); - break; - - case SB_LINERIGHT: - setEditTrack(editTrack + 1); - break; - - case SB_PAGELEFT: - setEditTrack(editTrack - windowTracks); - break; - - case SB_PAGEDOWN: - setEditTrack(editTrack + windowTracks); - break; - - case SB_THUMBPOSITION: - case SB_THUMBTRACK: - setEditTrack(getScrollPos(hwnd, SB_HORZ)); - break; - } - - return FALSE; -} - -void TrackView::editEnterValue() -{ - if (editString.size() > 0) - { - sync::Track &t = syncData->getTrack(editTrack); - - sync::Track::KeyFrame newKey; - if (t.isKeyFrame(editRow)) newKey = *t.getKeyFrame(editRow); // copy old key - newKey.value = float(_tstof(editString.c_str())); // modify value - - SyncEditData::Command *cmd = syncData->getSetKeyFrameCommand(editTrack, editRow, newKey); - syncData->exec(cmd); - - editString.clear(); - invalidatePos(editTrack, editRow); - } - else MessageBeep(0); -} - -void TrackView::editDelete() -{ - int selectLeft = min(selectStartTrack, selectStopTrack); - int selectRight = max(selectStartTrack, selectStopTrack); - int selectTop = min(selectStartRow, selectStopRow); - int selectBottom = max(selectStartRow, selectStopRow); - - SyncEditData::MultiCommand *multiCmd = new SyncEditData::MultiCommand(); - for (int track = selectLeft; track <= selectRight; ++track) - { - sync::Track &t = syncData->getTrack(track); - for (int row = selectTop; row <= selectBottom; ++row) - { - if (t.isKeyFrame(row)) - { - SyncEditData::Command *cmd = new SyncEditData::DeleteCommand(track, row); - multiCmd->addCommand(cmd); - } - } - } - - if (0 == multiCmd->getSize()) - { - MessageBeep(0); - delete multiCmd; - } - else - { - syncData->exec(multiCmd); - invalidateRange(selectLeft, selectRight, selectTop, selectBottom); - } -} - -void TrackView::editBiasValue(float amount) -{ - int selectLeft = min(selectStartTrack, selectStopTrack); - int selectRight = max(selectStartTrack, selectStopTrack); - int selectTop = min(selectStartRow, selectStopRow); - int selectBottom = max(selectStartRow, selectStopRow); - - SyncEditData::MultiCommand *multiCmd = new SyncEditData::MultiCommand(); - for (int track = selectLeft; track <= selectRight; ++track) - { - sync::Track &t = syncData->getTrack(track); - for (int row = selectTop; row <= selectBottom; ++row) - { - if (t.isKeyFrame(row)) - { - sync::Track::KeyFrame newKey = *t.getKeyFrame(row); // copy old key - newKey.value += amount; // modify value - - // add sub-command - SyncEditData::Command *cmd = syncData->getSetKeyFrameCommand(track, row, newKey); - multiCmd->addCommand(cmd); - } - } - } - - if (0 == multiCmd->getSize()) - { - MessageBeep(0); - delete multiCmd; - } - else - { - syncData->exec(multiCmd); - invalidateRange(selectLeft, selectRight, selectTop, selectBottom); - } -} - -LRESULT TrackView::onKeyDown(UINT keyCode, UINT /*flags*/) -{ - if (editString.empty() && getSyncData()->clientPaused) - { - switch (keyCode) - { - case VK_UP: - if (GetKeyState(VK_CONTROL) < 0) - { - float bias = 1.0f; - if (GetKeyState(VK_SHIFT) < 0) bias = 0.1f; - editBiasValue(bias); - } - else setEditRow(editRow - 1); - break; - - case VK_DOWN: - if (GetKeyState(VK_CONTROL) < 0) - { - float bias = 1.0f; - if (GetKeyState(VK_SHIFT) < 0) bias = 0.1f; - editBiasValue(-bias); - } - else setEditRow(editRow + 1); - break; - - case VK_LEFT: setEditTrack(editTrack - 1); break; - case VK_RIGHT: setEditTrack(editTrack + 1); break; - - case VK_PRIOR: - if (GetKeyState(VK_CONTROL) < 0) - { - float bias = 10.0f; - if (GetKeyState(VK_SHIFT) < 0) bias = 100.0f; - editBiasValue(bias); - } - else setEditRow(editRow - windowRows / 2); - break; - - case VK_NEXT: - if (GetKeyState(VK_CONTROL) < 0) - { - float bias = 10.0f; - if (GetKeyState(VK_SHIFT) < 0) bias = 100.0f; - editBiasValue(-bias); - } - else setEditRow(editRow + windowRows / 2); - break; - - default: - break; - } - } - - switch (keyCode) - { - case VK_RETURN: editEnterValue(); break; - case VK_DELETE: editDelete(); break; - - case VK_BACK: - if (!editString.empty()) - { - editString.resize(editString.size() - 1); - invalidatePos(editTrack, editRow); - } - else MessageBeep(0); - break; - - case VK_CANCEL: - case VK_ESCAPE: - if (!editString.empty()) - { - // return to old value (i.e don't clear) - editString.clear(); - invalidatePos(editTrack, editRow); - MessageBeep(0); - } - break; - case VK_SPACE: - getSyncData()->sendPauseCommand( !getSyncData()->clientPaused ); - break; - } - return FALSE; -} - -LRESULT TrackView::onChar(UINT keyCode, UINT flags) -{ - switch (char(keyCode)) - { - case '.': - // only one '.' allowed - if (std::string::npos != editString.find('.')) - { - MessageBeep(0); - break; - } - case '-': - if (editString.empty()) - { - editString.push_back(char(keyCode)); - invalidatePos(editTrack, editRow); - } - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - editString.push_back(char(keyCode)); - invalidatePos(editTrack, editRow); - break; - } - return FALSE; -} - -LRESULT TrackView::onSize(int width, int height) -{ - windowWidth = width; - windowHeight = height; - - windowRows = (height - topMarginHeight) / fontHeight; - windowTracks = (width - leftMarginWidth) / trackWidth; - - setEditRow(editRow); - setupScrollBars(); - return FALSE; -} - -LRESULT TrackView::windowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - ASSERT(hwnd == this->hwnd); - - switch(msg) - { - case WM_CREATE: return onCreate(); - - case WM_CLOSE: - DestroyWindow(hwnd); - break; - - case WM_DESTROY: - PostQuitMessage(0); - break; - - case WM_SIZE: return onSize(LOWORD(lParam), HIWORD(lParam)); - case WM_VSCROLL: return onVScroll(LOWORD(wParam), getScrollPos(hwnd, SB_VERT)); - case WM_HSCROLL: return onHScroll(LOWORD(wParam), getScrollPos(hwnd, SB_HORZ)); - case WM_PAINT: return onPaint(); - case WM_KEYDOWN: return onKeyDown((UINT)wParam, (UINT)lParam); - case WM_CHAR: return onChar((UINT)wParam, (UINT)lParam); - - case WM_COPY: editCopy(); break; - case WM_CUT: editCut(); break; - case WM_PASTE: - editPaste(); - InvalidateRect(hwnd, NULL, FALSE); - break; - - case WM_UNDO: - if (!syncData->undo()) MessageBeep(0); - // unfortunately, we don't know how much to invalidate... so we'll just invalidate it all. - InvalidateRect(hwnd, NULL, FALSE); - break; - - case WM_REDO: - if (!syncData->redo()) MessageBeep(0); - // unfortunately, we don't know how much to invalidate... so we'll just invalidate it all. - InvalidateRect(hwnd, NULL, FALSE); - break; - - default: - return DefWindowProc(hwnd, msg, wParam, lParam); - } - return FALSE; -} - -static LRESULT CALLBACK trackViewWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - // Get the TrackView instance (if any) -#pragma warning(suppress:4312) /* remove a pointless warning */ - TrackView *trackView = (TrackView*)GetWindowLongPtr(hwnd, 0); - - switch(msg) - { - case WM_NCCREATE: - // Get TrackView from createstruct - trackView = (TrackView*)((CREATESTRUCT*)lParam)->lpCreateParams; - trackView->hwnd = hwnd; - - // Set the TrackView instance -#pragma warning(suppress:4244) /* remove a pointless warning */ - SetWindowLongPtr(hwnd, 0, (LONG_PTR)trackView); - - // call the proper window procedure - return trackView->windowProc(hwnd, msg, wParam, lParam); - break; - - case WM_NCDESTROY: - ASSERT(NULL != trackView); - { - // call the window proc and store away the return code - LRESULT res = trackView->windowProc(hwnd, msg, wParam, lParam); - - // get rid of the TrackView instance - trackView = NULL; - SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL); - - // return the stored return code - return res; - } - break; - - default: - ASSERT(NULL != trackView); - return trackView->windowProc(hwnd, msg, wParam, lParam); - } -} - -ATOM registerTrackViewWindowClass(HINSTANCE hInstance) -{ - WNDCLASSEX wc; - - wc.cbSize = sizeof(WNDCLASSEX); - wc.style = 0; - wc.lpfnWndProc = trackViewWindowProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = sizeof(TrackView*); - wc.hInstance = hInstance; - wc.hIcon = 0; - wc.hCursor = LoadCursor(NULL, IDC_IBEAM); - wc.hbrBackground = (HBRUSH)0; - wc.lpszMenuName = NULL; - wc.lpszClassName = trackViewWindowClassName; - wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - - return RegisterClassEx(&wc); -} - -HWND TrackView::create(HINSTANCE hInstance, HWND hwndParent) -{ - HWND hwnd = CreateWindowEx( - WS_EX_CLIENTEDGE, - trackViewWindowClassName, _T(""), - WS_VSCROLL | WS_HSCROLL | WS_CHILD | WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, // x, y - CW_USEDEFAULT, CW_USEDEFAULT, // width, height - hwndParent, NULL, hInstance, (void*)this - ); - return hwnd; -} - diff --git a/trackview.h b/trackview.h deleted file mode 100644 index e43fbaf..0000000 --- a/trackview.h +++ /dev/null @@ -1,143 +0,0 @@ -#pragma once - -#include "synceditdata.h" - -#include -#include -#include - -// custom messages -#define WM_REDO (WM_USER + 1) - -class TrackView -{ -public: - TrackView(); - ~TrackView(); - - HWND create(HINSTANCE hInstance, HWND hwndParent); - HWND getWin(){ return hwnd; } - - void setSyncData(SyncEditData *syncData) { this->syncData = syncData; } - SyncEditData *getSyncData() { return syncData; } - - void setRows(int rows); - int getRows() const { return rows; } - void editBiasValue(float amount); - - void setEditRow(int newEditRow); - int getEditRow() { return editRow; } - -private: - // some nasty hackery to forward the window messages - friend static LRESULT CALLBACK trackViewWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - LRESULT windowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - - // events - LRESULT onCreate(); - LRESULT onPaint(); - LRESULT onVScroll(UINT sbCode, int newPos); - LRESULT onHScroll(UINT sbCode, int newPos); - LRESULT onSize(int width, int height); - LRESULT onKeyDown(UINT keyCode, UINT flags); - LRESULT onChar(UINT keyCode, UINT flags); - - void editEnterValue(); - void editDelete(); - void editCopy(); - void editCut(); - void editPaste(); - - void paintTracks(HDC hdc, RECT rcTracks); - void paintTopMargin(HDC hdc, RECT rcTracks); - - void setupScrollBars(); - void setScrollPos(int newScrollPosX, int newScrollPosY); - void scrollWindow(int newScrollPosX, int newScrollPosY); - - void invalidateRange(int startTrack, int stopTrack, int startRow, int stopRow) - { - RECT rect; - rect.left = getScreenX(min(startTrack, stopTrack)); - rect.right = getScreenX(max(startTrack, stopTrack) + 1); - rect.top = getScreenY(min(startRow, stopRow)); - rect.bottom = getScreenY(max(startRow, stopRow) + 1); - InvalidateRect(hwnd, &rect, FALSE); - } - - void invalidatePos(int track, int row) - { - RECT rect; - rect.left = getScreenX(track); - rect.right = getScreenX(track + 1); - rect.top = getScreenY(row); - rect.bottom = getScreenY(row + 1); - InvalidateRect(hwnd, &rect, FALSE); - } - - void invalidateRow(int row) - { - RECT clientRect; - GetClientRect(hwnd, &clientRect); - - RECT rect; - rect.left = clientRect.left; - rect.right = clientRect.right; - rect.top = getScreenY(row); - rect.bottom = getScreenY(row + 1); - - InvalidateRect(hwnd, &rect, FALSE); - } - - void invalidateTrack(int track) - { - RECT clientRect; - GetClientRect(hwnd, &clientRect); - - RECT rect; - rect.left = getScreenX(track); - rect.right = getScreenX(track + 1); - rect.top = clientRect.top; - rect.bottom = clientRect.bottom; - - InvalidateRect(hwnd, &rect, FALSE); - } - - void setEditTrack(int newEditTrack); - - int getScreenY(int row); - int getScreenX(int track); - - int getTrackCount() - { - sync::Data *syncData = getSyncData(); - if (NULL == syncData) return 0; - return int(syncData->getTrackCount()); - }; - - int selectStartTrack, selectStopTrack; - int selectStartRow, selectStopRow; - - HBRUSH bgBaseBrush, bgDarkBrush; - HBRUSH selectBaseBrush, selectDarkBrush; - HPEN rowPen, rowSelectPen; - HBRUSH editBrush; - - /* cursor position */ - int editRow, editTrack; - - int scrollPosX, scrollPosY; - int windowWidth, windowHeight; - int windowRows, windowTracks; - - SyncEditData *syncData; - - std::basic_string editString; - - HWND hwnd; - - UINT clipboardFormat; - int rows; -}; - -ATOM registerTrackViewWindowClass(HINSTANCE hInstance);