Skip to content

Commit 1a6f3f8

Browse files
committedApr 24, 2024
#62; Toggle on-screen help text for controls by pressing H
1 parent abfdd94 commit 1a6f3f8

8 files changed

+160
-45
lines changed
 

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ see all supported options.
127127

128128
## Controls
129129

130+
- H: Toggle on-screen help text for controls
130131
- Space: Toggle play/pause
131132
- Comma `,`: Toggle bidirectional in-buffer loop/pause
132133
- Period `.`: Toggle forward-only in-buffer loop/pause

‎controls.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include "controls.h"
2+
3+
static const std::vector<std::pair<std::string, std::string>> controls{{"H", "Toggle on-screen help text for controls"},
4+
{"Space", "Toggle play/pause"},
5+
{",", "Toggle bidirectional in-buffer loop/pause"},
6+
{".", "Toggle forward-only in-buffer loop/pause"},
7+
{"Escape", "Quit"},
8+
{"Down arrow", "Seek 15 seconds backward"},
9+
{"Left arrow", "Seek 1 second backward"},
10+
{"Page down", "Seek 600 seconds backward"},
11+
{"Up arrow", "Seek 15 seconds forward"},
12+
{"Right arrow", "Seek 1 second forward"},
13+
{"Page up", "Seek 600 seconds forward"},
14+
{"J", "Reduce playback speed"},
15+
{"L", "Increase playback speed"},
16+
{"S", "Swap left and right video"},
17+
{"A", "Move to the previous frame in the buffer"},
18+
{"D", "Move to the next frame in the buffer"},
19+
{"F", "Save both frames as PNG images in the current directory"},
20+
{"P", "Print mouse position and pixel value under cursor to console"},
21+
{"Z", "Magnify area around cursor (result shown in lower left corner)"},
22+
{"C", "Magnify area around cursor (result shown in lower right corner)"},
23+
{"R", "Re-center and reset zoom to 100% (x1)"},
24+
{"1", "Toggle hide/show left video"},
25+
{"2", "Toggle hide/show right video"},
26+
{"3", "Toggle hide/show HUD"},
27+
{"5", "Zoom 50% (x0.5)"},
28+
{"6", "Zoom 100% (x1)"},
29+
{"7", "Zoom 200% (x2)"},
30+
{"8", "Zoom 400% (x4)"},
31+
{"0", "Toggle video/subtraction mode"},
32+
{"+", "Time-shift right video 1 frame forward"},
33+
{"-", "Time-shift right video 1 frame backward"}};
34+
35+
static const std::vector<std::string> instructions{
36+
"Move the mouse horizontally to adjust the movable slider position.",
37+
"Use the mouse wheel to zoom in/out on the pixel under the cursor. Pan the view by moving the mouse while holding down the right button.",
38+
"Left-click the mouse to perform a time seek based on the horizontal position of the mouse cursor relative to the window width (the target position is shown in the lower right corner).",
39+
"Hold the SHIFT key while pressing D to decode and move to the next frame.",
40+
"Hold CTRL while time-shifting with +/- for faster increments/decrements of 10 frames per keystroke. Similarly, hold down the ALT key for even bigger time-shifts of 100 frames."
41+
};
42+
43+
const std::vector<std::pair<std::string, std::string>> get_controls() {
44+
return controls;
45+
}
46+
47+
const std::vector<std::string> get_instructions() {
48+
return instructions;
49+
}

‎controls.h

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
#include <string>
3+
#include <vector>
4+
5+
const std::vector<std::pair<std::string, std::string>> get_controls();
6+
7+
const std::vector<std::string> get_instructions();

‎display.cpp

