Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/list_entry.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef CERTAMEN_LIST_ENTRY_HPP
#define CERTAMEN_LIST_ENTRY_HPP

#include <ftxui/component/event.hpp>
#include <ftxui/dom/elements.hpp>
#include <ftxui/screen/box.hpp>
#include <memory>
#include <vector>

using EntryBoxes = std::shared_ptr<std::vector<ftxui::Box>>;

inline EntryBoxes make_entry_boxes()
{
return std::make_shared<std::vector<ftxui::Box>>();
}

inline ftxui::Element list_entry(ftxui::Element el, bool selected,
EntryBoxes& boxes, int i)
{
if (selected) el = el | ftxui::color(ftxui::Color::Cyan) | ftxui::focus;
return el | ftxui::reflect((*boxes)[i]);
}

inline int mouse_click_index(ftxui::Event& event, const EntryBoxes& boxes)
{
if (!event.is_mouse() ||
event.mouse().button != ftxui::Mouse::Left ||
event.mouse().motion != ftxui::Mouse::Pressed)
return -1;
for (int i = 0; i < static_cast<int>(boxes->size()); ++i)
if ((*boxes)[i].Contain(event.mouse().x, event.mouse().y))
return i;
return -1;
}

#endif
41 changes: 35 additions & 6 deletions src/screens/change_answer.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "screens/change_answer.hpp"
#include "app.hpp"
#include "list_entry.hpp"
#include "nav.hpp"
#include "syntax.hpp"
#include <ftxui/component/component.hpp>
Expand All @@ -10,9 +11,32 @@ using namespace ftxui;

