aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-08-02 20:08:27 +0200
committerdec05eba <dec05eba@protonmail.com>2019-08-02 20:08:27 +0200
commit65cf7681a04f2511db8c7829e9828b53a6676c88 (patch)
tree6e7db509cf2bce4a10fa6d8bc89a9eae88d893fa
parent109c797d7c89223c9eed07dc322448b5c5fe3373 (diff)
Convert to sfml, starting on manganelo and youtube
-rw-r--r--.gitignore3
m---------depends/html-search0
-rw-r--r--fonts/Lato-Regular.ttfbin0 -> 656568 bytes
-rw-r--r--include/Program.h10
-rw-r--r--plugins/Manganelo.hpp10
-rw-r--r--plugins/Plugin.hpp38
-rw-r--r--plugins/Youtube.hpp10
-rw-r--r--project.conf2
-rw-r--r--src/Manganelo.cpp51
-rw-r--r--src/Plugin.cpp17
-rw-r--r--src/Program.c38
-rw-r--r--src/Youtube.cpp34
-rw-r--r--src/main.c147
-rw-r--r--src/main.cpp201
-rw-r--r--tests/main.c45
15 files changed, 398 insertions, 208 deletions
diff --git a/.gitignore b/.gitignore
index 636c6b9..3d24e52 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,6 @@ sibs-build/
compile_commands.json
tests/sibs-build/
tests/compile_commands.json
+
+.vscode/
+.gdb_history
diff --git a/depends/html-search b/depends/html-search
-Subproject c7500d39c6bae0084196ca7a7395ac85fff0992
+Subproject b2fd63ad96469b450eb98a8034073f5a8c1cb95
diff --git a/fonts/Lato-Regular.ttf b/fonts/Lato-Regular.ttf
new file mode 100644
index 0000000..0f3d0f8
--- /dev/null
+++ b/fonts/Lato-Regular.ttf
Binary files differ
diff --git a/include/Program.h b/include/Program.h
index 5f986a4..f891d8e 100644
--- a/include/Program.h
+++ b/include/Program.h
@@ -1,6 +1,10 @@
#ifndef QUICKMEDIA_PROGRAM_H
#define QUICKMEDIA_PROGRAM_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Return 0 if you want to continue reading */
typedef int (*ProgramOutputCallback)(char *data, int size, void *userdata);
@@ -8,6 +12,10 @@ typedef int (*ProgramOutputCallback)(char *data, int size, void *userdata);
@args need to have at least 2 arguments. The first which is the program name
and the last which is NULL, which indicates end of args
*/
-int exec_program(char **args, ProgramOutputCallback output_callback, void *userdata);
+int exec_program(const char **args, ProgramOutputCallback output_callback, void *userdata);
+
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/plugins/Manganelo.hpp b/plugins/Manganelo.hpp
new file mode 100644
index 0000000..fd56b85
--- /dev/null
+++ b/plugins/Manganelo.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "Plugin.hpp"
+
+namespace QuickMedia {
+ class Manganelo : public Plugin {
+ public:
+ SearchResult search(const std::string &text, std::vector<std::unique_ptr<BodyItem>> &result_items) override;
+ };
+} \ No newline at end of file
diff --git a/plugins/Plugin.hpp b/plugins/Plugin.hpp
new file mode 100644
index 0000000..bc518a8
--- /dev/null
+++ b/plugins/Plugin.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace QuickMedia {
+ class BodyItem {
+ public:
+ BodyItem(const std::string &_title): title(_title) {
+
+ }
+
+ std::string title;
+ std::string cover_url;
+ };
+
+ enum class SearchResult {
+ OK,
+ ERR,
+ NET_ERR
+ };
+
+ enum class DownloadResult {
+ OK,
+ ERR,
+ NET_ERR
+ };
+
+ class Plugin {
+ public:
+ virtual ~Plugin() = default;
+
+ virtual SearchResult search(const std::string &text, std::vector<std::unique_ptr<BodyItem>> &result_items) = 0;
+ protected:
+ DownloadResult download_to_string(const std::string &url, std::string &result);
+ };
+} \ No newline at end of file
diff --git a/plugins/Youtube.hpp b/plugins/Youtube.hpp
new file mode 100644
index 0000000..ea2918d
--- /dev/null
+++ b/plugins/Youtube.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "Plugin.hpp"
+
+namespace QuickMedia {
+ class Youtube : public Plugin {
+ public:
+ SearchResult search(const std::string &text, std::vector<std::unique_ptr<BodyItem>> &result_items) override;
+ };
+} \ No newline at end of file
diff --git a/project.conf b/project.conf
index c35ebe5..c0fdf68 100644
--- a/project.conf
+++ b/project.conf
@@ -5,4 +5,4 @@ version = "0.1.0"
platforms = ["posix"]
[dependencies]
-gtk+-3.0 = "3" \ No newline at end of file
+sfml-graphics = "2" \ No newline at end of file
diff --git a/src/Manganelo.cpp b/src/Manganelo.cpp
new file mode 100644
index 0000000..56a6d50
--- /dev/null
+++ b/src/Manganelo.cpp
@@ -0,0 +1,51 @@
+#include "../plugins/Manganelo.hpp"
+#include <quickmedia/HtmlSearch.h>
+
+namespace QuickMedia {
+ SearchResult Manganelo::search(const std::string &text, std::vector<std::unique_ptr<BodyItem>> &result_items) {
+ std::string url = "https://manganelo.com/search/";
+ // TODO: Escape @text. Need to replace space with underscore for example.
+ url += text;
+
+ std::string website_data;
+ if(download_to_string(url, website_data) != DownloadResult::OK)
+ return SearchResult::NET_ERR;
+
+ struct ItemData {
+ std::vector<std::unique_ptr<BodyItem>> &result_items;
+ size_t item_index;
+ };
+
+ ItemData item_data = { result_items, 0 };
+
+ QuickMediaHtmlSearch html_search;
+ int result = quickmedia_html_search_init(&html_search, website_data.c_str());
+ if(result != 0)
+ goto cleanup;
+
+ result = quickmedia_html_find_nodes_xpath(&html_search, "//h3[class=\"story_name\"]/a",
+ [](QuickMediaHtmlNode *node, void *userdata) {
+ ItemData *item_data = (ItemData*)userdata;
+ const char *href = quickmedia_html_node_get_attribute_value(node, "href");
+ const char *text = quickmedia_html_node_get_text(node);
+ auto item = std::make_unique<BodyItem>(text);
+ item_data->result_items.push_back(std::move(item));
+ }, &item_data);
+ if (result != 0)
+ goto cleanup;
+
+ result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class=\"story_item\"]//img",
+ [](QuickMediaHtmlNode *node, void *userdata) {
+ ItemData *item_data = (ItemData*)userdata;
+ const char *src = quickmedia_html_node_get_attribute_value(node, "src");
+ if(item_data->item_index < item_data->result_items.size()) {
+ item_data->result_items[item_data->item_index]->cover_url = src;
+ ++item_data->item_index;
+ }
+ }, &item_data);
+
+ cleanup:
+ quickmedia_html_search_deinit(&html_search);
+ return result == 0 ? SearchResult::OK : SearchResult::ERR;
+ }
+} \ No newline at end of file
diff --git a/src/Plugin.cpp b/src/Plugin.cpp
new file mode 100644
index 0000000..d2fe925
--- /dev/null
+++ b/src/Plugin.cpp
@@ -0,0 +1,17 @@
+#include "../plugins/Plugin.hpp"
+#include "../include/Program.h"
+
+static int accumulate_string(char *data, int size, void *userdata) {
+ std::string *str = (std::string*)userdata;
+ str->append(data, size);
+ return 0;
+}
+
+namespace QuickMedia {
+ DownloadResult Plugin::download_to_string(const std::string &url, std::string &result) {
+ const char *args[] = { "curl", "-H", "Accept-Language: en-US,en;q=0.5", "--compressed", "-s", "-L", url.c_str(), nullptr };
+ if(exec_program(args, accumulate_string, &result) != 0)
+ return DownloadResult::NET_ERR;
+ return DownloadResult::OK;
+ }
+} \ No newline at end of file
diff --git a/src/Program.c b/src/Program.c
index 526f64b..39957ed 100644
--- a/src/Program.c
+++ b/src/Program.c
@@ -8,7 +8,7 @@
#define READ_END 0
#define WRITE_END 1
-int exec_program(char **args, ProgramOutputCallback output_callback, void *userdata) {
+int exec_program(const char **args, ProgramOutputCallback output_callback, void *userdata) {
/* 1 arguments */
if(args[0] == NULL)
return -1;
@@ -28,24 +28,15 @@ int exec_program(char **args, ProgramOutputCallback output_callback, void *userd
close(fd[READ_END]);
close(fd[WRITE_END]);
- execv(args[0], args);
+ execvp(args[0], args);
return 0;
} else { /* parent */
close(fd[WRITE_END]);
+ int result = 0;
int status;
- waitpid(pid, &status, 0);
- if(!WIFEXITED(status))
- return -4;
-
- int exit_status = WEXITSTATUS(status);
- if(exit_status != 0) {
- fprintf(stderr, "Failed to execute program, exit status %d\n", exit_status);
- return -exit_status;
- }
char buffer[2048];
- int result = 0;
for(;;) {
ssize_t bytes_read = read(fd[READ_END], buffer, sizeof(buffer));
@@ -55,14 +46,33 @@ int exec_program(char **args, ProgramOutputCallback output_callback, void *userd
int err = errno;
fprintf(stderr, "Failed to read from pipe to program %s, error: %s\n", args[0], strerror(err));
result = -err;
- break;
+ goto cleanup;
}
if(output_callback(buffer, bytes_read, userdata) != 0)
break;
}
+ if(waitpid(pid, &status, WUNTRACED) == -1) {
+ perror("waitpid failed");
+ result = -5;
+ goto cleanup;
+ }
+
+ if(!WIFEXITED(status)) {
+ result = -4;
+ goto cleanup;
+ }
+
+ int exit_status = WEXITSTATUS(status);
+ if(exit_status != 0) {
+ fprintf(stderr, "Failed to execute program, exit status %d\n", exit_status);
+ result = -exit_status;
+ goto cleanup;
+ }
+
+ cleanup:
close(fd[READ_END]);
return result;
}
-} \ No newline at end of file
+}
diff --git a/src/Youtube.cpp b/src/Youtube.cpp
new file mode 100644
index 0000000..d8b046f
--- /dev/null
+++ b/src/Youtube.cpp
@@ -0,0 +1,34 @@
+#include "../plugins/Youtube.hpp"
+#include <quickmedia/HtmlSearch.h>
+
+namespace QuickMedia {
+ SearchResult Youtube::search(const std::string &text, std::vector<std::unique_ptr<BodyItem>> &result_items) {
+ std::string url = "https://youtube.com/results?search_query=";
+ // TODO: Escape @text
+ url += text;
+
+ std::string website_data;
+ if(download_to_string(url, website_data) != DownloadResult::OK)
+ return SearchResult::NET_ERR;
+
+ QuickMediaHtmlSearch html_search;
+ int result = quickmedia_html_search_init(&html_search, website_data.c_str());
+ if(result != 0)
+ goto cleanup;
+
+ result = quickmedia_html_find_nodes_xpath(&html_search, "//h3[class=\"yt-lockup-title\"]/a",
+ [](QuickMediaHtmlNode *node, void *userdata) {
+ auto *result_items = (std::vector<std::unique_ptr<BodyItem>>*)userdata;
+ const char *href = quickmedia_html_node_get_attribute_value(node, "href");
+ const char *title = quickmedia_html_node_get_attribute_value(node, "title");
+ printf("a href: %s, title: %s\n", href, title);
+
+ auto item = std::make_unique<BodyItem>(title);
+ result_items->push_back(std::move(item));
+ }, &result_items);
+
+ cleanup:
+ quickmedia_html_search_deinit(&html_search);
+ return result == 0 ? SearchResult::OK : SearchResult::ERR;
+ }
+} \ No newline at end of file
diff --git a/src/main.c b/src/main.c
deleted file mode 100644
index a909d28..0000000
--- a/src/main.c
+++ /dev/null
@@ -1,147 +0,0 @@
-#include <gtk/gtk.h>
-#include <glib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <quickmedia/HtmlSearch.h>
-
-static GtkWidget *window = NULL;
-static GtkWidget *search_entry = NULL;
-static GtkWidget *list = NULL;
-/* TODO: Optimize this. There shouldn't be a need to copy the whole buffer everytime it's modified */
-static gchar *search_text = NULL;
-
-typedef struct {
- const char *data;
- size_t size;
-} StringView;
-
-typedef enum {
- DATA_INVALID,
- DATA_TITLE,
- DATA_DESCRIPTION,
- DATA_IMAGE
-} DataType;
-
-static GtkLabel* get_list_item_title(GtkListBoxRow *row) {
- GtkWidget *child_widget = GTK_WIDGET(gtk_container_get_children(GTK_CONTAINER(row))->data);
- return GTK_LABEL(gtk_grid_get_child_at(GTK_GRID(child_widget), 0, 0));
-}
-
-static gboolean focus_out_callback(GtkWidget *widget, GdkEvent *event, gpointer userdata) {
- gtk_widget_destroy(window);
- return FALSE;
-}
-
-static gboolean filter_func(GtkListBoxRow *row, gpointer userdata) {
- GtkLabel *row_title_label = get_list_item_title(row);
- gboolean show = !search_text || strlen(search_text) == 0 || strstr(gtk_label_get_text(row_title_label), search_text) != NULL;
- if(!show && gtk_list_box_get_selected_row(GTK_LIST_BOX(list)) == row) {
- gtk_list_box_unselect_row(GTK_LIST_BOX(list), row);
- }
- return show;
-}
-
-static void list_move_select(GtkListBox *list, gint direction) {
- GtkListBoxRow *row = gtk_list_box_get_selected_row(GTK_LIST_BOX(list));
- if(!row)
- return;
-
- gint current_row_index = gtk_list_box_row_get_index(row);
- GtkListBoxRow *new_row = gtk_list_box_get_row_at_index(GTK_LIST_BOX(list), current_row_index + direction);
- if(new_row)
- gtk_list_box_select_row(GTK_LIST_BOX(list), new_row);
-}
-
-static gboolean keypress_callback(GtkWidget *widget, GdkEventKey *event, gpointer userdata) {
- if(event->keyval == GDK_KEY_BackSpace) {
- gtk_editable_delete_text(GTK_EDITABLE(search_entry), 0, -1);
- } else if(event->keyval == GDK_KEY_Return || event->keyval == GDK_KEY_KP_Enter) {
- GtkListBoxRow *row = gtk_list_box_get_selected_row(GTK_LIST_BOX(list));
- if(row) {
- if(gtk_widget_is_visible(GTK_WIDGET(row))) {
- GtkLabel *row_title_label = get_list_item_title(row);
- puts(gtk_label_get_text(row_title_label));
- } else {
- puts(gtk_entry_get_text(GTK_ENTRY(search_entry)));
- }
- }
- gtk_widget_destroy(window);
- return FALSE;
- } else if(event->keyval == GDK_KEY_Escape) {
- gtk_widget_destroy(window);
- return FALSE;
- } else if(event->keyval == GDK_KEY_Up) {
- list_move_select(GTK_LIST_BOX(list), -1);
- return FALSE;
- } else if(event->keyval == GDK_KEY_Down) {
- list_move_select(GTK_LIST_BOX(list), 1);
- return FALSE;
- } else {
- gint position = -1;
- gtk_editable_insert_text(GTK_EDITABLE(search_entry), event->string, -1, &position);
- //printf("key press %d\n", event->keyval);
- }
-
- g_free(search_text);
- search_text = gtk_editable_get_chars(GTK_EDITABLE(search_entry), 0, -1);
- gtk_list_box_invalidate_filter(GTK_LIST_BOX(list));
- return TRUE;
-}
-
-static GtkWidget* create_entry(const char *text, const char *description) {
- GtkWidget *entry = gtk_grid_new();
- GtkWidget *label_widget = gtk_label_new(text);
- gtk_grid_attach(GTK_GRID(entry), label_widget, 0, 0, 1, 1);
- GtkWidget *description_widget = gtk_label_new(description);
- gtk_grid_attach(GTK_GRID(entry), description_widget, 1, 0, 1, 1);
- return entry;
-}
-
-static void activate(GtkApplication *app, gpointer userdata) {
- window = gtk_application_window_new(app);
- gtk_window_set_title(GTK_WINDOW(window), "QuickMedia");
- gtk_window_set_default_size(GTK_WINDOW(window), 600, 300);
-
- GtkWidget *grid = gtk_grid_new();
- gtk_container_add(GTK_CONTAINER(window), grid);
-
- search_entry = gtk_search_entry_new();
- gtk_widget_set_sensitive(search_entry, FALSE);
- GdkRGBA text_color;
- gdk_rgba_parse(&text_color, "black");
- gtk_widget_override_color(search_entry, GTK_STATE_FLAG_INSENSITIVE, &text_color);
- gtk_widget_set_hexpand(search_entry, TRUE);
- gtk_grid_attach(GTK_GRID(grid), search_entry, 0, 0, 1, 1);
-
- GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
- gtk_grid_attach(GTK_GRID(grid), scrolled_window, 0, 1, 1, 1);
-
- list = gtk_list_box_new();
- gtk_widget_set_hexpand(list, TRUE);
- gtk_widget_set_vexpand(list, TRUE);
- gtk_list_box_set_filter_func(GTK_LIST_BOX(list), filter_func, NULL, NULL);
- gtk_container_add(GTK_CONTAINER(scrolled_window), list);
-
- for(int i = 0; i < 100; ++i) {
- GtkWidget *item = create_entry("hello, world!", "description");
- gtk_list_box_insert(GTK_LIST_BOX(list), item, i);
- }
-
- gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
- gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
- gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
- gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
- gtk_widget_show_all(window);
-
- gtk_widget_add_events(window, GDK_KEY_PRESS_MASK | GDK_FOCUS_CHANGE_MASK);
- g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(keypress_callback), NULL);
- g_signal_connect(G_OBJECT(window), "focus-out-event", G_CALLBACK(focus_out_callback), NULL);
-}
-
-int main(int argc, char **argv) {
- GtkApplication *app = gtk_application_new("org.dec05eba.quickmedia", G_APPLICATION_FLAGS_NONE);
- g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
- int status = g_application_run(G_APPLICATION(app), argc, argv);
- g_object_unref(app);
- return status;
-}
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..4689bc5
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,201 @@
+#include "../include/Program.h"
+#include "../plugins/Manganelo.hpp"
+#include "../plugins/Youtube.hpp"
+#include <SFML/Graphics.hpp>
+#include <string>
+#include <vector>
+
+const sf::Color front_color(43, 45, 47);
+const sf::Color back_color(33, 35, 37);
+
+namespace QuickMedia {
+ class Body {
+ public:
+ Body(sf::Font &font) : title_text("", font, 14), selected_item(0) {
+ title_text.setFillColor(sf::Color::White);
+ }
+
+ void add_item(std::unique_ptr<BodyItem> item) {
+ items.push_back(std::move(item));
+ }
+
+ void select_previous_item() {
+ selected_item = std::max(0, selected_item - 1);
+ }
+
+ void select_next_item() {
+ const int last_item = std::max(0, (int)items.size() - 1);
+ selected_item = std::min(last_item, selected_item + 1);
+ }
+
+ void reset_selected() {
+ selected_item = 0;
+ }
+
+ void clear_items() {
+ items.clear();
+ }
+
+ void draw(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size) {
+ const float font_height = title_text.getCharacterSize() + 8.0f;
+
+ sf::RectangleShape image(sf::Vector2f(50, 50));
+ image.setFillColor(sf::Color::White);
+
+ sf::RectangleShape item_background;
+ item_background.setFillColor(front_color);
+ item_background.setOutlineThickness(1.0f);
+ item_background.setOutlineColor(sf::Color(63, 65, 67));
+
+ sf::RectangleShape selected_border(sf::Vector2f(5.0f, 50));
+ selected_border.setFillColor(sf::Color::Red);
+
+ int i = 0;
+ for(const auto &item : items) {
+ sf::Vector2f item_pos = pos;
+ if(i == selected_item) {
+ selected_border.setPosition(pos);
+ window.draw(selected_border);
+ item_pos.x += selected_border.getSize().x;
+ }
+
+ item_background.setPosition(item_pos);
+ item_background.setSize(sf::Vector2f(size.x, 50));
+ window.draw(item_background);
+
+ image.setPosition(item_pos);
+ window.draw(image);
+
+ title_text.setString(item->title);
+ title_text.setPosition(item_pos.x + 50 + 10, item_pos.y);
+ window.draw(title_text);
+
+ pos.y += 50 + 10;
+ ++i;
+ }
+ }
+
+ sf::Text title_text;
+ int selected_item;
+ std::vector<std::unique_ptr<BodyItem>> items;
+ };
+}
+
+static void search(sf::String text, QuickMedia::Body *body, QuickMedia::Plugin *plugin) {
+ body->clear_items();
+ QuickMedia::SearchResult search_result = plugin->search(text, body->items);
+ fprintf(stderr, "Search result: %d\n", search_result);
+}
+
+int main() {
+ const float padding_horizontal = 10.0f;
+ const float padding_vertical = 10.0f;
+
+ sf::RenderWindow window(sf::VideoMode(800, 800), "SFML works!");
+ window.setVerticalSyncEnabled(true);
+
+ sf::Font font;
+ if(!font.loadFromFile("fonts/Lato-Regular.ttf")) {
+ fprintf(stderr, "Failed to load font!\n");
+ abort();
+ }
+
+ bool show_placeholder = true;
+ sf::Color text_placeholder_color(255, 255, 255, 100);
+ sf::Text search_text("Search...", font, 18);
+ search_text.setFillColor(text_placeholder_color);
+
+ bool resized = true;
+ sf::Vector2f window_size(window.getSize().x, window.getSize().y);
+
+ sf::RectangleShape search_background;
+ search_background.setFillColor(front_color);
+ search_background.setPosition(padding_horizontal, padding_vertical);
+ const float search_background_margin_horizontal = 8.0f;
+ const float search_background_margin_vertical = 4.0f;
+
+ sf::RectangleShape body_background;
+ body_background.setFillColor(front_color);
+
+ QuickMedia::Body body(font);
+ QuickMedia::Manganelo manganelo_plugin;
+ QuickMedia::Youtube youtube_plugin;
+ QuickMedia::Plugin *plugin = &youtube_plugin;
+
+ while (window.isOpen()) {
+ sf::Event event;
+ while (window.pollEvent(event)) {
+ if (event.type == sf::Event::Closed)
+ window.close();
+ else if(event.type == sf::Event::Resized) {
+ window_size.x = event.size.width;
+ window_size.y = event.size.height;
+ sf::FloatRect visible_area(0, 0, window_size.x, window_size.y);
+ window.setView(sf::View(visible_area));
+ resized = true;
+ } else if(event.type == sf::Event::KeyPressed) {
+ if(event.key.code == sf::Keyboard::Up) {
+ body.select_previous_item();
+ } else if(event.key.code == sf::Keyboard::Down) {
+ body.select_next_item();
+ }
+ } else if(event.type == sf::Event::TextEntered) {
+ if(event.text.unicode == 8 && !show_placeholder) { // Backspace
+ sf::String str = search_text.getString();
+ if(str.getSize() > 0) {
+ str.erase(str.getSize() - 1, 1);
+ search_text.setString(str);
+ if(str.getSize() == 0) {
+ show_placeholder = true;
+ search_text.setString("Search...");
+ search_text.setFillColor(text_placeholder_color);
+ }
+ }
+ } else if(event.text.unicode == 13 && !show_placeholder) { // Return
+ body.reset_selected();
+ search(search_text.getString(), &body, plugin);
+ show_placeholder = true;
+ search_text.setString("Search...");
+ search_text.setFillColor(text_placeholder_color);
+ } else if(event.text.unicode > 31) { // Non-control character
+ if(show_placeholder) {
+ show_placeholder = false;
+ search_text.setString("");
+ search_text.setFillColor(sf::Color::White);
+ }
+ sf::String str = search_text.getString();
+ str += event.text.unicode;
+ search_text.setString(str);
+ }
+ }
+ }
+
+ if(resized) {
+ resized = false;
+
+ float font_height = search_text.getCharacterSize() + 8.0f;
+ float rect_height = font_height + search_background_margin_vertical * 2.0f;
+ search_background.setSize(sf::Vector2f(window_size.x - padding_horizontal * 2.0f, rect_height));
+ search_text.setPosition(padding_horizontal + search_background_margin_horizontal, padding_vertical + search_background_margin_vertical);
+
+ float body_padding_horizontal = 50.0f;
+ float body_padding_vertical = 50.0f;
+ float body_width = window_size.x - body_padding_horizontal * 2.0f;
+ if(body_width < 400) {
+ body_width = window_size.x;
+ body_padding_horizontal = 0.0f;
+ }
+ body_background.setPosition(body_padding_horizontal, search_background.getPosition().y + search_background.getSize().y + body_padding_vertical);
+ body_background.setSize(sf::Vector2f(body_width, window_size.y));
+ }
+
+ window.clear(back_color);
+ body.draw(window, body_background.getPosition(), body_background.getSize());
+ window.draw(search_background);
+ window.draw(search_text);
+ window.display();
+ }
+
+ return 0;
+}
+
diff --git a/tests/main.c b/tests/main.c
deleted file mode 100644
index 3ba930b..0000000
--- a/tests/main.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <stdio.h>
-#include "../include/Program.h"
-#include <quickmedia/HtmlSearch.h>
-#include <stdlib.h>
-#include <string.h>
-
-typedef struct {
- char *data;
- size_t size;
-} Buffer;
-
-static int program_output_callback(char *data, int size, void *userdata) {
- Buffer *buf = userdata;
- size_t new_size = buf->size + size;
- buf->data = realloc(buf->data, new_size + 1);
- buf->data[new_size] = '\0';
- memcpy(buf->data + buf->size, data, size);
- buf->size = new_size;
- return 0;
-}
-
-static void html_search_callback(QuickMediaHtmlNode *node, void *userdata) {
- const char *href = quickmedia_html_node_get_attribute_value(node, "href");
- QuickMediaStringView text = quickmedia_html_node_get_text(node);
- printf("a href: %s, text: %.*s\n", href, text.size, text.data);
-}
-
-int main(int argc, char **argv) {
- Buffer buf;
- buf.data = NULL;
- buf.size = 0;
- char *args[] = { "/usr/bin/curl", "-s", "-L", "https://manganelo.com/search/naruto", NULL };
- exec_program(args, program_output_callback, &buf);
- /*printf("%s\n", buf.data);*/
-
- QuickMediaHtmlSearch html_search;
- if(quickmedia_html_search_init(&html_search, buf.data) != 0)
- return -1;
- if(quickmedia_html_find_nodes_xpath(&html_search, "//h3[class=\"story_name\"]//a", html_search_callback, NULL) != 0)
- return -1;
- quickmedia_html_search_deinit(&html_search);
-
- free(buf.data);
- return 0;
-}