Version initiale du logiciel. Développement commencé le 06/01/2026, en reprenant certaines parties/idées de miniDart, que j'ai écrit quelques années plus tôt
Cette révision appartient à :
275
imgui_utils.cxx
Fichier normal
275
imgui_utils.cxx
Fichier normal
@@ -0,0 +1,275 @@
|
||||
/* ImGui utils */
|
||||
|
||||
/* Fichier contenant quelques fonctionnalités basées sur ImGui :
|
||||
* VToggleButton() dérivé de ToggleButton
|
||||
* DrawVToggleButton
|
||||
*
|
||||
* Copyright Eric Bachard 2026/01/14 18h20
|
||||
* License GPL v2
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#endif
|
||||
|
||||
#include "digital_modulation_fr.hpp"
|
||||
#include "imgui.h"
|
||||
#include "vtoggle_button.h"
|
||||
#include "imgui_utils.h"
|
||||
#include "imgui_themes.h"
|
||||
|
||||
#ifdef M_PI
|
||||
#undef M_PI
|
||||
#define M_PI 3.14159265358979323846f
|
||||
#endif
|
||||
|
||||
void selectThemeMenu(Application * p_app)
|
||||
{
|
||||
static THEME selected_menutheme = p_app->get_current_theme();
|
||||
|
||||
if (ImGui::BeginMenu(THEME_MENU_ENTRY))
|
||||
{
|
||||
if (ImGui::Selectable(TRADITIONAL_GREEN_THEME_MENU_ENTRY))
|
||||
selected_menutheme = LIGHT_GREEN_THEME;
|
||||
|
||||
if (ImGui::Selectable(DARK_THEME_MENU_ENTRY))
|
||||
selected_menutheme = DARK_THEME;
|
||||
|
||||
if (ImGui::Selectable(CLASSIC_THEME_MENU_ENTRY))
|
||||
selected_menutheme = CLASSIC_THEME;
|
||||
|
||||
if (ImGui::Selectable(LIGHT_BLUE_THEME_MENU_ENTRY))
|
||||
selected_menutheme = LIGHT_BLUE_THEME;
|
||||
|
||||
if (ImGui::Selectable(WINDOWS_THEME_MENU_ENTRY))
|
||||
selected_menutheme = WINDOWS_THEME;
|
||||
|
||||
if (selected_menutheme != p_app->get_current_theme())
|
||||
p_app->setTheme(selected_menutheme);
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void selectFrameSize(DigitalModulation * p_Dmod)
|
||||
{
|
||||
// by default, we recopy the current value
|
||||
int frame_length = p_Dmod->getWordSize();
|
||||
|
||||
if (ImGui::BeginMenu(FRAME_SIZE))
|
||||
{
|
||||
if (ImGui::Selectable(HEIGHT_BITS_FRAME_SIZE))
|
||||
frame_length = 8;
|
||||
|
||||
if (ImGui::Selectable(SIXTEEN_BITS_FRAME_SIZE))
|
||||
frame_length = 16;
|
||||
|
||||
if (ImGui::Selectable(TWENTY_FOUR_BITS_FRAME_SIZE))
|
||||
frame_length = 24;
|
||||
|
||||
if (frame_length != p_Dmod->getWordSize())
|
||||
p_Dmod->setWordSize(frame_length);
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ToogleButton transformé en VToggleButton
|
||||
bool VToggleButton(const char* str_id, bool* v)
|
||||
{
|
||||
ImVec2 p = ImGui::GetCursorScreenPos();
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
// Taille du toggle
|
||||
// FIXME : elaborate
|
||||
float width = ImGui::GetFrameHeight();
|
||||
//float width = VTOGGLEBUTTON_WIDTH;
|
||||
float height = width * 1.8f;
|
||||
float radius = width * 0.5f;
|
||||
|
||||
ImGui::InvisibleButton(str_id, ImVec2(width, height));
|
||||
|
||||
// Vérifie si le bouton a été cliqué
|
||||
bool clicked = ImGui::IsItemClicked();
|
||||
if (clicked)
|
||||
*v = !*v;
|
||||
|
||||
// Choix de la couleur de fond selon l'état
|
||||
ImU32 col_bg = ImGui::IsItemHovered()
|
||||
? (*v ? IM_COL32(165,231,88,255) : IM_COL32(200,200,200,255)) //ON
|
||||
: (*v ? IM_COL32(145,211,68,255) : IM_COL32(218,218,218,255)); //OFF
|
||||
|
||||
draw_list->AddRectFilled( p, ImVec2(p.x + width, p.y + height), col_bg, radius ); // Dessine le rectangle du Toggle
|
||||
float cy = *v ? (p.y + radius) : (p.y + height - radius); // Position verticale du petit rond
|
||||
draw_list->AddCircleFilled( ImVec2(p.x + radius, cy), radius - 2.0f, IM_COL32(255,255,255,255) ); // Dessine le rond blanc du Toggle
|
||||
|
||||
return clicked;
|
||||
}
|
||||
|
||||
void drawVToggleButtons(int * dm_bits, int wordSize)
|
||||
{
|
||||
// CHILD2_WIDTH = 300.0f
|
||||
float drawSize = ImGui::GetContentRegionAvail().x - CHILD2_WIDTH;
|
||||
|
||||
// FIXME : calculer sérieusement ces valeurs
|
||||
//TEST
|
||||
|
||||
// La formule :
|
||||
// draw_size = (P+B)wordSize + P + marges // Il y a 1 padding de plus que de boutons dessinés
|
||||
//
|
||||
// 20.0f because fo the left/right margins
|
||||
// On dessine dans la child window 1,
|
||||
// et le nombre de pixels n'est plus le même en plein écran
|
||||
// exemple : drawSize = 664.0f contre 1304.0f en plein écran.
|
||||
// 2 solutions : soit dessiner a valeur définie et testée (pas très pro)
|
||||
// soit calculer précisément le padding. Or la formule ne semble pas fonctionner ...
|
||||
// La valeur de 20.0f est soustraite car il faut tenir compte d'une marge à gauche
|
||||
// et d'une marge à droite pour le canvas.
|
||||
// current best value : 20.0f
|
||||
float padding = ((drawSize - 20.0f) - VTOGGLEBUTTON_WIDTH * (float)wordSize)/((float)wordSize + 1);
|
||||
|
||||
// hack ... le temps de corriger la formule
|
||||
if (wordSize == 8)
|
||||
padding += 32.0f;
|
||||
|
||||
if (wordSize == 16)
|
||||
padding += 7.5f;
|
||||
|
||||
if (drawSize > 1000.0F)
|
||||
{
|
||||
if (wordSize == 8)
|
||||
padding += 7.3f; // best value 7.3f
|
||||
|
||||
if (wordSize == 16)
|
||||
padding += 2.3f; // best value 2.3f
|
||||
else
|
||||
padding += 1.2f; // best value 1.2f
|
||||
}
|
||||
// end hack
|
||||
|
||||
ImGui::Dummy(ImVec2(padding / 2.0f, 0.0f)); ImGui::SameLine(); // Padding pour le premier bouton
|
||||
|
||||
for (int i = 0; i < wordSize ; i++)
|
||||
{
|
||||
ImGui::PushID(i);
|
||||
bool bit = (dm_bits[i] != 0);
|
||||
|
||||
if (VToggleButton("##Button", &bit))
|
||||
dm_bits[i] = bit ? 1 : 0;
|
||||
ImGui::PopID();
|
||||
|
||||
if (i < (wordSize - 1)) // Pas de padding pour le dernier
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(padding, 0.0f)); ImGui::SameLine();
|
||||
}
|
||||
}
|
||||
// debug purpose
|
||||
//#define DEBUG_ME
|
||||
#ifdef DEBUG_ME
|
||||
ImGui::Text(" wordSize : %d", wordSize);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text(" padding : %f", padding);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text(" drawSize : %f", drawSize);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("VTOGGLEBUTTON_WIDTH : %f", VTOGGLEBUTTON_WIDTH);
|
||||
#endif /* DEBUG_ME */
|
||||
}
|
||||
|
||||
void highlightFrame(int * dm_bits, int wordSize)
|
||||
{
|
||||
ImVec2 text_pos = ImGui::GetCursorScreenPos();
|
||||
// pour avoir la surbrillance de longueur variable
|
||||
std::string text_trame = "Trame :";
|
||||
|
||||
for (int i = 0; i < wordSize; i++)
|
||||
{
|
||||
if (0 == i % 8 && i != 0) // Découpage par octets
|
||||
text_trame += " ";
|
||||
|
||||
text_trame += " ";
|
||||
text_trame += std::to_string(dm_bits[i]);
|
||||
}
|
||||
|
||||
ImVec2 text_size = ImGui::CalcTextSize(text_trame.c_str());
|
||||
ImGui::GetWindowDrawList()->AddRectFilled(
|
||||
text_pos,
|
||||
ImVec2(text_pos.x + text_size.x, text_pos.y + text_size.y),
|
||||
IM_COL32(255, 255, 0, 128) // Jaune semi-transparent
|
||||
);
|
||||
ImGui::Text("%s", text_trame.c_str());
|
||||
ImGui::NewLine();
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
// Helper to draw a small modulation example (Témoin visuel). Code proposé par
|
||||
void DrawIndicator(const char * label,
|
||||
float * carrier_freq,
|
||||
DigitalModulationType * p_modulation_type,
|
||||
int * samples_per_bit,
|
||||
float amp_scale,
|
||||
float phase_offset,
|
||||
ImU32 color,
|
||||
ImVec2 size)
|
||||
{
|
||||
ImGui::Text("%s", label);
|
||||
ImVec2 p = ImGui::GetCursorScreenPos();
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
// Fond gris clair pour le témoin
|
||||
draw_list->AddRectFilled(p, ImVec2(p.x + size.x, p.y + size.y), IM_COL32(245, 245, 245, 255));
|
||||
|
||||
// Bordure
|
||||
draw_list->AddRect(p, ImVec2(p.x + size.x, p.y + size.y), IM_COL32(180, 180, 180, 255));
|
||||
|
||||
float cy = p.y + size.y * 0.5f; // Centre vertical
|
||||
float base_amp = (size.y * 0.35f); // Amplitude de base (laisse une marge)
|
||||
|
||||
ImVec2 prev;
|
||||
bool first = true;
|
||||
|
||||
// On dessine 2 périodes (ou le double si un symbole est codé sur 2 bits),
|
||||
// pour bien visualiser la forme
|
||||
static float k2 = 1.0f;
|
||||
|
||||
switch (*p_modulation_type)
|
||||
{
|
||||
case MOD_MASK_TYPE :
|
||||
case MOD_M_QAM_TYPE:
|
||||
case MOD_4_QAM_TYPE:
|
||||
case MOD_MFSK_TYPE :
|
||||
k2 = 2.0f;
|
||||
break;
|
||||
|
||||
default:
|
||||
k2 = 1.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
// tracé de la courbe
|
||||
for (int i = 0; i <= *samples_per_bit; i++)
|
||||
{
|
||||
float t = (float)i / (float)*samples_per_bit; // 0 à 1
|
||||
// Formule du signal : sin(2*PI * f * t + phase)
|
||||
float y = cy - sinf(k2 * 2.0f * M_PI * (* carrier_freq) * t + phase_offset) * (base_amp * amp_scale);
|
||||
float x = p.x + t * size.x;
|
||||
ImVec2 curr(x, y);
|
||||
|
||||
if (!first)
|
||||
draw_list->AddLine(prev, curr, color, 1.5f); // Ligne un peu plus épaisse
|
||||
prev = curr;
|
||||
first = false;
|
||||
}
|
||||
|
||||
// Réserve l'espace pour qu'ImGui ne dessine pas par dessus
|
||||
ImGui::Dummy(size);
|
||||
// Petit espacement vertical après
|
||||
ImGui::Dummy(ImVec2(0, 5));
|
||||
}
|
||||
|
||||
Référencer dans un nouveau ticket
Bloquer un utilisateur