1 // This file is part of the utui library, a terminal UI framework.
3 // Copyright (C) 2006 by Mike Sharov <msharov@users.sourceforge.net>
4 // This file is free software, distributed under the MIT License.
10 #include "ctrl/menu.h"
12 //----------------------------------------------------------------------
14 const Point2d
CWindow::pos_CaretOff (-1, -1);
16 //----------------------------------------------------------------------
19 /// Default constructor.
20 CWindow::CWindow (void)
26 m_CaretPos (pos_CaretOff
)
30 /// Virtual destructor.
31 CWindow::~CWindow (void)
36 /// Initializes the window.
37 void CWindow::OnCreate (void)
39 foreach (winvec_t::iterator
, i
, m_Children
)
44 /// Uninitializes the window.
45 void CWindow::OnDestroy (void)
47 ClearFlag (f_Created
);
48 eachfor (winvec_t::reverse_iterator
, i
, m_Children
)
52 //----------------------------------------------------------------------
53 // Child window maintenance
55 /// Deletes all child windows.
56 void CWindow::DeleteAllChildren (void)
59 DeleteAllLayoutItems();
60 for (int i
= m_Children
.size() - 1; i
>= 0; --i
) {
62 Delete (m_Children
[i
]);
67 /// Adds \p pw to the (owning) child window list.
68 void CWindow::AddChild (pwin_t pw
)
70 m_Children
.push_back (pw
);
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
) {
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");
96 parent
->AddLayoutItem (pw
); // non-owning reference pointer for layout
97 const size_t ncli ((pwd
++)->nChildren
);
99 AddChild (static_cast<pwin_t
>(pw
));
101 AddLayoutItem (pw
); // owning pointer in the window object
102 for (uoff_t i
= 0; i
< ncli
; ++i
)
103 pwd
= InitFromDesc (pwd
, pw
);
108 /// Called whenever a child window closes itself.
109 void CWindow::OnChildClose (uoff_t i
)
112 SetFocus (GetNextFocus());
113 if (CW(i
).Flag (f_Created
))
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
125 foreach (winvec_t::const_iterator
, i
, m_Children
) {
126 if ((*i
)->SeenCWRect (r
, pw
)) {
127 r
+= (*i
)->WindowRect()[0];
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
) {
141 if ((pw
= (*i
)->ParentWindowOf (w
)))
147 /// Returns the parent window of this window. Slow.
148 CWindow::pwin_t
CWindow::ParentWindow (void) const
150 return (CRootWindow::Instance().ParentWindowOf (this));
153 //----------------------------------------------------------------------
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());
164 uint32_t of
= Focus();
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
))
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
) {
183 if ((*i
)->Flag (f_Closed
)) {
184 OnChildClose (distance (m_Children
.begin(), 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
198 LI(0).SizeHints (wr
);
200 simd::pmin (r
[1], wr
[1]);
203 /// Sets the window rect to \p wr.
204 void CWindow::OnResize (rcrect_t wr
)
209 m_GC
.Resize (wa
[1][0], wa
[1][1]);
215 /// Routes \p key down the focus path.
216 void CWindow::OnKey (wchar_t key
)
218 foreach (cmdkvec_t::const_iterator
, i
, m_CommandKeys
)
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
)) {
226 if (CW(i
).Flag (f_NoTabOrder
)) {
227 SetFocus (GetNextFocus());
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)
256 foreach (winvec_t::iterator
, i
, m_Children
) {
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 //----------------------------------------------------------------------
268 /// Sets \p f as the focused child window.
269 void CWindow::SetFocus (uoff_t f
)
273 if (m_Focus
< m_Children
.size())
274 CW(m_Focus
).OnLoseFocus();
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();
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
;