1 /***************************************************************************
2  *   Copyright (C) 2008-2021 by Andrzej Rybczak                            *
3  *   andrzej@rybczak.net                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU 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, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
19  ***************************************************************************/
20 
21 #ifndef NCMPCPP_SCREEN_H
22 #define NCMPCPP_SCREEN_H
23 
24 #include "curses/menu.h"
25 #include "curses/scrollpad.h"
26 #include "screens/screen_type.h"
27 
28 void drawSeparator(int x);
29 void genericMouseButtonPressed(NC::Window &w, MEVENT me);
30 void scrollpadMouseButtonPressed(NC::Scrollpad &w, MEVENT me);
31 
32 /// An interface for various instantiations of Screen template class. Since C++ doesn't like
33 /// comparison of two different instantiations of the same template class we need the most
34 /// basic class to be non-template to allow it.
35 struct BaseScreen
36 {
BaseScreenBaseScreen37 	BaseScreen() : hasToBeResized(false) { }
~BaseScreenBaseScreen38 	virtual ~BaseScreen() { }
39 
40 	/// @see Screen::isActiveWindow()
41 	virtual bool isActiveWindow(const NC::Window &w_) const = 0;
42 
43 	/// @see Screen::activeWindow()
44 	virtual NC::Window *activeWindow() = 0;
45 	virtual const NC::Window *activeWindow() const = 0;
46 
47 	/// @see Screen::refresh()
48 	virtual void refresh() = 0;
49 
50 	/// @see Screen::refreshWindow()
51 	virtual void refreshWindow() = 0;
52 
53 	/// @see Screen::scroll()
54 	virtual void scroll(NC::Scroll where) = 0;
55 
56 	/// Method used for switching to screen
57 	virtual void switchTo() = 0;
58 
59 	/// Method that should resize screen
60 	/// if requested by hasToBeResized
61 	virtual void resize() = 0;
62 
63 	/// @return ncurses timeout parameter for the screen
64 	virtual int windowTimeout() = 0;
65 
66 	/// @return title of the screen
67 	virtual std::wstring title() = 0;
68 
69 	/// @return type of the screen
70 	virtual ScreenType type() = 0;
71 
72 	/// If the screen contantly has to update itself
73 	/// somehow, it should be called by this function.
74 	virtual void update() = 0;
75 
76 	/// @see Screen::mouseButtonPressed()
77 	virtual void mouseButtonPressed(MEVENT me) = 0;
78 
79 	/// @return true if screen can be locked. Note that returning
80 	/// false here doesn't neccesarily mean that screen is also not
81 	/// mergable (eg. lyrics screen is not lockable since that wouldn't
82 	/// make much sense, but it's perfectly fine to merge it).
83 	virtual bool isLockable() = 0;
84 
85 	/// @return true if screen is mergable, ie. can be "proper" subwindow
86 	/// if one of the screens is locked. Screens that somehow resemble popups
87 	/// will want to return false here.
88 	virtual bool isMergable() = 0;
89 
90 	/// Locks current screen.
91 	/// @return true if lock was successful, false otherwise. Note that
92 	/// if there is already locked screen, it'll not overwrite it.
93 	bool lock();
94 
95 	/// Should be set to true each time screen needs resize
96 	bool hasToBeResized;
97 
98 	/// Unlocks a screen, ie. hides merged window (if there is one set).
99 	static void unlock();
100 
101 	const static int defaultWindowTimeout = 500;
102 
103 protected:
104 	/// Gets X offset and width of current screen to be used eg. in resize() function.
105 	/// @param adjust_locked_screen indicates whether this function should
106 	/// automatically adjust locked screen's dimensions (if there is one set)
107 	/// if current screen is going to be subwindow.
108 	void getWindowResizeParams(size_t &x_offset, size_t &width, bool adjust_locked_screen = true);
109 };
110 
111 void applyToVisibleWindows(std::function<void(BaseScreen *)> f);
112 void updateInactiveScreen(BaseScreen *screen_to_be_set);
113 bool isVisible(BaseScreen *screen);
114 
115 /// Class that all screens should derive from. It provides basic interface
116 /// for the screen to be working properly and assumes that we didn't forget
117 /// about anything vital.
118 ///
119 template <typename WindowT> struct Screen : public BaseScreen
120 {
121 	typedef WindowT WindowType;
122 	typedef typename std::add_lvalue_reference<
123 		WindowType
124 	>::type WindowReference;
125 	typedef typename std::add_lvalue_reference<
126 		typename std::add_const<WindowType>::type
127 	>::type ConstWindowReference;
128 
129 private:
130 	template <bool IsPointer, typename Result, typename ConstResult>
131 	struct getObject {
applyScreen::getObject132 		static Result &apply(WindowReference w) { return w; }
constApplyScreen::getObject133 		static ConstResult &constApply(ConstWindowReference w) { return w; }
134 	};
135 	template <typename Result, typename ConstResult>
136 	struct getObject<true, Result, ConstResult> {
137 		static Result &apply(WindowType w) { return *w; }
138 		static ConstResult &constApply(const WindowType w) { return *w; }
139 	};
140 
141 	typedef getObject<
142 		std::is_pointer<WindowT>::value,
143 		typename std::remove_pointer<WindowT>::type,
144 		typename std::add_const<
145 			typename std::remove_pointer<WindowT>::type
146 		>::type
147 	> Accessor;
148 
149 public:
150 	Screen() { }
151 	Screen(WindowT w_) : w(w_) { }
152 
153 	virtual ~Screen() { }
154 
155 	virtual bool isActiveWindow(const NC::Window &w_) const override {
156 		return &Accessor::constApply(w) == &w_;
157 	}
158 
159 	/// Since some screens contain more that one window
160 	/// it's useful to determine the one that is being
161 	/// active
162 	/// @return address to window object cast to void *
163 	virtual NC::Window *activeWindow() override {
164 		return &Accessor::apply(w);
165 	}
166 	virtual const NC::Window *activeWindow() const override {
167 		return &Accessor::constApply(w);
168 	}
169 
170 	/// Refreshes whole screen
171 	virtual void refresh() override {
172 		Accessor::apply(w).display();
173 	}
174 
175 	/// Refreshes active window of the screen
176 	virtual void refreshWindow() override {
177 		Accessor::apply(w).display();
178 	}
179 
180 	/// Scrolls the screen by given amount of lines and
181 	/// if fancy scrolling feature is disabled, enters the
182 	/// loop that holds main loop until user releases the key
183 	/// @param where indicates where one wants to scroll
184 	virtual void scroll(NC::Scroll where) override {
185 		Accessor::apply(w).scroll(where);
186 	}
187 
188 	/// @return timeout parameter used for the screen (in ms)
189 	/// @default defaultWindowTimeout
190 	virtual int windowTimeout() override {
191 		return defaultWindowTimeout;
192 	}
193 
194 	/// Invoked after there was one of mouse buttons pressed
195 	/// @param me struct that contains coords of where the click
196 	/// had its place and button actions
197 	virtual void mouseButtonPressed(MEVENT me) override {
198 		genericMouseButtonPressed(Accessor::apply(w), me);
199 	}
200 
201 	/// @return currently active window
202 	WindowReference main() {
203 		return w;
204 	}
205 	ConstWindowReference main() const {
206 		return w;
207 	}
208 
209 protected:
210 	/// Template parameter that should indicate the main type
211 	/// of window used by the screen. What is more, it should
212 	/// always be assigned to the currently active window (if
213 	/// acreen contains more that one)
214 	WindowT w;
215 };
216 
217 /// Specialization for Screen<Scrollpad>::mouseButtonPressed that should
218 /// not scroll whole page, but rather a few lines (the number of them is
219 /// defined in the config)
220 template <> inline void Screen<NC::Scrollpad>::mouseButtonPressed(MEVENT me) {
221 	scrollpadMouseButtonPressed(w, me);
222 }
223 
224 #endif // NCMPCPP_SCREEN_H
225 
226