xaizek / pms (License: GPLv3+) (since 2018-12-07)
Older version of Practical Music Search written in C++.
Commit 22ccd57871adf77d607c666e880b866569427248

Merge curses and window management, and use several curses windows.
Author: Kim Tore Jensen
Author date (UTC): 2012-08-17 21:55
Committer name: Kim Tore Jensen
Committer date (UTC): 2012-08-17 21:55
Parent(s): ab0086775f79fb95a70569cd2a43e5917df11cc6
Signing key:
Tree: 24bbdf20de6dd88d9c53f0c8d0b9de11d148bcec
File Lines added Lines deleted
src/Makefile.am 1 1
src/console.cpp 1 3
src/curses.cpp 0 177
src/curses.h 0 100
src/field.cpp 1 3
src/input.cpp 0 1
src/main.cpp 7 17
src/mpd.cpp 3 4
src/pms.cpp 5 7
src/wconsole.cpp 4 6
src/window.cpp 70 15
src/window.h 53 3
src/windowmanager.cpp 74 10
src/wsonglist.cpp 11 14
src/wstatusbar.cpp 12 14
src/wtopbar.cpp 5 7
File src/Makefile.am changed (mode: 100644) (index 6cfbbb1..d0fb1f3)
1 1 bin_PROGRAMS = pms bin_PROGRAMS = pms
2 pms_SOURCES = clipboard.cpp color.cpp command.cpp config.cpp console.cpp curses.cpp field.cpp input.cpp keybinding.cpp main.cpp mpd.cpp pms.cpp search.cpp song.cpp songlist.cpp sort.cpp topbar.cpp wconsole.cpp window.cpp windowmanager.cpp wsonglist.cpp wstatusbar.cpp wtopbar.cpp
2 pms_SOURCES = clipboard.cpp color.cpp command.cpp config.cpp console.cpp field.cpp input.cpp keybinding.cpp main.cpp mpd.cpp pms.cpp search.cpp song.cpp songlist.cpp sort.cpp topbar.cpp wconsole.cpp window.cpp windowmanager.cpp wsonglist.cpp wstatusbar.cpp wtopbar.cpp
3 3 pms_LDADD = @CURSES_LIB@ pms_LDADD = @CURSES_LIB@
File src/console.cpp changed (mode: 100644) (index 993dd93..a65e54e)
20 20
21 21 #include "console.h" #include "console.h"
22 22 #include "window.h" #include "window.h"
23 #include "curses.h"
24 23 #include <stdarg.h> #include <stdarg.h>
25 24 #include <stdio.h> #include <stdio.h>
26 25 #include <string> #include <string>
 
30 29 using namespace std; using namespace std;
31 30
32 31 vector<Logline *> logbuffer; vector<Logline *> logbuffer;
33 extern Curses * curses;
34 32 extern Windowmanager * wm; extern Windowmanager * wm;
35 33
36 34 Logline::Logline(int lvl, const char * ln) Logline::Logline(int lvl, const char * ln)
 
