Show cursor on exit
[utui.git] / rootwin.cc
blobf246e81cc167ed49a33b310b50b414dbf86bc7d2
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 // rootwin.cc
7 //
9 #include "rootwin.h"
10 #include "msgbox.h"
12 //----------------------------------------------------------------------
14 long CRootWindow::s_IdleTimeout = 200000;
16 //----------------------------------------------------------------------
18 /// Singleton instance reference.
19 /*static*/ CRootWindow& CRootWindow::Instance (void)
21 static CRootWindow w;
22 return (w);
25 /// Default constructor.
26 CRootWindow::CRootWindow (void)
27 : CWindow (),
28 m_TI (),
29 m_Kb (),
30 m_Screen (),
31 m_ScreenPos ()
35 /// Virtual destructor.
36 CRootWindow::~CRootWindow (void)
38 CRootWindow::OnDestroy(); // This is for abnormal exit.
41 /// Writes the window GC onto the terminal.
42 void CRootWindow::Flush (void)
44 CGC& rgc (GC());
45 bool bCursorOff = (m_ScreenPos == pos_CaretOff);
46 bool bWillBeOff = (CaretPos() == pos_CaretOff);
47 if (rgc.MakeDiffFrom (m_Screen)) {
48 // gc now has only new stuff, the rest is zeroed out, and isn't drawn.
49 cout << m_TI.HideCursor();
50 bCursorOff = true;
51 cout << m_TI.Image (0, 0, rgc.Width(), rgc.Height(), rgc.Canvas().begin());
52 m_Screen.Image (rgc); // Now apply the same diff to the screen cache.
53 rgc.Image (m_Screen); // ... and copy it back for a fresh start.
55 if (!bCursorOff && bWillBeOff) {
56 cout << m_TI.HideCursor();
57 bCursorOff = true;
59 bCursorOff |= (m_ScreenPos != CaretPos());
60 if (bCursorOff & ((m_ScreenPos = CaretPos()) != pos_CaretOff)) {
61 cout << m_TI.MoveTo (CaretPos()[0], CaretPos()[1]);
62 cout << m_TI.ShowCursor();
64 if (bCursorOff)
65 cout.flush();
68 /// Initializes the output device.
69 void CRootWindow::OnCreate (void)
71 CWindow::OnCreate();
73 m_TI.Load(); // The terminfo database
74 m_Kb.Open (m_TI); // Put the keyboard in UI mode
75 cout << m_TI.HideCursor(); // No cursor in UI mode
76 cout << m_TI.Clear(); // Screen is clear in the beginning
78 OnResize (Rect (0, 0, m_TI.Width(), m_TI.Height()));
81 /// Deinitializes the output device.
82 void CRootWindow::OnDestroy (void)
84 if (!m_Kb.IsInUIMode()) // To not close twice (from dtor)
85 return;
86 m_Kb.Close(); // Coming back to tty mode
87 cout << m_TI.Clear(); // Clear the screen
88 cout << m_TI.ShowCursor(); // No cursor in UI mode
89 cout.flush(); // Now
90 CWindow::OnDestroy(); // OnDestroy errors can now be printed to tty
93 /// Sets the window rect to \p wr.
94 void CRootWindow::OnResize (rcrect_t wr)
96 CWindow::OnResize (wr);
97 m_Screen.Resize (wr.Width(), wr.Height());
98 // Root window children are placed wherever they want to be.
99 Rect cwr;
100 foreach (winvec_t::iterator, i, Children()) {
101 (*i)->SizeHints (cwr = wr);
102 (*i)->OnResize (cwr);
106 /// Called when a root-level exception is caught.
107 void CRootWindow::OnError (exception& e)
109 // Print the exception to string
110 ostringstream os;
111 os << e;
112 // Delete all windows to avoid further errors.
113 DeleteAllChildren();
114 // Display the error in a box.
115 MessageBox (os.str());
116 // If any of the above throws, Terminate gets called with a message and a dtor call.
119 /// Checks for keypresses and other events.
120 wchar_t CRootWindow::GetKey (void) const
122 wchar_t key = m_Kb.GetKey (false);
123 if (!key)
124 m_Kb.WaitForKeyData (s_IdleTimeout);
125 return (key);
128 /// The main event loop.
129 int CRootWindow::Run (void)
131 OnGainFocus();
132 while (!Flag (f_Closed) & !Children().empty()) {
133 Paint();
134 Flush();
135 wchar_t key;
136 if ((key = GetKey()))
137 OnKey (key);
138 OnIdle();
140 OnLoseFocus();
141 return (Status());
144 //----------------------------------------------------------------------
146 int CRootWindow::s_ModalStack [15];
147 unsigned int CRootWindow::s_ModalDepth = 1;
149 /// Extracts status information from the child window before it dies.
150 void CRootWindow::OnChildClose (uoff_t i)
152 CWindow::OnChildClose (i);
153 s_ModalStack[s_ModalDepth-1] = CW(i).Status();
156 /// Runs \p pw as a modal dialog. \p pw is deleted before returning.
157 int CRootWindow::RunModal (CDialog* pw)
159 assert (s_ModalDepth < VectorSize(s_ModalStack) - 1 && "Too many nested modal dialog calls. Either use fewer or increase s_ModalStack size in rootwin.cc");
160 s_ModalStack [s_ModalDepth++] = 0;
161 uint32_t ci = Children().size(), oldFocus (Focus());
162 AddChild (pw);
163 SetFocus (ci);
164 while ((ci < Children().size()) && Children()[ci] == pw) {
165 Paint();
166 Flush();
167 wchar_t key;
168 if ((key = GetKey()))
169 pw->OnKey (key);
170 OnIdle();
172 if (oldFocus >= Children().size())
173 oldFocus = GetNextFocus(-1);
174 SetFocus (oldFocus);
175 return (s_ModalStack [--s_ModalDepth]);