edit with undo!

This commit is contained in:
Erik Faye-Lund 2008-01-17 22:54:45 +00:00
parent bb3aeab4f9
commit 8f9877f79b
5 changed files with 425 additions and 121 deletions

View File

@ -51,11 +51,22 @@ public:
return &iter->second;
}
void deleteKeyFrame(int row)
{
keyFrames.erase(row);
}
void setKeyFrame(int row, const KeyFrame &keyFrame)
{
keyFrames[row] = keyFrame;
}
void setKeyFrame(int row, const float value)
{
keyFrames[row] = KeyFrame(value);
}
private:
typedef std::map<int, struct KeyFrame> KeyFrameContainer;
KeyFrameContainer keyFrames;
@ -71,6 +82,16 @@ public:
return tracks[name] = SyncTrack();
}
SyncTrack &getTrack(size_t track)
{
assert(track >= 0);
assert(track < tracks.size());
SyncData::TrackContainer::iterator trackIter = tracks.begin();
for (size_t currTrack = 0; currTrack < track; ++currTrack, ++trackIter);
return trackIter->second;
}
size_t getTrackCount() { return tracks.size(); }
// private:

View File

@ -3,6 +3,7 @@
#include "stdafx.h"
#include <windows.h>
#include <commctrl.h>
#include "trackview.h"
@ -10,27 +11,86 @@ const TCHAR *mainWindowClassName = _T("MainWindow");
TrackView *trackView;
HWND trackViewWin;
HWND statusBarWin;
static LRESULT CALLBACK mainWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
trackViewWin = trackView->create(GetModuleHandle(NULL), hwnd);
InitCommonControls();
statusBarWin = CreateWindowEx(
0, // no extended styles
STATUSCLASSNAME, // status bar
(LPCTSTR)"mordi", // no text
SBARS_SIZEGRIP | WS_VISIBLE | WS_CHILD, // styles
0, 0, 0, 0, // x, y, cx, cy
hwnd, // parent window
(HMENU)100, // window ID
GetModuleHandle(NULL), // instance
NULL // window data
);
int statwidths[] = {100, -1};
SendMessage(statusBarWin, SB_SETPARTS, sizeof(statwidths)/sizeof(int), (LPARAM)statwidths);
SendMessage(statusBarWin, SB_SETTEXT, 0, (LPARAM)"Hi there :)");
HMENU fileMenu = CreatePopupMenu();
AppendMenu(fileMenu, MF_STRING, 0, "&Open\tCtrl+O");
AppendMenu(fileMenu, MF_STRING, 2, "&Save\tCtrl+S");
AppendMenu(fileMenu, MF_STRING, 3, "Save &As");
AppendMenu(fileMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(fileMenu, MF_STRING, 3, "&Exit");
HMENU editMenu = CreatePopupMenu();
AppendMenu(editMenu, MF_STRING, WM_USER+0, "&Undo\tCtrl+Z");
AppendMenu(editMenu, MF_STRING, WM_USER+1, "&Redo\tShift+Ctrl+Z");
AppendMenu(editMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(editMenu, MF_STRING, WM_CUT, "Cu&t\tCtrl+X");
AppendMenu(editMenu, MF_STRING, WM_COPY, "&Copy\tCtrl+C");
AppendMenu(editMenu, MF_STRING, WM_PASTE, "&Paste\tCtrl+V");
HMENU rootMenu = CreateMenu();
AppendMenu(rootMenu, MF_STRING | MF_POPUP, (UINT_PTR)fileMenu, "&File");
AppendMenu(rootMenu, MF_STRING | MF_POPUP, (UINT_PTR)editMenu, "&Edit");
SetMenu(hwnd, rootMenu);
}
break;
case WM_SIZE:
{
int width = LOWORD(lParam);
int height = HIWORD(lParam);
MoveWindow(trackViewWin, 0, 0, width, height, TRUE);
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_COMMAND:
switch (wParam)
{
case WM_COPY:
/* PostMessage(m_hWnd, WM_COPY, 0, 0); */
/* HMMMM.... not working... */
printf("copy!\n");
break;
default:
printf("cmd %d %d\n", wParam, lParam);
}
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
@ -57,12 +117,84 @@ static ATOM registerMainWindowClass(HINSTANCE hInstance)
return RegisterClassEx(&wc);
}
#include <winsock2.h>
int _tmain(int argc, _TCHAR* argv[])
{
HWND hwnd;
MSG Msg;
HINSTANCE hInstance = GetModuleHandle(NULL);
#if 0
WSADATA wsaData;
int error = WSAStartup( MAKEWORD( 2, 0 ), &wsaData );
if (0 != error)
{
fputs("Failed to init WinSock", stderr);
exit(1);
}
if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0)
{
fputs("Wrong version of WinSock", stderr);
exit(1);
}
SOCKET server = 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( 21 );
if (SOCKET_ERROR == bind( server, (struct sockaddr *)&sin, sizeof(sin)))
{
fputs("Coult not start server", stderr);
exit(1);
}
while ( listen( server, SOMAXCONN ) == SOCKET_ERROR );
int length = sizeof(sin);
SOCKET client = accept( server, (sockaddr *)&sin, &length );
const char *test = "TEST123";
int sent = send( client, test, strlen(test), 0);
if (SOCKET_ERROR == sent)
{
int err = WSAGetLastError();
fprintf(stderr, "failed to send - err %d\n", err);
exit(1);
}
unsigned long int nonBlock = 1;
if (ioctlsocket(client, FIONBIO, &nonBlock) == SOCKET_ERROR)
{
printf("ioctlsocket() failed \n");
exit(1);
}
int read = 0;
while (read < 20)
{
char buffer[1024];
int len = recv(client, buffer, 1024, 0);
if (0 < len)
{
printf("got \"%s\" - left: %d\n", buffer, 20 - (read + len));
read += len;
}
}
closesocket(client);
closesocket(server);
WSACleanup();
#endif
SyncData syncData;
SyncTrack &camXTrack = syncData.getTrack("cam.x");
SyncTrack &camYTrack = syncData.getTrack("cam.y");
@ -118,13 +250,23 @@ int _tmain(int argc, _TCHAR* argv[])
ShowWindow(hwnd, TRUE);
UpdateWindow(hwnd);
#if 0
/* while (1)
{
SOCKET client;
int length;
length = sizeof sin;
client = accept( server, (sockaddr *)&sin, &length );
} */
#else
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
#endif
delete trackView;
trackView = NULL;

View File

@ -60,6 +60,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib comctl32.lib "
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
@ -134,6 +135,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib comctl32.lib "
LinkIncremental="1"
GenerateManifest="false"
GenerateDebugInformation="true"

View File

@ -11,10 +11,9 @@ static const int fontHeight = 16;
static const int fontWidth = 6;
static const int trackWidth = fontWidth * 16;
static const int rows = 0x80;
TrackView::TrackView() : syncData(NULL)
TrackView::TrackView()
{
scrollPosX = 0;
scrollPosY = 0;
@ -44,12 +43,13 @@ int TrackView::getScreenX(int track)
return leftMarginWidth + (track * trackWidth) - scrollPosX;
}
void TrackView::onCreate()
LRESULT TrackView::onCreate()
{
setupScrollBars();
return FALSE;
}
void TrackView::onPaint()
LRESULT TrackView::onPaint()
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
@ -59,6 +59,8 @@ void TrackView::onPaint()
paintTracks(hdc, ps.rcPaint);
EndPaint(hwnd, &ps);
return FALSE;
}
void TrackView::paintTopMargin(HDC hdc, RECT rcTracks)
@ -202,17 +204,21 @@ void TrackView::paintTracks(HDC hdc, RECT rcTracks)
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);
bool drawEditString = false;
if (row == editRow && track == editTrack)
{
// DrawFocusRect(hdc, &fillRect);
Rectangle(hdc, fillRect.left, fillRect.top, fillRect.right, fillRect.bottom);
if (editString.size() > 0) drawEditString = true;
}
const SyncTrack &track = trackIter->second;
bool key = track.isKeyFrame(row);
/* format the text */
if (!key) _sntprintf_s(temp, 256, _T("---"));
if (drawEditString) _sntprintf_s(temp, 256, editString.c_str());
else if (!key) _sntprintf_s(temp, 256, _T("---"));
else
{
float val = track.getKeyFrame(row)->value;
@ -347,21 +353,6 @@ void TrackView::setEditTrack(int newEditTrack)
editTrack = max(editTrack, 0);
editTrack = min(editTrack, getTrackCount() - 1);
// sync up iterators
/* int currEditTrack = oldEditTrack;
while (editTrack != currEditTrack)
{
if (currEditTrack < editTrack)
{
currEditTrack++;
}
else
{
currEditTrack--;
}
} */
RECT trackRect;
// dirty old and new marker
@ -406,7 +397,7 @@ static int getScrollPos(HWND hwnd, int bar)
return int(si.nTrackPos);
}
void TrackView::onVScroll(UINT sbCode, int newPos)
LRESULT TrackView::onVScroll(UINT sbCode, int newPos)
{
switch (sbCode)
{
@ -435,9 +426,11 @@ void TrackView::onVScroll(UINT sbCode, int newPos)
setEditRow(getScrollPos(hwnd, SB_VERT));
break;
}
return FALSE;
}
void TrackView::onHScroll(UINT sbCode, int newPos)
LRESULT TrackView::onHScroll(UINT sbCode, int newPos)
{
switch (sbCode)
{
@ -470,57 +463,73 @@ void TrackView::onHScroll(UINT sbCode, int newPos)
setEditTrack(getScrollPos(hwnd, SB_HORZ));
break;
}
return FALSE;
}
void TrackView::onKeyDown(UINT keyCode, UINT flags)
LRESULT TrackView::onKeyDown(UINT keyCode, UINT flags)
{
bool refreshCaret = false;
bool ctrlDown = GetKeyState(VK_CONTROL) < 0 ? true : false;
bool shiftDown = GetKeyState(VK_SHIFT) < 0 ? true : false;
bool altDown = GetKeyState(VK_MENU) < 0 ? true : false;
if (editString.empty())
{
switch (keyCode)
{
case VK_UP: setEditRow(editRow - 1); break;
case VK_DOWN: setEditRow(editRow + 1); break;
case VK_LEFT: setEditTrack(editTrack - 1); break;
case VK_RIGHT: setEditTrack(editTrack + 1); break;
case VK_PRIOR: setEditRow(editRow - windowRows / 2); break;
case VK_NEXT: setEditRow(editRow + windowRows / 2); break;
case 'U':
if (true == ctrlDown && true == shiftDown)
{
if (!syncDataEdit.redo()) MessageBeep(0);
}
else if (true == ctrlDown)
{
if (!syncDataEdit.undo()) MessageBeep(0);
}
InvalidateRect(hwnd, NULL, TRUE);
break;
}
}
switch (keyCode)
{
case VK_UP: setEditRow(editRow - 1); break;
case VK_DOWN: setEditRow(editRow + 1); break;
case VK_LEFT: setEditTrack(editTrack - 1); break;
case VK_RIGHT: setEditTrack(editTrack + 1); break;
case VK_PRIOR: setEditRow(editRow - windowRows / 2); break;
case VK_NEXT: setEditRow(editRow + windowRows / 2); break;
}
}
void TrackView::onChar(UINT keyCode, UINT flags)
{
bool refresh = false;
printf("char: \"%c\" (%d) - flags: %x\n", (char)keyCode, keyCode, flags);
switch ((char)keyCode)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
editString.push_back(keyCode);
printf("accepted: %c - %s\n", (char)keyCode, editString.c_str());
refresh = true;
case VK_RETURN:
{
SyncDataEdit::EditCommand *cmd = new SyncDataEdit::EditCommand(
editTrack, editRow,
float(atof(editString.c_str()))
);
syncDataEdit.exec(cmd);
editString.clear();
refreshCaret = true;
}
break;
case VK_RETURN:
printf("submit: %f\n", atof(editString.c_str()));
// TODO: submit new number
editString.clear();
refresh = true;
case VK_DELETE:
{
SyncTrack &track = getSyncData()->getTrack(editTrack);
track.deleteKeyFrame(editRow);
refreshCaret = true;
}
break;
case VK_BACK:
if (editString.size() > 0)
{
editString.resize(editString.size() - 1);
refresh = true;
refreshCaret = true;
}
else MessageBeep(0);
break;
@ -532,28 +541,67 @@ void TrackView::onChar(UINT keyCode, UINT flags)
// return to old value (i.e don't clear)
editString.clear();
refresh = true;
refreshCaret = true;
MessageBeep(0);
}
break;
default:
MessageBeep(0);
}
if (refresh)
if (refreshCaret)
{
/* RECT rowRect;
NB: getScreenX(int track)
rowRect.left = clientRect.left;
rowRect.right = clientRect.right;
rowRect.top = getScreenY(oldEditRow);
rowRect.bottom = rowRect.top + fontHeight;
InvalidateRect(hwnd, &rowRect, TRUE); */
RECT rowRect;
rowRect.left = getScreenX(editTrack);
rowRect.right = getScreenX(editTrack + 1);
rowRect.top = getScreenY(editRow);
rowRect.bottom = getScreenY(editRow + 1);
InvalidateRect(hwnd, &rowRect, TRUE);
}
return FALSE;
}
void TrackView::onSize(int width, int height)
LRESULT TrackView::onChar(UINT keyCode, UINT flags)
{
bool refreshCaret = false;
printf("char: \"%c\" (%d) - flags: %x\n", (char)keyCode, keyCode, flags);
switch ((char)keyCode)
{
case '.':
// only one '.' allowed
if (std::string::npos != editString.find('.'))
{
MessageBeep(0);
break;
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
editString.push_back(keyCode);
printf("accepted: %c - %s\n", (char)keyCode, editString.c_str());
refreshCaret = true;
break;
}
if (refreshCaret)
{
RECT rowRect;
rowRect.left = getScreenX(editTrack);
rowRect.right = getScreenX(editTrack + 1);
rowRect.top = getScreenY(editRow);
rowRect.bottom = getScreenY(editRow + 1);
InvalidateRect(hwnd, &rowRect, TRUE);
}
return FALSE;
}
LRESULT TrackView::onSize(int width, int height)
{
const int oldWindowWidth = windowWidth;
const int oldWindowHeight = windowHeight;
@ -566,6 +614,7 @@ void TrackView::onSize(int width, int height)
setEditRow(editRow);
setupScrollBars();
return FALSE;
}
LRESULT TrackView::windowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
@ -574,9 +623,7 @@ LRESULT TrackView::windowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
switch(msg)
{
case WM_CREATE:
onCreate();
break;
case WM_CREATE: return onCreate();
case WM_CLOSE:
DestroyWindow(hwnd);
@ -586,28 +633,15 @@ LRESULT TrackView::windowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
PostQuitMessage(0);
break;
case WM_SIZE:
onSize(LOWORD(lParam), HIWORD(lParam));
break;
case WM_VSCROLL:
onVScroll(LOWORD(wParam), getScrollPos(hwnd, SB_VERT));
break;
case WM_HSCROLL:
onHScroll(LOWORD(wParam), getScrollPos(hwnd, SB_HORZ));
break;
case WM_PAINT:
onPaint();
break;
case WM_KEYDOWN:
onKeyDown((UINT)wParam, (UINT)lParam);
break;
case WM_CHAR:
onChar((UINT)wParam, (UINT)lParam);
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:
printf("copy!\n");
break;
default:

View File

@ -2,47 +2,152 @@
#include "syncdata.h"
#include <list>
#include <string>
#include <stack>
class SyncData;
class SyncDataEdit
{
public:
SyncDataEdit() : syncData(NULL) {}
void setSyncData(SyncData *syncData) { this->syncData = syncData; }
SyncData *getSyncData() { return syncData; }
class Command
{
public:
virtual ~Command() {}
virtual void exec(SyncDataEdit *data) = 0;
virtual void undo(SyncDataEdit *data) = 0;
};
class EditCommand : public Command
{
public:
EditCommand(int track, int row, float value) : track(track), row(row), newVal(value) {}
~EditCommand() {}
virtual void exec(SyncDataEdit *data)
{
SyncTrack &track = data->getSyncData()->getTrack(this->track);
oldValExisting = track.isKeyFrame(row);
if (oldValExisting) oldVal = track.getKeyFrame(row)->value;
track.setKeyFrame(row, newVal);
}
virtual void undo(SyncDataEdit *data)
{
SyncTrack &track = data->getSyncData()->getTrack(this->track);
if (!oldValExisting) track.deleteKeyFrame(row);
else track.setKeyFrame(row, oldVal);
}
private:
int track, row;
float newVal, oldVal;
bool oldValExisting;
};
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;
}
}
private:
std::stack<Command*> undoStack;
std::stack<Command*> redoStack;
SyncData *syncData;
};
class TrackView
{
public:
TrackView();
~TrackView();
HWND create(HINSTANCE hInstance, HWND hwndParent);
HWND getWin(){ return hwnd; }
void setSyncData(SyncData *syncData) { this->syncData = syncData; }
SyncData *getSyncData() { return syncData; }
void setSyncData(SyncData *syncData) { this->syncDataEdit.setSyncData(syncData); }
SyncData *getSyncData() { return syncDataEdit.getSyncData(); }
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
void onCreate();
void onPaint();
void onVScroll(UINT sbCode, int newPos);
void onHScroll(UINT sbCode, int newPos);
void onSize(int width, int height);
void onKeyDown(UINT keyCode, UINT flags);
void onChar(UINT keyCode, UINT flags);
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);
// the window procedure
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 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, TRUE);
}
void setEditRow(int newEditRow);
void setEditTrack(int newEditTrack);
int getScreenY(int row);
int getScreenX(int track);
@ -52,16 +157,16 @@ private:
if (NULL == syncData) return 0;
return int(syncData->getTrackCount());
};
/* cursor position */
int editRow, editTrack;
int scrollPosX, scrollPosY;
int windowWidth, windowHeight;
int windowRows, windowTracks;
SyncData *syncData;
SyncDataEdit syncDataEdit;
std::string editString;
HWND hwnd;