... ... void console_log(int level, const char * format, ...)
52 50 logbuffer.push_back(new Logline(level, buffer)); logbuffer.push_back(new Logline(level, buffer));
53 51
54 52 /* Make it possible to log stuff before window system is brought up */ /* Make it possible to log stuff before window system is brought up */
55 if (wm->console == NULL)
53 if (!wm || wm->console == NULL)
56 54 return; return;
57 55
58 56 if (wm->console->position == wm->console->content_size() - wm->console->height() - 2) if (wm->console->position == wm->console->content_size() - wm->console->height() - 2)
File src/curses.cpp deleted (index 16c01f7..0000000)
1 /* vi:set ts=8 sts=8 sw=8 noet:
2 *
3 * Practical Music Search
4 * Copyright (c) 2006-2011 Kim Tore Jensen
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "curses.h"
22 #include "color.h"
23 #include "config.h"
24 #include <cstring>
25 #include <string>
26 #include <stdlib.h>
27 #include <math.h>
28
29 using namespace std;
30
31 extern Config * config;
32
33 Curses::Curses()
34 {
35 if ((initscr()) == NULL)
36 {
37 ready = false;
38 return;
39 }
40
41 noecho();
42 raw();
43 nodelay(stdscr, true);
44 keypad(stdscr, true);
45 curs_set(0);
46
47 if (has_colors())
48 {
49 start_color();
50 use_default_colors();
51 hascolors = true;
52 }
53
54 clear();
55 refresh();
56
57 ready = true;
58 }
59
60 Curses::~Curses()
61 {
62 clear();
63 refresh();
64 endwin();
65 }
66
67 void Curses::detect_dimensions()
68 {
69 memset(&self, 0, sizeof self);
70 memset(&topbar, 0, sizeof topbar);
71 memset(&main, 0, sizeof main);
72 memset(&statusbar, 0, sizeof statusbar);
73 memset(&readout, 0, sizeof readout);
74
75 self.right = COLS - 1;
76 self.bottom = LINES - 1;
77
78 topbar.top = 0;
79 topbar.bottom = topbar.top + config->topbar_height - 1;
80 if (topbar.bottom < 0)
81 topbar.bottom = 0;
82 topbar.right = self.right;
83
84 main.top = topbar.bottom + 1;
85 main.bottom = self.bottom - 1;
86 main.right = self.right;
87
88 statusbar.top = self.bottom;
89 statusbar.bottom = self.bottom;
90 statusbar.right = self.right - 3;
91
92 readout.top = statusbar.top;
93 readout.bottom = statusbar.bottom;
94 readout.left = statusbar.right + 1;
95 readout.right = self.right;
96 }
97
98 void Curses::setcursor(Rect * rect, int y, int x)
99 {
100 if (!rect)
101 return;
102
103 move(rect->top + y, rect->left + x);
104 }
105
106 void Curses::flush()
107 {
108 refresh();
109 }
110
111 void Curses::clearline(Rect * rect, int line, Color * c)
112 {
113 Rect r;
114
115 if (!rect)
116 return;
117
118 memcpy(&r, rect, sizeof r);
119 if ((r.top += line) > r.bottom)
120 return;
121
122 r.bottom = r.top;
123
124 wipe(&r, c);
125 }
126
127 void Curses::wipe(Rect * rect, Color * c)
128 {
129 int y;
130
131 if (!rect)
132 return;
133
134 attron(c->pair | A_INVIS);
135 for (y = rect->top; y <= rect->bottom; y++)
136 {
137 mvhline(y, rect->left, ' ', rect->right - rect->left + 1);
138 }
139 attroff(c->pair | A_INVIS);
140 flush();
141 }
142
143 void Curses::bell()
144 {
145 if (!config->use_bell)
146 return;
147
148 if (config->visual_bell)
149 {
150 if (flash() == ERR)
151 beep();
152 }
153 else
154 {
155 if (beep() == ERR)
156 flash();
157 }
158 }
159
160 void Curses::print(Rect * rect, Color * c, int y, int x, const char * fmt, ...)
161 {
162 va_list ap;
163 char buffer[1024];
164
165 if (!rect || !c) {
166 return;
167 }
168
169 va_start(ap, fmt);
170 vsprintf(buffer, fmt, ap);
171 va_end(ap);
172
173 move(rect->top + y, rect->left + x);
174 attron(c->pair);
175 printw(buffer);
176 attroff(c->pair);
177 }
File src/curses.h deleted (index 63cde50..0000000)
1 /* vi:set ts=8 sts=8 sw=8 noet:
2 *
3 * Practical Music Search
4 * Copyright (c) 2006-2011 Kim Tore Jensen
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #ifndef _PMS_CURSES_H_
22 #define _PMS_CURSES_H_
23
24 #include "../build.h"
25
26 #if defined HAVE_NCURSESW_CURSES_H
27 #include <ncursesw/curses.h>
28 #elif defined HAVE_NCURSESW_H
29 #include <ncursesw.h>
30 #elif defined HAVE_NCURSES_CURSES_H
31 #include <ncurses/curses.h>
32 #elif defined HAVE_NCURSES_H
33 #include <ncurses.h>
34 #elif defined HAVE_CURSES_H
35 #include <curses.h>
36 #else
37 #error "SysV or X/Open-compatible Curses header file required"
38 #endif
39
40 #include "color.h"
41
42 typedef struct
43 {
44 int left;
45 int top;
46 int right;
47 int bottom;
48 }
49
50 Rect;
51
52 class Curses
53 {
54 public:
55
56 Curses();
57 ~Curses();
58
59 /*
60 * Prints formatted, color output onto a rectangle.
61 *
62 * %s = char *
63 * %d = int
64 * %f = double
65 * %B %/B = bold on/off
66 * %R %/R = reverse on/off
67 * %0-n% %/0-n% = color on/off
68 *
69 */
70 void print(Rect * rect, Color * c, int y, int x, const char * fmt, ...);
71
72 /* Refresh the screen. */
73 void flush();
74
75 /* Clear a line, relative to rect. */
76 void clearline(Rect * rect, int line, Color * c);
77
78 /* Clear the rectangle. */
79 void wipe(Rect * rect, Color * c);
80
81 /* Set cursor position relative to rect */
82 void setcursor(Rect * rect, int y, int x);
83
84 /* Set left/right/top/bottom layout for all panels */
85 void detect_dimensions();
86
87 /* Trigger the bell */
88 void bell();
89
90 Rect self;
91 Rect topbar;
92 Rect main;
93 Rect statusbar;
94 Rect readout;
95
96 bool ready;
97 bool hascolors;
98 };
99
100 #endif /* _PMS_CURSES_H_ */
File src/field.cpp changed (mode: 100644) (index 9a73006..b1f5ff8)
22 22 #include "song.h" #include "song.h"
23 23 #include "mpd.h" #include "mpd.h"
24 24 #include "config.h" #include "config.h"
25 #include "curses.h"
26 25 #include "window.h" #include "window.h"
27 26 #include <vector> #include <vector>
28 27 #include <string> #include <string>
 
... ... using namespace std;
30 29
31 30 extern MPD * mpd; extern MPD * mpd;
32 31 extern Config * config; extern Config * config;
33 extern Curses * curses;
34 32 extern Windowmanager * wm; extern Windowmanager * wm;
35 33
36 34 Field::Field(field_t nfield, string name, string mpd_name, string tit, unsigned int minl, unsigned int maxl) Field::Field(field_t nfield, string name, string mpd_name, string tit, unsigned int minl, unsigned int maxl)
 
... ... string Field::format(Song * song)
69 67 tmp.clear(); tmp.clear();
70 68 if (mpd->status.length == -1 || mpd->status.elapsed == -1) if (mpd->status.length == -1 || mpd->status.elapsed == -1)
71 69 return tmp; return tmp;
72 i = mpd->status.elapsed * (curses->topbar.right - curses->topbar.left) / mpd->status.length;
70 i = mpd->status.elapsed * (wm->topbar->rect.right - wm->topbar->rect.left) / mpd->status.length;
73 71 while (i-- >= 0) while (i-- >= 0)
74 72 tmp += '='; tmp += '=';
75 73 tmp += '>'; tmp += '>';
File src/input.cpp changed (mode: 100644) (index c7c42c9..b5d94f0)
19 19 */ */
20 20
21 21 #include "input.h" #include "input.h"
22 #include "curses.h"
23 22 #include "command.h" #include "command.h"
24 23 #include "window.h" #include "window.h"
25 24 #include "config.h" #include "config.h"
File src/main.cpp changed (mode: 100644) (index 3a6d54c..2a82f9f)
34 34 #include <sys/time.h> #include <sys/time.h>
35 35
36 36 Fieldtypes * fieldtypes; Fieldtypes * fieldtypes;
37 Curses * curses;
38 37 Config * config; Config * config;
39 38 MPD * mpd; MPD * mpd;
40 39 Windowmanager * wm; Windowmanager * wm;
 
... ... int main(int argc, char *argv[])
51 50
52 51 setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
53 52
54 curses = new Curses();
55 if (!curses->ready)
56 {
57 perror("Fatal: failed to initialise ncurses.\n");
58 return 1;
59 }
60
61 53 fieldtypes = new Fieldtypes(); fieldtypes = new Fieldtypes();
62 54 keybindings = new Keybindings(); keybindings = new Keybindings();
63 55 commandlist = new Commandlist(); commandlist = new Commandlist();
64 config = new Config();
65 56 mpd = new MPD(); mpd = new MPD();
66 57 input = new Input(); input = new Input();
67 wm = new Windowmanager();
68 wm->activate(WMAIN(wm->console));
69
70 58 pms = new PMS(); pms = new PMS();
71 config->source_default_config();
72
73 curses->detect_dimensions();
59 wm = new Windowmanager();
60 wm->init_ncurses();
61 config = new Config();
74 62
63 wm->detect_dimensions();
64 wm->activate(WMAIN(wm->console));
75 65 stinfo("%s", PACKAGE_STRING); stinfo("%s", PACKAGE_STRING);
66 config->source_default_config();
76 67
77 68 memset(&conn, 0, sizeof conn); memset(&conn, 0, sizeof conn);
78 curses->detect_dimensions();
79 69 wm->playlist->songlist = &(mpd->playlist); wm->playlist->songlist = &(mpd->playlist);
80 70 wm->library->songlist = &(mpd->library); wm->library->songlist = &(mpd->library);
81 71 wm->draw(); wm->draw();
 
... ... int main(int argc, char *argv[])
125 115 pms->run_event(input->next()); pms->run_event(input->next());
126 116 } }
127 117
128 delete curses;
118 delete wm;
129 119 } }
File src/mpd.cpp changed (mode: 100644) (index 0348691..3e8844c)
... ... using namespace std;
42 42 extern Config * config; extern Config * config;
43 43 extern Windowmanager * wm; extern Windowmanager * wm;
44 44 extern Fieldtypes * fieldtypes; extern Fieldtypes * fieldtypes;
45 extern Curses * curses;
46 45 extern MPD * mpd; extern MPD * mpd;
47 46
48 47 void update_library_statusbar() void update_library_statusbar()
49 48 { {
50 49 unsigned int percent; unsigned int percent;
51 50 percent = round(((float)mpd->library.size() / mpd->stats.songs) * 100.00); percent = round(((float)mpd->library.size() / mpd->stats.songs) * 100.00);
52 curses->wipe(&(curses->statusbar), config->colors.statusbar);
53 curses->print(&(curses->statusbar), config->colors.statusbar, 0, 0, "Retrieving library: %d%%%%", percent);
54 curses->flush();
51 wm->statusbar->clear(config->colors.statusbar);
52 wm->statusbar->print(config->colors.statusbar, 0, 0, "Retrieving library: %d%%%%", percent);
53 wm->flush();
55 54 } }
56 55
57 56 MPD::MPD() MPD::MPD()
File src/pms.cpp changed (mode: 100644) (index b956c5e..c4272fb)
20 20
21 21 #include "pms.h" #include "pms.h"
22 22 #include "console.h" #include "console.h"
23 #include "curses.h"
24 23 #include "config.h" #include "config.h"
25 24 #include "window.h" #include "window.h"
26 25 #include "command.h" #include "command.h"
 
33 32
34 33 extern Config * config; extern Config * config;
35 34 extern MPD * mpd; extern MPD * mpd;
36 extern Curses * curses;
37 35 extern Windowmanager * wm; extern Windowmanager * wm;
38 36 extern Input * input; extern Input * input;
39 37 extern Commandlist * commandlist; extern Commandlist * commandlist;
 
... ... int PMS::run_event(Inputevent * ev)
131 129 return quit(); return quit();
132 130
133 131 case ACT_RESIZE: case ACT_RESIZE:
134 curses->detect_dimensions();
132 wm->detect_dimensions();
135 133 wm->playlist->update_column_length(); wm->playlist->update_column_length();
136 134 wm->library->update_column_length(); wm->library->update_column_length();
137 135 wm->draw(); wm->draw();
 
... ... int PMS::run_event(Inputevent * ev)
248 246 else if (ev->result == INPUT_RESULT_BUFFERED) else if (ev->result == INPUT_RESULT_BUFFERED)
249 247 { {
250 248 wm->statusbar->draw(); wm->statusbar->draw();
251 curses->flush();
249 wm->flush();
252 250 wm->topbar->qdraw(); wm->topbar->qdraw();
253 251
254 252 if (input->mode == INPUT_MODE_LIVESEARCH) if (input->mode == INPUT_MODE_LIVESEARCH)
 
... ... int PMS::set_opt(Inputevent * ev)
386 384 if (opt->mask & OPT_CHANGE_MPD) if (opt->mask & OPT_CHANGE_MPD)
387 385 mpd->apply_opts(); mpd->apply_opts();
388 386 if (opt->mask & OPT_CHANGE_DIMENSIONS) if (opt->mask & OPT_CHANGE_DIMENSIONS)
389 curses->detect_dimensions();
387 wm->detect_dimensions();
390 388 if (opt->mask & OPT_CHANGE_PLAYMODE) if (opt->mask & OPT_CHANGE_PLAYMODE)
391 389 { {
392 390 mpd->update_playstring(); mpd->update_playstring();
 
... ... int PMS::set_opt(Inputevent * ev)
408 406 return true; return true;
409 407 } }
410 408
411 curses->flush();
409 wm->flush();
412 410
413 411 return true; return true;
414 412 } }
 