+63
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <string>
99
#include <thread>
1010
#include "ffmpeg.h"
11+
#include "controls.h"
1112
#include "source_code_pro_regular_ttf.h"
1213
#include "string_utils.h"
1314
extern "C" {
@@ -23,6 +24,8 @@ static const SDL_Color LOOP_OFF_LABEL_COLOR = {0, 0, 0, 0};
2324
static const SDL_Color LOOP_FW_LABEL_COLOR = {80, 127, 255, 0};
2425
static const SDL_Color LOOP_PP_LABEL_COLOR = {191, 95, 60, 0};
2526
static const SDL_Color TEXT_COLOR = {255, 255, 255, 0};
27+
static const SDL_Color HELP_TEXT_PRIMARY_COLOR = {255, 255, 255, 0};
28+
static const SDL_Color HELP_TEXT_ALTERNATE_COLOR = {255, 255, 192, 0};
2629
static const SDL_Color POSITION_COLOR = {255, 255, 192, 0};
2730
static const SDL_Color TARGET_COLOR = {200, 200, 140, 0};
2831
static const SDL_Color ZOOM_COLOR = {255, 165, 0, 0};
@@ -231,6 +234,34 @@ Display::Display(const int display_number,
231234

232235
diff_planes_ = {diff_plane_0, nullptr, nullptr};
233236
diff_pitches_ = {video_width_ * 3 * (use_10_bpc ? sizeof(uint16_t) : sizeof(uint8_t)), 0, 0};
237+
238+
// initialize help texts
239+
bool primary_color = true;
240+
241+
auto add_help_texture = [&](const std::string& text) {
242+
SDL_Surface* surface = TTF_RenderText_Blended_Wrapped(small_font_, text.c_str(), primary_color ? HELP_TEXT_PRIMARY_COLOR : HELP_TEXT_ALTERNATE_COLOR, drawable_width_ - 20);
243+
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer_, surface);
244+
int h;
245+
SDL_QueryTexture(texture, NULL, NULL, NULL, &h);
246+
help_textures_.push_back(texture);
247+
SDL_FreeSurface(surface);
248+
249+
help_total_height_ += h;
250+
primary_color = !primary_color;
251+
};
252+
253+
add_help_texture("Controls:");
254+
add_help_texture(" ");
255+
256+
for (auto& key_description_pair : get_controls()) {
257+
add_help_texture(string_sprintf(" %-12s %s", key_description_pair.first.c_str(), key_description_pair.second.c_str()));
258+
}
259+
260+
add_help_texture(" ");
261+
262+
for (auto& text : get_instructions()) {
263+
add_help_texture(text);
264+
}
234265
}
235266

236267
Display::~Display() {
@@ -242,6 +273,10 @@ Display::~Display() {
242273
SDL_DestroyTexture(message_texture_);
243274
}
244275

276+
for (auto help_texture : help_textures_) {
277+
SDL_DestroyTexture(help_texture);
278+
}
279+
245280
TTF_CloseFont(small_font_);
246281
TTF_CloseFont(big_font_);
247282

@@ -526,6 +561,23 @@ std::string Display::get_and_format_rgb_yuv_pixel(uint8_t* rgb_plane, const size
526561
return "RGB" + format_pixel(rgb) + ", YUV" + format_pixel(yuv);
527562
}
528563

564+
void Display::render_help() {
565+
int y = help_y_offset_; // yOffset
566+
567+
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
568+
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 160);
569+
SDL_Rect rect = {0, 0, drawable_width_, drawable_height_};
570+
SDL_RenderFillRect(renderer_, &rect);
571+
572+
for (size_t i = 0; i < help_textures_.size(); i++) {
573+
int w, h;
574+
SDL_QueryTexture(help_textures_[i], NULL, NULL, &w, &h);
575+
SDL_Rect dst = {10, y, w, h};
576+
SDL_RenderCopy(renderer_, help_textures_[i], NULL, &dst);
577+
y += h + 5;
578+
}
579+
}
580+
529581
void Display::refresh(std::array<uint8_t*, 3> planes_left,
530582
std::array<size_t, 3> pitches_left,
531583
std::array<size_t, 2> original_dims_left,
@@ -942,6 +994,10 @@ void Display::refresh(std::array<uint8_t*, 3> planes_left,
942994
}
943995
}
944996

997+
if (show_help_) {
998+
render_help();
999+
}
1000+
9451001
SDL_RenderPresent(renderer_);
9461002
}
9471003

