1 //
2 // This file is part of libyacurs.
3 // Copyright (C) 2013  Rafael Ostertag
4 //
5 // This program is free software: you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation, either version 3 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program.  If not, see
17 // <http://www.gnu.org/licenses/>.
18 //
19 //
20 // $Id$
21 
22 #include <cassert>
23 
24 #include "eventqueue.h"
25 #include "focusmanager.h"
26 #include "yacursdbg.h"
27 #include "yacursex.h"
28 
29 using namespace YACURS;
30 
31 const FocusManager::fgid_t FocusManager::nfgid = (FocusManager::fgid_t)-1;
32 FocusManager::fgid_t FocusManager::_active_focusgroup = FocusManager::nfgid;
33 std::vector<FocusGroup*> FocusManager::_focus_groups;
34 
35 //
36 // Private
37 //
focus_change_handler(Event & e)38 void FocusManager::focus_change_handler(Event& e) {
39     assert(e == EVT_FOCUS_NEXT || e == EVT_FOCUS_PREVIOUS);
40 
41     if (_focus_groups.empty()) return;
42     assert(_active_focusgroup < _focus_groups.size());
43     assert(_focus_groups[_active_focusgroup] != 0);
44     assert(_focus_groups[_active_focusgroup]->active());
45 
46     if (e.type() == EVT_FOCUS_NEXT) {
47         _focus_groups[_active_focusgroup]->focus_next();
48         DEBUGOUT(DBG_FOCUSMGR, "focus_next() on " << _active_focusgroup);
49     } else if (e.type() == EVT_FOCUS_PREVIOUS) {
50         _focus_groups[_active_focusgroup]->focus_previous();
51         DEBUGOUT(DBG_FOCUSMGR, "focus_previous() on " << _active_focusgroup);
52     } else {
53         throw EXCEPTIONS::UnexpectedEvent();
54     }
55 }
56 
57 //
58 // Protected
59 //
60 
61 //
62 // Public
63 //
64 
init()65 void FocusManager::init() {
66     DEBUGOUT(DBG_FOCUSMGR, "Initialize Focus Manager");
67     EventQueue::connect_event(EventConnectorFunction1(
68         EVT_FOCUS_NEXT, FocusManager::focus_change_handler));
69     EventQueue::connect_event(EventConnectorFunction1(
70         EVT_FOCUS_PREVIOUS, FocusManager::focus_change_handler));
71 }
72 
uninit()73 void FocusManager::uninit() {
74     DEBUGOUT(DBG_FOCUSMGR, "Uninitialize Focus Manager");
75     EventQueue::disconnect_event(EventConnectorFunction1(
76         EVT_FOCUS_NEXT, FocusManager::focus_change_handler));
77     EventQueue::disconnect_event(EventConnectorFunction1(
78         EVT_FOCUS_PREVIOUS, FocusManager::focus_change_handler));
79 
80     for (fgid_t i = 0; i < _focus_groups.size(); i++)
81         if (_focus_groups[i] != 0) {
82             delete _focus_groups[i];
83             _focus_groups[i] = 0;
84         }
85 }
86 
new_focus_group()87 FocusManager::fgid_t FocusManager::new_focus_group() {
88     fgid_t id = FocusManager::nfgid;
89 
90     if (_focus_groups.empty()) {
91         id = _focus_groups.size();  // == 0
92         _focus_groups.push_back(new FocusGroup);
93         DEBUGOUT(DBG_FOCUSMGR, "New Focus Group (first) "
94                                    << (void*)(_focus_groups[id])
95                                    << " with ID: " << id);
96     } else {
97         // Search for a free slot in the vector
98         for (fgid_t i = 0; i < _focus_groups.size(); i++) {
99             if (_focus_groups[i] == 0) {
100                 // found free slot
101                 id = i;
102                 _focus_groups[i] = new FocusGroup;
103                 DEBUGOUT(DBG_FOCUSMGR, "New Focus Group (reuse slot) "
104                                            << (void*)(_focus_groups[id])
105                                            << " with ID: " << id);
106                 break;
107             }
108         }
109 
110         // Check if we have found a free slot, i.e. id has been set
111         if (id == FocusManager::nfgid) {
112             // No, no free slot, so create new slot.
113             id = _focus_groups.size();
114             _focus_groups.push_back(new FocusGroup);
115             DEBUGOUT(DBG_FOCUSMGR, "New Focus Group (new slot) "
116                                        << (void*)(_focus_groups[id])
117                                        << " with ID: " << id);
118         }
119     }
120 
121     assert(id != FocusManager::nfgid);
122     assert(id < _focus_groups.size());
123     return id;
124 }
125 
destroy_focus_group(fgid_t id)126 void FocusManager::destroy_focus_group(fgid_t id) {
127     assert(!_focus_groups.empty());
128     assert(id < _focus_groups.size());
129 
130     // check if the FocusGroup still exists.
131     //
132     // It is possible that the Focus Groups have been destroyed by a
133     // call to ::uninit() due to termination of the event loop, but
134     // destruction of Windows were still not done. See the test
135     // 'listbox2.cc' for an example of this bevavior
136     if (_focus_groups[id] == 0) return;
137 
138     // Destructor of FocusGroup is supposed to take care of removing
139     // focus, so we simply destroy the group.
140     delete _focus_groups[id];
141     _focus_groups[id] = 0;
142     DEBUGOUT(DBG_FOCUSMGR, "Destroy Focus Group " << (void*)(_focus_groups[id])
143                                                   << " with ID: " << id);
144 
145     if (_active_focusgroup == id) _active_focusgroup = FocusManager::nfgid;
146 }
147 
focus_group_add(fgid_t id,WidgetBase * w)148 void FocusManager::focus_group_add(fgid_t id, WidgetBase* w) {
149     assert(w != 0);
150     assert(!_focus_groups.empty());
151     assert(id < _focus_groups.size());
152     assert(_focus_groups[id] != 0);
153 
154     _focus_groups[id]->add(w);
155 
156     DEBUGOUT(DBG_FOCUSMGR, "Add widget " << (void*)(w) << " to Focus Group "
157                                          << (void*)(_focus_groups[id])
158                                          << " with ID: " << id);
159 }
160 
focus_group_remove(fgid_t id,WidgetBase * w)161 void FocusManager::focus_group_remove(fgid_t id, WidgetBase* w) {
162     assert(w != 0);
163     assert(id != FocusManager::nfgid);
164 
165     // check if the FocusGroup still exists.
166     //
167     // It is possible that the Focus Groups have been destroyed by a
168     // call to ::uninit() due to termination of the event loop, but
169     // destruction of Windows were still not done. See the test
170     // 'listbox2.cc' for an example of this bevavior
171     if (_focus_groups[id] == 0) return;
172 
173     _focus_groups[id]->remove(w);
174 
175     DEBUGOUT(DBG_FOCUSMGR, "Remove widget " << (void*)(w) << " to Focus Group "
176                                             << (void*)(_focus_groups[id])
177                                             << " with ID: " << id);
178 }
179 
focus_group_activate(fgid_t id)180 void FocusManager::focus_group_activate(fgid_t id) {
181     assert(!_focus_groups.empty());
182     assert(id < _focus_groups.size());
183     assert(_focus_groups[id] != 0);
184     // We cannot assert this here, because fgid_t is probably of
185     // unsigned type and initially set to -1, so we cannot get past
186     // this assertion, since the first call which would make
187     // subsequent calls pass, always fails.
188     //
189     // assert(_active_focusgroup<_focus_groups.size());
190 
191     // Deactivate the current Active Focus Group, if any.
192     if (_active_focusgroup != FocusManager::nfgid &&  // not initialized yet
193         _focus_groups[_active_focusgroup] != 0 /* Focus Group destroyed */) {
194         assert(_active_focusgroup < _focus_groups.size());
195         _focus_groups[_active_focusgroup]->deactivate();
196         DEBUGOUT(DBG_FOCUSMGR, "Deactivated Focus Group "
197                                    << (void*)(_focus_groups[_active_focusgroup])
198                                    << " with ID: " << _active_focusgroup);
199     }
200 
201     _focus_groups[id]->activate();
202     _active_focusgroup = id;
203     DEBUGOUT(DBG_FOCUSMGR, "Activated Focus Group "
204                                << (void*)(_focus_groups[id])
205                                << " with ID: " << id);
206 }
207 
refocus()208 void FocusManager::refocus() {
209     if (_focus_groups.empty()) return;
210 
211     assert(_active_focusgroup != FocusManager::nfgid);
212     assert(_focus_groups[_active_focusgroup] != 0);
213     // This would make many tests fail. Also, it should be no problem
214     // if we don't assert.
215     //
216     // assert(!_focus_groups.empty());
217 
218     _focus_groups[_active_focusgroup]->refocus();
219     DEBUGOUT(DBG_FOCUSMGR, "Refocus Focus Group "
220                                << (void*)(_focus_groups[_active_focusgroup])
221                                << " with ID: " << _active_focusgroup);
222 }
223 
reset()224 void FocusManager::reset() {
225     if (_focus_groups.empty()) return;
226     assert(_active_focusgroup != FocusManager::nfgid);
227     assert(_focus_groups[_active_focusgroup] != 0);
228     _focus_groups[_active_focusgroup]->reset();
229     DEBUGOUT(DBG_FOCUSMGR, "Reset Focus Group "
230                                << (void*)(_focus_groups[_active_focusgroup])
231                                << " with ID: " << _active_focusgroup);
232 }
233 
active_focus_group()234 FocusManager::fgid_t FocusManager::active_focus_group() {
235     return _active_focusgroup;
236 }
237