diff --git a/Editor/AnimationWindow.cpp b/Editor/AnimationWindow.cpp index 28abf3a4c..f3f306ded 100644 --- a/Editor/AnimationWindow.cpp +++ b/Editor/AnimationWindow.cpp @@ -11,14 +11,14 @@ void AnimationWindow::Create(EditorComponent* editor) SetSize(XMFLOAT2(520, 140)); float x = 140; - float y = 10; + float y = 0; float hei = 18; float step = hei + 2; animationsComboBox.Create("Animation: "); animationsComboBox.SetSize(XMFLOAT2(300, hei)); - animationsComboBox.SetPos(XMFLOAT2(x, y += step)); + animationsComboBox.SetPos(XMFLOAT2(x, y)); animationsComboBox.SetEnabled(false); animationsComboBox.OnSelect([&](wi::gui::EventArgs args) { entity = wi::scene::GetScene().animations.GetEntity(args.iValue); diff --git a/Editor/CameraWindow.cpp b/Editor/CameraWindow.cpp index ab7cae4ff..3e4989f6a 100644 --- a/Editor/CameraWindow.cpp +++ b/Editor/CameraWindow.cpp @@ -37,14 +37,14 @@ void CameraWindow::Create(EditorComponent* editor) SetSize(XMFLOAT2(380, 360)); float x = 200; - float y = 10; + float y = 0; float hei = 18; float step = hei + 2; farPlaneSlider.Create(100, 10000, 5000, 100000, "Far Plane: "); farPlaneSlider.SetTooltip("Controls the camera's far clip plane, geometry farther than this will be clipped."); farPlaneSlider.SetSize(XMFLOAT2(100, hei)); - farPlaneSlider.SetPos(XMFLOAT2(x, y += step)); + farPlaneSlider.SetPos(XMFLOAT2(x, y)); farPlaneSlider.SetValue(wi::scene::GetCamera().zFarP); farPlaneSlider.OnSlide([&](wi::gui::EventArgs args) { Scene& scene = wi::scene::GetScene(); diff --git a/Editor/DecalWindow.cpp b/Editor/DecalWindow.cpp index 2e691aa4a..5c6515d3c 100644 --- a/Editor/DecalWindow.cpp +++ b/Editor/DecalWindow.cpp @@ -9,15 +9,15 @@ using namespace wi::scene; void DecalWindow::Create(EditorComponent* editor) { wi::gui::Window::Create("Decal Window"); - SetSize(XMFLOAT2(400, 200)); + SetSize(XMFLOAT2(420, 200)); float x = 200; - float y = 5; + float y = 0; float hei = 18; float step = hei + 2; placementCheckBox.Create("Decal Placement Enabled: "); - placementCheckBox.SetPos(XMFLOAT2(x, y += step)); + placementCheckBox.SetPos(XMFLOAT2(x, y)); placementCheckBox.SetSize(XMFLOAT2(hei, hei)); placementCheckBox.SetCheck(false); placementCheckBox.SetTooltip("Enable decal placement. Use the left mouse button to place decals to the scene."); diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index ac394d7d7..18a0fb7c5 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -1021,7 +1021,6 @@ void EditorComponent::Load() RecordSelection(archive); }); - sceneGraphView.SetColor(wi::Color(100, 100, 100, 100), wi::gui::IDLE); GetGUI().AddWidget(&sceneGraphView); diff --git a/Editor/EmitterWindow.cpp b/Editor/EmitterWindow.cpp index 82cbf520c..643f9a025 100644 --- a/Editor/EmitterWindow.cpp +++ b/Editor/EmitterWindow.cpp @@ -10,16 +10,16 @@ using namespace wi::scene; void EmitterWindow::Create(EditorComponent* editor) { wi::gui::Window::Create("Emitter Window"); - SetSize(XMFLOAT2(680, 720)); + SetSize(XMFLOAT2(680, 420)); float x = 200; - float y = 5; + float y = 0; float itemheight = 18; float step = itemheight + 2; emitterNameField.Create("EmitterName"); - emitterNameField.SetPos(XMFLOAT2(x, y += step)); + emitterNameField.SetPos(XMFLOAT2(x, y)); emitterNameField.SetSize(XMFLOAT2(300, itemheight)); emitterNameField.OnInputAccepted([=](wi::gui::EventArgs args) { NameComponent* name = wi::scene::GetScene().names.GetComponent(entity); diff --git a/Editor/EnvProbeWindow.cpp b/Editor/EnvProbeWindow.cpp index 8bbac511f..a6d0243d0 100644 --- a/Editor/EnvProbeWindow.cpp +++ b/Editor/EnvProbeWindow.cpp @@ -10,10 +10,10 @@ void EnvProbeWindow::Create(EditorComponent* editor) wi::gui::Window::Create("Environment Probe Window"); SetSize(XMFLOAT2(300, 200)); - float x = 100, y = 5, step = 35; + float x = 100, y = 0, step = 35; realTimeCheckBox.Create("RealTime: "); - realTimeCheckBox.SetPos(XMFLOAT2(x, y += step)); + realTimeCheckBox.SetPos(XMFLOAT2(x, y)); realTimeCheckBox.SetEnabled(false); realTimeCheckBox.OnClick([&](wi::gui::EventArgs args) { EnvironmentProbeComponent* probe = wi::scene::GetScene().probes.GetComponent(entity); diff --git a/Editor/ForceFieldWindow.cpp b/Editor/ForceFieldWindow.cpp index 81a4e9dc4..1a49c7699 100644 --- a/Editor/ForceFieldWindow.cpp +++ b/Editor/ForceFieldWindow.cpp @@ -12,13 +12,13 @@ void ForceFieldWindow::Create(EditorComponent* editor) SetSize(XMFLOAT2(420, 120)); float x = 150; - float y = 10; + float y = 0; float hei = 18; float step = hei + 2; addButton.Create("Add Force Field"); addButton.SetSize(XMFLOAT2(150, hei)); - addButton.SetPos(XMFLOAT2(x, y += step)); + addButton.SetPos(XMFLOAT2(x, y)); addButton.OnClick([=](wi::gui::EventArgs args) { Entity entity = wi::scene::GetScene().Entity_CreateForce("editorForce"); ForceFieldComponent* force = wi::scene::GetScene().forces.GetComponent(entity); diff --git a/Editor/HairParticleWindow.cpp b/Editor/HairParticleWindow.cpp index 036e0abda..e3444de6b 100644 --- a/Editor/HairParticleWindow.cpp +++ b/Editor/HairParticleWindow.cpp @@ -11,13 +11,13 @@ void HairParticleWindow::Create(EditorComponent* editor) SetSize(XMFLOAT2(600, 260)); float x = 160; - float y = 10; + float y = 0; float hei = 18; float step = hei + 2; addButton.Create("Add Hair Particle System"); - addButton.SetPos(XMFLOAT2(x, y += step)); + addButton.SetPos(XMFLOAT2(x, y)); addButton.SetSize(XMFLOAT2(200, hei)); addButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = wi::scene::GetScene(); diff --git a/Editor/IKWindow.cpp b/Editor/IKWindow.cpp index 9c58f3d9f..285966e1d 100644 --- a/Editor/IKWindow.cpp +++ b/Editor/IKWindow.cpp @@ -12,14 +12,14 @@ void IKWindow::Create(EditorComponent* editor) SetSize(XMFLOAT2(400, 150)); float x = 120; - float y = 10; + float y = 0; float siz = 200; float hei = 18; float step = hei + 2; createButton.Create("Create"); createButton.SetTooltip("Create/Remove IK Component to selected entity"); - createButton.SetPos(XMFLOAT2(x, y += step)); + createButton.SetPos(XMFLOAT2(x, y)); createButton.SetSize(XMFLOAT2(siz, hei)); AddWidget(&createButton); diff --git a/Editor/LayerWindow.cpp b/Editor/LayerWindow.cpp index df9092bf9..9e8dd71dc 100644 --- a/Editor/LayerWindow.cpp +++ b/Editor/LayerWindow.cpp @@ -9,10 +9,10 @@ using namespace wi::scene; void LayerWindow::Create(EditorComponent* editor) { wi::gui::Window::Create("Layer Window"); - SetSize(XMFLOAT2(410, 290)); + SetSize(XMFLOAT2(420, 290)); float x = 30; - float y = 25; + float y = 0; float step = 25; float siz = 20; diff --git a/Editor/LightWindow.cpp b/Editor/LightWindow.cpp index 9f98d653e..27813c6d0 100644 --- a/Editor/LightWindow.cpp +++ b/Editor/LightWindow.cpp @@ -12,16 +12,16 @@ using namespace wi::scene; void LightWindow::Create(EditorComponent* editor) { wi::gui::Window::Create("Light Window"); - SetSize(XMFLOAT2(650, 500)); + SetSize(XMFLOAT2(650, 300)); float x = 450; - float y = 20; + float y = 0; float hei = 18; float step = hei + 2; energySlider.Create(0.1f, 64, 0, 100000, "Energy: "); energySlider.SetSize(XMFLOAT2(100, hei)); - energySlider.SetPos(XMFLOAT2(x, y += step)); + energySlider.SetPos(XMFLOAT2(x, y)); energySlider.OnSlide([&](wi::gui::EventArgs args) { LightComponent* light = wi::scene::GetScene().lights.GetComponent(entity); if (light != nullptr) diff --git a/Editor/MaterialWindow.cpp b/Editor/MaterialWindow.cpp index 838119040..7d0c294ec 100644 --- a/Editor/MaterialWindow.cpp +++ b/Editor/MaterialWindow.cpp @@ -9,15 +9,15 @@ using namespace wi::scene; void MaterialWindow::Create(EditorComponent* editor) { wi::gui::Window::Create("Material Window"); - SetSize(XMFLOAT2(720, 620)); + SetSize(XMFLOAT2(730, 620)); - float x = 670, y = 0; float hei = 18; float step = hei + 2; + float x = 670, y = 0; shadowReceiveCheckBox.Create("Receive Shadow: "); shadowReceiveCheckBox.SetTooltip("Receives shadow or not?"); - shadowReceiveCheckBox.SetPos(XMFLOAT2(540, y += step)); + shadowReceiveCheckBox.SetPos(XMFLOAT2(540, y)); shadowReceiveCheckBox.SetSize(XMFLOAT2(hei, hei)); shadowReceiveCheckBox.OnClick([&](wi::gui::EventArgs args) { MaterialComponent* material = wi::scene::GetScene().materials.GetComponent(entity); @@ -426,14 +426,14 @@ void MaterialWindow::Create(EditorComponent* editor) // - x = 10; - y = 0; hei = 20; step = hei + 2; + x = 10; + y = 0; materialNameField.Create("MaterialName"); materialNameField.SetTooltip("Set a name for the material..."); - materialNameField.SetPos(XMFLOAT2(10, y += step)); + materialNameField.SetPos(XMFLOAT2(10, y)); materialNameField.SetSize(XMFLOAT2(300, hei)); materialNameField.OnInputAccepted([=](wi::gui::EventArgs args) { NameComponent* name = wi::scene::GetScene().names.GetComponent(entity); diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index 9f1343814..b7602a111 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -14,7 +14,7 @@ using namespace wi::scene; void MeshWindow::Create(EditorComponent* editor) { wi::gui::Window::Create("Mesh Window"); - SetSize(XMFLOAT2(580, 580)); + SetSize(XMFLOAT2(580, 380)); float x = 150; float y = 0; @@ -23,17 +23,17 @@ void MeshWindow::Create(EditorComponent* editor) float infolabel_height = 190; meshInfoLabel.Create("Mesh Info"); - meshInfoLabel.SetPos(XMFLOAT2(x - 50, y += step)); + meshInfoLabel.SetPos(XMFLOAT2(x - 50, y)); meshInfoLabel.SetSize(XMFLOAT2(450, infolabel_height)); meshInfoLabel.SetColor(wi::Color::Transparent()); AddWidget(&meshInfoLabel); // Left side: - y = infolabel_height + 10; + y = infolabel_height + 5; subsetComboBox.Create("Selected subset: "); subsetComboBox.SetSize(XMFLOAT2(40, hei)); - subsetComboBox.SetPos(XMFLOAT2(x, y += step)); + subsetComboBox.SetPos(XMFLOAT2(x, y)); subsetComboBox.SetEnabled(false); subsetComboBox.OnSelect([=](wi::gui::EventArgs args) { Scene& scene = wi::scene::GetScene(); @@ -474,11 +474,11 @@ void MeshWindow::Create(EditorComponent* editor) // Right side: x = 150; - y = infolabel_height + 10; + y = infolabel_height + 5; subsetMaterialComboBox.Create("Subset Material: "); subsetMaterialComboBox.SetSize(XMFLOAT2(200, hei)); - subsetMaterialComboBox.SetPos(XMFLOAT2(x + 180, y += step)); + subsetMaterialComboBox.SetPos(XMFLOAT2(x + 180, y)); subsetMaterialComboBox.SetEnabled(false); subsetMaterialComboBox.OnSelect([&](wi::gui::EventArgs args) { Scene& scene = wi::scene::GetScene(); diff --git a/Editor/NameWindow.cpp b/Editor/NameWindow.cpp index 27e1105dd..d5a6e32c1 100644 --- a/Editor/NameWindow.cpp +++ b/Editor/NameWindow.cpp @@ -19,7 +19,7 @@ void NameWindow::Create(EditorComponent* editor) nameInput.Create(""); nameInput.SetDescription("Name: "); - nameInput.SetPos(XMFLOAT2(x, y += step)); + nameInput.SetPos(XMFLOAT2(x, y)); nameInput.SetSize(XMFLOAT2(siz, hei)); nameInput.OnInputAccepted([=](wi::gui::EventArgs args) { NameComponent* name = wi::scene::GetScene().names.GetComponent(entity); diff --git a/Editor/ObjectWindow.cpp b/Editor/ObjectWindow.cpp index fd4738347..5efe2058c 100644 --- a/Editor/ObjectWindow.cpp +++ b/Editor/ObjectWindow.cpp @@ -261,7 +261,7 @@ void ObjectWindow::Create(EditorComponent* editor) this->editor = editor; wi::gui::Window::Create("Object Window"); - SetSize(XMFLOAT2(660, 520)); + SetSize(XMFLOAT2(670, 320)); float x = 200; float y = 0; @@ -270,7 +270,7 @@ void ObjectWindow::Create(EditorComponent* editor) nameLabel.Create("NAMELABEL"); nameLabel.SetText(""); - nameLabel.SetPos(XMFLOAT2(x - 30, y += step)); + nameLabel.SetPos(XMFLOAT2(x - 30, y)); nameLabel.SetSize(XMFLOAT2(150, hei)); AddWidget(&nameLabel); diff --git a/Editor/PaintToolWindow.cpp b/Editor/PaintToolWindow.cpp index ab9bdb62f..5435a48a2 100644 --- a/Editor/PaintToolWindow.cpp +++ b/Editor/PaintToolWindow.cpp @@ -14,16 +14,16 @@ void PaintToolWindow::Create(EditorComponent* editor) this->editor = editor; wi::gui::Window::Create("Paint Tool Window"); - SetSize(XMFLOAT2(400, 600)); + SetSize(XMFLOAT2(410, 610)); float x = 100; - float y = 5; + float y = 0; float hei = 20; float step = hei + 4; modeComboBox.Create("Mode: "); modeComboBox.SetTooltip("Choose paint tool mode"); - modeComboBox.SetPos(XMFLOAT2(x, y += step)); + modeComboBox.SetPos(XMFLOAT2(x, y)); modeComboBox.SetSize(XMFLOAT2(200, hei)); modeComboBox.AddItem("Disabled"); modeComboBox.AddItem("Texture"); diff --git a/Editor/PostprocessWindow.cpp b/Editor/PostprocessWindow.cpp index 33575c8e6..ce4975def 100644 --- a/Editor/PostprocessWindow.cpp +++ b/Editor/PostprocessWindow.cpp @@ -9,10 +9,10 @@ using namespace wi::graphics; void PostprocessWindow::Create(EditorComponent* editor) { wi::gui::Window::Create("PostProcess Window"); - SetSize(XMFLOAT2(420, 500)); + SetSize(XMFLOAT2(420, 400)); float x = 150; - float y = 10; + float y = 0; float hei = 18; float step = hei + 2; @@ -20,7 +20,7 @@ void PostprocessWindow::Create(EditorComponent* editor) exposureSlider.SetTooltip("Set the tonemap exposure value"); exposureSlider.SetScriptTip("RenderPath3D::SetExposure(float value)"); exposureSlider.SetSize(XMFLOAT2(100, hei)); - exposureSlider.SetPos(XMFLOAT2(x, y += step)); + exposureSlider.SetPos(XMFLOAT2(x, y)); exposureSlider.SetValue(editor->renderPath->getExposure()); exposureSlider.OnSlide([=](wi::gui::EventArgs args) { editor->renderPath->setExposure(args.fValue); diff --git a/Editor/RendererWindow.cpp b/Editor/RendererWindow.cpp index 7c3e1fce4..af0c72ea7 100644 --- a/Editor/RendererWindow.cpp +++ b/Editor/RendererWindow.cpp @@ -11,14 +11,15 @@ void RendererWindow::Create(EditorComponent* editor) wi::renderer::SetToDrawGridHelper(true); wi::renderer::SetToDrawDebugCameras(true); - SetSize(XMFLOAT2(580, 600)); + SetSize(XMFLOAT2(580, 400)); - float x = 220, y = 5, step = 20, itemheight = 18; + float step = 20, itemheight = 18; + float x = 220, y = 0; vsyncCheckBox.Create("VSync: "); vsyncCheckBox.SetTooltip("Toggle vertical sync"); vsyncCheckBox.SetScriptTip("SetVSyncEnabled(opt bool enabled)"); - vsyncCheckBox.SetPos(XMFLOAT2(x, y += step)); + vsyncCheckBox.SetPos(XMFLOAT2(x, y)); vsyncCheckBox.SetSize(XMFLOAT2(itemheight, itemheight)); vsyncCheckBox.SetCheck(editor->main->swapChain.desc.vsync); vsyncCheckBox.OnClick([=](wi::gui::EventArgs args) { @@ -529,11 +530,11 @@ void RendererWindow::Create(EditorComponent* editor) // Visualizer toggles: - x = 540, y = 5; + x = 540, y = 0; physicsDebugCheckBox.Create("Physics visualizer: "); physicsDebugCheckBox.SetTooltip("Visualize the physics world"); - physicsDebugCheckBox.SetPos(XMFLOAT2(x, y += step)); + physicsDebugCheckBox.SetPos(XMFLOAT2(x, y)); physicsDebugCheckBox.SetSize(XMFLOAT2(itemheight, itemheight)); physicsDebugCheckBox.OnClick([](wi::gui::EventArgs args) { wi::physics::SetDebugDrawEnabled(args.bValue); diff --git a/Editor/SoundWindow.cpp b/Editor/SoundWindow.cpp index 66993a548..c408795b7 100644 --- a/Editor/SoundWindow.cpp +++ b/Editor/SoundWindow.cpp @@ -13,12 +13,12 @@ void SoundWindow::Create(EditorComponent* editor) SetSize(XMFLOAT2(440, 220)); float x = 20; - float y = 10; + float y = 0; float hei = 18; float step = hei + 2; reverbComboBox.Create("Reverb: "); - reverbComboBox.SetPos(XMFLOAT2(x + 80, y += step)); + reverbComboBox.SetPos(XMFLOAT2(x + 80, y)); reverbComboBox.SetSize(XMFLOAT2(180, hei)); reverbComboBox.OnSelect([&](wi::gui::EventArgs args) { wi::audio::SetReverb((wi::audio::REVERB_PRESET)args.iValue); diff --git a/Editor/SpringWindow.cpp b/Editor/SpringWindow.cpp index ba44ca7db..0e3a36f1a 100644 --- a/Editor/SpringWindow.cpp +++ b/Editor/SpringWindow.cpp @@ -12,14 +12,14 @@ void SpringWindow::Create(EditorComponent* editor) SetSize(XMFLOAT2(460, 200)); float x = 150; - float y = 10; + float y = 0; float siz = 200; float hei = 18; float step = hei + 2; createButton.Create("Create"); createButton.SetTooltip("Create/Remove Spring Component to selected entity"); - createButton.SetPos(XMFLOAT2(x, y += step)); + createButton.SetPos(XMFLOAT2(x, y)); createButton.SetSize(XMFLOAT2(siz, hei)); AddWidget(&createButton); diff --git a/Editor/TerrainGenerator.cpp b/Editor/TerrainGenerator.cpp index 4bb4a5657..4814aad75 100644 --- a/Editor/TerrainGenerator.cpp +++ b/Editor/TerrainGenerator.cpp @@ -172,7 +172,7 @@ void TerrainGenerator::init() centerToCamCheckBox.Create("Center to Cam: "); centerToCamCheckBox.SetTooltip("Automatically generate chunks around camera. This sets the center chunk to camera position."); centerToCamCheckBox.SetSize(XMFLOAT2(hei, hei)); - centerToCamCheckBox.SetPos(XMFLOAT2(x, y += step)); + centerToCamCheckBox.SetPos(XMFLOAT2(x, y)); centerToCamCheckBox.SetCheck(true); AddWidget(¢erToCamCheckBox); diff --git a/Editor/TransformWindow.cpp b/Editor/TransformWindow.cpp index ebe0799d3..8abeca67d 100644 --- a/Editor/TransformWindow.cpp +++ b/Editor/TransformWindow.cpp @@ -9,7 +9,7 @@ using namespace wi::scene; void TransformWindow::Create(EditorComponent* editor) { wi::gui::Window::Create("Transform Window"); - SetSize(XMFLOAT2(460, 180)); + SetSize(XMFLOAT2(480, 200)); float x = 100; float y = 0; @@ -19,7 +19,7 @@ void TransformWindow::Create(EditorComponent* editor) createButton.Create("Create New Transform"); createButton.SetTooltip("Create a new entity with only a trasform component"); - createButton.SetPos(XMFLOAT2(x, y += step)); + createButton.SetPos(XMFLOAT2(x, y)); createButton.SetSize(XMFLOAT2(350, hei)); createButton.OnClick([=](wi::gui::EventArgs args) { Entity entity = CreateEntity(); diff --git a/Editor/WeatherWindow.cpp b/Editor/WeatherWindow.cpp index d2fc8fd8d..905312343 100644 --- a/Editor/WeatherWindow.cpp +++ b/Editor/WeatherWindow.cpp @@ -12,14 +12,14 @@ void WeatherWindow::Create(EditorComponent* editor) SetSize(XMFLOAT2(660, 680)); float x = 180; - float y = 20; + float y = 0; float hei = 18; float step = hei + 2; heightFogCheckBox.Create("Height fog: "); heightFogCheckBox.SetSize(XMFLOAT2(hei, hei)); - heightFogCheckBox.SetPos(XMFLOAT2(x + 100, y += step)); + heightFogCheckBox.SetPos(XMFLOAT2(x + 100, y)); heightFogCheckBox.OnClick([&](wi::gui::EventArgs args) { auto& weather = GetWeather(); weather.SetHeightFog(args.bValue); @@ -396,11 +396,11 @@ void WeatherWindow::Create(EditorComponent* editor) x = 340; - y = 20; + y = 0; colorComboBox.Create("Color picker mode: "); colorComboBox.SetSize(XMFLOAT2(120, hei)); - colorComboBox.SetPos(XMFLOAT2(x + 150, y += step)); + colorComboBox.SetPos(XMFLOAT2(x + 150, y)); colorComboBox.AddItem("Ambient color"); colorComboBox.AddItem("Horizon color"); colorComboBox.AddItem("Zenith color"); diff --git a/WickedEngine/wiGUI.cpp b/WickedEngine/wiGUI.cpp index c4d0f8745..f4cdf1ba6 100644 --- a/WickedEngine/wiGUI.cpp +++ b/WickedEngine/wiGUI.cpp @@ -197,6 +197,11 @@ namespace wi::gui sprites[i].params.blendFlag = wi::enums::BLENDMODE_OPAQUE; sprites[i].params.enableBackground(); } + + active_area.pos.x = 0; + active_area.pos.y = 0; + active_area.siz.x = std::numeric_limits::max(); + active_area.siz.y = std::numeric_limits::max(); } void Widget::Update(const wi::Canvas& canvas, float dt) { @@ -233,10 +238,10 @@ namespace wi::gui XMStoreFloat3(&translation, T); XMStoreFloat3(&scale, S); - scissorRect.bottom = (int32_t)(translation.y + scale.y); - scissorRect.left = (int32_t)(translation.x); - scissorRect.right = (int32_t)(translation.x + scale.x); - scissorRect.top = (int32_t)(translation.y); + scissorRect.bottom = (int32_t)std::ceil(translation.y + scale.y); + scissorRect.left = (int32_t)std::floor(translation.x); + scissorRect.right = (int32_t)std::ceil(translation.x + scale.x); + scissorRect.top = (int32_t)std::floor(translation.y); // default sprite and font placement: for (int i = IDLE; i < WIDGETSTATE_COUNT; ++i) @@ -508,7 +513,36 @@ namespace wi::gui Hitbox2D Widget::GetPointerHitbox() const { XMFLOAT4 pointer = wi::input::GetPointer(); - return Hitbox2D(XMFLOAT2(pointer.x, pointer.y), XMFLOAT2(1, 1)); + Hitbox2D hb = Hitbox2D(XMFLOAT2(pointer.x, pointer.y), XMFLOAT2(1, 1)); + HitboxConstrain(hb); // this is used to filter out pointer outside of active_area (outside of scissor basically) + return hb; + } + void Widget::HitboxConstrain(wi::primitive::Hitbox2D& hb) const + { + float left = hb.pos.x; + float right = hb.pos.x + hb.siz.x; + float top = hb.pos.y; + float bottom = hb.pos.y + hb.siz.y; + + float area_left = active_area.pos.x; + float area_right = active_area.pos.x + active_area.siz.x; + float area_top = active_area.pos.y; + float area_bottom = active_area.pos.y + active_area.siz.y; + + bottom = std::min(bottom, area_bottom); + top = std::max(top, area_top); + left = std::max(left, area_left); + right = std::min(right, area_right); + + hb.pos.x = left; + hb.pos.y = top; + hb.siz.x = std::max(0.0f, right - left); + hb.siz.y = std::max(0.0f, bottom - top); + + if (parent != nullptr) + { + parent->HitboxConstrain(hb); + } } @@ -994,10 +1028,10 @@ namespace wi::gui valueInputField.SetPos(XMFLOAT2(translation.x + scale.x + 2, translation.y)); valueInputField.AttachTo(this); - scissorRect.bottom = (int32_t)(translation.y + scale.y); - scissorRect.left = (int32_t)(translation.x); - scissorRect.right = (int32_t)(translation.x + scale.x + 20 + scale.y * 2); // include the valueInputField - scissorRect.top = (int32_t)(translation.y); + scissorRect.bottom = (int32_t)std::ceil(translation.y + scale.y); + scissorRect.left = (int32_t)std::floor(translation.x); + scissorRect.right = (int32_t)std::ceil(translation.x + scale.x + 20 + scale.y * 2); // include the valueInputField + scissorRect.top = (int32_t)std::floor(translation.y); for (int i = 0; i < WIDGETSTATE_COUNT; ++i) { @@ -1683,6 +1717,179 @@ namespace wi::gui + void ScrollBar::Update(const wi::Canvas& canvas, float dt) + { + if (!IsVisible()) + { + return; + } + + Widget::Update(canvas, dt); + + if (scale.x > scale.y) + { + vertical = false; + } + else + { + vertical = true; + } + + if (IsEnabled()) + { + if (state == FOCUS) + { + state = IDLE; + } + if (state == DEACTIVATING) + { + state = IDLE; + } + if (state == ACTIVE) + { + Deactivate(); + } + + Hitbox2D hitbox = Hitbox2D(XMFLOAT2(translation.x, translation.y), XMFLOAT2(scale.x, scale.y)); + Hitbox2D pointerHitbox = GetPointerHitbox(); + + if (state == IDLE && hitbox.intersects(pointerHitbox)) + { + state = FOCUS; + } + + bool clicked = false; + if (wi::input::Press(wi::input::MOUSE_BUTTON_LEFT)) + { + clicked = true; + } + + bool click_down = false; + if (wi::input::Down(wi::input::MOUSE_BUTTON_LEFT)) + { + click_down = true; + if (state == FOCUS || state == DEACTIVATING) + { + // Keep pressed until mouse is released + Activate(); + } + } + float scrollbar_begin; + float scrollbar_end; + float scrollbar_size; + + if (vertical) + { + scrollbar_begin = translation.y; + scrollbar_end = scrollbar_begin + scale.y; + scrollbar_size = scrollbar_end - scrollbar_begin; + scrollbar_granularity = std::min(1.0f, scrollbar_size / std::max(1.0f, list_length)); + scrollbar_length = std::max(scale.x * 2, scrollbar_size * scrollbar_granularity); + } + else + { + scrollbar_begin = translation.x; + scrollbar_end = scrollbar_begin + scale.x; + scrollbar_size = scrollbar_end - scrollbar_begin; + scrollbar_granularity = std::min(1.0f, scrollbar_size / std::max(1.0f, list_length)); + scrollbar_length = std::max(scale.y * 2, scrollbar_size * scrollbar_granularity); + } + + if (!click_down) + { + scrollbar_state = SCROLLBAR_INACTIVE; + } + + if (IsScrollbarRequired() && hitbox.intersects(pointerHitbox)) + { + if (clicked) + { + scrollbar_state = SCROLLBAR_GRABBED; + grab_pos = pointerHitbox.pos; + grab_pos.x = wi::math::Clamp(grab_pos.x, scrollbar_begin + scrollbar_delta, scrollbar_begin + scrollbar_delta + scrollbar_length); + grab_pos.y = wi::math::Clamp(grab_pos.y, scrollbar_begin + scrollbar_delta, scrollbar_begin + scrollbar_delta + scrollbar_length); + grab_delta = scrollbar_delta; + } + else if (!click_down) + { + scrollbar_state = SCROLLBAR_HOVER; + state = FOCUS; + } + } + + if (scrollbar_state == SCROLLBAR_GRABBED) + { + Activate(); + if (vertical) + { + scrollbar_delta = grab_delta + pointerHitbox.pos.y - grab_pos.y; + } + else + { + scrollbar_delta = grab_delta + pointerHitbox.pos.x - grab_pos.x; + } + } + + scrollbar_delta = wi::math::Clamp(scrollbar_delta, 0, scrollbar_size - scrollbar_length); + if (scrollbar_begin < scrollbar_end - scrollbar_length) + { + scrollbar_value = wi::math::InverseLerp(scrollbar_begin, scrollbar_end - scrollbar_length, scrollbar_begin + scrollbar_delta); + } + else + { + scrollbar_value = 0; + } + + list_offset = -scrollbar_value * (list_length - scrollbar_size * (1.0f - overscroll)); + } + + if (vertical) + { + for (int i = 0; i < arraysize(sprites_knob); ++i) + { + sprites_knob[i].params.pos.x = translation.x + knob_inset_border.x; + sprites_knob[i].params.pos.y = translation.y + knob_inset_border.y + scrollbar_delta; + sprites_knob[i].params.siz.x = scale.x - knob_inset_border.x * 2; + sprites_knob[i].params.siz.y = scrollbar_length - knob_inset_border.y * 2; + } + } + else + { + for (int i = 0; i < arraysize(sprites_knob); ++i) + { + sprites_knob[i].params.pos.x = translation.x + knob_inset_border.x + scrollbar_delta; + sprites_knob[i].params.pos.y = translation.y + knob_inset_border.y; + sprites_knob[i].params.siz.x = scrollbar_length - knob_inset_border.x * 2; + sprites_knob[i].params.siz.y = scale.y - knob_inset_border.y * 2; + } + } + } + void ScrollBar::Render(const wi::Canvas& canvas, CommandList cmd) const + { + if (!IsVisible()) + { + return; + } + if (!IsScrollbarRequired()) + return; + + // scrollbar background + wi::image::Params fx = sprites[state].params; + fx.pos = XMFLOAT3(translation.x, translation.y, 0); + fx.siz = XMFLOAT2(scale.x, scale.y); + fx.color = sprites[IDLE].params.color; + wi::image::Draw(wi::texturehelper::getWhite(), fx, cmd); + + // scrollbar knob + sprites_knob[scrollbar_state].Draw(cmd); + + } + + + + + + static const float windowcontrolSize = 20.0f; void Window::Create(const std::string& name, bool window_controls) { @@ -1760,6 +1967,20 @@ namespace wi::gui }); minimizeButton.SetTooltip("Minimize window"); AddWidget(&minimizeButton); + + scrollbar_horizontal.SetColor(wi::Color(80, 80, 80, 100), wi::gui::IDLE); + scrollbar_horizontal.sprites_knob[ScrollBar::SCROLLBAR_INACTIVE].params.color = wi::Color(140, 140, 140, 140); + scrollbar_horizontal.sprites_knob[ScrollBar::SCROLLBAR_HOVER].params.color = wi::Color(180, 180, 180, 180); + scrollbar_horizontal.sprites_knob[ScrollBar::SCROLLBAR_GRABBED].params.color = wi::Color::White(); + scrollbar_horizontal.knob_inset_border = XMFLOAT2(2, 4); + AddWidget(&scrollbar_horizontal); + + scrollbar_vertical.SetColor(wi::Color(80, 80, 80, 100), wi::gui::IDLE); + scrollbar_vertical.sprites_knob[ScrollBar::SCROLLBAR_INACTIVE].params.color = wi::Color(140, 140, 140, 140); + scrollbar_vertical.sprites_knob[ScrollBar::SCROLLBAR_HOVER].params.color = wi::Color(180, 180, 180, 180); + scrollbar_vertical.sprites_knob[ScrollBar::SCROLLBAR_GRABBED].params.color = wi::Color::White(); + scrollbar_vertical.knob_inset_border = XMFLOAT2(4, 2); + AddWidget(&scrollbar_vertical); } else { @@ -1775,11 +1996,18 @@ namespace wi::gui SetVisible(true); SetMinimized(false); } - void Window::AddWidget(Widget* widget) + void Window::AddWidget(Widget* widget, bool scrollable) { widget->SetEnabled(this->IsEnabled()); widget->SetVisible(this->IsVisible()); - widget->AttachTo(this); + if (scrollable) + { + widget->AttachTo(&scrollable_area); + } + else + { + widget->AttachTo(this); + } widgets.push_back(widget); } @@ -1809,10 +2037,14 @@ namespace wi::gui moveDragger.force_disable = force_disable; resizeDragger_UpperLeft.force_disable = force_disable; resizeDragger_BottomRight.force_disable = force_disable; + scrollbar_horizontal.force_disable = force_disable; + scrollbar_vertical.force_disable = force_disable; moveDragger.Update(canvas, dt); resizeDragger_UpperLeft.Update(canvas, dt); resizeDragger_BottomRight.Update(canvas, dt); + scrollbar_horizontal.Update(canvas, dt); + scrollbar_vertical.Update(canvas, dt); // Don't allow moving outside of screen: if (parent == nullptr) @@ -1866,14 +2098,70 @@ namespace wi::gui label.SetPos(XMFLOAT2(translation.x, translation.y)); label.AttachTo(this); } + if (scrollbar_horizontal.parent != nullptr) + { + scrollbar_horizontal.Detach(); + scrollbar_horizontal.SetSize(XMFLOAT2(scale.x - windowcontrolSize, windowcontrolSize)); + scrollbar_horizontal.SetPos(XMFLOAT2(translation.x, translation.y + scale.y - windowcontrolSize)); + scrollbar_horizontal.AttachTo(this); + } + if (scrollbar_vertical.parent != nullptr) + { + scrollbar_vertical.Detach(); + scrollbar_vertical.SetSize(XMFLOAT2(windowcontrolSize, scale.y - 2 - windowcontrolSize * 2)); + scrollbar_vertical.SetPos(XMFLOAT2(translation.x + scale.x - windowcontrolSize, translation.y + 1 + windowcontrolSize)); + scrollbar_vertical.AttachTo(this); + } Hitbox2D pointerHitbox = GetPointerHitbox(); uint32_t priority = 0; + // Compute scrollable area: + float scroll_length_horizontal = 0; + float scroll_length_vertical = 0; + for (auto& widget : widgets) + { + if (widget->parent == &scrollable_area) + { + scroll_length_horizontal = std::max(scroll_length_horizontal, widget->translation_local.x + widget->scale_local.x); + scroll_length_vertical = std::max(scroll_length_vertical, widget->translation_local.y + widget->scale_local.y); + } + } + scrollbar_horizontal.SetListLength(scroll_length_horizontal); + scrollbar_vertical.SetListLength(scroll_length_vertical); + scrollable_area.Detach(); + scrollable_area.ClearTransform(); + scrollable_area.Translate(translation); + scrollable_area.Translate(XMFLOAT3(scrollbar_horizontal.GetOffset(), windowcontrolSize + 1 + scrollbar_vertical.GetOffset(), 0)); + scrollable_area.Update(canvas, dt); + scrollable_area.AttachTo(this); + scrollable_area.scissorRect = scissorRect; + scrollable_area.scissorRect.left += 1; + scrollable_area.scissorRect.top += (int32_t)windowcontrolSize + 1; + if (scrollbar_horizontal.parent != nullptr && scrollbar_horizontal.IsScrollbarRequired()) + { + scrollable_area.scissorRect.bottom -= (int32_t)windowcontrolSize + 1; + } + if (scrollbar_vertical.parent != nullptr && scrollbar_vertical.IsScrollbarRequired()) + { + scrollable_area.scissorRect.right -= (int32_t)windowcontrolSize + 1; + } + scrollable_area.active_area.pos.x = float(scrollable_area.scissorRect.left); + scrollable_area.active_area.pos.y = float(scrollable_area.scissorRect.top); + scrollable_area.active_area.siz.x = float(scrollable_area.scissorRect.right) - float(scrollable_area.scissorRect.left); + scrollable_area.active_area.siz.y = float(scrollable_area.scissorRect.bottom) - float(scrollable_area.scissorRect.top); + + bool focus = false; for (auto& widget : widgets) { + // Don't update these again: + if (widget == &scrollbar_horizontal) + continue; + if (widget == &scrollbar_vertical) + continue; + widget->force_disable = force_disable || focus; widget->Update(canvas, dt); widget->force_disable = false; @@ -1888,10 +2176,6 @@ namespace wi::gui widget->priority = ~0u; } - if (widget->IsVisible() && widget->hitBox.intersects(pointerHitbox)) - { - focus = true; - } if (widget->GetState() > IDLE) { focus = true; @@ -1904,6 +2188,12 @@ namespace wi::gui return a->priority < b->priority; }); + if (pointerHitbox.intersects(hitBox) && !force_disable && !focus) // when window is in focus, but other widgets aren't + { + // This is outside scrollbar code, because it can also be scrolled if parent widget is only in focus + scrollbar_vertical.Scroll(wi::input::GetPointer().z * 20); + } + if (IsMinimized()) { hitBox.siz.y = windowcontrolSize; @@ -1987,10 +2277,28 @@ namespace wi::gui for (size_t i = 0; i < widgets.size(); ++i) { const Widget* widget = widgets[widgets.size() - i - 1]; - ApplyScissor(canvas, scissorRect, cmd); + if (widget->parent == nullptr) + { + ApplyScissor(canvas, scissorRect, cmd); + } + else + { + ApplyScissor(canvas, widget->parent->scissorRect, cmd); + } widget->Render(canvas, cmd); } + + //Rect scissorRect; + //scissorRect.bottom = (int32_t)(canvas.GetPhysicalHeight()); + //scissorRect.left = (int32_t)(0); + //scissorRect.right = (int32_t)(canvas.GetPhysicalWidth()); + //scissorRect.top = (int32_t)(0); + //GraphicsDevice* device = wi::graphics::GetDevice(); + //device->BindScissorRects(1, &scissorRect, cmd); + //wi::image::Draw(wi::texturehelper::getWhite(), wi::image::Params(scrollable_area.active_area.pos.x, scrollable_area.active_area.pos.y, scrollable_area.active_area.siz.x, scrollable_area.active_area.siz.y, wi::Color(255,0,255,100)), cmd); + //Hitbox2D p = scrollable_area.GetPointerHitbox(); + //wi::image::Draw(wi::texturehelper::getWhite(), wi::image::Params(p.pos.x, p.pos.y, p.siz.x * 10, p.siz.y * 10, wi::Color(255,0,0,100)), cmd); } void Window::RenderTooltip(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const { @@ -2024,6 +2332,10 @@ namespace wi::gui continue; if (x == &resizeDragger_BottomRight) continue; + if (x == &scrollbar_horizontal) + continue; + if (x == &scrollbar_vertical) + continue; x->SetEnabled(value); } } @@ -2178,7 +2490,7 @@ namespace wi::gui SetColor(wi::Color(100, 100, 100, 100)); float x = 250; - float y = 110; + float y = 100; float step = 20; text_R.Create("R"); @@ -2261,7 +2573,7 @@ namespace wi::gui AddWidget(&text_V); alphaSlider.Create(0, 255, 255, 255, ""); - alphaSlider.SetPos(XMFLOAT2(20, 230)); + alphaSlider.SetPos(XMFLOAT2(20, y)); alphaSlider.SetSize(XMFLOAT2(150, 18)); alphaSlider.SetText("A: "); alphaSlider.SetTooltip("Value for ALPHA - TRANSPARENCY channel (0-255)"); @@ -2747,7 +3059,7 @@ namespace wi::gui { XMStoreFloat4x4(&cb.g_xTransform, XMMatrixScaling(sca, sca, 1) * - XMMatrixTranslation(translation.x + scale.x - 40 * sca, translation.y + 40, 0) * + XMMatrixTranslation(translation.x + scale.x - 40 * sca, translation.y + 50, 0) * Projection ); cb.g_xColor = final_color.toFloat4(); @@ -2808,37 +3120,46 @@ namespace wi::gui - - constexpr float item_height() { return 20.0f; } - constexpr float tree_scrollbar_width() { return 12.0f; } void TreeList::Create(const std::string& name) { SetName(name); SetText(name); OnSelect([](EventArgs args) {}); - SetSize(XMFLOAT2(100, 20)); + SetColor(wi::Color(100, 100, 100, 100), wi::gui::IDLE); for (int i = FOCUS + 1; i < WIDGETSTATE_COUNT; ++i) { sprites[i].params.color = sprites[FOCUS].params.color; + scrollbar.sprites[i].params.color = sprites[FOCUS].params.color; } font.params.v_align = wi::font::WIFALIGN_CENTER; + + scrollbar.SetColor(wi::Color(80, 80, 80, 100), wi::gui::IDLE); + scrollbar.sprites_knob[ScrollBar::SCROLLBAR_INACTIVE].params.color = wi::Color(140, 140, 140, 140); + scrollbar.sprites_knob[ScrollBar::SCROLLBAR_HOVER].params.color = wi::Color(180, 180, 180, 180); + scrollbar.sprites_knob[ScrollBar::SCROLLBAR_GRABBED].params.color = wi::Color::White(); + scrollbar.SetOverScroll(0.25f); } float TreeList::GetItemOffset(int index) const { - return 2 + list_offset + index * item_height(); + return 2 + scrollbar.GetOffset() + index * item_height(); } Hitbox2D TreeList::GetHitbox_ListArea() const { - return Hitbox2D(XMFLOAT2(translation.x, translation.y + item_height() + 1), XMFLOAT2(scale.x - tree_scrollbar_width() - 1, scale.y - item_height() - 1)); + Hitbox2D retval = Hitbox2D(XMFLOAT2(translation.x, translation.y + item_height() + 1), XMFLOAT2(scale.x, scale.y - item_height() - 1)); + if (scrollbar.IsScrollbarRequired()) + { + retval.siz.x -= scrollbar.scale.x + 1; + } + return retval; } Hitbox2D TreeList::GetHitbox_Item(int visible_count, int level) const { XMFLOAT2 pos = XMFLOAT2(translation.x + 2 + level * item_height(), translation.y + GetItemOffset(visible_count) + item_height() * 0.5f); Hitbox2D hitbox; hitbox.pos = XMFLOAT2(pos.x + item_height() * 0.5f + 2, pos.y - item_height() * 0.5f); - hitbox.siz = XMFLOAT2(scale.x - 2 - item_height() * 0.5f - 2 - level * item_height() - tree_scrollbar_width() - 2, item_height()); + hitbox.siz = XMFLOAT2(scale.x - 2 - item_height() * 0.5f - 2 - level * item_height() - scrollbar.scale.x - 2, item_height()); return hitbox; } Hitbox2D TreeList::GetHitbox_ItemOpener(int visible_count, int level) const @@ -2900,7 +3221,7 @@ namespace wi::gui } // compute control-list height - list_height = 0; + float scroll_length = 0; { int parent_level = 0; bool parent_open = true; @@ -2912,65 +3233,32 @@ namespace wi::gui } parent_open = item.open; parent_level = item.level; - list_height += item_height(); + scroll_length += item_height(); } } + scrollbar.SetListLength(scroll_length); - const float scrollbar_begin = translation.y + item_height(); - const float scrollbar_end = scrollbar_begin + scale.y - item_height(); - const float scrollbar_size = scrollbar_end - scrollbar_begin; - const float scrollbar_granularity = std::min(1.0f, scrollbar_size / std::max(1.0f, list_height)); - scrollbar_height = std::max(tree_scrollbar_width() * 2, scrollbar_size * scrollbar_granularity); - if (!click_down) + if (GetState() == FOCUS) { - scrollbar_state = SCROLLBAR_INACTIVE; + // This is outside scrollbar code, because it can also be scrolled if parent widget is only in focus + scrollbar.Scroll(wi::input::GetPointer().z * 10); } - - Hitbox2D scroll_box; - scroll_box.pos = XMFLOAT2(translation.x + scale.x - tree_scrollbar_width(), translation.y + item_height() + 1); - scroll_box.siz = XMFLOAT2(tree_scrollbar_width(), scale.y - item_height() - 1); - if (scroll_box.intersects(pointerHitbox)) + const float scrollbar_width = 12; + scrollbar.SetSize(XMFLOAT2(scrollbar_width - 1, scale.y - 1 - item_height())); + scrollbar.SetPos(XMFLOAT2(translation.x + 1 + scale.x - scrollbar_width, translation.y + 1 + item_height())); + scrollbar.Update(canvas, dt); + if (scrollbar.GetState() > IDLE) { - if (clicked) - { - scrollbar_state = SCROLLBAR_GRABBED; - } - else if (!click_down) - { - scrollbar_state = SCROLLBAR_HOVER; - state = FOCUS; - } + Deactivate(); } - if (scrollbar_state == SCROLLBAR_GRABBED) - { - Activate(); - scrollbar_delta = pointerHitbox.pos.y - scrollbar_height * 0.5f - scrollbar_begin; - } - - if (state == FOCUS) - { - scrollbar_delta -= wi::input::GetPointer().z * 10; - } - scrollbar_delta = wi::math::Clamp(scrollbar_delta, 0, scrollbar_size - scrollbar_height); - if (scrollbar_begin < scrollbar_end - scrollbar_height) - { - scrollbar_value = wi::math::InverseLerp(scrollbar_begin, scrollbar_end - scrollbar_height, scrollbar_begin + scrollbar_delta); - } - else - { - scrollbar_value = 0; - } - - list_offset = -scrollbar_value * (list_height - scrollbar_size * 0.75f); - Hitbox2D itemlist_box = GetHitbox_ListArea(); // control-list item_highlight = -1; opener_highlight = -1; - if (scrollbar_state == SCROLLBAR_INACTIVE) + if (scrollbar.GetState() == IDLE) { int i = -1; int visible_count = 0; @@ -3045,28 +3333,12 @@ namespace wi::gui font.Draw(cmd); - // scrollbar background - wi::image::Params fx = sprites[state].params; - fx.pos = XMFLOAT3(translation.x + scale.x - tree_scrollbar_width(), translation.y + item_height() + 1, 0); - fx.siz = XMFLOAT2(tree_scrollbar_width(), scale.y - item_height() - 1); - fx.color = sprites[IDLE].params.color; - wi::image::Draw(wi::texturehelper::getWhite(), fx, cmd); - - // scrollbar - wi::Color scrollbar_color = wi::Color::fromFloat4(sprites[IDLE].params.color); - if (scrollbar_state == SCROLLBAR_HOVER) - { - scrollbar_color = wi::Color::fromFloat4(sprites[FOCUS].params.color); - } - else if (scrollbar_state == SCROLLBAR_GRABBED) - { - scrollbar_color = wi::Color::White(); - } - wi::image::Draw(wi::texturehelper::getWhite() - , wi::image::Params(translation.x + scale.x - tree_scrollbar_width(), translation.y + item_height() + 1 + scrollbar_delta, tree_scrollbar_width(), scrollbar_height, scrollbar_color), cmd); + scrollbar.Render(canvas, cmd); // list background Hitbox2D itemlist_box = GetHitbox_ListArea(); + wi::image::Params fx = sprites[state].params; + fx.color = sprites[IDLE].params.color; fx.pos = XMFLOAT3(itemlist_box.pos.x, itemlist_box.pos.y, 0); fx.siz = XMFLOAT2(itemlist_box.siz.x, itemlist_box.siz.y); wi::image::Draw(wi::texturehelper::getWhite(), fx, cmd); diff --git a/WickedEngine/wiGUI.h b/WickedEngine/wiGUI.h index 01d9c058e..d09e904c5 100644 --- a/WickedEngine/wiGUI.h +++ b/WickedEngine/wiGUI.h @@ -100,7 +100,7 @@ namespace wi::gui void SetImage(wi::Resource textureResource, WIDGETSTATE state = WIDGETSTATE_COUNT); virtual void Update(const wi::Canvas& canvas, float dt); - virtual void Render(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const = 0; + virtual void Render(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const {} virtual void RenderTooltip(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const; wi::Sprite sprites[WIDGETSTATE_COUNT]; @@ -122,6 +122,9 @@ namespace wi::gui void ApplyScissor(const wi::Canvas& canvas, const wi::graphics::Rect rect, wi::graphics::CommandList cmd, bool constrain_to_parent = true) const; wi::primitive::Hitbox2D GetPointerHitbox() const; + wi::primitive::Hitbox2D active_area; // Pointer hitbox constrain area + void HitboxConstrain(wi::primitive::Hitbox2D& hb) const; + bool priority_change = true; uint32_t priority = 0; bool force_disable = false; @@ -294,6 +297,50 @@ namespace wi::gui void OnSelect(std::function func); }; + // Generic scroll bar + class ScrollBar : public Widget + { + protected: + float scrollbar_delta = 0; + float scrollbar_length = 0; + float scrollbar_value = 0; + float scrollbar_granularity = 1; + float list_length = 0; + float list_offset = 0; + float overscroll = 0; + bool vertical = true; + XMFLOAT2 grab_pos = {}; + float grab_delta = 0; + + public: + // Set the list's length that will be scrollable and moving + void SetListLength(float size) { list_length = size; } + // The scrolling offset that should be applied to the list items + float GetOffset() const { return list_offset; } + // This can be called by user for extra scrolling on top of base functionality + void Scroll(float amount) { scrollbar_delta -= amount; } + // How much the max scrolling will offset the list even further than it would be necessary for fitting + // this value is in percent of a full scrollbar's worth of extra offset + // 0: no extra offset + // 1: full extra offset + void SetOverScroll(float amount) { overscroll = amount; } + // Check whether the scrollbar is required (when the items don't and scrolling could be used) + bool IsScrollbarRequired() const { return scrollbar_granularity < 1; } + + enum SCROLLBAR_STATE + { + SCROLLBAR_INACTIVE, + SCROLLBAR_HOVER, + SCROLLBAR_GRABBED, + SCROLLBAR_STATE_COUNT, + } scrollbar_state = SCROLLBAR_INACTIVE; + wi::Sprite sprites_knob[SCROLLBAR_STATE_COUNT]; + XMFLOAT2 knob_inset_border = {}; + + void Update(const wi::Canvas& canvas, float dt) override; + void Render(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const override; + }; + // Widget container class Window :public Widget { @@ -304,12 +351,15 @@ namespace wi::gui Button resizeDragger_BottomRight; Button moveDragger; Label label; + ScrollBar scrollbar_vertical; + ScrollBar scrollbar_horizontal; wi::vector widgets; bool minimized = false; + Widget scrollable_area; public: void Create(const std::string& name, bool window_controls = true); - void AddWidget(Widget* widget); + void AddWidget(Widget* widget, bool scrollable = true); void RemoveWidget(Widget* widget); void RemoveWidgets(); @@ -373,22 +423,10 @@ namespace wi::gui }; protected: std::function onSelect; - float list_height = 0; - float list_offset = 0; int item_highlight = -1; int opener_highlight = -1; - enum SCROLLBAR_STATE - { - SCROLLBAR_INACTIVE, - SCROLLBAR_HOVER, - SCROLLBAR_GRABBED, - TREESTATE_COUNT, - } scrollbar_state = SCROLLBAR_INACTIVE; - - float scrollbar_delta = 0; - float scrollbar_height = 0; - float scrollbar_value = 0; + ScrollBar scrollbar; wi::primitive::Hitbox2D GetHitbox_ListArea() const; wi::primitive::Hitbox2D GetHitbox_Item(int visible_count, int level) const; diff --git a/WickedEngine/wiMath.h b/WickedEngine/wiMath.h index a871a3e47..a0d5b5ddf 100644 --- a/WickedEngine/wiMath.h +++ b/WickedEngine/wiMath.h @@ -154,9 +154,31 @@ namespace wi::math } constexpr float Clamp(float val, float min, float max) { - if (val < min) return min; - else if (val > max) return max; - return val; + return std::min(max, std::max(min, val)); + } + constexpr XMFLOAT2 Clamp(XMFLOAT2 val, XMFLOAT2 min, XMFLOAT2 max) + { + XMFLOAT2 retval = val; + retval.x = Clamp(retval.x, min.x, max.x); + retval.y = Clamp(retval.y, min.y, max.y); + return retval; + } + constexpr XMFLOAT3 Clamp(XMFLOAT3 val, XMFLOAT3 min, XMFLOAT3 max) + { + XMFLOAT3 retval = val; + retval.x = Clamp(retval.x, min.x, max.x); + retval.y = Clamp(retval.y, min.y, max.y); + retval.z = Clamp(retval.z, min.z, max.z); + return retval; + } + constexpr XMFLOAT4 Clamp(XMFLOAT4 val, XMFLOAT4 min, XMFLOAT4 max) + { + XMFLOAT4 retval = val; + retval.x = Clamp(retval.x, min.x, max.x); + retval.y = Clamp(retval.y, min.y, max.y); + retval.z = Clamp(retval.z, min.z, max.z); + retval.w = Clamp(retval.w, min.w, max.w); + return retval; } constexpr float SmoothStep(float value1, float value2, float amount) { @@ -165,6 +187,9 @@ namespace wi::math } constexpr bool Collision2D(const XMFLOAT2& hitBox1Pos, const XMFLOAT2& hitBox1Siz, const XMFLOAT2& hitBox2Pos, const XMFLOAT2& hitBox2Siz) { + if (hitBox1Siz.x <= 0 || hitBox1Siz.y <= 0 || hitBox2Siz.x <= 0 || hitBox2Siz.y <= 0) + return false; + if (hitBox1Pos.x + hitBox1Siz.x < hitBox2Pos.x) return false; else if (hitBox1Pos.x > hitBox2Pos.x + hitBox2Siz.x) diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index e69d0d759..c5a5c3aab 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -1577,7 +1577,6 @@ namespace wi::scene } wi::jobsystem::context ctx; - wi::physics::RunPhysicsUpdateSystem(ctx, *this, dt); // Scan mesh subset counts to allocate GPU geometry data: geometryAllocator.store(0u); @@ -1591,6 +1590,8 @@ namespace wi::scene std::memset(TLAS_instancesMapped, 0, TLAS_instancesUpload->desc.size); }); + wi::physics::RunPhysicsUpdateSystem(ctx, *this, dt); + RunAnimationUpdateSystem(ctx); RunTransformUpdateSystem(ctx); diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 40a25ca9e..0d8220338 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 60; // minor bug fixes, alterations, refactors, updates - const int revision = 69; + const int revision = 70; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);