2018-10-31 09:19:44 +00:00
# include "ImGuiWrapper.hpp"
2018-11-27 11:10:21 +00:00
# include <cstdio>
2018-11-26 09:56:07 +00:00
# include <vector>
2019-01-24 10:30:29 +00:00
# include <cmath>
# include <stdexcept>
2018-11-26 09:56:07 +00:00
# include <boost/format.hpp>
# include <boost/log/trivial.hpp>
2020-05-06 18:45:57 +00:00
# include <boost/filesystem.hpp>
2018-10-31 09:19:44 +00:00
2018-11-26 09:56:07 +00:00
# include <wx/string.h>
2018-10-31 09:19:44 +00:00
# include <wx/event.h>
2019-02-15 14:35:32 +00:00
# include <wx/clipbrd.h>
2018-11-26 09:56:07 +00:00
# include <wx/debug.h>
2018-10-31 09:19:44 +00:00
# include <GL/glew.h>
2020-04-01 09:51:44 +00:00
# ifndef IMGUI_DEFINE_MATH_OPERATORS
# define IMGUI_DEFINE_MATH_OPERATORS
# endif
2019-01-18 14:02:07 +00:00
# include <imgui/imgui_internal.h>
2018-11-26 09:56:07 +00:00
# include "libslic3r/libslic3r.h"
2018-11-26 13:41:58 +00:00
# include "libslic3r/Utils.hpp"
2019-03-27 13:42:09 +00:00
# include "3DScene.hpp"
2018-11-26 09:56:07 +00:00
# include "GUI.hpp"
2020-04-14 15:54:15 +00:00
# include "I18N.hpp"
2020-04-20 19:46:16 +00:00
# include "Search.hpp"
2018-11-20 17:40:57 +00:00
2020-05-06 19:29:51 +00:00
# include "../Utils/MacDarkMode.hpp"
2020-05-06 18:45:57 +00:00
# include "nanosvg/nanosvg.h"
# include "nanosvg/nanosvgrast.h"
2018-10-31 09:19:44 +00:00
namespace Slic3r {
namespace GUI {
2018-11-20 17:40:57 +00:00
2018-10-31 09:19:44 +00:00
2020-05-06 18:45:57 +00:00
static const std : : map < const char , std : : string > font_icons = {
{ ImGui : : PrintIconMarker , " cog " } ,
{ ImGui : : PrinterIconMarker , " printer " } ,
{ ImGui : : PrinterSlaIconMarker , " sla_printer " } ,
{ ImGui : : FilamentIconMarker , " spool " } ,
{ ImGui : : MaterialIconMarker , " resin " }
} ;
2019-04-01 12:12:05 +00:00
ImGuiWrapper : : ImGuiWrapper ( )
2019-02-19 12:26:26 +00:00
: m_glyph_ranges ( nullptr )
2019-05-23 16:04:27 +00:00
, m_font_cjk ( false )
2019-04-01 12:12:05 +00:00
, m_font_size ( 18.0 )
2019-02-19 12:26:26 +00:00
, m_font_texture ( 0 )
2019-01-24 10:30:29 +00:00
, m_style_scaling ( 1.0 )
2018-11-26 09:56:07 +00:00
, m_mouse_buttons ( 0 )
2019-01-18 14:02:07 +00:00
, m_disabled ( false )
2019-02-19 11:39:24 +00:00
, m_new_frame_open ( false )
2018-10-31 09:19:44 +00:00
{
ImGui : : CreateContext ( ) ;
2019-02-15 14:35:32 +00:00
init_input ( ) ;
2019-02-19 13:46:29 +00:00
init_style ( ) ;
2018-10-31 09:19:44 +00:00
2019-01-24 10:30:29 +00:00
ImGui : : GetIO ( ) . IniFilename = nullptr ;
2019-03-29 13:57:53 +00:00
}
2018-10-31 09:19:44 +00:00
2019-03-29 13:57:53 +00:00
ImGuiWrapper : : ~ ImGuiWrapper ( )
{
2019-04-01 12:12:05 +00:00
destroy_font ( ) ;
2019-03-29 13:57:53 +00:00
ImGui : : DestroyContext ( ) ;
2018-10-31 09:19:44 +00:00
}
2019-02-19 12:26:26 +00:00
void ImGuiWrapper : : set_language ( const std : : string & language )
{
2019-03-26 16:57:54 +00:00
if ( m_new_frame_open ) {
// ImGUI internally locks the font between NewFrame() and EndFrame()
// NewFrame() might've been called here because of input from the 3D scene;
// call EndFrame()
ImGui : : EndFrame ( ) ;
m_new_frame_open = false ;
}
2019-02-19 12:26:26 +00:00
const ImWchar * ranges = nullptr ;
size_t idx = language . find ( ' _ ' ) ;
std : : string lang = ( idx = = std : : string : : npos ) ? language : language . substr ( 0 , idx ) ;
static const ImWchar ranges_latin2 [ ] =
{
0x0020 , 0x00FF , // Basic Latin + Latin Supplement
0x0100 , 0x017F , // Latin Extended-A
0 ,
} ;
2019-05-23 16:04:27 +00:00
static const ImWchar ranges_turkish [ ] = {
0x0020 , 0x01FF , // Basic Latin + Latin Supplement
0x0100 , 0x017F , // Latin Extended-A
0x0180 , 0x01FF , // Turkish
0 ,
} ;
static const ImWchar ranges_vietnamese [ ] =
{
0x0020 , 0x00FF , // Basic Latin
0x0102 , 0x0103 ,
0x0110 , 0x0111 ,
0x0128 , 0x0129 ,
0x0168 , 0x0169 ,
0x01A0 , 0x01A1 ,
0x01AF , 0x01B0 ,
0x1EA0 , 0x1EF9 ,
0 ,
} ;
m_font_cjk = false ;
2019-02-19 12:26:26 +00:00
if ( lang = = " cs " | | lang = = " pl " ) {
ranges = ranges_latin2 ;
} else if ( lang = = " ru " | | lang = = " uk " ) {
2019-05-23 16:04:27 +00:00
ranges = ImGui : : GetIO ( ) . Fonts - > GetGlyphRangesCyrillic ( ) ; // Default + about 400 Cyrillic characters
} else if ( lang = = " tr " ) {
ranges = ranges_turkish ;
} else if ( lang = = " vi " ) {
ranges = ranges_vietnamese ;
2019-12-10 12:40:57 +00:00
} else if ( lang = = " ja " ) {
2019-05-23 16:04:27 +00:00
ranges = ImGui : : GetIO ( ) . Fonts - > GetGlyphRangesJapanese ( ) ; // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs
m_font_cjk = true ;
2019-05-19 08:52:09 +00:00
} else if ( lang = = " ko " ) {
2019-05-23 16:04:27 +00:00
ranges = ImGui : : GetIO ( ) . Fonts - > GetGlyphRangesKorean ( ) ; // Default + Korean characters
m_font_cjk = true ;
2019-02-19 12:26:26 +00:00
} else if ( lang = = " zh " ) {
2019-05-23 16:04:27 +00:00
ranges = ( language = = " zh_TW " ) ?
// Traditional Chinese
// Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs
ImGui : : GetIO ( ) . Fonts - > GetGlyphRangesChineseFull ( ) :
// Simplified Chinese
// Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese
ImGui : : GetIO ( ) . Fonts - > GetGlyphRangesChineseSimplifiedCommon ( ) ;
m_font_cjk = true ;
} else if ( lang = = " th " ) {
ranges = ImGui : : GetIO ( ) . Fonts - > GetGlyphRangesThai ( ) ; // Default + Thai characters
} else {
ranges = ImGui : : GetIO ( ) . Fonts - > GetGlyphRangesDefault ( ) ; // Basic Latin, Extended Latin
2019-02-19 12:26:26 +00:00
}
if ( ranges ! = m_glyph_ranges ) {
m_glyph_ranges = ranges ;
2019-04-01 12:12:05 +00:00
destroy_font ( ) ;
2019-02-19 12:26:26 +00:00
}
}
2018-10-31 09:19:44 +00:00
void ImGuiWrapper : : set_display_size ( float w , float h )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
io . DisplaySize = ImVec2 ( w , h ) ;
io . DisplayFramebufferScale = ImVec2 ( 1.0f , 1.0f ) ;
}
2019-04-02 11:26:22 +00:00
void ImGuiWrapper : : set_scaling ( float font_size , float scale_style , float scale_both )
2019-01-24 10:30:29 +00:00
{
2019-04-02 11:26:22 +00:00
font_size * = scale_both ;
scale_style * = scale_both ;
if ( m_font_size = = font_size & & m_style_scaling = = scale_style ) {
2019-04-01 13:36:48 +00:00
return ;
2019-01-24 10:30:29 +00:00
}
2019-04-01 12:12:05 +00:00
2019-04-01 13:36:48 +00:00
m_font_size = font_size ;
2019-04-02 11:26:22 +00:00
ImGui : : GetStyle ( ) . ScaleAllSizes ( scale_style / m_style_scaling ) ;
m_style_scaling = scale_style ;
2019-04-01 13:36:48 +00:00
destroy_font ( ) ;
2019-01-24 10:30:29 +00:00
}
2018-11-26 09:56:07 +00:00
bool ImGuiWrapper : : update_mouse_data ( wxMouseEvent & evt )
2018-10-31 09:19:44 +00:00
{
2019-02-22 13:52:32 +00:00
if ( ! display_initialized ( ) ) {
return false ;
}
2018-10-31 09:19:44 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
io . MousePos = ImVec2 ( ( float ) evt . GetX ( ) , ( float ) evt . GetY ( ) ) ;
2019-03-13 13:44:59 +00:00
io . MouseDown [ 0 ] = evt . LeftIsDown ( ) ;
io . MouseDown [ 1 ] = evt . RightIsDown ( ) ;
io . MouseDown [ 2 ] = evt . MiddleIsDown ( ) ;
2018-10-31 09:19:44 +00:00
2019-03-13 13:44:59 +00:00
unsigned buttons = ( evt . LeftIsDown ( ) ? 1 : 0 ) | ( evt . RightIsDown ( ) ? 2 : 0 ) | ( evt . MiddleIsDown ( ) ? 4 : 0 ) ;
2018-11-26 09:56:07 +00:00
m_mouse_buttons = buttons ;
2019-02-19 11:39:24 +00:00
new_frame ( ) ;
return want_mouse ( ) ;
2018-10-31 09:19:44 +00:00
}
2019-02-15 14:35:32 +00:00
bool ImGuiWrapper : : update_key_data ( wxKeyEvent & evt )
{
2019-02-22 13:52:32 +00:00
if ( ! display_initialized ( ) ) {
return false ;
}
2019-02-15 14:35:32 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
if ( evt . GetEventType ( ) = = wxEVT_CHAR ) {
// Char event
2019-02-19 11:39:24 +00:00
const auto key = evt . GetUnicodeKey ( ) ;
if ( key ! = 0 ) {
io . AddInputCharacter ( key ) ;
}
2019-02-20 15:55:00 +00:00
new_frame ( ) ;
return want_keyboard ( ) | | want_text_input ( ) ;
2019-02-15 14:35:32 +00:00
} else {
// Key up/down event
int key = evt . GetKeyCode ( ) ;
wxCHECK_MSG ( key > = 0 & & key < IM_ARRAYSIZE ( io . KeysDown ) , false , " Received invalid key code " ) ;
io . KeysDown [ key ] = evt . GetEventType ( ) = = wxEVT_KEY_DOWN ;
io . KeyShift = evt . ShiftDown ( ) ;
io . KeyCtrl = evt . ControlDown ( ) ;
io . KeyAlt = evt . AltDown ( ) ;
io . KeySuper = evt . MetaDown ( ) ;
2019-02-21 10:54:18 +00:00
new_frame ( ) ;
return want_keyboard ( ) | | want_text_input ( ) ;
2019-02-20 15:55:00 +00:00
}
2019-02-15 14:35:32 +00:00
}
2018-10-31 09:19:44 +00:00
void ImGuiWrapper : : new_frame ( )
{
2019-02-19 11:39:24 +00:00
if ( m_new_frame_open ) {
return ;
}
2019-04-01 12:12:05 +00:00
if ( m_font_texture = = 0 ) {
2019-05-28 10:53:16 +00:00
init_font ( true ) ;
2019-04-01 12:12:05 +00:00
}
2018-10-31 09:19:44 +00:00
ImGui : : NewFrame ( ) ;
2019-02-19 11:39:24 +00:00
m_new_frame_open = true ;
2018-10-31 09:19:44 +00:00
}
void ImGuiWrapper : : render ( )
{
ImGui : : Render ( ) ;
render_draw_data ( ImGui : : GetDrawData ( ) ) ;
2019-02-19 11:39:24 +00:00
m_new_frame_open = false ;
2018-10-31 09:19:44 +00:00
}
2019-04-01 13:36:48 +00:00
ImVec2 ImGuiWrapper : : calc_text_size ( const wxString & text )
{
auto text_utf8 = into_u8 ( text ) ;
2019-05-13 12:28:03 +00:00
ImVec2 size = ImGui : : CalcTextSize ( text_utf8 . c_str ( ) ) ;
2019-05-24 10:01:26 +00:00
/*#ifdef __linux__
2019-05-13 12:28:03 +00:00
size . x * = m_style_scaling ;
size . y * = m_style_scaling ;
2019-05-24 10:01:26 +00:00
# endif* /
2019-05-13 12:28:03 +00:00
return size ;
2019-04-01 13:36:48 +00:00
}
2019-07-10 11:45:25 +00:00
void ImGuiWrapper : : set_next_window_pos ( float x , float y , int flag , float pivot_x , float pivot_y )
2018-10-31 09:19:44 +00:00
{
2019-07-10 11:45:25 +00:00
ImGui : : SetNextWindowPos ( ImVec2 ( x , y ) , ( ImGuiCond ) flag , ImVec2 ( pivot_x , pivot_y ) ) ;
2019-01-24 14:44:00 +00:00
ImGui : : SetNextWindowSize ( ImVec2 ( 0.0 , 0.0 ) ) ;
2018-10-31 09:19:44 +00:00
}
void ImGuiWrapper : : set_next_window_bg_alpha ( float alpha )
{
ImGui : : SetNextWindowBgAlpha ( alpha ) ;
}
2018-11-26 09:56:07 +00:00
bool ImGuiWrapper : : begin ( const std : : string & name , int flags )
2018-10-31 09:19:44 +00:00
{
return ImGui : : Begin ( name . c_str ( ) , nullptr , ( ImGuiWindowFlags ) flags ) ;
}
2018-11-26 09:56:07 +00:00
bool ImGuiWrapper : : begin ( const wxString & name , int flags )
{
return begin ( into_u8 ( name ) , flags ) ;
}
2019-12-16 12:35:45 +00:00
bool ImGuiWrapper : : begin ( const std : : string & name , bool * close , int flags )
{
return ImGui : : Begin ( name . c_str ( ) , close , ( ImGuiWindowFlags ) flags ) ;
}
bool ImGuiWrapper : : begin ( const wxString & name , bool * close , int flags )
{
return begin ( into_u8 ( name ) , close , flags ) ;
}
2018-10-31 09:19:44 +00:00
void ImGuiWrapper : : end ( )
{
ImGui : : End ( ) ;
}
2018-11-26 09:56:07 +00:00
bool ImGuiWrapper : : button ( const wxString & label )
{
auto label_utf8 = into_u8 ( label ) ;
return ImGui : : Button ( label_utf8 . c_str ( ) ) ;
}
2019-01-30 07:26:23 +00:00
bool ImGuiWrapper : : radio_button ( const wxString & label , bool active )
{
auto label_utf8 = into_u8 ( label ) ;
return ImGui : : RadioButton ( label_utf8 . c_str ( ) , active ) ;
}
2018-11-26 09:56:07 +00:00
bool ImGuiWrapper : : input_double ( const std : : string & label , const double & value , const std : : string & format )
2018-10-31 09:19:44 +00:00
{
2018-11-26 09:56:07 +00:00
return ImGui : : InputDouble ( label . c_str ( ) , const_cast < double * > ( & value ) , 0.0f , 0.0f , format . c_str ( ) ) ;
2018-10-31 09:19:44 +00:00
}
2020-02-21 11:17:46 +00:00
bool ImGuiWrapper : : input_double ( const wxString & label , const double & value , const std : : string & format )
{
auto label_utf8 = into_u8 ( label ) ;
return input_double ( label_utf8 , value , format ) ;
}
2018-11-26 09:56:07 +00:00
bool ImGuiWrapper : : input_vec3 ( const std : : string & label , const Vec3d & value , float width , const std : : string & format )
2018-10-31 09:19:44 +00:00
{
bool value_changed = false ;
ImGui : : BeginGroup ( ) ;
for ( int i = 0 ; i < 3 ; + + i )
{
std : : string item_label = ( i = = 0 ) ? " X " : ( ( i = = 1 ) ? " Y " : " Z " ) ;
ImGui : : PushID ( i ) ;
ImGui : : PushItemWidth ( width ) ;
2018-11-26 09:56:07 +00:00
value_changed | = ImGui : : InputDouble ( item_label . c_str ( ) , const_cast < double * > ( & value ( i ) ) , 0.0f , 0.0f , format . c_str ( ) ) ;
2018-10-31 09:19:44 +00:00
ImGui : : PopID ( ) ;
}
ImGui : : EndGroup ( ) ;
return value_changed ;
}
2018-11-26 09:56:07 +00:00
bool ImGuiWrapper : : checkbox ( const wxString & label , bool & value )
{
auto label_utf8 = into_u8 ( label ) ;
return ImGui : : Checkbox ( label_utf8 . c_str ( ) , & value ) ;
}
2019-03-04 11:21:00 +00:00
void ImGuiWrapper : : text ( const char * label )
{
ImGui : : Text ( label , NULL ) ;
}
void ImGuiWrapper : : text ( const std : : string & label )
{
this - > text ( label . c_str ( ) ) ;
}
2018-11-26 14:54:12 +00:00
void ImGuiWrapper : : text ( const wxString & label )
{
2019-04-01 12:12:05 +00:00
auto label_utf8 = into_u8 ( label ) ;
this - > text ( label_utf8 . c_str ( ) ) ;
2018-11-26 14:54:12 +00:00
}
2019-12-04 14:12:00 +00:00
bool ImGuiWrapper : : slider_float ( const char * label , float * v , float v_min , float v_max , const char * format /* = "%.3f"*/ , float power /* = 1.0f*/ )
{
return ImGui : : SliderFloat ( label , v , v_min , v_max , format , power ) ;
}
bool ImGuiWrapper : : slider_float ( const std : : string & label , float * v , float v_min , float v_max , const char * format /* = "%.3f"*/ , float power /* = 1.0f*/ )
{
return this - > slider_float ( label . c_str ( ) , v , v_min , v_max , format , power ) ;
}
bool ImGuiWrapper : : slider_float ( const wxString & label , float * v , float v_min , float v_max , const char * format /* = "%.3f"*/ , float power /* = 1.0f*/ )
{
auto label_utf8 = into_u8 ( label ) ;
return this - > slider_float ( label_utf8 . c_str ( ) , v , v_min , v_max , format , power ) ;
}
2019-03-04 14:40:06 +00:00
bool ImGuiWrapper : : combo ( const wxString & label , const std : : vector < std : : string > & options , int & selection )
2019-01-30 07:26:23 +00:00
{
// this is to force the label to the left of the widget:
text ( label ) ;
ImGui : : SameLine ( ) ;
2019-03-04 14:40:06 +00:00
int selection_out = - 1 ;
bool res = false ;
2019-06-25 15:23:53 +00:00
const char * selection_str = selection < ( int ) options . size ( ) ? options [ selection ] . c_str ( ) : " " ;
2019-03-04 14:40:06 +00:00
if ( ImGui : : BeginCombo ( " " , selection_str ) ) {
2019-06-25 15:23:53 +00:00
for ( int i = 0 ; i < ( int ) options . size ( ) ; i + + ) {
2019-03-04 14:40:06 +00:00
if ( ImGui : : Selectable ( options [ i ] . c_str ( ) , i = = selection ) ) {
selection_out = i ;
}
2019-03-04 11:21:00 +00:00
}
2019-03-04 14:40:06 +00:00
2019-03-04 11:21:00 +00:00
ImGui : : EndCombo ( ) ;
2019-03-04 14:40:06 +00:00
res = true ;
2019-03-04 11:21:00 +00:00
}
2019-03-04 14:40:06 +00:00
selection = selection_out ;
return res ;
2019-03-04 11:21:00 +00:00
}
2020-04-27 14:00:54 +00:00
// Scroll up for one item
static void scroll_up ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
float item_size_y = window - > DC . PrevLineSize . y + g . Style . ItemSpacing . y ;
float win_top = window - > Scroll . y ;
ImGui : : SetScrollY ( win_top - item_size_y ) ;
}
// Scroll down for one item
static void scroll_down ( )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
float item_size_y = window - > DC . PrevLineSize . y + g . Style . ItemSpacing . y ;
float win_top = window - > Scroll . y ;
ImGui : : SetScrollY ( win_top + item_size_y ) ;
}
static void process_mouse_wheel ( int & mouse_wheel )
{
if ( mouse_wheel > 0 )
scroll_up ( ) ;
else if ( mouse_wheel < 0 )
scroll_down ( ) ;
mouse_wheel = 0 ;
}
bool ImGuiWrapper : : undo_redo_list ( const ImVec2 & size , const bool is_undo , bool ( * items_getter ) ( const bool , int , const char * * ) , int & hovered , int & selected , int & mouse_wheel )
2019-07-08 16:01:14 +00:00
{
2019-07-09 13:27:28 +00:00
bool is_hovered = false ;
ImGui : : ListBoxHeader ( " " , size ) ;
2019-07-08 16:01:14 +00:00
2019-07-09 13:27:28 +00:00
int i = 0 ;
const char * item_text ;
while ( items_getter ( is_undo , i , & item_text ) )
{
ImGui : : Selectable ( item_text , i < hovered ) ;
2019-07-08 16:01:14 +00:00
2019-07-09 13:27:28 +00:00
if ( ImGui : : IsItemHovered ( ) ) {
2019-08-13 19:21:41 +00:00
ImGui : : SetTooltip ( " %s " , item_text ) ;
2019-07-09 13:27:28 +00:00
hovered = i ;
is_hovered = true ;
}
2019-07-08 16:01:14 +00:00
2019-07-09 13:27:28 +00:00
if ( ImGui : : IsItemClicked ( ) )
selected = i ;
i + + ;
}
2020-04-27 14:00:54 +00:00
if ( is_hovered )
process_mouse_wheel ( mouse_wheel ) ;
2019-07-09 13:27:28 +00:00
ImGui : : ListBoxFooter ( ) ;
return is_hovered ;
2019-07-08 16:01:14 +00:00
}
2020-04-01 09:51:44 +00:00
// It's a copy of IMGui::Selactable function.
// But a little beat modified to change a label text.
// If item is hovered we should use another color for highlighted letters.
// To do that we push a ColorMarkerHovered symbol at the very beginning of the label
// This symbol will be used to a color selection for the highlighted letters.
// see imgui_draw.cpp, void ImFont::RenderText()
static bool selectable ( const char * label , bool selected , ImGuiSelectableFlags flags = 0 , const ImVec2 & size_arg = ImVec2 ( 0 , 0 ) )
{
ImGuiWindow * window = ImGui : : GetCurrentWindow ( ) ;
if ( window - > SkipItems )
return false ;
ImGuiContext & g = * GImGui ;
const ImGuiStyle & style = g . Style ;
if ( ( flags & ImGuiSelectableFlags_SpanAllColumns ) & & window - > DC . CurrentColumns ) // FIXME-OPT: Avoid if vertically clipped.
ImGui : : PushColumnsBackground ( ) ;
ImGuiID id = window - > GetID ( label ) ;
ImVec2 label_size = ImGui : : CalcTextSize ( label , NULL , true ) ;
ImVec2 size ( size_arg . x ! = 0.0f ? size_arg . x : label_size . x , size_arg . y ! = 0.0f ? size_arg . y : label_size . y ) ;
ImVec2 pos = window - > DC . CursorPos ;
pos . y + = window - > DC . CurrLineTextBaseOffset ;
ImRect bb_inner ( pos , pos + size ) ;
ImGui : : ItemSize ( size , 0.0f ) ;
// Fill horizontal space.
ImVec2 window_padding = window - > WindowPadding ;
float max_x = ( flags & ImGuiSelectableFlags_SpanAllColumns ) ? ImGui : : GetWindowContentRegionMax ( ) . x : ImGui : : GetContentRegionMax ( ) . x ;
float w_draw = ImMax ( label_size . x , window - > Pos . x + max_x - window_padding . x - pos . x ) ;
ImVec2 size_draw ( ( size_arg . x ! = 0 & & ! ( flags & ImGuiSelectableFlags_DrawFillAvailWidth ) ) ? size_arg . x : w_draw , size_arg . y ! = 0.0f ? size_arg . y : size . y ) ;
ImRect bb ( pos , pos + size_draw ) ;
if ( size_arg . x = = 0.0f | | ( flags & ImGuiSelectableFlags_DrawFillAvailWidth ) )
bb . Max . x + = window_padding . x ;
// Selectables are tightly packed together so we extend the box to cover spacing between selectable.
const float spacing_x = style . ItemSpacing . x ;
const float spacing_y = style . ItemSpacing . y ;
const float spacing_L = IM_FLOOR ( spacing_x * 0.50f ) ;
const float spacing_U = IM_FLOOR ( spacing_y * 0.50f ) ;
bb . Min . x - = spacing_L ;
bb . Min . y - = spacing_U ;
bb . Max . x + = ( spacing_x - spacing_L ) ;
bb . Max . y + = ( spacing_y - spacing_U ) ;
bool item_add ;
if ( flags & ImGuiSelectableFlags_Disabled )
{
ImGuiItemFlags backup_item_flags = window - > DC . ItemFlags ;
window - > DC . ItemFlags | = ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNavDefaultFocus ;
item_add = ImGui : : ItemAdd ( bb , id ) ;
window - > DC . ItemFlags = backup_item_flags ;
}
else
{
item_add = ImGui : : ItemAdd ( bb , id ) ;
}
if ( ! item_add )
{
if ( ( flags & ImGuiSelectableFlags_SpanAllColumns ) & & window - > DC . CurrentColumns )
ImGui : : PopColumnsBackground ( ) ;
return false ;
}
// We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries
ImGuiButtonFlags button_flags = 0 ;
if ( flags & ImGuiSelectableFlags_NoHoldingActiveID ) { button_flags | = ImGuiButtonFlags_NoHoldingActiveId ; }
if ( flags & ImGuiSelectableFlags_PressedOnClick ) { button_flags | = ImGuiButtonFlags_PressedOnClick ; }
if ( flags & ImGuiSelectableFlags_PressedOnRelease ) { button_flags | = ImGuiButtonFlags_PressedOnRelease ; }
if ( flags & ImGuiSelectableFlags_Disabled ) { button_flags | = ImGuiButtonFlags_Disabled ; }
if ( flags & ImGuiSelectableFlags_AllowDoubleClick ) { button_flags | = ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick ; }
if ( flags & ImGuiSelectableFlags_AllowItemOverlap ) { button_flags | = ImGuiButtonFlags_AllowItemOverlap ; }
if ( flags & ImGuiSelectableFlags_Disabled )
selected = false ;
const bool was_selected = selected ;
bool hovered , held ;
bool pressed = ImGui : : ButtonBehavior ( bb , id , & hovered , & held , button_flags ) ;
// Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard
if ( pressed | | ( hovered & & ( flags & ImGuiSelectableFlags_SetNavIdOnHover ) ) )
{
if ( ! g . NavDisableMouseHover & & g . NavWindow = = window & & g . NavLayer = = window - > DC . NavLayerCurrent )
{
g . NavDisableHighlight = true ;
ImGui : : SetNavID ( id , window - > DC . NavLayerCurrent , window - > DC . NavFocusScopeIdCurrent ) ;
}
}
if ( pressed )
ImGui : : MarkItemEdited ( id ) ;
if ( flags & ImGuiSelectableFlags_AllowItemOverlap )
ImGui : : SetItemAllowOverlap ( ) ;
// In this branch, Selectable() cannot toggle the selection so this will never trigger.
if ( selected ! = was_selected ) //-V547
window - > DC . LastItemStatusFlags | = ImGuiItemStatusFlags_ToggledSelection ;
// Render
if ( held & & ( flags & ImGuiSelectableFlags_DrawHoveredWhenHeld ) )
hovered = true ;
if ( hovered | | selected )
{
const ImU32 col = ImGui : : GetColorU32 ( ( held & & hovered ) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header ) ;
ImGui : : RenderFrame ( bb . Min , bb . Max , col , false , 0.0f ) ;
ImGui : : RenderNavHighlight ( bb , id , ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding ) ;
}
if ( ( flags & ImGuiSelectableFlags_SpanAllColumns ) & & window - > DC . CurrentColumns )
{
ImGui : : PopColumnsBackground ( ) ;
bb . Max . x - = ( ImGui : : GetContentRegionMax ( ) . x - max_x ) ;
}
// mark a label with a ImGui::ColorMarkerHovered, if item is hovered
char * marked_label = new char [ 255 ] ;
if ( hovered )
sprintf ( marked_label , " %c%s " , ImGui : : ColorMarkerHovered , label ) ;
else
strcpy ( marked_label , label ) ;
if ( flags & ImGuiSelectableFlags_Disabled ) ImGui : : PushStyleColor ( ImGuiCol_Text , style . Colors [ ImGuiCol_TextDisabled ] ) ;
ImGui : : RenderTextClipped ( bb_inner . Min , bb_inner . Max , marked_label , NULL , & label_size , style . SelectableTextAlign , & bb ) ;
if ( flags & ImGuiSelectableFlags_Disabled ) ImGui : : PopStyleColor ( ) ;
delete [ ] marked_label ;
// Automatically close popups
if ( pressed & & ( window - > Flags & ImGuiWindowFlags_Popup ) & & ! ( flags & ImGuiSelectableFlags_DontClosePopups ) & & ! ( window - > DC . ItemFlags & ImGuiItemFlags_SelectableDontClosePopup ) ) ImGui : : CloseCurrentPopup ( ) ;
IMGUI_TEST_ENGINE_ITEM_INFO ( id , label , window - > DC . ItemFlags ) ;
return pressed ;
}
2020-04-20 15:37:03 +00:00
// Scroll so that the hovered item is at the top of the window
static void scroll_y ( int hover_id )
{
if ( hover_id < 0 )
return ;
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
float item_size_y = window - > DC . PrevLineSize . y + g . Style . ItemSpacing . y ;
float item_delta = 0.5 * item_size_y ;
float item_top = item_size_y * hover_id ;
float item_bottom = item_top + item_size_y ;
float win_top = window - > Scroll . y ;
float win_bottom = window - > Scroll . y + window - > Size . y ;
if ( item_bottom + item_delta > = win_bottom )
ImGui : : SetScrollY ( win_top + item_size_y ) ;
else if ( item_top - item_delta < = win_top )
ImGui : : SetScrollY ( win_top - item_size_y ) ;
}
// Use this function instead of ImGui::IsKeyPressed.
// ImGui::IsKeyPressed is related for *GImGui.IO.KeysDownDuration[user_key_index]
// And after first key pressing IsKeyPressed() return "true" always even if key wasn't pressed
static void process_key_down ( ImGuiKey imgui_key , std : : function < void ( ) > f )
{
if ( ImGui : : IsKeyDown ( ImGui : : GetKeyIndex ( imgui_key ) ) )
{
f ( ) ;
// set KeysDown to false to avoid redundant key down processing
ImGuiContext & g = * GImGui ;
g . IO . KeysDown [ ImGui : : GetKeyIndex ( imgui_key ) ] = false ;
}
}
2020-04-20 19:46:16 +00:00
void ImGuiWrapper : : search_list ( const ImVec2 & size_ , bool ( * items_getter ) ( int , const char * * label , const char * * tooltip ) , char * search_str ,
2020-05-07 16:39:38 +00:00
Search : : OptionViewParameters & view_params , int & selected , bool & edited , int & mouse_wheel , bool is_localized )
2020-03-28 18:39:24 +00:00
{
2020-05-07 16:39:38 +00:00
int & hovered_id = view_params . hovered_id ;
2020-03-28 18:39:24 +00:00
// ImGui::ListBoxHeader("", size);
{
// rewrote part of function to add a TextInput instead of label Text
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = ImGui : : GetCurrentWindow ( ) ;
if ( window - > SkipItems )
return ;
const ImGuiStyle & style = g . Style ;
// Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
ImVec2 size = ImGui : : CalcItemSize ( size_ , ImGui : : CalcItemWidth ( ) , ImGui : : GetTextLineHeightWithSpacing ( ) * 7.4f + style . ItemSpacing . y ) ;
ImRect frame_bb ( window - > DC . CursorPos , ImVec2 ( window - > DC . CursorPos . x + size . x , window - > DC . CursorPos . y + size . y ) ) ;
ImRect bb ( frame_bb . Min , frame_bb . Max ) ;
window - > DC . LastItemRect = bb ; // Forward storage for ListBoxFooter.. dodgy.
g . NextItemData . ClearFlags ( ) ;
if ( ! ImGui : : IsRectVisible ( bb . Min , bb . Max ) )
{
ImGui : : ItemSize ( bb . GetSize ( ) , style . FramePadding . y ) ;
ImGui : : ItemAdd ( bb , 0 , & frame_bb ) ;
return ;
}
ImGui : : BeginGroup ( ) ;
const ImGuiID id = ImGui : : GetID ( search_str ) ;
ImVec2 search_size = ImVec2 ( size . x , ImGui : : GetTextLineHeightWithSpacing ( ) + style . ItemSpacing . y ) ;
2020-04-08 18:22:38 +00:00
if ( ! ImGui : : IsAnyItemFocused ( ) & & ! ImGui : : IsAnyItemActive ( ) & & ! ImGui : : IsMouseClicked ( 0 ) )
ImGui : : SetKeyboardFocusHere ( 0 ) ;
// The press on Esc key invokes editing of InputText (removes last changes)
// So we should save previous value...
std : : string str = search_str ;
2020-04-22 13:46:23 +00:00
ImGui : : InputTextEx ( " " , NULL , search_str , 20 , search_size , ImGuiInputTextFlags_AutoSelectAll , NULL , NULL ) ;
2020-03-28 18:39:24 +00:00
edited = ImGui : : IsItemEdited ( ) ;
2020-04-20 19:46:16 +00:00
if ( edited )
2020-05-07 16:39:38 +00:00
hovered_id = 0 ;
2020-03-28 18:39:24 +00:00
2020-04-20 15:37:03 +00:00
process_key_down ( ImGuiKey_Escape , [ & selected , search_str , str ] ( ) {
2020-04-08 18:22:38 +00:00
// use 9999 to mark selection as a Esc key
selected = 9999 ;
// ... and when Esc key was pressed, than revert search_str value
strcpy ( search_str , str . c_str ( ) ) ;
2020-04-20 15:37:03 +00:00
} ) ;
2020-04-08 18:22:38 +00:00
2020-03-28 18:39:24 +00:00
ImGui : : BeginChildFrame ( id , frame_bb . GetSize ( ) ) ;
}
2020-04-20 19:46:16 +00:00
int i = 0 ;
2020-03-28 18:39:24 +00:00
const char * item_text ;
2020-04-20 19:46:16 +00:00
const char * tooltip ;
2020-04-20 15:37:03 +00:00
int mouse_hovered = - 1 ;
2020-04-20 19:46:16 +00:00
while ( items_getter ( i , & item_text , & tooltip ) )
2020-03-28 18:39:24 +00:00
{
2020-04-20 15:37:03 +00:00
selectable ( item_text , i = = hovered_id ) ;
2020-03-28 18:39:24 +00:00
2020-04-20 15:37:03 +00:00
if ( ImGui : : IsItemHovered ( ) ) {
2020-04-20 19:46:16 +00:00
ImGui : : SetTooltip ( " %s " , /*item_text*/ tooltip ) ;
2020-05-07 16:39:38 +00:00
hovered_id = - 1 ;
2020-04-20 15:37:03 +00:00
mouse_hovered = i ;
}
2020-03-28 18:39:24 +00:00
if ( ImGui : : IsItemClicked ( ) )
selected = i ;
i + + ;
}
2020-04-27 14:00:54 +00:00
// Process mouse wheel
if ( mouse_hovered > 0 )
process_mouse_wheel ( mouse_wheel ) ;
2020-04-20 15:37:03 +00:00
// process Up/DownArrows and Enter
process_key_down ( ImGuiKey_UpArrow , [ & hovered_id , mouse_hovered ] ( ) {
if ( mouse_hovered > 0 )
scroll_up ( ) ;
else {
2020-05-07 16:39:38 +00:00
if ( hovered_id > 0 )
2020-04-20 15:37:03 +00:00
- - hovered_id ;
scroll_y ( hovered_id ) ;
}
} ) ;
process_key_down ( ImGuiKey_DownArrow , [ & hovered_id , mouse_hovered , i ] ( ) {
if ( mouse_hovered > 0 )
scroll_down ( ) ;
else {
2020-05-07 16:39:38 +00:00
if ( hovered_id < 0 )
2020-04-20 15:37:03 +00:00
hovered_id = 0 ;
2020-05-07 16:39:38 +00:00
else if ( hovered_id < i - 1 )
2020-04-20 15:37:03 +00:00
+ + hovered_id ;
scroll_y ( hovered_id ) ;
}
} ) ;
process_key_down ( ImGuiKey_Enter , [ & selected , hovered_id ] ( ) {
selected = hovered_id ;
} ) ;
2020-03-28 18:39:24 +00:00
ImGui : : ListBoxFooter ( ) ;
2020-04-14 15:54:15 +00:00
2020-04-24 09:01:14 +00:00
auto check_box = [ & edited , this ] ( const wxString & label , bool & check ) {
2020-04-20 19:46:16 +00:00
ImGui : : SameLine ( ) ;
bool ch = check ;
checkbox ( label , ch ) ;
if ( ImGui : : IsItemClicked ( ) ) {
check = ! check ;
2020-04-24 09:01:14 +00:00
edited = true ;
2020-04-20 19:46:16 +00:00
}
} ;
2020-04-14 15:54:15 +00:00
// add checkboxes for show/hide Categories and Groups
text ( _L ( " Use for search " ) + " : " ) ;
2020-04-20 19:46:16 +00:00
check_box ( _L ( " Category " ) , view_params . category ) ;
2020-05-07 16:39:38 +00:00
if ( is_localized )
check_box ( _L ( " Search in English " ) , view_params . english ) ;
2020-03-28 18:39:24 +00:00
}
2019-01-18 14:02:07 +00:00
void ImGuiWrapper : : disabled_begin ( bool disabled )
{
wxCHECK_RET ( ! m_disabled , " ImGUI: Unbalanced disabled_begin() call " ) ;
if ( disabled ) {
ImGui : : PushItemFlag ( ImGuiItemFlags_Disabled , true ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_Alpha , ImGui : : GetStyle ( ) . Alpha * 0.5f ) ;
m_disabled = true ;
}
}
void ImGuiWrapper : : disabled_end ( )
{
if ( m_disabled ) {
ImGui : : PopItemFlag ( ) ;
ImGui : : PopStyleVar ( ) ;
m_disabled = false ;
}
}
2018-11-26 09:56:07 +00:00
bool ImGuiWrapper : : want_mouse ( ) const
{
return ImGui : : GetIO ( ) . WantCaptureMouse ;
}
bool ImGuiWrapper : : want_keyboard ( ) const
{
return ImGui : : GetIO ( ) . WantCaptureKeyboard ;
}
bool ImGuiWrapper : : want_text_input ( ) const
{
return ImGui : : GetIO ( ) . WantTextInput ;
}
bool ImGuiWrapper : : want_any_input ( ) const
{
const auto io = ImGui : : GetIO ( ) ;
return io . WantCaptureMouse | | io . WantCaptureKeyboard | | io . WantTextInput ;
}
2020-03-19 12:32:34 +00:00
# ifdef __APPLE__
static const ImWchar ranges_keyboard_shortcuts [ ] =
{
2020-03-19 15:09:52 +00:00
0x21E7 , 0x21E7 , // OSX Shift Key symbol
2020-03-19 12:32:34 +00:00
0x2318 , 0x2318 , // OSX Command Key symbol
0x2325 , 0x2325 , // OSX Option Key symbol
0 ,
} ;
# endif // __APPLE__
2020-05-06 18:45:57 +00:00
std : : vector < unsigned char > ImGuiWrapper : : load_svg ( const std : : string & bitmap_name , unsigned target_width , unsigned target_height )
{
std : : vector < unsigned char > empty_vector ;
# ifdef __WXMSW__
std : : string folder = " white \\ " ;
# else
std : : string folder = " white/ " ;
# endif
if ( ! boost : : filesystem : : exists ( Slic3r : : var ( folder + bitmap_name + " .svg " ) ) )
folder . clear ( ) ;
NSVGimage * image = : : nsvgParseFromFile ( Slic3r : : var ( folder + bitmap_name + " .svg " ) . c_str ( ) , " px " , 96.0f ) ;
if ( image = = nullptr )
return empty_vector ;
float svg_scale = target_height ! = 0 ?
( float ) target_height / image - > height : target_width ! = 0 ?
( float ) target_width / image - > width : 1 ;
int width = ( int ) ( svg_scale * image - > width + 0.5f ) ;
int height = ( int ) ( svg_scale * image - > height + 0.5f ) ;
int n_pixels = width * height ;
if ( n_pixels < = 0 ) {
: : nsvgDelete ( image ) ;
return empty_vector ;
}
NSVGrasterizer * rast = : : nsvgCreateRasterizer ( ) ;
if ( rast = = nullptr ) {
: : nsvgDelete ( image ) ;
return empty_vector ;
}
std : : vector < unsigned char > data ( n_pixels * 4 , 0 ) ;
: : nsvgRasterize ( rast , image , 0 , 0 , svg_scale , data . data ( ) , width , height , width * 4 ) ;
: : nsvgDeleteRasterizer ( rast ) ;
: : nsvgDelete ( image ) ;
return data ;
}
2019-05-28 10:53:16 +00:00
void ImGuiWrapper : : init_font ( bool compress )
2019-01-24 10:30:29 +00:00
{
2019-04-01 12:12:05 +00:00
destroy_font ( ) ;
2019-01-24 12:16:46 +00:00
2019-01-24 10:30:29 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
io . Fonts - > Clear ( ) ;
2020-03-19 08:51:54 +00:00
// Create ranges of characters from m_glyph_ranges, possibly adding some OS specific special characters.
ImVector < ImWchar > ranges ;
ImFontAtlas : : GlyphRangesBuilder builder ;
builder . AddRanges ( m_glyph_ranges ) ;
# ifdef __APPLE__
2020-03-19 12:32:34 +00:00
if ( m_font_cjk )
// Apple keyboard shortcuts are only contained in the CJK fonts.
builder . AddRanges ( ranges_keyboard_shortcuts ) ;
2020-03-19 08:51:54 +00:00
# endif
builder . BuildRanges ( & ranges ) ; // Build the final result (ordered ranges with all the unique characters submitted)
//FIXME replace with io.Fonts->AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, m_font_size, nullptr, ranges.Data);
2019-05-23 16:04:27 +00:00
//https://github.com/ocornut/imgui/issues/220
2020-03-19 08:51:54 +00:00
ImFont * font = io . Fonts - > AddFontFromFileTTF ( ( Slic3r : : resources_dir ( ) + " /fonts/ " + ( m_font_cjk ? " NotoSansCJK-Regular.ttc " : " NotoSans-Regular.ttf " ) ) . c_str ( ) , m_font_size , nullptr , ranges . Data ) ;
2019-01-24 10:30:29 +00:00
if ( font = = nullptr ) {
font = io . Fonts - > AddFontDefault ( ) ;
if ( font = = nullptr ) {
throw std : : runtime_error ( " ImGui: Could not load deafult font " ) ;
}
}
2020-03-19 12:32:34 +00:00
# ifdef __APPLE__
2020-03-19 15:09:52 +00:00
ImFontConfig config ;
config . MergeMode = true ;
if ( ! m_font_cjk ) {
2020-03-19 12:32:34 +00:00
// Apple keyboard shortcuts are only contained in the CJK fonts.
2020-03-19 15:09:52 +00:00
ImFont * font_cjk = io . Fonts - > AddFontFromFileTTF ( ( Slic3r : : resources_dir ( ) + " /fonts/NotoSansCJK-Regular.ttc " ) . c_str ( ) , m_font_size , & config , ranges_keyboard_shortcuts ) ;
assert ( font_cjk ! = nullptr ) ;
}
2020-03-19 12:32:34 +00:00
# endif
2020-05-06 18:45:57 +00:00
float font_scale = m_font_size / 15 ;
int icon_sz = lround ( 16 * font_scale ) ; // default size of icon is 16 px
int rect_id = io . Fonts - > CustomRects . Size ; // id of the rectangle added next
// add rectangles for the icons to the font atlas
for ( auto & icon : font_icons )
io . Fonts - > AddCustomRectFontGlyph ( font , icon . first , icon_sz , icon_sz , 3.0 * font_scale + icon_sz ) ;
2018-10-31 09:19:44 +00:00
// Build texture atlas
unsigned char * pixels ;
int width , height ;
io . Fonts - > GetTexDataAsRGBA32 ( & pixels , & width , & height ) ; // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
2020-05-06 18:45:57 +00:00
// Fill rectangles from the SVG-icons
for ( auto icon : font_icons ) {
if ( const ImFontAtlas : : CustomRect * rect = io . Fonts - > GetCustomRectByIndex ( rect_id ) ) {
std : : vector < unsigned char > raw_data = load_svg ( icon . second , icon_sz , icon_sz ) ;
const ImU32 * pIn = ( ImU32 * ) raw_data . data ( ) ;
for ( int y = 0 ; y < icon_sz ; y + + ) {
ImU32 * pOut = ( ImU32 * ) pixels + ( rect - > Y + y ) * width + ( rect - > X ) ;
for ( int x = 0 ; x < icon_sz ; x + + )
* pOut + + = * pIn + + ;
}
}
rect_id + + ;
}
2018-10-31 09:19:44 +00:00
// Upload texture to graphics system
GLint last_texture ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glGetIntegerv ( GL_TEXTURE_BINDING_2D , & last_texture ) ) ;
glsafe ( : : glGenTextures ( 1 , & m_font_texture ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , m_font_texture ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ) ;
glsafe ( : : glPixelStorei ( GL_UNPACK_ROW_LENGTH , 0 ) ) ;
2019-05-28 10:53:16 +00:00
if ( compress & & GLEW_EXT_texture_compression_s3tc )
2019-05-21 12:19:03 +00:00
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_COMPRESSED_RGBA_S3TC_DXT5_EXT , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , pixels ) ) ;
else
glsafe ( : : glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , pixels ) ) ;
2018-10-31 09:19:44 +00:00
// Store our identifier
io . Fonts - > TexID = ( ImTextureID ) ( intptr_t ) m_font_texture ;
// Restore state
2019-03-27 13:42:09 +00:00
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , last_texture ) ) ;
2018-10-31 09:19:44 +00:00
}
2019-02-15 14:35:32 +00:00
void ImGuiWrapper : : init_input ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
io . KeyMap [ ImGuiKey_Tab ] = WXK_TAB ;
io . KeyMap [ ImGuiKey_LeftArrow ] = WXK_LEFT ;
io . KeyMap [ ImGuiKey_RightArrow ] = WXK_RIGHT ;
io . KeyMap [ ImGuiKey_UpArrow ] = WXK_UP ;
io . KeyMap [ ImGuiKey_DownArrow ] = WXK_DOWN ;
io . KeyMap [ ImGuiKey_PageUp ] = WXK_PAGEUP ;
io . KeyMap [ ImGuiKey_PageDown ] = WXK_PAGEDOWN ;
io . KeyMap [ ImGuiKey_Home ] = WXK_HOME ;
io . KeyMap [ ImGuiKey_End ] = WXK_END ;
io . KeyMap [ ImGuiKey_Insert ] = WXK_INSERT ;
io . KeyMap [ ImGuiKey_Delete ] = WXK_DELETE ;
io . KeyMap [ ImGuiKey_Backspace ] = WXK_BACK ;
io . KeyMap [ ImGuiKey_Space ] = WXK_SPACE ;
io . KeyMap [ ImGuiKey_Enter ] = WXK_RETURN ;
io . KeyMap [ ImGuiKey_Escape ] = WXK_ESCAPE ;
io . KeyMap [ ImGuiKey_A ] = ' A ' ;
io . KeyMap [ ImGuiKey_C ] = ' C ' ;
io . KeyMap [ ImGuiKey_V ] = ' V ' ;
io . KeyMap [ ImGuiKey_X ] = ' X ' ;
io . KeyMap [ ImGuiKey_Y ] = ' Y ' ;
io . KeyMap [ ImGuiKey_Z ] = ' Z ' ;
2019-02-18 15:44:35 +00:00
// Don't let imgui special-case Mac, wxWidgets already do that
io . ConfigMacOSXBehaviors = false ;
2019-02-15 14:35:32 +00:00
// Setup clipboard interaction callbacks
io . SetClipboardTextFn = clipboard_set ;
io . GetClipboardTextFn = clipboard_get ;
io . ClipboardUserData = this ;
}
2019-02-19 13:46:29 +00:00
void ImGuiWrapper : : init_style ( )
{
ImGuiStyle & style = ImGui : : GetStyle ( ) ;
auto set_color = [ & ] ( ImGuiCol_ col , unsigned hex_color ) {
style . Colors [ col ] = ImVec4 (
( ( hex_color > > 24 ) & 0xff ) / 255.0f ,
( ( hex_color > > 16 ) & 0xff ) / 255.0f ,
( ( hex_color > > 8 ) & 0xff ) / 255.0f ,
( hex_color & 0xff ) / 255.0f ) ;
} ;
2019-12-11 14:30:25 +00:00
static const unsigned COL_WINDOW_BACKGROND = 0x222222cc ;
static const unsigned COL_GREY_DARK = 0x555555ff ;
2019-02-19 13:46:29 +00:00
static const unsigned COL_GREY_LIGHT = 0x666666ff ;
2019-02-25 15:47:49 +00:00
static const unsigned COL_ORANGE_DARK = 0xc16737ff ;
static const unsigned COL_ORANGE_LIGHT = 0xff7d38ff ;
2019-02-19 13:46:29 +00:00
2019-12-11 14:30:25 +00:00
// Window
style . WindowRounding = 4.0f ;
set_color ( ImGuiCol_WindowBg , COL_WINDOW_BACKGROND ) ;
2019-02-19 13:46:29 +00:00
set_color ( ImGuiCol_TitleBgActive , COL_ORANGE_DARK ) ;
2019-12-11 14:30:25 +00:00
// Generics
2019-02-19 13:46:29 +00:00
set_color ( ImGuiCol_FrameBg , COL_GREY_DARK ) ;
set_color ( ImGuiCol_FrameBgHovered , COL_GREY_LIGHT ) ;
set_color ( ImGuiCol_FrameBgActive , COL_GREY_LIGHT ) ;
// Text selection
set_color ( ImGuiCol_TextSelectedBg , COL_ORANGE_DARK ) ;
// Buttons
set_color ( ImGuiCol_Button , COL_ORANGE_DARK ) ;
set_color ( ImGuiCol_ButtonHovered , COL_ORANGE_LIGHT ) ;
set_color ( ImGuiCol_ButtonActive , COL_ORANGE_LIGHT ) ;
// Checkbox
set_color ( ImGuiCol_CheckMark , COL_ORANGE_LIGHT ) ;
// ComboBox items
set_color ( ImGuiCol_Header , COL_ORANGE_DARK ) ;
set_color ( ImGuiCol_HeaderHovered , COL_ORANGE_LIGHT ) ;
set_color ( ImGuiCol_HeaderActive , COL_ORANGE_LIGHT ) ;
2019-03-13 13:50:32 +00:00
// Slider
set_color ( ImGuiCol_SliderGrab , COL_ORANGE_DARK ) ;
set_color ( ImGuiCol_SliderGrabActive , COL_ORANGE_LIGHT ) ;
2019-10-02 13:55:26 +00:00
// Separator
set_color ( ImGuiCol_Separator , COL_ORANGE_LIGHT ) ;
2019-02-19 13:46:29 +00:00
}
2018-11-26 09:56:07 +00:00
void ImGuiWrapper : : render_draw_data ( ImDrawData * draw_data )
2018-10-31 09:19:44 +00:00
{
2018-11-27 14:35:30 +00:00
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
2018-10-31 09:19:44 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
int fb_width = ( int ) ( draw_data - > DisplaySize . x * io . DisplayFramebufferScale . x ) ;
int fb_height = ( int ) ( draw_data - > DisplaySize . y * io . DisplayFramebufferScale . y ) ;
2018-11-27 11:10:21 +00:00
if ( fb_width = = 0 | | fb_height = = 0 )
2018-10-31 09:19:44 +00:00
return ;
draw_data - > ScaleClipRects ( io . DisplayFramebufferScale ) ;
2018-11-27 11:10:21 +00:00
// We are using the OpenGL fixed pipeline to make the example code simpler to read!
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
2019-03-27 13:42:09 +00:00
GLint last_texture ; glsafe ( : : glGetIntegerv ( GL_TEXTURE_BINDING_2D , & last_texture ) ) ;
GLint last_polygon_mode [ 2 ] ; glsafe ( : : glGetIntegerv ( GL_POLYGON_MODE , last_polygon_mode ) ) ;
GLint last_viewport [ 4 ] ; glsafe ( : : glGetIntegerv ( GL_VIEWPORT , last_viewport ) ) ;
GLint last_scissor_box [ 4 ] ; glsafe ( : : glGetIntegerv ( GL_SCISSOR_BOX , last_scissor_box ) ) ;
glsafe ( : : glPushAttrib ( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT ) ) ;
glsafe ( : : glEnable ( GL_BLEND ) ) ;
glsafe ( : : glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ) ;
glsafe ( : : glDisable ( GL_CULL_FACE ) ) ;
glsafe ( : : glDisable ( GL_DEPTH_TEST ) ) ;
glsafe ( : : glDisable ( GL_LIGHTING ) ) ;
glsafe ( : : glDisable ( GL_COLOR_MATERIAL ) ) ;
glsafe ( : : glEnable ( GL_SCISSOR_TEST ) ) ;
glsafe ( : : glEnableClientState ( GL_VERTEX_ARRAY ) ) ;
glsafe ( : : glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ) ;
glsafe ( : : glEnableClientState ( GL_COLOR_ARRAY ) ) ;
glsafe ( : : glEnable ( GL_TEXTURE_2D ) ) ;
glsafe ( : : glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ) ;
glsafe ( : : glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ) ;
2018-11-27 14:35:30 +00:00
GLint texture_env_mode = GL_MODULATE ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glGetTexEnviv ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , & texture_env_mode ) ) ;
glsafe ( : : glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , GL_MODULATE ) ) ;
2018-11-27 11:10:21 +00:00
//glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound
2018-10-31 09:19:44 +00:00
// Setup viewport, orthographic projection matrix
2018-11-27 11:10:21 +00:00
// Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
2019-03-27 13:42:09 +00:00
glsafe ( : : glViewport ( 0 , 0 , ( GLsizei ) fb_width , ( GLsizei ) fb_height ) ) ;
glsafe ( : : glMatrixMode ( GL_PROJECTION ) ) ;
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glLoadIdentity ( ) ) ;
glsafe ( : : glOrtho ( draw_data - > DisplayPos . x , draw_data - > DisplayPos . x + draw_data - > DisplaySize . x , draw_data - > DisplayPos . y + draw_data - > DisplaySize . y , draw_data - > DisplayPos . y , - 1.0f , + 1.0f ) ) ;
glsafe ( : : glMatrixMode ( GL_MODELVIEW ) ) ;
glsafe ( : : glPushMatrix ( ) ) ;
glsafe ( : : glLoadIdentity ( ) ) ;
2018-11-27 11:10:21 +00:00
// Render command lists
2018-10-31 09:19:44 +00:00
ImVec2 pos = draw_data - > DisplayPos ;
for ( int n = 0 ; n < draw_data - > CmdListsCount ; n + + )
{
const ImDrawList * cmd_list = draw_data - > CmdLists [ n ] ;
2018-11-27 11:10:21 +00:00
const ImDrawVert * vtx_buffer = cmd_list - > VtxBuffer . Data ;
const ImDrawIdx * idx_buffer = cmd_list - > IdxBuffer . Data ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glVertexPointer ( 2 , GL_FLOAT , sizeof ( ImDrawVert ) , ( const GLvoid * ) ( ( const char * ) vtx_buffer + IM_OFFSETOF ( ImDrawVert , pos ) ) ) ) ;
glsafe ( : : glTexCoordPointer ( 2 , GL_FLOAT , sizeof ( ImDrawVert ) , ( const GLvoid * ) ( ( const char * ) vtx_buffer + IM_OFFSETOF ( ImDrawVert , uv ) ) ) ) ;
glsafe ( : : glColorPointer ( 4 , GL_UNSIGNED_BYTE , sizeof ( ImDrawVert ) , ( const GLvoid * ) ( ( const char * ) vtx_buffer + IM_OFFSETOF ( ImDrawVert , col ) ) ) ) ;
2018-10-31 09:19:44 +00:00
for ( int cmd_i = 0 ; cmd_i < cmd_list - > CmdBuffer . Size ; cmd_i + + )
{
const ImDrawCmd * pcmd = & cmd_list - > CmdBuffer [ cmd_i ] ;
if ( pcmd - > UserCallback )
{
// User callback (registered via ImDrawList::AddCallback)
pcmd - > UserCallback ( cmd_list , pcmd ) ;
}
else
{
ImVec4 clip_rect = ImVec4 ( pcmd - > ClipRect . x - pos . x , pcmd - > ClipRect . y - pos . y , pcmd - > ClipRect . z - pos . x , pcmd - > ClipRect . w - pos . y ) ;
if ( clip_rect . x < fb_width & & clip_rect . y < fb_height & & clip_rect . z > = 0.0f & & clip_rect . w > = 0.0f )
{
// Apply scissor/clipping rectangle
2019-03-27 13:42:09 +00:00
glsafe ( : : glScissor ( ( int ) clip_rect . x , ( int ) ( fb_height - clip_rect . w ) , ( int ) ( clip_rect . z - clip_rect . x ) , ( int ) ( clip_rect . w - clip_rect . y ) ) ) ;
2018-10-31 09:19:44 +00:00
// Bind texture, Draw
2019-03-27 13:42:09 +00:00
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , ( GLuint ) ( intptr_t ) pcmd - > TextureId ) ) ;
glsafe ( : : glDrawElements ( GL_TRIANGLES , ( GLsizei ) pcmd - > ElemCount , sizeof ( ImDrawIdx ) = = 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT , idx_buffer ) ) ;
2018-10-31 09:19:44 +00:00
}
}
2018-11-27 11:10:21 +00:00
idx_buffer + = pcmd - > ElemCount ;
2018-10-31 09:19:44 +00:00
}
}
2018-11-27 11:10:21 +00:00
// Restore modified state
2019-03-27 13:42:09 +00:00
glsafe ( : : glTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , texture_env_mode ) ) ;
glsafe ( : : glDisableClientState ( GL_COLOR_ARRAY ) ) ;
glsafe ( : : glDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ) ;
glsafe ( : : glDisableClientState ( GL_VERTEX_ARRAY ) ) ;
glsafe ( : : glBindTexture ( GL_TEXTURE_2D , ( GLuint ) last_texture ) ) ;
glsafe ( : : glMatrixMode ( GL_MODELVIEW ) ) ;
glsafe ( : : glPopMatrix ( ) ) ;
glsafe ( : : glMatrixMode ( GL_PROJECTION ) ) ;
glsafe ( : : glPopMatrix ( ) ) ;
glsafe ( : : glPopAttrib ( ) ) ;
glsafe ( : : glPolygonMode ( GL_FRONT , ( GLenum ) last_polygon_mode [ 0 ] ) ; glPolygonMode ( GL_BACK , ( GLenum ) last_polygon_mode [ 1 ] ) ) ;
glsafe ( : : glViewport ( last_viewport [ 0 ] , last_viewport [ 1 ] , ( GLsizei ) last_viewport [ 2 ] , ( GLsizei ) last_viewport [ 3 ] ) ) ;
glsafe ( : : glScissor ( last_scissor_box [ 0 ] , last_scissor_box [ 1 ] , ( GLsizei ) last_scissor_box [ 2 ] , ( GLsizei ) last_scissor_box [ 3 ] ) ) ;
2018-10-31 09:19:44 +00:00
}
2019-02-22 13:52:32 +00:00
bool ImGuiWrapper : : display_initialized ( ) const
{
const ImGuiIO & io = ImGui : : GetIO ( ) ;
return io . DisplaySize . x > = 0.0f & & io . DisplaySize . y > = 0.0f ;
}
2019-04-01 12:12:05 +00:00
void ImGuiWrapper : : destroy_font ( )
2018-10-31 09:19:44 +00:00
{
2019-04-01 12:12:05 +00:00
if ( m_font_texture ! = 0 ) {
2018-10-31 09:19:44 +00:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
io . Fonts - > TexID = 0 ;
2019-03-27 13:42:09 +00:00
glsafe ( : : glDeleteTextures ( 1 , & m_font_texture ) ) ;
2018-10-31 09:19:44 +00:00
m_font_texture = 0 ;
}
}
2019-02-15 14:35:32 +00:00
const char * ImGuiWrapper : : clipboard_get ( void * user_data )
{
ImGuiWrapper * self = reinterpret_cast < ImGuiWrapper * > ( user_data ) ;
const char * res = " " ;
if ( wxTheClipboard - > Open ( ) ) {
if ( wxTheClipboard - > IsSupported ( wxDF_TEXT ) ) {
wxTextDataObject data ;
wxTheClipboard - > GetData ( data ) ;
if ( data . GetTextLength ( ) > 0 ) {
2019-02-19 11:39:24 +00:00
self - > m_clipboard_text = into_u8 ( data . GetText ( ) ) ;
res = self - > m_clipboard_text . c_str ( ) ;
2019-02-15 14:35:32 +00:00
}
}
wxTheClipboard - > Close ( ) ;
}
return res ;
}
void ImGuiWrapper : : clipboard_set ( void * /* user_data */ , const char * text )
{
if ( wxTheClipboard - > Open ( ) ) {
wxTheClipboard - > SetData ( new wxTextDataObject ( wxString : : FromUTF8 ( text ) ) ) ; // object owned by the clipboard
wxTheClipboard - > Close ( ) ;
}
}
2018-11-27 14:35:30 +00:00
2018-10-31 09:19:44 +00:00
} // namespace GUI
} // namespace Slic3r