mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-11 09:40:26 +00:00
Preparing TransportWindow for focusing capabilities:
1) Added more to ILayout's interface, including focus mode (circular versus terminating), and the ability to focus by index. 2) Added pseudo-focus modes to TransportWindow so it behaves vaguely like a layout, but without the overhead. 3) Removed unused WindowLayout and updated build files. 4) Fixed a bug in MainLayout where focused view wasn't being properly Blur()'d when changing focus to the command bar 5) Fixed some FocusPrev() and FocusNext() logic in LayoutBase
This commit is contained in:
parent
0f3b577838
commit
bec8caf280
@ -47,7 +47,6 @@ set (BOX_SRCS
|
||||
./cursespp/TextInput.cpp
|
||||
./cursespp/TextLabel.cpp
|
||||
./cursespp/Window.cpp
|
||||
./cursespp/WindowLayout.cpp
|
||||
)
|
||||
|
||||
add_executable(musikbox ${BOX_SRCS})
|
||||
|
@ -49,7 +49,6 @@ using namespace musik::core::library::constants;
|
||||
|
||||
#define TRANSPORT_HEIGHT 3
|
||||
|
||||
|
||||
#define SHOULD_REFOCUS(target) \
|
||||
(this->visibleLayout == target) && \
|
||||
(this->shortcuts && !this->shortcuts->IsFocused())
|
||||
@ -69,7 +68,6 @@ LibraryLayout::LibraryLayout(PlaybackService& playback, LibraryPtr library)
|
||||
}
|
||||
|
||||
LibraryLayout::~LibraryLayout() {
|
||||
|
||||
}
|
||||
|
||||
void LibraryLayout::Layout() {
|
||||
@ -103,6 +101,8 @@ void LibraryLayout::Layout() {
|
||||
|
||||
void LibraryLayout::ChangeMainLayout(std::shared_ptr<cursespp::LayoutBase> newLayout) {
|
||||
if (this->visibleLayout != newLayout) {
|
||||
this->transportView->SetFocus(TransportWindow::FocusNone);
|
||||
|
||||
if (this->visibleLayout) {
|
||||
this->RemoveWindow(this->visibleLayout);
|
||||
this->visibleLayout->Hide();
|
||||
@ -113,6 +113,11 @@ void LibraryLayout::ChangeMainLayout(std::shared_ptr<cursespp::LayoutBase> newLa
|
||||
this->visibleLayout->Layout();
|
||||
this->visibleLayout->Show();
|
||||
|
||||
/* ask the visible layout to terminate focusing, not do it
|
||||
in a circular fashion. when we hit the end, we'll focus
|
||||
the transport! see FocusNext() and FocusPrev(). */
|
||||
this->visibleLayout->SetFocusMode(ILayout::FocusModeTerminating);
|
||||
|
||||
if (this->IsVisible()) {
|
||||
this->BringToTop();
|
||||
}
|
||||
@ -201,19 +206,67 @@ void LibraryLayout::OnSearchResultSelected(
|
||||
this->browseLayout->ScrollTo(fieldType, fieldId);
|
||||
}
|
||||
|
||||
IWindowPtr LibraryLayout::FocusTransportNext() {
|
||||
if (this->transportView->FocusNext()) {
|
||||
return this->transportView;
|
||||
}
|
||||
|
||||
this->transportView->SetFocus(TransportWindow::FocusNone);
|
||||
return this->visibleLayout->FocusFirst();
|
||||
}
|
||||
|
||||
IWindowPtr LibraryLayout::FocusTransportPrev() {
|
||||
if (this->transportView->FocusPrev()) {
|
||||
return this->transportView;
|
||||
}
|
||||
|
||||
this->transportView->SetFocus(TransportWindow::FocusNone);
|
||||
return this->visibleLayout->FocusLast();
|
||||
}
|
||||
|
||||
IWindowPtr LibraryLayout::FocusNext() {
|
||||
return this->visibleLayout->FocusNext();
|
||||
if (this->transportView->IsFocused()) {
|
||||
return this->FocusTransportNext();
|
||||
}
|
||||
|
||||
IWindowPtr focus = this->visibleLayout->FocusNext();
|
||||
|
||||
/* no next focus? kick over to the transport */
|
||||
if (!focus) {
|
||||
this->transportView->FocusFirst();
|
||||
focus = this->transportView;
|
||||
}
|
||||
|
||||
return focus;
|
||||
}
|
||||
|
||||
IWindowPtr LibraryLayout::FocusPrev() {
|
||||
return this->visibleLayout->FocusPrev();
|
||||
if (this->transportView->IsFocused()) {
|
||||
return this->FocusTransportPrev();
|
||||
}
|
||||
|
||||
IWindowPtr focus = this->visibleLayout->FocusPrev();
|
||||
|
||||
if (!focus) {
|
||||
this->transportView->FocusLast();
|
||||
focus = this->transportView;
|
||||
}
|
||||
|
||||
return focus;
|
||||
}
|
||||
|
||||
IWindowPtr LibraryLayout::GetFocus() {
|
||||
return this->visibleLayout->GetFocus();
|
||||
return this->transportView->IsFocused()
|
||||
? this->transportView
|
||||
: this->visibleLayout->GetFocus();
|
||||
}
|
||||
|
||||
bool LibraryLayout::SetFocus(cursespp::IWindowPtr window) {
|
||||
if (window == this->transportView) {
|
||||
this->transportView->RestoreFocus();
|
||||
return true;
|
||||
}
|
||||
|
||||
return this->visibleLayout->SetFocus(window);
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,9 @@ namespace musik {
|
||||
void OnLayoutChanged();
|
||||
void UpdateShortcutsWindow();
|
||||
|
||||
cursespp::IWindowPtr FocusTransportNext();
|
||||
cursespp::IWindowPtr FocusTransportPrev();
|
||||
|
||||
PlaybackService& playback;
|
||||
musik::core::audio::ITransport& transport;
|
||||
musik::core::LibraryPtr library;
|
||||
|
@ -108,9 +108,10 @@ void MainLayout::SetMainLayout(std::shared_ptr<cursespp::LayoutBase> layout) {
|
||||
|
||||
this->RemoveWindow(this->layout);
|
||||
this->layout->Hide();
|
||||
this->lastFocus.reset();
|
||||
}
|
||||
|
||||
this->lastFocus.reset();
|
||||
|
||||
if (this->topLevelLayout) {
|
||||
this->topLevelLayout->SetShortcutsWindow(nullptr);
|
||||
}
|
||||
@ -151,6 +152,22 @@ cursespp::IWindowPtr MainLayout::BlurShortcuts() {
|
||||
return this->layout ? this->layout->GetFocus() : IWindowPtr();
|
||||
}
|
||||
|
||||
void MainLayout::FocusShortcuts() {
|
||||
this->shortcuts->Focus();
|
||||
|
||||
if (this->layout) {
|
||||
this->lastFocus = this->layout->GetFocus();
|
||||
|
||||
if (this->lastFocus) {
|
||||
this->lastFocus->Blur();
|
||||
}
|
||||
|
||||
this->layout->SetFocus(IWindowPtr());
|
||||
}
|
||||
|
||||
this->shortcuts->Focus();
|
||||
}
|
||||
|
||||
bool MainLayout::KeyPress(const std::string& key) {
|
||||
if (prefs->GetBool(box::prefs::keys::EscFocusesShortcuts, true)) {
|
||||
if (key == "^[" ||
|
||||
@ -160,21 +177,12 @@ bool MainLayout::KeyPress(const std::string& key) {
|
||||
this->shortcutsFocused = !this->shortcutsFocused;
|
||||
|
||||
if (this->shortcutsFocused) {
|
||||
this->shortcuts->Focus();
|
||||
|
||||
if (this->layout) {
|
||||
this->lastFocus = this->layout->GetFocus();
|
||||
this->layout->SetFocus(IWindowPtr());
|
||||
}
|
||||
this->FocusShortcuts();
|
||||
}
|
||||
else {
|
||||
this->BlurShortcuts();
|
||||
}
|
||||
|
||||
this->shortcutsFocused
|
||||
? this->shortcuts->Focus()
|
||||
: this->shortcuts->Blur();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ namespace musik {
|
||||
private:
|
||||
void Initialize();
|
||||
cursespp::IWindowPtr BlurShortcuts();
|
||||
void FocusShortcuts();
|
||||
|
||||
std::shared_ptr<musik::core::Preferences> prefs;
|
||||
std::shared_ptr<cursespp::ShortcutsWindow> shortcuts;
|
||||
|
@ -52,6 +52,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
|
||||
using namespace musik::core;
|
||||
using namespace musik::core::audio;
|
||||
@ -69,14 +70,9 @@ using namespace cursespp;
|
||||
#define MIN_WIDTH 20
|
||||
#define MIN_HEIGHT 2
|
||||
|
||||
#define DEBOUNCE_REFRESH(x) \
|
||||
#define DEBOUNCE_REFRESH(mode, delay) \
|
||||
this->RemoveMessage(REFRESH_TRANSPORT_READOUT); \
|
||||
this->PostMessage(REFRESH_TRANSPORT_READOUT, 0, 0, x);
|
||||
|
||||
#define DEBOUNCE_REFRESH_AND_SYNC_TIME() \
|
||||
this->lastTime = this->transport.Position(); \
|
||||
DEBOUNCE_REFRESH(0)
|
||||
|
||||
this->PostMessage(REFRESH_TRANSPORT_READOUT, (int64) mode, 0, delay);
|
||||
|
||||
#define ON(w, a) if (a != -1) { wattron(w, a); }
|
||||
#define OFF(w, a) if (a != -1) { wattroff(w, a); }
|
||||
@ -203,9 +199,10 @@ size_t writePlayingFormat(
|
||||
}
|
||||
|
||||
TransportWindow::TransportWindow(musik::box::PlaybackService& playback)
|
||||
: Window(NULL)
|
||||
: Window(nullptr)
|
||||
, playback(playback)
|
||||
, transport(playback.GetTransport())
|
||||
, focus(FocusNone)
|
||||
{
|
||||
this->SetFrameVisible(false);
|
||||
this->playback.TrackChanged.connect(this, &TransportWindow::OnPlaybackServiceTrackChanged);
|
||||
@ -220,43 +217,93 @@ TransportWindow::TransportWindow(musik::box::PlaybackService& playback)
|
||||
TransportWindow::~TransportWindow() {
|
||||
}
|
||||
|
||||
void TransportWindow::SetFocus(FocusTarget target) {
|
||||
if (target != this->focus) {
|
||||
auto last = this->focus;
|
||||
this->focus = target;
|
||||
|
||||
if (this->focus == FocusNone) {
|
||||
this->lastFocus = last;
|
||||
this->Blur();
|
||||
}
|
||||
else {
|
||||
this->Focus();
|
||||
}
|
||||
|
||||
DEBOUNCE_REFRESH(TimeSync, 0);
|
||||
}
|
||||
}
|
||||
|
||||
TransportWindow::FocusTarget TransportWindow::GetFocus() const {
|
||||
return this->focus;
|
||||
}
|
||||
|
||||
void TransportWindow::Show() {
|
||||
Window::Show();
|
||||
this->Update();
|
||||
}
|
||||
|
||||
bool TransportWindow::FocusNext() {
|
||||
this->SetFocus((FocusTarget)(((int) this->focus + 1) % 3));
|
||||
return (this->focus != FocusNone);
|
||||
}
|
||||
|
||||
bool TransportWindow::FocusPrev() {
|
||||
this->SetFocus((FocusTarget)(((int) this->focus - 1) % 3));
|
||||
return (this->focus != FocusNone);
|
||||
}
|
||||
|
||||
void TransportWindow::FocusFirst() {
|
||||
this->SetFocus(FocusVolume);
|
||||
}
|
||||
|
||||
void TransportWindow::FocusLast() {
|
||||
this->SetFocus(FocusTime);
|
||||
}
|
||||
|
||||
void TransportWindow::RestoreFocus() {
|
||||
this->Focus();
|
||||
this->SetFocus(this->lastFocus);
|
||||
}
|
||||
|
||||
void TransportWindow::OnFocusChanged(bool focused) {
|
||||
if (!focused) {
|
||||
this->SetFocus(FocusNone);
|
||||
}
|
||||
}
|
||||
|
||||
void TransportWindow::ProcessMessage(IMessage &message) {
|
||||
int type = message.Type();
|
||||
|
||||
if (type == REFRESH_TRANSPORT_READOUT) {
|
||||
this->Update();
|
||||
DEBOUNCE_REFRESH(REFRESH_INTERVAL_MS)
|
||||
this->Update((TimeMode) message.UserData1());
|
||||
DEBOUNCE_REFRESH(TimeSmooth, REFRESH_INTERVAL_MS)
|
||||
}
|
||||
}
|
||||
|
||||
void TransportWindow::OnPlaybackServiceTrackChanged(size_t index, TrackPtr track) {
|
||||
this->currentTrack = track;
|
||||
this->lastTime = DEFAULT_TIME;
|
||||
DEBOUNCE_REFRESH(0);
|
||||
DEBOUNCE_REFRESH(TimeSync, 0);
|
||||
}
|
||||
|
||||
void TransportWindow::OnPlaybackModeChanged() {
|
||||
DEBOUNCE_REFRESH_AND_SYNC_TIME();
|
||||
DEBOUNCE_REFRESH(TimeSync, 0);
|
||||
}
|
||||
|
||||
void TransportWindow::OnTransportVolumeChanged() {
|
||||
DEBOUNCE_REFRESH_AND_SYNC_TIME();
|
||||
DEBOUNCE_REFRESH(TimeSync, 0);
|
||||
}
|
||||
|
||||
void TransportWindow::OnTransportTimeChanged(double time) {
|
||||
DEBOUNCE_REFRESH_AND_SYNC_TIME();
|
||||
DEBOUNCE_REFRESH(TimeSmooth, 0);
|
||||
}
|
||||
|
||||
void TransportWindow::OnPlaybackShuffled(bool shuffled) {
|
||||
DEBOUNCE_REFRESH_AND_SYNC_TIME();
|
||||
DEBOUNCE_REFRESH(TimeSync, 0);
|
||||
}
|
||||
|
||||
void TransportWindow::Update() {
|
||||
void TransportWindow::Update(TimeMode timeMode) {
|
||||
this->Clear();
|
||||
|
||||
size_t cx = (size_t) this->GetContentWidth();
|
||||
@ -272,6 +319,12 @@ void TransportWindow::Update() {
|
||||
int64 gb = COLOR_PAIR(CURSESPP_TEXT_ACTIVE);
|
||||
int64 disabled = COLOR_PAIR(CURSESPP_TEXT_DISABLED);
|
||||
|
||||
int64 volumeAttrs = (this->focus == FocusVolume)
|
||||
? COLOR_PAIR(CURSESPP_TEXT_FOCUSED) : -1;
|
||||
|
||||
int64 timerAttrs = (this->focus == FocusTime)
|
||||
? COLOR_PAIR(CURSESPP_TEXT_FOCUSED) : -1;
|
||||
|
||||
/* prepare the "shuffle" label */
|
||||
|
||||
std::string shuffleLabel = " shuffle";
|
||||
@ -330,7 +383,9 @@ void TransportWindow::Update() {
|
||||
|
||||
volume += " ";
|
||||
|
||||
ON(c, volumeAttrs);
|
||||
wprintw(c, volume.c_str());
|
||||
OFF(c, volumeAttrs);
|
||||
|
||||
/* repeat mode setup */
|
||||
|
||||
@ -355,35 +410,42 @@ void TransportWindow::Update() {
|
||||
|
||||
/* time slider */
|
||||
|
||||
int64 timerAttrs = 0;
|
||||
int64 currentTimeAttrs = timerAttrs;
|
||||
|
||||
if (paused) { /* blink the track if paused */
|
||||
int64 now = duration_cast<seconds>(
|
||||
system_clock::now().time_since_epoch()).count();
|
||||
|
||||
if (now % 2 == 0) {
|
||||
timerAttrs = COLOR_PAIR(CURSESPP_TEXT_HIDDEN);
|
||||
currentTimeAttrs = COLOR_PAIR(CURSESPP_TEXT_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
transport.Position();
|
||||
|
||||
/* calculating playback time is inexact because it's based on buffers that
|
||||
are sent to the output. here we use a simple smoothing function to hopefully
|
||||
mitigate jumping around. basically: draw the time as one second more than the
|
||||
last time we displayed, unless they are more than few seconds apart. note this
|
||||
only works if REFRESH_INTERVAL_MS is 1000. */
|
||||
double smoothedTime = this->lastTime += 1.0f; /* 1000 millis */
|
||||
double actualTime = transport.Position();
|
||||
int secondsCurrent = (int) round(this->lastTime); /* mode == TimeLast */
|
||||
|
||||
if (paused || stopped || fabs(smoothedTime - actualTime) > TIME_SLOP) {
|
||||
smoothedTime = actualTime;
|
||||
if (timeMode == TimeSmooth) {
|
||||
double smoothedTime = this->lastTime += 1.0f; /* 1000 millis */
|
||||
double actualTime = transport.Position();
|
||||
|
||||
if (paused || stopped || fabs(smoothedTime - actualTime) > TIME_SLOP) {
|
||||
smoothedTime = actualTime;
|
||||
}
|
||||
|
||||
this->lastTime = smoothedTime;
|
||||
/* end time smoothing */
|
||||
|
||||
secondsCurrent = (int) round(smoothedTime);
|
||||
}
|
||||
else if (timeMode == TimeSync) {
|
||||
this->lastTime = transport.Position();
|
||||
secondsCurrent = (int) round(this->lastTime);
|
||||
}
|
||||
|
||||
this->lastTime = smoothedTime;
|
||||
/* end time smoothing */
|
||||
|
||||
int secondsCurrent = (int) round(smoothedTime);
|
||||
int secondsTotal = boost::lexical_cast<int>(duration);
|
||||
|
||||
std::string currentTime = duration::Duration(std::min(secondsCurrent, secondsTotal));
|
||||
@ -409,9 +471,11 @@ void TransportWindow::Update() {
|
||||
timerTrack += (i == thumbOffset) ? "■" : "─";
|
||||
}
|
||||
|
||||
wattron(c, timerAttrs); /* blink if paused */
|
||||
ON(c, currentTimeAttrs); /* blink if paused */
|
||||
wprintw(c, currentTime.c_str());
|
||||
wattroff(c, timerAttrs);
|
||||
OFF(c, currentTimeAttrs);
|
||||
|
||||
ON(c, timerAttrs);
|
||||
|
||||
/* using wprintw() here on large displays (1440p+) will exceed the internal
|
||||
buffer length of 512 characters, so use boost format. */
|
||||
@ -420,11 +484,13 @@ void TransportWindow::Update() {
|
||||
|
||||
waddstr(c, fmt.c_str());
|
||||
|
||||
OFF(c, timerAttrs);
|
||||
|
||||
/* repeat mode draw */
|
||||
wprintw(c, repeatLabel.c_str());
|
||||
wattron(c, repeatAttrs);
|
||||
ON(c, repeatAttrs);
|
||||
wprintw(c, repeatModeLabel.c_str());
|
||||
wattroff(c, repeatAttrs);
|
||||
OFF(c, repeatAttrs);
|
||||
|
||||
this->Repaint();
|
||||
}
|
||||
|
@ -50,16 +50,36 @@ namespace musik {
|
||||
public sigslot::has_slots<>
|
||||
{
|
||||
public:
|
||||
enum FocusTarget {
|
||||
FocusNone = 0,
|
||||
FocusVolume = 1,
|
||||
FocusTime = 2
|
||||
};
|
||||
|
||||
TransportWindow(musik::box::PlaybackService& playback);
|
||||
virtual ~TransportWindow();
|
||||
|
||||
virtual void ProcessMessage(cursespp::IMessage &message);
|
||||
|
||||
virtual void Show();
|
||||
virtual void OnFocusChanged(bool focused);
|
||||
|
||||
void Update();
|
||||
void SetFocus(FocusTarget target);
|
||||
FocusTarget GetFocus() const;
|
||||
bool FocusNext();
|
||||
bool FocusPrev();
|
||||
void FocusFirst();
|
||||
void FocusLast();
|
||||
void RestoreFocus();
|
||||
|
||||
private:
|
||||
enum TimeMode {
|
||||
TimeLast = 0,
|
||||
TimeSmooth = 1,
|
||||
TimeSync = 2
|
||||
};
|
||||
|
||||
void Update(TimeMode mode = TimeSmooth);
|
||||
|
||||
void OnPlaybackServiceTrackChanged(size_t index, musik::core::TrackPtr track);
|
||||
void OnPlaybackModeChanged();
|
||||
void OnTransportVolumeChanged();
|
||||
@ -70,6 +90,7 @@ namespace musik {
|
||||
musik::core::audio::ITransport& transport;
|
||||
musik::box::PlaybackService& playback;
|
||||
musik::core::TrackPtr currentTrack;
|
||||
FocusTarget focus, lastFocus;
|
||||
double lastTime;
|
||||
};
|
||||
}
|
||||
|
@ -42,11 +42,27 @@
|
||||
namespace cursespp {
|
||||
class ILayout : public IWindowGroup, public IKeyHandler, public IOrderable, public IDisplayable {
|
||||
public:
|
||||
enum FocusMode {
|
||||
FocusModeCircular = 0,
|
||||
FocusModeTerminating = 1
|
||||
};
|
||||
|
||||
virtual ~ILayout() { }
|
||||
virtual IWindowPtr FocusNext() = 0;
|
||||
virtual IWindowPtr FocusPrev() = 0;
|
||||
|
||||
virtual IWindowPtr GetFocus() = 0;
|
||||
virtual int GetFocusIndex() = 0;
|
||||
|
||||
virtual bool SetFocus(IWindowPtr window) = 0;
|
||||
virtual void SetFocusIndex(int index) = 0;
|
||||
|
||||
virtual int GetFocusableCount() = 0;
|
||||
virtual IWindowPtr GetFocusableAt(int index) = 0;
|
||||
|
||||
virtual FocusMode GetFocusMode() const = 0;
|
||||
virtual void SetFocusMode(FocusMode mode) = 0;
|
||||
|
||||
virtual void Layout() = 0;
|
||||
};
|
||||
|
||||
|
@ -33,11 +33,15 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdafx.h>
|
||||
#include <climits>
|
||||
#include "LayoutBase.h"
|
||||
#include "Colors.h"
|
||||
|
||||
using namespace cursespp;
|
||||
|
||||
static const int AUTO_FOCUS = -1;
|
||||
static const int NO_FOCUS = -2;
|
||||
|
||||
template <typename T> static int find(std::vector<T>& haystack, T& needle) {
|
||||
int i = 0;
|
||||
typename std::vector<T>::iterator it = haystack.begin();
|
||||
@ -76,8 +80,9 @@ static inline IWindowPtr adjustFocus(IWindowPtr oldFocus, IWindowPtr newFocus) {
|
||||
}
|
||||
|
||||
LayoutBase::LayoutBase(IWindow* parent)
|
||||
: Window(parent) {
|
||||
this->focused = -1;
|
||||
: Window(parent)
|
||||
, focusMode(FocusModeCircular) {
|
||||
this->focused = AUTO_FOCUS;
|
||||
this->SetFrameVisible(false);
|
||||
}
|
||||
|
||||
@ -199,7 +204,7 @@ void LayoutBase::SortFocusables() {
|
||||
this->focused = find(this->focusable, focusedWindow);
|
||||
}
|
||||
|
||||
if (focused == -1 && this->focusable.size() > 0) {
|
||||
if (focused == AUTO_FOCUS && this->focusable.size() > 0) {
|
||||
this->focused = 0;
|
||||
adjustFocus(IWindowPtr(), this->focusable[this->focused]);
|
||||
}
|
||||
@ -226,7 +231,7 @@ IWindowPtr LayoutBase::GetWindowAt(size_t position) {
|
||||
bool LayoutBase::SetFocus(IWindowPtr focus) {
|
||||
if (!focus) {
|
||||
adjustFocus(GetFocus(), focus);
|
||||
this->focused = -1;
|
||||
this->focused = AUTO_FOCUS;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@ -243,8 +248,19 @@ bool LayoutBase::SetFocus(IWindowPtr focus) {
|
||||
|
||||
IWindowPtr LayoutBase::FocusNext() {
|
||||
IWindowPtr oldFocus = GetFocus();
|
||||
if (++this->focused >= (int) this->focusable.size()) {
|
||||
this->focused = 0;
|
||||
if (this->focused == NO_FOCUS && this->focusMode == FocusModeTerminating) {
|
||||
/* nothing. we're already terminated. */
|
||||
}
|
||||
else if (this->focused + 1 >= AUTO_FOCUS) {
|
||||
++this->focused;
|
||||
if (this->focused >= (int) this->focusable.size()) {
|
||||
if (this->focusMode == FocusModeCircular) {
|
||||
this->focused = 0;
|
||||
}
|
||||
else {
|
||||
this->focused = NO_FOCUS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return adjustFocus(oldFocus, GetFocus());
|
||||
@ -252,13 +268,31 @@ IWindowPtr LayoutBase::FocusNext() {
|
||||
|
||||
IWindowPtr LayoutBase::FocusPrev() {
|
||||
IWindowPtr oldFocus = GetFocus();
|
||||
if (--this->focused < 0) {
|
||||
this->focused = (int) this->focusable.size() - 1;
|
||||
--this->focused;
|
||||
if (this->focused < 0) {
|
||||
if (this->focusMode == FocusModeCircular) {
|
||||
this->focused = (int) this->focusable.size() - 1;
|
||||
}
|
||||
else {
|
||||
this->focused = NO_FOCUS;
|
||||
}
|
||||
}
|
||||
|
||||
return adjustFocus(oldFocus, GetFocus());
|
||||
}
|
||||
|
||||
IWindowPtr LayoutBase::FocusFirst() {
|
||||
IWindowPtr oldFocus = GetFocus();
|
||||
this->focused = 0;
|
||||
return adjustFocus(oldFocus, GetFocus());
|
||||
}
|
||||
|
||||
IWindowPtr LayoutBase::FocusLast() {
|
||||
IWindowPtr oldFocus = GetFocus();
|
||||
this->focused = (int) this->focusable.size() - 1;
|
||||
return adjustFocus(oldFocus, GetFocus());
|
||||
}
|
||||
|
||||
IWindowPtr LayoutBase::GetFocus() {
|
||||
if (this->focused >= 0 && this->focusable.size() > 0) {
|
||||
return this->focusable[this->focused];
|
||||
@ -267,6 +301,34 @@ IWindowPtr LayoutBase::GetFocus() {
|
||||
return IWindowPtr();
|
||||
}
|
||||
|
||||
int LayoutBase::GetFocusIndex() {
|
||||
return this->focused;
|
||||
}
|
||||
|
||||
void LayoutBase::SetFocusIndex(int index) {
|
||||
if (this->focused != index) {
|
||||
IWindowPtr oldFocus = GetFocus();
|
||||
this->focused = index;
|
||||
adjustFocus(oldFocus, GetFocus());
|
||||
}
|
||||
}
|
||||
|
||||
int LayoutBase::GetFocusableCount() {
|
||||
return this->focusable.size();
|
||||
}
|
||||
|
||||
IWindowPtr LayoutBase::GetFocusableAt(int index) {
|
||||
return this->focusable.at(index);
|
||||
}
|
||||
|
||||
ILayout::FocusMode LayoutBase::GetFocusMode() const {
|
||||
return this->focusMode;
|
||||
}
|
||||
|
||||
void LayoutBase::SetFocusMode(FocusMode mode) {
|
||||
this->focusMode = mode;
|
||||
}
|
||||
|
||||
bool LayoutBase::KeyPress(const std::string& key) {
|
||||
if (key == "KEY_LEFT" || key == "KEY_UP") {
|
||||
this->FocusPrev();
|
||||
|
@ -40,7 +40,7 @@
|
||||
#include <vector>
|
||||
|
||||
namespace cursespp {
|
||||
class LayoutBase :
|
||||
class LayoutBase :
|
||||
public Window,
|
||||
#if (__clang_major__ == 7 && __clang_minor__ == 3)
|
||||
public std::enable_shared_from_this<LayoutBase>,
|
||||
@ -63,9 +63,22 @@ namespace cursespp {
|
||||
/* ILayout */
|
||||
virtual IWindowPtr FocusNext();
|
||||
virtual IWindowPtr FocusPrev();
|
||||
|
||||
virtual IWindowPtr GetFocus();
|
||||
virtual bool SetFocus(IWindowPtr window);
|
||||
|
||||
virtual int GetFocusIndex();
|
||||
virtual void SetFocusIndex(int index);
|
||||
|
||||
virtual int GetFocusableCount();
|
||||
virtual IWindowPtr GetFocusableAt(int index);
|
||||
|
||||
virtual FocusMode GetFocusMode() const;
|
||||
virtual void SetFocusMode(FocusMode mode);
|
||||
|
||||
virtual IWindowPtr FocusFirst();
|
||||
virtual IWindowPtr FocusLast();
|
||||
|
||||
virtual void Layout() = 0;
|
||||
|
||||
/* IKeyHandler */
|
||||
@ -86,5 +99,6 @@ namespace cursespp {
|
||||
std::vector<IWindowPtr> children;
|
||||
std::vector<IWindowPtr> focusable;
|
||||
int focused;
|
||||
FocusMode focusMode;
|
||||
};
|
||||
}
|
||||
|
@ -1,93 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2016 musikcube team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdafx.h>
|
||||
#include "WindowLayout.h"
|
||||
|
||||
using namespace cursespp;
|
||||
|
||||
WindowLayout::WindowLayout(IWindowPtr window) {
|
||||
this->window = window;
|
||||
}
|
||||
|
||||
WindowLayout::~WindowLayout() {
|
||||
}
|
||||
|
||||
bool WindowLayout::AddWindow(IWindowPtr window) {
|
||||
throw std::runtime_error("AddWindow() not supported in WindowLayout. Use Push()");
|
||||
}
|
||||
|
||||
bool WindowLayout::RemoveWindow(IWindowPtr window) {
|
||||
throw std::runtime_error("RemoveWindow() not supported in WindowLayout. Use Push()");
|
||||
}
|
||||
|
||||
size_t WindowLayout::GetWindowCount() {
|
||||
throw std::runtime_error("GetWindowCount() not supported in WindowLayout.");
|
||||
}
|
||||
|
||||
IWindowPtr WindowLayout::GetWindowAt(size_t position) {
|
||||
throw std::runtime_error("GetWindowAt() not supported in WindowLayout.");
|
||||
}
|
||||
|
||||
void WindowLayout::Show() {
|
||||
this->window->Show();
|
||||
}
|
||||
|
||||
void WindowLayout::Hide() {
|
||||
this->window->Hide();
|
||||
}
|
||||
|
||||
bool WindowLayout::KeyPress(int64 ch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IWindowPtr WindowLayout::FocusNext() {
|
||||
return this->window;
|
||||
}
|
||||
|
||||
IWindowPtr WindowLayout::FocusPrev() {
|
||||
return this->window;
|
||||
}
|
||||
|
||||
IWindowPtr WindowLayout::GetFocus() {
|
||||
return this->window;
|
||||
}
|
||||
|
||||
void WindowLayout::BringToTop() {
|
||||
this->window->BringToTop();
|
||||
}
|
||||
|
||||
void WindowLayout::SendToBottom() {
|
||||
this->window->SendToBottom();
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2016 musikcube team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ILayout.h"
|
||||
|
||||
namespace cursespp {
|
||||
class WindowLayout : public ILayout, public std::enable_shared_from_this<ILayout> {
|
||||
public:
|
||||
WindowLayout(IWindowPtr window);
|
||||
virtual ~WindowLayout();
|
||||
|
||||
/* ILayout */
|
||||
virtual IWindowPtr FocusNext();
|
||||
virtual IWindowPtr FocusPrev();
|
||||
virtual IWindowPtr GetFocus();
|
||||
virtual void Layout() { }
|
||||
|
||||
/* IOrderable */
|
||||
virtual void BringToTop();
|
||||
virtual void SendToBottom();
|
||||
|
||||
/* IDisplayable */
|
||||
virtual void Show();
|
||||
virtual void Hide();
|
||||
|
||||
/* IKeyHandler */
|
||||
virtual bool KeyPress(int64 ch);
|
||||
|
||||
/* IWindowGroup */
|
||||
virtual bool AddWindow(IWindowPtr window);
|
||||
virtual bool RemoveWindow(IWindowPtr window);
|
||||
virtual size_t GetWindowCount();
|
||||
virtual IWindowPtr GetWindowAt(size_t position);
|
||||
|
||||
private:
|
||||
IWindowPtr window;
|
||||
};
|
||||
}
|
@ -159,7 +159,6 @@
|
||||
<ClCompile Include="cursespp\TextInput.cpp" />
|
||||
<ClCompile Include="cursespp\TextLabel.cpp" />
|
||||
<ClCompile Include="cursespp\Window.cpp" />
|
||||
<ClCompile Include="cursespp\WindowLayout.cpp" />
|
||||
<ClCompile Include="cursespp\Message.cpp" />
|
||||
<ClCompile Include="cursespp\MessageQueue.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
@ -229,7 +228,6 @@
|
||||
<ClInclude Include="cursespp\TextInput.h" />
|
||||
<ClInclude Include="cursespp\TextLabel.h" />
|
||||
<ClInclude Include="cursespp\Window.h" />
|
||||
<ClInclude Include="cursespp\WindowLayout.h" />
|
||||
<ClInclude Include="cursespp\Message.h" />
|
||||
<ClInclude Include="cursespp\MessageQueue.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
|
@ -54,9 +54,6 @@
|
||||
<ClCompile Include="app\util\GlobalHotkeys.cpp">
|
||||
<Filter>app\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cursespp\WindowLayout.cpp">
|
||||
<Filter>cursespp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="app\service\PlaybackService.cpp">
|
||||
<Filter>app\service</Filter>
|
||||
</ClCompile>
|
||||
@ -231,9 +228,6 @@
|
||||
<ClInclude Include="cursespp\IOrderable.h">
|
||||
<Filter>cursespp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cursespp\WindowLayout.h">
|
||||
<Filter>cursespp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cursespp\ILayoutStack.h">
|
||||
<Filter>cursespp</Filter>
|
||||
</ClInclude>
|
||||
|
Loading…
x
Reference in New Issue
Block a user