kNCurses/TilingWindowManager.cpp

170 lines
5.3 KiB
C++

/**
* @author Christian Burger (christian@krikkel.de)
*/
#include "kNCurses/TilingWindowManager.hpp"
#include "kNCurses/Window.hpp"
#include "Debug.hpp"
#include <ncursesw/ncurses.h>
#include <algorithm>
namespace krikkel::NCurses
{
using std::list;
using std::pair;
using std::recursive_mutex;
using std::scoped_lock;
TilingWindowManager::TilingWindowManager(NCursesWindow *rootWindow, recursive_mutex *ncursesMutex)
: Window(*rootWindow), ncursesMutex(ncursesMutex)
{}
void TilingWindowManager::addWindow(Window *window, windowDimension size)
{
WindowStackElement stackElement(window, size);
stack.push_back(stackElement);
visibleStack.push_back(stackElement);
}
std::recursive_mutex *TilingWindowManager::getNCursesMutex()
{
return ncursesMutex;
}
void TilingWindowManager::hideWindow(Window *window)
{
if(window->hidden)
return;
visibleStack.remove_if(
[window](WindowStackElement element)
{
return element.first == window;
});
window->hidden = true;
}
void TilingWindowManager::showWindow(Window *window)
{
if(!window->hidden)
return;
list<WindowStackElement>::iterator currentVisibleWindowElement = visibleStack.begin();
for(WindowStackElement currentWindowElement : stack)
{
if(currentWindowElement.first == window)
{
visibleStack.insert(currentVisibleWindowElement, currentWindowElement);
window->hidden = false;
break;
}
if(currentWindowElement != (*currentVisibleWindowElement))
continue;
++currentVisibleWindowElement;
}
}
void TilingWindowManager::invertWindowsVisibility()
{
list<WindowStackElement> originallyVisibleStack(visibleStack);
list<WindowStackElement>::iterator originallyVisibleStackIterator = originallyVisibleStack.begin();
visibleStack.clear();
for(WindowStackElement currentWindowElement : stack)
if(originallyVisibleStackIterator != originallyVisibleStack.end()
&& currentWindowElement == *originallyVisibleStackIterator)
{
currentWindowElement.first->hidden = true;
++originallyVisibleStackIterator;
continue;
}
else
{
currentWindowElement.first->hidden = false;
visibleStack.push_back(currentWindowElement);
}
}
int TilingWindowManager::resize(int rows, int cols)
{
int result = Window::resize(rows, cols);
updateLayout();
return result;
}
int TilingWindowManager::refresh()
{
scoped_lock lock(*ncursesMutex);
int result = Window::refresh();
for(WindowStackElement stackElement : visibleStack)
// @todo there are return values; compound them?
stackElement.first->refresh();
return result;
}
void TilingWindowManager::updateLayout()
{
scoped_lock lock(*ncursesMutex);
size_t stackSize = visibleStack.size();
if(stackSize == 0)
{
clear();
return;
}
int unitSize = getRelativeUnitSizeForVisibleWindows(getAvailableSpace()) - 1;
windowPosition position = 0;
auto lastButNotLeast = prev(visibleStack.end());
for(auto stackElementIterator = visibleStack.begin()
; stackElementIterator != lastButNotLeast
; ++stackElementIterator)
{
WindowStackElement stackElement = *stackElementIterator;
Window *window = stackElement.first;
if(!window->isHidden())
{
int windowShift;
int windowSize = stackElement.second;
if(windowSize < 0)
windowShift = unitSize * (-windowSize);
else
windowShift = windowSize;
resizeAndMoveWindow(window, windowShift, position);
position += windowShift;
__debug_log("drawing line at " + std::to_string(position));
moveCursor(position++);
windowBorder();
}
}
resizeAndMoveWindow((*lastButNotLeast).first, getAvailableSpace() - position, position);
}
TilingWindowManager::windowDimension TilingWindowManager::getRelativeUnitSizeForVisibleWindows(windowDimension spaceAvailable)
{
uint16_t numberOfRelativeUnits = 0;
windowDimension absoluteSum = 0;
for(WindowStackElement stackElement : visibleStack)
{
windowDimension size = stackElement.second;
if(size < 0)
numberOfRelativeUnits -= size;
else
absoluteSum += size;
}
windowDimension relativeUnitSize = (spaceAvailable - absoluteSum) / numberOfRelativeUnits;
windowDimension remainder = (spaceAvailable - absoluteSum - relativeUnitSize * numberOfRelativeUnits);
if(remainder > 0 && remainder * 2 < numberOfRelativeUnits)
++relativeUnitSize;
return relativeUnitSize;
}
}