mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-13 17:53:11 +02:00
Compare commits
108 Commits
606fa10984
...
3c608d7ab5
Author | SHA1 | Date | |
---|---|---|---|
|
3c608d7ab5 | ||
|
5dc6d43f43 | ||
|
98dd5a68eb | ||
|
18b56539a6 | ||
|
9b006c4f3b | ||
|
8035a66152 | ||
|
45166bf5c3 | ||
|
6ab6283e2e | ||
|
fc7d91214d | ||
|
dcbadb5857 | ||
|
3b97804cb6 | ||
|
e72def55a9 | ||
|
fcf40deae2 | ||
|
ef602be91f | ||
|
bd5cb76fcd | ||
|
de26550b5a | ||
|
7deff606be | ||
|
6e2b20ed0e | ||
|
2f1a91279f | ||
|
6e316d9faa | ||
|
3c5fb9d90d | ||
|
11cc86e586 | ||
|
5e2fd084b9 | ||
|
a1f816e8be | ||
|
abf3438ed6 | ||
|
cb4c8e6647 | ||
|
d356073798 | ||
|
b38d9d7f81 | ||
|
297ca1bb7b | ||
|
f9e25c2e06 | ||
|
b0a6dc4acf | ||
|
59dcdb4a4f | ||
|
39889f8446 | ||
|
3f8abe3744 | ||
|
0acc659676 | ||
|
78c93ee0fb | ||
|
9622cf8ff1 | ||
|
3cca1e87d8 | ||
|
aac15f4596 | ||
|
ceed9ca5f8 | ||
|
6c4edd178e | ||
|
cfa87cfc2c | ||
|
b3b75270ce | ||
|
f1db857804 | ||
|
cdd43fe5fa | ||
|
836b3267bb | ||
|
66930ea703 | ||
|
0e60722c4b | ||
|
2b3f21b9ff | ||
|
dd8a059925 | ||
|
63fe36847e | ||
|
99a16e4306 | ||
|
5ca8fdb7cd | ||
|
88ee07e910 | ||
|
71907f0888 | ||
|
6397b6d3c6 | ||
|
d1356140fa | ||
|
30d158a60f | ||
|
c674e1749e | ||
|
c783218f93 | ||
|
07885145b3 | ||
|
500da3c15d | ||
|
fbd2e36b79 | ||
|
61fd5e7413 | ||
|
bf8d2d7bf6 | ||
|
2a93e1bfb1 | ||
|
9f097d5ae8 | ||
|
80996e70f8 | ||
|
ec8131c7bf | ||
|
2ad7c345ec | ||
|
a2e0d07c87 | ||
|
4e1dd875ae | ||
|
c737e0b360 | ||
|
c29aa7643c | ||
|
58b2ccb3d5 | ||
|
a05f8b9e36 | ||
|
9f2b84ba52 | ||
|
b345e34423 | ||
|
081b414ad5 | ||
|
58caa5c496 | ||
|
f0f5472e4d | ||
|
0b174b5227 | ||
|
765838ecf7 | ||
|
2276ae05e3 | ||
|
6838d55051 | ||
|
95abb3be8b | ||
|
41425ac32d | ||
|
0b47169387 | ||
|
7b98a8d697 | ||
|
4184e60e24 | ||
|
36eb0e4a11 | ||
|
49c7f62548 | ||
|
35f0213011 | ||
|
cb87f83dfc | ||
|
ead7de69ca | ||
|
dedc10a163 | ||
|
330361d0cb | ||
|
01d32211ba | ||
|
09c40a0e0f | ||
|
fdbf740ee2 | ||
|
93b0004175 | ||
|
0a162ded84 | ||
|
01f6776226 | ||
|
adbc80aade | ||
|
0b102fc085 | ||
|
22288e02a2 | ||
|
58f4ca7ed6 | ||
|
7664d92028 |
@ -9,6 +9,7 @@ win64_build:
|
||||
image: registry.gitlab.com/kicad/kicad-ci/windows-build-image/ltsc2022-msvc:latest
|
||||
variables:
|
||||
VCPKG_BINARY_SOURCES: 'nuget,gitlab,readwrite'
|
||||
VCPKG_DISABLE_COMPILER_TRACKING: '1'
|
||||
# Switch the compressor to fastzip and reduce the compression level
|
||||
FF_USE_FASTZIP: "true"
|
||||
CACHE_COMPRESSION_LEVEL: "fast"
|
||||
@ -39,8 +40,6 @@ win64_build:
|
||||
../../
|
||||
- cmake --build . 2>&1 | tee compilation_log.txt
|
||||
- cd ../../
|
||||
after_script:
|
||||
- Get-Content -Path C:\builder\vcpkg\buildtrees\wxpython-33\python3-tool-post-install-err.log
|
||||
artifacts:
|
||||
# Only save the artifacts that are needed for running the tests in the next stage
|
||||
# and the compilation log. The entire build directory is too large to save as an
|
||||
|
@ -35,14 +35,22 @@
|
||||
#include <advanced_config.h>
|
||||
#include <build_version.h>
|
||||
#include <board.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_field.h>
|
||||
#include <reporter.h>
|
||||
#include <gal/opengl/gl_context_mgr.h>
|
||||
#include <core/profile.h> // To use GetRunningMicroSecs or another profiling utility
|
||||
#include <bitmaps.h>
|
||||
#include <kiway_holder.h>
|
||||
#include <kiway.h>
|
||||
#include <macros.h>
|
||||
#include <pgm_base.h>
|
||||
#include <settings/settings_manager.h>
|
||||
#include <tool/tool_dispatcher.h>
|
||||
#include <string_utils.h>
|
||||
#include <mail_type.h>
|
||||
#include <kiway_express.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <widgets/wx_busy_indicator.h>
|
||||
|
||||
@ -92,28 +100,12 @@ END_EVENT_TABLE()
|
||||
EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow* aParent, const wxGLAttributes& aGLAttribs,
|
||||
BOARD_ADAPTER& aBoardAdapter, CAMERA& aCamera,
|
||||
S3D_CACHE* a3DCachePointer ) :
|
||||
HIDPI_GL_3D_CANVAS( EDA_DRAW_PANEL_GAL::GetVcSettings(), aCamera, aParent, aGLAttribs,
|
||||
EDA_3D_CANVAS_ID, wxDefaultPosition,
|
||||
wxDefaultSize, wxFULL_REPAINT_ON_RESIZE ),
|
||||
m_eventDispatcher( nullptr ),
|
||||
m_parentStatusBar( nullptr ),
|
||||
m_parentInfoBar( nullptr ),
|
||||
m_glRC( nullptr ),
|
||||
m_is_opengl_initialized( false ),
|
||||
m_is_opengl_version_supported( true ),
|
||||
m_editing_timeout_timer( this, wxID_HIGHEST + 1 ),
|
||||
m_redraw_trigger_timer( this, wxID_HIGHEST + 2 ),
|
||||
m_render_pivot( false ),
|
||||
m_camera_moving_speed( 1.0f ),
|
||||
m_strtime_camera_movement( 0 ),
|
||||
m_animation_enabled( true ),
|
||||
m_moving_speed_multiplier( 3 ),
|
||||
m_boardAdapter( aBoardAdapter ),
|
||||
m_3d_render( nullptr ),
|
||||
m_opengl_supports_raytracing( true ),
|
||||
m_render_raytracing_was_requested( false ),
|
||||
m_accelerator3DShapes( nullptr ),
|
||||
m_currentRollOverItem( nullptr )
|
||||
HIDPI_GL_3D_CANVAS( EDA_DRAW_PANEL_GAL::GetVcSettings(), aCamera, aParent, aGLAttribs,
|
||||
EDA_3D_CANVAS_ID, wxDefaultPosition,
|
||||
wxDefaultSize, wxFULL_REPAINT_ON_RESIZE ),
|
||||
m_editing_timeout_timer( this, wxID_HIGHEST + 1 ),
|
||||
m_redraw_trigger_timer( this, wxID_HIGHEST + 2 ),
|
||||
m_boardAdapter( aBoardAdapter )
|
||||
{
|
||||
wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::EDA_3D_CANVAS" ) );
|
||||
|
||||
@ -481,8 +473,10 @@ void EDA_3D_CANVAS::DoRePaint()
|
||||
|
||||
if( m_camera_is_moving )
|
||||
{
|
||||
const int64_t curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
|
||||
curtime_delta_s = ( curtime_delta / 1e6 ) * m_camera_moving_speed;
|
||||
const int64_t curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
|
||||
// Convert microseconds to seconds as float and apply speed multiplier
|
||||
curtime_delta_s = static_cast<float>( static_cast<double>( curtime_delta ) / 1e6 )
|
||||
* m_camera_moving_speed;
|
||||
m_camera.Interpolate( curtime_delta_s );
|
||||
|
||||
if( curtime_delta_s > 1.0f )
|
||||
@ -751,7 +745,8 @@ void EDA_3D_CANVAS::RenderToFrameBuffer( unsigned char* buffer, int width, int h
|
||||
if( m_camera_is_moving )
|
||||
{
|
||||
const int64_t curtime_delta = GetRunningMicroSecs() - m_strtime_camera_movement;
|
||||
curtime_delta_s = ( curtime_delta / 1e6 ) * m_camera_moving_speed;
|
||||
curtime_delta_s = static_cast<float>( static_cast<double>( curtime_delta ) / 1e6 )
|
||||
* m_camera_moving_speed;
|
||||
m_camera.Interpolate( curtime_delta_s );
|
||||
|
||||
if( curtime_delta_s > 1.0f )
|
||||
@ -887,7 +882,7 @@ void EDA_3D_CANVAS::OnZoomGesture( wxZoomGestureEvent& aEvent )
|
||||
m_camera.Pan( aEvent.GetPosition() );
|
||||
m_camera.SetCurMousePosition( aEvent.GetPosition() );
|
||||
|
||||
m_camera.Zoom( aEvent.GetZoomFactor() / m_gestureLastZoomFactor );
|
||||
m_camera.Zoom( static_cast<float>( aEvent.GetZoomFactor() / m_gestureLastZoomFactor ) );
|
||||
|
||||
m_gestureLastZoomFactor = aEvent.GetZoomFactor();
|
||||
|
||||
@ -930,7 +925,7 @@ void EDA_3D_CANVAS::OnRotateGesture( wxRotateGestureEvent& aEvent )
|
||||
if( m_camera_is_moving )
|
||||
return;
|
||||
|
||||
m_camera.RotateScreen( m_gestureLastAngle - aEvent.GetRotationAngle() );
|
||||
m_camera.RotateScreen( static_cast<float>( m_gestureLastAngle - aEvent.GetRotationAngle() ) );
|
||||
m_gestureLastAngle = aEvent.GetRotationAngle();
|
||||
|
||||
DisplayStatus();
|
||||
@ -1066,9 +1061,45 @@ void EDA_3D_CANVAS::OnLeftDown( wxMouseEvent& event )
|
||||
{
|
||||
RAY mouseRay = getRayAtCurrentMousePosition();
|
||||
|
||||
BOARD_ITEM *intersectedBoardItem = m_3d_render_raytracing->IntersectBoardItem( mouseRay );
|
||||
BOARD_ITEM* intersectedBoardItem = m_3d_render_raytracing->IntersectBoardItem( mouseRay );
|
||||
|
||||
// !TODO: send a selection item to pcbnew, eg: via kiway?
|
||||
if( intersectedBoardItem )
|
||||
{
|
||||
FOOTPRINT* footprint = nullptr;
|
||||
|
||||
switch( intersectedBoardItem->Type() )
|
||||
{
|
||||
case PCB_FOOTPRINT_T:
|
||||
footprint = static_cast<FOOTPRINT*>( intersectedBoardItem );
|
||||
break;
|
||||
|
||||
case PCB_PAD_T:
|
||||
footprint = static_cast<PAD*>( intersectedBoardItem )->GetParentFootprint();
|
||||
break;
|
||||
|
||||
case PCB_FIELD_T:
|
||||
footprint = static_cast<PCB_FIELD*>( intersectedBoardItem )->GetParentFootprint();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( footprint )
|
||||
{
|
||||
std::string command =
|
||||
fmt::format( "$SELECT: 0,F{}",
|
||||
EscapeString( footprint->GetReference(), CTX_IPC ).ToStdString() );
|
||||
|
||||
EDA_3D_VIEWER_FRAME* frame = static_cast<EDA_3D_VIEWER_FRAME*>( GetParent() );
|
||||
|
||||
if( frame )
|
||||
{
|
||||
frame->Kiway().ExpressMail( FRAME_PCB_EDITOR, MAIL_SELECTION, command, frame );
|
||||
frame->Kiway().ExpressMail( FRAME_SCH, MAIL_SELECTION, command, frame );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1088,14 +1119,14 @@ void EDA_3D_CANVAS::OnLeftUp( wxMouseEvent& event )
|
||||
int logicalW = logicalSize.GetWidth();
|
||||
int logicalH = logicalSize.GetHeight();
|
||||
|
||||
int gizmo_x, gizmo_y, gizmo_width, gizmo_height;
|
||||
int gizmo_x = 0, gizmo_y = 0, gizmo_width = 0, gizmo_height = 0;
|
||||
std::tie( gizmo_x, gizmo_y, gizmo_width, gizmo_height ) = m_3d_render_opengl->getGizmoViewport();
|
||||
|
||||
float scaleX = static_cast<float>( gizmo_width ) / logicalW;
|
||||
float scaleY = static_cast<float>( gizmo_height ) / logicalH;
|
||||
float scaleX = static_cast<float>( static_cast<double>( gizmo_width ) / static_cast<double>( logicalW ) );
|
||||
float scaleY = static_cast<float>( static_cast<double>( gizmo_height ) / static_cast<double>( logicalH ) );
|
||||
|
||||
int scaledMouseX = static_cast<int>( event.GetX() * scaleX );
|
||||
int scaledMouseY = static_cast<int>( ( logicalH - event.GetY() ) * scaleY );
|
||||
int scaledMouseX = static_cast<int>( static_cast<float>( event.GetX() ) * scaleX );
|
||||
int scaledMouseY = static_cast<int>( static_cast<float>( logicalH - event.GetY() ) * scaleY );
|
||||
|
||||
m_3d_render_opengl->handleGizmoMouseInput( scaledMouseX, scaledMouseY );
|
||||
Refresh();
|
||||
@ -1229,7 +1260,7 @@ void EDA_3D_CANVAS::request_start_moving_camera( float aMovingSpeed, bool aRende
|
||||
|
||||
// Map speed multiplier option to actual multiplier value
|
||||
// [1,2,3,4,5] -> [0.25, 0.5, 1, 2, 4]
|
||||
aMovingSpeed *= ( 1 << m_moving_speed_multiplier ) / 8.0f;
|
||||
aMovingSpeed *= static_cast<float>( ( 1 << m_moving_speed_multiplier ) ) / 8.0f;
|
||||
|
||||
m_render_pivot = aRenderPivot;
|
||||
m_camera_moving_speed = aMovingSpeed;
|
||||
@ -1249,7 +1280,7 @@ void EDA_3D_CANVAS::move_pivot_based_on_cur_mouse_position()
|
||||
{
|
||||
RAY mouseRay = getRayAtCurrentMousePosition();
|
||||
|
||||
float hit_t;
|
||||
float hit_t = 0.0f;
|
||||
|
||||
// Test it with the board bounding box
|
||||
if( m_boardAdapter.GetBBox().Intersect( mouseRay, &hit_t ) )
|
||||
|
@ -42,7 +42,7 @@ class RENDER_3D_RAYTRACE_GL;
|
||||
class RENDER_3D_OPENGL;
|
||||
|
||||
|
||||
#define EDA_3D_CANVAS_ID wxID_HIGHEST + 1321
|
||||
#define EDA_3D_CANVAS_ID (wxID_HIGHEST + 1321)
|
||||
|
||||
/**
|
||||
* Implement a canvas based on a wxGLCanvas
|
||||
@ -61,7 +61,7 @@ public:
|
||||
EDA_3D_CANVAS( wxWindow* aParent, const wxGLAttributes& aGLAttribs, BOARD_ADAPTER& aSettings,
|
||||
CAMERA& aCamera, S3D_CACHE* a3DCachePointer );
|
||||
|
||||
~EDA_3D_CANVAS();
|
||||
~EDA_3D_CANVAS() override;
|
||||
|
||||
/**
|
||||
* Set a dispatcher that processes events and forwards them to tools.
|
||||
@ -302,36 +302,36 @@ private:
|
||||
RAY getRayAtCurrentMousePosition();
|
||||
|
||||
private:
|
||||
TOOL_DISPATCHER* m_eventDispatcher;
|
||||
wxStatusBar* m_parentStatusBar; // Parent statusbar to report progress
|
||||
WX_INFOBAR* m_parentInfoBar;
|
||||
TOOL_DISPATCHER* m_eventDispatcher = nullptr;
|
||||
wxStatusBar* m_parentStatusBar = nullptr; // Parent statusbar to report progress
|
||||
WX_INFOBAR* m_parentInfoBar = nullptr;
|
||||
|
||||
wxGLContext* m_glRC; // Current OpenGL context
|
||||
bool m_is_opengl_initialized;
|
||||
bool m_is_opengl_version_supported;
|
||||
wxGLContext* m_glRC = nullptr; // Current OpenGL context
|
||||
bool m_is_opengl_initialized = false;
|
||||
bool m_is_opengl_version_supported = true;
|
||||
|
||||
wxTimer m_editing_timeout_timer; // Expires after some time signaling that
|
||||
// the mouse / keyboard movements are over
|
||||
wxTimer m_redraw_trigger_timer; // Used to schedule a redraw event
|
||||
std::atomic_flag m_is_currently_painting; // Avoid drawing twice at the same time
|
||||
std::atomic_flag m_is_currently_painting = ATOMIC_FLAG_INIT; // Avoid drawing twice at the same time
|
||||
|
||||
bool m_render_pivot; // Render the pivot while camera moving
|
||||
float m_camera_moving_speed; // 1.0f will be 1:1
|
||||
int64_t m_strtime_camera_movement; // Ticktime of camera movement start
|
||||
bool m_animation_enabled; // Camera animation enabled
|
||||
int m_moving_speed_multiplier; // Camera animation speed multiplier option
|
||||
bool m_render_pivot = false; // Render the pivot while camera moving
|
||||
float m_camera_moving_speed = 1.0f; // 1.0f will be 1:1
|
||||
int64_t m_strtime_camera_movement = 0; // Ticktime of camera movement start
|
||||
bool m_animation_enabled = true; // Camera animation enabled
|
||||
int m_moving_speed_multiplier = 3; // Camera animation speed multiplier option
|
||||
|
||||
BOARD_ADAPTER& m_boardAdapter; // Pre-computed 3D info and settings
|
||||
RENDER_3D_BASE* m_3d_render;
|
||||
RENDER_3D_BASE* m_3d_render = nullptr;
|
||||
RENDER_3D_RAYTRACE_GL* m_3d_render_raytracing;
|
||||
RENDER_3D_OPENGL* m_3d_render_opengl;
|
||||
|
||||
bool m_opengl_supports_raytracing;
|
||||
bool m_render_raytracing_was_requested;
|
||||
bool m_opengl_supports_raytracing = true;
|
||||
bool m_render_raytracing_was_requested = false;
|
||||
|
||||
ACCELERATOR_3D* m_accelerator3DShapes; // used for mouse over searching
|
||||
ACCELERATOR_3D* m_accelerator3DShapes = nullptr; // used for mouse over searching
|
||||
|
||||
BOARD_ITEM* m_currentRollOverItem;
|
||||
BOARD_ITEM* m_currentRollOverItem = nullptr;
|
||||
|
||||
bool m_render3dmousePivot = false; // Render the 3dmouse pivot
|
||||
SFVEC3F m_3dmousePivotPos; // The position of the 3dmouse pivot
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "render_3d_opengl.h"
|
||||
#include <board.h>
|
||||
#include <footprint.h>
|
||||
#include <pcb_track.h>
|
||||
#include "../../3d_math.h"
|
||||
#include "convert_basic_shapes_to_polygon.h"
|
||||
#include <lset.h>
|
||||
@ -726,6 +727,54 @@ void RENDER_3D_OPENGL::generateCylinder( const SFVEC2F& aCenter, float aInnerRad
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::generateDisk( const SFVEC2F& aCenter, float aRadius, float aZ,
|
||||
unsigned int aNr_sides_per_circle, TRIANGLE_DISPLAY_LIST* aDstLayer,
|
||||
bool aTop )
|
||||
{
|
||||
const float delta = 2.0f * glm::pi<float>() / (float) aNr_sides_per_circle;
|
||||
|
||||
for( unsigned int i = 0; i < aNr_sides_per_circle; ++i )
|
||||
{
|
||||
float a0 = delta * i;
|
||||
float a1 = delta * ( i + 1 );
|
||||
const SFVEC3F p0( aCenter.x + cosf( a0 ) * aRadius,
|
||||
aCenter.y + sinf( a0 ) * aRadius, aZ );
|
||||
const SFVEC3F p1( aCenter.x + cosf( a1 ) * aRadius,
|
||||
aCenter.y + sinf( a1 ) * aRadius, aZ );
|
||||
const SFVEC3F c( aCenter.x, aCenter.y, aZ );
|
||||
|
||||
if( aTop )
|
||||
aDstLayer->m_layer_top_triangles->AddTriangle( p1, p0, c );
|
||||
else
|
||||
aDstLayer->m_layer_bot_triangles->AddTriangle( p0, p1, c );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::generateDimple( const SFVEC2F& aCenter, float aRadius, float aZ,
|
||||
float aDepth, unsigned int aNr_sides_per_circle,
|
||||
TRIANGLE_DISPLAY_LIST* aDstLayer, bool aTop )
|
||||
{
|
||||
const float delta = 2.0f * glm::pi<float>() / (float) aNr_sides_per_circle;
|
||||
const SFVEC3F c( aCenter.x, aCenter.y, aTop ? aZ - aDepth : aZ + aDepth );
|
||||
|
||||
for( unsigned int i = 0; i < aNr_sides_per_circle; ++i )
|
||||
{
|
||||
float a0 = delta * i;
|
||||
float a1 = delta * ( i + 1 );
|
||||
const SFVEC3F p0( aCenter.x + cosf( a0 ) * aRadius,
|
||||
aCenter.y + sinf( a0 ) * aRadius, aZ );
|
||||
const SFVEC3F p1( aCenter.x + cosf( a1 ) * aRadius,
|
||||
aCenter.y + sinf( a1 ) * aRadius, aZ );
|
||||
|
||||
if( aTop )
|
||||
aDstLayer->m_layer_top_triangles->AddTriangle( p0, p1, c );
|
||||
else
|
||||
aDstLayer->m_layer_bot_triangles->AddTriangle( p1, p0, c );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RENDER_3D_OPENGL::generateViasAndPads()
|
||||
{
|
||||
if( !m_boardAdapter.GetBoard() )
|
||||
@ -882,6 +931,63 @@ void RENDER_3D_OPENGL::generateViasAndPads()
|
||||
delete layerTriangles;
|
||||
}
|
||||
}
|
||||
|
||||
TRIANGLE_DISPLAY_LIST* frontCover = new TRIANGLE_DISPLAY_LIST( m_boardAdapter.GetViaCount() );
|
||||
TRIANGLE_DISPLAY_LIST* backCover = new TRIANGLE_DISPLAY_LIST( m_boardAdapter.GetViaCount() );
|
||||
|
||||
for( const PCB_TRACK* track : m_boardAdapter.GetBoard()->Tracks() )
|
||||
{
|
||||
if( track->Type() != PCB_VIA_T )
|
||||
continue;
|
||||
|
||||
const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
|
||||
|
||||
const float holediameter = via->GetDrillValue() * m_boardAdapter.BiuTo3dUnits();
|
||||
const float hole_radius = holediameter / 2.0f + 2.0 * platingThickness3d;
|
||||
const SFVEC2F center( via->GetStart().x * m_boardAdapter.BiuTo3dUnits(),
|
||||
-via->GetStart().y * m_boardAdapter.BiuTo3dUnits() );
|
||||
unsigned int seg = m_boardAdapter.GetCircleSegmentCount( via->GetDrillValue() );
|
||||
|
||||
PCB_LAYER_ID top_layer, bottom_layer;
|
||||
via->LayerPair( &top_layer, &bottom_layer );
|
||||
float ztop, zbot, dummy;
|
||||
getLayerZPos( top_layer, ztop, dummy );
|
||||
getLayerZPos( bottom_layer, dummy, zbot );
|
||||
|
||||
bool frontCovering = via->GetFrontCoveringMode() == COVERING_MODE::COVERED || via->IsTented( F_Mask );
|
||||
bool backCovering = via->GetBackCoveringMode() == COVERING_MODE::COVERED || via->IsTented( B_Mask );
|
||||
bool frontPlugged = via->GetFrontPluggingMode() == PLUGGING_MODE::PLUGGED;
|
||||
bool backPlugged = via->GetBackPluggingMode() == PLUGGING_MODE::PLUGGED;
|
||||
bool filled = via->GetFillingMode() == FILLING_MODE::FILLED
|
||||
|| via->GetCappingMode() == CAPPING_MODE::CAPPED;
|
||||
|
||||
const float depth = hole_radius * 0.3f;
|
||||
|
||||
if( frontCovering )
|
||||
{
|
||||
if( filled || !frontPlugged )
|
||||
generateDisk( center, hole_radius, ztop, seg, frontCover, true );
|
||||
else
|
||||
generateDimple( center, hole_radius, ztop, depth, seg, frontCover, true );
|
||||
}
|
||||
|
||||
if( backCovering )
|
||||
{
|
||||
if( filled || !backPlugged )
|
||||
generateDisk( center, hole_radius, zbot, seg, backCover, false );
|
||||
else
|
||||
generateDimple( center, hole_radius, zbot, depth, seg, backCover, false );
|
||||
}
|
||||
}
|
||||
|
||||
if( frontCover->m_layer_top_triangles->GetVertexSize() > 0 )
|
||||
m_viaFrontCover = new OPENGL_RENDER_LIST( *frontCover, 0, 0.0f, 0.0f );
|
||||
|
||||
if( backCover->m_layer_bot_triangles->GetVertexSize() > 0 )
|
||||
m_viaBackCover = new OPENGL_RENDER_LIST( *backCover, 0, 0.0f, 0.0f );
|
||||
|
||||
delete frontCover;
|
||||
delete backCover;
|
||||
}
|
||||
|
||||
|
||||
|
@ -72,6 +72,8 @@ RENDER_3D_OPENGL::RENDER_3D_OPENGL( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& aAdap
|
||||
m_outerViaThroughHoles = nullptr;
|
||||
m_microviaHoles = nullptr;
|
||||
m_padHoles = nullptr;
|
||||
m_viaFrontCover = nullptr;
|
||||
m_viaBackCover = nullptr;
|
||||
|
||||
m_circleTexture = 0;
|
||||
m_grid = 0;
|
||||
@ -947,6 +949,8 @@ void RENDER_3D_OPENGL::freeAllLists()
|
||||
|
||||
DELETE_AND_FREE( m_microviaHoles )
|
||||
DELETE_AND_FREE( m_padHoles )
|
||||
DELETE_AND_FREE( m_viaFrontCover )
|
||||
DELETE_AND_FREE( m_viaBackCover )
|
||||
}
|
||||
|
||||
|
||||
@ -968,6 +972,17 @@ void RENDER_3D_OPENGL::renderSolderMaskLayer( PCB_LAYER_ID aLayerID, float aZPos
|
||||
setLayerMaterial( aLayerID );
|
||||
m_board->SetItIsTransparent( true );
|
||||
m_board->DrawCulled( aShowThickness, solder_mask, via_holes );
|
||||
|
||||
if( aLayerID == F_Mask && m_viaFrontCover )
|
||||
{
|
||||
m_viaFrontCover->ApplyScalePosition( aZPos, 4 * m_boardAdapter.GetNonCopperLayerThickness() );
|
||||
m_viaFrontCover->DrawTop();
|
||||
}
|
||||
else if( aLayerID == B_Mask && m_viaBackCover )
|
||||
{
|
||||
m_viaBackCover->ApplyScalePosition( aZPos, 4 * m_boardAdapter.GetNonCopperLayerThickness() );
|
||||
m_viaBackCover->DrawBot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,6 +123,14 @@ private:
|
||||
float aZtop, float aZbot, unsigned int aNr_sides_per_circle,
|
||||
TRIANGLE_DISPLAY_LIST* aDstLayer );
|
||||
|
||||
void generateDisk( const SFVEC2F& aCenter, float aRadius, float aZ,
|
||||
unsigned int aNr_sides_per_circle, TRIANGLE_DISPLAY_LIST* aDstLayer,
|
||||
bool aTop );
|
||||
|
||||
void generateDimple( const SFVEC2F& aCenter, float aRadius, float aZ, float aDepth,
|
||||
unsigned int aNr_sides_per_circle, TRIANGLE_DISPLAY_LIST* aDstLayer,
|
||||
bool aTop );
|
||||
|
||||
void generateViasAndPads();
|
||||
|
||||
/**
|
||||
@ -236,6 +244,8 @@ private:
|
||||
|
||||
OPENGL_RENDER_LIST* m_microviaHoles;
|
||||
OPENGL_RENDER_LIST* m_padHoles;
|
||||
OPENGL_RENDER_LIST* m_viaFrontCover;
|
||||
OPENGL_RENDER_LIST* m_viaBackCover;
|
||||
|
||||
// Caches
|
||||
std::map<wxString, MODEL_3D*> m_3dModelMap;
|
||||
|
@ -277,7 +277,7 @@ void RENDER_3D_RAYTRACE_BASE::renderTracing( uint8_t* ptrPBO, REPORTER* aStatusR
|
||||
BS::multi_future<void> futures;
|
||||
|
||||
for( size_t i = 0; i < tp.get_thread_count(); ++i )
|
||||
futures.push_back( tp.submit( processBlocks ) );
|
||||
futures.push_back( tp.submit_task( processBlocks ) );
|
||||
|
||||
futures.wait();
|
||||
|
||||
@ -486,9 +486,12 @@ void RENDER_3D_RAYTRACE_BASE::renderBlockTracing( uint8_t* ptrPBO, signed int iB
|
||||
// Initialize ray packets
|
||||
const SFVEC2UI& blockPos = m_blockPositions[iBlock];
|
||||
const SFVEC2I blockPosI = SFVEC2I( blockPos.x + m_xoffset, blockPos.y + m_yoffset );
|
||||
const SFVEC2F randDisp = ( m_camera.GetProjection() == PROJECTION_TYPE::ORTHO ) ?
|
||||
SFVEC2F( 0.0f, 0.0f ) :
|
||||
SFVEC2F( DISP_FACTOR, DISP_FACTOR );
|
||||
|
||||
RAYPACKET blockPacket( m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, DISP_FACTOR ),
|
||||
SFVEC2F( DISP_FACTOR, DISP_FACTOR ) /* Displacement random factor */ );
|
||||
RAYPACKET blockPacket( m_camera, (SFVEC2F) blockPosI + randDisp,
|
||||
randDisp /* Displacement random factor */ );
|
||||
|
||||
|
||||
HITINFO_PACKET hitPacket_X0Y0[RAYPACKET_RAYS_PER_PACKET];
|
||||
@ -566,7 +569,7 @@ void RENDER_3D_RAYTRACE_BASE::renderBlockTracing( uint8_t* ptrPBO, signed int iB
|
||||
HITINFO_PACKET_init( hitPacket_AA_X1Y1 );
|
||||
|
||||
RAYPACKET blockPacket_AA_X1Y1( m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f, 0.5f ),
|
||||
SFVEC2F( DISP_FACTOR, DISP_FACTOR ) );
|
||||
randDisp );
|
||||
|
||||
if( !m_accelerator->Intersect( blockPacket_AA_X1Y1, hitPacket_AA_X1Y1 ) )
|
||||
{
|
||||
@ -603,16 +606,16 @@ void RENDER_3D_RAYTRACE_BASE::renderBlockTracing( uint8_t* ptrPBO, signed int iB
|
||||
RAY blockRayPck_AA_X1Y1_half[RAYPACKET_RAYS_PER_PACKET];
|
||||
|
||||
RAYPACKET_InitRays_with2DDisplacement(
|
||||
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f - DISP_FACTOR, DISP_FACTOR ),
|
||||
SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y0 );
|
||||
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.5f - randDisp.x, randDisp.y ),
|
||||
randDisp, blockRayPck_AA_X1Y0 );
|
||||
|
||||
RAYPACKET_InitRays_with2DDisplacement(
|
||||
m_camera, (SFVEC2F) blockPosI + SFVEC2F( DISP_FACTOR, 0.5f - DISP_FACTOR ),
|
||||
SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X0Y1 );
|
||||
m_camera, (SFVEC2F) blockPosI + SFVEC2F( randDisp.x, 0.5f - randDisp.y ),
|
||||
randDisp, blockRayPck_AA_X0Y1 );
|
||||
|
||||
RAYPACKET_InitRays_with2DDisplacement(
|
||||
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.25f - DISP_FACTOR, 0.25f - DISP_FACTOR ),
|
||||
SFVEC2F( DISP_FACTOR, DISP_FACTOR ), blockRayPck_AA_X1Y1_half );
|
||||
m_camera, (SFVEC2F) blockPosI + SFVEC2F( 0.25f - randDisp.x, 0.25f - randDisp.y ),
|
||||
randDisp, blockRayPck_AA_X1Y1_half );
|
||||
|
||||
renderAntiAliasPackets( bgColor, hitPacket_X0Y0, hitPacket_AA_X1Y1, blockRayPck_AA_X1Y0,
|
||||
hitColor_AA_X1Y0 );
|
||||
|
@ -633,7 +633,8 @@ set( COMMON_GIT_SRCS
|
||||
git/project_git_utils.cpp
|
||||
git/kicad_git_common.cpp
|
||||
git/kicad_git_errors.cpp
|
||||
git/project_git_utils.cpp
|
||||
git/git_backend.cpp
|
||||
git/libgit_backend.cpp
|
||||
)
|
||||
|
||||
set( COMMON_SRCS
|
||||
|
@ -190,7 +190,7 @@ void DESIGN_BLOCK_LIST_IMPL::loadDesignBlocks()
|
||||
};
|
||||
|
||||
for( size_t ii = 0; ii < num_elements; ++ii )
|
||||
returns[ii] = tp.submit( db_thread );
|
||||
returns[ii] = tp.submit_task( db_thread );
|
||||
|
||||
for( const std::future<size_t>& ret : returns )
|
||||
{
|
||||
|
@ -167,9 +167,7 @@ void PANEL_EMBEDDED_FILES::resizeGrid()
|
||||
bool PANEL_EMBEDDED_FILES::TransferDataToWindow()
|
||||
{
|
||||
m_files_grid->ClearGrid();
|
||||
|
||||
if( m_files_grid->GetNumberRows() > 0 )
|
||||
m_files_grid->DeleteRows( 0, m_files_grid->GetNumberRows() );
|
||||
m_files_grid->ClearRows();
|
||||
|
||||
int ii = 0;
|
||||
|
||||
|
@ -87,6 +87,10 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin
|
||||
m_stealsFocus( true ),
|
||||
m_statusPopup( nullptr )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// need to fix broken cairo rendering on Windows with wx 3.3
|
||||
SetDoubleBuffered( false );
|
||||
#endif
|
||||
m_PaintEventCounter = std::make_unique<PROF_COUNTER>( "Draw panel paint events" );
|
||||
|
||||
if( Pgm().GetCommonSettings()->m_Appearance.show_scrollbars )
|
||||
|
@ -1059,32 +1059,35 @@ std::vector<wxWindow*> EDA_DRAW_FRAME::findDialogs()
|
||||
}
|
||||
|
||||
|
||||
void EDA_DRAW_FRAME::FocusOnLocation( const VECTOR2I& aPos )
|
||||
void EDA_DRAW_FRAME::FocusOnLocation( const VECTOR2I& aPos, bool aAllowScroll )
|
||||
{
|
||||
bool centerView = false;
|
||||
BOX2D r = GetCanvas()->GetView()->GetViewport();
|
||||
|
||||
// Center if we're off the current view, or within 10% of its edge
|
||||
r.Inflate( - r.GetWidth() / 10.0 );
|
||||
|
||||
if( !r.Contains( aPos ) )
|
||||
centerView = true;
|
||||
|
||||
bool centerView = false;
|
||||
std::vector<BOX2D> dialogScreenRects;
|
||||
|
||||
for( wxWindow* dialog : findDialogs() )
|
||||
if( aAllowScroll )
|
||||
{
|
||||
dialogScreenRects.emplace_back( ToVECTOR2D( GetCanvas()->ScreenToClient( dialog->GetScreenPosition() ) ),
|
||||
ToVECTOR2D( dialog->GetSize() ) );
|
||||
}
|
||||
BOX2D r = GetCanvas()->GetView()->GetViewport();
|
||||
|
||||
// Center if we're behind an obscuring dialog, or within 10% of its edge
|
||||
for( BOX2D rect : dialogScreenRects )
|
||||
{
|
||||
rect.Inflate( rect.GetWidth() / 10 );
|
||||
// Center if we're off the current view, or within 10% of its edge
|
||||
r.Inflate( - r.GetWidth() / 10.0 );
|
||||
|
||||
if( rect.Contains( GetCanvas()->GetView()->ToScreen( aPos ) ) )
|
||||
if( !r.Contains( aPos ) )
|
||||
centerView = true;
|
||||
|
||||
for( wxWindow* dialog : findDialogs() )
|
||||
{
|
||||
dialogScreenRects.emplace_back( ToVECTOR2D( GetCanvas()->ScreenToClient( dialog->GetScreenPosition() ) ),
|
||||
ToVECTOR2D( dialog->GetSize() ) );
|
||||
}
|
||||
|
||||
// Center if we're behind an obscuring dialog, or within 10% of its edge
|
||||
for( BOX2D rect : dialogScreenRects )
|
||||
{
|
||||
rect.Inflate( rect.GetWidth() / 10 );
|
||||
|
||||
if( rect.Contains( GetCanvas()->GetView()->ToScreen( aPos ) ) )
|
||||
centerView = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( centerView )
|
||||
|
@ -1382,6 +1382,15 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const
|
||||
|
||||
return poly.Collide( aPosition, maxdist );
|
||||
}
|
||||
else if( m_cornerRadius > 0 )
|
||||
{
|
||||
ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ), m_cornerRadius );
|
||||
SHAPE_POLY_SET poly;
|
||||
rr.TransformToPolygon( poly );
|
||||
|
||||
if( poly.CollideEdge( aPosition, nullptr, maxdist ) )
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<VECTOR2I> pts = GetRectCorners();
|
||||
@ -1393,13 +1402,13 @@ bool EDA_SHAPE::hitTest( const VECTOR2I& aPosition, int aAccuracy ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( IsHatchedFill() && GetHatching().Collide( aPosition, maxdist ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( IsHatchedFill() && GetHatching().Collide( aPosition, maxdist ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
case SHAPE_T::POLY:
|
||||
if( IsFilledForHitTesting() )
|
||||
{
|
||||
@ -1441,6 +1450,40 @@ bool EDA_SHAPE::hitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co
|
||||
|
||||
BOX2I bbox = getBoundingBox();
|
||||
|
||||
auto checkOutline =
|
||||
[&]( const SHAPE_LINE_CHAIN& outline )
|
||||
{
|
||||
int count = (int) outline.GetPointCount();
|
||||
|
||||
for( int ii = 0; ii < count; ii++ )
|
||||
{
|
||||
VECTOR2I vertex = outline.GetPoint( ii );
|
||||
|
||||
// Test if the point is within aRect
|
||||
if( arect.Contains( vertex ) )
|
||||
return true;
|
||||
|
||||
if( ii + 1 < count )
|
||||
{
|
||||
VECTOR2I vertexNext = outline.GetPoint( ii + 1 );
|
||||
|
||||
// Test if this edge intersects aRect
|
||||
if( arect.Intersects( vertex, vertexNext ) )
|
||||
return true;
|
||||
}
|
||||
else if( outline.IsClosed() )
|
||||
{
|
||||
VECTOR2I vertexNext = outline.GetPoint( 0 );
|
||||
|
||||
// Test if this edge intersects aRect
|
||||
if( arect.Intersects( vertex, vertexNext ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
switch( m_shape )
|
||||
{
|
||||
case SHAPE_T::CIRCLE:
|
||||
@ -1487,6 +1530,17 @@ bool EDA_SHAPE::hitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co
|
||||
{
|
||||
return arect.Contains( bbox );
|
||||
}
|
||||
else if( m_cornerRadius > 0 )
|
||||
{
|
||||
ROUNDRECT rr( SHAPE_RECT( GetStart(), GetRectangleWidth(), GetRectangleHeight() ), m_cornerRadius );
|
||||
SHAPE_POLY_SET poly;
|
||||
rr.TransformToPolygon( poly );
|
||||
|
||||
// Account for the width of the line
|
||||
arect.Inflate( GetWidth() / 2 );
|
||||
|
||||
return checkOutline( poly.Outline( 0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<VECTOR2I> pts = GetRectCorners();
|
||||
@ -1528,34 +1582,8 @@ bool EDA_SHAPE::hitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co
|
||||
|
||||
for( int ii = 0; ii < m_poly.OutlineCount(); ++ii )
|
||||
{
|
||||
const SHAPE_LINE_CHAIN& poly = m_poly.Outline( ii );
|
||||
int count = (int) poly.GetPointCount();
|
||||
|
||||
for( int jj = 0; jj < count; jj++ )
|
||||
{
|
||||
VECTOR2I vertex = poly.GetPoint( jj );
|
||||
|
||||
// Test if the point is within aRect
|
||||
if( arect.Contains( vertex ) )
|
||||
return true;
|
||||
|
||||
if( jj + 1 < count )
|
||||
{
|
||||
VECTOR2I vertexNext = poly.GetPoint( jj + 1 );
|
||||
|
||||
// Test if this edge intersects aRect
|
||||
if( arect.Intersects( vertex, vertexNext ) )
|
||||
return true;
|
||||
}
|
||||
else if( poly.IsClosed() )
|
||||
{
|
||||
VECTOR2I vertexNext = poly.GetPoint( 0 );
|
||||
|
||||
// Test if this edge intersects aRect
|
||||
if( arect.Intersects( vertex, vertexNext ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if( checkOutline( m_poly.Outline( ii ) ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1364,6 +1364,11 @@ CAIRO_GAL::CAIRO_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
|
||||
m_currentTarget = TARGET_NONCACHED;
|
||||
SetTarget( TARGET_NONCACHED );
|
||||
|
||||
#ifdef _WIN32
|
||||
// need to fix broken cairo rendering on Windows with wx 3.3
|
||||
SetDoubleBuffered( false );
|
||||
#endif
|
||||
|
||||
m_bitmapBuffer = nullptr;
|
||||
m_wxOutput = nullptr;
|
||||
|
||||
|
@ -22,16 +22,13 @@
|
||||
*/
|
||||
|
||||
#include "git_add_to_index_handler.h"
|
||||
#include <git/kicad_git_memory.h>
|
||||
#include "git_backend.h"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <wx/log.h>
|
||||
|
||||
GIT_ADD_TO_INDEX_HANDLER::GIT_ADD_TO_INDEX_HANDLER( git_repository* aRepository )
|
||||
GIT_ADD_TO_INDEX_HANDLER::GIT_ADD_TO_INDEX_HANDLER( git_repository* aRepository ) :
|
||||
KIGIT_COMMON( aRepository )
|
||||
{
|
||||
m_repository = aRepository;
|
||||
m_filesToAdd.clear();
|
||||
}
|
||||
|
||||
@ -43,66 +40,11 @@ GIT_ADD_TO_INDEX_HANDLER::~GIT_ADD_TO_INDEX_HANDLER()
|
||||
|
||||
bool GIT_ADD_TO_INDEX_HANDLER::AddToIndex( const wxString& aFilePath )
|
||||
{
|
||||
// Test if file is currently in the index
|
||||
|
||||
git_index* index = nullptr;
|
||||
size_t at_pos = 0;
|
||||
|
||||
if( git_repository_index( &index, m_repository ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to get repository index" );
|
||||
return false;
|
||||
}
|
||||
|
||||
KIGIT::GitIndexPtr indexPtr( index );
|
||||
|
||||
if( git_index_find( &at_pos, index, aFilePath.ToUTF8().data() ) == GIT_OK )
|
||||
{
|
||||
wxLogError( "%s already in index", aFilePath );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add file to index if not already there
|
||||
m_filesToAdd.push_back( aFilePath );
|
||||
|
||||
return true;
|
||||
return GetGitBackend()->AddToIndex( this, aFilePath );
|
||||
}
|
||||
|
||||
|
||||
bool GIT_ADD_TO_INDEX_HANDLER::PerformAddToIndex()
|
||||
{
|
||||
git_index* index = nullptr;
|
||||
|
||||
m_filesFailedToAdd.clear();
|
||||
|
||||
if( git_repository_index( &index, m_repository ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to get repository index" );
|
||||
std::copy( m_filesToAdd.begin(), m_filesToAdd.end(), std::back_inserter( m_filesFailedToAdd ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
KIGIT::GitIndexPtr indexPtr( index );
|
||||
|
||||
for( auto& file : m_filesToAdd )
|
||||
{
|
||||
if( git_index_add_bypath( index, file.ToUTF8().data() ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to add %s to index", file );
|
||||
m_filesFailedToAdd.push_back( file );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( git_index_write( index ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to write index" );
|
||||
m_filesFailedToAdd.clear();
|
||||
std::copy( m_filesToAdd.begin(), m_filesToAdd.end(),
|
||||
std::back_inserter( m_filesFailedToAdd ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return GetGitBackend()->PerformAddToIndex( this );
|
||||
}
|
||||
|
@ -24,12 +24,13 @@
|
||||
#ifndef GIT_ADD_TO_INDEX_HANDLER_H_
|
||||
#define GIT_ADD_TO_INDEX_HANDLER_H_
|
||||
|
||||
#include <git2.h>
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <vector>
|
||||
#include <wx/string.h>
|
||||
|
||||
class wxString;
|
||||
class LIBGIT_BACKEND;
|
||||
|
||||
class GIT_ADD_TO_INDEX_HANDLER
|
||||
class GIT_ADD_TO_INDEX_HANDLER : public KIGIT_COMMON
|
||||
{
|
||||
public:
|
||||
GIT_ADD_TO_INDEX_HANDLER( git_repository* aRepository );
|
||||
@ -40,8 +41,7 @@ public:
|
||||
bool PerformAddToIndex();
|
||||
|
||||
private:
|
||||
git_repository* m_repository;
|
||||
|
||||
friend class LIBGIT_BACKEND;
|
||||
std::vector<wxString> m_filesToAdd;
|
||||
std::vector<wxString> m_filesFailedToAdd;
|
||||
};
|
||||
|
36
common/git/git_backend.cpp
Normal file
36
common/git/git_backend.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "git_backend.h"
|
||||
|
||||
static GIT_BACKEND* s_backend = nullptr;
|
||||
|
||||
GIT_BACKEND* GetGitBackend()
|
||||
{
|
||||
return s_backend;
|
||||
}
|
||||
|
||||
void SetGitBackend( GIT_BACKEND* aBackend )
|
||||
{
|
||||
s_backend = aBackend;
|
||||
}
|
127
common/git/git_backend.h
Normal file
127
common/git/git_backend.h
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef GIT_BACKEND_H_
|
||||
#define GIT_BACKEND_H_
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <wx/string.h>
|
||||
|
||||
class GIT_CLONE_HANDLER;
|
||||
class GIT_COMMIT_HANDLER;
|
||||
class GIT_PUSH_HANDLER;
|
||||
class GIT_STATUS_HANDLER;
|
||||
class GIT_ADD_TO_INDEX_HANDLER;
|
||||
class GIT_REMOVE_FROM_INDEX_HANDLER;
|
||||
class GIT_CONFIG_HANDLER;
|
||||
class GIT_INIT_HANDLER;
|
||||
class GIT_BRANCH_HANDLER;
|
||||
class GIT_PULL_HANDLER;
|
||||
class GIT_REVERT_HANDLER;
|
||||
struct RemoteConfig;
|
||||
struct git_repository;
|
||||
enum class InitResult;
|
||||
enum class BranchResult;
|
||||
enum class PullResult;
|
||||
struct FileStatus;
|
||||
enum class PushResult;
|
||||
|
||||
// Commit result shared across backend and handlers
|
||||
enum class CommitResult
|
||||
{
|
||||
Success,
|
||||
Error,
|
||||
Cancelled
|
||||
};
|
||||
|
||||
class GIT_BACKEND
|
||||
{
|
||||
public:
|
||||
virtual ~GIT_BACKEND() = default;
|
||||
|
||||
virtual void Init() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
// Whether the libgit2 library is available/initialized enough for use
|
||||
virtual bool IsLibraryAvailable() = 0;
|
||||
|
||||
virtual bool Clone( GIT_CLONE_HANDLER* aHandler ) = 0;
|
||||
|
||||
virtual CommitResult Commit( GIT_COMMIT_HANDLER* aHandler,
|
||||
const std::vector<wxString>& aFiles,
|
||||
const wxString& aMessage,
|
||||
const wxString& aAuthorName,
|
||||
const wxString& aAuthorEmail ) = 0;
|
||||
|
||||
virtual PushResult Push( GIT_PUSH_HANDLER* aHandler ) = 0;
|
||||
|
||||
virtual bool HasChangedFiles( GIT_STATUS_HANDLER* aHandler ) = 0;
|
||||
|
||||
virtual std::map<wxString, FileStatus> GetFileStatus( GIT_STATUS_HANDLER* aHandler,
|
||||
const wxString& aPathspec ) = 0;
|
||||
|
||||
virtual wxString GetCurrentBranchName( GIT_STATUS_HANDLER* aHandler ) = 0;
|
||||
|
||||
virtual void UpdateRemoteStatus( GIT_STATUS_HANDLER* aHandler,
|
||||
const std::set<wxString>& aLocalChanges,
|
||||
const std::set<wxString>& aRemoteChanges,
|
||||
std::map<wxString, FileStatus>& aFileStatus ) = 0;
|
||||
|
||||
virtual wxString GetWorkingDirectory( GIT_STATUS_HANDLER* aHandler ) = 0;
|
||||
|
||||
virtual wxString GetWorkingDirectory( GIT_CONFIG_HANDLER* aHandler ) = 0;
|
||||
virtual bool GetConfigString( GIT_CONFIG_HANDLER* aHandler, const wxString& aKey,
|
||||
wxString& aValue ) = 0;
|
||||
|
||||
virtual bool IsRepository( GIT_INIT_HANDLER* aHandler, const wxString& aPath ) = 0;
|
||||
virtual InitResult InitializeRepository( GIT_INIT_HANDLER* aHandler, const wxString& aPath ) = 0;
|
||||
virtual bool SetupRemote( GIT_INIT_HANDLER* aHandler, const RemoteConfig& aConfig ) = 0;
|
||||
|
||||
virtual BranchResult SwitchToBranch( GIT_BRANCH_HANDLER* aHandler, const wxString& aBranchName ) = 0;
|
||||
virtual bool BranchExists( GIT_BRANCH_HANDLER* aHandler, const wxString& aBranchName ) = 0;
|
||||
|
||||
virtual bool PerformFetch( GIT_PULL_HANDLER* aHandler, bool aSkipLock ) = 0;
|
||||
virtual PullResult PerformPull( GIT_PULL_HANDLER* aHandler ) = 0;
|
||||
|
||||
virtual void PerformRevert( GIT_REVERT_HANDLER* aHandler ) = 0;
|
||||
|
||||
virtual git_repository* GetRepositoryForFile( const char* aFilename ) = 0;
|
||||
virtual int CreateBranch( git_repository* aRepo, const wxString& aBranchName ) = 0;
|
||||
virtual bool RemoveVCS( git_repository*& aRepo, const wxString& aProjectPath,
|
||||
bool aRemoveGitDir, wxString* aErrors ) = 0;
|
||||
|
||||
virtual bool AddToIndex( GIT_ADD_TO_INDEX_HANDLER* aHandler, const wxString& aFilePath ) = 0;
|
||||
|
||||
virtual bool PerformAddToIndex( GIT_ADD_TO_INDEX_HANDLER* aHandler ) = 0;
|
||||
|
||||
virtual bool RemoveFromIndex( GIT_REMOVE_FROM_INDEX_HANDLER* aHandler, const wxString& aFilePath ) = 0;
|
||||
|
||||
virtual void PerformRemoveFromIndex( GIT_REMOVE_FROM_INDEX_HANDLER* aHandler ) = 0;
|
||||
};
|
||||
|
||||
GIT_BACKEND* GetGitBackend();
|
||||
void SetGitBackend( GIT_BACKEND* aBackend );
|
||||
|
||||
#endif
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "git_branch_handler.h"
|
||||
#include "git_backend.h"
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <git/kicad_git_memory.h>
|
||||
#include <trace_helpers.h>
|
||||
@ -35,89 +36,12 @@ GIT_BRANCH_HANDLER::~GIT_BRANCH_HANDLER()
|
||||
|
||||
bool GIT_BRANCH_HANDLER::BranchExists( const wxString& aBranchName )
|
||||
{
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
return false;
|
||||
|
||||
git_reference* branchRef = nullptr;
|
||||
bool exists = LookupBranchReference( aBranchName, &branchRef );
|
||||
|
||||
if( branchRef )
|
||||
git_reference_free( branchRef );
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
bool GIT_BRANCH_HANDLER::LookupBranchReference( const wxString& aBranchName, git_reference** aReference )
|
||||
{
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
return false;
|
||||
|
||||
// Try direct lookup first
|
||||
if( git_reference_lookup( aReference, repo, aBranchName.mb_str() ) == GIT_OK )
|
||||
return true;
|
||||
|
||||
// Try dwim (Do What I Mean) lookup for short branch names
|
||||
if( git_reference_dwim( aReference, repo, aBranchName.mb_str() ) == GIT_OK )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return GetGitBackend()->BranchExists( this, aBranchName );
|
||||
}
|
||||
|
||||
BranchResult GIT_BRANCH_HANDLER::SwitchToBranch( const wxString& aBranchName )
|
||||
{
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
{
|
||||
AddErrorString( _( "No repository available" ) );
|
||||
return BranchResult::Error;
|
||||
}
|
||||
|
||||
// Look up the branch reference
|
||||
git_reference* branchRef = nullptr;
|
||||
|
||||
if( !LookupBranchReference( aBranchName, &branchRef ) )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to lookup branch '%s': %s" ),
|
||||
aBranchName, KIGIT_COMMON::GetLastGitError() ) );
|
||||
return BranchResult::BranchNotFound;
|
||||
}
|
||||
|
||||
KIGIT::GitReferencePtr branchRefPtr( branchRef );
|
||||
const char* branchRefName = git_reference_name( branchRef );
|
||||
git_object* branchObj = nullptr;
|
||||
|
||||
if( git_revparse_single( &branchObj, repo, aBranchName.mb_str() ) != GIT_OK )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to find branch head for '%s': %s" ),
|
||||
aBranchName, KIGIT_COMMON::GetLastGitError() ) );
|
||||
return BranchResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitObjectPtr branchObjPtr( branchObj );
|
||||
|
||||
// Switch to the branch
|
||||
if( git_checkout_tree( repo, branchObj, nullptr ) != GIT_OK )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to switch to branch '%s': %s" ),
|
||||
aBranchName, KIGIT_COMMON::GetLastGitError() ) );
|
||||
return BranchResult::CheckoutFailed;
|
||||
}
|
||||
|
||||
// Update the HEAD reference
|
||||
if( git_repository_set_head( repo, branchRefName ) != GIT_OK )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to update HEAD reference for branch '%s': %s" ),
|
||||
aBranchName, KIGIT_COMMON::GetLastGitError() ) );
|
||||
return BranchResult::Error;
|
||||
}
|
||||
|
||||
wxLogTrace( traceGit, "Successfully switched to branch '%s'", aBranchName );
|
||||
return BranchResult::Success;
|
||||
return GetGitBackend()->SwitchToBranch( this, aBranchName );
|
||||
}
|
||||
|
||||
void GIT_BRANCH_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )
|
||||
|
@ -57,15 +57,6 @@ public:
|
||||
bool BranchExists( const wxString& aBranchName );
|
||||
|
||||
void UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage ) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Look up a branch reference by name
|
||||
* @param aBranchName Name of the branch
|
||||
* @param aReference Output parameter for the reference
|
||||
* @return True if successful, false otherwise
|
||||
*/
|
||||
bool LookupBranchReference( const wxString& aBranchName, git_reference** aReference );
|
||||
};
|
||||
|
||||
#endif // GIT_BRANCH_HANDLER_H
|
@ -23,13 +23,8 @@
|
||||
|
||||
#include "git_clone_handler.h"
|
||||
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <git/kicad_git_memory.h>
|
||||
#include <trace_helpers.h>
|
||||
|
||||
#include <git2.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/log.h>
|
||||
#include "git_backend.h"
|
||||
|
||||
GIT_CLONE_HANDLER::GIT_CLONE_HANDLER( KIGIT_COMMON* aCommon ) : KIGIT_REPO_MIXIN( aCommon )
|
||||
{}
|
||||
@ -41,55 +36,7 @@ GIT_CLONE_HANDLER::~GIT_CLONE_HANDLER()
|
||||
|
||||
bool GIT_CLONE_HANDLER::PerformClone()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock( GetCommon()->m_gitActionMutex, std::try_to_lock );
|
||||
|
||||
if( !lock.owns_lock() )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_CLONE_HANDLER::PerformClone() could not lock" );
|
||||
return false;
|
||||
}
|
||||
|
||||
wxFileName clonePath( m_clonePath );
|
||||
|
||||
if( !clonePath.DirExists() )
|
||||
{
|
||||
if( !clonePath.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Could not create directory '%s'" ),
|
||||
m_clonePath ) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
git_clone_options cloneOptions;
|
||||
git_clone_init_options( &cloneOptions, GIT_CLONE_OPTIONS_VERSION );
|
||||
cloneOptions.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
|
||||
cloneOptions.checkout_opts.progress_cb = clone_progress_cb;
|
||||
cloneOptions.checkout_opts.progress_payload = this;
|
||||
cloneOptions.fetch_opts.callbacks.transfer_progress = transfer_progress_cb;
|
||||
cloneOptions.fetch_opts.callbacks.credentials = credentials_cb;
|
||||
cloneOptions.fetch_opts.callbacks.payload = this;
|
||||
|
||||
TestedTypes() = 0;
|
||||
ResetNextKey();
|
||||
git_repository* newRepo = nullptr;
|
||||
wxString remote = GetCommon()->m_remote;
|
||||
|
||||
if( git_clone( &newRepo, remote.mbc_str(), m_clonePath.mbc_str(),
|
||||
&cloneOptions ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Could not clone repository '%s'" ), remote ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
GetCommon()->SetRepo( newRepo );
|
||||
|
||||
if( m_progressReporter )
|
||||
m_progressReporter->Hide();
|
||||
|
||||
m_previousProgress = 0;
|
||||
|
||||
return true;
|
||||
return GetGitBackend()->Clone( this );
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,8 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "git_commit_handler.h"
|
||||
#include <git/kicad_git_memory.h>
|
||||
#include <wx/log.h>
|
||||
#include "git_backend.h"
|
||||
|
||||
GIT_COMMIT_HANDLER::GIT_COMMIT_HANDLER( git_repository* aRepo ) :
|
||||
KIGIT_COMMON( aRepo )
|
||||
@ -34,121 +33,13 @@ GIT_COMMIT_HANDLER::~GIT_COMMIT_HANDLER()
|
||||
{}
|
||||
|
||||
|
||||
GIT_COMMIT_HANDLER::CommitResult
|
||||
CommitResult
|
||||
GIT_COMMIT_HANDLER::PerformCommit( const std::vector<wxString>& aFiles,
|
||||
const wxString& aMessage,
|
||||
const wxString& aAuthorName,
|
||||
const wxString& aAuthorEmail )
|
||||
{
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
return CommitResult::Error;
|
||||
|
||||
git_index* index = nullptr;
|
||||
|
||||
if( git_repository_index( &index, repo ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to get repository index: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return CommitResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitIndexPtr indexPtr( index );
|
||||
|
||||
for( const wxString& file : aFiles )
|
||||
{
|
||||
if( git_index_add_bypath( index, file.mb_str() ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to add file to index: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return CommitResult::Error;
|
||||
}
|
||||
}
|
||||
|
||||
if( git_index_write( index ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to write index: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return CommitResult::Error;
|
||||
}
|
||||
|
||||
git_oid tree_id;
|
||||
|
||||
if( git_index_write_tree( &tree_id, index ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to write tree: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return CommitResult::Error;
|
||||
}
|
||||
|
||||
git_tree* tree = nullptr;
|
||||
|
||||
if( git_tree_lookup( &tree, repo, &tree_id ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to lookup tree: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return CommitResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitTreePtr treePtr( tree );
|
||||
git_commit* parent = nullptr;
|
||||
|
||||
if( git_repository_head_unborn( repo ) == 0 )
|
||||
{
|
||||
git_reference* headRef = nullptr;
|
||||
|
||||
if( git_repository_head( &headRef, repo ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to get HEAD reference: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return CommitResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitReferencePtr headRefPtr( headRef );
|
||||
|
||||
if( git_reference_peel( (git_object**) &parent, headRef, GIT_OBJECT_COMMIT ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to get commit: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return CommitResult::Error;
|
||||
}
|
||||
}
|
||||
|
||||
KIGIT::GitCommitPtr parentPtr( parent );
|
||||
|
||||
git_signature* author = nullptr;
|
||||
|
||||
if( git_signature_now( &author, aAuthorName.mb_str(), aAuthorEmail.mb_str() ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to create author signature: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return CommitResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitSignaturePtr authorPtr( author );
|
||||
git_oid oid;
|
||||
size_t parentsCount = parent ? 1 : 0;
|
||||
#if( LIBGIT2_VER_MAJOR == 1 && LIBGIT2_VER_MINOR == 8 \
|
||||
&& ( LIBGIT2_VER_REVISION < 2 || LIBGIT2_VER_REVISION == 3 ) )
|
||||
git_commit* const parents[1] = { parent };
|
||||
git_commit** const parentsPtr = parent ? parents : nullptr;
|
||||
#else
|
||||
const git_commit* parents[1] = { parent };
|
||||
const git_commit** parentsPtr = parent ? parents : nullptr;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
if( git_commit_create( &oid, repo, "HEAD", author, author, nullptr,
|
||||
aMessage.mb_str(), tree, parentsCount, parentsPtr ) != 0 )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to create commit: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return CommitResult::Error;
|
||||
}
|
||||
|
||||
return CommitResult::Success;
|
||||
return GetGitBackend()->Commit( this, aFiles, aMessage, aAuthorName, aAuthorEmail );
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,25 +27,20 @@
|
||||
// Define a class to handle git commit operations
|
||||
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <git2.h>
|
||||
#include "git_backend.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/string.h>
|
||||
|
||||
class LIBGIT_BACKEND;
|
||||
|
||||
class GIT_COMMIT_HANDLER : public KIGIT_COMMON
|
||||
{
|
||||
public:
|
||||
GIT_COMMIT_HANDLER( git_repository* aRepo );
|
||||
virtual ~GIT_COMMIT_HANDLER();
|
||||
|
||||
enum class CommitResult
|
||||
{
|
||||
Success,
|
||||
Error,
|
||||
Cancelled
|
||||
};
|
||||
|
||||
CommitResult PerformCommit( const std::vector<wxString>& aFiles,
|
||||
const wxString& aMessage,
|
||||
const wxString& aAuthorName,
|
||||
@ -54,6 +49,7 @@ public:
|
||||
wxString GetErrorString() const;
|
||||
|
||||
private:
|
||||
friend class LIBGIT_BACKEND;
|
||||
void AddErrorString( const wxString& aErrorString );
|
||||
|
||||
wxString m_errorString;
|
||||
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "git_config_handler.h"
|
||||
#include "git_backend.h"
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <git/kicad_git_memory.h>
|
||||
#include <pgm_base.h>
|
||||
@ -59,48 +60,12 @@ GitUserConfig GIT_CONFIG_HANDLER::GetUserConfig()
|
||||
|
||||
wxString GIT_CONFIG_HANDLER::GetWorkingDirectory()
|
||||
{
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
return wxEmptyString;
|
||||
|
||||
const char* workdir = git_repository_workdir( repo );
|
||||
|
||||
if( !workdir )
|
||||
return wxEmptyString;
|
||||
|
||||
return wxString( workdir );
|
||||
return GetGitBackend()->GetWorkingDirectory( this );
|
||||
}
|
||||
|
||||
bool GIT_CONFIG_HANDLER::GetConfigString( const wxString& aKey, wxString& aValue )
|
||||
{
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
return false;
|
||||
|
||||
git_config* config = nullptr;
|
||||
|
||||
if( git_repository_config( &config, repo ) != GIT_OK )
|
||||
{
|
||||
wxLogTrace( traceGit, "Failed to get repository config: %s", KIGIT_COMMON::GetLastGitError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
KIGIT::GitConfigPtr configPtr( config );
|
||||
|
||||
git_config_entry* entry = nullptr;
|
||||
int result = git_config_get_entry( &entry, config, aKey.mb_str() );
|
||||
KIGIT::GitConfigEntryPtr entryPtr( entry );
|
||||
|
||||
if( result != GIT_OK || entry == nullptr )
|
||||
{
|
||||
wxLogTrace( traceGit, "Config key '%s' not found", aKey );
|
||||
return false;
|
||||
}
|
||||
|
||||
aValue = wxString( entry->value );
|
||||
return true;
|
||||
return GetGitBackend()->GetConfigString( this, aKey, aValue );
|
||||
}
|
||||
|
||||
void GIT_CONFIG_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )
|
||||
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "git_init_handler.h"
|
||||
#include "git_backend.h"
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <git/kicad_git_memory.h>
|
||||
#include <trace_helpers.h>
|
||||
@ -35,118 +36,17 @@ GIT_INIT_HANDLER::~GIT_INIT_HANDLER()
|
||||
|
||||
bool GIT_INIT_HANDLER::IsRepository( const wxString& aPath )
|
||||
{
|
||||
git_repository* repo = nullptr;
|
||||
int error = git_repository_open( &repo, aPath.mb_str() );
|
||||
|
||||
if( error == 0 )
|
||||
{
|
||||
git_repository_free( repo );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return GetGitBackend()->IsRepository( this, aPath );
|
||||
}
|
||||
|
||||
InitResult GIT_INIT_HANDLER::InitializeRepository( const wxString& aPath )
|
||||
{
|
||||
// Check if directory is already a git repository
|
||||
if( IsRepository( aPath ) )
|
||||
{
|
||||
return InitResult::AlreadyExists;
|
||||
}
|
||||
|
||||
git_repository* repo = nullptr;
|
||||
|
||||
if( git_repository_init( &repo, aPath.mb_str(), 0 ) != GIT_OK )
|
||||
{
|
||||
if( repo )
|
||||
git_repository_free( repo );
|
||||
|
||||
AddErrorString( wxString::Format( _( "Failed to initialize Git repository: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return InitResult::Error;
|
||||
}
|
||||
|
||||
// Update the common repository pointer
|
||||
GetCommon()->SetRepo( repo );
|
||||
|
||||
wxLogTrace( traceGit, "Successfully initialized Git repository at %s", aPath );
|
||||
return InitResult::Success;
|
||||
return GetGitBackend()->InitializeRepository( this, aPath );
|
||||
}
|
||||
|
||||
bool GIT_INIT_HANDLER::SetupRemote( const RemoteConfig& aConfig )
|
||||
{
|
||||
// This is an optional step
|
||||
if( aConfig.url.IsEmpty() )
|
||||
return true;
|
||||
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
{
|
||||
AddErrorString( _( "No repository available to set up remote" ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update connection settings in common
|
||||
GetCommon()->SetUsername( aConfig.username );
|
||||
GetCommon()->SetPassword( aConfig.password );
|
||||
GetCommon()->SetSSHKey( aConfig.sshKey );
|
||||
|
||||
git_remote* remote = nullptr;
|
||||
wxString fullURL;
|
||||
|
||||
// Build the full URL based on connection type
|
||||
if( aConfig.connType == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_SSH )
|
||||
{
|
||||
fullURL = aConfig.username + "@" + aConfig.url;
|
||||
}
|
||||
else if( aConfig.connType == KIGIT_COMMON::GIT_CONN_TYPE::GIT_CONN_HTTPS )
|
||||
{
|
||||
fullURL = aConfig.url.StartsWith( "https" ) ? "https://" : "http://";
|
||||
|
||||
if( !aConfig.username.empty() )
|
||||
{
|
||||
fullURL.append( aConfig.username );
|
||||
|
||||
if( !aConfig.password.empty() )
|
||||
{
|
||||
fullURL.append( wxS( ":" ) );
|
||||
fullURL.append( aConfig.password );
|
||||
}
|
||||
|
||||
fullURL.append( wxS( "@" ) );
|
||||
}
|
||||
|
||||
// Extract the bare URL (without protocol prefix)
|
||||
wxString bareURL = aConfig.url;
|
||||
if( bareURL.StartsWith( "https://" ) )
|
||||
bareURL = bareURL.Mid( 8 );
|
||||
else if( bareURL.StartsWith( "http://" ) )
|
||||
bareURL = bareURL.Mid( 7 );
|
||||
|
||||
fullURL.append( bareURL );
|
||||
}
|
||||
else
|
||||
{
|
||||
fullURL = aConfig.url;
|
||||
}
|
||||
|
||||
int error = git_remote_create_with_fetchspec( &remote, repo, "origin",
|
||||
fullURL.ToStdString().c_str(),
|
||||
"+refs/heads/*:refs/remotes/origin/*" );
|
||||
|
||||
KIGIT::GitRemotePtr remotePtr( remote );
|
||||
|
||||
if( error != GIT_OK )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to create remote: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
wxLogTrace( traceGit, "Successfully set up remote origin" );
|
||||
return true;
|
||||
return GetGitBackend()->SetupRemote( this, aConfig );
|
||||
}
|
||||
|
||||
void GIT_INIT_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )
|
||||
|
@ -22,188 +22,22 @@
|
||||
*/
|
||||
|
||||
#include "git_pull_handler.h"
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <git/kicad_git_memory.h>
|
||||
#include <trace_helpers.h>
|
||||
|
||||
#include <wx/log.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
#include <memory>
|
||||
#include "git_backend.h"
|
||||
|
||||
GIT_PULL_HANDLER::GIT_PULL_HANDLER( KIGIT_COMMON* aCommon ) : KIGIT_REPO_MIXIN( aCommon )
|
||||
{
|
||||
}
|
||||
|
||||
{}
|
||||
|
||||
GIT_PULL_HANDLER::~GIT_PULL_HANDLER()
|
||||
{
|
||||
}
|
||||
|
||||
{}
|
||||
|
||||
bool GIT_PULL_HANDLER::PerformFetch( bool aSkipLock )
|
||||
{
|
||||
if( !GetRepo() )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - No repository found" );
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock( GetCommon()->m_gitActionMutex, std::try_to_lock );
|
||||
|
||||
if( !aSkipLock && !lock.owns_lock() )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - Could not lock mutex" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fetch updates from remote repository
|
||||
git_remote* remote = nullptr;
|
||||
|
||||
if( git_remote_lookup( &remote, GetRepo(), "origin" ) != 0 )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - Failed to lookup remote 'origin'" );
|
||||
AddErrorString( wxString::Format( _( "Could not lookup remote '%s'" ), "origin" ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
KIGIT::GitRemotePtr remotePtr( remote );
|
||||
|
||||
git_remote_callbacks remoteCallbacks;
|
||||
git_remote_init_callbacks( &remoteCallbacks, GIT_REMOTE_CALLBACKS_VERSION );
|
||||
remoteCallbacks.sideband_progress = progress_cb;
|
||||
remoteCallbacks.transfer_progress = transfer_progress_cb;
|
||||
remoteCallbacks.credentials = credentials_cb;
|
||||
remoteCallbacks.payload = this;
|
||||
GetCommon()->SetCancelled( false );
|
||||
|
||||
TestedTypes() = 0;
|
||||
ResetNextKey();
|
||||
|
||||
if( git_remote_connect( remote, GIT_DIRECTION_FETCH, &remoteCallbacks, nullptr, nullptr ) )
|
||||
{
|
||||
wxString errorMsg = KIGIT_COMMON::GetLastGitError();
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - Failed to connect to remote: %s", errorMsg );
|
||||
AddErrorString( wxString::Format( _( "Could not connect to remote '%s': %s" ), "origin", errorMsg ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
git_fetch_options fetchOptions;
|
||||
git_fetch_init_options( &fetchOptions, GIT_FETCH_OPTIONS_VERSION );
|
||||
fetchOptions.callbacks = remoteCallbacks;
|
||||
|
||||
if( git_remote_fetch( remote, nullptr, &fetchOptions, nullptr ) )
|
||||
{
|
||||
wxString errorMsg = KIGIT_COMMON::GetLastGitError();
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - Failed to fetch from remote: %s", errorMsg );
|
||||
AddErrorString( wxString::Format( _( "Could not fetch data from remote '%s': %s" ), "origin", errorMsg ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformFetch() - Fetch completed successfully" );
|
||||
return true;
|
||||
return GetGitBackend()->PerformFetch( this, aSkipLock );
|
||||
}
|
||||
|
||||
|
||||
PullResult GIT_PULL_HANDLER::PerformPull()
|
||||
{
|
||||
PullResult result = PullResult::Success;
|
||||
std::unique_lock<std::mutex> lock( GetCommon()->m_gitActionMutex, std::try_to_lock );
|
||||
|
||||
if( !lock.owns_lock() )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Could not lock mutex" );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
if( !PerformFetch( true ) )
|
||||
return PullResult::Error;
|
||||
|
||||
git_oid pull_merge_oid = {};
|
||||
|
||||
if( git_repository_fetchhead_foreach( GetRepo(), fetchhead_foreach_cb,
|
||||
&pull_merge_oid ) )
|
||||
{
|
||||
AddErrorString( _( "Could not read 'FETCH_HEAD'" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
git_annotated_commit* fetchhead_commit;
|
||||
|
||||
if( git_annotated_commit_lookup( &fetchhead_commit, GetRepo(), &pull_merge_oid ) )
|
||||
{
|
||||
AddErrorString( _( "Could not lookup commit" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitAnnotatedCommitPtr fetchheadCommitPtr( fetchhead_commit );
|
||||
const git_annotated_commit* merge_commits[] = { fetchhead_commit };
|
||||
git_merge_analysis_t merge_analysis;
|
||||
git_merge_preference_t merge_preference = GIT_MERGE_PREFERENCE_NONE;
|
||||
|
||||
if( git_merge_analysis( &merge_analysis, &merge_preference, GetRepo(), merge_commits, 1 ) )
|
||||
{
|
||||
AddErrorString( _( "Could not analyze merge" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
if( merge_analysis & GIT_MERGE_ANALYSIS_UNBORN )
|
||||
{
|
||||
AddErrorString( _( "Invalid HEAD. Cannot merge." ) );
|
||||
return PullResult::MergeFailed;
|
||||
}
|
||||
|
||||
// Nothing to do if the repository is up to date
|
||||
if( merge_analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Repository is up to date" );
|
||||
git_repository_state_cleanup( GetRepo() );
|
||||
return PullResult::UpToDate;
|
||||
}
|
||||
|
||||
// Fast-forward is easy, just update the local reference
|
||||
if( merge_analysis & GIT_MERGE_ANALYSIS_FASTFORWARD )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Fast-forward merge" );
|
||||
return handleFastForward();
|
||||
}
|
||||
|
||||
if( merge_analysis & GIT_MERGE_ANALYSIS_NORMAL )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Normal merge" );
|
||||
|
||||
// Check git config to determine if we should rebase or merge
|
||||
git_config* config = nullptr;
|
||||
|
||||
if( git_repository_config( &config, GetRepo() ) != GIT_OK )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Failed to get repository config" );
|
||||
AddErrorString( _( "Could not access repository configuration" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitConfigPtr configPtr( config );
|
||||
|
||||
// Check for pull.rebase config
|
||||
int rebase_value = 0;
|
||||
int ret = git_config_get_bool( &rebase_value, config, "pull.rebase" );
|
||||
|
||||
// If pull.rebase is set to true, use rebase; otherwise use merge
|
||||
if( ret == GIT_OK && rebase_value )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Using rebase based on config" );
|
||||
return handleRebase( merge_commits, 1 );
|
||||
}
|
||||
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Using merge based on config" );
|
||||
return handleMerge( merge_commits, 1 );
|
||||
}
|
||||
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::PerformPull() - Merge needs resolution" );
|
||||
//TODO: handle merges when they need to be resolved
|
||||
|
||||
return result;
|
||||
return GetGitBackend()->PerformPull( this );
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::string, std::vector<CommitDetails>>>&
|
||||
@ -212,384 +46,7 @@ GIT_PULL_HANDLER::GetFetchResults() const
|
||||
return m_fetchResults;
|
||||
}
|
||||
|
||||
|
||||
std::string GIT_PULL_HANDLER::getFirstLineFromCommitMessage( const std::string& aMessage )
|
||||
{
|
||||
if( aMessage.empty() )
|
||||
return aMessage;
|
||||
|
||||
size_t firstLineEnd = aMessage.find_first_of( '\n' );
|
||||
|
||||
if( firstLineEnd != std::string::npos )
|
||||
return aMessage.substr( 0, firstLineEnd );
|
||||
|
||||
return aMessage;
|
||||
}
|
||||
|
||||
|
||||
std::string GIT_PULL_HANDLER::getFormattedCommitDate( const git_time& aTime )
|
||||
{
|
||||
char dateBuffer[64];
|
||||
time_t time = static_cast<time_t>( aTime.time );
|
||||
struct tm timeInfo;
|
||||
#ifdef _WIN32
|
||||
localtime_s( &timeInfo, &time );
|
||||
#else
|
||||
gmtime_r( &time, &timeInfo );
|
||||
#endif
|
||||
strftime( dateBuffer, sizeof( dateBuffer ), "%Y-%b-%d %H:%M:%S", &timeInfo );
|
||||
return dateBuffer;
|
||||
}
|
||||
|
||||
|
||||
PullResult GIT_PULL_HANDLER::handleFastForward()
|
||||
{
|
||||
git_reference* rawRef = nullptr;
|
||||
|
||||
// Get the current HEAD reference
|
||||
if( git_repository_head( &rawRef, GetRepo() ) )
|
||||
{
|
||||
AddErrorString( _( "Could not get repository head" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitReferencePtr headRef( rawRef );
|
||||
|
||||
git_oid updatedRefOid;
|
||||
const char* currentBranchName = git_reference_name( rawRef );
|
||||
const char* branch_shorthand = git_reference_shorthand( rawRef );
|
||||
wxString remote_name = GetRemotename();
|
||||
wxString remoteBranchName = wxString::Format( "refs/remotes/%s/%s",
|
||||
remote_name, branch_shorthand );
|
||||
|
||||
// Get the OID of the updated reference (remote-tracking branch)
|
||||
if( git_reference_name_to_id( &updatedRefOid, GetRepo(), remoteBranchName.c_str() ) != GIT_OK )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Could not get reference OID for reference '%s'" ),
|
||||
remoteBranchName ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
// Get the target commit object
|
||||
git_commit* targetCommit = nullptr;
|
||||
|
||||
if( git_commit_lookup( &targetCommit, GetRepo(), &updatedRefOid ) != GIT_OK )
|
||||
{
|
||||
AddErrorString( _( "Could not look up target commit" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitCommitPtr targetCommitPtr( targetCommit );
|
||||
|
||||
// Get the tree from the target commit
|
||||
git_tree* targetTree = nullptr;
|
||||
|
||||
if( git_commit_tree( &targetTree, targetCommit ) != GIT_OK )
|
||||
{
|
||||
git_commit_free( targetCommit );
|
||||
AddErrorString( _( "Could not get tree from target commit" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitTreePtr targetTreePtr( targetTree );
|
||||
|
||||
// Perform a checkout to update the working directory
|
||||
git_checkout_options checkoutOptions;
|
||||
git_checkout_init_options( &checkoutOptions, GIT_CHECKOUT_OPTIONS_VERSION );
|
||||
auto notify_cb = []( git_checkout_notify_t why, const char* path, const git_diff_file* baseline,
|
||||
const git_diff_file* target, const git_diff_file* workdir, void* payload ) -> int
|
||||
{
|
||||
switch( why )
|
||||
{
|
||||
case GIT_CHECKOUT_NOTIFY_CONFLICT:
|
||||
wxLogTrace( traceGit, "Checkout conflict: %s", path ? path : "unknown" );
|
||||
break;
|
||||
case GIT_CHECKOUT_NOTIFY_DIRTY:
|
||||
wxLogTrace( traceGit, "Checkout dirty: %s", path ? path : "unknown" );
|
||||
break;
|
||||
case GIT_CHECKOUT_NOTIFY_UPDATED:
|
||||
wxLogTrace( traceGit, "Checkout updated: %s", path ? path : "unknown" );
|
||||
break;
|
||||
case GIT_CHECKOUT_NOTIFY_UNTRACKED:
|
||||
wxLogTrace( traceGit, "Checkout untracked: %s", path ? path : "unknown" );
|
||||
break;
|
||||
case GIT_CHECKOUT_NOTIFY_IGNORED:
|
||||
wxLogTrace( traceGit, "Checkout ignored: %s", path ? path : "unknown" );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
checkoutOptions.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS;
|
||||
checkoutOptions.notify_flags = GIT_CHECKOUT_NOTIFY_ALL;
|
||||
checkoutOptions.notify_cb = notify_cb;
|
||||
|
||||
if( git_checkout_tree( GetRepo(), reinterpret_cast<git_object*>( targetTree ), &checkoutOptions ) != GIT_OK )
|
||||
{
|
||||
AddErrorString( _( "Failed to perform checkout operation." ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
git_reference* updatedRef = nullptr;
|
||||
|
||||
// Update the current branch to point to the new commit
|
||||
if (git_reference_set_target(&updatedRef, rawRef, &updatedRefOid, nullptr) != GIT_OK)
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Failed to update reference '%s' to point to '%s'" ), currentBranchName,
|
||||
git_oid_tostr_s( &updatedRefOid ) ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitReferencePtr updatedRefPtr( updatedRef );
|
||||
|
||||
// Clean up the repository state
|
||||
if( git_repository_state_cleanup( GetRepo() ) != GIT_OK )
|
||||
{
|
||||
AddErrorString( _( "Failed to clean up repository state after fast-forward." ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
git_revwalk* revWalker = nullptr;
|
||||
|
||||
// Collect commit details for updated references
|
||||
if( git_revwalk_new( &revWalker, GetRepo() ) != GIT_OK )
|
||||
{
|
||||
AddErrorString( _( "Failed to initialize revision walker." ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitRevWalkPtr revWalkerPtr( revWalker );
|
||||
git_revwalk_sorting( revWalker, GIT_SORT_TIME );
|
||||
|
||||
if( git_revwalk_push_glob( revWalker, currentBranchName ) != GIT_OK )
|
||||
{
|
||||
AddErrorString( _( "Failed to push reference to revision walker." ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::vector<CommitDetails>>& branchCommits = m_fetchResults.emplace_back();
|
||||
branchCommits.first = currentBranchName;
|
||||
|
||||
git_oid commitOid;
|
||||
|
||||
while( git_revwalk_next( &commitOid, revWalker ) == GIT_OK )
|
||||
{
|
||||
git_commit* commit = nullptr;
|
||||
|
||||
if( git_commit_lookup( &commit, GetRepo(), &commitOid ) )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Could not lookup commit '%s'" ),
|
||||
git_oid_tostr_s( &commitOid ) ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitCommitPtr commitPtr( commit );
|
||||
|
||||
CommitDetails details;
|
||||
details.m_sha = git_oid_tostr_s( &commitOid );
|
||||
details.m_firstLine = getFirstLineFromCommitMessage( git_commit_message( commit ) );
|
||||
details.m_author = git_commit_author( commit )->name;
|
||||
details.m_date = getFormattedCommitDate( git_commit_author( commit )->when );
|
||||
|
||||
branchCommits.second.push_back( details );
|
||||
}
|
||||
|
||||
return PullResult::FastForward;
|
||||
}
|
||||
|
||||
|
||||
PullResult GIT_PULL_HANDLER::handleMerge( const git_annotated_commit** aMergeHeads,
|
||||
size_t aMergeHeadsCount )
|
||||
{
|
||||
git_merge_options merge_opts;
|
||||
git_merge_options_init( &merge_opts, GIT_MERGE_OPTIONS_VERSION );
|
||||
|
||||
git_checkout_options checkout_opts;
|
||||
git_checkout_init_options( &checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION );
|
||||
|
||||
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
|
||||
|
||||
if( git_merge( GetRepo(), aMergeHeads, aMergeHeadsCount, &merge_opts, &checkout_opts ) )
|
||||
{
|
||||
AddErrorString( _( "Could not merge commits" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
// Get the repository index
|
||||
git_index* index = nullptr;
|
||||
|
||||
if( git_repository_index( &index, GetRepo() ) )
|
||||
{
|
||||
AddErrorString( _( "Could not get repository index" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitIndexPtr indexPtr( index );
|
||||
|
||||
// Check for conflicts
|
||||
git_index_conflict_iterator* conflicts = nullptr;
|
||||
|
||||
if( git_index_conflict_iterator_new( &conflicts, index ) )
|
||||
{
|
||||
AddErrorString( _( "Could not get conflict iterator" ) );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitIndexConflictIteratorPtr conflictsPtr( conflicts );
|
||||
|
||||
const git_index_entry* ancestor = nullptr;
|
||||
const git_index_entry* our = nullptr;
|
||||
const git_index_entry* their = nullptr;
|
||||
std::vector<ConflictData> conflict_data;
|
||||
|
||||
while( git_index_conflict_next( &ancestor, &our, &their, conflicts ) == 0 )
|
||||
{
|
||||
// Case 3: Both files have changed
|
||||
if( ancestor && our && their )
|
||||
{
|
||||
ConflictData conflict_datum;
|
||||
conflict_datum.filename = our->path;
|
||||
conflict_datum.our_oid = our->id;
|
||||
conflict_datum.their_oid = their->id;
|
||||
conflict_datum.our_commit_time = our->mtime.seconds;
|
||||
conflict_datum.their_commit_time = their->mtime.seconds;
|
||||
conflict_datum.our_status = _( "Changed" );
|
||||
conflict_datum.their_status = _( "Changed" );
|
||||
conflict_datum.use_ours = true;
|
||||
|
||||
conflict_data.push_back( conflict_datum );
|
||||
}
|
||||
// Case 4: File added in both ours and theirs
|
||||
else if( !ancestor && our && their )
|
||||
{
|
||||
ConflictData conflict_datum;
|
||||
conflict_datum.filename = our->path;
|
||||
conflict_datum.our_oid = our->id;
|
||||
conflict_datum.their_oid = their->id;
|
||||
conflict_datum.our_commit_time = our->mtime.seconds;
|
||||
conflict_datum.their_commit_time = their->mtime.seconds;
|
||||
conflict_datum.our_status = _( "Added" );
|
||||
conflict_datum.their_status = _( "Added" );
|
||||
conflict_datum.use_ours = true;
|
||||
|
||||
conflict_data.push_back( conflict_datum );
|
||||
}
|
||||
// Case 1: Remote file has changed or been added, local file has not
|
||||
else if( their && !our )
|
||||
{
|
||||
// Accept their changes
|
||||
git_index_add( index, their );
|
||||
}
|
||||
// Case 2: Local file has changed or been added, remote file has not
|
||||
else if( our && !their )
|
||||
{
|
||||
// Accept our changes
|
||||
git_index_add( index, our );
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogError( wxS( "Unexpected conflict state" ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( conflict_data.empty() )
|
||||
{
|
||||
git_index_conflict_cleanup( index );
|
||||
git_index_write( index );
|
||||
}
|
||||
|
||||
return conflict_data.empty() ? PullResult::Success : PullResult::MergeFailed;
|
||||
}
|
||||
|
||||
|
||||
PullResult GIT_PULL_HANDLER::handleRebase( const git_annotated_commit** aMergeHeads, size_t aMergeHeadsCount )
|
||||
{
|
||||
// Get the current branch reference
|
||||
git_reference* head_ref = nullptr;
|
||||
|
||||
if( git_repository_head( &head_ref, GetRepo() ) )
|
||||
{
|
||||
wxString errorMsg = KIGIT_COMMON::GetLastGitError();
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to get HEAD: %s", errorMsg );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitReferencePtr headRefPtr(head_ref);
|
||||
|
||||
// Initialize rebase operation
|
||||
git_rebase* rebase = nullptr;
|
||||
git_rebase_options rebase_opts = GIT_REBASE_OPTIONS_INIT;
|
||||
rebase_opts.checkout_options.checkout_strategy = GIT_CHECKOUT_SAFE;
|
||||
|
||||
if( git_rebase_init( &rebase, GetRepo(), nullptr, nullptr, aMergeHeads[0], &rebase_opts ) )
|
||||
{
|
||||
wxString errorMsg = KIGIT_COMMON::GetLastGitError();
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to initialize rebase: %s", errorMsg );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitRebasePtr rebasePtr( rebase );
|
||||
git_rebase_operation* operation = nullptr;
|
||||
|
||||
while( git_rebase_next( &operation, rebase ) != GIT_ITEROVER )
|
||||
{
|
||||
// Check for conflicts
|
||||
git_index* index = nullptr;
|
||||
if( git_repository_index( &index, GetRepo() ) )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to get index: %s",
|
||||
KIGIT_COMMON::GetLastGitError() );
|
||||
return PullResult::Error;
|
||||
}
|
||||
KIGIT::GitIndexPtr indexPtr( index );
|
||||
|
||||
if( git_index_has_conflicts( index ) )
|
||||
{
|
||||
// Abort the rebase if there are conflicts because we need to merge manually
|
||||
git_rebase_abort( rebase );
|
||||
AddErrorString( _( "Conflicts detected during rebase" ) );
|
||||
return PullResult::MergeFailed;
|
||||
}
|
||||
|
||||
git_oid commit_id;
|
||||
git_signature* committer = nullptr;
|
||||
|
||||
if( git_signature_default( &committer, GetRepo() ) )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to create signature: %s",
|
||||
KIGIT_COMMON::GetLastGitError() );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitSignaturePtr committerPtr( committer );
|
||||
|
||||
if( git_rebase_commit( &commit_id, rebase, nullptr, committer, nullptr, nullptr ) != GIT_OK )
|
||||
{
|
||||
wxString errorMsg = KIGIT_COMMON::GetLastGitError();
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to commit operation: %s", errorMsg );
|
||||
git_rebase_abort( rebase );
|
||||
return PullResult::Error;
|
||||
}
|
||||
}
|
||||
|
||||
// Finish the rebase
|
||||
if( git_rebase_finish( rebase, nullptr ) )
|
||||
{
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Failed to finish rebase: %s",
|
||||
KIGIT_COMMON::GetLastGitError() );
|
||||
return PullResult::Error;
|
||||
}
|
||||
|
||||
wxLogTrace( traceGit, "GIT_PULL_HANDLER::handleRebase() - Rebase completed successfully" );
|
||||
git_repository_state_cleanup( GetRepo() );
|
||||
return PullResult::Success;
|
||||
}
|
||||
|
||||
|
||||
void GIT_PULL_HANDLER::UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage )
|
||||
{
|
||||
|
||||
ReportProgress( aCurrent, aTotal, aMessage );
|
||||
}
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
#include <git2.h>
|
||||
|
||||
// Structure to store commit details
|
||||
struct CommitDetails
|
||||
@ -50,22 +49,12 @@ enum class PullResult : int
|
||||
FastForward
|
||||
};
|
||||
|
||||
struct ConflictData
|
||||
{
|
||||
std::string filename;
|
||||
std::string our_status;
|
||||
std::string their_status;
|
||||
git_oid our_oid;
|
||||
git_oid their_oid;
|
||||
git_time_t our_commit_time;
|
||||
git_time_t their_commit_time;
|
||||
bool use_ours; // Flag indicating user's choice (true = ours, false = theirs)
|
||||
};
|
||||
|
||||
class LIBGIT_BACKEND;
|
||||
|
||||
class GIT_PULL_HANDLER : public KIGIT_REPO_MIXIN
|
||||
{
|
||||
public:
|
||||
friend class LIBGIT_BACKEND;
|
||||
GIT_PULL_HANDLER( KIGIT_COMMON* aCommon );
|
||||
~GIT_PULL_HANDLER();
|
||||
|
||||
@ -77,15 +66,8 @@ public:
|
||||
// Implementation for progress updates
|
||||
void UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage ) override;
|
||||
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::string, std::vector<CommitDetails>>> m_fetchResults;
|
||||
|
||||
std::string getFirstLineFromCommitMessage( const std::string& aMessage );
|
||||
std::string getFormattedCommitDate( const git_time& aTime );
|
||||
PullResult handleFastForward();
|
||||
PullResult handleMerge( const git_annotated_commit** aMergeHeads, size_t aMergeHeadsCount );
|
||||
PullResult handleRebase( const git_annotated_commit** aMergeHeads, size_t aMergeHeadsCount );
|
||||
};
|
||||
|
||||
#endif // _GIT_PULL_HANDLER_H_
|
||||
|
@ -22,13 +22,8 @@
|
||||
*/
|
||||
|
||||
#include "git_push_handler.h"
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <git/kicad_git_memory.h>
|
||||
#include <trace_helpers.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <wx/log.h>
|
||||
#include "git_backend.h"
|
||||
|
||||
GIT_PUSH_HANDLER::GIT_PUSH_HANDLER( KIGIT_COMMON* aRepo ) : KIGIT_REPO_MIXIN( aRepo )
|
||||
{}
|
||||
@ -38,79 +33,7 @@ GIT_PUSH_HANDLER::~GIT_PUSH_HANDLER()
|
||||
|
||||
PushResult GIT_PUSH_HANDLER::PerformPush()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock( GetCommon()->m_gitActionMutex, std::try_to_lock );
|
||||
|
||||
if(!lock.owns_lock())
|
||||
{
|
||||
wxLogTrace(traceGit, "GIT_PUSH_HANDLER::PerformPush: Could not lock mutex");
|
||||
return PushResult::Error;
|
||||
}
|
||||
|
||||
PushResult result = PushResult::Success;
|
||||
|
||||
// Fetch updates from remote repository
|
||||
git_remote* remote = nullptr;
|
||||
|
||||
if(git_remote_lookup(&remote, GetRepo(), "origin") != 0)
|
||||
{
|
||||
AddErrorString(_("Could not lookup remote"));
|
||||
return PushResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitRemotePtr remotePtr(remote);
|
||||
|
||||
git_remote_callbacks remoteCallbacks;
|
||||
git_remote_init_callbacks(&remoteCallbacks, GIT_REMOTE_CALLBACKS_VERSION);
|
||||
remoteCallbacks.sideband_progress = progress_cb;
|
||||
remoteCallbacks.transfer_progress = transfer_progress_cb;
|
||||
remoteCallbacks.update_tips = update_cb;
|
||||
remoteCallbacks.push_transfer_progress = push_transfer_progress_cb;
|
||||
remoteCallbacks.credentials = credentials_cb;
|
||||
remoteCallbacks.payload = this;
|
||||
GetCommon()->SetCancelled( false );
|
||||
|
||||
TestedTypes() = 0;
|
||||
ResetNextKey();
|
||||
|
||||
if( git_remote_connect( remote, GIT_DIRECTION_PUSH, &remoteCallbacks, nullptr, nullptr ) )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Could not connect to remote: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
return PushResult::Error;
|
||||
}
|
||||
|
||||
git_push_options pushOptions;
|
||||
git_push_init_options( &pushOptions, GIT_PUSH_OPTIONS_VERSION );
|
||||
pushOptions.callbacks = remoteCallbacks;
|
||||
|
||||
// Get the current HEAD reference
|
||||
git_reference* head = nullptr;
|
||||
|
||||
if( git_repository_head( &head, GetRepo() ) != 0 )
|
||||
{
|
||||
git_remote_disconnect( remote );
|
||||
AddErrorString( _( "Could not get repository head" ) );
|
||||
return PushResult::Error;
|
||||
}
|
||||
|
||||
KIGIT::GitReferencePtr headPtr( head );
|
||||
|
||||
// Create refspec for current branch
|
||||
const char* refs[1];
|
||||
refs[0] = git_reference_name( head );
|
||||
const git_strarray refspecs = { (char**) refs, 1 };
|
||||
|
||||
if( git_remote_push( remote, &refspecs, &pushOptions ) )
|
||||
{
|
||||
AddErrorString( wxString::Format( _( "Could not push to remote: %s" ),
|
||||
KIGIT_COMMON::GetLastGitError() ) );
|
||||
git_remote_disconnect( remote );
|
||||
return PushResult::Error;
|
||||
}
|
||||
|
||||
git_remote_disconnect( remote );
|
||||
|
||||
return result;
|
||||
return GetGitBackend()->Push( this );
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,15 +21,14 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <wx/string.h>
|
||||
#include "git_remove_from_index_handler.h"
|
||||
#include "git_backend.h"
|
||||
|
||||
#include <wx/log.h>
|
||||
|
||||
#include <git/kicad_git_memory.h>
|
||||
#include "git_remove_from_index_handler.h"
|
||||
|
||||
GIT_REMOVE_FROM_INDEX_HANDLER::GIT_REMOVE_FROM_INDEX_HANDLER( git_repository* aRepository )
|
||||
GIT_REMOVE_FROM_INDEX_HANDLER::GIT_REMOVE_FROM_INDEX_HANDLER( git_repository* aRepository ) :
|
||||
KIGIT_COMMON( aRepository )
|
||||
{
|
||||
m_repository = aRepository;
|
||||
m_filesToRemove.clear();
|
||||
}
|
||||
|
||||
@ -41,61 +40,11 @@ GIT_REMOVE_FROM_INDEX_HANDLER::~GIT_REMOVE_FROM_INDEX_HANDLER()
|
||||
|
||||
bool GIT_REMOVE_FROM_INDEX_HANDLER::RemoveFromIndex( const wxString& aFilePath )
|
||||
{
|
||||
// Test if file is currently in the index
|
||||
|
||||
git_index* index = nullptr;
|
||||
size_t at_pos = 0;
|
||||
|
||||
if( git_repository_index( &index, m_repository ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to get repository index" );
|
||||
return false;
|
||||
}
|
||||
|
||||
KIGIT::GitIndexPtr indexPtr( index );
|
||||
|
||||
if( git_index_find( &at_pos, index, aFilePath.ToUTF8().data() ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to find index entry for %s", aFilePath );
|
||||
return false;
|
||||
}
|
||||
|
||||
m_filesToRemove.push_back( aFilePath );
|
||||
return true;
|
||||
return GetGitBackend()->RemoveFromIndex( this, aFilePath );
|
||||
}
|
||||
|
||||
|
||||
void GIT_REMOVE_FROM_INDEX_HANDLER::PerformRemoveFromIndex()
|
||||
{
|
||||
for( auto& file : m_filesToRemove )
|
||||
{
|
||||
git_index* index = nullptr;
|
||||
git_oid oid;
|
||||
|
||||
if( git_repository_index( &index, m_repository ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to get repository index" );
|
||||
return;
|
||||
}
|
||||
|
||||
KIGIT::GitIndexPtr indexPtr( index );
|
||||
|
||||
if( git_index_remove_bypath( index, file.ToUTF8().data() ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to remove index entry for %s", file );
|
||||
return;
|
||||
}
|
||||
|
||||
if( git_index_write( index ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to write index" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( git_index_write_tree( &oid, index ) != 0 )
|
||||
{
|
||||
wxLogError( "Failed to write index tree" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
GetGitBackend()->PerformRemoveFromIndex( this );
|
||||
}
|
||||
|
@ -24,12 +24,13 @@
|
||||
#ifndef GIT_REMOVE_FROM_INDEX_HANDLER_H_
|
||||
#define GIT_REMOVE_FROM_INDEX_HANDLER_H_
|
||||
|
||||
#include <git2.h>
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <vector>
|
||||
#include <wx/string.h>
|
||||
|
||||
class wxString;
|
||||
class LIBGIT_BACKEND;
|
||||
|
||||
class GIT_REMOVE_FROM_INDEX_HANDLER
|
||||
class GIT_REMOVE_FROM_INDEX_HANDLER : public KIGIT_COMMON
|
||||
{
|
||||
public:
|
||||
GIT_REMOVE_FROM_INDEX_HANDLER( git_repository* aRepository );
|
||||
@ -41,7 +42,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
git_repository* m_repository;
|
||||
friend class LIBGIT_BACKEND;
|
||||
|
||||
std::vector<wxString> m_filesToRemove;
|
||||
};
|
||||
|
@ -22,11 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "git_revert_handler.h"
|
||||
|
||||
#include <wx/log.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include <trace_helpers.h>
|
||||
#include "git_backend.h"
|
||||
|
||||
|
||||
GIT_REVERT_HANDLER::GIT_REVERT_HANDLER( git_repository* aRepository )
|
||||
@ -46,74 +42,8 @@ bool GIT_REVERT_HANDLER::Revert( const wxString& aFilePath )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void checkout_progress_cb( const char *path, size_t cur, size_t tot, void *payload )
|
||||
{
|
||||
wxLogTrace( traceGit, wxS( "checkout_progress_cb: %s %zu/%zu" ), path, cur, tot );
|
||||
}
|
||||
|
||||
|
||||
static int checkout_notify_cb( git_checkout_notify_t why, const char *path,
|
||||
const git_diff_file *baseline,
|
||||
const git_diff_file *target,
|
||||
const git_diff_file *workdir, void *payload )
|
||||
{
|
||||
GIT_REVERT_HANDLER* handler = static_cast<GIT_REVERT_HANDLER*>(payload);
|
||||
|
||||
if( why & ( GIT_CHECKOUT_NOTIFY_CONFLICT | GIT_CHECKOUT_NOTIFY_IGNORED
|
||||
| GIT_CHECKOUT_NOTIFY_UPDATED ) )
|
||||
handler->PushFailedFile( path );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void GIT_REVERT_HANDLER::PerformRevert()
|
||||
{
|
||||
git_object* head_commit = NULL;
|
||||
git_checkout_options opts;
|
||||
git_checkout_init_options( &opts, GIT_CHECKOUT_OPTIONS_VERSION );
|
||||
|
||||
// Get the HEAD commit
|
||||
if( git_revparse_single( &head_commit, m_repository, "HEAD" ) != 0 )
|
||||
{
|
||||
// Handle error. If we cannot get the HEAD, then there's no point proceeding.
|
||||
return;
|
||||
}
|
||||
|
||||
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
char** paths = new char*[m_filesToRevert.size()];
|
||||
|
||||
for( size_t ii = 0; ii < m_filesToRevert.size(); ii++ )
|
||||
{
|
||||
// Set paths to the specific file
|
||||
paths[ii] = wxStrdup( m_filesToRevert[ii].ToUTF8() );
|
||||
}
|
||||
|
||||
git_strarray arr = { paths, m_filesToRevert.size() };
|
||||
|
||||
opts.paths = arr;
|
||||
opts.progress_cb = checkout_progress_cb;
|
||||
opts.notify_cb = checkout_notify_cb;
|
||||
opts.notify_payload = static_cast<void*>( this );
|
||||
|
||||
// Attempt to checkout the file(s)
|
||||
if( git_checkout_tree(m_repository, head_commit, &opts ) != 0 )
|
||||
{
|
||||
const git_error *e = git_error_last();
|
||||
|
||||
if( e )
|
||||
{
|
||||
wxLogTrace( traceGit, wxS( "Checkout failed: %d: %s" ), e->klass, e->message );
|
||||
}
|
||||
}
|
||||
|
||||
// Free the HEAD commit
|
||||
for( size_t ii = 0; ii < m_filesToRevert.size(); ii++ )
|
||||
delete( paths[ii] );
|
||||
|
||||
delete[] paths;
|
||||
|
||||
git_object_free( head_commit );
|
||||
GetGitBackend()->PerformRevert( this );
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,10 @@
|
||||
#include <git2.h>
|
||||
#include <vector>
|
||||
#include <wx/string.h>
|
||||
// TEMPORARY HACKFIX INCLUDE FOR STD::VECTOR EXPORT OUT OF KICOMMON ON WINDOWS
|
||||
#include <settings/parameters.h>
|
||||
|
||||
class LIBGIT_BACKEND;
|
||||
|
||||
class GIT_REVERT_HANDLER
|
||||
{
|
||||
@ -44,6 +48,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
friend class LIBGIT_BACKEND;
|
||||
git_repository* m_repository;
|
||||
|
||||
std::vector<wxString> m_filesToRevert;
|
||||
|
@ -22,10 +22,8 @@
|
||||
*/
|
||||
|
||||
#include "git_status_handler.h"
|
||||
#include <git/kicad_git_common.h>
|
||||
#include <git/kicad_git_memory.h>
|
||||
#include <trace_helpers.h>
|
||||
#include <wx/log.h>
|
||||
#include "git_backend.h"
|
||||
|
||||
GIT_STATUS_HANDLER::GIT_STATUS_HANDLER( KIGIT_COMMON* aCommon ) : KIGIT_REPO_MIXIN( aCommon )
|
||||
{}
|
||||
@ -35,171 +33,29 @@ GIT_STATUS_HANDLER::~GIT_STATUS_HANDLER()
|
||||
|
||||
bool GIT_STATUS_HANDLER::HasChangedFiles()
|
||||
{
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
return false;
|
||||
|
||||
git_status_options opts;
|
||||
git_status_init_options( &opts, GIT_STATUS_OPTIONS_VERSION );
|
||||
|
||||
opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
|
||||
opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
|
||||
| GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
|
||||
|
||||
git_status_list* status_list = nullptr;
|
||||
|
||||
if( git_status_list_new( &status_list, repo, &opts ) != GIT_OK )
|
||||
{
|
||||
wxLogTrace( traceGit, "Failed to get status list: %s", KIGIT_COMMON::GetLastGitError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
KIGIT::GitStatusListPtr status_list_ptr( status_list );
|
||||
bool hasChanges = ( git_status_list_entrycount( status_list ) > 0 );
|
||||
|
||||
return hasChanges;
|
||||
return GetGitBackend()->HasChangedFiles( this );
|
||||
}
|
||||
|
||||
std::map<wxString, FileStatus> GIT_STATUS_HANDLER::GetFileStatus( const wxString& aPathspec )
|
||||
{
|
||||
std::map<wxString, FileStatus> fileStatusMap;
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
return fileStatusMap;
|
||||
|
||||
git_status_options status_options;
|
||||
git_status_init_options( &status_options, GIT_STATUS_OPTIONS_VERSION );
|
||||
status_options.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
|
||||
status_options.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_INCLUDE_UNMODIFIED;
|
||||
|
||||
// Set up pathspec if provided
|
||||
std::string pathspec_str;
|
||||
std::vector<const char*> pathspec_ptrs;
|
||||
|
||||
if( !aPathspec.IsEmpty() )
|
||||
{
|
||||
pathspec_str = aPathspec.ToStdString();
|
||||
pathspec_ptrs.push_back( pathspec_str.c_str() );
|
||||
|
||||
status_options.pathspec.strings = const_cast<char**>( pathspec_ptrs.data() );
|
||||
status_options.pathspec.count = pathspec_ptrs.size();
|
||||
}
|
||||
|
||||
git_status_list* status_list = nullptr;
|
||||
|
||||
if( git_status_list_new( &status_list, repo, &status_options ) != GIT_OK )
|
||||
{
|
||||
wxLogTrace( traceGit, "Failed to get git status list: %s", KIGIT_COMMON::GetLastGitError() );
|
||||
return fileStatusMap;
|
||||
}
|
||||
|
||||
KIGIT::GitStatusListPtr statusListPtr( status_list );
|
||||
|
||||
size_t count = git_status_list_entrycount( status_list );
|
||||
wxString repoWorkDir( git_repository_workdir( repo ) );
|
||||
|
||||
for( size_t ii = 0; ii < count; ++ii )
|
||||
{
|
||||
const git_status_entry* entry = git_status_byindex( status_list, ii );
|
||||
std::string path( entry->head_to_index ? entry->head_to_index->old_file.path
|
||||
: entry->index_to_workdir->old_file.path );
|
||||
|
||||
wxString absPath = repoWorkDir + path;
|
||||
|
||||
FileStatus fileStatus;
|
||||
fileStatus.filePath = absPath;
|
||||
fileStatus.gitStatus = entry->status;
|
||||
fileStatus.status = ConvertStatus( entry->status );
|
||||
|
||||
fileStatusMap[absPath] = fileStatus;
|
||||
}
|
||||
|
||||
return fileStatusMap;
|
||||
return GetGitBackend()->GetFileStatus( this, aPathspec );
|
||||
}
|
||||
|
||||
wxString GIT_STATUS_HANDLER::GetCurrentBranchName()
|
||||
{
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
return wxEmptyString;
|
||||
|
||||
git_reference* currentBranchReference = nullptr;
|
||||
int rc = git_repository_head( ¤tBranchReference, repo );
|
||||
KIGIT::GitReferencePtr currentBranchReferencePtr( currentBranchReference );
|
||||
|
||||
if( currentBranchReference )
|
||||
{
|
||||
return git_reference_shorthand( currentBranchReference );
|
||||
}
|
||||
else if( rc == GIT_EUNBORNBRANCH )
|
||||
{
|
||||
// Unborn branch - could return empty or a default name
|
||||
return wxEmptyString;
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( traceGit, "Failed to lookup current branch: %s", KIGIT_COMMON::GetLastGitError() );
|
||||
return wxEmptyString;
|
||||
}
|
||||
return GetGitBackend()->GetCurrentBranchName( this );
|
||||
}
|
||||
|
||||
void GIT_STATUS_HANDLER::UpdateRemoteStatus( const std::set<wxString>& aLocalChanges,
|
||||
const std::set<wxString>& aRemoteChanges,
|
||||
std::map<wxString, FileStatus>& aFileStatus )
|
||||
const std::set<wxString>& aRemoteChanges,
|
||||
std::map<wxString, FileStatus>& aFileStatus )
|
||||
{
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
return;
|
||||
|
||||
wxString repoWorkDir( git_repository_workdir( repo ) );
|
||||
|
||||
// Update status based on local/remote changes
|
||||
for( auto& [absPath, fileStatus] : aFileStatus )
|
||||
{
|
||||
// Convert absolute path to relative path for comparison
|
||||
wxString relativePath = absPath;
|
||||
if( relativePath.StartsWith( repoWorkDir ) )
|
||||
{
|
||||
relativePath = relativePath.Mid( repoWorkDir.length() );
|
||||
#ifdef _WIN32
|
||||
relativePath.Replace( wxS( "\\" ), wxS( "/" ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string relativePathStd = relativePath.ToStdString();
|
||||
|
||||
// Only update if the file is not already modified/added/deleted
|
||||
if( fileStatus.status == KIGIT_COMMON::GIT_STATUS::GIT_STATUS_CURRENT )
|
||||
{
|
||||
if( aLocalChanges.count( relativePathStd ) )
|
||||
{
|
||||
fileStatus.status = KIGIT_COMMON::GIT_STATUS::GIT_STATUS_AHEAD;
|
||||
}
|
||||
else if( aRemoteChanges.count( relativePathStd ) )
|
||||
{
|
||||
fileStatus.status = KIGIT_COMMON::GIT_STATUS::GIT_STATUS_BEHIND;
|
||||
}
|
||||
}
|
||||
}
|
||||
GetGitBackend()->UpdateRemoteStatus( this, aLocalChanges, aRemoteChanges, aFileStatus );
|
||||
}
|
||||
|
||||
wxString GIT_STATUS_HANDLER::GetWorkingDirectory()
|
||||
{
|
||||
git_repository* repo = GetRepo();
|
||||
|
||||
if( !repo )
|
||||
return wxEmptyString;
|
||||
|
||||
const char* workdir = git_repository_workdir( repo );
|
||||
|
||||
if( !workdir )
|
||||
return wxEmptyString;
|
||||
|
||||
return wxString( workdir );
|
||||
return GetGitBackend()->GetWorkingDirectory( this );
|
||||
}
|
||||
|
||||
KIGIT_COMMON::GIT_STATUS GIT_STATUS_HANDLER::ConvertStatus( unsigned int aGitStatus )
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
class LIBGIT_BACKEND;
|
||||
|
||||
struct FileStatus
|
||||
{
|
||||
wxString filePath;
|
||||
@ -80,6 +82,7 @@ public:
|
||||
void UpdateProgress( int aCurrent, int aTotal, const wxString& aMessage ) override;
|
||||
|
||||
private:
|
||||
friend class LIBGIT_BACKEND;
|
||||
/**
|
||||
* Convert git status flags to KIGIT_COMMON::GIT_STATUS
|
||||
* @param aGitStatus Raw git status flags
|
||||
|
@ -33,6 +33,8 @@
|
||||
|
||||
#include <wx/string.h>
|
||||
|
||||
class LIBGIT_BACKEND;
|
||||
|
||||
class KIGIT_COMMON
|
||||
{
|
||||
|
||||
@ -174,6 +176,7 @@ protected:
|
||||
friend class GIT_PUSH_HANDLER;
|
||||
friend class GIT_PULL_HANDLER;
|
||||
friend class GIT_CLONE_HANDLER;
|
||||
friend class LIBGIT_BACKEND;
|
||||
friend class PROJECT_TREE_PANE;
|
||||
|
||||
private:
|
||||
|
1358
common/git/libgit_backend.cpp
Normal file
1358
common/git/libgit_backend.cpp
Normal file
File diff suppressed because it is too large
Load Diff
100
common/git/libgit_backend.h
Normal file
100
common/git/libgit_backend.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/gpl-3.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 3 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef LIBGIT_BACKEND_H_
|
||||
#define LIBGIT_BACKEND_H_
|
||||
|
||||
#include "git_backend.h"
|
||||
|
||||
// Forward declarations to avoid exposing libgit2 headers
|
||||
struct git_annotated_commit;
|
||||
|
||||
class LIBGIT_BACKEND : public GIT_BACKEND
|
||||
{
|
||||
public:
|
||||
void Init() override;
|
||||
void Shutdown() override;
|
||||
bool IsLibraryAvailable() override;
|
||||
|
||||
bool Clone( GIT_CLONE_HANDLER* aHandler ) override;
|
||||
|
||||
CommitResult Commit( GIT_COMMIT_HANDLER* aHandler,
|
||||
const std::vector<wxString>& aFiles,
|
||||
const wxString& aMessage,
|
||||
const wxString& aAuthorName,
|
||||
const wxString& aAuthorEmail ) override;
|
||||
|
||||
PushResult Push( GIT_PUSH_HANDLER* aHandler ) override;
|
||||
|
||||
bool HasChangedFiles( GIT_STATUS_HANDLER* aHandler ) override;
|
||||
|
||||
std::map<wxString, FileStatus> GetFileStatus( GIT_STATUS_HANDLER* aHandler,
|
||||
const wxString& aPathspec ) override;
|
||||
|
||||
wxString GetCurrentBranchName( GIT_STATUS_HANDLER* aHandler ) override;
|
||||
|
||||
void UpdateRemoteStatus( GIT_STATUS_HANDLER* aHandler,
|
||||
const std::set<wxString>& aLocalChanges,
|
||||
const std::set<wxString>& aRemoteChanges,
|
||||
std::map<wxString, FileStatus>& aFileStatus ) override;
|
||||
|
||||
wxString GetWorkingDirectory( GIT_STATUS_HANDLER* aHandler ) override;
|
||||
|
||||
wxString GetWorkingDirectory( GIT_CONFIG_HANDLER* aHandler ) override;
|
||||
bool GetConfigString( GIT_CONFIG_HANDLER* aHandler, const wxString& aKey,
|
||||
wxString& aValue ) override;
|
||||
|
||||
bool IsRepository( GIT_INIT_HANDLER* aHandler, const wxString& aPath ) override;
|
||||
InitResult InitializeRepository( GIT_INIT_HANDLER* aHandler, const wxString& aPath ) override;
|
||||
bool SetupRemote( GIT_INIT_HANDLER* aHandler, const RemoteConfig& aConfig ) override;
|
||||
|
||||
BranchResult SwitchToBranch( GIT_BRANCH_HANDLER* aHandler, const wxString& aBranchName ) override;
|
||||
bool BranchExists( GIT_BRANCH_HANDLER* aHandler, const wxString& aBranchName ) override;
|
||||
|
||||
bool PerformFetch( GIT_PULL_HANDLER* aHandler, bool aSkipLock ) override;
|
||||
PullResult PerformPull( GIT_PULL_HANDLER* aHandler ) override;
|
||||
|
||||
void PerformRevert( GIT_REVERT_HANDLER* aHandler ) override;
|
||||
|
||||
git_repository* GetRepositoryForFile( const char* aFilename ) override;
|
||||
int CreateBranch( git_repository* aRepo, const wxString& aBranchName ) override;
|
||||
bool RemoveVCS( git_repository*& aRepo, const wxString& aProjectPath,
|
||||
bool aRemoveGitDir, wxString* aErrors ) override;
|
||||
|
||||
bool AddToIndex( GIT_ADD_TO_INDEX_HANDLER* aHandler, const wxString& aFilePath ) override;
|
||||
|
||||
bool PerformAddToIndex( GIT_ADD_TO_INDEX_HANDLER* aHandler ) override;
|
||||
|
||||
bool RemoveFromIndex( GIT_REMOVE_FROM_INDEX_HANDLER* aHandler, const wxString& aFilePath ) override;
|
||||
|
||||
void PerformRemoveFromIndex( GIT_REMOVE_FROM_INDEX_HANDLER* aHandler ) override;
|
||||
|
||||
private:
|
||||
PullResult handleFastForward( GIT_PULL_HANDLER* aHandler );
|
||||
PullResult handleMerge( GIT_PULL_HANDLER* aHandler, const git_annotated_commit** aMergeHeads,
|
||||
size_t aMergeHeadsCount );
|
||||
PullResult handleRebase( GIT_PULL_HANDLER* aHandler, const git_annotated_commit** aMergeHeads,
|
||||
size_t aMergeHeadsCount );
|
||||
};
|
||||
|
||||
#endif
|
@ -22,105 +22,25 @@
|
||||
*/
|
||||
|
||||
#include "project_git_utils.h"
|
||||
#include "kicad_git_common.h"
|
||||
#include "kicad_git_memory.h"
|
||||
#include <git/kicad_git_compat.h>
|
||||
#include <trace_helpers.h>
|
||||
#include <wx/log.h>
|
||||
#include <wx/filename.h>
|
||||
#include <gestfich.h>
|
||||
#include "git_backend.h"
|
||||
|
||||
namespace KIGIT
|
||||
{
|
||||
|
||||
git_repository* PROJECT_GIT_UTILS::GetRepositoryForFile( const char* aFilename )
|
||||
{
|
||||
git_repository* repo = nullptr;
|
||||
git_buf repo_path = GIT_BUF_INIT;
|
||||
|
||||
if( git_repository_discover( &repo_path, aFilename, 0, nullptr ) != GIT_OK )
|
||||
{
|
||||
wxLogTrace( traceGit, "Can't repo discover %s: %s", aFilename,
|
||||
KIGIT_COMMON::GetLastGitError() );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
KIGIT::GitBufPtr repo_path_ptr( &repo_path );
|
||||
|
||||
if( git_repository_open( &repo, repo_path.ptr ) != GIT_OK )
|
||||
{
|
||||
wxLogTrace( traceGit, "Can't open repo for %s: %s", repo_path.ptr,
|
||||
KIGIT_COMMON::GetLastGitError() );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return repo;
|
||||
return GetGitBackend()->GetRepositoryForFile( aFilename );
|
||||
}
|
||||
|
||||
int PROJECT_GIT_UTILS::CreateBranch( git_repository* aRepo, const wxString& aBranchName )
|
||||
{
|
||||
git_oid head_oid;
|
||||
|
||||
if( int error = git_reference_name_to_id( &head_oid, aRepo, "HEAD" ); error != GIT_OK )
|
||||
{
|
||||
wxLogTrace( traceGit, "Failed to lookup HEAD reference: %s",
|
||||
KIGIT_COMMON::GetLastGitError() );
|
||||
return error;
|
||||
}
|
||||
|
||||
git_commit* commit = nullptr;
|
||||
|
||||
if( int error = git_commit_lookup( &commit, aRepo, &head_oid ); error != GIT_OK )
|
||||
{
|
||||
wxLogTrace( traceGit, "Failed to lookup commit: %s",
|
||||
KIGIT_COMMON::GetLastGitError() );
|
||||
return error;
|
||||
}
|
||||
|
||||
KIGIT::GitCommitPtr commitPtr( commit );
|
||||
git_reference* branchRef = nullptr;
|
||||
|
||||
if( int error = git_branch_create( &branchRef, aRepo, aBranchName.mb_str(), commit, 0 ); error != GIT_OK )
|
||||
{
|
||||
wxLogTrace( traceGit, "Failed to create branch: %s",
|
||||
KIGIT_COMMON::GetLastGitError() );
|
||||
return error;
|
||||
}
|
||||
|
||||
git_reference_free( branchRef );
|
||||
return 0;
|
||||
return GetGitBackend()->CreateBranch( aRepo, aBranchName );
|
||||
}
|
||||
|
||||
bool PROJECT_GIT_UTILS::RemoveVCS( git_repository*& aRepo, const wxString& aProjectPath,
|
||||
bool aRemoveGitDir, wxString* aErrors )
|
||||
{
|
||||
if( aRepo )
|
||||
{
|
||||
git_repository_free( aRepo );
|
||||
aRepo = nullptr;
|
||||
}
|
||||
|
||||
if( aRemoveGitDir )
|
||||
{
|
||||
wxFileName gitDir( aProjectPath, wxEmptyString );
|
||||
gitDir.AppendDir( ".git" );
|
||||
|
||||
if( gitDir.DirExists() )
|
||||
{
|
||||
wxString errors;
|
||||
if( !RmDirRecursive( gitDir.GetPath(), &errors ) )
|
||||
{
|
||||
if( aErrors )
|
||||
*aErrors = errors;
|
||||
|
||||
wxLogTrace( traceGit, "Failed to remove .git directory: %s", errors );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxLogTrace( traceGit, "Successfully removed VCS from project" );
|
||||
return true;
|
||||
return GetGitBackend()->RemoveVCS( aRepo, aProjectPath, aRemoveGitDir, aErrors );
|
||||
}
|
||||
|
||||
} // namespace KIGIT
|
||||
} // namespace KIGIT
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <wx/txtstrm.h>
|
||||
#include <wx/wfstream.h>
|
||||
#include <tool/tool_action.h>
|
||||
#include <tool/tool_event.h>
|
||||
|
||||
|
||||
/*
|
||||
@ -159,6 +160,10 @@ static struct hotkey_name_descr hotkeyNameList[] =
|
||||
#define MODIFIER_CMD_MAC wxT( "Cmd+" )
|
||||
#define MODIFIER_CTRL_BASE wxT( "Ctrl+" )
|
||||
#define MODIFIER_SHIFT wxT( "Shift+" )
|
||||
#define MODIFIER_META wxT( "Meta+" )
|
||||
#define MODIFIER_WIN wxT( "Win+" )
|
||||
#define MODIFIER_SUPER wxT( "Super+" )
|
||||
#define MODIFIER_ALTGR wxT( "AltGr+" )
|
||||
|
||||
|
||||
wxString KeyNameFromKeyCode( int aKeycode, bool* aIsFound )
|
||||
@ -175,6 +180,14 @@ wxString KeyNameFromKeyCode( int aKeycode, bool* aIsFound )
|
||||
return wxString( MODIFIER_SHIFT ).BeforeFirst( '+' );
|
||||
else if( aKeycode == WXK_ALT )
|
||||
return wxString( MODIFIER_ALT ).BeforeFirst( '+' );
|
||||
#ifdef WXK_WINDOWS_LEFT
|
||||
else if( aKeycode == WXK_WINDOWS_LEFT || aKeycode == WXK_WINDOWS_RIGHT )
|
||||
return wxString( MODIFIER_WIN ).BeforeFirst( '+' );
|
||||
#endif
|
||||
#ifdef WXK_META
|
||||
else if( aKeycode == WXK_META )
|
||||
return wxString( MODIFIER_META ).BeforeFirst( '+' );
|
||||
#endif
|
||||
|
||||
// Assume keycode of 0 is "unassigned"
|
||||
if( (aKeycode & MD_CTRL) != 0 )
|
||||
@ -186,7 +199,16 @@ wxString KeyNameFromKeyCode( int aKeycode, bool* aIsFound )
|
||||
if( (aKeycode & MD_SHIFT) != 0 )
|
||||
modifier << MODIFIER_SHIFT;
|
||||
|
||||
aKeycode &= ~( MD_CTRL | MD_ALT | MD_SHIFT );
|
||||
if( (aKeycode & MD_META) != 0 )
|
||||
modifier << MODIFIER_META;
|
||||
|
||||
if( (aKeycode & MD_SUPER) != 0 )
|
||||
modifier << MODIFIER_WIN;
|
||||
|
||||
if( (aKeycode & MD_ALTGR) != 0 )
|
||||
modifier << MODIFIER_ALTGR;
|
||||
|
||||
aKeycode &= ~MD_MODIFIER_MASK;
|
||||
|
||||
if( (aKeycode > ' ') && (aKeycode < 0x7F ) )
|
||||
{
|
||||
@ -262,7 +284,7 @@ int KeyCodeFromKeyName( const wxString& keyname )
|
||||
{
|
||||
int ii, keycode = KEY_NON_FOUND;
|
||||
|
||||
// Search for modifiers: Ctrl+ Alt+ and Shift+
|
||||
// Search for modifiers: Ctrl+ Alt+ Shift+ and others
|
||||
// Note: on Mac OSX, the Cmd key is equiv here to Ctrl
|
||||
wxString key = keyname;
|
||||
wxString prefix;
|
||||
@ -292,6 +314,26 @@ int KeyCodeFromKeyName( const wxString& keyname )
|
||||
modifier |= MD_SHIFT;
|
||||
prefix = MODIFIER_SHIFT;
|
||||
}
|
||||
else if( key.StartsWith( MODIFIER_META ) )
|
||||
{
|
||||
modifier |= MD_META;
|
||||
prefix = MODIFIER_META;
|
||||
}
|
||||
else if( key.StartsWith( MODIFIER_WIN ) )
|
||||
{
|
||||
modifier |= MD_SUPER;
|
||||
prefix = MODIFIER_WIN;
|
||||
}
|
||||
else if( key.StartsWith( MODIFIER_SUPER ) )
|
||||
{
|
||||
modifier |= MD_SUPER;
|
||||
prefix = MODIFIER_SUPER;
|
||||
}
|
||||
else if( key.StartsWith( MODIFIER_ALTGR ) )
|
||||
{
|
||||
modifier |= MD_ALTGR;
|
||||
prefix = MODIFIER_ALTGR;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
|
@ -40,8 +40,7 @@ JOB_EXPORT_SCH_BOM::JOB_EXPORT_SCH_BOM() :
|
||||
m_sortField(),
|
||||
m_sortAsc( true ),
|
||||
m_filterString(),
|
||||
m_excludeDNP( false ),
|
||||
m_includeExcludedFromBOM( false )
|
||||
m_excludeDNP( false )
|
||||
{
|
||||
m_params.emplace_back( new JOB_PARAM<wxString>( "field_delimiter",
|
||||
&m_fieldDelimiter,
|
||||
@ -70,13 +69,8 @@ JOB_EXPORT_SCH_BOM::JOB_EXPORT_SCH_BOM() :
|
||||
m_fieldsGroupBy ) );
|
||||
m_params.emplace_back( new JOB_PARAM<wxString>( "sort_field", &m_sortField, m_sortField ) );
|
||||
m_params.emplace_back( new JOB_PARAM<bool>( "sort_asc", &m_sortAsc, m_sortAsc ) );
|
||||
m_params.emplace_back( new JOB_PARAM<wxString>( "filter_string",
|
||||
&m_filterString,
|
||||
m_filterString ) );
|
||||
m_params.emplace_back( new JOB_PARAM<wxString>( "filter_string", &m_filterString, m_filterString ) );
|
||||
m_params.emplace_back( new JOB_PARAM<bool>( "exclude_dnp", &m_excludeDNP, m_excludeDNP ) );
|
||||
m_params.emplace_back( new JOB_PARAM<bool>( "include_excluded_from_bom",
|
||||
&m_includeExcludedFromBOM,
|
||||
m_includeExcludedFromBOM ) );
|
||||
|
||||
m_params.emplace_back( new JOB_PARAM<wxString>( "bom_preset_name",
|
||||
&m_bomPresetName,
|
||||
|
@ -55,7 +55,6 @@ public:
|
||||
bool m_sortAsc;
|
||||
wxString m_filterString;
|
||||
bool m_excludeDNP;
|
||||
bool m_includeExcludedFromBOM;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -19,11 +19,23 @@
|
||||
|
||||
#include "lib_table_grid_tricks.h"
|
||||
#include "lib_table_grid.h"
|
||||
#include <wx/clipbrd.h>
|
||||
#include <wx/log.h>
|
||||
|
||||
|
||||
LIB_TABLE_GRID_TRICKS::LIB_TABLE_GRID_TRICKS( WX_GRID* aGrid ) :
|
||||
GRID_TRICKS( aGrid )
|
||||
{
|
||||
m_grid->Disconnect( wxEVT_CHAR_HOOK );
|
||||
m_grid->Connect( wxEVT_CHAR_HOOK, wxCharEventHandler( LIB_TABLE_GRID_TRICKS::onCharHook ), nullptr, this );
|
||||
}
|
||||
|
||||
LIB_TABLE_GRID_TRICKS::LIB_TABLE_GRID_TRICKS( WX_GRID* aGrid,
|
||||
std::function<void( wxCommandEvent& )> aAddHandler ) :
|
||||
GRID_TRICKS( aGrid, aAddHandler )
|
||||
{
|
||||
m_grid->Disconnect( wxEVT_CHAR_HOOK );
|
||||
m_grid->Connect( wxEVT_CHAR_HOOK, wxCharEventHandler( LIB_TABLE_GRID_TRICKS::onCharHook ), nullptr, this );
|
||||
}
|
||||
|
||||
|
||||
@ -134,6 +146,61 @@ void LIB_TABLE_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
|
||||
GRID_TRICKS::doPopupSelection( event );
|
||||
}
|
||||
}
|
||||
void LIB_TABLE_GRID_TRICKS::onCharHook( wxKeyEvent& ev )
|
||||
{
|
||||
if( ev.GetModifiers() == wxMOD_CONTROL && ev.GetKeyCode() == 'V' && m_grid->IsCellEditControlShown() )
|
||||
{
|
||||
wxLogNull doNotLog;
|
||||
|
||||
if( wxTheClipboard->Open() )
|
||||
{
|
||||
if( wxTheClipboard->IsSupported( wxDF_TEXT ) || wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
|
||||
{
|
||||
wxTextDataObject data;
|
||||
wxTheClipboard->GetData( data );
|
||||
|
||||
wxString text = data.GetText();
|
||||
|
||||
if( !text.Contains( '\t' ) && text.Contains( ',' ) )
|
||||
text.Replace( ',', '\t' );
|
||||
|
||||
if( text.Contains( '\t' ) || text.Contains( '\n' ) || text.Contains( '\r' ) )
|
||||
{
|
||||
m_grid->CancelPendingChanges();
|
||||
int row = m_grid->GetGridCursorRow();
|
||||
|
||||
// Check if the current row already has data (has a nickname)
|
||||
wxGridTableBase* table = m_grid->GetTable();
|
||||
if( table && row >= 0 && row < table->GetNumberRows() )
|
||||
{
|
||||
// Check if the row has a nickname (indicating it has existing data)
|
||||
wxString nickname = table->GetValue( row, COL_NICKNAME );
|
||||
if( !nickname.IsEmpty() )
|
||||
{
|
||||
// Row already has data, don't allow pasting over it
|
||||
wxTheClipboard->Close();
|
||||
wxBell(); // Provide audio feedback
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_grid->ClearSelection();
|
||||
m_grid->SelectRow( row );
|
||||
m_grid->SetGridCursor( row, 0 );
|
||||
getSelectedArea();
|
||||
paste_text( text );
|
||||
wxTheClipboard->Close();
|
||||
m_grid->ForceRefresh();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
}
|
||||
|
||||
GRID_TRICKS::onCharHook( ev );
|
||||
}
|
||||
|
||||
|
||||
bool LIB_TABLE_GRID_TRICKS::handleDoubleClick( wxGridEvent& aEvent )
|
||||
|
@ -1160,7 +1160,9 @@ void UOP::Exec( CONTEXT* ctx )
|
||||
return;
|
||||
|
||||
case TR_OP_METHOD_CALL:
|
||||
m_func( ctx, m_ref.get() );
|
||||
if( m_func )
|
||||
m_func( ctx, m_ref.get() );
|
||||
|
||||
return;
|
||||
|
||||
default:
|
||||
@ -1321,9 +1323,8 @@ VALUE* UCODE::Run( CONTEXT* ctx )
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// rules which fail outright should not be fired
|
||||
std::unique_ptr<VALUE> temp_false = std::make_unique<VALUE>( 0 );
|
||||
return ctx->StoreValue( temp_false.get() );
|
||||
// rules which fail outright should not be fired; return 0/false
|
||||
return ctx->StoreValue( new VALUE( 0 ) );
|
||||
}
|
||||
|
||||
if( ctx->SP() == 1 )
|
||||
@ -1339,8 +1340,7 @@ VALUE* UCODE::Run( CONTEXT* ctx )
|
||||
wxASSERT( ctx->SP() == 1 );
|
||||
|
||||
// non-well-formed rules should not be fired on a release build
|
||||
std::unique_ptr<VALUE> temp_false = std::make_unique<VALUE>( 0 );
|
||||
return ctx->StoreValue( temp_false.get() );
|
||||
return ctx->StoreValue( new VALUE( 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,16 @@
|
||||
#include <properties/pg_properties.h>
|
||||
#include <widgets/color_swatch.h>
|
||||
#include <widgets/unit_binder.h>
|
||||
#include <bitmaps.h>
|
||||
#include <frame_type.h>
|
||||
#include <kiway_player.h>
|
||||
#include <kiway.h>
|
||||
#include <wx/filedlg.h>
|
||||
#include <wx/intl.h>
|
||||
#include <eda_doc.h>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/bmpbuttn.h>
|
||||
|
||||
#include <wx/log.h>
|
||||
|
||||
@ -31,6 +41,8 @@ const wxString PG_UNIT_EDITOR::EDITOR_NAME = wxS( "KiCadUnitEditor" );
|
||||
const wxString PG_CHECKBOX_EDITOR::EDITOR_NAME = wxS( "KiCadCheckboxEditor" );
|
||||
const wxString PG_COLOR_EDITOR::EDITOR_NAME = wxS( "KiCadColorEditor" );
|
||||
const wxString PG_RATIO_EDITOR::EDITOR_NAME = wxS( "KiCadRatioEditor" );
|
||||
const wxString PG_FPID_EDITOR::EDITOR_NAME = wxS( "KiCadFpidEditor" );
|
||||
const wxString PG_URL_EDITOR::EDITOR_NAME = wxS( "KiCadUrlEditor" );
|
||||
|
||||
|
||||
PG_UNIT_EDITOR::PG_UNIT_EDITOR( EDA_DRAW_FRAME* aFrame ) :
|
||||
@ -51,6 +63,9 @@ PG_UNIT_EDITOR::~PG_UNIT_EDITOR()
|
||||
|
||||
wxString PG_UNIT_EDITOR::BuildEditorName( EDA_DRAW_FRAME* aFrame )
|
||||
{
|
||||
if( !aFrame )
|
||||
return EDITOR_NAME + "NoFrame";
|
||||
|
||||
return EDITOR_NAME + aFrame->GetName();
|
||||
}
|
||||
|
||||
@ -458,3 +473,164 @@ void PG_RATIO_EDITOR::UpdateControl( wxPGProperty* aProperty, wxWindow* aCtrl )
|
||||
"properties!" ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PG_FPID_EDITOR::PG_FPID_EDITOR( EDA_DRAW_FRAME* aFrame ) : m_frame( aFrame )
|
||||
{
|
||||
m_editorName = BuildEditorName( aFrame );
|
||||
}
|
||||
|
||||
|
||||
void PG_FPID_EDITOR::UpdateFrame( EDA_DRAW_FRAME* aFrame )
|
||||
{
|
||||
m_frame = aFrame;
|
||||
m_editorName = BuildEditorName( aFrame );
|
||||
}
|
||||
|
||||
|
||||
wxString PG_FPID_EDITOR::BuildEditorName( EDA_DRAW_FRAME* aFrame )
|
||||
{
|
||||
if( !aFrame )
|
||||
return EDITOR_NAME + "NoFrame";
|
||||
|
||||
return EDITOR_NAME + aFrame->GetName();
|
||||
}
|
||||
|
||||
|
||||
wxPGWindowList PG_FPID_EDITOR::CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty,
|
||||
const wxPoint& aPos, const wxSize& aSize ) const
|
||||
{
|
||||
wxPGMultiButton* buttons = new wxPGMultiButton( aGrid, aSize );
|
||||
buttons->Add( KiBitmap( BITMAPS::small_library ) );
|
||||
buttons->Finalize( aGrid, aPos );
|
||||
wxSize textSize = buttons->GetPrimarySize();
|
||||
wxWindow* textCtrl = aGrid->GenerateEditorTextCtrl( aPos, textSize,
|
||||
aProperty->GetValueAsString(), nullptr, 0,
|
||||
aProperty->GetMaxLength() );
|
||||
wxPGWindowList ret( textCtrl, buttons );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PG_FPID_EDITOR::OnEvent( wxPropertyGrid* aGrid, wxPGProperty* aProperty, wxWindow* aCtrl,
|
||||
wxEvent& aEvent ) const
|
||||
{
|
||||
if( aEvent.GetEventType() == wxEVT_BUTTON )
|
||||
{
|
||||
wxString fpid = aProperty->GetValue().GetString();
|
||||
|
||||
if( KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_frame ) )
|
||||
{
|
||||
if( frame->ShowModal( &fpid, m_frame ) )
|
||||
aGrid->ChangePropertyValue( aProperty, fpid );
|
||||
|
||||
frame->Destroy();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return wxPGTextCtrlEditor::OnEvent( aGrid, aProperty, aCtrl, aEvent );
|
||||
}
|
||||
|
||||
|
||||
PG_URL_EDITOR::PG_URL_EDITOR( EDA_DRAW_FRAME* aFrame ) : m_frame( aFrame )
|
||||
{
|
||||
m_editorName = BuildEditorName( aFrame );
|
||||
}
|
||||
|
||||
|
||||
void PG_URL_EDITOR::UpdateFrame( EDA_DRAW_FRAME* aFrame )
|
||||
{
|
||||
m_frame = aFrame;
|
||||
m_editorName = BuildEditorName( aFrame );
|
||||
}
|
||||
|
||||
|
||||
wxString PG_URL_EDITOR::BuildEditorName( EDA_DRAW_FRAME* aFrame )
|
||||
{
|
||||
if( !aFrame )
|
||||
return EDITOR_NAME + "NoFrame";
|
||||
|
||||
return EDITOR_NAME + aFrame->GetName();
|
||||
}
|
||||
|
||||
|
||||
wxPGWindowList PG_URL_EDITOR::CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty,
|
||||
const wxPoint& aPos, const wxSize& aSize ) const
|
||||
{
|
||||
wxPGMultiButton* buttons = new wxPGMultiButton( aGrid, aSize );
|
||||
// Use a folder icon when no datasheet is set; otherwise use a globe icon.
|
||||
wxString urlValue = aProperty->GetValueAsString();
|
||||
bool hasUrl = !( urlValue.IsEmpty() || urlValue == wxS( "~" ) );
|
||||
buttons->Add( KiBitmap( hasUrl ? BITMAPS::www : BITMAPS::small_folder ) );
|
||||
buttons->Finalize( aGrid, aPos );
|
||||
wxSize textSize = buttons->GetPrimarySize();
|
||||
wxWindow* textCtrl = aGrid->GenerateEditorTextCtrl( aPos, textSize,
|
||||
aProperty->GetValueAsString(), nullptr, 0,
|
||||
aProperty->GetMaxLength() );
|
||||
wxPGWindowList ret( textCtrl, buttons );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool PG_URL_EDITOR::OnEvent( wxPropertyGrid* aGrid, wxPGProperty* aProperty, wxWindow* aCtrl,
|
||||
wxEvent& aEvent ) const
|
||||
{
|
||||
if( aEvent.GetEventType() == wxEVT_BUTTON )
|
||||
{
|
||||
wxString filename = aProperty->GetValue().GetString();
|
||||
|
||||
if( filename.IsEmpty() || filename == wxS( "~" ) )
|
||||
{
|
||||
wxFileDialog openFileDialog( m_frame, _( "Open file" ), wxS( "" ), wxS( "" ),
|
||||
_( "All Files" ) + wxS( " (*.*)|*.*" ),
|
||||
wxFD_OPEN | wxFD_FILE_MUST_EXIST );
|
||||
|
||||
if( openFileDialog.ShowModal() == wxID_OK )
|
||||
{
|
||||
filename = openFileDialog.GetPath();
|
||||
aGrid->ChangePropertyValue( aProperty, wxString::Format( wxS( "file://%s" ),
|
||||
filename ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GetAssociatedDocument( m_frame, filename, &m_frame->Prj() );
|
||||
}
|
||||
|
||||
// Update the button icon to reflect presence/absence of URL
|
||||
if( wxObject* src = aEvent.GetEventObject() )
|
||||
{
|
||||
wxString newUrl = aProperty->GetValueAsString();
|
||||
bool hasUrl = !( newUrl.IsEmpty() || newUrl == wxS( "~" ) );
|
||||
auto bmp = KiBitmap( hasUrl ? BITMAPS::www : BITMAPS::small_folder );
|
||||
|
||||
if( wxWindow* win = wxDynamicCast( src, wxWindow ) )
|
||||
{
|
||||
if( wxBitmapButton* bb = wxDynamicCast( win, wxBitmapButton ) )
|
||||
{
|
||||
bb->SetBitmap( bmp );
|
||||
}
|
||||
else if( wxButton* b = wxDynamicCast( win, wxButton ) )
|
||||
{
|
||||
b->SetBitmap( bmp );
|
||||
}
|
||||
else if( wxWindow* parent = win->GetParent() )
|
||||
{
|
||||
if( wxPGMultiButton* buttons = wxDynamicCast( parent, wxPGMultiButton ) )
|
||||
{
|
||||
wxWindow* btn0 = buttons->GetButton( 0 );
|
||||
if( wxBitmapButton* bb0 = wxDynamicCast( btn0, wxBitmapButton ) )
|
||||
bb0->SetBitmap( bmp );
|
||||
else if( wxButton* b0 = wxDynamicCast( btn0, wxButton ) )
|
||||
b0->SetBitmap( bmp );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return wxPGTextCtrlEditor::OnEvent( aGrid, aProperty, aCtrl, aEvent );
|
||||
}
|
||||
|
@ -61,11 +61,8 @@ EDIT_POINT* EDIT_POINTS::FindPoint( const VECTOR2I& aLocation, KIGFX::VIEW *aVie
|
||||
|
||||
if( m_allowPoints )
|
||||
{
|
||||
// Check from the end so that we get the topmost point
|
||||
for( auto r_it = m_points.rbegin(); r_it != m_points.rend(); ++r_it )
|
||||
for( EDIT_POINT& point : m_points )
|
||||
{
|
||||
EDIT_POINT& point = *r_it;
|
||||
|
||||
if( point.WithinPoint( aLocation, size ) )
|
||||
return &point;
|
||||
}
|
||||
|
@ -158,6 +158,43 @@ TOOL_DISPATCHER::~TOOL_DISPATCHER()
|
||||
delete st;
|
||||
}
|
||||
|
||||
int TOOL_DISPATCHER::decodeModifiers( const wxKeyboardState* aState )
|
||||
{
|
||||
int mods = 0;
|
||||
int wxmods = aState->GetModifiers();
|
||||
|
||||
// Returns the state of key modifiers (Alt, Ctrl and so on). Be carefull:
|
||||
// the flag wxMOD_ALTGR is defined in wxWidgets as wxMOD_CONTROL|wxMOD_ALT
|
||||
// So AltGr key cannot used as modifier key because it is the same as Alt key + Ctrl key.
|
||||
#if CAN_USE_ALTGR_KEY
|
||||
if( wxmods & wxMOD_ALTGR )
|
||||
mods |= MD_ALTGR;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if( wxmods & wxMOD_CONTROL )
|
||||
mods |= MD_CTRL;
|
||||
|
||||
if( wxmods & wxMOD_ALT )
|
||||
mods |= MD_ALT;
|
||||
}
|
||||
|
||||
if( wxmods & wxMOD_SHIFT )
|
||||
mods |= MD_SHIFT;
|
||||
|
||||
#ifdef wxMOD_META
|
||||
if( wxmods & wxMOD_META )
|
||||
mods |= MD_META;
|
||||
#endif
|
||||
|
||||
#ifdef wxMOD_WIN
|
||||
if( wxmods & wxMOD_WIN )
|
||||
mods |= MD_SUPER;
|
||||
#endif
|
||||
|
||||
return mods;
|
||||
}
|
||||
|
||||
|
||||
void TOOL_DISPATCHER::ResetState()
|
||||
{
|
||||
@ -297,7 +334,19 @@ static bool isKeyModifierOnly( int aKeyCode )
|
||||
{
|
||||
static std::vector<enum wxKeyCode> special_keys =
|
||||
{
|
||||
WXK_CONTROL, WXK_RAW_CONTROL, WXK_SHIFT, WXK_ALT
|
||||
WXK_CONTROL, WXK_RAW_CONTROL, WXK_SHIFT, WXK_ALT,
|
||||
#ifdef WXK_WINDOWS_LEFT
|
||||
WXK_WINDOWS_LEFT, WXK_WINDOWS_RIGHT,
|
||||
#endif
|
||||
#ifdef WXK_MENU
|
||||
WXK_MENU,
|
||||
#endif
|
||||
#ifdef WXK_COMMAND
|
||||
WXK_COMMAND,
|
||||
#endif
|
||||
#ifdef WXK_META
|
||||
WXK_META,
|
||||
#endif
|
||||
};
|
||||
|
||||
return alg::contains( special_keys, aKeyCode );
|
||||
@ -515,7 +564,7 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||
if( !evt && me->GetWheelRotation() != 0 )
|
||||
{
|
||||
const unsigned modBits =
|
||||
static_cast<unsigned>( mods ) & ( MD_CTRL | MD_ALT | MD_SHIFT );
|
||||
static_cast<unsigned>( mods ) & MD_MODIFIER_MASK;
|
||||
const bool shouldHandle = std::popcount( modBits ) > 1;
|
||||
|
||||
if( shouldHandle )
|
||||
|
@ -149,6 +149,9 @@ const std::string TOOL_EVENT::Format() const
|
||||
{ MD_SHIFT, "shift" },
|
||||
{ MD_CTRL, "ctrl" },
|
||||
{ MD_ALT, "alt" },
|
||||
{ MD_SUPER, "super" },
|
||||
{ MD_META, "meta" },
|
||||
{ MD_ALTGR, "altgr" },
|
||||
{ 0, "" }
|
||||
};
|
||||
|
||||
|
@ -640,15 +640,36 @@ void LIB_TREE::onQueryCharHook( wxKeyEvent& aKeyStroke )
|
||||
{
|
||||
int hotkey = aKeyStroke.GetKeyCode();
|
||||
|
||||
if( aKeyStroke.GetModifiers() & wxMOD_CONTROL )
|
||||
hotkey += MD_CTRL;
|
||||
int mods = aKeyStroke.GetModifiers();
|
||||
|
||||
if( aKeyStroke.GetModifiers() & wxMOD_ALT )
|
||||
hotkey += MD_ALT;
|
||||
// the flag wxMOD_ALTGR is defined in wxWidgets as wxMOD_CONTROL|wxMOD_ALT
|
||||
// So AltGr key cannot used as modifier key because it is the same as Alt key + Ctrl key.
|
||||
#if CAN_USE_ALTGR_KEY
|
||||
if( wxmods & wxMOD_ALTGR )
|
||||
mods |= MD_ALTGR;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if( mods & wxMOD_CONTROL )
|
||||
hotkey += MD_CTRL;
|
||||
|
||||
if( aKeyStroke.GetModifiers() & wxMOD_SHIFT )
|
||||
if( mods & wxMOD_ALT )
|
||||
hotkey += MD_ALT;
|
||||
}
|
||||
|
||||
if( mods & wxMOD_SHIFT )
|
||||
hotkey += MD_SHIFT;
|
||||
|
||||
#ifdef wxMOD_META
|
||||
if( mods & wxMOD_META )
|
||||
hotkey += MD_META;
|
||||
#endif
|
||||
|
||||
#ifdef wxMOD_WIN
|
||||
if( mods & wxMOD_WIN )
|
||||
hotkey += MD_SUPER;
|
||||
#endif
|
||||
|
||||
if( hotkey == ACTIONS::expandAll.GetHotKey()
|
||||
|| hotkey == ACTIONS::expandAll.GetHotKeyAlt() )
|
||||
{
|
||||
@ -860,14 +881,31 @@ void LIB_TREE::onTreeCharHook( wxKeyEvent& aKeyStroke )
|
||||
{
|
||||
int hotkey = aKeyStroke.GetKeyCode();
|
||||
|
||||
if( aKeyStroke.ShiftDown() )
|
||||
int mods = aKeyStroke.GetModifiers();
|
||||
|
||||
if( mods & wxMOD_ALTGR )
|
||||
hotkey |= MD_ALTGR;
|
||||
else
|
||||
{
|
||||
if( mods & wxMOD_ALT )
|
||||
hotkey |= MD_ALT;
|
||||
|
||||
if( mods & wxMOD_CONTROL )
|
||||
hotkey |= MD_CTRL;
|
||||
}
|
||||
|
||||
if( mods & wxMOD_SHIFT )
|
||||
hotkey |= MD_SHIFT;
|
||||
|
||||
if( aKeyStroke.AltDown() )
|
||||
hotkey |= MD_ALT;
|
||||
#ifdef wxMOD_META
|
||||
if( mods & wxMOD_META )
|
||||
hotkey |= MD_META;
|
||||
#endif
|
||||
|
||||
if( aKeyStroke.ControlDown() )
|
||||
hotkey |= MD_CTRL;
|
||||
#ifdef wxMOD_WIN
|
||||
if( mods & wxMOD_WIN )
|
||||
hotkey |= MD_SUPER;
|
||||
#endif
|
||||
|
||||
if( tool->GetManager()->GetActionManager()->RunHotKey( hotkey ) )
|
||||
aKeyStroke.Skip( false );
|
||||
|
@ -670,7 +670,7 @@ long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
|
||||
{
|
||||
long key = aEvent.GetKeyCode();
|
||||
bool is_tab = aEvent.IsKeyInCategory( WXK_CATEGORY_TAB );
|
||||
|
||||
printf("key %lX mod %X\n", key, aEvent.GetModifiers());
|
||||
if( key == WXK_ESCAPE )
|
||||
{
|
||||
return 0;
|
||||
@ -693,14 +693,35 @@ long WIDGET_HOTKEY_LIST::MapKeypressToKeycode( const wxKeyEvent& aEvent )
|
||||
*/
|
||||
bool keyIsLetter = key >= 'A' && key <= 'Z';
|
||||
|
||||
if( aEvent.ShiftDown() && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) )
|
||||
int mods = aEvent.GetModifiers();
|
||||
|
||||
if( ( mods & wxMOD_SHIFT ) && ( keyIsLetter || key > 256 || key == 9 || key == 32 ) )
|
||||
key |= MD_SHIFT;
|
||||
|
||||
if( aEvent.ControlDown() )
|
||||
key |= MD_CTRL;
|
||||
// the flag wxMOD_ALTGR is defined in wxWidgets as wxMOD_CONTROL|wxMOD_ALT
|
||||
// So AltGr key cannot used as modifier key because it is the same as Alt key + Ctrl key.
|
||||
#if CAN_USE_ALTGR_KEY
|
||||
if( wxmods & wxMOD_ALTGR )
|
||||
mods |= MD_ALTGR;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if( mods & wxMOD_CONTROL )
|
||||
key |= MD_CTRL;
|
||||
|
||||
if( aEvent.AltDown() )
|
||||
key |= MD_ALT;
|
||||
if( mods & wxMOD_ALT )
|
||||
key |= MD_ALT;
|
||||
}
|
||||
|
||||
#ifdef wxMOD_META
|
||||
if( mods & wxMOD_META )
|
||||
key |= MD_META;
|
||||
#endif
|
||||
|
||||
#ifdef wxMOD_WIN
|
||||
if( mods & wxMOD_WIN )
|
||||
key |= MD_SUPER;
|
||||
#endif
|
||||
|
||||
return key;
|
||||
}
|
||||
|
@ -1614,11 +1614,10 @@ void CONNECTION_GRAPH::resolveAllDrivers()
|
||||
|
||||
thread_pool& tp = GetKiCadThreadPool();
|
||||
|
||||
auto results = tp.parallelize_loop( dirty_graphs.size(),
|
||||
[&]( const int a, const int b)
|
||||
auto results = tp.submit_loop( 0, dirty_graphs.size(),
|
||||
[&]( const int ii )
|
||||
{
|
||||
for( int ii = a; ii < b; ++ii )
|
||||
update_lambda( dirty_graphs[ii] );
|
||||
update_lambda( dirty_graphs[ii] );
|
||||
});
|
||||
results.wait();
|
||||
|
||||
@ -2257,11 +2256,10 @@ void CONNECTION_GRAPH::buildConnectionGraph( std::function<void( SCH_ITEM* )>* a
|
||||
|
||||
thread_pool& tp = GetKiCadThreadPool();
|
||||
|
||||
auto results = tp.parallelize_loop( m_driver_subgraphs.size(),
|
||||
[&]( const int a, const int b)
|
||||
auto results = tp.submit_loop( 0, m_driver_subgraphs.size(),
|
||||
[&]( const int ii )
|
||||
{
|
||||
for( int ii = a; ii < b; ++ii )
|
||||
m_driver_subgraphs[ii]->UpdateItemConnections();
|
||||
m_driver_subgraphs[ii]->UpdateItemConnections();
|
||||
});
|
||||
|
||||
results.wait();
|
||||
@ -2464,12 +2462,11 @@ void CONNECTION_GRAPH::buildConnectionGraph( std::function<void( SCH_ITEM* )>* a
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto results2 = tp.parallelize_loop( m_driver_subgraphs.size(),
|
||||
[&]( const int a, const int b)
|
||||
auto results2 = tp.submit_loop( 0, m_driver_subgraphs.size(),
|
||||
[&]( const int ii )
|
||||
{
|
||||
for( int ii = a; ii < b; ++ii )
|
||||
updateItemConnectionsTask( m_driver_subgraphs[ii] );
|
||||
});
|
||||
updateItemConnectionsTask( m_driver_subgraphs[ii] );
|
||||
} );
|
||||
results2.wait();
|
||||
|
||||
m_net_code_to_subgraphs_map.clear();
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <id.h>
|
||||
#include <confirm.h>
|
||||
#include <widgets/wx_html_report_box.h>
|
||||
#include <widgets/std_bitmap_button.h>
|
||||
#include <dialogs/dialog_text_entry.h>
|
||||
#include <string_utils.h>
|
||||
#include <kiplatform/ui.h>
|
||||
@ -76,15 +77,15 @@ DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) :
|
||||
m_running( false ),
|
||||
m_ercRun( false ),
|
||||
m_centerMarkerOnIdle( nullptr ),
|
||||
m_severities( 0 )
|
||||
m_crossprobe( true ),
|
||||
m_scroll_on_crossprobe( true )
|
||||
{
|
||||
m_currentSchematic = &parent->Schematic();
|
||||
|
||||
SetName( DIALOG_ERC_WINDOW_NAME ); // Set a window name to be able to find it
|
||||
KIPLATFORM::UI::SetFloatLevel( this );
|
||||
|
||||
if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
|
||||
m_severities = cfg->m_Appearance.erc_severities;
|
||||
m_bMenu->SetBitmap( KiBitmapBundle( BITMAPS::config ) );
|
||||
|
||||
m_messages->SetImmediateMode();
|
||||
|
||||
@ -92,7 +93,7 @@ DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) :
|
||||
|
||||
m_markerTreeModel = new ERC_TREE_MODEL( parent, m_markerDataView );
|
||||
m_markerDataView->AssociateModel( m_markerTreeModel );
|
||||
m_markerTreeModel->Update( m_markerProvider, m_severities );
|
||||
m_markerTreeModel->Update( m_markerProvider, getSeverities() );
|
||||
|
||||
m_ignoredList->InsertColumn( 0, wxEmptyString, wxLIST_FORMAT_LEFT, DEFAULT_SINGLE_COL_WIDTH );
|
||||
|
||||
@ -129,8 +130,11 @@ DIALOG_ERC::DIALOG_ERC( SCH_EDIT_FRAME* parent ) :
|
||||
|
||||
SetFocus();
|
||||
|
||||
syncCheckboxes();
|
||||
updateDisplayedCounts();
|
||||
if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
|
||||
{
|
||||
m_crossprobe = cfg->m_ERCDialog.crossprobe;
|
||||
m_scroll_on_crossprobe = cfg->m_ERCDialog.scroll_on_crossprobe;
|
||||
}
|
||||
|
||||
// Now all widgets have the size fixed, call FinishDialogSettings
|
||||
finishDialogSettings();
|
||||
@ -148,7 +152,10 @@ DIALOG_ERC::~DIALOG_ERC()
|
||||
g_lastERCIgnored.push_back( { m_ignoredList->GetItemText( ii ), m_ignoredList->GetItemData( ii ) } );
|
||||
|
||||
if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
|
||||
cfg->m_Appearance.erc_severities = m_severities;
|
||||
{
|
||||
cfg->m_ERCDialog.crossprobe = m_crossprobe;
|
||||
cfg->m_ERCDialog.scroll_on_crossprobe = m_scroll_on_crossprobe;
|
||||
}
|
||||
|
||||
m_markerTreeModel->DecRef();
|
||||
}
|
||||
@ -189,6 +196,59 @@ void DIALOG_ERC::UpdateAnnotationWarning()
|
||||
}
|
||||
|
||||
|
||||
int DIALOG_ERC::getSeverities()
|
||||
{
|
||||
int severities = 0;
|
||||
|
||||
if( m_showErrors->GetValue() )
|
||||
severities |= RPT_SEVERITY_ERROR;
|
||||
|
||||
if( m_showWarnings->GetValue() )
|
||||
severities |= RPT_SEVERITY_WARNING;
|
||||
|
||||
if( m_showExclusions->GetValue() )
|
||||
severities |= RPT_SEVERITY_EXCLUSION;
|
||||
|
||||
return severities;
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_ERC::OnMenu( wxCommandEvent& event )
|
||||
{
|
||||
// Build a pop menu:
|
||||
wxMenu menu;
|
||||
|
||||
menu.Append( 4206, _( "Cross-probe Selected Items" ),
|
||||
_( "Highlight corresponding items on canvas when selected in the ERC list" ),
|
||||
wxITEM_CHECK );
|
||||
menu.Check( 4206, m_crossprobe );
|
||||
|
||||
menu.Append( 4207, _( "Center on Cross-probe" ),
|
||||
_( "When cross-probing, scroll the canvas so that the item is visible" ),
|
||||
wxITEM_CHECK );
|
||||
menu.Check( 4207, m_scroll_on_crossprobe );
|
||||
|
||||
// menu_id is the selected submenu id from the popup menu or wxID_NONE
|
||||
int menu_id = m_bMenu->GetPopupMenuSelectionFromUser( menu );
|
||||
|
||||
if( menu_id == 0 || menu_id == 4206 )
|
||||
{
|
||||
m_crossprobe = !m_crossprobe;
|
||||
}
|
||||
else if( menu_id == 1 || menu_id == 4207 )
|
||||
{
|
||||
m_scroll_on_crossprobe = !m_scroll_on_crossprobe;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DIALOG_ERC::TransferDataToWindow()
|
||||
{
|
||||
UpdateData();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool DIALOG_ERC::updateUI()
|
||||
{
|
||||
// If ERC checks ever get slow enough we'll want a progress indicator...
|
||||
@ -217,6 +277,13 @@ void DIALOG_ERC::Report( const wxString& aMessage )
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_ERC::UpdateData()
|
||||
{
|
||||
m_markerTreeModel->Update( m_markerProvider, getSeverities() );
|
||||
updateDisplayedCounts();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_ERC::updateDisplayedCounts()
|
||||
{
|
||||
int numErrors = 0;
|
||||
@ -348,30 +415,14 @@ void DIALOG_ERC::OnCloseErcDialog( wxCloseEvent& aEvent )
|
||||
// Dialog is mode-less so let the parent know that it needs to be destroyed.
|
||||
if( !IsModal() && !IsQuasiModal() )
|
||||
{
|
||||
wxCommandEvent* evt = new wxCommandEvent( EDA_EVT_CLOSE_ERC_DIALOG, wxID_ANY );
|
||||
|
||||
wxWindow* parent = GetParent();
|
||||
|
||||
if( parent )
|
||||
wxQueueEvent( parent, evt );
|
||||
if( wxWindow* parent = GetParent() )
|
||||
wxQueueEvent( parent, new wxCommandEvent( EDA_EVT_CLOSE_ERC_DIALOG, wxID_ANY ) );
|
||||
}
|
||||
|
||||
aEvent.Skip();
|
||||
}
|
||||
|
||||
|
||||
static int RPT_SEVERITY_ALL = RPT_SEVERITY_WARNING | RPT_SEVERITY_ERROR | RPT_SEVERITY_EXCLUSION;
|
||||
|
||||
|
||||
void DIALOG_ERC::syncCheckboxes()
|
||||
{
|
||||
m_showAll->SetValue( m_severities == RPT_SEVERITY_ALL );
|
||||
m_showErrors->SetValue( m_severities & RPT_SEVERITY_ERROR );
|
||||
m_showWarnings->SetValue( m_severities & RPT_SEVERITY_WARNING );
|
||||
m_showExclusions->SetValue( m_severities & RPT_SEVERITY_EXCLUSION );
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_ERC::OnLinkClicked( wxHtmlLinkEvent& event )
|
||||
{
|
||||
m_parent->OnAnnotate();
|
||||
@ -446,8 +497,7 @@ void DIALOG_ERC::OnRunERCClick( wxCommandEvent& event )
|
||||
}
|
||||
|
||||
if( m_cancelled )
|
||||
// @spellingerror
|
||||
m_messages->Report( _( "-------- ERC canceled by user.<br><br>" ), RPT_SEVERITY_INFO );
|
||||
m_messages->Report( _( "-------- ERC cancelled by user.<br><br>" ), RPT_SEVERITY_INFO );
|
||||
else
|
||||
m_messages->Report( _( "Done.<br><br>" ), RPT_SEVERITY_INFO );
|
||||
|
||||
@ -508,7 +558,7 @@ void DIALOG_ERC::testErc()
|
||||
}
|
||||
|
||||
// Update marker list:
|
||||
m_markerTreeModel->Update( m_markerProvider, m_severities );
|
||||
m_markerTreeModel->Update( m_markerProvider, getSeverities() );
|
||||
|
||||
// Display new markers from the current screen:
|
||||
for( SCH_ITEM* marker : m_parent->GetScreen()->Items().OfType( SCH_MARKER_T ) )
|
||||
@ -523,6 +573,12 @@ void DIALOG_ERC::testErc()
|
||||
|
||||
void DIALOG_ERC::OnERCItemSelected( wxDataViewEvent& aEvent )
|
||||
{
|
||||
if( !m_crossprobe )
|
||||
{
|
||||
aEvent.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
const KIID& itemID = RC_TREE_MODEL::ToUUID( aEvent.GetItem() );
|
||||
SCH_SHEET_PATH sheet;
|
||||
SCH_ITEM* item = m_parent->Schematic().ResolveItem( itemID, &sheet, true );
|
||||
@ -568,7 +624,7 @@ void DIALOG_ERC::OnERCItemSelected( wxDataViewEvent& aEvent )
|
||||
m_parent->RedrawScreen( m_parent->GetScreen()->m_ScrollCenter, false );
|
||||
}
|
||||
|
||||
m_parent->FocusOnItem( item );
|
||||
m_parent->FocusOnItem( item, m_scroll_on_crossprobe );
|
||||
redrawDrawPanel();
|
||||
}
|
||||
|
||||
@ -762,7 +818,7 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
|
||||
m_parent->GetCanvas()->GetView()->Update( marker );
|
||||
|
||||
// Update view
|
||||
if( m_severities & RPT_SEVERITY_EXCLUSION )
|
||||
if( getSeverities() & RPT_SEVERITY_EXCLUSION )
|
||||
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->ValueChanged( node );
|
||||
else
|
||||
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->DeleteCurrentItem( false );
|
||||
@ -788,7 +844,7 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
|
||||
}
|
||||
|
||||
// Rebuild model and view
|
||||
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, m_severities );
|
||||
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
|
||||
modified = true;
|
||||
break;
|
||||
|
||||
@ -804,7 +860,7 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
|
||||
}
|
||||
|
||||
// Rebuild model and view
|
||||
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, m_severities );
|
||||
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
|
||||
modified = true;
|
||||
break;
|
||||
|
||||
@ -830,7 +886,7 @@ void DIALOG_ERC::OnERCItemRClick( wxDataViewEvent& aEvent )
|
||||
ScreenList.DeleteMarkers( MARKER_BASE::MARKER_ERC, rcItem->GetErrorCode() );
|
||||
|
||||
// Rebuild model and view
|
||||
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, m_severities );
|
||||
static_cast<RC_TREE_MODEL*>( aEvent.GetModel() )->Update( m_markerProvider, getSeverities() );
|
||||
modified = true;
|
||||
}
|
||||
break;
|
||||
@ -956,7 +1012,7 @@ void DIALOG_ERC::ExcludeMarker( SCH_MARKER* aMarker )
|
||||
m_parent->GetCanvas()->GetView()->Update( marker );
|
||||
|
||||
// Update view
|
||||
if( m_severities & RPT_SEVERITY_EXCLUSION )
|
||||
if( getSeverities() & RPT_SEVERITY_EXCLUSION )
|
||||
m_markerTreeModel->ValueChanged( node );
|
||||
else
|
||||
m_markerTreeModel->DeleteCurrentItem( false );
|
||||
@ -976,28 +1032,14 @@ void DIALOG_ERC::OnEditViolationSeverities( wxHyperlinkEvent& aEvent )
|
||||
|
||||
void DIALOG_ERC::OnSeverity( wxCommandEvent& aEvent )
|
||||
{
|
||||
int flag = 0;
|
||||
|
||||
if( aEvent.GetEventObject() == m_showAll )
|
||||
flag = RPT_SEVERITY_ALL;
|
||||
else if( aEvent.GetEventObject() == m_showErrors )
|
||||
flag = RPT_SEVERITY_ERROR;
|
||||
else if( aEvent.GetEventObject() == m_showWarnings )
|
||||
flag = RPT_SEVERITY_WARNING;
|
||||
else if( aEvent.GetEventObject() == m_showExclusions )
|
||||
flag = RPT_SEVERITY_EXCLUSION;
|
||||
{
|
||||
m_showErrors->SetValue( true );
|
||||
m_showWarnings->SetValue( aEvent.IsChecked() );
|
||||
m_showExclusions->SetValue( aEvent.IsChecked() );
|
||||
}
|
||||
|
||||
if( aEvent.IsChecked() )
|
||||
m_severities |= flag;
|
||||
else if( aEvent.GetEventObject() == m_showAll )
|
||||
m_severities = RPT_SEVERITY_ERROR;
|
||||
else
|
||||
m_severities &= ~flag;
|
||||
|
||||
syncCheckboxes();
|
||||
|
||||
m_markerTreeModel->Update( m_markerProvider, m_severities );
|
||||
updateDisplayedCounts();
|
||||
UpdateData();
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,6 +49,8 @@ public:
|
||||
DIALOG_ERC( SCH_EDIT_FRAME* parent );
|
||||
~DIALOG_ERC();
|
||||
|
||||
bool TransferDataToWindow() override;
|
||||
|
||||
// PROGRESS_REPORTER_BASE calls
|
||||
bool updateUI() override;
|
||||
void AdvancePhase( const wxString& aMessage ) override;
|
||||
@ -66,10 +68,14 @@ public:
|
||||
*/
|
||||
void ExcludeMarker( SCH_MARKER* aMarker = nullptr );
|
||||
|
||||
void UpdateData();
|
||||
void UpdateAnnotationWarning();
|
||||
|
||||
private:
|
||||
int getSeverities();
|
||||
|
||||
// from DIALOG_ERC_BASE:
|
||||
void OnMenu( wxCommandEvent& aEvent ) override;
|
||||
void OnCloseErcDialog( wxCloseEvent& event ) override;
|
||||
void OnRunERCClick( wxCommandEvent& event ) override;
|
||||
void OnDeleteOneClick( wxCommandEvent& event ) override;
|
||||
@ -92,8 +98,6 @@ private:
|
||||
|
||||
void testErc();
|
||||
|
||||
bool writeReport( const wxString& aFullFileName );
|
||||
|
||||
void deleteAllMarkers( bool aIncludeExclusions );
|
||||
|
||||
void syncCheckboxes();
|
||||
@ -114,7 +118,8 @@ private:
|
||||
|
||||
const SCH_MARKER* m_centerMarkerOnIdle;
|
||||
|
||||
int m_severities;
|
||||
bool m_crossprobe;
|
||||
bool m_scroll_on_crossprobe;
|
||||
};
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "widgets/std_bitmap_button.h"
|
||||
#include "widgets/wx_html_report_box.h"
|
||||
#include "widgets/wx_infobar.h"
|
||||
|
||||
@ -29,6 +30,24 @@ DIALOG_ERC_BASE::DIALOG_ERC_BASE( wxWindow* parent, wxWindowID id, const wxStrin
|
||||
wxBoxSizer* bMainSizer;
|
||||
bMainSizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
wxGridBagSizer* gbSizerOptions;
|
||||
gbSizerOptions = new wxGridBagSizer( 0, 0 );
|
||||
gbSizerOptions->SetFlexibleDirection( wxBOTH );
|
||||
gbSizerOptions->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
|
||||
m_bMenu = new STD_BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
|
||||
m_bMenu->SetMinSize( wxSize( 30,30 ) );
|
||||
|
||||
gbSizerOptions->Add( m_bMenu, wxGBPosition( 0, 2 ), wxGBSpan( 2, 1 ), wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
gbSizerOptions->AddGrowableCol( 0 );
|
||||
gbSizerOptions->AddGrowableCol( 1 );
|
||||
gbSizerOptions->AddGrowableRow( 0 );
|
||||
gbSizerOptions->AddGrowableRow( 1 );
|
||||
|
||||
bMainSizer->Add( gbSizerOptions, 0, wxEXPAND|wxLEFT, 5 );
|
||||
|
||||
m_runningResultsBook = new wxSimplebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
|
||||
running = new wxPanel( m_runningResultsBook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
wxBoxSizer* bSizer14;
|
||||
@ -195,6 +214,7 @@ DIALOG_ERC_BASE::DIALOG_ERC_BASE( wxWindow* parent, wxWindowID id, const wxStrin
|
||||
|
||||
// Connect Events
|
||||
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_ERC_BASE::OnCloseErcDialog ) );
|
||||
m_bMenu->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnMenu ), NULL, this );
|
||||
m_messages->Connect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_ERC_BASE::OnLinkClicked ), NULL, this );
|
||||
m_markerDataView->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemDClick ), NULL, this );
|
||||
m_markerDataView->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemRClick ), NULL, this );
|
||||
@ -216,6 +236,7 @@ DIALOG_ERC_BASE::~DIALOG_ERC_BASE()
|
||||
{
|
||||
// Disconnect Events
|
||||
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_ERC_BASE::OnCloseErcDialog ) );
|
||||
m_bMenu->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_ERC_BASE::OnMenu ), NULL, this );
|
||||
m_messages->Disconnect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( DIALOG_ERC_BASE::OnLinkClicked ), NULL, this );
|
||||
m_markerDataView->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemDClick ), NULL, this );
|
||||
m_markerDataView->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( DIALOG_ERC_BASE::OnERCItemRClick ), NULL, this );
|
||||
|
@ -14,7 +14,7 @@
|
||||
<property name="embedded_files_path">res</property>
|
||||
<property name="encoding">UTF-8</property>
|
||||
<property name="file">dialog_erc_base</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="first_id">7100</property>
|
||||
<property name="internationalize">1</property>
|
||||
<property name="lua_skip_events">1</property>
|
||||
<property name="lua_ui_table">UI</property>
|
||||
@ -135,6 +135,101 @@
|
||||
<property name="name">bMainSizer</property>
|
||||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND|wxLEFT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxGridBagSizer" expanded="true">
|
||||
<property name="empty_cell_size"></property>
|
||||
<property name="flexible_direction">wxBOTH</property>
|
||||
<property name="growablecols">0,1</property>
|
||||
<property name="growablerows">0,1</property>
|
||||
<property name="hgap">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="name">gbSizerOptions</property>
|
||||
<property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
|
||||
<property name="permission">none</property>
|
||||
<property name="vgap">0</property>
|
||||
<object class="gbsizeritem" expanded="true">
|
||||
<property name="border">5</property>
|
||||
<property name="colspan">1</property>
|
||||
<property name="column">2</property>
|
||||
<property name="flag">wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="row">0</property>
|
||||
<property name="rowspan">2</property>
|
||||
<object class="wxBitmapButton" expanded="true">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer">0</property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position">0</property>
|
||||
<property name="aui_row">0</property>
|
||||
<property name="auth_needed">0</property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="bitmap"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="current"></property>
|
||||
<property name="default">0</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="disabled"></property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="drag_accept_files">0</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="focus"></property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Refresh Grouping</property>
|
||||
<property name="margins"></property>
|
||||
<property name="markup">0</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size">30,30</property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_bMenu</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="position"></property>
|
||||
<property name="pressed"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">STD_BITMAP_BUTTON; widgets/std_bitmap_button.h; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
<event name="OnButtonClick">OnMenu</event>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND|wxTOP|wxRIGHT</property>
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <wx/artprov.h>
|
||||
#include <wx/xrc/xmlres.h>
|
||||
#include <wx/intl.h>
|
||||
class STD_BITMAP_BUTTON;
|
||||
class WX_HTML_REPORT_BOX;
|
||||
class WX_INFOBAR;
|
||||
|
||||
@ -20,13 +21,16 @@ class WX_INFOBAR;
|
||||
#include <wx/colour.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/bmpbuttn.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/icon.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/html/htmlwin.h>
|
||||
#include <wx/gauge.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/icon.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/dataview.h>
|
||||
#include <wx/listctrl.h>
|
||||
@ -35,12 +39,11 @@ class WX_INFOBAR;
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <widgets/number_badge.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/dialog.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define ID_ERASE_DRC_MARKERS 1000
|
||||
#define ID_ERASE_DRC_MARKERS 7100
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class DIALOG_ERC_BASE
|
||||
@ -51,6 +54,7 @@ class DIALOG_ERC_BASE : public DIALOG_SHIM
|
||||
|
||||
protected:
|
||||
WX_INFOBAR* m_infoBar;
|
||||
STD_BITMAP_BUTTON* m_bMenu;
|
||||
wxSimplebook* m_runningResultsBook;
|
||||
wxPanel* running;
|
||||
wxNotebook* m_runningNotebook;
|
||||
@ -82,6 +86,7 @@ class DIALOG_ERC_BASE : public DIALOG_SHIM
|
||||
|
||||
// Virtual event handlers, override them in your derived class
|
||||
virtual void OnCloseErcDialog( wxCloseEvent& event ) { event.Skip(); }
|
||||
virtual void OnMenu( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnLinkClicked( wxHtmlLinkEvent& event ) { event.Skip(); }
|
||||
virtual void OnERCItemDClick( wxDataViewEvent& event ) { event.Skip(); }
|
||||
virtual void OnERCItemRClick( wxDataViewEvent& event ) { event.Skip(); }
|
||||
|
@ -77,8 +77,8 @@ public:
|
||||
*/
|
||||
std::vector<std::pair<FIELD_T, wxString>> GetFields() const;
|
||||
|
||||
bool GetKeepSymbol() { return m_keepSymbol; }
|
||||
bool GetPlaceAllUnits() { return m_useUnits; }
|
||||
bool GetKeepSymbol() { return m_keepSymbol->GetValue(); }
|
||||
bool GetPlaceAllUnits() { return m_useUnits->GetValue(); }
|
||||
|
||||
public:
|
||||
static std::mutex g_Mutex;
|
||||
|
@ -269,7 +269,6 @@ DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent,
|
||||
|
||||
preset.name = m_job->m_bomPresetName;
|
||||
preset.excludeDNP = m_job->m_excludeDNP;
|
||||
preset.includeExcludedFromBOM = m_job->m_includeExcludedFromBOM;
|
||||
preset.filterString = m_job->m_filterString;
|
||||
preset.sortAsc = m_job->m_sortAsc;
|
||||
preset.sortField = m_job->m_sortField;
|
||||
@ -922,16 +921,28 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnMenu( wxCommandEvent& event )
|
||||
// Build a pop menu:
|
||||
wxMenu menu;
|
||||
|
||||
menu.Append( 4204, _( "Include 'DNP' Symbols" ), wxEmptyString, wxITEM_CHECK );
|
||||
menu.Append( 4205, _( "Include 'Exclude from BOM' Symbols" ), wxEmptyString, wxITEM_CHECK );
|
||||
menu.AppendSeparator();
|
||||
menu.Append( 4206, _( "Highlight on Cross Probe" ), wxEmptyString, wxITEM_CHECK );
|
||||
menu.Append( 4207, _( "Select on Cross Probe" ), wxEmptyString, wxITEM_CHECK );
|
||||
|
||||
menu.Append( 4204, _( "Include 'DNP' Symbols" ),
|
||||
_( "Show symbols marked 'DNP' in the table. This setting also controls whether or not 'DNP' "
|
||||
"symbols are included on export." ),
|
||||
wxITEM_CHECK );
|
||||
menu.Check( 4204, !m_dataModel->GetExcludeDNP() );
|
||||
|
||||
menu.Append( 4205, _( "Include 'Exclude from BOM' Symbols" ),
|
||||
_( "Show symbols marked 'Exclude from BOM' in the table. Symbols marked 'Exclude from BOM' "
|
||||
"are never included on export." ),
|
||||
wxITEM_CHECK );
|
||||
menu.Check( 4205, m_dataModel->GetIncludeExcludedFromBOM() );
|
||||
|
||||
menu.AppendSeparator();
|
||||
|
||||
menu.Append( 4206, _( "Highlight on Cross-probe" ),
|
||||
_( "Highlight corresponding item on canvas when it is selected in the table" ),
|
||||
wxITEM_CHECK );
|
||||
menu.Check( 4206, cfg.selection_mode == 0 );
|
||||
|
||||
menu.Append( 4207, _( "Select on Cross-probe" ),
|
||||
_( "Select corresponding item on canvas when it is selected in the table" ),
|
||||
wxITEM_CHECK );
|
||||
menu.Check( 4207, cfg.selection_mode == 1 );
|
||||
|
||||
// menu_id is the selected submenu id from the popup menu or wxID_NONE
|
||||
@ -947,7 +958,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnMenu( wxCommandEvent& event )
|
||||
}
|
||||
else if( menu_id == 1 || menu_id == 4205 )
|
||||
{
|
||||
m_dataModel->SetExcludeDNP( m_dataModel->GetIncludeExcludedFromBOM() );
|
||||
m_dataModel->SetIncludeExcludedFromBOM( !m_dataModel->GetIncludeExcludedFromBOM() );
|
||||
m_dataModel->RebuildRows();
|
||||
m_grid->ForceRefresh();
|
||||
|
||||
@ -1300,8 +1311,18 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnPreviewRefresh( wxCommandEvent& event )
|
||||
|
||||
void DIALOG_SYMBOL_FIELDS_TABLE::PreviewRefresh()
|
||||
{
|
||||
bool saveIncludeExcudedFromBOM = m_dataModel->GetIncludeExcludedFromBOM();
|
||||
|
||||
m_dataModel->SetIncludeExcludedFromBOM( false );
|
||||
m_dataModel->RebuildRows();
|
||||
|
||||
m_textOutput->SetValue( m_dataModel->Export( GetCurrentBomFmtSettings() ) );
|
||||
|
||||
if( saveIncludeExcudedFromBOM )
|
||||
{
|
||||
m_dataModel->SetIncludeExcludedFromBOM( true );
|
||||
m_dataModel->RebuildRows();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1499,7 +1520,6 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnOk( wxCommandEvent& aEvent )
|
||||
BOM_PRESET presetFields = m_dataModel->GetBomSettings();
|
||||
m_job->m_sortAsc = presetFields.sortAsc;
|
||||
m_job->m_excludeDNP = presetFields.excludeDNP;
|
||||
m_job->m_includeExcludedFromBOM = presetFields.includeExcludedFromBOM;
|
||||
m_job->m_filterString = presetFields.filterString;
|
||||
m_job->m_sortField = presetFields.sortField;
|
||||
|
||||
|
@ -169,7 +169,7 @@ DIALOG_SYMBOL_FIELDS_TABLE_BASE::DIALOG_SYMBOL_FIELDS_TABLE_BASE( wxWindow* pare
|
||||
m_bMenu = new STD_BITMAP_BUTTON( m_panelEdit, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
|
||||
m_bMenu->SetMinSize( wxSize( 30,30 ) );
|
||||
|
||||
bControls->Add( m_bMenu, 0, wxRIGHT, 5 );
|
||||
bControls->Add( m_bMenu, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 );
|
||||
|
||||
|
||||
bEditSizer->Add( bControls, 0, wxEXPAND|wxLEFT|wxTOP, 5 );
|
||||
|
@ -1384,7 +1384,7 @@
|
||||
</object>
|
||||
<object class="sizeritem" expanded="false">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxRIGHT</property>
|
||||
<property name="flag">wxRIGHT|wxALIGN_CENTER_VERTICAL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxBitmapButton" expanded="false">
|
||||
<property name="BottomDockable">1</property>
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <lib_table_grid.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
#include <env_paths.h>
|
||||
#include <functional>
|
||||
#include <eeschema_id.h>
|
||||
#include <symbol_edit_frame.h>
|
||||
#include <symbol_viewer_frame.h>
|
||||
@ -153,6 +154,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
SYMBOL_GRID_TRICKS( DIALOG_EDIT_LIBRARY_TABLES* aParent, WX_GRID* aGrid,
|
||||
std::function<void( wxCommandEvent& )> aAddHandler ) :
|
||||
LIB_TABLE_GRID_TRICKS( aGrid, aAddHandler ),
|
||||
m_dialog( aParent )
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
DIALOG_EDIT_LIBRARY_TABLES* m_dialog;
|
||||
|
||||
@ -224,8 +232,21 @@ protected:
|
||||
}
|
||||
else
|
||||
{
|
||||
// paste spreadsheet formatted text.
|
||||
GRID_TRICKS::paste_text( cb_text );
|
||||
wxString text = cb_text;
|
||||
|
||||
if( !text.Contains( '\t' ) && text.Contains( ',' ) )
|
||||
text.Replace( ',', '\t' );
|
||||
|
||||
if( text.Contains( '\t' ) )
|
||||
{
|
||||
int row = m_grid->GetGridCursorRow();
|
||||
m_grid->ClearSelection();
|
||||
m_grid->SelectRow( row );
|
||||
m_grid->SetGridCursor( row, 0 );
|
||||
getSelectedArea();
|
||||
}
|
||||
|
||||
GRID_TRICKS::paste_text( text );
|
||||
|
||||
m_grid->AutoSizeColumns( false );
|
||||
}
|
||||
@ -250,7 +271,8 @@ void PANEL_SYM_LIB_TABLE::setupGrid( WX_GRID* aGrid )
|
||||
};
|
||||
|
||||
// add Cut, Copy, and Paste to wxGrids
|
||||
aGrid->PushEventHandler( new SYMBOL_GRID_TRICKS( m_parent, aGrid ) );
|
||||
aGrid->PushEventHandler( new SYMBOL_GRID_TRICKS( m_parent, aGrid,
|
||||
[this]( wxCommandEvent& event ) { appendRowHandler( event ); } ) );
|
||||
|
||||
aGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
|
||||
|
||||
|
@ -92,6 +92,10 @@ enum id_eeschema_frm
|
||||
// to select one unit among MAX_UNIT_COUNT_PER_PACKAGE in popup menu
|
||||
ID_POPUP_SCH_SELECT_UNIT_END = ID_POPUP_SCH_SELECT_UNIT1 + MAX_UNIT_COUNT_PER_PACKAGE,
|
||||
|
||||
ID_POPUP_SCH_PLACE_UNIT,
|
||||
ID_POPUP_SCH_PLACE_UNIT1,
|
||||
ID_POPUP_SCH_PLACE_UNIT_END = ID_POPUP_SCH_PLACE_UNIT1 + MAX_UNIT_COUNT_PER_PACKAGE,
|
||||
|
||||
ID_POPUP_SCH_SELECT_BODY_STYLE,
|
||||
ID_POPUP_SCH_SELECT_BODY_STYLE1,
|
||||
ID_POPUP_SCH_SELECT_BODY_STYLE_END = ID_POPUP_SCH_SELECT_BODY_STYLE1 + MAX_BODY_STYLE_PER_PACKAGE,
|
||||
|
@ -668,7 +668,6 @@ int EESCHEMA_JOBS_HANDLER::JobExportBom( JOB* aJob )
|
||||
preset.filterString = aBomJob->m_filterString;
|
||||
preset.groupSymbols = ( aBomJob->m_fieldsGroupBy.size() > 0 );
|
||||
preset.excludeDNP = aBomJob->m_excludeDNP;
|
||||
preset.includeExcludedFromBOM = aBomJob->m_includeExcludedFromBOM;
|
||||
}
|
||||
|
||||
dataModel.ApplyBomPreset( preset );
|
||||
|
@ -189,9 +189,6 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
|
||||
m_params.emplace_back( new PARAM<int>( "appearance.edit_label_height",
|
||||
&m_Appearance.edit_label_height, -1 ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<int>( "appearance.erc_severities",
|
||||
&m_Appearance.erc_severities, RPT_SEVERITY_ERROR | RPT_SEVERITY_WARNING ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<bool>( "appearance.footprint_preview",
|
||||
&m_Appearance.footprint_preview, true ) );
|
||||
|
||||
@ -591,6 +588,12 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
|
||||
m_params.emplace_back( new PARAM<int>( "symbol_chooser.sort_mode",
|
||||
&m_SymChooserPanel.sort_mode, 0 ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<bool>( "ERC.crossprobe",
|
||||
&m_ERCDialog.crossprobe, true ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<bool>( "ERC.scroll_on_crossprobe",
|
||||
&m_ERCDialog.scroll_on_crossprobe, true ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<bool>( "import_graphics.interactive_placement",
|
||||
&m_ImportGraphics.interactive_placement, true ) );
|
||||
|
||||
|
@ -68,7 +68,6 @@ public:
|
||||
int edit_label_width;
|
||||
int edit_label_height;
|
||||
bool edit_label_multiple;
|
||||
int erc_severities;
|
||||
bool footprint_preview;
|
||||
bool print_sheet_reference;
|
||||
wxString default_font;
|
||||
@ -265,6 +264,12 @@ public:
|
||||
int sort_mode;
|
||||
};
|
||||
|
||||
struct DIALOG_ERC
|
||||
{
|
||||
bool crossprobe;
|
||||
bool scroll_on_crossprobe;
|
||||
};
|
||||
|
||||
struct DIALOG_IMPORT_GRAPHICS
|
||||
{
|
||||
bool interactive_placement;
|
||||
@ -328,40 +333,31 @@ private:
|
||||
static std::vector<NETLIST_PLUGIN_SETTINGS> netlistSettingsFromJson( const nlohmann::json& aObj );
|
||||
|
||||
public:
|
||||
APPEARANCE m_Appearance;
|
||||
APPEARANCE m_Appearance;
|
||||
AUI_PANELS m_AuiPanels;
|
||||
|
||||
AUTOPLACE_FIELDS m_AutoplaceFields;
|
||||
DRAWING m_Drawing;
|
||||
INPUT m_Input;
|
||||
AUTOPLACE_FIELDS m_AutoplaceFields;
|
||||
SELECTION m_Selection;
|
||||
|
||||
AUI_PANELS m_AuiPanels;
|
||||
|
||||
DRAWING m_Drawing;
|
||||
|
||||
FIND_REPLACE_EXTRA m_FindReplaceExtra;
|
||||
|
||||
INPUT m_Input;
|
||||
|
||||
PAGE_SETTINGS m_PageSettings;
|
||||
|
||||
PANEL_ANNOTATE m_AnnotatePanel;
|
||||
|
||||
PANEL_BOM m_BomPanel;
|
||||
PAGE_SETTINGS m_PageSettings;
|
||||
PANEL_ANNOTATE m_AnnotatePanel;
|
||||
PANEL_BOM m_BomPanel;
|
||||
|
||||
PANEL_SYMBOL_FIELDS_TABLE m_FieldEditorPanel;
|
||||
PANEL_LIB_VIEW m_LibViewPanel;
|
||||
PANEL_NETLIST m_NetlistPanel;
|
||||
PANEL_SYM_CHOOSER m_SymChooserPanel;
|
||||
|
||||
PANEL_LIB_VIEW m_LibViewPanel;
|
||||
FIND_REPLACE_EXTRA m_FindReplaceExtra;
|
||||
DIALOG_ERC m_ERCDialog;
|
||||
DIALOG_IMPORT_GRAPHICS m_ImportGraphics;
|
||||
|
||||
PANEL_NETLIST m_NetlistPanel;
|
||||
SIMULATOR m_Simulator;
|
||||
|
||||
PANEL_SYM_CHOOSER m_SymChooserPanel;
|
||||
bool m_RescueNeverShow;
|
||||
|
||||
DIALOG_IMPORT_GRAPHICS m_ImportGraphics;
|
||||
|
||||
SELECTION m_Selection;
|
||||
|
||||
SIMULATOR m_Simulator;
|
||||
|
||||
bool m_RescueNeverShow;
|
||||
|
||||
wxString m_lastSymbolLibDir;
|
||||
wxString m_lastSymbolLibDir;
|
||||
};
|
||||
|
||||
|
@ -159,6 +159,13 @@ bool SCH_BITMAP::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) c
|
||||
}
|
||||
|
||||
|
||||
bool SCH_BITMAP::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
|
||||
{
|
||||
return KIGEOM::BoxHitTest( aPoly, GetBoundingBox(), aContained );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SCH_BITMAP::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
|
||||
int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
|
||||
{
|
||||
|
@ -100,6 +100,7 @@ public:
|
||||
|
||||
bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override;
|
||||
bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy = 0 ) const override;
|
||||
bool HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const override;
|
||||
|
||||
void Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
|
||||
int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed ) override;
|
||||
|
@ -2032,7 +2032,7 @@ bool SCH_EDIT_FRAME::GetShowAllPins() const
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem )
|
||||
void SCH_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll )
|
||||
{
|
||||
// nullptr will clear the current focus
|
||||
if( aItem != nullptr && !aItem->IsSCH_ITEM() )
|
||||
@ -2060,7 +2060,7 @@ void SCH_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem )
|
||||
lastBrightenedItemID = aItem->m_Uuid;
|
||||
}
|
||||
|
||||
FocusOnLocation( aItem->GetFocusPosition() );
|
||||
FocusOnLocation( aItem->GetFocusPosition(), aAllowScroll );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -755,7 +755,7 @@ public:
|
||||
int GetSchematicJunctionSize();
|
||||
double GetSchematicHopOverScale();
|
||||
|
||||
void FocusOnItem( EDA_ITEM* aItem ) override;
|
||||
void FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll = true ) override;
|
||||
|
||||
bool IsSyncingSelection() { return m_syncingPcbToSchSelection; }
|
||||
|
||||
|
@ -165,28 +165,6 @@ SCH_ITEM* SCH_ITEM::Duplicate( bool addToParentGroup, SCH_COMMIT* aCommit, bool
|
||||
}
|
||||
|
||||
|
||||
void SCH_ITEM::SetUnitProp( const wxString& aUnit )
|
||||
{
|
||||
if( aUnit == _HKI( "All units" ) )
|
||||
{
|
||||
m_unit = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if( SYMBOL* symbol = GetParentSymbol() )
|
||||
{
|
||||
for( int unit = 1; unit <= symbol->GetUnitCount(); unit++ )
|
||||
{
|
||||
if( symbol->GetUnitDisplayName( unit, false ) == aUnit )
|
||||
{
|
||||
m_unit = unit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
wxString SCH_ITEM::GetUnitDisplayName( int aUnit, bool aLabel ) const
|
||||
{
|
||||
if( aUnit == 0 )
|
||||
@ -208,13 +186,6 @@ wxString SCH_ITEM::GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
|
||||
wxString SCH_ITEM::GetUnitProp() const
|
||||
{
|
||||
return GetUnitDisplayName( m_unit, false );
|
||||
}
|
||||
|
||||
|
||||
void SCH_ITEM::SetBodyStyleProp( const wxString& aBodyStyle )
|
||||
{
|
||||
if( aBodyStyle == _HKI( "All body styles" ) )
|
||||
@ -734,21 +705,21 @@ static struct SCH_ITEM_DESC
|
||||
return false;
|
||||
};
|
||||
|
||||
propMgr.AddProperty( new PROPERTY<SCH_ITEM, wxString>( _HKI( "Unit" ),
|
||||
&SCH_ITEM::SetUnitProp, &SCH_ITEM::GetUnitProp ) )
|
||||
propMgr.AddProperty( new PROPERTY<SCH_ITEM, int>( _HKI( "Unit" ),
|
||||
&SCH_ITEM::SetUnit, &SCH_ITEM::GetUnit ) )
|
||||
.SetAvailableFunc( multiUnit )
|
||||
.SetIsHiddenFromDesignEditors()
|
||||
.SetChoicesFunc( []( INSPECTABLE* aItem )
|
||||
{
|
||||
wxPGChoices choices;
|
||||
choices.Add( _HKI( "All units" ) );
|
||||
choices.Add( _HKI( "All units" ), 0 );
|
||||
|
||||
if( SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aItem ) )
|
||||
{
|
||||
if( SYMBOL* symbol = item->GetParentSymbol() )
|
||||
{
|
||||
for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
|
||||
choices.Add( symbol->GetUnitDisplayName( ii, false ) );
|
||||
choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,9 +240,6 @@ public:
|
||||
virtual wxString GetUnitDisplayName( int aUnit, bool aLabel ) const;
|
||||
virtual wxString GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const;
|
||||
|
||||
virtual void SetUnitProp( const wxString& aUnit );
|
||||
virtual wxString GetUnitProp() const;
|
||||
|
||||
virtual void SetBodyStyle( int aBodyStyle ) { m_bodyStyle = aBodyStyle; }
|
||||
int GetBodyStyle() const { return m_bodyStyle; }
|
||||
|
||||
|
@ -34,6 +34,9 @@
|
||||
#include <string_utils.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <schematic.h>
|
||||
#include <sch_screen.h>
|
||||
#include <sch_sheet.h>
|
||||
#include <sch_sheet_pin.h>
|
||||
#include <settings/color_settings.h>
|
||||
#include <sch_painter.h>
|
||||
#include <default_values.h>
|
||||
@ -314,6 +317,82 @@ COLOR4D SCH_LABEL_BASE::GetLabelColor() const
|
||||
}
|
||||
|
||||
|
||||
void SCH_LABEL_BASE::SetLabelShape( LABEL_SHAPE aShape )
|
||||
{
|
||||
m_shape = (LABEL_FLAG_SHAPE) aShape;
|
||||
|
||||
static bool s_inUpdate = false;
|
||||
|
||||
if( s_inUpdate )
|
||||
return;
|
||||
|
||||
s_inUpdate = true;
|
||||
|
||||
if( Type() == SCH_HIER_LABEL_T )
|
||||
{
|
||||
SCH_HIERLABEL* label = static_cast<SCH_HIERLABEL*>( this );
|
||||
SCH_SCREEN* screen = static_cast<SCH_SCREEN*>( label->GetParent() );
|
||||
|
||||
if( screen )
|
||||
{
|
||||
const wxString& text = label->GetText();
|
||||
|
||||
for( SCH_ITEM* item : screen->Items().OfType( SCH_HIER_LABEL_T ) )
|
||||
{
|
||||
SCH_HIERLABEL* other = static_cast<SCH_HIERLABEL*>( item );
|
||||
|
||||
if( other != label && other->GetText() == text )
|
||||
other->SetLabelShape( aShape );
|
||||
}
|
||||
|
||||
for( const SCH_SHEET_PATH& sheetPath : screen->GetClientSheetPaths() )
|
||||
{
|
||||
SCH_SHEET* sheet = sheetPath.Last();
|
||||
|
||||
if( sheet )
|
||||
{
|
||||
for( SCH_SHEET_PIN* pin : sheet->GetPins() )
|
||||
{
|
||||
if( pin->GetText() == text )
|
||||
pin->SetLabelShape( aShape );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( Type() == SCH_SHEET_PIN_T )
|
||||
{
|
||||
SCH_SHEET_PIN* pin = static_cast<SCH_SHEET_PIN*>( this );
|
||||
SCH_SHEET* parent = pin->GetParent();
|
||||
|
||||
if( parent )
|
||||
{
|
||||
const wxString& text = pin->GetText();
|
||||
SCH_SCREEN* screen = parent->GetScreen();
|
||||
|
||||
if( screen )
|
||||
{
|
||||
for( SCH_ITEM* item : screen->Items().OfType( SCH_HIER_LABEL_T ) )
|
||||
{
|
||||
SCH_HIERLABEL* hlabel = static_cast<SCH_HIERLABEL*>( item );
|
||||
|
||||
if( hlabel->GetText() == text )
|
||||
hlabel->SetLabelShape( aShape );
|
||||
}
|
||||
}
|
||||
|
||||
for( SCH_SHEET_PIN* other : parent->GetPins() )
|
||||
{
|
||||
if( other != pin && other->GetText() == text )
|
||||
other->SetLabelShape( aShape );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_inUpdate = false;
|
||||
}
|
||||
|
||||
|
||||
void SCH_LABEL_BASE::SetSpinStyle( SPIN_STYLE aSpinStyle )
|
||||
{
|
||||
// Assume "Right" and Left" mean which side of the anchor the text will be on
|
||||
|
@ -173,12 +173,19 @@ public:
|
||||
bool HasConnectivityChanges( const SCH_ITEM* aItem,
|
||||
const SCH_SHEET_PATH* aInstance = nullptr ) const override;
|
||||
|
||||
LABEL_FLAG_SHAPE GetShape() const { return m_shape; }
|
||||
void SetShape( LABEL_FLAG_SHAPE aShape ) { m_shape = aShape; }
|
||||
|
||||
// Type-specific versions for property manager
|
||||
LABEL_SHAPE GetLabelShape() const { return (LABEL_SHAPE) m_shape; }
|
||||
void SetLabelShape( LABEL_SHAPE aShape ) { m_shape = (LABEL_FLAG_SHAPE) aShape; }
|
||||
void SetLabelShape( LABEL_SHAPE aShape );
|
||||
|
||||
LABEL_FLAG_SHAPE GetShape() const { return m_shape; }
|
||||
void SetShape( LABEL_FLAG_SHAPE aShape )
|
||||
{
|
||||
// Set flags directly if a flag shape
|
||||
if( aShape >= F_FIRST )
|
||||
m_shape = aShape;
|
||||
else
|
||||
SetLabelShape( (LABEL_SHAPE) aShape );
|
||||
}
|
||||
|
||||
COLOR4D GetLabelColor() const;
|
||||
|
||||
|
@ -2986,7 +2986,7 @@ static struct SCH_SYMBOL_DESC
|
||||
return false;
|
||||
};
|
||||
|
||||
propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Unit" ),
|
||||
propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, int>( _HKI( "Unit" ),
|
||||
&SCH_SYMBOL::SetUnitProp, &SCH_SYMBOL::GetUnitProp ) )
|
||||
.SetAvailableFunc( multiUnit )
|
||||
.SetChoicesFunc( []( INSPECTABLE* aItem )
|
||||
@ -2996,7 +2996,7 @@ static struct SCH_SYMBOL_DESC
|
||||
if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
|
||||
{
|
||||
for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
|
||||
choices.Add( symbol->GetUnitDisplayName( ii, false ) );
|
||||
choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
|
||||
}
|
||||
|
||||
return choices;
|
||||
|
@ -497,24 +497,15 @@ public:
|
||||
SetValueFieldText( aRef );
|
||||
}
|
||||
|
||||
wxString GetUnitProp() const override
|
||||
int GetUnitProp() const
|
||||
{
|
||||
int unit = GetUnitSelection( &Schematic()->CurrentSheet() );
|
||||
|
||||
return GetUnitDisplayName( unit, false );
|
||||
return GetUnitSelection( &Schematic()->CurrentSheet() );
|
||||
}
|
||||
|
||||
void SetUnitProp( const wxString& aUnit ) override
|
||||
void SetUnitProp( int aUnit )
|
||||
{
|
||||
for( int unit = 1; unit <= GetUnitCount(); unit++ )
|
||||
{
|
||||
if( GetUnitDisplayName( unit, false ) == aUnit )
|
||||
{
|
||||
SetUnitSelection( &Schematic()->CurrentSheet(), unit );
|
||||
SetUnit( unit );
|
||||
return;
|
||||
}
|
||||
}
|
||||
SetUnitSelection( &Schematic()->CurrentSheet(), aUnit );
|
||||
SetUnit( aUnit );
|
||||
}
|
||||
|
||||
wxString GetBodyStyleProp() const override
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <sch_painter.h>
|
||||
#include <wx/log.h>
|
||||
#include <sch_table.h>
|
||||
#include <geometry/geometry_utils.h>
|
||||
|
||||
|
||||
SCH_TABLE::SCH_TABLE( int aLineWidth ) :
|
||||
@ -327,6 +328,12 @@ bool SCH_TABLE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) co
|
||||
}
|
||||
|
||||
|
||||
bool SCH_TABLE::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
|
||||
{
|
||||
return KIGEOM::BoxHitTest( aPoly, GetBoundingBox(), aContained );
|
||||
}
|
||||
|
||||
|
||||
void SCH_TABLE::DrawBorders( const std::function<void( const VECTOR2I& aPt1, const VECTOR2I& aPt2,
|
||||
const STROKE_PARAMS& aStroke )>& aCallback ) const
|
||||
{
|
||||
|
@ -214,8 +214,8 @@ public:
|
||||
std::vector<int> ViewGetLayers() const override;
|
||||
|
||||
bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override;
|
||||
|
||||
bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy = 0 ) const override;
|
||||
bool HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const override;
|
||||
|
||||
void DrawBorders( const std::function<void( const VECTOR2I& aPt1, const VECTOR2I& aPt2,
|
||||
const STROKE_PARAMS& aStroke )>& aCallback ) const;
|
||||
|
@ -224,6 +224,7 @@ static struct SCH_TABLECELL_DESC
|
||||
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Width" ) );
|
||||
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Style" ) );
|
||||
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Line Color" ) );
|
||||
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_SHAPE ), _HKI( "Corner Radius" ) );
|
||||
|
||||
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Width" ) );
|
||||
propMgr.Mask( TYPE_HASH( SCH_TABLECELL ), TYPE_HASH( EDA_TEXT ), _HKI( "Height" ) );
|
||||
|
@ -613,6 +613,7 @@ static struct SCH_TEXTBOX_DESC
|
||||
propMgr.InheritsAfter( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ) );
|
||||
|
||||
propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_SHAPE ), _HKI( "Shape" ) );
|
||||
propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_SHAPE ), _HKI( "Corner Radius" ) );
|
||||
|
||||
propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ), _HKI( "Width" ) );
|
||||
propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ), _HKI( "Height" ) );
|
||||
|
@ -140,11 +140,10 @@ void SPICE_LIBRARY_PARSER::ReadFile( const wxString& aFilePath, REPORTER& aRepor
|
||||
// Read all self-contained models in parallel
|
||||
thread_pool& tp = GetKiCadThreadPool();
|
||||
|
||||
auto results = tp.parallelize_loop( modelQueue.size(),
|
||||
[&]( const int a, const int b )
|
||||
auto results = tp.submit_loop( 0, modelQueue.size(),
|
||||
[&]( const int ii )
|
||||
{
|
||||
for( int ii = a; ii < b; ++ii )
|
||||
createModel( ii, true );
|
||||
createModel( ii, true );
|
||||
} );
|
||||
results.wait();
|
||||
|
||||
|
@ -1541,7 +1541,7 @@ const BOX2I SYMBOL_EDIT_FRAME::GetDocumentExtents( bool aIncludeAllVisible ) con
|
||||
}
|
||||
|
||||
|
||||
void SYMBOL_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem )
|
||||
void SYMBOL_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll )
|
||||
{
|
||||
static KIID lastBrightenedItemID( niluuid );
|
||||
|
||||
@ -1587,7 +1587,7 @@ void SYMBOL_EDIT_FRAME::FocusOnItem( EDA_ITEM* aItem )
|
||||
lastBrightenedItemID = aItem->m_Uuid;
|
||||
}
|
||||
|
||||
FocusOnLocation( VECTOR2I( aItem->GetFocusPosition().x, -aItem->GetFocusPosition().y ) );
|
||||
FocusOnLocation( VECTOR2I( aItem->GetFocusPosition().x, -aItem->GetFocusPosition().y ), aAllowScroll );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,7 +377,7 @@ public:
|
||||
|
||||
void KiwayMailIn( KIWAY_EXPRESS& mail ) override;
|
||||
|
||||
void FocusOnItem( EDA_ITEM* aItem ) override;
|
||||
void FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll = true ) override;
|
||||
|
||||
/**
|
||||
* Load a symbol from the schematic to edit in place.
|
||||
|
@ -438,8 +438,8 @@ TOOL_ACTION SCH_ACTIONS::placeNextSymbolUnit( TOOL_ACTION_ARGS()
|
||||
.FriendlyName( _( "Place Next Symbol Unit" ) )
|
||||
.Tooltip( _( "Place the next unit of the current symbol that is missing from the schematic" ) )
|
||||
.Flags( AF_ACTIVATE )
|
||||
// The symbol to use as a reference for the next unit
|
||||
.Parameter<SCH_SYMBOL*>( nullptr ) );
|
||||
// The symbol to use as a reference for the next unit and optionally the unit number
|
||||
.Parameter<SCH_ACTIONS::PLACE_SYMBOL_UNIT_PARAMS>( {} ) );
|
||||
|
||||
TOOL_ACTION SCH_ACTIONS::placePower( TOOL_ACTION_ARGS()
|
||||
.Name( "eeschema.InteractiveDrawing.placePowerSymbol" )
|
||||
|
@ -310,4 +310,12 @@ public:
|
||||
///< If a symbol is provide, reannotate it?
|
||||
bool m_Reannotate = true;
|
||||
};
|
||||
|
||||
struct PLACE_SYMBOL_UNIT_PARAMS
|
||||
{
|
||||
///< Symbol used as reference for unit placement
|
||||
SCH_SYMBOL* m_Symbol = nullptr;
|
||||
///< Unit number to place; 0 means next available unit
|
||||
int m_Unit = 0;
|
||||
};
|
||||
};
|
||||
|
@ -619,7 +619,10 @@ int SCH_DRAWING_TOOLS::PlaceSymbol( const TOOL_EVENT& aEvent )
|
||||
|
||||
int SCH_DRAWING_TOOLS::PlaceNextSymbolUnit( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
SCH_SYMBOL* symbol = aEvent.Parameter<SCH_SYMBOL*>();
|
||||
const SCH_ACTIONS::PLACE_SYMBOL_UNIT_PARAMS& params =
|
||||
aEvent.Parameter<SCH_ACTIONS::PLACE_SYMBOL_UNIT_PARAMS>();
|
||||
SCH_SYMBOL* symbol = params.m_Symbol;
|
||||
int requestedUnit = params.m_Unit;
|
||||
|
||||
// TODO: get from selection
|
||||
if( !symbol )
|
||||
@ -654,8 +657,23 @@ int SCH_DRAWING_TOOLS::PlaceNextSymbolUnit( const TOOL_EVENT& aEvent )
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Find the lowest unit number that is missing
|
||||
const int nextMissing = *std::min_element( missingUnits.begin(), missingUnits.end() );
|
||||
int nextMissing;
|
||||
|
||||
if( requestedUnit > 0 )
|
||||
{
|
||||
if( missingUnits.count( requestedUnit ) == 0 )
|
||||
{
|
||||
m_frame->ShowInfoBarMsg( _( "Requested unit already placed." ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
nextMissing = requestedUnit;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the lowest unit number that is missing
|
||||
nextMissing = *std::min_element( missingUnits.begin(), missingUnits.end() );
|
||||
}
|
||||
|
||||
std::unique_ptr<SCH_SYMBOL> newSymbol = std::make_unique<SCH_SYMBOL>( *symbol );
|
||||
const SCH_SHEET_PATH& sheetPath = m_frame->GetCurrentSheet();
|
||||
@ -3079,6 +3097,7 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
|
||||
KIGFX::VIEW_CONTROLS* controls = getViewControls();
|
||||
EE_GRID_HELPER grid( m_toolMgr );
|
||||
VECTOR2I cursorPos;
|
||||
bool startedWithDrag = false; // Track if initial sheet placement started with a drag
|
||||
|
||||
m_toolMgr->RunAction( ACTIONS::selectionClear );
|
||||
|
||||
@ -3170,7 +3189,8 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
|
||||
}
|
||||
}
|
||||
else if( !sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
|
||||
|| evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick ) ) )
|
||||
|| evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick )
|
||||
|| evt->IsDrag( BUT_LEFT ) ) )
|
||||
{
|
||||
SCH_SELECTION& selection = m_selectionTool->GetSelection();
|
||||
|
||||
@ -3193,7 +3213,15 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
|
||||
|
||||
m_toolMgr->RunAction( ACTIONS::selectionClear );
|
||||
|
||||
sheet = new SCH_SHEET( m_frame->GetCurrentSheet().Last(), cursorPos );
|
||||
VECTOR2I sheetPos = evt->IsDrag( BUT_LEFT ) ?
|
||||
grid.Align( evt->DragOrigin(), GRID_HELPER_GRIDS::GRID_GRAPHICS ) :
|
||||
cursorPos;
|
||||
|
||||
// Remember whether this sheet was initiated with a drag so we can treat mouse-up as
|
||||
// the terminating (second) click.
|
||||
startedWithDrag = evt->IsDrag( BUT_LEFT );
|
||||
|
||||
sheet = new SCH_SHEET( m_frame->GetCurrentSheet().Last(), sheetPos );
|
||||
sheet->SetScreen( nullptr );
|
||||
|
||||
wxString ext = wxString( "." ) + FILEEXT::KiCadSchematicFileExtension;
|
||||
@ -3247,10 +3275,11 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
|
||||
m_view->ClearPreview();
|
||||
m_view->AddToPreview( sheet->Clone() );
|
||||
}
|
||||
else if( sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
|
||||
|| isSyntheticClick
|
||||
|| evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick )
|
||||
|| evt->IsAction( &ACTIONS::finishInteractive ) ) )
|
||||
else if( sheet && ( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT )
|
||||
|| isSyntheticClick
|
||||
|| evt->IsAction( &ACTIONS::cursorClick ) || evt->IsAction( &ACTIONS::cursorDblClick )
|
||||
|| evt->IsAction( &ACTIONS::finishInteractive )
|
||||
|| ( startedWithDrag && evt->IsMouseUp( BUT_LEFT ) ) ) )
|
||||
{
|
||||
getViewControls()->SetAutoPan( false );
|
||||
getViewControls()->CaptureCursor( false );
|
||||
@ -3320,7 +3349,8 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
|
||||
evt->SetPassEvent();
|
||||
break;
|
||||
}
|
||||
else if( sheet && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
|
||||
else if( sheet && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion()
|
||||
|| evt->IsDrag( BUT_LEFT ) ) )
|
||||
{
|
||||
sizeSheet( sheet, cursorPos );
|
||||
m_view->ClearPreview();
|
||||
|
@ -121,11 +121,16 @@ private:
|
||||
break; // We have used all IDs for these submenus
|
||||
}
|
||||
|
||||
if( !missingUnits.empty() )
|
||||
{
|
||||
AppendSeparator();
|
||||
|
||||
wxMenuItem* item = Add( SCH_ACTIONS::placeNextSymbolUnit );
|
||||
item->Enable( missingUnits.size() );
|
||||
for( int unitNumber : missingUnits )
|
||||
{
|
||||
wxString placeText = wxString::Format( _( "Place unit %s" ),
|
||||
symbol->GetUnitDisplayName( unitNumber, false ) );
|
||||
Append( ID_POPUP_SCH_PLACE_UNIT1 + unitNumber - 1, placeText );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -46,6 +46,9 @@
|
||||
#include <pgm_base.h>
|
||||
#include <view/view_controls.h>
|
||||
#include <settings/settings_manager.h>
|
||||
#include <math/box2.h>
|
||||
#include <base_units.h>
|
||||
#include <sch_screen.h>
|
||||
#include "sch_move_tool.h"
|
||||
|
||||
|
||||
@ -500,6 +503,7 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
|
||||
TOOL_EVENT* evt = ©
|
||||
VECTOR2I prevPos;
|
||||
GRID_HELPER_GRIDS snapLayer = GRID_CURRENT;
|
||||
SCH_SHEET* hoverSheet = nullptr;
|
||||
|
||||
m_cursor = controls->GetCursorPosition();
|
||||
|
||||
@ -771,7 +775,65 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
|
||||
|
||||
m_cursor = grid.BestSnapAnchor( controls->GetCursorPosition( false ),
|
||||
snapLayer, selection );
|
||||
// Determine potential target sheet.
|
||||
SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( m_frame->GetScreen()->GetItem( m_cursor, 0,
|
||||
SCH_SHEET_T ) );
|
||||
if( sheet && sheet->IsSelected() )
|
||||
sheet = nullptr; // Never target a selected sheet
|
||||
|
||||
if( !sheet )
|
||||
{
|
||||
// Build current selection bounding box in its (already moved) position.
|
||||
BOX2I selBBox;
|
||||
for( EDA_ITEM* it : selection )
|
||||
{
|
||||
if( SCH_ITEM* schIt = dynamic_cast<SCH_ITEM*>( it ) )
|
||||
selBBox.Merge( schIt->GetBoundingBox() );
|
||||
}
|
||||
|
||||
if( selBBox.GetWidth() > 0 && selBBox.GetHeight() > 0 )
|
||||
{
|
||||
VECTOR2I selCenter( selBBox.GetX() + selBBox.GetWidth() / 2,
|
||||
selBBox.GetY() + selBBox.GetHeight() / 2 );
|
||||
|
||||
// Find first non-selected sheet whose body fully contains the selection
|
||||
// or at least contains its center point.
|
||||
for( SCH_ITEM* it : m_frame->GetScreen()->Items().OfType( SCH_SHEET_T ) )
|
||||
{
|
||||
SCH_SHEET* candidate = static_cast<SCH_SHEET*>( it );
|
||||
if( candidate->IsSelected() || candidate->IsRootSheet() )
|
||||
continue;
|
||||
|
||||
BOX2I body = candidate->GetBodyBoundingBox();
|
||||
|
||||
if( body.Contains( selBBox ) || body.Contains( selCenter ) )
|
||||
{
|
||||
sheet = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( sheet != hoverSheet )
|
||||
{
|
||||
if( hoverSheet )
|
||||
{
|
||||
hoverSheet->ClearFlags( BRIGHTENED );
|
||||
m_frame->UpdateItem( hoverSheet, false );
|
||||
}
|
||||
|
||||
hoverSheet = sheet;
|
||||
|
||||
if( hoverSheet )
|
||||
{
|
||||
hoverSheet->SetFlags( BRIGHTENED );
|
||||
m_frame->UpdateItem( hoverSheet, false );
|
||||
}
|
||||
}
|
||||
|
||||
m_frame->GetCanvas()->SetCurrentCursor( hoverSheet ? KICURSOR::PLACE
|
||||
: KICURSOR::MOVING );
|
||||
VECTOR2I delta( m_cursor - prevPos );
|
||||
m_anchorPos = m_cursor;
|
||||
|
||||
@ -1032,6 +1094,22 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
|
||||
|
||||
} while( ( evt = Wait() ) ); //Should be assignment not equality test
|
||||
|
||||
SCH_SHEET* targetSheet = hoverSheet;
|
||||
|
||||
if( hoverSheet )
|
||||
{
|
||||
hoverSheet->ClearFlags( BRIGHTENED );
|
||||
m_frame->UpdateItem( hoverSheet, false );
|
||||
}
|
||||
|
||||
if( targetSheet )
|
||||
{
|
||||
moveSelectionToSheet( selection, targetSheet, aCommit );
|
||||
m_toolMgr->RunAction( ACTIONS::selectionClear );
|
||||
m_newDragLines.clear();
|
||||
m_changedDragLines.clear();
|
||||
}
|
||||
|
||||
// Create a selection of original selection, drag selected/changed items, and new
|
||||
// bend lines for later before we clear them in the aCommit. We'll need these
|
||||
// to check for new junctions needed, etc.
|
||||
@ -1135,6 +1213,60 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
|
||||
}
|
||||
|
||||
|
||||
void SCH_MOVE_TOOL::moveSelectionToSheet( SCH_SELECTION& aSelection, SCH_SHEET* aTargetSheet,
|
||||
SCH_COMMIT* aCommit )
|
||||
{
|
||||
SCH_SCREEN* destScreen = aTargetSheet->GetScreen();
|
||||
SCH_SCREEN* srcScreen = m_frame->GetScreen();
|
||||
|
||||
BOX2I bbox;
|
||||
|
||||
for( EDA_ITEM* item : aSelection )
|
||||
bbox.Merge( static_cast<SCH_ITEM*>( item )->GetBoundingBox() );
|
||||
|
||||
VECTOR2I offset = VECTOR2I( 0, 0 ) - bbox.GetPosition();
|
||||
int step = schIUScale.MilsToIU( 50 );
|
||||
bool overlap = false;
|
||||
|
||||
do
|
||||
{
|
||||
BOX2I moved = bbox;
|
||||
moved.Move( offset );
|
||||
overlap = false;
|
||||
|
||||
for( SCH_ITEM* existing : destScreen->Items() )
|
||||
{
|
||||
if( moved.Intersects( existing->GetBoundingBox() ) )
|
||||
{
|
||||
overlap = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( overlap )
|
||||
offset += VECTOR2I( step, step );
|
||||
} while( overlap );
|
||||
|
||||
for( EDA_ITEM* item : aSelection )
|
||||
{
|
||||
SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item );
|
||||
|
||||
// Remove from current screen and view manually
|
||||
m_frame->RemoveFromScreen( schItem, srcScreen );
|
||||
|
||||
// Move the item
|
||||
schItem->Move( offset );
|
||||
|
||||
// Add to destination screen manually (won't add to view since it's not current)
|
||||
destScreen->Append( schItem );
|
||||
|
||||
// Record in commit with CHT_DONE flag to bypass automatic screen/view operations
|
||||
aCommit->Stage( schItem, CHT_REMOVE | CHT_DONE, srcScreen );
|
||||
aCommit->Stage( schItem, CHT_ADD | CHT_DONE, destScreen );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_MOVE_TOOL::trimDanglingLines( SCH_COMMIT* aCommit )
|
||||
{
|
||||
// Need a local cleanup first to ensure we remove unneeded junctions
|
||||
@ -1163,8 +1295,7 @@ void SCH_MOVE_TOOL::trimDanglingLines( SCH_COMMIT* aCommit )
|
||||
{
|
||||
line->SetFlags( STRUCT_DELETED );
|
||||
aCommit->Removed( line, m_frame->GetScreen() );
|
||||
|
||||
updateItem( line, false );
|
||||
updateItem( line, false ); // Update any cached visuals before commit processes
|
||||
m_frame->RemoveFromScreen( line, m_frame->GetScreen() );
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,9 @@ class SCH_LINE;
|
||||
class SCH_LABEL_BASE;
|
||||
class SCH_SHEET_PIN;
|
||||
class SCH_JUNCTION;
|
||||
class SCH_SELECTION;
|
||||
class SCH_SHEET;
|
||||
class SCH_COMMIT;
|
||||
|
||||
|
||||
struct SPECIAL_CASE_LABEL_INFO
|
||||
@ -81,6 +84,8 @@ private:
|
||||
void orthoLineDrag( SCH_COMMIT* aCommit, SCH_LINE* line, const VECTOR2I& splitDelta,
|
||||
int& xBendCount, int& yBendCount, const EE_GRID_HELPER& grid );
|
||||
|
||||
void moveSelectionToSheet( SCH_SELECTION& aSelection, SCH_SHEET* aTarget, SCH_COMMIT* aCommit );
|
||||
|
||||
///< Clears the new drag lines and removes them from the screen
|
||||
void clearNewDragLines();
|
||||
|
||||
|
@ -787,6 +787,16 @@ int SCH_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
|
||||
if( symbol )
|
||||
static_cast<SCH_EDIT_FRAME*>( m_frame )->SelectUnit( symbol, unit );
|
||||
}
|
||||
else if( *evt->GetCommandId() >= ID_POPUP_SCH_PLACE_UNIT
|
||||
&& *evt->GetCommandId() <= ID_POPUP_SCH_PLACE_UNIT_END )
|
||||
{
|
||||
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( m_selection.Front() );
|
||||
int unit = *evt->GetCommandId() - ID_POPUP_SCH_PLACE_UNIT;
|
||||
|
||||
if( symbol )
|
||||
m_toolMgr->RunAction( SCH_ACTIONS::placeNextSymbolUnit,
|
||||
SCH_ACTIONS::PLACE_SYMBOL_UNIT_PARAMS{ symbol, unit } );
|
||||
}
|
||||
else if( *evt->GetCommandId() >= ID_POPUP_SCH_SELECT_BODY_STYLE
|
||||
&& *evt->GetCommandId() <= ID_POPUP_SCH_SELECT_BODY_STYLE_END )
|
||||
{
|
||||
|
@ -546,15 +546,36 @@ void HIERARCHY_PANE::onCharHook( wxKeyEvent& aKeyStroke )
|
||||
{
|
||||
int hotkey = aKeyStroke.GetKeyCode();
|
||||
|
||||
if( aKeyStroke.GetModifiers() & wxMOD_CONTROL )
|
||||
hotkey += MD_CTRL;
|
||||
int mods = aKeyStroke.GetModifiers();
|
||||
|
||||
if( aKeyStroke.GetModifiers() & wxMOD_ALT )
|
||||
hotkey += MD_ALT;
|
||||
// the flag wxMOD_ALTGR is defined in wxWidgets as wxMOD_CONTROL|wxMOD_ALT
|
||||
// So AltGr key cannot used as modifier key because it is the same as Alt key + Ctrl key.
|
||||
#if CAN_USE_ALTGR_KEY
|
||||
if( wxmods & wxMOD_ALTGR )
|
||||
mods |= MD_ALTGR;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if( mods & wxMOD_CONTROL )
|
||||
hotkey += MD_CTRL;
|
||||
|
||||
if( aKeyStroke.GetModifiers() & wxMOD_SHIFT )
|
||||
if( mods & wxMOD_ALT )
|
||||
hotkey += MD_ALT;
|
||||
}
|
||||
|
||||
if( mods & wxMOD_SHIFT )
|
||||
hotkey += MD_SHIFT;
|
||||
|
||||
#ifdef wxMOD_META
|
||||
if( mods & wxMOD_META )
|
||||
hotkey += MD_META;
|
||||
#endif
|
||||
|
||||
#ifdef wxMOD_WIN
|
||||
if( mods & wxMOD_WIN )
|
||||
hotkey += MD_SUPER;
|
||||
#endif
|
||||
|
||||
if( hotkey == ACTIONS::expandAll.GetHotKey()
|
||||
|| hotkey == ACTIONS::expandAll.GetHotKeyAlt() )
|
||||
{
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <schematic.h>
|
||||
#include <sch_symbol.h>
|
||||
#include <sch_field.h>
|
||||
#include <template_fieldnames.h>
|
||||
#include <settings/color_settings.h>
|
||||
#include <string_utils.h>
|
||||
#include <tool/tool_manager.h>
|
||||
@ -149,6 +150,32 @@ SCH_PROPERTIES_PANEL::SCH_PROPERTIES_PANEL( wxWindow* aParent, SCH_BASE_FRAME* a
|
||||
{
|
||||
m_colorEditorInstance = static_cast<PG_COLOR_EDITOR*>( it->second );
|
||||
}
|
||||
|
||||
it = wxPGGlobalVars->m_mapEditorClasses.find( PG_FPID_EDITOR::BuildEditorName( m_frame ) );
|
||||
|
||||
if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
|
||||
{
|
||||
m_fpEditorInstance = static_cast<PG_FPID_EDITOR*>( it->second );
|
||||
m_fpEditorInstance->UpdateFrame( m_frame );
|
||||
}
|
||||
else
|
||||
{
|
||||
PG_FPID_EDITOR* fpEditor = new PG_FPID_EDITOR( m_frame );
|
||||
m_fpEditorInstance = static_cast<PG_FPID_EDITOR*>( wxPropertyGrid::RegisterEditorClass( fpEditor ) );
|
||||
}
|
||||
|
||||
it = wxPGGlobalVars->m_mapEditorClasses.find( PG_URL_EDITOR::BuildEditorName( m_frame ) );
|
||||
|
||||
if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
|
||||
{
|
||||
m_urlEditorInstance = static_cast<PG_URL_EDITOR*>( it->second );
|
||||
m_urlEditorInstance->UpdateFrame( m_frame );
|
||||
}
|
||||
else
|
||||
{
|
||||
PG_URL_EDITOR* urlEditor = new PG_URL_EDITOR( m_frame );
|
||||
m_urlEditorInstance = static_cast<PG_URL_EDITOR*>( wxPropertyGrid::RegisterEditorClass( urlEditor ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -156,6 +183,8 @@ SCH_PROPERTIES_PANEL::SCH_PROPERTIES_PANEL( wxWindow* aParent, SCH_BASE_FRAME* a
|
||||
SCH_PROPERTIES_PANEL::~SCH_PROPERTIES_PANEL()
|
||||
{
|
||||
m_unitEditorInstance->UpdateFrame( nullptr );
|
||||
m_fpEditorInstance->UpdateFrame( nullptr );
|
||||
m_urlEditorInstance->UpdateFrame( nullptr );
|
||||
}
|
||||
|
||||
|
||||
@ -226,6 +255,11 @@ wxPGProperty* SCH_PROPERTIES_PANEL::createPGProperty( const PROPERTY_BASE* aProp
|
||||
colorProp->SetBackgroundColor( bg );
|
||||
}
|
||||
|
||||
if( aProperty->Name() == GetCanonicalFieldName( FIELD_T::FOOTPRINT ) )
|
||||
prop->SetEditor( PG_FPID_EDITOR::BuildEditorName( m_frame ) );
|
||||
else if( aProperty->Name() == GetCanonicalFieldName( FIELD_T::DATASHEET ) )
|
||||
prop->SetEditor( PG_URL_EDITOR::BuildEditorName( m_frame ) );
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,8 @@ class PROPERTY_MANAGER;
|
||||
class PG_UNIT_EDITOR;
|
||||
class PG_CHECKBOX_EDITOR;
|
||||
class PG_COLOR_EDITOR;
|
||||
class PG_FPID_EDITOR;
|
||||
class PG_URL_EDITOR;
|
||||
|
||||
class SCH_PROPERTIES_PANEL : public PROPERTIES_PANEL
|
||||
{
|
||||
@ -60,6 +62,8 @@ protected:
|
||||
PG_UNIT_EDITOR* m_unitEditorInstance;
|
||||
PG_CHECKBOX_EDITOR* m_checkboxEditorInstance;
|
||||
PG_COLOR_EDITOR* m_colorEditorInstance;
|
||||
PG_FPID_EDITOR* m_fpEditorInstance;
|
||||
PG_URL_EDITOR* m_urlEditorInstance;
|
||||
|
||||
static std::set<wxString> m_currentFieldNames;
|
||||
wxPGChoices m_nets;
|
||||
|
@ -671,8 +671,7 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int aCommand, char* aBuff,
|
||||
break;
|
||||
|
||||
case IMAGE_POLARITY:
|
||||
// These commands are deprecated since 2012.
|
||||
// So do nothing and prompt the user about this command
|
||||
// Note: these commands IPPOS and IPNEG are deprecated since 2012.
|
||||
if( strncasecmp( aText, "NEG", 3 ) == 0 )
|
||||
{
|
||||
m_ImageNegative = true;
|
||||
@ -688,7 +687,6 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int aCommand, char* aBuff,
|
||||
// actual effect. Just skip it.
|
||||
}
|
||||
|
||||
ok = false;
|
||||
break;
|
||||
|
||||
case LOAD_POLARITY:
|
||||
|
@ -306,14 +306,14 @@ public:
|
||||
*
|
||||
* @param aPos is the point to go to.
|
||||
*/
|
||||
void FocusOnLocation( const VECTOR2I& aPos );
|
||||
void FocusOnLocation( const VECTOR2I& aPos, bool aAllowScroll = true );
|
||||
|
||||
/**
|
||||
* Focus on a particular canvas item.
|
||||
*
|
||||
* @param aItem is the item to focus on. nullptr clears the focus.
|
||||
*/
|
||||
virtual void FocusOnItem( EDA_ITEM* aItem ) {}
|
||||
virtual void FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll = true ) {}
|
||||
|
||||
virtual void ClearFocus() { FocusOnItem( nullptr ); }
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "grid_tricks.h"
|
||||
#include <functional>
|
||||
|
||||
class LIB_TABLE_GRID_TRICKS : public GRID_TRICKS
|
||||
{
|
||||
@ -33,6 +34,7 @@ class LIB_TABLE_GRID_TRICKS : public GRID_TRICKS
|
||||
|
||||
public:
|
||||
explicit LIB_TABLE_GRID_TRICKS( WX_GRID* aGrid );
|
||||
LIB_TABLE_GRID_TRICKS( WX_GRID* aGrid, std::function<void( wxCommandEvent& )> aAddHandler );
|
||||
|
||||
virtual ~LIB_TABLE_GRID_TRICKS(){};
|
||||
|
||||
@ -43,5 +45,7 @@ protected:
|
||||
virtual void optionsEditor( int aRow ) = 0;
|
||||
bool handleDoubleClick( wxGridEvent& aEvent ) override;
|
||||
|
||||
void onCharHook( wxKeyEvent& ev );
|
||||
|
||||
virtual bool supportsVisibilityColumn() { return false; }
|
||||
};
|
||||
|
@ -220,9 +220,10 @@ public:
|
||||
|
||||
EDA_ITEM* ResolveItem( const KIID& aId, bool aAllowNullptrReturn = false ) const override;
|
||||
|
||||
void FocusOnItem( EDA_ITEM* aItem ) override;
|
||||
void FocusOnItem( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer = UNDEFINED_LAYER );
|
||||
void FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID aLayer = UNDEFINED_LAYER );
|
||||
void FocusOnItem( EDA_ITEM* aItem, bool aAllowScroll = true ) override;
|
||||
void FocusOnItem( BOARD_ITEM* aItem, PCB_LAYER_ID aLayer = UNDEFINED_LAYER, bool aAllowScroll = true );
|
||||
void FocusOnItems( std::vector<BOARD_ITEM*> aItems, PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
|
||||
bool aAllowScroll = true );
|
||||
|
||||
void HideSolderMask();
|
||||
void ShowSolderMask();
|
||||
|
@ -110,7 +110,7 @@ public:
|
||||
*/
|
||||
void BuildArgvUtf8();
|
||||
|
||||
BS::thread_pool& GetThreadPool() { return *m_singleton.m_ThreadPool; }
|
||||
BS::thread_pool<0>& GetThreadPool() { return *m_singleton.m_ThreadPool; }
|
||||
|
||||
GL_CONTEXT_MANAGER* GetGLContextManager() { return m_singleton.m_GLContextManager; }
|
||||
|
||||
|
@ -125,4 +125,58 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class PG_FPID_EDITOR : public wxPGTextCtrlEditor
|
||||
{
|
||||
public:
|
||||
static const wxString EDITOR_NAME;
|
||||
|
||||
PG_FPID_EDITOR( EDA_DRAW_FRAME* aFrame );
|
||||
|
||||
virtual ~PG_FPID_EDITOR() {}
|
||||
|
||||
wxString GetName() const override { return m_editorName; }
|
||||
|
||||
void UpdateFrame( EDA_DRAW_FRAME* aFrame );
|
||||
|
||||
static wxString BuildEditorName( EDA_DRAW_FRAME* aFrame );
|
||||
|
||||
wxPGWindowList CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty,
|
||||
const wxPoint& aPos, const wxSize& aSize ) const override;
|
||||
|
||||
bool OnEvent( wxPropertyGrid* aGrid, wxPGProperty* aProperty, wxWindow* aCtrl,
|
||||
wxEvent& aEvent ) const override;
|
||||
|
||||
private:
|
||||
EDA_DRAW_FRAME* m_frame;
|
||||
wxString m_editorName;
|
||||
};
|
||||
|
||||
|
||||
class PG_URL_EDITOR : public wxPGTextCtrlEditor
|
||||
{
|
||||
public:
|
||||
static const wxString EDITOR_NAME;
|
||||
|
||||
PG_URL_EDITOR( EDA_DRAW_FRAME* aFrame );
|
||||
|
||||
virtual ~PG_URL_EDITOR() {}
|
||||
|
||||
wxString GetName() const override { return m_editorName; }
|
||||
|
||||
void UpdateFrame( EDA_DRAW_FRAME* aFrame );
|
||||
|
||||
static wxString BuildEditorName( EDA_DRAW_FRAME* aFrame );
|
||||
|
||||
wxPGWindowList CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty,
|
||||
const wxPoint& aPos, const wxSize& aSize ) const override;
|
||||
|
||||
bool OnEvent( wxPropertyGrid* aGrid, wxPGProperty* aProperty, wxWindow* aCtrl,
|
||||
wxEvent& aEvent ) const override;
|
||||
|
||||
private:
|
||||
EDA_DRAW_FRAME* m_frame;
|
||||
wxString m_editorName;
|
||||
};
|
||||
|
||||
|
||||
#endif //KICAD_PG_EDITORS_H
|
||||
|
@ -25,6 +25,7 @@
|
||||
class GL_CONTEXT_MANAGER;
|
||||
namespace BS
|
||||
{
|
||||
template <std::uint8_t>
|
||||
class thread_pool;
|
||||
}
|
||||
|
||||
@ -42,7 +43,7 @@ public:
|
||||
void Init();
|
||||
|
||||
public:
|
||||
BS::thread_pool* m_ThreadPool;
|
||||
BS::thread_pool<0>* m_ThreadPool;
|
||||
GL_CONTEXT_MANAGER* m_GLContextManager;
|
||||
};
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <bs_thread_pool.hpp>
|
||||
#include <import_export.h>
|
||||
|
||||
using thread_pool = BS::thread_pool;
|
||||
using thread_pool = BS::thread_pool<0>;
|
||||
|
||||
/**
|
||||
* Get a reference to the current thread pool. N.B., you cannot copy the thread pool
|
||||
|
@ -84,22 +84,9 @@ private:
|
||||
/// Returns the instance of VIEW, used by the application.
|
||||
KIGFX::VIEW* getView();
|
||||
|
||||
/// Saves the state of key modifiers (Alt, Ctrl and so on).
|
||||
static int decodeModifiers( const wxKeyboardState* aState )
|
||||
{
|
||||
int mods = 0;
|
||||
|
||||
if( aState->ControlDown() )
|
||||
mods |= MD_CTRL;
|
||||
|
||||
if( aState->AltDown() )
|
||||
mods |= MD_ALT;
|
||||
|
||||
if( aState->ShiftDown() )
|
||||
mods |= MD_SHIFT;
|
||||
|
||||
return mods;
|
||||
}
|
||||
/// Returns the state of key modifiers (Alt, Ctrl and so on) as OR'ed list
|
||||
/// of bits (MD_CTRL, MD_ALT ...)
|
||||
static int decodeModifiers( const wxKeyboardState* aState );
|
||||
|
||||
private:
|
||||
/// The time threshold for a mouse button press that distinguishes between a single mouse
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user