... ... int PMS::livesearch(string terms, bool exitsearch)
595 593 win->songlist->liveclear(); win->songlist->liveclear();
596 594 input->setmode(INPUT_MODE_COMMAND); input->setmode(INPUT_MODE_COMMAND);
597 595 wm->statusbar->qdraw(); wm->statusbar->qdraw();
598 curses->flush();
596 wm->flush();
599 597 } }
600 598
601 599 if (song && (i = win->songlist->sfind(song->fhash)) != string::npos) if (song && (i = win->songlist->sfind(song->fhash)) != string::npos)
File src/wconsole.cpp changed (mode: 100644) (index a10b764..7701952)
20 20
21 21 #include "window.h" #include "window.h"
22 22 #include "console.h" #include "console.h"
23 #include "curses.h"
24 23 #include "config.h" #include "config.h"
25 24 #include <string> #include <string>
26 25 #include <vector> #include <vector>
 
28 27 using namespace std; using namespace std;
29 28
30 29 extern vector<Logline *> logbuffer; extern vector<Logline *> logbuffer;
31 extern Curses * curses;
32 30 extern Config * config; extern Config * config;
33 31
34 32 void Wconsole::drawline(int rely) void Wconsole::drawline(int rely)
 
... ... void Wconsole::drawline(int rely)
39 37 if (config->show_window_title) if (config->show_window_title)
40 38 ++rely; ++rely;
41 39
42 if (rely + rect->top > rect->bottom || linepos >= logbuffer.size())
40 if (rely + rect.top > rect.bottom || linepos >= logbuffer.size())
43 41 { {
44 curses->clearline(rect, rely, config->colors.console);
42 clearline(rely, config->colors.console);
45 43 return; return;
46 44 } }
47 45
48 46 c = logbuffer[linepos]->level == MSG_LEVEL_ERR ? config->colors.error : config->colors.console; c = logbuffer[linepos]->level == MSG_LEVEL_ERR ? config->colors.error : config->colors.console;
49 47
50 curses->clearline(rect, rely, c);
51 curses->print(rect, c, rely, 0, logbuffer[linepos]->line.c_str());
48 clearline(rely, c);
49 print(c, rely, 0, logbuffer[linepos]->line.c_str());
52 50 } }
53 51
54 52 unsigned int Wconsole::content_size() unsigned int Wconsole::content_size()
File src/window.cpp changed (mode: 100644) (index 175dd8b..94854f8)
19 19 */ */
20 20
21 21 #include <math.h> #include <math.h>
22 #include <string.h>
22 23 #include "window.h" #include "window.h"
23 #include "curses.h"
24 24 #include "config.h" #include "config.h"
25 25
26 26 extern Windowmanager * wm; extern Windowmanager * wm;
27 extern Curses * curses;
28 27 extern Config * config; extern Config * config;
29 28
29 Window::Window()
30 {
31 window = NULL;
32 memset(&rect, 0, sizeof rect);
33 }
34
35 void Window::set_dimensions(int top, int left, int bottom, int right)
36 {
37 if (window) {
38 delwin(window);
39 }
40 rect.top = top;
41 rect.left = left;
42 rect.bottom = bottom;
43 rect.right = right;
44 window = newwin(bottom-top+1, right-left+1, top, left);
45 }
46
47 void Window::flush()
48 {
49 wrefresh(window);
50 }
51
52 void Window::print(Color * c, int y, int x, const char * fmt, ...)
53 {
54 va_list ap;
55 char buffer[1024];
56
57 if (!c) {
58 return;
59 }
60
61 va_start(ap, fmt);
62 vsprintf(buffer, fmt, ap);
63 va_end(ap);
64
65 wattron(window, c->pair);
66 mvwprintw(window, y, x, buffer);
67 wattroff(window, c->pair);
68 }
69
70 void Window::clearline(int line, Color * c)
71 {
72 wattron(window, c->pair | A_INVIS);
73 mvwhline(window, line, rect.left, ' ', rect.right - rect.left);
74 wattroff(window, c->pair | A_INVIS);
75 }
76
30 77 void Window::draw() void Window::draw()
31 78 { {
32 79 unsigned int i, h; unsigned int i, h;
33 80
34 if (!rect || !visible())
81 if (!visible())
35 82 return; return;
36 83
37 84 need_draw = false; need_draw = false;
 
... ... void Window::draw()
40 87
41 88 for (i = 0; i <= h; i++) for (i = 0; i <= h; i++)
42 89 drawline(i); drawline(i);
90
91 /*FIXME*/
92 wrefresh(window);
43 93 } }
44 94
45 95 void Window::qdraw() void Window::qdraw()
 
... ... void Window::qdraw()
49 99
50 100 void Window::clear() void Window::clear()
51 101 { {
52 curses->wipe(rect, config->colors.standard);
102 wclear(window);
103 }
104
105 void Window::clear(Color * c)
106 {
107 wclear(window);
108 /*FIXME*/
109 //clear(config->colors.standard);
53 110 } }
54 111
55 112 unsigned int Window::height() unsigned int Window::height()
56 113 { {
57 if (!rect) return 0;
58 return rect->bottom - rect->top;
114 return rect.bottom - rect.top;
59 115 } }
60 116
61 117 Wmain::Wmain() Wmain::Wmain()
 
