Files
fileman/src/mainWindow.cpp
T
2021-07-11 09:59:03 +02:00

463 lines
13 KiB
C++

#include "mainWindow.h"
#include <iostream>
#include <sstream>
#include <climits>
#include "def.h"
#include "sdlutils.h"
#include "fileUtils.h"
#include "dialog.h"
#include "textInput.h"
#include "textViewer.h"
#include "textEditor.h"
#include "imageViewer.h"
// Destructor
MainWindow::~MainWindow(void)
{
}
//------------------------------------------------------------------------------
// Constructor
MainWindow::MainWindow(const std::string &p_title):
IWindow(true, p_title)
{
// List files
if (! m_fileLister.list(m_title))
{
// Path is wrong, fallback to '/'
m_title = "/";
m_fileLister.list(m_title);
}
// Number of items
m_nbItems = m_fileLister.getNbElements();
// Adjust scrollbar
adjustScrollbar();
INHIBIT(std::cout << "Path: " << m_title << " (" << m_nbItems << ") items\n";)
}
//------------------------------------------------------------------------------
// Draw window
void MainWindow::render(const bool p_focus)
{
// Clear screen
SDL_SetRenderDrawColor(g_renderer, COLOR_BODY_BG, 255);
SDL_RenderClear(g_renderer);
// Render title background
SDL_SetRenderDrawColor(g_renderer, COLOR_TITLE_BG, 255);
SDL_Rect rect { 0, 0, SCREEN_WIDTH, LINE_HEIGHT };
SDL_RenderFillRect(g_renderer, &rect);
// Render title
int l_y = LINE_HEIGHT / 2;
SDLUtils::renderTexture(g_iconFloppy, MARGIN_X, l_y, SDLUtils::T_ALIGN_LEFT, SDLUtils::T_ALIGN_MIDDLE);
SDLUtils::renderText(m_title, g_font, MARGIN_X + ICON_SIZE + MARGIN_X, l_y, {COLOR_TEXT_NORMAL}, {COLOR_TITLE_BG}, SDLUtils::T_ALIGN_LEFT, SDLUtils::T_ALIGN_MIDDLE);
// Render cursor
if (p_focus)
SDL_SetRenderDrawColor(g_renderer, COLOR_CURSOR_FOCUS, 255);
else
SDL_SetRenderDrawColor(g_renderer, COLOR_CURSOR_NO_FOCUS, 255);
rect.x = 0;
rect.y = LINE_HEIGHT + (m_cursor - m_camera.y) * LINE_HEIGHT;
rect.w = SCREEN_WIDTH - m_scrollbar.w;
rect.h = LINE_HEIGHT;
SDL_RenderFillRect(g_renderer, &rect);
// Render scrollbar
if (m_scrollbar.h > 0)
SDL_RenderFillRect(g_renderer, &m_scrollbar);
// Render file list
l_y += LINE_HEIGHT;
SDL_Color l_fgColor = {COLOR_TEXT_NORMAL};
SDL_Color l_bgColor = {COLOR_BODY_BG};
int sizeW = 0;
for (int l_i = m_camera.y; l_i < m_camera.y + m_nbVisibleLines && l_i < m_nbItems; ++l_i)
{
// Colors for the line
if (m_fileLister[l_i].m_selected)
l_fgColor = {COLOR_TEXT_SELECTED};
else
l_fgColor = {COLOR_TEXT_NORMAL};
l_bgColor = getBackgroundColor(l_i, p_focus);
// Icon
if (m_fileLister[l_i].m_name == "..")
SDLUtils::renderTexture(g_iconUp, MARGIN_X, l_y, SDLUtils::T_ALIGN_LEFT, SDLUtils::T_ALIGN_MIDDLE);
else if (m_fileLister.isDirectory(l_i))
SDLUtils::renderTexture(g_iconDir, MARGIN_X, l_y, SDLUtils::T_ALIGN_LEFT, SDLUtils::T_ALIGN_MIDDLE);
else if (ImageViewer::extensionIsSupported(m_fileLister[l_i].m_ext))
SDLUtils::renderTexture(g_iconImage, MARGIN_X, l_y, SDLUtils::T_ALIGN_LEFT, SDLUtils::T_ALIGN_MIDDLE);
else
SDLUtils::renderTexture(g_iconFile, MARGIN_X, l_y, SDLUtils::T_ALIGN_LEFT, SDLUtils::T_ALIGN_MIDDLE);
// File size
if (m_fileLister[l_i].m_size == ULLONG_MAX)
sizeW = 0;
else
sizeW = SDLUtils::renderText(FileUtils::formatSize(m_fileLister[l_i].m_size), g_font, SCREEN_WIDTH - m_scrollbar.w - MARGIN_X, l_y, l_fgColor, l_bgColor, SDLUtils::T_ALIGN_RIGHT, SDLUtils::T_ALIGN_MIDDLE);
// File name
SDLUtils::renderText(m_fileLister[l_i].m_name, g_font, MARGIN_X + ICON_SIZE + MARGIN_X, l_y, l_fgColor, l_bgColor, SDLUtils::T_ALIGN_LEFT, SDLUtils::T_ALIGN_MIDDLE, SCREEN_WIDTH - 4*MARGIN_X - ICON_SIZE - m_scrollbar.w - sizeW);
// Next line
l_y += LINE_HEIGHT;
}
}
//------------------------------------------------------------------------------
// Move cursor up / down
void MainWindow::moveCursorUp(const int p_step, bool p_loop)
{
IWindow::moveCursorUp(p_step, p_loop);
adjustCamera();
adjustScrollbarPosition();
}
void MainWindow::moveCursorDown(const int p_step, bool p_loop)
{
IWindow::moveCursorDown(p_step, p_loop);
adjustCamera();
adjustScrollbarPosition();
}
//------------------------------------------------------------------------------
// Key pressed
void MainWindow::keyPressed(const SDL_Event &event)
{
// Button Validate
if (BUTTON_PRESSED_VALIDATE)
{
// Reset timer
resetTimer();
// Open directory or file
if (m_fileLister.isDirectory(m_cursor))
openHighlightedDir();
else
openHighlightedFile();
return;
}
// Button Back
if (BUTTON_PRESSED_BACK)
{
// Reset timer
resetTimer();
// If we're already at '/, do nothing
if (m_title == "/")
return;
// Select and open ".."
m_cursor = 0;
openHighlightedDir();
return;
}
// Button context menu
if (BUTTON_PRESSED_MENU_CONTEXT)
{
// Reset timer
resetTimer();
// Open context menu
openContextMenu();
return;
}
// Button select
if (BUTTON_PRESSED_SELECT)
{
// Reset timer
resetTimer();
// Select / unselect highlighted item
selectHighlightedItem(true);
return;
}
}
//------------------------------------------------------------------------------
// Open highlighted dir
void MainWindow::openHighlightedDir(void)
{
// Build new path
std::string l_newDir("");
std::string l_oldDir("");
if (m_fileLister[m_cursor].m_name == "..")
{
// New path = parent
size_t l_pos = m_title.rfind('/');
l_newDir = m_title.substr(0, l_pos);
if (l_newDir.empty())
l_newDir = "/";
l_oldDir = m_title.substr(l_pos + 1);
}
else
{
// New path
l_newDir = m_title + (m_title == "/" ? "" : "/") + m_fileLister[m_cursor].m_name;
}
// List the new path
if (! m_fileLister.list(l_newDir))
{
// An error occurred, stay at current dir
m_fileLister.list(m_title);
g_hasChanged = true;
return;
}
// New path is OK
m_title = l_newDir;
m_nbItems = m_fileLister.getNbElements();
// If it's a back movement, restore old highlighted dir
if (! l_oldDir.empty())
m_cursor = m_fileLister.searchDir(l_oldDir);
else
m_cursor = 0;
// Adjust camera
adjustCamera();
// Adjust scrollbar
adjustScrollbar();
// New render
g_hasChanged = true;
INHIBIT(std::cout << "Path: " << m_title << " (" << m_nbItems << ") items\n";)
}
//------------------------------------------------------------------------------
// Open highlighted dir
void MainWindow::openHighlightedFile(void)
{
// Case: file is a supported image
if (ImageViewer::extensionIsSupported(m_fileLister[m_cursor].m_ext))
{
ImageViewer imageViewer(m_title, &m_fileLister, m_cursor);
imageViewer.execute();
return;
}
// Dialog 'view as text' / 'edit as text'
int action = -1;
{
Dialog l_dialog("Open:");
l_dialog.addOption("View as text", 0, g_iconFileText);
l_dialog.addOption("Edit as text", 1, g_iconEdit);
l_dialog.addOption("Cancel", 2, g_iconCancel);
action = l_dialog.execute();
}
if (action != 0 && action != 1)
return;
// If the file is > 1M, ask for confirmation
if (m_fileLister[m_cursor].m_size > 1024 * 1024)
{
Dialog l_dialog("Question:");
l_dialog.addLabel("The file is big. Open anyway?");
l_dialog.addOption("Yes", 0, g_iconSelect);
l_dialog.addOption("No", 1, g_iconCancel);
if (l_dialog.execute() != 0)
return;
}
// View file as text
if (action == 0)
{
TextViewer textViewer(m_title + (m_title == "/" ? "" : "/") + m_fileLister[m_cursor].m_name);
textViewer.execute();
}
// Edit file as text
else
{
TextEditor textEditor(m_title + (m_title == "/" ? "" : "/") + m_fileLister[m_cursor].m_name);
textEditor.execute();
}
}
//------------------------------------------------------------------------------
// Select highlighted item
void MainWindow::selectHighlightedItem(const bool p_step)
{
// Cannot select '..'
if (m_fileLister[m_cursor].m_name == "..")
return;
// Select/unselect highlighted item
m_fileLister[m_cursor].m_selected = ! m_fileLister[m_cursor].m_selected;
// Move 1 step if requested
if (p_step)
moveCursorDown(1, false);
g_hasChanged = true;
}
//------------------------------------------------------------------------------
// Open context menu
void MainWindow::openContextMenu(void)
{
// If no file is selected, select current file
auto nbSelected = m_fileLister.getNbSelected();
bool autoUnselect = false;
if (nbSelected == 0)
{
selectHighlightedItem(false);
nbSelected = m_fileLister.getNbSelected();
autoUnselect = true;
}
// Open dialog
int result = -1;
{
std::ostringstream oss;
oss << nbSelected << " selected";
Dialog l_dialog (oss.str());
if (nbSelected > 0)
{
l_dialog.addOption("Copy", 0, g_iconCopy);
l_dialog.addOption("Cut", 1, g_iconCut);
}
if (m_clipboard.size() > 0)
l_dialog.addOption("Paste", 2, g_iconPaste);
if (nbSelected > 0)
l_dialog.addOption("Delete", 3, g_iconTrash);
if (nbSelected == 1)
l_dialog.addOption("Rename", 9, g_iconEdit);
#ifndef FIRMWARE_351ELEC
if (m_fileLister.getNbSelected('d') > 0)
l_dialog.addOption("Size", 4, g_iconDisk);
#endif
l_dialog.addOption("Select all", 5, g_iconSelect);
l_dialog.addOption("Select none", 6, g_iconNone);
l_dialog.addOption("New directory", 7, g_iconNewDir);
l_dialog.addOption("Quit", 8, g_iconQuit);
result = l_dialog.execute();
}
switch(result)
{
// Copy
case 0:
m_fileLister.getSelectList(m_title, m_clipboard);
m_clipboardOperation = 'c';
INHIBIT(std::cout << m_clipboard.size() << " added to clipboard for copy\n";)
break;
// Move
case 1:
m_fileLister.getSelectList(m_title, m_clipboard);
m_clipboardOperation = 'm';
INHIBIT(std::cout << m_clipboard.size() << " added to clipboard for move\n";)
break;
// Paste
case 2:
if (m_clipboardOperation == 'c')
FileUtils::copyFiles(m_clipboard, m_title);
else if (m_clipboardOperation == 'm')
FileUtils::moveFiles(m_clipboard, m_title);
refresh();
break;
// Delete
case 3:
m_fileLister.getSelectList(m_title, m_clipboard);
FileUtils::removeFiles(m_clipboard);
m_clipboard.clear();
refresh();
break;
// Size
case 4:
{
// Display a "please wait" message
Dialog dialogPleaseWait("Info");
dialogPleaseWait.addLabel("Please wait...");
dialogPleaseWait.render(true);
IWindow::renderPresent();
m_fileLister.computeSelectedDirSize(m_title);
g_hasChanged = true;
}
break;
// Select all
case 5:
m_fileLister.setSelectedAll(true);
autoUnselect = false;
g_hasChanged = true;
break;
// Select none
case 6:
m_fileLister.setSelectedAll(false);
g_hasChanged = true;
break;
// Quit
case 8:
m_retVal = 0;
break;
// New directory
case 7:
{
TextInput textInput("New directory", g_iconNewDir);
if (textInput.execute() != -2 && ! textInput.getInputText().empty())
{
FileUtils::makeDirectory(m_title + (m_title == "/" ? "" : "/") + textInput.getInputText());
refresh();
}
}
break;
// Rename
case 9:
{
std::string fileSrc = m_fileLister.getSelectFirst();
TextInput textInput("Rename", g_iconEdit, fileSrc);
if (textInput.execute() != -2 && ! textInput.getInputText().empty())
{
FileUtils::renameFile(m_title + (m_title == "/" ? "" : "/") + fileSrc, m_title + (m_title == "/" ? "" : "/") + textInput.getInputText());
refresh();
}
}
break;
default:
break;
}
// If the file was auto-selected, auto-unselect it
if (autoUnselect)
{
m_fileLister.setSelectedAll(false);
g_hasChanged = true;
}
}
//------------------------------------------------------------------------------
// Refresh current directory
void MainWindow::refresh(void)
{
INHIBIT(std::cout << "MainWindow::refresh\n";)
// List the current path
if (! m_fileLister.list(m_title))
{
// Path is wrong, fallback to default
m_title = START_PATH;
m_fileLister.list(m_title);
}
// Update number of items
m_nbItems = m_fileLister.getNbElements();
// Adjust selected line
if (m_cursor > m_nbItems - 1)
m_cursor = m_nbItems - 1;
// Adjust camera
adjustCamera();
// Adjust scrollbar
adjustScrollbar();
// New render
g_hasChanged = true;
}
//------------------------------------------------------------------------------
// Adjust camera
void MainWindow::adjustCamera(void)
{
if (m_nbItems <= m_nbVisibleLines)
m_camera.y = 0;
else if (m_cursor < m_camera.y)
m_camera.y = m_cursor;
else if (m_cursor > m_camera.y + m_nbVisibleLines - 1)
m_camera.y = m_cursor - m_nbVisibleLines + 1;
}