summaryrefslogtreecommitdiffstats
path: root/curses/cursesstatusbar.H
blob: 50bc4c3ccb0cf6e5f679332fc9398e4cdb79bc10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
** Copyright 2002-2011, Double Precision Inc.
**
** See COPYING for distribution information.
*/

#ifndef cursesstatusbar_H
#define cursesstatusbar_H

#include "mycurses.H"
#include "curseskeyhandler.H"
#include "cursescontainer.H"
#include "cursesfield.H"

#include "timer.H"

#include <string>
#include <vector>
#include <wchar.h>

//////////////////////////////////////////////////////////////////////////////
//
// The status bar - moves itself to the bottom of the screen.  Occupies three
// last lines: a one line status/help line, and two lines that list current
// keyboard shortcuts.
//
// Status messages are prioritized, and only messages of the same or higher
// priority level are shown.  The clearstatus() clears the current message,
// which is also automatically cleared 10 seconds after the first keypress
//
// Messages that cannot fit on one line are automatically word-wrapped, and
// are shown in a larger popup that comes up from the bottom of the screen,
// which must be cleared with a keypress
//
// The status bar can also be converted to a one-line input field, by calling
// the createPrompt() method, which returns a pointer to the created
// CursesField object (which may be further customized).  The status bar
// automatically destroys the CursesField abort when the input concludes
// (by pressing ENTER, or by manually calling fieldAbort() ).
//
// The first character of the status line may be a busy-throbber (a rotating
// line).  The throbber must be animated by repeatedly calling the busy()
// method (which should be kicked off a 1 second timer).  The throbber is
// cleared by clearstatus().
//
// The status bar also includes a summary of all installed KeyHandler
// objects.  If the list of available function keys exceeds the available
// space, the list is shown in pieces, with a control key cycling through
// to the next status key summary piece.

class CursesScreen;

class CursesStatusBar : public CursesContainer, public CursesKeyHandler {

	std::vector<unicode_char> statusText;
	std::vector<unicode_char> progressText;
	time_t progressTime;

	int busyCounter;

	CursesScreen *parentScreen;

	std::vector< std::vector<unicode_char> > extendedErrorMsg;

	// The status bar is sometimes turned into a one-line field entry.
	// This is done by creating a CursesField child, which is why
	// CursesStatusBar subclasses CursesContainer.
	// We need to subclass CursesField in order to fix up a few things...

	class Field : public CursesField {
		CursesStatusBar *me;
	public:
		Field(CursesStatusBar *parent, size_t widthArg,
		      size_t maxlengthArg,
		      std::string initValue);
		~Field();

		bool processKeyInFocus(const Key &key);

		bool writeText(const char *text, int row, int col,
			       const CursesAttr &attr) const;
		bool writeText(const std::vector<unicode_char> &text,
			       int row, int col,
			       const Curses::CursesAttr &attr) const;
	};

	Field *fieldActive;      // Not NULL when input takes place

	std::string fieldValue;  // Entered input
	bool fieldAborted;       // Whether input was aborted

	TimerRedirect<CursesStatusBar> clearStatusTimer;

	CursesAttr attrStatusBar, attrHotKey, attrHotKeyDescr;

public:
	void fieldEnter();	// Accept input
	void fieldAbort();	// Abort input
private:

	// Shortcut keys.

	size_t max_sc_nlen;	// Largest shortcut name
	size_t max_sc_dlen;	// Largest shortcut description

	std::vector <std::vector <std::vector <
		std::pair< std::vector<unicode_char>,
			   std::vector<unicode_char> > > > > shortcuts;

	// A std::pair of name/description string, inside a two-element vector
	// (the two-row column on the status bar), inside a vector of all
	// columns that fit on one screen, inside a vector of all pages of
	// shortcut descriptions

	size_t currentShortcutPage;	// Current page of shortcuts shown

	void rebuildShortcuts();	// Rebuild the shortcuts array
public:

	static std::string shortcut_next_key;
	static std::string shortcut_next_descr;
	static unicode_char shortcut_next_keycode;

	friend class Field;

	// Status line priorities

	enum statusLevel {
		NORMAL,		// Normal message
		INPROGRESS,	// Something's in progress
		EXPUNGED,	// Folder's been expunged
		SYSERROR,	// System error
		DISCONNECTED,	// Server dropped connection
		SERVERERROR,	// Other server error
		LOGINERROR	// Login error
	};

	CursesStatusBar(CursesScreen *parent);
	~CursesStatusBar();

	static std::string extendedErrorPrompt; // Non empty - wrapped text

	int getWidth() const;
	int getHeight() const;

	void setStatusBarAttr(CursesAttr);
	void setHotKeyAttr(CursesAttr);
	void setHotKeyDescr(CursesAttr);

	void draw();
	void resized();

	void status(std::string statusText, statusLevel level=NORMAL);
	void progress(std::string progress);
	bool progressWanted();

	void clearstatus();

	void busy();	// Throbber animation

	void notbusy(); // Not busy any more

	// Create a one-line input field.

	CursesField *createPrompt(std::string prompt, std::string initvalue="");

	bool prompting() const { return fieldActive != NULL; }
	bool promptAborted() const { return fieldAborted; }

	std::string getPromptValue() const
	{
		return (fieldActive != NULL ? fieldActive->getText()
			: fieldValue);
	}

private:
	statusLevel currentLevel;

	void resetRow();

	bool processKey(const Curses::Key &key);
	bool listKeys( std::vector< std::pair<std::string, std::string> > &list);
};

#endif