Clean project structure.
This commit is contained in:
parent
78a4fa99ff
commit
947bf937fd
496 changed files with 206 additions and 137 deletions
4
src/ui/CMakeLists.txt
Normal file
4
src/ui/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
add_subdirectory(client)
|
||||
add_subdirectory(ui_controls)
|
||||
add_subdirectory(ui_elements)
|
||||
add_subdirectory(windows)
|
29
src/ui/client/CMakeLists.txt
Normal file
29
src/ui/client/CMakeLists.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
set(MODULE_NAME client)
|
||||
|
||||
list(APPEND TARGET_HEADERS
|
||||
TopBar.h
|
||||
StatusBar.h
|
||||
GuiApplication.h
|
||||
TabbedPanelWidget.h
|
||||
TopBarMenu.h)
|
||||
|
||||
list(APPEND TARGET_SOURCES
|
||||
TopBar.cpp
|
||||
StatusBar.cpp
|
||||
GuiApplication.cpp
|
||||
TabbedPanelWidget.cpp
|
||||
TopBarMenu.cpp)
|
||||
|
||||
add_library(${MODULE_NAME} SHARED ${TARGET_SOURCES} ${TARGET_HEADERS})
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ui_controls windows core console database geometry)
|
||||
|
||||
target_include_directories(${MODULE_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/text_editor
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/audio_editor
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/image_editor
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/web_client
|
||||
)
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/ui)
|
||||
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
66
src/ui/client/GuiApplication.cpp
Normal file
66
src/ui/client/GuiApplication.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
#include "GuiApplication.h"
|
||||
|
||||
#include "UiInterfaceFactory.h"
|
||||
#include "Window.h"
|
||||
#include "WindowManager.h"
|
||||
#include "DesktopManager.h"
|
||||
#include "FontsManager.h"
|
||||
#include "MainApplication.h"
|
||||
#include "AbstractUiInterface.h"
|
||||
#include "Widget.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
GuiApplication::GuiApplication(std::unique_ptr<CommandLineArgs> args, std::unique_ptr<MainApplication> mainApp)
|
||||
: AbstractDesktopApp(),
|
||||
mDesktopManager(DesktopManager::Create(this))
|
||||
{
|
||||
if (mainApp)
|
||||
{
|
||||
mMainApplication = std::move(mainApp);
|
||||
}
|
||||
else
|
||||
{
|
||||
mMainApplication = MainApplication::Create();
|
||||
mMainApplication->initialize(args ? std::move(args) : CommandLineArgs::Create());
|
||||
}
|
||||
}
|
||||
|
||||
GuiApplication::~GuiApplication()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AbstractApp* GuiApplication::getMainApplication() const
|
||||
{
|
||||
return mMainApplication.get();
|
||||
}
|
||||
|
||||
AbstractUIInterface* GuiApplication::getUiInterface() const
|
||||
{
|
||||
return mUiInterface.get();
|
||||
}
|
||||
|
||||
void GuiApplication::initializeViews()
|
||||
{
|
||||
mDesktopManager->getWindowManager()->getMainWindow()->setSize(800, 600);
|
||||
}
|
||||
|
||||
void GuiApplication::setUiInterfaceBackend(UiInterfaceFactory::Backend backend)
|
||||
{
|
||||
mUiInterfaceBackend = backend;
|
||||
}
|
||||
|
||||
void GuiApplication::run()
|
||||
{
|
||||
initializeViews();
|
||||
|
||||
MLOG_INFO("Creating Window Interface");
|
||||
mUiInterface = UiInterfaceFactory::create(mDesktopManager.get(), mUiInterfaceBackend);
|
||||
|
||||
mUiInterface->loop();
|
||||
|
||||
MLOG_INFO("Window Interface Shut Down");
|
||||
|
||||
mMainApplication->shutDown();
|
||||
}
|
37
src/ui/client/GuiApplication.h
Normal file
37
src/ui/client/GuiApplication.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractDesktopApp.h"
|
||||
#include "UiInterfaceFactory.h"
|
||||
#include "CommandLineArgs.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class MainApplication;
|
||||
class DesktopManager;
|
||||
class AbstractUiInterface;
|
||||
|
||||
class GuiApplication : public AbstractDesktopApp
|
||||
{
|
||||
public:
|
||||
GuiApplication(std::unique_ptr<CommandLineArgs> args = nullptr, std::unique_ptr<MainApplication> mainApp = nullptr);
|
||||
|
||||
~GuiApplication();
|
||||
|
||||
AbstractApp* getMainApplication() const override;
|
||||
|
||||
AbstractUIInterface* getUiInterface() const override;
|
||||
|
||||
void setUiInterfaceBackend(UiInterfaceFactory::Backend backend);
|
||||
|
||||
void run();
|
||||
|
||||
protected:
|
||||
virtual void initializeViews();
|
||||
|
||||
std::unique_ptr<DesktopManager> mDesktopManager;
|
||||
std::unique_ptr<MainApplication> mMainApplication;
|
||||
|
||||
private:
|
||||
UiInterfaceFactory::Backend mUiInterfaceBackend = UiInterfaceFactory::Backend::UNSET;
|
||||
std::unique_ptr<AbstractUIInterface> mUiInterface;
|
||||
};
|
13
src/ui/client/StatusBar.cpp
Normal file
13
src/ui/client/StatusBar.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "StatusBar.h"
|
||||
|
||||
#include "Color.h"
|
||||
|
||||
StatusBar::StatusBar()
|
||||
{
|
||||
setBackgroundColor(Color(200, 200, 200));
|
||||
}
|
||||
|
||||
std::unique_ptr<StatusBar> StatusBar::Create()
|
||||
{
|
||||
return std::make_unique<StatusBar>();
|
||||
}
|
13
src/ui/client/StatusBar.h
Normal file
13
src/ui/client/StatusBar.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
class StatusBar : public Widget
|
||||
{
|
||||
public:
|
||||
StatusBar();
|
||||
|
||||
static std::unique_ptr<StatusBar> Create();
|
||||
};
|
||||
|
||||
using StatusBarUPtr = std::unique_ptr<StatusBar>;
|
57
src/ui/client/TabbedPanelWidget.cpp
Normal file
57
src/ui/client/TabbedPanelWidget.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include "TabbedPanelWidget.h"
|
||||
#include "StackWidget.h"
|
||||
#include "HorizontalSpacer.h"
|
||||
#include "VerticalSpacer.h"
|
||||
#include "TextNode.h"
|
||||
#include "Button.h"
|
||||
|
||||
TabbedPanelWidget::TabbedPanelWidget()
|
||||
: mNavPanel(),
|
||||
mStack()
|
||||
{
|
||||
auto stack = StackWidget::Create();
|
||||
mStack = stack.get();
|
||||
|
||||
auto nav = HorizontalSpacer::Create();
|
||||
mNavPanel = nav.get();
|
||||
nav->setSize({0, 0, 0, 0, 200, 0});
|
||||
|
||||
auto vertSpacer = VerticalSpacer::Create();
|
||||
vertSpacer->addWidgetWithScale(std::move(nav), 1);
|
||||
vertSpacer->addWidgetWithScale(std::move(stack), 4);
|
||||
addWidget(std::move(vertSpacer));
|
||||
}
|
||||
|
||||
std::unique_ptr<TabbedPanelWidget> TabbedPanelWidget::Create()
|
||||
{
|
||||
return std::make_unique<TabbedPanelWidget>();
|
||||
}
|
||||
|
||||
StackWidget* TabbedPanelWidget::getStack() const
|
||||
{
|
||||
return mStack;
|
||||
}
|
||||
|
||||
void TabbedPanelWidget::addPanel(WidgetUPtr panel, const std::string& label)
|
||||
{
|
||||
auto button = Button::Create();
|
||||
button->setLabel(label);
|
||||
button->setBackgroundColor(Color(156, 156, 156));
|
||||
button->setMargin({1, 0, 0, 1});
|
||||
|
||||
auto rawPanel = panel.get();
|
||||
auto onClick = [this, rawPanel](Widget*){
|
||||
if(this && rawPanel)
|
||||
{
|
||||
this->getStack()->showChild(rawPanel);
|
||||
}
|
||||
};
|
||||
button->setOnClickFunction(onClick);
|
||||
|
||||
mStack->addWidget(std::move(panel));
|
||||
mStack->showChild(rawPanel);
|
||||
|
||||
mNavPanel->addWidget(std::move(button));
|
||||
}
|
||||
|
||||
|
23
src/ui/client/TabbedPanelWidget.h
Normal file
23
src/ui/client/TabbedPanelWidget.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
#include "StackWidget.h"
|
||||
#include <string>
|
||||
|
||||
class TabbedPanelWidget : public Widget
|
||||
{
|
||||
public:
|
||||
TabbedPanelWidget();
|
||||
|
||||
static std::unique_ptr<TabbedPanelWidget> Create();
|
||||
|
||||
void addPanel(WidgetUPtr panel, const std::string& label);
|
||||
|
||||
StackWidget* getStack() const;
|
||||
|
||||
private:
|
||||
Widget* mNavPanel;
|
||||
StackWidget* mStack;
|
||||
};
|
||||
|
||||
using TabbedPanelWidgetUPtr = std::unique_ptr<TabbedPanelWidget>;
|
39
src/ui/client/TopBar.cpp
Normal file
39
src/ui/client/TopBar.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include "TopBar.h"
|
||||
|
||||
#include "Color.h"
|
||||
#include "Theme.h"
|
||||
|
||||
#include "Button.h"
|
||||
#include "TopBarMenu.h"
|
||||
|
||||
TopBar::TopBar()
|
||||
{
|
||||
setBackgroundColor(Theme::getBackgroundPrimary());
|
||||
|
||||
auto fileButton = Button::Create();
|
||||
fileButton->setLabel("File");
|
||||
fileButton->setBackgroundColor(Theme::getBackgroundPrimary());
|
||||
fileButton->setMargin(2);
|
||||
fileButton->setMaxWidth(60);
|
||||
|
||||
auto onClick = [this](Widget* self){
|
||||
if(this)
|
||||
{
|
||||
auto menu = std::make_unique<TopBarMenu>();
|
||||
auto window = getTopLevelWindow();
|
||||
window->addPopup(std::move(menu));
|
||||
};
|
||||
};
|
||||
fileButton->setOnClickFunction(onClick);
|
||||
addWidget(std::move(fileButton));
|
||||
}
|
||||
|
||||
TopBar::~TopBar()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<TopBar> TopBar::Create()
|
||||
{
|
||||
return std::make_unique<TopBar>();
|
||||
}
|
17
src/ui/client/TopBar.h
Normal file
17
src/ui/client/TopBar.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
class TopBarMenu;
|
||||
|
||||
class TopBar : public Widget
|
||||
{
|
||||
public:
|
||||
TopBar();
|
||||
|
||||
~TopBar();
|
||||
|
||||
static std::unique_ptr<TopBar> Create();
|
||||
};
|
||||
|
||||
using TopBarUPtr = std::unique_ptr<TopBar>;
|
0
src/ui/client/TopBarMenu.cpp
Normal file
0
src/ui/client/TopBarMenu.cpp
Normal file
16
src/ui/client/TopBarMenu.h
Normal file
16
src/ui/client/TopBarMenu.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
#include "Window.h"
|
||||
|
||||
class TopBarMenu : public Widget
|
||||
{
|
||||
public:
|
||||
void popupFrom(Widget* parent)
|
||||
{
|
||||
auto window = parent->getTopLevelWindow();
|
||||
|
||||
|
||||
}
|
||||
};
|
110
src/ui/ui_controls/Button.cpp
Normal file
110
src/ui/ui_controls/Button.cpp
Normal file
|
@ -0,0 +1,110 @@
|
|||
#include "Button.h"
|
||||
|
||||
#include "TextNode.h"
|
||||
#include "GeometryNode.h"
|
||||
#include "TransformNode.h"
|
||||
|
||||
#include "MouseEvent.h"
|
||||
#include "FileLogger.h"
|
||||
|
||||
Button::Button()
|
||||
: Widget(),
|
||||
mLabel(),
|
||||
mCachedColor(255, 255, 255),
|
||||
mClickedColor(Color(180, 180, 180)),
|
||||
mClickFunc()
|
||||
{
|
||||
mName = "Button";
|
||||
}
|
||||
|
||||
Button::~Button()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<Button> Button::Create()
|
||||
{
|
||||
return std::make_unique<Button>();
|
||||
}
|
||||
|
||||
void Button::setOnClickFunction(clickFunc func)
|
||||
{
|
||||
mClickFunc = func;
|
||||
}
|
||||
|
||||
void Button::setLabel(const std::string& text)
|
||||
{
|
||||
if (text != mLabel)
|
||||
{
|
||||
mLabel = text;
|
||||
mContentDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Button::onMyMouseEvent(const MouseEvent* event)
|
||||
{
|
||||
MLOG_INFO("Widget mouse event");
|
||||
if(event->getAction() == MouseEvent::Action::Pressed)
|
||||
{
|
||||
mCachedColor = mBackgroundColor;
|
||||
setBackgroundColor(mClickedColor);
|
||||
if(mClickFunc)
|
||||
{
|
||||
mClickFunc(this);
|
||||
}
|
||||
}
|
||||
else if(event->getAction() == MouseEvent::Action::Released)
|
||||
{
|
||||
setBackgroundColor(mCachedColor);
|
||||
}
|
||||
}
|
||||
|
||||
bool Button::isDirty() const
|
||||
{
|
||||
return Widget::isDirty() || mContentDirty;
|
||||
}
|
||||
|
||||
void Button::doPaint(const PaintEvent* event)
|
||||
{
|
||||
updateBackground(event);
|
||||
updateLabel(event);
|
||||
}
|
||||
|
||||
void Button::updateLabel(const PaintEvent* event)
|
||||
{
|
||||
unsigned fontOffset = unsigned(mLabel.size()) * 4;
|
||||
auto middle = DiscretePoint(mLocation.getX() + mSize.mWidth/2 - fontOffset, mLocation.getY() + mSize.mHeight/2 + 4);
|
||||
|
||||
if (!mTextNode)
|
||||
{
|
||||
mTextNode = TextNode::Create(mLabel, middle);
|
||||
mTextNode->setName(mName + "_TextNode");
|
||||
mTextNode->setContent(mLabel);
|
||||
mTextNode->setWidth(mSize.mWidth);
|
||||
mTextNode->setHeight(mSize.mHeight);
|
||||
mRootNode->addChild(mTextNode.get());
|
||||
}
|
||||
|
||||
if (mTransformDirty)
|
||||
{
|
||||
mTextNode->setLocation(middle);
|
||||
mTextNode->setWidth(mSize.mWidth);
|
||||
mTextNode->setHeight(mSize.mHeight);
|
||||
}
|
||||
|
||||
if (mMaterialDirty)
|
||||
{
|
||||
mTextNode->setFillColor(mBackgroundColor);
|
||||
}
|
||||
|
||||
if (mContentDirty)
|
||||
{
|
||||
mTextNode->setContent(mLabel);
|
||||
mContentDirty = false;
|
||||
}
|
||||
|
||||
if (mVisibilityDirty)
|
||||
{
|
||||
mTextNode->setIsVisible(mVisible);
|
||||
}
|
||||
}
|
46
src/ui/ui_controls/Button.h
Normal file
46
src/ui/ui_controls/Button.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
#include "Color.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
class PaintEvent;
|
||||
class MouseEvent;
|
||||
class TextNode;
|
||||
|
||||
class Button : public Widget
|
||||
{
|
||||
public:
|
||||
using clickFunc = std::function<void(Widget* self)>;
|
||||
|
||||
Button();
|
||||
|
||||
~Button();
|
||||
|
||||
static std::unique_ptr<Button> Create();
|
||||
|
||||
void setLabel(const std::string& text);
|
||||
|
||||
void setOnClickFunction(clickFunc func);
|
||||
|
||||
protected:
|
||||
void onMyMouseEvent(const MouseEvent* event) override;
|
||||
|
||||
bool isDirty() const override;
|
||||
void doPaint(const PaintEvent* event) override;
|
||||
|
||||
void updateLabel(const PaintEvent* event);
|
||||
|
||||
private:
|
||||
std::string mLabel;
|
||||
clickFunc mClickFunc;
|
||||
Color mCachedColor;
|
||||
Color mClickedColor;
|
||||
|
||||
std::unique_ptr<TextNode> mTextNode;
|
||||
bool mContentDirty{true};
|
||||
};
|
||||
|
||||
using ButtonUPtr = std::unique_ptr<Button>;
|
0
src/ui/ui_controls/ButtonGroup.cpp
Normal file
0
src/ui/ui_controls/ButtonGroup.cpp
Normal file
23
src/ui/ui_controls/ButtonGroup.h
Normal file
23
src/ui/ui_controls/ButtonGroup.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
class ButtonGroup : public Widget
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Orientation
|
||||
{
|
||||
HORIZONTAL,
|
||||
VERTICAL
|
||||
};
|
||||
|
||||
ButtonGroup();
|
||||
|
||||
~ButtonGroup();
|
||||
|
||||
static std::unique_ptr<ButtonGroup> Create();
|
||||
|
||||
private:
|
||||
bool mExclusiveActivation{true};
|
||||
};
|
32
src/ui/ui_controls/CMakeLists.txt
Normal file
32
src/ui/ui_controls/CMakeLists.txt
Normal file
|
@ -0,0 +1,32 @@
|
|||
set(MODULE_NAME ui_controls)
|
||||
|
||||
list(APPEND HEADERS
|
||||
Button.h
|
||||
ButtonGroup.h
|
||||
Label.h
|
||||
HorizontalSpacer.h
|
||||
VerticalSpacer.h
|
||||
StackWidget.h
|
||||
TextBox.h
|
||||
)
|
||||
|
||||
list(APPEND LIB_INCLUDES
|
||||
Button.cpp
|
||||
ButtonGroup.cpp
|
||||
Label.cpp
|
||||
HorizontalSpacer.cpp
|
||||
VerticalSpacer.cpp
|
||||
StackWidget.cpp
|
||||
TextBox.cpp
|
||||
)
|
||||
|
||||
add_library(${MODULE_NAME} SHARED ${LIB_INCLUDES} ${HEADERS})
|
||||
|
||||
target_include_directories(${MODULE_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/
|
||||
)
|
||||
target_link_libraries(${MODULE_NAME} PUBLIC ui_elements)
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/ui)
|
||||
|
||||
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
54
src/ui/ui_controls/HorizontalSpacer.cpp
Normal file
54
src/ui/ui_controls/HorizontalSpacer.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include "HorizontalSpacer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <iostream>
|
||||
|
||||
HorizontalSpacer::HorizontalSpacer()
|
||||
: Widget(),
|
||||
mScales()
|
||||
{
|
||||
mName = "HorizontalSpacer";
|
||||
}
|
||||
|
||||
std::unique_ptr<HorizontalSpacer> HorizontalSpacer::Create()
|
||||
{
|
||||
return std::make_unique<HorizontalSpacer>();
|
||||
}
|
||||
|
||||
void HorizontalSpacer::addWidget(WidgetUPtr widget)
|
||||
{
|
||||
addWidgetWithScale(std::move(widget), 1.0);
|
||||
}
|
||||
|
||||
void HorizontalSpacer::addWidgetWithScale(WidgetUPtr widget, double scale)
|
||||
{
|
||||
Widget::addWidget(std::move(widget));
|
||||
mScales.push_back(scale);
|
||||
}
|
||||
|
||||
void HorizontalSpacer::updateChildLocations()
|
||||
{
|
||||
double scaleSum = std::accumulate(mScales.begin(), mScales.end(), 0.0);
|
||||
double offset = 0;
|
||||
double height = mSize.mHeight;
|
||||
if (mSize.mMaxHeight > 0 && height > mSize.mMaxHeight)
|
||||
{
|
||||
height = mSize.mMaxHeight;
|
||||
}
|
||||
|
||||
for(std::size_t idx=0; idx<mChildren.size(); idx++)
|
||||
{
|
||||
auto& child = mChildren[idx];
|
||||
double scale = mScales[idx];
|
||||
double delta = height * (scale/scaleSum);
|
||||
auto size = child->getSize();
|
||||
if (size.mMaxHeight > 0 && delta > size.mMaxHeight)
|
||||
{
|
||||
delta = size.mMaxHeight;
|
||||
}
|
||||
child->setBounds(mSize.mWidth, unsigned(delta));
|
||||
child->setLocation(DiscretePoint(mLocation.getX(), mLocation.getY() + unsigned(offset)));
|
||||
offset += delta;
|
||||
}
|
||||
}
|
21
src/ui/ui_controls/HorizontalSpacer.h
Normal file
21
src/ui/ui_controls/HorizontalSpacer.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
#include <vector>
|
||||
|
||||
class HorizontalSpacer : public Widget
|
||||
{
|
||||
public:
|
||||
HorizontalSpacer();
|
||||
|
||||
static std::unique_ptr<HorizontalSpacer> Create();
|
||||
|
||||
void addWidget(WidgetUPtr widget) override;
|
||||
|
||||
void addWidgetWithScale(WidgetUPtr widget, double scale);
|
||||
private:
|
||||
void updateChildLocations() override;
|
||||
std::vector<double> mScales;
|
||||
};
|
||||
|
||||
using HorizontalSpacerUPtr = std::unique_ptr<HorizontalSpacer>;
|
74
src/ui/ui_controls/Label.cpp
Normal file
74
src/ui/ui_controls/Label.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include "Label.h"
|
||||
|
||||
#include "TextNode.h"
|
||||
#include "TransformNode.h"
|
||||
#include "GeometryNode.h"
|
||||
|
||||
Label::Label()
|
||||
: Widget(),
|
||||
mLabel()
|
||||
{
|
||||
mName = "Label";
|
||||
}
|
||||
|
||||
std::unique_ptr<Label> Label::Create()
|
||||
{
|
||||
return std::make_unique<Label>();
|
||||
}
|
||||
|
||||
void Label::setLabel(const std::string& text)
|
||||
{
|
||||
if (text != mLabel)
|
||||
{
|
||||
mLabel = text;
|
||||
mContentDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Label::isDirty() const
|
||||
{
|
||||
return Widget::isDirty() || mContentDirty;
|
||||
}
|
||||
|
||||
void Label::doPaint(const PaintEvent* event)
|
||||
{
|
||||
updateBackground(event);
|
||||
updateLabel(event);
|
||||
}
|
||||
|
||||
void Label::updateLabel(const PaintEvent* event)
|
||||
{
|
||||
unsigned fontOffset = unsigned(mLabel.size()) * 4;
|
||||
auto middle = DiscretePoint(mLocation.getX() + mSize.mWidth/2 - fontOffset, mLocation.getY() + mSize.mHeight/2 + 4);
|
||||
|
||||
if (!mTextNode)
|
||||
{
|
||||
mTextNode = TextNode::Create(mLabel, middle);
|
||||
mTextNode->setWidth(mSize.mWidth);
|
||||
mTextNode->setHeight(mSize.mHeight);
|
||||
mRootNode->addChild(mTextNode.get());
|
||||
}
|
||||
|
||||
if (mMaterialDirty)
|
||||
{
|
||||
mTextNode->setFillColor(mBackgroundColor);
|
||||
}
|
||||
|
||||
if (mTransformDirty)
|
||||
{
|
||||
mTextNode->setLocation(middle);
|
||||
mTextNode->setWidth(mSize.mWidth);
|
||||
mTextNode->setHeight(mSize.mHeight);
|
||||
}
|
||||
|
||||
if (mContentDirty)
|
||||
{
|
||||
mTextNode->setContent(mLabel);
|
||||
mContentDirty = false;
|
||||
}
|
||||
|
||||
if (mVisibilityDirty)
|
||||
{
|
||||
mTextNode->setIsVisible(mVisible);
|
||||
}
|
||||
}
|
34
src/ui/ui_controls/Label.h
Normal file
34
src/ui/ui_controls/Label.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class TextNode;
|
||||
|
||||
class Label : public Widget
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Label();
|
||||
|
||||
virtual ~Label() = default;
|
||||
|
||||
static std::unique_ptr<Label> Create();
|
||||
|
||||
void setLabel(const std::string& text);
|
||||
|
||||
private:
|
||||
bool isDirty() const override;
|
||||
void doPaint(const PaintEvent* event) override;
|
||||
|
||||
void updateLabel(const PaintEvent* event);
|
||||
|
||||
std::string mLabel;
|
||||
std::unique_ptr<TextNode> mTextNode;
|
||||
bool mContentDirty{true};
|
||||
|
||||
};
|
||||
|
||||
using LabelUPtr = std::unique_ptr<Label>;
|
28
src/ui/ui_controls/StackWidget.cpp
Normal file
28
src/ui/ui_controls/StackWidget.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include "StackWidget.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
StackWidget::StackWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<StackWidget> StackWidget::Create()
|
||||
{
|
||||
return std::make_unique<StackWidget>();
|
||||
}
|
||||
|
||||
void StackWidget::showChild(Widget* target)
|
||||
{
|
||||
for(auto& child : mChildren)
|
||||
{
|
||||
if(child.get() == target)
|
||||
{
|
||||
child->setVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
child->setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
15
src/ui/ui_controls/StackWidget.h
Normal file
15
src/ui/ui_controls/StackWidget.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
class StackWidget : public Widget
|
||||
{
|
||||
public:
|
||||
StackWidget();
|
||||
|
||||
static std::unique_ptr<StackWidget> Create();
|
||||
|
||||
void showChild(Widget* child);
|
||||
};
|
||||
|
||||
using StackWidgetUPtr = std::unique_ptr<StackWidget>;
|
113
src/ui/ui_controls/TextBox.cpp
Normal file
113
src/ui/ui_controls/TextBox.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
#include "TextBox.h"
|
||||
|
||||
#include "TextNode.h"
|
||||
#include "GeometryNode.h"
|
||||
#include "KeyboardEvent.h"
|
||||
#include "TransformNode.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
TextBox::TextBox()
|
||||
: Widget(),
|
||||
mContent(),
|
||||
mCaps(false)
|
||||
{
|
||||
mBackgroundColor = Color(250, 250, 250);
|
||||
mPadding = {20, 0, 20, 0};
|
||||
}
|
||||
|
||||
std::unique_ptr<TextBox> TextBox::Create()
|
||||
{
|
||||
return std::make_unique<TextBox>();
|
||||
}
|
||||
|
||||
void TextBox::setContent(const std::string& text)
|
||||
{
|
||||
mContent = text;
|
||||
mContentDirty = true;
|
||||
}
|
||||
|
||||
std::string TextBox::getContent() const
|
||||
{
|
||||
return mContent;
|
||||
}
|
||||
|
||||
void TextBox::appendContent(const std::string& text)
|
||||
{
|
||||
mContent += text;
|
||||
mContentDirty = true;
|
||||
}
|
||||
|
||||
bool TextBox::onMyKeyboardEvent(const KeyboardEvent* event)
|
||||
{
|
||||
if(!event || !mVisible) return false;
|
||||
|
||||
if(event->isFunctionKey())
|
||||
{
|
||||
if (event->getFunction() == Keyboard::Function::ENTER)
|
||||
{
|
||||
appendContent("\n");
|
||||
}
|
||||
else if(event->getFunction() == Keyboard::Function::BACKSPACE)
|
||||
{
|
||||
mContent = mContent.substr(0, mContent.size()-1);
|
||||
mContentDirty = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto keyString = event->getKeyString();
|
||||
if (keyString.length() < 2)
|
||||
{
|
||||
appendContent(keyString);
|
||||
}
|
||||
else
|
||||
{
|
||||
appendContent("?");
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextBox::isDirty() const
|
||||
{
|
||||
return Widget::isDirty() || mContentDirty;
|
||||
}
|
||||
|
||||
void TextBox::doPaint(const PaintEvent* event)
|
||||
{
|
||||
updateBackground(event);
|
||||
updateLabel(event);
|
||||
}
|
||||
|
||||
void TextBox::updateLabel(const PaintEvent* event)
|
||||
{
|
||||
auto loc = DiscretePoint(mLocation.getX() + mPadding.mLeft, mLocation.getY() + mPadding.mTop + unsigned(0));
|
||||
|
||||
if (!mTextNode)
|
||||
{
|
||||
mTextNode = TextNode::Create(mContent, loc);
|
||||
mTextNode->setWidth(mSize.mWidth);
|
||||
mTextNode->setHeight(mSize.mHeight);
|
||||
mRootNode->addChild(mTextNode.get());
|
||||
}
|
||||
|
||||
if (mMaterialDirty)
|
||||
{
|
||||
mTextNode->setFillColor(mBackgroundColor);
|
||||
}
|
||||
|
||||
if (mTransformDirty)
|
||||
{
|
||||
mTextNode->setLocation(loc);
|
||||
mTextNode->setWidth(mSize.mWidth);
|
||||
mTextNode->setHeight(mSize.mHeight);
|
||||
}
|
||||
|
||||
if (mContentDirty)
|
||||
{
|
||||
mTextNode->setContent(mContent);
|
||||
mContentDirty = false;
|
||||
}
|
||||
}
|
38
src/ui/ui_controls/TextBox.h
Normal file
38
src/ui/ui_controls/TextBox.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class TextNode;
|
||||
|
||||
class TextBox : public Widget
|
||||
{
|
||||
public:
|
||||
TextBox();
|
||||
|
||||
static std::unique_ptr<TextBox> Create();
|
||||
|
||||
void setContent(const std::string& text);
|
||||
|
||||
std::string getContent() const;
|
||||
|
||||
void appendContent(const std::string& text);
|
||||
|
||||
//void onPaintEvent(const PaintEvent* event) override;
|
||||
|
||||
bool onMyKeyboardEvent(const KeyboardEvent* event) override;
|
||||
|
||||
private:
|
||||
bool isDirty() const override;
|
||||
void doPaint(const PaintEvent* event) override;
|
||||
|
||||
void updateLabel(const PaintEvent* event);
|
||||
|
||||
std::string mContent;
|
||||
std::unique_ptr<TextNode> mTextNode;
|
||||
bool mContentDirty{true};
|
||||
bool mCaps;
|
||||
};
|
||||
|
||||
using TextBoxUPtr = std::unique_ptr<TextBox>;
|
44
src/ui/ui_controls/VerticalSpacer.cpp
Normal file
44
src/ui/ui_controls/VerticalSpacer.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include "VerticalSpacer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
VerticalSpacer::VerticalSpacer()
|
||||
: Widget(),
|
||||
mScales()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<VerticalSpacer> VerticalSpacer::Create()
|
||||
{
|
||||
return std::make_unique<VerticalSpacer>();
|
||||
}
|
||||
|
||||
void VerticalSpacer::addWidget(WidgetUPtr widget)
|
||||
{
|
||||
addWidgetWithScale(std::move(widget), 1.0);
|
||||
}
|
||||
|
||||
void VerticalSpacer::addWidgetWithScale(WidgetUPtr widget, double scale)
|
||||
{
|
||||
Widget::addWidget(std::move(widget));
|
||||
mScales.push_back(scale);
|
||||
}
|
||||
|
||||
void VerticalSpacer::updateChildLocations()
|
||||
{
|
||||
double scaleSum = std::accumulate(mScales.begin(), mScales.end(), 0.0);
|
||||
double offset = 0;
|
||||
unsigned delta = mSize.mWidth / unsigned(mChildren.size());
|
||||
for(std::size_t idx=0; idx<mChildren.size(); idx++)
|
||||
{
|
||||
auto& child = mChildren[idx];
|
||||
double scale = mScales[idx];
|
||||
double delta = mSize.mWidth * (scale/scaleSum);
|
||||
child->setBounds(unsigned(delta), mSize.mHeight);
|
||||
child->setLocation(DiscretePoint(mLocation.getX() + unsigned(offset), mLocation.getY()));
|
||||
offset += delta;
|
||||
}
|
||||
}
|
||||
|
22
src/ui/ui_controls/VerticalSpacer.h
Normal file
22
src/ui/ui_controls/VerticalSpacer.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
class VerticalSpacer : public Widget
|
||||
{
|
||||
|
||||
public:
|
||||
VerticalSpacer();
|
||||
|
||||
static std::unique_ptr<VerticalSpacer> Create();
|
||||
|
||||
void addWidget(WidgetUPtr widget) override;
|
||||
|
||||
void addWidgetWithScale(WidgetUPtr widget, double scale);
|
||||
|
||||
private:
|
||||
void updateChildLocations() override;
|
||||
std::vector<double> mScales;
|
||||
};
|
||||
|
||||
using VerticalSpacerUPtr = std::unique_ptr<VerticalSpacer>;
|
43
src/ui/ui_elements/CMakeLists.txt
Normal file
43
src/ui/ui_elements/CMakeLists.txt
Normal file
|
@ -0,0 +1,43 @@
|
|||
set(MODULE_NAME ui_elements)
|
||||
|
||||
list(APPEND LIB_INCLUDES
|
||||
desktop_elements/Keyboard.h
|
||||
desktop_elements/Keyboard.cpp
|
||||
desktop_elements/IPlatformScreen.h
|
||||
desktop_elements/Screen.h
|
||||
desktop_elements/Screen.cpp
|
||||
desktop_elements/IPlatformWindow.h
|
||||
desktop_elements/Window.h
|
||||
desktop_elements/Window.cpp
|
||||
ui_events/KeyboardEvent.h
|
||||
ui_events/KeyboardEvent.cpp
|
||||
ui_events/MouseEvent.h
|
||||
ui_events/MouseEvent.cpp
|
||||
ui_events/UiEvent.h
|
||||
ui_events/UiEvent.cpp
|
||||
ui_events/PaintEvent.h
|
||||
ui_events/PaintEvent.cpp
|
||||
ui_events/ResizeEvent.h
|
||||
ui_events/ResizeEvent.cpp
|
||||
widgets/Widget.h
|
||||
widgets/Widget.cpp
|
||||
widgets/WidgetState.h
|
||||
widgets/WidgetState.cpp
|
||||
style/Theme.h
|
||||
style/Theme.cpp
|
||||
)
|
||||
|
||||
add_library(${MODULE_NAME} SHARED ${LIB_INCLUDES})
|
||||
|
||||
target_include_directories(${MODULE_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/widgets
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/style
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui_events
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/desktop_elements
|
||||
)
|
||||
target_link_libraries(${MODULE_NAME} PUBLIC core geometry graphics visual_elements image)
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/ui)
|
||||
|
||||
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
12
src/ui/ui_elements/desktop_elements/DisplayState.h
Normal file
12
src/ui/ui_elements/desktop_elements/DisplayState.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
namespace WindowState
|
||||
{
|
||||
enum class Display
|
||||
{
|
||||
NORMAL,
|
||||
MINIMIZED,
|
||||
MAXIMIZED,
|
||||
FULL_SCREEN
|
||||
};
|
||||
}
|
11
src/ui/ui_elements/desktop_elements/IPlatformScreen.h
Normal file
11
src/ui/ui_elements/desktop_elements/IPlatformScreen.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
class IPlatformScreen
|
||||
{
|
||||
public:
|
||||
virtual ~IPlatformScreen() = default;
|
||||
};
|
||||
|
||||
using IPlatformScreenPtr = std::unique_ptr<IPlatformScreen>;
|
41
src/ui/ui_elements/desktop_elements/IPlatformWindow.h
Normal file
41
src/ui/ui_elements/desktop_elements/IPlatformWindow.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace mt
|
||||
{
|
||||
class Screen;
|
||||
class Window;
|
||||
}
|
||||
|
||||
class IPlatformSurface
|
||||
{
|
||||
public:
|
||||
virtual ~IPlatformSurface() = default;
|
||||
virtual void beforePaint(mt::Screen* screen) = 0;
|
||||
virtual void afterPaint(mt::Screen* screen) = 0;
|
||||
};
|
||||
|
||||
class IPlatformWindow : public IPlatformSurface
|
||||
{
|
||||
public:
|
||||
IPlatformWindow(mt::Window* window)
|
||||
: mWindow(window)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~IPlatformWindow() = default;
|
||||
|
||||
virtual void show() = 0;
|
||||
|
||||
virtual void map() = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual void onResize(unsigned width, unsigned height) = 0;
|
||||
protected:
|
||||
mt::Window* mWindow{nullptr};
|
||||
};
|
||||
|
||||
using IPlatformWindowPtr = std::unique_ptr<IPlatformWindow>;
|
22
src/ui/ui_elements/desktop_elements/Keyboard.cpp
Normal file
22
src/ui/ui_elements/desktop_elements/Keyboard.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include "Keyboard.h"
|
||||
|
||||
Keyboard::Keyboard()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<Keyboard> Keyboard::Create()
|
||||
{
|
||||
return std::make_unique<Keyboard>();
|
||||
}
|
||||
|
||||
std::string Keyboard::getKeyString(KeyCode code)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
Keyboard::Function Keyboard::getFunction(KeyCode code)
|
||||
{
|
||||
return Function::UNSET;
|
||||
}
|
||||
|
34
src/ui/ui_elements/desktop_elements/Keyboard.h
Normal file
34
src/ui/ui_elements/desktop_elements/Keyboard.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class Keyboard
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Function
|
||||
{
|
||||
UNSET,
|
||||
ENTER,
|
||||
BACKSPACE,
|
||||
TAB
|
||||
};
|
||||
|
||||
using KeyCode = unsigned;
|
||||
using KeyState = unsigned;
|
||||
|
||||
public:
|
||||
Keyboard();
|
||||
|
||||
virtual ~Keyboard() = default;
|
||||
|
||||
static std::unique_ptr<Keyboard> Create();
|
||||
|
||||
virtual std::string getKeyString(KeyCode code);
|
||||
|
||||
virtual Function getFunction(KeyCode code);
|
||||
|
||||
};
|
||||
|
||||
using KeyboardUPtr = std::unique_ptr<Keyboard>;
|
34
src/ui/ui_elements/desktop_elements/Screen.cpp
Normal file
34
src/ui/ui_elements/desktop_elements/Screen.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
#include "Screen.h"
|
||||
|
||||
#include "IPlatformScreen.h"
|
||||
|
||||
namespace mt{
|
||||
Screen::Screen()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Screen::~Screen()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<Screen> Screen::Create()
|
||||
{
|
||||
return std::make_unique<Screen>();
|
||||
}
|
||||
|
||||
IPlatformScreen* Screen::GetPlatformScreen() const
|
||||
{
|
||||
if (mPlatformScreen)
|
||||
{
|
||||
return mPlatformScreen.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Screen::SetPlatformScreen(IPlatformScreenPtr screen)
|
||||
{
|
||||
mPlatformScreen = std::move(screen);
|
||||
}
|
||||
}
|
29
src/ui/ui_elements/desktop_elements/Screen.h
Normal file
29
src/ui/ui_elements/desktop_elements/Screen.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
class IPlatformScreen;
|
||||
using IPlatformScreenPtr = std::unique_ptr<IPlatformScreen>;
|
||||
|
||||
namespace mt{
|
||||
class Screen
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Screen();
|
||||
|
||||
~Screen();
|
||||
|
||||
static std::unique_ptr<Screen> Create();
|
||||
|
||||
IPlatformScreen* GetPlatformScreen() const;
|
||||
|
||||
void SetPlatformScreen(IPlatformScreenPtr screen);
|
||||
|
||||
private:
|
||||
|
||||
IPlatformScreenPtr mPlatformScreen {nullptr};
|
||||
};
|
||||
}
|
||||
using ScreenPtr = std::unique_ptr<mt::Screen>;
|
221
src/ui/ui_elements/desktop_elements/Window.cpp
Normal file
221
src/ui/ui_elements/desktop_elements/Window.cpp
Normal file
|
@ -0,0 +1,221 @@
|
|||
#include "Window.h"
|
||||
|
||||
#include "PaintEvent.h"
|
||||
#include "MouseEvent.h"
|
||||
#include "KeyboardEvent.h"
|
||||
|
||||
#include "Widget.h"
|
||||
#include "Scene.h"
|
||||
#include "TriMesh.h"
|
||||
#include "RootNode.h"
|
||||
#include "TransformNode.h"
|
||||
#include "AbstractPainter.h"
|
||||
|
||||
#include "DrawingContext.h"
|
||||
#include "FontsManager.h"
|
||||
|
||||
#include "IPlatformWindow.h"
|
||||
#include "Screen.h"
|
||||
#include "Image.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace mt
|
||||
{
|
||||
|
||||
Window::Window(DrawingMode drawingMode, FontsManager* fontsManager)
|
||||
: DrawingSurface(),
|
||||
mWidget(Widget::Create())
|
||||
{
|
||||
mWidth = 800;
|
||||
mHeight = 600;
|
||||
mWidget->setBounds(mWidth, mHeight);
|
||||
mWidget->setWindow(this);
|
||||
|
||||
mDrawingContext = std::make_unique<DrawingContext>(this, fontsManager, drawingMode);
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<Window> Window::Create(DrawingMode drawingMode, FontsManager* fontsManager)
|
||||
{
|
||||
return std::make_unique<Window>(drawingMode, fontsManager);
|
||||
}
|
||||
|
||||
void Window::setIsSizingOnGoing(bool sizingOngoing)
|
||||
{
|
||||
mSizingOngoing = sizingOngoing;
|
||||
}
|
||||
|
||||
bool Window::getIsSizingOnGoing() const
|
||||
{
|
||||
return mSizingOngoing;
|
||||
}
|
||||
|
||||
void Window::setSize(unsigned width, unsigned height, bool triggerResize)
|
||||
{
|
||||
if (width == mWidth && height == mHeight)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DrawingSurface::setSize(width, height);
|
||||
if (triggerResize && !mSizingOngoing)
|
||||
{
|
||||
onResize();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::onResize()
|
||||
{
|
||||
mWidget->setBounds(mWidth, mHeight);
|
||||
|
||||
if (mPlatformWindow)
|
||||
{
|
||||
mPlatformWindow->onResize(mWidth, mHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::clearPlatformWindow()
|
||||
{
|
||||
mPlatformWindow.reset();
|
||||
}
|
||||
|
||||
void Window::onMouseEvent(const MouseEvent* event)
|
||||
{
|
||||
mWidget->onMouseEvent(event);
|
||||
}
|
||||
|
||||
void Window::onKeyboardEvent(const KeyboardEvent* event)
|
||||
{
|
||||
mWidget->onKeyboardEvent(event);
|
||||
}
|
||||
|
||||
void Window::onPaint(const PaintEvent* event)
|
||||
{
|
||||
mWidget->onPaintEvent(event);
|
||||
}
|
||||
|
||||
void Window::setWidget(WidgetPtr widget)
|
||||
{
|
||||
if (mWidget)
|
||||
{
|
||||
mWidget.reset();
|
||||
}
|
||||
mWidget = std::move(widget);
|
||||
mWidget->setBounds(mWidth, mHeight);
|
||||
mWidget->setWindow(this);
|
||||
}
|
||||
|
||||
IPlatformWindow* Window::getPlatformWindow() const
|
||||
{
|
||||
if (mPlatformWindow)
|
||||
{
|
||||
return mPlatformWindow.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Window::setPlatformWindow(IPlatformWindowPtr window)
|
||||
{
|
||||
mPlatformWindow = std::move(window);
|
||||
}
|
||||
|
||||
void Window::map()
|
||||
{
|
||||
if (mPlatformWindow)
|
||||
{
|
||||
mPlatformWindow->map();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::show()
|
||||
{
|
||||
if (mPlatformWindow)
|
||||
{
|
||||
mPlatformWindow->show();
|
||||
}
|
||||
}
|
||||
|
||||
DrawingContext* Window::getDrawingContent() const
|
||||
{
|
||||
return mDrawingContext.get();
|
||||
}
|
||||
|
||||
void Window::doPaint(mt::Screen* screen)
|
||||
{
|
||||
if (mPlatformWindow)
|
||||
{
|
||||
mPlatformWindow->beforePaint(screen);
|
||||
|
||||
if (auto scene = getScene(); scene->isEmpty())
|
||||
{
|
||||
scene->addNode(mWidget->getRootNode());
|
||||
}
|
||||
|
||||
mDrawingContext->paint();
|
||||
|
||||
mPlatformWindow->afterPaint(screen);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::clear()
|
||||
{
|
||||
if (mPlatformWindow)
|
||||
{
|
||||
mPlatformWindow->clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool Window::isDirty() const
|
||||
{
|
||||
return mWidget->needsUpdate();
|
||||
}
|
||||
|
||||
void Window::setDisplayState(WindowState::Display state)
|
||||
{
|
||||
mDisplayState = state;
|
||||
}
|
||||
|
||||
WindowState::Display Window::getDisplayState() const
|
||||
{
|
||||
return mDisplayState;
|
||||
}
|
||||
|
||||
void Window::setTitle(const std::string& title)
|
||||
{
|
||||
mTitle = title;
|
||||
}
|
||||
|
||||
const std::string& Window::getTitle() const
|
||||
{
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
void Window::addPopup(std::unique_ptr<Widget> popupWidget)
|
||||
{
|
||||
if (mPopupFunc)
|
||||
{
|
||||
mPopupFunc(this, std::move(popupWidget));
|
||||
}
|
||||
}
|
||||
|
||||
void Window::setPopupHandler(onPopupFunc func)
|
||||
{
|
||||
mPopupFunc = func;
|
||||
}
|
||||
|
||||
void Window::setParent(Window* parent)
|
||||
{
|
||||
mParent = parent;
|
||||
}
|
||||
|
||||
Window* Window::getParent() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
}
|
107
src/ui/ui_elements/desktop_elements/Window.h
Normal file
107
src/ui/ui_elements/desktop_elements/Window.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
#pragma once
|
||||
|
||||
#include "DrawingSurface.h"
|
||||
#include "DisplayState.h"
|
||||
#include "DrawingContext.h"
|
||||
#include "Widget.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
class PaintEvent;
|
||||
class MouseEvent;
|
||||
class KeyboardEvent;
|
||||
|
||||
class DrawingContext;
|
||||
class FontsManager;
|
||||
enum class DrawingMode;
|
||||
|
||||
using WidgetPtr = std::unique_ptr<Widget>;
|
||||
class IPlatformWindow;
|
||||
using IPlatformWindowPtr = std::unique_ptr<IPlatformWindow>;
|
||||
|
||||
namespace mt
|
||||
{
|
||||
|
||||
class Screen;
|
||||
|
||||
class Window : public DrawingSurface
|
||||
{
|
||||
|
||||
public:
|
||||
using onPopupFunc = std::function<void(mt::Window* parent, std::unique_ptr<Widget> popup)>;
|
||||
|
||||
Window(DrawingMode drawingMode = DrawingMode::GRAPH, FontsManager* fontsManager = nullptr);
|
||||
|
||||
~Window();
|
||||
|
||||
static std::unique_ptr<Window> Create(DrawingMode drawingMode = DrawingMode::GRAPH, FontsManager* fontsManager = nullptr);
|
||||
|
||||
void addPopup(std::unique_ptr<Widget> popupWidget);
|
||||
|
||||
void clear();
|
||||
|
||||
void clearPlatformWindow();
|
||||
|
||||
void doPaint(mt::Screen* screen);
|
||||
|
||||
IPlatformWindow* getPlatformWindow() const;
|
||||
|
||||
const std::string& getTitle() const;
|
||||
|
||||
Window* getParent() const;
|
||||
|
||||
DrawingContext* getDrawingContent() const;
|
||||
|
||||
WindowState::Display getDisplayState() const;
|
||||
|
||||
bool getIsSizingOnGoing() const;
|
||||
|
||||
bool isDirty() const;
|
||||
|
||||
void map();
|
||||
|
||||
void onPaint(const PaintEvent* event);
|
||||
|
||||
void onMouseEvent(const MouseEvent* event);
|
||||
|
||||
void onResize();
|
||||
|
||||
void onKeyboardEvent(const KeyboardEvent* event);
|
||||
|
||||
void setPlatformWindow(IPlatformWindowPtr window);
|
||||
|
||||
void setPopupHandler(onPopupFunc func);
|
||||
|
||||
void setParent(Window* parent);
|
||||
|
||||
void show();
|
||||
|
||||
void setIsSizingOnGoing(bool sizingOngoing);
|
||||
|
||||
void setSize(unsigned width, unsigned height, bool triggerResize = true) override;
|
||||
|
||||
void setTitle(const std::string& title);
|
||||
|
||||
void setWidget(WidgetPtr widget);
|
||||
|
||||
void setDisplayState(WindowState::Display state);
|
||||
|
||||
private:
|
||||
WidgetPtr mWidget {nullptr};
|
||||
std::string mTitle;
|
||||
IPlatformWindowPtr mPlatformWindow {nullptr};
|
||||
std::unique_ptr<DrawingContext> mDrawingContext;
|
||||
|
||||
onPopupFunc mPopupFunc;
|
||||
Window* mParent{nullptr};
|
||||
|
||||
bool mSizingOngoing{ false };
|
||||
WindowState::Display mDisplayState{ WindowState::Display::NORMAL };
|
||||
};
|
||||
}
|
||||
|
||||
using WindowUPtr = std::unique_ptr<mt::Window>;
|
26
src/ui/ui_elements/style/Theme.cpp
Normal file
26
src/ui/ui_elements/style/Theme.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include "Theme.h"
|
||||
|
||||
Color Theme::getBackgroundPrimary()
|
||||
{
|
||||
return {245, 245, 245};
|
||||
}
|
||||
|
||||
Color Theme::getBannerBackground()
|
||||
{
|
||||
return {181, 189, 200};
|
||||
}
|
||||
|
||||
Color Theme::getButtonPrimaryBackground()
|
||||
{
|
||||
return {200, 200, 200};
|
||||
}
|
||||
|
||||
Color Theme::getButtonPrimaryPressed()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
Color Theme::getTextPrimary()
|
||||
{
|
||||
return {};
|
||||
}
|
15
src/ui/ui_elements/style/Theme.h
Normal file
15
src/ui/ui_elements/style/Theme.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include "Color.h"
|
||||
|
||||
class Theme
|
||||
{
|
||||
public:
|
||||
static Color getBackgroundPrimary();
|
||||
|
||||
static Color getBannerBackground();
|
||||
|
||||
static Color getButtonPrimaryBackground();
|
||||
|
||||
static Color getButtonPrimaryPressed();
|
||||
|
||||
static Color getTextPrimary();
|
||||
};
|
54
src/ui/ui_elements/ui_events/KeyboardEvent.cpp
Normal file
54
src/ui/ui_elements/ui_events/KeyboardEvent.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include "KeyboardEvent.h"
|
||||
|
||||
KeyboardEvent::KeyboardEvent()
|
||||
: UiEvent(),
|
||||
mAction(),
|
||||
mKeyString()
|
||||
{
|
||||
mType = UiEvent::Type::Keyboard;
|
||||
}
|
||||
|
||||
KeyboardEvent::~KeyboardEvent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<KeyboardEvent> KeyboardEvent::Create()
|
||||
{
|
||||
return std::make_unique<KeyboardEvent>();
|
||||
}
|
||||
|
||||
void KeyboardEvent::setKeyString(const std::string& key)
|
||||
{
|
||||
mKeyString = key;
|
||||
}
|
||||
|
||||
std::string KeyboardEvent::getKeyString() const
|
||||
{
|
||||
return mKeyString;
|
||||
}
|
||||
|
||||
void KeyboardEvent::setAction(Action action)
|
||||
{
|
||||
mAction = action;
|
||||
}
|
||||
|
||||
KeyboardEvent::Action KeyboardEvent::getAction() const
|
||||
{
|
||||
return mAction;
|
||||
}
|
||||
|
||||
bool KeyboardEvent::isFunctionKey() const
|
||||
{
|
||||
return mFunction != Keyboard::Function::UNSET;
|
||||
}
|
||||
|
||||
Keyboard::Function KeyboardEvent::getFunction() const
|
||||
{
|
||||
return mFunction;
|
||||
}
|
||||
|
||||
void KeyboardEvent::setFunction(Keyboard::Function function)
|
||||
{
|
||||
mFunction = function;
|
||||
}
|
47
src/ui/ui_elements/ui_events/KeyboardEvent.h
Normal file
47
src/ui/ui_elements/ui_events/KeyboardEvent.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "UiEvent.h"
|
||||
#include "Keyboard.h"
|
||||
|
||||
class KeyboardEvent : public UiEvent
|
||||
{
|
||||
public:
|
||||
enum class Action
|
||||
{
|
||||
Pressed,
|
||||
Released
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
KeyboardEvent();
|
||||
|
||||
~KeyboardEvent();
|
||||
|
||||
static std::unique_ptr<KeyboardEvent> Create();
|
||||
|
||||
void setKeyString(const std::string& key);
|
||||
|
||||
std::string getKeyString() const;
|
||||
|
||||
void setAction(Action action);
|
||||
|
||||
Action getAction() const;
|
||||
|
||||
bool isFunctionKey() const;
|
||||
|
||||
Keyboard::Function getFunction() const;
|
||||
|
||||
void setFunction(Keyboard::Function function);
|
||||
|
||||
private:
|
||||
|
||||
Keyboard::Function mFunction{Keyboard::Function::UNSET};
|
||||
Action mAction;
|
||||
std::string mKeyString;
|
||||
|
||||
};
|
||||
using KeyboardEventUPtr = std::unique_ptr<KeyboardEvent>;
|
51
src/ui/ui_elements/ui_events/MouseEvent.cpp
Normal file
51
src/ui/ui_elements/ui_events/MouseEvent.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "MouseEvent.h"
|
||||
|
||||
MouseEvent::MouseEvent()
|
||||
: UiEvent(),
|
||||
mClientLocation(0, 0),
|
||||
mScreenLocation(0, 0),
|
||||
mAction()
|
||||
{
|
||||
mType = UiEvent::Type::Mouse;
|
||||
}
|
||||
|
||||
MouseEvent::~MouseEvent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<MouseEvent> MouseEvent::Create()
|
||||
{
|
||||
return std::make_unique<MouseEvent>();
|
||||
}
|
||||
|
||||
void MouseEvent::setClientLocation(Pixel location)
|
||||
{
|
||||
mClientLocation = location;
|
||||
}
|
||||
|
||||
void MouseEvent::setScreenLocation(Pixel location)
|
||||
{
|
||||
mScreenLocation = location;
|
||||
}
|
||||
|
||||
void MouseEvent::setAction(MouseEvent::Action action)
|
||||
{
|
||||
mAction = action;
|
||||
}
|
||||
|
||||
Pixel MouseEvent::getClientLocation() const
|
||||
{
|
||||
return mClientLocation;
|
||||
}
|
||||
|
||||
Pixel MouseEvent::getScreenLocation() const
|
||||
{
|
||||
return mScreenLocation;
|
||||
}
|
||||
|
||||
MouseEvent::Action MouseEvent::getAction() const
|
||||
{
|
||||
return mAction;
|
||||
}
|
||||
|
42
src/ui/ui_elements/ui_events/MouseEvent.h
Normal file
42
src/ui/ui_elements/ui_events/MouseEvent.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "DiscretePoint.h"
|
||||
#include "UiEvent.h"
|
||||
|
||||
class MouseEvent : public UiEvent
|
||||
{
|
||||
public:
|
||||
enum class Action
|
||||
{
|
||||
Pressed,
|
||||
Released
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
MouseEvent();
|
||||
|
||||
~MouseEvent();
|
||||
|
||||
static std::unique_ptr<MouseEvent> Create();
|
||||
|
||||
Pixel getClientLocation() const;
|
||||
|
||||
Pixel getScreenLocation() const;
|
||||
|
||||
Action getAction() const;
|
||||
|
||||
void setClientLocation(Pixel location);
|
||||
|
||||
void setScreenLocation(Pixel location);
|
||||
|
||||
void setAction(Action action);
|
||||
|
||||
private:
|
||||
Pixel mClientLocation;
|
||||
Pixel mScreenLocation;
|
||||
Action mAction;
|
||||
};
|
||||
using MouseEventUPtr = std::unique_ptr<MouseEvent>;
|
18
src/ui/ui_elements/ui_events/PaintEvent.cpp
Normal file
18
src/ui/ui_elements/ui_events/PaintEvent.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include "PaintEvent.h"
|
||||
|
||||
PaintEvent::PaintEvent()
|
||||
: UiEvent()
|
||||
{
|
||||
mType = UiEvent::Type::Paint;
|
||||
}
|
||||
|
||||
PaintEvent::~PaintEvent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<PaintEvent> PaintEvent::Create()
|
||||
{
|
||||
return std::make_unique<PaintEvent>();
|
||||
}
|
||||
|
16
src/ui/ui_elements/ui_events/PaintEvent.h
Normal file
16
src/ui/ui_elements/ui_events/PaintEvent.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "UiEvent.h"
|
||||
|
||||
class PaintEvent : public UiEvent
|
||||
{
|
||||
public:
|
||||
PaintEvent();
|
||||
|
||||
~PaintEvent();
|
||||
|
||||
static std::unique_ptr<PaintEvent> Create();
|
||||
};
|
||||
using PaintEventUPtr = std::unique_ptr<PaintEvent>;
|
20
src/ui/ui_elements/ui_events/ResizeEvent.cpp
Normal file
20
src/ui/ui_elements/ui_events/ResizeEvent.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include "ResizeEvent.h"
|
||||
|
||||
ResizeEvent::ResizeEvent(unsigned width, unsigned height)
|
||||
: UiEvent(),
|
||||
mWidth(width),
|
||||
mHeight(height)
|
||||
{
|
||||
mType = UiEvent::Type::Resize;
|
||||
}
|
||||
|
||||
ResizeEvent::~ResizeEvent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<ResizeEvent> ResizeEvent::Create(unsigned width, unsigned height)
|
||||
{
|
||||
return std::make_unique<ResizeEvent>(width, height);
|
||||
}
|
||||
|
30
src/ui/ui_elements/ui_events/ResizeEvent.h
Normal file
30
src/ui/ui_elements/ui_events/ResizeEvent.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "UiEvent.h"
|
||||
|
||||
class ResizeEvent : public UiEvent
|
||||
{
|
||||
public:
|
||||
ResizeEvent(unsigned width, unsigned height);
|
||||
|
||||
~ResizeEvent();
|
||||
|
||||
static std::unique_ptr<ResizeEvent> Create(unsigned width, unsigned height);
|
||||
|
||||
unsigned getWidth() const
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
unsigned getHeight() const
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned mWidth{0};
|
||||
unsigned mHeight{0};
|
||||
};
|
||||
using ResizeEventPtr = std::unique_ptr<ResizeEvent>;
|
23
src/ui/ui_elements/ui_events/UiEvent.cpp
Normal file
23
src/ui/ui_elements/ui_events/UiEvent.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "UiEvent.h"
|
||||
|
||||
UiEvent::UiEvent()
|
||||
: mType(Type::Unknown)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
UiEvent::~UiEvent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<UiEvent> UiEvent::Create()
|
||||
{
|
||||
return std::make_unique<UiEvent>();
|
||||
}
|
||||
|
||||
UiEvent::Type UiEvent::GetType() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
30
src/ui/ui_elements/ui_events/UiEvent.h
Normal file
30
src/ui/ui_elements/ui_events/UiEvent.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
class UiEvent
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Type{
|
||||
Unknown,
|
||||
Paint,
|
||||
Mouse,
|
||||
Keyboard,
|
||||
Resize
|
||||
};
|
||||
|
||||
protected:
|
||||
UiEvent::Type mType;
|
||||
|
||||
public:
|
||||
|
||||
UiEvent();
|
||||
|
||||
virtual ~UiEvent();
|
||||
|
||||
static std::unique_ptr<UiEvent> Create();
|
||||
|
||||
Type GetType() const;
|
||||
};
|
||||
using UiEventUPtr = std::unique_ptr<UiEvent>;
|
395
src/ui/ui_elements/widgets/Widget.cpp
Normal file
395
src/ui/ui_elements/widgets/Widget.cpp
Normal file
|
@ -0,0 +1,395 @@
|
|||
#include "Widget.h"
|
||||
|
||||
#include "RectangleNode.h"
|
||||
#include "MouseEvent.h"
|
||||
#include "KeyboardEvent.h"
|
||||
#include "PaintEvent.h"
|
||||
|
||||
#include "AbstractVisualNode.h"
|
||||
#include "TextNode.h"
|
||||
#include "TransformNode.h"
|
||||
#include "RootNode.h"
|
||||
|
||||
#include "Window.h"
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <iostream>
|
||||
|
||||
Widget::Widget()
|
||||
: mLocation(DiscretePoint(0, 0)),
|
||||
mSize({100, 0, 0, 100, 0, 0}),
|
||||
mPadding(),
|
||||
mMargin(),
|
||||
mRootNode(std::make_unique<TransformNode>()),
|
||||
mChildren(),
|
||||
mBorderThickness(0),
|
||||
mBackgroundColor(Color(255, 255, 255)),
|
||||
mBorderColor(Color(0, 0, 0)),
|
||||
mVisible(true)
|
||||
{
|
||||
mName = "Widget";
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<Widget> Widget::Create()
|
||||
{
|
||||
return std::make_unique<Widget>();
|
||||
}
|
||||
|
||||
void Widget::addWidget(WidgetUPtr widget)
|
||||
{
|
||||
widget->setParent(this);
|
||||
|
||||
mPendingChildNodes.push_back(widget->getRootNode());
|
||||
mChildren.push_back(std::move(widget));
|
||||
}
|
||||
|
||||
Widget::BoundedSize Widget::getSize() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
const DiscretePoint& Widget::getLocation() const
|
||||
{
|
||||
return mLocation;
|
||||
}
|
||||
|
||||
TransformNode* Widget::getRootNode() const
|
||||
{
|
||||
return mRootNode.get();
|
||||
}
|
||||
|
||||
void Widget::setSize(const BoundedSize& size)
|
||||
{
|
||||
if (size != mSize)
|
||||
{
|
||||
mSize = size;
|
||||
mTransformDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setMargin(unsigned margin)
|
||||
{
|
||||
setMargin({margin, margin, margin, margin});
|
||||
}
|
||||
|
||||
void Widget::setMargin(const BoundaryOffset& margin)
|
||||
{
|
||||
if (margin != mMargin)
|
||||
{
|
||||
mMargin = margin;
|
||||
mTransformDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setPadding(unsigned padding)
|
||||
{
|
||||
setPadding({padding, padding, padding, padding});
|
||||
}
|
||||
|
||||
void Widget::setPadding(const BoundaryOffset& padding)
|
||||
{
|
||||
if (padding != mPadding)
|
||||
{
|
||||
mPadding = padding;
|
||||
mTransformDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setBounds(unsigned width, unsigned height)
|
||||
{
|
||||
if (mSize.mMaxWidth > 0 && width > mSize.mMaxWidth)
|
||||
{
|
||||
width = mSize.mMaxWidth;
|
||||
}
|
||||
|
||||
if (mSize.mMaxHeight > 0 && height > mSize.mMaxHeight)
|
||||
{
|
||||
height = mSize.mMaxHeight;
|
||||
}
|
||||
|
||||
if (width != mSize.mWidth || height != mSize.mHeight)
|
||||
{
|
||||
mTransformDirty = true;
|
||||
mSize.mWidth = width;
|
||||
mSize.mHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setBackgroundColor(const Color& color)
|
||||
{
|
||||
if (mBackgroundColor != color)
|
||||
{
|
||||
mBackgroundColor = color;
|
||||
mMaterialDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setLocation(const DiscretePoint& loc)
|
||||
{
|
||||
if (mLocation != loc)
|
||||
{
|
||||
mLocation = loc;
|
||||
mTransformDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setVisible(bool visible)
|
||||
{
|
||||
if (mVisible != visible)
|
||||
{
|
||||
mVisibilityDirty = true;
|
||||
|
||||
mVisible = visible;
|
||||
|
||||
for (auto& child : mChildren)
|
||||
{
|
||||
child->setVisible(mVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Widget::isDirty() const
|
||||
{
|
||||
return mTransformDirty || mMaterialDirty || mVisibilityDirty || mPendingChildNodes.size() > 0;
|
||||
}
|
||||
|
||||
bool Widget::needsUpdate() const
|
||||
{
|
||||
if (isDirty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
for(auto& child: mChildren)
|
||||
{
|
||||
if (child->needsUpdate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Widget::setMaxWidth(unsigned maxWidth)
|
||||
{
|
||||
if (mSize.mMaxWidth != maxWidth)
|
||||
{
|
||||
mTransformDirty = true;
|
||||
mSize.mMaxWidth = maxWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::doPaint(const PaintEvent* event)
|
||||
{
|
||||
updateBackground(event);
|
||||
}
|
||||
|
||||
void Widget::onPaintEvent(const PaintEvent* event)
|
||||
{
|
||||
if (!needsUpdate())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDirty())
|
||||
{
|
||||
mRootNode->setName(mName + "_RootNode");
|
||||
|
||||
doPaint(event);
|
||||
|
||||
if (mVisibilityDirty)
|
||||
{
|
||||
mRootNode->setIsVisible(mVisible);
|
||||
}
|
||||
|
||||
mTransformDirty = false;
|
||||
mMaterialDirty = false;
|
||||
mVisibilityDirty = false;
|
||||
}
|
||||
|
||||
for (auto node : mPendingChildNodes)
|
||||
{
|
||||
mRootNode->addChild(node);
|
||||
}
|
||||
mPendingChildNodes.clear();
|
||||
|
||||
updateChildLocations();
|
||||
|
||||
for(auto& child: mChildren)
|
||||
{
|
||||
child->onPaintEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::updateChildLocations()
|
||||
{
|
||||
for(auto& child: mChildren)
|
||||
{
|
||||
child->setBounds(mSize.mWidth, mSize.mHeight);
|
||||
child->setLocation(mLocation);
|
||||
}
|
||||
}
|
||||
|
||||
bool Widget::contains(const DiscretePoint& loc) const
|
||||
{
|
||||
if(loc.getX() < mLocation.getX())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(loc.getX() > mLocation.getX() + mSize.mWidth)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(loc.getY() > mLocation.getY() + mSize.mHeight)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(loc.getY() < mLocation.getY())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Widget::onKeyboardEvent(const KeyboardEvent* event)
|
||||
{
|
||||
bool inChild = false;
|
||||
for(const auto& child : mChildren)
|
||||
{
|
||||
if(child->onKeyboardEvent(event))
|
||||
{
|
||||
inChild = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!inChild)
|
||||
{
|
||||
return onMyKeyboardEvent(event);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Widget::onMyKeyboardEvent(const KeyboardEvent* event)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Widget::onMouseEvent(const MouseEvent* event)
|
||||
{
|
||||
bool inChild = false;
|
||||
for(const auto& child : mChildren)
|
||||
{
|
||||
if(child->onMouseEvent(event))
|
||||
{
|
||||
inChild = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!inChild)
|
||||
{
|
||||
if(mVisible && contains(event->getClientLocation()))
|
||||
{
|
||||
onMyMouseEvent(event);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Widget::onMyMouseEvent(const MouseEvent* event)
|
||||
{
|
||||
MLOG_INFO("Widget mouse event");
|
||||
}
|
||||
|
||||
void Widget::updateBackground(const PaintEvent* event)
|
||||
{
|
||||
unsigned locX = mLocation.getX() + mMargin.mLeft;
|
||||
unsigned locY = mLocation.getY() + mMargin.mTop;
|
||||
unsigned deltaX = mSize.mWidth - mMargin.mLeft - mMargin.mRight;
|
||||
unsigned deltaY = mSize.mHeight - mMargin.mTop - mMargin.mBottom;
|
||||
|
||||
if (!mBackgroundNode)
|
||||
{
|
||||
mBackgroundNode = std::make_unique<RectangleNode>(DiscretePoint(locX, locY), deltaX, deltaY);
|
||||
mBackgroundNode->setName(mName + "_BackgroundNode");
|
||||
mRootNode->addChild(mBackgroundNode.get());
|
||||
}
|
||||
|
||||
if (mTransformDirty)
|
||||
{
|
||||
mBackgroundNode->setWidth(deltaX);
|
||||
mBackgroundNode->setHeight(deltaY);
|
||||
mBackgroundNode->setLocation(DiscretePoint(locX, locY));
|
||||
}
|
||||
|
||||
if (mMaterialDirty)
|
||||
{
|
||||
mBackgroundNode->setFillColor(mBackgroundColor);
|
||||
mBackgroundNode->setStrokeColor(mBorderColor);
|
||||
mBackgroundNode->setStrokeThickness(mBorderThickness);
|
||||
}
|
||||
|
||||
if (mVisibilityDirty)
|
||||
{
|
||||
mBackgroundNode->setIsVisible(mVisible);
|
||||
}
|
||||
}
|
||||
|
||||
mt::Window* Widget::getTopLevelWindow() const
|
||||
{
|
||||
if(mWindow)
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
std::cout << "I am " << getName() << std::endl;
|
||||
|
||||
auto lastParent = mParent;
|
||||
auto nextParent = mParent;
|
||||
while(nextParent)
|
||||
{
|
||||
lastParent = nextParent;
|
||||
nextParent = lastParent->getParent();
|
||||
std::cout << "Checking if " << lastParent->getName() << std::endl;
|
||||
if (nextParent)
|
||||
{
|
||||
std::cout << "Next is " << nextParent->getName() << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "no next" << std::endl;
|
||||
}
|
||||
}
|
||||
return lastParent->getTopLevelWindow();
|
||||
}
|
||||
|
||||
Widget* Widget::getParent() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
mt::Window* Widget::getWindow() const
|
||||
{
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
void Widget::setParent(Widget* parent)
|
||||
{
|
||||
mParent = parent;
|
||||
}
|
||||
|
||||
void Widget::setWindow(mt::Window* window)
|
||||
{
|
||||
mWindow = window;
|
||||
}
|
176
src/ui/ui_elements/widgets/Widget.h
Normal file
176
src/ui/ui_elements/widgets/Widget.h
Normal file
|
@ -0,0 +1,176 @@
|
|||
#pragma once
|
||||
|
||||
#include "DiscretePoint.h"
|
||||
#include "FontItem.h"
|
||||
#include "Color.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class MouseEvent;
|
||||
class KeyboardEvent;
|
||||
class PaintEvent;
|
||||
|
||||
class AbstractVisualNode;
|
||||
class TransformNode;
|
||||
class RectangleNode;
|
||||
|
||||
namespace mt
|
||||
{
|
||||
class Window;
|
||||
}
|
||||
|
||||
class Widget
|
||||
{
|
||||
public:
|
||||
struct BoundaryOffset
|
||||
{
|
||||
bool operator==(const BoundaryOffset& rhs) const
|
||||
{
|
||||
return (mLeft == rhs.mLeft)
|
||||
&& (mRight == rhs.mRight)
|
||||
&& (mTop == rhs.mTop)
|
||||
&& (mBottom == rhs.mBottom);
|
||||
}
|
||||
bool operator!=(const BoundaryOffset& rhs) const
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
unsigned mLeft = 0;
|
||||
unsigned mRight = 0;
|
||||
unsigned mTop = 0;
|
||||
unsigned mBottom = 0;
|
||||
};
|
||||
|
||||
struct BoundedSize
|
||||
{
|
||||
bool operator==(const BoundedSize& rhs) const
|
||||
{
|
||||
return (mWidth == rhs.mWidth)
|
||||
&& (mMaxWidth == rhs.mMaxWidth)
|
||||
&& (mMinWidth == rhs.mMinWidth)
|
||||
&& (mHeight == rhs.mHeight)
|
||||
&& (mMaxHeight == rhs.mMaxHeight)
|
||||
&& (mMinHeight == rhs.mMinHeight);
|
||||
}
|
||||
bool operator!=(const BoundedSize& rhs) const
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
unsigned mWidth = 0;
|
||||
unsigned mMaxWidth = 0;
|
||||
unsigned mMinWidth = 0;
|
||||
unsigned mHeight = 0;
|
||||
unsigned mMaxHeight = 0;
|
||||
unsigned mMinHeight = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Widget();
|
||||
|
||||
virtual ~Widget();
|
||||
|
||||
static std::unique_ptr<Widget> Create();
|
||||
|
||||
virtual void addWidget(std::unique_ptr<Widget> widget);
|
||||
|
||||
BoundedSize getSize() const;
|
||||
|
||||
TransformNode* getRootNode() const;
|
||||
|
||||
const DiscretePoint& getLocation() const;
|
||||
|
||||
virtual void onPaintEvent(const PaintEvent* event);
|
||||
|
||||
virtual bool onMouseEvent(const MouseEvent* event);
|
||||
|
||||
virtual bool onKeyboardEvent(const KeyboardEvent* event);
|
||||
|
||||
bool contains(const DiscretePoint& loc) const;
|
||||
|
||||
void setBackgroundColor(const Color& color);
|
||||
|
||||
void setBounds(unsigned width, unsigned height);
|
||||
|
||||
void setSize(const BoundedSize& size);
|
||||
|
||||
void setMaxWidth(unsigned maxWidth);
|
||||
|
||||
void setMargin(unsigned margin);
|
||||
|
||||
void setMargin(const BoundaryOffset& margin);
|
||||
|
||||
void setPadding(unsigned padding);
|
||||
|
||||
void setPadding(const BoundaryOffset& padding);
|
||||
|
||||
void setLocation(const DiscretePoint& loc);
|
||||
|
||||
void setVisible(bool visible);
|
||||
|
||||
void setName(const std::string& name)
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
const std::string& getName() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
bool needsUpdate() const;
|
||||
|
||||
void setWindow(mt::Window* window);
|
||||
|
||||
mt::Window* getTopLevelWindow() const;
|
||||
|
||||
protected:
|
||||
virtual bool onMyKeyboardEvent(const KeyboardEvent* event);
|
||||
|
||||
virtual void onMyMouseEvent(const MouseEvent* event);
|
||||
|
||||
virtual void updateBackground(const PaintEvent* event);
|
||||
|
||||
virtual void doPaint(const PaintEvent* event);
|
||||
|
||||
virtual void updateChildLocations();
|
||||
|
||||
virtual bool isDirty() const;
|
||||
|
||||
void setParent(Widget* parent);
|
||||
|
||||
Widget* getParent() const;
|
||||
|
||||
mt::Window* getWindow() const;
|
||||
|
||||
DiscretePoint mLocation;
|
||||
BoundedSize mSize;
|
||||
BoundaryOffset mPadding;
|
||||
BoundaryOffset mMargin;
|
||||
|
||||
std::unique_ptr<TransformNode> mRootNode;
|
||||
std::vector<std::unique_ptr<Widget> > mChildren;
|
||||
unsigned mBorderThickness{0};
|
||||
Color mBackgroundColor;
|
||||
Color mBorderColor;
|
||||
bool mVisible{true};
|
||||
|
||||
std::unique_ptr<RectangleNode> mBackgroundNode;
|
||||
|
||||
bool mTransformDirty{true};
|
||||
bool mMaterialDirty{true};
|
||||
bool mVisibilityDirty{true};
|
||||
|
||||
std::string mName;
|
||||
std::vector<TransformNode*> mPendingChildNodes;
|
||||
|
||||
FontItem mDefaultFont;
|
||||
Widget* mParent{nullptr};
|
||||
mt::Window* mWindow{nullptr};
|
||||
};
|
||||
|
||||
using WidgetUPtr = std::unique_ptr<Widget>;
|
0
src/ui/ui_elements/widgets/WidgetState.cpp
Normal file
0
src/ui/ui_elements/widgets/WidgetState.cpp
Normal file
0
src/ui/ui_elements/widgets/WidgetState.h
Normal file
0
src/ui/ui_elements/widgets/WidgetState.h
Normal file
20
src/ui/windows/AbstractDesktopApp.h
Normal file
20
src/ui/windows/AbstractDesktopApp.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "AbstractApp.h"
|
||||
|
||||
class AbstractUIInterface;
|
||||
|
||||
class AbstractDesktopApp
|
||||
{
|
||||
public:
|
||||
AbstractDesktopApp() = default;
|
||||
virtual ~AbstractDesktopApp() = default;
|
||||
|
||||
virtual AbstractApp* getMainApplication() const = 0;
|
||||
|
||||
virtual AbstractUIInterface* getUiInterface() const = 0;
|
||||
};
|
||||
|
||||
using AbstractDesktopAppPtr = std::shared_ptr<AbstractDesktopApp>;
|
112
src/ui/windows/CMakeLists.txt
Normal file
112
src/ui/windows/CMakeLists.txt
Normal file
|
@ -0,0 +1,112 @@
|
|||
set(MODULE_NAME windows)
|
||||
|
||||
set (platform_INCLUDES "")
|
||||
set (platform_LIBS "")
|
||||
|
||||
if(UNIX)
|
||||
message(STATUS "Checking dependencies for module: window")
|
||||
find_package(X11 QUIET)
|
||||
if(X11_FOUND)
|
||||
list(APPEND platform_INCLUDES
|
||||
ui_interfaces/x11/XcbInterface.cpp
|
||||
ui_interfaces/x11/XcbEventInterface.cpp
|
||||
ui_interfaces/x11/XcbWindow.cpp
|
||||
ui_interfaces/x11/XcbScreen.cpp
|
||||
ui_interfaces/x11/XcbImage.cpp
|
||||
ui_interfaces/x11/XcbTextInterface.cpp
|
||||
ui_interfaces/x11/XcbKeyboard.cpp
|
||||
ui_interfaces/x11/XcbGlInterface.cpp
|
||||
ui_interfaces/x11/XcbExtensionInterface.cpp
|
||||
ui_interfaces/x11/XcbGlWindowInterface.cpp
|
||||
)
|
||||
list(APPEND platform_LIBS ${X11_LIBRARIES} ${X11_xcb_LIB} ${X11_X11_xcb_LIB} ${X11_xkbcommon_LIB} ${X11_xkbcommon_X11_LIB} libxcb-image.so)
|
||||
list(APPEND X11_INCLUDE_DIRS ${X11_xkbcommon_INCLUDE_PATH})
|
||||
list(APPEND DEFINES "HAS_X11")
|
||||
else()
|
||||
message(STATUS "X11 not found - skipping support")
|
||||
endif()
|
||||
|
||||
find_package(Wayland QUIET)
|
||||
if(WAYLAND_FOUND)
|
||||
list(APPEND platform_INCLUDES
|
||||
ui_interfaces/wayland/WaylandInterface.cpp
|
||||
ui_interfaces/wayland/WaylandSurface.cpp
|
||||
ui_interfaces/wayland/WaylandBuffer.cpp
|
||||
ui_interfaces/wayland/WaylandPointerInterface.cpp
|
||||
ui_interfaces/wayland/WaylandSeatInterface.cpp
|
||||
ui_interfaces/wayland/WaylandKeyboard.cpp
|
||||
ui_interfaces/wayland/WaylandEglInterface.cpp
|
||||
ui_interfaces/wayland/WaylandEglWindowInterface.cpp
|
||||
${WAYLAND_XDG_SOURCE}
|
||||
)
|
||||
list(APPEND platform_LIBS OpenGL::EGL)
|
||||
list(APPEND DEFINES "HAS_WAYLAND")
|
||||
|
||||
set(OpenGL_GL_PREFERENCE "GLVND")
|
||||
find_package(OpenGL QUIET)
|
||||
if (OpenGL_FOUND)
|
||||
list(APPEND platform_LIBS ${WAYLAND_LIBRARIES})
|
||||
endif()
|
||||
else()
|
||||
Message(STATUS "Wayland not found - skipping support")
|
||||
endif()
|
||||
else()
|
||||
list(APPEND platform_INCLUDES
|
||||
ui_interfaces/win32/Win32UIInterface.h
|
||||
ui_interfaces/win32/Win32UIInterface.cpp
|
||||
ui_interfaces/win32/Win32WindowInterface.h
|
||||
ui_interfaces/win32/Win32WindowInterface.cpp
|
||||
ui_interfaces/win32/Win32Window.h
|
||||
ui_interfaces/win32/Win32Window.cpp
|
||||
ui_interfaces/win32/directx/Win32DxWindowInterface.h
|
||||
ui_interfaces/win32/directx/Win32DxWindowInterface.cpp
|
||||
ui_interfaces/win32/directx/DirectXDescriptors.h
|
||||
ui_interfaces/win32/directx/DirectXDescriptors.cpp
|
||||
ui_interfaces/win32/directx/DirectX2dIntegration.h
|
||||
ui_interfaces/win32/directx/DirectX2dIntegration.cpp
|
||||
ui_interfaces/win32/directx/DirectXBuffers.h
|
||||
ui_interfaces/win32/directx/DirectXBuffers.cpp
|
||||
ui_interfaces/win32/directx/DirectXCommandList.h
|
||||
ui_interfaces/win32/directx/DirectXCommandList.cpp
|
||||
)
|
||||
|
||||
list(APPEND platform_LIBS D3D12.lib D3DCompiler.lib DXGI.lib Dwrite.lib D2d1.lib D3D11.lib)
|
||||
|
||||
find_package(DirectX-Headers REQUIRED)
|
||||
list(APPEND platform_LIBS Microsoft::DirectX-Headers)
|
||||
endif()
|
||||
|
||||
list(APPEND windows_LIB_INCLUDES
|
||||
ui_interfaces/AbstractUiInterface.h
|
||||
ui_interfaces/UiInterfaceFactory.cpp
|
||||
managers/WindowManager.h
|
||||
managers/DesktopManager.h
|
||||
managers/EventManager.h
|
||||
managers/WindowManager.cpp
|
||||
managers/DesktopManager.cpp
|
||||
managers/EventManager.cpp
|
||||
)
|
||||
|
||||
# add the library
|
||||
add_library(windows SHARED ${windows_LIB_INCLUDES} ${platform_INCLUDES})
|
||||
|
||||
target_include_directories(windows PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/managers
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/x11
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/wayland
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/win32
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui_interfaces/win32/directx
|
||||
${WAYLAND_INCLUDE_DIRS}
|
||||
${X11_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_compile_definitions(${MODULE_NAME} PRIVATE ${DEFINES})
|
||||
if(UNIX)
|
||||
target_compile_options(${MODULE_NAME} PRIVATE -Wno-attributes) # From xdg shell autogen code
|
||||
endif()
|
||||
target_link_libraries(${MODULE_NAME} PUBLIC ${platform_LIBS} core geometry graphics ui_elements)
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src/ui)
|
||||
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
|
142
src/ui/windows/managers/DesktopManager.cpp
Normal file
142
src/ui/windows/managers/DesktopManager.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
#include "DesktopManager.h"
|
||||
|
||||
#include "AbstractDesktopApp.h"
|
||||
#include "AbstractUiInterface.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
#include "Widget.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
DesktopManager::DesktopManager(AbstractDesktopApp* application)
|
||||
: mScreens(),
|
||||
mKeyboard(Keyboard::Create()),
|
||||
mUiApplication(application),
|
||||
mEventManager(EventManager::Create()),
|
||||
mFontsManager(FontsManager::Create())
|
||||
{
|
||||
mWindowManager = WindowManager::Create(this);
|
||||
}
|
||||
|
||||
DesktopManager::~DesktopManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<DesktopManager> DesktopManager::Create(AbstractDesktopApp* application)
|
||||
{
|
||||
return std::make_unique<DesktopManager>(application);
|
||||
}
|
||||
|
||||
void DesktopManager::clearEvents()
|
||||
{
|
||||
mEventManager->ClearEvents();
|
||||
}
|
||||
|
||||
FontsManager* DesktopManager::getFontsManager() const
|
||||
{
|
||||
return mFontsManager.get();
|
||||
}
|
||||
|
||||
void DesktopManager::onKeyboardEvent(const KeyboardEvent* event)
|
||||
{
|
||||
mWindowManager->onKeyboardEvent(event);
|
||||
}
|
||||
|
||||
void DesktopManager::onPaintEvent(const PaintEvent* event)
|
||||
{
|
||||
mWindowManager->onPaintEvent(event);
|
||||
}
|
||||
|
||||
void DesktopManager::onMouseEvent(const MouseEvent* event)
|
||||
{
|
||||
mWindowManager->onMouseEvent(event);
|
||||
}
|
||||
|
||||
void DesktopManager::onUiEvent(UiEventUPtr eventUPtr)
|
||||
{
|
||||
const auto event = mEventManager->AddEvent(std::move(eventUPtr));
|
||||
switch (event->GetType())
|
||||
{
|
||||
case (UiEvent::Type::Paint):
|
||||
{
|
||||
onPaintEvent(dynamic_cast<const PaintEvent*>(event));
|
||||
break;
|
||||
}
|
||||
case (UiEvent::Type::Keyboard):
|
||||
{
|
||||
onKeyboardEvent(dynamic_cast<const KeyboardEvent*>(event));
|
||||
break;
|
||||
}
|
||||
case (UiEvent::Type::Resize):
|
||||
{
|
||||
auto resize_event = dynamic_cast<const ResizeEvent*>(event);
|
||||
mWindowManager->onResizeEvent(resize_event);
|
||||
break;
|
||||
}
|
||||
case (UiEvent::Type::Mouse):
|
||||
{
|
||||
auto mouseEvent = dynamic_cast<const MouseEvent*>(event);
|
||||
onMouseEvent(mouseEvent);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Keyboard* DesktopManager::getKeyboard() const
|
||||
{
|
||||
return mKeyboard.get();
|
||||
}
|
||||
|
||||
void DesktopManager::setKeyboard(KeyboardUPtr keyboard)
|
||||
{
|
||||
mKeyboard = std::move(keyboard);
|
||||
}
|
||||
|
||||
AbstractApp* DesktopManager::getMainApp() const
|
||||
{
|
||||
return mUiApplication->getMainApplication();
|
||||
}
|
||||
|
||||
void DesktopManager::addScreen(ScreenPtr screen)
|
||||
{
|
||||
mScreens.push_back(std::move(screen));
|
||||
}
|
||||
|
||||
mt::Screen* DesktopManager::getDefaultScreen() const
|
||||
{
|
||||
if (mScreens.size() > 0)
|
||||
{
|
||||
return mScreens[0].get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DesktopManager::setWindowManager(WindowManagerUPtr windowManager)
|
||||
{
|
||||
mWindowManager = std::move(windowManager);
|
||||
}
|
||||
|
||||
WindowManager* DesktopManager::getWindowManager() const
|
||||
{
|
||||
return mWindowManager.get();
|
||||
}
|
||||
|
||||
void DesktopManager::addWindow(mt::Window* window)
|
||||
{
|
||||
if (auto ui_interface = mUiApplication->getUiInterface())
|
||||
{
|
||||
std::cout << "Adding popup window" << std::endl;
|
||||
ui_interface->addWindow(window);
|
||||
ui_interface->showWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopManager::onLoopIteration()
|
||||
{
|
||||
auto defaultScreen = getDefaultScreen();
|
||||
|
||||
mWindowManager->onLoopIteration(defaultScreen);
|
||||
}
|
68
src/ui/windows/managers/DesktopManager.h
Normal file
68
src/ui/windows/managers/DesktopManager.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "Keyboard.h"
|
||||
#include "Screen.h"
|
||||
#include "KeyboardEvent.h"
|
||||
#include "PaintEvent.h"
|
||||
#include "MouseEvent.h"
|
||||
#include "WindowManager.h"
|
||||
#include "UiEvent.h"
|
||||
#include "AbstractApp.h"
|
||||
#include "EventManager.h"
|
||||
#include "FontsManager.h"
|
||||
|
||||
class AbstractDesktopApp;
|
||||
|
||||
class DesktopManager
|
||||
{
|
||||
public:
|
||||
DesktopManager(AbstractDesktopApp* application);
|
||||
|
||||
~DesktopManager();
|
||||
|
||||
static std::unique_ptr<DesktopManager> Create(AbstractDesktopApp* application);
|
||||
|
||||
void setWindowManager(WindowManagerUPtr windowManager);
|
||||
|
||||
AbstractApp* getMainApp() const;
|
||||
|
||||
WindowManager* getWindowManager() const;
|
||||
|
||||
Keyboard* getKeyboard() const;
|
||||
|
||||
FontsManager* getFontsManager() const;
|
||||
|
||||
void addScreen(ScreenPtr screen);
|
||||
|
||||
mt::Screen* getDefaultScreen() const;
|
||||
|
||||
void setKeyboard(KeyboardUPtr keyboard);
|
||||
|
||||
void onUiEvent(UiEventUPtr event);
|
||||
|
||||
void onKeyboardEvent(const KeyboardEvent* keyboardEvent);
|
||||
|
||||
void onMouseEvent(const MouseEvent* mouseEvent);
|
||||
|
||||
void onPaintEvent(const PaintEvent* paintEvent);
|
||||
|
||||
void clearEvents();
|
||||
|
||||
void onLoopIteration();
|
||||
|
||||
void addWindow(mt::Window* window);
|
||||
|
||||
private:
|
||||
std::vector<ScreenPtr> mScreens;
|
||||
|
||||
FontsManagerPtr mFontsManager;
|
||||
WindowManagerUPtr mWindowManager;
|
||||
KeyboardUPtr mKeyboard;
|
||||
EventManagerUPtr mEventManager;
|
||||
AbstractDesktopApp* mUiApplication;
|
||||
};
|
||||
|
||||
using DesktopManagerUPtr = std::unique_ptr<DesktopManager>;
|
23
src/ui/windows/managers/EventManager.cpp
Normal file
23
src/ui/windows/managers/EventManager.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "EventManager.h"
|
||||
|
||||
EventManager::EventManager()
|
||||
: mEvents()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<EventManager> EventManager::Create()
|
||||
{
|
||||
return std::make_unique<EventManager>();
|
||||
}
|
||||
|
||||
UiEvent* EventManager::AddEvent(UiEventUPtr event)
|
||||
{
|
||||
mEvents.push_back(std::move(event));
|
||||
return mEvents[mEvents.size()-1].get();
|
||||
}
|
||||
|
||||
void EventManager::ClearEvents()
|
||||
{
|
||||
mEvents.clear();
|
||||
}
|
22
src/ui/windows/managers/EventManager.h
Normal file
22
src/ui/windows/managers/EventManager.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "UiEvent.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class EventManager
|
||||
{
|
||||
std::vector<UiEventUPtr> mEvents;
|
||||
|
||||
public:
|
||||
|
||||
EventManager();
|
||||
|
||||
static std::unique_ptr<EventManager> Create();
|
||||
|
||||
UiEvent* AddEvent(UiEventUPtr event);
|
||||
|
||||
void ClearEvents();
|
||||
};
|
||||
|
||||
using EventManagerUPtr = std::unique_ptr<EventManager>;
|
93
src/ui/windows/managers/WindowManager.cpp
Normal file
93
src/ui/windows/managers/WindowManager.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
#include "WindowManager.h"
|
||||
|
||||
#include "DesktopManager.h"
|
||||
|
||||
WindowManager::WindowManager(DesktopManager* desktopManager)
|
||||
: mWindows(),
|
||||
mDesktopManager(desktopManager)
|
||||
{
|
||||
addWindow(mt::Window::Create(mDrawMode, desktopManager->getFontsManager()));
|
||||
}
|
||||
|
||||
WindowManager::~WindowManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<WindowManager> WindowManager::Create(DesktopManager* desktopManager)
|
||||
{
|
||||
return std::make_unique<WindowManager>(desktopManager);
|
||||
}
|
||||
|
||||
void WindowManager::onPaintEvent(const PaintEvent* event)
|
||||
{
|
||||
getMainWindow()->onPaint(event);
|
||||
}
|
||||
|
||||
void WindowManager::onMouseEvent(const MouseEvent* event)
|
||||
{
|
||||
getMainWindow()->onMouseEvent(event);
|
||||
}
|
||||
|
||||
void WindowManager::onResizeEvent(const ResizeEvent* event)
|
||||
{
|
||||
getMainWindow()->setSize(event->getWidth(), event->getHeight());
|
||||
}
|
||||
|
||||
void WindowManager::onKeyboardEvent(const KeyboardEvent* event)
|
||||
{
|
||||
getMainWindow()->onKeyboardEvent(event);
|
||||
}
|
||||
|
||||
void WindowManager::addWindow(WindowUPtr window)
|
||||
{
|
||||
auto popup_handler = [this](mt::Window* parent, std::unique_ptr<Widget> popup){
|
||||
onAddPopupWindow(parent, std::move(popup));
|
||||
};
|
||||
window->setPopupHandler(popup_handler);
|
||||
mWindows.push_back(std::move(window));
|
||||
}
|
||||
|
||||
void WindowManager::onAddPopupWindow(mt::Window* parent, std::unique_ptr<Widget> widget)
|
||||
{
|
||||
auto popup = mt::Window::Create(mDrawMode, mDesktopManager->getFontsManager());
|
||||
popup->setWidget(std::move(widget));
|
||||
popup->setParent(parent);
|
||||
|
||||
auto popup_raw = popup.get();
|
||||
addWindow(std::move(popup));
|
||||
|
||||
mDesktopManager->addWindow(popup_raw);
|
||||
}
|
||||
|
||||
void WindowManager::clearPlatformWindows()
|
||||
{
|
||||
for (auto& window : mWindows)
|
||||
{
|
||||
window->clearPlatformWindow();
|
||||
}
|
||||
}
|
||||
|
||||
mt::Window* WindowManager::getMainWindow() const
|
||||
{
|
||||
if(mWindows.size()>0)
|
||||
{
|
||||
return mWindows[0].get();
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::onLoopIteration(mt::Screen* screen)
|
||||
{
|
||||
for (auto& window : mWindows)
|
||||
{
|
||||
if (window->isDirty())
|
||||
{
|
||||
window->onPaint(nullptr);
|
||||
window->doPaint(screen);
|
||||
}
|
||||
}
|
||||
}
|
60
src/ui/windows/managers/WindowManager.h
Normal file
60
src/ui/windows/managers/WindowManager.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "Window.h"
|
||||
#include "DrawingContext.h"
|
||||
|
||||
#include "PaintEvent.h"
|
||||
#include "MouseEvent.h"
|
||||
#include "ResizeEvent.h"
|
||||
#include "KeyboardEvent.h"
|
||||
|
||||
class Widget;
|
||||
class DesktopManager;
|
||||
|
||||
class WindowManager
|
||||
{
|
||||
public:
|
||||
WindowManager(DesktopManager* desktopManager);
|
||||
|
||||
~WindowManager();
|
||||
|
||||
static std::unique_ptr<WindowManager> Create(DesktopManager* desktopManager);
|
||||
|
||||
void addWindow(WindowUPtr window);
|
||||
|
||||
mt::Window* getMainWindow() const;
|
||||
|
||||
void onPaintEvent(const PaintEvent* event);
|
||||
|
||||
void onMouseEvent(const MouseEvent* event);
|
||||
|
||||
void onKeyboardEvent(const KeyboardEvent* event);
|
||||
|
||||
void onResizeEvent(const ResizeEvent* event);
|
||||
|
||||
void clearPlatformWindows();
|
||||
|
||||
std::size_t getNumWindows() const
|
||||
{
|
||||
return mWindows.size();
|
||||
}
|
||||
|
||||
mt::Window* getWindow(std::size_t idx) const
|
||||
{
|
||||
return mWindows[idx].get();
|
||||
}
|
||||
|
||||
void onLoopIteration(mt::Screen* screen);
|
||||
|
||||
void onAddPopupWindow(mt::Window* parent, std::unique_ptr<Widget> widget);
|
||||
|
||||
private:
|
||||
std::vector<WindowUPtr> mWindows;
|
||||
DrawingMode mDrawMode{ DrawingMode::GRAPH };
|
||||
DesktopManager* mDesktopManager{nullptr};
|
||||
};
|
||||
|
||||
using WindowManagerUPtr = std::unique_ptr<WindowManager>;
|
38
src/ui/windows/ui_interfaces/AbstractUiInterface.h
Normal file
38
src/ui/windows/ui_interfaces/AbstractUiInterface.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace mt
|
||||
{
|
||||
class Window;
|
||||
}
|
||||
|
||||
class DesktopManager;
|
||||
|
||||
class AbstractUIInterface
|
||||
{
|
||||
public:
|
||||
|
||||
AbstractUIInterface(DesktopManager* desktopManager, bool useHardware = false)
|
||||
: mDesktopManager(desktopManager),
|
||||
mUseHardwareRendering(useHardware)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~AbstractUIInterface() = default;
|
||||
|
||||
virtual void loop() = 0;
|
||||
|
||||
virtual void showWindow(mt::Window* window) = 0;
|
||||
|
||||
virtual void addWindow(mt::Window* window) = 0;
|
||||
|
||||
protected:
|
||||
virtual void initialize() = 0;
|
||||
virtual void shutDown() = 0;
|
||||
|
||||
virtual void initializeHardwareRendering() {};
|
||||
|
||||
DesktopManager* mDesktopManager{nullptr};
|
||||
bool mUseHardwareRendering{false};
|
||||
};
|
27
src/ui/windows/ui_interfaces/NullUiInterface.h
Normal file
27
src/ui/windows/ui_interfaces/NullUiInterface.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractUiInterface.h"
|
||||
#include "DesktopManager.h"
|
||||
#include "FontsManager.h"
|
||||
|
||||
class NullUIInterface : public AbstractUIInterface
|
||||
{
|
||||
public:
|
||||
|
||||
NullUIInterface(DesktopManager* desktopManager, bool useHardware = false)
|
||||
: AbstractUIInterface(desktopManager, useHardware)
|
||||
{
|
||||
};
|
||||
|
||||
virtual ~NullUIInterface() = default;
|
||||
|
||||
void loop() override{};
|
||||
|
||||
void showWindow(mt::Window* window) override{};
|
||||
|
||||
void addWindow(mt::Window* window) override{};
|
||||
|
||||
protected:
|
||||
void initialize() override{};
|
||||
void shutDown() override{};
|
||||
};
|
48
src/ui/windows/ui_interfaces/UiInterfaceFactory.cpp
Normal file
48
src/ui/windows/ui_interfaces/UiInterfaceFactory.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include "UiInterfaceFactory.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef HAS_X11
|
||||
#include "XcbInterface.h"
|
||||
#endif
|
||||
#ifdef HAS_WAYLAND
|
||||
#include "WaylandInterface.h"
|
||||
#endif
|
||||
#else
|
||||
#include "Win32UiInterface.h"
|
||||
#endif
|
||||
|
||||
#include "NullUiInterface.h"
|
||||
|
||||
#include "Widget.h"
|
||||
|
||||
std::unique_ptr<AbstractUIInterface> UiInterfaceFactory::create(DesktopManager* desktopManager, Backend backend)
|
||||
{
|
||||
|
||||
#ifdef __linux__
|
||||
if (backend == Backend::UNSET || backend == Backend::X11 || backend == Backend::X11_RASTER)
|
||||
{
|
||||
#ifdef HAS_X11
|
||||
const bool use_hardware = (backend != Backend::X11_RASTER);
|
||||
return std::make_unique<XcbInterface>(desktopManager, use_hardware);
|
||||
#else
|
||||
return std::make_unique<NullUIInterface>(desktopManager);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAS_WAYLAND
|
||||
const bool use_hardware = (backend != Backend::WAYLAND_RASTER);
|
||||
return std::make_unique<WaylandInterface>(desktopManager, use_hardware);
|
||||
#else
|
||||
#ifdef HAS_X11
|
||||
const bool use_hardware = (backend != Backend::X11_RASTER);
|
||||
return std::make_unique<XcbInterface>(desktopManager, use_hardware);
|
||||
#else
|
||||
return std::make_unique<NullUIInterface>(desktopManager);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
return std::make_unique<Win32UIInterface>(desktopManager, true);
|
||||
#endif
|
||||
}
|
22
src/ui/windows/ui_interfaces/UiInterfaceFactory.h
Normal file
22
src/ui/windows/ui_interfaces/UiInterfaceFactory.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractUiInterface.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class DesktopManager;
|
||||
|
||||
class UiInterfaceFactory
|
||||
{
|
||||
public:
|
||||
enum class Backend
|
||||
{
|
||||
UNSET,
|
||||
X11_RASTER,
|
||||
X11,
|
||||
WAYLAND_RASTER,
|
||||
WAYLAND
|
||||
};
|
||||
|
||||
static std::unique_ptr<AbstractUIInterface> create(DesktopManager* desktopManager, Backend backend = Backend::UNSET);
|
||||
};
|
78
src/ui/windows/ui_interfaces/wayland/WaylandBuffer.cpp
Normal file
78
src/ui/windows/ui_interfaces/wayland/WaylandBuffer.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include "WaylandBuffer.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void WaylandBuffer::initializeSharedBuffer(int size)
|
||||
{
|
||||
mSharedMemory = std::make_unique<SharedMemory>();
|
||||
mSharedMemory->allocate("/wl_shm-XXXXXX", size);
|
||||
|
||||
if (!mSharedMemory->isValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mPoolData = static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, mSharedMemory->getFileDescriptor(), 0));
|
||||
if (mPoolData == MAP_FAILED)
|
||||
{
|
||||
close(mSharedMemory->getFileDescriptor());
|
||||
mPoolData = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandBuffer::setSharedMemory(wl_shm* shared_memory)
|
||||
{
|
||||
mWlSharedMemory = shared_memory;
|
||||
}
|
||||
|
||||
void WaylandBuffer::setUpPool(int size, int width, int height, int stride)
|
||||
{
|
||||
if (!mSharedMemory->isValid())
|
||||
{
|
||||
MLOG_ERROR("Failed to allocate shared memory.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mPoolData)
|
||||
{
|
||||
MLOG_ERROR("Failed to allocate shared memory.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto pool = wl_shm_create_pool(mWlSharedMemory, mSharedMemory->getFileDescriptor(), size);
|
||||
|
||||
int index = 0;
|
||||
// int offset = height * stride * index; // Two buffers, offset to starting point of second
|
||||
int offset = 0;
|
||||
|
||||
mWorkingBuffer = wl_shm_pool_create_buffer(pool, offset, width, height, stride, WL_SHM_FORMAT_XRGB8888);
|
||||
|
||||
wl_shm_pool_destroy(pool);
|
||||
close(mSharedMemory->getFileDescriptor());
|
||||
}
|
||||
|
||||
void WaylandBuffer::tearDownPool(int size)
|
||||
{
|
||||
munmap(mPoolData, size);
|
||||
|
||||
auto wl_buffer_release = [](void *data, struct wl_buffer *wl_buffer)
|
||||
{
|
||||
wl_buffer_destroy(wl_buffer);
|
||||
};
|
||||
mBufferListener.release = wl_buffer_release;
|
||||
|
||||
wl_buffer_add_listener(mWorkingBuffer, &mBufferListener, nullptr);
|
||||
}
|
||||
|
||||
uint8_t* WaylandBuffer::getPoolData()
|
||||
{
|
||||
return mPoolData;
|
||||
}
|
||||
|
||||
wl_buffer* WaylandBuffer::getWorkingBuffer()
|
||||
{
|
||||
return mWorkingBuffer;
|
||||
}
|
33
src/ui/windows/ui_interfaces/wayland/WaylandBuffer.h
Normal file
33
src/ui/windows/ui_interfaces/wayland/WaylandBuffer.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "wayland-client.h"
|
||||
|
||||
#include "SharedMemory.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class WaylandBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
WaylandBuffer() = default;
|
||||
void initializeSharedBuffer(int size);
|
||||
|
||||
uint8_t* getPoolData();
|
||||
wl_buffer* getWorkingBuffer();
|
||||
|
||||
void setUpPool(int size, int width, int height, int stride);
|
||||
void setSharedMemory(wl_shm* shared_memory);
|
||||
|
||||
void tearDownPool(int size);
|
||||
|
||||
private:
|
||||
wl_shm* mWlSharedMemory{nullptr};
|
||||
|
||||
std::unique_ptr<SharedMemory> mSharedMemory;
|
||||
uint8_t* mPoolData{nullptr};
|
||||
wl_shm_pool* mPool{nullptr};
|
||||
|
||||
wl_buffer* mWorkingBuffer{nullptr};
|
||||
wl_buffer_listener mBufferListener;
|
||||
};
|
78
src/ui/windows/ui_interfaces/wayland/WaylandEglInterface.cpp
Normal file
78
src/ui/windows/ui_interfaces/wayland/WaylandEglInterface.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include "WaylandEglInterface.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <wayland-egl.h>
|
||||
|
||||
WaylandEglInterface::WaylandEglInterface(wl_display* display)
|
||||
{
|
||||
initialize(display);
|
||||
}
|
||||
|
||||
void WaylandEglInterface::initialize(wl_display* display)
|
||||
{
|
||||
mEglDisplay = eglGetDisplay((EGLNativeDisplayType) display);
|
||||
if (mEglDisplay == EGL_NO_DISPLAY)
|
||||
{
|
||||
MLOG_ERROR("Can't create egl display")
|
||||
return;
|
||||
}
|
||||
|
||||
EGLint major{0};
|
||||
EGLint minor{0};
|
||||
if (eglInitialize(mEglDisplay, &major, &minor) != EGL_TRUE)
|
||||
{
|
||||
MLOG_ERROR("Can't initialise egl display")
|
||||
return;
|
||||
}
|
||||
|
||||
EGLint count{0};
|
||||
eglGetConfigs(mEglDisplay, nullptr, 0, &count);
|
||||
|
||||
EGLConfig* configs;
|
||||
configs = static_cast<EGLConfig*>(calloc(count, sizeof* configs));
|
||||
|
||||
EGLint n{0};
|
||||
EGLint config_attribs[] = {
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL_NONE
|
||||
};
|
||||
eglChooseConfig(mEglDisplay, config_attribs, configs, count, &n);
|
||||
EGLint size{0};
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
eglGetConfigAttrib(mEglDisplay, configs[i], EGL_BUFFER_SIZE, &size);
|
||||
// printf("Buffer size for config %d is %d\n", i, size);
|
||||
eglGetConfigAttrib(mEglDisplay, configs[i], EGL_RED_SIZE, &size);
|
||||
// printf("Red size for config %d is %d\n", i, size);
|
||||
|
||||
// just choose the first one
|
||||
mEglConfig = configs[i];
|
||||
break;
|
||||
}
|
||||
|
||||
static const EGLint context_attribs[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL_NONE
|
||||
};
|
||||
mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, context_attribs);
|
||||
}
|
||||
|
||||
EGLDisplay WaylandEglInterface::getDisplay() const
|
||||
{
|
||||
return mEglDisplay;
|
||||
}
|
||||
|
||||
EGLConfig WaylandEglInterface::getConfig() const
|
||||
{
|
||||
return mEglConfig;
|
||||
}
|
||||
|
||||
EGLContext WaylandEglInterface::getContext() const
|
||||
{
|
||||
return mEglContext;
|
||||
}
|
24
src/ui/windows/ui_interfaces/wayland/WaylandEglInterface.h
Normal file
24
src/ui/windows/ui_interfaces/wayland/WaylandEglInterface.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
struct wl_display;
|
||||
|
||||
class WaylandEglInterface
|
||||
{
|
||||
public:
|
||||
WaylandEglInterface(wl_display* display);
|
||||
|
||||
EGLDisplay getDisplay() const;
|
||||
|
||||
EGLConfig getConfig() const;
|
||||
|
||||
EGLContext getContext() const;
|
||||
|
||||
private:
|
||||
void initialize(wl_display* display);
|
||||
|
||||
EGLDisplay mEglDisplay;
|
||||
EGLConfig mEglConfig;
|
||||
EGLContext mEglContext;
|
||||
};
|
|
@ -0,0 +1,85 @@
|
|||
#include "WaylandEglWindowInterface.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <wayland-egl.h>
|
||||
|
||||
WaylandEglWindowInterface::WaylandEglWindowInterface(WaylandEglInterface* eglInterface)
|
||||
: mEglInterface(eglInterface)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WaylandEglWindowInterface::initialize(wl_surface* surface, int width, int height)
|
||||
{
|
||||
if (mEglSurface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mEglWindow = wl_egl_window_create(surface, width, height);
|
||||
if (mEglWindow == EGL_NO_SURFACE)
|
||||
{
|
||||
MLOG_ERROR("Can't create egl window");
|
||||
return;
|
||||
}
|
||||
|
||||
mEglSurface = eglCreateWindowSurface(mEglInterface->getDisplay(), mEglInterface->getConfig(), reinterpret_cast<EGLNativeWindowType>(mEglWindow), nullptr);
|
||||
|
||||
if (!mEglSurface)
|
||||
{
|
||||
switch(eglGetError())
|
||||
{
|
||||
case EGL_BAD_DISPLAY:
|
||||
fprintf(stderr, "EGL_BAD_DISPLAY\n");
|
||||
break;
|
||||
case EGL_NOT_INITIALIZED:
|
||||
fprintf(stderr, "EGL_NOT_INITIALIZED\n");
|
||||
break;
|
||||
case EGL_BAD_CONFIG:
|
||||
fprintf(stderr, "EGL_BAD_CONFIG\n");
|
||||
break;
|
||||
case EGL_BAD_NATIVE_WINDOW:
|
||||
fprintf(stderr, "EGL_BAD_NATIVE_WINDOW\n");
|
||||
break;
|
||||
case EGL_BAD_ATTRIBUTE:
|
||||
fprintf(stderr, "EGL_BAD_ATTRIBUTE\n");
|
||||
break;
|
||||
case EGL_BAD_ALLOC:
|
||||
fprintf(stderr, "EGL_BAD_ALLOC\n");
|
||||
break;
|
||||
case EGL_BAD_MATCH:
|
||||
fprintf(stderr, "EGL_BAD_MATCH\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown EGL error\n");
|
||||
}
|
||||
MLOG_ERROR("Created surface failed");
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandEglWindowInterface::beforePaint()
|
||||
{
|
||||
if (!mEglSurface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!eglMakeCurrent(mEglInterface->getDisplay(), mEglSurface, mEglSurface, mEglInterface->getContext()))
|
||||
{
|
||||
MLOG_ERROR("Made current failed");
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandEglWindowInterface::afterPaint()
|
||||
{
|
||||
if (!mEglSurface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!eglSwapBuffers(mEglInterface->getDisplay(), mEglSurface))
|
||||
{
|
||||
MLOG_ERROR("Swapped buffers failed");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "WaylandEglInterface.h"
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
struct wl_egl_window;
|
||||
struct wl_surface;
|
||||
|
||||
class WaylandEglWindowInterface
|
||||
{
|
||||
public:
|
||||
|
||||
WaylandEglWindowInterface(WaylandEglInterface* eglInterface);
|
||||
|
||||
void initialize(wl_surface* surface, int width, int height);
|
||||
|
||||
void beforePaint();
|
||||
void afterPaint();
|
||||
|
||||
private:
|
||||
wl_egl_window* mEglWindow{nullptr};
|
||||
EGLSurface mEglSurface{nullptr};
|
||||
WaylandEglInterface* mEglInterface;
|
||||
};
|
157
src/ui/windows/ui_interfaces/wayland/WaylandInterface.cpp
Normal file
157
src/ui/windows/ui_interfaces/wayland/WaylandInterface.cpp
Normal file
|
@ -0,0 +1,157 @@
|
|||
#include "WaylandInterface.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
#include "DesktopManager.h"
|
||||
#include "WindowManager.h"
|
||||
#include "FontsManager.h"
|
||||
|
||||
#include "WaylandSurface.h"
|
||||
#include "WaylandBuffer.h"
|
||||
#include "WaylandSeatInterface.h"
|
||||
#include "WaylandEglInterface.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
void WaylandInterface::registryHandleGlobalEvent(void *data, struct wl_registry *registry,
|
||||
uint32_t name, const char *interface, uint32_t version)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandInterface*>(data);
|
||||
std::stringstream sstrm;
|
||||
sstrm << "interface: " << interface << " version " << version << " name " << name;
|
||||
//MLOG_INFO(sstrm.str());
|
||||
|
||||
if (strcmp(interface, wl_compositor_interface.name) == 0)
|
||||
{
|
||||
thisClass->setCompositor(static_cast<wl_compositor*>(wl_registry_bind(registry, name, &wl_compositor_interface, 4)));
|
||||
}
|
||||
else if (strcmp(interface, wl_shm_interface.name) == 0)
|
||||
{
|
||||
thisClass->setSharedMemory(static_cast<wl_shm*>(wl_registry_bind(registry, name, &wl_shm_interface, 1)));
|
||||
}
|
||||
else if (strcmp(interface, xdg_wm_base_interface.name) == 0)
|
||||
{
|
||||
thisClass->setXdgBase(static_cast<xdg_wm_base*>(wl_registry_bind(registry, name, &xdg_wm_base_interface, 1)));
|
||||
}
|
||||
else if (strcmp(interface, wl_seat_interface.name) == 0)
|
||||
{
|
||||
thisClass->setSeat(static_cast<wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, 5)));
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandInterface::registryHandleGlobalRemoveEvent(void *data, struct wl_registry *registry, uint32_t name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
WaylandInterface::WaylandInterface(DesktopManager* desktopManager, std::unique_ptr<FontsManager> fontsManager, bool useHardware)
|
||||
: AbstractUIInterface(desktopManager, std::move(fontsManager), useHardware),
|
||||
mBuffer(std::make_shared<WaylandBuffer>())
|
||||
{
|
||||
mRegistryListener.global = registryHandleGlobalEvent;
|
||||
mRegistryListener.global_remove = registryHandleGlobalRemoveEvent;
|
||||
}
|
||||
|
||||
WaylandInterface::~WaylandInterface()
|
||||
{
|
||||
shutDown();
|
||||
}
|
||||
|
||||
void WaylandInterface::initialize()
|
||||
{
|
||||
mDisplay = wl_display_connect(nullptr);
|
||||
|
||||
if (!mDisplay)
|
||||
{
|
||||
MLOG_ERROR("Display connect error");
|
||||
return;
|
||||
}
|
||||
|
||||
auto registry = wl_display_get_registry(mDisplay);
|
||||
if (!registry)
|
||||
{
|
||||
MLOG_ERROR("Failed to get registry");
|
||||
return;
|
||||
}
|
||||
|
||||
wl_registry_add_listener(registry, &mRegistryListener, this);
|
||||
wl_display_roundtrip(mDisplay);
|
||||
|
||||
if (mUseHardwareRendering)
|
||||
{
|
||||
initializeHardwareRendering();
|
||||
}
|
||||
|
||||
const auto num_windows = mDesktopManager->getWindowManager()->getNumWindows();
|
||||
for(std::size_t idx=0; idx< num_windows; idx++)
|
||||
{
|
||||
addWindow(mDesktopManager->getWindowManager()->getWindow(idx));
|
||||
}
|
||||
|
||||
mDesktopManager->getWindowManager()->getMainWindow()->show();
|
||||
}
|
||||
|
||||
void WaylandInterface::initializeHardwareRendering()
|
||||
{
|
||||
mEglInterface = std::make_unique<WaylandEglInterface>(mDisplay);
|
||||
}
|
||||
|
||||
void WaylandInterface::setSeat(wl_seat* seat)
|
||||
{
|
||||
mSeatInterface = std::make_unique<WaylandSeatInterface>(seat);
|
||||
}
|
||||
|
||||
void WaylandInterface::setXdgBase(xdg_wm_base* xdg_base)
|
||||
{
|
||||
mXdgBase = xdg_base;
|
||||
auto xdg_ping_handler = [](void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandInterface*>(data);
|
||||
thisClass->doXdgPong(serial);
|
||||
};
|
||||
mXdgBaseListener.ping = xdg_ping_handler;
|
||||
xdg_wm_base_add_listener(mXdgBase, &mXdgBaseListener, this);
|
||||
}
|
||||
|
||||
void WaylandInterface::setCompositor(wl_compositor* compositor)
|
||||
{
|
||||
mCompositor = compositor;
|
||||
}
|
||||
|
||||
void WaylandInterface::setSharedMemory(wl_shm* shared_memory)
|
||||
{
|
||||
mBuffer->setSharedMemory(shared_memory);
|
||||
}
|
||||
|
||||
void WaylandInterface::doXdgPong(uint32_t serial)
|
||||
{
|
||||
xdg_wm_base_pong(mXdgBase, serial);
|
||||
}
|
||||
|
||||
void WaylandInterface::addWindow(mt::Window* window)
|
||||
{
|
||||
WaylandSurface::add(window, mCompositor, mXdgBase, mBuffer, mFontsManager.get(), mEglInterface.get());
|
||||
}
|
||||
|
||||
void WaylandInterface::showWindow(mt::Window* window)
|
||||
{
|
||||
window->show();
|
||||
}
|
||||
|
||||
void WaylandInterface::shutDown()
|
||||
{
|
||||
if (mDisplay)
|
||||
{
|
||||
wl_display_disconnect(mDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandInterface::loop()
|
||||
{
|
||||
initialize();
|
||||
|
||||
while (wl_display_dispatch(mDisplay) != -1)
|
||||
{
|
||||
/* This space deliberately left blank */
|
||||
}
|
||||
}
|
61
src/ui/windows/ui_interfaces/wayland/WaylandInterface.h
Normal file
61
src/ui/windows/ui_interfaces/wayland/WaylandInterface.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
#include "Window.h"
|
||||
#include "SharedMemory.h"
|
||||
#include "AbstractUiInterface.h"
|
||||
|
||||
#include "wayland-client.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
class WaylandBuffer;
|
||||
class WaylandSeatInterface;
|
||||
class WaylandEglInterface;
|
||||
|
||||
class WaylandInterface : public AbstractUIInterface
|
||||
{
|
||||
|
||||
public:
|
||||
WaylandInterface(DesktopManager* desktopManager, std::unique_ptr<FontsManager> fontsManager, bool useHardware = true);
|
||||
|
||||
~WaylandInterface();
|
||||
|
||||
void loop() override;
|
||||
|
||||
void addWindow(mt::Window* window) override;
|
||||
|
||||
void showWindow(mt::Window* window) override;
|
||||
|
||||
private:
|
||||
void initialize() override;
|
||||
|
||||
void initializeHardwareRendering() override;
|
||||
|
||||
void shutDown() override;
|
||||
|
||||
static void registryHandleGlobalEvent(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version);
|
||||
static void registryHandleGlobalRemoveEvent(void *data, struct wl_registry *registry, uint32_t name);
|
||||
|
||||
void doXdgPong(uint32_t serial);
|
||||
|
||||
void setCompositor(wl_compositor* compositor);
|
||||
|
||||
void setSharedMemory(wl_shm* shared_memory);
|
||||
|
||||
void setSeat(wl_seat* seat);
|
||||
|
||||
void setXdgBase(xdg_wm_base* xdg_base);
|
||||
|
||||
wl_display* mDisplay{nullptr};
|
||||
wl_compositor* mCompositor{nullptr};
|
||||
wl_registry_listener mRegistryListener;
|
||||
|
||||
xdg_wm_base* mXdgBase{nullptr};
|
||||
xdg_wm_base_listener mXdgBaseListener;
|
||||
|
||||
std::shared_ptr<WaylandBuffer> mBuffer;
|
||||
std::unique_ptr<WaylandSeatInterface> mSeatInterface;
|
||||
std::unique_ptr<WaylandEglInterface> mEglInterface;
|
||||
};
|
111
src/ui/windows/ui_interfaces/wayland/WaylandKeyboard.cpp
Normal file
111
src/ui/windows/ui_interfaces/wayland/WaylandKeyboard.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include "WaylandKeyboard.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
void WaylandKeyboard::keyboardKeymapEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandKeyboard*>(data);
|
||||
thisClass->onKeymapEvent(wl_keyboard, format, fd, size);
|
||||
}
|
||||
|
||||
void WaylandKeyboard::keyboardEnterEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandKeyboard*>(data);
|
||||
thisClass->onEnterEvent(keys);
|
||||
}
|
||||
|
||||
void WaylandKeyboard::keyboardPressedEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandKeyboard*>(data);
|
||||
thisClass->onPressedEvent(key, state);
|
||||
}
|
||||
|
||||
static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WaylandKeyboard::keyboardModifierEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandKeyboard*>(data);
|
||||
thisClass->onKeyboardModifier(mods_depressed, mods_latched, mods_locked, group);
|
||||
}
|
||||
|
||||
void WaylandKeyboard::onKeyboardModifier(uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
|
||||
{
|
||||
xkb_state_update_mask(mXkbState, mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
}
|
||||
|
||||
void WaylandKeyboard::onEnterEvent(struct wl_array *keys)
|
||||
{
|
||||
void* key;
|
||||
wl_array_for_each(key, keys)
|
||||
{
|
||||
uint32_t* key_type = static_cast<uint32_t*>(key);
|
||||
|
||||
char buf[128];
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, *key_type + 8);
|
||||
xkb_keysym_get_name(sym, buf, sizeof(buf));
|
||||
//fprintf(stderr, "sym: %-12s (%d), ", buf, sym);
|
||||
xkb_state_key_get_utf8(mXkbState, *key_type + 8, buf, sizeof(buf));
|
||||
//fprintf(stderr, "utf8: '%s'\n", buf);
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandKeyboard::onPressedEvent(uint32_t key, uint32_t state)
|
||||
{
|
||||
char buf[128];
|
||||
uint32_t keycode = key + 8;
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState, keycode);
|
||||
xkb_keysym_get_name(sym, buf, sizeof(buf));
|
||||
const char *action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? "press" : "release";
|
||||
//fprintf(stderr, "key %s: sym: %-12s (%d), ", action, buf, sym);
|
||||
xkb_state_key_get_utf8(mXkbState, keycode, buf, sizeof(buf));
|
||||
//fprintf(stderr, "utf8: '%s'\n", buf);
|
||||
}
|
||||
|
||||
void WaylandKeyboard::onKeymapEvent(struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)
|
||||
{
|
||||
// assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
|
||||
char* map_shm = static_cast<char*>(mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0));
|
||||
// assert(map_shm != MAP_FAILED);
|
||||
|
||||
struct xkb_keymap* xkb_keymap = xkb_keymap_new_from_string(mXkbContext, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
munmap(map_shm, size);
|
||||
close(fd);
|
||||
|
||||
struct xkb_state* xkb_state = xkb_state_new(xkb_keymap);
|
||||
xkb_keymap_unref(mXkbKeymap);
|
||||
xkb_state_unref(mXkbState);
|
||||
mXkbKeymap = xkb_keymap;
|
||||
mXkbState = xkb_state;
|
||||
}
|
||||
|
||||
WaylandKeyboard::WaylandKeyboard(wl_keyboard* keyboard)
|
||||
: mKeyboard(keyboard)
|
||||
{
|
||||
mXkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
|
||||
mKeyboardListener.keymap = keyboardKeymapEvent;
|
||||
mKeyboardListener.enter = keyboardEnterEvent;
|
||||
mKeyboardListener.key = keyboardPressedEvent;
|
||||
mKeyboardListener.leave = wl_keyboard_leave;
|
||||
mKeyboardListener.modifiers = keyboardModifierEvent;
|
||||
mKeyboardListener.repeat_info = wl_keyboard_repeat_info;
|
||||
|
||||
wl_keyboard_add_listener(mKeyboard, &mKeyboardListener, this);
|
||||
}
|
||||
|
||||
|
||||
WaylandKeyboard::~WaylandKeyboard()
|
||||
{
|
||||
wl_keyboard_release(mKeyboard);
|
||||
}
|
34
src/ui/windows/ui_interfaces/wayland/WaylandKeyboard.h
Normal file
34
src/ui/windows/ui_interfaces/wayland/WaylandKeyboard.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include "Keyboard.h"
|
||||
|
||||
#include "wayland-client.h"
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
class WaylandKeyboard : public Keyboard
|
||||
{
|
||||
public:
|
||||
WaylandKeyboard(wl_keyboard* keyboard);
|
||||
|
||||
~WaylandKeyboard();
|
||||
|
||||
std::string getKeyString(KeyCode keyCode) override { return "";};
|
||||
|
||||
private:
|
||||
static void keyboardKeymapEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size);
|
||||
static void keyboardEnterEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys);
|
||||
static void keyboardPressedEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
|
||||
static void keyboardModifierEvent(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group);
|
||||
|
||||
void onKeyboardModifier(uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group);
|
||||
void onKeymapEvent(struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size);
|
||||
void onEnterEvent(struct wl_array *keys);
|
||||
void onPressedEvent(uint32_t key, uint32_t state);
|
||||
|
||||
wl_keyboard* mKeyboard{nullptr};
|
||||
xkb_state* mXkbState{nullptr};
|
||||
xkb_context* mXkbContext{nullptr};
|
||||
xkb_keymap* mXkbKeymap{nullptr};
|
||||
wl_keyboard_listener mKeyboardListener;
|
||||
};
|
28
src/ui/windows/ui_interfaces/wayland/WaylandPointerEvent.h
Normal file
28
src/ui/windows/ui_interfaces/wayland/WaylandPointerEvent.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "wayland-client.h"
|
||||
|
||||
enum pointer_event_mask {
|
||||
POINTER_EVENT_ENTER = 1 << 0,
|
||||
POINTER_EVENT_LEAVE = 1 << 1,
|
||||
POINTER_EVENT_MOTION = 1 << 2,
|
||||
POINTER_EVENT_BUTTON = 1 << 3,
|
||||
POINTER_EVENT_AXIS = 1 << 4,
|
||||
POINTER_EVENT_AXIS_SOURCE = 1 << 5,
|
||||
POINTER_EVENT_AXIS_STOP = 1 << 6,
|
||||
POINTER_EVENT_AXIS_DISCRETE = 1 << 7,
|
||||
};
|
||||
|
||||
struct WaylandPointerEvent {
|
||||
uint32_t event_mask;
|
||||
wl_fixed_t surface_x, surface_y;
|
||||
uint32_t button, state;
|
||||
uint32_t time {0};
|
||||
uint32_t serial;
|
||||
struct {
|
||||
bool valid;
|
||||
wl_fixed_t value;
|
||||
int32_t discrete;
|
||||
} axes[2];
|
||||
uint32_t axis_source;
|
||||
};
|
127
src/ui/windows/ui_interfaces/wayland/WaylandPointerInterface.cpp
Normal file
127
src/ui/windows/ui_interfaces/wayland/WaylandPointerInterface.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
#include "WaylandPointerInterface.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
WaylandPointerInterface::~WaylandPointerInterface()
|
||||
{
|
||||
wl_pointer_release(mPointer);
|
||||
}
|
||||
|
||||
void WaylandPointerInterface::pointerFrameEvent(void *data, struct wl_pointer *wl_pointer)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandPointerInterface*>(data);
|
||||
thisClass->onPointerFrame();
|
||||
}
|
||||
|
||||
void WaylandPointerInterface::pointerEnterEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandPointerInterface*>(data);
|
||||
thisClass->onPointerEnter(serial, surface, surface_x, surface_y);
|
||||
}
|
||||
|
||||
void WaylandPointerInterface::pointerLeaveEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandPointerInterface*>(data);
|
||||
thisClass->onPointerLeave(serial);
|
||||
}
|
||||
|
||||
void WaylandPointerInterface::pointerMotionEvent(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandPointerInterface*>(data);
|
||||
thisClass->onPointerMotion(time, surface_x, surface_y);
|
||||
}
|
||||
|
||||
void WaylandPointerInterface::pointerButtonEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandPointerInterface*>(data);
|
||||
thisClass->onPointerButton(serial, time, button, state);
|
||||
}
|
||||
|
||||
void WaylandPointerInterface::onPointerFrame()
|
||||
{
|
||||
if (mWorkingPointerEvent.event_mask & POINTER_EVENT_ENTER)
|
||||
{
|
||||
const auto locx = wl_fixed_to_double(mWorkingPointerEvent.surface_x);
|
||||
const auto locy = wl_fixed_to_double(mWorkingPointerEvent.surface_y);
|
||||
}
|
||||
else if (mWorkingPointerEvent.event_mask & POINTER_EVENT_LEAVE)
|
||||
{
|
||||
|
||||
}
|
||||
else if (mWorkingPointerEvent.event_mask & POINTER_EVENT_MOTION)
|
||||
{
|
||||
|
||||
}
|
||||
else if (mWorkingPointerEvent.event_mask & POINTER_EVENT_BUTTON)
|
||||
{
|
||||
const bool released = mWorkingPointerEvent.state == WL_POINTER_BUTTON_STATE_RELEASED;
|
||||
}
|
||||
mWorkingPointerEvent = WaylandPointerEvent();
|
||||
}
|
||||
|
||||
void WaylandPointerInterface::onPointerButton(uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
|
||||
{
|
||||
mWorkingPointerEvent.event_mask |= POINTER_EVENT_BUTTON;
|
||||
mWorkingPointerEvent.time = time;
|
||||
mWorkingPointerEvent.serial = serial;
|
||||
mWorkingPointerEvent.button = button;
|
||||
mWorkingPointerEvent.state = state;
|
||||
}
|
||||
|
||||
void WaylandPointerInterface::onPointerEnter(uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||
{
|
||||
mWorkingPointerEvent.event_mask |= POINTER_EVENT_ENTER;
|
||||
mWorkingPointerEvent.serial = serial;
|
||||
mWorkingPointerEvent.surface_x = surface_x;
|
||||
mWorkingPointerEvent.surface_y = surface_y;
|
||||
}
|
||||
|
||||
void WaylandPointerInterface::onPointerLeave(uint32_t serial)
|
||||
{
|
||||
mWorkingPointerEvent.event_mask |= POINTER_EVENT_LEAVE;
|
||||
mWorkingPointerEvent.serial = serial;
|
||||
}
|
||||
|
||||
void WaylandPointerInterface::onPointerMotion(uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
|
||||
{
|
||||
mWorkingPointerEvent.event_mask |= POINTER_EVENT_MOTION;
|
||||
mWorkingPointerEvent.time = time;
|
||||
mWorkingPointerEvent.surface_x = surface_x;
|
||||
mWorkingPointerEvent.surface_y = surface_y;
|
||||
}
|
||||
|
||||
WaylandPointerInterface::WaylandPointerInterface(wl_pointer* pointer)
|
||||
: mPointer(pointer)
|
||||
{
|
||||
mPointerListener.enter = pointerEnterEvent;
|
||||
mPointerListener.leave = pointerLeaveEvent;
|
||||
mPointerListener.button = pointerButtonEvent;
|
||||
mPointerListener.motion = pointerMotionEvent;
|
||||
mPointerListener.axis = wl_pointer_axis;
|
||||
mPointerListener.axis_discrete = wl_pointer_axis_discrete;
|
||||
mPointerListener.axis_source = wl_pointer_axis_source;
|
||||
mPointerListener.axis_stop = wl_pointer_axis_stop;
|
||||
mPointerListener.frame = pointerFrameEvent;
|
||||
|
||||
wl_pointer_add_listener(mPointer, &mPointerListener, this);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "WaylandPointerEvent.h"
|
||||
|
||||
class WaylandPointerInterface
|
||||
{
|
||||
public:
|
||||
WaylandPointerInterface(wl_pointer* pointer);
|
||||
|
||||
~WaylandPointerInterface();
|
||||
|
||||
private:
|
||||
static void pointerEnterEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y);
|
||||
static void pointerLeaveEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface);
|
||||
static void pointerMotionEvent(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y);
|
||||
static void pointerButtonEvent(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
|
||||
static void pointerFrameEvent(void *data, struct wl_pointer *wl_pointer);
|
||||
|
||||
void onPointerButton(uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
|
||||
void onPointerLeave(uint32_t serial);
|
||||
void onPointerEnter(uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y);
|
||||
void onPointerMotion(uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y);
|
||||
void onPointerFrame();
|
||||
|
||||
wl_pointer* mPointer{nullptr};
|
||||
wl_pointer_listener mPointerListener;
|
||||
|
||||
WaylandPointerEvent mWorkingPointerEvent;
|
||||
};
|
|
@ -0,0 +1,48 @@
|
|||
#include "WaylandSeatInterface.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
void WaylandSeatInterface::seatCapabilitiesEvent(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandSeatInterface*>(data);
|
||||
thisClass->onSeatCapabilitiesEvent(capabilities);
|
||||
}
|
||||
|
||||
void WaylandSeatInterface::onSeatCapabilitiesEvent(uint32_t capabilities)
|
||||
{
|
||||
const bool have_pointer = capabilities & WL_SEAT_CAPABILITY_POINTER;
|
||||
if (have_pointer && mPointerInterface == nullptr)
|
||||
{
|
||||
auto pointer = wl_seat_get_pointer(mSeat);
|
||||
mPointerInterface = std::make_unique<WaylandPointerInterface>(pointer);
|
||||
}
|
||||
else if (!have_pointer && mPointerInterface!= nullptr)
|
||||
{
|
||||
mPointerInterface.reset();
|
||||
}
|
||||
|
||||
const bool have_keyboard = capabilities & WL_SEAT_CAPABILITY_KEYBOARD;
|
||||
if (have_keyboard && mKeyboard == nullptr)
|
||||
{
|
||||
auto keyboard = wl_seat_get_keyboard(mSeat);
|
||||
mKeyboard = std::make_unique<WaylandKeyboard>(keyboard);
|
||||
}
|
||||
else if (!have_keyboard && mKeyboard!= nullptr)
|
||||
{
|
||||
mKeyboard.reset();
|
||||
}
|
||||
}
|
||||
|
||||
WaylandSeatInterface::WaylandSeatInterface(wl_seat* seat)
|
||||
: mSeat(seat)
|
||||
{
|
||||
mSeatListener.capabilities = seatCapabilitiesEvent;
|
||||
mSeatListener.name = seatNameEvent;
|
||||
|
||||
wl_seat_add_listener(mSeat, &mSeatListener, this);
|
||||
}
|
||||
|
||||
void WaylandSeatInterface::seatNameEvent(void *data, struct wl_seat *wl_seat, const char *name)
|
||||
{
|
||||
MLOG_INFO("seat name: " << name);
|
||||
}
|
27
src/ui/windows/ui_interfaces/wayland/WaylandSeatInterface.h
Normal file
27
src/ui/windows/ui_interfaces/wayland/WaylandSeatInterface.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "WaylandPointerInterface.h"
|
||||
#include "WaylandKeyboard.h"
|
||||
|
||||
#include "wayland-client.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class WaylandSeatInterface
|
||||
{
|
||||
public:
|
||||
WaylandSeatInterface(wl_seat* seat);
|
||||
|
||||
private:
|
||||
static void seatCapabilitiesEvent(void *data, struct wl_seat *wl_seat, uint32_t capabilities);
|
||||
|
||||
static void seatNameEvent(void *data, struct wl_seat *wl_seat, const char *name);
|
||||
|
||||
void onSeatCapabilitiesEvent(uint32_t capabilities);
|
||||
|
||||
wl_seat* mSeat{nullptr};
|
||||
wl_seat_listener mSeatListener;
|
||||
|
||||
std::unique_ptr<WaylandKeyboard> mKeyboard;
|
||||
std::unique_ptr<WaylandPointerInterface> mPointerInterface;
|
||||
};
|
140
src/ui/windows/ui_interfaces/wayland/WaylandSurface.cpp
Normal file
140
src/ui/windows/ui_interfaces/wayland/WaylandSurface.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
#include "WaylandSurface.h"
|
||||
|
||||
#include "WaylandEglWindowInterface.h"
|
||||
#include "ImagePrimitives.h"
|
||||
|
||||
#include "DrawingContext.h"
|
||||
#include "FontsManager.h"
|
||||
|
||||
void WaylandSurface::add(mt::Window* window, wl_compositor* compositor, xdg_wm_base* xdg_wm_base, std::shared_ptr<WaylandBuffer> buffer, FontsManager* fontsManager, WaylandEglInterface* eglInterface)
|
||||
{
|
||||
auto wayland_window = std::make_unique<WaylandSurface>(window, compositor, xdg_wm_base, buffer, eglInterface);
|
||||
|
||||
const auto drawing_mode = eglInterface ? DrawingMode::GRAPH : DrawingMode::RASTER;
|
||||
window->setPlatformWindow(std::move(wayland_window), fontsManager, drawing_mode);
|
||||
}
|
||||
|
||||
WaylandSurface::WaylandSurface(mt::Window* window, wl_compositor* compositor, xdg_wm_base* xdg_wm_base, std::shared_ptr<WaylandBuffer> buffer, WaylandEglInterface* eglInterface)
|
||||
: IPlatformWindow(window),
|
||||
mCompositor(compositor),
|
||||
mXdgWmBase(xdg_wm_base),
|
||||
mBuffer(buffer)
|
||||
{
|
||||
if (eglInterface)
|
||||
{
|
||||
mEglWindowInterface = std::make_unique<WaylandEglWindowInterface>(eglInterface);
|
||||
}
|
||||
}
|
||||
|
||||
WaylandSurface::~WaylandSurface()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WaylandSurface::show()
|
||||
{
|
||||
map();
|
||||
}
|
||||
|
||||
void WaylandSurface::clear()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WaylandSurface::map()
|
||||
{
|
||||
if (!mSurface)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandSurface::initialize()
|
||||
{
|
||||
mSurface = wl_compositor_create_surface(mCompositor);
|
||||
mXdgSurface = xdg_wm_base_get_xdg_surface(mXdgWmBase, mSurface);
|
||||
|
||||
auto xdg_surface_configure = [](void *data, struct xdg_surface *xdg_surface, uint32_t serial)
|
||||
{
|
||||
auto thisClass = static_cast<WaylandSurface*>(data);
|
||||
thisClass->onConfigure(xdg_surface, serial);
|
||||
};
|
||||
mXdgSurfaceListener.configure = xdg_surface_configure;
|
||||
|
||||
xdg_surface_add_listener(mXdgSurface, &mXdgSurfaceListener, this);
|
||||
|
||||
mXdgTopLevel = xdg_surface_get_toplevel(mXdgSurface);
|
||||
xdg_toplevel_set_title(mXdgTopLevel, "Example client");
|
||||
|
||||
auto region = wl_compositor_create_region(mCompositor);
|
||||
wl_region_add(region, 0, 0, mWindow->getWidth(), mWindow->getHeight());
|
||||
wl_surface_set_opaque_region(mSurface, region);
|
||||
|
||||
wl_surface_commit(mSurface);
|
||||
}
|
||||
|
||||
void WaylandSurface::onConfigure(xdg_surface *xdg_surface, uint32_t serial)
|
||||
{
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
beforePaint(nullptr);
|
||||
}
|
||||
|
||||
void WaylandSurface::beforePaint(mt::Screen* screen)
|
||||
{
|
||||
if (mEglWindowInterface)
|
||||
{
|
||||
mEglWindowInterface->initialize(mSurface, mWindow->getWidth(), mWindow->getHeight());
|
||||
mEglWindowInterface->beforePaint();
|
||||
}
|
||||
else
|
||||
{
|
||||
beforePaintSoftware();
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandSurface::afterPaint(mt::Screen* screen)
|
||||
{
|
||||
if (mEglWindowInterface)
|
||||
{
|
||||
mEglWindowInterface->afterPaint();
|
||||
}
|
||||
else
|
||||
{
|
||||
afterPaintSoftware();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned WaylandSurface::getImageBufferSize() const
|
||||
{
|
||||
const auto width = mWindow->getWidth();
|
||||
const auto height = mWindow->getHeight();
|
||||
const int stride = width * mWorkingBitDepth;
|
||||
|
||||
//const int numBuffers = 2; // i.e. front/back
|
||||
return height * stride * mNumFrameBuffers;
|
||||
}
|
||||
|
||||
void WaylandSurface::beforePaintSoftware()
|
||||
{
|
||||
const auto width = mWindow->getWidth();
|
||||
const auto height = mWindow->getHeight();
|
||||
const int stride = width * mWorkingBitDepth;
|
||||
|
||||
const int shm_pool_size = getImageBufferSize();
|
||||
|
||||
mBuffer->initializeSharedBuffer(shm_pool_size);
|
||||
mBuffer->setUpPool(shm_pool_size, width, height, stride);
|
||||
|
||||
//ImagePrimitives::drawCheckerboard(mBuffer->getPoolData(), width, height, offset);
|
||||
}
|
||||
|
||||
void WaylandSurface::afterPaintSoftware()
|
||||
{
|
||||
const int shm_pool_size = getImageBufferSize();
|
||||
mBuffer->tearDownPool(shm_pool_size);
|
||||
|
||||
wl_surface_attach(mSurface, mBuffer->getWorkingBuffer(), 0, 0);
|
||||
//wl_surface_damage(mSurface, 0, 0, UINT32_MAX, UINT32_MAX);
|
||||
wl_surface_commit(mSurface);
|
||||
}
|
||||
|
71
src/ui/windows/ui_interfaces/wayland/WaylandSurface.h
Normal file
71
src/ui/windows/ui_interfaces/wayland/WaylandSurface.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
#pragma once
|
||||
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
#include "wayland-client.h"
|
||||
|
||||
#include "Window.h"
|
||||
#include "SharedMemory.h"
|
||||
#include "WaylandBuffer.h"
|
||||
|
||||
#include "IPlatformWindow.h"
|
||||
|
||||
struct wl_surface;
|
||||
struct xdg_surface;
|
||||
struct xdg_toplevel;
|
||||
|
||||
class WaylandEglInterface;
|
||||
class WaylandEglWindowInterface;
|
||||
|
||||
class FontsManager;
|
||||
|
||||
class WaylandSurface : public IPlatformWindow
|
||||
{
|
||||
public:
|
||||
|
||||
static void add(mt::Window* window, wl_compositor* compositor, xdg_wm_base* xdg_wm_base, std::shared_ptr<WaylandBuffer> buffer, FontsManager* fontsManager, WaylandEglInterface* eglInterface);
|
||||
|
||||
WaylandSurface(mt::Window* window, wl_compositor* compositor, xdg_wm_base* xdg_wm_base, std::shared_ptr<WaylandBuffer> buffer, WaylandEglInterface* eglInterface);
|
||||
|
||||
~WaylandSurface();
|
||||
|
||||
void onConfigure(xdg_surface *xdg_surface, uint32_t serial);
|
||||
|
||||
void show();
|
||||
|
||||
void map();
|
||||
|
||||
void clear();
|
||||
|
||||
void onResize(unsigned width, unsigned height)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
void beforePaint(mt::Screen* screen) override;
|
||||
void afterPaint(mt::Screen* screen) override;
|
||||
|
||||
void beforePaintSoftware();
|
||||
void afterPaintSoftware();
|
||||
|
||||
unsigned getImageBufferSize() const;
|
||||
|
||||
mt::Window* mWindow{nullptr};
|
||||
|
||||
wl_compositor* mCompositor{nullptr};
|
||||
xdg_wm_base* mXdgWmBase{nullptr};
|
||||
std::shared_ptr<WaylandBuffer> mBuffer;
|
||||
std::unique_ptr<WaylandEglWindowInterface> mEglWindowInterface;
|
||||
|
||||
wl_surface* mSurface{nullptr};
|
||||
xdg_surface* mXdgSurface{nullptr};
|
||||
xdg_surface_listener mXdgSurfaceListener;
|
||||
|
||||
xdg_toplevel* mXdgTopLevel{nullptr};
|
||||
unsigned mWorkingBitDepth{4};
|
||||
unsigned mNumFrameBuffers{1};
|
||||
};
|
||||
|
||||
using WaylandSurfacePtr = std::unique_ptr<WaylandSurface>;
|
0
src/ui/windows/ui_interfaces/wayland/XdgInterface.cpp
Normal file
0
src/ui/windows/ui_interfaces/wayland/XdgInterface.cpp
Normal file
0
src/ui/windows/ui_interfaces/wayland/XdgInterface.h
Normal file
0
src/ui/windows/ui_interfaces/wayland/XdgInterface.h
Normal file
71
src/ui/windows/ui_interfaces/win32/Win32UIInterface.cpp
Normal file
71
src/ui/windows/ui_interfaces/win32/Win32UIInterface.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
#include "Win32UIInterface.h"
|
||||
|
||||
#include "DesktopManager.h"
|
||||
#include "DirectXInterface.h"
|
||||
#include "DirectX2dInterface.h"
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <dxgi.h>
|
||||
#include <dxgi1_6.h>
|
||||
#include <Windows.h>
|
||||
|
||||
Win32UIInterface::Win32UIInterface(DesktopManager* desktopManager, bool useHardware)
|
||||
: AbstractUIInterface(desktopManager, useHardware),
|
||||
mWindowInterface(std::make_unique<Win32WindowInterface>())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Win32UIInterface::initialize()
|
||||
{
|
||||
if (mUseHardwareRendering)
|
||||
{
|
||||
initializeHardwareRendering();
|
||||
}
|
||||
|
||||
const auto num_windows = mDesktopManager->getWindowManager()->getNumWindows();
|
||||
for (std::size_t idx = 0; idx < num_windows; idx++)
|
||||
{
|
||||
addWindow(mDesktopManager->getWindowManager()->getWindow(idx));
|
||||
}
|
||||
showWindow(mDesktopManager->getWindowManager()->getMainWindow());
|
||||
}
|
||||
|
||||
void Win32UIInterface::loop()
|
||||
{
|
||||
initialize();
|
||||
|
||||
// Run the message loop.
|
||||
MSG msg = { };
|
||||
while (::GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
if (msg.message == WM_QUIT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
::TranslateMessage(&msg);
|
||||
::DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
void Win32UIInterface::shutDown()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Win32UIInterface::showWindow(mt::Window* window)
|
||||
{
|
||||
mWindowInterface->show(window);
|
||||
}
|
||||
|
||||
void Win32UIInterface::addWindow(mt::Window* window)
|
||||
{
|
||||
mWindowInterface->add(window, mDesktopManager, mDxInterface.get());
|
||||
}
|
||||
|
||||
void Win32UIInterface::initializeHardwareRendering()
|
||||
{
|
||||
mDxInterface = std::make_unique<DirectXInterface>();
|
||||
mDxInterface->initialize();
|
||||
}
|
34
src/ui/windows/ui_interfaces/win32/Win32UIInterface.h
Normal file
34
src/ui/windows/ui_interfaces/win32/Win32UIInterface.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include "Window.h"
|
||||
|
||||
#include "Win32WindowInterface.h"
|
||||
#include "AbstractUiInterface.h"
|
||||
|
||||
class DesktopManager;
|
||||
|
||||
class DirectXInterface;
|
||||
using DirectXInterfacePtr = std::unique_ptr<DirectXInterface>;
|
||||
|
||||
class Win32UIInterface : public AbstractUIInterface
|
||||
{
|
||||
public:
|
||||
Win32UIInterface(DesktopManager* desktopManager, bool useHardware = false);
|
||||
|
||||
~Win32UIInterface() = default;
|
||||
|
||||
void addWindow(mt::Window* window) override;
|
||||
|
||||
void initialize() override;
|
||||
|
||||
void loop() override;
|
||||
|
||||
void shutDown() override;
|
||||
|
||||
void showWindow(mt::Window* window) override;
|
||||
|
||||
private:
|
||||
void initializeHardwareRendering() override;
|
||||
Win32WindowInterfacePtr mWindowInterface;
|
||||
DirectXInterfacePtr mDxInterface;
|
||||
};
|
268
src/ui/windows/ui_interfaces/win32/Win32Window.cpp
Normal file
268
src/ui/windows/ui_interfaces/win32/Win32Window.cpp
Normal file
|
@ -0,0 +1,268 @@
|
|||
#include "Win32Window.h"
|
||||
|
||||
#include "Win32WindowInterface.h"
|
||||
#include "DirectXInterface.h"
|
||||
#include "Win32DxWindowInterface.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
#include "UnicodeUtils.h"
|
||||
#include "Widget.h"
|
||||
#include "DrawingContext.h"
|
||||
#include "DirectXPainter.h"
|
||||
|
||||
#include "KeyboardEvent.h"
|
||||
#include "DesktopManager.h"
|
||||
|
||||
#include <WinUser.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
LRESULT CALLBACK FreeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
Win32Window::Win32Window(mt::Window* window, DirectXInterface* dxInterface)
|
||||
: IPlatformWindow(window)
|
||||
{
|
||||
if (dxInterface)
|
||||
{
|
||||
mDxInterface = std::make_unique<Win32DxWindowInterface>(window, dxInterface);
|
||||
dynamic_cast<DirectXPainter*>(window->getDrawingContent()->getPainter())->setDxInterface(dxInterface);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Win32Window> Win32Window::Create(mt::Window* window, DirectXInterface* dxInterface)
|
||||
{
|
||||
return std::make_unique<Win32Window>(window, dxInterface);
|
||||
}
|
||||
|
||||
HWND Win32Window::getHandle() const
|
||||
{
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
void Win32Window::createNative(Win32ApplicationContext* context, DesktopManager* desktopManager)
|
||||
{
|
||||
mDesktopManager = desktopManager;
|
||||
|
||||
const char CLASS_NAME[] = "Sample Window Class";
|
||||
|
||||
auto hInstance = reinterpret_cast<HINSTANCE>(context->hInstance);
|
||||
WNDCLASS wc = { };
|
||||
wc.lpfnWndProc = FreeWindowProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.lpszClassName = CLASS_NAME;
|
||||
|
||||
RegisterClass(&wc);
|
||||
|
||||
MLOG_INFO("Request window create");
|
||||
mHandle = CreateWindowEx(
|
||||
0, // Optional window styles.
|
||||
CLASS_NAME, // Window class
|
||||
"Notes TK", // Window text
|
||||
WS_OVERLAPPEDWINDOW, // Window style
|
||||
|
||||
// Size and position
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
|
||||
nullptr, // Parent window
|
||||
nullptr, // Menu
|
||||
hInstance, // Instance handle
|
||||
this // Additional application data
|
||||
);
|
||||
|
||||
if (mHandle == nullptr)
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
auto dw = ::GetLastError();
|
||||
|
||||
::FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, dw,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
|
||||
|
||||
MLOG_INFO("Request window failed: " << dw);
|
||||
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
MLOG_INFO("Request window create got handle: " << "0x" << mHandle);
|
||||
}
|
||||
|
||||
void Win32Window::onPaintMessage()
|
||||
{
|
||||
mDesktopManager->onUiEvent(PaintEvent::Create());
|
||||
|
||||
mWindow->doPaint(nullptr);
|
||||
}
|
||||
|
||||
void Win32Window::onMouseDownMessage(int x, int y)
|
||||
{
|
||||
auto event = MouseEvent::Create();
|
||||
event->setClientLocation({ static_cast<unsigned>(x), static_cast<unsigned>(y) });
|
||||
event->setAction(MouseEvent::Action::Pressed);
|
||||
mDesktopManager->onUiEvent(std::move(event));
|
||||
MLOG_INFO("Mouse down at: " << x << " , " << y);
|
||||
}
|
||||
|
||||
void Win32Window::onMouseUpMessage(int x, int y)
|
||||
{
|
||||
auto event = MouseEvent::Create();
|
||||
event->setClientLocation({ static_cast<unsigned>(x), static_cast<unsigned>(y) });
|
||||
event->setAction(MouseEvent::Action::Released);
|
||||
mDesktopManager->onUiEvent(std::move(event));
|
||||
MLOG_INFO("Mouse up at: " << x << " , " << y);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK Win32Window::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_DESTROY:
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
case WM_CHAR:
|
||||
{
|
||||
auto key_event = std::make_unique<KeyboardEvent>();
|
||||
key_event->setAction(KeyboardEvent::Action::Pressed);
|
||||
|
||||
auto keyChar = (wchar_t)wParam;
|
||||
key_event->setKeyString(UnicodeUtils::utf16ToUtf8String(std::wstring(1, keyChar)));
|
||||
mDesktopManager->onUiEvent(std::move(key_event));
|
||||
return 0;
|
||||
}
|
||||
case WM_PAINT:
|
||||
{
|
||||
onPaintMessage();
|
||||
return 0;
|
||||
}
|
||||
case WM_LBUTTONDOWN :
|
||||
{
|
||||
const auto x = GET_X_LPARAM(lParam);
|
||||
const auto y = GET_Y_LPARAM(lParam);
|
||||
onMouseDownMessage(x, y);
|
||||
return 0;
|
||||
}
|
||||
case WM_LBUTTONUP:
|
||||
{
|
||||
const auto x = GET_X_LPARAM(lParam);
|
||||
const auto y = GET_Y_LPARAM(lParam);
|
||||
onMouseUpMessage(x, y);
|
||||
return 0;
|
||||
}
|
||||
case WM_SIZE:
|
||||
{
|
||||
auto width = LOWORD(lParam);
|
||||
auto height = HIWORD(lParam);
|
||||
MLOG_INFO("WM_SIZE: " << width << " | " << height);
|
||||
|
||||
mWindow->setSize(width, height, false);
|
||||
if (wParam == SIZE_MINIMIZED)
|
||||
{
|
||||
mWindow->setDisplayState(WindowState::Display::MINIMIZED);
|
||||
}
|
||||
else if (wParam == SIZE_MAXIMIZED)
|
||||
{
|
||||
mWindow->setDisplayState(WindowState::Display::MAXIMIZED);
|
||||
mWindow->onResize();
|
||||
}
|
||||
else if (wParam == SIZE_RESTORED)
|
||||
{
|
||||
if (mWindow->getDisplayState() == WindowState::Display::MINIMIZED)
|
||||
{
|
||||
mWindow->setDisplayState(WindowState::Display::NORMAL);
|
||||
mWindow->onResize();
|
||||
}
|
||||
else if (mWindow->getDisplayState() == WindowState::Display::MAXIMIZED)
|
||||
{
|
||||
mWindow->setDisplayState(WindowState::Display::NORMAL);
|
||||
mWindow->onResize();
|
||||
}
|
||||
else if (!mWindow->getIsSizingOnGoing())
|
||||
{
|
||||
mWindow->onResize();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
case WM_ENTERSIZEMOVE:
|
||||
{
|
||||
MLOG_INFO("WM_ENTERSIZEMOVE");
|
||||
mWindow->setIsSizingOnGoing(true);
|
||||
return 0;
|
||||
}
|
||||
case WM_EXITSIZEMOVE:
|
||||
{
|
||||
MLOG_INFO("WM_EXITSIZEMOVE");
|
||||
mWindow->setIsSizingOnGoing(false);
|
||||
mWindow->onResize();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return DefWindowProc(mHandle, message, wParam, lParam);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK FreeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
Win32Window* window;
|
||||
|
||||
if (uMsg == WM_NCCREATE)
|
||||
{
|
||||
CREATESTRUCT* cs = (CREATESTRUCT*)lParam;
|
||||
window = (Win32Window*)cs->lpCreateParams;
|
||||
|
||||
SetLastError(0);
|
||||
if (::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)window) == 0)
|
||||
{
|
||||
if (GetLastError() != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
window = (Win32Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
}
|
||||
|
||||
if (window)
|
||||
{
|
||||
window->setHandle(hwnd);
|
||||
return window->WindowProc(uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
void Win32Window::beforePaint(mt::Screen* screen)
|
||||
{
|
||||
if (mDxInterface)
|
||||
{
|
||||
mDxInterface->initialize();
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Window::afterPaint(mt::Screen* screen)
|
||||
{
|
||||
if (mDxInterface)
|
||||
{
|
||||
mDxInterface->onRender();
|
||||
}
|
||||
else
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(mHandle, &ps);
|
||||
|
||||
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
|
||||
|
||||
auto text = L"Hello World";
|
||||
auto val = DrawText(hdc, (LPCSTR)(&text[0]), -1, &ps.rcPaint, 0);
|
||||
|
||||
EndPaint(mHandle, &ps);
|
||||
}
|
||||
}
|
||||
|
||||
void Win32Window::onResize(unsigned width, unsigned height)
|
||||
{
|
||||
if (mDxInterface)
|
||||
{
|
||||
mDxInterface->onResize();
|
||||
}
|
||||
}
|
63
src/ui/windows/ui_interfaces/win32/Win32Window.h
Normal file
63
src/ui/windows/ui_interfaces/win32/Win32Window.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include "IPlatformWindow.h"
|
||||
#include <Windows.h>
|
||||
|
||||
class Win32ApplicationContext;
|
||||
class Win32DxWindowInterface;
|
||||
class DesktopManager;
|
||||
class DirectXInterface;
|
||||
|
||||
class Win32Window : public IPlatformWindow
|
||||
{
|
||||
public:
|
||||
Win32Window(mt::Window* window, DirectXInterface* dxInterface = nullptr);
|
||||
virtual ~Win32Window() = default;
|
||||
|
||||
static std::unique_ptr<Win32Window> Create(mt::Window* window, DirectXInterface* dxInterface = nullptr);
|
||||
|
||||
LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
HWND getHandle() const;
|
||||
|
||||
void setHandle(HWND handle)
|
||||
{
|
||||
mHandle = handle;
|
||||
}
|
||||
|
||||
int getCmdShow() const
|
||||
{
|
||||
return mCmdShow;
|
||||
}
|
||||
|
||||
void setCmdShow(int cmdShow)
|
||||
{
|
||||
mCmdShow = cmdShow;
|
||||
}
|
||||
|
||||
void createNative(Win32ApplicationContext* context, DesktopManager* desktopManager);
|
||||
|
||||
void show() {};
|
||||
|
||||
void map() {};
|
||||
|
||||
void clear() {};
|
||||
|
||||
void onResize(unsigned width, unsigned height);
|
||||
|
||||
void beforePaint(mt::Screen* screen);
|
||||
|
||||
void afterPaint(mt::Screen* screen);
|
||||
|
||||
private:
|
||||
void onMouseDownMessage(int x, int y);
|
||||
|
||||
void onMouseUpMessage(int x, int y);
|
||||
|
||||
void onPaintMessage();
|
||||
|
||||
HWND mHandle{ 0 };
|
||||
int mCmdShow{ 0 };
|
||||
DesktopManager* mDesktopManager{ nullptr };
|
||||
std::unique_ptr<Win32DxWindowInterface> mDxInterface;
|
||||
};
|
36
src/ui/windows/ui_interfaces/win32/Win32WindowInterface.cpp
Normal file
36
src/ui/windows/ui_interfaces/win32/Win32WindowInterface.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include "Win32WindowInterface.h"
|
||||
|
||||
#include "Win32Window.h"
|
||||
#include "DesktopManager.h"
|
||||
#include "DrawingContext.h"
|
||||
#include "DirectXInterface.h"
|
||||
#include "Widget.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
Win32WindowInterface::Win32WindowInterface()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Win32WindowInterface::show(mt::Window* window)
|
||||
{
|
||||
auto platformWindow = dynamic_cast<Win32Window*>(window->getPlatformWindow());
|
||||
MLOG_INFO("Showing platform window: " << platformWindow->getHandle());
|
||||
::ShowWindow(platformWindow->getHandle(), platformWindow->getCmdShow());
|
||||
}
|
||||
|
||||
void Win32WindowInterface::add(mt::Window* window, DesktopManager* desktopManager, DirectXInterface* dxInterface)
|
||||
{
|
||||
auto context = dynamic_cast<Win32ApplicationContext*>(desktopManager->getMainApp()->GetApplicationContext());
|
||||
|
||||
auto win32_window = Win32Window::Create(window, dxInterface);
|
||||
win32_window->createNative(context, desktopManager);
|
||||
win32_window->setCmdShow(context->nCmdShow);
|
||||
window->setPlatformWindow(std::move(win32_window));
|
||||
|
||||
window->getPlatformWindow()->beforePaint(nullptr);
|
||||
}
|
||||
|
31
src/ui/windows/ui_interfaces/win32/Win32WindowInterface.h
Normal file
31
src/ui/windows/ui_interfaces/win32/Win32WindowInterface.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "Window.h"
|
||||
#include "AbstractApp.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class DesktopManager;
|
||||
class FontsManager;
|
||||
class DirectXInterface;
|
||||
|
||||
class Win32ApplicationContext : public IApplicationContext
|
||||
{
|
||||
public:
|
||||
void* hInstance{ nullptr };
|
||||
int nCmdShow{ 0 };
|
||||
};
|
||||
|
||||
class Win32WindowInterface
|
||||
{
|
||||
public:
|
||||
Win32WindowInterface();
|
||||
|
||||
void add(mt::Window* window, DesktopManager* desktopManager, DirectXInterface* dxInterface = nullptr);
|
||||
|
||||
void show(mt::Window* window);
|
||||
};
|
||||
|
||||
using Win32WindowInterfacePtr = std::unique_ptr<Win32WindowInterface>;
|
|
@ -0,0 +1,94 @@
|
|||
#include "DirectX2dIntegration.h"
|
||||
|
||||
#include "Window.h"
|
||||
#include "Widget.h"
|
||||
#include "DirectXPainter.h"
|
||||
#include "DrawingContext.h"
|
||||
|
||||
#include "DirectXInterface.h"
|
||||
#include "DirectX2dInterface.h"
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <d3d11on12.h>
|
||||
#include <d2d1_3.h>
|
||||
#include <d2d1_1.h>
|
||||
|
||||
DirectX2dIntegration::DirectX2dIntegration(mt::Window* window, DirectXInterface* dxInterface, UINT frameCount)
|
||||
: mDxInterface(dxInterface),
|
||||
mWindow(window),
|
||||
mFrameCount(frameCount)
|
||||
{
|
||||
mDx2dInterface = dxInterface->getD2dInterface();
|
||||
}
|
||||
|
||||
ID3D11Resource* const* DirectX2dIntegration::getD11on12WrappedBackBuffer() const
|
||||
{
|
||||
return mWrappedBackBuffers[mFrameIndex].GetAddressOf();
|
||||
}
|
||||
|
||||
ID2D1Bitmap1* DirectX2dIntegration::getD2dRenderTarget() const
|
||||
{
|
||||
return mD2dRenderTargets[mFrameIndex].Get();
|
||||
}
|
||||
|
||||
void DirectX2dIntegration::render()
|
||||
{
|
||||
// Acquire our wrapped render target resource for the current back buffer.
|
||||
mDxInterface->get11On12Device()->AcquireWrappedResources(getD11on12WrappedBackBuffer(), 1);
|
||||
|
||||
// Render text directly to the back buffer.
|
||||
mDx2dInterface->getContext()->SetTarget(getD2dRenderTarget());
|
||||
|
||||
mWindow->getDrawingContent()->getPainter()->paint();
|
||||
|
||||
// Release our wrapped render target resource. Releasing
|
||||
// transitions the back buffer resource to the state specified
|
||||
// as the OutState when the wrapped resource was created.
|
||||
mDxInterface->get11On12Device()->ReleaseWrappedResources(getD11on12WrappedBackBuffer(), 1);
|
||||
|
||||
// Flush to submit the 11 command list to the shared command queue.
|
||||
mDxInterface->getD3d11DeviceContext()->Flush();
|
||||
}
|
||||
|
||||
void DirectX2dIntegration::clearBuffers()
|
||||
{
|
||||
for (auto& buffer : mWrappedBackBuffers)
|
||||
{
|
||||
buffer.Reset();
|
||||
}
|
||||
mWrappedBackBuffers.clear();
|
||||
|
||||
for (auto& buffer : mD2dRenderTargets)
|
||||
{
|
||||
buffer.Reset();
|
||||
}
|
||||
mD2dRenderTargets.clear();
|
||||
|
||||
mDx2dInterface->getContext()->SetTarget(nullptr);
|
||||
mDxInterface->getD3d11DeviceContext()->Flush();
|
||||
}
|
||||
|
||||
void DirectX2dIntegration::wrapBuffer(ID3D12Resource* renderTarget)
|
||||
{
|
||||
mWrappedBackBuffers.push_back(Microsoft::WRL::ComPtr<ID3D11Resource>());
|
||||
|
||||
D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET };
|
||||
mDxInterface->get11On12Device()->CreateWrappedResource(renderTarget, &d3d11Flags,
|
||||
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT, IID_PPV_ARGS(&mWrappedBackBuffers[mWrappedBackBuffers.size()-1]));
|
||||
|
||||
float dpiX{ 96.0 };
|
||||
float dpiY{ 96.0 };
|
||||
//mDx2dInterface->getFactory()->GetDesktopDpi(&dpiX, &dpiY);
|
||||
const auto pixel_format = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED);
|
||||
const auto bitmap_props = D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, pixel_format, dpiX, dpiY);
|
||||
|
||||
mD2dRenderTargets.push_back(Microsoft::WRL::ComPtr<ID2D1Bitmap1>());
|
||||
Microsoft::WRL::ComPtr<IDXGISurface> surface;
|
||||
mWrappedBackBuffers[mWrappedBackBuffers.size() - 1].As(&surface);
|
||||
mDx2dInterface->getContext()->CreateBitmapFromDxgiSurface(surface.Get(), &bitmap_props, &mD2dRenderTargets[mD2dRenderTargets.size()-1]);
|
||||
}
|
||||
|
||||
void DirectX2dIntegration::updateBackbufferIndex(UINT idx)
|
||||
{
|
||||
mFrameIndex = idx;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <wrl.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
class DirectXInterface;
|
||||
class DirectX2dInterface;
|
||||
|
||||
namespace mt
|
||||
{
|
||||
class Window;
|
||||
}
|
||||
struct ID3D12Resource;
|
||||
struct ID3D11Resource;
|
||||
struct ID2D1Bitmap1;
|
||||
|
||||
class DirectX2dIntegration
|
||||
{
|
||||
public:
|
||||
DirectX2dIntegration(mt::Window* window, DirectXInterface* dxInterface, UINT frameCount);
|
||||
|
||||
void clearBuffers();
|
||||
|
||||
void render();
|
||||
|
||||
void updateBackbufferIndex(UINT idx);
|
||||
|
||||
void wrapBuffer(ID3D12Resource* referenceBuffer);
|
||||
|
||||
private:
|
||||
ID3D11Resource* const* getD11on12WrappedBackBuffer() const;
|
||||
ID2D1Bitmap1* getD2dRenderTarget() const;
|
||||
|
||||
DirectXInterface* mDxInterface{ nullptr };
|
||||
DirectX2dInterface* mDx2dInterface{ nullptr };
|
||||
mt::Window* mWindow{ nullptr };
|
||||
|
||||
UINT mFrameCount{ 2 };
|
||||
UINT mFrameIndex{ 0 };
|
||||
std::vector<Microsoft::WRL::ComPtr<ID3D11Resource> > mWrappedBackBuffers;
|
||||
std::vector<Microsoft::WRL::ComPtr<ID2D1Bitmap1> > mD2dRenderTargets;
|
||||
};
|
109
src/ui/windows/ui_interfaces/win32/directx/DirectXBuffers.cpp
Normal file
109
src/ui/windows/ui_interfaces/win32/directx/DirectXBuffers.cpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
#include "DirectXBuffers.h"
|
||||
|
||||
#include "DirectXDescriptors.h"
|
||||
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include <dxgi.h>
|
||||
#include <dxgi1_6.h>
|
||||
#include <d3d12.h>
|
||||
#include <directx/d3dx12.h>
|
||||
|
||||
DirectXBuffers::DirectXBuffers(UINT frameCount)
|
||||
: mFrameCount(frameCount)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DirectXBuffers::clear()
|
||||
{
|
||||
for (auto& buffer : mBackBuffers)
|
||||
{
|
||||
auto count = buffer.Reset();
|
||||
}
|
||||
mBackBuffers.clear();
|
||||
mDepthStencilBuffer.Reset();
|
||||
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
bool DirectXBuffers::isInitialized()
|
||||
{
|
||||
return mInitialized;
|
||||
}
|
||||
|
||||
UINT DirectXBuffers::getCurrentBackBufferIndex() const
|
||||
{
|
||||
return mBackBufferIndex;
|
||||
}
|
||||
|
||||
ID3D12Resource* DirectXBuffers::getCurrentBackBuffer() const
|
||||
{
|
||||
return mBackBuffers[mBackBufferIndex].Get();
|
||||
}
|
||||
|
||||
ID3D12Resource* DirectXBuffers::getBackBuffer(UINT index) const
|
||||
{
|
||||
return mBackBuffers[index].Get();
|
||||
}
|
||||
|
||||
ID3D12Resource* DirectXBuffers::getDepthStencilBuffer() const
|
||||
{
|
||||
return mDepthStencilBuffer.Get();
|
||||
}
|
||||
|
||||
void DirectXBuffers::updateBackbufferIndex(UINT index)
|
||||
{
|
||||
mBackBufferIndex = index;
|
||||
}
|
||||
|
||||
void DirectXBuffers::setupBackBuffers(ID3D12Device* device, IDXGISwapChain4* swapChain, DirectXDescriptors* descriptors)
|
||||
{
|
||||
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_heap_handle(descriptors->getRtvHandle());
|
||||
for (UINT i = 0; i < mFrameCount; i++)
|
||||
{
|
||||
mBackBuffers.push_back(Microsoft::WRL::ComPtr<ID3D12Resource>());
|
||||
|
||||
swapChain->GetBuffer(i, IID_PPV_ARGS(&mBackBuffers[mBackBuffers.size()-1]));
|
||||
device->CreateRenderTargetView(mBackBuffers[mBackBuffers.size() - 1].Get(), nullptr, rtv_heap_handle);
|
||||
|
||||
rtv_heap_handle.Offset(1, descriptors->getRtvDescriptorSize());
|
||||
|
||||
}
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
void DirectXBuffers::setupDepthStencilHeap(ID3D12Device* device, unsigned width, unsigned height)
|
||||
{
|
||||
D3D12_RESOURCE_DESC depthStencilDesc;
|
||||
depthStencilDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
depthStencilDesc.Alignment = 0;
|
||||
depthStencilDesc.Width = width;
|
||||
depthStencilDesc.Height = height;
|
||||
depthStencilDesc.DepthOrArraySize = 1;
|
||||
depthStencilDesc.MipLevels = 1;
|
||||
depthStencilDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;
|
||||
depthStencilDesc.SampleDesc.Count = 1;
|
||||
depthStencilDesc.SampleDesc.Quality = 0;
|
||||
depthStencilDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||
depthStencilDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||
|
||||
D3D12_CLEAR_VALUE optClear;
|
||||
optClear.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
optClear.DepthStencil.Depth = 1.0f;
|
||||
optClear.DepthStencil.Stencil = 0;
|
||||
|
||||
auto props = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
|
||||
device->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE,
|
||||
&depthStencilDesc, D3D12_RESOURCE_STATE_COMMON, &optClear, IID_PPV_ARGS(mDepthStencilBuffer.GetAddressOf()));
|
||||
}
|
||||
|
||||
void DirectXBuffers::setupDepthStencilView(ID3D12Device* device, DirectXDescriptors* descriptors)
|
||||
{
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc;
|
||||
dsvDesc.Flags = D3D12_DSV_FLAG_NONE;
|
||||
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
|
||||
dsvDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
dsvDesc.Texture2D.MipSlice = 0;
|
||||
device->CreateDepthStencilView(mDepthStencilBuffer.Get(), &dsvDesc, descriptors->getDsvHandle());
|
||||
}
|
42
src/ui/windows/ui_interfaces/win32/directx/DirectXBuffers.h
Normal file
42
src/ui/windows/ui_interfaces/win32/directx/DirectXBuffers.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <wrl.h>
|
||||
#include <vector>
|
||||
|
||||
class DirectXDescriptors;
|
||||
struct ID3D12Resource;
|
||||
struct ID3D12Device;
|
||||
struct IDXGISwapChain4;
|
||||
|
||||
class DirectXBuffers
|
||||
{
|
||||
public:
|
||||
DirectXBuffers(UINT frameCount);
|
||||
|
||||
void clear();
|
||||
|
||||
UINT getCurrentBackBufferIndex() const;
|
||||
|
||||
ID3D12Resource* getCurrentBackBuffer() const;
|
||||
|
||||
ID3D12Resource* getBackBuffer(UINT index) const;
|
||||
|
||||
ID3D12Resource* getDepthStencilBuffer() const;
|
||||
|
||||
bool isInitialized();
|
||||
|
||||
void setupBackBuffers(ID3D12Device* device, IDXGISwapChain4* swapChain, DirectXDescriptors* descriptors);
|
||||
|
||||
void setupDepthStencilHeap(ID3D12Device* device, unsigned width, unsigned height);
|
||||
|
||||
void setupDepthStencilView(ID3D12Device* device, DirectXDescriptors* descriptors);
|
||||
|
||||
void updateBackbufferIndex(UINT index);
|
||||
|
||||
private:
|
||||
bool mInitialized{ false };
|
||||
UINT mFrameCount{ 2 };
|
||||
UINT mBackBufferIndex{ 0 };
|
||||
std::vector<Microsoft::WRL::ComPtr<ID3D12Resource> > mBackBuffers;
|
||||
Microsoft::WRL::ComPtr<ID3D12Resource> mDepthStencilBuffer;
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
#include "DirectXCommandList.h"
|
||||
|
||||
#include <d3d12.h>
|
||||
|
||||
void DirectXCommandList::close()
|
||||
{
|
||||
mCommandList->Close();
|
||||
}
|
||||
|
||||
void DirectXCommandList::create(ID3D12Device* device, ID3D12PipelineState* pso)
|
||||
{
|
||||
device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&mCommandAllocator));
|
||||
device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCommandAllocator.Get(), pso, IID_PPV_ARGS(&mCommandList));
|
||||
mCommandList->Close();
|
||||
}
|
||||
|
||||
ID3D12GraphicsCommandList* DirectXCommandList::get() const
|
||||
{
|
||||
return mCommandList.Get();
|
||||
}
|
||||
|
||||
void DirectXCommandList::execute(ID3D12CommandQueue* queue)
|
||||
{
|
||||
ID3D12CommandList* ppCommandLists[] = { mCommandList.Get() };
|
||||
queue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
|
||||
}
|
||||
|
||||
void DirectXCommandList::reset(ID3D12PipelineState* pso)
|
||||
{
|
||||
mCommandList->Reset(mCommandAllocator.Get(), pso);
|
||||
}
|
||||
|
||||
void DirectXCommandList::resetAllocator()
|
||||
{
|
||||
mCommandAllocator->Reset();
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <wrl.h>
|
||||
|
||||
struct ID3D12CommandAllocator;
|
||||
struct ID3D12GraphicsCommandList;
|
||||
struct ID3D12PipelineState;
|
||||
struct ID3D12CommandQueue;
|
||||
struct ID3D12Device;
|
||||
|
||||
class DirectXCommandList
|
||||
{
|
||||
public:
|
||||
void close();
|
||||
|
||||
void create(ID3D12Device* device, ID3D12PipelineState* pso);
|
||||
|
||||
ID3D12GraphicsCommandList* get() const;
|
||||
|
||||
void execute(ID3D12CommandQueue* queue);
|
||||
|
||||
void resetAllocator();
|
||||
|
||||
void reset(ID3D12PipelineState* pso);
|
||||
|
||||
private:
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandAllocator> mCommandAllocator;
|
||||
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> mCommandList;
|
||||
};
|
|
@ -0,0 +1,76 @@
|
|||
#include "DirectXDescriptors.h"
|
||||
|
||||
#include <directx/d3dx12.h>
|
||||
|
||||
UINT DirectXDescriptors::getRtvDescriptorSize() const
|
||||
{
|
||||
return mRtvDescriptorSize;
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE DirectXDescriptors::getRtvHandle(int index) const
|
||||
{
|
||||
if (index == -1)
|
||||
{
|
||||
return CD3DX12_CPU_DESCRIPTOR_HANDLE(mRtvHeap->GetCPUDescriptorHandleForHeapStart());
|
||||
}
|
||||
else
|
||||
{
|
||||
return CD3DX12_CPU_DESCRIPTOR_HANDLE(mRtvHeap->GetCPUDescriptorHandleForHeapStart(), index, mRtvDescriptorSize);
|
||||
}
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE DirectXDescriptors::getDsvHandle() const
|
||||
{
|
||||
return mDsvHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
}
|
||||
|
||||
void DirectXDescriptors::updateDescriptorSizes(ID3D12Device* device)
|
||||
{
|
||||
mRtvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
mDsvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
|
||||
mCbvSrvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
}
|
||||
|
||||
void DirectXDescriptors::setupDefaultDescriptorHeaps(ID3D12Device* device, unsigned numFrames)
|
||||
{
|
||||
updateDescriptorSizes(device);
|
||||
setupRtvDescriptorHeap(device, numFrames);
|
||||
setupDsvDescriptorHeap(device);
|
||||
}
|
||||
|
||||
void DirectXDescriptors::setupRtvDescriptorHeap(ID3D12Device* device, unsigned numFrames)
|
||||
{
|
||||
D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
|
||||
rtvHeapDesc.NumDescriptors = numFrames;
|
||||
rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||
rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||
device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&mRtvHeap));
|
||||
}
|
||||
|
||||
void DirectXDescriptors::setupDsvDescriptorHeap(ID3D12Device* device)
|
||||
{
|
||||
D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
|
||||
dsvHeapDesc.NumDescriptors = 1;
|
||||
dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
|
||||
dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||
dsvHeapDesc.NodeMask = 0;
|
||||
device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&mDsvHeap));
|
||||
}
|
||||
|
||||
void DirectXDescriptors::setupSrvDescriptorHeap(ID3D12Device* device)
|
||||
{
|
||||
D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
|
||||
srvHeapDesc.NumDescriptors = 1;
|
||||
srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||
srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvHeap));
|
||||
}
|
||||
|
||||
void DirectXDescriptors::setupCbvDescriptorHeap(ID3D12Device* device)
|
||||
{
|
||||
D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc = {};
|
||||
cbvHeapDesc.NumDescriptors = 1;
|
||||
cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||
cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
device->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&mCbvHeap));
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <wrl.h>
|
||||
#include <d3d12.h>
|
||||
|
||||
class DirectXDescriptors
|
||||
{
|
||||
public:
|
||||
UINT getRtvDescriptorSize() const;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE getRtvHandle(int index = -1) const;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE getDsvHandle() const;
|
||||
|
||||
void setupDefaultDescriptorHeaps(ID3D12Device* device, unsigned numFrames = 2);
|
||||
private:
|
||||
void updateDescriptorSizes(ID3D12Device* device);
|
||||
void setupRtvDescriptorHeap(ID3D12Device* device, unsigned numFrames);
|
||||
void setupDsvDescriptorHeap(ID3D12Device* device);
|
||||
void setupSrvDescriptorHeap(ID3D12Device* device);
|
||||
void setupCbvDescriptorHeap(ID3D12Device* device);
|
||||
|
||||
UINT mRtvDescriptorSize{ 0 };
|
||||
UINT mDsvDescriptorSize{ 0 };
|
||||
UINT mCbvSrvDescriptorSize{ 0 };
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mRtvHeap;
|
||||
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mDsvHeap;
|
||||
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mSrvHeap;
|
||||
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> mCbvHeap;
|
||||
};
|
|
@ -0,0 +1,297 @@
|
|||
#include "Win32DxWindowInterface.h"
|
||||
|
||||
#include "DirectXInterface.h"
|
||||
#include "Win32Window.h"
|
||||
#include "Window.h"
|
||||
#include "Widget.h"
|
||||
#include "FileLogger.h"
|
||||
|
||||
#include "DirectXDescriptors.h"
|
||||
#include "DirectX2dIntegration.h"
|
||||
#include "DirectXBuffers.h"
|
||||
#include "DirectXCommandList.h"
|
||||
|
||||
#include "DrawingContext.h"
|
||||
#include "DirectXPainter.h"
|
||||
#include "DirectXMeshPainter.h"
|
||||
|
||||
#include <dxgi.h>
|
||||
#include <dxgi1_6.h>
|
||||
#include <d3d12sdklayers.h>
|
||||
#include <D3Dcommon.h>
|
||||
|
||||
Win32DxWindowInterface::Win32DxWindowInterface(mt::Window* window, DirectXInterface* dxInterface)
|
||||
: mWindow(window),
|
||||
mDxInterface(dxInterface)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Win32DxWindowInterface::~Win32DxWindowInterface()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Win32DxWindowInterface::destroyWindow()
|
||||
{
|
||||
flushCommandQueue();
|
||||
::CloseHandle(mFenceEvent);
|
||||
}
|
||||
|
||||
void Win32DxWindowInterface::onRender()
|
||||
{
|
||||
if (!mIsValid)
|
||||
{
|
||||
MLOG_INFO("Invalid state - returning");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mBuffers->isInitialized())
|
||||
{
|
||||
MLOG_INFO("Buffer not initialized - returning");
|
||||
return;
|
||||
}
|
||||
|
||||
updateCommandList();
|
||||
|
||||
mCommandList->execute(mDxInterface->getCommandQueue());
|
||||
|
||||
mD2dIntegration->render();
|
||||
|
||||
mSwapChain->Present(1, 0);
|
||||
|
||||
flushCommandQueue();
|
||||
}
|
||||
|
||||
void Win32DxWindowInterface::updateCommandList()
|
||||
{
|
||||
// Command list allocators can only be reset when the associated
|
||||
// command lists have finished execution on the GPU; apps should use
|
||||
// fences to determine GPU execution progress.
|
||||
mCommandList->resetAllocator();
|
||||
|
||||
// However, when ExecuteCommandList() is called on a particular command
|
||||
// list, that command list can then be reset at any time and must be before
|
||||
// re-recording.
|
||||
mCommandList->reset(getPipelineState());
|
||||
|
||||
// Set necessary state.
|
||||
auto painter = dynamic_cast<DirectXPainter*>(mWindow->getDrawingContent()->getPainter());
|
||||
mCommandList->get()->SetGraphicsRootSignature(painter->getMeshPainter()->getRootSignature());
|
||||
mCommandList->get()->RSSetViewports(1, &mViewport);
|
||||
mCommandList->get()->RSSetScissorRects(1, &mScissorRect);
|
||||
|
||||
// Indicate that the back buffer will be used as a render target.
|
||||
auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(mBuffers->getCurrentBackBuffer(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
mCommandList->get()->ResourceBarrier(1, &barrier);
|
||||
|
||||
auto rtv_handle = mDescriptors->getRtvHandle(static_cast<int>(mBuffers->getCurrentBackBufferIndex()));
|
||||
mCommandList->get()->OMSetRenderTargets(1, &rtv_handle, FALSE, nullptr);
|
||||
|
||||
painter->paintBackground(rtv_handle, mCommandList->get());
|
||||
painter->paintMesh(mCommandList->get());
|
||||
|
||||
// Indicate that the back buffer will now be used to present. (Exclude as handled by D2D integration later)
|
||||
//barrier = CD3DX12_RESOURCE_BARRIER::Transition(mBuffers->getCurrentBackBuffer(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
|
||||
//mCommandList->get()->ResourceBarrier(1, &barrier);
|
||||
|
||||
mCommandList->close();
|
||||
}
|
||||
|
||||
bool Win32DxWindowInterface::initialize()
|
||||
{
|
||||
if (mInitialized)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
mInitialized = true;
|
||||
MLOG_INFO("D3D Win init");
|
||||
|
||||
mD2dIntegration = std::make_unique<DirectX2dIntegration>(mWindow, mDxInterface, FrameCount);
|
||||
mBuffers = std::make_unique<DirectXBuffers>(FrameCount);
|
||||
|
||||
if (!createSwapChain())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mCommandList = std::make_unique<DirectXCommandList>();
|
||||
mCommandList->create(mDxInterface->getD3dDevice(), getPipelineState());
|
||||
|
||||
createSyncObjects();
|
||||
|
||||
mDescriptors = std::make_unique<DirectXDescriptors>();
|
||||
mDescriptors->setupDefaultDescriptorHeaps(mDxInterface->getD3dDevice());
|
||||
|
||||
onResize();
|
||||
|
||||
if (!loadAssets())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
flushCommandQueue();
|
||||
|
||||
mIsValid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Win32DxWindowInterface::onResize()
|
||||
{
|
||||
MLOG_INFO("On resize");
|
||||
mIsValid = false;
|
||||
|
||||
flushCommandQueue();
|
||||
|
||||
mCommandList->reset(getPipelineState());
|
||||
|
||||
clearBuffers();
|
||||
|
||||
resizeSwapChain();
|
||||
|
||||
populateBuffers();
|
||||
|
||||
mCommandList->close();
|
||||
|
||||
mCommandList->execute(mDxInterface->getCommandQueue());
|
||||
|
||||
flushCommandQueue();
|
||||
|
||||
updateViewport();
|
||||
|
||||
mIsValid = true;
|
||||
}
|
||||
|
||||
void Win32DxWindowInterface::resizeSwapChain()
|
||||
{
|
||||
const auto width = mWindow->getWidth();
|
||||
const auto height = mWindow->getHeight();
|
||||
MLOG_INFO("Resizing swap chain to: " << width << " | " << height);
|
||||
mSwapChain->ResizeBuffers(FrameCount, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
|
||||
updateBackbufferIndex(0);
|
||||
}
|
||||
|
||||
void Win32DxWindowInterface::updateViewport()
|
||||
{
|
||||
const auto width = mWindow->getWidth();
|
||||
const auto height = mWindow->getHeight();
|
||||
mViewport = CD3DX12_VIEWPORT(0.0f, 0.0f, static_cast<float>(width), static_cast<float>(height));
|
||||
mScissorRect = CD3DX12_RECT(0, 0, width, height);
|
||||
}
|
||||
|
||||
void Win32DxWindowInterface::clearBuffers()
|
||||
{
|
||||
mD2dIntegration->clearBuffers();
|
||||
mBuffers->clear();
|
||||
}
|
||||
|
||||
ID3D12PipelineState* Win32DxWindowInterface::getPipelineState() const
|
||||
{
|
||||
auto painter = dynamic_cast<DirectXPainter*>(mWindow->getDrawingContent()->getPainter());
|
||||
return painter->getMeshPainter()->getPipelineState();
|
||||
}
|
||||
|
||||
void Win32DxWindowInterface::populateBuffers()
|
||||
{
|
||||
MLOG_INFO("Populating buffers");
|
||||
auto d3d_device = mDxInterface->getD3dDevice();
|
||||
mBuffers->setupBackBuffers(d3d_device, mSwapChain.Get(), mDescriptors.get());
|
||||
for (UINT idx = 0; idx < FrameCount; idx++)
|
||||
{
|
||||
mD2dIntegration->wrapBuffer(mBuffers->getBackBuffer(idx));
|
||||
}
|
||||
|
||||
const auto width = mWindow->getWidth();
|
||||
const auto height = mWindow->getHeight();
|
||||
if (width > 0 and height > 0)
|
||||
{
|
||||
mBuffers->setupDepthStencilHeap(mDxInterface->getD3dDevice(), width, height);
|
||||
mBuffers->setupDepthStencilView(mDxInterface->getD3dDevice(), mDescriptors.get());
|
||||
|
||||
auto barrier = CD3DX12_RESOURCE_BARRIER::Transition(mBuffers->getDepthStencilBuffer(), D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
mCommandList->get()->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
}
|
||||
|
||||
bool Win32DxWindowInterface::createSwapChain()
|
||||
{
|
||||
mSwapChain.Reset();
|
||||
|
||||
const auto width = mWindow->getWidth();
|
||||
const auto height = mWindow->getHeight();
|
||||
const auto hwnd = dynamic_cast<Win32Window*>(mWindow->getPlatformWindow())->getHandle();
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
|
||||
swapChainDesc.BufferCount = FrameCount;
|
||||
swapChainDesc.Width = width;
|
||||
swapChainDesc.Height = height;
|
||||
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
swapChainDesc.SampleDesc.Count = 1;
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGISwapChain1> swapChain;
|
||||
if (FAILED(mDxInterface->getDxgiFactory()->CreateSwapChainForHwnd(mDxInterface->getCommandQueue(), hwnd, &swapChainDesc, nullptr, nullptr, &swapChain)))
|
||||
{
|
||||
MLOG_ERROR("Failed to create swap chain for hwnd: " << hwnd);
|
||||
return false;
|
||||
}
|
||||
swapChain.As(&mSwapChain);
|
||||
|
||||
// Prevent fullscreen toggle
|
||||
mDxInterface->getDxgiFactory()->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
|
||||
|
||||
// Update index for backbuffer
|
||||
updateBackbufferIndex(mSwapChain->GetCurrentBackBufferIndex());
|
||||
return true;
|
||||
}
|
||||
|
||||
void Win32DxWindowInterface::updateBackbufferIndex(UINT index)
|
||||
{
|
||||
mBuffers->updateBackbufferIndex(index);
|
||||
mD2dIntegration->updateBackbufferIndex(index);
|
||||
}
|
||||
|
||||
bool Win32DxWindowInterface::loadAssets()
|
||||
{
|
||||
auto painter = dynamic_cast<DirectXPainter*>(mWindow->getDrawingContent()->getPainter());
|
||||
painter->initializeMesh();
|
||||
painter->updateMesh();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Win32DxWindowInterface::createSyncObjects()
|
||||
{
|
||||
mDxInterface->getD3dDevice()->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&mFence));
|
||||
mFenceValue = 1;
|
||||
|
||||
// Create an event handle to use for frame synchronization.
|
||||
mFenceEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
if (mFenceEvent == nullptr)
|
||||
{
|
||||
//ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
|
||||
}
|
||||
|
||||
// Wait for the command list to execute; we are reusing the same command
|
||||
// list in our main loop but for now, we just want to wait for setup to
|
||||
// complete before continuing.
|
||||
flushCommandQueue();
|
||||
}
|
||||
|
||||
void Win32DxWindowInterface::flushCommandQueue()
|
||||
{
|
||||
// Signal and increment the fence value.
|
||||
const UINT64 fence = mFenceValue;
|
||||
mDxInterface->getCommandQueue()->Signal(mFence.Get(), fence);
|
||||
mFenceValue++;
|
||||
|
||||
// Wait until the previous frame is finished.
|
||||
if (mFence->GetCompletedValue() < fence)
|
||||
{
|
||||
mFence->SetEventOnCompletion(fence, mFenceEvent);
|
||||
::WaitForSingleObject(mFenceEvent, INFINITE);
|
||||
}
|
||||
|
||||
updateBackbufferIndex(mSwapChain->GetCurrentBackBufferIndex());
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <wrl.h>
|
||||
#include <d3d12.h>
|
||||
#include <directx/d3dx12.h>
|
||||
|
||||
class DirectXInterface;
|
||||
class DirectXDescriptors;
|
||||
class DirectX2dIntegration;
|
||||
class DirectXBuffers;
|
||||
class DirectXCommandList;
|
||||
namespace mt
|
||||
{
|
||||
class Window;
|
||||
}
|
||||
|
||||
struct ID3D12CommandAllocator;
|
||||
struct ID3D12GraphicsCommandList;
|
||||
struct IDXGISwapChain4;
|
||||
struct ID3D12Resource;
|
||||
struct ID3D12Fence;
|
||||
struct ID3D12PipelineState;
|
||||
|
||||
class Win32DxWindowInterface
|
||||
{
|
||||
public:
|
||||
Win32DxWindowInterface(mt::Window* window, DirectXInterface* dxInterface);
|
||||
|
||||
~Win32DxWindowInterface();
|
||||
|
||||
bool initialize();
|
||||
|
||||
void onResize();
|
||||
|
||||
void onRender();
|
||||
|
||||
private:
|
||||
bool loadAssets();
|
||||
|
||||
void updateCommandList();
|
||||
|
||||
void destroyWindow();
|
||||
|
||||
bool createSwapChain();
|
||||
void resizeSwapChain();
|
||||
|
||||
void clearBuffers();
|
||||
void populateBuffers();
|
||||
void updateBackbufferIndex(UINT index);
|
||||
|
||||
void createSyncObjects();
|
||||
void flushCommandQueue();
|
||||
|
||||
void updateViewport();
|
||||
|
||||
ID3D12PipelineState* getPipelineState() const;
|
||||
|
||||
DirectXInterface* mDxInterface{ nullptr };
|
||||
bool mInitialized{ false };
|
||||
bool mIsValid{ false };
|
||||
|
||||
mt::Window* mWindow{ nullptr };
|
||||
CD3DX12_VIEWPORT mViewport;
|
||||
CD3DX12_RECT mScissorRect;
|
||||
|
||||
std::unique_ptr<DirectXDescriptors> mDescriptors;
|
||||
std::unique_ptr<DirectX2dIntegration> mD2dIntegration;
|
||||
std::unique_ptr<DirectXBuffers> mBuffers;
|
||||
std::unique_ptr<DirectXCommandList> mCommandList;
|
||||
|
||||
Microsoft::WRL::ComPtr<IDXGISwapChain4> mSwapChain;
|
||||
|
||||
static const UINT FrameCount = 2;
|
||||
Microsoft::WRL::ComPtr<ID3D12Fence> mFence;
|
||||
uint64_t mFenceValue = 0;
|
||||
uint64_t mFrameFenceValues[FrameCount] = {};
|
||||
HANDLE mFenceEvent{};
|
||||
};
|
||||
|
||||
using XcbGlWindowInterfacePtr = std::unique_ptr<Win32DxWindowInterface>;
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue