Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <windows.h>
- #include <commctrl.h>
- #include <vector>
- #include <string>
- #include <sstream>
- #include <set>
- #include <map>
- #pragma comment(lib, "Comctl32.lib")
- // Actual code block for the logc
- struct RectModel {
- int Index;
- double X, Y, Width, Height;
- };
- struct Edges {
- double Left, Right, Top, Bottom;
- };
- Edges GetEdges(const RectModel& rect) {
- return Edges{
- rect.X,
- rect.X + rect.Width,
- rect.Y,
- rect.Y + rect.Height
- };
- }
- bool IsValidPosition(int index, const std::vector<RectModel>& rects) {
- if (index < 0 || index >= rects.size()) return false;
- const RectModel& rect = rects[index];
- int role = index % 4;
- Edges pos = GetEdges(rect);
- const RectModel* leftNeighbor = (index - 2 >= 0) ? &rects[index - 2] : nullptr;
- const RectModel* rightNeighbor = (index + 2 < rects.size()) ? &rects[index + 2] : nullptr;
- int pairIndex = (role == 0 || role == 2) ? index + 1 : index - 1;
- const RectModel* pair = (pairIndex >= 0 && pairIndex < rects.size()) ? &rects[pairIndex] : nullptr;
- if (leftNeighbor) {
- Edges left = GetEdges(*leftNeighbor);
- if (pos.Left < left.Right)
- return false;
- }
- if (rightNeighbor) {
- Edges right = GetEdges(*rightNeighbor);
- if (pos.Right > right.Left)
- return false;
- }
- if (pair) {
- Edges pairPos = GetEdges(*pair);
- if (role == 0 || role == 2) {
- if (pos.Bottom > pairPos.Top)
- return false;
- }
- else {
- if (pos.Top < pairPos.Bottom)
- return false;
- }
- }
- return true;
- }
- std::set<int> GetInvalidRectIndexes(const std::vector<RectModel>& rects) {
- std::set<int> invalid;
- for (int i = 0; i < rects.size(); ++i) {
- if (!IsValidPosition(i, rects)) {
- invalid.insert(i);
- }
- }
- return invalid;
- }
- //********************************************************************************//
- // --- Input Data ---
- std::vector<RectModel> GetRectData() {
- return {
- {0, 80, 275, 130, 150},
- {1, 80, 720, 130, 150},
- {2, 250, 275, 130, 150},
- {3, 250, 720, 130, 150},
- {4, 460, 275, 130, 150},
- {5, 460, 720, 130, 150},
- {6, 640, 275, 130, 150},
- {7, 640, 720, 130, 150},
- {8, 830, 275, 130, 150},
- {9, 830, 720, 130, 150},
- {10, 1000, 275, 130, 150},
- {11, 1000, 720, 130, 150},
- {12, 1220, 275, 130, 150},
- {13, 1220, 720, 130, 150},
- {14, 1380, 275, 130, 150},
- {15, 1380, 720, 130, 150},
- {16, 1580, 275, 130, 150},
- {17, 1580, 720, 130, 150},
- {18, 1730, 275, 130, 150},
- {19, 1730, 720, 130, 150}
- };
- }
- // --- Globals ---
- std::vector<RectModel> rects;
- std::set<int> invalidIndexes;
- std::map<int, std::wstring> InvalidReasons;
- std::vector<std::wstring> OverlapMessages;
- int selectedIndex = -1;
- // *******************************************Visuals*****************************************************
- HWND hSliderX, hSliderY, hEditBox, hEditWidth, hEditHeight;
- std::wstring GetInvalidReasonString(int index, const std::vector<RectModel>& rects) {
- if (index < 0 || index >= rects.size()) return L"Invalid index";
- const RectModel& rect = rects[index];
- int role = index % 4;
- Edges pos = GetEdges(rect);
- const RectModel* leftNeighbor = (index - 2 >= 0) ? &rects[index - 2] : nullptr;
- const RectModel* rightNeighbor = (index + 2 < rects.size()) ? &rects[index + 2] : nullptr;
- int pairIndex = (role == 0 || role == 2) ? index + 1 : index - 1;
- const RectModel* pair = (pairIndex >= 0 && pairIndex < rects.size()) ? &rects[pairIndex] : nullptr;
- std::wstring error;
- // X constraint
- if (leftNeighbor) {
- Edges left = GetEdges(*leftNeighbor);
- if (pos.Left < left.Right)
- error += L"Crosses vertical axis of left neighbor. ";
- }
- if (rightNeighbor) {
- Edges right = GetEdges(*rightNeighbor);
- if (pos.Right > right.Left)
- error += L"Crosses vertical axis of right neighbor. ";
- }
- // Y constraint
- if (pair) {
- Edges pairPos = GetEdges(*pair);
- if (role == 0 || role == 2) {
- if (pos.Bottom > pairPos.Top)
- error += L"Crosses horizontal axis of its pair. ";
- }
- else {
- if (pos.Top < pairPos.Bottom)
- error += L"Crosses horizontal axis of its pair. ";
- }
- }
- // Role mismatch
- int groupStart = (index / 4) * 4;
- int groupEnd = min((int)rects.size(), groupStart + 4);
- if (groupEnd - groupStart == 4) {
- const Edges& current = GetEdges(rect);
- const Edges& TL = GetEdges(rects[groupStart]);
- const Edges& BL = GetEdges(rects[groupStart + 1]);
- const Edges& TR = GetEdges(rects[groupStart + 2]);
- const Edges& BR = GetEdges(rects[groupStart + 3]);
- switch (role) {
- case 0: if (!(current.Left <= TR.Left && current.Top <= BL.Top)) error += L"Expected Top-Left. "; break;
- case 1: if (!(current.Left <= BR.Left && current.Top >= TL.Bottom)) error += L"Expected Bottom-Left. "; break;
- case 2: if (!(current.Left >= TL.Right && current.Top <= BR.Top)) error += L"Expected Top-Right. "; break;
- case 3: if (!(current.Left >= BL.Right && current.Top >= TR.Bottom)) error += L"Expected Bottom-Right. "; break;
- }
- }
- return error;
- }
- void UpdateValidation() {
- invalidIndexes.clear();
- InvalidReasons.clear();
- OverlapMessages.clear();
- std::map<std::wstring, std::vector<int>> crossGroups;
- for (int i = 0; i < rects.size(); ++i) {
- if (!IsValidPosition(i, rects)) {
- invalidIndexes.insert(i);
- std::wstring reason = GetInvalidReasonString(i, rects);
- InvalidReasons[i] = reason;
- // Check if it's a cross-axis issue
- if (reason.find(L"Crosses vertical axis") != std::wstring::npos ||
- reason.find(L"Crosses horizontal axis") != std::wstring::npos) {
- std::wstring key = L"group_" + std::to_wstring(i / 4);
- crossGroups[key].push_back(i);
- }
- }
- }
- for (const auto& group : crossGroups) {
- const auto& affected = group.second;
- std::wstringstream ss;
- ss << L"Rectangles at indices [";
- for (size_t i = 0; i < affected.size(); ++i) {
- ss << affected[i];
- if (i < affected.size() - 1) ss << L", ";
- }
- ss << L"] cross the horizontal or vertical axis of neighbors. ";
- ss << L"Currently these are marked invalid, but only those that mismatch their role should be marked.";
- OverlapMessages.push_back(ss.str());
- }
- }
- void UpdateSelectedRectFromSliders() {
- if (selectedIndex < 0 || selectedIndex >= rects.size()) return;
- int x = SendMessage(hSliderX, TBM_GETPOS, 0, 0);
- int y = SendMessage(hSliderY, TBM_GETPOS, 0, 0);
- rects[selectedIndex].X = x;
- rects[selectedIndex].Y = y;
- UpdateValidation();
- }
- void SetSlidersToRectPosition() {
- if (selectedIndex < 0 || selectedIndex >= rects.size()) return;
- const RectModel& r = rects[selectedIndex];
- SendMessage(hSliderX, TBM_SETPOS, TRUE, static_cast<int>(r.X));
- SendMessage(hSliderY, TBM_SETPOS, TRUE, static_cast<int>(r.Y));
- wchar_t buf[32];
- swprintf_s(buf, L"%d", static_cast<int>(r.Width));
- SetWindowText(hEditWidth, buf);
- swprintf_s(buf, L"%d", static_cast<int>(r.Height));
- SetWindowText(hEditHeight, buf);
- }
- LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
- switch (msg) {
- case WM_CREATE: {
- InitCommonControls();
- // Label for Index
- CreateWindow(L"STATIC", L"Index:", WS_VISIBLE | WS_CHILD,
- 10, 10, 40, 20, hwnd, nullptr, nullptr, nullptr);
- // Edit box for entering the index
- hEditBox = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER,
- 60, 10, 50, 20, hwnd, (HMENU)1001, nullptr, nullptr);
- // Label for X slider
- CreateWindow(L"STATIC", L"X Position:", WS_VISIBLE | WS_CHILD,
- 10, 50, 100, 20, hwnd, nullptr, nullptr, nullptr);
- // X position slider
- hSliderX = CreateWindow(TRACKBAR_CLASS, L"X Slider", WS_VISIBLE | WS_CHILD | TBS_AUTOTICKS,
- 130, 50, 300, 30, hwnd, (HMENU)1002, nullptr, nullptr);
- SendMessage(hSliderX, TBM_SETRANGE, TRUE, MAKELPARAM(0, 1800));
- // Label for Y slider
- CreateWindow(L"STATIC", L"Y Position:", WS_VISIBLE | WS_CHILD,
- 10, 90, 100, 20, hwnd, nullptr, nullptr, nullptr);
- // Y position slider
- hSliderY = CreateWindow(TRACKBAR_CLASS, L"Y Slider", WS_VISIBLE | WS_CHILD | TBS_AUTOTICKS,
- 130, 90, 300, 30, hwnd, (HMENU)1003, nullptr, nullptr);
- SendMessage(hSliderY, TBM_SETRANGE, TRUE, MAKELPARAM(0, 1000));
- // Label for Width
- CreateWindow(L"STATIC", L"Width:", WS_VISIBLE | WS_CHILD,
- 460, 50, 50, 20, hwnd, nullptr, nullptr, nullptr);
- // Width input
- hEditWidth = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER,
- 520, 50, 60, 20, hwnd, (HMENU)1004, nullptr, nullptr);
- // Label for Height
- CreateWindow(L"STATIC", L"Height:", WS_VISIBLE | WS_CHILD,
- 460, 90, 50, 20, hwnd, nullptr, nullptr, nullptr);
- // Height input
- hEditHeight = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER,
- 520, 90, 60, 20, hwnd, (HMENU)1005, nullptr, nullptr);
- break;
- }
- case WM_COMMAND: {
- if (LOWORD(wParam) == 1001 && HIWORD(wParam) == EN_CHANGE) {
- wchar_t buf[16];
- GetWindowText(hEditBox, buf, 16);
- int idx = _wtoi(buf);
- if (idx >= 0 && idx < rects.size()) {
- selectedIndex = idx;
- SetSlidersToRectPosition();
- }
- }
- else if ((LOWORD(wParam) == 1004 || LOWORD(wParam) == 1005) && HIWORD(wParam) == EN_CHANGE) {
- if (selectedIndex >= 0 && selectedIndex < rects.size()) {
- wchar_t buf[16];
- GetWindowText(hEditWidth, buf, 16);
- int newWidth = _wtoi(buf);
- GetWindowText(hEditHeight, buf, 16);
- int newHeight = _wtoi(buf);
- if (newWidth > 0 && newHeight > 0) {
- rects[selectedIndex].Width = newWidth;
- rects[selectedIndex].Height = newHeight;
- UpdateValidation();
- RECT canvasRect = { 0, 150, 1920, 1080 };
- InvalidateRect(hwnd, &canvasRect, FALSE);
- }
- }
- }
- break;
- }
- case WM_HSCROLL: {
- if ((HWND)lParam == hSliderX || (HWND)lParam == hSliderY) {
- UpdateSelectedRectFromSliders();
- RECT canvasRect = { 0, 150, 1920, 1080 };
- InvalidateRect(hwnd, &canvasRect, FALSE);
- }
- break;
- }
- case WM_ERASEBKGND:
- return 1;
- case WM_PAINT: {
- PAINTSTRUCT ps;
- HDC hdc = BeginPaint(hwnd, &ps);
- RECT clientRect;
- GetClientRect(hwnd, &clientRect);
- HDC memDC = CreateCompatibleDC(hdc);
- HBITMAP memBitmap = CreateCompatibleBitmap(hdc, clientRect.right, clientRect.bottom);
- HBITMAP oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);
- HBRUSH bgBrush = CreateSolidBrush(RGB(255, 255, 255));
- FillRect(memDC, &clientRect, bgBrush);
- DeleteObject(bgBrush);
- if (!OverlapMessages.empty()) {
- SetBkMode(memDC, TRANSPARENT);
- SetTextColor(memDC, RGB(200, 0, 0));
- int msgY = 170;
- for (const auto& msg : OverlapMessages) {
- RECT textRect = { 400, msgY, 1600, msgY + 40 };
- DrawText(memDC, msg.c_str(), -1, &textRect, DT_CENTER | DT_TOP | DT_WORDBREAK);
- msgY += 40;
- }
- }
- // Draw rects onto memDC
- for (const auto& rect : rects) {
- RECT r;
- r.left = static_cast<LONG>(rect.X);
- r.top = static_cast<LONG>(rect.Y);
- r.right = r.left + static_cast<LONG>(rect.Width);
- r.bottom = r.top + static_cast<LONG>(rect.Height);
- bool isInvalid = invalidIndexes.count(rect.Index) > 0;
- HPEN pen = CreatePen(PS_SOLID, 3, isInvalid ? RGB(255, 0, 0) : RGB(0, 200, 0));
- HPEN oldPen = (HPEN)SelectObject(memDC, pen);
- HBRUSH oldBrush = (HBRUSH)SelectObject(memDC, GetStockObject(NULL_BRUSH));
- Rectangle(memDC, r.left, r.top, r.right, r.bottom);
- SelectObject(memDC, oldBrush);
- SelectObject(memDC, oldPen);
- DeleteObject(pen);
- std::wstringstream ss;
- ss << rect.Index;
- std::wstring label = ss.str();
- SetBkMode(memDC, TRANSPARENT);
- SetTextColor(memDC, RGB(0, 0, 0));
- DrawText(memDC, label.c_str(), -1, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
- // Draw validation message if invalid
- auto it = InvalidReasons.find(rect.Index);
- if (it != InvalidReasons.end()) {
- RECT msgRect = r;
- msgRect.top = r.bottom + 5;
- msgRect.bottom = msgRect.top + 80;
- msgRect.left -= 50;
- msgRect.right += 50;
- SetTextColor(memDC, RGB(200, 0, 0));
- DrawText(memDC, it->second.c_str(), -1, &msgRect, DT_CENTER | DT_TOP | DT_WORDBREAK);
- }
- }
- BitBlt(hdc, 0, 0, clientRect.right, clientRect.bottom, memDC, 0, 0, SRCCOPY);
- // Clean up
- SelectObject(memDC, oldBitmap);
- DeleteObject(memBitmap);
- DeleteDC(memDC);
- EndPaint(hwnd, &ps);
- break;
- }
- case WM_DESTROY:
- PostQuitMessage(0);
- break;
- default:
- return DefWindowProc(hwnd, msg, wParam, lParam);
- }
- return 0;
- }
- int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {
- const wchar_t CLASS_NAME[] = L"RectEditorWin32";
- WNDCLASS wc = {};
- wc.lpfnWndProc = WndProc;
- wc.hInstance = hInstance;
- wc.lpszClassName = CLASS_NAME;
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
- RegisterClass(&wc);
- HWND hwnd = CreateWindowEx(
- 0, CLASS_NAME, L"RectModel Editor - Win32",
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT, CW_USEDEFAULT, 1920, 1080,
- nullptr, nullptr, hInstance, nullptr
- );
- if (!hwnd) return 0;
- rects = GetRectData();
- UpdateValidation();
- ShowWindow(hwnd, nCmdShow);
- UpdateWindow(hwnd);
- MSG msg = {};
- while (GetMessage(&msg, nullptr, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement