<commit_before>/*
 * ParameterGroups.cpp
 *
 * Copyright (C) 2020 by Universitaet Stuttgart (VIS).
 * Alle Rechte vorbehalten.
 */

#include "stdafx.h"
#include "ParameterGroups.h"

using namespace megamol;
using namespace megamol::gui;

megamol::gui::ParameterGroups::ParameterGroups(void) : utils(), group_widget_ids(), button_tex_ids{0, 0, 0, 0} {

    // Add group widget data for animation
    GroupWidgetData animation;
    animation.active = false;
    animation.type.emplace(ParamType::BOOL, 1);
    animation.type.emplace(ParamType::BUTTON, 3);
    animation.type.emplace(ParamType::FLOAT, 2);
    animation.callback = [&, this](ParamPtrVectorType& params) { this->group_widget_animation(params); };
    group_widget_ids["animation"] = animation;
}

megamol::gui::ParameterGroups::~ParameterGroups(void) {}

bool megamol::gui::ParameterGroups::PresentGUI(megamol::gui::ParamVectorType& inout_params,
    const std::string& in_module_fullname, const std::string& in_search, bool in_extended, bool in_ignore_extended,
    megamol::gui::ParameterPresentation::WidgetScope in_scope,
    const std::shared_ptr<TransferFunctionEditor> in_external_tf_editor, bool& out_open_external_tf_editor) {

    out_open_external_tf_editor = false;

    // Nothing to do if there are no parameters
    if (inout_params.empty()) return true;

    if (in_scope == ParameterPresentation::WidgetScope::GLOBAL) {
        // GLOBAL

        for (auto& param : inout_params) {
            this->draw_parameter(
                param, in_module_fullname, in_search, in_scope, in_external_tf_editor, out_open_external_tf_editor);
        }
    } else {
        // LOCAL
        ImGui::BeginGroup();
        ImGui::Indent();

        ParamGroupType group_map;
        for (auto& param : inout_params) {
            auto param_namespace = param.GetNameSpace();

            if (!in_ignore_extended) {
                param.present.extended = in_extended;
            }

            if (!param_namespace.empty()) {
                // Sort parameters with namespace to group
                group_map[param_namespace].first.emplace_back(&param);
                group_map[param_namespace].second[param.type]++;
            } else {
                // Draw parameters without namespace at the beginning
                this->draw_parameter(
                    param, in_module_fullname, in_search, in_scope, in_external_tf_editor, out_open_external_tf_editor);
            }
        }

        // Draw grouped parameters
        for (auto& group : group_map) {
            auto group_name = group.first;
            bool found_group_widget = false;

            // Draw group widget
            for (auto& group_widget_id : this->group_widget_ids) {
                // Check for same group name and count of different parameter types
                /// TODO Is this check too expensive (also check group_name?) - Alternative?
                if (group_widget_id.second.type == group.second.second) {
                    found_group_widget = true;
                    group_widget_id.second.active = true;
                    this->draw_group(group_widget_id.first, group_widget_id.second, group.second.first, in_extended);
                }
            }

            // Draw grouped parameters with no custom group widget
            if (!found_group_widget) {

                // Skip if no parameter is visible and extended mode is unset
                bool visible = false;
                bool extended = false;
                for (auto& param : group.second.first) {
                    visible = visible || param->present.IsGUIVisible();
                    extended = extended || param->present.extended;
                }
                if (!visible && !extended) continue;

                // Open namespace header when parameter search is active
                if (!in_search.empty()) {
                    auto headerId = ImGui::GetID(group_name.c_str());
                    ImGui::GetStateStorage()->SetInt(headerId, 1);
                }
                if (ImGui::CollapsingHeader(group_name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
                    ImGui::Indent();
                    for (auto& param : group.second.first) {
                        this->draw_parameter((*param), in_module_fullname, in_search, in_scope, in_external_tf_editor,
                            out_open_external_tf_editor);
                    }
                    // Vertical spacing
                    /// ImGui::Dummy(ImVec2(1.0f, ImGui::GetFrameHeightWithSpacing()));
                    ImGui::Unindent();
                }
            }
        }

        // Vertical spacing
        /// ImGui::Dummy(ImVec2(1.0f, ImGui::GetFrameHeightWithSpacing()));
        ImGui::Unindent();
        ImGui::EndGroup();
    }
    return true;
}

bool megamol::gui::ParameterGroups::ParameterGroupGUIStateToJSON(
    nlohmann::json& inout_json, const std::string& module_fullname) {

    for (auto& group_widget_id : group_widget_ids) {
        if (group_widget_id.second.active) {
            std::string param_fullname = module_fullname + "::" + "PARAMGROUP_" + group_widget_id.first;

            group_widget_id.second.ParameterGUIStateToJSON(inout_json, param_fullname);
        }
    }

    return false;
}

bool megamol::gui::ParameterGroups::ParameterGroupGUIStateFromJSONString(
    const std::string& in_json_string, const std::string& module_fullname) {

    for (auto& group_widget_id : group_widget_ids) {
        std::string param_fullname = module_fullname + "::" + "PARAMGROUP_" + group_widget_id.first;

        if (group_widget_id.second.ParameterGUIStateFromJSONString(in_json_string, param_fullname)) {
            group_widget_id.second.active = true;
        }
    }

    return false;
}

void megamol::gui::ParameterGroups::draw_group(
    const std::string& in_group_name, GroupWidgetData& group_data, ParamPtrVectorType& input_params, bool in_extended) {

    ImGui::PushID(in_group_name.c_str());

    if (in_extended) {
        // Visibility
        bool visible = group_data.IsGUIVisible();
        if (ImGui::RadioButton("###visibile", visible)) {
            group_data.SetGUIVisible(!visible);
        }
        this->utils.HoverToolTip("Visibility", ImGui::GetItemID(), 0.5f);
        ImGui::SameLine();

        // Read-only option
        bool readonly = group_data.IsGUIReadOnly();
        if (ImGui::Checkbox("###readonly", &readonly)) {
            group_data.SetGUIReadOnly(readonly);
        }
        this->utils.HoverToolTip("Read-Only", ImGui::GetItemID(), 0.5f);
        ImGui::SameLine();

        ParameterPresentation::PointCircleButton("", (group_data.GetGUIPresentation() != PresentType::Basic));
        if (ImGui::BeginPopupContextItem("param_present_button_context", 0)) {
            for (auto& present_name_pair : group_data.GetPresentationNameMap()) {
                if (group_data.IsPresentationCompatible(present_name_pair.first)) {
                    if (ImGui::MenuItem(present_name_pair.second.c_str(), nullptr,
                            (present_name_pair.first == group_data.GetGUIPresentation()))) {
                        group_data.SetGUIPresentation(present_name_pair.first);
                    }
                }
            }
            ImGui::EndPopup();
        }
        this->utils.HoverToolTip("Presentation", ImGui::GetItemID(), 0.5f);
        ImGui::SameLine();
    }

    // Call group widget draw function
    if (group_data.IsGUIVisible() || in_extended) {

        if (group_data.IsGUIReadOnly()) {
            GUIUtils::ReadOnlyWigetStyle(true);
        }

        group_data.callback(input_params);

        if (group_data.IsGUIReadOnly()) {
            GUIUtils::ReadOnlyWigetStyle(false);
        }
    }

    ImGui::PopID();
}

void megamol::gui::ParameterGroups::draw_parameter(megamol::gui::Parameter& inout_param,
    const std::string& in_module_fullname, const std::string& in_search,
    megamol::gui::ParameterPresentation::WidgetScope in_scope,
    const std::shared_ptr<TransferFunctionEditor> in_external_tf_editor, bool& out_open_external_tf_editor) {

    if ((inout_param.type == ParamType::TRANSFERFUNCTION) && (in_external_tf_editor != nullptr)) {
        inout_param.present.ConnectExternalTransferFunctionEditor(in_external_tf_editor);
    }

    if (in_scope == ParameterPresentation::WidgetScope::GLOBAL) {
        // GLOBAL
        inout_param.PresentGUI(in_scope);
    } else {
        // LOCAL
        auto param_name = inout_param.full_name;
        bool param_searched = true;
        if (in_scope == ParameterPresentation::WidgetScope::LOCAL) {
            param_searched = megamol::gui::GUIUtils::FindCaseInsensitiveSubstring(param_name, in_search);
        }
        bool visible = (inout_param.present.IsGUIVisible() && param_searched) || inout_param.present.extended;

        if (visible) {
            if (inout_param.PresentGUI(in_scope)) {

                // Open window calling the transfer function editor callback
                if ((inout_param.type == ParamType::TRANSFERFUNCTION) && (in_external_tf_editor != nullptr)) {
                    out_open_external_tf_editor = true;
                    auto param_fullname = std::string(in_module_fullname.c_str()) + "::" + inout_param.full_name;
                    in_external_tf_editor->SetConnectedParameter(&inout_param, param_fullname);
                }
            }
        }
    }
}

void megamol::gui::ParameterGroups::group_widget_animation(ParamPtrVectorType& params) {

    // Check required parameters
    /// TODO Get specific parameters by name because of multiple same types
    Parameter* param_play = nullptr;
    Parameter* param_time = nullptr;
    Parameter* param_speed = nullptr;
    for (auto& param_ptr : params) {
        if ((param_ptr->GetName() == "play") && (param_ptr->type == ParamType::BOOL)) {
            param_play = param_ptr;
        }
        if ((param_ptr->GetName() == "time") && (param_ptr->type == ParamType::FLOAT)) {
            param_time = param_ptr;
        }
        if ((param_ptr->GetName() == "speed") && (param_ptr->type == ParamType::FLOAT)) {
            param_speed = param_ptr;
        }
    }
    if ((param_play == nullptr) || (param_time == nullptr) || (param_speed == nullptr)) {
        vislib::sys::Log::DefaultLog.WriteError(
            "Unable to find all required parameters by name for animation group widget. [%s, %s, line %d]\n", __FILE__,
            __FUNCTION__, __LINE__);
        return;
    }

    // Load button textures (once)
    if (this->button_tex_ids.play == 0) {
        megamol::gui::GUIUtils::LoadTexture("../share/resources/transport_ctrl_play.png", this->button_tex_ids.play);
    }
    if (this->button_tex_ids.pause == 0) {
        megamol::gui::GUIUtils::LoadTexture("../share/resources/transport_ctrl_pause.png", this->button_tex_ids.pause);
    }
    if (this->button_tex_ids.fastforward == 0) {
        megamol::gui::GUIUtils::LoadTexture(
            "../share/resources/transport_ctrl_fast-forward.png", this->button_tex_ids.fastforward);
    }
    if (this->button_tex_ids.fastrewind == 0) {
        megamol::gui::GUIUtils::LoadTexture(
            "../share/resources/transport_ctrl_fast-rewind.png", this->button_tex_ids.fastrewind);
    }
    if ((this->button_tex_ids.play == 0) || (this->button_tex_ids.pause == 0) ||
        (this->button_tex_ids.fastforward == 0) || (this->button_tex_ids.fastrewind == 0)) {
        vislib::sys::Log::DefaultLog.WriteError(
            "Unable to load all required button textures for animation group widget. [%s, %s, line %d]\n", __FILE__,
            __FUNCTION__, __LINE__);
        return;
    }

    // ------------------------------------------------------------------------
    ImGuiStyle& style = ImGui::GetStyle();

    float frame_height = ImGui::GetFrameHeightWithSpacing(); // ImGui::GetFrameHeight();

    float child_height = frame_height * 4.5f;
    auto child_flags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration;
    ImGui::BeginChild("group_widget_animation", ImVec2(0.0f, child_height), true, child_flags);

    ImGui::TextUnformatted("Animation");

    // Transport Buttons ------------------------------------------------------
    ImGui::PushStyleColor(ImGuiCol_Button, style.Colors[ImGuiCol_Button]);
    ImGui::PushStyleColor(ImGuiCol_ButtonHovered, style.Colors[ImGuiCol_ButtonActive]);
    ImGui::PushStyleColor(ImGuiCol_ButtonActive, style.Colors[ImGuiCol_ButtonHovered]);

    bool play = std::get<bool>(param_play->GetValue());
    float time = std::get<float>(param_time->GetValue());
    float speed = std::get<float>(param_speed->GetValue());
    std::string button_label;
    ImTextureID button_tex;

    /// PLAY - PAUSE
    button_label = "Play";
    button_tex = reinterpret_cast<ImTextureID>(this->button_tex_ids.play);
    if (play) {
        button_label = "Pause";
        button_tex = reinterpret_cast<ImTextureID>(this->button_tex_ids.pause);
    }

    if (ImGui::ImageButton(button_tex, ImVec2(frame_height, frame_height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), 1,
            style.Colors[ImGuiCol_Button], style.Colors[ImGuiCol_ButtonActive])) {
        play = !play;
    }
    this->utils.HoverToolTip(button_label, ImGui::GetItemID(), 1.0f, 5.0f);
    ImGui::SameLine();

    /// SLOWER
    button_label = "Slower";
    button_tex = reinterpret_cast<ImTextureID>(this->button_tex_ids.fastrewind);
    if (ImGui::ImageButton(button_tex, ImVec2(frame_height, frame_height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), 1,
            style.Colors[ImGuiCol_Button], style.Colors[ImGuiCol_ButtonActive])) {
        // play = true;
        speed /= 1.5f;
    }
    this->utils.HoverToolTip(button_label, ImGui::GetItemID(), 1.0f, 5.0f);
    ImGui::SameLine();

    /// FASTER
    button_label = "Faster";
    button_tex = reinterpret_cast<ImTextureID>(this->button_tex_ids.fastforward);
    if (ImGui::ImageButton(button_tex, ImVec2(frame_height, frame_height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), 1,
            style.Colors[ImGuiCol_Button], style.Colors[ImGuiCol_ButtonActive])) {
        // play = true;
        speed *= 1.5f;
    }
    this->utils.HoverToolTip(button_label, ImGui::GetItemID(), 1.0f, 5.0f);

    ImGui::PopStyleColor(3);

    param_play->SetValue(play);
    param_time->SetValue(time);
    param_speed->SetValue(speed);

    // Time -------------------------------------------------------------------

    param_time->PresentGUI(ParameterPresentation::WidgetScope::LOCAL);
    param_speed->PresentGUI(ParameterPresentation::WidgetScope::LOCAL);

    ImGui::EndChild();
}
<commit_msg>comment<commit_after>/*
 * ParameterGroups.cpp
 *
 * Copyright (C) 2020 by Universitaet Stuttgart (VIS).
 * Alle Rechte vorbehalten.
 */

/* HOWTO add your own parameter group:
 * 1] Add function drawing the new group widget: void group_widget_NEW-NAME(ParamPtrVectorType& params);
 * 2] Add group widget data in CTOR: GroupWidgetData NEW_NAME and add new function as callback
 */

#include "stdafx.h"
#include "ParameterGroups.h"

using namespace megamol;
using namespace megamol::gui;

megamol::gui::ParameterGroups::ParameterGroups(void) : utils(), group_widget_ids(), button_tex_ids{0, 0, 0, 0} {

    // Add group widget data for animation
    GroupWidgetData animation;
    animation.active = false;
    animation.type.emplace(ParamType::BOOL, 1);
    animation.type.emplace(ParamType::BUTTON, 3);
    animation.type.emplace(ParamType::FLOAT, 2);
    animation.callback = [&, this](ParamPtrVectorType& params) { this->group_widget_animation(params); };
    group_widget_ids["anim"] = animation;
}

megamol::gui::ParameterGroups::~ParameterGroups(void) {}

bool megamol::gui::ParameterGroups::PresentGUI(megamol::gui::ParamVectorType& inout_params,
    const std::string& in_module_fullname, const std::string& in_search, bool in_extended, bool in_ignore_extended,
    megamol::gui::ParameterPresentation::WidgetScope in_scope,
    const std::shared_ptr<TransferFunctionEditor> in_external_tf_editor, bool& out_open_external_tf_editor) {

    out_open_external_tf_editor = false;

    // Nothing to do if there are no parameters
    if (inout_params.empty()) return true;

    if (in_scope == ParameterPresentation::WidgetScope::GLOBAL) {
        // GLOBAL
        for (auto& param : inout_params) {
            this->draw_parameter(
                param, in_module_fullname, in_search, in_scope, in_external_tf_editor, out_open_external_tf_editor);
        }
    } else {
        // LOCAL
        ImGui::BeginGroup();
        ImGui::Indent();

        // Analyse parameter group membership and draw ungrouped parameters
        ParamGroupType group_map;
        for (auto& param : inout_params) {
            auto param_namespace = param.GetNameSpace();

            if (!in_ignore_extended) {
                param.present.extended = in_extended;
            }

            if (!param_namespace.empty()) {
                // Sort parameters with namespace to group
                group_map[param_namespace].first.emplace_back(&param);
                group_map[param_namespace].second[param.type]++;
            } else {
                // Draw parameters without namespace directly at the beginning
                this->draw_parameter(
                    param, in_module_fullname, in_search, in_scope, in_external_tf_editor, out_open_external_tf_editor);
            }
        }

        // Draw grouped parameters
        for (auto& group : group_map) {
            auto group_name = group.first;
            bool found_group_widget = false;

            // Draw group widget (if defined) ...
            for (auto& group_widget_id : this->group_widget_ids) {
                // Check for same group name and count of different parameter types
                /// TODO Is this check too expensive (remove check for group_name?) ...
                if ((group_widget_id.second.type == group.second.second) && (group_widget_id.first == group.first)) {
                    found_group_widget = true;
                    group_widget_id.second.active = true;
                    this->draw_group(group_widget_id.first, group_widget_id.second, group.second.first, in_extended);
                }
            }

            // ... else draw grouped parameters with no custom group widget using namespace header.
            if (!found_group_widget) {

                // Skip if no parameter is visible and extended mode is not set.
                bool visible = false;
                bool extended = false;
                for (auto& param : group.second.first) {
                    visible = visible || param->present.IsGUIVisible();
                    extended = extended || param->present.extended;
                }
                if (!visible && !extended) continue;

                // Open namespace header when parameter search is active.
                if (!in_search.empty()) {
                    auto headerId = ImGui::GetID(group_name.c_str());
                    ImGui::GetStateStorage()->SetInt(headerId, 1);
                }
                if (ImGui::CollapsingHeader(group_name.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
                    ImGui::Indent();
                    for (auto& param : group.second.first) {
                        this->draw_parameter((*param), in_module_fullname, in_search, in_scope, in_external_tf_editor,
                            out_open_external_tf_editor);
                    }
                    // Vertical spacing
                    /// ImGui::Dummy(ImVec2(1.0f, ImGui::GetFrameHeightWithSpacing()));
                    ImGui::Unindent();
                }
            }
        }

        // Vertical spacing
        /// ImGui::Dummy(ImVec2(1.0f, ImGui::GetFrameHeightWithSpacing()));
        ImGui::Unindent();
        ImGui::EndGroup();
    }
    return true;
}

bool megamol::gui::ParameterGroups::ParameterGroupGUIStateToJSON(
    nlohmann::json& inout_json, const std::string& module_fullname) {

    for (auto& group_widget_id : group_widget_ids) {
        if (group_widget_id.second.active) {
            std::string param_fullname = module_fullname + "::" + "PARAMGROUP_" + group_widget_id.first;

            group_widget_id.second.ParameterGUIStateToJSON(inout_json, param_fullname);
        }
    }

    return false;
}

bool megamol::gui::ParameterGroups::ParameterGroupGUIStateFromJSONString(
    const std::string& in_json_string, const std::string& module_fullname) {

    for (auto& group_widget_id : group_widget_ids) {
        std::string param_fullname = module_fullname + "::" + "PARAMGROUP_" + group_widget_id.first;

        if (group_widget_id.second.ParameterGUIStateFromJSONString(in_json_string, param_fullname)) {
            group_widget_id.second.active = true;
        }
    }

    return false;
}

void megamol::gui::ParameterGroups::draw_group(
    const std::string& in_group_name, GroupWidgetData& group_data, ParamPtrVectorType& input_params, bool in_extended) {

    ImGui::PushID(in_group_name.c_str());

    if (in_extended) {
        // Visibility
        bool visible = group_data.IsGUIVisible();
        if (ImGui::RadioButton("###visibile", visible)) {
            group_data.SetGUIVisible(!visible);
        }
        this->utils.HoverToolTip("Visibility", ImGui::GetItemID(), 0.5f);
        ImGui::SameLine();

        // Read-only option
        bool readonly = group_data.IsGUIReadOnly();
        if (ImGui::Checkbox("###readonly", &readonly)) {
            group_data.SetGUIReadOnly(readonly);
        }
        this->utils.HoverToolTip("Read-Only", ImGui::GetItemID(), 0.5f);
        ImGui::SameLine();

        ParameterPresentation::PointCircleButton("", (group_data.GetGUIPresentation() != PresentType::Basic));
        if (ImGui::BeginPopupContextItem("param_present_button_context", 0)) {
            for (auto& present_name_pair : group_data.GetPresentationNameMap()) {
                if (group_data.IsPresentationCompatible(present_name_pair.first)) {
                    if (ImGui::MenuItem(present_name_pair.second.c_str(), nullptr,
                            (present_name_pair.first == group_data.GetGUIPresentation()))) {
                        group_data.SetGUIPresentation(present_name_pair.first);
                    }
                }
            }
            ImGui::EndPopup();
        }
        this->utils.HoverToolTip("Presentation", ImGui::GetItemID(), 0.5f);
        ImGui::SameLine();
    }

    // Call group widget draw function
    if (group_data.IsGUIVisible() || in_extended) {

        if (group_data.IsGUIReadOnly()) {
            GUIUtils::ReadOnlyWigetStyle(true);
        }

        group_data.callback(input_params);

        if (group_data.IsGUIReadOnly()) {
            GUIUtils::ReadOnlyWigetStyle(false);
        }
    }

    ImGui::PopID();
}

void megamol::gui::ParameterGroups::draw_parameter(megamol::gui::Parameter& inout_param,
    const std::string& in_module_fullname, const std::string& in_search,
    megamol::gui::ParameterPresentation::WidgetScope in_scope,
    const std::shared_ptr<TransferFunctionEditor> in_external_tf_editor, bool& out_open_external_tf_editor) {

    if ((inout_param.type == ParamType::TRANSFERFUNCTION) && (in_external_tf_editor != nullptr)) {
        inout_param.present.ConnectExternalTransferFunctionEditor(in_external_tf_editor);
    }

    if (in_scope == ParameterPresentation::WidgetScope::GLOBAL) {
        // GLOBAL
        inout_param.PresentGUI(in_scope);
    } else {
        // LOCAL
        auto param_name = inout_param.full_name;
        bool param_searched = true;
        if (in_scope == ParameterPresentation::WidgetScope::LOCAL) {
            param_searched = megamol::gui::GUIUtils::FindCaseInsensitiveSubstring(param_name, in_search);
        }
        bool visible = (inout_param.present.IsGUIVisible() && param_searched) || inout_param.present.extended;

        if (visible) {
            if (inout_param.PresentGUI(in_scope)) {

                // Open window calling the transfer function editor callback
                if ((inout_param.type == ParamType::TRANSFERFUNCTION) && (in_external_tf_editor != nullptr)) {
                    out_open_external_tf_editor = true;
                    auto param_fullname = std::string(in_module_fullname.c_str()) + "::" + inout_param.full_name;
                    in_external_tf_editor->SetConnectedParameter(&inout_param, param_fullname);
                }
            }
        }
    }
}

void megamol::gui::ParameterGroups::group_widget_animation(ParamPtrVectorType& params) {

    // Check required parameters
    /// TODO Get specific parameters by name because of multiple same types
    Parameter* param_play = nullptr;
    Parameter* param_time = nullptr;
    Parameter* param_speed = nullptr;
    for (auto& param_ptr : params) {
        if ((param_ptr->GetName() == "play") && (param_ptr->type == ParamType::BOOL)) {
            param_play = param_ptr;
        }
        if ((param_ptr->GetName() == "time") && (param_ptr->type == ParamType::FLOAT)) {
            param_time = param_ptr;
        }
        if ((param_ptr->GetName() == "speed") && (param_ptr->type == ParamType::FLOAT)) {
            param_speed = param_ptr;
        }
    }
    if ((param_play == nullptr) || (param_time == nullptr) || (param_speed == nullptr)) {
        vislib::sys::Log::DefaultLog.WriteError(
            "Unable to find all required parameters by name for animation group widget. [%s, %s, line %d]\n", __FILE__,
            __FUNCTION__, __LINE__);
        return;
    }

    // Load button textures (once)
    if (this->button_tex_ids.play == 0) {
        megamol::gui::GUIUtils::LoadTexture("../share/resources/transport_ctrl_play.png", this->button_tex_ids.play);
    }
    if (this->button_tex_ids.pause == 0) {
        megamol::gui::GUIUtils::LoadTexture("../share/resources/transport_ctrl_pause.png", this->button_tex_ids.pause);
    }
    if (this->button_tex_ids.fastforward == 0) {
        megamol::gui::GUIUtils::LoadTexture(
            "../share/resources/transport_ctrl_fast-forward.png", this->button_tex_ids.fastforward);
    }
    if (this->button_tex_ids.fastrewind == 0) {
        megamol::gui::GUIUtils::LoadTexture(
            "../share/resources/transport_ctrl_fast-rewind.png", this->button_tex_ids.fastrewind);
    }
    if ((this->button_tex_ids.play == 0) || (this->button_tex_ids.pause == 0) ||
        (this->button_tex_ids.fastforward == 0) || (this->button_tex_ids.fastrewind == 0)) {
        vislib::sys::Log::DefaultLog.WriteError(
            "Unable to load all required button textures for animation group widget. [%s, %s, line %d]\n", __FILE__,
            __FUNCTION__, __LINE__);
        return;
    }

    // ------------------------------------------------------------------------
    ImGuiStyle& style = ImGui::GetStyle();
    float frame_height = ImGui::GetFrameHeightWithSpacing(); // ImGui::GetFrameHeight();
    float child_height = frame_height * 4.5f;
    auto child_flags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration;
    ImGui::BeginChild("group_widget_animation", ImVec2(0.0f, child_height), true, child_flags);

    // Caption
    ImGui::TextUnformatted("Animation");

    // Transport Buttons ------------------------------------------------------
    ImGui::PushStyleColor(ImGuiCol_Button, style.Colors[ImGuiCol_Button]);
    ImGui::PushStyleColor(ImGuiCol_ButtonHovered, style.Colors[ImGuiCol_ButtonActive]);
    ImGui::PushStyleColor(ImGuiCol_ButtonActive, style.Colors[ImGuiCol_ButtonHovered]);

    bool play = std::get<bool>(param_play->GetValue());
    float time = std::get<float>(param_time->GetValue());
    float speed = std::get<float>(param_speed->GetValue());
    std::string button_label;
    ImTextureID button_tex;

    /// PLAY - PAUSE
    button_label = "Play";
    button_tex = reinterpret_cast<ImTextureID>(this->button_tex_ids.play);
    if (play) {
        button_label = "Pause";
        button_tex = reinterpret_cast<ImTextureID>(this->button_tex_ids.pause);
    }

    if (ImGui::ImageButton(button_tex, ImVec2(frame_height, frame_height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), 1,
            style.Colors[ImGuiCol_Button], style.Colors[ImGuiCol_ButtonActive])) {
        play = !play;
    }
    this->utils.HoverToolTip(button_label, ImGui::GetItemID(), 1.0f, 5.0f);
    ImGui::SameLine();

    /// SLOWER
    button_label = "Slower";
    button_tex = reinterpret_cast<ImTextureID>(this->button_tex_ids.fastrewind);
    if (ImGui::ImageButton(button_tex, ImVec2(frame_height, frame_height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), 1,
            style.Colors[ImGuiCol_Button], style.Colors[ImGuiCol_ButtonActive])) {
        // play = true;
        speed /= 1.5f;
    }
    this->utils.HoverToolTip(button_label, ImGui::GetItemID(), 1.0f, 5.0f);
    ImGui::SameLine();

    /// FASTER
    button_label = "Faster";
    button_tex = reinterpret_cast<ImTextureID>(this->button_tex_ids.fastforward);
    if (ImGui::ImageButton(button_tex, ImVec2(frame_height, frame_height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), 1,
            style.Colors[ImGuiCol_Button], style.Colors[ImGuiCol_ButtonActive])) {
        // play = true;
        speed *= 1.5f;
    }
    this->utils.HoverToolTip(button_label, ImGui::GetItemID(), 1.0f, 5.0f);

    ImGui::PopStyleColor(3);

    param_play->SetValue(play);
    param_time->SetValue(time);
    param_speed->SetValue(speed);

    // Time -------------------------------------------------------------------

    param_time->PresentGUI(ParameterPresentation::WidgetScope::LOCAL);

    // Speed -------------------------------------------------------------------

    param_speed->PresentGUI(ParameterPresentation::WidgetScope::LOCAL);

    ImGui::EndChild();
}
<|endoftext|>


<commit_before>#include "runtime_internal.h"
#include "../buffer_t.h"
#include "HalideRuntime.h"
#include "device_interface.h"

extern "C" {

extern void *malloc(size_t);
extern void free(void *);

}

namespace Halide { namespace Runtime { namespace Internal {

struct device_handle_wrapper {
    uint64_t device_handle;
    const halide_device_interface *interface;
};

WEAK uint64_t new_device_wrapper(uint64_t handle, const struct halide_device_interface *interface) {
    // Using malloc instead of halide_malloc avoids alignment overhead.
    device_handle_wrapper *wrapper = (device_handle_wrapper *)malloc(sizeof(device_handle_wrapper));
    if (wrapper == NULL) {
        return 0;
    }
    wrapper->device_handle = handle;
    wrapper->interface = interface;
    return (uint64_t)wrapper;
}

WEAK void delete_device_wrapper(uint64_t wrapper) {
    free((device_handle_wrapper *)wrapper);
}

WEAK uint64_t get_device_handle(uint64_t dev_field) {
    const device_handle_wrapper *wrapper = (const device_handle_wrapper *)dev_field;
    if (wrapper == NULL) {
        return 0;
    }
    return wrapper->device_handle;
}

inline const halide_device_interface *get_device_interface(struct buffer_t *buf) {
    if (buf->dev == 0) {
        return NULL;
    }
    return ((device_handle_wrapper *)buf->dev)->interface;
}

}}} // namespace Halide::Runtime::Internal

extern "C" {

/** Release all data associated with the current GPU backend, in particular
 * all resources (memory, texture, context handles) allocated by Halide. Must
 * be called explicitly when using AOT compilation. */
void halide_device_release(void *user_context, const halide_device_interface *interface) {
    interface->device_release(user_context);
}

/** Copy image data from device memory to host memory. This must be called
 * explicitly to copy back the results of a GPU-based filter. */
int halide_copy_to_host(void *user_context, struct buffer_t *buf) {
    const halide_device_interface *interface = get_device_interface(buf);
    if (interface == NULL) {
        return 0;
    }
    return interface->copy_to_host(user_context, buf);
}

/** Copy image data from host memory to device memory. This should not be
 * called directly; Halide handles copying to the device automatically. */
int halide_copy_to_device(void *user_context, struct buffer_t *buf) {
    const halide_device_interface *interface = get_device_interface(buf);
    if (interface == NULL) {
        return 0;
    }
    return interface->copy_to_device(user_context, buf);
}

/** Wait for current GPU operations to complete. Calling this explicitly
 * should rarely be necessary, except maybe for profiling. */
int halide_device_sync(void *user_context, struct buffer_t *buf) {
    const halide_device_interface *interface = get_device_interface(buf);
    if (interface == NULL) {
        return 0;
    }
    return interface->device_sync(user_context, buf);
}

/** Allocate device memory to back a buffer_t. */
int halide_device_malloc(void *user_context, struct buffer_t *buf, const halide_device_interface *interface) {
    return interface->device_malloc(user_context, buf);
}

/** Free any device memory associated with a buffer_t. */
int halide_device_free(void *user_context, struct buffer_t *buf) {
    if (buf != NULL) {
        const halide_device_interface *interface = get_device_interface(buf);
        if (interface != NULL) {
            return interface->device_sync(user_context, buf);
        }
    }
    return 0;
}

} // extern "C" linkage
<commit_msg>Add debug code to device_wrapper.cpp<commit_after>#include "runtime_internal.h"
#include "../buffer_t.h"
#include "HalideRuntime.h"
#include "device_interface.h"

extern "C" {

extern void *malloc(size_t);
extern void free(void *);

}

namespace Halide { namespace Runtime { namespace Internal {

struct device_handle_wrapper {
    uint64_t device_handle;
    const halide_device_interface *interface;
};

WEAK uint64_t new_device_wrapper(uint64_t handle, const struct halide_device_interface *interface) {
    // Using malloc instead of halide_malloc avoids alignment overhead.
    device_handle_wrapper *wrapper = (device_handle_wrapper *)malloc(sizeof(device_handle_wrapper));
    if (wrapper == NULL) {
        return 0;
    }
    wrapper->device_handle = handle;
    wrapper->interface = interface;
    debug(NULL) << "Creating device wrapper for interface " << interface << " handle " << (void *)handle << " wrapper " << wrapper << "\n";
    return (uint64_t)wrapper;
}

WEAK void delete_device_wrapper(uint64_t wrapper) {
    device_handle_wrapper *wrapper_ptr = (device_handle_wrapper *)wrapper;
    debug(NULL) << "Deleting device wrapper for interface " << wrapper_ptr->interface << " device_handle " << (void *)wrapper_ptr->device_handle << " at addr " << wrapper_ptr << "\n";
    free(wrapper_ptr);
}

WEAK uint64_t get_device_handle(uint64_t dev_field) {
    const device_handle_wrapper *wrapper = (const device_handle_wrapper *)dev_field;
    if (wrapper == NULL) {
        debug(NULL) << "Getting device handle for NULL wrappe\n";
        return 0;
    }
    debug(NULL) << "Getting device handle for interface " << wrapper->interface << " device_handle " << (void *)wrapper->device_handle << " at addr " << wrapper << "\n";
    return wrapper->device_handle;
}

inline const halide_device_interface *get_device_interface(struct buffer_t *buf) {
    if (buf->dev == 0) {
        return NULL;
    }
    return ((device_handle_wrapper *)buf->dev)->interface;
}

}}} // namespace Halide::Runtime::Internal

extern "C" {

/** Release all data associated with the current GPU backend, in particular
 * all resources (memory, texture, context handles) allocated by Halide. Must
 * be called explicitly when using AOT compilation. */
void halide_device_release(void *user_context, const halide_device_interface *interface) {
    interface->device_release(user_context);
}

/** Copy image data from device memory to host memory. This must be called
 * explicitly to copy back the results of a GPU-based filter. */
int halide_copy_to_host(void *user_context, struct buffer_t *buf) {
    const halide_device_interface *interface = get_device_interface(buf);
    if (interface == NULL) {
        return 0;
    }
    return interface->copy_to_host(user_context, buf);
}

/** Copy image data from host memory to device memory. This should not be
 * called directly; Halide handles copying to the device automatically. */
int halide_copy_to_device(void *user_context, struct buffer_t *buf) {
    const halide_device_interface *interface = get_device_interface(buf);
    if (interface == NULL) {
        return 0;
    }
    return interface->copy_to_device(user_context, buf);
}

/** Wait for current GPU operations to complete. Calling this explicitly
 * should rarely be necessary, except maybe for profiling. */
int halide_device_sync(void *user_context, struct buffer_t *buf) {
    const halide_device_interface *interface = get_device_interface(buf);
    if (interface == NULL) {
        return 0;
    }
    return interface->device_sync(user_context, buf);
}

/** Allocate device memory to back a buffer_t. */
int halide_device_malloc(void *user_context, struct buffer_t *buf, const halide_device_interface *interface) {
    return interface->device_malloc(user_context, buf);
}

/** Free any device memory associated with a buffer_t. */
int halide_device_free(void *user_context, struct buffer_t *buf) {
    if (buf != NULL) {
        const halide_device_interface *interface = get_device_interface(buf);
        if (interface != NULL) {
            return interface->device_sync(user_context, buf);
        }
    }
    return 0;
}

} // extern "C" linkage
<|endoftext|>


<commit_before>/**
 * \file
 * \brief SemaphorePriorityTestCase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-19
 */

#include "SemaphorePriorityTestCase.hpp"

#include "priorityTestPhases.hpp"
#include "SequenceAsserter.hpp"

#include "distortos/StaticThread.hpp"
#include "distortos/ThisThread.hpp"
#include "distortos/statistics.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// pair of sequence points
using SequencePoints = std::pair<unsigned int, unsigned int>;

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// priority of current test thread - just above idle, lower than any value in priorityTestPhases array
constexpr uint8_t testThreadPriority {1};

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {256};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions' declarations
+---------------------------------------------------------------------------------------------------------------------*/

void thread(SequenceAsserter& sequenceAsserter, SequencePoints sequencePoints, Semaphore& semaphore);

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// type of test thread
using TestThread = decltype(makeStaticThread<testThreadStackSize>({}, thread,
		std::ref(std::declval<SequenceAsserter&>()), std::declval<SequencePoints>(),
		std::ref(std::declval<Semaphore&>())));

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Test thread.
 *
 * Marks the first sequence point in SequenceAsserter, waits for the semaphore and marks the last sequence point in
 * SequenceAsserter.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoints is a pair of sequence points for this instance
 * \param [in] semaphore is a reference to shared semaphore
 */

void thread(SequenceAsserter& sequenceAsserter, const SequencePoints sequencePoints, Semaphore& semaphore)
{
	sequenceAsserter.sequencePoint(sequencePoints.first);
	semaphore.wait();
	sequenceAsserter.sequencePoint(sequencePoints.second);
}

/**
 * \brief Builder of TestThread objects.
 *
 * \param [in] firstSequencePoint is the first sequence point for this instance - equal to the order in which this
 * thread will be started
 * \param [in] threadParameters is a reference to ThreadParameters object
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] semaphore is a reference to shared semaphore
 *
 * \return constructed TestThread object
 */

TestThread makeTestThread(const unsigned int firstSequencePoint, const ThreadParameters& threadParameters,
		SequenceAsserter& sequenceAsserter, Semaphore& semaphore)
{
	return makeStaticThread<testThreadStackSize>(threadParameters.first, thread, std::ref(sequenceAsserter),
			SequencePoints{firstSequencePoint, threadParameters.second + totalThreads}, std::ref(semaphore));
}

/**
 * \brief Runs the test case.
 *
 * \attention this function expects the priority of test thread to be testThreadPriority
 *
 * \return true if the test case succeeded, false otherwise
 */

bool testRunner()
{
	const auto contextSwitchCount = statistics::getContextSwitchCount();
	std::remove_const<decltype(contextSwitchCount)>::type expectedContextSwitchCount {};

	for (const auto& phase : priorityTestPhases)
	{
		SequenceAsserter sequenceAsserter;
		Semaphore semaphore {0};

		std::array<TestThread, totalThreads> threads
		{{
				makeTestThread(0, phase.first[phase.second[0]], sequenceAsserter, semaphore),
				makeTestThread(1, phase.first[phase.second[1]], sequenceAsserter, semaphore),
				makeTestThread(2, phase.first[phase.second[2]], sequenceAsserter, semaphore),
				makeTestThread(3, phase.first[phase.second[3]], sequenceAsserter, semaphore),
				makeTestThread(4, phase.first[phase.second[4]], sequenceAsserter, semaphore),
				makeTestThread(5, phase.first[phase.second[5]], sequenceAsserter, semaphore),
				makeTestThread(6, phase.first[phase.second[6]], sequenceAsserter, semaphore),
				makeTestThread(7, phase.first[phase.second[7]], sequenceAsserter, semaphore),
				makeTestThread(8, phase.first[phase.second[8]], sequenceAsserter, semaphore),
				makeTestThread(9, phase.first[phase.second[9]], sequenceAsserter, semaphore),
		}};

		bool result {true};

		for (auto& thread : threads)
		{
			thread.start();
			// 2 context switches: "into" the thread and "back" to main thread when test thread blocks on semaphore
			expectedContextSwitchCount += 2;
			if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
				result = false;
		}

		if (sequenceAsserter.assertSequence(totalThreads) == false || semaphore.getValue() != 0)
			result = false;

		for (size_t i = 0; i < threads.size(); ++i)
		{
			semaphore.post();
			// 2 context switches: into" the unblocked thread and "back" to main thread when test thread terminates
			expectedContextSwitchCount += 2;
			if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount ||
					semaphore.getValue() != 0)
				result = false;
		}

		for (auto& thread : threads)
			thread.join();

		if (result == false || sequenceAsserter.assertSequence(totalThreads * 2) == false || semaphore.getValue() != 0)
			return false;
	}

	if (statistics::getContextSwitchCount() - contextSwitchCount != 4 * totalThreads * priorityTestPhases.size())
		return false;

	return true;
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool SemaphorePriorityTestCase::Implementation::run_() const
{
	const auto thisThreadPriority = ThisThread::getPriority();
	ThisThread::setPriority(testThreadPriority);
	const auto ret = testRunner();
	ThisThread::setPriority(thisThreadPriority);
	return ret;
}

}	// namespace test

}	// namespace distortos
<commit_msg>test: move all code from local testRunner() to SemaphorePriorityTestCase::Implementation::run_() - priority is changed/restored in PrioritizedTestCase now<commit_after>/**
 * \file
 * \brief SemaphorePriorityTestCase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-19
 */

#include "SemaphorePriorityTestCase.hpp"

#include "priorityTestPhases.hpp"
#include "SequenceAsserter.hpp"

#include "distortos/StaticThread.hpp"
#include "distortos/statistics.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// pair of sequence points
using SequencePoints = std::pair<unsigned int, unsigned int>;

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {256};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions' declarations
+---------------------------------------------------------------------------------------------------------------------*/

void thread(SequenceAsserter& sequenceAsserter, SequencePoints sequencePoints, Semaphore& semaphore);

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// type of test thread
using TestThread = decltype(makeStaticThread<testThreadStackSize>({}, thread,
		std::ref(std::declval<SequenceAsserter&>()), std::declval<SequencePoints>(),
		std::ref(std::declval<Semaphore&>())));

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Test thread.
 *
 * Marks the first sequence point in SequenceAsserter, waits for the semaphore and marks the last sequence point in
 * SequenceAsserter.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoints is a pair of sequence points for this instance
 * \param [in] semaphore is a reference to shared semaphore
 */

void thread(SequenceAsserter& sequenceAsserter, const SequencePoints sequencePoints, Semaphore& semaphore)
{
	sequenceAsserter.sequencePoint(sequencePoints.first);
	semaphore.wait();
	sequenceAsserter.sequencePoint(sequencePoints.second);
}

/**
 * \brief Builder of TestThread objects.
 *
 * \param [in] firstSequencePoint is the first sequence point for this instance - equal to the order in which this
 * thread will be started
 * \param [in] threadParameters is a reference to ThreadParameters object
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] semaphore is a reference to shared semaphore
 *
 * \return constructed TestThread object
 */

TestThread makeTestThread(const unsigned int firstSequencePoint, const ThreadParameters& threadParameters,
		SequenceAsserter& sequenceAsserter, Semaphore& semaphore)
{
	return makeStaticThread<testThreadStackSize>(threadParameters.first, thread, std::ref(sequenceAsserter),
			SequencePoints{firstSequencePoint, threadParameters.second + totalThreads}, std::ref(semaphore));
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool SemaphorePriorityTestCase::Implementation::run_() const
{
	const auto contextSwitchCount = statistics::getContextSwitchCount();
	std::remove_const<decltype(contextSwitchCount)>::type expectedContextSwitchCount {};

	for (const auto& phase : priorityTestPhases)
	{
		SequenceAsserter sequenceAsserter;
		Semaphore semaphore {0};

		std::array<TestThread, totalThreads> threads
		{{
				makeTestThread(0, phase.first[phase.second[0]], sequenceAsserter, semaphore),
				makeTestThread(1, phase.first[phase.second[1]], sequenceAsserter, semaphore),
				makeTestThread(2, phase.first[phase.second[2]], sequenceAsserter, semaphore),
				makeTestThread(3, phase.first[phase.second[3]], sequenceAsserter, semaphore),
				makeTestThread(4, phase.first[phase.second[4]], sequenceAsserter, semaphore),
				makeTestThread(5, phase.first[phase.second[5]], sequenceAsserter, semaphore),
				makeTestThread(6, phase.first[phase.second[6]], sequenceAsserter, semaphore),
				makeTestThread(7, phase.first[phase.second[7]], sequenceAsserter, semaphore),
				makeTestThread(8, phase.first[phase.second[8]], sequenceAsserter, semaphore),
				makeTestThread(9, phase.first[phase.second[9]], sequenceAsserter, semaphore),
		}};

		bool result {true};

		for (auto& thread : threads)
		{
			thread.start();
			// 2 context switches: "into" the thread and "back" to main thread when test thread blocks on semaphore
			expectedContextSwitchCount += 2;
			if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount)
				result = false;
		}

		if (sequenceAsserter.assertSequence(totalThreads) == false || semaphore.getValue() != 0)
			result = false;

		for (size_t i = 0; i < threads.size(); ++i)
		{
			semaphore.post();
			// 2 context switches: into" the unblocked thread and "back" to main thread when test thread terminates
			expectedContextSwitchCount += 2;
			if (statistics::getContextSwitchCount() - contextSwitchCount != expectedContextSwitchCount ||
					semaphore.getValue() != 0)
				result = false;
		}

		for (auto& thread : threads)
			thread.join();

		if (result == false || sequenceAsserter.assertSequence(totalThreads * 2) == false || semaphore.getValue() != 0)
			return false;
	}

	if (statistics::getContextSwitchCount() - contextSwitchCount != 4 * totalThreads * priorityTestPhases.size())
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<|endoftext|>


<commit_before>#pragma once

#include "constants.hpp"
#include "filesystem.hpp"
#include "logger.hpp"
#include "session.hpp"
#include "types.hpp"
#include <fstream>
#include <json/json.hpp>
#include <natural_sort/natural_sort.hpp>
#include <string>
#include <unordered_map>

// Example: tests/src/core_configuration/json/example.json

namespace krbn {
class core_configuration final {
public:
#include "core_configuration/global_configuration.hpp"

  class profile final {
  public:
#include "core_configuration/profile/complex_modifications.hpp"
#include "core_configuration/profile/device.hpp"
#include "core_configuration/profile/simple_modifications.hpp"
#include "core_configuration/profile/virtual_hid_keyboard.hpp"

    profile(const nlohmann::json& json) : json_(json),
                                          selected_(false),
                                          simple_modifications_(json.find("simple_modifications") != json.end() ? json["simple_modifications"] : nlohmann::json()),
                                          fn_function_keys_(nlohmann::json({
                                              {"f1", "display_brightness_decrement"},
                                              {"f2", "display_brightness_increment"},
                                              {"f3", "mission_control"},
                                              {"f4", "launchpad"},
                                              {"f5", "illumination_decrement"},
                                              {"f6", "illumination_increment"},
                                              {"f7", "rewind"},
                                              {"f8", "play_or_pause"},
                                              {"f9", "fastforward"},
                                              {"f10", "mute"},
                                              {"f11", "volume_decrement"},
                                              {"f12", "volume_increment"},
                                          })),
                                          complex_modifications_(json.find("complex_modifications") != json.end() ? json["complex_modifications"] : nlohmann::json()),
                                          virtual_hid_keyboard_(json.find("virtual_hid_keyboard") != json.end() ? json["virtual_hid_keyboard"] : nlohmann::json()) {
      {
        const std::string key = "name";
        if (json.find(key) != json.end() && json[key].is_string()) {
          name_ = json[key];
        }
      }
      {
        const std::string key = "selected";
        if (json.find(key) != json.end() && json[key].is_boolean()) {
          selected_ = json[key];
        }
      }
      {
        const std::string key = "fn_function_keys";
        if (json.find(key) != json.end() && json[key].is_object()) {
          for (auto it = json[key].begin(); it != json[key].end(); ++it) {
            // it.key() is always std::string.
            if (it.value().is_string()) {
              fn_function_keys_.replace_second(it.key(), it.value());
            }
          }
        }
      }
      {
        const std::string key = "devices";
        if (json.find(key) != json.end() && json[key].is_array()) {
          for (const auto& device_json : json[key]) {
            devices_.emplace_back(device_json);
          }
        }
      }
    }

    nlohmann::json to_json(void) const {
      auto j = json_;
      j["name"] = name_;
      j["selected"] = selected_;
      j["simple_modifications"] = simple_modifications_;
      j["fn_function_keys"] = fn_function_keys_;
      j["complex_modifications"] = complex_modifications_;
      j["virtual_hid_keyboard"] = virtual_hid_keyboard_;
      j["devices"] = devices_;
      return j;
    }

    const std::string& get_name(void) const {
      return name_;
    }
    void set_name(const std::string& value) {
      name_ = value;
    }

    bool get_selected(void) const {
      return selected_;
    }
    void set_selected(bool value) {
      selected_ = value;
    }

    const std::vector<std::pair<std::string, std::string>>& get_simple_modifications(void) const {
      return simple_modifications_.get_pairs();
    }
    void push_back_simple_modification(void) {
      simple_modifications_.push_back_pair();
    }
    void erase_simple_modification(size_t index) {
      simple_modifications_.erase_pair(index);
    }
    void replace_simple_modification(size_t index, const std::string& from, const std::string& to) {
      simple_modifications_.replace_pair(index, from, to);
    }
    const std::unordered_map<key_code, key_code> get_simple_modifications_key_code_map(void) const {
      return simple_modifications_.to_key_code_map();
    }

    const std::vector<std::pair<std::string, std::string>>& get_fn_function_keys(void) const {
      return fn_function_keys_.get_pairs();
    }
    void replace_fn_function_key(const std::string& from, const std::string& to) {
      fn_function_keys_.replace_second(from, to);
    }
    const std::unordered_map<key_code, key_code> get_fn_function_keys_key_code_map(void) const {
      return fn_function_keys_.to_key_code_map();
    }

    const complex_modifications& get_complex_modifications(void) const {
      return complex_modifications_;
    }
    void push_back_complex_modifications_rule(const profile::complex_modifications::rule& rule) {
      complex_modifications_.push_back_rule(rule);
    }
    void erase_complex_modifications_rule(size_t index) {
      complex_modifications_.erase_rule(index);
    }
    void swap_complex_modifications_rules(size_t index1, size_t index2) {
      complex_modifications_.swap_rules(index1, index2);
    }

    const virtual_hid_keyboard& get_virtual_hid_keyboard(void) const {
      return virtual_hid_keyboard_;
    }
    virtual_hid_keyboard& get_virtual_hid_keyboard(void) {
      return virtual_hid_keyboard_;
    }

    const std::vector<device>& get_devices(void) const {
      return devices_;
    }
    bool get_device_ignore(const device::identifiers& identifiers) {
      for (const auto& d : devices_) {
        if (d.get_identifiers() == identifiers) {
          return d.get_ignore();
        }
      }
      return false;
    }
    void set_device_ignore(const device::identifiers& identifiers,
                           bool ignore) {
      for (auto&& device : devices_) {
        if (device.get_identifiers() == identifiers) {
          device.set_ignore(ignore);
          return;
        }
      }

      auto json = nlohmann::json({
          {"identifiers", identifiers.to_json()},
          {"ignore", ignore},
      });
      devices_.emplace_back(json);
    }
    bool get_device_disable_built_in_keyboard_if_exists(const device::identifiers& identifiers) {
      for (const auto& d : devices_) {
        if (d.get_identifiers() == identifiers) {
          return d.get_disable_built_in_keyboard_if_exists();
        }
      }
      return false;
    }
    void set_device_disable_built_in_keyboard_if_exists(const device::identifiers& identifiers,
                                                        bool disable_built_in_keyboard_if_exists) {
      for (auto&& device : devices_) {
        if (device.get_identifiers() == identifiers) {
          device.set_disable_built_in_keyboard_if_exists(disable_built_in_keyboard_if_exists);
          return;
        }
      }

      auto json = nlohmann::json({
          {"identifiers", identifiers.to_json()},
          {"disable_built_in_keyboard_if_exists", disable_built_in_keyboard_if_exists},
      });
      devices_.emplace_back(json);
    }

  private:
    nlohmann::json json_;
    std::string name_;
    bool selected_;
    simple_modifications simple_modifications_;
    simple_modifications fn_function_keys_;
    complex_modifications complex_modifications_;
    virtual_hid_keyboard virtual_hid_keyboard_;
    std::vector<device> devices_;
  };

  core_configuration(const core_configuration&) = delete;

  core_configuration(const std::string& file_path) : loaded_(true),
                                                     global_configuration_(nlohmann::json()) {
    bool valid_file_owner = false;

    // Load karabiner.json only when the owner is root or current session user.
    if (filesystem::exists(file_path)) {
      if (filesystem::is_owned(file_path, 0)) {
        valid_file_owner = true;
      } else {
        if (auto console_user_id = session::get_current_console_user_id()) {
          if (filesystem::is_owned(file_path, *console_user_id)) {
            valid_file_owner = true;
          }
        }
      }

      if (!valid_file_owner) {
        logger::get_logger().warn("{0} is not owned by a valid user.", file_path);
        loaded_ = false;

      } else {
        std::ifstream input(file_path);
        if (input) {
          try {
            json_ = nlohmann::json::parse(input);

            {
              const std::string key = "global";
              if (json_.find(key) != json_.end()) {
                global_configuration_ = global_configuration(json_[key]);
              }
            }
            {
              const std::string key = "profiles";
              if (json_.find(key) != json_.end() && json_[key].is_array()) {
                for (const auto& profile_json : json_[key]) {
                  profiles_.emplace_back(profile_json);
                }
              }
            }

          } catch (std::exception& e) {
            logger::get_logger().error("parse error in {0}: {1}", file_path, e.what());
            json_ = nlohmann::json();
            loaded_ = false;
          }
        }
      }
    }

    // Fallbacks
    if (profiles_.empty()) {
      profiles_.emplace_back(nlohmann::json({
          {"name", "Default profile"},
          {"selected", true},
      }));
    }
  }

  nlohmann::json to_json(void) const {
    auto j = json_;
    j["global"] = global_configuration_;
    j["profiles"] = profiles_;
    return j;
  }

  bool is_loaded(void) const { return loaded_; }

  const global_configuration& get_global_configuration(void) const {
    return global_configuration_;
  }
  global_configuration& get_global_configuration(void) {
    return global_configuration_;
  }

  const std::vector<profile>& get_profiles(void) const {
    return profiles_;
  }
  void set_profile_name(size_t index, const std::string name) {
    if (index < profiles_.size()) {
      profiles_[index].set_name(name);
    }
  }
  void select_profile(size_t index) {
    if (index < profiles_.size()) {
      for (size_t i = 0; i < profiles_.size(); ++i) {
        if (i == index) {
          profiles_[i].set_selected(true);
        } else {
          profiles_[i].set_selected(false);
        }
      }
    }
  }
  void push_back_profile(void) {
    profiles_.emplace_back(nlohmann::json({
        {"name", "New profile"},
    }));
  }
  void erase_profile(size_t index) {
    if (index < profiles_.size()) {
      if (profiles_.size() > 1) {
        profiles_.erase(profiles_.begin() + index);
      }
    }
  }

  profile& get_selected_profile(void) {
    for (auto&& profile : profiles_) {
      if (profile.get_selected()) {
        return profile;
      }
    }
    return profiles_[0];
  }

  // Note:
  // Be careful calling `save` method.
  // If the configuration file is corrupted temporarily (user editing the configuration file in editor),
  // the user data will be lost by the `save` method.
  // Thus, we should call the `save` method only when it is neccessary.

  bool save_to_file(const std::string& file_path) {
    filesystem::create_directory_with_intermediate_directories(filesystem::dirname(file_path), 0700);

    std::ofstream output(file_path);
    if (!output) {
      return false;
    }

    output << std::setw(4) << to_json() << std::endl;
    return true;
  }

private:
  nlohmann::json json_;
  bool loaded_;

  global_configuration global_configuration_;
  std::vector<profile> profiles_;
};

inline void to_json(nlohmann::json& json, const core_configuration::global_configuration& global_configuration) {
  json = global_configuration.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile& profile) {
  json = profile.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::simple_modifications& simple_modifications) {
  json = simple_modifications.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::complex_modifications& complex_modifications) {
  json = complex_modifications.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::complex_modifications::rule& rule) {
  json = rule.get_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::virtual_hid_keyboard& virtual_hid_keyboard) {
  json = virtual_hid_keyboard.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::device::identifiers& identifiers) {
  json = identifiers.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::device& device) {
  json = device.to_json();
}
} // namespace krbn
<commit_msg>add set_complex_modifications_parameter<commit_after>#pragma once

#include "constants.hpp"
#include "filesystem.hpp"
#include "logger.hpp"
#include "session.hpp"
#include "types.hpp"
#include <fstream>
#include <json/json.hpp>
#include <natural_sort/natural_sort.hpp>
#include <string>
#include <unordered_map>

// Example: tests/src/core_configuration/json/example.json

namespace krbn {
class core_configuration final {
public:
#include "core_configuration/global_configuration.hpp"

  class profile final {
  public:
#include "core_configuration/profile/complex_modifications.hpp"
#include "core_configuration/profile/device.hpp"
#include "core_configuration/profile/simple_modifications.hpp"
#include "core_configuration/profile/virtual_hid_keyboard.hpp"

    profile(const nlohmann::json& json) : json_(json),
                                          selected_(false),
                                          simple_modifications_(json.find("simple_modifications") != json.end() ? json["simple_modifications"] : nlohmann::json()),
                                          fn_function_keys_(nlohmann::json({
                                              {"f1", "display_brightness_decrement"},
                                              {"f2", "display_brightness_increment"},
                                              {"f3", "mission_control"},
                                              {"f4", "launchpad"},
                                              {"f5", "illumination_decrement"},
                                              {"f6", "illumination_increment"},
                                              {"f7", "rewind"},
                                              {"f8", "play_or_pause"},
                                              {"f9", "fastforward"},
                                              {"f10", "mute"},
                                              {"f11", "volume_decrement"},
                                              {"f12", "volume_increment"},
                                          })),
                                          complex_modifications_(json.find("complex_modifications") != json.end() ? json["complex_modifications"] : nlohmann::json()),
                                          virtual_hid_keyboard_(json.find("virtual_hid_keyboard") != json.end() ? json["virtual_hid_keyboard"] : nlohmann::json()) {
      {
        const std::string key = "name";
        if (json.find(key) != json.end() && json[key].is_string()) {
          name_ = json[key];
        }
      }
      {
        const std::string key = "selected";
        if (json.find(key) != json.end() && json[key].is_boolean()) {
          selected_ = json[key];
        }
      }
      {
        const std::string key = "fn_function_keys";
        if (json.find(key) != json.end() && json[key].is_object()) {
          for (auto it = json[key].begin(); it != json[key].end(); ++it) {
            // it.key() is always std::string.
            if (it.value().is_string()) {
              fn_function_keys_.replace_second(it.key(), it.value());
            }
          }
        }
      }
      {
        const std::string key = "devices";
        if (json.find(key) != json.end() && json[key].is_array()) {
          for (const auto& device_json : json[key]) {
            devices_.emplace_back(device_json);
          }
        }
      }
    }

    nlohmann::json to_json(void) const {
      auto j = json_;
      j["name"] = name_;
      j["selected"] = selected_;
      j["simple_modifications"] = simple_modifications_;
      j["fn_function_keys"] = fn_function_keys_;
      j["complex_modifications"] = complex_modifications_;
      j["virtual_hid_keyboard"] = virtual_hid_keyboard_;
      j["devices"] = devices_;
      return j;
    }

    const std::string& get_name(void) const {
      return name_;
    }
    void set_name(const std::string& value) {
      name_ = value;
    }

    bool get_selected(void) const {
      return selected_;
    }
    void set_selected(bool value) {
      selected_ = value;
    }

    const std::vector<std::pair<std::string, std::string>>& get_simple_modifications(void) const {
      return simple_modifications_.get_pairs();
    }
    void push_back_simple_modification(void) {
      simple_modifications_.push_back_pair();
    }
    void erase_simple_modification(size_t index) {
      simple_modifications_.erase_pair(index);
    }
    void replace_simple_modification(size_t index, const std::string& from, const std::string& to) {
      simple_modifications_.replace_pair(index, from, to);
    }
    const std::unordered_map<key_code, key_code> get_simple_modifications_key_code_map(void) const {
      return simple_modifications_.to_key_code_map();
    }

    const std::vector<std::pair<std::string, std::string>>& get_fn_function_keys(void) const {
      return fn_function_keys_.get_pairs();
    }
    void replace_fn_function_key(const std::string& from, const std::string& to) {
      fn_function_keys_.replace_second(from, to);
    }
    const std::unordered_map<key_code, key_code> get_fn_function_keys_key_code_map(void) const {
      return fn_function_keys_.to_key_code_map();
    }

    const complex_modifications& get_complex_modifications(void) const {
      return complex_modifications_;
    }
    void push_back_complex_modifications_rule(const profile::complex_modifications::rule& rule) {
      complex_modifications_.push_back_rule(rule);
    }
    void erase_complex_modifications_rule(size_t index) {
      complex_modifications_.erase_rule(index);
    }
    void swap_complex_modifications_rules(size_t index1, size_t index2) {
      complex_modifications_.swap_rules(index1, index2);
    }
    void set_complex_modifications_parameter(const std::string& name, int value) {
      complex_modifications_.set_parameter_value(name, value);
    }

    const virtual_hid_keyboard& get_virtual_hid_keyboard(void) const {
      return virtual_hid_keyboard_;
    }
    virtual_hid_keyboard& get_virtual_hid_keyboard(void) {
      return virtual_hid_keyboard_;
    }

    const std::vector<device>& get_devices(void) const {
      return devices_;
    }
    bool get_device_ignore(const device::identifiers& identifiers) {
      for (const auto& d : devices_) {
        if (d.get_identifiers() == identifiers) {
          return d.get_ignore();
        }
      }
      return false;
    }
    void set_device_ignore(const device::identifiers& identifiers,
                           bool ignore) {
      for (auto&& device : devices_) {
        if (device.get_identifiers() == identifiers) {
          device.set_ignore(ignore);
          return;
        }
      }

      auto json = nlohmann::json({
          {"identifiers", identifiers.to_json()},
          {"ignore", ignore},
      });
      devices_.emplace_back(json);
    }
    bool get_device_disable_built_in_keyboard_if_exists(const device::identifiers& identifiers) {
      for (const auto& d : devices_) {
        if (d.get_identifiers() == identifiers) {
          return d.get_disable_built_in_keyboard_if_exists();
        }
      }
      return false;
    }
    void set_device_disable_built_in_keyboard_if_exists(const device::identifiers& identifiers,
                                                        bool disable_built_in_keyboard_if_exists) {
      for (auto&& device : devices_) {
        if (device.get_identifiers() == identifiers) {
          device.set_disable_built_in_keyboard_if_exists(disable_built_in_keyboard_if_exists);
          return;
        }
      }

      auto json = nlohmann::json({
          {"identifiers", identifiers.to_json()},
          {"disable_built_in_keyboard_if_exists", disable_built_in_keyboard_if_exists},
      });
      devices_.emplace_back(json);
    }

  private:
    nlohmann::json json_;
    std::string name_;
    bool selected_;
    simple_modifications simple_modifications_;
    simple_modifications fn_function_keys_;
    complex_modifications complex_modifications_;
    virtual_hid_keyboard virtual_hid_keyboard_;
    std::vector<device> devices_;
  };

  core_configuration(const core_configuration&) = delete;

  core_configuration(const std::string& file_path) : loaded_(true),
                                                     global_configuration_(nlohmann::json()) {
    bool valid_file_owner = false;

    // Load karabiner.json only when the owner is root or current session user.
    if (filesystem::exists(file_path)) {
      if (filesystem::is_owned(file_path, 0)) {
        valid_file_owner = true;
      } else {
        if (auto console_user_id = session::get_current_console_user_id()) {
          if (filesystem::is_owned(file_path, *console_user_id)) {
            valid_file_owner = true;
          }
        }
      }

      if (!valid_file_owner) {
        logger::get_logger().warn("{0} is not owned by a valid user.", file_path);
        loaded_ = false;

      } else {
        std::ifstream input(file_path);
        if (input) {
          try {
            json_ = nlohmann::json::parse(input);

            {
              const std::string key = "global";
              if (json_.find(key) != json_.end()) {
                global_configuration_ = global_configuration(json_[key]);
              }
            }
            {
              const std::string key = "profiles";
              if (json_.find(key) != json_.end() && json_[key].is_array()) {
                for (const auto& profile_json : json_[key]) {
                  profiles_.emplace_back(profile_json);
                }
              }
            }

          } catch (std::exception& e) {
            logger::get_logger().error("parse error in {0}: {1}", file_path, e.what());
            json_ = nlohmann::json();
            loaded_ = false;
          }
        }
      }
    }

    // Fallbacks
    if (profiles_.empty()) {
      profiles_.emplace_back(nlohmann::json({
          {"name", "Default profile"},
          {"selected", true},
      }));
    }
  }

  nlohmann::json to_json(void) const {
    auto j = json_;
    j["global"] = global_configuration_;
    j["profiles"] = profiles_;
    return j;
  }

  bool is_loaded(void) const { return loaded_; }

  const global_configuration& get_global_configuration(void) const {
    return global_configuration_;
  }
  global_configuration& get_global_configuration(void) {
    return global_configuration_;
  }

  const std::vector<profile>& get_profiles(void) const {
    return profiles_;
  }
  void set_profile_name(size_t index, const std::string name) {
    if (index < profiles_.size()) {
      profiles_[index].set_name(name);
    }
  }
  void select_profile(size_t index) {
    if (index < profiles_.size()) {
      for (size_t i = 0; i < profiles_.size(); ++i) {
        if (i == index) {
          profiles_[i].set_selected(true);
        } else {
          profiles_[i].set_selected(false);
        }
      }
    }
  }
  void push_back_profile(void) {
    profiles_.emplace_back(nlohmann::json({
        {"name", "New profile"},
    }));
  }
  void erase_profile(size_t index) {
    if (index < profiles_.size()) {
      if (profiles_.size() > 1) {
        profiles_.erase(profiles_.begin() + index);
      }
    }
  }

  profile& get_selected_profile(void) {
    for (auto&& profile : profiles_) {
      if (profile.get_selected()) {
        return profile;
      }
    }
    return profiles_[0];
  }

  // Note:
  // Be careful calling `save` method.
  // If the configuration file is corrupted temporarily (user editing the configuration file in editor),
  // the user data will be lost by the `save` method.
  // Thus, we should call the `save` method only when it is neccessary.

  bool save_to_file(const std::string& file_path) {
    filesystem::create_directory_with_intermediate_directories(filesystem::dirname(file_path), 0700);

    std::ofstream output(file_path);
    if (!output) {
      return false;
    }

    output << std::setw(4) << to_json() << std::endl;
    return true;
  }

private:
  nlohmann::json json_;
  bool loaded_;

  global_configuration global_configuration_;
  std::vector<profile> profiles_;
};

inline void to_json(nlohmann::json& json, const core_configuration::global_configuration& global_configuration) {
  json = global_configuration.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile& profile) {
  json = profile.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::simple_modifications& simple_modifications) {
  json = simple_modifications.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::complex_modifications& complex_modifications) {
  json = complex_modifications.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::complex_modifications::rule& rule) {
  json = rule.get_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::complex_modifications::parameters& parameters) {
  json = parameters.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::virtual_hid_keyboard& virtual_hid_keyboard) {
  json = virtual_hid_keyboard.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::device::identifiers& identifiers) {
  json = identifiers.to_json();
}

inline void to_json(nlohmann::json& json, const core_configuration::profile::device& device) {
  json = device.to_json();
}
} // namespace krbn
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "topicchooser.h"

#include <QMap>
#include <QUrl>

#include <QKeyEvent>
#include <QStandardItemModel>
#include <QSortFilterProxyModel>

TopicChooser::TopicChooser(QWidget *parent, const QString &keyword,
        const QMap<QString, QUrl> &links)
    : QDialog(parent)
    , m_filterModel(new QSortFilterProxyModel(this))
{
    ui.setupUi(this);

    setFocusProxy(ui.lineEdit);
    ui.lineEdit->installEventFilter(this);
    ui.lineEdit->setPlaceholderText(tr("Filter"));
    ui.label->setText(tr("Choose a topic for %1:").arg(keyword));

    QStandardItemModel *model = new QStandardItemModel(this);
    m_filterModel->setSourceModel(model);
    m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);

    QMap<QString, QUrl>::const_iterator it = links.constBegin();
    for (; it != links.constEnd(); ++it) {
        m_links.append(it.value());
        QStandardItem *item = new QStandardItem(it.key());
        item->setToolTip(it.value().toString());
        model->appendRow(item);
    }

    ui.listWidget->setModel(m_filterModel);
    ui.listWidget->setUniformItemSizes(true);
    ui.listWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);

    if (m_filterModel->rowCount() != 0)
        ui.listWidget->setCurrentIndex(m_filterModel->index(0, 0));

    connect(ui.buttonDisplay, SIGNAL(clicked()), this, SLOT(acceptDialog()));
    connect(ui.buttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
    connect(ui.listWidget, SIGNAL(activated(QModelIndex)), this,
        SLOT(activated(QModelIndex)));
    connect(ui.lineEdit, SIGNAL(filterChanged(QString)), this,
        SLOT(setFilter(QString)));
}

QUrl TopicChooser::link() const
{
    if (m_activedIndex.isValid())
        return m_links.at(m_filterModel->mapToSource(m_activedIndex).row());
    return QUrl();
}

void TopicChooser::acceptDialog()
{
    m_activedIndex = ui.listWidget->currentIndex();
    accept();
}

void TopicChooser::setFilter(const QString &pattern)
{
    m_filterModel->setFilterFixedString(pattern);
    if (m_filterModel->rowCount() != 0 && !ui.listWidget->currentIndex().isValid())
        ui.listWidget->setCurrentIndex(m_filterModel->index(0, 0));
}

void TopicChooser::activated(const QModelIndex &index)
{
    m_activedIndex = index;
    accept();
}

bool TopicChooser::eventFilter(QObject *object, QEvent *event)
{
    if (object == ui.lineEdit && event->type() == QEvent::KeyPress) {
        QModelIndex idx = ui.listWidget->currentIndex();
        switch ((static_cast<QKeyEvent*>(event)->key())) {
            case Qt::Key_Up:
                idx = m_filterModel->index(idx.row() - 1, idx.column(),
                    idx.parent());
                if (idx.isValid())
                    ui.listWidget->setCurrentIndex(idx);
                break;

            case Qt::Key_Down:
                idx = m_filterModel->index(idx.row() + 1, idx.column(),
                    idx.parent());
                if (idx.isValid())
                    ui.listWidget->setCurrentIndex(idx);
                break;

            default: ;
        }
    } else if (ui.lineEdit && event->type() == QEvent::FocusIn
        && static_cast<QFocusEvent *>(event)->reason() != Qt::MouseFocusReason) {
        ui.lineEdit->selectAll();
        ui.lineEdit->setFocus();
    }
    return QDialog::eventFilter(object, event);
}
<commit_msg>Help: Add page up/down handling to topic chooser<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "topicchooser.h"

#include <QMap>
#include <QUrl>

#include <QKeyEvent>
#include <QStandardItemModel>
#include <QSortFilterProxyModel>

TopicChooser::TopicChooser(QWidget *parent, const QString &keyword,
        const QMap<QString, QUrl> &links)
    : QDialog(parent)
    , m_filterModel(new QSortFilterProxyModel(this))
{
    ui.setupUi(this);

    setFocusProxy(ui.lineEdit);
    ui.lineEdit->installEventFilter(this);
    ui.lineEdit->setPlaceholderText(tr("Filter"));
    ui.label->setText(tr("Choose a topic for %1:").arg(keyword));

    QStandardItemModel *model = new QStandardItemModel(this);
    m_filterModel->setSourceModel(model);
    m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);

    QMap<QString, QUrl>::const_iterator it = links.constBegin();
    for (; it != links.constEnd(); ++it) {
        m_links.append(it.value());
        QStandardItem *item = new QStandardItem(it.key());
        item->setToolTip(it.value().toString());
        model->appendRow(item);
    }

    ui.listWidget->setModel(m_filterModel);
    ui.listWidget->setUniformItemSizes(true);
    ui.listWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);

    if (m_filterModel->rowCount() != 0)
        ui.listWidget->setCurrentIndex(m_filterModel->index(0, 0));

    connect(ui.buttonDisplay, SIGNAL(clicked()), this, SLOT(acceptDialog()));
    connect(ui.buttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
    connect(ui.listWidget, SIGNAL(activated(QModelIndex)), this,
        SLOT(activated(QModelIndex)));
    connect(ui.lineEdit, SIGNAL(filterChanged(QString)), this,
        SLOT(setFilter(QString)));
}

QUrl TopicChooser::link() const
{
    if (m_activedIndex.isValid())
        return m_links.at(m_filterModel->mapToSource(m_activedIndex).row());
    return QUrl();
}

void TopicChooser::acceptDialog()
{
    m_activedIndex = ui.listWidget->currentIndex();
    accept();
}

void TopicChooser::setFilter(const QString &pattern)
{
    m_filterModel->setFilterFixedString(pattern);
    if (m_filterModel->rowCount() != 0 && !ui.listWidget->currentIndex().isValid())
        ui.listWidget->setCurrentIndex(m_filterModel->index(0, 0));
}

void TopicChooser::activated(const QModelIndex &index)
{
    m_activedIndex = index;
    accept();
}

bool TopicChooser::eventFilter(QObject *object, QEvent *event)
{
    if (object == ui.lineEdit && event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent*>(event);
        int dIndex = 0;
        switch (ke->key()) {
        case Qt::Key_Up:
            dIndex = -1;
            break;
        case Qt::Key_Down:
            dIndex = +1;
            break;
        case Qt::Key_PageUp:
            dIndex = -5;
            break;
        case Qt::Key_PageDown:
            dIndex = +5;
            break;
        default:
            break;
        }
        if (dIndex != 0) {
            QModelIndex idx = ui.listWidget->currentIndex();
            int newIndex = qMin(m_filterModel->rowCount(idx.parent()) - 1,
                                qMax(0, idx.row() + dIndex));
            idx = m_filterModel->index(newIndex, idx.column(), idx.parent());
            if (idx.isValid())
                ui.listWidget->setCurrentIndex(idx);
            return true;
        }
    } else if (ui.lineEdit && event->type() == QEvent::FocusIn
        && static_cast<QFocusEvent *>(event)->reason() != Qt::MouseFocusReason) {
        ui.lineEdit->selectAll();
        ui.lineEdit->setFocus();
    }
    return QDialog::eventFilter(object, event);
}
<|endoftext|>


<commit_before>#include "tagha.h"

CTagha::CTagha(void *script)
{
	Tagha_Init((struct Tagha *)this, script);
}

CTagha::CTagha(void *script, const struct CNativeInfo natives[])
{
	Tagha_Init((struct Tagha *)this, script);
	Tagha_RegisterNatives((struct Tagha *)this, (const struct NativeInfo *)natives);
}
CTagha::~CTagha()
{

}

bool CTagha::RegisterNatives(const struct CNativeInfo natives[])
{
	return Tagha_RegisterNatives((struct Tagha *)this, (const struct NativeInfo *)natives);
}
void *CTagha::GetGlobalVarByName(const char *varname)
{
	return Tagha_GetGlobalVarByName((struct Tagha *)this, varname);
}

int32_t CTagha::CallFunc(const char *funcname, const size_t args, union TaghaVal params[])
{
	return Tagha_CallFunc((struct Tagha *)this, funcname, args, params);
}

union TaghaVal CTagha::GetReturnValue()
{
	return Tagha_GetReturnValue((struct Tagha *)this);
}

int32_t CTagha::RunScript(int32_t argc, char *argv[])
{
	return Tagha_RunScript((struct Tagha *)this, argc, argv);
}

/////////////////////////////////////////////////////////////////////////////////
<commit_msg>Implementing GetError and PrintVMState for C++ interface<commit_after>#include "tagha.h"

CTagha::CTagha(void *script)
{
	Tagha_Init((struct Tagha *)this, script);
}

CTagha::CTagha(void *script, const struct CNativeInfo natives[])
{
	Tagha_Init((struct Tagha *)this, script);
	Tagha_RegisterNatives((struct Tagha *)this, (const struct NativeInfo *)natives);
}
CTagha::~CTagha()
{

}

bool CTagha::RegisterNatives(const struct CNativeInfo natives[])
{
	return Tagha_RegisterNatives((struct Tagha *)this, (const struct NativeInfo *)natives);
}
void *CTagha::GetGlobalVarByName(const char *varname)
{
	return Tagha_GetGlobalVarByName((struct Tagha *)this, varname);
}

int32_t CTagha::CallFunc(const char *funcname, const size_t args, union TaghaVal params[])
{
	return Tagha_CallFunc((struct Tagha *)this, funcname, args, params);
}

union TaghaVal CTagha::GetReturnValue()
{
	return Tagha_GetReturnValue((struct Tagha *)this);
}

int32_t CTagha::RunScript(int32_t argc, char *argv[])
{
	return Tagha_RunScript((struct Tagha *)this, argc, argv);
}

const char *CTagha::GetError()
{
	return Tagha_GetError((struct Tagha *)this);
}

void CTagha::PrintVMState()
{
	Tagha_PrintVMState((struct Tagha *)this);
}

/////////////////////////////////////////////////////////////////////////////////
<|endoftext|>