Show cursor on exit
[utui.git] / window.cc
bloba59f3f3fa4a24f493093b7efa5fc41d404cf023c
1 // This file is part of the utui library, a terminal UI framework.
2 //
3 // Copyright (C) 2006 by Mike Sharov <msharov@users.sourceforge.net>
4 // This file is free software, distributed under the MIT License.
5 //
6 // window.cc
7 //
9 #include "rootwin.h"
10 #include "ctrl/menu.h"
12 //----------------------------------------------------------------------
14 const Point2d CWindow::pos_CaretOff (-1, -1);
16 //----------------------------------------------------------------------
17 // Housekeeping
19 /// Default constructor.
20 CWindow::CWindow (void)
21 : CDocumentClient (),
22 m_GC (),
23 m_Children (),
24 m_WindowRect (),
25 m_Focus (NO_FOCUS),
26 m_CaretPos (pos_CaretOff)
30 /// Virtual destructor.
31 CWindow::~CWindow (void)
33 DeleteAllChildren();
36 /// Initializes the window.
37 void CWindow::OnCreate (void)
39 foreach (winvec_t::iterator, i, m_Children)
40 (*i)->OnCreate();
41 SetFlag (f_Created);
44 /// Uninitializes the window.
45 void CWindow::OnDestroy (void)
47 ClearFlag (f_Created);
48 eachfor (winvec_t::reverse_iterator, i, m_Children)
49 (*i)->OnDestroy();
52 //----------------------------------------------------------------------
53 // Child window maintenance
55 /// Deletes all child windows.
56 void CWindow::DeleteAllChildren (void)
58 SetFocus (NO_FOCUS);
59 DeleteAllLayoutItems();
60 for (int i = m_Children.size() - 1; i >= 0; --i) {
61 OnChildClose (i);
62 Delete (m_Children[i]);
64 m_Children.clear();
67 /// Adds \p pw to the (owning) child window list.
68 void CWindow::AddChild (pwin_t pw)
70 m_Children.push_back (pw);
71 if (Flag (f_Created))
72 pw->OnCreate();
73 if (Flag (f_Resized))
74 OnResize (WindowRect());
77 /// Removes \p pw from internal list of children without deleting it.
78 void CWindow::RemoveChild (pwin_t pw)
80 foreach (winvec_t::iterator, i, m_Children) {
81 if (*i == pw) {
82 OnChildClose (distance (m_Children.begin(), i));
83 --(i = m_Children.erase (i));
88 /// Uses the given descriptors to stuff the container.
89 pcwidesc_t CWindow::InitFromDesc (pcwidesc_t pwd, pwidget_t parent)
91 assert (pwd->pfnFactory && "Unexpected end of dialog descriptor list");
92 pwidget_t pw = (*pwd->pfnFactory)(pwd->initValue);
93 assert (pw && "Widget factories should throw on failure");
94 assert ((pwd->nChildren || dynamic_cast<pwin_t>(pw)) && "Layout helper objects must have at least one window to layout");
95 if (parent)
96 parent->AddLayoutItem (pw); // non-owning reference pointer for layout
97 const size_t ncli ((pwd++)->nChildren);
98 if (!ncli)
99 AddChild (static_cast<pwin_t>(pw));
100 else {
101 AddLayoutItem (pw); // owning pointer in the window object
102 for (uoff_t i = 0; i < ncli; ++i)
103 pwd = InitFromDesc (pwd, pw);
105 return (pwd);
108 /// Called whenever a child window closes itself.
109 void CWindow::OnChildClose (uoff_t i)
111 if (Focus() == i)
112 SetFocus (GetNextFocus());
113 if (CW(i).Flag (f_Created))
114 CW(i).OnDestroy();
117 /// Returns in \p r the area of window \p pw in this window's coordinates.
118 /// false is returned if \p pw is not in this window's subtree.
119 bool CWindow::SeenCWRect (Rect& r, pcwin_t pw) const
121 if (pw == this) {
122 r = WindowArea();
123 return (true);
125 foreach (winvec_t::const_iterator, i, m_Children) {
126 if ((*i)->SeenCWRect (r, pw)) {
127 r += (*i)->WindowRect()[0];
128 return (true);
131 return (false);
134 /// Searches through ths subtree under this window to find the parent of \p w.
135 CWindow::pwin_t CWindow::ParentWindowOf (pcwin_t w)
137 foreach (winvec_t::const_iterator, i, m_Children) {
138 if (*i == w)
139 return (this);
140 pwin_t pw;
141 if ((pw = (*i)->ParentWindowOf (w)))
142 return (pw);
144 return (NULL);
147 /// Returns the parent window of this window. Slow.
148 CWindow::pwin_t CWindow::ParentWindow (void) const
150 return (CRootWindow::Instance().ParentWindowOf (this));
153 //----------------------------------------------------------------------
154 // Event handlers
156 /// Finds the next focus if the current one gives it up.
157 uint32_t CWindow::GetNextFocus (int dir) const
159 const size_t ni (m_Children.size());
160 if (!ni)
161 return (NO_FOCUS);
162 if (dir < 0)
163 dir += ni;
164 uint32_t of = Focus();
165 if (of >= ni)
166 of = ni - dir;
167 uint32_t nf = of;
168 // Cycle through all the children looking for something on the tab order.
169 while ((nf = (nf+dir)%ni) != of && CW(nf).Flag(f_NoTabOrder));
170 // If there was no focus, check if nf is tabbable
171 if (nf == of && Focus() == NO_FOCUS && CW(nf).Flag(f_NoTabOrder))
172 nf = NO_FOCUS;
173 return (nf);
176 /// Called on every event loop iteration.
177 void CWindow::OnIdle (void)
179 if (Focus() < m_Children.size() && CW(Focus()).Flag (f_OffersFocus))
180 SetFocus (GetNextFocus());
181 foreach (winvec_t::iterator, i, m_Children) {
182 (*i)->OnIdle();
183 if ((*i)->Flag (f_Closed)) {
184 OnChildClose (distance (m_Children.begin(), i));
185 Delete (*i);
186 --(i = m_Children.erase (i));
191 /// Returns the recommended area of the window when \p r is the total available area.
192 void CWindow::SizeHints (rrect_t wr) const
194 if (!NLI())
195 return;
196 Rect r (wr);
197 wr -= r[0];
198 LI(0).SizeHints (wr);
199 wr += r[0];
200 simd::pmin (r[1], wr[1]);
203 /// Sets the window rect to \p wr.
204 void CWindow::OnResize (rcrect_t wr)
206 m_WindowRect = wr;
207 Rect wa (wr);
208 wa -= wr[0];
209 m_GC.Resize (wa[1][0], wa[1][1]);
210 if (NLI())
211 LI(0).OnResize (wa);
212 SetFlag (f_Resized);
215 /// Routes \p key down the focus path.
216 void CWindow::OnKey (wchar_t key)
218 foreach (cmdkvec_t::const_iterator, i, m_CommandKeys)
219 if (i->key == key)
220 CMenuBar::Instance()->ExecuteCommand (i->cmd);
221 const wchar_t normkey = tolower (key & kvm_KeyMask);
222 for (uoff_t i = 0; i < m_Children.size(); ++ i) {
223 wchar_t ack = CW(i).FocusAccelKey();
224 if ((ack == normkey) | (ack == key)) {
225 SetFocus (i);
226 if (CW(i).Flag (f_NoTabOrder)) {
227 SetFocus (GetNextFocus());
228 return;
230 key = kv_Enter;
233 if (m_Focus < m_Children.size())
234 CW(m_Focus).OnKey (key);
237 /// Handles command \p cmd by forwarding it to child windows.
238 void CWindow::OnCommand (cmd_t cmd)
240 foreach (winvec_t::iterator, i, m_Children)
241 (*i)->OnCommand (cmd);
244 /// Updates the state of command \p cmd.
245 void CWindow::OnUpdateCommandUI (rcmd_t rcmd) const
247 foreach (winvec_t::const_iterator, i, m_Children)
248 (*i)->OnUpdateCommandUI (rcmd);
251 /// Draws the window and its children onto the internal gc.
252 void CWindow::Paint (void)
254 CaretOff();
255 OnDraw (GC());
256 foreach (winvec_t::iterator, i, m_Children) {
257 (*i)->Paint();
258 rcrect_t r ((*i)->WindowRect());
259 GC().Image (r[0][0], r[0][1], r.Width(), r.Height(), (*i)->GC().Canvas());
260 if (distance (m_Children.begin(), i) == m_Focus && (*i)->CaretPos() != pos_CaretOff)
261 CaretTo ((*i)->WindowRect()[0] + (*i)->CaretPos());
265 //----------------------------------------------------------------------
266 // Focus management
268 /// Sets \p f as the focused child window.
269 void CWindow::SetFocus (uoff_t f)
271 if (m_Focus == f)
272 return;
273 if (m_Focus < m_Children.size())
274 CW(m_Focus).OnLoseFocus();
275 m_Focus = f;
276 if (m_Focus < m_Children.size())
277 CW(m_Focus).OnGainFocus();
280 /// Called when this window loses focus.
281 void CWindow::OnGainFocus (void)
283 SetFlag (f_HasFocus);
284 if (m_Focus >= m_Children.size())
285 SetFocus (GetNextFocus());
286 if (m_Focus < m_Children.size())
287 CW(m_Focus).OnGainFocus();
290 /// Called when this window gains focus.
291 void CWindow::OnLoseFocus (void)
293 if (m_Focus < m_Children.size())
294 CW(m_Focus).OnLoseFocus();
295 CaretOff();
296 ClearFlag (f_HasFocus);
297 ClearFlag (f_OffersFocus);
300 /// Moves the caret to \p pt.
301 void CWindow::CaretTo (rcpos_t pt)
303 if (dim_t(pt[0]) >= WindowRect().Width() || dim_t(pt[1]) >= WindowRect().Height())
304 m_CaretPos = pos_CaretOff;
305 else
306 m_CaretPos = pt;