mirror of https://github.com/odrling/Aegisub
Add scroll arrows to the karaoke syllable bar when the contents are too wide to fit. Closes #1516.
This commit is contained in:
parent
b020322a3a
commit
55bdbf8d48
|
@ -52,6 +52,7 @@
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "selection_controller.h"
|
#include "selection_controller.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
template<class Container, class Value>
|
template<class Container, class Value>
|
||||||
static inline size_t last_lt_or_eq(Container const& c, Value const& v) {
|
static inline size_t last_lt_or_eq(Container const& c, Value const& v) {
|
||||||
|
@ -70,11 +71,11 @@ AudioKaraoke::AudioKaraoke(wxWindow *parent, agi::Context *c)
|
||||||
, audio_closed(c->audioController->AddAudioCloseListener(&AudioKaraoke::OnAudioClosed, this))
|
, audio_closed(c->audioController->AddAudioCloseListener(&AudioKaraoke::OnAudioClosed, this))
|
||||||
, active_line(0)
|
, active_line(0)
|
||||||
, kara(new AssKaraoke)
|
, kara(new AssKaraoke)
|
||||||
|
, scroll_x(0)
|
||||||
, enabled(false)
|
, enabled(false)
|
||||||
{
|
{
|
||||||
using std::tr1::bind;
|
using std::tr1::bind;
|
||||||
|
|
||||||
|
|
||||||
cancel_button = new wxBitmapButton(this, -1, GETIMAGE(kara_split_cancel_16));
|
cancel_button = new wxBitmapButton(this, -1, GETIMAGE(kara_split_cancel_16));
|
||||||
cancel_button->SetToolTip(_("Discard all uncommitted splits"));
|
cancel_button->SetToolTip(_("Discard all uncommitted splits"));
|
||||||
cancel_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, bind(&AudioKaraoke::CancelSplit, this));
|
cancel_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, bind(&AudioKaraoke::CancelSplit, this));
|
||||||
|
@ -102,6 +103,7 @@ AudioKaraoke::AudioKaraoke(wxWindow *parent, agi::Context *c)
|
||||||
split_area->Bind(wxEVT_MOTION, &AudioKaraoke::OnMouse, this);
|
split_area->Bind(wxEVT_MOTION, &AudioKaraoke::OnMouse, this);
|
||||||
split_area->Bind(wxEVT_LEAVE_WINDOW, &AudioKaraoke::OnMouse, this);
|
split_area->Bind(wxEVT_LEAVE_WINDOW, &AudioKaraoke::OnMouse, this);
|
||||||
split_area->Bind(wxEVT_CONTEXT_MENU, &AudioKaraoke::OnContextMenu, this);
|
split_area->Bind(wxEVT_CONTEXT_MENU, &AudioKaraoke::OnContextMenu, this);
|
||||||
|
scroll_timer.Bind(wxEVT_TIMER, &AudioKaraoke::OnScrollTimer, this);
|
||||||
|
|
||||||
c->selectionController->AddSelectionListener(this);
|
c->selectionController->AddSelectionListener(this);
|
||||||
|
|
||||||
|
@ -141,8 +143,6 @@ void AudioKaraoke::SetEnabled(bool en) {
|
||||||
enabled = en;
|
enabled = en;
|
||||||
|
|
||||||
c->audioBox->ShowKaraokeBar(enabled);
|
c->audioBox->ShowKaraokeBar(enabled);
|
||||||
split_area->SetSize(GetSize().GetWidth(), -1);
|
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
LoadFromLine();
|
LoadFromLine();
|
||||||
c->audioController->SetTimingController(CreateKaraokeTimingController(c, kara.get(), file_changed));
|
c->audioController->SetTimingController(CreateKaraokeTimingController(c, kara.get(), file_changed));
|
||||||
|
@ -166,19 +166,54 @@ void AudioKaraoke::OnPaint(wxPaintEvent &) {
|
||||||
wxMemoryDC bmp_dc(rendered_line);
|
wxMemoryDC bmp_dc(rendered_line);
|
||||||
|
|
||||||
// Draw the text and split lines
|
// Draw the text and split lines
|
||||||
dc.Blit(0, 0, w, h, &bmp_dc, 0, 0);
|
dc.Blit(-scroll_x, 0, rendered_line.GetWidth(), h, &bmp_dc, 0, 0);
|
||||||
|
|
||||||
// Draw the split line under the mouse
|
// Draw the split line under the mouse
|
||||||
dc.SetPen(*wxRED);
|
dc.SetPen(*wxRED);
|
||||||
dc.DrawLine(mouse_pos, 0, mouse_pos, h);
|
dc.DrawLine(mouse_pos, 0, mouse_pos, h);
|
||||||
|
|
||||||
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||||
|
|
||||||
|
int width_past_bmp = w + scroll_x - rendered_line.GetWidth();
|
||||||
|
dc.SetBrush(*wxWHITE_BRUSH);
|
||||||
|
if (width_past_bmp > 0)
|
||||||
|
dc.DrawRectangle(w - width_past_bmp, 0, width_past_bmp, h);
|
||||||
|
|
||||||
|
// Draw scroll arrows if needed
|
||||||
|
if (scroll_x > 0) {
|
||||||
|
dc.DrawRectangle(0, 0, 20, h);
|
||||||
|
|
||||||
|
wxPoint triangle[] = {
|
||||||
|
wxPoint(10, h / 2 - 6),
|
||||||
|
wxPoint(4, h / 2),
|
||||||
|
wxPoint(10, h / 2 + 6)
|
||||||
|
};
|
||||||
|
dc.SetBrush(*wxBLACK_BRUSH);
|
||||||
|
dc.DrawPolygon(3, triangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rendered_line.GetWidth() - scroll_x > w) {
|
||||||
|
dc.SetBrush(*wxWHITE_BRUSH);
|
||||||
|
dc.DrawRectangle(w - 20, 0, 20, h);
|
||||||
|
|
||||||
|
wxPoint triangle[] = {
|
||||||
|
wxPoint(w - 10, h / 2 - 6),
|
||||||
|
wxPoint(w - 4, h / 2),
|
||||||
|
wxPoint(w - 10, h / 2 + 6)
|
||||||
|
};
|
||||||
|
dc.SetBrush(*wxBLACK_BRUSH);
|
||||||
|
dc.DrawPolygon(3, triangle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioKaraoke::RenderText() {
|
void AudioKaraoke::RenderText() {
|
||||||
int w, h;
|
wxSize bmp_size = split_area->GetClientSize();
|
||||||
split_area->GetClientSize(&w, &h);
|
int line_width = spaced_text.size() * char_width + 5;
|
||||||
|
if (line_width > bmp_size.GetWidth())
|
||||||
|
bmp_size.SetWidth(line_width);
|
||||||
|
|
||||||
if (!rendered_line.IsOk() || split_area->GetClientSize() != rendered_line.GetSize()) {
|
if (!rendered_line.IsOk() || bmp_size != rendered_line.GetSize()) {
|
||||||
rendered_line = wxBitmap(w, h);
|
rendered_line = wxBitmap(bmp_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMemoryDC dc(rendered_line);
|
wxMemoryDC dc(rendered_line);
|
||||||
|
@ -186,13 +221,13 @@ void AudioKaraoke::RenderText() {
|
||||||
// Draw background
|
// Draw background
|
||||||
dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)));
|
dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)));
|
||||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||||
dc.DrawRectangle(0, 0, w, h);
|
dc.DrawRectangle(wxPoint(), bmp_size);
|
||||||
|
|
||||||
dc.SetFont(split_font);
|
dc.SetFont(split_font);
|
||||||
dc.SetTextForeground(wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)));
|
dc.SetTextForeground(wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)));
|
||||||
|
|
||||||
// Draw each character in the line
|
// Draw each character in the line
|
||||||
int y = (h - char_height) / 2;
|
int y = (bmp_size.GetHeight() - char_height) / 2;
|
||||||
for (size_t i = 0; i < spaced_text.size(); ++i) {
|
for (size_t i = 0; i < spaced_text.size(); ++i) {
|
||||||
dc.DrawText(spaced_text[i], char_x[i], y);
|
dc.DrawText(spaced_text[i], char_x[i], y);
|
||||||
}
|
}
|
||||||
|
@ -200,7 +235,7 @@ void AudioKaraoke::RenderText() {
|
||||||
// Draw the lines between each syllable
|
// Draw the lines between each syllable
|
||||||
dc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
|
dc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
|
||||||
for (size_t i = 0; i < syl_lines.size(); ++i) {
|
for (size_t i = 0; i < syl_lines.size(); ++i) {
|
||||||
dc.DrawLine(syl_lines[i], 0, syl_lines[i], h);
|
dc.DrawLine(syl_lines[i], 0, syl_lines[i], bmp_size.GetHeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,8 +263,45 @@ void AudioKaraoke::OnMouse(wxMouseEvent &event) {
|
||||||
|
|
||||||
mouse_pos = event.GetX();
|
mouse_pos = event.GetX();
|
||||||
|
|
||||||
if (event.Leaving())
|
if (event.Leaving()) {
|
||||||
mouse_pos = -1;
|
mouse_pos = -1;
|
||||||
|
split_area->Refresh(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scroll_timer.IsRunning() || split_area->HasCapture()) {
|
||||||
|
if (event.LeftUp()) {
|
||||||
|
scroll_timer.Stop();
|
||||||
|
split_area->ReleaseMouse();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the mouse is over a scroll arrow
|
||||||
|
int client_width = split_area->GetClientSize().GetWidth();
|
||||||
|
if (scroll_x > 0 && mouse_pos < 20) {
|
||||||
|
scroll_dir = -1;
|
||||||
|
}
|
||||||
|
else if (scroll_x + client_width < rendered_line.GetWidth() && mouse_pos > client_width - 20) {
|
||||||
|
scroll_dir = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
scroll_dir = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scroll_dir) {
|
||||||
|
mouse_pos = -1;
|
||||||
|
if (event.LeftDown()) {
|
||||||
|
split_area->Refresh(false);
|
||||||
|
scroll_timer.Start(50);
|
||||||
|
split_area->CaptureMouse();
|
||||||
|
wxTimerEvent evt;
|
||||||
|
OnScrollTimer(evt);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shifted_pos = mouse_pos + scroll_x;
|
||||||
|
|
||||||
if (!event.LeftDown()) {
|
if (!event.LeftDown()) {
|
||||||
// Erase the old line and draw the new one
|
// Erase the old line and draw the new one
|
||||||
|
@ -238,14 +310,14 @@ void AudioKaraoke::OnMouse(wxMouseEvent &event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Character to insert the new split point before
|
// Character to insert the new split point before
|
||||||
int split_pos = std::min<int>((mouse_pos - char_width / 2) / char_width, spaced_text.size());
|
int split_pos = std::min<int>((shifted_pos - char_width / 2) / char_width, spaced_text.size());
|
||||||
|
|
||||||
// Syllable this character is in
|
// Syllable this character is in
|
||||||
int syl = last_lt_or_eq(syl_start_points, split_pos);
|
int syl = last_lt_or_eq(syl_start_points, split_pos);
|
||||||
|
|
||||||
// If the click is sufficiently close to a line of a syllable split,
|
// If the click is sufficiently close to a line of a syllable split,
|
||||||
// remove that split rather than adding a new one
|
// remove that split rather than adding a new one
|
||||||
if ((syl > 0 && mouse_pos <= syl_lines[syl - 1] + 2) || (syl < (int)syl_lines.size() && mouse_pos >= syl_lines[syl] - 2)) {
|
if ((syl > 0 && shifted_pos <= syl_lines[syl - 1] + 2) || (syl < (int)syl_lines.size() && shifted_pos >= syl_lines[syl] - 2)) {
|
||||||
kara->RemoveSplit(syl);
|
kara->RemoveSplit(syl);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -258,7 +330,21 @@ void AudioKaraoke::OnMouse(wxMouseEvent &event) {
|
||||||
split_area->Refresh(false);
|
split_area->Refresh(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioKaraoke::OnScrollTimer(wxTimerEvent &) {
|
||||||
|
scroll_x += scroll_dir * char_width * 3;
|
||||||
|
|
||||||
|
int max_scroll = rendered_line.GetWidth() + 20 - split_area->GetClientSize().GetWidth();
|
||||||
|
if (scroll_x < 0 || scroll_x > max_scroll) {
|
||||||
|
scroll_x = mid(0, scroll_x, max_scroll);
|
||||||
|
scroll_timer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
split_area->Refresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
void AudioKaraoke::LoadFromLine() {
|
void AudioKaraoke::LoadFromLine() {
|
||||||
|
scroll_x = 0;
|
||||||
|
scroll_timer.Stop();
|
||||||
kara->SetLine(active_line, true);
|
kara->SetLine(active_line, true);
|
||||||
SetDisplayText();
|
SetDisplayText();
|
||||||
accept_button->Enable(kara->GetText() != active_line->Text);
|
accept_button->Enable(kara->GetText() != active_line->Text);
|
||||||
|
|
|
@ -97,6 +97,10 @@ class AudioKaraoke : public wxWindow, private SelectionListener<AssDialogue> {
|
||||||
/// Left x coordinate of each character in spaced_text in pixels
|
/// Left x coordinate of each character in spaced_text in pixels
|
||||||
std::vector<int> char_x;
|
std::vector<int> char_x;
|
||||||
|
|
||||||
|
int scroll_x;
|
||||||
|
int scroll_dir;
|
||||||
|
wxTimer scroll_timer;
|
||||||
|
|
||||||
int char_height; ///< Maximum character height in pixels
|
int char_height; ///< Maximum character height in pixels
|
||||||
int char_width; ///< Maximum character width in pixels
|
int char_width; ///< Maximum character width in pixels
|
||||||
int mouse_pos; ///< Last x coordinate of the mouse
|
int mouse_pos; ///< Last x coordinate of the mouse
|
||||||
|
@ -142,6 +146,7 @@ class AudioKaraoke : public wxWindow, private SelectionListener<AssDialogue> {
|
||||||
void OnSelectedSetChanged(Selection const&, Selection const&) { }
|
void OnSelectedSetChanged(Selection const&, Selection const&) { }
|
||||||
void OnAudioOpened();
|
void OnAudioOpened();
|
||||||
void OnAudioClosed();
|
void OnAudioClosed();
|
||||||
|
void OnScrollTimer(wxTimerEvent &event);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
|
|
Loading…
Reference in New Issue