... ... Wmain::Wmain()
66 122
67 123 unsigned int Wmain::height() unsigned int Wmain::height()
68 124 { {
69 if (!rect) return 0;
70 return rect->bottom - rect->top - (config->show_window_title ? 1 : 0);
125 return rect.bottom - rect.top - (config->show_window_title ? 1 : 0);
71 126 } }
72 127
73 128 void Wmain::draw() void Wmain::draw()
74 129 { {
75 if (!rect || !visible())
130 if (!visible())
76 131 return; return;
77 132
78 133 if (config->show_window_title) if (config->show_window_title)
79 134 { {
80 curses->clearline(rect, 0, config->colors.windowtitle);
81 curses->print(rect, config->colors.windowtitle, 0, 0, title.c_str());
135 clearline(0, config->colors.windowtitle);
136 print(config->colors.windowtitle, 0, 0, title.c_str());
82 137 } }
83 138
84 139 Window::draw(); Window::draw();
 
... ... void Wmain::scroll_window(int offset)
97 152 if (offset < 0) if (offset < 0)
98 153 { {
99 154 offset = 0; offset = 0;
100 curses->bell();
155 wm->bell();
101 156 } }
102 157 if (offset > limit) if (offset > limit)
103 158 { {
104 159 offset = limit; offset = limit;
105 curses->bell();
160 wm->bell();
106 161 } }
107 162
108 163 if ((int)position == offset) if ((int)position == offset)
 
... ... void Wmain::move_cursor(int offset)
137 192 if (offset < 0) if (offset < 0)
138 193 { {
139 194 offset = 0; offset = 0;
140 curses->bell();
195 wm->bell();
141 196 } }
142 197 else if (offset > (int)content_size() - 1) else if (offset > (int)content_size() - 1)
143 198 { {
144 199 offset = content_size() - 1; offset = content_size() - 1;
145 curses->bell();
200 wm->bell();
146 201 } }
147 202
148 203 if ((int)cursor == offset) if ((int)cursor == offset)
File src/window.h changed (mode: 100644) (index d2ddb70..326c89a)
21 21 #ifndef _PMS_WINDOW_H_ #ifndef _PMS_WINDOW_H_
22 22 #define _PMS_WINDOW_H_ #define _PMS_WINDOW_H_
23 23
24 #include "curses.h"
24 #include "../build.h"
25
26 #if defined HAVE_NCURSESW_CURSES_H
27 #include <ncursesw/curses.h>
28 #elif defined HAVE_NCURSESW_H
29 #include <ncursesw.h>
30 #elif defined HAVE_NCURSES_CURSES_H
31 #include <ncurses/curses.h>
32 #elif defined HAVE_NCURSES_H
33 #include <ncurses.h>
34 #elif defined HAVE_CURSES_H
35 #include <curses.h>
36 #else
37 #error "SysV or X/Open-compatible Curses header file required"
38 #endif
39
40 #include "color.h"
25 41 #include "songlist.h" #include "songlist.h"
26 42 #include "command.h" #include "command.h"
27 43 #include <sys/time.h> #include <sys/time.h>
 
... ... using namespace std;
34 50 #define WMAIN(x) dynamic_cast<Wmain *>(x) #define WMAIN(x) dynamic_cast<Wmain *>(x)
35 51 #define WSONGLIST(x) dynamic_cast<Wsonglist *>(x) #define WSONGLIST(x) dynamic_cast<Wsonglist *>(x)
36 52
53 typedef struct
54 {
55 int left;
56 int top;
57 int right;
58 int bottom;
59 }
60 Rect;
61
37 62 class Window class Window
38 63 { {
39 64 protected: protected:
40 Rect * rect;
65 WINDOW * window;
41 66
42 67 public: public:
68 Window();
69
70 Rect rect;
43 71 bool need_draw; bool need_draw;
44 void set_rect(Rect * r) { rect = r; };
72
73 /* Set dimensions and update ncurses window */
74 void set_dimensions(int top, int left, int bottom, int right);
45 75
46 76 /* Window height */ /* Window height */
47 77 unsigned int height(); unsigned int height();
 
... ... class Window
52 82 /* Queue draw until next tick */ /* Queue draw until next tick */
53 83 void qdraw(); void qdraw();
54 84
85 /* Flush to ncurses */
86 void flush();
87
55 88 /* Clear this window */ /* Clear this window */
56 89 void clear(); void clear();
90 void clear(Color * c);
91 void clearline(int y, Color * c);
57 92
58 93 /* Is this window visible? */ /* Is this window visible? */
59 94 virtual bool visible() { return true; }; virtual bool visible() { return true; };
 
... ... class Window
61 96 /* Draw one line on rect */ /* Draw one line on rect */
62 97 virtual void drawline(int y) = 0; virtual void drawline(int y) = 0;
63 98
99 /* Draw text somewhere */
100 void print(Color * c, int y, int x, const char * fmt, ...);
64 101 }; };
65 102
66 103 class Wmain : public Window class Wmain : public Window
 
... ... class Windowmanager
176 213
177 214 public: public:
178 215 Windowmanager(); Windowmanager();
216 ~Windowmanager();
217
218 /* What kind of input events are accepted right now */
219 bool ready;
179 220
180 221 /* What kind of input events are accepted right now */ /* What kind of input events are accepted right now */
181 222 int context; int context;
182 223
224 /* Initialize ncurses stuff */
225 void init_ncurses();
226
183 227 /* Redraw all visible windows */ /* Redraw all visible windows */
184 228 void draw(); void draw();
185 229
 
... ... class Windowmanager
195 239 /* Activate a window */ /* Activate a window */
196 240 bool activate(Wmain * nactive); bool activate(Wmain * nactive);
197 241
242 /* Set left/right/top/bottom layout for all panels */
243 void detect_dimensions();
244
245 /* Trigger the bell */
246 void bell();
247
198 248 /* Activate the last used window */ /* Activate the last used window */
199 249 bool toggle(); bool toggle();
200 250
File src/windowmanager.cpp changed (mode: 100644) (index dc4f488..c0614af)
22 22 #include "curses.h" #include "curses.h"
23 23 #include "command.h" #include "command.h"
24 24 #include "mpd.h" #include "mpd.h"
25 #include "color.h"
25 26 #include "config.h" #include "config.h"
26 27 #include "input.h" #include "input.h"
27 28 #include <string> #include <string>
28 29 #include <vector> #include <vector>
29 30 #include <algorithm> #include <algorithm>
31 #include <cstring>
32 #include <stdlib.h>
33 #include <math.h>
34
30 35 using namespace std; using namespace std;
31 36
32 extern Curses * curses;
33 37 extern MPD * mpd; extern MPD * mpd;
34 38 extern Config * config; extern Config * config;
35 39 extern Input * input; extern Input * input;
 
... ... Windowmanager::Windowmanager()
38 42 { {
39 43 /* Setup static windows that are not in the window list */ /* Setup static windows that are not in the window list */
40 44 topbar = new Wtopbar; topbar = new Wtopbar;
41 topbar->set_rect(&curses->topbar);
42 45 statusbar = new Wstatusbar; statusbar = new Wstatusbar;
43 statusbar->set_rect(&curses->statusbar);
44 46 readout = new Wreadout; readout = new Wreadout;
45 readout->set_rect(&curses->readout);
46 47
47 48 /* Setup static windows that appear in the window list */ /* Setup static windows that appear in the window list */
48 49 console = new Wconsole; console = new Wconsole;
49 console->set_rect(&curses->main);
50 50 console->title = "Console"; console->title = "Console";
51 51 playlist = new Wsonglist; playlist = new Wsonglist;
52 playlist->set_rect(&curses->main);
53 52 playlist->title = "Playlist"; playlist->title = "Playlist";
54 53 library = new Wsonglist; library = new Wsonglist;
55 library->set_rect(&curses->main);
56 54 library->title = "Library"; library->title = "Library";
57 55 windows.push_back(WMAIN(console)); windows.push_back(WMAIN(console));
58 56 windows.push_back(WMAIN(playlist)); windows.push_back(WMAIN(playlist));
59 57 windows.push_back(WMAIN(library)); windows.push_back(WMAIN(library));
60 58 } }
61 59
60 void Windowmanager::init_ncurses()
61 {
62 if ((initscr()) == NULL)
63 {
64 ready = false;
65 return;
66 }
67
68 noecho();
69 raw();
70 nodelay(stdscr, true);
71 keypad(stdscr, true);
72 curs_set(0);
73
74 if (has_colors())
75 {
76 start_color();
77 use_default_colors();
78 }
79 }
80
81 Windowmanager::~Windowmanager()
82 {
83 clear();
84 refresh();
85 endwin();
86 }
87
88 void Windowmanager::detect_dimensions()
89 {
90 vector<Wmain *>::iterator wit;
91
92 topbar->set_dimensions(0, 0, config->topbar_height-1, COLS);
93 statusbar->set_dimensions(LINES-1, 0, LINES-1, COLS-4);
94 readout->set_dimensions(LINES-1, COLS-3, LINES-1, COLS);
95 wit = windows.begin();
96 while (wit != windows.end()) {
97 (*wit)->set_dimensions(config->topbar_height, 0, LINES-2, COLS);
98 ++wit;
99 }
100 }
101
62 102 void Windowmanager::draw() void Windowmanager::draw()
63 103 { {
64 104 topbar->draw(); topbar->draw();
65 105 statusbar->draw(); statusbar->draw();
66 106 readout->draw(); readout->draw();
67 107 active->draw(); active->draw();
68
69 108 flush(); flush();
70 109 } }
71 110
 
... ... void Windowmanager::qdraw()
90 129
91 130 void Windowmanager::flush() void Windowmanager::flush()
92 131 { {
93 curses->flush();
132 vector<Wmain *>::iterator wit;
133
134 topbar->flush();
135 statusbar->flush();
136 readout->flush();
137 wit = windows.begin();
138 while (wit != windows.end()) {
139 (*wit)->flush();
140 ++wit;
141 }
94 142 } }
95 143
96 144 bool Windowmanager::activate(Wmain * nactive) bool Windowmanager::activate(Wmain * nactive)
 
... ... void Windowmanager::cycle(int offset)
175 223
176 224 active->draw(); active->draw();
177 225 readout->draw(); readout->draw();
178 curses->flush();
179 226 } }
180 227
181 228 void Windowmanager::update_column_length() void Windowmanager::update_column_length()
 
... ... void Windowmanager::update_column_length()
188 235 w->update_column_length(); w->update_column_length();
189 236 } }
190 237 } }
238
239 void Windowmanager::bell()
240 {
241 if (!config->use_bell)
242 return;
243
244 if (config->visual_bell)
245 {
246 if (flash() == ERR)
247 beep();
248 }
249 else
250 {
251 if (beep() == ERR)
252 flash();
253 }
254 }
File src/wsonglist.cpp changed (mode: 100644) (index d3c738b..de28b35)
20 20
21 21 #include "window.h" #include "window.h"
22 22 #include "songlist.h" #include "songlist.h"
23 #include "curses.h"
24 23 #include "config.h" #include "config.h"
25 24 #include "mpd.h" #include "mpd.h"
26 25 #include "field.h" #include "field.h"
 
30 29
31 30 using namespace std; using namespace std;
32 31
33 extern Curses * curses;
34 32 extern Config * config; extern Config * config;
35 33 extern MPD * mpd; extern MPD * mpd;
36 34 extern Windowmanager * wm; extern Windowmanager * wm;
 
... ... void Wsonglist::draw()
40 38 unsigned int x = 0, i, it; unsigned int x = 0, i, it;
41 39 string wtitle; string wtitle;
42 40
43 if (!rect || !visible())
41 if (!visible())
44 42 return; return;
45 43
46 44 if (config->show_column_headers) if (config->show_column_headers)
47 45 { {
48 46 i = config->show_window_title ? 1 : 0; i = config->show_window_title ? 1 : 0;
49 curses->clearline(rect, i, config->colors.columnheader);
47 clearline(i, config->colors.columnheader);
50 48 for (it = 0; it < column_len.size(); ++it) for (it = 0; it < column_len.size(); ++it)
51 49 { {
52 curses->print(rect, config->colors.columnheader, i, x, config->songlist_columns[it]->title.c_str());
50 print(config->colors.columnheader, i, x, config->songlist_columns[it]->title.c_str());
53 51 x += column_len[it] + 1; x += column_len[it] + 1;
54 52 } }
55 53 } }
 