@@ -1034,6 +1090,10 @@ void Display::input() {
10341090

10351091
update_move_offset(move_offset_ + pan_offset);
10361092
}
1093+
1094+
help_y_offset_ += -event_.motion.yrel * (help_total_height_ * 3 / drawable_height_);
1095+
help_y_offset_ = std::max(help_y_offset_, drawable_height_ - help_total_height_ - int(help_textures_.size()) * 5);
1096+
help_y_offset_ = std::min(help_y_offset_, 0);
10371097
break;
10381098
case SDL_MOUSEBUTTONDOWN:
10391099
if (event_.button.button != SDL_BUTTON_RIGHT) {
@@ -1043,6 +1103,9 @@ void Display::input() {
10431103
break;
10441104
case SDL_KEYDOWN:
10451105
switch (event_.key.keysym.sym) {
1106+
case SDLK_h:
1107+
show_help_ = !show_help_;
1108+
break;
10461109
case SDLK_ESCAPE:
10471110
quit_ = true;
10481111
break;

‎display.h

+7
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class Display {
6868
float video_to_window_height_factor_;
6969
float font_scale_;
7070

71+
bool show_help_{false};
7172
bool quit_{false};
7273
bool play_{true};
7374
Loop buffer_play_loop_mode_{off};
@@ -139,6 +140,10 @@ class Display {
139140
const std::string right_file_stem_;
140141
int saved_image_number_{1};
141142

143+
std::vector<SDL_Texture*> help_textures_;
144+
int help_total_height_;
145+
int help_y_offset_{0};
146+
142147
void print_verbose_info();
143148

144149
void convert_to_packed_10_bpc(std::array<uint8_t*, 3> in_planes, std::array<size_t, 3> in_pitches, std::array<uint32_t*, 3> out_planes, std::array<size_t, 3> out_pitches, const SDL_Rect& roi);
@@ -170,6 +175,8 @@ class Display {
170175
std::string format_pixel(const std::array<int, 3>& rgb);
171176
std::string get_and_format_rgb_yuv_pixel(uint8_t* rgb_plane, const size_t pitch, const int x, const int y);
172177

178+
void render_help();
179+
173180
float compute_zoom_factor(const float zoom_level) const;
174181
Vector2D compute_relative_move_offset(const Vector2D& zoom_point, const float zoom_factor) const;
175182
void update_zoom_factor_and_move_offset(const float zoom_factor);

‎main.cpp

+6-45
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <vector>
77
#include "argagg.h"
88
#include "string_utils.h"
9+
#include "controls.h"
910
#include "video_compare.h"
1011

1112
#ifdef _WIN32
@@ -50,57 +51,17 @@ void free_argv(int argc, char** argv) {
5051
static const std::string REPEAT_FILE_NAME("__");
5152

5253
void print_controls() {
53-
const std::vector<std::pair<std::string, std::string>> controls{{"Space", "Toggle play/pause"},
54-
{",", "Toggle bidirectional in-buffer loop/pause"},
55-
{".", "Toggle forward-only in-buffer loop/pause"},
56-
{"Escape", "Quit"},
57-
{"Down arrow", "Seek 15 seconds backward"},
58-
{"Left arrow", "Seek 1 second backward"},
59-
{"Page down", "Seek 600 seconds backward"},
60-
{"Up arrow", "Seek 15 seconds forward"},
61-
{"Right arrow", "Seek 1 second forward"},
62-
{"Page up", "Seek 600 seconds forward"},
63-
{"J", "Reduce playback speed"},
64-
{"L", "Increase playback speed"},
65-
{"S", "Swap left and right video"},
66-
{"A", "Move to the previous frame in the buffer"},
67-
{"D", "Move to the next frame in the buffer"},
68-
{"F", "Save both frames as PNG images in the current directory"},
69-
{"P", "Print mouse position and pixel value under cursor to console"},
70-
{"Z", "Magnify area around cursor (result shown in lower left corner)"},
71-
{"C", "Magnify area around cursor (result shown in lower right corner)"},
72-
{"R", "Re-center and reset zoom to 100% (x1)"},
73-
{"1", "Toggle hide/show left video"},
74-
{"2", "Toggle hide/show right video"},
75-
{"3", "Toggle hide/show HUD"},
76-
{"5", "Zoom 50% (x0.5)"},
77-
{"6", "Zoom 100% (x1)"},
78-
{"7", "Zoom 200% (x2)"},
79-
{"8", "Zoom 400% (x4)"},
80-
{"0", "Toggle video/subtraction mode"},
81-
{"+", "Time-shift right video 1 frame forward"},
82-
{"-", "Time-shift right video 1 frame backward"}};
83-
8454
std::cout << "Controls:" << std::endl << std::endl;
8555

86-
for (auto& key_description_pair : controls) {
56+
for (auto& key_description_pair : get_controls()) {
8757
std::cout << string_sprintf(" %-12s %s", key_description_pair.first.c_str(), key_description_pair.second.c_str()) << std::endl;
8858
}
8959

90-
std::cout << std::endl << "Move the mouse horizontally to adjust the movable slider position." << std::endl << std::endl;
91-
92-
std::cout << "Use the mouse wheel to zoom in/out on the pixel under the cursor. Pan the view" << std::endl;
93-
std::cout << "by moving the mouse while holding down the right button." << std::endl << std::endl;
94-
95-
std::cout << "Left-click the mouse to perform a time seek based on the horizontal position" << std::endl;
96-
std::cout << "of the mouse cursor relative to the window width (the target position is" << std::endl;
97-
std::cout << "shown in the lower right corner)." << std::endl << std::endl;
60+
for (auto& instruction : get_instructions()) {
61+
std::cout << std::endl;
9862

99-
std::cout << "Hold the SHIFT key while pressing D to decode and move to the next frame." << std::endl << std::endl;
100-
101-
std::cout << "Hold CTRL while time-shifting with +/- for faster increments/decrements" << std::endl;
102-
std::cout << "of 10 frames per keystroke. Similarly, hold down the ALT key for even" << std::endl;
103-
std::cout << "bigger time-shifts of 100 frames." << std::endl;
63+
print_wrapped(instruction, 80);
64+
}
10465
}
10566

10667
void find_matching_video_demuxers(const std::string& search_string) {

‎string_utils.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "string_utils.h"
2+
#include <iostream>
23
#include <algorithm>
34
#include <cmath>
45
#include <numeric>
@@ -225,3 +226,27 @@ std::string stringify_pixel_format(const AVPixelFormat pixel_format, const AVCol
225226

226227
return string_sprintf("%s%s", av_get_pix_fmt_name(pixel_format), range_and_color_space.c_str());
227228
}
229+
230+
void print_wrapped(const std::string& text, const size_t line_length) {
231+
size_t pos = 0;
232+
233+
while (pos < text.length()) {
234+
size_t next_pos = (pos + line_length < text.length()) ? pos + line_length : text.length();
235+
236+
if (next_pos != text.length()) {
237+
size_t space_pos = text.rfind(' ', next_pos);
238+
239+
if (space_pos != std::string::npos && space_pos > pos) {
240+
next_pos = space_pos;
241+
}
242+
}
243+
244+
std::cout << text.substr(pos, next_pos - pos) << std::endl;
245+
246+
pos = text.find_first_not_of(' ', next_pos);
247+
248+
if (pos == std::string::npos) {
249+
break;
250+
}
251+
}
252+
}

‎string_utils.h

+2
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,5 @@ std::string stringify_file_size(const int64_t size, const unsigned precision = 0
4444
std::string stringify_bit_rate(const int64_t bit_rate, const unsigned precision = 0) noexcept;
4545

4646
std::string stringify_pixel_format(const AVPixelFormat pixel_format, const AVColorRange color_range, const AVColorSpace color_space, const AVColorPrimaries color_primaries, const AVColorTransferCharacteristic color_trc) noexcept;
47+
48+
void print_wrapped(const std::string& text, const size_t line_length);

0 commit comments

Comments
 (0)
Please sign in to comment.