ftxui::Component make_change_answer_screen(AppState& state)
{
auto component = CatchEvent(Renderer([](bool) { return text(""); }), [&](Event event) {
auto entry_boxes = make_entry_boxes();

auto component = CatchEvent(Renderer([](bool) { return text(""); }), [&, entry_boxes](Event event) {
if (state.target_indices.empty()) return false;

int clicked = mouse_click_index(event, entry_boxes);
if (clicked >= 0)
{
if (state.change_answer_phase == 0)
{
state.select_question_idx = clicked;
int real_idx = state.target_indices[clicked];
state.change_answer_phase = 1;
state.select_new_answer = state.questions[real_idx].answer;
}
else
{
state.select_new_answer = clicked;
int real_idx = state.target_indices[state.select_question_idx];
state.questions[real_idx].answer = state.select_new_answer;
state.status_message = "Answer updated.";
state.change_answer_phase = 0;
}
return true;
}

if (state.change_answer_phase == 0)
{
int count = static_cast<int>(state.target_indices.size());
Expand Down Expand Up @@ -54,21 +78,24 @@ ftxui::Component make_change_answer_screen(AppState& state)
return false;
});

return Renderer(component, [&] {
return Renderer(component, [&, entry_boxes] {
if (state.target_indices.empty())
return text(" No questions for this file. ") | center | borderRounded;

Elements body;

if (state.change_answer_phase == 0)
{
int count = static_cast<int>(state.target_indices.size());
entry_boxes->resize(count);

body.push_back(text(""));
body.push_back(text(" Change Answer ") | bold | center);
body.push_back(text(""));
body.push_back(separator() | color(Color::GrayDark));
body.push_back(text(""));

for (int i = 0; i < static_cast<int>(state.target_indices.size()); ++i)
for (int i = 0; i < count; ++i)
{
bool sel = (i == state.select_question_idx);
const auto& q = state.questions[state.target_indices[i]];
Expand All @@ -82,7 +109,7 @@ ftxui::Component make_change_answer_screen(AppState& state)
text(answer_hint) | dim | color(Color::Green),
});
if (sel) entry = entry | color(Color::Cyan) | focus;
body.push_back(entry);
body.push_back(entry | reflect((*entry_boxes)[i]));
}

body.push_back(text(""));
Expand All @@ -109,7 +136,9 @@ ftxui::Component make_change_answer_screen(AppState& state)

body.push_back(text(""));

for (int i = 0; i < static_cast<int>(q.choices.size()); ++i)
int num_choices = static_cast<int>(q.choices.size());
entry_boxes->resize(num_choices);
for (int i = 0; i < num_choices; ++i)
{
bool is_current = (i == q.answer);
bool is_new = (i == state.select_new_answer);
Expand All @@ -122,7 +151,7 @@ ftxui::Component make_change_answer_screen(AppState& state)
});
if (is_new) choice_el = choice_el | color(Color::Cyan) | focus;
else choice_el = choice_el | dim;
body.push_back(choice_el);
body.push_back(choice_el | reflect((*entry_boxes)[i]));
}

body.push_back(text(""));
Expand Down
42 changes: 36 additions & 6 deletions src/screens/edit_choice.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "screens/edit_choice.hpp"
#include "app.hpp"
#include "list_entry.hpp"
#include "nav.hpp"
#include "syntax.hpp"
#include <ftxui/component/component.hpp>
Expand All @@ -10,6 +11,7 @@ using namespace ftxui;

ftxui::Component make_edit_choice_screen(AppState& state)
{
auto entry_boxes = make_entry_boxes();
auto text_input = Input(&state.edit_choice_text, "Choice text...");

auto save_btn = Button(" Save ", [&] {
Expand All @@ -35,8 +37,31 @@ ftxui::Component make_edit_choice_screen(AppState& state)

auto inner = Container::Vertical({});

auto component = CatchEvent(inner, [&](Event event) {
auto component = CatchEvent(inner, [&, entry_boxes](Event event) {
if (state.target_indices.empty()) return false;

if (state.edit_choice_phase != 2)
{
int clicked = mouse_click_index(event, entry_boxes);
if (clicked >= 0)
{
if (state.edit_choice_phase == 0)
{
state.edit_choice_question_idx = clicked;
state.edit_choice_phase = 1;
state.edit_choice_choice_idx = 0;
}
else
{
state.edit_choice_choice_idx = clicked;
int real_idx = state.target_indices[state.edit_choice_question_idx];
state.edit_choice_text = state.questions[real_idx].choices[clicked];
state.edit_choice_phase = 2;
}
return true;
}
}

if (state.edit_choice_phase == 2)
{
if (event == Event::Escape)
Expand Down Expand Up @@ -87,7 +112,7 @@ ftxui::Component make_edit_choice_screen(AppState& state)
});

return Renderer(component, [&, inner, focusable, edit_container,
text_input, save_btn, cancel_btn] {
text_input, save_btn, cancel_btn, entry_boxes] {
inner->DetachAllChildren();
if (state.edit_choice_phase == 2)
inner->Add(edit_container);
Expand All @@ -101,13 +126,16 @@ ftxui::Component make_edit_choice_screen(AppState& state)

if (state.edit_choice_phase == 0)
{
int count = static_cast<int>(state.target_indices.size());
entry_boxes->resize(count);

body.push_back(text(""));
body.push_back(text(" Edit Choice ") | bold | center);
body.push_back(text(""));
body.push_back(separator() | color(Color::GrayDark));
body.push_back(text(""));

for (int i = 0; i < static_cast<int>(state.target_indices.size()); ++i)
for (int i = 0; i < count; ++i)
{
bool sel = (i == state.edit_choice_question_idx);
const auto& q = state.questions[state.target_indices[i]];
Expand All @@ -117,7 +145,7 @@ ftxui::Component make_edit_choice_screen(AppState& state)
text(q.question) | (sel ? bold : nothing),
});
if (sel) entry = entry | color(Color::Cyan) | focus;
body.push_back(entry);
body.push_back(entry | reflect((*entry_boxes)[i]));
}

body.push_back(text(""));
Expand All @@ -144,7 +172,9 @@ ftxui::Component make_edit_choice_screen(AppState& state)

body.push_back(text(""));

for (int i = 0; i < static_cast<int>(q.choices.size()); ++i)
int num_choices = static_cast<int>(q.choices.size());
entry_boxes->resize(num_choices);
for (int i = 0; i < num_choices; ++i)
{
bool sel = (i == state.edit_choice_choice_idx);
bool is_answer = (i == q.answer);
Expand All @@ -156,7 +186,7 @@ ftxui::Component make_edit_choice_screen(AppState& state)
});
if (sel) choice_el = choice_el | color(Color::Cyan) | focus;
else choice_el = choice_el | dim;
body.push_back(choice_el);
body.push_back(choice_el | reflect((*entry_boxes)[i]));
}

body.push_back(text(""));
Expand Down
17 changes: 13 additions & 4 deletions src/screens/list_questions.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "screens/list_questions.hpp"
#include "app.hpp"
#include "list_entry.hpp"
#include "nav.hpp"
#include "syntax.hpp"
#include <ftxui/component/component.hpp>
Expand All @@ -15,11 +16,16 @@ ftxui::Component make_list_questions_screen(AppState& state)
auto explain_toggle = Checkbox(" Explain", &state.list_show_explain);

auto controls = Container::Horizontal({answer_toggle, code_toggle, explain_toggle});
auto entry_boxes = make_entry_boxes();

auto component = Container::Vertical({controls});

component |= CatchEvent([&](Event event) {
component |= CatchEvent([&, entry_boxes](Event event) {
int count = static_cast<int>(state.target_indices.size());

int clicked = mouse_click_index(event, entry_boxes);
if (clicked >= 0) { state.list_selected = clicked; return true; }

if (nav_up_down(event, state.list_selected, count)) return true;
if (event == Event::Character('b') || event == Event::Escape)
{
Expand All @@ -29,9 +35,12 @@ ftxui::Component make_list_questions_screen(AppState& state)
return false;
});

return Renderer(component, [&, answer_toggle, code_toggle, explain_toggle] {
return Renderer(component, [&, answer_toggle, code_toggle, explain_toggle, entry_boxes] {
int count = static_cast<int>(state.target_indices.size());
entry_boxes->resize(count);

Elements list_entries;
for (int i = 0; i < static_cast<int>(state.target_indices.size()); ++i)
for (int i = 0; i < count; ++i)
{
bool selected = (i == state.list_selected);
const auto& q = state.questions[state.target_indices[i]];
Expand All @@ -47,7 +56,7 @@ ftxui::Component make_list_questions_screen(AppState& state)
: text(""),
});
if (selected) entry = entry | color(Color::Cyan) | focus;
list_entries.push_back(entry);
list_entries.push_back(entry | reflect((*entry_boxes)[i]));
}

auto list_panel = vbox(std::move(list_entries))
Expand Down
33 changes: 22 additions & 11 deletions src/screens/load_quiz.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "screens/load_quiz.hpp"
#include "app.hpp"
#include "list_entry.hpp"
#include "nav.hpp"
#include <ftxui/component/component.hpp>
#include <ftxui/component/event.hpp>
Expand Down Expand Up @@ -28,16 +29,28 @@ ftxui::Component make_load_quiz_screen(AppState& state)
auto action_row = Container::Horizontal({load_btn, done_btn});
auto input_area = Container::Vertical({path_input, action_row});
auto focusable = Renderer([](bool) { return text(""); });
auto entry_boxes = make_entry_boxes();

auto inner = Container::Vertical({});
auto tab = Container::Tab({focusable, input_area}, &state.load_screen_mode);

auto component = CatchEvent(inner, [&](Event event) {
auto component = CatchEvent(tab, [&, entry_boxes](Event event) {
if (event == Event::Escape)
{
state.return_to_menu();
return true;
}

if (!state.loaded_files.empty())
{
int clicked = mouse_click_index(event, entry_boxes);
if (clicked >= 0)
{
state.load_screen_mode = 0;
state.load_screen_selected = clicked;
return true;
}
}

if (event == Event::Tab)
{
if (!state.loaded_files.empty())
Expand Down Expand Up @@ -67,13 +80,9 @@ ftxui::Component make_load_quiz_screen(AppState& state)
return false;
});

return Renderer(component, [&, inner, focusable, input_area,
path_input, load_btn, done_btn] {
inner->DetachAllChildren();
if (state.load_screen_mode == 0 && !state.loaded_files.empty())
inner->Add(focusable);
else
inner->Add(input_area);
return Renderer(component, [&, path_input, load_btn, done_btn, entry_boxes] {
if (state.loaded_files.empty())
state.load_screen_mode = 1;

Elements body;
body.push_back(text(""));
Expand All @@ -87,7 +96,9 @@ ftxui::Component make_load_quiz_screen(AppState& state)
body.push_back(text(" Loaded files:") | dim);
body.push_back(text(""));

for (int i = 0; i < static_cast<int>(state.loaded_files.size()); ++i)
int file_count = static_cast<int>(state.loaded_files.size());
entry_boxes->resize(file_count);
for (int i = 0; i < file_count; ++i)
{
bool sel = (state.load_screen_mode == 0 && i == state.load_screen_selected);
const auto& lf = state.loaded_files[i];
Expand All @@ -104,7 +115,7 @@ ftxui::Component make_load_quiz_screen(AppState& state)
sel ? (text(" unload →") | color(Color::RedLight)) : text(""),
});
if (sel) entry = entry | color(Color::Cyan);
body.push_back(entry);
body.push_back(entry | reflect((*entry_boxes)[i]));
}

body.push_back(text(""));
Expand Down
Loading
Loading