Qt widgets
This commit is contained in:
parent
6cc15c1989
commit
8264d93da3
@ -3,17 +3,24 @@ project(cg1)
|
|||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
find_package (Qt5Widgets REQUIRED)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
add_executable(
|
add_executable(
|
||||||
cg1
|
cg1
|
||||||
|
|
||||||
WIN32
|
WIN32
|
||||||
|
src/main.cpp
|
||||||
|
|
||||||
src/frame.hpp
|
src/frame.hpp
|
||||||
src/drawing_assets.hpp
|
src/drawing_assets.hpp
|
||||||
src/drawing_assets.cpp
|
src/drawing_assets.cpp
|
||||||
src/painter.cpp
|
src/painter.cpp
|
||||||
src/painter.hpp
|
src/painter.hpp
|
||||||
src/main.cpp
|
src/old_main.cpp
|
||||||
|
|
||||||
)
|
src/ui.hpp
|
||||||
|
src/ui.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
qt5_use_modules(cg1 Widgets)
|
253
src/main.cpp
253
src/main.cpp
@ -1,248 +1,13 @@
|
|||||||
// lab_1_basics.cpp : Определяет точку входа для приложения.
|
#include <QApplication>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#include "ui.hpp"
|
||||||
|
|
||||||
#include <Windows.h>
|
int main(int argc, char **argv) {
|
||||||
#include <commctrl.h>
|
QApplication qapp(argc, argv);
|
||||||
#include "stdio.h"
|
|
||||||
#include "frame.hpp"
|
|
||||||
#include "painter.hpp"
|
|
||||||
|
|
||||||
// Windows-приложение для создания буфера кадра
|
auto w = new MainWindow();
|
||||||
|
w->show();
|
||||||
LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
|
|
||||||
|
|
||||||
HWND hWndStatusBar; // Дескриптор компонента StatusBar
|
|
||||||
|
|
||||||
int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode) {
|
|
||||||
char szWinName[] = "Graphics Window Class"; // Имя класса окна
|
|
||||||
|
|
||||||
HWND hWnd; // Дескриптор главного окна
|
|
||||||
MSG msg;
|
|
||||||
WNDCLASSA wcl; // Определитель класса окна
|
|
||||||
wcl.hInstance = hThisInstance; // Дескриптор приложения
|
|
||||||
wcl.lpszClassName = szWinName;// Имя класса окна
|
|
||||||
wcl.lpfnWndProc = WindowProc; // Функция обработки сообщений
|
|
||||||
wcl.style = 0; // Стиль по умолчанию
|
|
||||||
wcl.hIcon = LoadIcon(nullptr, IDI_APPLICATION);// Иконка
|
|
||||||
wcl.hCursor = LoadCursor(nullptr, IDC_ARROW); // Курсор
|
|
||||||
wcl.lpszMenuName = nullptr; // Без меню
|
|
||||||
wcl.cbClsExtra = 0; // Без дополнительной информации
|
|
||||||
wcl.cbWndExtra = sizeof(PainterState *) + sizeof(Painter **);
|
|
||||||
static_assert(sizeof(PainterState *) == sizeof(LONG_PTR));
|
|
||||||
static_assert(sizeof(Painter **) == sizeof(LONG_PTR));
|
|
||||||
|
|
||||||
|
|
||||||
wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); //Белый фон
|
|
||||||
|
|
||||||
if (!RegisterClassA(&wcl)) // Регистрируем класс окна
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
hWnd = CreateWindowA(szWinName, // Создать окно
|
|
||||||
"Лабораторная работа №1. Буфер кадра. Алгоритмы Брезенхейма",
|
|
||||||
WS_OVERLAPPEDWINDOW, // Стиль окна
|
|
||||||
CW_USEDEFAULT, // x-координата
|
|
||||||
CW_USEDEFAULT, // y-координата
|
|
||||||
CW_USEDEFAULT, // Ширина
|
|
||||||
CW_USEDEFAULT, // Высота
|
|
||||||
HWND_DESKTOP, // Без родительского окна
|
|
||||||
nullptr, // Без меню
|
|
||||||
hThisInstance, // Дескриптор приложения
|
|
||||||
nullptr); // Без дополнительных аргументов
|
|
||||||
|
|
||||||
// Создаём компонент типа StatusBar
|
|
||||||
hWndStatusBar = CreateWindowExA(
|
|
||||||
0, STATUSCLASSNAMEA, nullptr,
|
|
||||||
WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
|
|
||||||
0, 0, 0, 0,
|
|
||||||
hWnd, (HMENU) 10001,
|
|
||||||
hThisInstance, nullptr
|
|
||||||
);
|
|
||||||
|
|
||||||
// Настройка частей StatusBar'а
|
|
||||||
int statwidths[] = {150, 300, 450, -1};
|
|
||||||
SendMessageA(hWndStatusBar, SB_SETPARTS, sizeof(statwidths) / sizeof(int), (LPARAM) statwidths);
|
|
||||||
|
|
||||||
ShowWindow(hWnd, nWinMode); // Показать окно
|
|
||||||
UpdateWindow(hWnd); // Перерисовать окно
|
|
||||||
|
|
||||||
while (GetMessage(&msg, nullptr, 0, 0)) // Запустить цикл обработки сообщений
|
|
||||||
{
|
|
||||||
TranslateMessage(&msg); // Разрешить использование клавиатуры
|
|
||||||
DispatchMessage(&msg); // Вернуть управление операционной системе Windows
|
|
||||||
}
|
|
||||||
|
|
||||||
return msg.wParam;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Следующая функция вызывается операционной системой Windows и получает в качестве
|
|
||||||
// параметров сообщения из очереди сообщений данного приложения
|
|
||||||
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
||||||
static int pixelSize = 8; // Размер "большого" пикселя
|
|
||||||
|
|
||||||
switch (message) {
|
|
||||||
case WM_CREATE:
|
|
||||||
SetTimer(hWnd, 1, 1000 / 30, nullptr);
|
|
||||||
SetWindowLongPtr(hWnd, 0, (LONG_PTR) new PainterState());
|
|
||||||
SetWindowLongPtr(hWnd, sizeof(PainterState *), (LONG_PTR) &predefined_painters[0]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_PAINT: {
|
|
||||||
PAINTSTRUCT ps;
|
|
||||||
|
|
||||||
HDC hdc = BeginPaint(hWnd, &ps);
|
|
||||||
|
|
||||||
// Определяем ширину и высоту окна
|
|
||||||
RECT rect = ps.rcPaint;
|
|
||||||
GetClientRect(hWnd, &rect);
|
|
||||||
|
|
||||||
int width = rect.right - rect.left;
|
|
||||||
int height = rect.bottom - rect.top;
|
|
||||||
|
|
||||||
// Рисование в буфер кадра
|
|
||||||
|
|
||||||
int ratio = pixelSize; // Размер "большого" пикселя
|
|
||||||
|
|
||||||
int W = width / ratio;
|
|
||||||
int H = (height - 22) / ratio; // Отнимем высоту StatusBar'а
|
|
||||||
|
|
||||||
Frame frame(W, H);
|
|
||||||
auto *state = reinterpret_cast<PainterState *>(GetWindowLongPtr(hWnd, 0));
|
|
||||||
auto *painter = *reinterpret_cast<Painter **>(GetWindowLongPtr(hWnd, sizeof(PainterState *)));
|
|
||||||
PixelGridPainter{COLOR{245, 245, 245}, COLOR{240, 240, 240}}.draw(state, &frame);
|
|
||||||
painter->draw(state, &frame);
|
|
||||||
|
|
||||||
// Системная структура для хранения цвета пикселя
|
|
||||||
// Буфер кадра, который будет передаваться операционной системе, должен состоять из массива этих структур
|
|
||||||
// Она не совпадает с порядком следования цветов в формате RBG
|
|
||||||
typedef struct tagRGBPIXEL {
|
|
||||||
unsigned char BLUE; // Компонента синего цвета
|
|
||||||
unsigned char GREEN; // Компонента зелёного цвета
|
|
||||||
unsigned char RED; // Компонента красного цвета
|
|
||||||
unsigned char ALPHA; // Прозрачность
|
|
||||||
} RGBPIXEL;
|
|
||||||
|
|
||||||
// Выделение памяти для второго буфера, который будет передаваться функции CreateBitmap для создания картинки
|
|
||||||
RGBPIXEL *bitmap = (RGBPIXEL *) HeapAlloc(GetProcessHeap(), 0, width * height * sizeof(RGBPIXEL));
|
|
||||||
|
|
||||||
// Копирование массива пикселей в соответствии с системным форматом пикселя и масштабирование картинки
|
|
||||||
// W и H - ширина и высота изображения в буфере кадра
|
|
||||||
// ratio - коэффициент масштабирования пикселей
|
|
||||||
for (int y = 0; y < H * ratio; y++)
|
|
||||||
for (int x = 0; x < W * ratio; x++) {
|
|
||||||
RGBPIXEL *pixel = bitmap + y * width + x;
|
|
||||||
COLOR color = frame.get_pixel(x / ratio, y / ratio);
|
|
||||||
pixel->RED = color.red;
|
|
||||||
pixel->GREEN = color.green;
|
|
||||||
pixel->BLUE = color.blue;
|
|
||||||
pixel->ALPHA = color.alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Получить дескриптор на новое растровое изображение
|
|
||||||
HBITMAP hBitMap = CreateBitmap(width, height, 1, sizeof(RGBPIXEL) * 8, bitmap);
|
|
||||||
|
|
||||||
// Освободить память, которую занимает буфер цвета
|
|
||||||
HeapFree(GetProcessHeap(), 0, bitmap);
|
|
||||||
|
|
||||||
// Создать в оперативной памяти контекст, совместимый с экранным контекстом, который мы используем, чтобы рисовать
|
|
||||||
HDC srcHdc = CreateCompatibleDC(hdc);
|
|
||||||
|
|
||||||
// Связать картинку с новым контекстом
|
|
||||||
SelectObject(srcHdc, hBitMap);
|
|
||||||
|
|
||||||
// Копировать содержимое из временного контекста srcHdc в основной контекст окна hdc
|
|
||||||
BitBlt(
|
|
||||||
hdc, // Основной контекст
|
|
||||||
0, 0, // Координаты левого верхнего угла, от которого будет выполняться вставка
|
|
||||||
width, // Ширина вставляемого изображения
|
|
||||||
height, // Высота вставляемого изображения
|
|
||||||
srcHdc, // Дескриптор временного контекста
|
|
||||||
0, 0, // Координаты считываемого изображения
|
|
||||||
SRCCOPY); // Параметры операции - копирование
|
|
||||||
|
|
||||||
EndPaint(hWnd, &ps);
|
|
||||||
|
|
||||||
// Удаление картинки из памяти
|
|
||||||
DeleteObject(hBitMap);
|
|
||||||
|
|
||||||
// Удаление временного контекста
|
|
||||||
DeleteDC(srcHdc);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_MOUSEMOVE: {
|
|
||||||
char str[256];
|
|
||||||
|
|
||||||
SendMessageA(hWndStatusBar, SB_SETTEXTA, 3, (LPARAM) "F4: Сменить рисунок");
|
|
||||||
|
|
||||||
// Устанавливаем текст в разных частях StatusBar'а
|
|
||||||
// Экранные координаты курсора мыши
|
|
||||||
sprintf_s(str, "X = %d, Y = %d", LOWORD(lParam), HIWORD(lParam));
|
|
||||||
SendMessageA(hWndStatusBar, SB_SETTEXTA, 2, (LPARAM) str);
|
|
||||||
|
|
||||||
// Координаты пикселя в буфере кадра
|
|
||||||
sprintf_s(str, "BX = %d, BY = %d", LOWORD(lParam) / pixelSize, HIWORD(lParam) / pixelSize);
|
|
||||||
SendMessageA(hWndStatusBar, SB_SETTEXTA, 1, (LPARAM) str);
|
|
||||||
|
|
||||||
sprintf_s(str, "Масштаб (F2/F3): %d", pixelSize);
|
|
||||||
SendMessageA(hWndStatusBar, SB_SETTEXTA, 0, (LPARAM) str);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_LBUTTONDOWN:
|
|
||||||
reinterpret_cast<PainterState *>(GetWindowLongPtr(hWnd, 0))->set_clicked_pixel(LOWORD(lParam) / pixelSize, HIWORD(lParam) / pixelSize);
|
|
||||||
InvalidateRect(hWnd, nullptr, false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_KEYDOWN:
|
|
||||||
if (wParam == VK_F2 || wParam == VK_F3) {
|
|
||||||
if (pixelSize > 1 && wParam == VK_F2) pixelSize--;
|
|
||||||
if (pixelSize < 64 && wParam == VK_F3) pixelSize++;
|
|
||||||
|
|
||||||
InvalidateRect(hWnd, nullptr, false);
|
|
||||||
|
|
||||||
char str[256];
|
|
||||||
sprintf_s(str, "Масштаб (F2/F3): %d", pixelSize);
|
|
||||||
SendMessageA(hWndStatusBar, SB_SETTEXTA, 0, (LPARAM) str);
|
|
||||||
}
|
|
||||||
if (wParam == VK_F1) {
|
|
||||||
MessageBoxA(hWnd, "Работу выполнил студент группы ПВ-221 Колесников А.И.", "О программе", MB_ICONINFORMATION);
|
|
||||||
}
|
|
||||||
if (wParam == VK_F4) {
|
|
||||||
auto newPtr = reinterpret_cast<Painter const *const *>(GetWindowLongPtr(hWnd, sizeof(PainterState *)));
|
|
||||||
newPtr++;
|
|
||||||
if (*newPtr == nullptr)
|
|
||||||
newPtr = &predefined_painters[0];
|
|
||||||
|
|
||||||
SetWindowLongPtr(hWnd, sizeof(PainterState *), (LONG_PTR) newPtr);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Обработка сообщения на изменение размера окна
|
|
||||||
case WM_SIZE:
|
|
||||||
SendMessageA(hWndStatusBar, WM_SIZE, 0, 0);
|
|
||||||
InvalidateRect(hWnd, nullptr, false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_TIMER:
|
|
||||||
reinterpret_cast<PainterState *>(GetWindowLongPtr(hWnd, 0))->angle += 0.05;
|
|
||||||
InvalidateRect(hWnd, nullptr, false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
case WM_DESTROY:
|
|
||||||
delete reinterpret_cast<PainterState *>(GetWindowLongPtr(hWnd, 0));
|
|
||||||
SetWindowLongPtr(hWnd, 0, reinterpret_cast<LONG_PTR>(nullptr));
|
|
||||||
PostQuitMessage(0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Все сообщения, не обрабатываемые в данной функции, направляются на обработку по умолчанию
|
|
||||||
return DefWindowProcA(hWnd, message, wParam, lParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
QApplication::exec();
|
||||||
|
}
|
129
src/ui.cpp
Normal file
129
src/ui.cpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#include <QWidget>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "ui.hpp"
|
||||||
|
|
||||||
|
const QString StatusBar::_scale_label_template{"[F2]/[F3] Масштаб: %1 пикселей"};
|
||||||
|
const QString StatusBar::_painter_label_template{"[Q] Отображаемая фигура: %1/%2"};
|
||||||
|
const QString StatusBar::_x_template{"X=%1"};
|
||||||
|
const QString StatusBar::_y_template{"Y=%1"};
|
||||||
|
|
||||||
|
StatusBar::StatusBar(QWidget *parent) : QWidget(parent) {
|
||||||
|
this->_layout = new QGridLayout(parent);
|
||||||
|
this->setLayout(this->_layout);
|
||||||
|
|
||||||
|
auto add_label = [&](QLabel **dst, QString text, int row, int column, QFlags<Qt::AlignmentFlag> alignment) {
|
||||||
|
*dst = new QLabel(text, this);
|
||||||
|
this->_layout->addWidget(*dst, row, column, alignment);
|
||||||
|
};
|
||||||
|
|
||||||
|
add_label(&(this->_scale_label), StatusBar::_scale_label_template.arg("??"), 0, 0, Qt::AlignRight);
|
||||||
|
add_label(&(this->_painter_label), StatusBar::_painter_label_template.arg("??", "??"), 1, 0, Qt::AlignRight);
|
||||||
|
|
||||||
|
add_label(&(this->_screen_coordinates.title), "Экранные координаты:", 0, 1, Qt::AlignRight);
|
||||||
|
add_label(&(this->_screen_coordinates.x), StatusBar::_x_template.arg("??"), 0, 2, Qt::AlignHCenter);
|
||||||
|
add_label(&(this->_screen_coordinates.y), StatusBar::_y_template.arg("??"), 0, 3, Qt::AlignHCenter);
|
||||||
|
|
||||||
|
add_label(&(this->_scaled_coordinates.title), "Системные координаты:", 1, 1, Qt::AlignRight);
|
||||||
|
add_label(&(this->_scaled_coordinates.x), StatusBar::_x_template.arg("??"), 1, 2, Qt::AlignHCenter);
|
||||||
|
add_label(&(this->_scaled_coordinates.y), StatusBar::_y_template.arg("??"), 1, 3, Qt::AlignHCenter);
|
||||||
|
|
||||||
|
this->_layout->setColumnStretch(4, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBar::set_coordinates(unsigned int screen_x, unsigned int screen_y, unsigned int scaled_x, unsigned int scaled_y) {
|
||||||
|
this->_screen_coordinates.x->setText(StatusBar::_x_template.arg(screen_x));
|
||||||
|
this->_screen_coordinates.y->setText(StatusBar::_y_template.arg(screen_y));
|
||||||
|
|
||||||
|
this->_scaled_coordinates.x->setText(StatusBar::_x_template.arg(scaled_x));
|
||||||
|
this->_scaled_coordinates.y->setText(StatusBar::_y_template.arg(scaled_y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBar::set_scale(unsigned int current_scale) {
|
||||||
|
this->_scale_label->setText(StatusBar::_scale_label_template.arg(current_scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBar::set_painter_index(unsigned int index, unsigned int painters_count) {
|
||||||
|
this->_painter_label->setText(StatusBar::_painter_label_template.arg(index).arg(painters_count));
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas::Canvas(QWidget *parent) : QWidget(parent), _current_frame{}, _sync{} {
|
||||||
|
this->setMouseTracking(true);
|
||||||
|
this->grabKeyboard();
|
||||||
|
|
||||||
|
this->_mouse_processing.is_pressed = false;
|
||||||
|
this->_mouse_processing.pressed_at = QPoint(0, 0);
|
||||||
|
this->_mouse_processing.is_moved_while_pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::set_frame(QImage &f) {
|
||||||
|
this->_sync.lock();
|
||||||
|
this->_current_frame = std::move(f);
|
||||||
|
this->_sync.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::paintEvent(QPaintEvent *event) {
|
||||||
|
QPainter painter{};
|
||||||
|
painter.begin(this);
|
||||||
|
this->_sync.lock();
|
||||||
|
painter.drawImage(this->_current_frame.rect(), this->_current_frame);
|
||||||
|
this->_sync.unlock();
|
||||||
|
painter.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::resizeEvent(QResizeEvent *event) {
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
emit this->resized(event->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::MainWindow() : QWidget{} {
|
||||||
|
this->_layout = new QGridLayout(this);
|
||||||
|
this->setLayout(this->_layout);
|
||||||
|
|
||||||
|
this->_status_bar = new StatusBar(this);
|
||||||
|
this->_layout->addWidget(this->_status_bar, 0, 0);
|
||||||
|
|
||||||
|
this->_canvas = new Canvas(this);
|
||||||
|
this->_layout->addWidget(this->_canvas, 1, 0);
|
||||||
|
|
||||||
|
this->_layout->setColumnStretch(0, 1);
|
||||||
|
this->_layout->setRowStretch(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::keyPressEvent(QKeyEvent *event) {
|
||||||
|
emit this->key_pressed(static_cast<Qt::Key>(event->key()));
|
||||||
|
std::cout << "key pressed" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::mousePressEvent(QMouseEvent *event) {
|
||||||
|
this->_mouse_processing.is_pressed = true;
|
||||||
|
this->_mouse_processing.pressed_at = event->pos();
|
||||||
|
this->_mouse_processing.is_moved_while_pressed = false;
|
||||||
|
std::cout << "mouse press" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::mouseMoveEvent(QMouseEvent *event) {
|
||||||
|
if (this->_mouse_processing.is_pressed) {
|
||||||
|
this->_mouse_processing.is_moved_while_pressed = true;
|
||||||
|
emit this->pressed_mouse_moved(event->pos());
|
||||||
|
} else {
|
||||||
|
emit this->pressed_mouse_moved(event->pos());
|
||||||
|
}
|
||||||
|
std::cout << "mouse move" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Canvas::mouseReleaseEvent(QMouseEvent *event) {
|
||||||
|
this->_mouse_processing.is_pressed = false;
|
||||||
|
if (this->_mouse_processing.is_moved_while_pressed) {
|
||||||
|
emit this->mouse_dragged(this->_mouse_processing.pressed_at, event->pos());
|
||||||
|
} else {
|
||||||
|
emit this->mouse_clicked(event->pos());
|
||||||
|
}
|
||||||
|
std::cout << "mouse release" << std::endl;
|
||||||
|
}
|
||||||
|
|
107
src/ui.hpp
Normal file
107
src/ui.hpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QSize>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
|
||||||
|
#include "frame.hpp"
|
||||||
|
|
||||||
|
class StatusBar : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
QGridLayout *_layout;
|
||||||
|
|
||||||
|
QLabel *_scale_label;
|
||||||
|
static const QString _scale_label_template;
|
||||||
|
|
||||||
|
QLabel *_painter_label;
|
||||||
|
static const QString _painter_label_template;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
QLabel *title;
|
||||||
|
QLabel *x;
|
||||||
|
QLabel *y;
|
||||||
|
} _screen_coordinates, _scaled_coordinates;
|
||||||
|
static const QString _x_template, _y_template;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit StatusBar(QWidget *parent);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void set_coordinates(unsigned screen_x, unsigned screen_y, unsigned scaled_x, unsigned scaled_y);
|
||||||
|
|
||||||
|
void set_scale(unsigned current_scale);
|
||||||
|
|
||||||
|
void set_painter_index(unsigned index, unsigned painters_count);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Canvas : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
QMutex _sync;
|
||||||
|
QImage _current_frame;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Canvas(QWidget *parent);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void set_frame(QImage &f);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void resized(QSize new_size);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct {
|
||||||
|
bool is_pressed;
|
||||||
|
QPoint pressed_at;
|
||||||
|
bool is_moved_while_pressed;
|
||||||
|
} _mouse_processing;
|
||||||
|
public:
|
||||||
|
|
||||||
|
void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
|
void mouseMoveEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void key_pressed(Qt::Key key);
|
||||||
|
|
||||||
|
void released_mouse_moved(QPoint to);
|
||||||
|
|
||||||
|
void pressed_mouse_moved(QPoint to);
|
||||||
|
|
||||||
|
void mouse_clicked(QPoint where);
|
||||||
|
|
||||||
|
void mouse_dragged(QPoint from, QPoint to);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class MainWindow : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
QGridLayout *_layout;
|
||||||
|
public:
|
||||||
|
StatusBar *_status_bar;
|
||||||
|
Canvas *_canvas;
|
||||||
|
|
||||||
|
MainWindow();
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user