From ffd03326bc6cf689d2b62c6c96426452332977fb Mon Sep 17 00:00:00 2001 From: Dan Date: Sun, 17 Mar 2024 21:39:15 -0700 Subject: [PATCH 01/15] all work related to new windows --- VortexEditor/GUI/VColorSelect.cpp | 694 +++++++++++----------- VortexEditor/VortexEditor.cpp | 29 +- VortexEditor/VortexEditor.h | 6 + VortexEditor/VortexEditor.rc | 2 + VortexEditor/VortexEditor.vcxproj | 414 ++++++------- VortexEditor/VortexEditor.vcxproj.filters | 300 +++++----- VortexEditor/VortexEngine | 2 +- VortexEditor/resource.h | 6 +- 8 files changed, 756 insertions(+), 697 deletions(-) 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/VortexEditor.cpp b/VortexEditor/VortexEditor.cpp index d88ed05..1f87cd8 100644 --- a/VortexEditor/VortexEditor.cpp +++ b/VortexEditor/VortexEditor.cpp @@ -224,17 +224,34 @@ 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); // 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); + + // show subwindows + m_colorPicker.show(); + m_modeRandomizer.show(); + m_communityBrowser.show(); // apply the icon m_hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1)); @@ -422,6 +439,12 @@ 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; default: break; } diff --git a/VortexEditor/VortexEditor.h b/VortexEditor/VortexEditor.h index 1c1e2aa..ff69abc 100644 --- a/VortexEditor/VortexEditor.h +++ b/VortexEditor/VortexEditor.h @@ -26,6 +26,8 @@ // editor includes #include "VortexColorPicker.h" +#include "VortexModeRandomizer.h" +#include "VortexCommunityBrowser.h" #include "ArduinoSerial.h" // stl includes @@ -46,6 +48,8 @@ class Colorset; class VortexEditor { friend class VortexColorPicker; + friend class VortexModeRandomizer; + friend class VortexCommunityBrowser; public: VortexEditor(); ~VortexEditor(); @@ -244,6 +248,8 @@ class VortexEditor // the vortex color picker window VortexColorPicker m_colorPicker; + VortexModeRandomizer m_modeRandomizer; + VortexCommunityBrowser m_communityBrowser; }; extern VortexEditor *g_pEditor; diff --git a/VortexEditor/VortexEditor.rc b/VortexEditor/VortexEditor.rc index 10b8615..8e36419 100644 --- a/VortexEditor/VortexEditor.rc +++ b/VortexEditor/VortexEditor.rc @@ -96,6 +96,8 @@ BEGIN POPUP "Tools" BEGIN MENUITEM "Color Picker", ID_TOOLS_COLOR_PICKER + MENUITEM "Mode Randomizer", ID_TOOLS_MODE_RANDOMIZER + MENUITEM "Community Browser", ID_TOOLS_COMMUNITY_BROWSER END POPUP "Options" BEGIN diff --git a/VortexEditor/VortexEditor.vcxproj b/VortexEditor/VortexEditor.vcxproj index 0a07a3b..c0b4445 100644 --- a/VortexEditor/VortexEditor.vcxproj +++ b/VortexEditor/VortexEditor.vcxproj @@ -1,205 +1,211 @@ - - - - - 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..0f8e5e3 100644 --- a/VortexEditor/VortexEditor.vcxproj.filters +++ b/VortexEditor/VortexEditor.vcxproj.filters @@ -1,142 +1,160 @@ - - - - - {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 + + + + + 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 + + + + + Resource Files + + + + + Resource Files + + \ No newline at end of file diff --git a/VortexEditor/VortexEngine b/VortexEditor/VortexEngine index 6e6017b..45f6320 160000 --- a/VortexEditor/VortexEngine +++ b/VortexEditor/VortexEngine @@ -1 +1 @@ -Subproject commit 6e6017b4174498217fd67cc95c0026c904a7398d +Subproject commit 45f63209076fbce2a75df2368dd30efa365e2a08 diff --git a/VortexEditor/resource.h b/VortexEditor/resource.h index e2ccbfc..59a8bb2 100644 --- a/VortexEditor/resource.h +++ b/VortexEditor/resource.h @@ -45,13 +45,17 @@ #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 // 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_COMMAND_VALUE 40064 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif From cc420111e837854adf8ee94b4281dab93afac694 Mon Sep 17 00:00:00 2001 From: Dan Date: Sun, 17 Mar 2024 21:40:44 -0700 Subject: [PATCH 02/15] other files for new windows --- VortexEditor/GUI/VPatternStrip.cpp | 396 ++++++++++++++++++++++++ VortexEditor/GUI/VPatternStrip.h | 89 ++++++ VortexEditor/VortexCommunityBrowser.cpp | 226 ++++++++++++++ VortexEditor/VortexCommunityBrowser.h | 71 +++++ VortexEditor/VortexModeRandomizer.cpp | 84 +++++ VortexEditor/VortexModeRandomizer.h | 55 ++++ 6 files changed, 921 insertions(+) create mode 100644 VortexEditor/GUI/VPatternStrip.cpp create mode 100644 VortexEditor/GUI/VPatternStrip.h create mode 100644 VortexEditor/VortexCommunityBrowser.cpp create mode 100644 VortexEditor/VortexCommunityBrowser.h create mode 100644 VortexEditor/VortexModeRandomizer.cpp create mode 100644 VortexEditor/VortexModeRandomizer.h diff --git a/VortexEditor/GUI/VPatternStrip.cpp b/VortexEditor/GUI/VPatternStrip.cpp new file mode 100644 index 0000000..46ccc32 --- /dev/null +++ b/VortexEditor/GUI/VPatternStrip.cpp @@ -0,0 +1,396 @@ +#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_colorLabel(), + m_callback(nullptr), + m_color(0), + m_active(true), + m_selected(false), + m_selectable(true), + m_colorSequence() +{ +} + +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 &modeData, uintptr_t menuID, VPatternStripCallback callback) : + VPatternStrip() +{ + init(hInstance, parent, title, backcol, width, height, x, y, lineWidth, modeData, menuID, callback); +} + +VPatternStrip::~VPatternStrip() +{ + 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 &modeData, 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_colorLabel.init(hInstance, parent, title, backcol, 100, 24, x + width + 6, y + (height / 4), 0, nullptr); + + //// preview box for current color + //m_colorPreview.init(hInst, m_communityBrowserWindow, "", BACK_COL, 122, 96, 273, 274, PREVIEW_ID, clickCurColorCallback); + //m_colorPreview.setActive(true); + //m_colorPreview.setColor(0xFF0000); + //m_colorPreview.setSelectable(false); + + // load the communty modes into the local vortex instance for the browser window + m_vortex.init(); + m_vortex.setLedCount(1); + m_vortex.setTickrate(30); + m_vortex.engine().modes().clearModes(); + m_vortex.loadModeFromJson(modeData); +} + +void VPatternStrip::cleanup() +{ +} + +uint32_t m_scrollOffset = 0; + +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 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 an off-screen buffer to perform our drawing operations + HDC backbuffDC = CreateCompatibleDC(hdc); + HBITMAP backbuffer = CreateCompatibleBitmap(hdc, width, height); + HBITMAP oldBitmap = (HBITMAP)SelectObject(backbuffDC, backbuffer); + + // Initially fill the background + FillRect(backbuffDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); + + // Draw the new frame on top + uint32_t numLines = m_colorSequence.size(); // Number of lines we have in our sequence + + // Calculate the starting x position for the first line (right-most) + int startX = width - (numLines * m_lineWidth) % width; + + for (int i = 0; i < numLines; ++i) { + // Determine the color for this line + RGBColor col = m_colorSequence[i]; + if (col.empty()) { + continue; + } + HBRUSH brush = getBrushCol(col.raw()); + if (!brush) { + continue; + } + // draw the line + int xPos = (startX + (i * m_lineWidth)) % width; + RECT lineRect = { xPos, rect.top, xPos + m_lineWidth, rect.bottom }; + FillRect(backbuffDC, &lineRect, brush); + } + + // Create a temporary DC for the darkening operation + HDC tempDC = CreateCompatibleDC(hdc); + HBITMAP tempBitmap = CreateCompatibleBitmap(hdc, width, height); + SelectObject(tempDC, tempBitmap); + + // Copy current backbuffer content to tempDC + BitBlt(tempDC, 0, 0, width, height, backbuffDC, 0, 0, SRCCOPY); + + BLENDFUNCTION blendFunc = { 0 }; + blendFunc.BlendOp = AC_SRC_OVER; + blendFunc.SourceConstantAlpha = 230; // Adjust for desired trail darkness + blendFunc.AlphaFormat = 0; + + // Apply the darkening effect on the backbuffer using content from tempDC + AlphaBlend(backbuffDC, 0, 0, width, height, tempDC, 0, 0, width, height, blendFunc); + + // Cleanup temporary objects + DeleteDC(tempDC); + DeleteObject(tempBitmap); + + // Copy the off-screen buffer to the screen + BitBlt(hdc, 0, 0, width, height, backbuffDC, 0, 0, SRCCOPY); + + // Cleanup + SelectObject(backbuffDC, oldBitmap); + DeleteObject(backbuffer); + DeleteDC(backbuffDC); + EndPaint(m_hwnd, &paintStruct); +} + +void VPatternStrip::command(WPARAM wParam, LPARAM lParam) +{ +} + +void VPatternStrip::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 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() +{ + setColor(0); +} + +void VPatternStrip::setColor(uint32_t col) +{ + m_color = col; + m_colorLabel.setText(getColorName()); + redraw(); +} + +string VPatternStrip::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 VPatternStrip::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)); +} + +uint32_t VPatternStrip::getColor() const +{ + return m_color; +} + +bool VPatternStrip::isActive() const +{ + return m_active; +} + +void VPatternStrip::setActive(bool active) +{ + m_active = active; + m_colorLabel.setVisible(active); + if (!m_active) { + setSelected(false); + } +} + +bool VPatternStrip::isSelected() const +{ + return m_selected; +} + +void VPatternStrip::setSelected(bool selected) +{ + m_selected = selected; + if (m_selected) { + m_colorLabel.setForeColor(0xFFFFFF); + } else { + m_colorLabel.setForeColor(0xAAAAAA); + } +} + +void VPatternStrip::setLabelEnabled(bool enabled) +{ + m_colorLabel.setVisible(enabled); + m_colorLabel.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); +} diff --git a/VortexEditor/GUI/VPatternStrip.h b/VortexEditor/GUI/VPatternStrip.h new file mode 100644 index 0000000..13f8595 --- /dev/null +++ b/VortexEditor/GUI/VPatternStrip.h @@ -0,0 +1,89 @@ +#pragma once + +#include "VWindow.h" + +#include "VLabel.h" + +#include "VortexLib.h" + +#include + +class VPatternStrip : public VWindow +{ +public: + // type of selection event for callback + enum SelectEvent { + SELECT_LEFT_CLICK, + SELECT_CTRL_LEFT_CLICK, + SELECT_SHIFT_LEFT_CLICK, + SELECT_RIGHT_CLICK, + }; + // callback upon selection + 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(); + + 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, + uint32_t linewidth, const json &modeData, uintptr_t menuID, VPatternStripCallback callback); + virtual void cleanup(); + + virtual void run(); + + // 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; + + // window message for right button press, only exists here + void rightButtonPress(); + + void clear(); + void setColor(uint32_t col); + uint32_t getColor() const; + std::string getColorName() const; + void setColor(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); + +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; + + // local vortex instance to render community modes + Vortex m_vortex; + + // internal vgui label for display of color code + VLabel m_colorLabel; + + VPatternStripCallback m_callback; + // the color in this slot + uint32_t m_color; + // whether this slot is actually used + bool m_active; + // whether this slot is selected for changes + bool m_selected; + // whether this control is selectable + bool m_selectable; + + // vector of colors + std::deque m_colorSequence; + // the line width + uint32_t m_lineWidth; + // number of 'slices' (slices = width / line size) + uint32_t m_numSlices; +}; + diff --git a/VortexEditor/VortexCommunityBrowser.cpp b/VortexEditor/VortexCommunityBrowser.cpp new file mode 100644 index 0000000..f1ee3f8 --- /dev/null +++ b/VortexEditor/VortexCommunityBrowser.cpp @@ -0,0 +1,226 @@ +#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 +#include + +#pragma comment(lib, "winhttp.lib") + +#define PREVIEW_ID 55501 +#define PATTERN_STRIP_ID 55601 + +using namespace std; +using json = nlohmann::json; + +VortexCommunityBrowser::VortexCommunityBrowser() : + m_isOpen(false), + m_hIcon(nullptr), + m_mutex(nullptr), + m_runThreadId(nullptr), + m_communityBrowserWindow(), + m_patternStrips() +{ +} + +VortexCommunityBrowser::~VortexCommunityBrowser() +{ + DestroyIcon(m_hIcon); + TerminateThread(m_runThreadId, 0); +} + +// initialize the color picker +bool VortexCommunityBrowser::init(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); + + // fetch json of modes from community api + try { + m_communityModes = json::parse(GetHttpRequest(L"vortex.community", L"/modes/json")); + } catch (...) { + return false; + } + + // Verify if 'data' is an array + if (!m_communityModes.contains("data")) { + std::cerr << "'data' is not an array or does not exist" << std::endl; + return false; + } + + uint32_t i = 0; + for (auto mode : m_communityModes["data"]) { + if (!mode.contains("modeData")) { + //continue; + } + shared_ptr strip = make_shared(hInst, + m_communityBrowserWindow, "Mode " + to_string(i), BACK_COL, + 300, 32, 16, 16 + (i * 36), 2, mode["modeData"], PATTERN_STRIP_ID + i, nullptr); + m_patternStrips.push_back(move(strip)); + i++; + } + + // 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); + + m_runThreadId = CreateThread(NULL, 0, runThread, this, 0, NULL); + + return true; +} + +DWORD __stdcall VortexCommunityBrowser::runThread(void *arg) +{ + VortexCommunityBrowser *browser = (VortexCommunityBrowser *)arg; + while (1) { + if (browser->m_isOpen) { + browser->run(); + } + } + return 0; +} + +void VortexCommunityBrowser::run() +{ + for (auto strip : m_patternStrips) { + strip.get()->run(); + } +} + +void VortexCommunityBrowser::show() +{ + if (m_isOpen) { + return; + } + m_communityBrowserWindow.setVisible(true); + m_communityBrowserWindow.setEnabled(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(); + } + m_isOpen = false; +} + +void VortexCommunityBrowser::loseFocus() +{ +} + +std::wstring VortexCommunityBrowser::GetHttpRequest(const std::wstring& host, const std::wstring& path) +{ + DWORD dwSize = 0; + DWORD dwDownloaded = 0; + LPSTR pszOutBuffer; + std::wstring result; + BOOL bResults = FALSE; + HINTERNET hSession = NULL, + hConnect = NULL, + hRequest = NULL; + + // Use WinHttpOpen to obtain a session handle. + hSession = WinHttpOpen(L"A Vortex Editor/1.0", + WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0); + if (!hSession) { + return L""; + } + hConnect = WinHttpConnect(hSession, host.c_str(), + INTERNET_DEFAULT_HTTP_PORT, 0); + // Create an HTTP request handle. + if (!hConnect) { + return L""; + } + hRequest = WinHttpOpenRequest(hConnect, L"GET", path.c_str(), + NULL, WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + 0); + // Send a request. + if (!hRequest) { + return L""; + } + bResults = WinHttpSendRequest(hRequest, + WINHTTP_NO_ADDITIONAL_HEADERS, 0, + WINHTTP_NO_REQUEST_DATA, 0, + 0, 0); + + // End the request. + if (!bResults) { + return L""; + } + bResults = WinHttpReceiveResponse(hRequest, NULL); + + // Keep checking for data until there is nothing left. + if (!bResults) { + return L""; + } + do { + // Check for available data. + dwSize = 0; + if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) { + //std::wcout << L"Error " << GetLastError() << L" in WinHttpQueryDataAvailable.\n"; + } + + // Allocate space for the buffer. + pszOutBuffer = new char[dwSize + 1]; + if (!pszOutBuffer) { + //std::wcout << L"Out of memory\n"; + dwSize = 0; + return L""; + } + // Read the data. + ZeroMemory(pszOutBuffer, dwSize + 1); + if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) { + delete[] pszOutBuffer; + return L""; + } + result.append(pszOutBuffer, pszOutBuffer + dwDownloaded); + // Free the memory allocated to the buffer. + delete[] pszOutBuffer; + } while (dwSize > 0); + + // Close any open handles. + if (hRequest) { + WinHttpCloseHandle(hRequest); + } + if (hConnect) { + WinHttpCloseHandle(hConnect); + } + if (hSession) { + WinHttpCloseHandle(hSession); + } + + if (result.empty()) { + return std::wstring(); + } + return result; +} diff --git a/VortexEditor/VortexCommunityBrowser.h b/VortexEditor/VortexCommunityBrowser.h new file mode 100644 index 0000000..79e607b --- /dev/null +++ b/VortexEditor/VortexCommunityBrowser.h @@ -0,0 +1,71 @@ +#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); + // run the mode randomizer + void run(); + + // show/hide the mode randomizer window + void show(); + void hide(); + void loseFocus(); + std::wstring GetHttpRequest(const std::wstring &host, const std::wstring &path); + + 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 DWORD __stdcall runThread(void *arg); + + bool m_isOpen; + + HICON m_hIcon; + + // modes fetched from community api + nlohmann::json 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; +}; \ No newline at end of file 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; + +}; + From 2071bf531cfc917901ba3988057d3031aea8a59c Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 23 Apr 2024 20:40:33 -0700 Subject: [PATCH 03/15] lots of work --- VortexEditor/GUI/VButton.cpp | 183 +++-- VortexEditor/GUI/VChildWindow.cpp | 345 +++++----- VortexEditor/GUI/VPatternStrip.cpp | 260 ++++--- VortexEditor/GUI/VPatternStrip.h | 159 ++--- VortexEditor/GUI/VSelectBox.cpp | 766 ++++++++++++--------- VortexEditor/GUI/VSelectBox.h | 181 ++--- VortexEditor/GUI/VStatusBar.cpp | 233 +++---- VortexEditor/GUI/VWindow.cpp | 800 +++++++++++----------- VortexEditor/HttpClient.cpp | 132 ++++ VortexEditor/HttpClient.h | 27 + VortexEditor/VortexCommunityBrowser.cpp | 205 +++--- VortexEditor/VortexCommunityBrowser.h | 30 +- VortexEditor/VortexEditor.cpp | 43 +- VortexEditor/VortexEditor.h | 9 +- VortexEditor/VortexEditor.rc | 25 +- VortexEditor/VortexEditor.vcxproj | 16 +- VortexEditor/VortexEditor.vcxproj.filters | 42 ++ VortexEditor/VortexEditorTutorial.cpp | 240 +++++++ VortexEditor/VortexEditorTutorial.h | 102 +++ VortexEditor/resource.h | 14 +- chromadeck-logo-square-64.bmp | Bin 0 -> 5176 bytes gloves-logo-square-64.bmp | Bin 0 -> 12344 bytes handle-logo-square-64.bmp | Bin 0 -> 5176 bytes orbit-logo-square-64.bmp | Bin 0 -> 5176 bytes 24 files changed, 2283 insertions(+), 1529 deletions(-) create mode 100644 VortexEditor/HttpClient.cpp create mode 100644 VortexEditor/HttpClient.h create mode 100644 VortexEditor/VortexEditorTutorial.cpp create mode 100644 VortexEditor/VortexEditorTutorial.h create mode 100644 chromadeck-logo-square-64.bmp create mode 100644 gloves-logo-square-64.bmp create mode 100644 handle-logo-square-64.bmp create mode 100644 orbit-logo-square-64.bmp 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/VPatternStrip.cpp b/VortexEditor/GUI/VPatternStrip.cpp index 46ccc32..4029813 100644 --- a/VortexEditor/GUI/VPatternStrip.cpp +++ b/VortexEditor/GUI/VPatternStrip.cpp @@ -23,32 +23,41 @@ WNDCLASS VPatternStrip::m_wc = { 0 }; VPatternStrip::VPatternStrip() : VWindow(), m_vortex(), - m_colorLabel(), + m_runThreadId(nullptr), + m_stripLabel(), m_callback(nullptr), - m_color(0), m_active(true), m_selected(false), m_selectable(true), - m_colorSequence() + 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 &modeData, uintptr_t menuID, VPatternStripCallback callback) : + uint32_t lineWidth, const json &js, uintptr_t menuID, VPatternStripCallback callback) : VPatternStrip() { - init(hInstance, parent, title, backcol, width, height, x, y, lineWidth, modeData, menuID, callback); + 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 &modeData, uintptr_t menuID, VPatternStripCallback callback) + uint32_t lineWidth, const json &js, uintptr_t menuID, VPatternStripCallback callback) { // store callback and menu id m_callback = callback; @@ -81,27 +90,46 @@ void VPatternStrip::init(HINSTANCE hInstance, VWindow &parent, const string &tit // 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); - - //// preview box for current color - //m_colorPreview.init(hInst, m_communityBrowserWindow, "", BACK_COL, 122, 96, 273, 274, PREVIEW_ID, clickCurColorCallback); - //m_colorPreview.setActive(true); - //m_colorPreview.setColor(0xFF0000); - //m_colorPreview.setSelectable(false); + 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(30); - m_vortex.engine().modes().clearModes(); - m_vortex.loadModeFromJson(modeData); + + HDC hdc = GetDC(m_hwnd); + createBackBuffer(hdc, width, height); + + loadJson(js); } -void VPatternStrip::cleanup() +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"]); + setActive(true); + } } -uint32_t m_scrollOffset = 0; +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() { @@ -138,29 +166,34 @@ static HBRUSH getBrushCol(DWORD rgbcol) void VPatternStrip::paint() { - PAINTSTRUCT paintStruct; - HDC hdc = BeginPaint(m_hwnd, &paintStruct); + 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() +{ + // Ensure the backbuffer is ready for drawing + if (!m_backbufferDC) { + return; + } + RECT rect; GetClientRect(m_hwnd, &rect); uint32_t width = rect.right - rect.left; uint32_t height = rect.bottom - rect.top; - // Create an off-screen buffer to perform our drawing operations - HDC backbuffDC = CreateCompatibleDC(hdc); - HBITMAP backbuffer = CreateCompatibleBitmap(hdc, width, height); - HBITMAP oldBitmap = (HBITMAP)SelectObject(backbuffDC, backbuffer); - - // Initially fill the background - FillRect(backbuffDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); + // Fill the backbuffer background + FillRect(m_backbufferDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); - // Draw the new frame on top - uint32_t numLines = m_colorSequence.size(); // Number of lines we have in our sequence - - // Calculate the starting x position for the first line (right-most) + // Draw the color sequence + uint32_t numLines = m_colorSequence.size(); int startX = width - (numLines * m_lineWidth) % width; - for (int i = 0; i < numLines; ++i) { - // Determine the color for this line RGBColor col = m_colorSequence[i]; if (col.empty()) { continue; @@ -169,40 +202,10 @@ void VPatternStrip::paint() if (!brush) { continue; } - // draw the line int xPos = (startX + (i * m_lineWidth)) % width; RECT lineRect = { xPos, rect.top, xPos + m_lineWidth, rect.bottom }; - FillRect(backbuffDC, &lineRect, brush); + FillRect(m_backbufferDC, &lineRect, brush); } - - // Create a temporary DC for the darkening operation - HDC tempDC = CreateCompatibleDC(hdc); - HBITMAP tempBitmap = CreateCompatibleBitmap(hdc, width, height); - SelectObject(tempDC, tempBitmap); - - // Copy current backbuffer content to tempDC - BitBlt(tempDC, 0, 0, width, height, backbuffDC, 0, 0, SRCCOPY); - - BLENDFUNCTION blendFunc = { 0 }; - blendFunc.BlendOp = AC_SRC_OVER; - blendFunc.SourceConstantAlpha = 230; // Adjust for desired trail darkness - blendFunc.AlphaFormat = 0; - - // Apply the darkening effect on the backbuffer using content from tempDC - AlphaBlend(backbuffDC, 0, 0, width, height, tempDC, 0, 0, width, height, blendFunc); - - // Cleanup temporary objects - DeleteDC(tempDC); - DeleteObject(tempBitmap); - - // Copy the off-screen buffer to the screen - BitBlt(hdc, 0, 0, width, height, backbuffDC, 0, 0, SRCCOPY); - - // Cleanup - SelectObject(backbuffDC, oldBitmap); - DeleteObject(backbuffer); - DeleteDC(backbuffDC); - EndPaint(m_hwnd, &paintStruct); } void VPatternStrip::command(WPARAM wParam, LPARAM lParam) @@ -211,6 +214,8 @@ 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) { @@ -255,42 +260,11 @@ void VPatternStrip::rightButtonPress() void VPatternStrip::clear() { - setColor(0); -} - -void VPatternStrip::setColor(uint32_t col) -{ - m_color = col; - m_colorLabel.setText(getColorName()); - redraw(); -} - -string VPatternStrip::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 VPatternStrip::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)); -} - -uint32_t VPatternStrip::getColor() const -{ - return m_color; + 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 @@ -301,9 +275,16 @@ bool VPatternStrip::isActive() const void VPatternStrip::setActive(bool active) { m_active = active; - m_colorLabel.setVisible(active); + m_stripLabel.setVisible(active); if (!m_active) { setSelected(false); + WaitForSingleObject(m_runThreadId, INFINITE); + m_runThreadId = nullptr; + clear(); + return; + } + if (!m_runThreadId) { + m_runThreadId = CreateThread(NULL, 0, runThread, this, 0, NULL); } } @@ -316,16 +297,16 @@ void VPatternStrip::setSelected(bool selected) { m_selected = selected; if (m_selected) { - m_colorLabel.setForeColor(0xFFFFFF); + m_stripLabel.setForeColor(0xFFFFFF); } else { - m_colorLabel.setForeColor(0xAAAAAA); + m_stripLabel.setForeColor(0xAAAAAA); } } void VPatternStrip::setLabelEnabled(bool enabled) { - m_colorLabel.setVisible(enabled); - m_colorLabel.setEnabled(enabled); + m_stripLabel.setVisible(enabled); + m_stripLabel.setEnabled(enabled); } void VPatternStrip::setSelectable(bool selectable) @@ -394,3 +375,74 @@ void VPatternStrip::registerWindowClass(HINSTANCE hInstance, COLORREF backcol) 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 index 13f8595..63accbe 100644 --- a/VortexEditor/GUI/VPatternStrip.h +++ b/VortexEditor/GUI/VPatternStrip.h @@ -1,89 +1,90 @@ #pragma once #include "VWindow.h" - #include "VLabel.h" - #include "VortexLib.h" - #include +#include +#include -class VPatternStrip : public VWindow -{ +class VPatternStrip : public VWindow { public: - // type of selection event for callback - enum SelectEvent { - SELECT_LEFT_CLICK, - SELECT_CTRL_LEFT_CLICK, - SELECT_SHIFT_LEFT_CLICK, - SELECT_RIGHT_CLICK, - }; - // callback upon selection - 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(); - - 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, - uint32_t linewidth, const json &modeData, uintptr_t menuID, VPatternStripCallback callback); - virtual void cleanup(); - - virtual void run(); - - // 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; - - // window message for right button press, only exists here - void rightButtonPress(); - - void clear(); - void setColor(uint32_t col); - uint32_t getColor() const; - std::string getColorName() const; - void setColor(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); + 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; - - // local vortex instance to render community modes - Vortex m_vortex; - - // internal vgui label for display of color code - VLabel m_colorLabel; - - VPatternStripCallback m_callback; - // the color in this slot - uint32_t m_color; - // whether this slot is actually used - bool m_active; - // whether this slot is selected for changes - bool m_selected; - // whether this control is selectable - bool m_selectable; - - // vector of colors - std::deque m_colorSequence; - // the line width - uint32_t m_lineWidth; - // number of 'slices' (slices = width / line size) - uint32_t m_numSlices; -}; - + 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_runThreadId; + 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..0d0b1c7 100644 --- a/VortexEditor/GUI/VSelectBox.cpp +++ b/VortexEditor/GUI/VSelectBox.cpp @@ -1,337 +1,431 @@ -#include "VSelectBox.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_HUE_SAT_BOX "VSelectBox" - -#define PI 3.141592654 - -WNDCLASS VSelectBox::m_wc = {0}; - -VSelectBox::VSelectBox() : - VWindow(), - m_borderSize(1), - m_width(0), - m_height(0), - m_innerLeft(0), - m_innerTop(0), - m_innerRight(0), - m_innerBottom(0), - m_innerWidth(0), - m_innerHeight(0), - m_drawHLine(true), - m_drawVLine(true), - m_drawCircle(true), - m_pressed(false), - m_xSelect(0), - m_ySelect(0), - m_callback(nullptr), - m_bitmap(nullptr) -{ -} - -VSelectBox::VSelectBox(HINSTANCE hInstance, VWindow &parent, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, - uintptr_t menuID, VSelectBoxCallback callback) : - VSelectBox() -{ - init(hInstance, parent, title, backcol, width, height, x, y, menuID, callback); -} - -VSelectBox::~VSelectBox() -{ - cleanup(); -} - -void VSelectBox::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, VSelectBoxCallback callback) -{ - // store callback and menu id - m_callback = callback; - - // register window class if it hasn't been registered yet - registerWindowClass(hInstance, backcol); - - if (!menuID) { - menuID = nextMenuID++; - } - - if (!parent.addChild(menuID, this)) { - return; - } - - m_innerWidth = width; - m_innerHeight = height; - - 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; - - // create the window - m_hwnd = CreateWindow(WC_HUE_SAT_BOX, title.c_str(), - WS_CHILD | WS_OVERLAPPED | WS_VISIBLE | WS_TABSTOP | WS_CLIPCHILDREN, - x, y, m_width, m_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, "", backcol, 100, 24, x + width + 6, y + (height / 4), 0, nullptr); -} - -void VSelectBox::cleanup() -{ -} - -void VSelectBox::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 VSelectBox::paint() -{ - PAINTSTRUCT paintStruct; - 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); - - // 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); - DeleteDC(bmpDC); - - // draw the lines and circle - uint32_t selectorSize = 5; - if (m_drawHLine) { - SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); - if (m_drawCircle) { - if (m_xSelect > selectorSize) { - MoveToEx(backbuffDC, m_innerLeft, m_innerTop + m_ySelect, NULL); - LineTo(backbuffDC, m_innerLeft + (m_xSelect - selectorSize), m_innerTop + m_ySelect); - } - MoveToEx(backbuffDC, m_innerLeft + (m_xSelect + selectorSize), m_innerTop + m_ySelect, NULL); - LineTo(backbuffDC, m_innerLeft + m_innerWidth, m_innerTop + m_ySelect); - } else { - MoveToEx(backbuffDC, m_innerLeft, m_innerTop + m_ySelect, NULL); - LineTo(backbuffDC, m_innerLeft + m_innerWidth, m_innerTop + m_ySelect); - } - } - if (m_drawVLine) { - SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); - if (m_drawCircle) { - if (m_ySelect > selectorSize) { - MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop, NULL); - LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + (m_ySelect - selectorSize)); - } - MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + (m_ySelect + selectorSize), NULL); - LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + m_innerHeight); - } else { - MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop, NULL); - LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + m_innerHeight); - } - } - if (m_drawCircle) { - SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); - SelectObject(backbuffDC, GetStockObject(HOLLOW_BRUSH)); - Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize), - m_innerTop + (m_ySelect - selectorSize), - m_innerLeft + (m_xSelect + selectorSize) + 1, - m_innerTop + (m_ySelect + selectorSize) + 1); - SelectObject(backbuffDC, GetStockObject(BLACK_PEN)); - Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize) + 1, - m_innerTop + (m_ySelect - selectorSize) + 1, - m_innerLeft + (m_xSelect + selectorSize), - m_innerTop + (m_ySelect + selectorSize)); - SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); - Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize) + 2, - m_innerTop + (m_ySelect - selectorSize) + 2, - m_innerLeft + (m_xSelect + selectorSize) - 1, - m_innerTop + (m_ySelect + selectorSize) - 1); - } - - BitBlt(hdc, 0, 0, m_width, m_height, backbuffDC, 0, 0, SRCCOPY); - - DeleteObject(backbuffer); - DeleteDC(backbuffDC); - - EndPaint(m_hwnd, &paintStruct); -} - -void VSelectBox::command(WPARAM wParam, LPARAM lParam) -{ -} - -void VSelectBox::pressButton(WPARAM wParam, LPARAM lParam) -{ - // Get the window client area. - RECT rc; - GetClientRect(m_hwnd, &rc); - // Convert the client area to screen coordinates. - POINT pt = { rc.left, rc.top }; - POINT pt2 = { rc.right, rc.bottom }; - ClientToScreen(m_hwnd, &pt); - ClientToScreen(m_hwnd, &pt2); - SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y); - // enable mouse capture on the window so we receive mouse move - SetCapture(m_hwnd); - // Confine the cursor. - ClipCursor(&rc); - m_pressed = true; - SelectEvent sevent = SELECT_PRESS; - if (wParam & MK_CONTROL) { - sevent = SELECT_CTRL_PRESS; - } - if (wParam & MK_SHIFT) { - sevent = SELECT_SHIFT_PRESS; - } - doCallback(sevent); -} - -void VSelectBox::releaseButton(WPARAM wParam, LPARAM lParam) -{ - if (!m_pressed) { - return; - } - ClipCursor(NULL); - ReleaseCapture(); - m_pressed = false; - doCallback(SELECT_RELEASE); -} - -void VSelectBox::mouseMove() -{ - if (!m_pressed) { - return; - } - doCallback(SELECT_DRAG); -} - -void VSelectBox::doCallback(SelectEvent sevent) -{ - if (!m_callback) { - return; - } - POINT pos; - GetCursorPos(&pos); - ScreenToClient(m_hwnd, &pos); - if (pos.x < (LONG)m_innerLeft) pos.x = m_innerLeft; - if (pos.x > (LONG)m_innerRight) pos.x = m_innerRight; - if (pos.y < (LONG)m_innerTop) pos.y = m_innerTop; - if (pos.y > (LONG)m_innerBottom) pos.y = m_innerBottom; - uint32_t innerX = pos.x - m_innerLeft; - uint32_t innerY = pos.y - m_innerTop; - setSelection(innerX, innerY); - m_callback(m_callbackArg, innerX, innerY, sevent); -} - -void VSelectBox::setBackground(HBITMAP hBitmap) -{ - m_bitmap = hBitmap; -} - -void VSelectBox::setSelection(uint32_t x, uint32_t y) -{ - m_xSelect = x; - m_ySelect = y; - // redraw? - //redraw(); -} - -LRESULT CALLBACK VSelectBox::window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - VSelectBox *pColorSelect = (VSelectBox *)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_MOUSEMOVE: - pColorSelect->mouseMove(); - break; - case WM_CTLCOLORSTATIC: - return (INT_PTR)pColorSelect->m_wc.hbrBackground; - case WM_ERASEBKGND: - return 1; - case WM_CREATE: - pColorSelect->create(); - break; - case WM_PAINT: - pColorSelect->paint(); - return 0; - case WM_COMMAND: - pColorSelect->command(wParam, lParam); - break; - case WM_DESTROY: - pColorSelect->cleanup(); - break; - default: - break; - } - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -void VSelectBox::registerWindowClass(HINSTANCE hInstance, COLORREF backcol) -{ - if (m_wc.lpfnWndProc == VSelectBox::window_proc) { - // alredy registered - return; - } - // class registration - m_wc.lpfnWndProc = VSelectBox::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_HUE_SAT_BOX; - RegisterClass(&m_wc); +#include "VSelectBox.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_HUE_SAT_BOX "VSelectBox" + +#define PI 3.141592654 + +WNDCLASS VSelectBox::m_wc = {0}; + +VSelectBox::VSelectBox() : + VWindow(), + m_borderSize(1), + m_width(0), + m_height(0), + m_innerLeft(0), + m_innerTop(0), + m_innerRight(0), + m_innerBottom(0), + m_innerWidth(0), + m_innerHeight(0), + m_drawHLine(true), + 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_hoverBitmap(nullptr) +{ +} + +VSelectBox::VSelectBox(HINSTANCE hInstance, VWindow &parent, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uintptr_t menuID, VSelectBoxCallback callback) : + VSelectBox() +{ + init(hInstance, parent, title, backcol, width, height, x, y, menuID, callback); +} + +VSelectBox::~VSelectBox() +{ + cleanup(); +} + +void VSelectBox::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, VSelectBoxCallback callback) +{ + // store callback and menu id + m_callback = callback; + + // register window class if it hasn't been registered yet + registerWindowClass(hInstance, backcol); + + if (!menuID) { + menuID = nextMenuID++; + } + + if (!parent.addChild(menuID, this)) { + return; + } + + m_innerWidth = width; + m_innerHeight = height; + + 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; + + // create the window + m_hwnd = CreateWindow(WC_HUE_SAT_BOX, title.c_str(), + WS_CHILD | WS_OVERLAPPED | WS_VISIBLE | WS_TABSTOP | WS_CLIPCHILDREN, + x, y, m_width, m_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, "", backcol, 100, 24, x + width + 6, y + (height / 4), 0, nullptr); +} + +void VSelectBox::cleanup() +{ +} + +void VSelectBox::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 VSelectBox::paint() +//{ +// PAINTSTRUCT paintStruct; +// 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); +// +// // 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); +// DeleteDC(bmpDC); +// +// +// BitBlt(hdc, 0, 0, m_width, m_height, backbuffDC, 0, 0, SRCCOPY); +// +// DeleteObject(backbuffer); +// DeleteDC(backbuffDC); +// +// EndPaint(m_hwnd, &paintStruct); +//} + +void VSelectBox::paint() +{ + PAINTSTRUCT paintStruct; + memset(&paintStruct, 0, sizeof(paintStruct)); + HDC hdc = BeginPaint(m_hwnd, &paintStruct); + + HDC backbuffDC = CreateCompatibleDC(hdc); + HBITMAP backbuffer = CreateCompatibleBitmap(hdc, m_width, m_height); + HBITMAP hbmOldBackbuffer = (HBITMAP)SelectObject(backbuffDC, backbuffer); + + HDC bmpDC = CreateCompatibleDC(hdc); + HBITMAP hbmpOld = (HBITMAP)SelectObject(bmpDC, m_mouseInside ? m_hoverBitmap : m_bitmap); + + 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 + uint32_t selectorSize = 5; + if (m_drawHLine) { + SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); + if (m_drawCircle) { + if (m_xSelect > selectorSize) { + MoveToEx(backbuffDC, m_innerLeft, m_innerTop + m_ySelect, NULL); + LineTo(backbuffDC, m_innerLeft + (m_xSelect - selectorSize), m_innerTop + m_ySelect); + } + MoveToEx(backbuffDC, m_innerLeft + (m_xSelect + selectorSize), m_innerTop + m_ySelect, NULL); + LineTo(backbuffDC, m_innerLeft + m_innerWidth, m_innerTop + m_ySelect); + } else { + MoveToEx(backbuffDC, m_innerLeft, m_innerTop + m_ySelect, NULL); + LineTo(backbuffDC, m_innerLeft + m_innerWidth, m_innerTop + m_ySelect); + } + } + if (m_drawVLine) { + SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); + if (m_drawCircle) { + if (m_ySelect > selectorSize) { + MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop, NULL); + LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + (m_ySelect - selectorSize)); + } + MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + (m_ySelect + selectorSize), NULL); + LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + m_innerHeight); + } else { + MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop, NULL); + LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + m_innerHeight); + } + } + if (m_drawCircle) { + SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); + SelectObject(backbuffDC, GetStockObject(HOLLOW_BRUSH)); + Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize), + m_innerTop + (m_ySelect - selectorSize), + m_innerLeft + (m_xSelect + selectorSize) + 1, + m_innerTop + (m_ySelect + selectorSize) + 1); + SelectObject(backbuffDC, GetStockObject(BLACK_PEN)); + Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize) + 1, + m_innerTop + (m_ySelect - selectorSize) + 1, + m_innerLeft + (m_xSelect + selectorSize), + m_innerTop + (m_ySelect + selectorSize)); + SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); + Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize) + 2, + m_innerTop + (m_ySelect - selectorSize) + 2, + m_innerLeft + (m_xSelect + selectorSize) - 1, + 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) +{ +} + +void VSelectBox::pressButton(WPARAM wParam, LPARAM lParam) +{ + // Get the window client area. + RECT rc; + GetClientRect(m_hwnd, &rc); + // Convert the client area to screen coordinates. + POINT pt = { rc.left, rc.top }; + POINT pt2 = { rc.right, rc.bottom }; + ClientToScreen(m_hwnd, &pt); + ClientToScreen(m_hwnd, &pt2); + SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y); + // enable mouse capture on the window so we receive mouse move + SetCapture(m_hwnd); + // Confine the cursor. + ClipCursor(&rc); + m_pressed = true; + SelectEvent sevent = SELECT_PRESS; + if (wParam & MK_CONTROL) { + sevent = SELECT_CTRL_PRESS; + } + if (wParam & MK_SHIFT) { + sevent = SELECT_SHIFT_PRESS; + } + doCallback(sevent); +} + +void VSelectBox::releaseButton(WPARAM wParam, LPARAM lParam) +{ + if (!m_pressed) { + return; + } + ClipCursor(NULL); + ReleaseCapture(); + m_pressed = false; + doCallback(SELECT_RELEASE); +} + +void VSelectBox::mouseMove(uint32_t buttons, uint16_t x, uint16_t y) +{ + //if (inside != m_mouseInside) { + // if (inside) { + // mouseEnter(); + // } else { + // mouseLeave(); + // } + //} + if (!m_mouseInside) { + 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; + } + setBorderSize(0); + if (!m_pressed) { + return; + } + doCallback(SELECT_DRAG); +} + +void VSelectBox::doCallback(SelectEvent sevent) +{ + if (!m_callback) { + return; + } + POINT pos; + GetCursorPos(&pos); + ScreenToClient(m_hwnd, &pos); + if (pos.x < (LONG)m_innerLeft) pos.x = m_innerLeft; + if (pos.x > (LONG)m_innerRight) pos.x = m_innerRight; + if (pos.y < (LONG)m_innerTop) pos.y = m_innerTop; + if (pos.y > (LONG)m_innerBottom) pos.y = m_innerBottom; + uint32_t innerX = pos.x - m_innerLeft; + uint32_t innerY = pos.y - m_innerTop; + setSelection(innerX, innerY); + m_callback(m_callbackArg, innerX, innerY, sevent); +} + +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; + m_ySelect = y; + // redraw? + //redraw(); +} + +LRESULT CALLBACK VSelectBox::window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + VSelectBox *pSelectBox = (VSelectBox *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (!pSelectBox) { + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + switch (uMsg) { + case WM_VSCROLL: + break; + case WM_LBUTTONDOWN: + pSelectBox->pressButton(wParam, lParam); + break; + case WM_LBUTTONUP: + pSelectBox->releaseButton(wParam, lParam); + break; + case WM_MOUSEMOVE: + pSelectBox->mouseMove(wParam, LOWORD(lParam), HIWORD(lParam)); + break; + case WM_MOUSELEAVE: + InvalidateRect(pSelectBox->m_hwnd, nullptr, FALSE); + pSelectBox->m_mouseInside = false; + break; + case WM_CTLCOLORSTATIC: + return (INT_PTR)pSelectBox->m_wc.hbrBackground; + case WM_ERASEBKGND: + return 1; + case WM_CREATE: + pSelectBox->create(); + break; + case WM_PAINT: + pSelectBox->paint(); + return 0; + case WM_COMMAND: + pSelectBox->command(wParam, lParam); + break; + case WM_DESTROY: + pSelectBox->cleanup(); + break; + default: + break; + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +void VSelectBox::registerWindowClass(HINSTANCE hInstance, COLORREF backcol) +{ + if (m_wc.lpfnWndProc == VSelectBox::window_proc) { + // alredy registered + return; + } + // class registration + m_wc.lpfnWndProc = VSelectBox::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_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/VortexCommunityBrowser.cpp b/VortexEditor/VortexCommunityBrowser.cpp index f1ee3f8..94f36ad 100644 --- a/VortexEditor/VortexCommunityBrowser.cpp +++ b/VortexEditor/VortexCommunityBrowser.cpp @@ -9,6 +9,8 @@ #include "Serial/Compression.h" +#include "HttpClient.h" + #include #include @@ -17,58 +19,52 @@ #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; -using json = nlohmann::json; VortexCommunityBrowser::VortexCommunityBrowser() : + m_hInstance(nullptr), m_isOpen(false), m_hIcon(nullptr), m_mutex(nullptr), - m_runThreadId(nullptr), m_communityBrowserWindow(), - m_patternStrips() + m_patternStrips(), + m_prevPageButton(), + m_nextPageButton(), + m_pageLabel(), + m_curPage(1), + m_lastPage(false) { } VortexCommunityBrowser::~VortexCommunityBrowser() { DestroyIcon(m_hIcon); - TerminateThread(m_runThreadId, 0); } // 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); - // fetch json of modes from community api - try { - m_communityModes = json::parse(GetHttpRequest(L"vortex.community", L"/modes/json")); - } catch (...) { - return false; - } - - // Verify if 'data' is an array - if (!m_communityModes.contains("data")) { - std::cerr << "'data' is not an array or does not exist" << std::endl; - return false; - } - - uint32_t i = 0; - for (auto mode : m_communityModes["data"]) { - if (!mode.contains("modeData")) { - //continue; - } - shared_ptr strip = make_shared(hInst, - m_communityBrowserWindow, "Mode " + to_string(i), BACK_COL, - 300, 32, 16, 16 + (i * 36), 2, mode["modeData"], PATTERN_STRIP_ID + i, nullptr); - m_patternStrips.push_back(move(strip)); - i++; - } + 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, @@ -80,27 +76,15 @@ bool VortexCommunityBrowser::init(HINSTANCE hInst) m_hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1)); SendMessage(m_communityBrowserWindow.hwnd(), WM_SETICON, ICON_BIG, (LPARAM)m_hIcon); - m_runThreadId = CreateThread(NULL, 0, runThread, this, 0, NULL); - - return true; -} - -DWORD __stdcall VortexCommunityBrowser::runThread(void *arg) -{ - VortexCommunityBrowser *browser = (VortexCommunityBrowser *)arg; - while (1) { - if (browser->m_isOpen) { - browser->run(); - } + // 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)); } - return 0; -} -void VortexCommunityBrowser::run() -{ - for (auto strip : m_patternStrips) { - strip.get()->run(); - } + return loadPage(); } void VortexCommunityBrowser::show() @@ -135,92 +119,61 @@ void VortexCommunityBrowser::loseFocus() { } -std::wstring VortexCommunityBrowser::GetHttpRequest(const std::wstring& host, const std::wstring& path) +json VortexCommunityBrowser::fetchModesJson(uint32_t page, uint32_t pageSize) { - DWORD dwSize = 0; - DWORD dwDownloaded = 0; - LPSTR pszOutBuffer; - std::wstring result; - BOOL bResults = FALSE; - HINTERNET hSession = NULL, - hConnect = NULL, - hRequest = NULL; - - // Use WinHttpOpen to obtain a session handle. - hSession = WinHttpOpen(L"A Vortex Editor/1.0", - WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, 0); - if (!hSession) { - return L""; - } - hConnect = WinHttpConnect(hSession, host.c_str(), - INTERNET_DEFAULT_HTTP_PORT, 0); - // Create an HTTP request handle. - if (!hConnect) { - return L""; - } - hRequest = WinHttpOpenRequest(hConnect, L"GET", path.c_str(), - NULL, WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - 0); - // Send a request. - if (!hRequest) { - return L""; - } - bResults = WinHttpSendRequest(hRequest, - WINHTTP_NO_ADDITIONAL_HEADERS, 0, - WINHTTP_NO_REQUEST_DATA, 0, - 0, 0); - - // End the request. - if (!bResults) { - return L""; + HttpClient httpClient("VortexEditor/1.0"); + json result; + try { + map queryParams = { + { "page", to_string(page) }, + { "pageSize", to_string(pageSize) }, + }; + string jsonResponse = httpClient.SendRequest("vortex.community", "/modes/json", "GET", {}, "", queryParams); + // Parse and return the JSON object + result = json::parse(jsonResponse); + } catch (const exception &e) { + cerr << "Exception caught: " << e.what() << endl; } - bResults = WinHttpReceiveResponse(hRequest, NULL); + return result; +} - // Keep checking for data until there is nothing left. - if (!bResults) { - return L""; +bool VortexCommunityBrowser::loadPage() +{ + // fetch json of modes from community api + try { + m_communityModes = fetchModesJson(m_curPage, MODES_PER_PAGE); + } catch (...) { + return false; } - do { - // Check for available data. - dwSize = 0; - if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) { - //std::wcout << L"Error " << GetLastError() << L" in WinHttpQueryDataAvailable.\n"; - } - - // Allocate space for the buffer. - pszOutBuffer = new char[dwSize + 1]; - if (!pszOutBuffer) { - //std::wcout << L"Out of memory\n"; - dwSize = 0; - return L""; - } - // Read the data. - ZeroMemory(pszOutBuffer, dwSize + 1); - if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) { - delete[] pszOutBuffer; - return L""; - } - result.append(pszOutBuffer, pszOutBuffer + dwDownloaded); - // Free the memory allocated to the buffer. - delete[] pszOutBuffer; - } while (dwSize > 0); - - // Close any open handles. - if (hRequest) { - WinHttpCloseHandle(hRequest); + // Verify if 'data' is an array + if (!m_communityModes.contains("data")) { + cerr << "'data' is not an array or does not exist" << endl; + return false; } - if (hConnect) { - WinHttpCloseHandle(hConnect); + for (uint32_t i = 0; i < MODES_PER_PAGE; ++i) { + auto mode = m_communityModes["data"][i]; + m_patternStrips[i]->loadJson(mode); } - if (hSession) { - WinHttpCloseHandle(hSession); + uint32_t numPages = m_communityModes["pages"]; + m_lastPage = (m_curPage == numPages); + m_pageLabel.setText(to_string(m_curPage) + " / " + to_string(numPages)); + return true; +} + +bool VortexCommunityBrowser::prevPage() +{ + if (m_curPage <= 1) { + return false; } + m_curPage--; + return loadPage(); +} - if (result.empty()) { - return std::wstring(); +bool VortexCommunityBrowser::nextPage() +{ + if (m_lastPage) { + return false; } - return result; + m_curPage++; + return loadPage(); } diff --git a/VortexEditor/VortexCommunityBrowser.h b/VortexEditor/VortexCommunityBrowser.h index 79e607b..79378c4 100644 --- a/VortexEditor/VortexCommunityBrowser.h +++ b/VortexEditor/VortexCommunityBrowser.h @@ -27,17 +27,17 @@ class VortexCommunityBrowser // 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(); - std::wstring GetHttpRequest(const std::wstring &host, const std::wstring &path); + json fetchModesJson(uint32_t page = 1, uint32_t pageSize = 15); + bool loadPage(); + bool prevPage(); + bool nextPage(); bool isOpen() const { return m_isOpen; } - HWND hwnd() const { return m_communityBrowserWindow.hwnd(); } private: @@ -49,8 +49,14 @@ class VortexCommunityBrowser 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 runThread(void *arg); + HINSTANCE m_hInstance; bool m_isOpen; @@ -62,10 +68,20 @@ class VortexCommunityBrowser // mutex to synchronize access to vortex engine HANDLE m_mutex; // thread that runs the community browser vortex engine instance - HANDLE m_runThreadId; + //HANDLE m_runThreadId; // child window for mode randomizer tool VChildWindow m_communityBrowserWindow; // preview of color - std::vector> m_patternStrips; + 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 1f87cd8..1bafd94 100644 --- a/VortexEditor/VortexEditor.cpp +++ b/VortexEditor/VortexEditor.cpp @@ -208,7 +208,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); @@ -248,10 +249,14 @@ bool VortexEditor::init(HINSTANCE hInst) m_communityBrowser.init(hInst); SetWindowPos(m_communityBrowser.hwnd(), 0, pos.right + 2, pos.top - 200, 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(); + //m_colorPicker.show(); + //m_modeRandomizer.show(); + //m_communityBrowser.show(); // apply the icon m_hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1)); @@ -383,8 +388,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(); @@ -1283,6 +1291,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()); @@ -1918,3 +1944,8 @@ int VortexEditor::getPortListIndex() const } return -1; } + +void VortexEditor::beginTutorial() +{ + m_tutorial.show(); +} diff --git a/VortexEditor/VortexEditor.h b/VortexEditor/VortexEditor.h index ff69abc..365f48f 100644 --- a/VortexEditor/VortexEditor.h +++ b/VortexEditor/VortexEditor.h @@ -28,6 +28,7 @@ #include "VortexColorPicker.h" #include "VortexModeRandomizer.h" #include "VortexCommunityBrowser.h" +#include "VortexEditorTutorial.h" #include "ArduinoSerial.h" // stl includes @@ -64,6 +65,8 @@ class VortexEditor HINSTANCE hInst() const { return m_hInstance; } + void addMode(VWindow *window, const Mode *mode); + private: // print to the log static void printlog(const char *file, const char *func, int line, const char *msg, ...); @@ -191,6 +194,9 @@ class VortexEditor // get the current pattern selection from the pattern dropdown PatternID patternSelection() const; + // start the interactive tutorial + void beginTutorial(); + // ================================== // Member data @@ -244,12 +250,13 @@ 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; }; extern VortexEditor *g_pEditor; diff --git a/VortexEditor/VortexEditor.rc b/VortexEditor/VortexEditor.rc index 8e36419..72a153a 100644 --- a/VortexEditor/VortexEditor.rc +++ b/VortexEditor/VortexEditor.rc @@ -108,7 +108,8 @@ BEGIN 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 @@ -161,6 +162,28 @@ BEGIN END END + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BITMAP1 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\chromadeck-logo-square-64.bmp" + +IDB_BITMAP2 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\gloves-logo-square-64.bmp" + +IDB_BITMAP3 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\handle-logo-square-64.bmp" + +IDB_BITMAP4 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\orbit-logo-square-64.bmp" + +IDB_BITMAP5 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\chromadeck-logo-square-green-64.bmp" + +IDB_BITMAP6 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\gloves-logo-square-green-64.bmp" + +IDB_BITMAP7 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\handle-logo-square-green-64.bmp" + +IDB_BITMAP8 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\orbit-logo-square-green-64.bmp" + #endif // English (United Kingdom) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/VortexEditor/VortexEditor.vcxproj b/VortexEditor/VortexEditor.vcxproj index c0b4445..5e2db5c 100644 --- a/VortexEditor/VortexEditor.vcxproj +++ b/VortexEditor/VortexEditor.vcxproj @@ -143,7 +143,7 @@ true $(ProjectDir);$(ProjectDir)\EngineDependencies;$(ProjectDir)\VortexEngine\VortexEngine\src\;$(ProjectDir)\VortexEngine\VortexEngine\VortexLib\ MultiThreaded - Disabled + MaxSpeed Windows @@ -167,13 +167,16 @@ + + + @@ -190,19 +193,30 @@ + + + + + + + + + + + diff --git a/VortexEditor/VortexEditor.vcxproj.filters b/VortexEditor/VortexEditor.vcxproj.filters index 0f8e5e3..fb7a33c 100644 --- a/VortexEditor/VortexEditor.vcxproj.filters +++ b/VortexEditor/VortexEditor.vcxproj.filters @@ -81,6 +81,15 @@ Source Files\GUI + + Source Files\GUI + + + Source Files + + + Source Files + @@ -146,6 +155,15 @@ Header Files\GUI + + Header Files\GUI + + + Header Files + + + Header Files + @@ -156,5 +174,29 @@ 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..d490763 --- /dev/null +++ b/VortexEditor/VortexEditorTutorial.cpp @@ -0,0 +1,240 @@ +#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() +{ +} + +VortexEditorTutorial::~VortexEditorTutorial() +{ + DestroyIcon(m_hIcon); +} + +// 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, selectOrbitCallback); + 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, selectOrbitCallback); + 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, selectOrbitCallback); + 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()) { + 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(40); // 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); +} diff --git a/VortexEditor/VortexEditorTutorial.h b/VortexEditor/VortexEditorTutorial.h new file mode 100644 index 0000000..a9ff250 --- /dev/null +++ b/VortexEditor/VortexEditorTutorial.h @@ -0,0 +1,102 @@ +#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); + } + + void selectOrbit(uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent) { + } + + 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/resource.h b/VortexEditor/resource.h index 59a8bb2..59fa08e 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 @@ -49,13 +57,15 @@ #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 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 109 -#define _APS_NEXT_COMMAND_VALUE 40064 +#define _APS_NEXT_RESOURCE_VALUE 117 +#define _APS_NEXT_COMMAND_VALUE 40066 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/chromadeck-logo-square-64.bmp b/chromadeck-logo-square-64.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5008941917ab9ef7a599286900737d4f9a341437 GIT binary patch literal 5176 zcmds4cT`kY8vikXKy=XIAqXN@5tI-*f(WCq4kfTd2{lNytSgZP*+iOAiJ~C5iUx#` z6%-JHh+-^A?24<4ZP#9p?O2b!cX!_4d-L8nOh)tHzH?^o?<>FWe)qobmNz=Y(-`u{ zLkF;xA>a2uE$GYjfeMN`di4tL-o3-st5-2>*f4l_ zc;Nc=>o{@Z1nTPQ5EmB*A0HnqU%ni-Z{J37aj`swTeoh(+uIvbsT4bQ?7*8hZ*cMA zMG!)8<;oRo+qMmXfr0Sy@j~_qAqeqXBpPvtFYiqcshFz(*Hi~ale!`0Ol5fKr%dGjWwPoEAgEiG7BSm5EqhcGcQ!Mu6%aP8VP1O)|Q z=+L2)<#E12g1U_P*G8VRjXFP$;kq_U%rfu8#ki1wicC@l{j|n81(e?uw}~@=<4d?`0?X7 za^wh-lapa@Z;w5D_Q1~04u=jM!kIH?U}e}8|RJb4m+etuZDZXLF6-HOuEQmk3C1_urtKz4RER<2x$tgI|JI5^<> z^XF)4YC?H=Iff4(j+B%X2m}J;=H{ZRstV@j<~Vom97c^Ah0xGY7#J8pUtb@Qk&!rk z`ZN|TT7-iK4;?(UA9oE$VZHXHnq`x|Rh0xUf~% zqV?;;|M{=0;G+iSdf=d56D506&3mWPZQ-HL8dnWN2>#t^Lv!e-mXQ5jh@wIpJvGQe zP*E;r7!>s{pS>c5ByHU%`JE*8G;`Q8W*lEMYL8VHz;$#)J``yh1%)6UB7gbLjPa4izPu!fVeFrH%`tkBgC22O2oR=cB%qM zqAIB>B93Q0X?}yY_Ew6^Hw`3TQEA&$Ok-OiMQv(pXXsSoZ}q<=QUeE2lzV->HLLz+ z^Utz!sQMtldNy&^RR-KQY|P=x3@%h&aO*r66R-W2kOrQD5z_c`@WVvLz;6qG3Rg@$ z&m@}3nMC0vuI*QO$#XSbxRNbvTFw$G0?g++w~C7@xiW)Ctrf>Gm~Mkv{>*_~eG4J| zxH5x9tH~M$)9nDJjwD%JHD%n}mnXBr!j>;tOoPn#mE5<9r`A}oUnL)bWTnOoCC6rY z75$>Ja+F+EicOw$0x2qO8YvrPbS+U*osmY~N>0`>c_J;KL{HpJjVk#oi`hh+Py*EE z2a-Bvn$xJrY6$C1`53l;oNK|e0~6qbUsSfe2; z{FPDkXUdw7lY9PAe(A^cr|g}rtE~ArdEp;ey>w3txLdE{lv0}nr+lb?^k-e|wTtvw zK@FHXuUJv2B?au!EL%Tw)X-SdTte8>s!$+EphVN)O+^Zk zos%ohQ{&#PDNH==`((gsDk1y>q+15xkV1%_>=>V7llgbWdgi;Rm89O^eka>MFF#9-@NOSe>NnjaG}$+e7vgWs z4a98}SN|6xX6uWq4;7QYa%JbfUERz6lezj7@mMde%-}D_5#Fnsz|x^*z&O$E7?pI2 zicjFKyd>`TL@fVi!bX#RZQ0G+HI<+JYzk4TuX)jg@a|k};GoZ0Y8Uv5|Do{S@r%HS zNS4C^(f}noB!89#@CtF@IMJ|QsFEVgTQ)mJ;UCGedVd^u}{;}{Xac3Jv}|gbX@-)E$Xkn+&l7b z_=kUgXz>@Q7A^kB-~aq4@vol2t>ee5Q>RY;{{F>AT!n>&W@cs|^=bb88aHfuW9ic zVh$ZT)Y*v3&d#nWo|!ahk`YFn`}gm!=~BjRc6PQggY)_G=lTafcA4Gh&!0EON@ixJ zCVp0S85|xye3+D!xM*=OzfGGqHr?E~apN?VOJ=WLy_&9V-MXIzhRCR;Ok2_L#*G`A zy*zd5RH^yYsZ$+0wf}p|zw)!OwU+!wiQwR1300F=xNu>kN~D0f`51wLJ1e__uZ|MD zQB+iv6j0*tW74a#vf_XBSMZ{s%a<=nF*89yi_`b3b(NiY<&v@DNJ>@87>)HPJ?m8g=j9J*i5CU#SOr%-El1&zUKH zKEB>BU%r$LA~=QTz;~f`Yv?dHeS5xbYSQ3T5-tr%$W;m&XGK4k%@|ZQE)#()8K0XD}-& zDq6Mvr!HnCM};52691qv!+oDXljJ|IlHBWs}OPiU9-r-@biYa+HZ2 z&fm3bm;BS?$B%~%A6i^oBsr6;nvI{f%vn5x^7#08sY(#d#ZRj>YjQ0oPI&R+g;Zr_ zWhJ^`*sx)e$(*&fx6Q~%mmCPg@P~$mqQ6U*E}J)RR%(Mb06(q#{e78+vMWnVOWU<; z$K=|!ZJX2|9uem3GEd3~zG3)x?%av@H3Y!Cyrmcc8x^ar%#{Oty|0WV$0V5 zjQYt;%vmV|VHkemcIVEWEi5ePQ>8X&!|>CP{a611eJiUz#CaPV8xnq@9G%Qr%`K8) z_)$A}@L*3*PoZCVHyA%k4jn$kE8M(w6FM+3(96pU;^Cu*Lxv9Cx35%bMbZZ2pFVwh zSXh|UBZ)I-&X}2*=H{-hK2p75Lmnwmc||$2o4ae?hPJB_y8Y0lxTJV*!Cp*Yh~I#L{r3EK55)TQ|L)qY zvnqaywmv>Sx;a1b&BfI@B{dltCR%cGQe@;(As-eNdhA$T0q5YsD)cv0FFJhq@QSPz zh<(DpD!Z_#P$*H|F-IsaDJg-ELQDvOgoOCz>1l!ngQKH^OrfQQl$4b9>(|Ri2$HCn zm}sy0o^RjQ<=Z5LbLY-xJryz%KaccIUBG<#DPRg2?oG#E7fz?xrDrS`ZI$>j%`zb| z10yCjTAC2Vh7B8viaxC)csnm|JqiDV+6O{l$Bymp?yj3&u}Ju zJ@^S4WRFr|c=(ce&Q4N;5kc=`F8RpC^HzjR;e%$bhT`qisf z`h&7W$gwH4f9KQ4*9IRQTZ&FsC~@2mye_#>PVH!5sMi60UA`}ztQnS z6IVAE6@Hl3Hdfp}2Y%LWYip|smg6b)i}i~Q4jXejdz-TIvd@kG(W6Hqh8yhv6DN+7 zMK2Cn#7Zsjvl0=9Sr$u5ijBcf;tD+6&ZX&patupLOOh@G^y6np>GcU z6DLmaQmlQnlJgf-M0wFE3Z&XJdsq6@F?0LK5M1>(;S<1Z_q}29I1U{p^@@ z@w3NN;U}{ikhr_MGp#_*W7F~H<>h^O{PmFa z-M-_eQ<@%snmc~P?c2tRey6)WoSQw7b;%plcY5*Et$ zORU~*W37*fh^VPK#xc=|k)TJ3M#1Ky2*_1Jal=zd96FJ?ZNJwC3 z*T4>lW8%=z#T;|j);^dpVS=tUT@De60wzb&ED-GA0s;b%0Y5`MAu*mw$J7Hq(~x>^ zX=w=?b1KhlvUF87#7Rg<-MbM6njBs&r2CeXa*REZ+Y}tYsg9kA>PFIyChg~Y+lrI)!jKUoFNtv9S z=Ah8Y$%%$2^LN~83gEn8~F_4x^ttX!FeL+BKm_vq0BF|x|0 zgV!{gn3z~zUPdS*ZZQ5wj~=ZlW-yZ;!7cF#ahND6ElEmBGFX*nLnZ}Pccuf!0XRof z#uz5vCKIE=cJ=BNO#J5lq5Jqug7YTkDPPJN1GS;Hqye~{j{&Alo7VKv(xS!x0TEGx ASpWb4 literal 0 HcmV?d00001 diff --git a/handle-logo-square-64.bmp b/handle-logo-square-64.bmp new file mode 100644 index 0000000000000000000000000000000000000000..530662cc38a3c6f0c530caad95da26a58a4b0678 GIT binary patch literal 5176 zcmdUzX;c*18HV2;z-A=H9*N8-i?Z3GHYmG*2+BGNsDMaEkU>CYQE&-CmO)ttTp1EG z3T{MjkBUSM5XKQOXhe^mfZ0(st$!2EP$=8Ev{X=hULqbeMO3#>T?a(-X62&&H)omk<;bgc~<*AS^5lCr+F|PEHP0!Wt0a&$a6&^fzfMdsw z;r;vf*uQ^23=Iu2bm&lYbaY_bwrz-ui^Ic*53zgqZmeIw9xq?ML~Cm+UcY{gef#zy zH#ZlPCQZVyVZ(6z_;JL?$K%P9CkPG>#@xAc;q2^;Wy_Y~-Me=vDJg-8i3!G!ACKDF zTGZFq!`Igrg@uK9{`@&QJ3A2`9*)Y&O5C|~2jj+#gO867^78UfP*8wPn>HaTDhjJt zug2}$w_#>xhW7S$7#kboz<~p(s;YuiD#iBg+i~>hQFM2A1x}tki4h}4;PK zQc_Z|aN$CX9z7aXR#s?kZpN-%yKwmMVKg;0;rjLKNKa44+O=zyWBHr?kku9IWcu~6 zV?z&R(4(j0+sa*)q(R3;rO*Vn(c{~#ljtJ_V#C;}+sC0R114tn0a@A06|(leF~iui zMUpR)&-p3pJiq_F%;{$tSLYvLeCsQz9Z6rErnK-i7z#?*gg zshS@h&L`MaNsp1-f2p~GUV+-bQGgX=dDC=n#PQ94&JiShO*%D><<|#?2mw|!@!Z54 zWqdP8$g6o#uK$gPsu>?H}v1UrU? zpOOFVXZHg4je;F*0kDpC_JxL~UppZRSgoy6Mb5rZ6|SM7c7uKP`$1c!N^lh*TSY_d zMx~~|WJU7Ilu~tCd^~BF-N`I5Su| zKxxHPkV}AX>1d?zE6_5&q#5Q<-1DCwNzcnrji2JrM2TM_@Q3;HSdmM3Hs@bRqQ!(~ z5ry+F3gRO>3E`x=8BKo<;Yq~LE>8e?zEt~Z|C)aK{ir{M`+g~WZ}ZGa|MN-z?DPT# zlE{tl45Fk9{icId+lwM0m2h@?0kcUILkf`A7w4Zy?{EC91nvxf)FTE))6XO(aePj) zoFshD`ejo|#4wRj(e~4(tK%8m`OTfF5MvpuKZa}wtU8m$((fqNYS?oAkiH-Ar*J$% z%SMI%{Os}s(8Z40Xrn(ryF3AtX?pL5gYx%~5LzI;IpZ(x59Z1TGP0R!*;RfcXKkQT zf|Pzi0rpOu#PzQ(;NCbu|6$S82nC^U}&Ta`OcO9l!CE|ikq5gab=R^D;@TiC0)G%^u)q0*pujg&2im< Hn)3eui)1i` literal 0 HcmV?d00001 diff --git a/orbit-logo-square-64.bmp b/orbit-logo-square-64.bmp new file mode 100644 index 0000000000000000000000000000000000000000..69f2732e7966e044f56687a914ebe6c00ac8e6be GIT binary patch literal 5176 zcmds5XH-;48oe}e6c-Cep_`mU#sMTKu8uSoAj=XJ+y(>#K|vIZD2qrC1;IEYtT>rU_ym;*R01J&(U+tIfs4kH4U#L_;>4^?)TOA-Fqv%s`{#%h7A86Tp6YV z3}P&wj*k`$IKQATVBA~!;T+7@ph1IRXJ-d%Yioprgdi_34;2*^*s)^=_U+q;wHf%t4b~XY717T%lh3M#L)YjJG{{8#-`t>Vr-@c8uwl-8(S7Y3`ad2>O0HqY? z&!5MaFJJKa^JknobqX6dZiJVY7wqlr5g8eYJ$v@x?c29_`t&Ip8XDm5?~f59M&QGT z4|w6DMNTs#OpO1Sl>p#;jShpslTqZQHiN)6)|V9y~xvNeSxe>TvVsO|-YS zBPl5fGiJ=dix)3YR#t{jpFSZzJ|4%89fPs4F_tf14v|QN3l}aRI5-%K7A?Z!#fvd* z+B6gv7GmbinJ_am!=p!!FnsuMBqk=}=+UECx^yXWa&oYJ`*uhq5?s4>4SoCeMP+3r zva+&ZYHErjM~=Y7#RXTcT*0PIo3L)(I-EOq4i**`$j!}#udgpYe*B23Q>Vhl#s*if zUPXR>K2lOr5D*Z6_wV0h_wLZ)6>J9J9n^i z=T7Y1yBE`^Pe)5j3(lTBi-QLbV%f4~*uQ^2Zrr$mOP4MoDk=&qR;<9BIdiaU*De?t z8Nt=n6&EjFgp-pK`t|Dv6B830I&=sH1qB#AdNd9nK8&KGB2-mXVe{tA$jr>d!i5Ww zkdT0&pddVc{1|CzX^4r5!O4>+F@F4btX;bnZ{EB?L_`G2%gZru-aMQ*aROtUut z6JTg)2(eg<$&)9eckkX9IB+1Eo0}0D8j7Z-CX5<23PXkr!ILLXaO>7BT)%!D;o;%% z_V&h>EnDF1?2MY48k|0T8U_XiIB?(qUcP*Z*w|S3`1oMx(4n&J^nddlATTMYi!ano zclxESpeeign+7(xzB<^L@Jd;Dj=fe7C7RDvw}^P$4pX9^`C|`y(OgsblQLQA+0k&w zy_-%f)pb7-RQ zg64x#LY8(TLucl|T(v+7+cZiKP2=cD+nHl;4RV5;q2u=A1`$yL?j1i|*$H7Io3d zuBmJX?D$a8UK*2Z!ifBX?kMs=0PvTiGnE_;OTA0G0>3d!n=K=|TvE#l*r4c>G_p`{xpxr22^7n>&JY7Iz)X=( zL{bYT_Gj87UNP_4$E^S2Sxi^q*8vnp#b1jfxj9)0wYf z{<40hbiE6uRkHI%M&dntDJ_3qFy+?@*UF8X=JQ;NX4rZ~&$rdfhpEB~d3#qDFOwN^ z&%b16$!I=Wk~mB%qPVKI}T6a+>x+3go)fpwNxrN|epX3vij zxfdf%jwwn489=cjKaiy}0=#9nfXl6vDs46wpvYBDK$Nq55XYa+cQ4{x_R$&gJ($;r zIe_K1r?7w~nk{9}a&$tbFs@~0F*HX`ppZTP|IB*>BDSII#UV6@-#TmO(!2$1a@64o zD+lLmR!byg4|=OhD3~ zZ62_6mZBunB9oaThf?-Bp`t{xu|(7U(>vNrmEAxrxI2p^iqa|3F;pC{g3GxQ#56HZ zo6^agKoXZdxgPw93A1!cBcfv_sG~Dime@Gvl0xYuR$wwm<-P>t2$4=5jU2C@PKalJ zmd?BdLi7iB@evYAq$!SuX`&P2!O?xg$=DDc9T?+D0{+0nx=km4WI#c|+8np4c0JNq!oobbp4shi6aNEN191WjfOz7x|s2 zR&9vl*kxn+v11{sWwHUGKKs{{>LPH`lxsLyV;%l`SCVniAE>EyM?3Y6OSLSmtZmdO z*xK2v|MAw@l>sJ3rm`){Qxch(Tl9d<$@KZ1kwIS`ml*f^zCUwU{Dz_>(ALq_(>E~q OPOn#QLxF}L-~R*J)d*++ literal 0 HcmV?d00001 From ae220e8a961b79836c54ac05d7f5c9fb7f29d7c9 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 24 Apr 2024 19:55:55 -0700 Subject: [PATCH 04/15] more work on windows --- VortexEditor/GUI/VSelectBox.cpp | 833 ++++++++++++------------ VortexEditor/VortexCommunityBrowser.cpp | 15 +- VortexEditor/VortexCommunityBrowser.h | 4 + VortexEditor/VortexEditorTutorial.cpp | 76 ++- VortexEditor/VortexEditorTutorial.h | 30 +- 5 files changed, 517 insertions(+), 441 deletions(-) diff --git a/VortexEditor/GUI/VSelectBox.cpp b/VortexEditor/GUI/VSelectBox.cpp index 0d0b1c7..8e4eda5 100644 --- a/VortexEditor/GUI/VSelectBox.cpp +++ b/VortexEditor/GUI/VSelectBox.cpp @@ -1,431 +1,402 @@ -#include "VSelectBox.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_HUE_SAT_BOX "VSelectBox" - -#define PI 3.141592654 - -WNDCLASS VSelectBox::m_wc = {0}; - -VSelectBox::VSelectBox() : - VWindow(), - m_borderSize(1), - m_width(0), - m_height(0), - m_innerLeft(0), - m_innerTop(0), - m_innerRight(0), - m_innerBottom(0), - m_innerWidth(0), - m_innerHeight(0), - m_drawHLine(true), - 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_hoverBitmap(nullptr) -{ -} - -VSelectBox::VSelectBox(HINSTANCE hInstance, VWindow &parent, const string &title, - COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, - uintptr_t menuID, VSelectBoxCallback callback) : - VSelectBox() -{ - init(hInstance, parent, title, backcol, width, height, x, y, menuID, callback); -} - -VSelectBox::~VSelectBox() -{ - cleanup(); -} - -void VSelectBox::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, VSelectBoxCallback callback) -{ - // store callback and menu id - m_callback = callback; - - // register window class if it hasn't been registered yet - registerWindowClass(hInstance, backcol); - - if (!menuID) { - menuID = nextMenuID++; - } - - if (!parent.addChild(menuID, this)) { - return; - } - - m_innerWidth = width; - m_innerHeight = height; - - 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; - - // create the window - m_hwnd = CreateWindow(WC_HUE_SAT_BOX, title.c_str(), - WS_CHILD | WS_OVERLAPPED | WS_VISIBLE | WS_TABSTOP | WS_CLIPCHILDREN, - x, y, m_width, m_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, "", backcol, 100, 24, x + width + 6, y + (height / 4), 0, nullptr); -} - -void VSelectBox::cleanup() -{ -} - -void VSelectBox::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 VSelectBox::paint() -//{ -// PAINTSTRUCT paintStruct; -// 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); -// -// // 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); -// DeleteDC(bmpDC); -// -// -// BitBlt(hdc, 0, 0, m_width, m_height, backbuffDC, 0, 0, SRCCOPY); -// -// DeleteObject(backbuffer); -// DeleteDC(backbuffDC); -// -// EndPaint(m_hwnd, &paintStruct); -//} - -void VSelectBox::paint() -{ - PAINTSTRUCT paintStruct; - memset(&paintStruct, 0, sizeof(paintStruct)); - HDC hdc = BeginPaint(m_hwnd, &paintStruct); - - HDC backbuffDC = CreateCompatibleDC(hdc); - HBITMAP backbuffer = CreateCompatibleBitmap(hdc, m_width, m_height); - HBITMAP hbmOldBackbuffer = (HBITMAP)SelectObject(backbuffDC, backbuffer); - - HDC bmpDC = CreateCompatibleDC(hdc); - HBITMAP hbmpOld = (HBITMAP)SelectObject(bmpDC, m_mouseInside ? m_hoverBitmap : m_bitmap); - - 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 - uint32_t selectorSize = 5; - if (m_drawHLine) { - SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); - if (m_drawCircle) { - if (m_xSelect > selectorSize) { - MoveToEx(backbuffDC, m_innerLeft, m_innerTop + m_ySelect, NULL); - LineTo(backbuffDC, m_innerLeft + (m_xSelect - selectorSize), m_innerTop + m_ySelect); - } - MoveToEx(backbuffDC, m_innerLeft + (m_xSelect + selectorSize), m_innerTop + m_ySelect, NULL); - LineTo(backbuffDC, m_innerLeft + m_innerWidth, m_innerTop + m_ySelect); - } else { - MoveToEx(backbuffDC, m_innerLeft, m_innerTop + m_ySelect, NULL); - LineTo(backbuffDC, m_innerLeft + m_innerWidth, m_innerTop + m_ySelect); - } - } - if (m_drawVLine) { - SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); - if (m_drawCircle) { - if (m_ySelect > selectorSize) { - MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop, NULL); - LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + (m_ySelect - selectorSize)); - } - MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + (m_ySelect + selectorSize), NULL); - LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + m_innerHeight); - } else { - MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop, NULL); - LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + m_innerHeight); - } - } - if (m_drawCircle) { - SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); - SelectObject(backbuffDC, GetStockObject(HOLLOW_BRUSH)); - Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize), - m_innerTop + (m_ySelect - selectorSize), - m_innerLeft + (m_xSelect + selectorSize) + 1, - m_innerTop + (m_ySelect + selectorSize) + 1); - SelectObject(backbuffDC, GetStockObject(BLACK_PEN)); - Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize) + 1, - m_innerTop + (m_ySelect - selectorSize) + 1, - m_innerLeft + (m_xSelect + selectorSize), - m_innerTop + (m_ySelect + selectorSize)); - SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); - Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize) + 2, - m_innerTop + (m_ySelect - selectorSize) + 2, - m_innerLeft + (m_xSelect + selectorSize) - 1, - 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) -{ -} - -void VSelectBox::pressButton(WPARAM wParam, LPARAM lParam) -{ - // Get the window client area. - RECT rc; - GetClientRect(m_hwnd, &rc); - // Convert the client area to screen coordinates. - POINT pt = { rc.left, rc.top }; - POINT pt2 = { rc.right, rc.bottom }; - ClientToScreen(m_hwnd, &pt); - ClientToScreen(m_hwnd, &pt2); - SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y); - // enable mouse capture on the window so we receive mouse move - SetCapture(m_hwnd); - // Confine the cursor. - ClipCursor(&rc); - m_pressed = true; - SelectEvent sevent = SELECT_PRESS; - if (wParam & MK_CONTROL) { - sevent = SELECT_CTRL_PRESS; - } - if (wParam & MK_SHIFT) { - sevent = SELECT_SHIFT_PRESS; - } - doCallback(sevent); -} - -void VSelectBox::releaseButton(WPARAM wParam, LPARAM lParam) -{ - if (!m_pressed) { - return; - } - ClipCursor(NULL); - ReleaseCapture(); - m_pressed = false; - doCallback(SELECT_RELEASE); -} - -void VSelectBox::mouseMove(uint32_t buttons, uint16_t x, uint16_t y) -{ - //if (inside != m_mouseInside) { - // if (inside) { - // mouseEnter(); - // } else { - // mouseLeave(); - // } - //} - if (!m_mouseInside) { - 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; - } - setBorderSize(0); - if (!m_pressed) { - return; - } - doCallback(SELECT_DRAG); -} - -void VSelectBox::doCallback(SelectEvent sevent) -{ - if (!m_callback) { - return; - } - POINT pos; - GetCursorPos(&pos); - ScreenToClient(m_hwnd, &pos); - if (pos.x < (LONG)m_innerLeft) pos.x = m_innerLeft; - if (pos.x > (LONG)m_innerRight) pos.x = m_innerRight; - if (pos.y < (LONG)m_innerTop) pos.y = m_innerTop; - if (pos.y > (LONG)m_innerBottom) pos.y = m_innerBottom; - uint32_t innerX = pos.x - m_innerLeft; - uint32_t innerY = pos.y - m_innerTop; - setSelection(innerX, innerY); - m_callback(m_callbackArg, innerX, innerY, sevent); -} - -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; - m_ySelect = y; - // redraw? - //redraw(); -} - -LRESULT CALLBACK VSelectBox::window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - VSelectBox *pSelectBox = (VSelectBox *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (!pSelectBox) { - return DefWindowProc(hwnd, uMsg, wParam, lParam); - } - switch (uMsg) { - case WM_VSCROLL: - break; - case WM_LBUTTONDOWN: - pSelectBox->pressButton(wParam, lParam); - break; - case WM_LBUTTONUP: - pSelectBox->releaseButton(wParam, lParam); - break; - case WM_MOUSEMOVE: - pSelectBox->mouseMove(wParam, LOWORD(lParam), HIWORD(lParam)); - break; - case WM_MOUSELEAVE: - InvalidateRect(pSelectBox->m_hwnd, nullptr, FALSE); - pSelectBox->m_mouseInside = false; - break; - case WM_CTLCOLORSTATIC: - return (INT_PTR)pSelectBox->m_wc.hbrBackground; - case WM_ERASEBKGND: - return 1; - case WM_CREATE: - pSelectBox->create(); - break; - case WM_PAINT: - pSelectBox->paint(); - return 0; - case WM_COMMAND: - pSelectBox->command(wParam, lParam); - break; - case WM_DESTROY: - pSelectBox->cleanup(); - break; - default: - break; - } - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -void VSelectBox::registerWindowClass(HINSTANCE hInstance, COLORREF backcol) -{ - if (m_wc.lpfnWndProc == VSelectBox::window_proc) { - // alredy registered - return; - } - // class registration - m_wc.lpfnWndProc = VSelectBox::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_HUE_SAT_BOX; - RegisterClass(&m_wc); -} \ No newline at end of file +#include "VSelectBox.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_HUE_SAT_BOX "VSelectBox" + +#define PI 3.141592654 + +WNDCLASS VSelectBox::m_wc = {0}; + +VSelectBox::VSelectBox() : + VWindow(), + m_borderSize(1), + m_width(0), + m_height(0), + m_innerLeft(0), + m_innerTop(0), + m_innerRight(0), + m_innerBottom(0), + m_innerWidth(0), + m_innerHeight(0), + m_drawHLine(true), + 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_hoverBitmap(nullptr) +{ +} + +VSelectBox::VSelectBox(HINSTANCE hInstance, VWindow &parent, const string &title, + COLORREF backcol, uint32_t width, uint32_t height, uint32_t x, uint32_t y, + uintptr_t menuID, VSelectBoxCallback callback) : + VSelectBox() +{ + init(hInstance, parent, title, backcol, width, height, x, y, menuID, callback); +} + +VSelectBox::~VSelectBox() +{ + cleanup(); +} + +void VSelectBox::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, VSelectBoxCallback callback) +{ + // store callback and menu id + m_callback = callback; + + // register window class if it hasn't been registered yet + registerWindowClass(hInstance, backcol); + + if (!menuID) { + menuID = nextMenuID++; + } + + if (!parent.addChild(menuID, this)) { + return; + } + + m_innerWidth = width; + m_innerHeight = height; + + 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; + + // create the window + m_hwnd = CreateWindow(WC_HUE_SAT_BOX, title.c_str(), + WS_CHILD | WS_OVERLAPPED | WS_VISIBLE | WS_TABSTOP | WS_CLIPCHILDREN, + x, y, m_width, m_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, "", backcol, 100, 24, x + width + 6, y + (height / 4), 0, nullptr); +} + +void VSelectBox::cleanup() +{ +} + +void VSelectBox::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 VSelectBox::paint() +{ + PAINTSTRUCT paintStruct; + memset(&paintStruct, 0, sizeof(paintStruct)); + HDC hdc = BeginPaint(m_hwnd, &paintStruct); + + HDC backbuffDC = CreateCompatibleDC(hdc); + HBITMAP backbuffer = CreateCompatibleBitmap(hdc, m_width, m_height); + HBITMAP hbmOldBackbuffer = (HBITMAP)SelectObject(backbuffDC, backbuffer); + + HDC bmpDC = CreateCompatibleDC(hdc); + 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 + uint32_t selectorSize = 5; + if (m_drawHLine) { + SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); + if (m_drawCircle) { + if (m_xSelect > selectorSize) { + MoveToEx(backbuffDC, m_innerLeft, m_innerTop + m_ySelect, NULL); + LineTo(backbuffDC, m_innerLeft + (m_xSelect - selectorSize), m_innerTop + m_ySelect); + } + MoveToEx(backbuffDC, m_innerLeft + (m_xSelect + selectorSize), m_innerTop + m_ySelect, NULL); + LineTo(backbuffDC, m_innerLeft + m_innerWidth, m_innerTop + m_ySelect); + } else { + MoveToEx(backbuffDC, m_innerLeft, m_innerTop + m_ySelect, NULL); + LineTo(backbuffDC, m_innerLeft + m_innerWidth, m_innerTop + m_ySelect); + } + } + if (m_drawVLine) { + SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); + if (m_drawCircle) { + if (m_ySelect > selectorSize) { + MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop, NULL); + LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + (m_ySelect - selectorSize)); + } + MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + (m_ySelect + selectorSize), NULL); + LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + m_innerHeight); + } else { + MoveToEx(backbuffDC, m_innerLeft + m_xSelect, m_innerTop, NULL); + LineTo(backbuffDC, m_innerLeft + m_xSelect, m_innerTop + m_innerHeight); + } + } + if (m_drawCircle) { + SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); + SelectObject(backbuffDC, GetStockObject(HOLLOW_BRUSH)); + Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize), + m_innerTop + (m_ySelect - selectorSize), + m_innerLeft + (m_xSelect + selectorSize) + 1, + m_innerTop + (m_ySelect + selectorSize) + 1); + SelectObject(backbuffDC, GetStockObject(BLACK_PEN)); + Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize) + 1, + m_innerTop + (m_ySelect - selectorSize) + 1, + m_innerLeft + (m_xSelect + selectorSize), + m_innerTop + (m_ySelect + selectorSize)); + SelectObject(backbuffDC, GetStockObject(WHITE_PEN)); + Ellipse(backbuffDC, m_innerLeft + (m_xSelect - selectorSize) + 2, + m_innerTop + (m_ySelect - selectorSize) + 2, + m_innerLeft + (m_xSelect + selectorSize) - 1, + 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) +{ +} + +void VSelectBox::pressButton(WPARAM wParam, LPARAM lParam) +{ + // Get the window client area. + RECT rc; + GetClientRect(m_hwnd, &rc); + // Convert the client area to screen coordinates. + POINT pt = { rc.left, rc.top }; + POINT pt2 = { rc.right, rc.bottom }; + ClientToScreen(m_hwnd, &pt); + ClientToScreen(m_hwnd, &pt2); + SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y); + // enable mouse capture on the window so we receive mouse move + SetCapture(m_hwnd); + // Confine the cursor. + ClipCursor(&rc); + m_pressed = true; + SelectEvent sevent = SELECT_PRESS; + if (wParam & MK_CONTROL) { + sevent = SELECT_CTRL_PRESS; + } + if (wParam & MK_SHIFT) { + sevent = SELECT_SHIFT_PRESS; + } + doCallback(sevent); +} + +void VSelectBox::releaseButton(WPARAM wParam, LPARAM lParam) +{ + if (!m_pressed) { + return; + } + ClipCursor(NULL); + ReleaseCapture(); + m_pressed = false; + doCallback(SELECT_RELEASE); +} + +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; + } + doCallback(SELECT_DRAG); +} + +void VSelectBox::doCallback(SelectEvent sevent) +{ + if (!m_callback) { + return; + } + POINT pos; + GetCursorPos(&pos); + ScreenToClient(m_hwnd, &pos); + if (pos.x < (LONG)m_innerLeft) pos.x = m_innerLeft; + if (pos.x > (LONG)m_innerRight) pos.x = m_innerRight; + if (pos.y < (LONG)m_innerTop) pos.y = m_innerTop; + if (pos.y > (LONG)m_innerBottom) pos.y = m_innerBottom; + uint32_t innerX = pos.x - m_innerLeft; + uint32_t innerY = pos.y - m_innerTop; + setSelection(innerX, innerY); + m_callback(m_callbackArg, innerX, innerY, sevent); +} + +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; + m_ySelect = y; + // redraw? + //redraw(); +} + +LRESULT CALLBACK VSelectBox::window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + VSelectBox *pSelectBox = (VSelectBox *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (!pSelectBox) { + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + switch (uMsg) { + case WM_VSCROLL: + break; + case WM_LBUTTONDOWN: + pSelectBox->pressButton(wParam, lParam); + break; + case WM_LBUTTONUP: + pSelectBox->releaseButton(wParam, lParam); + break; + case WM_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)pSelectBox->m_wc.hbrBackground; + case WM_ERASEBKGND: + return 1; + case WM_CREATE: + pSelectBox->create(); + break; + case WM_PAINT: + pSelectBox->paint(); + return 0; + case WM_COMMAND: + pSelectBox->command(wParam, lParam); + break; + case WM_DESTROY: + pSelectBox->cleanup(); + break; + default: + break; + } + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +void VSelectBox::registerWindowClass(HINSTANCE hInstance, COLORREF backcol) +{ + if (m_wc.lpfnWndProc == VSelectBox::window_proc) { + // alredy registered + return; + } + // class registration + m_wc.lpfnWndProc = VSelectBox::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_HUE_SAT_BOX; + RegisterClass(&m_wc); +} diff --git a/VortexEditor/VortexCommunityBrowser.cpp b/VortexEditor/VortexCommunityBrowser.cpp index 94f36ad..d61c51d 100644 --- a/VortexEditor/VortexCommunityBrowser.cpp +++ b/VortexEditor/VortexCommunityBrowser.cpp @@ -29,6 +29,7 @@ using namespace std; VortexCommunityBrowser::VortexCommunityBrowser() : + m_hThread(nullptr), m_hInstance(nullptr), m_isOpen(false), m_hIcon(nullptr), @@ -84,7 +85,19 @@ bool VortexCommunityBrowser::init(HINSTANCE hInst) m_patternStrips.push_back(move(strip)); } - return loadPage(); + m_hThread = CreateThread(NULL, 0, backgroundLoader, this, 0, NULL); + + return true; +} + +DWORD __stdcall VortexCommunityBrowser::backgroundLoader(void *pthis) +{ + VortexCommunityBrowser *browser = (VortexCommunityBrowser *)pthis; + Sleep(300); + browser->loadPage(); + CloseHandle(browser->m_hThread); + browser->m_hThread = nullptr; + return 0; } void VortexCommunityBrowser::show() diff --git a/VortexEditor/VortexCommunityBrowser.h b/VortexEditor/VortexCommunityBrowser.h index 79378c4..77d0653 100644 --- a/VortexEditor/VortexCommunityBrowser.h +++ b/VortexEditor/VortexCommunityBrowser.h @@ -56,6 +56,10 @@ class VortexCommunityBrowser ((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; diff --git a/VortexEditor/VortexEditorTutorial.cpp b/VortexEditor/VortexEditorTutorial.cpp index d490763..48bc927 100644 --- a/VortexEditor/VortexEditorTutorial.cpp +++ b/VortexEditor/VortexEditorTutorial.cpp @@ -32,13 +32,19 @@ VortexEditorTutorial::VortexEditorTutorial() : m_glovesSelect(), m_chromadeckBitmap(), m_chromadeckSelectedBitmap(), - m_chromadeckSelect() + 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 @@ -80,7 +86,7 @@ bool VortexEditorTutorial::init(HINSTANCE hInst) m_orbitSelect.setBorderSize(0); // the handles select - m_handlesSelect.init(hInst, m_tutorialWindow, "handles", BACK_COL, 64, 64, 124, 100, 123124, selectOrbitCallback); + 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); @@ -92,7 +98,7 @@ bool VortexEditorTutorial::init(HINSTANCE hInst) m_handlesSelect.setBorderSize(0); // the gloves select - m_glovesSelect.init(hInst, m_tutorialWindow, "gloves", BACK_COL, 64, 64, 214, 100, 123125, selectOrbitCallback); + 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); @@ -104,7 +110,7 @@ bool VortexEditorTutorial::init(HINSTANCE hInst) m_glovesSelect.setBorderSize(0); // the chromadeck select - m_chromadeckSelect.init(hInst, m_tutorialWindow, "chromadeck", BACK_COL, 64, 64, 304, 100, 123126, selectOrbitCallback); + 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); @@ -173,7 +179,7 @@ void VortexEditorTutorial::loseFocus() DWORD __stdcall VortexEditorTutorial::runThread(void *arg) { VortexEditorTutorial *editorTutorial = (VortexEditorTutorial *)arg; - while (editorTutorial->m_currentScriptIndex < editorTutorial->m_script.size()) { + while (editorTutorial->m_currentScriptIndex < (editorTutorial->m_script.size() - 1)) { WaitForSingleObject(editorTutorial->m_mutex, INFINITE); if (editorTutorial->m_nextPressed) { editorTutorial->m_nextPressed = false; @@ -188,7 +194,7 @@ DWORD __stdcall VortexEditorTutorial::runThread(void *arg) const std::string &message = editorTutorial->m_script[editorTutorial->m_currentScriptIndex]; std::string msg; for (size_t i = 0; i < message.length(); ++i) { - Sleep(40); // Simulate typing delay + Sleep(30); // Simulate typing delay msg += message[i]; // Place your method to update the text in UI here editorTutorial->UpdateTextDisplay(msg.c_str()); @@ -204,6 +210,7 @@ DWORD __stdcall VortexEditorTutorial::runThread(void *arg) Sleep(1000); // Adjust as needed editorTutorial->NextMessageAutomatically(); } + return 0; } @@ -238,3 +245,60 @@ void VortexEditorTutorial::NextMessageAutomatically() } 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 index a9ff250..0338667 100644 --- a/VortexEditor/VortexEditorTutorial.h +++ b/VortexEditor/VortexEditorTutorial.h @@ -55,10 +55,35 @@ class VortexEditorTutorial static void selectOrbitCallback(void *pthis, uint32_t x, uint32_t y, VSelectBox::SelectEvent sevent) { ((VortexEditorTutorial *)pthis)->selectOrbit(x, y, sevent); } - - void selectOrbit(uint32_t x, uint32_t y, VSelectBox::SelectEvent 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; @@ -69,7 +94,6 @@ class VortexEditorTutorial uint32_t m_currentScriptIndex; bool m_nextPressed; - // mutex that is posted once we're loaded HANDLE m_mutex; HANDLE m_runThread; From 02a339a9ff6d8459749c043fd841a3a0923a9b3a Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 26 Apr 2024 16:27:46 -0700 Subject: [PATCH 05/15] fixed for latest serialization changes --- VortexEditor/VortexEngine | 2 +- VortexEditor/VortexPort.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VortexEditor/VortexEngine b/VortexEditor/VortexEngine index 45f6320..8478001 160000 --- a/VortexEditor/VortexEngine +++ b/VortexEditor/VortexEngine @@ -1 +1 @@ -Subproject commit 45f63209076fbce2a75df2368dd30efa365e2a08 +Subproject commit 8478001a4adcc0f7dc94bea9966ef22288ae1138 diff --git a/VortexEditor/VortexPort.cpp b/VortexEditor/VortexPort.cpp index 4452378..2d8f3e4 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) { @@ -173,7 +173,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 From 8656b726fcb4de82cdb65a9c644b0f7fbfcdc026 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 26 Apr 2024 16:30:54 -0700 Subject: [PATCH 06/15] oops --- VortexEditor/GUI/VPatternListBox.cpp | 102 +++++++++++++++++++++++++++ VortexEditor/GUI/VPatternListBox.h | 37 ++++++++++ 2 files changed, 139 insertions(+) create mode 100644 VortexEditor/GUI/VPatternListBox.cpp create mode 100644 VortexEditor/GUI/VPatternListBox.h 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 +}; From 04aceacd10b427efac5404ff86ad297a07d3a39a Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 26 Apr 2024 16:32:14 -0700 Subject: [PATCH 07/15] added logo files --- chromadeck-logo-square-green-64.bmp | Bin 0 -> 12344 bytes gloves-logo-square-green-64.bmp | Bin 0 -> 12344 bytes handle-logo-square-green-64.bmp | Bin 0 -> 12344 bytes orbit-logo-square-green-64.bmp | Bin 0 -> 12344 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 chromadeck-logo-square-green-64.bmp create mode 100644 gloves-logo-square-green-64.bmp create mode 100644 handle-logo-square-green-64.bmp create mode 100644 orbit-logo-square-green-64.bmp diff --git a/chromadeck-logo-square-green-64.bmp b/chromadeck-logo-square-green-64.bmp new file mode 100644 index 0000000000000000000000000000000000000000..13cebacf75abda4f938a7a79740cc6fc9066fd84 GIT binary patch literal 12344 zcmdT~3rtg27zXEzy2Tk{7L!E{Z7Gj}Euw{Cl?J2?c__FR!mAchw8$(iOa>w^1u8>P zQNRZ}#0P>1)v1edi}AI%>C|j)*&}hfN8I8x+uVD&uioYEdP~o}a0`Rxv^n>j|NQ@V z&i(tJ|NqYkj|)+_J^m>1>w~ZQ->J*Q zKe}v>Y;8J0eo&dTB}tj26wAdz5e#TN7BC=+fu|KOUg5aaOk7-nRPuYLv!19P7_y1rbrjQC|LD{Xxe?8|G7Vu4vcYU7f#m zGG(#qSZeQlZ;45QU({0$q)__5xN|WmWvgZALLoEh__d?u`<8+;1wM1QQ1R=Zku+n+ zH#;(qX1d3@zp(s;&flF*0opP;VKgv5o$xg3Ed1ki}4}yQlx)4YQ=a%nUXmP9x3qLeRRii>FezzEueDJsa(E8MZ zrywY*AqqndJv{Vc){6uFQ-_(tV5=#ROv-yk7=tAk~?RjDpW6MDMlI|rcs|vbG(EtF}Z~#-7ZJbR|6#@Xd3xLNg z8Z#zwOv9HAbmIUjm_kTaNZ%^rq%|-p@Ze8&wGmR5A74%>JQPU?AB=?}$rI&Hz_OdA zDk=W30wrQN)-7^#q-LvzY;brAYP!?pt>WI@V0hP@Tf>Lvj&FCc92-8P9BE)52u=u- z-u#xCb6<#E7t0*ttiJNpO4uTg3=hgWIV0n2Z~vv;L+=4rg%=7ri9w(#(y-Nq@hlCO z!ea2@6Hy;Q>Gt;9+xgHtqk(JW9`6oT+BdY$XqfG=W-|(sXi|+-;BGZ!;2{Wlf{=bIzNSVaJ5;^@9fnxK=`hTHH!4Z>1;fYY$caVu-Xu@{@QvZou&p&CHMe{Rw%uKCng*fe-2c*1XZB} z0mre3#wy<`D`Wunld7tUV*lb7rn~Vr^nvc^tE)&pJ8d*XIxy zG;(cT5D{sK3``9q$U?A*1T69-){m?NGM9J3lbnz;VUBeUdFxl|lv8I;B_yj{C1}^GUWFp!4jNj)qY$H8bmZ(Z*64}LvzA6g-^?wM!Br4-obk; zyHYmAI3;{zxTEUUe^KB3bu&amCA?(zW18HKT%?F`=m1w4q1oV}63!WJFhGu8I2wmj zsm-ZW{1uuV3VoyASKixs!leuz2Sb;E!ii`rG$WM4?-}UXa<^sKv1MuPX=HzU@PP5; zjCdruEg6}4oRNtFMHGJg=5*%pMz>GLhaRqif3$y} z;Hk#c##BChV22_1+2m*UJ=n*G-Wd&!EynA{V<}dgSmBI@*}kxLAptzPMAJnz*X`*z z&QkYjoj~xE2)I~CW^$%VKwNRTLL!%t@!NYfKKt$qT2%@d_L_{248swFODr?47O-;u zgo&t(D&dE=#uN5jF$&MKMZz1$*-G$|U;<#ru9)%|EFgg=XII753gonrE4JPg6gvP$ zL}7#@LUIcZnBuGB=_x?fQxB!Wt>uKxB*5t^EDW=Svkngv9uED_!j=?W7R@^CA|t1J zF)Fq)mQtj!*TbL*SWo^3ot#h|2>_cqhKSx4jb5mYrdTsD@boO^=FV-q--b1T!JM>s z63-375gVTtn0H+H!$M(4YrWSRvb2BKPH4=mieHRh-OW0jDG0xm!Z{0E0ND81M(Yi$ z-%EZh7(yO##;4z{$K^Cm00If{3eua?>9aW@m>tK;7s)FxS0X9F6D0n9{D~3jmR~CO zk0-eYj*$A>f{+>UX7#md$HS(EpCzlYVudIYPgt5w07!Ok4B{(|JB z$1G-~%&@#^p|7{GAmI@^FSUP}-*K9vgtnWHn-w|*l}X@~>v96mS)P#vkp(9Ua6gI_ zKH!duBu^qWOR@DcX9u#z+l~1r@*~UdMsrZ%Brtd jBSmBV&{}o9s`Nssx!bI7)T?vVo?)J1f0tc5cXRs(g;3V= literal 0 HcmV?d00001 diff --git a/gloves-logo-square-green-64.bmp b/gloves-logo-square-green-64.bmp new file mode 100644 index 0000000000000000000000000000000000000000..207da98c1a780ebab43939e63116e82d8a81ddf8 GIT binary patch literal 12344 zcmeI2c~sQb6~}4+?SHnXO-^j1zzoPTAP57p2@Jd72oC!;fFmG?EXpDfc7XvIc0u+X z1%=US5>I2AShaeziDIlkH>d_uKKjz$d^WJ@*x$nLE z?z?Z?{Ov6DX8vsPYK;GNv;RNRdjpc5-jDJ5vY(LunF72R(?1L2U|Dd*#R{FDvQNwS zp?s=OtzaRvD7jFga~Ej1scDnZDkD|pd|!UYgAVyK`BI*;3uS7R)9wmCDqM$mek=Mt4mKa+Az)J#q~T}w`vEU^o$Uye10Dx`vuxshL< zU*<&SQXYpG2dYr5U>k0`6#Z!Ho$syL#i{N0l_<2{VC`S(uk+)c>8_1sTvAQTFXy^_7C=9b$n%ah*v zY3wpQPSuXId_f_+AzUpsEex#i04b2Q?*JP@#Xi4AS`a%an4*vTf`f9%2^j6}V zYWc&Pl&xgSH)VTfHa|4HDS1ObZ6%(ciI?$q@kXDH(jHZXfPw&OZ6!gFB~YzTOMq=# zx(3~?NPQc9p;HPEfo=b)%T-FdjQvLYfyV<>l@dQ&4`k~iE6+v`@@(u9j(;~!8$xKi z+h$~?CccI7Yp>L@Yr@E3L!ngFni2+nzK6{(pOzatE7&HaEQGCDGe5crX!mcr)r2Qt zpMP+_2nyNFy?1ykXrFoGob1f5137vu+N;rn=-Jd8G#@!BSKxmp$5ul*CKKOJ*p}MBQ7AOO)575?Z1EWG>ZxjWor1FkmIb{1|JaYhnyWRxNcj1p z_%q(ip#1QhO`kWhl`qJTzRYq>Nt1!c{oG8B>_#11gGZVN)epfg-i|#+t#@0|1dE+C zaj3M{43AHh><dkZaNq1cIX%hlT^oMW+&NEPd#%QJhf&|7KB}bpay7?%b_ihn z;xoncqmid0`0f=K%W28l-HYZ&Te}cD@I$$zLqb&%VX^#Zm2o27uAD#i-56Eny2X{) z$12Q<7Gll1)Ho*}O`;_bbmNa|jbij$8R!2dpREnD4*X~p)DwthNQbiW(@Ksh2N6-> z$+edLH#a4%-tJSRM#r_}gLA9Fxka-RxedtTVs&cJG+_ z7^;T~@Nbs+yz~#!WjAFxC$kX(Nv}#FuW$3qKABy6z1Cp6e&&aB^Mp1eLhAb|Ti;EF z9MupdsuV#$iA0{DRE@qZJXf$H^;Z>_DoQ^oMHlD@kMRy}$sbA}?EHA=+bO?P@}H!w zs7ADXWINSE1o$`KR$s|s#wlT;N#vWO_eYVBB1Xc=0esK(TIioIUnILB+xqTSG-30X zT`VI?lwQ#tTruEL4u$A~REVF5Pdu7PWH7kP+-L|*H6)ED)uTN>ai>W?aI*Q)HMR-L42;-u<*AbMVNUslxqSrI z&OW&l0Y8=@fqCa#AqJF!vH4L5hZ)o}=P>tN*)#I(2+B3^!)a7snhPW%N5Xwtys0~7 z^Ft48UiDcO=^Zb0ZZ1me9d0QVslZ-Er7-_I<%bJ{}E%w!bKxg_Za* zF1%glJ%43f8F|VtmSM3BJsBczDgVgRVT@zqku9_)!YwReoPy^{p2=1DQO%>#gVfQ1 zf8gr@wtgjkd=z&`oP10n*w}Jd;<{%Y)+s(E{E(v$L<_rwm=9DNQ~|903kCbUcz%p8 z41Vxm4DIYQEk^_rwLg;bod^7yx}X9v9~fARe2bX~1W*Oy&{ioD|M z;Ajt-*dP2zQz%6d;71|56=W^>>#o^yel-(V>H(*r^FWb|Uy;Y>U`r zm%@+06?kBq&;Emt2c0BN;ZkM?Ux0sFK0Du3{15m6A2}My<`?yg5+>v4T-<*0-&P1%fMsg~dYH z-@Dl>s5=nxr?^wh_Wxx53vvW8?M!T-ncp+fbGh~M#qu}bY_^HF>3YC;0J?rbwbEiG zGn$J0?y2r5LACJVFbt4GgoBBX2?X&$aZqm%{DyC~uPXm4msQAmvH3BFt>djpr_}zs z@u!cc|q>De)t{TyvSJiD$=qJ8*skZOS+kRNz5mf)kS}KZnmz;)i2F zzANwjJhWOOf7)o8_WY=6U}+F64Hij79Lw4KgCWmQSS}2!3p2E3vg_LO=N@HZ;}^^i zLd}1#`7tPJ_b;{nXR-4~v+?oiYy1CS*q^x-V&b3k;A{nqMe*Z|AnMx`)U#1Df8Oa_ zQJ)BwME-eE{7@b<7QG-p>cH_LKfGA}$dL#P0nU{R^2Z;FLwZMhe(w}-*E< zBnip+CHqJ=u8G5kLUGMK^kmRETJh4IYE%^9k!06pxRS;Ofy7H#RT$yNRF9vG$D+g1 z13#9b^pbSxSDr7&)kVw=CFV4c&xBfh@3XzN1?04 z6=ug#eDp!#C9k)_r{sg-(TWGaeJ6(hse z^{^9N*hkuH*G}77m?~~bZh0T%r5s3E?Y&ytW{auE6Yvs;5_f&H%QM51Oe$?!>*@U$ DPmcn% literal 0 HcmV?d00001 diff --git a/handle-logo-square-green-64.bmp b/handle-logo-square-green-64.bmp new file mode 100644 index 0000000000000000000000000000000000000000..057a44a0c8ac9ea47ee1d717986d2408f0f75dd7 GIT binary patch literal 12344 zcmeI2dr(x@9mmm_Orpt5#+l5JNiYbzcXwG}cZHSZtvqKDaCw#hZUos~Ua7ofVL^m7 z;_xs5k%ZSEj!}Yu%BD@DO{2BeChbJ087HwdZTd{wrtNgnrfJ#~`@=)8*K^M~dkuU4 z%g$vv&(HbZ-#z!7-#KTKvP^ov+n>$wt%koX%YUo<{2}D$w;J--uS0*g6W~j&R&!b| z#u3x_Mq}&c);$;ZIOZMpIlFDv=JmpgLA36C9YE~!_K>6yAoCwpoXU2}23hsz>&3Oa zHUtHrmVMUVa;XI%&P&e7oslYy3h`sDvD1H__T2LL@M^o%rVLXezEZ1no_G2X4yd^= z=E5_>fzO3-)*-8J;fNM(jYj&za>LGkdDiDmPoJ6_g#rBgnB zYGdlwZ*G;3f8gB%U01r~i- zhw(Gk5xWu#uB8r}3fJX_K_zzs-C$Ln~7}U5o*-DA&Nz>OwmB&kX&~{q(st zmNgg%Bz%qaTf~-o9Ea7)z;ny@psF**|Va9C3XCuYdMfHijZb_x^YxuOIX}KCCNRM;kv&MoLis-!Z&{c!QAmgyRXZU@Yaxua6L` zcf8%f)(`tyfzJkFG%UL1&=w*b64M*fk^aQ0L|U2D!Bh;0MIR}CgjN^n=fb(V`8sl$ zMNjEWDFzfq;pq%~Kz?^5>W4Yv!Tbk>Oe|cnP(jvq%Ts-}8teo6&$bEb7SPn6r<4s! zjLAp0Pi&{bAw8}v4%uH{pa)-qRO>@8y}_^nW)o`3MNdLsf|&1b^B?}rFtye#PeES+(*JbN(~M$} z1v;T4fi)g3df30hU+dKF{_bwCyHZm1!@0?#r|DvownYo@wS{Zp8-{M8S0L1xwJ!@9 zDBGDWO!rmz9`t{uqaW}*k^Z!rG+$}H!&&sG5|+=Wp#Qw`*(-OlzLHvT_2`o2^PSYH zRB`SKQ=sdD^Nj2RLqyN@o)rSc)lEev#FwHUmWnMuY{{F-bG+(k{y{T%M`EBb<%OFs zC_|Rd@1T_fR}Tnt#bFp{Tt9MEy;hYwnY-uvd!($ddHqoZQ7`}PWib<_z%1YPRvWxl z!Xe_Z^2cb?BB}+eW}$xfPslzJDm?b_7&gSgq|k7ofhK7webK`ua>)Lh(l#+hDzG+j z6}Bd44bkyNjoPQ}2#&t1PE^svfT>}fD>M!t-hYjHFb4zjM%_lQ`r%wy->&C@SfKJ- zl{8i5N6Ur!D<-JZDD)W&%SRP;3L0OiKQu11`x<$P1is~lnhiV<3(!1sXjHoXxSlu+ z%SRt7e2AuhX>oUZaSB%A^jyoi7Gg=ZeujOd>t{S)hJHBQKH$shX#F zgJ6M-7pVu+nVp$D9|C5VnP?wK%pA?cuzVEW3tFw_H=B7rLq9kP;G~H+$DoP(w%^Ct z+2AKf)QZV!qA8j9;{?qGW%!3e{cwt1b(}grz?)*7wSrpSED(4g_kp_aQM~Tk(`#~d zGH)LUF!aNHIWIe*s|fkvnZsNIgCy;)cTVl(`J9F;8)mtn0D<`^p*KO@q>ku}NFGRL zZ|gz%sKO|o4*@QPW4O>z9-czlP#O#fswP!@Pdw~f(v+k0g8n7v6MeviF6}R6m%rCs zO@ikC_@)1W`as|QM90!)5%P08bMI9lyF9L6=VSfpP0Nc@bQfv0K6XLn)*o+;7utVo zxi3#?Vee7Bymnk}Bv2Q~aIx5rl9(Hnch~#nTm9foDRfIapZo`0=tJ*OccF<2*@>9` z#GQ%k@qtala$#do=zOBP@a?apj5$W$I1n)9n0)wr-B;aW{rj%$!)|jWQTRclP=8c* z)YM<5Rss~(b)0et;V4`=O?6gBDF$Ig zVVsP2+%l|3Uaz~_$uZW^WhJuhwRYL z^Skeefm-Q}>Cn}A!NdTx!e3k{XW3_&{d`tznW0|}#oOcgk|;m~Vu@Ilm}g=JZw`w2 zuyjgureTFKl$0nO(4^F-xGuQbF1GPk{kQA&S$cp=A+XB;L}%93p04HLC}3_itHQnW H{rvt1gcFJ- literal 0 HcmV?d00001 diff --git a/orbit-logo-square-green-64.bmp b/orbit-logo-square-green-64.bmp new file mode 100644 index 0000000000000000000000000000000000000000..e42bd8a2037178ac4631b68ef718c668231ff7e9 GIT binary patch literal 12344 zcmdT~2}~T<8ODwkS+Oi7j-^;iA|>Y7T^3Uo1Iq#lWMKhwQ?o2AH){hiU~YV{6k{6_ zUmWH#EEo|RbDCpiSCMnd&fz3Vt0ZmOMzYdGacm`Ol%`G7wC=Xw_>o~eJG*l*RIN3v z-@Nx9-~W#P{qKLHPYw<6xce^zze@Z?E&Z+W*n*OW$6B;++Ccv9R^Ue|-#^c7o~lTd z&ZINc7!sQj^M>W4tm{G6*S* zetJLifO+csDNa-pDldF@A>&krI!Y}CjTjz9u%ggbIQNe^2_Sh{W`3A4b(j>}S7k`!At)U5`M?Ms^`Rl@;GSXFdw^z;wY0JiUqeT`QeR|BCd znI-m;_K(`pI{w|bu23fo?>$rzmIycm0)AcEx;4pb>R+#SrB2>@%e)2Z?*IAy?H^Jm zO#F3Xd;0c!!129k(ljs}yp7iy*QT!ZNbpQkA^bAlXBQ|VKVN#L=pMLwy55(cGkF~ZwDbLoh-#Rz3VH;Qd^M<>=3VgaFnMz#{8w zR;FZD875%1Wg3Pa9^RociPxwkl#mvvqjPJBF@)f+SrEM$VHDs|nE(J@pf9p4 zSXd?`4kQZidD;*hHh~{Ia_1j9=}O@RXbgWYoR|RcqB;=aF>ON9nIwU8o`uc&mK9#e zE8L6M^RO6~Umf;{=OZZaZ;Bp$VnWiOMDV}>FXSEM9l1yJazAAa|+yfPu}$;v0moI&C!cZ!NL@%SI~m$py2fwyO2 zkNoTR&cXwx2MA^yPoC*`hLquvFqhnbk*Rw0Kd6tGd&hdCS2e# z0pD7%@`tb`d{;O?I(HOmP(O5Q2nj=$BE0UsvX_%ZU}fgHOlO%7stO6L5&|ecIQ# z^XZ!WGs~!$;E6yi0b&BKd*lL7FXY%(R9wlG$Hv=G7XipfRCfv-d{RV zIxkqr#BfjjO|~y*n4K{B{UoLhfzAA-Jks5PKJe-RI%mrXo>Z#zs&n6*1B-K_5@L~3 zU@DcjoI0G!M2<49fXUVW(9I#0PUQwRvni}F481{2Sd&8CtdR#{gS>#9rKQ+XXm!Yu zlAJK6ePG%>4xfpZv#hVuU;ObR%&@pFaEdSz^Mj#a*ib)s@VhqdN(B_(OfIo{36S8KXcZk}E~4T8~e6v^i3Go@rxf zZs^FZkyXXXDZKB~zJO%*Jt-5I@G?F+ZGD?#Yv$A|L#4xBcd5?RJ-cw&OiDOjT=|WE zD}N4+WiP%E*wM6u_d5+HHWB4WWy3EU=I_k2l*;mo^LY7mxp(l=t)d82Vn`7?1sQ|t zF4qz7DhqOaVO23x;Tz{Jun~h%5Uo01T|8Xe{Ykg0K$q7v1U4srbHdzZ_6g(psz(qY zNkmu|8l$G@Owo~dj=b>A3%r;?fb4YZo2|J$xqgX$t2NIh*@8TPZ-OsA)6MS8wv1S; h*R02Wdkjy*l?J?G`A6-EQpPHA-7iTzH Date: Fri, 26 Apr 2024 16:40:00 -0700 Subject: [PATCH 08/15] moved bmp files --- VortexEditor/VortexEditor.rc | 16 ++++++++-------- .../chromadeck-logo-square-64.bmp | Bin .../chromadeck-logo-square-green-64.bmp | Bin .../gloves-logo-square-64.bmp | Bin .../gloves-logo-square-green-64.bmp | Bin .../handle-logo-square-64.bmp | Bin .../handle-logo-square-green-64.bmp | Bin .../orbit-logo-square-64.bmp | Bin .../orbit-logo-square-green-64.bmp | Bin 9 files changed, 8 insertions(+), 8 deletions(-) rename chromadeck-logo-square-64.bmp => VortexEditor/chromadeck-logo-square-64.bmp (100%) rename chromadeck-logo-square-green-64.bmp => VortexEditor/chromadeck-logo-square-green-64.bmp (100%) rename gloves-logo-square-64.bmp => VortexEditor/gloves-logo-square-64.bmp (100%) rename gloves-logo-square-green-64.bmp => VortexEditor/gloves-logo-square-green-64.bmp (100%) rename handle-logo-square-64.bmp => VortexEditor/handle-logo-square-64.bmp (100%) rename handle-logo-square-green-64.bmp => VortexEditor/handle-logo-square-green-64.bmp (100%) rename orbit-logo-square-64.bmp => VortexEditor/orbit-logo-square-64.bmp (100%) rename orbit-logo-square-green-64.bmp => VortexEditor/orbit-logo-square-green-64.bmp (100%) diff --git a/VortexEditor/VortexEditor.rc b/VortexEditor/VortexEditor.rc index 72a153a..bb9691e 100644 --- a/VortexEditor/VortexEditor.rc +++ b/VortexEditor/VortexEditor.rc @@ -168,21 +168,21 @@ END // Bitmap // -IDB_BITMAP1 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\chromadeck-logo-square-64.bmp" +IDB_BITMAP1 BITMAP "chromadeck-logo-square-64.bmp" -IDB_BITMAP2 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\gloves-logo-square-64.bmp" +IDB_BITMAP2 BITMAP "gloves-logo-square-64.bmp" -IDB_BITMAP3 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\handle-logo-square-64.bmp" +IDB_BITMAP3 BITMAP "handle-logo-square-64.bmp" -IDB_BITMAP4 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\orbit-logo-square-64.bmp" +IDB_BITMAP4 BITMAP "orbit-logo-square-64.bmp" -IDB_BITMAP5 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\chromadeck-logo-square-green-64.bmp" +IDB_BITMAP5 BITMAP "chromadeck-logo-square-green-64.bmp" -IDB_BITMAP6 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\gloves-logo-square-green-64.bmp" +IDB_BITMAP6 BITMAP "gloves-logo-square-green-64.bmp" -IDB_BITMAP7 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\handle-logo-square-green-64.bmp" +IDB_BITMAP7 BITMAP "handle-logo-square-green-64.bmp" -IDB_BITMAP8 BITMAP "C:\\Users\\danie\\source\\repos\\VortexEditor\\orbit-logo-square-green-64.bmp" +IDB_BITMAP8 BITMAP "orbit-logo-square-green-64.bmp" #endif // English (United Kingdom) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/chromadeck-logo-square-64.bmp b/VortexEditor/chromadeck-logo-square-64.bmp similarity index 100% rename from chromadeck-logo-square-64.bmp rename to VortexEditor/chromadeck-logo-square-64.bmp diff --git a/chromadeck-logo-square-green-64.bmp b/VortexEditor/chromadeck-logo-square-green-64.bmp similarity index 100% rename from chromadeck-logo-square-green-64.bmp rename to VortexEditor/chromadeck-logo-square-green-64.bmp diff --git a/gloves-logo-square-64.bmp b/VortexEditor/gloves-logo-square-64.bmp similarity index 100% rename from gloves-logo-square-64.bmp rename to VortexEditor/gloves-logo-square-64.bmp diff --git a/gloves-logo-square-green-64.bmp b/VortexEditor/gloves-logo-square-green-64.bmp similarity index 100% rename from gloves-logo-square-green-64.bmp rename to VortexEditor/gloves-logo-square-green-64.bmp diff --git a/handle-logo-square-64.bmp b/VortexEditor/handle-logo-square-64.bmp similarity index 100% rename from handle-logo-square-64.bmp rename to VortexEditor/handle-logo-square-64.bmp diff --git a/handle-logo-square-green-64.bmp b/VortexEditor/handle-logo-square-green-64.bmp similarity index 100% rename from handle-logo-square-green-64.bmp rename to VortexEditor/handle-logo-square-green-64.bmp diff --git a/orbit-logo-square-64.bmp b/VortexEditor/orbit-logo-square-64.bmp similarity index 100% rename from orbit-logo-square-64.bmp rename to VortexEditor/orbit-logo-square-64.bmp diff --git a/orbit-logo-square-green-64.bmp b/VortexEditor/orbit-logo-square-green-64.bmp similarity index 100% rename from orbit-logo-square-green-64.bmp rename to VortexEditor/orbit-logo-square-green-64.bmp From f477a913dc6cf26a5929ee37ce8110fe8f5d71e3 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 6 May 2024 01:14:13 -0700 Subject: [PATCH 09/15] testing predraw on one part --- VortexEditor/GUI/VPatternStrip.cpp | 54 ++++++++++++++++------ VortexEditor/GUI/VPatternStrip.h | 2 +- VortexEditor/VortexCommunityBrowser.cpp | 59 ++++++++++++++++--------- VortexEditor/VortexCommunityBrowser.h | 5 ++- VortexEditor/VortexEditor.cpp | 12 ++++- VortexEditor/VortexEditor.h | 4 ++ VortexEditor/VortexEditor.vcxproj | 2 +- VortexEditor/VortexEngine | 2 +- 8 files changed, 100 insertions(+), 40 deletions(-) diff --git a/VortexEditor/GUI/VPatternStrip.cpp b/VortexEditor/GUI/VPatternStrip.cpp index 4029813..c0aed2c 100644 --- a/VortexEditor/GUI/VPatternStrip.cpp +++ b/VortexEditor/GUI/VPatternStrip.cpp @@ -23,7 +23,7 @@ WNDCLASS VPatternStrip::m_wc = { 0 }; VPatternStrip::VPatternStrip() : VWindow(), m_vortex(), - m_runThreadId(nullptr), + m_runThread(nullptr), m_stripLabel(), m_callback(nullptr), m_active(true), @@ -96,7 +96,8 @@ void VPatternStrip::init(HINSTANCE hInstance, VWindow &parent, const string &tit // load the communty modes into the local vortex instance for the browser window m_vortex.init(); m_vortex.setLedCount(1); - m_vortex.setTickrate(30); + m_vortex.setTickrate(40); + //m_vortex.setInstantTimestep(true); HDC hdc = GetDC(m_hwnd); createBackBuffer(hdc, width, height); @@ -113,8 +114,21 @@ void VPatternStrip::loadJson(const json &js) } m_vortex.engine().modes().clearModes(); m_vortex.loadModeFromJson(js["modeData"]); - setActive(true); } + + 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) @@ -175,9 +189,7 @@ void VPatternStrip::paint() drawToBackBuffer(); } -void VPatternStrip::drawToBackBuffer() -{ - // Ensure the backbuffer is ready for drawing +void VPatternStrip::drawToBackBuffer() { if (!m_backbufferDC) { return; } @@ -190,20 +202,29 @@ void VPatternStrip::drawToBackBuffer() // Fill the backbuffer background FillRect(m_backbufferDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); - // Draw the color sequence + // 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) { - RGBColor col = m_colorSequence[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; - RECT lineRect = { xPos, rect.top, xPos + m_lineWidth, rect.bottom }; + lineRect.left = xPos; + lineRect.right = xPos + m_lineWidth; + FillRect(m_backbufferDC, &lineRect, brush); } } @@ -276,15 +297,22 @@ void VPatternStrip::setActive(bool active) { m_active = active; m_stripLabel.setVisible(active); + + // if active == false if (!m_active) { setSelected(false); - WaitForSingleObject(m_runThreadId, INFINITE); - m_runThreadId = nullptr; + if (m_runThread) { + WaitForSingleObject(m_runThread, INFINITE); + m_runThread = nullptr; + } clear(); + // end active == false return; } - if (!m_runThreadId) { - m_runThreadId = CreateThread(NULL, 0, runThread, this, 0, NULL); + + // otherwise active = true + if (!m_runThread) { + m_runThread = CreateThread(NULL, 0, runThread, this, 0, NULL); } } diff --git a/VortexEditor/GUI/VPatternStrip.h b/VortexEditor/GUI/VPatternStrip.h index 63accbe..c777fce 100644 --- a/VortexEditor/GUI/VPatternStrip.h +++ b/VortexEditor/GUI/VPatternStrip.h @@ -64,7 +64,7 @@ class VPatternStrip : public VWindow { static DWORD __stdcall runThread(void *arg); Vortex m_vortex; - HANDLE m_runThreadId; + HANDLE m_runThread; VLabel m_stripLabel; VPatternStripCallback m_callback; bool m_active; diff --git a/VortexEditor/VortexCommunityBrowser.cpp b/VortexEditor/VortexCommunityBrowser.cpp index d61c51d..43c6093 100644 --- a/VortexEditor/VortexCommunityBrowser.cpp +++ b/VortexEditor/VortexCommunityBrowser.cpp @@ -39,7 +39,7 @@ VortexCommunityBrowser::VortexCommunityBrowser() : m_prevPageButton(), m_nextPageButton(), m_pageLabel(), - m_curPage(1), + m_curPage(0), m_lastPage(false) { } @@ -93,8 +93,9 @@ bool VortexCommunityBrowser::init(HINSTANCE hInst) DWORD __stdcall VortexCommunityBrowser::backgroundLoader(void *pthis) { VortexCommunityBrowser *browser = (VortexCommunityBrowser *)pthis; - Sleep(300); - browser->loadPage(); + // load the first two pages + browser->loadPage(0, false); + browser->loadPage(1, false); CloseHandle(browser->m_hThread); browser->m_hThread = nullptr; return 0; @@ -107,6 +108,9 @@ void VortexCommunityBrowser::show() } 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; } @@ -125,6 +129,9 @@ void VortexCommunityBrowser::hide() 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; } @@ -150,36 +157,46 @@ json VortexCommunityBrowser::fetchModesJson(uint32_t page, uint32_t pageSize) return result; } -bool VortexCommunityBrowser::loadPage() +bool VortexCommunityBrowser::loadCurPage(bool active) { - // fetch json of modes from community api - try { - m_communityModes = fetchModesJson(m_curPage, MODES_PER_PAGE); - } catch (...) { - return false; - } - // Verify if 'data' is an array - if (!m_communityModes.contains("data")) { - cerr << "'data' is not an array or does not exist" << endl; - return false; + 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["data"][i]; + auto mode = m_communityModes[m_curPage]["data"][i]; m_patternStrips[i]->loadJson(mode); + m_patternStrips[i]->setActive(active); } - uint32_t numPages = m_communityModes["pages"]; - m_lastPage = (m_curPage == numPages); - m_pageLabel.setText(to_string(m_curPage) + " / " + to_string(numPages)); + 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 <= 1) { + if (!m_curPage) { return false; } m_curPage--; - return loadPage(); + return loadCurPage(); } bool VortexCommunityBrowser::nextPage() @@ -188,5 +205,5 @@ bool VortexCommunityBrowser::nextPage() return false; } m_curPage++; - return loadPage(); + return loadCurPage(); } diff --git a/VortexEditor/VortexCommunityBrowser.h b/VortexEditor/VortexCommunityBrowser.h index 77d0653..c116eaf 100644 --- a/VortexEditor/VortexCommunityBrowser.h +++ b/VortexEditor/VortexCommunityBrowser.h @@ -33,7 +33,8 @@ class VortexCommunityBrowser void hide(); void loseFocus(); json fetchModesJson(uint32_t page = 1, uint32_t pageSize = 15); - bool loadPage(); + bool loadCurPage(bool active = true); + bool loadPage(uint32_t page, bool active = true); bool prevPage(); bool nextPage(); @@ -67,7 +68,7 @@ class VortexCommunityBrowser HICON m_hIcon; // modes fetched from community api - nlohmann::json m_communityModes; + std::vector m_communityModes; // mutex to synchronize access to vortex engine HANDLE m_mutex; diff --git a/VortexEditor/VortexEditor.cpp b/VortexEditor/VortexEditor.cpp index 1bafd94..ffa5d1e 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(), @@ -323,7 +324,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(); @@ -331,6 +332,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 diff --git a/VortexEditor/VortexEditor.h b/VortexEditor/VortexEditor.h index 365f48f..c4eb5dd 100644 --- a/VortexEditor/VortexEditor.h +++ b/VortexEditor/VortexEditor.h @@ -68,6 +68,8 @@ class VortexEditor 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, ...); @@ -218,6 +220,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 diff --git a/VortexEditor/VortexEditor.vcxproj b/VortexEditor/VortexEditor.vcxproj index 5e2db5c..8d31d61 100644 --- a/VortexEditor/VortexEditor.vcxproj +++ b/VortexEditor/VortexEditor.vcxproj @@ -143,7 +143,7 @@ true $(ProjectDir);$(ProjectDir)\EngineDependencies;$(ProjectDir)\VortexEngine\VortexEngine\src\;$(ProjectDir)\VortexEngine\VortexEngine\VortexLib\ MultiThreaded - MaxSpeed + Disabled Windows diff --git a/VortexEditor/VortexEngine b/VortexEditor/VortexEngine index 8478001..c7c8190 160000 --- a/VortexEditor/VortexEngine +++ b/VortexEditor/VortexEngine @@ -1 +1 @@ -Subproject commit 8478001a4adcc0f7dc94bea9966ef22288ae1138 +Subproject commit c7c8190e4be26c26713b503af6172a2e78c1853b From f4bdcbe4b46f601c28d27ebde11a881e116e9afc Mon Sep 17 00:00:00 2001 From: Dan Date: Sun, 16 Jun 2024 04:59:06 -0700 Subject: [PATCH 10/15] lots of new stuff for chromalink --- VortexEditor/VortexChromaLink.cpp | 159 ++++++++++++++++++++++ VortexEditor/VortexChromaLink.h | 61 +++++++++ VortexEditor/VortexEditor.cpp | 13 +- VortexEditor/VortexEditor.h | 3 + VortexEditor/VortexEditor.rc | 1 + VortexEditor/VortexEditor.vcxproj | 10 ++ VortexEditor/VortexEditor.vcxproj.filters | 30 ++++ VortexEditor/VortexPort.cpp | 5 + VortexEditor/VortexPort.h | 2 + VortexEditor/resource.h | 3 +- 10 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 VortexEditor/VortexChromaLink.cpp create mode 100644 VortexEditor/VortexChromaLink.h diff --git a/VortexEditor/VortexChromaLink.cpp b/VortexEditor/VortexChromaLink.cpp new file mode 100644 index 0000000..4abea0b --- /dev/null +++ b/VortexEditor/VortexChromaLink.cpp @@ -0,0 +1,159 @@ +#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 + +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); + + // 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(); +} + diff --git a/VortexEditor/VortexChromaLink.h b/VortexEditor/VortexChromaLink.h new file mode 100644 index 0000000..8ff7c86 --- /dev/null +++ b/VortexEditor/VortexChromaLink.h @@ -0,0 +1,61 @@ +#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(); + + 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(); + } + + 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; + +}; diff --git a/VortexEditor/VortexEditor.cpp b/VortexEditor/VortexEditor.cpp index ffa5d1e..32f12a6 100644 --- a/VortexEditor/VortexEditor.cpp +++ b/VortexEditor/VortexEditor.cpp @@ -228,6 +228,7 @@ bool VortexEditor::init(HINSTANCE hInst) 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); // add user callback for refreshes m_window.installUserCallback(WM_REFRESH_UI, refreshWindowCallback); @@ -250,6 +251,10 @@ bool VortexEditor::init(HINSTANCE hInst) 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); @@ -463,6 +468,9 @@ void VortexEditor::handleMenus(uintptr_t hMenu) case ID_TOOLS_COMMUNITY_BROWSER: m_communityBrowser.show(); return; + case ID_TOOLS_CHROMALINK: + m_chromalink.show(); + return; default: break; } @@ -978,12 +986,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 diff --git a/VortexEditor/VortexEditor.h b/VortexEditor/VortexEditor.h index c4eb5dd..acaeb70 100644 --- a/VortexEditor/VortexEditor.h +++ b/VortexEditor/VortexEditor.h @@ -28,6 +28,7 @@ #include "VortexColorPicker.h" #include "VortexModeRandomizer.h" #include "VortexCommunityBrowser.h" +#include "VortexChromaLink.h" #include "VortexEditorTutorial.h" #include "ArduinoSerial.h" @@ -48,6 +49,7 @@ class Colorset; class VortexEditor { + friend class VortexChromaLink; friend class VortexColorPicker; friend class VortexModeRandomizer; friend class VortexCommunityBrowser; @@ -261,6 +263,7 @@ class VortexEditor 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 bb9691e..5705e48 100644 --- a/VortexEditor/VortexEditor.rc +++ b/VortexEditor/VortexEditor.rc @@ -98,6 +98,7 @@ BEGIN MENUITEM "Color Picker", ID_TOOLS_COLOR_PICKER MENUITEM "Mode Randomizer", ID_TOOLS_MODE_RANDOMIZER MENUITEM "Community Browser", ID_TOOLS_COMMUNITY_BROWSER + MENUITEM "Chromalink", ID_TOOLS_CHROMALINK END POPUP "Options" BEGIN diff --git a/VortexEditor/VortexEditor.vcxproj b/VortexEditor/VortexEditor.vcxproj index 8d31d61..3c70671 100644 --- a/VortexEditor/VortexEditor.vcxproj +++ b/VortexEditor/VortexEditor.vcxproj @@ -168,6 +168,7 @@ + @@ -195,6 +196,7 @@ + @@ -217,7 +219,15 @@ + + + + + + + + diff --git a/VortexEditor/VortexEditor.vcxproj.filters b/VortexEditor/VortexEditor.vcxproj.filters index fb7a33c..82367c8 100644 --- a/VortexEditor/VortexEditor.vcxproj.filters +++ b/VortexEditor/VortexEditor.vcxproj.filters @@ -90,6 +90,9 @@ Source Files + + Source Files + @@ -164,6 +167,9 @@ Header Files + + Header Files + @@ -198,5 +204,29 @@ 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/VortexPort.cpp b/VortexEditor/VortexPort.cpp index 2d8f3e4..60a4a4b 100644 --- a/VortexEditor/VortexPort.cpp +++ b/VortexEditor/VortexPort.cpp @@ -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()); 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/resource.h b/VortexEditor/resource.h index 59fa08e..f21cbad 100644 --- a/VortexEditor/resource.h +++ b/VortexEditor/resource.h @@ -59,13 +59,14 @@ #define ID_TOOLS_COMMUNITY_BROWSER 40063 #define ID_HELP_TUTORIAL 40064 #define ID_HELP_WIKI 40065 +#define ID_TOOLS_CHROMALINK 40066 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 117 -#define _APS_NEXT_COMMAND_VALUE 40066 +#define _APS_NEXT_COMMAND_VALUE 40067 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif From 768a5be120d13af5b1c132fde8a3baddf753231c Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 17 Jun 2024 01:11:30 -0700 Subject: [PATCH 11/15] work on chromalink --- VortexEditor/VortexChromaLink.cpp | 70 +++++++++++++++++++++++++++++++ VortexEditor/VortexChromaLink.h | 5 +++ 2 files changed, 75 insertions(+) diff --git a/VortexEditor/VortexChromaLink.cpp b/VortexEditor/VortexChromaLink.cpp index 4abea0b..538cccb 100644 --- a/VortexEditor/VortexChromaLink.cpp +++ b/VortexEditor/VortexChromaLink.cpp @@ -12,6 +12,7 @@ #include "VortexPort.h" #define CHROMALINK_PULL_ID 58001 +#define CHROMALINK_PUSH_ID 58002 using namespace std; @@ -45,6 +46,8 @@ bool VortexChromaLink::init(HINSTANCE hInst) 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)); @@ -157,3 +160,70 @@ void VortexChromaLink::pullDuoMode() 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 index 8ff7c86..9ef87ab 100644 --- a/VortexEditor/VortexChromaLink.h +++ b/VortexEditor/VortexChromaLink.h @@ -30,6 +30,7 @@ class VortexChromaLink void hide(); void loseFocus(); void pullDuoMode(); + void pushDuoMode(); bool isOpen() const { return m_isOpen; } @@ -47,6 +48,9 @@ class VortexChromaLink static void pullCallback(void *pthis, VWindow *window) { ((VortexChromaLink *)pthis)->pullDuoMode(); } + static void pushCallback(void *pthis, VWindow *window) { + ((VortexChromaLink *)pthis)->pushDuoMode(); + } bool m_isOpen; @@ -57,5 +61,6 @@ class VortexChromaLink // pull from the connected duo via chromadeck VButton m_pullButton; + VButton m_pushButton; }; From 92c1fa56b557836f6e567948c130b9c646fa9567 Mon Sep 17 00:00:00 2001 From: Dan Date: Sun, 7 Jul 2024 18:00:04 -0700 Subject: [PATCH 12/15] adjusted pats url --- VortexEditor/VortexCommunityBrowser.cpp | 2 +- VortexEditor/VortexEngine | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VortexEditor/VortexCommunityBrowser.cpp b/VortexEditor/VortexCommunityBrowser.cpp index 43c6093..4b53250 100644 --- a/VortexEditor/VortexCommunityBrowser.cpp +++ b/VortexEditor/VortexCommunityBrowser.cpp @@ -148,7 +148,7 @@ json VortexCommunityBrowser::fetchModesJson(uint32_t page, uint32_t pageSize) { "page", to_string(page) }, { "pageSize", to_string(pageSize) }, }; - string jsonResponse = httpClient.SendRequest("vortex.community", "/modes/json", "GET", {}, "", queryParams); + string jsonResponse = httpClient.SendRequest("vortex.community", "/pats/json", "GET", {}, "", queryParams); // Parse and return the JSON object result = json::parse(jsonResponse); } catch (const exception &e) { diff --git a/VortexEditor/VortexEngine b/VortexEditor/VortexEngine index c7c8190..cf4b887 160000 --- a/VortexEditor/VortexEngine +++ b/VortexEditor/VortexEngine @@ -1 +1 @@ -Subproject commit c7c8190e4be26c26713b503af6172a2e78c1853b +Subproject commit cf4b887f0e8de5a2e08044927d27dbaf31f322b4 From 3d2d70d3355a781b866db2346e58b45d0240239c Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 8 Jul 2024 23:17:18 -0700 Subject: [PATCH 13/15] Added set device option --- VortexEditor/VortexEditor.cpp | 24 ++++++++++++++++++++++++ VortexEditor/VortexEditor.rc | 9 +++++++++ VortexEditor/VortexEngine | 2 +- VortexEditor/resource.h | 9 ++++++++- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/VortexEditor/VortexEditor.cpp b/VortexEditor/VortexEditor.cpp index 32f12a6..0f8b347 100644 --- a/VortexEditor/VortexEditor.cpp +++ b/VortexEditor/VortexEditor.cpp @@ -229,6 +229,12 @@ bool VortexEditor::init(HINSTANCE hInst) 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); @@ -471,6 +477,24 @@ void VortexEditor::handleMenus(uintptr_t hMenu) case ID_TOOLS_CHROMALINK: m_chromalink.show(); return; + case ID_CHOOSE_DEVICE_ORBIT: + m_engine.leds().setLedCount(28); + break; + case ID_CHOOSE_DEVICE_HANDLE: + m_engine.leds().setLedCount(3); + break; + case ID_CHOOSE_DEVICE_GLOVES: + m_engine.leds().setLedCount(10); + break; + case ID_CHOOSE_DEVICE_CHROMADECK: + m_engine.leds().setLedCount(20); + break; + case ID_CHOOSE_DEVICE_SPARK: + m_engine.leds().setLedCount(6); + break; + case ID_CHOOSE_DEVICE_DUO: + m_engine.leds().setLedCount(2); + break; default: break; } diff --git a/VortexEditor/VortexEditor.rc b/VortexEditor/VortexEditor.rc index 5705e48..8f2734f 100644 --- a/VortexEditor/VortexEditor.rc +++ b/VortexEditor/VortexEditor.rc @@ -105,6 +105,15 @@ 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 diff --git a/VortexEditor/VortexEngine b/VortexEditor/VortexEngine index cf4b887..2c79e66 160000 --- a/VortexEditor/VortexEngine +++ b/VortexEditor/VortexEngine @@ -1 +1 @@ -Subproject commit cf4b887f0e8de5a2e08044927d27dbaf31f322b4 +Subproject commit 2c79e66e389ce82d460f15a996b57c592b29b303 diff --git a/VortexEditor/resource.h b/VortexEditor/resource.h index f21cbad..77ffda9 100644 --- a/VortexEditor/resource.h +++ b/VortexEditor/resource.h @@ -60,13 +60,20 @@ #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 117 -#define _APS_NEXT_COMMAND_VALUE 40067 +#define _APS_NEXT_COMMAND_VALUE 40074 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif From 2c29c3eaddd01a6114616a81b132c73bbafe6802 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 8 Jul 2024 23:34:00 -0700 Subject: [PATCH 14/15] fixed led count changing --- VortexEditor/VortexEditor.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/VortexEditor/VortexEditor.cpp b/VortexEditor/VortexEditor.cpp index 0f8b347..0d5f1f3 100644 --- a/VortexEditor/VortexEditor.cpp +++ b/VortexEditor/VortexEditor.cpp @@ -478,22 +478,22 @@ void VortexEditor::handleMenus(uintptr_t hMenu) m_chromalink.show(); return; case ID_CHOOSE_DEVICE_ORBIT: - m_engine.leds().setLedCount(28); + m_vortex.setLedCount(28); break; case ID_CHOOSE_DEVICE_HANDLE: - m_engine.leds().setLedCount(3); + m_vortex.setLedCount(3); break; case ID_CHOOSE_DEVICE_GLOVES: - m_engine.leds().setLedCount(10); + m_vortex.setLedCount(10); break; case ID_CHOOSE_DEVICE_CHROMADECK: - m_engine.leds().setLedCount(20); + m_vortex.setLedCount(20); break; case ID_CHOOSE_DEVICE_SPARK: - m_engine.leds().setLedCount(6); + m_vortex.setLedCount(6); break; case ID_CHOOSE_DEVICE_DUO: - m_engine.leds().setLedCount(2); + m_vortex.setLedCount(2); break; default: break; From a4e3a7808f4f68c44b2206f1d90f6b643a199154 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 19 Aug 2024 18:38:37 -0700 Subject: [PATCH 15/15] Disabled new windows temporarily --- VortexEditor/VortexEditor.rc | 6 +++--- VortexEditor/VortexEngine | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/VortexEditor/VortexEditor.rc b/VortexEditor/VortexEditor.rc index 8f2734f..a0158bc 100644 --- a/VortexEditor/VortexEditor.rc +++ b/VortexEditor/VortexEditor.rc @@ -96,9 +96,9 @@ BEGIN POPUP "Tools" BEGIN MENUITEM "Color Picker", ID_TOOLS_COLOR_PICKER - MENUITEM "Mode Randomizer", ID_TOOLS_MODE_RANDOMIZER - MENUITEM "Community Browser", ID_TOOLS_COMMUNITY_BROWSER - MENUITEM "Chromalink", ID_TOOLS_CHROMALINK + 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 diff --git a/VortexEditor/VortexEngine b/VortexEditor/VortexEngine index 2c79e66..9f0dc09 160000 --- a/VortexEditor/VortexEngine +++ b/VortexEditor/VortexEngine @@ -1 +1 @@ -Subproject commit 2c79e66e389ce82d460f15a996b57c592b29b303 +Subproject commit 9f0dc090970d070b4e3b21400d45b7d4d1877035