Das Problem besteht darin das der hittest (also die Prüfung ob die Maus drüber ist) nur anhand der Daten des vererbten Widgets stattfindet. Das heißt wenn man z.B "slider.setposition(...)" aufrufen würde, dann würde sich das auf die Transformmatrix des Widget beziehen und nicht auf die des eigentlichen Sliders(also Track und Thumb). Das Thema ist leider so abstrakt behindert, dass ich nicht in der Lage bin es genau beschreiben zu könnnen. Es ist wahrscheinlich einfach wieder nur ein Verständnisproblem welches uns hier diesen Ärger beschert.
Hier mal die Slider.h
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
#ifndef SLIDER_H
#define SLIDER_H
#include <gui/widgets/Widget.h>
namespace gui
{
class Slider : public Widget
{
public:
Slider(float width, float height);
void update() override;
void setValue(int percent);
int getValue();
private:
void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
void updatePosition(sf::Event& ev);
void calculateValue();
//Callback functions
void onWidgetReleased(sf::Event& ev) override;
void onWidgetPressed(sf::Event& ev) override;
void onWidgetEntered(sf::Event& ev) override;
void onWidgetLeft(sf::Event& ev) override;
void onWidgetMoved(sf::Event& ev) override;
sf::RectangleShape _track, _thumb;
int _percentValue;
};
}
#endif // !SLIDER_H
|
Und die dazugehörige Slider.cpp
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
#include <gui\widgets\Slider.h>
namespace gui
{
/////////////////////////////////////////////////////////////////////////////////////
Slider::Slider(float width, float height)
: Widget(width, height)
, _percentValue(0)
{
_track.setSize(sf::Vector2f(width, height));
_track.setFillColor(sf::Color::Black);
_thumb.setSize(sf::Vector2f(this->getWidth()/8, this->getWidth()/8));
_thumb.setOrigin(sf::Vector2f(_thumb.getSize().x/2, _thumb.getSize().y/2));
_thumb.setFillColor(sf::Color::Green);
//Hinzufügen der Callbacks gebunden an Events
this->addEventListener(sf::Event::MouseButtonReleased, std::bind(&Slider::onWidgetReleased, this, std::placeholders::_1));
this->addEventListener(sf::Event::MouseButtonPressed, std::bind(&Slider::onWidgetPressed, this, std::placeholders::_1));
this->addEventListener(sf::Event::MouseEntered, std::bind(&Slider::onWidgetEntered, this, std::placeholders::_1));
this->addEventListener(sf::Event::MouseLeft, std::bind(&Slider::onWidgetLeft, this, std::placeholders::_1));
this->addEventListener(sf::Event::MouseMoved, std::bind(&Slider::onWidgetMoved, this, std::placeholders::_1));
this->setType(WidgetType::Slider);
this->setDraggable(true);
}
/////////////////////////////////////////////////////////////////////////////////////
void Slider::update()
{
}
/////////////////////////////////////////////////////////////////////////////////////
void Slider::updatePosition(sf::Event& ev)
{
//Diese Funktion ist dazu gedacht den Thumb auf der Track zu bewegen
//if (_thumb.getGlobalBounds().contains(this->globalToLocal(ev.mouseMove.x, ev.mouseMove.y)))
//{
// std::cout << "ok\n";
//}
float diffX = this->globalToLocal(ev.mouseMove.x, ev.mouseMove.y).x - _track.getPosition().x;
_thumb.setPosition(sf::Vector2f(_track.getPosition().x + diffX, _track.getGlobalBounds().height/2));
if (_thumb.getPosition().x > _track.getGlobalBounds().width - _thumb.getGlobalBounds().width/2)
{
_thumb.setPosition(sf::Vector2f(_track.getGlobalBounds().width - _thumb.getGlobalBounds().width / 2, _thumb.getPosition().y));
}
else if (_thumb.getPosition().x < _thumb.getGlobalBounds().width/2)
{
_thumb.setPosition(sf::Vector2f(_thumb.getGlobalBounds().width / 2, _thumb.getPosition().y));
}
}
/////////////////////////////////////////////////////////////////////////////////////
void Slider::onWidgetReleased(sf::Event & ev)
{
this->setClicked(false);
}
/////////////////////////////////////////////////////////////////////////////////////
void Slider::onWidgetPressed(sf::Event & ev)
{
this->setClicked(true);
}
/////////////////////////////////////////////////////////////////////////////////////
void Slider::onWidgetEntered(sf::Event & ev)
{
this->setHovered(true);
_track.setFillColor(sf::Color::Blue);
}
/////////////////////////////////////////////////////////////////////////////////////
void Slider::onWidgetLeft(sf::Event & ev)
{
this->setHovered(false);
_track.setFillColor(sf::Color::Black);
}
/////////////////////////////////////////////////////////////////////////////////////
void Slider::onWidgetMoved(sf::Event & ev)
{
updatePosition(ev);
//calculateValue();
}
/////////////////////////////////////////////////////////////////////////////////////
void Slider::calculateValue()
{
static float trackLenght = _track.getGlobalBounds().width - this->getWidth();
float diffX = this->getPosition().x - _track.getPosition().x;
_percentValue = 100 / trackLenght * diffX;
std::cout << trackLenght << " - " << _percentValue << " - " << diffX <<"\n";
}
/////////////////////////////////////////////////////////////////////////////////////
void Slider::setValue(int percent)
{
_percentValue = percent;
}
/////////////////////////////////////////////////////////////////////////////////////
int Slider::getValue()
{
return _percentValue;
}
/////////////////////////////////////////////////////////////////////////////////////
void Slider::draw(sf::RenderTarget & target, sf::RenderStates states) const
{
//Thumb und Track werden nach den States gezeichnet. (Die States stammen von übergeordneten Widgets)
target.draw(_track, states);
target.draw(_thumb, states);
}
/////////////////////////////////////////////////////////////////////////////////////
}
|
Die Sliderschiene(_track) und der Sliderkopf(_thumb) werden von den sf::RenderStates transformiert.
Hier noch der Hittest welcher prüft ob man mit der Maus über dem Widget ist. (Die Funktionen stammen aus der Basisklasse aller Gui Elemente: Widget.cpp)
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
bool Widget::hittest(float mouseX, float mouseY)
{
sf::Vector2f localMousePos = globalToLocal(mouseX, mouseY);
//std::cout << "X: " << localMousePos .x << " | Y: " << localMousePos.y << "\n";
return (localMousePos.x > 0 && localMousePos.x < _width && localMousePos.y > 0 && localMousePos.y < _height);
}
/////////////////////////////////////////////////////////////////////////////////////
sf::Vector2f Widget::globalToLocal(float x, float y)
{ //Die Funktion wandelt den globalen space in den lokalen um. (um eine relative Mausposition zu schaffen)
sf::Transform mtx = getConcatenatedMatrix();
mtx = mtx.getInverse();
return mtx.transformPoint(x, y);
}
/////////////////////////////////////////////////////////////////////////////////////
sf::Transform Widget::getConcatenatedMatrix()
{
//Es werden solange die Tramsformmatrizen aufmultipliziert bis das Child kein Parent mehr hat.
while (this->getParent() != nullptr)
{
return this->getTransform() * _parent->getConcatenatedMatrix();
}
return this->getTransform();
}
|
Die hittest Funktion wird dann übers Eventsystem aufgerufen (z.B wenn eine Mausbewegung stattgefunden hat).
Die Gui ist nach dem Composite pattern aufgebaut und besagt das es Elemente gibt die weitere Elemente von gleicher Art aufnehmen können, und welche die es nicht können.
Bei der Gui ist es einmal das Widget welches die Elemente sind die keine weiteren Elmente aufnehmen können(z.B Button,
Slider), und die WidgetContainer die es können(z.B Fenster).
Das Problem beim Slider ist halt nun dass es kein WidgetContainer sein kann, da man ihm sonst ja auch ein Fenster zuordnen könnte. Was aber gehen würde wäre wenn der Slider ein WidgetContainer wäre, sodass man ihm ein Button als Child gibt, welches den Thumb repräsentiert. Die momentane Lage sieht dann halt so aus dass wir für die Track und den Thumb einfach sf::RectangleShape`s nehmen. Jetzt muss man halt selber definieren was der Slider nun ist, entweder Thumb oder Track. Dies muss man vorab klären da man ja prüfen muss ob man überm Slider ist (Also über der Track, oder über dem Thumb ?). Meine Idee war es das Widget als Thumb zu behandeln, also Widget Position gleich der Thumb Position, sowie Größe, Rotation usw... Aber irgendwie will das ganze auch nich so.