/*************************************************************************** * Copyright (C) 2008-2010 by Andrzej Rybczak * * electricityispower@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef _SCREEN_H #define _SCREEN_H #include "window.h" #include "menu.h" #include "mpdpp.h" #include "helpers.h" #include "settings.h" #include "status.h" /// An interface for various instantiations of Screen template class. Since C++ doesn't like /// comparison of two different instantiations of the same template class we need the most /// basic class to be non-template to allow it. /// class BasicScreen { public: /// Initializes all variables to zero /// BasicScreen() : hasToBeResized(0), isInitialized(0) { } virtual ~BasicScreen() { } /// @see Screen::ActiveWindow() /// virtual void *ActiveWindow() = 0; /// Method used for switching to screen /// virtual void SwitchTo() = 0; /// Method that should resize screen /// if requested by hasToBeResized /// virtual void Resize() = 0; /// @return title of the screen /// virtual std::basic_string Title() = 0; /// If the screen contantly has to update itself /// somehow, it should be called by this function. /// virtual void Update() { } /// @see Screen::Refresh() /// virtual void Refresh() = 0; /// @see Screen::RefreshWindow() /// virtual void RefreshWindow() = 0; /// see Screen::ReadKey() /// virtual void ReadKey(int &key) = 0; /// @see Screen::Scroll() /// virtual void Scroll(Where where, const int key[2] = 0) = 0; /// Invoked after Enter was pressed /// virtual void EnterPressed() = 0; /// Invoked after Space was pressed /// virtual void SpacePressed() = 0; /// @see Screen::MouseButtonPressed() /// virtual void MouseButtonPressed(MEVENT) { } /// @return pointer to currently selected song in the screen /// (if screen provides one) or null pointer otherwise. /// virtual MPD::Song *CurrentSong() { return 0; } /// @return true if the screen allows selecting items, false otherwise /// virtual bool allowsSelection() = 0; /// Reverses selection. Does nothing by default since pure /// virtual allowsSelection() should remind of this function /// to be defined /// virtual void ReverseSelection() { } /// Gets selected songs' positions from the screen /// @param v vector to be filled with positions /// virtual void GetSelectedSongs(GNUC_UNUSED MPD::SongList &v) { } /// Applies a filter to the screen virtual void ApplyFilter(GNUC_UNUSED const std::string &filter) { } /// @return pointer to instantiation of Menu template class /// cast to List if available or null pointer otherwise /// virtual List *GetList() = 0; /// When this is overwritten with a function returning true, the /// screen will be used in tab switching. /// virtual bool isTabbable() { return false; } /// Should be set to true each time screen needs resize /// bool hasToBeResized; protected: /// Since screens initialization is lazy, we don't want to do /// this in the constructor. This function should be invoked /// only once and after that isInitialized flag has to be set /// to true to somehow avoid next attempt of initialization. /// virtual void Init() = 0; /// Flag that inditates whether the screen is initialized or not /// bool isInitialized; }; /// Class that all screens should derive from. It provides basic interface /// for the screen to be working properly and assumes that we didn't forget /// about anything vital. /// template class Screen : public BasicScreen { public: Screen() : w(0) { } virtual ~Screen() { } /// Since some screens contain more that one window /// it's useful to determine the one that is being /// active /// @return address to window object cast to void * /// virtual void *ActiveWindow(); /// @return pointer to currently active window /// WindowType *Main(); /// Refreshes whole screen /// virtual void Refresh(); /// Refreshes active window of the screen /// virtual void RefreshWindow(); /// Reads a key from the screen /// virtual void ReadKey(int &key); /// Scrolls the screen by given amount of lines and /// if fancy scrolling feature is disabled, enters the /// loop that holds main loop until user releases the key /// @param where indicates where one wants to scroll /// @param key needed if fancy scrolling is disabled to /// define the conditional for while loop /// virtual void Scroll(Where where, const int key[2] = 0); /// Invoked after there was one of mouse buttons pressed /// @param me struct that contains coords of where the click /// had its place and button actions /// virtual void MouseButtonPressed(MEVENT me); protected: /// Template parameter that should indicate the main type /// of window used by the screen. What is more, it should /// always be assigned to the currently active window (if /// acreen contains more that one) /// WindowType *w; }; template void *Screen::ActiveWindow() { return w; } template WindowType *Screen::Main() { return w; } template void Screen::Refresh() { w->Display(); } template void Screen::RefreshWindow() { w->Display(); } template void Screen::ReadKey(int &key) { w->ReadKey(key); } template void Screen::Scroll(Where where, const int key[2]) { if (!Config.fancy_scrolling && key) { int in = key[0]; w->SetTimeout(50); while (Keypressed(in, key)) { TraceMpdStatus(); w->Scroll(where); w->Refresh(); ReadKey(in); } w->SetTimeout(ncmpcpp_window_timeout); } else w->Scroll(where); } template void Screen::MouseButtonPressed(MEVENT me) { if (me.bstate & BUTTON2_PRESSED) { Scroll(wPageDown); } else if (me.bstate & BUTTON4_PRESSED) { Scroll(wPageUp); } } /// Specialization for Screen::MouseButtonPressed, that should /// not scroll whole page, but rather a few lines (the number of them is /// defined in the config) /// template <> inline void Screen::MouseButtonPressed(MEVENT me) { if (me.bstate & BUTTON2_PRESSED) { for (size_t i = 0; i < Config.lines_scrolled; ++i) Scroll(wDown); } else if (me.bstate & BUTTON4_PRESSED) { for (size_t i = 0; i < Config.lines_scrolled; ++i) Scroll(wUp); } } #endif