Make Timer a workspace window

This commit is contained in:
Bruno Herbelin
2022-01-06 09:13:50 +01:00
parent 3a300a4ca3
commit b894ea866a
2 changed files with 348 additions and 302 deletions

View File

@@ -90,6 +90,7 @@ using namespace std;
TextEditor editor;
#include "UserInterfaceManager.h"
#define PLOT_CIRCLE_SEGMENTS 64
#define PLOT_ARRAY_SIZE 180
#define LABEL_AUTO_MEDIA_PLAYER ICON_FA_CARET_SQUARE_RIGHT " Dynamic selection"
#define LABEL_STORE_SELECTION " Store selection"
@@ -100,7 +101,6 @@ void ShowAboutGStreamer(bool* p_open);
void ShowAboutOpengl(bool* p_open);
void ShowSandbox(bool* p_open);
void SetMouseCursor(ImVec2 mousepos, View::Cursor c = View::Cursor());
void SetNextWindowVisible(ImVec2 pos, ImVec2 size, float margin = 180.f);
std::string readable_date_time_string(std::string date){
if (date.length()<12)
@@ -266,7 +266,7 @@ void UserInterface::handleKeyboard()
}
else if (ImGui::IsKeyPressed( GLFW_KEY_T )) {
// Timers
Settings::application.widget.timer = !Settings::application.widget.timer;
timercontrol.setVisible(!Settings::application.widget.timer);
}
else if (ImGui::IsKeyPressed( GLFW_KEY_G )) {
// Developer toolbox
@@ -776,6 +776,7 @@ void UserInterface::Render()
// update windows before render
outputcontrol.Update();
sourcecontrol.Update();
timercontrol.Update();
// warning modal dialog
Log::Render(&Settings::application.widget.logs);
@@ -786,9 +787,6 @@ void UserInterface::Render()
// windows
if (Settings::application.widget.toolbox)
toolbox.Render();
if (Settings::application.widget.timer && ( Settings::application.widget.timer_view < 0 ||
Settings::application.widget.timer_view == Settings::application.current_view ))
RenderTimer();
if (Settings::application.widget.shader_editor)
RenderShaderEditor();
if (Settings::application.widget.logs)
@@ -804,6 +802,10 @@ void UserInterface::Render()
if (sourcecontrol.Visible())
sourcecontrol.Render();
// Timer controller
if (timercontrol.Visible())
timercontrol.Render();
// Notes
RenderNotes();
@@ -963,270 +965,6 @@ void UserInterface::handleScreenshot()
}
}
#define MAX_SEGMENTS 64
void UserInterface::RenderTimer()
{
// timer modes : 0 Metronome, 1 Stopwatch
static std::array< std::string, 2 > timer_menu = { "Metronome", "Stopwatch" };
// constraint position
static ImVec2 timer_window_pos = ImVec2(1080, 20);
static ImVec2 timer_window_size_min = ImVec2(11.f * ImGui::GetTextLineHeight(), 11.f * ImGui::GetTextLineHeight());
static ImVec2 timer_window_size = timer_window_size_min * 1.1f;
SetNextWindowVisible(timer_window_pos, timer_window_size);
// constraint square resizing
ImGui::SetNextWindowSizeConstraints(timer_window_size_min, timer_window_size_min * 1.5f, CustomConstraints::Square);
if ( !ImGui::Begin(IMGUI_TITLE_TIMER, &Settings::application.widget.timer, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ))
{
ImGui::End();
return;
}
// current window
ImGuiWindow* window = ImGui::GetCurrentWindow();
timer_window_pos = window->Pos;
timer_window_size = window->Size;
// menu (no title bar)
if (ImGui::BeginMenuBar())
{
// Close and widget menu
if (ImGuiToolkit::IconButton(4,16))
Settings::application.widget.timer = false;
if (ImGui::BeginMenu(IMGUI_TITLE_TIMER))
{
// Enable/Disable Ableton Link
if ( ImGui::MenuItem( ICON_FA_USER_CLOCK " Ableton Link", nullptr, &Settings::application.timer.link_enabled) ) {
Metronome::manager().setEnabled(Settings::application.timer.link_enabled);
}
// output manager menu
ImGui::Separator();
bool pinned = Settings::application.widget.timer_view == Settings::application.current_view;
if ( ImGui::MenuItem( MENU_PINWINDOW, nullptr, &pinned) ){
if (pinned)
Settings::application.widget.timer_view = Settings::application.current_view;
else
Settings::application.widget.timer_view = -1;
}
if ( ImGui::MenuItem( MENU_CLOSE, SHORTCUT_TIMER) )
Settings::application.widget.timer = false;
ImGui::EndMenu();
}
// Selection of the timer mode
if (ImGui::BeginMenu( timer_menu[Settings::application.timer.mode].c_str() ))
{
for (size_t i = 0; i < timer_menu.size(); ++i) {
if (ImGui::MenuItem(timer_menu[i].c_str(), NULL, Settings::application.timer.mode==i))
Settings::application.timer.mode = i;
}
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
// Window draw parameters
ImDrawList* draw_list = ImGui::GetWindowDrawList();
// positions and size of GUI elements
const float margin = window->MenuBarHeight();
const float h = 0.4f * ImGui::GetFrameHeight();
const ImVec2 circle_top_left = window->Pos + ImVec2(margin + h, margin + h);
const ImVec2 circle_top_right = window->Pos + ImVec2(window->Size.y - margin - h, margin + h);
const ImVec2 circle_botom_right = window->Pos + ImVec2(window->Size.y - margin - h, window->Size.x - margin - h);
const ImVec2 circle_center = window->Pos + (window->Size + ImVec2(margin, margin) )/ 2.f;
const float circle_radius = (window->Size.y - 2.f * margin) / 2.f;
// color palette
const ImU32 colorbg = ImGui::GetColorU32(ImGuiCol_FrameBgActive, 0.6f);
const ImU32 colorfg = ImGui::GetColorU32(ImGuiCol_FrameBg, 2.5f);
const ImU32 colorline = ImGui::GetColorU32(ImGuiCol_PlotHistogram);
//
// METRONOME
//
if (Settings::application.timer.mode < 1) {
// Metronome info
double t = Metronome::manager().tempo();
double p = Metronome::manager().phase();
double q = Metronome::manager().quantum();
uint np = (int) Metronome::manager().peers();
// draw background ring
draw_list->AddCircleFilled(circle_center, circle_radius, colorbg, MAX_SEGMENTS);
// draw quarter
static const float resolution = MAX_SEGMENTS / (2.f * M_PI);
static ImVec2 buffer[MAX_SEGMENTS];
float a0 = -M_PI_2 + (floor(p)/floor(q)) * (2.f * M_PI);
float a1 = a0 + (1.f / floor(q)) * (2.f * M_PI);
int n = ImMax(3, (int)((a1 - a0) * resolution));
double da = (a1 - a0) / (n - 1);
int index = 0;
buffer[index++] = circle_center;
for (int i = 0; i < n; ++i) {
double a = a0 + i * da;
buffer[index++] = ImVec2(circle_center.x + circle_radius * cos(a), circle_center.y + circle_radius * sin(a));
}
draw_list->AddConvexPolyFilled(buffer, index, colorfg);
// draw clock hand
a0 = -M_PI_2 + (p/q) * (2.f * M_PI);
draw_list->AddLine(ImVec2(circle_center.x + margin * cos(a0), circle_center.y + margin * sin(a0)),
ImVec2(circle_center.x + circle_radius * cos(a0), circle_center.y + circle_radius * sin(a0)), colorline, 2.f);
// centered indicator 'x / N'
draw_list->AddCircleFilled(circle_center, margin, colorfg, MAX_SEGMENTS);
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
char text_buf[24];
sprintf(text_buf, "%d/%d", (int)(p)+1, (int)(q) );
ImVec2 label_size = ImGui::CalcTextSize(text_buf, NULL);
ImGui::SetCursorScreenPos(circle_center - label_size/2);
ImGui::Text("%s", text_buf);
ImGui::PopFont();
// left slider : quantum
float float_value = ceil(Metronome::manager().quantum());
ImGui::SetCursorScreenPos(timer_window_pos + ImVec2(0.5f * margin, 1.5f * margin));
if ( ImGui::VSliderFloat("##quantum", ImVec2(0.5f * margin, 2.f * circle_radius ), &float_value, 2, 200, "", 2.f) ){
Metronome::manager().setQuantum( ceil(float_value) );
}
if (ImGui::IsItemHovered() || ImGui::IsItemActive() ) {
ImGui::BeginTooltip();
guint64 time_phase = GST_SECOND * (60.0 * q / t) ;
ImGui::Text("%d beats per phase\n= %s at %d BPM", (int) ceil(float_value),
GstToolkit::time_to_string(time_phase, GstToolkit::TIME_STRING_READABLE).c_str(), (int) t);
ImGui::EndTooltip();
}
// Controls NOT operational if peer connected
if (np >0 ) {
// Tempo
ImGui::SetCursorScreenPos(circle_top_right);
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_BOLD);
ImGui::PushStyleColor(ImGuiCol_Text, colorfg);
sprintf(text_buf, "%d", (int) ceil(t) );
ImGui::Text("%s", text_buf);
ImGui::PopStyleColor();
ImGui::PopFont();
if (ImGui::IsItemHovered()){
sprintf(text_buf, "%d BPM\n(set by peer)", (int) ceil(t));
ImGuiToolkit::ToolTip(text_buf);
}
}
// Controls operational only if no peer
else {
// Tempo
ImGui::SetCursorScreenPos(circle_top_right);
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_BOLD);
sprintf(text_buf, "%d", (int) ceil(t) );
ImGui::Text("%s", text_buf);
ImGui::PopFont();
if (ImGui::IsItemClicked())
ImGui::OpenPopup("bpm_popup");
else if (ImGui::IsItemHovered()){
sprintf(text_buf, "%d BPM\n(clic to edit)", (int) ceil(t));
ImGuiToolkit::ToolTip(text_buf);
}
if (ImGui::BeginPopup("bpm_popup", ImGuiWindowFlags_NoMove))
{
ImGui::SetNextItemWidth(80);
ImGui::InputText("BPM", text_buf, 8, ImGuiInputTextFlags_CharsDecimal);
if (ImGui::IsItemDeactivatedAfterEdit()) {
int t = 0;
sscanf(text_buf, "%d", &t);
t = CLAMP(t, 20, 2000);
Metronome::manager().setTempo((double) t);
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
// restart icon
ImGui::SetCursorScreenPos(circle_top_left);
if (ImGuiToolkit::IconButton(9, 13)) {
Metronome::manager().restart();
}
}
// Network indicator, if link enabled
if (Settings::application.timer.link_enabled) {
ImGui::SetCursorScreenPos(circle_botom_right);
ImGuiToolkit::Icon(16, 5, np > 0);
if (ImGui::IsItemHovered()){
sprintf(text_buf, np < 1 ? "Ableton Link\nNo peer" : "Ableton Link\n%d peer%c", np, np < 2 ? ' ' : 's' );
ImGuiToolkit::ToolTip(text_buf);
}
}
}
//
// STOPWATCH
//
else {
// clock times
static guint64 start_time_ = gst_util_get_timestamp ();
static guint64 start_time_hand_ = gst_util_get_timestamp ();
static guint64 duration_hand_ = Settings::application.timer.stopwatch_duration * GST_SECOND;
guint64 time_ = gst_util_get_timestamp ();
// draw ring
draw_list->AddCircle(circle_center, circle_radius, colorbg, MAX_SEGMENTS, 12 );
draw_list->AddCircleFilled(ImVec2(circle_center.x, circle_center.y - circle_radius), 7, colorfg, MAX_SEGMENTS);
// draw indicator time hand
double da = -M_PI_2 + ( (double) (time_-start_time_hand_) / (double) duration_hand_) * (2.f * M_PI);
draw_list->AddCircleFilled(ImVec2(circle_center.x + circle_radius * cos(da), circle_center.y + circle_radius * sin(da)), 7, colorline, MAX_SEGMENTS);
// left slider : countdown
float float_value = (float) Settings::application.timer.stopwatch_duration;
ImGui::SetCursorScreenPos(timer_window_pos + ImVec2(0.5f * margin, 1.5f * margin));
if ( ImGui::VSliderFloat("##duration", ImVec2(0.5f * margin, 2.f * circle_radius ), &float_value, 1, 3600, "", 3.f) ){
Settings::application.timer.stopwatch_duration = (uint64_t) float_value;
duration_hand_ = Settings::application.timer.stopwatch_duration * GST_SECOND;
}
if (ImGui::IsItemHovered() || ImGui::IsItemActive()) {
ImGui::BeginTooltip();
ImGui::Text("%s\ncountdown", GstToolkit::time_to_string(duration_hand_, GstToolkit::TIME_STRING_READABLE).c_str() );
ImGui::EndTooltip();
}
// main text: elapsed time
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
char text_buf[24];
sprintf(text_buf, "%s", GstToolkit::time_to_string(time_-start_time_, GstToolkit::TIME_STRING_FIXED).c_str() );
ImVec2 label_size = ImGui::CalcTextSize(text_buf, NULL);
ImGui::SetCursorScreenPos(circle_center - label_size/2);
ImGui::Text("%s", text_buf);
ImGui::PopFont();
// small text: remaining time
ImGui::PushStyleColor(ImGuiCol_Text, colorfg);
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_BOLD);
sprintf(text_buf, "%s", GstToolkit::time_to_string(duration_hand_-(time_-start_time_hand_)%duration_hand_, GstToolkit::TIME_STRING_READABLE).c_str() );
label_size = ImGui::CalcTextSize(text_buf, NULL);
ImGui::SetCursorScreenPos(circle_center + ImVec2(0.f, circle_radius * -0.7f) - label_size/2);
ImGui::Text("%s", text_buf);
ImGui::PopFont();
ImGui::PopStyleColor();
// reset icon
ImGui::SetCursorScreenPos(circle_top_left);
if (ImGuiToolkit::IconButton(8, 13))
start_time_ = start_time_hand_ = time_; // reset timers
// TODO : pause ?
}
ImGui::End();
}
int UserInterface::RenderViewNavigator(int *shift)
{
// calculate potential target view index :
@@ -1336,7 +1074,7 @@ void UserInterface::showSourceEditor(Source *s)
}
RenderSource *rs = dynamic_cast<RenderSource *>(s);
if (rs != nullptr) {
Settings::application.widget.preview = true;
outputcontrol.setVisible(true);
return;
}
navigator.showPannelSource( Mixer::manager().indexCurrentSource() );
@@ -2166,6 +1904,7 @@ void WorkspaceWindow::toggleClearRestoreWorkspace()
void WorkspaceWindow::restoreWorkspace(bool instantaneous)
{
clear_workspace_enabled = false;
for(auto it = windows_.cbegin(); it != windows_.cend(); ++it) {
ImGuiProperties *impl = (*it)->impl_;
if (impl && impl->ptr)
@@ -2238,7 +1977,7 @@ void WorkspaceWindow::Update()
// if an animation is requested
else if (impl_->animation) {
// increment animation progress by small steps
impl_->progress += SIGN(impl_->target -impl_->progress) * 0.01f;
impl_->progress += SIGN(impl_->target -impl_->progress) * 0.1f;
// finished animation : apply full target position
if (ABS_DIFF(impl_->target, impl_->progress) < 0.05f) {
impl_->animation = false;
@@ -2252,7 +1991,7 @@ void WorkspaceWindow::Update()
}
}
// if clear mode is fullly enabled
else if (clear_workspace_enabled)
else if (clear_workspace_enabled && Visible())
{
// draw another window on top of the WorkspaceWindow, at exact same position and size
ImGuiWindow* window = impl_->ptr;
@@ -2298,6 +2037,12 @@ void SourceController::resetActiveSelection()
void SourceController::setVisible(bool on)
{
if (WorkspaceWindow::clear_workspace_enabled) {
WorkspaceWindow::restoreWorkspace(on);
// do not change status: the restore workspace above showed the window
if (!on) return;
}
if (on && Settings::application.widget.media_player_view != Settings::application.current_view)
Settings::application.widget.media_player_view = -1;
@@ -3702,6 +3447,12 @@ OutputPreview::OutputPreview() : WorkspaceWindow("OutputPreview"), video_recorde
void OutputPreview::setVisible(bool on)
{
if (WorkspaceWindow::clear_workspace_enabled) {
WorkspaceWindow::restoreWorkspace(on);
// do not change status: the restore workspace above showed the window
if (!on) return;
}
if (on && Settings::application.widget.preview_view != Settings::application.current_view)
Settings::application.widget.preview_view = -1;
@@ -3781,8 +3532,6 @@ void OutputPreview::Render()
FrameBuffer *output = Mixer::manager().session()->frame();
if (output)
{
ImGui::SetNextWindowPos(ImVec2(1180, 20), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(400, 260), ImGuiCond_FirstUseEver);
// constraint position
static ImVec2 preview_window_pos = ImVec2(1180, 20);
@@ -3792,10 +3541,11 @@ void OutputPreview::Render()
// constraint aspect ratio resizing
float ar = output->aspectRatio();
ImGui::SetNextWindowSizeConstraints(ImVec2(300, 200), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, &ar);
ImGui::SetNextWindowPos(ImVec2(1180, 20), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(400, 260), ImGuiCond_FirstUseEver);
if ( !ImGui::Begin(name_, &Settings::application.widget.preview,
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar |
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ) )
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ) )
{
ImGui::End();
return;
@@ -4105,6 +3855,289 @@ void OutputPreview::Render()
#endif
}
///
/// TIMER & METRONOME
///
TimerMetronome::TimerMetronome() : WorkspaceWindow("Timer")
{
// timer modes : 0 Metronome, 1 Stopwatch
timer_menu = { "Metronome", "Stopwatch" };
// clock times
start_time_ = gst_util_get_timestamp ();
start_time_hand_ = gst_util_get_timestamp ();
duration_hand_ = Settings::application.timer.stopwatch_duration * GST_SECOND;
}
void TimerMetronome::setVisible(bool on)
{
if (WorkspaceWindow::clear_workspace_enabled) {
WorkspaceWindow::restoreWorkspace(on);
// do not change status: the restore workspace above showed the window
if (!on) return;
}
if (on && Settings::application.widget.timer_view != Settings::application.current_view)
Settings::application.widget.timer_view = -1;
Settings::application.widget.timer = on;
}
bool TimerMetronome::Visible() const
{
return ( Settings::application.widget.timer
&& (Settings::application.widget.timer_view < 0 || Settings::application.widget.timer_view == Settings::application.current_view )
);
}
void TimerMetronome::Render()
{
// constraint square resizing
static ImVec2 timer_window_size_min = ImVec2(11.f * ImGui::GetTextLineHeight(), 11.f * ImGui::GetTextLineHeight());
ImGui::SetNextWindowSizeConstraints(timer_window_size_min, timer_window_size_min * 1.5f, CustomConstraints::Square);
ImGui::SetNextWindowPos(ImVec2(600, 20), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(timer_window_size_min, ImGuiCond_FirstUseEver);
if ( !ImGui::Begin(name_, &Settings::application.widget.timer,
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse ))
{
ImGui::End();
return;
}
// menu (no title bar)
if (ImGui::BeginMenuBar())
{
// Close and widget menu
if (ImGuiToolkit::IconButton(4,16))
Settings::application.widget.timer = false;
if (ImGui::BeginMenu(IMGUI_TITLE_TIMER))
{
// Enable/Disable Ableton Link
if ( ImGui::MenuItem( ICON_FA_USER_CLOCK " Ableton Link", nullptr, &Settings::application.timer.link_enabled) ) {
Metronome::manager().setEnabled(Settings::application.timer.link_enabled);
}
// output manager menu
ImGui::Separator();
bool pinned = Settings::application.widget.timer_view == Settings::application.current_view;
if ( ImGui::MenuItem( MENU_PINWINDOW, nullptr, &pinned) ){
if (pinned)
Settings::application.widget.timer_view = Settings::application.current_view;
else
Settings::application.widget.timer_view = -1;
}
if ( ImGui::MenuItem( MENU_CLOSE, SHORTCUT_TIMER) )
Settings::application.widget.timer = false;
ImGui::EndMenu();
}
// Selection of the timer mode
if (ImGui::BeginMenu( timer_menu[Settings::application.timer.mode].c_str() ))
{
for (size_t i = 0; i < timer_menu.size(); ++i) {
if (ImGui::MenuItem(timer_menu[i].c_str(), NULL, Settings::application.timer.mode==i))
Settings::application.timer.mode = i;
}
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
// current windowdraw parameters
ImGuiWindow* window = ImGui::GetCurrentWindow();
ImDrawList* draw_list = window->DrawList;
// positions and size of GUI elements
const float margin = window->MenuBarHeight();
const float h = 0.4f * ImGui::GetFrameHeight();
const ImVec2 circle_top_left = window->Pos + ImVec2(margin + h, margin + h);
const ImVec2 circle_top_right = window->Pos + ImVec2(window->Size.y - margin - h, margin + h);
const ImVec2 circle_botom_right = window->Pos + ImVec2(window->Size.y - margin - h, window->Size.x - margin - h);
const ImVec2 circle_center = window->Pos + (window->Size + ImVec2(margin, margin) )/ 2.f;
const float circle_radius = (window->Size.y - 2.f * margin) / 2.f;
// color palette
static ImU32 colorbg = ImGui::GetColorU32(ImGuiCol_FrameBgActive, 0.6f);
static ImU32 colorfg = ImGui::GetColorU32(ImGuiCol_FrameBg, 2.5f);
static ImU32 colorline = ImGui::GetColorU32(ImGuiCol_PlotHistogram);
//
// METRONOME
//
if (Settings::application.timer.mode < 1) {
// Metronome info
double t = Metronome::manager().tempo();
double p = Metronome::manager().phase();
double q = Metronome::manager().quantum();
uint np = (int) Metronome::manager().peers();
// draw background ring
draw_list->AddCircleFilled(circle_center, circle_radius, colorbg, PLOT_CIRCLE_SEGMENTS);
// draw quarter
static const float resolution = PLOT_CIRCLE_SEGMENTS / (2.f * M_PI);
static ImVec2 buffer[PLOT_CIRCLE_SEGMENTS];
float a0 = -M_PI_2 + (floor(p)/floor(q)) * (2.f * M_PI);
float a1 = a0 + (1.f / floor(q)) * (2.f * M_PI);
int n = ImMax(3, (int)((a1 - a0) * resolution));
double da = (a1 - a0) / (n - 1);
int index = 0;
buffer[index++] = circle_center;
for (int i = 0; i < n; ++i) {
double a = a0 + i * da;
buffer[index++] = ImVec2(circle_center.x + circle_radius * cos(a), circle_center.y + circle_radius * sin(a));
}
draw_list->AddConvexPolyFilled(buffer, index, colorfg);
// draw clock hand
a0 = -M_PI_2 + (p/q) * (2.f * M_PI);
draw_list->AddLine(ImVec2(circle_center.x + margin * cos(a0), circle_center.y + margin * sin(a0)),
ImVec2(circle_center.x + circle_radius * cos(a0), circle_center.y + circle_radius * sin(a0)), colorline, 2.f);
// centered indicator 'x / N'
draw_list->AddCircleFilled(circle_center, margin, colorfg, PLOT_CIRCLE_SEGMENTS);
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_MONO);
char text_buf[24];
sprintf(text_buf, "%d/%d", (int)(p)+1, (int)(q) );
ImVec2 label_size = ImGui::CalcTextSize(text_buf, NULL);
ImGui::SetCursorScreenPos(circle_center - label_size/2);
ImGui::Text("%s", text_buf);
ImGui::PopFont();
// left slider : quantum
float float_value = ceil(Metronome::manager().quantum());
ImGui::SetCursorPos(ImVec2(0.5f * margin, 1.5f * margin));
if ( ImGui::VSliderFloat("##quantum", ImVec2(0.5f * margin, 2.f * circle_radius ), &float_value, 2, 200, "", 2.f) ){
Metronome::manager().setQuantum( ceil(float_value) );
}
if (ImGui::IsItemHovered() || ImGui::IsItemActive() ) {
ImGui::BeginTooltip();
guint64 time_phase = GST_SECOND * (60.0 * q / t) ;
ImGui::Text("%d beats per phase\n= %s at %d BPM", (int) ceil(float_value),
GstToolkit::time_to_string(time_phase, GstToolkit::TIME_STRING_READABLE).c_str(), (int) t);
ImGui::EndTooltip();
}
// Controls NOT operational if peer connected
if (np >0 ) {
// Tempo
ImGui::SetCursorScreenPos(circle_top_right);
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_BOLD);
ImGui::PushStyleColor(ImGuiCol_Text, colorfg);
sprintf(text_buf, "%d", (int) ceil(t) );
ImGui::Text("%s", text_buf);
ImGui::PopStyleColor();
ImGui::PopFont();
if (ImGui::IsItemHovered()){
sprintf(text_buf, "%d BPM\n(set by peer)", (int) ceil(t));
ImGuiToolkit::ToolTip(text_buf);
}
}
// Controls operational only if no peer
else {
// Tempo
ImGui::SetCursorScreenPos(circle_top_right);
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_BOLD);
sprintf(text_buf, "%d", (int) ceil(t) );
ImGui::Text("%s", text_buf);
ImGui::PopFont();
if (ImGui::IsItemClicked())
ImGui::OpenPopup("bpm_popup");
else if (ImGui::IsItemHovered()){
sprintf(text_buf, "%d BPM\n(clic to edit)", (int) ceil(t));
ImGuiToolkit::ToolTip(text_buf);
}
if (ImGui::BeginPopup("bpm_popup", ImGuiWindowFlags_NoMove))
{
ImGui::SetNextItemWidth(80);
ImGui::InputText("BPM", text_buf, 8, ImGuiInputTextFlags_CharsDecimal);
if (ImGui::IsItemDeactivatedAfterEdit()) {
int t = 0;
sscanf(text_buf, "%d", &t);
t = CLAMP(t, 20, 2000);
Metronome::manager().setTempo((double) t);
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
// restart icon
ImGui::SetCursorScreenPos(circle_top_left);
if (ImGuiToolkit::IconButton(9, 13)) {
Metronome::manager().restart();
}
}
// Network indicator, if link enabled
if (Settings::application.timer.link_enabled) {
ImGui::SetCursorScreenPos(circle_botom_right);
ImGuiToolkit::Icon(16, 5, np > 0);
if (ImGui::IsItemHovered()){
sprintf(text_buf, np < 1 ? "Ableton Link\nNo peer" : "Ableton Link\n%d peer%c", np, np < 2 ? ' ' : 's' );
ImGuiToolkit::ToolTip(text_buf);
}
}
}
//
// STOPWATCH
//
else {
guint64 time_ = gst_util_get_timestamp ();
// draw ring
draw_list->AddCircle(circle_center, circle_radius, colorbg, PLOT_CIRCLE_SEGMENTS, 12 );
draw_list->AddCircleFilled(ImVec2(circle_center.x, circle_center.y - circle_radius), 7, colorfg, PLOT_CIRCLE_SEGMENTS);
// draw indicator time hand
double da = -M_PI_2 + ( (double) (time_-start_time_hand_) / (double) duration_hand_) * (2.f * M_PI);
draw_list->AddCircleFilled(ImVec2(circle_center.x + circle_radius * cos(da), circle_center.y + circle_radius * sin(da)), 7, colorline, PLOT_CIRCLE_SEGMENTS);
// left slider : countdown
float float_value = (float) Settings::application.timer.stopwatch_duration;
ImGui::SetCursorPos(ImVec2(0.5f * margin, 1.5f * margin));
if ( ImGui::VSliderFloat("##duration", ImVec2(0.5f * margin, 2.f * circle_radius ), &float_value, 1, 3600, "", 3.f) ){
Settings::application.timer.stopwatch_duration = (uint64_t) float_value;
duration_hand_ = Settings::application.timer.stopwatch_duration * GST_SECOND;
}
if (ImGui::IsItemHovered() || ImGui::IsItemActive()) {
ImGui::BeginTooltip();
ImGui::Text("%s\ncountdown", GstToolkit::time_to_string(duration_hand_, GstToolkit::TIME_STRING_READABLE).c_str() );
ImGui::EndTooltip();
}
// main text: elapsed time
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
char text_buf[24];
sprintf(text_buf, "%s", GstToolkit::time_to_string(time_-start_time_, GstToolkit::TIME_STRING_FIXED).c_str() );
ImVec2 label_size = ImGui::CalcTextSize(text_buf, NULL);
ImGui::SetCursorScreenPos(circle_center - label_size/2);
ImGui::Text("%s", text_buf);
ImGui::PopFont();
// small text: remaining time
ImGui::PushStyleColor(ImGuiCol_Text, colorfg);
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_BOLD);
sprintf(text_buf, "%s", GstToolkit::time_to_string(duration_hand_-(time_-start_time_hand_)%duration_hand_, GstToolkit::TIME_STRING_READABLE).c_str() );
label_size = ImGui::CalcTextSize(text_buf, NULL);
ImGui::SetCursorScreenPos(circle_center + ImVec2(0.f, circle_radius * -0.7f) - label_size/2);
ImGui::Text("%s", text_buf);
ImGui::PopFont();
ImGui::PopStyleColor();
// reset icon
ImGui::SetCursorScreenPos(circle_top_left);
if (ImGuiToolkit::IconButton(8, 13))
start_time_ = start_time_hand_ = time_; // reset timers
// TODO : pause ?
}
ImGui::End();
}
///
/// NAVIGATOR
@@ -5607,32 +5640,20 @@ void Navigator::RenderMainPannelVimix()
tooltip_ = { TOOLTIP_NOTE, SHORTCUT_NOTE};
ImGui::SameLine(0, ImGui::GetTextLineHeight());
if ( ImGuiToolkit::IconButton( ICON_FA_PLAY_CIRCLE ) ) {
if (Settings::application.widget.media_player && Settings::application.widget.media_player_view > -1 && Settings::application.widget.media_player_view != Settings::application.current_view)
Settings::application.widget.media_player_view = Settings::application.current_view;
else
Settings::application.widget.media_player = !Settings::application.widget.media_player;
}
if ( ImGuiToolkit::IconButton( ICON_FA_PLAY_CIRCLE ) )
UserInterface::manager().sourcecontrol.setVisible(!Settings::application.widget.media_player);
if (ImGui::IsItemHovered())
tooltip_ = { TOOLTIP_PLAYER, SHORTCUT_PLAYER};
ImGui::SameLine(0, ImGui::GetTextLineHeight());
if ( ImGuiToolkit::IconButton( ICON_FA_DESKTOP ) ) {
if (Settings::application.widget.preview && Settings::application.widget.preview_view > -1 && Settings::application.widget.preview_view != Settings::application.current_view)
Settings::application.widget.preview_view = Settings::application.current_view;
else
Settings::application.widget.preview = !Settings::application.widget.preview;
}
if ( ImGuiToolkit::IconButton( ICON_FA_DESKTOP ) )
UserInterface::manager().outputcontrol.setVisible(!Settings::application.widget.preview);
if (ImGui::IsItemHovered())
tooltip_ = { TOOLTIP_OUTPUT, SHORTCUT_OUTPUT};
ImGui::SameLine(0, ImGui::GetTextLineHeight());
if ( ImGuiToolkit::IconButton( ICON_FA_CLOCK ) ) {
if (Settings::application.widget.timer && Settings::application.widget.timer_view > -1 && Settings::application.widget.timer_view != Settings::application.current_view)
Settings::application.widget.timer_view = Settings::application.current_view;
else
Settings::application.widget.timer = !Settings::application.widget.timer;
}
if ( ImGuiToolkit::IconButton( ICON_FA_CLOCK ) )
UserInterface::manager().timercontrol.setVisible(!Settings::application.widget.timer);
if (ImGui::IsItemHovered())
tooltip_ = { TOOLTIP_TIMER, SHORTCUT_TIMER};
@@ -6292,8 +6313,8 @@ void SetMouseCursor(ImVec2 mousepos, View::Cursor c)
}
}
void SetNextWindowVisible(ImVec2 pos, ImVec2 size, float margin)
{
//void SetNextWindowVisible(ImVec2 pos, ImVec2 size, float margin)
//{
// bool need_update = false;
// ImVec2 pos_target = pos;
// const ImGuiIO& io = ImGui::GetIO();
@@ -6316,5 +6337,5 @@ void SetNextWindowVisible(ImVec2 pos, ImVec2 size, float margin)
// }
// if (need_update)
// ImGui::SetNextWindowPos(pos_target, ImGuiCond_Always);
}
//}