... ... void Wsonglist::draw()
59 57 wtitle = title; wtitle = title;
60 58 if (songlist->searchresult) if (songlist->searchresult)
61 59 wtitle += " <<search results>>"; wtitle += " <<search results>>";
62 curses->clearline(rect, 0, config->colors.windowtitle);
63 curses->print(rect, config->colors.windowtitle, 0, 0, wtitle.c_str());
60 clearline(0, config->colors.windowtitle);
61 print(config->colors.windowtitle, 0, 0, wtitle.c_str());
64 62 } }
65 63
66 64 Window::draw(); Window::draw();
 
... ... void Wsonglist::drawline(int rely)
82 80 if (config->show_column_headers) if (config->show_column_headers)
83 81 ++rely; ++rely;
84 82
85 if (!songlist || rely + rect->top > rect->bottom || linepos >= songlist->size())
83 if (!songlist || rely + rect.top > rect.bottom || linepos >= songlist->size())
86 84 { {
87 curses->clearline(rect, rely, config->colors.standard);
85 clearline(rely, config->colors.standard);
88 86 return; return;
89 87 } }
90 88
 
... ... void Wsonglist::drawline(int rely)
103 101 else else
104 102 color = NULL; color = NULL;
105 103
106 curses->clearline(rect, rely, color ? color : config->colors.standard);
104 clearline(rely, color ? color : config->colors.standard);
107 105
108 106 for (it = 0; it < column_len.size(); ++it) for (it = 0; it < column_len.size(); ++it)
109 107 { {
110 curses->print(rect, color ? color : config->colors.field[config->songlist_columns[it]->type], rely, x, song->f[config->songlist_columns[it]->type].c_str());
108 print(color ? color : config->colors.field[config->songlist_columns[it]->type], rely, x, song->f[config->songlist_columns[it]->type].c_str());
111 109 x += column_len[it] + 1; x += column_len[it] + 1;
112 110 } }
113 111 } }
 
... ... selection_t Wsonglist::get_selection(long multiplier)
147 145
148 146 unsigned int Wsonglist::height() unsigned int Wsonglist::height()
149 147 { {
150 if (!rect) return 0;
151 148 return Wmain::height() - (config->show_column_headers ? 1 : 0); return Wmain::height() - (config->show_column_headers ? 1 : 0);
152 149 } }
153 150
 
... ... void Wsonglist::update_column_length()
173 170
174 171 column_len.clear(); column_len.clear();
175 172
176 if (!rect || !songlist)
173 if (!songlist)
177 174 return; return;
178 175
179 max = rect->right - rect->left - config->songlist_columns.size() + 1;
176 max = rect.right - rect.left - config->songlist_columns.size() + 1;
180 177
181 178 for (column = config->songlist_columns.begin(); column != config->songlist_columns.end(); ++column) for (column = config->songlist_columns.begin(); column != config->songlist_columns.end(); ++column)
182 179 { {
File src/wstatusbar.cpp changed (mode: 100644) (index a5b0b72..ad4f890)
20 20
21 21 #include "window.h" #include "window.h"
22 22 #include "console.h" #include "console.h"
23 #include "curses.h"
24 23 #include "input.h" #include "input.h"
25 24 #include "config.h" #include "config.h"
26 25 #include "mpd.h" #include "mpd.h"
 
32 31 using namespace std; using namespace std;
33 32
34 33 extern vector<Logline *> logbuffer; extern vector<Logline *> logbuffer;
35 extern Curses * curses;
36 34 extern Windowmanager * wm; extern Windowmanager * wm;
37 35 extern Input * input; extern Input * input;
38 36 extern Config * config; extern Config * config;
 
... ... void Wstatusbar::drawline(int rely)
49 47 Wsonglist * ws; Wsonglist * ws;
50 48 string pstr; string pstr;
51 49 size_t vscroll = 0; size_t vscroll = 0;
52 size_t width = rect->right - rect->left;
50 size_t width = rect.right - rect.left;
53 51 vector<Logline *>::reverse_iterator i; vector<Logline *>::reverse_iterator i;
54 52 Color * c; Color * c;
55 53
 
... ... void Wstatusbar::drawline(int rely)
75 73 if ((ws = WSONGLIST(wm->active)) != NULL && ws->songlist->visual_start != -1) if ((ws = WSONGLIST(wm->active)) != NULL && ws->songlist->visual_start != -1)
76 74 { {
77 75 pstr = "-- VISUAL --"; pstr = "-- VISUAL --";
78 curses->wipe(rect, config->colors.statusbar);
79 curses->print(rect, config->colors.statusbar, rely, 0, pstr.c_str());
76 clear(config->colors.statusbar);
77 print(config->colors.statusbar, rely, 0, pstr.c_str());
80 78 break; break;
81 79 } }
82 80 cl_isreset = true; cl_isreset = true;
83 curses->wipe(rect, config->colors.statusbar);
84 curses->print(rect, config->colors.statusbar, rely, 0, mpd->playstring.c_str());
81 clear(config->colors.statusbar);
82 print(config->colors.statusbar, rely, 0, mpd->playstring.c_str());
85 83 break; break;
86 84 } }
87 85
88 86 /* Draw last statusbar message */ /* Draw last statusbar message */
89 87 cl_isreset = false; cl_isreset = false;
90 88 c = (*i)->level == MSG_LEVEL_ERR ? config->colors.error : config->colors.statusbar; c = (*i)->level == MSG_LEVEL_ERR ? config->colors.error : config->colors.statusbar;
91 curses->wipe(rect, c);
92 curses->print(rect, c, rely, 0, (*i)->line.c_str());
89 clear(c);
90 print(c, rely, 0, (*i)->line.c_str());
93 91 break; break;
94 92 } }
95 93 break; break;
 
