Add "move exact" and "duplicate" tools to pcbnew
This commit is contained in:
parent
74e83e924a
commit
4f3672da4d
|
@ -217,6 +217,9 @@ set( BMAPS_MID
|
|||
drag_track_segment
|
||||
drc_off
|
||||
drc
|
||||
duplicate_line
|
||||
duplicate_pad
|
||||
duplicate_text
|
||||
edges_sketch
|
||||
edit_comp_footprint
|
||||
edit_component
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
/* Do not modify this file, it was automatically generated by the
|
||||
* PNG2cpp CMake script, using a *.png file as input.
|
||||
*/
|
||||
|
||||
#include <bitmaps.h>
|
||||
|
||||
static const unsigned char png[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
|
||||
0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1a, 0x08, 0x06, 0x00, 0x00, 0x00, 0xa9, 0x4a, 0x4c,
|
||||
0xce, 0x00, 0x00, 0x01, 0x41, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xed, 0x96, 0xb1, 0x4a, 0x03,
|
||||
0x41, 0x14, 0x45, 0xcf, 0xbc, 0x59, 0x0d, 0xc4, 0x08, 0xb1, 0x90, 0x4d, 0x0c, 0x6c, 0x61, 0xb0,
|
||||
0x88, 0xda, 0xa7, 0x16, 0x0b, 0xc1, 0xc2, 0x0f, 0xf0, 0x23, 0xfc, 0x06, 0xbb, 0x94, 0xd6, 0x62,
|
||||
0x21, 0x6c, 0x76, 0x9d, 0xd5, 0x14, 0x42, 0x2c, 0x2c, 0x44, 0x44, 0xd2, 0x07, 0x2b, 0x2d, 0x52,
|
||||
0x08, 0x62, 0x61, 0x11, 0x14, 0x4c, 0xc2, 0x82, 0x1a, 0xc7, 0x4f, 0x50, 0x21, 0x93, 0xc2, 0x58,
|
||||
0x9c, 0xfa, 0xf0, 0x86, 0xfb, 0xde, 0x1d, 0xac, 0xb5, 0x8c, 0x03, 0xc6, 0x2e, 0xe2, 0x00, 0xeb,
|
||||
0x82, 0x09, 0x10, 0x7d, 0xc7, 0x15, 0x78, 0x11, 0x6c, 0x1b, 0x58, 0x70, 0x1a, 0x86, 0x18, 0x96,
|
||||
0x62, 0xa5, 0xd2, 0x08, 0x6c, 0x22, 0x72, 0x1f, 0xc3, 0x86, 0xb3, 0xd4, 0x85, 0x50, 0x35, 0x4a,
|
||||
0xf5, 0xae, 0xf3, 0xf9, 0xcf, 0x86, 0xe7, 0xf5, 0x13, 0xad, 0xc3, 0x10, 0x66, 0x9c, 0xc4, 0x3b,
|
||||
0x84, 0x55, 0x23, 0xf2, 0xdc, 0xf6, 0xfd, 0xe1, 0x45, 0x2e, 0x97, 0x26, 0x4a, 0x35, 0x9d, 0xed,
|
||||
0x51, 0x02, 0x65, 0x23, 0xf2, 0xd4, 0xf6, 0xfd, 0x8f, 0xd3, 0xe9, 0xe9, 0xbe, 0x11, 0xd9, 0x71,
|
||||
0xb6, 0xb0, 0x47, 0xb0, 0x72, 0x2c, 0x32, 0x78, 0x58, 0x5c, 0xb4, 0x46, 0xa9, 0xc1, 0x09, 0xcc,
|
||||
0x3b, 0xbb, 0x0c, 0x89, 0xd6, 0x57, 0x37, 0x85, 0xc2, 0x67, 0x6b, 0x6e, 0x2e, 0x4d, 0x44, 0x6a,
|
||||
0xce, 0x44, 0x31, 0xac, 0x35, 0x3c, 0xaf, 0xff, 0x58, 0x2e, 0x5b, 0x23, 0xd2, 0x8b, 0x61, 0x33,
|
||||
0x82, 0xbd, 0x43, 0xc8, 0x8f, 0x54, 0x54, 0x87, 0x62, 0xac, 0x54, 0xf7, 0xb6, 0x54, 0xb2, 0x97,
|
||||
0xb3, 0xb3, 0x69, 0x22, 0xf2, 0x76, 0xac, 0x75, 0x6b, 0xa4, 0x13, 0x45, 0xb0, 0x1e, 0x43, 0xda,
|
||||
0xd0, 0xfa, 0xbd, 0x13, 0x04, 0xf6, 0xa5, 0x52, 0xb1, 0xcd, 0x4c, 0xe6, 0xb5, 0x0e, 0x5b, 0x23,
|
||||
0x7f, 0xba, 0x08, 0x96, 0x8d, 0xc8, 0xdd, 0x79, 0x36, 0xdb, 0xef, 0x04, 0x81, 0x35, 0x22, 0xdd,
|
||||
0x13, 0xd0, 0x4e, 0x6a, 0x62, 0x1f, 0xa6, 0x8e, 0x44, 0x6a, 0x11, 0x0c, 0x63, 0x91, 0x5d, 0xe7,
|
||||
0x7d, 0x14, 0x42, 0xb5, 0x0e, 0xc5, 0x9f, 0xf4, 0xd1, 0x99, 0x0b, 0x26, 0x40, 0xf4, 0xf7, 0x3e,
|
||||
0x27, 0xff, 0xa2, 0xdf, 0xf2, 0x05, 0x63, 0x00, 0xb0, 0xc1, 0xf1, 0xcc, 0x65, 0x5d, 0x00, 0x00,
|
||||
0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
|
||||
};
|
||||
|
||||
const BITMAP_OPAQUE duplicate_line_xpm[1] = {{ png, sizeof( png ), "duplicate_line_xpm" }};
|
||||
|
||||
//EOF
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
/* Do not modify this file, it was automatically generated by the
|
||||
* PNG2cpp CMake script, using a *.png file as input.
|
||||
*/
|
||||
|
||||
#include <bitmaps.h>
|
||||
|
||||
static const unsigned char png[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
|
||||
0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1a, 0x08, 0x06, 0x00, 0x00, 0x00, 0xa9, 0x4a, 0x4c,
|
||||
0xce, 0x00, 0x00, 0x02, 0x12, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xd5, 0x54, 0x4d, 0x48, 0x54,
|
||||
0x51, 0x18, 0x3d, 0xef, 0x4e, 0xf8, 0x83, 0x0c, 0x31, 0x9a, 0x1b, 0x45, 0x66, 0xd1, 0x6a, 0x60,
|
||||
0xda, 0xb6, 0x69, 0xe1, 0xaa, 0x89, 0x36, 0x41, 0x20, 0x41, 0xab, 0x20, 0xc6, 0xa5, 0xd0, 0xc2,
|
||||
0xad, 0x36, 0x69, 0x30, 0xd0, 0x66, 0x08, 0x5d, 0xd8, 0x22, 0x06, 0x52, 0xf3, 0xe9, 0x4a, 0x26,
|
||||
0xa9, 0x45, 0x42, 0x09, 0xea, 0xea, 0x6d, 0x24, 0x10, 0x8d, 0x76, 0x12, 0x21, 0x44, 0x8c, 0xe2,
|
||||
0x28, 0xa2, 0xf5, 0x3a, 0xdf, 0x7d, 0xdf, 0x44, 0x0c, 0x09, 0xce, 0xcc, 0xf3, 0x41, 0x8b, 0xc3,
|
||||
0x7d, 0xef, 0xfb, 0xee, 0x3d, 0xe7, 0x9e, 0xef, 0xbb, 0xf7, 0xc2, 0xf7, 0x7d, 0x44, 0x81, 0x9a,
|
||||
0x1f, 0x38, 0xc8, 0x21, 0x8b, 0x27, 0xf8, 0xc8, 0xb1, 0x6c, 0x11, 0x7c, 0x67, 0x25, 0x17, 0x8a,
|
||||
0x10, 0xc9, 0x7a, 0x88, 0x35, 0x62, 0x87, 0xf0, 0x88, 0x65, 0x85, 0xa7, 0x31, 0xc9, 0xf5, 0x34,
|
||||
0x25, 0xa4, 0x4e, 0x84, 0x68, 0x8b, 0x28, 0x9d, 0x81, 0x2d, 0x3b, 0xa7, 0x41, 0x67, 0x55, 0x37,
|
||||
0x59, 0xdd, 0x75, 0x09, 0x8f, 0xf1, 0x86, 0xe3, 0x06, 0xb1, 0xab, 0xd8, 0xd0, 0x98, 0x88, 0xed,
|
||||
0xc4, 0x46, 0x31, 0xf8, 0x0a, 0x48, 0xb9, 0xc0, 0xd5, 0x05, 0xe0, 0x72, 0x7d, 0x42, 0x41, 0x1f,
|
||||
0x3c, 0x25, 0x13, 0x91, 0x4f, 0x18, 0x43, 0xbf, 0x85, 0x7c, 0x33, 0x96, 0x18, 0xc6, 0xbb, 0xfb,
|
||||
0x37, 0x9c, 0xaf, 0x2f, 0x3b, 0xcc, 0xf1, 0x0c, 0x97, 0xb9, 0xc6, 0x1c, 0xbd, 0x76, 0x9c, 0xc3,
|
||||
0x69, 0xe0, 0x4e, 0x3d, 0x8e, 0xca, 0xda, 0x8f, 0x92, 0x75, 0x41, 0x81, 0x3f, 0x13, 0x02, 0xb1,
|
||||
0xdd, 0xf4, 0x03, 0xac, 0x3c, 0xef, 0x32, 0x07, 0xe3, 0x49, 0x73, 0xb2, 0x10, 0x8b, 0xad, 0xce,
|
||||
0x39, 0xce, 0xd1, 0x6a, 0x22, 0xf1, 0x6b, 0xde, 0x98, 0x43, 0x0a, 0x0f, 0x84, 0x26, 0xa4, 0x39,
|
||||
0x99, 0x53, 0x96, 0x38, 0xc9, 0xaf, 0xd1, 0x55, 0x65, 0xb3, 0xb7, 0x57, 0xdc, 0x7d, 0xfb, 0x00,
|
||||
0x5c, 0x0a, 0xa5, 0x74, 0x9a, 0xf3, 0x64, 0x6e, 0x75, 0x31, 0x05, 0x8a, 0x5e, 0x77, 0xf7, 0xcf,
|
||||
0xa5, 0xf6, 0xf6, 0x03, 0x0a, 0x0f, 0xb1, 0x8c, 0xf7, 0x38, 0xde, 0x0d, 0xe5, 0x30, 0xc8, 0xdc,
|
||||
0xea, 0x62, 0x92, 0x3e, 0x5c, 0x6c, 0x69, 0xd9, 0xfb, 0x92, 0x4c, 0xfa, 0xec, 0xd7, 0xa9, 0xf4,
|
||||
0x6e, 0x16, 0xb8, 0x1e, 0xda, 0xf1, 0x7e, 0x0b, 0xb4, 0x92, 0x74, 0x49, 0x88, 0x97, 0xe3, 0xf1,
|
||||
0xe3, 0x1f, 0xa9, 0x94, 0xbf, 0xdd, 0xd7, 0x27, 0x25, 0xfc, 0x1c, 0xfa, 0x85, 0x2d, 0x02, 0x6d,
|
||||
0x24, 0x7e, 0xc1, 0x83, 0x51, 0x11, 0x47, 0xef, 0xe3, 0xf1, 0x7d, 0x0a, 0x0f, 0x5e, 0xd8, 0x13,
|
||||
0xc4, 0xbe, 0xdc, 0x9c, 0x33, 0xe6, 0xfb, 0xac, 0xe3, 0x54, 0x78, 0xbf, 0x3a, 0xce, 0x25, 0x54,
|
||||
0xff, 0x6d, 0xb7, 0x1b, 0xcb, 0x5c, 0x79, 0x84, 0xc2, 0xed, 0x5b, 0x58, 0xe7, 0xb7, 0x4b, 0xe4,
|
||||
0x25, 0x56, 0xbb, 0xb1, 0xc6, 0x45, 0x72, 0xe8, 0x24, 0x9e, 0x11, 0x45, 0xa2, 0x40, 0x3c, 0x55,
|
||||
0x14, 0x34, 0x26, 0xb9, 0xce, 0xa6, 0x84, 0xd4, 0x89, 0x10, 0x4d, 0x61, 0x14, 0x23, 0xff, 0x84,
|
||||
0xe4, 0x64, 0x8e, 0x3a, 0x6b, 0xd4, 0x4d, 0xc6, 0xee, 0x5a, 0x08, 0x85, 0x36, 0x87, 0x09, 0x62,
|
||||
0x46, 0x31, 0x61, 0x63, 0x81, 0x98, 0x38, 0xcb, 0x34, 0x23, 0x94, 0xb7, 0x25, 0x0a, 0xc8, 0x44,
|
||||
0x64, 0x92, 0x48, 0x2b, 0x26, 0x6d, 0x2c, 0xc8, 0x49, 0x19, 0xf3, 0xcd, 0x08, 0xb9, 0xb6, 0x1f,
|
||||
0x01, 0x99, 0xb8, 0x48, 0xff, 0x95, 0x4b, 0xdb, 0x58, 0x90, 0x93, 0x9e, 0xb9, 0xff, 0x85, 0x50,
|
||||
0x64, 0xa5, 0x8b, 0xe8, 0x30, 0x44, 0x75, 0xbc, 0x23, 0xbb, 0xb0, 0xb5, 0x4f, 0x90, 0xf6, 0xcc,
|
||||
0xbd, 0x90, 0x27, 0xa8, 0x5e, 0xfc, 0x06, 0x78, 0x64, 0xb7, 0x0e, 0x00, 0x4c, 0xaa, 0xda, 0x00,
|
||||
0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
|
||||
};
|
||||
|
||||
const BITMAP_OPAQUE duplicate_pad_xpm[1] = {{ png, sizeof( png ), "duplicate_pad_xpm" }};
|
||||
|
||||
//EOF
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
/* Do not modify this file, it was automatically generated by the
|
||||
* PNG2cpp CMake script, using a *.png file as input.
|
||||
*/
|
||||
|
||||
#include <bitmaps.h>
|
||||
|
||||
static const unsigned char png[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
|
||||
0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1a, 0x08, 0x06, 0x00, 0x00, 0x00, 0xa9, 0x4a, 0x4c,
|
||||
0xce, 0x00, 0x00, 0x01, 0x6e, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0x63, 0xf8, 0xff, 0xff, 0x3f,
|
||||
0x03, 0x3d, 0x30, 0x84, 0x60, 0x98, 0xfd, 0x9f, 0x54, 0xbc, 0x98, 0x81, 0x41, 0x65, 0x19, 0x03,
|
||||
0x83, 0x3d, 0x90, 0xd6, 0x5f, 0xc5, 0xc0, 0xc0, 0x49, 0x75, 0x8b, 0x0c, 0x18, 0xf2, 0xfe, 0xb7,
|
||||
0x31, 0x29, 0xfd, 0x5f, 0x02, 0xd4, 0xba, 0x94, 0x81, 0xe1, 0xdf, 0x6a, 0x16, 0x96, 0xaf, 0x2b,
|
||||
0x98, 0x98, 0x6e, 0x00, 0x2d, 0x94, 0x24, 0xc5, 0xa2, 0x06, 0xb8, 0x04, 0x92, 0xe1, 0x48, 0x62,
|
||||
0x0d, 0x91, 0x4c, 0x5e, 0xff, 0x2b, 0x98, 0x0c, 0xfe, 0x03, 0x0d, 0x9f, 0xb1, 0x92, 0x89, 0xe9,
|
||||
0xd2, 0x2a, 0x16, 0x96, 0xef, 0x87, 0x05, 0x05, 0x7f, 0x2f, 0x63, 0x64, 0x7c, 0x39, 0x97, 0x81,
|
||||
0x81, 0x97, 0x18, 0x8b, 0x1a, 0x50, 0x24, 0xb0, 0x58, 0x04, 0xb3, 0x0c, 0x59, 0x0c, 0x68, 0xe1,
|
||||
0xb4, 0x7d, 0xfc, 0xfc, 0x5f, 0x77, 0xf3, 0xf0, 0x7c, 0x5d, 0xc6, 0xc4, 0x54, 0x8d, 0xd7, 0x22,
|
||||
0xac, 0x12, 0x38, 0x2c, 0x42, 0xc7, 0xc0, 0x20, 0xe4, 0x03, 0xfa, 0xe6, 0xfb, 0x3d, 0x05, 0x85,
|
||||
0xff, 0xcb, 0x99, 0x98, 0x3e, 0x02, 0x83, 0xd3, 0x0b, 0x28, 0xd6, 0x3f, 0x9f, 0x81, 0x41, 0x80,
|
||||
0xaa, 0x16, 0x81, 0xe2, 0x66, 0x39, 0x23, 0xe3, 0xb5, 0x2b, 0x52, 0x52, 0xff, 0xf7, 0xf2, 0xf2,
|
||||
0x7e, 0x03, 0xfa, 0xf0, 0xd7, 0x4a, 0x66, 0xe6, 0xc3, 0x54, 0xf5, 0x11, 0xd0, 0xe5, 0xce, 0x40,
|
||||
0x1f, 0x7c, 0x5f, 0xcd, 0xcc, 0xfc, 0xfb, 0x8e, 0xbc, 0xfc, 0xff, 0xf7, 0x9a, 0x9a, 0xff, 0x37,
|
||||
0xb1, 0xb3, 0x7f, 0x02, 0x5a, 0xee, 0x47, 0x8b, 0xa0, 0xd3, 0x02, 0x06, 0xd9, 0xf5, 0xed, 0x5c,
|
||||
0x5c, 0x5f, 0x6e, 0xcb, 0xc9, 0x81, 0x82, 0xef, 0x0d, 0x30, 0xb9, 0x33, 0x53, 0xdd, 0x22, 0x10,
|
||||
0x9e, 0xc9, 0xc0, 0xc0, 0x0a, 0x4c, 0x08, 0xed, 0x40, 0x4b, 0xff, 0x2e, 0x65, 0x62, 0x6a, 0xa0,
|
||||
0x49, 0x62, 0x40, 0xc6, 0x8b, 0x18, 0x18, 0xcc, 0x71, 0xe5, 0x27, 0x92, 0x2d, 0x02, 0xf2, 0x37,
|
||||
0x93, 0x8a, 0x07, 0xd6, 0x22, 0xa0, 0x84, 0x03, 0x10, 0x1f, 0x40, 0x2b, 0x7a, 0x40, 0x7c, 0x07,
|
||||
0x54, 0x8b, 0xe6, 0x44, 0x61, 0xb3, 0x1c, 0x21, 0x36, 0x27, 0x8a, 0x90, 0x45, 0x38, 0xcb, 0x39,
|
||||
0x84, 0xa1, 0x08, 0x4b, 0x70, 0x59, 0x84, 0x6c, 0x19, 0xde, 0xa0, 0x23, 0xa9, 0x0a, 0xc0, 0x61,
|
||||
0x11, 0x51, 0x89, 0x61, 0xd4, 0xa2, 0x51, 0x8b, 0x46, 0xb8, 0x45, 0x0c, 0x0c, 0x33, 0x75, 0x81,
|
||||
0x86, 0xb7, 0xa3, 0x15, 0x39, 0xed, 0x20, 0x71, 0x2a, 0x5b, 0x84, 0xbf, 0x7c, 0xa3, 0x7a, 0xd0,
|
||||
0x11, 0x83, 0x01, 0xfa, 0xc4, 0x94, 0x7d, 0x09, 0xb7, 0x71, 0x10, 0x00, 0x00, 0x00, 0x00, 0x49,
|
||||
0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
|
||||
};
|
||||
|
||||
const BITMAP_OPAQUE duplicate_text_xpm[1] = {{ png, sizeof( png ), "duplicate_text_xpm" }};
|
||||
|
||||
//EOF
|
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="26"
|
||||
width="26"
|
||||
version="1.1"
|
||||
id="svg18970"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="duplicate_line.svg">
|
||||
<metadata
|
||||
id="metadata18987">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="996"
|
||||
id="namedview18985"
|
||||
showgrid="false"
|
||||
inkscape:zoom="16"
|
||||
inkscape:cx="21.793817"
|
||||
inkscape:cy="19.733911"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg18970"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:object-nodes="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3029"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs18972" />
|
||||
<g
|
||||
id="g18103"
|
||||
transform="matrix(0.92021476,-0.39141384,0.39141384,0.92021476,-3.5098229,-2.4696189)">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 14.365778,23.401859 c 0.202438,-4.960549 -0.864872,-7.852869 -4.328751,-9.928645 2.506618,4.326299 2.740146,6.262366 2.389978,9.710201 l -1.626346,-0.20242 2.198044,3.513613 2.945419,-2.915713 z"
|
||||
style="fill:#ef2929;fill-opacity:1;stroke:#a40000;stroke-width:1"
|
||||
id="path17320" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.92443,0,0,1,54.5375,-34.419499)"
|
||||
id="g18878">
|
||||
<rect
|
||||
width="23.798449"
|
||||
height="3.0000014"
|
||||
ry="0"
|
||||
x="-56.832317"
|
||||
y="36.419498"
|
||||
id="rect18882"
|
||||
style="fill:#009b00" />
|
||||
</g>
|
||||
<g
|
||||
id="g3096"
|
||||
transform="matrix(0.92443,0,0,1,54.5375,-18.419498)"
|
||||
style="opacity:0.7">
|
||||
<rect
|
||||
style="fill:#009b00"
|
||||
id="rect3098"
|
||||
y="36.419498"
|
||||
x="-56.832317"
|
||||
ry="0"
|
||||
height="3.0000014"
|
||||
width="23.798449" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="26"
|
||||
height="26"
|
||||
id="svg8431"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="duplicate_pad.svg">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="640"
|
||||
inkscape:window-height="480"
|
||||
id="namedview3013"
|
||||
showgrid="false"
|
||||
inkscape:zoom="9.0769231"
|
||||
inkscape:cx="13"
|
||||
inkscape:cy="12.173729"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg8431" />
|
||||
<metadata
|
||||
id="metadata8454">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8433" />
|
||||
<path
|
||||
d="m 7.0000002,1.4999999 c -3.0387414,0 -5.5000003,2.4612576 -5.5000003,5.4999999 C 1.4999999,10.038741 3.9612588,12.5 7.0000002,12.5 10.038743,12.5 12.5,10.038741 12.5,6.9999998 12.5,3.9612575 10.038743,1.4999999 7.0000002,1.4999999 z m 0,3.0000001 C 8.354733,4.5 9.5,5.6452668 9.5,7 9.5,8.3547332 8.354733,9.5 7.0000002,9.5 5.6452663,9.5 4.5,8.354733 4.5,6.9999998 4.5,5.6452666 5.6452663,4.5 7.0000002,4.5 z"
|
||||
id="path3763"
|
||||
style="fill:#008000;fill-opacity:0.69803922;stroke:#008000;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<use
|
||||
transform="translate(12,12)"
|
||||
id="use3206"
|
||||
style="opacity:0.7"
|
||||
x="0"
|
||||
y="0"
|
||||
width="26"
|
||||
height="26"
|
||||
xlink:href="#path3763" />
|
||||
<path
|
||||
d="M 18.334055,9.5305414 C 16.578714,4.886534 14.749271,4.2773887 10.82266,6.330495 c 4.402043,-0.7545299 4.614505,0.4480843 5.641806,3.757893 l -1.575818,0.450305 3.397949,2.372933 1.569168,-3.8359591 z"
|
||||
id="path17320"
|
||||
style="fill:#ef2929;fill-opacity:1;stroke:#a40000;stroke-width:1" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,90 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="26"
|
||||
width="26"
|
||||
version="1.1"
|
||||
id="svg18970"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="duplicate_text.svg">
|
||||
<metadata
|
||||
id="metadata18987">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="996"
|
||||
id="namedview18985"
|
||||
showgrid="false"
|
||||
inkscape:zoom="16"
|
||||
inkscape:cx="13.659451"
|
||||
inkscape:cy="12.783886"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g18103"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:object-nodes="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3029"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs18972" />
|
||||
<g
|
||||
style="fill-rule:evenodd"
|
||||
transform="matrix(1.1098933,0,0,1.075965,-25.392974,-45.041873)"
|
||||
id="g19009">
|
||||
<path
|
||||
style="fill:#00009b"
|
||||
d="M 1 1 L 1 5 L 2 5 L 4 3 L 6 3 L 6 13 L 4 14 L 4 15 L 7 15 L 8 15 L 11 15 L 11 14 L 9 13 L 9 3 L 11 3 L 13 5 L 14 5 L 14 1 L 8 1 L 7 1 L 1 1 z "
|
||||
transform="matrix(0.90098751,0,0,0.92939826,22.878752,41.861838)"
|
||||
id="path19013" />
|
||||
</g>
|
||||
<g
|
||||
id="g18103"
|
||||
transform="matrix(0.92021476,-0.39141384,0.39141384,0.92021476,-2.5098229,-9.469619)">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 14.365778,23.401859 c 0.202438,-4.960549 -1.242615,-6.237163 -5.6595543,-5.884794 4.3461583,1.028691 4.0709493,2.218515 3.7207813,5.66635 l -1.626346,-0.20242 2.198044,3.513613 2.945419,-2.915713 z"
|
||||
style="fill:#ef2929;fill-opacity:1;stroke:#a40000;stroke-width:1"
|
||||
id="path17320" />
|
||||
</g>
|
||||
<use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#g19009"
|
||||
id="use3037"
|
||||
transform="translate(11,10)"
|
||||
width="26"
|
||||
height="26"
|
||||
style="opacity:0.7" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
|
@ -97,6 +97,9 @@ double To_User_Unit( EDA_UNITS_T aUnit, double aValue )
|
|||
case INCHES:
|
||||
return IU_TO_IN( aValue );
|
||||
|
||||
case DEGREES:
|
||||
return aValue / 10.0f;
|
||||
|
||||
default:
|
||||
return aValue;
|
||||
}
|
||||
|
@ -246,6 +249,10 @@ wxString StringFromValue( EDA_UNITS_T aUnit, int aValue, bool aAddUnitSymbol )
|
|||
stringValue += _( " mm" );
|
||||
break;
|
||||
|
||||
case DEGREES:
|
||||
stringValue += _( " deg" );
|
||||
break;
|
||||
|
||||
case UNSCALED_UNITS:
|
||||
break;
|
||||
}
|
||||
|
@ -277,6 +284,11 @@ double From_User_Unit( EDA_UNITS_T aUnit, double aValue )
|
|||
value = IN_TO_IU( aValue );
|
||||
break;
|
||||
|
||||
case DEGREES:
|
||||
// Convert to "decidegrees"
|
||||
value = aValue * 10;
|
||||
break;
|
||||
|
||||
default:
|
||||
case UNSCALED_UNITS:
|
||||
value = aValue;
|
||||
|
@ -286,7 +298,7 @@ double From_User_Unit( EDA_UNITS_T aUnit, double aValue )
|
|||
}
|
||||
|
||||
|
||||
int ValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue )
|
||||
double DoubleValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue )
|
||||
{
|
||||
double value;
|
||||
double dtmp = 0;
|
||||
|
@ -328,22 +340,39 @@ int ValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue )
|
|||
// Check the optional unit designator (2 ch significant)
|
||||
wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
|
||||
|
||||
if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
|
||||
if( aUnits == INCHES || aUnits == MILLIMETRES )
|
||||
{
|
||||
aUnits = INCHES;
|
||||
if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
|
||||
{
|
||||
aUnits = INCHES;
|
||||
}
|
||||
else if( unit == wxT( "mm" ) )
|
||||
{
|
||||
aUnits = MILLIMETRES;
|
||||
}
|
||||
else if( unit == wxT( "mi" ) || unit == wxT( "th" ) ) // Mils or thous
|
||||
{
|
||||
aUnits = INCHES;
|
||||
dtmp /= 1000;
|
||||
}
|
||||
}
|
||||
else if( unit == wxT( "mm" ) )
|
||||
else if( aUnits == DEGREES )
|
||||
{
|
||||
aUnits = MILLIMETRES;
|
||||
}
|
||||
else if( unit == wxT( "mi" ) || unit == wxT( "th" ) ) // Mils or thous
|
||||
{
|
||||
aUnits = INCHES;
|
||||
dtmp /= 1000;
|
||||
if( unit == wxT( "ra" ) ) // Radians
|
||||
{
|
||||
dtmp *= 180.0f / M_PI;
|
||||
}
|
||||
}
|
||||
|
||||
value = From_User_Unit( aUnits, dtmp );
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
int ValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue )
|
||||
{
|
||||
double value = DoubleValueFromString( aUnits, aTextValue );
|
||||
return KiROUND( value );
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ void BLOCK_SELECTOR::SetMessageBlock( EDA_DRAW_FRAME* frame )
|
|||
|
||||
case BLOCK_MOVE: // Move
|
||||
case BLOCK_PRESELECT_MOVE: // Move with preselection list
|
||||
case BLOCK_MOVE_EXACT:
|
||||
msg = _( "Block Move" );
|
||||
break;
|
||||
|
||||
|
|
|
@ -144,6 +144,10 @@ wxString ReturnUnitSymbol( EDA_UNITS_T aUnit, const wxString& formatString )
|
|||
tmp = _( "mm" );
|
||||
break;
|
||||
|
||||
case DEGREES:
|
||||
label = _( "\u00b0" ); // Ring symbol
|
||||
break;
|
||||
|
||||
case UNSCALED_UNITS:
|
||||
break;
|
||||
}
|
||||
|
@ -171,6 +175,10 @@ wxString GetUnitsLabel( EDA_UNITS_T aUnit )
|
|||
label = _( "millimeters" );
|
||||
break;
|
||||
|
||||
case DEGREES:
|
||||
label = _( "degrees" );
|
||||
break;
|
||||
|
||||
case UNSCALED_UNITS:
|
||||
label = _( "units" );
|
||||
break;
|
||||
|
@ -194,6 +202,10 @@ wxString GetAbbreviatedUnitsLabel( EDA_UNITS_T aUnit )
|
|||
label = _( "mm" );
|
||||
break;
|
||||
|
||||
case DEGREES:
|
||||
label = _( "deg" );
|
||||
break;
|
||||
|
||||
case UNSCALED_UNITS:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -195,7 +195,8 @@ private:
|
|||
|
||||
|
||||
TOOL_MANAGER::TOOL_MANAGER() :
|
||||
m_model( NULL ), m_view( NULL ), m_viewControls( NULL ), m_editFrame( NULL )
|
||||
m_model( NULL ), m_view( NULL ), m_viewControls( NULL ), m_editFrame( NULL ),
|
||||
m_undoInhibit( false )
|
||||
{
|
||||
m_actionMgr = new ACTION_MANAGER( this );
|
||||
|
||||
|
@ -713,3 +714,23 @@ bool TOOL_MANAGER::isActive( TOOL_BASE* aTool )
|
|||
// Just check if the tool is on the active tools stack
|
||||
return std::find( m_activeTools.begin(), m_activeTools.end(), aTool->GetId() ) != m_activeTools.end();
|
||||
}
|
||||
|
||||
|
||||
void TOOL_MANAGER::IncUndoInhibit()
|
||||
{
|
||||
m_undoInhibit++;
|
||||
}
|
||||
|
||||
|
||||
void TOOL_MANAGER::DecUndoInhibit()
|
||||
{
|
||||
m_undoInhibit--;
|
||||
|
||||
wxASSERT_MSG( m_undoInhibit >= 0, wxT( "Undo inhibit count decremented past zero" ) );
|
||||
}
|
||||
|
||||
|
||||
bool TOOL_MANAGER::IsUndoInhibited() const
|
||||
{
|
||||
return m_undoInhibit > 0;
|
||||
}
|
||||
|
|
|
@ -197,6 +197,9 @@ bool LIB_EDIT_FRAME::HandleBlockEnd( wxDC* DC )
|
|||
|
||||
case BLOCK_SELECT_ITEMS_ONLY:
|
||||
break;
|
||||
|
||||
case BLOCK_MOVE_EXACT:
|
||||
break;
|
||||
}
|
||||
|
||||
if( !nextCmd )
|
||||
|
|
|
@ -156,6 +156,11 @@ void SCH_BASE_FRAME::UpdateStatusBar()
|
|||
locformatter = wxT( "dx %.2f dy %.2f d %.2f" );
|
||||
break;
|
||||
|
||||
// Not a length unit, shouldn't be possible in g_UserUnit?
|
||||
case DEGREES:
|
||||
wxASSERT_MSG( false, wxT( "Not a length unit: " + g_UserUnit ) );
|
||||
// no break
|
||||
|
||||
case UNSCALED_UNITS:
|
||||
absformatter = wxT( "X %f Y %f" );
|
||||
locformatter = wxT( "dx %f dy %f d %f" );
|
||||
|
|
|
@ -843,6 +843,10 @@ void GERBVIEW_FRAME::UpdateStatusBar()
|
|||
formatter = wxT( "Ro %.5f Th %.1f" );
|
||||
break;
|
||||
|
||||
case DEGREES:
|
||||
wxASSERT_MSG( false, wxT( "Not a length unit " + g_UserUnit ) );
|
||||
// no break
|
||||
|
||||
case UNSCALED_UNITS:
|
||||
formatter = wxT( "Ro %f Th %f" );
|
||||
break;
|
||||
|
@ -871,6 +875,10 @@ void GERBVIEW_FRAME::UpdateStatusBar()
|
|||
locformatter = wxT( "dx %.5f dy %.5f dist %.3f" );
|
||||
break;
|
||||
|
||||
case DEGREES:
|
||||
wxASSERT_MSG( false, wxT( "Not a length unit " + g_UserUnit ) );
|
||||
// no break
|
||||
|
||||
case UNSCALED_UNITS:
|
||||
absformatter = wxT( "X %f Y %f" );
|
||||
locformatter = wxT( "dx %f dy %f d %f" );
|
||||
|
|
|
@ -148,10 +148,21 @@ wxString& operator <<( wxString& aString, const wxPoint& aPoint );
|
|||
void PutValueInLocalUnits( wxTextCtrl& aTextCtr, int aValue );
|
||||
|
||||
/**
|
||||
* Return in internal units the value "val" given in inch or mm
|
||||
* Return in internal units the value "val" given in a real unit
|
||||
* such as "in", "mm" or "deg"
|
||||
*/
|
||||
double From_User_Unit( EDA_UNITS_T aUnit, double aValue );
|
||||
|
||||
|
||||
/**
|
||||
* Function DoubleValueFromString
|
||||
* converts \a aTextValue to a double
|
||||
* @param aUnits The units of \a aTextValue.
|
||||
* @param aTextValue A reference to a wxString object containing the string to convert.
|
||||
* @return A double representing that value in internal units
|
||||
*/
|
||||
double DoubleValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue );
|
||||
|
||||
/**
|
||||
* Function ValueFromString
|
||||
* converts \a aTextValue in \a aUnits to internal units used by the application.
|
||||
|
|
|
@ -174,6 +174,9 @@ EXTERN_BITMAP( drag_segment_withslope_xpm )
|
|||
EXTERN_BITMAP( drag_track_segment_xpm )
|
||||
EXTERN_BITMAP( drc_off_xpm )
|
||||
EXTERN_BITMAP( drc_xpm )
|
||||
EXTERN_BITMAP( duplicate_line_xpm )
|
||||
EXTERN_BITMAP( duplicate_pad_xpm )
|
||||
EXTERN_BITMAP( duplicate_text_xpm )
|
||||
EXTERN_BITMAP( edges_sketch_xpm )
|
||||
EXTERN_BITMAP( edit_comp_footprint_xpm )
|
||||
EXTERN_BITMAP( edit_component_xpm )
|
||||
|
|
|
@ -62,6 +62,7 @@ typedef enum {
|
|||
BLOCK_ZOOM,
|
||||
BLOCK_ABORT,
|
||||
BLOCK_PRESELECT_MOVE,
|
||||
BLOCK_MOVE_EXACT,
|
||||
BLOCK_SELECT_ITEMS_ONLY,
|
||||
BLOCK_MIRROR_X,
|
||||
BLOCK_MIRROR_Y
|
||||
|
|
|
@ -89,6 +89,16 @@ public:
|
|||
|
||||
virtual const wxPoint& GetPosition() const = 0;
|
||||
|
||||
/**
|
||||
* Function GetCenter()
|
||||
*
|
||||
* This defaults to the same point as returned by GetPosition(), unless
|
||||
* overridden
|
||||
*
|
||||
* @return centre point of the item
|
||||
*/
|
||||
virtual const wxPoint GetCenter() const { return GetPosition(); }
|
||||
|
||||
virtual void SetPosition( const wxPoint& aPos ) = 0;
|
||||
|
||||
/**
|
||||
|
|
|
@ -166,7 +166,8 @@ inline int Mils2mm( double x ) { return KiROUND( x * 25.4 / 1000. ); }
|
|||
enum EDA_UNITS_T {
|
||||
INCHES = 0,
|
||||
MILLIMETRES = 1,
|
||||
UNSCALED_UNITS = 2
|
||||
UNSCALED_UNITS = 2,
|
||||
DEGREES = 3,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -158,6 +158,7 @@ enum main_id
|
|||
ID_POPUP_CANCEL_CURRENT_COMMAND,
|
||||
ID_POPUP_CLOSE_CURRENT_TOOL,
|
||||
ID_POPUP_MOVE_BLOCK,
|
||||
ID_POPUP_MOVE_BLOCK_EXACT,
|
||||
ID_POPUP_DRAG_BLOCK,
|
||||
ID_POPUP_COPY_BLOCK,
|
||||
ID_POPUP_ROTATE_BLOCK,
|
||||
|
|
|
@ -301,6 +301,29 @@ public:
|
|||
return actionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the undo inhibit counter. This will indicate that tools
|
||||
* should not create an undo point, as another tool is doing it already,
|
||||
* and considers that its operation is atomic, even if it calls another one
|
||||
* (for example a duplicate calls a move)
|
||||
*/
|
||||
void IncUndoInhibit();
|
||||
|
||||
/**
|
||||
* Decrements the inhibit counter. An assert is raised if the counter drops
|
||||
* below zero
|
||||
*/
|
||||
void DecUndoInhibit();
|
||||
|
||||
/**
|
||||
* Report if the tool manager has been told at least once that undo
|
||||
* points should not be created. This can be ignored if the undo point
|
||||
* is still required.
|
||||
*
|
||||
* @return true if undo are inhibited
|
||||
*/
|
||||
bool IsUndoInhibited() const;
|
||||
|
||||
private:
|
||||
struct TOOL_STATE;
|
||||
typedef std::pair<TOOL_EVENT_LIST, TOOL_STATE_FUNC> TRANSITION;
|
||||
|
@ -428,6 +451,9 @@ private:
|
|||
|
||||
/// Flag saying if the currently processed event should be passed to other tools.
|
||||
bool m_passEvent;
|
||||
|
||||
/// Counter of undo inhibitions. When zero, undo is not inhibited
|
||||
int m_undoInhibit;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -471,6 +471,10 @@ void PL_EDITOR_FRAME::UpdateStatusBar()
|
|||
SetStatusText( _("mm"), 5 );
|
||||
break;
|
||||
|
||||
case DEGREES:
|
||||
wxASSERT_MSG( false, wxT( "Not a length unit: " + g_UserUnit ) );
|
||||
// no break
|
||||
|
||||
case UNSCALED_UNITS:
|
||||
SetStatusText( wxEmptyString, 5 );
|
||||
break;
|
||||
|
|
|
@ -104,6 +104,8 @@ set( PCBNEW_DIALOGS
|
|||
dialogs/dialog_pcb_text_properties_base.cpp
|
||||
dialogs/dialog_pns_settings.cpp
|
||||
dialogs/dialog_pns_settings_base.cpp
|
||||
dialogs/dialog_move_exact.cpp
|
||||
dialogs/dialog_move_exact_base.cpp
|
||||
dialogs/dialog_non_copper_zones_properties.cpp
|
||||
dialogs/dialog_non_copper_zones_properties_base.cpp
|
||||
dialogs/dialog_pad_properties.cpp
|
||||
|
|
|
@ -607,6 +607,7 @@ GENERAL_COLLECTORS_GUIDE PCB_BASE_FRAME::GetCollectorsGuide()
|
|||
return guide;
|
||||
}
|
||||
|
||||
|
||||
void PCB_BASE_FRAME::SetToolID( int aId, int aCursor, const wxString& aToolMsg )
|
||||
{
|
||||
bool redraw = false;
|
||||
|
@ -674,6 +675,10 @@ void PCB_BASE_FRAME::UpdateStatusBar()
|
|||
formatter = wxT( "Ro %.6f Th %.1f" );
|
||||
break;
|
||||
|
||||
case DEGREES:
|
||||
wxASSERT_MSG( false, wxT( "Not a length unit " + g_UserUnit ) );
|
||||
// no break
|
||||
|
||||
case UNSCALED_UNITS:
|
||||
formatter = wxT( "Ro %f Th %f" );
|
||||
break;
|
||||
|
@ -703,6 +708,10 @@ void PCB_BASE_FRAME::UpdateStatusBar()
|
|||
locformatter = wxT( "dx %.6f dy %.6f dist %.3f" );
|
||||
break;
|
||||
|
||||
case DEGREES: // not a length unit, shouldn't be possible in g_UserUnit?
|
||||
wxASSERT_MSG( false, wxT( "Not a length unit: " + g_UserUnit ) );
|
||||
//no break;
|
||||
|
||||
case UNSCALED_UNITS:
|
||||
absformatter = wxT( "X %f Y %f" );
|
||||
locformatter = wxT( "dx %f dy %f dist %f" );
|
||||
|
@ -804,6 +813,7 @@ void PCB_BASE_FRAME::updateGridSelectBox()
|
|||
|
||||
// Update grid values with the current units setting.
|
||||
m_gridSelectBox->Clear();
|
||||
|
||||
wxArrayString gridsList;
|
||||
int icurr = GetScreen()->BuildGridsChoiceList( gridsList, g_UserUnit != INCHES );
|
||||
|
||||
|
|
|
@ -53,14 +53,19 @@
|
|||
#include <class_dimension.h>
|
||||
#include <class_edge_mod.h>
|
||||
|
||||
#include <dialogs/dialog_move_exact.h>
|
||||
|
||||
|
||||
#define BLOCK_COLOR BROWN
|
||||
|
||||
// Functions defined here, but used also in other files
|
||||
// These 2 functions are used in modedit to rotate or mirror the whole footprint
|
||||
// so they are called with force_all = true
|
||||
// These 3 functions are used in modedit to rotate, mirror or move the
|
||||
// whole footprint so they are called with force_all = true
|
||||
void MirrorMarkedItems( MODULE* module, wxPoint offset, bool force_all = false );
|
||||
void RotateMarkedItems( MODULE* module, wxPoint offset, bool force_all = false );
|
||||
void MoveMarkedItemsExactly( MODULE* module, const wxPoint& centre,
|
||||
const wxPoint& translation, double rotation,
|
||||
bool force_all = false );
|
||||
|
||||
// Local functions:
|
||||
static void DrawMovingBlockOutlines( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
|
||||
|
@ -166,6 +171,26 @@ bool FOOTPRINT_EDIT_FRAME::HandleBlockEnd( wxDC* DC )
|
|||
|
||||
break;
|
||||
|
||||
case BLOCK_MOVE_EXACT:
|
||||
itemsCount = MarkItemsInBloc( currentModule, GetScreen()->m_BlockLocate );
|
||||
|
||||
if( itemsCount )
|
||||
{
|
||||
wxPoint translation;
|
||||
double rotation = 0;
|
||||
|
||||
DIALOG_MOVE_EXACT dialog( this, translation, rotation );
|
||||
int ret = dialog.ShowModal();
|
||||
|
||||
if( ret == DIALOG_MOVE_EXACT::MOVE_OK )
|
||||
{
|
||||
SaveCopyInUndoList( currentModule, UR_MODEDIT );
|
||||
const wxPoint blockCentre = GetScreen()->m_BlockLocate.Centre();
|
||||
MoveMarkedItemsExactly( currentModule, blockCentre, translation, rotation );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BLOCK_PRESELECT_MOVE: // Move with preselection list
|
||||
nextcmd = true;
|
||||
m_canvas->SetMouseCaptureCallback( DrawMovingBlockOutlines );
|
||||
|
@ -194,7 +219,6 @@ bool FOOTPRINT_EDIT_FRAME::HandleBlockEnd( wxDC* DC )
|
|||
RotateMarkedItems( currentModule, GetScreen()->m_BlockLocate.Centre() );
|
||||
break;
|
||||
|
||||
|
||||
case BLOCK_MIRROR_X:
|
||||
case BLOCK_MIRROR_Y:
|
||||
case BLOCK_FLIP: // mirror
|
||||
|
@ -706,6 +730,78 @@ void ClearMarkItems( MODULE* module )
|
|||
}
|
||||
|
||||
|
||||
void MoveMarkedItemsExactly( MODULE* module, const wxPoint& centre,
|
||||
const wxPoint& translation,
|
||||
double rotation, bool force_all )
|
||||
{
|
||||
if( module == NULL )
|
||||
return;
|
||||
|
||||
if( module->Reference().IsSelected() || force_all )
|
||||
{
|
||||
module->Reference().RotateTransformWithModule( centre, rotation );
|
||||
module->Reference().MoveTransformWithModule( translation );
|
||||
}
|
||||
|
||||
if( module->Value().IsSelected() || force_all )
|
||||
{
|
||||
module->Value().RotateTransformWithModule( centre, rotation );
|
||||
module->Value().MoveTransformWithModule( translation );
|
||||
}
|
||||
|
||||
D_PAD* pad = module->Pads();
|
||||
|
||||
for( ; pad != NULL; pad = pad->Next() )
|
||||
{
|
||||
if( !pad->IsSelected() && !force_all )
|
||||
continue;
|
||||
|
||||
// rotate about centre point,
|
||||
wxPoint newPos = pad->GetPosition();
|
||||
RotatePoint( &newPos, centre, rotation );
|
||||
|
||||
// shift and update
|
||||
newPos += translation;
|
||||
pad->SetPosition( newPos );
|
||||
pad->SetPos0( newPos );
|
||||
|
||||
// finally apply rotation to the pad itself
|
||||
pad->Rotate( newPos, rotation );
|
||||
}
|
||||
|
||||
EDA_ITEM* item = module->GraphicalItems();
|
||||
|
||||
for( ; item != NULL; item = item->Next() )
|
||||
{
|
||||
if( !item->IsSelected() && !force_all )
|
||||
continue;
|
||||
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_MODULE_TEXT_T:
|
||||
{
|
||||
TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item );
|
||||
|
||||
text->RotateTransformWithModule( centre, rotation );
|
||||
text->MoveTransformWithModule( translation );
|
||||
break;
|
||||
}
|
||||
case PCB_MODULE_EDGE_T:
|
||||
{
|
||||
EDGE_MODULE* em = static_cast<EDGE_MODULE*>( item );
|
||||
em->Rotate( centre, rotation );
|
||||
em->Move( translation );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
ClearMarkItems( module );
|
||||
}
|
||||
|
||||
|
||||
/* Mark items inside rect.
|
||||
* Items are inside rect when an end point is inside rect
|
||||
*/
|
||||
|
|
|
@ -94,10 +94,41 @@ void DRAWSEGMENT::Copy( DRAWSEGMENT* source )
|
|||
|
||||
void DRAWSEGMENT::Rotate( const wxPoint& aRotCentre, double aAngle )
|
||||
{
|
||||
RotatePoint( &m_Start, aRotCentre, aAngle );
|
||||
RotatePoint( &m_End, aRotCentre, aAngle );
|
||||
}
|
||||
switch( m_Shape )
|
||||
{
|
||||
case S_ARC:
|
||||
case S_SEGMENT:
|
||||
case S_CIRCLE:
|
||||
// these can all be done by just rotating the start and end points
|
||||
RotatePoint( &m_Start, aRotCentre, aAngle);
|
||||
RotatePoint( &m_End, aRotCentre, aAngle);
|
||||
break;
|
||||
|
||||
case S_POLYGON:
|
||||
for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ )
|
||||
{
|
||||
RotatePoint( &m_PolyPoints[ii], aRotCentre, aAngle);
|
||||
}
|
||||
break;
|
||||
|
||||
case S_CURVE:
|
||||
RotatePoint( &m_Start, aRotCentre, aAngle);
|
||||
RotatePoint( &m_End, aRotCentre, aAngle);
|
||||
|
||||
for( unsigned int ii = 0; ii < m_BezierPoints.size(); ii++ )
|
||||
{
|
||||
RotatePoint( &m_BezierPoints[ii], aRotCentre, aAngle);
|
||||
}
|
||||
break;
|
||||
|
||||
case S_RECT:
|
||||
default:
|
||||
// un-handled edge transform
|
||||
wxASSERT_MSG( false, wxT( "DRAWSEGMENT::Rotate not implemented for "
|
||||
+ ShowShape( m_Shape ) ) );
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
void DRAWSEGMENT::Flip( const wxPoint& aCentre )
|
||||
{
|
||||
|
@ -112,6 +143,37 @@ void DRAWSEGMENT::Flip( const wxPoint& aCentre )
|
|||
SetLayer( FlipLayer( GetLayer() ) );
|
||||
}
|
||||
|
||||
const wxPoint DRAWSEGMENT::GetCenter() const
|
||||
{
|
||||
wxPoint c;
|
||||
|
||||
switch( m_Shape )
|
||||
{
|
||||
case S_ARC:
|
||||
case S_CIRCLE:
|
||||
c = m_Start;
|
||||
break;
|
||||
|
||||
case S_SEGMENT:
|
||||
// Midpoint of the line
|
||||
c = ( GetStart() + GetEnd() ) / 2;
|
||||
break;
|
||||
|
||||
case S_POLYGON:
|
||||
case S_RECT:
|
||||
case S_CURVE:
|
||||
c = GetBoundingBox().Centre();
|
||||
break;
|
||||
|
||||
default:
|
||||
wxASSERT_MSG( false, "DRAWSEGMENT::GetCentre not implemented for shape"
|
||||
+ ShowShape( GetShape() ) );
|
||||
break;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
const wxPoint DRAWSEGMENT::GetArcEnd() const
|
||||
{
|
||||
wxPoint endPoint; // start of arc
|
||||
|
|
|
@ -117,7 +117,7 @@ public:
|
|||
// m_Start, m_End, and m_Angle.
|
||||
// No Set...() function for these attributes.
|
||||
|
||||
const wxPoint& GetCenter() const { return m_Start; }
|
||||
const wxPoint GetCenter() const; //override
|
||||
const wxPoint& GetArcStart() const { return m_End; }
|
||||
const wxPoint GetArcEnd() const;
|
||||
|
||||
|
|
|
@ -1111,3 +1111,101 @@ void MODULE::SetOrientation( double newangle )
|
|||
CalculateBoundingBox();
|
||||
}
|
||||
|
||||
BOARD_ITEM* MODULE::DuplicateAndAddItem( const BOARD_ITEM* aItem,
|
||||
bool aIncrementPadNumbers )
|
||||
{
|
||||
BOARD_ITEM* new_item = NULL;
|
||||
|
||||
switch( aItem->Type() )
|
||||
{
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
D_PAD* new_pad = new D_PAD( *static_cast<const D_PAD*>( aItem ) );
|
||||
|
||||
if( aIncrementPadNumbers )
|
||||
{
|
||||
// Take the next available pad number
|
||||
new_pad->IncrementPadName( true, true );
|
||||
}
|
||||
|
||||
Pads().PushBack( new_pad );
|
||||
new_item = new_pad;
|
||||
break;
|
||||
}
|
||||
case PCB_MODULE_TEXT_T:
|
||||
{
|
||||
const TEXTE_MODULE* old_text = static_cast<const TEXTE_MODULE*>( aItem );
|
||||
|
||||
// do not duplicate value or reference fields
|
||||
// (there can only be one of each)
|
||||
if( old_text->GetType() == TEXTE_MODULE::TEXT_is_DIVERS )
|
||||
{
|
||||
TEXTE_MODULE* new_text = new TEXTE_MODULE( *old_text );
|
||||
|
||||
GraphicalItems().PushBack( new_text );
|
||||
new_item = new_text;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PCB_MODULE_EDGE_T:
|
||||
{
|
||||
EDGE_MODULE* new_edge = new EDGE_MODULE(
|
||||
*static_cast<const EDGE_MODULE*>(aItem) );
|
||||
|
||||
GraphicalItems().PushBack( new_edge );
|
||||
new_item = new_edge;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Un-handled item for duplication
|
||||
wxASSERT_MSG( false, "Duplication not supported for items of class "
|
||||
+ aItem->GetClass() );
|
||||
break;
|
||||
}
|
||||
|
||||
return new_item;
|
||||
}
|
||||
|
||||
wxString MODULE::GetNextPadName( bool aFillSequenceGaps ) const
|
||||
{
|
||||
std::set<int> usedNumbers;
|
||||
|
||||
// Create a set of used pad numbers
|
||||
for( D_PAD* pad = Pads(); pad; pad = pad->Next() )
|
||||
{
|
||||
wxString padName = pad->GetPadName();
|
||||
int padNumber = 0;
|
||||
int base = 1;
|
||||
|
||||
// Trim and extract the trailing numeric part
|
||||
while( padName.Len() && padName.Last() >= '0' && padName.Last() <= '9' )
|
||||
{
|
||||
padNumber += ( padName.Last() - '0' ) * base;
|
||||
padName.RemoveLast();
|
||||
base *= 10;
|
||||
}
|
||||
|
||||
usedNumbers.insert( padNumber );
|
||||
}
|
||||
|
||||
// By default go to the end of the sequence
|
||||
int candidate = *usedNumbers.end();
|
||||
|
||||
// Filling in gaps in pad numbering
|
||||
if( aFillSequenceGaps )
|
||||
{
|
||||
// start at the beginning
|
||||
candidate = *usedNumbers.begin();
|
||||
|
||||
for( std::set<int>::iterator it = usedNumbers.begin(),
|
||||
itEnd = usedNumbers.end(); it != itEnd; ++it )
|
||||
{
|
||||
if( *it - candidate > 1 )
|
||||
break;
|
||||
|
||||
candidate = *it;
|
||||
}
|
||||
}
|
||||
|
||||
return wxString::Format( wxT( "%i" ), ++candidate );
|
||||
}
|
||||
|
|
|
@ -453,6 +453,16 @@ public:
|
|||
*/
|
||||
unsigned GetPadCount( INCLUDE_NPTH_T aIncludeNPTH = INCLUDE_NPTH_T( INCLUDE_NPTH ) ) const;
|
||||
|
||||
/**
|
||||
* Function GetNextPadName
|
||||
* returns the next available pad name in the module
|
||||
*
|
||||
* @param aFillSequenceGaps true if the numbering should "fill in" gaps in
|
||||
* the sequence, else return the highest value + 1
|
||||
* @return the next available pad name
|
||||
*/
|
||||
wxString GetNextPadName( bool aFillSequenceGaps ) const;
|
||||
|
||||
double GetArea() const { return m_Surface; }
|
||||
|
||||
time_t GetLink() const { return m_Link; }
|
||||
|
@ -464,6 +474,9 @@ public:
|
|||
int GetPlacementCost90() const { return m_CntRot90; }
|
||||
void SetPlacementCost90( int aCost ) { m_CntRot90 = aCost; }
|
||||
|
||||
BOARD_ITEM* DuplicateAndAddItem( const BOARD_ITEM* item,
|
||||
bool aIncrementPadNumbers );
|
||||
|
||||
/**
|
||||
* Function Add3DModel
|
||||
* adds \a a3DModel definition to the end of the 3D model list.
|
||||
|
|
|
@ -408,6 +408,16 @@ void D_PAD::SetPadName( const wxString& name )
|
|||
}
|
||||
|
||||
|
||||
void D_PAD::IncrementPadName( bool aSkipUnconnectable, bool aFillSequenceGaps )
|
||||
{
|
||||
bool skip = aSkipUnconnectable
|
||||
&& ( GetAttribute() == PAD_HOLE_NOT_PLATED );
|
||||
|
||||
if( !skip )
|
||||
SetPadName(GetParent()->GetNextPadName( aFillSequenceGaps ));
|
||||
}
|
||||
|
||||
|
||||
void D_PAD::Copy( D_PAD* source )
|
||||
{
|
||||
if( source == NULL )
|
||||
|
|
|
@ -103,6 +103,16 @@ public:
|
|||
void SetPadName( const wxString& name ); // Change pad name
|
||||
const wxString GetPadName() const;
|
||||
|
||||
/**
|
||||
* Function IncrementPadName
|
||||
*
|
||||
* Increments the pad name to the next available name in the module.
|
||||
*
|
||||
* @param aSkipUnconnectable skips any pads that are not connectable (for
|
||||
* example NPTH)
|
||||
*/
|
||||
void IncrementPadName( bool aSkipUnconnectable, bool aFillSequenceGaps );
|
||||
|
||||
bool PadNameEqual( const D_PAD* other ) const
|
||||
{
|
||||
return m_NumPadName == other->m_NumPadName; // hide tricks behind sensible API
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014 John Beard, john.j.beard@gmail.com
|
||||
* Copyright (C) 1992-2014 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 2
|
||||
* 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/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <wxPcbStruct.h>
|
||||
#include <base_units.h>
|
||||
|
||||
#include <module_editor_frame.h>
|
||||
|
||||
#include "dialog_move_exact.h"
|
||||
|
||||
// initialise statics
|
||||
DIALOG_MOVE_EXACT::MOVE_EXACT_OPTIONS DIALOG_MOVE_EXACT::m_options;
|
||||
|
||||
|
||||
DIALOG_MOVE_EXACT::DIALOG_MOVE_EXACT( PCB_BASE_FRAME* aParent,
|
||||
wxPoint& translation, double& rotation ):
|
||||
DIALOG_MOVE_EXACT_BASE( aParent ),
|
||||
m_translation( translation ),
|
||||
m_rotation( rotation )
|
||||
{
|
||||
// set the unit labels
|
||||
m_xUnit->SetLabelText( GetAbbreviatedUnitsLabel( g_UserUnit ) );
|
||||
m_yUnit->SetLabelText( GetAbbreviatedUnitsLabel( g_UserUnit ) );
|
||||
// rotation is always degrees
|
||||
m_rotUnit->SetLabelText( _( "deg" ) );
|
||||
|
||||
// tabbing goes through the entries in sequence
|
||||
m_yEntry->MoveAfterInTabOrder( m_xEntry );
|
||||
m_rotEntry->MoveAfterInTabOrder( m_yEntry );
|
||||
|
||||
// and set up the entries according to the saved options
|
||||
m_polarCoords->SetValue( m_options.polarCoords );
|
||||
m_xEntry->SetValue( wxString::FromDouble( m_options.entry1 ) );
|
||||
m_yEntry->SetValue( wxString::FromDouble( m_options.entry2 ) );
|
||||
m_rotEntry->SetValue( wxString::FromDouble( m_options.entryRotation ) );
|
||||
}
|
||||
|
||||
|
||||
DIALOG_MOVE_EXACT::~DIALOG_MOVE_EXACT()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Convert a given Cartesian point into a polar representation.
|
||||
*
|
||||
* Linear units are not considered, the answer is in the same units as given
|
||||
* Angle is returned in degrees
|
||||
*/
|
||||
void DIALOG_MOVE_EXACT::ToPolarDeg( double x, double y, double& r, double& q )
|
||||
{
|
||||
// convert to polar coordinates
|
||||
r = hypot ( x, y );
|
||||
|
||||
q = ( r != 0) ? RAD2DEG( atan2( y, x ) ) : 0;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Get the (Cartesian) translation described by the text entries
|
||||
* @param val output translation vector
|
||||
* @param polar interpret as polar coords
|
||||
* @return false if error (though the text conversion functions don't report errors)
|
||||
*/
|
||||
bool DIALOG_MOVE_EXACT::GetTranslationInIU ( wxPoint& val, bool polar )
|
||||
{
|
||||
if( polar )
|
||||
{
|
||||
const int r = ValueFromTextCtrl( *m_xEntry );
|
||||
const double q = DoubleValueFromString( DEGREES, m_yEntry->GetValue() );
|
||||
|
||||
val.x = r * cos( DEG2RAD( q / 10.0 ) );
|
||||
val.y = r * sin( DEG2RAD( q / 10.0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// direct read
|
||||
val.x = ValueFromTextCtrl( *m_xEntry );
|
||||
val.y = ValueFromTextCtrl( *m_yEntry );
|
||||
}
|
||||
|
||||
// no validation to do here, but in future, you could return false here
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_MOVE_EXACT::OnPolarChanged( wxCommandEvent& event )
|
||||
{
|
||||
bool newPolar = m_polarCoords->IsChecked();
|
||||
wxPoint val;
|
||||
|
||||
// get the value as previously stored
|
||||
GetTranslationInIU( val, !newPolar );
|
||||
|
||||
if( newPolar )
|
||||
{
|
||||
// convert to polar coordinates
|
||||
double r, q;
|
||||
ToPolarDeg( val.x, val.y, r, q);
|
||||
|
||||
PutValueInLocalUnits( *m_xEntry, round( r / 10.0) * 10 );
|
||||
m_xLabel->SetLabelText( wxT( "r:" ) );
|
||||
|
||||
m_yEntry->SetValue( wxString::FromDouble( q ) );
|
||||
m_yLabel->SetLabelText( wxT( "\u03b8:" ) ); // theta
|
||||
|
||||
m_yUnit->SetLabelText( GetAbbreviatedUnitsLabel( DEGREES ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// vector is already in Cartesian, so just render out
|
||||
|
||||
// note - round off the last decimal place (10nm) to prevent
|
||||
// (some) rounding causing errors when round-tripping
|
||||
// you can never eliminate entirely, however
|
||||
PutValueInLocalUnits( *m_xEntry, round( val.x / 10.0) * 10 );
|
||||
m_xLabel->SetLabelText( wxT( "x:" ) );
|
||||
|
||||
PutValueInLocalUnits( *m_yEntry, round( val.y / 10.0) * 10 );
|
||||
m_yLabel->SetLabelText( wxT( "y:" ) );
|
||||
|
||||
m_yUnit->SetLabelText( GetAbbreviatedUnitsLabel( g_UserUnit ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_MOVE_EXACT::OnClear( wxCommandEvent& event )
|
||||
{
|
||||
wxObject* obj = event.GetEventObject();
|
||||
wxTextCtrl* entry = NULL;
|
||||
|
||||
if( obj == m_clearX )
|
||||
{
|
||||
entry = m_xEntry;
|
||||
}
|
||||
else if( obj == m_clearY )
|
||||
{
|
||||
entry = m_yEntry;
|
||||
}
|
||||
else if( obj == m_clearRot )
|
||||
{
|
||||
entry = m_rotEntry;
|
||||
}
|
||||
|
||||
if( entry )
|
||||
entry->SetValue( "0" );
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_MOVE_EXACT::OnCancelClick( wxCommandEvent& event )
|
||||
{
|
||||
EndModal( MOVE_ABORT );
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_MOVE_EXACT::OnOkClick( wxCommandEvent& event )
|
||||
{
|
||||
m_rotation = DoubleValueFromString( DEGREES, m_rotEntry->GetValue() );
|
||||
|
||||
// for the output, we only deliver a Cartesian vector
|
||||
bool ok = GetTranslationInIU( m_translation, m_polarCoords->IsChecked() );
|
||||
|
||||
if ( ok )
|
||||
{
|
||||
// save the settings
|
||||
m_options.polarCoords = m_polarCoords->GetValue();
|
||||
m_xEntry->GetValue().ToDouble( &m_options.entry1 );
|
||||
m_yEntry->GetValue().ToDouble( &m_options.entry2 );
|
||||
m_rotEntry->GetValue().ToDouble( &m_options.entryRotation );
|
||||
|
||||
EndModal( MOVE_OK );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Reset a text field to be 0 if it was exited while blank
|
||||
*/
|
||||
void DIALOG_MOVE_EXACT::OnTextFocusLost( wxFocusEvent& event )
|
||||
{
|
||||
wxTextCtrl* obj = static_cast<wxTextCtrl*>( event.GetEventObject() );
|
||||
|
||||
if( obj->GetValue().IsEmpty() )
|
||||
{
|
||||
obj->SetValue("0");
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014 John Beard, john.j.beard@gmail.com
|
||||
* Copyright (C) 1992-2014 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 2
|
||||
* 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/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef __DIALOG_MOVE_EXACT__
|
||||
#define __DIALOG_MOVE_EXACT__
|
||||
|
||||
// Include the wxFormBuider header base:
|
||||
#include <vector>
|
||||
#include <dialog_move_exact_base.h>
|
||||
|
||||
class DIALOG_MOVE_EXACT : public DIALOG_MOVE_EXACT_BASE
|
||||
{
|
||||
private:
|
||||
|
||||
wxPoint& m_translation;
|
||||
double& m_rotation;
|
||||
|
||||
public:
|
||||
|
||||
enum MOVE_EDIT_T
|
||||
{
|
||||
MOVE_ABORT, ///< if not changed or error
|
||||
MOVE_OK, ///< if successfully changed
|
||||
};
|
||||
|
||||
// Constructor and destructor
|
||||
DIALOG_MOVE_EXACT( PCB_BASE_FRAME* aParent, wxPoint& translation,
|
||||
double& rotation );
|
||||
~DIALOG_MOVE_EXACT();
|
||||
|
||||
private:
|
||||
|
||||
void OnTextFocusLost( wxFocusEvent& event );
|
||||
void OnPolarChanged( wxCommandEvent& event );
|
||||
void OnClear( wxCommandEvent& event );
|
||||
|
||||
void OnCancelClick( wxCommandEvent& event );
|
||||
void OnOkClick( wxCommandEvent& event );
|
||||
|
||||
void ToPolarDeg( double x, double y, double& r, double& q );
|
||||
bool GetTranslationInIU ( wxPoint& val, bool polar );
|
||||
|
||||
/**
|
||||
* Persistent dialog options
|
||||
*/
|
||||
struct MOVE_EXACT_OPTIONS
|
||||
{
|
||||
bool polarCoords;
|
||||
double entry1;
|
||||
double entry2;
|
||||
double entryRotation;
|
||||
|
||||
MOVE_EXACT_OPTIONS():
|
||||
polarCoords(false),
|
||||
entry1(0),
|
||||
entry2(0),
|
||||
entryRotation(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// persistent settings
|
||||
static MOVE_EXACT_OPTIONS m_options;
|
||||
};
|
||||
|
||||
#endif // __DIALOG_MOVE_EXACT__
|
|
@ -0,0 +1,114 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Jun 6 2014)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO "NOT" EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "dialog_move_exact_base.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DIALOG_MOVE_EXACT_BASE::DIALOG_MOVE_EXACT_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
|
||||
{
|
||||
this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize );
|
||||
|
||||
wxBoxSizer* bMainSizer;
|
||||
bMainSizer = new wxBoxSizer( wxVERTICAL );
|
||||
|
||||
m_polarCoords = new wxCheckBox( this, wxID_ANY, _("Polar coordinates"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
bMainSizer->Add( m_polarCoords, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
wxFlexGridSizer* fgSizer2;
|
||||
fgSizer2 = new wxFlexGridSizer( 0, 4, 0, 0 );
|
||||
fgSizer2->AddGrowableCol( 1 );
|
||||
fgSizer2->SetFlexibleDirection( wxBOTH );
|
||||
fgSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
|
||||
|
||||
m_xLabel = new wxStaticText( this, wxID_ANY, _("x:"), wxDefaultPosition, wxSize( -1,-1 ), 0 );
|
||||
m_xLabel->Wrap( -1 );
|
||||
fgSizer2->Add( m_xLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 );
|
||||
|
||||
m_xEntry = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizer2->Add( m_xEntry, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
m_xUnit = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_xUnit->Wrap( -1 );
|
||||
fgSizer2->Add( m_xUnit, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL, 5 );
|
||||
|
||||
m_clearX = new wxBitmapButton( this, wxID_CLEAR, wxArtProvider::GetBitmap( wxART_DELETE, wxART_BUTTON ), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW );
|
||||
fgSizer2->Add( m_clearX, 0, wxALL, 5 );
|
||||
|
||||
m_yLabel = new wxStaticText( this, wxID_ANY, _("y:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_yLabel->Wrap( -1 );
|
||||
fgSizer2->Add( m_yLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 );
|
||||
|
||||
m_yEntry = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizer2->Add( m_yEntry, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
m_yUnit = new wxStaticText( this, wxID_ANY, _("mm"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_yUnit->Wrap( -1 );
|
||||
fgSizer2->Add( m_yUnit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
m_clearY = new wxBitmapButton( this, wxID_CLEAR, wxArtProvider::GetBitmap( wxART_DELETE, wxART_BUTTON ), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW );
|
||||
fgSizer2->Add( m_clearY, 0, wxALL, 5 );
|
||||
|
||||
m_rotLabel = new wxStaticText( this, wxID_ANY, _("Rotate:"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_rotLabel->Wrap( -1 );
|
||||
fgSizer2->Add( m_rotLabel, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 );
|
||||
|
||||
m_rotEntry = new wxTextCtrl( this, wxID_ANY, _("0"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
fgSizer2->Add( m_rotEntry, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
m_rotUnit = new wxStaticText( this, wxID_ANY, _("deg"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_rotUnit->Wrap( -1 );
|
||||
fgSizer2->Add( m_rotUnit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
m_clearRot = new wxBitmapButton( this, wxID_CLEAR, wxArtProvider::GetBitmap( wxART_DELETE, wxART_BUTTON ), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW );
|
||||
fgSizer2->Add( m_clearRot, 0, wxALL, 5 );
|
||||
|
||||
|
||||
bMainSizer->Add( fgSizer2, 1, wxEXPAND, 5 );
|
||||
|
||||
m_stdButtons = new wxStdDialogButtonSizer();
|
||||
m_stdButtonsOK = new wxButton( this, wxID_OK );
|
||||
m_stdButtons->AddButton( m_stdButtonsOK );
|
||||
m_stdButtonsCancel = new wxButton( this, wxID_CANCEL );
|
||||
m_stdButtons->AddButton( m_stdButtonsCancel );
|
||||
m_stdButtons->Realize();
|
||||
|
||||
bMainSizer->Add( m_stdButtons, 0, wxALL|wxEXPAND, 5 );
|
||||
|
||||
|
||||
this->SetSizer( bMainSizer );
|
||||
this->Layout();
|
||||
bMainSizer->Fit( this );
|
||||
|
||||
// Connect Events
|
||||
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_MOVE_EXACT_BASE::OnClose ) );
|
||||
m_polarCoords->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnPolarChanged ), NULL, this );
|
||||
m_xEntry->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
||||
m_clearX->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this );
|
||||
m_yEntry->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
||||
m_clearY->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this );
|
||||
m_rotEntry->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
||||
m_clearRot->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this );
|
||||
m_stdButtonsCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnCancelClick ), NULL, this );
|
||||
m_stdButtonsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnOkClick ), NULL, this );
|
||||
}
|
||||
|
||||
DIALOG_MOVE_EXACT_BASE::~DIALOG_MOVE_EXACT_BASE()
|
||||
{
|
||||
// Disconnect Events
|
||||
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_MOVE_EXACT_BASE::OnClose ) );
|
||||
m_polarCoords->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnPolarChanged ), NULL, this );
|
||||
m_xEntry->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
||||
m_clearX->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this );
|
||||
m_yEntry->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
||||
m_clearY->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this );
|
||||
m_rotEntry->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( DIALOG_MOVE_EXACT_BASE::OnTextFocusLost ), NULL, this );
|
||||
m_clearRot->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnClear ), NULL, this );
|
||||
m_stdButtonsCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnCancelClick ), NULL, this );
|
||||
m_stdButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_MOVE_EXACT_BASE::OnOkClick ), NULL, this );
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Jun 6 2014)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO "NOT" EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __DIALOG_MOVE_EXACT_BASE_H__
|
||||
#define __DIALOG_MOVE_EXACT_BASE_H__
|
||||
|
||||
#include <wx/artprov.h>
|
||||
#include <wx/xrc/xmlres.h>
|
||||
#include <wx/intl.h>
|
||||
class DIALOG_SHIM;
|
||||
|
||||
#include "dialog_shim.h"
|
||||
#include <wx/string.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/gdicmn.h>
|
||||
#include <wx/font.h>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/icon.h>
|
||||
#include <wx/bmpbuttn.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/dialog.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Class DIALOG_MOVE_EXACT_BASE
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class DIALOG_MOVE_EXACT_BASE : public DIALOG_SHIM
|
||||
{
|
||||
private:
|
||||
|
||||
protected:
|
||||
wxCheckBox* m_polarCoords;
|
||||
wxStaticText* m_xLabel;
|
||||
wxTextCtrl* m_xEntry;
|
||||
wxStaticText* m_xUnit;
|
||||
wxBitmapButton* m_clearX;
|
||||
wxStaticText* m_yLabel;
|
||||
wxTextCtrl* m_yEntry;
|
||||
wxStaticText* m_yUnit;
|
||||
wxBitmapButton* m_clearY;
|
||||
wxStaticText* m_rotLabel;
|
||||
wxTextCtrl* m_rotEntry;
|
||||
wxStaticText* m_rotUnit;
|
||||
wxBitmapButton* m_clearRot;
|
||||
wxStdDialogButtonSizer* m_stdButtons;
|
||||
wxButton* m_stdButtonsOK;
|
||||
wxButton* m_stdButtonsCancel;
|
||||
|
||||
// Virtual event handlers, overide them in your derived class
|
||||
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
|
||||
virtual void OnPolarChanged( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnTextFocusLost( wxFocusEvent& event ) { event.Skip(); }
|
||||
virtual void OnClear( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnCancelClick( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnOkClick( wxCommandEvent& event ) { event.Skip(); }
|
||||
|
||||
|
||||
public:
|
||||
|
||||
DIALOG_MOVE_EXACT_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Move item"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
|
||||
~DIALOG_MOVE_EXACT_BASE();
|
||||
|
||||
};
|
||||
|
||||
#endif //__DIALOG_MOVE_EXACT_BASE_H__
|
|
@ -108,6 +108,10 @@ static EDA_HOTKEY HkEditBoardItem( wxT( "Edit Item" ), HK_EDIT_ITEM, 'E' );
|
|||
static EDA_HOTKEY HkFlipItem( wxT( "Flip Item" ), HK_FLIP_ITEM, 'F' );
|
||||
static EDA_HOTKEY HkRotateItem( wxT( "Rotate Item" ), HK_ROTATE_ITEM, 'R' );
|
||||
static EDA_HOTKEY HkMoveItem( wxT( "Move Item" ), HK_MOVE_ITEM, 'M' );
|
||||
static EDA_HOTKEY HkMoveItemExact( wxT( "Move Item Exactly" ), HK_MOVE_ITEM_EXACT, 'M' + GR_KB_CTRL );
|
||||
static EDA_HOTKEY HkDuplicateItem( wxT( "Duplicate Item" ), HK_DUPLICATE_ITEM, 'D' + GR_KB_CTRL );
|
||||
static EDA_HOTKEY HkDuplicateItemAndIncrement( wxT( "Duplicate Item and Increment" ),
|
||||
HK_DUPLICATE_ITEM_AND_INCREMENT, 'D' + GR_KB_SHIFTCTRL );
|
||||
static EDA_HOTKEY HkCopyItem( wxT( "Copy Item" ), HK_COPY_ITEM, 'C' );
|
||||
static EDA_HOTKEY HkDragFootprint( wxT( "Drag Item" ), HK_DRAG_ITEM, 'G' );
|
||||
static EDA_HOTKEY HkGetAndMoveFootprint( wxT( "Get and Move Footprint" ), HK_GET_AND_MOVE_FOOTPRINT, 'T' );
|
||||
|
@ -300,6 +304,7 @@ EDA_HOTKEY* board_edit_Hotkey_List[] =
|
|||
// List of hotkey descriptors for the module editor
|
||||
EDA_HOTKEY* module_edit_Hotkey_List[] = {
|
||||
&HkMoveItem, &HkRotateItem, &HkEditBoardItem,
|
||||
&HkMoveItemExact, &HkDuplicateItem, &HkDuplicateItemAndIncrement,
|
||||
&HkDelete,
|
||||
&HkSaveModule,
|
||||
NULL
|
||||
|
|
|
@ -41,6 +41,7 @@ enum hotkey_id_commnand {
|
|||
HK_FLIP_ITEM,
|
||||
HK_COPY_ITEM,
|
||||
HK_MOVE_ITEM,
|
||||
HK_MOVE_ITEM_EXACT,
|
||||
HK_DRAG_ITEM,
|
||||
HK_GET_AND_MOVE_FOOTPRINT,
|
||||
HK_LOCK_UNLOCK_FOOTPRINT,
|
||||
|
@ -60,6 +61,8 @@ enum hotkey_id_commnand {
|
|||
HK_SWITCH_TRACK_DISPLAY_MODE,
|
||||
HK_FIND_ITEM,
|
||||
HK_EDIT_ITEM,
|
||||
HK_DUPLICATE_ITEM,
|
||||
HK_DUPLICATE_ITEM_AND_INCREMENT,
|
||||
HK_PLACE_ITEM,
|
||||
HK_SWITCH_TRACK_WIDTH_TO_NEXT,
|
||||
HK_SWITCH_TRACK_WIDTH_TO_PREVIOUS,
|
||||
|
|
|
@ -896,7 +896,6 @@ bool PCB_EDIT_FRAME::OnHotkeyMoveItem( int aIdCommand )
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PCB_EDIT_FRAME::OnHotkeyPlaceItem( wxDC* aDC )
|
||||
{
|
||||
BOARD_ITEM* item = GetCurItem();
|
||||
|
|
|
@ -152,31 +152,84 @@ bool FOOTPRINT_EDIT_FRAME::OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPos
|
|||
OnHotkeyMoveItem( HK_MOVE_ITEM );
|
||||
break;
|
||||
|
||||
case HK_MOVE_ITEM_EXACT:
|
||||
if( blockActive )
|
||||
{
|
||||
cmd.SetId( ID_POPUP_MOVE_BLOCK_EXACT );
|
||||
GetEventHandler()->ProcessEvent( cmd );
|
||||
}
|
||||
else
|
||||
{
|
||||
OnHotkeyMoveItemExact();
|
||||
}
|
||||
break;
|
||||
|
||||
case HK_ROTATE_ITEM:
|
||||
OnHotkeyRotateItem( HK_ROTATE_ITEM );
|
||||
break;
|
||||
|
||||
case HK_DUPLICATE_ITEM:
|
||||
case HK_DUPLICATE_ITEM_AND_INCREMENT:
|
||||
OnHotkeyDuplicateItem( HK_Descr->m_Idcommand );
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FOOTPRINT_EDIT_FRAME::OnHotkeyEditItem( int aIdCommand )
|
||||
BOARD_ITEM* FOOTPRINT_EDIT_FRAME::PrepareItemForHotkey( bool failIfCurrentlyEdited )
|
||||
{
|
||||
BOARD_ITEM* item = GetCurItem();
|
||||
bool itemCurrentlyEdited = item && item->GetFlags();
|
||||
bool blockActive = GetScreen()->m_BlockLocate.GetCommand() != BLOCK_IDLE;
|
||||
|
||||
if( itemCurrentlyEdited || blockActive )
|
||||
return false;
|
||||
if( failIfCurrentlyEdited )
|
||||
{
|
||||
if( itemCurrentlyEdited || blockActive )
|
||||
return NULL;
|
||||
|
||||
item = ModeditLocateAndDisplay();
|
||||
item = ModeditLocateAndDisplay();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( blockActive )
|
||||
return NULL;
|
||||
|
||||
if( !itemCurrentlyEdited )
|
||||
item = ModeditLocateAndDisplay();
|
||||
}
|
||||
|
||||
// set item if we can, but don't clear if not
|
||||
if( item )
|
||||
SetCurItem( item );
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
bool FOOTPRINT_EDIT_FRAME::PostCommandMenuEvent( int evt_type )
|
||||
{
|
||||
if( evt_type != 0 )
|
||||
{
|
||||
wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED );
|
||||
evt.SetEventObject( this );
|
||||
evt.SetId( evt_type );
|
||||
wxPostEvent( this, evt );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FOOTPRINT_EDIT_FRAME::OnHotkeyEditItem( int aIdCommand )
|
||||
{
|
||||
BOARD_ITEM* item = PrepareItemForHotkey( true );
|
||||
|
||||
if( item == NULL )
|
||||
return false;
|
||||
|
||||
SetCurItem( item );
|
||||
|
||||
int evt_type = 0; // Used to post a wxCommandEvent on demand
|
||||
|
||||
switch( item->Type() )
|
||||
|
@ -209,35 +262,17 @@ bool FOOTPRINT_EDIT_FRAME::OnHotkeyEditItem( int aIdCommand )
|
|||
break;
|
||||
}
|
||||
|
||||
if( evt_type != 0 )
|
||||
{
|
||||
wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED );
|
||||
evt.SetEventObject( this );
|
||||
evt.SetId( evt_type );
|
||||
wxPostEvent( this, evt );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return PostCommandMenuEvent( evt_type );
|
||||
}
|
||||
|
||||
|
||||
bool FOOTPRINT_EDIT_FRAME::OnHotkeyDeleteItem( int aIdCommand )
|
||||
{
|
||||
BOARD_ITEM* item = GetCurItem();
|
||||
bool itemCurrentlyEdited = item && item->GetFlags();
|
||||
bool blockActive = GetScreen()->m_BlockLocate.GetCommand() != BLOCK_IDLE;
|
||||
|
||||
if( itemCurrentlyEdited || blockActive )
|
||||
return false;
|
||||
|
||||
item = ModeditLocateAndDisplay();
|
||||
BOARD_ITEM* item = PrepareItemForHotkey( true );
|
||||
|
||||
if( item == NULL )
|
||||
return false;
|
||||
|
||||
SetCurItem( item );
|
||||
|
||||
int evt_type = 0; // Used to post a wxCommandEvent on demand
|
||||
|
||||
switch( item->Type() )
|
||||
|
@ -264,35 +299,17 @@ bool FOOTPRINT_EDIT_FRAME::OnHotkeyDeleteItem( int aIdCommand )
|
|||
break;
|
||||
}
|
||||
|
||||
if( evt_type != 0 )
|
||||
{
|
||||
wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED );
|
||||
evt.SetEventObject( this );
|
||||
evt.SetId( evt_type );
|
||||
wxPostEvent( this, evt );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return PostCommandMenuEvent( evt_type );
|
||||
}
|
||||
|
||||
|
||||
bool FOOTPRINT_EDIT_FRAME::OnHotkeyMoveItem( int aIdCommand )
|
||||
{
|
||||
BOARD_ITEM* item = GetCurItem();
|
||||
bool itemCurrentlyEdited = item && item->GetFlags();
|
||||
bool blockActive = GetScreen()->m_BlockLocate.GetCommand() != BLOCK_IDLE;
|
||||
|
||||
if( itemCurrentlyEdited || blockActive )
|
||||
return false;
|
||||
|
||||
item = ModeditLocateAndDisplay();
|
||||
BOARD_ITEM* item = PrepareItemForHotkey( true );
|
||||
|
||||
if( item == NULL )
|
||||
return false;
|
||||
|
||||
SetCurItem( item );
|
||||
|
||||
int evt_type = 0; // Used to post a wxCommandEvent on demand
|
||||
|
||||
switch( item->Type() )
|
||||
|
@ -319,36 +336,70 @@ bool FOOTPRINT_EDIT_FRAME::OnHotkeyMoveItem( int aIdCommand )
|
|||
break;
|
||||
}
|
||||
|
||||
if( evt_type != 0 )
|
||||
return PostCommandMenuEvent( evt_type );
|
||||
}
|
||||
|
||||
|
||||
bool FOOTPRINT_EDIT_FRAME::OnHotkeyMoveItemExact()
|
||||
{
|
||||
BOARD_ITEM* item = PrepareItemForHotkey( false );
|
||||
|
||||
if( item == NULL )
|
||||
return false;
|
||||
|
||||
int evt_type = 0; // Used to post a wxCommandEvent on demand
|
||||
|
||||
switch( item->Type() )
|
||||
{
|
||||
wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED );
|
||||
evt.SetEventObject( this );
|
||||
evt.SetId( evt_type );
|
||||
wxPostEvent( this, evt );
|
||||
return true;
|
||||
case PCB_PAD_T:
|
||||
case PCB_MODULE_EDGE_T:
|
||||
case PCB_MODULE_TEXT_T:
|
||||
evt_type = ID_POPUP_PCB_MOVE_EXACT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
return PostCommandMenuEvent( evt_type );
|
||||
}
|
||||
|
||||
bool FOOTPRINT_EDIT_FRAME::OnHotkeyDuplicateItem( int aIdCommand )
|
||||
{
|
||||
BOARD_ITEM* item = PrepareItemForHotkey( true );
|
||||
|
||||
if( item == NULL )
|
||||
return false;
|
||||
|
||||
int evt_type = 0; // Used to post a wxCommandEvent on demand
|
||||
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_PAD_T:
|
||||
case PCB_MODULE_EDGE_T:
|
||||
case PCB_MODULE_TEXT_T:
|
||||
if( aIdCommand == HK_DUPLICATE_ITEM )
|
||||
evt_type = ID_POPUP_PCB_DUPLICATE_ITEM;
|
||||
else
|
||||
evt_type = ID_POPUP_PCB_DUPLICATE_ITEM_AND_INCREMENT;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return PostCommandMenuEvent( evt_type );
|
||||
}
|
||||
|
||||
|
||||
bool FOOTPRINT_EDIT_FRAME::OnHotkeyRotateItem( int aIdCommand )
|
||||
{
|
||||
BOARD_ITEM* item = GetCurItem();
|
||||
bool itemCurrentlyEdited = item && item->GetFlags();
|
||||
int evt_type = 0; // Used to post a wxCommandEvent on demand
|
||||
bool blockActive = GetScreen()->m_BlockLocate.GetCommand() != BLOCK_IDLE;
|
||||
|
||||
if( blockActive )
|
||||
return false;
|
||||
|
||||
if( !itemCurrentlyEdited )
|
||||
item = ModeditLocateAndDisplay();
|
||||
BOARD_ITEM* item = PrepareItemForHotkey( false );
|
||||
|
||||
if( item == NULL )
|
||||
return false;
|
||||
|
||||
SetCurItem( item );
|
||||
int evt_type = 0; // Used to post a wxCommandEvent on demand
|
||||
|
||||
switch( item->Type() )
|
||||
{
|
||||
|
@ -362,14 +413,5 @@ bool FOOTPRINT_EDIT_FRAME::OnHotkeyRotateItem( int aIdCommand )
|
|||
break;
|
||||
}
|
||||
|
||||
if( evt_type != 0 )
|
||||
{
|
||||
wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED );
|
||||
evt.SetEventObject( this );
|
||||
evt.SetId( evt_type );
|
||||
wxPostEvent( this, evt );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return PostCommandMenuEvent( evt_type );
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include <tool/tool_manager.h>
|
||||
|
||||
#include <dialog_edit_module_for_Modedit.h>
|
||||
#include <dialog_move_exact.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
#include <menus_helpers.h>
|
||||
#include <footprint_wizard_frame.h>
|
||||
|
@ -64,10 +65,13 @@
|
|||
|
||||
|
||||
// Functions defined in block_module_editor, but used here
|
||||
// These 2 functions are used in modedit to rotate or mirror the whole footprint
|
||||
// so they are called with force_all = true
|
||||
// These 3 functions are used in modedit to rotate, mirror or move the
|
||||
// whole footprint so they are called with force_all = true
|
||||
void MirrorMarkedItems( MODULE* module, wxPoint offset, bool force_all = false );
|
||||
void RotateMarkedItems( MODULE* module, wxPoint offset, bool force_all = false );
|
||||
void MoveMarkedItemsExactly( MODULE* module, const wxPoint& centre,
|
||||
const wxPoint& translation, double rotation,
|
||||
bool force_all = false );
|
||||
|
||||
|
||||
BOARD_ITEM* FOOTPRINT_EDIT_FRAME::ModeditLocateAndDisplay( int aHotKeyCode )
|
||||
|
@ -635,6 +639,38 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
|||
m_canvas->MoveCursorToCrossHair();
|
||||
break;
|
||||
|
||||
case ID_POPUP_PCB_DUPLICATE_ITEM:
|
||||
duplicateItems( false );
|
||||
break;
|
||||
|
||||
case ID_POPUP_PCB_DUPLICATE_ITEM_AND_INCREMENT:
|
||||
duplicateItems( true );
|
||||
break;
|
||||
|
||||
case ID_POPUP_PCB_MOVE_EXACT:
|
||||
{
|
||||
wxPoint translation;
|
||||
double rotation = 0;
|
||||
|
||||
DIALOG_MOVE_EXACT dialog( this, translation, rotation );
|
||||
int ret = dialog.ShowModal();
|
||||
|
||||
if( ret == DIALOG_MOVE_EXACT::MOVE_OK )
|
||||
{
|
||||
SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT );
|
||||
|
||||
BOARD_ITEM* item = GetScreen()->GetCurItem();
|
||||
|
||||
item->Move( translation );
|
||||
item->Rotate( item->GetPosition(), rotation );
|
||||
m_canvas->Refresh();
|
||||
}
|
||||
|
||||
m_canvas->MoveCursorToCrossHair();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_POPUP_PCB_IMPORT_PAD_SETTINGS:
|
||||
SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT );
|
||||
m_canvas->MoveCursorToCrossHair();
|
||||
|
@ -735,6 +771,7 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
|||
|
||||
case ID_MODEDIT_MODULE_ROTATE:
|
||||
case ID_MODEDIT_MODULE_MIRROR:
|
||||
case ID_MODEDIT_MODULE_MOVE_EXACT:
|
||||
SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT );
|
||||
Transform( (MODULE*) GetScreen()->GetCurItem(), id );
|
||||
m_canvas->Refresh();
|
||||
|
@ -799,6 +836,12 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
|||
HandleBlockEnd( &dc );
|
||||
break;
|
||||
|
||||
case ID_POPUP_MOVE_BLOCK_EXACT:
|
||||
GetScreen()->m_BlockLocate.SetCommand( BLOCK_MOVE_EXACT );
|
||||
GetScreen()->m_BlockLocate.SetMessageBlock( this );
|
||||
HandleBlockEnd( &dc );
|
||||
break;
|
||||
|
||||
case ID_GEN_IMPORT_DXF_FILE:
|
||||
InvokeDXFDialogModuleImport( this, GetBoard()->m_Modules );
|
||||
m_canvas->Refresh();
|
||||
|
@ -812,6 +855,49 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
|
|||
}
|
||||
|
||||
|
||||
void FOOTPRINT_EDIT_FRAME::DuplicateItems( bool aIncrement )
|
||||
{
|
||||
SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT );
|
||||
|
||||
BOARD_ITEM* item = GetScreen()->GetCurItem();
|
||||
MODULE* module = static_cast<MODULE*>( item->GetParent() );
|
||||
|
||||
int move_cmd = 0;
|
||||
|
||||
BOARD_ITEM* new_item = module->DuplicateAndAddItem(
|
||||
item, aIncrement );
|
||||
|
||||
if( new_item )
|
||||
{
|
||||
switch( new_item->Type() )
|
||||
{
|
||||
case PCB_PAD_T:
|
||||
move_cmd = ID_POPUP_PCB_MOVE_PAD_REQUEST;
|
||||
break;
|
||||
case PCB_MODULE_TEXT_T:
|
||||
move_cmd = ID_POPUP_PCB_MOVE_TEXTMODULE_REQUEST;
|
||||
break;
|
||||
case PCB_MODULE_EDGE_T:
|
||||
move_cmd = ID_POPUP_PCB_MOVE_EDGE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( move_cmd )
|
||||
{
|
||||
SetMsgPanel( new_item );
|
||||
SetCurItem( new_item );
|
||||
|
||||
m_canvas->MoveCursorToCrossHair();
|
||||
|
||||
// pick up the item and start moving
|
||||
PostCommandMenuEvent( move_cmd );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FOOTPRINT_EDIT_FRAME::Transform( MODULE* module, int transform )
|
||||
{
|
||||
switch( transform )
|
||||
|
@ -824,6 +910,23 @@ void FOOTPRINT_EDIT_FRAME::Transform( MODULE* module, int transform )
|
|||
MirrorMarkedItems( module, wxPoint(0,0), true );
|
||||
break;
|
||||
|
||||
case ID_MODEDIT_MODULE_MOVE_EXACT:
|
||||
{
|
||||
wxPoint translation;
|
||||
double rotation = 0;
|
||||
|
||||
DIALOG_MOVE_EXACT dialog( this, translation, rotation );
|
||||
int ret = dialog.ShowModal();
|
||||
|
||||
if( ret == DIALOG_MOVE_EXACT::MOVE_OK )
|
||||
{
|
||||
MoveMarkedItemsExactly( module, wxPoint(0, 0),
|
||||
translation, rotation, true );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
DisplayInfoMessage( this, wxT( "Not available" ) );
|
||||
break;
|
||||
|
|
|
@ -173,7 +173,7 @@ void FOOTPRINT_EDIT_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos )
|
|||
// so deselect the active tool
|
||||
SetToolID( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor(), wxEmptyString );
|
||||
SetCurItem( NULL );
|
||||
m_canvas->Refresh();
|
||||
m_canvas->Refresh();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -260,6 +260,11 @@ bool FOOTPRINT_EDIT_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMen
|
|||
AddMenuItem( PopMenu, ID_POPUP_DELETE_BLOCK,
|
||||
_( "Delete Block (shift+ctrl + drag mouse)" ),
|
||||
KiBitmap( delete_xpm ) );
|
||||
|
||||
msg = AddHotkeyName( _("Move Block Exactly" ),
|
||||
g_Module_Editor_Hokeys_Descr, HK_MOVE_ITEM_EXACT );
|
||||
AddMenuItem( PopMenu, ID_POPUP_MOVE_BLOCK_EXACT,
|
||||
msg, KiBitmap( move_xpm ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -286,10 +291,14 @@ bool FOOTPRINT_EDIT_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMen
|
|||
KiBitmap( rotate_module_ccw_xpm ) );
|
||||
AddMenuItem( transform_choice, ID_MODEDIT_MODULE_MIRROR, _( "Mirror" ),
|
||||
KiBitmap( mirror_footprint_axisY_xpm ) );
|
||||
AddMenuItem( transform_choice, ID_MODEDIT_MODULE_MOVE_EXACT, _( "Move Exactly" ),
|
||||
KiBitmap( move_module_xpm ) );
|
||||
|
||||
msg = AddHotkeyName( _( "Edit Footprint" ), g_Module_Editor_Hokeys_Descr, HK_EDIT_ITEM );
|
||||
AddMenuItem( PopMenu, ID_POPUP_PCB_EDIT_MODULE_PRMS, msg, KiBitmap( edit_module_xpm ) );
|
||||
AddMenuItem( PopMenu, transform_choice, ID_MODEDIT_TRANSFORM_MODULE,
|
||||
_( "Transform Footprint" ), KiBitmap( edit_xpm ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -309,6 +318,12 @@ bool FOOTPRINT_EDIT_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMen
|
|||
msg = AddHotkeyName( _("Delete Pad" ), g_Module_Editor_Hokeys_Descr, HK_DELETE );
|
||||
AddMenuItem( PopMenu, ID_POPUP_PCB_DELETE_PAD, msg, KiBitmap( delete_pad_xpm ) );
|
||||
|
||||
msg = AddHotkeyName( _( "Duplicate Pad" ), g_Module_Editor_Hokeys_Descr, HK_DUPLICATE_ITEM );
|
||||
AddMenuItem( PopMenu, ID_POPUP_PCB_DUPLICATE_ITEM, msg, KiBitmap( duplicate_pad_xpm ) );
|
||||
|
||||
msg = AddHotkeyName( _("Move Pad Exactly" ), g_Module_Editor_Hokeys_Descr, HK_MOVE_ITEM_EXACT );
|
||||
AddMenuItem( PopMenu, ID_POPUP_PCB_MOVE_EXACT, msg, KiBitmap( move_pad_xpm ) );
|
||||
|
||||
if( !flags )
|
||||
{
|
||||
PopMenu->AppendSeparator();
|
||||
|
@ -331,6 +346,25 @@ bool FOOTPRINT_EDIT_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMen
|
|||
HK_ROTATE_ITEM );
|
||||
AddMenuItem( PopMenu, ID_POPUP_PCB_ROTATE_TEXTMODULE, msg, KiBitmap( rotate_field_xpm ) );
|
||||
|
||||
{
|
||||
// Do not show option to duplicate value or reference fields
|
||||
// (there can only be one of each)
|
||||
|
||||
const MODULE* module = static_cast<MODULE*>( item->GetParent() );
|
||||
const TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item );
|
||||
|
||||
if( &module->Reference() != text && &module->Value() != text )
|
||||
{
|
||||
msg = AddHotkeyName( _( "Duplicate Text" ),
|
||||
g_Module_Editor_Hokeys_Descr, HK_DUPLICATE_ITEM );
|
||||
AddMenuItem( PopMenu, ID_POPUP_PCB_DUPLICATE_ITEM,
|
||||
msg, KiBitmap( duplicate_text_xpm ) );
|
||||
}
|
||||
}
|
||||
|
||||
msg = AddHotkeyName( _("Move Text Exactly" ), g_Module_Editor_Hokeys_Descr, HK_MOVE_ITEM_EXACT );
|
||||
AddMenuItem( PopMenu, ID_POPUP_PCB_MOVE_EXACT, msg, KiBitmap( move_field_xpm ) );
|
||||
|
||||
if( !flags )
|
||||
{
|
||||
msg = AddHotkeyName( _("Edit Text" ), g_Module_Editor_Hokeys_Descr,
|
||||
|
@ -359,6 +393,12 @@ bool FOOTPRINT_EDIT_FRAME::OnRightClick( const wxPoint& MousePos, wxMenu* PopMen
|
|||
AddMenuItem( PopMenu, ID_POPUP_PCB_MOVE_EDGE, msg, KiBitmap( move_line_xpm ) );
|
||||
}
|
||||
|
||||
msg = AddHotkeyName( _( "Duplicate Edge" ), g_Module_Editor_Hokeys_Descr, HK_DUPLICATE_ITEM );
|
||||
AddMenuItem( PopMenu, ID_POPUP_PCB_DUPLICATE_ITEM, msg, KiBitmap( duplicate_line_xpm ) );
|
||||
|
||||
msg = AddHotkeyName( _("Move Edge Exactly" ), g_Module_Editor_Hokeys_Descr, HK_MOVE_ITEM_EXACT );
|
||||
AddMenuItem( PopMenu, ID_POPUP_PCB_MOVE_EXACT, msg, KiBitmap( move_line_xpm ) );
|
||||
|
||||
if( ( flags & (IS_NEW | IS_MOVED) ) == IS_MOVED )
|
||||
AddMenuItem( PopMenu, ID_POPUP_PCB_PLACE_EDGE, _( "Place edge" ),
|
||||
KiBitmap( checked_ok_xpm ) );
|
||||
|
|
|
@ -145,10 +145,15 @@ public:
|
|||
*/
|
||||
bool OnHotKey( wxDC* aDC, int aHotKey, const wxPoint& aPosition, EDA_ITEM* aItem = NULL );
|
||||
|
||||
BOARD_ITEM* PrepareItemForHotkey( bool failIfCurrentlyEdited );
|
||||
bool PostCommandMenuEvent( int evt_type );
|
||||
|
||||
bool OnHotkeyEditItem( int aIdCommand );
|
||||
bool OnHotkeyDeleteItem( int aIdCommand );
|
||||
bool OnHotkeyMoveItem( int aIdCommand );
|
||||
bool OnHotkeyMoveItemExact();
|
||||
bool OnHotkeyRotateItem( int aIdCommand );
|
||||
bool OnHotkeyDuplicateItem( int aIdCommand );
|
||||
|
||||
/**
|
||||
* Function Show3D_Frame
|
||||
|
@ -530,6 +535,14 @@ protected:
|
|||
* @return a pointer to the new text, or NULL if aborted
|
||||
*/
|
||||
TEXTE_MODULE* CreateTextModule( MODULE* aModule, wxDC* aDC );
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Duplicate the item under the cursor
|
||||
* @param aIncrement increment the number of pad (if that is what is selected)
|
||||
*/
|
||||
void duplicateItems( bool aIncrement );
|
||||
};
|
||||
|
||||
#endif // MODULE_EDITOR_FRAME_H_
|
||||
|
|
|
@ -148,6 +148,7 @@ BEGIN_EVENT_TABLE( FOOTPRINT_EDIT_FRAME, PCB_BASE_FRAME )
|
|||
// Module transformations
|
||||
EVT_MENU( ID_MODEDIT_MODULE_ROTATE, FOOTPRINT_EDIT_FRAME::Process_Special_Functions )
|
||||
EVT_MENU( ID_MODEDIT_MODULE_MIRROR, FOOTPRINT_EDIT_FRAME::Process_Special_Functions )
|
||||
EVT_MENU( ID_MODEDIT_MODULE_MOVE_EXACT, FOOTPRINT_EDIT_FRAME::Process_Special_Functions )
|
||||
|
||||
EVT_MENU( ID_PCB_DRAWINGS_WIDTHS_SETUP, FOOTPRINT_EDIT_FRAME::Process_Special_Functions )
|
||||
EVT_MENU( ID_PCB_PAD_SETUP, FOOTPRINT_EDIT_FRAME::Process_Special_Functions )
|
||||
|
|
|
@ -61,6 +61,9 @@ enum pcbnew_ids
|
|||
ID_POPUP_PCB_ROTATE_PAD,
|
||||
ID_POPUP_PCB_MOVE_PAD_REQUEST,
|
||||
ID_POPUP_PCB_DRAG_PAD_REQUEST,
|
||||
ID_POPUP_PCB_DUPLICATE_ITEM,
|
||||
ID_POPUP_PCB_DUPLICATE_ITEM_AND_INCREMENT,
|
||||
ID_POPUP_PCB_MOVE_EXACT,
|
||||
|
||||
ID_POPUP_PCB_MOVE_TEXTMODULE_REQUEST,
|
||||
ID_POPUP_PCB_ROTATE_TEXTMODULE,
|
||||
|
@ -346,6 +349,7 @@ enum pcbnew_ids
|
|||
ID_MODEDIT_TRANSFORM_MODULE,
|
||||
ID_MODEDIT_MODULE_ROTATE,
|
||||
ID_MODEDIT_MODULE_MIRROR,
|
||||
ID_MODEDIT_MODULE_MOVE_EXACT,
|
||||
ID_MODEDIT_IMPORT_PART,
|
||||
ID_MODEDIT_EXPORT_PART,
|
||||
ID_MODEDIT_CREATE_NEW_LIB_AND_SAVE_CURRENT_PART,
|
||||
|
|
|
@ -64,6 +64,18 @@ TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit",
|
|||
AS_GLOBAL, 'M',
|
||||
"Move", "Moves the selected item(s)", AF_ACTIVATE );
|
||||
|
||||
TOOL_ACTION COMMON_ACTIONS::duplicate( "pcbnew.InteractiveEdit.duplicate",
|
||||
AS_GLOBAL, MD_CTRL + int( 'D' ),
|
||||
"Duplicate", "Duplicates the selected item(s)" );
|
||||
|
||||
TOOL_ACTION COMMON_ACTIONS::duplicateIncrement( "pcbnew.InteractiveEdit.duplicateIncrementPads",
|
||||
AS_GLOBAL, MD_CTRL + MD_SHIFT + int( 'D' ),
|
||||
"Duplicate", "Duplicates the selected item(s), incrementing pad numbers" );
|
||||
|
||||
TOOL_ACTION COMMON_ACTIONS::moveExact( "pcbnew.InteractiveEdit.moveExact",
|
||||
AS_GLOBAL, MD_CTRL + int( 'M' ),
|
||||
"Move Exactly...", "Moves the selected item(s) by an exact amount" );
|
||||
|
||||
TOOL_ACTION COMMON_ACTIONS::rotate( "pcbnew.InteractiveEdit.rotate",
|
||||
AS_GLOBAL, 'R',
|
||||
"Rotate", "Rotates selected item(s)" );
|
||||
|
|
|
@ -65,6 +65,15 @@ public:
|
|||
/// Activation of the edit tool
|
||||
static TOOL_ACTION properties;
|
||||
|
||||
/// Activation of the exact move tool
|
||||
static TOOL_ACTION moveExact;
|
||||
|
||||
/// Activation of the duplication tool
|
||||
static TOOL_ACTION duplicate;
|
||||
|
||||
/// Activation of the duplication tool with incrementing (e.g. pad number)
|
||||
static TOOL_ACTION duplicateIncrement;
|
||||
|
||||
/// Deleting a BOARD_ITEM
|
||||
static TOOL_ACTION remove;
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
#include "selection_tool.h"
|
||||
#include "edit_tool.h"
|
||||
|
||||
#include <dialogs/dialog_move_exact.h>
|
||||
|
||||
EDIT_TOOL::EDIT_TOOL() :
|
||||
TOOL_INTERACTIVE( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ), m_editModules( false )
|
||||
{
|
||||
|
@ -71,6 +73,7 @@ bool EDIT_TOOL::Init()
|
|||
m_selectionTool->AddMenuItem( COMMON_ACTIONS::flip, SELECTION_CONDITIONS::NotEmpty );
|
||||
m_selectionTool->AddMenuItem( COMMON_ACTIONS::remove, SELECTION_CONDITIONS::NotEmpty );
|
||||
m_selectionTool->AddMenuItem( COMMON_ACTIONS::properties, SELECTION_CONDITIONS::NotEmpty );
|
||||
m_selectionTool->AddMenuItem( COMMON_ACTIONS::moveExact, SELECTION_CONDITIONS::NotEmpty );
|
||||
|
||||
m_offset.x = 0;
|
||||
m_offset.y = 0;
|
||||
|
@ -110,6 +113,12 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
controls->SetSnapping( true );
|
||||
controls->ForceCursorPosition( false );
|
||||
|
||||
// cumulative translation
|
||||
wxPoint totalMovement( 0, 0 );
|
||||
|
||||
// make sure nothing is inhibiting undo points
|
||||
bool inhibitUndo = m_toolMgr->IsUndoInhibited();
|
||||
|
||||
// Main loop: keep receiving events
|
||||
while( OPT_TOOL_EVENT evt = Wait() )
|
||||
{
|
||||
|
@ -145,6 +154,37 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
|
||||
break; // exit the loop, as there is no further processing for removed items
|
||||
}
|
||||
else if( evt->IsAction( &COMMON_ACTIONS::duplicate ) )
|
||||
{
|
||||
// On duplicate, stop moving this item
|
||||
// The duplicate tool should then select the new item and start
|
||||
// a new move procedure
|
||||
break;
|
||||
}
|
||||
else if( evt->IsAction( &COMMON_ACTIONS::moveExact ) )
|
||||
{
|
||||
// Can't do this, because the selection will then contain
|
||||
// stale pointers and it will all go horribly wrong...
|
||||
//editFrame->RestoreCopyFromUndoList( dummy );
|
||||
//
|
||||
// So, instead, reset the position manually
|
||||
for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
|
||||
{
|
||||
BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );
|
||||
item->SetPosition( item->GetPosition() - totalMovement );
|
||||
|
||||
// And what about flipping and rotation?
|
||||
// for now, they won't be undone, but maybe that is how
|
||||
// it should be, so you can flip and move exact in the
|
||||
// same action?
|
||||
}
|
||||
|
||||
// This causes a double event, so we will get the dialogue
|
||||
// correctly, somehow - why does Rotate not?
|
||||
//MoveExact( aEvent );
|
||||
break; // exit the loop - we move exactly, so we have
|
||||
// finished moving
|
||||
}
|
||||
}
|
||||
|
||||
else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
|
||||
|
@ -156,6 +196,8 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) -
|
||||
selection.Item<BOARD_ITEM>( 0 )->GetPosition();
|
||||
|
||||
totalMovement += movement;
|
||||
|
||||
// Drag items to the current cursor position
|
||||
for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
|
||||
selection.Item<BOARD_ITEM>( i )->Move( movement + m_offset );
|
||||
|
@ -168,8 +210,11 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
break;
|
||||
|
||||
// Save items, so changes can be undone
|
||||
editFrame->OnModify();
|
||||
editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED );
|
||||
if( !inhibitUndo )
|
||||
{
|
||||
editFrame->OnModify();
|
||||
editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED );
|
||||
}
|
||||
|
||||
if( selection.Size() == 1 )
|
||||
{
|
||||
|
@ -195,6 +240,7 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
|
||||
controls->SetAutoPan( true );
|
||||
m_dragging = true;
|
||||
m_toolMgr->IncUndoInhibit();
|
||||
}
|
||||
|
||||
selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
|
||||
|
@ -203,9 +249,14 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
|
||||
else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) )
|
||||
break; // Finish
|
||||
|
||||
}
|
||||
|
||||
if( m_dragging )
|
||||
m_toolMgr->DecUndoInhibit();
|
||||
|
||||
m_dragging = false;
|
||||
|
||||
m_offset.x = 0;
|
||||
m_offset.y = 0;
|
||||
|
||||
|
@ -324,7 +375,8 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent )
|
|||
|
||||
wxPoint rotatePoint = getModificationPoint( selection );
|
||||
|
||||
if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag
|
||||
// If it is being dragged, then it is already saved with UR_CHANGED flag
|
||||
if( !m_toolMgr->IsUndoInhibited() )
|
||||
{
|
||||
editFrame->OnModify();
|
||||
editFrame->SaveCopyInUndoList( selection.items, UR_ROTATED, rotatePoint );
|
||||
|
@ -378,7 +430,7 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent )
|
|||
|
||||
wxPoint flipPoint = getModificationPoint( selection );
|
||||
|
||||
if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag
|
||||
if( !m_toolMgr->IsUndoInhibited() ) // If it is being dragged, then it is already saved with UR_CHANGED flag
|
||||
{
|
||||
editFrame->OnModify();
|
||||
editFrame->SaveCopyInUndoList( selection.items, UR_FLIPPED, flipPoint );
|
||||
|
@ -532,6 +584,69 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem )
|
|||
}
|
||||
|
||||
|
||||
int EDIT_TOOL::MoveExact( TOOL_EVENT& aEvent )
|
||||
{
|
||||
const SELECTION& selection = m_selectionTool->GetSelection();
|
||||
|
||||
// Shall the selection be cleared at the end?
|
||||
bool unselect = selection.Empty();
|
||||
|
||||
if( !makeSelection( selection ) || m_selectionTool->CheckLock() )
|
||||
{
|
||||
setTransitions();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
wxPoint translation;
|
||||
double rotation = 0;
|
||||
|
||||
PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();
|
||||
|
||||
DIALOG_MOVE_EXACT dialog( editFrame, translation, rotation );
|
||||
int ret = dialog.ShowModal();
|
||||
|
||||
if( ret == DIALOG_MOVE_EXACT::MOVE_OK )
|
||||
{
|
||||
if( !m_toolMgr->IsUndoInhibited() )
|
||||
{
|
||||
editFrame->OnModify();
|
||||
// Record an action of move and rotate
|
||||
editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED );
|
||||
}
|
||||
|
||||
wxPoint rotPoint = selection.GetCenter();
|
||||
|
||||
for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
|
||||
{
|
||||
BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );
|
||||
|
||||
item->Move( translation );
|
||||
item->Rotate( rotPoint, rotation );
|
||||
|
||||
if( !m_dragging )
|
||||
item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
|
||||
}
|
||||
|
||||
updateRatsnest( m_dragging );
|
||||
|
||||
if( m_dragging )
|
||||
selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
|
||||
else
|
||||
getModel<BOARD>()->GetRatsnest()->Recalculate();
|
||||
|
||||
if( unselect )
|
||||
m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
|
||||
|
||||
m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true );
|
||||
}
|
||||
|
||||
setTransitions();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void EDIT_TOOL::setTransitions()
|
||||
{
|
||||
Go( &EDIT_TOOL::Main, COMMON_ACTIONS::editActivate.MakeEvent() );
|
||||
|
@ -539,6 +654,7 @@ void EDIT_TOOL::setTransitions()
|
|||
Go( &EDIT_TOOL::Flip, COMMON_ACTIONS::flip.MakeEvent() );
|
||||
Go( &EDIT_TOOL::Remove, COMMON_ACTIONS::remove.MakeEvent() );
|
||||
Go( &EDIT_TOOL::Properties, COMMON_ACTIONS::properties.MakeEvent() );
|
||||
Go( &EDIT_TOOL::MoveExact, COMMON_ACTIONS::moveExact.MakeEvent() );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -91,6 +91,20 @@ public:
|
|||
*/
|
||||
int Remove( TOOL_EVENT& aEvent );
|
||||
|
||||
/**
|
||||
* Function Duplicate()
|
||||
*
|
||||
* Duplicates a component and starts a move action
|
||||
*/
|
||||
int Duplicate( TOOL_EVENT& aEvent );
|
||||
|
||||
/**
|
||||
* Function MoveExact()
|
||||
*
|
||||
* Invokes a dialog box to allow moving of the item by an exact amount.
|
||||
*/
|
||||
int MoveExact( TOOL_EVENT& aEvent );
|
||||
|
||||
/**
|
||||
* Function EditModules()
|
||||
*
|
||||
|
|
|
@ -74,6 +74,7 @@ bool MODULE_TOOLS::Init()
|
|||
}
|
||||
|
||||
selectionTool->AddMenuItem( COMMON_ACTIONS::enumeratePads );
|
||||
selectionTool->AddMenuItem( COMMON_ACTIONS::duplicate );
|
||||
|
||||
setTransitions();
|
||||
|
||||
|
@ -81,44 +82,6 @@ bool MODULE_TOOLS::Init()
|
|||
}
|
||||
|
||||
|
||||
static wxString getNextPadName( MODULE* aModule )
|
||||
{
|
||||
std::set<int> usedNumbers;
|
||||
|
||||
// Create a set of used pad numbers
|
||||
for( D_PAD* pad = aModule->Pads(); pad; pad = pad->Next() )
|
||||
{
|
||||
wxString padName = pad->GetPadName();
|
||||
int padNumber = 0;
|
||||
int base = 1;
|
||||
|
||||
// Trim and extract the trailing numeric part
|
||||
while( padName.Len() && padName.Last() >= '0' && padName.Last() <= '9' )
|
||||
{
|
||||
padNumber += ( padName.Last() - '0' ) * base;
|
||||
padName.RemoveLast();
|
||||
base *= 10;
|
||||
}
|
||||
|
||||
usedNumbers.insert( padNumber );
|
||||
}
|
||||
|
||||
int candidate = *usedNumbers.begin();
|
||||
|
||||
// Look for a gap in pad numbering
|
||||
for( std::set<int>::iterator it = usedNumbers.begin(),
|
||||
itEnd = usedNumbers.end(); it != itEnd; ++it )
|
||||
{
|
||||
if( *it - candidate > 1 )
|
||||
break;
|
||||
|
||||
candidate = *it;
|
||||
}
|
||||
|
||||
return wxString::Format( wxT( "%i" ), ++candidate );
|
||||
}
|
||||
|
||||
|
||||
int MODULE_TOOLS::PlacePad( TOOL_EVENT& aEvent )
|
||||
{
|
||||
m_frame->SetToolID( ID_MODEDIT_PAD_TOOL, wxCURSOR_PENCIL, _( "Add pads" ) );
|
||||
|
@ -189,14 +152,8 @@ int MODULE_TOOLS::PlacePad( TOOL_EVENT& aEvent )
|
|||
// ( pad position for module orient, 0, and relative to the module position)
|
||||
pad->SetLocalCoord();
|
||||
|
||||
/* NPTH pads take empty pad number (since they can't be connected),
|
||||
* other pads get incremented from the last one edited */
|
||||
wxString padName;
|
||||
|
||||
if( pad->GetAttribute() != PAD_HOLE_NOT_PLATED )
|
||||
padName = getNextPadName( module );
|
||||
|
||||
pad->SetPadName( padName );
|
||||
// Take the next available pad number
|
||||
pad->IncrementPadName( true, true );
|
||||
|
||||
// Handle the view aspect
|
||||
preview.Remove( pad );
|
||||
|
@ -532,6 +489,85 @@ int MODULE_TOOLS::PasteItems( TOOL_EVENT& aEvent )
|
|||
return 0;
|
||||
}
|
||||
|
||||
int MODULE_TOOLS::DuplicateItems( TOOL_EVENT& aEvent )
|
||||
{
|
||||
bool increment = aEvent.IsAction( &COMMON_ACTIONS::duplicateIncrement );
|
||||
|
||||
MODULE* module = m_board->m_Modules;
|
||||
assert( module );
|
||||
|
||||
// first, check if we have a selection, or try to get one
|
||||
SELECTION_TOOL* selTool = m_toolMgr->GetTool<SELECTION_TOOL>();
|
||||
|
||||
if( selTool->GetSelection().Empty() )
|
||||
{
|
||||
m_toolMgr->RunAction( COMMON_ACTIONS::selectionCursor, true );
|
||||
}
|
||||
|
||||
const SELECTION& selection = selTool->GetSelection();
|
||||
|
||||
// if we don't have a selection by now, this tool can't do anything
|
||||
if( selection.Empty() || selTool->CheckLock() )
|
||||
{
|
||||
setTransitions();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we have a selection to work on now, so start the tool process
|
||||
|
||||
m_frame->OnModify();
|
||||
m_frame->SaveCopyInUndoList( module, UR_MODEDIT );
|
||||
|
||||
// prevent other tools making undo points while the duplicate is going on
|
||||
// so that if you cancel, you don't get a duplicate object hiding over
|
||||
// the original
|
||||
m_toolMgr->IncUndoInhibit();
|
||||
|
||||
std::vector<BOARD_ITEM*> old_items;
|
||||
|
||||
for( int i = 0; i < selection.Size(); ++i )
|
||||
{
|
||||
BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i );
|
||||
|
||||
if( item )
|
||||
old_items.push_back( item );
|
||||
}
|
||||
|
||||
for( unsigned i = 0; i < old_items.size(); ++i )
|
||||
{
|
||||
BOARD_ITEM* item = old_items[i];
|
||||
|
||||
// Unselect the item, so we won't pick it up again
|
||||
// Do this first, so a single-item duplicate will correctly call
|
||||
// SetCurItem and show the item properties
|
||||
m_toolMgr->RunAction( COMMON_ACTIONS::unselectItem, true, item );
|
||||
|
||||
BOARD_ITEM* new_item = module->DuplicateAndAddItem( item, increment );
|
||||
|
||||
if( new_item )
|
||||
{
|
||||
m_view->Add( new_item );
|
||||
|
||||
// Select the new item, so we can pick it up
|
||||
m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, new_item );
|
||||
}
|
||||
}
|
||||
|
||||
m_frame->DisplayToolMsg( wxString::Format( _( "Duplicated %d item(s)" ),
|
||||
(int) old_items.size() ) );
|
||||
|
||||
// pick up the selected item(s) and start moving
|
||||
// this works well for "dropping" copies around
|
||||
m_toolMgr->RunAction( COMMON_ACTIONS::editActivate, true );
|
||||
|
||||
// and re-enable undos
|
||||
m_toolMgr->DecUndoInhibit();
|
||||
|
||||
setTransitions();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int MODULE_TOOLS::ModuleTextOutlines( TOOL_EVENT& aEvent )
|
||||
{
|
||||
|
@ -608,6 +644,8 @@ void MODULE_TOOLS::setTransitions()
|
|||
Go( &MODULE_TOOLS::EnumeratePads, COMMON_ACTIONS::enumeratePads.MakeEvent() );
|
||||
Go( &MODULE_TOOLS::CopyItems, COMMON_ACTIONS::copyItems.MakeEvent() );
|
||||
Go( &MODULE_TOOLS::PasteItems, COMMON_ACTIONS::pasteItems.MakeEvent() );
|
||||
Go( &MODULE_TOOLS::DuplicateItems, COMMON_ACTIONS::duplicate.MakeEvent() );
|
||||
Go( &MODULE_TOOLS::DuplicateItems, COMMON_ACTIONS::duplicateIncrement.MakeEvent() );
|
||||
Go( &MODULE_TOOLS::ModuleTextOutlines, COMMON_ACTIONS::moduleTextOutlines.MakeEvent() );
|
||||
Go( &MODULE_TOOLS::ModuleEdgeOutlines, COMMON_ACTIONS::moduleEdgeOutlines.MakeEvent() );
|
||||
}
|
||||
|
|
|
@ -77,6 +77,9 @@ public:
|
|||
*/
|
||||
int PasteItems( TOOL_EVENT& aEvent );
|
||||
|
||||
|
||||
int DuplicateItems ( TOOL_EVENT& aEvent );
|
||||
|
||||
/**
|
||||
* Function ModuleTextOutlines()
|
||||
*
|
||||
|
|
|
@ -939,3 +939,27 @@ void SELECTION::clear()
|
|||
items.ClearItemsList();
|
||||
group->Clear();
|
||||
}
|
||||
|
||||
|
||||
wxPoint SELECTION::GetCenter() const
|
||||
{
|
||||
wxPoint centre;
|
||||
|
||||
if( Size() == 1 )
|
||||
{
|
||||
centre = Item<BOARD_ITEM>( 0 )->GetCenter();
|
||||
}
|
||||
else
|
||||
{
|
||||
EDA_RECT bbox = Item<BOARD_ITEM>( 0 )->GetBoundingBox();
|
||||
for( unsigned int i = 1; i < items.GetCount(); ++i )
|
||||
{
|
||||
BOARD_ITEM* item = Item<BOARD_ITEM>( i );
|
||||
bbox.Merge( item->GetBoundingBox() );
|
||||
}
|
||||
|
||||
centre = bbox.Centre();
|
||||
}
|
||||
|
||||
return centre;
|
||||
}
|
||||
|
|
|
@ -70,6 +70,8 @@ struct SELECTION
|
|||
return static_cast<T*>( items.GetPickedItem( aIndex ) );
|
||||
}
|
||||
|
||||
wxPoint GetCenter() const;
|
||||
|
||||
private:
|
||||
/// Clears both the VIEW_GROUP and set of selected items. Please note that it does not
|
||||
/// change properties of selected items (e.g. selection flag).
|
||||
|
|
Loading…
Reference in New Issue