diff --git a/VortexEditor/GUI/VButton.cpp b/VortexEditor/GUI/VButton.cpp index a3939cb..ff1e9f9 100644 --- a/VortexEditor/GUI/VButton.cpp +++ b/VortexEditor/GUI/VButton.cpp @@ -1,92 +1,91 @@ -#include "VButton.h" - -// Windows includes -#include - -// Vortex Engine includes -#include "EditorConfig.h" - -// Editor includes -#include "VortexEditor.h" - -using namespace std; - -VButton::VButton() : - VWindow(), - m_callback(nullptr) -{ -} - -VButton::VButton(HINSTANCE hInstance, VWindow &parent, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, - uintptr_t menuID, VWindowCallback callback) : - VButton() -{ - init(hInstance, parent, title, backcol, width, height, x, y, menuID, callback); -} - -VButton::~VButton() -{ - cleanup(); -} - -void VButton::init(HINSTANCE hInstance, VWindow &parent, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, - uintptr_t menuID, VWindowCallback callback) -{ - // store callback and menu id - m_callback = callback; - m_backColor = backcol; - m_foreColor = RGB(0xD0, 0xD0, 0xD0); - - if (!menuID) { - menuID = nextMenuID++; - } - - if (!parent.addChild(menuID, this)) { - return; - } - - // create the window - m_hwnd = CreateWindow(WC_BUTTON, title.c_str(), - WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | WS_TABSTOP, - x, y, width, height, parent.hwnd(), (HMENU)menuID, nullptr, nullptr); - if (!m_hwnd) { - MessageBox(nullptr, "Failed to open window", "Error", 0); - throw exception("idk"); - } - - // set 'this' in the user data area of the class so that the static callback - // routine can access the object - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); -} - -void VButton::cleanup() -{ -} - -void VButton::create() -{ -} - -void VButton::paint() -{ -} - -void VButton::command(WPARAM wParam, LPARAM lParam) -{ - if (!m_callback) { - return; - } - m_callback(m_callbackArg, this); -} - -void VButton::pressButton(WPARAM wParam, LPARAM lParam) -{ -} - -void VButton::releaseButton(WPARAM wParam, LPARAM lParam) -{ -} - - +#include "VButton.h" + +// Windows includes +#include +#include + +// Vortex Engine includes +#include "EditorConfig.h" + +// Editor includes +#include "VortexEditor.h" + +using namespace std; + +VButton::VButton() : + VWindow(), + m_callback(nullptr) +{ +} + +VButton::VButton(HINSTANCE hInstance, VWindow &parent, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uintptr_t menuID, VWindowCallback callback) : + VButton() +{ + init(hInstance, parent, title, backcol, width, height, x, y, menuID, callback); +} + +VButton::~VButton() +{ + cleanup(); +} + +void VButton::init(HINSTANCE hInstance, VWindow &parent, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uintptr_t menuID, VWindowCallback callback) +{ + // store callback and menu id + m_callback = callback; + m_backColor = backcol; + m_foreColor = RGB(0xD0, 0xD0, 0xD0); + + if (!menuID) { + menuID = nextMenuID++; + } + + if (!parent.addChild(menuID, this)) { + return; + } + + // create the window + m_hwnd = CreateWindow(WC_BUTTON, title.c_str(), + WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | WS_TABSTOP, + x, y, width, height, parent.hwnd(), (HMENU)menuID, nullptr, nullptr); + if (!m_hwnd) { + MessageBox(nullptr, "Failed to open window", "Error", 0); + throw exception("idk"); + } + + // set 'this' in the user data area of the class so that the static callback + // routine can access the object + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); +} + +void VButton::cleanup() +{ +} + +void VButton::create() +{ +} + +void VButton::paint() +{ +} + +void VButton::command(WPARAM wParam, LPARAM lParam) +{ + if (!m_callback) { + return; + } + m_callback(m_callbackArg, this); +} + +void VButton::pressButton(WPARAM wParam, LPARAM lParam) +{ +} + +void VButton::releaseButton(WPARAM wParam, LPARAM lParam) +{ +} diff --git a/VortexEditor/GUI/VChildWindow.cpp b/VortexEditor/GUI/VChildWindow.cpp index ca854ea..e71316d 100644 --- a/VortexEditor/GUI/VChildWindow.cpp +++ b/VortexEditor/GUI/VChildWindow.cpp @@ -1,173 +1,174 @@ -#include "VChildWindow.h" - -// Vortex Engine includes -#include "EditorConfig.h" - -// Editor includes -#include "VortexEditor.h" - -#include -#include - -#include "resource.h" - -using namespace std; - -WNDCLASS VChildWindow::m_wc = {0}; - -VChildWindow::VChildWindow() : - VWindow() -{ -} - -VChildWindow::VChildWindow(HINSTANCE hinstance, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, - void *callbackArg) : - VChildWindow() -{ - init(hinstance, title, backcol, width, height, callbackArg); -} - -VChildWindow::~VChildWindow() -{ - cleanup(); -} - -void VChildWindow::init(HINSTANCE hInstance, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, - void *callbackArg) -{ - // store callback - m_callbackArg = callbackArg; - - // register a window class for the window if not done yet - registerWindowClass(hInstance, backcol); - - // get desktop rect so we can center the window - RECT desktop; - GetClientRect(GetDesktopWindow(), &desktop); - - // create the window - m_hwnd = CreateWindow(WC_VCHILDWINDOW, title.c_str(), - WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, - (desktop.right / 2) - (width / 2), (desktop.bottom / 2) - (height / 2), - width, height, nullptr, nullptr, hInstance, nullptr); - if (!m_hwnd) { - MessageBox(nullptr, "Failed to open window", "Error", 0); - throw exception("idk"); - } - - // set 'this' in the user data area of the class so that the static callback - // routine can access the object - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); -} - -void VChildWindow::cleanup() -{ -} - -bool VChildWindow::process(MSG &msg) -{ - return IsDialogMessage(m_hwnd, &msg); -} - -void VChildWindow::create() -{ -} - -void VChildWindow::paint() -{ - PAINTSTRUCT ps; - HDC hdc = BeginPaint(m_hwnd, &ps); - EndPaint(m_hwnd, &ps); -} - -void VChildWindow::pressButton(WPARAM wParam, LPARAM lParam) -{ -} - -void VChildWindow::releaseButton(WPARAM wParam, LPARAM lParam) -{ -} - -void VChildWindow::setVisible(bool visible) -{ - VWindow::setVisible(visible); - if (!visible && m_closeCallback) { - m_closeCallback(m_callbackArg, this); - } -} - -void VChildWindow::setCloseCallback(VWindowCallback callback) -{ - m_closeCallback = callback; -} - -LRESULT CALLBACK VChildWindow::window_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - VChildWindow *pWindow = (VChildWindow *)GetWindowLongPtr(hWnd, GWLP_USERDATA); - if (!pWindow) { - return DefWindowProc(hWnd, uMsg, wParam, lParam); - } - switch (uMsg) { - case WM_VSCROLL: - break; - case WM_LBUTTONDOWN: - pWindow->pressButton(wParam, lParam); - break; - case WM_LBUTTONUP: - pWindow->releaseButton(wParam, lParam); - break; - case WM_CREATE: - pWindow->create(); - break; - case WM_KILLFOCUS: - pWindow->loseFocus(wParam, lParam); - break; - case WM_PAINT: - pWindow->paint(); - return 0; - case WM_CTLCOLORSTATIC: - // for static controls we pass the hwnd of the window itself - return pWindow->controlColor(wParam, lParam); - case WM_COMMAND: - pWindow->command(wParam, lParam); - break; - case WM_DEVICECHANGE: - if (!pWindow->m_deviceCallback) { - break; - } - // Output some messages to the window. - if (wParam == DBT_DEVICEARRIVAL) { - pWindow->m_deviceCallback(pWindow->m_callbackArg, (DEV_BROADCAST_HDR *)lParam, true); - } else if (wParam == DBT_DEVICEREMOVECOMPLETE) { - pWindow->m_deviceCallback(pWindow->m_callbackArg, (DEV_BROADCAST_HDR *)lParam, false); - } - // should we handle DBT_DEVNODES_CHANGED ? - break; - case WM_CLOSE: - pWindow->setVisible(false); - return 0; - case WM_QUIT: - case WM_DESTROY: - return 0; - default: - break; - } - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - -void VChildWindow::registerWindowClass(HINSTANCE hInstance, COLORREF backcol) -{ - if (m_wc.lpfnWndProc == VChildWindow::window_proc) { - // alredy registered - return; - } - // class registration - m_wc.lpfnWndProc = VChildWindow::window_proc; - m_wc.hInstance = hInstance; - m_wc.lpszClassName = WC_VCHILDWINDOW; - m_wc.hbrBackground = CreateSolidBrush(backcol); - //m_wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); - RegisterClass(&m_wc); +#include "VChildWindow.h" + +// Vortex Engine includes +#include "EditorConfig.h" + +// Editor includes +#include "VortexEditor.h" + +#include +#include + +#include "resource.h" + +using namespace std; + +WNDCLASS VChildWindow::m_wc = {0}; + +VChildWindow::VChildWindow() : + VWindow(), + m_closeCallback(nullptr) +{ +} + +VChildWindow::VChildWindow(HINSTANCE hinstance, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, + void *callbackArg) : + VChildWindow() +{ + init(hinstance, title, backcol, width, height, callbackArg); +} + +VChildWindow::~VChildWindow() +{ + cleanup(); +} + +void VChildWindow::init(HINSTANCE hInstance, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, + void *callbackArg) +{ + // store callback + m_callbackArg = callbackArg; + + // register a window class for the window if not done yet + registerWindowClass(hInstance, backcol); + + // get desktop rect so we can center the window + RECT desktop; + GetClientRect(GetDesktopWindow(), &desktop); + + // create the window + m_hwnd = CreateWindow(WC_VCHILDWINDOW, title.c_str(), + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, + (desktop.right / 2) - (width / 2), (desktop.bottom / 2) - (height / 2), + width, height, nullptr, nullptr, hInstance, nullptr); + if (!m_hwnd) { + MessageBox(nullptr, "Failed to open window", "Error", 0); + throw exception("idk"); + } + + // set 'this' in the user data area of the class so that the static callback + // routine can access the object + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); +} + +void VChildWindow::cleanup() +{ +} + +bool VChildWindow::process(MSG &msg) +{ + return IsDialogMessage(m_hwnd, &msg); +} + +void VChildWindow::create() +{ +} + +void VChildWindow::paint() +{ + PAINTSTRUCT ps; + HDC hdc = BeginPaint(m_hwnd, &ps); + EndPaint(m_hwnd, &ps); +} + +void VChildWindow::pressButton(WPARAM wParam, LPARAM lParam) +{ +} + +void VChildWindow::releaseButton(WPARAM wParam, LPARAM lParam) +{ +} + +void VChildWindow::setVisible(bool visible) +{ + VWindow::setVisible(visible); + if (!visible && m_closeCallback) { + m_closeCallback(m_callbackArg, this); + } +} + +void VChildWindow::setCloseCallback(VWindowCallback callback) +{ + m_closeCallback = callback; +} + +LRESULT CALLBACK VChildWindow::window_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + VChildWindow *pWindow = (VChildWindow *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + if (!pWindow) { + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } + switch (uMsg) { + case WM_VSCROLL: + break; + case WM_LBUTTONDOWN: + pWindow->pressButton(wParam, lParam); + break; + case WM_LBUTTONUP: + pWindow->releaseButton(wParam, lParam); + break; + case WM_CREATE: + pWindow->create(); + break; + case WM_KILLFOCUS: + pWindow->loseFocus(wParam, lParam); + break; + case WM_PAINT: + pWindow->paint(); + return 0; + case WM_CTLCOLORSTATIC: + // for static controls we pass the hwnd of the window itself + return pWindow->controlColor(wParam, lParam); + case WM_COMMAND: + pWindow->command(wParam, lParam); + break; + case WM_DEVICECHANGE: + if (!pWindow->m_deviceCallback) { + break; + } + // Output some messages to the window. + if (wParam == DBT_DEVICEARRIVAL) { + pWindow->m_deviceCallback(pWindow->m_callbackArg, (DEV_BROADCAST_HDR *)lParam, true); + } else if (wParam == DBT_DEVICEREMOVECOMPLETE) { + pWindow->m_deviceCallback(pWindow->m_callbackArg, (DEV_BROADCAST_HDR *)lParam, false); + } + // should we handle DBT_DEVNODES_CHANGED ? + break; + case WM_CLOSE: + pWindow->setVisible(false); + return 0; + case WM_QUIT: + case WM_DESTROY: + return 0; + default: + break; + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +void VChildWindow::registerWindowClass(HINSTANCE hInstance, COLORREF backcol) +{ + if (m_wc.lpfnWndProc == VChildWindow::window_proc) { + // alredy registered + return; + } + // class registration + m_wc.lpfnWndProc = VChildWindow::window_proc; + m_wc.hInstance = hInstance; + m_wc.lpszClassName = WC_VCHILDWINDOW; + m_wc.hbrBackground = CreateSolidBrush(backcol); + //m_wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); + RegisterClass(&m_wc); } \ No newline at end of file diff --git a/VortexEditor/GUI/VColorSelect.cpp b/VortexEditor/GUI/VColorSelect.cpp index 1c845d9..54c6441 100644 --- a/VortexEditor/GUI/VColorSelect.cpp +++ b/VortexEditor/GUI/VColorSelect.cpp @@ -1,347 +1,347 @@ -#include "VColorSelect.h" - -// Windows includes -#include -#include - -// Vortex Engine includes -#include "EditorConfig.h" -#include "Colors/ColorTypes.h" - -// Editor includes -#include "VortexEditor.h" - -using namespace std; - -#define WC_COLOR_SELECT "VColorSelect" - -WNDCLASS VColorSelect::m_wc = {0}; - -VColorSelect::VColorSelect() : - VWindow(), - m_callback(nullptr), - m_color(0), - m_active(false), - m_selected(false), - m_selectable(true) -{ -} - -VColorSelect::VColorSelect(HINSTANCE hInstance, VWindow &parent, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, - uintptr_t menuID, VColorSelectCallback callback) : - VColorSelect() -{ - init(hInstance, parent, title, backcol, width, height, x, y, menuID, callback); -} - -VColorSelect::~VColorSelect() -{ - cleanup(); -} - -void VColorSelect::init(HINSTANCE hInstance, VWindow &parent, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, - uintptr_t menuID, VColorSelectCallback callback) -{ - // store callback and menu id - m_callback = callback; - m_backColor = backcol; - m_foreColor = RGB(0xD0, 0xD0, 0xD0); - - // register window class if it hasn't been registered yet - registerWindowClass(hInstance, backcol); - - if (!menuID) { - menuID = nextMenuID++; - } - - if (!parent.addChild(menuID, this)) { - return; - } - - // create the window - m_hwnd = CreateWindow(WC_COLOR_SELECT, title.c_str(), - WS_CHILD | WS_OVERLAPPED | WS_VISIBLE | WS_TABSTOP, - x, y, width, height, parent.hwnd(), (HMENU)menuID, nullptr, nullptr); - if (!m_hwnd) { - MessageBox(nullptr, "Failed to open window", "Error", 0); - throw exception("idk"); - } - - // set 'this' in the user data area of the class so that the static callback - // routine can access the object - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); - - m_colorLabel.init(hInstance, parent, title, backcol, 100, 24, x + width + 6, y + (height / 4), 0, nullptr); -} - -void VColorSelect::cleanup() -{ -} - -void VColorSelect::create() -{ -} - -static HBRUSH getBrushCol(DWORD rgbcol) -{ - static std::map m_brushmap; - HBRUSH br; - COLORREF col = RGB((rgbcol >> 16) & 0xFF, (rgbcol >> 8) & 0xFF, rgbcol & 0xFF); - if (m_brushmap.find(col) == m_brushmap.end()) { - br = CreateSolidBrush(col); - m_brushmap[col] = br; - } - br = m_brushmap[col]; - return br; -} - -void VColorSelect::paint() -{ - PAINTSTRUCT paintStruct; - memset(&paintStruct, 0, sizeof(paintStruct)); - HDC hdc = BeginPaint(m_hwnd, &paintStruct); - - RECT rect; - GetClientRect(m_hwnd, &rect); - - uint32_t width = rect.right - rect.left; - uint32_t height = rect.bottom - rect.top; - - // create a backbuffer and select it - HDC backbuffDC = CreateCompatibleDC(hdc); - HBITMAP backbuffer = CreateCompatibleBitmap(hdc, width, height); - SelectObject(backbuffDC, backbuffer); - - COLORREF frontCol = getColor(); - COLORREF borderCol; - - if (m_selected) { - borderCol = 0xFFFFFF; // white - } else { - if (m_active) { - // border is bright if a color is selected, or dark if 'blank' (black) - borderCol = frontCol ? 0xAAAAAA : 0x606060; - } else { - // force the frontcol to 0 if not active, and red border - borderCol = 0xFF0000; - frontCol = 0; - } - } - FillRect(backbuffDC, &rect, getBrushCol(borderCol)); - -#define BORDER_WIDTH 1 - rect.left += BORDER_WIDTH; - rect.top += BORDER_WIDTH; - rect.right -= BORDER_WIDTH; - rect.bottom -= BORDER_WIDTH; - FillRect(backbuffDC, &rect, getBrushCol(frontCol)); - - BitBlt(hdc, 0, 0, width, height, backbuffDC, 0, 0, SRCCOPY); - - DeleteObject(backbuffer); - DeleteDC(backbuffDC); - - EndPaint(m_hwnd, &paintStruct); -} - -void VColorSelect::command(WPARAM wParam, LPARAM lParam) -{ -} - -void VColorSelect::pressButton(WPARAM wParam, LPARAM lParam) -{ - if (m_selectable) { - setSelected(!m_selected); - if (m_selected && !m_active) { - // if the box was inactive and just selected, activate it - setActive(true); - clear(); - } - } - SelectEvent sevent = SELECT_LEFT_CLICK; - if (wParam & MK_CONTROL) { - sevent = SELECT_CTRL_LEFT_CLICK; - } - if (wParam & MK_SHIFT) { - sevent = SELECT_SHIFT_LEFT_CLICK; - } - if (m_callback) { - m_callback(m_callbackArg, this, sevent); - } -} - -void VColorSelect::releaseButton(WPARAM wParam, LPARAM lParam) -{ -} - -// window message for right button press, only exists here -void VColorSelect::rightButtonPress() -{ - if (m_selectable) { - if (m_selected) { - setSelected(false); - } else { - if (m_color == 0) { - setActive(false); - } - clear(); - } - } - if (m_callback) { - m_callback(m_callbackArg, this, SELECT_RIGHT_CLICK); - } -} - -void VColorSelect::clear() -{ - setColor(0); -} - -void VColorSelect::setColor(uint32_t col) -{ - m_color = col; - m_colorLabel.setText(getColorName()); - redraw(); -} - -string VColorSelect::getColorName() const -{ - if (m_color == 0) { - return "blank"; - } - char colText[64] = { 0 }; - snprintf(colText, sizeof(colText), "#%02X%02X%02X", - (m_color >> 16) & 0xFF, (m_color >> 8) & 0xFF, m_color & 0xFF); - return colText; -} - -void VColorSelect::setColor(std::string name) -{ - if (name == "blank") { - setColor(0); - return; - } - // either the start of string, or string + 1 if the first - // letter is a hashtag/pound character - const char *hexStr = name.c_str() + (name[0] == '#'); - setColor(strtoul(hexStr, NULL, 16)); -} - -void VColorSelect::setFlippedColor(uint32_t col) -{ - setColor(((col >> 16) & 0xFF) | (col & 0xFF00) | ((col << 16) & 0xFF0000)); -} - -uint32_t VColorSelect::getColor() const -{ - return m_color; -} - -uint32_t VColorSelect::getFlippedColor() const -{ - return ((m_color >> 16) & 0xFF) | (m_color & 0xFF00) | ((m_color << 16) & 0xFF0000); -} - -bool VColorSelect::isActive() const -{ - return m_active; -} - -void VColorSelect::setActive(bool active) -{ - m_active = active; - m_colorLabel.setVisible(active); - if (!m_active) { - setSelected(false); - } -} - -bool VColorSelect::isSelected() const -{ - return m_selected; -} - -void VColorSelect::setSelected(bool selected) -{ - m_selected = selected; - if (m_selected) { - m_colorLabel.setForeColor(0xFFFFFF); - } else { - m_colorLabel.setForeColor(0xAAAAAA); - } -} - -void VColorSelect::setLabelEnabled(bool enabled) -{ - m_colorLabel.setVisible(enabled); - m_colorLabel.setEnabled(enabled); -} - -void VColorSelect::setSelectable(bool selectable) -{ - m_selectable = selectable; - if (!m_selectable) { - setSelected(false); - } -} - -LRESULT CALLBACK VColorSelect::window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - VColorSelect *pColorSelect = (VColorSelect *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (!pColorSelect) { - return DefWindowProc(hwnd, uMsg, wParam, lParam); - } - switch (uMsg) { - case WM_VSCROLL: - break; - case WM_LBUTTONDOWN: - pColorSelect->pressButton(wParam, lParam); - break; - case WM_LBUTTONUP: - pColorSelect->releaseButton(wParam, lParam); - break; - case WM_RBUTTONUP: - pColorSelect->rightButtonPress(); - break; - case WM_KEYDOWN: - // TODO: implement key control of color select? - break; - case WM_CTLCOLORSTATIC: - return (INT_PTR)pColorSelect->m_wc.hbrBackground; - case WM_CREATE: - pColorSelect->create(); - break; - case WM_PAINT: - pColorSelect->paint(); - return 0; - case WM_ERASEBKGND: - return 1; - case WM_COMMAND: - pColorSelect->command(wParam, lParam); - break; - case WM_DESTROY: - pColorSelect->cleanup(); - break; - default: - break; - } - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -void VColorSelect::registerWindowClass(HINSTANCE hInstance, COLORREF backcol) -{ - if (m_wc.lpfnWndProc == VColorSelect::window_proc) { - // alredy registered - return; - } - // class registration - m_wc.lpfnWndProc = VColorSelect::window_proc; - m_wc.hInstance = hInstance; - m_wc.hbrBackground = CreateSolidBrush(backcol); - m_wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW; - m_wc.hCursor = LoadCursor(NULL, IDC_ARROW); - m_wc.lpszClassName = WC_COLOR_SELECT; - RegisterClass(&m_wc); -} +#include "VColorSelect.h" + +// Windows includes +#include +#include + +// Vortex Engine includes +#include "EditorConfig.h" +#include "Colors/ColorTypes.h" + +// Editor includes +#include "VortexEditor.h" + +using namespace std; + +#define WC_COLOR_SELECT "VColorSelect" + +WNDCLASS VColorSelect::m_wc = {0}; + +VColorSelect::VColorSelect() : + VWindow(), + m_callback(nullptr), + m_color(0), + m_active(false), + m_selected(false), + m_selectable(true) +{ +} + +VColorSelect::VColorSelect(HINSTANCE hInstance, VWindow &parent, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uintptr_t menuID, VColorSelectCallback callback) : + VColorSelect() +{ + init(hInstance, parent, title, backcol, width, height, x, y, menuID, callback); +} + +VColorSelect::~VColorSelect() +{ + cleanup(); +} + +void VColorSelect::init(HINSTANCE hInstance, VWindow &parent, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uintptr_t menuID, VColorSelectCallback callback) +{ + // store callback and menu id + m_callback = callback; + m_backColor = backcol; + m_foreColor = RGB(0xD0, 0xD0, 0xD0); + + // register window class if it hasn't been registered yet + registerWindowClass(hInstance, backcol); + + if (!menuID) { + menuID = nextMenuID++; + } + + if (!parent.addChild(menuID, this)) { + return; + } + + // create the window + m_hwnd = CreateWindow(WC_COLOR_SELECT, title.c_str(), + WS_CHILD | WS_OVERLAPPED | WS_VISIBLE | WS_TABSTOP, + x, y, width, height, parent.hwnd(), (HMENU)menuID, nullptr, nullptr); + if (!m_hwnd) { + MessageBox(nullptr, "Failed to open window", "Error", 0); + throw exception("idk"); + } + + // set 'this' in the user data area of the class so that the static callback + // routine can access the object + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); + + m_colorLabel.init(hInstance, parent, title, backcol, 100, 24, x + width + 6, y + (height / 4), 0, nullptr); +} + +void VColorSelect::cleanup() +{ +} + +void VColorSelect::create() +{ +} + +static HBRUSH getBrushCol(DWORD rgbcol) +{ + static std::map m_brushmap; + HBRUSH br; + COLORREF col = RGB((rgbcol >> 16) & 0xFF, (rgbcol >> 8) & 0xFF, rgbcol & 0xFF); + if (m_brushmap.find(col) == m_brushmap.end()) { + br = CreateSolidBrush(col); + m_brushmap[col] = br; + } + br = m_brushmap[col]; + return br; +} + +void VColorSelect::paint() +{ + PAINTSTRUCT paintStruct; + memset(&paintStruct, 0, sizeof(paintStruct)); + HDC hdc = BeginPaint(m_hwnd, &paintStruct); + + RECT rect; + GetClientRect(m_hwnd, &rect); + + uint32_t width = rect.right - rect.left; + uint32_t height = rect.bottom - rect.top; + + // create a backbuffer and select it + HDC backbuffDC = CreateCompatibleDC(hdc); + HBITMAP backbuffer = CreateCompatibleBitmap(hdc, width, height); + SelectObject(backbuffDC, backbuffer); + + COLORREF frontCol = getColor(); + COLORREF borderCol; + + if (m_selected) { + borderCol = 0xFFFFFF; // white + } else { + if (m_active) { + // border is bright if a color is selected, or dark if 'blank' (black) + borderCol = frontCol ? 0xAAAAAA : 0x606060; + } else { + // force the frontcol to 0 if not active, and red border + borderCol = 0xFF0000; + frontCol = 0; + } + } + FillRect(backbuffDC, &rect, getBrushCol(borderCol)); + +#define BORDER_WIDTH 1 + rect.left += BORDER_WIDTH; + rect.top += BORDER_WIDTH; + rect.right -= BORDER_WIDTH; + rect.bottom -= BORDER_WIDTH; + FillRect(backbuffDC, &rect, getBrushCol(frontCol)); + + BitBlt(hdc, 0, 0, width, height, backbuffDC, 0, 0, SRCCOPY); + + DeleteObject(backbuffer); + DeleteDC(backbuffDC); + + EndPaint(m_hwnd, &paintStruct); +} + +void VColorSelect::command(WPARAM wParam, LPARAM lParam) +{ +} + +void VColorSelect::pressButton(WPARAM wParam, LPARAM lParam) +{ + if (m_selectable) { + setSelected(!m_selected); + if (m_selected && !m_active) { + // if the box was inactive and just selected, activate it + setActive(true); + clear(); + } + } + SelectEvent sevent = SELECT_LEFT_CLICK; + if (wParam & MK_CONTROL) { + sevent = SELECT_CTRL_LEFT_CLICK; + } + if (wParam & MK_SHIFT) { + sevent = SELECT_SHIFT_LEFT_CLICK; + } + if (m_callback) { + m_callback(m_callbackArg, this, sevent); + } +} + +void VColorSelect::releaseButton(WPARAM wParam, LPARAM lParam) +{ +} + +// window message for right button press, only exists here +void VColorSelect::rightButtonPress() +{ + if (m_selectable) { + if (m_selected) { + setSelected(false); + } else { + if (m_color == 0) { + setActive(false); + } + clear(); + } + } + if (m_callback) { + m_callback(m_callbackArg, this, SELECT_RIGHT_CLICK); + } +} + +void VColorSelect::clear() +{ + setColor(0); +} + +void VColorSelect::setColor(uint32_t col) +{ + m_color = col; + m_colorLabel.setText(getColorName()); + redraw(); +} + +string VColorSelect::getColorName() const +{ + if (m_color == 0) { + return "blank"; + } + char colText[64] = { 0 }; + snprintf(colText, sizeof(colText), "#%02X%02X%02X", + (m_color >> 16) & 0xFF, (m_color >> 8) & 0xFF, m_color & 0xFF); + return colText; +} + +void VColorSelect::setColor(std::string name) +{ + if (name == "blank") { + setColor(0); + return; + } + // either the start of string, or string + 1 if the first + // letter is a hashtag/pound character + const char *hexStr = name.c_str() + (name[0] == '#'); + setColor(strtoul(hexStr, NULL, 16)); +} + +void VColorSelect::setFlippedColor(uint32_t col) +{ + setColor(((col >> 16) & 0xFF) | (col & 0xFF00) | ((col << 16) & 0xFF0000)); +} + +uint32_t VColorSelect::getColor() const +{ + return m_color; +} + +uint32_t VColorSelect::getFlippedColor() const +{ + return ((m_color >> 16) & 0xFF) | (m_color & 0xFF00) | ((m_color << 16) & 0xFF0000); +} + +bool VColorSelect::isActive() const +{ + return m_active; +} + +void VColorSelect::setActive(bool active) +{ + m_active = active; + m_colorLabel.setVisible(active); + if (!m_active) { + setSelected(false); + } +} + +bool VColorSelect::isSelected() const +{ + return m_selected; +} + +void VColorSelect::setSelected(bool selected) +{ + m_selected = selected; + if (m_selected) { + m_colorLabel.setForeColor(0xFFFFFF); + } else { + m_colorLabel.setForeColor(0xAAAAAA); + } +} + +void VColorSelect::setLabelEnabled(bool enabled) +{ + m_colorLabel.setVisible(enabled); + m_colorLabel.setEnabled(enabled); +} + +void VColorSelect::setSelectable(bool selectable) +{ + m_selectable = selectable; + if (!m_selectable) { + setSelected(false); + } +} + +LRESULT CALLBACK VColorSelect::window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + VColorSelect *pColorSelect = (VColorSelect *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (!pColorSelect) { + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + switch (uMsg) { + case WM_VSCROLL: + break; + case WM_LBUTTONDOWN: + pColorSelect->pressButton(wParam, lParam); + break; + case WM_LBUTTONUP: + pColorSelect->releaseButton(wParam, lParam); + break; + case WM_RBUTTONUP: + pColorSelect->rightButtonPress(); + break; + case WM_KEYDOWN: + // TODO: implement key control of color select? + break; + case WM_CTLCOLORSTATIC: + return (INT_PTR)pColorSelect->m_wc.hbrBackground; + case WM_CREATE: + pColorSelect->create(); + break; + case WM_PAINT: + pColorSelect->paint(); + return 0; + case WM_ERASEBKGND: + return 1; + case WM_COMMAND: + pColorSelect->command(wParam, lParam); + break; + case WM_DESTROY: + pColorSelect->cleanup(); + break; + default: + break; + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +void VColorSelect::registerWindowClass(HINSTANCE hInstance, COLORREF backcol) +{ + if (m_wc.lpfnWndProc == VColorSelect::window_proc) { + // alredy registered + return; + } + // class registration + m_wc.lpfnWndProc = VColorSelect::window_proc; + m_wc.hInstance = hInstance; + m_wc.hbrBackground = CreateSolidBrush(backcol); + m_wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW; + m_wc.hCursor = LoadCursor(NULL, IDC_ARROW); + m_wc.lpszClassName = WC_COLOR_SELECT; + RegisterClass(&m_wc); +} diff --git a/VortexEditor/GUI/VPatternListBox.cpp b/VortexEditor/GUI/VPatternListBox.cpp new file mode 100644 index 0000000..7986ebb --- /dev/null +++ b/VortexEditor/GUI/VPatternListBox.cpp @@ -0,0 +1,102 @@ +#include "VPatternListBox.h" +#include +#include + +#define WC_PATTERN_LIST_BOX "VPatternListBox" + +// Constructor with initialization list +VPatternListBox::VPatternListBox() + : VWindow(), m_scrollPos(0), m_callback(nullptr) {} + +// Delegate constructor +VPatternListBox::VPatternListBox(HINSTANCE hInstance, VWindow &parent, uint32_t width, uint32_t height, + uint32_t x, uint32_t y, uintptr_t menuID, VWindowCallback callback) + : VPatternListBox() { + init(hInstance, parent, width, height, x, y, menuID, callback); +} + +// Destructor +VPatternListBox::~VPatternListBox() { + cleanup(); +} + +// Initialize the VPatternListBox +void VPatternListBox::init(HINSTANCE hInstance, VWindow &parent, uint32_t width, uint32_t height, + uint32_t x, uint32_t y, uintptr_t menuID, VWindowCallback callback) { + m_callback = callback; + + m_hwnd = CreateWindow(WC_PATTERN_LIST_BOX, "", WS_CHILD | WS_VISIBLE | WS_VSCROLL, + x, y, width, height, parent.hwnd(), (HMENU)menuID, hInstance, nullptr); + if (!m_hwnd) { + MessageBox(nullptr, "Failed to create pattern list box", "Error", MB_OK); + return; + } + + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, reinterpret_cast(this)); +} + +// Clean up resources +void VPatternListBox::cleanup() { + // Cleanup logic here +} + +// Handle creation logic +void VPatternListBox::create() { + // Additional setup on creation +} + +// Handle painting of the list box +void VPatternListBox::paint() { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(m_hwnd, &ps); + + drawPatternStrips(hdc); + + EndPaint(m_hwnd, &ps); +} + +// Add a new pattern strip to the list +void VPatternListBox::addPatternStrip(std::shared_ptr patternStrip) { + m_patternStrips.push_back(patternStrip); + // Update view +} + +// Remove a pattern strip from the list +void VPatternListBox::removePatternStrip(size_t index) { + if (index < m_patternStrips.size()) { + m_patternStrips.erase(m_patternStrips.begin() + index); + // Update view + } +} + +// Clear all pattern strips +void VPatternListBox::clearPatternStrips() { + m_patternStrips.clear(); + // Update view +} + +// Draw all pattern strips within the list box +void VPatternListBox::drawPatternStrips(HDC hdc) { + int yOffset = 0; + for (auto &strip : m_patternStrips) { + if (yOffset - m_scrollPos >= -40 && yOffset - m_scrollPos < m_height) { + strip->draw(hdc, 0, yOffset - m_scrollPos, 200, 32); + } + yOffset += 40; + } +} + +// Command handling (placeholder for future logic) +void VPatternListBox::command(WPARAM wParam, LPARAM lParam) { + // Implement as needed +} + +// Handle button press events (placeholder for future logic) +void VPatternListBox::pressButton(WPARAM wParam, LPARAM lParam) { + // Implement as needed +} + +// Handle button release events (placeholder for future logic) +void VPatternListBox::releaseButton(WPARAM wParam, LPARAM lParam) { + // Implement as needed +} diff --git a/VortexEditor/GUI/VPatternListBox.h b/VortexEditor/GUI/VPatternListBox.h new file mode 100644 index 0000000..4409e77 --- /dev/null +++ b/VortexEditor/GUI/VPatternListBox.h @@ -0,0 +1,37 @@ +#pragma once + +#include "VWindow.h" +#include "VPatternStrip.h" // Ensure this includes the definition of VPatternStrip +#include +#include + +class VPatternListBox : public VWindow { +public: + VPatternListBox(); + VPatternListBox(HINSTANCE hInstance, VWindow& parent, uint32_t width, uint32_t height, uint32_t x, uint32_t y, uintptr_t menuID, VWindowCallback callback); + virtual ~VPatternListBox(); + + void init(HINSTANCE hInstance, VWindow& parent, uint32_t width, uint32_t height, uint32_t x, uint32_t y, uintptr_t menuID, VWindowCallback callback); + virtual void cleanup() override; + + // Override these methods for custom behavior + virtual void create() override; + virtual void paint() override; + virtual void command(WPARAM wParam, LPARAM lParam) override; + virtual void pressButton(WPARAM wParam, LPARAM lParam) override; + virtual void releaseButton(WPARAM wParam, LPARAM lParam) override; + + // Methods to manage pattern strips + void addPatternStrip(std::shared_ptr patternStrip); + void removePatternStrip(size_t index); + void clearPatternStrips(); + +protected: + std::vector> m_patternStrips; // Container for pattern strips + uint32_t m_scrollPos; + uint32_t m_height; + +private: + VWindowCallback m_callback; + void drawPatternStrips(HDC hdc); // Helper function to draw pattern strips +}; diff --git a/VortexEditor/GUI/VPatternStrip.cpp b/VortexEditor/GUI/VPatternStrip.cpp new file mode 100644 index 0000000..c0aed2c --- /dev/null +++ b/VortexEditor/GUI/VPatternStrip.cpp @@ -0,0 +1,476 @@ +#include "VPatternStrip.h" + +// Windows includes +#include +#include + +// Vortex Engine includes +#include "EditorConfig.h" +#include "Colors/ColorTypes.h" + +// Editor includes +#include "VortexEditor.h" + +using namespace std; + +#pragma comment(lib, "Msimg32.lib"); + +#define WC_PATTERN_STRIP "VPatternStrip" +#define LINE_SIZE 2 + +WNDCLASS VPatternStrip::m_wc = { 0 }; + +VPatternStrip::VPatternStrip() : + VWindow(), + m_vortex(), + m_runThread(nullptr), + m_stripLabel(), + m_callback(nullptr), + m_active(true), + m_selected(false), + m_selectable(true), + m_colorSequence(), + m_lineWidth(1), + m_numSlices(0), + m_backbufferDC(nullptr), + m_backbuffer(nullptr), + m_oldBitmap(nullptr), + m_backbufferWidth(0), + m_backbufferHeight(0), + m_scrollOffset(0) +{ +} + +VPatternStrip::VPatternStrip(HINSTANCE hInstance, VWindow &parent, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uint32_t lineWidth, const json &js, uintptr_t menuID, VPatternStripCallback callback) : + VPatternStrip() +{ + init(hInstance, parent, title, backcol, width, height, x, y, lineWidth, js, menuID, callback); +} + +VPatternStrip::~VPatternStrip() +{ + setActive(false); + cleanup(); +} + +void VPatternStrip::init(HINSTANCE hInstance, VWindow &parent, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uint32_t lineWidth, const json &js, uintptr_t menuID, VPatternStripCallback callback) +{ + // store callback and menu id + m_callback = callback; + m_backColor = backcol; + m_foreColor = RGB(0xD0, 0xD0, 0xD0); + m_numSlices = width / LINE_SIZE; + m_lineWidth = lineWidth; + + // register window class if it hasn't been registered yet + registerWindowClass(hInstance, backcol); + + if (!menuID) { + menuID = nextMenuID++; + } + + if (!parent.addChild(menuID, this)) { + return; + } + + // create the window + m_hwnd = CreateWindow(WC_PATTERN_STRIP, title.c_str(), + WS_CHILD | WS_OVERLAPPED | WS_VISIBLE | WS_TABSTOP, + x, y, width, height, parent.hwnd(), (HMENU)menuID, nullptr, nullptr); + if (!m_hwnd) { + MessageBox(nullptr, "Failed to open window", "Error", 0); + throw exception("idk"); + } + + // set 'this' in the user data area of the class so that the static callback + // routine can access the object + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); + + m_stripLabel.init(hInstance, parent, "", backcol, 400, 24, x + width + 6, y + (height / 4), 0, nullptr); + //m_colorLabel.setVisible(false); + + // load the communty modes into the local vortex instance for the browser window + m_vortex.init(); + m_vortex.setLedCount(1); + m_vortex.setTickrate(40); + //m_vortex.setInstantTimestep(true); + + HDC hdc = GetDC(m_hwnd); + createBackBuffer(hdc, width, height); + + loadJson(js); +} + +void VPatternStrip::loadJson(const json &js) +{ + setActive(false); + if (js.contains("modeData")) { + if (js.contains("name")) { + m_stripLabel.setText(js["name"]); + } + m_vortex.engine().modes().clearModes(); + m_vortex.loadModeFromJson(js["modeData"]); + } + + m_vortex.setInstantTimestep(true); + for (uint32_t i = 0; i < m_backbufferWidth; ++i) { + m_vortex.engine().tick(); + RGBColor col = m_vortex.engine().leds().getLed(0); + m_colorSequence.push_back(col); + if (m_colorSequence.size() > m_numSlices) { + m_colorSequence.pop_front(); + } + // Update scroll offset for scrolling animation + m_scrollOffset = (m_scrollOffset + 1) % m_numSlices; + } + m_vortex.setInstantTimestep(false); + +} + +DWORD __stdcall VPatternStrip::runThread(void *arg) +{ + VPatternStrip *strip = (VPatternStrip *)arg; + while (strip->m_active) { + strip->run(); + } + return 0; +} + +void VPatternStrip::cleanup() +{ + destroyBackBuffer(); +} + +void VPatternStrip::run() +{ + m_vortex.engine().tick(); + RGBColor col = m_vortex.engine().leds().getLed(0); + m_colorSequence.push_back(col); + if (m_colorSequence.size() > m_numSlices) { + m_colorSequence.pop_front(); + } + + // Update scroll offset for scrolling animation + m_scrollOffset = (m_scrollOffset + 1) % m_numSlices; + + // Trigger window update for animation + InvalidateRect(m_hwnd, nullptr, FALSE); +} + +void VPatternStrip::create() +{ +} + +static HBRUSH getBrushCol(DWORD rgbcol) +{ + static std::map m_brushmap; + HBRUSH br; + COLORREF col = RGB((rgbcol >> 16) & 0xFF, (rgbcol >> 8) & 0xFF, rgbcol & 0xFF); + if (m_brushmap.find(col) == m_brushmap.end()) { + br = CreateSolidBrush(col); + m_brushmap[col] = br; + } + br = m_brushmap[col]; + return br; +} + +void VPatternStrip::paint() +{ + PAINTSTRUCT ps; + HDC hdc = BeginPaint(m_hwnd, &ps); + // Copy the backbuffer to the screen + BitBlt(hdc, 0, 0, m_backbufferWidth, m_backbufferHeight, m_backbufferDC, 0, 0, SRCCOPY); + EndPaint(m_hwnd, &ps); + // draw backbuffer + drawToBackBuffer(); +} + +void VPatternStrip::drawToBackBuffer() { + if (!m_backbufferDC) { + return; + } + + RECT rect; + GetClientRect(m_hwnd, &rect); + uint32_t width = rect.right - rect.left; + uint32_t height = rect.bottom - rect.top; + + // Fill the backbuffer background + FillRect(m_backbufferDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); + + // Calculate the starting position for drawing lines + uint32_t numLines = m_colorSequence.size(); + int startX = width - (numLines * m_lineWidth) % width; + RECT lineRect; + lineRect.top = rect.top; + lineRect.bottom = rect.bottom; + + // Iterate through each color in the sequence and draw the corresponding line + for (int i = 0; i < numLines; ++i) { + const auto& col = m_colorSequence[i]; + if (col.empty()) { + continue; + } + + HBRUSH brush = getBrushCol(col.raw()); + if (!brush) { + continue; + } + + int xPos = (startX + (i * m_lineWidth)) % width; + lineRect.left = xPos; + lineRect.right = xPos + m_lineWidth; + + FillRect(m_backbufferDC, &lineRect, brush); + } +} + +void VPatternStrip::command(WPARAM wParam, LPARAM lParam) +{ +} + +void VPatternStrip::pressButton(WPARAM wParam, LPARAM lParam) +{ + g_pEditor->addMode(nullptr, m_vortex.engine().modes().curMode()); + //m_vortex.setTickrate(100); + //if (m_selectable) { + // setSelected(!m_selected); + // if (m_selected && !m_active) { + // // if the box was inactive and just selected, activate it + // setActive(true); + // clear(); + // } + //} + //SelectEvent sevent = SELECT_LEFT_CLICK; + //if (wParam & MK_CONTROL) { + // sevent = SELECT_CTRL_LEFT_CLICK; + //} + //if (wParam & MK_SHIFT) { + // sevent = SELECT_SHIFT_LEFT_CLICK; + //} + //if (m_callback) { + // m_callback(m_callbackArg, this, sevent); + //} +} + +void VPatternStrip::releaseButton(WPARAM wParam, LPARAM lParam) +{ +} + +// window message for right button press, only exists here +void VPatternStrip::rightButtonPress() +{ + //if (m_selectable) { + // if (m_selected) { + // setSelected(false); + // } else { + // if (m_color == 0) { + // setActive(false); + // } + // clear(); + // } + //} + //if (m_callback) { + // m_callback(m_callbackArg, this, SELECT_RIGHT_CLICK); + //} +} + +void VPatternStrip::clear() +{ + RECT rect; + GetClientRect(m_hwnd, &rect); + FillRect(m_backbufferDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); + m_colorSequence.clear(); + InvalidateRect(m_hwnd, nullptr, FALSE); +} + +bool VPatternStrip::isActive() const +{ + return m_active; +} + +void VPatternStrip::setActive(bool active) +{ + m_active = active; + m_stripLabel.setVisible(active); + + // if active == false + if (!m_active) { + setSelected(false); + if (m_runThread) { + WaitForSingleObject(m_runThread, INFINITE); + m_runThread = nullptr; + } + clear(); + // end active == false + return; + } + + // otherwise active = true + if (!m_runThread) { + m_runThread = CreateThread(NULL, 0, runThread, this, 0, NULL); + } +} + +bool VPatternStrip::isSelected() const +{ + return m_selected; +} + +void VPatternStrip::setSelected(bool selected) +{ + m_selected = selected; + if (m_selected) { + m_stripLabel.setForeColor(0xFFFFFF); + } else { + m_stripLabel.setForeColor(0xAAAAAA); + } +} + +void VPatternStrip::setLabelEnabled(bool enabled) +{ + m_stripLabel.setVisible(enabled); + m_stripLabel.setEnabled(enabled); +} + +void VPatternStrip::setSelectable(bool selectable) +{ + m_selectable = selectable; + if (!m_selectable) { + setSelected(false); + } +} + +LRESULT CALLBACK VPatternStrip::window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + VPatternStrip *pPatternStrip = (VPatternStrip *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (!pPatternStrip) { + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + switch (uMsg) { + case WM_VSCROLL: + break; + case WM_LBUTTONDOWN: + pPatternStrip->pressButton(wParam, lParam); + break; + case WM_LBUTTONUP: + pPatternStrip->releaseButton(wParam, lParam); + break; + case WM_RBUTTONUP: + pPatternStrip->rightButtonPress(); + break; + case WM_KEYDOWN: + // TODO: implement key control of color select? + break; + case WM_CTLCOLORSTATIC: + return (INT_PTR)pPatternStrip->m_wc.hbrBackground; + case WM_CREATE: + pPatternStrip->create(); + break; + case WM_PAINT: + pPatternStrip->paint(); + return 0; + case WM_ERASEBKGND: + return 1; + case WM_COMMAND: + pPatternStrip->command(wParam, lParam); + break; + case WM_DESTROY: + pPatternStrip->cleanup(); + break; + default: + break; + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +void VPatternStrip::registerWindowClass(HINSTANCE hInstance, COLORREF backcol) +{ + if (m_wc.lpfnWndProc == VPatternStrip::window_proc) { + // alredy registered + return; + } + // class registration + m_wc.lpfnWndProc = VPatternStrip::window_proc; + m_wc.hInstance = hInstance; + m_wc.hbrBackground = CreateSolidBrush(backcol); + m_wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW; + m_wc.hCursor = LoadCursor(NULL, IDC_ARROW); + m_wc.lpszClassName = WC_PATTERN_STRIP; + RegisterClass(&m_wc); +} + +void VPatternStrip::updateVisuals() +{ + if (!m_backbufferDC) return; + + // Clear the backbuffer with the background color + RECT backbufferRect = { 0, 0, m_backbufferWidth, m_backbufferHeight }; + FillRect(m_backbufferDC, &backbufferRect, (HBRUSH)GetStockObject(BLACK_BRUSH)); + + // Implement your drawing logic here, similar to the existing drawToBackBuffer logic + // This might involve iterating over m_colorSequence and drawing each color + int xPos = 0; + for (const auto &color : m_colorSequence) { + HBRUSH brush = getBrushCol(color.raw()); + RECT lineRect = { xPos, 0, xPos + m_lineWidth, m_backbufferHeight }; + FillRect(m_backbufferDC, &lineRect, brush); + xPos += m_lineWidth; + if (xPos >= m_backbufferWidth) break; // Stop if we've filled the whole backbuffer + } +} + +void VPatternStrip::draw(HDC hdc, int x, int y, int width, int height) +{ + updateVisuals(); // Make sure visuals are up-to-date before drawing + + // Use BitBlt to transfer the backbuffer content to the specified device context. + // Adjust source and destination rectangles if you want to support scaling or partial drawing. + BitBlt(hdc, x, y, width, height, m_backbufferDC, 0, 0, SRCCOPY); +} + +//void VPatternStrip::paint() +//{ +// PAINTSTRUCT ps; +// HDC hdc = BeginPaint(m_hwnd, &ps); +// +// updateVisuals(); // Update the backbuffer first +// +// // Now draw the backbuffer to this window's client area. +// BitBlt(hdc, 0, 0, m_backbufferWidth, m_backbufferHeight, m_backbufferDC, 0, 0, SRCCOPY); +// +// EndPaint(m_hwnd, &ps); +//} + +// Remember to implement createBackBuffer and destroyBackBuffer methods as well. +// These methods will handle the creation and destruction of the backbuffer resources. + +void VPatternStrip::createBackBuffer(HDC hdc, uint32_t width, uint32_t height) +{ + if (m_backbufferDC) { + // If there's already a backbuffer, release it first + destroyBackBuffer(); + } + + m_backbufferDC = CreateCompatibleDC(hdc); + m_backbuffer = CreateCompatibleBitmap(hdc, width, height); + m_oldBitmap = (HBITMAP)SelectObject(m_backbufferDC, m_backbuffer); + m_backbufferWidth = width; + m_backbufferHeight = height; +} + +void VPatternStrip::destroyBackBuffer() +{ + if (m_backbufferDC) { + SelectObject(m_backbufferDC, m_oldBitmap); // Restore the old bitmap + DeleteDC(m_backbufferDC); + DeleteObject(m_backbuffer); + m_backbufferDC = nullptr; + m_backbuffer = nullptr; + } +} + diff --git a/VortexEditor/GUI/VPatternStrip.h b/VortexEditor/GUI/VPatternStrip.h new file mode 100644 index 0000000..c777fce --- /dev/null +++ b/VortexEditor/GUI/VPatternStrip.h @@ -0,0 +1,90 @@ +#pragma once + +#include "VWindow.h" +#include "VLabel.h" +#include "VortexLib.h" +#include +#include +#include + +class VPatternStrip : public VWindow { +public: + enum SelectEvent { + SELECT_LEFT_CLICK, + SELECT_CTRL_LEFT_CLICK, + SELECT_SHIFT_LEFT_CLICK, + SELECT_RIGHT_CLICK, + }; + + typedef void (*VPatternStripCallback)(void* arg, VPatternStrip* select, SelectEvent sevent); + + VPatternStrip(); + VPatternStrip(HINSTANCE hinstance, VWindow& parent, const std::string& title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uint32_t linewidth, const json& modeData, uintptr_t menuID, VPatternStripCallback callback); + virtual ~VPatternStrip(); + + void init(HINSTANCE hinstance, VWindow& parent, const std::string& title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uint32_t linewidth, const json& modeData, uintptr_t menuID, VPatternStripCallback callback); + void cleanup(); + + void loadJson(const json &modeData); + + void run(); + void create() override; + void paint() override; + void command(WPARAM wParam, LPARAM lParam) override; + void pressButton(WPARAM wParam, LPARAM lParam) override; + void releaseButton(WPARAM wParam, LPARAM lParam) override; + void rightButtonPress(); + + void clear(); + void setColor(uint32_t col); + uint32_t getColor() const; + std::string getColorName() const; + void setColor(const std::string& name); + + bool isActive() const; + void setActive(bool active); + bool isSelected() const; + void setSelected(bool selected); + + void setLabelEnabled(bool enabled); + void setSelectable(bool selectable); + + // New method for external drawing + void draw(HDC hdc, int x, int y, int width, int height); + +private: + static LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + static void registerWindowClass(HINSTANCE hInstance, COLORREF backcol); + static WNDCLASS m_wc; + + static DWORD __stdcall runThread(void *arg); + + Vortex m_vortex; + HANDLE m_runThread; + VLabel m_stripLabel; + VPatternStripCallback m_callback; + bool m_active; + bool m_selected; + bool m_selectable; + + std::deque m_colorSequence; + uint32_t m_lineWidth; + uint32_t m_numSlices; + + // Backbuffer management + HDC m_backbufferDC; + HBITMAP m_backbuffer; + HBITMAP m_oldBitmap; + uint32_t m_backbufferWidth; + uint32_t m_backbufferHeight; + uint32_t m_scrollOffset; + + void createBackBuffer(HDC hdc, uint32_t width, uint32_t height); + void destroyBackBuffer(); + void updateVisuals(); // New method to update the backbuffer visuals + void drawToBackBuffer(); +}; \ No newline at end of file diff --git a/VortexEditor/GUI/VSelectBox.cpp b/VortexEditor/GUI/VSelectBox.cpp index 8d2fcc9..8e4eda5 100644 --- a/VortexEditor/GUI/VSelectBox.cpp +++ b/VortexEditor/GUI/VSelectBox.cpp @@ -34,10 +34,13 @@ VSelectBox::VSelectBox() : m_drawVLine(true), m_drawCircle(true), m_pressed(false), + m_useTransparency(false), + m_mouseInside(false), m_xSelect(0), m_ySelect(0), m_callback(nullptr), - m_bitmap(nullptr) + m_bitmap(nullptr), + m_hoverBitmap(nullptr) { } @@ -131,16 +134,31 @@ void VSelectBox::paint() memset(&paintStruct, 0, sizeof(paintStruct)); HDC hdc = BeginPaint(m_hwnd, &paintStruct); - // create a backbuffer and select it HDC backbuffDC = CreateCompatibleDC(hdc); HBITMAP backbuffer = CreateCompatibleBitmap(hdc, m_width, m_height); - SelectObject(backbuffDC, backbuffer); + HBITMAP hbmOldBackbuffer = (HBITMAP)SelectObject(backbuffDC, backbuffer); - // copy the bitmap into the backbuffer HDC bmpDC = CreateCompatibleDC(hdc); - HBITMAP hbmpOld = (HBITMAP)SelectObject(bmpDC, m_bitmap); - BitBlt(backbuffDC, 0, 0, m_width, m_height, bmpDC, 0, 0, BLACKNESS); - BitBlt(backbuffDC, m_innerLeft, m_innerTop, m_innerWidth, m_innerHeight, bmpDC, 0, 0, SRCCOPY); + HBITMAP back = m_bitmap; + if (m_mouseInside && m_hoverBitmap) { + back = m_hoverBitmap; + } + HBITMAP hbmpOld = (HBITMAP)SelectObject(bmpDC, back); + + if (m_useTransparency) { + // Fill the background with a color that will be made transparent + HBRUSH hBrush = CreateSolidBrush(RGB(45, 45, 45)); // Magenta, assuming this is the transparent color + FillRect(backbuffDC, &paintStruct.rcPaint, hBrush); + DeleteObject(hBrush); + + // Use TransparentBlt to copy the bitmap with transparency + TransparentBlt(backbuffDC, m_innerLeft, m_innerTop, m_innerWidth, m_innerHeight, bmpDC, 0, 0, m_innerWidth, m_innerHeight, RGB(255, 0, 255)); + } else { + // Use BitBlt to copy the bitmap without transparency + BitBlt(backbuffDC, m_innerLeft, m_innerTop, m_innerWidth, m_innerHeight, bmpDC, 0, 0, SRCCOPY); + } + + SelectObject(bmpDC, hbmpOld); DeleteDC(bmpDC); // draw the lines and circle @@ -192,14 +210,17 @@ void VSelectBox::paint() m_innerTop + (m_ySelect + selectorSize) - 1); } + BitBlt(hdc, 0, 0, m_width, m_height, backbuffDC, 0, 0, SRCCOPY); + SelectObject(backbuffDC, hbmOldBackbuffer); // Restore the original bitmap DeleteObject(backbuffer); DeleteDC(backbuffDC); EndPaint(m_hwnd, &paintStruct); } + void VSelectBox::command(WPARAM wParam, LPARAM lParam) { } @@ -241,8 +262,18 @@ void VSelectBox::releaseButton(WPARAM wParam, LPARAM lParam) doCallback(SELECT_RELEASE); } -void VSelectBox::mouseMove() +void VSelectBox::mouseMove(uint32_t buttons, uint16_t x, uint16_t y) { + if (!m_mouseInside && m_hoverBitmap) { + TRACKMOUSEEVENT mouseEvent; + mouseEvent.cbSize = sizeof(mouseEvent); + mouseEvent.dwFlags = 2; + mouseEvent.hwndTrack = m_hwnd; + mouseEvent.dwHoverTime = 0; + TrackMouseEvent(&mouseEvent); + InvalidateRect(m_hwnd, nullptr, FALSE); + m_mouseInside = true; + } if (!m_pressed) { return; } @@ -272,6 +303,34 @@ void VSelectBox::setBackground(HBITMAP hBitmap) m_bitmap = hBitmap; } +void VSelectBox::setHoverBackground(HBITMAP hBitmap) +{ + m_hoverBitmap = hBitmap; +} + +void VSelectBox::setBackgroundTransparency(bool transparent) +{ + m_useTransparency = transparent; +} + +void VSelectBox::setBorderSize(uint32_t borderSize) +{ + m_borderSize = borderSize; + + uint32_t borders = m_borderSize * 2; + m_width = m_innerWidth + borders; + m_height = m_innerHeight + borders; + + m_innerLeft = m_borderSize; + m_innerTop = m_borderSize; + // if the inner width/height is 1 (it's 1 pixel big) then it's the same + // pixel as the inner left/top. That helps to understand the -1 offset + // because the inside size is 1x1 but the inner left == inner right and + // the inner top == inner bottom because it's all the same 1x1 inner pixel + m_innerRight = m_borderSize + m_innerWidth - 1; + m_innerBottom = m_borderSize + m_innerHeight - 1; +} + void VSelectBox::setSelection(uint32_t x, uint32_t y) { m_xSelect = x; @@ -282,37 +341,43 @@ void VSelectBox::setSelection(uint32_t x, uint32_t y) LRESULT CALLBACK VSelectBox::window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - VSelectBox *pColorSelect = (VSelectBox *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (!pColorSelect) { + VSelectBox *pSelectBox = (VSelectBox *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (!pSelectBox) { return DefWindowProc(hwnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_VSCROLL: break; case WM_LBUTTONDOWN: - pColorSelect->pressButton(wParam, lParam); + pSelectBox->pressButton(wParam, lParam); break; case WM_LBUTTONUP: - pColorSelect->releaseButton(wParam, lParam); + pSelectBox->releaseButton(wParam, lParam); break; case WM_MOUSEMOVE: - pColorSelect->mouseMove(); + pSelectBox->mouseMove(wParam, LOWORD(lParam), HIWORD(lParam)); + break; + case WM_MOUSELEAVE: + if (pSelectBox->m_hoverBitmap) { + InvalidateRect(pSelectBox->m_hwnd, nullptr, FALSE); + } + pSelectBox->m_mouseInside = false; break; case WM_CTLCOLORSTATIC: - return (INT_PTR)pColorSelect->m_wc.hbrBackground; + return (INT_PTR)pSelectBox->m_wc.hbrBackground; case WM_ERASEBKGND: return 1; case WM_CREATE: - pColorSelect->create(); + pSelectBox->create(); break; case WM_PAINT: - pColorSelect->paint(); + pSelectBox->paint(); return 0; case WM_COMMAND: - pColorSelect->command(wParam, lParam); + pSelectBox->command(wParam, lParam); break; case WM_DESTROY: - pColorSelect->cleanup(); + pSelectBox->cleanup(); break; default: break; @@ -334,4 +399,4 @@ void VSelectBox::registerWindowClass(HINSTANCE hInstance, COLORREF backcol) m_wc.hCursor = LoadCursor(NULL, IDC_ARROW); m_wc.lpszClassName = WC_HUE_SAT_BOX; RegisterClass(&m_wc); -} \ No newline at end of file +} diff --git a/VortexEditor/GUI/VSelectBox.h b/VortexEditor/GUI/VSelectBox.h index 81f9788..31d2d2a 100644 --- a/VortexEditor/GUI/VSelectBox.h +++ b/VortexEditor/GUI/VSelectBox.h @@ -1,87 +1,94 @@ -#pragma once - -#include "VWindow.h" - -#include "VLabel.h" - -class RGBColor; - -class VSelectBox : public VWindow -{ -public: - // type of selection event for callback - enum SelectEvent { - SELECT_PRESS, - SELECT_CTRL_PRESS, - SELECT_SHIFT_PRESS, - SELECT_DRAG, - SELECT_RELEASE - }; - // callback upon selection - typedef void (*VSelectBoxCallback)(void *arg, uint32_t x, uint32_t y, SelectEvent sevent); - - VSelectBox(); - VSelectBox(HINSTANCE hinstance, VWindow &parent, const std::string &title, - COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, - uintptr_t menuID, VSelectBoxCallback callback); - virtual ~VSelectBox(); - - virtual void init(HINSTANCE hinstance, VWindow &parent, const std::string &title, - COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, - uintptr_t menuID, VSelectBoxCallback callback); - virtual void cleanup(); - - // windows message handlers - virtual void create() override; - virtual void paint() override; - virtual void command(WPARAM wParam, LPARAM lParam) override; - virtual void pressButton(WPARAM wParam, LPARAM lParam) override; - virtual void releaseButton(WPARAM wParam, LPARAM lParam) override; - virtual void mouseMove(); - - // set a background via callback to convert x/y to rgb - //void setBackground(VFillCallback fillCallback); - void setBackground(HBITMAP hBitmap); - void setSelection(uint32_t x, uint32_t y); - - // whether to draw specific components - void setDrawHLine(bool draw) { m_drawHLine = draw; } - void setDrawVLine(bool draw) { m_drawVLine = draw; } - void setDrawCircle(bool draw) { m_drawCircle = draw; } - -private: - static LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - static void registerWindowClass(HINSTANCE hInstance, COLORREF backcol); - static WNDCLASS m_wc; - - void doCallback(SelectEvent sevent); - - uint32_t m_borderSize; - - uint32_t m_width; - uint32_t m_height; - - // local coords of the inner rectangle that contains the actual - uint32_t m_innerLeft; - uint32_t m_innerTop; - uint32_t m_innerRight; - uint32_t m_innerBottom; - - uint32_t m_innerWidth; - uint32_t m_innerHeight; - - bool m_drawHLine; - bool m_drawVLine; - bool m_drawCircle; - - bool m_pressed; - - uint32_t m_xSelect; - uint32_t m_ySelect; - - // internal vgui label for display of color code - VLabel m_colorLabel; - - VSelectBoxCallback m_callback; - HBITMAP m_bitmap; -}; +#pragma once + +#include "VWindow.h" + +#include "VLabel.h" + +class RGBColor; + +class VSelectBox : public VWindow +{ +public: + // type of selection event for callback + enum SelectEvent { + SELECT_PRESS, + SELECT_CTRL_PRESS, + SELECT_SHIFT_PRESS, + SELECT_DRAG, + SELECT_RELEASE + }; + // callback upon selection + typedef void (*VSelectBoxCallback)(void *arg, uint32_t x, uint32_t y, SelectEvent sevent); + + VSelectBox(); + VSelectBox(HINSTANCE hinstance, VWindow &parent, const std::string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uintptr_t menuID, VSelectBoxCallback callback); + virtual ~VSelectBox(); + + virtual void init(HINSTANCE hinstance, VWindow &parent, const std::string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uintptr_t menuID, VSelectBoxCallback callback); + virtual void cleanup(); + + // windows message handlers + virtual void create() override; + virtual void paint() override; + virtual void command(WPARAM wParam, LPARAM lParam) override; + virtual void pressButton(WPARAM wParam, LPARAM lParam) override; + virtual void releaseButton(WPARAM wParam, LPARAM lParam) override; + virtual void mouseMove(uint32_t buttons, uint16_t x, uint16_t y); + + // set a background via callback to convert x/y to rgb + //void setBackground(VFillCallback fillCallback); + void setBackground(HBITMAP hBitmap); + void setHoverBackground(HBITMAP hBitmap); + void setBackgroundTransparency(bool transparent); + void setBorderSize(uint32_t borderSize); + void setSelection(uint32_t x, uint32_t y); + + // whether to draw specific components + void setDrawHLine(bool draw) { m_drawHLine = draw; } + void setDrawVLine(bool draw) { m_drawVLine = draw; } + void setDrawCircle(bool draw) { m_drawCircle = draw; } + +private: + static LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + static void registerWindowClass(HINSTANCE hInstance, COLORREF backcol); + static WNDCLASS m_wc; + + void doCallback(SelectEvent sevent); + + uint32_t m_borderSize; + + uint32_t m_width; + uint32_t m_height; + + // local coords of the inner rectangle that contains the actual + uint32_t m_innerLeft; + uint32_t m_innerTop; + uint32_t m_innerRight; + uint32_t m_innerBottom; + + uint32_t m_innerWidth; + uint32_t m_innerHeight; + + bool m_drawHLine; + bool m_drawVLine; + bool m_drawCircle; + + bool m_pressed; + bool m_useTransparency; + + bool m_mouseInside; + + uint32_t m_xSelect; + uint32_t m_ySelect; + + // internal vgui label for display of color code + VLabel m_colorLabel; + + VSelectBoxCallback m_callback; + HBITMAP m_bitmap; + HBITMAP m_hoverBitmap; +}; diff --git a/VortexEditor/GUI/VStatusBar.cpp b/VortexEditor/GUI/VStatusBar.cpp index 125a200..98863e1 100644 --- a/VortexEditor/GUI/VStatusBar.cpp +++ b/VortexEditor/GUI/VStatusBar.cpp @@ -1,115 +1,118 @@ -#include "VStatusBar.h" - -// Windows includes -#include -#include - -// Vortex Engine includes -#include "EditorConfig.h" - -// Editor includes -#include "VortexEditor.h" - -using namespace std; - -VStatusBar::VStatusBar() : - VWindow(), - m_callback(nullptr) -{ -} - -VStatusBar::VStatusBar(HINSTANCE hInstance, VWindow &parent, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, - uintptr_t menuID, VWindowCallback callback) : - VStatusBar() -{ - init(hInstance, parent, title, backcol, width, height, x, y, menuID, callback); -} - -VStatusBar::~VStatusBar() -{ - cleanup(); -} - -void VStatusBar::init(HINSTANCE hInstance, VWindow &parent, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, - uintptr_t menuID, VWindowCallback callback) -{ - // store callback and menu id - m_callback = callback; - m_backColor = backcol; - m_foreColor = RGB(0xD0, 0xD0, 0xD0); - - if (!menuID) { - menuID = nextMenuID++; - } - - if (!parent.addChild(menuID, this)) { - return; - } - - // create the window - m_hwnd = CreateWindow(WC_EDIT, title.c_str(), - WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP | ES_READONLY, - x, y, width, height, parent.hwnd(), (HMENU)menuID, nullptr, nullptr); - if (!m_hwnd) { - MessageBox(nullptr, "Failed to open window", "Error", 0); - throw exception("idk"); - } - - // set 'this' in the user data area of the class so that the static callback - // routine can access the object - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); -} - -void VStatusBar::cleanup() -{ -} - -void VStatusBar::create() -{ -} - -void VStatusBar::paint() -{ -} - -void VStatusBar::command(WPARAM wParam, LPARAM lParam) -{ - int reason = HIWORD(wParam); - if (!m_callback || reason != EN_CHANGE) { - return; - } - m_callback(m_callbackArg, this); -} - -void VStatusBar::pressButton(WPARAM wParam, LPARAM lParam) -{ -} - -void VStatusBar::releaseButton(WPARAM wParam, LPARAM lParam) -{ -} - -void VStatusBar::setText(std::string item) -{ - Edit_SetText(m_hwnd, item.c_str()); -} - -void VStatusBar::clearText() -{ - setText(""); -} - -string VStatusBar::getText() const -{ - char text[256] = {0}; - Edit_GetText(m_hwnd, text, sizeof(text)); - return text; -} - -void VStatusBar::setStatus(COLORREF col, std::string status) -{ - setForeColor(col); - setText(" " + status); -} +#include "VStatusBar.h" + +// Windows includes +#include +#include + +// Vortex Engine includes +#include "EditorConfig.h" + +// Editor includes +#include "VortexEditor.h" + +using namespace std; + +VStatusBar::VStatusBar() : + VWindow(), + m_callback(nullptr) +{ +} + +VStatusBar::VStatusBar(HINSTANCE hInstance, VWindow &parent, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uintptr_t menuID, VWindowCallback callback) : + VStatusBar() +{ + init(hInstance, parent, title, backcol, width, height, x, y, menuID, callback); +} + +VStatusBar::~VStatusBar() +{ + cleanup(); +} + +void VStatusBar::init(HINSTANCE hInstance, VWindow &parent, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uintptr_t menuID, VWindowCallback callback) +{ + // store callback and menu id + m_callback = callback; + m_backColor = backcol; + m_foreColor = RGB(0xD0, 0xD0, 0xD0); + + if (!menuID) { + menuID = nextMenuID++; + } + + if (!parent.addChild(menuID, this)) { + return; + } + + // create the window + m_hwnd = CreateWindow(WC_EDIT, title.c_str(), + WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP | ES_READONLY, + x, y, width, height, parent.hwnd(), (HMENU)menuID, nullptr, nullptr); + if (!m_hwnd) { + MessageBox(nullptr, "Failed to open window", "Error", 0); + throw exception("idk"); + } + + // set 'this' in the user data area of the class so that the static callback + // routine can access the object + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); +} + +void VStatusBar::cleanup() +{ +} + +void VStatusBar::create() +{ +} + +void VStatusBar::paint() +{ +} + +void VStatusBar::command(WPARAM wParam, LPARAM lParam) +{ + int reason = HIWORD(wParam); + if (!m_callback || reason != EN_CHANGE) { + return; + } + m_callback(m_callbackArg, this); +} + +void VStatusBar::pressButton(WPARAM wParam, LPARAM lParam) +{ +} + +void VStatusBar::releaseButton(WPARAM wParam, LPARAM lParam) +{ +} + +void VStatusBar::setText(std::string item) +{ + SendMessage(m_hwnd, WM_SETREDRAW, FALSE, 0); // Disable redrawing + Edit_SetText(m_hwnd, item.c_str()); + SendMessage(m_hwnd, WM_SETREDRAW, TRUE, 0); // Re-enable redrawing + InvalidateRect(m_hwnd, NULL, TRUE); // Force redraw +} + +void VStatusBar::clearText() +{ + setText(""); +} + +string VStatusBar::getText() const +{ + char text[256] = {0}; + Edit_GetText(m_hwnd, text, sizeof(text)); + return text; +} + +void VStatusBar::setStatus(COLORREF col, std::string status) +{ + setForeColor(col); + setText(" " + status); +} diff --git a/VortexEditor/GUI/VWindow.cpp b/VortexEditor/GUI/VWindow.cpp index abaab79..4155d38 100644 --- a/VortexEditor/GUI/VWindow.cpp +++ b/VortexEditor/GUI/VWindow.cpp @@ -1,400 +1,400 @@ -#include "VWindow.h" - -#include -#include - -#include "resource.h" - -using namespace std; - -WNDCLASS VWindow::m_wc = {0}; -uint32_t VWindow::nextMenuID = 70000; - -// This GUID is for all USB serial host PnP drivers -GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, - 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 }; - -VWindow::VWindow() : - m_hwnd(nullptr), - m_tooltipHwnd(nullptr), - m_children(), - m_pParent(nullptr), - m_callbackArg(nullptr), - m_hDeviceNotify(nullptr), - m_deviceCallback(nullptr), - m_userCallbacks(), - m_backColor(0), - m_foreColor(0), - m_loseFocusCallback(nullptr), - m_backEnabled(false), - m_foreEnabled(false) -{ -} - -VWindow::VWindow(HINSTANCE hinstance, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, - void *callbackArg, const string &className) : - VWindow() -{ - init(hinstance, title, backcol, width, height, callbackArg, className); -} - -VWindow::~VWindow() -{ - cleanup(); -} - -void VWindow::init(HINSTANCE hInstance, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, - void *callbackArg, const string &className) -{ - // store callback - m_callbackArg = callbackArg; - m_backColor = backcol; - m_foreColor = RGB(0xD0, 0xD0, 0xD0); - - m_backEnabled = true; - m_foreEnabled = true; - - // register a window class for the window if not done yet - registerWindowClass(hInstance, backcol, className); - - // get desktop rect so we can center the window - RECT desktop; - GetClientRect(GetDesktopWindow(), &desktop); - - // create the window - m_hwnd = CreateWindow(className.c_str(), title.c_str(), - WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, - (desktop.right / 2) - (width / 2), (desktop.bottom / 2) - (height / 2), - width, height, nullptr, nullptr, hInstance, nullptr); - if (!m_hwnd) { - MessageBox(nullptr, "Failed to open window", "Error", 0); - throw exception("idk"); - } - - // set 'this' in the user data area of the class so that the static callback - // routine can access the object - SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); -} - -void VWindow::cleanup() -{ -} - -bool VWindow::process(MSG &msg) -{ - return IsDialogMessage(m_hwnd, &msg); -} - -void VWindow::create() -{ -} - -void VWindow::paint() -{ - PAINTSTRUCT ps; - HDC hdc = BeginPaint(m_hwnd, &ps); - - EndPaint(m_hwnd, &ps); -} - -INT_PTR VWindow::controlColor(WPARAM wParam, LPARAM lParam) -{ - // this function is kinda hacky and not really proper... - // ... but it works. - HWND childHwnd = (HWND)lParam; - VWindow *child = getChild(childHwnd); - if (child){ - return child->controlColor(wParam, lParam); - } - if (m_foreEnabled) { - SetTextColor((HDC)wParam, m_foreColor); - } - if (m_backEnabled) { - SetBkColor((HDC)wParam, m_backColor); - return (INT_PTR)m_wc.hbrBackground; - } - return 0; -} - -void VWindow::command(WPARAM wParam, LPARAM lParam) -{ - uintptr_t menuID = LOWORD(wParam); - if (menuID == ID_FILE_QUIT) { - PostQuitMessage(0); - return; - } - VWindow *child = getChild(menuID); - if (child) { - child->command(wParam, lParam); - return; - } - VMenuCallback menuCallback = getCallback(menuID); - if (menuCallback) { - menuCallback(m_callbackArg, menuID); - return; - } -} - -void VWindow::pressButton(WPARAM wParam, LPARAM lParam) -{ -} - -void VWindow::releaseButton(WPARAM wParam, LPARAM lParam) -{ -} - -void VWindow::loseFocus(WPARAM wParam, LPARAM lParam) -{ - VWindow *child = getChild((HWND)wParam); - if (child){ - child->loseFocus(wParam, lParam); - return; - } - if (m_loseFocusCallback) { - m_loseFocusCallback(m_callbackArg, this); - } -} - -bool VWindow::addChild(uintptr_t menuID, VWindow *child, uint32_t *out_id) -{ - if (m_children.find(menuID) != m_children.end()) { - return false; - } - child->m_pParent = this; - child->m_callbackArg = m_callbackArg; - m_children.insert(make_pair(menuID, child)); - if (out_id) { - *out_id = (uint32_t)(m_children.size() - 1); - } - return true; -} - -VWindow *VWindow::getChild(uintptr_t id) -{ - auto result = m_children.find(id); - if (result == m_children.end()) { - return nullptr; - } - return result->second; -} - -VWindow *VWindow::getChild(HWND hwnd) -{ - for (auto child = m_children.begin(); child != m_children.end(); ++child) { - if (child->second->hwnd() == hwnd) { - return child->second; - } - } - return nullptr; -} - -uint32_t VWindow::addCallback(uintptr_t menuID, VMenuCallback callback) -{ - m_menuCallbacks.insert(make_pair(menuID, callback)); - return (uint32_t)m_menuCallbacks.size(); -} - -VWindow::VMenuCallback VWindow::getCallback(uintptr_t menuID) -{ - auto entry = m_menuCallbacks.find(menuID); - if (entry == m_menuCallbacks.end()) { - return nullptr; - } - return entry->second; -} - -void VWindow::installUserCallback(uint32_t id, VWindowCallback callback) -{ - if (id < WM_USER) { - return; - } - m_userCallbacks.insert(make_pair(id - WM_USER, callback)); -} - -void VWindow::installDeviceCallback(VDeviceCallback callback) -{ - // only one is allowed - if (m_deviceCallback || m_hDeviceNotify) { - return; - } - m_deviceCallback = callback; - DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; - ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); - NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); - NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; - NotificationFilter.dbcc_classguid = WceusbshGUID; - - m_hDeviceNotify = RegisterDeviceNotification(m_hwnd, - &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); -} - -void VWindow::installLoseFocusCallback(VWindowCallback callback) -{ - if (m_loseFocusCallback) { - return; - } - m_loseFocusCallback = callback; -} - -void VWindow::redraw() -{ - RECT wndRect; - GetClientRect(m_hwnd, &wndRect); - InvalidateRect(m_hwnd, &wndRect, true); - //RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE); -} - -void VWindow::setTooltip(string text) -{ - if (m_tooltipHwnd) { - DestroyWindow(m_tooltipHwnd); - m_tooltipHwnd = nullptr; - } - // Create the tooltip. g_hInst is the global instance handle. - m_tooltipHwnd = CreateWindow(TOOLTIPS_CLASS, NULL, - WS_POPUP | TTS_ALWAYSTIP, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - m_hwnd, NULL, VWindow::m_wc.hInstance, NULL); - if (!m_tooltipHwnd) { - return; - } - - // Associate the tooltip with the tool. - TOOLINFO toolInfo = { 0 }; - toolInfo.cbSize = sizeof(toolInfo); - toolInfo.hwnd = m_hwnd; - toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS; - toolInfo.uId = (UINT_PTR)m_hwnd; - toolInfo.lpszText = (LPSTR)text.c_str(); - SendMessage(m_tooltipHwnd, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); -} - -void VWindow::setVisible(bool visible) -{ - ShowWindow(m_hwnd, visible); -} - -void VWindow::setEnabled(bool enable) -{ - EnableWindow(m_hwnd, enable); -} - -void VWindow::setBackColor(COLORREF backcol) -{ - m_backColor = backcol; -} - -void VWindow::setForeColor(COLORREF forecol) -{ - m_foreColor = forecol; -} - -void VWindow::setBackEnabled(bool enable) -{ - m_backEnabled = enable; -} - -void VWindow::setForeEnabled(bool enable) -{ - m_foreEnabled = enable; -} - -bool VWindow::isVisible() const -{ - return IsWindowVisible(m_hwnd); -} - -bool VWindow::isEnabled() const -{ - return IsWindowEnabled(m_hwnd); -} - -bool VWindow::isBackEnabled() const -{ - return m_backEnabled; -} - -bool VWindow::isForeEnabled() const -{ - return m_foreEnabled; -} - -LRESULT CALLBACK VWindow::window_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - VWindow *pWindow = (VWindow *)GetWindowLongPtr(hWnd, GWLP_USERDATA); - if (!pWindow) { - return DefWindowProc(hWnd, uMsg, wParam, lParam); - } - uint32_t userMsgID = 0; - if (uMsg > WM_USER) { - userMsgID = (uint32_t)uMsg - WM_USER; - uMsg = WM_USER; - } - switch (uMsg) { - case WM_USER: - if (pWindow->m_userCallbacks.find(userMsgID) != pWindow->m_userCallbacks.end()) { - pWindow->m_userCallbacks[userMsgID](pWindow->m_callbackArg, pWindow); - } - break; - case WM_VSCROLL: - break; - case WM_LBUTTONDOWN: - pWindow->pressButton(wParam, lParam); - break; - case WM_LBUTTONUP: - pWindow->releaseButton(wParam, lParam); - break; - case WM_CTLCOLORSTATIC: - case WM_CTLCOLOREDIT: - // for static controls we pass the hwnd of the window itself - return pWindow->controlColor(wParam, lParam); - case WM_CREATE: - pWindow->create(); - break; - case WM_PAINT: - pWindow->paint(); - return 0; - case WM_KILLFOCUS: - pWindow->loseFocus(wParam, lParam); - break; - case WM_COMMAND: - pWindow->command(wParam, lParam); - break; - case WM_DEVICECHANGE: - if (!pWindow->m_deviceCallback) { - break; - } - // Output some messages to the window. - if (wParam == DBT_DEVICEARRIVAL) { - pWindow->m_deviceCallback(pWindow->m_callbackArg, (DEV_BROADCAST_HDR *)lParam, true); - } else if (wParam == DBT_DEVICEREMOVECOMPLETE) { - pWindow->m_deviceCallback(pWindow->m_callbackArg, (DEV_BROADCAST_HDR *)lParam, false); - } - // should we handle DBT_DEVNODES_CHANGED ? - break; - case WM_DESTROY: - pWindow->cleanup(); - PostQuitMessage(0); - break; - default: - break; - } - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - -void VWindow::registerWindowClass(HINSTANCE hInstance, COLORREF backcol, const string &className) -{ - if (m_wc.lpfnWndProc == VWindow::window_proc) { - // alredy registered - return; - } - // class registration - m_wc.lpfnWndProc = VWindow::window_proc; - m_wc.hInstance = hInstance; - m_wc.lpszClassName = className.c_str(); - m_wc.hbrBackground = CreateSolidBrush(backcol); - m_wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); - RegisterClass(&m_wc); -} +#include "VWindow.h" + +#include +#include + +#include "resource.h" + +using namespace std; + +WNDCLASS VWindow::m_wc = {0}; +uint32_t VWindow::nextMenuID = 70000; + +// This GUID is for all USB serial host PnP drivers +GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, + 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 }; + +VWindow::VWindow() : + m_hwnd(nullptr), + m_tooltipHwnd(nullptr), + m_children(), + m_pParent(nullptr), + m_callbackArg(nullptr), + m_hDeviceNotify(nullptr), + m_deviceCallback(nullptr), + m_userCallbacks(), + m_backColor(0), + m_foreColor(0), + m_loseFocusCallback(nullptr), + m_backEnabled(false), + m_foreEnabled(false) +{ +} + +VWindow::VWindow(HINSTANCE hinstance, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, + void *callbackArg, const string &className) : + VWindow() +{ + init(hinstance, title, backcol, width, height, callbackArg, className); +} + +VWindow::~VWindow() +{ + cleanup(); +} + +void VWindow::init(HINSTANCE hInstance, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, + void *callbackArg, const string &className) +{ + // store callback + m_callbackArg = callbackArg; + m_backColor = backcol; + m_foreColor = RGB(0xD0, 0xD0, 0xD0); + + m_backEnabled = true; + m_foreEnabled = true; + + // register a window class for the window if not done yet + registerWindowClass(hInstance, backcol, className); + + // get desktop rect so we can center the window + RECT desktop; + GetClientRect(GetDesktopWindow(), &desktop); + + // create the window + m_hwnd = CreateWindow(className.c_str(), title.c_str(), + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE | WS_CLIPCHILDREN, + (desktop.right / 2) - (width / 2), (desktop.bottom / 2) - (height / 2), + width, height, nullptr, nullptr, hInstance, nullptr); + if (!m_hwnd) { + MessageBox(nullptr, "Failed to open window", "Error", 0); + throw exception("idk"); + } + + // set 'this' in the user data area of the class so that the static callback + // routine can access the object + SetWindowLongPtr(m_hwnd, GWLP_USERDATA, (LONG_PTR)this); +} + +void VWindow::cleanup() +{ +} + +bool VWindow::process(MSG &msg) +{ + return IsDialogMessage(m_hwnd, &msg); +} + +void VWindow::create() +{ +} + +void VWindow::paint() +{ + PAINTSTRUCT ps; + HDC hdc = BeginPaint(m_hwnd, &ps); + + EndPaint(m_hwnd, &ps); +} + +INT_PTR VWindow::controlColor(WPARAM wParam, LPARAM lParam) +{ + // this function is kinda hacky and not really proper... + // ... but it works. + HWND childHwnd = (HWND)lParam; + VWindow *child = getChild(childHwnd); + if (child){ + return child->controlColor(wParam, lParam); + } + if (m_foreEnabled) { + SetTextColor((HDC)wParam, m_foreColor); + } + if (m_backEnabled) { + SetBkColor((HDC)wParam, m_backColor); + return (INT_PTR)m_wc.hbrBackground; + } + return 0; +} + +void VWindow::command(WPARAM wParam, LPARAM lParam) +{ + uintptr_t menuID = LOWORD(wParam); + if (menuID == ID_FILE_QUIT) { + PostQuitMessage(0); + return; + } + VWindow *child = getChild(menuID); + if (child) { + child->command(wParam, lParam); + return; + } + VMenuCallback menuCallback = getCallback(menuID); + if (menuCallback) { + menuCallback(m_callbackArg, menuID); + return; + } +} + +void VWindow::pressButton(WPARAM wParam, LPARAM lParam) +{ +} + +void VWindow::releaseButton(WPARAM wParam, LPARAM lParam) +{ +} + +void VWindow::loseFocus(WPARAM wParam, LPARAM lParam) +{ + VWindow *child = getChild((HWND)wParam); + if (child){ + child->loseFocus(wParam, lParam); + return; + } + if (m_loseFocusCallback) { + m_loseFocusCallback(m_callbackArg, this); + } +} + +bool VWindow::addChild(uintptr_t menuID, VWindow *child, uint32_t *out_id) +{ + if (m_children.find(menuID) != m_children.end()) { + return false; + } + child->m_pParent = this; + child->m_callbackArg = m_callbackArg; + m_children.insert(make_pair(menuID, child)); + if (out_id) { + *out_id = (uint32_t)(m_children.size() - 1); + } + return true; +} + +VWindow *VWindow::getChild(uintptr_t id) +{ + auto result = m_children.find(id); + if (result == m_children.end()) { + return nullptr; + } + return result->second; +} + +VWindow *VWindow::getChild(HWND hwnd) +{ + for (auto child = m_children.begin(); child != m_children.end(); ++child) { + if (child->second->hwnd() == hwnd) { + return child->second; + } + } + return nullptr; +} + +uint32_t VWindow::addCallback(uintptr_t menuID, VMenuCallback callback) +{ + m_menuCallbacks.insert(make_pair(menuID, callback)); + return (uint32_t)m_menuCallbacks.size(); +} + +VWindow::VMenuCallback VWindow::getCallback(uintptr_t menuID) +{ + auto entry = m_menuCallbacks.find(menuID); + if (entry == m_menuCallbacks.end()) { + return nullptr; + } + return entry->second; +} + +void VWindow::installUserCallback(uint32_t id, VWindowCallback callback) +{ + if (id < WM_USER) { + return; + } + m_userCallbacks.insert(make_pair(id - WM_USER, callback)); +} + +void VWindow::installDeviceCallback(VDeviceCallback callback) +{ + // only one is allowed + if (m_deviceCallback || m_hDeviceNotify) { + return; + } + m_deviceCallback = callback; + DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; + ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); + NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + NotificationFilter.dbcc_classguid = WceusbshGUID; + + m_hDeviceNotify = RegisterDeviceNotification(m_hwnd, + &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); +} + +void VWindow::installLoseFocusCallback(VWindowCallback callback) +{ + if (m_loseFocusCallback) { + return; + } + m_loseFocusCallback = callback; +} + +void VWindow::redraw() +{ + RECT wndRect; + GetClientRect(m_hwnd, &wndRect); + InvalidateRect(m_hwnd, &wndRect, true); + //RedrawWindow(m_hwnd, NULL, NULL, RDW_INVALIDATE); +} + +void VWindow::setTooltip(string text) +{ + if (m_tooltipHwnd) { + DestroyWindow(m_tooltipHwnd); + m_tooltipHwnd = nullptr; + } + // Create the tooltip. g_hInst is the global instance handle. + m_tooltipHwnd = CreateWindow(TOOLTIPS_CLASS, NULL, + WS_POPUP | TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + m_hwnd, NULL, VWindow::m_wc.hInstance, NULL); + if (!m_tooltipHwnd) { + return; + } + + // Associate the tooltip with the tool. + TOOLINFO toolInfo = { 0 }; + toolInfo.cbSize = sizeof(toolInfo); + toolInfo.hwnd = m_hwnd; + toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS; + toolInfo.uId = (UINT_PTR)m_hwnd; + toolInfo.lpszText = (LPSTR)text.c_str(); + SendMessage(m_tooltipHwnd, TTM_ADDTOOL, 0, (LPARAM)&toolInfo); +} + +void VWindow::setVisible(bool visible) +{ + ShowWindow(m_hwnd, visible); +} + +void VWindow::setEnabled(bool enable) +{ + EnableWindow(m_hwnd, enable); +} + +void VWindow::setBackColor(COLORREF backcol) +{ + m_backColor = backcol; +} + +void VWindow::setForeColor(COLORREF forecol) +{ + m_foreColor = forecol; +} + +void VWindow::setBackEnabled(bool enable) +{ + m_backEnabled = enable; +} + +void VWindow::setForeEnabled(bool enable) +{ + m_foreEnabled = enable; +} + +bool VWindow::isVisible() const +{ + return IsWindowVisible(m_hwnd); +} + +bool VWindow::isEnabled() const +{ + return IsWindowEnabled(m_hwnd); +} + +bool VWindow::isBackEnabled() const +{ + return m_backEnabled; +} + +bool VWindow::isForeEnabled() const +{ + return m_foreEnabled; +} + +LRESULT CALLBACK VWindow::window_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + VWindow *pWindow = (VWindow *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + if (!pWindow) { + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } + uint32_t userMsgID = 0; + if (uMsg > WM_USER) { + userMsgID = (uint32_t)uMsg - WM_USER; + uMsg = WM_USER; + } + switch (uMsg) { + case WM_USER: + if (pWindow->m_userCallbacks.find(userMsgID) != pWindow->m_userCallbacks.end()) { + pWindow->m_userCallbacks[userMsgID](pWindow->m_callbackArg, pWindow); + } + break; + case WM_VSCROLL: + break; + case WM_LBUTTONDOWN: + pWindow->pressButton(wParam, lParam); + break; + case WM_LBUTTONUP: + pWindow->releaseButton(wParam, lParam); + break; + case WM_CTLCOLORSTATIC: + case WM_CTLCOLOREDIT: + // for static controls we pass the hwnd of the window itself + return pWindow->controlColor(wParam, lParam); + case WM_CREATE: + pWindow->create(); + break; + case WM_PAINT: + pWindow->paint(); + return 0; + case WM_KILLFOCUS: + pWindow->loseFocus(wParam, lParam); + break; + case WM_COMMAND: + pWindow->command(wParam, lParam); + break; + case WM_DEVICECHANGE: + if (!pWindow->m_deviceCallback) { + break; + } + // Output some messages to the window. + if (wParam == DBT_DEVICEARRIVAL) { + pWindow->m_deviceCallback(pWindow->m_callbackArg, (DEV_BROADCAST_HDR *)lParam, true); + } else if (wParam == DBT_DEVICEREMOVECOMPLETE) { + pWindow->m_deviceCallback(pWindow->m_callbackArg, (DEV_BROADCAST_HDR *)lParam, false); + } + // should we handle DBT_DEVNODES_CHANGED ? + break; + case WM_DESTROY: + pWindow->cleanup(); + PostQuitMessage(0); + break; + default: + break; + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +void VWindow::registerWindowClass(HINSTANCE hInstance, COLORREF backcol, const string &className) +{ + if (m_wc.lpfnWndProc == VWindow::window_proc) { + // alredy registered + return; + } + // class registration + m_wc.lpfnWndProc = VWindow::window_proc; + m_wc.hInstance = hInstance; + m_wc.lpszClassName = className.c_str(); + m_wc.hbrBackground = CreateSolidBrush(backcol); + m_wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); + RegisterClass(&m_wc); +} diff --git a/VortexEditor/HttpClient.cpp b/VortexEditor/HttpClient.cpp new file mode 100644 index 0000000..363340c --- /dev/null +++ b/VortexEditor/HttpClient.cpp @@ -0,0 +1,132 @@ +#include "HttpClient.h" + +using namespace std; + +HttpClient::HttpClient(const string &userAgent) + : userAgent(ConvertToWideString(userAgent)) +{ +} + +string HttpClient::SendRequest(const string &host, const string &path, const string &method, + const map &headers, const string &requestData, const map &queryParams) +{ + wstring responseW; + string result; + wstring hostW = ConvertToWideString(host); + wstring pathW = BuildFullPath(ConvertToWideString(path), ConvertMapToWideString(queryParams)); + wstring methodW = ConvertToWideString(method); + + HINTERNET hSession = nullptr; + HINTERNET hConnect = nullptr; + HINTERNET hRequest = nullptr; + + hSession = WinHttpOpen(userAgent.c_str(), WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + if (!hSession) { + throw runtime_error("Failed to open HTTP session"); + } + + hConnect = WinHttpConnect(hSession, hostW.c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0); + if (!hConnect) { + throw runtime_error("Failed to connect"); + } + + hRequest = WinHttpOpenRequest(hConnect, methodW.c_str(), pathW.c_str(), + NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); + if (!hRequest) { + throw runtime_error("Failed to open HTTP request"); + } + + for (const auto &pair : headers) { + wstring fullHeader = ConvertToWideString(pair.first + ": " + pair.second); + if (!WinHttpAddRequestHeaders(hRequest, fullHeader.c_str(), -1, WINHTTP_ADDREQ_FLAG_ADD)) { + throw runtime_error("Failed to add request header"); + } + } + + vector requestDataW(requestData.begin(), requestData.end()); + BOOL bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, requestDataW.data(), + requestDataW.size() * sizeof(wchar_t), requestDataW.size() * sizeof(wchar_t), 0); + if (!bResults) { + throw runtime_error("Failed to send request"); + } + bResults = WinHttpReceiveResponse(hRequest, NULL); + if (!bResults) { + throw runtime_error("Failed to receive response"); + } + + DWORD dwSize = 0; + DWORD dwDownloaded = 0; + do { + if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) { + throw runtime_error("Failed to query data available"); + } + + vector buffer(dwSize + 1); + if (!WinHttpReadData(hRequest, buffer.data(), dwSize, &dwDownloaded)) { + throw runtime_error("Failed to read data"); + } + + responseW.append(buffer.begin(), buffer.begin() + dwDownloaded); + } while (dwSize > 0); + + // Convert wide string to UTF-8 + result = ConvertToNarrowString(responseW); + + WinHttpCloseHandle(hRequest); + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hSession); + + return result; +} + +wstring HttpClient::BuildFullPath(const wstring &path, const map &queryParams) +{ + if (queryParams.empty()) { + return path; + } + + wstringstream fullUrlStream; + fullUrlStream << path; + if (!queryParams.empty()) { + fullUrlStream << L"?"; + for (auto iter = queryParams.begin(); iter != queryParams.end(); ++iter) { + if (iter != queryParams.begin()) { + fullUrlStream << L"&"; + } + fullUrlStream << iter->first << L"=" << iter->second; + } + } + return fullUrlStream.str(); +} + +wstring HttpClient::ConvertToWideString(const string &input) +{ + if (input.empty()) { + return L""; + } + int size_needed = MultiByteToWideChar(CP_UTF8, 0, &input[0], (int)input.size(), NULL, 0); + wstring wstrTo(size_needed, 0); + MultiByteToWideChar(CP_UTF8, 0, &input[0], (int)input.size(), &wstrTo[0], size_needed); + return wstrTo; +} + +string HttpClient::ConvertToNarrowString(const wstring &input) +{ + if (input.empty()) { + return ""; + } + int size_needed = WideCharToMultiByte(CP_UTF8, 0, &input[0], (int)input.size(), NULL, 0, NULL, NULL); + string strTo(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, &input[0], (int)input.size(), &strTo[0], size_needed, NULL, NULL); + return strTo; +} + +map HttpClient::ConvertMapToWideString(const map &inputMap) +{ + map outputMap; + for (const auto &kv : inputMap) { + outputMap[ConvertToWideString(kv.first)] = ConvertToWideString(kv.second); + } + return outputMap; +} diff --git a/VortexEditor/HttpClient.h b/VortexEditor/HttpClient.h new file mode 100644 index 0000000..5419ccd --- /dev/null +++ b/VortexEditor/HttpClient.h @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include + +class HttpClient +{ +public: + HttpClient(const std::string &userAgent); + std::string SendRequest(const std::string &host, const std::string &path, + const std::string &method = "GET", + const std::map &headers = {}, + const std::string &requestData = "", + const std::map &queryParams = {}); + +private: + std::wstring userAgent; + bool useHttps; + + std::wstring BuildFullPath(const std::wstring &path, const std::map &queryParams); + static std::wstring ConvertToWideString(const std::string &input); + static std::string ConvertToNarrowString(const std::wstring &input); + static std::map ConvertMapToWideString(const std::map &inputMap); +}; diff --git a/VortexEditor/VortexChromaLink.cpp b/VortexEditor/VortexChromaLink.cpp new file mode 100644 index 0000000..538cccb --- /dev/null +++ b/VortexEditor/VortexChromaLink.cpp @@ -0,0 +1,229 @@ +#include "VortexChromaLink.h" +#include "VortexEditor.h" +#include "EditorConfig.h" + +#include "Colors/Colorset.h" +#include "Colors/Colortypes.h" +#include "Modes/Mode.h" + +#include "resource.h" + +#include "Serial/Compression.h" +#include "VortexPort.h" + +#define CHROMALINK_PULL_ID 58001 +#define CHROMALINK_PUSH_ID 58002 + +using namespace std; + +VortexChromaLink::VortexChromaLink() : + m_isOpen(false), + m_hIcon(nullptr), + m_chromaLinkWindow() +{ +} + +VortexChromaLink::~VortexChromaLink() +{ + DestroyIcon(m_hIcon); +} + +// initialize the color picker +bool VortexChromaLink::init(HINSTANCE hInst) +{ + // the color picker + m_chromaLinkWindow.init(hInst, "Vortex Chroma Link", BACK_COL, 369, 242, this); + m_chromaLinkWindow.setVisible(false); + m_chromaLinkWindow.setCloseCallback(hideGUICallback); + m_chromaLinkWindow.installLoseFocusCallback(loseFocusCallback); + + // create stuff + + HFONT hFont = CreateFont(15, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, + FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial"); + //SendMessage(m_customColorsLabel.hwnd(), WM_SETFONT, WPARAM(hFont), TRUE); + + m_pullButton.init(hInst, m_chromaLinkWindow, "Pull Duo", BACK_COL, + 64, 28, 10, 10, CHROMALINK_PULL_ID, pullCallback); + m_pushButton.init(hInst, m_chromaLinkWindow, "Push Duo", BACK_COL, + 64, 28, 10, 40, CHROMALINK_PUSH_ID, pushCallback); + + // apply the icon + m_hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1)); + SendMessage(m_chromaLinkWindow.hwnd(), WM_SETICON, ICON_BIG, (LPARAM)m_hIcon); + + return true; +} + +void VortexChromaLink::run() +{ +} + +void VortexChromaLink::show() +{ + if (m_isOpen) { + return; + } + m_chromaLinkWindow.setVisible(true); + m_chromaLinkWindow.setEnabled(true); + m_isOpen = true; +} + +void VortexChromaLink::hide() +{ + if (!m_isOpen) { + return; + } + if (m_chromaLinkWindow.isVisible()) { + m_chromaLinkWindow.setVisible(false); + } + if (m_chromaLinkWindow.isEnabled()) { + m_chromaLinkWindow.setEnabled(false); + } + for (uint32_t i = 0; i < 8; ++i) { + //g_pEditor->m_colorSelects[i].setSelected(false); + //g_pEditor->m_colorSelects[i].redraw(); + } + m_isOpen = false; +} + +void VortexChromaLink::loseFocus() +{ +} + +void VortexChromaLink::pullDuoMode() +{ + VortexPort *port = nullptr; + if (!g_pEditor->isConnected() || !g_pEditor->getCurPort(&port)) { + return; + } + ByteStream headerBuffer; + // now immediately tell it what to do + port->writeData(EDITOR_VERB_PULL_CHROMA_HDR); + headerBuffer.clear(); + if (!port->readByteStream(headerBuffer) || !headerBuffer.size()) { + debug("Couldn't read anything"); + return; + } + // now send the done message + port->writeData(EDITOR_VERB_PULL_MODES_DONE); + //g_pEditor->m_vortex.matchLedCount(stream, false); + //g_pEditor->m_vortex.setModes(stream); + // wait for the ack + port->expectData(EDITOR_VERB_PULL_CHROMA_HDR_ACK); + + struct HeaderData + { + uint8_t vMajor; + uint8_t vMinor; + uint8_t globalFlags; + uint8_t brightness; + uint8_t numModes; + }; + // quick way to interpret the data + HeaderData *headerData = (HeaderData *)headerBuffer.data(); + if (!headerData) { + return; + } + if (headerData->vMajor != 1 || headerData->vMinor != 2) { + return; + } + g_pEditor->m_vortex.setLedCount(2); + g_pEditor->m_vortex.engine().modes().clearModes(); + for (uint8_t i = 0; i < headerData->numModes; ++i) { + ByteStream modeBuffer; + // tell it to send a mode + port->writeData(EDITOR_VERB_PULL_CHROMA_MODE); + // it's ready for the mode idx + port->expectData(EDITOR_VERB_READY); + // send the mode idx + port->writeData((uint8_t *)&i, 1); + // read the mode + modeBuffer.clear(); + if (!port->readByteStream(modeBuffer) || !modeBuffer.size()) { + debug("Couldn't read anything"); + return; + } + // now send the done message + port->writeData(EDITOR_VERB_PULL_MODES_DONE); + // wait for the ack from the gloves + port->expectData(EDITOR_VERB_PULL_CHROMA_MODE_ACK); + Mode newMode(g_pEditor->m_engine); + newMode.unserialize(modeBuffer); + // add the mode + g_pEditor->m_vortex.addMode(&newMode); + } + // refresh the mode list + g_pEditor->refreshModeList(); + // demo the current mode + g_pEditor->demoCurMode(); +} + +void VortexChromaLink::pushDuoMode() +{ + VortexPort *port = nullptr; + if (!g_pEditor->isConnected() || !g_pEditor->getCurPort(&port)) { + return; + } + // now immediately tell it what to do + port->writeData(EDITOR_VERB_PUSH_CHROMA_HDR); + // wait for the ready + port->expectData(EDITOR_VERB_READY); + // send the header + struct HeaderData + { + uint8_t vMajor; + uint8_t vMinor; + uint8_t globalFlags; + uint8_t brightness; + uint8_t numModes; + }; + // quick way to interpret the data + HeaderData headerData; + headerData.vMajor = 1; + headerData.vMinor = 2; + headerData.globalFlags = 0; + headerData.brightness = 255; + headerData.numModes = g_pEditor->m_engine.modes().numModes(); + // max 9 modes on duo + if (headerData.numModes > 9) { + headerData.numModes = 9; + } + ByteStream headerBuffer(sizeof(headerData), (const uint8_t *)&headerData); + port->writeData(headerBuffer); + port->expectData(EDITOR_VERB_PUSH_CHROMA_HDR_ACK); + // backup the mode idx in the engine + uint8_t oldModeIdx = g_pEditor->m_engine.modes().curModeIndex(); + g_pEditor->m_engine.modes().setCurMode(0); + for (uint8_t i = 0; i < headerData.numModes; ++i) { + ByteStream modeBuffer; + // tell it to send a mode + port->writeData(EDITOR_VERB_PUSH_CHROMA_MODE); + // it's ready for the mode idx + port->expectData(EDITOR_VERB_READY); + // send the mode idx + port->writeData((uint8_t *)&i, 1); + // wait till it's ready for the mode + port->expectData(EDITOR_VERB_READY); + // grab the current mode from the engine + Mode *cur = g_pEditor->m_engine.modes().curMode(); + if (cur) { + // serialize it to the mode buffer + cur->serialize(modeBuffer); + } + modeBuffer.recalcCRC(); + // send the mode + port->writeData(modeBuffer); + // wait for the ack + port->expectData(EDITOR_VERB_PULL_CHROMA_MODE_ACK); + // iterate to the next mode + g_pEditor->m_engine.modes().nextMode(); + } + // restore the mode idx in the engine since we changed it + g_pEditor->m_engine.modes().setCurMode(oldModeIdx); + // refresh the mode list + g_pEditor->refreshModeList(); + // demo the current mode + g_pEditor->demoCurMode(); +} diff --git a/VortexEditor/VortexChromaLink.h b/VortexEditor/VortexChromaLink.h new file mode 100644 index 0000000..9ef87ab --- /dev/null +++ b/VortexEditor/VortexChromaLink.h @@ -0,0 +1,66 @@ +#pragma once + +// windows includes +#include + +// gui includes +#include "GUI/VChildwindow.h" +#include "GUI/VColorSelect.h" +#include "GUI/VSelectBox.h" +#include "GUI/VComboBox.h" +#include "GUI/VTextBox.h" +#include "GUI/VButton.h" +#include "GUI/VLabel.h" + +#include "Colors/Colortypes.h" + +class VortexChromaLink +{ +public: + VortexChromaLink(); + ~VortexChromaLink(); + + // initialize the test framework + bool init(HINSTANCE hInstance); + // run the mode randomizer + void run(); + + // show/hide the mode randomizer window + void show(); + void hide(); + void loseFocus(); + void pullDuoMode(); + void pushDuoMode(); + + bool isOpen() const { return m_isOpen; } + + HWND hwnd() const { return m_chromaLinkWindow.hwnd(); } + +private: + // ================================== + // Mode Randomizer GUI + static void hideGUICallback(void *pthis, VWindow *window) { + ((VortexChromaLink *)pthis)->hide(); + } + static void loseFocusCallback(void *pthis, VWindow *window) { + ((VortexChromaLink *)pthis)->loseFocus(); + } + static void pullCallback(void *pthis, VWindow *window) { + ((VortexChromaLink *)pthis)->pullDuoMode(); + } + static void pushCallback(void *pthis, VWindow *window) { + ((VortexChromaLink *)pthis)->pushDuoMode(); + } + + bool m_isOpen; + + HICON m_hIcon; + + // child window for mode randomizer tool + VChildWindow m_chromaLinkWindow; + + // pull from the connected duo via chromadeck + VButton m_pullButton; + VButton m_pushButton; + +}; diff --git a/VortexEditor/VortexCommunityBrowser.cpp b/VortexEditor/VortexCommunityBrowser.cpp new file mode 100644 index 0000000..4b53250 --- /dev/null +++ b/VortexEditor/VortexCommunityBrowser.cpp @@ -0,0 +1,209 @@ +#include "VortexCommunityBrowser.h" +#include "VortexEditor.h" +#include "EditorConfig.h" + +#include "Colors/Colorset.h" +#include "Colors/Colortypes.h" + +#include "resource.h" + +#include "Serial/Compression.h" + +#include "HttpClient.h" + +#include +#include + +#pragma comment(lib, "winhttp.lib") + +#define PREVIEW_ID 55501 +#define PATTERN_STRIP_ID 55601 + +#define NEXT_PAGE_ID 55705 +#define PREV_PAGE_ID 55706 +#define PAGE_LABEL_ID 55707 + +// number of modes requested and displayed on each page +#define MODES_PER_PAGE 15 + +using namespace std; + +VortexCommunityBrowser::VortexCommunityBrowser() : + m_hThread(nullptr), + m_hInstance(nullptr), + m_isOpen(false), + m_hIcon(nullptr), + m_mutex(nullptr), + m_communityBrowserWindow(), + m_patternStrips(), + m_prevPageButton(), + m_nextPageButton(), + m_pageLabel(), + m_curPage(0), + m_lastPage(false) +{ +} + +VortexCommunityBrowser::~VortexCommunityBrowser() +{ + DestroyIcon(m_hIcon); +} + +// initialize the color picker +bool VortexCommunityBrowser::init(HINSTANCE hInst) +{ + m_hInstance = hInst; + + // the color picker + m_communityBrowserWindow.init(hInst, "Vortex Community Browser", BACK_COL, 420, 690, this); + m_communityBrowserWindow.setVisible(false); + m_communityBrowserWindow.setCloseCallback(hideGUICallback); + m_communityBrowserWindow.installLoseFocusCallback(loseFocusCallback); + + m_prevPageButton.init(hInst, m_communityBrowserWindow, "Prev", BACK_COL, + 64, 32, 100, 600, NEXT_PAGE_ID, prevPageCallback); + m_nextPageButton.init(hInst, m_communityBrowserWindow, "Next", BACK_COL, + 64, 32, 256, 600, PREV_PAGE_ID, nextPageCallback); + m_pageLabel.init(hInst, m_communityBrowserWindow, "1 / 1", BACK_COL, + 64, 32, 195, 600, PAGE_LABEL_ID, nullptr); + + // create stuff + HFONT hFont = CreateFont(15, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, + FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial"); + //SendMessage(m_customColorsLabel.hwnd(), WM_SETFONT, WPARAM(hFont), TRUE); + + // apply the icon + m_hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1)); + SendMessage(m_communityBrowserWindow.hwnd(), WM_SETICON, ICON_BIG, (LPARAM)m_hIcon); + + // 15 modes per page + for (uint32_t i = 0; i < MODES_PER_PAGE; ++i) { + unique_ptr strip = make_unique(m_hInstance, + m_communityBrowserWindow, "", BACK_COL, + 370, 32, 16, 16 + (i * 38), 2, json(), PATTERN_STRIP_ID + i, nullptr); + m_patternStrips.push_back(move(strip)); + } + + m_hThread = CreateThread(NULL, 0, backgroundLoader, this, 0, NULL); + + return true; +} + +DWORD __stdcall VortexCommunityBrowser::backgroundLoader(void *pthis) +{ + VortexCommunityBrowser *browser = (VortexCommunityBrowser *)pthis; + // load the first two pages + browser->loadPage(0, false); + browser->loadPage(1, false); + CloseHandle(browser->m_hThread); + browser->m_hThread = nullptr; + return 0; +} + +void VortexCommunityBrowser::show() +{ + if (m_isOpen) { + return; + } + m_communityBrowserWindow.setVisible(true); + m_communityBrowserWindow.setEnabled(true); + for (uint32_t i = 0; i < MODES_PER_PAGE; ++i) { + m_patternStrips[i]->setActive(true); + } + m_isOpen = true; +} + +void VortexCommunityBrowser::hide() +{ + if (!m_isOpen) { + return; + } + if (m_communityBrowserWindow.isVisible()) { + m_communityBrowserWindow.setVisible(false); + } + if (m_communityBrowserWindow.isEnabled()) { + m_communityBrowserWindow.setEnabled(false); + } + for (uint32_t i = 0; i < 8; ++i) { + g_pEditor->m_colorSelects[i].setSelected(false); + g_pEditor->m_colorSelects[i].redraw(); + } + for (uint32_t i = 0; i < MODES_PER_PAGE; ++i) { + m_patternStrips[i]->setActive(false); + } + m_isOpen = false; +} + +void VortexCommunityBrowser::loseFocus() +{ +} + +json VortexCommunityBrowser::fetchModesJson(uint32_t page, uint32_t pageSize) +{ + HttpClient httpClient("VortexEditor/1.0"); + json result; + try { + map queryParams = { + { "page", to_string(page) }, + { "pageSize", to_string(pageSize) }, + }; + string jsonResponse = httpClient.SendRequest("vortex.community", "/pats/json", "GET", {}, "", queryParams); + // Parse and return the JSON object + result = json::parse(jsonResponse); + } catch (const exception &e) { + cerr << "Exception caught: " << e.what() << endl; + } + return result; +} + +bool VortexCommunityBrowser::loadCurPage(bool active) +{ + return loadPage(m_curPage, active); +} + +bool VortexCommunityBrowser::loadPage(uint32_t page, bool active) +{ + // if the page hasn't been loaded yet + if (m_communityModes.size() <= m_curPage) { + // fetch json of modes from community api + try { + // cache the page of data + m_communityModes.push_back(fetchModesJson(m_curPage + 1, MODES_PER_PAGE)); + } catch (...) { + return false; + } + // Verify if 'data' is an array + if (!m_communityModes[m_curPage].contains("data")) { + cerr << "'data' is not an array or does not exist" << endl; + return false; + } + } + for (uint32_t i = 0; i < MODES_PER_PAGE; ++i) { + auto mode = m_communityModes[m_curPage]["data"][i]; + m_patternStrips[i]->loadJson(mode); + m_patternStrips[i]->setActive(active); + } + uint32_t numPages = m_communityModes[m_curPage]["pages"]; + m_lastPage = (m_curPage == (numPages - 1)); + m_pageLabel.setText(to_string(m_curPage + 1) + " / " + to_string(numPages)); + return true; +} + +bool VortexCommunityBrowser::prevPage() +{ + if (!m_curPage) { + return false; + } + m_curPage--; + return loadCurPage(); +} + +bool VortexCommunityBrowser::nextPage() +{ + if (m_lastPage) { + return false; + } + m_curPage++; + return loadCurPage(); +} diff --git a/VortexEditor/VortexCommunityBrowser.h b/VortexEditor/VortexCommunityBrowser.h new file mode 100644 index 0000000..c116eaf --- /dev/null +++ b/VortexEditor/VortexCommunityBrowser.h @@ -0,0 +1,92 @@ +#pragma once + +// windows includes +#include + +// gui includes +#include "GUI/VChildwindow.h" +#include "GUI/VPatternStrip.h" +#include "GUI/VSelectBox.h" +#include "GUI/VComboBox.h" +#include "GUI/VTextBox.h" +#include "GUI/VButton.h" +#include "GUI/VLabel.h" + +#include "Colors/Colortypes.h" + +// engine includes +#include "VortexLib.h" + +#include "json.hpp" + +class VortexCommunityBrowser +{ +public: + VortexCommunityBrowser(); + ~VortexCommunityBrowser(); + + // initialize the test framework + bool init(HINSTANCE hInstance); + + // show/hide the mode randomizer window + void show(); + void hide(); + void loseFocus(); + json fetchModesJson(uint32_t page = 1, uint32_t pageSize = 15); + bool loadCurPage(bool active = true); + bool loadPage(uint32_t page, bool active = true); + bool prevPage(); + bool nextPage(); + + bool isOpen() const { return m_isOpen; } + HWND hwnd() const { return m_communityBrowserWindow.hwnd(); } + +private: + // ================================== + // Mode Randomizer GUI + static void hideGUICallback(void *pthis, VWindow *window) { + ((VortexCommunityBrowser *)pthis)->hide(); + } + static void loseFocusCallback(void *pthis, VWindow *window) { + ((VortexCommunityBrowser *)pthis)->loseFocus(); + } + static void prevPageCallback(void *pthis, VWindow *window) { + ((VortexCommunityBrowser *)pthis)->prevPage(); + } + static void nextPageCallback(void *pthis, VWindow *window) { + ((VortexCommunityBrowser *)pthis)->nextPage(); + } + + static DWORD __stdcall backgroundLoader(void *pthis); + // a handle to the thread that initializes in the background + HANDLE m_hThread; + + HINSTANCE m_hInstance; + + bool m_isOpen; + + HICON m_hIcon; + + // modes fetched from community api + std::vector m_communityModes; + + // mutex to synchronize access to vortex engine + HANDLE m_mutex; + // thread that runs the community browser vortex engine instance + //HANDLE m_runThreadId; + + // child window for mode randomizer tool + VChildWindow m_communityBrowserWindow; + // preview of color + std::vector> m_patternStrips; + + // next/prev page buttons + VButton m_prevPageButton; + VButton m_nextPageButton; + VLabel m_pageLabel; + + // the current page of the browser + uint32_t m_curPage; + // whether we're on the last page (received all responses) + bool m_lastPage; +}; \ No newline at end of file diff --git a/VortexEditor/VortexEditor.cpp b/VortexEditor/VortexEditor.cpp index d88ed05..0d5f1f3 100644 --- a/VortexEditor/VortexEditor.cpp +++ b/VortexEditor/VortexEditor.cpp @@ -63,6 +63,7 @@ VortexEditor::VortexEditor() : m_portList(), m_accelTable(), m_lastClickedColor(0), + m_scanPortsThread(nullptr), m_window(), m_portSelection(), m_pushButton(), @@ -208,7 +209,8 @@ bool VortexEditor::init(HINSTANCE hInst) m_window.addCallback(ID_EDIT_COPY_COLOR_SET_TO_ALL, handleMenusCallback); m_window.addCallback(ID_EDIT_COPY_PATTERN_TO_ALL, handleMenusCallback); m_window.addCallback(ID_HELP_ABOUT, handleMenusCallback); - m_window.addCallback(ID_HELP_HELP, handleMenusCallback); + m_window.addCallback(ID_HELP_TUTORIAL, handleMenusCallback); + m_window.addCallback(ID_HELP_WIKI, handleMenusCallback); m_window.addCallback(ID_EDIT_COPY_COLORSET, handleMenusCallback); m_window.addCallback(ID_EDIT_PASTE_COLORSET, handleMenusCallback); m_window.addCallback(ID_EDIT_CLEAR_PATTERN, handleMenusCallback); @@ -224,17 +226,49 @@ bool VortexEditor::init(HINSTANCE hInst) m_window.addCallback(ID_FILE_IMPORT, handleMenusCallback); m_window.addCallback(ID_FILE_EXPORT, handleMenusCallback); m_window.addCallback(ID_TOOLS_COLOR_PICKER, handleMenusCallback); + m_window.addCallback(ID_TOOLS_MODE_RANDOMIZER, handleMenusCallback); + m_window.addCallback(ID_TOOLS_COMMUNITY_BROWSER, handleMenusCallback); + m_window.addCallback(ID_TOOLS_CHROMALINK, handleMenusCallback); + m_window.addCallback(ID_CHOOSE_DEVICE_ORBIT, handleMenusCallback); + m_window.addCallback(ID_CHOOSE_DEVICE_HANDLE, handleMenusCallback); + m_window.addCallback(ID_CHOOSE_DEVICE_GLOVES, handleMenusCallback); + m_window.addCallback(ID_CHOOSE_DEVICE_CHROMADECK, handleMenusCallback); + m_window.addCallback(ID_CHOOSE_DEVICE_SPARK, handleMenusCallback); + m_window.addCallback(ID_CHOOSE_DEVICE_DUO, handleMenusCallback); // add user callback for refreshes m_window.installUserCallback(WM_REFRESH_UI, refreshWindowCallback); m_window.installUserCallback(WM_TEST_CONNECT, connectTestFrameworkCallback); m_window.installUserCallback(WM_TEST_DISCONNECT, disconnectTestFrameworkCallback); - // initialize the color picker window - m_colorPicker.init(hInst); + // current window pos for child window init RECT pos; GetWindowRect(m_window.hwnd(), &pos); - SetWindowPos(m_colorPicker.hwnd(), 0, pos.left - 400, pos.top-200, 0, 0, SWP_NOSIZE); + + // initialize the color picker window + m_colorPicker.init(hInst); + SetWindowPos(m_colorPicker.hwnd(), 0, pos.left - 422, pos.top-200, 0, 0, SWP_NOSIZE); + + // initialize the mode randomizer window + m_modeRandomizer.init(hInst); + SetWindowPos(m_modeRandomizer.hwnd(), 0, pos.left + 50, pos.top-300, 0, 0, SWP_NOSIZE); + + // initialize the community browser window + m_communityBrowser.init(hInst); + SetWindowPos(m_communityBrowser.hwnd(), 0, pos.right + 2, pos.top - 200, 0, 0, SWP_NOSIZE); + + // initialize the chromalink + m_chromalink.init(hInst); + SetWindowPos(m_chromalink.hwnd(), 0, pos.left + 200, pos.bottom - 50, 0, 0, SWP_NOSIZE); + + // initialize the tutorial + m_tutorial.init(hInst); + SetWindowPos(m_tutorial.hwnd(), 0, pos.left + 180, pos.top + 50, 0, 0, SWP_NOSIZE); + + // show subwindows + //m_colorPicker.show(); + //m_modeRandomizer.show(); + //m_communityBrowser.show(); // apply the icon m_hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1)); @@ -301,7 +335,7 @@ bool VortexEditor::init(HINSTANCE hInst) m_window.installDeviceCallback(deviceChangeCallback); // check for connected devices - scanPorts(); + m_scanPortsThread = CreateThread(NULL, 0, scanPortsThread, this, 0, NULL); // trigger a ui refresh refreshModeList(); @@ -309,6 +343,15 @@ bool VortexEditor::init(HINSTANCE hInst) return true; } +DWORD __stdcall VortexEditor::scanPortsThread(void *arg) +{ + VortexEditor *editor = (VortexEditor *)arg; + editor->scanPorts(); + CloseHandle(editor->m_scanPortsThread); + editor->m_scanPortsThread = nullptr; + return 0; +} + void VortexEditor::run() { // main message loop @@ -366,8 +409,11 @@ void VortexEditor::handleMenus(uintptr_t hMenu) case ID_HELP_ABOUT: MessageBox(m_window.hwnd(), "Vortex Editor 1.0\nMade by Daniel Fraser and Shane Aronson", "About", 0); break; - case ID_HELP_HELP: - ShellExecute(NULL, "open", "https://github.com/StoneOrbits/VortexEditor/wiki", NULL, NULL, SW_SHOWNORMAL); + case ID_HELP_WIKI: + ShellExecute(NULL, "open", "https://stoneorbits.github.io/VortexEngine/editor.html", NULL, NULL, SW_SHOWNORMAL); + return; + case ID_HELP_TUTORIAL: + beginTutorial(); return; case ID_EDIT_COPY_COLORSET: copyColorset(); @@ -422,6 +468,33 @@ void VortexEditor::handleMenus(uintptr_t hMenu) case ID_TOOLS_COLOR_PICKER: m_colorPicker.show(); return; + case ID_TOOLS_MODE_RANDOMIZER: + m_modeRandomizer.show(); + return; + case ID_TOOLS_COMMUNITY_BROWSER: + m_communityBrowser.show(); + return; + case ID_TOOLS_CHROMALINK: + m_chromalink.show(); + return; + case ID_CHOOSE_DEVICE_ORBIT: + m_vortex.setLedCount(28); + break; + case ID_CHOOSE_DEVICE_HANDLE: + m_vortex.setLedCount(3); + break; + case ID_CHOOSE_DEVICE_GLOVES: + m_vortex.setLedCount(10); + break; + case ID_CHOOSE_DEVICE_CHROMADECK: + m_vortex.setLedCount(20); + break; + case ID_CHOOSE_DEVICE_SPARK: + m_vortex.setLedCount(6); + break; + case ID_CHOOSE_DEVICE_DUO: + m_vortex.setLedCount(2); + break; default: break; } @@ -937,12 +1010,13 @@ void VortexEditor::pull(VWindow *window) debug("Couldn't read anything"); return; } - m_vortex.matchLedCount(stream, false); - m_vortex.setModes(stream); // now send the done message port->writeData(EDITOR_VERB_PULL_MODES_DONE); // wait for the ack from the gloves port->expectData(EDITOR_VERB_PULL_MODES_ACK); + // now set the modes + m_vortex.matchLedCount(stream, false); + m_vortex.setModes(stream); // unserialized all our modes debug("Unserialized %u modes", m_vortex.numModes()); // refresh the mode list @@ -1260,6 +1334,24 @@ void VortexEditor::addMode(VWindow *window) } } +void VortexEditor::addMode(VWindow *window, const Mode *mode) +{ + if (!mode) { + return; + } +#if MAX_MODES != 0 + if (m_vortex.numModes() >= MAX_MODES) { + return; + } +#endif + debug("Adding mode %u", m_vortex.numModes() + 1); + m_vortex.addMode(mode); + m_vortex.setCurMode(m_vortex.numModes() - 1); + m_modeListBox.setSelection(m_vortex.curModeIndex()); + refreshModeList(); + demoCurMode(); +} + void VortexEditor::delMode(VWindow *window) { debug("Deleting mode %u", m_vortex.curModeIndex()); @@ -1895,3 +1987,8 @@ int VortexEditor::getPortListIndex() const } return -1; } + +void VortexEditor::beginTutorial() +{ + m_tutorial.show(); +} diff --git a/VortexEditor/VortexEditor.h b/VortexEditor/VortexEditor.h index 1c1e2aa..acaeb70 100644 --- a/VortexEditor/VortexEditor.h +++ b/VortexEditor/VortexEditor.h @@ -26,6 +26,10 @@ // editor includes #include "VortexColorPicker.h" +#include "VortexModeRandomizer.h" +#include "VortexCommunityBrowser.h" +#include "VortexChromaLink.h" +#include "VortexEditorTutorial.h" #include "ArduinoSerial.h" // stl includes @@ -45,7 +49,10 @@ class Colorset; class VortexEditor { + friend class VortexChromaLink; friend class VortexColorPicker; + friend class VortexModeRandomizer; + friend class VortexCommunityBrowser; public: VortexEditor(); ~VortexEditor(); @@ -60,7 +67,11 @@ class VortexEditor HINSTANCE hInst() const { return m_hInstance; } + void addMode(VWindow *window, const Mode *mode); + private: + static DWORD __stdcall scanPortsThread(void *arg); + // print to the log static void printlog(const char *file, const char *func, int line, const char *msg, ...); @@ -187,6 +198,9 @@ class VortexEditor // get the current pattern selection from the pattern dropdown PatternID patternSelection() const; + // start the interactive tutorial + void beginTutorial(); + // ================================== // Member data @@ -208,6 +222,8 @@ class VortexEditor // keeps track of the last colorset entry selected to support shift+click // which needs to set prevIndex to curIndex upon shift clicking uint32_t m_lastClickedColor; + // thread for scanning the ports for connected devices on init + HANDLE m_scanPortsThread; // ================================== // GUI Members @@ -240,10 +256,14 @@ class VortexEditor VSelectBox m_storageProgress; // ================================== - // Color picker GUI + // Sub-window GUIS // the vortex color picker window VortexColorPicker m_colorPicker; + VortexModeRandomizer m_modeRandomizer; + VortexCommunityBrowser m_communityBrowser; + VortexEditorTutorial m_tutorial; + VortexChromaLink m_chromalink; }; extern VortexEditor *g_pEditor; diff --git a/VortexEditor/VortexEditor.rc b/VortexEditor/VortexEditor.rc index 10b8615..a0158bc 100644 --- a/VortexEditor/VortexEditor.rc +++ b/VortexEditor/VortexEditor.rc @@ -96,17 +96,30 @@ BEGIN POPUP "Tools" BEGIN MENUITEM "Color Picker", ID_TOOLS_COLOR_PICKER + MENUITEM "Mode Randomizer\t(Coming Soon)", ID_TOOLS_MODE_RANDOMIZER, INACTIVE + MENUITEM "Community Browser\t(Coming Soon)", ID_TOOLS_COMMUNITY_BROWSER, INACTIVE + MENUITEM "Chromalink\t(Coming Soon)", ID_TOOLS_CHROMALINK, INACTIVE END POPUP "Options" BEGIN MENUITEM "Transmit to Duo\tctrl+u", ID_OPTIONS_TRANSMIT_DUO MENUITEM "Transmit Infrared\tctrl+i", ID_OPTIONS_TRANSMIT_INFRARED MENUITEM "Receive from Duo\tctrl+k", ID_OPTIONS_RECEIVE_FROM_DUO + POPUP "Set Device" + BEGIN + MENUITEM "Orbit (28)", ID_CHOOSE_DEVICE_ORBIT + MENUITEM "Handle (3)", ID_CHOOSE_DEVICE_HANDLE + MENUITEM "Gloves (10)", ID_CHOOSE_DEVICE_GLOVES + MENUITEM "Chromadeck (20)", ID_CHOOSE_DEVICE_CHROMADECK + MENUITEM "Spark (6)", ID_CHOOSE_DEVICE_SPARK + MENUITEM "Duo (2)", ID_CHOOSE_DEVICE_DUO + END END POPUP "Help" BEGIN MENUITEM "About", ID_HELP_ABOUT - MENUITEM "Help", ID_HELP_HELP + MENUITEM "Tutorial", ID_HELP_TUTORIAL + MENUITEM "Wiki", ID_HELP_WIKI END END @@ -159,6 +172,28 @@ BEGIN END END + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BITMAP1 BITMAP "chromadeck-logo-square-64.bmp" + +IDB_BITMAP2 BITMAP "gloves-logo-square-64.bmp" + +IDB_BITMAP3 BITMAP "handle-logo-square-64.bmp" + +IDB_BITMAP4 BITMAP "orbit-logo-square-64.bmp" + +IDB_BITMAP5 BITMAP "chromadeck-logo-square-green-64.bmp" + +IDB_BITMAP6 BITMAP "gloves-logo-square-green-64.bmp" + +IDB_BITMAP7 BITMAP "handle-logo-square-green-64.bmp" + +IDB_BITMAP8 BITMAP "orbit-logo-square-green-64.bmp" + #endif // English (United Kingdom) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/VortexEditor/VortexEditor.vcxproj b/VortexEditor/VortexEditor.vcxproj index 0a07a3b..3c70671 100644 --- a/VortexEditor/VortexEditor.vcxproj +++ b/VortexEditor/VortexEditor.vcxproj @@ -1,205 +1,235 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {3cbed1a0-74dc-4856-9e0e-7781477906fb} - VortexEditor - 10.0 - - - - Application - true - v143 - MultiByte - - - Application - false - v143 - true - MultiByte - - - Application - true - v143 - MultiByte - - - Application - false - v143 - true - MultiByte - - - - - - - - - - - - - - - - - - - - - true - - - false - - - true - - - false - - - - Level3 - true - PROJECT_NAME_$(SolutionName);WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(ProjectDir);$(ProjectDir)\EngineDependencies;$(ProjectDir)\VortexEngine\VortexEngine\src\;$(ProjectDir)\VortexEngine\VortexEngine\VortexLib\ - - - Windows - true - VortexEngine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(OutputPath)\;%(AdditionalLibraryDirectories) - - - - - Level3 - true - true - true - PROJECT_NAME_$(SolutionName);WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(ProjectDir);$(ProjectDir)\EngineDependencies;$(ProjectDir)\VortexEngine\VortexEngine\src\;$(ProjectDir)\VortexEngine\VortexEngine\VortexLib\ - MultiThreaded - Disabled - - - Windows - true - true - true - VortexEngine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(OutputPath)\;%(AdditionalLibraryDirectories) - - - - - Level3 - true - PROJECT_NAME_$(SolutionName);_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(ProjectDir);$(ProjectDir)\EngineDependencies;$(ProjectDir)\VortexEngine\VortexEngine\src\;$(ProjectDir)\VortexEngine\VortexEngine\VortexLib\ - - - Windows - true - VortexEngine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(OutputPath)\;%(AdditionalLibraryDirectories) - - - - - Level3 - true - true - true - PROJECT_NAME_$(SolutionName);NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - $(ProjectDir);$(ProjectDir)\EngineDependencies;$(ProjectDir)\VortexEngine\VortexEngine\src\;$(ProjectDir)\VortexEngine\VortexEngine\VortexLib\ - MultiThreaded - Disabled - - - Windows - true - true - true - VortexEngine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - $(OutputPath)\;%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {3cbed1a0-74dc-4856-9e0e-7781477906fb} + VortexEditor + 10.0 + + + + Application + true + v143 + MultiByte + + + Application + false + v143 + true + MultiByte + + + Application + true + v143 + MultiByte + + + Application + false + v143 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + PROJECT_NAME_$(SolutionName);WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProjectDir);$(ProjectDir)\EngineDependencies;$(ProjectDir)\VortexEngine\VortexEngine\src\;$(ProjectDir)\VortexEngine\VortexEngine\VortexLib\ + + + Windows + true + VortexEngine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutputPath)\;%(AdditionalLibraryDirectories) + + + + + Level3 + true + true + true + PROJECT_NAME_$(SolutionName);WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProjectDir);$(ProjectDir)\EngineDependencies;$(ProjectDir)\VortexEngine\VortexEngine\src\;$(ProjectDir)\VortexEngine\VortexEngine\VortexLib\ + MultiThreaded + Disabled + + + Windows + true + true + true + VortexEngine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutputPath)\;%(AdditionalLibraryDirectories) + + + + + Level3 + true + PROJECT_NAME_$(SolutionName);_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProjectDir);$(ProjectDir)\EngineDependencies;$(ProjectDir)\VortexEngine\VortexEngine\src\;$(ProjectDir)\VortexEngine\VortexEngine\VortexLib\ + + + Windows + true + VortexEngine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutputPath)\;%(AdditionalLibraryDirectories) + + + + + Level3 + true + true + true + PROJECT_NAME_$(SolutionName);NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ProjectDir);$(ProjectDir)\EngineDependencies;$(ProjectDir)\VortexEngine\VortexEngine\src\;$(ProjectDir)\VortexEngine\VortexEngine\VortexLib\ + MultiThreaded + Disabled + + + Windows + true + true + true + VortexEngine.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + $(OutputPath)\;%(AdditionalLibraryDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/VortexEditor/VortexEditor.vcxproj.filters b/VortexEditor/VortexEditor.vcxproj.filters index 27a8eee..82367c8 100644 --- a/VortexEditor/VortexEditor.vcxproj.filters +++ b/VortexEditor/VortexEditor.vcxproj.filters @@ -1,142 +1,232 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {b5f8bfdf-76bc-41dc-bbee-fd501300679c} - - - {16a98195-7cb8-4620-81d6-a2f85873808a} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files\GUI - - - Source Files\GUI - - - Source Files\GUI - - - Source Files\GUI - - - Source Files\GUI - - - Source Files\GUI - - - Source Files\GUI - - - Source Files\GUI - - - Source Files\GUI - - - Source Files\GUI - - - Source Files\GUI - - - Source Files\GUI - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\GUI - - - Header Files\GUI - - - Header Files\GUI - - - Header Files\GUI - - - Header Files\GUI - - - Header Files\GUI - - - Header Files\GUI - - - Header Files\GUI - - - Header Files\GUI - - - Header Files\GUI - - - Header Files\GUI - - - Header Files\GUI - - - - - Resource Files - - - - - Resource Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {b5f8bfdf-76bc-41dc-bbee-fd501300679c} + + + {16a98195-7cb8-4620-81d6-a2f85873808a} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\GUI + + + Source Files\GUI + + + Source Files\GUI + + + Source Files\GUI + + + Source Files\GUI + + + Source Files\GUI + + + Source Files\GUI + + + Source Files\GUI + + + Source Files\GUI + + + Source Files\GUI + + + Source Files\GUI + + + Source Files\GUI + + + Source Files + + + Source Files + + + Source Files\GUI + + + Source Files\GUI + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\GUI + + + Header Files\GUI + + + Header Files\GUI + + + Header Files\GUI + + + Header Files\GUI + + + Header Files\GUI + + + Header Files\GUI + + + Header Files\GUI + + + Header Files\GUI + + + Header Files\GUI + + + Header Files\GUI + + + Header Files\GUI + + + Header Files + + + Header Files + + + Header Files\GUI + + + Header Files\GUI + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + \ No newline at end of file diff --git a/VortexEditor/VortexEditorTutorial.cpp b/VortexEditor/VortexEditorTutorial.cpp new file mode 100644 index 0000000..48bc927 --- /dev/null +++ b/VortexEditor/VortexEditorTutorial.cpp @@ -0,0 +1,304 @@ +#include "VortexEditorTutorial.h" +#include "VortexEditor.h" +#include "EditorConfig.h" + +#include "Colors/Colorset.h" +#include "Colors/Colortypes.h" + +#include "resource.h" + +#include "Serial/Compression.h" + +using namespace std; + +VortexEditorTutorial::VortexEditorTutorial() : + m_isOpen(false), + m_hIcon(nullptr), + m_script(), + m_currentScriptIndex(0), + m_nextPressed(false), + m_mutex(nullptr), + m_runThread(nullptr), + m_tutorialWindow(), + m_tutorialStatus(), + m_orbitBitmap(), + m_orbitSelectedBitmap(), + m_orbitSelect(), + m_handlesBitmap(), + m_handlesSelectedBitmap(), + m_handlesSelect(), + m_glovesBitmap(), + m_glovesSelectedBitmap(), + m_glovesSelect(), + m_chromadeckBitmap(), + m_chromadeckSelectedBitmap(), + m_chromadeckSelect(), + m_selectedDevice(SELECTED_NONE) +{ +} + +VortexEditorTutorial::~VortexEditorTutorial() +{ + DestroyIcon(m_hIcon); + if (m_runThread) { + TerminateThread(m_runThread, 0); + WaitForSingleObject(m_runThread, 100); + m_runThread = 0; + } +} + +// initialize the color picker +bool VortexEditorTutorial::init(HINSTANCE hInst) +{ + // the color picker + m_tutorialWindow.init(hInst, "Vortex Editor Tutorial", BACK_COL, 420, 240, this); + m_tutorialWindow.setVisible(false); + m_tutorialWindow.setCloseCallback(hideGUICallback); + m_tutorialWindow.installLoseFocusCallback(loseFocusCallback); + + // status bar + m_tutorialStatus.init(hInst, m_tutorialWindow, "", BACK_COL, 375, 24, 10, 16, 0, nullptr); + m_tutorialStatus.setForeEnabled(true); + m_tutorialStatus.setBackEnabled(true); + m_tutorialStatus.setStatus(RGB(30, 164, 153), "Welcome to the Vortex Editor Tutorial"); + + // load bitmaps for buttons + m_chromadeckBitmap = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP1), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + m_glovesBitmap = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP2), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + m_handlesBitmap = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP3), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + m_orbitBitmap = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP4), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + + m_chromadeckSelectedBitmap = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP5), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + m_glovesSelectedBitmap = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP6), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + m_handlesSelectedBitmap = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP7), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + m_orbitSelectedBitmap = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP8), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + + // the orbit select + m_orbitSelect.init(hInst, m_tutorialWindow, "orbit", RGB(20, 20, 20), 64, 64, 34, 100, 123123, selectOrbitCallback); + m_orbitSelect.setVisible(true); + m_orbitSelect.setEnabled(true); + m_orbitSelect.setBackground(m_orbitBitmap); + m_orbitSelect.setHoverBackground(m_orbitSelectedBitmap); + m_orbitSelect.setBackgroundTransparency(true); + m_orbitSelect.setDrawCircle(false); + m_orbitSelect.setDrawHLine(false); + m_orbitSelect.setDrawVLine(false); + m_orbitSelect.setBorderSize(0); + + // the handles select + m_handlesSelect.init(hInst, m_tutorialWindow, "handles", BACK_COL, 64, 64, 124, 100, 123124, selectHandleCallback); + m_handlesSelect.setVisible(true); + m_handlesSelect.setEnabled(true); + m_handlesSelect.setBackground(m_handlesBitmap); + m_handlesSelect.setHoverBackground(m_handlesSelectedBitmap); + m_handlesSelect.setBackgroundTransparency(false); + m_handlesSelect.setDrawCircle(false); + m_handlesSelect.setDrawHLine(false); + m_handlesSelect.setDrawVLine(false); + m_handlesSelect.setBorderSize(0); + + // the gloves select + m_glovesSelect.init(hInst, m_tutorialWindow, "gloves", BACK_COL, 64, 64, 214, 100, 123125, selectGlovesCallback); + m_glovesSelect.setVisible(true); + m_glovesSelect.setEnabled(true); + m_glovesSelect.setBackground(m_glovesBitmap); + m_glovesSelect.setHoverBackground(m_glovesSelectedBitmap); + m_glovesSelect.setBackgroundTransparency(false); + m_glovesSelect.setDrawCircle(false); + m_glovesSelect.setDrawHLine(false); + m_glovesSelect.setDrawVLine(false); + m_glovesSelect.setBorderSize(0); + + // the chromadeck select + m_chromadeckSelect.init(hInst, m_tutorialWindow, "chromadeck", BACK_COL, 64, 64, 304, 100, 123126, selectChromadeckCallback); + m_chromadeckSelect.setVisible(true); + m_chromadeckSelect.setEnabled(true); + m_chromadeckSelect.setBackground(m_chromadeckBitmap); + m_chromadeckSelect.setHoverBackground(m_chromadeckSelectedBitmap); + m_chromadeckSelect.setBackgroundTransparency(false); + m_chromadeckSelect.setDrawCircle(false); + m_chromadeckSelect.setDrawHLine(false); + m_chromadeckSelect.setDrawVLine(false); + m_chromadeckSelect.setBorderSize(0); + + // create stuff + HFONT hFont = CreateFont(15, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, + FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial"); + //SendMessage(m_customColorsLabel.hwnd(), WM_SETFONT, WPARAM(hFont), TRUE); + + // apply the icon + m_hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1)); + SendMessage(m_tutorialWindow.hwnd(), WM_SETICON, ICON_BIG, (LPARAM)m_hIcon); + + m_script = { + "Welcome to the Vortex Editor Tutorial", + "Which Vortex Device will you be using?", + }; + + return true; +} + +void VortexEditorTutorial::run() +{ +} + +void VortexEditorTutorial::show() +{ + if (m_isOpen) { + return; + } + m_tutorialWindow.setVisible(true); + m_tutorialWindow.setEnabled(true); + m_isOpen = true; + + if (!m_runThread) { + // start the runthread + m_runThread = CreateThread(NULL, 0, runThread, this, 0, NULL); + } +} + +void VortexEditorTutorial::hide() +{ + if (!m_isOpen) { + return; + } + if (m_tutorialWindow.isVisible()) { + m_tutorialWindow.setVisible(false); + } + if (m_tutorialWindow.isEnabled()) { + m_tutorialWindow.setEnabled(false); + } + m_isOpen = false; +} + +void VortexEditorTutorial::loseFocus() +{ +} + +DWORD __stdcall VortexEditorTutorial::runThread(void *arg) +{ + VortexEditorTutorial *editorTutorial = (VortexEditorTutorial *)arg; + while (editorTutorial->m_currentScriptIndex < (editorTutorial->m_script.size() - 1)) { + WaitForSingleObject(editorTutorial->m_mutex, INFINITE); + if (editorTutorial->m_nextPressed) { + editorTutorial->m_nextPressed = false; + editorTutorial->m_currentScriptIndex++; + if (editorTutorial->m_currentScriptIndex >= editorTutorial->m_script.size()) { + ReleaseMutex(editorTutorial->m_mutex); + break; + } + } + ReleaseMutex(editorTutorial->m_mutex); + + const std::string &message = editorTutorial->m_script[editorTutorial->m_currentScriptIndex]; + std::string msg; + for (size_t i = 0; i < message.length(); ++i) { + Sleep(30); // Simulate typing delay + msg += message[i]; + // Place your method to update the text in UI here + editorTutorial->UpdateTextDisplay(msg.c_str()); + WaitForSingleObject(editorTutorial->m_mutex, INFINITE); + if (editorTutorial->m_nextPressed) { + ReleaseMutex(editorTutorial->m_mutex); + break; // Move to the next message if "next" is pressed + } + ReleaseMutex(editorTutorial->m_mutex); + } + + // Wait a bit before proceeding to the next message automatically + Sleep(1000); // Adjust as needed + editorTutorial->NextMessageAutomatically(); + } + + return 0; +} + +void VortexEditorTutorial::StartTutorial() +{ + m_currentScriptIndex = 0; + // Start the thread that displays the first message + m_runThread = CreateThread(nullptr, 0, runThread, this, 0, nullptr); +} + +void VortexEditorTutorial::NextMessage() +{ + // Advances to the next message when the 'next' button is clicked + WaitForSingleObject(m_mutex, INFINITE); + if (m_currentScriptIndex + 1 < m_script.size()) { + m_nextPressed = true; // Signal to proceed to the next message + } + ReleaseMutex(m_mutex); +} + +void VortexEditorTutorial::UpdateTextDisplay(const char *text) +{ + m_tutorialStatus.setText(text); +} + +void VortexEditorTutorial::NextMessageAutomatically() +{ + // Automatically proceed to the next message or handle end of script + WaitForSingleObject(m_mutex, INFINITE); + if (!m_nextPressed && m_currentScriptIndex + 1 < m_script.size()) { + m_nextPressed = true; + } + ReleaseMutex(m_mutex); +} + +void VortexEditorTutorial::selectOrbit(uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent) +{ + if (sevent != VSelectBox::SelectEvent::SELECT_RELEASE) { + return; + } + + //m_orbitSelect.setVisible(false); + m_handlesSelect.setVisible(false); + m_glovesSelect.setVisible(false); + m_chromadeckSelect.setVisible(false); + + m_selectedDevice = SELECTED_ORBIT; +} + +void VortexEditorTutorial::selectHandle(uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent) +{ + if (sevent != VSelectBox::SelectEvent::SELECT_RELEASE) { + return; + } + + m_orbitSelect.setVisible(false); + //m_handlesSelect.setVisible(false); + m_glovesSelect.setVisible(false); + m_chromadeckSelect.setVisible(false); + + m_selectedDevice = SELECTED_HANDLE; +} + +void VortexEditorTutorial::selectGloves(uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent) +{ + if (sevent != VSelectBox::SelectEvent::SELECT_RELEASE) { + return; + } + + m_orbitSelect.setVisible(false); + m_handlesSelect.setVisible(false); + //m_glovesSelect.setVisible(false); + m_chromadeckSelect.setVisible(false); + + m_selectedDevice = SELECTED_GLOVES; +} + +void VortexEditorTutorial::selectChromadeck(uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent) +{ + if (sevent != VSelectBox::SelectEvent::SELECT_RELEASE) { + return; + } + + m_orbitSelect.setVisible(false); + m_handlesSelect.setVisible(false); + m_glovesSelect.setVisible(false); + //m_chromadeckSelect.setVisible(false); + + m_selectedDevice = SELECTED_CHROMADECK; +} + diff --git a/VortexEditor/VortexEditorTutorial.h b/VortexEditor/VortexEditorTutorial.h new file mode 100644 index 0000000..0338667 --- /dev/null +++ b/VortexEditor/VortexEditorTutorial.h @@ -0,0 +1,126 @@ +#pragma once + +// windows includes +#include + +// gui includes +#include "GUI/VChildwindow.h" +#include "GUI/VColorSelect.h" +#include "GUI/VSelectBox.h" +#include "GUI/VStatusBar.h" +#include "GUI/VComboBox.h" +#include "GUI/VTextBox.h" +#include "GUI/VButton.h" +#include "GUI/VLabel.h" + +#include "Colors/Colortypes.h" + +#include + +class VortexEditorTutorial +{ +public: + VortexEditorTutorial(); + ~VortexEditorTutorial(); + + // initialize the test framework + bool init(HINSTANCE hInstance); + // run the mode randomizer + void run(); + + // show/hide the mode randomizer window + void show(); + void hide(); + void loseFocus(); + void StartTutorial(); + void NextMessage(); + + void UpdateTextDisplay(const char *text); + void NextMessageAutomatically(); + + bool isOpen() const { return m_isOpen; } + + HWND hwnd() const { return m_tutorialWindow.hwnd(); } + +private: + // ================================== + // Mode Randomizer GUI + static void hideGUICallback(void *pthis, VWindow *window) { + ((VortexEditorTutorial *)pthis)->hide(); + } + static void loseFocusCallback(void *pthis, VWindow *window) { + ((VortexEditorTutorial *)pthis)->loseFocus(); + } + // callbacks for selecting sv and h + static void selectOrbitCallback(void *pthis, uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent) { + ((VortexEditorTutorial *)pthis)->selectOrbit(x, y, sevent); + } + // callbacks for selecting sv and h + static void selectHandleCallback(void *pthis, uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent) { + ((VortexEditorTutorial *)pthis)->selectHandle(x, y, sevent); + } + // callbacks for selecting sv and h + static void selectGlovesCallback(void *pthis, uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent) { + ((VortexEditorTutorial *)pthis)->selectGloves(x, y, sevent); + } + // callbacks for selecting sv and h + static void selectChromadeckCallback(void *pthis, uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent) { + ((VortexEditorTutorial *)pthis)->selectChromadeck(x, y, sevent); + } + + void selectOrbit(uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent); + void selectHandle(uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent); + void selectGloves(uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent); + void selectChromadeck(uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent); + + enum SelectedDevice { + SELECTED_NONE, + + SELECTED_ORBIT, + SELECTED_HANDLE, + SELECTED_GLOVES, + SELECTED_CHROMADECK + }; + + SelectedDevice m_selectedDevice; + + static DWORD __stdcall runThread(void *arg); + + bool m_isOpen; + + HICON m_hIcon; + + std::vector m_script; + uint32_t m_currentScriptIndex; + bool m_nextPressed; + + // mutex that is posted once we're loaded + HANDLE m_mutex; + HANDLE m_runThread; + + // child window for mode randomizer tool + VChildWindow m_tutorialWindow; + + // textbox to print out messages + VStatusBar m_tutorialStatus; + + // the orbit button/selection + HBITMAP m_orbitBitmap; + HBITMAP m_orbitSelectedBitmap; + VSelectBox m_orbitSelect; + + // the handles button/selection + HBITMAP m_handlesBitmap; + HBITMAP m_handlesSelectedBitmap; + VSelectBox m_handlesSelect; + + // the gloves button/selection + HBITMAP m_glovesBitmap; + HBITMAP m_glovesSelectedBitmap; + VSelectBox m_glovesSelect; + + // the chromadeck button/selection + HBITMAP m_chromadeckBitmap; + HBITMAP m_chromadeckSelectedBitmap; + VSelectBox m_chromadeckSelect; +}; diff --git a/VortexEditor/VortexEngine b/VortexEditor/VortexEngine index 6e6017b..9f0dc09 160000 --- a/VortexEditor/VortexEngine +++ b/VortexEditor/VortexEngine @@ -1 +1 @@ -Subproject commit 6e6017b4174498217fd67cc95c0026c904a7398d +Subproject commit 9f0dc090970d070b4e3b21400d45b7d4d1877035 diff --git a/VortexEditor/VortexModeRandomizer.cpp b/VortexEditor/VortexModeRandomizer.cpp new file mode 100644 index 0000000..eae8abe --- /dev/null +++ b/VortexEditor/VortexModeRandomizer.cpp @@ -0,0 +1,84 @@ +#include "VortexModeRandomizer.h" +#include "VortexEditor.h" +#include "EditorConfig.h" + +#include "Colors/Colorset.h" +#include "Colors/Colortypes.h" + +#include "resource.h" + +#include "Serial/Compression.h" + +using namespace std; + +VortexModeRandomizer::VortexModeRandomizer() : + m_isOpen(false), + m_hIcon(nullptr), + m_modeRandomizerWindow() +{ +} + +VortexModeRandomizer::~VortexModeRandomizer() +{ + DestroyIcon(m_hIcon); +} + +// initialize the color picker +bool VortexModeRandomizer::init(HINSTANCE hInst) +{ + // the color picker + m_modeRandomizerWindow.init(hInst, "Vortex Mode Randomizer", BACK_COL, 690, 420, this); + m_modeRandomizerWindow.setVisible(false); + m_modeRandomizerWindow.setCloseCallback(hideGUICallback); + m_modeRandomizerWindow.installLoseFocusCallback(loseFocusCallback); + + // create stuff + + HFONT hFont = CreateFont(15, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, + FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial"); + //SendMessage(m_customColorsLabel.hwnd(), WM_SETFONT, WPARAM(hFont), TRUE); + + // apply the icon + m_hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1)); + SendMessage(m_modeRandomizerWindow.hwnd(), WM_SETICON, ICON_BIG, (LPARAM)m_hIcon); + + return true; +} + +void VortexModeRandomizer::run() +{ +} + +void VortexModeRandomizer::show() +{ + if (m_isOpen) { + return; + } + m_modeRandomizerWindow.setVisible(true); + m_modeRandomizerWindow.setEnabled(true); + m_isOpen = true; +} + +void VortexModeRandomizer::hide() +{ + if (!m_isOpen) { + return; + } + if (m_modeRandomizerWindow.isVisible()) { + m_modeRandomizerWindow.setVisible(false); + } + if (m_modeRandomizerWindow.isEnabled()) { + m_modeRandomizerWindow.setEnabled(false); + } + for (uint32_t i = 0; i < 8; ++i) { + g_pEditor->m_colorSelects[i].setSelected(false); + g_pEditor->m_colorSelects[i].redraw(); + } + m_isOpen = false; +} + +void VortexModeRandomizer::loseFocus() +{ +} + diff --git a/VortexEditor/VortexModeRandomizer.h b/VortexEditor/VortexModeRandomizer.h new file mode 100644 index 0000000..a59e3bd --- /dev/null +++ b/VortexEditor/VortexModeRandomizer.h @@ -0,0 +1,55 @@ +#pragma once + +// windows includes +#include + +// gui includes +#include "GUI/VChildwindow.h" +#include "GUI/VColorSelect.h" +#include "GUI/VSelectBox.h" +#include "GUI/VComboBox.h" +#include "GUI/VTextBox.h" +#include "GUI/VButton.h" +#include "GUI/VLabel.h" + +#include "Colors/Colortypes.h" + +class VortexModeRandomizer +{ +public: + VortexModeRandomizer(); + ~VortexModeRandomizer(); + + // initialize the test framework + bool init(HINSTANCE hInstance); + // run the mode randomizer + void run(); + + // show/hide the mode randomizer window + void show(); + void hide(); + void loseFocus(); + + bool isOpen() const { return m_isOpen; } + + HWND hwnd() const { return m_modeRandomizerWindow.hwnd(); } + +private: + // ================================== + // Mode Randomizer GUI + static void hideGUICallback(void *pthis, VWindow *window) { + ((VortexModeRandomizer *)pthis)->hide(); + } + static void loseFocusCallback(void *pthis, VWindow *window) { + ((VortexModeRandomizer *)pthis)->loseFocus(); + } + + bool m_isOpen; + + HICON m_hIcon; + + // child window for mode randomizer tool + VChildWindow m_modeRandomizerWindow; + +}; + diff --git a/VortexEditor/VortexPort.cpp b/VortexEditor/VortexPort.cpp index 4452378..60a4a4b 100644 --- a/VortexEditor/VortexPort.cpp +++ b/VortexEditor/VortexPort.cpp @@ -145,7 +145,7 @@ int VortexPort::waitData(ByteStream &stream) } debug_send("%u %x << Waited 1 byte data\n", g_counter++, GetCurrentThreadId()); // insert the byte into the output stream - stream.serialize(byte); + stream.serialize8(byte); // check how much more data is avail int data = bytesAvailable(); if (data > 0) { @@ -156,6 +156,11 @@ int VortexPort::waitData(ByteStream &stream) return stream.size(); } +int VortexPort::writeData(uint8_t *data, uint32_t size) +{ + return m_serialPort.writeData(data, size); +} + int VortexPort::writeData(const std::string &message) { debug_send("%u %x > Writing message: %s\n", g_counter++, GetCurrentThreadId(), message.c_str()); @@ -173,7 +178,7 @@ int VortexPort::writeData(ByteStream &stream) // create a new ByteStream that will contain the size + full stream ByteStream buf(size + sizeof(size)); // serialize the size into the buf - buf.serialize(size); + buf.serialize32(size); // append the raw data of the input stream (crc/flags/size/buffer) buf.append(ByteStream(size, (const uint8_t *)stream.rawData())); // We must send the whole buffer in one go, cannot send size first diff --git a/VortexEditor/VortexPort.h b/VortexEditor/VortexPort.h index 100d9f8..69b881a 100644 --- a/VortexEditor/VortexPort.h +++ b/VortexEditor/VortexPort.h @@ -25,6 +25,8 @@ class VortexPort int readData(ByteStream &stream); // wait till data arrives then read it out int waitData(ByteStream &stream); + // write byte to the port + int writeData(uint8_t *data, uint32_t size); // write a message to the port int writeData(const std::string &message); // write a buffer of binary data to the port diff --git a/VortexEditor/chromadeck-logo-square-64.bmp b/VortexEditor/chromadeck-logo-square-64.bmp new file mode 100644 index 0000000..5008941 Binary files /dev/null and b/VortexEditor/chromadeck-logo-square-64.bmp differ diff --git a/VortexEditor/chromadeck-logo-square-green-64.bmp b/VortexEditor/chromadeck-logo-square-green-64.bmp new file mode 100644 index 0000000..13cebac Binary files /dev/null and b/VortexEditor/chromadeck-logo-square-green-64.bmp differ diff --git a/VortexEditor/gloves-logo-square-64.bmp b/VortexEditor/gloves-logo-square-64.bmp new file mode 100644 index 0000000..56e1b8f Binary files /dev/null and b/VortexEditor/gloves-logo-square-64.bmp differ diff --git a/VortexEditor/gloves-logo-square-green-64.bmp b/VortexEditor/gloves-logo-square-green-64.bmp new file mode 100644 index 0000000..207da98 Binary files /dev/null and b/VortexEditor/gloves-logo-square-green-64.bmp differ diff --git a/VortexEditor/handle-logo-square-64.bmp b/VortexEditor/handle-logo-square-64.bmp new file mode 100644 index 0000000..530662c Binary files /dev/null and b/VortexEditor/handle-logo-square-64.bmp differ diff --git a/VortexEditor/handle-logo-square-green-64.bmp b/VortexEditor/handle-logo-square-green-64.bmp new file mode 100644 index 0000000..057a44a Binary files /dev/null and b/VortexEditor/handle-logo-square-green-64.bmp differ diff --git a/VortexEditor/orbit-logo-square-64.bmp b/VortexEditor/orbit-logo-square-64.bmp new file mode 100644 index 0000000..69f2732 Binary files /dev/null and b/VortexEditor/orbit-logo-square-64.bmp differ diff --git a/VortexEditor/orbit-logo-square-green-64.bmp b/VortexEditor/orbit-logo-square-green-64.bmp new file mode 100644 index 0000000..e42bd8a Binary files /dev/null and b/VortexEditor/orbit-logo-square-green-64.bmp differ diff --git a/VortexEditor/resource.h b/VortexEditor/resource.h index e2ccbfc..77ffda9 100644 --- a/VortexEditor/resource.h +++ b/VortexEditor/resource.h @@ -4,6 +4,14 @@ // #define IDR_MENU1 101 #define IDI_ICON1 104 +#define IDB_BITMAP1 109 +#define IDB_BITMAP2 110 +#define IDB_BITMAP3 111 +#define IDB_BITMAP4 112 +#define IDB_BITMAP5 113 +#define IDB_BITMAP6 114 +#define IDB_BITMAP7 115 +#define IDB_BITMAP8 116 #define ID_FILE_PUSH 40001 #define ID_FILE_PULL 40002 #define ID_FILE_LOAD 40003 @@ -45,13 +53,27 @@ #define ID_OPTIONS_RECEIVEFROMDUO 40057 #define ID_OPTIONS_RECEIVE_FROM_DUO 40058 #define ID_OPTIONS_RECEIVE_DUO 40059 +#define ID_TOOLS_RANDOMIZER 40060 +#define ID_TOOLS_COMMUNITYBROWSER 40061 +#define ID_TOOLS_MODE_RANDOMIZER 40062 +#define ID_TOOLS_COMMUNITY_BROWSER 40063 +#define ID_HELP_TUTORIAL 40064 +#define ID_HELP_WIKI 40065 +#define ID_TOOLS_CHROMALINK 40066 +#define ID_OPTIONS_CHOOSEDEVICE 40067 +#define ID_CHOOSE_DEVICE_ORBIT 40068 +#define ID_CHOOSE_DEVICE_HANDLE 40069 +#define ID_CHOOSE_DEVICE_GLOVES 40070 +#define ID_CHOOSE_DEVICE_CHROMADECK 40071 +#define ID_CHOOSE_DEVICE_SPARK 40072 +#define ID_CHOOSE_DEVICE_DUO 40073 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 109 -#define _APS_NEXT_COMMAND_VALUE 40060 +#define _APS_NEXT_RESOURCE_VALUE 117 +#define _APS_NEXT_COMMAND_VALUE 40074 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif