mirror of
https://github.com/nzbget/nzbget.git
synced 2026-02-18 14:53:58 -05:00
1306 lines
32 KiB
C++
1306 lines
32 KiB
C++
/*
|
|
* This file if part of nzbget
|
|
*
|
|
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
|
* Copyright (C) 2007 Andrei Prygounkov <hugbug@users.sourceforge.net>
|
|
*
|
|
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* $Revision$
|
|
* $Date$
|
|
*
|
|
*/
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#include "win32.h"
|
|
#endif
|
|
|
|
#ifndef DISABLE_CURSES
|
|
|
|
#ifdef HAVE_NCURSES_H
|
|
#include <ncurses.h>
|
|
#endif
|
|
#ifdef HAVE_NCURSES_NCURSES_H
|
|
#include <ncurses/ncurses.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifndef WIN32
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include "nzbget.h"
|
|
#include "NCursesFrontend.h"
|
|
#include "Options.h"
|
|
|
|
#ifdef HAVE_CURSES_H
|
|
// curses.h header must be included last to avoid problems on Solaris
|
|
// (and possibly other systems, that uses curses.h (not ncurses.h)
|
|
#include <curses.h>
|
|
// "#undef erase" is neccessary on Solaris
|
|
#undef erase
|
|
#endif
|
|
|
|
extern Options* g_pOptions;
|
|
extern void ExitProc();
|
|
|
|
static const int NCURSES_COLORPAIR_TEXT = 1;
|
|
static const int NCURSES_COLORPAIR_INFO = 2;
|
|
static const int NCURSES_COLORPAIR_WARNING = 3;
|
|
static const int NCURSES_COLORPAIR_ERROR = 4;
|
|
static const int NCURSES_COLORPAIR_DEBUG = 5;
|
|
static const int NCURSES_COLORPAIR_STATUS = 6;
|
|
static const int NCURSES_COLORPAIR_KEYBAR = 7;
|
|
static const int NCURSES_COLORPAIR_INFOLINE = 8;
|
|
static const int NCURSES_COLORPAIR_TEXTHIGHL = 9;
|
|
static const int NCURSES_COLORPAIR_CURSOR = 10;
|
|
|
|
static const int MAX_SCREEN_WIDTH = 512;
|
|
|
|
#ifdef WIN32
|
|
static const int COLOR_BLACK = 0;
|
|
static const int COLOR_BLUE = FOREGROUND_BLUE;
|
|
static const int COLOR_RED = FOREGROUND_RED;
|
|
static const int COLOR_GREEN = FOREGROUND_GREEN;
|
|
static const int COLOR_WHITE = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
|
|
static const int COLOR_MAGENTA = FOREGROUND_RED | FOREGROUND_BLUE;
|
|
static const int COLOR_CYAN = FOREGROUND_BLUE | FOREGROUND_GREEN;
|
|
static const int COLOR_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;
|
|
|
|
static const int READKEY_EMPTY = 0;
|
|
|
|
#define KEY_DOWN VK_DOWN
|
|
#define KEY_UP VK_UP
|
|
#define KEY_PPAGE VK_PRIOR
|
|
#define KEY_NPAGE VK_NEXT
|
|
#define KEY_END VK_END
|
|
#define KEY_HOME VK_HOME
|
|
#define KEY_BACKSPACE VK_BACK
|
|
|
|
#else
|
|
|
|
static const int READKEY_EMPTY = ERR;
|
|
|
|
#endif
|
|
|
|
NCursesFrontend::GroupInfo::GroupInfo(int iID, const char* szNZBFilename)
|
|
{
|
|
m_iID = iID;
|
|
m_szNZBFilename = strdup(szNZBFilename);
|
|
m_iFileCount = 0;
|
|
m_lSize = 0;
|
|
m_lRemainingSize = 0;
|
|
m_lPausedSize = 0;
|
|
}
|
|
|
|
NCursesFrontend::GroupInfo::~GroupInfo()
|
|
{
|
|
if (m_szNZBFilename)
|
|
{
|
|
free(m_szNZBFilename);
|
|
}
|
|
}
|
|
|
|
NCursesFrontend::NCursesFrontend()
|
|
{
|
|
m_iScreenHeight = 0;
|
|
m_iScreenWidth = 0;
|
|
m_iInputNumberIndex = 0;
|
|
m_eInputMode = eNormal;
|
|
m_bSummary = true;
|
|
m_bFileList = true;
|
|
m_iNeededLogEntries = 0;
|
|
m_iQueueWinTop = 0;
|
|
m_iQueueWinHeight = 0;
|
|
m_iQueueWinClientHeight = 0;
|
|
m_iMessagesWinTop = 0;
|
|
m_iMessagesWinHeight = 0;
|
|
m_iMessagesWinClientHeight = 0;
|
|
m_iSelectedQueueEntry = 0;
|
|
m_iQueueScrollOffset = 0;
|
|
m_bShowNZBname = g_pOptions->GetCursesNZBName();
|
|
m_bShowTimestamp = g_pOptions->GetCursesTime();
|
|
m_bGroupFiles = g_pOptions->GetCursesGroup();
|
|
m_QueueWindowPercentage = 0.5f;
|
|
m_iDataUpdatePos = 0;
|
|
|
|
m_groupQueue.clear();
|
|
|
|
// Setup curses
|
|
#ifdef WIN32
|
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
m_pScreenBuffer = NULL;
|
|
m_pOldScreenBuffer = NULL;
|
|
m_ColorAttr.clear();
|
|
|
|
CONSOLE_CURSOR_INFO ConsoleCursorInfo;
|
|
GetConsoleCursorInfo(hConsole, &ConsoleCursorInfo);
|
|
ConsoleCursorInfo.bVisible = false;
|
|
SetConsoleCursorInfo(hConsole, &ConsoleCursorInfo);
|
|
if (IsRemoteMode())
|
|
{
|
|
SetConsoleTitle("NZBGet - remote mode");
|
|
}
|
|
else
|
|
{
|
|
SetConsoleTitle("NZBGet");
|
|
}
|
|
|
|
m_bUseColor = true;
|
|
#else
|
|
m_pWindow = initscr();
|
|
if (m_pWindow == NULL)
|
|
{
|
|
printf("ERROR: m_pWindow == NULL\n");
|
|
exit(-1);
|
|
}
|
|
keypad(stdscr, true);
|
|
nodelay((WINDOW*)m_pWindow, true);
|
|
noecho();
|
|
curs_set(0);
|
|
m_bUseColor = has_colors();
|
|
#endif
|
|
|
|
if (m_bUseColor)
|
|
{
|
|
#ifndef WIN32
|
|
start_color();
|
|
#endif
|
|
init_pair(0, COLOR_WHITE, COLOR_BLUE);
|
|
init_pair(NCURSES_COLORPAIR_TEXT, COLOR_WHITE, COLOR_BLACK);
|
|
init_pair(NCURSES_COLORPAIR_INFO, COLOR_GREEN, COLOR_BLACK);
|
|
init_pair(NCURSES_COLORPAIR_WARNING, COLOR_MAGENTA, COLOR_BLACK);
|
|
init_pair(NCURSES_COLORPAIR_ERROR, COLOR_RED, COLOR_BLACK);
|
|
init_pair(NCURSES_COLORPAIR_DEBUG, COLOR_WHITE, COLOR_BLACK);
|
|
init_pair(NCURSES_COLORPAIR_STATUS, COLOR_BLUE, COLOR_WHITE);
|
|
init_pair(NCURSES_COLORPAIR_KEYBAR, COLOR_WHITE, COLOR_BLUE);
|
|
init_pair(NCURSES_COLORPAIR_INFOLINE, COLOR_WHITE, COLOR_BLUE);
|
|
init_pair(NCURSES_COLORPAIR_TEXTHIGHL, COLOR_BLACK, COLOR_CYAN);
|
|
init_pair(NCURSES_COLORPAIR_CURSOR, COLOR_BLACK, COLOR_YELLOW);
|
|
}
|
|
}
|
|
|
|
NCursesFrontend::~NCursesFrontend()
|
|
{
|
|
#ifdef WIN32
|
|
if (m_pScreenBuffer)
|
|
{
|
|
free(m_pScreenBuffer);
|
|
}
|
|
if (m_pOldScreenBuffer)
|
|
{
|
|
free(m_pOldScreenBuffer);
|
|
}
|
|
m_ColorAttr.clear();
|
|
|
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
CONSOLE_CURSOR_INFO ConsoleCursorInfo;
|
|
GetConsoleCursorInfo(hConsole, &ConsoleCursorInfo);
|
|
ConsoleCursorInfo.bVisible = true;
|
|
SetConsoleCursorInfo(hConsole, &ConsoleCursorInfo);
|
|
#else
|
|
keypad(stdscr, false);
|
|
echo();
|
|
curs_set(1);
|
|
endwin();
|
|
#endif
|
|
printf("\n");
|
|
}
|
|
|
|
void NCursesFrontend::Run()
|
|
{
|
|
debug("Entering NCursesFrontend-loop");
|
|
|
|
int iScreenUpdateInterval = 25;
|
|
int iScreenUpdatePos = 0;
|
|
m_iDataUpdatePos = 0;
|
|
|
|
while (!IsStopped())
|
|
{
|
|
// The data (queue and log) is updated each m_iUpdateInterval msec,
|
|
// but the window is updated more often for better reaction on user's input
|
|
if (iScreenUpdatePos <= 0)
|
|
{
|
|
iScreenUpdatePos = iScreenUpdateInterval;
|
|
Update();
|
|
if (m_iDataUpdatePos <= 0)
|
|
{
|
|
m_iDataUpdatePos = m_iUpdateInterval;
|
|
}
|
|
}
|
|
|
|
usleep(10 * 1000);
|
|
iScreenUpdatePos -= 10;
|
|
m_iDataUpdatePos -= 10;
|
|
}
|
|
|
|
FreeData();
|
|
ClearGroupQueue();
|
|
|
|
debug("Exiting NCursesFrontend-loop");
|
|
}
|
|
|
|
void NCursesFrontend::NeedUpdateData()
|
|
{
|
|
m_iDataUpdatePos = 10;
|
|
}
|
|
|
|
void NCursesFrontend::Update()
|
|
{
|
|
// Figure out how big the screen is
|
|
CalcWindowSizes();
|
|
|
|
if (m_iDataUpdatePos <= 0)
|
|
{
|
|
FreeData();
|
|
ClearGroupQueue();
|
|
m_iNeededLogEntries = m_iMessagesWinClientHeight;
|
|
if (!PrepareData())
|
|
{
|
|
return;
|
|
}
|
|
PrepareGroupQueue();
|
|
}
|
|
|
|
if (m_eInputMode == eEditQueue)
|
|
{
|
|
int iQueueSize = CalcQueueSize();
|
|
if (iQueueSize == 0)
|
|
{
|
|
m_iSelectedQueueEntry = 0;
|
|
m_eInputMode = eNormal;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------
|
|
// Print Current NZBQueue
|
|
//------------------------------------------
|
|
if (m_iQueueWinHeight > 0)
|
|
{
|
|
PrintQueue();
|
|
}
|
|
|
|
//------------------------------------------
|
|
// Print Messages
|
|
//------------------------------------------
|
|
if (m_iMessagesWinHeight > 0)
|
|
{
|
|
PrintMessages();
|
|
}
|
|
|
|
PrintStatus();
|
|
|
|
PrintKeyInputBar();
|
|
|
|
// Update the input
|
|
UpdateInput();
|
|
|
|
RefreshScreen();
|
|
}
|
|
|
|
void NCursesFrontend::CalcWindowSizes()
|
|
{
|
|
int iNrRows, iNrColumns;
|
|
#ifdef WIN32
|
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
CONSOLE_SCREEN_BUFFER_INFO BufInfo;
|
|
GetConsoleScreenBufferInfo(hConsole, &BufInfo);
|
|
iNrRows = BufInfo.srWindow.Bottom - BufInfo.srWindow.Top + 1;
|
|
iNrColumns = BufInfo.srWindow.Right - BufInfo.srWindow.Left + 1;
|
|
#else
|
|
getmaxyx(stdscr, iNrRows, iNrColumns);
|
|
#endif
|
|
if (iNrRows != m_iScreenHeight || iNrColumns != m_iScreenWidth)
|
|
{
|
|
#ifdef WIN32
|
|
m_iScreenBufferSize = iNrRows * iNrColumns * sizeof(CHAR_INFO);
|
|
m_pScreenBuffer = (CHAR_INFO*)malloc(m_iScreenBufferSize);
|
|
memset(m_pScreenBuffer, 0, m_iScreenBufferSize);
|
|
m_pOldScreenBuffer = (CHAR_INFO*)malloc(m_iScreenBufferSize);
|
|
memset(m_pOldScreenBuffer, 0, m_iScreenBufferSize);
|
|
#else
|
|
clear();
|
|
#endif
|
|
m_iScreenHeight = iNrRows;
|
|
m_iScreenWidth = iNrColumns;
|
|
}
|
|
|
|
int iQueueSize = CalcQueueSize();
|
|
|
|
m_iQueueWinTop = 0;
|
|
m_iQueueWinHeight = (int)((float) (m_iScreenHeight - 2) * m_QueueWindowPercentage);
|
|
if (m_iQueueWinHeight - 1 > iQueueSize)
|
|
{
|
|
m_iQueueWinHeight = iQueueSize > 0 ? iQueueSize + 1 : 1 + 1;
|
|
}
|
|
m_iQueueWinClientHeight = m_iQueueWinHeight - 1;
|
|
if (m_iQueueWinClientHeight < 0)
|
|
{
|
|
m_iQueueWinClientHeight = 0;
|
|
}
|
|
|
|
m_iMessagesWinTop = m_iQueueWinTop + m_iQueueWinHeight;
|
|
m_iMessagesWinHeight = m_iScreenHeight - m_iQueueWinHeight - 2;
|
|
m_iMessagesWinClientHeight = m_iMessagesWinHeight - 1;
|
|
if (m_iMessagesWinClientHeight < 0)
|
|
{
|
|
m_iMessagesWinClientHeight = 0;
|
|
}
|
|
}
|
|
|
|
int NCursesFrontend::CalcQueueSize()
|
|
{
|
|
if (m_bGroupFiles)
|
|
{
|
|
return m_groupQueue.size();
|
|
}
|
|
else
|
|
{
|
|
DownloadQueue* pDownloadQueue = LockQueue();
|
|
int iQueueSize = pDownloadQueue->size();
|
|
UnlockQueue();
|
|
return iQueueSize;
|
|
}
|
|
}
|
|
|
|
void NCursesFrontend::PlotLine(const char * szString, int iRow, int iPos, int iColorPair)
|
|
{
|
|
char szBuffer[MAX_SCREEN_WIDTH];
|
|
snprintf(szBuffer, sizeof(szBuffer), "%-*s", m_iScreenWidth, szString);
|
|
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
|
int iLen = strlen(szBuffer);
|
|
if (iLen > m_iScreenWidth - iPos && m_iScreenWidth - iPos < MAX_SCREEN_WIDTH)
|
|
{
|
|
szBuffer[m_iScreenWidth - iPos] = '\0';
|
|
}
|
|
|
|
PlotText(szBuffer, iRow, iPos, iColorPair, false);
|
|
}
|
|
|
|
void NCursesFrontend::PlotText(const char * szString, int iRow, int iPos, int iColorPair, bool bBlink)
|
|
{
|
|
#ifdef WIN32
|
|
int iBufPos = iRow * m_iScreenWidth + iPos;
|
|
int len = strlen(szString);
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
m_pScreenBuffer[iBufPos + i].Char.AsciiChar = szString[i];
|
|
m_pScreenBuffer[iBufPos + i].Attributes = m_ColorAttr[iColorPair];
|
|
}
|
|
#else
|
|
if( m_bUseColor )
|
|
{
|
|
attron(COLOR_PAIR(iColorPair));
|
|
if (bBlink)
|
|
{
|
|
attron(A_BLINK);
|
|
}
|
|
}
|
|
mvaddstr(iRow, iPos, (char*)szString);
|
|
if( m_bUseColor )
|
|
{
|
|
attroff(COLOR_PAIR(iColorPair));
|
|
if (bBlink)
|
|
{
|
|
attroff(A_BLINK);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void NCursesFrontend::RefreshScreen()
|
|
{
|
|
#ifdef WIN32
|
|
bool bBufChanged = memcmp(m_pScreenBuffer, m_pOldScreenBuffer, m_iScreenBufferSize);
|
|
if (bBufChanged)
|
|
{
|
|
COORD BufSize;
|
|
BufSize.X = m_iScreenWidth;
|
|
BufSize.Y = m_iScreenHeight;
|
|
|
|
COORD BufCoord;
|
|
BufCoord.X = 0;
|
|
BufCoord.Y = 0;
|
|
|
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
CONSOLE_SCREEN_BUFFER_INFO BufInfo;
|
|
GetConsoleScreenBufferInfo(hConsole, &BufInfo);
|
|
WriteConsoleOutput(hConsole, m_pScreenBuffer, BufSize, BufCoord, &BufInfo.srWindow);
|
|
|
|
BufInfo.dwCursorPosition.X = BufInfo.srWindow.Right;
|
|
BufInfo.dwCursorPosition.Y = BufInfo.srWindow.Bottom;
|
|
SetConsoleCursorPosition(hConsole, BufInfo.dwCursorPosition);
|
|
|
|
memcpy(m_pOldScreenBuffer, m_pScreenBuffer, m_iScreenBufferSize);
|
|
}
|
|
#else
|
|
// Cursor placement
|
|
wmove((WINDOW*)m_pWindow, m_iScreenHeight, m_iScreenWidth);
|
|
|
|
// NCurses refresh
|
|
refresh();
|
|
#endif
|
|
}
|
|
|
|
#ifdef WIN32
|
|
void NCursesFrontend::init_pair(int iColorNumber, WORD wForeColor, WORD wBackColor)
|
|
{
|
|
m_ColorAttr.resize(iColorNumber + 1);
|
|
m_ColorAttr[iColorNumber] = wForeColor | (wBackColor << 4);
|
|
}
|
|
#endif
|
|
|
|
void NCursesFrontend::PrintMessages()
|
|
{
|
|
int iLineNr = m_iMessagesWinTop;
|
|
|
|
char szBuffer[MAX_SCREEN_WIDTH];
|
|
snprintf(szBuffer, sizeof(szBuffer), "%s Messages", m_bUseColor ? "" : "*** ");
|
|
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
|
PlotLine(szBuffer, iLineNr++, 0, NCURSES_COLORPAIR_INFOLINE);
|
|
|
|
int iLine = iLineNr + m_iMessagesWinClientHeight - 1;
|
|
int iLinesToPrint = m_iMessagesWinClientHeight;
|
|
|
|
Log::Messages* pMessages = LockMessages();
|
|
|
|
// print messages from bottom
|
|
for (int i = (int)pMessages->size() - 1; i >= 0 && iLinesToPrint > 0; i--)
|
|
{
|
|
int iPrintedLines = PrintMessage((*pMessages)[i], iLine, iLinesToPrint);
|
|
iLine -= iPrintedLines;
|
|
iLinesToPrint -= iPrintedLines;
|
|
}
|
|
|
|
if (iLinesToPrint > 0)
|
|
{
|
|
// too few messages, print them again from top
|
|
iLine = iLineNr + m_iMessagesWinClientHeight - 1;
|
|
while (iLinesToPrint-- > 0)
|
|
{
|
|
PlotLine("", iLine--, 0, NCURSES_COLORPAIR_TEXT);
|
|
}
|
|
int iLinesToPrint2 = m_iMessagesWinClientHeight;
|
|
for (int i = (int)pMessages->size() - 1; i >= 0 && iLinesToPrint2 > 0; i--)
|
|
{
|
|
int iPrintedLines = PrintMessage((*pMessages)[i], iLine, iLinesToPrint2);
|
|
iLine -= iPrintedLines;
|
|
iLinesToPrint2 -= iPrintedLines;
|
|
}
|
|
}
|
|
|
|
UnlockMessages();
|
|
}
|
|
|
|
int NCursesFrontend::PrintMessage(Message* Msg, int iRow, int iMaxLines)
|
|
{
|
|
char* szMessageType[] = { "INFO ", "WARNING ", "ERROR ", "DEBUG "};
|
|
const int iMessageTypeColor[] = { NCURSES_COLORPAIR_INFO, NCURSES_COLORPAIR_WARNING,
|
|
NCURSES_COLORPAIR_ERROR, NCURSES_COLORPAIR_DEBUG };
|
|
|
|
char* szText = (char*)Msg->GetText();
|
|
|
|
if (m_bShowTimestamp)
|
|
{
|
|
int iLen = strlen(szText) + 50;
|
|
szText = (char*)malloc(iLen);
|
|
|
|
time_t rawtime = Msg->GetTime();
|
|
char szTime[50];
|
|
#ifdef HAVE_CTIME_R_3
|
|
ctime_r(&rawtime, szTime, 50);
|
|
#else
|
|
ctime_r(&rawtime, szTime);
|
|
#endif
|
|
szTime[50-1] = '\0';
|
|
szTime[strlen(szTime) - 1] = '\0'; // trim LF
|
|
|
|
snprintf(szText, iLen, "%s - %s", szTime, Msg->GetText());
|
|
szText[iLen - 1] = '\0';
|
|
}
|
|
else
|
|
{
|
|
szText = strdup(szText);
|
|
}
|
|
|
|
// replace CR and LF characters with spaces
|
|
for (char* p = szText; *p; p++)
|
|
{
|
|
if (*p == '\n' || *p == '\r')
|
|
{
|
|
*p = ' ';
|
|
}
|
|
}
|
|
|
|
int iLen = strlen(szText);
|
|
int iWinWidth = m_iScreenWidth - 8;
|
|
int iMsgLines = iLen / iWinWidth;
|
|
if (iLen % iWinWidth > 0)
|
|
{
|
|
iMsgLines++;
|
|
}
|
|
|
|
int iLines = 0;
|
|
for (int i = iMsgLines - 1; i >= 0 && iLines < iMaxLines; i--)
|
|
{
|
|
int iR = iRow - iMsgLines + i + 1;
|
|
PlotLine(szText + iWinWidth * i, iR, 8, NCURSES_COLORPAIR_TEXT);
|
|
if (i == 0)
|
|
{
|
|
PlotText(szMessageType[Msg->GetKind()], iR, 0, iMessageTypeColor[Msg->GetKind()], false);
|
|
}
|
|
else
|
|
{
|
|
PlotText(" ", iR, 0, iMessageTypeColor[Msg->GetKind()], false);
|
|
}
|
|
iLines++;
|
|
}
|
|
|
|
free(szText);
|
|
|
|
return iLines;
|
|
}
|
|
|
|
void NCursesFrontend::PrintStatus()
|
|
{
|
|
char tmp[MAX_SCREEN_WIDTH];
|
|
int iStatusRow = m_iScreenHeight - 2;
|
|
|
|
char timeString[100];
|
|
timeString[0] = '\0';
|
|
|
|
if (m_fCurrentDownloadSpeed > 0.0)
|
|
{
|
|
long long remain_sec = (long long)(m_lRemainingSize / (m_fCurrentDownloadSpeed * 1024));
|
|
int h = 0;
|
|
int m = 0;
|
|
int s = 0;
|
|
while (remain_sec > 3600)
|
|
{
|
|
h++;
|
|
remain_sec -= 3600;
|
|
}
|
|
while (remain_sec > 60)
|
|
{
|
|
m++;
|
|
remain_sec -= 60;
|
|
}
|
|
s = remain_sec;
|
|
|
|
sprintf(timeString, " (~ %.2d:%.2d:%.2d)", h, m, s);
|
|
}
|
|
|
|
char szDownloadLimit[128];
|
|
if (m_fDownloadLimit > 0.0f)
|
|
{
|
|
sprintf(szDownloadLimit, ", Limit %.0f KB/s", m_fDownloadLimit);
|
|
}
|
|
else
|
|
{
|
|
szDownloadLimit[0] = 0;
|
|
}
|
|
|
|
char szParStatus[128];
|
|
if (m_iParJobCount > 0)
|
|
{
|
|
sprintf(szParStatus, ", processing %i par%s", m_iParJobCount, m_iParJobCount > 1 ? "s" : "");
|
|
}
|
|
else
|
|
{
|
|
szParStatus[0] = 0;
|
|
}
|
|
|
|
snprintf(tmp, MAX_SCREEN_WIDTH, " %d threads, %.0f KB/s, %.2f MB remaining%s%s%s%s", m_iThreadCount, m_fCurrentDownloadSpeed, (float)(m_lRemainingSize / 1024.0 / 1024.0), timeString, szParStatus, m_bPause ? ", Paused" : "", szDownloadLimit);
|
|
tmp[MAX_SCREEN_WIDTH - 1] = '\0';
|
|
PlotLine(tmp, iStatusRow, 0, NCURSES_COLORPAIR_STATUS);
|
|
}
|
|
|
|
void NCursesFrontend::PrintKeyInputBar()
|
|
{
|
|
int iQueueSize = CalcQueueSize();
|
|
int iInputBarRow = m_iScreenHeight - 1;
|
|
|
|
switch (m_eInputMode)
|
|
{
|
|
case eNormal:
|
|
PlotLine("(Q)uit | (E)dit | (P)ause | (R)ate | n(Z)b | (W)indow | (T)ime | (G)roup", iInputBarRow, 0, NCURSES_COLORPAIR_KEYBAR);
|
|
break;
|
|
case eEditQueue:
|
|
{
|
|
char* szStatus = NULL;
|
|
if (m_iSelectedQueueEntry > 0 && iQueueSize > 1 && m_iSelectedQueueEntry == iQueueSize - 1)
|
|
{
|
|
if (m_bGroupFiles)
|
|
{
|
|
// Up-/Down-commands for groups not supported yet
|
|
szStatus = "(Q)uit | (E)xit | (P)ause | (D)elete | (T)op";
|
|
}
|
|
else
|
|
{
|
|
szStatus = "(Q)uit | (E)xit | (P)ause | (D)elete | (U)p/(T)op";
|
|
}
|
|
}
|
|
else if (iQueueSize > 1 && m_iSelectedQueueEntry == 0)
|
|
{
|
|
if (m_bGroupFiles)
|
|
{
|
|
// Up-/Down-commands for groups not supported yet
|
|
szStatus = "(Q)uit | (E)xit | (P)ause | (D)elete | (B)ottom";
|
|
}
|
|
else
|
|
{
|
|
szStatus = "(Q)uit | (E)xit | (P)ause | (D)elete | dow(N)/(B)ottom";
|
|
}
|
|
}
|
|
else if (iQueueSize > 1)
|
|
{
|
|
if (m_bGroupFiles)
|
|
{
|
|
// Up-/Down-commands for groups not supported yet
|
|
szStatus = "(Q)uit | (E)xit | (P)ause | (D)elete | (T)op/(B)ottom";
|
|
}
|
|
else
|
|
{
|
|
szStatus = "(Q)uit | (E)xit | (P)ause | (D)elete | (U)p/dow(N)/(T)op/(B)ottom";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
szStatus = "(Q)uit | (E)xit | (P)ause | (D)elete";
|
|
}
|
|
|
|
PlotLine(szStatus, iInputBarRow, 0, NCURSES_COLORPAIR_KEYBAR);
|
|
break;
|
|
}
|
|
case eDownloadRate:
|
|
char szString[128];
|
|
snprintf(szString, 128, "Download rate: %i", m_iInputValue);
|
|
szString[128-1] = '\0';
|
|
PlotLine(szString, iInputBarRow, 0, NCURSES_COLORPAIR_KEYBAR);
|
|
// Print the cursor
|
|
PlotText(" ", iInputBarRow, 15 + m_iInputNumberIndex, NCURSES_COLORPAIR_CURSOR, true);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void NCursesFrontend::PrintQueue()
|
|
{
|
|
if (m_bGroupFiles)
|
|
{
|
|
PrintGroupQueue();
|
|
}
|
|
else
|
|
{
|
|
PrintFileQueue();
|
|
}
|
|
}
|
|
|
|
void NCursesFrontend::PrintFileQueue()
|
|
{
|
|
int iLineNr = m_iQueueWinTop;
|
|
|
|
DownloadQueue* pDownloadQueue = LockQueue();
|
|
if (pDownloadQueue->empty())
|
|
{
|
|
char szBuffer[MAX_SCREEN_WIDTH];
|
|
snprintf(szBuffer, sizeof(szBuffer), "%s Files for downloading", m_bUseColor ? "" : "*** ");
|
|
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
|
PlotLine(szBuffer, iLineNr++, 0, NCURSES_COLORPAIR_INFOLINE);
|
|
PlotLine("Ready to receive nzb-job", iLineNr++, 0, NCURSES_COLORPAIR_TEXT);
|
|
}
|
|
else
|
|
{
|
|
iLineNr++;
|
|
long long lRemaining = 0;
|
|
long long lPaused = 0;
|
|
int iPausedFiles = 0;
|
|
int i = 0;
|
|
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++, i++)
|
|
{
|
|
FileInfo* pFileInfo = *it;
|
|
|
|
if (i >= m_iQueueScrollOffset && i < m_iQueueScrollOffset + m_iQueueWinHeight -1)
|
|
{
|
|
PrintFilename(pFileInfo, iLineNr++, i == m_iSelectedQueueEntry);
|
|
}
|
|
|
|
if (pFileInfo->GetPaused())
|
|
{
|
|
iPausedFiles++;
|
|
lPaused += pFileInfo->GetRemainingSize();
|
|
}
|
|
lRemaining += pFileInfo->GetRemainingSize();
|
|
}
|
|
|
|
char szRemaining[20];
|
|
FormatFileSize(szRemaining, sizeof(szRemaining), lRemaining);
|
|
|
|
char szUnpaused[20];
|
|
FormatFileSize(szUnpaused, sizeof(szUnpaused), lRemaining - lPaused);
|
|
|
|
char szBuffer[MAX_SCREEN_WIDTH];
|
|
snprintf(szBuffer, sizeof(szBuffer), " %sFiles for downloading - %i / %i files in queue - %s / %s",
|
|
m_bUseColor ? "" : "*** ", pDownloadQueue->size(), pDownloadQueue->size() - iPausedFiles, szRemaining, szUnpaused);
|
|
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
|
PlotLine(szBuffer, m_iQueueWinTop, 0, NCURSES_COLORPAIR_INFOLINE);
|
|
}
|
|
UnlockQueue();
|
|
}
|
|
|
|
void NCursesFrontend::PrintFilename(FileInfo * pFileInfo, int iRow, bool bSelected)
|
|
{
|
|
int color = 0;
|
|
const char* Brace1 = "[";
|
|
const char* Brace2 = "]";
|
|
if (m_eInputMode == eEditQueue && bSelected)
|
|
{
|
|
color = NCURSES_COLORPAIR_TEXTHIGHL;
|
|
if (!m_bUseColor)
|
|
{
|
|
Brace1 = "<";
|
|
Brace2 = ">";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
color = NCURSES_COLORPAIR_TEXT;
|
|
}
|
|
|
|
char szCompleted[20];
|
|
szCompleted[0] = '\0';
|
|
if (pFileInfo->GetRemainingSize() < pFileInfo->GetSize())
|
|
{
|
|
sprintf(szCompleted, ", %i%%", (int)(100 - pFileInfo->GetRemainingSize() * 100.0 / pFileInfo->GetSize()));
|
|
}
|
|
|
|
char szNZBNiceName[1024];
|
|
if (m_bShowNZBname)
|
|
{
|
|
pFileInfo->GetNiceNZBName(szNZBNiceName, 1023);
|
|
int len = strlen(szNZBNiceName);
|
|
szNZBNiceName[len] = PATH_SEPARATOR;
|
|
szNZBNiceName[len + 1] = '\0';
|
|
}
|
|
else
|
|
{
|
|
szNZBNiceName[0] = '\0';
|
|
}
|
|
|
|
char szBuffer[MAX_SCREEN_WIDTH];
|
|
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i%s %s%s (%.2f MB%s)%s", Brace1, pFileInfo->GetID(), Brace2, szNZBNiceName, pFileInfo->GetFilename(), pFileInfo->GetSize() / 1024.0 / 1024.0, szCompleted, pFileInfo->GetPaused() ? " (paused)" : "");
|
|
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
|
|
|
PlotLine(szBuffer, iRow, 0, color);
|
|
}
|
|
|
|
void NCursesFrontend::FormatFileSize(char * szBuffer, int iBufLen, long long lFileSize)
|
|
{
|
|
if (lFileSize > 1024 * 1024 * 1024)
|
|
{
|
|
snprintf(szBuffer, iBufLen, "%.2f GB", (float)lFileSize / 1024 / 1024 / 1024);
|
|
}
|
|
else if (lFileSize > 1024 * 1024)
|
|
{
|
|
snprintf(szBuffer, iBufLen, "%.2f MB", (float)lFileSize / 1024 / 1024);
|
|
}
|
|
else if (lFileSize > 1024)
|
|
{
|
|
snprintf(szBuffer, iBufLen, "%.2f KB", (float)lFileSize / 1024);
|
|
}
|
|
else
|
|
{
|
|
snprintf(szBuffer, iBufLen, "%i", (int)lFileSize);
|
|
}
|
|
szBuffer[iBufLen - 1] = '\0';
|
|
}
|
|
|
|
void NCursesFrontend::PrintGroupQueue()
|
|
{
|
|
int iLineNr = m_iQueueWinTop;
|
|
|
|
GroupQueue* pGroupQueue = &m_groupQueue;
|
|
if (pGroupQueue->empty())
|
|
{
|
|
char szBuffer[MAX_SCREEN_WIDTH];
|
|
snprintf(szBuffer, sizeof(szBuffer), "%s NZBs for downloading", m_bUseColor ? "" : "*** ");
|
|
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
|
PlotLine(szBuffer, iLineNr++, 0, NCURSES_COLORPAIR_INFOLINE);
|
|
PlotLine("Ready to receive nzb-job", iLineNr++, 0, NCURSES_COLORPAIR_TEXT);
|
|
}
|
|
else
|
|
{
|
|
iLineNr++;
|
|
long long lRemaining = 0;
|
|
long long lPaused = 0;
|
|
int i = 0;
|
|
for (GroupQueue::iterator it = pGroupQueue->begin(); it != pGroupQueue->end(); it++, i++)
|
|
{
|
|
GroupInfo* pGroupInfo = *it;
|
|
|
|
if (i >= m_iQueueScrollOffset && i < m_iQueueScrollOffset + m_iQueueWinHeight -1)
|
|
{
|
|
PrintGroupname(pGroupInfo, iLineNr++, i == m_iSelectedQueueEntry);
|
|
}
|
|
|
|
lRemaining += pGroupInfo->GetRemainingSize();
|
|
lPaused += pGroupInfo->GetPausedSize();
|
|
}
|
|
|
|
char szRemaining[20];
|
|
FormatFileSize(szRemaining, sizeof(szRemaining), lRemaining);
|
|
|
|
char szUnpaused[20];
|
|
FormatFileSize(szUnpaused, sizeof(szUnpaused), lRemaining - lPaused);
|
|
|
|
char szBuffer[MAX_SCREEN_WIDTH];
|
|
snprintf(szBuffer, sizeof(szBuffer), " %sNZBs for downloading - %i NZBs in queue - %s / %s",
|
|
m_bUseColor ? "" : "*** ", pGroupQueue->size(), szRemaining, szUnpaused);
|
|
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
|
PlotLine(szBuffer, m_iQueueWinTop, 0, NCURSES_COLORPAIR_INFOLINE);
|
|
}
|
|
}
|
|
|
|
void NCursesFrontend::PrintGroupname(GroupInfo * pGroupInfo, int iRow, bool bSelected)
|
|
{
|
|
int color = 0;
|
|
const char* Brace1 = "[";
|
|
const char* Brace2 = "]";
|
|
if (m_eInputMode == eEditQueue && bSelected)
|
|
{
|
|
color = NCURSES_COLORPAIR_TEXTHIGHL;
|
|
if (!m_bUseColor)
|
|
{
|
|
Brace1 = "<";
|
|
Brace2 = ">";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
color = NCURSES_COLORPAIR_TEXT;
|
|
}
|
|
|
|
long long lUnpausedRemainingSize = pGroupInfo->GetRemainingSize() - pGroupInfo->GetPausedSize();
|
|
|
|
char szRemaining[20];
|
|
FormatFileSize(szRemaining, sizeof(szRemaining), lUnpausedRemainingSize);
|
|
|
|
char szPaused[20];
|
|
szPaused[0] = '\0';
|
|
if (pGroupInfo->GetPausedSize() > 0)
|
|
{
|
|
char szPausedSize[20];
|
|
FormatFileSize(szPausedSize, sizeof(szPausedSize), pGroupInfo->GetPausedSize());
|
|
sprintf(szPaused, " + %s paused", szPausedSize);
|
|
}
|
|
|
|
char szNZBNiceName[1024];
|
|
FileInfo::MakeNiceNZBName(pGroupInfo->GetNZBFilename(), szNZBNiceName, 1023);
|
|
|
|
char szBuffer[MAX_SCREEN_WIDTH];
|
|
snprintf(szBuffer, MAX_SCREEN_WIDTH, "%s%i%s %s (%i file%s, %s%s)", Brace1, pGroupInfo->GetID(), Brace2, szNZBNiceName,
|
|
pGroupInfo->m_iFileCount, pGroupInfo->m_iFileCount > 1 ? "s" : "", szRemaining, szPaused);
|
|
szBuffer[MAX_SCREEN_WIDTH - 1] = '\0';
|
|
|
|
PlotLine(szBuffer, iRow, 0, color);
|
|
}
|
|
|
|
void NCursesFrontend::PrepareGroupQueue()
|
|
{
|
|
m_groupQueue.clear();
|
|
|
|
DownloadQueue* pDownloadQueue = LockQueue();
|
|
for (DownloadQueue::iterator it = pDownloadQueue->begin(); it != pDownloadQueue->end(); it++)
|
|
{
|
|
FileInfo* pFileInfo = *it;
|
|
GroupInfo* pGroupInfo = NULL;
|
|
for (GroupQueue::iterator itg = m_groupQueue.begin(); itg != m_groupQueue.end(); itg++)
|
|
{
|
|
GroupInfo* pGroupInfo1 = *itg;
|
|
if (!strcmp(pGroupInfo1->GetNZBFilename(), pFileInfo->GetNZBFilename()))
|
|
{
|
|
pGroupInfo = pGroupInfo1;
|
|
break;
|
|
}
|
|
}
|
|
if (!pGroupInfo)
|
|
{
|
|
pGroupInfo = new GroupInfo(pFileInfo->GetID(), pFileInfo->GetNZBFilename());
|
|
m_groupQueue.push_back(pGroupInfo);
|
|
}
|
|
pGroupInfo->m_iFileCount++;
|
|
pGroupInfo->m_lSize += pFileInfo->GetSize();
|
|
pGroupInfo->m_lRemainingSize += pFileInfo->GetRemainingSize();
|
|
if (pFileInfo->GetPaused())
|
|
{
|
|
pGroupInfo->m_lPausedSize += pFileInfo->GetRemainingSize();
|
|
}
|
|
}
|
|
UnlockQueue();
|
|
}
|
|
|
|
void NCursesFrontend::ClearGroupQueue()
|
|
{
|
|
for (GroupQueue::iterator it = m_groupQueue.begin(); it != m_groupQueue.end(); it++)
|
|
{
|
|
delete *it;
|
|
}
|
|
m_groupQueue.clear();
|
|
}
|
|
|
|
bool NCursesFrontend::EditQueue(QueueEditor::EEditAction eAction, int iOffset)
|
|
{
|
|
int ID = 0;
|
|
bool bPause = false;
|
|
|
|
if (m_bGroupFiles)
|
|
{
|
|
if (m_iSelectedQueueEntry >= 0 && m_iSelectedQueueEntry < (int)m_groupQueue.size())
|
|
{
|
|
GroupInfo* pGroupInfo = m_groupQueue[m_iSelectedQueueEntry];
|
|
ID = pGroupInfo->GetID();
|
|
bPause = pGroupInfo->GetRemainingSize() > pGroupInfo->GetPausedSize();
|
|
}
|
|
if (eAction == QueueEditor::eaFilePause)
|
|
{
|
|
eAction = bPause ? QueueEditor::eaFilePause : QueueEditor::eaFileResume;
|
|
}
|
|
|
|
// map file-edit-actions to group-edit-actions
|
|
QueueEditor::EEditAction FileToGroupMap[] = {
|
|
(QueueEditor::EEditAction)0,
|
|
QueueEditor::eaGroupMoveOffset,
|
|
QueueEditor::eaGroupMoveTop,
|
|
QueueEditor::eaGroupMoveBottom,
|
|
QueueEditor::eaGroupPause,
|
|
QueueEditor::eaGroupResume,
|
|
QueueEditor::eaGroupDelete };
|
|
eAction = FileToGroupMap[eAction];
|
|
}
|
|
else
|
|
{
|
|
DownloadQueue* pDownloadQueue = LockQueue();
|
|
if (m_iSelectedQueueEntry >= 0 && m_iSelectedQueueEntry < (int)pDownloadQueue->size())
|
|
{
|
|
FileInfo* pFileInfo = (*pDownloadQueue)[m_iSelectedQueueEntry];
|
|
ID = pFileInfo->GetID();
|
|
bPause = !pFileInfo->GetPaused();
|
|
}
|
|
UnlockQueue();
|
|
if (eAction == QueueEditor::eaFilePause)
|
|
{
|
|
eAction = bPause ? QueueEditor::eaFilePause : QueueEditor::eaFileResume;
|
|
}
|
|
}
|
|
|
|
if (ID != 0)
|
|
{
|
|
return ServerEditQueue(eAction, iOffset, ID);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void NCursesFrontend::SetCurrentQueueEntry(int iEntry)
|
|
{
|
|
int iQueueSize = CalcQueueSize();
|
|
|
|
if (iEntry < 0)
|
|
{
|
|
iEntry = 0;
|
|
}
|
|
else if (iEntry > iQueueSize - 1)
|
|
{
|
|
iEntry = iQueueSize - 1;
|
|
}
|
|
|
|
if (iEntry > m_iQueueScrollOffset + m_iQueueWinClientHeight ||
|
|
iEntry < m_iQueueScrollOffset - m_iQueueWinClientHeight)
|
|
{
|
|
m_iQueueScrollOffset = iEntry - m_iQueueWinClientHeight / 2;
|
|
}
|
|
else if (iEntry < m_iQueueScrollOffset)
|
|
{
|
|
m_iQueueScrollOffset -= m_iQueueWinClientHeight;
|
|
}
|
|
else if (iEntry >= m_iQueueScrollOffset + m_iQueueWinClientHeight)
|
|
{
|
|
m_iQueueScrollOffset += m_iQueueWinClientHeight;
|
|
}
|
|
|
|
if (m_iQueueScrollOffset > iQueueSize - m_iQueueWinClientHeight)
|
|
{
|
|
m_iQueueScrollOffset = iQueueSize - m_iQueueWinClientHeight;
|
|
}
|
|
if (m_iQueueScrollOffset < 0)
|
|
{
|
|
m_iQueueScrollOffset = 0;
|
|
}
|
|
|
|
m_iSelectedQueueEntry = iEntry;
|
|
}
|
|
|
|
void NCursesFrontend::UpdateInput()
|
|
{
|
|
int iKey;
|
|
while ((iKey = ReadConsoleKey()) != READKEY_EMPTY)
|
|
{
|
|
int iQueueSize = CalcQueueSize();
|
|
|
|
// Normal or edit queue mode
|
|
if (m_eInputMode == eNormal || m_eInputMode == eEditQueue)
|
|
{
|
|
switch (iKey)
|
|
{
|
|
case 'q':
|
|
// Key 'q' for quit
|
|
ExitProc();
|
|
break;
|
|
case 'z':
|
|
// show/hide NZBFilename
|
|
m_bShowNZBname = !m_bShowNZBname;
|
|
break;
|
|
case 'w':
|
|
// swicth window sizes
|
|
if (m_QueueWindowPercentage == 0.5)
|
|
{
|
|
m_QueueWindowPercentage = 1;
|
|
}
|
|
else if (m_QueueWindowPercentage == 1 && m_eInputMode != eEditQueue)
|
|
{
|
|
m_QueueWindowPercentage = 0;
|
|
}
|
|
else
|
|
{
|
|
m_QueueWindowPercentage = 0.5;
|
|
}
|
|
CalcWindowSizes();
|
|
SetCurrentQueueEntry(m_iSelectedQueueEntry);
|
|
break;
|
|
case 'g':
|
|
// group/ungroup files
|
|
m_bGroupFiles = !m_bGroupFiles;
|
|
SetCurrentQueueEntry(m_iSelectedQueueEntry);
|
|
NeedUpdateData();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Normal mode
|
|
if (m_eInputMode == eNormal)
|
|
{
|
|
switch (iKey)
|
|
{
|
|
case 'p':
|
|
// Key 'p' for pause
|
|
if (!IsRemoteMode())
|
|
{
|
|
info(m_bPause ? "Unpausing download" : "Pausing download");
|
|
}
|
|
ServerPauseUnpause(!m_bPause);
|
|
break;
|
|
case '\'':
|
|
ServerDumpDebug();
|
|
break;
|
|
case 'e':
|
|
case 10: // return
|
|
case 13: // enter
|
|
if (iQueueSize > 0)
|
|
{
|
|
m_eInputMode = eEditQueue;
|
|
if (m_QueueWindowPercentage == 0)
|
|
{
|
|
m_QueueWindowPercentage = 0.5;
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
case 'r':
|
|
// Download rate
|
|
m_eInputMode = eDownloadRate;
|
|
m_iInputNumberIndex = 0;
|
|
m_iInputValue = 0;
|
|
return;
|
|
case 't':
|
|
// show/hide Timestamps
|
|
m_bShowTimestamp = !m_bShowTimestamp;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Edit Queue mode
|
|
if (m_eInputMode == eEditQueue)
|
|
{
|
|
switch (iKey)
|
|
{
|
|
case 'e':
|
|
case 10: // return
|
|
case 13: // enter
|
|
m_eInputMode = eNormal;
|
|
return;
|
|
case KEY_DOWN:
|
|
if (m_iSelectedQueueEntry < iQueueSize - 1)
|
|
{
|
|
SetCurrentQueueEntry(m_iSelectedQueueEntry + 1);
|
|
}
|
|
break;
|
|
case KEY_UP:
|
|
if (m_iSelectedQueueEntry > 0)
|
|
{
|
|
SetCurrentQueueEntry(m_iSelectedQueueEntry - 1);
|
|
}
|
|
break;
|
|
case KEY_PPAGE:
|
|
if (m_iSelectedQueueEntry > 0)
|
|
{
|
|
if (m_iSelectedQueueEntry == m_iQueueScrollOffset)
|
|
{
|
|
m_iQueueScrollOffset -= m_iQueueWinClientHeight;
|
|
SetCurrentQueueEntry(m_iSelectedQueueEntry - m_iQueueWinClientHeight);
|
|
}
|
|
else
|
|
{
|
|
SetCurrentQueueEntry(m_iQueueScrollOffset);
|
|
}
|
|
}
|
|
break;
|
|
case KEY_NPAGE:
|
|
if (m_iSelectedQueueEntry < iQueueSize - 1)
|
|
{
|
|
if (m_iSelectedQueueEntry == m_iQueueScrollOffset + m_iQueueWinClientHeight - 1)
|
|
{
|
|
m_iQueueScrollOffset += m_iQueueWinClientHeight;
|
|
SetCurrentQueueEntry(m_iSelectedQueueEntry + m_iQueueWinClientHeight);
|
|
}
|
|
else
|
|
{
|
|
SetCurrentQueueEntry(m_iQueueScrollOffset + m_iQueueWinClientHeight - 1);
|
|
}
|
|
}
|
|
break;
|
|
case KEY_HOME:
|
|
SetCurrentQueueEntry(0);
|
|
break;
|
|
case KEY_END:
|
|
SetCurrentQueueEntry(iQueueSize > 0 ? iQueueSize - 1 : 0);
|
|
break;
|
|
case 'p':
|
|
// Key 'p' for pause
|
|
EditQueue(QueueEditor::eaFilePause, 0);
|
|
break;
|
|
case 'd':
|
|
// Delete entry
|
|
if (EditQueue(QueueEditor::eaFileDelete, 0))
|
|
{
|
|
SetCurrentQueueEntry(m_iSelectedQueueEntry);
|
|
}
|
|
break;
|
|
case 'u':
|
|
if (EditQueue(QueueEditor::eaFileMoveOffset, -1))
|
|
{
|
|
SetCurrentQueueEntry(m_iSelectedQueueEntry - 1);
|
|
}
|
|
break;
|
|
case 'n':
|
|
if (EditQueue(QueueEditor::eaFileMoveOffset, +1))
|
|
{
|
|
SetCurrentQueueEntry(m_iSelectedQueueEntry + 1);
|
|
}
|
|
break;
|
|
case 't':
|
|
if (EditQueue(QueueEditor::eaFileMoveTop, 0))
|
|
{
|
|
SetCurrentQueueEntry(0);
|
|
}
|
|
break;
|
|
case 'b':
|
|
if (EditQueue(QueueEditor::eaFileMoveBottom, 0))
|
|
{
|
|
SetCurrentQueueEntry(iQueueSize > 0 ? iQueueSize - 1 : 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Edit download rate input mode
|
|
if (m_eInputMode == eDownloadRate)
|
|
{
|
|
// Numbers
|
|
if (m_iInputNumberIndex < 5 && iKey >= '0' && iKey <= '9')
|
|
{
|
|
m_iInputValue = (m_iInputValue * 10) + (iKey - '0');
|
|
m_iInputNumberIndex++;
|
|
}
|
|
// Enter
|
|
else if (iKey == 10 || iKey == 13)
|
|
{
|
|
ServerSetDownloadRate((float)m_iInputValue);
|
|
m_eInputMode = eNormal;
|
|
return;
|
|
}
|
|
// Escape
|
|
else if (iKey == 27)
|
|
{
|
|
m_eInputMode = eNormal;
|
|
return;
|
|
}
|
|
// Backspace
|
|
else if (m_iInputNumberIndex > 0 && iKey == KEY_BACKSPACE)
|
|
{
|
|
int iRemain = m_iInputValue % 10;
|
|
|
|
m_iInputValue = (m_iInputValue - iRemain) / 10;
|
|
m_iInputNumberIndex--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int NCursesFrontend::ReadConsoleKey()
|
|
{
|
|
#ifdef WIN32
|
|
HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
|
|
DWORD NumberOfEvents;
|
|
BOOL bOK = GetNumberOfConsoleInputEvents(hConsole, &NumberOfEvents);
|
|
if (bOK && NumberOfEvents > 0)
|
|
{
|
|
while (NumberOfEvents--)
|
|
{
|
|
INPUT_RECORD InputRecord;
|
|
DWORD NumberOfEventsRead;
|
|
if (ReadConsoleInput(hConsole, &InputRecord, 1, &NumberOfEventsRead) &&
|
|
NumberOfEventsRead > 0 &&
|
|
InputRecord.EventType == KEY_EVENT &&
|
|
InputRecord.Event.KeyEvent.bKeyDown)
|
|
{
|
|
return tolower(InputRecord.Event.KeyEvent.wVirtualKeyCode);
|
|
}
|
|
}
|
|
}
|
|
return READKEY_EMPTY;
|
|
#else
|
|
return getch();
|
|
#endif
|
|
}
|
|
|
|
#endif
|