]> git.sesse.net Git - casparcg/blob - core/interaction/interaction_aggregator.h
[config] Fixes #464
[casparcg] / core / interaction / interaction_aggregator.h
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Helge Norberg, helge.norberg@svt.se
20 */
21
22 #pragma once
23
24 #include <queue>
25 #include <functional>
26
27 #include <boost/optional.hpp>
28
29 #include "interaction_event.h"
30 #include "interaction_sink.h"
31 #include "../frame/frame_transform.h"
32 #include "util.h"
33
34 namespace caspar { namespace core {
35
36 typedef std::pair<frame_transform, interaction_sink*> interaction_target;
37 typedef std::function<boost::optional<interaction_target> (double x, double y)>
38                 collission_detector;
39
40 class interaction_aggregator
41 {
42         std::queue<interaction_event::ptr> events_;
43         collission_detector collission_detector_;
44
45
46         boost::optional<interaction_target> clicked_and_held_;
47         int num_buttons_clicked_and_held_                                               = 0;
48 public:
49         interaction_aggregator(const collission_detector& collission_detector)
50                 : collission_detector_(collission_detector)
51         {
52         }
53
54         void offer(const interaction_event::ptr& event)
55         {
56                 if (!events_.empty()
57                                 && is<mouse_move_event>(event)
58                                 && is<mouse_move_event>(events_.back()))
59                 {
60                         events_.back() = event;
61                 }
62                 else
63                 {
64                         events_.push(event);
65                 }
66         }
67
68         void translate_and_send()
69         {
70                 while (!events_.empty())
71                 {
72                         translate_and_send(events_.front());
73                         events_.pop();
74                 }
75         }
76
77         void translate_and_send(const interaction_event::ptr& event)
78         {
79                 if (is<position_event>(event))
80                 {
81                         auto pos_event = as<position_event>(event);
82                         boost::optional<interaction_target> target;
83
84                         if (clicked_and_held_)
85                                 target = clicked_and_held_;
86                         else
87                                 target = collission_detector_(pos_event->x, pos_event->y);
88
89                         if (is<mouse_button_event>(event))
90                         {
91                                 auto button_event = as<mouse_button_event>(event);
92
93                                 if (button_event->pressed)
94                                 {
95                                         if (num_buttons_clicked_and_held_ == 0)
96                                                 clicked_and_held_ = target;
97
98                                         ++num_buttons_clicked_and_held_;
99                                 }
100                                 else
101                                         --num_buttons_clicked_and_held_;
102
103                                 if (num_buttons_clicked_and_held_ == 0)
104                                         clicked_and_held_.reset();
105                         }
106
107                         if (target)
108                                 target->second->on_interaction(
109                                                 pos_event->translate(target->first));
110                 }
111         }
112 };
113
114 }}