... ... void Wstatusbar::drawline(int rely)
101 99 vscroll = input->strbuf.size() - width; vscroll = input->strbuf.size() - width;
102 100 if (vscroll > input->cursorpos) if (vscroll > input->cursorpos)
103 101 vscroll = input->cursorpos; vscroll = input->cursorpos;
104 curses->wipe(rect, config->colors.standard);
102 clear(config->colors.standard);
105 103
106 104 if (input->mode == INPUT_MODE_INPUT) if (input->mode == INPUT_MODE_INPUT)
107 105 pstr = ":"; pstr = ":";
 
... ... void Wstatusbar::drawline(int rely)
110 108 else if (input->mode == INPUT_MODE_LIVESEARCH) else if (input->mode == INPUT_MODE_LIVESEARCH)
111 109 pstr = "/"; pstr = "/";
112 110
113 curses->print(rect, config->colors.statusbar, rely, 0, pstr.c_str());
114 curses->print(rect, config->colors.statusbar, rely, pstr.size(), input->strbuf.substr(vscroll).c_str());
115 curses->setcursor(rect, rely, input->cursorpos - vscroll + pstr.size());
111 print(config->colors.statusbar, rely, 0, pstr.c_str());
112 print(config->colors.statusbar, rely, pstr.size(), input->strbuf.substr(vscroll).c_str());
113 wmove(window, rely, input->cursorpos - vscroll + pstr.size());
116 114 break; break;
117 115 } }
118 116 } }
 
... ... void Wreadout::drawline(int rely)
133 131 else else
134 132 sprintf(buf, "%2d", 100 * win->position / (win->content_size() - win->height() - 1)); sprintf(buf, "%2d", 100 * win->position / (win->content_size() - win->height() - 1));
135 133
136 curses->print(rect, config->colors.readout, 0, 0, "%s%%%%", buf);
134 print(config->colors.readout, 0, 0, "%s%%%%", buf);
137 135 } }
File src/wtopbar.cpp changed (mode: 100644) (index b98cafb..efae37f)
20 20
21 21 #include "window.h" #include "window.h"
22 22 #include "config.h" #include "config.h"
23 #include "curses.h"
24 23 #include "topbar.h" #include "topbar.h"
25 24 #include "field.h" #include "field.h"
26 25 #include "mpd.h" #include "mpd.h"
27 26
28 27 extern Config * config; extern Config * config;
29 extern Curses * curses;
30 28 extern Topbar * topbar; extern Topbar * topbar;
31 29 extern MPD * mpd; extern MPD * mpd;
32 30
 
... ... void Wtopbar::drawline(int rely)
39 37 int x; int x;
40 38 unsigned int strl; unsigned int strl;
41 39
42 if (!rect || rely < 0 || rely > (int)height())
40 if (rely < 0 || rely > (int)height())
43 41 return; return;
44 42
45 43 y = (unsigned int)rely; y = (unsigned int)rely;
46 44
47 curses->clearline(rect, y, config->colors.topbar);
45 clearline(y, config->colors.topbar);
48 46
49 47 /* Cycle left, center, right */ /* Cycle left, center, right */
50 48 for (pos = 0; pos < 3; pos++) for (pos = 0; pos < 3; pos++)
 
... ... void Wtopbar::drawline(int rely)
61 59 if (pos == 0) if (pos == 0)
62 60 x = 0; x = 0;
63 61 else if (pos == 1) else if (pos == 1)
64 x = ((rect->right - rect->left) / 2) - (strl / 2);
62 x = ((rect.right - rect.left) / 2) - (strl / 2);
65 63 else if (pos == 2) else if (pos == 2)
66 x = rect->right - rect->left - strl + 1;
64 x = rect.right - rect.left - strl + 1;
67 65
68 66 /* Iterate through segments and draw them */ /* Iterate through segments and draw them */
69 67 for (seg = topbar->lines[pos].at(y)->segments.begin(); seg != topbar->lines[pos].at(y)->segments.end(); ++seg) for (seg = topbar->lines[pos].at(y)->segments.begin(); seg != topbar->lines[pos].at(y)->segments.end(); ++seg)
70 68 { {
71 69 for (chunk = (*seg)->chunks.begin(); chunk != (*seg)->chunks.end(); ++chunk) for (chunk = (*seg)->chunks.begin(); chunk != (*seg)->chunks.end(); ++chunk)
72 70 { {
73 curses->print(rect, (*chunk)->color, rely, x, (*chunk)->str.c_str());
71 print((*chunk)->color, rely, x, (*chunk)->str.c_str());
74 72 x += (*chunk)->str.size(); x += (*chunk)->str.size();
75 73 } }
76 74 } }
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/pms

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/pms

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master