Task 2.0.0 Code Salvage

This commit is contained in:
Paul Beckingham
2010-09-09 20:49:17 -04:00
parent 7f54b89f24
commit 73ff6ea973
29 changed files with 2713 additions and 4 deletions

221
src/ui/UI.cpp Normal file
View File

@@ -0,0 +1,221 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2010, Paul Beckingham.
// All rights reserved.
//
// 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 Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <ncurses.h>
#include <ctype.h>
#include <pthread.h>
#include "log.h"
#include "UI.h"
// Constriction point for ncurses calls.
pthread_mutex_t conch = PTHREAD_MUTEX_INITIALIZER;
////////////////////////////////////////////////////////////////////////////////
UI::UI ()
: current (NULL)
{
}
////////////////////////////////////////////////////////////////////////////////
UI::~UI ()
{
std::map <std::string, Layout*>::iterator it;
for (it = layouts.begin (); it != layouts.end (); ++it)
delete it->second;
layouts.clear ();
}
////////////////////////////////////////////////////////////////////////////////
void UI::add (const std::string& name, Layout* layout)
{
logWrite ("UI::add %s", name.c_str ());
layouts[name] = layout;
// First layout added automatically becomes the current layout. Subsequent
// layouts accumulate.
if (current == NULL)
current = layout;
}
////////////////////////////////////////////////////////////////////////////////
void UI::switchLayout (const std::string& name)
{
logWrite ("UI::switchLayout %s", name.c_str ());
if (layouts.find (name) == layouts.end ())
throw std::string ("Cannot switch to non-existent layout '") + name + "'";
// Only switch if the proposed layout is not the current layout.
if (layouts[name] != current)
{
// Close the old windows.
current->deinitialize ();
// Set the new current layout.
current = layouts[name];
// Create the new windows.
current->initialize ();
// Need a size recalc, because the new current layout may have been used
// before at a different size.
this->recalc (COLS, LINES);
}
}
////////////////////////////////////////////////////////////////////////////////
void UI::initialize ()
{
logWrite ("UI::initialize");
// Rainbow.
init_pair (1, COLOR_WHITE, COLOR_BLUE);
init_pair (2, COLOR_WHITE, COLOR_RED);
init_pair (3, COLOR_BLACK, COLOR_GREEN);
init_pair (4, COLOR_WHITE, COLOR_MAGENTA);
init_pair (5, COLOR_BLACK, COLOR_CYAN);
init_pair (6, COLOR_BLACK, COLOR_YELLOW);
init_pair (7, COLOR_BLACK, COLOR_WHITE);
init_pair (8, COLOR_CYAN, COLOR_BLUE);
init_pair (9, COLOR_BLUE, COLOR_CYAN);
init_pair (10, COLOR_YELLOW, COLOR_BLUE);
// init_pair (11, COLOR_GREEN, COLOR_BLACK);
// Plain.
init_pair (20, COLOR_WHITE, COLOR_BLACK);
// Propagate to current layout.
current->initialize ();
}
////////////////////////////////////////////////////////////////////////////////
void UI::deinitialize ()
{
logWrite ("UI::deinitialize");
current->deinitialize ();
}
////////////////////////////////////////////////////////////////////////////////
void UI::interactive ()
{
logWrite ("UI::interactive");
if (!current)
throw std::string ("Cannot start interactive mode without an initial layout.");
initscr ();
logWrite ("UI::interactive ncurses started");
refresh (); // Blank screen.
curs_set (0);
if (has_colors ())
start_color ();
this->recalc (COLS, LINES);
this->initialize ();
current->redraw ();
keypad (stdscr, TRUE);
noecho ();
nl ();
raw ();
cbreak ();
mousemask (ALL_MOUSE_EVENTS, NULL);
while (this->event (getch ()))
;
this->deinitialize ();
endwin ();
logWrite ("UI::interactive ncurses stopped");
}
////////////////////////////////////////////////////////////////////////////////
bool UI::event (int e)
{
switch (e)
{
case 'd': // Default layout
switchLayout ("default");
this->recalc (COLS, LINES);
current->redraw (true);
break;
case 's': // report.stats layout
switchLayout ("report.stats");
this->recalc (COLS, LINES);
current->redraw (true);
break;
case 'Q': // Quit.
case 'q': // quit.
logWrite ("UI::event %c", (char)e);
return false;
break;
case ERR: // No need to propagate this.
logWrite ("UI::event ERR ignored");
break;
case KEY_RESIZE: // This gets propagated through UI::recalc.
logWrite ("UI::event KEY_RESIZE");
this->recalc (COLS, LINES);
current->redraw (true); // TODO has no apparent effect.
break;
default: // Unhandled events are propagated.
// Ctrl-L is handled by the layout.
logWrite ("UI::event %d delegated", e);
current->event (e);
break;
}
return true; // Continue;
}
////////////////////////////////////////////////////////////////////////////////
// This is called at the beginning, to calculate element sizes, and on every
// window resize.
void UI::recalc (int w, int h)
{
logWrite ("UI::recalc %d,%d", w, h);
// The current layout needs to know.
current->recalc (w, h);
// Park the cursor.
// TODO Evaluate whether this is needed.
pthread_mutex_lock (&conch);
move (h - 1, w - 1);
pthread_mutex_unlock (&conch);
}
////////////////////////////////////////////////////////////////////////////////