aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md8
-rw-r--r--include/ImageViewer.hpp4
-rw-r--r--include/QuickMedia.hpp5
-rw-r--r--src/Body.cpp9
-rw-r--r--src/ImageViewer.cpp30
-rw-r--r--src/QuickMedia.cpp100
6 files changed, 114 insertions, 42 deletions
diff --git a/README.md b/README.md
index 859a192..2d88ade 100644
--- a/README.md
+++ b/README.md
@@ -82,18 +82,22 @@ Type text and then wait and QuickMedia will automatically search.\
### Local anime search page controls
`Ctrl+R`: Mark the anime as watched/unwatched.
### Manga page view controls
-`Arrow up`/`Ctrl+K`: Go to the next page (or chapter if the current page is the last one).\
-`Arrow down`/`Ctrl+J`: Go to the previous page (or chapter if the current page is the first one).\
+`Arrow up`/`Ctrl+K`: Go to the previous page (or chapter if the current page is the last one).\
+`Arrow down`/`Ctrl+J`: Go to the next page (or chapter if the current page is the first one).\
`Page up`: Go back 10 pages.\
`Page down`: Go forward 10 pages.\
`Home`: Go to the first page.\
`End`: Go to the last page.\
+`Ctrl+Arrow up`/`Ctrl+Alt+K`: Go to the previous chapter.\
+`Ctrl+Arrow down`/`Ctrl+Alt+J`: Go to the next chapter.\
`F`: Toggle between scaling the image to the window size or only down scaling if the image is too large.\
`I`: Switch to scroll view.
### Manga scroll view controls
`Arrow up`/`Ctrl+K`: Move up.\
`Arrow down`/`Ctrl+J`: Move down.\
`Mouse scroll`/`Middle mouse click+Move mouse`: Smoothly scroll.\
+`Ctrl+Arrow up`/`Ctrl+Alt+K`: Go to the previous chapter.\
+`Ctrl+Arrow down`/`Ctrl+Alt+J`: Go to the next chapter.\
`F`: Toggle between scaling the image to the window size or only down scaling if the image is too large.\
`I`: Switch to page view.
### Manga chapters controls
diff --git a/include/ImageViewer.hpp b/include/ImageViewer.hpp
index c1fb6ad..cb63229 100644
--- a/include/ImageViewer.hpp
+++ b/include/ImageViewer.hpp
@@ -41,7 +41,9 @@ namespace QuickMedia {
enum class ImageViewerAction {
NONE,
RETURN,
- SWITCH_TO_SINGLE_IMAGE_MODE
+ SWITCH_TO_SINGLE_IMAGE_MODE,
+ PREVIOUS_CHAPTER,
+ NEXT_CHAPTER
};
class ImageViewer {
diff --git a/include/QuickMedia.hpp b/include/QuickMedia.hpp
index 1fda7a3..c1df4ed 100644
--- a/include/QuickMedia.hpp
+++ b/include/QuickMedia.hpp
@@ -134,8 +134,9 @@ namespace QuickMedia {
void video_content_page(Page *parent_page, VideoPage *video_page, std::string video_title, bool download_if_streaming_fails, Body *parent_body, int play_index, int *parent_body_page = nullptr, const std::string &parent_page_search = "");
void save_manga_progress(MangaImagesPage *images_page, Json::Value &json_chapters, Json::Value &json_chapter, int &latest_read);
// Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter
- int image_page(MangaImagesPage *images_page, Body *chapters_body);
- void image_continuous_page(MangaImagesPage *images_page);
+ int image_page(MangaImagesPage *images_page, Body *chapters_body, bool &continue_left_off);
+ // Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter
+ int image_continuous_page(MangaImagesPage *images_page);
void image_board_thread_page(ImageBoardThreadPage *thread_page, Body *thread_body);
void chat_login_page();
bool chat_page(MatrixChatPage *matrix_chat_page, RoomData *current_room);
diff --git a/src/Body.cpp b/src/Body.cpp
index dbcaab0..6bf816d 100644
--- a/src/Body.cpp
+++ b/src/Body.cpp
@@ -1419,7 +1419,7 @@ namespace QuickMedia {
window.draw(loading_icon);
text_offset_x += body_spacing[body_theme].image_padding_x + item->loaded_image_size.x;
}
- } else if(item->thumbnail_size.x > 0) {
+ } else if(draw_thumbnails && item->thumbnail_size.x > 0) {
text_offset_x += body_spacing[body_theme].image_padding_x + item->loaded_image_size.x;
}
@@ -1662,7 +1662,7 @@ namespace QuickMedia {
if(item->loaded_image_size.y < 0.1f)
item->loaded_image_size = content_size.to_vec2f();
}
- } else if(item->thumbnail_size.x > 0) {
+ } else if(draw_thumbnails && item->thumbnail_size.x > 0) {
if(!show_thumbnail)
item->loaded_image_size.x = content_size.x;
// TODO: Fix. This makes the body item have incorrect position when loading and if the item is merge_with_previous? and has an embedded item
@@ -1670,8 +1670,9 @@ namespace QuickMedia {
// image_height = content_size.y;
}
- const float text_offset_x = body_spacing[body_theme].padding_x + body_spacing[body_theme].image_padding_x + item->loaded_image_size.x;
- const float text_max_width = rendering_card_view ? width : (width - text_offset_x - body_spacing[body_theme].image_padding_x);
+ const float image_padding_x = !draw_thumbnails ? 0.0f : body_spacing[body_theme].image_padding_x;
+ const float text_offset_x = body_spacing[body_theme].padding_x + image_padding_x + item->loaded_image_size.x;
+ const float text_max_width = rendering_card_view ? width : (width - text_offset_x - image_padding_x);
if(load_texture)
update_dirty_state(item, text_max_width);
diff --git a/src/ImageViewer.cpp b/src/ImageViewer.cpp
index d00c375..1176046 100644
--- a/src/ImageViewer.cpp
+++ b/src/ImageViewer.cpp
@@ -194,6 +194,22 @@ namespace QuickMedia {
return value >= 0.0 ? 1.0 : -1.0;
}
+ static bool is_key_scroll_up(const mgl::Event::KeyEvent &key) {
+ return (!key.control && key.code == mgl::Keyboard::Up) || (!key.alt && key.control && key.code == mgl::Keyboard::K);
+ }
+
+ static bool is_key_scroll_down(const mgl::Event::KeyEvent &key) {
+ return (!key.control && key.code == mgl::Keyboard::Down) || (!key.alt && key.control && key.code == mgl::Keyboard::J);
+ }
+
+ static bool is_key_previous_chapter(const mgl::Event::KeyEvent &key) {
+ return (key.control && key.code == mgl::Keyboard::Up) || (key.alt && key.control && key.code == mgl::Keyboard::K);
+ }
+
+ static bool is_key_next_chapter(const mgl::Event::KeyEvent &key) {
+ return (key.control && key.code == mgl::Keyboard::Down) || (key.alt && key.control && key.code == mgl::Keyboard::J);
+ }
+
ImageViewerAction ImageViewer::draw() {
const double frame_delta = frame_timer.restart();
const double scroll_speed_key_input = 200.0;
@@ -229,11 +245,17 @@ namespace QuickMedia {
window_size.x = event.size.width;
window_size.y = event.size.height;
} else if(event.type == mgl::Event::KeyPressed) {
- if(event.key.code == mgl::Keyboard::Up || (event.key.control && event.key.code == mgl::Keyboard::K))
+ if(is_key_scroll_up(event.key))
up_pressed = true;
- if(event.key.code == mgl::Keyboard::Down || (event.key.control && event.key.code == mgl::Keyboard::J))
+ if(is_key_scroll_down(event.key))
down_pressed = true;
+ if(is_key_previous_chapter(event.key))
+ return ImageViewerAction::PREVIOUS_CHAPTER;
+
+ if(is_key_next_chapter(event.key))
+ return ImageViewerAction::NEXT_CHAPTER;
+
if(event.key.code == mgl::Keyboard::Escape)
return ImageViewerAction::RETURN;
@@ -243,9 +265,9 @@ namespace QuickMedia {
if(event.key.code == mgl::Keyboard::F)
*fit_image_to_window = !*fit_image_to_window;
} else if(event.type == mgl::Event::KeyReleased) {
- if(event.key.code == mgl::Keyboard::Up || (event.key.control && event.key.code == mgl::Keyboard::K))
+ if(is_key_scroll_up(event.key))
up_pressed = false;
- if(event.key.code == mgl::Keyboard::Down || (event.key.control && event.key.code == mgl::Keyboard::J))
+ if(is_key_scroll_down(event.key))
down_pressed = false;
} else if(event.type == mgl::Event::MouseWheelScrolled/* && event.mouse_wheel_scroll.wheel == mgl::Mouse::VerticalWheel*/) {
scroll_speed += scroll_speed_mouse_wheel * event.mouse_wheel_scroll.delta * frame_delta;
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 4242fa1..a0bd3ea 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -1117,11 +1117,17 @@ namespace QuickMedia {
auto search_page = std::make_unique<MangaGenericSearchPage>(this, plugin_name, "https://mangakatana.com/", false);
add_mangakatana_handlers(search_page.get());
- tabs.push_back(Tab{create_body(), std::make_unique<BookmarksPage>(this, search_page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
+ auto bookmarks_body = create_body();
+ bookmarks_body->draw_thumbnails = false;
+
+ auto history_body = create_body();
+ history_body->draw_thumbnails = false;
+
+ tabs.push_back(Tab{std::move(bookmarks_body), std::make_unique<BookmarksPage>(this, search_page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
tabs.push_back(Tab{create_body(), std::move(search_page), create_search_bar("Search...", 400)});
auto history_page = std::make_unique<HistoryPage>(this, tabs.back().page.get(), HistoryType::MANGA);
- tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
+ tabs.push_back(Tab{std::move(history_body), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
start_tab_index = 1;
} else if(strcmp(plugin_name, "mangadex") == 0) {
@@ -2192,24 +2198,27 @@ namespace QuickMedia {
current_page = pop_page_stack();
} else {
while(window.is_open() && (current_page == PageType::IMAGES || current_page == PageType::IMAGES_CONTINUOUS)) {
+ int page_navigation = 0;
+ bool continue_left_off = false;
+
if(current_page == PageType::IMAGES) {
- while(current_page == PageType::IMAGES) {
- int page_navigation = image_page(manga_images_page, chapters_body);
- if(page_navigation == -1) {
- // TODO: Make this work if the list is sorted differently than from newest to oldest.
- chapters_body->select_next_item();
- select_episode(chapters_body->get_selected(), true);
- image_index = 99999; // Start at the page that shows we are at the end of the chapter
- manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url);
- } else if(page_navigation == 1) {
- // TODO: Make this work if the list is sorted differently than from newest to oldest.
- chapters_body->select_previous_item();
- select_episode(chapters_body->get_selected(), true);
- manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url);
- }
- }
+ page_navigation = image_page(manga_images_page, chapters_body, continue_left_off);
} else if(current_page == PageType::IMAGES_CONTINUOUS) {
- image_continuous_page(manga_images_page);
+ page_navigation = image_continuous_page(manga_images_page);
+ }
+
+ if(page_navigation == -1) {
+ // TODO: Make this work if the list is sorted differently than from newest to oldest.
+ chapters_body->select_next_item();
+ select_episode(chapters_body->get_selected(), !continue_left_off);
+ if(!continue_left_off)
+ image_index = 99999; // Start at the page that shows we are at the end of the chapter
+ manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url);
+ } else if(page_navigation == 1) {
+ // TODO: Make this work if the list is sorted differently than from newest to oldest.
+ chapters_body->select_previous_item();
+ select_episode(chapters_body->get_selected(), !continue_left_off);
+ manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url);
}
}
}
@@ -3053,7 +3062,9 @@ namespace QuickMedia {
bool update_time_pos = false;
bool update_duration = false;
bool update_window_focus = false;
+ bool update_window_focus_timer = false;
mgl::Clock video_time_pos_clock;
+ mgl::Clock update_window_focus_time; // HACK!
std::string youtube_video_id_dummy;
const bool is_youtube = youtube_url_extract_id(video_page->get_url(), youtube_video_id_dummy);
@@ -3076,7 +3087,7 @@ namespace QuickMedia {
mgl::WindowHandle video_player_window = None;
auto on_window_create = [&](mgl::WindowHandle _video_player_window) mutable {
video_player_window = _video_player_window;
- XSelectInput(disp, video_player_window, KeyPressMask | PointerMotionMask);
+ XSelectInput(disp, video_player_window, KeyPressMask | PointerMotionMask | FocusChangeMask);
redirect_focus_to_video_player_window(video_player_window);
XSync(disp, False);
@@ -3086,7 +3097,8 @@ namespace QuickMedia {
video_player->add_subtitle(subtitle_data.url, subtitle_data.title, "eng");
update_time_pos = true;
- update_window_focus = true;
+ update_window_focus_timer = true;
+ update_window_focus_time.restart();
};
int64_t youtube_video_content_length = 0;
@@ -3336,8 +3348,8 @@ namespace QuickMedia {
while (current_page == PageType::VIDEO_CONTENT && window.is_open() && !go_to_previous_page) {
while (window.poll_event(event)) {
common_event_handler(event);
- if(event.type == mgl::Event::GainedFocus && video_player_window) {
- redirect_focus_to_video_player_window(video_player_window);
+ if(event.type == mgl::Event::GainedFocus) {
+ update_window_focus = true;
} else if(event.type == mgl::Event::Resized) {
window_size.x = event.size.width;
window_size.y = event.size.height;
@@ -3358,11 +3370,23 @@ namespace QuickMedia {
}
handle_x11_events();
+ if(video_player_window && XCheckTypedWindowEvent(disp, video_player_window, FocusIn, &xev)) {}
+
+ if(video_player_window && XCheckTypedWindowEvent(disp, video_player_window, FocusOut, &xev)) {
+ update_window_focus = true;
+ }
+
if(video_player_window && update_window_focus) {
update_window_focus = false;
redirect_focus_to_video_player_window(video_player_window);
}
+ if(video_player_window && update_window_focus_timer && update_window_focus_time.get_elapsed_time_seconds() >= 0.5) {
+ update_window_focus_timer = false;
+ update_window_focus = false;
+ redirect_focus_to_video_player_window(video_player_window);
+ }
+
if(video_player && video_player_window && XCheckTypedWindowEvent(disp, video_player_window, KeyPress, &xev)/* && xev.xkey.subwindow == video_player_window*/) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
@@ -3920,9 +3944,10 @@ namespace QuickMedia {
}
}
- int Program::image_page(MangaImagesPage *images_page, Body *chapters_body) {
+ int Program::image_page(MangaImagesPage *images_page, Body *chapters_body, bool &continue_left_off) {
int page_navigation = 0;
image_download_cancel = false;
+ continue_left_off = false;
content_cache_dir = get_cache_dir().join(images_page->get_service_name()).join(manga_id_base64).join(base64_url_encode(images_page->get_chapter_name()));
if(create_directory_recursive(content_cache_dir) != 0) {
@@ -4005,7 +4030,7 @@ namespace QuickMedia {
} else if(event.type == mgl::Event::GainedFocus) {
redraw = true;
} else if(event.type == mgl::Event::KeyPressed) {
- if(event.key.code == mgl::Keyboard::Up || (event.key.control && event.key.code == mgl::Keyboard::K)) {
+ if((!event.key.control && event.key.code == mgl::Keyboard::Up) || (!event.key.alt && event.key.control && event.key.code == mgl::Keyboard::K)) {
if(image_index > 0) {
--image_index;
goto end_of_images_page;
@@ -4013,7 +4038,7 @@ namespace QuickMedia {
page_navigation = -1;
goto end_of_images_page;
}
- } else if(event.key.code == mgl::Keyboard::Down || (event.key.control && event.key.code == mgl::Keyboard::J)) {
+ } else if((!event.key.control && event.key.code == mgl::Keyboard::Down) || (!event.key.alt && event.key.control && event.key.code == mgl::Keyboard::J)) {
if(image_index < num_manga_pages) {
++image_index;
goto end_of_images_page;
@@ -4041,6 +4066,12 @@ namespace QuickMedia {
image_index = num_manga_pages;
goto end_of_images_page;
}
+ } else if((event.key.control && event.key.code == mgl::Keyboard::Up) || (event.key.alt && event.key.control && event.key.code == mgl::Keyboard::K)) {
+ page_navigation = -1;
+ goto end_of_images_page;
+ } else if((event.key.control && event.key.code == mgl::Keyboard::Down) || (event.key.alt && event.key.control && event.key.code == mgl::Keyboard::J)) {
+ page_navigation = 1;
+ goto end_of_images_page;
} else if(event.key.code == mgl::Keyboard::Escape) {
current_page = pop_page_stack();
} else if(event.key.code == mgl::Keyboard::I) {
@@ -4130,24 +4161,25 @@ namespace QuickMedia {
return page_navigation;
}
- void Program::image_continuous_page(MangaImagesPage *images_page) {
+ int Program::image_continuous_page(MangaImagesPage *images_page) {
+ int page_navigation = 0;
image_download_cancel = false;
content_cache_dir = get_cache_dir().join(images_page->get_service_name()).join(manga_id_base64).join(base64_url_encode(images_page->get_chapter_name()));
if(create_directory_recursive(content_cache_dir) != 0) {
show_notification("QuickMedia", "Failed to create directory: " + content_cache_dir.data, Urgency::CRITICAL);
current_page = pop_page_stack();
- return;
+ return page_navigation;
}
download_chapter_images_if_needed(images_page);
if(num_manga_pages == 0) {
current_page = pop_page_stack();
- return;
+ return page_navigation;
}
if(current_page != PageType::IMAGES_CONTINUOUS || !window.is_open())
- return;
+ return page_navigation;
Json::Value json_chapters;
Json::Value json_chapter;
@@ -4171,6 +4203,14 @@ namespace QuickMedia {
image_view_mode = ImageViewMode::SINGLE;
current_page = PageType::IMAGES;
break;
+ case ImageViewerAction::PREVIOUS_CHAPTER: {
+ page_navigation = -1;
+ goto end_of_continuous_images_page;
+ }
+ case ImageViewerAction::NEXT_CHAPTER: {
+ page_navigation = 1;
+ goto end_of_continuous_images_page;
+ }
}
AsyncImageLoader::get_instance().update();
window.display();
@@ -4189,8 +4229,10 @@ namespace QuickMedia {
}
}
+ end_of_continuous_images_page:
window_size.x = window.get_size().x;
window_size.y = window.get_size().y;
+ return page_navigation;
}
static bool get_image_board_last_posted_filepath(const char *plugin_name, Path &path) {