/** * @author Christian Burger (christian@krikkel.de) */ #include "kNCurses/TilingWindowManager.hpp" #include "kNCurses/Window.hpp" #include "Debug.hpp" #include #include 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::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 originallyVisibleStack(visibleStack); list::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; } }